global_time_sync_slave.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. /*
  2. * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
  3. */
  4. #include <gtest/gtest.h>
  5. #include <uavcan/node/publisher.hpp>
  6. #include <uavcan/protocol/global_time_sync_slave.hpp>
  7. #include "helpers.hpp"
  8. TEST(GlobalTimeSyncSlave, Basic)
  9. {
  10. InterlinkedTestNodesWithClockMock nodes(64, 65);
  11. SystemClockMock& slave_clock = nodes.clock_a;
  12. SystemClockMock& master_clock = nodes.clock_b;
  13. slave_clock.advance(1000000);
  14. master_clock.advance(1000000);
  15. master_clock.monotonic_auto_advance = slave_clock.monotonic_auto_advance = 1000;
  16. master_clock.preserve_utc = slave_clock.preserve_utc = true;
  17. slave_clock.utc = 0; // Not set yet
  18. uavcan::GlobalDataTypeRegistry::instance().reset();
  19. uavcan::DefaultDataTypeRegistrator<uavcan::protocol::GlobalTimeSync> _reg1;
  20. uavcan::GlobalTimeSyncSlave gtss(nodes.a);
  21. uavcan::Publisher<uavcan::protocol::GlobalTimeSync> gts_pub(nodes.b);
  22. ASSERT_LE(0, gtss.start());
  23. ASSERT_FALSE(gtss.isActive());
  24. ASSERT_FALSE(gtss.getMasterNodeID().isValid());
  25. /*
  26. * Empty broadcast
  27. * The slave must only register the timestamp and adjust nothing
  28. */
  29. uavcan::protocol::GlobalTimeSync gts;
  30. gts.previous_transmission_timestamp_usec = 0;
  31. gts_pub.broadcast(gts);
  32. gts.previous_transmission_timestamp_usec = master_clock.utc;
  33. nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(10));
  34. ASSERT_EQ(0, slave_clock.utc);
  35. ASSERT_EQ(1000000, master_clock.utc);
  36. std::cout << "Master mono=" << master_clock.monotonic << " utc=" << master_clock.utc << std::endl;
  37. std::cout << "Slave mono=" << slave_clock.monotonic << " utc=" << slave_clock.utc << std::endl;
  38. ASSERT_FALSE(gtss.isActive());
  39. ASSERT_FALSE(gtss.getMasterNodeID().isValid());
  40. /*
  41. * Follow-up broadcast with proper time
  42. * Slave must adjust now
  43. */
  44. gts_pub.broadcast(gts);
  45. gts.previous_transmission_timestamp_usec = master_clock.utc;
  46. nodes.spinBoth(uavcan::MonotonicDuration());
  47. ASSERT_EQ(1000000, slave_clock.utc);
  48. ASSERT_EQ(1000000, master_clock.utc);
  49. std::cout << "Master mono=" << master_clock.monotonic << " utc=" << master_clock.utc << std::endl;
  50. std::cout << "Slave mono=" << slave_clock.monotonic << " utc=" << slave_clock.utc << std::endl;
  51. master_clock.utc += 1000000;
  52. slave_clock.utc += 1000000;
  53. ASSERT_TRUE(gtss.isActive());
  54. ASSERT_EQ(nodes.b.getNodeID(), gtss.getMasterNodeID());
  55. /*
  56. * Next follow-up, slave is synchronized now
  57. * Will update
  58. */
  59. gts_pub.broadcast(gts);
  60. gts.previous_transmission_timestamp_usec = master_clock.utc;
  61. nodes.spinBoth(uavcan::MonotonicDuration());
  62. ASSERT_EQ(2000000, slave_clock.utc);
  63. ASSERT_EQ(2000000, master_clock.utc);
  64. master_clock.utc += 1000000;
  65. slave_clock.utc += 1000000;
  66. ASSERT_TRUE(gtss.isActive());
  67. ASSERT_EQ(nodes.b.getNodeID(), gtss.getMasterNodeID());
  68. /*
  69. * Next follow-up, slave is synchronized now
  70. * Will adjust
  71. */
  72. gts_pub.broadcast(gts);
  73. gts.previous_transmission_timestamp_usec = master_clock.utc;
  74. nodes.spinBoth(uavcan::MonotonicDuration());
  75. ASSERT_EQ(3000000, slave_clock.utc);
  76. ASSERT_EQ(3000000, master_clock.utc);
  77. master_clock.utc += 1000000;
  78. slave_clock.utc += 1000000;
  79. ASSERT_EQ(4000000, slave_clock.utc);
  80. ASSERT_EQ(4000000, master_clock.utc);
  81. ASSERT_TRUE(gtss.isActive());
  82. ASSERT_EQ(nodes.b.getNodeID(), gtss.getMasterNodeID());
  83. /*
  84. * Another master
  85. * This one has higher priority, so it will be preferred
  86. */
  87. SystemClockMock master2_clock(100);
  88. master2_clock.monotonic_auto_advance = 1000;
  89. master2_clock.preserve_utc = true;
  90. PairableCanDriver master2_can(master2_clock);
  91. master2_can.others.insert(&nodes.can_a);
  92. TestNode master2_node(master2_can, master2_clock, 8);
  93. uavcan::Publisher<uavcan::protocol::GlobalTimeSync> gts_pub2(master2_node);
  94. /*
  95. * Update step, no adjustment yet
  96. */
  97. gts.previous_transmission_timestamp_usec = 0;
  98. gts_pub2.broadcast(gts);
  99. gts.previous_transmission_timestamp_usec = master2_clock.utc;
  100. nodes.spinBoth(uavcan::MonotonicDuration());
  101. ASSERT_EQ(4000000, slave_clock.utc);
  102. ASSERT_EQ(100, master2_clock.utc);
  103. master2_clock.utc += 1000000;
  104. ASSERT_TRUE(gtss.isActive());
  105. ASSERT_EQ(master2_node.getNodeID(), gtss.getMasterNodeID());
  106. /*
  107. * Adjustment
  108. */
  109. gts_pub2.broadcast(gts);
  110. nodes.spinBoth(uavcan::MonotonicDuration());
  111. ASSERT_EQ(100, slave_clock.utc);
  112. ASSERT_TRUE(gtss.isActive());
  113. ASSERT_EQ(master2_node.getNodeID(), gtss.getMasterNodeID());
  114. /*
  115. * Another master will be ignored now
  116. */
  117. gts.previous_transmission_timestamp_usec = 99999999;
  118. // Update
  119. gts_pub.broadcast(gts);
  120. nodes.spinBoth(uavcan::MonotonicDuration());
  121. ASSERT_EQ(100, slave_clock.utc);
  122. // Adjust
  123. gts_pub.broadcast(gts);
  124. nodes.spinBoth(uavcan::MonotonicDuration());
  125. ASSERT_EQ(100, slave_clock.utc);
  126. ASSERT_TRUE(gtss.isActive());
  127. ASSERT_EQ(master2_node.getNodeID(), gtss.getMasterNodeID());
  128. /*
  129. * Timeout
  130. */
  131. slave_clock.advance(100000000);
  132. ASSERT_FALSE(gtss.isActive());
  133. ASSERT_FALSE(gtss.getMasterNodeID().isValid());
  134. }
  135. #if !defined(BYTE_ORDER) || !defined(LITTLE_ENDIAN) || (BYTE_ORDER != LITTLE_ENDIAN)
  136. # error "This test cannot be executed on this platform"
  137. #endif
  138. static uavcan::Frame makeSyncMsg(uavcan::uint64_t usec, uavcan::NodeID snid, uavcan::TransferID tid)
  139. {
  140. uavcan::Frame frame(uavcan::protocol::GlobalTimeSync::DefaultDataTypeID, uavcan::TransferTypeMessageBroadcast,
  141. snid, uavcan::NodeID::Broadcast, tid);
  142. frame.setStartOfTransfer(true);
  143. frame.setEndOfTransfer(true);
  144. EXPECT_EQ(7, frame.setPayload(reinterpret_cast<uint8_t*>(&usec), 7)); // Assuming little endian!!!
  145. return frame;
  146. }
  147. static void broadcastSyncMsg(CanIfaceMock& iface, uavcan::uint64_t usec, uavcan::NodeID snid, uavcan::TransferID tid)
  148. {
  149. const uavcan::Frame frame = makeSyncMsg(usec, snid, tid);
  150. uavcan::CanFrame can_frame;
  151. ASSERT_TRUE(frame.compile(can_frame));
  152. iface.pushRx(can_frame);
  153. }
  154. TEST(GlobalTimeSyncSlave, Validation)
  155. {
  156. SystemClockMock slave_clock;
  157. slave_clock.monotonic = 1000000;
  158. slave_clock.preserve_utc = true;
  159. CanDriverMock slave_can(3, slave_clock);
  160. for (uint8_t i = 0; i < slave_can.getNumIfaces(); i++)
  161. {
  162. slave_can.ifaces.at(i).enable_utc_timestamping = true;
  163. }
  164. TestNode node(slave_can, slave_clock, 64);
  165. uavcan::GlobalTimeSyncSlave gtss(node);
  166. uavcan::Publisher<uavcan::protocol::GlobalTimeSync> gts_pub(node);
  167. ASSERT_LE(0, gtss.start());
  168. ASSERT_FALSE(gtss.isActive());
  169. ASSERT_FALSE(gtss.getMasterNodeID().isValid());
  170. ASSERT_EQ(0, slave_clock.utc);
  171. /*
  172. * Update/adjust/update
  173. */
  174. broadcastSyncMsg(slave_can.ifaces.at(0), 0, 8, 0); // Locked on this
  175. broadcastSyncMsg(slave_can.ifaces.at(1), 2000, 8, 0); // Ignored
  176. ASSERT_LE(0, node.spin(uavcan::MonotonicDuration::fromMSec(10)));
  177. broadcastSyncMsg(slave_can.ifaces.at(0), 1000, 8, 1); // Adjust 1000 ahead
  178. broadcastSyncMsg(slave_can.ifaces.at(1), 2000, 8, 1); // Ignored
  179. ASSERT_LE(0, node.spin(uavcan::MonotonicDuration::fromMSec(10)));
  180. ASSERT_TRUE(gtss.isActive());
  181. ASSERT_EQ(8, gtss.getMasterNodeID().get());
  182. ASSERT_EQ(1000, slave_clock.utc);
  183. broadcastSyncMsg(slave_can.ifaces.at(0), 2000, 8, 2); // Update
  184. ASSERT_LE(0, node.spin(uavcan::MonotonicDuration::fromMSec(10)));
  185. ASSERT_EQ(1000, slave_clock.utc);
  186. std::cout << slave_clock.monotonic << std::endl;
  187. /*
  188. * TID jump simulates a frame loss
  189. */
  190. broadcastSyncMsg(slave_can.ifaces.at(0), 3000, 8, 4); // Adjustment skipped - expected TID 3, update instead
  191. ASSERT_LE(0, node.spin(uavcan::MonotonicDuration::fromMSec(10)));
  192. ASSERT_TRUE(gtss.isActive());
  193. ASSERT_EQ(8, gtss.getMasterNodeID().get());
  194. ASSERT_EQ(1000, slave_clock.utc);
  195. std::cout << slave_clock.monotonic << std::endl;
  196. /*
  197. * Valid adjustment - continuing from TID 4
  198. */
  199. broadcastSyncMsg(slave_can.ifaces.at(0), 3000, 8, 5); // Slave UTC was 1000, master reports 3000 --> shift ahead
  200. broadcastSyncMsg(slave_can.ifaces.at(1), 2000, 8, 5);
  201. ASSERT_LE(0, node.spin(uavcan::MonotonicDuration::fromMSec(10)));
  202. ASSERT_TRUE(gtss.isActive());
  203. ASSERT_EQ(8, gtss.getMasterNodeID().get());
  204. ASSERT_EQ(3000, slave_clock.utc);
  205. std::cout << slave_clock.monotonic << std::endl;
  206. /*
  207. * Update, then very long delay with correct TID
  208. */
  209. broadcastSyncMsg(slave_can.ifaces.at(0), 2000, 8, 6); // Valid update, slave UTC is 3000
  210. broadcastSyncMsg(slave_can.ifaces.at(1), 2000, 8, 6);
  211. ASSERT_LE(0, node.spin(uavcan::MonotonicDuration::fromMSec(10)));
  212. slave_clock.monotonic += 5000000;
  213. broadcastSyncMsg(slave_can.ifaces.at(0), 5000, 8, 7); // Adjustment skipped
  214. broadcastSyncMsg(slave_can.ifaces.at(1), 2000, 8, 7);
  215. ASSERT_LE(0, node.spin(uavcan::MonotonicDuration::fromMSec(10)));
  216. broadcastSyncMsg(slave_can.ifaces.at(0), 5000, 8, 8); // Valid adjustment now
  217. broadcastSyncMsg(slave_can.ifaces.at(1), 2000, 8, 8);
  218. ASSERT_LE(0, node.spin(uavcan::MonotonicDuration::fromMSec(10)));
  219. ASSERT_TRUE(gtss.isActive());
  220. ASSERT_EQ(8, gtss.getMasterNodeID().get());
  221. ASSERT_EQ(5000, slave_clock.utc);
  222. std::cout << slave_clock.monotonic << std::endl;
  223. }
  224. TEST(GlobalTimeSyncSlave, Suppression)
  225. {
  226. SystemClockMock slave_clock;
  227. slave_clock.monotonic = 1000000;
  228. slave_clock.preserve_utc = true;
  229. CanDriverMock slave_can(3, slave_clock);
  230. for (uint8_t i = 0; i < slave_can.getNumIfaces(); i++)
  231. {
  232. slave_can.ifaces.at(i).enable_utc_timestamping = true;
  233. }
  234. TestNode node(slave_can, slave_clock, 64);
  235. uavcan::GlobalTimeSyncSlave gtss(node);
  236. uavcan::Publisher<uavcan::protocol::GlobalTimeSync> gts_pub(node);
  237. ASSERT_LE(0, gtss.start());
  238. ASSERT_EQ(0, slave_clock.utc);
  239. gtss.suppress(true);
  240. broadcastSyncMsg(slave_can.ifaces.at(0), 0, 8, 0); // Locked on this
  241. broadcastSyncMsg(slave_can.ifaces.at(1), 2000, 8, 0); // Ignored
  242. ASSERT_LE(0, node.spin(uavcan::MonotonicDuration::fromMSec(10)));
  243. broadcastSyncMsg(slave_can.ifaces.at(0), 1000, 8, 1); // Adjust 1000 ahead
  244. broadcastSyncMsg(slave_can.ifaces.at(1), 2000, 8, 1); // Ignored
  245. ASSERT_LE(0, node.spin(uavcan::MonotonicDuration::fromMSec(10)));
  246. ASSERT_TRUE(gtss.isActive());
  247. ASSERT_EQ(8, gtss.getMasterNodeID().get());
  248. ASSERT_EQ(0, slave_clock.utc); // The clock shall not be asjusted
  249. }