]> git.tdb.fi Git - r2c2.git/blobdiff - source/libr2c2/intellibox.cpp
Cosmetic fixes
[r2c2.git] / source / libr2c2 / intellibox.cpp
index 7702ed6b1bdde49b9309c2da9ef72f54fd3e2ae6..3f3edf2aad00774b7262fbe0fe9a3f94c71a9787 100644 (file)
@@ -1,13 +1,4 @@
-/* $Id$
-
-This file is part of R²C²
-Copyright © 2010  Mikkosoft Productions, Mikko Rasa
-Distributed under the GPL
-*/
-
-#include <fcntl.h>
-#include <termios.h>
-#include <sys/poll.h>
+#include <msp/core/maputils.h>
 #include <msp/io/print.h>
 #include <msp/time/units.h>
 #include <msp/time/utils.h>
@@ -20,55 +11,39 @@ using namespace Msp;
 
 namespace R2C2 {
 
-Intellibox::Intellibox(const string &dev):
+Intellibox::Intellibox(const Options &opts):
+       serial(opts.get<string>(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);
+               serial.set_baud_rate(baud[i]);
+               serial.put('\xC4');
 
-               write(serial_fd, "\xC4", 1);
-
-               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 +91,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 +110,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 +197,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 +229,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<<turnout.bits)-1;
-       if(((state^turnout.state)&mask)==0 || ((state^turnout.pending)&mask)==0)
+       if(((state^turnout.state)&mask)==0 || ((state^turnout.pending)&mask)==0 || !turnout.synced)
        {
                turnout.state = state;
                turnout.pending = state;
-               signal_turnout.emit(addr, state);
+               turnout_state_changed(addr, turnout);
                return;
        }
 
@@ -268,13 +271,41 @@ unsigned Intellibox::get_turnout(unsigned addr) const
        return 0;
 }
 
-void Intellibox::add_sensor(unsigned addr)
+unsigned Intellibox::add_signal(unsigned addr, const SignalType &)
+{
+       return add_turnout(addr, 1, true);
+}
+
+void Intellibox::remove_signal(unsigned addr)
+{
+       remove_turnout(addr);
+}
+
+void Intellibox::set_signal(unsigned addr, unsigned state)
+{
+       set_turnout(addr, state);
+}
+
+unsigned Intellibox::get_signal(unsigned addr) const
+{
+       return get_turnout(addr);
+}
+
+unsigned Intellibox::add_sensor(unsigned addr)
 {
        if(!sensors.count(addr))
        {
                sensors[addr];
                update_sensors = true;
        }
+
+       return addr;
+}
+
+void Intellibox::remove_sensor(unsigned addr)
+{
+       sensors.erase(addr);
+       update_sensors = true;
 }
 
 bool Intellibox::get_sensor(unsigned addr) const
@@ -285,6 +316,11 @@ bool Intellibox::get_sensor(unsigned addr) const
        return false;
 }
 
+float Intellibox::get_telemetry_value(const string &name) const
+{
+       throw key_error(name);
+}
+
 void Intellibox::tick()
 {
        const Time::TimeStamp t = Time::now();
@@ -334,8 +370,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());
@@ -348,23 +383,21 @@ void Intellibox::tick()
        if(!queue.empty())
        {
                const CommandSlot &slot = queue.front();
-               write(serial_fd, slot.data, slot.length);
+               serial.write(reinterpret_cast<const char *>(slot.data), slot.length);
                command_sent = true;
        }
 }
 
 void Intellibox::flush()
 {
-       Time::TimeStamp t = Time::now();
        for(list<CommandSlot>::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<const char *>(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;
                }
        }
@@ -380,7 +413,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)
@@ -498,7 +531,7 @@ void Intellibox::process_reply(const Time::TimeStamp &t)
                        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)
@@ -567,7 +600,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;
                        }
                }
@@ -599,8 +632,10 @@ void Intellibox::process_reply(const Time::TimeStamp &t)
                        {
                                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);
@@ -620,24 +655,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<<i))
-                                               signal_loco_function.emit(addr, i, loco.funcs&(1<<i));
-                       }
+                       unsigned funcs_changed = loco.funcs^funcs;
+                       loco.funcs = funcs;
+
+                       if(speed_changed)
+                               signal_loco_speed.emit(addr, loco.speed, loco.reverse);
+                       for(unsigned i=0; i<5; ++i)
+                               if(funcs_changed&(1<<i))
+                                       signal_loco_function.emit(addr, i, loco.funcs&(1<<i));
                }
                else
                        error(cmd, err);
@@ -669,7 +702,7 @@ unsigned Intellibox::read_all(unsigned char *buf, unsigned len)
 {
        unsigned pos = 0;
        while(pos<len)
-               pos += read(serial_fd, buf+pos, len-pos);
+               pos += serial.read(reinterpret_cast<char *>(buf+pos), len-pos);
 
        return pos;
 }
@@ -737,10 +770,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)
 { }
 
 
@@ -748,7 +783,9 @@ Intellibox::Turnout::Turnout():
        bits(1),
        state(0),
        active(false),
-       pending(false)
+       synced(false),
+       pending(0),
+       signal(false)
 { }