]> git.tdb.fi Git - r2c2.git/blob - source/libr2c2/intellibox.h
Add telemetry framework for drivers
[r2c2.git] / source / libr2c2 / intellibox.h
1 #ifndef LIBR2C2_INTELLIBOX_H_
2 #define LIBR2C2_INTELLIBOX_H_
3
4 #include <map>
5 #include <msp/io/serial.h>
6 #include <msp/time/timestamp.h>
7 #include "driver.h"
8
9 namespace R2C2 {
10
11 /**
12 Driver for Uhlenbrock Intellibox.  Uses the P50X binary protocol over RS232.
13
14 Motorola decoders with 27 speed steps are supported by manually generating the
15 commands necessary to reach the "half-steps".  However, sending a rapid stream
16 of speed changes to the same locomotive seems to cause excessive lag, so we
17 cheat a bit; instead of sending the half-step command immediately, we send it
18 with a 500ms delay, but only if no new set_loco_speed calls have occurred.  As
19 a downside from this accelerations and decelerations are still jerky.
20 */
21 class Intellibox: public Driver
22 {
23 private:
24         enum Command
25         {
26                 CMD_LOK=0x80,
27                 CMD_LOK_STATUS=0x84,
28                 CMD_LOK_CONFIG=0x85,
29                 CMD_FUNC=0x88,
30                 CMD_FUNC_STATUS=0x8C,
31                 CMD_TURNOUT=0x90,
32                 CMD_TURNOUT_FREE=0x93,
33                 CMD_TURNOUT_STATUS=0x94,
34                 CMD_TURNOUT_GROUP_STATUS=0x95,
35                 CMD_SENSOR_STATUS=0x98,
36                 CMD_SENSOR_REPORT=0x99,
37                 CMD_SENSOR_PARAM_SET=0x9D,
38                 CMD_STATUS=0xA2,
39                 CMD_POWER_OFF=0xA6,
40                 CMD_POWER_ON=0xA7,
41                 CMD_NOP=0xC4,
42                 CMD_EVENT=0xC8,
43                 CMD_EVENT_LOK=0xC9,
44                 CMD_EVENT_TURNOUT=0xCA,
45                 CMD_EVENT_SENSOR=0xCB
46         };
47
48         enum Error
49         {
50                 ERR_NO_ERROR=0,
51                 ERR_SYS_ERROR,
52                 ERR_BAD_PARAM,
53                 ERR_POWER_OFF=0x6,
54                 ERR_NO_LOK_SPACE=0x8,  // No space in lok command buffer
55                 ERR_NO_TURNOUT_SPACE,  // No space in turnout command buffer
56                 ERR_NO_DATA,           // "no Lok status available (Lok is not in a slot)"
57                 ERR_NO_SLOT,           // "there is no slot available"
58                 ERR_BAD_LOK_ADDR,
59                 ERR_LOK_BUSY,
60                 ERR_BAD_TURNOUT_ADDR,
61                 ERR_BAD_SO_VALUE,
62                 ERR_NO_I2C_SPACE,
63                 ERR_LOW_TURNOUT_SPACE=0x40,
64                 ERR_LOK_HALTED,
65                 ERR_LOK_POWER_OFF
66         };
67
68         enum Protocol
69         {
70                 NONE,
71                 MM,
72                 MM_27
73         };
74
75         struct Locomotive
76         {
77                 Protocol protocol;
78                 bool ext_func;
79                 unsigned speed;
80                 bool reverse;
81                 unsigned funcs;
82                 int pending_half_step;
83                 Msp::Time::TimeStamp half_step_delay;
84
85                 Locomotive();
86         };
87
88         // These are used for signals as well, but Intellibox calls them turnouts.
89         struct Turnout
90         {
91                 unsigned bits;
92                 unsigned state;
93                 bool active;
94                 bool synced;
95                 unsigned pending;
96                 Msp::Time::TimeStamp off_timeout;
97                 bool signal;
98
99                 Turnout();
100         };
101
102         struct Sensor
103         {
104                 bool state;
105                 Msp::Time::TimeStamp off_timeout;
106
107                 Sensor();
108         };
109
110         struct CommandSlot
111         {
112                 Command cmd;
113                 unsigned addr;
114                 unsigned char data[8];
115                 unsigned length;
116         };
117
118         Msp::IO::Serial serial;
119         bool power;
120         bool halted;
121         std::map<unsigned, Locomotive> locos;
122         std::map<unsigned, Turnout> turnouts;
123         std::map<unsigned, Sensor> sensors;
124         bool update_sensors;
125         std::list<CommandSlot> queue;
126         bool command_sent;
127         Msp::Time::TimeStamp next_event_query;
128
129 public:
130         Intellibox(const Options &);
131
132         virtual void set_power(bool);
133         virtual bool get_power() const { return power; }
134         virtual void halt(bool);
135         virtual bool is_halted() const { return halted; }
136
137         virtual const char *enumerate_protocols(unsigned) const;
138         virtual unsigned get_protocol_speed_steps(const std::string &) const;
139         virtual DetectedLocomotive *enumerate_detected_locos(unsigned) const { return 0; }
140         virtual unsigned add_loco(unsigned, const std::string &, const VehicleType &);
141         virtual void remove_loco(unsigned);
142         virtual void set_loco_speed(unsigned, unsigned);
143         virtual void set_loco_reverse(unsigned, bool);
144         virtual void set_loco_function(unsigned, unsigned, bool);
145
146         virtual unsigned add_turnout(unsigned, const TrackType &);
147         virtual void remove_turnout(unsigned);
148 private:
149         unsigned add_turnout(unsigned, unsigned, bool);
150         void turnout_state_changed(unsigned, const Turnout &) const;
151 public:
152         virtual void set_turnout(unsigned, unsigned);
153         virtual unsigned get_turnout(unsigned) const;
154
155         virtual unsigned add_signal(unsigned, const SignalType &);
156         virtual void remove_signal(unsigned);
157         virtual void set_signal(unsigned, unsigned);
158         virtual unsigned get_signal(unsigned) const;
159
160 public:
161         virtual unsigned add_sensor(unsigned);
162         virtual void remove_sensor(unsigned);
163         virtual void set_sensor(unsigned, bool) { }
164         virtual bool get_sensor(unsigned) const;
165
166         virtual const TelemetryInfo *enumerate_telemetry(unsigned) const { return 0; }
167         virtual float get_telemetry_value(const std::string &) const;
168
169         virtual void tick();
170         virtual void flush();
171
172 private:
173         Protocol map_protocol(const std::string &) const;
174         void command(Command);
175         void command(Command, const unsigned char *, unsigned);
176         void command(Command, unsigned, const unsigned char *, unsigned);
177         void loco_command(unsigned, unsigned, bool, unsigned, bool);
178         void turnout_command(unsigned, bool, bool);
179         void process_reply(const Msp::Time::TimeStamp &);
180         unsigned read_all(unsigned char *, unsigned);
181         unsigned read_status(Error *);
182         void error(Command, Error);
183 };
184
185 } // namespace R2C2
186
187 #endif