]> git.tdb.fi Git - r2c2.git/blob - source/libr2c2/intellibox.h
Rename the project to R²C²
[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                 MM,
77                 MM_27
78         };
79
80         struct Locomotive
81         {
82                 Protocol protocol;
83                 unsigned speed;
84                 bool reverse;
85                 unsigned funcs;
86                 int pending_half_step;
87                 Msp::Time::TimeStamp half_step_delay;
88
89                 Locomotive();
90         };
91
92         struct Turnout
93         {
94                 bool state;
95                 bool active;
96                 bool pending;
97                 Msp::Time::TimeStamp off_timeout;
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         int serial_fd;
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 std::string &);
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 void add_loco(unsigned, const std::string &);
140         virtual void set_loco_speed(unsigned, unsigned);
141         virtual void set_loco_reverse(unsigned, bool);
142         virtual void set_loco_function(unsigned, unsigned, bool);
143
144         virtual void add_turnout(unsigned);
145         virtual void set_turnout(unsigned, bool);
146         virtual bool get_turnout(unsigned) const;
147
148         virtual void add_sensor(unsigned);
149         virtual void set_sensor(unsigned, bool) { }
150         virtual bool get_sensor(unsigned) const;
151
152         virtual void tick();
153         virtual void flush();
154
155 private:
156         Protocol map_protocol(const std::string &) const;
157         void command(Command);
158         void command(Command, const unsigned char *, unsigned);
159         void command(Command, unsigned, const unsigned char *, unsigned);
160         void loco_command(unsigned, unsigned, bool, unsigned);
161         void turnout_command(unsigned, bool, bool);
162         void process_reply(const Msp::Time::TimeStamp &);
163         unsigned read_all(unsigned char *, unsigned);
164         unsigned read_status(Error *);
165         void error(Command, Error);
166 };
167
168 } // namespace R2C2
169
170 #endif