X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Flibr2c2%2Farducontrol.cpp;h=9edc1e2244d41beb448921617186dfe635c4d192;hb=83778cdecccaa02c943cb9b49fb20f1c546b15bd;hp=47584f44bb8b145496a0b6d9a52c118f4c68fcd9;hpb=58c56db5f740d9d3c56ff64f4062b108076c63c3;p=r2c2.git diff --git a/source/libr2c2/arducontrol.cpp b/source/libr2c2/arducontrol.cpp index 47584f4..9edc1e2 100644 --- a/source/libr2c2/arducontrol.cpp +++ b/source/libr2c2/arducontrol.cpp @@ -1,4 +1,7 @@ #include +#include +#include +#include #include #include #include "arducontrol.h" @@ -15,19 +18,29 @@ ArduControl::ProtocolInfo ArduControl::protocol_info[2] = { 0x3FFF, 126, 15 } // MFX }; -ArduControl::ArduControl(const string &dev): - serial(dev), - debug(1), +ArduControl::ArduControl(const Options &opts): + serial(opts.get(string(), "ttyUSB0")), + debug(opts.get("debug")), + state_file("arducontrol.state"), power(false), + halted(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 +48,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,12 +64,23 @@ 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); } } -void ArduControl::halt(bool) +void ArduControl::halt(bool h) { + if(h==halted) + return; + + halted = h; + if(halted) + { + for(LocomotiveMap::const_iterator i=locomotives.begin(); i!=locomotives.end(); ++i) + set_loco_speed(i->first, 0); + } + + signal_halt.emit(halted); } const char *ArduControl::enumerate_protocols(unsigned i) const @@ -107,6 +131,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); @@ -120,10 +158,13 @@ void ArduControl::set_loco_speed(unsigned id, unsigned speed) if(speed>protocol_info[loco.proto].max_speed) throw invalid_argument("ArduControl::set_loco_speed"); + if(speed && halted) + return; + if(loco.speed.set(speed)) { PendingCommand cmd(loco, Locomotive::SPEED); - push_command(cmd); + command_queue.push(cmd); refresh.add_loco(loco); } @@ -135,7 +176,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); } @@ -153,7 +194,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); @@ -273,7 +314,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) { @@ -287,15 +329,8 @@ void ArduControl::tick() MfxInfo info; if(mfx_search.pop_info(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; + MfxInfoArray::iterator i = add_mfx_info(info); + save_state(); signal_locomotive_detected.emit(*i); } } @@ -337,9 +372,7 @@ void ArduControl::tick() Accessory &acc = i->second; if(tag.command==Accessory::ACTIVATE) - { off_timeout = Time::now()+acc.active_time; - } else if(tag.command==Accessory::DEACTIVATE) { if(acc.state.commit(tag.serial)) @@ -371,7 +404,7 @@ void ArduControl::tick() } } - while(!active_accessory && !accessory_queue.empty()) + while(power && !active_accessory && !accessory_queue.empty()) { Accessory &acc = *accessory_queue.front(); @@ -383,9 +416,12 @@ void ArduControl::tick() unsigned lowest_bit = changes&~(changes-1); unsigned i; for(i=0; (lowest_bit>>i)>1; ++i) ; + active_index = i; acc.state.set(acc.state^lowest_bit); PendingCommand cmd(acc, Accessory::ACTIVATE, i); - push_command(cmd); + command_queue.push(cmd); + + monitor.reset_peak(); } else accessory_queue.pop_front(); @@ -396,9 +432,24 @@ void ArduControl::tick() Time::TimeStamp t = Time::now(); if(t>off_timeout) { + Accessory &acc = *active_accessory; + + if(acc.kind==Accessory::TURNOUT && monitor.get_peak()<0.5f) + { + unsigned bit = 1<id); + st.sub.push_back((DataFile::Statement("address"), i->address)); + st.sub.push_back((DataFile::Statement("name"), i->name)); + writer.write(st); + } } @@ -522,6 +558,8 @@ ArduControl::Accessory::Accessory(Kind k, unsigned a, unsigned b): address(a), bits(b), state(0), + uncertain((1< +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), @@ -696,11 +754,17 @@ void ArduControl::RefreshTask::advance() ArduControl::S88Task::S88Task(ArduControl &c): control(c), n_octets(0), - octets_remaining(0) + octets_remaining(0), + delay(0) { } bool ArduControl::S88Task::get_work(PendingCommand &cmd) { + if(delay) + { + --delay; + return false; + } if(octets_remaining || !n_octets) return false; @@ -709,6 +773,8 @@ bool ArduControl::S88Task::get_work(PendingCommand &cmd) cmd.command[1] = octets_remaining; cmd.length = 2; + delay = 4; + return true; } @@ -733,7 +799,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) @@ -800,7 +866,7 @@ bool ArduControl::MfxSearchTask::get_work(PendingCommand &cmd) info.address = next_address; info.name = format("%08X", bits); info.id = bits; - push_info(info); + queue.push(info); cmd.command[0] = MFX_ASSIGN_ADDRESS; cmd.command[1] = next_address>>8; @@ -863,27 +929,69 @@ void ArduControl::MfxSearchTask::process_reply(const char *reply, unsigned lengt } } -void ArduControl::MfxSearchTask::push_info(const MfxInfo &info) +void ArduControl::MfxSearchTask::set_next_address(unsigned a) { - MutexLock lock(mutex); - queue.push_back(info); + next_address = a; } bool ArduControl::MfxSearchTask::pop_info(MfxInfo &info) { - MutexLock lock(mutex); - if(queue.empty()) + return queue.pop(info); +} + + +ArduControl::MonitorTask::MonitorTask(): + voltage(0), + current(0), + base_level(0), + peak_level(0), + next_type(0) +{ } + +bool ArduControl::MonitorTask::get_work(PendingCommand &cmd) +{ + Time::TimeStamp t = Time::now(); + if(t(reply[1])<<8) | static_cast(reply[2]))/1000.0f; + else if(type==TRACK_CURRENT && length==5) + { + current = ((static_cast(reply[1])<<8) | static_cast(reply[2]))/1000.0f; + float peak = ((static_cast(reply[3])<<8) | static_cast(reply[4]))/1000.0f; + peak_level = max(peak_level, peak); + base_level = min(base_level, current); + } +} + +void ArduControl::MonitorTask::reset_peak() +{ + base_level = current; + peak_level = current; +} + ArduControl::ControlThread::ControlThread(ArduControl &c): control(c), done(false) { + tasks.push_back(&control.monitor); tasks.push_back(&control.mfx_announce); tasks.push_back(&control.mfx_search); tasks.push_back(&control.s88); @@ -911,7 +1019,7 @@ void ArduControl::ControlThread::main() for(unsigned i=0; (success && i=1) + IO::print("ArduControl detection failed\n"); + done = true; + return; + } + if(control.debug>=1) IO::print("ArduControl detected at %d bits/s\n", rate); @@ -953,9 +1069,9 @@ void ArduControl::ControlThread::init_baud_rate() if(do_command(cmd)==COMMAND_OK) { control.serial.set_baud_rate(rates[0]); + Time::sleep(Time::sec); if(do_command(cmd)==COMMAND_OK) { - Time::sleep(Time::sec); if(control.debug>=1) IO::print("Rate changed to %d bits/s\n", rates[0]); } @@ -965,7 +1081,7 @@ void ArduControl::ControlThread::init_baud_rate() 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) @@ -1052,7 +1168,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 { @@ -1063,4 +1179,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