mavlink.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. /*
  2. mavlink class for handling OpenDroneID messages
  3. */
  4. #include <Arduino.h>
  5. #include "mavlink.h"
  6. #include "board_config.h"
  7. #include "version.h"
  8. #include "parameters.h"
  9. #define SERIAL_BAUD 115200
  10. static HardwareSerial *serial_ports[MAVLINK_COMM_NUM_BUFFERS];
  11. #include <generated/mavlink_helpers.h>
  12. mavlink_system_t mavlink_system = {0, MAV_COMP_ID_ODID_TXRX_1};
  13. /*
  14. send a buffer out a MAVLink channel
  15. 函数作用:把字节缓冲区通过指定MAVLink通道发送出去
  16. */
  17. void comm_send_buffer(mavlink_channel_t chan, const uint8_t *buf, uint8_t len)
  18. {
  19. if (chan >= MAVLINK_COMM_NUM_BUFFERS || serial_ports[uint8_t(chan)] == nullptr) {
  20. return; // 通道号超出支持范围 通道对应的串口未绑定(空指针)
  21. }
  22. auto &serial = *serial_ports[uint8_t(chan)]; // 从全局数组中获取通道对应的物理串口引用
  23. serial.write(buf, len); // 把字节缓冲区写入串口(核心:完成物理发送)
  24. }
  25. /*
  26. abstraction for MAVLink on a serial port
  27. */
  28. MAVLinkSerial::MAVLinkSerial(HardwareSerial &_serial, mavlink_channel_t _chan) :
  29. serial(_serial), // 绑定物理串口(如Serial1)到类成员serial
  30. chan(_chan) // 绑定MAVLink通道号(如MAVLINK_COMM_0)到类成员chan
  31. {
  32. serial_ports[uint8_t(_chan - MAVLINK_COMM_0)] = &serial; // 函数体:将串口指针存入全局数组serial_ports
  33. }
  34. void MAVLinkSerial::init(void)
  35. {
  36. // print banner at startup
  37. serial.printf("ArduRemoteID version %u.%u %08x\n",
  38. FW_VERSION_MAJOR, FW_VERSION_MINOR, GIT_VERSION);
  39. mavlink_system.sysid = g.mavlink_sysid; // 初始化MAVLink系统ID:从全局配置g中读取预设的mavlink_sysid
  40. }
  41. // 地面站(如 Mission Planner)会向 RemoteID 模块发送 PARAM_REQUEST_LIST 消息,
  42. // 请求获取所有参数(如 UIN、运营人 ID、发送频率等),
  43. // 这段代码就是按 50ms 间隔逐个回复参数值,方便地面站配置 / 查看 RemoteID 模块的参数。
  44. void MAVLinkSerial::update(void)
  45. {
  46. const uint32_t now_ms = millis();
  47. if (mavlink_system.sysid != 0) { // 分支1:如果MAVLink系统ID已初始化(非0)
  48. update_send(); // 执行MAVLink消息发送逻辑
  49. } else if (g.mavlink_sysid != 0) { // 分支2:如果系统ID未初始化,但配置了g.mavlink_sysid(外部配置)
  50. mavlink_system.sysid = g.mavlink_sysid; // 用配置值初始化系统ID
  51. } else if (now_ms - last_hb_warn_ms >= 2000) { // 分支3:系统ID未初始化,且无配置 → 打印心跳等待提示(每2秒一次)
  52. last_hb_warn_ms = millis();
  53. serial.printf("Waiting for heartbeat\n"); // 串口打印:等待飞控心跳
  54. // serial.printf("等待心跳包\n");
  55. }
  56. update_receive(); // 接收串口数据,解析飞控发来的MAVLink消息
  57. // 如果参数请求未完成,且距离上次发送超过50ms
  58. if (param_request_last_ms != 0 && now_ms - param_request_last_ms > 50) {
  59. param_request_last_ms = now_ms;
  60. float value;
  61. if (param_next->get_as_float(value)) { // 读取下一个参数的浮点值(如UIN、运营人ID转的浮点/字符串)
  62. // 发送MAVLink PARAM_VALUE消息(回复地面站的参数查询)
  63. mavlink_msg_param_value_send(chan, // MAVLink通道
  64. param_next->name, value, // 参数名(如"UIN"、"OPERATOR_ID") // 参数值
  65. MAV_PARAM_TYPE_REAL32, // 参数类型(浮点型)
  66. g.param_count_float(), // 浮点参数总数
  67. g.param_index_float(param_next)); // 当前参数索引
  68. }
  69. param_next++; // 指向下一个参数
  70. if (param_next->ptype == Parameters::ParamType::NONE) { // 如果参数遍历完成 → 重置状态
  71. param_next = nullptr;
  72. param_request_last_ms = 0;
  73. }
  74. }
  75. }
  76. /*
  77. RemoteID 模块每秒向飞控 / 地面站发送 MAVLink 心跳包(标识自身为 ODID 设备),
  78. 并附带发送无人机解锁状态—— 让飞控 / 地面站识别
  79. “这是一个 RemoteID 设备”,并知晓无人机的解锁 / 上锁状态
  80. */
  81. void MAVLinkSerial::update_send(void)
  82. {
  83. uint32_t now_ms = millis();
  84. if (now_ms - last_hb_ms >= 1000) {
  85. last_hb_ms = now_ms;
  86. mavlink_msg_heartbeat_send(
  87. chan,
  88. MAV_TYPE_ODID,
  89. MAV_AUTOPILOT_INVALID,
  90. 0,
  91. 0,
  92. 0);
  93. // send arming status
  94. arm_status_send();
  95. }
  96. }
  97. void MAVLinkSerial::update_receive(void) // 流式处理 一次处理缓冲区所有数据 然后解析
  98. {
  99. // receive new packets
  100. mavlink_message_t msg; // 1. 定义MAVLink消息结构体(存储解析后的完整消息)
  101. mavlink_status_t status; // 2. 定义MAVLink状态结构体(记录解析状态,如丢包、同步等)
  102. status.packet_rx_drop_count = 0; // 3. 重置丢包计数(初始化解析状态)
  103. const uint16_t nbytes = serial.available(); // 4. 获取串口缓冲区中待读取的字节数
  104. for (uint16_t i=0; i<nbytes; i++) { // 5. 遍历读取所有字节,逐字节解析
  105. const uint8_t c = (uint8_t)serial.read(); // 6. 读取1个字节(飞控发来的MAVLink数据)
  106. // Try to get a new message
  107. if (mavlink_parse_char(chan, c, &msg, &status)) { // 7. 核心:逐字节解析MAVLink消息
  108. process_packet(status, msg); // 8. 解析出完整消息后,交给process_packet()处理(提取位置/状态等核心数据)
  109. }
  110. }
  111. }
  112. /*
  113. printf via MAVLink STATUSTEXT for debugging
  114. 传统串口打印需要现场接电脑调试,而 MAVLink STATUSTEXT 消息可通过飞控转发到地面站,
  115. 即使无人机在空中,也能实时看到 RemoteID 模块的调试日志;
  116. */
  117. void MAVLinkSerial::mav_printf(uint8_t severity, const char *fmt, ...)
  118. {
  119. va_list arg_list; // 1. 定义可变参数列表(处理printf风格的可变参数)
  120. char text[MAVLINK_MSG_STATUSTEXT_FIELD_TEXT_LEN+1] {}; // 2. 定义日志文本缓冲区:长度=STATUSTEXT消息的text字段长度+1(+1是字符串结束符)
  121. va_start(arg_list, fmt); // 3. 初始化可变参数列表,指向fmt后的第一个参数
  122. vsnprintf(text, sizeof(text), fmt, arg_list); // 4. 格式化字符串:把fmt+可变参数写入text缓冲区,限制长度为缓冲区大小
  123. va_end(arg_list); // 5. 结束可变参数列表
  124. // 6. 发送MAVLink STATUSTEXT消息
  125. mavlink_msg_statustext_send(chan, // MAVLink通道号(对应飞控串口
  126. severity, // 日志级别
  127. text, // 格式化后的日志文本
  128. 0, 0); // 扩展参数(MAVLink 2.0新增,暂用0)
  129. }
  130. /*
  131. 专门针对 OpenDroneID(ODID)标准的各类消息做解析,同时处理参数交互、安全指令等辅助逻辑
  132. */
  133. void MAVLinkSerial::process_packet(mavlink_status_t &status, mavlink_message_t &msg)
  134. {
  135. const uint32_t now_ms = millis();
  136. switch (msg.msgid) {
  137. case MAVLINK_MSG_ID_HEARTBEAT: { // 心跳消息处理
  138. mavlink_heartbeat_t hb;
  139. if (mavlink_system.sysid == 0) { // 系统ID未初始化时
  140. mavlink_msg_heartbeat_decode(&msg, &hb); // 仅接收飞控(非地面站GCS)的心跳,初始化模块sysid
  141. if (msg.sysid > 0 && hb.type != MAV_TYPE_GCS) {
  142. mavlink_system.sysid = msg.sysid; // 过滤地面站(GCS)心跳:只从飞控获取 sysid,防止地面站干扰
  143. }
  144. }
  145. break;
  146. }
  147. case MAVLINK_MSG_ID_OPEN_DRONE_ID_LOCATION: { // 位置消息 无人机经纬度、高度、速度、timestamp(时间戳)等位置信息
  148. mavlink_msg_open_drone_id_location_decode(&msg, &location);
  149. if (g.options & OPTIONS_PRINT_RID_MAVLINK) {
  150. Serial.printf("MAVLink: got Location\n");
  151. }
  152. if (last_location_timestamp != location.timestamp) {
  153. //only update the timestamp if we receive information with a different timestamp
  154. last_location_ms = millis();
  155. last_location_timestamp = location.timestamp;
  156. }
  157. last_location_ms = now_ms;
  158. break;
  159. }
  160. case MAVLINK_MSG_ID_OPEN_DRONE_ID_BASIC_ID: { // 基础 ID 消息
  161. mavlink_open_drone_id_basic_id_t basic_id_tmp;
  162. if (g.options & OPTIONS_PRINT_RID_MAVLINK) {
  163. Serial.printf("MAVLink: got BasicID\n");
  164. } // 仅接收有效数据:UAS_ID非空 + ID类型合法(1~MAV_ODID_ID_TYPE_SPECIFIC_SESSION_ID)
  165. mavlink_msg_open_drone_id_basic_id_decode(&msg, &basic_id_tmp);
  166. if ((strlen((const char*) basic_id_tmp.uas_id) > 0) && (basic_id_tmp.id_type > 0) && (basic_id_tmp.id_type <= MAV_ODID_ID_TYPE_SPECIFIC_SESSION_ID)) {
  167. //only update if we receive valid data
  168. basic_id = basic_id_tmp; // 更新本地缓存
  169. last_basic_id_ms = now_ms; // 记录最后接收时间
  170. }
  171. break;
  172. }
  173. case MAVLINK_MSG_ID_OPEN_DRONE_ID_AUTHENTICATION: { // 其他 ODID 消息(认证 / 自描述 / 系统 / 运营商 ID)
  174. mavlink_msg_open_drone_id_authentication_decode(&msg, &authentication);
  175. if (g.options & OPTIONS_PRINT_RID_MAVLINK) {
  176. Serial.printf("MAVLink: got Auth\n");
  177. }
  178. break;
  179. }
  180. case MAVLINK_MSG_ID_OPEN_DRONE_ID_SELF_ID: { // 无人机自描述信息(如机型、用途)
  181. mavlink_msg_open_drone_id_self_id_decode(&msg, &self_id);
  182. if (g.options & OPTIONS_PRINT_RID_MAVLINK) {
  183. Serial.printf("MAVLink: got SelfID\n");
  184. }
  185. last_self_id_ms = now_ms;
  186. break;
  187. }
  188. case MAVLINK_MSG_ID_OPEN_DRONE_ID_SYSTEM: { // 系统信息(运营人位置、高度基准)
  189. mavlink_msg_open_drone_id_system_decode(&msg, &system);
  190. if (g.options & OPTIONS_PRINT_RID_MAVLINK) {
  191. Serial.printf("MAVLink: got System\n");
  192. }
  193. if ((last_system_timestamp != system.timestamp) || (system.timestamp == 0)) {
  194. //only update the timestamp if we receive information with a different timestamp
  195. last_system_ms = millis();
  196. last_system_timestamp = system.timestamp;
  197. }
  198. break;
  199. }
  200. case MAVLINK_MSG_ID_OPEN_DRONE_ID_SYSTEM_UPDATE: { // 运营人位置更新
  201. if (g.options & OPTIONS_PRINT_RID_MAVLINK) {
  202. Serial.printf("MAVLink: got System update\n");
  203. }
  204. mavlink_open_drone_id_system_update_t pkt_system_update;
  205. mavlink_msg_open_drone_id_system_update_decode(&msg, &pkt_system_update);
  206. system.operator_latitude = pkt_system_update.operator_latitude;
  207. system.operator_longitude = pkt_system_update.operator_longitude;
  208. system.operator_altitude_geo = pkt_system_update.operator_altitude_geo;
  209. system.timestamp = pkt_system_update.timestamp;
  210. if (last_system_ms != 0) {
  211. // we can only mark system as updated if we have the other
  212. // information already
  213. if ((last_system_timestamp != system.timestamp) || (pkt_system_update.timestamp == 0)) {
  214. //only update the timestamp if we receive information with a different timestamp
  215. last_system_ms = millis();
  216. last_system_timestamp = pkt_system_update.timestamp;
  217. }
  218. last_system_ms = now_ms;
  219. }
  220. break;
  221. }
  222. case MAVLINK_MSG_ID_OPEN_DRONE_ID_OPERATOR_ID: { // 运营人 ID(如企业名称、联系方式)
  223. mavlink_msg_open_drone_id_operator_id_decode(&msg, &operator_id);
  224. if (g.options & OPTIONS_PRINT_RID_MAVLINK) {
  225. Serial.printf("MAVLink: got OperatorID\n");
  226. }
  227. last_operator_id_ms = now_ms;
  228. break;
  229. }
  230. case MAVLINK_MSG_ID_PARAM_REQUEST_LIST: { // 参数列表请求
  231. param_next = g.find_by_index_float(0);
  232. param_request_last_ms = millis();
  233. break;
  234. };
  235. case MAVLINK_MSG_ID_PARAM_REQUEST_READ: { // 参数读取请求
  236. mavlink_param_request_read_t pkt;
  237. mavlink_msg_param_request_read_decode(&msg, &pkt);
  238. const Parameters::Param *p;
  239. if (pkt.param_index < 0) {
  240. p = g.find(pkt.param_id);
  241. } else {
  242. p = g.find_by_index_float(pkt.param_index);
  243. }
  244. float value;
  245. if (!p || !p->get_as_float(value)) {
  246. return;
  247. }
  248. if (p != nullptr && (p->flags & PARAM_FLAG_HIDDEN)) {
  249. return;
  250. }
  251. mavlink_msg_param_value_send(chan,
  252. p->name, value,
  253. MAV_PARAM_TYPE_REAL32,
  254. g.param_count_float(),
  255. g.param_index_float(p));
  256. break;
  257. }
  258. case MAVLINK_MSG_ID_PARAM_SET: { // 参数设置
  259. /*
  260. 解析地面站发来的参数设置请求 → 校验参数类型 / 有效性 → 执行锁定安全逻辑(仅允许提高锁定级别)
  261. → 执行参数修改(或拒绝)→ 回复修改后的参数值给地面站确认。
  262. */
  263. mavlink_param_set_t pkt;
  264. mavlink_msg_param_set_decode(&msg, &pkt);
  265. auto *p = g.find(pkt.param_id);
  266. float value;
  267. if (pkt.param_type != MAV_PARAM_TYPE_REAL32 ||
  268. !p || !p->get_as_float(value)) {
  269. return;
  270. }
  271. p->get_as_float(value);
  272. /*
  273. 当模块锁定(lock_level>0)时,只要满足「修改的不是 LOCK_LEVEL 参数」OR「修改 LOCK_LEVEL 但新值≤当前值」
  274. 其中一个条件,就拒绝修改;
  275. 只有「修改 LOCK_LEVEL 且新值 > 当前值」才允许。
  276. */
  277. if (g.lock_level > 0 &&
  278. (strcmp(p->name, "LOCK_LEVEL") != 0 ||
  279. uint8_t(pkt.param_value) <= uint8_t(value))) {
  280. // only param set allowed is to increase lock level
  281. mav_printf(MAV_SEVERITY_ERROR, "Parameters locked");
  282. } else { // 不满足条件 → 允许修改(仅两种情况:1.未锁定;2.锁定但提高LOCK_LEVEL)
  283. p->set_as_float(pkt.param_value);
  284. }
  285. p->get_as_float(value);
  286. mavlink_msg_param_value_send(chan,
  287. p->name, value,
  288. MAV_PARAM_TYPE_REAL32,
  289. g.param_count_float(),
  290. g.param_index_float(p));
  291. break;
  292. }
  293. case MAVLINK_MSG_ID_SECURE_COMMAND: // 安全指令处理
  294. case MAVLINK_MSG_ID_SECURE_COMMAND_REPLY: {
  295. mavlink_secure_command_t pkt;
  296. mavlink_msg_secure_command_decode(&msg, &pkt);
  297. handle_secure_command(pkt);
  298. break;
  299. }
  300. default: // 默认分支
  301. // we don't care about other packets
  302. break;
  303. }
  304. }
  305. void MAVLinkSerial::arm_status_send(void)
  306. { // 1. 判定解锁状态码:
  307. const uint8_t status = parse_fail==nullptr?MAV_ODID_ARM_STATUS_GOOD_TO_ARM:MAV_ODID_ARM_STATUS_PRE_ARM_FAIL_GENERIC;
  308. const char *reason = parse_fail==nullptr?"":parse_fail; // 2. 判定失败原因:
  309. mavlink_msg_open_drone_id_arm_status_send( // 3. 发送MAVLink OpenDroneID解锁状态消息(ODID标准消息)
  310. chan,
  311. status,
  312. reason);
  313. }