]> git.tdb.fi Git - r2c2.git/blob - source/libr2c2/arducontrol.h
Provide some telemetry values from ArduControl
[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/datafile/objectloader.h>
7 #include <msp/fs/path.h>
8 #include <msp/io/serial.h>
9 #include <msp/time/timedelta.h>
10 #include <msp/time/timestamp.h>
11 #include "driver.h"
12
13 namespace R2C2 {
14
15 class ArduControl: public Driver
16 {
17 public:
18         class Loader: public Msp::DataFile::ObjectLoader<ArduControl>
19         {
20         public:
21                 Loader(ArduControl &);
22
23         private:
24                 void mfx_announce_serial(unsigned);
25                 void mfx_locomotive(unsigned);
26         };
27
28 private:
29         enum Command
30         {
31                 POWER_ON = 0x01,
32                 POWER_OFF = 0x02,
33                 READ_POWER_STATE = 0x03,
34                 READ_TRACK_CURRENT = 0x08,
35                 SET_OVERCURRENT_LIMIT = 0x09,
36                 READ_INPUT_VOLTAGE = 0x0A,
37                 MOTOROLA_SPEED = 0x11,
38                 MOTOROLA_REVERSE = 0x12,
39                 MOTOROLA_SPEED_DIRECTION = 0x13,
40                 MOTOROLA_SPEED_FUNCTION = 0x14,
41                 MOTOROLA_SOLENOID = 0x15,
42                 MFX_SET_STATION_ID = 0x21,
43                 MFX_ANNOUNCE = 0x22,
44                 MFX_SEARCH = 0x23,
45                 MFX_ASSIGN_ADDRESS = 0x24,
46                 MFX_PING = 0x25,
47                 MFX_SPEED = 0x28,
48                 MFX_SPEED_FUNCS8 = 0x29,
49                 MFX_SPEED_FUNCS16 = 0x2A,
50                 S88_READ = 0x30,
51                 SET_BAUD_RATE = 0x70,
52                 COMMAND_OK = 0x80,
53                 RECEIVE_OVERRUN = 0x81,
54                 FRAMING_ERROR = 0x82,
55                 INVALID_COMMAND = 0x83,
56                 LENGTH_ERROR = 0x84,
57                 INVALID_VALUE = 0x85,
58                 OVERCURRENT = 0xA0,
59                 BAUD_CHANGE_FAILED = 0xA1,
60                 TRACK_CURRENT = 0xC0,
61                 INPUT_VOLTAGE = 0xC1,
62                 POWER_STATE = 0xC2,
63                 S88_DATA = 0xD0,
64                 MFX_SEARCH_FEEDBACK = 0xD1,
65                 MFX_PING_FEEDBACK = 0xD2
66         };
67
68         struct Tag
69         {
70                 enum Type
71                 {
72                         NONE,
73                         GENERAL,
74                         LOCOMOTIVE,
75                         ACCESSORY,
76                         SENSOR
77                 };
78
79                 Type type;
80                 unsigned char command;
81                 unsigned short serial;
82                 unsigned id;
83
84                 Tag();
85
86                 operator bool() const { return type!=NONE; }
87         };
88
89         enum GeneralCommand
90         {
91                 POWER,
92                 NEW_LOCO
93         };
94
95         enum Protocol
96         {
97                 MM,
98                 MFX
99         };
100
101         struct ProtocolInfo
102         {
103                 unsigned max_address;
104                 unsigned max_speed;
105                 unsigned max_func;
106         };
107
108         template<typename T>
109         struct ControlledVariable
110         {
111                 T current;
112                 T pending;
113                 unsigned short serial;
114
115                 ControlledVariable(): current(), pending(), serial(0) { }
116                 ControlledVariable(T v): current(v), pending(v), serial(0) { }
117
118                 bool set(T v) { if(v==pending) return false; pending = v; ++serial; return true; }
119                 bool commit(unsigned short s) { if(s!=serial) return false; current = pending; return true; }
120                 void rollback() { pending = current; ++serial; }
121
122                 operator T() const { return current; }
123         };
124
125         struct Locomotive
126         {
127                 enum Command
128                 {
129                         SPEED,
130                         REVERSE,
131                         FUNCTIONS
132                 };
133
134                 unsigned id;
135                 Protocol proto;
136                 unsigned address;
137                 ControlledVariable<unsigned> speed;
138                 ControlledVariable<bool> reverse;
139                 ControlledVariable<unsigned> funcs;
140                 unsigned last_change_age;
141
142                 Locomotive(Protocol, unsigned);
143
144                 unsigned create_speed_dir_command(char *) const;
145                 unsigned create_speed_func_command(unsigned, char *) const;
146         };
147
148         struct MfxInfo: public DetectedLocomotive
149         {
150                 class Loader: public Msp::DataFile::ObjectLoader<MfxInfo>
151                 {
152                 public:
153                         Loader(MfxInfo &);
154                 };
155
156                 unsigned id;
157         };
158
159         struct Accessory
160         {
161                 enum Kind
162                 {
163                         TURNOUT,
164                         SIGNAL
165                 };
166
167                 enum Command
168                 {
169                         ACTIVATE,
170                         DEACTIVATE
171                 };
172
173                 Kind kind;
174                 unsigned address;
175                 unsigned bits;
176                 unsigned valid_states;
177                 ControlledVariable<unsigned> state;
178                 unsigned uncertain;
179                 unsigned target;
180                 Msp::Time::TimeDelta active_time;
181
182                 Accessory(Kind, unsigned, unsigned, unsigned);
183
184                 unsigned create_state_command(unsigned, bool, char *) const;
185         };
186
187         struct Sensor
188         {
189                 enum Command
190                 {
191                         STATE
192                 };
193
194                 unsigned address;
195                 ControlledVariable<bool> state;
196
197                 Sensor(unsigned);
198         };
199
200         struct PendingCommand
201         {
202                 Tag tag;
203                 char command[15];
204                 unsigned char length;
205                 unsigned repeat_count;
206
207                 PendingCommand();
208                 PendingCommand(GeneralCommand);
209                 PendingCommand(Locomotive &, Locomotive::Command, unsigned = 0);
210                 PendingCommand(Accessory &, Accessory::Command, unsigned = 0);
211         };
212
213         template<typename T>
214         class Queue
215         {
216         private:
217                 std::list<T> items;
218                 Msp::Mutex mutex;
219
220         public:
221                 void push(const T &);
222                 bool pop(T &);
223                 unsigned size() const;
224                 bool empty() const;
225         };
226
227         class Task
228         {
229         protected:
230                 std::string name;
231                 unsigned priority;
232                 Msp::Time::TimeStamp sleep_timeout;
233
234                 Task(const std::string &, unsigned = 0);
235         public:
236                 virtual ~Task() { }
237
238                 const std::string &get_name() const { return name; }
239
240                 virtual bool get_work(PendingCommand &) = 0;
241                 virtual void process_reply(const char *, unsigned) { }
242
243                 unsigned get_priority() const { return priority; }
244                 const Msp::Time::TimeStamp &get_sleep_timeout() const { return sleep_timeout; }
245         protected:
246                 void sleep(const Msp::Time::TimeDelta &);
247         };
248
249         class CommandQueueTask: public Task
250         {
251         private:
252                 Queue<PendingCommand> queue;
253
254         public:
255                 CommandQueueTask();
256
257                 virtual bool get_work(PendingCommand &);
258
259                 void push(const PendingCommand &);
260                 unsigned size() const { return queue.size(); }
261                 bool empty() const { return queue.empty(); }
262         };
263
264         class RefreshTask: public Task
265         {
266         private:
267                 typedef std::list<Locomotive *> LocomotivePtrList;
268
269                 LocomotivePtrList cycle;
270                 LocomotivePtrList::iterator next;
271                 unsigned round;
272                 Locomotive *loco;
273                 unsigned phase;
274                 Msp::Mutex mutex;
275
276         public:
277                 RefreshTask();
278
279                 virtual bool get_work(PendingCommand &);
280
281                 void add_loco(Locomotive &);
282                 void remove_loco(Locomotive &);
283         private:
284                 Locomotive *get_next_loco();
285                 void advance();
286         };
287
288         class S88Task: public Task
289         {
290         private:
291                 ArduControl &control;
292                 unsigned n_octets;
293                 unsigned octets_remaining;
294                 Msp::Time::TimeStamp last_poll;
295                 Msp::Time::TimeDelta latency;
296
297         public:
298                 S88Task(ArduControl &);
299
300                 virtual bool get_work(PendingCommand &);
301                 virtual void process_reply(const char *, unsigned);
302
303                 void set_n_octets(unsigned);
304                 void grow_n_octets(unsigned);
305
306                 const Msp::Time::TimeDelta &get_latency() const { return latency; }
307         };
308
309         class MfxAnnounceTask: public Task
310         {
311         private:
312                 unsigned serial;
313
314         public:
315                 MfxAnnounceTask();
316
317                 virtual bool get_work(PendingCommand &);
318
319                 void set_serial(unsigned);
320                 unsigned get_serial() const { return serial; }
321         };
322
323         class MfxSearchTask: public Task
324         {
325         private:
326                 ArduControl &control;
327                 unsigned next_address;
328                 unsigned size;
329                 unsigned bits;
330                 unsigned misses;
331                 Queue<MfxInfo> queue;
332
333         public:
334                 MfxSearchTask(ArduControl &);
335
336                 virtual bool get_work(PendingCommand &);
337                 virtual void process_reply(const char *, unsigned);
338
339                 void set_next_address(unsigned);
340                 bool pop_info(MfxInfo &);
341         };
342
343         class MonitorTask: public Task
344         {
345         private:
346                 float voltage;
347                 float current;
348                 float base_level;
349                 float peak_level;
350                 unsigned next_type;
351
352         public:
353                 MonitorTask();
354
355                 virtual bool get_work(PendingCommand &);
356                 virtual void process_reply(const char *, unsigned);
357
358                 float get_voltage() const { return voltage; }
359                 float get_current() const { return current; }
360                 void reset_peak();
361                 float get_peak() const { return peak_level-base_level; }
362         };
363
364         class ControlThread: public Msp::Thread
365         {
366         private:
367                 ArduControl &control;
368                 bool done;
369                 std::vector<Task *> tasks;
370
371         public:
372                 ControlThread(ArduControl &);
373
374                 void exit();
375         private:
376                 virtual void main();
377                 void init_baud_rate();
378                 bool get_work(PendingCommand &);
379                 unsigned do_command(const PendingCommand &, const Msp::Time::TimeDelta &);
380                 unsigned process_reply(const char *, unsigned);
381                 void set_power(bool);
382         };
383
384         typedef std::map<unsigned, Locomotive> LocomotiveMap;
385         typedef std::vector<MfxInfo> MfxInfoArray;
386         typedef std::map<unsigned, Accessory> AccessoryMap;
387         typedef std::list<Accessory *> AccessoryPtrList;
388         typedef std::map<unsigned, Sensor> SensorMap;
389
390         Msp::IO::Serial serial;
391         unsigned debug;
392         Msp::FS::Path state_file;
393
394         ControlledVariable<bool> power;
395         bool halted;
396
397         LocomotiveMap locomotives;
398         MfxInfoArray mfx_info;
399         AccessoryMap accessories;
400         AccessoryPtrList accessory_queue;
401         Accessory *active_accessory;
402         unsigned char active_index;
403         Msp::Time::TimeStamp off_timeout;
404
405         SensorMap sensors;
406
407         Msp::Time::TimeDelta command_timeout;
408         CommandQueueTask command_queue;
409         Queue<Tag> completed_commands;
410         RefreshTask refresh;
411         S88Task s88;
412         MfxAnnounceTask mfx_announce;
413         MfxSearchTask mfx_search;
414         MonitorTask monitor;
415         ControlThread thread;
416
417         static ProtocolInfo protocol_info[2];
418         static TelemetryInfo telemetry_info[4];
419
420 public:
421         ArduControl(const Options &);
422         ~ArduControl();
423
424         virtual void set_power(bool);
425         virtual bool get_power() const { return power; }
426         virtual void halt(bool);
427         virtual bool is_halted() const { return halted; }
428
429         virtual const char *enumerate_protocols(unsigned) const;
430 private:
431         static Protocol map_protocol(const std::string &);
432 public:
433         virtual unsigned get_protocol_speed_steps(const std::string &) const;
434
435         virtual const DetectedLocomotive *enumerate_detected_locos(unsigned) const;
436         virtual unsigned add_loco(unsigned, const std::string &, const VehicleType &);
437 private:
438         MfxInfoArray::iterator add_mfx_info(const MfxInfo &);
439 public:
440         virtual void remove_loco(unsigned);
441         virtual void set_loco_speed(unsigned, unsigned);
442         virtual void set_loco_reverse(unsigned, bool);
443         virtual void set_loco_function(unsigned, unsigned, bool);
444
445         virtual unsigned add_turnout(unsigned, const TrackType &);
446         virtual void remove_turnout(unsigned);
447         virtual void set_turnout(unsigned, unsigned);
448         virtual unsigned get_turnout(unsigned) const;
449
450         virtual unsigned add_signal(unsigned, const SignalType &);
451         virtual void remove_signal(unsigned);
452         virtual void set_signal(unsigned, unsigned);
453         virtual unsigned get_signal(unsigned) const;
454
455 private:
456         unsigned add_accessory(Accessory::Kind, unsigned, unsigned, unsigned);
457         void remove_accessory(Accessory::Kind, unsigned);
458         void set_accessory(Accessory::Kind, unsigned, unsigned);
459         unsigned get_accessory(Accessory::Kind, unsigned) const;
460         void activate_accessory_by_mask(Accessory &, unsigned);
461
462 public:
463         virtual unsigned add_sensor(unsigned);
464         virtual void remove_sensor(unsigned);
465         virtual void set_sensor(unsigned, bool) { }
466         virtual bool get_sensor(unsigned) const;
467
468         virtual const TelemetryInfo *enumerate_telemetry(unsigned) const;
469         virtual float get_telemetry_value(const std::string &) const;
470
471         virtual void tick();
472         virtual void flush();
473 private:
474         void save_state() const;
475 };
476
477 } // namespace R2C2
478
479 #endif