mirror of
https://gitee.com/mirrors_PX4/PX4-Autopilot.git
synced 2026-10-14 05:23:33 +08:00
spinOnce(), fixes #31
This commit is contained in:
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user