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.
29 #ifdef USE_RX_EXPRESSLRS
31 #include "build/build_config.h"
32 #include "common/utils.h"
33 #include "common/maths.h"
35 #include "rx/expresslrs_common.h"
36 #include "drivers/rx/rx_sx127x.h"
37 #include "drivers/rx/rx_sx1280.h"
39 STATIC_UNIT_TESTED
uint16_t crc14tab
[ELRS_CRC_LEN
] = {0};
41 static uint8_t volatile fhssIndex
= 0;
42 STATIC_UNIT_TESTED
uint8_t fhssSequence
[ELRS_NR_SEQUENCE_ENTRIES
] = {0};
43 static uint16_t seqCount
= 0;
44 static uint8_t syncChannel
= 0;
45 static uint32_t freqSpread
= 0;
47 #define MS_TO_US(ms) (ms * 1000)
49 // Regarding failsafe timeout values:
50 // @CapnBry - Higher rates shorter timeout. Usually it runs 1-1.5 seconds with complete sync 500Hz.
51 // 250Hz is 2-5s. 150Hz 2.5s. 50Hz stays in sync all 5 seconds of my test.
52 // The failsafe timeout values come from the ELRS project's ExpressLRS_AirRateConfig definitions.
53 elrsModSettings_t airRateConfig
[][ELRS_RATE_MAX
] = {
56 {0, RATE_LORA_200HZ
, SX127x_BW_500_00_KHZ
, SX127x_SF_6
, SX127x_CR_4_7
, 5000, TLM_RATIO_1_64
, 4, 8},
57 {1, RATE_LORA_100HZ
, SX127x_BW_500_00_KHZ
, SX127x_SF_7
, SX127x_CR_4_7
, 10000, TLM_RATIO_1_64
, 4, 8},
58 {2, RATE_LORA_50HZ
, SX127x_BW_500_00_KHZ
, SX127x_SF_8
, SX127x_CR_4_7
, 20000, TLM_RATIO_1_16
, 4, 10},
59 {3, RATE_LORA_25HZ
, SX127x_BW_500_00_KHZ
, SX127x_SF_9
, SX127x_CR_4_7
, 40000, TLM_RATIO_1_8
, 2, 10}
64 {0, RATE_LORA_500HZ
, SX1280_LORA_BW_0800
, SX1280_LORA_SF5
, SX1280_LORA_CR_LI_4_6
, 2000, TLM_RATIO_1_128
, 4, 12},
65 {1, RATE_LORA_250HZ
, SX1280_LORA_BW_0800
, SX1280_LORA_SF6
, SX1280_LORA_CR_LI_4_7
, 4000, TLM_RATIO_1_64
, 4, 14},
66 {2, RATE_LORA_150HZ
, SX1280_LORA_BW_0800
, SX1280_LORA_SF7
, SX1280_LORA_CR_LI_4_7
, 6666, TLM_RATIO_1_32
, 4, 12},
67 {3, RATE_LORA_50HZ
, SX1280_LORA_BW_0800
, SX1280_LORA_SF8
, SX1280_LORA_CR_LI_4_7
, 20000, TLM_RATIO_1_16
, 2, 12}
70 #if !defined(USE_RX_SX127X) && !defined(USE_RX_SX1280)
75 elrsRfPerfParams_t rfPerfConfig
[][ELRS_RATE_MAX
] = {
78 {0, RATE_LORA_200HZ
, -112, 4380, 3000, 2500, 600, 5000},
79 {1, RATE_LORA_100HZ
, -117, 8770, 3500, 2500, 600, 5000},
80 {2, RATE_LORA_50HZ
, -120, 17540, 4000, 2500, 600, 5000},
81 {3, RATE_LORA_25HZ
, -123, 17540, 6000, 4000, 0, 5000}
86 {0, RATE_LORA_500HZ
, -105, 1665, 2500, 2500, 3, 5000},
87 {1, RATE_LORA_250HZ
, -108, 3300, 3000, 2500, 6, 5000},
88 {2, RATE_LORA_150HZ
, -112, 5871, 3500, 2500, 10, 5000},
89 {3, RATE_LORA_50HZ
, -115, 10798, 4000, 2500, 0, 5000}
92 #if !defined(USE_RX_SX127X) && !defined(USE_RX_SX1280)
97 const elrsFhssConfig_t fhssConfigs
[] = {
99 {AU433
, FREQ_HZ_TO_REG_VAL_900(433420000), FREQ_HZ_TO_REG_VAL_900(434420000), 3},
100 {AU915
, FREQ_HZ_TO_REG_VAL_900(915500000), FREQ_HZ_TO_REG_VAL_900(926900000), 20},
101 {EU433
, FREQ_HZ_TO_REG_VAL_900(433100000), FREQ_HZ_TO_REG_VAL_900(434450000), 3},
102 {EU868
, FREQ_HZ_TO_REG_VAL_900(865275000), FREQ_HZ_TO_REG_VAL_900(869575000), 13},
103 {IN866
, FREQ_HZ_TO_REG_VAL_900(865375000), FREQ_HZ_TO_REG_VAL_900(866950000), 4},
104 {FCC915
, FREQ_HZ_TO_REG_VAL_900(903500000), FREQ_HZ_TO_REG_VAL_900(926900000), 40},
107 {ISM2400
, FREQ_HZ_TO_REG_VAL_24(2400400000), FREQ_HZ_TO_REG_VAL_24(2479400000), 80},
108 {CE2400
, FREQ_HZ_TO_REG_VAL_24(2400400000), FREQ_HZ_TO_REG_VAL_24(2479400000), 80},
110 #if !defined(USE_RX_SX127X) && !defined(USE_RX_SX1280)
115 const elrsFhssConfig_t
*fhssConfig
;
117 void generateCrc14Table(void)
120 for (uint16_t i
= 0; i
< ELRS_CRC_LEN
; i
++) {
122 for (uint8_t j
= 0; j
< 8; j
++) {
123 crc
= (crc
<< 1) ^ ((crc
& 0x2000) ? ELRS_CRC14_POLY
: 0);
129 uint16_t calcCrc14(uint8_t *data
, uint8_t len
, uint16_t crc
)
132 crc
= (crc
<< 8) ^ crc14tab
[((crc
>> 6) ^ (uint16_t) *data
++) & 0x00FF];
137 uint32_t fhssGetInitialFreq(const int32_t freqCorrection
)
139 return fhssConfig
->freqStart
+ (syncChannel
* freqSpread
/ ELRS_FREQ_SPREAD_SCALE
) - freqCorrection
;
142 uint8_t fhssGetNumEntries(void)
144 return fhssConfig
->freqCount
;
147 uint8_t fhssGetCurrIndex(void)
152 void fhssSetCurrIndex(const uint8_t value
)
154 fhssIndex
= value
% seqCount
;
157 uint32_t fhssGetNextFreq(const int32_t freqCorrection
)
159 fhssIndex
= (fhssIndex
+ 1) % seqCount
;
160 uint32_t freq
= fhssConfig
->freqStart
+ (freqSpread
* fhssSequence
[fhssIndex
] / ELRS_FREQ_SPREAD_SCALE
) - freqCorrection
;
164 static uint32_t seed
= 0;
166 // returns 0 <= x < max where max < 256
167 static uint8_t rngN(const uint8_t max
)
169 const uint32_t m
= 2147483648;
170 const uint32_t a
= 214013;
171 const uint32_t c
= 2531011;
172 seed
= (a
* seed
+ c
) % m
;
173 return (seed
>> 16) % max
;
179 2. No two repeated channels
180 3. Equal occurance of each (or as even as possible) of each channel
184 Fill the sequence array with the sync channel every FHSS_FREQ_CNT
185 Iterate through the array, and for each block, swap each entry in it with
186 another random entry, excluding the sync channel.
189 void fhssGenSequence(const uint8_t UID
[], const elrsFreqDomain_e dom
)
191 seed
= (((long)UID
[2] << 24) + ((long)UID
[3] << 16) + ((long)UID
[4] << 8) + UID
[5]) ^ ELRS_OTA_VERSION_ID
;
192 fhssConfig
= &fhssConfigs
[dom
];
193 seqCount
= (256 / MAX(fhssConfig
->freqCount
, 1)) * fhssConfig
->freqCount
;
194 syncChannel
= (fhssConfig
->freqCount
/ 2) + 1;
195 freqSpread
= (fhssConfig
->freqStop
- fhssConfig
->freqStart
) * ELRS_FREQ_SPREAD_SCALE
/ MAX((fhssConfig
->freqCount
- 1), 1);
197 // initialize the sequence array
198 for (uint16_t i
= 0; i
< seqCount
; i
++) {
199 if (i
% fhssConfig
->freqCount
== 0) {
200 fhssSequence
[i
] = syncChannel
;
201 } else if (i
% fhssConfig
->freqCount
== syncChannel
) {
204 fhssSequence
[i
] = i
% fhssConfig
->freqCount
;
208 for (uint16_t i
= 0; i
< seqCount
; i
++) {
209 // if it's not the sync channel
210 if (i
% fhssConfig
->freqCount
!= 0) {
211 uint8_t offset
= (i
/ fhssConfig
->freqCount
) * fhssConfig
->freqCount
; // offset to start of current block
212 uint8_t rand
= rngN(fhssConfig
->freqCount
- 1) + 1; // random number between 1 and numFreqs
214 // switch this entry and another random entry in the same block
215 uint8_t temp
= fhssSequence
[i
];
216 fhssSequence
[i
] = fhssSequence
[offset
+ rand
];
217 fhssSequence
[offset
+ rand
] = temp
;
222 uint8_t tlmRatioEnumToValue(const elrsTlmRatio_e enumval
)
224 // !! TLM_RATIO_STD/TLM_RATIO_DISARMED should be converted by the caller !!
225 if (enumval
== TLM_RATIO_NO_TLM
) {
229 // 1 << (8 - (enumval - TLM_RATIO_NO_TLM))
230 // 1_128 = 128, 1_64 = 64, 1_32 = 32, etc
231 return 1 << (8 + TLM_RATIO_NO_TLM
- enumval
);
234 uint16_t rateEnumToHz(const elrsRfRate_e eRate
)
237 case RATE_LORA_500HZ
: return 500;
238 case RATE_LORA_250HZ
: return 250;
239 case RATE_LORA_200HZ
: return 200;
240 case RATE_LORA_150HZ
: return 150;
241 case RATE_LORA_100HZ
: return 100;
242 case RATE_LORA_50HZ
: return 50;
243 case RATE_LORA_25HZ
: return 25;
244 case RATE_LORA_4HZ
: return 4;
249 uint16_t txPowerIndexToValue(const uint8_t index
)
265 #define ELRS_LQ_DEPTH 4 //100 % 32
267 typedef struct linkQuality_s
{
268 uint32_t array
[ELRS_LQ_DEPTH
];
274 static linkQuality_t lq
;
276 void lqIncrease(void)
278 if (!lqPeriodIsSet()) {
279 lq
.array
[lq
.index
] |= lq
.mask
;
284 void lqNewPeriod(void)
292 // At idx N / 32 and bit N % 32, wrap back to idx=0, bit=0
293 if ((lq
.index
== 3) && (lq
.mask
& (1 << ELRS_LQ_DEPTH
))) {
298 if ((lq
.array
[lq
.index
] & lq
.mask
) != 0) {
299 lq
.array
[lq
.index
] &= ~lq
.mask
;
309 bool lqPeriodIsSet(void)
311 return lq
.array
[lq
.index
] & lq
.mask
;
316 memset(&lq
, 0, sizeof(lq
));
320 uint16_t convertSwitch1b(const uint16_t val
)
322 return val
? 2000 : 1000;
325 // 3b to decode 7 pos switches
326 uint16_t convertSwitch3b(const uint16_t val
)
335 default: return 1500;
339 uint16_t convertSwitchNb(const uint16_t val
, const uint16_t max
)
341 return (val
> max
) ? 1500 : val
* 1000 / max
+ 1000;
344 uint8_t hybridWideNonceToSwitchIndex(const uint8_t nonce
)
346 // Returns the sequence (0 to 7, then 0 to 7 rotated left by 1):
347 // 0, 1, 2, 3, 4, 5, 6, 7,
348 // 1, 2, 3, 4, 5, 6, 7, 0
349 // Because telemetry can occur on every 2, 4, 8, 16, 32, 64, 128th packet
350 // this makes sure each of the 8 values is sent at least once every 16 packets
351 // regardless of the TLM ratio
352 // Index 7 also can never fall on a telemetry slot
353 return ((nonce
& 0x07) + ((nonce
>> 3) & 0x01)) % 8;
356 uint8_t airRateIndexToIndex900(uint8_t airRate
, uint8_t currentIndex
)
374 uint8_t airRateIndexToIndex24(uint8_t airRate
, uint8_t currentIndex
)
402 #endif /* USE_RX_EXPRESSLRS */