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 MSP_RSSI_TIMEOUT_US 1500000 // 1.5 sec
95 #define RSSI_ADC_DIVISOR (4096 / 1024)
96 #define RSSI_OFFSET_SCALING (1024 / 100.0f)
98 rssiSource_e rssiSource
;
99 linkQualitySource_e linkQualitySource
;
101 static bool rxDataProcessingRequired
= false;
102 static bool auxiliaryProcessingRequired
= false;
104 static bool rxSignalReceived
= false;
105 static bool rxFlightChannelsValid
= false;
106 static bool rxIsInFailsafeMode
= true;
107 static uint8_t rxChannelCount
;
109 static timeUs_t needRxSignalBefore
= 0;
110 static timeUs_t suspendRxSignalUntil
= 0;
111 static uint8_t skipRxSamples
= 0;
113 static float rcRaw
[MAX_SUPPORTED_RC_CHANNEL_COUNT
]; // interval [1000;2000]
114 float rcData
[MAX_SUPPORTED_RC_CHANNEL_COUNT
]; // interval [1000;2000]
115 uint32_t validRxSignalTimeout
[MAX_SUPPORTED_RC_CHANNEL_COUNT
];
117 #define MAX_INVALID_PULSE_TIME 300 // hold time in millisecons after bad channel or Rx link loss
118 #define PPM_AND_PWM_SAMPLE_COUNT 3
120 #define DELAY_50_HZ (1000000 / 50)
121 #define DELAY_33_HZ (1000000 / 33)
122 #define DELAY_15_HZ (1000000 / 15)
123 #define DELAY_10_HZ (1000000 / 10)
124 #define DELAY_5_HZ (1000000 / 5)
125 #define SKIP_RC_ON_SUSPEND_PERIOD 1500000 // 1.5 second period in usec (call frequency independent)
126 #define SKIP_RC_SAMPLES_ON_RESUME 2 // flush 2 samples to drop wrong measurements (timing independent)
128 rxRuntimeState_t rxRuntimeState
;
129 static uint8_t rcSampleIndex
= 0;
131 PG_REGISTER_ARRAY_WITH_RESET_FN(rxChannelRangeConfig_t
, NON_AUX_CHANNEL_COUNT
, rxChannelRangeConfigs
, PG_RX_CHANNEL_RANGE_CONFIG
, 0);
132 void pgResetFn_rxChannelRangeConfigs(rxChannelRangeConfig_t
*rxChannelRangeConfigs
)
134 // set default calibration to full range and 1:1 mapping
135 for (int i
= 0; i
< NON_AUX_CHANNEL_COUNT
; i
++) {
136 rxChannelRangeConfigs
[i
].min
= PWM_RANGE_MIN
;
137 rxChannelRangeConfigs
[i
].max
= PWM_RANGE_MAX
;
141 PG_REGISTER_ARRAY_WITH_RESET_FN(rxFailsafeChannelConfig_t
, MAX_SUPPORTED_RC_CHANNEL_COUNT
, rxFailsafeChannelConfigs
, PG_RX_FAILSAFE_CHANNEL_CONFIG
, 0);
142 void pgResetFn_rxFailsafeChannelConfigs(rxFailsafeChannelConfig_t
*rxFailsafeChannelConfigs
)
144 for (int i
= 0; i
< MAX_SUPPORTED_RC_CHANNEL_COUNT
; i
++) {
145 rxFailsafeChannelConfigs
[i
].mode
= (i
< NON_AUX_CHANNEL_COUNT
) ? RX_FAILSAFE_MODE_AUTO
: RX_FAILSAFE_MODE_HOLD
;
146 rxFailsafeChannelConfigs
[i
].step
= (i
== THROTTLE
)
147 ? CHANNEL_VALUE_TO_RXFAIL_STEP(RX_MIN_USEC
)
148 : CHANNEL_VALUE_TO_RXFAIL_STEP(RX_MID_USEC
);
152 void resetAllRxChannelRangeConfigurations(rxChannelRangeConfig_t
*rxChannelRangeConfig
) {
153 // set default calibration to full range and 1:1 mapping
154 for (int i
= 0; i
< NON_AUX_CHANNEL_COUNT
; i
++) {
155 rxChannelRangeConfig
->min
= PWM_RANGE_MIN
;
156 rxChannelRangeConfig
->max
= PWM_RANGE_MAX
;
157 rxChannelRangeConfig
++;
161 static float nullReadRawRC(const rxRuntimeState_t
*rxRuntimeState
, uint8_t channel
)
163 UNUSED(rxRuntimeState
);
166 return PPM_RCVR_TIMEOUT
;
169 static uint8_t nullFrameStatus(rxRuntimeState_t
*rxRuntimeState
)
171 UNUSED(rxRuntimeState
);
173 return RX_FRAME_PENDING
;
176 static bool nullProcessFrame(const rxRuntimeState_t
*rxRuntimeState
)
178 UNUSED(rxRuntimeState
);
183 STATIC_UNIT_TESTED
bool isPulseValid(uint16_t pulseDuration
)
185 return pulseDuration
>= rxConfig()->rx_min_usec
&&
186 pulseDuration
<= rxConfig()->rx_max_usec
;
190 static bool serialRxInit(const rxConfig_t
*rxConfig
, rxRuntimeState_t
*rxRuntimeState
)
192 bool enabled
= false;
193 switch (rxRuntimeState
->serialrxProvider
) {
194 #ifdef USE_SERIALRX_SRXL2
196 enabled
= srxl2RxInit(rxConfig
, rxRuntimeState
);
199 #ifdef USE_SERIALRX_SPEKTRUM
201 case SERIALRX_SPEKTRUM1024
:
202 case SERIALRX_SPEKTRUM2048
:
203 enabled
= spektrumInit(rxConfig
, rxRuntimeState
);
206 #ifdef USE_SERIALRX_SBUS
208 enabled
= sbusInit(rxConfig
, rxRuntimeState
);
211 #ifdef USE_SERIALRX_SUMD
213 enabled
= sumdInit(rxConfig
, rxRuntimeState
);
216 #ifdef USE_SERIALRX_SUMH
218 enabled
= sumhInit(rxConfig
, rxRuntimeState
);
221 #ifdef USE_SERIALRX_XBUS
222 case SERIALRX_XBUS_MODE_B
:
223 case SERIALRX_XBUS_MODE_B_RJ01
:
224 enabled
= xBusInit(rxConfig
, rxRuntimeState
);
227 #ifdef USE_SERIALRX_IBUS
229 enabled
= ibusInit(rxConfig
, rxRuntimeState
);
232 #ifdef USE_SERIALRX_JETIEXBUS
233 case SERIALRX_JETIEXBUS
:
234 enabled
= jetiExBusInit(rxConfig
, rxRuntimeState
);
237 #ifdef USE_SERIALRX_CRSF
239 enabled
= crsfRxInit(rxConfig
, rxRuntimeState
);
242 #ifdef USE_SERIALRX_GHST
244 enabled
= ghstRxInit(rxConfig
, rxRuntimeState
);
247 #ifdef USE_SERIALRX_TARGET_CUSTOM
248 case SERIALRX_TARGET_CUSTOM
:
249 enabled
= targetCustomSerialRxInit(rxConfig
, rxRuntimeState
);
252 #ifdef USE_SERIALRX_FPORT
254 enabled
= fportRxInit(rxConfig
, rxRuntimeState
);
267 if (featureIsEnabled(FEATURE_RX_PARALLEL_PWM
)) {
268 rxRuntimeState
.rxProvider
= RX_PROVIDER_PARALLEL_PWM
;
269 } else if (featureIsEnabled(FEATURE_RX_PPM
)) {
270 rxRuntimeState
.rxProvider
= RX_PROVIDER_PPM
;
271 } else if (featureIsEnabled(FEATURE_RX_SERIAL
)) {
272 rxRuntimeState
.rxProvider
= RX_PROVIDER_SERIAL
;
273 } else if (featureIsEnabled(FEATURE_RX_MSP
)) {
274 rxRuntimeState
.rxProvider
= RX_PROVIDER_MSP
;
275 } else if (featureIsEnabled(FEATURE_RX_SPI
)) {
276 rxRuntimeState
.rxProvider
= RX_PROVIDER_SPI
;
278 rxRuntimeState
.rxProvider
= RX_PROVIDER_NONE
;
280 rxRuntimeState
.serialrxProvider
= rxConfig()->serialrx_provider
;
281 rxRuntimeState
.rcReadRawFn
= nullReadRawRC
;
282 rxRuntimeState
.rcFrameStatusFn
= nullFrameStatus
;
283 rxRuntimeState
.rcProcessFrameFn
= nullProcessFrame
;
284 rxRuntimeState
.lastRcFrameTimeUs
= 0;
287 for (int i
= 0; i
< MAX_SUPPORTED_RC_CHANNEL_COUNT
; i
++) {
288 rcData
[i
] = rxConfig()->midrc
;
289 validRxSignalTimeout
[i
] = millis() + MAX_INVALID_PULSE_TIME
;
292 rcData
[THROTTLE
] = (featureIsEnabled(FEATURE_3D
)) ? rxConfig()->midrc
: rxConfig()->rx_min_usec
;
294 // Initialize ARM switch to OFF position when arming via switch is defined
295 // TODO - move to rc_mode.c
296 for (int i
= 0; i
< MAX_MODE_ACTIVATION_CONDITION_COUNT
; i
++) {
297 const modeActivationCondition_t
*modeActivationCondition
= modeActivationConditions(i
);
298 if (modeActivationCondition
->modeId
== BOXARM
&& IS_RANGE_USABLE(&modeActivationCondition
->range
)) {
299 // ARM switch is defined, determine an OFF value
301 if (modeActivationCondition
->range
.startStep
> 0) {
302 value
= MODE_STEP_TO_CHANNEL_VALUE((modeActivationCondition
->range
.startStep
- 1));
304 value
= MODE_STEP_TO_CHANNEL_VALUE((modeActivationCondition
->range
.endStep
+ 1));
306 // Initialize ARM AUX channel to OFF value
307 rcData
[modeActivationCondition
->auxChannelIndex
+ NON_AUX_CHANNEL_COUNT
] = value
;
311 switch (rxRuntimeState
.rxProvider
) {
316 case RX_PROVIDER_SERIAL
:
318 const bool enabled
= serialRxInit(rxConfig(), &rxRuntimeState
);
320 rxRuntimeState
.rcReadRawFn
= nullReadRawRC
;
321 rxRuntimeState
.rcFrameStatusFn
= nullFrameStatus
;
329 case RX_PROVIDER_MSP
:
330 rxMspInit(rxConfig(), &rxRuntimeState
);
336 case RX_PROVIDER_SPI
:
338 const bool enabled
= rxSpiInit(rxSpiConfig(), &rxRuntimeState
);
340 rxRuntimeState
.rcReadRawFn
= nullReadRawRC
;
341 rxRuntimeState
.rcFrameStatusFn
= nullFrameStatus
;
348 #if defined(USE_PWM) || defined(USE_PPM)
349 case RX_PROVIDER_PPM
:
350 case RX_PROVIDER_PARALLEL_PWM
:
351 rxPwmInit(rxConfig(), &rxRuntimeState
);
358 if (featureIsEnabled(FEATURE_RSSI_ADC
)) {
359 rssiSource
= RSSI_SOURCE_ADC
;
362 if (rxConfig()->rssi_channel
> 0) {
363 rssiSource
= RSSI_SOURCE_RX_CHANNEL
;
366 // Setup source frame RSSI filtering to take averaged values every FRAME_ERR_RESAMPLE_US
367 pt1FilterInit(&frameErrFilter
, pt1FilterGain(GET_FRAME_ERR_LPF_FREQUENCY(rxConfig()->rssi_src_frame_lpf_period
), FRAME_ERR_RESAMPLE_US
/1000000.0));
369 rxChannelCount
= MIN(rxConfig()->max_aux_channel
+ NON_AUX_CHANNEL_COUNT
, rxRuntimeState
.channelCount
);
372 bool rxIsReceivingSignal(void)
374 return rxSignalReceived
;
377 bool rxAreFlightChannelsValid(void)
379 return rxFlightChannelsValid
;
382 void suspendRxPwmPpmSignal(void)
384 #if defined(USE_PWM) || defined(USE_PPM)
385 if (rxRuntimeState
.rxProvider
== RX_PROVIDER_PARALLEL_PWM
|| rxRuntimeState
.rxProvider
== RX_PROVIDER_PPM
) {
386 suspendRxSignalUntil
= micros() + SKIP_RC_ON_SUSPEND_PERIOD
;
387 skipRxSamples
= SKIP_RC_SAMPLES_ON_RESUME
;
388 failsafeOnRxSuspend(SKIP_RC_ON_SUSPEND_PERIOD
);
393 void resumeRxPwmPpmSignal(void)
395 #if defined(USE_PWM) || defined(USE_PPM)
396 if (rxRuntimeState
.rxProvider
== RX_PROVIDER_PARALLEL_PWM
|| rxRuntimeState
.rxProvider
== RX_PROVIDER_PPM
) {
397 suspendRxSignalUntil
= micros();
398 skipRxSamples
= SKIP_RC_SAMPLES_ON_RESUME
;
399 failsafeOnRxResume();
404 #ifdef USE_RX_LINK_QUALITY_INFO
405 #define LINK_QUALITY_SAMPLE_COUNT 16
407 STATIC_UNIT_TESTED
uint16_t updateLinkQualitySamples(uint16_t value
)
409 static uint16_t samples
[LINK_QUALITY_SAMPLE_COUNT
];
410 static uint8_t sampleIndex
= 0;
411 static uint16_t sum
= 0;
413 sum
+= value
- samples
[sampleIndex
];
414 samples
[sampleIndex
] = value
;
415 sampleIndex
= (sampleIndex
+ 1) % LINK_QUALITY_SAMPLE_COUNT
;
416 return sum
/ LINK_QUALITY_SAMPLE_COUNT
;
419 void rxSetRfMode(uint8_t rfModeValue
)
421 rfMode
= rfModeValue
;
425 static void setLinkQuality(bool validFrame
, timeDelta_t currentDeltaTimeUs
)
427 static uint16_t rssiSum
= 0;
428 static uint16_t rssiCount
= 0;
429 static timeDelta_t resampleTimeUs
= 0;
431 #ifdef USE_RX_LINK_QUALITY_INFO
432 if (linkQualitySource
== LQ_SOURCE_NONE
) {
433 // calculate new sample mean
434 linkQuality
= updateLinkQualitySamples(validFrame
? LINK_QUALITY_MAX_VALUE
: 0);
438 if (rssiSource
== RSSI_SOURCE_FRAME_ERRORS
) {
439 resampleTimeUs
+= currentDeltaTimeUs
;
440 rssiSum
+= validFrame
? RSSI_MAX_VALUE
: 0;
443 if (resampleTimeUs
>= FRAME_ERR_RESAMPLE_US
) {
444 setRssi(rssiSum
/ rssiCount
, rssiSource
);
447 resampleTimeUs
-= FRAME_ERR_RESAMPLE_US
;
452 void setLinkQualityDirect(uint16_t linkqualityValue
)
454 #ifdef USE_RX_LINK_QUALITY_INFO
455 linkQuality
= linkqualityValue
;
457 UNUSED(linkqualityValue
);
461 #ifdef USE_RX_LINK_UPLINK_POWER
462 void rxSetUplinkTxPwrMw(uint16_t uplinkTxPwrMwValue
)
464 uplinkTxPwrMw
= uplinkTxPwrMwValue
;
468 bool rxUpdateCheck(timeUs_t currentTimeUs
, timeDelta_t currentDeltaTimeUs
)
470 UNUSED(currentTimeUs
);
471 UNUSED(currentDeltaTimeUs
);
473 return taskUpdateRxMainInProgress() || rxDataProcessingRequired
|| auxiliaryProcessingRequired
;
476 FAST_CODE_NOINLINE
void rxFrameCheck(timeUs_t currentTimeUs
, timeDelta_t currentDeltaTimeUs
, timeDelta_t anticipatedDeltaTime10thUs
)
478 bool signalReceived
= false;
479 bool useDataDrivenProcessing
= true;
480 // Need the next packet in 2.5 x the anticipated time
481 timeDelta_t needRxSignalMaxDelayUs
= anticipatedDeltaTime10thUs
* 2 / 8;
483 DEBUG_SET(DEBUG_RX_SIGNAL_LOSS
, 2, needRxSignalMaxDelayUs
/ 10);
485 if (taskUpdateRxMainInProgress()) {
486 // No need to check for new data as a packet is being processed already
490 switch (rxRuntimeState
.rxProvider
) {
494 #if defined(USE_PWM) || defined(USE_PPM)
495 case RX_PROVIDER_PPM
:
496 if (isPPMDataBeingReceived()) {
497 signalReceived
= true;
498 rxIsInFailsafeMode
= false;
499 resetPPMDataReceivedState();
503 case RX_PROVIDER_PARALLEL_PWM
:
504 if (isPWMDataBeingReceived()) {
505 signalReceived
= true;
506 rxIsInFailsafeMode
= false;
507 useDataDrivenProcessing
= false;
512 case RX_PROVIDER_SERIAL
:
513 case RX_PROVIDER_MSP
:
514 case RX_PROVIDER_SPI
:
516 const uint8_t frameStatus
= rxRuntimeState
.rcFrameStatusFn(&rxRuntimeState
);
517 if (frameStatus
& RX_FRAME_COMPLETE
) {
518 rxIsInFailsafeMode
= (frameStatus
& RX_FRAME_FAILSAFE
) != 0;
519 bool rxFrameDropped
= (frameStatus
& RX_FRAME_DROPPED
) != 0;
520 signalReceived
= !(rxIsInFailsafeMode
|| rxFrameDropped
);
521 setLinkQuality(signalReceived
, currentDeltaTimeUs
);
523 if (frameStatus
& RX_FRAME_PROCESSING_REQUIRED
) {
524 auxiliaryProcessingRequired
= true;
531 if (signalReceived
) {
532 needRxSignalBefore
= currentTimeUs
+ needRxSignalMaxDelayUs
;
533 rxSignalReceived
= true; // immediately process data
535 // no signal, wait 100ms and perform signal loss behaviour every 100ms
536 if (cmpTimeUs(needRxSignalBefore
, currentTimeUs
) > (timeDelta_t
)DELAY_10_HZ
) {
537 rxSignalReceived
= false;
538 // rcData[] needs to be processed to rcCommand
539 rxDataProcessingRequired
= true;
540 needRxSignalBefore
= currentTimeUs
+ (timeDelta_t
)DELAY_10_HZ
;
544 if (signalReceived
&& useDataDrivenProcessing
) {
545 rxDataProcessingRequired
= true;
549 #if defined(USE_PWM) || defined(USE_PPM)
550 static uint16_t calculateChannelMovingAverage(uint8_t chan
, uint16_t sample
)
552 static int16_t rcSamples
[MAX_SUPPORTED_RX_PARALLEL_PWM_OR_PPM_CHANNEL_COUNT
][PPM_AND_PWM_SAMPLE_COUNT
];
553 static int16_t rcDataMean
[MAX_SUPPORTED_RX_PARALLEL_PWM_OR_PPM_CHANNEL_COUNT
];
554 static bool rxSamplesCollected
= false;
556 const uint8_t currentSampleIndex
= rcSampleIndex
% PPM_AND_PWM_SAMPLE_COUNT
;
558 // update the recent samples and compute the average of them
559 rcSamples
[chan
][currentSampleIndex
] = sample
;
561 // avoid returning an incorrect average which would otherwise occur before enough samples
562 if (!rxSamplesCollected
) {
563 if (rcSampleIndex
< PPM_AND_PWM_SAMPLE_COUNT
) {
566 rxSamplesCollected
= true;
569 rcDataMean
[chan
] = 0;
570 for (int sampleIndex
= 0; sampleIndex
< PPM_AND_PWM_SAMPLE_COUNT
; sampleIndex
++) {
571 rcDataMean
[chan
] += rcSamples
[chan
][sampleIndex
];
573 return rcDataMean
[chan
] / PPM_AND_PWM_SAMPLE_COUNT
;
577 static uint16_t getRxfailValue(uint8_t channel
)
579 const rxFailsafeChannelConfig_t
*channelFailsafeConfig
= rxFailsafeChannelConfigs(channel
);
581 switch (channelFailsafeConfig
->mode
) {
582 case RX_FAILSAFE_MODE_AUTO
:
587 return rxConfig()->midrc
;
589 if (featureIsEnabled(FEATURE_3D
) && !IS_RC_MODE_ACTIVE(BOX3D
) && !flight3DConfig()->switched_mode3d
) {
590 return rxConfig()->midrc
;
592 return rxConfig()->rx_min_usec
;
598 case RX_FAILSAFE_MODE_INVALID
:
599 case RX_FAILSAFE_MODE_HOLD
:
600 return rcData
[channel
];
602 case RX_FAILSAFE_MODE_SET
:
603 return RXFAIL_STEP_TO_CHANNEL_VALUE(channelFailsafeConfig
->step
);
607 STATIC_UNIT_TESTED
float applyRxChannelRangeConfiguraton(float sample
, const rxChannelRangeConfig_t
*range
)
609 // Avoid corruption of channel with a value of PPM_RCVR_TIMEOUT
610 if (sample
== PPM_RCVR_TIMEOUT
) {
611 return PPM_RCVR_TIMEOUT
;
614 sample
= scaleRangef(sample
, range
->min
, range
->max
, PWM_RANGE_MIN
, PWM_RANGE_MAX
);
615 sample
= constrainf(sample
, PWM_PULSE_MIN
, PWM_PULSE_MAX
);
620 static void readRxChannelsApplyRanges(void)
622 for (int channel
= 0; channel
< rxChannelCount
; channel
++) {
624 const uint8_t rawChannel
= channel
< RX_MAPPABLE_CHANNEL_COUNT
? rxConfig()->rcmap
[channel
] : channel
;
626 // sample the channel
628 #if defined(USE_RX_MSP_OVERRIDE)
629 if (rxConfig()->msp_override_channels_mask
) {
630 sample
= rxMspOverrideReadRawRc(&rxRuntimeState
, rxConfig(), rawChannel
);
634 sample
= rxRuntimeState
.rcReadRawFn(&rxRuntimeState
, rawChannel
);
637 // apply the rx calibration
638 if (channel
< NON_AUX_CHANNEL_COUNT
) {
639 sample
= applyRxChannelRangeConfiguraton(sample
, rxChannelRangeConfigs(channel
));
642 rcRaw
[channel
] = sample
;
646 static void detectAndApplySignalLossBehaviour(void)
648 const uint32_t currentTimeMs
= millis();
649 const bool failsafeAuxSwitch
= IS_RC_MODE_ACTIVE(BOXFAILSAFE
);
650 bool validRxPacket
= rxSignalReceived
&& !failsafeAuxSwitch
;
651 // becomes false when a packet is bad or we use a failsafe switch - logged to blackbox
652 rxFlightChannelsValid
= true;
653 // becomes false when one or more flight channels has bad Rx data for longer than hold time
655 DEBUG_SET(DEBUG_RX_SIGNAL_LOSS
, 0, rxSignalReceived
);
656 DEBUG_SET(DEBUG_RX_SIGNAL_LOSS
, 1, rxIsInFailsafeMode
);
658 for (int channel
= 0; channel
< rxChannelCount
; channel
++) {
659 float sample
= rcRaw
[channel
];
660 const bool thisChannelValid
= validRxPacket
&& isPulseValid(sample
); // for all or just one channel alone
662 if (thisChannelValid
) {
663 // reset invalid pulse period timer for each good-channel
664 validRxSignalTimeout
[channel
] = currentTimeMs
+ MAX_INVALID_PULSE_TIME
;
666 // set failsafe and hold values
667 if (failsafeIsActive() && ARMING_FLAG(ARMED
)) {
668 // STAGE 2 failsafe is active, and armed. Apply failsafe values until failsafe ends or disarmed
669 if (channel
< NON_AUX_CHANNEL_COUNT
) {
670 if (channel
== THROTTLE
) {
671 sample
= failsafeConfig()->failsafe_throttle
;
673 sample
= rxConfig()->midrc
;
675 } else if (!failsafeAuxSwitch
) {
676 // Aux channels as Set in Configurator, unless failsafe initiated by switch
677 sample
= getRxfailValue(channel
);
680 if (!thisChannelValid
) {
681 if (cmp32(currentTimeMs
, validRxSignalTimeout
[channel
]) < 0) {
682 // HOLD PERIOD for any invalid channels
684 // STAGE 1 failsafe settings apply to any channels invalid for more than hold time
685 if (channel
< NON_AUX_CHANNEL_COUNT
) {
686 rxFlightChannelsValid
= false;
687 sample
= getRxfailValue(channel
);
688 // affected RPYT values will be set as per Stage 1 Configurator settings
689 } else if (!failsafeAuxSwitch
) {
690 // Aux channels as Set in Configurator, unless failsafe initiated by switch
691 sample
= getRxfailValue(channel
);
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
);
704 // set rcData to either clean raw incoming values, or failsafe values
705 rcData
[channel
] = sample
;
709 if (!rxFlightChannelsValid
) {
710 // show RXLOSS in OSD if any RPYT channel, or any packets, are lost for more than hold time
711 setArmingDisabled(ARMING_DISABLED_RX_FAILSAFE
);
714 if (validRxPacket
&& rxFlightChannelsValid
) {
715 // failsafe switches are off, packet is good, no invalid channel for more than hold time
716 // --> start the timer to exit stage 2 failsafe
717 unsetArmingDisabled(ARMING_DISABLED_RX_FAILSAFE
);
718 failsafeOnValidDataReceived();
720 // failsafe switch is on, or a bad packet, or at least one invalid channel for more than hold time
721 // -> start timer to enter stage2 failsafe
722 // note stage 2 onset will be delayed by hold time if we only have some bad channels in otherwise good packets
723 failsafeOnValidDataFailed();
726 DEBUG_SET(DEBUG_RX_SIGNAL_LOSS
, 3, rcData
[THROTTLE
]);
729 bool calculateRxChannelsAndUpdateFailsafe(timeUs_t currentTimeUs
)
731 if (auxiliaryProcessingRequired
) {
732 auxiliaryProcessingRequired
= !rxRuntimeState
.rcProcessFrameFn(&rxRuntimeState
);
735 if (!rxDataProcessingRequired
) {
739 rxDataProcessingRequired
= false;
741 // only proceed when no more samples to skip and suspend period is over
742 if (skipRxSamples
|| currentTimeUs
<= suspendRxSignalUntil
) {
743 if (currentTimeUs
> suspendRxSignalUntil
) {
750 readRxChannelsApplyRanges();
751 detectAndApplySignalLossBehaviour();
758 void parseRcChannels(const char *input
, rxConfig_t
*rxConfig
)
760 for (const char *c
= input
; *c
; c
++) {
761 const char *s
= strchr(rcChannelLetters
, *c
);
762 if (s
&& (s
< rcChannelLetters
+ RX_MAPPABLE_CHANNEL_COUNT
)) {
763 rxConfig
->rcmap
[s
- rcChannelLetters
] = c
- input
;
768 void setRssiDirect(uint16_t newRssi
, rssiSource_e source
)
770 if (source
!= rssiSource
) {
777 #define RSSI_SAMPLE_COUNT 16
779 static uint16_t updateRssiSamples(uint16_t value
)
781 static uint16_t samples
[RSSI_SAMPLE_COUNT
];
782 static uint8_t sampleIndex
= 0;
783 static unsigned sum
= 0;
785 sum
+= value
- samples
[sampleIndex
];
786 samples
[sampleIndex
] = value
;
787 sampleIndex
= (sampleIndex
+ 1) % RSSI_SAMPLE_COUNT
;
788 return sum
/ RSSI_SAMPLE_COUNT
;
791 void setRssi(uint16_t rssiValue
, rssiSource_e source
)
793 if (source
!= rssiSource
) {
798 if (source
== RSSI_SOURCE_FRAME_ERRORS
) {
799 rssi
= pt1FilterApply(&frameErrFilter
, rssiValue
);
801 // calculate new sample mean
802 rssi
= updateRssiSamples(rssiValue
);
806 void setRssiMsp(uint8_t newMspRssi
)
808 if (rssiSource
== RSSI_SOURCE_NONE
) {
809 rssiSource
= RSSI_SOURCE_MSP
;
812 if (rssiSource
== RSSI_SOURCE_MSP
) {
813 rssi
= ((uint16_t)newMspRssi
) << 2;
814 lastMspRssiUpdateUs
= micros();
818 static void updateRSSIPWM(void)
820 // Read value of AUX channel as rssi
821 int16_t pwmRssi
= rcData
[rxConfig()->rssi_channel
- 1];
823 // Range of rawPwmRssi is [1000;2000]. rssi should be in [0;1023];
824 setRssiDirect(scaleRange(constrain(pwmRssi
, PWM_RANGE_MIN
, PWM_RANGE_MAX
), PWM_RANGE_MIN
, PWM_RANGE_MAX
, 0, RSSI_MAX_VALUE
), RSSI_SOURCE_RX_CHANNEL
);
827 static void updateRSSIADC(timeUs_t currentTimeUs
)
830 UNUSED(currentTimeUs
);
832 static uint32_t rssiUpdateAt
= 0;
834 if ((int32_t)(currentTimeUs
- rssiUpdateAt
) < 0) {
837 rssiUpdateAt
= currentTimeUs
+ DELAY_50_HZ
;
839 const uint16_t adcRssiSample
= adcGetChannel(ADC_RSSI
);
840 uint16_t rssiValue
= adcRssiSample
/ RSSI_ADC_DIVISOR
;
842 setRssi(rssiValue
, RSSI_SOURCE_ADC
);
846 void updateRSSI(timeUs_t currentTimeUs
)
848 switch (rssiSource
) {
849 case RSSI_SOURCE_RX_CHANNEL
:
852 case RSSI_SOURCE_ADC
:
853 updateRSSIADC(currentTimeUs
);
855 case RSSI_SOURCE_MSP
:
856 if (cmpTimeUs(micros(), lastMspRssiUpdateUs
) > MSP_RSSI_TIMEOUT_US
) {
865 uint16_t getRssi(void)
867 uint16_t rssiValue
= rssi
;
869 // RSSI_Invert option
870 if (rxConfig()->rssi_invert
) {
871 rssiValue
= RSSI_MAX_VALUE
- rssiValue
;
874 return rxConfig()->rssi_scale
/ 100.0f
* rssiValue
+ rxConfig()->rssi_offset
* RSSI_OFFSET_SCALING
;
877 uint8_t getRssiPercent(void)
879 return scaleRange(getRssi(), 0, RSSI_MAX_VALUE
, 0, 100);
882 int16_t getRssiDbm(void)
887 #define RSSI_SAMPLE_COUNT_DBM 16
889 static int16_t updateRssiDbmSamples(int16_t value
)
891 static int16_t samplesdbm
[RSSI_SAMPLE_COUNT_DBM
];
892 static uint8_t sampledbmIndex
= 0;
893 static int sumdbm
= 0;
895 sumdbm
+= value
- samplesdbm
[sampledbmIndex
];
896 samplesdbm
[sampledbmIndex
] = value
;
897 sampledbmIndex
= (sampledbmIndex
+ 1) % RSSI_SAMPLE_COUNT_DBM
;
898 return sumdbm
/ RSSI_SAMPLE_COUNT_DBM
;
901 void setRssiDbm(int16_t rssiDbmValue
, rssiSource_e source
)
903 if (source
!= rssiSource
) {
907 rssiDbm
= updateRssiDbmSamples(rssiDbmValue
);
910 void setRssiDbmDirect(int16_t newRssiDbm
, rssiSource_e source
)
912 if (source
!= rssiSource
) {
916 rssiDbm
= newRssiDbm
;
919 #ifdef USE_RX_LINK_QUALITY_INFO
920 uint16_t rxGetLinkQuality(void)
925 uint8_t rxGetRfMode(void)
930 uint16_t rxGetLinkQualityPercent(void)
932 return (linkQualitySource
== LQ_SOURCE_NONE
) ? scaleRange(linkQuality
, 0, LINK_QUALITY_MAX_VALUE
, 0, 100) : linkQuality
;
936 #ifdef USE_RX_LINK_UPLINK_POWER
937 uint16_t rxGetUplinkTxPwrMw(void)
939 return uplinkTxPwrMw
;
943 uint16_t rxGetRefreshRate(void)
945 return rxRuntimeState
.rxRefreshRate
;
948 bool isRssiConfigured(void)
950 return rssiSource
!= RSSI_SOURCE_NONE
;
953 timeDelta_t
rxGetFrameDelta(timeDelta_t
*frameAgeUs
)
955 static timeUs_t previousFrameTimeUs
= 0;
956 static timeDelta_t frameTimeDeltaUs
= 0;
958 if (rxRuntimeState
.rcFrameTimeUsFn
) {
959 const timeUs_t frameTimeUs
= rxRuntimeState
.rcFrameTimeUsFn();
961 *frameAgeUs
= cmpTimeUs(micros(), frameTimeUs
);
963 const timeDelta_t deltaUs
= cmpTimeUs(frameTimeUs
, previousFrameTimeUs
);
965 frameTimeDeltaUs
= deltaUs
;
966 previousFrameTimeUs
= frameTimeUs
;
970 return frameTimeDeltaUs
;
973 timeUs_t
rxFrameTimeUs(void)
975 return rxRuntimeState
.lastRcFrameTimeUs
;