From 6d17448be57d2c1e622eb23f061d39acb9f41639 Mon Sep 17 00:00:00 2001 From: Raphael Coeffic Date: Thu, 12 Dec 2024 02:19:34 +0100 Subject: [PATCH] feat: S.Port telemetry for PPM/SBUS external module (#5689) Co-authored-by: Michael --- .../src/firmwares/edgetx/yaml_moduledata.cpp | 14 +++- companion/src/firmwares/moduledata.cpp | 10 ++- companion/src/firmwares/moduledata.h | 3 +- companion/src/modeledit/setup_module.cpp | 5 +- companion/src/modelprinter.cpp | 2 +- radio/src/gui/128x64/model_setup.cpp | 14 +++- radio/src/gui/212x64/model_setup.cpp | 13 +++- .../src/gui/colorlcd/module/module_setup.cpp | 13 +++- radio/src/pulses/modules_constants.h | 8 ++- radio/src/pulses/ppm.cpp | 23 +++++++ radio/src/pulses/pxx1.cpp | 2 +- radio/src/pulses/sbus.cpp | 65 ++++++++++++++++++- radio/src/telemetry/frsky.cpp | 12 ++-- radio/src/telemetry/frsky.h | 4 +- radio/src/telemetry/multi.cpp | 6 +- radio/src/translations.cpp | 1 + radio/src/translations.h | 1 + radio/src/translations/untranslated.h | 3 +- 18 files changed, 171 insertions(+), 28 deletions(-) diff --git a/companion/src/firmwares/edgetx/yaml_moduledata.cpp b/companion/src/firmwares/edgetx/yaml_moduledata.cpp index b53c8230d..283f5510c 100644 --- a/companion/src/firmwares/edgetx/yaml_moduledata.cpp +++ b/companion/src/firmwares/edgetx/yaml_moduledata.cpp @@ -109,7 +109,13 @@ static const YamlLookupTable r9mLut = { static const YamlLookupTable ppmLut = { { 0, "NOTLM" }, - { 1, "MLINK" } + { 1, "MLINK" }, + { 2, "SPort"} +}; + +static const YamlLookupTable sbusLut = { + { 0, "NOTLM" }, + { 1, "SPort"} }; static const YamlLookupTable dsmLut = { @@ -175,6 +181,9 @@ Node convert::encode(const ModuleData& rhs) case PULSES_PPM: node["subType"] = LookupValue(ppmLut, subtype); break; + case PULSES_SBUS: + node["subType"] = LookupValue(sbusLut, subtype); + break; case PULSES_MULTIMODULE: { int rfProtocol = rhs.multi.rfProtocol + 1; int subType = rhs.subType; @@ -317,6 +326,9 @@ bool convert::decode(const Node& node, ModuleData& rhs) case PULSES_PPM: { subType >> ppmLut >> rhs.subType; } break; + case PULSES_SBUS: { + subType >> sbusLut >> rhs.subType; + } break; case PULSES_LP45: { int subProto = 0; subType >> dsmLut >> subProto; diff --git a/companion/src/firmwares/moduledata.cpp b/companion/src/firmwares/moduledata.cpp index a021d39ba..c2f80f507 100644 --- a/companion/src/firmwares/moduledata.cpp +++ b/companion/src/firmwares/moduledata.cpp @@ -258,7 +258,13 @@ QString ModuleData::subTypeToString(int type) const static const QString ppmSubTypeStrings[PPM_NUM_SUBTYPES] = { tr("No Telemetry"), - tr("MLink") + tr("MLink"), + tr("SPort") + }; + + static const QString sbusSubTypeStrings[SBUS_NUM_SUBTYPES] = { + tr("No Telemetry"), + tr("SPort") }; if (type < 0) @@ -269,6 +275,8 @@ QString ModuleData::subTypeToString(int type) const return Multiprotocols::subTypeToString((int)multi.rfProtocol, (unsigned)type); case PULSES_PPM: return CHECK_IN_ARRAY(ppmSubTypeStrings, type); + case PULSES_SBUS: + return CHECK_IN_ARRAY(sbusSubTypeStrings, type); case PULSES_PXX_R9M: return CHECK_IN_ARRAY(strings, type); default: diff --git a/companion/src/firmwares/moduledata.h b/companion/src/firmwares/moduledata.h index 06abd3d09..ec81dd619 100644 --- a/companion/src/firmwares/moduledata.h +++ b/companion/src/firmwares/moduledata.h @@ -103,7 +103,8 @@ enum ModuleSubtypeR9M { MODULE_SUBTYPE_R9M_LAST=MODULE_SUBTYPE_R9M_AUPLUS }; -#define PPM_NUM_SUBTYPES 2 +#define PPM_NUM_SUBTYPES 3 +#define SBUS_NUM_SUBTYPES 2 constexpr int PXX2_MAX_RECEIVERS_PER_MODULE = 3; constexpr int PXX2_LEN_RX_NAME = 8; diff --git a/companion/src/modeledit/setup_module.cpp b/companion/src/modeledit/setup_module.cpp index 558da90e3..ac18c9f6c 100644 --- a/companion/src/modeledit/setup_module.cpp +++ b/companion/src/modeledit/setup_module.cpp @@ -373,7 +373,7 @@ void ModulePanel::update() break; case PULSES_SBUS: module.channelsCount = 16; - mask |= MASK_SBUSPPM_FIELDS| MASK_CHANNELS_RANGE; + mask |= MASK_SUBTYPES | MASK_SBUSPPM_FIELDS| MASK_CHANNELS_RANGE; break; case PULSES_MULTIMODULE: mask |= MASK_CHANNELS_RANGE | MASK_RX_NUMBER | MASK_MULTIMODULE | MASK_SUBTYPES; @@ -521,6 +521,9 @@ void ModulePanel::update() case PULSES_PPM: numEntries = PPM_NUM_SUBTYPES; break; + case PULSES_SBUS: + numEntries = SBUS_NUM_SUBTYPES; + break; default: break; } diff --git a/companion/src/modelprinter.cpp b/companion/src/modelprinter.cpp index e7460f5ad..4d0dae9b0 100644 --- a/companion/src/modelprinter.cpp +++ b/companion/src/modelprinter.cpp @@ -202,7 +202,7 @@ QString ModelPrinter::printModule(int idx) else { str << printLabelValue(tr("Protocol"), ModuleData::protocolToString(module.protocol)); if (module.protocol) { - if (module.protocol == PULSES_PPM) + if (module.protocol == PULSES_PPM || module.protocol == PULSES_SBUS) str << printLabelValue(tr("Sub Type"), module.subTypeToString()); str << printLabelValue(tr("Channels"), QString("%1-%2").arg(module.channelsStart + 1).arg(module.channelsStart + module.channelsCount)); if (module.protocol == PULSES_PPM || module.protocol == PULSES_SBUS) { diff --git a/radio/src/gui/128x64/model_setup.cpp b/radio/src/gui/128x64/model_setup.cpp index 693e4b685..8107bd434 100644 --- a/radio/src/gui/128x64/model_setup.cpp +++ b/radio/src/gui/128x64/model_setup.cpp @@ -318,7 +318,9 @@ static uint8_t VIEWOPT_ROW(uint8_t value) { return expandState.viewOpt ? value : inline uint8_t MODULE_TYPE_ROWS(int moduleIdx) { - if (isModuleXJT(moduleIdx) || isModuleISRM(moduleIdx) || isModuleR9MNonAccess(moduleIdx) || isModuleDSM2(moduleIdx) || isModulePPM(moduleIdx)) + if (isModuleXJT(moduleIdx) || isModuleISRM(moduleIdx) || + isModuleR9MNonAccess(moduleIdx) || isModuleDSM2(moduleIdx) || + isModuleSBUS(moduleIdx) || isModulePPM(moduleIdx)) return 1; else return 0; @@ -1250,6 +1252,10 @@ void menuModelSetup(event_t event) lcdDrawTextAtIndex(lcdNextPos + 3, y, STR_ISRM_RF_PROTOCOLS, g_model.moduleData[INTERNAL_MODULE].subType, menuHorizontalPosition == 1 ? attr : 0); + else if (isModuleSBUS(moduleIdx)) + lcdDrawTextAtIndex(lcdNextPos + 3, y, STR_SBUS_PROTOCOLS, + g_model.moduleData[moduleIdx].subType, + menuHorizontalPosition == 1 ? attr : 0); #if defined(PPM) else if (isModulePPM(moduleIdx)) lcdDrawTextAtIndex(lcdNextPos + 3, y, STR_PPM_PROTOCOLS, @@ -1330,11 +1336,15 @@ void menuModelSetup(event_t event) CHECK_INCDEC_MODELVAR(event, g_model.moduleData[moduleIdx].subType, DSM2_PROTO_LP45, DSM2_PROTO_DSMX); + } else if (isModuleSBUS(moduleIdx)) { + CHECK_INCDEC_MODELVAR(event, + g_model.moduleData[moduleIdx].subType, + SBUS_PROTO_TLM_NONE, SBUS_PROTO_TLM_SPORT); #if defined(PPM) } else if (isModulePPM(moduleIdx)) { CHECK_INCDEC_MODELVAR(event, g_model.moduleData[moduleIdx].subType, - PPM_PROTO_TLM_NONE, PPM_PROTO_TLM_MLINK); + PPM_PROTO_TLM_NONE, PPM_PROTO_TLM_SPORT); #endif } else if (isModuleR9MNonAccess(moduleIdx)) { g_model.moduleData[moduleIdx].subType = diff --git a/radio/src/gui/212x64/model_setup.cpp b/radio/src/gui/212x64/model_setup.cpp index 0feed3cb7..7783396c0 100644 --- a/radio/src/gui/212x64/model_setup.cpp +++ b/radio/src/gui/212x64/model_setup.cpp @@ -382,7 +382,9 @@ inline uint8_t TIMER_ROW(uint8_t timer, uint8_t value) inline uint8_t EXTERNAL_MODULE_TYPE_ROW() { - if (isModuleXJT(EXTERNAL_MODULE) || isModuleR9MNonAccess(EXTERNAL_MODULE) || isModuleDSM2(EXTERNAL_MODULE) || isModuleAFHDS3(EXTERNAL_MODULE) || isModulePPM(EXTERNAL_MODULE)) + if (isModuleXJT(EXTERNAL_MODULE) || isModuleR9MNonAccess(EXTERNAL_MODULE) || + isModuleDSM2(EXTERNAL_MODULE) || isModuleAFHDS3(EXTERNAL_MODULE) || + isModuleSBUS(EXTERNAL_MODULE) || isModulePPM(EXTERNAL_MODULE)) return 1; else return 0; @@ -1103,6 +1105,8 @@ void menuModelSetup(event_t event) lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_MODULE_PROTOCOLS, reusableBuffer.moduleSetup.newType, menuHorizontalPosition==0 ? attr : 0); if (isModuleXJT(EXTERNAL_MODULE)) lcdDrawTextAtIndex(lcdNextPos + 3, y, STR_XJT_ACCST_RF_PROTOCOLS, g_model.moduleData[EXTERNAL_MODULE].subType, menuHorizontalPosition==1 ? attr : 0); + else if (isModuleSBUS(EXTERNAL_MODULE)) + lcdDrawTextAtIndex(lcdNextPos + 3, y, STR_SBUS_PROTOCOLS, g_model.moduleData[EXTERNAL_MODULE].subType, menuHorizontalPosition==1 ? attr : 0); #if defined(PPM) else if (isModulePPM(EXTERNAL_MODULE)) lcdDrawTextAtIndex(lcdNextPos + 3, y, STR_PPM_PROTOCOLS, g_model.moduleData[EXTERNAL_MODULE].subType, menuHorizontalPosition==1 ? attr : 0); @@ -1145,11 +1149,16 @@ void menuModelSetup(event_t event) event, g_model.moduleData[EXTERNAL_MODULE].subType, DSM2_PROTO_LP45, DSM2_PROTO_DSMX); } + else if (isModuleSBUS(EXTERNAL_MODULE)) { + CHECK_INCDEC_MODELVAR( + event, g_model.moduleData[EXTERNAL_MODULE].subType, + SBUS_PROTO_TLM_NONE, SBUS_PROTO_TLM_SPORT); + } #if defined(PPM) else if (isModulePPM(EXTERNAL_MODULE)) { CHECK_INCDEC_MODELVAR( event, g_model.moduleData[EXTERNAL_MODULE].subType, - PPM_PROTO_TLM_NONE, PPM_PROTO_TLM_MLINK); + PPM_PROTO_TLM_NONE, PPM_PROTO_TLM_SPORT); } #endif #if defined(MULTIMODULE) diff --git a/radio/src/gui/colorlcd/module/module_setup.cpp b/radio/src/gui/colorlcd/module/module_setup.cpp index f3ad81e6c..8c9283286 100644 --- a/radio/src/gui/colorlcd/module/module_setup.cpp +++ b/radio/src/gui/colorlcd/module/module_setup.cpp @@ -587,14 +587,15 @@ class ModuleSubTypeChoice : public Choice void setSubTypeValue(int32_t newValue) { - if (isModuleXJT(moduleIdx) || isModuleDSM2(moduleIdx) || isModuleR9MNonAccess(moduleIdx) + if (isModuleXJT(moduleIdx) || isModuleDSM2(moduleIdx) || + isModuleR9MNonAccess(moduleIdx) || isModuleSBUS(moduleIdx) #if defined(PPM) || isModulePPM(moduleIdx) #endif #if defined(PXX2) || isModuleISRM(moduleIdx) #endif - ) { + ) { if (isModuleXJT(moduleIdx)) { g_model.moduleData[moduleIdx].channelsStart = 0; g_model.moduleData[moduleIdx].channelsCount = defaultModuleChannels_M8(moduleIdx); @@ -632,10 +633,16 @@ class ModuleSubTypeChoice : public Choice setValues(STR_DSM_PROTOCOLS); setTextHandler(nullptr); } + else if (isModuleSBUS(moduleIdx)) { + setMin(SBUS_PROTO_TLM_NONE); + setMax(SBUS_PROTO_TLM_SPORT); + setValues(STR_SBUS_PROTOCOLS); + setTextHandler(nullptr); + } #if defined(PPM) else if (isModulePPM(moduleIdx)) { setMin(PPM_PROTO_TLM_NONE); - setMax(PPM_PROTO_TLM_MLINK); + setMax(PPM_PROTO_TLM_SPORT); setValues(STR_PPM_PROTOCOLS); setTextHandler(nullptr); } diff --git a/radio/src/pulses/modules_constants.h b/radio/src/pulses/modules_constants.h index 7e40d25d7..cec1dbc49 100644 --- a/radio/src/pulses/modules_constants.h +++ b/radio/src/pulses/modules_constants.h @@ -123,7 +123,13 @@ enum MMDSM2Subtypes { enum ModuleSubtypePPM { PPM_PROTO_TLM_NONE, - PPM_PROTO_TLM_MLINK + PPM_PROTO_TLM_MLINK, + PPM_PROTO_TLM_SPORT +}; + +enum ModuleSubtypeSBUS { + SBUS_PROTO_TLM_NONE, + SBUS_PROTO_TLM_SPORT }; enum ModuleSubtypeDSM2 { diff --git a/radio/src/pulses/ppm.cpp b/radio/src/pulses/ppm.cpp index 5c56150d9..c4882ffdf 100644 --- a/radio/src/pulses/ppm.cpp +++ b/radio/src/pulses/ppm.cpp @@ -118,6 +118,23 @@ static bool ppmInitMLinkTelemetry(uint8_t module) return false; } +static const etx_serial_init ppmSportSerialParams = { + .baudrate = FRSKY_SPORT_BAUDRATE, + .encoding = ETX_Encoding_8N1, + .direction = ETX_Dir_RX, + .polarity = ETX_Pol_Normal, +}; + +static bool ppmInitSPortTelemetry(uint8_t module) +{ + // Try S.PORT hardware USART (requires HW inverters) + if (modulePortInitSerial(module, ETX_MOD_PORT_SPORT, &ppmSportSerialParams, false) != nullptr) { + return true; + } + + return false; +} + static void _init_telemetry(uint8_t module, uint8_t telemetry_type) { switch (telemetry_type) { @@ -127,6 +144,12 @@ static void _init_telemetry(uint8_t module, uint8_t telemetry_type) } break; + case PPM_PROTO_TLM_SPORT: + if (ppmInitSPortTelemetry(module)) { + _processTelemetryData = processFrskySportTelemetryData; + } + break; + default: _processTelemetryData = nullptr; break; diff --git a/radio/src/pulses/pxx1.cpp b/radio/src/pulses/pxx1.cpp index c6839c277..86c8d7670 100644 --- a/radio/src/pulses/pxx1.cpp +++ b/radio/src/pulses/pxx1.cpp @@ -405,7 +405,7 @@ static void pxx1ProcessData(void* ctx, uint8_t data, uint8_t* buffer, uint8_t* l auto mod_st = (etx_module_state_t*)ctx; auto module = modulePortGetModule(mod_st); - processFrskySportTelemetryData(module, data, buffer, *len); + processFrskySportTelemetryData(module, data, buffer, len); } const etx_proto_driver_t Pxx1Driver = { diff --git a/radio/src/pulses/sbus.cpp b/radio/src/pulses/sbus.cpp index 5c6a63b34..f325c4f3b 100644 --- a/radio/src/pulses/sbus.cpp +++ b/radio/src/pulses/sbus.cpp @@ -93,6 +93,9 @@ static void setupPulsesSbus(uint8_t module, uint8_t*& p_buf) #define SBUS_BAUDRATE 100000 +typedef void (*ppm_telemetry_fct_t)(uint8_t module, uint8_t data, uint8_t* buffer, uint8_t* len); +static ppm_telemetry_fct_t _processTelemetryData; + const etx_serial_init sbusUartParams = { .baudrate = SBUS_BAUDRATE, .encoding = ETX_Encoding_8E2, @@ -100,6 +103,38 @@ const etx_serial_init sbusUartParams = { .polarity = ETX_Pol_Inverted, }; +static const etx_serial_init sbusSportSerialParams = { + .baudrate = FRSKY_SPORT_BAUDRATE, + .encoding = ETX_Encoding_8N1, + .direction = ETX_Dir_RX, + .polarity = ETX_Pol_Normal, +}; + +static bool sbusInitSPortTelemetry(uint8_t module) +{ + // Try S.PORT hardware USART (requires HW inverters) + if (modulePortInitSerial(module, ETX_MOD_PORT_SPORT, &sbusSportSerialParams, false) != nullptr) { + return true; + } + + return false; +} + +static void _init_telemetry(uint8_t module, uint8_t telemetry_type) +{ + switch (telemetry_type) { + case SBUS_PROTO_TLM_SPORT: + if (sbusInitSPortTelemetry(module)) { + _processTelemetryData = processFrskySportTelemetryData; + } + break; + + default: + _processTelemetryData = nullptr; + break; + } +} + static void* sbusInit(uint8_t module) { #if defined(HARDWARE_INTERNAL_MODULE) @@ -111,6 +146,11 @@ static void* sbusInit(uint8_t module) if (!mod_st) return nullptr; mixerSchedulerSetPeriod(module, SBUS_PERIOD(module)); + + uint8_t telemetry_type = g_model.moduleData[module].subType; + mod_st->user_data = (void*)(uintptr_t)telemetry_type; + + _init_telemetry(module, telemetry_type); return (void*)mod_st; } @@ -148,12 +188,33 @@ static void sbusSendPulses(void* ctx, uint8_t* buffer, int16_t* channels, uint8_ mixerSchedulerSetPeriod(module, SBUS_PERIOD(module)); } +static void sbusProcessTelemetryData(void* ctx, uint8_t data, uint8_t* buffer, uint8_t* len) { + auto mod_st = (etx_module_state_t*)ctx; + auto module = modulePortGetModule(mod_st); + + if (_processTelemetryData) { + _processTelemetryData(module, data, buffer, len); + } +} + +static void sbusOnConfigChange(void* ctx) +{ + auto mod_st = (etx_module_state_t*)ctx; + auto module = modulePortGetModule(mod_st); + + uint8_t telemetry_type = (uint8_t)(uintptr_t)mod_st->user_data; + if (telemetry_type != g_model.moduleData[module].subType) { + // restart during next mixer cycle + restartModuleAsync(module, 0); + } +} + const etx_proto_driver_t SBusDriver = { .protocol = PROTOCOL_CHANNELS_SBUS, .init = sbusInit, .deinit = sbusDeInit, .sendPulses = sbusSendPulses, - .processData = nullptr, + .processData = sbusProcessTelemetryData, .processFrame = nullptr, - .onConfigChange = nullptr, + .onConfigChange = sbusOnConfigChange, }; diff --git a/radio/src/telemetry/frsky.cpp b/radio/src/telemetry/frsky.cpp index 1294fef74..a58a4a8ff 100644 --- a/radio/src/telemetry/frsky.cpp +++ b/radio/src/telemetry/frsky.cpp @@ -87,16 +87,16 @@ static inline bool pushFrskyTelemetryData(bool is_sport, uint8_t data, return false; } -void processFrskyDTelemetryData(uint8_t module, uint8_t data, uint8_t* buffer, uint8_t& len) +void processFrskyDTelemetryData(uint8_t module, uint8_t data, uint8_t* buffer, uint8_t* len) { - if (pushFrskyTelemetryData(false, data, buffer, len)) { - frskyDProcessPacket(module, buffer, len); + if (pushFrskyTelemetryData(false, data, buffer, *len)) { + frskyDProcessPacket(module, buffer, *len); } } -void processFrskySportTelemetryData(uint8_t module, uint8_t data, uint8_t* buffer, uint8_t& len) +void processFrskySportTelemetryData(uint8_t module, uint8_t data, uint8_t* buffer, uint8_t* len) { - if (pushFrskyTelemetryData(true, data, buffer, len)) { - sportProcessTelemetryPacket(module, buffer, len); + if (pushFrskyTelemetryData(true, data, buffer, *len)) { + sportProcessTelemetryPacket(module, buffer, *len); } } diff --git a/radio/src/telemetry/frsky.h b/radio/src/telemetry/frsky.h index 04a399f47..5df512ec4 100644 --- a/radio/src/telemetry/frsky.h +++ b/radio/src/telemetry/frsky.h @@ -105,10 +105,10 @@ void sportProcessTelemetryPacketWithoutCrc(uint8_t module, uint8_t origin, const uint8_t *packet); void processFrskySportTelemetryData(uint8_t module, uint8_t data, - uint8_t* buffer, uint8_t& len); + uint8_t* buffer, uint8_t* len); void processFrskyDTelemetryData(uint8_t module, uint8_t data, - uint8_t* buffer, uint8_t& len); + uint8_t* buffer, uint8_t* len); #if defined(NO_RAS) inline bool isRasValueValid() diff --git a/radio/src/telemetry/multi.cpp b/radio/src/telemetry/multi.cpp index 9d4604616..2cc92f564 100644 --- a/radio/src/telemetry/multi.cpp +++ b/radio/src/telemetry/multi.cpp @@ -625,7 +625,7 @@ void processMultiTelemetryData(uint8_t data, uint8_t module) case FrskyTelemetryFallback: setMultiTelemetryBufferState(module, FrskyTelemetryFallbackFirstByte); - processFrskySportTelemetryData(module, data, rxBuffer, rxBufferCount); + processFrskySportTelemetryData(module, data, rxBuffer, &rxBufferCount); break; case FrskyTelemetryFallbackFirstByte: @@ -633,7 +633,7 @@ void processMultiTelemetryData(uint8_t data, uint8_t module) setMultiTelemetryBufferState(module, MultiStatusOrFrskyData); } else { - processFrskySportTelemetryData(module, data, rxBuffer, rxBufferCount); + processFrskySportTelemetryData(module, data, rxBuffer, &rxBufferCount); if (data != 0x7e) setMultiTelemetryBufferState(module, FrskyTelemetryFallbackNextBytes); } @@ -641,7 +641,7 @@ void processMultiTelemetryData(uint8_t data, uint8_t module) break; case FrskyTelemetryFallbackNextBytes: - processFrskySportTelemetryData(module, data, rxBuffer, rxBufferCount); + processFrskySportTelemetryData(module, data, rxBuffer, &rxBufferCount); if (data == 0x7e) { // end of packet or start of new packet setMultiTelemetryBufferState(module, FrskyTelemetryFallbackFirstByte); diff --git a/radio/src/translations.cpp b/radio/src/translations.cpp index 7f186322a..065e3986a 100644 --- a/radio/src/translations.cpp +++ b/radio/src/translations.cpp @@ -74,6 +74,7 @@ ISTR(XJT_ACCST_RF_PROTOCOLS); ISTR(ISRM_RF_PROTOCOLS); ISTR(R9M_PXX2_RF_PROTOCOLS); ISTR(PPM_PROTOCOLS); +ISTR(SBUS_PROTOCOLS); ISTR(DSM_PROTOCOLS); ISTR(AFHDS3_PROTOCOLS); ISTR(AFHDS3_POWERS); diff --git a/radio/src/translations.h b/radio/src/translations.h index bbac8bc72..94f0ccc52 100644 --- a/radio/src/translations.h +++ b/radio/src/translations.h @@ -193,6 +193,7 @@ extern const char* const STR_XJT_ACCST_RF_PROTOCOLS[]; extern const char* const STR_ISRM_RF_PROTOCOLS[]; extern const char* const STR_R9M_PXX2_RF_PROTOCOLS[]; extern const char* const STR_PPM_PROTOCOLS[]; +extern const char* const STR_SBUS_PROTOCOLS[]; extern const char* const STR_DSM_PROTOCOLS[]; extern const char* const STR_CRSF_BAUDRATE[]; extern const char* const STR_PPM_POL[]; diff --git a/radio/src/translations/untranslated.h b/radio/src/translations/untranslated.h index 97fbbbf72..b915382dc 100644 --- a/radio/src/translations/untranslated.h +++ b/radio/src/translations/untranslated.h @@ -86,7 +86,8 @@ #define TR_R9M_FCC_POWER_VALUES "10mW","100mW","500mW","1W (auto)" #define TR_R9M_LBT_POWER_VALUES "25mW 8CH","25mW 16CH","200mW NoTele","500mW NoTele" -#define TR_PPM_PROTOCOLS TR("No Telem", "No Telemetry"),"MLink" +#define TR_PPM_PROTOCOLS TR("No Telem", "No Telemetry"),"MLink","SPort" +#define TR_SBUS_PROTOCOLS TR("No Telem", "No Telemetry"),"SPort" #define TR_DSM_PROTOCOLS "LP45","DSM2","DSMX" #define TR_MULTI_PROTOCOLS PROTO_NAMES