2 * This file is part of ExpressLRS
3 * See https://github.com/AlessandroAU/ExpressLRS
5 * This file provides utilities for packing and unpacking the data to
6 * be sent over the radio link.
14 static_assert(sizeof(OTA_Packet4_s
) == OTA4_PACKET_SIZE
, "OTA4 packet stuct is invalid!");
15 static_assert(sizeof(OTA_Packet8_s
) == OTA8_PACKET_SIZE
, "OTA8 packet stuct is invalid!");
18 volatile uint8_t OtaNonce
;
19 uint16_t OtaCrcInitializer
;
20 OtaSwitchMode_e OtaSwitchModeCurrent
;
23 static Crc2Byte ota_crc
;
24 ValidatePacketCrc_t OtaValidatePacketCrc
;
25 GeneratePacketCrc_t OtaGeneratePacketCrc
;
27 void OtaUpdateCrcInitFromUid()
29 OtaCrcInitializer
= (UID
[4] << 8) | UID
[5];
30 OtaCrcInitializer
^= OTA_VERSION_ID
;
33 static inline uint8_t ICACHE_RAM_ATTR
HybridWideNonceToSwitchIndex(uint8_t const nonce
)
35 // Returns the sequence (0 to 7, then 0 to 7 rotated left by 1):
36 // 0, 1, 2, 3, 4, 5, 6, 7,
37 // 1, 2, 3, 4, 5, 6, 7, 0
38 // Because telemetry can occur on every 2, 4, 8, 16, 32, 64, 128th packet
39 // this makes sure each of the 8 values is sent at least once every 16 packets
40 // regardless of the TLM ratio
41 // Index 7 also can never fall on a telemetry slot
42 return ((nonce
& 0b111) + ((nonce
>> 3) & 0b1)) % 8;
45 #if TARGET_TX || defined(UNIT_TEST)
47 // Current ChannelData generator function being used by TX
48 PackChannelData_t OtaPackChannelData
;
49 #if defined(DEBUG_RCVR_LINKSTATS)
50 static uint32_t packetCnt
;
53 /******** Decimate 11bit to 10bit functions ********/
54 typedef uint32_t (*Decimate11to10_fn
)(uint32_t ch11bit
);
56 static uint32_t ICACHE_RAM_ATTR
Decimate11to10_Limit(uint32_t ch11bit
)
58 // Limit 10-bit result to the range CRSF_CHANNEL_VALUE_MIN/MAX
59 return CRSF_to_UINT10(constrain(ch11bit
, CRSF_CHANNEL_VALUE_MIN
, CRSF_CHANNEL_VALUE_MAX
));
62 static uint32_t ICACHE_RAM_ATTR
Decimate11to10_Div2(uint32_t ch11bit
)
64 // Simple divide-by-2 to discard the bit
69 * @brief: Pack 4x 11-bit channel array into 4x 10 bit channel struct
70 * @desc: Values are packed little-endianish such that bits A987654321 -> 87654321, 000000A9
71 * which is compatible with the 10-bit CRSF subset RC frame structure (0x17) in
72 * Betaflight, but depends on which decimate function is used if it is legacy or CRSFv3 10-bit
73 * destChannels4x10 must be zeroed before this call, the channels are ORed into it
75 static void ICACHE_RAM_ATTR
PackUInt11ToChannels4x10(uint32_t const * const src
, OTA_Channels_4x10
* const destChannels4x10
, Decimate11to10_fn decimate
)
77 const unsigned DEST_PRECISION
= 10; // number of bits for each dest, must be <SRC
78 uint8_t *dest
= (uint8_t *)destChannels4x10
;
80 unsigned destShift
= 0;
81 for (unsigned ch
=0; ch
<4; ++ch
)
83 // Convert to DEST_PRECISION value
84 unsigned chVal
= decimate(src
[ch
]);
86 // Put the low bits in any remaining dest capacity
87 *dest
++ |= chVal
<< destShift
;
89 // Shift the high bits down and place them into the next dest byte
90 unsigned srcBitsLeft
= DEST_PRECISION
- 8 + destShift
;
91 *dest
= chVal
>> (DEST_PRECISION
- srcBitsLeft
);
92 // Next dest should be shifted up by the bits consumed
93 // if destShift == 8 then everything should reset for another set
94 // but this code only expects to do the 4 channels -> 5 bytes evenly
95 destShift
= srcBitsLeft
;
99 static void ICACHE_RAM_ATTR
PackChannelDataHybridCommon(OTA_Packet4_s
* const ota4
, const uint32_t *channelData
)
101 ota4
->type
= PACKET_TYPE_RCDATA
;
102 #if defined(DEBUG_RCVR_LINKSTATS)
103 // Incremental packet counter for verification on the RX side, 32 bits shoved into CH1-CH4
104 ota4
->dbg_linkstats
.packetNum
= packetCnt
++;
106 // CRSF input is 11bit and OTA will carry only 10bit. Discard the Extended Limits (E.Limits)
107 // range and use the full 10bits to carry only 998us - 2012us
108 PackUInt11ToChannels4x10(&channelData
[0], &ota4
->rc
.ch
, &Decimate11to10_Limit
);
109 ota4
->rc
.ch4
= CRSF_to_BIT(channelData
[4]);
110 #endif /* !DEBUG_RCVR_LINKSTATS */
114 * Hybrid switches packet encoding for sending over the air
116 * Analog channels are reduced to 10 bits to allow for switch encoding
117 * Switch[0] is sent on every packet.
118 * A 3 bit switch index and 3-4 bit value is used to send the remaining switches
119 * in a round-robin fashion.
121 * Inputs: channelData, TelemetryStatus
122 * Outputs: OTA_Packet4_s, side-effects the sentSwitch value
124 // The next switch index to send, where 0=AUX2 and 6=AUX8
125 static uint8_t Hybrid8NextSwitchIndex
;
126 #if defined(UNIT_TEST)
127 void OtaSetHybrid8NextSwitchIndex(uint8_t idx
) { Hybrid8NextSwitchIndex
= idx
; }
129 void ICACHE_RAM_ATTR
GenerateChannelDataHybrid8(OTA_Packet_s
* const otaPktPtr
, const uint32_t *channelData
,
130 bool const TelemetryStatus
, uint8_t const tlmDenom
)
134 OTA_Packet4_s
* const ota4
= &otaPktPtr
->std
;
135 PackChannelDataHybridCommon(ota4
, channelData
);
137 // Actually send switchIndex - 1 in the packet, to shift down 1-7 (0b111) to 0-6 (0b110)
138 // If the two high bits are 0b11, the receiver knows it is the last switch and can use
139 // that bit to store data
140 uint8_t bitclearedSwitchIndex
= Hybrid8NextSwitchIndex
;
142 // AUX8 is High Resolution 16-pos (4-bit)
143 if (bitclearedSwitchIndex
== 6)
144 value
= CRSF_to_N(channelData
[6 + 1 + 4], 16);
146 value
= CRSF_to_SWITCH3b(channelData
[bitclearedSwitchIndex
+ 1 + 4]);
149 TelemetryStatus
<< 6 |
150 // tell the receiver which switch index this is
151 bitclearedSwitchIndex
<< 3 |
152 // include the switch value
155 // update the sent value
156 Hybrid8NextSwitchIndex
= (bitclearedSwitchIndex
+ 1) % 7;
160 * Return the OTA value respresentation of the switch contained in ChannelData
161 * Switches 1-6 (AUX2-AUX7) are 6 or 7 bit depending on the lowRes parameter
163 static uint8_t ICACHE_RAM_ATTR
HybridWideSwitchToOta(const uint32_t *channelData
, uint8_t const switchIdx
, bool const lowRes
)
165 uint16_t ch
= channelData
[switchIdx
+ 4];
166 uint8_t binCount
= (lowRes
) ? 64 : 128;
167 ch
= CRSF_to_N(ch
, binCount
);
169 return ch
& 0b111111; // 6-bit
171 return ch
& 0b1111111; // 7-bit
175 * HybridWide switches packet encoding for sending over the air
177 * Analog channels are reduced to 10 bits to allow for switch encoding
178 * Switch[0] is sent on every packet.
179 * A 6 or 7 bit switch value is used to send the remaining switches
180 * in a round-robin fashion.
182 * Inputs: cchannelData, TelemetryStatus
183 * Outputs: OTA_Packet4_s
185 void ICACHE_RAM_ATTR
GenerateChannelDataHybridWide(OTA_Packet_s
* const otaPktPtr
, const uint32_t *channelData
,
186 bool const TelemetryStatus
, uint8_t const tlmDenom
)
188 OTA_Packet4_s
* const ota4
= &otaPktPtr
->std
;
189 PackChannelDataHybridCommon(ota4
, channelData
);
191 uint8_t telemBit
= TelemetryStatus
<< 6;
192 uint8_t nextSwitchIndex
= HybridWideNonceToSwitchIndex(OtaNonce
);
194 // Using index 7 means the telemetry bit will always be sent in the packet
195 // preceding the RX's telemetry slot for all tlmDenom >= 8
196 // For more frequent telemetry rates, include the bit in every
197 // packet and degrade the value to 6-bit
198 // (technically we could squeeze 7-bits in for 2 channels with tlmDenom=4)
199 if (nextSwitchIndex
== 7)
201 value
= telemBit
| CRSF::LinkStatistics
.uplink_TX_Power
;
205 bool telemInEveryPacket
= (tlmDenom
> 1) && (tlmDenom
< 8);
206 value
= HybridWideSwitchToOta(channelData
, nextSwitchIndex
+ 1, telemInEveryPacket
);
207 if (telemInEveryPacket
)
211 ota4
->rc
.switches
= value
;
214 static void ICACHE_RAM_ATTR
GenerateChannelData8ch12ch(OTA_Packet8_s
* const ota8
, const uint32_t *channelData
, bool const TelemetryStatus
, bool const isHighAux
)
216 // All channel data is 10 bit apart from AUX1 which is 1 bit
217 ota8
->rc
.packetType
= PACKET_TYPE_RCDATA
;
218 ota8
->rc
.telemetryStatus
= TelemetryStatus
;
219 // uplinkPower has 8 items but only 3 bits, but 0 is 0 power which we never use, shift 1-8 -> 0-7
220 ota8
->rc
.uplinkPower
= constrain(CRSF::LinkStatistics
.uplink_TX_Power
, 1, 8) - 1;
221 ota8
->rc
.isHighAux
= isHighAux
;
222 ota8
->rc
.ch4
= CRSF_to_BIT(channelData
[4]);
223 #if defined(DEBUG_RCVR_LINKSTATS)
224 // Incremental packet counter for verification on the RX side, 32 bits shoved into CH1-CH4
225 ota8
->dbg_linkstats
.packetNum
= packetCnt
++;
228 // 8ch always: low=0 high=5
229 // 12ch isHighAux=false: low=0 high=5
230 // 12ch isHighAux=true: low=0 high=9
231 // 16ch isHighAux=false: low=0 high=4
232 // 16ch isHighAux=true: low=8 high=12
235 if (OtaSwitchModeCurrent
== smHybridOr16ch
)
252 chSrcHigh
= isHighAux
? 9 : 5;
254 PackUInt11ToChannels4x10(&channelData
[chSrcLow
], &ota8
->rc
.chLow
, &Decimate11to10_Div2
);
255 PackUInt11ToChannels4x10(&channelData
[chSrcHigh
], &ota8
->rc
.chHigh
, &Decimate11to10_Div2
);
259 static void ICACHE_RAM_ATTR
GenerateChannelData8ch(OTA_Packet_s
* const otaPktPtr
, const uint32_t *channelData
, bool const TelemetryStatus
, uint8_t const tlmDenom
)
263 GenerateChannelData8ch12ch((OTA_Packet8_s
* const)otaPktPtr
, channelData
, TelemetryStatus
, false);
266 static bool FullResIsHighAux
;
267 #if defined(UNIT_TEST)
268 void OtaSetFullResNextChannelSet(bool next
) { FullResIsHighAux
= next
; }
270 static void ICACHE_RAM_ATTR
GenerateChannelData12ch(OTA_Packet_s
* const otaPktPtr
, const uint32_t *channelData
, bool const TelemetryStatus
, uint8_t const tlmDenom
)
274 // Every time this function is called, the opposite high Aux channels are sent
275 // This tries to ensure a fair split of high and low aux channels packets even
276 // at 1:2 ratio and around sync packets
277 GenerateChannelData8ch12ch((OTA_Packet8_s
* const)otaPktPtr
, channelData
, TelemetryStatus
, FullResIsHighAux
);
278 FullResIsHighAux
= !FullResIsHighAux
;
283 #if TARGET_RX || defined(UNIT_TEST)
285 // Current ChannelData unpacker function being used by RX
286 UnpackChannelData_t OtaUnpackChannelData
;
288 #if defined(DEBUG_RCVR_LINKSTATS)
289 // Sequential PacketID from the TX
290 uint32_t debugRcvrLinkstatsPacketId
;
293 static void UnpackChannels4x10ToUInt11(OTA_Channels_4x10
const * const srcChannels4x10
, uint32_t * const dest
)
295 uint8_t const * const payload
= (uint8_t const * const)srcChannels4x10
;
296 constexpr unsigned numOfChannels
= 4;
297 constexpr unsigned srcBits
= 10;
298 constexpr unsigned dstBits
= 11;
299 constexpr unsigned inputChannelMask
= (1 << srcBits
) - 1;
300 constexpr unsigned precisionShift
= dstBits
- srcBits
;
302 // code from BetaFlight rx/crsf.cpp / bitpacker_unpack
303 uint8_t bitsMerged
= 0;
304 uint32_t readValue
= 0;
305 unsigned readByteIndex
= 0;
306 for (uint8_t n
= 0; n
< numOfChannels
; n
++)
308 while (bitsMerged
< srcBits
)
310 uint8_t readByte
= payload
[readByteIndex
++];
311 readValue
|= ((uint32_t) readByte
) << bitsMerged
;
314 //printf("rv=%x(%x) bm=%u\n", readValue, (readValue & channelMask), bitsMerged);
315 dest
[n
] = (readValue
& inputChannelMask
) << precisionShift
;
316 readValue
>>= srcBits
;
317 bitsMerged
-= srcBits
;
320 #endif /* !DEBUG_RCVR_LINKSTATS */
322 static void ICACHE_RAM_ATTR
UnpackChannelDataHybridCommon(OTA_Packet4_s
const * const ota4
, uint32_t *channelData
)
324 #if defined(DEBUG_RCVR_LINKSTATS)
325 debugRcvrLinkstatsPacketId
= ota4
->dbg_linkstats
.packetNum
;
327 // The analog channels, encoded as 10bit where 0 = 998us and 1023 = 2012us
328 UnpackChannels4x10ToUInt11(&ota4
->rc
.ch
, &channelData
[0]);
329 // The unpacker simply does a << 1 to convert 10 to 11bit, but Hybrid/Wide modes
330 // only pack a subset of the full range CRSF data, so properly expand it
331 // This is ~80 bytes less code than passing an 10-to-11 expander fn to the unpacker
332 for (unsigned ch
=0; ch
<4; ++ch
)
334 channelData
[ch
] = UINT10_to_CRSF(channelData
[ch
] >> 1);
336 channelData
[4] = BIT_to_CRSF(ota4
->rc
.ch4
);
341 * Hybrid switches decoding of over the air data
343 * Hybrid switches uses 10 bits for each analog channel,
344 * 2 bits for the low latency switch[0]
345 * 3 bits for the round-robin switch index and 2 bits for the value
348 * Output: channelData
349 * Returns: TelemetryStatus bit
351 bool ICACHE_RAM_ATTR
UnpackChannelDataHybridSwitch8(OTA_Packet_s
const * const otaPktPtr
, uint32_t *channelData
,
352 uint8_t const tlmDenom
)
356 OTA_Packet4_s
const * const ota4
= (OTA_Packet4_s
const * const)otaPktPtr
;
357 UnpackChannelDataHybridCommon(ota4
, channelData
);
359 // The round-robin switch, switchIndex is actually index-1
360 // to leave the low bit open for switch 7 (sent as 0b11x)
361 // where x is the high bit of switch 7
362 const uint8_t switchByte
= ota4
->rc
.switches
;
363 uint8_t switchIndex
= (switchByte
& 0b111000) >> 3;
364 if (switchIndex
>= 6)
366 // Because AUX1 (index 0) is the low latency switch, the low bit
367 // of the switchIndex can be used as data, and arrives as index "6"
368 channelData
[11] = N_to_CRSF(switchByte
& 0b1111, 15);
372 channelData
[5+switchIndex
] = SWITCH3b_to_CRSF(switchByte
& 0b111);
375 // TelemetryStatus bit
376 return switchByte
& (1 << 6);
380 * HybridWide switches decoding of over the air data
382 * Hybrid switches uses 10 bits for each analog channel,
383 * 1 bits for the low latency switch[0]
384 * 6 or 7 bits for the round-robin switch
385 * 1 bit for the TelemetryStatus, which may be in every packet or just idx 7
386 * depending on TelemetryRatio
388 * Output: channelData
389 * Returns: TelemetryStatus bit
391 bool ICACHE_RAM_ATTR
UnpackChannelDataHybridWide(OTA_Packet_s
const * const otaPktPtr
, uint32_t *channelData
,
392 uint8_t const tlmDenom
)
394 static bool TelemetryStatus
= false;
396 OTA_Packet4_s
const * const ota4
= (OTA_Packet4_s
const * const)otaPktPtr
;
397 UnpackChannelDataHybridCommon(ota4
, channelData
);
399 // The round-robin switch, 6-7 bits with the switch index implied by the nonce
400 const uint8_t switchByte
= ota4
->rc
.switches
;
401 bool telemInEveryPacket
= (tlmDenom
> 1) && (tlmDenom
< 8);
402 uint8_t switchIndex
= HybridWideNonceToSwitchIndex(OtaNonce
);
403 if (telemInEveryPacket
|| switchIndex
== 7)
404 TelemetryStatus
= (switchByte
& 0b01000000) >> 6;
405 if (switchIndex
== 7)
407 CRSF::updateUplinkPower(switchByte
& 0b111111);
412 uint16_t switchValue
;
413 if (telemInEveryPacket
)
416 switchValue
= switchByte
& 0b111111; // 6-bit
421 switchValue
= switchByte
& 0b1111111; // 7-bit
424 channelData
[5 + switchIndex
] = N_to_CRSF(switchValue
, bins
);
427 return TelemetryStatus
;
430 bool ICACHE_RAM_ATTR
UnpackChannelData8ch(OTA_Packet_s
const * const otaPktPtr
, uint32_t *channelData
, uint8_t const tlmDenom
)
434 OTA_Packet8_s
const * const ota8
= (OTA_Packet8_s
const * const)otaPktPtr
;
436 #if defined(DEBUG_RCVR_LINKSTATS)
437 debugRcvrLinkstatsPacketId
= ota8
->dbg_linkstats
.packetNum
;
441 if (OtaSwitchModeCurrent
== smHybridOr16ch
)
443 if (ota8
->rc
.isHighAux
)
456 channelData
[4] = BIT_to_CRSF(ota8
->rc
.ch4
);
458 chDstHigh
= (ota8
->rc
.isHighAux
) ? 9 : 5;
461 // Analog channels packed 10bit covering the entire CRSF extended range (i.e. not just 988-2012)
462 // ** Different than the 10bit encoding in Hybrid/Wide mode **
463 UnpackChannels4x10ToUInt11(&ota8
->rc
.chLow
, &channelData
[chDstLow
]);
464 UnpackChannels4x10ToUInt11(&ota8
->rc
.chHigh
, &channelData
[chDstHigh
]);
466 // Restore the uplink_TX_Power range 0-7 -> 1-8
467 CRSF::updateUplinkPower(ota8
->rc
.uplinkPower
+ 1);
468 return ota8
->rc
.telemetryStatus
;
472 bool ICACHE_RAM_ATTR
ValidatePacketCrcFull(OTA_Packet_s
* const otaPktPtr
)
474 uint16_t const calculatedCRC
=
475 ota_crc
.calc((uint8_t*)otaPktPtr
, OTA8_CRC_CALC_LEN
, OtaCrcInitializer
);
476 return otaPktPtr
->full
.crc
== calculatedCRC
;
479 bool ICACHE_RAM_ATTR
ValidatePacketCrcStd(OTA_Packet_s
* const otaPktPtr
)
481 uint8_t backupCrcHigh
= otaPktPtr
->std
.crcHigh
;
483 uint16_t const inCRC
= ((uint16_t)otaPktPtr
->std
.crcHigh
<< 8) + otaPktPtr
->std
.crcLow
;
484 // For smHybrid the CRC only has the packet type in byte 0
485 // For smWide the FHSS slot is added to the CRC in byte 0 on PACKET_TYPE_RCDATAs
486 #if defined(TARGET_RX)
487 if (otaPktPtr
->std
.type
== PACKET_TYPE_RCDATA
&& OtaSwitchModeCurrent
== smWideOr8ch
)
489 otaPktPtr
->std
.crcHigh
= (OtaNonce
% ExpressLRS_currAirRate_Modparams
->FHSShopInterval
) + 1;
494 otaPktPtr
->std
.crcHigh
= 0;
496 uint16_t const calculatedCRC
=
497 ota_crc
.calc((uint8_t*)otaPktPtr
, OTA4_CRC_CALC_LEN
, OtaCrcInitializer
);
499 otaPktPtr
->std
.crcHigh
= backupCrcHigh
;
501 return inCRC
== calculatedCRC
;
504 void ICACHE_RAM_ATTR
GeneratePacketCrcFull(OTA_Packet_s
* const otaPktPtr
)
506 otaPktPtr
->full
.crc
= ota_crc
.calc((uint8_t*)otaPktPtr
, OTA8_CRC_CALC_LEN
, OtaCrcInitializer
);
509 void ICACHE_RAM_ATTR
GeneratePacketCrcStd(OTA_Packet_s
* const otaPktPtr
)
511 #if defined(TARGET_TX)
512 // artificially inject the low bits of the nonce on data packets, this will be overwritten with the CRC after it's calculated
513 if (otaPktPtr
->std
.type
== PACKET_TYPE_RCDATA
&& OtaSwitchModeCurrent
== smWideOr8ch
)
515 otaPktPtr
->std
.crcHigh
= (OtaNonce
% ExpressLRS_currAirRate_Modparams
->FHSShopInterval
) + 1;
518 uint16_t crc
= ota_crc
.calc((uint8_t*)otaPktPtr
, OTA4_CRC_CALC_LEN
, OtaCrcInitializer
);
519 otaPktPtr
->std
.crcHigh
= (crc
>> 8);
520 otaPktPtr
->std
.crcLow
= crc
;
523 void OtaUpdateSerializers(OtaSwitchMode_e
const switchMode
, uint8_t packetSize
)
525 OtaIsFullRes
= (packetSize
== OTA8_PACKET_SIZE
);
529 OtaValidatePacketCrc
= &ValidatePacketCrcFull
;
530 OtaGeneratePacketCrc
= &GeneratePacketCrcFull
;
531 ota_crc
.init(16, ELRS_CRC16_POLY
);
533 #if defined(TARGET_TX) || defined(UNIT_TEST)
534 if (switchMode
== smWideOr8ch
)
535 OtaPackChannelData
= &GenerateChannelData8ch
;
537 OtaPackChannelData
= &GenerateChannelData12ch
;
539 #if defined(TARGET_RX) || defined(UNIT_TEST)
540 OtaUnpackChannelData
= &UnpackChannelData8ch
;
546 OtaValidatePacketCrc
= &ValidatePacketCrcStd
;
547 OtaGeneratePacketCrc
= &GeneratePacketCrcStd
;
548 ota_crc
.init(14, ELRS_CRC14_POLY
);
550 if (switchMode
== smWideOr8ch
)
552 #if defined(TARGET_TX) || defined(UNIT_TEST)
553 OtaPackChannelData
= &GenerateChannelDataHybridWide
;
555 #if defined(TARGET_RX) || defined(UNIT_TEST)
556 OtaUnpackChannelData
= &UnpackChannelDataHybridWide
;
558 } // !is8ch and smWideOr8ch
562 #if defined(TARGET_TX) || defined(UNIT_TEST)
563 OtaPackChannelData
= &GenerateChannelDataHybrid8
;
565 #if defined(TARGET_RX) || defined(UNIT_TEST)
566 OtaUnpackChannelData
= &UnpackChannelDataHybridSwitch8
;
568 } // !is8ch and smHybridOr16ch
571 OtaSwitchModeCurrent
= switchMode
;
574 void OtaPackAirportData(OTA_Packet_s
* const otaPktPtr
, FIFO
<AP_MAX_BUF_LEN
> *inputBuffer
)
576 otaPktPtr
->std
.type
= PACKET_TYPE_TLM
;
579 uint8_t count
= inputBuffer
->size();
582 count
= std::min(count
, (uint8_t)ELRS8_TELEMETRY_BYTES_PER_CALL
);
583 otaPktPtr
->full
.airport
.count
= count
;
584 inputBuffer
->popBytes(otaPktPtr
->full
.airport
.payload
, count
);
588 count
= std::min(count
, (uint8_t)ELRS4_TELEMETRY_BYTES_PER_CALL
);
589 otaPktPtr
->std
.airport
.count
= count
;
590 inputBuffer
->popBytes(otaPktPtr
->std
.airport
.payload
, count
);
591 otaPktPtr
->std
.airport
.type
= ELRS_TELEMETRY_TYPE_DATA
;
593 inputBuffer
->unlock();
596 void OtaUnpackAirportData(OTA_Packet_s
const * const otaPktPtr
, FIFO
<AP_MAX_BUF_LEN
> *outputBuffer
)
600 uint8_t count
= otaPktPtr
->full
.airport
.count
;
601 outputBuffer
->atomicPushBytes(otaPktPtr
->full
.airport
.payload
, count
);
605 uint8_t count
= otaPktPtr
->std
.airport
.count
;
606 outputBuffer
->atomicPushBytes(otaPktPtr
->std
.airport
.payload
, count
);