1
0
Fork 0
mirror of https://github.com/betaflight/betaflight.git synced 2025-07-18 22:05:17 +03:00
betaflight/src/rx_common.c
Dominic Clifton 1925df26ca Add RSSI PWM on CH2 input.
Also support FrSky 1khz RSSI.  See documentation also added in this
commit.

This commit also cleans up the PWM mapping code.  'mask' didn't need to
be a mask and it wasn't possible to add another 'type' since there were
only 4 possible values when it was a mask and they were already defined.  
Combined with switching to using 16 bits instead of 8 for the mapping
configurations, it's now possible to have 256 types instead of 4 at the
expense of a few bytes of flash.

Moved the RSSI calculation into rx_common.c, previously it was in the
main loop.
2014-05-24 00:01:59 +01:00

321 lines
8.7 KiB
C

#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "platform.h"
#include "common/maths.h"
#include "config.h"
#include "drivers/serial_common.h"
#include "serial_common.h"
#include "failsafe.h"
#include "drivers/pwm_rx.h"
#include "drivers/pwm_rssi.h"
#include "rx_pwm.h"
#include "rx_sbus.h"
#include "rx_spektrum.h"
#include "rx_sumd.h"
#include "rx_msp.h"
#include "rx_common.h"
extern int16_t debug[4];
void rxPwmInit(rxRuntimeConfig_t *rxRuntimeConfig, rcReadRawDataPtr *callback);
bool sbusInit(rxConfig_t *initialRxConfig, rxRuntimeConfig_t *rxRuntimeConfig, rcReadRawDataPtr *callback);
bool spektrumInit(rxConfig_t *rxConfig, rxRuntimeConfig_t *rxRuntimeConfig, rcReadRawDataPtr *callback);
bool sumdInit(rxConfig_t *rxConfig, rxRuntimeConfig_t *rxRuntimeConfig, rcReadRawDataPtr *callback);
bool rxMspInit(rxConfig_t *rxConfig, rxRuntimeConfig_t *rxRuntimeConfig, rcReadRawDataPtr *callback);
const char rcChannelLetters[] = "AERT1234";
uint16_t rssi; // range: [0;1023]
int16_t rcData[MAX_SUPPORTED_RC_CHANNEL_COUNT]; // interval [1000;2000]
#define PPM_AND_PWM_SAMPLE_COUNT 4
#define PULSE_MIN 750 // minimum PWM pulse width which is considered valid
#define PULSE_MAX 2250 // maximum PWM pulse width which is considered valid
static rcReadRawDataPtr rcReadRawFunc = NULL; // receive data from default (pwm/ppm) or additional (spek/sbus/?? receiver drivers)
rxRuntimeConfig_t rxRuntimeConfig;
static rxConfig_t *rxConfig;
void serialRxInit(rxConfig_t *rxConfig);
static failsafe_t *failsafe;
void useRxConfig(rxConfig_t *rxConfigToUse)
{
rxConfig = rxConfigToUse;
}
void updateSerialRxFunctionConstraint(functionConstraint_t *functionConstraintToUpdate)
{
switch (rxConfig->serialrx_provider) {
case SERIALRX_SPEKTRUM1024:
case SERIALRX_SPEKTRUM2048:
spektrumUpdateSerialRxFunctionConstraint(functionConstraintToUpdate);
break;
case SERIALRX_SBUS:
sbusUpdateSerialRxFunctionConstraint(functionConstraintToUpdate);
break;
case SERIALRX_SUMD:
sumdUpdateSerialRxFunctionConstraint(functionConstraintToUpdate);
break;
}
}
void rxInit(rxConfig_t *rxConfig, failsafe_t *initialFailsafe)
{
uint8_t i;
useRxConfig(rxConfig);
for (i = 0; i < MAX_SUPPORTED_RC_CHANNEL_COUNT; i++) {
rcData[i] = rxConfig->midrc;
}
failsafe = initialFailsafe;
if (feature(FEATURE_RX_SERIAL)) {
serialRxInit(rxConfig);
}
if (feature(FEATURE_RX_MSP)) {
rxMspInit(rxConfig, &rxRuntimeConfig, &rcReadRawFunc);
}
if (feature(FEATURE_RX_PPM) || feature(FEATURE_RX_PARALLEL_PWM)) {
rxPwmInit(&rxRuntimeConfig, &rcReadRawFunc);
}
}
void serialRxInit(rxConfig_t *rxConfig)
{
bool enabled = false;
switch (rxConfig->serialrx_provider) {
case SERIALRX_SPEKTRUM1024:
case SERIALRX_SPEKTRUM2048:
enabled = spektrumInit(rxConfig, &rxRuntimeConfig, &rcReadRawFunc);
break;
case SERIALRX_SBUS:
enabled = sbusInit(rxConfig, &rxRuntimeConfig, &rcReadRawFunc);
break;
case SERIALRX_SUMD:
enabled = sumdInit(rxConfig, &rxRuntimeConfig, &rcReadRawFunc);
break;
}
if (!enabled) {
featureClear(FEATURE_RX_SERIAL);
rcReadRawFunc = NULL;
}
}
bool isSerialRxFrameComplete(rxConfig_t *rxConfig)
{
switch (rxConfig->serialrx_provider) {
case SERIALRX_SPEKTRUM1024:
case SERIALRX_SPEKTRUM2048:
return spektrumFrameComplete();
case SERIALRX_SBUS:
return sbusFrameComplete();
case SERIALRX_SUMD:
return sumdFrameComplete();
}
return false;
}
uint8_t calculateChannelRemapping(uint8_t *channelMap, uint8_t channelMapEntryCount, uint8_t channelToRemap)
{
if (channelToRemap < channelMapEntryCount) {
return channelMap[channelToRemap];
}
return channelToRemap;
}
static bool rcDataReceived = false;
static uint32_t rxTime = 0;
void updateRx(void)
{
rcDataReceived = false;
// calculate rc stuff from serial-based receivers (spek/sbus)
if (feature(FEATURE_RX_SERIAL)) {
rcDataReceived = isSerialRxFrameComplete(rxConfig);
}
if (feature(FEATURE_RX_MSP)) {
rcDataReceived = rxMspFrameComplete();
}
if (rcDataReceived) {
if (feature(FEATURE_FAILSAFE)) {
failsafe->vTable->reset();
}
}
}
bool shouldProcessRx(uint32_t currentTime)
{
return rcDataReceived || ((int32_t)(currentTime - rxTime) >= 0); // data driven or 50Hz
}
static bool isRxDataDriven(void) {
return !(feature(FEATURE_RX_PARALLEL_PWM | FEATURE_RX_PPM));
}
static uint8_t rcSampleIndex = 0;
uint16_t calculateNonDataDrivenChannel(uint8_t chan, uint16_t sample)
{
static int16_t rcSamples[MAX_SUPPORTED_RX_PARALLEL_PWM_OR_PPM_CHANNEL_COUNT][PPM_AND_PWM_SAMPLE_COUNT];
static int16_t rcDataMean[MAX_SUPPORTED_RX_PARALLEL_PWM_OR_PPM_CHANNEL_COUNT];
uint8_t currentSampleIndex = rcSampleIndex % PPM_AND_PWM_SAMPLE_COUNT;
// update the recent samples and compute the average of them
rcSamples[chan][currentSampleIndex] = sample;
rcDataMean[chan] = 0;
uint8_t sampleIndex;
for (sampleIndex = 0; sampleIndex < PPM_AND_PWM_SAMPLE_COUNT; sampleIndex++)
rcDataMean[chan] += rcSamples[chan][sampleIndex];
return rcDataMean[chan] / PPM_AND_PWM_SAMPLE_COUNT;
}
void processRxChannels(void)
{
uint8_t chan;
bool shouldCheckPulse = true;
if (feature(FEATURE_FAILSAFE | FEATURE_RX_PPM)) {
shouldCheckPulse = isPPMDataBeingReceived();
resetPPMDataReceivedState();
}
for (chan = 0; chan < rxRuntimeConfig.channelCount; chan++) {
if (!rcReadRawFunc) {
rcData[chan] = rxConfig->midrc;
continue;
}
uint8_t rawChannel = calculateChannelRemapping(rxConfig->rcmap, REMAPPABLE_CHANNEL_COUNT, chan);
// sample the channel
uint16_t sample = rcReadRawFunc(&rxRuntimeConfig, rawChannel);
if (feature(FEATURE_FAILSAFE) && shouldCheckPulse) {
failsafe->vTable->checkPulse(rawChannel, sample);
}
// validate the range
if (sample < PULSE_MIN || sample > PULSE_MAX)
sample = rxConfig->midrc;
if (isRxDataDriven()) {
rcData[chan] = sample;
} else {
rcData[chan] = calculateNonDataDrivenChannel(chan, sample);
}
}
}
void processDataDrivenRx(void)
{
if (!rcDataReceived) {
return;
}
failsafe->vTable->reset();
processRxChannels();
rcDataReceived = false;
}
void processNonDataDrivenRx(void)
{
rcSampleIndex++;
processRxChannels();
}
void calculateRxChannelsAndUpdateFailsafe(uint32_t currentTime)
{
rxTime = currentTime + 20000;
if (feature(FEATURE_FAILSAFE)) {
failsafe->vTable->incrementCounter();
}
if (isRxDataDriven()) {
processDataDrivenRx();
} else {
processNonDataDrivenRx();
}
}
void parseRcChannels(const char *input, rxConfig_t *rxConfig)
{
const char *c, *s;
for (c = input; *c; c++) {
s = strchr(rcChannelLetters, *c);
if (s)
rxConfig->rcmap[s - rcChannelLetters] = c - input;
}
}
void updateRSSI(void)
{
if (rxConfig->rssi_channel == 0 && !feature(FEATURE_RSSI_PWM)) {
return;
}
int16_t rawPwmRssi = 0;
if (rxConfig->rssi_channel > 0) {
// Read value of AUX channel as rssi
rawPwmRssi = rcData[rxConfig->rssi_channel - 1];
} else if (feature(FEATURE_RSSI_PWM)) {
rawPwmRssi = pwmRSSIRead();
if (rxConfig->rssi_pwm_provider == RSSI_PWM_PROVIDER_FRSKY_1KHZ) {
// FrSky X8R has a 1khz RSSI output which is too fast for the IRQ handlers
// Values range from 0 to 970 and over 1000 when the transmitter is off.
// When the transmitter is OFF the pulse is too short to be detected hence the high value
// because the edge detection in the IRQ handler is the detecting the wrong edges.
if (rawPwmRssi > 1000) {
rawPwmRssi = 0;
}
rawPwmRssi += 1000;
}
}
#if 1
debug[3] = rawPwmRssi;
#endif
// Range of rawPwmRssi is [1000;2000]. rssi should be in [0;1023];
rssi = (uint16_t)((constrain(rawPwmRssi - 1000, 0, 1000) / 1000.0f) * 1023.0f);
}