123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216 |
- /*
- * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
- */
- #include <gtest/gtest.h>
- #include <uavcan/transport/can_io.hpp>
- #include "can.hpp"
- static int getQueueLength(uavcan::CanTxQueue& queue)
- {
- const uavcan::CanTxQueue::Entry* p = queue.peek();
- int length = 0;
- while (p)
- {
- length++;
- p = p->getNextListNode();
- }
- return length;
- }
- static bool isInQueue(uavcan::CanTxQueue& queue, const uavcan::CanFrame& frame)
- {
- const uavcan::CanTxQueue::Entry* p = queue.peek();
- while (p)
- {
- if (frame == p->frame)
- {
- return true;
- }
- p = p->getNextListNode();
- }
- return false;
- }
- TEST(CanTxQueue, Qos)
- {
- const uavcan::CanIOFlags flags = 0;
- uavcan::CanTxQueue::Entry e1(makeCanFrame(100, "", EXT), tsMono(1000), uavcan::CanTxQueue::Volatile, flags);
- uavcan::CanTxQueue::Entry e2(makeCanFrame(100, "", EXT), tsMono(1000), uavcan::CanTxQueue::Volatile, flags);
- EXPECT_FALSE(e1.qosHigherThan(e2));
- EXPECT_FALSE(e2.qosHigherThan(e1));
- EXPECT_FALSE(e1.qosLowerThan(e2));
- EXPECT_FALSE(e2.qosLowerThan(e1));
- e2.qos = uavcan::CanTxQueue::Persistent;
- EXPECT_FALSE(e1.qosHigherThan(e2));
- EXPECT_TRUE(e2.qosHigherThan(e1));
- EXPECT_TRUE(e1.qosLowerThan(e2));
- EXPECT_FALSE(e2.qosLowerThan(e1));
- e1.qos = uavcan::CanTxQueue::Persistent;
- e1.frame.id -= 1;
- EXPECT_TRUE(e1.qosHigherThan(e2));
- EXPECT_FALSE(e2.qosHigherThan(e1));
- EXPECT_FALSE(e1.qosLowerThan(e2));
- EXPECT_TRUE(e2.qosLowerThan(e1));
- }
- TEST(CanTxQueue, TxQueue)
- {
- using uavcan::CanTxQueue;
- using uavcan::CanFrame;
- ASSERT_GE(40, sizeof(CanTxQueue::Entry)); // should be true for any platforms, though not required
- uavcan::PoolAllocator<40 * 4, 40> pool;
- SystemClockMock clockmock;
- CanTxQueue queue(pool, clockmock, 99999);
- EXPECT_TRUE(queue.isEmpty());
- const uavcan::CanIOFlags flags = 0;
- // Descending priority
- const CanFrame f0 = makeCanFrame(0, "f0", EXT);
- const CanFrame f1 = makeCanFrame(10, "f1", EXT);
- const CanFrame f2 = makeCanFrame(20, "f2", EXT);
- const CanFrame f3 = makeCanFrame(100, "f3", EXT);
- const CanFrame f4 = makeCanFrame(10000, "f4", EXT);
- const CanFrame f5 = makeCanFrame(99999, "f5", EXT);
- const CanFrame f5a = makeCanFrame(99999, "f5a", EXT);
- const CanFrame f6 = makeCanFrame(999999, "f6", EXT);
- /*
- * Priority insertion
- */
- queue.push(f4, tsMono(100), CanTxQueue::Persistent, flags);
- EXPECT_FALSE(queue.isEmpty());
- EXPECT_EQ(1, pool.getNumUsedBlocks());
- EXPECT_EQ(f4, queue.peek()->frame);
- EXPECT_TRUE(queue.topPriorityHigherOrEqual(f5));
- EXPECT_TRUE(queue.topPriorityHigherOrEqual(f4)); // Equal
- EXPECT_FALSE(queue.topPriorityHigherOrEqual(f3));
- queue.push(f3, tsMono(200), CanTxQueue::Persistent, flags);
- EXPECT_EQ(f3, queue.peek()->frame);
- queue.push(f0, tsMono(300), CanTxQueue::Volatile, flags);
- EXPECT_EQ(f0, queue.peek()->frame);
- queue.push(f1, tsMono(400), CanTxQueue::Volatile, flags);
- EXPECT_EQ(f0, queue.peek()->frame); // Still f0, since it is highest
- EXPECT_TRUE(queue.topPriorityHigherOrEqual(f0)); // Equal
- EXPECT_TRUE(queue.topPriorityHigherOrEqual(f1));
- // Out of free memory now
- EXPECT_EQ(0, queue.getRejectedFrameCount());
- EXPECT_EQ(4, getQueueLength(queue));
- EXPECT_TRUE(isInQueue(queue, f0));
- EXPECT_TRUE(isInQueue(queue, f1));
- EXPECT_TRUE(isInQueue(queue, f3));
- EXPECT_TRUE(isInQueue(queue, f4));
- const CanTxQueue::Entry* p = queue.peek();
- while (p)
- {
- std::cout << p->toString() << std::endl;
- p = p->getNextListNode();
- }
- /*
- * QoS
- */
- EXPECT_FALSE(isInQueue(queue, f2));
- queue.push(f2, tsMono(100), CanTxQueue::Volatile, flags); // Non preempting, will be rejected
- EXPECT_FALSE(isInQueue(queue, f2));
- queue.push(f2, tsMono(500), CanTxQueue::Persistent, flags); // Will override f1 (f3 and f4 are presistent)
- EXPECT_TRUE(isInQueue(queue, f2));
- EXPECT_FALSE(isInQueue(queue, f1));
- EXPECT_EQ(4, getQueueLength(queue));
- EXPECT_EQ(2, queue.getRejectedFrameCount());
- EXPECT_EQ(f0, queue.peek()->frame); // Check the priority
- queue.push(f5, tsMono(600), CanTxQueue::Persistent, flags); // Will override f0 (rest are presistent)
- EXPECT_TRUE(isInQueue(queue, f5));
- EXPECT_FALSE(isInQueue(queue, f0));
- EXPECT_EQ(f2, queue.peek()->frame); // Check the priority
- // No volatile frames left now
- queue.push(f5a, tsMono(700), CanTxQueue::Persistent, flags); // Will override f5 (same frame, same QoS)
- EXPECT_TRUE(isInQueue(queue, f5a));
- EXPECT_FALSE(isInQueue(queue, f5));
- queue.push(f6, tsMono(700), CanTxQueue::Persistent, flags); // Will be rejected (lowest QoS)
- EXPECT_FALSE(isInQueue(queue, f6));
- EXPECT_FALSE(queue.topPriorityHigherOrEqual(f0));
- EXPECT_TRUE(queue.topPriorityHigherOrEqual(f2)); // Equal
- EXPECT_TRUE(queue.topPriorityHigherOrEqual(f5a));
- EXPECT_EQ(4, getQueueLength(queue));
- EXPECT_EQ(4, pool.getNumUsedBlocks());
- EXPECT_EQ(5, queue.getRejectedFrameCount());
- EXPECT_TRUE(isInQueue(queue, f2));
- EXPECT_TRUE(isInQueue(queue, f3));
- EXPECT_TRUE(isInQueue(queue, f4));
- EXPECT_TRUE(isInQueue(queue, f5a));
- EXPECT_EQ(f2, queue.peek()->frame); // Check the priority
- /*
- * Expiration
- */
- clockmock.monotonic = 101;
- queue.push(f0, tsMono(800), CanTxQueue::Volatile, flags); // Will replace f4 which is expired now
- EXPECT_TRUE(isInQueue(queue, f0));
- EXPECT_FALSE(isInQueue(queue, f4));
- EXPECT_EQ(6, queue.getRejectedFrameCount());
- clockmock.monotonic = 1001;
- queue.push(f5, tsMono(2000), CanTxQueue::Volatile, flags); // Entire queue is expired
- EXPECT_TRUE(isInQueue(queue, f5));
- EXPECT_EQ(1, getQueueLength(queue)); // Just one entry left - f5
- EXPECT_EQ(1, pool.getNumUsedBlocks()); // Make sure there is no leaks
- EXPECT_EQ(10, queue.getRejectedFrameCount());
- queue.push(f0, tsMono(1000), CanTxQueue::Persistent, flags); // This entry is already expired
- EXPECT_EQ(1, getQueueLength(queue));
- EXPECT_EQ(1, pool.getNumUsedBlocks());
- EXPECT_EQ(11, queue.getRejectedFrameCount());
- /*
- * Removing
- */
- queue.push(f4, tsMono(5000), CanTxQueue::Volatile, flags);
- EXPECT_EQ(2, getQueueLength(queue));
- EXPECT_TRUE(isInQueue(queue, f4));
- EXPECT_EQ(f4, queue.peek()->frame);
- CanTxQueue::Entry* entry = queue.peek();
- EXPECT_TRUE(entry);
- queue.remove(entry);
- EXPECT_FALSE(entry);
- EXPECT_FALSE(isInQueue(queue, f4));
- EXPECT_TRUE(isInQueue(queue, f5));
- entry = queue.peek();
- EXPECT_TRUE(entry);
- queue.remove(entry);
- EXPECT_FALSE(entry);
- EXPECT_FALSE(isInQueue(queue, f5));
- EXPECT_EQ(0, getQueueLength(queue)); // Final state checks
- EXPECT_EQ(0, pool.getNumUsedBlocks());
- EXPECT_EQ(11, queue.getRejectedFrameCount());
- EXPECT_FALSE(queue.peek());
- EXPECT_FALSE(queue.topPriorityHigherOrEqual(f0));
- }
|