diff --git a/companion/src/firmwares/edgetx/edgetxinterface.cpp b/companion/src/firmwares/edgetx/edgetxinterface.cpp index ad31f1f15..e75428b2b 100644 --- a/companion/src/firmwares/edgetx/edgetxinterface.cpp +++ b/companion/src/firmwares/edgetx/edgetxinterface.cpp @@ -42,7 +42,7 @@ static void writeYamlToByteArray(const YAML::Node& node, QByteArray& data) qDebug() << data_ostream.str().c_str(); } -bool loadModelsListFromYaml(std::vector categories, +bool loadModelsListFromYaml(std::vector& categories, EtxModelfiles& modelFiles, const QByteArray& data) { @@ -102,16 +102,42 @@ bool loadRadioSettingsFromYaml(GeneralSettings& settings, const QByteArray& data return true; } +// TODO: +// 'modelFiles' should be ordered by Category index to avoid +// turning the sequence into a map. +// +bool writeModelsListToYaml(const std::vector& categories, + const EtxModelfiles& modelFiles, + QByteArray& data) +{ + YAML::Node node; + for (const auto& modelFile: modelFiles) { + + YAML::Node cat_attrs; + cat_attrs["filename"] = modelFile.first; + + const std::string cat_name = categories[modelFile.second].name; + node[modelFile.second][cat_name].push_back(cat_attrs); + } + + writeYamlToByteArray(node, data); + return true; +} + bool writeModelToYaml(const ModelData& model, QByteArray& data) { - return false; + YAML::Node node; + node = model; + + writeYamlToByteArray(node, data); + return true; } bool writeRadioSettingsToYaml(const GeneralSettings& settings, QByteArray& data) { YAML::Node node; node = settings; - writeYamlToByteArray(node, data); + writeYamlToByteArray(node, data); return false; } diff --git a/companion/src/firmwares/edgetx/edgetxinterface.h b/companion/src/firmwares/edgetx/edgetxinterface.h index 641f080ee..e3743c829 100644 --- a/companion/src/firmwares/edgetx/edgetxinterface.h +++ b/companion/src/firmwares/edgetx/edgetxinterface.h @@ -30,12 +30,16 @@ typedef std::pair EtxModelfileCategoryPair; typedef std::list EtxModelfiles; -bool loadModelsListFromYaml(std::vector categories, +bool loadModelsListFromYaml(std::vector& categories, EtxModelfiles& modelFiles, const QByteArray& data); bool loadModelFromYaml(ModelData& model, const QByteArray& data); bool loadRadioSettingsFromYaml(GeneralSettings& settings, const QByteArray& data); +bool writeModelsListToYaml(const std::vector& categories, + const EtxModelfiles& modelFiles, + QByteArray& data); + bool writeModelToYaml(const ModelData& model, QByteArray& data); bool writeRadioSettingsToYaml(const GeneralSettings& settings, QByteArray& data); diff --git a/companion/src/firmwares/edgetx/yaml_modeldata.cpp b/companion/src/firmwares/edgetx/yaml_modeldata.cpp index 968f7949a..e31989958 100644 --- a/companion/src/firmwares/edgetx/yaml_modeldata.cpp +++ b/companion/src/firmwares/edgetx/yaml_modeldata.cpp @@ -21,7 +21,7 @@ #include "yaml_modeldata.h" #include "modeldata.h" -const YamlLookupTable timerModeLut = { +static const YamlLookupTable timerModeLut = { {TimerData::TIMERMODE_OFF, "OFF"}, {TimerData::TIMERMODE_ON, "ON"}, {TimerData::TIMERMODE_START, "START"}, @@ -30,7 +30,7 @@ const YamlLookupTable timerModeLut = { {TimerData::TIMERMODE_THR_START, "THR_START"}, }; -const YamlLookupTable trainerModeLut = { +static const YamlLookupTable trainerModeLut = { { TRAINER_MODE_OFF, "OFF" }, { TRAINER_MODE_MASTER_JACK, "MASTER_TRAINER_JACK" }, { TRAINER_MODE_SLAVE_JACK, "SLAVE" }, @@ -41,3 +41,172 @@ const YamlLookupTable trainerModeLut = { { TRAINER_MODE_SLAVE_BLUETOOTH, "SLAVE_BT" }, { TRAINER_MODE_MULTI, "MASTER_MULTI" }, }; + +namespace YAML +{ +Node convert::encode(const TimerData& rhs) +{ + Node node; + node["swtch"] = rhs.swtch; + node["mode"] = timerModeLut << rhs.mode; + node["name"] = rhs.name; + node["minuteBeep"] = rhs.minuteBeep; + node["countdownBeep"] = rhs.countdownBeep; + node["start"] = rhs.val; + node["persistent"] = rhs.persistent; + node["countdownStart"] = rhs.countdownStart; + node["value"] = rhs.pvalue; + return node; +} + +bool convert::decode(const Node& node, TimerData& rhs) +{ + node["swtch"] >> rhs.swtch; + node["mode"] >> timerModeLut >> rhs.mode; + node["name"] >> rhs.name; + node["minuteBeep"] >> rhs.minuteBeep; + node["countdownBeep"] >> rhs.countdownBeep; + node["start"] >> rhs.val; + node["persistent"] >> rhs.persistent; + node["countdownStart"] >> rhs.countdownStart; + node["value"] >> rhs.pvalue; + return true; +} + +Node convert::encode(const ModelData& rhs) +{ + Node node; + node["header"]["name"] = rhs.name; + node["header"]["bitmap"] = rhs.bitmap; + // TODO: modelId + + for (int i=0; i::decode(const Node& node, ModelData& rhs) +{ + if (!node.IsMap()) return false; + + if (node["header"]) { + const auto& header = node["header"]; + if (!header.IsMap()) return false; + + header["name"] >> rhs.name; + header["bitmap"] >> rhs.bitmap; + // TODO: modelId + } + + if (node["timers"]) { + const auto& timers = node["timers"]; + if (!timers.IsMap()) return false; + timers >> rhs.timers; + } + + node["noGlobalFunctions"] >> rhs.noGlobalFunctions; + node["thrTrim"] >> rhs.thrTrim; + node["trimInc"] >> rhs.trimInc; + node["displayTrims"] >> rhs.trimsDisplay; + node["disableThrottleWarning"] >> rhs.disableThrottleWarning; + // node[] >> rhs.beepANACenter; + node["extendedLimits"] >> rhs.extendedLimits; + node["extendedTrims"] >> rhs.extendedTrims; + node["throttleReversed"] >> rhs.throttleReversed; + + // flightModeData[] + // mixData[] + // limitData[] + // inputNames[] + // expoData[] + // curves[] + // logicalSw[] + // customFn[] + + // swashRingData + // thrTraceSrc + // switchWarningStates + // thrTrimSwitch + // potsWarningMode + // potsWarnEnabled[] + // potsWarnPosition[] + + node["displayChecklist"] >> rhs.displayChecklist; + + // gvarData[] + // mavlink ??? + // telemetryProtocol ??? + // frsky + // rssiSource + // rssiAlarms + + node["trainerMode"] >> trainerModeLut >> rhs.trainerMode; + + // moduleData[] + // scriptData[] + // sensorData[] + + node["toplcdTimer"] >> rhs.toplcdTimer; + + // customScreens + // topBarData + node["view"] >> rhs.view; + node["modelRegistrationID"] >> rhs.registrationId; + + return true; +} + +} // namespace YAML diff --git a/companion/src/firmwares/edgetx/yaml_modeldata.h b/companion/src/firmwares/edgetx/yaml_modeldata.h index afdee120f..5150d25da 100644 --- a/companion/src/firmwares/edgetx/yaml_modeldata.h +++ b/companion/src/firmwares/edgetx/yaml_modeldata.h @@ -25,118 +25,17 @@ #include -extern const YamlLookupTable timerModeLut; -extern const YamlLookupTable trainerModeLut; - -// extern const YamlLookupTable backlightModeLut; -// extern const YamlLookupTable bluetoothModeLut; -// extern const YamlLookupTable uartModeLut; -// extern const YamlLookupTable antennaModeLut; - namespace YAML { -// ENUM_CONVERTER(GeneralSettings::BeeperMode, beeperModeLut); - template <> struct convert { - // static YAML::Node encode(const GeneralSettings& rhs) { - // Node node; - // // TODO: convert struct into Node - // return node; - // } - - static bool decode(const Node& node, TimerData& rhs) - { - node["swtch"] >> rhs.swtch; - node["mode"] >> timerModeLut >> rhs.mode; - node["name"] >> rhs.name; - node["minuteBeep"] >> rhs.minuteBeep; - node["countdownBeep"] >> rhs.countdownBeep; - node["start"] >> rhs.val; - node["persistent"] >> rhs.persistent; - node["countdownStart"] >> rhs.countdownStart; - node["value"] >> rhs.pvalue; - return true; - } + static Node encode(const TimerData& rhs); + static bool decode(const Node& node, TimerData& rhs); }; template <> struct convert { - // static YAML::Node encode(const GeneralSettings& rhs) { - // Node node; - // // TODO: convert struct into Node - // return node; - // } - - static bool decode(const Node& node, ModelData& rhs) - { - if (!node.IsMap()) return false; - - if (node["header"]) { - const auto& header = node["header"]; - if (!header.IsMap()) return false; - - header["name"] >> rhs.name; - header["bitmap"] >> rhs.bitmap; - // TODO: modelId - } - - if (node["timers"]) { - const auto& timers = node["timers"]; - if (!timers.IsMap()) return false; - timers >> rhs.timers; - } - - node["noGlobalFunctions"] >> rhs.noGlobalFunctions; - node["thrTrim"] >> rhs.thrTrim; - node["trimInc"] >> rhs.trimInc; - node["displayTrims"] >> rhs.trimsDisplay; - node["disableThrottleWarning"] >> rhs.disableThrottleWarning; - //node[] >> rhs.beepANACenter; - node["extendedLimits"] >> rhs.extendedLimits; - node["extendedTrims"] >> rhs.extendedTrims; - node["throttleReversed"] >> rhs.throttleReversed; - - //flightModeData[] - //mixData[] - //limitData[] - //inputNames[] - //expoData[] - //curves[] - //logicalSw[] - //customFn[] - - //swashRingData - //thrTraceSrc - //switchWarningStates - //thrTrimSwitch - //potsWarningMode - //potsWarnEnabled[] - //potsWarnPosition[] - - node["displayChecklist"] >> rhs.displayChecklist; - - //gvarData[] - //mavlink ??? - //telemetryProtocol ??? - //frsky - //rssiSource - //rssiAlarms - - node["trainerMode"] >> trainerModeLut >> rhs.trainerMode; - - //moduleData[] - //scriptData[] - //sensorData[] - - node["toplcdTimer"] >> rhs.toplcdTimer; - - //customScreens - //topBarData - node["view"] >> rhs.view; - node["modelRegistrationID"] >> rhs.registrationId; - - return true; - } + static Node encode(const ModelData& rhs); + static bool decode(const Node& node, ModelData& rhs); }; } // namespace YAML diff --git a/companion/src/firmwares/edgetx/yaml_ops.cpp b/companion/src/firmwares/edgetx/yaml_ops.cpp index 4cb877175..ed7983fb3 100644 --- a/companion/src/firmwares/edgetx/yaml_ops.cpp +++ b/companion/src/firmwares/edgetx/yaml_ops.cpp @@ -56,7 +56,7 @@ void operator >> (const YAML::Node& node, bool& value) namespace YAML { -Node operator << (const YamlLookupTable& lut, const int& value) +std::string LookupValue(const YamlLookupTable& lut, const int& value) { const auto& it = find_if(lut.begin(), lut.end(), [=](const YamlLookupTableElmt& elmt) { @@ -65,7 +65,17 @@ Node operator << (const YamlLookupTable& lut, const int& value) }); if (it != lut.end()) { - return Node(it->second); + return it->second; + } + + return std::string(); +} + +Node operator << (const YamlLookupTable& lut, const int& value) +{ + std::string str = LookupValue(lut, value); + if (!str.empty()) { + return Node(str); } return Node(); } diff --git a/companion/src/firmwares/edgetx/yaml_ops.h b/companion/src/firmwares/edgetx/yaml_ops.h index 9b5c81d26..52f90082a 100644 --- a/companion/src/firmwares/edgetx/yaml_ops.h +++ b/companion/src/firmwares/edgetx/yaml_ops.h @@ -113,6 +113,7 @@ void operator>>(const YAML::Node& node, T (&value)[N]) namespace YAML { +std::string LookupValue(const YamlLookupTable& lut, const int& value); Node operator << (const YamlLookupTable& lut, const int& value); template diff --git a/companion/src/firmwares/edgetx/yaml_rawswitch.cpp b/companion/src/firmwares/edgetx/yaml_rawswitch.cpp index 4794dc2f4..9bad86be9 100644 --- a/companion/src/firmwares/edgetx/yaml_rawswitch.cpp +++ b/companion/src/firmwares/edgetx/yaml_rawswitch.cpp @@ -50,6 +50,55 @@ namespace YAML { ENUM_CONVERTER(RawSwitchType, switchTypeLut); +Node convert::encode(const RawSwitch& rhs) +{ + std::string sw_str; + + int32_t sval = rhs.index; + if (rhs.index < 0) { + sval = -sval; + sw_str += "!"; + } + + switch (rhs.type) { + case SWITCH_TYPE_SWITCH: + sw_str += 'S'; + sw_str += 'A' + sval; + break; + + case SWITCH_TYPE_VIRTUAL: + sw_str += "L"; + sw_str += std::to_string(sval + 1); + break; + + case SWITCH_TYPE_MULTIPOS_POT: + sw_str += "6P"; + sw_str += std::to_string(sval / XPOTS_MULTIPOS_COUNT); + sw_str += std::to_string(sval % XPOTS_MULTIPOS_COUNT); + break; + + case SWITCH_TYPE_TRIM: + sw_str += LookupValue(trimSwitchLut, sval); + break; + + case SWITCH_TYPE_FLIGHT_MODE: + sw_str += "FM"; + sw_str += std::to_string(sval); + break; + + case SWITCH_TYPE_SENSOR: + sw_str += "T"; + sw_str += std::to_string(sval + 1); + break; + + default: + sw_str += LookupValue(switchTypeLut, rhs.type); + break; + } + + return Node(sw_str); +} + bool convert::decode(const Node& node, RawSwitch& rhs) { const std::string& sw_str = node.Scalar(); diff --git a/companion/src/firmwares/edgetx/yaml_rawswitch.h b/companion/src/firmwares/edgetx/yaml_rawswitch.h index ce0031e57..95128aac2 100644 --- a/companion/src/firmwares/edgetx/yaml_rawswitch.h +++ b/companion/src/firmwares/edgetx/yaml_rawswitch.h @@ -25,7 +25,7 @@ namespace YAML { template <> struct convert { - // static YAML::Node encode(const GeneralSettings& rhs); + static Node encode(const RawSwitch& rhs); static bool decode(const Node& node, RawSwitch& rhs); }; diff --git a/companion/src/storage/categorized.cpp b/companion/src/storage/categorized.cpp index 420a9b666..a32442587 100644 --- a/companion/src/storage/categorized.cpp +++ b/companion/src/storage/categorized.cpp @@ -290,5 +290,30 @@ bool CategorizedStorageFormat::writeYaml(const RadioData & radioData) return false; } - return writeFile(radioSettingsBuffer, "RADIO/radio.yml"); + if (!writeFile(radioSettingsBuffer, "RADIO/radio.yml")) { + return false; + } + + EtxModelfiles modelFiles; + for (const auto& model : radioData.models) { + + // TODO: verify '.yml' (in case we moved from '.bin') + QString modelFilename = QString("MODELS/%1").arg(model.filename); + QByteArray modelData; + writeModelToYaml(model, modelData); + if (!writeFile(modelData, modelFilename)) { + return false; + } + + modelFiles.push_back({ std::string(model.filename), model.category }); + } + + // TODO: sort 'modelFiles' by category index + QByteArray modelslistBuffer; + if (!writeModelsListToYaml(radioData.categories, modelFiles, modelslistBuffer) + || writeFile(modelslistBuffer, "MODELS/models.yml")) { + return false; + } + + return true; }