]> git.tdb.fi Git - r2c2.git/blobdiff - source/libmarklin/train.cpp
Allow intercepting and denying turnout route and locomotive speed changes
[r2c2.git] / source / libmarklin / train.cpp
index f8ef1715dbc5aa6d7a6a33bd476bb9db510d0939..7d6afbae1f1c074ad281712ae43cde0be3888460 100644 (file)
@@ -10,6 +10,7 @@ Distributed under the GPL
 #include <msp/time/units.h>
 #include <msp/time/utils.h>
 #include "control.h"
+#include "except.h"
 #include "tracktype.h"
 #include "trafficmanager.h"
 #include "train.h"
@@ -38,6 +39,13 @@ Train::Train(TrafficManager &tm, Locomotive &l):
        const map<unsigned, Sensor *> &sensors=trfc_mgr.get_control().get_sensors();
        for(map<unsigned, Sensor *>::const_iterator i=sensors.begin(); i!=sensors.end(); ++i)
                i->second->signal_state_changed.connect(sigc::bind(sigc::mem_fun(this, &Train::sensor_event), i->second));
+
+       const map<unsigned, Turnout *> &turnouts=trfc_mgr.get_control().get_turnouts();
+       for(map<unsigned, Turnout *>::const_iterator i=turnouts.begin(); i!=turnouts.end(); ++i)
+       {
+               i->second->signal_route_changing.connect(sigc::bind(sigc::mem_fun(this, &Train::turnout_route_changing), i->second));
+               i->second->signal_route_changed.connect(sigc::bind(sigc::mem_fun(this, &Train::turnout_route_changed), i->second));
+       }
 }
 
 void Train::set_name(const string &n)
@@ -60,6 +68,8 @@ void Train::set_speed(unsigned speed)
                        i->block->reserve(0);
                rsv_blocks.clear();
        }
+       else
+               reserve_more();
 
        update_speed();
        pure_speed=false;
@@ -93,16 +103,24 @@ void Train::place(Block *block, unsigned entry)
 
 bool Train::free_block(Block *block)
 {
+       unsigned nsens=0;
        for(list<BlockRef>::iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
+       {
                if(i->block==block)
                {
+                       if(nsens<1)
+                               return false;
                        while(i!=rsv_blocks.end())
                        {
                                i->block->reserve(0);
                                i=rsv_blocks.erase(i);
                        }
+                       update_speed();
                        return true;
                }
+               else if(i->block->get_sensor_id())
+                       ++nsens;
+       }
 
        return false;
 }
@@ -110,7 +128,10 @@ bool Train::free_block(Block *block)
 void Train::tick(const Time::TimeStamp &t, const Time::TimeDelta &dt)
 {
        if(try_reserve && t>try_reserve)
+       {
+               reserve_more();
                update_speed();
+       }
 
        if(cur_track)
        {
@@ -193,7 +214,10 @@ void Train::sensor_event(bool state, Sensor *sensor)
                                set_position(i->block->get_endpoints()[i->entry]);
 
                if(target_speed)
+               {
+                       reserve_more();
                        update_speed();
+               }
        }
        else
        {
@@ -212,6 +236,44 @@ void Train::sensor_event(bool state, Sensor *sensor)
        }
 }
 
+void Train::turnout_route_changing(unsigned, Turnout *turnout)
+{
+       unsigned tid=turnout->get_address();
+       for(list<BlockRef>::const_iterator i=cur_blocks.begin(); i!=cur_blocks.end(); ++i)
+               if(i->block->get_turnout_id()==tid)
+                       throw TurnoutBusy(this);
+       
+       unsigned nsens=0;
+       for(list<BlockRef>::const_iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
+       {
+               if(i->block->get_turnout_id()==tid)
+               {
+                       if(nsens<1)
+                               throw TurnoutBusy(this);
+                       break;
+               }
+               else if(i->block->get_sensor_id())
+                       ++nsens;
+       }
+}
+
+void Train::turnout_route_changed(unsigned, Turnout *turnout)
+{
+       unsigned tid=turnout->get_address();
+       for(list<BlockRef>::iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
+               if(i->block->get_turnout_id()==tid)
+               {
+                       while(i!=rsv_blocks.end())
+                       {
+                               i->block->reserve(0);
+                               i=rsv_blocks.erase(i);
+                       }
+                       reserve_more();
+                       update_speed();
+                       return;
+               }
+}
+
 unsigned Train::reserve_more()
 {
        BlockRef *last=0;
@@ -274,15 +336,19 @@ void Train::update_speed()
        }
        else
        {
-               unsigned n=reserve_more();
-               if(n==0)
+               unsigned nsens=0;
+               for(list<BlockRef>::const_iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
+                       if(i->block->get_sensor_id())
+                               ++nsens;
+
+               if(nsens==0)
                {
                        loco.set_speed(0);
                        pure_speed=false;
                        try_reserve=Time::now()+2*Time::sec;
                        set_status("Blocked");
                }
-               else if(n==1)
+               else if(nsens==1 && target_speed>3)
                {
                        loco.set_speed(3);
                        pure_speed=false;