]> git.tdb.fi Git - r2c2.git/blobdiff - source/libmarklin/train.cpp
Use RAII for setting the anti-recursion flags
[r2c2.git] / source / libmarklin / train.cpp
index 920ae4ab37e678a64ae5c54a5b8953b545a3e61c..8166c09a86944d1bb4251dec61a38819d08b8920 100644 (file)
@@ -24,6 +24,19 @@ Distributed under the GPL
 using namespace std;
 using namespace Msp;
 
+namespace {
+
+struct SetFlag
+{
+       bool &flag;
+
+       SetFlag(bool &f): flag(f) { flag = true; }
+       ~SetFlag() { flag = false; }
+};
+
+}
+
+
 namespace Marklin {
 
 Train::Train(Layout &l, const VehicleType &t, unsigned a):
@@ -32,6 +45,8 @@ Train::Train(Layout &l, const VehicleType &t, unsigned a):
        address(a),
        priority(0),
        pending_block(0),
+       reserving(false),
+       advancing(false),
        controller(new AIControl(*this, new SimpleController)),
        timetable(0),
        active(false),
@@ -200,7 +215,7 @@ void Train::set_route(const Route *r)
        next_route = 0;
        end_of_route = false;
 
-       if(route)
+       if(route && !cur_blocks.empty())
        {
                BlockRef &last = (rsv_blocks.empty() ? cur_blocks.back() : rsv_blocks.back());
                BlockRef next = last.next();
@@ -272,7 +287,7 @@ void Train::place(Block &block, unsigned entry)
        else
        {
                const Block::Endpoint &bep = block.get_endpoints()[entry];
-               vehicles.front()->place(bep.track, bep.track_ep, 0, Vehicle::BACK_BUFFER);
+               vehicles.back()->place(bep.track, bep.track_ep, 0, Vehicle::BACK_BUFFER);
        }
 }
 
@@ -308,6 +323,9 @@ int Train::get_entry_to_block(Block &block) const
 
 float Train::get_reserved_distance() const
 {
+       if(cur_blocks.empty())
+               return 0;
+
        Vehicle &veh = *(reverse ? vehicles.back() : vehicles.front());
        const VehicleType &vtype = veh.get_type();
 
@@ -407,7 +425,10 @@ void Train::tick(const Time::TimeStamp &t, const Time::TimeDelta &dt)
 
                float d = get_real_speed(current_speed)*(dt/Time::sec);
                if(ok)
+               {
+                       SetFlag setf(advancing);
                        vehicle.advance(reverse ? -d : d);
+               }
                else if(accurate_position)
                {
                        overshoot_dist += d;
@@ -435,7 +456,10 @@ void Train::tick(const Time::TimeStamp &t, const Time::TimeDelta &dt)
                unsigned entry = bep.track_ep;
 
                bool found = false;
-               float dist = veh.get_offset()-veh.get_type().get_length()/2;
+               float dist = veh.get_offset();
+               if(reverse)
+                       dist = veh.get_track()->get_type().get_path_length(veh.get_track()->get_active_path())-dist;
+               dist -= veh.get_type().get_length()/2;
                while(1)
                {
                        if(track==veh.get_track())
@@ -514,7 +538,7 @@ void Train::save(list<DataFile::Statement> &st) const
        }
 }
 
-void Train::control_changed(const TrainControl &ctrl)
+void Train::control_changed(const Controller::Control &ctrl)
 {
        signal_control_changed.emit(ctrl.name, ctrl.value);
 }
@@ -589,7 +613,7 @@ void Train::sensor_event(unsigned addr, bool state)
                                j->block->traverse(j->entry, &block_len);
                                travel_dist += block_len;
 
-                               if(j->block->get_sensor_id()==addr)
+                               if(j->block->get_sensor_id()==addr && !advancing)
                                {
                                        const Block::Endpoint &bep = j->block->get_endpoints()[j->entry];
                                        if(reverse)
@@ -648,7 +672,7 @@ void Train::sensor_event(unsigned addr, bool state)
                                }
                        }
                
-               if(end!=cur_blocks.begin())
+               if(end!=cur_blocks.begin() && end!=cur_blocks.end())
                        // Free blocks up to the last inactive sensor
                        release_blocks(cur_blocks, cur_blocks.begin(), end);
        }
@@ -661,7 +685,12 @@ void Train::turnout_event(unsigned addr, bool)
                unsigned pending_addr = pending_block->get_turnout_id();
                bool double_addr = (*pending_block->get_tracks().begin())->get_type().is_double_address();
                if(addr==pending_addr || (double_addr && addr==pending_addr+1))
-                       reserve_more();
+               {
+                       if(reserving)
+                               pending_block = 0;
+                       else
+                               reserve_more();
+               }
        }
 }
 
@@ -714,6 +743,8 @@ unsigned Train::reserve_more()
                }
        }
 
+       SetFlag setf(reserving);
+
        bool got_more = false;
        BlockRef *good = last;
        unsigned good_sens = nsens;
@@ -802,10 +833,13 @@ unsigned Train::reserve_more()
                        if(path!=static_cast<int>(entry_ep.track->get_active_path()))
                        {
                                // The turnout is set to wrong path - switch and wait for it
-                               link->reserve(0);
                                pending_block = link;
                                entry_ep.track->set_active_path(path);
-                               break;
+                               if(pending_block)
+                               {
+                                       link->reserve(0);
+                                       break;
+                               }
                        }
                }
 
@@ -827,6 +861,7 @@ unsigned Train::reserve_more()
                        last = &rsv_blocks.back();
        }
 
+
        // Make any sensorless blocks at the beginning immediately current
        list<BlockRef>::iterator i;
        for(i=rsv_blocks.begin(); (i!=rsv_blocks.end() && !i->block->get_sensor_id()); ++i) ;