RemoteIDModule.ino 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  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 "mavlink.h"
  15. #include "DroneCAN.h"
  16. #include "WiFi_TX.h"
  17. #include "BLE_TX.h"
  18. #include "parameters.h"
  19. #include "webinterface.h"
  20. #include "check_firmware.h"
  21. #include <esp_ota_ops.h>
  22. #include "efuse.h"
  23. #include "led.h"
  24. #if AP_DRONECAN_ENABLED
  25. static DroneCAN dronecan;
  26. #endif
  27. #if AP_MAVLINK_ENABLED
  28. static MAVLinkSerial mavlink1{Serial1, MAVLINK_COMM_0};
  29. static MAVLinkSerial mavlink2{Serial, MAVLINK_COMM_1};
  30. #endif
  31. static WiFi_NAN wifi;
  32. static BLE_TX ble;
  33. #define DEBUG_BAUDRATE 57600
  34. // OpenDroneID output data structure
  35. ODID_UAS_Data UAS_data;
  36. static uint32_t last_location_ms;
  37. static WebInterface webif;
  38. #include "soc/soc.h"
  39. #include "soc/rtc_cntl_reg.h"
  40. static bool arm_check_ok = false; // goes true for LED arm check status
  41. static bool pfst_check_ok = false;
  42. /*
  43. setup serial ports
  44. */
  45. void setup()
  46. {
  47. // disable brownout checking
  48. WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);
  49. g.init();
  50. led.set_state(Led::LedState::INIT);
  51. led.update();
  52. // Serial for debug printf
  53. Serial.begin(g.baudrate);
  54. // Serial1 for MAVLink
  55. Serial1.begin(g.baudrate, SERIAL_8N1, PIN_UART_RX, PIN_UART_TX);
  56. // set all fields to invalid/initial values
  57. odid_initUasData(&UAS_data);
  58. #if AP_MAVLINK_ENABLED
  59. mavlink1.init();
  60. mavlink2.init();
  61. #endif
  62. #if AP_DRONECAN_ENABLED
  63. dronecan.init();
  64. #endif
  65. set_efuses();
  66. CheckFirmware::check_OTA_running();
  67. #if defined(PIN_CAN_EN)
  68. // optional CAN enable pin
  69. pinMode(PIN_CAN_EN, OUTPUT);
  70. digitalWrite(PIN_CAN_EN, HIGH);
  71. #endif
  72. #if defined(PIN_CAN_nSILENT)
  73. // disable silent pin
  74. pinMode(PIN_CAN_nSILENT, OUTPUT);
  75. digitalWrite(PIN_CAN_nSILENT, HIGH);
  76. #endif
  77. #if defined(PIN_CAN_TERM)
  78. // optional CAN termination control
  79. pinMode(PIN_CAN_TERM, OUTPUT);
  80. digitalWrite(PIN_CAN_TERM, HIGH);
  81. #endif
  82. pfst_check_ok = true; // note - this will need to be expanded to better capture PFST test status
  83. // initially set LED for fail
  84. led.set_state(Led::LedState::ARM_FAIL);
  85. esp_log_level_set("*", ESP_LOG_DEBUG);
  86. esp_ota_mark_app_valid_cancel_rollback();
  87. }
  88. #define IMIN(x,y) ((x)<(y)?(x):(y))
  89. #define ODID_COPY_STR(to, from) strncpy(to, (const char*)from, IMIN(sizeof(to), sizeof(from)))
  90. /*
  91. check parsing of UAS_data, this checks ranges of values to ensure we
  92. will produce a valid pack
  93. */
  94. static const char *check_parse(void)
  95. {
  96. {
  97. ODID_Location_encoded encoded {};
  98. if (encodeLocationMessage(&encoded, &UAS_data.Location) != ODID_SUCCESS) {
  99. return "bad LOCATION data";
  100. }
  101. }
  102. {
  103. ODID_System_encoded encoded {};
  104. if (encodeSystemMessage(&encoded, &UAS_data.System) != ODID_SUCCESS) {
  105. return "bad SYSTEM data";
  106. }
  107. }
  108. {
  109. ODID_BasicID_encoded encoded {};
  110. if (encodeBasicIDMessage(&encoded, &UAS_data.BasicID[0]) != ODID_SUCCESS) {
  111. return "bad BASIC_ID data";
  112. }
  113. }
  114. {
  115. ODID_SelfID_encoded encoded {};
  116. if (encodeSelfIDMessage(&encoded, &UAS_data.SelfID) != ODID_SUCCESS) {
  117. return "bad SELF_ID data";
  118. }
  119. }
  120. {
  121. ODID_OperatorID_encoded encoded {};
  122. if (encodeOperatorIDMessage(&encoded, &UAS_data.OperatorID) != ODID_SUCCESS) {
  123. return "bad OPERATOR_ID data";
  124. }
  125. }
  126. return nullptr;
  127. }
  128. /*
  129. fill in UAS_data from MAVLink packets
  130. */
  131. static void set_data(Transport &t)
  132. {
  133. const auto &operator_id = t.get_operator_id();
  134. const auto &basic_id = t.get_basic_id();
  135. const auto &system = t.get_system();
  136. const auto &self_id = t.get_self_id();
  137. const auto &location = t.get_location();
  138. /*
  139. if we don't have BasicID info from parameters and we have it
  140. from the DroneCAN or MAVLink transport then copy it to the
  141. parameters to persist it. This makes it possible to set the
  142. UAS_ID string via a MAVLink BASIC_ID message and also offers a
  143. migration path from the old approach of GCS setting these values
  144. to having them as parameters
  145. */
  146. if (!g.have_basic_id_info()) {
  147. if (basic_id.ua_type != 0 &&
  148. basic_id.id_type != 0 &&
  149. strnlen((const char *)basic_id.uas_id, 20) > 0) {
  150. g.set_by_name_uint8("UAS_TYPE", basic_id.ua_type);
  151. g.set_by_name_uint8("UAS_ID_TYPE", basic_id.id_type);
  152. char uas_id[21] {};
  153. ODID_COPY_STR(uas_id, basic_id.uas_id);
  154. g.set_by_name_string("UAS_ID", uas_id);
  155. }
  156. }
  157. // BasicID
  158. if (g.have_basic_id_info()) {
  159. // from parameters
  160. UAS_data.BasicID[0].UAType = (ODID_uatype_t)g.ua_type;
  161. UAS_data.BasicID[0].IDType = (ODID_idtype_t)g.id_type;
  162. ODID_COPY_STR(UAS_data.BasicID[0].UASID, g.uas_id);
  163. } else {
  164. // from transport
  165. UAS_data.BasicID[0].UAType = (ODID_uatype_t)basic_id.ua_type;
  166. UAS_data.BasicID[0].IDType = (ODID_idtype_t)basic_id.id_type;
  167. ODID_COPY_STR(UAS_data.BasicID[0].UASID, basic_id.uas_id);
  168. }
  169. UAS_data.BasicIDValid[0] = 1;
  170. // OperatorID
  171. UAS_data.OperatorID.OperatorIdType = (ODID_operatorIdType_t)operator_id.operator_id_type;
  172. ODID_COPY_STR(UAS_data.OperatorID.OperatorId, operator_id.operator_id);
  173. UAS_data.OperatorIDValid = 1;
  174. // SelfID
  175. UAS_data.SelfID.DescType = (ODID_desctype_t)self_id.description_type;
  176. ODID_COPY_STR(UAS_data.SelfID.Desc, self_id.description);
  177. UAS_data.SelfIDValid = 1;
  178. // System
  179. if (system.timestamp != 0) {
  180. UAS_data.System.OperatorLocationType = (ODID_operator_location_type_t)system.operator_location_type;
  181. UAS_data.System.ClassificationType = (ODID_classification_type_t)system.classification_type;
  182. UAS_data.System.OperatorLatitude = system.operator_latitude * 1.0e-7;
  183. UAS_data.System.OperatorLongitude = system.operator_longitude * 1.0e-7;
  184. UAS_data.System.AreaCount = system.area_count;
  185. UAS_data.System.AreaRadius = system.area_radius;
  186. UAS_data.System.AreaCeiling = system.area_ceiling;
  187. UAS_data.System.AreaFloor = system.area_floor;
  188. UAS_data.System.CategoryEU = (ODID_category_EU_t)system.category_eu;
  189. UAS_data.System.ClassEU = (ODID_class_EU_t)system.class_eu;
  190. UAS_data.System.OperatorAltitudeGeo = system.operator_altitude_geo;
  191. UAS_data.System.Timestamp = system.timestamp;
  192. UAS_data.SystemValid = 1;
  193. }
  194. // Location
  195. if (location.timestamp != 0) {
  196. UAS_data.Location.Status = (ODID_status_t)location.status;
  197. UAS_data.Location.Direction = location.direction*0.01;
  198. UAS_data.Location.SpeedHorizontal = location.speed_horizontal*0.01;
  199. UAS_data.Location.SpeedVertical = location.speed_vertical*0.01;
  200. UAS_data.Location.Latitude = location.latitude*1.0e-7;
  201. UAS_data.Location.Longitude = location.longitude*1.0e-7;
  202. UAS_data.Location.AltitudeBaro = location.altitude_barometric;
  203. UAS_data.Location.AltitudeGeo = location.altitude_geodetic;
  204. UAS_data.Location.HeightType = (ODID_Height_reference_t)location.height_reference;
  205. UAS_data.Location.Height = location.height;
  206. UAS_data.Location.HorizAccuracy = (ODID_Horizontal_accuracy_t)location.horizontal_accuracy;
  207. UAS_data.Location.VertAccuracy = (ODID_Vertical_accuracy_t)location.vertical_accuracy;
  208. UAS_data.Location.BaroAccuracy = (ODID_Vertical_accuracy_t)location.barometer_accuracy;
  209. UAS_data.Location.SpeedAccuracy = (ODID_Speed_accuracy_t)location.speed_accuracy;
  210. UAS_data.Location.TSAccuracy = (ODID_Timestamp_accuracy_t)location.timestamp_accuracy;
  211. UAS_data.Location.TimeStamp = location.timestamp;
  212. UAS_data.LocationValid = 1;
  213. }
  214. const char *reason = check_parse();
  215. if (reason == nullptr) {
  216. t.arm_status_check(reason);
  217. }
  218. t.set_parse_fail(reason);
  219. arm_check_ok = (reason==nullptr);
  220. led.set_state(pfst_check_ok && arm_check_ok? Led::LedState::ARM_OK : Led::LedState::ARM_FAIL);
  221. uint32_t now_ms = millis();
  222. uint32_t location_age_ms = now_ms - t.get_last_location_ms();
  223. uint32_t last_location_age_ms = now_ms - last_location_ms;
  224. if (location_age_ms < last_location_age_ms) {
  225. last_location_ms = t.get_last_location_ms();
  226. }
  227. }
  228. static uint8_t loop_counter = 0;
  229. void loop()
  230. {
  231. #if AP_MAVLINK_ENABLED
  232. mavlink1.update();
  233. mavlink2.update();
  234. #endif
  235. #if AP_DRONECAN_ENABLED
  236. dronecan.update();
  237. #endif
  238. const uint32_t now_ms = millis();
  239. if (g.webserver_enable) {
  240. webif.update();
  241. }
  242. // the transports have common static data, so we can just use the
  243. // first for status
  244. #if AP_MAVLINK_ENABLED
  245. auto &transport = mavlink1;
  246. #elif AP_DRONECAN_ENABLED
  247. auto &transport = dronecan;
  248. #else
  249. #error "Must enable DroneCAN or MAVLink"
  250. #endif
  251. bool have_location = false;
  252. const uint32_t last_location_ms = transport.get_last_location_ms();
  253. const uint32_t last_system_ms = transport.get_last_system_ms();
  254. led.update();
  255. if (g.bcast_powerup) {
  256. // if we are broadcasting on powerup we always mark location valid
  257. // so the location with default data is sent
  258. if (!UAS_data.LocationValid) {
  259. UAS_data.Location.Status = ODID_STATUS_REMOTE_ID_SYSTEM_FAILURE;
  260. UAS_data.LocationValid = 1;
  261. }
  262. } else {
  263. // only broadcast if we have received a location at least once
  264. if (last_location_ms == 0) {
  265. delay(1);
  266. return;
  267. }
  268. }
  269. if (last_location_ms == 0 ||
  270. now_ms - last_location_ms > 5000) {
  271. UAS_data.Location.Status = ODID_STATUS_REMOTE_ID_SYSTEM_FAILURE;
  272. }
  273. if (last_system_ms == 0 ||
  274. now_ms - last_system_ms > 5000) {
  275. UAS_data.Location.Status = ODID_STATUS_REMOTE_ID_SYSTEM_FAILURE;
  276. }
  277. if (transport.get_parse_fail() != nullptr) {
  278. UAS_data.Location.Status = ODID_STATUS_REMOTE_ID_SYSTEM_FAILURE;
  279. }
  280. set_data(transport);
  281. static uint32_t last_update_wifi_ms;
  282. if (g.wifi_nan_rate > 0 &&
  283. now_ms - last_update_wifi_ms > 1000/g.wifi_nan_rate) {
  284. last_update_wifi_ms = now_ms;
  285. wifi.transmit(UAS_data);
  286. }
  287. static uint32_t last_update_bt5_ms;
  288. if (g.bt5_rate > 0 &&
  289. now_ms - last_update_bt5_ms > 1000/g.bt5_rate) {
  290. last_update_bt5_ms = now_ms;
  291. ble.transmit_longrange(UAS_data);
  292. }
  293. static uint32_t last_update_bt4_ms;
  294. if (g.bt4_rate > 0 &&
  295. now_ms - last_update_bt4_ms > 200/g.bt4_rate) {
  296. last_update_bt4_ms = now_ms;
  297. ble.transmit_legacy(UAS_data);
  298. ble.transmit_legacy_name(UAS_data);
  299. }
  300. // sleep for a bit for power saving
  301. delay(1);
  302. }