Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for external Multiplex MLink JR type module #3352

Merged
merged 9 commits into from
May 16, 2023
11 changes: 11 additions & 0 deletions companion/src/firmwares/edgetx/yaml_moduledata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@ static const YamlLookupTable r9mLut = {
{ MODULE_SUBTYPE_R9M_AUPLUS, "AUPLUS" },
};

static const YamlLookupTable ppmLut = {
{ 0, "NOTLM" },
{ 1, "MLINK" }
};

static const YamlLookupTable dsmLut = {
{ 0, "LP45" },
{ 1, "DSM2" },
Expand Down Expand Up @@ -240,6 +245,9 @@ Node convert<ModuleData>::encode(const ModuleData& rhs)
case PULSES_LP45:
node["subType"] = LookupValue(dsmLut, subtype);
break;
case PULSES_PPM:
node["subType"] = LookupValue(ppmLut, subtype);
break;
case PULSES_MULTIMODULE: {
int rfProtocol = rhs.multi.rfProtocol + 1;
int subType = rhs.subType;
Expand Down Expand Up @@ -355,6 +363,9 @@ bool convert<ModuleData>::decode(const Node& node, ModuleData& rhs)
case PULSES_PXX_R9M_LITE: {
subType >> r9mLut >> rhs.subType;
} break;
case PULSES_PPM: {
subType >> ppmLut >> rhs.subType;
} break;
case PULSES_LP45: {
int subProto = 0;
subType >> dsmLut >> subProto;
Expand Down
7 changes: 7 additions & 0 deletions companion/src/firmwares/moduledata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -247,12 +247,19 @@ QString ModuleData::subTypeToString(int type) const
"915MHz"
};

static const QString ppmSubTypeStrings[PPM_NUM_SUBTYPES] = {
tr("No Telemetry"),
tr("MLink")
};

mha1 marked this conversation as resolved.
Show resolved Hide resolved
if (type < 0)
type = subType;

switch (protocol) {
case PULSES_MULTIMODULE:
return Multiprotocols::subTypeToString((int)multi.rfProtocol, (unsigned)type);
case PULSES_PPM:
return CHECK_IN_ARRAY(ppmSubTypeStrings, type);
case PULSES_PXX_R9M:
return CHECK_IN_ARRAY(strings, type);
case PULSES_AFHDS3:
Expand Down
2 changes: 2 additions & 0 deletions companion/src/firmwares/moduledata.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,8 @@ enum ModuleSubtypeR9M {
MODULE_SUBTYPE_R9M_LAST=MODULE_SUBTYPE_R9M_AUPLUS
};

#define PPM_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.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,7 @@ void ModulePanel::update()
ui->telemetryBaudrate->setField(module.ghost.telemetryBaudrate);
break;
case PULSES_PPM:
mask |= MASK_PPM_FIELDS | MASK_SBUSPPM_FIELDS| MASK_CHANNELS_RANGE| MASK_CHANNELS_COUNT;
mask |= MASK_SUBTYPES | MASK_PPM_FIELDS | MASK_SBUSPPM_FIELDS| MASK_CHANNELS_RANGE| MASK_CHANNELS_COUNT;
if (IS_9XRPRO(board)) {
mask |= MASK_OPEN_DRAIN;
}
Expand Down Expand Up @@ -626,6 +626,9 @@ void ModulePanel::update()
case PULSES_AFHDS3:
numEntries = 4;
break;
case PULSES_PPM:
numEntries = PPM_NUM_SUBTYPES;
break;
default:
break;
}
Expand Down
2 changes: 2 additions & 0 deletions companion/src/modelprinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,8 @@ QString ModelPrinter::printModule(int idx)
else {
str << printLabelValue(tr("Protocol"), ModuleData::protocolToString(module.protocol));
if (module.protocol) {
if (module.protocol == PULSES_PPM)
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) {
str << printLabelValue(tr("Frame length"), QString("%1ms").arg(printPPMFrameLength(module.ppm.frameLength)));
Expand Down
14 changes: 13 additions & 1 deletion radio/src/gui/128x64/model_setup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ enum MenuModelSetupItems {

inline uint8_t MODULE_TYPE_ROWS(int moduleIdx)
{
if (isModuleXJT(moduleIdx) || isModuleISRM(moduleIdx) || isModuleR9MNonAccess(moduleIdx) || isModuleDSM2(moduleIdx))
if (isModuleXJT(moduleIdx) || isModuleISRM(moduleIdx) || isModuleR9MNonAccess(moduleIdx) || isModuleDSM2(moduleIdx) || isModulePPM(moduleIdx))
return 1;
else
return 0;
Expand Down Expand Up @@ -1055,6 +1055,12 @@ void menuModelSetup(event_t event)
lcdDrawTextAtIndex(lcdNextPos + 3, y, STR_ISRM_RF_PROTOCOLS,
g_model.moduleData[INTERNAL_MODULE].subType,
menuHorizontalPosition == 1 ? attr : 0);
#if defined(PPM)
else if (isModulePPM(moduleIdx))
lcdDrawTextAtIndex(lcdNextPos + 3, y, STR_PPM_PROTOCOLS,
g_model.moduleData[moduleIdx].subType,
menuHorizontalPosition == 1 ? attr : 0);
#endif
else if (isModuleDSM2(moduleIdx))
lcdDrawTextAtIndex(lcdNextPos + 3, y, STR_DSM_PROTOCOLS,
g_model.moduleData[moduleIdx].subType,
Expand Down Expand Up @@ -1129,6 +1135,12 @@ void menuModelSetup(event_t event)
CHECK_INCDEC_MODELVAR(event,
g_model.moduleData[moduleIdx].subType,
DSM2_PROTO_LP45, DSM2_PROTO_DSMX);
#if defined(PPM)
} else if (isModulePPM(moduleIdx)) {
CHECK_INCDEC_MODELVAR(event,
g_model.moduleData[moduleIdx].subType,
PPM_PROTO_TLM_NONE, PPM_PROTO_TLM_MLINK);
#endif
} else if (isModuleR9MNonAccess(moduleIdx)) {
g_model.moduleData[moduleIdx].subType =
checkIncDec(event, g_model.moduleData[moduleIdx].subType,
Expand Down
11 changes: 10 additions & 1 deletion radio/src/gui/212x64/model_setup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ void editTimerCountdown(int timerIdx, coord_t y, LcdFlags attr, event_t event)

inline uint8_t EXTERNAL_MODULE_TYPE_ROW()
{
if (isModuleXJT(EXTERNAL_MODULE) || isModuleR9MNonAccess(EXTERNAL_MODULE) || isModuleDSM2(EXTERNAL_MODULE) || isModuleAFHDS3(EXTERNAL_MODULE))
if (isModuleXJT(EXTERNAL_MODULE) || isModuleR9MNonAccess(EXTERNAL_MODULE) || isModuleDSM2(EXTERNAL_MODULE) || isModuleAFHDS3(EXTERNAL_MODULE) || isModulePPM(EXTERNAL_MODULE))
return 1;
else
return 0;
Expand Down Expand Up @@ -1012,6 +1012,10 @@ 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);
#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);
#endif
else if (isModuleDSM2(EXTERNAL_MODULE))
lcdDrawTextAtIndex(lcdNextPos + 3, y, STR_DSM_PROTOCOLS, g_model.moduleData[EXTERNAL_MODULE].subType, menuHorizontalPosition==1 ? attr : 0);
else if (isModuleR9MNonAccess(EXTERNAL_MODULE))
Expand Down Expand Up @@ -1045,7 +1049,12 @@ void menuModelSetup(event_t event)
case 1:
if (isModuleDSM2(EXTERNAL_MODULE)) {
CHECK_INCDEC_MODELVAR(event, g_model.moduleData[EXTERNAL_MODULE].subType, DSM2_PROTO_LP45, DSM2_PROTO_DSMX);
}
#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);
}
#endif
#if defined(MULTIMODULE)
else if (isModuleMultimodule(EXTERNAL_MODULE)) {
int multiRfProto = g_model.moduleData[EXTERNAL_MODULE].multi.rfProtocol;
Expand Down
11 changes: 11 additions & 0 deletions radio/src/gui/colorlcd/module_setup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -598,6 +598,17 @@ void ModuleSubTypeChoice::update()
setAvailableHandler(nullptr);
setTextHandler(nullptr);
}
#if defined(PPM)
else if (isModulePPM(moduleIdx)) {
setMin(PPM_PROTO_TLM_NONE);
setMax(PPM_PROTO_TLM_MLINK);
setValues(STR_PPM_PROTOCOLS);
setGetValueHandler(GET_DEFAULT(md->subType));
setSetValueHandler(SET_DEFAULT(md->subType));
setAvailableHandler(nullptr);
setTextHandler(nullptr);
}
#endif
else if (isModuleR9MNonAccess(moduleIdx)) {
setMin(MODULE_SUBTYPE_R9M_FCC);
setMax(MODULE_SUBTYPE_R9M_LAST);
Expand Down
1 change: 1 addition & 0 deletions radio/src/hal/module_driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ enum ChannelsProtocols {
PROTOCOL_CHANNELS_UNINITIALIZED,
PROTOCOL_CHANNELS_NONE,
PROTOCOL_CHANNELS_PPM,
PROTOCOL_CHANNELS_PPM_MLINK,
PROTOCOL_CHANNELS_PXX1,
PROTOCOL_CHANNELS_DSM2_LP45,
PROTOCOL_CHANNELS_DSM2_DSM2,
Expand Down
5 changes: 4 additions & 1 deletion radio/src/pulses/modules_constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,10 @@ enum MMDSM2Subtypes {
MM_RF_DSM2_SUBTYPE_AUTO
};


enum ModuleSubtypePPM {
PPM_PROTO_TLM_NONE,
PPM_PROTO_TLM_MLINK
};

enum ModuleSubtypeDSM2 {
DSM2_PROTO_LP45,
Expand Down
36 changes: 36 additions & 0 deletions radio/src/pulses/ppm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@

#include "opentx.h"

#include "telemetry/mlink.h"

// Minimum space after the last PPM pulse in us
#define PPM_SAFE_MARGIN 3000 // 3ms

Expand Down Expand Up @@ -158,3 +160,37 @@ const etx_proto_driver_t PpmDriver = {
.sendPulses = ppmSendPulses,
.processData = nullptr,
};

//
// additions for PPM with external MLink Module telemetry
//

static void* ppmMLinkInit(uint8_t module);

const etx_proto_driver_t PpmDriverMLink = {
.protocol = PROTOCOL_CHANNELS_PPM_MLINK,
.init = ppmMLinkInit,
.deinit = ppmDeInit,
.sendPulses = ppmSendPulses,
.processData = processExternalMLinkSerialData,
};

static etx_serial_init ppmMLinkSerialParams = {
.baudrate = PPM_MSB_BAUDRATE,
.encoding = ETX_Encoding_8N1,
.direction = ETX_Dir_RX,
.polarity = ETX_Pol_Inverted,
};

static void* ppmMLinkInit(uint8_t module) {
etx_module_state_t *mod_st = (etx_module_state_t *)ppmInit(module);

if (!mod_st)
return nullptr;

if (!modulePortInitSerial(module, ETX_MOD_PORT_UART, &ppmMLinkSerialParams)) {
modulePortInitSerial(module, ETX_MOD_PORT_SPORT_INV, &ppmMLinkSerialParams);
}

return (void*)mod_st;
}
1 change: 1 addition & 0 deletions radio/src/pulses/ppm.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@
#include "hal/module_driver.h"

extern const etx_proto_driver_t PpmDriver;
extern const etx_proto_driver_t PpmDriverMLink;
14 changes: 13 additions & 1 deletion radio/src/pulses/pulses.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,16 @@ uint8_t getRequiredProtocol(uint8_t module)

switch (getModuleType(module)) {
case MODULE_TYPE_PPM:
protocol = PROTOCOL_CHANNELS_PPM;
switch (g_model.moduleData[module].subType) {
case PPM_PROTO_TLM_NONE:
protocol = PROTOCOL_CHANNELS_PPM;
break;
case PPM_PROTO_TLM_MLINK:
protocol = PROTOCOL_CHANNELS_PPM_MLINK;
break;
default:
protocol = PROTOCOL_CHANNELS_PPM;
}
break;

case MODULE_TYPE_XJT_PXX1:
Expand Down Expand Up @@ -462,6 +471,9 @@ static void pulsesEnableModule(uint8_t module, uint8_t protocol)
case PROTOCOL_CHANNELS_PPM:
_init_module(module, &PpmDriver);
break;
case PROTOCOL_CHANNELS_PPM_MLINK:
_init_module(module, &PpmDriverMLink);
break;
#endif

#if defined(INTERNAL_MODULE_AFHDS2A) && defined(AFHDS2)
Expand Down
10 changes: 10 additions & 0 deletions radio/src/storage/yaml/yaml_datastructs_funcs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1845,6 +1845,12 @@ static const struct YamlIdStr enum_FLYSKY_Subtypes[] = {
{ 0, NULL }
};

static const struct YamlIdStr enum_PPM_Subtypes[] = {
{ 0, "NOTLM" },
{ 1, "MLINK" },
{ 0, NULL }
};

static const struct YamlIdStr enum_DSM2_Subtypes[] = {
{ 0, "LP45" },
{ 1, "DSM2" },
Expand Down Expand Up @@ -1888,6 +1894,8 @@ static void r_modSubtype(void* user, uint8_t* data, uint32_t bitoffs,
#endif
} else if (md->type == MODULE_TYPE_DSM2) {
md->subType = yaml_parse_enum(enum_DSM2_Subtypes, val, val_len);
} else if (md->type == MODULE_TYPE_PPM) {
md->subType = yaml_parse_enum(enum_PPM_Subtypes, val, val_len);
} else {
md->subType = yaml_str2uint(val, val_len);
}
Expand Down Expand Up @@ -1925,6 +1933,8 @@ static bool w_modSubtype(void* user, uint8_t* data, uint32_t bitoffs,
#endif
} else if (md->type == MODULE_TYPE_DSM2) {
str = yaml_output_enum(md->subType, enum_DSM2_Subtypes);
} else if (md->type == MODULE_TYPE_PPM) {
str = yaml_output_enum(md->subType, enum_PPM_Subtypes);
} else {
str = yaml_unsigned2str(val);
}
Expand Down
Loading