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/>.
29 #include "build/build_config.h"
30 #include "build/debug.h"
32 #include "common/maths.h"
33 #include "common/utils.h"
34 #include "common/filter.h"
36 #include "config/config.h"
37 #include "config/config_reset.h"
38 #include "config/feature.h"
40 #include "drivers/adc.h"
41 #include "drivers/rx/rx_pwm.h"
42 #include "drivers/time.h"
44 #include "fc/rc_controls.h"
45 #include "fc/rc_modes.h"
46 #include "fc/runtime_config.h"
49 #include "flight/failsafe.h"
51 #include "io/serial.h"
54 #include "pg/pg_ids.h"
61 #include "rx/spektrum.h"
68 #include "rx/jetiexbus.h"
71 #include "rx/rx_spi.h"
72 #include "rx/targetcustomserial.h"
73 #include "rx/msp_override.h"
76 const char rcChannelLetters
[] = "AERT12345678abcdefgh";
78 static uint16_t rssi
= 0; // range: [0;1023]
79 static int16_t rssiDbm
= CRSF_RSSI_MIN
; // range: [-130,20]
80 static timeUs_t lastMspRssiUpdateUs
= 0;
82 static pt1Filter_t frameErrFilter
;
84 #ifdef USE_RX_LINK_QUALITY_INFO
85 static uint16_t linkQuality
= 0;
86 static uint8_t rfMode
= 0;
89 #ifdef USE_RX_LINK_UPLINK_POWER
90 static uint16_t uplinkTxPwrMw
= 0; //Uplink Tx power in mW
93 #define RSSI_ADC_DIVISOR (4096 / 1024)
94 #define RSSI_OFFSET_SCALING (1024 / 100.0f)
96 rssiSource_e rssiSource
;
97 linkQualitySource_e linkQualitySource
;
99 static bool rxDataProcessingRequired
= false;
100 static bool auxiliaryProcessingRequired
= false;
102 static bool rxSignalReceived
= false;
103 static bool rxFlightChannelsValid
= false;
104 static uint8_t rxChannelCount
;
106 static timeUs_t needRxSignalBefore
= 0;
107 static timeUs_t suspendRxSignalUntil
= 0;
108 static uint8_t skipRxSamples
= 0;
110 static float rcRaw
[MAX_SUPPORTED_RC_CHANNEL_COUNT
]; // last received raw value, as it comes
111 float rcData
[MAX_SUPPORTED_RC_CHANNEL_COUNT
]; // scaled, modified, checked and constrained values
112 uint32_t validRxSignalTimeout
[MAX_SUPPORTED_RC_CHANNEL_COUNT
];
114 #define MAX_INVALID_PULSE_TIME_MS 300 // hold time in milliseconds after bad channel or Rx link loss
115 // will not be actioned until the nearest multiple of 100ms
116 #define PPM_AND_PWM_SAMPLE_COUNT 3
118 #define DELAY_20_MS (20 * 1000) // 20ms in us
119 #define DELAY_100_MS (100 * 1000) // 100ms in us
120 #define DELAY_1500_MS (1500 * 1000) // 1.5 seconds in us
121 #define SKIP_RC_SAMPLES_ON_RESUME 2 // flush 2 samples to drop wrong measurements (timing independent)
123 rxRuntimeState_t rxRuntimeState
;
124 static uint8_t rcSampleIndex
= 0;
126 PG_REGISTER_ARRAY_WITH_RESET_FN(rxChannelRangeConfig_t
, NON_AUX_CHANNEL_COUNT
, rxChannelRangeConfigs
, PG_RX_CHANNEL_RANGE_CONFIG
, 0);
127 void pgResetFn_rxChannelRangeConfigs(rxChannelRangeConfig_t
*rxChannelRangeConfigs
)
129 // set default calibration to full range and 1:1 mapping
130 for (int i
= 0; i
< NON_AUX_CHANNEL_COUNT
; i
++) {
131 rxChannelRangeConfigs
[i
].min
= PWM_RANGE_MIN
;
132 rxChannelRangeConfigs
[i
].max
= PWM_RANGE_MAX
;
136 PG_REGISTER_ARRAY_WITH_RESET_FN(rxFailsafeChannelConfig_t
, MAX_SUPPORTED_RC_CHANNEL_COUNT
, rxFailsafeChannelConfigs
, PG_RX_FAILSAFE_CHANNEL_CONFIG
, 0);
137 void pgResetFn_rxFailsafeChannelConfigs(rxFailsafeChannelConfig_t
*rxFailsafeChannelConfigs
)
139 for (int i
= 0; i
< MAX_SUPPORTED_RC_CHANNEL_COUNT
; i
++) {
140 rxFailsafeChannelConfigs
[i
].mode
= (i
< NON_AUX_CHANNEL_COUNT
) ? RX_FAILSAFE_MODE_AUTO
: RX_FAILSAFE_MODE_HOLD
;
141 rxFailsafeChannelConfigs
[i
].step
= (i
== THROTTLE
)
142 ? CHANNEL_VALUE_TO_RXFAIL_STEP(RX_MIN_USEC
)
143 : CHANNEL_VALUE_TO_RXFAIL_STEP(RX_MID_USEC
);
147 void resetAllRxChannelRangeConfigurations(rxChannelRangeConfig_t
*rxChannelRangeConfig
)
149 // set default calibration to full range and 1:1 mapping
150 for (int i
= 0; i
< NON_AUX_CHANNEL_COUNT
; i
++) {
151 rxChannelRangeConfig
->min
= PWM_RANGE_MIN
;
152 rxChannelRangeConfig
->max
= PWM_RANGE_MAX
;
153 rxChannelRangeConfig
++;
157 static float nullReadRawRC(const rxRuntimeState_t
*rxRuntimeState
, uint8_t channel
)
159 UNUSED(rxRuntimeState
);
162 return PPM_RCVR_TIMEOUT
;
165 static uint8_t nullFrameStatus(rxRuntimeState_t
*rxRuntimeState
)
167 UNUSED(rxRuntimeState
);
169 return RX_FRAME_PENDING
;
172 static bool nullProcessFrame(const rxRuntimeState_t
*rxRuntimeState
)
174 UNUSED(rxRuntimeState
);
179 STATIC_UNIT_TESTED
bool isPulseValid(uint16_t pulseDuration
)
181 return pulseDuration
>= rxConfig()->rx_min_usec
&&
182 pulseDuration
<= rxConfig()->rx_max_usec
;
186 static bool serialRxInit(const rxConfig_t
*rxConfig
, rxRuntimeState_t
*rxRuntimeState
)
188 bool enabled
= false;
189 switch (rxRuntimeState
->serialrxProvider
) {
190 #ifdef USE_SERIALRX_SRXL2
192 enabled
= srxl2RxInit(rxConfig
, rxRuntimeState
);
195 #ifdef USE_SERIALRX_SPEKTRUM
197 case SERIALRX_SPEKTRUM1024
:
198 case SERIALRX_SPEKTRUM2048
:
199 enabled
= spektrumInit(rxConfig
, rxRuntimeState
);
202 #ifdef USE_SERIALRX_SBUS
204 enabled
= sbusInit(rxConfig
, rxRuntimeState
);
207 #ifdef USE_SERIALRX_SUMD
209 enabled
= sumdInit(rxConfig
, rxRuntimeState
);
212 #ifdef USE_SERIALRX_SUMH
214 enabled
= sumhInit(rxConfig
, rxRuntimeState
);
217 #ifdef USE_SERIALRX_XBUS
218 case SERIALRX_XBUS_MODE_B
:
219 case SERIALRX_XBUS_MODE_B_RJ01
:
220 enabled
= xBusInit(rxConfig
, rxRuntimeState
);
223 #ifdef USE_SERIALRX_IBUS
225 enabled
= ibusInit(rxConfig
, rxRuntimeState
);
228 #ifdef USE_SERIALRX_JETIEXBUS
229 case SERIALRX_JETIEXBUS
:
230 enabled
= jetiExBusInit(rxConfig
, rxRuntimeState
);
233 #ifdef USE_SERIALRX_CRSF
235 enabled
= crsfRxInit(rxConfig
, rxRuntimeState
);
238 #ifdef USE_SERIALRX_GHST
240 enabled
= ghstRxInit(rxConfig
, rxRuntimeState
);
243 #ifdef USE_SERIALRX_TARGET_CUSTOM
244 case SERIALRX_TARGET_CUSTOM
:
245 enabled
= targetCustomSerialRxInit(rxConfig
, rxRuntimeState
);
248 #ifdef USE_SERIALRX_FPORT
250 enabled
= fportRxInit(rxConfig
, rxRuntimeState
);
263 if (featureIsEnabled(FEATURE_RX_PARALLEL_PWM
)) {
264 rxRuntimeState
.rxProvider
= RX_PROVIDER_PARALLEL_PWM
;
265 } else if (featureIsEnabled(FEATURE_RX_PPM
)) {
266 rxRuntimeState
.rxProvider
= RX_PROVIDER_PPM
;
267 } else if (featureIsEnabled(FEATURE_RX_SERIAL
)) {
268 rxRuntimeState
.rxProvider
= RX_PROVIDER_SERIAL
;
269 } else if (featureIsEnabled(FEATURE_RX_MSP
)) {
270 rxRuntimeState
.rxProvider
= RX_PROVIDER_MSP
;
271 } else if (featureIsEnabled(FEATURE_RX_SPI
)) {
272 rxRuntimeState
.rxProvider
= RX_PROVIDER_SPI
;
274 rxRuntimeState
.rxProvider
= RX_PROVIDER_NONE
;
276 rxRuntimeState
.serialrxProvider
= rxConfig()->serialrx_provider
;
277 rxRuntimeState
.rcReadRawFn
= nullReadRawRC
;
278 rxRuntimeState
.rcFrameStatusFn
= nullFrameStatus
;
279 rxRuntimeState
.rcProcessFrameFn
= nullProcessFrame
;
280 rxRuntimeState
.lastRcFrameTimeUs
= 0;
283 for (int i
= 0; i
< MAX_SUPPORTED_RC_CHANNEL_COUNT
; i
++) {
284 rcData
[i
] = rxConfig()->midrc
;
285 validRxSignalTimeout
[i
] = millis() + MAX_INVALID_PULSE_TIME_MS
;
288 rcData
[THROTTLE
] = (featureIsEnabled(FEATURE_3D
)) ? rxConfig()->midrc
: rxConfig()->rx_min_usec
;
290 // Initialize ARM switch to OFF position when arming via switch is defined
291 // TODO - move to rc_mode.c
292 for (int i
= 0; i
< MAX_MODE_ACTIVATION_CONDITION_COUNT
; i
++) {
293 const modeActivationCondition_t
*modeActivationCondition
= modeActivationConditions(i
);
294 if (modeActivationCondition
->modeId
== BOXARM
&& IS_RANGE_USABLE(&modeActivationCondition
->range
)) {
295 // ARM switch is defined, determine an OFF value
297 if (modeActivationCondition
->range
.startStep
> 0) {
298 value
= MODE_STEP_TO_CHANNEL_VALUE((modeActivationCondition
->range
.startStep
- 1));
300 value
= MODE_STEP_TO_CHANNEL_VALUE((modeActivationCondition
->range
.endStep
+ 1));
302 // Initialize ARM AUX channel to OFF value
303 rcData
[modeActivationCondition
->auxChannelIndex
+ NON_AUX_CHANNEL_COUNT
] = value
;
307 switch (rxRuntimeState
.rxProvider
) {
312 case RX_PROVIDER_SERIAL
:
314 const bool enabled
= serialRxInit(rxConfig(), &rxRuntimeState
);
316 rxRuntimeState
.rcReadRawFn
= nullReadRawRC
;
317 rxRuntimeState
.rcFrameStatusFn
= nullFrameStatus
;
325 case RX_PROVIDER_MSP
:
326 rxMspInit(rxConfig(), &rxRuntimeState
);
332 case RX_PROVIDER_SPI
:
334 const bool enabled
= rxSpiInit(rxSpiConfig(), &rxRuntimeState
);
336 rxRuntimeState
.rcReadRawFn
= nullReadRawRC
;
337 rxRuntimeState
.rcFrameStatusFn
= nullFrameStatus
;
344 #if defined(USE_PWM) || defined(USE_PPM)
345 case RX_PROVIDER_PPM
:
346 case RX_PROVIDER_PARALLEL_PWM
:
347 rxPwmInit(rxConfig(), &rxRuntimeState
);
354 if (featureIsEnabled(FEATURE_RSSI_ADC
)) {
355 rssiSource
= RSSI_SOURCE_ADC
;
358 if (rxConfig()->rssi_channel
> 0) {
359 rssiSource
= RSSI_SOURCE_RX_CHANNEL
;
362 // Setup source frame RSSI filtering to take averaged values every FRAME_ERR_RESAMPLE_US
363 pt1FilterInit(&frameErrFilter
, pt1FilterGain(GET_FRAME_ERR_LPF_FREQUENCY(rxConfig()->rssi_src_frame_lpf_period
), FRAME_ERR_RESAMPLE_US
/1000000.0));
365 rxChannelCount
= MIN(rxConfig()->max_aux_channel
+ NON_AUX_CHANNEL_COUNT
, rxRuntimeState
.channelCount
);
368 bool rxIsReceivingSignal(void)
370 return rxSignalReceived
;
373 bool rxAreFlightChannelsValid(void)
375 return rxFlightChannelsValid
;
378 void suspendRxSignal(void)
380 #if defined(USE_PWM) || defined(USE_PPM)
381 if (rxRuntimeState
.rxProvider
== RX_PROVIDER_PARALLEL_PWM
|| rxRuntimeState
.rxProvider
== RX_PROVIDER_PPM
) {
382 suspendRxSignalUntil
= micros() + DELAY_1500_MS
; // 1.5s
383 skipRxSamples
= SKIP_RC_SAMPLES_ON_RESUME
;
386 failsafeOnRxSuspend(DELAY_1500_MS
); // 1.5s
389 void resumeRxSignal(void)
391 #if defined(USE_PWM) || defined(USE_PPM)
392 if (rxRuntimeState
.rxProvider
== RX_PROVIDER_PARALLEL_PWM
|| rxRuntimeState
.rxProvider
== RX_PROVIDER_PPM
) {
393 suspendRxSignalUntil
= micros();
394 skipRxSamples
= SKIP_RC_SAMPLES_ON_RESUME
;
397 failsafeOnRxResume();
400 #ifdef USE_RX_LINK_QUALITY_INFO
401 #define LINK_QUALITY_SAMPLE_COUNT 16
403 STATIC_UNIT_TESTED
uint16_t updateLinkQualitySamples(uint16_t value
)
405 static uint16_t samples
[LINK_QUALITY_SAMPLE_COUNT
];
406 static uint8_t sampleIndex
= 0;
407 static uint16_t sum
= 0;
409 sum
+= value
- samples
[sampleIndex
];
410 samples
[sampleIndex
] = value
;
411 sampleIndex
= (sampleIndex
+ 1) % LINK_QUALITY_SAMPLE_COUNT
;
412 return sum
/ LINK_QUALITY_SAMPLE_COUNT
;
415 void rxSetRfMode(uint8_t rfModeValue
)
417 rfMode
= rfModeValue
;
421 static void setLinkQuality(bool validFrame
, timeDelta_t currentDeltaTimeUs
)
423 static uint16_t rssiSum
= 0;
424 static uint16_t rssiCount
= 0;
425 static timeDelta_t resampleTimeUs
= 0;
427 #ifdef USE_RX_LINK_QUALITY_INFO
428 if (linkQualitySource
== LQ_SOURCE_NONE
) {
429 // calculate new sample mean
430 linkQuality
= updateLinkQualitySamples(validFrame
? LINK_QUALITY_MAX_VALUE
: 0);
434 if (rssiSource
== RSSI_SOURCE_FRAME_ERRORS
) {
435 resampleTimeUs
+= currentDeltaTimeUs
;
436 rssiSum
+= validFrame
? RSSI_MAX_VALUE
: 0;
439 if (resampleTimeUs
>= FRAME_ERR_RESAMPLE_US
) {
440 setRssi(rssiSum
/ rssiCount
, rssiSource
);
443 resampleTimeUs
-= FRAME_ERR_RESAMPLE_US
;
448 void setLinkQualityDirect(uint16_t linkqualityValue
)
450 #ifdef USE_RX_LINK_QUALITY_INFO
451 linkQuality
= linkqualityValue
;
453 UNUSED(linkqualityValue
);
457 #ifdef USE_RX_LINK_UPLINK_POWER
458 void rxSetUplinkTxPwrMw(uint16_t uplinkTxPwrMwValue
)
460 uplinkTxPwrMw
= uplinkTxPwrMwValue
;
464 bool rxUpdateCheck(timeUs_t currentTimeUs
, timeDelta_t currentDeltaTimeUs
)
466 UNUSED(currentTimeUs
);
467 UNUSED(currentDeltaTimeUs
);
469 return taskUpdateRxMainInProgress() || rxDataProcessingRequired
|| auxiliaryProcessingRequired
;
472 FAST_CODE_NOINLINE
void rxFrameCheck(timeUs_t currentTimeUs
, timeDelta_t currentDeltaTimeUs
)
474 bool signalReceived
= false;
475 bool useDataDrivenProcessing
= true;
476 timeDelta_t needRxSignalMaxDelayUs
= DELAY_100_MS
;
478 DEBUG_SET(DEBUG_RX_SIGNAL_LOSS
, 2, MIN(2000, currentDeltaTimeUs
/ 100));
480 if (taskUpdateRxMainInProgress()) {
481 // no need to check for new data as a packet is being processed already
485 switch (rxRuntimeState
.rxProvider
) {
489 #if defined(USE_PWM) || defined(USE_PPM)
490 case RX_PROVIDER_PPM
:
491 if (isPPMDataBeingReceived()) {
492 signalReceived
= true;
493 resetPPMDataReceivedState();
497 case RX_PROVIDER_PARALLEL_PWM
:
498 if (isPWMDataBeingReceived()) {
499 signalReceived
= true;
500 useDataDrivenProcessing
= false;
505 case RX_PROVIDER_SERIAL
:
506 case RX_PROVIDER_MSP
:
507 case RX_PROVIDER_SPI
:
509 const uint8_t frameStatus
= rxRuntimeState
.rcFrameStatusFn(&rxRuntimeState
);
510 DEBUG_SET(DEBUG_RX_SIGNAL_LOSS
, 1, (frameStatus
& RX_FRAME_FAILSAFE
));
511 signalReceived
= (frameStatus
& RX_FRAME_COMPLETE
) && !(frameStatus
& (RX_FRAME_FAILSAFE
| RX_FRAME_DROPPED
));
512 setLinkQuality(signalReceived
, currentDeltaTimeUs
);
513 auxiliaryProcessingRequired
|= (frameStatus
& RX_FRAME_PROCESSING_REQUIRED
);
519 if (signalReceived
) {
520 // true only when a new packet arrives
521 needRxSignalBefore
= currentTimeUs
+ needRxSignalMaxDelayUs
;
522 rxSignalReceived
= true; // immediately process packet data
523 if (useDataDrivenProcessing
) {
524 rxDataProcessingRequired
= true;
525 // process the new Rx packet when it arrives
528 // watch for next packet
529 if (cmpTimeUs(currentTimeUs
, needRxSignalBefore
) > 0) {
530 // initial time to signalReceived failure is 100ms, then we check every 100ms
531 rxSignalReceived
= false;
532 needRxSignalBefore
= currentTimeUs
+ needRxSignalMaxDelayUs
;
533 // review and process rcData values every 100ms in case failsafe changed them
534 rxDataProcessingRequired
= true;
538 DEBUG_SET(DEBUG_RX_SIGNAL_LOSS
, 0, rxSignalReceived
);
541 #if defined(USE_PWM) || defined(USE_PPM)
542 static uint16_t calculateChannelMovingAverage(uint8_t chan
, uint16_t sample
)
544 static int16_t rcSamples
[MAX_SUPPORTED_RX_PARALLEL_PWM_OR_PPM_CHANNEL_COUNT
][PPM_AND_PWM_SAMPLE_COUNT
];
545 static int16_t rcDataMean
[MAX_SUPPORTED_RX_PARALLEL_PWM_OR_PPM_CHANNEL_COUNT
];
546 static bool rxSamplesCollected
= false;
548 const uint8_t currentSampleIndex
= rcSampleIndex
% PPM_AND_PWM_SAMPLE_COUNT
;
550 // update the recent samples and compute the average of them
551 rcSamples
[chan
][currentSampleIndex
] = sample
;
553 // avoid returning an incorrect average which would otherwise occur before enough samples
554 if (!rxSamplesCollected
) {
555 if (rcSampleIndex
< PPM_AND_PWM_SAMPLE_COUNT
) {
558 rxSamplesCollected
= true;
561 rcDataMean
[chan
] = 0;
562 for (int sampleIndex
= 0; sampleIndex
< PPM_AND_PWM_SAMPLE_COUNT
; sampleIndex
++) {
563 rcDataMean
[chan
] += rcSamples
[chan
][sampleIndex
];
565 return rcDataMean
[chan
] / PPM_AND_PWM_SAMPLE_COUNT
;
569 static uint16_t getRxfailValue(uint8_t channel
)
571 const rxFailsafeChannelConfig_t
*channelFailsafeConfig
= rxFailsafeChannelConfigs(channel
);
572 const bool failsafeAuxSwitch
= IS_RC_MODE_ACTIVE(BOXFAILSAFE
);
574 switch (channelFailsafeConfig
->mode
) {
575 case RX_FAILSAFE_MODE_AUTO
:
580 return rxConfig()->midrc
;
582 if (featureIsEnabled(FEATURE_3D
) && !IS_RC_MODE_ACTIVE(BOX3D
) && !flight3DConfig()->switched_mode3d
) {
583 return rxConfig()->midrc
;
585 return rxConfig()->rx_min_usec
;
591 case RX_FAILSAFE_MODE_INVALID
:
592 case RX_FAILSAFE_MODE_HOLD
:
593 if (failsafeAuxSwitch
) {
594 return rcRaw
[channel
]; // current values are allowed through on held channels with switch induced failsafe
596 return rcData
[channel
]; // last good value
598 case RX_FAILSAFE_MODE_SET
:
599 return RXFAIL_STEP_TO_CHANNEL_VALUE(channelFailsafeConfig
->step
);
603 STATIC_UNIT_TESTED
float applyRxChannelRangeConfiguraton(float sample
, const rxChannelRangeConfig_t
*range
)
605 // Avoid corruption of channel with a value of PPM_RCVR_TIMEOUT
606 if (sample
== PPM_RCVR_TIMEOUT
) {
607 return PPM_RCVR_TIMEOUT
;
610 sample
= scaleRangef(sample
, range
->min
, range
->max
, PWM_RANGE_MIN
, PWM_RANGE_MAX
);
611 // out of range channel values are now constrained after the validity check in detectAndApplySignalLossBehaviour()
615 static void readRxChannelsApplyRanges(void)
617 for (int channel
= 0; channel
< rxChannelCount
; channel
++) {
619 const uint8_t rawChannel
= channel
< RX_MAPPABLE_CHANNEL_COUNT
? rxConfig()->rcmap
[channel
] : channel
;
621 // sample the channel
623 #if defined(USE_RX_MSP_OVERRIDE)
624 if (rxConfig()->msp_override_channels_mask
) {
625 sample
= rxMspOverrideReadRawRc(&rxRuntimeState
, rxConfig(), rawChannel
);
629 sample
= rxRuntimeState
.rcReadRawFn(&rxRuntimeState
, rawChannel
);
632 // apply the rx calibration
633 if (channel
< NON_AUX_CHANNEL_COUNT
) {
634 sample
= applyRxChannelRangeConfiguraton(sample
, rxChannelRangeConfigs(channel
));
637 rcRaw
[channel
] = sample
;
641 void detectAndApplySignalLossBehaviour(void)
643 const uint32_t currentTimeMs
= millis();
644 const bool failsafeAuxSwitch
= IS_RC_MODE_ACTIVE(BOXFAILSAFE
);
645 rxFlightChannelsValid
= rxSignalReceived
&& !failsafeAuxSwitch
;
646 // set rxFlightChannelsValid false when a packet is bad or we use a failsafe switch
648 for (int channel
= 0; channel
< rxChannelCount
; channel
++) {
649 float sample
= rcRaw
[channel
]; // sample has latest RC value, rcData has last 'accepted valid' value
650 const bool thisChannelValid
= rxFlightChannelsValid
&& isPulseValid(sample
);
651 // if the whole packet is bad, consider all channels bad
653 if (thisChannelValid
) {
654 // reset the invalid pulse period timer for every good channel
655 validRxSignalTimeout
[channel
] = currentTimeMs
+ MAX_INVALID_PULSE_TIME_MS
;
658 if (ARMING_FLAG(ARMED
) && failsafeIsActive()) {
659 // while in failsafe Stage 2, whether Rx loss or switch induced, pass valid incoming flight channel values
660 // this allows GPS Rescue to detect the 30% requirement for termination
661 if (channel
< NON_AUX_CHANNEL_COUNT
) {
662 if (!thisChannelValid
) {
663 if (channel
== THROTTLE
) {
664 sample
= failsafeConfig()->failsafe_throttle
; // stage 2 failsafe throttle value
666 sample
= rxConfig()->midrc
;
670 // During Stage 2, set aux channels as per Stage 1 configuration
671 sample
= getRxfailValue(channel
);
674 if (failsafeAuxSwitch
) {
675 sample
= getRxfailValue(channel
);
676 // set channels to Stage 1 values immediately failsafe switch is activated
677 } else if (!thisChannelValid
) {
678 // everything was normal and this channel was invalid
679 if (cmp32(currentTimeMs
, validRxSignalTimeout
[channel
]) < 0) {
680 // first 300ms of Stage 1 failsafe
681 sample
= rcData
[channel
];
682 // HOLD last valid value on bad channel/s for MAX_INVALID_PULSE_TIME_MS (300ms)
684 // remaining Stage 1 failsafe period after 300ms
685 if (channel
< NON_AUX_CHANNEL_COUNT
) {
686 rxFlightChannelsValid
= false;
687 // declare signal lost after 300ms of any one bad flight channel
689 sample
= getRxfailValue(channel
);
690 // set channels that are invalid for more than 300ms to Stage 1 values
695 sample
= constrainf(sample
, PWM_PULSE_MIN
, PWM_PULSE_MAX
);
697 #if defined(USE_PWM) || defined(USE_PPM)
698 if (rxRuntimeState
.rxProvider
== RX_PROVIDER_PARALLEL_PWM
|| rxRuntimeState
.rxProvider
== RX_PROVIDER_PPM
) {
699 // smooth output for PWM and PPM using moving average
700 rcData
[channel
] = calculateChannelMovingAverage(channel
, sample
);
705 // set rcData to either validated incoming values, or failsafe-modified values
706 rcData
[channel
] = sample
;
710 if (rxFlightChannelsValid
) {
711 failsafeOnValidDataReceived();
712 // --> start the timer to exit stage 2 failsafe
714 failsafeOnValidDataFailed();
715 // -> start timer to enter stage2 failsafe
718 DEBUG_SET(DEBUG_RX_SIGNAL_LOSS
, 3, rcData
[THROTTLE
]);
721 bool calculateRxChannelsAndUpdateFailsafe(timeUs_t currentTimeUs
)
723 if (auxiliaryProcessingRequired
) {
724 auxiliaryProcessingRequired
= !rxRuntimeState
.rcProcessFrameFn(&rxRuntimeState
);
727 if (!rxDataProcessingRequired
) {
731 rxDataProcessingRequired
= false;
733 // only proceed when no more samples to skip and suspend period is over
734 if (skipRxSamples
|| currentTimeUs
<= suspendRxSignalUntil
) {
735 if (currentTimeUs
> suspendRxSignalUntil
) {
742 readRxChannelsApplyRanges(); // returns rcRaw
743 detectAndApplySignalLossBehaviour(); // returns rcData
750 void parseRcChannels(const char *input
, rxConfig_t
*rxConfig
)
752 for (const char *c
= input
; *c
; c
++) {
753 const char *s
= strchr(rcChannelLetters
, *c
);
754 if (s
&& (s
< rcChannelLetters
+ RX_MAPPABLE_CHANNEL_COUNT
)) {
755 rxConfig
->rcmap
[s
- rcChannelLetters
] = c
- input
;
760 void setRssiDirect(uint16_t newRssi
, rssiSource_e source
)
762 if (source
!= rssiSource
) {
769 #define RSSI_SAMPLE_COUNT 16
771 static uint16_t updateRssiSamples(uint16_t value
)
773 static uint16_t samples
[RSSI_SAMPLE_COUNT
];
774 static uint8_t sampleIndex
= 0;
775 static unsigned sum
= 0;
777 sum
+= value
- samples
[sampleIndex
];
778 samples
[sampleIndex
] = value
;
779 sampleIndex
= (sampleIndex
+ 1) % RSSI_SAMPLE_COUNT
;
780 return sum
/ RSSI_SAMPLE_COUNT
;
783 void setRssi(uint16_t rssiValue
, rssiSource_e source
)
785 if (source
!= rssiSource
) {
790 if (source
== RSSI_SOURCE_FRAME_ERRORS
) {
791 rssi
= pt1FilterApply(&frameErrFilter
, rssiValue
);
793 // calculate new sample mean
794 rssi
= updateRssiSamples(rssiValue
);
798 void setRssiMsp(uint8_t newMspRssi
)
800 if (rssiSource
== RSSI_SOURCE_NONE
) {
801 rssiSource
= RSSI_SOURCE_MSP
;
804 if (rssiSource
== RSSI_SOURCE_MSP
) {
805 rssi
= ((uint16_t)newMspRssi
) << 2;
806 lastMspRssiUpdateUs
= micros();
810 static void updateRSSIPWM(void)
812 // Read value of AUX channel as rssi
813 int16_t pwmRssi
= rcData
[rxConfig()->rssi_channel
- 1];
815 // Range of rawPwmRssi is [1000;2000]. rssi should be in [0;1023];
816 setRssiDirect(scaleRange(constrain(pwmRssi
, PWM_RANGE_MIN
, PWM_RANGE_MAX
), PWM_RANGE_MIN
, PWM_RANGE_MAX
, 0, RSSI_MAX_VALUE
), RSSI_SOURCE_RX_CHANNEL
);
819 static void updateRSSIADC(timeUs_t currentTimeUs
)
822 UNUSED(currentTimeUs
);
824 static uint32_t rssiUpdateAt
= 0;
826 if ((int32_t)(currentTimeUs
- rssiUpdateAt
) < 0) {
829 rssiUpdateAt
= currentTimeUs
+ DELAY_20_MS
;
831 const uint16_t adcRssiSample
= adcGetChannel(ADC_RSSI
);
832 uint16_t rssiValue
= adcRssiSample
/ RSSI_ADC_DIVISOR
;
834 setRssi(rssiValue
, RSSI_SOURCE_ADC
);
838 void updateRSSI(timeUs_t currentTimeUs
)
840 switch (rssiSource
) {
841 case RSSI_SOURCE_RX_CHANNEL
:
844 case RSSI_SOURCE_ADC
:
845 updateRSSIADC(currentTimeUs
);
847 case RSSI_SOURCE_MSP
:
848 if (cmpTimeUs(micros(), lastMspRssiUpdateUs
) > DELAY_1500_MS
) { // 1.5s
857 uint16_t getRssi(void)
859 uint16_t rssiValue
= rssi
;
861 // RSSI_Invert option
862 if (rxConfig()->rssi_invert
) {
863 rssiValue
= RSSI_MAX_VALUE
- rssiValue
;
866 return rxConfig()->rssi_scale
/ 100.0f
* rssiValue
+ rxConfig()->rssi_offset
* RSSI_OFFSET_SCALING
;
869 uint8_t getRssiPercent(void)
871 return scaleRange(getRssi(), 0, RSSI_MAX_VALUE
, 0, 100);
874 int16_t getRssiDbm(void)
879 #define RSSI_SAMPLE_COUNT_DBM 16
881 static int16_t updateRssiDbmSamples(int16_t value
)
883 static int16_t samplesdbm
[RSSI_SAMPLE_COUNT_DBM
];
884 static uint8_t sampledbmIndex
= 0;
885 static int sumdbm
= 0;
887 sumdbm
+= value
- samplesdbm
[sampledbmIndex
];
888 samplesdbm
[sampledbmIndex
] = value
;
889 sampledbmIndex
= (sampledbmIndex
+ 1) % RSSI_SAMPLE_COUNT_DBM
;
890 return sumdbm
/ RSSI_SAMPLE_COUNT_DBM
;
893 void setRssiDbm(int16_t rssiDbmValue
, rssiSource_e source
)
895 if (source
!= rssiSource
) {
899 rssiDbm
= updateRssiDbmSamples(rssiDbmValue
);
902 void setRssiDbmDirect(int16_t newRssiDbm
, rssiSource_e source
)
904 if (source
!= rssiSource
) {
908 rssiDbm
= newRssiDbm
;
911 #ifdef USE_RX_LINK_QUALITY_INFO
912 uint16_t rxGetLinkQuality(void)
917 uint8_t rxGetRfMode(void)
922 uint16_t rxGetLinkQualityPercent(void)
924 return (linkQualitySource
== LQ_SOURCE_NONE
) ? scaleRange(linkQuality
, 0, LINK_QUALITY_MAX_VALUE
, 0, 100) : linkQuality
;
928 #ifdef USE_RX_LINK_UPLINK_POWER
929 uint16_t rxGetUplinkTxPwrMw(void)
931 return uplinkTxPwrMw
;
935 bool isRssiConfigured(void)
937 return rssiSource
!= RSSI_SOURCE_NONE
;
940 timeDelta_t
rxGetFrameDelta(timeDelta_t
*frameAgeUs
)
942 static timeUs_t previousFrameTimeUs
= 0;
943 static timeDelta_t frameTimeDeltaUs
= 0;
945 if (rxRuntimeState
.rcFrameTimeUsFn
) {
946 const timeUs_t frameTimeUs
= rxRuntimeState
.rcFrameTimeUsFn();
948 *frameAgeUs
= cmpTimeUs(micros(), frameTimeUs
);
950 const timeDelta_t deltaUs
= cmpTimeUs(frameTimeUs
, previousFrameTimeUs
);
952 frameTimeDeltaUs
= deltaUs
;
953 previousFrameTimeUs
= frameTimeUs
;
957 return frameTimeDeltaUs
;
960 timeUs_t
rxFrameTimeUs(void)
962 return rxRuntimeState
.lastRcFrameTimeUs
;