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