spinOnce(), fixes #31

This commit is contained in:
Pavel Kirienko
2015-05-27 11:53:12 +03:00
parent 89c8ed0cf1
commit 74298b1860
6 changed files with 99 additions and 4 deletions
@@ -76,6 +76,18 @@ public:
{
return getScheduler().spin(getMonotonicTime() + duration);
}
/**
* This method is designed for non-blocking applications.
* Instead of blocking, it returns immediately once all available CAN frames and timer events are processed.
* Note that this is unlike plain @ref spin(), which will strictly return when the deadline is reached,
* even if there still are unprocessed events.
* This method returns 0 if no errors occurred, or a negative error code if something failed (see error.hpp).
*/
int spinOnce()
{
return getScheduler().spinOnce();
}
};
}
@@ -77,6 +77,17 @@ class UAVCAN_EXPORT Scheduler : Noncopyable
MonotonicDuration cleanup_period_;
bool inside_spin_;
struct InsideSpinSetter
{
Scheduler& owner;
InsideSpinSetter(Scheduler& o)
: owner(o)
{
owner.inside_spin_ = true;
}
~InsideSpinSetter() { owner.inside_spin_ = false; }
};
MonotonicTime computeDispatcherSpinDeadline(MonotonicTime spin_deadline) const;
void pollCleanup(MonotonicTime mono_ts, uint32_t num_frames_processed_with_last_spin);
@@ -91,10 +102,18 @@ public:
/**
* Spin until the deadline, or until some error occurs.
* This function will return strictly when the deadline is reached, even if there are unprocessed frames.
* Returns negative error code.
*/
int spin(MonotonicTime deadline);
/**
* Non-blocking version of @ref spin() - spins until all pending frames and events are processed,
* or until some error occurs. If there's nothing to do, returns immediately.
* Returns negative error code.
*/
int spinOnce();
DeadlineScheduler& getDeadlineScheduler() { return deadline_scheduler_; }
Dispatcher& getDispatcher() { return dispatcher_; }
@@ -119,8 +119,16 @@ public:
, self_node_id_is_set_(false)
{ }
/**
* This version returns strictly when the deadline is reached.
*/
int spin(MonotonicTime deadline);
/**
* This version does not return untill all available frames are processed.
*/
int spinOnce();
/**
* Refer to CanIOManager::send() for the parameter description
*/
+24 -2
View File
@@ -159,7 +159,8 @@ int Scheduler::spin(MonotonicTime deadline)
UAVCAN_ASSERT(0);
return -ErrRecursiveCall;
}
inside_spin_ = true;
InsideSpinSetter iss(*this);
UAVCAN_ASSERT(inside_spin_);
int retval = 0;
while (true)
@@ -179,7 +180,28 @@ int Scheduler::spin(MonotonicTime deadline)
}
}
inside_spin_ = false;
return retval;
}
int Scheduler::spinOnce()
{
if (inside_spin_) // Preventing recursive calls
{
UAVCAN_ASSERT(0);
return -ErrRecursiveCall;
}
InsideSpinSetter iss(*this);
UAVCAN_ASSERT(inside_spin_);
const int retval = dispatcher_.spinOnce();
if (retval < 0)
{
return retval;
}
const MonotonicTime ts = deadline_scheduler_.pollAndGetMonotonicTime(getSystemClock());
pollCleanup(ts, unsigned(retval));
return retval;
}
+34
View File
@@ -229,6 +229,40 @@ int Dispatcher::spin(MonotonicTime deadline)
return num_frames_processed;
}
int Dispatcher::spinOnce()
{
int num_frames_processed = 0;
while (true)
{
CanIOFlags flags = 0;
CanRxFrame frame;
const int res = canio_.receive(frame, MonotonicTime(), flags);
if (res < 0)
{
return res;
}
else if (res > 0)
{
if (flags & CanIOFlagLoopback)
{
handleLoopbackFrame(frame);
}
else
{
num_frames_processed++;
handleFrame(frame);
}
}
else
{
break; // No frames left
}
}
return num_frames_processed;
}
int Dispatcher::send(const Frame& frame, MonotonicTime tx_deadline, MonotonicTime blocking_deadline,
CanTxQueue::Qos qos, CanIOFlags flags, uint8_t iface_mask)
{
+2 -2
View File
@@ -163,7 +163,7 @@ TEST(Dispatcher, Reception)
while (true)
{
const int res = dispatcher.spin(tsMono(0));
const int res = dispatcher.spinOnce();
ASSERT_LE(0, res);
clockmock.advance(100);
if (res == 0)
@@ -298,7 +298,7 @@ TEST(Dispatcher, Spin)
ASSERT_EQ(100, clockmock.monotonic);
ASSERT_EQ(0, dispatcher.spin(tsMono(1000)));
ASSERT_LE(1000, clockmock.monotonic);
ASSERT_EQ(0, dispatcher.spin(tsMono(0)));
ASSERT_EQ(0, dispatcher.spinOnce());
ASSERT_LE(1000, clockmock.monotonic);
ASSERT_EQ(0, dispatcher.spin(tsMono(1100)));
ASSERT_LE(1100, clockmock.monotonic);