Skip to content

Commit

Permalink
feat: S.Port telemetry for PPM/SBUS external module (#5689)
Browse files Browse the repository at this point in the history
Co-authored-by: Michael <mha1@users.noreply.github.com>
  • Loading branch information
raphaelcoeffic and mha1 authored Dec 12, 2024
1 parent 3d1e7a9 commit 6d17448
Show file tree
Hide file tree
Showing 18 changed files with 171 additions and 28 deletions.
14 changes: 13 additions & 1 deletion companion/src/firmwares/edgetx/yaml_moduledata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down Expand Up @@ -175,6 +181,9 @@ Node convert<ModuleData>::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;
Expand Down Expand Up @@ -317,6 +326,9 @@ bool convert<ModuleData>::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;
Expand Down
10 changes: 9 additions & 1 deletion companion/src/firmwares/moduledata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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:
Expand Down
3 changes: 2 additions & 1 deletion companion/src/firmwares/moduledata.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
5 changes: 4 additions & 1 deletion companion/src/modeledit/setup_module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down
2 changes: 1 addition & 1 deletion companion/src/modelprinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
14 changes: 12 additions & 2 deletions radio/src/gui/128x64/model_setup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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 =
Expand Down
13 changes: 11 additions & 2 deletions radio/src/gui/212x64/model_setup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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)
Expand Down
13 changes: 10 additions & 3 deletions radio/src/gui/colorlcd/module/module_setup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
}
Expand Down
8 changes: 7 additions & 1 deletion radio/src/pulses/modules_constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
23 changes: 23 additions & 0 deletions radio/src/pulses/ppm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion radio/src/pulses/pxx1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down
65 changes: 63 additions & 2 deletions radio/src/pulses/sbus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,13 +93,48 @@ 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,
.direction = ETX_Dir_TX,
.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)
Expand All @@ -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;
}

Expand Down Expand Up @@ -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,
};
12 changes: 6 additions & 6 deletions radio/src/telemetry/frsky.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Loading

0 comments on commit 6d17448

Please sign in to comment.