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