]> git.tdb.fi Git - r2c2.git/blob - source/libr2c2/block.cpp
Make sure Block::signal_reserved is emitted consistently
[r2c2.git] / source / libr2c2 / block.cpp
1 #include <algorithm>
2 #include <msp/core/raii.h>
3 #include <msp/strings/format.h>
4 #include <msp/time/units.h>
5 #include "block.h"
6 #include "layout.h"
7 #include "route.h"
8 #include "trackcircuit.h"
9 #include "trackiter.h"
10 #include "tracktype.h"
11
12 using namespace std;
13 using namespace Msp;
14
15 namespace R2C2 {
16
17 Block::Block(Layout &l, Track &start):
18         TrackChain(l),
19         id(0),
20         sensor_addr(start.get_sensor_address()),
21         turnout_addr(start.get_turnout_address()),
22         conflict(false),
23         sensor(0),
24         train(0),
25         pending_train(0),
26         emitting_reserve(false)
27 {
28         add_track(start);
29
30         if(start.get_type().is_turnout())
31         {
32                 unsigned nls = start.get_n_link_slots();
33                 for(unsigned i=0; i<nls; ++i)
34                         endpoints.push_back(Endpoint(&start, i));
35         }
36         else
37         {
38                 unsigned nls = start.get_n_link_slots();
39                 for(unsigned i=0; i<nls; ++i)
40                 {
41                         TrackIter iter = TrackIter(&start, i).flip();
42                         for(; (iter && check_validity(*iter)==VALID); iter=iter.next())
43                                 add_track(*iter);
44                         if((iter = iter.flip()))
45                                 endpoints.push_back(Endpoint(iter.track(), iter.entry()));
46                 }
47         }
48
49         determine_id();
50
51         const set<Block *> &blocks = layout.get_all<Block>();
52         for(set<Block *>::const_iterator i=blocks.begin(); (!conflict && i!=blocks.end()); ++i)
53                 conflict = (id==(*i)->get_id());
54
55         if(!conflict && sensor_addr)
56                 sensor = new TrackCircuit(layout, *this);
57
58         layout.add(*this);
59 }
60
61 Block::~Block()
62 {
63         set<Track *> trks = tracks;
64         tracks.clear();
65         for(set<Track *>::iterator i=trks.begin(); i!=trks.end(); ++i)
66                 (*i)->set_block(0);
67
68         for(vector<Endpoint>::iterator i=endpoints.begin(); i!=endpoints.end(); ++i)
69                 if(Block *blk = i->link)
70                 {
71                         i->link = 0;
72                         blk->break_link(*this);
73                 }
74
75         layout.remove(*this);
76
77         delete sensor;
78 }
79
80 void Block::set_name(const string &)
81 {
82         throw logic_error("Block names can't be set");
83 }
84
85 void Block::on_track_added(Track &track)
86 {
87         track.set_block(this);
88 }
89
90 TrackChain::Validity Block::check_validity(Track &track) const
91 {
92         if(track.get_sensor_address()!=sensor_addr || track.get_turnout_address()!=turnout_addr)
93                 return INCOMPATIBLE;
94
95         return TrackChain::check_validity(track);
96 }
97
98 const Block::Endpoint &Block::get_endpoint(unsigned i) const
99 {
100         if(i>=endpoints.size())
101                 throw out_of_range("Block::get_endpoint");
102
103         return endpoints[i];
104 }
105
106 int Block::get_endpoint_by_link(Block &other) const
107 {
108         for(unsigned i=0; i<endpoints.size(); ++i)
109                 if(endpoints[i].link==&other)
110                         return i;
111
112         return -1;
113 }
114
115 float Block::get_path_length(unsigned entry, const Route *route) const
116 {
117         if(entry>=endpoints.size())
118                 throw out_of_range("Block::get_path_length");
119
120         TrackIter t_iter = endpoints[entry].track_iter();
121
122         float result = 0;
123         while(t_iter && has_track(*t_iter))
124         {
125                 unsigned path = (route ? route->get_path(*t_iter) : t_iter->get_active_path());
126                 result += t_iter->get_type().get_path_length(path);
127
128                 t_iter = t_iter.next(path);
129         }
130
131         return result;
132 }
133
134 void Block::check_link(Block &other)
135 {
136         for(vector<Endpoint>::iterator i=endpoints.begin(); i!=endpoints.end(); ++i)
137         {
138                 if(i->link)
139                         continue;
140
141                 for(vector<Endpoint>::iterator j=other.endpoints.begin(); j!=other.endpoints.end(); ++j)
142                         if(j->track==i->track->get_link(i->track_ep) && j->track->get_link(j->track_ep)==i->track && !j->link)
143                         {
144                                 i->link = &other;
145                                 j->link = this;
146
147                                 determine_id();
148                                 other.determine_id();
149                         }
150         }
151 }
152
153 void Block::break_link(Block &other)
154 {
155         for(vector<Endpoint>::iterator i=endpoints.begin(); i!=endpoints.end(); ++i)
156                 if(i->link==&other)
157                 {
158                         i->link = 0;
159                         other.break_link(*this);
160                         determine_id();
161                 }
162 }
163
164 Block *Block::get_link(unsigned epi) const
165 {
166         if(epi>=endpoints.size())
167                 throw out_of_range("Block::get_link");
168         return endpoints[epi].link;
169 }
170
171 bool Block::reserve(Train *t)
172 {
173         if(!t || !(emitting_reserve ? pending_train : train))
174         {
175                 pending_train = t;
176                 if(!emitting_reserve)
177                 {
178                         while(pending_train!=train)
179                         {
180                                 train = pending_train;
181                                 SetFlag setf(emitting_reserve);
182                                 signal_reserved.emit(train);
183                         }
184                 }
185
186                 return true;
187         }
188         else
189                 return false;
190 }
191
192 void Block::determine_id()
193 {
194         string n;
195         if(sensor_addr)
196         {
197                 id = 0x1000|sensor_addr;
198                 n = format("Sensor %d", sensor_addr);
199         }
200         else if(turnout_addr)
201         {
202                 id = 0x2000|turnout_addr;
203                 n = format("Turnout %d", turnout_addr);
204         }
205         else if(endpoints.size()==2)
206         {
207                 unsigned id1 = endpoints[0].link ? endpoints[0].link->get_id() : 1;
208                 unsigned id2 = endpoints[1].link ? endpoints[1].link->get_id() : 1;
209                 if(id2<id1)
210                         swap(id1, id2);
211                 id = (id1<<16)|id2;
212         }
213         else if(endpoints.size()==1)
214         {
215                 unsigned id1 = endpoints[0].link ? endpoints[0].link->get_id() : 1;
216                 id = 0x10000 | id1;
217         }
218
219         if(n.empty())
220                 n = format("Block %x", id);
221
222         name = n;
223         signal_name_changed.emit(name);
224 }
225
226 DataFile::Statement Block::save_reference() const
227 {
228         return (DataFile::Statement("block"), id);
229 }
230
231
232 Block::Endpoint::Endpoint(Track *t, unsigned e):
233         track(t),
234         track_ep(e),
235         link(0)
236 { }
237
238 TrackIter Block::Endpoint::track_iter() const
239 {
240         return TrackIter(track, track_ep);
241 }
242
243 } // namespace R2C2