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