2 * This file is part of Cleanflight and Betaflight.
4 * Cleanflight and Betaflight are free software. You can redistribute
5 * this software and/or modify this software under the terms of the
6 * GNU General Public License as published by the Free Software
7 * Foundation, either version 3 of the License, or (at your option)
10 * Cleanflight and Betaflight are distributed in the hope that they
11 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this software.
18 * If not, see <http://www.gnu.org/licenses/>.
22 * Based on https://github.com/ExpressLRS/ExpressLRS
23 * Thanks to AlessandroAU, original creator of the ExpressLRS project.
26 * Phobos- - Original port.
32 #ifdef USE_RX_EXPRESSLRS
34 #include "config/feature.h"
35 #include "fc/runtime_config.h"
37 #include "msp/msp_protocol.h"
39 #include "rx/crsf_protocol.h"
40 #include "rx/expresslrs_telemetry.h"
42 #include "telemetry/crsf.h"
43 #include "telemetry/telemetry.h"
45 #include "sensors/battery.h"
46 #include "sensors/sensors.h"
48 static uint8_t tlmBuffer
[CRSF_FRAME_SIZE_MAX
];
51 CRSF_FRAME_GPS_INDEX
= 0,
52 CRSF_FRAME_BATTERY_SENSOR_INDEX
,
53 CRSF_FRAME_ATTITUDE_INDEX
,
54 CRSF_FRAME_FLIGHT_MODE_INDEX
,
55 CRSF_FRAME_PAYLOAD_TYPES_COUNT
//should be last
58 static crsfFrameType_e payloadTypes
[] = {
60 CRSF_FRAMETYPE_BATTERY_SENSOR
,
61 CRSF_FRAMETYPE_ATTITUDE
,
62 CRSF_FRAMETYPE_FLIGHT_MODE
65 STATIC_UNIT_TESTED
uint8_t tlmSensors
= 0;
66 STATIC_UNIT_TESTED
uint8_t currentPayloadIndex
;
69 static uint8_t length
;
70 static uint8_t bytesPerCall
;
71 static uint8_t currentOffset
;
72 static uint8_t currentPackage
;
73 static bool waitUntilTelemetryConfirm
;
74 static uint16_t waitCount
;
75 static uint16_t maxWaitCount
;
76 static volatile stubbornSenderState_e senderState
;
78 static void telemetrySenderResetState(void)
84 waitUntilTelemetryConfirm
= true;
86 // 80 corresponds to UpdateTelemetryRate(ANY, 2, 1), which is what the TX uses in boost mode
88 senderState
= ELRS_SENDER_IDLE
;
93 * Queues a message to send, will abort the current message if one is currently being transmitted
95 void setTelemetryDataToTransmit(const uint8_t lengthToTransmit
, uint8_t* dataToTransmit
, const uint8_t bpc
)
97 if (lengthToTransmit
/ bpc
>= ELRS_TELEMETRY_MAX_PACKAGES
) {
101 length
= lengthToTransmit
;
102 data
= dataToTransmit
;
107 senderState
= (senderState
== ELRS_SENDER_IDLE
) ? ELRS_SENDING
: ELRS_RESYNC_THEN_SEND
;
110 bool isTelemetrySenderActive(void)
112 return senderState
!= ELRS_SENDER_IDLE
;
115 void getCurrentTelemetryPayload(uint8_t *packageIndex
, uint8_t *count
, uint8_t **currentData
)
117 switch (senderState
) {
119 case ELRS_RESYNC_THEN_SEND
:
120 *packageIndex
= ELRS_TELEMETRY_MAX_PACKAGES
;
125 *currentData
= data
+ currentOffset
;
126 *packageIndex
= currentPackage
;
127 if (bytesPerCall
> 1) {
128 if (currentOffset
+ bytesPerCall
<= length
) {
129 *count
= bytesPerCall
;
131 *count
= length
- currentOffset
;
144 void confirmCurrentTelemetryPayload(const bool telemetryConfirmValue
)
146 stubbornSenderState_e nextSenderState
= senderState
;
148 switch (senderState
) {
150 if (telemetryConfirmValue
!= waitUntilTelemetryConfirm
) {
152 if (waitCount
> maxWaitCount
) {
153 waitUntilTelemetryConfirm
= !telemetryConfirmValue
;
154 nextSenderState
= ELRS_RESYNC
;
159 currentOffset
+= bytesPerCall
;
161 waitUntilTelemetryConfirm
= !waitUntilTelemetryConfirm
;
164 if (currentOffset
>= length
) {
165 nextSenderState
= ELRS_WAIT_UNTIL_NEXT_CONFIRM
;
171 case ELRS_RESYNC_THEN_SEND
:
172 case ELRS_WAIT_UNTIL_NEXT_CONFIRM
:
173 if (telemetryConfirmValue
== waitUntilTelemetryConfirm
) {
174 nextSenderState
= (senderState
== ELRS_RESYNC_THEN_SEND
) ? ELRS_SENDING
: ELRS_SENDER_IDLE
;
175 waitUntilTelemetryConfirm
= !telemetryConfirmValue
;
176 } else if (senderState
== ELRS_WAIT_UNTIL_NEXT_CONFIRM
) { // switch to resync if tx does not confirm value fast enough
178 if (waitCount
> maxWaitCount
) {
179 waitUntilTelemetryConfirm
= !telemetryConfirmValue
;
180 nextSenderState
= ELRS_RESYNC
;
186 case ELRS_SENDER_IDLE
:
190 senderState
= nextSenderState
;
193 #ifdef USE_MSP_OVER_TELEMETRY
194 static uint8_t *mspData
;
195 static volatile bool finishedData
;
196 static volatile uint8_t mspLength
;
197 static volatile uint8_t mspBytesPerCall
;
198 static volatile uint8_t mspCurrentOffset
;
199 static volatile uint8_t mspCurrentPackage
;
200 static volatile bool mspConfirm
;
202 STATIC_UNIT_TESTED
volatile bool mspReplyPending
;
203 STATIC_UNIT_TESTED
volatile bool deviceInfoReplyPending
;
205 void mspReceiverResetState(void) {
208 mspCurrentOffset
= 0;
209 mspCurrentPackage
= 0;
212 mspReplyPending
= false;
213 deviceInfoReplyPending
= false;
216 bool getCurrentMspConfirm(void)
221 void setMspDataToReceive(const uint8_t maxLength
, uint8_t* dataToReceive
, const uint8_t bpc
)
223 mspLength
= maxLength
;
224 mspData
= dataToReceive
;
225 mspCurrentPackage
= 1;
226 mspCurrentOffset
= 0;
227 finishedData
= false;
228 mspBytesPerCall
= bpc
;
231 void receiveMspData(const uint8_t packageIndex
, const volatile uint8_t* receiveData
)
233 if (packageIndex
== 0 && mspCurrentPackage
> 1) {
235 mspConfirm
= !mspConfirm
;
239 if (packageIndex
== ELRS_MSP_MAX_PACKAGES
) {
240 mspConfirm
= !mspConfirm
;
241 mspCurrentPackage
= 1;
242 mspCurrentOffset
= 0;
243 finishedData
= false;
251 if (packageIndex
== mspCurrentPackage
) {
252 for (uint8_t i
= 0; i
< mspBytesPerCall
; i
++) {
253 mspData
[mspCurrentOffset
++] = *(receiveData
+ i
);
257 mspConfirm
= !mspConfirm
;
264 bool hasFinishedMspData(void)
269 void mspReceiverUnlock(void)
272 mspCurrentPackage
= 1;
273 mspCurrentOffset
= 0;
274 finishedData
= false;
278 static uint8_t mspFrameSize
= 0;
280 static void bufferMspResponse(uint8_t *payload
, const uint8_t payloadSize
)
282 mspFrameSize
= getCrsfMspFrame(tlmBuffer
, payload
, payloadSize
);
285 void processMspPacket(uint8_t *packet
)
288 case CRSF_FRAMETYPE_DEVICE_PING
:
289 deviceInfoReplyPending
= true;
291 case CRSF_FRAMETYPE_MSP_REQ
:
293 case CRSF_FRAMETYPE_MSP_WRITE
: //TODO: MSP_EEPROM_WRITE command is disabled.
294 if (packet
[ELRS_MSP_COMMAND_INDEX
] != MSP_EEPROM_WRITE
&& bufferCrsfMspFrame(&packet
[ELRS_MSP_PACKET_OFFSET
], CRSF_FRAME_RX_MSP_FRAME_SIZE
)) {
295 handleCrsfMspFrameBuffer(&bufferMspResponse
);
296 mspReplyPending
= true;
306 * Called when the telemetry ratio or air rate changes, calculate
307 * the new threshold for how many times the telemetryConfirmValue
308 * can be wrong in a row before giving up and going to RESYNC
310 void updateTelemetryRate(const uint16_t airRate
, const uint8_t tlmRatio
, const uint8_t tlmBurst
)
312 // consipicuously unused airRate parameter, the wait count is strictly based on number
313 // of packets, not time between the telemetry packets, or a wall clock timeout
315 // The expected number of packet periods between telemetry packets
316 uint32_t packsBetween
= tlmRatio
* (1 + tlmBurst
) / tlmBurst
;
317 maxWaitCount
= packsBetween
* ELRS_TELEMETRY_MAX_MISSED_PACKETS
;
320 void initTelemetry(void)
322 if (!featureIsEnabled(FEATURE_TELEMETRY
)) {
326 if (sensors(SENSOR_ACC
) && telemetryIsSensorEnabled(SENSOR_PITCH
| SENSOR_ROLL
| SENSOR_HEADING
)) {
327 tlmSensors
|= BIT(CRSF_FRAME_ATTITUDE_INDEX
);
329 if ((isBatteryVoltageConfigured() && telemetryIsSensorEnabled(SENSOR_VOLTAGE
))
330 || (isAmperageConfigured() && telemetryIsSensorEnabled(SENSOR_CURRENT
| SENSOR_FUEL
))) {
331 tlmSensors
|= BIT(CRSF_FRAME_BATTERY_SENSOR_INDEX
);
333 if (telemetryIsSensorEnabled(SENSOR_MODE
)) {
334 tlmSensors
|= BIT(CRSF_FRAME_FLIGHT_MODE_INDEX
);
337 if (featureIsEnabled(FEATURE_GPS
)
338 && telemetryIsSensorEnabled(SENSOR_ALTITUDE
| SENSOR_LAT_LONG
| SENSOR_GROUND_SPEED
| SENSOR_HEADING
)) {
339 tlmSensors
|= BIT(CRSF_FRAME_GPS_INDEX
);
343 telemetrySenderResetState();
344 #ifdef USE_MSP_OVER_TELEMETRY
345 mspReceiverResetState();
349 bool getNextTelemetryPayload(uint8_t *nextPayloadSize
, uint8_t **payloadData
)
351 #ifdef USE_MSP_OVER_TELEMETRY
352 if (deviceInfoReplyPending
) {
353 *nextPayloadSize
= getCrsfFrame(tlmBuffer
, CRSF_FRAMETYPE_DEVICE_INFO
);
354 *payloadData
= tlmBuffer
;
355 deviceInfoReplyPending
= false;
357 } else if (mspReplyPending
) {
358 *nextPayloadSize
= mspFrameSize
;
359 *payloadData
= tlmBuffer
;
360 mspReplyPending
= false;
364 if (tlmSensors
& BIT(currentPayloadIndex
)) {
365 *nextPayloadSize
= getCrsfFrame(tlmBuffer
, payloadTypes
[currentPayloadIndex
]);
366 *payloadData
= tlmBuffer
;
367 currentPayloadIndex
= (currentPayloadIndex
+ 1) % CRSF_FRAME_PAYLOAD_TYPES_COUNT
;
370 currentPayloadIndex
= (currentPayloadIndex
+ 1) % CRSF_FRAME_PAYLOAD_TYPES_COUNT
;
371 *nextPayloadSize
= 0;