]> git.tdb.fi Git - r2c2.git/blob - source/libmarklin/train.cpp
Add networking library and a remote control program
[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(speed==target_speed)
63                 return;
64         if(!target_speed && speed)
65                 travel_speed = static_cast<int>(round(speed*speed_scale*87*3.6/5))*5;
66
67         target_speed = speed;
68         if(!target_speed)
69         {
70                 // XXX We might roll onto a new sensor and get confused - should delay freeing blocks a bit
71                 for(list<BlockRef>::iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
72                         i->block->reserve(0);
73                 rsv_blocks.clear();
74         }
75         else
76                 reserve_more();
77
78         signal_target_speed_changed.emit(target_speed);
79
80         update_speed();
81         pure_speed = false;
82 }
83
84 void Train::set_reverse(bool rev)
85 {
86         loco.set_reverse(rev);
87 }
88
89 void Train::place(Block *block, unsigned entry)
90 {
91         for(list<BlockRef>::iterator i=rsv_blocks.begin(); i!=rsv_blocks.end();)
92         {
93                 i->block->reserve(0);
94                 i = rsv_blocks.erase(i);
95         }
96
97         for(list<BlockRef>::iterator i=cur_blocks.begin(); i!=cur_blocks.end();)
98         {
99                 i->block->reserve(0);
100                 i = cur_blocks.erase(i);
101         }
102
103         if(!block->reserve(this))
104         {
105                 set_status("Unplaced");
106                 return;
107         }
108
109         cur_blocks.push_back(BlockRef(block, entry));
110         set_position(block->get_endpoints()[entry]);
111
112         set_status("Stopped");
113 }
114
115 bool Train::free_block(Block *block)
116 {
117         unsigned nsens = 0;
118         for(list<BlockRef>::iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
119         {
120                 if(i->block==block)
121                 {
122                         if(nsens<1)
123                                 return false;
124                         while(i!=rsv_blocks.end())
125                         {
126                                 i->block->reserve(0);
127                                 i = rsv_blocks.erase(i);
128                         }
129                         update_speed();
130                         return true;
131                 }
132                 else if(i->block->get_sensor_id())
133                         ++nsens;
134         }
135
136         return false;
137 }
138
139 void Train::tick(const Time::TimeStamp &t, const Time::TimeDelta &dt)
140 {
141         if(try_reserve && t>try_reserve)
142         {
143                 reserve_more();
144                 update_speed();
145         }
146
147         if(cur_track)
148         {
149                 unsigned route = 0;
150                 if(cur_track->get_turnout_id())
151                         route = trfc_mgr.get_control().get_turnout(cur_track->get_turnout_id()).get_route();
152
153                 offset += speed_scale*loco.get_speed()*(dt/Time::sec);
154                 if(offset>cur_track->get_type().get_route_length(route))
155                 {
156                         int out = cur_track->traverse(cur_track_ep, route);
157                         if(out>=0)
158                         {
159                                 Track *next = cur_track->get_link(out);
160                                 if(next)
161                                         cur_track_ep = next->get_endpoint_by_link(*cur_track);
162                                 cur_track = next;
163                                 offset = 0;
164                         }
165                         else
166                                 cur_track = 0;
167                 }
168
169                 if(cur_track)
170                         pos = cur_track->get_point(cur_track_ep, route, offset);
171         }
172 }
173
174 void Train::save(list<DataFile::Statement> &st) const
175 {
176         st.push_back((DataFile::Statement("name"), name));
177         st.push_back((DataFile::Statement("speed_scale"), speed_scale, speed_scale_weight));
178 }
179
180 void Train::locomotive_reverse_changed(bool)
181 {
182         for(list<BlockRef>::iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
183                 i->block->reserve(0);
184         rsv_blocks.clear();
185         cur_blocks.reverse();
186         for(list<BlockRef>::iterator i=cur_blocks.begin(); i!=cur_blocks.end(); ++i)
187                 i->entry = i->block->traverse(i->entry);
188         reserve_more();
189         update_speed();
190 }
191
192 void Train::sensor_event(bool state, Sensor *sensor)
193 {
194         unsigned addr = sensor->get_address();
195
196         if(state)
197         {
198                 list<BlockRef>::iterator i;
199                 for(i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
200                         if(i->block->get_sensor_id() && i->block->get_sensor_id()!=addr)
201                                 break;
202
203                 if(i!=rsv_blocks.begin())
204                 {
205                         float travel_time_secs = (Time::now()-last_entry_time)/Time::sec;
206                         travel_speed = static_cast<int>(round(travel_dist/travel_time_secs*87*3.6/5))*5;
207
208                         if(pure_speed)
209                         {
210                                 float weight = loco.get_speed()*travel_dist;
211                                 if(weight)
212                                 {
213                                         weight *= weight;
214                                         float scale = travel_dist/travel_time_secs/loco.get_speed();
215                                         cout<<"Updating speed_scale: "<<speed_scale<<'x'<<speed_scale_weight<<" + "<<scale<<'x'<<weight<<'\n';
216                                         speed_scale = (speed_scale*speed_scale_weight+scale*weight)/(speed_scale_weight+weight);
217                                         speed_scale_weight += weight;
218                                         cout<<"  Result: "<<speed_scale<<'x'<<speed_scale_weight<<'\n';
219                                 }
220                         }
221
222                         travel_dist = 0;
223                         float block_len;
224                         for(list<BlockRef>::iterator j=rsv_blocks.begin(); j!=i; ++j)
225                         {
226                                 j->block->traverse(j->entry, &block_len);
227                                 travel_dist += block_len;
228                         }
229                         last_entry_time = Time::now();
230                         pure_speed = true;
231
232                         cur_blocks.splice(cur_blocks.end(), rsv_blocks, rsv_blocks.begin(), i);
233                 }
234
235                 for(i=cur_blocks.begin(); i!=cur_blocks.end(); ++i)
236                         if(i->block->get_sensor_id()==addr)
237                                 set_position(i->block->get_endpoints()[i->entry]);
238
239                 if(target_speed)
240                 {
241                         reserve_more();
242                         update_speed();
243                 }
244         }
245         else
246         {
247                 for(list<BlockRef>::iterator i=cur_blocks.begin(); i!=cur_blocks.end(); ++i)
248                         if(i->block->get_sensor_id()==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                                 break;
255                         }
256
257                 if(target_speed)
258                         reserve_more();
259         }
260 }
261
262 void Train::turnout_route_changing(unsigned, Turnout *turnout)
263 {
264         unsigned tid = turnout->get_address();
265         for(list<BlockRef>::const_iterator i=cur_blocks.begin(); i!=cur_blocks.end(); ++i)
266                 if(i->block->get_turnout_id()==tid)
267                         throw TurnoutBusy(this);
268         
269         unsigned nsens = 0;
270         for(list<BlockRef>::const_iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
271         {
272                 if(i->block->get_turnout_id()==tid)
273                 {
274                         if(nsens<1)
275                                 throw TurnoutBusy(this);
276                         break;
277                 }
278                 else if(i->block->get_sensor_id())
279                         ++nsens;
280         }
281 }
282
283 void Train::turnout_route_changed(unsigned, Turnout *turnout)
284 {
285         unsigned tid = turnout->get_address();
286         for(list<BlockRef>::iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
287                 if(i->block->get_turnout_id()==tid)
288                 {
289                         while(i!=rsv_blocks.end())
290                         {
291                                 i->block->reserve(0);
292                                 i = rsv_blocks.erase(i);
293                         }
294                         reserve_more();
295                         update_speed();
296                         return;
297                 }
298 }
299
300 unsigned Train::reserve_more()
301 {
302         BlockRef *last = 0;
303         if(!rsv_blocks.empty())
304                 last = &rsv_blocks.back();
305         else if(!cur_blocks.empty())
306                 last = &cur_blocks.back();
307         if(!last)
308                 return 0;
309
310         unsigned nsens = 0;
311         for(list<BlockRef>::const_iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
312                 if(i->block->get_sensor_id())
313                         ++nsens;
314
315         bool result = false;
316         while(nsens<2)
317         {
318                 int exit = last->block->traverse(last->entry);
319                 if(exit>=0) 
320                 {
321                         Block *link = last->block->get_link(exit);
322                         if(link && link->reserve(this))
323                         {
324                                 rsv_blocks.push_back(BlockRef(link, link->get_endpoint_by_link(*last->block)));
325                                 last = &rsv_blocks.back();
326                                 if(last->block->get_sensor_id())
327                                 {
328                                         ++nsens;
329                                         result = true;
330                                 }
331                         }
332                         else
333                                 break;
334                 }
335                 else
336                         break;
337         }
338
339         while(last && !last->block->get_sensor_id())
340         {
341                 last->block->reserve(0);
342                 rsv_blocks.erase(--rsv_blocks.end());
343                 if(!rsv_blocks.empty())
344                         last = &rsv_blocks.back();
345                 else
346                         last = 0;
347         }
348
349         return nsens;
350 }
351
352 void Train::update_speed()
353 {
354         if(!target_speed)
355         {
356                 loco.set_speed(0);
357                 try_reserve = Time::TimeStamp();
358                 set_status("Stopped");
359         }
360         else
361         {
362                 unsigned nsens = 0;
363                 for(list<BlockRef>::const_iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
364                         if(i->block->get_sensor_id())
365                                 ++nsens;
366
367                 if(nsens==0)
368                 {
369                         loco.set_speed(0);
370                         pure_speed = false;
371                         try_reserve = Time::now()+2*Time::sec;
372                         set_status("Blocked");
373                 }
374                 else if(nsens==1 && target_speed>3)
375                 {
376                         loco.set_speed(3);
377                         pure_speed = false;
378                         try_reserve = Time::now()+2*Time::sec;
379                         set_status("Slow");
380                 }
381                 else
382                 {
383                         loco.set_speed(target_speed);
384                         try_reserve = Time::TimeStamp();
385                         set_status(format("Traveling %d kmh", travel_speed));
386                 }
387         }
388 }
389
390 void Train::set_status(const string &s)
391 {
392         status = s;
393         signal_status_changed.emit(s);
394 }
395
396 void Train::set_position(const Block::Endpoint &bep)
397 {
398         cur_track = bep.track;
399         cur_track_ep = bep.track_ep;
400         offset = 0;
401         pos = cur_track->get_endpoint_position(cur_track_ep);
402 }
403
404
405 Train::Loader::Loader(Train &t):
406         DataFile::BasicLoader<Train>(t)
407 {
408         add("name",        &Train::name);
409         add("speed_scale", &Train::speed_scale, &Train::speed_scale_weight);
410 }
411
412 } // namespace Marklin