]> git.tdb.fi Git - r2c2.git/blobdiff - source/libr2c2/intellibox.h
Rename the project to R²C²
[r2c2.git] / source / libr2c2 / intellibox.h
diff --git a/source/libr2c2/intellibox.h b/source/libr2c2/intellibox.h
new file mode 100644 (file)
index 0000000..8655bfc
--- /dev/null
@@ -0,0 +1,170 @@
+/* $Id$
+
+This file is part of R²C²
+Copyright © 2010  Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#ifndef LIBR2C2_INTELLIBOX_H_
+#define LIBR2C2_INTELLIBOX_H_
+
+#include <map>
+#include <msp/time/timestamp.h>
+#include "driver.h"
+
+namespace R2C2 {
+
+/**
+Driver for Uhlenbrock Intellibox.  Uses the P50X binary protocol over RS232.
+
+Motorola decoders with 27 speed steps are supported by manually generating the
+commands necessary to reach the "half-steps".  However, sending a rapid stream
+of speed changes to the same locomotive seems to cause excessive lag, so we
+cheat a bit; instead of sending the half-step command immediately, we send it
+with a 500ms delay, but only if no new set_loco_speed calls have occurred.  As
+a downside from this accelerations and decelerations are still jerky.
+*/
+class Intellibox: public Driver
+{
+private:
+       enum Command
+       {
+               CMD_LOK=0x80,
+               CMD_LOK_STATUS=0x84,
+               CMD_LOK_CONFIG=0x85,
+               CMD_FUNC=0x88,
+               CMD_FUNC_STATUS=0x8C,
+               CMD_TURNOUT=0x90,
+               CMD_TURNOUT_FREE=0x93,
+               CMD_TURNOUT_STATUS=0x94,
+               CMD_TURNOUT_GROUP_STATUS=0x95,
+               CMD_SENSOR_STATUS=0x98,
+               CMD_SENSOR_REPORT=0x99,
+               CMD_SENSOR_PARAM_SET=0x9D,
+               CMD_STATUS=0xA2,
+               CMD_POWER_OFF=0xA6,
+               CMD_POWER_ON=0xA7,
+               CMD_NOP=0xC4,
+               CMD_EVENT=0xC8,
+               CMD_EVENT_LOK=0xC9,
+               CMD_EVENT_TURNOUT=0xCA,
+               CMD_EVENT_SENSOR=0xCB
+       };
+
+       enum Error
+       {
+               ERR_NO_ERROR=0,
+               ERR_SYS_ERROR,
+               ERR_BAD_PARAM,
+               ERR_POWER_OFF=0x6,
+               ERR_NO_LOK_SPACE=0x8,  // No space in lok command buffer
+               ERR_NO_TURNOUT_SPACE,  // No space in turnout command buffer
+               ERR_NO_DATA,           // "no Lok status available (Lok is not in a slot)"
+               ERR_NO_SLOT,           // "there is no slot available"
+               ERR_BAD_LOK_ADDR,
+               ERR_LOK_BUSY,
+               ERR_BAD_TURNOUT_ADDR,
+               ERR_BAD_SO_VALUE,
+               ERR_NO_I2C_SPACE,
+               ERR_LOW_TURNOUT_SPACE=0x40,
+               ERR_LOK_HALTED,
+               ERR_LOK_POWER_OFF,
+       };
+
+       enum Protocol
+       {
+               MM,
+               MM_27
+       };
+
+       struct Locomotive
+       {
+               Protocol protocol;
+               unsigned speed;
+               bool reverse;
+               unsigned funcs;
+               int pending_half_step;
+               Msp::Time::TimeStamp half_step_delay;
+
+               Locomotive();
+       };
+
+       struct Turnout
+       {
+               bool state;
+               bool active;
+               bool pending;
+               Msp::Time::TimeStamp off_timeout;
+
+               Turnout();
+       };
+
+       struct Sensor
+       {
+               bool state;
+               Msp::Time::TimeStamp off_timeout;
+
+               Sensor();
+       };
+
+       struct CommandSlot
+       {
+               Command cmd;
+               unsigned addr;
+               unsigned char data[8];
+               unsigned length;
+       };
+
+       int serial_fd;
+       bool power;
+       bool halted;
+       std::map<unsigned, Locomotive> locos;
+       std::map<unsigned, Turnout> turnouts;
+       std::map<unsigned, Sensor> sensors;
+       bool update_sensors;
+       std::list<CommandSlot> queue;
+       bool command_sent;
+       Msp::Time::TimeStamp next_event_query;
+
+public:
+       Intellibox(const std::string &);
+
+       virtual void set_power(bool);
+       virtual bool get_power() const { return power; }
+       virtual void halt(bool);
+       virtual bool is_halted() const { return halted; }
+
+       virtual const char *enumerate_protocols(unsigned) const;
+       virtual unsigned get_protocol_speed_steps(const std::string &) const;
+       virtual void add_loco(unsigned, const std::string &);
+       virtual void set_loco_speed(unsigned, unsigned);
+       virtual void set_loco_reverse(unsigned, bool);
+       virtual void set_loco_function(unsigned, unsigned, bool);
+
+       virtual void add_turnout(unsigned);
+       virtual void set_turnout(unsigned, bool);
+       virtual bool get_turnout(unsigned) const;
+
+       virtual void add_sensor(unsigned);
+       virtual void set_sensor(unsigned, bool) { }
+       virtual bool get_sensor(unsigned) const;
+
+       virtual void tick();
+       virtual void flush();
+
+private:
+       Protocol map_protocol(const std::string &) const;
+       void command(Command);
+       void command(Command, const unsigned char *, unsigned);
+       void command(Command, unsigned, const unsigned char *, unsigned);
+       void loco_command(unsigned, unsigned, bool, unsigned);
+       void turnout_command(unsigned, bool, bool);
+       void process_reply(const Msp::Time::TimeStamp &);
+       unsigned read_all(unsigned char *, unsigned);
+       unsigned read_status(Error *);
+       void error(Command, Error);
+};
+
+} // namespace R2C2
+
+#endif