can.hpp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. /*
  2. * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
  3. */
  4. #pragma once
  5. #include <cassert>
  6. #include <queue>
  7. #include <vector>
  8. #include <gtest/gtest.h>
  9. #include <uavcan/transport/can_io.hpp>
  10. #include <uavcan/transport/frame.hpp>
  11. #include <uavcan/driver/can.hpp>
  12. #include <uavcan/driver/system_clock.hpp>
  13. #include "../../clock.hpp"
  14. class CanIfaceMock : public uavcan::ICanIface
  15. {
  16. public:
  17. struct FrameWithTime
  18. {
  19. uavcan::CanFrame frame;
  20. uavcan::MonotonicTime time;
  21. uavcan::UtcTime time_utc;
  22. uavcan::CanIOFlags flags;
  23. FrameWithTime(const uavcan::CanFrame& frame, uavcan::MonotonicTime time)
  24. : frame(frame)
  25. , time(time)
  26. , flags(0)
  27. { }
  28. FrameWithTime(const uavcan::CanFrame& frame, uavcan::MonotonicTime time, uavcan::UtcTime time_utc)
  29. : frame(frame)
  30. , time(time)
  31. , time_utc(time_utc)
  32. , flags(0)
  33. { }
  34. FrameWithTime(const uavcan::CanFrame& frame, uint64_t time_usec)
  35. : frame(frame)
  36. , time(uavcan::MonotonicTime::fromUSec(time_usec))
  37. , flags(0)
  38. { }
  39. };
  40. std::queue<FrameWithTime> tx; ///< Queue of outgoing frames (bus <-- library)
  41. std::queue<FrameWithTime> rx; ///< Queue of incoming frames (bus --> library)
  42. std::queue<FrameWithTime> loopback; ///< Loopback
  43. bool writeable;
  44. bool tx_failure;
  45. bool rx_failure;
  46. uint64_t num_errors;
  47. uavcan::ISystemClock& iclock;
  48. bool enable_utc_timestamping;
  49. uavcan::CanFrame pending_tx;
  50. CanIfaceMock(uavcan::ISystemClock& iclock)
  51. : writeable(true)
  52. , tx_failure(false)
  53. , rx_failure(false)
  54. , num_errors(0)
  55. , iclock(iclock)
  56. , enable_utc_timestamping(false)
  57. { }
  58. void pushRx(const uavcan::CanFrame& frame)
  59. {
  60. rx.push(FrameWithTime(frame, iclock.getMonotonic()));
  61. }
  62. void pushRx(const uavcan::RxFrame& frame)
  63. {
  64. uavcan::CanFrame can_frame;
  65. EXPECT_TRUE(frame.compile(can_frame));
  66. rx.push(FrameWithTime(can_frame, frame.getMonotonicTimestamp(), frame.getUtcTimestamp()));
  67. }
  68. bool matchAndPopTx(const uavcan::CanFrame& frame, uavcan::MonotonicTime tx_deadline)
  69. {
  70. if (tx.empty())
  71. {
  72. std::cout << "Tx buffer is empty" << std::endl;
  73. return false;
  74. }
  75. const FrameWithTime frame_time = tx.front();
  76. tx.pop();
  77. return (frame_time.frame == frame) && (frame_time.time == tx_deadline);
  78. }
  79. bool matchPendingTx(const uavcan::CanFrame& frame) const
  80. {
  81. if (pending_tx != frame)
  82. {
  83. std::cout << "Pending TX mismatch: \n"
  84. << " Expected: " << frame.toString(uavcan::CanFrame::StrAligned) << "\n"
  85. << " Actual: " << pending_tx.toString(uavcan::CanFrame::StrAligned) << std::endl;
  86. }
  87. return pending_tx == frame;
  88. }
  89. bool matchAndPopTx(const uavcan::CanFrame& frame, uint64_t tx_deadline_usec)
  90. {
  91. return matchAndPopTx(frame, uavcan::MonotonicTime::fromUSec(tx_deadline_usec));
  92. }
  93. uavcan::CanFrame popTxFrame()
  94. {
  95. if (tx.empty())
  96. {
  97. std::cout << "Tx buffer is empty" << std::endl;
  98. std::abort();
  99. }
  100. const FrameWithTime frame_time = tx.front();
  101. tx.pop();
  102. return frame_time.frame;
  103. }
  104. virtual uavcan::int16_t send(const uavcan::CanFrame& frame, uavcan::MonotonicTime tx_deadline,
  105. uavcan::CanIOFlags flags)
  106. {
  107. assert(this);
  108. EXPECT_TRUE(writeable); // Shall never be called when not writeable
  109. if (tx_failure)
  110. {
  111. return -1;
  112. }
  113. if (!writeable)
  114. {
  115. return 0;
  116. }
  117. tx.push(FrameWithTime(frame, tx_deadline));
  118. tx.back().flags = flags;
  119. if (flags & uavcan::CanIOFlagLoopback)
  120. {
  121. loopback.push(FrameWithTime(frame, iclock.getMonotonic()));
  122. }
  123. return 1;
  124. }
  125. virtual uavcan::int16_t receive(uavcan::CanFrame& out_frame, uavcan::MonotonicTime& out_ts_monotonic,
  126. uavcan::UtcTime& out_ts_utc, uavcan::CanIOFlags& out_flags)
  127. {
  128. assert(this);
  129. if (loopback.empty())
  130. {
  131. EXPECT_TRUE(rx.size()); // Shall never be called when not readable
  132. if (rx_failure)
  133. {
  134. return -1;
  135. }
  136. if (rx.empty())
  137. {
  138. return 0;
  139. }
  140. const FrameWithTime frame = rx.front();
  141. rx.pop();
  142. out_frame = frame.frame;
  143. out_ts_monotonic = frame.time;
  144. out_ts_utc = frame.time_utc;
  145. out_flags = frame.flags;
  146. }
  147. else
  148. {
  149. out_flags |= uavcan::CanIOFlagLoopback;
  150. const FrameWithTime frame = loopback.front();
  151. loopback.pop();
  152. out_frame = frame.frame;
  153. out_ts_monotonic = frame.time;
  154. out_ts_utc = frame.time_utc;
  155. }
  156. // Let's just all pretend that this code is autogenerated, instead of being carefully designed by a human.
  157. if (out_ts_utc.isZero())
  158. {
  159. out_ts_utc = enable_utc_timestamping ? iclock.getUtc() : uavcan::UtcTime();
  160. }
  161. return 1;
  162. }
  163. // cppcheck-suppress unusedFunction
  164. // cppcheck-suppress functionConst
  165. virtual uavcan::int16_t configureFilters(const uavcan::CanFilterConfig*, uavcan::uint16_t) { return 0; }
  166. // cppcheck-suppress unusedFunction
  167. virtual uavcan::uint16_t getNumFilters() const { return 4; } // decrease number of HW_filters from 9 to 4
  168. virtual uavcan::uint64_t getErrorCount() const { return num_errors; }
  169. };
  170. class CanDriverMock : public uavcan::ICanDriver
  171. {
  172. public:
  173. std::vector<CanIfaceMock> ifaces;
  174. uavcan::ISystemClock& iclock;
  175. bool select_failure;
  176. CanDriverMock(unsigned num_ifaces, uavcan::ISystemClock& iclock)
  177. : ifaces(num_ifaces, CanIfaceMock(iclock))
  178. , iclock(iclock)
  179. , select_failure(false)
  180. { }
  181. void pushRxToAllIfaces(const uavcan::CanFrame& can_frame)
  182. {
  183. for (uint8_t i = 0; i < getNumIfaces(); i++)
  184. {
  185. ifaces.at(i).pushRx(can_frame);
  186. }
  187. }
  188. virtual uavcan::int16_t select(uavcan::CanSelectMasks& inout_masks,
  189. const uavcan::CanFrame* (& pending_tx)[uavcan::MaxCanIfaces],
  190. uavcan::MonotonicTime deadline)
  191. {
  192. assert(this);
  193. //std::cout << "Write/read masks: " << inout_write_iface_mask << "/" << inout_read_iface_mask << std::endl;
  194. for (unsigned i = 0; i < ifaces.size(); i++)
  195. {
  196. ifaces.at(i).pending_tx = (pending_tx[i] == UAVCAN_NULLPTR) ? uavcan::CanFrame() : *pending_tx[i];
  197. }
  198. if (select_failure)
  199. {
  200. return -1;
  201. }
  202. const uavcan::uint8_t valid_iface_mask = uavcan::uint8_t((1 << getNumIfaces()) - 1);
  203. EXPECT_FALSE(inout_masks.write & ~valid_iface_mask);
  204. EXPECT_FALSE(inout_masks.read & ~valid_iface_mask);
  205. uavcan::uint8_t out_write_mask = 0;
  206. uavcan::uint8_t out_read_mask = 0;
  207. for (unsigned i = 0; i < getNumIfaces(); i++)
  208. {
  209. const uavcan::uint8_t mask = uavcan::uint8_t(1 << i);
  210. if ((inout_masks.write & mask) && ifaces.at(i).writeable)
  211. {
  212. out_write_mask |= mask;
  213. }
  214. if ((inout_masks.read & mask) && (ifaces.at(i).rx.size() || ifaces.at(i).loopback.size()))
  215. {
  216. out_read_mask |= mask;
  217. }
  218. }
  219. inout_masks.write = out_write_mask;
  220. inout_masks.read = out_read_mask;
  221. if ((out_write_mask | out_read_mask) == 0)
  222. {
  223. const uavcan::MonotonicTime ts = iclock.getMonotonic();
  224. const uavcan::MonotonicDuration diff = deadline - ts;
  225. SystemClockMock* const mock = dynamic_cast<SystemClockMock*>(&iclock);
  226. if (mock)
  227. {
  228. if (diff.isPositive())
  229. {
  230. mock->advance(uint64_t(diff.toUSec())); // Emulating timeout
  231. }
  232. }
  233. else
  234. {
  235. if (diff.isPositive())
  236. {
  237. usleep(unsigned(diff.toUSec()));
  238. }
  239. }
  240. return 0;
  241. }
  242. return 1; // This value is not being checked anyway, it just has to be greater than zero
  243. }
  244. virtual uavcan::ICanIface* getIface(uavcan::uint8_t iface_index) { return &ifaces.at(iface_index); }
  245. virtual const uavcan::ICanIface* getIface(uavcan::uint8_t iface_index) const { return &ifaces.at(iface_index); }
  246. virtual uavcan::uint8_t getNumIfaces() const { return uavcan::uint8_t(ifaces.size()); }
  247. };
  248. enum FrameType { STD, EXT };
  249. inline uavcan::CanFrame makeCanFrame(uint32_t id, const std::string& str_data, FrameType type)
  250. {
  251. id |= (type == EXT) ? uavcan::CanFrame::FlagEFF : 0;
  252. return uavcan::CanFrame(id, reinterpret_cast<const uint8_t*>(str_data.c_str()), uavcan::uint8_t(str_data.length()));
  253. }