diff --git a/companion/src/firmwares/edgetx/yaml_moduledata.cpp b/companion/src/firmwares/edgetx/yaml_moduledata.cpp index ff9c4a5a5eb..9219a586e49 100644 --- a/companion/src/firmwares/edgetx/yaml_moduledata.cpp +++ b/companion/src/firmwares/edgetx/yaml_moduledata.cpp @@ -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::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::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; diff --git a/companion/src/firmwares/moduledata.cpp b/companion/src/firmwares/moduledata.cpp index 37985a64d40..bea6aa14235 100644 --- a/companion/src/firmwares/moduledata.cpp +++ b/companion/src/firmwares/moduledata.cpp @@ -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: diff --git a/companion/src/firmwares/moduledata.h b/companion/src/firmwares/moduledata.h index e554e69e99a..4d927c01f78 100644 --- a/companion/src/firmwares/moduledata.h +++ b/companion/src/firmwares/moduledata.h @@ -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; diff --git a/companion/src/modeledit/setup.cpp b/companion/src/modeledit/setup.cpp index 05f5bbfe9f4..edfc73a6f9c 100644 --- a/companion/src/modeledit/setup.cpp +++ b/companion/src/modeledit/setup.cpp @@ -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; } diff --git a/companion/src/modelprinter.cpp b/companion/src/modelprinter.cpp index 79283eac14b..7e851205700 100644 --- a/companion/src/modelprinter.cpp +++ b/companion/src/modelprinter.cpp @@ -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))); diff --git a/radio/src/gui/128x64/model_setup.cpp b/radio/src/gui/128x64/model_setup.cpp index 42ce9cc39b2..ece655ee41d 100644 --- a/radio/src/gui/128x64/model_setup.cpp +++ b/radio/src/gui/128x64/model_setup.cpp @@ -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, diff --git a/radio/src/gui/212x64/model_setup.cpp b/radio/src/gui/212x64/model_setup.cpp index 91ee9f8abfc..e2fb9426ef9 100644 --- a/radio/src/gui/212x64/model_setup.cpp +++ b/radio/src/gui/212x64/model_setup.cpp @@ -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; diff --git a/radio/src/gui/colorlcd/module_setup.cpp b/radio/src/gui/colorlcd/module_setup.cpp index 5cb47173d71..e2cd59754b8 100644 --- a/radio/src/gui/colorlcd/module_setup.cpp +++ b/radio/src/gui/colorlcd/module_setup.cpp @@ -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); diff --git a/radio/src/hal/module_driver.h b/radio/src/hal/module_driver.h index 11c04023c39..2c9489fd328 100644 --- a/radio/src/hal/module_driver.h +++ b/radio/src/hal/module_driver.h @@ -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, diff --git a/radio/src/pulses/modules_constants.h b/radio/src/pulses/modules_constants.h index 0d7223023c6..69db89c620c 100644 --- a/radio/src/pulses/modules_constants.h +++ b/radio/src/pulses/modules_constants.h @@ -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, diff --git a/radio/src/pulses/ppm.cpp b/radio/src/pulses/ppm.cpp index 3dafbd29d04..8792e934622 100644 --- a/radio/src/pulses/ppm.cpp +++ b/radio/src/pulses/ppm.cpp @@ -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; +} diff --git a/radio/src/pulses/ppm.h b/radio/src/pulses/ppm.h index 336ace47b34..e8834aeccc5 100644 --- a/radio/src/pulses/ppm.h +++ b/radio/src/pulses/ppm.h @@ -24,3 +24,4 @@ #include "hal/module_driver.h" extern const etx_proto_driver_t PpmDriver; +extern const etx_proto_driver_t PpmDriverMLink; diff --git a/radio/src/pulses/pulses.cpp b/radio/src/pulses/pulses.cpp index 641b25fb642..7a5091909a7 100755 --- a/radio/src/pulses/pulses.cpp +++ b/radio/src/pulses/pulses.cpp @@ -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) diff --git a/radio/src/storage/yaml/yaml_datastructs_funcs.cpp b/radio/src/storage/yaml/yaml_datastructs_funcs.cpp index 9637fae6bc1..94def2f5e18 100644 --- a/radio/src/storage/yaml/yaml_datastructs_funcs.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_funcs.cpp @@ -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); } diff --git a/radio/src/telemetry/mlink.cpp b/radio/src/telemetry/mlink.cpp index c2caf003218..e1ee4856029 100644 --- a/radio/src/telemetry/mlink.cpp +++ b/radio/src/telemetry/mlink.cpp @@ -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 +} diff --git a/radio/src/telemetry/mlink.h b/radio/src/telemetry/mlink.h index 85c13836cd2..5ecc8d6e4f8 100644 --- a/radio/src/telemetry/mlink.h +++ b/radio/src/telemetry/mlink.h @@ -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); diff --git a/radio/src/telemetry/multi.cpp b/radio/src/telemetry/multi.cpp index c668e1bd836..38f09984d4c 100644 --- a/radio/src/telemetry/multi.cpp +++ b/radio/src/telemetry/multi.cpp @@ -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; diff --git a/radio/src/telemetry/telemetry_sensors.cpp b/radio/src/telemetry/telemetry_sensors.cpp index f7b88e1beea..a2ce55428fb 100644 --- a/radio/src/telemetry/telemetry_sensors.cpp +++ b/radio/src/telemetry/telemetry_sensors.cpp @@ -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; diff --git a/radio/src/translations.cpp b/radio/src/translations.cpp index a6ab9410688..67d5b3cce0e 100644 --- a/radio/src/translations.cpp +++ b/radio/src/translations.cpp @@ -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); diff --git a/radio/src/translations.h b/radio/src/translations.h index 4e01b2c6e60..c30b4318c6f 100644 --- a/radio/src/translations.h +++ b/radio/src/translations.h @@ -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[]; diff --git a/radio/src/translations/untranslated.h b/radio/src/translations/untranslated.h index 51d5f0584ac..397ed5c7990 100644 --- a/radio/src/translations/untranslated.h +++ b/radio/src/translations/untranslated.h @@ -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"