From c5d686a6f0b31090d7759711110035506a1a761f Mon Sep 17 00:00:00 2001 From: Raphael Coeffic Date: Wed, 1 Dec 2021 10:14:01 +0100 Subject: [PATCH] WiP: write GeneralSettings to YAML --- companion/src/firmwares/CMakeLists.txt | 1 + .../src/firmwares/edgetx/edgetxinterface.cpp | 13 ++- .../src/firmwares/edgetx/edgetxinterface.h | 4 +- .../firmwares/edgetx/yaml_generalsettings.h | 109 +++++++++++++++++- companion/src/firmwares/edgetx/yaml_ops.cpp | 19 ++- companion/src/firmwares/edgetx/yaml_ops.h | 39 +++++-- .../src/firmwares/edgetx/yaml_trainerdata.cpp | 73 ++++++++++++ .../src/firmwares/edgetx/yaml_trainerdata.h | 60 +++------- companion/src/storage/categorized.cpp | 15 +-- 9 files changed, 261 insertions(+), 72 deletions(-) create mode 100644 companion/src/firmwares/edgetx/yaml_trainerdata.cpp diff --git a/companion/src/firmwares/CMakeLists.txt b/companion/src/firmwares/CMakeLists.txt index 9768c01f4..4d149548f 100644 --- a/companion/src/firmwares/CMakeLists.txt +++ b/companion/src/firmwares/CMakeLists.txt @@ -33,6 +33,7 @@ set(firmwares_SRCS edgetx/yaml_ops.cpp edgetx/yaml_generalsettings.cpp edgetx/yaml_calibdata.cpp + edgetx/yaml_trainerdata.cpp edgetx/yaml_switchconfig.cpp edgetx/yaml_modeldata.cpp edgetx/yaml_rawswitch.cpp diff --git a/companion/src/firmwares/edgetx/edgetxinterface.cpp b/companion/src/firmwares/edgetx/edgetxinterface.cpp index ddab0fc0d..3ee882abe 100644 --- a/companion/src/firmwares/edgetx/edgetxinterface.cpp +++ b/companion/src/firmwares/edgetx/edgetxinterface.cpp @@ -31,6 +31,14 @@ static YAML::Node loadYamlFromByteArray(const QByteArray& data) return YAML::Load(data_istream); } +static void writeYamlToByteArray(const YAML::Node& node, QByteArray& data) +{ + // TODO: use real streaming to avoid memory copies + std::stringstream data_ostream; + data_ostream << node; + data = QByteArray::fromStdString(data_ostream.str()); +} + bool loadModelsListFromYaml(std::vector categories, EtxModelfiles& modelFiles, const QByteArray& data) @@ -98,5 +106,8 @@ bool writeModelToYaml(const ModelData& model, QByteArray& data) bool writeRadioSettingsToYaml(const GeneralSettings& settings, QByteArray& data) { - return false; + YAML::Node node; + node = settings; + writeYamlToByteArray(node, data); + return true; } diff --git a/companion/src/firmwares/edgetx/edgetxinterface.h b/companion/src/firmwares/edgetx/edgetxinterface.h index 1a87cb181..641f080ee 100644 --- a/companion/src/firmwares/edgetx/edgetxinterface.h +++ b/companion/src/firmwares/edgetx/edgetxinterface.h @@ -37,5 +37,5 @@ bool loadModelsListFromYaml(std::vector categories, bool loadModelFromYaml(ModelData& model, const QByteArray& data); bool loadRadioSettingsFromYaml(GeneralSettings& settings, const QByteArray& data); -bool writeModelToByteArray(const ModelData& model, QByteArray& data); -bool writeRadioSettingsToByteArray(const GeneralSettings& settings, QByteArray& data); +bool writeModelToYaml(const ModelData& model, QByteArray& data); +bool writeRadioSettingsToYaml(const GeneralSettings& settings, QByteArray& data); diff --git a/companion/src/firmwares/edgetx/yaml_generalsettings.h b/companion/src/firmwares/edgetx/yaml_generalsettings.h index 47307816b..b7c95b263 100644 --- a/companion/src/firmwares/edgetx/yaml_generalsettings.h +++ b/companion/src/firmwares/edgetx/yaml_generalsettings.h @@ -39,11 +39,109 @@ namespace YAML { template<> struct convert { - // static YAML::Node encode(const GeneralSettings& rhs) { - // Node node; - // // TODO: convert struct into Node - // return node; - // } + static YAML::Node encode(const GeneralSettings& rhs) { + Node node; + + node["version"] = rhs.version; + + // Radio calib + // YamlCalibData calib; + // node["calib"] = calib; + // calib.copy(rhs.calibMid, rhs.calibSpanNeg, rhs.calibSpanPos); + + node["currModel"] = rhs.currModelIndex; + node["currModelFilename"] = rhs.currModelFilename; + node["contrast"] = rhs.contrast; + node["vBatWarn"] = rhs.vBatWarn; + node["txVoltageCalibration"] = rhs.txVoltageCalibration; + + node["vBatMin"] = rhs.vBatMin + 90; + node["vBatMax"] = rhs.vBatMax + 120; + + node["backlightMode"] = backlightModeLut << rhs.backlightMode; + node["trainer"] = rhs.trainer; + node["view"] = rhs.view; + node["fai"] = rhs.fai; + node["disableMemoryWarning"] = rhs.disableMemoryWarning; + node["beepMode"] = rhs.beeperMode; + node["disableAlarmWarning"] = rhs.disableAlarmWarning; + node["disableRssiPoweroffAlarm"] = rhs.disableRssiPoweroffAlarm; + node["USBMode"] = rhs.usbMode; + node["jackMode"] = rhs.jackMode; + node["hapticMode"] = rhs.hapticMode; + node["stickMode"] = rhs.stickMode; + node["timezone"] = rhs.timezone; + node["adjustRTC"] = rhs.adjustRTC; + node["inactivityTimer"] = rhs.inactivityTimer; + node["telemetryBaudrate"] = rhs.telemetryBaudrate; // TODO: conversion??? + node["splashMode"] = rhs.splashMode; // TODO: B&W only + node["templateSetup"] = rhs.templateSetup; + node["hapticLength"] = rhs.hapticLength + 2; + node["speakerPitch"] = rhs.speakerPitch * 15; + node["hapticStrength"] = rhs.hapticStrength + 2; + node["beepLength"] = rhs.beeperLength + 2; + node["gpsFormat"] = rhs.gpsFormat; + node["speakerVolume"] = rhs.speakerVolume + 12 ; + node["backlightBright"] = rhs.backlightBright; + node["switchesDelay"] = rhs.switchesDelay; + node["globalTimer"] = rhs.globalTimer; + node["bluetoothName"] = rhs.bluetoothName; + node["bluetoothBaudrate"] = rhs.bluetoothBaudrate; + node["bluetoothMode"] = bluetoothModeLut << rhs.bluetoothMode; + node["countryCode"] = rhs.countryCode; + node["jitterFilter"] = rhs.jitterFilter; + node["disableRtcWarning"] = rhs.rtcCheckDisable; // TODO: verify + node["keysBacklight"] = rhs.keysBacklight; + node["imperial"] = rhs.imperial; + node["ttsLanguage"] = rhs.ttsLanguage; + node["beepVolume"] = rhs.beepVolume + 2; + node["wavVolume"] = rhs.wavVolume + 2; + node["varioVolume"] = rhs.varioVolume + 2; + node["varioPitch"] = rhs.varioPitch * 10; + node["varioRange"] = rhs.varioRange * 15; + node["varioRepeat"] = rhs.varioRepeat; + node["backgroundVolume"] = rhs.backgroundVolume + 2; + node["auxSerialMode"] = uartModeLut << rhs.auxSerialMode; + node["aux2SerialMode"] = uartModeLut << rhs.aux2SerialMode; + node["antennaMode"] = antennaModeLut << rhs.antennaMode; + node["backlightColor"] = rhs.backlightColor; + + // if (node["customFn"]) { + // const YAML::Node& cfn = node["customFn"]; + // for (int i = 0; i < CPN_MAX_SPECIAL_FUNCTIONS; i++) { + // cfn[i] = rhs.customFn[i]; + // } + // } + + // YamlStickConfig stickConfig; + // node["sticksConfig"] = stickConfig; + + // YamlSwitchConfig switchConfig; + // node["switchConfig"] = switchConfig; + // switchConfig.copy(rhs.switchName, rhs.switchConfig); + + // YamlPotConfig potsConfig; + // node["potsConfig"] = potsConfig; + // potsConfig.copy(rhs.potName, rhs.potConfig); + + // YamlSliderConfig slidersConfig; + // node["slidersConfig"] = slidersConfig; + // slidersConfig.copy(rhs.sliderName, rhs.sliderConfig); + + // Color lcd theme settings are not used in EdgeTx + // RadioTheme::ThemeData themeData; + + node["ownerRegistrationID"] = rhs.registrationId; + + // Gyro (for now only xlites) + node["gyroMax"] = rhs.gyroMax; + node["gyroOffset"] = rhs.gyroOffset; + + // OneBit sampling (X9D only?) + node["uartSampleMode"] = rhs.uartSampleMode; + + return node; + } static bool decode(const Node& node, GeneralSettings& rhs) { @@ -138,6 +236,7 @@ namespace YAML { YamlStickConfig stickConfig; node["sticksConfig"] >> stickConfig; + stickConfig.copy(rhs.stickName); YamlSwitchConfig switchConfig; node["switchConfig"] >> switchConfig; diff --git a/companion/src/firmwares/edgetx/yaml_ops.cpp b/companion/src/firmwares/edgetx/yaml_ops.cpp index bde2129b2..4cb877175 100644 --- a/companion/src/firmwares/edgetx/yaml_ops.cpp +++ b/companion/src/firmwares/edgetx/yaml_ops.cpp @@ -19,7 +19,6 @@ */ #include "yaml_ops.h" -#include YAML::Node operator >> (const YAML::Node& node, const YamlLookupTable& lut) { @@ -54,3 +53,21 @@ void operator >> (const YAML::Node& node, bool& value) value = node.as(); } } + +namespace YAML { + +Node operator << (const YamlLookupTable& lut, const int& value) +{ + const auto& it = + find_if(lut.begin(), lut.end(), [=](const YamlLookupTableElmt& elmt) { + if (elmt.first == value) return true; + return false; + }); + + if (it != lut.end()) { + return Node(it->second); + } + return Node(); +} + +} diff --git a/companion/src/firmwares/edgetx/yaml_ops.h b/companion/src/firmwares/edgetx/yaml_ops.h index af79fba0c..cbd323c0a 100644 --- a/companion/src/firmwares/edgetx/yaml_ops.h +++ b/companion/src/firmwares/edgetx/yaml_ops.h @@ -21,6 +21,7 @@ #pragma once #include +#include #include typedef std::pair YamlLookupTableElmt; @@ -59,7 +60,6 @@ private: T factor; }; - YAML::Node operator >> (const YAML::Node& node, const YamlLookupTable& lut); void operator >> (const YAML::Node& node, const ioffset_int& value); @@ -111,17 +111,40 @@ void operator>>(const YAML::Node& node, T (&value)[N]) //return true; } +namespace YAML { + +Node operator << (const YamlLookupTable& lut, const int& value); + +template +struct convert_enum +{ + static YAML::Node encode(const T& rhs) + { + return lut << rhs; + } + static bool decode(const YAML::Node& node, T& rhs) + { + if (node) { + YAML::Node conv = node >> lut; + if (conv.IsScalar()) { + rhs = (T)conv.as(); + } + } + return true; + } +}; + +} + #define ENUM_CONVERTER(enum_type, lut) \ template <> \ struct convert { \ + static YAML::Node encode(const enum_type& rhs) \ + { \ + return convert_enum::encode(rhs); \ + } \ static bool decode(const YAML::Node& node, enum_type& rhs) \ { \ - if (node) { \ - YAML::Node conv = node >> lut; \ - if (conv.IsScalar()) { \ - rhs = (enum_type)conv.as(); \ - } \ - } \ - return true; \ + return convert_enum::decode(node, rhs); \ } \ } diff --git a/companion/src/firmwares/edgetx/yaml_trainerdata.cpp b/companion/src/firmwares/edgetx/yaml_trainerdata.cpp new file mode 100644 index 000000000..702628526 --- /dev/null +++ b/companion/src/firmwares/edgetx/yaml_trainerdata.cpp @@ -0,0 +1,73 @@ +/* + * 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_trainerdata.h" +#include "generalsettings.h" + +const YamlLookupTable trainerMixMode = { + {TrainerMix::TRN_MIX_MODE_OFF, "OFF"}, + {TrainerMix::TRN_MIX_MODE_ADD, "ADD"}, + {TrainerMix::TRN_MIX_MODE_SUBST, "REPL"}, +}; + +namespace YAML +{ + +Node convert::encode(const TrainerMix& rhs) +{ + Node node; + // TODO: convert struct into Node + return node; +} + +bool convert::decode(const Node& node, TrainerMix& rhs) +{ + node["srcChn"] >> rhs.src; + // node["mode"] >> rhs.mode; // TODO: string mapping + node["studWeight"] >> rhs.weight; + return true; +} + +Node convert::encode(const TrainerData& rhs) +{ + Node node; + // TODO: convert struct into Node + return node; +} + +bool convert::decode(const Node& node, TrainerData& rhs) +{ + if (node["calib"]) { + const Node& calib = node["calib"]; + for (int i = 0; i < 4; i++) { + calib[i] >> rhs.calib[i]; + } + } + + if (node["mix"]) { + const Node& mix = node["mix"]; + for (int i = 0; i < 4; i++) { + mix[i] >> rhs.mix[i]; + } + } + return true; +} + +} // namespace YAML diff --git a/companion/src/firmwares/edgetx/yaml_trainerdata.h b/companion/src/firmwares/edgetx/yaml_trainerdata.h index 766c0930b..7bbcac2cd 100644 --- a/companion/src/firmwares/edgetx/yaml_trainerdata.h +++ b/companion/src/firmwares/edgetx/yaml_trainerdata.h @@ -21,51 +21,19 @@ #include "yaml_ops.h" #include "generalsettings.h" -namespace YAML { +extern const YamlLookupTable trainerMixMode; - template<> - struct convert { +namespace YAML +{ +template <> +struct convert { + static Node encode(const TrainerMix& rhs); + static bool decode(const Node& node, TrainerMix& rhs); +}; - // static YAML::Node encode(const TrainerMix& rhs) { - // Node node; - // // TODO: convert struct into Node - // return node; - // } - - static bool decode(const YAML::Node& node, TrainerMix& rhs) - { - node["srcChn"] >> rhs.src; - //node["mode"] >> rhs.mode; // TODO: string mapping - node["studWeight"] >> rhs.weight; - return true; - } - }; - - template<> - struct convert { - - // static YAML::Node encode(const TrainerData& rhs) { - // Node node; - // // TODO: convert struct into Node - // return node; - // } - - static bool decode(const YAML::Node& node, TrainerData& rhs) - { - if (node["calib"]) { - const YAML::Node& calib = node["calib"]; - for (int i = 0; i < 4; i++) { - calib[i] >> rhs.calib[i]; - } - } - - if (node["mix"]) { - const YAML::Node& mix = node["mix"]; - for (int i = 0; i < 4; i++) { - mix[i] >> rhs.mix[i]; - } - } - return true; - } - }; -} +template <> +struct convert { + static Node encode(const TrainerData& rhs); + static bool decode(const Node& node, TrainerData& rhs); +}; +} // namespace YAML diff --git a/companion/src/storage/categorized.cpp b/companion/src/storage/categorized.cpp index 24f0c9979..f09253280 100644 --- a/companion/src/storage/categorized.cpp +++ b/companion/src/storage/categorized.cpp @@ -220,13 +220,6 @@ bool CategorizedStorageFormat::loadYaml(RadioData & radioData) qDebug() << tr("Found %1").arg(filename); } - // setError(tr("Error: Yaml format ignored - under development")); - // return false; // force failure until fully developed - - /* - This code a copy of loadBin with yaml file extensions ONLY - */ - QByteArray radioSettingsBuffer; if (!loadFile(radioSettingsBuffer, "RADIO/radio.yml")) { setError(tr("Can't extract RADIO/radio.yml")); @@ -291,6 +284,10 @@ bool CategorizedStorageFormat::loadYaml(RadioData & radioData) bool CategorizedStorageFormat::writeYaml(const RadioData & radioData) { - setError("Error: Yaml format ignored - under development"); - return false; // force failure until fully developed + QByteArray radioSettingsBuffer; + if (!writeRadioSettingsToYaml(radioData.generalSettings, radioSettingsBuffer)) { + return false; + } + + return writeFile(radioSettingsBuffer, "RADIO/radio.yml"); }