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