]> git.tdb.fi Git - r2c2.git/blobdiff - source/libr2c2/arducontrol.h
Turn ArduControl command_queue into a Task
[r2c2.git] / source / libr2c2 / arducontrol.h
index cbdecad3a27513c70bb0e168b661d1bd6349a2e8..4373a84f707713e6b7d80c1e927875719b6cad0a 100644 (file)
@@ -3,6 +3,8 @@
 
 #include <msp/core/mutex.h>
 #include <msp/core/thread.h>
+#include <msp/datafile/objectloader.h>
+#include <msp/fs/path.h>
 #include <msp/io/serial.h>
 #include <msp/time/timedelta.h>
 #include <msp/time/timestamp.h>
@@ -12,11 +14,23 @@ namespace R2C2 {
 
 class ArduControl: public Driver
 {
+public:
+       class Loader: public Msp::DataFile::ObjectLoader<ArduControl>
+       {
+       public:
+               Loader(ArduControl &);
+
+       private:
+               void mfx_announce_serial(unsigned);
+               void mfx_locomotive(unsigned);
+       };
+
 private:
        enum Command
        {
                POWER_ON = 0x01,
                POWER_OFF = 0x02,
+               READ_POWER_STATE = 0x03,
                READ_TRACK_CURRENT = 0x08,
                SET_OVERCURRENT_LIMIT = 0x09,
                READ_INPUT_VOLTAGE = 0x0A,
@@ -25,7 +39,16 @@ private:
                MOTOROLA_SPEED_DIRECTION = 0x13,
                MOTOROLA_SPEED_FUNCTION = 0x14,
                MOTOROLA_SOLENOID = 0x15,
+               MFX_SET_STATION_ID = 0x21,
+               MFX_ANNOUNCE = 0x22,
+               MFX_SEARCH = 0x23,
+               MFX_ASSIGN_ADDRESS = 0x24,
+               MFX_PING = 0x25,
+               MFX_SPEED = 0x28,
+               MFX_SPEED_FUNCS8 = 0x29,
+               MFX_SPEED_FUNCS16 = 0x2A,
                S88_READ = 0x30,
+               SET_BAUD_RATE = 0x70,
                COMMAND_OK = 0x80,
                RECEIVE_OVERRUN = 0x81,
                FRAMING_ERROR = 0x82,
@@ -33,9 +56,13 @@ private:
                LENGTH_ERROR = 0x84,
                INVALID_VALUE = 0x85,
                OVERCURRENT = 0xA0,
+               BAUD_CHANGE_FAILED = 0xA1,
                TRACK_CURRENT = 0xC0,
                INPUT_VOLTAGE = 0xC1,
-               S88_DATA = 0xD0
+               POWER_STATE = 0xC2,
+               S88_DATA = 0xD0,
+               MFX_SEARCH_FEEDBACK = 0xD1,
+               MFX_PING_FEEDBACK = 0xD2
        };
 
        struct Tag
@@ -52,7 +79,7 @@ private:
                Type type;
                unsigned char command;
                unsigned short serial;
-               unsigned address;
+               unsigned id;
 
                Tag();
 
@@ -61,13 +88,21 @@ private:
 
        enum GeneralCommand
        {
-               POWER
+               POWER,
+               NEW_LOCO
        };
 
        enum Protocol
        {
-               NONE,
-               MM
+               MM,
+               MFX
+       };
+
+       struct ProtocolInfo
+       {
+               unsigned max_address;
+               unsigned max_speed;
+               unsigned max_func;
        };
 
        template<typename T>
@@ -82,6 +117,7 @@ private:
 
                bool set(T v) { if(v==pending) return false; pending = v; ++serial; return true; }
                bool commit(unsigned short s) { if(s!=serial) return false; current = pending; return true; }
+               void rollback() { pending = current; ++serial; }
 
                operator T() const { return current; }
        };
@@ -95,6 +131,7 @@ private:
                        FUNCTIONS
                };
 
+               unsigned id;
                Protocol proto;
                unsigned address;
                ControlledVariable<unsigned> speed;
@@ -108,6 +145,17 @@ private:
                unsigned create_speed_func_command(unsigned, char *) const;
        };
 
+       struct MfxInfo: public DetectedLocomotive
+       {
+               class Loader: public Msp::DataFile::ObjectLoader<MfxInfo>
+               {
+               public:
+                       Loader(MfxInfo &);
+               };
+
+               unsigned id;
+       };
+
        struct Accessory
        {
                enum Kind
@@ -125,11 +173,13 @@ private:
                Kind kind;
                unsigned address;
                unsigned bits;
+               unsigned valid_states;
                ControlledVariable<unsigned> state;
+               unsigned uncertain;
                unsigned target;
                Msp::Time::TimeDelta active_time;
 
-               Accessory(Kind, unsigned, unsigned);
+               Accessory(Kind, unsigned, unsigned, unsigned);
 
                unsigned create_state_command(unsigned, bool, char *) const;
        };
