X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Flibmarklin%2Fintellibox.cpp;h=416d02184e9564836361da811ef247a4777a0f3c;hb=6ba6af3637c299ab00828c49de9151429488cc17;hp=35880610145de2d426c4c860bbf4ba9a56e43652;hpb=651698847d5293cfb15b6fb23a394701388c0151;p=r2c2.git diff --git a/source/libmarklin/intellibox.cpp b/source/libmarklin/intellibox.cpp index 3588061..416d021 100644 --- a/source/libmarklin/intellibox.cpp +++ b/source/libmarklin/intellibox.cpp @@ -20,6 +20,7 @@ namespace Marklin { Intellibox::Intellibox(const string &dev): power(false), + halted(false), update_sensors(false), command_sent(false) { @@ -80,6 +81,19 @@ void Intellibox::set_power(bool p) signal_power.emit(power); } +void Intellibox::halt(bool h) +{ + halted = h; + if(halted) + { + for(map::iterator i=locos.begin(); i!=locos.end(); ++i) + if(i->second.speed) + set_loco_speed(i->first, 0); + } + + signal_halt.emit(halted); +} + void Intellibox::add_loco(unsigned addr) { if(!locos.count(addr)) @@ -96,17 +110,23 @@ void Intellibox::add_loco(unsigned addr) void Intellibox::set_loco_speed(unsigned addr, unsigned speed) { Locomotive &loco = locos[addr]; + if(speed==loco.speed) + return; + if(speed && halted) + return; + loco.speed = speed; loco_command(addr, speed, loco.reverse, loco.funcs|0x100); - signal_loco_speed.emit(addr, speed, loco.reverse); } void Intellibox::set_loco_reverse(unsigned addr, bool rev) { Locomotive &loco = locos[addr]; + if(rev==loco.reverse) + return; + loco.reverse = rev; loco_command(addr, loco.speed, rev, loco.funcs|0x100); - signal_loco_speed.emit(addr, loco.speed, rev); } void Intellibox::set_loco_function(unsigned addr, unsigned func, bool state) @@ -141,6 +161,7 @@ void Intellibox::set_turnout(unsigned addr, bool state) turnout.pending = state; turnout.active = true; + turnout.off_timeout = Time::TimeStamp(); turnout_command(addr, state, true); } @@ -230,8 +251,22 @@ void Intellibox::tick() 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 }; + bool first = true; + while(poll(&pfd, 1, (first ? -1 : 0))>0) + { + char data[16]; + read(serial_fd, data, 16); + first = false; + } + } + + queue.clear(); + command_sent = false; } void Intellibox::command(Command cmd) @@ -342,7 +377,10 @@ void Intellibox::process_reply(const Time::TimeStamp &t) read_all(data, 2); unsigned addr = data[0]+((data[1]&7)<<8); - signal_turnout.emit(addr, (data[1]&0x80)!=0); + Turnout &turnout = turnouts[addr]; + turnout.state = (data[1]&0x80)!=0; + turnout.pending = turnout.state; + signal_turnout.emit(addr, turnout.state); } } else if(cmd==CMD_EVENT_SENSOR) @@ -376,15 +414,30 @@ void Intellibox::process_reply(const Time::TimeStamp &t) } } } - else if(cmd==CMD_TURNOUT) + else if(cmd==CMD_LOK) { - unsigned char err; - read_all(&err, 1); + Error err; + read_status(&err); if(err==ERR_NO_ERROR) { unsigned addr = queue.front().addr; - Turnout &turnout = turnouts[addr]; + Locomotive &loco = locos[addr]; + signal_loco_speed.emit(addr, loco.speed, loco.reverse); + } + else + error(cmd, err); + } + else if(cmd==CMD_TURNOUT) + { + Error err; + read_status(&err); + + unsigned addr = queue.front().addr; + Turnout &turnout = turnouts[addr]; + + if(err==ERR_NO_ERROR) + { turnout.state = turnout.pending; if(turnout.active) { @@ -394,11 +447,16 @@ void Intellibox::process_reply(const Time::TimeStamp &t) } else if(err==ERR_NO_I2C_SPACE) queue.push_back(queue.front()); + else + { + turnout.pending = turnout.state; + error(cmd, err); + } } else if(cmd==CMD_TURNOUT_STATUS) { - unsigned char err; - read_all(&err, 1); + Error err; + read_status(&err); if(err==ERR_NO_ERROR) { @@ -412,14 +470,17 @@ void Intellibox::process_reply(const Time::TimeStamp &t) if(state!=turnout.state) { turnout.state = state; + turnout.pending = state; signal_turnout.emit(addr, turnout.state); } } + else + error(cmd, err); } else if(cmd==CMD_LOK_STATUS) { - unsigned char err; - read_all(&err, 1); + Error err; + read_status(&err); if(err==ERR_NO_ERROR) { @@ -450,6 +511,8 @@ void Intellibox::process_reply(const Time::TimeStamp &t) signal_loco_function.emit(addr, i, loco.funcs&(1<(c); + return ret; +} + +void Intellibox::error(Command cmd, Error err) +{ + const char *cmd_str = 0; + switch(cmd) + { + case CMD_LOK: cmd_str = "CMD_LOK"; break; + case CMD_LOK_STATUS: cmd_str = "CMD_LOK_STATUS"; break; + case CMD_LOK_CONFIG: cmd_str = "CMD_LOK_CONFIG"; break; + case CMD_FUNC: cmd_str = "CMD_FUNC"; break; + case CMD_FUNC_STATUS: cmd_str = "CMD_FUNC_STATUS"; break; + case CMD_TURNOUT: cmd_str = "CMD_TURNOUT"; break; + case CMD_TURNOUT_FREE: cmd_str = "CMD_TURNOUT_FREE"; break; + case CMD_TURNOUT_STATUS: cmd_str = "CMD_TURNOUT_STATUS"; break; + case CMD_TURNOUT_GROUP_STATUS: cmd_str = "CMD_TURNOUT_GROUP_STATUS"; break; + case CMD_SENSOR_STATUS: cmd_str = "CMD_SENSOR_STATUS"; break; + case CMD_SENSOR_REPORT: cmd_str = "CMD_SENSOR_REPORT"; break; + case CMD_SENSOR_PARAM_SET: cmd_str = "CMD_SENSOR_PARAM_SET"; break; + case CMD_STATUS: cmd_str = "CMD_STATUS"; break; + case CMD_POWER_OFF: cmd_str = "CMD_POWER_OFF"; break; + case CMD_POWER_ON: cmd_str = "CMD_POWER_ON"; break; + case CMD_NOP: cmd_str = "CMD_NOP"; break; + case CMD_EVENT: cmd_str = "CMD_EVENT"; break; + case CMD_EVENT_LOK: cmd_str = "CMD_EVENT_LOK"; break; + case CMD_EVENT_TURNOUT: cmd_str = "CMD_EVENT_TURNOUT"; break; + case CMD_EVENT_SENSOR: cmd_str = "CMD_EVENT_SENSOR"; break; + default: cmd_str = "(unknown command)"; + } + + const char *err_str = 0; + switch(err) + { + case ERR_NO_ERROR: err_str = "ERR_NO_ERROR"; break; + case ERR_SYS_ERROR: err_str = "ERR_SYS_ERROR"; break; + case ERR_BAD_PARAM: err_str = "ERR_BAD_PARAM"; break; + case ERR_POWER_OFF: err_str = "ERR_POWER_OFF"; break; + case ERR_NO_LOK_SPACE: err_str = "ERR_NO_LOK_SPACE"; break; + case ERR_NO_TURNOUT_SPACE: err_str = "ERR_NO_TURNOUT_SPACE"; break; + case ERR_NO_DATA: err_str = "ERR_NO_DATA"; break; + case ERR_NO_SLOT: err_str = "ERR_NO_SLOT"; break; + case ERR_BAD_LOK_ADDR: err_str = "ERR_BAD_LOK_ADDR"; break; + case ERR_LOK_BUSY: err_str = "ERR_LOK_BUSY"; break; + case ERR_BAD_TURNOUT_ADDR: err_str = "ERR_BAD_TURNOUT_ADDR"; break; + case ERR_BAD_SO_VALUE: err_str = "ERR_BAD_SO_VALUE"; break; + case ERR_NO_I2C_SPACE: err_str = "ERR_NO_I2C_SPACE"; break; + case ERR_LOW_TURNOUT_SPACE: err_str = "ERR_LOW_TURNOUT_SPACE"; break; + case ERR_LOK_HALTED: err_str = "ERR_LOK_HALTED"; break; + case ERR_LOK_POWER_OFF: err_str = "ERR_LOK_POWER_OFF"; break; + default: cmd_str = "(unknown error)"; + } + + IO::print("Error: %s: %s\n", cmd_str, err_str); +} + Intellibox::Locomotive::Locomotive(): speed(0), @@ -491,7 +617,8 @@ Intellibox::Locomotive::Locomotive(): Intellibox::Turnout::Turnout(): state(false), - active(false) + active(false), + pending(false) { }