RemoteIDModule.ino 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909
  1. /*
  2. implement OpenDroneID MAVLink and DroneCAN support
  3. */
  4. /*
  5. released under GNU GPL v2 or later
  6. */
  7. #include "options.h"
  8. #include <Arduino.h>
  9. #include "version.h"
  10. #include <math.h>
  11. #include <time.h>
  12. #include <sys/time.h>
  13. #include <opendroneid.h>
  14. #include "cndroneid.h"
  15. #include "mavlink.h"
  16. #include "DroneCAN.h"
  17. #include "WiFi_TX.h"
  18. #include "BLE_TX.h"
  19. #include <esp_wifi.h>
  20. #include <WiFi.h>
  21. #include "parameters.h"
  22. #include "webinterface.h"
  23. #include "check_firmware.h"
  24. #include <esp_ota_ops.h>
  25. #include "efuse.h"
  26. #include "led.h"
  27. // did_GB2025 是GB 46750—2025相关的协议实现
  28. // cn_did 是2023年的试运行协议实现 本质与opendroneid没有太大区别
  29. // 发给mavlink 的消息也会被调试串口转发 一个是心跳 一个是错误状态
  30. #if AP_DRONECAN_ENABLED
  31. static DroneCAN dronecan;
  32. #endif
  33. #if AP_MAVLINK_ENABLED
  34. static MAVLinkSerial mavlink1{Serial1, MAVLINK_COMM_0};
  35. static MAVLinkSerial mavlink2{Serial, MAVLINK_COMM_1};
  36. #endif
  37. static WiFi_TX wifi;
  38. static BLE_TX ble;
  39. #define DEBUG_BAUDRATE 57600
  40. // OpenDroneID output data structure
  41. ODID_UAS_Data UAS_data;
  42. CNDID_UAS_Data CN_UAS_data; // 国标输出结构体 每个报文的大小都是25字节 走转发
  43. UavIdentificationData GB2025_UAS_data;
  44. String status_reason;
  45. static uint32_t last_location_ms;
  46. static WebInterface webif;
  47. #include "soc/soc.h"
  48. #include "soc/rtc_cntl_reg.h"
  49. static bool arm_check_ok = false; // goes true for LED arm check status
  50. static bool pfst_check_ok = false;
  51. void print_g_struct()
  52. {
  53. Serial.println("\n========== GLOBAL STRUCTURE g ==========");
  54. // 基础配置
  55. Serial.printf("LOCK_LEVEL = %d\n", g.lock_level);
  56. Serial.printf("CAN_NODE = %u\n", g.can_node);
  57. #if defined(PIN_CAN_TERM)
  58. Serial.printf("CAN_TERMINATE = %u\n", g.can_term);
  59. #endif
  60. // UAS 相关
  61. Serial.printf("UAS_TYPE = %u\n", g.ua_type);
  62. Serial.printf("UAS_ID_TYPE = %u\n", g.id_type);
  63. Serial.printf("UAS_ID = %s\n", g.uas_id);
  64. Serial.printf("UAS_TYPE_2 = %u\n", g.ua_type_2);
  65. Serial.printf("UAS_ID_TYPE_2 = %u\n", g.id_type_2);
  66. Serial.printf("UAS_ID_2 = %s\n", g.uas_id_2);
  67. // 通信配置
  68. Serial.printf("BAUDRATE = %lu\n", g.baudrate);
  69. Serial.printf("WIFI_NAN_RATE = %.2f\n", g.wifi_nan_rate);
  70. Serial.printf("WIFI_BEACON_RATE = %.2f\n", g.wifi_beacon_rate);
  71. Serial.printf("WIFI_POWER = %.2f dBm\n", g.wifi_power);
  72. // 蓝牙配置(重点!)
  73. Serial.printf("BT4_RATE = %.2f Hz\n", g.bt4_rate);
  74. Serial.printf("BT4_POWER = %.2f dBm\n", g.bt4_power);
  75. Serial.printf("BT5_RATE = %.2f Hz\n", g.bt5_rate);
  76. Serial.printf("BT5_POWER = %.2f dBm\n", g.bt5_power);
  77. // Web 和 WiFi
  78. Serial.printf("WEBSERVER_EN = %u\n", g.webserver_enable);
  79. Serial.printf("WIFI_SSID = %s\n", g.wifi_ssid);
  80. Serial.printf("WIFI_PASSWORD = %s\n", g.wifi_password); // 注意:生产环境慎打密码
  81. Serial.printf("WIFI_CHANNEL = %u\n", g.wifi_channel);
  82. // 其他配置
  83. Serial.printf("BCAST_POWERUP = %u\n", g.bcast_powerup);
  84. Serial.printf("MAVLINK_SYSID = %u\n", g.mavlink_sysid);
  85. Serial.printf("OPTIONS = %u\n", g.options);
  86. Serial.printf("TO_DEFAULTS = %u\n", g.to_factory_defaults);
  87. Serial.printf("DONE_INIT = %u\n", g.done_init);
  88. Serial.printf("PROTOCOL = %u\n", g.protocol);
  89. Serial.println("==========================================\n");
  90. }
  91. /*
  92. setup serial ports
  93. */
  94. void setup()
  95. {
  96. // delay(2000);
  97. // disable brownout checking
  98. WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);
  99. g.init();
  100. // g.protocol = 2;
  101. led.set_state(Led::LedState::INIT);
  102. led.update();
  103. // Serial for debug printf
  104. Serial.begin(g.baudrate);
  105. // print_g_struct();
  106. // g.protocol = 1;
  107. // Serial1 for MAVLink
  108. Serial1.begin(g.baudrate, SERIAL_8N1, PIN_UART_RX, PIN_UART_TX);
  109. if (g.webserver_enable) {
  110. // need WiFi for web server
  111. wifi.init();
  112. }
  113. // set all fields to invalid/initial values
  114. odid_initUasData(&UAS_data);
  115. cndid_initUasData(&CN_UAS_data);
  116. uav_identification_data_init(&GB2025_UAS_data);
  117. #if AP_MAVLINK_ENABLED
  118. mavlink1.init();
  119. mavlink2.init();
  120. #endif
  121. #if AP_DRONECAN_ENABLED
  122. dronecan.init();
  123. #endif
  124. set_efuses();
  125. CheckFirmware::check_OTA_running();
  126. #if defined(PIN_CAN_EN)
  127. // optional CAN enable pin
  128. pinMode(PIN_CAN_EN, OUTPUT);
  129. digitalWrite(PIN_CAN_EN, HIGH);
  130. #endif
  131. #if defined(PIN_CAN_nSILENT)
  132. // disable silent pin
  133. pinMode(PIN_CAN_nSILENT, OUTPUT);
  134. digitalWrite(PIN_CAN_nSILENT, HIGH);
  135. #endif
  136. #if defined(PIN_CAN_TERM)
  137. #if !defined(CAN_TERM_EN)
  138. #define CAN_TERM_EN HIGH
  139. #endif
  140. // optional CAN termination control
  141. pinMode(PIN_CAN_TERM, OUTPUT);
  142. if (g.can_term == 1) {
  143. digitalWrite(PIN_CAN_TERM, CAN_TERM_EN);
  144. } else {
  145. digitalWrite(PIN_CAN_TERM, !CAN_TERM_EN);
  146. }
  147. #endif
  148. #if defined(BUZZER_PIN)
  149. //set BuZZER OUTPUT ACTIVE, just to show it works
  150. pinMode(GPIO_NUM_39, OUTPUT);
  151. digitalWrite(GPIO_NUM_39, HIGH);
  152. #endif
  153. pfst_check_ok = true; // note - this will need to be expanded to better capture PFST test status
  154. // initially set LED for fail
  155. led.set_state(Led::LedState::ARM_FAIL);
  156. esp_log_level_set("*", ESP_LOG_DEBUG);
  157. esp_ota_mark_app_valid_cancel_rollback();
  158. }
  159. #define IMIN(x,y) ((x)<(y)?(x):(y))
  160. #define ODID_COPY_STR(to, from) strncpy(to, (const char*)from, IMIN(sizeof(to), sizeof(from)))
  161. /**
  162. * mavlink 到 GB2025 转换
  163. */
  164. int odid_to_gb2025_safe(const ODID_UAS_Data *odid, UavIdentificationData *gb) {
  165. if (!odid || !gb) return -1;
  166. uav_identification_data_init(gb);
  167. gb->coord_type = COORD_WGS84;
  168. /* ========== 001-唯一产品识别码 ========== */
  169. if (odid->BasicIDValid[0]) {
  170. // BasicID总是有值的,即使无效也有默认值
  171. memcpy(gb->unique_code, odid->BasicID[0].UASID, 20);
  172. // 不需要有效性标志,因为这是固定字段
  173. }
  174. /* ========== 002-实名登记标志 ========== */
  175. if (odid->OperatorIDValid) {
  176. char last_8[9] = {0};
  177. size_t actual_len = strlen(odid->OperatorID.OperatorId);
  178. if (actual_len >= 8) {
  179. strcpy(last_8, &odid->OperatorID.OperatorId[actual_len - 8]);
  180. }
  181. // 当长度<8时,last_8全为0,复制过去就是8个0x00
  182. memcpy(gb->register_id, last_8, 8);
  183. }
  184. /* ========== 003-运行类别 ========== */
  185. if (odid->SystemValid) {
  186. // 检查枚举值范围
  187. if (odid->System.CategoryEU >= 0 && odid->System.CategoryEU < 4) {
  188. gb->run_class = (UavRunClass)odid->System.CategoryEU;
  189. gb->flag_run_class = true;
  190. } else {
  191. gb->run_class = UAV_RUN_UNDEFINED;
  192. gb->flag_run_class = false; // 标记为未收到有效值
  193. }
  194. }
  195. /* ========== 004-无人机分类 ========== */
  196. if (odid->BasicIDValid[0]) {
  197. // 检查UAType是否在有效范围内
  198. if (odid->BasicID[0].UAType >= 0 && (UavType)odid->BasicID[0].UAType < 5) {
  199. gb->uav_type = (UavType)odid->BasicID[0].UAType;
  200. } else {
  201. gb->uav_type = UAV_TYPE_RESERVED; // 设为预留值
  202. }
  203. }
  204. /* ========== 006/008-经纬度处理 ========== */
  205. if (odid->LocationValid) {
  206. // 检查经纬度是否有效
  207. bool lat_valid = (odid->Location.Latitude >= -90 &&
  208. odid->Location.Latitude <= 90 &&
  209. odid->Location.Latitude != 0); // 0通常是无效值
  210. bool lon_valid = (odid->Location.Longitude >= -180 &&
  211. odid->Location.Longitude <= 180 &&
  212. odid->Location.Longitude != 0);
  213. if (lat_valid && lon_valid) {
  214. gb->uav_lat = odid->Location.Latitude;
  215. gb->uav_lon = odid->Location.Longitude;
  216. gb->is_uav_pos_valid = true;
  217. } else {
  218. // 非法经纬度:标记为无效,编码时会自动处理
  219. gb->uav_lat = 0;
  220. gb->uav_lon = 0;
  221. gb->is_uav_pos_valid = false;
  222. }
  223. }
  224. /* ========== 009-航迹角 ========== */
  225. if (odid->LocationValid) {
  226. // 航迹角有效范围:0-360,且不是无效值361
  227. if (odid->Location.Direction >= 0 &&
  228. odid->Location.Direction <= 360 &&
  229. odid->Location.Direction != INV_DIR) {
  230. gb->track_angle = odid->Location.Direction;
  231. gb->is_track_angle_valid = true;
  232. } else {
  233. gb->track_angle = 0;
  234. gb->is_track_angle_valid = false;
  235. }
  236. }
  237. /* ========== 010-地速 ========== */
  238. if (odid->LocationValid) {
  239. // 地速有效范围:0-254.25,且不是无效值255
  240. if (odid->Location.SpeedHorizontal >= 0 &&
  241. odid->Location.SpeedHorizontal <= MAX_SPEED_H &&
  242. odid->Location.SpeedHorizontal != INV_SPEED_H) {
  243. gb->ground_speed = odid->Location.SpeedHorizontal;
  244. gb->is_ground_speed_valid = true;
  245. } else {
  246. gb->ground_speed = 0;
  247. gb->is_ground_speed_valid = false;
  248. }
  249. }
  250. /* ========== 012-垂直速度 ========== */
  251. if (odid->LocationValid) {
  252. // 垂直速度有效范围:-62 到 62,且不是无效值63
  253. if (odid->Location.SpeedVertical >= MIN_SPEED_V &&
  254. odid->Location.SpeedVertical <= MAX_SPEED_V &&
  255. odid->Location.SpeedVertical != INV_SPEED_V) {
  256. gb->uav_vert_speed = odid->Location.SpeedVertical;
  257. gb->is_vert_speed_valid = true;
  258. gb->flag_vert_speed = true;
  259. } else {
  260. gb->uav_vert_speed = 0;
  261. gb->is_vert_speed_valid = false;
  262. gb->flag_vert_speed = false; // 标记为未收到
  263. }
  264. }
  265. /* ========== 高度类处理(013/014/007/011) ========== */
  266. if (odid->LocationValid) {
  267. // Serial.printf("Geo altitude %f \r\n", odid->Location.AltitudeGeo);
  268. // Serial.printf("Rel Height %f \r\n", odid->Location.Height);
  269. // Serial.printf("Baro altitude %f \r\n", odid->Location.AltitudeBaro);
  270. // Serial.printf("time stamp %f \r\n", odid->Location.TimeStamp);
  271. // 大地高度
  272. if (odid->Location.AltitudeGeo > MIN_ALT &&
  273. odid->Location.AltitudeGeo <= MAX_ALT) {
  274. gb->uav_geo_alt = odid->Location.AltitudeGeo;
  275. gb->is_uav_geo_alt_valid = true;
  276. } else {
  277. gb->uav_geo_alt = 0;
  278. gb->is_uav_geo_alt_valid = false;
  279. }
  280. // 气压高度
  281. if (odid->Location.AltitudeBaro > MIN_ALT &&
  282. odid->Location.AltitudeBaro <= MAX_ALT) {
  283. gb->uav_press_alt = odid->Location.AltitudeBaro;
  284. gb->is_press_alt_valid = true;
  285. gb->flag_press_alt = true;
  286. } else {
  287. gb->uav_press_alt = 0;
  288. gb->is_press_alt_valid = false;
  289. gb->flag_press_alt = false;
  290. }
  291. // 相对高度
  292. if (odid->Location.Height > MIN_ALT &&
  293. odid->Location.Height <= MAX_ALT) {
  294. gb->uav_rel_alt = odid->Location.Height;
  295. gb->is_rel_alt_valid = true;
  296. gb->flag_rel_alt = true;
  297. } else {
  298. gb->uav_rel_alt = 0;
  299. gb->is_rel_alt_valid = false;
  300. gb->flag_rel_alt = false;
  301. }
  302. }
  303. /* ========== 015-运行状态 ========== */
  304. if (odid->LocationValid) {
  305. // 检查状态值范围
  306. if (odid->Location.Status >= 0 && odid->Location.Status < 6) {
  307. gb->run_state = (UavRunState)odid->Location.Status;
  308. } else {
  309. gb->run_state = UAV_STATE_UNREPORTED;
  310. }
  311. }
  312. /* ========== 精度枚举值处理 ========== */
  313. if (odid->LocationValid) {
  314. // 水平精度(0-15有效)
  315. gb->hori_accuracy = (odid->Location.HorizAccuracy >= 0 && odid->Location.HorizAccuracy <= 12) ?
  316. (UavHorizontalAccuracy_t)odid->Location.HorizAccuracy : UAV_HOR_ACC_UNKNOWN;
  317. // 垂直精度(0-6有效,7-15预留)
  318. gb->vert_accuracy = (odid->Location.VertAccuracy >=0 && odid->Location.VertAccuracy <= 6) ?
  319. (UavVerticalAccuracy_t)odid->Location.VertAccuracy : UAV_VER_ACC_UNKNOWN;
  320. // 速度精度(0-4有效,5-15预留)
  321. gb->speed_accuracy = (odid->Location.SpeedAccuracy >=0 && odid->Location.SpeedAccuracy <= 4) ?
  322. (UAVSpeedAccuracy_t)odid->Location.SpeedAccuracy : UAV_SPEED_ACC_UNKNOWN;
  323. // 时间戳精度(0-8都有效)
  324. gb->time_accuracy = (odid->Location.TSAccuracy >= 0 && odid->Location.TSAccuracy <= 8)?
  325. (UavTimestampAccuracy_t)odid->Location.TSAccuracy : UAV_TIME_ACC_UNKNOWN;
  326. }
  327. /* ========== 遥控站位置 时间戳========== */
  328. if (odid->SystemValid) {
  329. // 检查遥控站经纬度
  330. bool sta_lat_valid = (odid->System.OperatorLatitude >= -90 &&
  331. odid->System.OperatorLatitude <= 90);
  332. bool sta_lon_valid = (odid->System.OperatorLongitude >= -180 &&
  333. odid->System.OperatorLongitude <= 180);
  334. if (sta_lat_valid && sta_lon_valid &&
  335. (odid->System.OperatorLatitude != 0 || odid->System.OperatorLongitude != 0)) {
  336. gb->station_lat = odid->System.OperatorLatitude;
  337. gb->station_lon = odid->System.OperatorLongitude;
  338. gb->is_station_pos_valid = true;
  339. } else {
  340. gb->station_lat = 0;
  341. gb->station_lon = 0;
  342. gb->is_station_pos_valid = false;
  343. }
  344. // 遥控站高度
  345. if (odid->System.OperatorAltitudeGeo > MIN_ALT &&
  346. odid->System.OperatorAltitudeGeo <= MAX_ALT) {
  347. gb->station_geo_alt = odid->System.OperatorAltitudeGeo;
  348. gb->is_station_alt_valid = true;
  349. } else {
  350. gb->station_geo_alt = 0;
  351. gb->is_station_alt_valid = false;
  352. }
  353. if (odid->System.Timestamp < 0)
  354. {
  355. gb->timestamp = 0;
  356. gb->is_timestamp_valid = false;
  357. } else {
  358. gb->timestamp = (uint64_t)(odid->System.Timestamp * 1000); // 使用unix时间 单位ms
  359. gb->is_timestamp_valid = true;
  360. }
  361. }
  362. return 0;
  363. }
  364. /*
  365. check parsing of UAS_data, this checks ranges of values to ensure we
  366. will produce a valid pack
  367. returns nullptr on no error, or a string error
  368. 检查UAS数据的解析情况,这会检查值的范围以确保我们能生成一个有效的数据包。
  369. 无错误时返回空指针,否则返回字符串形式的错误信息。
  370. */
  371. static const char *check_parse(void)
  372. {
  373. String ret = "";
  374. {
  375. ODID_Location_encoded encoded {};
  376. if (encodeLocationMessage(&encoded, &UAS_data.Location) != ODID_SUCCESS) {
  377. ret += "LOC ";
  378. }
  379. }
  380. {
  381. ODID_System_encoded encoded {};
  382. if (encodeSystemMessage(&encoded, &UAS_data.System) != ODID_SUCCESS) {
  383. ret += "SYS ";
  384. }
  385. }
  386. {
  387. ODID_BasicID_encoded encoded {};
  388. if (UAS_data.BasicIDValid[0] == 1) {
  389. if (encodeBasicIDMessage(&encoded, &UAS_data.BasicID[0]) != ODID_SUCCESS) {
  390. ret += "ID_1 ";
  391. }
  392. }
  393. memset(&encoded, 0, sizeof(encoded));
  394. if (UAS_data.BasicIDValid[1] == 1) {
  395. if (encodeBasicIDMessage(&encoded, &UAS_data.BasicID[1]) != ODID_SUCCESS) {
  396. ret += "ID_2 ";
  397. }
  398. }
  399. }
  400. {
  401. ODID_SelfID_encoded encoded {};
  402. if (encodeSelfIDMessage(&encoded, &UAS_data.SelfID) != ODID_SUCCESS) {
  403. ret += "SELF_ID ";
  404. }
  405. }
  406. {
  407. ODID_OperatorID_encoded encoded {};
  408. if (encodeOperatorIDMessage(&encoded, &UAS_data.OperatorID) != ODID_SUCCESS) {
  409. ret += "OP_ID ";
  410. }
  411. }
  412. if (ret.length() > 0) {
  413. // if all errors would occur in this function, it will fit in
  414. // 50 chars that is also the max for the arm status message
  415. // 如果所有错误都发生在这个函数中,它会刚好容纳
  416. // 50个字符,这也是臂状态消息的最大长度
  417. static char return_string[50];
  418. memset(return_string, 0, sizeof(return_string));
  419. snprintf(return_string, sizeof(return_string)-1, "bad %s data", ret.c_str());
  420. Serial.printf("error %s\n", return_string);
  421. return return_string;
  422. }
  423. return nullptr;
  424. }
  425. /*
  426. fill in UAS_data from MAVLink packets
  427. */
  428. static void set_data(Transport &t) // 两种类型都获取 广播按照需要的进行广播
  429. { // 从mavlink获取数据包
  430. const auto &operator_id = t.get_operator_id();
  431. const auto &basic_id = t.get_basic_id();
  432. const auto &system = t.get_system();
  433. const auto &self_id = t.get_self_id();
  434. const auto &location = t.get_location();
  435. odid_initUasData(&UAS_data);
  436. cndid_initUasData(&CN_UAS_data); // 复位UAS数据结构体
  437. uav_identification_data_init(&GB2025_UAS_data);
  438. /*
  439. if we don't have BasicID info from parameters and we have it
  440. from the DroneCAN or MAVLink transport then copy it to the
  441. parameters to persist it. This makes it possible to set the
  442. UAS_ID string via a MAVLink BASIC_ID message and also offers a
  443. migration path from the old approach of GCS setting these values
  444. to having them as parameters
  445. BasicID 2 can be set in parameters, or provided via mavlink We
  446. don't persist the BasicID2 if provided via mavlink to allow
  447. users to change BasicID2 on different days
  448. */
  449. if (!g.have_basic_id_info() && !(g.options & OPTIONS_DONT_SAVE_BASIC_ID_TO_PARAMETERS)) {
  450. if (basic_id.ua_type != 0 &&
  451. basic_id.id_type != 0 &&
  452. strnlen((const char *)basic_id.uas_id, 20) > 0) {
  453. g.set_by_name_uint8("UAS_TYPE", basic_id.ua_type);
  454. g.set_by_name_uint8("UAS_ID_TYPE", basic_id.id_type);
  455. char uas_id[21] {};
  456. ODID_COPY_STR(uas_id, basic_id.uas_id);
  457. g.set_by_name_string("UAS_ID", uas_id);
  458. }
  459. } // 是否配置了保存基本ID的选项 == 存到eeprom 可以用国际的协议存储BASE ID
  460. // BasicID
  461. if (g.have_basic_id_info() && !(g.options & OPTIONS_DONT_SAVE_BASIC_ID_TO_PARAMETERS)) {
  462. // from parameters
  463. UAS_data.BasicID[0].UAType = (ODID_uatype_t)g.ua_type;
  464. UAS_data.BasicID[0].IDType = (ODID_idtype_t)g.id_type;
  465. // 国际国标 的 基础ID参数是一样的 拷贝
  466. CN_UAS_data.BasicID[0].UAType = (CNDID_UAType_t)g.ua_type;
  467. CN_UAS_data.BasicID[0].IDType = (CNDID_IDType_t)g.id_type;
  468. ODID_COPY_STR(UAS_data.BasicID[0].UASID, g.uas_id);
  469. ODID_COPY_STR(CN_UAS_data.BasicID[0].UASID, g.uas_id); // 拷贝
  470. UAS_data.BasicIDValid[0] = 1;
  471. CN_UAS_data.BasicIDValid[0] = 1; // 拷贝
  472. // BasicID 2
  473. if (g.have_basic_id_2_info()) {
  474. // from parameters
  475. UAS_data.BasicID[1].UAType = (ODID_uatype_t)g.ua_type_2;
  476. UAS_data.BasicID[1].IDType = (ODID_idtype_t)g.id_type_2;
  477. // 国际国标 的 基础ID参数是一样的 拷贝
  478. CN_UAS_data.BasicID[1].UAType = (CNDID_UAType_t)g.ua_type;
  479. CN_UAS_data.BasicID[1].IDType = (CNDID_IDType_t)g.id_type;
  480. ODID_COPY_STR(UAS_data.BasicID[1].UASID, g.uas_id_2);
  481. ODID_COPY_STR(CN_UAS_data.BasicID[1].UASID, g.uas_id_2); // 拷贝
  482. UAS_data.BasicIDValid[1] = 1;
  483. CN_UAS_data.BasicIDValid[1] = 1; // 拷贝
  484. } else if (strcmp((const char*)g.uas_id, (const char*)basic_id.uas_id) != 0) {
  485. /*
  486. no BasicID 2 in the parameters, if one is provided on MAVLink
  487. and it is a different uas_id from the basicID1 then use it as BasicID2
  488. */
  489. if (basic_id.ua_type != 0 &&
  490. basic_id.id_type != 0 &&
  491. strnlen((const char *)basic_id.uas_id, 20) > 0) {
  492. UAS_data.BasicID[1].UAType = (ODID_uatype_t)basic_id.ua_type;
  493. UAS_data.BasicID[1].IDType = (ODID_idtype_t)basic_id.id_type;
  494. ODID_COPY_STR(UAS_data.BasicID[1].UASID, basic_id.uas_id);
  495. UAS_data.BasicIDValid[1] = 1;
  496. // 拷贝
  497. CN_UAS_data.BasicID[1].UAType = (CNDID_UAType_t)basic_id.ua_type;
  498. CN_UAS_data.BasicID[1].IDType = (CNDID_IDType_t)basic_id.id_type;
  499. ODID_COPY_STR(CN_UAS_data.BasicID[1].UASID, basic_id.uas_id);
  500. CN_UAS_data.BasicIDValid[1] = 1;
  501. }
  502. }
  503. }
  504. if (g.options & OPTIONS_DONT_SAVE_BASIC_ID_TO_PARAMETERS) {
  505. if (basic_id.ua_type != 0 &&
  506. basic_id.id_type != 0 &&
  507. strnlen((const char *)basic_id.uas_id, 20) > 0) {
  508. if (strcmp((const char*)UAS_data.BasicID[0].UASID, (const char*)basic_id.uas_id) != 0 && strnlen((const char *)basic_id.uas_id, 20) > 0) {
  509. UAS_data.BasicID[1].UAType = (ODID_uatype_t)basic_id.ua_type;
  510. UAS_data.BasicID[1].IDType = (ODID_idtype_t)basic_id.id_type;
  511. ODID_COPY_STR(UAS_data.BasicID[1].UASID, basic_id.uas_id);
  512. UAS_data.BasicIDValid[1] = 1;
  513. // 拷贝
  514. CN_UAS_data.BasicID[1].UAType = (CNDID_UAType_t)basic_id.ua_type;
  515. CN_UAS_data.BasicID[1].IDType = (CNDID_IDType_t)basic_id.id_type;
  516. ODID_COPY_STR(CN_UAS_data.BasicID[1].UASID, basic_id.uas_id);
  517. CN_UAS_data.BasicIDValid[1] = 1;
  518. } else {
  519. UAS_data.BasicID[0].UAType = (ODID_uatype_t)basic_id.ua_type;
  520. UAS_data.BasicID[0].IDType = (ODID_idtype_t)basic_id.id_type;
  521. ODID_COPY_STR(UAS_data.BasicID[0].UASID, basic_id.uas_id);
  522. UAS_data.BasicIDValid[0] = 1;
  523. // 拷贝
  524. CN_UAS_data.BasicID[0].UAType = (CNDID_UAType_t)basic_id.ua_type;
  525. CN_UAS_data.BasicID[0].IDType = (CNDID_IDType_t)basic_id.id_type;
  526. ODID_COPY_STR(CN_UAS_data.BasicID[0].UASID, basic_id.uas_id); // 拷贝
  527. CN_UAS_data.BasicIDValid[0] = 1; // 拷贝
  528. }
  529. }
  530. }
  531. // OperatorID
  532. if (strlen(operator_id.operator_id) > 0) {
  533. UAS_data.OperatorID.OperatorIdType = (ODID_operatorIdType_t)operator_id.operator_id_type;
  534. ODID_COPY_STR(UAS_data.OperatorID.OperatorId, operator_id.operator_id);
  535. UAS_data.OperatorIDValid = 1;
  536. }
  537. //
  538. // SelfID
  539. if (strlen(self_id.description) > 0) {
  540. UAS_data.SelfID.DescType = (ODID_desctype_t)self_id.description_type;
  541. ODID_COPY_STR(UAS_data.SelfID.Desc, self_id.description);
  542. UAS_data.SelfIDValid = 1;
  543. }
  544. // SelfID CN
  545. if (strlen(self_id.description) > 0) {
  546. CN_UAS_data.SelfID.DescType= (CNDID_DescType_t)self_id.description_type;
  547. ODID_COPY_STR(CN_UAS_data.SelfID.Desc, self_id.description); // 拷贝函数通用
  548. CN_UAS_data.SelfIDValid = 1;
  549. }
  550. // System
  551. if (system.timestamp != 0) {
  552. UAS_data.System.OperatorLocationType = (ODID_operator_location_type_t)system.operator_location_type;
  553. UAS_data.System.ClassificationType = (ODID_classification_type_t)system.classification_type;
  554. UAS_data.System.OperatorLatitude = system.operator_latitude * 1.0e-7;
  555. UAS_data.System.OperatorLongitude = system.operator_longitude * 1.0e-7;
  556. UAS_data.System.AreaCount = system.area_count;
  557. UAS_data.System.AreaRadius = system.area_radius;
  558. UAS_data.System.AreaCeiling = system.area_ceiling;
  559. UAS_data.System.AreaFloor = system.area_floor;
  560. UAS_data.System.CategoryEU = (ODID_category_EU_t)system.category_eu;
  561. UAS_data.System.ClassEU = (ODID_class_EU_t)system.class_eu;
  562. UAS_data.System.OperatorAltitudeGeo = system.operator_altitude_geo;
  563. UAS_data.System.Timestamp = system.timestamp;
  564. UAS_data.SystemValid = 1;
  565. }
  566. // System CN
  567. if (system.timestamp != 0) {
  568. CN_UAS_data.System.Coord_Type = (CNDID_CoordType_t)CN_COORD_TYPE; // 坐标系建议写死
  569. CN_UAS_data.System.OperatorLocationType = (CNDID_operator_location_type_t)system.operator_location_type;
  570. CN_UAS_data.System.Classification_Type = (CNDID_classification_type_t)system.classification_type;
  571. CN_UAS_data.System.OperatorLatitude = system.operator_latitude * 1.0e-7;
  572. CN_UAS_data.System.OperatorLongitude = system.operator_longitude * 1.0e-7;
  573. CN_UAS_data.System.AreaCount = system.area_count;
  574. CN_UAS_data.System.AreaRadius = system.area_radius;
  575. CN_UAS_data.System.AreaCeiling = system.area_ceiling;
  576. CN_UAS_data.System.AreaFloor = system.area_floor;
  577. CN_UAS_data.System.CategoryCN = (CNDID_category_CN_t)system.category_eu; // 右边是mvlink自动生成的结构体成员不能更改
  578. CN_UAS_data.System.ClassCN = (CNDID_class_CN_t)system.class_eu; // 右边是mvlink自动生成的结构体成员不能更改
  579. CN_UAS_data.System.OperatorAltitudeGeo = system.operator_altitude_geo;
  580. CN_UAS_data.System.Timestamp = system.timestamp;
  581. CN_UAS_data.SystemValid = 1;
  582. }
  583. // Location
  584. if (location.timestamp != 0) {
  585. UAS_data.Location.Status = (ODID_status_t)location.status;
  586. UAS_data.Location.Direction = location.direction*0.01;
  587. UAS_data.Location.SpeedHorizontal = location.speed_horizontal*0.01;
  588. UAS_data.Location.SpeedVertical = location.speed_vertical*0.01;
  589. UAS_data.Location.Latitude = location.latitude*1.0e-7;
  590. UAS_data.Location.Longitude = location.longitude*1.0e-7;
  591. UAS_data.Location.AltitudeBaro = location.altitude_barometric;
  592. UAS_data.Location.AltitudeGeo = location.altitude_geodetic;
  593. UAS_data.Location.HeightType = (ODID_Height_reference_t)location.height_reference;
  594. UAS_data.Location.Height = location.height;
  595. UAS_data.Location.HorizAccuracy = (ODID_Horizontal_accuracy_t)location.horizontal_accuracy;
  596. UAS_data.Location.VertAccuracy = (ODID_Vertical_accuracy_t)location.vertical_accuracy;
  597. UAS_data.Location.BaroAccuracy = (ODID_Vertical_accuracy_t)location.barometer_accuracy;
  598. UAS_data.Location.SpeedAccuracy = (ODID_Speed_accuracy_t)location.speed_accuracy;
  599. UAS_data.Location.TSAccuracy = (ODID_Timestamp_accuracy_t)location.timestamp_accuracy;
  600. UAS_data.Location.TimeStamp = location.timestamp;
  601. UAS_data.LocationValid = 1;
  602. }
  603. // Location CN
  604. if (location.timestamp != 0) {
  605. CN_UAS_data.Location.Status = (CNDID_Status_t)location.status;
  606. CN_UAS_data.Location.Direction = location.direction*0.01;
  607. CN_UAS_data.Location.SpeedHorizontal = location.speed_horizontal*0.01;
  608. CN_UAS_data.Location.SpeedVertical = location.speed_vertical*0.01;
  609. CN_UAS_data.Location.Latitude = location.latitude*1.0e-7;
  610. CN_UAS_data.Location.Longitude = location.longitude*1.0e-7;
  611. CN_UAS_data.Location.AltitudeBaro = location.altitude_barometric;
  612. CN_UAS_data.Location.AltitudeGeo = location.altitude_geodetic;
  613. CN_UAS_data.Location.HeightType = (CNDID_HeightReference_t)location.height_reference;
  614. CN_UAS_data.Location.Height = location.height;
  615. CN_UAS_data.Location.HorizAccuracy = (CNDID_HorizontalAccuracy_t)location.horizontal_accuracy;
  616. CN_UAS_data.Location.VertAccuracy = (CNDID_VerticalAccuracy_t)location.vertical_accuracy;
  617. CN_UAS_data.Location.BaroAccuracy = (CNDID_VerticalAccuracy_t)location.barometer_accuracy;
  618. CN_UAS_data.Location.SpeedAccuracy = (CNDID_SpeedAccuracy_t)location.speed_accuracy;
  619. CN_UAS_data.Location.TSAccuracy = (CNDID_TimeStampAccuracy_t)location.timestamp_accuracy;
  620. CN_UAS_data.Location.TimeStamp = location.timestamp;
  621. CN_UAS_data.LocationValid = 1;
  622. }
  623. // GB2025 数据转换
  624. odid_to_gb2025_safe(&UAS_data, &GB2025_UAS_data);
  625. // memcpy(GB2025_UAS_data.unique_code, basic_id.uas_id, 20);
  626. // memcpy(GB2025_UAS_data.register_id, operator_id.operator_id, 8); // 从操作员ID里复用
  627. // GB2025_UAS_data.uav_type = basic_id.ua_type;
  628. // GB2025_UAS_data.run_class = system.category_eu;
  629. // GB2025_UAS_data.station_type = system.operator_location_type;
  630. // GB2025_UAS_data.station_lat = system.operator_latitude * 1.0e-7;
  631. // GB2025_UAS_data.station_lon = system.operator_longitude * 1.0e-7;
  632. // GB2025_UAS_data.station_geo_alt = system.operator_altitude_geo;
  633. // GB2025_UAS_data.uav_lat = location.latitude*1.0e-7;
  634. // GB2025_UAS_data.uav_lon = location.longitude*1.0e-7;
  635. // GB2025_UAS_data.track_angle = location.direction*0.01;
  636. // GB2025_UAS_data.ground_speed = location.speed_horizontal*0.01;
  637. // GB2025_UAS_data.uav_rel_alt = location.height_reference;
  638. // GB2025_UAS_data.uav_vert_speed = location.speed_vertical*0.01;
  639. // GB2025_UAS_data.uav_geo_alt = location.altitude_geodetic;
  640. // GB2025_UAS_data.uav_press_alt = location.altitude_barometric;
  641. // GB2025_UAS_data.run_state = location.status;
  642. // GB2025_UAS_datacoord_type = COORD_WGS84;
  643. // GB2025_UAS_data.hori_accuracy = location.horizontal_accuracy;
  644. // GB2025_UAS_data.vert_accuracy = location.vertical_accuracy;
  645. // GB2025_UAS_data.speed_accuracy = location.speed_accuracy;
  646. // GB2025_UAS_data.timestamp = (uint64_t)(odid->Location.TimeStamp * 1000);;
  647. // GB2025_UAS_data.time_accuracy = location.timestamp_accuracy;
  648. const char *reason = check_parse(); // 内部以区分国标 国际
  649. t.arm_status_check(reason); // 内部以区分国标 国际
  650. t.set_parse_fail(reason); // 设置错误原因
  651. arm_check_ok = (reason==nullptr);
  652. if (g.options & OPTIONS_FORCE_ARM_OK) { // 设置强制绿灯?
  653. arm_check_ok = true;
  654. }
  655. led.set_state(pfst_check_ok && arm_check_ok? Led::LedState::ARM_OK : Led::LedState::ARM_FAIL);
  656. uint32_t now_ms = millis();
  657. uint32_t location_age_ms = now_ms - t.get_last_location_ms();
  658. uint32_t last_location_age_ms = now_ms - last_location_ms;
  659. if (location_age_ms < last_location_age_ms) {
  660. last_location_ms = t.get_last_location_ms();
  661. }
  662. }
  663. static uint8_t loop_counter = 0;
  664. void loop()
  665. {
  666. #if AP_MAVLINK_ENABLED
  667. mavlink1.update(); // mavlink实际使用该串口
  668. mavlink2.update();
  669. #endif
  670. #if AP_DRONECAN_ENABLED
  671. dronecan.update(); // 开启了drone can
  672. #endif
  673. const uint32_t now_ms = millis();
  674. // the transports have common static data, so we can just use the
  675. // first for status
  676. // 这些传输工具具有共同的静态数据,所以我们只需使用第一个来获取状态
  677. #if AP_MAVLINK_ENABLED
  678. auto &transport = mavlink1; // 默认使用串口接收 mavlink数据
  679. #elif AP_DRONECAN_ENABLED
  680. auto &transport = dronecan;
  681. #else
  682. #error "Must enable DroneCAN or MAVLink"
  683. #endif
  684. if(g.com_port == CAN_PORT){
  685. auto &transport = dronecan;
  686. }else if(g.com_port == UART_PORT){
  687. auto &transport = mavlink1;
  688. }
  689. bool have_location = false;
  690. // - last_location_ms:最后一次收到有效位置数据的时间戳(毫秒)
  691. // - last_system_ms:最后一次收到飞控系统消息的时间戳(毫秒)
  692. const uint32_t last_location_ms = transport.get_last_location_ms();
  693. const uint32_t last_system_ms = transport.get_last_system_ms();
  694. led.update();
  695. status_reason = ""; // 初始化故障原因描述(默认空)
  696. if (last_location_ms == 0 ||
  697. now_ms - last_location_ms > 5000) {
  698. UAS_data.Location.Status = ODID_STATUS_REMOTE_ID_SYSTEM_FAILURE; // 相同的故障ID 4 // web页面可视
  699. CN_UAS_data.Location.Status = CNDID_STATUS_REMOTE_ID_SYSTEM_FAILURE;
  700. }
  701. if (last_system_ms == 0 ||
  702. now_ms - last_system_ms > 5000) {
  703. UAS_data.Location.Status = ODID_STATUS_REMOTE_ID_SYSTEM_FAILURE;
  704. CN_UAS_data.Location.Status = CNDID_STATUS_REMOTE_ID_SYSTEM_FAILURE;
  705. }
  706. // 判定条件3:数据解析失败(飞控消息格式错误/解析出错)
  707. if (transport.get_parse_fail() != nullptr) {
  708. UAS_data.Location.Status = ODID_STATUS_REMOTE_ID_SYSTEM_FAILURE;
  709. CN_UAS_data.Location.Status = CNDID_STATUS_REMOTE_ID_SYSTEM_FAILURE;
  710. status_reason = String(transport.get_parse_fail()); // 状态原因上传web页面
  711. }
  712. // web update has to happen after we update Status above
  713. // 网络更新必须在我们更新上述状态之后进行
  714. if (g.webserver_enable) {
  715. webif.update();
  716. }
  717. if (g.bcast_powerup) { // true 上电即广播"模式
  718. // if we are broadcasting on powerup we always mark location valid
  719. // so the location with default data is sent
  720. // 如果我们在启动时进行广播,我们总是会标记位置有效
  721. // 这样就会发送带有默认数据的位置信息
  722. if (!UAS_data.LocationValid) {
  723. UAS_data.Location.Status = ODID_STATUS_REMOTE_ID_SYSTEM_FAILURE;
  724. UAS_data.LocationValid = 1;
  725. }
  726. } else {
  727. // only broadcast if we have received a location at least once
  728. // 仅在我们至少接收过一次位置信息时才进行广播
  729. if (last_location_ms == 0) {
  730. delay(1); // 没接收到位置信息直接退出该次loop 执行完毕后还会再次进入
  731. return;
  732. }
  733. }
  734. set_data(transport);
  735. // Serial.printf("/***********************************/\n");
  736. // Serial.printf("ID %s %s\n",UAS_data.BasicID[0].UASID, UAS_data.BasicID[1].UASID);
  737. // Serial.printf("OP ID %s\n",UAS_data.OperatorID.OperatorId);
  738. // Serial.printf("sys timestamp %d %d\n",UAS_data.System.Timestamp, UAS_data.System.OperatorLocationType);
  739. // Serial.printf("loc timestamp %d %d\n",UAS_data.Location.TimeStamp, UAS_data.Location);
  740. // Serial.printf("/***********************************/\n");
  741. static uint32_t last_update_wifi_nan_ms; // wifi_nan_rate发送频率HZ 达到对应的时间了就启动RemoteID WIFI_NAN发送
  742. if (g.wifi_nan_rate > 0 &&
  743. now_ms - last_update_wifi_nan_ms > 1000/g.wifi_nan_rate) {
  744. last_update_wifi_nan_ms = now_ms;
  745. if(g.protocol == PROTOCOL_EU)
  746. wifi.transmit_nan(UAS_data);
  747. else if(g.protocol == PROTOCOL_CN2023)
  748. wifi.transmit_cn_nan(CN_UAS_data); // 这个可要可不要 国标只要求发送wifi beacon 信标帧
  749. else if(g.protocol == PROTOCOL_GB2025)
  750. wifi.transmit_GB2025_nan(GB2025_UAS_data);
  751. // Serial.printf("update_wifi_nan\n");
  752. }
  753. static uint32_t last_update_wifi_beacon_ms; // wifi_beacon_rate发送频率HZ 达到对应的时间了就启动RemoteID WIFI_BEACON发送
  754. if (g.wifi_beacon_rate > 0 &&
  755. now_ms - last_update_wifi_beacon_ms > 1000/g.wifi_beacon_rate) {
  756. last_update_wifi_beacon_ms = now_ms;
  757. if(g.protocol == PROTOCOL_EU)
  758. wifi.transmit_beacon(UAS_data);
  759. else if(g.protocol == PROTOCOL_CN2023)
  760. wifi.transmit_cn_beacon(CN_UAS_data);
  761. else if(g.protocol == PROTOCOL_GB2025)
  762. wifi.transmit_GB2025_beacon(GB2025_UAS_data);
  763. // Serial.printf("update_wifi_beacon\n");
  764. }
  765. static uint32_t last_update_bt5_ms; // BLE 远端蓝牙发送频率 bt5_rate 达到对应的时间了就启动RemoteID BLE5发送
  766. if (g.bt5_rate > 0 &&
  767. now_ms - last_update_bt5_ms > 1000/g.bt5_rate) {
  768. last_update_bt5_ms = now_ms;
  769. if(g.protocol == PROTOCOL_EU)
  770. ble.transmit_longrange(UAS_data);
  771. else if(g.protocol == PROTOCOL_CN2023)
  772. ble.transmit_cn_longrange(CN_UAS_data);
  773. else if(g.protocol == PROTOCOL_GB2025)
  774. ble.transmit_GB2025_longrange(GB2025_UAS_data); // 国标只要求bt5
  775. Serial.printf("update_bt5\n");
  776. }
  777. static uint32_t last_update_bt4_ms; // BLE 近端蓝牙发送频率 bt4_rate 达到对应的时间了就启动RemoteID BLE4发送
  778. int bt4_states = 0;
  779. if(g.protocol == PROTOCOL_EU)
  780. bt4_states = UAS_data.BasicIDValid[1] ? 7 : 6;
  781. else if(g.protocol == PROTOCOL_CN2023)
  782. bt4_states = CN_UAS_data.BasicIDValid[1] ? 7 : 6; // CN 最多只发6条其实 为了间隔上同步
  783. // Serial.printf("bt4 state %d\n", bt4_states);
  784. if (g.bt4_rate > 0 &&
  785. now_ms - last_update_bt4_ms > (1000.0f/bt4_states)/g.bt4_rate) {
  786. last_update_bt4_ms = now_ms;
  787. if(g.protocol == PROTOCOL_EU)
  788. ble.transmit_legacy(UAS_data);
  789. else if(g.protocol == PROTOCOL_CN2023)
  790. ble.transmit_cn_legacy(CN_UAS_data);
  791. // Serial.printf("update_bt4\n");
  792. }
  793. // sleep for a bit for power saving 节能
  794. delay(1);
  795. }