]> git.tdb.fi Git - r2c2.git/blob - source/libmarklin/train.cpp
Add train status display
[r2c2.git] / source / libmarklin / train.cpp
1 #include <msp/time/units.h>
2 #include <msp/time/utils.h>
3 #include "control.h"
4 #include "trafficmanager.h"
5 #include "train.h"
6
7 using namespace Msp;
8
9 #include <iostream>
10 using namespace std;
11
12 namespace Marklin {
13
14 Train::Train(TrafficManager &tm, Locomotive &l):
15         trfc_mgr(tm),
16         loco(l),
17         target_speed(0),
18         status("Unplaced")
19 {
20         trfc_mgr.add_train(this);
21
22         const map<unsigned, Sensor *> &sensors=trfc_mgr.get_control().get_sensors();
23         for(map<unsigned, Sensor *>::const_iterator i=sensors.begin(); i!=sensors.end(); ++i)
24                 i->second->signal_state_changed.connect(sigc::bind(sigc::mem_fun(this, &Train::sensor_event), i->second));
25 }
26
27 void Train::set_name(const string &n)
28 {
29         name=n;
30
31         signal_name_changed.emit(name);
32 }
33
34 void Train::set_speed(unsigned speed)
35 {
36         target_speed=speed;
37         if(!target_speed)
38         {
39                 // XXX We might roll onto a new sensor and get confused - should delay freeing blocks a bit
40                 for(list<BlockRef>::iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
41                         i->block->reserve(0);
42                 rsv_blocks.clear();
43                 try_reserve=Time::TimeStamp();
44         }
45         else if(rsv_blocks.empty() && !reserve_more())
46                 return;
47
48         loco.set_speed(speed);
49         set_status(target_speed ? "Traveling" : "Stopped");
50 }
51
52 void Train::place(Block *block, unsigned entry)
53 {
54         for(list<BlockRef>::iterator i=rsv_blocks.begin(); i!=rsv_blocks.end();)
55         {
56                 i->block->reserve(0);
57                 i=rsv_blocks.erase(i);
58         }
59
60         for(list<BlockRef>::iterator i=cur_blocks.begin(); i!=cur_blocks.end();)
61         {
62                 i->block->reserve(0);
63                 i=cur_blocks.erase(i);
64         }
65
66         if(!block->reserve(this))
67         {
68                 set_status("Unplaced");
69                 return;
70         }
71
72         cur_blocks.push_back(BlockRef(block, entry));
73
74         set_status("Stopped");
75 }
76
77 bool Train::free_block(Block *block)
78 {
79         for(list<BlockRef>::iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
80                 if(i->block==block)
81                 {
82                         while(i!=rsv_blocks.end())
83                         {
84                                 i->block->reserve(0);
85                                 i=rsv_blocks.erase(i);
86                         }
87                         return true;
88                 }
89
90         return false;
91 }
92
93 void Train::tick(const Time::TimeStamp &t)
94 {
95         if(try_reserve && t>try_reserve)
96         {
97                 if(reserve_more() || !rsv_blocks.empty())
98                 {
99                         loco.set_speed(target_speed);
100                         set_status("Traveling");
101                         try_reserve=Time::TimeStamp();
102                 }
103                 else
104                         try_reserve=t+2*Time::sec;
105         }
106 }
107
108 void Train::sensor_event(bool state, Sensor *sensor)
109 {
110         unsigned addr=sensor->get_address();
111
112         if(state)
113         {
114                 list<BlockRef>::iterator i;
115                 for(i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
116                         if(i->block->get_sensor_id() && i->block->get_sensor_id()!=addr)
117                                 break;
118
119                 if(i!=rsv_blocks.begin())
120                 {
121                         cur_blocks.splice(cur_blocks.end(), rsv_blocks, rsv_blocks.begin(), i);
122                         cout<<"Train "<<name<<" advanced, "<<cur_blocks.size()<<" cur_blocks, "<<rsv_blocks.size()<<" rsv_blocks\n";
123                 }
124
125                 if(target_speed && rsv_blocks.empty() && !reserve_more())
126                 {
127                         loco.set_speed(0);
128                         try_reserve=Time::now()+2*Time::sec;
129                         set_status("Blocked");
130                 }
131         }
132         else
133         {
134                 cout<<"Train "<<name<<" finding blocks to free\n";
135                 list<BlockRef>::iterator i;
136                 for(i=cur_blocks.begin(); i!=cur_blocks.end(); ++i)
137                 {
138                         if(i->block->get_sensor_id()==addr)
139                         {
140                                 ++i;
141                                 for(list<BlockRef>::iterator j=cur_blocks.begin(); j!=i; ++j)
142                                         j->block->reserve(0);
143                                 cout<<"  "<<distance(cur_blocks.begin(), i)<<" blocks freed, ";
144                                 cur_blocks.erase(cur_blocks.begin(), i);
145                                 cout<<cur_blocks.size()<<" cur_blocks\n";
146                         }
147                 }
148
149                 if(target_speed)
150                         reserve_more();
151         }
152 }
153
154 bool Train::reserve_more()
155 {
156         BlockRef *last=0;
157         if(!rsv_blocks.empty())
158                 last=&rsv_blocks.back();
159         else if(!cur_blocks.empty())
160                 last=&cur_blocks.back();
161         if(!last)
162                 return false;
163
164         cout<<"Train "<<name<<" reserving more blocks\n";
165
166         bool result=false;
167         unsigned size=rsv_blocks.size();
168         while(size<3)
169         {
170                 int exit=last->block->traverse(last->entry);
171                 if(exit>=0) 
172                 {
173                         Block *link=last->block->get_link(exit);
174                         if(link && link->reserve(this))
175                         {
176                                 rsv_blocks.push_back(BlockRef(link, link->get_endpoint_by_link(*last->block)));
177                                 last=&rsv_blocks.back();
178                                 ++size;
179                                 result=true;
180                         }
181                         else
182                                 break;
183                 }
184                 else
185                         break;
186         }
187
188         cout<<"  "<<rsv_blocks.size()<<" rsv_blocks\n";
189
190         return result;
191 }
192
193 void Train::set_status(const string &s)
194 {
195         status=s;
196         signal_status_changed.emit(s);
197 }
198
199 } // namespace Marklin