]> git.tdb.fi Git - r2c2.git/blob - source/libmarklin/train.cpp
Add Id tags and copyright notices to files
[r2c2.git] / source / libmarklin / train.cpp
1 /* $Id$
2
3 This file is part of the MSP Märklin suite
4 Copyright © 2006-2008 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 "trafficmanager.h"
14 #include "train.h"
15
16 using namespace Msp;
17
18 #include <iostream>
19 using namespace std;
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         real_speed(0)
30 {
31         trfc_mgr.add_train(this);
32
33         const map<unsigned, Sensor *> &sensors=trfc_mgr.get_control().get_sensors();
34         for(map<unsigned, Sensor *>::const_iterator i=sensors.begin(); i!=sensors.end(); ++i)
35                 i->second->signal_state_changed.connect(sigc::bind(sigc::mem_fun(this, &Train::sensor_event), i->second));
36 }
37
38 void Train::set_name(const string &n)
39 {
40         name=n;
41
42         signal_name_changed.emit(name);
43 }
44
45 void Train::set_speed(unsigned speed)
46 {
47         unsigned old_speed=target_speed;
48
49         target_speed=speed;
50         if(!target_speed)
51         {
52                 // XXX We might roll onto a new sensor and get confused - should delay freeing blocks a bit
53                 for(list<BlockRef>::iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
54                         i->block->reserve(0);
55                 rsv_blocks.clear();
56                 try_reserve=Time::TimeStamp();
57         }
58         else if(rsv_blocks.empty() && !reserve_more())
59                 return;
60
61         loco.set_speed(speed);
62         if(!old_speed && target_speed)
63                 set_status("Traveling --- kmh");
64         else if(old_speed && !target_speed)
65                 set_status("Stopped");
66 }
67
68 void Train::place(Block *block, unsigned entry)
69 {
70         for(list<BlockRef>::iterator i=rsv_blocks.begin(); i!=rsv_blocks.end();)
71         {
72                 i->block->reserve(0);
73                 i=rsv_blocks.erase(i);
74         }
75
76         for(list<BlockRef>::iterator i=cur_blocks.begin(); i!=cur_blocks.end();)
77         {
78                 i->block->reserve(0);
79                 i=cur_blocks.erase(i);
80         }
81
82         if(!block->reserve(this))
83         {
84                 set_status("Unplaced");
85                 return;
86         }
87
88         cur_blocks.push_back(BlockRef(block, entry));
89
90         set_status("Stopped");
91 }
92
93 bool Train::free_block(Block *block)
94 {
95         for(list<BlockRef>::iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
96                 if(i->block==block)
97                 {
98                         while(i!=rsv_blocks.end())
99                         {
100                                 i->block->reserve(0);
101                                 i=rsv_blocks.erase(i);
102                         }
103                         return true;
104                 }
105
106         return false;
107 }
108
109 void Train::tick(const Time::TimeStamp &t)
110 {
111         if(try_reserve && t>try_reserve)
112         {
113                 if(reserve_more() || !rsv_blocks.empty())
114                 {
115                         loco.set_speed(target_speed);
116                         set_status("Traveling --- kmh");
117                         try_reserve=Time::TimeStamp();
118                 }
119                 else
120                         try_reserve=t+2*Time::sec;
121         }
122 }
123
124 void Train::sensor_event(bool state, Sensor *sensor)
125 {
126         unsigned addr=sensor->get_address();
127
128         if(state)
129         {
130                 list<BlockRef>::iterator i;
131                 for(i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
132                         if(i->block->get_sensor_id() && i->block->get_sensor_id()!=addr)
133                                 break;
134
135                 if(i!=rsv_blocks.begin())
136                 {
137                         real_speed=static_cast<int>(round(travel_dist/((Time::now()-last_entry_time)/Time::sec)*87*3.6/5))*5;
138                         set_status(format("Traveling %3d kmh", real_speed));
139
140                         travel_dist=0;
141                         float block_len;
142                         for(list<BlockRef>::iterator j=rsv_blocks.begin(); j!=i; ++j)
143                         {
144                                 j->block->traverse(j->entry, &block_len);
145                                 cout<<"Advancing: block "<<j->block<<" (sensor "<<j->block->get_sensor_id()<<") length "<<block_len<<'\n';
146                                 travel_dist+=block_len;
147                         }
148                         last_entry_time=Time::now();
149
150                         cur_blocks.splice(cur_blocks.end(), rsv_blocks, rsv_blocks.begin(), i);
151                         cout<<"Train "<<name<<" advanced, "<<cur_blocks.size()<<" cur_blocks, "<<rsv_blocks.size()<<" rsv_blocks\n";
152                 }
153
154                 if(target_speed && !reserve_more() && rsv_blocks.empty())
155                 {
156                         loco.set_speed(0);
157                         try_reserve=Time::now()+2*Time::sec;
158                         set_status("Blocked");
159                 }
160         }
161         else
162         {
163                 cout<<"Train "<<name<<" finding blocks to free\n";
164                 list<BlockRef>::iterator i;
165                 for(i=cur_blocks.begin(); i!=cur_blocks.end(); ++i)
166                 {
167                         if(i->block->get_sensor_id()==addr)
168                         {
169                                 ++i;
170                                 for(list<BlockRef>::iterator j=cur_blocks.begin(); j!=i; ++j)
171                                         j->block->reserve(0);
172                                 cout<<"  "<<distance(cur_blocks.begin(), i)<<" blocks freed, ";
173                                 cur_blocks.erase(cur_blocks.begin(), i);
174                                 cout<<cur_blocks.size()<<" cur_blocks\n";
175                         }
176                 }
177
178                 if(target_speed)
179                         reserve_more();
180         }
181 }
182
183 bool Train::reserve_more()
184 {
185         BlockRef *last=0;
186         if(!rsv_blocks.empty())
187                 last=&rsv_blocks.back();
188         else if(!cur_blocks.empty())
189                 last=&cur_blocks.back();
190         if(!last)
191                 return false;
192
193         cout<<"Train "<<name<<" reserving more blocks\n";
194
195         bool result=false;
196         unsigned size=rsv_blocks.size();
197         while(size<3)
198         {
199                 int exit=last->block->traverse(last->entry);
200                 if(exit>=0) 
201                 {
202                         Block *link=last->block->get_link(exit);
203                         if(link && link->reserve(this))
204                         {
205                                 rsv_blocks.push_back(BlockRef(link, link->get_endpoint_by_link(*last->block)));
206                                 last=&rsv_blocks.back();
207                                 ++size;
208                                 result=true;
209                         }
210                         else
211                                 break;
212                 }
213                 else
214                         break;
215         }
216
217         cout<<"  "<<rsv_blocks.size()<<" rsv_blocks\n";
218
219         return result;
220 }
221
222 void Train::set_status(const string &s)
223 {
224         status=s;
225         signal_status_changed.emit(s);
226 }
227
228 } // namespace Marklin