]> git.tdb.fi Git - r2c2.git/blob - source/libr2c2/arducontrol.h
Move further stuff from the ArduControl main class into Task classes
[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_POWER_STATE = 0x03,
21                 READ_TRACK_CURRENT = 0x08,
22                 SET_OVERCURRENT_LIMIT = 0x09,
23                 READ_INPUT_VOLTAGE = 0x0A,
24                 MOTOROLA_SPEED = 0x11,
25                 MOTOROLA_REVERSE = 0x12,
26                 MOTOROLA_SPEED_DIRECTION = 0x13,
27                 MOTOROLA_SPEED_FUNCTION = 0x14,
28                 MOTOROLA_SOLENOID = 0x15,
29                 MFX_SET_STATION_ID = 0x21,
30                 MFX_ANNOUNCE = 0x22,
31                 MFX_SEARCH = 0x23,
32                 MFX_ASSIGN_ADDRESS = 0x24,
33                 MFX_PING = 0x25,
34                 MFX_SPEED = 0x28,
35                 MFX_SPEED_FUNCS8 = 0x29,
36                 MFX_SPEED_FUNCS16 = 0x2A,
37                 S88_READ = 0x30,
38                 COMMAND_OK = 0x80,
39                 RECEIVE_OVERRUN = 0x81,
40                 FRAMING_ERROR = 0x82,
41                 INVALID_COMMAND = 0x83,
42                 LENGTH_ERROR = 0x84,
43                 INVALID_VALUE = 0x85,
44                 OVERCURRENT = 0xA0,
45                 TRACK_CURRENT = 0xC0,
46                 INPUT_VOLTAGE = 0xC1,
47                 POWER_STATE = 0xC2,
48                 S88_DATA = 0xD0,
49                 MFX_FEEDBACK = 0xD1
50         };
51
52         struct Tag
53         {
54                 enum Type
55                 {
56                         NONE,
57                         GENERAL,
58                         LOCOMOTIVE,
59                         ACCESSORY,
60                         SENSOR
61                 };
62
63                 Type type;
64                 unsigned char command;
65                 unsigned short serial;
66                 unsigned id;
67
68                 Tag();
69
70                 operator bool() const { return type!=NONE; }
71         };
72
73         enum GeneralCommand
74         {
75                 POWER
76         };
77
78         enum Protocol
79         {
80                 MM,
81                 MFX
82         };
83
84         struct ProtocolInfo
85         {
86                 unsigned max_address;
87                 unsigned max_speed;
88                 unsigned max_func;
89         };
90
91         template<typename T>
92         struct ControlledVariable
93         {
94                 T current;
95                 T pending;
96                 unsigned short serial;
97
98                 ControlledVariable(): current(), pending(), serial(0) { }
99                 ControlledVariable(T v): current(v), pending(v), serial(0) { }
100
101                 bool set(T v) { if(v==pending) return false; pending = v; ++serial; return true; }
102                 bool commit(unsigned short s) { if(s!=serial) return false; current = pending; return true; }
103
104                 operator T() const { return current; }
105         };
106
107         struct Locomotive
108         {
109                 enum Command
110                 {
111                         SPEED,
112                         REVERSE,
113                         FUNCTIONS
114                 };
115
116                 unsigned id;
117                 Protocol proto;
118                 unsigned address;
119                 ControlledVariable<unsigned> speed;
120                 ControlledVariable<bool> reverse;
121                 ControlledVariable<unsigned> funcs;
122                 unsigned last_change_age;
123
124                 Locomotive(Protocol, unsigned);
125
126                 unsigned create_speed_dir_command(char *) const;
127                 unsigned create_speed_func_command(unsigned, char *) const;
128         };
129
130         struct Accessory
131         {
132                 enum Kind
133                 {
134                         TURNOUT,
135                         SIGNAL
136                 };
137
138                 enum Command
139                 {
140                         ACTIVATE,
141                         DEACTIVATE
142                 };
143
144                 Kind kind;
145                 unsigned address;
146                 unsigned bits;
147                 ControlledVariable<unsigned> state;
148                 unsigned target;
149                 Msp::Time::TimeDelta active_time;
150
151                 Accessory(Kind, unsigned, unsigned);
152
153                 unsigned create_state_command(unsigned, bool, char *) const;
154         };
155
156         struct Sensor
157         {
158                 enum Command
159                 {
160                         STATE
161                 };
162
163                 unsigned address;
164                 ControlledVariable<bool> state;
165
166                 Sensor(unsigned);
167         };
168
169         struct PendingCommand
170         {
171                 Tag tag;
172                 char command[15];
173                 unsigned char length;
174                 unsigned repeat_count;
175
176                 PendingCommand();
177                 PendingCommand(GeneralCommand);
178                 PendingCommand(Locomotive &, Locomotive::Command, unsigned = 0);
179                 PendingCommand(Accessory &, Accessory::Command, unsigned = 0);
180         };
181
182         class Task
183         {
184         protected:
185                 Task() { }
186         public:
187                 virtual ~Task() { }
188
189                 virtual bool get_work(PendingCommand &) = 0;
190                 virtual void process_reply(const char *, unsigned) { }
191         };
192
193         class RefreshTask: public Task
194         {
195         private:
196                 typedef std::list<Locomotive *> LocomotivePtrList;
197
198                 LocomotivePtrList cycle;
199                 LocomotivePtrList::iterator next;
200                 unsigned round;
201                 Locomotive *loco;
202                 unsigned phase;
203                 Msp::Mutex mutex;
204
205         public:
206                 RefreshTask();
207
208                 virtual bool get_work(PendingCommand &);
209
210                 void add_loco(Locomotive &);
211                 void remove_loco(Locomotive &);
212         private:
213                 Locomotive *get_next_loco();
214                 void advance();
215         };
216
217         class S88Task: public Task
218         {
219         private:
220                 ArduControl &control;
221                 unsigned n_octets;
222                 unsigned octets_remaining;
223
224         public:
225                 S88Task(ArduControl &);
226
227                 virtual bool get_work(PendingCommand &);
228                 virtual void process_reply(const char *, unsigned);
229
230                 void set_n_octets(unsigned);
231                 void grow_n_octets(unsigned);
232         };
233
234         class MfxAnnounceTask: public Task
235         {
236         private:
237                 unsigned serial;
238                 Msp::Time::TimeStamp next;
239
240         public:
241                 MfxAnnounceTask();
242
243                 virtual bool get_work(PendingCommand &);
244
245                 void set_serial(unsigned);
246         };
247
248         class MfxSearchTask: public Task
249         {
250         private:
251                 ArduControl &control;
252                 unsigned next_address;
253                 Msp::Time::TimeStamp next;
254                 unsigned size;
255                 unsigned bits;
256                 bool pending;
257
258         public:
259                 MfxSearchTask(ArduControl &);
260
261                 virtual bool get_work(PendingCommand &);
262                 virtual void process_reply(const char *, unsigned);
263         };
264
265         class ControlThread: public Msp::Thread
266         {
267         private:
268                 ArduControl &control;
269                 bool done;
270                 std::vector<Task *> tasks;
271
272         public:
273                 ControlThread(ArduControl &);
274
275                 void exit();
276         private:
277                 virtual void main();
278                 bool get_work(PendingCommand &);
279                 unsigned do_command(const PendingCommand &);
280                 unsigned process_reply(const char *, unsigned);
281         };
282
283         typedef std::map<unsigned, Locomotive> LocomotiveMap;
284         typedef std::map<unsigned, Accessory> AccessoryMap;
285         typedef std::list<Accessory *> AccessoryPtrList;
286         typedef std::map<unsigned, Sensor> SensorMap;
287
288         Msp::IO::Serial serial;
289         unsigned debug;
290
291         ControlledVariable<bool> power;
292
293         LocomotiveMap locomotives;
294         AccessoryMap accessories;
295         AccessoryPtrList accessory_queue;
296         Accessory *active_accessory;
297         Msp::Time::TimeStamp off_timeout;
298         std::list<PendingCommand> command_queue;
299         std::list<Tag> completed_commands;
300
301         SensorMap sensors;
302
303         Msp::Mutex mutex;
304         RefreshTask refresh;
305         S88Task s88;
306         MfxAnnounceTask mfx_announce;
307         MfxSearchTask mfx_search;
308         ControlThread thread;
309
310         static ProtocolInfo protocol_info[2];
311
312 public:
313         ArduControl(const std::string &);
314         ~ArduControl();
315
316         virtual void set_power(bool);
317         virtual bool get_power() const { return power; }
318         virtual void halt(bool);
319         virtual bool is_halted() const { return false; }
320
321         virtual const char *enumerate_protocols(unsigned) const;
322 private:
323         static Protocol map_protocol(const std::string &);
324 public:
325         virtual unsigned get_protocol_speed_steps(const std::string &) const;
326
327         virtual unsigned add_loco(unsigned, const std::string &, const VehicleType &);
328         virtual void remove_loco(unsigned);
329         virtual void set_loco_speed(unsigned, unsigned);
330         virtual void set_loco_reverse(unsigned, bool);
331         virtual void set_loco_function(unsigned, unsigned, bool);
332
333         virtual unsigned add_turnout(unsigned, const TrackType &);
334         virtual void remove_turnout(unsigned);
335         virtual void set_turnout(unsigned, unsigned);
336         virtual unsigned get_turnout(unsigned) const;
337
338         virtual unsigned add_signal(unsigned, const SignalType &);
339         virtual void remove_signal(unsigned);
340         virtual void set_signal(unsigned, unsigned);
341         virtual unsigned get_signal(unsigned) const;
342
343 private:
344         unsigned add_accessory(Accessory::Kind, unsigned, unsigned);
345         void remove_accessory(Accessory::Kind, unsigned);
346         void set_accessory(Accessory::Kind, unsigned, unsigned);
347         unsigned get_accessory(Accessory::Kind, unsigned) const;
348
349 public:
350         virtual unsigned add_sensor(unsigned);
351         virtual void remove_sensor(unsigned);
352         virtual void set_sensor(unsigned, bool) { }
353         virtual bool get_sensor(unsigned) const;
354
355         virtual void tick();
356         virtual void flush();
357
358 private:
359         void push_command(const PendingCommand &);
360         bool pop_command(PendingCommand &);
361         void push_completed_tag(const Tag &);
362         Tag pop_completed_tag();
363 };
364
365 } // namespace R2C2
366
367 #endif