@@ -147,11 +197,161 @@ private:
                Sensor(unsigned);
        };
 
+       struct PendingCommand
+       {
+               Tag tag;
+               char command[15];
+               unsigned char length;
+               unsigned repeat_count;
+
+               PendingCommand();
+               PendingCommand(GeneralCommand);
+               PendingCommand(Locomotive &, Locomotive::Command, unsigned = 0);
+               PendingCommand(Accessory &, Accessory::Command, unsigned = 0);
+       };
+
+       template<typename T>
+       class Queue
+       {
+       private:
+               std::list<T> items;
+               Msp::Mutex mutex;
+
+       public:
+               void push(const T &);
+               bool pop(T &);
+               bool empty() const;
+       };
+
+       class Task
+       {
+       protected:
+               Task() { }
+       public:
+               virtual ~Task() { }
+
+               virtual bool get_work(PendingCommand &) = 0;
+               virtual void process_reply(const char *, unsigned) { }
+       };
+
+       class CommandQueueTask: public Task
+       {
+       private:
+               Queue<PendingCommand> queue;
+
+       public:
+               virtual bool get_work(PendingCommand &);
+
+               void push(const PendingCommand &);
+               bool empty() const { return queue.empty(); }
+       };
+
+       class RefreshTask: public Task
+       {
+       private:
+               typedef std::list<Locomotive *> LocomotivePtrList;
+
+               LocomotivePtrList cycle;
+               LocomotivePtrList::iterator next;
+               unsigned round;
+               Locomotive *loco;
+               unsigned phase;
+               Msp::Mutex mutex;
+
+       public:
+               RefreshTask();
+
+               virtual bool get_work(PendingCommand &);
+
+               void add_loco(Locomotive &);
+               void remove_loco(Locomotive &);
+       private:
+               Locomotive *get_next_loco();
+               void advance();
+       };
+
+       class S88Task: public Task
+       {
+       private:
+               ArduControl &control;
+               unsigned n_octets;
+               unsigned octets_remaining;
+               unsigned delay;
+
+       public:
+               S88Task(ArduControl &);
+
+               virtual bool get_work(PendingCommand &);
+               virtual void process_reply(const char *, unsigned);
+
+               void set_n_octets(unsigned);
+               void grow_n_octets(unsigned);
+       };
+
+       class MfxAnnounceTask: public Task
+       {
+       private:
+               unsigned serial;
+               Msp::Time::TimeStamp next;
+
+       public:
+               MfxAnnounceTask();
+
+               virtual bool get_work(PendingCommand &);
+
+               void set_serial(unsigned);
+               unsigned get_serial() const { return serial; }
+       };
+
+       class MfxSearchTask: public Task
+       {
+       private:
+               ArduControl &control;
+               unsigned next_address;
+               Msp::Time::TimeStamp next;
+               unsigned size;
+               unsigned bits;
+               unsigned misses;
+               Queue<MfxInfo> queue;
+
+       public:
+               MfxSearchTask(ArduControl &);
+
+               virtual bool get_work(PendingCommand &);
+               virtual void process_reply(const char *, unsigned);
+
+               void set_next_address(unsigned);
+               bool pop_info(MfxInfo &);
+       };
+
+       class MonitorTask: public Task
+       {
+       private:
+               float voltage;
+               float current;
+               float base_level;
+               float peak_level;
+               Msp::Time::TimeStamp next_poll;
+               unsigned next_type;
+
+       public:
+               MonitorTask();
+
+               virtual bool get_work(PendingCommand &);
+               virtual void process_reply(const char *, unsigned);
+
+               float get_voltage() const { return voltage; }
+               float get_current() const { return current; }
+               void reset_peak();
+               float get_peak() const { return peak_level-base_level; }
+       };
+
        class ControlThread: public Msp::Thread
        {
        private:
                ArduControl &control;
                bool done;
+               std::vector<Task *> tasks;
 
        public:
                ControlThread(ArduControl &);
@@ -159,56 +359,56 @@ private:
                void exit();
        private:
                virtual void main();
-       };
-
-       struct QueuedCommand
-       {
-               Tag tag;
-               char command[15];
-               unsigned char length;
-
-               QueuedCommand();
-               QueuedCommand(GeneralCommand);
-               QueuedCommand(Locomotive &, Locomotive::Command, unsigned = 0);
-               QueuedCommand(Accessory &, Accessory::Command, unsigned = 0);
+               void init_baud_rate();
+               bool get_work(PendingCommand &);
+               unsigned do_command(const PendingCommand &, const Msp::Time::TimeDelta &);
+               unsigned process_reply(const char *, unsigned);
+               void set_power(bool);
        };
 
        typedef std::map<unsigned, Locomotive> LocomotiveMap;
