From 80e10207bee4d774f3015a5e946d463d2c828029 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Tue, 19 May 2009 18:46:03 +0000 Subject: [PATCH] Allow setting sensor ID for multiple tracks at once Support for controlling turnouts with more than 2 routes Snap flex-tracks last when loading a layout to get them correctly snapped Slow down trains when there's only one free sensor block ahead Put each turnout into its own block to avoid blocking adjacent tracks --- source/designer/designer.cpp | 40 ++++++++---- source/engineer/engineer.cpp | 5 +- source/libmarklin/block.cpp | 9 ++- source/libmarklin/layout.cpp | 17 ++++- source/libmarklin/trafficmanager.cpp | 5 +- source/libmarklin/train.cpp | 97 +++++++++++++++++++++------- source/libmarklin/train.h | 4 +- source/libmarklin/turnout.cpp | 38 ++++++++--- source/libmarklin/turnout.h | 7 +- 9 files changed, 161 insertions(+), 61 deletions(-) diff --git a/source/designer/designer.cpp b/source/designer/designer.cpp index 2913aea..5a7ee62 100644 --- a/source/designer/designer.cpp +++ b/source/designer/designer.cpp @@ -1,7 +1,7 @@ /* $Id$ This file is part of the MSP Märklin suite -Copyright © 2006-2008 Mikkosoft Productions, Mikko Rasa +Copyright © 2006-2009 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -385,11 +385,26 @@ void Designer::key_press(unsigned code, unsigned mod, wchar_t ch) } else if(key==Msp::Input::KEY_S) { - Track *track=selection->get_track(); - if(selection->size()==1 && track->get_type().get_n_routes()==1) + const set &tracks=selection->get_tracks(); + bool ok=false; + int id=-1; + for(set::const_iterator i=tracks.begin(); i!=tracks.end(); ++i) + { + if((*i)->get_type().get_n_routes()==1) + ok=true; + if(static_cast((*i)->get_sensor_id())!=id) + { + if(id==-1) + id=(*i)->get_sensor_id(); + else + id=-2; + } + } + if(ok) { ostringstream ss; - ss<get_sensor_id(); + if(id>=0) + ss<signal_cancel.connect(sigc::mem_fun(this, &Designer::input_dismiss)); input->signal_accept.connect(sigc::mem_fun(this, &Designer::sensor_id_accept)); @@ -654,15 +669,18 @@ void Designer::turnout_id_accept() void Designer::sensor_id_accept() { - Track *track=selection->get_track(); + const set &tracks=selection->get_tracks(); unsigned id=lexical_cast(input->get_text()); - track->set_sensor_id(id); + for(set::const_iterator i=tracks.begin(); i!=tracks.end(); ++i) + { + (*i)->set_sensor_id(id); - Track3D &t3d=layout_3d->get_track(*track); - if(id) - t3d.set_color(GL::Color(1, 1, 0.5)); - else - t3d.set_color(GL::Color(1, 1, 1)); + Track3D &t3d=layout_3d->get_track(**i); + if(id) + t3d.set_color(GL::Color(1, 1, 0.5)); + else + t3d.set_color(GL::Color(1, 1, 1)); + } input_dismiss(); } diff --git a/source/engineer/engineer.cpp b/source/engineer/engineer.cpp index ea87df6..fc6d75d 100644 --- a/source/engineer/engineer.cpp +++ b/source/engineer/engineer.cpp @@ -1,7 +1,7 @@ /* $Id$ This file is part of the MSP Märklin suite -Copyright © 2006-2008 Mikkosoft Productions, Mikko Rasa +Copyright © 2006-2009 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -19,6 +19,7 @@ Distributed under the GPL #include #include #include +#include "libmarklin/tracktype.h" #include "engineer.h" #include "mainpanel.h" #include "trainpanel.h" @@ -315,7 +316,7 @@ void Engineer::button_press(int x, int y, unsigned btn, unsigned) if(unsigned tid=track->get_track().get_turnout_id()) { Turnout &turnout=control.get_turnout(tid); - turnout.set_route(1-turnout.get_route()); + turnout.set_route((turnout.get_route()+1)%track->get_track().get_type().get_n_routes()); } else if(simulate) { diff --git a/source/libmarklin/block.cpp b/source/libmarklin/block.cpp index a304a15..03cb2dc 100644 --- a/source/libmarklin/block.cpp +++ b/source/libmarklin/block.cpp @@ -1,7 +1,7 @@ /* $Id$ This file is part of the MSP Märklin suite -Copyright © 2006-2008 Mikkosoft Productions, Mikko Rasa +Copyright © 2006-2009 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -38,7 +38,7 @@ Block::Block(TrafficManager &tm, Track &start): for(unsigned i=0; iget_sensor_id()==sensor_id) + if(links[i]->get_sensor_id()==sensor_id && !links[i]->get_turnout_id() && !track->get_turnout_id()) { queue.push_back(links[i]); tracks.insert(links[i]); @@ -100,11 +100,10 @@ int Block::traverse(unsigned epi, float *len) const return i; Track *next=track->get_link(other_ep); + if(tracks.count(next)==0) + return -1; track_ep=next->get_endpoint_by_link(*track); track=next; - - if(tracks.count(track)==0) - return -1; } } diff --git a/source/libmarklin/layout.cpp b/source/libmarklin/layout.cpp index 470d573..4835f2e 100644 --- a/source/libmarklin/layout.cpp +++ b/source/libmarklin/layout.cpp @@ -1,7 +1,7 @@ /* $Id$ This file is part of the MSP Märklin suite -Copyright © 2006-2008 Mikkosoft Productions, Mikko Rasa +Copyright © 2006-2009 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -47,8 +47,21 @@ void Layout::check_links() for(set::iterator i=tracks.begin(); i!=tracks.end(); ++i) (*i)->break_links(); + set flext; for(set::iterator i=tracks.begin(); i!=tracks.end(); ++i) - for(set::iterator j=i; j!=tracks.end(); ++j) + { + if((*i)->get_flex()) + flext.insert(*i); + else + { + for(set::iterator j=i; j!=tracks.end(); ++j) + if(j!=i) + (*i)->snap_to(**j, true); + } + } + + for(set::iterator i=flext.begin(); i!=flext.end(); ++i) + for(set::iterator j=tracks.begin(); j!=tracks.end(); ++j) if(j!=i) (*i)->snap_to(**j, true); } diff --git a/source/libmarklin/trafficmanager.cpp b/source/libmarklin/trafficmanager.cpp index 9666f12..4cc186b 100644 --- a/source/libmarklin/trafficmanager.cpp +++ b/source/libmarklin/trafficmanager.cpp @@ -1,7 +1,7 @@ /* $Id$ This file is part of the MSP Märklin suite -Copyright © 2006-2008 Mikkosoft Productions, Mikko Rasa +Copyright © 2006-2009 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -9,6 +9,7 @@ Distributed under the GPL #include #include "control.h" #include "layout.h" +#include "tracktype.h" #include "trafficmanager.h" #include "turnout.h" @@ -27,7 +28,7 @@ TrafficManager::TrafficManager(Control &c, Layout &l): for(set::const_iterator i=tracks.begin(); i!=tracks.end(); ++i) { if(unsigned tid=(*i)->get_turnout_id()) - new Turnout(control, tid); + new Turnout(control, tid, (*i)->get_type().get_n_routes()>=3); if(unsigned sid=(*i)->get_sensor_id()) new Sensor(control, sid); diff --git a/source/libmarklin/train.cpp b/source/libmarklin/train.cpp index a0943a7..4974318 100644 --- a/source/libmarklin/train.cpp +++ b/source/libmarklin/train.cpp @@ -1,7 +1,7 @@ /* $Id$ This file is part of the MSP Märklin suite -Copyright © 2006-2008 Mikkosoft Productions, Mikko Rasa +Copyright © 2006-2009 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -54,15 +54,31 @@ void Train::set_speed(unsigned speed) i->block->reserve(0); rsv_blocks.clear(); try_reserve=Time::TimeStamp(); + loco.set_speed(0); + if(old_speed) + set_status("Stopped"); + } + else + { + unsigned n=reserve_more(); + if(n==0) + { + try_reserve=Time::now()+2*Time::sec; + set_status("Blocked"); + } + else if(n==1) + { + loco.set_speed(3); + try_reserve=Time::now()+2*Time::sec; + set_status("Slow"); + } + else + { + loco.set_speed(speed); + if(!old_speed) + set_status("Traveling --- kmh"); + } } - else if(rsv_blocks.empty() && !reserve_more()) - return; - - loco.set_speed(speed); - if(!old_speed && target_speed) - set_status("Traveling --- kmh"); - else if(old_speed && !target_speed) - set_status("Stopped"); } void Train::place(Block *block, unsigned entry) @@ -110,12 +126,19 @@ void Train::tick(const Time::TimeStamp &t) { if(try_reserve && t>try_reserve) { - if(reserve_more() || !rsv_blocks.empty()) + unsigned n=reserve_more(); + if(n>=2) { loco.set_speed(target_speed); set_status("Traveling --- kmh"); try_reserve=Time::TimeStamp(); } + else if(n==1) + { + loco.set_speed(3); + set_status("Slow"); + try_reserve=t+2*Time::sec; + } else try_reserve=t+2*Time::sec; } @@ -151,19 +174,27 @@ void Train::sensor_event(bool state, Sensor *sensor) cout<<"Train "<::iterator i; - for(i=cur_blocks.begin(); i!=cur_blocks.end(); ++i) - { + for(list::iterator i=cur_blocks.begin(); i!=cur_blocks.end(); ++i) if(i->block->get_sensor_id()==addr) { ++i; @@ -173,14 +204,13 @@ void Train::sensor_event(bool state, Sensor *sensor) cur_blocks.erase(cur_blocks.begin(), i); cout<::const_iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i) + if(i->block->get_sensor_id()) + ++nsens; + bool result=false; - unsigned size=rsv_blocks.size(); - while(size<3) + while(nsens<2) { int exit=last->block->traverse(last->entry); if(exit>=0) @@ -204,8 +238,11 @@ bool Train::reserve_more() { rsv_blocks.push_back(BlockRef(link, link->get_endpoint_by_link(*last->block))); last=&rsv_blocks.back(); - ++size; - result=true; + if(last->block->get_sensor_id()) + { + ++nsens; + result=true; + } } else break; @@ -214,9 +251,19 @@ bool Train::reserve_more() break; } + while(last && !last->block->get_sensor_id()) + { + last->block->reserve(0); + rsv_blocks.erase(--rsv_blocks.end()); + if(!rsv_blocks.empty()) + last=&rsv_blocks.back(); + else + last=0; + } + cout<<" "<>8)&0xFF; - control.command(CMD_TURNOUT_STATUS, data, 2).signal_done.connect(sigc::mem_fun(this, &Turnout::status_reply)); + control.command(CMD_TURNOUT_STATUS, data, 2).signal_done.connect(sigc::bind(sigc::mem_fun(this, &Turnout::status_reply), false)); + if(dual) + { + data[0]=(addr+1)&0xFF; + data[1]=((addr+1)>>8)&0xFF; + control.command(CMD_TURNOUT_STATUS, data, 2).signal_done.connect(sigc::bind(sigc::mem_fun(this, &Turnout::status_reply), true)); + } } void Turnout::set_route(unsigned r) @@ -47,15 +54,23 @@ void Turnout::command(bool on) { unsigned char data[2]; data[0]=addr&0xFF; - data[1]=((addr>>8)&0x7) | (on ? 0x40 : 0) | (route==0 ? 0x80 : 0); + data[1]=((addr>>8)&0x7) | (on ? 0x40 : 0) | (route&1 ? 0 : 0x80); control.command(CMD_TURNOUT, data, 2); + if(dual) + { + data[0]=(addr+1)&0xFF; + data[1]=(((addr+1)>>8)&0x7) | (on ? 0x40 : 0) | (route&2 ? 0 : 0x80); + control.command(CMD_TURNOUT, data, 2); + } } -void Turnout::status_reply(const Reply &reply) +void Turnout::status_reply(const Reply &reply, bool high) { if(reply.get_error()==ERR_NO_ERROR) { - route=(reply.get_data()[0]&0x04) ? 0 : 1; + bool v=!(reply.get_data()[0]&0x04); + unsigned b=(high?2:1); + route=(route&~b)|(v?b:0); signal_route_changed.emit(route); } } @@ -69,9 +84,14 @@ bool Turnout::switch_timeout() void Turnout::turnout_event(unsigned a, bool r) { - if(a==addr && r!=route) + if(a==addr && r!=(route&1)) + { + route=(route&2)|(r?1:0); + signal_route_changed.emit(route); + } + else if(dual && a==addr+1 && r!=((route>>1)&1)) { - route=r; + route=(route&1)|(r?2:0); signal_route_changed.emit(route); } } diff --git a/source/libmarklin/turnout.h b/source/libmarklin/turnout.h index 82b50d5..ae68654 100644 --- a/source/libmarklin/turnout.h +++ b/source/libmarklin/turnout.h @@ -1,7 +1,7 @@ /* $Id$ This file is part of the MSP Märklin suite -Copyright © 2006-2008 Mikkosoft Productions, Mikko Rasa +Copyright © 2006-2009 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -25,18 +25,19 @@ private: Control &control; unsigned addr; unsigned route; + bool dual; public: sigc::signal signal_route_changed; - Turnout(Control &, unsigned); + Turnout(Control &, unsigned, bool =false); void set_route(unsigned); unsigned get_address() const { return addr; } unsigned get_route() const { return route; } private: void command(bool); - void status_reply(const Reply &); + void status_reply(const Reply &, bool); bool switch_timeout(); void turnout_event(unsigned, bool); }; -- 2.43.0