]> git.tdb.fi Git - r2c2.git/blob - source/libr2c2/intellibox.h
efdf3b2edd633b72fe54a1f0471b75d45269bef4
[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         struct Turnout
89         {
90                 unsigned bits;
91                 unsigned state;
92                 bool active;
93                 bool synced;
94                 unsigned pending;
95                 Msp::Time::TimeStamp off_timeout;
96
97                 Turnout();
98         };
99
100         struct Sensor
101         {
102                 bool state;
103                 Msp::Time::TimeStamp off_timeout;
104
105                 Sensor();
106         };
107
108         struct CommandSlot
109         {
110                 Command cmd;
111                 unsigned addr;
112                 unsigned char data[8];
113                 unsigned length;
114         };
115
116         Msp::IO::Serial serial;
117         bool power;
118         bool halted;
119         std::map<unsigned, Locomotive> locos;
120         std::map<unsigned, Turnout> turnouts;
121         std::map<unsigned, Sensor> sensors;
122         bool update_sensors;
123         std::list<CommandSlot> queue;
124         bool command_sent;
125         Msp::Time::TimeStamp next_event_query;
126
127 public:
128         Intellibox(const std::string &);
129
130         virtual void set_power(bool);
131         virtual bool get_power() const { return power; }
132         virtual void halt(bool);
133         virtual bool is_halted() const { return halted; }
134
135         virtual const char *enumerate_protocols(unsigned) const;
136         virtual unsigned get_protocol_speed_steps(const std::string &) const;
137         virtual void add_loco(unsigned, const std::string &, const VehicleType &);
138         virtual void set_loco_speed(unsigned, unsigned);
139         virtual void set_loco_reverse(unsigned, bool);
140         virtual void set_loco_function(unsigned, unsigned, bool);
141
142         virtual void add_turnout(unsigned, const TrackType &);
143         virtual void set_turnout(unsigned, unsigned);
144         virtual unsigned get_turnout(unsigned) const;
145
146         virtual void add_sensor(unsigned);
147         virtual void set_sensor(unsigned, bool) { }
148         virtual bool get_sensor(unsigned) const;
149
150         virtual void tick();
151         virtual void flush();
152
153 private:
154         Protocol map_protocol(const std::string &) const;
155         void command(Command);
156         void command(Command, const unsigned char *, unsigned);
157         void command(Command, unsigned, const unsigned char *, unsigned);
158         void loco_command(unsigned, unsigned, bool, unsigned, bool);
159         void turnout_command(unsigned, bool, bool);
160         void process_reply(const Msp::Time::TimeStamp &);
161         unsigned read_all(unsigned char *, unsigned);
162         unsigned read_status(Error *);
163         void error(Command, Error);
164 };
165
166 } // namespace R2C2
167
168 #endif