X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Flibr2c2%2Farducontrol.cpp;h=2361d8540d561ccff6477836b36fc41ebba114dc;hb=d5d8ee8;hp=8c17234051752e2527295016e197d2b8d8e5237c;hpb=aada4cd3c335e6cf55d64200b9d92e8f9310fa1d;p=r2c2.git diff --git a/source/libr2c2/arducontrol.cpp b/source/libr2c2/arducontrol.cpp index 8c17234..2361d85 100644 --- a/source/libr2c2/arducontrol.cpp +++ b/source/libr2c2/arducontrol.cpp @@ -1,4 +1,7 @@ #include +#include +#include +#include #include #include #include "arducontrol.h" @@ -18,16 +21,25 @@ ArduControl::ProtocolInfo ArduControl::protocol_info[2] = ArduControl::ArduControl(const string &dev): serial(dev), debug(1), + state_file("arducontrol.state"), power(false), active_accessory(0), s88(*this), mfx_search(*this), thread(*this) { + if(FS::exists(state_file)) + DataFile::load(*this, state_file.str()); + + unsigned max_address = 0; + for(MfxInfoArray::const_iterator i=mfx_info.begin(); i!=mfx_info.end(); ++i) + max_address = max(max_address, i->address); + mfx_search.set_next_address(max_address+1); + PendingCommand cmd; cmd.command[0] = READ_POWER_STATE; cmd.length = 1; - push_command(cmd); + command_queue.push(cmd); cmd.command[0] = MFX_SET_STATION_ID; cmd.command[1] = 'R'; @@ -35,7 +47,7 @@ ArduControl::ArduControl(const string &dev): cmd.command[3] = 'C'; cmd.command[4] = '2'; cmd.length = 5; - push_command(cmd); + command_queue.push(cmd); } ArduControl::~ArduControl() @@ -51,7 +63,7 @@ void ArduControl::set_power(bool p) cmd.tag.serial = power.serial; cmd.command[0] = (p ? POWER_ON : POWER_OFF); cmd.length = 1; - push_command(cmd); + command_queue.push(cmd); } } @@ -84,6 +96,14 @@ unsigned ArduControl::get_protocol_speed_steps(const string &proto_name) const return protocol_info[map_protocol(proto_name)].max_speed; } +const Driver::DetectedLocomotive *ArduControl::enumerate_detected_locos(unsigned i) const +{ + if(i>=mfx_info.size()) + return 0; + + return &mfx_info[i]; +} + unsigned ArduControl::add_loco(unsigned addr, const string &proto_name, const VehicleType &) { if(!addr) @@ -99,6 +119,20 @@ unsigned ArduControl::add_loco(unsigned addr, const string &proto_name, const Ve return loco.id; } +ArduControl::MfxInfoArray::iterator ArduControl::add_mfx_info(const MfxInfo &info) +{ + MfxInfoArray::iterator i; + for(i=mfx_info.begin(); (i!=mfx_info.end() && i->id!=info.id); ++i) ; + if(i==mfx_info.end()) + { + mfx_info.push_back(info); + i = --mfx_info.end(); + } + else + *i = info; + return i; +} + void ArduControl::remove_loco(unsigned id) { Locomotive &loco = get_item(locomotives, id); @@ -115,7 +149,7 @@ void ArduControl::set_loco_speed(unsigned id, unsigned speed) if(loco.speed.set(speed)) { PendingCommand cmd(loco, Locomotive::SPEED); - push_command(cmd); + command_queue.push(cmd); refresh.add_loco(loco); } @@ -127,7 +161,7 @@ void ArduControl::set_loco_reverse(unsigned id, bool rev) if(loco.reverse.set(rev)) { PendingCommand cmd(loco, Locomotive::REVERSE); - push_command(cmd); + command_queue.push(cmd); refresh.add_loco(loco); } @@ -145,7 +179,7 @@ void ArduControl::set_loco_function(unsigned id, unsigned func, bool state) if(func>0 || loco.proto!=MM) { PendingCommand cmd(loco, Locomotive::FUNCTIONS, func); - push_command(cmd); + command_queue.push(cmd); } refresh.add_loco(loco); @@ -265,7 +299,8 @@ bool ArduControl::get_sensor(unsigned addr) const void ArduControl::tick() { - while(Tag tag = pop_completed_tag()) + Tag tag; + while(completed_commands.pop(tag)) { if(tag.type==Tag::GENERAL) { @@ -274,6 +309,16 @@ void ArduControl::tick() if(power.commit(tag.serial)) signal_power.emit(power.current); } + else if(tag.command==NEW_LOCO) + { + MfxInfo info; + if(mfx_search.pop_info(info)) + { + MfxInfoArray::iterator i = add_mfx_info(info); + save_state(); + signal_locomotive_detected.emit(*i); + } + } } else if(tag.type==Tag::LOCOMOTIVE) { @@ -360,7 +405,7 @@ void ArduControl::tick() for(i=0; (lowest_bit>>i)>1; ++i) ; acc.state.set(acc.state^lowest_bit); PendingCommand cmd(acc, Accessory::ACTIVATE, i); - push_command(cmd); + command_queue.push(cmd); } else accessory_queue.pop_front(); @@ -373,7 +418,7 @@ void ArduControl::tick() { off_timeout = Time::TimeStamp(); PendingCommand cmd(*active_accessory, Accessory::DEACTIVATE); - push_command(cmd); + command_queue.push(cmd); } } } @@ -382,36 +427,21 @@ void ArduControl::flush() { } -void ArduControl::push_command(const PendingCommand &cmd) +void ArduControl::save_state() const { - MutexLock lock(mutex); - command_queue.push_back(cmd); -} + FS::RedirectedPath tmp_file(state_file); + IO::BufferedFile out(tmp_file.str(), IO::M_WRITE); + DataFile::Writer writer(out); -bool ArduControl::pop_command(PendingCommand &cmd) -{ - MutexLock lock(mutex); - if(command_queue.empty()) - return false; - cmd = command_queue.front(); - command_queue.pop_front(); - return true; -} - -void ArduControl::push_completed_tag(const Tag &tag) -{ - MutexLock lock(mutex); - completed_commands.push_back(tag); -} - -ArduControl::Tag ArduControl::pop_completed_tag() -{ - MutexLock lock(mutex); - if(completed_commands.empty()) - return Tag(); - Tag tag = completed_commands.front(); - completed_commands.pop_front(); - return tag; + writer.write((DataFile::Statement("mfx_announce_serial"), mfx_announce.get_serial())); + for(MfxInfoArray::const_iterator i=mfx_info.begin(); i!=mfx_info.end(); ++i) + { + DataFile::Statement st("mfx_locomotive"); + st.append(i->id); + st.sub.push_back((DataFile::Statement("address"), i->address)); + st.sub.push_back((DataFile::Statement("name"), i->name)); + writer.write(st); + } } @@ -575,6 +605,26 @@ ArduControl::PendingCommand::PendingCommand(Accessory &acc, Accessory::Command c } +template +void ArduControl::Queue::push(const T &item) +{ + MutexLock lock(mutex); + items.push_back(item); +} + +template +bool ArduControl::Queue::pop(T &item) +{ + MutexLock lock(mutex); + if(items.empty()) + return false; + + item = items.front(); + items.pop_front(); + return true; +} + + ArduControl::RefreshTask::RefreshTask(): next(cycle.end()), round(0), @@ -708,7 +758,7 @@ void ArduControl::S88Task::process_reply(const char *reply, unsigned length) tag.command = Sensor::STATE; tag.serial = i->second.state.serial; tag.id = i->first; - control.push_completed_tag(tag); + control.completed_commands.push(tag); } if(count>octets_remaining) @@ -770,6 +820,13 @@ bool ArduControl::MfxSearchTask::get_work(PendingCommand &cmd) if(control.debug>=1) IO::print("Assigning MFX address %d to decoder %08X\n", next_address, bits); + MfxInfo info; + info.protocol = "MFX"; + info.address = next_address; + info.name = format("%08X", bits); + info.id = bits; + queue.push(info); + cmd.command[0] = MFX_ASSIGN_ADDRESS; cmd.command[1] = next_address>>8; cmd.command[2] = next_address; @@ -777,6 +834,10 @@ bool ArduControl::MfxSearchTask::get_work(PendingCommand &cmd) cmd.command[3+i] = bits>>(24-i*8); cmd.length = 7; + cmd.tag.type = Tag::GENERAL; + cmd.tag.command = NEW_LOCO; + cmd.tag.id = bits; + size = 0; bits = 0; ++next_address; @@ -827,6 +888,16 @@ void ArduControl::MfxSearchTask::process_reply(const char *reply, unsigned lengt } } +void ArduControl::MfxSearchTask::set_next_address(unsigned a) +{ + next_address = a; +} + +bool ArduControl::MfxSearchTask::pop_info(MfxInfo &info) +{ + return queue.pop(info); +} + ArduControl::ControlThread::ControlThread(ArduControl &c): control(c), @@ -848,6 +919,8 @@ void ArduControl::ControlThread::exit() void ArduControl::ControlThread::main() { + init_baud_rate(); + while(!done) { PendingCommand cmd; @@ -857,16 +930,67 @@ void ArduControl::ControlThread::main() for(unsigned i=0; (success && i=1) + IO::print("ArduControl detected at %d bits/s\n", rate); + + if(rate!=rates[0]) + { + PendingCommand cmd; + cmd.command[0] = SET_BAUD_RATE; + cmd.command[1] = rates[0]>>8; + cmd.command[2] = rates[0]; + cmd.length = 3; + if(do_command(cmd)==COMMAND_OK) + { + control.serial.set_baud_rate(rates[0]); + Time::sleep(Time::sec); + if(do_command(cmd)==COMMAND_OK) + { + if(control.debug>=1) + IO::print("Rate changed to %d bits/s\n", rates[0]); + } + } + } +} + bool ArduControl::ControlThread::get_work(PendingCommand &cmd) { - if(control.pop_command(cmd)) + if(control.command_queue.pop(cmd)) return true; for(vector::iterator i=tasks.begin(); i!=tasks.end(); ++i) @@ -953,7 +1077,7 @@ unsigned ArduControl::ControlThread::process_reply(const char *reply, unsigned r tag.type = Tag::GENERAL; tag.command = POWER; tag.serial = control.power.serial; - control.push_completed_tag(tag); + control.completed_commands.push(tag); } else { @@ -964,4 +1088,34 @@ unsigned ArduControl::ControlThread::process_reply(const char *reply, unsigned r return 0; } + +ArduControl::Loader::Loader(ArduControl &c): + DataFile::ObjectLoader(c) +{ + add("mfx_announce_serial", &Loader::mfx_announce_serial); + add("mfx_locomotive", &Loader::mfx_locomotive); +} + +void ArduControl::Loader::mfx_announce_serial(unsigned s) +{ + obj.mfx_announce.set_serial(s); +} + +void ArduControl::Loader::mfx_locomotive(unsigned id) +{ + MfxInfo info; + info.id = id; + info.protocol = "MFX"; + load_sub(info); + obj.add_mfx_info(info); +} + + +ArduControl::MfxInfo::Loader::Loader(MfxInfo &i): + DataFile::ObjectLoader(i) +{ + add("address", static_cast(&MfxInfo::address)); + add("name", static_cast(&MfxInfo::name)); +} + } // namespace R2C2