]> git.tdb.fi Git - r2c2.git/blob - source/libr2c2/arducontrol.h
Add some more range checks in ArduControl and improve existing ones
[r2c2.git] / source / libr2c2 / arducontrol.h
1 #ifndef LIBR2C2_ARDUCONTROL_H_
2 #define LIBR2C2_ARDUCONTROL_H_
3
4 #include <msp/core/mutex.h>
5 #include <msp/core/thread.h>
6 #include <msp/io/serial.h>
7 #include <msp/time/timedelta.h>
8 #include <msp/time/timestamp.h>
9 #include "driver.h"
10
11 namespace R2C2 {
12
13 class ArduControl: public Driver
14 {
15 private:
16         enum Command
17         {
18                 POWER_ON = 0x01,
19                 POWER_OFF = 0x02,
20                 READ_TRACK_CURRENT = 0x08,
21                 SET_OVERCURRENT_LIMIT = 0x09,
22                 READ_INPUT_VOLTAGE = 0x0A,
23                 MOTOROLA_SPEED = 0x11,
24                 MOTOROLA_REVERSE = 0x12,
25                 MOTOROLA_SPEED_DIRECTION = 0x13,
26                 MOTOROLA_SPEED_FUNCTION = 0x14,
27                 MOTOROLA_SOLENOID = 0x15,
28                 S88_READ = 0x30,
29                 COMMAND_OK = 0x80,
30                 RECEIVE_OVERRUN = 0x81,
31                 FRAMING_ERROR = 0x82,
32                 INVALID_COMMAND = 0x83,
33                 LENGTH_ERROR = 0x84,
34                 INVALID_VALUE = 0x85,
35                 OVERCURRENT = 0xA0,
36                 TRACK_CURRENT = 0xC0,
37                 INPUT_VOLTAGE = 0xC1,
38                 S88_DATA = 0xD0
39         };
40
41         struct Tag
42         {
43                 enum Type
44                 {
45                         NONE,
46                         GENERAL,
47                         LOCOMOTIVE,
48                         ACCESSORY,
49                         SENSOR
50                 };
51
52                 Type type;
53                 unsigned char command;
54                 unsigned short serial;
55                 unsigned id;
56
57                 Tag();
58
59                 operator bool() const { return type!=NONE; }
60         };
61
62         enum GeneralCommand
63         {
64                 POWER
65         };
66
67         enum Protocol
68         {
69                 MM
70         };
71
72         struct ProtocolInfo
73         {
74                 unsigned max_address;
75                 unsigned max_speed;
76                 unsigned max_func;
77         };
78
79         template<typename T>
80         struct ControlledVariable
81         {
82                 T current;
83                 T pending;
84                 unsigned short serial;
85
86                 ControlledVariable(): current(), pending(), serial(0) { }
87                 ControlledVariable(T v): current(v), pending(v), serial(0) { }
88
89                 bool set(T v) { if(v==pending) return false; pending = v; ++serial; return true; }
90                 bool commit(unsigned short s) { if(s!=serial) return false; current = pending; return true; }
91
92                 operator T() const { return current; }
93         };
94
95         struct Locomotive
96         {
97                 enum Command
98                 {
99                         SPEED,
100                         REVERSE,
101                         FUNCTIONS
102                 };
103
104                 unsigned id;
105                 Protocol proto;
106                 unsigned address;
107                 ControlledVariable<unsigned> speed;
108                 ControlledVariable<bool> reverse;
109                 ControlledVariable<unsigned> funcs;
110                 unsigned last_change_age;
111
112                 Locomotive(Protocol, unsigned);
113
114                 unsigned create_speed_dir_command(char *) const;
115                 unsigned create_speed_func_command(unsigned, char *) const;
116         };
117
118         struct Accessory
119         {
120                 enum Kind
121                 {
122                         TURNOUT,
123                         SIGNAL
124                 };
125
126                 enum Command
127                 {
128                         ACTIVATE,
129                         DEACTIVATE
130                 };
131
132                 Kind kind;
133                 unsigned address;
134                 unsigned bits;
135                 ControlledVariable<unsigned> state;
136                 unsigned target;
137                 Msp::Time::TimeDelta active_time;
138
139                 Accessory(Kind, unsigned, unsigned);
140
141                 unsigned create_state_command(unsigned, bool, char *) const;
142         };
143
144         struct Sensor
145         {
146                 enum Command
147                 {
148                         STATE
149                 };
150
151                 unsigned address;
152                 ControlledVariable<bool> state;
153
154                 Sensor(unsigned);
155         };
156
157         class ControlThread: public Msp::Thread
158         {
159         private:
160                 ArduControl &control;
161                 bool done;
162
163         public:
164                 ControlThread(ArduControl &);
165
166                 void exit();
167         private:
168                 virtual void main();
169         };
170
171         struct QueuedCommand
172         {
173                 Tag tag;
174                 char command[15];
175                 unsigned char length;
176
177                 QueuedCommand();
178                 QueuedCommand(GeneralCommand);
179                 QueuedCommand(Locomotive &, Locomotive::Command, unsigned = 0);
180                 QueuedCommand(Accessory &, Accessory::Command, unsigned = 0);
181         };
182
183         typedef std::map<unsigned, Locomotive> LocomotiveMap;
184         typedef std::list<Locomotive *> LocomotivePtrList;
185         typedef std::map<unsigned, Accessory> AccessoryMap;
186         typedef std::list<Accessory *> AccessoryPtrList;
187         typedef std::map<unsigned, Sensor> SensorMap;
188
189         Msp::IO::Serial serial;
190         bool debug;
191
192         ControlledVariable<bool> power;
193
194         LocomotiveMap locomotives;
195         LocomotivePtrList refresh_cycle;
196         LocomotivePtrList::iterator next_refresh;
197         unsigned refresh_counter;
198         AccessoryMap accessories;
199         AccessoryPtrList accessory_queue;
200         Accessory *active_accessory;
201         Msp::Time::TimeStamp off_timeout;
202         std::list<QueuedCommand> command_queue;
203         std::list<Tag> completed_commands;
204
205         SensorMap sensors;
206         unsigned n_s88_octets;
207
208         Msp::Mutex mutex;
209         ControlThread thread;
210
211         static ProtocolInfo protocol_info[2];
212
213 public:
214         ArduControl(const std::string &);
215         ~ArduControl();
216
217         virtual void set_power(bool);
218         virtual bool get_power() const { return power; }
219         virtual void halt(bool);
220         virtual bool is_halted() const { return false; }
221
222         virtual const char *enumerate_protocols(unsigned) const;
223 private:
224         static Protocol map_protocol(const std::string &);
225 public:
226         virtual unsigned get_protocol_speed_steps(const std::string &) const;
227
228         virtual unsigned add_loco(unsigned, const std::string &, const VehicleType &);
229         virtual void remove_loco(unsigned);
230         virtual void set_loco_speed(unsigned, unsigned);
231         virtual void set_loco_reverse(unsigned, bool);
232         virtual void set_loco_function(unsigned, unsigned, bool);
233 private:
234         void add_loco_to_refresh(Locomotive &);
235         void remove_loco_from_refresh(Locomotive &);
236         Locomotive *get_loco_to_refresh();
237         void advance_next_refresh();
238
239 public:
240         virtual unsigned add_turnout(unsigned, const TrackType &);
241         virtual void remove_turnout(unsigned);
242         virtual void set_turnout(unsigned, unsigned);
243         virtual unsigned get_turnout(unsigned) const;
244
245         virtual unsigned add_signal(unsigned, const SignalType &);
246         virtual void remove_signal(unsigned);
247         virtual void set_signal(unsigned, unsigned);
248         virtual unsigned get_signal(unsigned) const;
249
250 private:
251         unsigned add_accessory(Accessory::Kind, unsigned, unsigned);
252         void remove_accessory(Accessory::Kind, unsigned);
253         void set_accessory(Accessory::Kind, unsigned, unsigned);
254         unsigned get_accessory(Accessory::Kind, unsigned) const;
255
256 public:
257         virtual unsigned add_sensor(unsigned);
258         virtual void remove_sensor(unsigned);
259         virtual void set_sensor(unsigned, bool) { }
260         virtual bool get_sensor(unsigned) const;
261
262         virtual void tick();
263         virtual void flush();
264
265 private:
266         void push_command(const QueuedCommand &);
267         bool pop_command(QueuedCommand &);
268         void push_completed_tag(const Tag &);
269         Tag pop_completed_tag();
270 };
271
272 } // namespace R2C2
273
274 #endif