-       typedef std::list<Locomotive *> LocomotivePtrList;
+       typedef std::vector<MfxInfo> MfxInfoArray;
        typedef std::map<unsigned, Accessory> AccessoryMap;
        typedef std::list<Accessory *> AccessoryPtrList;
        typedef std::map<unsigned, Sensor> SensorMap;
 
        Msp::IO::Serial serial;
-       bool debug;
+       unsigned debug;
+       Msp::FS::Path state_file;
 
        ControlledVariable<bool> power;
+       bool halted;
 
        LocomotiveMap locomotives;
-       LocomotivePtrList refresh_cycle;
-       LocomotivePtrList::iterator next_refresh;
-       unsigned refresh_counter;
+       MfxInfoArray mfx_info;
        AccessoryMap accessories;
        AccessoryPtrList accessory_queue;
        Accessory *active_accessory;
+       unsigned char active_index;
        Msp::Time::TimeStamp off_timeout;
-       std::list<QueuedCommand> command_queue;
-       std::list<Tag> completed_commands;
 
        SensorMap sensors;
-       unsigned n_s88_octets;
 
-       Msp::Mutex mutex;
+       Msp::Time::TimeDelta command_timeout;
+       CommandQueueTask command_queue;
+       Queue<Tag> completed_commands;
+       RefreshTask refresh;
+       S88Task s88;
+       MfxAnnounceTask mfx_announce;
+       MfxSearchTask mfx_search;
+       MonitorTask monitor;
        ControlThread thread;
 
+       static ProtocolInfo protocol_info[2];
+
 public:
-       ArduControl(const std::string &);
+       ArduControl(const Options &);
        ~ArduControl();
 
        virtual void set_power(bool);
        virtual bool get_power() const { return power; }
        virtual void halt(bool);
-       virtual bool is_halted() const { return false; }
+       virtual bool is_halted() const { return halted; }
 
        virtual const char *enumerate_protocols(unsigned) const;
 private:
@@ -216,48 +416,43 @@ private:
 public:
        virtual unsigned get_protocol_speed_steps(const std::string &) const;
 
-       virtual void add_loco(unsigned, const std::string &, const VehicleType &);
+       virtual const DetectedLocomotive *enumerate_detected_locos(unsigned) const;
+       virtual unsigned add_loco(unsigned, const std::string &, const VehicleType &);
+private:
+       MfxInfoArray::iterator add_mfx_info(const MfxInfo &);
+public:
        virtual void remove_loco(unsigned);
        virtual void set_loco_speed(unsigned, unsigned);
        virtual void set_loco_reverse(unsigned, bool);
        virtual void set_loco_function(unsigned, unsigned, bool);
-private:
-       void add_loco_to_refresh(Locomotive &);
-       void remove_loco_from_refresh(Locomotive &);
-       Locomotive *get_loco_to_refresh();
-       void advance_next_refresh();
 
-public:
-       virtual void add_turnout(unsigned, const TrackType &);
+       virtual unsigned add_turnout(unsigned, const TrackType &);
        virtual void remove_turnout(unsigned);
        virtual void set_turnout(unsigned, unsigned);
        virtual unsigned get_turnout(unsigned) const;
 
-       virtual void add_signal(unsigned, const SignalType &);
+       virtual unsigned add_signal(unsigned, const SignalType &);
        virtual void remove_signal(unsigned);
        virtual void set_signal(unsigned, unsigned);
        virtual unsigned get_signal(unsigned) const;
 
 private:
-       void add_accessory(Accessory::Kind, unsigned, unsigned);
+       unsigned add_accessory(Accessory::Kind, unsigned, unsigned, unsigned);
        void remove_accessory(Accessory::Kind, unsigned);
        void set_accessory(Accessory::Kind, unsigned, unsigned);
        unsigned get_accessory(Accessory::Kind, unsigned) const;
+       void activate_accessory_by_mask(Accessory &, unsigned);
 
 public:
-       virtual void add_sensor(unsigned);
+       virtual unsigned add_sensor(unsigned);
        virtual void remove_sensor(unsigned);
        virtual void set_sensor(unsigned, bool) { }
        virtual bool get_sensor(unsigned) const;
 
        virtual void tick();
        virtual void flush();
-
 private:
-       void push_command(const QueuedCommand &);
-       bool pop_command(QueuedCommand &);
-       void push_completed_tag(const Tag &);
-       Tag pop_completed_tag();
+       void save_state() const;
 };
 
 } // namespace R2C2