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