]> git.tdb.fi Git - r2c2.git/blob - source/libr2c2/centralstation.cpp
2138e10702ee27497e70a641edc8fbd12d9d20ab
[r2c2.git] / source / libr2c2 / centralstation.cpp
1 #include <algorithm>
2 #include <msp/core/refptr.h>
3 #include <msp/io/print.h>
4 #include <msp/net/resolve.h>
5 #include <msp/strings/utils.h>
6 #include <msp/time/units.h>
7 #include <msp/time/utils.h>
8 #include "centralstation.h"
9 #include "tracktype.h"
10 #include "vehicletype.h"
11
12 using namespace std;
13 using namespace Msp;
14
15 namespace R2C2 {
16
17 CentralStation::CentralStation(const string &host):
18         socket(Net::INET),
19         pending_commands(0),
20         power(false),
21         halted(false),
22         locos_synced(false),
23         accessories_synced(false),
24         sensors_synced(false)
25 {
26         RefPtr<Net::SockAddr> addr = Net::resolve(host+":15471");
27         socket.connect(*addr);
28
29         IO::print("Connected to central station at %s\n", addr->str());
30
31         command("get(1, status)");
32         command("request(1, view)");
33         command("queryObjects(10, addr, name)");
34         command("queryObjects(11, addr)");
35         command("queryObjects(26)");
36 }
37
38 CentralStation::~CentralStation()
39 {
40         command("release(1, view)", true);
41         for(LocoMap::iterator i=locos.begin(); (i!=locos.end() && !(i->first&0x10000)); ++i)
42                 command(format("release(%d, view, control)", i->first));
43         for(AccessoryMap::iterator i=accessories.begin(); (i!=accessories.end() && !(i->first&0x10000)); ++i)
44                 command(format("release(%d, view, control)", i->first));
45         while(IO::poll(socket, IO::P_INPUT, 100*Time::msec))
46                 while(receive()) ;
47 }
48
49 void CentralStation::set_power(bool p)
50 {
51         power = p;
52         command(format("set(1, %s)", (power ? "go" : "stop")));
53 }
54
55 void CentralStation::halt(bool h)
56 {
57         halted = h;
58         if(halted)
59         {
60                 for(LocoMap::iterator i=locos.begin(); i!=locos.end(); ++i)
61                         if(i->second.speed)
62                                 set_loco_speed(i->first, 0);
63         }
64
65         signal_halt.emit(halted);
66 }
67
68 const char *CentralStation::enumerate_protocols(unsigned index) const
69 {
70         if(index==MM)
71                 return "MM";
72         else if(index==MM_27)
73                 return "MM-27";
74         else if(index==MFX)
75                 return "MFX";
76         else
77                 return 0;
78 }
79
80 unsigned CentralStation::get_protocol_speed_steps(const string &name) const
81 {
82         switch(map_protocol(name))
83         {
84         case MM: return 14;
85         case MM_27: return 27;
86         case MFX: return 126;
87         default: return 0;
88         }
89 }
90
91 void CentralStation::add_loco(unsigned addr, const string &proto_name, const VehicleType &type)
92 {
93         Protocol proto = map_protocol(proto_name);
94
95         unsigned id = map_address(locos, loco_addr, addr);
96         if(!id)
97         {
98                 Locomotive &loco = locos[addr|0x10000];
99                 loco.name = type.get_name();
100                 loco.protocol = proto;
101                 loco.address = addr;
102
103                 const VehicleType::FunctionMap &type_funcs = type.get_functions();
104                 for(VehicleType::FunctionMap::const_iterator i=type_funcs.begin(); i!=type_funcs.end(); ++i)
105                         loco.func_mask |= 1<<i->first;
106
107                 if(locos_synced && proto!=MFX)
108                         command("create(10)");
109         }
110         else
111                 command(format("request(%d, view, control, force)", id));
112 }
113
114 void CentralStation::remove_loco(unsigned addr)
115 {
116         unsigned id = map_address(locos, loco_addr, addr);
117         if(id)
118                 command(format("release(%d, view, control)", id));
119 }
120
121 void CentralStation::set_loco_speed(unsigned addr, unsigned speed)
122 {
123         if(speed && halted)
124                 return;
125
126         unsigned id = map_address(locos, loco_addr, addr);
127         if(id)
128         {
129                 Locomotive &loco = locos[id];
130                 if(loco.protocol==MFX && speed)
131                         ++speed;
132                 command(format("set(%d, speedstep[%d])", id, speed));
133         }
134 }
135
136 void CentralStation::set_loco_reverse(unsigned addr, bool rev)
137 {
138         unsigned id = map_address(locos, loco_addr, addr);
139         if(id)
140                 command(format("set(%d, dir[%d])", id, rev));
141 }
142
143 void CentralStation::set_loco_function(unsigned addr, unsigned func, bool state)
144 {
145         unsigned id = map_address(locos, loco_addr, addr);
146         if(id)
147                 command(format("set(%d, func[%d, %d])", id, func, state));
148 }
149
150 void CentralStation::add_turnout(unsigned addr, const TrackType &type)
151 {
152         unsigned straight = type.get_paths();
153         bool left = false;
154         bool right = false;
155         bool cross = false;
156
157         const vector<TrackPart> &parts = type.get_parts();
158         for(vector<TrackPart>::const_iterator i=parts.begin(); i!=parts.end(); ++i)
159         {
160                 OrientedPoint start = i->get_point(0);
161                 OrientedPoint end = i->get_point(i->get_length());
162                 if(abs(end.rotation-start.rotation).radians()<0.01)
163                 {
164                         (end.rotation>start.rotation ? left : right) = true;
165                         straight &= ~(1<<i->get_path());
166                 }
167                 else if(abs(start.rotation).radians()>0.01)
168                         cross = true;
169         }
170
171         MagnetAccessory::Symbol symbol = MagnetAccessory::TURNOUT_LEFT;
172         if(cross)
173                 symbol = MagnetAccessory::TURNOUT_DOUBLESLIP;
174         else if(left && right)
175                 symbol = MagnetAccessory::TURNOUT_THREEWAY;
176         else if(left)
177                 symbol = (straight ? MagnetAccessory::TURNOUT_LEFT : MagnetAccessory::TURNOUT_CURVED_LEFT);
178         else if(right)
179                 symbol = (straight ? MagnetAccessory::TURNOUT_RIGHT : MagnetAccessory::TURNOUT_CURVED_RIGHT);
180
181         MagnetAccessory &turnout = add_accessory(addr, MagnetAccessory::TURNOUT, symbol);
182         turnout.bits = type.get_state_bits();
183 }
184
185 void CentralStation::remove_turnout(unsigned addr)
186 {
187         remove_accessory(addr);
188 }
189
190 void CentralStation::set_turnout(unsigned addr, unsigned state)
191 {
192         set_accessory_state(addr, MagnetAccessory::TURNOUT, state);
193 }
194
195 unsigned CentralStation::get_turnout(unsigned addr) const
196 {
197         return get_accessory_state(addr, MagnetAccessory::TURNOUT);
198 }
199
200 void CentralStation::add_signal(unsigned addr, const SignalType &)
201 {
202         add_accessory(addr, MagnetAccessory::SIGNAL, MagnetAccessory::SEMAPHORE_HOME);
203 }
204
205 void CentralStation::remove_signal(unsigned addr)
206 {
207         remove_accessory(addr);
208 }
209
210 void CentralStation::set_signal(unsigned addr, unsigned state)
211 {
212         set_accessory_state(addr, MagnetAccessory::SIGNAL, state);
213 }
214
215 unsigned CentralStation::get_signal(unsigned addr) const
216 {
217         return get_accessory_state(addr, MagnetAccessory::SIGNAL);
218 }
219
220 CentralStation::MagnetAccessory &CentralStation::add_accessory(unsigned addr, MagnetAccessory::Type type, MagnetAccessory::Symbol symbol)
221 {
222         unsigned id = map_address(accessories, accessory_addr, addr);
223         if(!id)
224         {
225                 id = addr|0x10000;
226
227                 MagnetAccessory &accessory = accessories[id];
228                 accessory.address = addr;
229                 accessory.type = type;
230                 accessory.symbol = symbol;
231
232                 accessory_addr[addr] = id;
233
234                 if(accessories_synced)
235                         command("create(11, append)");
236
237                 return accessory;
238         }
239         else
240         {
241                 MagnetAccessory &accessory = accessories[id];
242                 command(format("request(%d, view, control)", id));
243                 if(accessory.symbol!=symbol)
244                         command(format("set(%d, symbol[%d])", symbol));
245
246                 return accessory;
247         }
248 }
249
250 void CentralStation::remove_accessory(unsigned addr)
251 {
252         unsigned id = map_address(accessories, accessory_addr, addr);
253         if(id)
254                 command(format("release(%d, view, control)", id));
255 }
256
257 void CentralStation::set_accessory_state(unsigned addr, MagnetAccessory::Type type, unsigned state)
258 {
259         unsigned id = map_address(accessories, accessory_addr, addr);
260         if(id)
261         {
262                 MagnetAccessory &accessory = accessories[id];
263                 if(accessory.type!=type)
264                         throw logic_error("accessory type conflict");
265
266                 unsigned mask = (1<<accessory.bits)-1;
267
268                 if(((state^accessory.state)&mask)==0 || !accessory.synced)
269                 {
270                         accessory.state = state;
271                         accessory_state_changed(accessory);
272                         return;
273                 }
274
275                 accessory.state = (accessory.state&mask) | (state&~mask);
276
277                 command(format("set(%d, state[%d])", id, state&mask));
278         }
279 }
280
281 unsigned CentralStation::get_accessory_state(unsigned addr, MagnetAccessory::Type type) const
282 {
283         unsigned id = map_address(accessories, accessory_addr, addr);
284         if(id)
285         {
286                 AccessoryMap::const_iterator i = accessories.find(id);
287                 if(i!=accessories.end() && i->second.type==type)
288                         return i->second.state;
289         }
290         return 0;
291 }
292
293 void CentralStation::accessory_state_changed(const MagnetAccessory &accessory) const
294 {
295         if(accessory.type==MagnetAccessory::TURNOUT)
296                 signal_turnout.emit(accessory.address, accessory.state);
297         else if(accessory.type==MagnetAccessory::SIGNAL)
298                 signal_signal.emit(accessory.address, accessory.state);
299 }
300
301 void CentralStation::add_sensor(unsigned addr)
302 {
303         sensors.insert(SensorMap::value_type(addr, Sensor()));
304
305         if(sensors_synced)
306         {
307                 if(addr>s88.size()*16)
308                         command("create(26, add[0])");
309         }
310 }
311
312 void CentralStation::remove_sensor(unsigned)
313 {
314 }
315
316 bool CentralStation::get_sensor(unsigned addr) const
317 {
318         SensorMap::const_iterator i = sensors.find(addr);
319         if(i!=sensors.end())
320                 return i->second.state;
321         return false;
322 }
323
324 void CentralStation::tick()
325 {
326         while(Message msg = receive())
327         {
328                 if(msg.footer.code)
329                         IO::print("\033[31m*** ERROR: %s: %d %s ***\033[0m\n", msg.header.value, msg.footer.code, msg.footer.value);
330
331                 if(msg.header.type=="REPLY")
332                         process_reply(msg);
333                 else if(msg.header.type=="EVENT")
334                         process_event(msg);
335         }
336 }
337
338 void CentralStation::flush()
339 {
340 }
341
342 void CentralStation::command(const string &cmd, bool force)
343 {
344         if(pending_commands<10 || force)
345         {
346                 socket.write(cmd+"\r\n");
347                 ++pending_commands;
348         }
349         else
350                 cmd_queue.push_back(cmd);
351 }
352
353 CentralStation::Message CentralStation::receive()
354 {
355         while(IO::poll(socket, IO::P_INPUT, Time::zero))
356         {
357                 char rbuf[1024];
358                 unsigned len = socket.read(rbuf, sizeof(rbuf));
359                 if(!len)
360                         return Message();
361
362                 in_buffer.append(rbuf, len);
363         }
364
365         if(!in_buffer.empty())
366         {
367                 string::iterator iter = in_buffer.begin();
368                 if(Message msg = parse_message(iter, in_buffer.end()))
369                 {
370                         skip(iter, in_buffer.end(), "\r\n");
371                         in_buffer.erase(in_buffer.begin(), iter);
372
373                         if(msg.header.type=="REPLY" && pending_commands>0)
374                         {
375                                 --pending_commands;
376                                 if(!cmd_queue.empty())
377                                 {
378                                         command(cmd_queue.front());
379                                         cmd_queue.pop_front();
380                                 }
381                         }
382
383                         return msg;
384                 }
385         }
386
387         return Message();
388 }
389
390 void CentralStation::process_reply(const Message &msg)
391 {
392         if(!msg.header.value.compare(0, 4, "get("))
393         {
394                 for(Message::ObjectMap::const_iterator i=msg.content.begin(); i!=msg.content.end(); ++i)
395                 {
396                         if(accessories.count(i->first))
397                                 accessories[i->first].synced = true;
398
399                         process_object(i->first, i->second);
400                 }
401         }
402         else if(!msg.header.value.compare(0, 16, "queryObjects(10,"))
403         {
404                 for(Message::ObjectMap::const_iterator i=msg.content.begin(); i!=msg.content.end(); ++i)
405                 {
406                         LocoMap::iterator j = locos.find(i->first);
407                         if(j==locos.end())
408                         {
409                                 bool found = false;
410                                 Message::AttribMap::const_iterator k = i->second.find("addr");
411                                 if(k!=i->second.end())
412                                 {
413                                         unsigned addr = lexical_cast<unsigned>(k->second);
414
415                                         j = locos.find(addr|0x10000);
416                                         if(j!=locos.end())
417                                         {
418                                                 command(format("request(%d, view, control, force)", i->first));
419                                                 string cmd = format("get(%d, dir", i->first);
420                                                 for(unsigned l=0; j->second.func_mask>>l; ++l)
421                                                         if((j->second.func_mask>>l)&1)
422                                                                 cmd += format(", func[%d]", l);
423                                                 cmd += ')';
424                                                 command(cmd);
425
426                                                 locos.insert(LocoMap::value_type(i->first, j->second));
427                                                 locos.erase(j);
428
429                                                 found = true;
430                                         }
431                                 }
432
433                                 if(!found)
434                                         locos.insert(LocoMap::value_type(i->first, Locomotive()));
435                         }
436
437                         process_object(i->first, i->second);
438                 }
439
440                 locos_synced = true;
441
442                 if(locos.lower_bound(0x10000)!=locos.end())
443                         command("create(10)");
444         }
445         else if(!msg.header.value.compare(0, 16, "queryObjects(11,"))
446         {
447                 for(Message::ObjectMap::const_iterator i=msg.content.begin(); i!=msg.content.end(); ++i)
448                 {
449                         AccessoryMap::iterator j = accessories.find(i->first);
450                         if(j==accessories.end())
451                         {
452                                 bool found = false;
453                                 Message::AttribMap::const_iterator k = i->second.find("addr");
454                                 if(k!=i->second.end())
455                                 {
456                                         unsigned addr = lexical_cast<unsigned>(k->second);
457
458                                         j = accessories.find(addr|0x10000);
459                                         if(j!=accessories.end())
460                                         {
461                                                 command(format("request(%d, view, control)", i->first));
462                                                 command(format("set(%d, symbol[%d])", i->first, j->second.symbol));
463                                                 command(format("get(%d, state)", i->first));
464
465                                                 accessories.insert(AccessoryMap::value_type(i->first, j->second));
466                                                 accessories.erase(j);
467
468                                                 found = true;
469                                         }
470                                 }
471
472                                 if(!found)
473                                         accessories.insert(AccessoryMap::value_type(i->first, MagnetAccessory()));
474                         }
475
476                         process_object(i->first, i->second);
477                 }
478
479                 accessories_synced = true;
480
481                 for(AccessoryMap::const_iterator i=accessories.lower_bound(0x10000); i!=accessories.end(); ++i)
482                         command("create(11, append)");
483         }
484         else if(msg.header.value=="queryObjects(26)")
485         {
486                 s88.clear();
487                 for(Message::ObjectMap::const_iterator i=msg.content.begin(); i!=msg.content.end(); ++i)
488                 {
489                         s88.push_back(i->first);
490                         command(format("request(%d, view)", i->first));
491                         command(format("get(%d, state)", i->first));
492                 }
493
494                 sensors_synced = true;
495
496                 if(!sensors.empty())
497                 {
498                         unsigned high_addr = (--sensors.end())->first;
499                         if(high_addr>16*s88.size())
500                                 command("create(26, add[0])");
501                 }
502         }
503         else if(msg.header.value=="create(10)")
504         {
505                 Message::ObjectMap::const_iterator i = msg.content.find(10);
506                 if(i!=msg.content.end())
507                 {
508                         Message::AttribMap::const_iterator j = i->second.find("id");
509                         if(j!=i->second.end())
510                         {
511                                 unsigned id = lexical_cast<unsigned>(j->second);
512                                 LocoMap::iterator k = locos.lower_bound(0x10000);
513                                 if(k!=locos.end())
514                                 {
515                                         command(format("request(%d, view, control)", id));
516                                         command(format("set(%d, addr[%d], protocol[%s], name[\"%s\"])",
517                                                 id, k->second.address, (k->second.protocol==MM_27 ? "MM27" : "MM14"), k->second.name));
518                                         command("create(10, append)");
519
520                                         locos.insert(LocoMap::value_type(id, k->second));
521                                         locos.erase(k);
522                                 }
523                         }
524                 }
525
526                 if(locos.lower_bound(0x10000)!=locos.end())
527                         command("create(10)");
528         }
529         else if(!msg.header.value.compare(0, 10, "create(11,"))
530         {
531                 Message::ObjectMap::const_iterator i = msg.content.find(11);
532                 if(i!=msg.content.end())
533                 {
534                         Message::AttribMap::const_iterator j = i->second.find("id");
535                         if(j!=i->second.end())
536                         {
537                                 unsigned id = lexical_cast<unsigned>(j->second);
538                                 AccessoryMap::iterator k = accessories.lower_bound(0x10000);
539                                 if(k!=accessories.end())
540                                 {
541                                         command(format("request(%d, view, control)", id));
542                                         const char *label = (k->second.type==MagnetAccessory::SIGNAL ? "Signal" : "Switch");
543                                         command(format("set(%d, addr[%d], symbol[%d], name1[\"%s\"], name2[\"%d\"], name3[\"\"])",
544                                                 id, k->second.address, k->second.symbol, label, k->second.address));
545                                         command(format("set(%d, state[%d])", id, k->second.state&((1<<k->second.bits)-1)));
546
547                                         k->second.synced = true;
548                                         accessories.insert(AccessoryMap::value_type(id, k->second));
549                                         accessories.erase(k);
550                                 }
551                         }
552                 }
553         }
554         else if(!msg.header.value.compare(0, 10, "create(26,"))
555                 command("queryObjects(26)");
556 }
557
558 void CentralStation::process_event(const Message &msg)
559 {
560         for(Message::ObjectMap::const_iterator i=msg.content.begin(); i!=msg.content.end(); ++i)
561                 process_object(i->first, i->second);
562 }
563
564 void CentralStation::process_object(unsigned id, const Message::AttribMap &attribs)
565 {
566         if(id==1)
567         {
568                 for(Message::AttribMap::const_iterator i=attribs.begin(); i!=attribs.end(); ++i)
569                         if(i->first=="status")
570                         {
571                                 power = (i->second=="GO");
572                                 signal_power.emit(power);
573                         }
574         }
575         else if(locos.count(id))
576         {
577                 Locomotive &loco = locos[id];
578                 bool speed_changed = false;
579                 unsigned funcs_changed = 0;
580                 for(Message::AttribMap::const_iterator i=attribs.begin(); i!=attribs.end(); ++i)
581                 {
582                         if(i->first=="name")
583                                 loco.name = i->second.substr(1, i->second.size()-2);
584                         else if(i->first=="addr")
585                         {
586                                 loco_addr.erase(loco.address);
587                                 loco.address = lexical_cast<unsigned>(i->second);
588                                 loco_addr[loco.address] = id;
589                         }
590                         else if(i->first=="protocol")
591                         {
592                                 if(i->second=="MM")
593                                         loco.protocol = MM;
594                                 else if(i->second=="MM27")
595                                         loco.protocol = MM_27;
596                                 else if(i->second=="MFX")
597                                         loco.protocol = MFX;
598                         }
599                         else if(i->first=="speedstep")
600                         {
601                                 loco.speed = lexical_cast<unsigned>(i->second);
602                                 if(loco.protocol==MFX && loco.speed)
603                                         --loco.speed;
604                                 speed_changed = true;
605                         }
606                         else if(i->first=="dir")
607                         {
608                                 loco.reverse = i->second[0]!='0';
609                                 speed_changed = true;
610                         }
611                         else if(i->first=="func")
612                         {
613                                 vector<string> parts = split(i->second, ", ");
614                                 unsigned func = lexical_cast<unsigned>(parts[0]);
615                                 bool value = lexical_cast<unsigned>(parts[1]);
616                                 loco.funcs &= ~(1<<func);
617                                 if(value)
618                                         loco.funcs |= 1<<func;
619                                 funcs_changed |= 1<<func;
620                         }
621                         else if(i->first=="msg")
622                         {
623                                 if(i->second=="CONTROL_LOST")
624                                         command(format("request(%d, control, force)", id));
625                         }
626                 }
627
628                 if(speed_changed)
629                         signal_loco_speed.emit(loco.address, loco.speed, loco.reverse);
630                 for(unsigned i=0; funcs_changed>>i; ++i)
631                         if(funcs_changed&(1<<i))
632                                 signal_loco_function.emit(loco.address, i, loco.funcs&(1<<i));
633         }
634         else if(accessories.count(id))
635         {
636                 MagnetAccessory &accessory = accessories[id];
637                 bool state_changed = false;
638                 for(Message::AttribMap::const_iterator i=attribs.begin(); i!=attribs.end(); ++i)
639                 {
640                         if(i->first=="addr")
641                         {
642                                 accessory_addr.erase(accessory.address);
643                                 accessory.address = lexical_cast<unsigned>(i->second);
644                                 accessory_addr[accessory.address] = id;
645                         }
646                         else if(i->first=="state")
647                         {
648                                 unsigned state = lexical_cast<unsigned>(i->second);
649                                 unsigned mask = (1<<accessory.bits)-1;
650                                 accessory.state = (accessory.state&~mask) | (state&mask);
651                                 state_changed = true;
652                         }
653                 }
654
655                 if(state_changed)
656                         accessory_state_changed(accessory);
657         }
658         else if(find(s88.begin(), s88.end(), id)!=s88.end())
659         {
660                 unsigned base = 0;
661                 for(; (base<s88.size() && s88[base]!=id); ++base) ;
662
663                 for(Message::AttribMap::const_iterator i=attribs.begin(); i!=attribs.end(); ++i)
664                 {
665                         if(i->first=="state")
666                         {
667                                 unsigned state = lexical_cast<unsigned>(i->second, "%i");
668                                 for(unsigned j=0; j<16; ++j)
669                                 {
670                                         unsigned addr = base*16+j+1;
671                                         Sensor &sensor = sensors[addr];
672                                         bool s = state&(1<<j);
673                                         if(s!=sensor.state)
674                                         {
675                                                 sensor.state = s;
676                                                 signal_sensor.emit(addr, sensor.state);
677                                         }
678                                 }
679                         }
680                 }
681         }
682 }
683
684 CentralStation::Protocol CentralStation::map_protocol(const string &name) const
685 {
686         if(name=="MM")
687                 return MM;
688         else if(name=="MM-27")
689                 return MM_27;
690         else if(name=="MFX")
691                 return MFX;
692         else
693                 throw invalid_argument("CentralStation::map_protocol");
694 }
695
696 template<typename T>
697 unsigned CentralStation::map_address(const map<unsigned, T> &omap, const AddressMap &amap, unsigned addr) const
698 {
699         if(omap.count(addr))
700                 return addr;
701         else
702         {
703                 AddressMap::const_iterator i = amap.find(addr);
704                 if(i!=amap.end())
705                         return i->second;
706                 else
707                         return 0;
708         }
709 }
710
711 void CentralStation::skip(string::iterator &iter, const string::iterator &end, const string &what) const
712 {
713         for(; (iter!=end && what.find(*iter)!=string::npos); ++iter) ;
714 }
715
716 string CentralStation::parse_token(string::iterator &iter, const string::iterator &end, const string &stop) const
717 {
718         vector<char> parens;
719         bool quote = false;
720         string token;
721
722         skip(iter, end, stop);
723
724         for(; iter!=end; ++iter)
725         {
726                 if(stop.find(*iter)!=string::npos && parens.empty() && !quote)
727                         break;
728                 else if(*iter=='(' || *iter=='[')
729                         parens.push_back(*iter);
730                 else if((*iter==')' || *iter==']') && !parens.empty())
731                 {
732                         if((*iter==')' && parens.back()!='(') || (*iter==']' && parens.back()!='['))
733                                 IO::print("Mismatched parentheses\n");
734                         parens.pop_back();
735                 }
736                 else if(*iter=='"')
737                         quote = !quote;
738
739                 token += *iter;
740         }
741
742         return token;
743 }
744
745 CentralStation::Tag CentralStation::parse_tag(string::iterator &iter, const string::iterator &end) const
746 {
747         Tag tag;
748
749         for(; (iter!=end && *iter!='<'); ++iter) ;
750         if(iter==end)
751                 return Tag();
752
753         tag.type = parse_token(++iter, end, " >");
754         if(tag.type=="END")
755         {
756                 string code = parse_token(iter, end, " >");
757                 tag.code = lexical_cast<unsigned>(code);
758         }
759         skip(iter, end, " ");
760         tag.value = parse_token(iter, end, ">");
761         if(iter==end)
762                 return Tag();
763         ++iter;
764
765         return tag;
766 }
767
768 CentralStation::Message CentralStation::parse_message(string::iterator &iter, const string::iterator &end) const
769 {
770         Message msg;
771
772         msg.header = parse_tag(iter, end);
773
774         while(iter!=end)
775         {
776                 skip(iter, end, "\r\n");
777                 if(*iter=='<')
778                         break;
779
780                 string id = parse_token(iter, end, " \r\n<");
781                 Message::AttribMap &attribs = msg.content[lexical_cast<unsigned>(id)];
782                 while(iter!=end && *iter!='\n' && *iter!='\r')
783                 {
784                         string attr = parse_token(iter, end, " \r\n<");
785                         string::size_type open_bracket = attr.find('[');
786                         if(open_bracket!=string::npos)
787                         {
788                                 string::size_type close_bracket = attr.rfind(']');
789                                 string attr_name = attr.substr(0, open_bracket);
790                                 string attr_value = attr.substr(open_bracket+1, close_bracket-open_bracket-1);
791                                 attribs.insert(Message::AttribMap::value_type(attr_name, attr_value));
792                         }
793                         else
794                                 attribs.insert(Message::AttribMap::value_type(attr, string()));
795                 }
796         }
797
798         msg.footer = parse_tag(iter, end);
799         if(msg.footer.type.empty())
800                 return Message();
801
802         return msg;
803 }
804
805
806 CentralStation::Tag::Tag():
807         code(0)
808 { }
809
810 CentralStation::Tag::operator bool() const
811 {
812         return !type.empty();
813 }
814
815
816 CentralStation::Message::operator bool() const
817 {
818         return header && footer;
819 }
820
821
822 CentralStation::Locomotive::Locomotive():
823         address(0),
824         speed(0),
825         reverse(false),
826         func_mask(0),
827         funcs(0),
828         control(false)
829 { }
830
831
832 CentralStation::MagnetAccessory::MagnetAccessory():
833         address(0),
834         type(TURNOUT),
835         symbol(TURNOUT_LEFT),
836         state(0),
837         bits(1),
838         synced(false)
839 { }
840
841
842 CentralStation::Sensor::Sensor():
843         state(false)
844 { }
845
846 } // namespace R2C2