#ifndef LIBR2C2_ARDUCONTROL_H_
#define LIBR2C2_ARDUCONTROL_H_
+#include <deque>
#include <msp/core/mutex.h>
#include <msp/core/thread.h>
#include <msp/datafile/objectloader.h>
MFX_SEARCH = 0x23,
MFX_ASSIGN_ADDRESS = 0x24,
MFX_PING = 0x25,
+ MFX_READ = 0x26,
MFX_SPEED = 0x28,
MFX_SPEED_FUNCS8 = 0x29,
MFX_SPEED_FUNCS16 = 0x2A,
POWER_STATE = 0xC2,
S88_DATA = 0xD0,
MFX_SEARCH_FEEDBACK = 0xD1,
- MFX_PING_FEEDBACK = 0xD2
+ MFX_PING_FEEDBACK = 0xD2,
+ MFX_READ_FEEDBACK = 0xD3
};
struct Tag
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;
};
class Queue
{
private:
- std::list<T> items;
+ std::deque<T> items;
Msp::Mutex mutex;
public:
void push(const T &);
bool pop(T &);
+ unsigned size() const;
+ bool empty() const;
};
class Task
{
protected:
- Task() { }
+ 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
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
ArduControl &control;
unsigned n_octets;
unsigned octets_remaining;
- unsigned delay;
+ Msp::Time::TimeStamp last_poll;
+ Msp::Time::TimeDelta latency;
public:
S88Task(ArduControl &);
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;
- Msp::Time::TimeStamp next;
public:
MfxAnnounceTask();
private:
ArduControl &control;
unsigned next_address;
- Msp::Time::TimeStamp next;
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 &);
float current;
float base_level;
float peak_level;
- Msp::Time::TimeStamp next_poll;
unsigned next_type;
public:
ArduControl &control;
bool done;
std::vector<Task *> tasks;
+ unsigned cmd_rate;
+ unsigned cmd_count;
+ Msp::Time::TimeStamp cmd_rate_start;
public:
ControlThread(ArduControl &);
+ unsigned get_command_rate() const { return cmd_rate; }
+
void exit();
private:
virtual void main();
void init_baud_rate();
bool get_work(PendingCommand &);
- unsigned do_command(const 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;
Msp::FS::Path state_file;
ControlledVariable<bool> power;
+ bool halted;
LocomotiveMap locomotives;
MfxInfoArray mfx_info;
SensorMap sensors;
- Msp::Mutex mutex;
- Queue<PendingCommand> command_queue;
+ Msp::Time::TimeDelta command_timeout;
+ CommandQueueTask command_queue;
Queue<Tag> completed_commands;
RefreshTask refresh;
S88Task s88;
ControlThread thread;
static ProtocolInfo protocol_info[2];
+ static TelemetryInfo telemetry_info[6];
public:
ArduControl(const Options &);
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:
virtual unsigned add_loco(unsigned, const std::string &, const VehicleType &);
private:
MfxInfoArray::iterator add_mfx_info(const MfxInfo &);
+ MfxInfo *find_mfx_info(unsigned);
public:
virtual void remove_loco(unsigned);
virtual void set_loco_speed(unsigned, unsigned);
virtual unsigned get_signal(unsigned) const;
private:
- unsigned 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 unsigned add_sensor(unsigned);
virtual void set_sensor(unsigned, bool) { }
virtual bool get_sensor(unsigned) const;
+ virtual const TelemetryInfo *enumerate_telemetry(unsigned) const;
+ virtual float get_telemetry_value(const std::string &) const;
+
virtual void tick();
virtual void flush();
private: