tx_queue.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. /*
  2. * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
  3. */
  4. #include <gtest/gtest.h>
  5. #include <uavcan/transport/can_io.hpp>
  6. #include "can.hpp"
  7. static int getQueueLength(uavcan::CanTxQueue& queue)
  8. {
  9. const uavcan::CanTxQueue::Entry* p = queue.peek();
  10. int length = 0;
  11. while (p)
  12. {
  13. length++;
  14. p = p->getNextListNode();
  15. }
  16. return length;
  17. }
  18. static bool isInQueue(uavcan::CanTxQueue& queue, const uavcan::CanFrame& frame)
  19. {
  20. const uavcan::CanTxQueue::Entry* p = queue.peek();
  21. while (p)
  22. {
  23. if (frame == p->frame)
  24. {
  25. return true;
  26. }
  27. p = p->getNextListNode();
  28. }
  29. return false;
  30. }
  31. TEST(CanTxQueue, Qos)
  32. {
  33. const uavcan::CanIOFlags flags = 0;
  34. uavcan::CanTxQueue::Entry e1(makeCanFrame(100, "", EXT), tsMono(1000), uavcan::CanTxQueue::Volatile, flags);
  35. uavcan::CanTxQueue::Entry e2(makeCanFrame(100, "", EXT), tsMono(1000), uavcan::CanTxQueue::Volatile, flags);
  36. EXPECT_FALSE(e1.qosHigherThan(e2));
  37. EXPECT_FALSE(e2.qosHigherThan(e1));
  38. EXPECT_FALSE(e1.qosLowerThan(e2));
  39. EXPECT_FALSE(e2.qosLowerThan(e1));
  40. e2.qos = uavcan::CanTxQueue::Persistent;
  41. EXPECT_FALSE(e1.qosHigherThan(e2));
  42. EXPECT_TRUE(e2.qosHigherThan(e1));
  43. EXPECT_TRUE(e1.qosLowerThan(e2));
  44. EXPECT_FALSE(e2.qosLowerThan(e1));
  45. e1.qos = uavcan::CanTxQueue::Persistent;
  46. e1.frame.id -= 1;
  47. EXPECT_TRUE(e1.qosHigherThan(e2));
  48. EXPECT_FALSE(e2.qosHigherThan(e1));
  49. EXPECT_FALSE(e1.qosLowerThan(e2));
  50. EXPECT_TRUE(e2.qosLowerThan(e1));
  51. }
  52. TEST(CanTxQueue, TxQueue)
  53. {
  54. using uavcan::CanTxQueue;
  55. using uavcan::CanFrame;
  56. ASSERT_GE(40, sizeof(CanTxQueue::Entry)); // should be true for any platforms, though not required
  57. uavcan::PoolAllocator<40 * 4, 40> pool;
  58. SystemClockMock clockmock;
  59. CanTxQueue queue(pool, clockmock, 99999);
  60. EXPECT_TRUE(queue.isEmpty());
  61. const uavcan::CanIOFlags flags = 0;
  62. // Descending priority
  63. const CanFrame f0 = makeCanFrame(0, "f0", EXT);
  64. const CanFrame f1 = makeCanFrame(10, "f1", EXT);
  65. const CanFrame f2 = makeCanFrame(20, "f2", EXT);
  66. const CanFrame f3 = makeCanFrame(100, "f3", EXT);
  67. const CanFrame f4 = makeCanFrame(10000, "f4", EXT);
  68. const CanFrame f5 = makeCanFrame(99999, "f5", EXT);
  69. const CanFrame f5a = makeCanFrame(99999, "f5a", EXT);
  70. const CanFrame f6 = makeCanFrame(999999, "f6", EXT);
  71. /*
  72. * Priority insertion
  73. */
  74. queue.push(f4, tsMono(100), CanTxQueue::Persistent, flags);
  75. EXPECT_FALSE(queue.isEmpty());
  76. EXPECT_EQ(1, pool.getNumUsedBlocks());
  77. EXPECT_EQ(f4, queue.peek()->frame);
  78. EXPECT_TRUE(queue.topPriorityHigherOrEqual(f5));
  79. EXPECT_TRUE(queue.topPriorityHigherOrEqual(f4)); // Equal
  80. EXPECT_FALSE(queue.topPriorityHigherOrEqual(f3));
  81. queue.push(f3, tsMono(200), CanTxQueue::Persistent, flags);
  82. EXPECT_EQ(f3, queue.peek()->frame);
  83. queue.push(f0, tsMono(300), CanTxQueue::Volatile, flags);
  84. EXPECT_EQ(f0, queue.peek()->frame);
  85. queue.push(f1, tsMono(400), CanTxQueue::Volatile, flags);
  86. EXPECT_EQ(f0, queue.peek()->frame); // Still f0, since it is highest
  87. EXPECT_TRUE(queue.topPriorityHigherOrEqual(f0)); // Equal
  88. EXPECT_TRUE(queue.topPriorityHigherOrEqual(f1));
  89. // Out of free memory now
  90. EXPECT_EQ(0, queue.getRejectedFrameCount());
  91. EXPECT_EQ(4, getQueueLength(queue));
  92. EXPECT_TRUE(isInQueue(queue, f0));
  93. EXPECT_TRUE(isInQueue(queue, f1));
  94. EXPECT_TRUE(isInQueue(queue, f3));
  95. EXPECT_TRUE(isInQueue(queue, f4));
  96. const CanTxQueue::Entry* p = queue.peek();
  97. while (p)
  98. {
  99. std::cout << p->toString() << std::endl;
  100. p = p->getNextListNode();
  101. }
  102. /*
  103. * QoS
  104. */
  105. EXPECT_FALSE(isInQueue(queue, f2));
  106. queue.push(f2, tsMono(100), CanTxQueue::Volatile, flags); // Non preempting, will be rejected
  107. EXPECT_FALSE(isInQueue(queue, f2));
  108. queue.push(f2, tsMono(500), CanTxQueue::Persistent, flags); // Will override f1 (f3 and f4 are presistent)
  109. EXPECT_TRUE(isInQueue(queue, f2));
  110. EXPECT_FALSE(isInQueue(queue, f1));
  111. EXPECT_EQ(4, getQueueLength(queue));
  112. EXPECT_EQ(2, queue.getRejectedFrameCount());
  113. EXPECT_EQ(f0, queue.peek()->frame); // Check the priority
  114. queue.push(f5, tsMono(600), CanTxQueue::Persistent, flags); // Will override f0 (rest are presistent)
  115. EXPECT_TRUE(isInQueue(queue, f5));
  116. EXPECT_FALSE(isInQueue(queue, f0));
  117. EXPECT_EQ(f2, queue.peek()->frame); // Check the priority
  118. // No volatile frames left now
  119. queue.push(f5a, tsMono(700), CanTxQueue::Persistent, flags); // Will override f5 (same frame, same QoS)
  120. EXPECT_TRUE(isInQueue(queue, f5a));
  121. EXPECT_FALSE(isInQueue(queue, f5));
  122. queue.push(f6, tsMono(700), CanTxQueue::Persistent, flags); // Will be rejected (lowest QoS)
  123. EXPECT_FALSE(isInQueue(queue, f6));
  124. EXPECT_FALSE(queue.topPriorityHigherOrEqual(f0));
  125. EXPECT_TRUE(queue.topPriorityHigherOrEqual(f2)); // Equal
  126. EXPECT_TRUE(queue.topPriorityHigherOrEqual(f5a));
  127. EXPECT_EQ(4, getQueueLength(queue));
  128. EXPECT_EQ(4, pool.getNumUsedBlocks());
  129. EXPECT_EQ(5, queue.getRejectedFrameCount());
  130. EXPECT_TRUE(isInQueue(queue, f2));
  131. EXPECT_TRUE(isInQueue(queue, f3));
  132. EXPECT_TRUE(isInQueue(queue, f4));
  133. EXPECT_TRUE(isInQueue(queue, f5a));
  134. EXPECT_EQ(f2, queue.peek()->frame); // Check the priority
  135. /*
  136. * Expiration
  137. */
  138. clockmock.monotonic = 101;
  139. queue.push(f0, tsMono(800), CanTxQueue::Volatile, flags); // Will replace f4 which is expired now
  140. EXPECT_TRUE(isInQueue(queue, f0));
  141. EXPECT_FALSE(isInQueue(queue, f4));
  142. EXPECT_EQ(6, queue.getRejectedFrameCount());
  143. clockmock.monotonic = 1001;
  144. queue.push(f5, tsMono(2000), CanTxQueue::Volatile, flags); // Entire queue is expired
  145. EXPECT_TRUE(isInQueue(queue, f5));
  146. EXPECT_EQ(1, getQueueLength(queue)); // Just one entry left - f5
  147. EXPECT_EQ(1, pool.getNumUsedBlocks()); // Make sure there is no leaks
  148. EXPECT_EQ(10, queue.getRejectedFrameCount());
  149. queue.push(f0, tsMono(1000), CanTxQueue::Persistent, flags); // This entry is already expired
  150. EXPECT_EQ(1, getQueueLength(queue));
  151. EXPECT_EQ(1, pool.getNumUsedBlocks());
  152. EXPECT_EQ(11, queue.getRejectedFrameCount());
  153. /*
  154. * Removing
  155. */
  156. queue.push(f4, tsMono(5000), CanTxQueue::Volatile, flags);
  157. EXPECT_EQ(2, getQueueLength(queue));
  158. EXPECT_TRUE(isInQueue(queue, f4));
  159. EXPECT_EQ(f4, queue.peek()->frame);
  160. CanTxQueue::Entry* entry = queue.peek();
  161. EXPECT_TRUE(entry);
  162. queue.remove(entry);
  163. EXPECT_FALSE(entry);
  164. EXPECT_FALSE(isInQueue(queue, f4));
  165. EXPECT_TRUE(isInQueue(queue, f5));
  166. entry = queue.peek();
  167. EXPECT_TRUE(entry);
  168. queue.remove(entry);
  169. EXPECT_FALSE(entry);
  170. EXPECT_FALSE(isInQueue(queue, f5));
  171. EXPECT_EQ(0, getQueueLength(queue)); // Final state checks
  172. EXPECT_EQ(0, pool.getNumUsedBlocks());
  173. EXPECT_EQ(11, queue.getRejectedFrameCount());
  174. EXPECT_FALSE(queue.peek());
  175. EXPECT_FALSE(queue.topPriorityHigherOrEqual(f0));
  176. }