]> git.tdb.fi Git - r2c2.git/blobdiff - source/libmarklin/intellibox.cpp
Make LCD output selectable at runtime through an extra I/O pin
[r2c2.git] / source / libmarklin / intellibox.cpp
index 416d02184e9564836361da811ef247a4777a0f3c..1dc2e7049c7cc2e94f3c34597872b35de5f29dd7 100644 (file)
@@ -94,11 +94,32 @@ void Intellibox::halt(bool h)
        signal_halt.emit(halted);
 }
 
-void Intellibox::add_loco(unsigned addr)
+const char *Intellibox::enumerate_protocols(unsigned i) const
 {
+       if(i==MM)
+               return "MM";
+       else if(i==MM_27)
+               return "MM-27";
+       return 0;
+}
+
+unsigned Intellibox::get_protocol_speed_steps(const string &proto_name) const
+{
+       Protocol proto = map_protocol(proto_name);
+       if(proto==MM)
+               return 14;
+       else if(proto==MM_27)
+               return 27;
+       return 0;
+}
+
+void Intellibox::add_loco(unsigned addr, const string &proto_name)
+{
+       Protocol proto = map_protocol(proto_name);
+
        if(!locos.count(addr))
        {
-               locos[addr];
+               locos[addr].protocol = proto;
 
                unsigned char data[2];
                data[0] = addr&0xFF;
@@ -111,12 +132,47 @@ void Intellibox::set_loco_speed(unsigned addr, unsigned speed)
 {
        Locomotive &loco = locos[addr];
        if(speed==loco.speed)
+       {
+               if(loco.pending_half_step)
+               {
+                       loco.pending_half_step = 0;
+                       loco.half_step_delay = Time::TimeStamp();
+                       signal_loco_speed.emit(addr, speed, loco.reverse);
+               }
                return;
+       }
        if(speed && halted)
                return;
 
+       if(loco.protocol==MM_27)
+       {
+               if(speed>27)
+                       speed = 27;
+
+               if(speed>loco.speed && !(speed&1))
+               {
+                       loco.pending_half_step = -1;
+                       speed |= 1;
+               }
+               else if(speed<loco.speed && (speed&1))
+               {
+                       loco.pending_half_step = 1;
+                       speed &= ~1;
+               }
+               else
+                       loco.pending_half_step = 0;
+               loco.half_step_delay = Time::TimeStamp();
+
+               loco_command(addr, (speed+1)/2, loco.reverse, loco.funcs|0x100);
+       }
+       else
+       {
+               if(speed>14)
+                       speed = 14;
+
+               loco_command(addr, speed, loco.reverse, loco.funcs|0x100);
+       }
        loco.speed = speed;
-       loco_command(addr, speed, loco.reverse, loco.funcs|0x100);
 }
 
 void Intellibox::set_loco_reverse(unsigned addr, bool rev)
@@ -201,6 +257,15 @@ void Intellibox::tick()
                command(CMD_EVENT);
        }
 
+       for(map<unsigned, Locomotive>::iterator i=locos.begin(); i!=locos.end(); ++i)
+               if(i->second.protocol==MM_27 && i->second.pending_half_step && i->second.half_step_delay && t>i->second.half_step_delay)
+               {
+                       i->second.speed += i->second.pending_half_step;
+                       i->second.pending_half_step = 0;
+                       i->second.half_step_delay = Time::TimeStamp();
+                       loco_command(i->first, (i->second.speed+1)/2, i->second.reverse, i->second.funcs|0x100);
+               }
+
        for(map<unsigned, Turnout>::iterator i=turnouts.begin(); i!=turnouts.end(); ++i)
                if(i->second.active && i->second.off_timeout && t>i->second.off_timeout)
                {
@@ -269,6 +334,16 @@ void Intellibox::flush()
        command_sent = false;
 }
 
+Intellibox::Protocol Intellibox::map_protocol(const string &name) const
+{
+       if(name=="MM")
+               return MM;
+       else if(name=="MM-27")
+               return MM_27;
+       else
+               throw InvalidParameterValue("Unknown protocol");
+}
+
 void Intellibox::command(Command cmd)
 {
        command(cmd, 0, 0);
@@ -423,7 +498,9 @@ void Intellibox::process_reply(const Time::TimeStamp &t)
                {
                        unsigned addr = queue.front().addr;
                        Locomotive &loco = locos[addr];
-                       signal_loco_speed.emit(addr, loco.speed, loco.reverse);
+                       signal_loco_speed.emit(addr, loco.speed+loco.pending_half_step, loco.reverse);
+                       if(loco.pending_half_step)
+                               loco.half_step_delay = Time::now()+500*Time::msec;
                }
                else
                        error(cmd, err);