]> git.tdb.fi Git - r2c2.git/blob - source/libmarklin/train.cpp
09f587020588bc69fd91c5f51d2747a9094a7110
[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 #include <iostream>
22
23 namespace Marklin {
24
25 Train::Train(TrafficManager &tm, Locomotive &l):
26         trfc_mgr(tm),
27         loco(l),
28         target_speed(0),
29         status("Unplaced"),
30         travel_dist(0),
31         travel_speed(0),
32         pure_speed(false),
33         speed_scale(0.02),
34         speed_scale_weight(0),
35         cur_track(0)
36 {
37         trfc_mgr.add_train(this);
38
39         loco.signal_reverse_changed.connect(sigc::mem_fun(this, &Train::locomotive_reverse_changed));
40
41         const map<unsigned, Sensor *> &sensors = trfc_mgr.get_control().get_sensors();
42         for(map<unsigned, Sensor *>::const_iterator i=sensors.begin(); i!=sensors.end(); ++i)
43                 i->second->signal_state_changed.connect(sigc::bind(sigc::mem_fun(this, &Train::sensor_event), i->second));
44
45         const map<unsigned, Turnout *> &turnouts = trfc_mgr.get_control().get_turnouts();
46         for(map<unsigned, Turnout *>::const_iterator i=turnouts.begin(); i!=turnouts.end(); ++i)
47         {
48                 i->second->signal_route_changing.connect(sigc::bind(sigc::mem_fun(this, &Train::turnout_route_changing), i->second));
49                 i->second->signal_route_changed.connect(sigc::bind(sigc::mem_fun(this, &Train::turnout_route_changed), i->second));
50         }
51 }
52
53 void Train::set_name(const string &n)
54 {
55         name = n;
56
57         signal_name_changed.emit(name);
58 }
59
60 void Train::set_speed(unsigned speed)
61 {
62         if(!target_speed && speed)
63                 travel_speed = static_cast<int>(round(speed*speed_scale*87*3.6/5))*5;
64
65         target_speed = speed;
66         if(!target_speed)
67         {
68                 // XXX We might roll onto a new sensor and get confused - should delay freeing blocks a bit
69                 for(list<BlockRef>::iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
70                         i->block->reserve(0);
71                 rsv_blocks.clear();
72         }
73         else
74                 reserve_more();
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::place(Block *block, unsigned entry)
86 {
87         for(list<BlockRef>::iterator i=rsv_blocks.begin(); i!=rsv_blocks.end();)
88         {
89                 i->block->reserve(0);
90                 i = rsv_blocks.erase(i);
91         }
92
93         for(list<BlockRef>::iterator i=cur_blocks.begin(); i!=cur_blocks.end();)
94         {
95                 i->block->reserve(0);
96                 i = cur_blocks.erase(i);
97         }
98
99         if(!block->reserve(this))
100         {
101                 set_status("Unplaced");
102                 return;
103         }
104
105         cur_blocks.push_back(BlockRef(block, entry));
106         set_position(block->get_endpoints()[entry]);
107
108         set_status("Stopped");
109 }
110
111 bool Train::free_block(Block *block)
112 {
113         unsigned nsens = 0;
114         for(list<BlockRef>::iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
115         {
116                 if(i->block==block)
117                 {
118                         if(nsens<1)
119                                 return false;
120                         while(i!=rsv_blocks.end())
121                         {
122                                 i->block->reserve(0);
123                                 i = rsv_blocks.erase(i);
124                         }
125                         update_speed();
126                         return true;
127                 }
128                 else if(i->block->get_sensor_id())
129                         ++nsens;
130         }
131
132         return false;
133 }
134
135 void Train::tick(const Time::TimeStamp &t, const Time::TimeDelta &dt)
136 {
137         if(try_reserve && t>try_reserve)
138         {
139                 reserve_more();
140                 update_speed();
141         }
142
143         if(cur_track)
144         {
145                 unsigned route = 0;
146                 if(cur_track->get_turnout_id())
147                         route = trfc_mgr.get_control().get_turnout(cur_track->get_turnout_id()).get_route();
148
149                 offset += speed_scale*loco.get_speed()*(dt/Time::sec);
150                 if(offset>cur_track->get_type().get_route_length(route))
151                 {
152                         int out = cur_track->traverse(cur_track_ep, route);
153                         if(out>=0)
154                         {
155                                 Track *next = cur_track->get_link(out);
156                                 if(next)
157                                         cur_track_ep = next->get_endpoint_by_link(*cur_track);
158                                 cur_track = next;
159                                 offset = 0;
160                         }
161                         else
162                                 cur_track = 0;
163                 }
164
165                 if(cur_track)
166                         pos = cur_track->get_point(cur_track_ep, route, offset);
167         }
168 }
169
170 void Train::save(list<DataFile::Statement> &st) const
171 {
172         st.push_back((DataFile::Statement("name"), name));
173         st.push_back((DataFile::Statement("speed_scale"), speed_scale, speed_scale_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                                 float weight = loco.get_speed()*travel_dist;
207                                 if(weight)
208                                 {
209                                         weight *= weight;
210                                         float scale = travel_dist/travel_time_secs/loco.get_speed();
211                                         cout<<"Updating speed_scale: "<<speed_scale<<'x'<<speed_scale_weight<<" + "<<scale<<'x'<<weight<<'\n';
212                                         speed_scale = (speed_scale*speed_scale_weight+scale*weight)/(speed_scale_weight+weight);
213                                         speed_scale_weight += weight;
214                                         cout<<"  Result: "<<speed_scale<<'x'<<speed_scale_weight<<'\n';
215                                 }
216                         }
217
218                         travel_dist = 0;
219                         float block_len;
220                         for(list<BlockRef>::iterator j=rsv_blocks.begin(); j!=i; ++j)
221                         {
222                                 j->block->traverse(j->entry, &block_len);
223                                 travel_dist += block_len;
224                         }
225                         last_entry_time = Time::now();
226                         pure_speed = true;
227
228                         cur_blocks.splice(cur_blocks.end(), rsv_blocks, rsv_blocks.begin(), i);
229                 }
230
231                 for(i=cur_blocks.begin(); i!=cur_blocks.end(); ++i)
232                         if(i->block->get_sensor_id()==addr)
233                                 set_position(i->block->get_endpoints()[i->entry]);
234
235                 if(target_speed)
236                 {
237                         reserve_more();
238                         update_speed();
239                 }
240         }
241         else
242         {
243                 for(list<BlockRef>::iterator i=cur_blocks.begin(); i!=cur_blocks.end(); ++i)
244                         if(i->block->get_sensor_id()==addr)
245                         {
246                                 ++i;
247                                 for(list<BlockRef>::iterator j=cur_blocks.begin(); j!=i; ++j)
248                                         j->block->reserve(0);
249                                 cur_blocks.erase(cur_blocks.begin(), i);
250                                 break;
251                         }
252
253                 if(target_speed)
254                         reserve_more();
255         }
256 }
257
258 void Train::turnout_route_changing(unsigned, Turnout *turnout)
259 {
260         unsigned tid = turnout->get_address();
261         for(list<BlockRef>::const_iterator i=cur_blocks.begin(); i!=cur_blocks.end(); ++i)
262                 if(i->block->get_turnout_id()==tid)
263                         throw TurnoutBusy(this);
264         
265         unsigned nsens = 0;
266         for(list<BlockRef>::const_iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
267         {
268                 if(i->block->get_turnout_id()==tid)
269                 {
270                         if(nsens<1)
271                                 throw TurnoutBusy(this);
272                         break;
273                 }
274                 else if(i->block->get_sensor_id())
275                         ++nsens;
276         }
277 }
278
279 void Train::turnout_route_changed(unsigned, Turnout *turnout)
280 {
281         unsigned tid = turnout->get_address();
282         for(list<BlockRef>::iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
283                 if(i->block->get_turnout_id()==tid)
284                 {
285                         while(i!=rsv_blocks.end())
286                         {
287                                 i->block->reserve(0);
288                                 i = rsv_blocks.erase(i);
289                         }
290                         reserve_more();
291                         update_speed();
292                         return;
293                 }
294 }
295
296 unsigned Train::reserve_more()
297 {
298         BlockRef *last = 0;
299         if(!rsv_blocks.empty())
300                 last = &rsv_blocks.back();
301         else if(!cur_blocks.empty())
302                 last = &cur_blocks.back();
303         if(!last)
304                 return 0;
305
306         unsigned nsens = 0;
307         for(list<BlockRef>::const_iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
308                 if(i->block->get_sensor_id())
309                         ++nsens;
310
311         bool result = false;
312         while(nsens<2)
313         {
314                 int exit = last->block->traverse(last->entry);
315                 if(exit>=0) 
316                 {
317                         Block *link = last->block->get_link(exit);
318                         if(link && link->reserve(this))
319                         {
320                                 rsv_blocks.push_back(BlockRef(link, link->get_endpoint_by_link(*last->block)));
321                                 last = &rsv_blocks.back();
322                                 if(last->block->get_sensor_id())
323                                 {
324                                         ++nsens;
325                                         result = true;
326                                 }
327                         }
328                         else
329                                 break;
330                 }
331                 else
332                         break;
333         }
334
335         while(last && !last->block->get_sensor_id())
336         {
337                 last->block->reserve(0);
338                 rsv_blocks.erase(--rsv_blocks.end());
339                 if(!rsv_blocks.empty())
340                         last = &rsv_blocks.back();
341                 else
342                         last = 0;
343         }
344
345         return nsens;
346 }
347
348 void Train::update_speed()
349 {
350         if(!target_speed)
351         {
352                 loco.set_speed(0);
353                 try_reserve = Time::TimeStamp();
354                 set_status("Stopped");
355         }
356         else
357         {
358                 unsigned nsens = 0;
359                 for(list<BlockRef>::const_iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
360                         if(i->block->get_sensor_id())
361                                 ++nsens;
362
363                 if(nsens==0)
364                 {
365                         loco.set_speed(0);
366                         pure_speed = false;
367                         try_reserve = Time::now()+2*Time::sec;
368                         set_status("Blocked");
369                 }
370                 else if(nsens==1 && target_speed>3)
371                 {
372                         loco.set_speed(3);
373                         pure_speed = false;
374                         try_reserve = Time::now()+2*Time::sec;
375                         set_status("Slow");
376                 }
377                 else
378                 {
379                         loco.set_speed(target_speed);
380                         try_reserve = Time::TimeStamp();
381                         set_status(format("Traveling %d kmh", travel_speed));
382                 }
383         }
384 }
385
386 void Train::set_status(const string &s)
387 {
388         status = s;
389         signal_status_changed.emit(s);
390 }
391
392 void Train::set_position(const Block::Endpoint &bep)
393 {
394         cur_track = bep.track;
395         cur_track_ep = bep.track_ep;
396         offset = 0;
397         pos = cur_track->get_endpoint_position(cur_track_ep);
398 }
399
400
401 Train::Loader::Loader(Train &t):
402         DataFile::BasicLoader<Train>(t)
403 {
404         add("name",        &Train::name);
405         add("speed_scale", &Train::speed_scale, &Train::speed_scale_weight);
406 }
407
408 } // namespace Marklin