Silence unused-variable warning (#2872)
[ExpressLRS.git] / src / lib / OTA / OTA.cpp
blob219b994172d77f296b480e2ff223e406fda15e5e
1 /**
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.
7 */
9 #include "OTA.h"
10 #include "common.h"
11 #include "CRSF.h"
12 #include <cassert>
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!");
17 bool OtaIsFullRes;
18 volatile uint8_t OtaNonce;
19 uint16_t OtaCrcInitializer;
20 OtaSwitchMode_e OtaSwitchModeCurrent;
22 // CRC
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;
51 #endif
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
65 return ch11bit >> 1;
68 /***
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
74 ***/
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;
79 *dest = 0;
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++;
105 #else
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; }
128 #endif
129 void ICACHE_RAM_ATTR GenerateChannelDataHybrid8(OTA_Packet_s * const otaPktPtr, const uint32_t *channelData,
130 bool const TelemetryStatus, uint8_t const tlmDenom)
132 (void)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;
141 uint8_t value;
142 // AUX8 is High Resolution 16-pos (4-bit)
143 if (bitclearedSwitchIndex == 6)
144 value = CRSF_to_N(channelData[6 + 1 + 4], 16);
145 else
146 value = CRSF_to_SWITCH3b(channelData[bitclearedSwitchIndex + 1 + 4]);
148 ota4->rc.switches =
149 TelemetryStatus << 6 |
150 // tell the receiver which switch index this is
151 bitclearedSwitchIndex << 3 |
152 // include the switch value
153 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);
168 if (lowRes)
169 return ch & 0b111111; // 6-bit
170 else
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);
193 uint8_t value;
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;
203 else
205 bool telemInEveryPacket = (tlmDenom > 1) && (tlmDenom < 8);
206 value = HybridWideSwitchToOta(channelData, nextSwitchIndex + 1, telemInEveryPacket);
207 if (telemInEveryPacket)
208 value |= telemBit;
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++;
226 #else
227 // Sources:
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
233 uint8_t chSrcLow;
234 uint8_t chSrcHigh;
235 if (OtaSwitchModeCurrent == smHybridOr16ch)
237 // 16ch mode
238 if (isHighAux)
240 chSrcLow = 8;
241 chSrcHigh = 12;
243 else
245 chSrcLow = 0;
246 chSrcHigh = 4;
249 else
251 chSrcLow = 0;
252 chSrcHigh = isHighAux ? 9 : 5;
254 PackUInt11ToChannels4x10(&channelData[chSrcLow], &ota8->rc.chLow, &Decimate11to10_Div2);
255 PackUInt11ToChannels4x10(&channelData[chSrcHigh], &ota8->rc.chHigh, &Decimate11to10_Div2);
256 #endif
259 static void ICACHE_RAM_ATTR GenerateChannelData8ch(OTA_Packet_s * const otaPktPtr, const uint32_t *channelData, bool const TelemetryStatus, uint8_t const tlmDenom)
261 (void)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; }
269 #endif
270 static void ICACHE_RAM_ATTR GenerateChannelData12ch(OTA_Packet_s * const otaPktPtr, const uint32_t *channelData, bool const TelemetryStatus, uint8_t const tlmDenom)
272 (void)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;
280 #endif
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;
291 #else
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;
312 bitsMerged += 8;
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;
326 #else
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);
337 #endif
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
347 * Input: Buffer
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)
354 (void)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);
370 else
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);
409 else
411 uint8_t bins;
412 uint16_t switchValue;
413 if (telemInEveryPacket)
415 bins = 63;
416 switchValue = switchByte & 0b111111; // 6-bit
418 else
420 bins = 127;
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)
432 (void)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;
438 #else
439 uint8_t chDstLow;
440 uint8_t chDstHigh;
441 if (OtaSwitchModeCurrent == smHybridOr16ch)
443 if (ota8->rc.isHighAux)
445 chDstLow = 8;
446 chDstHigh = 12;
448 else
450 chDstLow = 0;
451 chDstHigh = 4;
454 else
456 channelData[4] = BIT_to_CRSF(ota8->rc.ch4);
457 chDstLow = 0;
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]);
465 #endif
466 // Restore the uplink_TX_Power range 0-7 -> 1-8
467 CRSF::updateUplinkPower(ota8->rc.uplinkPower + 1);
468 return ota8->rc.telemetryStatus;
470 #endif
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;
491 else
492 #endif
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;
517 #endif
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);
527 if (OtaIsFullRes)
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;
536 else
537 OtaPackChannelData = &GenerateChannelData12ch;
538 #endif
539 #if defined(TARGET_RX) || defined(UNIT_TEST)
540 OtaUnpackChannelData = &UnpackChannelData8ch;
541 #endif
542 } // is8ch
544 else
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;
554 #endif
555 #if defined(TARGET_RX) || defined(UNIT_TEST)
556 OtaUnpackChannelData = &UnpackChannelDataHybridWide;
557 #endif
558 } // !is8ch and smWideOr8ch
560 else
562 #if defined(TARGET_TX) || defined(UNIT_TEST)
563 OtaPackChannelData = &GenerateChannelDataHybrid8;
564 #endif
565 #if defined(TARGET_RX) || defined(UNIT_TEST)
566 OtaUnpackChannelData = &UnpackChannelDataHybridSwitch8;
567 #endif
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;
578 inputBuffer->lock();
579 uint8_t count = inputBuffer->size();
580 if (OtaIsFullRes)
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);
586 else
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)
598 if (OtaIsFullRes)
600 uint8_t count = otaPktPtr->full.airport.count;
601 outputBuffer->atomicPushBytes(otaPktPtr->full.airport.payload, count);
603 else
605 uint8_t count = otaPktPtr->std.airport.count;
606 outputBuffer->atomicPushBytes(otaPktPtr->std.airport.payload, count);