DroneCAN.cpp 17 KB

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