Line data Source code
1 : /*
2 : Common GCS MAVLink functions for all vehicle types
3 :
4 : This program is free software: you can redistribute it and/or modify
5 : it under the terms of the GNU General Public License as published by
6 : the Free Software Foundation, either version 3 of the License, or
7 : (at your option) any later version.
8 :
9 : This program is distributed in the hope that it will be useful,
10 : but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : GNU General Public License for more details.
13 :
14 : You should have received a copy of the GNU General Public License
15 : along with this program. If not, see <http://www.gnu.org/licenses/>.
16 : */
17 :
18 : #include "GCS_config.h"
19 :
20 : #if HAL_GCS_ENABLED
21 :
22 : #include "GCS.h"
23 :
24 : #include <AC_Fence/AC_Fence.h>
25 : #include <AP_Compass/AP_Compass.h>
26 : #include <AP_ADSB/AP_ADSB.h>
27 : #include <AP_AdvancedFailsafe/AP_AdvancedFailsafe.h>
28 : #include <AP_AHRS/AP_AHRS.h>
29 : #include <AP_HAL/AP_HAL.h>
30 : #include <AP_Arming/AP_Arming.h>
31 : #include <AP_InternalError/AP_InternalError.h>
32 : #include <AP_Logger/AP_Logger.h>
33 : #include <AP_OpticalFlow/AP_OpticalFlow.h>
34 : #include <AP_Vehicle/AP_Vehicle.h>
35 : #include <AP_RangeFinder/AP_RangeFinder.h>
36 : #include <AP_RangeFinder/AP_RangeFinder_Backend.h>
37 : #include <AP_Airspeed/AP_Airspeed.h>
38 : #include <AP_Camera/AP_Camera.h>
39 : #include <AP_Gripper/AP_Gripper.h>
40 : #include <AC_Sprayer/AC_Sprayer.h>
41 : #include <AP_BLHeli/AP_BLHeli.h>
42 : #include <AP_Relay/AP_Relay.h>
43 : #include <AP_RSSI/AP_RSSI.h>
44 : #include <AP_RTC/AP_RTC.h>
45 : #include <AP_Scheduler/AP_Scheduler.h>
46 : #include <AP_SerialManager/AP_SerialManager.h>
47 : #include <AP_RCTelemetry/AP_Spektrum_Telem.h>
48 : #include <AP_Mount/AP_Mount.h>
49 : #include <AP_Common/AP_FWVersion.h>
50 : #include <AP_VisualOdom/AP_VisualOdom.h>
51 : #include <AP_Baro/AP_Baro.h>
52 : #include <AP_EFI/AP_EFI.h>
53 : #include <AP_Proximity/AP_Proximity.h>
54 : #include <AP_Scripting/AP_Scripting.h>
55 : #include <SRV_Channel/SRV_Channel.h>
56 : #include <AP_Terrain/AP_Terrain.h>
57 : #include <AP_Winch/AP_Winch.h>
58 : #include <AP_Mission/AP_Mission.h>
59 : #include <AP_OpenDroneID/AP_OpenDroneID.h>
60 : #include <AP_OSD/AP_OSD.h>
61 : #include <AP_RCTelemetry/AP_CRSF_Telem.h>
62 : #include <AP_RPM/AP_RPM.h>
63 : #include <AP_AIS/AP_AIS.h>
64 : #include <AP_Filesystem/AP_Filesystem.h>
65 : #include <AP_Frsky_Telem/AP_Frsky_Telem.h>
66 : #include <RC_Channel/RC_Channel.h>
67 : #include <AP_VisualOdom/AP_VisualOdom.h>
68 : #include <AP_LandingGear/AP_LandingGear.h>
69 : #include <AP_Landing/AP_Landing_config.h>
70 : #include <AP_Generator/AP_Generator_Loweheiser.h>
71 :
72 : #include "MissionItemProtocol_Waypoints.h"
73 : #include "MissionItemProtocol_Rally.h"
74 : #include "MissionItemProtocol_Fence.h"
75 :
76 : #include <AP_CANManager/AP_MAVLinkCAN.h>
77 :
78 : #include <AP_Notify/AP_Notify.h>
79 : #include <AP_Vehicle/AP_Vehicle_config.h>
80 :
81 : #include <stdio.h>
82 :
83 : #if AP_RADIO_ENABLED
84 : #include <AP_Radio/AP_Radio.h>
85 : #include <AP_BoardConfig/AP_BoardConfig.h>
86 : #endif
87 :
88 : #if CONFIG_HAL_BOARD == HAL_BOARD_SITL
89 : #include <SITL/SITL.h>
90 : #endif
91 :
92 : #if HAL_MAX_CAN_PROTOCOL_DRIVERS
93 : #include <AP_CANManager/AP_CANManager.h>
94 : #include <AP_Common/AP_Common.h>
95 :
96 : #include <AP_PiccoloCAN/AP_PiccoloCAN.h>
97 : #include <AP_DroneCAN/AP_DroneCAN.h>
98 : #endif
99 :
100 : #include <AP_BattMonitor/AP_BattMonitor_config.h>
101 : #if AP_BATTERY_ENABLED
102 : #include <AP_BattMonitor/AP_BattMonitor.h>
103 : #endif
104 : #include <AP_GPS/AP_GPS.h>
105 :
106 : #include <AP_RCProtocol/AP_RCProtocol_config.h>
107 : #if AP_RCPROTOCOL_ENABLED
108 : #include <AP_RCProtocol/AP_RCProtocol.h>
109 : #endif
110 :
111 : #if HAL_WITH_IO_MCU
112 : #include <AP_IOMCU/AP_IOMCU.h>
113 : extern AP_IOMCU iomcu;
114 : #endif
115 :
116 : #include "GCS_FTP.h"
117 :
118 : #include <ctype.h>
119 :
120 : extern const AP_HAL::HAL& hal;
121 :
122 : struct GCS_MAVLINK::LastRadioStatus GCS_MAVLINK::last_radio_status;
123 : mavlink_channel_mask_t GCS_MAVLINK::mavlink_active = 0;
124 : mavlink_channel_mask_t GCS_MAVLINK::chan_is_streaming = 0;
125 : uint32_t GCS_MAVLINK::reserve_param_space_start_ms;
126 :
127 : // private channels are ones used for point-to-point protocols, and
128 : // don't get broadcasts or fwded packets
129 : mavlink_channel_mask_t GCS_MAVLINK::mavlink_private = 0;
130 :
131 : GCS *GCS::_singleton = nullptr;
132 :
133 : GCS_MAVLINK_InProgress GCS_MAVLINK_InProgress::in_progress_tasks[1];
134 : uint32_t GCS_MAVLINK_InProgress::last_check_ms;
135 :
136 133140 : GCS_MAVLINK::GCS_MAVLINK(AP_HAL::UARTDriver &uart)
137 : {
138 6340 : AP_Param::setup_object_defaults(this, var_info);
139 :
140 6340 : _port = &uart;
141 6340 : }
142 :
143 6340 : bool GCS_MAVLINK::init(uint8_t instance)
144 : {
145 : // get associated mavlink channel
146 6340 : chan = (mavlink_channel_t)(MAVLINK_COMM_0 + instance);
147 6340 : if (!valid_channel(chan)) {
148 0 : return false;
149 : }
150 :
151 : // find instance of MAVLink protocol; the protocol_match method in
152 : // AP_SerialManager means this will match MAVLink2 and MAVLinkHL,
153 : // too:
154 6340 : uartstate = AP::serialmanager().find_protocol_instance(AP_SerialManager::SerialProtocol_MAVLink, instance);
155 6340 : if (uartstate == nullptr) {
156 0 : return false;
157 : }
158 :
159 : // fill in the device ID (a parameter which allows a user to
160 : // understand what their MAVn_ parameters actually correspond to)
161 6340 : devid.set(uartstate->get_device_id());
162 :
163 : // PARAMETER_CONVERSION - Added: May-2025 for ArduPilot-4.7
164 : // convert parameters; we used to use bits in the UARTDriver to
165 : // remember whether the mavlink connection on that interface was
166 : // "private" or not, and whether to ignore streamrate sets via
167 : // REQUEST_DATA_STREAM. We moved that into the MAVn_OPTIONS, this
168 : // is the conversion:
169 6340 : if (!options_were_converted) {
170 919 : auto &sm = AP::serialmanager();
171 919 : options_were_converted.set_and_save(1);
172 919 : if (_port->option_is_set(AP_HAL::UARTDriver::Option::OPTION_MAVLINK_NO_FORWARD_old)) {
173 0 : enable_option(Option::NO_FORWARD);
174 : // turn the bit off in the UART options. We can only get
175 : // away with this because we are (in a very nearby commit)
176 : // changing the width of the SERIALn_OPTIONS. This means
177 : // older firmwares will still see the SERIALn_OPTIONS bits
178 : // as set, newer firmwares will see zeroes. We have a
179 : // prearm check that users have not set the old bit.
180 : // Sorry.
181 0 : sm.disable_option(uartstate->idx, AP_HAL::UARTDriver::Option::OPTION_MAVLINK_NO_FORWARD_old);
182 : }
183 919 : if (_port->option_is_set(AP_HAL::UARTDriver::Option::OPTION_NOSTREAMOVERRIDE_old)) {
184 0 : enable_option(Option::NOSTREAMOVERRIDE);
185 : // turn the bit off in the UART options. We can only get
186 : // away with this because we are (in a very nearby commit)
187 : // changing the width of the SERIALn_OPTIONS. This means
188 : // older firmwares will still see the SERIALn_OPTIONS bits
189 : // as set, newer firmwares will see zeroes. We have a
190 : // prearm check that users have not set the old bit.
191 : // Sorry.
192 0 : sm.disable_option(uartstate->idx, AP_HAL::UARTDriver::Option::OPTION_NOSTREAMOVERRIDE_old);
193 : }
194 : }
195 :
196 : // and init the gcs instance
197 :
198 : // whether this port is considered "private":
199 6340 : if (option_enabled(Option::NO_FORWARD)) {
200 11 : set_channel_private(chan);
201 : }
202 :
203 : /*
204 : Now try to cope with SiK radios that may be stuck in bootloader
205 : mode because CTS was held while powering on. This tells the
206 : bootloader to wait for a firmware. It affects any SiK radio with
207 : CTS connected that is externally powered. To cope we send 0x30
208 : 0x20 at 115200 on startup, which tells the bootloader to reset
209 : and boot normally
210 : */
211 6340 : _port->begin(115200);
212 6340 : AP_HAL::UARTDriver::flow_control old_flow_control = _port->get_flow_control();
213 6340 : _port->set_flow_control(AP_HAL::UARTDriver::FLOW_CONTROL_DISABLE);
214 25360 : for (uint8_t i=0; i<3; i++) {
215 19020 : hal.scheduler->delay(1);
216 19020 : _port->write(0x30);
217 19020 : _port->write(0x20);
218 : }
219 : // since tcdrain() and TCSADRAIN may not be implemented...
220 6340 : hal.scheduler->delay(1);
221 :
222 6340 : _port->set_flow_control(old_flow_control);
223 :
224 : // now change back to desired baudrate
225 6340 : _port->begin(uartstate->baudrate());
226 :
227 6340 : mavlink_comm_port[chan] = _port;
228 :
229 6340 : const auto mavlink_protocol = uartstate->get_protocol();
230 :
231 6340 : if (mavlink_protocol == AP_SerialManager::SerialProtocol_MAVLink2 ||
232 : mavlink_protocol == AP_SerialManager::SerialProtocol_MAVLinkHL) {
233 : #if AP_MAVLINK_SIGNING_ENABLED
234 : // load signing key
235 6331 : load_signing_key();
236 : #endif // AP_MAVLINK_SIGNING_ENABLED
237 : } else {
238 : // user has asked to only send MAVLink1
239 9 : _channel_status.flags |= MAVLINK_STATUS_FLAG_OUT_MAVLINK1;
240 : }
241 :
242 : #if HAL_HIGH_LATENCY2_ENABLED
243 6340 : if (mavlink_protocol == AP_SerialManager::SerialProtocol_MAVLinkHL) {
244 2 : is_high_latency_link = true;
245 : }
246 : #endif
247 6340 : return true;
248 : }
249 :
250 1117088 : void GCS_MAVLINK::send_meminfo(void)
251 : {
252 1117088 : unsigned __brkval = 0;
253 1117088 : uint32_t memory = hal.util->available_memory();
254 1117088 : mavlink_msg_meminfo_send(chan, __brkval, MIN(memory, 0xFFFFU), memory);
255 1117088 : }
256 :
257 : // report power supply status
258 1117088 : void GCS_MAVLINK::send_power_status(void)
259 : {
260 1117088 : if (!gcs().vehicle_initialised()) {
261 : // avoid unnecessary errors being reported to user
262 243 : return;
263 : }
264 3350535 : mavlink_msg_power_status_send(chan,
265 1116845 : hal.analogin->board_voltage() * 1000,
266 1116845 : hal.analogin->servorail_voltage() * 1000,
267 1116845 : hal.analogin->power_status_flags());
268 : }
269 :
270 : #if AP_SCHEDULER_ENABLED
271 : // cap the MAVLink message rate. It can't be greater than 0.8 * SCHED_LOOP_RATE
272 441903 : uint16_t GCS_MAVLINK::cap_message_interval(uint16_t interval_ms) const
273 : {
274 441903 : if (interval_ms == 0) {
275 154942 : return 0;
276 : }
277 286961 : if (interval_ms*800 < AP::scheduler().get_loop_period_us()) {
278 1 : return AP::scheduler().get_loop_period_us()/800.0f;
279 : }
280 286960 : return interval_ms;
281 : }
282 : #endif
283 :
284 : #if HAL_WITH_MCU_MONITORING
285 : // report MCU voltage/temperature status
286 : void GCS_MAVLINK::send_mcu_status(void)
287 : {
288 : if (!gcs().vehicle_initialised()) {
289 : // avoid unnecessary errors being reported to user
290 : return;
291 : }
292 : mavlink_msg_mcu_status_send(chan,
293 : 0, // only one MCU
294 : hal.analogin->mcu_temperature() * 100,
295 : hal.analogin->mcu_voltage() * 1000,
296 : hal.analogin->mcu_voltage_min() * 1000,
297 : hal.analogin->mcu_voltage_max() * 1000);
298 : }
299 : #endif
300 :
301 : #if AP_BATTERY_ENABLED
302 : // returns the battery remaining percentage if valid, -1 otherwise
303 1986617 : int8_t GCS_MAVLINK::battery_remaining_pct(const uint8_t instance) const {
304 : uint8_t percentage;
305 1986617 : return AP::battery().capacity_remaining_pct(percentage, instance) ? MIN(percentage, INT8_MAX) : -1;
306 : }
307 :
308 868214 : void GCS_MAVLINK::send_battery_status(const uint8_t instance) const
309 : {
310 : // catch the battery backend not supporting the required number of cells
311 : static_assert(sizeof(AP_BattMonitor::cells) >= (sizeof(uint16_t) * MAVLINK_MSG_BATTERY_STATUS_FIELD_VOLTAGES_LEN),
312 : "Not enough battery cells for the MAVLink message");
313 :
314 868214 : const AP_BattMonitor &battery = AP::battery();
315 : float temp;
316 868214 : bool got_temperature = battery.get_temperature(temp, instance);
317 :
318 : // prepare arrays of individual cell voltages
319 : uint16_t cell_mvolts[MAVLINK_MSG_BATTERY_STATUS_FIELD_VOLTAGES_LEN];
320 : uint16_t cell_mvolts_ext[MAVLINK_MSG_BATTERY_STATUS_FIELD_VOLTAGES_EXT_LEN];
321 868214 : const uint16_t max_cell_mV = 0xFFFEU;
322 868214 : const uint16_t invalid_cell_mV = 0xFFFFU;
323 :
324 868214 : if (battery.has_cell_voltages(instance)) {
325 302 : const AP_BattMonitor::cells& batt_cells = battery.get_cell_voltages(instance);
326 : static_assert(sizeof(cell_mvolts) <= sizeof(batt_cells.cells), "cell array length not large enough");
327 :
328 : // copy the first 10 cells
329 302 : memcpy(cell_mvolts, batt_cells.cells, sizeof(cell_mvolts));
330 : // 11 ... 14 use a second cell_volts_ext array
331 1510 : for (uint8_t i = 0; i < MAVLINK_MSG_BATTERY_STATUS_FIELD_VOLTAGES_EXT_LEN; i++) {
332 1208 : if (MAVLINK_MSG_BATTERY_STATUS_FIELD_VOLTAGES_LEN+i < uint8_t(ARRAY_SIZE(batt_cells.cells))) {
333 1208 : cell_mvolts_ext[i] = batt_cells.cells[MAVLINK_MSG_BATTERY_STATUS_FIELD_VOLTAGES_LEN+i];
334 : } else {
335 0 : cell_mvolts_ext[i] = 0;
336 : }
337 : }
338 : /*
339 : now adjust voltages to cope with two things:
340 : 1) we may be reporting sag corrected voltage
341 : 2) the battery may have more cells than can be reported by the backend, so the actual voltage may be higher than the sum
342 : */
343 302 : const float voltage_mV = battery.gcs_voltage(instance) * 1e3f;
344 302 : float voltage_mV_sum = 0;
345 302 : uint8_t non_zero_cell_count = 0;
346 3322 : for (uint8_t i=0; i<MAVLINK_MSG_BATTERY_STATUS_FIELD_VOLTAGES_LEN; i++) {
347 3020 : if (cell_mvolts[i] > 0 && cell_mvolts[i] != invalid_cell_mV) {
348 2901 : non_zero_cell_count++;
349 2901 : voltage_mV_sum += cell_mvolts[i];
350 : }
351 : }
352 1510 : for (uint8_t i=0; i<MAVLINK_MSG_BATTERY_STATUS_FIELD_VOLTAGES_EXT_LEN; i++) {
353 1208 : if (cell_mvolts_ext[i] > 0 && cell_mvolts_ext[i] != invalid_cell_mV) {
354 1140 : non_zero_cell_count++;
355 1140 : voltage_mV_sum += cell_mvolts_ext[i];
356 : }
357 : }
358 302 : if (voltage_mV > voltage_mV_sum && non_zero_cell_count > 0) {
359 : // distribute the extra voltage over the non-zero cells
360 283 : uint32_t extra_mV = (voltage_mV - voltage_mV_sum) / non_zero_cell_count;
361 3113 : for (uint8_t i=0; i<MAVLINK_MSG_BATTERY_STATUS_FIELD_VOLTAGES_LEN; i++) {
362 2830 : if (cell_mvolts[i] > 0 && cell_mvolts[i] != invalid_cell_mV) {
363 2830 : cell_mvolts[i] = MIN(cell_mvolts[i] + extra_mV, max_cell_mV);
364 : }
365 : }
366 1415 : for (uint8_t i=0; i<MAVLINK_MSG_BATTERY_STATUS_FIELD_VOLTAGES_EXT_LEN; i++) {
367 1132 : if (cell_mvolts_ext[i] > 0 && cell_mvolts_ext[i] != invalid_cell_mV) {
368 1132 : cell_mvolts_ext[i] = MIN(cell_mvolts_ext[i] + extra_mV, max_cell_mV);
369 : }
370 : }
371 : }
372 : } else {
373 : // for battery monitors that cannot provide voltages for individual cells the battery's total voltage is put into the first cell
374 : // if the total voltage cannot fit into a single field, the remainder into subsequent fields.
375 : // the GCS can then recover the pack voltage by summing all non ignored cell values an we can report a pack up to 655.34 V
376 867912 : float voltage_mV = battery.gcs_voltage(instance) * 1e3f;
377 9547032 : for (uint8_t i = 0; i < MAVLINK_MSG_BATTERY_STATUS_FIELD_VOLTAGES_LEN; i++) {
378 8679120 : if (voltage_mV < 0.001f) {
379 : // too small to send to the GCS, set it to the no cell value
380 7812677 : cell_mvolts[i] = UINT16_MAX;
381 : } else {
382 866443 : cell_mvolts[i] = MIN(voltage_mV, max_cell_mV); // Can't send more then UINT16_MAX - 1 in a cell
383 866443 : voltage_mV -= max_cell_mV;
384 : }
385 : }
386 4339560 : for (uint8_t i = 0; i < MAVLINK_MSG_BATTERY_STATUS_FIELD_VOLTAGES_EXT_LEN; i++) {
387 3471648 : cell_mvolts_ext[i] = 0;
388 : }
389 : }
390 :
391 : float current, consumed_mah, consumed_wh;
392 868214 : const int8_t percentage = battery_remaining_pct(instance);
393 :
394 868214 : if (battery.current_amps(current, instance)) {
395 868214 : current = constrain_float(current * 100,-INT16_MAX,INT16_MAX);
396 : } else {
397 0 : current = -1;
398 : }
399 868214 : if (!battery.consumed_mah(consumed_mah, instance)) {
400 0 : consumed_mah = -1;
401 : }
402 868214 : if (battery.consumed_wh(consumed_wh, instance)) {
403 867639 : consumed_wh *= 36;
404 : } else {
405 575 : consumed_wh = -1;
406 : }
407 : uint32_t time_remaining;
408 868214 : if (!battery.time_remaining(time_remaining, instance)) {
409 868214 : time_remaining = 0;
410 : }
411 :
412 1736730 : mavlink_msg_battery_status_send(chan,
413 : instance, // id
414 : MAV_BATTERY_FUNCTION_UNKNOWN, // function
415 : MAV_BATTERY_TYPE_UNKNOWN, // type
416 302 : got_temperature ? ((int16_t) (temp * 100)) : INT16_MAX, // temperature. INT16_MAX if unknown
417 : cell_mvolts, // cell voltages
418 : current, // current in centiampere
419 : consumed_mah, // total consumed current in milliampere.hour
420 : consumed_wh, // consumed energy in hJ (hecto-Joules)
421 868214 : constrain_int16(percentage, -1, 100),
422 : time_remaining, // time remaining, seconds
423 868214 : battery.get_mavlink_charge_state(instance), // battery charge state
424 : cell_mvolts_ext, // Cell 11..14 voltages
425 : 0, // battery mode
426 : battery.get_mavlink_fault_bitmask(instance)); // fault_bitmask
427 868214 : }
428 :
429 : // returns true if all battery instances were reported
430 1117755 : bool GCS_MAVLINK::send_battery_status()
431 : {
432 1117755 : const AP_BattMonitor &battery = AP::battery();
433 :
434 10274545 : for(uint8_t i = 0; i < AP_BATT_MONITOR_MAX_INSTANCES; i++) {
435 10025004 : const uint8_t battery_id = (last_battery_status_idx + 1) % AP_BATT_MONITOR_MAX_INSTANCES;
436 10025004 : const auto configured_type = battery.configured_type(battery_id);
437 868844 : if (configured_type != AP_BattMonitor::Type::NONE &&
438 10893848 : configured_type == battery.allocated_type(battery_id) &&
439 868230 : !battery.option_is_set(battery_id, AP_BattMonitor_Params::Options::InternalUseOnly)) {
440 868214 : CHECK_PAYLOAD_SIZE(BATTERY_STATUS);
441 868214 : send_battery_status(battery_id);
442 868214 : last_battery_status_idx = battery_id;
443 868214 : return true;
444 : } else {
445 9156790 : last_battery_status_idx = battery_id;
446 : }
447 : }
448 249541 : return true;
449 : }
450 : #endif // AP_BATTERY_ENABLED
451 :
452 : #if AP_RANGEFINDER_ENABLED
453 107705 : void GCS_MAVLINK::send_distance_sensor(const AP_RangeFinder_Backend *sensor, const uint8_t instance) const
454 : {
455 107705 : if (!sensor->has_data()) {
456 1760 : return;
457 : }
458 :
459 105945 : int8_t quality_pct = sensor->signal_quality_pct();
460 : // ardupilot defines this field as -1 is unknown, 0 is poor, 100 is excellent
461 : // mavlink defines this field as 0 is unknown, 1 is invalid, 100 is perfect
462 : uint8_t quality;
463 105945 : if (quality_pct == RangeFinder::SIGNAL_QUALITY_UNKNOWN) {
464 94000 : quality = 0;
465 11945 : } else if (quality_pct > 1 && quality_pct <= RangeFinder::SIGNAL_QUALITY_MAX) {
466 11113 : quality = quality_pct;
467 : } else {
468 832 : quality = 1;
469 : }
470 :
471 105945 : mavlink_msg_distance_sensor_send(
472 105945 : chan,
473 : AP_HAL::millis(), // time since system boot TODO: take time of measurement
474 105945 : MIN(sensor->min_distance() * 100, 65535),// minimum distance the sensor can measure in centimeters
475 105945 : MIN(sensor->max_distance() * 100, 65535),// maximum distance the sensor can measure in centimeters
476 211890 : MIN(sensor->distance() * 100, 65535), // current distance reading
477 105945 : sensor->get_mav_distance_sensor_type(), // type from MAV_DISTANCE_SENSOR enum
478 : instance, // onboard ID of the sensor == instance
479 105945 : sensor->orientation(), // direction the sensor faces from MAV_SENSOR_ORIENTATION enum
480 : 0, // Measurement covariance in centimeters, 0 for unknown / invalid readings
481 : 0, // horizontal FOV
482 : 0, // vertical FOV
483 : (const float *)nullptr, // quaternion of sensor orientation for MAV_SENSOR_ROTATION_CUSTOM
484 : quality); // Signal quality of the sensor. 0 = unknown/unset signal quality, 1 = invalid signal, 100 = perfect signal.
485 : }
486 : #endif // AP_RANGEFINDER_ENABLED
487 :
488 : // send any and all distance_sensor messages. This starts by sending
489 : // any distance sensors not used by a Proximity sensor, then sends the
490 : // proximity sensor ones.
491 1117775 : void GCS_MAVLINK::send_distance_sensor()
492 : {
493 : #if AP_RANGEFINDER_ENABLED
494 1117775 : RangeFinder *rangefinder = RangeFinder::get_singleton();
495 1117775 : if (rangefinder == nullptr) {
496 0 : return;
497 : }
498 :
499 : // if we have a proximity backend that utilizes rangefinders cull
500 : // sending them here, and allow the later proximity code to manage
501 : // them
502 1117775 : bool filter_possible_proximity_sensors = false;
503 :
504 : #if HAL_PROXIMITY_ENABLED
505 1117775 : AP_Proximity *proximity = AP_Proximity::get_singleton();
506 1117775 : if (proximity != nullptr) {
507 568277 : for (uint8_t i = 0; i < proximity->num_sensors(); i++) {
508 : #if AP_PROXIMITY_RANGEFINDER_ENABLED
509 4669 : if (proximity->get_type(i) == AP_Proximity::Type::RangeFinder) {
510 0 : filter_possible_proximity_sensors = true;
511 : }
512 : #endif
513 : }
514 : }
515 : #endif
516 :
517 12295515 : for (uint8_t i = 0; i < RANGEFINDER_MAX_INSTANCES; i++) {
518 11177741 : if (!HAVE_PAYLOAD_SPACE(chan, DISTANCE_SENSOR)) {
519 1 : return;
520 : }
521 11177740 : AP_RangeFinder_Backend *sensor = rangefinder->get_backend(i);
522 11177740 : if (sensor == nullptr) {
523 11070035 : continue;
524 : }
525 107705 : enum Rotation orient = sensor->orientation();
526 107705 : if (!filter_possible_proximity_sensors ||
527 0 : (orient > ROTATION_YAW_315 && orient != ROTATION_PITCH_90)) {
528 107705 : send_distance_sensor(sensor, i);
529 : }
530 : }
531 : #endif // AP_RANGEFINDER_ENABLED
532 :
533 : #if HAL_PROXIMITY_ENABLED
534 1117774 : send_proximity();
535 : #endif
536 : }
537 :
538 : #if AP_MAVLINK_MSG_RANGEFINDER_SENDING_ENABLED
539 4398 : void GCS_MAVLINK::send_rangefinder() const
540 : {
541 4398 : RangeFinder *rangefinder = RangeFinder::get_singleton();
542 4398 : if (rangefinder == nullptr) {
543 0 : return;
544 : }
545 4398 : AP_RangeFinder_Backend *s = rangefinder->find_instance(ROTATION_PITCH_270);
546 4398 : if (s == nullptr) {
547 0 : return;
548 : }
549 8796 : mavlink_msg_rangefinder_send(
550 4398 : chan,
551 : s->distance(),
552 4398 : s->voltage_mv() * 0.001f);
553 : }
554 : #endif // AP_MAVLINK_MSG_RANGEFINDER_SENDING_ENABLED
555 :
556 : #if HAL_PROXIMITY_ENABLED
557 1117774 : void GCS_MAVLINK::send_proximity()
558 : {
559 1117774 : AP_Proximity *proximity = AP_Proximity::get_singleton();
560 1117774 : if (proximity == nullptr) {
561 554167 : return; // this is wrong, but pretend we sent data and don't requeue
562 : }
563 :
564 : // get min/max distances
565 563607 : const uint16_t dist_min_cm = (uint16_t)(proximity->distance_min_m() * 100.0f); // minimum distance the sensor can measure in centimeters
566 563607 : const uint16_t dist_max_cm = (uint16_t)(proximity->distance_max_m() * 100.0f); // maximum distance the sensor can measure in centimeters
567 :
568 : // send horizontal distances
569 563607 : if (proximity->get_status() == AP_Proximity::Status::Good) {
570 : Proximity_Distance_Array dist_array;
571 3364 : if (proximity->get_horizontal_distances(dist_array)) {
572 26451 : for (uint8_t i = 0; i < PROXIMITY_MAX_DIRECTION; i++) {
573 23512 : if (!HAVE_PAYLOAD_SPACE(chan, DISTANCE_SENSOR)) {
574 0 : return;
575 : }
576 23512 : if (dist_array.valid(i)) {
577 19419 : proximity_ever_valid_bitmask |= (1U << i);
578 4093 : } else if (!(proximity_ever_valid_bitmask & (1U << i))) {
579 : // we've never sent this distance out, so we don't
580 : // need to send an invalid one.
581 1768 : continue;
582 : }
583 21744 : mavlink_msg_distance_sensor_send(
584 : chan,
585 : AP_HAL::millis(), // time since system boot
586 : dist_min_cm, // minimum distance the sensor can measure in centimeters
587 : dist_max_cm, // maximum distance the sensor can measure in centimeters
588 21744 : (uint16_t)(dist_array.distance[i] * 100.0f), // current distance reading
589 : MAV_DISTANCE_SENSOR_LASER, // type from MAV_DISTANCE_SENSOR enum
590 21744 : PROXIMITY_SENSOR_ID_START + i, // onboard ID of the sensor
591 21744 : dist_array.orientation[i], // direction the sensor faces from MAV_SENSOR_ORIENTATION enum
592 : 0, // Measurement covariance in centimeters, 0 for unknown / invalid readings
593 : 0, 0, nullptr, 0);
594 : }
595 : }
596 : }
597 :
598 : // send upward distance
599 : float dist_up_m;
600 563607 : if (proximity->get_upward_distance(dist_up_m)) {
601 1946 : if (!HAVE_PAYLOAD_SPACE(chan, DISTANCE_SENSOR)) {
602 0 : return;
603 : }
604 1946 : mavlink_msg_distance_sensor_send(
605 : chan,
606 : AP_HAL::millis(), // time since system boot
607 : dist_min_cm, // minimum distance the sensor can measure in centimeters
608 : dist_max_cm, // maximum distance the sensor can measure in centimeters
609 1946 : (uint16_t)(dist_up_m * 100.0f), // current distance reading
610 : MAV_DISTANCE_SENSOR_LASER, // type from MAV_DISTANCE_SENSOR enum
611 : PROXIMITY_SENSOR_ID_START + PROXIMITY_MAX_DIRECTION + 1, // onboard ID of the sensor
612 : MAV_SENSOR_ROTATION_PITCH_90, // direction upwards
613 : 0, // Measurement covariance in centimeters, 0 for unknown / invalid readings
614 : 0, 0, nullptr, 0);
615 : }
616 : }
617 : #endif // HAL_PROXIMITY_ENABLED
618 :
619 : #if AP_AHRS_ENABLED
620 : // report AHRS2 state
621 1120989 : void GCS_MAVLINK::send_ahrs2()
622 : {
623 1120989 : const auto *estimates = AP::ahrs().get_secondary_estimates();
624 1120989 : if (estimates == nullptr) {
625 7939 : return;
626 : }
627 :
628 1113050 : const Location &loc = estimates->location;
629 :
630 1113050 : mavlink_msg_ahrs2_send(chan,
631 1113050 : estimates->roll_rad,
632 1113050 : estimates->pitch_rad,
633 1113050 : estimates->yaw_rad,
634 1113050 : loc.alt*1.0e-2f,
635 1113050 : loc.lat,
636 1113050 : loc.lng);
637 : }
638 : #endif // AP_AHRS_ENABLED
639 :
640 14896 : MissionItemProtocol *GCS::get_prot_for_mission_type(const MAV_MISSION_TYPE mission_type) const
641 : {
642 14896 : if (mission_type >= ARRAY_SIZE(missionitemprotocols)) {
643 0 : return nullptr;
644 : }
645 14896 : return missionitemprotocols[mission_type];
646 : }
647 :
648 : // handle a request for the number of items we have stored for a mission type:
649 467 : void GCS_MAVLINK::handle_mission_request_list(const mavlink_message_t &msg)
650 : {
651 : // decode
652 : mavlink_mission_request_list_t packet;
653 467 : mavlink_msg_mission_request_list_decode(&msg, &packet);
654 :
655 467 : MissionItemProtocol *prot = gcs().get_prot_for_mission_type((MAV_MISSION_TYPE)packet.mission_type);
656 467 : if (prot == nullptr) {
657 0 : mavlink_msg_mission_ack_send(chan,
658 0 : msg.sysid,
659 0 : msg.compid,
660 : MAV_MISSION_UNSUPPORTED,
661 0 : packet.mission_type);
662 0 : return;
663 : }
664 :
665 467 : prot->handle_mission_request_list(*this, packet, msg);
666 : }
667 :
668 : /*
669 : handle a MISSION_REQUEST mavlink packet
670 : */
671 5582 : void GCS_MAVLINK::handle_mission_request_int(const mavlink_message_t &msg)
672 : {
673 : // decode
674 : mavlink_mission_request_int_t packet;
675 5582 : mavlink_msg_mission_request_int_decode(&msg, &packet);
676 :
677 5582 : MissionItemProtocol *prot = gcs().get_prot_for_mission_type((MAV_MISSION_TYPE)packet.mission_type);
678 5582 : if (prot == nullptr) {
679 0 : return;
680 : }
681 5582 : prot->handle_mission_request_int(*this, packet, msg);
682 : }
683 :
684 : #if AP_MAVLINK_MSG_MISSION_REQUEST_ENABLED
685 0 : void GCS_MAVLINK::handle_mission_request(const mavlink_message_t &msg)
686 : {
687 : // decode
688 : mavlink_mission_request_t packet;
689 0 : mavlink_msg_mission_request_decode(&msg, &packet);
690 :
691 0 : MissionItemProtocol *prot = gcs().get_prot_for_mission_type((MAV_MISSION_TYPE)packet.mission_type);
692 0 : if (prot == nullptr) {
693 0 : return;
694 : }
695 0 : prot->handle_mission_request(*this, packet, msg);
696 : }
697 : #endif
698 :
699 : // returns a MISSION_STATE numeration value best describing out
700 : // current mission state.
701 1115578 : MISSION_STATE GCS_MAVLINK::mission_state(const AP_Mission &mission) const
702 : {
703 1115578 : if (!mission.present()) {
704 728799 : return MISSION_STATE_NO_MISSION;
705 : }
706 386779 : switch (mission.state()) {
707 57769 : case AP_Mission::mission_state::MISSION_STOPPED:
708 57769 : return MISSION_STATE_NOT_STARTED;
709 322174 : case AP_Mission::mission_state::MISSION_RUNNING:
710 322174 : return MISSION_STATE_ACTIVE;
711 6836 : case AP_Mission::mission_state::MISSION_COMPLETE:
712 6836 : return MISSION_STATE_COMPLETE;
713 : }
714 :
715 : // compiler ensures we can't get here as no default case in above enumeration
716 :
717 0 : return MISSION_STATE_UNKNOWN;
718 : }
719 :
720 1115713 : void GCS_MAVLINK::send_mission_current(const class AP_Mission &mission, uint16_t seq)
721 : {
722 1115713 : auto num_commands = mission.num_commands();
723 1115713 : if (num_commands > 0) {
724 : // exclude home location from the count; see message definition.
725 1031334 : num_commands -= 1;
726 : }
727 :
728 : #if AP_VEHICLE_ENABLED
729 1115713 : const uint8_t mission_mode = AP::vehicle()->current_mode_requires_mission() ? 1 : 0;
730 : #else
731 : const uint8_t mission_mode = 0;
732 : #endif
733 :
734 1115713 : mavlink_msg_mission_current_send(
735 : chan,
736 : seq,
737 : num_commands, // total
738 1115713 : mission_state(mission), // mission_state
739 : mission_mode); // mission_mode
740 1115713 : }
741 :
742 : #if AP_MAVLINK_MISSION_SET_CURRENT_ENABLED
743 : /*
744 : handle a MISSION_SET_CURRENT mavlink packet
745 :
746 : Note that there exists a relatively new mavlink DO command,
747 : MAV_CMD_DO_SET_MISSION_CURRENT which provides an acknowledgement
748 : that the command has been received, rather than the GCS having to
749 : rely on getting back an identical sequence number as some currently
750 : do.
751 : */
752 2250 : void GCS_MAVLINK::handle_mission_set_current(AP_Mission &mission, const mavlink_message_t &msg)
753 : {
754 : // send_received_message_deprecation_warning("MISSION_SET_CURRENT");
755 :
756 : // decode
757 : mavlink_mission_set_current_t packet;
758 2250 : mavlink_msg_mission_set_current_decode(&msg, &packet);
759 :
760 : // set current command
761 2250 : if (mission.set_current_cmd(packet.seq)) {
762 : // because MISSION_SET_CURRENT is a message not a command,
763 : // there is not ACK associated with us successfully changing
764 : // our waypoint. Some GCSs use the fact we return exactly the
765 : // same mission sequence number in this packet as an ACK - so
766 : // if they send a MISSION_SET_CURRENT with seq number of 4
767 : // then they expect to receive a MISSION_CURRENT message with
768 : // exactly that sequence number in it, even if ArduPilot never
769 : // actually holds that as a sequence number (e.g. packet.seq==0).
770 375 : if (HAVE_PAYLOAD_SPACE(chan, MISSION_CURRENT)) {
771 375 : send_mission_current(mission, packet.seq);
772 : } else {
773 : // schedule it for later:
774 0 : send_message(MSG_CURRENT_WAYPOINT);
775 : }
776 : }
777 2250 : }
778 : #endif // AP_MAVLINK_MISSION_SET_CURRENT_ENABLED
779 :
780 : /*
781 : handle a MISSION_COUNT mavlink packet
782 : */
783 3177 : void GCS_MAVLINK::handle_mission_count(const mavlink_message_t &msg)
784 : {
785 : // decode
786 : mavlink_mission_count_t packet;
787 3177 : mavlink_msg_mission_count_decode(&msg, &packet);
788 :
789 3177 : MissionItemProtocol *prot = gcs().get_prot_for_mission_type((MAV_MISSION_TYPE)packet.mission_type);
790 3177 : if (prot == nullptr) {
791 0 : mavlink_msg_mission_ack_send(chan,
792 0 : msg.sysid,
793 0 : msg.compid,
794 : MAV_MISSION_UNSUPPORTED,
795 0 : packet.mission_type);
796 0 : return;
797 : }
798 :
799 3177 : prot->handle_mission_count(*this, packet, msg);
800 : }
801 :
802 : /*
803 : handle a MISSION_CLEAR_ALL mavlink packet
804 : */
805 4 : void GCS_MAVLINK::handle_mission_clear_all(const mavlink_message_t &msg)
806 : {
807 : // decode
808 : mavlink_mission_clear_all_t packet;
809 4 : mavlink_msg_mission_clear_all_decode(&msg, &packet);
810 :
811 4 : const MAV_MISSION_TYPE mission_type = (MAV_MISSION_TYPE)packet.mission_type;
812 4 : MissionItemProtocol *prot = gcs().get_prot_for_mission_type(mission_type);
813 4 : if (prot == nullptr) {
814 0 : send_mission_ack(msg, mission_type, MAV_MISSION_UNSUPPORTED);
815 0 : return;
816 : }
817 :
818 4 : prot->handle_mission_clear_all(*this, msg);
819 : }
820 :
821 103052786 : bool GCS_MAVLINK::requesting_mission_items() const
822 : {
823 412158248 : for (const auto *prot : gcs().missionitemprotocols) {
824 309126289 : if (prot && prot->receiving && prot->active_link_is(this)) {
825 20827 : return true;
826 : }
827 : }
828 103031959 : return false;
829 : }
830 :
831 5 : void GCS_MAVLINK::handle_mission_write_partial_list(const mavlink_message_t &msg)
832 : {
833 : // decode
834 : mavlink_mission_write_partial_list_t packet;
835 5 : mavlink_msg_mission_write_partial_list_decode(&msg, &packet);
836 :
837 5 : MissionItemProtocol *use_prot = gcs().get_prot_for_mission_type((MAV_MISSION_TYPE)packet.mission_type);
838 5 : if (use_prot == nullptr) {
839 0 : send_mission_ack(msg, (MAV_MISSION_TYPE)packet.mission_type, MAV_MISSION_UNSUPPORTED);
840 0 : return;
841 : }
842 5 : use_prot->handle_mission_write_partial_list(*this, msg, packet);
843 : }
844 :
845 : #if HAL_MOUNT_ENABLED
846 : /*
847 : pass mavlink messages to the AP_Mount singleton
848 : */
849 23720 : void GCS_MAVLINK::handle_mount_message(const mavlink_message_t &msg)
850 : {
851 23720 : AP_Mount *mount = AP::mount();
852 23720 : if (mount == nullptr) {
853 0 : return;
854 : }
855 23720 : mount->handle_message(chan, msg);
856 : }
857 :
858 : #endif
859 :
860 : /*
861 : pass parameter value messages through to mount library
862 : */
863 26 : void GCS_MAVLINK::handle_param_value(const mavlink_message_t &msg)
864 : {
865 : #if HAL_MOUNT_ENABLED
866 26 : AP_Mount *mount = AP::mount();
867 26 : if (mount == nullptr) {
868 0 : return;
869 : }
870 26 : mount->handle_param_value(msg);
871 : #endif
872 : }
873 :
874 3812 : void GCS_MAVLINK::send_text(MAV_SEVERITY severity, const char *fmt, ...) const
875 : {
876 : va_list arg_list;
877 3812 : va_start(arg_list, fmt);
878 3812 : gcs().send_textv(severity, fmt, arg_list, (1<<chan));
879 3812 : va_end(arg_list);
880 3812 : }
881 :
882 0 : float GCS_MAVLINK::telemetry_radio_rssi()
883 : {
884 0 : if (AP_HAL::millis() - last_radio_status.received_ms > 5000) {
885 : // telemetry radio has disappeared?!
886 0 : return 0;
887 : }
888 0 : if (last_radio_status.rssi == 255) {
889 : // see RADIO_STATUS packet definition
890 0 : return 0;
891 : }
892 0 : return last_radio_status.rssi/254.0f;
893 : }
894 :
895 1429658 : bool GCS_MAVLINK::last_txbuf_is_greater(uint8_t txbuf_limit)
896 : {
897 1429658 : if (AP_HAL::millis() - last_radio_status.received_ms > 5000) {
898 : // stale report
899 1089019 : return true;
900 : }
901 340639 : return last_radio_status.txbuf > txbuf_limit;
902 : }
903 :
904 0 : void GCS_MAVLINK::handle_radio_status(const mavlink_message_t &msg)
905 : {
906 : mavlink_radio_t packet;
907 0 : mavlink_msg_radio_decode(&msg, &packet);
908 :
909 0 : const uint32_t now = AP_HAL::millis();
910 :
911 0 : last_radio_status.received_ms = now;
912 0 : last_radio_status.rssi = packet.rssi;
913 :
914 : // record if the GCS has been receiving radio messages from
915 : // the aircraft
916 0 : if (packet.remrssi != 0) {
917 0 : last_radio_status.remrssi_ms = now;
918 : }
919 :
920 0 : last_radio_status.txbuf = packet.txbuf;
921 :
922 : // use the state of the transmit buffer in the radio to
923 : // control the stream rate, giving us adaptive software
924 : // flow control
925 0 : if (packet.txbuf < 20 && stream_slowdown_ms < 2000) {
926 : // we are very low on space - slow down a lot
927 0 : stream_slowdown_ms += 60;
928 0 : } else if (packet.txbuf < 50 && stream_slowdown_ms < 2000) {
929 : // we are a bit low on space, slow down slightly
930 0 : stream_slowdown_ms += 20;
931 0 : } else if (packet.txbuf > 95 && stream_slowdown_ms > 200) {
932 : // the buffer has plenty of space, speed up a lot
933 0 : stream_slowdown_ms -= 40;
934 0 : } else if (packet.txbuf > 90 && stream_slowdown_ms != 0) {
935 : // the buffer has enough space, speed up a bit
936 0 : if (stream_slowdown_ms > 20) {
937 0 : stream_slowdown_ms -= 20;
938 : } else {
939 0 : stream_slowdown_ms = 0;
940 : }
941 : }
942 :
943 : #if GCS_DEBUG_SEND_MESSAGE_TIMINGS
944 : if (stream_slowdown_ms > max_slowdown_ms) {
945 : max_slowdown_ms = stream_slowdown_ms;
946 : }
947 : #endif
948 :
949 : #if HAL_LOGGING_ENABLED
950 : //log rssi, noise, etc if logging Performance monitoring data
951 0 : if (AP::logger().should_log(log_radio_bit())) {
952 0 : AP::logger().Write_Radio(packet);
953 : }
954 : #endif
955 0 : }
956 :
957 5247 : void GCS_MAVLINK::handle_mission_item(const mavlink_message_t &msg)
958 : {
959 : mavlink_mission_item_int_t mission_item_int;
960 5247 : bool send_mission_item_warning = false;
961 5247 : if (msg.msgid == MAVLINK_MSG_ID_MISSION_ITEM) {
962 : mavlink_mission_item_t mission_item;
963 9 : mavlink_msg_mission_item_decode(&msg, &mission_item);
964 : #if AP_MISSION_ENABLED
965 9 : MAV_MISSION_RESULT ret = AP_Mission::convert_MISSION_ITEM_to_MISSION_ITEM_INT(mission_item, mission_item_int);
966 9 : if (ret != MAV_MISSION_ACCEPTED) {
967 0 : const MAV_MISSION_TYPE type = (MAV_MISSION_TYPE)mission_item_int.mission_type;
968 0 : send_mission_ack(msg, type, ret);
969 0 : return;
970 : }
971 : #else
972 : // No mission library, so we can't convert from MISSION_ITEM
973 : // to MISSION_ITEM_INT. Since we shouldn't be receiving fence
974 : // or rally items via MISSION_ITEM, we don't need to work hard
975 : // here, just fail:
976 : const MAV_MISSION_TYPE type = (MAV_MISSION_TYPE)mission_item.mission_type;
977 : send_mission_ack(msg, type, MAV_MISSION_UNSUPPORTED);
978 : return;
979 : #endif
980 9 : send_mission_item_warning = true;
981 : } else {
982 5238 : mavlink_msg_mission_item_int_decode(&msg, &mission_item_int);
983 : }
984 5247 : const MAV_MISSION_TYPE type = (MAV_MISSION_TYPE)mission_item_int.mission_type;
985 :
986 : #if AP_MISSION_ENABLED
987 5247 : const uint8_t current = mission_item_int.current;
988 :
989 5247 : if (type == MAV_MISSION_TYPE_MISSION && (current == 2 || current == 3)) {
990 8 : struct AP_Mission::Mission_Command cmd = {};
991 8 : MAV_MISSION_RESULT result = AP_Mission::mavlink_int_to_mission_cmd(mission_item_int, cmd);
992 8 : if (result != MAV_MISSION_ACCEPTED) {
993 : //decode failed
994 0 : send_mission_ack(msg, MAV_MISSION_TYPE_MISSION, result);
995 0 : return;
996 : }
997 : // guided or change-alt
998 8 : if (current == 2) {
999 : // current = 2 is a flag to tell us this is a "guided mode"
1000 : // waypoint and not for the mission
1001 7 : result = (handle_guided_request(cmd) ? MAV_MISSION_ACCEPTED
1002 : : MAV_MISSION_ERROR) ;
1003 1 : } else if (current == 3) {
1004 : //current = 3 is a flag to tell us this is a alt change only
1005 : // add home alt if needed
1006 1 : handle_change_alt_request(cmd.content.location);
1007 :
1008 : // verify we received the command
1009 1 : result = MAV_MISSION_ACCEPTED;
1010 : }
1011 8 : send_mission_ack(msg, MAV_MISSION_TYPE_MISSION, result);
1012 8 : return;
1013 : }
1014 : #endif
1015 :
1016 : // not a guided-mode reqest
1017 5239 : MissionItemProtocol *prot = gcs().get_prot_for_mission_type(type);
1018 5239 : if (prot == nullptr) {
1019 0 : send_mission_ack(msg, type, MAV_MISSION_UNSUPPORTED);
1020 0 : return;
1021 : }
1022 :
1023 5239 : if (send_mission_item_warning) {
1024 4 : prot->send_mission_item_warning();
1025 : }
1026 :
1027 5239 : if (!prot->receiving) {
1028 0 : send_mission_ack(msg, type, MAV_MISSION_ERROR);
1029 0 : return;
1030 : }
1031 :
1032 5239 : prot->handle_mission_item(msg, mission_item_int);
1033 : }
1034 :
1035 457146 : ap_message GCS_MAVLINK::mavlink_id_to_ap_message_id(const uint32_t mavlink_id) const
1036 : {
1037 : // MSG_NEXT_MISSION_REQUEST doesn't correspond to a mavlink message directly.
1038 : // It is used to request the next waypoint after receiving one.
1039 :
1040 : // MSG_NEXT_PARAM doesn't correspond to a mavlink message directly.
1041 : // It is used to send the next parameter in a stream after sending one
1042 :
1043 : // MSG_NAMED_FLOAT messages can't really be "streamed"...
1044 :
1045 : static const struct {
1046 : uint32_t mavlink_id;
1047 : ap_message msg_id;
1048 : } map[] {
1049 : { MAVLINK_MSG_ID_HEARTBEAT, MSG_HEARTBEAT},
1050 : { MAVLINK_MSG_ID_HOME_POSITION, MSG_HOME},
1051 : { MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN, MSG_ORIGIN},
1052 : { MAVLINK_MSG_ID_SYS_STATUS, MSG_SYS_STATUS},
1053 : { MAVLINK_MSG_ID_POWER_STATUS, MSG_POWER_STATUS},
1054 : #if HAL_WITH_MCU_MONITORING
1055 : { MAVLINK_MSG_ID_MCU_STATUS, MSG_MCU_STATUS},
1056 : #endif
1057 : { MAVLINK_MSG_ID_MEMINFO, MSG_MEMINFO},
1058 : { MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT, MSG_NAV_CONTROLLER_OUTPUT},
1059 : { MAVLINK_MSG_ID_MISSION_CURRENT, MSG_CURRENT_WAYPOINT},
1060 : { MAVLINK_MSG_ID_SERVO_OUTPUT_RAW, MSG_SERVO_OUTPUT_RAW},
1061 : { MAVLINK_MSG_ID_RC_CHANNELS, MSG_RC_CHANNELS},
1062 : #if AP_MAVLINK_MSG_RC_CHANNELS_RAW_ENABLED
1063 : { MAVLINK_MSG_ID_RC_CHANNELS_RAW, MSG_RC_CHANNELS_RAW},
1064 : #endif
1065 : { MAVLINK_MSG_ID_RAW_IMU, MSG_RAW_IMU},
1066 : { MAVLINK_MSG_ID_SCALED_IMU, MSG_SCALED_IMU},
1067 : { MAVLINK_MSG_ID_SCALED_IMU2, MSG_SCALED_IMU2},
1068 : { MAVLINK_MSG_ID_SCALED_IMU3, MSG_SCALED_IMU3},
1069 : #if AP_MAVLINK_MSG_HIGHRES_IMU_ENABLED
1070 : { MAVLINK_MSG_ID_HIGHRES_IMU, MSG_HIGHRES_IMU},
1071 : #endif
1072 : { MAVLINK_MSG_ID_SCALED_PRESSURE, MSG_SCALED_PRESSURE},
1073 : { MAVLINK_MSG_ID_SCALED_PRESSURE2, MSG_SCALED_PRESSURE2},
1074 : { MAVLINK_MSG_ID_SCALED_PRESSURE3, MSG_SCALED_PRESSURE3},
1075 : #if AP_GPS_GPS_RAW_INT_SENDING_ENABLED
1076 : { MAVLINK_MSG_ID_GPS_RAW_INT, MSG_GPS_RAW},
1077 : #endif
1078 : #if AP_GPS_GPS_RTK_SENDING_ENABLED
1079 : { MAVLINK_MSG_ID_GPS_RTK, MSG_GPS_RTK},
1080 : #endif
1081 : #if AP_GPS_GPS2_RAW_SENDING_ENABLED
1082 : { MAVLINK_MSG_ID_GPS2_RAW, MSG_GPS2_RAW},
1083 : #endif
1084 : #if AP_GPS_GPS2_RTK_SENDING_ENABLED
1085 : { MAVLINK_MSG_ID_GPS2_RTK, MSG_GPS2_RTK},
1086 : #endif
1087 : { MAVLINK_MSG_ID_SYSTEM_TIME, MSG_SYSTEM_TIME},
1088 : { MAVLINK_MSG_ID_PARAM_VALUE, MSG_NEXT_PARAM},
1089 : #if AP_FENCE_ENABLED
1090 : { MAVLINK_MSG_ID_FENCE_STATUS, MSG_FENCE_STATUS},
1091 : #endif
1092 : #if AP_SIM_ENABLED
1093 : { MAVLINK_MSG_ID_SIMSTATE, MSG_SIMSTATE},
1094 : { MAVLINK_MSG_ID_SIM_STATE, MSG_SIM_STATE},
1095 : #endif
1096 : #if AP_AHRS_ENABLED
1097 : { MAVLINK_MSG_ID_AHRS2, MSG_AHRS2},
1098 : { MAVLINK_MSG_ID_AHRS, MSG_AHRS},
1099 : { MAVLINK_MSG_ID_ATTITUDE, MSG_ATTITUDE},
1100 : { MAVLINK_MSG_ID_ATTITUDE_QUATERNION, MSG_ATTITUDE_QUATERNION},
1101 : { MAVLINK_MSG_ID_GLOBAL_POSITION_INT, MSG_LOCATION},
1102 : #if AP_AHRS_ENABLED
1103 : { MAVLINK_MSG_ID_LOCAL_POSITION_NED, MSG_LOCAL_POSITION},
1104 : #endif // AP_AHRS_ENABLED
1105 : { MAVLINK_MSG_ID_VFR_HUD, MSG_VFR_HUD},
1106 : #endif
1107 : #if AP_MAVLINK_MSG_WIND_ENABLED
1108 : { MAVLINK_MSG_ID_WIND, MSG_WIND},
1109 : #endif // AP_MAVLINK_MSG_WIND_ENABLED
1110 : #if AP_MAVLINK_MSG_RANGEFINDER_SENDING_ENABLED
1111 : { MAVLINK_MSG_ID_RANGEFINDER, MSG_RANGEFINDER},
1112 : #endif // AP_MAVLINK_MSG_RANGEFINDER_SENDING_ENABLED
1113 : { MAVLINK_MSG_ID_DISTANCE_SENSOR, MSG_DISTANCE_SENSOR},
1114 : #if AP_TERRAIN_AVAILABLE
1115 : { MAVLINK_MSG_ID_TERRAIN_REQUEST, MSG_TERRAIN_REQUEST},
1116 : { MAVLINK_MSG_ID_TERRAIN_REPORT, MSG_TERRAIN_REPORT},
1117 : #endif
1118 : #if AP_CAMERA_ENABLED
1119 : { MAVLINK_MSG_ID_CAMERA_FEEDBACK, MSG_CAMERA_FEEDBACK},
1120 : { MAVLINK_MSG_ID_CAMERA_INFORMATION, MSG_CAMERA_INFORMATION},
1121 : { MAVLINK_MSG_ID_CAMERA_SETTINGS, MSG_CAMERA_SETTINGS},
1122 : #if AP_CAMERA_SEND_FOV_STATUS_ENABLED
1123 : { MAVLINK_MSG_ID_CAMERA_FOV_STATUS, MSG_CAMERA_FOV_STATUS},
1124 : #endif
1125 : { MAVLINK_MSG_ID_CAMERA_CAPTURE_STATUS, MSG_CAMERA_CAPTURE_STATUS},
1126 : #if AP_CAMERA_SEND_THERMAL_RANGE_ENABLED
1127 : { MAVLINK_MSG_ID_CAMERA_THERMAL_RANGE, MSG_CAMERA_THERMAL_RANGE},
1128 : #endif // AP_CAMERA_SEND_THERMAL_RANGE_ENABLED
1129 : #if AP_MAVLINK_MSG_VIDEO_STREAM_INFORMATION_ENABLED
1130 : { MAVLINK_MSG_ID_VIDEO_STREAM_INFORMATION, MSG_VIDEO_STREAM_INFORMATION},
1131 : #endif // AP_MAVLINK_MSG_VIDEO_STREAM_INFORMATION_ENABLED
1132 : #endif // AP_CAMERA_ENABLED
1133 : #if HAL_MOUNT_ENABLED
1134 : { MAVLINK_MSG_ID_GIMBAL_DEVICE_ATTITUDE_STATUS, MSG_GIMBAL_DEVICE_ATTITUDE_STATUS},
1135 : { MAVLINK_MSG_ID_AUTOPILOT_STATE_FOR_GIMBAL_DEVICE, MSG_AUTOPILOT_STATE_FOR_GIMBAL_DEVICE},
1136 : { MAVLINK_MSG_ID_GIMBAL_MANAGER_INFORMATION, MSG_GIMBAL_MANAGER_INFORMATION},
1137 : { MAVLINK_MSG_ID_GIMBAL_MANAGER_STATUS, MSG_GIMBAL_MANAGER_STATUS},
1138 : #endif
1139 : #if AP_OPTICALFLOW_ENABLED
1140 : { MAVLINK_MSG_ID_OPTICAL_FLOW, MSG_OPTICAL_FLOW},
1141 : #endif
1142 : #if COMPASS_CAL_ENABLED
1143 : { MAVLINK_MSG_ID_MAG_CAL_PROGRESS, MSG_MAG_CAL_PROGRESS},
1144 : { MAVLINK_MSG_ID_MAG_CAL_REPORT, MSG_MAG_CAL_REPORT},
1145 : #endif
1146 : #if AP_AHRS_ENABLED
1147 : { MAVLINK_MSG_ID_EKF_STATUS_REPORT, MSG_EKF_STATUS_REPORT},
1148 : #endif // AP_AHRS_ENABLED
1149 : { MAVLINK_MSG_ID_PID_TUNING, MSG_PID_TUNING},
1150 : { MAVLINK_MSG_ID_VIBRATION, MSG_VIBRATION},
1151 : #if AP_RPM_ENABLED
1152 : { MAVLINK_MSG_ID_RPM, MSG_RPM},
1153 : #endif
1154 : { MAVLINK_MSG_ID_MISSION_ITEM_REACHED, MSG_MISSION_ITEM_REACHED},
1155 : { MAVLINK_MSG_ID_ATTITUDE_TARGET, MSG_ATTITUDE_TARGET},
1156 : { MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT, MSG_POSITION_TARGET_GLOBAL_INT},
1157 : { MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED, MSG_POSITION_TARGET_LOCAL_NED},
1158 : #if HAL_ADSB_ENABLED
1159 : { MAVLINK_MSG_ID_ADSB_VEHICLE, MSG_ADSB_VEHICLE},
1160 : #endif
1161 : #if AP_BATTERY_ENABLED
1162 : { MAVLINK_MSG_ID_BATTERY_STATUS, MSG_BATTERY_STATUS},
1163 : #endif
1164 : #if APM_BUILD_TYPE(APM_BUILD_ArduPlane)
1165 : { MAVLINK_MSG_ID_AOA_SSA, MSG_AOA_SSA},
1166 : #endif // APM_BUILD_ArduPlane
1167 : #if HAL_LANDING_DEEPSTALL_ENABLED && APM_BUILD_TYPE(APM_BUILD_ArduPlane)
1168 : { MAVLINK_MSG_ID_DEEPSTALL, MSG_LANDING},
1169 : #endif
1170 : { MAVLINK_MSG_ID_EXTENDED_SYS_STATE, MSG_EXTENDED_SYS_STATE},
1171 : { MAVLINK_MSG_ID_AUTOPILOT_VERSION, MSG_AUTOPILOT_VERSION},
1172 : #if HAL_EFI_ENABLED
1173 : { MAVLINK_MSG_ID_EFI_STATUS, MSG_EFI_STATUS},
1174 : #endif
1175 : #if HAL_GENERATOR_ENABLED
1176 : { MAVLINK_MSG_ID_GENERATOR_STATUS, MSG_GENERATOR_STATUS},
1177 : #endif
1178 : #if AP_WINCH_ENABLED
1179 : { MAVLINK_MSG_ID_WINCH_STATUS, MSG_WINCH_STATUS},
1180 : #endif
1181 : #if HAL_WITH_ESC_TELEM
1182 : { MAVLINK_MSG_ID_ESC_TELEMETRY_1_TO_4, MSG_ESC_TELEMETRY},
1183 : #endif
1184 : #if AP_RANGEFINDER_ENABLED && (APM_BUILD_TYPE(APM_BUILD_Rover) || APM_BUILD_TYPE(APM_BUILD_ArduSub))
1185 : { MAVLINK_MSG_ID_WATER_DEPTH, MSG_WATER_DEPTH},
1186 : #endif
1187 : #if HAL_HIGH_LATENCY2_ENABLED
1188 : { MAVLINK_MSG_ID_HIGH_LATENCY2, MSG_HIGH_LATENCY2},
1189 : #endif
1190 : #if AP_AIS_ENABLED
1191 : { MAVLINK_MSG_ID_AIS_VESSEL, MSG_AIS_VESSEL},
1192 : #endif
1193 : #if AP_MAVLINK_MSG_UAVIONIX_ADSB_OUT_STATUS_ENABLED
1194 : { MAVLINK_MSG_ID_UAVIONIX_ADSB_OUT_STATUS, MSG_UAVIONIX_ADSB_OUT_STATUS},
1195 : #endif
1196 : #if AP_MAVLINK_MSG_RELAY_STATUS_ENABLED
1197 : { MAVLINK_MSG_ID_RELAY_STATUS, MSG_RELAY_STATUS},
1198 : #endif
1199 : #if AP_AIRSPEED_ENABLED
1200 : { MAVLINK_MSG_ID_AIRSPEED, MSG_AIRSPEED},
1201 : #endif
1202 : { MAVLINK_MSG_ID_AVAILABLE_MODES, MSG_AVAILABLE_MODES},
1203 : { MAVLINK_MSG_ID_AVAILABLE_MODES_MONITOR, MSG_AVAILABLE_MODES_MONITOR},
1204 : #if AP_MAVLINK_MSG_FLIGHT_INFORMATION_ENABLED
1205 : { MAVLINK_MSG_ID_FLIGHT_INFORMATION, MSG_FLIGHT_INFORMATION},
1206 : #endif // AP_MAVLINK_MSG_FLIGHT_INFORMATION_ENABLED
1207 : #if AP_MAVLINK_UTM_GLOBAL_POSITION_SENDING_ENABLED
1208 : { MAVLINK_MSG_ID_UTM_GLOBAL_POSITION, MSG_UTM_GLOBAL_POSITION},
1209 : #endif // AP_MAVLINK_UTM_GLOBAL_POSITION_SENDING_ENABLED
1210 : };
1211 :
1212 14840995 : for (uint8_t i=0; i<ARRAY_SIZE(map); i++) {
1213 14840992 : if (map[i].mavlink_id == mavlink_id) {
1214 457143 : return map[i].msg_id;
1215 : }
1216 : }
1217 3 : return MSG_LAST;
1218 : }
1219 :
1220 6340 : bool GCS_MAVLINK::set_mavlink_message_id_interval(const uint32_t mavlink_id,
1221 : const uint16_t interval_ms)
1222 : {
1223 6340 : const ap_message id = mavlink_id_to_ap_message_id(mavlink_id);
1224 6340 : if (id == MSG_LAST) {
1225 : #if CONFIG_HAL_BOARD == HAL_BOARD_SITL
1226 0 : GCS_SEND_TEXT(MAV_SEVERITY_INFO, "No ap_message for mavlink id (%u)", (unsigned int)mavlink_id);
1227 : #endif // CONFIG_HAL_BOARD == HAL_BOARD_SITL
1228 0 : return false;
1229 : }
1230 6340 : return set_ap_message_interval(id, interval_ms);
1231 : }
1232 :
1233 1089924 : bool GCS_MAVLINK::should_send_message_in_delay_callback(const ap_message id) const
1234 : {
1235 : // No ID we return true for may take more than a few hundred
1236 : // microseconds to return!
1237 :
1238 1089924 : switch (id) {
1239 467295 : case MSG_NEXT_PARAM:
1240 : case MSG_HEARTBEAT:
1241 : #if HAL_HIGH_LATENCY2_ENABLED
1242 : case MSG_HIGH_LATENCY2:
1243 : #endif
1244 : case MSG_AUTOPILOT_VERSION:
1245 467295 : return true;
1246 622629 : default:
1247 622629 : return false;
1248 : }
1249 :
1250 : return false;
1251 : }
1252 :
1253 103052786 : uint16_t GCS_MAVLINK::get_reschedule_interval_ms(const deferred_message_bucket_t &deferred) const
1254 : {
1255 103052786 : uint32_t interval_ms = deferred.interval_ms;
1256 :
1257 103052786 : interval_ms += stream_slowdown_ms;
1258 :
1259 : // slow most messages down if we're transfering parameters or
1260 : // waypoints:
1261 103052786 : if (_queued_parameter) {
1262 : // we are sending parameters, penalize streams:
1263 235620 : interval_ms *= 4;
1264 : }
1265 103052786 : if (requesting_mission_items()) {
1266 : // we are sending requests for waypoints, penalize streams:
1267 20827 : interval_ms *= 4;
1268 : }
1269 : #if AP_MAVLINK_FTP_ENABLED
1270 103052786 : if (AP_HAL::millis() - GCS_FTP::get_last_send_ms(chan) < 1000) {
1271 : // we are sending ftp replies
1272 105418 : interval_ms *= 4;
1273 : }
1274 : #endif
1275 :
1276 103052786 : if (interval_ms > 60000) {
1277 0 : return 60000;
1278 : }
1279 :
1280 103052786 : return interval_ms;
1281 : }
1282 :
1283 : // typical runtime on fmuv3: 5 microseconds for 3 buckets
1284 1253105 : void GCS_MAVLINK::find_next_bucket_to_send(uint16_t now16_ms)
1285 : {
1286 : #if GCS_DEBUG_SEND_MESSAGE_TIMINGS
1287 : void *data = hal.scheduler->disable_interrupts_save();
1288 : uint32_t start_us = AP_HAL::micros();
1289 : #endif
1290 :
1291 : // all done sending this bucket... find another bucket...
1292 1253105 : sending_bucket_id = no_bucket_to_send;
1293 1253105 : uint16_t ms_before_send_next_bucket_to_send = UINT16_MAX;
1294 13784155 : for (uint8_t i=0; i<ARRAY_SIZE(deferred_message_bucket); i++) {
1295 12531050 : if (deferred_message_bucket[i].ap_message_ids.count() == 0) {
1296 : // no entries
1297 11138519 : continue;
1298 : }
1299 1392531 : const uint16_t interval = get_reschedule_interval_ms(deferred_message_bucket[i]);
1300 1392531 : const uint16_t ms_since_last_sent = now16_ms - deferred_message_bucket[i].last_sent_ms;
1301 : uint16_t ms_before_send_this_bucket;
1302 1392531 : if (ms_since_last_sent > interval) {
1303 : // should already have sent this bucket!
1304 3989 : ms_before_send_this_bucket = 0;
1305 : } else {
1306 1388542 : ms_before_send_this_bucket = interval - ms_since_last_sent;
1307 : }
1308 1392531 : if (ms_before_send_this_bucket < ms_before_send_next_bucket_to_send) {
1309 1356101 : sending_bucket_id = i;
1310 1356101 : ms_before_send_next_bucket_to_send = ms_before_send_this_bucket;
1311 : }
1312 : }
1313 1253105 : if (sending_bucket_id != no_bucket_to_send) {
1314 1253105 : bucket_message_ids_to_send = deferred_message_bucket[sending_bucket_id].ap_message_ids;
1315 : } else {
1316 0 : bucket_message_ids_to_send.clearall();
1317 : }
1318 :
1319 : #if GCS_DEBUG_SEND_MESSAGE_TIMINGS
1320 : uint32_t delta_us = AP_HAL::micros() - start_us;
1321 : hal.scheduler->restore_interrupts(data);
1322 : if (delta_us > try_send_message_stats.fnbts_maxtime) {
1323 : try_send_message_stats.fnbts_maxtime = delta_us;
1324 : }
1325 : #endif
1326 1253105 : }
1327 :
1328 101811856 : ap_message GCS_MAVLINK::next_deferred_bucket_message_to_send(uint16_t now16_ms)
1329 : {
1330 101811856 : if (sending_bucket_id == no_bucket_to_send) {
1331 : // could happen if all streamrates are zero?
1332 1404487 : return no_message_to_send;
1333 : }
1334 :
1335 100407369 : const uint16_t ms_since_last_sent = now16_ms - deferred_message_bucket[sending_bucket_id].last_sent_ms;
1336 100407369 : if (ms_since_last_sent < get_reschedule_interval_ms(deferred_message_bucket[sending_bucket_id])) {
1337 : // not time to send this bucket
1338 42807133 : return no_message_to_send;
1339 : }
1340 :
1341 57600236 : const int16_t next = bucket_message_ids_to_send.first_set();
1342 57600236 : if (next == -1) {
1343 : // should not happen
1344 : #if CONFIG_HAL_BOARD == HAL_BOARD_SITL
1345 0 : AP_HAL::panic("next_deferred_bucket_message_to_send called on empty bucket");
1346 : #endif
1347 0 : find_next_bucket_to_send(now16_ms);
1348 0 : return no_message_to_send;
1349 : }
1350 57600236 : return (ap_message)next;
1351 : }
1352 :
1353 : // call try_send_message if appropriate. Incorporates debug code to
1354 : // record how long it takes to send a message. try_send_message is
1355 : // expected to be overridden, not this function.
1356 142406475 : bool GCS_MAVLINK::do_try_send_message(const ap_message id)
1357 : {
1358 142406475 : const bool in_delay_callback = hal.scheduler->in_delay_callback();
1359 142406475 : if (in_delay_callback && !should_send_message_in_delay_callback(id)) {
1360 622629 : return true;
1361 : }
1362 141783846 : if (telemetry_delayed()) {
1363 0 : return false;
1364 : }
1365 141783846 : WITH_SEMAPHORE(comm_chan_lock(chan));
1366 : #if GCS_DEBUG_SEND_MESSAGE_TIMINGS
1367 : void *data = hal.scheduler->disable_interrupts_save();
1368 : uint32_t start_send_message_us = AP_HAL::micros();
1369 : #endif
1370 141783846 : if (!try_send_message(id)) {
1371 : // didn't fit in buffer...
1372 : #if GCS_DEBUG_SEND_MESSAGE_TIMINGS
1373 : try_send_message_stats.no_space_for_message++;
1374 : hal.scheduler->restore_interrupts(data);
1375 : #endif
1376 82542673 : return false;
1377 : }
1378 : #if GCS_DEBUG_SEND_MESSAGE_TIMINGS
1379 : const uint32_t delta_us = AP_HAL::micros() - start_send_message_us;
1380 : hal.scheduler->restore_interrupts(data);
1381 : if (delta_us > try_send_message_stats.longest_time_us) {
1382 : try_send_message_stats.longest_time_us = delta_us;
1383 : try_send_message_stats.longest_id = id;
1384 : }
1385 : #endif
1386 59241173 : return true;
1387 141783846 : }
1388 :
1389 951859 : int8_t GCS_MAVLINK::get_deferred_message_index(const ap_message id) const
1390 : {
1391 3775728 : for (uint8_t i=0; i<ARRAY_SIZE(deferred_message); i++) {
1392 2836563 : if (deferred_message[i].id == id) {
1393 12694 : return i;
1394 : }
1395 : }
1396 939165 : return -1;
1397 : }
1398 :
1399 186618095 : int8_t GCS_MAVLINK::deferred_message_to_send_index(uint16_t now16_ms)
1400 : {
1401 :
1402 186618095 : if (next_deferred_message_to_send_cache == -1) {
1403 1794823 : uint16_t ms_before_next_message_to_send = UINT16_MAX;
1404 7179292 : for (uint8_t i=0; i<ARRAY_SIZE(deferred_message); i++) {
1405 5384469 : const uint16_t interval_ms = deferred_message[i].interval_ms;
1406 5384469 : if (interval_ms == 0) {
1407 1793644 : continue;
1408 : }
1409 3590825 : const uint16_t ms_since_last_sent = now16_ms - deferred_message[i].last_sent_ms;
1410 : uint16_t ms_before_send_this_message;
1411 3590825 : if (ms_since_last_sent > interval_ms) {
1412 : // should already have sent this one!
1413 55537 : ms_before_send_this_message = 0;
1414 : #if GCS_DEBUG_SEND_MESSAGE_TIMINGS
1415 : try_send_message_stats.behind++;
1416 : #endif
1417 : } else {
1418 3535288 : ms_before_send_this_message = interval_ms - ms_since_last_sent;
1419 : }
1420 3590825 : if (ms_before_send_this_message < ms_before_next_message_to_send) {
1421 3427442 : next_deferred_message_to_send_cache = i;
1422 3427442 : ms_before_next_message_to_send = ms_before_send_this_message;
1423 : }
1424 : }
1425 : }
1426 :
1427 186618095 : if (next_deferred_message_to_send_cache == -1) {
1428 : // this really shouldn't happen; we force parameter rates, for example.
1429 0 : return -1;
1430 : }
1431 :
1432 : // an intermediate 16-bit variable is used here to strictly avoid
1433 : // type promotion creating 32-bit (or higher) maths here. Do not
1434 : // be tempted to remove ms_since_last_sent here.
1435 186618095 : const uint16_t ms_since_last_sent = now16_ms - deferred_message[next_deferred_message_to_send_cache].last_sent_ms;
1436 186618095 : if (ms_since_last_sent < deferred_message[next_deferred_message_to_send_cache].interval_ms) {
1437 102386310 : return -1;
1438 : }
1439 :
1440 84231785 : return next_deferred_message_to_send_cache;
1441 : }
1442 :
1443 13 : bool GCS_MAVLINK_InProgress::send_ack(MAV_RESULT result)
1444 : {
1445 13 : if (!HAVE_PAYLOAD_SPACE(chan, COMMAND_ACK)) {
1446 : // can't fit the ACK, come back to this later
1447 0 : return false;
1448 : }
1449 :
1450 13 : mavlink_msg_command_ack_send(
1451 : chan,
1452 13 : mav_cmd,
1453 : result,
1454 : 0,
1455 : 0,
1456 13 : requesting_sysid,
1457 13 : requesting_compid
1458 : );
1459 :
1460 13 : return true;
1461 : }
1462 :
1463 8 : bool GCS_MAVLINK_InProgress::send_in_progress()
1464 : {
1465 8 : return send_ack(MAV_RESULT_IN_PROGRESS);
1466 : }
1467 :
1468 5 : bool GCS_MAVLINK_InProgress::conclude(MAV_RESULT result)
1469 : {
1470 5 : if (!send_ack(result)) {
1471 0 : return false;
1472 : }
1473 5 : task = Type::NONE;
1474 5 : return true;
1475 : }
1476 :
1477 5 : GCS_MAVLINK_InProgress *GCS_MAVLINK_InProgress::get_task(MAV_CMD mav_cmd, GCS_MAVLINK_InProgress::Type t, uint8_t sysid, uint8_t compid, mavlink_channel_t chan)
1478 : {
1479 : // we can't have two outstanding tasks for the same command from
1480 : // the same mavlink node or the result is ambiguous:
1481 10 : for (auto &_task : in_progress_tasks) {
1482 5 : if (_task.task == Type::NONE) {
1483 5 : continue;
1484 : }
1485 0 : if (_task.mav_cmd == mav_cmd &&
1486 0 : _task.requesting_sysid == sysid &&
1487 0 : _task.requesting_compid == compid) {
1488 0 : return nullptr;
1489 : }
1490 : }
1491 :
1492 5 : for (auto &_task : in_progress_tasks) {
1493 5 : if (_task.task != Type::NONE) {
1494 0 : continue;
1495 : }
1496 5 : _task.chan = chan;
1497 5 : _task.task = t;
1498 5 : _task.mav_cmd = mav_cmd;
1499 5 : _task.requesting_sysid = sysid;
1500 5 : _task.requesting_compid = compid;
1501 5 : return &_task;
1502 : }
1503 0 : return nullptr;
1504 : }
1505 :
1506 :
1507 126754392 : void GCS_MAVLINK_InProgress::check_tasks()
1508 : {
1509 : // run these checks only intermittently (rate-limits the
1510 : // MAV_RESULT_IN_PROGRESS messages):
1511 126754392 : const uint32_t now_ms = AP_HAL::millis();
1512 126754392 : if (now_ms - last_check_ms < 1000) {
1513 126599787 : return;
1514 : }
1515 154605 : last_check_ms = now_ms;
1516 :
1517 309210 : for (auto &task : in_progress_tasks) {
1518 154605 : switch (task.task) {
1519 154592 : case Type::NONE:
1520 154592 : break;
1521 13 : case Type::AIRSPEED_CAL: {
1522 : #if AP_AIRSPEED_ENABLED
1523 13 : const AP_Airspeed *airspeed = AP_Airspeed::get_singleton();
1524 13 : switch (airspeed->get_calibration_state()) {
1525 0 : case AP_Airspeed::CalibrationState::NOT_STARTED:
1526 : case AP_Airspeed::CalibrationState::NOT_REQUIRED_ZERO_OFFSET:
1527 : // we shouldn't get here
1528 0 : task.conclude(MAV_RESULT_FAILED);
1529 0 : break;
1530 8 : case AP_Airspeed::CalibrationState::IN_PROGRESS:
1531 8 : task.send_in_progress();
1532 8 : break;
1533 0 : case AP_Airspeed::CalibrationState::FAILED:
1534 0 : task.conclude(MAV_RESULT_FAILED);
1535 0 : break;
1536 5 : case AP_Airspeed::CalibrationState::SUCCESS:
1537 5 : task.conclude(MAV_RESULT_ACCEPTED);
1538 5 : break;
1539 : }
1540 : #endif
1541 : }
1542 13 : break;
1543 0 : case Type::SD_FORMAT:
1544 : #if AP_FILESYSTEM_FORMAT_ENABLED
1545 0 : switch (AP::FS().get_format_status()) {
1546 0 : case AP_Filesystem_Backend::FormatStatus::NOT_STARTED:
1547 : // we shouldn't get here
1548 0 : task.conclude(MAV_RESULT_FAILED);
1549 0 : break;
1550 0 : case AP_Filesystem_Backend::FormatStatus::IN_PROGRESS:
1551 : case AP_Filesystem_Backend::FormatStatus::PENDING:
1552 0 : task.send_in_progress();
1553 0 : break;
1554 0 : case AP_Filesystem_Backend::FormatStatus::SUCCESS:
1555 0 : task.conclude(MAV_RESULT_ACCEPTED);
1556 0 : break;
1557 0 : case AP_Filesystem_Backend::FormatStatus::FAILURE:
1558 0 : task.conclude(MAV_RESULT_FAILED);
1559 0 : break;
1560 : }
1561 : #endif
1562 0 : break;
1563 : }
1564 : }
1565 : }
1566 :
1567 126754392 : void GCS_MAVLINK::update_send()
1568 : {
1569 : #if HAL_LOGGING_ENABLED
1570 126754392 : if (!hal.scheduler->in_delay_callback()) {
1571 : // AP_Logger will not send log data if we are armed.
1572 126097412 : AP::logger().handle_log_send();
1573 : }
1574 : #endif
1575 126754392 : if (!deferred_messages_initialised) {
1576 6340 : initialise_message_intervals_from_streamrates();
1577 : #if HAL_MAVLINK_INTERVALS_FROM_FILES_ENABLED
1578 6340 : initialise_message_intervals_from_config_files();
1579 : #endif
1580 6340 : deferred_messages_initialised = true;
1581 : }
1582 :
1583 : #if GCS_DEBUG_SEND_MESSAGE_TIMINGS
1584 : uint32_t retry_deferred_body_start = AP_HAL::micros();
1585 : #endif
1586 :
1587 : // check for any in-progress tasks; check_tasks does its own rate-limiting
1588 126754392 : GCS_MAVLINK_InProgress::check_tasks();
1589 :
1590 126754392 : const uint32_t start = AP_HAL::millis();
1591 126754392 : const uint16_t start16 = start & 0xFFFF;
1592 186618194 : while (AP_HAL::millis() - start < 5) { // spend a max of 5ms sending messages. This should never trigger - out_of_time() should become true
1593 186618194 : if (gcs().out_of_time()) {
1594 : #if GCS_DEBUG_SEND_MESSAGE_TIMINGS
1595 : try_send_message_stats.out_of_time++;
1596 : #endif
1597 99 : break;
1598 : }
1599 :
1600 : #if GCS_DEBUG_SEND_MESSAGE_TIMINGS
1601 : retry_deferred_body_start = AP_HAL::micros();
1602 : #endif
1603 :
1604 : // check if any "specially handled" messages should be sent out
1605 : {
1606 186618095 : const int8_t next = deferred_message_to_send_index(start16);
1607 186618095 : if (next != -1) {
1608 84231785 : if (!do_try_send_message(deferred_message[next].id)) {
1609 82443302 : break;
1610 : }
1611 : // we try to keep output on a regular clock to avoid
1612 : // user support questions:
1613 1788483 : const uint16_t interval_ms = deferred_message[next].interval_ms;
1614 1788483 : deferred_message[next].last_sent_ms += interval_ms;
1615 : // but we do not want to try to catch up too much:
1616 1788483 : if (uint16_t(start16 - deferred_message[next].last_sent_ms) > interval_ms) {
1617 179 : deferred_message[next].last_sent_ms = start16;
1618 : }
1619 :
1620 1788483 : next_deferred_message_to_send_cache = -1; // deferred_message_to_send will recalculate
1621 : #if GCS_DEBUG_SEND_MESSAGE_TIMINGS
1622 : const uint32_t stop = AP_HAL::micros();
1623 : const uint32_t delta = stop - retry_deferred_body_start;
1624 : if (delta > try_send_message_stats.max_retry_deferred_body_us) {
1625 : try_send_message_stats.max_retry_deferred_body_us = delta;
1626 : try_send_message_stats.max_retry_deferred_body_type = 1;
1627 : }
1628 : #endif
1629 1788483 : continue;
1630 1788483 : }
1631 : }
1632 :
1633 : // check for any messages that the code has explicitly sent
1634 102386310 : const int16_t fs = pushed_ap_message_ids.first_set();
1635 102386310 : if (fs != -1) {
1636 574454 : ap_message next = (ap_message)fs;
1637 574454 : if (!do_try_send_message(next)) {
1638 97936 : break;
1639 : }
1640 476518 : pushed_ap_message_ids.clear(next);
1641 : #if GCS_DEBUG_SEND_MESSAGE_TIMINGS
1642 : const uint32_t stop = AP_HAL::micros();
1643 : const uint32_t delta = stop - retry_deferred_body_start;
1644 : if (delta > try_send_message_stats.max_retry_deferred_body_us) {
1645 : try_send_message_stats.max_retry_deferred_body_us = delta;
1646 : try_send_message_stats.max_retry_deferred_body_type = 2;
1647 : }
1648 : #endif
1649 476518 : continue;
1650 476518 : }
1651 :
1652 101811856 : ap_message next = next_deferred_bucket_message_to_send(start16);
1653 101811856 : if (next != no_message_to_send) {
1654 57600236 : if (!do_try_send_message(next)) {
1655 1435 : break;
1656 : }
1657 57598801 : bucket_message_ids_to_send.clear(next);
1658 57598801 : if (bucket_message_ids_to_send.count() == 0) {
1659 : // we sent everything in the bucket. Reschedule it.
1660 : // we try to keep output on a regular clock to avoid
1661 : // user support questions:
1662 1252886 : const uint16_t interval_ms = get_reschedule_interval_ms(deferred_message_bucket[sending_bucket_id]);
1663 1252886 : deferred_message_bucket[sending_bucket_id].last_sent_ms += interval_ms;
1664 : // but we do not want to try to catch up too much:
1665 1252886 : if (uint16_t(start16 - deferred_message_bucket[sending_bucket_id].last_sent_ms) > interval_ms) {
1666 1672 : deferred_message_bucket[sending_bucket_id].last_sent_ms = start16;
1667 : }
1668 1252886 : find_next_bucket_to_send(start16);
1669 : }
1670 : #if GCS_DEBUG_SEND_MESSAGE_TIMINGS
1671 : const uint32_t stop = AP_HAL::micros();
1672 : const uint32_t delta = stop - retry_deferred_body_start;
1673 : if (delta > try_send_message_stats.max_retry_deferred_body_us) {
1674 : try_send_message_stats.max_retry_deferred_body_us = delta;
1675 : try_send_message_stats.max_retry_deferred_body_type = 3;
1676 : }
1677 : #endif
1678 57598801 : continue;
1679 57598801 : }
1680 44211620 : break;
1681 : }
1682 : #if GCS_DEBUG_SEND_MESSAGE_TIMINGS
1683 : const uint32_t stop = AP_HAL::micros();
1684 : const uint32_t delta = stop - retry_deferred_body_start;
1685 : if (delta > try_send_message_stats.max_retry_deferred_body_us) {
1686 : try_send_message_stats.max_retry_deferred_body_us = delta;
1687 : try_send_message_stats.max_retry_deferred_body_type = 4;
1688 : }
1689 : #endif
1690 :
1691 : // update the number of packets transmitted base on seqno, making
1692 : // the assumption that we don't send more than 256 messages
1693 : // between the last pass through here
1694 126754392 : send_packet_count += uint8_t(_channel_status.current_tx_seq - last_tx_seq);
1695 126754392 : last_tx_seq = _channel_status.current_tx_seq;
1696 126754392 : }
1697 :
1698 24580 : void GCS_MAVLINK::remove_message_from_bucket(int8_t bucket, ap_message id)
1699 : {
1700 24580 : deferred_message_bucket[bucket].ap_message_ids.clear(id);
1701 24580 : if (deferred_message_bucket[bucket].ap_message_ids.count() == 0) {
1702 : // bucket empty. Free it:
1703 758 : deferred_message_bucket[bucket].interval_ms = 0;
1704 758 : deferred_message_bucket[bucket].last_sent_ms = 0;
1705 : }
1706 :
1707 24580 : if (bucket == sending_bucket_id) {
1708 2552 : bucket_message_ids_to_send.clear(id);
1709 2552 : if (bucket_message_ids_to_send.count() == 0) {
1710 219 : find_next_bucket_to_send(AP_HAL::millis16());
1711 : } else {
1712 : #if CONFIG_HAL_BOARD == HAL_BOARD_SITL
1713 2333 : if (deferred_message_bucket[bucket].interval_ms == 0 &&
1714 0 : deferred_message_bucket[bucket].last_sent_ms == 0) {
1715 : // we just freed this bucket! this would mean that
1716 : // somehow our messages-still-to-send was a superset
1717 : // of the messages in the bucket we were sending,
1718 : // which would be bad.
1719 0 : INTERNAL_ERROR(AP_InternalError::error_t::flow_of_control);
1720 : }
1721 : #endif
1722 : }
1723 : }
1724 24580 : }
1725 :
1726 441730 : bool GCS_MAVLINK::set_ap_message_interval(enum ap_message id, uint16_t interval_ms)
1727 : {
1728 441730 : if (id == MSG_NEXT_PARAM) {
1729 : // force parameters to *always* get streamed so a vehicle is
1730 : // recoverable from bad configuration:
1731 6338 : if (interval_ms == 0) {
1732 3301 : interval_ms = 100;
1733 3037 : } else if (interval_ms > 1000) {
1734 0 : interval_ms = 1000;
1735 : }
1736 : }
1737 :
1738 : #if AP_SCHEDULER_ENABLED
1739 441730 : interval_ms = cap_message_interval(interval_ms);
1740 : #endif
1741 :
1742 : // check if it's a specially-handled message:
1743 441730 : const int8_t deferred_offset = get_deferred_message_index(id);
1744 441730 : if (deferred_offset != -1) {
1745 12688 : deferred_message[deferred_offset].interval_ms = interval_ms;
1746 12688 : deferred_message[deferred_offset].last_sent_ms = AP_HAL::millis16();
1747 12688 : return true;
1748 : }
1749 :
1750 : // see which bucket has the closest interval:
1751 429042 : int8_t closest_bucket = -1;
1752 429042 : uint16_t closest_bucket_interval_delta = UINT16_MAX;
1753 429042 : int8_t in_bucket = -1;
1754 429042 : int8_t empty_bucket_id = -1;
1755 4719462 : for (uint8_t i=0; i<ARRAY_SIZE(deferred_message_bucket); i++) {
1756 4290420 : const deferred_message_bucket_t &bucket = deferred_message_bucket[i];
1757 4290420 : if (bucket.interval_ms == 0) {
1758 : // unused bucket
1759 3963278 : if (empty_bucket_id == -1) {
1760 429042 : empty_bucket_id = i;
1761 : }
1762 : #if CONFIG_HAL_BOARD == HAL_BOARD_SITL
1763 3963278 : if (bucket.ap_message_ids.count() != 0) {
1764 0 : AP_HAL::panic("Bucket %u has zero interval but with ids set", i);
1765 : }
1766 : #endif
1767 3963278 : continue;
1768 : }
1769 327142 : if (bucket.ap_message_ids.get(id)) {
1770 55716 : in_bucket = i;
1771 : }
1772 327142 : const uint16_t interval_delta = abs(bucket.interval_ms - interval_ms);
1773 327142 : if (interval_delta < closest_bucket_interval_delta) {
1774 316486 : closest_bucket = i;
1775 316486 : closest_bucket_interval_delta = interval_delta;
1776 : }
1777 : }
1778 :
1779 429042 : if (in_bucket == -1 && interval_ms == 0) {
1780 : // not in a bucket and told to remove from scheduling
1781 154898 : return true;
1782 : }
1783 :
1784 274144 : if (in_bucket != -1) {
1785 55716 : if (interval_ms == 0) {
1786 : // remove it
1787 44 : remove_message_from_bucket(in_bucket, id);
1788 44 : return true;
1789 : }
1790 55672 : if (closest_bucket_interval_delta == 0 &&
1791 : in_bucket == closest_bucket) {
1792 : // don't need to move it
1793 31136 : return true;
1794 : }
1795 : // remove from existing bucket
1796 24536 : remove_message_from_bucket(in_bucket, id);
1797 24536 : if (empty_bucket_id == -1 &&
1798 0 : deferred_message_bucket[in_bucket].ap_message_ids.count() == 0) {
1799 0 : empty_bucket_id = in_bucket;
1800 : }
1801 : }
1802 :
1803 242964 : if (closest_bucket == -1 && empty_bucket_id == -1) {
1804 : // gah?!
1805 : #if CONFIG_HAL_BOARD == HAL_BOARD_SITL
1806 0 : ::fprintf(stderr, "no buckets?!\n");
1807 0 : abort();
1808 : #endif
1809 0 : return false;
1810 : }
1811 :
1812 242964 : if (closest_bucket_interval_delta != 0 &&
1813 : empty_bucket_id != -1) {
1814 : // allocate a bucket for this interval
1815 8667 : deferred_message_bucket[empty_bucket_id].interval_ms = interval_ms;
1816 8667 : deferred_message_bucket[empty_bucket_id].last_sent_ms = AP_HAL::millis16();
1817 8667 : closest_bucket = empty_bucket_id;
1818 : }
1819 :
1820 242964 : deferred_message_bucket[closest_bucket].ap_message_ids.set(id);
1821 :
1822 242964 : if (sending_bucket_id == no_bucket_to_send) {
1823 4313 : sending_bucket_id = closest_bucket;
1824 4313 : bucket_message_ids_to_send = deferred_message_bucket[closest_bucket].ap_message_ids;
1825 : }
1826 :
1827 242964 : return true;
1828 : }
1829 :
1830 : // queue a message to be sent (try_send_message does the *actual*
1831 : // mavlink work!)
1832 535645 : void GCS_MAVLINK::send_message(enum ap_message id)
1833 : {
1834 535645 : switch (id) {
1835 23630 : case MSG_HEARTBEAT:
1836 : #if HAL_HIGH_LATENCY2_ENABLED
1837 : case MSG_HIGH_LATENCY2:
1838 : #endif
1839 : #if AP_MAVLINK_SIGNING_ENABLED
1840 23630 : save_signing_timestamp(false);
1841 : #endif // AP_MAVLINK_SIGNING_ENABLED
1842 : // update the mask of all streaming channels
1843 23630 : if (is_streaming()) {
1844 14691 : GCS_MAVLINK::chan_is_streaming |= (1U<<(chan-MAVLINK_COMM_0));
1845 : } else {
1846 8939 : GCS_MAVLINK::chan_is_streaming &= ~(1U<<(chan-MAVLINK_COMM_0));
1847 : }
1848 23630 : break;
1849 512015 : default:
1850 512015 : break;
1851 : }
1852 :
1853 535645 : pushed_ap_message_ids.set(id);
1854 535645 : }
1855 :
1856 : // Plane only enables follow when scripting is enabled:
1857 : #if APM_BUILD_TYPE(APM_BUILD_ArduPlane)
1858 : #define AP_MAVLINK_FOLLOW_HANDLING_ENABLED (AP_SCRIPTING_ENABLED && AP_FOLLOW_ENABLED)
1859 : #elif APM_BUILD_TYPE(APM_BUILD_Rover) || APM_BUILD_COPTER_OR_HELI
1860 : #define AP_MAVLINK_FOLLOW_HANDLING_ENABLED AP_FOLLOW_ENABLED
1861 : #else
1862 : #define AP_MAVLINK_FOLLOW_HANDLING_ENABLED 0
1863 : #endif
1864 :
1865 2784593 : void GCS_MAVLINK::packetReceived(const mavlink_status_t &status,
1866 : const mavlink_message_t &msg)
1867 : {
1868 : // we exclude radio packets because we historically used this to
1869 : // make it possible to use the CLI over the radio
1870 2784593 : if (msg.msgid != MAVLINK_MSG_ID_RADIO && msg.msgid != MAVLINK_MSG_ID_RADIO_STATUS) {
1871 2784593 : mavlink_active |= (1U<<(chan-MAVLINK_COMM_0));
1872 : }
1873 2784593 : const auto mavlink_protocol = uartstate->get_protocol();
1874 2784593 : if (!(status.flags & MAVLINK_STATUS_FLAG_IN_MAVLINK1) &&
1875 2784593 : (status.flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) &&
1876 9804 : (mavlink_protocol == AP_SerialManager::SerialProtocol_MAVLink2 ||
1877 : mavlink_protocol == AP_SerialManager::SerialProtocol_MAVLinkHL)) {
1878 : // if we receive any MAVLink2 packets on a connection
1879 : // currently sending MAVLink1 then switch to sending
1880 : // MAVLink2
1881 0 : _channel_status.flags &= ~MAVLINK_STATUS_FLAG_OUT_MAVLINK1;
1882 : }
1883 2784593 : }
1884 :
1885 2784593 : void GCS_MAVLINK::raw_packetReceived(uint8_t framing_status,
1886 : const mavlink_status_t &status,
1887 : const mavlink_message_t &msg)
1888 : {
1889 2784593 : if (framing_status == MAVLINK_FRAMING_OK) {
1890 2784593 : packetReceived(status, msg);
1891 : }
1892 :
1893 2784593 : if (!routing.check_and_forward(framing_status, *this, msg)) {
1894 : // the routing code has indicated we should not handle this packet locally
1895 158 : return;
1896 : }
1897 2784435 : if (msg.msgid == MAVLINK_MSG_ID_GLOBAL_POSITION_INT) {
1898 : #if HAL_MOUNT_ENABLED
1899 : // allow mounts to see the location of other vehicles
1900 2801 : handle_mount_message(msg);
1901 : #endif
1902 : }
1903 : #if AP_SCRIPTING_ENABLED
1904 : {
1905 2784435 : AP_Scripting *scripting = AP_Scripting::get_singleton();
1906 2784435 : if (scripting != nullptr) {
1907 2784435 : scripting->handle_message(msg, chan);
1908 : }
1909 : }
1910 : #endif // AP_SCRIPTING_ENABLED
1911 :
1912 : #if AP_MAVLINK_FOLLOW_HANDLING_ENABLED
1913 : {
1914 2637438 : AP_Follow *follow = AP_Follow::get_singleton();
1915 2637438 : if (follow != nullptr) {
1916 2637438 : follow->handle_msg(msg);
1917 : }
1918 : }
1919 : #endif
1920 :
1921 2784435 : if (!accept_packet(status, msg)) {
1922 : // e.g. enforce-sysid says we shouldn't look at this packet
1923 68 : return;
1924 : }
1925 2784367 : handle_message(msg);
1926 : }
1927 :
1928 : void
1929 126756574 : GCS_MAVLINK::update_receive(uint32_t max_time_us)
1930 : {
1931 : // do absolutely nothing if we are locked
1932 126756574 : if (locked()) {
1933 0 : return;
1934 : }
1935 :
1936 : // receive new packets
1937 : mavlink_message_t msg;
1938 : mavlink_status_t status;
1939 126756574 : uint32_t tstart_us = AP_HAL::micros();
1940 126756574 : uint32_t now_ms = AP_HAL::millis();
1941 :
1942 126756574 : status.packet_rx_drop_count = 0;
1943 :
1944 126756574 : const uint16_t nbytes = _port->available();
1945 245621799 : for (uint16_t i=0; i<nbytes; i++)
1946 : {
1947 118867078 : const uint8_t c = (uint8_t)_port->read();
1948 118867078 : const uint32_t protocol_timeout = 4000;
1949 :
1950 118867078 : if (alternative.handler &&
1951 118867078 : now_ms - alternative.last_mavlink_ms > protocol_timeout) {
1952 : /*
1953 : we have an alternative protocol handler installed and we
1954 : haven't parsed a MAVLink packet for 4 seconds. Try
1955 : parsing using alternative handler
1956 : */
1957 0 : if (alternative.handler(c, mavlink_comm_port[chan])) {
1958 0 : alternative.last_alternate_ms = now_ms;
1959 0 : gcs_alternative_active[chan] = true;
1960 : }
1961 :
1962 : /*
1963 : we may also try parsing as MAVLink if we haven't had a
1964 : successful parse on the alternative protocol for 4s
1965 : */
1966 0 : if (now_ms - alternative.last_alternate_ms <= protocol_timeout) {
1967 0 : continue;
1968 : }
1969 : }
1970 :
1971 118867078 : bool parsed_packet = false;
1972 :
1973 : // Try to get a new message
1974 118867078 : const uint8_t framing = mavlink_frame_char_buffer(channel_buffer(), channel_status(), c, &msg, &status);
1975 118867078 : if (framing != MAVLINK_FRAMING_INCOMPLETE) {
1976 2784593 : hal.util->persistent_data.last_mavlink_msgid = msg.msgid;
1977 2784593 : raw_packetReceived(framing, status, msg);
1978 2782954 : if (framing == MAVLINK_FRAMING_OK) {
1979 2782954 : parsed_packet = true;
1980 2782954 : gcs_alternative_active[chan] = false;
1981 2782954 : alternative.last_mavlink_ms = now_ms;
1982 : }
1983 2782954 : hal.util->persistent_data.last_mavlink_msgid = 0;
1984 :
1985 : }
1986 : #if AP_SCRIPTING_ENABLED
1987 118865439 : if (framing == MAVLINK_FRAMING_BAD_CRC) {
1988 : // This may be a valid message that we don't know the crc extra for, pass it to scripting which might
1989 0 : AP_Scripting *scripting = AP_Scripting::get_singleton();
1990 0 : if (scripting != nullptr) {
1991 0 : scripting->handle_message(msg, chan);
1992 : }
1993 : }
1994 : #endif // AP_SCRIPTING_ENABLED
1995 :
1996 118865439 : if (parsed_packet || i % 100 == 0) {
1997 : // make sure we don't spend too much time parsing mavlink messages
1998 5060711 : if (AP_HAL::micros() - tstart_us > max_time_us) {
1999 214 : break;
2000 : }
2001 : }
2002 : }
2003 :
2004 126754935 : const uint32_t tnow = AP_HAL::millis();
2005 :
2006 : // send a timesync message every 10 seconds; this is for data
2007 : // collection purposes
2008 : #if HAL_HIGH_LATENCY2_ENABLED
2009 126754935 : if (tnow - _timesync_request.last_sent_ms > _timesync_request.interval_ms && !is_private() && !is_high_latency_link) {
2010 : #else
2011 : if (tnow - _timesync_request.last_sent_ms > _timesync_request.interval_ms && !is_private()) {
2012 : #endif
2013 75783112 : if (HAVE_PAYLOAD_SPACE(chan, TIMESYNC)) {
2014 15191 : send_timesync();
2015 15191 : _timesync_request.last_sent_ms = tnow;
2016 : }
2017 : }
2018 :
2019 : #if HAL_LOGGING_ENABLED
2020 : // consider logging mavlink stats:
2021 126754935 : if (is_active() || is_streaming()) {
2022 67299053 : if (tnow - last_mavlink_stats_logged > 1000) {
2023 311551 : log_mavlink_stats();
2024 311551 : last_mavlink_stats_logged = tnow;
2025 : }
2026 : }
2027 : #endif
2028 :
2029 : #if GCS_DEBUG_SEND_MESSAGE_TIMINGS
2030 :
2031 : const uint16_t now16_ms{AP_HAL::millis16()};
2032 :
2033 : if (uint16_t(now16_ms - try_send_message_stats.statustext_last_sent_ms) > 10000U) {
2034 : if (try_send_message_stats.longest_time_us) {
2035 : GCS_SEND_TEXT(MAV_SEVERITY_INFO,
2036 : "GCS.chan(%u): ap_msg=%u took %uus to send",
2037 : chan,
2038 : try_send_message_stats.longest_id,
2039 : try_send_message_stats.longest_time_us);
2040 : try_send_message_stats.longest_time_us = 0;
2041 : }
2042 : if (try_send_message_stats.no_space_for_message &&
2043 : (is_active() || is_streaming())) {
2044 : GCS_SEND_TEXT(MAV_SEVERITY_INFO,
2045 : "GCS.chan(%u): out-of-space: %u",
2046 : chan,
2047 : try_send_message_stats.no_space_for_message);
2048 : try_send_message_stats.no_space_for_message = 0;
2049 : }
2050 : if (try_send_message_stats.out_of_time) {
2051 : GCS_SEND_TEXT(MAV_SEVERITY_INFO,
2052 : "GCS.chan(%u): out-of-time=%u",
2053 : chan,
2054 : try_send_message_stats.out_of_time);
2055 : try_send_message_stats.out_of_time = 0;
2056 : }
2057 : if (max_slowdown_ms) {
2058 : GCS_SEND_TEXT(MAV_SEVERITY_INFO,
2059 : "GCS.chan(%u): max slowdown=%u",
2060 : chan,
2061 : max_slowdown_ms);
2062 : max_slowdown_ms = 0;
2063 : }
2064 : if (try_send_message_stats.behind) {
2065 : GCS_SEND_TEXT(MAV_SEVERITY_INFO,
2066 : "GCS.chan(%u): behind=%u",
2067 : chan,
2068 : try_send_message_stats.behind);
2069 : try_send_message_stats.behind = 0;
2070 : }
2071 : if (try_send_message_stats.fnbts_maxtime) {
2072 : GCS_SEND_TEXT(MAV_SEVERITY_INFO,
2073 : "GCS.chan(%u): fnbts_maxtime=%uus",
2074 : chan,
2075 : try_send_message_stats.fnbts_maxtime);
2076 : try_send_message_stats.fnbts_maxtime = 0;
2077 : }
2078 : if (try_send_message_stats.max_retry_deferred_body_us) {
2079 : GCS_SEND_TEXT(MAV_SEVERITY_INFO,
2080 : "GCS.chan(%u): retry_body_maxtime=%uus (%u)",
2081 : chan,
2082 : try_send_message_stats.max_retry_deferred_body_us,
2083 : try_send_message_stats.max_retry_deferred_body_type
2084 : );
2085 : try_send_message_stats.max_retry_deferred_body_us = 0;
2086 : }
2087 :
2088 : for (uint8_t i=0; i<ARRAY_SIZE(deferred_message_bucket); i++) {
2089 : GCS_SEND_TEXT(MAV_SEVERITY_INFO,
2090 : "B. intvl. (%u): %u %u %u %u %u",
2091 : chan,
2092 : deferred_message_bucket[0].interval_ms,
2093 : deferred_message_bucket[1].interval_ms,
2094 : deferred_message_bucket[2].interval_ms,
2095 : deferred_message_bucket[3].interval_ms,
2096 : deferred_message_bucket[4].interval_ms);
2097 : }
2098 :
2099 : try_send_message_stats.statustext_last_sent_ms = now16_ms;
2100 : }
2101 : #endif
2102 : }
2103 :
2104 : #if HAL_LOGGING_ENABLED
2105 : /*
2106 : record stats about this link to logger
2107 : */
2108 311551 : void GCS_MAVLINK::log_mavlink_stats()
2109 : {
2110 311551 : uint8_t flags = 0;
2111 : #if AP_MAVLINK_SIGNING_ENABLED
2112 311551 : if (signing_enabled()) {
2113 0 : flags |= (uint8_t)Flags::USING_SIGNING;
2114 : }
2115 : #endif // AP_MAVLINK_SIGNING_ENABLED
2116 311551 : if (is_streaming()) {
2117 305565 : flags |= (uint8_t)Flags::STREAMING;
2118 : }
2119 311551 : if (is_active()) {
2120 164580 : flags |= (uint8_t)Flags::ACTIVE;
2121 : }
2122 311551 : if (is_private()) {
2123 226 : flags |= (uint8_t)Flags::PRIVATE;
2124 : }
2125 311551 : if (locked()) {
2126 0 : flags |= (uint8_t)Flags::LOCKED;
2127 : }
2128 :
2129 311551 : const struct log_MAV pkt{
2130 : LOG_PACKET_HEADER_INIT(LOG_MAV_MSG),
2131 311551 : time_us : AP_HAL::micros64(),
2132 311551 : chan : (uint8_t)chan,
2133 311551 : packet_tx_count : send_packet_count,
2134 311551 : packet_rx_success_count: _channel_status.packet_rx_success_count,
2135 311551 : packet_rx_drop_count : _channel_status.packet_rx_drop_count,
2136 : flags : flags,
2137 311551 : stream_slowdown_ms : stream_slowdown_ms,
2138 311551 : times_full : out_of_space_to_send_count,
2139 311551 : GCS_SYSID_last_seen_ms : _sysid_gcs_last_seen_time_ms,
2140 311551 : };
2141 :
2142 311551 : AP::logger().WriteBlock(&pkt, sizeof(pkt));
2143 311551 : }
2144 : #endif
2145 :
2146 : /*
2147 : send the SYSTEM_TIME message
2148 : */
2149 1117844 : void GCS_MAVLINK::send_system_time() const
2150 : {
2151 1117844 : uint64_t time_unix = 0;
2152 : #if AP_RTC_ENABLED
2153 1117844 : AP::rtc().get_utc_usec(time_unix); // may fail, leaving time_unix at 0
2154 : #endif
2155 :
2156 1117844 : mavlink_msg_system_time_send(
2157 1117844 : chan,
2158 : time_unix,
2159 : AP_HAL::millis());
2160 1117844 : }
2161 :
2162 :
2163 1120196 : bool GCS_MAVLINK::sending_mavlink1() const
2164 : {
2165 1120196 : return ((_channel_status.flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) != 0);
2166 : }
2167 :
2168 : #if AP_RC_CHANNEL_ENABLED
2169 : /*
2170 : send RC_CHANNELS messages
2171 : */
2172 1117390 : void GCS_MAVLINK::send_rc_channels() const
2173 : {
2174 1117390 : uint16_t values[18] = {};
2175 1117390 : rc().get_radio_in(values, ARRAY_SIZE(values));
2176 :
2177 1117390 : mavlink_msg_rc_channels_send(
2178 1117390 : chan,
2179 : AP_HAL::millis(),
2180 1117390 : RC_Channels::get_valid_channel_count(),
2181 1117390 : values[0],
2182 1117390 : values[1],
2183 1117390 : values[2],
2184 1117390 : values[3],
2185 1117390 : values[4],
2186 1117390 : values[5],
2187 1117390 : values[6],
2188 1117390 : values[7],
2189 1117390 : values[8],
2190 1117390 : values[9],
2191 1117390 : values[10],
2192 1117390 : values[11],
2193 1117390 : values[12],
2194 1117390 : values[13],
2195 1117390 : values[14],
2196 1117390 : values[15],
2197 1117390 : values[16],
2198 1117390 : values[17],
2199 : #if AP_RSSI_ENABLED
2200 1117390 : receiver_rssi()
2201 : #else
2202 : 255 // meaning "unknown"
2203 : #endif
2204 : );
2205 1117390 : }
2206 :
2207 : #if AP_MAVLINK_MSG_RC_CHANNELS_RAW_ENABLED
2208 1117302 : void GCS_MAVLINK::send_rc_channels_raw() const
2209 : {
2210 : // for mavlink1 send RC_CHANNELS_RAW, for compatibility with OSD
2211 : // implementations
2212 1117302 : if (!sending_mavlink1()) {
2213 1117286 : return;
2214 : }
2215 :
2216 16 : uint16_t values[8] = {};
2217 16 : rc().get_radio_in(values, ARRAY_SIZE(values));
2218 :
2219 32 : mavlink_msg_rc_channels_raw_send(
2220 16 : chan,
2221 : AP_HAL::millis(),
2222 : 0,
2223 16 : values[0],
2224 16 : values[1],
2225 16 : values[2],
2226 16 : values[3],
2227 16 : values[4],
2228 16 : values[5],
2229 16 : values[6],
2230 16 : values[7],
2231 : #if AP_RSSI_ENABLED
2232 16 : receiver_rssi()
2233 : #else
2234 : 255 // meaning "unknown"
2235 : #endif
2236 : );
2237 : }
2238 : #endif // AP_MAVLINK_MSG_RC_CHANNELS_RAW_ENABLED
2239 : #endif // AP_RC_CHANNEL_ENABLED
2240 :
2241 1117608 : void GCS_MAVLINK::send_raw_imu()
2242 : {
2243 : #if AP_INERTIALSENSOR_ENABLED
2244 1117608 : const AP_InertialSensor &ins = AP::ins();
2245 :
2246 1117608 : const Vector3f &accel = ins.get_accel(0);
2247 1117608 : const Vector3f &gyro = ins.get_gyro(0);
2248 1117608 : Vector3f mag;
2249 : #if AP_COMPASS_ENABLED
2250 1117608 : const Compass &compass = AP::compass();
2251 1117608 : if (compass.get_count() >= 1) {
2252 1117250 : mag = compass.get_field(0);
2253 : }
2254 : #endif
2255 :
2256 1117608 : mavlink_msg_raw_imu_send(
2257 : chan,
2258 : AP_HAL::micros64(),
2259 1117608 : accel.x * 1000.0f / GRAVITY_MSS,
2260 1117608 : accel.y * 1000.0f / GRAVITY_MSS,
2261 1117608 : accel.z * 1000.0f / GRAVITY_MSS,
2262 1117608 : gyro.x * 1000.0f,
2263 1117608 : gyro.y * 1000.0f,
2264 1117608 : gyro.z * 1000.0f,
2265 1117608 : mag.x,
2266 1117608 : mag.y,
2267 1117608 : mag.z,
2268 : 0, // we use SCALED_IMU and SCALED_IMU2 for other IMUs
2269 1117608 : int16_t(ins.get_temperature(0)*100));
2270 : #endif
2271 1117608 : }
2272 :
2273 : #if AP_MAVLINK_MSG_HIGHRES_IMU_ENABLED
2274 0 : void GCS_MAVLINK::send_highres_imu()
2275 : {
2276 : static const uint16_t HIGHRES_IMU_UPDATED_XACC = 0x01;
2277 : static const uint16_t HIGHRES_IMU_UPDATED_YACC = 0x02;
2278 : static const uint16_t HIGHRES_IMU_UPDATED_ZACC = 0x04;
2279 : static const uint16_t HIGHRES_IMU_UPDATED_XGYRO = 0x08;
2280 : static const uint16_t HIGHRES_IMU_UPDATED_YGYRO = 0x10;
2281 : static const uint16_t HIGHRES_IMU_UPDATED_ZGYRO = 0x20;
2282 : #if AP_COMPASS_ENABLED
2283 : static const uint16_t HIGHRES_IMU_UPDATED_XMAG = 0x40;
2284 : static const uint16_t HIGHRES_IMU_UPDATED_YMAG = 0x80;
2285 : static const uint16_t HIGHRES_IMU_UPDATED_ZMAG = 0x100;
2286 : #endif // AP_COMPASS_ENABLED
2287 : #if AP_BARO_ENABLED
2288 : static const uint16_t HIGHRES_IMU_UPDATED_ABS_PRESSURE = 0x200;
2289 : static const uint16_t HIGHRES_IMU_UPDATED_DIFF_PRESSURE = 0x400;
2290 : static const uint16_t HIGHRES_IMU_UPDATED_PRESSURE_ALT = 0x800;
2291 : static const uint16_t HIGHRES_IMU_UPDATED_TEMPERATURE = 0x1000;
2292 : #endif // AP_BARO_ENABLED
2293 :
2294 0 : const AP_InertialSensor &ins = AP::ins();
2295 0 : const Vector3f& accel = ins.get_accel();
2296 0 : const Vector3f& gyro = ins.get_gyro();
2297 :
2298 0 : mavlink_highres_imu_t reply = {
2299 0 : .time_usec = AP_HAL::micros64(),
2300 0 : .xacc = accel.x,
2301 0 : .yacc = accel.y,
2302 0 : .zacc = accel.z,
2303 0 : .xgyro = gyro.x,
2304 0 : .ygyro = gyro.y,
2305 0 : .zgyro = gyro.z,
2306 : .xmag = 0.0,
2307 : .ymag = 0.0,
2308 : .zmag = 0.0,
2309 : .abs_pressure = 0.0,
2310 : .diff_pressure = 0.0,
2311 : .pressure_alt = 0.0,
2312 : .temperature = 0.0,
2313 : .fields_updated = (HIGHRES_IMU_UPDATED_XACC | HIGHRES_IMU_UPDATED_YACC | HIGHRES_IMU_UPDATED_ZACC |
2314 : HIGHRES_IMU_UPDATED_XGYRO | HIGHRES_IMU_UPDATED_YGYRO | HIGHRES_IMU_UPDATED_ZGYRO),
2315 0 : .id = ins.get_first_usable_accel(),
2316 0 : };
2317 :
2318 : #if AP_COMPASS_ENABLED
2319 0 : const Compass &compass = AP::compass();
2320 0 : if (compass.get_count() >= 1) {
2321 0 : const Vector3f field = compass.get_field() * 0.001f;
2322 0 : reply.xmag = field.x; // convert to gauss
2323 0 : reply.ymag = field.y;
2324 0 : reply.zmag = field.z;
2325 0 : reply.fields_updated |= (HIGHRES_IMU_UPDATED_XMAG | HIGHRES_IMU_UPDATED_YMAG | HIGHRES_IMU_UPDATED_ZMAG);
2326 : }
2327 : #endif
2328 :
2329 : #if AP_BARO_ENABLED
2330 0 : const AP_Baro &barometer = AP::baro();
2331 0 : reply.abs_pressure = barometer.get_pressure() * 0.01f;
2332 0 : reply.temperature = barometer.get_temperature();
2333 0 : reply.pressure_alt = barometer.get_altitude_AMSL();
2334 0 : reply.diff_pressure = reply.abs_pressure - barometer.get_ground_pressure() * 0.01f;
2335 0 : reply.fields_updated |= (HIGHRES_IMU_UPDATED_ABS_PRESSURE | HIGHRES_IMU_UPDATED_DIFF_PRESSURE |
2336 : HIGHRES_IMU_UPDATED_PRESSURE_ALT | HIGHRES_IMU_UPDATED_TEMPERATURE);
2337 : #endif
2338 :
2339 0 : mavlink_msg_highres_imu_send_struct(chan, &reply);
2340 0 : }
2341 : #endif // AP_MAVLINK_MSG_HIGHRES_IMU_ENABLED
2342 :
2343 2234176 : void GCS_MAVLINK::send_scaled_imu(uint8_t instance, void (*send_fn)(mavlink_channel_t chan, uint32_t time_ms, int16_t xacc, int16_t yacc, int16_t zacc, int16_t xgyro, int16_t ygyro, int16_t zgyro, int16_t xmag, int16_t ymag, int16_t zmag, int16_t temperature))
2344 : {
2345 : #if AP_INERTIALSENSOR_ENABLED
2346 2234176 : const AP_InertialSensor &ins = AP::ins();
2347 2234176 : int16_t _temperature = 0;
2348 :
2349 2234176 : bool have_data = false;
2350 2234176 : Vector3f accel{};
2351 2234176 : if (ins.get_accel_count() > instance) {
2352 1123516 : accel = ins.get_accel(instance);
2353 1123516 : _temperature = ins.get_temperature(instance)*100;
2354 1123516 : have_data = true;
2355 : }
2356 2234176 : Vector3f gyro{};
2357 2234176 : if (ins.get_gyro_count() > instance) {
2358 1123516 : gyro = ins.get_gyro(instance);
2359 1123516 : have_data = true;
2360 : }
2361 2234176 : Vector3f mag;
2362 : #if AP_COMPASS_ENABLED
2363 2234176 : const Compass &compass = AP::compass();
2364 2234176 : if (compass.get_count() > instance) {
2365 2233460 : mag = compass.get_field(instance);
2366 2233460 : have_data = true;
2367 : }
2368 : #endif
2369 2234176 : if (!have_data) {
2370 358 : return;
2371 : }
2372 2233818 : send_fn(
2373 : chan,
2374 : AP_HAL::millis(),
2375 2233818 : accel.x * 1000.0f / GRAVITY_MSS,
2376 2233818 : accel.y * 1000.0f / GRAVITY_MSS,
2377 2233818 : accel.z * 1000.0f / GRAVITY_MSS,
2378 2233818 : gyro.x * 1000.0f,
2379 2233818 : gyro.y * 1000.0f,
2380 2233818 : gyro.z * 1000.0f,
2381 2233818 : mag.x,
2382 2233818 : mag.y,
2383 2233818 : mag.z,
2384 : _temperature);
2385 : #endif
2386 : }
2387 :
2388 :
2389 : // send data for barometer and airspeed sensors instances. In the
2390 : // case that we run out of instances of one before the other we send
2391 : // the relevant fields as 0.
2392 3299481 : void GCS_MAVLINK::send_scaled_pressure_instance(uint8_t instance, void (*send_fn)(mavlink_channel_t chan, uint32_t time_boot_ms, float press_abs, float press_diff, int16_t temperature, int16_t temperature_press_diff))
2393 : {
2394 3299481 : const AP_Baro &barometer = AP::baro();
2395 :
2396 3299481 : bool have_data = false;
2397 :
2398 3299481 : float press_abs = 0.0f;
2399 3299481 : int16_t temperature = 0; // Absolute pressure temperature
2400 3299481 : int16_t temperature_press_diff = 0; // Differential pressure temperature
2401 3299481 : if (instance < barometer.num_instances()) {
2402 2247577 : press_abs = barometer.get_pressure(instance) * 0.01f;
2403 2247577 : temperature = barometer.get_temperature(instance)*100;
2404 2247577 : have_data = true;
2405 : }
2406 :
2407 3299481 : float press_diff = 0; // pascal
2408 : #if AP_AIRSPEED_ENABLED
2409 3299481 : AP_Airspeed *airspeed = AP_Airspeed::get_singleton();
2410 6593682 : if (airspeed != nullptr &&
2411 3294201 : airspeed->enabled(instance)) {
2412 576874 : press_diff = airspeed->get_differential_pressure(instance) * 0.01f;
2413 : float temp;
2414 576874 : if (airspeed->get_temperature(instance,temp)) {
2415 23148 : temperature_press_diff = temp * 100;
2416 23148 : if (temperature_press_diff == 0) {
2417 : // don't send zero as that is the value for 'no data'
2418 0 : temperature_press_diff = 1;
2419 : }
2420 : }
2421 576874 : have_data = true;
2422 : }
2423 : #endif
2424 :
2425 3299481 : if (!have_data) {
2426 1051799 : return;
2427 : }
2428 :
2429 2247682 : send_fn(
2430 : chan,
2431 : AP_HAL::millis(),
2432 : press_abs, // hectopascal
2433 : press_diff, // hectopascal
2434 : temperature, // 0.01 degrees C
2435 : temperature_press_diff); // 0.01 degrees C
2436 : }
2437 :
2438 1117303 : void GCS_MAVLINK::send_scaled_pressure()
2439 : {
2440 1117303 : send_scaled_pressure_instance(0, mavlink_msg_scaled_pressure_send);
2441 1117303 : }
2442 :
2443 1117088 : void GCS_MAVLINK::send_scaled_pressure2()
2444 : {
2445 1117088 : send_scaled_pressure_instance(1, mavlink_msg_scaled_pressure2_send);
2446 1117088 : }
2447 :
2448 1065090 : void GCS_MAVLINK::send_scaled_pressure3()
2449 : {
2450 1065090 : send_scaled_pressure_instance(2, mavlink_msg_scaled_pressure3_send);
2451 1065090 : }
2452 :
2453 : #if AP_AIRSPEED_ENABLED
2454 1117087 : void GCS_MAVLINK::send_airspeed()
2455 : {
2456 1117087 : AP_Airspeed *airspeed = AP_Airspeed::get_singleton();
2457 1117087 : if (airspeed == nullptr) {
2458 1760 : return;
2459 : }
2460 :
2461 2769100 : for (uint8_t i=0; i<AIRSPEED_MAX_SENSORS; i++) {
2462 : // Try and send the next sensor
2463 2214499 : const uint8_t index = (last_airspeed_idx + 1 + i) % AIRSPEED_MAX_SENSORS;
2464 2214499 : if (!airspeed->enabled(index)) {
2465 1653773 : continue;
2466 : }
2467 :
2468 : float temperature_float;
2469 560726 : int16_t temperature = INT16_MAX;
2470 560726 : if (airspeed->get_temperature(index, temperature_float)) {
2471 16453 : temperature = int16_t(temperature_float * 100);
2472 : }
2473 :
2474 560726 : uint8_t flags = 0;
2475 : // Set unhealthy flag
2476 560726 : if (!airspeed->healthy(index)) {
2477 3956 : flags |= AIRSPEED_SENSOR_FLAGS::AIRSPEED_SENSOR_UNHEALTHY;
2478 : }
2479 :
2480 : #if AP_AHRS_ENABLED
2481 : // Set using flag if the AHRS is using this sensor
2482 560726 : const AP_AHRS &ahrs = AP::ahrs();
2483 560726 : if (ahrs.using_airspeed_sensor() && (ahrs.get_active_airspeed_index() == index)) {
2484 526466 : flags |= AIRSPEED_SENSOR_FLAGS::AIRSPEED_SENSOR_USING;
2485 : }
2486 : #endif
2487 :
2488 : // Assemble message and send
2489 : const mavlink_airspeed_t msg {
2490 560726 : airspeed : airspeed->get_airspeed(index),
2491 560726 : raw_press : airspeed->get_differential_pressure(index),
2492 : temperature : temperature,
2493 : id : index,
2494 : flags : flags
2495 560726 : };
2496 :
2497 560726 : mavlink_msg_airspeed_send_struct(chan, &msg);
2498 :
2499 : // Only send one msg per call
2500 560726 : last_airspeed_idx = index;
2501 560726 : return;
2502 : }
2503 :
2504 : }
2505 : #endif // AP_AIRSPEED_ENABLED
2506 :
2507 : #if AP_AHRS_ENABLED
2508 1117757 : void GCS_MAVLINK::send_ahrs()
2509 : {
2510 1117757 : const AP_AHRS &ahrs = AP::ahrs();
2511 1117757 : const Vector3f &omega_I = ahrs.get_gyro_drift();
2512 1117757 : mavlink_msg_ahrs_send(
2513 : chan,
2514 1117757 : omega_I.x,
2515 1117757 : omega_I.y,
2516 1117757 : omega_I.z,
2517 : 0,
2518 : 0,
2519 : ahrs.get_error_rp(),
2520 : ahrs.get_error_yaw());
2521 1117757 : }
2522 : #endif // AP_AHRS_ENABLED
2523 :
2524 : /*
2525 : send a statustext text string to specific MAVLink bitmask
2526 : */
2527 262928 : void GCS::send_textv(MAV_SEVERITY severity, const char *fmt, va_list arg_list, mavlink_channel_mask_t dest_bitmask)
2528 : {
2529 262928 : char first_piece_of_text[MAVLINK_MSG_STATUSTEXT_FIELD_TEXT_LEN+1]{};
2530 :
2531 : do {
2532 : // send_text can be called from multiple threads; we must
2533 : // protect the "text" member with _statustext_sem
2534 262928 : WITH_SEMAPHORE(_statustext_queue.semaphore());
2535 262928 : hal.util->vsnprintf(statustext_printf_buffer, sizeof(statustext_printf_buffer), fmt, arg_list);
2536 262928 : memcpy(first_piece_of_text, statustext_printf_buffer, ARRAY_SIZE(first_piece_of_text)-1);
2537 :
2538 : // filter destination ports to only allow active ports.
2539 262928 : statustext_t statustext{};
2540 262928 : if (update_send_has_been_called) {
2541 262826 : statustext.bitmask = statustext_send_channel_mask();
2542 : } else {
2543 : // we have not yet initialised the streaming-channel-mask,
2544 : // which is done as part of the update() call. So just send
2545 : // it to all channels:
2546 102 : statustext.bitmask = (1<<_num_gcs)-1;
2547 : }
2548 262928 : statustext.bitmask &= dest_bitmask;
2549 262928 : if (!statustext.bitmask) {
2550 : // nowhere to send
2551 0 : break;
2552 : }
2553 :
2554 262928 : statustext.entry_created_ms = AP_HAL::millis16();
2555 262928 : statustext.msg.severity = severity;
2556 :
2557 : static uint16_t msgid;
2558 262928 : if (strlen(statustext_printf_buffer) > sizeof(statustext.msg.text)) {
2559 745 : msgid++;
2560 745 : if (msgid == 0) {
2561 0 : msgid = 1;
2562 : }
2563 745 : statustext.msg.id = msgid;
2564 : }
2565 :
2566 262928 : const char *remainder = statustext_printf_buffer;
2567 263679 : for (uint8_t i=0; i<_status_capacity; i++) {
2568 263679 : statustext.msg.chunk_seq = i;
2569 263679 : const size_t remainder_len = strlen(remainder);
2570 : // note that remainder_len may be zero here!
2571 263679 : uint16_t n = MIN(sizeof(statustext.msg.text), remainder_len);
2572 263679 : if (i == _status_capacity -1 && n == sizeof(statustext.msg.text)) {
2573 : // fantastic. This us a very long statustext and
2574 : // we've actually managed to push everything else out
2575 : // of the queue - this is the last chunk, so we MUST
2576 : // null-terminate.
2577 0 : n -= 1;
2578 : }
2579 263679 : memset(statustext.msg.text, '\0', sizeof(statustext.msg.text));
2580 263679 : memcpy(statustext.msg.text, remainder, n);
2581 : // The force push will ensure comm links do not block other comm links forever if they fail.
2582 : // If we push to a full buffer then we overwrite the oldest entry, effectively removing the
2583 : // block but not until the buffer fills up.
2584 263679 : _statustext_queue.push_force(statustext);
2585 263679 : remainder = &remainder[n];
2586 :
2587 : // note that remainder_len here is the remainder length for
2588 : // the *old* remainder!
2589 263679 : if (remainder_len < sizeof(statustext.msg.text) || statustext.msg.id == 0) {
2590 : break;
2591 : }
2592 : }
2593 262928 : } while (false);
2594 :
2595 : #if HAL_LOGGING_ENABLED
2596 : // given we don't really know what these methods get up to, we
2597 : // don't hold the statustext semaphore while doing them:
2598 262928 : AP_Logger *logger = AP_Logger::get_singleton();
2599 262928 : if (logger != nullptr) {
2600 262928 : logger->Write_Message(first_piece_of_text);
2601 : }
2602 : #endif
2603 :
2604 : #if AP_FRSKY_TELEM_ENABLED
2605 262928 : frsky = AP::frsky_telem();
2606 262928 : if (frsky != nullptr) {
2607 164 : frsky->queue_message(severity, first_piece_of_text);
2608 : }
2609 : #endif
2610 : #if HAL_SPEKTRUM_TELEM_ENABLED
2611 262928 : AP_Spektrum_Telem* spektrum = AP::spektrum_telem();
2612 262928 : if (spektrum != nullptr) {
2613 0 : spektrum->queue_message(severity, first_piece_of_text);
2614 : }
2615 : #endif
2616 : #if HAL_CRSF_TELEM_ENABLED
2617 262928 : AP_CRSF_Telem* crsf = AP::crsf_telem();
2618 262928 : if (crsf != nullptr) {
2619 262928 : crsf->queue_message(severity, first_piece_of_text);
2620 : }
2621 : #endif
2622 262928 : AP_Notify *notify = AP_Notify::get_singleton();
2623 262928 : if (notify) {
2624 262928 : notify->send_text(first_piece_of_text);
2625 : }
2626 :
2627 : // push the messages out straight away until the vehicle states
2628 : // that it is initialised. At that point we can assume
2629 : // update_send is being called
2630 262928 : if (!vehicle_initialised()) {
2631 5678 : service_statustext();
2632 : }
2633 262928 : }
2634 :
2635 41936955 : void GCS::service_statustext(void)
2636 : {
2637 41936955 : WITH_SEMAPHORE(_statustext_queue.semaphore());
2638 :
2639 41936955 : if (_statustext_queue.is_empty()) {
2640 : // nothing to do
2641 36841031 : return;
2642 : }
2643 :
2644 15345735 : for (uint8_t i=first_backend_to_send; i<num_gcs(); i++) {
2645 10249811 : chan(i)->service_statustext();
2646 : }
2647 10244571 : for (uint8_t i=0; i<first_backend_to_send; i++) {
2648 5148647 : chan(i)->service_statustext();
2649 : }
2650 :
2651 5095924 : _statustext_queue.prune();
2652 41936955 : }
2653 :
2654 5095924 : void GCS::StatusTextQueue::prune(void)
2655 : {
2656 : // consider pruning the statustext queue of ancient entries
2657 5095924 : const uint32_t now_ms = AP_HAL::millis();
2658 5095924 : if (now_ms - last_prune_ms < 1000) {
2659 5050856 : return;
2660 : }
2661 45068 : last_prune_ms = now_ms;
2662 :
2663 45068 : const uint16_t now16_ms = AP_HAL::millis16();
2664 66584 : for (uint8_t idx=0; idx<available(); ) {
2665 53944 : const GCS::statustext_t *statustext = (*this)[idx];
2666 53944 : if (statustext == nullptr) {
2667 0 : INTERNAL_ERROR(AP_InternalError::error_t::flow_of_control);
2668 0 : break;
2669 : }
2670 : // be wary of integer promotion here
2671 53944 : const uint16_t age = now16_ms - statustext->entry_created_ms;
2672 53944 : if (age > 5000) {
2673 : // too old. Purge it.
2674 21516 : remove(idx);
2675 21516 : continue;
2676 : }
2677 : // this is a queue. If this one wasn't too old then the next
2678 : // one isn't either.
2679 32428 : break;
2680 : }
2681 : }
2682 :
2683 : /*
2684 : send a statustext message to specific MAVLink connections in a bitmask
2685 :
2686 : must be called with semaphore held
2687 : */
2688 15398458 : void GCS_MAVLINK::service_statustext(void)
2689 : {
2690 15398458 : GCS::StatusTextQueue &_statustext_queue = gcs().statustext_queue();
2691 :
2692 15398458 : const mavlink_channel_mask_t chan_bit = (1U<<chan);
2693 : // note the lack of idx++ here. We may remove the iteration item
2694 : // from the queue as the last thing we do, in which case we don't
2695 : // want to move idx.
2696 15398458 : const uint16_t payload_size = PAYLOAD_SIZE(chan, STATUSTEXT);
2697 36811251 : for (uint8_t idx=0; idx<_statustext_queue.available(); ) {
2698 31582848 : WITH_SEMAPHORE(comm_chan_lock(chan));
2699 :
2700 31582848 : if (txspace() < payload_size) {
2701 10170055 : break;
2702 : }
2703 21412793 : GCS::statustext_t *statustext = _statustext_queue[idx];
2704 21412793 : if (statustext == nullptr) {
2705 0 : INTERNAL_ERROR(AP_InternalError::error_t::flow_of_control);
2706 0 : break;
2707 : }
2708 :
2709 : // check to see if we need to send this queue entry:
2710 21412793 : if (statustext->bitmask & chan_bit) {
2711 133678 : mavlink_msg_statustext_send(chan,
2712 133678 : statustext->msg.severity,
2713 133678 : statustext->msg.text,
2714 133678 : statustext->msg.id,
2715 133678 : statustext->msg.chunk_seq);
2716 : // indicate we've sent the message:
2717 133678 : statustext->bitmask &= ~chan_bit;
2718 :
2719 133678 : if (statustext->bitmask == 0) {
2720 : // sent everywhere it needs to be sent, remove it from the
2721 : // queue but leave idx as-is as we want to handle the
2722 : // remaining items which have been bumped up to out
2723 : // current index
2724 101530 : _statustext_queue.remove(idx);
2725 101530 : continue;
2726 : }
2727 : }
2728 : // this item still has places to go. Continue to iterate over the queue
2729 21311263 : idx++;
2730 31582848 : }
2731 15398458 : }
2732 :
2733 26530 : void GCS::send_message(enum ap_message id)
2734 : {
2735 106108 : for (uint8_t i=0; i<num_gcs(); i++) {
2736 79578 : chan(i)->send_message(id);
2737 : }
2738 26530 : }
2739 :
2740 41931277 : void GCS::update_send()
2741 : {
2742 : // cope with changes to mavlink system ID parameter
2743 41931277 : mavlink_system.sysid = sysid;
2744 :
2745 41931277 : update_send_has_been_called = true;
2746 :
2747 41931277 : if (!initialised_missionitemprotocol_objects) {
2748 2094 : initialised_missionitemprotocol_objects = true;
2749 : // once-only initialisation of MissionItemProtocol objects:
2750 : #if AP_MISSION_ENABLED
2751 2094 : missionitemprotocols[MAV_MISSION_TYPE_MISSION] = NEW_NOTHROW MissionItemProtocol_Waypoints(AP::mission());
2752 : #endif
2753 : #if HAL_RALLY_ENABLED
2754 2094 : AP_Rally *rally = AP::rally();
2755 2094 : if (rally != nullptr) {
2756 2061 : missionitemprotocols[MAV_MISSION_TYPE_RALLY] = NEW_NOTHROW MissionItemProtocol_Rally(*rally);
2757 : }
2758 : #endif
2759 : #if AP_FENCE_ENABLED
2760 2094 : AC_Fence *fence = AP::fence();
2761 2094 : if (fence != nullptr) {
2762 2061 : missionitemprotocols[MAV_MISSION_TYPE_FENCE] = NEW_NOTHROW MissionItemProtocol_Fence(*fence);
2763 : }
2764 : #endif
2765 : }
2766 :
2767 167725108 : for (auto *prot : missionitemprotocols) {
2768 125793831 : if (prot == nullptr) {
2769 197318 : continue;
2770 : }
2771 125596513 : prot->update();
2772 : }
2773 :
2774 : // round-robin the GCS_MAVLINK backend that gets to go first so
2775 : // one backend doesn't monopolise all of the time allowed for sending
2776 : // messages
2777 126275558 : for (uint8_t i=first_backend_to_send; i<num_gcs(); i++) {
2778 84344281 : chan(i)->update_send();
2779 : }
2780 84341388 : for (uint8_t i=0; i<first_backend_to_send; i++) {
2781 42410111 : chan(i)->update_send();
2782 : }
2783 :
2784 41931277 : service_statustext();
2785 :
2786 41931277 : first_backend_to_send++;
2787 41931277 : if (first_backend_to_send >= num_gcs()) {
2788 13905159 : first_backend_to_send = 0;
2789 : }
2790 41931277 : }
2791 :
2792 41933097 : void GCS::update_receive(void)
2793 : {
2794 168688032 : for (uint8_t i=0; i<num_gcs(); i++) {
2795 126756574 : chan(i)->update_receive();
2796 : }
2797 : // also update UART pass-thru, if enabled
2798 41931458 : update_passthru();
2799 41931458 : }
2800 :
2801 1679 : void GCS::send_mission_item_reached_message(uint16_t mission_index)
2802 : {
2803 6722 : for (uint8_t i=0; i<num_gcs(); i++) {
2804 5043 : chan(i)->mission_item_reached_index = mission_index;
2805 5043 : chan(i)->send_message(MSG_MISSION_ITEM_REACHED);
2806 : }
2807 1679 : }
2808 :
2809 2094 : void GCS::setup_console()
2810 : {
2811 2094 : AP_HAL::UARTDriver *uart = AP::serialmanager().find_serial(AP_SerialManager::SerialProtocol_MAVLink, 0);
2812 2094 : if (uart == nullptr) {
2813 : // this is probably not going to end well.
2814 0 : return;
2815 : }
2816 : if (ARRAY_SIZE(_chan_var_info) == 0) {
2817 : return;
2818 : }
2819 2094 : if (!create_gcs_mavlink_backend(*uart)) {
2820 0 : AP_BoardConfig::config_error("Failed to create MAVLink console backend");
2821 : }
2822 : }
2823 :
2824 :
2825 6340 : bool GCS::create_gcs_mavlink_backend(AP_HAL::UARTDriver &uart)
2826 : {
2827 6340 : if (_num_gcs >= ARRAY_SIZE(_chan_var_info)) {
2828 0 : return false;
2829 : }
2830 6340 : _chan[_num_gcs] = new_gcs_mavlink_backend(uart);
2831 6340 : if (_chan[_num_gcs] == nullptr) {
2832 0 : return false;
2833 : }
2834 :
2835 : // prepare parameters:
2836 6340 : _chan_var_info[_num_gcs] = _chan[_num_gcs]->var_info;
2837 6340 : AP_Param::load_object_from_eeprom(_chan[_num_gcs], _chan_var_info[_num_gcs]);
2838 :
2839 6340 : if (!_chan[_num_gcs]->init(_num_gcs)) {
2840 0 : delete _chan[_num_gcs];
2841 0 : _chan[_num_gcs] = nullptr;
2842 0 : return false;
2843 : }
2844 :
2845 6340 : _num_gcs++;
2846 6340 : return true;
2847 : }
2848 :
2849 2094 : void GCS::setup_uarts()
2850 : {
2851 : #if AP_FRSKY_TELEM_ENABLED
2852 2094 : if (frsky == nullptr) {
2853 2094 : frsky = NEW_NOTHROW AP_Frsky_Telem();
2854 2094 : if (frsky == nullptr || !frsky->init()) {
2855 2089 : delete frsky;
2856 2089 : frsky = nullptr;
2857 : }
2858 : }
2859 : #endif
2860 :
2861 : #if AP_LTM_TELEM_ENABLED
2862 2094 : ltm_telemetry.init();
2863 : #endif
2864 :
2865 : #if AP_DEVO_TELEM_ENABLED
2866 : devo_telemetry.init();
2867 : #endif
2868 :
2869 6340 : for (uint8_t i = 1; i < UINT8_MAX; i++) { // we really can't have this many serial connections, right?!
2870 6340 : AP_HAL::UARTDriver *uart = AP::serialmanager().find_serial(AP_SerialManager::SerialProtocol_MAVLink, i);
2871 6340 : if (uart == nullptr) {
2872 : // no more mavlink uarts
2873 2094 : return;
2874 : }
2875 4246 : if (!create_gcs_mavlink_backend(*uart)) {
2876 0 : AP_BoardConfig::config_error("Failed to create MAVLink backend %u", unsigned(i));
2877 : }
2878 : }
2879 :
2880 : // no way we allocated UINT8_MAX backends, something has gone wrong
2881 0 : INTERNAL_ERROR(AP_InternalError::error_t::flow_of_control);
2882 : }
2883 :
2884 : /*
2885 : handle a SET_MODE MAVLink message
2886 : */
2887 16 : void GCS_MAVLINK::handle_set_mode(const mavlink_message_t &msg)
2888 : {
2889 : mavlink_set_mode_t packet;
2890 16 : mavlink_msg_set_mode_decode(&msg, &packet);
2891 :
2892 16 : const uint8_t _base_mode = (uint8_t)packet.base_mode;
2893 16 : const uint32_t _custom_mode = packet.custom_mode;
2894 :
2895 16 : _set_mode_common(_base_mode, _custom_mode);
2896 16 : }
2897 :
2898 : /*
2899 : code common to both SET_MODE mavlink message and command long set_mode msg
2900 : */
2901 3329 : MAV_RESULT GCS_MAVLINK::_set_mode_common(const uint8_t _base_mode, const uint32_t _custom_mode)
2902 : {
2903 : // only accept custom modes because there is no easy mapping from Mavlink flight modes to AC flight modes
2904 : #if AP_VEHICLE_ENABLED
2905 3329 : if ((_base_mode & MAV_MODE_FLAG_CUSTOM_MODE_ENABLED) != 0) {
2906 3313 : if (!AP::vehicle()->set_mode(_custom_mode, ModeReason::GCS_COMMAND)) {
2907 : // often we should be returning DENIED rather than FAILED
2908 : // here. Perhaps a "has_mode" callback on AP_::vehicle()
2909 : // would do?
2910 297 : return MAV_RESULT_FAILED;
2911 : }
2912 3016 : return MAV_RESULT_ACCEPTED;
2913 : }
2914 : #endif
2915 :
2916 16 : if (_base_mode == MAV_MODE_FLAG_DECODE_POSITION_SAFETY) {
2917 : // set the safety switch position. Must be in a command by itself
2918 16 : if (_custom_mode == 0) {
2919 : // turn safety off (pwm outputs flow to the motors)
2920 8 : hal.rcout->force_safety_off();
2921 8 : return MAV_RESULT_ACCEPTED;
2922 : }
2923 8 : if (_custom_mode == 1) {
2924 : // turn safety on (no pwm outputs to the motors)
2925 8 : if (hal.rcout->force_safety_on()) {
2926 8 : return MAV_RESULT_ACCEPTED;
2927 : }
2928 0 : return MAV_RESULT_FAILED;
2929 : }
2930 0 : return MAV_RESULT_DENIED;
2931 : }
2932 :
2933 : // Command is invalid (is supported but has invalid parameters)
2934 0 : return MAV_RESULT_DENIED;
2935 : }
2936 :
2937 : #if AP_OPTICALFLOW_ENABLED
2938 : /*
2939 : send OPTICAL_FLOW message
2940 : */
2941 1117755 : void GCS_MAVLINK::send_opticalflow()
2942 : {
2943 1117755 : const AP_OpticalFlow *optflow = AP::opticalflow();
2944 :
2945 : // exit immediately if no optical flow sensor or not healthy
2946 2233750 : if (optflow == nullptr ||
2947 1115995 : !optflow->healthy()) {
2948 1112687 : return;
2949 : }
2950 :
2951 : // get rates from sensor
2952 5068 : const Vector2f &flowRate = optflow->flowRate();
2953 5068 : const Vector2f &bodyRate = optflow->bodyRate();
2954 :
2955 5068 : float hagl = 0;
2956 : #if AP_AHRS_ENABLED
2957 5068 : if (!AP::ahrs().get_hagl(hagl)) {
2958 1384 : hagl = 0;
2959 : }
2960 : #endif
2961 :
2962 : // populate and send message
2963 5068 : mavlink_msg_optical_flow_send(
2964 : chan,
2965 5068 : AP_HAL::millis(),
2966 : 0, // sensor id is zero
2967 5068 : flowRate.x,
2968 5068 : flowRate.y,
2969 5068 : flowRate.x - bodyRate.x,
2970 5068 : flowRate.y - bodyRate.y,
2971 5068 : optflow->quality(),
2972 : hagl, // ground distance (in meters) set to zero
2973 5068 : flowRate.x,
2974 5068 : flowRate.y);
2975 : }
2976 : #endif // AP_OPTICALFLOW_ENABLED
2977 :
2978 : /*
2979 : send AUTOPILOT_VERSION packet
2980 : */
2981 30 : void GCS_MAVLINK::send_autopilot_version() const
2982 : {
2983 : uint32_t flight_sw_version;
2984 30 : uint32_t middleware_sw_version = 0;
2985 : #ifdef APJ_BOARD_ID
2986 30 : uint32_t board_version { uint32_t(APJ_BOARD_ID) << 16 };
2987 : #else
2988 0 : uint32_t board_version = 0;
2989 : #endif
2990 30 : char flight_custom_version[MAVLINK_MSG_AUTOPILOT_VERSION_FIELD_FLIGHT_CUSTOM_VERSION_LEN]{};
2991 30 : char middleware_custom_version[MAVLINK_MSG_AUTOPILOT_VERSION_FIELD_MIDDLEWARE_CUSTOM_VERSION_LEN]{};
2992 30 : char os_custom_version[MAVLINK_MSG_AUTOPILOT_VERSION_FIELD_OS_CUSTOM_VERSION_LEN]{};
2993 : #ifdef HAL_USB_VENDOR_ID
2994 : const uint16_t vendor_id { HAL_USB_VENDOR_ID };
2995 : const uint16_t product_id { HAL_USB_PRODUCT_ID };
2996 : #else
2997 30 : uint16_t vendor_id = 0;
2998 30 : uint16_t product_id = 0;
2999 : #endif
3000 30 : uint64_t uid = 0;
3001 30 : uint8_t uid2[MAVLINK_MSG_AUTOPILOT_VERSION_FIELD_UID2_LEN] = {0};
3002 :
3003 30 : uint8_t uid_len = sizeof(uid2); // taken as reference and modified
3004 : // by following call:
3005 30 : hal.util->get_system_id_unformatted(uid2, uid_len);
3006 :
3007 30 : const AP_FWVersion &version = AP::fwversion();
3008 :
3009 30 : flight_sw_version = version.major << (8 * 3) | \
3010 30 : version.minor << (8 * 2) | \
3011 30 : version.patch << (8 * 1) | \
3012 30 : (uint32_t)(version.fw_type) << (8 * 0);
3013 :
3014 30 : if (version.fw_hash_str) {
3015 30 : strncpy_noterm(flight_custom_version, version.fw_hash_str, ARRAY_SIZE(flight_custom_version));
3016 : }
3017 :
3018 30 : if (version.middleware_hash_str) {
3019 0 : strncpy_noterm(middleware_custom_version, version.middleware_hash_str, ARRAY_SIZE(middleware_custom_version));
3020 : }
3021 :
3022 30 : if (version.os_hash_str) {
3023 0 : strncpy_noterm(os_custom_version, version.os_hash_str, ARRAY_SIZE(os_custom_version));
3024 : }
3025 :
3026 60 : mavlink_msg_autopilot_version_send(
3027 30 : chan,
3028 30 : capabilities(),
3029 : flight_sw_version,
3030 : middleware_sw_version,
3031 30 : version.os_sw_version,
3032 : board_version,
3033 : (uint8_t *)flight_custom_version,
3034 : (uint8_t *)middleware_custom_version,
3035 : (uint8_t *)os_custom_version,
3036 : vendor_id,
3037 : product_id,
3038 : uid,
3039 : uid2
3040 : );
3041 30 : }
3042 :
3043 :
3044 : #if AP_AHRS_ENABLED
3045 : /*
3046 : send LOCAL_POSITION_NED message
3047 : */
3048 1119336 : void GCS_MAVLINK::send_local_position() const
3049 : {
3050 1119336 : const AP_AHRS &ahrs = AP::ahrs();
3051 :
3052 1119336 : Vector3f local_position, velocity;
3053 2067649 : if (!ahrs.get_relative_position_NED_origin_float(local_position) ||
3054 948313 : !ahrs.get_velocity_NED(velocity)) {
3055 : // we don't know the position and velocity
3056 171236 : return;
3057 : }
3058 :
3059 948100 : mavlink_msg_local_position_ned_send(
3060 948100 : chan,
3061 : AP_HAL::millis(),
3062 : local_position.x,
3063 : local_position.y,
3064 : local_position.z,
3065 : velocity.x,
3066 : velocity.y,
3067 : velocity.z);
3068 : }
3069 : #endif
3070 :
3071 : /*
3072 : send VIBRATION message
3073 : */
3074 1115995 : void GCS_MAVLINK::send_vibration() const
3075 : {
3076 : #if AP_INERTIALSENSOR_ENABLED
3077 1115995 : const AP_InertialSensor &ins = AP::ins();
3078 :
3079 1115995 : Vector3f vibration = ins.get_vibration_levels();
3080 :
3081 1115995 : mavlink_msg_vibration_send(
3082 1115995 : chan,
3083 : AP_HAL::micros64(),
3084 : vibration.x,
3085 : vibration.y,
3086 : vibration.z,
3087 : ins.get_accel_clip_count(0),
3088 : ins.get_accel_clip_count(1),
3089 : ins.get_accel_clip_count(2));
3090 : #endif
3091 1115995 : }
3092 :
3093 468621 : void GCS_MAVLINK::send_named_float(const char *name, float value) const
3094 : {
3095 468621 : char float_name[MAVLINK_MSG_NAMED_VALUE_FLOAT_FIELD_NAME_LEN+1] {};
3096 468621 : strncpy(float_name, name, MAVLINK_MSG_NAMED_VALUE_FLOAT_FIELD_NAME_LEN);
3097 468621 : mavlink_msg_named_value_float_send(chan, AP_HAL::millis(), float_name, value);
3098 468621 : }
3099 :
3100 0 : void GCS_MAVLINK::send_named_int(const char *name, int32_t value) const
3101 : {
3102 0 : char int_name[MAVLINK_MSG_NAMED_VALUE_INT_FIELD_NAME_LEN+1] {};
3103 0 : strncpy(int_name, name, MAVLINK_MSG_NAMED_VALUE_INT_FIELD_NAME_LEN);
3104 0 : mavlink_msg_named_value_int_send(chan, AP_HAL::millis(), int_name, value);
3105 0 : }
3106 :
3107 : #if AP_AHRS_ENABLED
3108 11357 : void GCS_MAVLINK::send_home_position() const
3109 : {
3110 11357 : if (!AP::ahrs().home_is_set()) {
3111 0 : return;
3112 : }
3113 :
3114 11357 : const Location &home = AP::ahrs().get_home();
3115 :
3116 : // get home position from origin
3117 11357 : Vector3f home_pos_ned;
3118 11357 : if (home.get_vector_from_origin_NEU_cm(home_pos_ned)) {
3119 : // convert NEU in cm to NED in meters
3120 10643 : home_pos_ned *= 0.01f;
3121 10643 : home_pos_ned.z *= -1;
3122 : } else {
3123 714 : home_pos_ned = Vector3f{NAN, NAN, NAN};
3124 : }
3125 :
3126 11357 : const float q[4] {NAN, NAN, NAN, NAN};
3127 11357 : mavlink_msg_home_position_send(
3128 11357 : chan,
3129 11357 : home.lat,
3130 11357 : home.lng,
3131 11357 : home.alt * 10,
3132 : home_pos_ned.x,
3133 : home_pos_ned.y,
3134 : home_pos_ned.z,
3135 : q,
3136 : 0.0f, 0.0f, 0.0f,
3137 : AP_HAL::micros64());
3138 : }
3139 :
3140 11850 : void GCS_MAVLINK::send_gps_global_origin() const
3141 : {
3142 11850 : Location ekf_origin;
3143 11850 : if (!AP::ahrs().get_origin(ekf_origin)) {
3144 716 : return;
3145 : }
3146 11134 : mavlink_msg_gps_global_origin_send(
3147 11134 : chan,
3148 : ekf_origin.lat,
3149 : ekf_origin.lng,
3150 11134 : ekf_origin.alt * 10,
3151 : AP_HAL::micros64());
3152 : }
3153 : #endif // AP_AHRS_ENABLED
3154 :
3155 170070 : MAV_STATE GCS_MAVLINK::system_status() const
3156 : {
3157 170070 : MAV_STATE _system_status = vehicle_system_status();
3158 170070 : if (_system_status < MAV_STATE_CRITICAL) {
3159 : // note that POWEROFF and FLIGHT_TERMINATION are both >
3160 : // CRITICAL, so we will not overwrite POWEROFF and
3161 : // FLIGHT_TERMINATION even if we have internal errors. If new
3162 : // enum entries are added then this may also not overwrite
3163 : // those.
3164 166889 : if (AP::internalerror().errors()) {
3165 21 : _system_status = MAV_STATE_CRITICAL;
3166 : }
3167 : }
3168 170070 : return _system_status;
3169 : }
3170 :
3171 : /*
3172 : Send MAVLink heartbeat
3173 : */
3174 170070 : void GCS_MAVLINK::send_heartbeat() const
3175 : {
3176 680280 : mavlink_msg_heartbeat_send(
3177 170070 : chan,
3178 170070 : gcs().frame_type(),
3179 : MAV_AUTOPILOT_ARDUPILOTMEGA,
3180 170070 : base_mode(),
3181 170070 : gcs().custom_mode(),
3182 170070 : system_status());
3183 170070 : }
3184 :
3185 : #if AP_RC_CHANNEL_ENABLED
3186 25 : MAV_RESULT GCS_MAVLINK::handle_command_do_aux_function(const mavlink_command_int_t &packet)
3187 : {
3188 25 : if (packet.param2 > 2) {
3189 2 : return MAV_RESULT_DENIED;
3190 : }
3191 23 : const RC_Channel::AUX_FUNC aux_func = (RC_Channel::AUX_FUNC)packet.param1;
3192 23 : const RC_Channel::AuxSwitchPos position = (RC_Channel::AuxSwitchPos)packet.param2;
3193 23 : if (!rc().run_aux_function(aux_func, position, RC_Channel::AuxFuncTrigger::Source::MAVLINK, chan)) {
3194 : // note that this is not quite right; we could be more nuanced
3195 : // about our return code here.
3196 2 : return MAV_RESULT_FAILED;
3197 : }
3198 21 : return MAV_RESULT_ACCEPTED;
3199 : }
3200 : #endif // AP_RC_CHANNEL_ENABLED
3201 :
3202 216 : MAV_RESULT GCS_MAVLINK::handle_command_set_message_interval(const mavlink_command_int_t &packet)
3203 : {
3204 216 : if (!is_zero(packet.param3)) {
3205 0 : return MAV_RESULT_DENIED;
3206 : }
3207 216 : return set_message_interval((uint32_t)packet.param1, (int32_t)packet.param2);
3208 : }
3209 :
3210 220 : MAV_RESULT GCS_MAVLINK::set_message_interval(uint32_t msg_id, int32_t interval_us)
3211 : {
3212 220 : const ap_message id = mavlink_id_to_ap_message_id(msg_id);
3213 220 : if (id == MSG_LAST) {
3214 : #if CONFIG_HAL_BOARD == HAL_BOARD_SITL
3215 0 : GCS_SEND_TEXT(MAV_SEVERITY_INFO, "No ap_message for mavlink id (%u)", (unsigned int)msg_id);
3216 : #endif // CONFIG_HAL_BOARD == HAL_BOARD_SITL
3217 0 : return MAV_RESULT_DENIED;
3218 : }
3219 :
3220 : uint16_t interval_ms;
3221 220 : if (interval_us == 0) {
3222 : // zero is "reset to default rate"
3223 43 : if (!get_default_interval_for_ap_message(id, interval_ms)) {
3224 : // if we don't have a default interval then we assume that
3225 : // we do not send that message by default. That may not
3226 : // be strictly true if some random piece of code has set a
3227 : // rate as part of its initialisation - in which case that
3228 : // piece of code should probably be adding something into
3229 : // whatever get_default_interval_for_ap_message is looking
3230 : // at.
3231 36 : interval_ms = 0;
3232 : }
3233 177 : } else if (interval_us == -1) {
3234 : // minus-one is "stop sending"
3235 11 : interval_ms = 0;
3236 166 : } else if (interval_us < 0) {
3237 0 : return MAV_RESULT_DENIED;
3238 166 : } else if (interval_us < 1000) {
3239 : // don't squash sub-ms times to zero
3240 0 : interval_ms = 1;
3241 166 : } else if (interval_us > 60000000) {
3242 0 : interval_ms = 60000;
3243 : } else {
3244 166 : interval_ms = interval_us / 1000;
3245 : }
3246 : #if AP_SCHEDULER_ENABLED
3247 220 : if (interval_ms != 0 && cap_message_interval(interval_ms) > interval_ms) {
3248 1 : GCS_SEND_TEXT(MAV_SEVERITY_INFO, "Requested rate for message ID %u too fast. Increase SCHED_LOOP_RATE", (unsigned int)msg_id);
3249 1 : return MAV_RESULT_DENIED;
3250 : }
3251 : #endif
3252 219 : if (set_ap_message_interval(id, interval_ms)) {
3253 219 : return MAV_RESULT_ACCEPTED;
3254 : }
3255 :
3256 0 : return MAV_RESULT_FAILED;
3257 : }
3258 :
3259 : /*
3260 : this function is reserved for use by scripting
3261 : */
3262 0 : MAV_RESULT GCS::set_message_interval(uint8_t port_num, uint32_t msg_id, int32_t interval_us)
3263 : {
3264 0 : uint8_t channel = get_channel_from_port_number(port_num);
3265 :
3266 0 : GCS_MAVLINK *link = chan(channel);
3267 0 : if (link == nullptr) {
3268 0 : return MAV_RESULT_FAILED;
3269 : }
3270 0 : return link->set_message_interval(msg_id, interval_us);
3271 : }
3272 :
3273 0 : uint8_t GCS::get_channel_from_port_number(uint8_t port_num)
3274 : {
3275 0 : const AP_HAL::UARTDriver *u = AP::serialmanager().get_serial_by_id(port_num);
3276 0 : for (uint8_t i=0; i<num_gcs(); i++) {
3277 0 : if (chan(i)->get_uart() == u) {
3278 0 : return i;
3279 : }
3280 : }
3281 :
3282 0 : return UINT8_MAX;
3283 : }
3284 :
3285 450566 : MAV_RESULT GCS_MAVLINK::handle_command_request_message(const mavlink_command_int_t &packet)
3286 : {
3287 450566 : const uint32_t mavlink_id = (uint32_t)packet.param1;
3288 :
3289 450566 : if (mavlink_id == MAVLINK_MSG_ID_MESSAGE_INTERVAL) {
3290 2 : const mavlink_command_int_t msg_interval_cmd = { .param1 = packet.param2, };
3291 2 : return handle_command_get_message_interval(msg_interval_cmd);
3292 : }
3293 :
3294 450564 : const ap_message id = mavlink_id_to_ap_message_id(mavlink_id);
3295 450564 : if (id == MSG_LAST) {
3296 0 : return MAV_RESULT_FAILED;
3297 : }
3298 :
3299 450564 : switch(id) {
3300 0 : case MSG_AVAILABLE_MODES:
3301 0 : available_modes.requested = true;
3302 0 : available_modes.should_send = true;
3303 0 : available_modes.next_index = 1;
3304 0 : available_modes.requested_index = (uint8_t)packet.param2;
3305 0 : break;
3306 :
3307 : #if AP_CAMERA_ENABLED
3308 13 : case MSG_CAMERA_INFORMATION:
3309 : // param2 selects a specific camera instance (1-based); 0 means all
3310 13 : if (packet.param2 >= 1) {
3311 8 : AP_Camera *camera = AP::camera();
3312 8 : if (camera != nullptr) {
3313 8 : camera->set_camera_information_send_instance((int16_t)(packet.param2 - 1));
3314 : }
3315 : }
3316 13 : break;
3317 : #endif
3318 :
3319 450551 : default:
3320 450551 : break;
3321 : }
3322 :
3323 450564 : send_message(id);
3324 450564 : return MAV_RESULT_ACCEPTED;
3325 : }
3326 :
3327 510129 : bool GCS_MAVLINK::get_ap_message_interval(ap_message id, uint16_t &interval_ms) const
3328 : {
3329 : // check if it's a specially-handled message:
3330 510129 : const int8_t deferred_offset = get_deferred_message_index(id);
3331 510129 : if (deferred_offset != -1) {
3332 6 : interval_ms = deferred_message[deferred_offset].interval_ms;
3333 6 : return true;
3334 : }
3335 :
3336 : // check the deferred message buckets:
3337 634337 : for (uint8_t i=0; i<ARRAY_SIZE(deferred_message_bucket); i++) {
3338 634332 : const deferred_message_bucket_t &bucket = deferred_message_bucket[i];
3339 634332 : if (bucket.ap_message_ids.get(id)) {
3340 510118 : interval_ms = bucket.interval_ms;
3341 510118 : return true;
3342 : }
3343 : }
3344 :
3345 5 : return false;
3346 : }
3347 :
3348 16 : MAV_RESULT GCS_MAVLINK::handle_command_get_message_interval(const mavlink_command_int_t &packet)
3349 : {
3350 16 : if (txspace() < PAYLOAD_SIZE(chan, MESSAGE_INTERVAL) + PAYLOAD_SIZE(chan, COMMAND_ACK)) {
3351 0 : return MAV_RESULT_TEMPORARILY_REJECTED;
3352 : }
3353 :
3354 16 : const uint32_t mavlink_id = (uint32_t)packet.param1;
3355 16 : if (mavlink_id >= 2 << 15) {
3356 : // response packet limits range this works against!
3357 0 : mavlink_msg_message_interval_send(chan, mavlink_id, 0); // not available
3358 0 : return MAV_RESULT_FAILED;
3359 : }
3360 :
3361 16 : const ap_message id = mavlink_id_to_ap_message_id(mavlink_id);
3362 16 : if (id == MSG_LAST) {
3363 1 : mavlink_msg_message_interval_send(chan, mavlink_id, 0); // not available
3364 1 : return MAV_RESULT_FAILED;
3365 : }
3366 :
3367 15 : uint16_t interval_ms = 0;
3368 15 : if (!get_ap_message_interval(id, interval_ms) || interval_ms == 0) {
3369 : // not streaming this message at the moment...
3370 5 : mavlink_msg_message_interval_send(chan, mavlink_id, -1); // disabled
3371 5 : return MAV_RESULT_ACCEPTED;
3372 : }
3373 :
3374 10 : mavlink_msg_message_interval_send(chan, mavlink_id, interval_ms * 1000);
3375 10 : return MAV_RESULT_ACCEPTED;
3376 : }
3377 :
3378 :
3379 : // are we still delaying telemetry to try to avoid Xbee bricking?
3380 141783846 : bool GCS_MAVLINK::telemetry_delayed() const
3381 : {
3382 141783846 : uint32_t tnow = AP_HAL::millis() >> 10;
3383 141783846 : if (tnow >= gcs().telem_delay()) {
3384 141783846 : return false;
3385 : }
3386 0 : if (chan == MAVLINK_COMM_0 && hal.gpio->usb_connected()) {
3387 : // this is USB telemetry, so won't be an Xbee
3388 0 : return false;
3389 : }
3390 : // we're either on the 2nd UART, or no USB cable is connected
3391 : // we need to delay telemetry by the TELEM_DELAY time
3392 0 : return true;
3393 : }
3394 :
3395 :
3396 : /*
3397 : send SERVO_OUTPUT_RAW
3398 : */
3399 1192240 : void GCS_MAVLINK::send_servo_output_raw()
3400 : {
3401 1192240 : const uint32_t enabled_mask = ~SRV_Channels::get_output_channel_mask(SRV_Channel::k_GPIO);
3402 1192240 : if (enabled_mask == 0) {
3403 0 : return;
3404 : }
3405 :
3406 : #if NUM_SERVO_CHANNELS >= 17
3407 : static const uint8_t max_channels = 32;
3408 : #else
3409 : static const uint8_t max_channels = 16;
3410 : #endif
3411 :
3412 1192240 : uint16_t values[max_channels] {};
3413 1192240 : hal.rcout->read(values, max_channels);
3414 39343920 : for (uint8_t i=0; i<max_channels; i++) {
3415 38151680 : if (values[i] == 65535) {
3416 0 : values[i] = 0;
3417 : }
3418 : }
3419 1192240 : if ((enabled_mask & 0xFFFF) != 0) {
3420 1192240 : mavlink_msg_servo_output_raw_send(
3421 : chan,
3422 : AP_HAL::micros(),
3423 : 0, // port
3424 1192240 : values[0], values[1], values[2], values[3],
3425 1192240 : values[4], values[5], values[6], values[7],
3426 1192240 : values[8], values[9], values[10], values[11],
3427 1192240 : values[12], values[13], values[14], values[15]);
3428 : }
3429 :
3430 : #if NUM_SERVO_CHANNELS >= 17
3431 1192240 : if ((enabled_mask & 0xFFFF0000) != 0) {
3432 712 : mavlink_msg_servo_output_raw_send(
3433 : chan,
3434 : AP_HAL::micros(),
3435 : 1, // port
3436 712 : values[16], values[17], values[18], values[19],
3437 712 : values[20], values[21], values[22], values[23],
3438 712 : values[24], values[25], values[26], values[27],
3439 712 : values[28], values[29], values[30], values[31]);
3440 : }
3441 : #endif
3442 : }
3443 :
3444 :
3445 65 : void GCS_MAVLINK::send_accelcal_vehicle_position(uint32_t position)
3446 : {
3447 65 : if (HAVE_PAYLOAD_SPACE(chan, COMMAND_LONG)) {
3448 59 : mavlink_msg_command_long_send(
3449 : chan,
3450 : 0,
3451 : 0,
3452 : MAV_CMD_ACCELCAL_VEHICLE_POS,
3453 : 0,
3454 : (float) position,
3455 : 0, 0, 0, 0, 0, 0);
3456 : }
3457 65 : }
3458 :
3459 :
3460 181416 : float GCS_MAVLINK::vfr_hud_airspeed() const
3461 : {
3462 : #if AP_AIRSPEED_ENABLED
3463 181416 : AP_Airspeed *airspeed = AP_Airspeed::get_singleton();
3464 181416 : if (airspeed != nullptr && airspeed->healthy()) {
3465 5528 : return airspeed->get_airspeed();
3466 : }
3467 : #endif
3468 :
3469 : #if AP_GPS_ENABLED
3470 : // because most vehicles don't have airspeed sensors, we return a
3471 : // different sort of speed estimate in the relevant field for
3472 : // comparison's sake.
3473 175888 : return AP::gps().ground_speed();
3474 : #endif
3475 :
3476 : return 0.0;
3477 : }
3478 :
3479 1105338 : float GCS_MAVLINK::vfr_hud_climbrate() const
3480 : {
3481 : #if AP_AHRS_ENABLED
3482 1105338 : Vector3f velned;
3483 1150402 : if (AP::ahrs().get_velocity_NED(velned) ||
3484 45064 : AP::ahrs().get_vert_pos_rate_D(velned.z)) {
3485 1104642 : return -velned.z;
3486 : }
3487 : #endif
3488 696 : return 0;
3489 : }
3490 :
3491 : #if AP_AHRS_ENABLED
3492 1063138 : float GCS_MAVLINK::vfr_hud_alt() const
3493 : {
3494 1063138 : return global_position_current_loc.alt * 0.01f; // cm -> m
3495 : }
3496 :
3497 1119088 : void GCS_MAVLINK::send_vfr_hud()
3498 : {
3499 1119088 : AP_AHRS &ahrs = AP::ahrs();
3500 :
3501 : // return values ignored; we send stale data
3502 1119088 : UNUSED_RESULT(ahrs.get_location(global_position_current_loc));
3503 :
3504 2238176 : mavlink_msg_vfr_hud_send(
3505 : chan,
3506 1119088 : vfr_hud_airspeed(),
3507 : ahrs.groundspeed(),
3508 1119088 : ahrs.get_yaw_deg(),
3509 1119088 : abs(vfr_hud_throttle()),
3510 1119088 : vfr_hud_alt(),
3511 1119088 : vfr_hud_climbrate());
3512 1119088 : }
3513 : #endif // AP_AHRS_ENABLED
3514 :
3515 : /*
3516 : handle a MAV_CMD_PREFLIGHT_REBOOT_SHUTDOWN command
3517 :
3518 : Optionally disable PX4IO overrides. This is done for quadplanes to
3519 : prevent the mixer running while rebooting which can start the VTOL
3520 : motors. That can be dangerous when a preflight reboot is done with
3521 : the pilot close to the aircraft and can also damage the aircraft
3522 : */
3523 1640 : MAV_RESULT GCS_MAVLINK::handle_preflight_reboot(const mavlink_command_int_t &packet, const mavlink_message_t &msg)
3524 : {
3525 1640 : if ((packet.target_component != MAV_COMP_ID_ALL) && (packet.target_component != mavlink_system.compid)) {
3526 : // Make sure reboot/shutdown commands sent to a component don't cause the autopilot to reboot.
3527 1 : return MAV_RESULT_DENIED;
3528 : }
3529 :
3530 1639 : if (is_equal(packet.param1, 42.0f) &&
3531 1639 : is_equal(packet.param2, 24.0f) &&
3532 0 : is_equal(packet.param3, 71.0f)) {
3533 : #if AP_MAVLINK_FAILURE_CREATION_ENABLED
3534 0 : if (is_equal(packet.param4, 93.0f)) {
3535 : // this is a magic sequence to force the main loop to
3536 : // lockup. This is for testing the stm32 watchdog
3537 : // functionality
3538 : while (true) {
3539 0 : send_text(MAV_SEVERITY_WARNING,"entering lockup");
3540 0 : hal.scheduler->delay(250);
3541 : }
3542 : }
3543 0 : if (is_equal(packet.param4, 94.0f)) {
3544 : // the following text is unlikely to make it out...
3545 0 : send_text(MAV_SEVERITY_WARNING,"dereferencing a bad thing");
3546 :
3547 : #if CONFIG_HAL_BOARD != HAL_BOARD_ESP32
3548 : // esp32 can't do this bit, skip it, return an error
3549 0 : void *foo = (void*)0xE000ED38;
3550 :
3551 : typedef void (*fptr)();
3552 0 : fptr gptr = (fptr) (void *) foo;
3553 0 : gptr();
3554 : #endif
3555 0 : return MAV_RESULT_FAILED;
3556 : }
3557 0 : if (is_equal(packet.param4, 95.0f)) {
3558 : // the following text is unlikely to make it out...
3559 0 : send_text(MAV_SEVERITY_WARNING,"calling AP_HAL::panic(...)");
3560 :
3561 0 : AP_HAL::panic("panicing");
3562 :
3563 : // keep calm and carry on
3564 : }
3565 0 : if (is_equal(packet.param4, 96.0f)) {
3566 : // deliberately corrupt parameter storage
3567 0 : send_text(MAV_SEVERITY_WARNING,"wiping parameter storage header");
3568 0 : StorageAccess param_storage{StorageManager::StorageParam};
3569 0 : uint8_t zeros[40] {};
3570 0 : param_storage.write_block(0, zeros, sizeof(zeros));
3571 0 : return MAV_RESULT_ACCEPTED;
3572 : }
3573 0 : if (is_equal(packet.param4, 97.0f)) {
3574 : // create a really long loop
3575 0 : send_text(MAV_SEVERITY_WARNING,"Creating long loop");
3576 : // 250ms:
3577 0 : for (uint8_t i=0; i<250; i++) {
3578 0 : hal.scheduler->delay_microseconds(1000);
3579 : }
3580 0 : return MAV_RESULT_ACCEPTED;
3581 : }
3582 0 : if (is_equal(packet.param4, 98.0f)) {
3583 0 : send_text(MAV_SEVERITY_WARNING,"Creating internal error");
3584 0 : INTERNAL_ERROR(AP_InternalError::error_t::flow_of_control);
3585 0 : return MAV_RESULT_ACCEPTED;
3586 : }
3587 0 : if (is_equal(packet.param4, 100.0f)) {
3588 0 : send_text(MAV_SEVERITY_WARNING,"Creating mutex deadlock");
3589 0 : hal.scheduler->register_io_process(FUNCTOR_BIND_MEMBER(&GCS_MAVLINK::deadlock_sem, void));
3590 0 : while (!_deadlock_sem.taken) {
3591 0 : hal.scheduler->delay(1);
3592 : }
3593 0 : WITH_SEMAPHORE(_deadlock_sem.sem);
3594 0 : send_text(MAV_SEVERITY_WARNING,"deadlock passed");
3595 0 : return MAV_RESULT_ACCEPTED;
3596 0 : }
3597 0 : if (is_equal(packet.param4, 101.0f)) {
3598 : // the capital-U and ~ here are actually important for
3599 : // testing a MissionPlanner bug!
3600 0 : AP_BoardConfig::config_error("YOU~RE WELCOME!");
3601 : }
3602 0 : if (is_equal(packet.param4, 102.0f)) {
3603 : // attempt to write to address 0x5 (in the bottom 1kB on H7)
3604 : // which we either memory-protect or check for
3605 : // non-zeroness. We don't want to use 0x0 as that *even
3606 : // more magic*. So choose an offset which looks like
3607 : // we're dereferencing nullptr:
3608 0 : uint8_t *foo = (uint8_t*)0x05;
3609 :
3610 : #pragma GCC diagnostic push
3611 : #pragma GCC diagnostic ignored "-Warray-bounds"
3612 : #if !defined(__clang__) // avoid -Wunknown-warning-option
3613 : #pragma GCC diagnostic ignored "-Wstringop-overflow"
3614 : #endif
3615 0 : *foo = 0xab;
3616 : #pragma GCC diagnostic pop
3617 :
3618 0 : return MAV_RESULT_ACCEPTED;
3619 : }
3620 0 : if (is_equal(packet.param4, 103.0f)) {
3621 : // attempt to read from address 0x5 (in the bottom 1kB on
3622 : // H7) which we either memory-protect or check for
3623 : // non-zeroness. We don't want to use 0x0 as that *even
3624 : // more magic*. So choose an offset which looks like
3625 : // we're dereferencing nullptr:
3626 0 : uint8_t *foo = (uint8_t*)0x05;
3627 :
3628 : // we use send_text here to ensure we don't get elided.
3629 : // String is kept short for space reasons.
3630 : #pragma GCC diagnostic push
3631 : #pragma GCC diagnostic ignored "-Warray-bounds"
3632 : #if !defined(__clang__) // avoid -Wunknown-warning-option
3633 : #pragma GCC diagnostic ignored "-Wstringop-overflow"
3634 : #endif
3635 0 : send_text(MAV_SEVERITY_INFO, "x: %u", (unsigned)*foo);
3636 : #pragma GCC diagnostic pop
3637 :
3638 0 : return MAV_RESULT_ACCEPTED;
3639 : }
3640 : #endif // AP_MAVLINK_FAILURE_CREATION_ENABLED
3641 :
3642 : #if HAL_ENABLE_DFU_BOOT
3643 : if (is_equal(packet.param4, 99.0f)) {
3644 : #if AP_SIGNED_FIRMWARE
3645 : send_text(MAV_SEVERITY_ERROR, "Refusing DFU for secure firmware");
3646 : return MAV_RESULT_FAILED;
3647 : #else
3648 : send_text(MAV_SEVERITY_WARNING, "Entering DFU mode");
3649 : hal.util->boot_to_dfu();
3650 : return MAV_RESULT_ACCEPTED;
3651 : #endif
3652 : }
3653 : #endif
3654 : }
3655 :
3656 1639 : const bool reboot = is_equal(packet.param1, static_cast<float>(REBOOT_SHUTDOWN_ACTION_REBOOT));
3657 1639 : const bool reboot_to_bootloader = is_equal(packet.param1,
3658 : static_cast<float>(REBOOT_SHUTDOWN_ACTION_REBOOT_TO_BOOTLOADER));
3659 :
3660 : #if AP_REBOOT_MASS_STORAGE_ENABLED
3661 : const bool reboot_to_mass_storage = is_equal(packet.param1,
3662 : static_cast<float>(REBOOT_SHUTDOWN_ACTION_REBOOT_TO_MASS_STORAGE));
3663 :
3664 : // exporting writable storage must never be entered while armed
3665 : if (reboot_to_mass_storage && hal.util->get_soft_armed()) {
3666 : return MAV_RESULT_FAILED;
3667 : }
3668 : #endif
3669 :
3670 : // refuse reboot when armed:
3671 1639 : if (hal.util->get_soft_armed()) {
3672 : /// but allow it if forced:
3673 6 : const uint32_t magic_force_reboot_value = 20190226;
3674 6 : if (packet.y != magic_force_reboot_value) {
3675 0 : return MAV_RESULT_FAILED;
3676 : }
3677 : }
3678 :
3679 : #if AP_REBOOT_MASS_STORAGE_ENABLED
3680 : const bool supported_reboot_action = reboot || reboot_to_bootloader || reboot_to_mass_storage;
3681 : #else
3682 1639 : const bool supported_reboot_action = reboot || reboot_to_bootloader;
3683 : #endif
3684 1639 : if (!supported_reboot_action) {
3685 : // param1 must select a supported reboot action
3686 0 : return MAV_RESULT_UNSUPPORTED;
3687 : }
3688 :
3689 : #if AP_REBOOT_MASS_STORAGE_ENABLED
3690 : if (reboot_to_mass_storage && !hal.util->request_usb_msd()) {
3691 : return MAV_RESULT_UNSUPPORTED;
3692 : }
3693 : #endif
3694 :
3695 : #if CONFIG_HAL_BOARD == HAL_BOARD_SITL
3696 : { // autotest relies in receiving the ACK for the reboot. Ensure
3697 : // there is space for it:
3698 1639 : const uint32_t tstart_ms = AP_HAL::millis();
3699 1639 : while (AP_HAL::millis() - tstart_ms < 1000) {
3700 1639 : if (HAVE_PAYLOAD_SPACE(chan, COMMAND_ACK)) {
3701 1639 : break;
3702 : }
3703 0 : hal.scheduler->delay(10);
3704 : }
3705 : }
3706 : #endif
3707 :
3708 : // send ack before we reboot
3709 1639 : mavlink_msg_command_ack_send(chan, packet.command, MAV_RESULT_ACCEPTED,
3710 : 0, 0,
3711 1639 : msg.sysid,
3712 1639 : msg.compid);
3713 :
3714 : #if AP_VEHICLE_ENABLED
3715 1639 : AP::vehicle()->reboot(reboot_to_bootloader); // not expected to return
3716 : #else
3717 : hal.scheduler->reboot(reboot_to_bootloader);
3718 : #endif
3719 :
3720 0 : return MAV_RESULT_FAILED;
3721 : }
3722 :
3723 : #if AP_MAVLINK_FAILURE_CREATION_ENABLED
3724 : /*
3725 : take a semaphore and do not release it, triggering a deadlock
3726 : */
3727 0 : void GCS_MAVLINK::deadlock_sem(void)
3728 : {
3729 0 : if (!_deadlock_sem.taken) {
3730 0 : _deadlock_sem.taken = true;
3731 0 : _deadlock_sem.sem.take_blocking();
3732 : }
3733 0 : }
3734 : #endif
3735 :
3736 : /*
3737 : handle a flight termination request
3738 : */
3739 5 : MAV_RESULT GCS_MAVLINK::handle_flight_termination(const mavlink_command_int_t &packet)
3740 : {
3741 : #if AP_ADVANCEDFAILSAFE_ENABLED
3742 5 : AP_AdvancedFailsafe *failsafe = AP::advancedfailsafe();
3743 5 : if (failsafe == nullptr) {
3744 0 : return MAV_RESULT_UNSUPPORTED;
3745 : }
3746 :
3747 5 : bool should_terminate = packet.param1 > 0.5f;
3748 :
3749 5 : if (failsafe->gcs_terminate(should_terminate, "GCS request")) {
3750 5 : return MAV_RESULT_ACCEPTED;
3751 : }
3752 0 : return MAV_RESULT_FAILED;
3753 : #else
3754 : return MAV_RESULT_UNSUPPORTED;
3755 : #endif
3756 : }
3757 :
3758 : #if AP_RCPROTOCOL_ENABLED
3759 : /*
3760 : handle a R/C bind request (for spektrum)
3761 : */
3762 0 : MAV_RESULT GCS_MAVLINK::handle_START_RX_PAIR(const mavlink_command_int_t &packet)
3763 : {
3764 : // initiate bind procedure. We houls accept the DSM type from either
3765 : // param1 or param2 due to a past mixup with what parameter is the
3766 : // right one: const int dsmMode = (packet.param2 > 0) ? packet.param2 : packet.param1;
3767 0 : AP::RC().start_bind();
3768 :
3769 0 : return MAV_RESULT_ACCEPTED;
3770 : }
3771 : #endif // AP_RCPROTOCOL_ENABLED
3772 :
3773 14853 : uint64_t GCS_MAVLINK::timesync_receive_timestamp_ns() const
3774 : {
3775 14853 : uint64_t ret = _port->receive_time_constraint_us(PAYLOAD_SIZE(chan, TIMESYNC));
3776 14853 : if (ret == 0) {
3777 0 : ret = AP_HAL::micros64();
3778 : }
3779 14853 : return ret*1000LL;
3780 : }
3781 :
3782 15191 : uint64_t GCS_MAVLINK::timesync_timestamp_ns() const
3783 : {
3784 : // we add in our own system id try to ensure we only consider
3785 : // responses to our own timesync request messages
3786 15191 : return AP_HAL::micros64()*1000LL + mavlink_system.sysid;
3787 : }
3788 :
3789 : /*
3790 : return a timesync request
3791 : Sends back ts1 as received, and tc1 is the local timestamp in usec
3792 : */
3793 14853 : void GCS_MAVLINK::handle_timesync(const mavlink_message_t &msg)
3794 : {
3795 : // decode incoming timesync message
3796 : mavlink_timesync_t tsync;
3797 14853 : mavlink_msg_timesync_decode(&msg, &tsync);
3798 :
3799 14853 : if (tsync.tc1 != 0) {
3800 : // this is a response to a timesync request
3801 0 : if (tsync.ts1 != _timesync_request.sent_ts1) {
3802 : // we didn't actually send the request.... or it's a
3803 : // response to an ancient request...
3804 0 : return;
3805 : }
3806 : #if 0
3807 : GCS_SEND_TEXT(MAV_SEVERITY_INFO,
3808 : "timesync response sysid=%u (latency=%fms)",
3809 : msg.sysid,
3810 : round_trip_time_us*0.001f);
3811 : #endif
3812 :
3813 : #if HAL_LOGGING_ENABLED
3814 0 : const uint64_t round_trip_time_us = (timesync_receive_timestamp_ns() - _timesync_request.sent_ts1)*0.001f;
3815 0 : AP_Logger *logger = AP_Logger::get_singleton();
3816 0 : if (logger != nullptr) {
3817 0 : AP::logger().Write(
3818 : "TSYN",
3819 : "TimeUS,SysID,RTT",
3820 : "s-s",
3821 : "F-F",
3822 : "QBQ",
3823 : AP_HAL::micros64(),
3824 0 : msg.sysid,
3825 : round_trip_time_us
3826 : );
3827 : }
3828 : #endif // HAL_LOGGING_ENABLED
3829 0 : return;
3830 : }
3831 :
3832 14853 : if (!HAVE_PAYLOAD_SPACE(chan, TIMESYNC)) {
3833 : // drop this timesync request entirely
3834 0 : return;
3835 : }
3836 :
3837 : // create new timesync struct with tc1 field as system time in
3838 : // nanoseconds. The client timestamp is as close as possible to
3839 : // the time we received the TIMESYNC message.
3840 : mavlink_timesync_t rsync;
3841 14853 : rsync.tc1 = timesync_receive_timestamp_ns();
3842 14853 : rsync.ts1 = tsync.ts1;
3843 :
3844 : // respond with a timesync message
3845 14853 : mavlink_msg_timesync_send(
3846 : chan,
3847 : rsync.tc1,
3848 : rsync.ts1
3849 : );
3850 : }
3851 :
3852 : /*
3853 : * broadcast a timesync message. We may get multiple responses to this request.
3854 : */
3855 15191 : void GCS_MAVLINK::send_timesync()
3856 : {
3857 15191 : _timesync_request.sent_ts1 = timesync_timestamp_ns();
3858 15191 : mavlink_msg_timesync_send(
3859 : chan,
3860 : 0,
3861 : _timesync_request.sent_ts1
3862 : );
3863 15191 : }
3864 :
3865 1027468 : void GCS_MAVLINK::handle_statustext(const mavlink_message_t &msg)
3866 : {
3867 : #if HAL_LOGGING_ENABLED
3868 1027468 : AP_Logger *logger = AP_Logger::get_singleton();
3869 1027468 : if (logger == nullptr) {
3870 0 : return;
3871 : }
3872 :
3873 : mavlink_statustext_t packet;
3874 1027468 : mavlink_msg_statustext_decode(&msg, &packet);
3875 :
3876 1027468 : const uint8_t max_prefix_len = 14;
3877 1027468 : const uint8_t text_len = MAVLINK_MSG_STATUSTEXT_FIELD_TEXT_LEN+1+max_prefix_len;
3878 1027468 : if (msg.sysid != statustext_chunking.last_src_system ||
3879 1025369 : msg.compid != statustext_chunking.last_src_system ||
3880 1025346 : packet.id != statustext_chunking.last_id) {
3881 454141 : statustext_chunking.last_src_system = msg.sysid;
3882 454141 : statustext_chunking.last_src_component = msg.compid;
3883 454141 : statustext_chunking.last_id = packet.id;
3884 454141 : statustext_chunking.msg_id = AP::logger().get_MSG_id();
3885 : }
3886 :
3887 1027468 : uint8_t offset = 0;
3888 1027468 : char text[text_len] = {};
3889 1027468 : if (packet.chunk_seq == 0) {
3890 : // prefix with origin information
3891 454127 : if (gcs().sysid_is_gcs(msg.sysid)) {
3892 7036 : strncpy(text, "GCS:", ARRAY_SIZE(text));
3893 7036 : offset = strlen(text);
3894 : } else {
3895 894182 : offset = hal.util->snprintf(text,
3896 : max_prefix_len,
3897 : "SRC=%u/%u:",
3898 447091 : msg.sysid,
3899 447091 : msg.compid);
3900 447091 : offset = MIN(offset, max_prefix_len);
3901 : }
3902 : }
3903 :
3904 1027468 : memcpy(&text[offset], packet.text, MAVLINK_MSG_STATUSTEXT_FIELD_TEXT_LEN);
3905 :
3906 1027468 : logger->Write_MessageChunk(statustext_chunking.msg_id, text, packet.chunk_seq);
3907 : #endif
3908 : }
3909 :
3910 :
3911 : /*
3912 : handle logging of named values from mavlink.
3913 : */
3914 0 : void GCS_MAVLINK::handle_named_value(const mavlink_message_t &msg) const
3915 : {
3916 : #if HAL_LOGGING_ENABLED
3917 0 : auto *logger = AP_Logger::get_singleton();
3918 0 : if (logger == nullptr) {
3919 0 : return;
3920 : }
3921 : mavlink_named_value_float_t p;
3922 0 : mavlink_msg_named_value_float_decode(&msg, &p);
3923 0 : char s[11] {};
3924 0 : strncpy(s, p.name, sizeof(s)-1);
3925 0 : logger->Write("NVAL", "TimeUS,TimeBootMS,Name,Value,SSys,SCom", "ss#---", "FC----", "QINfBB",
3926 : AP_HAL::micros64(),
3927 : p.time_boot_ms,
3928 : s,
3929 0 : p.value,
3930 0 : msg.sysid,
3931 0 : msg.compid);
3932 : #endif
3933 : }
3934 :
3935 : #if AP_RTC_ENABLED
3936 2 : void GCS_MAVLINK::handle_system_time_message(const mavlink_message_t &msg)
3937 : {
3938 : mavlink_system_time_t packet;
3939 2 : mavlink_msg_system_time_decode(&msg, &packet);
3940 :
3941 2 : AP::rtc().set_utc_usec(packet.time_unix_usec, AP_RTC::SOURCE_MAVLINK_SYSTEM_TIME);
3942 2 : }
3943 : #endif
3944 :
3945 : #if AP_CAMERA_ENABLED
3946 13 : MAV_RESULT GCS_MAVLINK::handle_command_camera(const mavlink_command_int_t &packet)
3947 : {
3948 13 : AP_Camera *camera = AP::camera();
3949 13 : if (camera == nullptr) {
3950 0 : return MAV_RESULT_UNSUPPORTED;
3951 : }
3952 :
3953 13 : return camera->handle_command(packet);
3954 : }
3955 : #endif
3956 :
3957 :
3958 : #if AP_AHRS_ENABLED
3959 : // sets ekf_origin if it has not been set.
3960 : // should only be used when there is no GPS to provide an absolute position
3961 7 : MAV_RESULT GCS_MAVLINK::set_ekf_origin(const Location& loc)
3962 : {
3963 : // check location is valid
3964 7 : if (loc.is_zero()) {
3965 1 : return MAV_RESULT_DENIED;
3966 : }
3967 6 : if (!loc.check_latlng()) {
3968 0 : return MAV_RESULT_DENIED;
3969 : }
3970 :
3971 6 : AP_AHRS &ahrs = AP::ahrs();
3972 :
3973 : // check if EKF origin has already been set
3974 6 : Location ekf_origin;
3975 6 : if (ahrs.get_origin(ekf_origin)) {
3976 1 : return MAV_RESULT_FAILED;
3977 : }
3978 :
3979 5 : if (!ahrs.set_origin(loc)) {
3980 3 : return MAV_RESULT_FAILED;
3981 : }
3982 :
3983 : // send ekf origin to GCS
3984 2 : if (!try_send_message(MSG_ORIGIN)) {
3985 : // try again later
3986 0 : send_message(MSG_ORIGIN);
3987 : }
3988 2 : return MAV_RESULT_ACCEPTED;
3989 : }
3990 :
3991 : #if AP_MAVLINK_SET_GPS_GLOBAL_ORIGIN_MESSAGE_ENABLED
3992 5 : void GCS_MAVLINK::handle_set_gps_global_origin(const mavlink_message_t &msg)
3993 : {
3994 : mavlink_set_gps_global_origin_t packet;
3995 5 : mavlink_msg_set_gps_global_origin_decode(&msg, &packet);
3996 :
3997 : // sanity check location
3998 5 : if (!check_latlng(packet.latitude, packet.longitude)) {
3999 : // silently drop the request
4000 0 : return;
4001 : }
4002 : // sanity check altitude in mm, note that abs can't handle INT32_MIN correctly
4003 5 : if (packet.altitude < -LOCATION_ALT_MAX_M * 1000 || packet.altitude > LOCATION_ALT_MAX_M * 1000) {
4004 : // silently drop the request
4005 0 : return;
4006 : }
4007 :
4008 : const Location ekf_origin {
4009 : packet.latitude,
4010 : packet.longitude,
4011 5 : int32_t(packet.altitude * 0.1f), // mm -> cm
4012 : Location::AltFrame::ABSOLUTE
4013 5 : };
4014 5 : set_ekf_origin(ekf_origin);
4015 : }
4016 : #endif // AP_MAVLINK_SET_GPS_GLOBAL_ORIGIN_MESSAGE_ENABLED
4017 :
4018 : #endif // AP_AHRS_ENABLED
4019 :
4020 : /*
4021 : handle a DATA96 message
4022 : */
4023 0 : void GCS_MAVLINK::handle_data_packet(const mavlink_message_t &msg)
4024 : {
4025 : #if AP_RADIO_ENABLED
4026 : mavlink_data96_t m;
4027 : mavlink_msg_data96_decode(&msg, &m);
4028 : switch (m.type) {
4029 : case 42:
4030 : case 43: {
4031 : // pass to AP_Radio (for firmware upload and playing test tunes)
4032 : AP_Radio *radio = AP_Radio::get_singleton();
4033 : if (radio != nullptr) {
4034 : radio->handle_data_packet(chan, m);
4035 : }
4036 : break;
4037 : }
4038 : default:
4039 : // unknown
4040 : break;
4041 : }
4042 : #endif
4043 0 : }
4044 :
4045 : #if HAL_VISUALODOM_ENABLED
4046 3735 : void GCS_MAVLINK::handle_vision_position_delta(const mavlink_message_t &msg)
4047 : {
4048 3735 : AP_VisualOdom *visual_odom = AP::visualodom();
4049 3735 : if (visual_odom == nullptr) {
4050 0 : return;
4051 : }
4052 3735 : visual_odom->handle_vision_position_delta_msg(msg);
4053 : }
4054 :
4055 10472 : void GCS_MAVLINK::handle_vision_position_estimate(const mavlink_message_t &msg)
4056 : {
4057 : mavlink_vision_position_estimate_t m;
4058 10472 : mavlink_msg_vision_position_estimate_decode(&msg, &m);
4059 :
4060 10472 : handle_common_vision_position_estimate_data(m.usec, m.x, m.y, m.z, m.roll, m.pitch, m.yaw, m.covariance, m.reset_counter,
4061 10472 : PAYLOAD_SIZE(chan, VISION_POSITION_ESTIMATE));
4062 10472 : }
4063 :
4064 0 : void GCS_MAVLINK::handle_global_vision_position_estimate(const mavlink_message_t &msg)
4065 : {
4066 : mavlink_global_vision_position_estimate_t m;
4067 0 : mavlink_msg_global_vision_position_estimate_decode(&msg, &m);
4068 :
4069 0 : handle_common_vision_position_estimate_data(m.usec, m.x, m.y, m.z, m.roll, m.pitch, m.yaw, m.covariance, m.reset_counter,
4070 0 : PAYLOAD_SIZE(chan, GLOBAL_VISION_POSITION_ESTIMATE));
4071 0 : }
4072 :
4073 0 : void GCS_MAVLINK::handle_vicon_position_estimate(const mavlink_message_t &msg)
4074 : {
4075 : mavlink_vicon_position_estimate_t m;
4076 0 : mavlink_msg_vicon_position_estimate_decode(&msg, &m);
4077 :
4078 : // vicon position estimate does not include reset counter
4079 0 : handle_common_vision_position_estimate_data(m.usec, m.x, m.y, m.z, m.roll, m.pitch, m.yaw, m.covariance, 0,
4080 0 : PAYLOAD_SIZE(chan, VICON_POSITION_ESTIMATE));
4081 0 : }
4082 :
4083 : /*
4084 : handle ODOMETRY message. This message combines position, velocity
4085 : and attitude data
4086 : */
4087 0 : void GCS_MAVLINK::handle_odometry(const mavlink_message_t &msg)
4088 : {
4089 0 : AP_VisualOdom *visual_odom = AP::visualodom();
4090 0 : if (visual_odom == nullptr) {
4091 0 : return;
4092 : }
4093 :
4094 : mavlink_odometry_t m;
4095 0 : mavlink_msg_odometry_decode(&msg, &m);
4096 :
4097 0 : if (m.frame_id != MAV_FRAME_LOCAL_FRD ||
4098 0 : m.child_frame_id != MAV_FRAME_BODY_FRD) {
4099 : // only support local FRD frame data
4100 0 : return;
4101 : }
4102 :
4103 0 : Quaternion q{m.q[0],m.q[1],m.q[2],m.q[3]};
4104 :
4105 0 : float posErr = 0;
4106 0 : float angErr = 0;
4107 0 : if (!isnan(m.pose_covariance[0])) {
4108 0 : posErr = sqrtf(m.pose_covariance[0]+m.pose_covariance[6]+m.pose_covariance[11]);
4109 0 : angErr = sqrtf(m.pose_covariance[15]+m.pose_covariance[18]+m.pose_covariance[20]);
4110 : }
4111 :
4112 0 : const uint32_t timestamp_ms = correct_offboard_timestamp_usec_to_ms(m.time_usec, PAYLOAD_SIZE(chan, ODOMETRY));
4113 0 : visual_odom->handle_pose_estimate(m.time_usec, timestamp_ms, m.x, m.y, m.z, q, posErr, angErr, m.reset_counter, m.quality);
4114 :
4115 : // convert velocity vector from FRD to NED frame
4116 0 : Vector3f vel{m.vx, m.vy, m.vz};
4117 0 : vel = q * vel;
4118 0 : visual_odom->handle_vision_speed_estimate(m.time_usec, timestamp_ms, vel, 0, m.reset_counter, m.quality);
4119 : }
4120 :
4121 : // there are several messages which all have identical fields in them.
4122 : // This function provides common handling for the data contained in
4123 : // these packets
4124 10472 : void GCS_MAVLINK::handle_common_vision_position_estimate_data(const uint64_t usec,
4125 : const float x,
4126 : const float y,
4127 : const float z,
4128 : const float roll,
4129 : const float pitch,
4130 : const float yaw,
4131 : const float covariance[21],
4132 : const uint8_t reset_counter,
4133 : const uint16_t payload_size)
4134 : {
4135 10472 : float posErr = 0;
4136 10472 : float angErr = 0;
4137 : // correct offboard timestamp to be in local ms since boot
4138 10472 : uint32_t timestamp_ms = correct_offboard_timestamp_usec_to_ms(usec, payload_size);
4139 :
4140 10472 : AP_VisualOdom *visual_odom = AP::visualodom();
4141 10472 : if (visual_odom == nullptr) {
4142 0 : return;
4143 : }
4144 :
4145 10472 : if (!isnan(covariance[0])) {
4146 10472 : posErr = sqrtf(covariance[0]+covariance[6]+covariance[11]);
4147 10472 : angErr = sqrtf(covariance[15]+covariance[18]+covariance[20]);
4148 : }
4149 :
4150 10472 : visual_odom->handle_pose_estimate(usec, timestamp_ms, x, y, z, roll, pitch, yaw, posErr, angErr, reset_counter, 0);
4151 : }
4152 :
4153 0 : void GCS_MAVLINK::handle_att_pos_mocap(const mavlink_message_t &msg)
4154 : {
4155 : mavlink_att_pos_mocap_t m;
4156 0 : mavlink_msg_att_pos_mocap_decode(&msg, &m);
4157 :
4158 : // correct offboard timestamp to be in local ms since boot
4159 0 : uint32_t timestamp_ms = correct_offboard_timestamp_usec_to_ms(m.time_usec, PAYLOAD_SIZE(chan, ATT_POS_MOCAP));
4160 :
4161 0 : AP_VisualOdom *visual_odom = AP::visualodom();
4162 0 : if (visual_odom == nullptr) {
4163 0 : return;
4164 : }
4165 :
4166 0 : float posErr = 0;
4167 0 : float angErr = 0;
4168 0 : if (!isnan(m.covariance[0])) {
4169 0 : posErr = sqrtf(m.covariance[0]+m.covariance[6]+m.covariance[11]);
4170 0 : angErr = sqrtf(m.covariance[15]+m.covariance[18]+m.covariance[20]);
4171 : }
4172 :
4173 : // note: att_pos_mocap does not include reset counter
4174 0 : visual_odom->handle_pose_estimate(m.time_usec, timestamp_ms, m.x, m.y, m.z, m.q, posErr, angErr, 0, 0);
4175 : }
4176 :
4177 4438 : void GCS_MAVLINK::handle_vision_speed_estimate(const mavlink_message_t &msg)
4178 : {
4179 4438 : AP_VisualOdom *visual_odom = AP::visualodom();
4180 4438 : if (visual_odom == nullptr) {
4181 0 : return;
4182 : }
4183 : mavlink_vision_speed_estimate_t m;
4184 4438 : mavlink_msg_vision_speed_estimate_decode(&msg, &m);
4185 4438 : const Vector3f vel = {m.x, m.y, m.z};
4186 4438 : uint32_t timestamp_ms = correct_offboard_timestamp_usec_to_ms(m.usec, PAYLOAD_SIZE(chan, VISION_SPEED_ESTIMATE));
4187 4438 : float vel_err = 0;
4188 4438 : if (!isnan(m.covariance[0])) {
4189 4438 : vel_err = sqrtf(m.covariance[0]+m.covariance[4]+m.covariance[8]);
4190 : }
4191 4438 : visual_odom->handle_vision_speed_estimate(m.usec, timestamp_ms, vel, vel_err, m.reset_counter, 0);
4192 : }
4193 : #endif // HAL_VISUALODOM_ENABLED
4194 :
4195 7454 : void GCS_MAVLINK::handle_command_ack(const mavlink_message_t &msg)
4196 : {
4197 : mavlink_command_ack_t packet;
4198 7454 : mavlink_msg_command_ack_decode(&msg, &packet);
4199 :
4200 : #if HAL_INS_ACCELCAL_ENABLED
4201 7454 : AP_AccelCal *accelcal = AP::ins().get_acal();
4202 7454 : if (accelcal != nullptr) {
4203 6 : accelcal->handle_command_ack(packet, msg.sysid, msg.compid);
4204 : }
4205 : #endif // HAL_INS_ACCELCAL_ENABLED
4206 :
4207 : #if AP_GENERATOR_LOWEHEISER_ENABLED
4208 : // this might be an ACK from a loweheiser generator:
4209 7454 : handle_generator_message(msg);
4210 : #endif // AP_GENERATOR_LOWEHEISER_ENABLED
4211 7454 : }
4212 :
4213 : #if AP_RC_CHANNEL_ENABLED
4214 : // allow override of RC channel values for complete GCS
4215 : // control of switch position and RC PWM values.
4216 792 : void GCS_MAVLINK::handle_rc_channels_override(const mavlink_message_t &msg)
4217 : {
4218 792 : if (!gcs().sysid_is_gcs(msg.sysid)) {
4219 0 : return; // Only accept control from our gcs
4220 : }
4221 :
4222 792 : const uint32_t tnow = AP_HAL::millis();
4223 :
4224 : mavlink_rc_channels_override_t packet;
4225 792 : mavlink_msg_rc_channels_override_decode(&msg, &packet);
4226 :
4227 : const uint16_t override_data[] = {
4228 792 : packet.chan1_raw,
4229 792 : packet.chan2_raw,
4230 792 : packet.chan3_raw,
4231 792 : packet.chan4_raw,
4232 792 : packet.chan5_raw,
4233 792 : packet.chan6_raw,
4234 792 : packet.chan7_raw,
4235 792 : packet.chan8_raw,
4236 792 : packet.chan9_raw,
4237 792 : packet.chan10_raw,
4238 792 : packet.chan11_raw,
4239 792 : packet.chan12_raw,
4240 792 : packet.chan13_raw,
4241 792 : packet.chan14_raw,
4242 792 : packet.chan15_raw,
4243 792 : packet.chan16_raw
4244 792 : };
4245 :
4246 7128 : for (uint8_t i=0; i<8; i++) {
4247 : // Per MAVLink spec a value of UINT16_MAX means to ignore this field.
4248 6336 : if (override_data[i] != UINT16_MAX) {
4249 1802 : RC_Channels::set_override(i, override_data[i], tnow);
4250 : }
4251 : }
4252 7128 : for (uint8_t i=8; i<ARRAY_SIZE(override_data); i++) {
4253 : // Per MAVLink spec a value of zero or UINT16_MAX means to
4254 : // ignore this field.
4255 6336 : if (override_data[i] != 0 && override_data[i] != UINT16_MAX) {
4256 : // per the mavlink spec, a value of UINT16_MAX-1 means
4257 : // return the field to RC radio values:
4258 305 : const uint16_t value = override_data[i] == (UINT16_MAX-1) ? 0 : override_data[i];
4259 305 : RC_Channels::set_override(i, value, tnow);
4260 : }
4261 : }
4262 :
4263 792 : sysid_mygcs_seen(tnow);
4264 :
4265 : }
4266 : #endif // AP_RC_CHANNEL_ENABLED
4267 :
4268 : #if AP_OPTICALFLOW_ENABLED
4269 0 : void GCS_MAVLINK::handle_optical_flow(const mavlink_message_t &msg)
4270 : {
4271 0 : AP_OpticalFlow *optflow = AP::opticalflow();
4272 0 : if (optflow == nullptr) {
4273 0 : return;
4274 : }
4275 0 : optflow->handle_msg(msg);
4276 : }
4277 : #endif
4278 :
4279 :
4280 : #if AP_COMPASS_CALIBRATION_FIXED_YAW_ENABLED
4281 : /*
4282 : handle MAV_CMD_FIXED_MAG_CAL_YAW
4283 : */
4284 2 : MAV_RESULT GCS_MAVLINK::handle_command_fixed_mag_cal_yaw(const mavlink_command_int_t &packet)
4285 : {
4286 2 : Compass &compass = AP::compass();
4287 2 : if (!compass.mag_cal_fixed_yaw(packet.param1,
4288 2 : uint8_t(packet.param2),
4289 2 : packet.param3,
4290 2 : packet.param4)) {
4291 0 : return MAV_RESULT_FAILED;
4292 : }
4293 2 : return MAV_RESULT_ACCEPTED;
4294 : }
4295 : #endif // AP_COMPASS_CALIBRATION_FIXED_YAW_ENABLED
4296 :
4297 : #if COMPASS_CAL_ENABLED
4298 37 : MAV_RESULT GCS_MAVLINK::handle_command_mag_cal(const mavlink_command_int_t &packet)
4299 : {
4300 37 : return AP::compass().handle_mag_cal_command(packet);
4301 : }
4302 : #endif // COMPASS_CAL_ENABLED
4303 :
4304 : #if AP_MAVLINKCAN_ENABLED
4305 : /*
4306 : handle MAV_CMD_CAN_FORWARD
4307 : */
4308 0 : MAV_RESULT GCS_MAVLINK::handle_can_forward(const mavlink_command_int_t &packet, const mavlink_message_t &msg)
4309 : {
4310 0 : return AP_MAVLinkCAN::handle_can_forward(chan, packet, msg) ? MAV_RESULT_ACCEPTED : MAV_RESULT_FAILED;
4311 : }
4312 :
4313 : /*
4314 : handle CAN_FRAME messages
4315 : */
4316 0 : void GCS_MAVLINK::handle_can_frame(const mavlink_message_t &msg) const
4317 : {
4318 0 : AP_MAVLinkCAN::handle_can_frame(msg);
4319 0 : }
4320 : #endif // AP_MAVLINKCAN_ENABLED
4321 :
4322 497 : void GCS_MAVLINK::handle_distance_sensor(const mavlink_message_t &msg)
4323 : {
4324 : #if AP_RANGEFINDER_ENABLED
4325 497 : RangeFinder *rangefinder = AP::rangefinder();
4326 497 : if (rangefinder != nullptr) {
4327 497 : rangefinder->handle_msg(msg);
4328 : }
4329 : #endif
4330 :
4331 : #if HAL_PROXIMITY_ENABLED
4332 497 : AP_Proximity *proximity = AP::proximity();
4333 497 : if (proximity != nullptr) {
4334 497 : proximity->handle_msg(msg);
4335 : }
4336 : #endif
4337 497 : }
4338 :
4339 : #if HAL_PROXIMITY_ENABLED
4340 3 : void GCS_MAVLINK::handle_obstacle_distance(const mavlink_message_t &msg)
4341 : {
4342 3 : AP_Proximity *proximity = AP::proximity();
4343 3 : if (proximity != nullptr) {
4344 3 : proximity->handle_msg(msg);
4345 : }
4346 3 : }
4347 :
4348 376 : void GCS_MAVLINK::handle_obstacle_distance_3d(const mavlink_message_t &msg)
4349 : {
4350 376 : AP_Proximity *proximity = AP::proximity();
4351 376 : if (proximity != nullptr) {
4352 376 : proximity->handle_msg(msg);
4353 : }
4354 376 : }
4355 : #endif
4356 :
4357 : #if HAL_ADSB_ENABLED
4358 15 : void GCS_MAVLINK::handle_adsb_message(const mavlink_message_t &msg)
4359 : {
4360 15 : AP_ADSB *adsb = AP::ADSB();
4361 15 : if (adsb != nullptr) {
4362 15 : adsb->handle_message(chan, msg);
4363 : }
4364 15 : }
4365 : #endif
4366 :
4367 : #if OSD_PARAM_ENABLED
4368 0 : void GCS_MAVLINK::handle_osd_param_config(const mavlink_message_t &msg) const
4369 : {
4370 0 : AP_OSD *osd = AP::osd();
4371 0 : if (osd != nullptr) {
4372 0 : osd->handle_msg(msg, *this);
4373 : }
4374 0 : }
4375 : #endif
4376 :
4377 1064136 : void GCS_MAVLINK::handle_heartbeat(const mavlink_message_t &msg)
4378 : {
4379 : // if the heartbeat is from our GCS then we don't failsafe for
4380 : // now...
4381 1064136 : if (gcs().sysid_is_gcs(msg.sysid)) {
4382 14071 : sysid_mygcs_seen(AP_HAL::millis());
4383 : }
4384 1064136 : }
4385 :
4386 : /*
4387 : handle messages which don't require vehicle specific data
4388 : */
4389 2777428 : void GCS_MAVLINK::handle_message(const mavlink_message_t &msg)
4390 : {
4391 2777428 : switch (msg.msgid) {
4392 :
4393 1064136 : case MAVLINK_MSG_ID_HEARTBEAT: {
4394 1064136 : handle_heartbeat(msg);
4395 1064136 : break;
4396 : }
4397 :
4398 7454 : case MAVLINK_MSG_ID_COMMAND_ACK: {
4399 7454 : handle_command_ack(msg);
4400 7454 : break;
4401 : }
4402 :
4403 0 : case MAVLINK_MSG_ID_SETUP_SIGNING:
4404 0 : handle_setup_signing(msg);
4405 0 : break;
4406 :
4407 38620 : case MAVLINK_MSG_ID_PARAM_REQUEST_LIST:
4408 : case MAVLINK_MSG_ID_PARAM_SET:
4409 : case MAVLINK_MSG_ID_PARAM_REQUEST_READ:
4410 38620 : handle_common_param_message(msg);
4411 38620 : break;
4412 :
4413 : #if AP_MAVLINK_SET_GPS_GLOBAL_ORIGIN_MESSAGE_ENABLED
4414 5 : case MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN:
4415 5 : handle_set_gps_global_origin(msg);
4416 5 : break;
4417 : #endif
4418 :
4419 : #if AP_MAVLINK_MSG_DEVICE_OP_ENABLED
4420 0 : case MAVLINK_MSG_ID_DEVICE_OP_READ:
4421 0 : handle_device_op_read(msg);
4422 0 : break;
4423 0 : case MAVLINK_MSG_ID_DEVICE_OP_WRITE:
4424 0 : handle_device_op_write(msg);
4425 0 : break;
4426 : #endif
4427 :
4428 14853 : case MAVLINK_MSG_ID_TIMESYNC:
4429 14853 : handle_timesync(msg);
4430 14853 : break;
4431 : #if HAL_LOGGING_ENABLED
4432 23305 : case MAVLINK_MSG_ID_LOG_REQUEST_LIST:
4433 : case MAVLINK_MSG_ID_LOG_REQUEST_DATA:
4434 : case MAVLINK_MSG_ID_LOG_ERASE:
4435 : case MAVLINK_MSG_ID_LOG_REQUEST_END:
4436 : case MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS:
4437 23305 : AP::logger().handle_mavlink_msg(*this, msg);
4438 23305 : break;
4439 : #endif
4440 :
4441 : #if AP_MAVLINK_FTP_ENABLED
4442 125 : case MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL:
4443 125 : GCS_FTP::handle_file_transfer_protocol(msg, chan);
4444 125 : break;
4445 : #endif
4446 :
4447 : #if AP_CAMERA_ENABLED
4448 5 : case MAVLINK_MSG_ID_DIGICAM_CONTROL:
4449 : case MAVLINK_MSG_ID_GOPRO_HEARTBEAT: // heartbeat from a GoPro in Solo gimbal
4450 : case MAVLINK_MSG_ID_CAMERA_INFORMATION:
4451 : {
4452 5 : AP_Camera *camera = AP::camera();
4453 5 : if (camera == nullptr) {
4454 0 : return;
4455 : }
4456 5 : camera->handle_message(chan, msg);
4457 : }
4458 5 : break;
4459 : #endif
4460 :
4461 16 : case MAVLINK_MSG_ID_SET_MODE:
4462 16 : handle_set_mode(msg);
4463 16 : break;
4464 :
4465 : #if AP_MAVLINK_AUTOPILOT_VERSION_REQUEST_ENABLED
4466 0 : case MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST:
4467 0 : handle_send_autopilot_version(msg);
4468 0 : break;
4469 : #endif
4470 :
4471 16732 : case MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST:
4472 : case MAVLINK_MSG_ID_MISSION_REQUEST_LIST:
4473 : case MAVLINK_MSG_ID_MISSION_COUNT:
4474 : case MAVLINK_MSG_ID_MISSION_CLEAR_ALL:
4475 : case MAVLINK_MSG_ID_MISSION_ITEM:
4476 : case MAVLINK_MSG_ID_MISSION_ITEM_INT:
4477 : case MAVLINK_MSG_ID_MISSION_REQUEST_INT:
4478 : case MAVLINK_MSG_ID_MISSION_REQUEST:
4479 : case MAVLINK_MSG_ID_MISSION_ACK:
4480 : case MAVLINK_MSG_ID_MISSION_SET_CURRENT:
4481 16732 : handle_common_mission_message(msg);
4482 16732 : break;
4483 :
4484 530536 : case MAVLINK_MSG_ID_COMMAND_LONG:
4485 530536 : handle_command_long(msg);
4486 528897 : break;
4487 :
4488 618 : case MAVLINK_MSG_ID_COMMAND_INT:
4489 618 : handle_command_int(msg);
4490 618 : break;
4491 :
4492 : #if AP_TERRAIN_AVAILABLE
4493 15 : case MAVLINK_MSG_ID_TERRAIN_DATA:
4494 : case MAVLINK_MSG_ID_TERRAIN_CHECK: {
4495 15 : AP_Terrain *terrain = AP::terrain();
4496 15 : if (terrain != nullptr) {
4497 15 : terrain->handle_message(*this, msg);
4498 : }
4499 15 : break;
4500 : }
4501 : #endif
4502 :
4503 : #if HAL_MOUNT_ENABLED
4504 20919 : case MAVLINK_MSG_ID_GIMBAL_REPORT:
4505 : case MAVLINK_MSG_ID_GIMBAL_DEVICE_INFORMATION:
4506 : case MAVLINK_MSG_ID_GIMBAL_DEVICE_ATTITUDE_STATUS:
4507 : case MAVLINK_MSG_ID_GIMBAL_MANAGER_SET_ATTITUDE:
4508 : case MAVLINK_MSG_ID_GIMBAL_MANAGER_SET_PITCHYAW:
4509 20919 : handle_mount_message(msg);
4510 20919 : break;
4511 : #endif
4512 :
4513 26 : case MAVLINK_MSG_ID_PARAM_VALUE:
4514 26 : handle_param_value(msg);
4515 26 : break;
4516 :
4517 0 : case MAVLINK_MSG_ID_RADIO:
4518 : case MAVLINK_MSG_ID_RADIO_STATUS:
4519 0 : handle_radio_status(msg);
4520 0 : break;
4521 :
4522 : #if AP_MAVLINK_MSG_SERIAL_CONTROL_ENABLED
4523 0 : case MAVLINK_MSG_ID_SERIAL_CONTROL:
4524 0 : handle_serial_control(msg);
4525 0 : break;
4526 : #endif
4527 :
4528 : #if AP_GPS_ENABLED
4529 915 : case MAVLINK_MSG_ID_GPS_RTCM_DATA:
4530 : case MAVLINK_MSG_ID_GPS_INPUT:
4531 : case MAVLINK_MSG_ID_GPS_INJECT_DATA:
4532 915 : AP::gps().handle_msg(chan, msg);
4533 915 : break;
4534 : #endif
4535 :
4536 1027468 : case MAVLINK_MSG_ID_STATUSTEXT:
4537 1027468 : handle_statustext(msg);
4538 1027468 : break;
4539 :
4540 : #if AP_NOTIFY_MAVLINK_LED_CONTROL_SUPPORT_ENABLED
4541 0 : case MAVLINK_MSG_ID_LED_CONTROL:
4542 : // send message to Notify
4543 0 : AP_Notify::handle_led_control(msg);
4544 0 : break;
4545 : #endif
4546 :
4547 : #if AP_RC_CHANNEL_ENABLED
4548 56 : case MAVLINK_MSG_ID_MANUAL_CONTROL:
4549 56 : handle_manual_control(msg);
4550 56 : break;
4551 : #endif
4552 :
4553 : #if AP_NOTIFY_MAVLINK_PLAY_TUNE_SUPPORT_ENABLED
4554 0 : case MAVLINK_MSG_ID_PLAY_TUNE:
4555 : // send message to Notify
4556 0 : AP_Notify::handle_play_tune(msg);
4557 0 : break;
4558 : #endif
4559 :
4560 2124 : case MAVLINK_MSG_ID_REQUEST_DATA_STREAM:
4561 2124 : if (option_enabled(Option::NOSTREAMOVERRIDE)) {
4562 : // options indicate we are to ignore this stream rate
4563 : // request
4564 0 : break;
4565 : }
4566 2124 : handle_request_data_stream(msg);
4567 2124 : break;
4568 :
4569 0 : case MAVLINK_MSG_ID_DATA96:
4570 0 : handle_data_packet(msg);
4571 0 : break;
4572 :
4573 : #if HAL_VISUALODOM_ENABLED
4574 3735 : case MAVLINK_MSG_ID_VISION_POSITION_DELTA:
4575 3735 : handle_vision_position_delta(msg);
4576 3735 : break;
4577 :
4578 10472 : case MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE:
4579 10472 : handle_vision_position_estimate(msg);
4580 10472 : break;
4581 :
4582 0 : case MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE:
4583 0 : handle_global_vision_position_estimate(msg);
4584 0 : break;
4585 :
4586 0 : case MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE:
4587 0 : handle_vicon_position_estimate(msg);
4588 0 : break;
4589 :
4590 0 : case MAVLINK_MSG_ID_ODOMETRY:
4591 0 : handle_odometry(msg);
4592 0 : break;
4593 :
4594 0 : case MAVLINK_MSG_ID_ATT_POS_MOCAP:
4595 0 : handle_att_pos_mocap(msg);
4596 0 : break;
4597 :
4598 4438 : case MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE:
4599 4438 : handle_vision_speed_estimate(msg);
4600 4438 : break;
4601 : #endif // HAL_VISUALODOM_ENABLED
4602 :
4603 : #if AP_RTC_ENABLED
4604 2 : case MAVLINK_MSG_ID_SYSTEM_TIME:
4605 2 : handle_system_time_message(msg);
4606 2 : break;
4607 : #endif
4608 :
4609 : #if AP_RC_CHANNEL_ENABLED
4610 792 : case MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE:
4611 792 : handle_rc_channels_override(msg);
4612 792 : break;
4613 : #if AP_RCPROTOCOL_MAVLINK_RADIO_ENABLED
4614 0 : case MAVLINK_MSG_ID_RADIO_RC_CHANNELS:
4615 0 : handle_radio_rc_channels(msg);
4616 0 : break;
4617 : #endif
4618 : #endif
4619 :
4620 : #if AP_OPTICALFLOW_ENABLED
4621 0 : case MAVLINK_MSG_ID_OPTICAL_FLOW:
4622 0 : handle_optical_flow(msg);
4623 0 : break;
4624 : #endif
4625 :
4626 497 : case MAVLINK_MSG_ID_DISTANCE_SENSOR:
4627 497 : handle_distance_sensor(msg);
4628 497 : break;
4629 :
4630 : #if HAL_PROXIMITY_ENABLED
4631 3 : case MAVLINK_MSG_ID_OBSTACLE_DISTANCE:
4632 3 : handle_obstacle_distance(msg);
4633 3 : break;
4634 :
4635 376 : case MAVLINK_MSG_ID_OBSTACLE_DISTANCE_3D:
4636 376 : handle_obstacle_distance_3d(msg);
4637 376 : break;
4638 : #endif
4639 :
4640 : #if OSD_PARAM_ENABLED
4641 0 : case MAVLINK_MSG_ID_OSD_PARAM_CONFIG:
4642 : case MAVLINK_MSG_ID_OSD_PARAM_SHOW_CONFIG:
4643 0 : handle_osd_param_config(msg);
4644 0 : break;
4645 : #endif
4646 :
4647 : #if HAL_ADSB_ENABLED
4648 15 : case MAVLINK_MSG_ID_ADSB_VEHICLE:
4649 : case MAVLINK_MSG_ID_UAVIONIX_ADSB_OUT_CFG:
4650 : case MAVLINK_MSG_ID_UAVIONIX_ADSB_OUT_DYNAMIC:
4651 : case MAVLINK_MSG_ID_UAVIONIX_ADSB_TRANSCEIVER_HEALTH_REPORT:
4652 : case MAVLINK_MSG_ID_UAVIONIX_ADSB_OUT_CONTROL:
4653 15 : handle_adsb_message(msg);
4654 15 : break;
4655 : #endif
4656 :
4657 671 : case MAVLINK_MSG_ID_LANDING_TARGET:
4658 671 : handle_landing_target(msg);
4659 671 : break;
4660 :
4661 0 : case MAVLINK_MSG_ID_NAMED_VALUE_FLOAT:
4662 0 : handle_named_value(msg);
4663 0 : break;
4664 :
4665 : #if HAL_CANMANAGER_ENABLED
4666 0 : case MAVLINK_MSG_ID_CAN_FRAME:
4667 : case MAVLINK_MSG_ID_CANFD_FRAME:
4668 0 : handle_can_frame(msg);
4669 0 : break;
4670 : #endif
4671 :
4672 : #if AP_MAVLINKCAN_ENABLED
4673 0 : case MAVLINK_MSG_ID_CAN_FILTER_MODIFY:
4674 0 : AP_MAVLinkCAN::handle_can_filter_modify(msg);
4675 0 : break;
4676 : #endif // AP_MAVLINKCAN_ENABLED
4677 :
4678 : #if AP_OPENDRONEID_ENABLED
4679 0 : case MAVLINK_MSG_ID_OPEN_DRONE_ID_ARM_STATUS:
4680 : case MAVLINK_MSG_ID_OPEN_DRONE_ID_OPERATOR_ID:
4681 : case MAVLINK_MSG_ID_OPEN_DRONE_ID_SELF_ID:
4682 : case MAVLINK_MSG_ID_OPEN_DRONE_ID_BASIC_ID:
4683 : case MAVLINK_MSG_ID_OPEN_DRONE_ID_SYSTEM:
4684 : case MAVLINK_MSG_ID_OPEN_DRONE_ID_SYSTEM_UPDATE:
4685 0 : AP::opendroneid().handle_msg(chan, msg);
4686 0 : break;
4687 : #endif
4688 :
4689 : #if AP_SIGNED_FIRMWARE
4690 : case MAVLINK_MSG_ID_SECURE_COMMAND:
4691 : case MAVLINK_MSG_ID_SECURE_COMMAND_REPLY:
4692 : AP_CheckFirmware::handle_msg(chan, msg);
4693 : break;
4694 : #endif
4695 :
4696 : #if AP_EFI_MAV_ENABLED
4697 0 : case MAVLINK_MSG_ID_EFI_STATUS:
4698 : {
4699 0 : AP_EFI *efi = AP::EFI();
4700 0 : if (efi) {
4701 0 : efi->handle_EFI_message(msg);
4702 : }
4703 0 : break;
4704 : }
4705 : #endif
4706 : #if AP_GENERATOR_LOWEHEISER_ENABLED
4707 3815 : case MAVLINK_MSG_ID_LOWEHEISER_GOV_EFI:
4708 : // message received from Loweheiser mavlink connection
4709 3815 : handle_generator_message(msg);
4710 3815 : break;
4711 : #endif
4712 : }
4713 :
4714 : }
4715 :
4716 11269 : void GCS_MAVLINK::handle_generator_message(const mavlink_message_t &msg)
4717 : {
4718 : #if AP_GENERATOR_LOWEHEISER_ENABLED
4719 11269 : AP_Generator *generator = AP::generator();
4720 11269 : if (generator == nullptr) {
4721 0 : return;
4722 : }
4723 :
4724 11269 : auto *backend = generator->get_loweheiser();
4725 11269 : if (backend == nullptr) {
4726 64 : return;
4727 : }
4728 :
4729 11205 : backend->handle_mavlink_msg(*this, msg);
4730 : #endif
4731 : }
4732 :
4733 16732 : void GCS_MAVLINK::handle_common_mission_message(const mavlink_message_t &msg)
4734 : {
4735 16732 : switch (msg.msgid) {
4736 5 : case MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST: // MAV ID: 38
4737 : {
4738 5 : handle_mission_write_partial_list(msg);
4739 5 : break;
4740 : }
4741 :
4742 : // GCS has sent us a mission item, store to EEPROM
4743 5247 : case MAVLINK_MSG_ID_MISSION_ITEM: // MAV ID: 39
4744 : case MAVLINK_MSG_ID_MISSION_ITEM_INT:
4745 5247 : handle_mission_item(msg);
4746 5247 : break;
4747 :
4748 : // read an individual command from EEPROM and send it to the GCS
4749 5582 : case MAVLINK_MSG_ID_MISSION_REQUEST_INT:
4750 5582 : handle_mission_request_int(msg);
4751 5582 : break;
4752 :
4753 : #if AP_MAVLINK_MSG_MISSION_REQUEST_ENABLED
4754 0 : case MAVLINK_MSG_ID_MISSION_REQUEST:
4755 0 : handle_mission_request(msg);
4756 0 : break;
4757 : #endif
4758 :
4759 : #if AP_MAVLINK_MISSION_SET_CURRENT_ENABLED
4760 2250 : case MAVLINK_MSG_ID_MISSION_SET_CURRENT: // MAV ID: 41
4761 2250 : handle_mission_set_current(AP::mission(), msg);
4762 2250 : break;
4763 : #endif
4764 :
4765 : // GCS request the full list of commands, we return just the number and leave the GCS to then request each command individually
4766 467 : case MAVLINK_MSG_ID_MISSION_REQUEST_LIST: // MAV ID: 43
4767 : {
4768 467 : handle_mission_request_list(msg);
4769 467 : break;
4770 : }
4771 :
4772 : // GCS provides the full number of commands it wishes to upload
4773 : // individual commands will then be sent from the GCS using the MAVLINK_MSG_ID_MISSION_ITEM message
4774 3177 : case MAVLINK_MSG_ID_MISSION_COUNT: // MAV ID: 44
4775 : {
4776 3177 : handle_mission_count(msg);
4777 3177 : break;
4778 : }
4779 :
4780 4 : case MAVLINK_MSG_ID_MISSION_CLEAR_ALL: // MAV ID: 45
4781 : {
4782 4 : handle_mission_clear_all(msg);
4783 4 : break;
4784 : }
4785 :
4786 0 : case MAVLINK_MSG_ID_MISSION_ACK:
4787 : /* not used */
4788 0 : break;
4789 : }
4790 16732 : }
4791 :
4792 : #if AP_MAVLINK_AUTOPILOT_VERSION_REQUEST_ENABLED
4793 0 : void GCS_MAVLINK::handle_send_autopilot_version(const mavlink_message_t &msg)
4794 : {
4795 0 : send_message(MSG_AUTOPILOT_VERSION);
4796 0 : }
4797 : #endif
4798 :
4799 1004 : void GCS_MAVLINK::send_banner()
4800 : {
4801 : // mark the firmware version in the tlog
4802 1004 : const AP_FWVersion &fwver = AP::fwversion();
4803 :
4804 1004 : send_text(MAV_SEVERITY_INFO, "%s", fwver.fw_string);
4805 :
4806 1004 : if (fwver.middleware_name && fwver.os_name) {
4807 0 : send_text(MAV_SEVERITY_INFO, "%s: %s %s: %s",
4808 0 : fwver.middleware_name, fwver.middleware_hash_str,
4809 0 : fwver.os_name, fwver.os_hash_str);
4810 1004 : } else if (fwver.os_name) {
4811 0 : send_text(MAV_SEVERITY_INFO, "%s: %s",
4812 0 : fwver.os_name, fwver.os_hash_str);
4813 : }
4814 :
4815 : // send system ID if we can
4816 : char sysid[50];
4817 1004 : if (hal.util->get_system_id(sysid)) {
4818 1004 : send_text(MAV_SEVERITY_INFO, "%s", sysid);
4819 : }
4820 :
4821 : // send MCUID if we can
4822 : #if HAL_WITH_IO_MCU
4823 : #define REVID_MASK 0xFFFF0000
4824 : #define DEVID_MASK 0xFFF
4825 : if (AP_BoardConfig::io_enabled()) {
4826 : uint32_t mcuid = iomcu.get_mcu_id();
4827 : send_text(MAV_SEVERITY_INFO, "IOMCU: %x %x %lx", uint16_t(mcuid & DEVID_MASK), uint16_t((mcuid & REVID_MASK) >> 16U),
4828 : iomcu.get_cpu_id());
4829 : }
4830 : #endif
4831 :
4832 : // send RC output mode info if available
4833 : char banner_msg[50];
4834 1004 : if (hal.rcout->get_output_mode_banner(banner_msg, sizeof(banner_msg))) {
4835 0 : send_text(MAV_SEVERITY_INFO, "%s", banner_msg);
4836 : }
4837 :
4838 : #if AP_INERTIALSENSOR_ENABLED
4839 : // output any fast sampling status messages
4840 7028 : for (uint8_t i = 0; i < INS_MAX_BACKENDS; i++) {
4841 6024 : if (AP::ins().get_output_banner(i, banner_msg, sizeof(banner_msg))) {
4842 0 : send_text(MAV_SEVERITY_INFO, "%s", banner_msg);
4843 : }
4844 : }
4845 : #endif
4846 1004 : }
4847 :
4848 :
4849 : #if AP_SIM_ENABLED
4850 1127758 : void GCS_MAVLINK::send_simstate() const
4851 : {
4852 1127758 : SITL::SIM *sitl = AP::sitl();
4853 1127758 : if (sitl == nullptr) {
4854 0 : return;
4855 : }
4856 1127758 : sitl->simstate_send(get_chan());
4857 : }
4858 :
4859 2791 : void GCS_MAVLINK::send_sim_state() const
4860 : {
4861 2791 : SITL::SIM *sitl = AP::sitl();
4862 2791 : if (sitl == nullptr) {
4863 0 : return;
4864 : }
4865 2791 : sitl->sim_state_send(get_chan());
4866 : }
4867 : #endif
4868 :
4869 : #if AP_AHRS_ENABLED
4870 3 : MAV_RESULT GCS_MAVLINK::handle_command_do_set_global_origin(const mavlink_command_int_t &packet)
4871 : {
4872 3 : Location global_origin;
4873 3 : if (!location_from_command_t(packet, global_origin)) {
4874 1 : return MAV_RESULT_DENIED;
4875 : }
4876 :
4877 2 : return set_ekf_origin(global_origin);
4878 : }
4879 : #endif // AP_AHRS_ENABLED
4880 :
4881 : #if AP_BOOTLOADER_FLASHING_ENABLED
4882 : MAV_RESULT GCS_MAVLINK::handle_command_flash_bootloader(const mavlink_command_int_t &packet)
4883 : {
4884 : if (packet.x != 290876) {
4885 : GCS_SEND_TEXT(MAV_SEVERITY_INFO, "Magic not set");
4886 : return MAV_RESULT_FAILED;
4887 : }
4888 :
4889 : switch (hal.util->flash_bootloader()) {
4890 : case AP_HAL::Util::FlashBootloader::OK:
4891 : case AP_HAL::Util::FlashBootloader::NO_CHANGE:
4892 : // consider NO_CHANGE as success (so as not to display error to user)
4893 : return MAV_RESULT_ACCEPTED;
4894 : #if AP_SIGNED_FIRMWARE
4895 : case AP_HAL::Util::FlashBootloader::NOT_SIGNED:
4896 : GCS_SEND_TEXT(MAV_SEVERITY_ERROR, "Bootloader not signed");
4897 : break;
4898 : #endif
4899 : default:
4900 : break;
4901 : }
4902 :
4903 : return MAV_RESULT_FAILED;
4904 : }
4905 : #endif // AP_BOOTLOADER_FLASHING_ENABLED
4906 :
4907 6 : MAV_RESULT GCS_MAVLINK::_handle_command_preflight_calibration_baro(const mavlink_message_t &msg)
4908 : {
4909 : #if AP_BARO_CALIBRATION_ENABLED
4910 : // fast barometer calibration
4911 6 : GCS_SEND_TEXT(MAV_SEVERITY_INFO, "Updating barometer calibration");
4912 6 : AP::baro().update_calibration();
4913 6 : GCS_SEND_TEXT(MAV_SEVERITY_INFO, "Barometer calibration complete");
4914 : #endif // AP_BARO_CALIBRATION_ENABLED
4915 :
4916 : #if AP_AIRSPEED_ENABLED
4917 :
4918 6 : AP_Airspeed *airspeed = AP_Airspeed::get_singleton();
4919 6 : if (airspeed != nullptr && airspeed->enabled()) {
4920 5 : GCS_MAVLINK_InProgress *task = GCS_MAVLINK_InProgress::get_task(MAV_CMD_PREFLIGHT_CALIBRATION, GCS_MAVLINK_InProgress::Type::AIRSPEED_CAL, msg.sysid, msg.compid, chan);
4921 5 : if (task == nullptr) {
4922 0 : return MAV_RESULT_TEMPORARILY_REJECTED;
4923 : }
4924 5 : airspeed->calibrate(false);
4925 5 : return MAV_RESULT_IN_PROGRESS;
4926 : }
4927 : #endif
4928 :
4929 1 : return MAV_RESULT_ACCEPTED;
4930 : }
4931 :
4932 51 : MAV_RESULT GCS_MAVLINK::_handle_command_preflight_calibration(const mavlink_command_int_t &packet, const mavlink_message_t &msg)
4933 : {
4934 51 : MAV_RESULT ret = MAV_RESULT_UNSUPPORTED;
4935 :
4936 51 : EXPECT_DELAY_MS(30000);
4937 51 : if (is_equal(packet.param1,1.0f)) {
4938 : #if AP_INERTIALSENSOR_ENABLED
4939 2 : if (!AP::ins().calibrate_gyros()) {
4940 0 : return MAV_RESULT_FAILED;
4941 : }
4942 : #else
4943 : return MAV_RESULT_UNSUPPORTED;
4944 : #endif
4945 2 : return MAV_RESULT_ACCEPTED;
4946 : }
4947 :
4948 49 : if (is_equal(packet.param3,1.0f)) {
4949 6 : return _handle_command_preflight_calibration_baro(msg);
4950 : }
4951 :
4952 : #if AP_RC_CHANNEL_ENABLED
4953 43 : rc().calibrating(is_positive(packet.param4));
4954 : #endif
4955 :
4956 : #if HAL_INS_ACCELCAL_ENABLED
4957 43 : if (packet.x == PREFLIGHT_CALIBRATION_ACCELEROMETER_FULL) {
4958 : // start with gyro calibration
4959 2 : if (!AP::ins().calibrate_gyros()) {
4960 0 : return MAV_RESULT_FAILED;
4961 : }
4962 : // start accel cal
4963 2 : AP::ins().acal_init();
4964 2 : AP::ins().get_acal()->start(this, msg.sysid, msg.compid);
4965 2 : return MAV_RESULT_ACCEPTED;
4966 : }
4967 : #endif
4968 :
4969 : #if AP_INERTIALSENSOR_ENABLED
4970 : #if AP_AHRS_ENABLED
4971 41 : if (packet.x == PREFLIGHT_CALIBRATION_ACCELEROMETER_TRIM) {
4972 3 : return AP::ins().calibrate_trim();
4973 : }
4974 : #endif
4975 :
4976 38 : if (packet.x == PREFLIGHT_CALIBRATION_ACCELEROMETER_SIMPLE) {
4977 : // simple accel calibration
4978 27 : return AP::ins().simple_accel_cal();
4979 : }
4980 :
4981 : /*
4982 : allow GCS to force an existing calibration of accel and/or
4983 : compass to be written as valid. This is useful when reloading
4984 : parameters after a full parameter erase
4985 : */
4986 11 : if (packet.x == PREFLIGHT_CALIBRATION_ACCELEROMETER_FORCE_SAVE) {
4987 : // force existing accel calibration to be accepted as valid
4988 3 : AP::ins().force_save_calibration();
4989 3 : ret = MAV_RESULT_ACCEPTED;
4990 : }
4991 : #endif // AP_INERTIALSENSOR_ENABLED
4992 :
4993 : #if AP_COMPASS_ENABLED
4994 11 : if (is_equal(packet.param2, static_cast<float>(PREFLIGHT_CALIBRATION_MAGNETOMETER_FORCE_SAVE))) {
4995 : // force existing compass calibration to be accepted as valid
4996 8 : AP::compass().force_save_calibration();
4997 8 : ret = MAV_RESULT_ACCEPTED;
4998 : }
4999 : #endif
5000 :
5001 11 : return ret;
5002 51 : }
5003 :
5004 54 : MAV_RESULT GCS_MAVLINK::handle_command_preflight_calibration(const mavlink_command_int_t &packet, const mavlink_message_t &msg)
5005 : {
5006 54 : if (hal.util->get_soft_armed()) {
5007 : // *preflight*, remember?
5008 2 : GCS_SEND_TEXT(MAV_SEVERITY_NOTICE, "Disarm to allow calibration");
5009 2 : return MAV_RESULT_FAILED;
5010 : }
5011 : // now call subclass methods:
5012 52 : return _handle_command_preflight_calibration(packet, msg);
5013 : }
5014 :
5015 : #if AP_ARMING_ENABLED
5016 66595 : MAV_RESULT GCS_MAVLINK::handle_command_run_prearm_checks(const mavlink_command_int_t &packet)
5017 : {
5018 66595 : if (hal.util->get_soft_armed()) {
5019 0 : return MAV_RESULT_TEMPORARILY_REJECTED;
5020 : }
5021 66595 : (void)AP::arming().pre_arm_checks(true);
5022 66595 : return MAV_RESULT_ACCEPTED;
5023 : }
5024 : #endif // AP_ARMING_ENABLED
5025 :
5026 : #if AP_MISSION_ENABLED
5027 : // changes the current waypoint; at time of writing GCS
5028 : // implementations use the mavlink message MISSION_SET_CURRENT to set
5029 : // the current waypoint, rather than this DO command. It is hoped we
5030 : // can move to this command in the future to avoid acknowledgement
5031 : // issues with MISSION_SET_CURRENT
5032 12 : MAV_RESULT GCS_MAVLINK::handle_command_do_set_mission_current(const mavlink_command_int_t &packet)
5033 : {
5034 12 : AP_Mission &mission = AP::mission();
5035 :
5036 12 : if (is_equal(packet.param1, -1.0f) || packet.param1 >= 0) {
5037 : // these are the only values we handle - either -1 meaning do
5038 : // not reset waypoint (but reset counters) or a non-negative
5039 : // waypoint number
5040 : } else {
5041 : // invalid param1
5042 1 : return MAV_RESULT_DENIED;
5043 : }
5044 :
5045 11 : if (packet.param1 >= 0) {
5046 9 : const uint32_t seq = (uint32_t)packet.param1;
5047 9 : if (seq > INT16_MAX || !mission.is_valid_index(seq)) {
5048 2 : return MAV_RESULT_FAILED;
5049 : }
5050 : }
5051 :
5052 : // From https://mavlink.io/en/messages/common.html#MAV_CMD_DO_SET_MISSION_CURRENT:
5053 : // Param 2: Reset Mission
5054 : // - Resets mission. 1: true, 0: false. Resets jump counters to initial values
5055 : // and changes mission state "completed" to be "active" or "paused".
5056 9 : const bool reset_and_restart = is_equal(packet.param2, 1.0f);
5057 9 : if (reset_and_restart) {
5058 : // reset jump counters only
5059 3 : mission.reset_jump_counters();
5060 : }
5061 9 : if (packet.param1 >= 0) {
5062 7 : const uint32_t seq = (uint32_t)packet.param1;
5063 7 : if (!mission.set_current_cmd(seq)) {
5064 0 : return MAV_RESULT_FAILED;
5065 : }
5066 : }
5067 9 : if (reset_and_restart && packet.param1 >= 0) {
5068 2 : mission.resume();
5069 : }
5070 :
5071 : // volunteer the new current waypoint for all listeners
5072 9 : send_message(MSG_CURRENT_WAYPOINT);
5073 :
5074 9 : return MAV_RESULT_ACCEPTED;
5075 : }
5076 :
5077 5 : MAV_RESULT GCS_MAVLINK::handle_command_do_jump_tag(const mavlink_command_int_t &packet)
5078 : {
5079 5 : const uint32_t tag = (uint32_t)packet.param1;
5080 5 : if (tag > UINT16_MAX) {
5081 1 : return MAV_RESULT_DENIED;
5082 : }
5083 4 : if (!AP::mission().jump_to_tag(tag)) {
5084 3 : return MAV_RESULT_FAILED;
5085 : }
5086 :
5087 : // volunteer the new current waypoint for all listeners
5088 1 : send_message(MSG_CURRENT_WAYPOINT);
5089 :
5090 1 : return MAV_RESULT_ACCEPTED;
5091 : }
5092 : #endif
5093 :
5094 : #if AP_BATTERY_ENABLED
5095 18 : MAV_RESULT GCS_MAVLINK::handle_command_battery_reset(const mavlink_command_int_t &packet)
5096 : {
5097 18 : const uint16_t battery_mask = packet.param1;
5098 18 : const float percentage = packet.param2;
5099 18 : if (AP::battery().reset_remaining_mask(battery_mask, percentage)) {
5100 18 : return MAV_RESULT_ACCEPTED;
5101 : }
5102 0 : return MAV_RESULT_FAILED;
5103 : }
5104 : #endif
5105 :
5106 : #if AP_MAVLINK_MAV_CMD_REQUEST_AUTOPILOT_CAPABILITIES_ENABLED
5107 28 : MAV_RESULT GCS_MAVLINK::handle_command_request_autopilot_capabilities(const mavlink_command_int_t &packet)
5108 : {
5109 28 : if (!is_equal(packet.param1,1.0f)) {
5110 0 : return MAV_RESULT_FAILED;
5111 : }
5112 :
5113 28 : send_message(MSG_AUTOPILOT_VERSION);
5114 :
5115 28 : return MAV_RESULT_ACCEPTED;
5116 : }
5117 : #endif
5118 :
5119 3313 : MAV_RESULT GCS_MAVLINK::handle_command_do_set_mode(const mavlink_command_int_t &packet)
5120 : {
5121 3313 : const uint8_t _base_mode = (uint8_t)packet.param1;
5122 3313 : const uint32_t _custom_mode = (uint32_t)packet.param2;
5123 :
5124 3313 : return _set_mode_common(_base_mode, _custom_mode);
5125 : }
5126 :
5127 : #if AP_MAVLINK_MAV_CMD_GET_HOME_POSITION_ENABLED
5128 4738 : MAV_RESULT GCS_MAVLINK::handle_command_get_home_position(const mavlink_command_int_t &packet)
5129 : {
5130 4738 : if (!AP::ahrs().home_is_set()) {
5131 2785 : return MAV_RESULT_FAILED;
5132 : }
5133 1953 : if (!try_send_message(MSG_HOME)) {
5134 : // try again later
5135 0 : send_message(MSG_HOME);
5136 : }
5137 1953 : if (!try_send_message(MSG_ORIGIN)) {
5138 : // try again later
5139 0 : send_message(MSG_ORIGIN);
5140 : }
5141 :
5142 1953 : return MAV_RESULT_ACCEPTED;
5143 : }
5144 : #endif // AP_MAVLINK_MAV_CMD_GET_HOME_POSITION_ENABLED
5145 :
5146 0 : MAV_RESULT GCS_MAVLINK::handle_command_debug_trap(const mavlink_command_int_t &packet)
5147 : {
5148 : // magic number must be supplied to trap; you must *really* mean it.
5149 0 : if (uint32_t(packet.param1) != 32451) {
5150 0 : return MAV_RESULT_DENIED;
5151 : }
5152 0 : if (hal.util->trap()) {
5153 0 : return MAV_RESULT_ACCEPTED;
5154 : }
5155 0 : return MAV_RESULT_UNSUPPORTED;
5156 : }
5157 :
5158 : #if AP_AHRS_ENABLED
5159 6 : MAV_RESULT GCS_MAVLINK::handle_command_set_ekf_source_set(const mavlink_command_int_t &packet)
5160 : {
5161 : // source set must be between 1 and 3
5162 6 : uint32_t source_set = uint32_t(packet.param1);
5163 6 : if ((source_set >= 1) && (source_set <= 3)) {
5164 : // mavlink command uses range 1 to 3 while ahrs interface accepts 0 to 2
5165 4 : AP::ahrs().set_posvelyaw_source_set((AP_NavEKF_Source::SourceSetSelection)(source_set-1));
5166 4 : return MAV_RESULT_ACCEPTED;
5167 : }
5168 2 : return MAV_RESULT_DENIED;
5169 : }
5170 : #endif
5171 :
5172 : #if AP_GRIPPER_ENABLED
5173 16 : MAV_RESULT GCS_MAVLINK::handle_command_do_gripper(const mavlink_command_int_t &packet)
5174 : {
5175 16 : AP_Gripper &gripper = AP::gripper();
5176 :
5177 : // param1 : gripper number (ignored)
5178 : // param2 : action (0=release, 1=grab). See GRIPPER_ACTIONS enum.
5179 16 : if(!gripper.enabled()) {
5180 0 : return MAV_RESULT_FAILED;
5181 : }
5182 :
5183 16 : MAV_RESULT result = MAV_RESULT_ACCEPTED;
5184 :
5185 16 : switch ((uint8_t)packet.param2) {
5186 8 : case GRIPPER_ACTION_RELEASE:
5187 8 : gripper.release();
5188 8 : break;
5189 8 : case GRIPPER_ACTION_GRAB:
5190 8 : gripper.grab();
5191 8 : break;
5192 0 : default:
5193 0 : result = MAV_RESULT_FAILED;
5194 0 : break;
5195 : }
5196 :
5197 16 : return result;
5198 : }
5199 : #endif // AP_GRIPPER_ENABLED
5200 :
5201 : #if HAL_SPRAYER_ENABLED
5202 4 : MAV_RESULT GCS_MAVLINK::handle_command_do_sprayer(const mavlink_command_int_t &packet)
5203 : {
5204 4 : AC_Sprayer *sprayer = AP::sprayer();
5205 4 : if (sprayer == nullptr) {
5206 0 : return MAV_RESULT_FAILED;
5207 : }
5208 :
5209 4 : if (is_equal(packet.param1, 1.0f)) {
5210 2 : sprayer->run(true);
5211 2 : } else if (is_zero(packet.param1)) {
5212 2 : sprayer->run(false);
5213 : }
5214 :
5215 4 : return MAV_RESULT_ACCEPTED;
5216 : }
5217 : #endif
5218 :
5219 : #if AP_LANDINGGEAR_ENABLED
5220 : /*
5221 : handle MAV_CMD_AIRFRAME_CONFIGURATION for landing gear control
5222 : */
5223 4 : MAV_RESULT GCS_MAVLINK::handle_command_airframe_configuration(const mavlink_command_int_t &packet)
5224 : {
5225 : // Param 1: Select which gear, not used in ArduPilot
5226 : // Param 2: 0 = Deploy, 1 = Retract
5227 : // For safety, anything other than 1 will deploy
5228 4 : AP_LandingGear *lg = AP_LandingGear::get_singleton();
5229 4 : if (lg == nullptr) {
5230 0 : return MAV_RESULT_UNSUPPORTED;
5231 : }
5232 4 : switch ((uint8_t)packet.param2) {
5233 1 : case 1:
5234 1 : lg->set_position(AP_LandingGear::LandingGear_Retract);
5235 1 : return MAV_RESULT_ACCEPTED;
5236 3 : default:
5237 3 : lg->set_position(AP_LandingGear::LandingGear_Deploy);
5238 3 : return MAV_RESULT_ACCEPTED;
5239 : }
5240 : return MAV_RESULT_FAILED;
5241 : }
5242 : #endif
5243 :
5244 : #if HAL_INS_ACCELCAL_ENABLED
5245 0 : MAV_RESULT GCS_MAVLINK::handle_command_accelcal_vehicle_pos(const mavlink_command_int_t &packet)
5246 : {
5247 0 : if (AP::ins().get_acal() == nullptr ||
5248 0 : !AP::ins().get_acal()->gcs_vehicle_position(packet.param1)) {
5249 0 : return MAV_RESULT_FAILED;
5250 : }
5251 0 : return MAV_RESULT_ACCEPTED;
5252 : }
5253 : #endif // HAL_INS_ACCELCAL_ENABLED
5254 :
5255 : #if HAL_MOUNT_ENABLED
5256 437 : MAV_RESULT GCS_MAVLINK::handle_command_mount(const mavlink_command_int_t &packet, const mavlink_message_t &msg)
5257 : {
5258 437 : AP_Mount *mount = AP::mount();
5259 437 : if (mount == nullptr) {
5260 0 : return MAV_RESULT_UNSUPPORTED;
5261 : }
5262 437 : return mount->handle_command(packet, msg);
5263 : }
5264 : #endif // HAL_MOUNT_ENABLED
5265 :
5266 : #if AP_ARMING_ENABLED
5267 1681 : MAV_RESULT GCS_MAVLINK::handle_command_component_arm_disarm(const mavlink_command_int_t &packet)
5268 : {
5269 1681 : if (is_equal(packet.param1,1.0f)) {
5270 1178 : if (AP::arming().is_armed()) {
5271 26 : return MAV_RESULT_ACCEPTED;
5272 : }
5273 : // run pre_arm_checks and arm_checks and display failures
5274 1152 : const bool do_arming_checks = !is_equal(packet.param2,magic_force_arm_value) && !is_equal(packet.param2,magic_force_arm_disarm_value);
5275 1152 : if (AP::arming().arm(AP_Arming::Method::MAVLINK, do_arming_checks)) {
5276 1084 : return MAV_RESULT_ACCEPTED;
5277 : }
5278 68 : return MAV_RESULT_FAILED;
5279 : }
5280 503 : if (is_zero(packet.param1)) {
5281 503 : if (!AP::arming().is_armed()) {
5282 32 : return MAV_RESULT_ACCEPTED;
5283 : }
5284 471 : const bool forced = is_equal(packet.param2, magic_force_arm_disarm_value);
5285 : // note disarm()'s second parameter is "do_disarm_checks"
5286 471 : if (AP::arming().disarm(AP_Arming::Method::MAVLINK, !forced)) {
5287 464 : return MAV_RESULT_ACCEPTED;
5288 : }
5289 7 : return MAV_RESULT_FAILED;
5290 : }
5291 :
5292 0 : return MAV_RESULT_UNSUPPORTED;
5293 : }
5294 : #endif // AP_ARMING_ENABLED
5295 :
5296 202 : bool GCS_MAVLINK::location_from_command_t(const mavlink_command_int_t &in, Location &out)
5297 : {
5298 : // sanity check location
5299 202 : if (!check_latlng(in.x, in.y)) {
5300 2 : return false;
5301 : }
5302 :
5303 200 : if (!command_long_stores_location((MAV_CMD)in.command)) {
5304 0 : return false;
5305 : }
5306 :
5307 : // integer storage imposes limits on the altitudes we can accept:
5308 200 : if (isnan(in.z) || fabsf(in.z) > LOCATION_ALT_MAX_M) {
5309 0 : return false;
5310 : }
5311 :
5312 : Location::AltFrame frame;
5313 200 : if (!mavlink_coordinate_frame_to_location_alt_frame((MAV_FRAME)in.frame, frame)) {
5314 : // unknown coordinate frame
5315 0 : return false;
5316 : }
5317 :
5318 200 : out.lat = in.x;
5319 200 : out.lng = in.y;
5320 :
5321 200 : out.set_alt_m(in.z, frame);
5322 :
5323 200 : return true;
5324 : }
5325 :
5326 1590145 : bool GCS_MAVLINK::command_long_stores_location(const MAV_CMD command)
5327 : {
5328 1590145 : switch(command) {
5329 284 : case MAV_CMD_DO_SET_HOME:
5330 : case MAV_CMD_DO_SET_ROI:
5331 : case MAV_CMD_DO_SET_ROI_LOCATION:
5332 : // case MAV_CMD_NAV_TAKEOFF: // technically yes, but we don't do lat/lng
5333 : // case MAV_CMD_NAV_VTOL_TAKEOFF:
5334 : case MAV_CMD_DO_REPOSITION:
5335 : case MAV_CMD_EXTERNAL_POSITION_ESTIMATE:
5336 : case MAV_CMD_DO_SET_GLOBAL_ORIGIN:
5337 284 : return true;
5338 1589861 : default:
5339 1589861 : return false;
5340 : }
5341 : return false;
5342 : }
5343 :
5344 : #if AP_MAVLINK_COMMAND_LONG_ENABLED
5345 : // when conveyed via COMMAND_LONG, a command doesn't come with an
5346 : // explicit frame. When conveying a location they do have an assumed
5347 : // frame in ArduPilot, and this function returns that frame.
5348 28 : bool GCS_MAVLINK::mav_frame_for_command_long(MAV_FRAME &frame, MAV_CMD packet_command) const
5349 : {
5350 : static const struct {
5351 : uint32_t command;
5352 : MAV_FRAME frame;
5353 : } frame_map[] {
5354 : { MAV_CMD_FIXED_MAG_CAL_YAW, MAV_FRAME_GLOBAL_RELATIVE_ALT },
5355 : { MAV_CMD_DO_SET_ROI, MAV_FRAME_GLOBAL_RELATIVE_ALT },
5356 : { MAV_CMD_DO_SET_ROI_LOCATION, MAV_FRAME_GLOBAL_RELATIVE_ALT },
5357 : { MAV_CMD_DO_SET_HOME, MAV_FRAME_GLOBAL },
5358 : };
5359 :
5360 : // map from command to frame:
5361 83 : for (const auto &map : frame_map) {
5362 83 : if (map.command != packet_command) {
5363 55 : continue;
5364 : }
5365 28 : frame = map.frame;
5366 28 : return true;
5367 : }
5368 :
5369 0 : return false;
5370 : }
5371 :
5372 530536 : MAV_RESULT GCS_MAVLINK::try_command_long_as_command_int(const mavlink_command_long_t &packet, const mavlink_message_t &msg)
5373 : {
5374 530536 : MAV_FRAME frame = MAV_FRAME_GLOBAL_RELATIVE_ALT;
5375 530536 : if (command_long_stores_location((MAV_CMD)packet.command)) {
5376 : // we must be able to supply a frame for the location:
5377 28 : if (!mav_frame_for_command_long(frame, (MAV_CMD)packet.command)) {
5378 0 : return MAV_RESULT_UNSUPPORTED;
5379 : }
5380 : }
5381 :
5382 : // convert and run the command
5383 : mavlink_command_int_t command_int;
5384 530536 : convert_COMMAND_LONG_to_COMMAND_INT(packet, command_int, frame);
5385 :
5386 530536 : return handle_command_int_packet(command_int, msg);
5387 : }
5388 :
5389 : // returns a value suitable for COMMAND_INT.x or y based on a value
5390 : // coming in from COMMAND_LONG.p5 or p6:
5391 2118818 : static int32_t convert_COMMAND_LONG_loc_param(float param, bool stores_location)
5392 : {
5393 2118818 : if (isnan(param)) {
5394 0 : return 0;
5395 : }
5396 :
5397 2118818 : if (stores_location) {
5398 112 : return param *1e7;
5399 : }
5400 :
5401 2118706 : return param;
5402 : }
5403 :
5404 1059409 : void GCS_MAVLINK::convert_COMMAND_LONG_to_COMMAND_INT(const mavlink_command_long_t &in, mavlink_command_int_t &out, MAV_FRAME frame)
5405 : {
5406 1059409 : out = {};
5407 1059409 : out.target_system = in.target_system;
5408 1059409 : out.target_component = in.target_component;
5409 1059409 : out.frame = frame;
5410 1059409 : out.command = in.command;
5411 1059409 : out.current = 0;
5412 1059409 : out.autocontinue = 0;
5413 1059409 : out.param1 = in.param1;
5414 1059409 : out.param2 = in.param2;
5415 1059409 : out.param3 = in.param3;
5416 1059409 : out.param4 = in.param4;
5417 1059409 : const bool stores_location = command_long_stores_location((MAV_CMD)in.command);
5418 1059409 : out.x = convert_COMMAND_LONG_loc_param(in.param5, stores_location);
5419 1059409 : out.y = convert_COMMAND_LONG_loc_param(in.param6, stores_location);
5420 1059409 : out.z = in.param7;
5421 1059409 : }
5422 :
5423 530536 : void GCS_MAVLINK::handle_command_long(const mavlink_message_t &msg)
5424 : {
5425 : // decode packet
5426 : mavlink_command_long_t packet;
5427 530536 : mavlink_msg_command_long_decode(&msg, &packet);
5428 :
5429 : #if AP_SCRIPTING_ENABLED
5430 530536 : AP_Scripting *scripting = AP_Scripting::get_singleton();
5431 530536 : if (scripting != nullptr && scripting->is_handling_command(packet.command)) {
5432 : // Scripting has registered to receive this command, do not procces it internaly
5433 0 : return;
5434 : }
5435 : #endif
5436 :
5437 530536 : hal.util->persistent_data.last_mavlink_cmd = packet.command;
5438 :
5439 530536 : const MAV_RESULT result = try_command_long_as_command_int(packet, msg);
5440 :
5441 : // send ACK or NAK
5442 528897 : mavlink_msg_command_ack_send(chan, packet.command, result,
5443 : 0, 0,
5444 528897 : msg.sysid,
5445 528897 : msg.compid);
5446 :
5447 : #if HAL_LOGGING_ENABLED
5448 : // log the packet:
5449 : mavlink_command_int_t packet_int;
5450 528897 : convert_COMMAND_LONG_to_COMMAND_INT(packet, packet_int);
5451 528897 : AP::logger().Write_Command(packet_int, msg.sysid, msg.compid, result, true);
5452 : #endif
5453 :
5454 528897 : hal.util->persistent_data.last_mavlink_cmd = 0;
5455 : }
5456 :
5457 : #else
5458 : void GCS_MAVLINK::handle_command_long(const mavlink_message_t &msg)
5459 : {
5460 : // decode packet
5461 : mavlink_command_long_t packet;
5462 : mavlink_msg_command_long_decode(&msg, &packet);
5463 :
5464 : // send ACK or NAK
5465 : mavlink_msg_command_ack_send(
5466 : chan,
5467 : packet.command,
5468 : MAV_RESULT_COMMAND_INT_ONLY,
5469 : 0,
5470 : 0,
5471 : msg.sysid,
5472 : msg.compid
5473 : );
5474 :
5475 : }
5476 : #endif // AP_MAVLINK_COMMAND_LONG_ENABLED
5477 :
5478 0 : MAV_RESULT GCS_MAVLINK::handle_command_do_set_roi(const Location &roi_loc)
5479 : {
5480 : #if HAL_MOUNT_ENABLED
5481 0 : AP_Mount *mount = AP::mount();
5482 0 : if (mount == nullptr) {
5483 0 : return MAV_RESULT_UNSUPPORTED;
5484 : }
5485 :
5486 : // sanity check location
5487 0 : if (!roi_loc.check_latlng()) {
5488 0 : return MAV_RESULT_FAILED;
5489 : }
5490 :
5491 0 : if (!roi_loc.initialised()) {
5492 0 : mount->clear_roi_target();
5493 : } else {
5494 0 : mount->set_roi_target(roi_loc);
5495 : }
5496 0 : return MAV_RESULT_ACCEPTED;
5497 : #else
5498 : return MAV_RESULT_UNSUPPORTED;
5499 : #endif
5500 : }
5501 :
5502 :
5503 671 : void GCS_MAVLINK::handle_landing_target(const mavlink_message_t &msg)
5504 : {
5505 : mavlink_landing_target_t m;
5506 671 : mavlink_msg_landing_target_decode(&msg, &m);
5507 : // correct offboard timestamp
5508 671 : const uint32_t corrected_ms = correct_offboard_timestamp_usec_to_ms(m.time_usec, PAYLOAD_SIZE(chan, LANDING_TARGET));
5509 671 : handle_landing_target(m, corrected_ms);
5510 671 : }
5511 :
5512 :
5513 : #if AP_HOME_ENABLED
5514 17 : bool GCS_MAVLINK::set_home_to_current_location(bool _lock)
5515 : {
5516 : #if AP_VEHICLE_ENABLED
5517 17 : return AP::vehicle()->set_home_to_current_location(_lock);
5518 : #else
5519 : return false;
5520 : #endif
5521 : }
5522 :
5523 83 : bool GCS_MAVLINK::set_home(const Location& loc, bool _lock) {
5524 : #if AP_VEHICLE_ENABLED
5525 83 : return AP::vehicle()->set_home(loc, _lock);
5526 : #else
5527 : return false;
5528 : #endif
5529 : }
5530 : #endif // AP_HOME_ENABLED
5531 :
5532 : #if AP_HOME_ENABLED
5533 101 : MAV_RESULT GCS_MAVLINK::handle_command_do_set_home(const mavlink_command_int_t &packet)
5534 : {
5535 101 : if (is_equal(packet.param1, 1.0f) || (packet.x == 0 && packet.y == 0)) {
5536 : // param1 is 1 (or both lat and lon are zero); use current location
5537 17 : if (!set_home_to_current_location(true)) {
5538 0 : return MAV_RESULT_FAILED;
5539 : }
5540 17 : return MAV_RESULT_ACCEPTED;
5541 : }
5542 : // ensure param1 is zero
5543 84 : if (!is_zero(packet.param1)) {
5544 0 : return MAV_RESULT_FAILED;
5545 : }
5546 84 : Location new_home_loc;
5547 84 : if (!location_from_command_t(packet, new_home_loc)) {
5548 1 : return MAV_RESULT_DENIED;
5549 : }
5550 83 : if (!set_home(new_home_loc, true)) {
5551 0 : return MAV_RESULT_FAILED;
5552 : }
5553 83 : return MAV_RESULT_ACCEPTED;
5554 : }
5555 : #endif // AP_HOME_ENABLED
5556 :
5557 : #if AP_AHRS_POSITION_RESET_ENABLED
5558 2 : MAV_RESULT GCS_MAVLINK::handle_command_int_external_position_estimate(const mavlink_command_int_t &packet)
5559 : {
5560 4 : if ((packet.frame != MAV_FRAME_GLOBAL && packet.frame != MAV_FRAME_GLOBAL_INT) ||
5561 2 : !isnan(packet.z)) {
5562 : // we only support global frame without altitude
5563 0 : return MAV_RESULT_DENIED;
5564 : }
5565 :
5566 : // cope with the NaN when convering to Location
5567 2 : Location loc;
5568 2 : mavlink_command_int_t p2 = packet;
5569 2 : p2.z = 0;
5570 :
5571 2 : if (!location_from_command_t(p2, loc)) {
5572 0 : return MAV_RESULT_DENIED;
5573 : }
5574 2 : uint32_t timestamp_ms = correct_offboard_timestamp_usec_to_ms(uint64_t(p2.param1*1e6), PAYLOAD_SIZE(chan, COMMAND_INT));
5575 2 : const uint32_t processing_ms = p2.param2*1e3;
5576 2 : const float pos_accuracy = p2.param3;
5577 2 : if (timestamp_ms > processing_ms) {
5578 2 : timestamp_ms -= processing_ms;
5579 : }
5580 2 : if (!AP::ahrs().handle_external_position_estimate(loc, pos_accuracy, timestamp_ms)) {
5581 1 : return MAV_RESULT_FAILED;
5582 : }
5583 1 : return MAV_RESULT_ACCEPTED;
5584 : }
5585 : #endif // AP_AHRS_POSITION_RESET_ENABLED
5586 :
5587 : #if AP_AHRS_EXTERNAL_WIND_ESTIMATE_ENABLED
5588 22 : MAV_RESULT GCS_MAVLINK::handle_command_int_external_wind_estimate(const mavlink_command_int_t &packet)
5589 : {
5590 22 : if (packet.param1 < 0) {
5591 4 : return MAV_RESULT_DENIED;
5592 : }
5593 18 : if (packet.param3 < 0 || packet.param3 > 360) {
5594 4 : return MAV_RESULT_DENIED;
5595 : }
5596 :
5597 14 : AP::ahrs().set_external_wind_estimate(packet.param1, packet.param3);
5598 14 : return MAV_RESULT_ACCEPTED;
5599 : }
5600 : #endif // AP_AHRS_EXTERNAL_WIND_ESTIMATE_ENABLED
5601 :
5602 38 : MAV_RESULT GCS_MAVLINK::handle_command_do_set_roi(const mavlink_command_int_t &packet)
5603 : {
5604 : // be aware that this method is called for both MAV_CMD_DO_SET_ROI
5605 : // and MAV_CMD_DO_SET_ROI_LOCATION. If you intend to support any
5606 : // of the extra fields in the former then you will need to split
5607 : // off support for MAV_CMD_DO_SET_ROI_LOCATION (which doesn't
5608 : // support the extra fields).
5609 :
5610 : // param1 : /* Region of interest mode (not used)*/
5611 : // param2 : /* MISSION index/ target ID (not used)*/
5612 : // param3 : /* ROI index (not used)*/
5613 : // param4 : /* empty */
5614 : // x : lat
5615 : // y : lon
5616 : // z : alt
5617 38 : Location roi_loc;
5618 38 : if (!location_from_command_t(packet, roi_loc)) {
5619 0 : return MAV_RESULT_DENIED;
5620 : }
5621 38 : return handle_command_do_set_roi(roi_loc);
5622 : }
5623 :
5624 : #if AP_FILESYSTEM_FORMAT_ENABLED
5625 0 : MAV_RESULT GCS_MAVLINK::handle_command_storage_format(const mavlink_command_int_t &packet, const mavlink_message_t &msg)
5626 : {
5627 0 : if (!is_equal(packet.param1, 1.0f) ||
5628 0 : !is_equal(packet.param2, 1.0f)) {
5629 0 : return MAV_RESULT_UNSUPPORTED;
5630 : }
5631 0 : GCS_MAVLINK_InProgress *task = GCS_MAVLINK_InProgress::get_task(MAV_CMD_STORAGE_FORMAT, GCS_MAVLINK_InProgress::Type::SD_FORMAT, msg.sysid, msg.compid, chan);
5632 0 : if (task == nullptr) {
5633 0 : return MAV_RESULT_TEMPORARILY_REJECTED;
5634 : }
5635 0 : if (!AP::FS().format()) {
5636 0 : task->abort();
5637 0 : return MAV_RESULT_FAILED;
5638 : }
5639 0 : return MAV_RESULT_IN_PROGRESS;
5640 : }
5641 : #endif
5642 :
5643 2 : MAV_RESULT GCS_MAVLINK::handle_do_set_safety_switch_state(const mavlink_command_int_t &packet, const mavlink_message_t &msg)
5644 : {
5645 2 : switch ((SAFETY_SWITCH_STATE)packet.param1) {
5646 1 : case SAFETY_SWITCH_STATE_DANGEROUS:
5647 : // turn safety off (pwm outputs flow to the motors)
5648 1 : hal.rcout->force_safety_off();
5649 1 : return MAV_RESULT_ACCEPTED;
5650 1 : case SAFETY_SWITCH_STATE_SAFE:
5651 : // turn safety on (no pwm outputs to the motors)
5652 1 : if (hal.rcout->force_safety_on()) {
5653 1 : return MAV_RESULT_ACCEPTED;
5654 : }
5655 0 : return MAV_RESULT_FAILED;
5656 0 : default:
5657 0 : return MAV_RESULT_DENIED;
5658 : }
5659 : }
5660 :
5661 : #if AP_MAVLINK_FOLLOW_HANDLING_ENABLED
5662 0 : MAV_RESULT GCS_MAVLINK::handle_command_do_follow(const mavlink_command_int_t &packet, const mavlink_message_t &msg)
5663 : {
5664 0 : AP_Follow *follow = AP_Follow::get_singleton();
5665 0 : if (follow == nullptr) {
5666 0 : return MAV_RESULT_UNSUPPORTED;
5667 : }
5668 :
5669 : // param1: sysid of target to follow
5670 0 : if ((packet.param1 > 0) && (packet.param1 <= 255)) {
5671 0 : follow->set_target_sysid((uint8_t)packet.param1);
5672 0 : return MAV_RESULT_ACCEPTED;
5673 : }
5674 0 : return MAV_RESULT_DENIED;
5675 : }
5676 : #endif // AP_MAVLINK_FOLLOW_HANDLING_ENABLED
5677 :
5678 530592 : MAV_RESULT GCS_MAVLINK::handle_command_int_packet(const mavlink_command_int_t &packet, const mavlink_message_t &msg)
5679 : {
5680 530592 : switch (packet.command) {
5681 :
5682 : #if HAL_INS_ACCELCAL_ENABLED
5683 0 : case MAV_CMD_ACCELCAL_VEHICLE_POS:
5684 0 : return handle_command_accelcal_vehicle_pos(packet);
5685 : #endif
5686 :
5687 : #if AP_LANDINGGEAR_ENABLED
5688 4 : case MAV_CMD_AIRFRAME_CONFIGURATION:
5689 4 : return handle_command_airframe_configuration(packet);
5690 : #endif
5691 :
5692 : #if AP_BATTERY_ENABLED
5693 18 : case MAV_CMD_BATTERY_RESET:
5694 18 : return handle_command_battery_reset(packet);
5695 : #endif
5696 :
5697 : #if AP_MAVLINKCAN_ENABLED
5698 0 : case MAV_CMD_CAN_FORWARD:
5699 0 : return handle_can_forward(packet, msg);
5700 : #endif // AP_MAVLINKCAN_ENABLED
5701 :
5702 : #if HAL_HIGH_LATENCY2_ENABLED
5703 16 : case MAV_CMD_CONTROL_HIGH_LATENCY:
5704 16 : return handle_control_high_latency(packet);
5705 : #endif // HAL_HIGH_LATENCY2_ENABLED
5706 :
5707 0 : case MAV_CMD_DEBUG_TRAP:
5708 0 : return handle_command_debug_trap(packet);
5709 :
5710 : #if HAL_ADSB_ENABLED
5711 0 : case MAV_CMD_DO_ADSB_OUT_IDENT:
5712 0 : if ((AP::ADSB() != nullptr) && AP::ADSB()->ident_start()) {
5713 0 : return MAV_RESULT_ACCEPTED;
5714 : }
5715 0 : return MAV_RESULT_FAILED;
5716 : #endif
5717 :
5718 : #if AP_AHRS_ENABLED
5719 3 : case MAV_CMD_DO_SET_GLOBAL_ORIGIN:
5720 3 : return handle_command_do_set_global_origin(packet);
5721 : #endif // AP_AHRS_ENABLED
5722 :
5723 : #if AP_RC_CHANNEL_ENABLED
5724 25 : case MAV_CMD_DO_AUX_FUNCTION:
5725 25 : return handle_command_do_aux_function(packet);
5726 : #endif
5727 :
5728 : #if AP_FENCE_ENABLED
5729 95 : case MAV_CMD_DO_FENCE_ENABLE:
5730 95 : return handle_command_do_fence_enable(packet);
5731 : #endif
5732 :
5733 7 : case MAV_CMD_DO_FLIGHTTERMINATION:
5734 7 : return handle_flight_termination(packet);
5735 :
5736 : #if AP_GRIPPER_ENABLED
5737 16 : case MAV_CMD_DO_GRIPPER:
5738 16 : return handle_command_do_gripper(packet);
5739 : #endif
5740 :
5741 : #if AP_MISSION_ENABLED
5742 5 : case MAV_CMD_DO_JUMP_TAG:
5743 5 : return handle_command_do_jump_tag(packet);
5744 :
5745 12 : case MAV_CMD_DO_SET_MISSION_CURRENT:
5746 12 : return handle_command_do_set_mission_current(packet);
5747 : #endif
5748 :
5749 3313 : case MAV_CMD_DO_SET_MODE:
5750 3313 : return handle_command_do_set_mode(packet);
5751 :
5752 : #if HAL_SPRAYER_ENABLED
5753 4 : case MAV_CMD_DO_SPRAYER:
5754 4 : return handle_command_do_sprayer(packet);
5755 : #endif
5756 :
5757 : #if AP_CAMERA_ENABLED
5758 13 : case MAV_CMD_DO_DIGICAM_CONFIGURE:
5759 : case MAV_CMD_DO_DIGICAM_CONTROL:
5760 : case MAV_CMD_DO_SET_CAM_TRIGG_DIST:
5761 : case MAV_CMD_SET_CAMERA_ZOOM:
5762 : case MAV_CMD_SET_CAMERA_FOCUS:
5763 : case MAV_CMD_SET_CAMERA_SOURCE:
5764 : case MAV_CMD_IMAGE_START_CAPTURE:
5765 : case MAV_CMD_IMAGE_STOP_CAPTURE:
5766 : case MAV_CMD_CAMERA_TRACK_POINT:
5767 : case MAV_CMD_CAMERA_TRACK_RECTANGLE:
5768 : case MAV_CMD_CAMERA_STOP_TRACKING:
5769 : case MAV_CMD_VIDEO_START_CAPTURE:
5770 : case MAV_CMD_VIDEO_STOP_CAPTURE:
5771 13 : return handle_command_camera(packet);
5772 : #endif
5773 :
5774 14 : case MAV_CMD_DO_SET_ROI_NONE: {
5775 14 : const Location zero_loc;
5776 14 : return handle_command_do_set_roi(zero_loc);
5777 : }
5778 :
5779 38 : case MAV_CMD_DO_SET_ROI:
5780 : case MAV_CMD_DO_SET_ROI_LOCATION:
5781 38 : return handle_command_do_set_roi(packet);
5782 :
5783 : #if HAL_MOUNT_ENABLED
5784 437 : case MAV_CMD_DO_SET_ROI_SYSID:
5785 : case MAV_CMD_DO_MOUNT_CONFIGURE:
5786 : case MAV_CMD_DO_MOUNT_CONTROL:
5787 : case MAV_CMD_DO_GIMBAL_MANAGER_PITCHYAW:
5788 : case MAV_CMD_DO_GIMBAL_MANAGER_CONFIGURE:
5789 437 : return handle_command_mount(packet, msg);
5790 : #endif // HAL_MOUNT_ENABLED
5791 :
5792 4 : case MAV_CMD_DO_SEND_BANNER:
5793 4 : send_banner();
5794 4 : return MAV_RESULT_ACCEPTED;
5795 :
5796 : #if AP_HOME_ENABLED
5797 101 : case MAV_CMD_DO_SET_HOME:
5798 101 : return handle_command_do_set_home(packet);
5799 : #endif
5800 :
5801 : #if AP_AHRS_POSITION_RESET_ENABLED
5802 2 : case MAV_CMD_EXTERNAL_POSITION_ESTIMATE:
5803 2 : return handle_command_int_external_position_estimate(packet);
5804 : #endif
5805 : #if AP_AHRS_EXTERNAL_WIND_ESTIMATE_ENABLED
5806 22 : case MAV_CMD_EXTERNAL_WIND_ESTIMATE:
5807 22 : return handle_command_int_external_wind_estimate(packet);
5808 : #endif
5809 : #if AP_ARMING_ENABLED
5810 1712 : case MAV_CMD_COMPONENT_ARM_DISARM:
5811 1712 : return handle_command_component_arm_disarm(packet);
5812 : #endif
5813 : #if AP_COMPASS_CALIBRATION_FIXED_YAW_ENABLED
5814 2 : case MAV_CMD_FIXED_MAG_CAL_YAW:
5815 2 : return handle_command_fixed_mag_cal_yaw(packet);
5816 : #endif
5817 : #if COMPASS_CAL_ENABLED
5818 37 : case MAV_CMD_DO_START_MAG_CAL:
5819 : case MAV_CMD_DO_ACCEPT_MAG_CAL:
5820 : case MAV_CMD_DO_CANCEL_MAG_CAL:
5821 37 : return handle_command_mag_cal(packet);
5822 : #endif
5823 :
5824 : #if AP_BOOTLOADER_FLASHING_ENABLED
5825 : case MAV_CMD_FLASH_BOOTLOADER:
5826 : return handle_command_flash_bootloader(packet);
5827 : #endif
5828 :
5829 : #if AP_MAVLINK_MAV_CMD_GET_HOME_POSITION_ENABLED
5830 4738 : case MAV_CMD_GET_HOME_POSITION:
5831 4738 : return handle_command_get_home_position(packet);
5832 : #endif // AP_MAVLINK_MAV_CMD_GET_HOME_POSITION_ENABLED
5833 :
5834 54 : case MAV_CMD_PREFLIGHT_CALIBRATION:
5835 54 : return handle_command_preflight_calibration(packet, msg);
5836 :
5837 0 : case MAV_CMD_PREFLIGHT_STORAGE:
5838 0 : if (uint8_t(packet.param1) == PARAM_RESET_FACTORY_DEFAULT ||
5839 0 : uint8_t(packet.param1) == PARAM_RESET_ALL_DEFAULT) {
5840 0 : AP_Param::erase_all();
5841 0 : send_text(MAV_SEVERITY_WARNING, "All parameters reset, reboot board");
5842 0 : return MAV_RESULT_ACCEPTED;
5843 : }
5844 0 : return MAV_RESULT_DENIED;
5845 :
5846 1640 : case MAV_CMD_PREFLIGHT_REBOOT_SHUTDOWN:
5847 1640 : return handle_preflight_reboot(packet, msg);
5848 :
5849 2 : case MAV_CMD_DO_SET_SAFETY_SWITCH_STATE:
5850 2 : return handle_do_set_safety_switch_state(packet, msg);
5851 :
5852 : #if AP_MAVLINK_SERVO_RELAY_ENABLED
5853 823 : case MAV_CMD_DO_SET_SERVO:
5854 : case MAV_CMD_DO_REPEAT_SERVO:
5855 : case MAV_CMD_DO_SET_RELAY:
5856 : case MAV_CMD_DO_REPEAT_RELAY:
5857 823 : return handle_servorelay_message(packet);
5858 : #endif
5859 :
5860 : #if AP_MAVLINK_MAV_CMD_REQUEST_AUTOPILOT_CAPABILITIES_ENABLED
5861 28 : case MAV_CMD_REQUEST_AUTOPILOT_CAPABILITIES:
5862 28 : return handle_command_request_autopilot_capabilities(packet);
5863 : #endif
5864 :
5865 : #if AP_ARMING_ENABLED
5866 66595 : case MAV_CMD_RUN_PREARM_CHECKS:
5867 66595 : return handle_command_run_prearm_checks(packet);
5868 : #endif
5869 :
5870 : #if AP_SCRIPTING_ENABLED
5871 10 : case MAV_CMD_SCRIPTING:
5872 : {
5873 10 : AP_Scripting *scripting = AP_Scripting::get_singleton();
5874 10 : if (scripting == nullptr) {
5875 0 : return MAV_RESULT_UNSUPPORTED;
5876 : }
5877 10 : return scripting->handle_command_int_packet(packet);
5878 : }
5879 : #endif // AP_SCRIPTING_ENABLED
5880 :
5881 : #if AP_AHRS_ENABLED
5882 6 : case MAV_CMD_SET_EKF_SOURCE_SET:
5883 6 : return handle_command_set_ekf_source_set(packet);
5884 : #endif
5885 :
5886 : #if AP_RCPROTOCOL_ENABLED
5887 0 : case MAV_CMD_START_RX_PAIR:
5888 0 : return handle_START_RX_PAIR(packet);
5889 : #endif
5890 :
5891 : #if AP_FILESYSTEM_FORMAT_ENABLED
5892 0 : case MAV_CMD_STORAGE_FORMAT:
5893 0 : return handle_command_storage_format(packet, msg);
5894 : #endif
5895 :
5896 : // support for dealing with streamrate for a specific message and
5897 : // requesting a message instance:
5898 216 : case MAV_CMD_SET_MESSAGE_INTERVAL:
5899 216 : return handle_command_set_message_interval(packet);
5900 :
5901 14 : case MAV_CMD_GET_MESSAGE_INTERVAL:
5902 14 : return handle_command_get_message_interval(packet);
5903 :
5904 450566 : case MAV_CMD_REQUEST_MESSAGE:
5905 450566 : return handle_command_request_message(packet);
5906 :
5907 : #if AP_MAVLINK_FOLLOW_HANDLING_ENABLED
5908 0 : case MAV_CMD_DO_FOLLOW:
5909 0 : return handle_command_do_follow(packet, msg);
5910 : #endif
5911 : }
5912 :
5913 0 : return MAV_RESULT_UNSUPPORTED;
5914 : }
5915 :
5916 618 : void GCS_MAVLINK::handle_command_int(const mavlink_message_t &msg)
5917 : {
5918 : // decode packet
5919 : mavlink_command_int_t packet;
5920 618 : mavlink_msg_command_int_decode(&msg, &packet);
5921 :
5922 : #if AP_SCRIPTING_ENABLED
5923 618 : AP_Scripting *scripting = AP_Scripting::get_singleton();
5924 618 : if (scripting != nullptr && scripting->is_handling_command(packet.command)) {
5925 : // Scripting has registered to receive this command, do not procces it internaly
5926 0 : return;
5927 : }
5928 : #endif
5929 :
5930 618 : hal.util->persistent_data.last_mavlink_cmd = packet.command;
5931 :
5932 618 : const MAV_RESULT result = handle_command_int_packet(packet, msg);
5933 :
5934 : // send ACK or NAK
5935 618 : mavlink_msg_command_ack_send(chan, packet.command, result,
5936 : 0, 0,
5937 618 : msg.sysid,
5938 618 : msg.compid);
5939 :
5940 : #if HAL_LOGGING_ENABLED
5941 618 : AP::logger().Write_Command(packet, msg.sysid, msg.compid, result);
5942 : #endif
5943 :
5944 618 : hal.util->persistent_data.last_mavlink_cmd = 0;
5945 : }
5946 :
5947 422 : void GCS::try_send_queued_message_for_type(MAV_MISSION_TYPE type) const {
5948 422 : MissionItemProtocol *prot = get_prot_for_mission_type(type);
5949 422 : if (prot == nullptr) {
5950 0 : return;
5951 : }
5952 422 : prot->queued_request_send();
5953 : }
5954 :
5955 1117385 : bool GCS_MAVLINK::try_send_mission_message(const enum ap_message id)
5956 : {
5957 1117385 : switch (id) {
5958 : #if AP_MISSION_ENABLED
5959 1115338 : case MSG_CURRENT_WAYPOINT:
5960 : {
5961 1115338 : CHECK_PAYLOAD_SIZE(MISSION_CURRENT);
5962 1115338 : AP_Mission &mission = AP::mission();
5963 1115338 : send_mission_current(mission, mission.get_current_nav_index());
5964 1115338 : break;
5965 : }
5966 1625 : case MSG_MISSION_ITEM_REACHED:
5967 1625 : CHECK_PAYLOAD_SIZE(MISSION_ITEM_REACHED);
5968 1625 : mavlink_msg_mission_item_reached_send(chan, mission_item_reached_index);
5969 1625 : break;
5970 335 : case MSG_NEXT_MISSION_REQUEST_WAYPOINTS:
5971 335 : CHECK_PAYLOAD_SIZE(MISSION_REQUEST);
5972 335 : gcs().try_send_queued_message_for_type(MAV_MISSION_TYPE_MISSION);
5973 335 : break;
5974 : #endif
5975 : #if HAL_RALLY_ENABLED
5976 6 : case MSG_NEXT_MISSION_REQUEST_RALLY:
5977 6 : CHECK_PAYLOAD_SIZE(MISSION_REQUEST);
5978 6 : gcs().try_send_queued_message_for_type(MAV_MISSION_TYPE_RALLY);
5979 6 : break;
5980 : #endif
5981 : #if AP_FENCE_ENABLED
5982 81 : case MSG_NEXT_MISSION_REQUEST_FENCE:
5983 81 : CHECK_PAYLOAD_SIZE(MISSION_REQUEST);
5984 81 : gcs().try_send_queued_message_for_type(MAV_MISSION_TYPE_FENCE);
5985 81 : break;
5986 : #endif
5987 0 : default:
5988 0 : break;
5989 : }
5990 1117385 : return true;
5991 : }
5992 :
5993 : #if AP_RPM_ENABLED
5994 1120967 : void GCS_MAVLINK::send_rpm() const
5995 : {
5996 1120967 : AP_RPM *rpm = AP::rpm();
5997 1120967 : if (rpm == nullptr) {
5998 1064786 : return;
5999 : }
6000 :
6001 1120967 : if (!rpm->enabled(0) && !rpm->enabled(1)) {
6002 1064786 : return;
6003 : }
6004 :
6005 56181 : float rpm1 = -1, rpm2 = -1;
6006 :
6007 56181 : rpm->get_rpm(0, rpm1);
6008 56181 : rpm->get_rpm(1, rpm2);
6009 :
6010 56181 : mavlink_msg_rpm_send(
6011 56181 : chan,
6012 : rpm1,
6013 : rpm2);
6014 : }
6015 : #endif // AP_RPM_ENABLED
6016 :
6017 1117266 : void GCS_MAVLINK::send_sys_status()
6018 : {
6019 : // send extended status only once vehicle has been initialised
6020 : // to avoid unnecessary errors being reported to user
6021 1117266 : if (!gcs().vehicle_initialised()) {
6022 319 : return;
6023 : }
6024 : #if AP_BATTERY_ENABLED
6025 1116947 : const AP_BattMonitor &battery = AP::battery();
6026 : float battery_current;
6027 1116947 : const int8_t battery_remaining = battery_remaining_pct(AP_BATT_PRIMARY_INSTANCE);
6028 :
6029 1116947 : if (battery.healthy() && battery.current_amps(battery_current)) {
6030 866204 : battery_current = constrain_float(battery_current * 100,-INT16_MAX,INT16_MAX);
6031 : } else {
6032 250743 : battery_current = -1;
6033 : }
6034 : #endif
6035 :
6036 : uint32_t control_sensors_present;
6037 : uint32_t control_sensors_enabled;
6038 : uint32_t control_sensors_health;
6039 :
6040 1116947 : gcs().get_sensor_status_flags(control_sensors_present, control_sensors_enabled, control_sensors_health);
6041 :
6042 1116947 : const uint32_t errors = AP::internalerror().errors();
6043 1116947 : const uint16_t errors1 = errors & 0xffff;
6044 1116947 : const uint16_t errors2 = (errors>>16) & 0xffff;
6045 1116947 : const uint16_t errors4 = AP::internalerror().count() & 0xffff;
6046 1116947 : uint16_t errors_comm = 0;
6047 1116947 : mavlink_status_t *ms = mavlink_get_channel_status(chan);
6048 1116947 : if (ms) {
6049 1116947 : errors_comm = ms->packet_rx_drop_count;
6050 : }
6051 :
6052 : #if HAL_LOGGING_ENABLED
6053 1116947 : const uint16_t dropped_logmessage_count = AP::logger().num_dropped();
6054 : #else
6055 : const uint16_t dropped_logmessage_count = UINT16_MAX;
6056 : #endif // HAL_LOGGING_ENABLED
6057 :
6058 3350841 : mavlink_msg_sys_status_send(
6059 : chan,
6060 : control_sensors_present,
6061 : control_sensors_enabled,
6062 : control_sensors_health,
6063 : #if AP_SCHEDULER_ENABLED
6064 1116947 : static_cast<uint16_t>(AP::scheduler().load_average() * 1000),
6065 : #else
6066 : 0,
6067 : #endif
6068 : #if AP_BATTERY_ENABLED
6069 1116947 : battery.gcs_voltage() * 1000, // mV
6070 : battery_current, // in 10mA units
6071 : battery_remaining, // in %
6072 : #else
6073 : 0,
6074 : -1,
6075 : -1,
6076 : #endif
6077 : 0, // comm drops %,
6078 : errors_comm, // comm drops in pkts,
6079 : errors1,
6080 : errors2,
6081 : dropped_logmessage_count, // errors3
6082 : errors4, // errors4
6083 : 0, // control_sensors_present2,
6084 : 0, // control_sensors_enabled2,
6085 : 0 // control_sensors_health2
6086 : );
6087 : }
6088 :
6089 3716 : void GCS_MAVLINK::send_extended_sys_state() const
6090 : {
6091 3716 : mavlink_msg_extended_sys_state_send(chan, vtol_state(), landed_state());
6092 3716 : }
6093 :
6094 591993 : void GCS_MAVLINK::send_attitude() const
6095 : {
6096 : #if AP_AHRS_ENABLED
6097 591993 : const AP_AHRS &ahrs = AP::ahrs();
6098 591993 : const Vector3f omega = ahrs.get_gyro();
6099 591993 : mavlink_msg_attitude_send(
6100 591993 : chan,
6101 : AP_HAL::millis(),
6102 : ahrs.get_roll_rad(),
6103 : ahrs.get_pitch_rad(),
6104 : ahrs.get_yaw_rad(),
6105 591993 : omega.x,
6106 591993 : omega.y,
6107 591993 : omega.z);
6108 : #endif
6109 591993 : }
6110 :
6111 111 : void GCS_MAVLINK::send_attitude_quaternion() const
6112 : {
6113 : #if AP_AHRS_ENABLED
6114 111 : const AP_AHRS &ahrs = AP::ahrs();
6115 111 : Quaternion quat;
6116 111 : if (!ahrs.get_quaternion(quat)) {
6117 0 : return;
6118 : }
6119 111 : const Vector3f omega = ahrs.get_gyro();
6120 111 : const float repr_offseq_q[] {0,0,0,0}; // unused, but probably should correspond to the AHRS view?
6121 222 : mavlink_msg_attitude_quaternion_send(
6122 111 : chan,
6123 : AP_HAL::millis(),
6124 : quat.q1,
6125 : quat.q2,
6126 : quat.q3,
6127 : quat.q4,
6128 111 : omega.x, // rollspeed
6129 111 : omega.y, // pitchspeed
6130 111 : omega.z, // yawspeed
6131 : repr_offseq_q
6132 : );
6133 : #endif
6134 : }
6135 :
6136 1470955 : int32_t GCS_MAVLINK::global_position_int_alt() const {
6137 1470955 : return global_position_current_loc.alt * 10UL;
6138 : }
6139 1469481 : int32_t GCS_MAVLINK::global_position_int_relative_alt() const {
6140 : #if AP_AHRS_ENABLED
6141 : float posD;
6142 1469481 : AP::ahrs().get_relative_position_D_home(posD);
6143 1469481 : posD *= -1000.0f; // change from down to up and metres to millimeters
6144 1469481 : return posD;
6145 : #else
6146 : return 0;
6147 : #endif
6148 : }
6149 :
6150 1552531 : void GCS_MAVLINK::send_global_position_int()
6151 : {
6152 : #if AP_AHRS_ENABLED
6153 1552531 : AP_AHRS &ahrs = AP::ahrs();
6154 :
6155 1552531 : UNUSED_RESULT(ahrs.get_location(global_position_current_loc)); // return value ignored; we send stale data
6156 :
6157 1552531 : Vector3f vel;
6158 1552531 : if (!ahrs.get_velocity_NED(vel)) {
6159 44218 : vel.zero();
6160 : }
6161 :
6162 1552531 : mavlink_msg_global_position_int_send(
6163 : chan,
6164 : AP_HAL::millis(),
6165 : global_position_current_loc.lat, // in 1E7 degrees
6166 : global_position_current_loc.lng, // in 1E7 degrees
6167 1552531 : global_position_int_alt(), // millimeters above ground/sea level
6168 1552531 : global_position_int_relative_alt(), // millimeters above home
6169 1552531 : vel.x * 100, // X speed cm/s (+ve North)
6170 1552531 : vel.y * 100, // Y speed cm/s (+ve East)
6171 1552531 : vel.z * 100, // Z speed cm/s (+ve Down)
6172 1552531 : ahrs.yaw_sensor); // compass heading in 1/100 degree
6173 : #endif // AP_AHRS_ENABLED
6174 1552531 : }
6175 :
6176 : #if AP_MAVLINK_UTM_GLOBAL_POSITION_SENDING_ENABLED
6177 13 : void GCS_MAVLINK::send_utm_global_position() const
6178 : {
6179 13 : uint8_t flags = 0;
6180 :
6181 : // time (UNIX epoch microseconds)
6182 13 : uint64_t time_usec = 0;
6183 : #if AP_RTC_ENABLED
6184 13 : if (AP::rtc().get_utc_usec(time_usec)) {
6185 13 : flags |= UTM_DATA_AVAIL_FLAGS_TIME_VALID;
6186 : }
6187 : #endif // AP_RTC_ENABLED
6188 :
6189 : // UAS ID from hardware UID
6190 13 : uint8_t uas_id[MAVLINK_MSG_UTM_GLOBAL_POSITION_FIELD_UAS_ID_LEN] = {};
6191 : {
6192 13 : uint8_t len = ARRAY_SIZE(uas_id);
6193 13 : hal.util->get_system_id_unformatted(uas_id, len);
6194 : }
6195 13 : flags |= UTM_DATA_AVAIL_FLAGS_UAS_ID_AVAILABLE;
6196 :
6197 : // position
6198 13 : int32_t lat = 0;
6199 13 : int32_t lon = 0;
6200 13 : int32_t alt_mm = 0;
6201 13 : int32_t relative_alt_mm = 0;
6202 :
6203 13 : AP_AHRS &ahrs = AP::ahrs();
6204 13 : Location loc;
6205 13 : if (ahrs.get_location(loc)) {
6206 13 : lat = loc.lat;
6207 13 : lon = loc.lng;
6208 13 : flags |= UTM_DATA_AVAIL_FLAGS_POSITION_AVAILABLE;
6209 : }
6210 :
6211 : #if AP_GPS_ENABLED
6212 : // the message is very specific about wanting geoid altitude. At
6213 : // the moment the only place you can get one of those in ArduPilot
6214 : // is in the AP_GPS library.
6215 13 : float undulation_m = NaNf;
6216 13 : if (AP::gps().get_undulation(undulation_m)) {
6217 : // make the assumption that GLOBAL_POSITION_INT.alt is AMSL:
6218 13 : alt_mm = global_position_int_alt();
6219 13 : alt_mm -= undulation_m * 1000; // m -> mm
6220 13 : flags |= UTM_DATA_AVAIL_FLAGS_ALTITUDE_AVAILABLE;
6221 : }
6222 : #endif // AP_GPS_ENABLED
6223 :
6224 : #if AP_TERRAIN_AVAILABLE
6225 : // the message is specific about relative_alt being "Altitude above ground"
6226 13 : AP_Terrain *terrain = AP::terrain();
6227 13 : if (terrain != nullptr) {
6228 : float above_terrain_m;
6229 : // "true" here enables extrapolation
6230 10 : if (terrain->height_above_terrain(above_terrain_m, true)) {
6231 8 : relative_alt_mm = above_terrain_m * 1000;
6232 8 : flags |= UTM_DATA_AVAIL_FLAGS_RELATIVE_ALTITUDE_AVAILABLE;
6233 : }
6234 : }
6235 : #endif // AP_TERRAIN_AVAILABLE
6236 :
6237 : // velocity
6238 13 : int16_t vx = 0;
6239 13 : int16_t vy = 0;
6240 13 : int16_t vz = 0;
6241 13 : Vector3f vel;
6242 13 : if (ahrs.get_velocity_NED(vel)) {
6243 13 : vx = vel.x * 100;
6244 13 : vy = vel.y * 100;
6245 13 : vz = vel.z * 100;
6246 13 : flags |= UTM_DATA_AVAIL_FLAGS_HORIZONTAL_VELO_AVAILABLE;
6247 13 : flags |= UTM_DATA_AVAIL_FLAGS_VERTICAL_VELO_AVAILABLE;
6248 : }
6249 :
6250 : // next waypoint from vehicle-specific navigation
6251 13 : int32_t next_lat = 0;
6252 13 : int32_t next_lon = 0;
6253 13 : int32_t next_alt_mm = 0;
6254 : // the altitude must be wgs84, need undulation for that:
6255 : #if AP_GPS_ENABLED
6256 13 : Location next_loc;
6257 26 : if (!isnan(undulation_m) &&
6258 26 : get_target_location(next_loc) && next_loc.initialised()) {
6259 : float next_alt_m;
6260 8 : if (next_loc.get_alt_m(Location::AltFrame::ABSOLUTE, next_alt_m)) {
6261 8 : next_lat = next_loc.lat;
6262 8 : next_lon = next_loc.lng;
6263 8 : next_alt_mm = (int32_t)(next_alt_m * 1000.0f);
6264 8 : next_alt_mm -= undulation_m * 1000; // m -> mm
6265 8 : flags |= UTM_DATA_AVAIL_FLAGS_NEXT_WAYPOINT_AVAILABLE;
6266 : }
6267 : }
6268 : #endif // AP_GPS_ENABLED
6269 :
6270 : // flight state mapped from landed_state()
6271 13 : uint8_t flight_state = UTM_FLIGHT_STATE_UNKNOWN;
6272 13 : switch (landed_state()) {
6273 5 : case MAV_LANDED_STATE_UNDEFINED:
6274 : case MAV_LANDED_STATE_ENUM_END:
6275 5 : flight_state = UTM_FLIGHT_STATE_UNKNOWN;
6276 5 : break;
6277 2 : case MAV_LANDED_STATE_ON_GROUND:
6278 2 : flight_state = UTM_FLIGHT_STATE_GROUND;
6279 2 : break;
6280 6 : case MAV_LANDED_STATE_IN_AIR:
6281 : case MAV_LANDED_STATE_TAKEOFF:
6282 : case MAV_LANDED_STATE_LANDING:
6283 6 : flight_state = UTM_FLIGHT_STATE_AIRBORNE;
6284 6 : break;
6285 : }
6286 :
6287 13 : uint16_t h_acc_mm = 0, v_acc_mm = 0, vel_acc_cms = 0;
6288 : {
6289 : float pos_horiz_m, pos_vert_m, vel_m_s;
6290 13 : if (ahrs.get_pos_vel_uncertainty(pos_horiz_m, pos_vert_m, vel_m_s)) {
6291 13 : h_acc_mm = (uint16_t)constrain_float(pos_horiz_m * 1000.0f, 0, UINT16_MAX);
6292 13 : v_acc_mm = (uint16_t)constrain_float(pos_vert_m * 1000.0f, 0, UINT16_MAX);
6293 13 : vel_acc_cms = (uint16_t)constrain_float(vel_m_s * 100.0f, 0, UINT16_MAX);
6294 : }
6295 : }
6296 :
6297 13 : mavlink_utm_global_position_t msg_utm {
6298 : time : time_usec,
6299 : lat : lat,
6300 : lon : lon,
6301 : alt : alt_mm,
6302 : relative_alt : relative_alt_mm,
6303 : next_lat : next_lat,
6304 : next_lon : next_lon,
6305 : next_alt : next_alt_mm,
6306 : vx : vx,
6307 : vy : vy,
6308 : vz : vz,
6309 : h_acc : h_acc_mm,
6310 : v_acc : v_acc_mm,
6311 : vel_acc : vel_acc_cms,
6312 : update_rate : 0, // unknown/data-driven
6313 : flight_state : flight_state,
6314 : flags : flags,
6315 13 : };
6316 13 : memcpy(msg_utm.uas_id, uas_id, sizeof(msg_utm.uas_id));
6317 13 : mavlink_msg_utm_global_position_send_struct(chan, &msg_utm);
6318 13 : }
6319 : #endif // AP_MAVLINK_UTM_GLOBAL_POSITION_SENDING_ENABLED
6320 :
6321 : #if HAL_MOUNT_ENABLED
6322 1117755 : void GCS_MAVLINK::send_gimbal_device_attitude_status() const
6323 : {
6324 1117755 : AP_Mount *mount = AP::mount();
6325 1117755 : if (mount == nullptr) {
6326 1760 : return;
6327 : }
6328 1115995 : mount->send_gimbal_device_attitude_status(chan);
6329 : }
6330 :
6331 0 : void GCS_MAVLINK::send_gimbal_manager_information() const
6332 : {
6333 0 : AP_Mount *mount = AP::mount();
6334 0 : if (mount == nullptr) {
6335 0 : return;
6336 : }
6337 0 : mount->send_gimbal_manager_information(chan);
6338 : }
6339 :
6340 25 : void GCS_MAVLINK::send_gimbal_manager_status() const
6341 : {
6342 25 : AP_Mount *mount = AP::mount();
6343 25 : if (mount == nullptr) {
6344 0 : return;
6345 : }
6346 25 : mount->send_gimbal_manager_status(chan);
6347 : }
6348 : #endif
6349 :
6350 0 : void GCS_MAVLINK::send_set_position_target_global_int(uint8_t target_system, uint8_t target_component, const Location& loc)
6351 : {
6352 :
6353 0 : const uint16_t type_mask = POSITION_TARGET_TYPEMASK_VX_IGNORE | POSITION_TARGET_TYPEMASK_VY_IGNORE | POSITION_TARGET_TYPEMASK_VZ_IGNORE | \
6354 : POSITION_TARGET_TYPEMASK_AX_IGNORE | POSITION_TARGET_TYPEMASK_AY_IGNORE | POSITION_TARGET_TYPEMASK_AZ_IGNORE | \
6355 : POSITION_TARGET_TYPEMASK_YAW_IGNORE | POSITION_TARGET_TYPEMASK_YAW_RATE_IGNORE;
6356 :
6357 : // convert altitude to relative to home
6358 : float rel_alt_m;
6359 0 : if (!loc.get_alt_m(Location::AltFrame::ABOVE_HOME, rel_alt_m)) {
6360 0 : return;
6361 : }
6362 :
6363 0 : mavlink_msg_set_position_target_global_int_send(
6364 : chan,
6365 : AP_HAL::millis(),
6366 : target_system,
6367 : target_component,
6368 : MAV_FRAME_GLOBAL_RELATIVE_ALT,
6369 : type_mask,
6370 0 : loc.lat,
6371 0 : loc.lng,
6372 : rel_alt_m,
6373 : 0,0,0, // vx, vy, vz
6374 : 0,0,0, // ax, ay, az
6375 : 0,0); // yaw, yaw_rate
6376 : }
6377 :
6378 1117087 : void GCS_MAVLINK::send_position_target_global_int()
6379 : {
6380 1117087 : Location target;
6381 1117087 : if (!get_target_location(target)) {
6382 558559 : return;
6383 : }
6384 572722 : if (!target.initialised()) {
6385 10051 : return;
6386 : }
6387 : float alt_amsl_m;
6388 562671 : if (!target.get_alt_m(Location::AltFrame::ABSOLUTE, alt_amsl_m)) {
6389 4143 : return;
6390 : }
6391 : static constexpr uint16_t POSITION_TARGET_TYPEMASK_LAST_BYTE = 0xF000;
6392 : static constexpr uint16_t TYPE_MASK =
6393 : POSITION_TARGET_TYPEMASK_VX_IGNORE | POSITION_TARGET_TYPEMASK_VY_IGNORE |
6394 : POSITION_TARGET_TYPEMASK_VZ_IGNORE | POSITION_TARGET_TYPEMASK_AX_IGNORE |
6395 : POSITION_TARGET_TYPEMASK_AY_IGNORE | POSITION_TARGET_TYPEMASK_AZ_IGNORE |
6396 : POSITION_TARGET_TYPEMASK_YAW_IGNORE | POSITION_TARGET_TYPEMASK_YAW_RATE_IGNORE |
6397 : POSITION_TARGET_TYPEMASK_LAST_BYTE;
6398 558528 : mavlink_msg_position_target_global_int_send(
6399 : chan,
6400 : AP_HAL::millis(), // time_boot_ms
6401 : MAV_FRAME_GLOBAL, // targets are always global altitude
6402 : TYPE_MASK, // ignore everything except the x/y/z components
6403 : target.lat, // latitude as 1e7
6404 : target.lng, // longitude as 1e7
6405 : alt_amsl_m, // altitude AMSL in metres
6406 : 0.0f, // vx
6407 : 0.0f, // vy
6408 : 0.0f, // vz
6409 : 0.0f, // afx
6410 : 0.0f, // afy
6411 : 0.0f, // afz
6412 : 0.0f, // yaw
6413 : 0.0f); // yaw_rate
6414 : }
6415 :
6416 : #if HAL_GENERATOR_ENABLED
6417 1122504 : void GCS_MAVLINK::send_generator_status() const
6418 : {
6419 1122504 : AP_Generator *generator = AP::generator();
6420 1122504 : if (generator == nullptr) {
6421 0 : return;
6422 : }
6423 1122504 : generator->send_generator_status(*this);
6424 : }
6425 : #endif
6426 :
6427 : #if HAL_ADSB_ENABLED
6428 0 : void GCS_MAVLINK::send_uavionix_adsb_out_status() const
6429 : {
6430 0 : AP_ADSB *adsb = AP::ADSB();
6431 0 : if (adsb != nullptr) {
6432 0 : adsb->send_adsb_out_status(chan);
6433 : }
6434 0 : }
6435 : #endif
6436 :
6437 : #if AP_MAVLINK_MSG_RELAY_STATUS_ENABLED
6438 377 : bool GCS_MAVLINK::send_relay_status() const
6439 : {
6440 377 : AP_Relay *relay = AP::relay();
6441 377 : if (relay == nullptr) {
6442 : // must only return false if out of space:
6443 0 : return true;
6444 : }
6445 :
6446 377 : return relay->send_relay_status(*this);
6447 : }
6448 : #endif // AP_MAVLINK_MSG_RELAY_STATUS_ENABLED
6449 :
6450 11602 : void GCS_MAVLINK::send_autopilot_state_for_gimbal_device() const
6451 : {
6452 : #if AP_AHRS_ENABLED
6453 : // get attitude
6454 11602 : const AP_AHRS &ahrs = AP::ahrs();
6455 11602 : Quaternion quat;
6456 11602 : if (!ahrs.get_quaternion(quat)) {
6457 0 : return;
6458 : }
6459 11602 : const float repr_offseq_q[] = {quat.q1, quat.q2, quat.q3, quat.q4};
6460 :
6461 : // get velocity
6462 11602 : Vector3f vel;
6463 11602 : if (!ahrs.get_velocity_NED(vel)) {
6464 0 : vel.zero();
6465 : }
6466 :
6467 : // get vehicle earth-frame rotation rate targets
6468 11602 : Vector3f rate_ef_targets;
6469 : #if AP_VEHICLE_ENABLED
6470 11602 : const AP_Vehicle *vehicle = AP::vehicle();
6471 11602 : if (vehicle != nullptr) {
6472 11602 : vehicle->get_rate_ef_targets(rate_ef_targets);
6473 : }
6474 : #endif
6475 :
6476 : // get estimator flags
6477 11602 : uint16_t est_status_flags = 0;
6478 : nav_filter_status nav_filt_status;
6479 11602 : if (ahrs.get_filter_status(nav_filt_status)) {
6480 11602 : est_status_flags = (uint16_t)(nav_filt_status.value & 0xFFFF);
6481 : }
6482 :
6483 11602 : mavlink_msg_autopilot_state_for_gimbal_device_send(
6484 11602 : chan,
6485 11602 : mavlink_system.sysid, // target system (this autopilot's gimbal)
6486 : 0, // target component (anything)
6487 11602 : AP_HAL::micros(), // time boot us
6488 : repr_offseq_q, // attitude as quaternion
6489 : 0, // attitude estimated delay in micros
6490 : vel.x, // x speed in NED (m/s)
6491 : vel.y, // y speed in NED (m/s)
6492 : vel.z, // z speed in NED (m/s)
6493 : 0, // velocity estimated delay in micros
6494 : rate_ef_targets.z, // feed forward angular velocity z
6495 : est_status_flags, // estimator status
6496 : 0, // landed_state (see MAV_LANDED_STATE)
6497 11602 : AP::ahrs().get_yaw_rate_earth()); // [rad/s] Z component of angular velocity in NED (North, East, Down). NaN if unknown
6498 : #endif // AP_AHRS_ENABLED
6499 : }
6500 :
6501 : #if AP_MAVLINK_MSG_FLIGHT_INFORMATION_ENABLED
6502 0 : void GCS_MAVLINK::send_flight_information()
6503 : {
6504 0 : const uint64_t time_boot_micros = AP_HAL::micros64();
6505 0 : const uint32_t time_boot_ms = static_cast<uint32_t>(time_boot_micros / 1000);
6506 :
6507 : // This field is misnamed as `arming_time_utc` in MAVLink. However, it is
6508 : // not a UTC time, it is the microseconds since boot.
6509 0 : const uint64_t arm_time_us = AP::arming().arm_time_us();
6510 :
6511 0 : const MAV_LANDED_STATE current_landed_state = landed_state();
6512 0 : if (flight_info.last_landed_state != current_landed_state) {
6513 0 : switch (current_landed_state) {
6514 0 : case MAV_LANDED_STATE_IN_AIR:
6515 : case MAV_LANDED_STATE_TAKEOFF:
6516 : case MAV_LANDED_STATE_LANDING:
6517 0 : if (!flight_info.takeoff_time_us) {
6518 0 : flight_info.takeoff_time_us = time_boot_micros;
6519 : }
6520 0 : break;
6521 :
6522 0 : case MAV_LANDED_STATE_ON_GROUND:
6523 0 : flight_info.takeoff_time_us = 0;
6524 0 : break;
6525 :
6526 0 : case MAV_LANDED_STATE_UNDEFINED:
6527 : case MAV_LANDED_STATE_ENUM_END:
6528 0 : break;
6529 : }
6530 :
6531 0 : flight_info.last_landed_state = current_landed_state;
6532 : }
6533 :
6534 : // This field is misnamed as `takeoff_time_utc` in MAVLink. However, it is
6535 : // not a UTC time, it is the microseconds since boot.
6536 0 : uint64_t takeoff_time_us = flight_info.takeoff_time_us;
6537 :
6538 : // This field is misnamed as `flight_uuid` in MAVLink.
6539 0 : const uint64_t flight_number = 0;
6540 :
6541 0 : mavlink_msg_flight_information_send(
6542 : chan,
6543 : time_boot_ms,
6544 : arm_time_us,
6545 : takeoff_time_us,
6546 : flight_number,
6547 : 0 // landing_time, 0 meaning "not supported"
6548 : );
6549 0 : }
6550 : #endif // AP_MAVLINK_MSG_FLIGHT_INFORMATION_ENABLED
6551 :
6552 0 : void GCS_MAVLINK::send_received_message_deprecation_warning(const char * message)
6553 : {
6554 : // we're not expecting very many of these ever, so a tiny bit of
6555 : // de-duping is probably OK:
6556 0 : if (message == last_deprecation_message) {
6557 0 : return;
6558 : }
6559 :
6560 0 : const uint32_t now_ms = AP_HAL::millis();
6561 0 : if (last_deprecation_warning_send_time_ms - now_ms < 30000) {
6562 0 : return;
6563 : }
6564 0 : last_deprecation_warning_send_time_ms = now_ms;
6565 0 : last_deprecation_message = message;
6566 :
6567 0 : send_text(MAV_SEVERITY_INFO, "Received message (%s) is deprecated", message);
6568 : }
6569 :
6570 705655 : bool GCS_MAVLINK::send_available_modes()
6571 : {
6572 705655 : if (!available_modes.should_send) {
6573 : // must only return false if out of space
6574 705655 : return true;
6575 : }
6576 :
6577 0 : CHECK_PAYLOAD_SIZE(AVAILABLE_MODES);
6578 :
6579 : // Zero is a special case for send all.
6580 0 : const bool send_all = available_modes.requested_index == 0;
6581 : uint8_t request_index;
6582 0 : if (!send_all) {
6583 : // Single request
6584 0 : request_index = available_modes.requested_index;
6585 0 : available_modes.should_send = false;
6586 :
6587 : } else {
6588 : // Request all modes
6589 0 : request_index = available_modes.next_index;
6590 0 : available_modes.next_index += 1;
6591 : }
6592 :
6593 0 : const uint8_t mode_count = send_available_mode(request_index);
6594 :
6595 0 : if (send_all && (available_modes.next_index > mode_count)) {
6596 : // Sending all and just sent the last
6597 0 : available_modes.should_send = false;
6598 : }
6599 :
6600 0 : return true;
6601 : }
6602 :
6603 0 : bool GCS_MAVLINK::send_available_mode_monitor()
6604 : {
6605 0 : CHECK_PAYLOAD_SIZE(AVAILABLE_MODES_MONITOR);
6606 :
6607 0 : mavlink_msg_available_modes_monitor_send(
6608 : chan,
6609 0 : available_modes.available_modes_sequence
6610 : );
6611 :
6612 0 : return true;
6613 : }
6614 :
6615 81 : void GCS_MAVLINK::available_modes_changed()
6616 : {
6617 : // Only increment the counter if this channel is tracking modes
6618 81 : if (!available_modes.requested) {
6619 81 : return;
6620 : }
6621 :
6622 0 : available_modes.available_modes_sequence += 1;
6623 :
6624 : // Stream the AVAILABLE_MODES_MONITOR message
6625 : // This allows the GCS to re-request modes
6626 0 : set_ap_message_interval(MSG_AVAILABLE_MODES_MONITOR, 5000);
6627 : }
6628 :
6629 137647384 : bool GCS_MAVLINK::try_send_message(const enum ap_message id)
6630 : {
6631 137647384 : bool ret = true;
6632 :
6633 137647384 : switch(id) {
6634 :
6635 : #if AP_AHRS_ENABLED
6636 1144486 : case MSG_ATTITUDE:
6637 1144486 : CHECK_PAYLOAD_SIZE(ATTITUDE);
6638 1144401 : send_attitude();
6639 1144401 : break;
6640 :
6641 111 : case MSG_ATTITUDE_QUATERNION:
6642 111 : CHECK_PAYLOAD_SIZE(ATTITUDE_QUATERNION);
6643 111 : send_attitude_quaternion();
6644 111 : break;
6645 : #endif
6646 :
6647 84066992 : case MSG_NEXT_PARAM:
6648 84066992 : CHECK_PAYLOAD_SIZE(PARAM_VALUE);
6649 1625060 : queued_param_send();
6650 1625060 : break;
6651 :
6652 269141 : case MSG_HEARTBEAT:
6653 269141 : CHECK_PAYLOAD_SIZE(HEARTBEAT);
6654 170070 : last_heartbeat_time = AP_HAL::millis();
6655 170070 : send_heartbeat();
6656 170070 : break;
6657 :
6658 : #if AP_AHRS_ENABLED
6659 1552831 : case MSG_LOCATION:
6660 1552831 : CHECK_PAYLOAD_SIZE(GLOBAL_POSITION_INT);
6661 1552828 : send_global_position_int();
6662 1552828 : break;
6663 :
6664 11357 : case MSG_HOME:
6665 11357 : CHECK_PAYLOAD_SIZE(HOME_POSITION);
6666 11357 : send_home_position();
6667 11357 : break;
6668 :
6669 12085 : case MSG_ORIGIN:
6670 12085 : CHECK_PAYLOAD_SIZE(GPS_GLOBAL_ORIGIN);
6671 11850 : send_gps_global_origin();
6672 11850 : break;
6673 : #endif // AP_AHRS_ENABLED
6674 :
6675 : #if AP_MAVLINK_UTM_GLOBAL_POSITION_SENDING_ENABLED
6676 13 : case MSG_UTM_GLOBAL_POSITION:
6677 13 : CHECK_PAYLOAD_SIZE(UTM_GLOBAL_POSITION);
6678 13 : send_utm_global_position();
6679 13 : break;
6680 : #endif // AP_MAVLINK_UTM_GLOBAL_POSITION_SENDING_ENABLED
6681 :
6682 : #if AP_RPM_ENABLED
6683 1120967 : case MSG_RPM:
6684 1120967 : CHECK_PAYLOAD_SIZE(RPM);
6685 1120967 : send_rpm();
6686 1120967 : break;
6687 : #endif
6688 :
6689 1117385 : case MSG_CURRENT_WAYPOINT:
6690 : case MSG_MISSION_ITEM_REACHED:
6691 : case MSG_NEXT_MISSION_REQUEST_WAYPOINTS:
6692 : case MSG_NEXT_MISSION_REQUEST_RALLY:
6693 : case MSG_NEXT_MISSION_REQUEST_FENCE:
6694 1117385 : ret = try_send_mission_message(id);
6695 1117385 : break;
6696 :
6697 : #if COMPASS_CAL_ENABLED
6698 1117755 : case MSG_MAG_CAL_PROGRESS:
6699 1117755 : ret = AP::compass().send_mag_cal_progress(*this);
6700 1117755 : break;
6701 1117755 : case MSG_MAG_CAL_REPORT:
6702 1117755 : ret = AP::compass().send_mag_cal_report(*this);
6703 1117755 : break;
6704 : #endif
6705 :
6706 : #if AP_BATTERY_ENABLED
6707 1117755 : case MSG_BATTERY_STATUS:
6708 1117755 : send_battery_status();
6709 1117755 : break;
6710 : #endif // AP_BATTERY_ENABLED
6711 :
6712 : #if AP_AHRS_ENABLED
6713 1117755 : case MSG_EKF_STATUS_REPORT:
6714 1117755 : CHECK_PAYLOAD_SIZE(EKF_STATUS_REPORT);
6715 1117755 : AP::ahrs().send_ekf_status_report(*this);
6716 1117755 : break;
6717 : #endif
6718 :
6719 1117088 : case MSG_MEMINFO:
6720 1117088 : CHECK_PAYLOAD_SIZE(MEMINFO);
6721 1117088 : send_meminfo();
6722 1117088 : break;
6723 :
6724 : #if AP_FENCE_ENABLED
6725 1117208 : case MSG_FENCE_STATUS:
6726 1117208 : CHECK_PAYLOAD_SIZE(FENCE_STATUS);
6727 1117208 : send_fence_status();
6728 1117208 : break;
6729 : #endif
6730 :
6731 : #if AP_MAVLINK_MSG_RANGEFINDER_SENDING_ENABLED
6732 4400 : case MSG_RANGEFINDER:
6733 4400 : CHECK_PAYLOAD_SIZE(RANGEFINDER);
6734 4400 : send_rangefinder();
6735 4400 : break;
6736 : #endif // AP_MAVLINK_MSG_RANGEFINDER_SENDING_ENABLED
6737 :
6738 1117775 : case MSG_DISTANCE_SENSOR:
6739 1117775 : send_distance_sensor();
6740 1117775 : break;
6741 :
6742 : #if AP_CAMERA_ENABLED
6743 2884 : case MSG_CAMERA_FEEDBACK:
6744 : case MSG_CAMERA_INFORMATION:
6745 : case MSG_CAMERA_SETTINGS:
6746 : #if AP_CAMERA_SEND_FOV_STATUS_ENABLED
6747 : case MSG_CAMERA_FOV_STATUS:
6748 : #endif
6749 : case MSG_CAMERA_CAPTURE_STATUS:
6750 : #if AP_CAMERA_SEND_THERMAL_RANGE_ENABLED
6751 : case MSG_CAMERA_THERMAL_RANGE:
6752 : #endif
6753 : #if AP_MAVLINK_MSG_VIDEO_STREAM_INFORMATION_ENABLED
6754 : case MSG_VIDEO_STREAM_INFORMATION:
6755 : #endif // AP_MAVLINK_MSG_VIDEO_STREAM_INFORMATION_ENABLED
6756 : {
6757 2884 : AP_Camera *camera = AP::camera();
6758 2884 : if (camera == nullptr) {
6759 0 : break;
6760 : }
6761 2884 : return camera->send_mavlink_message(*this, id);
6762 : }
6763 : #endif // AP_CAMERA_ENABLED
6764 :
6765 1117756 : case MSG_SYSTEM_TIME:
6766 1117756 : CHECK_PAYLOAD_SIZE(SYSTEM_TIME);
6767 1117756 : send_system_time();
6768 1117756 : break;
6769 :
6770 : #if AP_GPS_GPS_RAW_INT_SENDING_ENABLED
6771 1117205 : case MSG_GPS_RAW:
6772 1117205 : CHECK_PAYLOAD_SIZE(GPS_RAW_INT);
6773 1117165 : AP::gps().send_mavlink_gps_raw(chan);
6774 1117165 : break;
6775 : #endif // AP_GPS_GPS_RAW_INT_SENDING_ENABLED
6776 : #if AP_GPS_GPS_RTK_SENDING_ENABLED
6777 1117087 : case MSG_GPS_RTK:
6778 1117087 : CHECK_PAYLOAD_SIZE(GPS_RTK);
6779 1117087 : AP::gps().send_mavlink_gps_rtk(chan, 0);
6780 1117087 : break;
6781 : #endif // AP_GPS_GPS_RTK_SENDING_ENABLED
6782 : #if AP_GPS_GPS2_RAW_SENDING_ENABLED
6783 1117087 : case MSG_GPS2_RAW:
6784 1117087 : CHECK_PAYLOAD_SIZE(GPS2_RAW);
6785 1117087 : AP::gps().send_mavlink_gps2_raw(chan);
6786 1117087 : break;
6787 : #endif // AP_GPS_GPS2_RAW_SENDING_ENABLED
6788 : #if AP_GPS_GPS2_RTK_SENDING_ENABLED
6789 1117087 : case MSG_GPS2_RTK:
6790 1117087 : CHECK_PAYLOAD_SIZE(GPS2_RTK);
6791 1117087 : AP::gps().send_mavlink_gps_rtk(chan, 1);
6792 1117087 : break;
6793 : #endif // AP_GPS_GPS2_RTK_SENDING_ENABLED
6794 :
6795 : #if AP_AHRS_ENABLED
6796 1119336 : case MSG_LOCAL_POSITION:
6797 1119336 : CHECK_PAYLOAD_SIZE(LOCAL_POSITION_NED);
6798 1119336 : send_local_position();
6799 1119336 : break;
6800 : #endif
6801 :
6802 : #if HAL_MOUNT_ENABLED
6803 1117867 : case MSG_GIMBAL_DEVICE_ATTITUDE_STATUS:
6804 1117867 : CHECK_PAYLOAD_SIZE(GIMBAL_DEVICE_ATTITUDE_STATUS);
6805 1117755 : send_gimbal_device_attitude_status();
6806 1117755 : break;
6807 11602 : case MSG_AUTOPILOT_STATE_FOR_GIMBAL_DEVICE:
6808 11602 : CHECK_PAYLOAD_SIZE(AUTOPILOT_STATE_FOR_GIMBAL_DEVICE);
6809 11602 : send_autopilot_state_for_gimbal_device();
6810 11602 : break;
6811 0 : case MSG_GIMBAL_MANAGER_INFORMATION:
6812 0 : CHECK_PAYLOAD_SIZE(GIMBAL_MANAGER_INFORMATION);
6813 0 : send_gimbal_manager_information();
6814 0 : break;
6815 25 : case MSG_GIMBAL_MANAGER_STATUS:
6816 25 : CHECK_PAYLOAD_SIZE(GIMBAL_MANAGER_STATUS);
6817 25 : send_gimbal_manager_status();
6818 25 : break;
6819 : #endif // HAL_MOUNT_ENABLED
6820 :
6821 : #if AP_OPTICALFLOW_ENABLED
6822 1117756 : case MSG_OPTICAL_FLOW:
6823 1117756 : CHECK_PAYLOAD_SIZE(OPTICAL_FLOW);
6824 1117755 : send_opticalflow();
6825 1117755 : break;
6826 : #endif
6827 :
6828 14691 : case MSG_ATTITUDE_TARGET:
6829 14691 : CHECK_PAYLOAD_SIZE(ATTITUDE_TARGET);
6830 14690 : send_attitude_target();
6831 14690 : break;
6832 :
6833 1117087 : case MSG_POSITION_TARGET_GLOBAL_INT:
6834 1117087 : CHECK_PAYLOAD_SIZE(POSITION_TARGET_GLOBAL_INT);
6835 1117087 : send_position_target_global_int();
6836 1117087 : break;
6837 :
6838 4724 : case MSG_POSITION_TARGET_LOCAL_NED:
6839 4724 : CHECK_PAYLOAD_SIZE(POSITION_TARGET_LOCAL_NED);
6840 4724 : send_position_target_local_ned();
6841 4724 : break;
6842 :
6843 1117088 : case MSG_POWER_STATUS:
6844 1117088 : CHECK_PAYLOAD_SIZE(POWER_STATUS);
6845 1117088 : send_power_status();
6846 1117088 : break;
6847 :
6848 : #if HAL_WITH_MCU_MONITORING
6849 : case MSG_MCU_STATUS:
6850 : CHECK_PAYLOAD_SIZE(MCU_STATUS);
6851 : send_mcu_status();
6852 : break;
6853 : #endif
6854 :
6855 : #if AP_RC_CHANNEL_ENABLED
6856 1117302 : case MSG_RC_CHANNELS:
6857 1117302 : CHECK_PAYLOAD_SIZE(RC_CHANNELS);
6858 1117302 : send_rc_channels();
6859 1117302 : break;
6860 :
6861 : #if AP_MAVLINK_MSG_RC_CHANNELS_RAW_ENABLED
6862 1117302 : case MSG_RC_CHANNELS_RAW:
6863 1117302 : CHECK_PAYLOAD_SIZE(RC_CHANNELS_RAW);
6864 1117302 : send_rc_channels_raw();
6865 1117302 : break;
6866 : #endif // AP_MAVLINK_MSG_RC_CHANNELS_RAW_ENABLED
6867 :
6868 : #endif
6869 :
6870 1117608 : case MSG_RAW_IMU:
6871 1117608 : CHECK_PAYLOAD_SIZE(RAW_IMU);
6872 1117608 : send_raw_imu();
6873 1117608 : break;
6874 :
6875 0 : case MSG_SCALED_IMU:
6876 0 : CHECK_PAYLOAD_SIZE(SCALED_IMU);
6877 0 : send_scaled_imu(0, mavlink_msg_scaled_imu_send);
6878 0 : break;
6879 :
6880 1117088 : case MSG_SCALED_IMU2:
6881 1117088 : CHECK_PAYLOAD_SIZE(SCALED_IMU2);
6882 1117088 : send_scaled_imu(1, mavlink_msg_scaled_imu2_send);
6883 1117088 : break;
6884 :
6885 1117088 : case MSG_SCALED_IMU3:
6886 1117088 : CHECK_PAYLOAD_SIZE(SCALED_IMU3);
6887 1117088 : send_scaled_imu(2, mavlink_msg_scaled_imu3_send);
6888 1117088 : break;
6889 : #if AP_MAVLINK_MSG_HIGHRES_IMU_ENABLED
6890 0 : case MSG_HIGHRES_IMU:
6891 0 : CHECK_PAYLOAD_SIZE(HIGHRES_IMU);
6892 0 : send_highres_imu();
6893 0 : break;
6894 : #endif
6895 :
6896 1117304 : case MSG_SCALED_PRESSURE:
6897 1117304 : CHECK_PAYLOAD_SIZE(SCALED_PRESSURE);
6898 1117303 : send_scaled_pressure();
6899 1117303 : break;
6900 :
6901 1117088 : case MSG_SCALED_PRESSURE2:
6902 1117088 : CHECK_PAYLOAD_SIZE(SCALED_PRESSURE2);
6903 1117088 : send_scaled_pressure2();
6904 1117088 : break;
6905 :
6906 1117088 : case MSG_SCALED_PRESSURE3:
6907 1117088 : CHECK_PAYLOAD_SIZE(SCALED_PRESSURE3);
6908 1117088 : send_scaled_pressure3();
6909 1117088 : break;
6910 :
6911 : #if AP_AIRSPEED_ENABLED
6912 1117087 : case MSG_AIRSPEED:
6913 1117087 : CHECK_PAYLOAD_SIZE(AIRSPEED);
6914 1117087 : send_airspeed();
6915 1117087 : break;
6916 : #endif
6917 :
6918 1131807 : case MSG_SERVO_OUTPUT_RAW:
6919 1131807 : CHECK_PAYLOAD_SIZE(SERVO_OUTPUT_RAW);
6920 1131807 : send_servo_output_raw();
6921 1131807 : break;
6922 :
6923 : #if AP_SIM_ENABLED
6924 1128799 : case MSG_SIMSTATE:
6925 1128799 : CHECK_PAYLOAD_SIZE(SIMSTATE);
6926 1127758 : send_simstate();
6927 1127758 : break;
6928 :
6929 2791 : case MSG_SIM_STATE:
6930 2791 : CHECK_PAYLOAD_SIZE(SIM_STATE);
6931 2791 : send_sim_state();
6932 2791 : break;
6933 : #endif
6934 :
6935 1117272 : case MSG_SYS_STATUS:
6936 1117272 : CHECK_PAYLOAD_SIZE(SYS_STATUS);
6937 1117266 : send_sys_status();
6938 1117266 : break;
6939 :
6940 : #if AP_AHRS_ENABLED
6941 1121064 : case MSG_AHRS2:
6942 1121064 : CHECK_PAYLOAD_SIZE(AHRS2);
6943 1120989 : send_ahrs2();
6944 1120989 : break;
6945 : #endif
6946 :
6947 1120967 : case MSG_PID_TUNING:
6948 1120967 : CHECK_PAYLOAD_SIZE(PID_TUNING);
6949 1120967 : send_pid_tuning();
6950 1120967 : break;
6951 :
6952 1117088 : case MSG_NAV_CONTROLLER_OUTPUT:
6953 1117088 : CHECK_PAYLOAD_SIZE(NAV_CONTROLLER_OUTPUT);
6954 1117088 : send_nav_controller_output();
6955 1117088 : break;
6956 :
6957 : #if AP_AHRS_ENABLED
6958 1117821 : case MSG_AHRS:
6959 1117821 : CHECK_PAYLOAD_SIZE(AHRS);
6960 1117757 : send_ahrs();
6961 1117757 : break;
6962 : #endif
6963 :
6964 3716 : case MSG_EXTENDED_SYS_STATE:
6965 3716 : CHECK_PAYLOAD_SIZE(EXTENDED_SYS_STATE);
6966 3716 : send_extended_sys_state();
6967 3716 : break;
6968 :
6969 : #if AP_AHRS_ENABLED
6970 1119092 : case MSG_VFR_HUD:
6971 1119092 : CHECK_PAYLOAD_SIZE(VFR_HUD);
6972 1119088 : send_vfr_hud();
6973 1119088 : break;
6974 : #endif
6975 :
6976 1115995 : case MSG_VIBRATION:
6977 1115995 : CHECK_PAYLOAD_SIZE(VIBRATION);
6978 1115995 : send_vibration();
6979 1115995 : break;
6980 :
6981 : #if HAL_GENERATOR_ENABLED
6982 1122504 : case MSG_GENERATOR_STATUS:
6983 1122504 : CHECK_PAYLOAD_SIZE(GENERATOR_STATUS);
6984 1122504 : send_generator_status();
6985 1122504 : break;
6986 : #endif
6987 :
6988 30 : case MSG_AUTOPILOT_VERSION:
6989 30 : CHECK_PAYLOAD_SIZE(AUTOPILOT_VERSION);
6990 30 : send_autopilot_version();
6991 30 : break;
6992 :
6993 : #if HAL_WITH_ESC_TELEM
6994 1120967 : case MSG_ESC_TELEMETRY:
6995 1120967 : AP::esc_telem().send_esc_telemetry_mavlink(uint8_t(chan));
6996 1120967 : break;
6997 : #endif
6998 :
6999 : #if HAL_EFI_ENABLED
7000 1122206 : case MSG_EFI_STATUS: {
7001 1122206 : CHECK_PAYLOAD_SIZE(EFI_STATUS);
7002 1122204 : AP_EFI *efi = AP::EFI();
7003 1122204 : if (efi) {
7004 1122204 : efi->send_mavlink_status(chan);
7005 : }
7006 1122204 : break;
7007 : }
7008 : #endif
7009 :
7010 : #if AP_WINCH_ENABLED
7011 1120967 : case MSG_WINCH_STATUS:
7012 1120967 : CHECK_PAYLOAD_SIZE(WINCH_STATUS);
7013 1120967 : send_winch_status();
7014 1120967 : break;
7015 : #endif
7016 :
7017 : #if HAL_HIGH_LATENCY2_ENABLED
7018 1456 : case MSG_HIGH_LATENCY2:
7019 1456 : CHECK_PAYLOAD_SIZE(HIGH_LATENCY2);
7020 1456 : send_high_latency2();
7021 1456 : break;
7022 : #endif // HAL_HIGH_LATENCY2_ENABLED
7023 :
7024 : #if AP_AIS_ENABLED
7025 1114539 : case MSG_AIS_VESSEL: {
7026 1114539 : AP_AIS *ais = AP_AIS::get_singleton();
7027 1114539 : if (ais) {
7028 124162 : ais->send(chan);
7029 : }
7030 1114539 : break;
7031 : }
7032 : #endif
7033 :
7034 : #if AP_MAVLINK_MSG_UAVIONIX_ADSB_OUT_STATUS_ENABLED
7035 0 : case MSG_UAVIONIX_ADSB_OUT_STATUS:
7036 0 : CHECK_PAYLOAD_SIZE(UAVIONIX_ADSB_OUT_STATUS);
7037 0 : send_uavionix_adsb_out_status();
7038 0 : break;
7039 : #endif
7040 :
7041 : #if AP_MAVLINK_MSG_RELAY_STATUS_ENABLED
7042 377 : case MSG_RELAY_STATUS:
7043 377 : ret = send_relay_status();
7044 377 : break;
7045 : #endif
7046 :
7047 705655 : case MSG_AVAILABLE_MODES:
7048 705655 : ret = send_available_modes();
7049 705655 : break;
7050 :
7051 0 : case MSG_AVAILABLE_MODES_MONITOR:
7052 0 : ret = send_available_mode_monitor();
7053 0 : break;
7054 :
7055 : #if AP_MAVLINK_MSG_FLIGHT_INFORMATION_ENABLED
7056 0 : case MSG_FLIGHT_INFORMATION:
7057 0 : CHECK_PAYLOAD_SIZE(FLIGHT_INFORMATION);
7058 0 : send_flight_information();
7059 0 : break;
7060 : #endif
7061 :
7062 : #if AP_TERRAIN_AVAILABLE
7063 1117756 : case MSG_TERRAIN_REQUEST: {
7064 1117756 : CHECK_PAYLOAD_SIZE(TERRAIN_REQUEST);
7065 1117756 : AP_Terrain *terrain = AP::terrain();
7066 1117756 : if (terrain != nullptr) {
7067 991097 : terrain->send_request(*this);
7068 : }
7069 1117756 : break;
7070 : }
7071 1117756 : case MSG_TERRAIN_REPORT: {
7072 1117756 : CHECK_PAYLOAD_SIZE(TERRAIN_REPORT);
7073 1117756 : AP_Terrain *terrain = AP::terrain();
7074 1117756 : if (terrain != nullptr) {
7075 991097 : terrain->send_report(*this);
7076 : }
7077 1117756 : break;
7078 : }
7079 : #endif // AP_TERRAIN_AVAILABLE
7080 :
7081 : #if AP_AIRSPEED_HYGROMETER_ENABLE
7082 : // hygrometer should be in its down library, not called via
7083 : // Plane's functions
7084 619663 : case MSG_HYGROMETER:
7085 : #endif
7086 : // ADSB should be moved down into here
7087 : case MSG_ADSB_VEHICLE:
7088 619663 : break;
7089 :
7090 0 : default:
7091 : // try_send_message must always at some stage return true for
7092 : // a message, or we will attempt to infinitely retry the
7093 : // message as part of send_message.
7094 : // This message will be sent out at the same rate as the
7095 : // unknown message, so should be safe.
7096 0 : GCS_SEND_TEXT(MAV_SEVERITY_DEBUG, "Sending unknown message (%u)", id);
7097 : #if CONFIG_HAL_BOARD == HAL_BOARD_SITL
7098 0 : AP_HAL::panic("Sending unknown ap_message %u", id);
7099 : #endif
7100 0 : break;
7101 : }
7102 :
7103 55101827 : return ret;
7104 : }
7105 :
7106 82485 : uint16_t GCS_MAVLINK::get_interval_for_stream(GCS_MAVLINK::streams id) const
7107 : {
7108 82485 : const int16_t frate = streamRates[id].get();
7109 82485 : if (frate == 0) {
7110 32173 : return 0;
7111 : }
7112 50312 : const uint32_t ret = 1000/frate;
7113 50312 : if (ret > 60000) {
7114 0 : return 60000;
7115 : }
7116 50312 : return ret;
7117 : }
7118 :
7119 82480 : void GCS_MAVLINK::initialise_message_intervals_for_stream(GCS_MAVLINK::streams id)
7120 : {
7121 446215 : for (uint8_t i=0; all_stream_entries[i].ap_message_ids != nullptr; i++) {
7122 446215 : const GCS_MAVLINK::stream_entries &entries = all_stream_entries[i];
7123 446215 : if (entries.stream_id != id) {
7124 363735 : continue;
7125 : }
7126 : // found it!
7127 82480 : const uint16_t interval_ms = get_interval_for_stream(id);
7128 517649 : for (uint8_t j=0; j<entries.num_ap_message_ids; j++) {
7129 435169 : set_ap_message_interval(entries.ap_message_ids[j], interval_ms);
7130 : }
7131 82480 : break;
7132 : }
7133 82480 : }
7134 :
7135 : #if HAL_MAVLINK_INTERVALS_FROM_FILES_ENABLED
7136 : // open and read contents of path, setting message intervals from each
7137 : // line
7138 2 : DefaultIntervalsFromFiles::DefaultIntervalsFromFiles(uint16_t max_num)
7139 : {
7140 2 : if (max_num == 0) {
7141 0 : return;
7142 : }
7143 2 : _intervals = NEW_NOTHROW from_file_default_interval[max_num];
7144 2 : _max_intervals = max_num;
7145 : }
7146 :
7147 1 : DefaultIntervalsFromFiles::~DefaultIntervalsFromFiles()
7148 : {
7149 1 : delete[] (_intervals);
7150 1 : }
7151 :
7152 4 : void DefaultIntervalsFromFiles::set(ap_message id, uint16_t interval)
7153 : {
7154 4 : if (_intervals == nullptr) {
7155 0 : return;
7156 : }
7157 :
7158 : // update any existing interval (last-one-in wins)
7159 6 : for (uint8_t i=0; i<_num_intervals; i++) {
7160 2 : if (_intervals[i].id == id) {
7161 0 : _intervals[i].interval = interval;
7162 0 : return;
7163 : }
7164 : }
7165 :
7166 : // store an interval we've not seen before:
7167 4 : if (_num_intervals == _max_intervals) {
7168 0 : return;
7169 : }
7170 :
7171 4 : _intervals[_num_intervals].id = id;
7172 4 : _intervals[_num_intervals].interval = interval;
7173 4 : _num_intervals++;
7174 : }
7175 :
7176 0 : bool DefaultIntervalsFromFiles::get_interval_for_ap_message_id(ap_message id, uint16_t &interval) const
7177 : {
7178 0 : for (uint16_t i=0; i<_num_intervals; i++) {
7179 0 : if (_intervals[i].id == id) {
7180 0 : interval = _intervals[i].interval;
7181 0 : return true;
7182 : }
7183 : }
7184 0 : return false;
7185 : }
7186 :
7187 2 : ap_message DefaultIntervalsFromFiles::id_at(uint8_t ofs) const
7188 : {
7189 2 : if (_intervals == nullptr || ofs >= _num_intervals) {
7190 0 : return MSG_LAST;
7191 : }
7192 2 : return _intervals[ofs].id;
7193 : }
7194 :
7195 2 : uint16_t DefaultIntervalsFromFiles::interval_at(uint8_t ofs) const
7196 : {
7197 2 : if (_intervals == nullptr || ofs >= _num_intervals) {
7198 0 : return -1; // unsigned-integer wrap
7199 : }
7200 2 : return _intervals[ofs].interval;
7201 : }
7202 :
7203 4 : void GCS_MAVLINK::get_intervals_from_filepath(const char *path, DefaultIntervalsFromFiles &intervals)
7204 : {
7205 4 : const int f = AP::FS().open(path, O_RDONLY);
7206 4 : if (f == -1) {
7207 2 : return;
7208 : }
7209 :
7210 : char line[20];
7211 8 : while (AP::FS().fgets(line, sizeof(line), f)) {
7212 6 : char *saveptr = nullptr;
7213 6 : const char *mavlink_id_str = strtok_r(line, " ", &saveptr);
7214 6 : if (mavlink_id_str == nullptr || strlen(mavlink_id_str) == 0) {
7215 2 : continue;
7216 : }
7217 6 : const uint32_t mavlink_id = atoi(mavlink_id_str);
7218 :
7219 6 : const ap_message msg_id = mavlink_id_to_ap_message_id(mavlink_id);
7220 6 : if (msg_id == MSG_LAST) {
7221 2 : continue;
7222 : }
7223 :
7224 4 : const char *interval_str = strtok_r(nullptr, "\r\n", &saveptr);
7225 4 : if (interval_str == nullptr || strlen(interval_str) == 0) {
7226 0 : continue;
7227 : }
7228 4 : const uint16_t interval = atoi(interval_str);
7229 :
7230 4 : intervals.set(msg_id, interval);
7231 : }
7232 :
7233 2 : AP::FS().close(f);
7234 : }
7235 :
7236 6340 : void GCS_MAVLINK::initialise_message_intervals_from_config_files()
7237 : {
7238 : static const char *path_templates[] {
7239 : "@ROMFS/message-intervals-chan%u.txt",
7240 : "message-intervals-chan%u.txt"
7241 : };
7242 :
7243 : // don't do anything at all if no files exist:
7244 6340 : bool exists = false;
7245 19019 : for (const char * path_template : path_templates) {
7246 : struct stat stats;
7247 : char *path;
7248 12680 : if (asprintf(&path, path_template, chan) == -1) {
7249 12679 : continue;
7250 : }
7251 12680 : if (AP::FS().stat(path, &stats) < 0) {
7252 12679 : free(path);
7253 12679 : continue;
7254 : }
7255 1 : free(path);
7256 1 : if (stats.st_size == 0) {
7257 0 : continue;
7258 : }
7259 1 : exists = true;
7260 1 : break;
7261 : }
7262 6340 : if (!exists) {
7263 6339 : return;
7264 : }
7265 :
7266 : // first over-allocate:
7267 1 : DefaultIntervalsFromFiles *overallocated = NEW_NOTHROW DefaultIntervalsFromFiles(128);
7268 1 : if (overallocated == nullptr) {
7269 0 : return;
7270 : }
7271 3 : for (const char * path_template : path_templates) {
7272 : char *path;
7273 2 : if (asprintf(&path, path_template, chan) == -1) {
7274 0 : continue;
7275 : }
7276 2 : get_intervals_from_filepath(path, *overallocated);
7277 2 : free(path);
7278 : }
7279 :
7280 : // then allocate just the right number and redo all of the work:
7281 1 : const uint16_t num_required = overallocated->num_intervals();
7282 1 : delete overallocated;
7283 1 : overallocated = nullptr;
7284 :
7285 1 : default_intervals_from_files = NEW_NOTHROW DefaultIntervalsFromFiles(num_required);
7286 1 : if (default_intervals_from_files == nullptr) {
7287 0 : return;
7288 : }
7289 3 : for (const char * path_template : path_templates) {
7290 : char *path;
7291 2 : if (asprintf(&path, path_template, chan) == -1) {
7292 0 : continue;
7293 : }
7294 2 : get_intervals_from_filepath(path, *default_intervals_from_files);
7295 2 : free(path);
7296 : }
7297 :
7298 : // now actually initialise the intervals:
7299 3 : for (uint8_t i=0; i<default_intervals_from_files->num_intervals(); i++) {
7300 2 : const ap_message id = default_intervals_from_files->id_at(i);
7301 2 : if (id == MSG_LAST) {
7302 : // internal error
7303 0 : break;
7304 : }
7305 2 : const uint16_t interval = default_intervals_from_files->interval_at(i);
7306 2 : set_ap_message_interval(id, interval);
7307 : }
7308 : }
7309 : #endif
7310 :
7311 6340 : void GCS_MAVLINK::initialise_message_intervals_from_streamrates()
7312 : {
7313 : #if HAL_HIGH_LATENCY2_ENABLED
7314 6340 : if (!is_high_latency_link) {
7315 : // this is O(n^2), but it's once at boot and across a 10-entry list...
7316 69718 : for (uint8_t i=0; all_stream_entries[i].ap_message_ids != nullptr; i++) {
7317 63380 : initialise_message_intervals_for_stream(all_stream_entries[i].stream_id);
7318 : }
7319 6338 : set_mavlink_message_id_interval(MAVLINK_MSG_ID_HEARTBEAT, 1000);
7320 : } else {
7321 2 : set_mavlink_message_id_interval(MAVLINK_MSG_ID_HIGH_LATENCY2, 5000);
7322 : }
7323 : #else
7324 : // this is O(n^2), but it's once at boot and across a 10-entry list...
7325 : for (uint8_t i=0; all_stream_entries[i].ap_message_ids != nullptr; i++) {
7326 : initialise_message_intervals_for_stream(all_stream_entries[i].stream_id);
7327 : }
7328 : set_mavlink_message_id_interval(MAVLINK_MSG_ID_HEARTBEAT, 1000);
7329 : #endif
7330 6340 : }
7331 :
7332 43 : bool GCS_MAVLINK::get_default_interval_for_ap_message(const ap_message id, uint16_t &interval) const
7333 : {
7334 43 : if (id == MSG_HEARTBEAT) {
7335 : // handle heartbeat requests as a special case because heartbeat is not "streamed"
7336 0 : interval = 1000;
7337 0 : return true;
7338 : }
7339 :
7340 : #if HAL_HIGH_LATENCY2_ENABLED
7341 43 : if (id == MSG_HIGH_LATENCY2) {
7342 : // handle HL2 requests as a special case because HL2 is not "streamed"
7343 2 : interval = 5000;
7344 2 : return true;
7345 : }
7346 : #endif
7347 :
7348 : #if HAL_MAVLINK_INTERVALS_FROM_FILES_ENABLED
7349 : // a user can specify default rates in files, which are read close
7350 : // to vehicle startup
7351 41 : if (default_intervals_from_files != nullptr &&
7352 0 : default_intervals_from_files->get_interval_for_ap_message_id(id, interval)) {
7353 0 : return true;
7354 : }
7355 : #endif
7356 :
7357 : // find which stream this ap_message is in
7358 430 : for (uint8_t i=0; all_stream_entries[i].ap_message_ids != nullptr; i++) {
7359 394 : const GCS_MAVLINK::stream_entries &entries = all_stream_entries[i];
7360 2425 : for (uint8_t j=0; j<entries.num_ap_message_ids; j++) {
7361 2036 : if (entries.ap_message_ids[j] == id) {
7362 5 : interval = get_interval_for_stream(all_stream_entries[i].stream_id);
7363 5 : return true;
7364 : }
7365 : }
7366 : }
7367 36 : return false;
7368 : }
7369 :
7370 : /*
7371 : correct an offboard timestamp in microseconds into a local timestamp
7372 : since boot in milliseconds. See the JitterCorrection code for details
7373 :
7374 : Return a value in milliseconds since boot (for use by the EKF)
7375 : */
7376 15583 : uint32_t GCS_MAVLINK::correct_offboard_timestamp_usec_to_ms(uint64_t offboard_usec, uint16_t payload_size)
7377 : {
7378 : uint64_t local_us;
7379 : // if the HAL supports it then constrain the latest possible time
7380 : // the packet could have been sent by the uart receive time and
7381 : // the baudrate and packet size.
7382 15583 : uint64_t uart_receive_time = _port->receive_time_constraint_us(payload_size);
7383 15583 : if (uart_receive_time != 0) {
7384 15583 : local_us = uart_receive_time;
7385 : } else {
7386 0 : local_us = AP_HAL::micros64();
7387 : }
7388 15583 : uint64_t corrected_us = lag_correction.correct_offboard_timestamp_usec(offboard_usec, local_us);
7389 :
7390 15583 : return corrected_us / 1000U;
7391 : }
7392 :
7393 : /*
7394 : return true if we will accept this packet. Used to implement MAV_GCS_ENFRCE
7395 : */
7396 2784435 : bool GCS_MAVLINK::accept_packet(const mavlink_status_t &status,
7397 : const mavlink_message_t &msg) const
7398 : {
7399 2784435 : if (msg.sysid == mavlink_system.sysid) {
7400 : // accept packets from our own components
7401 : // (e.g. mavlink-connected companion computers)
7402 21798 : return true;
7403 : }
7404 :
7405 2762637 : if (gcs().sysid_is_gcs(msg.sysid)) {
7406 37517 : return true;
7407 : }
7408 :
7409 2725120 : if (msg.msgid == MAVLINK_MSG_ID_RADIO ||
7410 2725120 : msg.msgid == MAVLINK_MSG_ID_RADIO_STATUS) {
7411 0 : return true;
7412 : }
7413 :
7414 2725120 : if (!gcs().option_is_enabled(GCS::Option::GCS_SYSID_ENFORCE)) {
7415 2725052 : return true;
7416 : }
7417 :
7418 68 : return false;
7419 : }
7420 :
7421 : /*
7422 : update UART pass-thru, if enabled
7423 : */
7424 41931458 : void GCS::update_passthru(void)
7425 : {
7426 : #if APM_BUILD_TYPE(APM_BUILD_UNKNOWN)
7427 : // examples don't have AP::serialmanager
7428 0 : return;
7429 : #endif
7430 :
7431 41931458 : WITH_SEMAPHORE(_passthru.sem);
7432 41931458 : uint32_t now = AP_HAL::millis();
7433 : uint32_t baud1, baud2;
7434 41931458 : bool enabled = AP::serialmanager().get_passthru(_passthru.port1, _passthru.port2, _passthru.timeout_s,
7435 : baud1, baud2);
7436 41931458 : if (enabled && !_passthru.enabled) {
7437 0 : _passthru.start_ms = now;
7438 0 : _passthru.last_ms = 0;
7439 0 : _passthru.enabled = true;
7440 0 : _passthru.last_port1_data_ms = now;
7441 0 : _passthru.baud1 = baud1;
7442 0 : _passthru.baud2 = baud2;
7443 0 : _passthru.parity1 = _passthru.port1->get_parity();
7444 0 : _passthru.parity2 = _passthru.port2->get_parity();
7445 0 : GCS_SEND_TEXT(MAV_SEVERITY_INFO, "Passthru enabled");
7446 0 : if (!_passthru.timer_installed) {
7447 0 : _passthru.timer_installed = true;
7448 0 : hal.scheduler->register_timer_process(FUNCTOR_BIND_MEMBER(&GCS::passthru_timer, void));
7449 : }
7450 41931458 : } else if (!enabled && _passthru.enabled) {
7451 0 : _passthru.enabled = false;
7452 0 : _passthru.port1->lock_port(0, 0);
7453 0 : _passthru.port2->lock_port(0, 0);
7454 : // Restore original baudrates
7455 0 : if (_passthru.baud1 != baud1) {
7456 0 : _passthru.port1->end();
7457 0 : _passthru.port1->begin(baud1);
7458 : }
7459 0 : if (_passthru.baud2 != baud2) {
7460 0 : _passthru.port2->end();
7461 0 : _passthru.port2->begin(baud2);
7462 : }
7463 : // Restore original parity
7464 0 : if (_passthru.parity1 != _passthru.port1->get_parity()) {
7465 0 : _passthru.port1->configure_parity(_passthru.parity1);
7466 : }
7467 0 : if (_passthru.parity2 != _passthru.port2->get_parity()) {
7468 0 : _passthru.port2->configure_parity(_passthru.parity2);
7469 : }
7470 0 : GCS_SEND_TEXT(MAV_SEVERITY_INFO, "Passthru disabled");
7471 41931458 : } else if (enabled &&
7472 0 : _passthru.timeout_s &&
7473 0 : now - _passthru.last_port1_data_ms > uint32_t(_passthru.timeout_s)*1000U) {
7474 : // timed out, disable
7475 0 : _passthru.enabled = false;
7476 0 : _passthru.port1->lock_port(0, 0);
7477 0 : _passthru.port2->lock_port(0, 0);
7478 0 : AP::serialmanager().disable_passthru();
7479 : // Restore original baudrates
7480 0 : if (_passthru.baud1 != baud1) {
7481 0 : _passthru.port1->end();
7482 0 : _passthru.port1->begin(baud1);
7483 : }
7484 0 : if (_passthru.baud2 != baud2) {
7485 0 : _passthru.port2->end();
7486 0 : _passthru.port2->begin(baud2);
7487 : }
7488 : // Restore original parity
7489 0 : if (_passthru.parity1 != _passthru.port1->get_parity()) {
7490 0 : _passthru.port1->configure_parity(_passthru.parity1);
7491 : }
7492 0 : if (_passthru.parity2 != _passthru.port2->get_parity()) {
7493 0 : _passthru.port2->configure_parity(_passthru.parity2);
7494 : }
7495 0 : GCS_SEND_TEXT(MAV_SEVERITY_INFO, "Passthru timed out");
7496 : }
7497 41931458 : }
7498 :
7499 : /*
7500 : called at 1kHz to handle pass-thru between SERIAL_PASS1 and SERIAL_PASS2 ports
7501 : */
7502 0 : void GCS::passthru_timer(void)
7503 : {
7504 0 : WITH_SEMAPHORE(_passthru.sem);
7505 :
7506 0 : if (!_passthru.enabled) {
7507 : // it has been disabled after starting
7508 0 : return;
7509 : }
7510 0 : if (_passthru.start_ms != 0) {
7511 0 : uint32_t now = AP_HAL::millis();
7512 0 : if (now - _passthru.start_ms < 1000) {
7513 : // delay for 1s so the reply for the SERIAL_PASS2 param set can be seen by GCS
7514 0 : return;
7515 : }
7516 0 : _passthru.start_ms = 0;
7517 0 : _passthru.port1->begin(_passthru.baud1);
7518 0 : _passthru.port2->begin(_passthru.baud2);
7519 : }
7520 :
7521 : // while pass-thru is enabled lock both ports. They remain
7522 : // locked until disabled again, or reboot
7523 0 : const uint32_t lock_key = 0x3256AB9F;
7524 0 : _passthru.port1->lock_port(lock_key, lock_key);
7525 0 : _passthru.port2->lock_port(lock_key, lock_key);
7526 :
7527 : // Check for requested Baud rates and parity over USB
7528 0 : uint32_t baud = _passthru.port1->get_usb_baud();
7529 0 : uint8_t parity = _passthru.port1->get_usb_parity();
7530 0 : if (baud != 0) { // port1 is USB
7531 0 : if (_passthru.baud2 != baud) {
7532 0 : _passthru.baud2 = baud;
7533 0 : _passthru.port2->end();
7534 0 : _passthru.port2->begin_locked(baud, 0, 0, lock_key);
7535 : }
7536 :
7537 0 : if (_passthru.parity2 != parity) {
7538 0 : _passthru.parity2 = parity;
7539 0 : _passthru.port2->configure_parity(parity);
7540 : }
7541 : }
7542 :
7543 0 : baud = _passthru.port2->get_usb_baud();
7544 0 : parity = _passthru.port2->get_usb_parity();
7545 0 : if (baud != 0) { // port2 is USB
7546 0 : if (_passthru.baud1 != baud) {
7547 0 : _passthru.baud1 = baud;
7548 0 : _passthru.port1->end();
7549 0 : _passthru.port1->begin_locked(baud, 0, 0, lock_key);
7550 : }
7551 :
7552 0 : if (_passthru.parity1 != parity) {
7553 0 : _passthru.parity1 = parity;
7554 0 : _passthru.port1->configure_parity(parity);
7555 : }
7556 : }
7557 :
7558 : uint8_t buf[64];
7559 :
7560 : // read from port1, and write to port2
7561 0 : int16_t nbytes = _passthru.port1->read_locked(buf, MIN(sizeof(buf),_passthru.port2->txspace()), lock_key);
7562 0 : if (nbytes > 0) {
7563 0 : _passthru.last_port1_data_ms = AP_HAL::millis();
7564 0 : _passthru.port2->write_locked(buf, nbytes, lock_key);
7565 : }
7566 :
7567 : // read from port2, and write to port1
7568 0 : nbytes = _passthru.port2->read_locked(buf, MIN(sizeof(buf),_passthru.port1->txspace()), lock_key);
7569 0 : if (nbytes > 0) {
7570 0 : _passthru.port1->write_locked(buf, nbytes, lock_key);
7571 : }
7572 0 : }
7573 :
7574 634 : bool GCS_MAVLINK::mavlink_coordinate_frame_to_location_alt_frame(const MAV_FRAME coordinate_frame, Location::AltFrame &frame)
7575 : {
7576 634 : switch (coordinate_frame) {
7577 174 : case MAV_FRAME_GLOBAL_RELATIVE_ALT: // solo shot manager incorrectly sends RELATIVE_ALT instead of RELATIVE_ALT_INT
7578 : case MAV_FRAME_GLOBAL_RELATIVE_ALT_INT:
7579 174 : frame = Location::AltFrame::ABOVE_HOME;
7580 174 : return true;
7581 123 : case MAV_FRAME_GLOBAL_TERRAIN_ALT:
7582 : case MAV_FRAME_GLOBAL_TERRAIN_ALT_INT:
7583 123 : frame = Location::AltFrame::ABOVE_TERRAIN;
7584 123 : return true;
7585 337 : case MAV_FRAME_GLOBAL:
7586 : case MAV_FRAME_GLOBAL_INT:
7587 337 : frame = Location::AltFrame::ABSOLUTE;
7588 337 : return true;
7589 0 : default:
7590 : #if CONFIG_HAL_BOARD == HAL_BOARD_SITL
7591 0 : GCS_SEND_TEXT(MAV_SEVERITY_INFO, "Unknown mavlink coordinate frame %u", coordinate_frame);
7592 : #endif
7593 0 : return false;
7594 : }
7595 : }
7596 :
7597 30 : uint64_t GCS_MAVLINK::capabilities() const
7598 : {
7599 30 : uint64_t ret = MAV_PROTOCOL_CAPABILITY_PARAM_FLOAT |
7600 : MAV_PROTOCOL_CAPABILITY_COMPASS_CALIBRATION;
7601 :
7602 30 : const auto mavlink_protocol = uartstate->get_protocol();
7603 30 : if (mavlink_protocol == AP_SerialManager::SerialProtocol_MAVLink2 || mavlink_protocol == AP_SerialManager::SerialProtocol_MAVLinkHL) {
7604 30 : ret |= MAV_PROTOCOL_CAPABILITY_MAVLINK2;
7605 : }
7606 :
7607 : #if AP_ADVANCEDFAILSAFE_ENABLED
7608 30 : AP_AdvancedFailsafe *failsafe = AP::advancedfailsafe();
7609 30 : if (failsafe != nullptr && failsafe->enabled()) {
7610 : // Copter and Sub may also set this bit as they can always terminate
7611 1 : ret |= MAV_PROTOCOL_CAPABILITY_FLIGHT_TERMINATION;
7612 : }
7613 : #endif
7614 :
7615 : #if HAL_RALLY_ENABLED
7616 30 : if (AP::rally()) {
7617 27 : ret |= MAV_PROTOCOL_CAPABILITY_MISSION_RALLY;
7618 : }
7619 : #endif
7620 :
7621 : #if AP_FENCE_ENABLED
7622 30 : if (AP::fence()) {
7623 27 : ret |= MAV_PROTOCOL_CAPABILITY_MISSION_FENCE;
7624 : }
7625 : #endif
7626 :
7627 : #if AP_MAVLINK_FTP_ENABLED
7628 30 : if (!AP_BoardConfig::ftp_disabled()){ //if ftp disable board option is not set
7629 30 : ret |= MAV_PROTOCOL_CAPABILITY_FTP;
7630 : }
7631 : #endif
7632 :
7633 30 : return ret;
7634 : }
7635 :
7636 :
7637 : #if AP_RC_CHANNEL_ENABLED
7638 134 : void GCS_MAVLINK::manual_override(RC_Channel *c, int16_t value_in, const uint16_t offset, const float scaler, const uint32_t tnow, const bool reversed)
7639 : {
7640 134 : if (c == nullptr) {
7641 0 : return;
7642 : }
7643 134 : int16_t override_value = 0;
7644 134 : if (value_in != INT16_MAX) {
7645 54 : const int16_t radio_min = c->get_radio_min();
7646 54 : const int16_t radio_max = c->get_radio_max();
7647 54 : if (reversed) {
7648 2 : value_in *= -1;
7649 : }
7650 54 : override_value = radio_min + (radio_max - radio_min) * (value_in + offset) / scaler;
7651 : }
7652 134 : c->set_override(override_value, tnow);
7653 : }
7654 :
7655 56 : void GCS_MAVLINK::handle_manual_control(const mavlink_message_t &msg)
7656 : {
7657 56 : if (!gcs().sysid_is_gcs(msg.sysid)) {
7658 0 : return; // only accept control from our gcs
7659 : }
7660 :
7661 : mavlink_manual_control_t packet;
7662 56 : mavlink_msg_manual_control_decode(&msg, &packet);
7663 :
7664 56 : if (packet.target != gcs().sysid_this_mav()) {
7665 0 : return; // only accept control aimed at us
7666 : }
7667 :
7668 56 : uint32_t tnow = AP_HAL::millis();
7669 :
7670 56 : handle_manual_control_axes(packet, tnow);
7671 :
7672 : // a manual control message is considered to be a 'heartbeat'
7673 : // from the ground station for failsafe purposes
7674 56 : sysid_mygcs_seen(tnow);
7675 : }
7676 : #endif // AP_RC_CHANNEL_ENABLED
7677 :
7678 : // called when valid traffic has been seen from our GCS
7679 14919 : void GCS_MAVLINK::sysid_mygcs_seen(uint32_t seen_time_ms)
7680 : {
7681 14919 : gcs().sysid_mygcs_seen(seen_time_ms);
7682 14919 : _sysid_gcs_last_seen_time_ms = seen_time_ms;
7683 14919 : }
7684 :
7685 :
7686 : #if AP_RSSI_ENABLED
7687 1117406 : uint8_t GCS_MAVLINK::receiver_rssi() const
7688 : {
7689 1117406 : AP_RSSI *aprssi = AP::rssi();
7690 1117406 : if (aprssi == nullptr) {
7691 0 : return UINT8_MAX;
7692 : }
7693 :
7694 1117406 : if (!aprssi->enabled()) {
7695 1117406 : return UINT8_MAX;
7696 : }
7697 :
7698 : // scale across the full valid range
7699 0 : return aprssi->read_receiver_rssi() * 254;
7700 : }
7701 : #endif
7702 :
7703 1144549328 : GCS &gcs()
7704 : {
7705 1144549328 : return *GCS::get_singleton();
7706 : }
7707 :
7708 : /*
7709 : send HIGH_LATENCY2 message
7710 : */
7711 : #if HAL_HIGH_LATENCY2_ENABLED
7712 1456 : void GCS_MAVLINK::send_high_latency2() const
7713 : {
7714 : #if AP_AHRS_ENABLED
7715 1456 : AP_AHRS &ahrs = AP::ahrs();
7716 1456 : Location global_position_current;
7717 1456 : UNUSED_RESULT(ahrs.get_location(global_position_current));
7718 : #if AP_BATTERY_ENABLED
7719 1456 : const int8_t battery_remaining = battery_remaining_pct(AP_BATT_PRIMARY_INSTANCE);
7720 : #endif
7721 :
7722 1456 : uint16_t current_waypoint = 0;
7723 : #if AP_MISSION_ENABLED
7724 1456 : current_waypoint = AP::mission().get_current_nav_index();
7725 : #endif
7726 :
7727 : uint32_t present;
7728 : uint32_t enabled;
7729 : uint32_t health;
7730 1456 : gcs().get_sensor_status_flags(present, enabled, health);
7731 : // Remap HL_FAILURE_FLAG from system status flags
7732 : static const struct PACKED status_map_t {
7733 : MAV_SYS_STATUS_SENSOR sensor;
7734 : HL_FAILURE_FLAG failure_flag;
7735 : } status_map[] {
7736 : { MAV_SYS_STATUS_SENSOR_GPS, HL_FAILURE_FLAG_GPS },
7737 : { MAV_SYS_STATUS_SENSOR_DIFFERENTIAL_PRESSURE, HL_FAILURE_FLAG_DIFFERENTIAL_PRESSURE },
7738 : { MAV_SYS_STATUS_SENSOR_ABSOLUTE_PRESSURE, HL_FAILURE_FLAG_ABSOLUTE_PRESSURE },
7739 : { MAV_SYS_STATUS_SENSOR_3D_ACCEL, HL_FAILURE_FLAG_3D_ACCEL },
7740 : { MAV_SYS_STATUS_SENSOR_3D_GYRO, HL_FAILURE_FLAG_3D_GYRO },
7741 : { MAV_SYS_STATUS_SENSOR_3D_MAG, HL_FAILURE_FLAG_3D_MAG },
7742 : { MAV_SYS_STATUS_TERRAIN, HL_FAILURE_FLAG_TERRAIN },
7743 : { MAV_SYS_STATUS_SENSOR_BATTERY, HL_FAILURE_FLAG_BATTERY },
7744 : { MAV_SYS_STATUS_SENSOR_RC_RECEIVER, HL_FAILURE_FLAG_RC_RECEIVER },
7745 : { MAV_SYS_STATUS_GEOFENCE, HL_FAILURE_FLAG_GEOFENCE },
7746 : { MAV_SYS_STATUS_AHRS, HL_FAILURE_FLAG_ESTIMATOR },
7747 : };
7748 :
7749 1456 : uint16_t failure_flags = 0;
7750 17472 : for (auto &map_entry : status_map) {
7751 16016 : if ((health & map_entry.sensor) == 0) {
7752 744 : failure_flags |= map_entry.failure_flag;
7753 : }
7754 : }
7755 :
7756 1456 : mavlink_msg_high_latency2_send(chan,
7757 : AP_HAL::millis(), //[ms] Timestamp (milliseconds since boot or Unix epoch)
7758 1456 : gcs().frame_type(), // Type of the MAV (quadrotor, helicopter, etc.)
7759 : MAV_AUTOPILOT_ARDUPILOTMEGA, // Autopilot type / class. Use MAV_AUTOPILOT_INVALID for components that are not flight controllers.
7760 1456 : gcs().custom_mode(), // A bitfield for use for autopilot-specific flags (2 byte version).
7761 : global_position_current.lat, // [degE7] Latitude
7762 : global_position_current.lng, // [degE7] Longitude
7763 1456 : global_position_current.alt * 0.01f, // [m] Altitude above mean sea level
7764 1456 : high_latency_target_altitude(), // [m] Altitude setpoint
7765 1456 : uint16_t(ahrs.get_yaw_deg()) / 2, // [deg/2] Heading
7766 1456 : high_latency_tgt_heading(), // [deg/2] Heading setpoint
7767 1456 : high_latency_tgt_dist_dam(), // [dam] Distance to target waypoint or position
7768 1456 : abs(vfr_hud_throttle()), // [%] Throttle
7769 1456 : MIN(vfr_hud_airspeed() * 5, UINT8_MAX), // [m/s*5] Airspeed
7770 1456 : high_latency_tgt_airspeed(), // [m/s*5] Airspeed setpoint
7771 1456 : MIN(ahrs.groundspeed() * 5, UINT8_MAX), // [m/s*5] Groundspeed
7772 1456 : high_latency_wind_speed(), // [m/s*5] Windspeed
7773 1456 : high_latency_wind_direction(), // [deg/2] Wind heading
7774 : 0, // [dm] Maximum error horizontal position since last message
7775 : 0, // [dm] Maximum error vertical position since last message
7776 1456 : high_latency_air_temperature(), // [degC] Air temperature from airspeed sensor
7777 : 0, // [dm/s] Maximum climb rate magnitude since last message
7778 : #if AP_BATTERY_ENABLED
7779 : battery_remaining, // [%] Battery level (-1 if field not provided).
7780 : #else
7781 : -1,
7782 : #endif
7783 : current_waypoint, // Current waypoint number
7784 : failure_flags, // Bitmap of failure flags.
7785 1456 : base_mode(), // Field for custom payload. base mode (arming status) in ArduPilot's case
7786 : 0, // Field for custom payload.
7787 : 0); // Field for custom payload.
7788 : #endif
7789 1456 : }
7790 :
7791 1456 : int8_t GCS_MAVLINK::high_latency_air_temperature() const
7792 : {
7793 : #if AP_AIRSPEED_ENABLED
7794 : // return units are degC
7795 1456 : AP_Airspeed *airspeed = AP_Airspeed::get_singleton();
7796 : float air_temperature;
7797 1456 : if (airspeed != nullptr && airspeed->enabled() && airspeed->get_temperature(air_temperature)) {
7798 1456 : return air_temperature;
7799 : }
7800 : #endif
7801 :
7802 0 : return INT8_MIN;
7803 : }
7804 :
7805 : /*
7806 : handle a MAV_CMD_CONTROL_HIGH_LATENCY command
7807 :
7808 : Enable or disable any marked (via SERIALn_PROTOCOL) high latency connections
7809 : */
7810 16 : MAV_RESULT GCS_MAVLINK::handle_control_high_latency(const mavlink_command_int_t &packet)
7811 : {
7812 : // high latency mode is enabled if param1=1 or disabled if param1=0
7813 16 : if (is_equal(packet.param1, 0.0f)) {
7814 8 : gcs().enable_high_latency_connections(false);
7815 8 : } else if (is_equal(packet.param1, 1.0f)) {
7816 8 : gcs().enable_high_latency_connections(true);
7817 : } else {
7818 0 : return MAV_RESULT_FAILED;
7819 : }
7820 :
7821 : // send to all other mavlink components with same sysid
7822 16 : mavlink_command_long_t hl_msg{};
7823 16 : hl_msg.command = MAV_CMD_CONTROL_HIGH_LATENCY;
7824 16 : hl_msg.param1 = packet.param1;
7825 16 : GCS_MAVLINK::send_to_components(MAVLINK_MSG_ID_COMMAND_LONG, (char*)&hl_msg, sizeof(hl_msg));
7826 :
7827 16 : return MAV_RESULT_ACCEPTED;
7828 : }
7829 : #endif // HAL_HIGH_LATENCY2_ENABLED
7830 :
7831 : #if AP_RCPROTOCOL_MAVLINK_RADIO_ENABLED
7832 0 : void GCS_MAVLINK::handle_radio_rc_channels(const mavlink_message_t &msg)
7833 : {
7834 : mavlink_radio_rc_channels_t packet;
7835 0 : mavlink_msg_radio_rc_channels_decode(&msg, &packet);
7836 :
7837 0 : AP::RC().handle_radio_rc_channels(&packet);
7838 0 : }
7839 : #endif // AP_RCPROTOCOL_MAVLINK_RADIO_ENABLED
7840 :
7841 : #endif // HAL_GCS_ENABLED
|