From 9b536a7197c424c3fa3809063c56da324b56dab2 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Mon, 1 Nov 2010 06:00:05 +0000 Subject: [PATCH] Add a path_changed signal to Track Keep blocks reserved while setting turnouts to avoid a race condition --- source/libmarklin/track.cpp | 4 ++ source/libmarklin/track.h | 2 + source/libmarklin/train.cpp | 134 ++++++++++++++++++++++-------------- source/libmarklin/train.h | 4 +- 4 files changed, 90 insertions(+), 54 deletions(-) diff --git a/source/libmarklin/track.cpp b/source/libmarklin/track.cpp index 6ec1c6c..9b63d5b 100644 --- a/source/libmarklin/track.cpp +++ b/source/libmarklin/track.cpp @@ -348,6 +348,10 @@ void Track::turnout_event(unsigned addr, bool state) active_path = (active_path&2) | (state ? 1 : 0); else if(type.is_double_address() && addr==turnout_id+1) active_path = (active_path&1) | (state ? 2 : 0); + else + return; + + signal_path_changed.emit(active_path); } diff --git a/source/libmarklin/track.h b/source/libmarklin/track.h index eaf8de2..e49fe67 100644 --- a/source/libmarklin/track.h +++ b/source/libmarklin/track.h @@ -33,6 +33,8 @@ public: void turnout_id(unsigned); }; + sigc::signal signal_path_changed; + private: Layout &layout; const TrackType &type; diff --git a/source/libmarklin/train.cpp b/source/libmarklin/train.cpp index 23c4b52..7030f38 100644 --- a/source/libmarklin/train.cpp +++ b/source/libmarklin/train.cpp @@ -47,6 +47,7 @@ Train::Train(Layout &l, const VehicleType &t, unsigned a): priority(0), yielding_to(0), cur_blocks_end(blocks.end()), + clear_blocks_end(blocks.end()), pending_block(0), reserving(false), advancing(false), @@ -78,10 +79,14 @@ Train::Train(Layout &l, const VehicleType &t, unsigned a): layout.signal_block_reserved.connect(sigc::mem_fun(this, &Train::block_reserved)); layout.get_driver().signal_sensor.connect(sigc::mem_fun(this, &Train::sensor_event)); - layout.get_driver().signal_turnout.connect(sigc::mem_fun(this, &Train::turnout_event)); layout.get_driver().signal_halt.connect(sigc::mem_fun(this, &Train::halt_event)); + const set &tracks = layout.get_tracks(); + for(set::const_iterator i=tracks.begin(); i!=tracks.end(); ++i) + if((*i)->get_turnout_id()) + (*i)->signal_path_changed.connect(sigc::hide(sigc::bind(sigc::mem_fun(this, &Train::turnout_path_changed), sigc::ref(**i)))); + controller->signal_control_changed.connect(sigc::mem_fun(this, &Train::control_changed)); } @@ -775,20 +780,16 @@ void Train::sensor_event(unsigned addr, bool state) } } -void Train::turnout_event(unsigned addr, bool) +void Train::turnout_path_changed(Track &track) { - if(pending_block && (!pending_block->get_train() || pending_block->get_train()==this)) - { - 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)) + for(list::iterator i=blocks.begin(); i!=blocks.end(); ++i) + if((*i)->get_turnout_id()==track.get_turnout_id()) { - if(reserving) - pending_block = 0; - else - reserve_more(); + if(!reserving) + check_turnout_paths(false); + else if(i==clear_blocks_end) + ++clear_blocks_end; } - } } void Train::halt_event(bool h) @@ -833,7 +834,7 @@ unsigned Train::reserve_more() float min_dist = controller->get_braking_distance()*1.3+approach_margin*2; BlockIter block = start; - BlockIter good = start; + list::iterator good_end = blocks.end(); Track *divert_track = 0; bool try_divert = false; unsigned good_sens = nsens; @@ -859,7 +860,7 @@ unsigned Train::reserve_more() // Keep the blocks if we arrived at the end of the route if(!blocking_train) { - good = last; + good_end = blocks.end(); good_sens = nsens; good_dist = dist; end_of_route = true; @@ -874,7 +875,7 @@ unsigned Train::reserve_more() { if(!blocking_train) { - good = last; + good_end = blocks.end(); good_sens = nsens; good_dist = dist; } @@ -931,7 +932,7 @@ unsigned Train::reserve_more() { /* The other train is not coming to the blocks we're holding, so we can keep them. */ - good = last; + good_end = blocks.end(); good_sens = nsens; good_dist = dist; } @@ -976,36 +977,11 @@ unsigned Train::reserve_more() points or if there was no turnout immediately before this one. With multiple successive turnouts (as is common in crossovers) it's best to hold at one we can divert from. */ - good = last; + good_end = blocks.end(); good_sens = nsens; good_dist = dist; } - // Figure out what path we'd like to take on the turnout - int path = -1; - for(list::iterator i=cur_route; (path<0 && i!=routes.end()); ++i) - path = i->route->get_turnout(block->get_turnout_id()); - if(path<0) - path = track->get_active_path(); - if(!(track_ep.paths&(1<>i; ++i) - if(track_ep.paths&(1<(track->get_active_path())) - { - // The turnout is set to wrong path - switch and wait for it - pending_block = &*block; - track->set_active_path(path); - if(pending_block) - { - block->reserve(0); - break; - } - } - if(multiple_paths && cur_route!=routes.end() && cur_route->diversion!=block->get_turnout_id()) /* There's multiple paths to be taken and we are on a route - take note of the diversion possibility */ @@ -1016,8 +992,14 @@ unsigned Train::reserve_more() contested_blocks.pop_front(); blocks.push_back(block); + if(cur_blocks_end==blocks.end()) --cur_blocks_end; + if(clear_blocks_end==blocks.end()) + --clear_blocks_end; + if(good_end==blocks.end()) + --good_end; + if(block->get_sensor_id()) ++nsens; if(nsens>0) @@ -1025,18 +1007,14 @@ unsigned Train::reserve_more() } // Unreserve blocks that were not good - while(blocks.end()!=cur_blocks_end && blocks.back()!=good) - { - if(--blocks.end()==cur_blocks_end) - cur_blocks_end = blocks.end(); - blocks.back()->reserve(0); - blocks.pop_back(); - } + release_blocks(good_end, blocks.end()); - if(!blocks.back()!=start) + if(blocks.back()!=start) // We got some new blocks, so no longer need to yield yielding_to = 0; + check_turnout_paths(true); + // Make any sensorless blocks at the beginning immediately current while(cur_blocks_end!=blocks.end() && !(*cur_blocks_end)->get_sensor_id()) ++cur_blocks_end; @@ -1047,6 +1025,54 @@ unsigned Train::reserve_more() return good_sens; } +void Train::check_turnout_paths(bool set) +{ + if(clear_blocks_end==blocks.end()) + return; + + list::iterator route = routes.begin(); + + for(list::iterator i=clear_blocks_end; i!=blocks.end(); ++i) + { + advance_route(route, *i->track_iter()); + + if((*i)->get_turnout_id()) + { + TrackIter track = i->track_iter(); + const TrackType::Endpoint &track_ep = track->get_type().get_endpoints()[track.entry()]; + + int path = -1; + for(list::iterator j=route; (path<0 && j!=routes.end()); ++j) + path = j->route->get_turnout((*i)->get_turnout_id()); + if(path<0) + path = track->get_active_path(); + if(!(track_ep.paths&(1<::iterator j = i; + if(++j!=blocks.end()) + { + TrackIter rev = j->track_iter().flip(); + unsigned mask = rev->get_type().get_endpoints()[rev.entry()].paths&track_ep.paths; + for(path=0; mask>1; mask>>=1, ++path) ; + } + else + return; + } + + if(path!=static_cast(track->get_active_path())) + { + if(set) + track->set_active_path(path); + + continue; + } + } + + if(i==clear_blocks_end) + ++clear_blocks_end; + } +} + float Train::get_reserved_distance_until(const Block *until_block, bool back) const { if(blocks.empty()) @@ -1060,9 +1086,9 @@ float Train::get_reserved_distance_until(const Block *until_block, bool back) co return 0; BlockList::const_iterator block = blocks.begin(); - while(block!=blocks.end() && !(*block)->has_track(*track)) + while(block!=clear_blocks_end && !(*block)->has_track(*track)) ++block; - if(block==blocks.end() || &**block==until_block) + if(block==clear_blocks_end || &**block==until_block) return 0; float result = veh.get_offset(); @@ -1089,7 +1115,7 @@ float Train::get_reserved_distance_until(const Block *until_block, bool back) co else { ++block; - if(block==blocks.end()) + if(block==clear_blocks_end) break; } @@ -1190,6 +1216,8 @@ void Train::release_blocks(BlockList::iterator begin, BlockList::iterator end) { if(begin==cur_blocks_end) cur_blocks_end = end; + if(begin==clear_blocks_end) + clear_blocks_end = end; Block &block = **begin; blocks.erase(begin++); diff --git a/source/libmarklin/train.h b/source/libmarklin/train.h index d637cc0..87fd4a5 100644 --- a/source/libmarklin/train.h +++ b/source/libmarklin/train.h @@ -81,6 +81,7 @@ private: std::vector vehicles; BlockList blocks; BlockList::iterator cur_blocks_end; + BlockList::iterator clear_blocks_end; Block *pending_block; bool reserving; bool advancing; @@ -157,10 +158,11 @@ private: void loco_speed_event(unsigned, unsigned, bool); void loco_func_event(unsigned, unsigned, bool); void sensor_event(unsigned, bool); - void turnout_event(unsigned, bool); + void turnout_path_changed(Track &); void halt_event(bool); void block_reserved(const Block &, const Train *); unsigned reserve_more(); + void check_turnout_paths(bool); float get_reserved_distance_until(const Block *, bool) const; float get_real_speed(unsigned) const; unsigned find_speed(float) const; -- 2.43.0