diff --git a/companion/src/firmwares/CMakeLists.txt b/companion/src/firmwares/CMakeLists.txt index 926ad2da8..e298b2a82 100644 --- a/companion/src/firmwares/CMakeLists.txt +++ b/companion/src/firmwares/CMakeLists.txt @@ -41,6 +41,7 @@ set(firmwares_SRCS edgetx/yaml_mixdata.cpp edgetx/yaml_expodata.cpp edgetx/yaml_curvedata.cpp + edgetx/yaml_moduledata.cpp datahelpers.cpp customisation_data.cpp ) diff --git a/companion/src/firmwares/edgetx/yaml_modeldata.cpp b/companion/src/firmwares/edgetx/yaml_modeldata.cpp index b348a375b..ffca31292 100644 --- a/companion/src/firmwares/edgetx/yaml_modeldata.cpp +++ b/companion/src/firmwares/edgetx/yaml_modeldata.cpp @@ -24,6 +24,7 @@ #include "yaml_rawsource.h" #include "yaml_expodata.h" #include "yaml_curvedata.h" +#include "yaml_moduledata.h" #include "modeldata.h" #include "output_data.h" @@ -338,7 +339,12 @@ Node convert::encode(const ModelData& rhs) node["trainerMode"] = trainerModeLut << rhs.trainerMode; - // moduleData[] + for (int i=0; i::decode(const Node& node, ModelData& rhs) // rssiAlarms node["trainerMode"] >> trainerModeLut >> rhs.trainerMode; - - // moduleData[] + node["moduleData"] >> rhs.moduleData; // scriptData[] // sensorData[] diff --git a/companion/src/firmwares/edgetx/yaml_moduledata.cpp b/companion/src/firmwares/edgetx/yaml_moduledata.cpp new file mode 100644 index 000000000..9fb1f407e --- /dev/null +++ b/companion/src/firmwares/edgetx/yaml_moduledata.cpp @@ -0,0 +1,390 @@ +/* + * Copyright (C) OpenTX + * + * Based on code named + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "yaml_moduledata.h" +#include "moduledata.h" +#include "rawsource.h" + +// type: TYPE_MULTIMODULE +// subType: 15,2 +// channelsStart: 0 +// channelsCount: 12 +// failsafeMode: NOT_SET +// mod: +// multi: +// disableTelemetry: 0 +// disableMapping: 0 +// autoBindMode: 0 +// lowPowerMode: 0 +// optionValue: 0 +// receiverTelemetryOff: 0 +// receiverHigherChannels: 0 + +static const YamlLookupTable protocolLut = { + { PULSES_OFF, "TYPE_NONE" }, + { PULSES_PPM, "TYPE_PPM" }, + { PULSES_PXX_XJT_X16, "TYPE_XJT_PXX1" }, + { PULSES_ACCESS_ISRM, "TYPE_ISRM_PXX2" }, + { PULSES_LP45, "TYPE_DSM2" }, + { PULSES_CROSSFIRE, "TYPE_CROSSFIRE" }, + { PULSES_MULTIMODULE, "TYPE_MULTIMODULE" }, + { PULSES_PXX_R9M, "TYPE_R9M_PXX1" }, + { PULSES_ACCESS_R9M, "TYPE_R9M_PXX2" }, + { PULSES_PXX_R9M_LITE, "TYPE_R9M_LITE_PXX1" }, + { PULSES_ACCESS_R9M_LITE, "TYPE_R9M_LITE_PXX2" }, + { PULSES_GHOST, "TYPE_GHOST" }, + { PULSES_ACCESS_R9M_LITE_PRO, "TYPE_R9M_LITE_PRO_PXX2" }, + { PULSES_SBUS, "TYPE_SBUS" }, + { PULSES_XJT_LITE_X16, "TYPE_XJT_LITE_PXX2" }, + { PULSES_AFHDS3, "TYPE_FLYSKY" }, +}; + +static const YamlLookupTable xjtLut = { + { 0, "D16" }, + { 1, "D8" }, + { 2, "LR12" }, +}; + +static const YamlLookupTable isrmLut = { + { 0, "ACCESS" }, + { 1, "D16" }, +}; + +static const YamlLookupTable r9mLut = { + { MODULE_SUBTYPE_R9M_FCC, "FCC" }, + { MODULE_SUBTYPE_R9M_EU, "EU" }, + { MODULE_SUBTYPE_R9M_EUPLUS, "EUPLUS" }, + { MODULE_SUBTYPE_R9M_AUPLUS, "AUPLUS" }, +}; + +static const YamlLookupTable dsmLut = { + { 0, "LP45" }, + { 1, "DSM2" }, + { 3, "DSMX" }, +}; + +static const YamlLookupTable failsafeLut = { + { FAILSAFE_NOT_SET, "NOT_SET" }, + { FAILSAFE_HOLD, "HOLD" }, + { FAILSAFE_CUSTOM, "CUSTOM" }, + { FAILSAFE_NOPULSES, "NOPULSES" }, + { FAILSAFE_RECEIVER, "RECEIVER" }, +}; + +enum MMRFrskySubtypes { + MM_RF_FRSKY_SUBTYPE_D16, + MM_RF_FRSKY_SUBTYPE_D8, + MM_RF_FRSKY_SUBTYPE_D16_8CH, + MM_RF_FRSKY_SUBTYPE_V8, + MM_RF_FRSKY_SUBTYPE_D16_LBT, + MM_RF_FRSKY_SUBTYPE_D16_LBT_8CH, + MM_RF_FRSKY_SUBTYPE_D8_CLONED, + MM_RF_FRSKY_SUBTYPE_D16_CLONED +}; + +// from radio/src/pulses/multi.cpp +static void convertMultiProtocolToEtx(int *protocol, int *subprotocol) +{ + if (*protocol == 3 && *subprotocol == 0) { + *protocol = MODULE_SUBTYPE_MULTI_FRSKY + 1; + *subprotocol = MM_RF_FRSKY_SUBTYPE_D8; + return; + } + + if (*protocol == 3 && *subprotocol == 1) { + *protocol = MODULE_SUBTYPE_MULTI_FRSKY + 1; + *subprotocol = MM_RF_FRSKY_SUBTYPE_D8_CLONED; + return; + } + + if (*protocol == 25) { + *protocol = MODULE_SUBTYPE_MULTI_FRSKY + 1; + *subprotocol = MM_RF_FRSKY_SUBTYPE_V8; + return; + } + + if (*protocol == 15) { + *protocol = MODULE_SUBTYPE_MULTI_FRSKY + 1; + + if (*subprotocol == 0) + *subprotocol = MM_RF_FRSKY_SUBTYPE_D16; + else if (*subprotocol == 1) + *subprotocol = MM_RF_FRSKY_SUBTYPE_D16_8CH; + else if (*subprotocol == 2) + *subprotocol = MM_RF_FRSKY_SUBTYPE_D16_LBT; + else if (*subprotocol == 3) + *subprotocol = MM_RF_FRSKY_SUBTYPE_D16_LBT_8CH; + else if (*subprotocol == 4) + *subprotocol = MM_RF_FRSKY_SUBTYPE_D16_CLONED; + + return; + } + + if (*protocol >= 25) + *protocol -= 1; + + if (*protocol >= 16) + *protocol -= 1; +} + +void convertEtxProtocolToMulti(int *protocol, int *subprotocol) +{ + // Special treatment for the FrSky entry... + if (*protocol == MODULE_SUBTYPE_MULTI_FRSKY + 1) { + if (*subprotocol == MM_RF_FRSKY_SUBTYPE_D8) { + //D8 + *protocol = 3; + *subprotocol = 0; + } + else if (*subprotocol == MM_RF_FRSKY_SUBTYPE_D8_CLONED) { + //D8 + *protocol = 3; + *subprotocol = 1; + } + else if (*subprotocol == MM_RF_FRSKY_SUBTYPE_V8) { + //V8 + *protocol = 25; + *subprotocol = 0; + } + else { + *protocol = 15; + if (*subprotocol == MM_RF_FRSKY_SUBTYPE_D16_8CH) + *subprotocol = 1; + else if (*subprotocol == MM_RF_FRSKY_SUBTYPE_D16) + *subprotocol = 0; // D16 + else if (*subprotocol == MM_RF_FRSKY_SUBTYPE_D16_LBT) + *subprotocol = 2; + else if (*subprotocol == MM_RF_FRSKY_SUBTYPE_D16_LBT_8CH) + *subprotocol = 3; + else + *subprotocol = 4; // D16_CLONED + } + } + else { + // 15 for Multimodule is FrskyX or D16 which we map as a protocol of 3 (FrSky) + // all protos > frskyx are therefore also off by one + if (*protocol >= 15) + *protocol += 1; + // 25 is again a FrSky *protocol (FrskyV) so shift again + if (*protocol >= 25) + *protocol += 1; + } +} + +namespace YAML +{ +Node convert::encode(const ModuleData& rhs) +{ + Node node; + int protocol = rhs.protocol; + int subtype = rhs.subType; + if (rhs.protocol >= PULSES_LP45 && rhs.protocol <= PULSES_DSMX) { + protocol = PULSES_LP45; + subtype = rhs.protocol - PULSES_LP45; + } else if (rhs.protocol == PULSES_ACCST_ISRM_D16 || rhs.protocol == PULSES_ACCESS_ISRM) { + protocol = PULSES_ACCESS_ISRM; + subtype = rhs.protocol - PULSES_ACCESS_ISRM; + } else if (rhs.protocol >= PULSES_PXX_XJT_X16 && rhs.protocol <= PULSES_PXX_XJT_LR12) { + protocol = PULSES_PXX_XJT_X16; + subtype = rhs.protocol - PULSES_PXX_XJT_X16; + } else if (rhs.protocol >= PULSES_XJT_LITE_X16 && rhs.protocol <= PULSES_XJT_LITE_LR12) { + protocol = PULSES_XJT_LITE_X16; + subtype = rhs.protocol - PULSES_XJT_LITE_X16; + } + node["type"] = LookupValue(protocolLut, protocol); + + switch (protocol) { + case PULSES_PXX_XJT_X16: + case PULSES_XJT_LITE_X16: + node["subType"] = LookupValue(xjtLut, subtype); + break; + case PULSES_ACCESS_ISRM: + node["subType"] = LookupValue(isrmLut, subtype); + break; + case PULSES_PXX_R9M: + case PULSES_PXX_R9M_LITE: + node["subType"] = LookupValue(r9mLut, subtype); + break; + case PULSES_LP45: + node["subType"] = LookupValue(dsmLut, subtype); + break; + case PULSES_MULTIMODULE: { + int rfProtocol = rhs.multi.rfProtocol + 1; + int subType = rhs.subType; + convertEtxProtocolToMulti(&rfProtocol, &subType); + std::string st_str = std::to_string(rfProtocol); + st_str += ","; + st_str += std::to_string(subType); + node["subType"] = st_str; + } break; + } + + node["channelsStart"] = rhs.channelsStart; + node["channelsCount"] = rhs.channelsCount; + node["failsafeMode"] = LookupValue(failsafeLut, rhs.failsafeMode); + + Node mod; + switch (protocol) { + case PULSES_PXX_XJT_X16: + case PULSES_PXX_R9M: + case PULSES_PXX_R9M_LITE: { + Node pxx; + pxx["power"] = rhs.pxx.power; + // pxx["receiverTelemetryOff"] = rhs.pxx.receiverTelemetryOff; + // pxx["receiverHigherChannels"] = rhs.pxx.receiverHigherChannels; + pxx["antennaMode"] = rhs.pxx.antennaMode; + mod["pxx"] = pxx; + } break; + case PULSES_ACCESS_ISRM: + case PULSES_ACCESS_R9M: + case PULSES_ACCESS_R9M_LITE: + case PULSES_ACCESS_R9M_LITE_PRO: + case PULSES_XJT_LITE_X16: { + Node pxx2; + pxx2["receivers"] = rhs.access.receivers; + pxx2["racingMode"] = rhs.access.racingMode; + for (int i=0; i::decode(const Node& node, ModuleData& rhs) +{ + node["type"] >> protocolLut >> rhs.protocol; + + Node subType; + node["subType"] >> subType; + + switch (rhs.protocol) { + case PULSES_PXX_XJT_X16: + case PULSES_XJT_LITE_X16: { + int subProto = 0; + subType >> xjtLut >> subProto; + rhs.protocol += subProto; + } break; + case PULSES_ACCESS_ISRM: { + int subProto = 0; + subType >> isrmLut >> subProto; + rhs.protocol += subProto; + } break; + case PULSES_PXX_R9M: + case PULSES_PXX_R9M_LITE: { + subType >> r9mLut >> rhs.subType; + } break; + case PULSES_LP45: { + int subProto = 0; + subType >> dsmLut >> subProto; + rhs.protocol += subProto; + } break; + case PULSES_MULTIMODULE: { + std::string st_str; + subType >> st_str; + if (!st_str.empty()) { + size_t pos = 0; + int rfProtocol = std::stoi(st_str, &pos); + st_str = st_str.substr(pos + 1); + int rfSubType = std::stoi(st_str); + convertMultiProtocolToEtx(&rfProtocol, &rfSubType); + if (rfProtocol > 0) { + rhs.multi.rfProtocol = rfProtocol - 1; + rhs.subType = rfSubType; + } + } + } break; + } + + node["channelsStart"] >> rhs.channelsStart; + node["channelsCount"] >> rhs.channelsCount; + node["failsafeMode"] >> failsafeLut >> rhs.failsafeMode; + + if (node["mod"]) { + Node mod = node["mod"]; + if (mod["ppm"]) { + Node ppm = mod["ppm"]; + ppm["delay"] >> rhs.ppm.delay; + ppm["pulsePol"] >> rhs.ppm.pulsePol; + ppm["outputType"] >> rhs.ppm.outputType; + ppm["frameLength"] >> rhs.ppm.frameLength; + } else if (mod["multi"]) { + Node multi = mod["multi"]; + multi["disableTelemetry"] >> rhs.multi.disableTelemetry; + multi["disableMapping"] >> rhs.multi.disableMapping; + multi["autoBindMode"] >> rhs.multi.autoBindMode; + multi["lowPowerMode"] >> rhs.multi.lowPowerMode; + multi["optionValue"] >> rhs.multi.optionValue; + // multi["receiverTelemetryOff"] >> rhs.pxx.receiverTelemetryOff; + // multi["receiverHigherChannels"] >> rhs.pxx.receiverHigherChannels; + } else if (mod["pxx"]) { + Node pxx = mod["pxx"]; + pxx["power"] >> rhs.pxx.power; + // pxx["receiverTelemetryOff"] >> rhs.pxx.receiverTelemetryOff; + // pxx["receiverHigherChannels"] >> rhs.pxx.receiverHigherChannels; + pxx["antennaMode"] >> rhs.pxx.antennaMode; + } else if (mod["sbus"]) { + mod["sbus"]["refreshRate"] >> rhs.ppm.frameLength; + } else if (mod["pxx2"]) { + Node pxx2 = mod["pxx2"]; + pxx2["receivers"] >> rhs.access.receivers; + pxx2["racingMode"] >> rhs.access.racingMode; + for (const auto& rx : pxx2["receiverName"]) { + rx >> rhs.access.receiverName; + } + } else if (mod["flysky"]) { + //TODO + } else if (mod["afhds3"]) { + //TODO + } + } + + return true; +} +} diff --git a/companion/src/firmwares/edgetx/yaml_moduledata.h b/companion/src/firmwares/edgetx/yaml_moduledata.h new file mode 100644 index 000000000..90b4cb67b --- /dev/null +++ b/companion/src/firmwares/edgetx/yaml_moduledata.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) OpenTX + * + * Based on code named + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "yaml_ops.h" +#include "moduledata.h" + +namespace YAML +{ +template <> +struct convert { + static Node encode(const ModuleData& rhs); + static bool decode(const Node& node, ModuleData& rhs); +}; +} // namespace YAML