send throttle in telemetry exactly as shown on osd
[inav.git] / src / main / telemetry / mavlink.c
blob58a96a92d454deb8c894561510919cb5d80730c8
1 /*
2 * This file is part of Cleanflight.
4 * Cleanflight 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.
9 * Cleanflight 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.
14 * You should have received a copy of the GNU General Public License
15 * along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
19 * telemetry_mavlink.c
21 * Author: Konstantin Sharlaimov
23 #include <stdbool.h>
24 #include <stdint.h>
25 #include <string.h>
26 #include <math.h>
28 #include "platform.h"
30 #if defined(USE_TELEMETRY) && defined(USE_TELEMETRY_MAVLINK)
32 #include "build/build_config.h"
33 #include "build/debug.h"
35 #include "common/axis.h"
36 #include "common/color.h"
37 #include "common/maths.h"
38 #include "common/utils.h"
39 #include "common/string_light.h"
41 #include "config/feature.h"
43 #include "drivers/serial.h"
44 #include "drivers/time.h"
45 #include "drivers/display.h"
46 #include "drivers/osd_symbols.h"
48 #include "fc/config.h"
49 #include "fc/fc_core.h"
50 #include "fc/rc_controls.h"
51 #include "fc/rc_modes.h"
52 #include "fc/runtime_config.h"
53 #include "fc/settings.h"
55 #include "flight/failsafe.h"
56 #include "flight/imu.h"
57 #include "flight/mixer.h"
58 #include "flight/pid.h"
59 #include "flight/servos.h"
61 #include "io/gps.h"
62 #include "io/ledstrip.h"
63 #include "io/serial.h"
64 #include "io/osd.h"
66 #include "navigation/navigation.h"
67 #include "navigation/navigation_private.h"
69 #include "rx/rx.h"
70 #include "rx/mavlink.h"
72 #include "sensors/acceleration.h"
73 #include "sensors/barometer.h"
74 #include "sensors/battery.h"
75 #include "sensors/boardalignment.h"
76 #include "sensors/gyro.h"
77 #include "sensors/pitotmeter.h"
78 #include "sensors/diagnostics.h"
79 #include "sensors/sensors.h"
80 #include "sensors/temperature.h"
81 #include "sensors/esc_sensor.h"
83 #include "telemetry/mavlink.h"
84 #include "telemetry/telemetry.h"
86 #include "blackbox/blackbox_io.h"
88 #include "scheduler/scheduler.h"
90 #pragma GCC diagnostic push
91 #pragma GCC diagnostic ignored "-Wunused-function"
92 #define MAVLINK_COMM_NUM_BUFFERS 1
93 #include "common/mavlink.h"
94 #pragma GCC diagnostic pop
96 #define TELEMETRY_MAVLINK_PORT_MODE MODE_RXTX
97 #define TELEMETRY_MAVLINK_MAXRATE 50
98 #define TELEMETRY_MAVLINK_DELAY ((1000 * 1000) / TELEMETRY_MAVLINK_MAXRATE)
101 * MAVLink requires angles to be in the range -Pi..Pi.
102 * This converts angles from a range of 0..Pi to -Pi..Pi
104 #define RADIANS_TO_MAVLINK_RANGE(angle) (angle > M_PIf) ? angle - (2 * M_PIf) : angle
106 /** @brief A mapping of plane flight modes for custom_mode field of heartbeat. */
107 typedef enum APM_PLANE_MODE
109 PLANE_MODE_MANUAL=0,
110 PLANE_MODE_CIRCLE=1,
111 PLANE_MODE_STABILIZE=2,
112 PLANE_MODE_TRAINING=3,
113 PLANE_MODE_ACRO=4,
114 PLANE_MODE_FLY_BY_WIRE_A=5,
115 PLANE_MODE_FLY_BY_WIRE_B=6,
116 PLANE_MODE_CRUISE=7,
117 PLANE_MODE_AUTOTUNE=8,
118 PLANE_MODE_AUTO=10,
119 PLANE_MODE_RTL=11,
120 PLANE_MODE_LOITER=12,
121 PLANE_MODE_TAKEOFF=13,
122 PLANE_MODE_AVOID_ADSB=14,
123 PLANE_MODE_GUIDED=15,
124 PLANE_MODE_INITIALIZING=16,
125 PLANE_MODE_QSTABILIZE=17,
126 PLANE_MODE_QHOVER=18,
127 PLANE_MODE_QLOITER=19,
128 PLANE_MODE_QLAND=20,
129 PLANE_MODE_QRTL=21,
130 PLANE_MODE_QAUTOTUNE=22,
131 PLANE_MODE_ENUM_END=23,
132 } APM_PLANE_MODE;
134 /** @brief A mapping of copter flight modes for custom_mode field of heartbeat. */
135 typedef enum APM_COPTER_MODE
137 COPTER_MODE_STABILIZE=0,
138 COPTER_MODE_ACRO=1,
139 COPTER_MODE_ALT_HOLD=2,
140 COPTER_MODE_AUTO=3,
141 COPTER_MODE_GUIDED=4,
142 COPTER_MODE_LOITER=5,
143 COPTER_MODE_RTL=6,
144 COPTER_MODE_CIRCLE=7,
145 COPTER_MODE_LAND=9,
146 COPTER_MODE_DRIFT=11,
147 COPTER_MODE_SPORT=13,
148 COPTER_MODE_FLIP=14,
149 COPTER_MODE_AUTOTUNE=15,
150 COPTER_MODE_POSHOLD=16,
151 COPTER_MODE_BRAKE=17,
152 COPTER_MODE_THROW=18,
153 COPTER_MODE_AVOID_ADSB=19,
154 COPTER_MODE_GUIDED_NOGPS=20,
155 COPTER_MODE_SMART_RTL=21,
156 COPTER_MODE_ENUM_END=22,
157 } APM_COPTER_MODE;
159 static serialPort_t *mavlinkPort = NULL;
160 static serialPortConfig_t *portConfig;
162 static bool mavlinkTelemetryEnabled = false;
163 static portSharing_e mavlinkPortSharing;
165 /* MAVLink datastream rates in Hz */
166 static uint8_t mavRates[] = {
167 [MAV_DATA_STREAM_EXTENDED_STATUS] = 2, // 2Hz
168 [MAV_DATA_STREAM_RC_CHANNELS] = 5, // 5Hz
169 [MAV_DATA_STREAM_POSITION] = 2, // 2Hz
170 [MAV_DATA_STREAM_EXTRA1] = 10, // 10Hz
171 [MAV_DATA_STREAM_EXTRA2] = 2, // 2Hz
172 [MAV_DATA_STREAM_EXTRA3] = 1 // 1Hz
175 #define MAXSTREAMS (sizeof(mavRates) / sizeof(mavRates[0]))
177 static timeUs_t lastMavlinkMessage = 0;
178 static uint8_t mavTicks[MAXSTREAMS];
179 static mavlink_message_t mavSendMsg;
180 static mavlink_message_t mavRecvMsg;
181 static mavlink_status_t mavRecvStatus;
183 static uint8_t mavSystemId = 1;
184 static uint8_t mavComponentId = MAV_COMP_ID_SYSTEM_CONTROL;
186 static APM_COPTER_MODE inavToArduCopterMap(flightModeForTelemetry_e flightMode)
188 switch (flightMode)
190 case FLM_ACRO: return COPTER_MODE_ACRO;
191 case FLM_ACRO_AIR: return COPTER_MODE_ACRO;
192 case FLM_ANGLE: return COPTER_MODE_STABILIZE;
193 case FLM_HORIZON: return COPTER_MODE_STABILIZE;
194 case FLM_ALTITUDE_HOLD: return COPTER_MODE_ALT_HOLD;
195 case FLM_POSITION_HOLD: return COPTER_MODE_POSHOLD;
196 case FLM_RTH: return COPTER_MODE_RTL;
197 case FLM_MISSION: return COPTER_MODE_AUTO;
198 case FLM_LAUNCH: return COPTER_MODE_THROW;
199 case FLM_FAILSAFE:
201 if (failsafePhase() == FAILSAFE_RETURN_TO_HOME) {
202 return COPTER_MODE_RTL;
203 } else if (failsafePhase() == FAILSAFE_LANDING) {
204 return COPTER_MODE_LAND;
205 } else {
206 // There is no valid mapping to ArduCopter
207 return COPTER_MODE_ENUM_END;
210 default: return COPTER_MODE_ENUM_END;
214 static APM_PLANE_MODE inavToArduPlaneMap(flightModeForTelemetry_e flightMode)
216 switch (flightMode)
218 case FLM_MANUAL: return PLANE_MODE_MANUAL;
219 case FLM_ACRO: return PLANE_MODE_ACRO;
220 case FLM_ACRO_AIR: return PLANE_MODE_ACRO;
221 case FLM_ANGLE: return PLANE_MODE_FLY_BY_WIRE_A;
222 case FLM_HORIZON: return PLANE_MODE_STABILIZE;
223 case FLM_ALTITUDE_HOLD: return PLANE_MODE_FLY_BY_WIRE_B;
224 case FLM_POSITION_HOLD: return PLANE_MODE_LOITER;
225 case FLM_RTH: return PLANE_MODE_RTL;
226 case FLM_MISSION: return PLANE_MODE_AUTO;
227 case FLM_CRUISE: return PLANE_MODE_CRUISE;
228 case FLM_LAUNCH: return PLANE_MODE_TAKEOFF;
229 case FLM_FAILSAFE:
231 if (failsafePhase() == FAILSAFE_RETURN_TO_HOME) {
232 return PLANE_MODE_RTL;
234 else if (failsafePhase() == FAILSAFE_LANDING) {
235 return PLANE_MODE_AUTO;
237 else {
238 // There is no valid mapping to ArduPlane
239 return PLANE_MODE_ENUM_END;
242 default: return PLANE_MODE_ENUM_END;
246 static int mavlinkStreamTrigger(enum MAV_DATA_STREAM streamNum)
248 uint8_t rate = (uint8_t) mavRates[streamNum];
249 if (rate == 0) {
250 return 0;
253 if (mavTicks[streamNum] == 0) {
254 // we're triggering now, setup the next trigger point
255 if (rate > TELEMETRY_MAVLINK_MAXRATE) {
256 rate = TELEMETRY_MAVLINK_MAXRATE;
259 mavTicks[streamNum] = (TELEMETRY_MAVLINK_MAXRATE / rate);
260 return 1;
263 // count down at TASK_RATE_HZ
264 mavTicks[streamNum]--;
265 return 0;
268 void freeMAVLinkTelemetryPort(void)
270 closeSerialPort(mavlinkPort);
271 mavlinkPort = NULL;
272 mavlinkTelemetryEnabled = false;
275 void initMAVLinkTelemetry(void)
277 portConfig = findSerialPortConfig(FUNCTION_TELEMETRY_MAVLINK);
278 mavlinkPortSharing = determinePortSharing(portConfig, FUNCTION_TELEMETRY_MAVLINK);
281 void configureMAVLinkTelemetryPort(void)
283 if (!portConfig) {
284 return;
287 baudRate_e baudRateIndex = portConfig->telemetry_baudrateIndex;
288 if (baudRateIndex == BAUD_AUTO) {
289 // default rate for minimOSD
290 baudRateIndex = BAUD_57600;
293 mavlinkPort = openSerialPort(portConfig->identifier, FUNCTION_TELEMETRY_MAVLINK, NULL, NULL, baudRates[baudRateIndex], TELEMETRY_MAVLINK_PORT_MODE, SERIAL_NOT_INVERTED);
295 if (!mavlinkPort) {
296 return;
299 mavlinkTelemetryEnabled = true;
302 static void configureMAVLinkStreamRates(void)
304 mavRates[MAV_DATA_STREAM_EXTENDED_STATUS] = telemetryConfig()->mavlink.extended_status_rate;
305 mavRates[MAV_DATA_STREAM_RC_CHANNELS] = telemetryConfig()->mavlink.rc_channels_rate;
306 mavRates[MAV_DATA_STREAM_POSITION] = telemetryConfig()->mavlink.position_rate;
307 mavRates[MAV_DATA_STREAM_EXTRA1] = telemetryConfig()->mavlink.extra1_rate;
308 mavRates[MAV_DATA_STREAM_EXTRA2] = telemetryConfig()->mavlink.extra2_rate;
309 mavRates[MAV_DATA_STREAM_EXTRA3] = telemetryConfig()->mavlink.extra3_rate;
312 void checkMAVLinkTelemetryState(void)
314 bool newTelemetryEnabledValue = telemetryDetermineEnabledState(mavlinkPortSharing);
316 if (newTelemetryEnabledValue == mavlinkTelemetryEnabled) {
317 return;
320 if (newTelemetryEnabledValue) {
321 configureMAVLinkTelemetryPort();
322 configureMAVLinkStreamRates();
323 } else
324 freeMAVLinkTelemetryPort();
327 static void mavlinkSendMessage(void)
329 uint8_t mavBuffer[MAVLINK_MAX_PACKET_LEN];
331 mavlink_status_t* chan_state = mavlink_get_channel_status(MAVLINK_COMM_0);
332 if (telemetryConfig()->mavlink.version == 1) {
333 chan_state->flags |= MAVLINK_STATUS_FLAG_OUT_MAVLINK1;
334 } else {
335 chan_state->flags &= ~MAVLINK_STATUS_FLAG_OUT_MAVLINK1;
338 int msgLength = mavlink_msg_to_send_buffer(mavBuffer, &mavSendMsg);
340 for (int i = 0; i < msgLength; i++) {
341 serialWrite(mavlinkPort, mavBuffer[i]);
345 void mavlinkSendSystemStatus(void)
347 // Receiver is assumed to be always present
348 uint32_t onboard_control_sensors_present = (MAV_SYS_STATUS_SENSOR_RC_RECEIVER);
349 // GYRO and RC are assumed as minimum requirements
350 uint32_t onboard_control_sensors_enabled = (MAV_SYS_STATUS_SENSOR_3D_GYRO | MAV_SYS_STATUS_SENSOR_RC_RECEIVER);
351 uint32_t onboard_control_sensors_health = 0;
353 if (getHwGyroStatus() == HW_SENSOR_OK) {
354 onboard_control_sensors_present |= MAV_SYS_STATUS_SENSOR_3D_GYRO;
355 // Missing presence will report as sensor unhealthy
356 onboard_control_sensors_health |= MAV_SYS_STATUS_SENSOR_3D_GYRO;
359 hardwareSensorStatus_e accStatus = getHwAccelerometerStatus();
360 if (accStatus == HW_SENSOR_OK) {
361 onboard_control_sensors_present |= MAV_SYS_STATUS_SENSOR_3D_ACCEL;
362 onboard_control_sensors_enabled |= MAV_SYS_STATUS_SENSOR_3D_ACCEL;
363 onboard_control_sensors_health |= MAV_SYS_STATUS_SENSOR_3D_ACCEL;
364 } else if (accStatus == HW_SENSOR_UNHEALTHY) {
365 onboard_control_sensors_present |= MAV_SYS_STATUS_SENSOR_3D_ACCEL;
366 onboard_control_sensors_enabled |= MAV_SYS_STATUS_SENSOR_3D_ACCEL;
367 } else if (accStatus == HW_SENSOR_UNAVAILABLE) {
368 onboard_control_sensors_enabled |= MAV_SYS_STATUS_SENSOR_3D_ACCEL;
371 hardwareSensorStatus_e compassStatus = getHwCompassStatus();
372 if (compassStatus == HW_SENSOR_OK) {
373 onboard_control_sensors_present |= MAV_SYS_STATUS_SENSOR_3D_MAG;
374 onboard_control_sensors_enabled |= MAV_SYS_STATUS_SENSOR_3D_MAG;
375 onboard_control_sensors_health |= MAV_SYS_STATUS_SENSOR_3D_MAG;
376 } else if (compassStatus == HW_SENSOR_UNHEALTHY) {
377 onboard_control_sensors_present |= MAV_SYS_STATUS_SENSOR_3D_MAG;
378 onboard_control_sensors_enabled |= MAV_SYS_STATUS_SENSOR_3D_MAG;
379 } else if (compassStatus == HW_SENSOR_UNAVAILABLE) {
380 onboard_control_sensors_enabled |= MAV_SYS_STATUS_SENSOR_3D_MAG;
383 hardwareSensorStatus_e baroStatus = getHwBarometerStatus();
384 if (baroStatus == HW_SENSOR_OK) {
385 onboard_control_sensors_present |= MAV_SYS_STATUS_SENSOR_ABSOLUTE_PRESSURE;
386 onboard_control_sensors_enabled |= MAV_SYS_STATUS_SENSOR_ABSOLUTE_PRESSURE;
387 onboard_control_sensors_health |= MAV_SYS_STATUS_SENSOR_ABSOLUTE_PRESSURE;
388 } else if (baroStatus == HW_SENSOR_UNHEALTHY) {
389 onboard_control_sensors_present |= MAV_SYS_STATUS_SENSOR_ABSOLUTE_PRESSURE;
390 onboard_control_sensors_enabled |= MAV_SYS_STATUS_SENSOR_ABSOLUTE_PRESSURE;
391 } else if (baroStatus == HW_SENSOR_UNAVAILABLE) {
392 onboard_control_sensors_enabled |= MAV_SYS_STATUS_SENSOR_ABSOLUTE_PRESSURE;
395 hardwareSensorStatus_e pitotStatus = getHwPitotmeterStatus();
396 if (pitotStatus == HW_SENSOR_OK) {
397 onboard_control_sensors_present |= MAV_SYS_STATUS_SENSOR_DIFFERENTIAL_PRESSURE;
398 onboard_control_sensors_enabled |= MAV_SYS_STATUS_SENSOR_DIFFERENTIAL_PRESSURE;
399 onboard_control_sensors_health |= MAV_SYS_STATUS_SENSOR_DIFFERENTIAL_PRESSURE;
400 } else if (pitotStatus == HW_SENSOR_UNHEALTHY) {
401 onboard_control_sensors_present |= MAV_SYS_STATUS_SENSOR_DIFFERENTIAL_PRESSURE;
402 onboard_control_sensors_enabled |= MAV_SYS_STATUS_SENSOR_DIFFERENTIAL_PRESSURE;
403 } else if (pitotStatus == HW_SENSOR_UNAVAILABLE) {
404 onboard_control_sensors_enabled |= MAV_SYS_STATUS_SENSOR_DIFFERENTIAL_PRESSURE;
407 hardwareSensorStatus_e gpsStatus = getHwGPSStatus();
408 if (gpsStatus == HW_SENSOR_OK) {
409 onboard_control_sensors_present |= MAV_SYS_STATUS_SENSOR_GPS;
410 onboard_control_sensors_enabled |= MAV_SYS_STATUS_SENSOR_GPS;
411 onboard_control_sensors_health |= MAV_SYS_STATUS_SENSOR_GPS;
412 } else if (gpsStatus == HW_SENSOR_UNHEALTHY) {
413 onboard_control_sensors_present |= MAV_SYS_STATUS_SENSOR_GPS;
414 onboard_control_sensors_enabled |= MAV_SYS_STATUS_SENSOR_GPS;
415 } else if (gpsStatus == HW_SENSOR_UNAVAILABLE) {
416 onboard_control_sensors_enabled |= MAV_SYS_STATUS_SENSOR_GPS;
419 hardwareSensorStatus_e opFlowStatus = getHwOpticalFlowStatus();
420 if (opFlowStatus == HW_SENSOR_OK) {
421 onboard_control_sensors_present |= MAV_SYS_STATUS_SENSOR_OPTICAL_FLOW;
422 onboard_control_sensors_enabled |= MAV_SYS_STATUS_SENSOR_OPTICAL_FLOW;
423 onboard_control_sensors_health |= MAV_SYS_STATUS_SENSOR_OPTICAL_FLOW;
424 } else if (opFlowStatus == HW_SENSOR_UNHEALTHY) {
425 onboard_control_sensors_present |= MAV_SYS_STATUS_SENSOR_OPTICAL_FLOW;
426 onboard_control_sensors_enabled |= MAV_SYS_STATUS_SENSOR_OPTICAL_FLOW;
427 } else if (opFlowStatus == HW_SENSOR_UNAVAILABLE) {
428 onboard_control_sensors_enabled |= MAV_SYS_STATUS_SENSOR_OPTICAL_FLOW;
431 hardwareSensorStatus_e rangefinderStatus = getHwRangefinderStatus();
432 if (rangefinderStatus == HW_SENSOR_OK) {
433 onboard_control_sensors_present |= MAV_SYS_STATUS_SENSOR_LASER_POSITION;
434 onboard_control_sensors_enabled |= MAV_SYS_STATUS_SENSOR_LASER_POSITION;
435 onboard_control_sensors_health |= MAV_SYS_STATUS_SENSOR_LASER_POSITION;
436 } else if (rangefinderStatus == HW_SENSOR_UNHEALTHY) {
437 onboard_control_sensors_present |= MAV_SYS_STATUS_SENSOR_LASER_POSITION;
438 onboard_control_sensors_enabled |= MAV_SYS_STATUS_SENSOR_LASER_POSITION;
439 } else if (rangefinderStatus == HW_SENSOR_UNAVAILABLE) {
440 onboard_control_sensors_enabled |= MAV_SYS_STATUS_SENSOR_LASER_POSITION;
443 if (rxIsReceivingSignal() && rxAreFlightChannelsValid()) {
444 onboard_control_sensors_health |= MAV_SYS_STATUS_SENSOR_RC_RECEIVER;
447 #ifdef USE_BLACKBOX
448 // BLACKBOX is assumed enabled and present for boards with capability
449 onboard_control_sensors_present |= MAV_SYS_STATUS_LOGGING;
450 onboard_control_sensors_enabled |= MAV_SYS_STATUS_LOGGING;
451 // Unhealthy only for cases with not enough space to record
452 if (!isBlackboxDeviceFull()) {
453 onboard_control_sensors_health |= MAV_SYS_STATUS_LOGGING;
455 #endif
457 mavlink_msg_sys_status_pack(mavSystemId, mavComponentId, &mavSendMsg,
458 // onboard_control_sensors_present Bitmask showing which onboard controllers and sensors are present.
459 //Value of 0: not present. Value of 1: present. Indices according MAV_SYS_STATUS_SENSOR
460 onboard_control_sensors_present,
461 // onboard_control_sensors_enabled Bitmask showing which onboard controllers and sensors are enabled
462 onboard_control_sensors_enabled,
463 // onboard_control_sensors_health Bitmask showing which onboard controllers and sensors are operational or have an error.
464 onboard_control_sensors_health,
465 // load Maximum usage in percent of the mainloop time, (0%: 0, 100%: 1000) should be always below 1000
466 constrain(averageSystemLoadPercent*10, 0, 1000),
467 // voltage_battery Battery voltage, in millivolts (1 = 1 millivolt)
468 feature(FEATURE_VBAT) ? getBatteryVoltage() * 10 : 0,
469 // current_battery Battery current, in 10*milliamperes (1 = 10 milliampere), -1: autopilot does not measure the current
470 isAmperageConfigured() ? getAmperage() : -1,
471 // battery_remaining Remaining battery energy: (0%: 0, 100%: 100), -1: autopilot estimate the remaining battery
472 feature(FEATURE_VBAT) ? calculateBatteryPercentage() : 100,
473 // drop_rate_comm Communication drops in percent, (0%: 0, 100%: 10'000), (UART, I2C, SPI, CAN), dropped packets on all links (packets that were corrupted on reception on the MAV)
475 // errors_comm Communication errors (UART, I2C, SPI, CAN), dropped packets on all links (packets that were corrupted on reception on the MAV)
477 // errors_count1 Autopilot-specific errors
479 // errors_count2 Autopilot-specific errors
481 // errors_count3 Autopilot-specific errors
483 // errors_count4 Autopilot-specific errors
486 mavlinkSendMessage();
489 void mavlinkSendRCChannelsAndRSSI(void)
491 #define GET_CHANNEL_VALUE(x) ((rxRuntimeConfig.channelCount >= (x + 1)) ? rxGetChannelValue(x) : 0)
492 mavlink_msg_rc_channels_raw_pack(mavSystemId, mavComponentId, &mavSendMsg,
493 // time_boot_ms Timestamp (milliseconds since system boot)
494 millis(),
495 // port Servo output port (set of 8 outputs = 1 port). Most MAVs will just use one, but this allows to encode more than 8 servos.
497 // chan1_raw RC channel 1 value, in microseconds
498 GET_CHANNEL_VALUE(0),
499 // chan2_raw RC channel 2 value, in microseconds
500 GET_CHANNEL_VALUE(1),
501 // chan3_raw RC channel 3 value, in microseconds
502 GET_CHANNEL_VALUE(2),
503 // chan4_raw RC channel 4 value, in microseconds
504 GET_CHANNEL_VALUE(3),
505 // chan5_raw RC channel 5 value, in microseconds
506 GET_CHANNEL_VALUE(4),
507 // chan6_raw RC channel 6 value, in microseconds
508 GET_CHANNEL_VALUE(5),
509 // chan7_raw RC channel 7 value, in microseconds
510 GET_CHANNEL_VALUE(6),
511 // chan8_raw RC channel 8 value, in microseconds
512 GET_CHANNEL_VALUE(7),
513 // rssi Receive signal strength indicator, 0: 0%, 254: 100%
514 //https://github.com/mavlink/mavlink/issues/1027
515 scaleRange(getRSSI(), 0, 1023, 0, 254));
516 #undef GET_CHANNEL_VALUE
518 mavlinkSendMessage();
521 #if defined(USE_GPS)
522 void mavlinkSendPosition(timeUs_t currentTimeUs)
524 uint8_t gpsFixType = 0;
526 if (!sensors(SENSOR_GPS))
527 return;
529 if (gpsSol.fixType == GPS_NO_FIX)
530 gpsFixType = 1;
531 else if (gpsSol.fixType == GPS_FIX_2D)
532 gpsFixType = 2;
533 else if (gpsSol.fixType == GPS_FIX_3D)
534 gpsFixType = 3;
536 mavlink_msg_gps_raw_int_pack(mavSystemId, mavComponentId, &mavSendMsg,
537 // time_usec Timestamp (microseconds since UNIX epoch or microseconds since system boot)
538 currentTimeUs,
539 // fix_type 0-1: no fix, 2: 2D fix, 3: 3D fix. Some applications will not use the value of this field unless it is at least two, so always correctly fill in the fix.
540 gpsFixType,
541 // lat Latitude in 1E7 degrees
542 gpsSol.llh.lat,
543 // lon Longitude in 1E7 degrees
544 gpsSol.llh.lon,
545 // alt Altitude in 1E3 meters (millimeters) above MSL
546 gpsSol.llh.alt * 10,
547 // eph GPS HDOP horizontal dilution of position in cm (m*100). If unknown, set to: 65535
548 gpsSol.eph,
549 // epv GPS VDOP horizontal dilution of position in cm (m*100). If unknown, set to: 65535
550 gpsSol.epv,
551 // vel GPS ground speed (m/s * 100). If unknown, set to: 65535
552 gpsSol.groundSpeed,
553 // cog Course over ground (NOT heading, but direction of movement) in degrees * 100, 0.0..359.99 degrees. If unknown, set to: 65535
554 gpsSol.groundCourse * 10,
555 // satellites_visible Number of satellites visible. If unknown, set to 255
556 gpsSol.numSat,
557 // alt_ellipsoid Altitude (above WGS84, EGM96 ellipsoid). Positive for up
559 // h_acc Position uncertainty in mm,
560 gpsSol.eph * 10,
561 // v_acc Altitude uncertainty in mm,
562 gpsSol.epv * 10,
563 // vel_acc Speed uncertainty in mm (??)
565 // hdg_acc Heading uncertainty in degE5
567 // yaw Yaw in earth frame from north. Use 0 if this GPS does not provide yaw. Use 65535 if this GPS is configured to provide yaw and is currently unable to provide it. Use 36000 for north.
570 mavlinkSendMessage();
572 // Global position
573 mavlink_msg_global_position_int_pack(mavSystemId, mavComponentId, &mavSendMsg,
574 // time_usec Timestamp (microseconds since UNIX epoch or microseconds since system boot)
575 currentTimeUs,
576 // lat Latitude in 1E7 degrees
577 gpsSol.llh.lat,
578 // lon Longitude in 1E7 degrees
579 gpsSol.llh.lon,
580 // alt Altitude in 1E3 meters (millimeters) above MSL
581 gpsSol.llh.alt * 10,
582 // relative_alt Altitude above ground in meters, expressed as * 1000 (millimeters)
583 getEstimatedActualPosition(Z) * 10,
584 // [cm/s] Ground X Speed (Latitude, positive north)
585 getEstimatedActualVelocity(X),
586 // [cm/s] Ground Y Speed (Longitude, positive east)
587 getEstimatedActualVelocity(Y),
588 // [cm/s] Ground Z Speed (Altitude, positive down)
589 getEstimatedActualVelocity(Z),
590 // [cdeg] Vehicle heading (yaw angle) (0.0..359.99 degrees, 0=north)
591 DECIDEGREES_TO_CENTIDEGREES(attitude.values.yaw)
594 mavlinkSendMessage();
596 mavlink_msg_gps_global_origin_pack(mavSystemId, mavComponentId, &mavSendMsg,
597 // latitude Latitude (WGS84), expressed as * 1E7
598 GPS_home.lat,
599 // longitude Longitude (WGS84), expressed as * 1E7
600 GPS_home.lon,
601 // altitude Altitude(WGS84), expressed as * 1000
602 GPS_home.alt * 10, // FIXME
603 // time_usec Timestamp (microseconds since system boot)
604 // Use millis() * 1000 as micros() will overflow after 1.19 hours.
605 ((uint64_t) millis()) * 1000);
607 mavlinkSendMessage();
609 #endif
611 void mavlinkSendAttitude(void)
613 mavlink_msg_attitude_pack(mavSystemId, mavComponentId, &mavSendMsg,
614 // time_boot_ms Timestamp (milliseconds since system boot)
615 millis(),
616 // roll Roll angle (rad)
617 RADIANS_TO_MAVLINK_RANGE(DECIDEGREES_TO_RADIANS(attitude.values.roll)),
618 // pitch Pitch angle (rad)
619 RADIANS_TO_MAVLINK_RANGE(DECIDEGREES_TO_RADIANS(-attitude.values.pitch)),
620 // yaw Yaw angle (rad)
621 RADIANS_TO_MAVLINK_RANGE(DECIDEGREES_TO_RADIANS(attitude.values.yaw)),
622 // rollspeed Roll angular speed (rad/s)
623 gyro.gyroADCf[FD_ROLL],
624 // pitchspeed Pitch angular speed (rad/s)
625 gyro.gyroADCf[FD_PITCH],
626 // yawspeed Yaw angular speed (rad/s)
627 gyro.gyroADCf[FD_YAW]);
629 mavlinkSendMessage();
632 void mavlinkSendHUDAndHeartbeat(void)
634 float mavAltitude = 0;
635 float mavGroundSpeed = 0;
636 float mavAirSpeed = 0;
637 float mavClimbRate = 0;
639 #if defined(USE_GPS)
640 // use ground speed if source available
641 if (sensors(SENSOR_GPS)) {
642 mavGroundSpeed = gpsSol.groundSpeed / 100.0f;
644 #endif
646 #if defined(USE_PITOT)
647 if (sensors(SENSOR_PITOT)) {
648 mavAirSpeed = getAirspeedEstimate() / 100.0f;
650 #endif
652 // select best source for altitude
653 mavAltitude = getEstimatedActualPosition(Z) / 100.0f;
654 mavClimbRate = getEstimatedActualVelocity(Z) / 100.0f;
656 int16_t thr = getThrottlePercent();
657 mavlink_msg_vfr_hud_pack(mavSystemId, mavComponentId, &mavSendMsg,
658 // airspeed Current airspeed in m/s
659 mavAirSpeed,
660 // groundspeed Current ground speed in m/s
661 mavGroundSpeed,
662 // heading Current heading in degrees, in compass units (0..360, 0=north)
663 DECIDEGREES_TO_DEGREES(attitude.values.yaw),
664 // throttle Current throttle setting in integer percent, 0 to 100
665 thr,
666 // alt Current altitude (MSL), in meters, if we have surface or baro use them, otherwise use GPS (less accurate)
667 mavAltitude,
668 // climb Current climb rate in meters/second
669 mavClimbRate);
671 mavlinkSendMessage();
674 uint8_t mavModes = MAV_MODE_FLAG_MANUAL_INPUT_ENABLED | MAV_MODE_FLAG_CUSTOM_MODE_ENABLED;
675 if (ARMING_FLAG(ARMED))
676 mavModes |= MAV_MODE_FLAG_SAFETY_ARMED;
678 uint8_t mavSystemType;
679 switch (mixerConfig()->platformType)
681 case PLATFORM_MULTIROTOR:
682 mavSystemType = MAV_TYPE_QUADROTOR;
683 break;
684 case PLATFORM_TRICOPTER:
685 mavSystemType = MAV_TYPE_TRICOPTER;
686 break;
687 case PLATFORM_AIRPLANE:
688 mavSystemType = MAV_TYPE_FIXED_WING;
689 break;
690 case PLATFORM_ROVER:
691 mavSystemType = MAV_TYPE_GROUND_ROVER;
692 break;
693 case PLATFORM_BOAT:
694 mavSystemType = MAV_TYPE_SURFACE_BOAT;
695 break;
696 case PLATFORM_HELICOPTER:
697 mavSystemType = MAV_TYPE_HELICOPTER;
698 break;
699 default:
700 mavSystemType = MAV_TYPE_GENERIC;
701 break;
704 flightModeForTelemetry_e flm = getFlightModeForTelemetry();
705 uint8_t mavCustomMode;
707 if (STATE(FIXED_WING_LEGACY)) {
708 mavCustomMode = (uint8_t)inavToArduPlaneMap(flm);
710 else {
711 mavCustomMode = (uint8_t)inavToArduCopterMap(flm);
714 if (flm != FLM_MANUAL) {
715 mavModes |= MAV_MODE_FLAG_STABILIZE_ENABLED;
717 if (flm == FLM_POSITION_HOLD || flm == FLM_RTH || flm == FLM_MISSION) {
718 mavModes |= MAV_MODE_FLAG_GUIDED_ENABLED;
721 uint8_t mavSystemState = 0;
722 if (ARMING_FLAG(ARMED)) {
723 if (failsafeIsActive()) {
724 mavSystemState = MAV_STATE_CRITICAL;
726 else {
727 mavSystemState = MAV_STATE_ACTIVE;
730 else if (areSensorsCalibrating()) {
731 mavSystemState = MAV_STATE_CALIBRATING;
733 else {
734 mavSystemState = MAV_STATE_STANDBY;
737 mavlink_msg_heartbeat_pack(mavSystemId, mavComponentId, &mavSendMsg,
738 // type Type of the MAV (quadrotor, helicopter, etc., up to 15 types, defined in MAV_TYPE ENUM)
739 mavSystemType,
740 // autopilot Autopilot type / class. defined in MAV_AUTOPILOT ENUM
741 MAV_AUTOPILOT_GENERIC,
742 // base_mode System mode bitfield, see MAV_MODE_FLAGS ENUM in mavlink/include/mavlink_types.h
743 mavModes,
744 // custom_mode A bitfield for use for autopilot-specific flags.
745 mavCustomMode,
746 // system_status System status flag, see MAV_STATE ENUM
747 mavSystemState);
749 mavlinkSendMessage();
752 void mavlinkSendBatteryTemperatureStatusText(void)
754 uint16_t batteryVoltages[MAVLINK_MSG_BATTERY_STATUS_FIELD_VOLTAGES_LEN];
755 uint16_t batteryVoltagesExt[MAVLINK_MSG_BATTERY_STATUS_FIELD_VOLTAGES_EXT_LEN];
756 memset(batteryVoltages, UINT16_MAX, sizeof(batteryVoltages));
757 memset(batteryVoltagesExt, 0, sizeof(batteryVoltagesExt));
758 if (feature(FEATURE_VBAT)) {
759 uint8_t batteryCellCount = getBatteryCellCount();
760 if (batteryCellCount > 0) {
761 for (int cell=0; cell < batteryCellCount && cell < MAVLINK_MSG_BATTERY_STATUS_FIELD_VOLTAGES_LEN + MAVLINK_MSG_BATTERY_STATUS_FIELD_VOLTAGES_EXT_LEN; cell++) {
762 if (cell < MAVLINK_MSG_BATTERY_STATUS_FIELD_VOLTAGES_LEN) {
763 batteryVoltages[cell] = getBatteryAverageCellVoltage() * 10;
764 } else {
765 batteryVoltagesExt[cell-MAVLINK_MSG_BATTERY_STATUS_FIELD_VOLTAGES_LEN] = getBatteryAverageCellVoltage() * 10;
769 else {
770 batteryVoltages[0] = getBatteryVoltage() * 10;
773 else {
774 batteryVoltages[0] = 0;
777 mavlink_msg_battery_status_pack(mavSystemId, mavComponentId, &mavSendMsg,
778 // id Battery ID
780 // battery_function Function of the battery
781 MAV_BATTERY_FUNCTION_UNKNOWN,
782 // type Type (chemistry) of the battery
783 MAV_BATTERY_TYPE_UNKNOWN,
784 // temperature Temperature of the battery in centi-degrees celsius. INT16_MAX for unknown temperature
785 INT16_MAX,
786 // voltages Battery voltage of cells, in millivolts (1 = 1 millivolt). Cells above the valid cell count for this battery should have the UINT16_MAX value.
787 batteryVoltages,
788 // current_battery Battery current, in 10*milliamperes (1 = 10 milliampere), -1: autopilot does not measure the current
789 isAmperageConfigured() ? getAmperage() : -1,
790 // current_consumed Consumed charge, in milliampere hours (1 = 1 mAh), -1: autopilot does not provide mAh consumption estimate
791 isAmperageConfigured() ? getMAhDrawn() : -1,
792 // energy_consumed Consumed energy, in 100*Joules (intergrated U*I*dt) (1 = 100 Joule), -1: autopilot does not provide energy consumption estimate
793 isAmperageConfigured() ? getMWhDrawn()*36 : -1,
794 // battery_remaining Remaining battery energy: (0%: 0, 100%: 100), -1: autopilot does not estimate the remaining battery);
795 feature(FEATURE_VBAT) ? calculateBatteryPercentage() : -1,
796 // time_remaining Remaining battery time, 0: autopilot does not provide remaining battery time estimate
797 0, // TODO this could easily be implemented
798 // charge_state State for extent of discharge, provided by autopilot for warning or external reactions
800 // voltages_ext Battery voltages for cells 11 to 14. Cells above the valid cell count for this battery should have a value of 0, where zero indicates not supported (note, this is different than for the voltages field and allows empty byte truncation). If the measured value is 0 then 1 should be sent instead.
801 batteryVoltagesExt,
802 // mode Battery mode. Default (0) is that battery mode reporting is not supported or battery is in normal-use mode.
804 // fault_bitmask Fault/health indications. These should be set when charge_state is MAV_BATTERY_CHARGE_STATE_FAILED or MAV_BATTERY_CHARGE_STATE_UNHEALTHY (if not, fault reporting is not supported).
807 mavlinkSendMessage();
810 int16_t temperature;
811 sensors(SENSOR_BARO) ? getBaroTemperature(&temperature) : getIMUTemperature(&temperature);
812 mavlink_msg_scaled_pressure_pack(mavSystemId, mavComponentId, &mavSendMsg,
813 millis(),
816 temperature * 10,
819 mavlinkSendMessage();
822 // FIXME - Status text is limited to boards with USE_OSD
823 #ifdef USE_OSD
824 char buff[MAVLINK_MSG_STATUSTEXT_FIELD_TEXT_LEN] = {" "};
825 textAttributes_t elemAttr = osdGetSystemMessage(buff, sizeof(buff), false);
826 if (buff[0] != SYM_BLANK) {
827 MAV_SEVERITY severity = MAV_SEVERITY_NOTICE;
828 if (TEXT_ATTRIBUTES_HAVE_BLINK(elemAttr)) {
829 severity = MAV_SEVERITY_CRITICAL;
830 } else if TEXT_ATTRIBUTES_HAVE_INVERTED(elemAttr) {
831 severity = MAV_SEVERITY_WARNING;
834 mavlink_msg_statustext_pack(mavSystemId, mavComponentId, &mavSendMsg,
835 (uint8_t)severity,
836 buff,
840 mavlinkSendMessage();
842 #endif
847 void processMAVLinkTelemetry(timeUs_t currentTimeUs)
849 // is executed @ TELEMETRY_MAVLINK_MAXRATE rate
850 if (mavlinkStreamTrigger(MAV_DATA_STREAM_EXTENDED_STATUS)) {
851 mavlinkSendSystemStatus();
854 if (mavlinkStreamTrigger(MAV_DATA_STREAM_RC_CHANNELS)) {
855 mavlinkSendRCChannelsAndRSSI();
858 #ifdef USE_GPS
859 if (mavlinkStreamTrigger(MAV_DATA_STREAM_POSITION)) {
860 mavlinkSendPosition(currentTimeUs);
862 #endif
864 if (mavlinkStreamTrigger(MAV_DATA_STREAM_EXTRA1)) {
865 mavlinkSendAttitude();
868 if (mavlinkStreamTrigger(MAV_DATA_STREAM_EXTRA2)) {
869 mavlinkSendHUDAndHeartbeat();
872 if (mavlinkStreamTrigger(MAV_DATA_STREAM_EXTRA3)) {
873 mavlinkSendBatteryTemperatureStatusText();
878 static bool handleIncoming_MISSION_CLEAR_ALL(void)
880 mavlink_mission_clear_all_t msg;
881 mavlink_msg_mission_clear_all_decode(&mavRecvMsg, &msg);
883 // Check if this message is for us
884 if (msg.target_system == mavSystemId) {
885 resetWaypointList();
886 mavlink_msg_mission_ack_pack(mavSystemId, mavComponentId, &mavSendMsg, mavRecvMsg.sysid, mavRecvMsg.compid, MAV_MISSION_ACCEPTED, MAV_MISSION_TYPE_MISSION);
887 mavlinkSendMessage();
888 return true;
891 return false;
894 // Static state for MISSION UPLOAD transaction (starting with MISSION_COUNT)
895 static int incomingMissionWpCount = 0;
896 static int incomingMissionWpSequence = 0;
898 static bool handleIncoming_MISSION_COUNT(void)
900 mavlink_mission_count_t msg;
901 mavlink_msg_mission_count_decode(&mavRecvMsg, &msg);
903 // Check if this message is for us
904 if (msg.target_system == mavSystemId) {
905 if (msg.count <= NAV_MAX_WAYPOINTS) {
906 incomingMissionWpCount = msg.count; // We need to know how many items to request
907 incomingMissionWpSequence = 0;
908 mavlink_msg_mission_request_pack(mavSystemId, mavComponentId, &mavSendMsg, mavRecvMsg.sysid, mavRecvMsg.compid, incomingMissionWpSequence, MAV_MISSION_TYPE_MISSION);
909 mavlinkSendMessage();
910 return true;
912 else if (ARMING_FLAG(ARMED)) {
913 mavlink_msg_mission_ack_pack(mavSystemId, mavComponentId, &mavSendMsg, mavRecvMsg.sysid, mavRecvMsg.compid, MAV_MISSION_ERROR, MAV_MISSION_TYPE_MISSION);
914 mavlinkSendMessage();
915 return true;
917 else {
918 mavlink_msg_mission_ack_pack(mavSystemId, mavComponentId, &mavSendMsg, mavRecvMsg.sysid, mavRecvMsg.compid, MAV_MISSION_NO_SPACE, MAV_MISSION_TYPE_MISSION);
919 mavlinkSendMessage();
920 return true;
924 return false;
927 static bool handleIncoming_MISSION_ITEM(void)
929 mavlink_mission_item_t msg;
930 mavlink_msg_mission_item_decode(&mavRecvMsg, &msg);
932 // Check if this message is for us
933 if (msg.target_system == mavSystemId) {
934 // Check supported values first
935 if (ARMING_FLAG(ARMED)) {
936 mavlink_msg_mission_ack_pack(mavSystemId, mavComponentId, &mavSendMsg, mavRecvMsg.sysid, mavRecvMsg.compid, MAV_MISSION_ERROR, MAV_MISSION_TYPE_MISSION);
937 mavlinkSendMessage();
938 return true;
941 if ((msg.autocontinue == 0) || (msg.command != MAV_CMD_NAV_WAYPOINT && msg.command != MAV_CMD_NAV_RETURN_TO_LAUNCH)) {
942 mavlink_msg_mission_ack_pack(mavSystemId, mavComponentId, &mavSendMsg, mavRecvMsg.sysid, mavRecvMsg.compid, MAV_MISSION_UNSUPPORTED, MAV_MISSION_TYPE_MISSION);
943 mavlinkSendMessage();
944 return true;
947 if ((msg.frame != MAV_FRAME_GLOBAL_RELATIVE_ALT) && !(msg.frame == MAV_FRAME_MISSION && msg.command == MAV_CMD_NAV_RETURN_TO_LAUNCH)) {
948 mavlink_msg_mission_ack_pack(mavSystemId, mavComponentId, &mavSendMsg, mavRecvMsg.sysid, mavRecvMsg.compid, MAV_MISSION_UNSUPPORTED_FRAME, MAV_MISSION_TYPE_MISSION);
949 mavlinkSendMessage();
950 return true;
953 if (msg.seq == incomingMissionWpSequence) {
954 incomingMissionWpSequence++;
956 navWaypoint_t wp;
957 wp.action = (msg.command == MAV_CMD_NAV_RETURN_TO_LAUNCH) ? NAV_WP_ACTION_RTH : NAV_WP_ACTION_WAYPOINT;
958 wp.lat = (int32_t)(msg.x * 1e7f);
959 wp.lon = (int32_t)(msg.y * 1e7f);
960 wp.alt = msg.z * 100.0f;
961 wp.p1 = 0;
962 wp.p2 = 0;
963 wp.p3 = 0;
964 wp.flag = (incomingMissionWpSequence >= incomingMissionWpCount) ? NAV_WP_FLAG_LAST : 0;
966 setWaypoint(incomingMissionWpSequence, &wp);
968 if (incomingMissionWpSequence >= incomingMissionWpCount) {
969 if (isWaypointListValid()) {
970 mavlink_msg_mission_ack_pack(mavSystemId, mavComponentId, &mavSendMsg, mavRecvMsg.sysid, mavRecvMsg.compid, MAV_MISSION_ACCEPTED, MAV_MISSION_TYPE_MISSION);
971 mavlinkSendMessage();
973 else {
974 mavlink_msg_mission_ack_pack(mavSystemId, mavComponentId, &mavSendMsg, mavRecvMsg.sysid, mavRecvMsg.compid, MAV_MISSION_INVALID, MAV_MISSION_TYPE_MISSION);
975 mavlinkSendMessage();
978 else {
979 mavlink_msg_mission_request_pack(mavSystemId, mavComponentId, &mavSendMsg, mavRecvMsg.sysid, mavRecvMsg.compid, incomingMissionWpSequence, MAV_MISSION_TYPE_MISSION);
980 mavlinkSendMessage();
983 else {
984 // Wrong sequence number received
985 mavlink_msg_mission_ack_pack(mavSystemId, mavComponentId, &mavSendMsg, mavRecvMsg.sysid, mavRecvMsg.compid, MAV_MISSION_INVALID_SEQUENCE, MAV_MISSION_TYPE_MISSION);
986 mavlinkSendMessage();
989 return true;
992 return false;
995 static bool handleIncoming_MISSION_REQUEST_LIST(void)
997 mavlink_mission_request_list_t msg;
998 mavlink_msg_mission_request_list_decode(&mavRecvMsg, &msg);
1000 // Check if this message is for us
1001 if (msg.target_system == mavSystemId) {
1002 mavlink_msg_mission_count_pack(mavSystemId, mavComponentId, &mavSendMsg, mavRecvMsg.sysid, mavRecvMsg.compid, getWaypointCount(), MAV_MISSION_TYPE_MISSION);
1003 mavlinkSendMessage();
1004 return true;
1007 return false;
1010 static bool handleIncoming_MISSION_REQUEST(void)
1012 mavlink_mission_request_t msg;
1013 mavlink_msg_mission_request_decode(&mavRecvMsg, &msg);
1015 // Check if this message is for us
1016 if (msg.target_system == mavSystemId) {
1017 int wpCount = getWaypointCount();
1019 if (msg.seq < wpCount) {
1020 navWaypoint_t wp;
1021 getWaypoint(msg.seq + 1, &wp);
1023 mavlink_msg_mission_item_pack(mavSystemId, mavComponentId, &mavSendMsg, mavRecvMsg.sysid, mavRecvMsg.compid,
1024 msg.seq,
1025 wp.action == NAV_WP_ACTION_RTH ? MAV_FRAME_MISSION : MAV_FRAME_GLOBAL_RELATIVE_ALT,
1026 wp.action == NAV_WP_ACTION_RTH ? MAV_CMD_NAV_RETURN_TO_LAUNCH : MAV_CMD_NAV_WAYPOINT,
1029 0, 0, 0, 0,
1030 wp.lat / 1e7f,
1031 wp.lon / 1e7f,
1032 wp.alt / 100.0f,
1033 MAV_MISSION_TYPE_MISSION);
1034 mavlinkSendMessage();
1036 else {
1037 mavlink_msg_mission_ack_pack(mavSystemId, mavComponentId, &mavSendMsg, mavRecvMsg.sysid, mavRecvMsg.compid, MAV_MISSION_INVALID_SEQUENCE, MAV_MISSION_TYPE_MISSION);
1038 mavlinkSendMessage();
1041 return true;
1044 return false;
1047 static bool handleIncoming_RC_CHANNELS_OVERRIDE(void) {
1048 mavlink_rc_channels_override_t msg;
1049 mavlink_msg_rc_channels_override_decode(&mavRecvMsg, &msg);
1050 // Don't check system ID because it's not configurable with systems like Crossfire
1051 mavlinkRxHandleMessage(&msg);
1052 return true;
1055 static bool processMAVLinkIncomingTelemetry(void)
1057 while (serialRxBytesWaiting(mavlinkPort) > 0) {
1058 // Limit handling to one message per cycle
1059 char c = serialRead(mavlinkPort);
1060 uint8_t result = mavlink_parse_char(0, c, &mavRecvMsg, &mavRecvStatus);
1061 if (result == MAVLINK_FRAMING_OK) {
1062 switch (mavRecvMsg.msgid) {
1063 case MAVLINK_MSG_ID_HEARTBEAT:
1064 break;
1065 case MAVLINK_MSG_ID_MISSION_CLEAR_ALL:
1066 return handleIncoming_MISSION_CLEAR_ALL();
1067 case MAVLINK_MSG_ID_MISSION_COUNT:
1068 return handleIncoming_MISSION_COUNT();
1069 case MAVLINK_MSG_ID_MISSION_ITEM:
1070 return handleIncoming_MISSION_ITEM();
1071 case MAVLINK_MSG_ID_MISSION_REQUEST_LIST:
1072 return handleIncoming_MISSION_REQUEST_LIST();
1073 case MAVLINK_MSG_ID_MISSION_REQUEST:
1074 return handleIncoming_MISSION_REQUEST();
1075 case MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE:
1076 return handleIncoming_RC_CHANNELS_OVERRIDE();
1077 default:
1078 return false;
1083 return false;
1086 void handleMAVLinkTelemetry(timeUs_t currentTimeUs)
1088 static bool incomingRequestServed;
1090 if (!mavlinkTelemetryEnabled) {
1091 return;
1094 if (!mavlinkPort) {
1095 return;
1098 // If we did serve data on incoming request - skip next scheduled messages batch to avoid link clogging
1099 if (processMAVLinkIncomingTelemetry()) {
1100 incomingRequestServed = true;
1103 if ((currentTimeUs - lastMavlinkMessage) >= TELEMETRY_MAVLINK_DELAY) {
1104 // Only process scheduled data if we didn't serve any incoming request this cycle
1105 if (!incomingRequestServed ||
1107 (rxConfig()->receiverType == RX_TYPE_SERIAL) &&
1108 (rxConfig()->serialrx_provider == SERIALRX_MAVLINK) &&
1109 !tristateWithDefaultOnIsActive(rxConfig()->halfDuplex)
1112 processMAVLinkTelemetry(currentTimeUs);
1114 lastMavlinkMessage = currentTimeUs;
1115 incomingRequestServed = false;
1119 #endif