DroneCAN.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510
  1. /*
  2. DroneCAN class for handling OpenDroneID messages
  3. */
  4. #include <Arduino.h>
  5. #include "version.h"
  6. #include <time.h>
  7. #include "DroneCAN.h"
  8. #include <canard.h>
  9. #include <uavcan.protocol.NodeStatus.h>
  10. #include <uavcan.protocol.GetNodeInfo.h>
  11. #include <uavcan.protocol.RestartNode.h>
  12. #include <uavcan.protocol.dynamic_node_id.Allocation.h>
  13. #include <dronecan.remoteid.BasicID.h>
  14. #include <dronecan.remoteid.Location.h>
  15. #include <dronecan.remoteid.SelfID.h>
  16. #include <dronecan.remoteid.System.h>
  17. #include <dronecan.remoteid.OperatorID.h>
  18. #include <dronecan.remoteid.ArmStatus.h>
  19. #define BOARD_ID 10001
  20. #define CAN_APP_NODE_NAME "ArduPilot RemoteIDModule"
  21. #define CAN_DEFAULT_NODE_ID 0 // use DNA
  22. #define UNUSED(x) (void)(x)
  23. // constructor
  24. DroneCAN::DroneCAN()
  25. {}
  26. static void onTransferReceived_trampoline(CanardInstance* ins, CanardRxTransfer* transfer);
  27. static bool shouldAcceptTransfer_trampoline(const CanardInstance* ins, uint64_t* out_data_type_signature, uint16_t data_type_id,
  28. CanardTransferType transfer_type,
  29. uint8_t source_node_id);
  30. // decoded messages
  31. void DroneCAN::init(void)
  32. {
  33. can_driver.init(1000000);
  34. canardInit(&canard, (uint8_t *)canard_memory_pool, sizeof(canard_memory_pool),
  35. onTransferReceived_trampoline, shouldAcceptTransfer_trampoline, NULL);
  36. #if CAN_DEFAULT_NODE_ID
  37. canardSetLocalNodeID(&canard, CAN_DEFAULT_NODE_ID);
  38. #endif
  39. canard.user_reference = (void*)this;
  40. }
  41. void DroneCAN::update(void)
  42. {
  43. if (do_DNA()) {
  44. const uint32_t now_ms = millis();
  45. if (now_ms - last_node_status_ms >= 1000) {
  46. last_node_status_ms = now_ms;
  47. node_status_send();
  48. arm_status_send();
  49. }
  50. }
  51. processTx();
  52. processRx();
  53. }
  54. void DroneCAN::node_status_send(void)
  55. {
  56. uint8_t buffer[UAVCAN_PROTOCOL_NODESTATUS_MAX_SIZE];
  57. node_status.uptime_sec = millis() / 1000U;
  58. node_status.vendor_specific_status_code = 0;
  59. const uint16_t len = uavcan_protocol_NodeStatus_encode(&node_status, buffer);
  60. static uint8_t tx_id;
  61. Serial.printf("sending NodeStatus len=%u\n", unsigned(len));
  62. canardBroadcast(&canard,
  63. UAVCAN_PROTOCOL_NODESTATUS_SIGNATURE,
  64. UAVCAN_PROTOCOL_NODESTATUS_ID,
  65. &tx_id,
  66. CANARD_TRANSFER_PRIORITY_LOW,
  67. (void*)buffer,
  68. len);
  69. }
  70. void DroneCAN::arm_status_send(void)
  71. {
  72. uint8_t buffer[DRONECAN_REMOTEID_ARMSTATUS_MAX_SIZE];
  73. dronecan_remoteid_ArmStatus arm_status {};
  74. const uint32_t max_age_location_ms = 3000;
  75. const uint32_t max_age_other_ms = 22000;
  76. const uint32_t now_ms = millis();
  77. const char *reason = "";
  78. arm_status.status = DRONECAN_REMOTEID_ARMSTATUS_ODID_ARM_STATUS_FAIL_GENERIC;
  79. if (last_location_ms == 0 || now_ms - last_location_ms > max_age_location_ms) {
  80. reason = "missing location message";
  81. } else if (last_basic_id_ms == 0 || now_ms - last_basic_id_ms > max_age_other_ms) {
  82. reason = "missing basic_id message";
  83. } else if (last_self_id_ms == 0 || now_ms - last_self_id_ms > max_age_other_ms) {
  84. reason = "missing self_id message";
  85. } else if (last_operator_id_ms == 0 || now_ms - last_operator_id_ms > max_age_other_ms) {
  86. reason = "missing operator_id message";
  87. } else if (last_system_ms == 0 || now_ms - last_system_ms > max_age_other_ms) {
  88. reason = "missing system message";
  89. } else if (msg_Location.latitude == 0 && msg_Location.longitude == 0) {
  90. reason = "Bad location";
  91. } else if (msg_System.operator_latitude == 0 && msg_System.operator_longitude == 0) {
  92. reason = "Bad operator location";
  93. } else {
  94. arm_status.status = DRONECAN_REMOTEID_ARMSTATUS_ODID_ARM_STATUS_GOOD_TO_ARM;
  95. }
  96. arm_status.error.len = strlen(reason);
  97. strncpy((char*)arm_status.error.data, reason, sizeof(arm_status.error.data));
  98. const uint16_t len = dronecan_remoteid_ArmStatus_encode(&arm_status, buffer);
  99. static uint8_t tx_id;
  100. canardBroadcast(&canard,
  101. DRONECAN_REMOTEID_ARMSTATUS_SIGNATURE,
  102. DRONECAN_REMOTEID_ARMSTATUS_ID,
  103. &tx_id,
  104. CANARD_TRANSFER_PRIORITY_LOW,
  105. (void*)buffer,
  106. len);
  107. }
  108. void DroneCAN::onTransferReceived(CanardInstance* ins,
  109. CanardRxTransfer* transfer)
  110. {
  111. if (canardGetLocalNodeID(ins) == CANARD_BROADCAST_NODE_ID) {
  112. if (transfer->transfer_type == CanardTransferTypeBroadcast &&
  113. transfer->data_type_id == UAVCAN_PROTOCOL_DYNAMIC_NODE_ID_ALLOCATION_ID) {
  114. handle_allocation_response(ins, transfer);
  115. }
  116. return;
  117. }
  118. const uint32_t now_ms = millis();
  119. switch (transfer->data_type_id) {
  120. case UAVCAN_PROTOCOL_GETNODEINFO_ID:
  121. handle_get_node_info(ins, transfer);
  122. break;
  123. case UAVCAN_PROTOCOL_RESTARTNODE_ID:
  124. Serial.printf("RestartNode\n");
  125. delay(20);
  126. esp_restart();
  127. break;
  128. case DRONECAN_REMOTEID_BASICID_ID:
  129. Serial.printf("Got BasicID\n");
  130. dronecan_remoteid_BasicID_decode(transfer, &msg_BasicID);
  131. last_basic_id_ms = now_ms;
  132. break;
  133. case DRONECAN_REMOTEID_LOCATION_ID:
  134. Serial.printf("Got Location\n");
  135. dronecan_remoteid_Location_decode(transfer, &msg_Location);
  136. last_location_ms = now_ms;
  137. break;
  138. case DRONECAN_REMOTEID_SELFID_ID:
  139. Serial.printf("Got SelfID\n");
  140. dronecan_remoteid_SelfID_decode(transfer, &msg_SelfID);
  141. last_self_id_ms = now_ms;
  142. break;
  143. case DRONECAN_REMOTEID_SYSTEM_ID:
  144. Serial.printf("Got System\n");
  145. dronecan_remoteid_System_decode(transfer, &msg_System);
  146. last_system_ms = now_ms;
  147. break;
  148. case DRONECAN_REMOTEID_OPERATORID_ID:
  149. Serial.printf("Got OperatorID\n");
  150. dronecan_remoteid_OperatorID_decode(transfer, &msg_OperatorID);
  151. last_operator_id_ms = now_ms;
  152. break;
  153. default:
  154. //Serial.printf("reject %u\n", transfer->data_type_id);
  155. break;
  156. }
  157. }
  158. bool DroneCAN::shouldAcceptTransfer(const CanardInstance* ins,
  159. uint64_t* out_data_type_signature,
  160. uint16_t data_type_id,
  161. CanardTransferType transfer_type,
  162. uint8_t source_node_id)
  163. {
  164. if (canardGetLocalNodeID(ins) == CANARD_BROADCAST_NODE_ID &&
  165. data_type_id == UAVCAN_PROTOCOL_DYNAMIC_NODE_ID_ALLOCATION_ID) {
  166. *out_data_type_signature = UAVCAN_PROTOCOL_DYNAMIC_NODE_ID_ALLOCATION_SIGNATURE;
  167. return true;
  168. }
  169. #define ACCEPT_ID(name) case name ## _ID: *out_data_type_signature = name ## _SIGNATURE; return true
  170. switch (data_type_id) {
  171. ACCEPT_ID(UAVCAN_PROTOCOL_GETNODEINFO);
  172. ACCEPT_ID(UAVCAN_PROTOCOL_RESTARTNODE);
  173. ACCEPT_ID(DRONECAN_REMOTEID_BASICID);
  174. ACCEPT_ID(DRONECAN_REMOTEID_LOCATION);
  175. ACCEPT_ID(DRONECAN_REMOTEID_SELFID);
  176. ACCEPT_ID(DRONECAN_REMOTEID_OPERATORID);
  177. ACCEPT_ID(DRONECAN_REMOTEID_SYSTEM);
  178. return true;
  179. }
  180. //Serial.printf("%u: reject ID 0x%x\n", millis(), data_type_id);
  181. return false;
  182. }
  183. static void onTransferReceived_trampoline(CanardInstance* ins,
  184. CanardRxTransfer* transfer)
  185. {
  186. DroneCAN *dc = (DroneCAN *)ins->user_reference;
  187. dc->onTransferReceived(ins, transfer);
  188. }
  189. /*
  190. see if we want to process this packet
  191. */
  192. static bool shouldAcceptTransfer_trampoline(const CanardInstance* ins,
  193. uint64_t* out_data_type_signature,
  194. uint16_t data_type_id,
  195. CanardTransferType transfer_type,
  196. uint8_t source_node_id)
  197. {
  198. DroneCAN *dc = (DroneCAN *)ins->user_reference;
  199. return dc->shouldAcceptTransfer(ins, out_data_type_signature,
  200. data_type_id,
  201. transfer_type,
  202. source_node_id);
  203. }
  204. void DroneCAN::processTx(void)
  205. {
  206. for (const CanardCANFrame* txf = NULL; (txf = canardPeekTxQueue(&canard)) != NULL;) {
  207. CANFrame txmsg {};
  208. txmsg.dlc = CANFrame::dataLengthToDlc(txf->data_len);
  209. memcpy(txmsg.data, txf->data, txf->data_len);
  210. txmsg.id = (txf->id | CANFrame::FlagEFF);
  211. // push message with 1s timeout
  212. if (can_driver.send(txmsg)) {
  213. canardPopTxQueue(&canard);
  214. tx_fail_count = 0;
  215. } else {
  216. if (tx_fail_count < 8) {
  217. tx_fail_count++;
  218. } else {
  219. canardPopTxQueue(&canard);
  220. }
  221. break;
  222. }
  223. }
  224. }
  225. void DroneCAN::processRx(void)
  226. {
  227. CANFrame rxmsg;
  228. while (can_driver.receive(rxmsg)) {
  229. CanardCANFrame rx_frame {};
  230. uint64_t timestamp = micros64();
  231. rx_frame.data_len = CANFrame::dlcToDataLength(rxmsg.dlc);
  232. memcpy(rx_frame.data, rxmsg.data, rx_frame.data_len);
  233. rx_frame.id = rxmsg.id;
  234. int err = canardHandleRxFrame(&canard, &rx_frame, timestamp);
  235. #if 0
  236. Serial.printf("%u: FX %08x %02x %02x %02x %02x %02x %02x %02x %02x (%u) -> %d\n",
  237. millis(),
  238. rx_frame.id,
  239. rxmsg.data[0], rxmsg.data[1], rxmsg.data[2], rxmsg.data[3],
  240. rxmsg.data[4], rxmsg.data[5], rxmsg.data[6], rxmsg.data[7],
  241. rx_frame.data_len,
  242. err);
  243. #else
  244. UNUSED(err);
  245. #endif
  246. }
  247. }
  248. CANFrame::CANFrame(uint32_t can_id, const uint8_t* can_data, uint8_t data_len, bool canfd_frame) :
  249. id(can_id)
  250. {
  251. if ((can_data == nullptr) || (data_len == 0) || (data_len > MaxDataLen)) {
  252. return;
  253. }
  254. memcpy(this->data, can_data, data_len);
  255. if (data_len <= 8) {
  256. dlc = data_len;
  257. } else {
  258. dlc = 8;
  259. }
  260. }
  261. uint8_t CANFrame::dataLengthToDlc(uint8_t data_length)
  262. {
  263. if (data_length <= 8) {
  264. return data_length;
  265. } else if (data_length <= 12) {
  266. return 9;
  267. } else if (data_length <= 16) {
  268. return 10;
  269. } else if (data_length <= 20) {
  270. return 11;
  271. } else if (data_length <= 24) {
  272. return 12;
  273. } else if (data_length <= 32) {
  274. return 13;
  275. } else if (data_length <= 48) {
  276. return 14;
  277. }
  278. return 15;
  279. }
  280. uint8_t CANFrame::dlcToDataLength(uint8_t dlc)
  281. {
  282. /*
  283. Data Length Code 9 10 11 12 13 14 15
  284. Number of data bytes 12 16 20 24 32 48 64
  285. */
  286. if (dlc <= 8) {
  287. return dlc;
  288. } else if (dlc == 9) {
  289. return 12;
  290. } else if (dlc == 10) {
  291. return 16;
  292. } else if (dlc == 11) {
  293. return 20;
  294. } else if (dlc == 12) {
  295. return 24;
  296. } else if (dlc == 13) {
  297. return 32;
  298. } else if (dlc == 14) {
  299. return 48;
  300. }
  301. return 64;
  302. }
  303. uint64_t DroneCAN::micros64(void)
  304. {
  305. uint32_t us = micros();
  306. if (us < last_micros32) {
  307. base_micros64 += 0x100000000ULL;
  308. }
  309. last_micros32 = us;
  310. return us + base_micros64;
  311. }
  312. /*
  313. handle a GET_NODE_INFO request
  314. */
  315. void DroneCAN::handle_get_node_info(CanardInstance* ins, CanardRxTransfer* transfer)
  316. {
  317. uint8_t buffer[UAVCAN_PROTOCOL_GETNODEINFO_RESPONSE_MAX_SIZE] {};
  318. uavcan_protocol_GetNodeInfoResponse pkt {};
  319. node_status.uptime_sec = millis() / 1000U;
  320. pkt.status = node_status;
  321. pkt.software_version.major = FW_VERSION_MAJOR;
  322. pkt.software_version.minor = FW_VERSION_MINOR;
  323. pkt.software_version.optional_field_flags = UAVCAN_PROTOCOL_SOFTWAREVERSION_OPTIONAL_FIELD_FLAG_VCS_COMMIT | UAVCAN_PROTOCOL_SOFTWAREVERSION_OPTIONAL_FIELD_FLAG_IMAGE_CRC;
  324. pkt.software_version.vcs_commit = GIT_VERSION;
  325. readUniqueID(pkt.hardware_version.unique_id);
  326. pkt.hardware_version.major = BOARD_ID >> 8;
  327. pkt.hardware_version.minor = BOARD_ID & 0xFF;
  328. snprintf((char*)pkt.name.data, sizeof(pkt.name.data), "%s", CAN_APP_NODE_NAME);
  329. pkt.name.len = strnlen((char*)pkt.name.data, sizeof(pkt.name.data));
  330. uint16_t total_size = uavcan_protocol_GetNodeInfoResponse_encode(&pkt, buffer);
  331. canardRequestOrRespond(ins,
  332. transfer->source_node_id,
  333. UAVCAN_PROTOCOL_GETNODEINFO_SIGNATURE,
  334. UAVCAN_PROTOCOL_GETNODEINFO_ID,
  335. &transfer->transfer_id,
  336. transfer->priority,
  337. CanardResponse,
  338. &buffer[0],
  339. total_size);
  340. }
  341. void DroneCAN::handle_allocation_response(CanardInstance* ins, CanardRxTransfer* transfer)
  342. {
  343. // Rule C - updating the randomized time interval
  344. send_next_node_id_allocation_request_at_ms =
  345. millis() + UAVCAN_PROTOCOL_DYNAMIC_NODE_ID_ALLOCATION_MIN_REQUEST_PERIOD_MS +
  346. random(1, UAVCAN_PROTOCOL_DYNAMIC_NODE_ID_ALLOCATION_MAX_FOLLOWUP_DELAY_MS);
  347. if (transfer->source_node_id == CANARD_BROADCAST_NODE_ID) {
  348. node_id_allocation_unique_id_offset = 0;
  349. return;
  350. }
  351. // Copying the unique ID from the message
  352. uavcan_protocol_dynamic_node_id_Allocation msg;
  353. uavcan_protocol_dynamic_node_id_Allocation_decode(transfer, &msg);
  354. // Obtaining the local unique ID
  355. uint8_t my_unique_id[sizeof(msg.unique_id.data)] {};
  356. readUniqueID(my_unique_id);
  357. // Matching the received UID against the local one
  358. if (memcmp(msg.unique_id.data, my_unique_id, msg.unique_id.len) != 0) {
  359. node_id_allocation_unique_id_offset = 0;
  360. return;
  361. }
  362. if (msg.unique_id.len < sizeof(msg.unique_id.data)) {
  363. // The allocator has confirmed part of unique ID, switching to the next stage and updating the timeout.
  364. node_id_allocation_unique_id_offset = msg.unique_id.len;
  365. send_next_node_id_allocation_request_at_ms -= UAVCAN_PROTOCOL_DYNAMIC_NODE_ID_ALLOCATION_MIN_REQUEST_PERIOD_MS;
  366. } else {
  367. // Allocation complete - copying the allocated node ID from the message
  368. canardSetLocalNodeID(ins, msg.node_id);
  369. Serial.printf("Node ID allocated: %u\n", unsigned(msg.node_id));
  370. }
  371. }
  372. bool DroneCAN::do_DNA(void)
  373. {
  374. if (canardGetLocalNodeID(&canard) != CANARD_BROADCAST_NODE_ID) {
  375. return true;
  376. }
  377. const uint32_t now = millis();
  378. if (now - last_DNA_start_ms < 1000 && node_id_allocation_unique_id_offset == 0) {
  379. return false;
  380. }
  381. last_DNA_start_ms = now;
  382. uint8_t node_id_allocation_transfer_id = 0;
  383. UNUSED(node_id_allocation_transfer_id);
  384. send_next_node_id_allocation_request_at_ms =
  385. now + UAVCAN_PROTOCOL_DYNAMIC_NODE_ID_ALLOCATION_MIN_REQUEST_PERIOD_MS +
  386. random(1, UAVCAN_PROTOCOL_DYNAMIC_NODE_ID_ALLOCATION_MAX_FOLLOWUP_DELAY_MS);
  387. uint8_t allocation_request[CANARD_CAN_FRAME_MAX_DATA_LEN - 1] {};
  388. allocation_request[0] = 0;
  389. if (node_id_allocation_unique_id_offset == 0) {
  390. allocation_request[0] |= 1;
  391. }
  392. uint8_t my_unique_id[sizeof(uavcan_protocol_dynamic_node_id_Allocation::unique_id.data)] {};
  393. readUniqueID(my_unique_id);
  394. static const uint8_t MaxLenOfUniqueIDInRequest = 6;
  395. uint8_t uid_size = (uint8_t)(sizeof(uavcan_protocol_dynamic_node_id_Allocation::unique_id.data) - node_id_allocation_unique_id_offset);
  396. if (uid_size > MaxLenOfUniqueIDInRequest) {
  397. uid_size = MaxLenOfUniqueIDInRequest;
  398. }
  399. memmove(&allocation_request[1], &my_unique_id[node_id_allocation_unique_id_offset], uid_size);
  400. // Broadcasting the request
  401. static uint8_t tx_id;
  402. canardBroadcast(&canard,
  403. UAVCAN_PROTOCOL_DYNAMIC_NODE_ID_ALLOCATION_SIGNATURE,
  404. UAVCAN_PROTOCOL_DYNAMIC_NODE_ID_ALLOCATION_ID,
  405. &tx_id,
  406. CANARD_TRANSFER_PRIORITY_LOW,
  407. &allocation_request[0],
  408. (uint16_t) (uid_size + 1));
  409. node_id_allocation_unique_id_offset = 0;
  410. return false;
  411. }
  412. void DroneCAN::readUniqueID(uint8_t id[6])
  413. {
  414. esp_efuse_mac_get_default(id);
  415. }
  416. bool DroneCAN::system_valid(void)
  417. {
  418. uint32_t now_ms = millis();
  419. uint32_t max_ms = 15000;
  420. if (last_system_ms == 0 ||
  421. last_self_id_ms == 0 ||
  422. last_basic_id_ms == 0 ||
  423. last_system_ms == 0 ||
  424. last_operator_id_ms == 0) {
  425. return false;
  426. }
  427. return (now_ms - last_system_ms < max_ms &&
  428. now_ms - last_self_id_ms < max_ms &&
  429. now_ms - last_basic_id_ms < max_ms &&
  430. now_ms - last_operator_id_ms < max_ms);
  431. }
  432. bool DroneCAN::location_valid(void)
  433. {
  434. uint32_t now_ms = millis();
  435. uint32_t max_ms = 2000;
  436. return last_location_ms != 0 && now_ms - last_location_ms < max_ms;
  437. }
  438. #if 0
  439. // xprintf is useful when debugging in C code such as libcanard
  440. extern "C" {
  441. void xprintf(const char *fmt, ...);
  442. }
  443. void xprintf(const char *fmt, ...)
  444. {
  445. char buffer[200] {};
  446. va_list ap;
  447. va_start(ap, fmt);
  448. uint32_t n = vsnprintf(buffer, sizeof(buffer), fmt, ap);
  449. va_end(ap);
  450. Serial.printf("%s", buffer);
  451. }
  452. #endif