mirror of
https://github.com/betaflight/betaflight.git
synced 2025-07-15 20:35:33 +03:00
Merge pull request #10360 from mikeller/immersionrc-irc-ghost-rssi-lq
Implement RSSI (dBm and Pct), LQ, in GHST driver
This commit is contained in:
commit
6e60138725
6 changed files with 90 additions and 31 deletions
|
@ -449,7 +449,7 @@ static void osdResetStats(void)
|
|||
stats.max_g_force = 0;
|
||||
stats.max_esc_temp = 0;
|
||||
stats.max_esc_rpm = 0;
|
||||
stats.min_link_quality = (linkQualitySource == LQ_SOURCE_RX_PROTOCOL_CRSF) ? 100 : 99; // percent
|
||||
stats.min_link_quality = (linkQualitySource == LQ_SOURCE_NONE) ? 99 : 100; // percent
|
||||
stats.min_rssi_dbm = CRSF_SNR_MAX;
|
||||
}
|
||||
|
||||
|
|
|
@ -984,6 +984,9 @@ static void osdElementLinkQuality(osdElementParms_t *element)
|
|||
osdLinkQuality = rxGetLinkQuality();
|
||||
const uint8_t osdRfMode = rxGetRfMode();
|
||||
tfp_sprintf(element->buff, "%c%1d:%2d", SYM_LINK_QUALITY, osdRfMode, osdLinkQuality);
|
||||
} else if (linkQualitySource == LQ_SOURCE_RX_PROTOCOL_GHST) { // 0-100
|
||||
osdLinkQuality = rxGetLinkQuality();
|
||||
tfp_sprintf(element->buff, "%c%2d", SYM_LINK_QUALITY, osdLinkQuality);
|
||||
} else { // 0-9
|
||||
osdLinkQuality = rxGetLinkQuality() * 10 / LINK_QUALITY_MAX_VALUE;
|
||||
if (osdLinkQuality >= 10) {
|
||||
|
|
|
@ -54,6 +54,9 @@
|
|||
#define GHST_MAX_FRAME_TIME_US 500 // 14 bytes @ 420k = ~450us
|
||||
#define GHST_TIME_BETWEEN_FRAMES_US 4500 // fastest frame rate = 222.22Hz, or 4500us
|
||||
|
||||
#define GHST_RSSI_DBM_MIN (-117) // Long Range mode value
|
||||
#define GHST_RSSI_DBM_MAX (-60) // Typical RSSI with typical power levels, typical antennas, and a few feet/meters between Tx and Rx
|
||||
|
||||
// define the time window after the end of the last received packet where telemetry packets may be sent
|
||||
// NOTE: This allows the Rx to double-up on Rx packets to transmit data other than servo data, but
|
||||
// only if sent < 1ms after the servo data packet.
|
||||
|
@ -212,41 +215,59 @@ static bool ghstProcessFrame(const rxRuntimeState_t *rxRuntimeState)
|
|||
}
|
||||
|
||||
if (ghstValidatedFrameAvailable) {
|
||||
int startIdx = 4;
|
||||
switch (ghstValidatedFrame.frame.type) {
|
||||
case GHST_UL_RC_CHANS_HS4_5TO8:
|
||||
case GHST_UL_RC_CHANS_HS4_9TO12:
|
||||
case GHST_UL_RC_CHANS_HS4_13TO16: {
|
||||
int startIdx = 0;
|
||||
|
||||
if (ghstValidatedFrame.frame.type >= GHST_UL_RC_CHANS_HS4_FIRST &&
|
||||
ghstValidatedFrame.frame.type <= GHST_UL_RC_CHANS_HS4_LAST) {
|
||||
const ghstPayloadPulses_t* const rcChannels = (ghstPayloadPulses_t*)&ghstValidatedFrame.frame.payload;
|
||||
|
||||
// all uplink frames contain CH1..4 data (12 bit)
|
||||
ghstChannelData[0] = rcChannels->ch1 >> 1;
|
||||
ghstChannelData[1] = rcChannels->ch2 >> 1;
|
||||
ghstChannelData[2] = rcChannels->ch3 >> 1;
|
||||
ghstChannelData[3] = rcChannels->ch4 >> 1;
|
||||
ghstChannelData[0] = rcChannels->ch1to4.ch1 >> 1;
|
||||
ghstChannelData[1] = rcChannels->ch1to4.ch2 >> 1;
|
||||
ghstChannelData[2] = rcChannels->ch1to4.ch3 >> 1;
|
||||
ghstChannelData[3] = rcChannels->ch1to4.ch4 >> 1;
|
||||
|
||||
// remainder of uplink frame contains 4 more channels (8 bit), sent in a round-robin fashion
|
||||
switch(ghstValidatedFrame.frame.type) {
|
||||
case GHST_UL_RC_CHANS_HS4_RSSI: {
|
||||
const ghstPayloadPulsesRssi_t* const rssiFrame = (ghstPayloadPulsesRssi_t*)&ghstValidatedFrame.frame.payload;
|
||||
|
||||
if (rssiSource == RSSI_SOURCE_RX_PROTOCOL) {
|
||||
// rssi sent sign-inverted
|
||||
const uint16_t rssiPercentScaled = scaleRange(-rssiFrame->rssi, GHST_RSSI_DBM_MIN, 0, GHST_RSSI_DBM_MAX, RSSI_MAX_VALUE);
|
||||
setRssi(rssiPercentScaled, RSSI_SOURCE_RX_PROTOCOL);
|
||||
}
|
||||
|
||||
#ifdef USE_RX_RSSI_DBM
|
||||
setRssiDbm(-rssiFrame->rssi, RSSI_SOURCE_RX_PROTOCOL);
|
||||
#endif
|
||||
|
||||
#ifdef USE_RX_LINK_QUALITY_INFO
|
||||
if (linkQualitySource == LQ_SOURCE_RX_PROTOCOL_GHST) {
|
||||
setLinkQualityDirect(rssiFrame->lq);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
case GHST_UL_RC_CHANS_HS4_5TO8: startIdx = 4; break;
|
||||
case GHST_UL_RC_CHANS_HS4_9TO12: startIdx = 8; break;
|
||||
case GHST_UL_RC_CHANS_HS4_13TO16: startIdx = 12; break;
|
||||
}
|
||||
|
||||
if (startIdx > 0)
|
||||
{
|
||||
// remainder of uplink frame contains 4 more channels (8 bit), sent in a round-robin fashion
|
||||
|
||||
ghstChannelData[startIdx++] = rcChannels->cha << 3;
|
||||
ghstChannelData[startIdx++] = rcChannels->chb << 3;
|
||||
ghstChannelData[startIdx++] = rcChannels->chc << 3;
|
||||
ghstChannelData[startIdx++] = rcChannels->chd << 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
STATIC_UNIT_TESTED uint16_t ghstReadRawRC(const rxRuntimeState_t *rxRuntimeState, uint8_t chan)
|
||||
{
|
||||
|
@ -306,6 +327,16 @@ bool ghstRxInit(const rxConfig_t *rxConfig, rxRuntimeState_t *rxRuntimeState)
|
|||
);
|
||||
serialPort->idleCallback = ghstIdle;
|
||||
|
||||
if (rssiSource == RSSI_SOURCE_NONE) {
|
||||
rssiSource = RSSI_SOURCE_RX_PROTOCOL;
|
||||
}
|
||||
|
||||
#ifdef USE_RX_LINK_QUALITY_INFO
|
||||
if (linkQualitySource == LQ_SOURCE_NONE) {
|
||||
linkQualitySource = LQ_SOURCE_RX_PROTOCOL_GHST;
|
||||
}
|
||||
#endif
|
||||
|
||||
return serialPort != NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -45,9 +45,15 @@ typedef enum {
|
|||
} ghstAddr_e;
|
||||
|
||||
typedef enum {
|
||||
GHST_UL_RC_CHANS_HS4_5TO8 = 0x10, // High Speed 4 channel, plus CH5-8
|
||||
GHST_UL_RC_CHANS_HS4_9TO12 = 0x11, // High Speed 4 channel, plus CH9-12
|
||||
GHST_UL_RC_CHANS_HS4_13TO16 = 0x12 // High Speed 4 channel, plus CH13-16
|
||||
// frame types 0x10 - 0x1f always include 4 primary channels, plus either 4 aux channels,
|
||||
// or other type-specific data. Expect types 0x14-0x1f to be added in the future, and even though
|
||||
// not explicitly supported, the 4 primary channels should always be extracted.
|
||||
GHST_UL_RC_CHANS_HS4_FIRST = 0x10, // First frame type including 4 primary channels
|
||||
GHST_UL_RC_CHANS_HS4_5TO8 = 0x10, // primary 4 channel, plus CH5-8
|
||||
GHST_UL_RC_CHANS_HS4_9TO12 = 0x11, // primary 4 channel, plus CH9-12
|
||||
GHST_UL_RC_CHANS_HS4_13TO16 = 0x12, // primary 4 channel, plus CH13-16
|
||||
GHST_UL_RC_CHANS_HS4_RSSI = 0x13, // primary 4 channel, plus RSSI, LQ, RF Mode, and Tx Power
|
||||
GHST_UL_RC_CHANS_HS4_LAST = 0x1f // Last frame type including 4 primary channels
|
||||
} ghstUl_e;
|
||||
|
||||
#define GHST_UL_RC_CHANS_SIZE 12 // 1 (type) + 10 (data) + 1 (crc)
|
||||
|
@ -80,16 +86,34 @@ typedef union ghstFrame_u {
|
|||
ghstFrameDef_t frame;
|
||||
} ghstFrame_t;
|
||||
|
||||
/* Pulses payload (channel data). Includes 4x high speed control channels, plus 4 channels from CH5-CH12 */
|
||||
typedef struct ghstPayloadPulses_s {
|
||||
// 80 bits, or 10 bytes
|
||||
|
||||
/* Pulses payload (channel data), for 4x 12-bit channels */
|
||||
typedef struct ghstPayloadServo4_s {
|
||||
// 48 bits, or 6 bytes
|
||||
unsigned int ch1: 12;
|
||||
unsigned int ch2: 12;
|
||||
unsigned int ch3: 12;
|
||||
unsigned int ch4: 12;
|
||||
} __attribute__ ((__packed__)) ghstPayloadServo4_t;
|
||||
|
||||
/* Pulses payload (channel data). Includes 4x high speed control channels, plus 4 channels from CH5-CH12 */
|
||||
typedef struct ghstPayloadPulses_s {
|
||||
// 80 bits, or 10 bytes
|
||||
ghstPayloadServo4_t ch1to4;
|
||||
|
||||
unsigned int cha: 8;
|
||||
unsigned int chb: 8;
|
||||
unsigned int chc: 8;
|
||||
unsigned int chd: 8;
|
||||
} __attribute__ ((__packed__)) ghstPayloadPulses_t;
|
||||
|
||||
/* Pulses payload (channel data), with RSSI/LQ, and other related data */
|
||||
typedef struct ghstPayloadPulsesRssi_s {
|
||||
// 80 bits, or 10 bytes
|
||||
ghstPayloadServo4_t ch1to4;
|
||||
|
||||
unsigned int lq: 8; // 0-100
|
||||
unsigned int rssi: 8; // 0 - 128 sign inverted, dBm
|
||||
unsigned int rfProtocol: 8;
|
||||
signed int txPwrdBm: 8; // tx power in dBm, use lookup table to map to published mW values
|
||||
} __attribute__ ((__packed__)) ghstPayloadPulsesRssi_t;
|
||||
|
|
|
@ -425,7 +425,7 @@ static void setLinkQuality(bool validFrame, timeDelta_t currentDeltaTimeUs)
|
|||
static timeDelta_t resampleTimeUs = 0;
|
||||
|
||||
#ifdef USE_RX_LINK_QUALITY_INFO
|
||||
if (linkQualitySource != LQ_SOURCE_RX_PROTOCOL_CRSF) {
|
||||
if (linkQualitySource == LQ_SOURCE_NONE) {
|
||||
// calculate new sample mean
|
||||
linkQuality = updateLinkQualitySamples(validFrame ? LINK_QUALITY_MAX_VALUE : 0);
|
||||
}
|
||||
|
@ -871,7 +871,7 @@ uint8_t rxGetRfMode(void)
|
|||
|
||||
uint16_t rxGetLinkQualityPercent(void)
|
||||
{
|
||||
return (linkQualitySource == LQ_SOURCE_RX_PROTOCOL_CRSF) ? linkQuality : scaleRange(linkQuality, 0, LINK_QUALITY_MAX_VALUE, 0, 100);
|
||||
return (linkQualitySource == LQ_SOURCE_NONE) ? scaleRange(linkQuality, 0, LINK_QUALITY_MAX_VALUE, 0, 100) : linkQuality;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -166,6 +166,7 @@ extern rssiSource_e rssiSource;
|
|||
typedef enum {
|
||||
LQ_SOURCE_NONE = 0,
|
||||
LQ_SOURCE_RX_PROTOCOL_CRSF,
|
||||
LQ_SOURCE_RX_PROTOCOL_GHST,
|
||||
} linkQualitySource_e;
|
||||
|
||||
extern linkQualitySource_e linkQualitySource;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue