RX serial refactor (user selectable CRSF/SBUS serial protocol) (#2094)
[ExpressLRS.git] / src / lib / OTA / OTA.cpp
blob2e1ed3d9573cc19df305b0614550637e9cb89d48
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 <assert.h>
13 static_assert(sizeof(OTA_Packet4_s) == OTA4_PACKET_SIZE, "OTA4 packet stuct is invalid!");
14 static_assert(sizeof(OTA_Packet8_s) == OTA8_PACKET_SIZE, "OTA8 packet stuct is invalid!");
16 bool OtaIsFullRes;
17 volatile uint8_t OtaNonce;
18 uint16_t OtaCrcInitializer;
19 OtaSwitchMode_e OtaSwitchModeCurrent;
21 // CRC
22 static Crc2Byte ota_crc;
23 ValidatePacketCrc_t OtaValidatePacketCrc;
24 GeneratePacketCrc_t OtaGeneratePacketCrc;
26 void OtaUpdateCrcInitFromUid()
28 OtaCrcInitializer = (UID[4] << 8) | UID[5];
29 OtaCrcInitializer ^= OTA_VERSION_ID;
32 static inline uint8_t ICACHE_RAM_ATTR HybridWideNonceToSwitchIndex(uint8_t const nonce)
34 // Returns the sequence (0 to 7, then 0 to 7 rotated left by 1):
35 // 0, 1, 2, 3, 4, 5, 6, 7,
36 // 1, 2, 3, 4, 5, 6, 7, 0
37 // Because telemetry can occur on every 2, 4, 8, 16, 32, 64, 128th packet
38 // this makes sure each of the 8 values is sent at least once every 16 packets
39 // regardless of the TLM ratio
40 // Index 7 also can never fall on a telemetry slot
41 return ((nonce & 0b111) + ((nonce >> 3) & 0b1)) % 8;
44 #if TARGET_TX || defined(UNIT_TEST)
46 // Current ChannelData generator function being used by TX
47 PackChannelData_t OtaPackChannelData;
48 #if defined(DEBUG_RCVR_LINKSTATS)
49 static uint32_t packetCnt;
50 #endif
52 /******** Decimate 11bit to 10bit functions ********/
53 typedef uint32_t (*Decimate11to10_fn)(uint32_t ch11bit);
55 static uint32_t ICACHE_RAM_ATTR Decimate11to10_Limit(uint32_t ch11bit)
57 // Limit 10-bit result to the range CRSF_CHANNEL_VALUE_MIN/MAX
58 return CRSF_to_UINT10(constrain(ch11bit, CRSF_CHANNEL_VALUE_MIN, CRSF_CHANNEL_VALUE_MAX));
61 static uint32_t ICACHE_RAM_ATTR Decimate11to10_Div2(uint32_t ch11bit)
63 // Simple divide-by-2 to discard the bit
64 return ch11bit >> 1;
67 /***
68 * @brief: Pack 4x 11-bit channel array into 4x 10 bit channel struct
69 * @desc: Values are packed little-endianish such that bits A987654321 -> 87654321, 000000A9
70 * which is compatible with the 10-bit CRSF subset RC frame structure (0x17) in
71 * Betaflight, but depends on which decimate function is used if it is legacy or CRSFv3 10-bit
72 * destChannels4x10 must be zeroed before this call, the channels are ORed into it
73 ***/
74 static void ICACHE_RAM_ATTR PackUInt11ToChannels4x10(uint32_t const * const src, OTA_Channels_4x10 * const destChannels4x10, Decimate11to10_fn decimate)
76 const unsigned DEST_PRECISION = 10; // number of bits for each dest, must be <SRC
77 uint8_t *dest = (uint8_t *)destChannels4x10;
78 *dest = 0;
79 unsigned destShift = 0;
80 for (unsigned ch=0; ch<4; ++ch)
82 // Convert to DEST_PRECISION value
83 unsigned chVal = decimate(src[ch]);
85 // Put the low bits in any remaining dest capacity
86 *dest++ |= chVal << destShift;
88 // Shift the high bits down and place them into the next dest byte
89 unsigned srcBitsLeft = DEST_PRECISION - 8 + destShift;
90 *dest = chVal >> (DEST_PRECISION - srcBitsLeft);
91 // Next dest should be shifted up by the bits consumed
92 // if destShift == 8 then everything should reset for another set
93 // but this code only expects to do the 4 channels -> 5 bytes evenly
94 destShift = srcBitsLeft;
98 static void ICACHE_RAM_ATTR PackChannelDataHybridCommon(OTA_Packet4_s * const ota4, const uint32_t *channelData)
100 ota4->type = PACKET_TYPE_RCDATA;
101 #if defined(DEBUG_RCVR_LINKSTATS)
102 // Incremental packet counter for verification on the RX side, 32 bits shoved into CH1-CH4
103 ota4->dbg_linkstats.packetNum = packetCnt++;
104 #else
105 // CRSF input is 11bit and OTA will carry only 10bit. Discard the Extended Limits (E.Limits)
106 // range and use the full 10bits to carry only 998us - 2012us
107 PackUInt11ToChannels4x10(&channelData[0], &ota4->rc.ch, &Decimate11to10_Limit);
108 ota4->rc.ch4 = CRSF_to_BIT(channelData[4]);
109 #endif /* !DEBUG_RCVR_LINKSTATS */
113 * Hybrid switches packet encoding for sending over the air
115 * Analog channels are reduced to 10 bits to allow for switch encoding
116 * Switch[0] is sent on every packet.
117 * A 3 bit switch index and 3-4 bit value is used to send the remaining switches
118 * in a round-robin fashion.
120 * Inputs: channelData, TelemetryStatus
121 * Outputs: OTA_Packet4_s, side-effects the sentSwitch value
123 // The next switch index to send, where 0=AUX2 and 6=AUX8
124 static uint8_t Hybrid8NextSwitchIndex;
125 #if defined(UNIT_TEST)
126 void OtaSetHybrid8NextSwitchIndex(uint8_t idx) { Hybrid8NextSwitchIndex = idx; }
127 #endif
128 void ICACHE_RAM_ATTR GenerateChannelDataHybrid8(OTA_Packet_s * const otaPktPtr, const uint32_t *channelData,
129 bool const TelemetryStatus, uint8_t const tlmDenom)
131 (void)tlmDenom;
133 OTA_Packet4_s * const ota4 = &otaPktPtr->std;
134 PackChannelDataHybridCommon(ota4, channelData);
136 // Actually send switchIndex - 1 in the packet, to shift down 1-7 (0b111) to 0-6 (0b110)
137 // If the two high bits are 0b11, the receiver knows it is the last switch and can use
138 // that bit to store data
139 uint8_t bitclearedSwitchIndex = Hybrid8NextSwitchIndex;
140 uint8_t value;
141 // AUX8 is High Resolution 16-pos (4-bit)
142 if (bitclearedSwitchIndex == 6)
143 value = CRSF_to_N(channelData[6 + 1 + 4], 16);
144 else
146 // AUX2-7 are Low Resolution, "7pos" 6+center (3-bit)
147 // The output is mapped evenly across 6 output values (0-5)
148 // with a special value 7 indicating the middle so it works
149 // with switches with a middle position as well as 6-position
150 const uint16_t CHANNEL_BIN_COUNT = 6;
151 const uint16_t CHANNEL_BIN_SIZE = (CRSF_CHANNEL_VALUE_MAX - CRSF_CHANNEL_VALUE_MIN) / CHANNEL_BIN_COUNT;
152 uint16_t ch = channelData[bitclearedSwitchIndex + 1 + 4];
153 // If channel is within 1/4 a BIN of being in the middle use special value 7
154 if (ch < (CRSF_CHANNEL_VALUE_MID-CHANNEL_BIN_SIZE/4)
155 || ch > (CRSF_CHANNEL_VALUE_MID+CHANNEL_BIN_SIZE/4))
156 value = CRSF_to_N(ch, CHANNEL_BIN_COUNT);
157 else
158 value = 7;
159 } // If not 16-pos
161 ota4->rc.switches =
162 TelemetryStatus << 6 |
163 // tell the receiver which switch index this is
164 bitclearedSwitchIndex << 3 |
165 // include the switch value
166 value;
168 // update the sent value
169 Hybrid8NextSwitchIndex = (bitclearedSwitchIndex + 1) % 7;
173 * Return the OTA value respresentation of the switch contained in ChannelData
174 * Switches 1-6 (AUX2-AUX7) are 6 or 7 bit depending on the lowRes parameter
176 static uint8_t ICACHE_RAM_ATTR HybridWideSwitchToOta(const uint32_t *channelData, uint8_t const switchIdx, bool const lowRes)
178 uint16_t ch = channelData[switchIdx + 4];
179 uint8_t binCount = (lowRes) ? 64 : 128;
180 ch = CRSF_to_N(ch, binCount);
181 if (lowRes)
182 return ch & 0b111111; // 6-bit
183 else
184 return ch & 0b1111111; // 7-bit
188 * HybridWide switches packet encoding for sending over the air
190 * Analog channels are reduced to 10 bits to allow for switch encoding
191 * Switch[0] is sent on every packet.
192 * A 6 or 7 bit switch value is used to send the remaining switches
193 * in a round-robin fashion.
195 * Inputs: cchannelData, TelemetryStatus
196 * Outputs: OTA_Packet4_s
198 void ICACHE_RAM_ATTR GenerateChannelDataHybridWide(OTA_Packet_s * const otaPktPtr, const uint32_t *channelData,
199 bool const TelemetryStatus, uint8_t const tlmDenom)
201 OTA_Packet4_s * const ota4 = &otaPktPtr->std;
202 PackChannelDataHybridCommon(ota4, channelData);
204 uint8_t telemBit = TelemetryStatus << 6;
205 uint8_t nextSwitchIndex = HybridWideNonceToSwitchIndex(OtaNonce);
206 uint8_t value;
207 // Using index 7 means the telemetry bit will always be sent in the packet
208 // preceding the RX's telemetry slot for all tlmDenom >= 8
209 // For more frequent telemetry rates, include the bit in every
210 // packet and degrade the value to 6-bit
211 // (technically we could squeeze 7-bits in for 2 channels with tlmDenom=4)
212 if (nextSwitchIndex == 7)
214 value = telemBit | CRSF::LinkStatistics.uplink_TX_Power;
216 else
218 bool telemInEveryPacket = (tlmDenom < 8);
219 value = HybridWideSwitchToOta(channelData, nextSwitchIndex + 1, telemInEveryPacket);
220 if (telemInEveryPacket)
221 value |= telemBit;
224 ota4->rc.switches = value;
227 static void ICACHE_RAM_ATTR GenerateChannelData8ch12ch(OTA_Packet8_s * const ota8, const uint32_t *channelData, bool const TelemetryStatus, bool const isHighAux)
229 // All channel data is 10 bit apart from AUX1 which is 1 bit
230 ota8->rc.packetType = PACKET_TYPE_RCDATA;
231 ota8->rc.telemetryStatus = TelemetryStatus;
232 // uplinkPower has 8 items but only 3 bits, but 0 is 0 power which we never use, shift 1-8 -> 0-7
233 ota8->rc.uplinkPower = constrain(CRSF::LinkStatistics.uplink_TX_Power, 1, 8) - 1;
234 ota8->rc.isHighAux = isHighAux;
235 ota8->rc.ch4 = CRSF_to_BIT(channelData[4]);
236 #if defined(DEBUG_RCVR_LINKSTATS)
237 // Incremental packet counter for verification on the RX side, 32 bits shoved into CH1-CH4
238 ota8->dbg_linkstats.packetNum = packetCnt++;
239 #else
240 // Sources:
241 // 8ch always: low=0 high=5
242 // 12ch isHighAux=false: low=0 high=5
243 // 12ch isHighAux=true: low=0 high=9
244 // 16ch isHighAux=false: low=0 high=4
245 // 16ch isHighAux=true: low=8 high=12
246 uint8_t chSrcLow;
247 uint8_t chSrcHigh;
248 if (OtaSwitchModeCurrent == smHybridOr16ch)
250 // 16ch mode
251 if (isHighAux)
253 chSrcLow = 8;
254 chSrcHigh = 12;
256 else
258 chSrcLow = 0;
259 chSrcHigh = 4;
262 else
264 chSrcLow = 0;
265 chSrcHigh = isHighAux ? 9 : 5;
267 PackUInt11ToChannels4x10(&channelData[chSrcLow], &ota8->rc.chLow, &Decimate11to10_Div2);
268 PackUInt11ToChannels4x10(&channelData[chSrcHigh], &ota8->rc.chHigh, &Decimate11to10_Div2);
269 #endif
272 static void ICACHE_RAM_ATTR GenerateChannelData8ch(OTA_Packet_s * const otaPktPtr, const uint32_t *channelData, bool const TelemetryStatus, uint8_t const tlmDenom)
274 (void)tlmDenom;
276 GenerateChannelData8ch12ch((OTA_Packet8_s * const)otaPktPtr, channelData, TelemetryStatus, false);
279 static bool FullResIsHighAux;
280 #if defined(UNIT_TEST)
281 void OtaSetFullResNextChannelSet(bool next) { FullResIsHighAux = next; }
282 #endif
283 static void ICACHE_RAM_ATTR GenerateChannelData12ch(OTA_Packet_s * const otaPktPtr, const uint32_t *channelData, bool const TelemetryStatus, uint8_t const tlmDenom)
285 (void)tlmDenom;
287 // Every time this function is called, the opposite high Aux channels are sent
288 // This tries to ensure a fair split of high and low aux channels packets even
289 // at 1:2 ratio and around sync packets
290 GenerateChannelData8ch12ch((OTA_Packet8_s * const)otaPktPtr, channelData, TelemetryStatus, FullResIsHighAux);
291 FullResIsHighAux = !FullResIsHighAux;
293 #endif
296 #if TARGET_RX || defined(UNIT_TEST)
298 // Current ChannelData unpacker function being used by RX
299 UnpackChannelData_t OtaUnpackChannelData;
301 #if defined(DEBUG_RCVR_LINKSTATS)
302 // Sequential PacketID from the TX
303 uint32_t debugRcvrLinkstatsPacketId;
304 #else
306 static void UnpackChannels4x10ToUInt11(OTA_Channels_4x10 const * const srcChannels4x10, uint32_t * const dest)
308 uint8_t const * const payload = (uint8_t const * const)srcChannels4x10;
309 constexpr unsigned numOfChannels = 4;
310 constexpr unsigned srcBits = 10;
311 constexpr unsigned dstBits = 11;
312 constexpr unsigned inputChannelMask = (1 << srcBits) - 1;
313 constexpr unsigned precisionShift = dstBits - srcBits;
315 // code from BetaFlight rx/crsf.cpp / bitpacker_unpack
316 uint8_t bitsMerged = 0;
317 uint32_t readValue = 0;
318 unsigned readByteIndex = 0;
319 for (uint8_t n = 0; n < numOfChannels; n++)
321 while (bitsMerged < srcBits)
323 uint8_t readByte = payload[readByteIndex++];
324 readValue |= ((uint32_t) readByte) << bitsMerged;
325 bitsMerged += 8;
327 //printf("rv=%x(%x) bm=%u\n", readValue, (readValue & channelMask), bitsMerged);
328 dest[n] = (readValue & inputChannelMask) << precisionShift;
329 readValue >>= srcBits;
330 bitsMerged -= srcBits;
333 #endif /* !DEBUG_RCVR_LINKSTATS */
335 static void ICACHE_RAM_ATTR UnpackChannelDataHybridCommon(OTA_Packet4_s const * const ota4, uint32_t *channelData)
337 #if defined(DEBUG_RCVR_LINKSTATS)
338 debugRcvrLinkstatsPacketId = ota4->dbg_linkstats.packetNum;
339 #else
340 // The analog channels, encoded as 10bit where 0 = 998us and 1023 = 2012us
341 UnpackChannels4x10ToUInt11(&ota4->rc.ch, &channelData[0]);
342 // The unpacker simply does a << 1 to convert 10 to 11bit, but Hybrid/Wide modes
343 // only pack a subset of the full range CRSF data, so properly expand it
344 // This is ~80 bytes less code than passing an 10-to-11 expander fn to the unpacker
345 for (unsigned ch=0; ch<4; ++ch)
347 channelData[ch] = UINT10_to_CRSF(channelData[ch] >> 1);
349 channelData[4] = BIT_to_CRSF(ota4->rc.ch4);
350 #endif
354 * Hybrid switches decoding of over the air data
356 * Hybrid switches uses 10 bits for each analog channel,
357 * 2 bits for the low latency switch[0]
358 * 3 bits for the round-robin switch index and 2 bits for the value
360 * Input: Buffer
361 * Output: channelData
362 * Returns: TelemetryStatus bit
364 bool ICACHE_RAM_ATTR UnpackChannelDataHybridSwitch8(OTA_Packet_s const * const otaPktPtr, uint32_t *channelData,
365 uint8_t const tlmDenom)
367 (void)tlmDenom;
369 OTA_Packet4_s const * const ota4 = (OTA_Packet4_s const * const)otaPktPtr;
370 UnpackChannelDataHybridCommon(ota4, channelData);
372 // The round-robin switch, switchIndex is actually index-1
373 // to leave the low bit open for switch 7 (sent as 0b11x)
374 // where x is the high bit of switch 7
375 const uint8_t switchByte = ota4->rc.switches;
376 uint8_t switchIndex = (switchByte & 0b111000) >> 3;
377 if (switchIndex >= 6)
379 // Because AUX1 (index 0) is the low latency switch, the low bit
380 // of the switchIndex can be used as data, and arrives as index "6"
381 channelData[11] = N_to_CRSF(switchByte & 0b1111, 15);
383 else
385 channelData[5+switchIndex] = SWITCH3b_to_CRSF(switchByte & 0b111);
388 // TelemetryStatus bit
389 return switchByte & (1 << 6);
393 * HybridWide switches decoding of over the air data
395 * Hybrid switches uses 10 bits for each analog channel,
396 * 1 bits for the low latency switch[0]
397 * 6 or 7 bits for the round-robin switch
398 * 1 bit for the TelemetryStatus, which may be in every packet or just idx 7
399 * depending on TelemetryRatio
401 * Output: channelData
402 * Returns: TelemetryStatus bit
404 bool ICACHE_RAM_ATTR UnpackChannelDataHybridWide(OTA_Packet_s const * const otaPktPtr, uint32_t *channelData,
405 uint8_t const tlmDenom)
407 static bool TelemetryStatus = false;
409 OTA_Packet4_s const * const ota4 = (OTA_Packet4_s const * const)otaPktPtr;
410 UnpackChannelDataHybridCommon(ota4, channelData);
412 // The round-robin switch, 6-7 bits with the switch index implied by the nonce
413 const uint8_t switchByte = ota4->rc.switches;
414 bool telemInEveryPacket = (tlmDenom < 8);
415 uint8_t switchIndex = HybridWideNonceToSwitchIndex(OtaNonce);
416 if (telemInEveryPacket || switchIndex == 7)
417 TelemetryStatus = (switchByte & 0b01000000) >> 6;
418 if (switchIndex == 7)
420 CRSF::LinkStatistics.uplink_TX_Power = switchByte & 0b111111;
422 else
424 uint8_t bins;
425 uint16_t switchValue;
426 if (telemInEveryPacket)
428 bins = 63;
429 switchValue = switchByte & 0b111111; // 6-bit
431 else
433 bins = 127;
434 switchValue = switchByte & 0b1111111; // 7-bit
437 channelData[5 + switchIndex] = N_to_CRSF(switchValue, bins);
440 return TelemetryStatus;
443 bool ICACHE_RAM_ATTR UnpackChannelData8ch(OTA_Packet_s const * const otaPktPtr, uint32_t *channelData, uint8_t const tlmDenom)
445 (void)tlmDenom;
447 OTA_Packet8_s const * const ota8 = (OTA_Packet8_s const * const)otaPktPtr;
449 #if defined(DEBUG_RCVR_LINKSTATS)
450 debugRcvrLinkstatsPacketId = ota8->dbg_linkstats.packetNum;
451 #else
452 uint8_t chDstLow;
453 uint8_t chDstHigh;
454 if (OtaSwitchModeCurrent == smHybridOr16ch)
456 if (ota8->rc.isHighAux)
458 chDstLow = 8;
459 chDstHigh = 12;
461 else
463 chDstLow = 0;
464 chDstHigh = 4;
467 else
469 channelData[4] = BIT_to_CRSF(ota8->rc.ch4);
470 chDstLow = 0;
471 chDstHigh = (ota8->rc.isHighAux) ? 9 : 5;
474 // Analog channels packed 10bit covering the entire CRSF extended range (i.e. not just 988-2012)
475 // ** Different than the 10bit encoding in Hybrid/Wide mode **
476 UnpackChannels4x10ToUInt11(&ota8->rc.chLow, &channelData[chDstLow]);
477 UnpackChannels4x10ToUInt11(&ota8->rc.chHigh, &channelData[chDstHigh]);
478 #endif
479 // Restore the uplink_TX_Power range 0-7 -> 1-8
480 CRSF::LinkStatistics.uplink_TX_Power = ota8->rc.uplinkPower + 1;
481 return ota8->rc.telemetryStatus;
483 #endif
485 bool ICACHE_RAM_ATTR ValidatePacketCrcFull(OTA_Packet_s * const otaPktPtr)
487 uint16_t const calculatedCRC =
488 ota_crc.calc((uint8_t*)otaPktPtr, OTA8_CRC_CALC_LEN, OtaCrcInitializer);
489 return otaPktPtr->full.crc == calculatedCRC;
492 bool ICACHE_RAM_ATTR ValidatePacketCrcStd(OTA_Packet_s * const otaPktPtr)
494 uint16_t const inCRC = ((uint16_t)otaPktPtr->std.crcHigh << 8) + otaPktPtr->std.crcLow;
495 // For smHybrid the CRC only has the packet type in byte 0
496 // For smWide the FHSS slot is added to the CRC in byte 0 on PACKET_TYPE_RCDATAs
497 #if defined(TARGET_RX)
498 if (otaPktPtr->std.type == PACKET_TYPE_RCDATA && OtaSwitchModeCurrent == smWideOr8ch)
500 otaPktPtr->std.crcHigh = (OtaNonce % ExpressLRS_currAirRate_Modparams->FHSShopInterval) + 1;
502 else
503 #endif
505 otaPktPtr->std.crcHigh = 0;
507 uint16_t const calculatedCRC =
508 ota_crc.calc((uint8_t*)otaPktPtr, OTA4_CRC_CALC_LEN, OtaCrcInitializer);
509 return inCRC == calculatedCRC;
512 void ICACHE_RAM_ATTR GeneratePacketCrcFull(OTA_Packet_s * const otaPktPtr)
514 otaPktPtr->full.crc = ota_crc.calc((uint8_t*)otaPktPtr, OTA8_CRC_CALC_LEN, OtaCrcInitializer);
517 void ICACHE_RAM_ATTR GeneratePacketCrcStd(OTA_Packet_s * const otaPktPtr)
519 #if defined(TARGET_TX)
520 // artificially inject the low bits of the nonce on data packets, this will be overwritten with the CRC after it's calculated
521 if (otaPktPtr->std.type == PACKET_TYPE_RCDATA && OtaSwitchModeCurrent == smWideOr8ch)
523 otaPktPtr->std.crcHigh = (OtaNonce % ExpressLRS_currAirRate_Modparams->FHSShopInterval) + 1;
525 #endif
526 uint16_t crc = ota_crc.calc((uint8_t*)otaPktPtr, OTA4_CRC_CALC_LEN, OtaCrcInitializer);
527 otaPktPtr->std.crcHigh = (crc >> 8);
528 otaPktPtr->std.crcLow = crc;
531 void OtaUpdateSerializers(OtaSwitchMode_e const switchMode, uint8_t packetSize)
533 OtaIsFullRes = (packetSize == OTA8_PACKET_SIZE);
535 if (OtaIsFullRes)
537 OtaValidatePacketCrc = &ValidatePacketCrcFull;
538 OtaGeneratePacketCrc = &GeneratePacketCrcFull;
539 ota_crc.init(16, ELRS_CRC16_POLY);
541 #if defined(TARGET_TX) || defined(UNIT_TEST)
542 if (switchMode == smWideOr8ch)
543 OtaPackChannelData = &GenerateChannelData8ch;
544 else
545 OtaPackChannelData = &GenerateChannelData12ch;
546 #endif
547 #if defined(TARGET_RX) || defined(UNIT_TEST)
548 OtaUnpackChannelData = &UnpackChannelData8ch;
549 #endif
550 } // is8ch
552 else
554 OtaValidatePacketCrc = &ValidatePacketCrcStd;
555 OtaGeneratePacketCrc = &GeneratePacketCrcStd;
556 ota_crc.init(14, ELRS_CRC14_POLY);
558 if (switchMode == smWideOr8ch)
560 #if defined(TARGET_TX) || defined(UNIT_TEST)
561 OtaPackChannelData = &GenerateChannelDataHybridWide;
562 #endif
563 #if defined(TARGET_RX) || defined(UNIT_TEST)
564 OtaUnpackChannelData = &UnpackChannelDataHybridWide;
565 #endif
566 } // !is8ch and smWideOr8ch
568 else
570 #if defined(TARGET_TX) || defined(UNIT_TEST)
571 OtaPackChannelData = &GenerateChannelDataHybrid8;
572 #endif
573 #if defined(TARGET_RX) || defined(UNIT_TEST)
574 OtaUnpackChannelData = &UnpackChannelDataHybridSwitch8;
575 #endif
576 } // !is8ch and smHybridOr16ch
579 OtaSwitchModeCurrent = switchMode;
582 void OtaPackAirportData(OTA_Packet_s * const otaPktPtr, FIFO_GENERIC<AP_MAX_BUF_LEN> * inputBuffer)
584 uint8_t count = inputBuffer->size();
585 if (OtaIsFullRes)
587 count = std::min(count, (uint8_t)ELRS8_TELEMETRY_BYTES_PER_CALL);
588 otaPktPtr->full.airport.count = count;
589 inputBuffer->popBytes(otaPktPtr->full.airport.payload, count);
591 else
593 count = std::min(count, (uint8_t)ELRS4_TELEMETRY_BYTES_PER_CALL);
594 otaPktPtr->std.airport.count = count;
595 inputBuffer->popBytes(otaPktPtr->std.airport.payload, count);
596 otaPktPtr->std.airport.type = ELRS_TELEMETRY_TYPE_DATA;
600 void OtaUnpackAirportData(OTA_Packet_s const * const otaPktPtr, FIFO_GENERIC<AP_MAX_BUF_LEN> * outputBuffer)
602 if (OtaIsFullRes)
604 uint8_t count = otaPktPtr->full.airport.count;
605 outputBuffer->pushBytes(otaPktPtr->full.airport.payload, count);
607 else
609 uint8_t count = otaPktPtr->std.airport.count;
610 outputBuffer->pushBytes(otaPktPtr->std.airport.payload, count);