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