X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Flibr2c2%2Farducontrol.cpp;h=3d49fabf4784c6b02ac278d67d4086b5f6d0e918;hb=6887e5cf8bcb6578309e09136172f445cf1f619b;hp=6d75c7542dd0490fb3cde74b8b2e771560636eb1;hpb=85dba3e775b10d1a653175318e79881e416db19a;p=r2c2.git diff --git a/source/libr2c2/arducontrol.cpp b/source/libr2c2/arducontrol.cpp index 6d75c75..3d49fab 100644 --- a/source/libr2c2/arducontrol.cpp +++ b/source/libr2c2/arducontrol.cpp @@ -18,6 +18,14 @@ ArduControl::ProtocolInfo ArduControl::protocol_info[2] = { 0x3FFF, 126, 15 } // MFX }; +Driver::TelemetryInfo ArduControl::telemetry_info[4] = +{ + { "voltage", "Voltage", "V", 1 }, + { "current", "Current", "A", 2 }, + { "cmd-queue-depth", "Cmd queue", "", 0 }, + { "s88-latency", "S88 latency", "ms", 0 } +}; + ArduControl::ArduControl(const Options &opts): serial(opts.get(string(), "ttyUSB0")), debug(opts.get("debug")), @@ -327,6 +335,28 @@ bool ArduControl::get_sensor(unsigned addr) const return get_item(sensors, addr).state; } +const Driver::TelemetryInfo *ArduControl::enumerate_telemetry(unsigned i) const +{ + if(i<4) + return telemetry_info+i; + else + return 0; +} + +float ArduControl::get_telemetry_value(const string &name) const +{ + if(name==telemetry_info[0].name) + return monitor.get_voltage(); + else if(name==telemetry_info[1].name) + return monitor.get_current(); + else if(name==telemetry_info[2].name) + return command_queue.size(); + else if(name==telemetry_info[3].name) + return s88.get_latency()/Time::msec; + else + throw key_error(name); +} + void ArduControl::tick() { Tag tag; @@ -695,6 +725,12 @@ bool ArduControl::Queue::pop(T &item) return true; } +template +unsigned ArduControl::Queue::size() const +{ + return items.size(); +} + template bool ArduControl::Queue::empty() const { @@ -702,7 +738,35 @@ bool ArduControl::Queue::empty() const } +bool ArduControl::CommandQueueTask::get_work(PendingCommand &cmd) +{ + return queue.pop(cmd); +} + +void ArduControl::CommandQueueTask::push(const PendingCommand &cmd) +{ + queue.push(cmd); +} + + +ArduControl::Task::Task(const string &n, unsigned p): + name(n), + priority(p) +{ } + +void ArduControl::Task::sleep(const Time::TimeDelta &dt) +{ + sleep_timeout = Time::now()+dt; +} + + +ArduControl::CommandQueueTask::CommandQueueTask(): + Task("CommandQueue") +{ } + + ArduControl::RefreshTask::RefreshTask(): + Task("Refresh", 2), next(cycle.end()), round(0), loco(0), @@ -789,35 +853,35 @@ void ArduControl::RefreshTask::advance() ++next; if(next==cycle.end()) { - next= cycle.begin(); + next = cycle.begin(); ++round; } } ArduControl::S88Task::S88Task(ArduControl &c): + Task("S88"), control(c), n_octets(0), - octets_remaining(0), - delay(0) + octets_remaining(0) { } bool ArduControl::S88Task::get_work(PendingCommand &cmd) { - if(delay) - { - --delay; - return false; - } if(octets_remaining || !n_octets) return false; + Time::TimeStamp t = Time::now(); + if(last_poll) + latency = t-last_poll; + last_poll = t; + octets_remaining = n_octets; cmd.command[0] = S88_READ; cmd.command[1] = octets_remaining; cmd.length = 2; - delay = 4; + sleep(100*Time::msec); return true; } @@ -866,20 +930,18 @@ void ArduControl::S88Task::grow_n_octets(unsigned n) ArduControl::MfxAnnounceTask::MfxAnnounceTask(): + Task("MfxAnnounce", 1), serial(0) { } bool ArduControl::MfxAnnounceTask::get_work(PendingCommand &cmd) { - Time::TimeStamp t = Time::now(); - if(t>8; cmd.command[2] = serial; cmd.length = 3; - next = t+400*Time::msec; + + sleep(400*Time::msec); return true; } @@ -891,26 +953,63 @@ void ArduControl::MfxAnnounceTask::set_serial(unsigned s) ArduControl::MfxSearchTask::MfxSearchTask(ArduControl &c): + Task("MfxSearch", 1), control(c), next_address(1), size(0), bits(0), - misses(0) + misses(0), + pending_info(0), + read_array(0), + read_offset(0), + read_length(0), + block_size(0) { } bool ArduControl::MfxSearchTask::get_work(PendingCommand &cmd) { + if(read_length>0) + { + cmd.command[0] = MFX_READ; + cmd.command[1] = pending_info->address>>8; + cmd.command[2] = pending_info->address; + unsigned index = read_array*0x40+read_offset; + cmd.command[3] = index>>8; + cmd.command[4] = index; + unsigned length = (read_length>=4 ? 4 : read_length>=2 ? 2 : 1); + cmd.command[5] = length; + cmd.length = 6; + + sleep(100*Time::msec); + + return true; + } + else if(pending_info) + { + queue.push(*pending_info); + Tag tag; + tag.type = Tag::GENERAL; + tag.command = NEW_LOCO; + tag.id = pending_info->id; + control.completed_commands.push(tag); + + if(control.debug>=1) + IO::print("Completed processing locomotive %s at address %d\n", pending_info->name, pending_info->address); + + delete pending_info; + pending_info = 0; + } + if(size>32) { 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); + pending_info = new MfxInfo; + pending_info->protocol = "MFX"; + pending_info->address = next_address; + pending_info->name = format("%08X", bits); + pending_info->id = bits; cmd.command[0] = MFX_ASSIGN_ADDRESS; cmd.command[1] = next_address>>8; @@ -919,28 +1018,25 @@ 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; + misses = 0; ++next_address; + read_array = 0; + read_offset = 0; + read_length = 6; + return true; } - Time::TimeStamp t = Time::now(); - if(t>(24-i*8); cmd.command[5] = size; cmd.length = 6; - next = t+200*Time::msec; + sleep(100*Time::msec); if(control.debug>=1) IO::print("Search %08X/%d\n", bits, size); @@ -965,12 +1061,72 @@ void ArduControl::MfxSearchTask::process_reply(const char *reply, unsigned lengt } else { - next = Time::now()+2*Time::sec; + sleep(2*Time::sec); bits = 0; size = 0; misses = 0; } } + else if(type==MFX_READ_FEEDBACK && length>=3) + { + if(reply[1]) + { + misses = 0; + + for(unsigned i=2; i(read_data[4])*static_cast(read_data[5]); + + bool array_handled = false; + if(read_data[0]==0x18) + { + for(unsigned i=1; iname = string(read_data+1, i-1); + array_handled = true; + break; + } + + if(!array_handled) + read_length = 4; + } + else + array_handled = true; + + if(array_handled && control.debug>=1) + { + IO::print("MFX CA %03X:", read_array); + for(unsigned i=0; i(read_data[i])); + IO::print("\n"); + } + + if(array_handled && read_array=10) + { + if(control.debug>=1) + IO::print("Failed to read MFX configuration from %d\n", pending_info->address); + read_length = 0; + } + } + } } void ArduControl::MfxSearchTask::set_next_address(unsigned a) @@ -985,6 +1141,7 @@ bool ArduControl::MfxSearchTask::pop_info(MfxInfo &info) ArduControl::MonitorTask::MonitorTask(): + Task("Monitor"), voltage(0), current(0), base_level(0), @@ -994,17 +1151,13 @@ ArduControl::MonitorTask::MonitorTask(): bool ArduControl::MonitorTask::get_work(PendingCommand &cmd) { - Time::TimeStamp t = Time::now(); - if(tget_sleep_timeout()<=t); ++count) ; + + for(; count>0; --count) + { + unsigned i = 0; + for(unsigned j=1; jget_priority()get_priority()) + i = j; - for(vector::iterator i=tasks.begin(); i!=tasks.end(); ++i) - if((*i)->get_work(cmd)) + Task *task = tasks[i]; + bool result = task->get_work(cmd); + + Time::TimeStamp st = max(task->get_sleep_timeout(), t); + for(; (i+1get_sleep_timeout()<=st); ++i) + tasks[i] = tasks[i+1]; + tasks[i] = task; + + if(result) + { + if(control.debug>=2) + IO::print("Scheduled task %s\n", task->get_name()); return true; + } + } // As fallback, send an idle packet for the MM protocol cmd.command[0] = MOTOROLA_SPEED;