diff --git a/src/main/osd/osd.c b/src/main/osd/osd.c index 2a1eb5289e..14bf2118da 100644 --- a/src/main/osd/osd.c +++ b/src/main/osd/osd.c @@ -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; } diff --git a/src/main/osd/osd_elements.c b/src/main/osd/osd_elements.c index 3aa8221492..ce586e6588 100644 --- a/src/main/osd/osd_elements.c +++ b/src/main/osd/osd_elements.c @@ -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) { diff --git a/src/main/rx/ghst.c b/src/main/rx/ghst.c index cc88f6ace3..c8108ada76 100644 --- a/src/main/rx/ghst.c +++ b/src/main/rx/ghst.c @@ -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,40 +215,58 @@ 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: { - const ghstPayloadPulses_t* const rcChannels = (ghstPayloadPulses_t*)&ghstValidatedFrame.frame.payload; + int startIdx = 0; - // 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; + 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; - // 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_5TO8: startIdx = 4; break; - case GHST_UL_RC_CHANS_HS4_9TO12: startIdx = 8; break; - case GHST_UL_RC_CHANS_HS4_13TO16: startIdx = 12; break; + // all uplink frames contain CH1..4 data (12 bit) + ghstChannelData[0] = rcChannels->ch1to4.ch1 >> 1; + ghstChannelData[1] = rcChannels->ch1to4.ch2 >> 1; + ghstChannelData[2] = rcChannels->ch1to4.ch3 >> 1; + ghstChannelData[3] = rcChannels->ch1to4.ch4 >> 1; + + 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; + return true; } 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; } diff --git a/src/main/rx/ghst_protocol.h b/src/main/rx/ghst_protocol.h index aded09dfb0..3af184a4f2 100644 --- a/src/main/rx/ghst_protocol.h +++ b/src/main/rx/ghst_protocol.h @@ -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; diff --git a/src/main/rx/rx.c b/src/main/rx/rx.c index 2a33c77f12..40d139deef 100644 --- a/src/main/rx/rx.c +++ b/src/main/rx/rx.c @@ -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 diff --git a/src/main/rx/rx.h b/src/main/rx/rx.h index 54540967af..87731bbf23 100644 --- a/src/main/rx/rx.h +++ b/src/main/rx/rx.h @@ -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;