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