]> git.tdb.fi Git - r2c2.git/blob - source/libr2c2/block.cpp
Fix remaining exception class names
[r2c2.git] / source / libr2c2 / block.cpp
1 #include <algorithm>
2 #include <msp/time/units.h>
3 #include "block.h"
4 #include "driver.h"
5 #include "layout.h"
6 #include "route.h"
7 #include "trackiter.h"
8 #include "tracktype.h"
9
10 using namespace std;
11 using namespace Msp;
12
13 namespace R2C2 {
14
15 Block::Block(Layout &l, Track &start):
16         layout(l),
17         id(0),
18         sensor_id(start.get_sensor_id()),
19         turnout_id(start.get_turnout_id()),
20         state(INACTIVE),
21         train(0)
22 {
23         tracks.insert(&start);
24         start.set_block(this);
25
26         list<Track *> queue;
27         queue.push_back(&start);
28
29         while(!queue.empty())
30         {
31                 Track *track = queue.front();
32                 queue.erase(queue.begin());
33
34                 const vector<Track *> &links = track->get_links();
35                 for(unsigned i=0; i<links.size(); ++i)
36                         if(links[i] && !tracks.count(links[i]))
37                         {
38                                 if(links[i]->get_sensor_id()==sensor_id && links[i]->get_turnout_id()==turnout_id)
39                                 {
40                                         queue.push_back(links[i]);
41                                         tracks.insert(links[i]);
42                                         links[i]->set_block(this);
43                                 }
44                                 else
45                                         endpoints.push_back(Endpoint(track, i));
46                         }
47         }
48
49         determine_id();
50
51         for(unsigned i=0; i<endpoints.size(); ++i)
52         {
53                 unsigned path = 1<<i;
54                 endpoints[i].paths |= path;
55                 find_paths(TrackIter(endpoints[i].track, endpoints[i].track_ep), path);
56         }
57
58         if(sensor_id && layout.has_driver())
59                 layout.get_driver().signal_sensor.connect(sigc::mem_fun(this, &Block::sensor_event));
60
61         layout.add_block(*this);
62 }
63
64 Block::~Block()
65 {
66         set<Track *> trks = tracks;
67         tracks.clear();
68         for(set<Track *>::iterator i=trks.begin(); i!=trks.end(); ++i)
69                 (*i)->set_block(0);
70
71         for(vector<Endpoint>::iterator i=endpoints.begin(); i!=endpoints.end(); ++i)
72                 if(Block *blk = i->link)
73                 {
74                         i->link = 0;
75                         blk->break_link(*this);
76                 }
77
78         layout.remove_block(*this);
79 }
80
81 bool Block::has_track(Track &t) const
82 {
83         return tracks.count(&t);
84 }
85
86 const Block::Endpoint &Block::get_endpoint(unsigned i) const
87 {
88         if(i>=endpoints.size())
89                 throw out_of_range("Block::get_endpoint");
90
91         return endpoints[i];
92 }
93
94 int Block::get_endpoint_by_link(Block &other) const
95 {
96         for(unsigned i=0; i<endpoints.size(); ++i)
97                 if(endpoints[i].link==&other)
98                         return i;
99
100         return -1;
101 }
102
103 float Block::get_path_length(unsigned entry, const Route *route) const
104 {
105         if(entry>=endpoints.size())
106                 throw out_of_range("Block::get_path_length");
107
108         TrackIter t_iter(endpoints[entry].track, endpoints[entry].track_ep);
109
110         float result = 0;
111         while(t_iter && has_track(*t_iter))
112         {
113                 unsigned path = (route ? route->get_path(*t_iter) : t_iter->get_active_path());
114                 result += t_iter->get_type().get_path_length(path);
115
116                 t_iter = t_iter.next(path);
117         }
118
119         return result;
120 }
121
122 void Block::check_link(Block &other)
123 {
124         for(vector<Endpoint>::iterator i=endpoints.begin(); i!=endpoints.end(); ++i)
125         {
126                 if(i->link)
127                         continue;
128
129                 for(vector<Endpoint>::iterator j=other.endpoints.begin(); j!=other.endpoints.end(); ++j)
130                         if(j->track==i->track->get_link(i->track_ep) && j->track->get_link(j->track_ep)==i->track && !j->link)
131                         {
132                                 i->link = &other;
133                                 j->link = this;
134
135                                 determine_id();
136                                 other.determine_id();
137                         }
138         }
139 }
140
141 void Block::break_link(Block &other)
142 {
143         for(vector<Endpoint>::iterator i=endpoints.begin(); i!=endpoints.end(); ++i)
144                 if(i->link==&other)
145                 {
146                         i->link = 0;
147                         other.break_link(*this);
148                         determine_id();
149                 }
150 }
151
152 Block *Block::get_link(unsigned epi) const
153 {
154         if(epi>=endpoints.size())
155                 throw out_of_range("Block::get_link");
156         return endpoints[epi].link;
157 }
158
159 bool Block::reserve(Train *t)
160 {
161         if(!t || !train)
162         {
163                 train = t;
164                 signal_reserved.emit(train);
165                 return true;
166         }
167         else
168                 return false;
169 }
170
171 void Block::tick(const Time::TimeDelta &dt)
172 {
173         if(state_confirm_timeout)
174         {
175                 state_confirm_timeout -= dt;
176                 if(state_confirm_timeout<=Time::zero)
177                 {
178                         if(state==MAYBE_INACTIVE)
179                                 state = INACTIVE;
180                         else if(state==MAYBE_ACTIVE)
181                                 state = ACTIVE;
182                         state_confirm_timeout = Time::zero;
183                         signal_state_changed.emit(state);
184                 }
185         }
186 }
187
188 void Block::find_paths(TrackIter track, unsigned path)
189 {
190         unsigned mask = track.endpoint().paths;
191         for(unsigned i=0; mask>>i; ++i)
192                 if(mask&(1<<i))
193                 {
194                         TrackIter next = track.next(i);
195                         if(!next)
196                                 continue;
197                         else if(has_track(*next))
198                                 find_paths(track.next(i), path);
199                         else
200                         {
201                                 next = next.flip();
202                                 for(vector<Endpoint>::iterator j=endpoints.begin(); j!=endpoints.end(); ++j)
203                                         if(j->track==next.track() && j->track_ep==next.entry())
204                                                 j->paths |= path;
205                         }
206                 }
207 }
208
209 void Block::determine_id()
210 {
211         if(sensor_id)
212                 id = 0x1000|sensor_id;
213         else if(turnout_id)
214                 id = 0x2000|turnout_id;
215         else if(endpoints.size()==2)
216         {
217                 unsigned id1 = endpoints[0].link ? endpoints[0].link->get_id() : 1;
218                 unsigned id2 = endpoints[1].link ? endpoints[1].link->get_id() : 1;
219                 if(id2<id1)
220                         swap(id1, id2);
221                 id = (id1<<16)|id2;
222         }
223         else if(endpoints.size()==1)
224         {
225                 unsigned id1 = endpoints[0].link ? endpoints[0].link->get_id() : 1;
226                 id = 0x10000 | id1;
227         }
228 }
229
230 void Block::sensor_event(unsigned addr, bool s)
231 {
232         if(addr==sensor_id)
233         {
234                 if(s && state<MAYBE_ACTIVE)
235                 {
236                         state = MAYBE_ACTIVE;
237                         state_confirm_timeout = 300*Time::msec;
238                         signal_state_changed.emit(state);
239                 }
240                 else if(!s && state>MAYBE_INACTIVE)
241                 {
242                         state = MAYBE_INACTIVE;
243                         state_confirm_timeout = 700*Time::msec;
244                         signal_state_changed.emit(state);
245                 }
246         }
247 }
248
249
250 Block::Endpoint::Endpoint(Track *t, unsigned e):
251         track(t),
252         track_ep(e),
253         link(0),
254         paths(0)
255 { }
256
257 } // namespace R2C2