Skip to content

Commit

Permalink
feat: Support for ext. Multiplex MLink JR type module (#3352)
Browse files Browse the repository at this point in the history
* introducing external MLink module telemetry as module PPM subtype

* implemented fix for sensor discovery display not showing all detected sensors (is in separate PR too)

implemented PPM subtypes in Companion

* add PPM subtype to model printer

finalize subtypes for PPM in Companion

* added logic to try to use HW UART with inverters turned off first (e.g. NV14), then, if not successfull use soft serial inverted (== uninverted data due to HW inverters on PCB)

changed start bit detection IRQ priority from 5 to the previous 0 (also in separate PR)

* extended telemetry timeout to 2s due to slow Mlink RSSI update rate

* changed the "NOTLM" sub-type texts to:

- "No Telem" for 128x64 (this is the max numbers of characters it can take)
- "No Telemetry" everything else including Companion

* Companion:

- lower case 1st charachter on PpmSubTypeStrings to ppmSubTypeStrings
- added telemetry hooks for ppmSubTypeStrings stringx

* simplified serial port initialization for MLink telemetry

* editorial change: corrected obsolete comment
  • Loading branch information
mha1 authored May 16, 2023
1 parent 3d6bc63 commit 5db37e2
Show file tree
Hide file tree
Showing 21 changed files with 231 additions and 14 deletions.
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")
};

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

0 comments on commit 5db37e2

Please sign in to comment.