+ 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::deque<T> items;
+ Msp::Mutex mutex;
+
+ public:
+ void push(const T &);
+ bool pop(T &);
+ unsigned size() const;
+ bool empty() const;
+ };
+
+ class Task
+ {
+ protected:
+ std::string name;
+ unsigned priority;
+ Msp::Time::TimeStamp sleep_timeout;
+
+ Task(const std::string &, unsigned = 0);
+ public:
+ virtual ~Task() { }
+
+ const std::string &get_name() const { return name; }
+
+ virtual bool get_work(PendingCommand &) = 0;
+ virtual void process_reply(const char *, unsigned) { }
+
+ unsigned get_priority() const { return priority; }
+ const Msp::Time::TimeStamp &get_sleep_timeout() const { return sleep_timeout; }
+ protected:
+ void sleep(const Msp::Time::TimeDelta &);
+ };
+
+ class CommandQueueTask: public Task
+ {
+ private:
+ Queue<PendingCommand> queue;
+
+ public:
+ CommandQueueTask();
+
+ virtual bool get_work(PendingCommand &);
+
+ void push(const PendingCommand &);
+ unsigned size() const { return queue.size(); }
+ 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;
+ Msp::Time::TimeStamp last_poll;
+ Msp::Time::TimeDelta latency;
+
+ 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);
+
+ const Msp::Time::TimeDelta &get_latency() const { return latency; }
+ };
+
+ class MfxAnnounceTask: public Task
+ {
+ private:
+ unsigned serial;
+
+ 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;
+ unsigned size;
+ unsigned bits;
+ unsigned misses;
+ Queue<MfxInfo> queue;
+
+ MfxInfo *pending_info;
+ unsigned read_array;
+ unsigned read_offset;
+ unsigned read_length;
+ char read_data[0x40];
+ unsigned block_size;
+
+ 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;
+ 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; }
+ };
+