]> git.tdb.fi Git - r2c2.git/blob - source/libr2c2/arducontrol.h
Add basic MFX support to arducontrol driver
[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         class ControlThread: public Msp::Thread
170         {
171         private:
172                 ArduControl &control;
173                 bool done;
174
175         public:
176                 ControlThread(ArduControl &);
177
178                 void exit();
179         private:
180                 virtual void main();
181         };
182
183         struct QueuedCommand
184         {
185                 Tag tag;
186                 char command[15];
187                 unsigned char length;
188
189                 QueuedCommand();
190                 QueuedCommand(GeneralCommand);
191                 QueuedCommand(Locomotive &, Locomotive::Command, unsigned = 0);
192                 QueuedCommand(Accessory &, Accessory::Command, unsigned = 0);
193         };
194
195         typedef std::map<unsigned, Locomotive> LocomotiveMap;
196         typedef std::list<Locomotive *> LocomotivePtrList;
197         typedef std::map<unsigned, Accessory> AccessoryMap;
198         typedef std::list<Accessory *> AccessoryPtrList;
199         typedef std::map<unsigned, Sensor> SensorMap;
200
201         Msp::IO::Serial serial;
202         unsigned debug;
203
204         ControlledVariable<bool> power;
205
206         LocomotiveMap locomotives;
207         LocomotivePtrList refresh_cycle;
208         LocomotivePtrList::iterator next_refresh;
209         unsigned refresh_counter;
210         AccessoryMap accessories;
211         AccessoryPtrList accessory_queue;
212         Accessory *active_accessory;
213         Msp::Time::TimeStamp off_timeout;
214         std::list<QueuedCommand> command_queue;
215         std::list<Tag> completed_commands;
216
217         SensorMap sensors;
218         unsigned n_s88_octets;
219
220         unsigned mfx_announce_serial;
221         unsigned next_mfx_address;
222
223         Msp::Mutex mutex;
224         ControlThread thread;
225
226         static ProtocolInfo protocol_info[2];
227
228 public:
229         ArduControl(const std::string &);
230         ~ArduControl();
231
232         virtual void set_power(bool);
233         virtual bool get_power() const { return power; }
234         virtual void halt(bool);
235         virtual bool is_halted() const { return false; }
236
237         virtual const char *enumerate_protocols(unsigned) const;
238 private:
239         static Protocol map_protocol(const std::string &);
240 public:
241         virtual unsigned get_protocol_speed_steps(const std::string &) const;
242
243         virtual unsigned add_loco(unsigned, const std::string &, const VehicleType &);
244         virtual void remove_loco(unsigned);
245         virtual void set_loco_speed(unsigned, unsigned);
246         virtual void set_loco_reverse(unsigned, bool);
247         virtual void set_loco_function(unsigned, unsigned, bool);
248 private:
249         void add_loco_to_refresh(Locomotive &);
250         void remove_loco_from_refresh(Locomotive &);
251         Locomotive *get_loco_to_refresh();
252         void advance_next_refresh();
253
254 public:
255         virtual unsigned add_turnout(unsigned, const TrackType &);
256         virtual void remove_turnout(unsigned);
257         virtual void set_turnout(unsigned, unsigned);
258         virtual unsigned get_turnout(unsigned) const;
259
260         virtual unsigned add_signal(unsigned, const SignalType &);
261         virtual void remove_signal(unsigned);
262         virtual void set_signal(unsigned, unsigned);
263         virtual unsigned get_signal(unsigned) const;
264
265 private:
266         unsigned add_accessory(Accessory::Kind, unsigned, unsigned);
267         void remove_accessory(Accessory::Kind, unsigned);
268         void set_accessory(Accessory::Kind, unsigned, unsigned);
269         unsigned get_accessory(Accessory::Kind, unsigned) const;
270
271 public:
272         virtual unsigned add_sensor(unsigned);
273         virtual void remove_sensor(unsigned);
274         virtual void set_sensor(unsigned, bool) { }
275         virtual bool get_sensor(unsigned) const;
276
277         virtual void tick();
278         virtual void flush();
279
280 private:
281         void push_command(const QueuedCommand &);
282         bool pop_command(QueuedCommand &);
283         void push_completed_tag(const Tag &);
284         Tag pop_completed_tag();
285 };
286
287 } // namespace R2C2
288
289 #endif