]> git.tdb.fi Git - r2c2.git/blob - source/libr2c2/arducontrol.h
Refer to things in the driver with abstract ids instead of addresses
[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_TRACK_CURRENT = 0x08,
21                 SET_OVERCURRENT_LIMIT = 0x09,
22                 READ_INPUT_VOLTAGE = 0x0A,
23                 MOTOROLA_SPEED = 0x11,
24                 MOTOROLA_REVERSE = 0x12,
25                 MOTOROLA_SPEED_DIRECTION = 0x13,
26                 MOTOROLA_SPEED_FUNCTION = 0x14,
27                 MOTOROLA_SOLENOID = 0x15,
28                 S88_READ = 0x30,
29                 COMMAND_OK = 0x80,
30                 RECEIVE_OVERRUN = 0x81,
31                 FRAMING_ERROR = 0x82,
32                 INVALID_COMMAND = 0x83,
33                 LENGTH_ERROR = 0x84,
34                 INVALID_VALUE = 0x85,
35                 OVERCURRENT = 0xA0,
36                 TRACK_CURRENT = 0xC0,
37                 INPUT_VOLTAGE = 0xC1,
38                 S88_DATA = 0xD0
39         };
40
41         struct Tag
42         {
43                 enum Type
44                 {
45                         NONE,
46                         GENERAL,
47                         LOCOMOTIVE,
48                         ACCESSORY,
49                         SENSOR
50                 };
51
52                 Type type;
53                 unsigned char command;
54                 unsigned short serial;
55                 unsigned id;
56
57                 Tag();
58
59                 operator bool() const { return type!=NONE; }
60         };
61
62         enum GeneralCommand
63         {
64                 POWER
65         };
66
67         enum Protocol
68         {
69                 NONE,
70                 MM
71         };
72
73         template<typename T>
74         struct ControlledVariable
75         {
76                 T current;
77                 T pending;
78                 unsigned short serial;
79
80                 ControlledVariable(): current(), pending(), serial(0) { }
81                 ControlledVariable(T v): current(v), pending(v), serial(0) { }
82
83                 bool set(T v) { if(v==pending) return false; pending = v; ++serial; return true; }
84                 bool commit(unsigned short s) { if(s!=serial) return false; current = pending; return true; }
85
86                 operator T() const { return current; }
87         };
88
89         struct Locomotive
90         {
91                 enum Command
92                 {
93                         SPEED,
94                         REVERSE,
95                         FUNCTIONS
96                 };
97
98                 unsigned id;
99                 Protocol proto;
100                 unsigned address;
101                 ControlledVariable<unsigned> speed;
102                 ControlledVariable<bool> reverse;
103                 ControlledVariable<unsigned> funcs;
104                 unsigned last_change_age;
105
106                 Locomotive(Protocol, unsigned);
107
108                 unsigned create_speed_dir_command(char *) const;
109                 unsigned create_speed_func_command(unsigned, char *) const;
110         };
111
112         struct Accessory
113         {
114                 enum Kind
115                 {
116                         TURNOUT,
117                         SIGNAL
118                 };
119
120                 enum Command
121                 {
122                         ACTIVATE,
123                         DEACTIVATE
124                 };
125
126                 Kind kind;
127                 unsigned address;
128                 unsigned bits;
129                 ControlledVariable<unsigned> state;
130                 unsigned target;
131                 Msp::Time::TimeDelta active_time;
132
133                 Accessory(Kind, unsigned, unsigned);
134
135                 unsigned create_state_command(unsigned, bool, char *) const;
136         };
137
138         struct Sensor
139         {
140                 enum Command
141                 {
142                         STATE
143                 };
144
145                 unsigned address;
146                 ControlledVariable<bool> state;
147
148                 Sensor(unsigned);
149         };
150
151         class ControlThread: public Msp::Thread
152         {
153         private:
154                 ArduControl &control;
155                 bool done;
156
157         public:
158                 ControlThread(ArduControl &);
159
160                 void exit();
161         private:
162                 virtual void main();
163         };
164
165         struct QueuedCommand
166         {
167                 Tag tag;
168                 char command[15];
169                 unsigned char length;
170
171                 QueuedCommand();
172                 QueuedCommand(GeneralCommand);
173                 QueuedCommand(Locomotive &, Locomotive::Command, unsigned = 0);
174                 QueuedCommand(Accessory &, Accessory::Command, unsigned = 0);
175         };
176
177         typedef std::map<unsigned, Locomotive> LocomotiveMap;
178         typedef std::list<Locomotive *> LocomotivePtrList;
179         typedef std::map<unsigned, Accessory> AccessoryMap;
180         typedef std::list<Accessory *> AccessoryPtrList;
181         typedef std::map<unsigned, Sensor> SensorMap;
182
183         Msp::IO::Serial serial;
184         bool debug;
185
186         ControlledVariable<bool> power;
187
188         LocomotiveMap locomotives;
189         LocomotivePtrList refresh_cycle;
190         LocomotivePtrList::iterator next_refresh;
191         unsigned refresh_counter;
192         AccessoryMap accessories;
193         AccessoryPtrList accessory_queue;
194         Accessory *active_accessory;
195         Msp::Time::TimeStamp off_timeout;
196         std::list<QueuedCommand> command_queue;
197         std::list<Tag> completed_commands;
198
199         SensorMap sensors;
200         unsigned n_s88_octets;
201
202         Msp::Mutex mutex;
203         ControlThread thread;
204
205 public:
206         ArduControl(const std::string &);
207         ~ArduControl();
208
209         virtual void set_power(bool);
210         virtual bool get_power() const { return power; }
211         virtual void halt(bool);
212         virtual bool is_halted() const { return false; }
213
214         virtual const char *enumerate_protocols(unsigned) const;
215 private:
216         static Protocol map_protocol(const std::string &);
217 public:
218         virtual unsigned get_protocol_speed_steps(const std::string &) const;
219
220         virtual unsigned add_loco(unsigned, const std::string &, const VehicleType &);
221         virtual void remove_loco(unsigned);
222         virtual void set_loco_speed(unsigned, unsigned);
223         virtual void set_loco_reverse(unsigned, bool);
224         virtual void set_loco_function(unsigned, unsigned, bool);
225 private:
226         void add_loco_to_refresh(Locomotive &);
227         void remove_loco_from_refresh(Locomotive &);
228         Locomotive *get_loco_to_refresh();
229         void advance_next_refresh();
230
231 public:
232         virtual unsigned add_turnout(unsigned, const TrackType &);
233         virtual void remove_turnout(unsigned);
234         virtual void set_turnout(unsigned, unsigned);
235         virtual unsigned get_turnout(unsigned) const;
236
237         virtual unsigned add_signal(unsigned, const SignalType &);
238         virtual void remove_signal(unsigned);
239         virtual void set_signal(unsigned, unsigned);
240         virtual unsigned get_signal(unsigned) const;
241
242 private:
243         unsigned add_accessory(Accessory::Kind, unsigned, unsigned);
244         void remove_accessory(Accessory::Kind, unsigned);
245         void set_accessory(Accessory::Kind, unsigned, unsigned);
246         unsigned get_accessory(Accessory::Kind, unsigned) const;
247
248 public:
249         virtual unsigned add_sensor(unsigned);
250         virtual void remove_sensor(unsigned);
251         virtual void set_sensor(unsigned, bool) { }
252         virtual bool get_sensor(unsigned) const;
253
254         virtual void tick();
255         virtual void flush();
256
257 private:
258         void push_command(const QueuedCommand &);
259         bool pop_command(QueuedCommand &);
260         void push_completed_tag(const Tag &);
261         Tag pop_completed_tag();
262 };
263
264 } // namespace R2C2
265
266 #endif