]> git.tdb.fi Git - r2c2.git/commitdiff
Add support for MM-27 protocol in Intellibox driver
authorMikko Rasa <tdb@tdb.fi>
Mon, 15 Nov 2010 21:06:46 +0000 (21:06 +0000)
committerMikko Rasa <tdb@tdb.fi>
Mon, 15 Nov 2010 21:06:46 +0000 (21:06 +0000)
Use an enum instead of string for storing train protocol
Fix an off-by-one error in Train

source/libmarklin/intellibox.cpp
source/libmarklin/intellibox.h
source/libmarklin/train.cpp

index bbe6781cd6b85d8090c3ed534989dec4460e4713..1dc2e7049c7cc2e94f3c34597872b35de5f29dd7 100644 (file)
@@ -96,21 +96,27 @@ void Intellibox::halt(bool h)
 
 const char *Intellibox::enumerate_protocols(unsigned i) const
 {
-       if(i==0)
+       if(i==MM)
                return "MM";
+       else if(i==MM_27)
+               return "MM-27";
        return 0;
 }
 
-unsigned Intellibox::get_protocol_speed_steps(const string &proto) const
+unsigned Intellibox::get_protocol_speed_steps(const string &proto_name) const
 {
-       if(proto=="MM")
+       Protocol proto = map_protocol(proto_name);
+       if(proto==MM)
                return 14;
-       else
-               throw InvalidParameterValue("Unknown protocol");
+       else if(proto==MM_27)
+               return 27;
+       return 0;
 }
 
-void Intellibox::add_loco(unsigned addr, const string &proto)
+void Intellibox::add_loco(unsigned addr, const string &proto_name)
 {
+       Protocol proto = map_protocol(proto_name);
+
        if(!locos.count(addr))
        {
                locos[addr].protocol = proto;
@@ -126,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)
@@ -216,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)
                {
@@ -284,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);
@@ -438,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);
index 565d3cbd1e23f9bb249f9a9289c389282a31f443..6d061a6076bb6a07b04cc843c257a1df95680ada 100644 (file)
@@ -14,6 +14,16 @@ Distributed under the GPL
 
 namespace Marklin {
 
+/**
+Driver for Uhlenbrock Intellibox.  Uses the P50X binary protocol over RS232.
+
+Motorola decoders with 27 speed steps are supported by manually generating the
+commands necessary to reach the "half-steps".  However, sending a rapid stream
+of speed changes to the same locomotive seems to cause excessive lag, so we
+cheat a bit; instead of sending the half-step command immediately, we send it
+with a 500ms delay, but only if no new set_loco_speed calls have occurred.  As
+a downside from this accelerations and decelerations are still jerky.
+*/
 class Intellibox: public Driver
 {
 private:
@@ -61,12 +71,20 @@ private:
                ERR_LOK_POWER_OFF,
        };
 
+       enum Protocol
+       {
+               MM,
+               MM_27
+       };
+
        struct Locomotive
        {
-               std::string protocol;
+               Protocol protocol;
                unsigned speed;
                bool reverse;
                unsigned funcs;
+               int pending_half_step;
+               Msp::Time::TimeStamp half_step_delay;
 
                Locomotive();
        };
@@ -135,6 +153,7 @@ public:
        virtual void flush();
 
 private:
+       Protocol map_protocol(const std::string &) const;
        void command(Command);
        void command(Command, const unsigned char *, unsigned);
        void command(Command, unsigned, const unsigned char *, unsigned);
index 0084f38fab8d4764c79c15873134b9f4a31d3049..859d3daea7988ea7544eb111cb72964613e7a8cd 100644 (file)
@@ -1109,7 +1109,7 @@ float Train::get_real_speed(unsigned i) const
        for(low=i; low>0; --low)
                if(real_speed[low].weight)
                        break;
-       for(high=i; high<real_speed.size(); ++high)
+       for(high=i; high+1<real_speed.size(); ++high)
                if(real_speed[high].weight)
                        break;