io.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. /*
  2. * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
  3. */
  4. #include <gtest/gtest.h>
  5. #include "can.hpp"
  6. static bool rxFrameEquals(const uavcan::CanRxFrame& rxframe, const uavcan::CanFrame& frame,
  7. uint64_t timestamp_usec, int iface_index)
  8. {
  9. if (static_cast<const uavcan::CanFrame&>(rxframe) != frame)
  10. {
  11. std::cout << "Frame mismatch:\n"
  12. << " " << rxframe.toString(uavcan::CanFrame::StrAligned) << "\n"
  13. << " " << frame.toString(uavcan::CanFrame::StrAligned) << std::endl;
  14. }
  15. return (static_cast<const uavcan::CanFrame&>(rxframe) == frame) &&
  16. (rxframe.ts_mono == uavcan::MonotonicTime::fromUSec(timestamp_usec)) &&
  17. (rxframe.iface_index == iface_index);
  18. }
  19. TEST(CanIOManager, Reception)
  20. {
  21. // Memory
  22. uavcan::PoolAllocator<sizeof(uavcan::CanTxQueue::Entry) * 4, sizeof(uavcan::CanTxQueue::Entry)> pool;
  23. // Platform interface
  24. SystemClockMock clockmock;
  25. CanDriverMock driver(2, clockmock);
  26. // IO Manager
  27. uavcan::CanIOManager iomgr(driver, pool, clockmock);
  28. ASSERT_EQ(2, iomgr.getNumIfaces());
  29. /*
  30. * Empty, will time out
  31. */
  32. uavcan::CanRxFrame frame;
  33. uavcan::CanIOFlags flags = uavcan::CanIOFlags();
  34. EXPECT_EQ(0, iomgr.receive(frame, tsMono(100), flags));
  35. EXPECT_EQ(0, flags);
  36. EXPECT_EQ(100, clockmock.monotonic);
  37. EXPECT_EQ(100, clockmock.utc);
  38. /*
  39. * Non empty from multiple ifaces
  40. */
  41. const uavcan::CanFrame frames[2][3] = {
  42. { makeCanFrame(1, "a0", EXT), makeCanFrame(99, "a1", EXT), makeCanFrame(803, "a2", STD) },
  43. { makeCanFrame(6341, "b0", EXT), makeCanFrame(196, "b1", STD), makeCanFrame(73, "b2", EXT) },
  44. };
  45. clockmock.advance(10);
  46. driver.ifaces.at(0).pushRx(frames[0][0]); // Timestamp 110
  47. driver.ifaces.at(1).pushRx(frames[1][0]);
  48. clockmock.advance(10);
  49. driver.ifaces.at(0).pushRx(frames[0][1]); // Timestamp 120
  50. driver.ifaces.at(1).pushRx(frames[1][1]);
  51. clockmock.advance(10);
  52. driver.ifaces.at(0).pushRx(frames[0][2]); // Timestamp 130
  53. driver.ifaces.at(1).pushRx(frames[1][2]);
  54. clockmock.advance(10);
  55. EXPECT_EQ(1, iomgr.receive(frame, uavcan::MonotonicTime(), flags));
  56. EXPECT_TRUE(rxFrameEquals(frame, frames[0][0], 110, 0));
  57. EXPECT_EQ(0, flags);
  58. EXPECT_EQ(1, iomgr.receive(frame, uavcan::MonotonicTime(), flags));
  59. EXPECT_TRUE(rxFrameEquals(frame, frames[0][1], 120, 0));
  60. EXPECT_EQ(0, flags);
  61. EXPECT_EQ(1, iomgr.receive(frame, uavcan::MonotonicTime(), flags));
  62. EXPECT_TRUE(rxFrameEquals(frame, frames[0][2], 130, 0));
  63. EXPECT_EQ(0, flags);
  64. EXPECT_EQ(1, iomgr.receive(frame, uavcan::MonotonicTime(), flags));
  65. EXPECT_TRUE(rxFrameEquals(frame, frames[1][0], 110, 1));
  66. EXPECT_EQ(0, flags);
  67. EXPECT_EQ(1, iomgr.receive(frame, uavcan::MonotonicTime(), flags));
  68. EXPECT_TRUE(rxFrameEquals(frame, frames[1][1], 120, 1));
  69. EXPECT_EQ(0, flags);
  70. EXPECT_EQ(1, iomgr.receive(frame, uavcan::MonotonicTime(), flags));
  71. EXPECT_TRUE(rxFrameEquals(frame, frames[1][2], 130, 1));
  72. EXPECT_EQ(0, flags);
  73. EXPECT_EQ(0, iomgr.receive(frame, uavcan::MonotonicTime(), flags)); // Will time out
  74. EXPECT_EQ(0, flags);
  75. /*
  76. * Perf counters
  77. */
  78. driver.select_failure = true;
  79. EXPECT_EQ(-uavcan::ErrDriver, iomgr.receive(frame, uavcan::MonotonicTime(), flags));
  80. driver.select_failure = false;
  81. driver.ifaces.at(1).pushRx(frames[0][0]);
  82. driver.ifaces.at(1).rx_failure = true;
  83. EXPECT_EQ(-uavcan::ErrDriver, iomgr.receive(frame, uavcan::MonotonicTime(), flags));
  84. driver.ifaces.at(0).num_errors = 9000;
  85. driver.ifaces.at(1).num_errors = 100500;
  86. EXPECT_EQ(9000, iomgr.getIfacePerfCounters(0).errors);
  87. EXPECT_EQ(100500, iomgr.getIfacePerfCounters(1).errors);
  88. EXPECT_EQ(3, iomgr.getIfacePerfCounters(0).frames_rx);
  89. EXPECT_EQ(3, iomgr.getIfacePerfCounters(1).frames_rx);
  90. EXPECT_EQ(0, iomgr.getIfacePerfCounters(0).frames_tx);
  91. EXPECT_EQ(0, iomgr.getIfacePerfCounters(1).frames_tx);
  92. }
  93. TEST(CanIOManager, Transmission)
  94. {
  95. using uavcan::CanIOManager;
  96. using uavcan::CanTxQueue;
  97. // Memory
  98. uavcan::PoolAllocator<sizeof(CanTxQueue::Entry) * 4, sizeof(CanTxQueue::Entry)> pool;
  99. // Platform interface
  100. SystemClockMock clockmock;
  101. CanDriverMock driver(2, clockmock);
  102. // IO Manager
  103. CanIOManager iomgr(driver, pool, clockmock, 9999);
  104. ASSERT_EQ(2, iomgr.getNumIfaces());
  105. const int ALL_IFACES_MASK = 3;
  106. const uavcan::CanFrame frames[] = {
  107. makeCanFrame(1, "a0", EXT), makeCanFrame(99, "a1", EXT), makeCanFrame(803, "a2", STD)
  108. };
  109. uavcan::CanIOFlags flags = uavcan::CanIOFlags();
  110. /*
  111. * Simple transmission
  112. */
  113. EXPECT_EQ(2, iomgr.send(frames[0], tsMono(100), tsMono(0), ALL_IFACES_MASK, CanTxQueue::Volatile, flags));
  114. EXPECT_TRUE(driver.ifaces.at(0).matchAndPopTx(frames[0], 100));
  115. EXPECT_TRUE(driver.ifaces.at(1).matchAndPopTx(frames[0], 100));
  116. EXPECT_TRUE(driver.ifaces.at(0).matchPendingTx(frames[0]));
  117. EXPECT_TRUE(driver.ifaces.at(1).matchPendingTx(frames[0]));
  118. EXPECT_EQ(1, iomgr.send(frames[1], tsMono(200), tsMono(100), 2, CanTxQueue::Persistent, flags)); // To #1 only
  119. EXPECT_TRUE(driver.ifaces.at(1).matchAndPopTx(frames[1], 200));
  120. EXPECT_TRUE(driver.ifaces.at(0).matchPendingTx(uavcan::CanFrame()));
  121. EXPECT_TRUE(driver.ifaces.at(1).matchPendingTx(frames[1]));
  122. EXPECT_EQ(0, clockmock.monotonic);
  123. EXPECT_EQ(0, clockmock.utc);
  124. EXPECT_TRUE(driver.ifaces.at(0).tx.empty());
  125. EXPECT_TRUE(driver.ifaces.at(1).tx.empty());
  126. EXPECT_EQ(0, iomgr.getIfacePerfCounters(0).errors);
  127. EXPECT_EQ(0, iomgr.getIfacePerfCounters(1).errors);
  128. /*
  129. * TX Queue basics
  130. */
  131. EXPECT_EQ(0, pool.getNumUsedBlocks());
  132. // Sending to both, #0 blocked
  133. driver.ifaces.at(0).writeable = false;
  134. EXPECT_LT(0, iomgr.send(frames[0], tsMono(201), tsMono(200), ALL_IFACES_MASK, CanTxQueue::Persistent, flags));
  135. EXPECT_TRUE(driver.ifaces.at(1).matchAndPopTx(frames[0], 201));
  136. EXPECT_EQ(200, clockmock.monotonic);
  137. EXPECT_EQ(200, clockmock.utc);
  138. EXPECT_TRUE(driver.ifaces.at(0).tx.empty());
  139. EXPECT_TRUE(driver.ifaces.at(1).tx.empty());
  140. EXPECT_EQ(1, pool.getNumUsedBlocks()); // One frame went into TX queue, and will expire soon
  141. EXPECT_TRUE(driver.ifaces.at(0).matchPendingTx(frames[0])); // This one will persist
  142. EXPECT_TRUE(driver.ifaces.at(1).matchPendingTx(uavcan::CanFrame())); // This will drop off on the second select()
  143. // Sending to both, both blocked
  144. driver.ifaces.at(1).writeable = false;
  145. EXPECT_EQ(0, iomgr.send(frames[1], tsMono(777), tsMono(300), ALL_IFACES_MASK, CanTxQueue::Volatile, flags));
  146. EXPECT_EQ(3, pool.getNumUsedBlocks()); // Total 3 frames in TX queue now
  147. EXPECT_TRUE(driver.ifaces.at(0).matchPendingTx(frames[0])); // Still 0
  148. EXPECT_TRUE(driver.ifaces.at(1).matchPendingTx(frames[1])); // 1!!
  149. // Sending to #0, both blocked
  150. EXPECT_EQ(0, iomgr.send(frames[2], tsMono(888), tsMono(400), 1, CanTxQueue::Persistent, flags));
  151. EXPECT_EQ(400, clockmock.monotonic);
  152. EXPECT_EQ(400, clockmock.utc);
  153. EXPECT_TRUE(driver.ifaces.at(0).tx.empty());
  154. EXPECT_TRUE(driver.ifaces.at(1).tx.empty());
  155. EXPECT_EQ(4, pool.getNumUsedBlocks());
  156. EXPECT_TRUE(driver.ifaces.at(0).matchPendingTx(frames[0]));
  157. EXPECT_TRUE(driver.ifaces.at(1).matchPendingTx(frames[1]));
  158. // At this time TX queues are containing the following data:
  159. // iface 0: frames[0] (EXPIRED), frames[1], frames[2]
  160. // iface 1: frames[1]
  161. // Sending to #1, both writeable
  162. driver.ifaces.at(0).writeable = true;
  163. driver.ifaces.at(1).writeable = true;
  164. // One frame per each iface will be sent:
  165. EXPECT_LT(0, iomgr.send(frames[0], tsMono(999), tsMono(500), 2, CanTxQueue::Persistent, flags));
  166. EXPECT_TRUE(driver.ifaces.at(0).matchAndPopTx(frames[1], 777)); // Note that frame[0] on iface #0 has expired
  167. EXPECT_TRUE(driver.ifaces.at(1).matchAndPopTx(frames[0], 999)); // In different order due to prioritization
  168. EXPECT_TRUE(driver.ifaces.at(0).tx.empty());
  169. EXPECT_TRUE(driver.ifaces.at(1).tx.empty());
  170. EXPECT_TRUE(driver.ifaces.at(0).matchPendingTx(frames[0])); // Expired but still will be reported
  171. EXPECT_TRUE(driver.ifaces.at(1).matchPendingTx(frames[0]));
  172. // Calling receive() to flush the rest two frames
  173. uavcan::CanRxFrame dummy_rx_frame;
  174. EXPECT_EQ(0, iomgr.receive(dummy_rx_frame, tsMono(0), flags));
  175. EXPECT_TRUE(driver.ifaces.at(0).matchAndPopTx(frames[2], 888));
  176. EXPECT_TRUE(driver.ifaces.at(1).matchAndPopTx(frames[1], 777));
  177. ASSERT_EQ(0, flags);
  178. EXPECT_TRUE(driver.ifaces.at(0).matchPendingTx(frames[2]));
  179. EXPECT_TRUE(driver.ifaces.at(1).matchPendingTx(frames[1]));
  180. // Final checks
  181. EXPECT_TRUE(driver.ifaces.at(0).tx.empty());
  182. EXPECT_TRUE(driver.ifaces.at(1).tx.empty());
  183. EXPECT_EQ(0, pool.getNumUsedBlocks()); // Make sure the memory was properly released
  184. EXPECT_EQ(1, iomgr.getIfacePerfCounters(0).errors); // This is because of expired frame[0]
  185. EXPECT_EQ(0, iomgr.getIfacePerfCounters(1).errors);
  186. /*
  187. * TX Queue updates from receive() call
  188. */
  189. driver.ifaces.at(0).writeable = false;
  190. driver.ifaces.at(1).writeable = false;
  191. // Sending 5 frames, one will be rejected
  192. EXPECT_EQ(0, iomgr.send(frames[2], tsMono(2222), tsMono(1000), ALL_IFACES_MASK, CanTxQueue::Persistent, flags));
  193. EXPECT_EQ(0, iomgr.send(frames[0], tsMono(3333), tsMono(1100), 2, CanTxQueue::Persistent, flags));
  194. // One frame kicked here:
  195. EXPECT_EQ(0, iomgr.send(frames[1], tsMono(4444), tsMono(1200), ALL_IFACES_MASK, CanTxQueue::Volatile, flags));
  196. EXPECT_TRUE(driver.ifaces.at(0).matchPendingTx(frames[1]));
  197. EXPECT_TRUE(driver.ifaces.at(1).matchPendingTx(frames[0]));
  198. // State checks
  199. EXPECT_EQ(4, pool.getNumUsedBlocks()); // TX queue is full
  200. EXPECT_EQ(1200, clockmock.monotonic);
  201. EXPECT_EQ(1200, clockmock.utc);
  202. EXPECT_TRUE(driver.ifaces.at(0).tx.empty());
  203. EXPECT_TRUE(driver.ifaces.at(1).tx.empty());
  204. // Preparing the driver mock for receive() call
  205. driver.ifaces.at(0).writeable = true;
  206. driver.ifaces.at(1).writeable = true;
  207. const uavcan::CanFrame rx_frames[] = { makeCanFrame(123, "rx0", STD), makeCanFrame(321, "rx1", EXT) };
  208. driver.ifaces.at(0).pushRx(rx_frames[0]);
  209. driver.ifaces.at(1).pushRx(rx_frames[1]);
  210. // This shall transmit _some_ frames now, at least one per iface (exact number can be changed - it will be OK)
  211. uavcan::CanRxFrame rx_frame;
  212. EXPECT_EQ(1, iomgr.receive(rx_frame, tsMono(0), flags)); // Non-blocking
  213. EXPECT_TRUE(rxFrameEquals(rx_frame, rx_frames[0], 1200, 0));
  214. EXPECT_TRUE(driver.ifaces.at(0).matchAndPopTx(frames[1], 4444));
  215. EXPECT_TRUE(driver.ifaces.at(1).matchAndPopTx(frames[0], 3333));
  216. ASSERT_EQ(0, flags);
  217. EXPECT_TRUE(driver.ifaces.at(0).matchPendingTx(frames[1]));
  218. EXPECT_TRUE(driver.ifaces.at(1).matchPendingTx(frames[0]));
  219. EXPECT_EQ(1, iomgr.receive(rx_frame, tsMono(0), flags));
  220. EXPECT_TRUE(rxFrameEquals(rx_frame, rx_frames[1], 1200, 1));
  221. EXPECT_TRUE(driver.ifaces.at(0).matchAndPopTx(frames[2], 2222));
  222. EXPECT_TRUE(driver.ifaces.at(1).matchAndPopTx(frames[2], 2222)); // Iface #1, frame[1] was rejected (VOLATILE)
  223. ASSERT_EQ(0, flags);
  224. EXPECT_TRUE(driver.ifaces.at(0).matchPendingTx(frames[2]));
  225. EXPECT_TRUE(driver.ifaces.at(1).matchPendingTx(frames[2]));
  226. // State checks
  227. EXPECT_EQ(0, pool.getNumUsedBlocks()); // TX queue is empty
  228. EXPECT_EQ(1200, clockmock.monotonic);
  229. EXPECT_EQ(1200, clockmock.utc);
  230. EXPECT_TRUE(driver.ifaces.at(0).tx.empty());
  231. EXPECT_TRUE(driver.ifaces.at(1).tx.empty());
  232. EXPECT_EQ(1, iomgr.getIfacePerfCounters(0).errors);
  233. EXPECT_EQ(1, iomgr.getIfacePerfCounters(1).errors); // This is because of rejected frame[1]
  234. /*
  235. * Error handling
  236. */
  237. // Select failure
  238. driver.select_failure = true;
  239. EXPECT_EQ(-uavcan::ErrDriver, iomgr.receive(rx_frame, tsMono(2000), flags));
  240. EXPECT_EQ(-uavcan::ErrDriver,
  241. iomgr.send(frames[0], tsMono(2100), tsMono(2000), ALL_IFACES_MASK, CanTxQueue::Volatile, flags));
  242. EXPECT_EQ(1200, clockmock.monotonic);
  243. EXPECT_EQ(1200, clockmock.utc);
  244. ASSERT_EQ(0, flags);
  245. EXPECT_TRUE(driver.ifaces.at(0).matchPendingTx(frames[0]));
  246. EXPECT_TRUE(driver.ifaces.at(1).matchPendingTx(frames[0]));
  247. // Transmission failure
  248. driver.select_failure = false;
  249. driver.ifaces.at(0).writeable = true;
  250. driver.ifaces.at(1).writeable = true;
  251. driver.ifaces.at(0).tx_failure = true;
  252. driver.ifaces.at(1).tx_failure = true;
  253. // Non-blocking - return < 0
  254. EXPECT_GE(0, iomgr.send(frames[0], tsMono(2200), tsMono(0), ALL_IFACES_MASK, CanTxQueue::Persistent, flags));
  255. EXPECT_TRUE(driver.ifaces.at(0).matchPendingTx(frames[0]));
  256. EXPECT_TRUE(driver.ifaces.at(1).matchPendingTx(frames[0]));
  257. ASSERT_EQ(2, pool.getNumUsedBlocks()); // Untransmitted frames will be buffered
  258. // Failure removed - transmission shall proceed
  259. driver.ifaces.at(0).tx_failure = false;
  260. driver.ifaces.at(1).tx_failure = false;
  261. EXPECT_EQ(0, iomgr.receive(rx_frame, tsMono(2500), flags));
  262. EXPECT_TRUE(driver.ifaces.at(0).matchAndPopTx(frames[0], 2200));
  263. EXPECT_TRUE(driver.ifaces.at(1).matchAndPopTx(frames[0], 2200));
  264. EXPECT_EQ(0, pool.getNumUsedBlocks()); // All transmitted
  265. ASSERT_EQ(0, flags);
  266. EXPECT_TRUE(driver.ifaces.at(0).matchPendingTx(uavcan::CanFrame())); // Last call will be receive-only,
  267. EXPECT_TRUE(driver.ifaces.at(1).matchPendingTx(uavcan::CanFrame())); // hence empty TX
  268. /*
  269. * Perf counters
  270. */
  271. EXPECT_EQ(1, iomgr.getIfacePerfCounters(0).frames_rx);
  272. EXPECT_EQ(1, iomgr.getIfacePerfCounters(1).frames_rx);
  273. EXPECT_EQ(6, iomgr.getIfacePerfCounters(0).frames_tx);
  274. EXPECT_EQ(8, iomgr.getIfacePerfCounters(1).frames_tx);
  275. }
  276. TEST(CanIOManager, Loopback)
  277. {
  278. using uavcan::CanIOManager;
  279. using uavcan::CanTxQueue;
  280. using uavcan::CanFrame;
  281. using uavcan::CanRxFrame;
  282. // Memory
  283. uavcan::PoolAllocator<sizeof(CanTxQueue::Entry) * 4, sizeof(CanTxQueue::Entry)> pool;
  284. // Platform interface
  285. SystemClockMock clockmock;
  286. CanDriverMock driver(2, clockmock);
  287. // IO Manager
  288. CanIOManager iomgr(driver, pool, clockmock);
  289. ASSERT_EQ(2, iomgr.getNumIfaces());
  290. CanFrame fr1;
  291. fr1.id = 123 | CanFrame::FlagEFF;
  292. CanFrame fr2;
  293. fr2.id = 456 | CanFrame::FlagEFF;
  294. CanRxFrame rfr1;
  295. CanRxFrame rfr2;
  296. uavcan::CanIOFlags flags = 0;
  297. ASSERT_EQ(1, iomgr.send(fr1, tsMono(1000), tsMono(0), 1, CanTxQueue::Volatile, uavcan::CanIOFlagLoopback));
  298. ASSERT_LE(0, iomgr.receive(rfr1, tsMono(100), flags));
  299. ASSERT_EQ(uavcan::CanIOFlagLoopback, flags);
  300. ASSERT_TRUE(rfr1 == fr1);
  301. flags = 0;
  302. ASSERT_EQ(1, iomgr.send(fr1, tsMono(1000), tsMono(0), 1, CanTxQueue::Volatile, uavcan::CanIOFlagLoopback));
  303. ASSERT_EQ(1, iomgr.send(fr2, tsMono(1000), tsMono(0), 1, CanTxQueue::Persistent, uavcan::CanIOFlagLoopback));
  304. ASSERT_LE(0, iomgr.receive(rfr1, tsMono(100), flags));
  305. ASSERT_EQ(uavcan::CanIOFlagLoopback, flags);
  306. ASSERT_LE(0, iomgr.receive(rfr2, tsMono(100), flags));
  307. ASSERT_EQ(uavcan::CanIOFlagLoopback, flags);
  308. ASSERT_TRUE(rfr1 == fr1);
  309. ASSERT_TRUE(rfr2 == fr2);
  310. /*
  311. * Perf counters
  312. * Loopback frames are not registered as RX
  313. */
  314. EXPECT_EQ(0, iomgr.getIfacePerfCounters(0).frames_rx);
  315. EXPECT_EQ(0, iomgr.getIfacePerfCounters(1).frames_rx);
  316. EXPECT_EQ(3, iomgr.getIfacePerfCounters(0).frames_tx);
  317. EXPECT_EQ(0, iomgr.getIfacePerfCounters(1).frames_tx);
  318. }
  319. TEST(CanIOManager, Size)
  320. {
  321. std::cout << sizeof(uavcan::CanIOManager) << std::endl;
  322. }