feat: Support for ext. Multiplex MLink JR type module (#3352)
* 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
This commit is contained in:
@@ -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" },
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -626,6 +626,9 @@ void ModulePanel::update()
|
||||
case PULSES_AFHDS3:
|
||||
numEntries = 4;
|
||||
break;
|
||||
case PULSES_PPM:
|
||||
numEntries = PPM_NUM_SUBTYPES;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -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)));
|
||||
|
||||
@@ -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;
|
||||
@@ -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,
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
@@ -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))
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -24,3 +24,4 @@
|
||||
#include "hal/module_driver.h"
|
||||
|
||||
extern const etx_proto_driver_t PpmDriver;
|
||||
extern const etx_proto_driver_t PpmDriverMLink;
|
||||
|
||||
@@ -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:
|
||||
@@ -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)
|
||||
|
||||
@@ -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" },
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ struct MLinkSensor
|
||||
};
|
||||
|
||||
const MLinkSensor mlinkSensors[] = {
|
||||
{MLINK_SPECIAL, STR_SENSOR_SPECIAL, UNIT_RAW, 0},
|
||||
{MLINK_RX_VOLTAGE, STR_SENSOR_BATT, UNIT_VOLTS, 1},
|
||||
{MLINK_VOLTAGE, STR_SENSOR_VFAS, UNIT_VOLTS, 1},
|
||||
{MLINK_CURRENT, STR_SENSOR_CURR, UNIT_AMPS, 1},
|
||||
@@ -44,6 +45,7 @@ const MLinkSensor mlinkSensors[] = {
|
||||
{MLINK_CAPACITY, STR_SENSOR_CAPACITY, UNIT_MAH, 0},
|
||||
{MLINK_FLOW, STR_SENSOR_FLOW, UNIT_MILLILITERS, 0},
|
||||
{MLINK_DISTANCE, STR_SENSOR_DIST, UNIT_KM, 1},
|
||||
{MLINK_GRATE, STR_SENSOR_ACC, UNIT_G, 1},
|
||||
{MLINK_LQI, STR_SENSOR_RSSI, UNIT_RAW, 0},
|
||||
{MLINK_LOSS, STR_SENSOR_LOSS, UNIT_RAW, 0},
|
||||
{MLINK_TX_RSSI, STR_SENSOR_TX_RSSI, UNIT_RAW, 0},
|
||||
@@ -59,13 +61,17 @@ const MLinkSensor * getMLinkSensor(uint16_t id)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void processMLinkPacket(const uint8_t * packet)
|
||||
void processMLinkPacket(const uint8_t * packet, bool multi)
|
||||
{
|
||||
const uint8_t * data = packet + 2;
|
||||
const uint8_t * data = packet; // pointer to setup for external module
|
||||
|
||||
// Multi telem
|
||||
setTelemetryValue(PROTOCOL_TELEMETRY_MLINK, MLINK_TX_RSSI, 0, 0, (packet[0] * 100) / 31, UNIT_RAW, 0);
|
||||
setTelemetryValue(PROTOCOL_TELEMETRY_MLINK, MLINK_TX_LQI, 0, 0, packet[1], UNIT_RAW, 0);
|
||||
if(multi) {
|
||||
// Multi telem
|
||||
setTelemetryValue(PROTOCOL_TELEMETRY_MLINK, MLINK_TX_RSSI, 0, 0, (packet[0] * 100) / 31, UNIT_RAW, 0);
|
||||
setTelemetryValue(PROTOCOL_TELEMETRY_MLINK, MLINK_TX_LQI, 0, 0, packet[1], UNIT_RAW, 0);
|
||||
|
||||
data = &packet[2]; // correct pointer to data for Multimodule
|
||||
}
|
||||
|
||||
// M-Link telem
|
||||
if (data[0] == 0x13) { // Telemetry type RX-9
|
||||
@@ -74,6 +80,9 @@ void processMLinkPacket(const uint8_t * packet)
|
||||
val = val >> 1; // remove alarm flag
|
||||
uint8_t adress = (data[i] & 0xF0) >> 4;
|
||||
switch (data[i] & 0x0F) {
|
||||
case MLINK_SVC:
|
||||
setTelemetryValue(PROTOCOL_TELEMETRY_MLINK, MLINK_SPECIAL, 0, 0, val & 0x007f, UNIT_RAW, 0);
|
||||
break;
|
||||
case MLINK_VOLTAGE:
|
||||
if ((data[i] & 0xF0) == 0x00){
|
||||
setTelemetryValue(PROTOCOL_TELEMETRY_MLINK, MLINK_RX_VOLTAGE, 0, adress, val, UNIT_VOLTS, 1);
|
||||
@@ -121,6 +130,9 @@ void processMLinkPacket(const uint8_t * packet)
|
||||
case MLINK_DISTANCE:
|
||||
setTelemetryValue(PROTOCOL_TELEMETRY_MLINK, MLINK_DISTANCE, 0, adress, val, UNIT_KM, 1);
|
||||
break;
|
||||
case MLINK_GRATE:
|
||||
setTelemetryValue(PROTOCOL_TELEMETRY_MLINK, MLINK_GRATE, 0, adress, val, UNIT_G, 1);
|
||||
break;
|
||||
case MLINK_LQI:
|
||||
uint8_t mlinkRssi = data[i + 1] >> 1;
|
||||
setTelemetryValue(PROTOCOL_TELEMETRY_MLINK, MLINK_LQI, 0, 0, mlinkRssi, UNIT_RAW, 0);
|
||||
@@ -137,7 +149,7 @@ void processMLinkPacket(const uint8_t * packet)
|
||||
setTelemetryValue(PROTOCOL_TELEMETRY_MLINK, MLINK_LQI, 0, 0, mlinkRssi, UNIT_RAW, 0);
|
||||
telemetryData.rssi.set(mlinkRssi);
|
||||
if (mlinkRssi > 0) {
|
||||
telemetryStreaming = TELEMETRY_TIMEOUT10ms;
|
||||
telemetryStreaming = 2*TELEMETRY_TIMEOUT10ms; // extended to 2s due to slow Mlink RSSI update rate
|
||||
}
|
||||
setTelemetryValue(PROTOCOL_TELEMETRY_MLINK, MLINK_LOSS, 0, 0, packet[7], UNIT_RAW, 0);
|
||||
}
|
||||
@@ -166,3 +178,61 @@ void mlinkSetDefault(int index, uint16_t id, uint8_t subId, uint8_t instance)
|
||||
|
||||
storageDirty(EE_MODEL);
|
||||
}
|
||||
|
||||
void processExternalMLinkSerialData(void* ctx, uint8_t data, uint8_t* buffer, uint8_t* len) {
|
||||
static bool destuff = false; // byte requires adjustment
|
||||
static bool started = false; // start of frame detected
|
||||
|
||||
if(!started) { // waiting for start byte
|
||||
if (data == MSB_STX) { // start byte detected
|
||||
destuff = false; // init
|
||||
*len = 0;
|
||||
started = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(data == MSB_STUFF_ESC) { // ignore stuffing byte
|
||||
destuff = true; // and treat next byte
|
||||
return;
|
||||
}
|
||||
|
||||
if(data != MSB_ETX) { // store any other byte than end byte
|
||||
if(*len >= MSB_EXT_MODULE_PACKET_LEN) { // sanity check: number of data bytes received
|
||||
started = false; // try again
|
||||
return;
|
||||
}
|
||||
|
||||
if(destuff) { // byte requires stuffing treatment
|
||||
destuff = false;
|
||||
data -= MSB_STUFF_OFFSET; // adjust byte
|
||||
}
|
||||
|
||||
buffer[(*len)++] = data; // collect data
|
||||
return;
|
||||
}
|
||||
|
||||
started = false; // end byte received, prepare for next frame, check buffer sanity
|
||||
|
||||
if(*len != MSB_EXT_MODULE_PACKET_LEN) { // sanity check: number of data bytes received
|
||||
return;
|
||||
}
|
||||
|
||||
if(buffer[6] != MSB_NORMAL && // sanity check: telemetry ok
|
||||
buffer[6] != MSB_NORMAL_FAST && // status must be normal mode with or without fast response
|
||||
buffer[6] != MSB_RANGE && // or range test mode with or without fast response
|
||||
buffer[6] != MSB_RANGE_FAST ) { // to have valid telemetry
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t sum = 1; // sanity check: checksum
|
||||
for (uint8_t i = 0; i < MSB_EXT_MODULE_PACKET_LEN; i++)
|
||||
sum += buffer[i]; // expect sum == 1+0xff = 0x00 for valid packet
|
||||
if (sum) { // fail packet if sum is not equal to 0x00
|
||||
return;
|
||||
}
|
||||
|
||||
// buffer is sane, build MPM like buffer and process it
|
||||
buffer[6] = MSB_VALID_TELEMETRY; // indicate valid telemetry, bytes 7-12 contain 2 Mlink parameters
|
||||
processMLinkPacket(&buffer[6], false); // process telemetry packet as if it came from MPM
|
||||
}
|
||||
|
||||
@@ -35,14 +35,34 @@ enum {
|
||||
MLINK_CAPACITY = 11,
|
||||
MLINK_FLOW = 12,
|
||||
MLINK_DISTANCE = 13,
|
||||
MLINK_GRATE = 14,
|
||||
MLINK_RX_VOLTAGE = 16, // out of range ID for specific RxBt treatment
|
||||
MLINK_LOSS = 17, // out of range ID for handling number of loss
|
||||
MLINK_TX_RSSI = 18, // out of range ID for handling Telemetry RSSi reported by multi
|
||||
MLINK_TX_LQI = 19, // out of range ID for handling Telemetry LQI reported by multi
|
||||
MLINK_SPECIAL = 20, // out of raneg ID fro handling special value class
|
||||
};
|
||||
|
||||
void processMLinkTelemetryData(uint8_t data, uint8_t* rxBuffer, uint8_t& rxBufferCount);
|
||||
#define MLINK_SVC 0 // ID speial value class - can't use in enum as indexes have to start at 0
|
||||
|
||||
void mlinkSetDefault(int index, uint16_t id, uint8_t subId, uint8_t instance);
|
||||
|
||||
// Used by multi protocol
|
||||
void processMLinkPacket(const uint8_t *packet);
|
||||
void processMLinkPacket(const uint8_t *packet, bool multi);
|
||||
|
||||
// used by telemetry driver
|
||||
#define MSB_EXT_MODULE_PACKET_LEN 18 // packet length minus start and stop byte
|
||||
#define MSB_STX 0x02 // start byte
|
||||
#define MSB_ETX 0x03 // stop byte
|
||||
#define MSB_STUFF_ESC 0x1B // ESC symbol
|
||||
#define MSB_STUFF_OFFSET 0x20 // byte stuffing offset
|
||||
#define MSB_VALID_TELEMETRY 0x13
|
||||
#define MSB_NORMAL 0x06
|
||||
#define MSB_NORMAL_FAST 0x04
|
||||
#define MSB_RANGE 0x46
|
||||
#define MSB_RANGE_FAST 0x44
|
||||
|
||||
// used by external MLink module driver
|
||||
#define PPM_MSB_BAUDRATE 115200
|
||||
|
||||
void processExternalMLinkSerialData(void* ctx, uint8_t data, uint8_t* buffer, uint8_t* len);
|
||||
|
||||
@@ -410,7 +410,7 @@ static void processMultiTelemetryPaket(const uint8_t * packet, uint8_t module)
|
||||
|
||||
case MLinkTelemetry:
|
||||
if (len > 6)
|
||||
processMLinkPacket(data);
|
||||
processMLinkPacket(data, true);
|
||||
else
|
||||
TRACE("[MP] Received M-Link telemetry len %d <= 6", len);
|
||||
break;
|
||||
|
||||
@@ -564,7 +564,9 @@ int setTelemetryValue(TelemetryProtocol protocol, uint16_t id, uint8_t subId,
|
||||
case PROTOCOL_TELEMETRY_HOTT:
|
||||
hottSetDefault(index, id, subId, instance);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(MULTIMODULE) or defined(PPM)
|
||||
case PROTOCOL_TELEMETRY_MLINK:
|
||||
mlinkSetDefault(index, id, subId, instance);
|
||||
break;
|
||||
|
||||
@@ -77,6 +77,7 @@ ISTR(TELEMETRY_PROTOCOLS);
|
||||
ISTR(XJT_ACCST_RF_PROTOCOLS);
|
||||
ISTR(ISRM_RF_PROTOCOLS);
|
||||
ISTR(R9M_PXX2_RF_PROTOCOLS);
|
||||
ISTR(PPM_PROTOCOLS);
|
||||
ISTR(DSM_PROTOCOLS);
|
||||
ISTR(AFHDS3_PROTOCOLS);
|
||||
ISTR(AFHDS3_POWERS);
|
||||
|
||||
@@ -196,6 +196,7 @@ extern const char* const STR_TELEMETRY_PROTOCOLS[];
|
||||
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_DSM_PROTOCOLS[];
|
||||
extern const char* const STR_FLYSKY_PROTOCOLS[];
|
||||
extern const char* const STR_CRSF_BAUDRATE[];
|
||||
|
||||
@@ -134,6 +134,7 @@
|
||||
#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_DSM_PROTOCOLS "LP45","DSM2","DSMX"
|
||||
|
||||
#define TR_MULTI_PROTOCOLS "FlySky","Hubsan","FrSkyD","Hisky","V2x2","DSM","Devo","YD717","KN","SymaX","SLT","CX10","CG023", \
|
||||
@@ -187,6 +188,7 @@
|
||||
#define STR_SENSOR_ACCX "AccX"
|
||||
#define STR_SENSOR_ACCY "AccY"
|
||||
#define STR_SENSOR_ACCZ "AccZ"
|
||||
#define STR_SENSOR_ACC "Acc"
|
||||
#define STR_SENSOR_GYROX "GYRX"
|
||||
#define STR_SENSOR_GYROY "GYRY"
|
||||
#define STR_SENSOR_GYROZ "GYRZ"
|
||||
@@ -318,6 +320,7 @@
|
||||
#define STR_SENSOR_SERVO_VOLTAGE "SrvV"
|
||||
#define STR_SENSOR_SERVO_TEMPERATURE "SrvT"
|
||||
#define STR_SENSOR_SERVO_STATUS "SrvS"
|
||||
#define STR_SENSOR_SPECIAL "Spcl"
|
||||
|
||||
#define STR_CHAR_RIGHT "\302\200"
|
||||
#define STR_CHAR_LEFT "\302\201"
|
||||
|
||||
Reference in New Issue
Block a user