]> git.tdb.fi Git - r2c2.git/blob - source/libmarklin/train.cpp
Only signal turnout path change when the command is successfully completed
[r2c2.git] / source / libmarklin / train.cpp
1 /* $Id$
2
3 This file is part of the MSP Märklin suite
4 Copyright © 2006-2009 Mikkosoft Productions, Mikko Rasa
5 Distributed under the GPL
6 */
7
8 #include <cmath>
9 #include <msp/strings/formatter.h>
10 #include <msp/time/units.h>
11 #include <msp/time/utils.h>
12 #include "control.h"
13 #include "except.h"
14 #include "route.h"
15 #include "tracktype.h"
16 #include "trafficmanager.h"
17 #include "train.h"
18
19 using namespace std;
20 using namespace Msp;
21
22 namespace Marklin {
23
24 Train::Train(TrafficManager &tm, Locomotive &l):
25         trfc_mgr(tm),
26         loco(l),
27         pending_block(0),
28         target_speed(0),
29         status("Unplaced"),
30         travel_dist(0),
31         travel_speed(0),
32         pure_speed(false),
33         real_speed(15),
34         cur_track(0)
35 {
36         trfc_mgr.add_train(this);
37
38         loco.signal_reverse_changed.connect(sigc::mem_fun(this, &Train::locomotive_reverse_changed));
39
40         const map<unsigned, Sensor *> &sensors = trfc_mgr.get_control().get_sensors();
41         for(map<unsigned, Sensor *>::const_iterator i=sensors.begin(); i!=sensors.end(); ++i)
42                 i->second->signal_state_changed.connect(sigc::bind(sigc::mem_fun(this, &Train::sensor_event), i->second));
43
44         const map<unsigned, Turnout *> &turnouts = trfc_mgr.get_control().get_turnouts();
45         for(map<unsigned, Turnout *>::const_iterator i=turnouts.begin(); i!=turnouts.end(); ++i)
46         {
47                 i->second->signal_path_changing.connect(sigc::bind(sigc::mem_fun(this, &Train::turnout_path_changing), i->second));
48                 i->second->signal_path_changed.connect(sigc::bind(sigc::mem_fun(this, &Train::turnout_path_changed), i->second));
49         }
50 }
51
52 void Train::set_name(const string &n)
53 {
54         name = n;
55
56         signal_name_changed.emit(name);
57 }
58
59 void Train::set_speed(unsigned speed)
60 {
61         if(speed==target_speed)
62                 return;
63         travel_speed = static_cast<int>(round(get_real_speed(speed)*87*3.6/5))*5;
64
65         target_speed = speed;
66         if(!target_speed)
67         {
68                 trfc_mgr.get_control().set_timer(3*Time::sec).signal_timeout.connect(
69                         sigc::bind_return(sigc::mem_fun(this, &Train::release_reserved_blocks), false));
70         }
71         else
72                 reserve_more();
73
74         signal_target_speed_changed.emit(target_speed);
75
76         update_speed();
77         pure_speed = false;
78 }
79
80 void Train::set_reverse(bool rev)
81 {
82         loco.set_reverse(rev);
83 }
84
85 void Train::set_route(const Route *r)
86 {
87         route = r;
88         signal_route_changed.emit(route);
89 }
90
91 void Train::place(Block *block, unsigned entry)
92 {
93         for(list<BlockRef>::iterator i=rsv_blocks.begin(); i!=rsv_blocks.end();)
94         {
95                 i->block->reserve(0);
96                 i = rsv_blocks.erase(i);
97         }
98
99         for(list<BlockRef>::iterator i=cur_blocks.begin(); i!=cur_blocks.end();)
100         {
101                 i->block->reserve(0);
102                 i = cur_blocks.erase(i);
103         }
104
105         if(!block->reserve(this))
106         {
107                 set_status("Unplaced");
108                 return;
109         }
110
111         cur_blocks.push_back(BlockRef(block, entry));
112         set_position(block->get_endpoints()[entry]);
113
114         set_status("Stopped");
115 }
116
117 bool Train::free_block(Block *block)
118 {
119         unsigned nsens = 0;
120         for(list<BlockRef>::iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
121         {
122                 if(i->block==block)
123                 {
124                         if(nsens<1)
125                                 return false;
126                         while(i!=rsv_blocks.end())
127                         {
128                                 i->block->reserve(0);
129                                 i = rsv_blocks.erase(i);
130                         }
131                         update_speed();
132                         return true;
133                 }
134                 else if(i->block->get_sensor_id())
135                         ++nsens;
136         }
137
138         return false;
139 }
140
141 void Train::tick(const Time::TimeStamp &t, const Time::TimeDelta &dt)
142 {
143         if(try_reserve && t>try_reserve)
144                 reserve_more();
145
146         if(cur_track)
147         {
148                 unsigned path = 0;
149                 if(cur_track->get_turnout_id())
150                         path = trfc_mgr.get_control().get_turnout(cur_track->get_turnout_id()).get_path();
151
152                 offset += get_real_speed(loco.get_speed())*(dt/Time::sec);
153                 if(offset>cur_track->get_type().get_path_length(path))
154                 {
155                         int out = cur_track->traverse(cur_track_ep, path);
156                         if(out>=0)
157                         {
158                                 Track *next = cur_track->get_link(out);
159                                 if(next)
160                                         cur_track_ep = next->get_endpoint_by_link(*cur_track);
161                                 cur_track = next;
162                                 offset = 0;
163                         }
164                         else
165                                 cur_track = 0;
166                 }
167
168                 if(cur_track)
169                         pos = cur_track->get_point(cur_track_ep, path, offset);
170         }
171 }
172
173 void Train::save(list<DataFile::Statement> &st) const
174 {
175         st.push_back((DataFile::Statement("name"), name));
176         for(unsigned i=0; i<=14; ++i)
177                 if(real_speed[i].weight)
178                         st.push_back((DataFile::Statement("real_speed"), i, real_speed[i].speed, real_speed[i].weight));
179 }
180
181 void Train::locomotive_reverse_changed(bool)
182 {
183         for(list<BlockRef>::iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
184                 i->block->reserve(0);
185         rsv_blocks.clear();
186         cur_blocks.reverse();
187         for(list<BlockRef>::iterator i=cur_blocks.begin(); i!=cur_blocks.end(); ++i)
188                 i->entry = i->block->traverse(i->entry);
189         reserve_more();
190
191         if(cur_track)
192         {
193                 unsigned path = 0;
194                 if(unsigned turnout = cur_track->get_turnout_id())
195                         path = trfc_mgr.get_control().get_turnout(turnout).get_path();
196                 cur_track_ep = cur_track->traverse(cur_track_ep, path);
197                 offset = cur_track->get_type().get_path_length(path)-offset;
198         }
199 }
200
201 void Train::sensor_event(bool state, Sensor *sensor)
202 {
203         unsigned addr = sensor->get_address();
204
205         if(state)
206         {
207                 list<BlockRef>::iterator i;
208                 for(i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
209                         if(i->block->get_sensor_id() && i->block->get_sensor_id()!=addr)
210                                 break;
211
212                 if(i!=rsv_blocks.begin())
213                 {
214                         float travel_time_secs = (Time::now()-last_entry_time)/Time::sec;
215                         travel_speed = static_cast<int>(round(travel_dist/travel_time_secs*87*3.6/5))*5;
216
217                         if(pure_speed)
218                         {
219                                 RealSpeed &rs = real_speed[loco.get_speed()];
220                                 rs.add(travel_dist/travel_time_secs, travel_time_secs);
221                         }
222
223                         travel_dist = 0;
224                         float block_len;
225                         for(list<BlockRef>::iterator j=rsv_blocks.begin(); j!=i; ++j)
226                         {
227                                 j->block->traverse(j->entry, &block_len);
228                                 travel_dist += block_len;
229                         }
230                         last_entry_time = Time::now();
231                         pure_speed = true;
232
233                         cur_blocks.splice(cur_blocks.end(), rsv_blocks, rsv_blocks.begin(), i);
234                 }
235
236                 for(i=cur_blocks.begin(); i!=cur_blocks.end(); ++i)
237                         if(i->block->get_sensor_id()==addr)
238                                 set_position(i->block->get_endpoints()[i->entry]);
239
240                 if(target_speed && reserve_more()<2)
241                         update_speed();
242         }
243         else
244         {
245                 for(list<BlockRef>::iterator i=cur_blocks.begin(); i!=cur_blocks.end(); ++i)
246                         if(unsigned b_addr = i->block->get_sensor_id())
247                         {
248                                 if(b_addr==addr)
249                                 {
250                                         ++i;
251                                         for(list<BlockRef>::iterator j=cur_blocks.begin(); j!=i; ++j)
252                                                 j->block->reserve(0);
253                                         cur_blocks.erase(cur_blocks.begin(), i);
254                                 }
255                                 break;
256                         }
257
258                 if(target_speed && pending_block && addr==pending_block->get_sensor_id())
259                         reserve_more();
260         }
261 }
262
263 void Train::turnout_path_changing(unsigned, Turnout *turnout)
264 {
265         unsigned tid = turnout->get_address();
266         for(list<BlockRef>::const_iterator i=cur_blocks.begin(); i!=cur_blocks.end(); ++i)
267                 if(i->block->get_turnout_id()==tid)
268                         throw TurnoutBusy(this);
269         
270         unsigned nsens = 0;
271         for(list<BlockRef>::const_iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
272         {
273                 if(i->block->get_turnout_id()==tid)
274                 {
275                         if(nsens<1)
276                                 throw TurnoutBusy(this);
277                         break;
278                 }
279                 else if(i->block->get_sensor_id())
280                         ++nsens;
281         }
282 }
283
284 void Train::turnout_path_changed(unsigned, Turnout *turnout)
285 {
286         unsigned tid = turnout->get_address();
287         for(list<BlockRef>::iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
288                 if(i->block->get_turnout_id()==tid)
289                 {
290                         while(i!=rsv_blocks.end())
291                         {
292                                 i->block->reserve(0);
293                                 i = rsv_blocks.erase(i);
294                         }
295                         reserve_more();
296                         return;
297                 }
298
299         if(pending_block && tid==pending_block->get_turnout_id())
300                 reserve_more();
301 }
302
303 unsigned Train::reserve_more()
304 {
305         BlockRef *last = 0;
306         if(!rsv_blocks.empty())
307                 last = &rsv_blocks.back();
308         else if(!cur_blocks.empty())
309                 last = &cur_blocks.back();
310         if(!last)
311                 return 0;
312
313         pending_block = 0;
314
315         unsigned nsens = 0;
316         for(list<BlockRef>::const_iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
317                 if(i->block->get_sensor_id())
318                         ++nsens;
319
320         bool got_more = false;
321         while(nsens<3)
322         {
323                 int exit = last->block->traverse(last->entry);
324                 if(exit<0)
325                         break;
326
327                 Block *link = last->block->get_link(exit);
328                 if(!link || !link->reserve(this))
329                 {
330                         pending_block = link;
331                         break;
332                 }
333
334                 if(route && link->get_turnout_id())
335                 {
336                         int path = route->get_turnout(link->get_turnout_id());
337                         Turnout &turnout = trfc_mgr.get_control().get_turnout(link->get_turnout_id());
338                         if(path>=0 && path!=turnout.get_path())
339                         {
340                                 link->reserve(0);
341                                 pending_block = link;
342                                 turnout.set_path(path);
343                                 break;
344                         }
345                 }
346
347                 rsv_blocks.push_back(BlockRef(link, link->get_endpoint_by_link(*last->block)));
348                 last = &rsv_blocks.back();
349                 if(last->block->get_sensor_id())
350                 {
351                         ++nsens;
352                         got_more = true;
353                 }
354         }
355
356         while(!rsv_blocks.empty() && !last->block->get_sensor_id())
357         {
358                 last->block->reserve(0);
359                 rsv_blocks.erase(--rsv_blocks.end());
360                 if(!rsv_blocks.empty())
361                         last = &rsv_blocks.back();
362                 else
363                         last = 0;
364         }
365
366         if(got_more)
367                 update_speed();
368
369         return nsens;
370 }
371
372 void Train::update_speed()
373 {
374         if(!target_speed)
375         {
376                 loco.set_speed(0);
377                 try_reserve = Time::TimeStamp();
378                 set_status("Stopped");
379         }
380         else
381         {
382                 unsigned nsens = 0;
383                 for(list<BlockRef>::const_iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
384                         if(i->block->get_sensor_id())
385                                 ++nsens;
386
387                 unsigned slow_speed = find_speed(0.1);  // 31.3 km/h
388                 if(nsens==0)
389                 {
390                         loco.set_speed(0);
391                         pure_speed = false;
392                         try_reserve = Time::now()+2*Time::sec;
393                         set_status("Blocked");
394                 }
395                 else if(nsens==1 && target_speed>slow_speed)
396                 {
397                         loco.set_speed(slow_speed);
398                         pure_speed = false;
399                         try_reserve = Time::now()+2*Time::sec;
400                         set_status("Slow");
401                 }
402                 else
403                 {
404                         loco.set_speed(target_speed);
405                         try_reserve = Time::TimeStamp();
406                         set_status(format("Traveling %d kmh", travel_speed));
407                 }
408         }
409 }
410
411 float Train::get_real_speed(unsigned i) const
412 {
413         if(real_speed[i].weight)
414                 return real_speed[i].speed;
415
416         unsigned low;
417         unsigned high;
418         for(low=i; low>0; --low)
419                 if(real_speed[low].weight)
420                         break;
421         for(high=i; high<14; ++high)
422                 if(real_speed[high].weight)
423                         break;
424
425         if(real_speed[high].weight)
426         {
427                 if(real_speed[low].weight)
428                 {
429                         float f = float(i-low)/(high-low);
430                         return real_speed[low].speed*(1-f)+real_speed[high].speed*f;
431                 }
432                 else
433                         return real_speed[high].speed*float(i)/high;
434         }
435         else if(real_speed[low].weight)
436                 return real_speed[low].speed*float(i)/low;
437         else
438                 return 0;
439 }
440
441 unsigned Train::find_speed(float real) const
442 {
443         if(real<=real_speed[0].speed)
444                 return 0;
445
446         unsigned low = 0;
447         unsigned high = 0;
448         for(unsigned i=0; (!high && i<=14); ++i)
449                 if(real_speed[i].weight)
450                 {
451                         if(real_speed[i].speed<real)
452                                 low = i;
453                         else
454                                 high = i;
455                 }
456         if(!high)
457         {
458                 if(!low)
459                         return 0;
460                 return min(static_cast<unsigned>(low*real/real_speed[low].speed), 14U);
461         }
462
463         float f = (real-real_speed[low].speed)/(real_speed[high].speed-real_speed[low].speed);
464         return static_cast<unsigned>(low*(1-f)+high*f+0.5);
465 }
466
467 void Train::set_status(const string &s)
468 {
469         status = s;
470         signal_status_changed.emit(s);
471 }
472
473 void Train::set_position(const Block::Endpoint &bep)
474 {
475         cur_track = bep.track;
476         cur_track_ep = bep.track_ep;
477         offset = 0;
478         pos = cur_track->get_endpoint_position(cur_track_ep);
479 }
480
481 void Train::release_reserved_blocks()
482 {
483         for(list<BlockRef>::iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
484                 i->block->reserve(0);
485         rsv_blocks.clear();
486 }
487
488
489 Train::RealSpeed::RealSpeed():
490         speed(0),
491         weight(0)
492 { }
493
494 void Train::RealSpeed::add(float s, float w)
495 {
496         speed = (speed*weight+s*w)/(weight+w);
497         weight = min(weight+w, 300.0f);
498 }
499
500
501 Train::Loader::Loader(Train &t):
502         DataFile::BasicLoader<Train>(t)
503 {
504         add("name",        &Train::name);
505         add("real_speed",  &Loader::real_speed);
506 }
507
508 void Train::Loader::real_speed(unsigned i, float speed, float weight)
509 {
510         obj.real_speed[i].speed = speed;
511         obj.real_speed[i].weight = weight;
512 }
513
514 } // namespace Marklin