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 "common/maths.h"
35 #include "config/feature.h"
36 #include "fc/runtime_config.h"
38 #include "msp/msp_protocol.h"
40 #include "rx/crsf_protocol.h"
41 #include "rx/expresslrs_telemetry.h"
43 #include "telemetry/crsf.h"
44 #include "telemetry/telemetry.h"
46 #include "sensors/battery.h"
47 #include "sensors/sensors.h"
49 static uint8_t tlmBuffer
[CRSF_FRAME_SIZE_MAX
];
52 CRSF_FRAME_GPS_INDEX
= 0,
53 CRSF_FRAME_BATTERY_SENSOR_INDEX
,
54 CRSF_FRAME_ATTITUDE_INDEX
,
55 CRSF_FRAME_FLIGHT_MODE_INDEX
,
56 CRSF_FRAME_PAYLOAD_TYPES_COUNT
//should be last
59 static crsfFrameType_e payloadTypes
[] = {
61 CRSF_FRAMETYPE_BATTERY_SENSOR
,
62 CRSF_FRAMETYPE_ATTITUDE
,
63 CRSF_FRAMETYPE_FLIGHT_MODE
66 STATIC_UNIT_TESTED
uint8_t tlmSensors
= 0;
67 STATIC_UNIT_TESTED
uint8_t currentPayloadIndex
;
69 static uint8_t *data
= NULL
;
70 static uint8_t length
= 0;
71 static uint8_t currentOffset
;
72 static uint8_t bytesLastPayload
;
73 static uint8_t currentPackage
;
74 static bool waitUntilTelemetryConfirm
;
75 static uint16_t waitCount
;
76 static uint16_t maxWaitCount
;
77 static volatile stubbornSenderState_e senderState
;
79 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
;
92 * Queues a message to send, will abort the current message if one is currently being transmitted
94 void setTelemetryDataToTransmit(const uint8_t lengthToTransmit
, uint8_t* dataToTransmit
)
96 length
= lengthToTransmit
;
97 data
= dataToTransmit
;
101 senderState
= (senderState
== ELRS_SENDER_IDLE
) ? ELRS_SENDING
: ELRS_RESYNC_THEN_SEND
;
104 bool isTelemetrySenderActive(void)
106 return senderState
!= ELRS_SENDER_IDLE
;
110 * Copy up to maxLen bytes from the current package to outData
113 uint8_t getCurrentTelemetryPayload(uint8_t *outData
)
115 uint8_t packageIndex
;
117 bytesLastPayload
= 0;
118 switch (senderState
) {
120 case ELRS_RESYNC_THEN_SEND
:
121 packageIndex
= ELRS_TELEMETRY_MAX_PACKAGES
;
124 bytesLastPayload
= MIN((uint8_t)(length
- currentOffset
), ELRS_TELEMETRY_BYTES_PER_CALL
);
125 // If this is the last data chunk, and there has been at least one other packet
126 // skip the blank packet needed for WAIT_UNTIL_NEXT_CONFIRM
127 if (currentPackage
> 1 && (currentOffset
+ bytesLastPayload
) >= length
) {
130 packageIndex
= currentPackage
;
132 memcpy(outData
, &data
[currentOffset
], bytesLastPayload
);
142 void confirmCurrentTelemetryPayload(const bool telemetryConfirmValue
)
144 stubbornSenderState_e nextSenderState
= senderState
;
146 switch (senderState
) {
148 if (telemetryConfirmValue
!= waitUntilTelemetryConfirm
) {
150 if (waitCount
> maxWaitCount
) {
151 waitUntilTelemetryConfirm
= !telemetryConfirmValue
;
152 nextSenderState
= ELRS_RESYNC
;
157 currentOffset
+= bytesLastPayload
;
158 if (currentOffset
>= length
) {
159 // A 0th packet is always requred so the reciver can
160 // differentiate a new send from a resend, if this is
161 // the first packet acked, send another, else IDLE
162 if (currentPackage
== 1) {
163 nextSenderState
= ELRS_WAIT_UNTIL_NEXT_CONFIRM
;
165 nextSenderState
= ELRS_SENDER_IDLE
;
170 waitUntilTelemetryConfirm
= !waitUntilTelemetryConfirm
;
175 case ELRS_RESYNC_THEN_SEND
:
176 case ELRS_WAIT_UNTIL_NEXT_CONFIRM
:
177 if (telemetryConfirmValue
== waitUntilTelemetryConfirm
) {
178 nextSenderState
= (senderState
== ELRS_RESYNC_THEN_SEND
) ? ELRS_SENDING
: ELRS_SENDER_IDLE
;
179 waitUntilTelemetryConfirm
= !telemetryConfirmValue
;
180 } else if (senderState
== ELRS_WAIT_UNTIL_NEXT_CONFIRM
) { // switch to resync if tx does not confirm value fast enough
182 if (waitCount
> maxWaitCount
) {
183 waitUntilTelemetryConfirm
= !telemetryConfirmValue
;
184 nextSenderState
= ELRS_RESYNC
;
190 case ELRS_SENDER_IDLE
:
194 senderState
= nextSenderState
;
197 #ifdef USE_MSP_OVER_TELEMETRY
198 static uint8_t *mspData
= NULL
;
199 static volatile bool finishedData
;
200 static volatile uint8_t mspLength
= 0;
201 static volatile uint8_t mspCurrentOffset
;
202 static volatile uint8_t mspCurrentPackage
;
203 static volatile bool mspConfirm
;
205 STATIC_UNIT_TESTED
volatile bool mspReplyPending
;
206 STATIC_UNIT_TESTED
volatile bool deviceInfoReplyPending
;
208 void mspReceiverResetState(void)
210 mspCurrentOffset
= 0;
211 mspCurrentPackage
= 1;
213 mspReplyPending
= false;
214 deviceInfoReplyPending
= false;
217 bool getCurrentMspConfirm(void)
222 void setMspDataToReceive(const uint8_t maxLength
, uint8_t* dataToReceive
)
224 mspLength
= maxLength
;
225 mspData
= dataToReceive
;
226 mspCurrentPackage
= 1;
227 mspCurrentOffset
= 0;
228 finishedData
= false;
231 void receiveMspData(const uint8_t packageIndex
, const volatile uint8_t* const receiveData
)
234 if (packageIndex
== ELRS_MSP_MAX_PACKAGES
) {
235 mspConfirm
= !mspConfirm
;
236 mspCurrentPackage
= 1;
237 mspCurrentOffset
= 0;
238 finishedData
= false;
246 bool acceptData
= false;
247 if (packageIndex
== 0 && mspCurrentPackage
> 1) {
248 // PackageIndex 0 (the final packet) can also contain data
251 } else if (packageIndex
== mspCurrentPackage
) {
256 if (acceptData
&& (receiveData
!= NULL
)) {
257 uint8_t len
= MIN((uint8_t)(mspLength
- mspCurrentOffset
), ELRS_MSP_BYTES_PER_CALL
);
258 memcpy(&mspData
[mspCurrentOffset
], (const uint8_t*) receiveData
, len
);
259 mspCurrentOffset
+= len
;
260 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
:
292 case CRSF_FRAMETYPE_MSP_WRITE
:
293 if (bufferCrsfMspFrame(&packet
[ELRS_MSP_PACKET_OFFSET
], CRSF_FRAME_RX_MSP_FRAME_SIZE
)) {
294 handleCrsfMspFrameBuffer(&bufferMspResponse
);
295 mspReplyPending
= true;
305 * Called when the telemetry ratio or air rate changes, calculate
306 * the new threshold for how many times the telemetryConfirmValue
307 * can be wrong in a row before giving up and going to RESYNC
309 void updateTelemetryRate(const uint16_t airRate
, const uint8_t tlmRatio
, const uint8_t tlmBurst
)
311 // consipicuously unused airRate parameter, the wait count is strictly based on number
312 // of packets, not time between the telemetry packets, or a wall clock timeout
314 // The expected number of packet periods between telemetry packets
315 uint32_t packsBetween
= tlmRatio
* (1 + tlmBurst
) / tlmBurst
;
316 maxWaitCount
= packsBetween
* ELRS_TELEMETRY_MAX_MISSED_PACKETS
;
319 void initTelemetry(void)
321 if (!featureIsEnabled(FEATURE_TELEMETRY
)) {
325 if (sensors(SENSOR_ACC
) && telemetryIsSensorEnabled(SENSOR_PITCH
| SENSOR_ROLL
| SENSOR_HEADING
)) {
326 tlmSensors
|= BIT(CRSF_FRAME_ATTITUDE_INDEX
);
328 if ((isBatteryVoltageConfigured() && telemetryIsSensorEnabled(SENSOR_VOLTAGE
))
329 || (isAmperageConfigured() && telemetryIsSensorEnabled(SENSOR_CURRENT
| SENSOR_FUEL
))) {
330 tlmSensors
|= BIT(CRSF_FRAME_BATTERY_SENSOR_INDEX
);
332 if (telemetryIsSensorEnabled(SENSOR_MODE
)) {
333 tlmSensors
|= BIT(CRSF_FRAME_FLIGHT_MODE_INDEX
);
336 if (featureIsEnabled(FEATURE_GPS
)
337 && telemetryIsSensorEnabled(SENSOR_ALTITUDE
| SENSOR_LAT_LONG
| SENSOR_GROUND_SPEED
| SENSOR_HEADING
)) {
338 tlmSensors
|= BIT(CRSF_FRAME_GPS_INDEX
);
342 telemetrySenderResetState();
343 #ifdef USE_MSP_OVER_TELEMETRY
344 mspReceiverResetState();
348 bool getNextTelemetryPayload(uint8_t *nextPayloadSize
, uint8_t **payloadData
)
350 #ifdef USE_MSP_OVER_TELEMETRY
351 if (deviceInfoReplyPending
) {
352 *nextPayloadSize
= getCrsfFrame(tlmBuffer
, CRSF_FRAMETYPE_DEVICE_INFO
);
353 *payloadData
= tlmBuffer
;
354 deviceInfoReplyPending
= false;
356 } else if (mspReplyPending
) {
357 *nextPayloadSize
= mspFrameSize
;
358 *payloadData
= tlmBuffer
;
359 mspReplyPending
= false;
363 if (tlmSensors
& BIT(currentPayloadIndex
)) {
364 *nextPayloadSize
= getCrsfFrame(tlmBuffer
, payloadTypes
[currentPayloadIndex
]);
365 *payloadData
= tlmBuffer
;
366 currentPayloadIndex
= (currentPayloadIndex
+ 1) % CRSF_FRAME_PAYLOAD_TYPES_COUNT
;
369 currentPayloadIndex
= (currentPayloadIndex
+ 1) % CRSF_FRAME_PAYLOAD_TYPES_COUNT
;
370 *nextPayloadSize
= 0;