The new scheduler can handle multiple tasks with the same priority, so
other things won't get blocked by the priority command queue for too
long. It also handles sleeping at the scheduler rather than individual
tasks.
+ArduControl::Task::Task(const string &n, unsigned p):
+ name(n),
+ priority(p)
+{ }
+
+void ArduControl::Task::sleep(const Time::TimeDelta &dt)
+{
+ sleep_timeout = Time::now()+dt;
+}
+
+
+ArduControl::CommandQueueTask::CommandQueueTask():
+ Task("CommandQueue")
+{ }
+
+
ArduControl::RefreshTask::RefreshTask():
ArduControl::RefreshTask::RefreshTask():
next(cycle.end()),
round(0),
loco(0),
next(cycle.end()),
round(0),
loco(0),
ArduControl::S88Task::S88Task(ArduControl &c):
ArduControl::S88Task::S88Task(ArduControl &c):
- octets_remaining(0),
- delay(0)
{ }
bool ArduControl::S88Task::get_work(PendingCommand &cmd)
{
{ }
bool ArduControl::S88Task::get_work(PendingCommand &cmd)
{
- if(delay)
- {
- --delay;
- return false;
- }
if(octets_remaining || !n_octets)
return false;
if(octets_remaining || !n_octets)
return false;
cmd.command[1] = octets_remaining;
cmd.length = 2;
cmd.command[1] = octets_remaining;
cmd.length = 2;
ArduControl::MfxAnnounceTask::MfxAnnounceTask():
ArduControl::MfxAnnounceTask::MfxAnnounceTask():
+ Task("MfxAnnounce", 1),
serial(0)
{ }
bool ArduControl::MfxAnnounceTask::get_work(PendingCommand &cmd)
{
serial(0)
{ }
bool ArduControl::MfxAnnounceTask::get_work(PendingCommand &cmd)
{
- Time::TimeStamp t = Time::now();
- if(t<next)
- return false;
-
cmd.command[0] = MFX_ANNOUNCE;
cmd.command[1] = serial>>8;
cmd.command[2] = serial;
cmd.length = 3;
cmd.command[0] = MFX_ANNOUNCE;
cmd.command[1] = serial>>8;
cmd.command[2] = serial;
cmd.length = 3;
- next = t+400*Time::msec;
+
+ sleep(400*Time::msec);
ArduControl::MfxSearchTask::MfxSearchTask(ArduControl &c):
ArduControl::MfxSearchTask::MfxSearchTask(ArduControl &c):
control(c),
next_address(1),
size(0),
control(c),
next_address(1),
size(0),
- Time::TimeStamp t = Time::now();
- if(t<next)
- return false;
-
cmd.command[0] = MFX_SEARCH;
for(unsigned i=0; i<4; ++i)
cmd.command[1+i] = bits>>(24-i*8);
cmd.command[5] = size;
cmd.length = 6;
cmd.command[0] = MFX_SEARCH;
for(unsigned i=0; i<4; ++i)
cmd.command[1+i] = bits>>(24-i*8);
cmd.command[5] = size;
cmd.length = 6;
- next = t+200*Time::msec;
if(control.debug>=1)
IO::print("Search %08X/%d\n", bits, size);
if(control.debug>=1)
IO::print("Search %08X/%d\n", bits, size);
- next = Time::now()+2*Time::sec;
bits = 0;
size = 0;
misses = 0;
bits = 0;
size = 0;
misses = 0;
ArduControl::MonitorTask::MonitorTask():
ArduControl::MonitorTask::MonitorTask():
voltage(0),
current(0),
base_level(0),
voltage(0),
current(0),
base_level(0),
bool ArduControl::MonitorTask::get_work(PendingCommand &cmd)
{
bool ArduControl::MonitorTask::get_work(PendingCommand &cmd)
{
- Time::TimeStamp t = Time::now();
- if(t<next_poll)
- return false;
-
if(next_type==0)
cmd.command[0] = READ_INPUT_VOLTAGE;
else
cmd.command[0] = READ_TRACK_CURRENT;
cmd.length = 1;
if(next_type==0)
cmd.command[0] = READ_INPUT_VOLTAGE;
else
cmd.command[0] = READ_TRACK_CURRENT;
cmd.length = 1;
- next_poll = t+200*Time::msec;
next_type = (next_type+1)%5;
return true;
next_type = (next_type+1)%5;
return true;
bool ArduControl::ControlThread::get_work(PendingCommand &cmd)
{
bool ArduControl::ControlThread::get_work(PendingCommand &cmd)
{
- for(vector<Task *>::iterator i=tasks.begin(); i!=tasks.end(); ++i)
- if((*i)->get_work(cmd))
+ Time::TimeStamp t = Time::now();
+
+ unsigned count = 0;
+ for(; (count<tasks.size() && tasks[count]->get_sleep_timeout()<=t); ++count) ;
+
+ for(; count>0; --count)
+ {
+ unsigned i = 0;
+ for(unsigned j=1; j<count; ++j)
+ if(tasks[j]->get_priority()<tasks[i]->get_priority())
+ i = j;
+
+ Task *task = tasks[i];
+ bool result = task->get_work(cmd);
+
+ Time::TimeStamp st = max(task->get_sleep_timeout(), t);
+ for(; (i+1<tasks.size() && tasks[i+1]->get_sleep_timeout()<=st); ++i)
+ tasks[i] = tasks[i+1];
+ tasks[i] = task;
+
+ if(result)
+ {
+ if(control.debug>=2)
+ IO::print("Scheduled task %s\n", task->get_name());
// As fallback, send an idle packet for the MM protocol
cmd.command[0] = MOTOROLA_SPEED;
// As fallback, send an idle packet for the MM protocol
cmd.command[0] = MOTOROLA_SPEED;
+ std::string name;
+ unsigned priority;
+ Msp::Time::TimeStamp sleep_timeout;
+
+ Task(const std::string &, unsigned = 0);
public:
virtual ~Task() { }
public:
virtual ~Task() { }
+ const std::string &get_name() const { return name; }
+
virtual bool get_work(PendingCommand &) = 0;
virtual void process_reply(const char *, unsigned) { }
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
};
class CommandQueueTask: public Task
Queue<PendingCommand> queue;
public:
Queue<PendingCommand> queue;
public:
virtual bool get_work(PendingCommand &);
void push(const PendingCommand &);
virtual bool get_work(PendingCommand &);
void push(const PendingCommand &);
ArduControl &control;
unsigned n_octets;
unsigned octets_remaining;
ArduControl &control;
unsigned n_octets;
unsigned octets_remaining;
public:
S88Task(ArduControl &);
public:
S88Task(ArduControl &);
{
private:
unsigned serial;
{
private:
unsigned serial;
- Msp::Time::TimeStamp next;
public:
MfxAnnounceTask();
public:
MfxAnnounceTask();
private:
ArduControl &control;
unsigned next_address;
private:
ArduControl &control;
unsigned next_address;
- Msp::Time::TimeStamp next;
unsigned size;
unsigned bits;
unsigned misses;
unsigned size;
unsigned bits;
unsigned misses;
float current;
float base_level;
float peak_level;
float current;
float base_level;
float peak_level;
- Msp::Time::TimeStamp next_poll;
unsigned next_type;
public:
unsigned next_type;
public: