X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Flibr2c2%2Fintellibox.h;fp=source%2Flibr2c2%2Fintellibox.h;h=8655bfc8ddc9509a472c0c091a6122ef02034004;hb=1ff06c5bc46a677fa389ef86c6b26664368f1653;hp=0000000000000000000000000000000000000000;hpb=9b05c573a38639827697fe393d55b7c76f5bde45;p=r2c2.git diff --git a/source/libr2c2/intellibox.h b/source/libr2c2/intellibox.h new file mode 100644 index 0000000..8655bfc --- /dev/null +++ b/source/libr2c2/intellibox.h @@ -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 +#include +#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 locos; + std::map turnouts; + std::map sensors; + bool update_sensors; + std::list 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