2 * This file is part of Cleanflight.
4 * Cleanflight is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * Cleanflight is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
24 #include "build_config.h"
28 #include "common/maths.h"
30 #include "config/config.h"
32 #include "drivers/serial.h"
33 #include "drivers/adc.h"
34 #include "io/serial.h"
36 #include "flight/failsafe.h"
38 #include "drivers/gpio.h"
39 #include "drivers/timer.h"
40 #include "drivers/pwm_rx.h"
43 #include "rx/spektrum.h"
51 extern int16_t debug
[4];
53 void rxPwmInit(rxRuntimeConfig_t
*rxRuntimeConfig
, rcReadRawDataPtr
*callback
);
55 bool sbusInit(rxConfig_t
*initialRxConfig
, rxRuntimeConfig_t
*rxRuntimeConfig
, rcReadRawDataPtr
*callback
);
56 bool spektrumInit(rxConfig_t
*rxConfig
, rxRuntimeConfig_t
*rxRuntimeConfig
, rcReadRawDataPtr
*callback
);
57 bool sumdInit(rxConfig_t
*rxConfig
, rxRuntimeConfig_t
*rxRuntimeConfig
, rcReadRawDataPtr
*callback
);
58 bool sumhInit(rxConfig_t
*rxConfig
, rxRuntimeConfig_t
*rxRuntimeConfig
, rcReadRawDataPtr
*callback
);
60 bool rxMspInit(rxConfig_t
*rxConfig
, rxRuntimeConfig_t
*rxRuntimeConfig
, rcReadRawDataPtr
*callback
);
62 const char rcChannelLetters
[] = "AERT12345678abcdefgh";
64 uint16_t rssi
= 0; // range: [0;1023]
66 int16_t rcData
[MAX_SUPPORTED_RC_CHANNEL_COUNT
]; // interval [1000;2000]
68 #define PPM_AND_PWM_SAMPLE_COUNT 4
70 #define PULSE_MIN 750 // minimum PWM pulse width which is considered valid
71 #define PULSE_MAX 2250 // maximum PWM pulse width which is considered valid
73 #define DELAY_50_HZ (1000000 / 50)
75 static rcReadRawDataPtr rcReadRawFunc
= NULL
; // receive data from default (pwm/ppm) or additional (spek/sbus/?? receiver drivers)
77 rxRuntimeConfig_t rxRuntimeConfig
;
78 static rxConfig_t
*rxConfig
;
80 void serialRxInit(rxConfig_t
*rxConfig
);
82 void useRxConfig(rxConfig_t
*rxConfigToUse
)
84 rxConfig
= rxConfigToUse
;
87 #define STICK_CHANNEL_COUNT 4
89 void rxInit(rxConfig_t
*rxConfig
)
93 useRxConfig(rxConfig
);
95 for (i
= 0; i
< MAX_SUPPORTED_RC_CHANNEL_COUNT
; i
++) {
96 rcData
[i
] = rxConfig
->midrc
;
100 if (feature(FEATURE_RX_SERIAL
)) {
101 serialRxInit(rxConfig
);
105 if (feature(FEATURE_RX_MSP
)) {
106 rxMspInit(rxConfig
, &rxRuntimeConfig
, &rcReadRawFunc
);
109 if (feature(FEATURE_RX_PPM
) || feature(FEATURE_RX_PARALLEL_PWM
)) {
110 rxPwmInit(&rxRuntimeConfig
, &rcReadRawFunc
);
113 rxRuntimeConfig
.auxChannelCount
= rxRuntimeConfig
.channelCount
- STICK_CHANNEL_COUNT
;
117 void serialRxInit(rxConfig_t
*rxConfig
)
119 bool enabled
= false;
120 switch (rxConfig
->serialrx_provider
) {
121 case SERIALRX_SPEKTRUM1024
:
122 case SERIALRX_SPEKTRUM2048
:
123 enabled
= spektrumInit(rxConfig
, &rxRuntimeConfig
, &rcReadRawFunc
);
126 enabled
= sbusInit(rxConfig
, &rxRuntimeConfig
, &rcReadRawFunc
);
129 enabled
= sumdInit(rxConfig
, &rxRuntimeConfig
, &rcReadRawFunc
);
132 enabled
= sumhInit(rxConfig
, &rxRuntimeConfig
, &rcReadRawFunc
);
134 case SERIALRX_XBUS_MODE_B
:
135 case SERIALRX_XBUS_MODE_B_RJ01
:
136 enabled
= xBusInit(rxConfig
, &rxRuntimeConfig
, &rcReadRawFunc
);
141 featureClear(FEATURE_RX_SERIAL
);
142 rcReadRawFunc
= NULL
;
146 uint8_t serialRxFrameStatus(rxConfig_t
*rxConfig
)
149 * FIXME: Each of the xxxxFrameStatus() methods MUST be able to survive being called without the
150 * corresponding xxxInit() method having been called first.
152 * This situation arises when the cli or the msp changes the value of rxConfig->serialrx_provider
154 * A solution is for the ___Init() to configure the serialRxFrameStatus function pointer which
155 * should be used instead of the switch statement below.
157 switch (rxConfig
->serialrx_provider
) {
158 case SERIALRX_SPEKTRUM1024
:
159 case SERIALRX_SPEKTRUM2048
:
160 return spektrumFrameStatus();
162 return sbusFrameStatus();
164 return sumdFrameStatus();
166 return sumhFrameStatus();
167 case SERIALRX_XBUS_MODE_B
:
168 case SERIALRX_XBUS_MODE_B_RJ01
:
169 return xBusFrameStatus();
171 return SERIAL_RX_FRAME_PENDING
;
175 uint8_t calculateChannelRemapping(uint8_t *channelMap
, uint8_t channelMapEntryCount
, uint8_t channelToRemap
)
177 if (channelToRemap
< channelMapEntryCount
) {
178 return channelMap
[channelToRemap
];
180 return channelToRemap
;
183 static bool rcDataReceived
= false;
185 static uint32_t rxUpdateAt
= 0;
190 rcDataReceived
= false;
193 if (feature(FEATURE_RX_SERIAL
)) {
194 uint8_t frameStatus
= serialRxFrameStatus(rxConfig
);
196 if (frameStatus
& SERIAL_RX_FRAME_COMPLETE
) {
197 rcDataReceived
= true;
198 if ((frameStatus
& SERIAL_RX_FRAME_FAILSAFE
) == 0 && feature(FEATURE_FAILSAFE
)) {
205 if (feature(FEATURE_RX_MSP
)) {
206 rcDataReceived
= rxMspFrameComplete();
207 if (rcDataReceived
&& feature(FEATURE_FAILSAFE
)) {
213 bool shouldProcessRx(uint32_t currentTime
)
215 return rcDataReceived
|| ((int32_t)(currentTime
- rxUpdateAt
) >= 0); // data driven or 50Hz
218 static bool isRxDataDriven(void) {
219 return !(feature(FEATURE_RX_PARALLEL_PWM
| FEATURE_RX_PPM
));
222 static uint8_t rcSampleIndex
= 0;
224 static uint16_t calculateNonDataDrivenChannel(uint8_t chan
, uint16_t sample
)
226 static int16_t rcSamples
[MAX_SUPPORTED_RX_PARALLEL_PWM_OR_PPM_CHANNEL_COUNT
][PPM_AND_PWM_SAMPLE_COUNT
];
227 static int16_t rcDataMean
[MAX_SUPPORTED_RX_PARALLEL_PWM_OR_PPM_CHANNEL_COUNT
];
228 static bool rxSamplesCollected
= false;
230 uint8_t currentSampleIndex
= rcSampleIndex
% PPM_AND_PWM_SAMPLE_COUNT
;
232 // update the recent samples and compute the average of them
233 rcSamples
[chan
][currentSampleIndex
] = sample
;
235 // avoid returning an incorrect average which would otherwise occur before enough samples
236 if (!rxSamplesCollected
) {
237 if (rcSampleIndex
< PPM_AND_PWM_SAMPLE_COUNT
) {
240 rxSamplesCollected
= true;
243 rcDataMean
[chan
] = 0;
246 for (sampleIndex
= 0; sampleIndex
< PPM_AND_PWM_SAMPLE_COUNT
; sampleIndex
++)
247 rcDataMean
[chan
] += rcSamples
[chan
][sampleIndex
];
249 return rcDataMean
[chan
] / PPM_AND_PWM_SAMPLE_COUNT
;
252 static void processRxChannels(void)
256 if (feature(FEATURE_RX_MSP
)) {
257 return; // rcData will have already been updated by MSP_SET_RAW_RC
260 bool shouldCheckPulse
= true;
262 if (feature(FEATURE_FAILSAFE
)) {
263 if (feature(FEATURE_RX_PPM
)) {
264 shouldCheckPulse
= isPPMDataBeingReceived();
265 resetPPMDataReceivedState();
267 shouldCheckPulse
= !isRxDataDriven();
271 for (chan
= 0; chan
< rxRuntimeConfig
.channelCount
; chan
++) {
273 if (!rcReadRawFunc
) {
274 rcData
[chan
] = rxConfig
->midrc
;
278 uint8_t rawChannel
= calculateChannelRemapping(rxConfig
->rcmap
, REMAPPABLE_CHANNEL_COUNT
, chan
);
280 // sample the channel
281 uint16_t sample
= rcReadRawFunc(&rxRuntimeConfig
, rawChannel
);
283 if (feature(FEATURE_FAILSAFE
) && shouldCheckPulse
) {
284 failsafeCheckPulse(chan
, sample
);
287 // validate the range
288 if (sample
< PULSE_MIN
|| sample
> PULSE_MAX
)
289 sample
= rxConfig
->midrc
;
291 if (isRxDataDriven()) {
292 rcData
[chan
] = sample
;
294 rcData
[chan
] = calculateNonDataDrivenChannel(chan
, sample
);
299 static void processDataDrivenRx(void)
304 static void processNonDataDrivenRx(void)
311 void calculateRxChannelsAndUpdateFailsafe(uint32_t currentTime
)
313 rxUpdateAt
= currentTime
+ DELAY_50_HZ
;
315 if (feature(FEATURE_FAILSAFE
)) {
319 if (isRxDataDriven()) {
320 processDataDrivenRx();
322 processNonDataDrivenRx();
326 void parseRcChannels(const char *input
, rxConfig_t
*rxConfig
)
330 for (c
= input
; *c
; c
++) {
331 s
= strchr(rcChannelLetters
, *c
);
332 if (s
&& (s
< rcChannelLetters
+ MAX_MAPPABLE_RX_INPUTS
))
333 rxConfig
->rcmap
[s
- rcChannelLetters
] = c
- input
;
337 void updateRSSIPWM(void)
340 // Read value of AUX channel as rssi
341 pwmRssi
= rcData
[rxConfig
->rssi_channel
- 1];
344 // Range of rawPwmRssi is [1000;2000]. rssi should be in [0;1023];
345 rssi
= (uint16_t)((constrain(pwmRssi
- 1000, 0, 1000) / 1000.0f
) * 1023.0f
);
348 #define RSSI_ADC_SAMPLE_COUNT 16
349 //#define RSSI_SCALE (0xFFF / 100.0f)
351 void updateRSSIADC(uint32_t currentTime
)
356 static uint8_t adcRssiSamples
[RSSI_ADC_SAMPLE_COUNT
];
357 static uint8_t adcRssiSampleIndex
= 0;
358 static uint32_t rssiUpdateAt
= 0;
360 if ((int32_t)(currentTime
- rssiUpdateAt
) < 0) {
363 rssiUpdateAt
= currentTime
+ DELAY_50_HZ
;
365 int16_t adcRssiMean
= 0;
366 uint16_t adcRssiSample
= adcGetChannel(ADC_RSSI
);
367 uint8_t rssiPercentage
= adcRssiSample
/ rxConfig
->rssi_scale
;
369 adcRssiSampleIndex
= (adcRssiSampleIndex
+ 1) % RSSI_ADC_SAMPLE_COUNT
;
371 adcRssiSamples
[adcRssiSampleIndex
] = rssiPercentage
;
375 for (sampleIndex
= 0; sampleIndex
< RSSI_ADC_SAMPLE_COUNT
; sampleIndex
++) {
376 adcRssiMean
+= adcRssiSamples
[sampleIndex
];
379 adcRssiMean
= adcRssiMean
/ RSSI_ADC_SAMPLE_COUNT
;
381 rssi
= (uint16_t)((constrain(adcRssiMean
, 0, 100) / 100.0f
) * 1023.0f
);
385 void updateRSSI(uint32_t currentTime
)
388 if (rxConfig
->rssi_channel
> 0) {
390 } else if (feature(FEATURE_RSSI_ADC
)) {
391 updateRSSIADC(currentTime
);