mirror of
https://gitee.com/mirrors_PX4/PX4-Autopilot.git
synced 2026-10-26 07:03:33 +08:00
Modified CAN driver API: Passing the next pending TX frames into the select() call to facilitate proper prioritization in the driver
This commit is contained in:
@@ -75,7 +75,9 @@ struct PairableCanDriver : public uavcan::ICanDriver, public uavcan::ICanIface
|
||||
|
||||
virtual uavcan::uint8_t getNumIfaces() const { return 1; }
|
||||
|
||||
virtual uavcan::int16_t select(uavcan::CanSelectMasks& inout_masks, uavcan::MonotonicTime blocking_deadline)
|
||||
virtual uavcan::int16_t select(uavcan::CanSelectMasks& inout_masks,
|
||||
const uavcan::CanFrame* (&)[uavcan::MaxCanIfaces],
|
||||
uavcan::MonotonicTime blocking_deadline)
|
||||
{
|
||||
if (inout_masks.read == 1)
|
||||
{
|
||||
|
||||
@@ -54,6 +54,7 @@ public:
|
||||
uint64_t num_errors;
|
||||
uavcan::ISystemClock& iclock;
|
||||
bool enable_utc_timestamping;
|
||||
uavcan::CanFrame pending_tx;
|
||||
|
||||
CanIfaceMock(uavcan::ISystemClock& iclock)
|
||||
: writeable(true)
|
||||
@@ -88,6 +89,17 @@ public:
|
||||
return (frame_time.frame == frame) && (frame_time.time == tx_deadline);
|
||||
}
|
||||
|
||||
bool matchPendingTx(const uavcan::CanFrame& frame) const
|
||||
{
|
||||
if (pending_tx != frame)
|
||||
{
|
||||
std::cout << "Pending TX mismatch: \n"
|
||||
<< " Expected: " << frame.toString(uavcan::CanFrame::StrAligned) << "\n"
|
||||
<< " Actual: " << pending_tx.toString(uavcan::CanFrame::StrAligned) << std::endl;
|
||||
}
|
||||
return pending_tx == frame;
|
||||
}
|
||||
|
||||
bool matchAndPopTx(const uavcan::CanFrame& frame, uint64_t tx_deadline_usec)
|
||||
{
|
||||
return matchAndPopTx(frame, uavcan::MonotonicTime::fromUSec(tx_deadline_usec));
|
||||
@@ -196,11 +208,18 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
virtual uavcan::int16_t select(uavcan::CanSelectMasks& inout_masks, uavcan::MonotonicTime deadline)
|
||||
virtual uavcan::int16_t select(uavcan::CanSelectMasks& inout_masks,
|
||||
const uavcan::CanFrame* (& pending_tx)[uavcan::MaxCanIfaces],
|
||||
uavcan::MonotonicTime deadline)
|
||||
{
|
||||
assert(this);
|
||||
//std::cout << "Write/read masks: " << inout_write_iface_mask << "/" << inout_read_iface_mask << std::endl;
|
||||
|
||||
for (unsigned i = 0; i < ifaces.size(); i++)
|
||||
{
|
||||
ifaces.at(i).pending_tx = (pending_tx[i] == NULL) ? uavcan::CanFrame() : *pending_tx[i];
|
||||
}
|
||||
|
||||
if (select_failure)
|
||||
{
|
||||
return -1;
|
||||
|
||||
@@ -13,13 +13,15 @@ TEST(CanDriverMock, Basic)
|
||||
SystemClockMock clockmock;
|
||||
CanDriverMock driver(3, clockmock);
|
||||
|
||||
const uavcan::CanFrame* pending_tx[uavcan::MaxCanIfaces] = { };
|
||||
|
||||
ASSERT_EQ(3, driver.getNumIfaces());
|
||||
|
||||
// All WR, no RD
|
||||
CanSelectMasks masks;
|
||||
masks.write = 7;
|
||||
masks.read = 7;
|
||||
EXPECT_LT(0, driver.select(masks, uavcan::MonotonicTime::fromUSec(100)));
|
||||
EXPECT_LT(0, driver.select(masks, pending_tx, uavcan::MonotonicTime::fromUSec(100)));
|
||||
EXPECT_EQ(7, masks.write);
|
||||
EXPECT_EQ(0, masks.read);
|
||||
|
||||
@@ -31,7 +33,7 @@ TEST(CanDriverMock, Basic)
|
||||
// No WR, no RD
|
||||
masks.write = 7;
|
||||
masks.read = 7;
|
||||
EXPECT_EQ(0, driver.select(masks, uavcan::MonotonicTime::fromUSec(100)));
|
||||
EXPECT_EQ(0, driver.select(masks, pending_tx, uavcan::MonotonicTime::fromUSec(100)));
|
||||
EXPECT_EQ(0, masks.write);
|
||||
EXPECT_EQ(0, masks.read);
|
||||
EXPECT_EQ(100, clockmock.monotonic);
|
||||
@@ -42,7 +44,7 @@ TEST(CanDriverMock, Basic)
|
||||
driver.ifaces.at(1).pushRx(fr1);
|
||||
masks.write = 7;
|
||||
masks.read = 6;
|
||||
EXPECT_LT(0, driver.select(masks, uavcan::MonotonicTime::fromUSec(100)));
|
||||
EXPECT_LT(0, driver.select(masks, pending_tx, uavcan::MonotonicTime::fromUSec(100)));
|
||||
EXPECT_EQ(0, masks.write);
|
||||
EXPECT_EQ(2, masks.read);
|
||||
CanFrame fr2;
|
||||
@@ -60,7 +62,7 @@ TEST(CanDriverMock, Basic)
|
||||
driver.select_failure = true;
|
||||
masks.write = 1;
|
||||
masks.read = 7;
|
||||
EXPECT_EQ(-1, driver.select(masks, uavcan::MonotonicTime::fromUSec(100)));
|
||||
EXPECT_EQ(-1, driver.select(masks, pending_tx, uavcan::MonotonicTime::fromUSec(100)));
|
||||
EXPECT_EQ(1, masks.write); // Leaving masks unchanged - the library must ignore them
|
||||
EXPECT_EQ(7, masks.read);
|
||||
}
|
||||
@@ -73,10 +75,12 @@ TEST(CanDriverMock, Loopback)
|
||||
SystemClockMock clockmock;
|
||||
CanDriverMock driver(1, clockmock);
|
||||
|
||||
const uavcan::CanFrame* pending_tx[uavcan::MaxCanIfaces] = { };
|
||||
|
||||
CanSelectMasks masks;
|
||||
masks.write = 1;
|
||||
masks.read = 1;
|
||||
EXPECT_LT(0, driver.select(masks, uavcan::MonotonicTime::fromUSec(100)));
|
||||
EXPECT_LT(0, driver.select(masks, pending_tx, uavcan::MonotonicTime::fromUSec(100)));
|
||||
EXPECT_EQ(1, masks.write);
|
||||
EXPECT_EQ(0, masks.read);
|
||||
|
||||
@@ -88,7 +92,7 @@ TEST(CanDriverMock, Loopback)
|
||||
|
||||
masks.write = 0;
|
||||
masks.read = 1;
|
||||
EXPECT_LT(0, driver.select(masks, uavcan::MonotonicTime::fromUSec(100)));
|
||||
EXPECT_LT(0, driver.select(masks, pending_tx, uavcan::MonotonicTime::fromUSec(100)));
|
||||
EXPECT_EQ(0, masks.write);
|
||||
EXPECT_EQ(1, masks.read);
|
||||
|
||||
|
||||
@@ -141,9 +141,13 @@ TEST(CanIOManager, Transmission)
|
||||
EXPECT_EQ(2, iomgr.send(frames[0], tsMono(100), tsMono(0), ALL_IFACES_MASK, CanTxQueue::Volatile, flags));
|
||||
EXPECT_TRUE(driver.ifaces.at(0).matchAndPopTx(frames[0], 100));
|
||||
EXPECT_TRUE(driver.ifaces.at(1).matchAndPopTx(frames[0], 100));
|
||||
EXPECT_TRUE(driver.ifaces.at(0).matchPendingTx(frames[0]));
|
||||
EXPECT_TRUE(driver.ifaces.at(1).matchPendingTx(frames[0]));
|
||||
|
||||
EXPECT_EQ(1, iomgr.send(frames[1], tsMono(200), tsMono(100), 2, CanTxQueue::Persistent, flags)); // To #1 only
|
||||
EXPECT_TRUE(driver.ifaces.at(1).matchAndPopTx(frames[1], 200));
|
||||
EXPECT_TRUE(driver.ifaces.at(0).matchPendingTx(uavcan::CanFrame()));
|
||||
EXPECT_TRUE(driver.ifaces.at(1).matchPendingTx(frames[1]));
|
||||
|
||||
EXPECT_EQ(0, clockmock.monotonic);
|
||||
EXPECT_EQ(0, clockmock.utc);
|
||||
@@ -166,11 +170,15 @@ TEST(CanIOManager, Transmission)
|
||||
EXPECT_TRUE(driver.ifaces.at(0).tx.empty());
|
||||
EXPECT_TRUE(driver.ifaces.at(1).tx.empty());
|
||||
EXPECT_EQ(1, pool.getNumUsedBlocks()); // One frame went into TX queue, and will expire soon
|
||||
EXPECT_TRUE(driver.ifaces.at(0).matchPendingTx(frames[0])); // This one will persist
|
||||
EXPECT_TRUE(driver.ifaces.at(1).matchPendingTx(uavcan::CanFrame())); // This will drop off on the second select()
|
||||
|
||||
// Sending to both, both blocked
|
||||
driver.ifaces.at(1).writeable = false;
|
||||
EXPECT_EQ(0, iomgr.send(frames[1], tsMono(777), tsMono(300), ALL_IFACES_MASK, CanTxQueue::Volatile, flags));
|
||||
EXPECT_EQ(3, pool.getNumUsedBlocks()); // Total 3 frames in TX queue now
|
||||
EXPECT_TRUE(driver.ifaces.at(0).matchPendingTx(frames[0])); // Still 0
|
||||
EXPECT_TRUE(driver.ifaces.at(1).matchPendingTx(frames[1])); // 1!!
|
||||
|
||||
// Sending to #0, both blocked
|
||||
EXPECT_EQ(0, iomgr.send(frames[2], tsMono(888), tsMono(400), 1, CanTxQueue::Persistent, flags));
|
||||
@@ -179,6 +187,8 @@ TEST(CanIOManager, Transmission)
|
||||
EXPECT_TRUE(driver.ifaces.at(0).tx.empty());
|
||||
EXPECT_TRUE(driver.ifaces.at(1).tx.empty());
|
||||
EXPECT_EQ(4, pool.getNumUsedBlocks());
|
||||
EXPECT_TRUE(driver.ifaces.at(0).matchPendingTx(frames[0]));
|
||||
EXPECT_TRUE(driver.ifaces.at(1).matchPendingTx(frames[1]));
|
||||
|
||||
// At this time TX queues are containing the following data:
|
||||
// iface 0: frames[0] (EXPIRED), frames[1], frames[2]
|
||||
@@ -193,6 +203,8 @@ TEST(CanIOManager, Transmission)
|
||||
EXPECT_TRUE(driver.ifaces.at(1).matchAndPopTx(frames[0], 999)); // In different order due to prioritization
|
||||
EXPECT_TRUE(driver.ifaces.at(0).tx.empty());
|
||||
EXPECT_TRUE(driver.ifaces.at(1).tx.empty());
|
||||
EXPECT_TRUE(driver.ifaces.at(0).matchPendingTx(frames[0])); // Expired but still will be reported
|
||||
EXPECT_TRUE(driver.ifaces.at(1).matchPendingTx(frames[0]));
|
||||
|
||||
// Calling receive() to flush the rest two frames
|
||||
uavcan::CanRxFrame dummy_rx_frame;
|
||||
@@ -200,6 +212,8 @@ TEST(CanIOManager, Transmission)
|
||||
EXPECT_TRUE(driver.ifaces.at(0).matchAndPopTx(frames[2], 888));
|
||||
EXPECT_TRUE(driver.ifaces.at(1).matchAndPopTx(frames[1], 777));
|
||||
ASSERT_EQ(0, flags);
|
||||
EXPECT_TRUE(driver.ifaces.at(0).matchPendingTx(frames[2]));
|
||||
EXPECT_TRUE(driver.ifaces.at(1).matchPendingTx(frames[1]));
|
||||
|
||||
// Final checks
|
||||
EXPECT_TRUE(driver.ifaces.at(0).tx.empty());
|
||||
@@ -220,6 +234,9 @@ TEST(CanIOManager, Transmission)
|
||||
// One frame kicked here:
|
||||
EXPECT_EQ(0, iomgr.send(frames[1], tsMono(4444), tsMono(1200), ALL_IFACES_MASK, CanTxQueue::Volatile, flags));
|
||||
|
||||
EXPECT_TRUE(driver.ifaces.at(0).matchPendingTx(frames[1]));
|
||||
EXPECT_TRUE(driver.ifaces.at(1).matchPendingTx(frames[0]));
|
||||
|
||||
// State checks
|
||||
EXPECT_EQ(4, pool.getNumUsedBlocks()); // TX queue is full
|
||||
EXPECT_EQ(1200, clockmock.monotonic);
|
||||
@@ -241,12 +258,16 @@ TEST(CanIOManager, Transmission)
|
||||
EXPECT_TRUE(driver.ifaces.at(0).matchAndPopTx(frames[1], 4444));
|
||||
EXPECT_TRUE(driver.ifaces.at(1).matchAndPopTx(frames[0], 3333));
|
||||
ASSERT_EQ(0, flags);
|
||||
EXPECT_TRUE(driver.ifaces.at(0).matchPendingTx(frames[1]));
|
||||
EXPECT_TRUE(driver.ifaces.at(1).matchPendingTx(frames[0]));
|
||||
|
||||
EXPECT_EQ(1, iomgr.receive(rx_frame, tsMono(0), flags));
|
||||
EXPECT_TRUE(rxFrameEquals(rx_frame, rx_frames[1], 1200, 1));
|
||||
EXPECT_TRUE(driver.ifaces.at(0).matchAndPopTx(frames[2], 2222));
|
||||
EXPECT_TRUE(driver.ifaces.at(1).matchAndPopTx(frames[2], 2222)); // Iface #1, frame[1] was rejected (VOLATILE)
|
||||
ASSERT_EQ(0, flags);
|
||||
EXPECT_TRUE(driver.ifaces.at(0).matchPendingTx(frames[2]));
|
||||
EXPECT_TRUE(driver.ifaces.at(1).matchPendingTx(frames[2]));
|
||||
|
||||
// State checks
|
||||
EXPECT_EQ(0, pool.getNumUsedBlocks()); // TX queue is empty
|
||||
@@ -268,6 +289,8 @@ TEST(CanIOManager, Transmission)
|
||||
EXPECT_EQ(1200, clockmock.monotonic);
|
||||
EXPECT_EQ(1200, clockmock.utc);
|
||||
ASSERT_EQ(0, flags);
|
||||
EXPECT_TRUE(driver.ifaces.at(0).matchPendingTx(frames[0]));
|
||||
EXPECT_TRUE(driver.ifaces.at(1).matchPendingTx(frames[0]));
|
||||
|
||||
// Transmission failure
|
||||
driver.select_failure = false;
|
||||
@@ -277,6 +300,8 @@ TEST(CanIOManager, Transmission)
|
||||
driver.ifaces.at(1).tx_failure = true;
|
||||
// Non-blocking - return < 0
|
||||
EXPECT_GE(0, iomgr.send(frames[0], tsMono(2200), tsMono(0), ALL_IFACES_MASK, CanTxQueue::Persistent, flags));
|
||||
EXPECT_TRUE(driver.ifaces.at(0).matchPendingTx(frames[0]));
|
||||
EXPECT_TRUE(driver.ifaces.at(1).matchPendingTx(frames[0]));
|
||||
|
||||
ASSERT_EQ(2, pool.getNumUsedBlocks()); // Untransmitted frames will be buffered
|
||||
|
||||
@@ -288,6 +313,8 @@ TEST(CanIOManager, Transmission)
|
||||
EXPECT_TRUE(driver.ifaces.at(1).matchAndPopTx(frames[0], 2200));
|
||||
EXPECT_EQ(0, pool.getNumUsedBlocks()); // All transmitted
|
||||
ASSERT_EQ(0, flags);
|
||||
EXPECT_TRUE(driver.ifaces.at(0).matchPendingTx(uavcan::CanFrame())); // Last call will be receive-only,
|
||||
EXPECT_TRUE(driver.ifaces.at(1).matchPendingTx(uavcan::CanFrame())); // hence empty TX
|
||||
|
||||
/*
|
||||
* Perf counters
|
||||
|
||||
Reference in New Issue
Block a user