X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Flibr2c2%2Fintellibox.cpp;h=c2e5d75af7fefd6eea28d927c55e700d9c7b5da4;hb=b78b49d85fbb9b2901c77e6450cfd41c0a818ac1;hp=64e785582dce0f8895deda28493af96cb5f7974c;hpb=247742fbc1c27bfc9fdef4630afcdc2408cdd550;p=r2c2.git diff --git a/source/libr2c2/intellibox.cpp b/source/libr2c2/intellibox.cpp index 64e7855..c2e5d75 100644 --- a/source/libr2c2/intellibox.cpp +++ b/source/libr2c2/intellibox.cpp @@ -1,13 +1,7 @@ -/* $Id$ - -This file is part of R²C² -Copyright © 2010 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - #include #include #include +#include #include #include #include @@ -20,55 +14,39 @@ using namespace Msp; namespace R2C2 { -Intellibox::Intellibox(const string &dev): +Intellibox::Intellibox(const Options &opts): + serial(opts.get(string(), "ttyUSB0")), power(false), halted(false), update_sensors(false), command_sent(false) { - serial_fd = ::open(dev.c_str(), O_RDWR); - if(serial_fd<0) - throw Exception("Couldn't open serial port\n"); + static unsigned baud[]= { 2400, 4800, 9600, 19200, 0 }; - static unsigned baud[]= - { - 2400, B2400, - 4800, B4800, - 9600, B9600, - 19200, B19200, - 0 - }; - - termios attr; - tcgetattr(serial_fd, &attr); - cfmakeraw(&attr); - attr.c_cflag |= CSTOPB; + serial.set_stop_bits(2); bool ok = false; bool p50 = false; - for(unsigned i=0; baud[i]; i+=2) + for(unsigned i=0; baud[i]; ++i) { - cfsetospeed(&attr, baud[i+1]); - tcsetattr(serial_fd, TCSADRAIN, &attr); - - write(serial_fd, "\xC4", 1); + serial.set_baud_rate(baud[i]); + serial.put('\xC4'); - pollfd pfd = { serial_fd, POLLIN, 0 }; - if(poll(&pfd, 1, 500)>0) + if(IO::poll(serial, IO::P_INPUT, 500*Time::msec)) { IO::print("IB detected at %d bits/s\n", baud[i]); char buf[2]; - p50 = (read(serial_fd, buf, 2)==2); + p50 = (serial.read(buf, 2)==2); ok = true; break; } } if(!ok) - throw Exception("IB not detected"); + throw runtime_error("IB not detected"); if(p50) - write(serial_fd, "xZzA1\r", 6); + serial.write("xZzA1\r", 6); command(CMD_STATUS); } @@ -116,7 +94,7 @@ unsigned Intellibox::get_protocol_speed_steps(const string &proto_name) const return 0; } -void Intellibox::add_loco(unsigned addr, const string &proto_name, const VehicleType &type) +unsigned Intellibox::add_loco(unsigned addr, const string &proto_name, const VehicleType &type) { Protocol proto = map_protocol(proto_name); @@ -135,6 +113,13 @@ void Intellibox::add_loco(unsigned addr, const string &proto_name, const Vehicle data[1] = (addr>>8)&0xFF; command(CMD_LOK_STATUS, addr, data, 2); } + + return addr; +} + +void Intellibox::remove_loco(unsigned addr) +{ + locos.erase(addr); } void Intellibox::set_loco_speed(unsigned addr, unsigned speed) @@ -215,12 +200,23 @@ void Intellibox::set_loco_function(unsigned addr, unsigned func, bool state) signal_loco_function.emit(addr, func, state); } -void Intellibox::add_turnout(unsigned addr, const TrackType &type) +unsigned Intellibox::add_turnout(unsigned addr, const TrackType &type) +{ + return add_turnout(addr, type.get_state_bits(), false); +} + +void Intellibox::remove_turnout(unsigned addr) +{ + turnouts.erase(addr); +} + +unsigned Intellibox::add_turnout(unsigned addr, unsigned bits, bool signal) { if(!turnouts.count(addr)) { Turnout &turnout = turnouts[addr]; - turnout.bits = type.get_state_bits(); + turnout.bits = bits; + turnout.signal = signal; unsigned char data[2]; data[0] = addr&0xFF; @@ -236,17 +232,27 @@ void Intellibox::add_turnout(unsigned addr, const TrackType &type) command(CMD_TURNOUT_STATUS, addr+i, data, 2); } } + + return addr; +} + +void Intellibox::turnout_state_changed(unsigned addr, const Turnout &turnout) const +{ + if(turnout.signal) + signal_signal.emit(addr, turnout.state); + else + signal_turnout.emit(addr, turnout.state); } void Intellibox::set_turnout(unsigned addr, unsigned state) { Turnout &turnout = turnouts[addr]; unsigned mask = (1<second.active = false; i->second.off_timeout = Time::TimeStamp(); - turnout_command(i->first, i->second.state, false); + for(unsigned j=0; jsecond.bits; ++j) + turnout_command(i->first+j, !(i->second.state&(1<::iterator i=sensors.begin(); i!=sensors.end(); ++i) @@ -333,8 +373,7 @@ void Intellibox::tick() if(!queue.empty() && command_sent) { - pollfd pfd = { serial_fd, POLLIN, 0 }; - if(poll(&pfd, 1, 0)>0) + if(IO::poll(serial, IO::P_INPUT, Time::zero)) { process_reply(t); queue.erase(queue.begin()); @@ -347,23 +386,21 @@ void Intellibox::tick() if(!queue.empty()) { const CommandSlot &slot = queue.front(); - write(serial_fd, slot.data, slot.length); + serial.write(reinterpret_cast(slot.data), slot.length); command_sent = true; } } void Intellibox::flush() { - Time::TimeStamp t = Time::now(); for(list::iterator i=queue.begin(); i!=queue.end(); ++i) { - write(serial_fd, i->data, i->length); - pollfd pfd = { serial_fd, POLLIN, 0 }; + serial.write(reinterpret_cast(i->data), i->length); bool first = true; - while(poll(&pfd, 1, (first ? -1 : 0))>0) + while(first ? IO::poll(serial, IO::P_INPUT) : IO::poll(serial, IO::P_INPUT, Time::zero)) { char data[16]; - read(serial_fd, data, 16); + serial.read(data, 16); first = false; } } @@ -379,7 +416,7 @@ Intellibox::Protocol Intellibox::map_protocol(const string &name) const else if(name=="MM-27") return MM_27; else - throw InvalidParameterValue("Unknown protocol"); + throw invalid_argument("Intellibox::map_protocol"); } void Intellibox::command(Command cmd) @@ -490,10 +527,14 @@ void Intellibox::process_reply(const Time::TimeStamp &t) read_all(data, 2); unsigned addr = data[0]+((data[1]&7)<<8); + unsigned mask = 1; + for(; !turnouts[addr].bits; --addr, mask<<=1) ; Turnout &turnout = turnouts[addr]; - turnout.state = (data[1]&0x80)!=0; + + unsigned bit = !(data[1]&0x80); + turnout.state = (turnout.state&~mask) | (bit*mask); turnout.pending = turnout.state; - signal_turnout.emit(addr, turnout.state); + turnout_state_changed(addr,turnout); } } else if(cmd==CMD_EVENT_SENSOR) @@ -553,11 +594,7 @@ void Intellibox::process_reply(const Time::TimeStamp &t) unsigned addr = queue.front().addr; unsigned mask = 1; - while(!turnouts[addr].bits) - { - --addr; - mask <<= 1; - } + for(; !turnouts[addr].bits; --addr, mask<<=1) ; Turnout &turnout = turnouts[addr]; if(err==ERR_NO_ERROR) @@ -566,7 +603,7 @@ void Intellibox::process_reply(const Time::TimeStamp &t) if(turnout.active) { if(turnout.state==turnout.pending) - signal_turnout.emit(addr, turnout.state); + turnout_state_changed(addr, turnout); turnout.off_timeout = t+500*Time::msec; } } @@ -590,20 +627,18 @@ void Intellibox::process_reply(const Time::TimeStamp &t) unsigned addr = queue.front().addr; unsigned mask = 1; - while(!turnouts[addr].bits) - { - --addr; - mask <<= 1; - } + for(; !turnouts[addr].bits; --addr, mask<<=1) ; Turnout &turnout = turnouts[addr]; - bool state = data&0x04; - if(state!=((turnout.state&mask)!=0)) + bool bit = !(data&0x04); + if(bit!=((turnout.state&mask)!=0)) { - turnout.state = (turnout.state&~mask) | (state ? mask : 0); + turnout.state = (turnout.state&~mask) | (bit*mask); turnout.pending = turnout.state; - signal_turnout.emit(addr, turnout.state); + turnout_state_changed(addr, turnout); } + + turnout.synced = true; } else error(cmd, err); @@ -623,24 +658,22 @@ void Intellibox::process_reply(const Time::TimeStamp &t) unsigned speed = (data[0]<=1 ? 0 : data[0]*2/19+1); bool reverse = !(data[1]&0x20); - if(speed!=loco.speed || reverse!=loco.reverse) - { - loco.speed = speed; - loco.reverse = reverse; - signal_loco_speed.emit(addr, loco.speed, loco.reverse); - } + bool speed_changed = (speed!=loco.speed || reverse!=loco.reverse); + + loco.speed = speed; + loco.reverse = reverse; unsigned funcs = (data[1]&0xF)<<1; if(data[1]&0x10) funcs |= 1; - if(funcs!=loco.funcs) - { - unsigned changed = loco.funcs^funcs; - loco.funcs = funcs; - for(unsigned i=0; i<5; ++i) - if(changed&(1<(buf+pos), len-pos); return pos; } @@ -740,10 +773,12 @@ void Intellibox::error(Command cmd, Error err) Intellibox::Locomotive::Locomotive(): + protocol(NONE), ext_func(false), speed(0), reverse(false), - funcs(0) + funcs(0), + pending_half_step(0) { } @@ -751,7 +786,9 @@ Intellibox::Turnout::Turnout(): bits(1), state(0), active(false), - pending(false) + synced(false), + pending(0), + signal(false) { }