diff --git a/.gitmodules b/.gitmodules index 1da1a8370..ec08cff60 100644 --- a/.gitmodules +++ b/.gitmodules @@ -5,3 +5,6 @@ [submodule "radio/src/thirdparty/AccessDenied"] path = radio/src/thirdparty/AccessDenied url = https://github.com/raphaelcoeffic/AccessDenied.git +[submodule "companion/src/thirdparty/yaml-cpp"] + path = companion/src/thirdparty/yaml-cpp + url = https://github.com/jbeder/yaml-cpp.git diff --git a/companion/src/CMakeLists.txt b/companion/src/CMakeLists.txt index 9c98e519d..35bfd2968 100644 --- a/companion/src/CMakeLists.txt +++ b/companion/src/CMakeLists.txt @@ -198,6 +198,12 @@ add_subdirectory(storage) add_subdirectory(thirdparty/qcustomplot) add_subdirectory(thirdparty/maxlibqt/src/widgets) +set(YAML_CPP_BUILD_TESTS OFF CACHE BOOL "Enable testing" FORCE) +set(YAML_CPP_BUILD_TOOLS OFF CACHE BOOL "Enable parse tools" FORCE) +set(YAML_CPP_BUILD_CONTRIB OFF CACHE BOOL "Enable contrib stuff in library" FORCE) +set(YAML_CPP_INSTALL OFF CACHE BOOL "Enable generation of install target" FORCE) +add_subdirectory(thirdparty/yaml-cpp) + ############# Companion ############### set(companion_SRCS @@ -313,7 +319,7 @@ add_subdirectory(tests) ############# Install #################### # Generate list of simulator plugins, used by all platforms -file(GLOB simulator_plugins "${CMAKE_BINARY_DIR}/*opentx-*simulator${CMAKE_SHARED_LIBRARY_SUFFIX}") +file(GLOB simulator_plugins "${CMAKE_BINARY_DIR}/*edgetx-*simulator${CMAKE_SHARED_LIBRARY_SUFFIX}") # the current flavour is not automatically added if build in the current cmake iteration, so always # add its library name to be sure @@ -349,7 +355,7 @@ if(POLICY CMP0026) endif() if(SIMU_TARGET) - get_property(current_plugin TARGET opentx-${FLAVOUR}-simulator PROPERTY LOCATION) + get_property(current_plugin TARGET edgetx-${FLAVOUR}-simulator PROPERTY LOCATION) list(APPEND simulator_plugins "${current_plugin}") endif() @@ -529,7 +535,7 @@ IF(APPLE) # technically a hack (that is already is in the Bundle library ...) install(CODE " include(BundleUtilities) - file(GLOB bundle_simulator_libs \"\${CMAKE_INSTALL_PREFIX}/${companion_res_dir}/libopentx-*${CMAKE_SHARED_LIBRARY_SUFFIX}\") + file(GLOB bundle_simulator_libs \"\${CMAKE_INSTALL_PREFIX}/${companion_res_dir}/libedgetx-*${CMAKE_SHARED_LIBRARY_SUFFIX}\") set(BU_CHMOD_BUNDLE_ITEMS on) fixup_bundle(\"${APPS}\" \"\${bundle_simulator_libs};${bundle_qt_libs};${bundle_tools_path}\" \"${QT_LIB_DIR}\") file(RENAME \"\${CMAKE_INSTALL_PREFIX}/${COMPANION_NAME}.app\" \"\${CMAKE_INSTALL_PREFIX}/${COMPANION_OSX_APP_BUNDLE_NAME}.app\") @@ -543,9 +549,9 @@ if(APPLE) set(CPACK_DMG_BACKGROUND_IMAGE ${COMPANION_SRC_DIRECTORY}/images/splash_dmg.png) set(CPACK_DMG_VOLUME_NAME "EdgeTX Companion") set(CPACK_DMG_DS_STORE ${PROJECT_SOURCE_DIR}/companion/targets/mac/DS_Store) - set(CPACK_PACKAGE_FILE_NAME "opentx-${CPACK_PACKAGE_NAME_LOWERCASE}-${VERSION}") + set(CPACK_PACKAGE_FILE_NAME "edgetx-${CPACK_PACKAGE_NAME_LOWERCASE}-${VERSION}") endif(APPLE) - + if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") get_filename_component(_qt_bin_dir "${QT_QMAKE_EXECUTABLE}" DIRECTORY) find_program(LINUXDEPLOY_EXECUTABLE linuxdeployqt HINTS "${_qt_bin_dir}") diff --git a/companion/src/apppreferencesdialog.cpp b/companion/src/apppreferencesdialog.cpp index 99f0bb90f..a89082cb2 100644 --- a/companion/src/apppreferencesdialog.cpp +++ b/companion/src/apppreferencesdialog.cpp @@ -28,6 +28,10 @@ #include "joystick.h" #include "joystickdialog.h" #endif +#include "moduledata.h" +#include "compounditemmodels.h" + +#include AppPreferencesDialog::AppPreferencesDialog(QWidget * parent) : QDialog(parent), @@ -97,6 +101,7 @@ void AppPreferencesDialog::accept() g.jsSupport(false); g.jsCtrl(0); } + profile.defaultInternalModule(ui->defaultInternalModuleCB->currentData().toInt()); profile.channelOrder(ui->channelorderCB->currentIndex()); profile.defaultMode(ui->stickmodeCB->currentIndex()); profile.renameFwFiles(ui->renameFirmware->isChecked()); @@ -256,6 +261,8 @@ void AppPreferencesDialog::initSettings() } #endif // Profile Tab Inits + ui->defaultInternalModuleCB->setModel(ModuleData::internalModuleItemModel()); + ui->defaultInternalModuleCB->setCurrentIndex(ui->defaultInternalModuleCB->findData(profile.defaultInternalModule())); ui->channelorderCB->setCurrentIndex(profile.channelOrder()); ui->stickmodeCB->setCurrentIndex(profile.defaultMode()); ui->renameFirmware->setChecked(profile.renameFwFiles()); @@ -453,6 +460,12 @@ void AppPreferencesDialog::on_clearImageButton_clicked() void AppPreferencesDialog::onBaseFirmwareChanged() { populateFirmwareOptions(getBaseFirmware()); + + Firmware *newfw = getFirmwareVariant(); + Profile & profile = g.currentProfile(); + profile.defaultInternalModule(Boards::getDefaultInternalModules(newfw->getBoard())); + ui->defaultInternalModuleCB->setModel(ModuleData::internalModuleItemModel(newfw->getBoard())); + ui->defaultInternalModuleCB->setCurrentIndex(ui->defaultInternalModuleCB->findData(profile.defaultInternalModule())); } Firmware *AppPreferencesDialog::getBaseFirmware() const diff --git a/companion/src/apppreferencesdialog.ui b/companion/src/apppreferencesdialog.ui index a3156efa3..888d6d1c6 100644 --- a/companion/src/apppreferencesdialog.ui +++ b/companion/src/apppreferencesdialog.ui @@ -51,178 +51,21 @@ Radio Profile - - - + + + - - 0 - 0 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 5 - - - 4 - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 6 - - - - - - 0 - 0 - - - - - 75 - true - - - - Splash Screen - - - - - - - true - - - true - - - - - - - Select Image - - - - - - - - 0 - 0 - - - - - 128 - 64 - - - - - 212 - 64 - - - - QFrame::StyledPanel - - - QFrame::Plain - - - 1 - - - - - - true - - - - - - - Clear Image - - - - - - - - 0 - 0 - - - - Qt::Horizontal - - - - - - - - - - + 0 0 - Offer to write FW to Tx after download + Default Stick Mode - - - - - 0 - 0 - - - - Qt::Horizontal - - - - + @@ -358,88 +201,27 @@ - - - - true + + + + If set it will override the application general setting + + + false - - - - - 0 - 0 - - - - Build Options - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - - - + + 0 0 - - Append version number to FW file name - - - - - Select Folder - - - - - - - - 0 - 0 - - - - - 75 - true - - - - Profile Name - - - - - - - - - - - 0 - 0 - - - - The profile specific folder, if set, will override general Backup folder - - - Backup folder - - - - + true @@ -455,39 +237,17 @@ - - - - - 0 - 0 - - - - - 75 - true - + + + + The profile specific folder, if set, will override general Backup folder - Other Settings + Select Folder - - - - - 0 - 0 - - - - Default Stick Mode - - - - + @@ -541,61 +301,61 @@ Mode 4: - - - - - 0 - 0 - + + + + true - Default Channel Order - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - if set, will override general backup enable - - - Enable automatic backup before writing firmware - - - - - - - - 0 - 0 - - - - Qt::Horizontal - - - - - - - If set it will override the application general setting + false + + + + + + + true + + + + + + + + 0 + 0 + + + + + 75 + true + + + + Profile Name + + + + + + + + 0 + 0 + + + + Append version number to FW file name + + + @@ -612,16 +372,6 @@ Mode 4: - - - - The profile specific folder, if set, will override general Backup folder - - - Select Folder - - - @@ -635,6 +385,136 @@ Mode 4: + + + + + 0 + 0 + + + + The profile specific folder, if set, will override general Backup folder + + + Backup folder + + + + + + + + 0 + 0 + + + + Default Channel Order + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + Default Int. Module + + + + + + + + 0 + 0 + + + + Qt::Horizontal + + + + + + + + 0 + 0 + + + + Offer to write FW to Tx after download + + + + + + + + 0 + 0 + + + + Build Options + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + + + + 0 + 0 + + + + Menu Language + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + Select Folder + + + + + + + Qt::Vertical + + + + 20 + 5 + + + + + + + + + 0 + 0 + + + + Qt::Horizontal + + + @@ -658,58 +538,188 @@ Mode 4: - - - - - 0 - 0 - - - - Menu Language - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - true - - - - - - false - - - - - - - Qt::Vertical - - - - 20 - 5 - - - - - - + + 0 0 + + if set, will override general backup enable + + + Enable automatic backup before writing firmware + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 6 + + + + + + 0 + 0 + + + + + 75 + true + + + + Splash Screen + + + + + + + true + + + true + + + + + + + Select Image + + + + + + + + 0 + 0 + + + + + 128 + 64 + + + + + 212 + 64 + + + + QFrame::StyledPanel + + + QFrame::Plain + + + 1 + + + + + + true + + + + + + + Clear Image + + + + + + + + 0 + 0 + + + + Qt::Horizontal + + + + + + + + + + + 0 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 5 + + + 4 + + + + + + + + + 0 + 0 + + + + + 75 + true + + + + Other Settings + + + + + + diff --git a/companion/src/companion.cpp b/companion/src/companion.cpp index 7a431b8f4..5059d93ff 100644 --- a/companion/src/companion.cpp +++ b/companion/src/companion.cpp @@ -69,28 +69,22 @@ void checkSettingsImport(bool force = false) if (!found && !force) return; - const QString impFileBtn = QCoreApplication::translate("Companion", "Import from File"); - const QString impPrevBtn = QCoreApplication::translate("Companion", "Import from v%1").arg(previousVersion); - const QString impNoneBtn = QCoreApplication::translate("Companion", "Do not import"); - QString msg; if (previousVersion.isEmpty()) { + const QString impFileBtn = QCoreApplication::translate("Companion", "Import from File"); + const QString impNoneBtn = QCoreApplication::translate("Companion", "Do not import"); + if (found) msg = QCoreApplication::translate("Companion", "We have found possible Companion settings backup file(s).\nDo you want to import settings from a file?"); else msg = QCoreApplication::translate("Companion", "Import settings from a file, or start with current values."); + + const int ret = QMessageBox::question(nullptr, CPN_STR_APP_NAME, msg, impNoneBtn, impFileBtn, 0, 0); + + if (!ret) + return; } else { - msg = QCoreApplication::translate("Companion", "We have found existing settings for Companion version: %1.\nDo you want to import them?\n\n" \ - "If you have a settings backup file, you may import that instead.").arg(previousVersion); - } - - const int ret = QMessageBox::question(nullptr, CPN_STR_APP_NAME, msg, impNoneBtn, impFileBtn, (previousVersion.isEmpty() ? QString() : impPrevBtn), 0, 0); - if (!ret) - return; - - // Import from previous version - if (ret == 2) { if (!g.importSettings(previousVersion)) { // very unlikely, but just in case of unexpected error, restart the import importError(); diff --git a/companion/src/constants.h b/companion/src/constants.h index b06792a91..53796f6fc 100644 --- a/companion/src/constants.h +++ b/companion/src/constants.h @@ -38,15 +38,17 @@ #define CPN_MAX_MODULES 2 #define CPN_MAX_STICKS Board::STICK_AXIS_COUNT #define CPN_MAX_TRIMS Board::TRIM_AXIS_COUNT -#define CPN_MAX_KNOBS 8 +#define CPN_MAX_POTS 8 #define CPN_MAX_SLIDERS 4 -#define CPN_MAX_POTS (CPN_MAX_KNOBS + CPN_MAX_SLIDERS) #define CPN_MAX_CYC 3 #define CPN_MAX_SWITCHES 32 #define CPN_MAX_FUNCTION_SWITCHES 6 #define CPN_MAX_MOUSE_ANALOGS 2 #define CPN_MAX_GYRO_ANALOGS 2 -#define CPN_MAX_ANALOGS (CPN_MAX_STICKS + CPN_MAX_POTS + CPN_MAX_MOUSE_ANALOGS + CPN_MAX_GYRO_ANALOGS) +#define CPN_MAX_ANALOGS (CPN_MAX_STICKS + CPN_MAX_POTS + CPN_MAX_SLIDERS + CPN_MAX_MOUSE_ANALOGS + CPN_MAX_GYRO_ANALOGS) +#define CPN_MAX_SENSORS 60 +#define CPN_MAX_SCRIPTS 9 +#define CPN_MAX_SCRIPT_INPUTS 10 #define CPN_STR_APP_NAME QCoreApplication::translate("Companion", "EdgeTX Companion") #define CPN_STR_TTL_INFO QCoreApplication::translate("Companion", "Information") // shared Title Case words, eg. for a window title or section heading @@ -60,8 +62,9 @@ #define DFU_FILES_FILTER "DFU " % CPN_STR_FILES % " (*.dfu);;" #define EEPE_FILES_FILTER "EEPE " % CPN_STR_FILES % " (*.eepe);;" #define OTX_FILES_FILTER "OpenTX " % CPN_STR_FILES % " (*.otx);;" -#define YML_FILES_FILTER "YAML " % CPN_STR_FILES % " (*.yml);;" -#define EEPROM_FILES_FILTER CPN_STR_RAD_MOD_SETTINGS % " " % CPN_STR_FILES % " (*.otx *.yml *.eepe *.bin *.hex);;" % OTX_FILES_FILTER % YML_FILES_FILTER % EEPE_FILES_FILTER % BIN_FILES_FILTER % HEX_FILES_FILTER +#define ETX_FILES_FILTER "EdgeTX " % CPN_STR_FILES % " (*.etx);;" +#define YML_FILES_FILTER "EdgeTX YAML " % CPN_STR_FILES % " (*.yml);;" +#define EEPROM_FILES_FILTER CPN_STR_RAD_MOD_SETTINGS % " " % CPN_STR_FILES % " (*.etx *.yml *.otx *.eepe *.bin *.hex);;" % ETX_FILES_FILTER % YML_FILES_FILTER % OTX_FILES_FILTER % EEPE_FILES_FILTER % BIN_FILES_FILTER % HEX_FILES_FILTER #define FLASH_FILES_FILTER "FLASH " % CPN_STR_FILES % " (*.bin *.hex *.dfu);;" % BIN_FILES_FILTER % HEX_FILES_FILTER % DFU_FILES_FILTER #define EXTERNAL_EEPROM_FILES_FILTER "EEPROM " % CPN_STR_FILES % " (*.bin *.hex);;" % BIN_FILES_FILTER % HEX_FILES_FILTER #define ER9X_EEPROM_FILE_TYPE "ER9X_EEPROM_FILE" diff --git a/companion/src/datamodels/compounditemmodels.cpp b/companion/src/datamodels/compounditemmodels.cpp index f4a135ee7..7ee049d1f 100644 --- a/companion/src/datamodels/compounditemmodels.cpp +++ b/companion/src/datamodels/compounditemmodels.cpp @@ -118,7 +118,7 @@ RawSourceItemModel::RawSourceItemModel(const GeneralSettings * const generalSett addItems(SOURCE_TYPE_CYC, RawSource::SourcesGroup, CPN_MAX_CYC); addItems(SOURCE_TYPE_PPM, RawSource::SourcesGroup, firmware->getCapability(TrainerInputs)); addItems(SOURCE_TYPE_CH, RawSource::SourcesGroup, firmware->getCapability(Outputs)); - addItems(SOURCE_TYPE_SPECIAL, RawSource::TelemGroup, 5); + addItems(SOURCE_TYPE_SPECIAL, RawSource::TelemGroup, SOURCE_TYPE_SPECIAL_COUNT); addItems(SOURCE_TYPE_TELEMETRY, RawSource::TelemGroup, firmware->getCapability(Sensors) * 3); addItems(SOURCE_TYPE_GVAR, RawSource::GVarsGroup, firmware->getCapability(Gvars)); } diff --git a/companion/src/firmwares/CMakeLists.txt b/companion/src/firmwares/CMakeLists.txt index 9a8593b99..870d14cde 100644 --- a/companion/src/firmwares/CMakeLists.txt +++ b/companion/src/firmwares/CMakeLists.txt @@ -29,6 +29,23 @@ set(firmwares_SRCS ersky9x/ersky9xinterface.cpp opentx/opentxeeprom.cpp opentx/opentxinterface.cpp + edgetx/edgetxinterface.cpp + 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 + edgetx/yaml_rawsource.cpp + edgetx/yaml_mixdata.cpp + edgetx/yaml_expodata.cpp + edgetx/yaml_curvedata.cpp + edgetx/yaml_moduledata.cpp + edgetx/yaml_logicalswitchdata.cpp + edgetx/yaml_customfunctiondata.cpp + edgetx/yaml_sensordata.cpp + edgetx/yaml_screendata.cpp datahelpers.cpp customisation_data.cpp ) @@ -48,14 +65,19 @@ set(firmwares_QT qt5_wrap_cpp(firmwares_SRCS ${firmwares_QT}) add_library(firmwares ${firmwares_SRCS} ${firmwares_HDRS}) + target_link_libraries(firmwares ${CPN_COMMON_LIB} datamodels Qt5::Core Qt5::Xml Qt5::Widgets) +target_link_libraries(firmwares yaml-cpp) + target_include_directories(firmwares PRIVATE ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} + ${COMPANION_SRC_DIRECTORY}/thirdparty/yaml-cpp/include PUBLIC "${CMAKE_CURRENT_LIST_DIR}" "${CMAKE_CURRENT_LIST_DIR}/er9x" "${CMAKE_CURRENT_LIST_DIR}/ersky9x" "${CMAKE_CURRENT_LIST_DIR}/opentx" + "${CMAKE_CURRENT_LIST_DIR}/edgetx" ) diff --git a/companion/src/firmwares/boards.cpp b/companion/src/firmwares/boards.cpp index af164355c..cf508533b 100644 --- a/companion/src/firmwares/boards.cpp +++ b/companion/src/firmwares/boards.cpp @@ -21,6 +21,7 @@ #include "boards.h" #include "macros.h" #include "compounditemmodels.h" +#include "moduledata.h" // TODO remove all those constants // Update: These are now all only used within this class. @@ -374,7 +375,7 @@ int Boards::getCapability(Board::Type board, Board::Capability capability) else if (IS_TARANIS_X9E(board)) return 4; else if (IS_HORUS_X10(board) || IS_FAMILY_T16(board)) - return 5; + return 7; else if (IS_HORUS_X12S(board)) return 3; else if (IS_FLYSKY_NV14(board)) @@ -486,6 +487,12 @@ int Boards::getCapability(Board::Type board, Board::Capability capability) case NumFunctionSwitches: return IS_JUMPER_TPRO(board) ? 6 : 0; + case HasSDCard: + return IS_STM32(board); + + case HasInternalModuleSupport: + return (IS_STM32(board) && !IS_TARANIS_X9(board)); + default: return 0; } @@ -507,104 +514,82 @@ QString Boards::getAxisName(int index) return CPN_STR_UNKNOWN_ITEM; } -QString Boards::getAnalogInputName(Board::Type board, int index) +StringTagMappingTable Boards::getAnalogNamesLookupTable(Board::Type board) { - if (index < 0) - return CPN_STR_UNKNOWN_ITEM; + StringTagMappingTable tbl; - if (index < getBoardCapability(board, Board::Sticks)) { - const QString sticks[] = { - tr("Rud"), - tr("Ele"), - tr("Thr"), - tr("Ail") - }; - return sticks[index]; + if (getBoardCapability(board, Board::Sticks)) { + tbl.insert(tbl.end(), {"Rud", "Ele", "Thr", "Ail"}); } - index -= getCapability(board, Board::Sticks); - if (IS_SKY9X(board)) { - const QString pots[] = { - "P1", - "P2", - "P3" - }; - if (index < DIM(pots)) - return pots[index]; - } - else if (IS_TARANIS_X9E(board)) { - const QString pots[] = { - "F1", - "F2", - "F3", - "F4", - "S1", - "S2", - "LS", - "RS" - }; - if (index < DIM(pots)) - return pots[index]; - } - else if (IS_TARANIS_XLITE(board)) { - const QString pots[] = { - "S1", - "S2", - "GyrX", - "GyrY" - }; - if (index < DIM(pots)) - return pots[index]; - } - else if (IS_TARANIS(board)) { - const QString pots[] = { - "S1", - "S2", - "S3", - "LS", - "RS" - }; - if (index < DIM(pots)) - return pots[index]; - } - else if (IS_HORUS_X12S(board)) { - const QString pots[] = { - "S1", - "6P", - "S2", - "L1", - "L2", - "LS", - "RS", - "JSx", - "JSy" - }; - if (index < DIM(pots)) - return pots[index]; - } - else if (IS_FLYSKY_NV14(board)) { - const QString pots[] = { - "VRA", - "VRB", - }; - if (index < DIM(pots)) - return pots[index]; - } - else if (IS_HORUS_X10(board) || IS_FAMILY_T16(board)) { - const QString pots[] = { - "S1", - "6P", - "S2", - "EX1", - "EX2", - "LS", - "RS" - }; - if (index < DIM(pots)) - return pots[index]; + tbl.insert(tbl.end(), {"P1", "P2", "P3"}); + } else if (IS_TARANIS_X9E(board)) { + tbl.insert(tbl.end(), { + {"F1", "POT1"}, + {"F2", "POT2"}, + {"F3", "POT3"}, + {"F4", "POT4"}, + {"S1", "SLIDER1"}, + {"S2", "SLIDER2"}, + {"LS", "SLIDER3"}, + {"RS", "SLIDER4"}, + }); + } else if (IS_TARANIS_XLITE(board)) { + tbl.insert(tbl.end(), { + {"S1", "POT1"}, + {"S2", "POT2"}, + {"GyrX", "GYRO1"}, + {"GyrY", "GYRO2"}, + }); + } else if (IS_TARANIS(board)) { + tbl.insert(tbl.end(), { + {"S1", "POT1"}, + {"S2", "POT2"}, + {"S3", "POT3"}, + {"LS", "SLIDER1"}, + {"RS", "SLIDER2"}, + }); + } else if (IS_HORUS_X12S(board)) { + tbl.insert(tbl.end(), { + {"S1", "S1"}, + {"6P", "6POS"}, + {"S2", "S2"}, + {"L1", "S3"}, + {"L2", "S4"}, + {"LS", "LS"}, + {"RS", "RS"}, + {"JSx", "MOUSE1"}, + {"JSy", "MOUSE2"}, + }); + } else if (IS_FLYSKY_NV14(board)) { + tbl.insert(tbl.end(), { + {"VRA", "POT1"}, + {"VRB", "POT2"}, + }); + } else if (IS_HORUS_X10(board) || IS_FAMILY_T16(board)) { + tbl.insert(tbl.end(), { + {"S1", "S1"}, + {"6P", "6POS"}, + {"S2", "S2"}, + {"EX1", "EXT1"}, + {"EX2", "EXT2"}, + {"EX3", "EXT3"}, + {"EX4", "EXT4"}, + {"LS", "LS"}, + {"RS", "RS"}, + }); } + return tbl; +} + +QString Boards::getAnalogInputName(Board::Type board, int index) +{ + const StringTagMappingTable& lut = getAnalogNamesLookupTable(board); + if (index < (int)lut.size()) + return QString::fromStdString(lut[index].name); + return CPN_STR_UNKNOWN_ITEM; } @@ -762,3 +747,126 @@ AbstractStaticItemModel * Boards::switchTypeItemModel() mdl->loadItemList(); return mdl; } + +// static +StringTagMappingTable Boards::getSwitchesLookupTable(Board::Type board) +{ + StringTagMappingTable tbl; + + for (int i = 0; i < Boards::getCapability(board, Board::Switches); i++) { + SwitchInfo si = Boards::getSwitchInfo(board, i); + if (si.config != SWITCH_NOT_AVAILABLE) // safety check in case Switches does not align + tbl.insert(tbl.end(), si.name.toStdString()); + } + + return tbl; +} + +// static +StringTagMappingTable Boards::getTrimSwitchesLookupTable(Board::Type board) +{ + StringTagMappingTable tbl; + + tbl.insert(tbl.end(), { + {std::to_string(TRIM_SW_LH_DEC), "TrimRudLeft"}, + {std::to_string(TRIM_SW_LH_INC), "TrimRudRight"}, + {std::to_string(TRIM_SW_LV_DEC), "TrimEleDown"}, + {std::to_string(TRIM_SW_LV_INC), "TrimEleUp"}, + {std::to_string(TRIM_SW_RV_DEC), "TrimThrDown"}, + {std::to_string(TRIM_SW_RV_INC), "TrimThrUp"}, + {std::to_string(TRIM_SW_RH_DEC), "TrimAilLeft"}, + {std::to_string(TRIM_SW_RH_INC), "TrimAilRight"}, + }); + + if (getCapability(board, Board::NumTrims) > 4) + tbl.insert(tbl.end(), { + {std::to_string(TRIM_SW_T5_DEC), "TrimT5Down"}, + {std::to_string(TRIM_SW_T5_INC), "TrimT5Up"}, + {std::to_string(TRIM_SW_T6_DEC), "TrimT6Down"}, + {std::to_string(TRIM_SW_T6_INC), "TrimT6Up"}, + }); + + return tbl; +} + +// static +StringTagMappingTable Boards::getTrimSourcesLookupTable(Board::Type board) +{ + StringTagMappingTable tbl; + + tbl.insert(tbl.end(), { + {std::to_string(TRIM_AXIS_LH), "TrimRud"}, + {std::to_string(TRIM_AXIS_LV), "TrimEle"}, + {std::to_string(TRIM_AXIS_RV), "TrimThr"}, + {std::to_string(TRIM_AXIS_RH), "TrimAil"}, + }); + + if (getCapability(board, Board::NumTrims) > 4) + tbl.insert(tbl.end(), { + {std::to_string(TRIM_AXIS_T5), "TrimT5"}, + {std::to_string(TRIM_AXIS_T6), "TrimT6"}, + }); + + return tbl; +} + +QList Boards::getSupportedInternalModules(Board::Type board) +{ + QList modules; + if (IS_TARANIS_X9DP_2019(board) || IS_TARANIS_X7_ACCESS(board)) { + modules = {MODULE_TYPE_ISRM_PXX2}; + } else if (IS_FLYSKY_NV14(board)) { + modules = {MODULE_TYPE_FLYSKY}; + } else if (IS_FAMILY_HORUS_OR_T16(board) || IS_FAMILY_T12(board) + || (IS_TARANIS_SMALL(board) && IS_ACCESS_RADIO(board))) { + modules.append({ + MODULE_TYPE_XJT_PXX1, + MODULE_TYPE_ISRM_PXX2, + MODULE_TYPE_CROSSFIRE, + MODULE_TYPE_MULTIMODULE, + }); + } else if (IS_TARANIS(board)) { + modules = {MODULE_TYPE_XJT_PXX1}; + } + + return modules; +} + +ModuleType Boards::getDefaultInternalModules(Board::Type board) +{ + switch(board) { + case BOARD_TARANIS_X7: + case BOARD_TARANIS_X9D: + case BOARD_TARANIS_X9DP: + case BOARD_TARANIS_X9E: + case BOARD_HORUS_X12S: + case BOARD_X10: + case BOARD_TARANIS_XLITE: + return MODULE_TYPE_XJT_PXX1; + + case BOARD_TARANIS_X7_ACCESS: + case BOARD_TARANIS_X9DP_2019: + case BOARD_X10_EXPRESS: + case BOARD_TARANIS_XLITES: + case BOARD_TARANIS_X9LITE: + case BOARD_TARANIS_X9LITES: + return MODULE_TYPE_ISRM_PXX2; + + case BOARD_JUMPER_T12: + case BOARD_JUMPER_T16: + case BOARD_RADIOMASTER_TX16S: + case BOARD_JUMPER_T18: + case BOARD_RADIOMASTER_TX12: + case BOARD_RADIOMASTER_T8: + case BOARD_JUMPER_TLITE: + case BOARD_RADIOMASTER_ZORRO: + case BOARD_JUMPER_TPRO: + return MODULE_TYPE_MULTIMODULE; + + case BOARD_FLYSKY_NV14: + return MODULE_TYPE_FLYSKY; + + default: + return MODULE_TYPE_NONE; + } +} diff --git a/companion/src/firmwares/boards.h b/companion/src/firmwares/boards.h index ea0476bda..07b8b572a 100644 --- a/companion/src/firmwares/boards.h +++ b/companion/src/firmwares/boards.h @@ -19,6 +19,8 @@ */ #pragma once +#include "datahelpers.h" +#include "moduledata.h" #include #include @@ -145,7 +147,9 @@ namespace Board { NumTrimSwitches, HasRTC, HasColorLcd, - NumFunctionSwitches + NumFunctionSwitches, + HasSDCard, + HasInternalModuleSupport }; struct SwitchInfo @@ -199,18 +203,26 @@ class Boards static int getEEpromSize(Board::Type board); static int getFlashSize(Board::Type board); static Board::SwitchInfo getSwitchInfo(Board::Type board, int index); + static StringTagMappingTable getSwitchesLookupTable(Board::Type board); static int getCapability(Board::Type board, Board::Capability capability); static QString getAxisName(int index); + static StringTagMappingTable getAnalogNamesLookupTable(Board::Type board); static QString getAnalogInputName(Board::Type board, int index); static bool isBoardCompatible(Board::Type board1, Board::Type board2); static QString getBoardName(Board::Type board); static QString potTypeToString(int value); static QString sliderTypeToString(int value); static QString switchTypeToString(int value); + static QString intModuleTypeToString(int value); static AbstractStaticItemModel * potTypeItemModel(); static AbstractStaticItemModel * sliderTypeItemModel(); static AbstractStaticItemModel * switchTypeItemModel(); - + static AbstractStaticItemModel * intModuleTypeItemModel(); + static StringTagMappingTable getTrimSwitchesLookupTable(Board::Type board); + static StringTagMappingTable getTrimSourcesLookupTable(Board::Type board); + static QList getSupportedInternalModules(Board::Type board); + static ModuleType getDefaultInternalModules(Board::Type board); + protected: Board::Type m_boardType; @@ -282,7 +294,12 @@ inline bool IS_FAMILY_T16(Board::Type board) inline bool IS_FAMILY_T12(Board::Type board) { - return board == Board::BOARD_JUMPER_T12 || board == Board::BOARD_RADIOMASTER_TX12 || board == Board::BOARD_RADIOMASTER_ZORRO || board == Board::BOARD_RADIOMASTER_T8 || board == Board::BOARD_JUMPER_TLITE; + return board == Board::BOARD_JUMPER_T12 || + board == Board::BOARD_RADIOMASTER_TX12 || + board == Board::BOARD_RADIOMASTER_ZORRO || + board == Board::BOARD_RADIOMASTER_T8 || + board == Board::BOARD_JUMPER_TLITE || + board == Board::BOARD_JUMPER_TPRO; } inline bool IS_FLYSKY_NV14(Board::Type board) @@ -400,10 +417,17 @@ inline bool IS_TARANIS_X9DP_2019(Board::Type board) return (board == Board::BOARD_TARANIS_X9DP_2019); } +inline bool IS_ACCESS_RADIO(Board::Type board) +{ + return IS_TARANIS_XLITES(board) || IS_TARANIS_X9LITE(board) || + board == Board::BOARD_TARANIS_X9DP_2019 || + board == Board::BOARD_X10_EXPRESS || IS_TARANIS_X7_ACCESS(board); +} + inline bool IS_ACCESS_RADIO(Board::Type board, const QString & id) { - return (IS_TARANIS_XLITES(board) || IS_TARANIS_X9LITE(board) || board == Board::BOARD_TARANIS_X9DP_2019 || board == Board::BOARD_X10_EXPRESS || IS_TARANIS_X7_ACCESS(board) || - (IS_FAMILY_HORUS_OR_T16(board) && id.contains("internalaccess"))); + return IS_ACCESS_RADIO(board) || + (IS_FAMILY_HORUS_OR_T16(board) && id.contains("internalaccess")); } inline bool HAS_EEPROM_YAML(Board::Type board) diff --git a/companion/src/firmwares/curvedata.cpp b/companion/src/firmwares/curvedata.cpp index 3843fb77b..904863a3d 100644 --- a/companion/src/firmwares/curvedata.cpp +++ b/companion/src/firmwares/curvedata.cpp @@ -30,18 +30,6 @@ void CurveData::clear(int count) { memset(reinterpret_cast(this), 0, sizeof(CurveData)); this->count = count; - - int incr = 200 / (count - 1); - - // points[0].x must be -100 - for (int i = 0; i < count; i++) { - if (i < count - 1) - points[i].x = -100 + incr * i; - else - points[i].x = 100; // points[last].x must be +100 do not risk a rounding issue using incr - - points[i].y = points[i].x; - } } bool CurveData::isEmpty() const diff --git a/companion/src/firmwares/customfunctiondata.cpp b/companion/src/firmwares/customfunctiondata.cpp index f60f1c74a..293bdd6db 100644 --- a/companion/src/firmwares/customfunctiondata.cpp +++ b/companion/src/firmwares/customfunctiondata.cpp @@ -84,7 +84,7 @@ QString CustomFunctionData::funcToString(const AssignFunc func, const ModelData else if (func == FuncReset) return tr("Reset"); else if (func >= FuncSetTimer1 && func <= FuncSetTimerLast) - return tr("Set %1").arg(RawSource(SOURCE_TYPE_SPECIAL, SOURCE_TYPE_SPECIAL_TIMER1_IDX + func - FuncSetTimer1).toString(model)); + return tr("Set %1").arg(RawSource(SOURCE_TYPE_SPECIAL, SOURCE_TYPE_SPECIAL_FIRST_TIMER + func - FuncSetTimer1).toString(model)); else if (func == FuncVario) return tr("Vario"); else if (func == FuncPlayPrompt) @@ -249,7 +249,7 @@ QString CustomFunctionData::resetToString(const int value, const ModelData * mod if (value < step) { if (value < firmware->getCapability(Timers)) - return RawSource(SOURCE_TYPE_SPECIAL, value + SOURCE_TYPE_SPECIAL_TIMER1_IDX).toString(model); + return RawSource(SOURCE_TYPE_SPECIAL, value + SOURCE_TYPE_SPECIAL_FIRST_TIMER).toString(model); else return QString(CPN_STR_UNKNOWN_ITEM); } diff --git a/companion/src/firmwares/customisation_data.cpp b/companion/src/firmwares/customisation_data.cpp index 34489aa59..fb9e1fed3 100644 --- a/companion/src/firmwares/customisation_data.cpp +++ b/companion/src/firmwares/customisation_data.cpp @@ -27,6 +27,26 @@ #define WHITE RADIO_RGB(0xFF, 0xFF, 0xFF) #define RED RADIO_RGB(229, 32, 30) +ZoneOptionValue::ZoneOptionValue() +{ + memset((void*)this, 0, sizeof(ZoneOptionValue)); +} + +ZoneOptionValueTyped::ZoneOptionValueTyped() +{ + memset((void*)this, 0, sizeof(ZoneOptionValueTyped)); +} + +WidgetPersistentData::WidgetPersistentData() +{ + memset((void*)this, 0, sizeof(WidgetPersistentData)); +} + +ZonePersistentData::ZonePersistentData() +{ + memset((void*)this, 0, sizeof(ZonePersistentData)); +} + inline void setZoneOptionValue(ZoneOptionValue& zov, bool value) { zov.boolValue = value; @@ -61,9 +81,13 @@ inline ZoneOptionValueEnum zoneValueEnumFromType(ZoneOption::Type type) return ZOV_Bool; case ZoneOption::Color: + return ZOV_Color; + + case ZoneOption::Source: + return ZOV_Source; + case ZoneOption::Timer: case ZoneOption::Switch: - case ZoneOption::Source: case ZoneOption::TextSize: default: return ZOV_Unsigned; @@ -85,6 +109,28 @@ inline const char * zoneOptionValueEnumToString(ZoneOptionValueEnum zovenum) { } } +static const ZoneOptionValueTyped zero_widget_option = {}; + +bool ZoneOptionValueTyped::isEmpty() const +{ + return !memcmp((void*)this, &zero_widget_option, sizeof(zero_widget_option)); +} + +bool ZonePersistentData::isEmpty() const +{ + return strlen(widgetName) == 0; +} + +RadioLayout::CustomScreenData::CustomScreenData() +{ + memset((void*)this, 0, sizeof(RadioLayout::CustomScreenData)); +} + +bool RadioLayout::CustomScreenData::isEmpty() const +{ + return strlen(layoutId) == 0; +} + void RadioTheme::init(const char* themeName, ThemeData& themeData) { memset(&themeData, 0, sizeof(ThemeData)); diff --git a/companion/src/firmwares/customisation_data.h b/companion/src/firmwares/customisation_data.h index baad3c828..b2d5bf72d 100644 --- a/companion/src/firmwares/customisation_data.h +++ b/companion/src/firmwares/customisation_data.h @@ -20,6 +20,7 @@ #pragma once #include "constants.h" +#include "rawsource.h" #include @@ -58,6 +59,10 @@ struct ZoneOptionValue // union in radio/src/datastructs.h int signedValue; unsigned int boolValue; char stringValue[LEN_ZONE_OPTION_STRING + 1]; + RawSource sourceValue; + unsigned int colorValue; + + ZoneOptionValue(); }; enum ZoneOptionValueEnum { @@ -65,7 +70,9 @@ enum ZoneOptionValueEnum { ZOV_Signed, ZOV_Bool, ZOV_String, - ZOV_LAST = ZOV_String + ZOV_Source, + ZOV_Color, + ZOV_LAST = ZOV_Color }; struct ZoneOption @@ -93,21 +100,33 @@ struct ZoneOptionValueTyped { ZoneOptionValueEnum type; ZoneOptionValue value; + + ZoneOptionValueTyped(); + bool isEmpty() const; }; struct WidgetPersistentData { ZoneOptionValueTyped options[MAX_WIDGET_OPTIONS]; + + WidgetPersistentData(); }; struct ZonePersistentData { char widgetName[WIDGET_NAME_LEN + 1]; WidgetPersistentData widgetData; + + ZonePersistentData(); + bool isEmpty() const; }; template struct WidgetsContainerPersistentData { ZonePersistentData zones[N]; ZoneOptionValueTyped options[O]; + + WidgetsContainerPersistentData() { + memset((void*)this, 0, sizeof(WidgetsContainerPersistentData)); + } }; typedef WidgetsContainerPersistentData @@ -141,6 +160,9 @@ class RadioLayout struct CustomScreenData { char layoutId[LAYOUT_ID_LEN + 1]; LayoutPersistentData layoutPersistentData; + + CustomScreenData(); + bool isEmpty() const; }; struct CustomScreens { diff --git a/companion/src/firmwares/datahelpers.cpp b/companion/src/firmwares/datahelpers.cpp index 8ae759a1b..a7003d75b 100644 --- a/companion/src/firmwares/datahelpers.cpp +++ b/companion/src/firmwares/datahelpers.cpp @@ -68,3 +68,26 @@ QString DataHelpers::timeToString(const int value, const unsigned int mask) result.append(QString("%1:%2").arg(minutes, 2, 10, QLatin1Char('0')).arg(seconds, 2, 10, QLatin1Char('0'))); return result; } + +int DataHelpers::getStringTagMappingIndex(const StringTagMappingTable& lut, const char * tag) +{ + auto it = + find_if(lut.begin(), lut.end(), [=](const StringTagMapping& elmt) { + if (elmt.tag == tag) return true; + return false; + }); + + if (it != lut.end()) { + return it - lut.begin(); + } + + return -1; +} + +std::string DataHelpers::getStringTagMappingTag(const StringTagMappingTable& lut, unsigned int index) +{ + if (index < lut.size()) + return lut[index].tag; + + return std::string(); +} diff --git a/companion/src/firmwares/datahelpers.h b/companion/src/firmwares/datahelpers.h index ccd3b0f64..07d7609e0 100644 --- a/companion/src/firmwares/datahelpers.h +++ b/companion/src/firmwares/datahelpers.h @@ -21,6 +21,46 @@ #pragma once #include +#include +#include + +struct StringTagMapping { + std::string name; + std::string tag; + + StringTagMapping() = default; + StringTagMapping(const char* name) : + name(name), tag(name) + { + } + StringTagMapping(const std::string& name) : + name(name), tag(name) + { + } + StringTagMapping(const char* name, const char* tag) : + name(name), tag(tag) + { + } + StringTagMapping(const std::string& name, const std::string& tag) : + name(name), tag(tag) + { + } +}; + +typedef std::vector StringTagMappingTable; + +#define STRINGTAGMAPPINGFUNCS_HELPER(tbl, name, index, tag) \ + inline int name##index (const char * tag) \ + { \ + return DataHelpers::getStringTagMappingIndex(tbl, tag); \ + } \ + \ + inline std::string name##tag (unsigned int index) \ + { \ + return DataHelpers::getStringTagMappingTag(tbl, index); \ + } + +#define STRINGTAGMAPPINGFUNCS(tbl, name) STRINGTAGMAPPINGFUNCS_HELPER(tbl, get##name, Index, Tag) class FieldRange { @@ -65,5 +105,6 @@ namespace DataHelpers QString boolToString(const bool value, const BoolFormat format); QString getElementName(const QString & prefix, const unsigned int index, const char * name = 0, const bool padding = false); QString timeToString(const int value, const unsigned int mask); - + int getStringTagMappingIndex(const StringTagMappingTable& lut, const char * tag); + std::string getStringTagMappingTag(const StringTagMappingTable& lut, unsigned int index); } diff --git a/companion/src/firmwares/edgetx/edgetxinterface.cpp b/companion/src/firmwares/edgetx/edgetxinterface.cpp new file mode 100644 index 000000000..f1f1a0c91 --- /dev/null +++ b/companion/src/firmwares/edgetx/edgetxinterface.cpp @@ -0,0 +1,169 @@ +/* + * 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 "edgetxinterface.h" + +#include "yaml_ops.h" +#include "yaml_generalsettings.h" +#include "yaml_modeldata.h" + +#include + +static YAML::Node loadYamlFromByteArray(const QByteArray& data) +{ + // TODO: use real streaming to avoid memory copies + std::istringstream data_istream(data.toStdString()); + 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()); + + qDebug() << "Saving YAML:"; + qDebug() << data_ostream.str().c_str(); +} + +bool loadModelsListFromYaml(std::vector& categories, + EtxModelfiles& modelFiles, + const QByteArray& data) +{ + if (data.size() == 0) + return true; + + try { + YAML::Node node = loadYamlFromByteArray(data); + if (!node.IsSequence()) return false; + + int modelIdx = 0; + for (const auto& cat : node) { + + if (!cat.IsMap()) continue; + + for (const auto& cat_map : cat) { + categories.push_back(cat_map.first.Scalar().c_str()); + + const auto& models = cat_map.second; + if (!models.IsSequence()) continue; + + for (const auto& model : models) { + std::string filename, name; + model["filename"] >> filename; + model["name"] >> name; + modelFiles.push_back( + {filename, name, (int)categories.size() - 1, modelIdx++}); + } + } + } + + } catch (const std::runtime_error& e) { + qDebug() << "YAML::ParserException: " << e.what(); + return false; + } + + return true; +} + +bool loadModelFromYaml(ModelData& model, const QByteArray& data) +{ + YAML::Node node = loadYamlFromByteArray(data); + node >> model; + + return true; +} + +bool loadRadioSettingsFromYaml(GeneralSettings& settings, const QByteArray& data) +{ + YAML::Node node = loadYamlFromByteArray(data); + node >> settings; + if (settings.version < CPN_CURRENT_SETTINGS_VERSION) { + qDebug() << "Older version of settings detected:" << settings.version; + } + else if (settings.version > CPN_CURRENT_SETTINGS_VERSION) { + qDebug() << "Newer version of settings detected:" << settings.version; + QMessageBox::critical(NULL, CPN_STR_APP_NAME, QCoreApplication::translate("EdgeTXInterface", "Companion does not support settings version %1!").arg(settings.version)); + return false; + } + + 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.filename; + cat_attrs["name"] = modelFile.name; + + if (modelFile.category >= (int)categories.size()) { + return false; + } + + const std::string cat_name = categories[modelFile.category].name; + node[modelFile.category][cat_name].push_back(cat_attrs); + } + + writeYamlToByteArray(node, data); + return true; +} + +bool writeModelToYaml(const ModelData& model, QByteArray& data) +{ + 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); + return true; +} + +std::string patchFilenameToYaml(const std::string& str) +{ + constexpr const char MODELS_EXT[] = ".bin"; + constexpr const char YAML_EXT[] = ".yml"; + constexpr unsigned bin_len = sizeof(MODELS_EXT) - 1; + + // patch file extension + auto const dot_pos = str.find_last_of('.'); + if ((dot_pos != std::string::npos) && (str.substr(dot_pos) == MODELS_EXT)) { + std::string tmp = str; + return tmp.replace(dot_pos, bin_len, YAML_EXT); + } + return str; +} diff --git a/companion/src/firmwares/edgetx/edgetxinterface.h b/companion/src/firmwares/edgetx/edgetxinterface.h new file mode 100644 index 000000000..55b374ac9 --- /dev/null +++ b/companion/src/firmwares/edgetx/edgetxinterface.h @@ -0,0 +1,55 @@ +/* + * 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. + */ + +#pragma once + +#include "radiodata.h" +#include + +#include +#include +#include + +constexpr unsigned int CPN_CURRENT_SETTINGS_VERSION = { 221 }; + +struct EtxModelMetadata { + std::string filename; + std::string name; + int category; + int modelIdx; +}; + +typedef std::list EtxModelfiles; + +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); + +std::string patchFilenameToYaml(const std::string& str); diff --git a/companion/src/firmwares/edgetx/yaml_calibdata.cpp b/companion/src/firmwares/edgetx/yaml_calibdata.cpp new file mode 100644 index 000000000..32f0b2000 --- /dev/null +++ b/companion/src/firmwares/edgetx/yaml_calibdata.cpp @@ -0,0 +1,93 @@ +/* + * 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_calibdata.h" +#include "eeprominterface.h" + +YamlCalibData::YamlCalibData() { memset(calib, 0, sizeof(calib)); } + +YamlCalibData::YamlCalibData(const int* calibMid, const int* calibSpanNeg, + const int* calibSpanPos) +{ + for (int i = 0; i < CPN_MAX_ANALOGS; i++) { + calib[i].mid = calibMid[i]; + calib[i].spanNeg = calibSpanNeg[i]; + calib[i].spanPos = calibSpanPos[i]; + } +} + +void YamlCalibData::copy(int* calibMid, int* calibSpanNeg, + int* calibSpanPos) const +{ + for (int i = 0; i < CPN_MAX_ANALOGS; i++) { + calibMid[i] = calib[i].mid; + calibSpanNeg[i] = calib[i].spanNeg; + calibSpanPos[i] = calib[i].spanPos; + } +} + +namespace YAML +{ + +Node convert::encode(const CalibData& rhs) +{ + Node node; + node["mid"] = rhs.mid; + node["spanNeg"] = rhs.spanNeg; + node["spanPos"] = rhs.spanPos; + return node; +} + +bool convert::decode(const Node& node, CalibData& rhs) +{ + if (!node.IsMap()) return false; + node["mid"] >> rhs.mid; + node["spanNeg"] >> rhs.spanNeg; + node["spanPos"] >> rhs.spanPos; + return true; +} + +Node convert::encode(const YamlCalibData& rhs) +{ + Node node; + int idx = 0; + const auto* calibIdxLut = getCurrentFirmware()->getAnalogIndexNamesLookupTable(); + for (const auto& kv : *calibIdxLut) { + node[kv.tag] = rhs.calib[idx++]; + } + return node; +} + +bool convert::decode(const Node& node, YamlCalibData& rhs) +{ + if (!node.IsMap()) return false; + + for (const auto& kv : node) { + std::string tag; + kv.first >> tag; + int idx = getCurrentFirmware()->getAnalogInputIndex(tag.c_str()); + if (idx >= 0) { + kv.second >> rhs.calib[idx]; + } + } + return true; +} + +} // namespace YAML diff --git a/companion/src/firmwares/edgetx/yaml_calibdata.h b/companion/src/firmwares/edgetx/yaml_calibdata.h new file mode 100644 index 000000000..be8f37981 --- /dev/null +++ b/companion/src/firmwares/edgetx/yaml_calibdata.h @@ -0,0 +1,51 @@ +/* + * 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 "generalsettings.h" + +struct CalibData { + int16_t mid; + int16_t spanNeg; + int16_t spanPos; +}; + +struct YamlCalibData { + CalibData calib[CPN_MAX_ANALOGS]; + + YamlCalibData(); + YamlCalibData(const int* calibMid, const int* calibSpanNeg, const int* calibSpanPos); + void copy(int* calibMid, int* calibSpanNeg, int* calibSpanPos) const; +}; + +namespace YAML +{ +template <> +struct convert { + static Node encode(const CalibData& rhs); + static bool decode(const Node& node, CalibData& rhs); +}; + +template <> +struct convert { + static Node encode(const YamlCalibData& rhs); + static bool decode(const Node& node, YamlCalibData& rhs); +}; +} // namespace YAML diff --git a/companion/src/firmwares/edgetx/yaml_curvedata.cpp b/companion/src/firmwares/edgetx/yaml_curvedata.cpp new file mode 100644 index 000000000..ec02f0b38 --- /dev/null +++ b/companion/src/firmwares/edgetx/yaml_curvedata.cpp @@ -0,0 +1,106 @@ +/* + * 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_curvedata.h" + +// CurveHeader curves[MAX_CURVES]; +// int8_t points[MAX_CURVE_POINTS]; + +void YamlReadCurvePoints(const YAML::Node& node, CurveData* curves) +{ + int pidx = 0; + for (int i = 0; i < CPN_MAX_CURVES; i++) { + CurveData& curve = curves[i]; + for (int j = 0; j < curve.count; j++) { + std::string pidx_str = std::to_string(pidx++); + if (node[pidx_str]) { + int y = 0; + node[pidx_str]["val"] >> y; + curve.points[j].y = (int8_t)y; + } + } + if (curve.type == CurveData::CURVE_TYPE_CUSTOM) { + // Custom curve: X points are trailing Y points + curve.points[0].x = -100; + for (int k = 1; k < curve.count - 1; k++) { + std::string pidx_str = std::to_string(pidx++); + if (node[pidx_str]) { + int x = 0; + node[pidx_str]["val"] >> x; + curve.points[k].x = (int8_t)x; + } + } + curve.points[curve.count - 1].x = +100; + } else { + // Standard curve: X points are generated + for (int k = 0; k < curve.count; k++) { + curve.points[k].x = -100 + (200 * k) / (curve.count - 1); + } + } + } +} + +void YamlWriteCurvePoints(YAML::Node& node, const CurveData* curves) +{ + int pidx = 0; + for (int i = 0; i < CPN_MAX_CURVES; i++) { + + //TODO: assert max number of points + // and raise exception + + const CurveData& curve = curves[i]; + if (!curve.isEmpty()) { + for (int k = 0; k < curve.count; k++) { + node[std::to_string(pidx++)]["val"] = (int)curve.points[k].y; + } + if (curve.type == CurveData::CURVE_TYPE_CUSTOM) { + for (int k = 1; k < curve.count - 1; k++) { + node[std::to_string(pidx++)]["val"] = (int)curve.points[k].x; + } + } + } else { + pidx += 5; + } + } +} + +namespace YAML +{ +Node convert::encode(const CurveData& rhs) +{ + Node node; + node["type"] = (int)rhs.type; + node["smooth"] = (int)rhs.smooth; + node["points"] = rhs.count - 5; + node["name"] = rhs.name; + return node; +} + +bool convert::decode(const Node& node, CurveData& rhs) +{ + int curve_type = 0; + node["type"] >> curve_type; + rhs.type = (CurveData::CurveType)curve_type; + node["smooth"] >> rhs.smooth; + node["points"] >> ioffset_int(rhs.count, -5); + node["name"] >> rhs.name; + return true; +} +} diff --git a/companion/src/firmwares/edgetx/yaml_curvedata.h b/companion/src/firmwares/edgetx/yaml_curvedata.h new file mode 100644 index 000000000..c33e7eeab --- /dev/null +++ b/companion/src/firmwares/edgetx/yaml_curvedata.h @@ -0,0 +1,34 @@ +/* + * 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 "curvedata.h" + +void YamlReadCurvePoints(const YAML::Node& node, CurveData* curves); +void YamlWriteCurvePoints(YAML::Node& node, const CurveData* curves); + +namespace YAML +{ +template <> +struct convert { + static Node encode(const CurveData& rhs); + static bool decode(const Node& node, CurveData& rhs); +}; +} // namespace YAML diff --git a/companion/src/firmwares/edgetx/yaml_customfunctiondata.cpp b/companion/src/firmwares/edgetx/yaml_customfunctiondata.cpp new file mode 100644 index 000000000..22d59f191 --- /dev/null +++ b/companion/src/firmwares/edgetx/yaml_customfunctiondata.cpp @@ -0,0 +1,365 @@ +/* + * 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_customfunctiondata.h" +#include "yaml_rawswitch.h" +#include "yaml_rawsource.h" + +static bool fnHasEnable(AssignFunc fn) +{ + return (fn <= FuncInstantTrim) + || (fn >= FuncReset && fn <= FuncSetTimerLast) + || (fn >= FuncAdjustGV1 && fn <= FuncBindExternalModule) + || (fn == FuncVolume); +} + +static bool fnHasRepeat(AssignFunc fn) +{ + return (fn == FuncPlayPrompt) + || (fn == FuncPlayValue) + || (fn == FuncPlayHaptic) + || (fn == FuncPlaySound); +} + +static const YamlLookupTable customFnLut = { + { FuncOverrideCH1, "OVERRIDE_CHANNEL" }, + { FuncTrainer, "TRAINER" }, + { FuncInstantTrim, "INSTANT_TRIM" }, + { FuncReset, "RESET" }, + { FuncSetTimer1, "SET_TIMER" }, + { FuncAdjustGV1, "ADJUST_GVAR" }, + { FuncVolume, "VOLUME" }, + { FuncSetFailsafe, "SET_FAILSAFE" }, + { FuncRangeCheckInternalModule, "RANGECHECK" }, + { FuncBindInternalModule, "BIND" }, + { FuncPlaySound, "PLAY_SOUND" }, + { FuncPlayPrompt, "PLAY_TRACK" }, + { FuncPlayValue, "PLAY_VALUE" }, + { FuncPlayScript, "PLAY_SCRIPT" }, + { FuncBackgroundMusic, "BACKGND_MUSIC" }, + { FuncBackgroundMusicPause, "BACKGND_MUSIC_PAUSE" }, + { FuncVario, "VARIO" }, + { FuncPlayHaptic, "HAPTIC" }, + { FuncLogs, "LOGS" }, + { FuncBacklight, "BACKLIGHT" }, + { FuncScreenshot, "SCREENSHOT" }, + { FuncRacingMode, "RACING_MODE" }, + { FuncDisableTouch, "DISABLE_TOUCH" }, +}; + +static const YamlLookupTable trainerLut = { + { 0, "sticks" }, + { 1, "Rud" }, + { 2, "Ele" }, + { 3, "Thr" }, + { 4, "Ail" }, + { 5, "chans" }, +}; + +static const YamlLookupTable soundLut = { + { 0, "Bp1" }, + { 1, "Bp2" }, + { 2, "Bp3" }, + { 3, "Wrn1" }, + { 4, "Wrn2" }, + { 5, "Chee" }, + { 6, "Rata" }, + { 7, "Tick" }, + { 8, "Sirn" }, + { 9, "Ring" }, + { 10, "SciF" }, + { 11, "Robt" }, + { 12, "Chrp" }, + { 13, "Tada" }, + { 14, "Crck" }, + { 15, "Alrm" }, +}; + +static const YamlLookupTable resetLut = { + { 0, "Tmr1" }, + { 1, "Tmr2" }, + { 2, "Tmr3" }, + { 3, "All" }, + { 4, "Tele" }, +}; + +static const YamlLookupTable gvarModeLut = { + { FUNC_ADJUST_GVAR_CONSTANT, "Cst" }, + { FUNC_ADJUST_GVAR_SOURCE, "Src" }, + { FUNC_ADJUST_GVAR_GVAR, "GVar" }, + { FUNC_ADJUST_GVAR_INCDEC, "IncDec" }, +}; + +static const YamlLookupTable moduleLut = { + { 0, "Int" }, + { 1, "Ext" }, +}; + +namespace YAML +{ +Node convert::encode(const CustomFunctionData& rhs) +{ + Node node; + node["swtch"] = rhs.swtch; + + int fn = rhs.func; + int p1 = 0; + if(fn >= FuncOverrideCH1 && fn <= FuncOverrideCHLast) { + p1 = fn - (int)FuncOverrideCH1; + fn = (int)FuncOverrideCH1; + } else if (fn >= FuncTrainer && fn <= FuncTrainerChannels) { + p1 = fn - (int)FuncTrainer; + fn = (int)FuncTrainer; + } else if (fn >= FuncSetTimer1 && fn <= FuncSetTimerLast) { + p1 = fn - (int)FuncSetTimer1; + fn = (int)FuncSetTimer1; + } else if (fn >= FuncAdjustGV1 && fn <= FuncAdjustGVLast) { + p1 = fn - (int)FuncAdjustGV1; + fn = (int)FuncAdjustGV1; + } else if (fn >= FuncRangeCheckInternalModule && fn <= FuncRangeCheckExternalModule) { + p1 = fn - (int)FuncRangeCheckInternalModule; + fn = (int)FuncRangeCheckInternalModule; + } else if (fn >= FuncBindInternalModule && fn <= FuncBindExternalModule) { + p1 = fn - (int)FuncBindInternalModule; + fn = (int)FuncBindInternalModule; + } + node["func"] = LookupValue(customFnLut, fn); + + bool add_comma = true; + std::string def; + switch(fn) { + case FuncOverrideCH1: + def += std::to_string(p1); + def += ","; + def += std::to_string(rhs.param); + break; + case FuncTrainer: + def += LookupValue(trainerLut, p1); + break; + case FuncPlaySound: + def += LookupValue(soundLut, rhs.param); + break; + case FuncPlayPrompt: + case FuncPlayScript: + case FuncBackgroundMusic: + def += std::string(rhs.paramarm); + break; + case FuncReset: + def += LookupValue(resetLut, rhs.param); + if (def.empty()) { + def += std::to_string(rhs.param - resetLut.size()); + } + break; + case FuncSetTimer1: { + def += LookupValue(resetLut, p1); + def += ","; + def += std::to_string(rhs.param); + } break; + case FuncPlayValue: + case FuncVolume: + case FuncBacklight: { + def += YamlRawSourceEncode(RawSource(rhs.param)); + } break; + case FuncAdjustGV1: { + // + GV # + def += std::to_string(p1); + def += ","; + def += LookupValue(gvarModeLut, rhs.adjustMode); + def += ","; + + switch(rhs.adjustMode) { + case FUNC_ADJUST_GVAR_CONSTANT: + case FUNC_ADJUST_GVAR_INCDEC: + def += std::to_string(rhs.param); + break; + case FUNC_ADJUST_GVAR_GVAR: + case FUNC_ADJUST_GVAR_SOURCE: { + def += YamlRawSourceEncode(RawSource(rhs.param)); + } break; + } + } break; + case FuncRangeCheckInternalModule: + case FuncBindInternalModule: { + def += LookupValue(moduleLut, p1); + } break; + case FuncLogs: + def += std::to_string(rhs.param); + break; + default: + add_comma = false; + break; + } + + if (fnHasEnable(rhs.func)) { + if (add_comma) { + def += ","; + } + def += std::to_string((int)rhs.enabled); + } else if(fnHasRepeat(rhs.func)) { + if (add_comma) { + def += ","; + } + if (rhs.repeatParam == 0) { + def += "1x"; + } else if (rhs.repeatParam == -1) { + def += "!1x"; + } else { + def += std::to_string(rhs.repeatParam); + } + } + + if (!def.empty()) { + node["def"] = def; + } + + return node; +} + +bool convert::decode(const Node& node, + CustomFunctionData& rhs) +{ + node["swtch"] >> rhs.swtch; + + int func = 0; + node["func"] >> customFnLut >> func; + rhs.func = (AssignFunc)func; + + std::string def_str; + node["def"] >> def_str; + std::stringstream def(def_str); + + switch(rhs.func) { + case FuncOverrideCH1: { + int ch=0; + def >> ch; + rhs.func = (AssignFunc)((int)rhs.func + ch); + def.ignore(); + def >> rhs.param; + } break; + case FuncTrainer: { + std::string value_str; + getline(def, value_str, ','); + int value=0; + Node(value_str) >> trainerLut >> value; + rhs.func = (AssignFunc)((int)rhs.func + value); + } break; + case FuncPlaySound: { + std::string snd; + getline(def, snd, ','); + Node(snd) >> soundLut >> rhs.param; + } break; + case FuncPlayPrompt: + case FuncPlayScript: + case FuncBackgroundMusic: { + std::string file_str; + getline(def, file_str, ','); + strncpy(rhs.paramarm, file_str.c_str(), sizeof(rhs.paramarm)-1); + } break; + case FuncReset: { + std::string rst_str; + getline(def, rst_str, ','); + try { + rhs.param = std::stoi(rst_str); + rhs.param += resetLut.size(); + break; + } catch(...) {} + Node(rst_str.c_str()) >> resetLut >> rhs.param; + } break; + case FuncSetTimer1: { + // + timer # + std::string tmr_str; + getline(def, tmr_str, ','); + int tmr = 0; + Node(tmr_str) >> resetLut >> tmr; + rhs.func = (AssignFunc)((int)rhs.func + tmr); + def >> rhs.param; + } break; + case FuncPlayValue: + case FuncVolume: + case FuncBacklight: { + std::string src_str; + getline(def, src_str, ','); + rhs.param = YamlRawSourceDecode(src_str).toValue(); + } break; + case FuncAdjustGV1: { + // + GV # + int gvar_idx=0; + def >> gvar_idx; + rhs.func = (AssignFunc)((int)rhs.func + gvar_idx); + def.ignore(); + + std::string mode; + getline(def, mode, ','); + Node(mode) >> gvarModeLut >> rhs.adjustMode; + switch(rhs.adjustMode) { + case FUNC_ADJUST_GVAR_CONSTANT: + case FUNC_ADJUST_GVAR_INCDEC: + def >> rhs.param; + break; + case FUNC_ADJUST_GVAR_GVAR: + case FUNC_ADJUST_GVAR_SOURCE: { + std::string src_str; + getline(def, src_str, ','); + RawSource src; + Node(src_str) >> src; + rhs.param = src.toValue(); + } break; + } + } break; + case FuncRangeCheckInternalModule: + case FuncBindInternalModule: { + // DANGEROUS_FUNCTIONS... + // + module # ??? + std::string mod; + getline(def, mod, ','); + int module=0; + Node(mod) >> moduleLut >> module; + rhs.func = (AssignFunc)((int)rhs.func + module); + } break; + case FuncLogs: { + int param = 0; + def >> param; + rhs.param = param; + } break; + default: + break; + } + + if (fnHasEnable(rhs.func)) { + int en = 0; + def >> en; + rhs.enabled = en; + } else if(fnHasRepeat(rhs.func)) { + std::string repeat; + getline(def, repeat); + if (repeat == "1x") { + rhs.repeatParam = 0; + } else if (repeat == "!1x") { + rhs.repeatParam = -1; + } else { + try { + rhs.repeatParam = std::stoi(repeat); + } catch(...) {} + } + } + + return true; +} +} // namespace YAML diff --git a/companion/src/firmwares/edgetx/yaml_customfunctiondata.h b/companion/src/firmwares/edgetx/yaml_customfunctiondata.h new file mode 100644 index 000000000..00e4700e1 --- /dev/null +++ b/companion/src/firmwares/edgetx/yaml_customfunctiondata.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 "customfunctiondata.h" + +namespace YAML +{ +template <> +struct convert { + static Node encode(const CustomFunctionData& rhs); + static bool decode(const Node& node, CustomFunctionData& rhs); +}; +} // namespace YAML diff --git a/companion/src/firmwares/edgetx/yaml_expodata.cpp b/companion/src/firmwares/edgetx/yaml_expodata.cpp new file mode 100644 index 000000000..2a4987022 --- /dev/null +++ b/companion/src/firmwares/edgetx/yaml_expodata.cpp @@ -0,0 +1,67 @@ +/* + * 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_expodata.h" +#include "yaml_mixdata.h" +#include "yaml_rawswitch.h" +#include "yaml_rawsource.h" +#include "curvereference.h" + +namespace YAML +{ +Node convert::encode(const ExpoData& rhs) +{ + Node node; + node["srcRaw"] = rhs.srcRaw; + node["scale"] = rhs.scale; + node["mode"] = rhs.mode; // InputMode + node["chn"] = rhs.chn; + node["swtch"] = rhs.swtch; + node["flightModes"] = YamlWriteFlightModes(rhs.flightModes); + node["weight"] = YamlWriteMixWeight(rhs.weight); + node["offset"] = rhs.offset; // YamlWriteMixWeight + node["curve"] = rhs.curve; + node["carryTrim"] = rhs.carryTrim; + node["name"] = rhs.name; + return node; +} + +bool convert::decode(const Node& node, ExpoData& rhs) +{ + node["srcRaw"] >> rhs.srcRaw; + node["scale"] >> rhs.scale; + node["mode"] >> rhs.mode; // InputMode + node["chn"] >> rhs.chn; + node["swtch"] >> rhs.swtch; + if (node["flightModes"]) { + rhs.flightModes = YamlReadFlightModes(node["flightModes"]); + } + if (node["weight"]) { + rhs.weight = YamlReadMixWeight(node["weight"]); + } + if (node["offset"]) { + rhs.offset = YamlReadMixWeight(node["offset"]); + } + node["curve"] >> rhs.curve; + node["carryTrim"] >> rhs.carryTrim; + node["name"] >> rhs.name; + return true; +} +} // namespace YAML diff --git a/companion/src/firmwares/edgetx/yaml_expodata.h b/companion/src/firmwares/edgetx/yaml_expodata.h new file mode 100644 index 000000000..1495bce6d --- /dev/null +++ b/companion/src/firmwares/edgetx/yaml_expodata.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 "input_data.h" + +namespace YAML +{ +template <> +struct convert { + static Node encode(const ExpoData& rhs); + static bool decode(const Node& node, ExpoData& rhs); +}; +} // namespace YAML diff --git a/companion/src/firmwares/edgetx/yaml_generalsettings.cpp b/companion/src/firmwares/edgetx/yaml_generalsettings.cpp new file mode 100644 index 000000000..d5c5ddaea --- /dev/null +++ b/companion/src/firmwares/edgetx/yaml_generalsettings.cpp @@ -0,0 +1,361 @@ +/* + * 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_generalsettings.h" +#include "yaml_customfunctiondata.h" +#include "yaml_trainerdata.h" +#include "yaml_calibdata.h" +#include "yaml_switchconfig.h" +#include "yaml_moduledata.h" + +#include "eeprominterface.h" +#include "edgetxinterface.h" + +#include + +const YamlLookupTable beeperModeLut = { + { GeneralSettings::BEEPER_QUIET, "mode_quiet" }, + { GeneralSettings::BEEPER_ALARMS_ONLY, "mode_alarms" }, + { GeneralSettings::BEEPER_NOKEYS, "mode_nokeys" }, + { GeneralSettings::BEEPER_ALL, "mode_all" }, +}; + +enum BacklightMode { + e_backlight_mode_off = 0, + e_backlight_mode_keys = 1, + e_backlight_mode_sticks = 2, + e_backlight_mode_all = e_backlight_mode_keys+e_backlight_mode_sticks, + e_backlight_mode_on +}; + +const YamlLookupTable backlightModeLut = { + { e_backlight_mode_off, "backlight_mode_off" }, + { e_backlight_mode_keys, "backlight_mode_keys" }, + { e_backlight_mode_sticks, "backlight_mode_sticks" }, + { e_backlight_mode_all, "backlight_mode_all" }, + { e_backlight_mode_on, "backlight_mode_on" }, +}; + +const YamlLookupTable bluetoothModeLut = { + { GeneralSettings::BLUETOOTH_MODE_OFF, "OFF" }, + { GeneralSettings::BLUETOOTH_MODE_TELEMETRY, "TELEMETRY" }, + { GeneralSettings::BLUETOOTH_MODE_TRAINER, "TRAINER" }, +}; + +const YamlLookupTable uartModeLut = { + { GeneralSettings::AUX_SERIAL_OFF, "MODE_NONE" }, + { GeneralSettings::AUX_SERIAL_TELE_MIRROR, "MODE_TELEMETRY_MIRROR" }, + { GeneralSettings::AUX_SERIAL_TELE_IN, "MODE_TELEMETRY" }, + { GeneralSettings::AUX_SERIAL_SBUS_TRAINER, "MODE_SBUS_TRAINER" }, + { GeneralSettings::AUX_SERIAL_LUA, "MODE_LUA" }, +}; + +const YamlLookupTable antennaModeLut = { + { GeneralSettings::ANTENNA_MODE_INTERNAL, "MODE_INTERNAL" }, + { GeneralSettings::ANTENNA_MODE_ASK, "MODE_ASK" }, + { GeneralSettings::ANTENNA_MODE_PER_MODEL, "MODE_PER_MODEL" }, + { GeneralSettings::ANTENNA_MODE_EXTERNAL, "MODE_EXTERNAL" }, + { GeneralSettings::ANTENNA_MODE_INTERNAL_EXTERNAL, "MODE_INTERNAL_EXTERNAL" }, +}; + +const YamlLookupTable internalModuleLut = { + { MODULE_TYPE_NONE, "TYPE_NONE" }, + { MODULE_TYPE_PPM, "TYPE_PPM" }, + { MODULE_TYPE_XJT_PXX1, "TYPE_XJT_PXX1" }, + { MODULE_TYPE_ISRM_PXX2, "TYPE_ISRM_PXX2" }, + { MODULE_TYPE_DSM2, "TYPE_DSM2" }, + { MODULE_TYPE_CROSSFIRE, "TYPE_CROSSFIRE" }, + { MODULE_TYPE_MULTIMODULE, "TYPE_MULTIMODULE" }, + { MODULE_TYPE_R9M_PXX1, "TYPE_R9M_PXX1" }, + { MODULE_TYPE_R9M_PXX2, "TYPE_R9M_PXX2" }, + { MODULE_TYPE_R9M_LITE_PXX1, "TYPE_R9M_LITE_PXX1" }, + { MODULE_TYPE_R9M_LITE_PXX2, "TYPE_R9M_LITE_PXX2" }, + { MODULE_TYPE_GHOST, "TYPE_GHOST" }, + { MODULE_TYPE_R9M_LITE_PRO_PXX2, "TYPE_R9M_LITE_PRO_PXX2" }, + { MODULE_TYPE_SBUS, "TYPE_SBUS" }, + { MODULE_TYPE_XJT_LITE_PXX2, "TYPE_XJT_LITE_PXX2" }, + { MODULE_TYPE_FLYSKY, "TYPE_FLYSKY" }, +}; + +namespace YAML +{ + +ENUM_CONVERTER(GeneralSettings::BeeperMode, beeperModeLut); + +Node convert::encode(const GeneralSettings& rhs) +{ + Node node; + + std::string board = getCurrentFirmware()->getFlavour().toStdString(); + node["board"] = board; + + node["version"] = CPN_CURRENT_SETTINGS_VERSION; + + YamlCalibData calib(rhs.calibMid, rhs.calibSpanNeg, rhs.calibSpanPos); + node["calib"] = calib; + + node["currModel"] = rhs.currModelIndex; + node["currModelFilename"] = patchFilenameToYaml(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 << std::abs(rhs.backlightMode); + node["trainer"] = rhs.trainer; + node["view"] = rhs.view; + node["fai"] = (int)rhs.fai; + node["disableMemoryWarning"] = (int)rhs.disableMemoryWarning; + node["beepMode"] = rhs.beeperMode; + node["disableAlarmWarning"] = (int)rhs.disableAlarmWarning; + node["disableRssiPoweroffAlarm"] = (int)rhs.disableRssiPoweroffAlarm; + node["USBMode"] = rhs.usbMode; + node["jackMode"] = rhs.jackMode; + node["hapticMode"] = rhs.hapticMode; + node["stickMode"] = rhs.stickMode; + node["timezone"] = rhs.timezone; + node["adjustRTC"] = (int)rhs.adjustRTC; + node["inactivityTimer"] = rhs.inactivityTimer; + node["telemetryBaudrate"] = rhs.telemetryBaudrate; // TODO: conversion??? + node["internalModule"] = LookupValue(internalModuleLut, rhs.internalModule); + node["splashMode"] = rhs.splashMode; // TODO: B&W only + node["lightAutoOff"] = rhs.backlightDelay; + 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"] = (int)rhs.jitterFilter; + node["disableRtcWarning"] = (int)rhs.rtcCheckDisable; // TODO: verify + node["keysBacklight"] = (int)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; + + for (int i = 0; i < CPN_MAX_SPECIAL_FUNCTIONS; i++) { + const CustomFunctionData& fn = rhs.customFn[i]; + if (!fn.isEmpty()) { + node["customFn"][std::to_string(i)] = fn; + } + } + + Node sticksConfig; + sticksConfig = YamlStickConfig(rhs.stickName); + if (sticksConfig && sticksConfig.IsMap()) { + node["sticksConfig"] = sticksConfig; + } + + Node switchConfig; + switchConfig = YamlSwitchConfig(rhs.switchName, rhs.switchConfig); + if (switchConfig && switchConfig.IsMap()) { + node["switchConfig"] = switchConfig; + } + + Node potsConfig; + potsConfig = YamlPotConfig(rhs.potName, rhs.potConfig); + if (potsConfig && potsConfig.IsMap()) { + node["potsConfig"] = potsConfig; + } + + Node slidersConfig; + slidersConfig = YamlSliderConfig(rhs.sliderName, rhs.sliderConfig); + if (slidersConfig && slidersConfig.IsMap()) { + node["slidersConfig"] = slidersConfig; + } + + // 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; +} + +bool convert::decode(const Node& node, GeneralSettings& rhs) +{ + if (!node.IsMap()) return false; + + // for (const auto& n : node) { + // qDebug() << QString::fromStdString(n.first.Scalar()); + // } + + node["version"] >> rhs.version; + + // Decoding uses profile firmare therefore all conversions are performed on the fly + // So set board to firmware board + // However we should alert users that conversions may have occured + // If conversion should rename file with _converted suffix as done for bin + // Need to pass back messages and flags like converted so they can be handled in a more suitable section + + rhs.variant = Board::BOARD_UNKNOWN; + + std::string flavour; + node["board"] >> flavour; + + auto fw = getCurrentFirmware(); + auto msfw = Firmware::getFirmwareForFlavour(QString(flavour.c_str())); + + if (flavour.empty()) { + qDebug() << "Warning: Settings file does not contain board flavour! Default firmware board will be used"; + flavour = msfw->getFlavour().toStdString(); + } + + qDebug() << "Settings version:" << rhs.version << "File flavour:" << flavour.c_str() << "Firmware flavour:" << fw->getFlavour(); + + if (fw->getFlavour().toStdString() != flavour) { + QString prmpt = QCoreApplication::translate("YamlGeneralSettings", "File board (%1) does not match current profile board (%2), models and settings will be converted where possible.\n\nDo you wish to continue?").arg(Boards::getBoardName(msfw->getBoard())).arg(Boards::getBoardName(fw->getBoard())); + + if (QMessageBox::question(NULL, CPN_STR_APP_NAME, prmpt, (QMessageBox::Yes | QMessageBox::No), QMessageBox::No) != QMessageBox::Yes) { + // TODO: this triggers an error in the calling code so we need a graceful way to handle + return false; + } + } + + rhs.variant = fw->getBoard(); + + 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"] >> ioffset_int(rhs.vBatMin, 90); + node["vBatMax"] >> ioffset_int(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??? + + if (node["internalModule"]) { + node["internalModule"] >> internalModuleLut >> rhs.internalModule; + } else { + rhs.internalModule = Boards::getDefaultInternalModules(fw->getBoard()); + } + + node["splashMode"] >> rhs.splashMode; // TODO: B&W only + node["lightAutoOff"] >> rhs.backlightDelay; + node["templateSetup"] >> rhs.templateSetup; + node["hapticLength"] >> ioffset_int(rhs.hapticLength, 2); + node["speakerPitch"] >> ifactor(rhs.speakerPitch, 15); + node["hapticStrength"] >> ioffset_int(rhs.hapticStrength, 2); + node["beepLength"] >> ioffset_int(rhs.beeperLength, 2); + node["gpsFormat"] >> rhs.gpsFormat; + node["speakerVolume"] >> ioffset_int(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"] >> ioffset_int(rhs.beepVolume, 2); + node["wavVolume"] >> ioffset_int(rhs.wavVolume, 2); + node["varioVolume"] >> ioffset_int(rhs.varioVolume, 2); + node["varioPitch"] >> ifactor(rhs.varioPitch, 10); + node["varioRange"] >> ifactor(rhs.varioRange, 15); + node["varioRepeat"] >> rhs.varioRepeat; + node["backgroundVolume"] >> ioffset_int(rhs.backgroundVolume, 2); + node["auxSerialMode"] >> uartModeLut >> rhs.auxSerialMode; + node["aux2SerialMode"] >> uartModeLut >> rhs.aux2SerialMode; + node["antennaMode"] >> antennaModeLut >> rhs.antennaMode; + node["backlightColor"] >> rhs.backlightColor; + node["customFn"] >> rhs.customFn; + + YamlStickConfig stickConfig; + node["sticksConfig"] >> stickConfig; + stickConfig.copy(rhs.stickName); + + 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 true; +} +} // namespace YAML diff --git a/companion/src/firmwares/edgetx/yaml_generalsettings.h b/companion/src/firmwares/edgetx/yaml_generalsettings.h new file mode 100644 index 000000000..401f6e4a1 --- /dev/null +++ b/companion/src/firmwares/edgetx/yaml_generalsettings.h @@ -0,0 +1,34 @@ +/* + * 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 "generalsettings.h" + +namespace YAML { + + template<> + struct convert { + + static Node encode(const GeneralSettings& rhs); + static bool decode(const Node& node, GeneralSettings& rhs); + }; +} + + diff --git a/companion/src/firmwares/edgetx/yaml_logicalswitchdata.cpp b/companion/src/firmwares/edgetx/yaml_logicalswitchdata.cpp new file mode 100644 index 000000000..852179b12 --- /dev/null +++ b/companion/src/firmwares/edgetx/yaml_logicalswitchdata.cpp @@ -0,0 +1,188 @@ +/* + * 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_logicalswitchdata.h" +#include "yaml_rawswitch.h" +#include "yaml_rawsource.h" + +static const YamlLookupTable funcLut = { + {LS_FN_OFF, "FUNC_NONE"}, + {LS_FN_VEQUAL, "FUNC_VEQUAL"}, + {LS_FN_VALMOSTEQUAL, "FUNC_VALMOSTEQUAL"}, + {LS_FN_VPOS, "FUNC_VPOS"}, + {LS_FN_VNEG, "FUNC_VNEG"}, + {LS_FN_APOS, "FUNC_APOS"}, + {LS_FN_ANEG, "FUNC_ANEG"}, + {LS_FN_AND, "FUNC_AND"}, + {LS_FN_OR, "FUNC_OR"}, + {LS_FN_XOR, "FUNC_XOR"}, + {LS_FN_EDGE, "FUNC_EDGE"}, + {LS_FN_EQUAL, "FUNC_EQUAL"}, + {LS_FN_GREATER, "FUNC_GREATER"}, + {LS_FN_LESS, "FUNC_LESS"}, + {LS_FN_DPOS, "FUNC_DIFFEGREATER"}, + {LS_FN_DAPOS, "FUNC_ADIFFEGREATER"}, + {LS_FN_TIMER, "FUNC_TIMER"}, + {LS_FN_STICKY, "FUNC_STICKY"}, +}; + +static int timerValue2lsw(uint32_t t) +{ + if (t < 20) { + return t - 129; + } else if (600) { + return t / 5 - 113; + } else { + return t / 10 - 53; + } +} +// val = [-129,-110] => [0,19] (step 1) +// val = [-109,6] => [20,595] (step 5) +// val = [7,122] => [600,1750] (step 10) +// +static int lswTimerValue(int val) +{ + return (val < -109 ? 129+val : (val < 7 ? (113+val)*5 : (53+val)*10)); +} + +namespace YAML +{ +Node convert::encode(const LogicalSwitchData& rhs) +{ + Node node; + node["func"] = funcLut << rhs.func; + + std::string def; + + switch (rhs.getFunctionFamily()) { + case LS_FAMILY_VBOOL: + case LS_FAMILY_STICKY: { + def += YamlRawSwitchEncode(RawSwitch(rhs.val1)); + def += ","; + def += YamlRawSwitchEncode(RawSwitch(rhs.val2)); + } break; + + case LS_FAMILY_EDGE: { + def += YamlRawSwitchEncode(RawSwitch(rhs.val1)); + def += ","; + def += std::to_string(lswTimerValue(rhs.val2)); + def += ","; + def += std::to_string(lswTimerValue(rhs.val3)); + } break; + + case LS_FAMILY_VCOMP: { + def += YamlRawSourceEncode(RawSource(rhs.val1)); + def += ","; + def += YamlRawSourceEncode(RawSource(rhs.val2)); + } break; + + case LS_FAMILY_TIMER: { + def += std::to_string(lswTimerValue(rhs.val1)); + def += ","; + def += std::to_string(lswTimerValue(rhs.val2)); + } break; + + default: { + def += YamlRawSourceEncode(RawSource(rhs.val1)); + def += ","; + def += std::to_string(rhs.val2); + } break; + } + + node["def"] = def; + node["delay"] = rhs.delay; + node["duration"] = rhs.duration; + node["andsw"] = YamlRawSwitchEncode(RawSwitch(rhs.andsw)); + + return node; +} + +bool convert::decode(const Node& node, + LogicalSwitchData& rhs) +{ + node["func"] >> funcLut >> rhs.func; + + std::string def_str; + node["def"] >> def_str; + std::stringstream def(def_str); + + switch (rhs.getFunctionFamily()) { + case LS_FAMILY_VBOOL: + case LS_FAMILY_STICKY: { + std::string sw_str; + getline(def, sw_str, ','); + rhs.val1 = YamlRawSwitchDecode(sw_str).toValue(); + getline(def, sw_str); + rhs.val2 = YamlRawSwitchDecode(sw_str).toValue(); + } break; + + case LS_FAMILY_EDGE: { + std::string sw_str; + getline(def, sw_str, ','); + rhs.val1 = YamlRawSwitchDecode(sw_str).toValue(); + int v2=0, v3=0; + def >> v2; + rhs.val2 = timerValue2lsw(v2); + def.ignore(); + if (def.peek() == '<') { + rhs.val3 = -1; + } else if (def.peek() == '-') { + rhs.val3 = 0; + } else { + def >> v3; + rhs.val3 = timerValue2lsw(v3); + } + } break; + + case LS_FAMILY_VCOMP: { + std::string src_str; + getline(def, src_str, ','); + rhs.val1 = YamlRawSourceDecode(src_str).toValue(); + getline(def, src_str); + rhs.val2 = YamlRawSourceDecode(src_str).toValue(); + } break; + + case LS_FAMILY_TIMER: { + int v1=0, v2=0; + def >> v1; + rhs.val1 = timerValue2lsw(v1); + def.ignore(); + def >> v2; + rhs.val2 = timerValue2lsw(v2); + } break; + + default: { + std::string src_str; + getline(def, src_str, ','); + rhs.val1 = YamlRawSourceDecode(src_str).toValue(); + def >> rhs.val2; + } break; + } + + node["delay"] >> rhs.delay; + node["duration"] >> rhs.duration; + + RawSwitch andsw; + node["andsw"] >> andsw; + rhs.andsw = andsw.toValue(); + + return true; +} +} // namespace YAML diff --git a/companion/src/firmwares/edgetx/yaml_logicalswitchdata.h b/companion/src/firmwares/edgetx/yaml_logicalswitchdata.h new file mode 100644 index 000000000..738a6fc8a --- /dev/null +++ b/companion/src/firmwares/edgetx/yaml_logicalswitchdata.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 "logicalswitchdata.h" + +namespace YAML +{ +template <> +struct convert { + static Node encode(const LogicalSwitchData& rhs); + static bool decode(const Node& node, LogicalSwitchData& rhs); +}; +} // namespace YAML diff --git a/companion/src/firmwares/edgetx/yaml_mixdata.cpp b/companion/src/firmwares/edgetx/yaml_mixdata.cpp new file mode 100644 index 000000000..5b53bf762 --- /dev/null +++ b/companion/src/firmwares/edgetx/yaml_mixdata.cpp @@ -0,0 +1,173 @@ +/* + * 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_mixdata.h" +#include "yaml_rawswitch.h" +#include "yaml_rawsource.h" +#include "curvereference.h" + +static const YamlLookupTable mixMultiplexLut = { + { MLTPX_ADD, "ADD" }, + { MLTPX_MUL, "MUL" }, + { MLTPX_REP, "REPL" }, +}; + +#define GVAR_SMALL 128 +#define CPN_GV1 1024 + +int32_t YamlReadMixWeight(const YAML::Node& node) +{ + std::string val = node.as(); + if ((val.size() >= 4) + && (val[0] == '-') + && (val[1] == 'G') + && (val[2] == 'V') + && (val[3] >= '1') + && (val[3] <= '9')) { + + return -10000 - std::stoi(val.substr(3)); + } + + if ((val.size() >= 3) + && (val[0] == 'G') + && (val[1] == 'V') + && (val[2] >= '1') + && (val[2] <= '9')) { + + return 10000 + std::stoi(val.substr(2)); + } + + try { + return std::stoi(val); + } catch(...) { + throw YAML::TypedBadConversion(node.Mark()); + } +} + +std::string YamlWriteMixWeight(int32_t sval) +{ + if (sval < -10000) { + int n = -sval - 10000; + return std::string("-GV") + std::to_string(n); + } else if (sval > 10000) { + int n = sval - 10000; + return std::string("GV") + std::to_string(n); + } + + return std::to_string(sval); +} + +uint32_t YamlReadFlightModes(const YAML::Node& node) +{ + std::string fm_str = node.as(); + uint32_t bits = 0; + uint32_t mask = 1; + + for (uint32_t i = 0; i < fm_str.size(); i++) { + if (fm_str[i] == '1') bits |= mask; + mask <<= 1; + } + return bits; +} + +std::string YamlWriteFlightModes(uint32_t val) +{ + std::string fm_str; + // TODO: constant for number of flight modes + for (int i=0; i<9; i++) { + uint32_t bit = (val >> i) & 1; + fm_str += bit ? "1" : "0"; + } + return fm_str; +} + +static const YamlLookupTable dummy = {}; + +namespace YAML +{ +ENUM_CONVERTER(MltpxValue, mixMultiplexLut); + +Node convert::encode(const CurveReference& rhs) +{ + Node node; + node["type"] = (int)rhs.type; + node["value"] = YamlWriteMixWeight(rhs.value); + return node; +} + +bool convert::decode(const Node& node, CurveReference& rhs) +{ + // no symbolic value defined in radio + int type = 0; + node["type"] >> type; + rhs.type = (CurveReference::CurveRefType)type; + if (node["value"]) { + rhs.value = YamlReadMixWeight(node["value"]); + } + return true; +} + +Node convert::encode(const MixData& rhs) +{ + Node node; + node["destCh"] = rhs.destCh - 1; + node["srcRaw"] = rhs.srcRaw; + node["weight"] = YamlWriteMixWeight(rhs.weight); + node["swtch"] = rhs.swtch; + node["curve"] = rhs.curve; + node["delayUp"] = rhs.delayUp; + node["delayDown"] = rhs.delayDown; + node["speedUp"] = rhs.speedUp; + node["speedDown"] = rhs.speedDown; + node["carryTrim"] = rhs.carryTrim; + node["mltpx"] = rhs.mltpx; + node["mixWarn"] = rhs.mixWarn; + node["flightModes"] = YamlWriteFlightModes(rhs.flightModes); + node["offset"] = YamlWriteMixWeight(rhs.sOffset); + node["name"] = rhs.name; + return node; +} + +bool convert::decode(const Node& node, MixData& rhs) +{ + node["destCh"] >> ioffset_int((int&)rhs.destCh, -1); + node["srcRaw"] >> rhs.srcRaw; + if (node["weight"]) { + rhs.weight = YamlReadMixWeight(node["weight"]); + } + node["swtch"] >> rhs.swtch; + node["curve"] >> rhs.curve; + node["delayUp"] >> rhs.delayUp; + node["delayDown"] >> rhs.delayDown; + node["speedUp"] >> rhs.speedUp; + node["speedDown"] >> rhs.speedDown; + node["carryTrim"] >> rhs.carryTrim; + node["mltpx"] >> rhs.mltpx; + node["mixWarn"] >> rhs.mixWarn; + if (node["flightModes"]) { + rhs.flightModes = YamlReadFlightModes(node["flightModes"]); + } + if (node["offset"]) { + rhs.sOffset = YamlReadMixWeight(node["offset"]); + } + node["name"] >> rhs.name; + return true; +} +} diff --git a/companion/src/firmwares/edgetx/yaml_mixdata.h b/companion/src/firmwares/edgetx/yaml_mixdata.h new file mode 100644 index 000000000..0b08702f6 --- /dev/null +++ b/companion/src/firmwares/edgetx/yaml_mixdata.h @@ -0,0 +1,44 @@ +/* + * 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 "mixdata.h" + +int32_t YamlReadMixWeight(const YAML::Node& node); +std::string YamlWriteMixWeight(int32_t sval); + +uint32_t YamlReadFlightModes(const YAML::Node& node); +std::string YamlWriteFlightModes(uint32_t val); + + +namespace YAML +{ +template <> +struct convert { + static Node encode(const CurveReference& rhs); + static bool decode(const Node& node, CurveReference& rhs); +}; + +template <> +struct convert { + static Node encode(const MixData& rhs); + static bool decode(const Node& node, MixData& rhs); +}; +} // namespace YAML diff --git a/companion/src/firmwares/edgetx/yaml_modeldata.cpp b/companion/src/firmwares/edgetx/yaml_modeldata.cpp new file mode 100644 index 000000000..45e5f8a4b --- /dev/null +++ b/companion/src/firmwares/edgetx/yaml_modeldata.cpp @@ -0,0 +1,1069 @@ +/* + * 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_modeldata.h" +#include "yaml_rawswitch.h" +#include "yaml_mixdata.h" +#include "yaml_rawsource.h" +#include "yaml_expodata.h" +#include "yaml_curvedata.h" +#include "yaml_moduledata.h" +#include "yaml_logicalswitchdata.h" +#include "yaml_customfunctiondata.h" +#include "yaml_sensordata.h" +#include "yaml_screendata.h" + +#include "modeldata.h" +#include "output_data.h" +#include "eeprominterface.h" + +#include + +static const YamlLookupTable timerModeLut = { + {TimerData::TIMERMODE_OFF, "OFF"}, + {TimerData::TIMERMODE_ON, "ON"}, + {TimerData::TIMERMODE_START, "START"}, + {TimerData::TIMERMODE_THR, "THR"}, + {TimerData::TIMERMODE_THR_REL, "THR_REL"}, + {TimerData::TIMERMODE_THR_START, "THR_START"}, +}; + +static const YamlLookupTable trainerModeLut = { + { TRAINER_MODE_OFF, "OFF" }, + { TRAINER_MODE_MASTER_JACK, "MASTER_TRAINER_JACK" }, + { TRAINER_MODE_SLAVE_JACK, "SLAVE" }, + { TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE, "MASTER_SBUS_EXT" }, + { TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE, "MASTER_CPPM_EXT" }, + { TRAINER_MODE_MASTER_BATTERY_COMPARTMENT, "MASTER_BATT_COMP" }, + { TRAINER_MODE_MASTER_BLUETOOTH, "MASTER_BT" }, + { TRAINER_MODE_SLAVE_BLUETOOTH, "SLAVE_BT" }, + { TRAINER_MODE_MULTI, "MASTER_MULTI" }, +}; + +static const YamlLookupTable swashTypeLut = { + { 0, "TYPE_NONE" }, + { 1, "TYPE_120" }, + { 2, "TYPE_120X" }, + { 3, "TYPE_140" }, + { 4, "TYPE_90" }, +}; + +static const YamlLookupTable potsWarningModeLut = { + { 0, "WARN_OFF" }, + { 1, "WARN_MANUAL" }, + { 2, "WARN_AUTO" }, +}; + +struct YamlTrim { + int mode = 0; + int ref = 0; + int value = 0; + + YamlTrim() = default; + YamlTrim(int mode, int ref, int value): + mode(mode), ref(ref), value(value) + {} + + bool isEmpty() { return !mode && !ref && !value; } +}; + +struct YamlThrTrace { + RawSource src; + + YamlThrTrace() = default; + + YamlThrTrace(unsigned int cpn_value) + { + if (cpn_value == 0) { + src = RawSource(SOURCE_TYPE_STICK, 2/* throttle */); + return; + } + cpn_value--; + Boards board(getCurrentBoard()); + int pots = board.getCapability(Board::Pots); + int sliders = board.getCapability(Board::Sliders); + if (cpn_value < (unsigned int)(pots + sliders)) { + src = RawSource(SOURCE_TYPE_STICK, 4/* sticks */ + cpn_value); + } + else { + cpn_value -= pots + sliders; + src = RawSource(SOURCE_TYPE_CH, cpn_value); + } + } + + unsigned int toCpn() + { + switch (src.type) { + case SOURCE_TYPE_STICK: + if (src.index == 2 /* throttle */) { + return 0; + } else { + return src.index - 4/* sticks */ + 1; + } + break; + case SOURCE_TYPE_CH: { + Boards board(getCurrentBoard()); + int pots = board.getCapability(Board::Pots); + int sliders = board.getCapability(Board::Sliders); + return pots + sliders + src.index; + } break; + default: + break; + } + return 0; + } +}; + +struct YamlPotsWarnEnabled { + unsigned int value; + + YamlPotsWarnEnabled() = default; + + YamlPotsWarnEnabled(const bool * potsWarnEnabled) + { + value = 0; + + for (int i = 0; i < 8; i++) { + value |= (*(potsWarnEnabled + i) << (7 - i)); + } + } + + void toCpn(bool * potsWarnEnabled) + { + memset(potsWarnEnabled, 0, sizeof(bool) * (CPN_MAX_POTS + CPN_MAX_SLIDERS)); + + for (int i = 1; i <= 8; i++) { + *(potsWarnEnabled + (i - 1)) = (bool)((value >> (8 - i)) & 1); + } + } +}; + +// modeldata: uint64_t switchWarningStates +// Yaml switchWarningState: AuBuEuFuG-IuJu +struct YamlSwitchWarningState { + + static constexpr size_t MASK_LEN = 2; + static constexpr size_t MASK = (1 << MASK_LEN) - 1; + + std::string src_str; + unsigned int enabled; + + YamlSwitchWarningState() = default; + + YamlSwitchWarningState(uint64_t cpn_value, unsigned int switchWarningEnable) + : enabled(~switchWarningEnable) + { + uint64_t states = cpn_value; + + std::stringstream ss; + for (int i = 0; i < Boards::getCapability(getCurrentBoard(), Board::Switches); i++) { + //TODO: exclude 2-pos toggle from switch warnings + if (enabled & (1 << i)) { + std::string tag = getCurrentFirmware()->getSwitchesTag(i); + const char *sw = tag.data(); + + if (tag.size() >= 2 && sw[0] == 'S') { + ss << sw[1]; + switch(states & MASK) { + case 0: + ss << 'u'; + break; + case 1: + ss << '-'; + break; + case 2: + ss << 'd'; + break; + } + } + } + states >>= MASK_LEN; + } + + ss >> src_str; + } + + uint64_t toCpn() + { + uint64_t states = 0; + enabled = 0; + + std::stringstream ss(src_str); + while (!ss.eof()) { + auto c = ss.get(); + if (c < 'A' && c > 'Z') { + ss.ignore(); + continue; + } + + std::string sw = std::string("S") + (char)c; + int index = getCurrentFirmware()->getSwitchesIndex(sw.c_str()); + if (index < 0) { + ss.ignore(); + continue; + } + + auto s = ss.get(); + + int value = 0; + switch(s) { + case 'u': + value = 0; + break; + case '-': + value = 1; + break; + case 'd': + value = 2; + break; + default: + continue; + } + + states |= ((uint64_t)value << (index * MASK_LEN)); + enabled |= (1 << index); + } + + return states; + } +}; + +template <> +void operator >> (const YAML::Node& node, FlightModeData& value) +{ + if (node && !node.IsNull()) { + YAML::convert::decode(node, value); + } +} + +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"] = (int)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; +} + +static int32_t YamlReadLimitValue(const YAML::Node& node, int32_t shift = 0) +{ + std::string val = node.as(); + if ((val.size() >= 4) + && (val[0] == '-') + && (val[1] == 'G') + && (val[2] == 'V') + && (val[3] >= '1') + && (val[3] <= '9')) { + + return -10000 - std::stoi(val.substr(3)); + } + + if ((val.size() >= 3) + && (val[0] == 'G') + && (val[1] == 'V') + && (val[2] >= '1') + && (val[2] <= '9')) { + + return 10000 + std::stoi(val.substr(2)); + } + + try { + return std::stoi(val) + shift; + } catch(...) { + throw YAML::TypedBadConversion(node.Mark()); + } +} + +static std::string YamlWriteLimitValue(int32_t sval, int32_t shift = 0) +{ + if (sval < -10000) { + int n = -sval - 10000; + return std::string("-GV") + std::to_string(n); + } else if (sval > 10000) { + int n = sval - 10000; + return std::string("GV") + std::to_string(n); + } + + return std::to_string(sval - shift); +} + +template <> +struct convert { + static Node encode(const LimitData& rhs) + { + Node node; + node["min"] = YamlWriteLimitValue(rhs.min, -1000); + node["max"] = YamlWriteLimitValue(rhs.max, 1000); + node["revert"] = (int)rhs.revert; + node["offset"] = YamlWriteLimitValue(rhs.offset); + node["ppmCenter"] = rhs.ppmCenter; + node["symetrical"] = (int)rhs.symetrical; + node["failsafe"] = rhs.failsafe; + node["name"] = rhs.name; + node["curve"] = rhs.curve.value; + return node; + } + + static bool decode(const Node& node, LimitData& rhs) + { + if (node["min"]) { + rhs.min = YamlReadLimitValue(node["min"], -1000); + } + if (node["max"]) { + rhs.max = YamlReadLimitValue(node["max"], 1000); + } + if (node["offset"]) { + rhs.offset = YamlReadLimitValue(node["offset"]); + } + node["revert"] >> rhs.revert; + node["ppmCenter"] >> rhs.ppmCenter; + node["symetrical"] >> rhs.symetrical; + node["failsafe"] >> rhs.failsafe; + node["name"] >> rhs.name; + node["curve"] >> rhs.curve.value; + return true; + } +}; + +template <> +struct convert { + static Node encode(const YamlTrim& rhs) + { + Node node; + node["value"] = rhs.value; + if (rhs.mode < 0) { + node["mode"] = -1; + } else { + node["mode"] = 2 * rhs.ref + rhs.mode; + } + return node; + } + static bool decode(const Node& node, YamlTrim& rhs) + { + node["value"] >> rhs.value; + + int trimMode = 0; + node["mode"] >> trimMode; + if (trimMode < 0) { + rhs.mode = trimMode; + } else { + rhs.mode = trimMode % 2; + rhs.ref = trimMode / 2; + } + return true; + } +}; + +Node EncodeFMData(const FlightModeData& rhs, int phaseIdx) +{ + Node node; + + size_t n_trims = Boards::getCapability(getCurrentBoard(), Board::NumTrims); + YamlTrim yt[n_trims]; + + Node trims; + for (size_t i=0; i 0) { + node["swtch"] = rhs.swtch; + } + node["name"] = rhs.name; + node["fadeIn"] = rhs.fadeIn; + node["fadeOut"] = rhs.fadeOut; + + Node gvars; + for (size_t i=0; i::decode(const Node& node, + FlightModeData& rhs) +{ + YamlTrim trims[CPN_MAX_TRIMS]; + node["trim"] >> trims; + for (size_t i = 0; i < CPN_MAX_TRIMS; i++) { + rhs.trimMode[i] = trims[i].mode; + rhs.trimRef[i] = trims[i].ref; + rhs.trim[i] = trims[i].value; + } + node["swtch"] >> rhs.swtch; + node["name"] >> rhs.name; + node["fadeIn"] >> rhs.fadeIn; + node["fadeOut"] >> rhs.fadeOut; + node["gvars"] >> rhs.gvars; + return true; +} + +template <> +struct convert { + static Node encode(const SwashRingData& rhs) + { + Node node; + node["type"] = swashTypeLut << rhs.type; + node["value"] = rhs.value; + node["collectiveSource"] = rhs.collectiveSource; + node["aileronSource"] = rhs.aileronSource; + node["elevatorSource"] = rhs.elevatorSource; + node["collectiveWeight"] = rhs.collectiveWeight; + node["aileronWeight"] = rhs.aileronWeight; + node["elevatorWeight"] = rhs.elevatorWeight; + return node; + } + + static bool decode(const Node& node, SwashRingData& rhs) + { + node["type"] >> swashTypeLut >> rhs.type; + node["value"] >> rhs.value; + node["collectiveSource"] >> rhs.collectiveSource; + node["aileronSource"] >> rhs.aileronSource; + node["elevatorSource"] >> rhs.elevatorSource; + node["collectiveWeight"] >> rhs.collectiveWeight; + node["aileronWeight"] >> rhs.aileronWeight; + node["elevatorWeight"] >> rhs.elevatorWeight; + return true; + } +}; + +template <> +struct convert { + static Node encode(const GVarData& rhs) + { + Node node; + node["name"] = rhs.name; + node["min"] = rhs.min; + node["max"] = rhs.max; + node["popup"] = (int)rhs.popup; + node["prec"] = rhs.prec; + node["unit"] = rhs.unit; + return node; + } + + static bool decode(const Node& node, GVarData& rhs) + { + node["name"] >> rhs.name; + node["min"] >> rhs.min; + node["max"] >> rhs.max; + node["popup"] >> rhs.popup; + node["prec"] >> rhs.prec; + node["unit"] >> rhs.unit; + return true; + } +}; + +struct YamlScriptDataInput { int i; }; + +template <> +struct convert { + static Node encode(const YamlScriptDataInput& rhs) + { + Node node; + node["u"]["value"] = rhs.i; + return node; + } + static bool decode(const Node& node, YamlScriptDataInput& rhs) + { + node["u"]["value"] >> rhs.i; + return true; + } +}; + +template <> +struct convert { + static Node encode(const ScriptData& rhs) + { + Node node; + node["file"] = rhs.filename; + node["name"] = rhs.name; + + for (int i=0; i < 6; i++) { + node["inputs"][std::to_string(i)]["u"]["value"] = (int)rhs.inputs[i]; + } + + return node; + } + + static bool decode(const Node& node, ScriptData& rhs) + { + node["file"] >> rhs.filename; + node["name"] >> rhs.name; + + YamlScriptDataInput inputs[CPN_MAX_SCRIPT_INPUTS]; + node["inputs"] >> inputs; + + for (int i=0; i < CPN_MAX_SCRIPT_INPUTS; i++) { + rhs.inputs[i] = inputs[i].i; + } + + return true; + } +}; + +template <> +struct convert { + static Node encode(const RSSIAlarmData& rhs) + { + Node node; + node["disabled"] = (int)rhs.disabled; + node["warning"] = rhs.warning - 45; + node["critical"] = rhs.critical - 42; + return node; + } + + static bool decode(const Node& node, RSSIAlarmData& rhs) + { + node["disabled"] >> rhs.disabled; + node["warning"] >> rhs.warning; + rhs.warning += 45; + node["critical"] >> rhs.critical; + rhs.critical += 42; + return true; + } +}; + +struct YamlTelemSource { + unsigned int src = 0; + YamlTelemSource() = default; + YamlTelemSource(const unsigned int src) : src(src) {} +}; + +template <> +struct convert { + static Node encode(const YamlTelemSource& rhs) + { + if (rhs.src == 0) + return Node("none"); + return Node(rhs.src - 1); + } + + static bool decode(const Node& node, YamlTelemSource& rhs) + { + if (node && node.IsScalar()) { + std::string str = node.Scalar(); + if (str == "none") { + rhs.src = 0; + } else { + try { + rhs.src = std::stoi(str) + 1; + } catch(...) {} + } + } + return true; + } +}; + +template <> +struct convert { + static Node encode(const FrSkyBarData& rhs) + { + Node node; + if (rhs.source.isSet()) { + node["source"] = rhs.source; + node["barMin"] = rhs.barMin; + node["barMax"] = rhs.barMax; + } + return node; + } + + static bool decode(const Node& node, FrSkyBarData& rhs) + { + node["source"] >> rhs.source; + node["barMin"] >> rhs.barMin; + node["barMax"] >> rhs.barMax; + return true; + } +}; + +template <> +struct convert { + static Node encode(const FrSkyLineData& rhs) + { + Node node, sources; + sources = encode_array(rhs.source); + if (sources && sources.IsMap()) { + node["sources"] = sources; + } + return node; + } + + static bool decode(const Node& node, FrSkyLineData& rhs) + { + node["sources"] >> rhs.source; + return true; + } +}; + +static const YamlLookupTable screenTypeLut = { + {TELEMETRY_SCREEN_NONE, "NONE"}, + {TELEMETRY_SCREEN_NUMBERS, "VALUES"}, + {TELEMETRY_SCREEN_BARS, "BARS"}, + {TELEMETRY_SCREEN_SCRIPT, "SCRIPT"}, +}; + +template <> +struct convert { + static Node encode(const FrSkyScreenData& rhs) + { + Node node; + node["type"] = LookupValue(screenTypeLut, rhs.type); + switch(rhs.type) { + case TELEMETRY_SCREEN_NONE: + break; + case TELEMETRY_SCREEN_NUMBERS: + node["lines"] = encode_array(rhs.body.lines); + break; + case TELEMETRY_SCREEN_BARS: + node["bars"] = encode_array(rhs.body.bars); + break; + case TELEMETRY_SCREEN_SCRIPT: + node["script"]["file"] = rhs.body.script.filename; + break; + } + return node; + } + + static bool decode(const Node& node, FrSkyScreenData& rhs) + { + node["type"] >> screenTypeLut >> rhs.type; + switch(rhs.type) { + case TELEMETRY_SCREEN_NONE: + return true; + case TELEMETRY_SCREEN_NUMBERS: + node["lines"] >> rhs.body.lines; + break; + case TELEMETRY_SCREEN_BARS: + node["bars"] >> rhs.body.bars; + break; + case TELEMETRY_SCREEN_SCRIPT: + if (node["script"]) { + const auto& script = node["script"]; + if (script && script.IsMap()) { + script["file"] >> rhs.body.script.filename; + } + } + break; + } + return true; + } +}; + +Node convert::encode(const ModelData& rhs) +{ + Node node; + auto board = getCurrentBoard(); + + Node header; + header["name"] = rhs.name; + header["bitmap"] = rhs.bitmap; + + for (int i=0; i inputs; + for (int i = 0; i < CPN_MAX_EXPOS; i++) { + const ExpoData& expo = rhs.expoData[i]; + if (!expo.isEmpty()) { + Node expoNode; + expoNode = expo; + node["expoData"].push_back(expoNode); + inputs.insert(expo.chn); + } + } + + for (auto input : inputs) { + if (rhs.inputNames[input][0]) { + node["inputNames"][std::to_string(input)]["val"] = rhs.inputNames[input]; + } + } + + for (int i = 0; i < CPN_MAX_CURVES; i++) { + const CurveData& curve = rhs.curves[i]; + if (!curve.isEmpty()) { + node["curves"][std::to_string(i)] = curve; + } + } + + YAML::Node points; + YamlWriteCurvePoints(points, rhs.curves); + if (points && (points.IsMap() || points.IsSequence())) { + node["points"] = points; + } + + for (int i = 0; i < CPN_MAX_LOGICAL_SWITCHES; i++) { + const LogicalSwitchData& ls = rhs.logicalSw[i]; + if (!ls.isEmpty()) { + node["logicalSw"][std::to_string(i)] = ls; + } + } + + for (int i = 0; i < CPN_MAX_SPECIAL_FUNCTIONS; i++) { + const CustomFunctionData& fn = rhs.customFn[i]; + if (!fn.isEmpty()) { + node["customFn"][std::to_string(i)] = fn; + } + } + + if (getCurrentFirmware()->getCapability(Heli)) + node["swashR"] = rhs.swashRingData; + + YamlThrTrace thrTrace(rhs.thrTraceSrc); + node["thrTraceSrc"] = thrTrace.src; + + YamlSwitchWarningState switchWarningState(rhs.switchWarningStates, rhs.switchWarningEnable); + node["switchWarningState"] = switchWarningState.src_str; + + node["thrTrimSw"] = rhs.thrTrimSwitch; + node["potsWarnMode"] = potsWarningModeLut << rhs.potsWarningMode; + + YamlPotsWarnEnabled potsWarnEnabled(&rhs.potsWarnEnabled[CPN_MAX_POTS + CPN_MAX_SLIDERS]); + node["potsWarnEnabled"] = potsWarnEnabled.value; + + for (int i = 0; i < CPN_MAX_POTS + CPN_MAX_SLIDERS; i++) { + if (rhs.potsWarnPosition[i] != 0) + node["potsWarnPosition"][std::to_string(i)]["val"] = rhs.potsWarnPosition[i]; + } + + node["displayChecklist"] = (int)rhs.displayChecklist; + + for (int i = 0; i < CPN_MAX_GVARS; i++) { + const GVarData& gv = rhs.gvarData[i]; + if (!gv.isEmpty()) { + node["gvars"][std::to_string(i)] = gv; + } + } + + // mavlink ??? + + node["telemetryProtocol"] = rhs.telemetryProtocol; + + if (!IS_FAMILY_HORUS_OR_T16(board)) { + Node screens; + for (int i=0; i<4; i++) { + const auto& scr = rhs.frsky.screens[i]; + if (scr.type != TELEMETRY_SCREEN_NONE) { + screens[std::to_string(i)] = rhs.frsky.screens[i]; + } + } + if (screens.IsMap()) { + node["screens"] = screens; + } + } + + Node vario; + vario["source"] = YamlTelemSource(rhs.frsky.varioSource); + vario["centerSilent"] = (int)rhs.frsky.varioCenterSilent; + vario["centerMax"] = rhs.frsky.varioCenterMax; + vario["centerMin"] = rhs.frsky.varioCenterMin; + vario["min"] = rhs.frsky.varioMin; + vario["max"] = rhs.frsky.varioMax; + + node["varioData"] = vario; + node["rssiSource"] = YamlTelemSource(rhs.rssiSource); + + if (IS_TARANIS_X9(getCurrentBoard())) { + node["voltsSource"] = YamlTelemSource(rhs.frsky.voltsSource); + node["altitudeSource"] = YamlTelemSource(rhs.frsky.altitudeSource); + } + + node["rssiAlarms"] = rhs.rssiAlarms; + node["trainerMode"] = trainerModeLut << rhs.trainerMode; + + for (int i=0; i 0) { + node["scriptData"][std::to_string(i)] = rhs.scriptData[i]; + } + } + + for (int i=0; igetCapability(FunctionSwitches)) { + node["functionSwitchConfig"] = rhs.functionSwitchConfig; + node["functionSwitchGroup"] = rhs.functionSwitchGroup; + node["functionSwitchStartConfig"] = rhs.functionSwitchStartConfig; + node["functionSwitchLogicalState"] = rhs.functionSwitchLogicalState; + + for (int i = 0; i < CPN_MAX_FUNCTION_SWITCHES; i++) { + if (strlen(rhs.functionSwitchNames[i]) > 0) { + node["functionSwitchNames"][std::to_string(i)] = + rhs.functionSwitchNames[i]; + } + } + } + + return node; +} + +bool convert::decode(const Node& node, ModelData& rhs) +{ + if (!node.IsMap()) return false; + + unsigned int modelIds[CPN_MAX_MODULES]; + memset(modelIds, 0, sizeof(modelIds)); + + if (node["header"]) { + const auto& header = node["header"]; + if (header.IsMap()) { + header["name"] >> rhs.name; + header["bitmap"] >> rhs.bitmap; + header["modelId"] >> modelIds; + } + } + + 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["beepANACenter"] >> rhs.beepANACenter; + node["extendedLimits"] >> rhs.extendedLimits; + node["extendedTrims"] >> rhs.extendedTrims; + node["throttleReversed"] >> rhs.throttleReversed; + + node["flightModeData"] >> rhs.flightModeData; + node["mixData"] >> rhs.mixData; + node["limitData"] >> rhs.limitData; + + node["inputNames"] >> rhs.inputNames; + node["expoData"] >> rhs.expoData; + + node["curves"] >> rhs.curves; + if (node["points"]) + YamlReadCurvePoints(node["points"], rhs.curves); + + node["logicalSw"] >> rhs.logicalSw; + node["customFn"] >> rhs.customFn; + + if (node["swashR"]) { + const auto& swashR = node["swashR"]; + if (!swashR.IsMap()) return false; + swashR >> rhs.swashRingData; + } + + YamlThrTrace thrTrace; + node["thrTraceSrc"] >> thrTrace.src; + rhs.thrTraceSrc = thrTrace.toCpn(); + + YamlSwitchWarningState switchWarningState; + node["switchWarningState"] >> switchWarningState.src_str; + rhs.switchWarningStates = switchWarningState.toCpn(); + rhs.switchWarningEnable = ~switchWarningState.enabled; + + node["thrTrimSw"] >> rhs.thrTrimSwitch; + node["potsWarnMode"] >> potsWarningModeLut >> rhs.potsWarningMode; + + YamlPotsWarnEnabled potsWarnEnabled; + node["potsWarnEnabled"] >> potsWarnEnabled.value; + potsWarnEnabled.toCpn(&rhs.potsWarnEnabled[CPN_MAX_POTS + CPN_MAX_SLIDERS]); + + node["potsWarnPosition"] >> rhs.potsWarnPosition; + + node["displayChecklist"] >> rhs.displayChecklist; + + node["gvars"] >> rhs.gvarData; + + // mavlink ??? + + node["telemetryProtocol"] >> rhs.telemetryProtocol; + + // frsky + if (node["screens"]) { + node["screens"] >> rhs.frsky.screens; + } + + if (node["varioData"]) { + const auto& vario = node["varioData"]; + + YamlTelemSource varioSrc; + vario["source"] >> varioSrc; + rhs.frsky.varioSource = varioSrc.src; + + vario["centerSilent"] >> rhs.frsky.varioCenterSilent; + vario["centerMax"] >> rhs.frsky.varioCenterMax; + vario["centerMin"] >> rhs.frsky.varioCenterMin; + vario["min"] >> rhs.frsky.varioMin; + vario["max"] >> rhs.frsky.varioMax; + } + + if (node["rssiSource"]) { + YamlTelemSource rssiSource; + node["rssiSource"] >> rssiSource; + rhs.rssiSource = rssiSource.src; + } + + if (node["voltsSource"]) { + YamlTelemSource voltsSource; + node["voltsSource"] >> voltsSource; + rhs.frsky.voltsSource = voltsSource.src; + } + + if (node["altitudeSource"]) { + YamlTelemSource altitudeSource; + node["altitudeSource"] >> altitudeSource; + rhs.frsky.altitudeSource = altitudeSource.src; + } + + node["rssiAlarms"] >> rhs.rssiAlarms; + node["trainerMode"] >> trainerModeLut >> rhs.trainerMode; + + node["moduleData"] >> rhs.moduleData; + for (int i=0; i> rhs.scriptData; + node["telemetrySensors"] >> rhs.sensorData; + + node["toplcdTimer"] >> rhs.toplcdTimer; + + node["screenData"] >> rhs.customScreens.customScreenData; + node["topbarData"] >> rhs.topBarData; + + node["view"] >> rhs.view; + node["modelRegistrationID"] >> rhs.registrationId; + + node["functionSwitchConfig"] >> rhs.functionSwitchConfig; + node["functionSwitchGroup"] >> rhs.functionSwitchGroup; + node["functionSwitchStartConfig"] >> rhs.functionSwitchStartConfig; + node["functionSwitchLogicalState"] >> rhs.functionSwitchLogicalState; + node["functionSwitchNames"] >> rhs.functionSwitchNames; + + return true; +} + +} // namespace YAML diff --git a/companion/src/firmwares/edgetx/yaml_modeldata.h b/companion/src/firmwares/edgetx/yaml_modeldata.h new file mode 100644 index 000000000..c3355c113 --- /dev/null +++ b/companion/src/firmwares/edgetx/yaml_modeldata.h @@ -0,0 +1,42 @@ +/* + * 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 "modeldata.h" + +namespace YAML { + +template <> +struct convert { + static Node encode(const TimerData& rhs); + static bool decode(const Node& node, TimerData& rhs); +}; + +template <> +struct convert { + static bool decode(const Node& node, FlightModeData& rhs); +}; + +template <> +struct convert { + static Node encode(const ModelData& rhs); + static bool decode(const Node& node, ModelData& rhs); +}; +} // namespace YAML diff --git a/companion/src/firmwares/edgetx/yaml_moduledata.cpp b/companion/src/firmwares/edgetx/yaml_moduledata.cpp new file mode 100644 index 000000000..a6c84d8d5 --- /dev/null +++ b/companion/src/firmwares/edgetx/yaml_moduledata.cpp @@ -0,0 +1,396 @@ +/* + * 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; + } +} + +static int exportPpmDelay(int delay) { return (delay - 300) / 50; } +static int importPpmDelay(int delay) { return 300 + 50 * delay; } + +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<(int)rhs.access.receivers; i++) { + pxx2["receiverName"][std::to_string(i)] = rhs.access.receiverName[i]; + } + mod["pxx2"] = pxx2; + } break; + case PULSES_MULTIMODULE: { + Node multi;; + multi["disableTelemetry"] = (int)rhs.multi.disableTelemetry; + multi["disableMapping"] = (int)rhs.multi.disableMapping; + multi["autoBindMode"] = (int)rhs.multi.autoBindMode; + multi["lowPowerMode"] = (int)rhs.multi.lowPowerMode; + multi["optionValue"] = rhs.multi.optionValue; + // multi["receiverTelemetryOff"] = (int)rhs.pxx.receiverTelemetryOff; + // multi["receiverHigherChannels"] = (int)rhs.pxx.receiverHigherChannels; + mod["multi"] = multi; + } break; + case PULSES_SBUS: { + Node sbus; + sbus["refreshRate"] = rhs.ppm.frameLength; + mod["sbus"] = sbus; + } break; + // TODO: afhds3, flysky + default: { + Node ppm; + ppm["delay"] = exportPpmDelay(rhs.ppm.delay); + ppm["pulsePol"] = (int)rhs.ppm.pulsePol; + ppm["outputType"] = (int)rhs.ppm.outputType; + ppm["frameLength"] = rhs.ppm.frameLength; + mod["ppm"] = ppm; + } break; + } + if (mod && mod.IsMap()) + node["mod"] = mod; + + return node; +} + +bool convert::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; + try { + 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; + } + } catch(...) {} + } + } break; + } + + node["channelsStart"] >> rhs.channelsStart; + node["channelsCount"] >> rhs.channelsCount; + node["failsafeMode"] >> failsafeLut >> rhs.failsafeMode; + + if (node["mod"]) { + const Node& mod = node["mod"]; + if (mod["ppm"]) { + const Node& ppm = mod["ppm"]; + ppm["delay"] >> rhs.ppm.delay; + rhs.ppm.delay = importPpmDelay(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 diff --git a/companion/src/firmwares/edgetx/yaml_ops.cpp b/companion/src/firmwares/edgetx/yaml_ops.cpp new file mode 100644 index 000000000..c89aaea89 --- /dev/null +++ b/companion/src/firmwares/edgetx/yaml_ops.cpp @@ -0,0 +1,83 @@ +/* + * 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" + +YAML::Node operator >> (const YAML::Node& node, const YamlLookupTable& lut) +{ + if (node && node.IsScalar()) { + std::string str = node.as(); + const auto& it = + find_if(lut.begin(), lut.end(), [=](const YamlLookupTableElmt& elmt) { + if (elmt.second == str) return true; + return false; + }); + + if (it != lut.end()) { + return YAML::Node(it->first); + } + return YAML::Node(); + } + + return node; +} + +void operator >> (const YAML::Node& node, const ioffset_int& value) +{ + if (node && node.IsScalar()) { + value.assign(node.as()); + } +} + +template <> +void operator >> (const YAML::Node& node, bool& value) +{ + if (node && node.IsScalar()) { + value = node.as(); + } +} + +namespace YAML { + +std::string LookupValue(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 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 new file mode 100644 index 000000000..539db8b96 --- /dev/null +++ b/companion/src/firmwares/edgetx/yaml_ops.h @@ -0,0 +1,173 @@ +/* + * 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. + */ + +#pragma once + +#include +#include +#include + +typedef std::pair YamlLookupTableElmt; +typedef std::vector YamlLookupTable; + +class ioffset_int { + +public: + ioffset_int(int& val, int offset) + : value(val), offset(offset) + {} + + void assign(int newValue) const { + value = newValue - offset; + } + +private: + int& value; + int offset; +}; + +template +class ifactor { + +public: + ifactor(T& val, int factor) + : value(val), factor(factor) + {} + + void assign(T newValue) const { + value = newValue / factor; + } + +private: + T& value; + T factor; +}; + +YAML::Node operator >> (const YAML::Node& node, const YamlLookupTable& lut); +void operator >> (const YAML::Node& node, const ioffset_int& value); + +template +void operator >> (const YAML::Node& node, const ifactor& value) +{ + if (node && node.IsScalar()) { + value.assign(node.as()); + } +} + +template +void operator >> (const YAML::Node& node, T& value) +{ + if (node && !node.IsNull()) { + value = node.as(); + } +} + +// type specialisation +template <> void operator >> (const YAML::Node& node, bool& value); + +template +void operator >> (const YAML::Node& node, char (&value)[N]) +{ + if (node && node.IsScalar()) { + auto str = node.as(); + str.copy(value, N-1); + value[std::min(str.size(), N-1)] = '\0'; + } +} + +template +void operator>>(const YAML::Node& node, T (&value)[N]) +{ + if (!node) return; + if (node.IsMap()) { + for (const auto& elmt : node) { + int idx = -1; + try { + idx = std::stoi(elmt.first.Scalar()); + } catch (...) { + } + if (idx < 0 || idx >= (int)N) continue; + + if (elmt.second.IsMap() && (elmt.second.size() == 1) && + elmt.second["val"]) { + elmt.second["val"] >> value[idx]; + } else { + elmt.second >> value[idx]; + } + } + } else if (node.IsSequence()) { + int idx = 0; + for (const auto& elmt : node) { + elmt >> value[idx]; + idx++; + } + } +} + +namespace YAML { + +std::string LookupValue(const YamlLookupTable& lut, const int& value); +Node operator << (const YamlLookupTable& lut, const int& value); + +template +Node encode_array(const T (&rhs)[N]) +{ + Node node; + for (size_t i = 0; i < N; i++) { + Node elmt; + elmt = rhs[i]; + node.push_back(elmt); + } + return node; +} + +template +struct convert_enum +{ + static YAML::Node encode(const YamlLookupTable& lut, const T& rhs) + { + return lut << rhs; + } + static bool decode(const YAML::Node& node, const YamlLookupTable& lut, 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(lut,rhs); \ + } \ + static bool decode(const YAML::Node& node, enum_type& rhs) \ + { \ + return convert_enum::decode(node, lut, rhs); \ + } \ + } diff --git a/companion/src/firmwares/edgetx/yaml_rawsource.cpp b/companion/src/firmwares/edgetx/yaml_rawsource.cpp new file mode 100644 index 000000000..4d8e98cfd --- /dev/null +++ b/companion/src/firmwares/edgetx/yaml_rawsource.cpp @@ -0,0 +1,254 @@ +/* + * 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_rawsource.h" +#include "eeprominterface.h" + +std::string YamlRawSourceEncode(const RawSource& rhs) +{ + std::string src_str; + switch (rhs.type) { + case SOURCE_TYPE_VIRTUAL_INPUT: + src_str += "I" + std::to_string(rhs.index); + break; + case SOURCE_TYPE_LUA_OUTPUT: + src_str += "lua("; + src_str += std::to_string(rhs.index / 16); + src_str += ","; + src_str += std::to_string(rhs.index % 16); + src_str += ")"; + break; + case SOURCE_TYPE_STICK: + src_str = getCurrentFirmware()->getAnalogInputTag(rhs.index); + break; + case SOURCE_TYPE_TRIM: + src_str = getCurrentFirmware()->getTrimSourcesTag(rhs.index); + break; + case SOURCE_TYPE_MAX: + src_str += "MAX"; + break; + case SOURCE_TYPE_SWITCH: + src_str += "S"; + src_str += (rhs.index + 'A'); + break; + case SOURCE_TYPE_CUSTOM_SWITCH: + src_str += "ls("; + src_str += std::to_string(rhs.index); + src_str += ")"; + break; + case SOURCE_TYPE_CYC: + src_str = getCurrentFirmware()->getRawSourceCyclicTag(rhs.index); + break; + case SOURCE_TYPE_PPM: + src_str += "tr("; + src_str += std::to_string(rhs.index); + src_str += ")"; + break; + case SOURCE_TYPE_CH: + src_str += "ch("; + src_str += std::to_string(rhs.index); + src_str += ")"; + break; + case SOURCE_TYPE_GVAR: + src_str += "gv("; + src_str += std::to_string(rhs.index); + src_str += ")"; + break; + case SOURCE_TYPE_SPECIAL: + src_str = getCurrentFirmware()->getRawSourceSpecialTypesTag(rhs.index); + break; + case SOURCE_TYPE_TELEMETRY: + src_str = "tele("; + switch (rhs.index % 3) { + case 0: + break; + case 1: + src_str += '-'; + break; + case 2: + src_str += '+'; + break; + } + src_str += std::to_string(rhs.index / 3); + src_str += ")"; + break; + default: + src_str = "NONE"; + break; + } + return src_str; +} + +RawSource YamlRawSourceDecode(const std::string& src_str) +{ + RawSource rhs; + const char* val = src_str.data(); + size_t val_len = src_str.size(); + + if (val_len > 1 && val[0] == 'I' + && (val[1] >= '0') && (val[1] <= '9')) { + + int idx = std::stoi(src_str.substr(1)); + if (idx < CPN_MAX_INPUTS) { + rhs = RawSource(SOURCE_TYPE_VIRTUAL_INPUT, idx); + } + } else if (val_len >= 2 + && val[0] == 'S' + && val[1] >= 'A' + && val[1] <= 'Z') { + + int idx = val[1] - 'A'; + if (idx < CPN_MAX_SWITCHES) + rhs = RawSource(SOURCE_TYPE_SWITCH, idx); + + } else if (val_len > 4 && + val[0] == 'l' && + val[1] == 'u' && + val[2] == 'a' && + val[3] == '(') { + + std::stringstream src(src_str.substr(4)); + int script = 0, output = 0; // TODO: check rename outputs to inputs??? + src >> script; + src.ignore(); + src >> output; + if (script < CPN_MAX_SCRIPTS && output < CPN_MAX_SCRIPT_INPUTS) + rhs = RawSource(SOURCE_TYPE_LUA_OUTPUT, script * 16 + output); + + } else if (val_len > 3 && + val[0] == 'l' && + val[1] == 's' && + val[2] == '(') { + + std::stringstream src(src_str.substr(3)); + int ls = 0; + src >> ls; + if (ls < CPN_MAX_LOGICAL_SWITCHES) + rhs = RawSource(SOURCE_TYPE_CUSTOM_SWITCH, ls); + + } else if (val_len > 3 && + val[0] == 't' && + val[1] == 'r' && + val[2] == '(') { + + std::stringstream src(src_str.substr(3)); + int tr = 0; + src >> tr; + if (tr < getCurrentFirmware()->getCapability(TrainerInputs)) + rhs = RawSource(SOURCE_TYPE_PPM, tr); + + } else if (val_len > 3 && + val[0] == 'c' && + val[1] == 'h' && + val[2] == '(') { + + std::stringstream src(src_str.substr(3)); + int ch = 0; + src >> ch; + if (ch < CPN_MAX_CHNOUT) + rhs = RawSource(SOURCE_TYPE_CH, ch); + + } else if (val_len > 3 && + val[0] == 'g' && + val[1] == 'v' && + val[2] == '(') { + + std::stringstream src(src_str.substr(3)); + int gv = 0; + src >> gv; + if (gv < CPN_MAX_GVARS) + rhs = RawSource(SOURCE_TYPE_GVAR, gv); + + } else if (val_len > 5 && + val[0] == 't' && + val[1] == 'e' && + val[2] == 'l' && + val[3] == 'e' && + val[4] == '(') { + + std::stringstream src(src_str.substr(5)); + + // parse sign + uint8_t sign = 0; + char c = src.peek(); + if (c == '-') { + sign = 1; + src.ignore(); + } else if (c == '+') { + sign = 2; + src.ignore(); + } + + int sensor = 0; + src >> sensor; + if (sensor < CPN_MAX_SENSORS) + rhs = RawSource(SOURCE_TYPE_TELEMETRY, sensor * 3 + sign); + + } else { + + YAML::Node node(src_str); + std::string ana_str; + node >> ana_str; + int ana_idx = getCurrentFirmware()->getAnalogInputIndex(ana_str.c_str()); + if (ana_idx >= 0) { + rhs.type = SOURCE_TYPE_STICK; + rhs.index = ana_idx; + } + + int trm_idx = getCurrentFirmware()->getTrimSourcesIndex(src_str.c_str()); + if (trm_idx >= 0) { + rhs.type = SOURCE_TYPE_TRIM; + rhs.index = trm_idx; + } + + int cyc_idx = getCurrentFirmware()->getRawSourceCyclicIndex(src_str.c_str()); + if (cyc_idx >= 0) { + rhs.type = SOURCE_TYPE_CYC; + rhs.index = cyc_idx; + } + + int sp_idx = getCurrentFirmware()->getRawSourceSpecialTypesIndex(src_str.c_str()); + if (sp_idx >= 0) { + rhs.type = SOURCE_TYPE_SPECIAL; + rhs.index = sp_idx; + } + + if (node.IsScalar() && node.as() == "MAX") { + rhs.type = SOURCE_TYPE_MAX; + rhs.index = 0; + } + } + + return rhs; +} + +namespace YAML { +Node convert::encode(const RawSource& rhs) +{ + return Node(YamlRawSourceEncode(rhs)); +} + +bool convert::decode(const Node& node, RawSource& rhs) +{ + std::string src_str = node.Scalar(); + rhs = YamlRawSourceDecode(src_str); + return true; +} +} // namespace YAML diff --git a/companion/src/firmwares/edgetx/yaml_rawsource.h b/companion/src/firmwares/edgetx/yaml_rawsource.h new file mode 100644 index 000000000..9775793b5 --- /dev/null +++ b/companion/src/firmwares/edgetx/yaml_rawsource.h @@ -0,0 +1,33 @@ +/* + * 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 "rawsource.h" + +std::string YamlRawSourceEncode(const RawSource& rhs); +RawSource YamlRawSourceDecode(const std::string& src_str); + +namespace YAML { +template <> +struct convert { + static Node encode(const RawSource& rhs); + static bool decode(const Node& node, RawSource& rhs); +}; +} diff --git a/companion/src/firmwares/edgetx/yaml_rawswitch.cpp b/companion/src/firmwares/edgetx/yaml_rawswitch.cpp new file mode 100644 index 000000000..34ae49321 --- /dev/null +++ b/companion/src/firmwares/edgetx/yaml_rawswitch.cpp @@ -0,0 +1,178 @@ +/* + * 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_rawswitch.h" +#include "eeprominterface.h" + +std::string YamlRawSwitchEncode(const RawSwitch& rhs) +{ + std::string sw_str; + int32_t sval = rhs.index; + if (rhs.index < 0) { + sval = -sval; + sw_str += "!"; + } + + int multiposcnt = Boards::getCapability(getCurrentBoard(), Board::MultiposPotsPositions); + + switch (rhs.type) { + case SWITCH_TYPE_SWITCH: + sw_str += getCurrentFirmware()->getSwitchesTag((sval - 1) / 3); + sw_str += std::to_string((sval - 1) % 3); + break; + + case SWITCH_TYPE_VIRTUAL: + sw_str += "L"; + sw_str += std::to_string(sval); + break; + + case SWITCH_TYPE_MULTIPOS_POT: + sw_str += "6P"; + sw_str += std::to_string(sval / multiposcnt); + sw_str += std::to_string(sval % multiposcnt); + break; + + case SWITCH_TYPE_TRIM: + sw_str += getCurrentFirmware()->getTrimSwitchesTag(sval); + break; + + case SWITCH_TYPE_FLIGHT_MODE: + sw_str += "FM"; + sw_str += std::to_string(sval - 1); + break; + + case SWITCH_TYPE_SENSOR: + sw_str += "T"; + sw_str += std::to_string(sval + 1); + break; + + case SWITCH_TYPE_TIMER_MODE: + // TODO: check as it appears to be depreciated as not in RawSwitch data model and not in radio yaml export + break; + + default: + sw_str += getCurrentFirmware()->getRawSwitchTypesTag(rhs.type); + break; + } + return sw_str; +} + +RawSwitch YamlRawSwitchDecode(const std::string& sw_str) +{ + RawSwitch rhs; // constructor sets to SWITCH_TYPE_NONE + const char* val = sw_str.data(); + size_t val_len = sw_str.size(); + std::string sw_str_tmp = sw_str; + + // yaml-cpp does not escape this + if (val_len > 0 && val[0] == '\\') { + val++; val_len--; + sw_str_tmp = sw_str_tmp.substr(1); + } + + bool neg = false; + if (val_len > 0 && val[0] == '!') { + neg = true; + val++; + val_len--; + sw_str_tmp = sw_str_tmp.substr(1); + } + + int multiposcnt = Boards::getCapability(getCurrentBoard(), Board::MultiposPotsPositions); + + // TODO: validate all expected numeric chars are numeric not just first + + if (val_len >= 2 && val[0] == 'L' && (val[1] >= '0' && val[1] <= '9')) { + + int sw_idx = std::stoi(sw_str_tmp.substr(1, val_len - 1)); + if (sw_idx < CPN_MAX_LOGICAL_SWITCHES) { + rhs = RawSwitch(SWITCH_TYPE_VIRTUAL, sw_idx); + } + + } else if (val_len > 3 && val[0] == '6' && val[1] == 'P' && + (val[2] >= '0' && val[2] <= '9') && + (val[3] >= '0' && val[3] < (multiposcnt + '0'))) { + + rhs = RawSwitch(SWITCH_TYPE_MULTIPOS_POT, + (val[2] - '0') * multiposcnt + (val[3] - '0')); + + } else if (val_len == 3 && val[0] == 'F' && val[1] == 'M' && + (val[2] >= '0' && val[2] <= '9')) { + + rhs = RawSwitch(SWITCH_TYPE_FLIGHT_MODE, val[2] - '0' + 1); + + } else if (val_len >= 2 && val[0] == 'T' && + (val[1] >= '0' && val[1] <= '9')) { + + // starts at T1 + int sensor_idx = std::stoi(sw_str_tmp.substr(1, val_len - 1)); + if ((sensor_idx > 0) && (sensor_idx < CPN_MAX_SENSORS)) { + rhs = RawSwitch(SWITCH_TYPE_SENSOR, sensor_idx - 1); + } + + } else if (sw_str_tmp.substr(0, 4) == std::string("Trim")) { + + int tsw_idx = getCurrentFirmware()->getTrimSwitchesIndex(sw_str_tmp.c_str()); + if (tsw_idx >= 0) { + rhs.type = SWITCH_TYPE_TRIM; + rhs.index = tsw_idx; + } + + } else if (val_len >= 3 && val[0] == 'S' && + (val[1] >= 'A' && val[1] <= 'Z') && + (val[2] >= '0' && val[2] <= '2')) { + + int sw_idx = getCurrentFirmware()->getSwitchesIndex(sw_str_tmp.substr(0, 2).c_str()); + if (sw_idx >= 0) { + rhs.type = SWITCH_TYPE_SWITCH; + rhs.index = sw_idx * 3 + (val[2] - '0' + 1); + } + + // TODO: SWITCH_TYPE_TIMER_MODE + // check as it appears to be depreciated as not in RawSwitch data model and not in radio yaml export + + } else { + // types which do not use index + int sw_type = getCurrentFirmware()->getRawSwitchTypesIndex(sw_str_tmp.c_str()); + if (sw_type >= 0) { + rhs.type = (RawSwitchType)sw_type; + rhs.index = 0; + } + } + + if (neg) { + rhs.index = -rhs.index; + } + return rhs; +} + +namespace YAML { + +Node convert::encode(const RawSwitch& rhs) +{ + return Node(YamlRawSwitchEncode(rhs)); +} + +bool convert::decode(const Node& node, RawSwitch& rhs) +{ + rhs = YamlRawSwitchDecode(node.Scalar()); + return true; +} +} // namespace YAML diff --git a/companion/src/firmwares/edgetx/yaml_rawswitch.h b/companion/src/firmwares/edgetx/yaml_rawswitch.h new file mode 100644 index 000000000..fa0a824a1 --- /dev/null +++ b/companion/src/firmwares/edgetx/yaml_rawswitch.h @@ -0,0 +1,35 @@ +/* + * 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 "rawswitch.h" + +std::string YamlRawSwitchEncode(const RawSwitch& rhs); +RawSwitch YamlRawSwitchDecode(const std::string& sw_str); + +namespace YAML { + +template <> +struct convert { + static Node encode(const RawSwitch& rhs); + static bool decode(const Node& node, RawSwitch& rhs); +}; + +} diff --git a/companion/src/firmwares/edgetx/yaml_screendata.cpp b/companion/src/firmwares/edgetx/yaml_screendata.cpp new file mode 100644 index 000000000..d4d8c2852 --- /dev/null +++ b/companion/src/firmwares/edgetx/yaml_screendata.cpp @@ -0,0 +1,145 @@ +/* + * 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_screendata.h" +#include "yaml_rawsource.h" +#include "yaml_ops.h" + +#include +#include + +static const YamlLookupTable zoneOptionValueEnum = { + {ZOV_Unsigned, "Unsigned"}, {ZOV_Signed, "Signed"}, {ZOV_Bool, "Bool"}, + {ZOV_String, "String"}, {ZOV_Source, "Source"}, {ZOV_Color, "Color"}, +}; + +std::string color_to_hex( unsigned int i ) +{ + std::stringstream stream; + stream << "0x" + << std::setfill ('0') << std::setw(6) + << std::hex << i; + return stream.str(); +} + +namespace YAML +{ +ENUM_CONVERTER(ZoneOptionValueEnum, zoneOptionValueEnum); + +Node convert::encode(const ZoneOptionValueTyped& rhs) +{ + Node node, value; + node["type"] = rhs.type; + + switch (rhs.type) { + case ZOV_Unsigned: + value["unsignedValue"] = rhs.value.unsignedValue; + break; + case ZOV_Signed: + value["signedValue"] = rhs.value.signedValue; + break; + case ZOV_Bool: + value["boolValue"] = rhs.value.boolValue; + break; + case ZOV_Source: + value["source"] = rhs.value.sourceValue; + break; + case ZOV_Color: + value["color"] = color_to_hex(rhs.value.colorValue); + break; + default: + break; + } + node["value"] = value; + return node; +} + +bool convert::decode(const Node& node, + ZoneOptionValueTyped& rhs) +{ + node["type"] >> rhs.type; + if (node["value"]) { + Node value = node["value"]; + if (value.IsMap()) { + value["unsignedValue"] >> rhs.value.unsignedValue; + value["signedValue"] >> rhs.value.signedValue; + value["boolValue"] >> rhs.value.boolValue; + value["stringValue"] >> rhs.value.stringValue; + value["source"] >> rhs.value.sourceValue; + value["color"] >> rhs.value.colorValue; + } + } + return true; +} + +template <> +struct convert { + static Node encode(const WidgetPersistentData& rhs) + { + Node node; + for (int i=0; i> rhs.options; + return true; + } +}; + +Node convert::encode(const ZonePersistentData& rhs) +{ + Node node; + node["widgetName"] = rhs.widgetName; + node["widgetData"] = rhs.widgetData; + return node; +} + +bool convert::decode(const Node& node, ZonePersistentData& rhs) +{ + node["widgetName"] >> rhs.widgetName; + node["widgetData"] >> rhs.widgetData; + return true; +} + +Node convert::encode(const ScreenData& rhs) +{ + Node node; + node["LayoutId"] = rhs.layoutId; + node["layoutData"] = rhs.layoutPersistentData; + return node; +} + +bool convert::decode(const Node& node, ScreenData& rhs) +{ + node["LayoutId"] >> rhs.layoutId; + node["layoutData"] >> rhs.layoutPersistentData; + return true; +} +} // namespace YAML diff --git a/companion/src/firmwares/edgetx/yaml_screendata.h b/companion/src/firmwares/edgetx/yaml_screendata.h new file mode 100644 index 000000000..81349e588 --- /dev/null +++ b/companion/src/firmwares/edgetx/yaml_screendata.h @@ -0,0 +1,72 @@ +/* + * 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 "customisation_data.h" + +namespace YAML +{ +template <> +struct convert { + static Node encode(const ZonePersistentData& rhs); + static bool decode(const Node& node, ZonePersistentData& rhs); +}; + +template <> +struct convert { + static Node encode(const ZoneOptionValueTyped& rhs); + static bool decode(const Node& node, ZoneOptionValueTyped& rhs); +}; + +template +struct convert > { + typedef WidgetsContainerPersistentData PersistentData; + static Node encode(const PersistentData& rhs) + { + Node node; + for (int i=0; i 0) { + node["zones"][std::to_string(i)] = rhs.zones[i]; + } + } + for(int i=0; i> rhs.zones; + node["options"] >> rhs.options; + return true; + } +}; + +typedef RadioLayout::CustomScreenData ScreenData; + +template <> +struct convert { + static Node encode(const ScreenData& rhs); + static bool decode(const Node& node, ScreenData& rhs); +}; +} // namespace YAML diff --git a/companion/src/firmwares/edgetx/yaml_sensordata.cpp b/companion/src/firmwares/edgetx/yaml_sensordata.cpp new file mode 100644 index 000000000..d90b32554 --- /dev/null +++ b/companion/src/firmwares/edgetx/yaml_sensordata.cpp @@ -0,0 +1,184 @@ +/* + * 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_sensordata.h" + +static const YamlLookupTable sensorType = { + {SensorData::TELEM_TYPE_CUSTOM, "TYPE_CUSTOM"}, + {SensorData::TELEM_TYPE_CALCULATED, "TYPE_CALCULATED"}, +}; + +static const YamlLookupTable sensorFormula = { + {SensorData::TELEM_FORMULA_ADD, "FORMULA_ADD"}, + {SensorData::TELEM_FORMULA_AVERAGE, "FORMULA_AVERAGE"}, + {SensorData::TELEM_FORMULA_MIN, "FORMULA_MIN"}, + {SensorData::TELEM_FORMULA_MAX, "FORMULA_MAX"}, + {SensorData::TELEM_FORMULA_MULTIPLY, "FORMULA_MULTIPLY"}, + {SensorData::TELEM_FORMULA_TOTALIZE, "FORMULA_TOTALIZE"}, + {SensorData::TELEM_FORMULA_CELL, "FORMULA_CELL"}, + {SensorData::TELEM_FORMULA_CONSUMPTION, "FORMULA_CONSUMPTION"}, + {SensorData::TELEM_FORMULA_DIST, "FORMULA_DIST"}, +}; + +namespace YAML +{ +Node convert::encode(const SensorData& rhs) +{ + Node node; + node["type"] = LookupValue(sensorType, rhs.type); + + Node cfg; + if (rhs.type == SensorData::TELEM_TYPE_CUSTOM) { + node["id1"]["id"] = rhs.id; + node["subid"] = rhs.subid; + + unsigned int instance = rhs.instance; + if (instance != 0) { + instance = + ((instance - 1) & 0x1F) | (rhs.rxIdx << 5) | (rhs.moduleIdx << 7); + } + node["id2"]["instance"] = instance; + cfg["custom"]["ratio"] = rhs.ratio; + cfg["custom"]["offset"] = rhs.offset; + } else { + if (rhs.persistent) { + node["persistent"] = 1; + node["id1"]["persistentValue"] = rhs.persistentValue; + } + + node["id2"]["formula"] = LookupValue(sensorFormula, rhs.formula); + + switch (rhs.formula) { + case SensorData::TELEM_FORMULA_CELL: + cfg["cell"]["source"] = rhs.source; + cfg["cell"]["index"] = rhs.index; + break; + case SensorData::TELEM_FORMULA_ADD: + case SensorData::TELEM_FORMULA_AVERAGE: + case SensorData::TELEM_FORMULA_MULTIPLY: + case SensorData::TELEM_FORMULA_MIN: + case SensorData::TELEM_FORMULA_MAX: { + Node sources; + for (int i = 0; i < 4; i++) { + if (rhs.sources[i]) { + sources[std::to_string(i)]["val"] = rhs.sources[i]; + } + } + cfg["calc"]["sources"] = sources; + } break; + case SensorData::TELEM_FORMULA_DIST: + if (rhs.gps) { + cfg["dist"]["gps"] = rhs.gps; + } + if (rhs.alt) { + cfg["dist"]["alt"] = rhs.alt; + } + break; + case SensorData::TELEM_FORMULA_CONSUMPTION: + case SensorData::TELEM_FORMULA_TOTALIZE: + cfg["consumption"]["source"] = rhs.amps; + default: + break; + } + } + + node["label"] = rhs.label; + node["unit"] = rhs.unit; + node["prec"] = rhs.prec; + node["autoOffset"] = (int)rhs.autoOffset; + node["filter"] = (int)rhs.filter; + node["logs"] = (int)rhs.logs; + node["persistent"] = (int)rhs.persistent; + node["onlyPositive"] = (int)rhs.onlyPositive; + + if (cfg && cfg.IsMap()) { + node["cfg"] = cfg; + } + return node; +} + +bool convert::decode(const Node& node, SensorData& rhs) +{ + node["type"] >> sensorType >> rhs.type; + if (node["id1"]) { + Node id1 = node["id1"]; + id1["id"] >> rhs.id; + id1["persistentValue"] >> rhs.persistentValue; + } + node["subid"] >> rhs.subid; + if (node["id2"]) { + Node id2 = node["id2"]; + id2["instance"] >> rhs.instance; + id2["formula"] >> sensorFormula >> rhs.formula; + } + + if (rhs.type == SensorData::TELEM_TYPE_CUSTOM) { + rhs.rxIdx = (rhs.instance >> 5) & 0x03; // 2 bits Rx idx + rhs.moduleIdx = (rhs.instance >> 7) & 0x1; // 1 bit module idx + rhs.instance = (rhs.instance & 0x1F) + 1; // 5 bits instance + } + + node["label"] >> rhs.label; + node["unit"] >> rhs.unit; + node["prec"] >> rhs.prec; + node["autoOffset"] >> rhs.autoOffset; + node["filter"] >> rhs.filter; + node["logs"] >> rhs.logs; + node["persistent"] >> rhs.persistent; + node["onlyPositive"] >> rhs.onlyPositive; + + if (node["cfg"]) { + Node cfg = node["cfg"]; + if (cfg.IsMap()) { + if (cfg["custom"]) { + Node custom = cfg["custom"]; + if (custom.IsMap()) { + custom["ratio"] >> rhs.ratio; + custom["offset"] >> rhs.offset; + } + } else if (cfg["cell"]) { + Node cell = cfg["cell"]; + if (cell.IsMap()) { + cell["source"] >> rhs.source; + cell["index"] >> rhs.index; + } + } else if (cfg["calc"]) { + Node calc = cfg["calc"]; + if (calc.IsMap()) { + calc["sources"] >> rhs.sources; + } + } else if (cfg["consumption"]) { + Node consumption = cfg["consumption"]; + if (consumption.IsMap()) { + consumption["source"] >> rhs.amps; + } + } else if (cfg["dist"]) { + Node dist = cfg["dist"]; + if (dist.IsMap()) { + dist["gps"] >> rhs.gps; + dist["alt"] >> rhs.alt; + } + } + } + } + + return true; +} +} // namespace YAML diff --git a/companion/src/firmwares/edgetx/yaml_sensordata.h b/companion/src/firmwares/edgetx/yaml_sensordata.h new file mode 100644 index 000000000..b914ba834 --- /dev/null +++ b/companion/src/firmwares/edgetx/yaml_sensordata.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 "sensordata.h" + +namespace YAML +{ +template <> +struct convert { + static Node encode(const SensorData& rhs); + static bool decode(const Node& node, SensorData& rhs); +}; +} // namespace YAML diff --git a/companion/src/firmwares/edgetx/yaml_switchconfig.cpp b/companion/src/firmwares/edgetx/yaml_switchconfig.cpp new file mode 100644 index 000000000..7ab997c55 --- /dev/null +++ b/companion/src/firmwares/edgetx/yaml_switchconfig.cpp @@ -0,0 +1,145 @@ +/* + * 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_switchconfig.h" + +#include "boards.h" +#include "eeprominterface.h" + +const YamlLookupTable switchConfigLut = { + {Board::SWITCH_NOT_AVAILABLE, "none"}, + {Board::SWITCH_TOGGLE, "toggle"}, + {Board::SWITCH_2POS, "2pos"}, + {Board::SWITCH_3POS, "3pos"}, +}; + + +const YamlLookupTable potConfigLut = { + {Board::POT_NONE, "none"}, + {Board::POT_WITH_DETENT, "with_detent"}, + {Board::POT_MULTIPOS_SWITCH, "multipos_switch"}, + {Board::POT_WITHOUT_DETENT, "without_detent"}, +}; + +const YamlLookupTable slidersLut = { + {0, "LS"}, + {1, "RS"}, +}; + +const YamlLookupTable sliderConfigLut = { + {Board::SLIDER_NONE, "none"}, + {Board::SLIDER_WITH_DETENT, "with_detent"}, +}; + +int YamlStickLookup::name2idx(const std::string& name) +{ + try { + int idx = std::stoi(name); + if (idx < 4) { + return idx; + } + } catch(...) {} + + return -1; +} + +std::string YamlStickLookup::idx2name(unsigned int idx) +{ + if (idx < 4) { + return std::to_string(idx); + } + + return std::string(); +} + +int YamlSwitchLookup::name2idx(const std::string& name) +{ + auto fw = getCurrentFirmware(); + int idx = fw->getSwitchesIndex(name.c_str()); + if (idx < 0) return -1; + + return idx; +} + +std::string YamlSwitchLookup::idx2name(unsigned int idx) +{ + auto fw = getCurrentFirmware(); + unsigned int switches = Boards::getCapability(fw->getBoard(), Board::Switches); + if (idx >= switches) return std::string(); + + return fw->getSwitchesTag(idx); +} + +int YamlPotLookup::name2idx(const std::string& name) +{ + auto fw = getCurrentFirmware(); + int idx = fw->getAnalogInputIndex(name.c_str()); + if (idx < 0) return idx; + + int sticks = Boards::getCapability(fw->getBoard(), Board::Sticks); + if (idx < sticks) return -1; + idx -= sticks; + + int pots = Boards::getCapability(fw->getBoard(), Board::Pots); + if (idx >= pots) return -1; + + return idx; +} + +std::string YamlPotLookup::idx2name(unsigned int idx) +{ + auto fw = getCurrentFirmware(); + unsigned int pots = Boards::getCapability(fw->getBoard(), Board::Pots); + if (idx >= pots) return std::string(); + + unsigned int sticks = Boards::getCapability(fw->getBoard(), Board::Sticks); + return fw->getAnalogInputTag(idx + sticks); +} + +int YamlSliderLookup::name2idx(const std::string& name) +{ + auto fw = getCurrentFirmware(); + int idx = fw->getAnalogInputIndex(name.c_str()); + if (idx < 0) return idx; + + int sticks = Boards::getCapability(fw->getBoard(), Board::Sticks); + if (idx < sticks) return -1; + idx -= sticks; + + int pots = Boards::getCapability(fw->getBoard(), Board::Pots); + if (idx < pots) return -1; + idx -= pots; + + int sliders = Boards::getCapability(fw->getBoard(), Board::Sliders); + if (idx >= sliders) return -1; + + return idx; +} + +std::string YamlSliderLookup::idx2name(unsigned int idx) +{ + auto fw = getCurrentFirmware(); + unsigned int sliders = Boards::getCapability(fw->getBoard(), Board::Sliders); + if (idx >= sliders) return std::string(); + + unsigned int sticks = Boards::getCapability(fw->getBoard(), Board::Sticks); + unsigned int pots = Boards::getCapability(fw->getBoard(), Board::Pots); + return fw->getAnalogInputTag(idx + pots + sticks); +} diff --git a/companion/src/firmwares/edgetx/yaml_switchconfig.h b/companion/src/firmwares/edgetx/yaml_switchconfig.h new file mode 100644 index 000000000..c5240e4e4 --- /dev/null +++ b/companion/src/firmwares/edgetx/yaml_switchconfig.h @@ -0,0 +1,162 @@ +/* + * 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. + */ + +#pragma once + +#include "yaml_ops.h" +#include "generalsettings.h" +#include + +struct YamlStickLookup { + static int name2idx(const std::string& name); + static std::string idx2name(unsigned int idx); +}; + +template +struct YamlNameConfig { + char name[N][HARDWARE_NAME_LEN + 1]; + + YamlNameConfig() { memset(name, 0, sizeof(name)); } + + YamlNameConfig(const char in_names[N][HARDWARE_NAME_LEN + 1]) + { + memcpy(name, in_names, sizeof(name)); + } + + void copy(char out_names[N][HARDWARE_NAME_LEN + 1]) + { + memcpy(out_names, name, sizeof(name)); + } +}; + +typedef YamlNameConfig YamlStickConfig; + +template +struct YamlKnobConfig : public YamlNameConfig { + unsigned int config[N]; + + YamlKnobConfig() { memset(config, 0, sizeof(config)); } + + YamlKnobConfig(const char in_names[N][HARDWARE_NAME_LEN + 1], + const unsigned int in_configs[N]) : + YamlNameConfig(in_names) + { + memcpy(config, in_configs, sizeof(config)); + } + + void copy(char out_names[N][HARDWARE_NAME_LEN + 1], + unsigned int out_configs[N]) + { + YamlNameConfig::copy(out_names); + memcpy(out_configs, config, sizeof(config)); + } +}; + +// SA: +// type: 3pos +// name: +struct YamlSwitchLookup { + static int name2idx(const std::string& name); + static std::string idx2name(unsigned int idx); +}; +extern const YamlLookupTable switchConfigLut; +typedef YamlKnobConfig + YamlSwitchConfig; + +// S1: +// type: with_detent +// name: +struct YamlPotLookup { + static int name2idx(const std::string& name); + static std::string idx2name(unsigned int idx); +}; +extern const YamlLookupTable potConfigLut; +typedef YamlKnobConfig YamlPotConfig; + +// S1: +// type: with_detent +// name: +struct YamlSliderLookup { + static int name2idx(const std::string& name); + static std::string idx2name(unsigned int idx); +}; +extern const YamlLookupTable sliderConfigLut; +typedef YamlKnobConfig + YamlSliderConfig; + +namespace YAML +{ +template +struct convert > { + static Node encode(const YamlNameConfig& rhs) + { + Node node; + for (unsigned int i=0; i& rhs) + { + if (!node.IsMap()) return false; + int idx = 0; + for (const auto& kv : node) { + idx = name_lookup::name2idx(kv.first.Scalar()); + if (idx >= 0) { + kv.second["name"] >> rhs.name[idx]; + } + } + return true; + } +}; + +template +struct convert > { + static Node encode(const YamlKnobConfig& rhs) + { + Node node; + for (unsigned int i=0; i& rhs) + { + if (!node.IsMap()) return false; + int idx = 0; + for (const auto& kv : node) { + idx = name_lookup::name2idx(kv.first.Scalar()); + if (idx >= 0) { + kv.second["type"] >> cfg_lut >> rhs.config[idx]; + kv.second["name"] >> rhs.name[idx]; + } + } + return true; + } +}; +} // namespace YAML diff --git a/companion/src/firmwares/edgetx/yaml_trainerdata.cpp b/companion/src/firmwares/edgetx/yaml_trainerdata.cpp new file mode 100644 index 000000000..b1952827d --- /dev/null +++ b/companion/src/firmwares/edgetx/yaml_trainerdata.cpp @@ -0,0 +1,80 @@ +/* + * 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; + node["srcChn"] = rhs.src; + node["mode"] = trainerMixMode << rhs.mode; + node["studWeight"] = rhs.weight; + return node; +} + +bool convert::decode(const Node& node, TrainerMix& rhs) +{ + node["srcChn"] >> rhs.src; + node["mode"] >> trainerMixMode >> rhs.mode; + node["studWeight"] >> rhs.weight; + return true; +} + +Node convert::encode(const TrainerData& rhs) +{ + Node node; + for (int i = 0; i < 4; i++) { + node["calib"][std::to_string(i)]["val"] = rhs.calib[i]; + } + for (int i = 0; i < 4; i++) { + node["mix"][std::to_string(i)] = rhs.mix[i]; + } + 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[std::to_string(i)]["val"] >> rhs.calib[i]; + } + } + + if (node["mix"]) { + const Node& mix = node["mix"]; + for (int i = 0; i < 4; i++) { + mix[std::to_string(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 new file mode 100644 index 000000000..7bbcac2cd --- /dev/null +++ b/companion/src/firmwares/edgetx/yaml_trainerdata.h @@ -0,0 +1,39 @@ +/* + * 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 "generalsettings.h" + +extern const YamlLookupTable trainerMixMode; + +namespace YAML +{ +template <> +struct convert { + static Node encode(const TrainerMix& rhs); + static bool decode(const Node& node, TrainerMix& rhs); +}; + +template <> +struct convert { + static Node encode(const TrainerData& rhs); + static bool decode(const Node& node, TrainerData& rhs); +}; +} // namespace YAML diff --git a/companion/src/firmwares/eeprominterface.cpp b/companion/src/firmwares/eeprominterface.cpp index 90272d0ad..7cefd6d7e 100644 --- a/companion/src/firmwares/eeprominterface.cpp +++ b/companion/src/firmwares/eeprominterface.cpp @@ -178,3 +178,9 @@ void Firmware::addOptionsGroup(const OptionsGroup & options) { this->opts.append(options); } + +QString Firmware::getFlavour() +{ + QStringList strl = id.split("-"); + return strl.count() >= 2 ? strl.at(1) : QString(); +} diff --git a/companion/src/firmwares/eeprominterface.h b/companion/src/firmwares/eeprominterface.h index 099501c9d..77a9ce783 100644 --- a/companion/src/firmwares/eeprominterface.h +++ b/companion/src/firmwares/eeprominterface.h @@ -26,6 +26,7 @@ #include "radiodata.h" #include "../../radio/src/definitions.h" #include "simulatorinterface.h" +#include "datahelpers.h" #include #include @@ -33,6 +34,7 @@ #include #include +#include const uint8_t modn12x3[4][4]= { {1, 2, 3, 4}, @@ -163,7 +165,9 @@ enum Capability { HasADCJitterFilter, HasTelemetryBaudrate, TopBarZones, - FunctionSwitches + FunctionSwitches, + HasModelsList, + HasFlySkyGimbals }; class EEPROMInterface @@ -258,6 +262,8 @@ enum EepromLoadErrors { NUM_ERRORS }; +constexpr char FIRMWARE_ID_PREFIX[] = { "edgetx-" }; + class Firmware { Q_DECLARE_TR_FUNCTIONS(Firmware) @@ -285,8 +291,16 @@ class Firmware board(board), variantBase(0), base(base), - eepromInterface(nullptr) - { } + eepromInterface(nullptr), + analogInputNamesLookupTable(Boards::getAnalogNamesLookupTable(board)), + switchesLookupTable(Boards::getSwitchesLookupTable(board)), + trimSwitchesLookupTable(Boards::getTrimSwitchesLookupTable(board)), + trimSourcesLookupTable(Boards::getTrimSourcesLookupTable(board)), + rawSwitchTypesLookupTable(RawSwitch::getRawSwitchTypesLookupTable()), + rawSourceSpecialTypesLookupTable(RawSource::getSpecialTypesLookupTable()), + rawSourceCyclicLookupTable(RawSource::getCyclicLookupTable()) + { + } virtual ~Firmware() { } @@ -393,6 +407,26 @@ class Firmware currentVariant = value; } + QString getFlavour(); + + static Firmware * getFirmwareForFlavour(const QString & flavour) + { + return getFirmwareForId(FIRMWARE_ID_PREFIX + flavour); + } + + const StringTagMappingTable* getAnalogIndexNamesLookupTable() + { + return &analogInputNamesLookupTable; + } + + STRINGTAGMAPPINGFUNCS(analogInputNamesLookupTable, AnalogInput); + STRINGTAGMAPPINGFUNCS(switchesLookupTable, Switches); + STRINGTAGMAPPINGFUNCS(trimSwitchesLookupTable, TrimSwitches); + STRINGTAGMAPPINGFUNCS(trimSourcesLookupTable, TrimSources); + STRINGTAGMAPPINGFUNCS(rawSwitchTypesLookupTable, RawSwitchTypes); + STRINGTAGMAPPINGFUNCS(rawSourceSpecialTypesLookupTable, RawSourceSpecialTypes); + STRINGTAGMAPPINGFUNCS(rawSourceCyclicLookupTable, RawSourceCyclic); + protected: QString id; QString name; @@ -400,6 +434,16 @@ class Firmware unsigned int variantBase; Firmware * base; EEPROMInterface * eepromInterface; + + // used by YAML encode and decode + const StringTagMappingTable analogInputNamesLookupTable; + const StringTagMappingTable switchesLookupTable; + const StringTagMappingTable trimSwitchesLookupTable; + const StringTagMappingTable trimSourcesLookupTable; + const StringTagMappingTable rawSwitchTypesLookupTable; + const StringTagMappingTable rawSourceSpecialTypesLookupTable; + const StringTagMappingTable rawSourceCyclicLookupTable; + QList languages; //QList ttslanguages; OptionsList opts; @@ -407,6 +451,7 @@ class Firmware static QVector registeredFirmwares; static Firmware * defaultVariant; static Firmware * currentVariant; + }; inline Firmware * getCurrentFirmware() diff --git a/companion/src/firmwares/generalsettings.cpp b/companion/src/firmwares/generalsettings.cpp index 2ccb66254..729c57b93 100644 --- a/companion/src/firmwares/generalsettings.cpp +++ b/companion/src/firmwares/generalsettings.cpp @@ -54,14 +54,18 @@ bool GeneralSettings::switchSourceAllowedTaranis(int index) const bool GeneralSettings::isPotAvailable(int index) const { - if (index < 0 || index > Boards::getCapability(getCurrentBoard(), Board::Pots)) + int numPots = Boards::getCapability(getCurrentBoard(), Board::Pots); + if (getCurrentFirmware()->getCapability(HasFlySkyGimbals)) + numPots -= 2; + + if (index < 0 || index >= numPots) return false; return potConfig[index] != Board::POT_NONE; } bool GeneralSettings::isSliderAvailable(int index) const { - if (index < 0 || index > Boards::getCapability(getCurrentBoard(), Board::Sliders)) + if (index < 0 || index >= Boards::getCapability(getCurrentBoard(), Board::Sliders)) return false; return sliderConfig[index] != Board::SLIDER_NONE; } @@ -241,6 +245,8 @@ GeneralSettings::GeneralSettings() } } + internalModule = g.profile[g.sessionId()].defaultInternalModule(); + const char * themeName = IS_FLYSKY_NV14(board) ? "FlySky" : "EdgeTX"; RadioTheme::init(themeName, themeData); } diff --git a/companion/src/firmwares/generalsettings.h b/companion/src/firmwares/generalsettings.h index 6904cc1a4..bf334c63a 100644 --- a/companion/src/firmwares/generalsettings.h +++ b/companion/src/firmwares/generalsettings.h @@ -161,6 +161,7 @@ class GeneralSettings { int vBatMin; int vBatMax; int backlightMode; + unsigned int internalModule; // Introducted in EdgeTX 2.6 yaml only TrainerData trainer; unsigned int view; // main screen view // TODO enum bool disableThrottleWarning; @@ -231,8 +232,8 @@ class GeneralSettings { char switchName[CPN_MAX_SWITCHES][HARDWARE_NAME_LEN + 1]; unsigned int switchConfig[CPN_MAX_SWITCHES]; char stickName[CPN_MAX_STICKS][HARDWARE_NAME_LEN + 1]; - char potName[CPN_MAX_KNOBS][HARDWARE_NAME_LEN + 1]; - unsigned int potConfig[CPN_MAX_KNOBS]; + char potName[CPN_MAX_POTS][HARDWARE_NAME_LEN + 1]; + unsigned int potConfig[CPN_MAX_POTS]; char sliderName[CPN_MAX_SLIDERS][HARDWARE_NAME_LEN + 1]; unsigned int sliderConfig[CPN_MAX_SLIDERS]; diff --git a/companion/src/firmwares/modeldata.h b/companion/src/firmwares/modeldata.h index 6a1443c12..71fb32a71 100644 --- a/companion/src/firmwares/modeldata.h +++ b/companion/src/firmwares/modeldata.h @@ -63,8 +63,6 @@ class RSSIAlarmData { } }; -#define CPN_MAX_SCRIPTS 9 -#define CPN_MAX_SCRIPT_INPUTS 10 class ScriptData { public: ScriptData() { clear(); } @@ -145,8 +143,8 @@ class ModelData { unsigned int switchWarningEnable; unsigned int thrTrimSwitch; unsigned int potsWarningMode; - bool potsWarnEnabled[CPN_MAX_POTS]; - int potsWarnPosition[CPN_MAX_POTS]; + bool potsWarnEnabled[CPN_MAX_POTS + CPN_MAX_SLIDERS]; + int potsWarnPosition[CPN_MAX_POTS + CPN_MAX_SLIDERS]; bool displayChecklist; GVarData gvarData[CPN_MAX_GVARS]; diff --git a/companion/src/firmwares/moduledata.cpp b/companion/src/firmwares/moduledata.cpp index 37bf5be4c..25bb5aec9 100644 --- a/companion/src/firmwares/moduledata.cpp +++ b/companion/src/firmwares/moduledata.cpp @@ -23,6 +23,11 @@ #include "multiprotocols.h" #include "afhds3.h" #include "radiodataconversionstate.h" +#include "compounditemmodels.h" +#include "generalsettings.h" + +#include +#include void ModuleData::convert(RadioDataConversionState & cstate) { @@ -149,7 +154,7 @@ QString ModuleData::indexToString(int index, Firmware * fw) } // static -QString ModuleData::protocolToString(unsigned protocol) +QString ModuleData::protocolToString(unsigned int protocol) { static const char * strings[] = { "OFF", @@ -159,8 +164,8 @@ QString ModuleData::protocolToString(unsigned protocol) "LP45", "DSM2", "DSMX", "PPM16", "PPMsim", "FrSky XJT (D16)", "FrSky XJT (D8)", "FrSky XJT (LR12)", "FrSky DJT", - "TBS Crossfire", - "DIY Multiprotocol Module", + "Crossfire", + "Multi", "FrSky R9M", "FrSky R9M Lite", "FrSky R9M Lite Pro", @@ -171,7 +176,7 @@ QString ModuleData::protocolToString(unsigned protocol) "FrSky ACCESS R9M Lite Pro", "FrSky XJT lite (D16)", "FrSky XJT lite (D8)", "FrSky XJT lite (LR12)", "AFHDS3", - "ImmersionRC Ghost" + "Ghost" }; return CHECK_IN_ARRAY(strings, protocol); @@ -262,3 +267,232 @@ int ModuleData::getMaxChannelCount() } return 8; } + +/* + If Companion did not combine the /radio/src/datastructs type and sub-type fields + this would be so much cleaner and, modules and protocols generally easier to maintain + Another case for refactoring ModuleData as a whole! +*/ + +// static +int ModuleData::getTypeFromProtocol(unsigned int protocol) +{ + // must be kept in sync with opentxeeprom.h ProtocolsConversionTable + + const QVector>ProtocolTypeTable = { + + { PULSES_OFF, MODULE_TYPE_NONE }, + { PULSES_PPM, MODULE_TYPE_PPM }, + + { PULSES_PXX_XJT_X16, MODULE_TYPE_XJT_PXX1 }, + { PULSES_PXX_XJT_D8, MODULE_TYPE_XJT_PXX1 }, + { PULSES_PXX_XJT_LR12, MODULE_TYPE_XJT_PXX1 }, + + { PULSES_ACCESS_ISRM, MODULE_TYPE_ISRM_PXX2 }, + { PULSES_ACCST_ISRM_D16, MODULE_TYPE_ISRM_PXX2 }, + + { PULSES_LP45, MODULE_TYPE_DSM2 }, + { PULSES_DSM2, MODULE_TYPE_DSM2 }, + { PULSES_DSMX, MODULE_TYPE_DSM2 }, + + { PULSES_CROSSFIRE, MODULE_TYPE_CROSSFIRE }, + { PULSES_MULTIMODULE, MODULE_TYPE_MULTIMODULE }, + { PULSES_PXX_R9M, MODULE_TYPE_R9M_PXX1 }, + { PULSES_ACCESS_R9M, MODULE_TYPE_R9M_PXX2 }, + { PULSES_PXX_R9M_LITE, MODULE_TYPE_R9M_LITE_PXX1 }, + { PULSES_ACCESS_R9M_LITE, MODULE_TYPE_R9M_LITE_PXX2 }, + { PULSES_GHOST, MODULE_TYPE_GHOST }, + { PULSES_ACCESS_R9M_LITE_PRO, MODULE_TYPE_R9M_LITE_PRO_PXX2 }, + { PULSES_SBUS, MODULE_TYPE_SBUS }, + + { PULSES_XJT_LITE_X16, MODULE_TYPE_XJT_LITE_PXX2 }, + { PULSES_XJT_LITE_D8, MODULE_TYPE_XJT_LITE_PXX2 }, + { PULSES_XJT_LITE_LR12, MODULE_TYPE_XJT_LITE_PXX2 }, + + { PULSES_AFHDS3, MODULE_TYPE_FLYSKY } + }; + + QPairelmt; + + foreach (elmt, ProtocolTypeTable) { + if (elmt.first == (int)protocol) + return elmt.second; + } + + return -1; +} + +// static +int ModuleData::getSubTypeFromProtocol(unsigned int protocol) +{ + if (protocol == PULSES_ACCST_ISRM_D16 || protocol == PULSES_ACCESS_ISRM) + return protocol - PULSES_ACCESS_ISRM; + else if (protocol >= PULSES_PXX_XJT_X16 && protocol <= PULSES_PXX_XJT_LR12) + return protocol - PULSES_PXX_XJT_X16; + else + return 0; +} + +// static +QString ModuleData::typeToString(int type) +{ + static const char * strings[] = { + "OFF", + "PPM", + "XJT", + "ISRM", + "DSM2", + "CRSF", + "MULTI", + "R9M", + "R9M ACCESS", + "R9MLite", + "R9ML ACCESS", + "GHST", + "R9MLP ACCESS", + "SBUS", + "XJT Lite", + "FLYSKY" + }; + + return CHECK_IN_ARRAY(strings, type); +} + +AbstractStaticItemModel * ModuleData::internalModuleItemModel(int board) +{ + AbstractStaticItemModel * mdl = new AbstractStaticItemModel(); + mdl->setName("moduledata.internalmodule"); + + auto modules = Boards::getSupportedInternalModules(board == Board::BOARD_UNKNOWN ? getCurrentBoard() : (Board::Type)board); + for(auto mod : modules) { + mdl->appendToItemList(typeToString(mod), mod); + } + + mdl->loadItemList(); + return mdl; +} + +// static +bool ModuleData::isProtocolAvailable(int moduleidx, unsigned int protocol, GeneralSettings & settings) +{ + if (protocol == PULSES_OFF) + return true; + + Firmware *fw = getCurrentFirmware(); + Board::Type board = fw->getBoard(); + + if (moduleidx == 0 && Boards::getCapability(board, Board::HasInternalModuleSupport)) + return (int)settings.internalModule == getTypeFromProtocol(protocol); + + QString id = fw->getId(); + + if (IS_HORUS_OR_TARANIS(board)) { + switch (moduleidx) { + case 1: + switch (protocol) { + case PULSES_OFF: + case PULSES_PPM: + return true; + case PULSES_PXX_XJT_X16: + case PULSES_PXX_XJT_D8: + case PULSES_PXX_XJT_LR12: + return !(IS_TARANIS_XLITES(board) || IS_TARANIS_X9LITE(board)); + case PULSES_PXX_R9M: + case PULSES_LP45: + case PULSES_DSM2: + case PULSES_DSMX: + case PULSES_SBUS: + case PULSES_MULTIMODULE: + case PULSES_CROSSFIRE: + case PULSES_AFHDS3: + case PULSES_GHOST: + return true; + case PULSES_ACCESS_R9M: + return IS_ACCESS_RADIO(board, id) || (IS_FAMILY_HORUS_OR_T16(board) && id.contains("externalaccessmod")); + case PULSES_PXX_R9M_LITE: + case PULSES_ACCESS_R9M_LITE: + case PULSES_ACCESS_R9M_LITE_PRO: + case PULSES_XJT_LITE_X16: + case PULSES_XJT_LITE_D8: + case PULSES_XJT_LITE_LR12: + return (IS_TARANIS_XLITE(board) || IS_TARANIS_X9LITE(board) || IS_JUMPER_TLITE(board)); + default: + return false; + } + + case -1: + switch (protocol) { + case PULSES_PPM: + return true; + default: + return false; + } + + default: + return false; + } + } + else if (IS_SKY9X(board)) { + switch (moduleidx) { + case 0: + switch (protocol) { + case PULSES_PPM: + case PULSES_PXX_XJT_X16: + case PULSES_PXX_XJT_D8: + case PULSES_PXX_XJT_LR12: + case PULSES_PXX_R9M: + case PULSES_LP45: + case PULSES_DSM2: + case PULSES_DSMX: + case PULSES_SBUS: + case PULSES_MULTIMODULE: + return true; + default: + return false; + } + break; + case 1: + switch (protocol) { + case PULSES_PPM: + return true; + default: + return false; + } + break; + default: + return false; + } + } + else { + switch (protocol) { + case PULSES_PPM: + case PULSES_DSMX: + case PULSES_LP45: + case PULSES_DSM2: + // case PULSES_PXX_DJT: // Unavailable for now + case PULSES_PPM16: + case PULSES_PPMSIM: + return true; + default: + return false; + } + } + + return false; // to avoid compiler warning +} + +// static +AbstractStaticItemModel * ModuleData::protocolItemModel(GeneralSettings & settings) +{ + AbstractStaticItemModel * mdl = new AbstractStaticItemModel(); + mdl->setName("moduledata.protocol"); + + for (int i = 0; i <= 1; i++) { + for (unsigned int j = 0; j < PULSES_PROTOCOL_LAST; j++) { + mdl->appendToItemList(protocolToString(j), j, isProtocolAvailable(i, j, settings), 0, i + 1/*flag cannot be 0*/); + } + } + + mdl->loadItemList(); + return mdl; +} diff --git a/companion/src/firmwares/moduledata.h b/companion/src/firmwares/moduledata.h index 04e936758..b1606f0d5 100644 --- a/companion/src/firmwares/moduledata.h +++ b/companion/src/firmwares/moduledata.h @@ -18,8 +18,7 @@ * GNU General Public License for more details. */ -#ifndef MODULEDATA_H -#define MODULEDATA_H +#pragma once #include "constants.h" @@ -27,6 +26,30 @@ class Firmware; class RadioDataConversionState; +class AbstractStaticItemModel; +class GeneralSettings; + +// from radio/src/pulses/module_constants.h +enum ModuleType { + MODULE_TYPE_NONE = 0, + MODULE_TYPE_PPM, + MODULE_TYPE_XJT_PXX1, + MODULE_TYPE_ISRM_PXX2, + MODULE_TYPE_DSM2, + MODULE_TYPE_CROSSFIRE, + MODULE_TYPE_MULTIMODULE, + MODULE_TYPE_R9M_PXX1, // R9M + MODULE_TYPE_R9M_PXX2, // R9M ACCESS + MODULE_TYPE_R9M_LITE_PXX1, //R9MLite + MODULE_TYPE_R9M_LITE_PXX2, //R9MLP + MODULE_TYPE_GHOST, // Replaces MODULE_TYPE_R9M_LITE_PRO_PXX1 which doesn't exist + MODULE_TYPE_R9M_LITE_PRO_PXX2, + MODULE_TYPE_SBUS, + MODULE_TYPE_XJT_LITE_PXX2, + MODULE_TYPE_FLYSKY, //no more protocols possible because of 4 bits value + MODULE_TYPE_COUNT, + MODULE_TYPE_MAX = MODULE_TYPE_COUNT - 1 +}; enum PulsesProtocol { PULSES_OFF, @@ -219,10 +242,14 @@ class ModuleData { QString subTypeToString(int type = -1) const; QString powerValueToString(Firmware * fw) const; static QString indexToString(int index, Firmware * fw); - static QString protocolToString(unsigned protocol); + static QString protocolToString(unsigned int protocol); static QStringList powerValueStrings(enum PulsesProtocol protocol, int subType, Firmware * fw); bool hasFailsafes(Firmware * fw) const; int getMaxChannelCount(); + static int getTypeFromProtocol(unsigned int protocol); + static int getSubTypeFromProtocol(unsigned int protocol); + static QString typeToString(int type); + static AbstractStaticItemModel * internalModuleItemModel(int board = -1); + static bool isProtocolAvailable(int moduleidx, unsigned int protocol, GeneralSettings & settings); + static AbstractStaticItemModel * protocolItemModel(GeneralSettings & settings); }; - -#endif // MODULEDATA_H diff --git a/companion/src/firmwares/opentx/opentxeeprom.cpp b/companion/src/firmwares/opentx/opentxeeprom.cpp index 421138999..9e186e095 100644 --- a/companion/src/firmwares/opentx/opentxeeprom.cpp +++ b/companion/src/firmwares/opentx/opentxeeprom.cpp @@ -79,6 +79,8 @@ inline int MAX_POTS(Board::Type board, int version) { if (version <= 218 && IS_FAMILY_HORUS_OR_T16(board)) return 3; + if (version <= 220 && (IS_HORUS_X10(board) || IS_FAMILY_T16(board))) + return 5; if (IS_FAMILY_T12(board)) return 2; return Boards::getCapability(board, Board::Pots); @@ -95,7 +97,7 @@ inline int MAX_POTS_STORAGE(Board::Type board, int version) { if (version <= 218 && IS_FAMILY_HORUS_OR_T16(board)) return 3; - if (version >= 219 && IS_FAMILY_HORUS_OR_T16(board)) + if (version <= 220 && IS_FAMILY_HORUS_OR_T16(board) && !IS_FLYSKY_NV14(board)) return 5; if (IS_FAMILY_T12(board)) return 2; @@ -105,6 +107,8 @@ inline int MAX_POTS_STORAGE(Board::Type board, int version) inline int MAX_POTS_SOURCES(Board::Type board, int version) { if (version <= 218 && IS_FAMILY_HORUS_OR_T16(board)) + return 3; + if (version <= 220 && (IS_HORUS_X10(board) || IS_FAMILY_T16(board))) return 5; if (IS_FAMILY_T12(board)) return 2; @@ -115,6 +119,8 @@ inline int MAX_XPOTS(Board::Type board, int version) { if (version <= 218 && IS_FAMILY_HORUS_OR_T16(board)) return 3; + if (version <= 220 && (IS_HORUS_X10(board) || IS_FAMILY_T16(board))) + return 5; if (IS_FAMILY_T12(board)) return 2; return Boards::getCapability(board, Board::MultiposPots); @@ -180,6 +186,7 @@ inline int MAX_MOUSE_ANALOG_SOURCES(Board::Type board, int version) #define NUM_PPM_INPUTS(board, version) 16 #define ROTENC_COUNT(board, version) ((IS_STM32(board) && version >= 218) ? 0 : 1) #define MAX_AUX_TRIMS(board) ((IS_FAMILY_HORUS_OR_T16(board) && !IS_FLYSKY_NV14(board)) ? 2 : 0) +#define MAX_SOURCE_TYPE_SPECIAL(board, version) SOURCE_TYPE_SPECIAL_COUNT inline int switchIndex(int i, Board::Type board, unsigned int version) { @@ -340,6 +347,8 @@ class SourcesConversionTable: public ConversionTable { int offset = 0; if (version <= 218 && IS_HORUS_X10(board) && i >= CPN_MAX_STICKS + MAX_POTS_STORAGE(board, version)) offset += 2; + if (version <= 220 && (IS_HORUS_X10(board) || IS_FAMILY_T16(board)) && i >= CPN_MAX_STICKS + MAX_POTS_STORAGE(board, version)) + offset += 2; addConversion(RawSource(SOURCE_TYPE_STICK, i + offset), val++); } @@ -376,12 +385,8 @@ class SourcesConversionTable: public ConversionTable { if (!(flags & FLAG_NOTELEMETRY)) { for (int i=0; ipoints[j].x = *cur++; curve->points[curve->count-1].x = +100; } - else { - for (int j=0; jcount; j++) - curve->points[j].x = -100 + (200*i) / (curve->count-1); - } qCDebug(eepromImport) << QString("imported curve: %3 points").arg(curve->count); } } @@ -2947,6 +2948,9 @@ OpenTxGeneralData::OpenTxGeneralData(GeneralSettings & generalData, Board::Type if (version <= 218 && IS_HORUS_X10(board) && (i == CPN_MAX_STICKS + 3)) { input += 2; } + if (version <= 220 && IS_FAMILY_HORUS_OR_T16(board) && (i == CPN_MAX_STICKS + 5)) { // make room for EXT3 and EXT4 + input += 2; + } internalField.Append(new SignedField<16>(this, generalData.calibMid[input])); internalField.Append(new SignedField<16>(this, generalData.calibSpanNeg[input])); internalField.Append(new SignedField<16>(this, generalData.calibSpanPos[input])); diff --git a/companion/src/firmwares/opentx/opentxinterface.cpp b/companion/src/firmwares/opentx/opentxinterface.cpp index 940d57456..97ea8ddbc 100644 --- a/companion/src/firmwares/opentx/opentxinterface.cpp +++ b/companion/src/firmwares/opentx/opentxinterface.cpp @@ -59,59 +59,59 @@ const char * OpenTxEepromInterface::getName() { switch (board) { case BOARD_JUMPER_T12: - return "OpenTX for Jumper T12"; + return "EdgeTX for Jumper T12"; case BOARD_JUMPER_TLITE: - return "OpenTX for Jumper T-Lite"; + return "EdgeTX for Jumper T-Lite"; case BOARD_JUMPER_TPRO: - return "OpenTX for Jumper T-Pro"; + return "EdgeTX for Jumper T-Pro"; case BOARD_JUMPER_T16: - return "OpenTX for Jumper T16"; + return "EdgeTX for Jumper T16"; case BOARD_JUMPER_T18: - return "OpenTX for Jumper T18"; + return "EdgeTX for Jumper T18"; case BOARD_RADIOMASTER_TX16S: - return "OpenTX for Radiomaster TX16S"; + return "EdgeTX for Radiomaster TX16S"; case BOARD_RADIOMASTER_TX12: - return "OpenTX for Radiomaster TX12"; + return "EdgeTX for Radiomaster TX12"; case BOARD_RADIOMASTER_ZORRO: - return "OpenTX for Radiomaster Zorro"; + return "EdgeTX for Radiomaster Zorro"; case BOARD_RADIOMASTER_T8: - return "OpenTX for Radiomaster T8"; + return "EdgeTX for Radiomaster T8"; case BOARD_TARANIS_X9D: - return "OpenTX for FrSky Taranis X9D"; + return "EdgeTX for FrSky Taranis X9D"; case BOARD_TARANIS_X9DP: - return "OpenTX for FrSky Taranis X9D+"; + return "EdgeTX for FrSky Taranis X9D+"; case BOARD_TARANIS_X9DP_2019: - return "OpenTX for FrSky Taranis X9D+ 2019"; + return "EdgeTX for FrSky Taranis X9D+ 2019"; case BOARD_TARANIS_X9E: - return "OpenTX for FrSky Taranis X9E"; + return "EdgeTX for FrSky Taranis X9E"; case BOARD_TARANIS_X7: - return "OpenTX for FrSky Taranis X7"; + return "EdgeTX for FrSky Taranis X7"; case BOARD_TARANIS_X7_ACCESS: - return "OpenTX for FrSky Taranis X7 Access"; + return "EdgeTX for FrSky Taranis X7 Access"; case BOARD_TARANIS_X9LITES: - return "OpenTX for FrSky Taranis X9-Lite S"; + return "EdgeTX for FrSky Taranis X9-Lite S"; case BOARD_TARANIS_X9LITE: - return "OpenTX for FrSky Taranis X9-Lite"; + return "EdgeTX for FrSky Taranis X9-Lite"; case BOARD_TARANIS_XLITE: - return "OpenTX for FrSky Taranis X-Lite"; + return "EdgeTX for FrSky Taranis X-Lite"; case BOARD_TARANIS_XLITES: - return "OpenTX for FrSky Taranis X-Lite S/Pro"; + return "EdgeTX for FrSky Taranis X-Lite S/Pro"; case BOARD_SKY9X: - return "OpenTX for Sky9x board / 9X"; + return "EdgeTX for Sky9x board / 9X"; case BOARD_9XRPRO: - return "OpenTX for 9XR-PRO"; + return "EdgeTX for 9XR-PRO"; case BOARD_AR9X: - return "OpenTX for ar9x board / 9X"; + return "EdgeTX for ar9x board / 9X"; case BOARD_HORUS_X12S: - return "OpenTX for FrSky Horus"; + return "EdgeTX for FrSky Horus"; case BOARD_X10: - return "OpenTX for FrSky X10"; + return "EdgeTX for FrSky X10"; case BOARD_X10_EXPRESS: - return "OpenTX for FrSky X10 Express"; + return "EdgeTX for FrSky X10 Express"; case BOARD_FLYSKY_NV14: - return "OpenTX for FlySky NV14"; + return "EdgeTX for FlySky NV14"; default: - return "OpenTX for an unknown board"; + return "Board is unknown to EdgeTX"; } } @@ -254,7 +254,7 @@ unsigned long OpenTxEepromInterface::load(RadioData &radioData, const uint8_t * errors.set(HAS_WARNINGS); } else if (version_error == NOT_OPENTX) { - dbg << " not open9x"; + dbg << " not OpenTX"; errors.set(version_error); return errors.to_ulong(); } @@ -286,7 +286,7 @@ unsigned long OpenTxEepromInterface::load(RadioData &radioData, const uint8_t * uint8_t OpenTxEepromInterface::getLastDataVersion(Board::Type board) { - return 220; + return 220; // Note: this is the last bin format before the switch to YAML introduced in Companion version 2.6 } void OpenTxEepromInterface::showErrors(const QString & title, const QStringList & errors) @@ -752,14 +752,17 @@ int OpenTxFirmware::getCapability(::Capability capability) case HasAntennaChoice: return ((IS_FAMILY_HORUS_OR_T16(board) && board != Board::BOARD_X10_EXPRESS) || (IS_TARANIS_XLITE(board) && !IS_TARANIS_XLITES(board))) ? true : false; case HasADCJitterFilter: - return IS_HORUS_OR_TARANIS(board) ? true : false; + return IS_HORUS_OR_TARANIS(board); case HasTelemetryBaudrate: - return IS_HORUS_OR_TARANIS(board) ? true : false; + return IS_HORUS_OR_TARANIS(board); case TopBarZones: return getCapability(LcdWidth) > getCapability(LcdHeight) ? 4 : 2; case FunctionSwitches: return IS_JUMPER_TPRO(board) ? 6 : 0; - + case HasModelsList: + return IS_FAMILY_HORUS_OR_T16(board); + case HasFlySkyGimbals: + return (IS_RADIOMASTER_TX16S(board) && id.contains("flyskygimbals")); default: return 0; } @@ -981,6 +984,13 @@ EepromLoadErrors OpenTxEepromInterface::checkVersion(unsigned int version) // ALL: TimerData countdownStart invert value // ALL: convert more fields from zchar to normal string // COLORLCD: change CustomScreenData and TopBarPersistentData + return OLD_VERSION; + + case 221: + // ALL: YAML storage + // X10PCB: add pots EXT3 and EXT4 (conversion required as shifts slider settings in multiple fields) + // RM TX16S: add Flysky gimbals firmware build option and repurpose EXT3 and EXT4 if selected + // ??: add source TX GPS break; default: @@ -1270,25 +1280,28 @@ void addOpenTxArm9xOptions(OpenTxFirmware * firmware, bool dblkeys = true) addOpenTxRfOptions(firmware, FLEX); } +// TODO: refactoring OpenTxFirmware constructor - need to check if used elsewhere and how +#define FIRMWAREID(flavour) std::string(FIRMWARE_ID_PREFIX).append(flavour).c_str() + void registerOpenTxFirmwares() { OpenTxFirmware * firmware; /* FrSky Taranis X9D+ board */ - firmware = new OpenTxFirmware("opentx-x9d+", Firmware::tr("FrSky Taranis X9D+"), BOARD_TARANIS_X9DP); + firmware = new OpenTxFirmware(FIRMWAREID("x9d+"), Firmware::tr("FrSky Taranis X9D+"), BOARD_TARANIS_X9DP); firmware->addOption("noras", Firmware::tr("Disable RAS (SWR)")); addOpenTxTaranisOptions(firmware); registerOpenTxFirmware(firmware); addOpenTxRfOptions(firmware, EU + FLEX + AFHDS3); /* FrSky Taranis X9D+ 2019 board */ - firmware = new OpenTxFirmware("opentx-x9d+2019", Firmware::tr("FrSky Taranis X9D+ 2019"), BOARD_TARANIS_X9DP_2019); + firmware = new OpenTxFirmware(FIRMWAREID("x9d+2019"), Firmware::tr("FrSky Taranis X9D+ 2019"), BOARD_TARANIS_X9DP_2019); addOpenTxTaranisOptions(firmware); registerOpenTxFirmware(firmware); addOpenTxRfOptions(firmware, FLEX); /* FrSky Taranis X9D board */ - firmware = new OpenTxFirmware("opentx-x9d", Firmware::tr("FrSky Taranis X9D"), BOARD_TARANIS_X9D); + firmware = new OpenTxFirmware(FIRMWAREID("x9d"), Firmware::tr("FrSky Taranis X9D"), BOARD_TARANIS_X9D); firmware->addOption("noras", Firmware::tr("Disable RAS (SWR)")); firmware->addOption("haptic", Firmware::tr("Haptic module installed")); addOpenTxTaranisOptions(firmware); @@ -1296,7 +1309,7 @@ void registerOpenTxFirmwares() addOpenTxRfOptions(firmware, EU + FLEX + AFHDS3); /* FrSky Taranis X9E board */ - firmware = new OpenTxFirmware("opentx-x9e", Firmware::tr("FrSky Taranis X9E"), BOARD_TARANIS_X9E); + firmware = new OpenTxFirmware(FIRMWAREID("x9e"), Firmware::tr("FrSky Taranis X9E"), BOARD_TARANIS_X9E); firmware->addOption("shutdownconfirm", Firmware::tr("Confirmation before radio shutdown")); firmware->addOption("horussticks", Firmware::tr("Horus gimbals installed (Hall sensors)")); addOpenTxTaranisOptions(firmware); @@ -1304,44 +1317,44 @@ void registerOpenTxFirmwares() addOpenTxRfOptions(firmware, EU + FLEX); /* FrSky X9-Lite board */ - firmware = new OpenTxFirmware("opentx-x9lite", Firmware::tr("FrSky Taranis X9-Lite"), BOARD_TARANIS_X9LITE); + firmware = new OpenTxFirmware(FIRMWAREID("x9lite"), Firmware::tr("FrSky Taranis X9-Lite"), BOARD_TARANIS_X9LITE); addOpenTxTaranisOptions(firmware); registerOpenTxFirmware(firmware); addOpenTxRfOptions(firmware, FLEX); /* FrSky X9-LiteS board */ - firmware = new OpenTxFirmware("opentx-x9lites", Firmware::tr("FrSky Taranis X9-Lite S"), BOARD_TARANIS_X9LITES); + firmware = new OpenTxFirmware(FIRMWAREID("x9lites"), Firmware::tr("FrSky Taranis X9-Lite S"), BOARD_TARANIS_X9LITES); addOpenTxTaranisOptions(firmware); registerOpenTxFirmware(firmware); addOpenTxRfOptions(firmware, FLEX); /* FrSky X7 board */ - firmware = new OpenTxFirmware("opentx-x7", Firmware::tr("FrSky Taranis X7 / X7S"), BOARD_TARANIS_X7); + firmware = new OpenTxFirmware(FIRMWAREID("x7"), Firmware::tr("FrSky Taranis X7 / X7S"), BOARD_TARANIS_X7); addOpenTxTaranisOptions(firmware); registerOpenTxFirmware(firmware); addOpenTxRfOptions(firmware, EU + FLEX); /* FrSky X7 Access board */ - firmware = new OpenTxFirmware("opentx-x7access", Firmware::tr("FrSky Taranis X7 / X7S Access"), BOARD_TARANIS_X7_ACCESS); + firmware = new OpenTxFirmware(FIRMWAREID("x7access"), Firmware::tr("FrSky Taranis X7 / X7S Access"), BOARD_TARANIS_X7_ACCESS); addOpenTxTaranisOptions(firmware); registerOpenTxFirmware(firmware); addOpenTxRfOptions(firmware, FLEX); /* FrSky X-Lite S/PRO board */ - firmware = new OpenTxFirmware("opentx-xlites", Firmware::tr("FrSky Taranis X-Lite S/PRO"), BOARD_TARANIS_XLITES); + firmware = new OpenTxFirmware(FIRMWAREID("xlites"), Firmware::tr("FrSky Taranis X-Lite S/PRO"), BOARD_TARANIS_XLITES); addOpenTxTaranisOptions(firmware); registerOpenTxFirmware(firmware); addOpenTxRfOptions(firmware, FLEX); /* FrSky X-Lite board */ - firmware = new OpenTxFirmware("opentx-xlite", Firmware::tr("FrSky Taranis X-Lite"), BOARD_TARANIS_XLITE); + firmware = new OpenTxFirmware(FIRMWAREID("xlite"), Firmware::tr("FrSky Taranis X-Lite"), BOARD_TARANIS_XLITE); // firmware->addOption("stdr9m", Firmware::tr("Use JR-sized R9M module")); addOpenTxTaranisOptions(firmware); registerOpenTxFirmware(firmware); addOpenTxRfOptions(firmware, EU + FLEX); /* FrSky X10 board */ - firmware = new OpenTxFirmware("opentx-x10", Firmware::tr("FrSky Horus X10 / X10S"), BOARD_X10); + firmware = new OpenTxFirmware(FIRMWAREID("x10"), Firmware::tr("FrSky Horus X10 / X10S"), BOARD_X10); addOpenTxFrskyOptions(firmware); firmware->addOption("internalaccess", Firmware::tr("Support for ACCESS internal module replacement")); firmware->addOption("externalaccessmod", Firmware::tr("Support hardware mod: R9M ACCESS")); @@ -1349,13 +1362,13 @@ void registerOpenTxFirmwares() addOpenTxRfOptions(firmware, EU + FLEX); /* FrSky X10 Express board */ - firmware = new OpenTxFirmware("opentx-x10express", Firmware::tr("FrSky Horus X10 Express / X10S Express"), BOARD_X10_EXPRESS); + firmware = new OpenTxFirmware(FIRMWAREID("x10express"), Firmware::tr("FrSky Horus X10 Express / X10S Express"), BOARD_X10_EXPRESS); addOpenTxFrskyOptions(firmware); registerOpenTxFirmware(firmware); addOpenTxRfOptions(firmware, FLEX); /* FrSky X12 (Horus) board */ - firmware = new OpenTxFirmware("opentx-x12s", Firmware::tr("FrSky Horus X12S"), BOARD_HORUS_X12S); + firmware = new OpenTxFirmware(FIRMWAREID("x12s"), Firmware::tr("FrSky Horus X12S"), BOARD_HORUS_X12S); addOpenTxFrskyOptions(firmware); firmware->addOption("internalaccess", Firmware::tr("Support for ACCESS internal module replacement")); firmware->addOption("externalaccessmod", Firmware::tr("Support hardware mod: R9M ACCESS")); @@ -1364,7 +1377,7 @@ void registerOpenTxFirmwares() addOpenTxRfOptions(firmware, EU + FLEX); /* Jumper T12 board */ - firmware = new OpenTxFirmware("opentx-t12", QCoreApplication::translate("Firmware", "Jumper T12 / T12 Pro"), BOARD_JUMPER_T12); + firmware = new OpenTxFirmware(FIRMWAREID("t12"), QCoreApplication::translate("Firmware", "Jumper T12 / T12 Pro"), BOARD_JUMPER_T12); addOpenTxCommonOptions(firmware); firmware->addOption("noheli", Firmware::tr("Disable HELI menu and cyclic mix support")); firmware->addOption("nogvars", Firmware::tr("Disable Global variables")); @@ -1375,7 +1388,7 @@ void registerOpenTxFirmwares() addOpenTxRfOptions(firmware, FLEX); /* Jumper T-Lite board */ - firmware = new OpenTxFirmware("opentx-tlite", QCoreApplication::translate("Firmware", "Jumper T-Lite"), BOARD_JUMPER_TLITE); + firmware = new OpenTxFirmware(FIRMWAREID("tlite"), QCoreApplication::translate("Firmware", "Jumper T-Lite"), BOARD_JUMPER_TLITE); addOpenTxCommonOptions(firmware); firmware->addOption("noheli", Firmware::tr("Disable HELI menu and cyclic mix support")); firmware->addOption("nogvars", Firmware::tr("Disable Global variables")); @@ -1385,7 +1398,7 @@ void registerOpenTxFirmwares() addOpenTxRfOptions(firmware, FLEX); /* Jumper T-Pro board */ - firmware = new OpenTxFirmware("opentx-tpro", QCoreApplication::translate("Firmware", "Jumper T-Pro"), BOARD_JUMPER_TPRO); + firmware = new OpenTxFirmware(FIRMWAREID("tpro"), QCoreApplication::translate("Firmware", "Jumper T-Pro"), BOARD_JUMPER_TPRO); addOpenTxCommonOptions(firmware); firmware->addOption("noheli", Firmware::tr("Disable HELI menu and cyclic mix support")); firmware->addOption("nogvars", Firmware::tr("Disable Global variables")); @@ -1395,7 +1408,7 @@ void registerOpenTxFirmwares() addOpenTxRfOptions(firmware, FLEX); /* Jumper T16 board */ - firmware = new OpenTxFirmware("opentx-t16", Firmware::tr("Jumper T16 / T16+ / T16 Pro"), BOARD_JUMPER_T16); + firmware = new OpenTxFirmware(FIRMWAREID("t16"), Firmware::tr("Jumper T16 / T16+ / T16 Pro"), BOARD_JUMPER_T16); addOpenTxFrskyOptions(firmware); firmware->addOption("internalmulti", Firmware::tr("Support for MULTI internal module")); firmware->addOption("bluetooth", Firmware::tr("Support for bluetooth module")); @@ -1404,7 +1417,7 @@ void registerOpenTxFirmwares() registerOpenTxFirmware(firmware); /* Radiomaster TX12 board */ - firmware = new OpenTxFirmware("opentx-tx12", QCoreApplication::translate("Firmware", "Radiomaster TX12"), BOARD_RADIOMASTER_TX12); + firmware = new OpenTxFirmware(FIRMWAREID("tx12"), QCoreApplication::translate("Firmware", "Radiomaster TX12"), BOARD_RADIOMASTER_TX12); addOpenTxCommonOptions(firmware); firmware->addOption("noheli", Firmware::tr("Disable HELI menu and cyclic mix support")); firmware->addOption("nogvars", Firmware::tr("Disable Global variables")); @@ -1414,7 +1427,7 @@ void registerOpenTxFirmwares() addOpenTxRfOptions(firmware, FLEX); /* Radiomaster Zorro board */ - firmware = new OpenTxFirmware("opentx-zorro", QCoreApplication::translate("Firmware", "Radiomaster Zorro"), Board::BOARD_RADIOMASTER_ZORRO); + firmware = new OpenTxFirmware(FIRMWAREID("zorro"), QCoreApplication::translate("Firmware", "Radiomaster Zorro"), Board::BOARD_RADIOMASTER_ZORRO); addOpenTxCommonOptions(firmware); firmware->addOption("noheli", Firmware::tr("Disable HELI menu and cyclic mix support")); firmware->addOption("nogvars", Firmware::tr("Disable Global variables")); @@ -1425,7 +1438,7 @@ void registerOpenTxFirmwares() addOpenTxRfOptions(firmware, FLEX + AFHDS3); /* Radiomaster T8 board */ - firmware = new OpenTxFirmware("opentx-t8", QCoreApplication::translate("Firmware", "Radiomaster T8"), BOARD_RADIOMASTER_T8); + firmware = new OpenTxFirmware(FIRMWAREID("t8"), QCoreApplication::translate("Firmware", "Radiomaster T8"), BOARD_RADIOMASTER_T8); addOpenTxCommonOptions(firmware); firmware->addOption("noheli", Firmware::tr("Disable HELI menu and cyclic mix support")); firmware->addOption("nogvars", Firmware::tr("Disable Global variables")); @@ -1436,17 +1449,18 @@ void registerOpenTxFirmwares() firmware->addOption("bindkey", Firmware::tr("Allow bind using bind key")); /* Radiomaster TX16S board */ - firmware = new OpenTxFirmware("opentx-tx16s", Firmware::tr("Radiomaster TX16S / SE / Hall / Masterfire"), BOARD_RADIOMASTER_TX16S); + firmware = new OpenTxFirmware(FIRMWAREID("tx16s"), Firmware::tr("Radiomaster TX16S / SE / Hall / Masterfire"), BOARD_RADIOMASTER_TX16S); addOpenTxFrskyOptions(firmware); addOpenTxRfOptions(firmware, FLEX); static const Firmware::Option opt_bt("bluetooth", Firmware::tr("Support for bluetooth module")); static const Firmware::Option opt_internal_gps("internalgps", Firmware::tr("Support internal GPS")); firmware->addOptionsGroup({opt_bt, opt_internal_gps}); firmware->addOption("externalaccessmod", Firmware::tr("Support hardware mod: R9M ACCESS")); + firmware->addOption("flyskygimbals", Firmware::tr("Support hardware mod: FlySky Paladin EV Gimbals")); registerOpenTxFirmware(firmware); /* Jumper T18 board */ - firmware = new OpenTxFirmware("opentx-t18", Firmware::tr("Jumper T18"), BOARD_JUMPER_T18); + firmware = new OpenTxFirmware(FIRMWAREID("t18"), Firmware::tr("Jumper T18"), BOARD_JUMPER_T18); addOpenTxFrskyOptions(firmware); firmware->addOption("bluetooth", Firmware::tr("Support for bluetooth module")); firmware->addOption("externalaccessmod", Firmware::tr("Support hardware mod: R9M ACCESS")); @@ -1454,30 +1468,30 @@ void registerOpenTxFirmwares() addOpenTxRfOptions(firmware, FLEX); /* FlySky NV14 board */ - firmware = new OpenTxFirmware("opentx-nv14", QCoreApplication::translate("Firmware", "FlySky NV14"), BOARD_FLYSKY_NV14); + firmware = new OpenTxFirmware(FIRMWAREID("nv14"), QCoreApplication::translate("Firmware", "FlySky NV14"), BOARD_FLYSKY_NV14); addOpenTxFrskyOptions(firmware); firmware->addOption("bluetooth", Firmware::tr("Support for bluetooth module")); addOpenTxRfOptions(firmware, FLEX + AFHDS3); registerOpenTxFirmware(firmware); /* 9XR-Pro */ - firmware = new OpenTxFirmware("opentx-9xrpro", Firmware::tr("Turnigy 9XR-PRO"), BOARD_9XRPRO); + firmware = new OpenTxFirmware(FIRMWAREID("9xrpro"), Firmware::tr("Turnigy 9XR-PRO"), BOARD_9XRPRO); addOpenTxArm9xOptions(firmware, false); registerOpenTxFirmware(firmware, true); /* ar9x board */ - firmware = new OpenTxFirmware("opentx-ar9x", Firmware::tr("9X with AR9X board"), BOARD_AR9X); + firmware = new OpenTxFirmware(FIRMWAREID("ar9x"), Firmware::tr("9X with AR9X board"), BOARD_AR9X); addOpenTxArm9xOptions(firmware, true); //firmware->addOption("rtc", Firmware::tr("Optional RTC added")); //firmware->addOption("volume", Firmware::tr("i2c volume control added")); registerOpenTxFirmware(firmware, true); /* Sky9x board */ - firmware = new OpenTxFirmware("opentx-sky9x", Firmware::tr("9X with Sky9x board"), BOARD_SKY9X); + firmware = new OpenTxFirmware(FIRMWAREID("sky9x"), Firmware::tr("9X with Sky9x board"), BOARD_SKY9X); addOpenTxArm9xOptions(firmware); registerOpenTxFirmware(firmware, true); - Firmware::setDefaultVariant(Firmware::getFirmwareForId("opentx-tx16s")); + Firmware::setDefaultVariant(Firmware::getFirmwareForFlavour("tx16s")); Firmware::setCurrentVariant(Firmware::getDefaultVariant()); } diff --git a/companion/src/firmwares/radiodata.cpp b/companion/src/firmwares/radiodata.cpp index c833281fd..56f68a5c8 100644 --- a/companion/src/firmwares/radiodata.cpp +++ b/companion/src/firmwares/radiodata.cpp @@ -39,7 +39,8 @@ void RadioData::fixModelFilename(unsigned int index) { ModelData & model = models[index]; QString filename(model.filename); - bool ok = filename.endsWith(".bin"); + const bool hasSDCard = Boards::getCapability(getCurrentFirmware()->getBoard(), Board::HasSDCard); + bool ok = hasSDCard ? filename.endsWith(".yml") : filename.endsWith(".bin"); if (ok) { if (filename.startsWith("model") && filename.mid(5, filename.length()-9).toInt() > 0) { ok = false; @@ -54,7 +55,7 @@ void RadioData::fixModelFilename(unsigned int index) } } if (!ok) { - sprintf(model.filename, "model%d.bin", index+1); + sprintf(model.filename, "model%d.%s", index + 1, hasSDCard ? "yml" : "bin"); } } @@ -68,11 +69,12 @@ void RadioData::fixModelFilenames() QString RadioData::getNextModelFilename() { + const bool hasSDCard = Boards::getCapability(getCurrentFirmware()->getBoard(), Board::HasSDCard); char filename[sizeof(ModelData::filename)]; int index = 0; bool found = true; while (found) { - sprintf(filename, "model%d.bin", ++index); + sprintf(filename, "model%d.%s", ++index, hasSDCard ? "yml" : "bin"); found = false; for (unsigned int i=0; iname, name, sizeof(CategoryData::name)); + memset(this->name, 0, sizeof(CategoryData::name)); + strncpy(this->name, name, sizeof(CategoryData::name)-1); } char name[15+1]; }; diff --git a/companion/src/firmwares/rawsource.cpp b/companion/src/firmwares/rawsource.cpp index 98fa363d4..b1ad52e30 100644 --- a/companion/src/firmwares/rawsource.cpp +++ b/companion/src/firmwares/rawsource.cpp @@ -96,6 +96,10 @@ RawSourceRange RawSource::getRange(const ModelData * model, const GeneralSetting result.max = 24 * 60 * result.step - 60; // 23:59:00 with 1-minute resolution result.unit = tr("s"); } + else if (index == 2) { //GPS + result.max = 30000; + result.min = -result.max; + } else { // Timers 1 - 3 result.step = 1; result.max = 9 * 60 * 60 - 1; // 8:59:59 (to match firmware) @@ -137,7 +141,7 @@ QString RawSource::toString(const ModelData * model, const GeneralSettings * con }; static const QString special[] = { - tr("Batt"), tr("Time"), tr("Timer1"), tr("Timer2"), tr("Timer3"), + tr("Batt"), tr("Time"), tr("GPS"), tr("Reserved1"), tr("Reserved2"), tr("Reserved3"), tr("Reserved4") }; static const QString rotary[] = { tr("REa"), tr("REb") }; @@ -208,11 +212,11 @@ QString RawSource::toString(const ModelData * model, const GeneralSettings * con return LimitData().nameToString(index); case SOURCE_TYPE_SPECIAL: - if (index >= SOURCE_TYPE_SPECIAL_TIMER1_IDX && index <= SOURCE_TYPE_SPECIAL_TIMER1_IDX + CPN_MAX_TIMERS - 1) { + if (index >= SOURCE_TYPE_SPECIAL_FIRST_TIMER && index <= SOURCE_TYPE_SPECIAL_LAST_TIMER) { if (model) - result = model->timers[index - SOURCE_TYPE_SPECIAL_TIMER1_IDX].nameToString(index - SOURCE_TYPE_SPECIAL_TIMER1_IDX); + result = model->timers[index - SOURCE_TYPE_SPECIAL_FIRST_TIMER].nameToString(index - SOURCE_TYPE_SPECIAL_FIRST_TIMER); else - result = TimerData().nameToString(index - SOURCE_TYPE_SPECIAL_TIMER1_IDX); + result = TimerData().nameToString(index - SOURCE_TYPE_SPECIAL_FIRST_TIMER); } else result = CHECK_IN_ARRAY(special, index); @@ -289,7 +293,7 @@ bool RawSource::isSlider(int * sliderIndex, Board::Type board) const bool RawSource::isTimeBased(Board::Type board) const { - return (type == SOURCE_TYPE_SPECIAL && index > 0); + return (type == SOURCE_TYPE_SPECIAL && index >= SOURCE_TYPE_SPECIAL_FIRST_TIMER && index <= SOURCE_TYPE_SPECIAL_LAST_TIMER); } bool RawSource::isAvailable(const ModelData * const model, const GeneralSettings * const gs, Board::Type board) const @@ -305,6 +309,9 @@ bool RawSource::isAvailable(const ModelData * const model, const GeneralSettings if (type == SOURCE_TYPE_SWITCH && index >= b.getCapability(Board::Switches)) return false; + if (type == SOURCE_TYPE_SPECIAL && index >= SOURCE_TYPE_SPECIAL_FIRST_RESERVED && index <= SOURCE_TYPE_SPECIAL_LAST_RESERVED) + return false; + if (model) { if (type == SOURCE_TYPE_VIRTUAL_INPUT && !model->isInputValid(index)) return false; @@ -411,3 +418,38 @@ QStringList RawSource::getSwitchList(Boards board) const } return ret; } + +// static +StringTagMappingTable RawSource::getSpecialTypesLookupTable() +{ + StringTagMappingTable tbl; + +tbl.insert(tbl.end(), { + {std::to_string(SOURCE_TYPE_SPECIAL_TX_BATT), "TX_VOLTAGE"}, + {std::to_string(SOURCE_TYPE_SPECIAL_TX_TIME), "TX_TIME"}, + {std::to_string(SOURCE_TYPE_SPECIAL_TX_GPS), "TX_GPS"}, + {std::to_string(SOURCE_TYPE_SPECIAL_RESERVED1), "RESERVED1"}, + {std::to_string(SOURCE_TYPE_SPECIAL_RESERVED2), "RESERVED2"}, + {std::to_string(SOURCE_TYPE_SPECIAL_RESERVED3), "RESERVED3"}, + {std::to_string(SOURCE_TYPE_SPECIAL_RESERVED4), "RESERVED4"}, + {std::to_string(SOURCE_TYPE_SPECIAL_TIMER1), "TIMER1"}, + {std::to_string(SOURCE_TYPE_SPECIAL_TIMER2), "TIMER2"}, + {std::to_string(SOURCE_TYPE_SPECIAL_TIMER3), "TIMER3"}, + }); + + return tbl; +} + +// static +StringTagMappingTable RawSource::getCyclicLookupTable() +{ + StringTagMappingTable tbl; + +tbl.insert(tbl.end(), { + {"0", "CYC1"}, + {"1", "CYC2"}, + {"2", "CYC3"}, + }); + + return tbl; +} diff --git a/companion/src/firmwares/rawsource.h b/companion/src/firmwares/rawsource.h index a7d293173..304024446 100644 --- a/companion/src/firmwares/rawsource.h +++ b/companion/src/firmwares/rawsource.h @@ -23,6 +23,7 @@ #include "boards.h" #include "constants.h" +#include "datahelpers.h" #include @@ -178,8 +179,25 @@ enum RawSourceType { MAX_SOURCE_TYPE }; +enum RawSourceTypeSpecial { + SOURCE_TYPE_SPECIAL_TX_BATT, + SOURCE_TYPE_SPECIAL_TX_TIME, + SOURCE_TYPE_SPECIAL_TX_GPS, + SOURCE_TYPE_SPECIAL_FIRST_RESERVED, + SOURCE_TYPE_SPECIAL_RESERVED1 = SOURCE_TYPE_SPECIAL_FIRST_RESERVED, + SOURCE_TYPE_SPECIAL_RESERVED2, + SOURCE_TYPE_SPECIAL_RESERVED3, + SOURCE_TYPE_SPECIAL_RESERVED4, + SOURCE_TYPE_SPECIAL_LAST_RESERVED = SOURCE_TYPE_SPECIAL_RESERVED4, + SOURCE_TYPE_SPECIAL_FIRST_TIMER, + SOURCE_TYPE_SPECIAL_TIMER1 = SOURCE_TYPE_SPECIAL_FIRST_TIMER, + SOURCE_TYPE_SPECIAL_TIMER2, + SOURCE_TYPE_SPECIAL_TIMER3, + SOURCE_TYPE_SPECIAL_LAST_TIMER = SOURCE_TYPE_SPECIAL_TIMER3, + SOURCE_TYPE_SPECIAL_COUNT +}; + constexpr int SOURCE_TYPE_STICK_THR_IDX { 3 }; // TODO is there a function to determine index? -constexpr int SOURCE_TYPE_SPECIAL_TIMER1_IDX { 2 }; // TODO temp const until Timers own source type class RawSourceRange { @@ -257,6 +275,8 @@ class RawSource { void clear() { type = SOURCE_TYPE_NONE; index = 0; } QStringList getStickList(Boards board) const; QStringList getSwitchList(Boards board) const; + static StringTagMappingTable getSpecialTypesLookupTable(); + static StringTagMappingTable getCyclicLookupTable(); bool operator == ( const RawSource & other) const { return (this->type == other.type) && (this->index == other.index); diff --git a/companion/src/firmwares/rawswitch.cpp b/companion/src/firmwares/rawswitch.cpp index 45d13b1fc..5ed4d1c68 100644 --- a/companion/src/firmwares/rawswitch.cpp +++ b/companion/src/firmwares/rawswitch.cpp @@ -241,3 +241,28 @@ QStringList RawSwitch::getSwitchList(Boards board) const } return ret; } + +// static +StringTagMappingTable RawSwitch::getRawSwitchTypesLookupTable() +{ + StringTagMappingTable tbl; + + tbl.insert(tbl.end(), { + {std::to_string(SWITCH_TYPE_NONE), "NONE"}, + {std::to_string(SWITCH_TYPE_SWITCH), "Sxn"}, + {std::to_string(SWITCH_TYPE_VIRTUAL), "Ln"}, + {std::to_string(SWITCH_TYPE_MULTIPOS_POT), "6Pn"}, + {std::to_string(SWITCH_TYPE_TRIM), "Trim"}, + {std::to_string(SWITCH_TYPE_ROTARY_ENCODER), "RE"}, + {std::to_string(SWITCH_TYPE_ON), "ON"}, + {std::to_string(SWITCH_TYPE_OFF), "OFF"}, + {std::to_string(SWITCH_TYPE_ONE), "ONE"}, + {std::to_string(SWITCH_TYPE_FLIGHT_MODE), "FMn"}, + {std::to_string(SWITCH_TYPE_TIMER_MODE), "Timer"}, + {std::to_string(SWITCH_TYPE_TELEMETRY), "TELEMETRY_STREAMING"}, + {std::to_string(SWITCH_TYPE_SENSOR), "Tnn"}, + {std::to_string(SWITCH_TYPE_ACT), "RADIO_ACTIVITY"}, + }); + + return tbl; +} diff --git a/companion/src/firmwares/rawswitch.h b/companion/src/firmwares/rawswitch.h index 762ff83ff..d108cf1d6 100644 --- a/companion/src/firmwares/rawswitch.h +++ b/companion/src/firmwares/rawswitch.h @@ -22,6 +22,7 @@ #include "boards.h" #include "constants.h" +#include "datahelpers.h" #include @@ -89,6 +90,7 @@ class RawSwitch { bool isSet() const { return type != SWITCH_TYPE_NONE || index != 0; } void clear() { type = SWITCH_TYPE_NONE; index = 0; } QStringList getSwitchList(Boards board) const; + static StringTagMappingTable getRawSwitchTypesLookupTable(); bool operator== ( const RawSwitch& other) const { return (this->type == other.type) && (this->index == other.index); diff --git a/companion/src/firmwares/sensordata.h b/companion/src/firmwares/sensordata.h index cec9a6a63..4722f9453 100644 --- a/companion/src/firmwares/sensordata.h +++ b/companion/src/firmwares/sensordata.h @@ -24,7 +24,6 @@ #include -constexpr int CPN_MAX_SENSORS { 60 }; constexpr int SENSOR_LABEL_LEN { 4 }; constexpr int SENSOR_ISCONFIGURABLE { 1 << 1 }; diff --git a/companion/src/firmwares/telem_data.cpp b/companion/src/firmwares/telem_data.cpp index 99743c7e2..07513c087 100644 --- a/companion/src/firmwares/telem_data.cpp +++ b/companion/src/firmwares/telem_data.cpp @@ -65,7 +65,7 @@ void FrSkyData::clear() fasOffset = 0; for (int i=0; i<4; i++) screens[i].clear(); - varioSource = 2/*VARIO*/; + varioSource = 0; blades = 2; } diff --git a/companion/src/firmwares/timerdata.cpp b/companion/src/firmwares/timerdata.cpp index 676b3b3c4..abde9046f 100644 --- a/companion/src/firmwares/timerdata.cpp +++ b/companion/src/firmwares/timerdata.cpp @@ -35,9 +35,12 @@ void TimerData::clear() swtch = RawSwitch(SWITCH_TYPE_NONE); } -bool TimerData::isEmpty() +bool TimerData::isEmpty() const { - return (swtch == RawSwitch(SWITCH_TYPE_NONE, 0) && mode == TIMERMODE_OFF && name[0] == '\0' && minuteBeep == 0 && countdownBeep == COUNTDOWNBEEP_SILENT && val == 0 && persistent == 0 /*&& pvalue == 0*/); + return (swtch == RawSwitch(SWITCH_TYPE_NONE, 0) && mode == TIMERMODE_OFF && + name[0] == '\0' && minuteBeep == 0 && + countdownBeep == COUNTDOWNBEEP_SILENT && val == 0 && + persistent == 0 /*&& pvalue == 0*/); } bool TimerData::isModeOff() diff --git a/companion/src/firmwares/timerdata.h b/companion/src/firmwares/timerdata.h index 42d008664..78bcec716 100644 --- a/companion/src/firmwares/timerdata.h +++ b/companion/src/firmwares/timerdata.h @@ -88,7 +88,7 @@ class TimerData { void convert(RadioDataConversionState & cstate); void clear(); - bool isEmpty(); + bool isEmpty() const; bool isModeOff(); QString nameToString(int index) const; QString countdownBeepToString() const; diff --git a/companion/src/flasheepromdialog.cpp b/companion/src/flasheepromdialog.cpp index 6c210f940..87cb08fb7 100644 --- a/companion/src/flasheepromdialog.cpp +++ b/companion/src/flasheepromdialog.cpp @@ -266,7 +266,7 @@ void FlashEEpromDialog::on_burnButton_clicked() backupFilename = generateProcessUniqueTempFileName("eeprom.bin"); } if (!backupFilename.isEmpty()) { - if (!readEeprom(backupFilename, progressDialog.progress())) { + if (!readSettings(backupFilename, progressDialog.progress())) { return; } } @@ -297,7 +297,7 @@ void FlashEEpromDialog::on_burnButton_clicked() } // and write... - bool result = writeEeprom(filename, progressDialog.progress()); + bool result = writeSettings(filename, progressDialog.progress()); if (!result && !progressDialog.isEmpty()) { progressDialog.exec(); } diff --git a/companion/src/flashfirmwaredialog.cpp b/companion/src/flashfirmwaredialog.cpp index fc45a89ff..97f37f15a 100644 --- a/companion/src/flashfirmwaredialog.cpp +++ b/companion/src/flashfirmwaredialog.cpp @@ -307,7 +307,7 @@ void FlashFirmwareDialog::startFlash(const QString &filename) backupPath=g.backupDir(); } backupFilename = backupPath + "/backup-" + QDateTime().currentDateTime().toString("yyyy-MM-dd-HHmmss") + ".bin"; - result = readEeprom(backupFilename, progressDialog.progress()); + result = readSettings(backupFilename, progressDialog.progress()); sleep(2); } @@ -322,14 +322,14 @@ void FlashFirmwareDialog::startFlash(const QString &filename) QMessageBox::warning(this, tr("Conversion failed"), tr("Cannot convert Models and Settings for use with this firmware, original data will be used")); restoreFilename = backupFilename; } - if (!writeEeprom(restoreFilename, progressDialog.progress())) { + if (!writeSettings(restoreFilename, progressDialog.progress())) { QMessageBox::warning(this, tr("Restore failed"), tr("Could not restore Models and Settings to Radio. The models and settings data file can be found at: %1").arg(backupFilename)); } } progressDialog.progress()->setInfo(tr("Flashing done")); } - + progressDialog.exec(); if (isTempFileName(filename)) { diff --git a/companion/src/generaledit/calibration.cpp b/companion/src/generaledit/calibration.cpp index e43b61a53..d955e0e6b 100644 --- a/companion/src/generaledit/calibration.cpp +++ b/companion/src/generaledit/calibration.cpp @@ -25,15 +25,22 @@ CalibrationPanel::CalibrationPanel(QWidget * parent, GeneralSettings & generalSettings, Firmware * firmware): GeneralPanel(parent, generalSettings, firmware) { - int rows = Boards::getCapability(getCurrentBoard(), Board::MaxAnalogs); + Board::Type board = getCurrentBoard(); + int rows = Boards::getCapability(board, Board::MaxAnalogs); QStringList headerLabels; headerLabels << "" << tr("Negative span") << tr("Mid value") << tr("Positive span"); TableLayout * tableLayout = new TableLayout(this, rows, headerLabels); - for (int i = 0; i < rows; i++) { + for (int i = 0, row = 0; i < rows; i++) { int col = 0; + if (firmware->getCapability(HasFlySkyGimbals) && + i >= (Boards::getCapability(board, Board::Sticks) + 5) && + i < (Boards::getCapability(board, Board::Sticks) + 7)) + continue; + + row++; QLabel * label = new QLabel(this); label->setText(firmware->getAnalogInputName(i)); tableLayout->addWidget(i, col++, label); diff --git a/companion/src/generaledit/hardware.cpp b/companion/src/generaledit/hardware.cpp index 477287b2e..c084607b4 100644 --- a/companion/src/generaledit/hardware.cpp +++ b/companion/src/generaledit/hardware.cpp @@ -33,6 +33,7 @@ constexpr char FIM_SWITCHTYPE2POS[] {"Switch Type 2 Pos"}; constexpr char FIM_SWITCHTYPE3POS[] {"Switch Type 3 Pos"}; +constexpr char FIM_INTERNALMODULES[] {"Internal Modules"}; HardwarePanel::HardwarePanel(QWidget * parent, GeneralSettings & generalSettings, Firmware * firmware, CompoundItemModelFactory * sharedItemModels): GeneralPanel(parent, generalSettings, firmware), @@ -52,6 +53,9 @@ HardwarePanel::HardwarePanel(QWidget * parent, GeneralSettings & generalSettings int auxmodelid = editorItemModels->registerItemModel(GeneralSettings::auxSerialModeItemModel()); int baudmodelid = editorItemModels->registerItemModel(GeneralSettings::telemetryBaudrateItemModel()); + id = editorItemModels->registerItemModel(ModuleData::internalModuleItemModel()); + tabFilteredModels->registerItemModel(new FilteredItemModel(editorItemModels->getItemModel(id)), FIM_INTERNALMODULES); + grid = new QGridLayout(this); int count; int row = 0; @@ -64,7 +68,8 @@ HardwarePanel::HardwarePanel(QWidget * parent, GeneralSettings & generalSettings } count = Boards::getCapability(board, Board::Pots); - if (count) { + count -= firmware->getCapability(HasFlySkyGimbals) ? 2 : 0; + if (count > 0) { for (int i = 0; i < count; i++) { addPot(i, row); } @@ -126,6 +131,26 @@ HardwarePanel::HardwarePanel(QWidget * parent, GeneralSettings & generalSettings addParams(row, antennaMode); } + if (Boards::getCapability(board, Board::HasInternalModuleSupport)) { + addLabel(tr("Internal module"), row, 0); + AutoComboBox *internalModule = new AutoComboBox(this); + internalModule->setModel(tabFilteredModels->getItemModel(FIM_INTERNALMODULES)); + internalModule->setField(generalSettings.internalModule, this); + addParams(row, internalModule); + connect(internalModule, &AutoComboBox::currentDataChanged, this, [=] () { + QMessageBox::warning(this, CPN_STR_APP_NAME, + tr("ALERT: Check each model's internal module protocol to ensure it is compatible!")); + }); + } + + if (firmware->getCapability(HasTelemetryBaudrate)) { + addLabel(tr("Maximum Baud"), row, 0); + AutoComboBox *maxBaudRate = new AutoComboBox(this); + maxBaudRate->setModel(editorItemModels->getItemModel(baudmodelid)); + maxBaudRate->setField(generalSettings.telemetryBaudrate, this); + addParams(row, maxBaudRate); + } + if (firmware->getCapability(HasAuxSerialMode)) { QString lbl = "Serial Port"; if (IS_RADIOMASTER_TX16S(board)) @@ -162,14 +187,6 @@ HardwarePanel::HardwarePanel(QWidget * parent, GeneralSettings & generalSettings addParams(row, sportPower); } - if (firmware->getCapability(HasTelemetryBaudrate)) { - addLabel(tr("Maximum Baud"), row, 0); - AutoComboBox *maxBaudRate = new AutoComboBox(this); - maxBaudRate->setModel(editorItemModels->getItemModel(baudmodelid)); - maxBaudRate->setField(generalSettings.telemetryBaudrate, this); - addParams(row, maxBaudRate); - } - if (firmware->getCapability(HastxCurrentCalibration)) { addLabel(tr("Current Offset"), row, 0); AutoSpinBox *txCurrentCalibration = new AutoSpinBox(this); diff --git a/companion/src/mainwindow.cpp b/companion/src/mainwindow.cpp index 54d06c071..dab9309e1 100644 --- a/companion/src/mainwindow.cpp +++ b/companion/src/mainwindow.cpp @@ -157,7 +157,7 @@ MainWindow::MainWindow(): if (!str.isEmpty()) { int fileType = getStorageType(str); - if (fileType==STORAGE_TYPE_EEPE || fileType==STORAGE_TYPE_EEPM || fileType==STORAGE_TYPE_BIN || fileType==STORAGE_TYPE_OTX) { + if (fileType==STORAGE_TYPE_EEPE || fileType==STORAGE_TYPE_EEPM || fileType==STORAGE_TYPE_BIN || fileType==STORAGE_TYPE_ETX) { MdiChild * child = createMdiChild(); if (child->loadFile(str)) { if (!(printing && model >= 0 && (getCurrentFirmware()->getCapability(Models) == 0 || modelgetCapability(Models)) && !printfilename.isEmpty())) { @@ -897,24 +897,24 @@ void MainWindow::customizeSplash() dialog->deleteLater(); } -void MainWindow::writeEeprom() +void MainWindow::writeSettings() { if (activeMdiChild()) - activeMdiChild()->writeEeprom(); + activeMdiChild()->writeSettings(); } -void MainWindow::readEeprom() +void MainWindow::readSettings() { Board::Type board = getCurrentBoard(); QString tempFile; - if (IS_FAMILY_HORUS_OR_T16(board)) - tempFile = generateProcessUniqueTempFileName("temp.otx"); + if (Boards::getCapability(board, Board::HasSDCard)) + tempFile = generateProcessUniqueTempFileName("temp.etx"); else tempFile = generateProcessUniqueTempFileName("temp.bin"); - qDebug() << "MainWindow::readEeprom(): using temp file: " << tempFile; + qDebug() << "Reading models and settings into temp file: " << tempFile; - if (readEepromFromRadio(tempFile)) { + if (readSettingsFromRadio(tempFile)) { MdiChild * child = createMdiChild(); child->newFile(false); child->loadFile(tempFile, false); @@ -933,10 +933,10 @@ bool MainWindow::readFirmwareFromRadio(const QString & filename) return result; } -bool MainWindow::readEepromFromRadio(const QString & filename) +bool MainWindow::readSettingsFromRadio(const QString & filename) { ProgressDialog progressDialog(this, tr("Read Models and Settings from Radio"), CompanionIcon("read_eeprom.png")); - bool result = ::readEeprom(filename, progressDialog.progress()); + bool result = ::readSettings(filename, progressDialog.progress()); if (!result) { if (!progressDialog.isEmpty()) { progressDialog.exec(); @@ -974,7 +974,7 @@ void MainWindow::readBackup() } QString fileName = QFileDialog::getSaveFileName(this, tr("Save Radio Backup to File"), g.eepromDir(), EXTERNAL_EEPROM_FILES_FILTER); if (!fileName.isEmpty()) { - if (!readEepromFromRadio(fileName)) + if (!readSettingsFromRadio(fileName)) return; } } @@ -1045,8 +1045,8 @@ void MainWindow::updateMenus() saveAsAct->setEnabled(activeChild); closeAct->setEnabled(activeChild); compareAct->setEnabled(activeChild); - writeEepromAct->setEnabled(activeChild); - readEepromAct->setEnabled(true); + writeSettingsAct->setEnabled(activeChild); + readSettingsAct->setEnabled(true); if (IS_FAMILY_HORUS_OR_T16(getCurrentBoard())) { writeBUToRadioAct->setEnabled(false); readBUToFileAct->setEnabled(false); @@ -1199,8 +1199,8 @@ void MainWindow::retranslateUi(bool showMsg) trAct(sdsyncAct, tr("Synchronize SD"), tr("SD card synchronization")); trAct(openDocURLAct, tr("Manuals and other Documents"), tr("Open the EdgeTX document page in a web browser")); - trAct(writeEepromAct, tr("Write Models and Settings To Radio"), tr("Write Models and Settings to Radio")); - trAct(readEepromAct, tr("Read Models and Settings From Radio"), tr("Read Models and Settings from Radio")); + trAct(writeSettingsAct, tr("Write Models and Settings To Radio"), tr("Write Models and Settings to Radio")); + trAct(readSettingsAct, tr("Read Models and Settings From Radio"), tr("Read Models and Settings from Radio")); trAct(burnConfigAct, tr("Configure Communications..."), tr("Configure software for communicating with the Radio")); trAct(writeBUToRadioAct, tr("Write Backup to Radio"), tr("Write Backup from file to Radio")); trAct(readBUToFileAct, tr("Backup Radio to File"), tr("Save a complete backup file of all settings and model data in the Radio")); @@ -1256,8 +1256,8 @@ void MainWindow::createActions() burnListAct = addAct("list.png", SLOT(burnList())); readFlashAct = addAct("read_flash.png", SLOT(readFlash())); writeFlashAct = addAct("write_flash.png", SLOT(writeFlash())); - writeEepromAct = addAct("write_eeprom.png", SLOT(writeEeprom())); - readEepromAct = addAct("read_eeprom.png", SLOT(readEeprom())); + writeSettingsAct = addAct("write_eeprom.png", SLOT(writeSettings())); + readSettingsAct = addAct("read_eeprom.png", SLOT(readSettings())); burnConfigAct = addAct("configure.png", SLOT(burnConfig())); writeBUToRadioAct = addAct("write_eeprom_file.png", SLOT(writeBackup())); @@ -1347,8 +1347,8 @@ void MainWindow::createMenus() settingsMenu->addAction(importSettingsAct); burnMenu = menuBar()->addMenu(""); - burnMenu->addAction(writeEepromAct); - burnMenu->addAction(readEepromAct); + burnMenu->addAction(writeSettingsAct); + burnMenu->addAction(readSettingsAct); burnMenu->addSeparator(); burnMenu->addAction(writeBUToRadioAct); burnMenu->addAction(readBUToFileAct); @@ -1435,8 +1435,8 @@ void MainWindow::createToolBars() burnToolBar = new QToolBar(this); addToolBar( Qt::LeftToolBarArea, burnToolBar ); burnToolBar->setObjectName("Write"); - burnToolBar->addAction(writeEepromAct); - burnToolBar->addAction(readEepromAct); + burnToolBar->addAction(writeSettingsAct); + burnToolBar->addAction(readSettingsAct); burnToolBar->addSeparator(); burnToolBar->addAction(writeBUToRadioAct); burnToolBar->addAction(readBUToFileAct); @@ -1626,9 +1626,11 @@ int MainWindow::newProfile(bool loadProfile) if (i == MAX_PROFILES) //Failed to find free slot return -1; + Firmware *newfw = Firmware::getDefaultVariant(); g.profile[i].init(); - g.profile[i].name(tr("New Radio")); - g.profile[i].fwType(Firmware::getDefaultVariant()->getId()); + g.profile[i].name("New Radio"); + g.profile[i].fwType(newfw->getId()); + g.profile[i].defaultInternalModule(Boards::getDefaultInternalModules(newfw->getBoard())); if (loadProfile) { if (loadProfileId(i)) diff --git a/companion/src/mainwindow.h b/companion/src/mainwindow.h index 78178d7f8..a93a8a84b 100644 --- a/companion/src/mainwindow.h +++ b/companion/src/mainwindow.h @@ -103,8 +103,8 @@ class MainWindow : public QMainWindow bool loadProfileId(const unsigned pid); void loadProfile(); void logFile(); - void writeEeprom(); - void readEeprom(); + void writeSettings(); + void readSettings(); void writeFlash(QString fileToFlash=""); void readFlash(); void writeBackup(); @@ -156,7 +156,7 @@ class MainWindow : public QMainWindow QMdiSubWindow * findMdiChild(const QString & fileName); bool anyChildrenDirty(); - bool readEepromFromRadio(const QString & filename); + bool readSettingsFromRadio(const QString & filename); bool readFirmwareFromRadio(const QString & filename); bool checkProfileRadioExists(int profId); @@ -203,8 +203,8 @@ class MainWindow : public QMainWindow QAction *changelogAct; QAction *compareAct; QAction *editSplashAct; - QAction *writeEepromAct; - QAction *readEepromAct; + QAction *writeSettingsAct; + QAction *readSettingsAct; QAction *burnConfigAct; QAction *burnListAct; QAction *writeFlashAct; diff --git a/companion/src/mdichild.cpp b/companion/src/mdichild.cpp index 600f44851..4e4d36ebd 100644 --- a/companion/src/mdichild.cpp +++ b/companion/src/mdichild.cpp @@ -1320,7 +1320,7 @@ void MdiChild::newFile(bool createDefaults) { static int sequenceNumber = 1; isUntitled = true; - curFile = QString("document%1.otx").arg(sequenceNumber++); + curFile = QString("document%1.etx").arg(sequenceNumber++); updateTitle(); if (createDefaults && firmware->getCapability(Capability::HasModelCategories)) { @@ -1345,6 +1345,7 @@ bool MdiChild::loadFile(const QString & filename, bool resetCurrentFile) setCurrentFile(filename); } + // For etx files this will never be true as any conversion occurs when parsing file if (!Boards::isBoardCompatible(storage.getBoard(), getCurrentBoard())) { if (!convertStorage(storage.getBoard(), getCurrentBoard(), true)) return false; @@ -1360,7 +1361,7 @@ bool MdiChild::loadFile(const QString & filename, bool resetCurrentFile) bool MdiChild::save() { QFileInfo fi(curFile); - if (isUntitled || !fi.isWritable()) { + if (isUntitled || !fi.isWritable() || fi.suffix().toLower() != "etx") { return saveAs(true); } else { @@ -1375,7 +1376,7 @@ bool MdiChild::saveAs(bool isNew) #ifdef __APPLE__ QString filter; #else - QString filter(OTX_FILES_FILTER % YML_FILES_FILTER); + QString filter(ETX_FILES_FILTER % YML_FILES_FILTER); #endif QString fileName = QFileDialog::getSaveFileName(this, tr("Save As"), g.eepromDir() + "/" + fi.fileName(), filter); @@ -1455,7 +1456,7 @@ void MdiChild::setCurrentFile(const QString & fileName) void MdiChild::forceNewFilename(const QString & suffix, const QString & ext) { - curFile.replace(QRegExp("\\.(eepe|bin|hex|otx)$"), suffix + "." + ext); + curFile.replace(QRegExp("\\.(eepe|bin|hex|otx|etx)$"), suffix + "." + ext); } bool MdiChild::convertStorage(Board::Type from, Board::Type to, bool newFile) @@ -1528,7 +1529,7 @@ int MdiChild::askQuestion(const QString & msg, QMessageBox::StandardButtons butt return QMessageBox::question(this, CPN_STR_APP_NAME, msg, buttons, defaultButton); } -void MdiChild::writeEeprom() // write to Tx +void MdiChild::writeSettings() // write to Tx { if (g.confirmWriteModelsAndSettings()) { QMessageBox msgbox; @@ -1547,19 +1548,21 @@ void MdiChild::writeEeprom() // write to Tx } Board::Type board = getCurrentBoard(); - if (IS_FAMILY_HORUS_OR_T16(board)) { + + if (Boards::getCapability(board, Board::HasSDCard)) { QString radioPath = findMassstoragePath("RADIO", true); qDebug() << "Searching for SD card, found" << radioPath; if (radioPath.isEmpty()) { - qDebug() << "MdiChild::writeEeprom(): Horus radio not found"; + qDebug() << "Radio SD card not found"; QMessageBox::critical(this, CPN_STR_TTL_ERROR, tr("Unable to find radio SD card!")); return; } if (saveFile(radioPath, false)) { - emit newStatusMessage(tr("Models and Settings written"), 2000); + QMessageBox::information(this, CPN_STR_TTL_INFO, tr("Saved models and settings to radio")); } else { qDebug() << "MdiChild::writeEeprom(): saveFile error"; + QMessageBox::critical(this, CPN_STR_TTL_ERROR, tr("Error saving models and settings to radio!")); } } else { diff --git a/companion/src/mdichild.h b/companion/src/mdichild.h index 079205cc1..af5aa49e8 100644 --- a/companion/src/mdichild.h +++ b/companion/src/mdichild.h @@ -87,7 +87,7 @@ class MdiChild : public QWidget bool saveAs(bool isNew=false); bool saveFile(const QString & fileName, bool setCurrent=true); void closeFile(bool force = false); - void writeEeprom(); + void writeSettings(); void print(int model=-1, const QString & filename=""); void onFirmwareChanged(); @@ -179,7 +179,7 @@ class MdiChild : public QWidget bool maybeSave(); void setCurrentFile(const QString & fileName); - void forceNewFilename(const QString & suffix = "", const QString & ext = "otx"); + void forceNewFilename(const QString & suffix = "", const QString & ext = "etx"); bool convertStorage(Board::Type from, Board::Type to, bool newFile = false); void showWarning(const QString & msg); int askQuestion(const QString & msg, QMessageBox::StandardButtons buttons = (QMessageBox::Yes | QMessageBox::No), QMessageBox::StandardButton defaultButton = QMessageBox::No); diff --git a/companion/src/modeledit/modeledit.cpp b/companion/src/modeledit/modeledit.cpp index 60ad7781f..c2f5b2c30 100644 --- a/companion/src/modeledit/modeledit.cpp +++ b/companion/src/modeledit/modeledit.cpp @@ -106,11 +106,12 @@ ModelEdit::ModelEdit(QWidget * parent, RadioData & radioData, int modelId, Firmw s1.report("Telemetry"); } - if (Boards::getCapability(firmware->getBoard(), Board::HasColorLcd)) { + // temporary hide + /*if (Boards::getCapability(firmware->getBoard(), Board::HasColorLcd)) { addTab(new ColorCustomScreensPanel(this, model, generalSettings, firmware, sharedItemModels), tr("Custom Screens")); s1.report("ColorLcd Custom Screens"); } - else if (firmware->getCapability(TelemetryCustomScreens)) { + else */if (firmware->getCapability(TelemetryCustomScreens)) { addTab(new TelemetryCustomScreensPanel(this, model, generalSettings, firmware, sharedItemModels), tr("Custom Screens")); s1.report("Telemetry Custom Screens"); } diff --git a/companion/src/modeledit/setup.cpp b/companion/src/modeledit/setup.cpp index f12d83a74..b838fc4b0 100644 --- a/companion/src/modeledit/setup.cpp +++ b/companion/src/modeledit/setup.cpp @@ -237,14 +237,12 @@ ModulePanel::ModulePanel(QWidget * parent, ModelData & model, ModuleData & modul ui->trainerMode->hide(); } - // The protocols available on this board - for (unsigned int i = 0; i < PULSES_PROTOCOL_LAST; i++) { - if (firmware->isAvailable((PulsesProtocol) i, moduleIdx)) { - ui->protocol->addItem(ModuleData::protocolToString(i), i); - if (i == module.protocol) - ui->protocol->setCurrentIndex(ui->protocol->count() - 1); - } + if (panelFilteredItemModels && moduleIdx >= 0) { + int id = panelFilteredItemModels->registerItemModel(new FilteredItemModel(ModuleData::protocolItemModel(generalSettings), moduleIdx + 1/*flag cannot be 0*/), QString("Module Protocol %1").arg(moduleIdx)); + ui->protocol->setModel(panelFilteredItemModels->getItemModel(id)); + ui->protocol->setField(module.protocol, this); } + for (int i = 0; i <= MODULE_SUBTYPE_MULTI_LAST; i++) { if (i == MODULE_SUBTYPE_MULTI_SCANNER) continue; @@ -266,7 +264,7 @@ ModulePanel::ModulePanel(QWidget * parent, ModelData & model, ModuleData & modul update(); - connect(ui->protocol, static_cast(&QComboBox::currentIndexChanged), this, &ModulePanel::onProtocolChanged); + connect(ui->protocol, &AutoComboBox::currentDataChanged, this, &ModulePanel::onProtocolChanged); connect(ui->multiSubType, static_cast(&QComboBox::currentIndexChanged), this, &ModulePanel::onSubTypeChanged); connect(ui->multiProtocol, static_cast(&QComboBox::currentIndexChanged), this, &ModulePanel::onMultiProtocolChanged); connect(this, &ModulePanel::channelsRangeChanged, this, &ModulePanel::setupFailsafes); @@ -662,8 +660,7 @@ void ModulePanel::update() void ModulePanel::onProtocolChanged(int index) { - if (!lock && module.protocol != ui->protocol->itemData(index).toUInt()) { - module.protocol = ui->protocol->itemData(index).toInt(); + if (!lock) { module.channelsCount = module.getMaxChannelCount(); update(); emit updateItemModels(); @@ -1171,6 +1168,7 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge panelItemModels->registerItemModel(TimerData::countdownBeepItemModel()); panelItemModels->registerItemModel(TimerData::countdownStartItemModel()); panelItemModels->registerItemModel(TimerData::persistentItemModel()); + panelItemModels->registerItemModel(TimerData::modeItemModel()); panelFilteredModels->registerItemModel(new FilteredItemModel(ModelData::trainerModeItemModel(generalSettings, firmware)), FIM_TRAINERMODE); Board::Type board = firmware->getBoard(); @@ -1320,6 +1318,7 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge Board::SwitchInfo switchInfo = Boards::getSwitchInfo(board, i); switchInfo.config = Board::SwitchType(generalSettings.switchConfig[i]); if (switchInfo.config == Board::SWITCH_NOT_AVAILABLE || switchInfo.config == Board::SWITCH_TOGGLE) { + model.switchWarningEnable |= (1 << i); continue; } RawSource src(RawSourceType::SOURCE_TYPE_SWITCH, i); @@ -1389,7 +1388,7 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge // ui->functionSwitchesLayout->hide(); for (int i = firmware->getCapability(NumFirstUsableModule); i < firmware->getCapability(NumModules); i++) { - modules[i] = new ModulePanel(this, model, model.moduleData[i], generalSettings, firmware, i); + modules[i] = new ModulePanel(this, model, model.moduleData[i], generalSettings, firmware, i, panelFilteredModels); ui->modulesLayout->addWidget(modules[i]); connect(modules[i], &ModulePanel::modified, this, &SetupPanel::modified); connect(modules[i], &ModulePanel::updateItemModels, this, &SetupPanel::onModuleUpdateItemModels); diff --git a/companion/src/modeledit/setup_module.ui b/companion/src/modeledit/setup_module.ui index f78bd2772..4689f6a8d 100644 --- a/companion/src/modeledit/setup_module.ui +++ b/companion/src/modeledit/setup_module.ui @@ -805,7 +805,7 @@ - + 0 diff --git a/companion/src/modelslist.cpp b/companion/src/modelslist.cpp index 864c10028..b11b15723 100644 --- a/companion/src/modelslist.cpp +++ b/companion/src/modelslist.cpp @@ -651,7 +651,7 @@ void TreeModel::refresh() EEPROMInterface * eepromInterface = getCurrentEEpromInterface(); Board::Type board = eepromInterface->getBoard(); TreeItem * defaultCategoryItem = NULL; - bool hasEepromSizeData = (IS_FAMILY_HORUS_OR_T16(board) ? false : true); + bool hasEepromSizeData = false; // not necessary with move to YAML storage for all boards TODO: remove unused code if (hasEepromSizeData) { availableEEpromSize = Boards::getEEpromSize(board) - 64; // let's consider fat @@ -753,7 +753,7 @@ bool TreeModel::isModelIdUnique(unsigned modelIdx, unsigned module, unsigned pro int cnt = 0; if (protocol== PULSES_PXX_XJT_D8) return true; - + for (auto const& model: radioData->models) { if (!model.isEmpty()) { const ModuleData& moduleData = model.moduleData[module]; diff --git a/companion/src/radiointerface.cpp b/companion/src/radiointerface.cpp index 2d9524521..9b5cca0dd 100644 --- a/companion/src/radiointerface.cpp +++ b/companion/src/radiointerface.cpp @@ -175,7 +175,7 @@ bool writeFirmware(const QString & filename, ProgressWidget * progress) return flashProcess.run(); } -bool readEeprom(const QString & filename, ProgressWidget * progress) +bool readSettings(const QString & filename, ProgressWidget * progress) { Board::Type board = getCurrentBoard(); @@ -186,64 +186,84 @@ bool readEeprom(const QString & filename, ProgressWidget * progress) return false; } - if (IS_FAMILY_HORUS_OR_T16(board)) { - QString radioPath = findMassstoragePath("RADIO", true); - qDebug() << "Searching for SD card, found" << radioPath; - if (radioPath.isEmpty()) { - QMessageBox::critical(progress, CPN_STR_TTL_ERROR, - QCoreApplication::translate("RadioInterface", "Unable to find radio SD card!")); - return false; - } - RadioData radioData; - Storage inputStorage(radioPath); - if (!inputStorage.load(radioData)) { - QMessageBox::critical(progress, CPN_STR_TTL_ERROR, inputStorage.error()); - return false; - } - Storage outputStorage(filename); - if (!outputStorage.write(radioData)) { - QMessageBox::critical(progress, CPN_STR_TTL_ERROR, outputStorage.error()); - return false; - } + if (Boards::getCapability(board, Board::HasSDCard)) + return readSettingsSDCard(filename, progress); + else + return readSettingsEeprom(filename, progress); +} - if (getCurrentBoard() == Board::BOARD_JUMPER_T16 && inputStorage.getBoard() == Board::BOARD_X10) { - if (displayT16ImportWarning() == false) - return false; - } +bool readSettingsSDCard(const QString & filename, ProgressWidget * progress) +{ + QString radioPath = findMassstoragePath("RADIO", true); + qDebug() << "Searching for SD card, found" << radioPath; + if (radioPath.isEmpty()) { + QMessageBox::critical(progress, CPN_STR_TTL_ERROR, + QCoreApplication::translate("RadioInterface", "Unable to find radio SD card!")); + return false; } - else { - QString path = findMassstoragePath("EEPROM.BIN"); - if (path.isEmpty()) { - // On previous OpenTX we called the EEPROM file "TARANIS.BIN" :( - path = findMassstoragePath("TARANIS.BIN"); - } - if (path.isEmpty()) { - // Mike's bootloader calls the EEPROM file "ERSKY9X.BIN" :( - path = findMassstoragePath("ERSKY9X.BIN"); - } - if (path.isEmpty()) { - RadioNotFoundDialog dialog(progress); - dialog.exec(); + + // if radio.yml it is a converted radio + // if radio.bin unconverted pre 2.6 + // if neither then unconverted eeprom or empty + if (!QFile::exists(radioPath % "/RADIO/radio.yml") && !QFile::exists(radioPath % "/RADIO/radio.bin")) + return readSettingsEeprom(filename, progress); + + RadioData radioData; + Storage inputStorage(radioPath); + if (!inputStorage.load(radioData)) { + QMessageBox::critical(progress, CPN_STR_TTL_ERROR, QCoreApplication::translate("RadioInterface", "Failed to read Models and Settings from") % radioPath); + return false; + } + Storage outputStorage(filename); + if (!outputStorage.write(radioData)) { + QMessageBox::critical(progress, CPN_STR_TTL_ERROR, QCoreApplication::translate("RadioInterface", "Failed to write Models and Setting file") % filename); + return false; + } + + if (getCurrentBoard() == Board::BOARD_JUMPER_T16 && inputStorage.getBoard() == Board::BOARD_X10) { + if (displayT16ImportWarning() == false) return false; - } - CopyProcess copyProcess(path, filename, progress); - if (!copyProcess.run()) { - return false; - } + } + + return QFileInfo(filename).exists(); +} - if (!IS_STM32(board)) { - FlashProcess flashProcess(getRadioInterfaceCmd(), getReadEEpromCmd(filename), progress); - if (!flashProcess.run()) { - return false; - } +bool readSettingsEeprom(const QString & filename, ProgressWidget * progress) +{ + Board::Type board = getCurrentBoard(); + + QString path = findMassstoragePath("EEPROM.BIN"); + if (path.isEmpty()) { + // On previous OpenTX we called the EEPROM file "TARANIS.BIN" :( + path = findMassstoragePath("TARANIS.BIN"); + } + if (path.isEmpty()) { + // Mike's bootloader calls the EEPROM file "ERSKY9X.BIN" :( + path = findMassstoragePath("ERSKY9X.BIN"); + } + if (path.isEmpty()) { + RadioNotFoundDialog dialog(progress); + dialog.exec(); + return false; + } + CopyProcess copyProcess(path, filename, progress); + if (!copyProcess.run()) { + return false; + } + + + if (!IS_STM32(board)) { + FlashProcess flashProcess(getRadioInterfaceCmd(), getReadEEpromCmd(filename), progress); + if (!flashProcess.run()) { + return false; } } return QFileInfo(filename).exists(); } -bool writeEeprom(const QString & filename, ProgressWidget * progress) +bool writeSettings(const QString & filename, ProgressWidget * progress) { Board::Type board = getCurrentBoard(); @@ -272,94 +292,29 @@ bool writeEeprom(const QString & filename, ProgressWidget * progress) return false; } -#if (QT_VERSION < QT_VERSION_CHECK(5, 4, 0)) -#if defined WIN32 || !defined __GNUC__ -#include -bool isRemovableMedia(const QString & vol) -{ - char szDosDeviceName[MAX_PATH]; - QString volume = vol; - UINT driveType = GetDriveType(volume.replace("/", "\\").toLatin1()); - if (driveType != DRIVE_REMOVABLE) - return false; - QueryDosDevice(volume.replace("/", "").toLatin1(), szDosDeviceName, MAX_PATH); - if (strstr(szDosDeviceName, "\\Floppy") != NULL) { // it's a floppy - return false; - } - return true; -} -#else - #include "mountlist.h" -#endif // defined WIN32 || !defined __GNUC__ -#endif // (QT_VERSION < QT_VERSION_CHECK(5, 4, 0)) - QString findMassstoragePath(const QString & filename, bool onlyPath) { QString temppath; - QString eepromfile; + QString probefile; bool found = false; + QRegularExpression fstypeRe("^(v?fat|msdos)", QRegularExpression::CaseInsensitiveOption); // Linux: "vfat"; macOS: "msdos"; Win: "FAT32" -#if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)) + foreach(const QStorageInfo & si, QStorageInfo::mountedVolumes()) { //qDebug() << si.rootPath() << si.name() << si.device() << si.displayName() << si.fileSystemType() << si.isReady(); if (!si.isReady() || !QString(si.fileSystemType()).contains(fstypeRe)) continue; temppath = si.rootPath(); - eepromfile = temppath % "/" % filename; - qDebug() << "Searching for" << eepromfile; - if (QFile::exists(eepromfile)) { + probefile = temppath % "/" % filename; + qDebug() << "Searching for" << probefile; + if (QFile::exists(probefile)) { found = true; break; } } -#elif defined WIN32 || !defined __GNUC__ - static QStringList blacklist; - foreach(const QFileInfo & drive, QDir::drives()) { - temppath = drive.absolutePath(); - if (blacklist.contains(temppath)) - continue; - if (!isRemovableMedia(temppath)) { - blacklist.append(temppath); - continue; - } - WCHAR szVolumeName[256] ; - WCHAR szFileSystemName[256]; - DWORD dwSerialNumber = 0; - DWORD dwMaxFileNameLength=256; - DWORD dwFileSystemFlags=0; - if (!GetVolumeInformationW( (WCHAR *) drive.absolutePath().utf16(),szVolumeName,256,&dwSerialNumber,&dwMaxFileNameLength,&dwFileSystemFlags,szFileSystemName,256)) - continue; - eepromfile = temppath % "/" % filename; - qDebug() << "Searching for" << eepromfile; - if (QFile::exists(eepromfile)) { - found = true; - break; - } - } -#else - const static QStringList blacklist = QStringList() << "/" << "/net" << "/proc" << "/run"; - QStringList drives; - struct mount_entry *entry; - struct mount_entry *firstEntry; - firstEntry = entry = read_file_system_list(true); - while (entry != NULL) { - temppath = entry->me_mountdir; - if (!drives.contains(entry->me_devname) && !blacklist.contains(temppath) && QString(entry->me_type).contains(fstypeRe)) { - drives.append(entry->me_devname); - eepromfile = temppath % "/" % filename; - qDebug() << "Searching for" << eepromfile; - if (QFile::exists(eepromfile)) { - found = true; - break; - } - } - entry = entry->me_next; - } - free_file_system_list(firstEntry); -#endif if (found) - return onlyPath ? temppath : eepromfile; + return onlyPath ? temppath : probefile; else return QString(); } diff --git a/companion/src/radiointerface.h b/companion/src/radiointerface.h index 37053fac5..76c635e83 100644 --- a/companion/src/radiointerface.h +++ b/companion/src/radiointerface.h @@ -40,7 +40,9 @@ QStringList getWriteFirmwareArgs(const QString &filename); bool readFirmware(const QString &filename, ProgressWidget *progress); bool writeFirmware(const QString &filename, ProgressWidget *progress); -bool readEeprom(const QString &filename, ProgressWidget *progress); -bool writeEeprom(const QString &filename, ProgressWidget *progress); +bool readSettings(const QString &filename, ProgressWidget *progress); +bool readSettingsSDCard(const QString &filename, ProgressWidget *progress); +bool readSettingsEeprom(const QString &filename, ProgressWidget *progress); +bool writeSettings(const QString &filename, ProgressWidget *progress); #endif // _RADIOINTERFACE_H_ diff --git a/companion/src/simulation/joystickdialog.cpp b/companion/src/simulation/joystickdialog.cpp index 223e2d77d..1be3dd508 100644 --- a/companion/src/simulation/joystickdialog.cpp +++ b/companion/src/simulation/joystickdialog.cpp @@ -103,7 +103,7 @@ void joystickDialog::populateSourceCombo(QComboBox * cb) for (i=0; i < Board::STICK_AXIS_COUNT; ++i) { cb->addItem(Boards::getAxisName(i) % tr(" Stick"), i); } - for (; i < Board::STICK_AXIS_COUNT + CPN_MAX_POTS; ++i) { + for (; i < Board::STICK_AXIS_COUNT + CPN_MAX_POTS + CPN_MAX_SLIDERS; ++i) { cb->addItem(tr("Knob/Slider %1").arg(i - Board::STICK_AXIS_COUNT + 1), i); } } diff --git a/companion/src/simulation/simulatorstartupdialog.cpp b/companion/src/simulation/simulatorstartupdialog.cpp index e48a32afe..8d70a2b50 100644 --- a/companion/src/simulation/simulatorstartupdialog.cpp +++ b/companion/src/simulation/simulatorstartupdialog.cpp @@ -120,7 +120,7 @@ QString SimulatorStartupDialog::radioEepromFileName(const QString & firmwareId, if (pos > 0) radioId = radioId.mid(pos+1); if (usesCategorizedStorage(radioId)) - ext = "otx"; + ext = "etx"; eepromFileName = QString("eeprom-%1.%2").arg(radioId, ext); eepromFileName = QDir(folder).filePath(eepromFileName.toLatin1()); diff --git a/companion/src/simulation/simulatorwidget.cpp b/companion/src/simulation/simulatorwidget.cpp index 8f3ef08c2..406e2bdbe 100644 --- a/companion/src/simulation/simulatorwidget.cpp +++ b/companion/src/simulation/simulatorwidget.cpp @@ -249,9 +249,9 @@ bool SimulatorWidget::setStartupData(const QByteArray & dataSource, bool fromFil error = store.error(); } else { - if (fileName.endsWith(".otx", Qt::CaseInsensitive)) { - // no radios can work with .otx files directly, so we load contents into either - // a temporary folder (Horus) or local data array (other radios) which we'll save back to .otx upon exit + if (fileName.endsWith(".etx", Qt::CaseInsensitive)) { + // no radios can work with .etx files directly, so we load contents into either + // a temporary folder (Horus) or local data array (other radios) which we'll save back to .etx upon exit if ((ret = setRadioData(&simuData))) { startupFromFile = false; return true; @@ -294,17 +294,20 @@ bool SimulatorWidget::setRadioData(RadioData * radioData) saveTempRadioData = (flags & SIMULATOR_FLAGS_STANDALONE); - if (IS_FAMILY_HORUS_OR_T16(m_board)) + // All radios use SD card data path from 2.6.0 on + bool hasSdCard = Boards::getCapability(m_board, Board::HasSDCard); + if (hasSdCard) ret = useTempDataPath(true); if (ret) { - if (radioDataPath.isEmpty()) { + if (!hasSdCard) { startupData.fill(0, Boards::getEEpromSize(m_board)); - if (firmware->getEEpromInterface()->save((uint8_t *)startupData.data(), *radioData, 0, firmware->getCapability(SimulatorVariant)) <= 0) { + if (firmware->getEEpromInterface()->save( + (uint8_t *)startupData.data(), *radioData, 0, + firmware->getCapability(SimulatorVariant)) <= 0) { ret = false; } - } - else { + } else { ret = saveRadioData(radioData, radioDataPath); } } @@ -365,7 +368,7 @@ bool SimulatorWidget::useTempDataPath(bool deleteOnClose) if (deleteTempRadioData) deleteTempData(); - QTemporaryDir tmpDir(QDir::tempPath() + "/otx-XXXXXX"); + QTemporaryDir tmpDir(QDir::tempPath() + "/etx-XXXXXX"); if (tmpDir.isValid()) { setDataPath(tmpDir.path()); tmpDir.setAutoRemove(false); @@ -379,7 +382,7 @@ bool SimulatorWidget::useTempDataPath(bool deleteOnClose) } } -// This will save radio data from temporary folder structure back into an .otx file, eg. for Horus. +// This will save radio data from temporary folder structure back into an .etx file, eg. for Horus. bool SimulatorWidget::saveTempData() { bool ret = false; diff --git a/companion/src/simulator.cpp b/companion/src/simulator.cpp index 283248496..7caca8e97 100644 --- a/companion/src/simulator.cpp +++ b/companion/src/simulator.cpp @@ -127,7 +127,7 @@ CommandLineParseResult cliOptions(SimulatorOptions * simOptions, int * profileId QApplication::translate("SimulatorMain", "type")); cliOptions.addPositionalArgument(QApplication::translate("SimulatorMain", "data-source"), - QApplication::translate("SimulatorMain", "Radio data (.bin/.eeprom/.otx) image file to use OR data folder path (for Horus-style radios).\n" + QApplication::translate("SimulatorMain", "Radio data (.bin/.eeprom/.etx) image file to use OR data folder path (for Horus-style radios).\n" "NOTE: any existing EEPROM data incompatible with the selected radio type may be overwritten!"), QApplication::translate("SimulatorMain", "[data-source]")); diff --git a/companion/src/storage/CMakeLists.txt b/companion/src/storage/CMakeLists.txt index 8df237238..31dd86e9f 100644 --- a/companion/src/storage/CMakeLists.txt +++ b/companion/src/storage/CMakeLists.txt @@ -12,6 +12,7 @@ set(storage_NAMES hexeeprom categorized sdcard + etx otx yaml ) diff --git a/companion/src/storage/appdata.cpp b/companion/src/storage/appdata.cpp index 5e64ad8fc..34a5aea6e 100644 --- a/companion/src/storage/appdata.cpp +++ b/companion/src/storage/appdata.cpp @@ -409,16 +409,10 @@ QMap AppData::getActiveProfiles() const void AppData::convertSettings(QSettings & settings) { quint32 savedVer = settings.value(SETTINGS_VERSION_KEY, 0).toUInt(); -#if (VERSION_NUMBER < QT_VERSION_CHECK(2, 3, 0)) - // convert old 2.2.x version marker; TODO: remove once v2.3 is established (because we'll always convert and clean 2.2.x settings anyway) - if (savedVer == 220) - savedVer = 0x2020000; -#endif - if (savedVer == CPN_SETTINGS_VERSION) return; if (savedVer > CPN_SETTINGS_VERSION) { - qWarning().noquote() << "Saved settings version is newer than current, skippig conversions. Saved:" << fmtHex(savedVer) << "Current:" << fmtHex(CPN_SETTINGS_VERSION); + qWarning().noquote() << "Saved settings version is newer than current, skipping conversions. Saved:" << fmtHex(savedVer) << "Current:" << fmtHex(CPN_SETTINGS_VERSION); return; } @@ -432,29 +426,24 @@ void AppData::convertSettings(QSettings & settings) << " from v" << fmtHex(savedVer) << " (" << fmtHex(savedMajMin) << ") to v" << fmtHex(CPN_SETTINGS_VERSION) << " (" << fmtHex(currMajMin) << "). Removing unused: " << removeUnused; - if (settings.contains("useWizard")) { - if (!settings.contains(newModelAction_key())) - settings.setValue(newModelAction_key(), (settings.value("useWizard").toBool() ? MODEL_ACT_WIZARD : MODEL_ACT_EDITOR)); - if (removeUnused) - settings.remove("useWizard"); - } - - // meaning of warningId changed during v2.2 development but value of "7" indicates old setting, removing it will restore defaults - if (savedMajMin < 0x203 && settings.contains("warningId") && settings.value("warningId").toInt() == 7) - settings.remove("warningId"); - - // Convert joystick settings to new style of key names - static const QString jsCalBasePath = QStringLiteral("JsCalibration/%1"); - if (settings.contains(jsCalBasePath.arg("stick0_axe"))) { - const QStringList vars({"axe", "inv", "max", "med", "min"}); - for (int i=0; i < MAX_JOYSTICKS; ++i) { - for (const QString & var : vars) { - const QString oldPath = jsCalBasePath.arg(QString("stick%1_%2").arg(i).arg(var)); // old format "/stick#_var" - const QVariant val = settings.value(oldPath); - if (val.isValid()) - settings.setValue(jsCalBasePath.arg(QString("%1/stick_%2").arg(i).arg(var)), val); // new format "/#/stick_var" - if (removeUnused) - settings.remove(oldPath); + // firmwares renamed from opentx-* to edgetx-* at 2.6 + if (savedMajMin <= 0x207) { // Note: change merged post 2.6 rc 1 and version bumped to 2.7 the Nightly users also require upgrade + qInfo().noquote() << "Converting profiles"; + static const QString profileFwTypePath = QStringLiteral("Profiles/profile%1/fwType"); + for (int i = 0; i < MAX_PROFILES; i++) { + if (settings.contains(profileFwTypePath.arg(i))) { + const QVariant oldValue = settings.value(profileFwTypePath.arg(i)); + if (oldValue.isValid()) { + const QString oldval = settings.value(profileFwTypePath.arg(i)).toString(); + QString newval = oldval; + newval.replace("opentx-", "edgetx-"); + if (oldval != newval) { + settings.setValue(profileFwTypePath.arg(i), newval); + qInfo().noquote().nospace() << "Converted entry " << profileFwTypePath.arg(i) + << " from (" << oldval << ")" + << " to (" << newval << ")"; + } + } } } } @@ -481,7 +470,8 @@ void AppData::clearUnusedSettings(QSettings & settings) bool AppData::findPreviousVersionSettings(QString * version) const { - static const QStringList versList({QStringLiteral("2.2"), QStringLiteral("2.1"), QStringLiteral("2.0")}); + // TODO need a more dynamic method since ETX moves so quickly + static const QStringList versList({QStringLiteral("2.6"), QStringLiteral("2.5"), QStringLiteral("2.4")}); for (const QString &ver : versList) { const QString prod("Companion " % ver); @@ -498,30 +488,15 @@ bool AppData::findPreviousVersionSettings(QString * version) const } } - QSettings settings(COMPANY, "OpenTX Companion"); - if (settings.contains(SETTINGS_VERSION_KEY)) { - *version = QStringLiteral("1.x"); - return true; - } - else { - settings.clear(); - } - return false; } bool AppData::importSettings(const QString & fromVersion) { - QString fromProduct; + QString fromProduct = PRODUCT_NO_VERS % " " % fromVersion; + //qDebug() << "From Product:" << fromProduct; upgradeFromVersion.clear(); - if (fromVersion.startsWith("2.")) - fromProduct = "Companion " % fromVersion; - else if (fromVersion == "1.x") - fromProduct = "OpenTX Companion"; - else - return false; - upgradeFromVersion = fromVersion; QSettings fromSettings(COMPANY, fromProduct); @@ -535,8 +510,10 @@ bool AppData::importSettings(QSettings * fromSettings) // Create temporary settings because we may modify them before import. QSettings tempSettings(COMPANY, PRODUCT % "_import"); - for (const QString & key : fromSettings->allKeys()) + for (const QString & key : fromSettings->allKeys()) { tempSettings.setValue(key, fromSettings->value(key)); + //qInfo().noquote() << "Import key(" << key << ") value(" << fromSettings->value(key) << ")"; + } // convert settings first to simplify import process convertSettings(tempSettings); diff --git a/companion/src/storage/appdata.h b/companion/src/storage/appdata.h index 49d8f0658..53ffb71d9 100644 --- a/companion/src/storage/appdata.h +++ b/companion/src/storage/appdata.h @@ -38,20 +38,21 @@ #include #include -//! CPN_SETTINGS_REVISION is used to track settings changes independently of OpenTX version. It should be reset to zero whenever settings are migrated to new COMPANY or PRODUCT. +//! CPN_SETTINGS_REVISION is used to track settings changes independently of EdgeTX version. It should be reset to zero whenever settings are migrated to new COMPANY or PRODUCT. //! \note !! Increment this value if properties are removed or refactored. It will trigger a conversion/cleanup of any stored settings. \sa AppData::convertSettings() -#define CPN_SETTINGS_REVISION 0 +#define CPN_SETTINGS_REVISION 1 // Note: bumped to ensure 2.7 Nightly version users also get upgraded //! CPN_SETTINGS_VERSION is used for settings data version tracking. #define CPN_SETTINGS_VERSION ((VERSION_NUMBER << 8) | CPN_SETTINGS_REVISION) #define COMPANY QStringLiteral("EdgeTX") #define COMPANY_DOMAIN QStringLiteral("edgetx.org") +#define PRODUCT_NO_VERS QStringLiteral("Companion") #define PRODUCT QStringLiteral("Companion " QT_STRINGIFY(VERSION_MAJOR) "." QT_STRINGIFY(VERSION_MINOR)) #define APP_COMPANION QStringLiteral("EdgeTX Companion") #define APP_SIMULATOR QStringLiteral("EdgeTX Simulator") -//! Default location for OpenTX-related user documents (settigns, logs, etc) +//! Default location for EdgeTX-related user documents (settigns, logs, etc) #define CPN_DOCUMENTS_LOCATION QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) % "/" % COMPANY //! Location for settings backup files. TODO: make option or remember last location. #define CPN_SETTINGS_BACKUP_DIR CPN_DOCUMENTS_LOCATION % "/backup" @@ -379,6 +380,7 @@ class Profile: public CompStoreObj PROPERTYSTR(sdPath) PROPERTYSTR(pBackupDir) + PROPERTY (int, defaultInternalModule, 0) PROPERTY4(int, channelOrder, "default_channel_order", 0) PROPERTY4(int, defaultMode, "default_mode", 1) PROPERTY (int, volumeGain, 10) diff --git a/companion/src/storage/categorized.cpp b/companion/src/storage/categorized.cpp index d659ae81f..4c3caf7c2 100644 --- a/companion/src/storage/categorized.cpp +++ b/companion/src/storage/categorized.cpp @@ -20,8 +20,49 @@ #include "categorized.h" #include "firmwares/opentx/opentxinterface.h" +#include "firmwares/edgetx/edgetxinterface.h" +#include "miniz.c" // Can only be included once! + +#include bool CategorizedStorageFormat::load(RadioData & radioData) +{ + StorageType st = getStorageType(filename); + if (st == STORAGE_TYPE_UNKNOWN) { + st = probeFormat(); + } + if (st == STORAGE_TYPE_ETX || st == STORAGE_TYPE_YML) { + return loadYaml(radioData); + } else { + return loadBin(radioData); + } +} + +bool CategorizedStorageFormat::write(const RadioData & radioData) +{ + StorageType st = getStorageType(filename); + if (st == STORAGE_TYPE_UNKNOWN) { + st = probeFormat(); + } + if (st == STORAGE_TYPE_ETX || st == STORAGE_TYPE_YML || + st == STORAGE_TYPE_UNKNOWN) { + return writeYaml(radioData); + } else { + return writeBin(radioData); + } +} + +StorageType CategorizedStorageFormat::probeFormat() +{ + if (QFile(filename + "/RADIO/radio.yml").exists()) // converted + return getStorageType("radio.yml"); + else if (QFile(filename + "/RADIO/radio.bin").exists()) // unconverted + return getStorageType("radio.bin"); + else + return getStorageType(filename); +} + +bool CategorizedStorageFormat::loadBin(RadioData & radioData) { QByteArray radioSettingsBuffer; if (!loadFile(radioSettingsBuffer, "RADIO/radio.bin")) { @@ -113,7 +154,7 @@ bool CategorizedStorageFormat::load(RadioData & radioData) return true; } -bool CategorizedStorageFormat::write(const RadioData & radioData) +bool CategorizedStorageFormat::writeBin(const RadioData & radioData) { QByteArray modelsList; // models.txt QByteArray radioSettingsData; // radio.bin @@ -145,7 +186,7 @@ bool CategorizedStorageFormat::write(const RadioData & radioData) if (!getCurrentFirmware()->getCapability(HasModelCategories)) { // Use format with model number and file name. This is needed because // radios without category support can have unused model slots - modelsList.append(QString("%1 %2\n").arg(m).arg(model.filename)); + modelsList.append(QString("%1 %2\n").arg(m).arg(model.filename).toLocal8Bit()); } else { sortedModels[model.category].push_back(QString("%1\n").arg(model.filename)); } @@ -153,10 +194,12 @@ bool CategorizedStorageFormat::write(const RadioData & radioData) if (getCurrentFirmware()->getCapability(HasModelCategories)) { for (size_t c=0; c filelist; + if (!getFileList(filelist)) { + setError(tr("Can't list files")); + return false; + } + + const std::regex yml_regex("MODELS/(model([0-9]+)\\.yml)"); + for(const auto& f : filelist) { + std::smatch match; + if (std::regex_match(f, match, yml_regex)) { + if (match.size() == 3) { + std::ssub_match modelFile = match[1]; + std::ssub_match modelIdx = match[2]; + modelFiles.push_back({ modelFile.str(), "", 0, std::stoi(modelIdx.str()) }); + } + } + } + } + + radioData.models.resize(modelFiles.size()); + for (const auto& mc : modelFiles) { + qDebug() << "Filename: " << mc.filename.c_str() << " / Category: " << mc.category; + + QByteArray modelBuffer; + QString filename = "MODELS/" + QString::fromStdString(mc.filename); + if (!loadFile(modelBuffer, filename)) { + setError(tr("Can't extract ") + filename); + return false; + } + + // Please note: + // ModelData() use memset to clear everything to 0 + // + auto& model = radioData.models[mc.modelIdx]; + + try { + if (!loadModelFromYaml(model,modelBuffer)) { + setError(tr("Can't load ") + filename); + return false; + } + } catch(const std::runtime_error& e) { + setError(tr("Can't load ") + filename + ":\n" + QString(e.what())); + return false; + } + + model.category = mc.category; + model.modelIndex = mc.modelIdx; + strncpy(model.filename, mc.filename.c_str(), sizeof(model.filename)-1); + + model.used = true; + } + + return true; +} + +bool CategorizedStorageFormat::writeYaml(const RadioData & radioData) +{ + QByteArray radioSettingsBuffer; + if (!writeRadioSettingsToYaml(radioData.generalSettings, radioSettingsBuffer)) { + return false; + } + + if (!writeFile(radioSettingsBuffer, "RADIO/radio.yml")) { + return false; + } + + bool hasCategories = getCurrentFirmware()->getCapability(HasModelCategories); + + EtxModelfiles modelFiles; + for (const auto& model : radioData.models) { + + if (model.isEmpty()) + continue; + + QString modelFilename; + if (hasCategories) { + std::string ymlFilename = patchFilenameToYaml(model.filename); + modelFilename = + QString("MODELS/%1").arg(QString::fromStdString(ymlFilename)); + modelFiles.push_back( + {ymlFilename, std::string(model.name), model.category}); + } else { + modelFilename = QString("MODELS/model%1.yml") + .arg(model.modelIndex, 2, 10, QLatin1Char('0')); + } + + QByteArray modelData; + writeModelToYaml(model, modelData); + if (!writeFile(modelData, modelFilename)) { + return false; + } + } + + if (hasCategories) { + // TODO: sort 'modelFiles' by category index + QByteArray modelslistBuffer; + if (!writeModelsListToYaml(radioData.categories, modelFiles, modelslistBuffer) + || !writeFile(modelslistBuffer, "MODELS/models.yml")) { + return false; + } + } + + return true; +} diff --git a/companion/src/storage/categorized.h b/companion/src/storage/categorized.h index 4eb624321..c14769d27 100644 --- a/companion/src/storage/categorized.h +++ b/companion/src/storage/categorized.h @@ -24,6 +24,8 @@ #include "storage.h" #include +#include +#include class CategorizedStorageFormat : public StorageFormat { @@ -41,6 +43,14 @@ class CategorizedStorageFormat : public StorageFormat protected: virtual bool loadFile(QByteArray & fileData, const QString & fileName) = 0; virtual bool writeFile(const QByteArray & fileData, const QString & fileName) = 0; + virtual bool getFileList(std::list& filelist) = 0; + + virtual bool loadBin(RadioData & radioData); + virtual bool writeBin(const RadioData & radioData); + virtual bool loadYaml(RadioData & radioData); + virtual bool writeYaml(const RadioData & radioData); + + StorageType probeFormat(); }; #endif // _CATEGORIZED_H_ diff --git a/companion/src/storage/etx.cpp b/companion/src/storage/etx.cpp new file mode 100644 index 000000000..8ec2085ef --- /dev/null +++ b/companion/src/storage/etx.cpp @@ -0,0 +1,130 @@ +/* + * 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 "etx.h" +#include + +#define MZ_ALLOCATION_SIZE (32*1024) + +bool EtxFormat::load(RadioData & radioData) +{ + QFile file(filename); + + if (!file.open(QFile::ReadOnly)) { + setError(tr("Error opening file %1:\n%2.").arg(filename).arg(file.errorString())); + return false; + } + + QByteArray archiveContents = file.readAll(); + + qDebug() << "File" << filename << "read, size:" << archiveContents.size(); + + // open zip file + memset(&zip_archive, 0, sizeof(zip_archive)); + if (!mz_zip_reader_init_mem(&zip_archive, archiveContents.data(), archiveContents.size(), 0)) { + qDebug() << tr("Error opening EdgeTX archive %1").arg(filename); + return false; + } + + bool result = CategorizedStorageFormat::load(radioData); + mz_zip_reader_end(&zip_archive); + return result; +} + +bool EtxFormat::write(const RadioData & radioData) +{ + qDebug() << "Saving to archive" << filename; + + memset(&zip_archive, 0, sizeof(zip_archive)); + if (!mz_zip_writer_init_heap(&zip_archive, 0, MZ_ALLOCATION_SIZE)) { + setError(tr("Error initializing EdgeTX archive writer")); + return false; + } + + bool result = CategorizedStorageFormat::write(radioData); + if (result) { + // finalize archive and get contents + char * archiveContents; + size_t archiveSize; + if (mz_zip_writer_finalize_heap_archive(&zip_archive, (void **)&archiveContents, &archiveSize)) { + qDebug() << "Archive size" << archiveSize; + // write contents to file + QFile file(filename); + if (file.open(QIODevice::WriteOnly)) { + qint64 len = file.write(archiveContents, archiveSize); + if (len != (qint64)archiveSize) { + setError(tr("Error writing file %1:\n%2.").arg(filename).arg(file.errorString())); + result = false; + } + } + else { + setError(tr("Error creating EdgeTX file %1:\n%2.").arg(filename).arg(file.errorString())); + result = false; + } + } + else { + setError(tr("Error creating EdgeTX archive")); + result = false; + } + } + + mz_zip_writer_end(&zip_archive); + return result; +} + +bool EtxFormat::loadFile(QByteArray & filedata, const QString & filename) +{ + size_t size; + void * data = mz_zip_reader_extract_file_to_heap(&zip_archive, qPrintable(filename), &size, 0); + if (!data) { + return false; + } + + qDebug() << QString("Extracted file %1, size=%2").arg(filename).arg(size); + filedata.clear(); + filedata.append((char *)data, size); + mz_free(data); + return true; +} + +bool EtxFormat::writeFile(const QByteArray & filedata, const QString & filename) +{ + if (!mz_zip_writer_add_mem(&zip_archive, filename.toStdString().c_str(), filedata.data(), filedata.size(), MZ_DEFAULT_LEVEL)) { + setError(tr("Error adding %1 to EdgeTX archive").arg(filename)); + return false; + } + + return true; +} + +bool EtxFormat::getFileList(std::list& filelist) +{ + int count = (int)mz_zip_reader_get_num_files(&zip_archive); + if (count == 0) return false; + + mz_zip_archive_file_stat file_stat; + for (int i=0; i + +#define MINIZ_HEADER_FILE_ONLY +#include "miniz.c" +#undef MINIZ_HEADER_FILE_ONLY + +class EtxFormat : public CategorizedStorageFormat +{ + Q_DECLARE_TR_FUNCTIONS(EtxFormat) + + public: + EtxFormat(const QString & filename): + CategorizedStorageFormat(filename) + { + } + + virtual QString name() { return "etx"; } + virtual bool load(RadioData & radioData); + virtual bool write(const RadioData & radioData); + + protected: + virtual bool loadFile(QByteArray & fileData, const QString & fileName); + virtual bool writeFile(const QByteArray & fileData, const QString & fileName); + virtual bool getFileList(std::list& filelist); + + mz_zip_archive zip_archive; +}; + +#endif // _ETX_H_ diff --git a/companion/src/storage/firmwareinterface.cpp b/companion/src/storage/firmwareinterface.cpp index 4357928d1..79ca4a2fe 100644 --- a/companion/src/storage/firmwareinterface.cpp +++ b/companion/src/storage/firmwareinterface.cpp @@ -305,11 +305,11 @@ bool FirmwareInterface::seekSplash(QByteArray sps, QByteArray spe, int size) return false; } -#define OTX_SPS_9X "SPS\0\200\100" -#define OTX_SPS_TARANIS "SPS\0\324\100" -#define OTX_SPS_SIZE 6 -#define OTX_SPE "SPE" -#define OTX_SPE_SIZE 4 +#define ETX_SPS_9X "SPS\0\200\100" +#define ETX_SPS_TARANIS "SPS\0\324\100" +#define ETX_SPS_SIZE 6 +#define ETX_SPE "SPE" +#define ETX_SPE_SIZE 4 void FirmwareInterface::seekSplash() { @@ -342,11 +342,11 @@ void FirmwareInterface::seekSplash() return; } - if (seekSplash(QByteArray(OTX_SPS_9X, OTX_SPS_SIZE), QByteArray(OTX_SPE, OTX_SPE_SIZE), 1024)) { + if (seekSplash(QByteArray(ETX_SPS_9X, ETX_SPS_SIZE), QByteArray(ETX_SPE, ETX_SPE_SIZE), 1024)) { return; } - if (seekSplash(QByteArray(OTX_SPS_TARANIS, OTX_SPS_SIZE), QByteArray(OTX_SPE, OTX_SPE_SIZE), RLE_SPLASH_MAX_SIZE)) { + if (seekSplash(QByteArray(ETX_SPS_TARANIS, ETX_SPS_SIZE), QByteArray(ETX_SPE, ETX_SPE_SIZE), RLE_SPLASH_MAX_SIZE)) { splashWidth = SPLASHX9D_WIDTH; splashHeight = SPLASHX9D_HEIGHT; splash_format = QImage::Format_Indexed8; diff --git a/companion/src/storage/otx.cpp b/companion/src/storage/otx.cpp index 90ea2bbf8..44dbd9ef2 100644 --- a/companion/src/storage/otx.cpp +++ b/companion/src/storage/otx.cpp @@ -19,7 +19,6 @@ */ #include "otx.h" -#include "miniz.c" #include #define MZ_ALLOCATION_SIZE (32*1024) @@ -40,7 +39,7 @@ bool OtxFormat::load(RadioData & radioData) // open zip file memset(&zip_archive, 0, sizeof(zip_archive)); if (!mz_zip_reader_init_mem(&zip_archive, archiveContents.data(), archiveContents.size(), 0)) { - qDebug() << tr("Error opening OTX archive %1").arg(filename); + qDebug() << tr("Error opening OpenTX archive %1").arg(filename); return false; } @@ -55,7 +54,7 @@ bool OtxFormat::write(const RadioData & radioData) memset(&zip_archive, 0, sizeof(zip_archive)); if (!mz_zip_writer_init_heap(&zip_archive, 0, MZ_ALLOCATION_SIZE)) { - setError(tr("Error initializing OTX archive writer")); + setError(tr("Error initializing OpenTX archive writer")); return false; } @@ -76,12 +75,12 @@ bool OtxFormat::write(const RadioData & radioData) } } else { - setError(tr("Error creating OTX file %1:\n%2.").arg(filename).arg(file.errorString())); + setError(tr("Error creating OpenTX file %1:\n%2.").arg(filename).arg(file.errorString())); result = false; } } else { - setError(tr("Error creating OTX archive")); + setError(tr("Error creating OpenTX archive")); result = false; } } @@ -108,7 +107,7 @@ bool OtxFormat::loadFile(QByteArray & filedata, const QString & filename) bool OtxFormat::writeFile(const QByteArray & filedata, const QString & filename) { if (!mz_zip_writer_add_mem(&zip_archive, filename.toStdString().c_str(), filedata.data(), filedata.size(), MZ_DEFAULT_LEVEL)) { - setError(tr("Error adding %1 to OTX archive").arg(filename)); + setError(tr("Error adding %1 to OpenTX archive").arg(filename)); return false; } diff --git a/companion/src/storage/otx.h b/companion/src/storage/otx.h index da4923488..37739074c 100644 --- a/companion/src/storage/otx.h +++ b/companion/src/storage/otx.h @@ -46,6 +46,7 @@ class OtxFormat : public CategorizedStorageFormat protected: virtual bool loadFile(QByteArray & fileData, const QString & fileName); virtual bool writeFile(const QByteArray & fileData, const QString & fileName); + virtual bool getFileList(std::list& filelist) { return false; } mz_zip_archive zip_archive; }; diff --git a/companion/src/storage/sdcard.cpp b/companion/src/storage/sdcard.cpp index 7c60a7155..c58c4bf84 100644 --- a/companion/src/storage/sdcard.cpp +++ b/companion/src/storage/sdcard.cpp @@ -57,8 +57,19 @@ bool SdcardFormat::writeFile(const QByteArray & data, const QString & filename) return true; } +bool SdcardFormat::getFileList(std::list& filelist) +{ + QDir dir(filename); + if (!dir.cd("MODELS")) return false; + + QStringList ql = dir.entryList(); + for (const auto& str : ql) { + filelist.push_back("MODELS/" + str.toStdString()); + } + return true; +} + bool SdcardStorageFactory::probe(const QString & path) { return QDir(path).exists(); } - diff --git a/companion/src/storage/sdcard.h b/companion/src/storage/sdcard.h index 1d7d813d2..cc6230a9b 100644 --- a/companion/src/storage/sdcard.h +++ b/companion/src/storage/sdcard.h @@ -41,6 +41,7 @@ class SdcardFormat : public CategorizedStorageFormat protected: virtual bool loadFile(QByteArray & fileData, const QString & fileName); virtual bool writeFile(const QByteArray & fileData, const QString & fileName); + virtual bool getFileList(std::list& filelist); }; class SdcardStorageFactory : public DefaultStorageFactory diff --git a/companion/src/storage/storage.cpp b/companion/src/storage/storage.cpp index 63a5f429e..ad7a7eabd 100644 --- a/companion/src/storage/storage.cpp +++ b/companion/src/storage/storage.cpp @@ -21,6 +21,7 @@ #include "bineeprom.h" #include "eepe.h" #include "otx.h" +#include "etx.h" #include "sdcard.h" #include "yaml.h" #include "firmwareinterface.h" @@ -42,6 +43,8 @@ StorageType getStorageType(const QString & filename) return STORAGE_TYPE_XML; else if (suffix == "OTX") return STORAGE_TYPE_OTX; + else if (suffix == "ETX") + return STORAGE_TYPE_ETX; else if (suffix == "YML") return STORAGE_TYPE_YML; else @@ -64,6 +67,7 @@ void registerStorageFactories() registerStorageFactory(new DefaultStorageFactory("eepe")); registerStorageFactory(new DefaultStorageFactory("hex")); registerStorageFactory(new DefaultStorageFactory("otx")); + registerStorageFactory(new DefaultStorageFactory("etx")); registerStorageFactory(new DefaultStorageFactory("yml")); registerStorageFactory(new SdcardStorageFactory()); } @@ -84,17 +88,20 @@ bool Storage::load(RadioData & radioData) bool ret = false; foreach(StorageFactory * factory, registeredStorageFactories) { - StorageFormat * format = factory->instance(filename); - if (format->load(radioData)) { - board = format->getBoard(); - setWarning(format->warning()); - ret = true; - break; + if (factory->probe(filename)) { + StorageFormat * format = factory->instance(filename); + if (format->load(radioData)) { + board = format->getBoard(); + setWarning(format->warning()); + ret = true; + delete format; + break; + } + else { + setError(format->error()); + } + delete format; } - else { - setError(format->error()); - } - delete format; } return ret; diff --git a/companion/src/storage/storage.h b/companion/src/storage/storage.h index f9843650e..d321aeb02 100644 --- a/companion/src/storage/storage.h +++ b/companion/src/storage/storage.h @@ -37,6 +37,7 @@ enum StorageType STORAGE_TYPE_XML, STORAGE_TYPE_SDCARD, STORAGE_TYPE_OTX, + STORAGE_TYPE_ETX, STORAGE_TYPE_YML }; diff --git a/companion/src/storage/yaml.cpp b/companion/src/storage/yaml.cpp index 9be4b5ef0..d404f9acd 100644 --- a/companion/src/storage/yaml.cpp +++ b/companion/src/storage/yaml.cpp @@ -19,7 +19,6 @@ */ #include "yaml.h" -#include "../../../radio/src/storage/yaml/yaml_tree_walker.h" // just to confirm valid compiler path #include #include diff --git a/companion/src/tests/conversions.cpp b/companion/src/tests/conversions.cpp index 8317d6ef3..b68fc0969 100644 --- a/companion/src/tests/conversions.cpp +++ b/companion/src/tests/conversions.cpp @@ -1,6 +1,6 @@ #include "gtests.h" #include "location.h" -#include "storage/otx.h" +#include "storage/etx.h" #include "storage/storage.h" #include "firmwares/opentx/opentxinterface.h" #include "firmwares/customfunctiondata.h" @@ -210,12 +210,12 @@ TEST(Conversions, ConversionX10From22) { QByteArray byteBuffer; -#define USE_OTX +#define USE_ETX -#if defined(USE_OTX) - OtxFormat otx(RADIO_TESTS_PATH "/model_22_x10.otx"); +#if defined(USE_ETX) + EtxFormat etx(RADIO_TESTS_PATH "/model_22_x10.etx"); RadioData radio; - EXPECT_EQ(true, otx.load(radio)); + EXPECT_EQ(true, etx.load(radio)); const GeneralSettings& settings = radio.generalSettings; const ModelData& model = radio.models[0]; @@ -253,7 +253,7 @@ TEST(Conversions, ConversionX10From22) EXPECT_STREQ("BT_X10", settings.bluetoothName); EXPECT_STREQ("EdgeTX", settings.themeData.themeName); -#if !defined(USE_OTX) +#if !defined(USE_ETX) byteBuffer.clear(); ASSERT_EQ(true, loadFile(byteBuffer, RADIO_TESTS_PATH "/model_22_x10/MODELS/model1.bin")); @@ -295,12 +295,12 @@ TEST(Conversions, ConversionX12SFrom22) { QByteArray byteBuffer; -#define USE_OTX +#define USE_ETX -#if defined(USE_OTX) - OtxFormat otx(RADIO_TESTS_PATH "/model_22_x12s.otx"); +#if defined(USE_ETX) + EtxFormat etx(RADIO_TESTS_PATH "/model_22_x12s.etx"); RadioData radio; - EXPECT_EQ(true, otx.load(radio)); + EXPECT_EQ(true, etx.load(radio)); const GeneralSettings& settings = radio.generalSettings; const ModelData& model = radio.models[0]; @@ -330,7 +330,7 @@ TEST(Conversions, ConversionX12SFrom22) EXPECT_STREQ("BT", settings.bluetoothName); EXPECT_STREQ("EdgeTX", settings.themeData.themeName); -#if !defined(USE_OTX) +#if !defined(USE_ETX) byteBuffer.clear(); ASSERT_EQ(true, loadFile(byteBuffer, RADIO_TESTS_PATH "/model_22_x10/MODELS/model1.bin")); diff --git a/companion/src/thirdparty/yaml-cpp b/companion/src/thirdparty/yaml-cpp new file mode 160000 index 000000000..9a3624205 --- /dev/null +++ b/companion/src/thirdparty/yaml-cpp @@ -0,0 +1 @@ +Subproject commit 9a3624205e8774953ef18f57067b3426c1c5ada6 diff --git a/companion/targets/windows/companion.nsi.in b/companion/targets/windows/companion.nsi.in index 4db7bc587..81c04314e 100644 --- a/companion/targets/windows/companion.nsi.in +++ b/companion/targets/windows/companion.nsi.in @@ -104,7 +104,7 @@ Section "EdgeTX Companion @VERSION_FAMILY@" SecDummy - Delete "$INSTDIR\opentx-*-simulator.dll" + Delete "$INSTDIR\edgetx-*-simulator.dll" RMDir /r "$INSTDIR\lang" RMDir /r "$INSTDIR\phonon_backend" @@ -116,8 +116,8 @@ Section "EdgeTX Companion @VERSION_FAMILY@" SecDummy ;Store installation folder WriteRegStr HKCU "Software\EdgeTX\Companion @VERSION_FAMILY@" "" $INSTDIR - ;Associate with extentions .otx - ${registerExtension} "$INSTDIR\companion.exe" ".otx" "EdgeTX Settings File" + ;Associate with extentions .etx + ${registerExtension} "$INSTDIR\companion.exe" ".etx" "EdgeTX Settings File" ;Create uninstaller WriteUninstaller "$INSTDIR\Uninstall.exe" @@ -177,7 +177,7 @@ Section "un.EdgeTX Companion @VERSION_FAMILY@" Delete "$INSTDIR\license.txt" Delete "$INSTDIR\companion.exe" Delete "$INSTDIR\simulator.exe" - Delete "$INSTDIR\*opentx-*-simulator.dll" + Delete "$INSTDIR\*edgetx-*-simulator.dll" Delete "$INSTDIR\SDL.dll" ; MSVC-specific libs Delete "$INSTDIR\msvcp140.dll" @@ -218,10 +218,7 @@ Section "un.EdgeTX Companion @VERSION_FAMILY@" RMDir "$INSTDIR" - ${unregisterExtension} ".bin" "BIN File" - ${unregisterExtension} ".hex" "HEX File" - ${unregisterExtension} ".eepm" "EEPE File" - ${unregisterExtension} ".otx" "EdgeTX Settings File" + ${unregisterExtension} ".etx" "EdgeTX Settings File" !insertmacro MUI_STARTMENU_GETFOLDER Application $StartMenuFolder @@ -275,7 +272,7 @@ Function StartMenuLocationCreator ${NSD_CreateLabel} 0u 0u 100% 12u $(SML_MainLabel) Pop $R0 - ${NSD_CreateRadioButton} 8u 20u 100% 12u $(SML_RadioCurrent) + ${NSD_CreateRadioButton} 8u 20u 100% 12u $(SML_RadioCurrent) Pop $StartMenuLocationRadioCurrent ${NSD_AddStyle} $StartMenuLocationRadioCurrent ${WS_GROUP} @@ -284,7 +281,7 @@ Function StartMenuLocationCreator ${If} $StartMenuLocationValue == "all_users" ${NSD_SetState} $StartMenuLocationRadioAll ${BST_CHECKED} - ${Else} + ${Else} ${NSD_SetState} $StartMenuLocationRadioCurrent ${BST_CHECKED} ${EndIf} diff --git a/radio/src/dataconstants.h b/radio/src/dataconstants.h index 356fc20f8..e24a035c6 100644 --- a/radio/src/dataconstants.h +++ b/radio/src/dataconstants.h @@ -240,10 +240,9 @@ enum TrainerMode { #endif enum UartModes { -#if defined(CLI) || defined(DEBUG) - UART_MODE_DEBUG, -#else UART_MODE_NONE, +#if defined(CLI) || defined(DEBUG) + UART_MODE_DEBUG SKIP = UART_MODE_NONE, #endif UART_MODE_TELEMETRY_MIRROR, UART_MODE_TELEMETRY, diff --git a/radio/src/datastructs_private.h b/radio/src/datastructs_private.h index c4453ee69..f2cd1fc32 100644 --- a/radio/src/datastructs_private.h +++ b/radio/src/datastructs_private.h @@ -65,7 +65,7 @@ PACK(struct CurveRef { uint8_t type; - int8_t value; + int8_t value CUST(in_read_weight,in_write_weight); }); PACK(struct MixData { @@ -76,7 +76,7 @@ PACK(struct MixData { uint16_t mixWarn:2; // mixer warning uint16_t mltpx:2 ENUM(MixerMultiplex); uint16_t spare:1 SKIP; - int32_t offset:14; + int32_t offset:14 CUST(in_read_weight,in_write_weight); int32_t swtch:9 CUST(r_swtchSrc,w_swtchSrc); uint32_t flightModes:9 CUST(r_flightModes, w_flightModes); CurveRef curve; @@ -102,7 +102,7 @@ PACK(struct ExpoData { int32_t weight:8 CUST(in_read_weight,in_write_weight); int32_t spare:1 SKIP; NOBACKUP(char name[LEN_EXPOMIX_NAME]); - int8_t offset; + int8_t offset CUST(in_read_weight,in_write_weight); CurveRef curve; }); @@ -111,10 +111,10 @@ PACK(struct ExpoData { */ PACK(struct LimitData { - int32_t min:11; - int32_t max:11; + int32_t min:11 CUST(in_read_weight,in_write_weight); + int32_t max:11 CUST(in_read_weight,in_write_weight); int32_t ppmCenter:10; // TODO can be reduced to 8 bits - int16_t offset:11; + int16_t offset:11 CUST(in_read_weight,in_write_weight); uint16_t symetrical:1; uint16_t revert:1; uint16_t spare:3 SKIP; @@ -834,6 +834,7 @@ PACK(struct RadioData { // Real attributes NOBACKUP(uint8_t version); + CUST_ATTR(board,nullptr,w_board); NOBACKUP(uint16_t variant SKIP); CalibData calib[NUM_STICKS + STORAGE_NUM_POTS + STORAGE_NUM_SLIDERS + STORAGE_NUM_MOUSE_ANALOGS] NO_IDX; NOBACKUP(uint16_t chkSum SKIP); @@ -867,12 +868,10 @@ PACK(struct RadioData { NOBACKUP(uint8_t templateSetup); // RETA order for receiver channels NOBACKUP(int8_t PPM_Multiplier); NOBACKUP(int8_t hapticLength CUST(r_5pos,w_5pos)); - N_HORUS_FIELD(N_TARANIS_FIELD(uint8_t spare2 SKIP)); - N_HORUS_FIELD(N_TARANIS_FIELD(uint8_t stickReverse)); NOBACKUP(int8_t beepLength:3 CUST(r_5pos,w_5pos)); NOBACKUP(int8_t hapticStrength:3 CUST(r_5pos,w_5pos)); NOBACKUP(uint8_t gpsFormat:1); - NOBACKUP(uint8_t unexpectedShutdown:1); + NOBACKUP(uint8_t unexpectedShutdown:1 SKIP); NOBACKUP(uint8_t speakerPitch CUST(r_spPitch,w_spPitch)); NOBACKUP(int8_t speakerVolume CUST(r_vol,w_vol)); NOBACKUP(int8_t vBatMin CUST(r_vbat_min,w_vbat_min)); diff --git a/radio/src/lua/api_general.cpp b/radio/src/lua/api_general.cpp index 354cdd1c8..c4b006b3e 100644 --- a/radio/src/lua/api_general.cpp +++ b/radio/src/lua/api_general.cpp @@ -1507,7 +1507,7 @@ then the loaded script (or "chunk") is returned as a function. Otherwise, return as part of the file name and the .lua/.luac will be appended to that. @param mode (string) (optional) Controls whether to force loading the text (.lua) or pre-compiled binary (.luac) - version of the script. By default OTx will load the newest version and compile a new binary if necessary (overwriting any + version of the script. By default ETX will load the newest version and compile a new binary if necessary (overwriting any existing .luac version of the same script, and stripping some debug info like line numbers). You can use `mode` to control the loading behavior more specifically. Possible values are: * `b` only binary. diff --git a/radio/src/lua/api_model.cpp b/radio/src/lua/api_model.cpp index e9dc36eb3..07f9f6832 100644 --- a/radio/src/lua/api_model.cpp +++ b/radio/src/lua/api_model.cpp @@ -158,7 +158,7 @@ static int luaModelGetModule(lua_State *L) if (module.type == MODULE_TYPE_MULTIMODULE) { int protocol = g_model.moduleData[idx].getMultiProtocol() + 1; int subprotocol = g_model.moduleData[idx].subType; - convertOtxProtocolToMulti(&protocol, &subprotocol); // Special treatment for the FrSky entry... + convertEtxProtocolToMulti(&protocol, &subprotocol); // Special treatment for the FrSky entry... lua_pushtableinteger(L, "protocol", protocol); lua_pushtableinteger(L, "subProtocol", subprotocol); if (getMultiModuleStatus(idx).isValid()) { @@ -231,8 +231,8 @@ static int luaModelSetModule(lua_State *L) #endif } #if defined(MULTIMODULE) - if (protocol > 0 && subprotocol >= 0) { // Both are needed to compute otx protocol - convertMultiProtocolToOtx(&protocol, &subprotocol); + if (protocol > 0 && subprotocol >= 0) { // Both are needed to compute etx protocol + convertMultiProtocolToEtx(&protocol, &subprotocol); g_model.moduleData[idx].setMultiProtocol(protocol - 1); g_model.moduleData[idx].subType = subprotocol; } diff --git a/radio/src/pulses/multi.cpp b/radio/src/pulses/multi.cpp index 93a2a2dfa..cb2bfdd9d 100644 --- a/radio/src/pulses/multi.cpp +++ b/radio/src/pulses/multi.cpp @@ -53,7 +53,7 @@ static void sendDSM(uint8_t moduleIdx); void multiPatchCustom(uint8_t moduleIdx) { if (g_model.moduleData[moduleIdx].multi.customProto) { - uint8_t type = g_model.moduleData[moduleIdx].getMultiProtocol() - 1; // custom where starting at 1, otx list at 0 + uint8_t type = g_model.moduleData[moduleIdx].getMultiProtocol() - 1; // custom where starting at 1, etx list at 0 int subtype = g_model.moduleData[moduleIdx].subType; g_model.moduleData[moduleIdx].multi.customProto = 0; @@ -268,7 +268,7 @@ void sendChannels(uint8_t moduleIdx) } } -void convertMultiProtocolToOtx(int *protocol, int *subprotocol) +void convertMultiProtocolToEtx(int *protocol, int *subprotocol) { if (*protocol == 3 && *subprotocol == 0) { *protocol = MODULE_SUBTYPE_MULTI_FRSKY + 1; @@ -312,7 +312,7 @@ void convertMultiProtocolToOtx(int *protocol, int *subprotocol) *protocol -= 1; } -void convertOtxProtocolToMulti(int *protocol, int *subprotocol) +void convertEtxProtocolToMulti(int *protocol, int *subprotocol) { // Special treatment for the FrSky entry... if (*protocol == MODULE_SUBTYPE_MULTI_FRSKY + 1) { @@ -407,7 +407,7 @@ void sendFrameProtocolHeader(uint8_t moduleIdx, bool failsafe) } // Special treatment for the FrSky entry... - convertOtxProtocolToMulti(&type, &subtype); + convertEtxProtocolToMulti(&type, &subtype); // Set the highest bit of option byte in AFHDS2A protocol to instruct MULTI to passthrough telemetry bytes instead // of sending Frsky D telemetry diff --git a/radio/src/pulses/multi.h b/radio/src/pulses/multi.h index d9a50d318..756fcf28a 100644 --- a/radio/src/pulses/multi.h +++ b/radio/src/pulses/multi.h @@ -25,8 +25,8 @@ #include "pulses_common.h" void multiPatchCustom(uint8_t moduleIdx); -void convertOtxProtocolToMulti(int *protocol, int *subprotocol); -void convertMultiProtocolToOtx(int *protocol, int *subprotocol); +void convertEtxProtocolToMulti(int *protocol, int *subprotocol); +void convertMultiProtocolToEtx(int *protocol, int *subprotocol); class UartMultiPulses: public DataBuffer { diff --git a/radio/src/sdcard.h b/radio/src/sdcard.h index 43896b690..51873d4b8 100644 --- a/radio/src/sdcard.h +++ b/radio/src/sdcard.h @@ -133,45 +133,45 @@ inline const char * SDCARD_ERROR(FRESULT result) const char * getBasename(const char * path); #if defined(PCBX12S) - #define OTX_FOURCC 0x3478746F // otx for X12S + #define ETX_FOURCC 0x3478746F // etx for X12S #elif defined(RADIO_T16) - #define OTX_FOURCC 0x3F78746F // otx for Jumper T16 + #define ETX_FOURCC 0x3F78746F // etx for Jumper T16 #elif defined(RADIO_T18) - #define OTX_FOURCC 0x4078746F // otx for Jumper T18 + #define ETX_FOURCC 0x4078746F // etx for Jumper T18 #elif defined(RADIO_TX16S) - #define OTX_FOURCC 0x3878746F // otx for Radiomaster TX16S + #define ETX_FOURCC 0x3878746F // etx for Radiomaster TX16S #elif defined(PCBX10) - #define OTX_FOURCC 0x3778746F // otx for X10 + #define ETX_FOURCC 0x3778746F // etx for X10 #elif defined(PCBX9E) - #define OTX_FOURCC 0x3578746F // otx for Taranis X9E + #define ETX_FOURCC 0x3578746F // etx for Taranis X9E #elif defined(PCBXLITES) - #define OTX_FOURCC 0x3B78746F // otx for Taranis X-Lite S + #define ETX_FOURCC 0x3B78746F // etx for Taranis X-Lite S #elif defined(PCBXLITE) - #define OTX_FOURCC 0x3978746F // otx for Taranis X-Lite + #define ETX_FOURCC 0x3978746F // etx for Taranis X-Lite #elif defined(RADIO_T12) - #define OTX_FOURCC 0x3D78746F // otx for Jumper T12 + #define ETX_FOURCC 0x3D78746F // etx for Jumper T12 #elif defined(RADIO_TLITE) - #define OTX_FOURCC 0x4278746F // otx for Jumper TLite + #define ETX_FOURCC 0x4278746F // etx for Jumper TLite #elif defined(RADIO_TPRO) - #define OTX_FOURCC 0x4678746F // otx for Jumper TPro + #define ETX_FOURCC 0x4678746F // etx for Jumper TPro #elif defined(RADIO_TX12) - #define OTX_FOURCC 0x4178746F // otx for Radiomaster TX12 + #define ETX_FOURCC 0x4178746F // etx for Radiomaster TX12 #elif defined(RADIO_ZORRO) - #define OTX_FOURCC 0x4778746F // otx for Radiomaster Zorro + #define ETX_FOURCC 0x4778746F // otx for Radiomaster Zorro #elif defined(RADIO_T8) - #define OTX_FOURCC 0x4378746F // otx for Radiomaster T8 + #define ETX_FOURCC 0x4378746F // etx for Radiomaster T8 #elif defined(PCBX7) - #define OTX_FOURCC 0x3678746F // otx for Taranis X7 / X7S / X7 Express / X7S Express + #define ETX_FOURCC 0x3678746F // etx for Taranis X7 / X7S / X7 Express / X7S Express #elif defined(PCBX9LITES) - #define OTX_FOURCC 0x3E78746F // otx for Taranis X9-Lite S + #define ETX_FOURCC 0x3E78746F // etx for Taranis X9-Lite S #elif defined(PCBX9LITE) - #define OTX_FOURCC 0x3C78746F // otx for Taranis X9-Lite + #define ETX_FOURCC 0x3C78746F // etx for Taranis X9-Lite #elif defined(PCBX9D) || defined(PCBX9DP) - #define OTX_FOURCC 0x3378746F // otx for Taranis X9D + #define ETX_FOURCC 0x3378746F // etx for Taranis X9D #elif defined(PCBNV14) - #define OTX_FOURCC 0x3A78746F // otx for NV14 + #define ETX_FOURCC 0x3A78746F // etx for NV14 #elif defined(PCBSKY9X) - #define OTX_FOURCC 0x3278746F // otx for sky9x + #define ETX_FOURCC 0x3278746F // etx for sky9x #endif bool isFileAvailable(const char * filename, bool exclDir = false); diff --git a/radio/src/storage/conversions/yaml/yaml_datastructs_funcs.cpp b/radio/src/storage/conversions/yaml/yaml_datastructs_funcs.cpp index 0894b995e..6d66fcf45 100644 --- a/radio/src/storage/conversions/yaml/yaml_datastructs_funcs.cpp +++ b/radio/src/storage/conversions/yaml/yaml_datastructs_funcs.cpp @@ -23,21 +23,27 @@ #include "datastructs_220.h" #include "myeeprom_220.h" -#define GVAR_SMALL 128 #define VOLUME_LEVEL_DEF 12 +bool w_board(void* user, uint8_t* data, uint32_t bitoffs, + yaml_writer_func wf, void* opaque) +{ + return wf(opaque, FLAVOUR, sizeof(FLAVOUR)-1); +} + #define in_read_weight nullptr bool in_write_weight(const YamlNode* node, uint32_t val, yaml_writer_func wf, void* opaque) { int32_t sval = yaml_to_signed(val, node->size); + int32_t gvar = (node->size > 8 ? GV1_LARGE : GV1_SMALL); - if (sval > GVAR_SMALL - 11 && sval < GVAR_SMALL - 1) { - char n = GVAR_SMALL - sval + '0'; + if (sval >= gvar - 10 && sval <= gvar) { + char n = gvar - sval + '1'; return wf(opaque, "-GV", 3) && wf(opaque, &n, 1); - } else if (sval < -GVAR_SMALL + 11 && sval > -GVAR_SMALL + 1) { - char n = val - GVAR_SMALL + '1'; + } else if (sval <= -gvar + 10 && sval >= -gvar) { + char n = val - gvar + '1'; return wf(opaque, "GV", 2) && wf(opaque, &n, 1); } @@ -1132,7 +1138,7 @@ bool w_modSubtype(void* user, uint8_t* data, uint32_t bitoffs, // data as-is (no FrSky special casing) int type = md->getMultiProtocol() + 1; int subtype = val; - convertOtxProtocolToMulti(&type, &subtype); + convertEtxProtocolToMulti(&type, &subtype); // output "[type],[subtype]" str = yaml_unsigned2str(type); diff --git a/radio/src/storage/conversions/yaml/yaml_datastructs_nv14.cpp b/radio/src/storage/conversions/yaml/yaml_datastructs_nv14.cpp index 557bb9ad6..1b12702e3 100644 --- a/radio/src/storage/conversions/yaml/yaml_datastructs_nv14.cpp +++ b/radio/src/storage/conversions/yaml/yaml_datastructs_nv14.cpp @@ -357,6 +357,7 @@ static const struct YamlNode struct_OpenTxTheme__PersistentData[] = { }; static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "version", 8 ), + YAML_CUSTOM("board",nullptr,w_board), YAML_PADDING( 16 ), YAML_ARRAY("calib", 48, 9, struct_CalibData, NULL), YAML_PADDING( 16 ), @@ -394,7 +395,7 @@ static const struct YamlNode struct_RadioData[] = { YAML_SIGNED_CUST( "beepLength", 3, r_5pos, w_5pos ), YAML_SIGNED_CUST( "hapticStrength", 3, r_5pos, w_5pos ), YAML_UNSIGNED( "gpsFormat", 1 ), - YAML_UNSIGNED( "unexpectedShutdown", 1 ), + YAML_PADDING( 1 ), YAML_UNSIGNED_CUST( "speakerPitch", 8, r_spPitch, w_spPitch ), YAML_SIGNED_CUST( "speakerVolume", 8, r_vol, w_vol ), YAML_SIGNED_CUST( "vBatMin", 8, r_vbat_min, w_vbat_min ), @@ -465,7 +466,7 @@ static const struct YamlNode struct_TimerData[] = { }; static const struct YamlNode struct_CurveRef[] = { YAML_UNSIGNED( "type", 8 ), - YAML_SIGNED( "value", 8 ), + YAML_SIGNED_CUST( "value", 8, in_read_weight, in_write_weight ), YAML_END }; static const struct YamlNode struct_MixData[] = { @@ -476,7 +477,7 @@ static const struct YamlNode struct_MixData[] = { YAML_UNSIGNED( "mixWarn", 2 ), YAML_ENUM("mltpx", 2, enum_MixerMultiplex), YAML_PADDING( 1 ), - YAML_SIGNED( "offset", 14 ), + YAML_SIGNED_CUST( "offset", 14, in_read_weight, in_write_weight ), YAML_SIGNED_CUST( "swtch", 9, r_swtchSrc, w_swtchSrc ), YAML_UNSIGNED_CUST( "flightModes", 9, r_flightModes, w_flightModes ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), @@ -489,10 +490,10 @@ static const struct YamlNode struct_MixData[] = { }; static const struct YamlNode struct_LimitData[] = { YAML_IDX, - YAML_SIGNED( "min", 11 ), - YAML_SIGNED( "max", 11 ), + YAML_SIGNED_CUST( "min", 11, in_read_weight, in_write_weight ), + YAML_SIGNED_CUST( "max", 11, in_read_weight, in_write_weight ), YAML_SIGNED( "ppmCenter", 10 ), - YAML_SIGNED( "offset", 11 ), + YAML_SIGNED_CUST( "offset", 11, in_read_weight, in_write_weight ), YAML_UNSIGNED( "symetrical", 1 ), YAML_UNSIGNED( "revert", 1 ), YAML_PADDING( 3 ), @@ -511,7 +512,7 @@ static const struct YamlNode struct_ExpoData[] = { YAML_SIGNED_CUST( "weight", 8, in_read_weight, in_write_weight ), YAML_PADDING( 1 ), YAML_STRING("name", 6), - YAML_SIGNED( "offset", 8 ), + YAML_SIGNED_CUST( "offset", 8, in_read_weight, in_write_weight ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), YAML_END }; diff --git a/radio/src/storage/conversions/yaml/yaml_datastructs_t12.cpp b/radio/src/storage/conversions/yaml/yaml_datastructs_t12.cpp index e6ae90e4e..5d02e2cd7 100644 --- a/radio/src/storage/conversions/yaml/yaml_datastructs_t12.cpp +++ b/radio/src/storage/conversions/yaml/yaml_datastructs_t12.cpp @@ -328,6 +328,7 @@ static const struct YamlNode struct_string_24[] = { }; static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "version", 8 ), + YAML_CUSTOM("board",nullptr,w_board), YAML_PADDING( 16 ), YAML_ARRAY("calib", 48, 6, struct_CalibData, NULL), YAML_PADDING( 16 ), @@ -363,7 +364,7 @@ static const struct YamlNode struct_RadioData[] = { YAML_SIGNED_CUST( "beepLength", 3, r_5pos, w_5pos ), YAML_SIGNED_CUST( "hapticStrength", 3, r_5pos, w_5pos ), YAML_UNSIGNED( "gpsFormat", 1 ), - YAML_UNSIGNED( "unexpectedShutdown", 1 ), + YAML_PADDING( 1 ), YAML_UNSIGNED_CUST( "speakerPitch", 8, r_spPitch, w_spPitch ), YAML_SIGNED_CUST( "speakerVolume", 8, r_vol, w_vol ), YAML_SIGNED_CUST( "vBatMin", 8, r_vbat_min, w_vbat_min ), @@ -430,7 +431,7 @@ static const struct YamlNode struct_TimerData[] = { }; static const struct YamlNode struct_CurveRef[] = { YAML_UNSIGNED( "type", 8 ), - YAML_SIGNED( "value", 8 ), + YAML_SIGNED_CUST( "value", 8, in_read_weight, in_write_weight ), YAML_END }; static const struct YamlNode struct_MixData[] = { @@ -441,7 +442,7 @@ static const struct YamlNode struct_MixData[] = { YAML_UNSIGNED( "mixWarn", 2 ), YAML_ENUM("mltpx", 2, enum_MixerMultiplex), YAML_PADDING( 1 ), - YAML_SIGNED( "offset", 14 ), + YAML_SIGNED_CUST( "offset", 14, in_read_weight, in_write_weight ), YAML_SIGNED_CUST( "swtch", 9, r_swtchSrc, w_swtchSrc ), YAML_UNSIGNED_CUST( "flightModes", 9, r_flightModes, w_flightModes ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), @@ -454,10 +455,10 @@ static const struct YamlNode struct_MixData[] = { }; static const struct YamlNode struct_LimitData[] = { YAML_IDX, - YAML_SIGNED( "min", 11 ), - YAML_SIGNED( "max", 11 ), + YAML_SIGNED_CUST( "min", 11, in_read_weight, in_write_weight ), + YAML_SIGNED_CUST( "max", 11, in_read_weight, in_write_weight ), YAML_SIGNED( "ppmCenter", 10 ), - YAML_SIGNED( "offset", 11 ), + YAML_SIGNED_CUST( "offset", 11, in_read_weight, in_write_weight ), YAML_UNSIGNED( "symetrical", 1 ), YAML_UNSIGNED( "revert", 1 ), YAML_PADDING( 3 ), @@ -476,7 +477,7 @@ static const struct YamlNode struct_ExpoData[] = { YAML_SIGNED_CUST( "weight", 8, in_read_weight, in_write_weight ), YAML_PADDING( 1 ), YAML_STRING("name", 6), - YAML_SIGNED( "offset", 8 ), + YAML_SIGNED_CUST( "offset", 8, in_read_weight, in_write_weight ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), YAML_END }; diff --git a/radio/src/storage/conversions/yaml/yaml_datastructs_t8.cpp b/radio/src/storage/conversions/yaml/yaml_datastructs_t8.cpp index 6fa0070ef..3b7452e96 100644 --- a/radio/src/storage/conversions/yaml/yaml_datastructs_t8.cpp +++ b/radio/src/storage/conversions/yaml/yaml_datastructs_t8.cpp @@ -328,6 +328,7 @@ static const struct YamlNode struct_string_24[] = { }; static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "version", 8 ), + YAML_CUSTOM("board",nullptr,w_board), YAML_PADDING( 16 ), YAML_ARRAY("calib", 48, 6, struct_CalibData, NULL), YAML_PADDING( 16 ), @@ -363,7 +364,7 @@ static const struct YamlNode struct_RadioData[] = { YAML_SIGNED_CUST( "beepLength", 3, r_5pos, w_5pos ), YAML_SIGNED_CUST( "hapticStrength", 3, r_5pos, w_5pos ), YAML_UNSIGNED( "gpsFormat", 1 ), - YAML_UNSIGNED( "unexpectedShutdown", 1 ), + YAML_PADDING( 1 ), YAML_UNSIGNED_CUST( "speakerPitch", 8, r_spPitch, w_spPitch ), YAML_SIGNED_CUST( "speakerVolume", 8, r_vol, w_vol ), YAML_SIGNED_CUST( "vBatMin", 8, r_vbat_min, w_vbat_min ), @@ -430,7 +431,7 @@ static const struct YamlNode struct_TimerData[] = { }; static const struct YamlNode struct_CurveRef[] = { YAML_UNSIGNED( "type", 8 ), - YAML_SIGNED( "value", 8 ), + YAML_SIGNED_CUST( "value", 8, in_read_weight, in_write_weight ), YAML_END }; static const struct YamlNode struct_MixData[] = { @@ -441,7 +442,7 @@ static const struct YamlNode struct_MixData[] = { YAML_UNSIGNED( "mixWarn", 2 ), YAML_ENUM("mltpx", 2, enum_MixerMultiplex), YAML_PADDING( 1 ), - YAML_SIGNED( "offset", 14 ), + YAML_SIGNED_CUST( "offset", 14, in_read_weight, in_write_weight ), YAML_SIGNED_CUST( "swtch", 9, r_swtchSrc, w_swtchSrc ), YAML_UNSIGNED_CUST( "flightModes", 9, r_flightModes, w_flightModes ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), @@ -454,10 +455,10 @@ static const struct YamlNode struct_MixData[] = { }; static const struct YamlNode struct_LimitData[] = { YAML_IDX, - YAML_SIGNED( "min", 11 ), - YAML_SIGNED( "max", 11 ), + YAML_SIGNED_CUST( "min", 11, in_read_weight, in_write_weight ), + YAML_SIGNED_CUST( "max", 11, in_read_weight, in_write_weight ), YAML_SIGNED( "ppmCenter", 10 ), - YAML_SIGNED( "offset", 11 ), + YAML_SIGNED_CUST( "offset", 11, in_read_weight, in_write_weight ), YAML_UNSIGNED( "symetrical", 1 ), YAML_UNSIGNED( "revert", 1 ), YAML_PADDING( 3 ), @@ -476,7 +477,7 @@ static const struct YamlNode struct_ExpoData[] = { YAML_SIGNED_CUST( "weight", 8, in_read_weight, in_write_weight ), YAML_PADDING( 1 ), YAML_STRING("name", 6), - YAML_SIGNED( "offset", 8 ), + YAML_SIGNED_CUST( "offset", 8, in_read_weight, in_write_weight ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), YAML_END }; diff --git a/radio/src/storage/conversions/yaml/yaml_datastructs_tlite.cpp b/radio/src/storage/conversions/yaml/yaml_datastructs_tlite.cpp index 6fa0070ef..3b7452e96 100644 --- a/radio/src/storage/conversions/yaml/yaml_datastructs_tlite.cpp +++ b/radio/src/storage/conversions/yaml/yaml_datastructs_tlite.cpp @@ -328,6 +328,7 @@ static const struct YamlNode struct_string_24[] = { }; static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "version", 8 ), + YAML_CUSTOM("board",nullptr,w_board), YAML_PADDING( 16 ), YAML_ARRAY("calib", 48, 6, struct_CalibData, NULL), YAML_PADDING( 16 ), @@ -363,7 +364,7 @@ static const struct YamlNode struct_RadioData[] = { YAML_SIGNED_CUST( "beepLength", 3, r_5pos, w_5pos ), YAML_SIGNED_CUST( "hapticStrength", 3, r_5pos, w_5pos ), YAML_UNSIGNED( "gpsFormat", 1 ), - YAML_UNSIGNED( "unexpectedShutdown", 1 ), + YAML_PADDING( 1 ), YAML_UNSIGNED_CUST( "speakerPitch", 8, r_spPitch, w_spPitch ), YAML_SIGNED_CUST( "speakerVolume", 8, r_vol, w_vol ), YAML_SIGNED_CUST( "vBatMin", 8, r_vbat_min, w_vbat_min ), @@ -430,7 +431,7 @@ static const struct YamlNode struct_TimerData[] = { }; static const struct YamlNode struct_CurveRef[] = { YAML_UNSIGNED( "type", 8 ), - YAML_SIGNED( "value", 8 ), + YAML_SIGNED_CUST( "value", 8, in_read_weight, in_write_weight ), YAML_END }; static const struct YamlNode struct_MixData[] = { @@ -441,7 +442,7 @@ static const struct YamlNode struct_MixData[] = { YAML_UNSIGNED( "mixWarn", 2 ), YAML_ENUM("mltpx", 2, enum_MixerMultiplex), YAML_PADDING( 1 ), - YAML_SIGNED( "offset", 14 ), + YAML_SIGNED_CUST( "offset", 14, in_read_weight, in_write_weight ), YAML_SIGNED_CUST( "swtch", 9, r_swtchSrc, w_swtchSrc ), YAML_UNSIGNED_CUST( "flightModes", 9, r_flightModes, w_flightModes ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), @@ -454,10 +455,10 @@ static const struct YamlNode struct_MixData[] = { }; static const struct YamlNode struct_LimitData[] = { YAML_IDX, - YAML_SIGNED( "min", 11 ), - YAML_SIGNED( "max", 11 ), + YAML_SIGNED_CUST( "min", 11, in_read_weight, in_write_weight ), + YAML_SIGNED_CUST( "max", 11, in_read_weight, in_write_weight ), YAML_SIGNED( "ppmCenter", 10 ), - YAML_SIGNED( "offset", 11 ), + YAML_SIGNED_CUST( "offset", 11, in_read_weight, in_write_weight ), YAML_UNSIGNED( "symetrical", 1 ), YAML_UNSIGNED( "revert", 1 ), YAML_PADDING( 3 ), @@ -476,7 +477,7 @@ static const struct YamlNode struct_ExpoData[] = { YAML_SIGNED_CUST( "weight", 8, in_read_weight, in_write_weight ), YAML_PADDING( 1 ), YAML_STRING("name", 6), - YAML_SIGNED( "offset", 8 ), + YAML_SIGNED_CUST( "offset", 8, in_read_weight, in_write_weight ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), YAML_END }; diff --git a/radio/src/storage/conversions/yaml/yaml_datastructs_tx12.cpp b/radio/src/storage/conversions/yaml/yaml_datastructs_tx12.cpp index ed52b20f5..366acd3da 100644 --- a/radio/src/storage/conversions/yaml/yaml_datastructs_tx12.cpp +++ b/radio/src/storage/conversions/yaml/yaml_datastructs_tx12.cpp @@ -328,6 +328,7 @@ static const struct YamlNode struct_string_24[] = { }; static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "version", 8 ), + YAML_CUSTOM("board",nullptr,w_board), YAML_PADDING( 16 ), YAML_ARRAY("calib", 48, 6, struct_CalibData, NULL), YAML_PADDING( 16 ), @@ -363,7 +364,7 @@ static const struct YamlNode struct_RadioData[] = { YAML_SIGNED_CUST( "beepLength", 3, r_5pos, w_5pos ), YAML_SIGNED_CUST( "hapticStrength", 3, r_5pos, w_5pos ), YAML_UNSIGNED( "gpsFormat", 1 ), - YAML_UNSIGNED( "unexpectedShutdown", 1 ), + YAML_PADDING( 1 ), YAML_UNSIGNED_CUST( "speakerPitch", 8, r_spPitch, w_spPitch ), YAML_SIGNED_CUST( "speakerVolume", 8, r_vol, w_vol ), YAML_SIGNED_CUST( "vBatMin", 8, r_vbat_min, w_vbat_min ), @@ -430,7 +431,7 @@ static const struct YamlNode struct_TimerData[] = { }; static const struct YamlNode struct_CurveRef[] = { YAML_UNSIGNED( "type", 8 ), - YAML_SIGNED( "value", 8 ), + YAML_SIGNED_CUST( "value", 8, in_read_weight, in_write_weight ), YAML_END }; static const struct YamlNode struct_MixData[] = { @@ -441,7 +442,7 @@ static const struct YamlNode struct_MixData[] = { YAML_UNSIGNED( "mixWarn", 2 ), YAML_ENUM("mltpx", 2, enum_MixerMultiplex), YAML_PADDING( 1 ), - YAML_SIGNED( "offset", 14 ), + YAML_SIGNED_CUST( "offset", 14, in_read_weight, in_write_weight ), YAML_SIGNED_CUST( "swtch", 9, r_swtchSrc, w_swtchSrc ), YAML_UNSIGNED_CUST( "flightModes", 9, r_flightModes, w_flightModes ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), @@ -454,10 +455,10 @@ static const struct YamlNode struct_MixData[] = { }; static const struct YamlNode struct_LimitData[] = { YAML_IDX, - YAML_SIGNED( "min", 11 ), - YAML_SIGNED( "max", 11 ), + YAML_SIGNED_CUST( "min", 11, in_read_weight, in_write_weight ), + YAML_SIGNED_CUST( "max", 11, in_read_weight, in_write_weight ), YAML_SIGNED( "ppmCenter", 10 ), - YAML_SIGNED( "offset", 11 ), + YAML_SIGNED_CUST( "offset", 11, in_read_weight, in_write_weight ), YAML_UNSIGNED( "symetrical", 1 ), YAML_UNSIGNED( "revert", 1 ), YAML_PADDING( 3 ), @@ -476,7 +477,7 @@ static const struct YamlNode struct_ExpoData[] = { YAML_SIGNED_CUST( "weight", 8, in_read_weight, in_write_weight ), YAML_PADDING( 1 ), YAML_STRING("name", 6), - YAML_SIGNED( "offset", 8 ), + YAML_SIGNED_CUST( "offset", 8, in_read_weight, in_write_weight ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), YAML_END }; diff --git a/radio/src/storage/conversions/yaml/yaml_datastructs_x10.cpp b/radio/src/storage/conversions/yaml/yaml_datastructs_x10.cpp index 0617009af..db2bd42cb 100644 --- a/radio/src/storage/conversions/yaml/yaml_datastructs_x10.cpp +++ b/radio/src/storage/conversions/yaml/yaml_datastructs_x10.cpp @@ -378,6 +378,7 @@ static const struct YamlNode struct_OpenTxTheme__PersistentData[] = { }; static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "version", 8 ), + YAML_CUSTOM("board",nullptr,w_board), YAML_PADDING( 16 ), YAML_ARRAY("calib", 48, 15, struct_CalibData, NULL), YAML_PADDING( 16 ), @@ -411,7 +412,7 @@ static const struct YamlNode struct_RadioData[] = { YAML_SIGNED_CUST( "beepLength", 3, r_5pos, w_5pos ), YAML_SIGNED_CUST( "hapticStrength", 3, r_5pos, w_5pos ), YAML_UNSIGNED( "gpsFormat", 1 ), - YAML_UNSIGNED( "unexpectedShutdown", 1 ), + YAML_PADDING( 1 ), YAML_UNSIGNED_CUST( "speakerPitch", 8, r_spPitch, w_spPitch ), YAML_SIGNED_CUST( "speakerVolume", 8, r_vol, w_vol ), YAML_SIGNED_CUST( "vBatMin", 8, r_vbat_min, w_vbat_min ), @@ -482,7 +483,7 @@ static const struct YamlNode struct_TimerData[] = { }; static const struct YamlNode struct_CurveRef[] = { YAML_UNSIGNED( "type", 8 ), - YAML_SIGNED( "value", 8 ), + YAML_SIGNED_CUST( "value", 8, in_read_weight, in_write_weight ), YAML_END }; static const struct YamlNode struct_MixData[] = { @@ -493,7 +494,7 @@ static const struct YamlNode struct_MixData[] = { YAML_UNSIGNED( "mixWarn", 2 ), YAML_ENUM("mltpx", 2, enum_MixerMultiplex), YAML_PADDING( 1 ), - YAML_SIGNED( "offset", 14 ), + YAML_SIGNED_CUST( "offset", 14, in_read_weight, in_write_weight ), YAML_SIGNED_CUST( "swtch", 9, r_swtchSrc, w_swtchSrc ), YAML_UNSIGNED_CUST( "flightModes", 9, r_flightModes, w_flightModes ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), @@ -506,10 +507,10 @@ static const struct YamlNode struct_MixData[] = { }; static const struct YamlNode struct_LimitData[] = { YAML_IDX, - YAML_SIGNED( "min", 11 ), - YAML_SIGNED( "max", 11 ), + YAML_SIGNED_CUST( "min", 11, in_read_weight, in_write_weight ), + YAML_SIGNED_CUST( "max", 11, in_read_weight, in_write_weight ), YAML_SIGNED( "ppmCenter", 10 ), - YAML_SIGNED( "offset", 11 ), + YAML_SIGNED_CUST( "offset", 11, in_read_weight, in_write_weight ), YAML_UNSIGNED( "symetrical", 1 ), YAML_UNSIGNED( "revert", 1 ), YAML_PADDING( 3 ), @@ -528,7 +529,7 @@ static const struct YamlNode struct_ExpoData[] = { YAML_SIGNED_CUST( "weight", 8, in_read_weight, in_write_weight ), YAML_PADDING( 1 ), YAML_STRING("name", 6), - YAML_SIGNED( "offset", 8 ), + YAML_SIGNED_CUST( "offset", 8, in_read_weight, in_write_weight ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), YAML_END }; diff --git a/radio/src/storage/conversions/yaml/yaml_datastructs_x12s.cpp b/radio/src/storage/conversions/yaml/yaml_datastructs_x12s.cpp index fd88dba4a..41e00722f 100644 --- a/radio/src/storage/conversions/yaml/yaml_datastructs_x12s.cpp +++ b/radio/src/storage/conversions/yaml/yaml_datastructs_x12s.cpp @@ -378,6 +378,7 @@ static const struct YamlNode struct_OpenTxTheme__PersistentData[] = { }; static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "version", 8 ), + YAML_CUSTOM("board",nullptr,w_board), YAML_PADDING( 16 ), YAML_ARRAY("calib", 48, 15, struct_CalibData, NULL), YAML_PADDING( 16 ), @@ -411,7 +412,7 @@ static const struct YamlNode struct_RadioData[] = { YAML_SIGNED_CUST( "beepLength", 3, r_5pos, w_5pos ), YAML_SIGNED_CUST( "hapticStrength", 3, r_5pos, w_5pos ), YAML_UNSIGNED( "gpsFormat", 1 ), - YAML_UNSIGNED( "unexpectedShutdown", 1 ), + YAML_PADDING( 1 ), YAML_UNSIGNED_CUST( "speakerPitch", 8, r_spPitch, w_spPitch ), YAML_SIGNED_CUST( "speakerVolume", 8, r_vol, w_vol ), YAML_SIGNED_CUST( "vBatMin", 8, r_vbat_min, w_vbat_min ), @@ -482,7 +483,7 @@ static const struct YamlNode struct_TimerData[] = { }; static const struct YamlNode struct_CurveRef[] = { YAML_UNSIGNED( "type", 8 ), - YAML_SIGNED( "value", 8 ), + YAML_SIGNED_CUST( "value", 8, in_read_weight, in_write_weight ), YAML_END }; static const struct YamlNode struct_MixData[] = { @@ -493,7 +494,7 @@ static const struct YamlNode struct_MixData[] = { YAML_UNSIGNED( "mixWarn", 2 ), YAML_ENUM("mltpx", 2, enum_MixerMultiplex), YAML_PADDING( 1 ), - YAML_SIGNED( "offset", 14 ), + YAML_SIGNED_CUST( "offset", 14, in_read_weight, in_write_weight ), YAML_SIGNED_CUST( "swtch", 9, r_swtchSrc, w_swtchSrc ), YAML_UNSIGNED_CUST( "flightModes", 9, r_flightModes, w_flightModes ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), @@ -506,10 +507,10 @@ static const struct YamlNode struct_MixData[] = { }; static const struct YamlNode struct_LimitData[] = { YAML_IDX, - YAML_SIGNED( "min", 11 ), - YAML_SIGNED( "max", 11 ), + YAML_SIGNED_CUST( "min", 11, in_read_weight, in_write_weight ), + YAML_SIGNED_CUST( "max", 11, in_read_weight, in_write_weight ), YAML_SIGNED( "ppmCenter", 10 ), - YAML_SIGNED( "offset", 11 ), + YAML_SIGNED_CUST( "offset", 11, in_read_weight, in_write_weight ), YAML_UNSIGNED( "symetrical", 1 ), YAML_UNSIGNED( "revert", 1 ), YAML_PADDING( 3 ), @@ -528,7 +529,7 @@ static const struct YamlNode struct_ExpoData[] = { YAML_SIGNED_CUST( "weight", 8, in_read_weight, in_write_weight ), YAML_PADDING( 1 ), YAML_STRING("name", 6), - YAML_SIGNED( "offset", 8 ), + YAML_SIGNED_CUST( "offset", 8, in_read_weight, in_write_weight ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), YAML_END }; diff --git a/radio/src/storage/conversions/yaml/yaml_datastructs_x7.cpp b/radio/src/storage/conversions/yaml/yaml_datastructs_x7.cpp index 6fa0070ef..3b7452e96 100644 --- a/radio/src/storage/conversions/yaml/yaml_datastructs_x7.cpp +++ b/radio/src/storage/conversions/yaml/yaml_datastructs_x7.cpp @@ -328,6 +328,7 @@ static const struct YamlNode struct_string_24[] = { }; static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "version", 8 ), + YAML_CUSTOM("board",nullptr,w_board), YAML_PADDING( 16 ), YAML_ARRAY("calib", 48, 6, struct_CalibData, NULL), YAML_PADDING( 16 ), @@ -363,7 +364,7 @@ static const struct YamlNode struct_RadioData[] = { YAML_SIGNED_CUST( "beepLength", 3, r_5pos, w_5pos ), YAML_SIGNED_CUST( "hapticStrength", 3, r_5pos, w_5pos ), YAML_UNSIGNED( "gpsFormat", 1 ), - YAML_UNSIGNED( "unexpectedShutdown", 1 ), + YAML_PADDING( 1 ), YAML_UNSIGNED_CUST( "speakerPitch", 8, r_spPitch, w_spPitch ), YAML_SIGNED_CUST( "speakerVolume", 8, r_vol, w_vol ), YAML_SIGNED_CUST( "vBatMin", 8, r_vbat_min, w_vbat_min ), @@ -430,7 +431,7 @@ static const struct YamlNode struct_TimerData[] = { }; static const struct YamlNode struct_CurveRef[] = { YAML_UNSIGNED( "type", 8 ), - YAML_SIGNED( "value", 8 ), + YAML_SIGNED_CUST( "value", 8, in_read_weight, in_write_weight ), YAML_END }; static const struct YamlNode struct_MixData[] = { @@ -441,7 +442,7 @@ static const struct YamlNode struct_MixData[] = { YAML_UNSIGNED( "mixWarn", 2 ), YAML_ENUM("mltpx", 2, enum_MixerMultiplex), YAML_PADDING( 1 ), - YAML_SIGNED( "offset", 14 ), + YAML_SIGNED_CUST( "offset", 14, in_read_weight, in_write_weight ), YAML_SIGNED_CUST( "swtch", 9, r_swtchSrc, w_swtchSrc ), YAML_UNSIGNED_CUST( "flightModes", 9, r_flightModes, w_flightModes ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), @@ -454,10 +455,10 @@ static const struct YamlNode struct_MixData[] = { }; static const struct YamlNode struct_LimitData[] = { YAML_IDX, - YAML_SIGNED( "min", 11 ), - YAML_SIGNED( "max", 11 ), + YAML_SIGNED_CUST( "min", 11, in_read_weight, in_write_weight ), + YAML_SIGNED_CUST( "max", 11, in_read_weight, in_write_weight ), YAML_SIGNED( "ppmCenter", 10 ), - YAML_SIGNED( "offset", 11 ), + YAML_SIGNED_CUST( "offset", 11, in_read_weight, in_write_weight ), YAML_UNSIGNED( "symetrical", 1 ), YAML_UNSIGNED( "revert", 1 ), YAML_PADDING( 3 ), @@ -476,7 +477,7 @@ static const struct YamlNode struct_ExpoData[] = { YAML_SIGNED_CUST( "weight", 8, in_read_weight, in_write_weight ), YAML_PADDING( 1 ), YAML_STRING("name", 6), - YAML_SIGNED( "offset", 8 ), + YAML_SIGNED_CUST( "offset", 8, in_read_weight, in_write_weight ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), YAML_END }; diff --git a/radio/src/storage/conversions/yaml/yaml_datastructs_x9d.cpp b/radio/src/storage/conversions/yaml/yaml_datastructs_x9d.cpp index cc7bde834..5241e7d00 100644 --- a/radio/src/storage/conversions/yaml/yaml_datastructs_x9d.cpp +++ b/radio/src/storage/conversions/yaml/yaml_datastructs_x9d.cpp @@ -335,6 +335,7 @@ static const struct YamlNode struct_string_24[] = { }; static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "version", 8 ), + YAML_CUSTOM("board",nullptr,w_board), YAML_PADDING( 16 ), YAML_ARRAY("calib", 48, 9, struct_CalibData, NULL), YAML_PADDING( 16 ), @@ -370,7 +371,7 @@ static const struct YamlNode struct_RadioData[] = { YAML_SIGNED_CUST( "beepLength", 3, r_5pos, w_5pos ), YAML_SIGNED_CUST( "hapticStrength", 3, r_5pos, w_5pos ), YAML_UNSIGNED( "gpsFormat", 1 ), - YAML_UNSIGNED( "unexpectedShutdown", 1 ), + YAML_PADDING( 1 ), YAML_UNSIGNED_CUST( "speakerPitch", 8, r_spPitch, w_spPitch ), YAML_SIGNED_CUST( "speakerVolume", 8, r_vol, w_vol ), YAML_SIGNED_CUST( "vBatMin", 8, r_vbat_min, w_vbat_min ), @@ -438,7 +439,7 @@ static const struct YamlNode struct_TimerData[] = { }; static const struct YamlNode struct_CurveRef[] = { YAML_UNSIGNED( "type", 8 ), - YAML_SIGNED( "value", 8 ), + YAML_SIGNED_CUST( "value", 8, in_read_weight, in_write_weight ), YAML_END }; static const struct YamlNode struct_MixData[] = { @@ -449,7 +450,7 @@ static const struct YamlNode struct_MixData[] = { YAML_UNSIGNED( "mixWarn", 2 ), YAML_ENUM("mltpx", 2, enum_MixerMultiplex), YAML_PADDING( 1 ), - YAML_SIGNED( "offset", 14 ), + YAML_SIGNED_CUST( "offset", 14, in_read_weight, in_write_weight ), YAML_SIGNED_CUST( "swtch", 9, r_swtchSrc, w_swtchSrc ), YAML_UNSIGNED_CUST( "flightModes", 9, r_flightModes, w_flightModes ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), @@ -462,10 +463,10 @@ static const struct YamlNode struct_MixData[] = { }; static const struct YamlNode struct_LimitData[] = { YAML_IDX, - YAML_SIGNED( "min", 11 ), - YAML_SIGNED( "max", 11 ), + YAML_SIGNED_CUST( "min", 11, in_read_weight, in_write_weight ), + YAML_SIGNED_CUST( "max", 11, in_read_weight, in_write_weight ), YAML_SIGNED( "ppmCenter", 10 ), - YAML_SIGNED( "offset", 11 ), + YAML_SIGNED_CUST( "offset", 11, in_read_weight, in_write_weight ), YAML_UNSIGNED( "symetrical", 1 ), YAML_UNSIGNED( "revert", 1 ), YAML_PADDING( 3 ), @@ -484,7 +485,7 @@ static const struct YamlNode struct_ExpoData[] = { YAML_SIGNED_CUST( "weight", 8, in_read_weight, in_write_weight ), YAML_PADDING( 1 ), YAML_STRING("name", 6), - YAML_SIGNED( "offset", 8 ), + YAML_SIGNED_CUST( "offset", 8, in_read_weight, in_write_weight ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), YAML_END }; diff --git a/radio/src/storage/conversions/yaml/yaml_datastructs_x9e.cpp b/radio/src/storage/conversions/yaml/yaml_datastructs_x9e.cpp index 3b0533b24..aeaed279f 100644 --- a/radio/src/storage/conversions/yaml/yaml_datastructs_x9e.cpp +++ b/radio/src/storage/conversions/yaml/yaml_datastructs_x9e.cpp @@ -374,6 +374,7 @@ static const struct YamlNode struct_string_24[] = { }; static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "version", 8 ), + YAML_CUSTOM("board",nullptr,w_board), YAML_PADDING( 16 ), YAML_ARRAY("calib", 48, 12, struct_CalibData, NULL), YAML_PADDING( 16 ), @@ -409,7 +410,7 @@ static const struct YamlNode struct_RadioData[] = { YAML_SIGNED_CUST( "beepLength", 3, r_5pos, w_5pos ), YAML_SIGNED_CUST( "hapticStrength", 3, r_5pos, w_5pos ), YAML_UNSIGNED( "gpsFormat", 1 ), - YAML_UNSIGNED( "unexpectedShutdown", 1 ), + YAML_PADDING( 1 ), YAML_UNSIGNED_CUST( "speakerPitch", 8, r_spPitch, w_spPitch ), YAML_SIGNED_CUST( "speakerVolume", 8, r_vol, w_vol ), YAML_SIGNED_CUST( "vBatMin", 8, r_vbat_min, w_vbat_min ), @@ -477,7 +478,7 @@ static const struct YamlNode struct_TimerData[] = { }; static const struct YamlNode struct_CurveRef[] = { YAML_UNSIGNED( "type", 8 ), - YAML_SIGNED( "value", 8 ), + YAML_SIGNED_CUST( "value", 8, in_read_weight, in_write_weight ), YAML_END }; static const struct YamlNode struct_MixData[] = { @@ -488,7 +489,7 @@ static const struct YamlNode struct_MixData[] = { YAML_UNSIGNED( "mixWarn", 2 ), YAML_ENUM("mltpx", 2, enum_MixerMultiplex), YAML_PADDING( 1 ), - YAML_SIGNED( "offset", 14 ), + YAML_SIGNED_CUST( "offset", 14, in_read_weight, in_write_weight ), YAML_SIGNED_CUST( "swtch", 9, r_swtchSrc, w_swtchSrc ), YAML_UNSIGNED_CUST( "flightModes", 9, r_flightModes, w_flightModes ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), @@ -501,10 +502,10 @@ static const struct YamlNode struct_MixData[] = { }; static const struct YamlNode struct_LimitData[] = { YAML_IDX, - YAML_SIGNED( "min", 11 ), - YAML_SIGNED( "max", 11 ), + YAML_SIGNED_CUST( "min", 11, in_read_weight, in_write_weight ), + YAML_SIGNED_CUST( "max", 11, in_read_weight, in_write_weight ), YAML_SIGNED( "ppmCenter", 10 ), - YAML_SIGNED( "offset", 11 ), + YAML_SIGNED_CUST( "offset", 11, in_read_weight, in_write_weight ), YAML_UNSIGNED( "symetrical", 1 ), YAML_UNSIGNED( "revert", 1 ), YAML_PADDING( 3 ), @@ -523,7 +524,7 @@ static const struct YamlNode struct_ExpoData[] = { YAML_SIGNED_CUST( "weight", 8, in_read_weight, in_write_weight ), YAML_PADDING( 1 ), YAML_STRING("name", 6), - YAML_SIGNED( "offset", 8 ), + YAML_SIGNED_CUST( "offset", 8, in_read_weight, in_write_weight ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), YAML_END }; diff --git a/radio/src/storage/conversions/yaml/yaml_datastructs_x9lite.cpp b/radio/src/storage/conversions/yaml/yaml_datastructs_x9lite.cpp index 6c80e26d0..d65fb41ac 100644 --- a/radio/src/storage/conversions/yaml/yaml_datastructs_x9lite.cpp +++ b/radio/src/storage/conversions/yaml/yaml_datastructs_x9lite.cpp @@ -315,6 +315,7 @@ static const struct YamlNode struct_string_24[] = { }; static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "version", 8 ), + YAML_CUSTOM("board",nullptr,w_board), YAML_PADDING( 16 ), YAML_ARRAY("calib", 48, 5, struct_CalibData, NULL), YAML_PADDING( 16 ), @@ -350,7 +351,7 @@ static const struct YamlNode struct_RadioData[] = { YAML_SIGNED_CUST( "beepLength", 3, r_5pos, w_5pos ), YAML_SIGNED_CUST( "hapticStrength", 3, r_5pos, w_5pos ), YAML_UNSIGNED( "gpsFormat", 1 ), - YAML_UNSIGNED( "unexpectedShutdown", 1 ), + YAML_PADDING( 1 ), YAML_UNSIGNED_CUST( "speakerPitch", 8, r_spPitch, w_spPitch ), YAML_SIGNED_CUST( "speakerVolume", 8, r_vol, w_vol ), YAML_SIGNED_CUST( "vBatMin", 8, r_vbat_min, w_vbat_min ), @@ -415,7 +416,7 @@ static const struct YamlNode struct_TimerData[] = { }; static const struct YamlNode struct_CurveRef[] = { YAML_UNSIGNED( "type", 8 ), - YAML_SIGNED( "value", 8 ), + YAML_SIGNED_CUST( "value", 8, in_read_weight, in_write_weight ), YAML_END }; static const struct YamlNode struct_MixData[] = { @@ -426,7 +427,7 @@ static const struct YamlNode struct_MixData[] = { YAML_UNSIGNED( "mixWarn", 2 ), YAML_ENUM("mltpx", 2, enum_MixerMultiplex), YAML_PADDING( 1 ), - YAML_SIGNED( "offset", 14 ), + YAML_SIGNED_CUST( "offset", 14, in_read_weight, in_write_weight ), YAML_SIGNED_CUST( "swtch", 9, r_swtchSrc, w_swtchSrc ), YAML_UNSIGNED_CUST( "flightModes", 9, r_flightModes, w_flightModes ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), @@ -439,10 +440,10 @@ static const struct YamlNode struct_MixData[] = { }; static const struct YamlNode struct_LimitData[] = { YAML_IDX, - YAML_SIGNED( "min", 11 ), - YAML_SIGNED( "max", 11 ), + YAML_SIGNED_CUST( "min", 11, in_read_weight, in_write_weight ), + YAML_SIGNED_CUST( "max", 11, in_read_weight, in_write_weight ), YAML_SIGNED( "ppmCenter", 10 ), - YAML_SIGNED( "offset", 11 ), + YAML_SIGNED_CUST( "offset", 11, in_read_weight, in_write_weight ), YAML_UNSIGNED( "symetrical", 1 ), YAML_UNSIGNED( "revert", 1 ), YAML_PADDING( 3 ), @@ -461,7 +462,7 @@ static const struct YamlNode struct_ExpoData[] = { YAML_SIGNED_CUST( "weight", 8, in_read_weight, in_write_weight ), YAML_PADDING( 1 ), YAML_STRING("name", 6), - YAML_SIGNED( "offset", 8 ), + YAML_SIGNED_CUST( "offset", 8, in_read_weight, in_write_weight ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), YAML_END }; diff --git a/radio/src/storage/conversions/yaml/yaml_datastructs_x9lites.cpp b/radio/src/storage/conversions/yaml/yaml_datastructs_x9lites.cpp index c07bf178b..903bf0b7f 100644 --- a/radio/src/storage/conversions/yaml/yaml_datastructs_x9lites.cpp +++ b/radio/src/storage/conversions/yaml/yaml_datastructs_x9lites.cpp @@ -323,6 +323,7 @@ static const struct YamlNode struct_string_24[] = { }; static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "version", 8 ), + YAML_CUSTOM("board",nullptr,w_board), YAML_PADDING( 16 ), YAML_ARRAY("calib", 48, 5, struct_CalibData, NULL), YAML_PADDING( 16 ), @@ -358,7 +359,7 @@ static const struct YamlNode struct_RadioData[] = { YAML_SIGNED_CUST( "beepLength", 3, r_5pos, w_5pos ), YAML_SIGNED_CUST( "hapticStrength", 3, r_5pos, w_5pos ), YAML_UNSIGNED( "gpsFormat", 1 ), - YAML_UNSIGNED( "unexpectedShutdown", 1 ), + YAML_PADDING( 1 ), YAML_UNSIGNED_CUST( "speakerPitch", 8, r_spPitch, w_spPitch ), YAML_SIGNED_CUST( "speakerVolume", 8, r_vol, w_vol ), YAML_SIGNED_CUST( "vBatMin", 8, r_vbat_min, w_vbat_min ), @@ -425,7 +426,7 @@ static const struct YamlNode struct_TimerData[] = { }; static const struct YamlNode struct_CurveRef[] = { YAML_UNSIGNED( "type", 8 ), - YAML_SIGNED( "value", 8 ), + YAML_SIGNED_CUST( "value", 8, in_read_weight, in_write_weight ), YAML_END }; static const struct YamlNode struct_MixData[] = { @@ -436,7 +437,7 @@ static const struct YamlNode struct_MixData[] = { YAML_UNSIGNED( "mixWarn", 2 ), YAML_ENUM("mltpx", 2, enum_MixerMultiplex), YAML_PADDING( 1 ), - YAML_SIGNED( "offset", 14 ), + YAML_SIGNED_CUST( "offset", 14, in_read_weight, in_write_weight ), YAML_SIGNED_CUST( "swtch", 9, r_swtchSrc, w_swtchSrc ), YAML_UNSIGNED_CUST( "flightModes", 9, r_flightModes, w_flightModes ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), @@ -449,10 +450,10 @@ static const struct YamlNode struct_MixData[] = { }; static const struct YamlNode struct_LimitData[] = { YAML_IDX, - YAML_SIGNED( "min", 11 ), - YAML_SIGNED( "max", 11 ), + YAML_SIGNED_CUST( "min", 11, in_read_weight, in_write_weight ), + YAML_SIGNED_CUST( "max", 11, in_read_weight, in_write_weight ), YAML_SIGNED( "ppmCenter", 10 ), - YAML_SIGNED( "offset", 11 ), + YAML_SIGNED_CUST( "offset", 11, in_read_weight, in_write_weight ), YAML_UNSIGNED( "symetrical", 1 ), YAML_UNSIGNED( "revert", 1 ), YAML_PADDING( 3 ), @@ -471,7 +472,7 @@ static const struct YamlNode struct_ExpoData[] = { YAML_SIGNED_CUST( "weight", 8, in_read_weight, in_write_weight ), YAML_PADDING( 1 ), YAML_STRING("name", 6), - YAML_SIGNED( "offset", 8 ), + YAML_SIGNED_CUST( "offset", 8, in_read_weight, in_write_weight ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), YAML_END }; diff --git a/radio/src/storage/conversions/yaml/yaml_datastructs_xlite.cpp b/radio/src/storage/conversions/yaml/yaml_datastructs_xlite.cpp index eb8e383a1..f42f55783 100644 --- a/radio/src/storage/conversions/yaml/yaml_datastructs_xlite.cpp +++ b/radio/src/storage/conversions/yaml/yaml_datastructs_xlite.cpp @@ -320,6 +320,7 @@ static const struct YamlNode struct_string_24[] = { }; static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "version", 8 ), + YAML_CUSTOM("board",nullptr,w_board), YAML_PADDING( 16 ), YAML_ARRAY("calib", 48, 6, struct_CalibData, NULL), YAML_PADDING( 16 ), @@ -355,7 +356,7 @@ static const struct YamlNode struct_RadioData[] = { YAML_SIGNED_CUST( "beepLength", 3, r_5pos, w_5pos ), YAML_SIGNED_CUST( "hapticStrength", 3, r_5pos, w_5pos ), YAML_UNSIGNED( "gpsFormat", 1 ), - YAML_UNSIGNED( "unexpectedShutdown", 1 ), + YAML_PADDING( 1 ), YAML_UNSIGNED_CUST( "speakerPitch", 8, r_spPitch, w_spPitch ), YAML_SIGNED_CUST( "speakerVolume", 8, r_vol, w_vol ), YAML_SIGNED_CUST( "vBatMin", 8, r_vbat_min, w_vbat_min ), @@ -422,7 +423,7 @@ static const struct YamlNode struct_TimerData[] = { }; static const struct YamlNode struct_CurveRef[] = { YAML_UNSIGNED( "type", 8 ), - YAML_SIGNED( "value", 8 ), + YAML_SIGNED_CUST( "value", 8, in_read_weight, in_write_weight ), YAML_END }; static const struct YamlNode struct_MixData[] = { @@ -433,7 +434,7 @@ static const struct YamlNode struct_MixData[] = { YAML_UNSIGNED( "mixWarn", 2 ), YAML_ENUM("mltpx", 2, enum_MixerMultiplex), YAML_PADDING( 1 ), - YAML_SIGNED( "offset", 14 ), + YAML_SIGNED_CUST( "offset", 14, in_read_weight, in_write_weight ), YAML_SIGNED_CUST( "swtch", 9, r_swtchSrc, w_swtchSrc ), YAML_UNSIGNED_CUST( "flightModes", 9, r_flightModes, w_flightModes ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), @@ -446,10 +447,10 @@ static const struct YamlNode struct_MixData[] = { }; static const struct YamlNode struct_LimitData[] = { YAML_IDX, - YAML_SIGNED( "min", 11 ), - YAML_SIGNED( "max", 11 ), + YAML_SIGNED_CUST( "min", 11, in_read_weight, in_write_weight ), + YAML_SIGNED_CUST( "max", 11, in_read_weight, in_write_weight ), YAML_SIGNED( "ppmCenter", 10 ), - YAML_SIGNED( "offset", 11 ), + YAML_SIGNED_CUST( "offset", 11, in_read_weight, in_write_weight ), YAML_UNSIGNED( "symetrical", 1 ), YAML_UNSIGNED( "revert", 1 ), YAML_PADDING( 3 ), @@ -468,7 +469,7 @@ static const struct YamlNode struct_ExpoData[] = { YAML_SIGNED_CUST( "weight", 8, in_read_weight, in_write_weight ), YAML_PADDING( 1 ), YAML_STRING("name", 6), - YAML_SIGNED( "offset", 8 ), + YAML_SIGNED_CUST( "offset", 8, in_read_weight, in_write_weight ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), YAML_END }; diff --git a/radio/src/storage/conversions/yaml/yaml_datastructs_xlites.cpp b/radio/src/storage/conversions/yaml/yaml_datastructs_xlites.cpp index fdbfae806..fc0febc7d 100644 --- a/radio/src/storage/conversions/yaml/yaml_datastructs_xlites.cpp +++ b/radio/src/storage/conversions/yaml/yaml_datastructs_xlites.cpp @@ -322,6 +322,7 @@ static const struct YamlNode struct_string_24[] = { }; static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "version", 8 ), + YAML_CUSTOM("board",nullptr,w_board), YAML_PADDING( 16 ), YAML_ARRAY("calib", 48, 6, struct_CalibData, NULL), YAML_PADDING( 16 ), @@ -357,7 +358,7 @@ static const struct YamlNode struct_RadioData[] = { YAML_SIGNED_CUST( "beepLength", 3, r_5pos, w_5pos ), YAML_SIGNED_CUST( "hapticStrength", 3, r_5pos, w_5pos ), YAML_UNSIGNED( "gpsFormat", 1 ), - YAML_UNSIGNED( "unexpectedShutdown", 1 ), + YAML_PADDING( 1 ), YAML_UNSIGNED_CUST( "speakerPitch", 8, r_spPitch, w_spPitch ), YAML_SIGNED_CUST( "speakerVolume", 8, r_vol, w_vol ), YAML_SIGNED_CUST( "vBatMin", 8, r_vbat_min, w_vbat_min ), @@ -426,7 +427,7 @@ static const struct YamlNode struct_TimerData[] = { }; static const struct YamlNode struct_CurveRef[] = { YAML_UNSIGNED( "type", 8 ), - YAML_SIGNED( "value", 8 ), + YAML_SIGNED_CUST( "value", 8, in_read_weight, in_write_weight ), YAML_END }; static const struct YamlNode struct_MixData[] = { @@ -437,7 +438,7 @@ static const struct YamlNode struct_MixData[] = { YAML_UNSIGNED( "mixWarn", 2 ), YAML_ENUM("mltpx", 2, enum_MixerMultiplex), YAML_PADDING( 1 ), - YAML_SIGNED( "offset", 14 ), + YAML_SIGNED_CUST( "offset", 14, in_read_weight, in_write_weight ), YAML_SIGNED_CUST( "swtch", 9, r_swtchSrc, w_swtchSrc ), YAML_UNSIGNED_CUST( "flightModes", 9, r_flightModes, w_flightModes ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), @@ -450,10 +451,10 @@ static const struct YamlNode struct_MixData[] = { }; static const struct YamlNode struct_LimitData[] = { YAML_IDX, - YAML_SIGNED( "min", 11 ), - YAML_SIGNED( "max", 11 ), + YAML_SIGNED_CUST( "min", 11, in_read_weight, in_write_weight ), + YAML_SIGNED_CUST( "max", 11, in_read_weight, in_write_weight ), YAML_SIGNED( "ppmCenter", 10 ), - YAML_SIGNED( "offset", 11 ), + YAML_SIGNED_CUST( "offset", 11, in_read_weight, in_write_weight ), YAML_UNSIGNED( "symetrical", 1 ), YAML_UNSIGNED( "revert", 1 ), YAML_PADDING( 3 ), @@ -472,7 +473,7 @@ static const struct YamlNode struct_ExpoData[] = { YAML_SIGNED_CUST( "weight", 8, in_read_weight, in_write_weight ), YAML_PADDING( 1 ), YAML_STRING("name", 6), - YAML_SIGNED( "offset", 8 ), + YAML_SIGNED_CUST( "offset", 8, in_read_weight, in_write_weight ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), YAML_END }; diff --git a/radio/src/storage/conversions/yaml/yaml_datastructs_zorro.cpp b/radio/src/storage/conversions/yaml/yaml_datastructs_zorro.cpp index 37ab5895d..4a655962a 100644 --- a/radio/src/storage/conversions/yaml/yaml_datastructs_zorro.cpp +++ b/radio/src/storage/conversions/yaml/yaml_datastructs_zorro.cpp @@ -328,6 +328,7 @@ static const struct YamlNode struct_string_24[] = { }; static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "version", 8 ), + YAML_CUSTOM("board",nullptr,w_board), YAML_PADDING( 16 ), YAML_ARRAY("calib", 48, 6, struct_CalibData, NULL), YAML_PADDING( 16 ), @@ -430,7 +431,7 @@ static const struct YamlNode struct_TimerData[] = { }; static const struct YamlNode struct_CurveRef[] = { YAML_UNSIGNED( "type", 8 ), - YAML_SIGNED( "value", 8 ), + YAML_SIGNED_CUST( "value", 8, in_read_weight, in_write_weight ), YAML_END }; static const struct YamlNode struct_MixData[] = { @@ -441,7 +442,7 @@ static const struct YamlNode struct_MixData[] = { YAML_UNSIGNED( "mixWarn", 2 ), YAML_ENUM("mltpx", 2, enum_MixerMultiplex), YAML_PADDING( 1 ), - YAML_SIGNED( "offset", 14 ), + YAML_SIGNED_CUST( "offset", 14, in_read_weight, in_write_weight ), YAML_SIGNED_CUST( "swtch", 9, r_swtchSrc, w_swtchSrc ), YAML_UNSIGNED_CUST( "flightModes", 9, r_flightModes, w_flightModes ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), @@ -454,10 +455,10 @@ static const struct YamlNode struct_MixData[] = { }; static const struct YamlNode struct_LimitData[] = { YAML_IDX, - YAML_SIGNED( "min", 11 ), - YAML_SIGNED( "max", 11 ), + YAML_SIGNED_CUST( "min", 11, in_read_weight, in_write_weight ), + YAML_SIGNED_CUST( "max", 11, in_read_weight, in_write_weight ), YAML_SIGNED( "ppmCenter", 10 ), - YAML_SIGNED( "offset", 11 ), + YAML_SIGNED_CUST( "offset", 11, in_read_weight, in_write_weight ), YAML_UNSIGNED( "symetrical", 1 ), YAML_UNSIGNED( "revert", 1 ), YAML_PADDING( 3 ), @@ -476,7 +477,7 @@ static const struct YamlNode struct_ExpoData[] = { YAML_SIGNED_CUST( "weight", 8, in_read_weight, in_write_weight ), YAML_PADDING( 1 ), YAML_STRING("name", 6), - YAML_SIGNED( "offset", 8 ), + YAML_SIGNED_CUST( "offset", 8, in_read_weight, in_write_weight ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), YAML_END }; diff --git a/radio/src/storage/eeprom_raw.cpp b/radio/src/storage/eeprom_raw.cpp index a7381319d..f3acf4ecb 100644 --- a/radio/src/storage/eeprom_raw.cpp +++ b/radio/src/storage/eeprom_raw.cpp @@ -473,7 +473,7 @@ const char * eeBackupModel(uint8_t i_fileSrc) uint16_t size = eeModelSize(i_fileSrc); - *(uint32_t*)&buf[0] = OTX_FOURCC; + *(uint32_t*)&buf[0] = ETX_FOURCC; buf[4] = g_eeGeneral.version; buf[5] = 'M'; *(uint16_t*)&buf[6] = size; @@ -540,7 +540,7 @@ const char * eeRestoreModel(uint8_t i_fileDst, char *model_name) } uint8_t version = (uint8_t)buf[4]; - if (*(uint32_t*)&buf[0] != OTX_FOURCC || version < FIRST_CONV_EEPROM_VER || version > EEPROM_VER || buf[5] != 'M') { + if (*(uint32_t*)&buf[0] != ETX_FOURCC || version < FIRST_CONV_EEPROM_VER || version > EEPROM_VER || buf[5] != 'M') { f_close(&restoreFile); return STR_INCOMPATIBLE; } diff --git a/radio/src/storage/eeprom_rlc.cpp b/radio/src/storage/eeprom_rlc.cpp index 8f18c72a1..0c8d80315 100644 --- a/radio/src/storage/eeprom_rlc.cpp +++ b/radio/src/storage/eeprom_rlc.cpp @@ -508,7 +508,7 @@ const char * eeBackupModel(uint8_t i_fileSrc) EFile theFile2; theFile2.openRd(FILE_MODEL(i_fileSrc)); - *(uint32_t*)&buf[0] = OTX_FOURCC; + *(uint32_t*)&buf[0] = ETX_FOURCC; buf[4] = g_eeGeneral.version; buf[5] = 'M'; *(uint16_t*)&buf[6] = eeModelSize(i_fileSrc); @@ -561,7 +561,7 @@ const char * eeRestoreModel(uint8_t i_fileDst, char *model_name) } uint8_t version = (uint8_t)buf[4]; - if (*(uint32_t*)&buf[0] != OTX_FOURCC || version < FIRST_CONV_EEPROM_VER || version > EEPROM_VER || buf[5] != 'M') { + if (*(uint32_t*)&buf[0] != ETX_FOURCC || version < FIRST_CONV_EEPROM_VER || version > EEPROM_VER || buf[5] != 'M') { f_close(&g_oLogFile); return STR_INCOMPATIBLE; } diff --git a/radio/src/storage/modelslist.cpp b/radio/src/storage/modelslist.cpp index b3c3f87e0..f4c609114 100644 --- a/radio/src/storage/modelslist.cpp +++ b/radio/src/storage/modelslist.cpp @@ -381,6 +381,7 @@ bool ModelsList::loadYaml() if (bytes_read == 0) break; + if (f_eof(&file)) yp.set_eof(); if (yp.parse(line, bytes_read) != YamlParser::CONTINUE_PARSING) break; } diff --git a/radio/src/storage/sdcard_raw.cpp b/radio/src/storage/sdcard_raw.cpp index 34bc56be4..b84c75554 100644 --- a/radio/src/storage/sdcard_raw.cpp +++ b/radio/src/storage/sdcard_raw.cpp @@ -37,7 +37,7 @@ const char *writeFileBin(const char *filename, const uint8_t *data, return SDCARD_ERROR(result); } - *(uint32_t*)&buf[0] = OTX_FOURCC; + *(uint32_t*)&buf[0] = ETX_FOURCC; buf[4] = version; buf[5] = 'M'; *(uint16_t*)&buf[6] = size; @@ -99,7 +99,7 @@ const char* openFileBin(const char * fullpath, FIL * file, uint16_t * size, uint } *version = (uint8_t)buf[4]; - if (*(uint32_t *)&buf[0] != OTX_FOURCC || *version < FIRST_CONV_EEPROM_VER || + if (*(uint32_t *)&buf[0] != ETX_FOURCC || *version < FIRST_CONV_EEPROM_VER || *version > EEPROM_VER || buf[5] != 'M') { f_close(file); return STR_INCOMPATIBLE; diff --git a/radio/src/storage/sdcard_yaml.cpp b/radio/src/storage/sdcard_yaml.cpp index 55e6f22cf..bbc28cddc 100644 --- a/radio/src/storage/sdcard_yaml.cpp +++ b/radio/src/storage/sdcard_yaml.cpp @@ -58,6 +58,7 @@ const char * readYamlFile(const char* fullpath, const YamlParserCalls* calls, vo if (bytes_read == 0) break; + if (f_eof(&file)) yp.set_eof(); if (yp.parse(buffer, bytes_read) != YamlParser::CONTINUE_PARSING) break; } diff --git a/radio/src/storage/yaml/yaml_bits.cpp b/radio/src/storage/yaml/yaml_bits.cpp index fc77bb98d..17c87bcf8 100644 --- a/radio/src/storage/yaml/yaml_bits.cpp +++ b/radio/src/storage/yaml/yaml_bits.cpp @@ -32,7 +32,7 @@ void yaml_put_bits(uint8_t* dst, uint32_t i, uint32_t bit_ofs, uint32_t bits) if (bit_ofs) { - *dst &= MASK_LOWER(bit_ofs); + *dst &= ~((MASK_LOWER(bits) << bit_ofs) & 0xFF); *(dst++) |= (i << bit_ofs) & 0xFF; if (bits <= 8 - bit_ofs) diff --git a/radio/src/storage/yaml/yaml_datastructs_funcs.cpp b/radio/src/storage/yaml/yaml_datastructs_funcs.cpp index 5af9c9299..b51017eaf 100644 --- a/radio/src/storage/yaml/yaml_datastructs_funcs.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_funcs.cpp @@ -28,6 +28,8 @@ // Use definitions from v220 conversions as long as nothing changes namespace yaml_conv_220 { + bool w_board(void* user, uint8_t* data, uint32_t bitoffs, yaml_writer_func wf, void* opaque); + bool in_write_weight(const YamlNode* node, uint32_t val, yaml_writer_func wf, void* opaque); bool output_source_1_param(const char* src_prefix, size_t src_len, uint32_t n, @@ -135,10 +137,16 @@ static inline void check_yaml_funcs() #endif } -#define GVAR_SMALL 128 +static bool w_board(void* user, uint8_t* data, uint32_t bitoffs, + yaml_writer_func wf, void* opaque) +{ + return yaml_conv_220::w_board(user, data, bitoffs, wf, opaque); +} static uint32_t in_read_weight(const YamlNode* node, const char* val, uint8_t val_len) { + int gvar = (node->size > 8 ? GV1_LARGE : GV1_SMALL); + if ((val_len == 4) && (val[0] == '-') && (val[1] == 'G') @@ -146,8 +154,8 @@ static uint32_t in_read_weight(const YamlNode* node, const char* val, uint8_t va && (val[3] >= '1') && (val[3] <= '9')) { - TRACE("%.*s -> %i\n", val_len, val, GVAR_SMALL - (val[3] - '0')); - return GVAR_SMALL - (val[3] - '0'); // -GVx => 128 - x + TRACE("%.*s -> %i\n", val_len, val, gvar - (val[3] - '0')); + return gvar - (val[3] - '1'); // -GVx => 128 - x } if ((val_len == 3) @@ -156,8 +164,8 @@ static uint32_t in_read_weight(const YamlNode* node, const char* val, uint8_t va && (val[2] >= '1') && (val[2] <= '9')) { - TRACE("%.*s -> %i\n", val_len, val, -GVAR_SMALL + (val[2] - '1')); - return -GVAR_SMALL + (val[2] - '1'); // GVx => -128 + (x-1) + TRACE("%.*s -> %i\n", val_len, val, -gvar + (val[2] - '1')); + return -gvar + (val[2] - '1'); // GVx => -128 + (x-1) } return (uint32_t)yaml_str2int(val, val_len); @@ -455,6 +463,11 @@ static uint32_t r_calib(void* user, const char* val, uint8_t val_len) uint32_t sw = yaml_parse_enum(enum_MixSources, val, val_len); if (sw >= MIXSRC_Rud) return sw - MIXSRC_Rud; + // detect invalid values + if (val_len == 0 || (val[0] < '0') || (val[0] > '9')) { + return -1; + } + return (uint32_t)yaml_str2int(val, val_len); } @@ -1646,8 +1659,8 @@ static void r_modSubtype(void* user, uint8_t* data, uint32_t bitoffs, val++; val_len--; int subtype = yaml_str2uint(val, val_len); - // convert to OTX format and write to vars - convertMultiProtocolToOtx(&type, &subtype); + // convert to ETX format and write to vars + convertMultiProtocolToEtx(&type, &subtype); if (type > 0) { md->setMultiProtocol(type - 1); md->subType = subtype; diff --git a/radio/src/storage/yaml/yaml_datastructs_nv14.cpp b/radio/src/storage/yaml/yaml_datastructs_nv14.cpp index 71e0dc879..48572ca88 100644 --- a/radio/src/storage/yaml/yaml_datastructs_nv14.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_nv14.cpp @@ -357,6 +357,7 @@ static const struct YamlNode struct_OpenTxTheme__PersistentData[] = { }; static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "version", 8 ), + YAML_CUSTOM("board",nullptr,w_board), YAML_PADDING( 16 ), YAML_ARRAY("calib", 48, 9, struct_CalibData, NULL), YAML_PADDING( 16 ), @@ -390,12 +391,10 @@ static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "templateSetup", 8 ), YAML_SIGNED( "PPM_Multiplier", 8 ), YAML_SIGNED_CUST( "hapticLength", 8, r_5pos, w_5pos ), - YAML_PADDING( 8 ), - YAML_UNSIGNED( "stickReverse", 8 ), YAML_SIGNED_CUST( "beepLength", 3, r_5pos, w_5pos ), YAML_SIGNED_CUST( "hapticStrength", 3, r_5pos, w_5pos ), YAML_UNSIGNED( "gpsFormat", 1 ), - YAML_UNSIGNED( "unexpectedShutdown", 1 ), + YAML_PADDING( 1 ), YAML_UNSIGNED_CUST( "speakerPitch", 8, r_spPitch, w_spPitch ), YAML_SIGNED_CUST( "speakerVolume", 8, r_vol, w_vol ), YAML_SIGNED_CUST( "vBatMin", 8, r_vbat_min, w_vbat_min ), @@ -466,7 +465,7 @@ static const struct YamlNode struct_TimerData[] = { }; static const struct YamlNode struct_CurveRef[] = { YAML_UNSIGNED( "type", 8 ), - YAML_SIGNED( "value", 8 ), + YAML_SIGNED_CUST( "value", 8, in_read_weight, in_write_weight ), YAML_END }; static const struct YamlNode struct_MixData[] = { @@ -477,7 +476,7 @@ static const struct YamlNode struct_MixData[] = { YAML_UNSIGNED( "mixWarn", 2 ), YAML_ENUM("mltpx", 2, enum_MixerMultiplex), YAML_PADDING( 1 ), - YAML_SIGNED( "offset", 14 ), + YAML_SIGNED_CUST( "offset", 14, in_read_weight, in_write_weight ), YAML_SIGNED_CUST( "swtch", 9, r_swtchSrc, w_swtchSrc ), YAML_UNSIGNED_CUST( "flightModes", 9, r_flightModes, w_flightModes ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), @@ -490,10 +489,10 @@ static const struct YamlNode struct_MixData[] = { }; static const struct YamlNode struct_LimitData[] = { YAML_IDX, - YAML_SIGNED( "min", 11 ), - YAML_SIGNED( "max", 11 ), + YAML_SIGNED_CUST( "min", 11, in_read_weight, in_write_weight ), + YAML_SIGNED_CUST( "max", 11, in_read_weight, in_write_weight ), YAML_SIGNED( "ppmCenter", 10 ), - YAML_SIGNED( "offset", 11 ), + YAML_SIGNED_CUST( "offset", 11, in_read_weight, in_write_weight ), YAML_UNSIGNED( "symetrical", 1 ), YAML_UNSIGNED( "revert", 1 ), YAML_PADDING( 3 ), @@ -512,7 +511,7 @@ static const struct YamlNode struct_ExpoData[] = { YAML_SIGNED_CUST( "weight", 8, in_read_weight, in_write_weight ), YAML_PADDING( 1 ), YAML_STRING("name", 6), - YAML_SIGNED( "offset", 8 ), + YAML_SIGNED_CUST( "offset", 8, in_read_weight, in_write_weight ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), YAML_END }; diff --git a/radio/src/storage/yaml/yaml_datastructs_t12.cpp b/radio/src/storage/yaml/yaml_datastructs_t12.cpp index 218804cb1..a0da3fdaf 100644 --- a/radio/src/storage/yaml/yaml_datastructs_t12.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_t12.cpp @@ -328,6 +328,7 @@ static const struct YamlNode struct_string_24[] = { }; static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "version", 8 ), + YAML_CUSTOM("board",nullptr,w_board), YAML_PADDING( 16 ), YAML_ARRAY("calib", 48, 6, struct_CalibData, NULL), YAML_PADDING( 16 ), @@ -364,7 +365,7 @@ static const struct YamlNode struct_RadioData[] = { YAML_SIGNED_CUST( "beepLength", 3, r_5pos, w_5pos ), YAML_SIGNED_CUST( "hapticStrength", 3, r_5pos, w_5pos ), YAML_UNSIGNED( "gpsFormat", 1 ), - YAML_UNSIGNED( "unexpectedShutdown", 1 ), + YAML_PADDING( 1 ), YAML_UNSIGNED_CUST( "speakerPitch", 8, r_spPitch, w_spPitch ), YAML_SIGNED_CUST( "speakerVolume", 8, r_vol, w_vol ), YAML_SIGNED_CUST( "vBatMin", 8, r_vbat_min, w_vbat_min ), @@ -430,7 +431,7 @@ static const struct YamlNode struct_TimerData[] = { }; static const struct YamlNode struct_CurveRef[] = { YAML_UNSIGNED( "type", 8 ), - YAML_SIGNED( "value", 8 ), + YAML_SIGNED_CUST( "value", 8, in_read_weight, in_write_weight ), YAML_END }; static const struct YamlNode struct_MixData[] = { @@ -441,7 +442,7 @@ static const struct YamlNode struct_MixData[] = { YAML_UNSIGNED( "mixWarn", 2 ), YAML_ENUM("mltpx", 2, enum_MixerMultiplex), YAML_PADDING( 1 ), - YAML_SIGNED( "offset", 14 ), + YAML_SIGNED_CUST( "offset", 14, in_read_weight, in_write_weight ), YAML_SIGNED_CUST( "swtch", 9, r_swtchSrc, w_swtchSrc ), YAML_UNSIGNED_CUST( "flightModes", 9, r_flightModes, w_flightModes ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), @@ -454,10 +455,10 @@ static const struct YamlNode struct_MixData[] = { }; static const struct YamlNode struct_LimitData[] = { YAML_IDX, - YAML_SIGNED( "min", 11 ), - YAML_SIGNED( "max", 11 ), + YAML_SIGNED_CUST( "min", 11, in_read_weight, in_write_weight ), + YAML_SIGNED_CUST( "max", 11, in_read_weight, in_write_weight ), YAML_SIGNED( "ppmCenter", 10 ), - YAML_SIGNED( "offset", 11 ), + YAML_SIGNED_CUST( "offset", 11, in_read_weight, in_write_weight ), YAML_UNSIGNED( "symetrical", 1 ), YAML_UNSIGNED( "revert", 1 ), YAML_PADDING( 3 ), @@ -476,7 +477,7 @@ static const struct YamlNode struct_ExpoData[] = { YAML_SIGNED_CUST( "weight", 8, in_read_weight, in_write_weight ), YAML_PADDING( 1 ), YAML_STRING("name", 6), - YAML_SIGNED( "offset", 8 ), + YAML_SIGNED_CUST( "offset", 8, in_read_weight, in_write_weight ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), YAML_END }; diff --git a/radio/src/storage/yaml/yaml_datastructs_t8.cpp b/radio/src/storage/yaml/yaml_datastructs_t8.cpp index c364bb3aa..70ae1f57e 100644 --- a/radio/src/storage/yaml/yaml_datastructs_t8.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_t8.cpp @@ -328,6 +328,7 @@ static const struct YamlNode struct_string_24[] = { }; static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "version", 8 ), + YAML_CUSTOM("board",nullptr,w_board), YAML_PADDING( 16 ), YAML_ARRAY("calib", 48, 6, struct_CalibData, NULL), YAML_PADDING( 16 ), @@ -364,7 +365,7 @@ static const struct YamlNode struct_RadioData[] = { YAML_SIGNED_CUST( "beepLength", 3, r_5pos, w_5pos ), YAML_SIGNED_CUST( "hapticStrength", 3, r_5pos, w_5pos ), YAML_UNSIGNED( "gpsFormat", 1 ), - YAML_UNSIGNED( "unexpectedShutdown", 1 ), + YAML_PADDING( 1 ), YAML_UNSIGNED_CUST( "speakerPitch", 8, r_spPitch, w_spPitch ), YAML_SIGNED_CUST( "speakerVolume", 8, r_vol, w_vol ), YAML_SIGNED_CUST( "vBatMin", 8, r_vbat_min, w_vbat_min ), @@ -430,7 +431,7 @@ static const struct YamlNode struct_TimerData[] = { }; static const struct YamlNode struct_CurveRef[] = { YAML_UNSIGNED( "type", 8 ), - YAML_SIGNED( "value", 8 ), + YAML_SIGNED_CUST( "value", 8, in_read_weight, in_write_weight ), YAML_END }; static const struct YamlNode struct_MixData[] = { @@ -441,7 +442,7 @@ static const struct YamlNode struct_MixData[] = { YAML_UNSIGNED( "mixWarn", 2 ), YAML_ENUM("mltpx", 2, enum_MixerMultiplex), YAML_PADDING( 1 ), - YAML_SIGNED( "offset", 14 ), + YAML_SIGNED_CUST( "offset", 14, in_read_weight, in_write_weight ), YAML_SIGNED_CUST( "swtch", 9, r_swtchSrc, w_swtchSrc ), YAML_UNSIGNED_CUST( "flightModes", 9, r_flightModes, w_flightModes ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), @@ -454,10 +455,10 @@ static const struct YamlNode struct_MixData[] = { }; static const struct YamlNode struct_LimitData[] = { YAML_IDX, - YAML_SIGNED( "min", 11 ), - YAML_SIGNED( "max", 11 ), + YAML_SIGNED_CUST( "min", 11, in_read_weight, in_write_weight ), + YAML_SIGNED_CUST( "max", 11, in_read_weight, in_write_weight ), YAML_SIGNED( "ppmCenter", 10 ), - YAML_SIGNED( "offset", 11 ), + YAML_SIGNED_CUST( "offset", 11, in_read_weight, in_write_weight ), YAML_UNSIGNED( "symetrical", 1 ), YAML_UNSIGNED( "revert", 1 ), YAML_PADDING( 3 ), @@ -476,7 +477,7 @@ static const struct YamlNode struct_ExpoData[] = { YAML_SIGNED_CUST( "weight", 8, in_read_weight, in_write_weight ), YAML_PADDING( 1 ), YAML_STRING("name", 6), - YAML_SIGNED( "offset", 8 ), + YAML_SIGNED_CUST( "offset", 8, in_read_weight, in_write_weight ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), YAML_END }; diff --git a/radio/src/storage/yaml/yaml_datastructs_tlite.cpp b/radio/src/storage/yaml/yaml_datastructs_tlite.cpp index c364bb3aa..70ae1f57e 100644 --- a/radio/src/storage/yaml/yaml_datastructs_tlite.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_tlite.cpp @@ -328,6 +328,7 @@ static const struct YamlNode struct_string_24[] = { }; static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "version", 8 ), + YAML_CUSTOM("board",nullptr,w_board), YAML_PADDING( 16 ), YAML_ARRAY("calib", 48, 6, struct_CalibData, NULL), YAML_PADDING( 16 ), @@ -364,7 +365,7 @@ static const struct YamlNode struct_RadioData[] = { YAML_SIGNED_CUST( "beepLength", 3, r_5pos, w_5pos ), YAML_SIGNED_CUST( "hapticStrength", 3, r_5pos, w_5pos ), YAML_UNSIGNED( "gpsFormat", 1 ), - YAML_UNSIGNED( "unexpectedShutdown", 1 ), + YAML_PADDING( 1 ), YAML_UNSIGNED_CUST( "speakerPitch", 8, r_spPitch, w_spPitch ), YAML_SIGNED_CUST( "speakerVolume", 8, r_vol, w_vol ), YAML_SIGNED_CUST( "vBatMin", 8, r_vbat_min, w_vbat_min ), @@ -430,7 +431,7 @@ static const struct YamlNode struct_TimerData[] = { }; static const struct YamlNode struct_CurveRef[] = { YAML_UNSIGNED( "type", 8 ), - YAML_SIGNED( "value", 8 ), + YAML_SIGNED_CUST( "value", 8, in_read_weight, in_write_weight ), YAML_END }; static const struct YamlNode struct_MixData[] = { @@ -441,7 +442,7 @@ static const struct YamlNode struct_MixData[] = { YAML_UNSIGNED( "mixWarn", 2 ), YAML_ENUM("mltpx", 2, enum_MixerMultiplex), YAML_PADDING( 1 ), - YAML_SIGNED( "offset", 14 ), + YAML_SIGNED_CUST( "offset", 14, in_read_weight, in_write_weight ), YAML_SIGNED_CUST( "swtch", 9, r_swtchSrc, w_swtchSrc ), YAML_UNSIGNED_CUST( "flightModes", 9, r_flightModes, w_flightModes ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), @@ -454,10 +455,10 @@ static const struct YamlNode struct_MixData[] = { }; static const struct YamlNode struct_LimitData[] = { YAML_IDX, - YAML_SIGNED( "min", 11 ), - YAML_SIGNED( "max", 11 ), + YAML_SIGNED_CUST( "min", 11, in_read_weight, in_write_weight ), + YAML_SIGNED_CUST( "max", 11, in_read_weight, in_write_weight ), YAML_SIGNED( "ppmCenter", 10 ), - YAML_SIGNED( "offset", 11 ), + YAML_SIGNED_CUST( "offset", 11, in_read_weight, in_write_weight ), YAML_UNSIGNED( "symetrical", 1 ), YAML_UNSIGNED( "revert", 1 ), YAML_PADDING( 3 ), @@ -476,7 +477,7 @@ static const struct YamlNode struct_ExpoData[] = { YAML_SIGNED_CUST( "weight", 8, in_read_weight, in_write_weight ), YAML_PADDING( 1 ), YAML_STRING("name", 6), - YAML_SIGNED( "offset", 8 ), + YAML_SIGNED_CUST( "offset", 8, in_read_weight, in_write_weight ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), YAML_END }; diff --git a/radio/src/storage/yaml/yaml_datastructs_tpro.cpp b/radio/src/storage/yaml/yaml_datastructs_tpro.cpp index 6966b1ff8..30485f8c3 100644 --- a/radio/src/storage/yaml/yaml_datastructs_tpro.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_tpro.cpp @@ -336,6 +336,7 @@ static const struct YamlNode struct_string_24[] = { }; static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "version", 8 ), + YAML_CUSTOM("board",nullptr,w_board), YAML_PADDING( 16 ), YAML_ARRAY("calib", 48, 6, struct_CalibData, NULL), YAML_PADDING( 16 ), @@ -372,7 +373,7 @@ static const struct YamlNode struct_RadioData[] = { YAML_SIGNED_CUST( "beepLength", 3, r_5pos, w_5pos ), YAML_SIGNED_CUST( "hapticStrength", 3, r_5pos, w_5pos ), YAML_UNSIGNED( "gpsFormat", 1 ), - YAML_UNSIGNED( "unexpectedShutdown", 1 ), + YAML_PADDING( 1 ), YAML_UNSIGNED_CUST( "speakerPitch", 8, r_spPitch, w_spPitch ), YAML_SIGNED_CUST( "speakerVolume", 8, r_vol, w_vol ), YAML_SIGNED_CUST( "vBatMin", 8, r_vbat_min, w_vbat_min ), @@ -436,7 +437,7 @@ static const struct YamlNode struct_TimerData[] = { }; static const struct YamlNode struct_CurveRef[] = { YAML_UNSIGNED( "type", 8 ), - YAML_SIGNED( "value", 8 ), + YAML_SIGNED_CUST( "value", 8, in_read_weight, in_write_weight ), YAML_END }; static const struct YamlNode struct_MixData[] = { @@ -447,7 +448,7 @@ static const struct YamlNode struct_MixData[] = { YAML_UNSIGNED( "mixWarn", 2 ), YAML_ENUM("mltpx", 2, enum_MixerMultiplex), YAML_PADDING( 1 ), - YAML_SIGNED( "offset", 14 ), + YAML_SIGNED_CUST( "offset", 14, in_read_weight, in_write_weight ), YAML_SIGNED_CUST( "swtch", 9, r_swtchSrc, w_swtchSrc ), YAML_UNSIGNED_CUST( "flightModes", 9, r_flightModes, w_flightModes ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), @@ -460,10 +461,10 @@ static const struct YamlNode struct_MixData[] = { }; static const struct YamlNode struct_LimitData[] = { YAML_IDX, - YAML_SIGNED( "min", 11 ), - YAML_SIGNED( "max", 11 ), + YAML_SIGNED_CUST( "min", 11, in_read_weight, in_write_weight ), + YAML_SIGNED_CUST( "max", 11, in_read_weight, in_write_weight ), YAML_SIGNED( "ppmCenter", 10 ), - YAML_SIGNED( "offset", 11 ), + YAML_SIGNED_CUST( "offset", 11, in_read_weight, in_write_weight ), YAML_UNSIGNED( "symetrical", 1 ), YAML_UNSIGNED( "revert", 1 ), YAML_PADDING( 3 ), @@ -482,7 +483,7 @@ static const struct YamlNode struct_ExpoData[] = { YAML_SIGNED_CUST( "weight", 8, in_read_weight, in_write_weight ), YAML_PADDING( 1 ), YAML_STRING("name", 6), - YAML_SIGNED( "offset", 8 ), + YAML_SIGNED_CUST( "offset", 8, in_read_weight, in_write_weight ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), YAML_END }; diff --git a/radio/src/storage/yaml/yaml_datastructs_tx12.cpp b/radio/src/storage/yaml/yaml_datastructs_tx12.cpp index 68e5bdf06..731f46515 100644 --- a/radio/src/storage/yaml/yaml_datastructs_tx12.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_tx12.cpp @@ -328,6 +328,7 @@ static const struct YamlNode struct_string_24[] = { }; static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "version", 8 ), + YAML_CUSTOM("board",nullptr,w_board), YAML_PADDING( 16 ), YAML_ARRAY("calib", 48, 6, struct_CalibData, NULL), YAML_PADDING( 16 ), @@ -364,7 +365,7 @@ static const struct YamlNode struct_RadioData[] = { YAML_SIGNED_CUST( "beepLength", 3, r_5pos, w_5pos ), YAML_SIGNED_CUST( "hapticStrength", 3, r_5pos, w_5pos ), YAML_UNSIGNED( "gpsFormat", 1 ), - YAML_UNSIGNED( "unexpectedShutdown", 1 ), + YAML_PADDING( 1 ), YAML_UNSIGNED_CUST( "speakerPitch", 8, r_spPitch, w_spPitch ), YAML_SIGNED_CUST( "speakerVolume", 8, r_vol, w_vol ), YAML_SIGNED_CUST( "vBatMin", 8, r_vbat_min, w_vbat_min ), @@ -430,7 +431,7 @@ static const struct YamlNode struct_TimerData[] = { }; static const struct YamlNode struct_CurveRef[] = { YAML_UNSIGNED( "type", 8 ), - YAML_SIGNED( "value", 8 ), + YAML_SIGNED_CUST( "value", 8, in_read_weight, in_write_weight ), YAML_END }; static const struct YamlNode struct_MixData[] = { @@ -441,7 +442,7 @@ static const struct YamlNode struct_MixData[] = { YAML_UNSIGNED( "mixWarn", 2 ), YAML_ENUM("mltpx", 2, enum_MixerMultiplex), YAML_PADDING( 1 ), - YAML_SIGNED( "offset", 14 ), + YAML_SIGNED_CUST( "offset", 14, in_read_weight, in_write_weight ), YAML_SIGNED_CUST( "swtch", 9, r_swtchSrc, w_swtchSrc ), YAML_UNSIGNED_CUST( "flightModes", 9, r_flightModes, w_flightModes ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), @@ -454,10 +455,10 @@ static const struct YamlNode struct_MixData[] = { }; static const struct YamlNode struct_LimitData[] = { YAML_IDX, - YAML_SIGNED( "min", 11 ), - YAML_SIGNED( "max", 11 ), + YAML_SIGNED_CUST( "min", 11, in_read_weight, in_write_weight ), + YAML_SIGNED_CUST( "max", 11, in_read_weight, in_write_weight ), YAML_SIGNED( "ppmCenter", 10 ), - YAML_SIGNED( "offset", 11 ), + YAML_SIGNED_CUST( "offset", 11, in_read_weight, in_write_weight ), YAML_UNSIGNED( "symetrical", 1 ), YAML_UNSIGNED( "revert", 1 ), YAML_PADDING( 3 ), @@ -476,7 +477,7 @@ static const struct YamlNode struct_ExpoData[] = { YAML_SIGNED_CUST( "weight", 8, in_read_weight, in_write_weight ), YAML_PADDING( 1 ), YAML_STRING("name", 6), - YAML_SIGNED( "offset", 8 ), + YAML_SIGNED_CUST( "offset", 8, in_read_weight, in_write_weight ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), YAML_END }; diff --git a/radio/src/storage/yaml/yaml_datastructs_x10.cpp b/radio/src/storage/yaml/yaml_datastructs_x10.cpp index 026ea7d1f..2db86eb85 100644 --- a/radio/src/storage/yaml/yaml_datastructs_x10.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_x10.cpp @@ -380,6 +380,7 @@ static const struct YamlNode struct_OpenTxTheme__PersistentData[] = { }; static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "version", 8 ), + YAML_CUSTOM("board",nullptr,w_board), YAML_PADDING( 16 ), YAML_ARRAY("calib", 48, 17, struct_CalibData, NULL), YAML_PADDING( 16 ), @@ -414,7 +415,7 @@ static const struct YamlNode struct_RadioData[] = { YAML_SIGNED_CUST( "beepLength", 3, r_5pos, w_5pos ), YAML_SIGNED_CUST( "hapticStrength", 3, r_5pos, w_5pos ), YAML_UNSIGNED( "gpsFormat", 1 ), - YAML_UNSIGNED( "unexpectedShutdown", 1 ), + YAML_PADDING( 1 ), YAML_UNSIGNED_CUST( "speakerPitch", 8, r_spPitch, w_spPitch ), YAML_SIGNED_CUST( "speakerVolume", 8, r_vol, w_vol ), YAML_SIGNED_CUST( "vBatMin", 8, r_vbat_min, w_vbat_min ), @@ -485,7 +486,7 @@ static const struct YamlNode struct_TimerData[] = { }; static const struct YamlNode struct_CurveRef[] = { YAML_UNSIGNED( "type", 8 ), - YAML_SIGNED( "value", 8 ), + YAML_SIGNED_CUST( "value", 8, in_read_weight, in_write_weight ), YAML_END }; static const struct YamlNode struct_MixData[] = { @@ -496,7 +497,7 @@ static const struct YamlNode struct_MixData[] = { YAML_UNSIGNED( "mixWarn", 2 ), YAML_ENUM("mltpx", 2, enum_MixerMultiplex), YAML_PADDING( 1 ), - YAML_SIGNED( "offset", 14 ), + YAML_SIGNED_CUST( "offset", 14, in_read_weight, in_write_weight ), YAML_SIGNED_CUST( "swtch", 9, r_swtchSrc, w_swtchSrc ), YAML_UNSIGNED_CUST( "flightModes", 9, r_flightModes, w_flightModes ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), @@ -509,10 +510,10 @@ static const struct YamlNode struct_MixData[] = { }; static const struct YamlNode struct_LimitData[] = { YAML_IDX, - YAML_SIGNED( "min", 11 ), - YAML_SIGNED( "max", 11 ), + YAML_SIGNED_CUST( "min", 11, in_read_weight, in_write_weight ), + YAML_SIGNED_CUST( "max", 11, in_read_weight, in_write_weight ), YAML_SIGNED( "ppmCenter", 10 ), - YAML_SIGNED( "offset", 11 ), + YAML_SIGNED_CUST( "offset", 11, in_read_weight, in_write_weight ), YAML_UNSIGNED( "symetrical", 1 ), YAML_UNSIGNED( "revert", 1 ), YAML_PADDING( 3 ), @@ -531,7 +532,7 @@ static const struct YamlNode struct_ExpoData[] = { YAML_SIGNED_CUST( "weight", 8, in_read_weight, in_write_weight ), YAML_PADDING( 1 ), YAML_STRING("name", 6), - YAML_SIGNED( "offset", 8 ), + YAML_SIGNED_CUST( "offset", 8, in_read_weight, in_write_weight ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), YAML_END }; diff --git a/radio/src/storage/yaml/yaml_datastructs_x12s.cpp b/radio/src/storage/yaml/yaml_datastructs_x12s.cpp index 0c81b1704..40b01a388 100644 --- a/radio/src/storage/yaml/yaml_datastructs_x12s.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_x12s.cpp @@ -378,6 +378,7 @@ static const struct YamlNode struct_OpenTxTheme__PersistentData[] = { }; static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "version", 8 ), + YAML_CUSTOM("board",nullptr,w_board), YAML_PADDING( 16 ), YAML_ARRAY("calib", 48, 15, struct_CalibData, NULL), YAML_PADDING( 16 ), @@ -412,7 +413,7 @@ static const struct YamlNode struct_RadioData[] = { YAML_SIGNED_CUST( "beepLength", 3, r_5pos, w_5pos ), YAML_SIGNED_CUST( "hapticStrength", 3, r_5pos, w_5pos ), YAML_UNSIGNED( "gpsFormat", 1 ), - YAML_UNSIGNED( "unexpectedShutdown", 1 ), + YAML_PADDING( 1 ), YAML_UNSIGNED_CUST( "speakerPitch", 8, r_spPitch, w_spPitch ), YAML_SIGNED_CUST( "speakerVolume", 8, r_vol, w_vol ), YAML_SIGNED_CUST( "vBatMin", 8, r_vbat_min, w_vbat_min ), @@ -483,7 +484,7 @@ static const struct YamlNode struct_TimerData[] = { }; static const struct YamlNode struct_CurveRef[] = { YAML_UNSIGNED( "type", 8 ), - YAML_SIGNED( "value", 8 ), + YAML_SIGNED_CUST( "value", 8, in_read_weight, in_write_weight ), YAML_END }; static const struct YamlNode struct_MixData[] = { @@ -494,7 +495,7 @@ static const struct YamlNode struct_MixData[] = { YAML_UNSIGNED( "mixWarn", 2 ), YAML_ENUM("mltpx", 2, enum_MixerMultiplex), YAML_PADDING( 1 ), - YAML_SIGNED( "offset", 14 ), + YAML_SIGNED_CUST( "offset", 14, in_read_weight, in_write_weight ), YAML_SIGNED_CUST( "swtch", 9, r_swtchSrc, w_swtchSrc ), YAML_UNSIGNED_CUST( "flightModes", 9, r_flightModes, w_flightModes ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), @@ -507,10 +508,10 @@ static const struct YamlNode struct_MixData[] = { }; static const struct YamlNode struct_LimitData[] = { YAML_IDX, - YAML_SIGNED( "min", 11 ), - YAML_SIGNED( "max", 11 ), + YAML_SIGNED_CUST( "min", 11, in_read_weight, in_write_weight ), + YAML_SIGNED_CUST( "max", 11, in_read_weight, in_write_weight ), YAML_SIGNED( "ppmCenter", 10 ), - YAML_SIGNED( "offset", 11 ), + YAML_SIGNED_CUST( "offset", 11, in_read_weight, in_write_weight ), YAML_UNSIGNED( "symetrical", 1 ), YAML_UNSIGNED( "revert", 1 ), YAML_PADDING( 3 ), @@ -529,7 +530,7 @@ static const struct YamlNode struct_ExpoData[] = { YAML_SIGNED_CUST( "weight", 8, in_read_weight, in_write_weight ), YAML_PADDING( 1 ), YAML_STRING("name", 6), - YAML_SIGNED( "offset", 8 ), + YAML_SIGNED_CUST( "offset", 8, in_read_weight, in_write_weight ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), YAML_END }; diff --git a/radio/src/storage/yaml/yaml_datastructs_x7.cpp b/radio/src/storage/yaml/yaml_datastructs_x7.cpp index c364bb3aa..70ae1f57e 100644 --- a/radio/src/storage/yaml/yaml_datastructs_x7.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_x7.cpp @@ -328,6 +328,7 @@ static const struct YamlNode struct_string_24[] = { }; static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "version", 8 ), + YAML_CUSTOM("board",nullptr,w_board), YAML_PADDING( 16 ), YAML_ARRAY("calib", 48, 6, struct_CalibData, NULL), YAML_PADDING( 16 ), @@ -364,7 +365,7 @@ static const struct YamlNode struct_RadioData[] = { YAML_SIGNED_CUST( "beepLength", 3, r_5pos, w_5pos ), YAML_SIGNED_CUST( "hapticStrength", 3, r_5pos, w_5pos ), YAML_UNSIGNED( "gpsFormat", 1 ), - YAML_UNSIGNED( "unexpectedShutdown", 1 ), + YAML_PADDING( 1 ), YAML_UNSIGNED_CUST( "speakerPitch", 8, r_spPitch, w_spPitch ), YAML_SIGNED_CUST( "speakerVolume", 8, r_vol, w_vol ), YAML_SIGNED_CUST( "vBatMin", 8, r_vbat_min, w_vbat_min ), @@ -430,7 +431,7 @@ static const struct YamlNode struct_TimerData[] = { }; static const struct YamlNode struct_CurveRef[] = { YAML_UNSIGNED( "type", 8 ), - YAML_SIGNED( "value", 8 ), + YAML_SIGNED_CUST( "value", 8, in_read_weight, in_write_weight ), YAML_END }; static const struct YamlNode struct_MixData[] = { @@ -441,7 +442,7 @@ static const struct YamlNode struct_MixData[] = { YAML_UNSIGNED( "mixWarn", 2 ), YAML_ENUM("mltpx", 2, enum_MixerMultiplex), YAML_PADDING( 1 ), - YAML_SIGNED( "offset", 14 ), + YAML_SIGNED_CUST( "offset", 14, in_read_weight, in_write_weight ), YAML_SIGNED_CUST( "swtch", 9, r_swtchSrc, w_swtchSrc ), YAML_UNSIGNED_CUST( "flightModes", 9, r_flightModes, w_flightModes ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), @@ -454,10 +455,10 @@ static const struct YamlNode struct_MixData[] = { }; static const struct YamlNode struct_LimitData[] = { YAML_IDX, - YAML_SIGNED( "min", 11 ), - YAML_SIGNED( "max", 11 ), + YAML_SIGNED_CUST( "min", 11, in_read_weight, in_write_weight ), + YAML_SIGNED_CUST( "max", 11, in_read_weight, in_write_weight ), YAML_SIGNED( "ppmCenter", 10 ), - YAML_SIGNED( "offset", 11 ), + YAML_SIGNED_CUST( "offset", 11, in_read_weight, in_write_weight ), YAML_UNSIGNED( "symetrical", 1 ), YAML_UNSIGNED( "revert", 1 ), YAML_PADDING( 3 ), @@ -476,7 +477,7 @@ static const struct YamlNode struct_ExpoData[] = { YAML_SIGNED_CUST( "weight", 8, in_read_weight, in_write_weight ), YAML_PADDING( 1 ), YAML_STRING("name", 6), - YAML_SIGNED( "offset", 8 ), + YAML_SIGNED_CUST( "offset", 8, in_read_weight, in_write_weight ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), YAML_END }; diff --git a/radio/src/storage/yaml/yaml_datastructs_x9d.cpp b/radio/src/storage/yaml/yaml_datastructs_x9d.cpp index 43b797e14..baa86f46d 100644 --- a/radio/src/storage/yaml/yaml_datastructs_x9d.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_x9d.cpp @@ -335,6 +335,7 @@ static const struct YamlNode struct_string_24[] = { }; static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "version", 8 ), + YAML_CUSTOM("board",nullptr,w_board), YAML_PADDING( 16 ), YAML_ARRAY("calib", 48, 9, struct_CalibData, NULL), YAML_PADDING( 16 ), @@ -371,7 +372,7 @@ static const struct YamlNode struct_RadioData[] = { YAML_SIGNED_CUST( "beepLength", 3, r_5pos, w_5pos ), YAML_SIGNED_CUST( "hapticStrength", 3, r_5pos, w_5pos ), YAML_UNSIGNED( "gpsFormat", 1 ), - YAML_UNSIGNED( "unexpectedShutdown", 1 ), + YAML_PADDING( 1 ), YAML_UNSIGNED_CUST( "speakerPitch", 8, r_spPitch, w_spPitch ), YAML_SIGNED_CUST( "speakerVolume", 8, r_vol, w_vol ), YAML_SIGNED_CUST( "vBatMin", 8, r_vbat_min, w_vbat_min ), @@ -438,7 +439,7 @@ static const struct YamlNode struct_TimerData[] = { }; static const struct YamlNode struct_CurveRef[] = { YAML_UNSIGNED( "type", 8 ), - YAML_SIGNED( "value", 8 ), + YAML_SIGNED_CUST( "value", 8, in_read_weight, in_write_weight ), YAML_END }; static const struct YamlNode struct_MixData[] = { @@ -449,7 +450,7 @@ static const struct YamlNode struct_MixData[] = { YAML_UNSIGNED( "mixWarn", 2 ), YAML_ENUM("mltpx", 2, enum_MixerMultiplex), YAML_PADDING( 1 ), - YAML_SIGNED( "offset", 14 ), + YAML_SIGNED_CUST( "offset", 14, in_read_weight, in_write_weight ), YAML_SIGNED_CUST( "swtch", 9, r_swtchSrc, w_swtchSrc ), YAML_UNSIGNED_CUST( "flightModes", 9, r_flightModes, w_flightModes ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), @@ -462,10 +463,10 @@ static const struct YamlNode struct_MixData[] = { }; static const struct YamlNode struct_LimitData[] = { YAML_IDX, - YAML_SIGNED( "min", 11 ), - YAML_SIGNED( "max", 11 ), + YAML_SIGNED_CUST( "min", 11, in_read_weight, in_write_weight ), + YAML_SIGNED_CUST( "max", 11, in_read_weight, in_write_weight ), YAML_SIGNED( "ppmCenter", 10 ), - YAML_SIGNED( "offset", 11 ), + YAML_SIGNED_CUST( "offset", 11, in_read_weight, in_write_weight ), YAML_UNSIGNED( "symetrical", 1 ), YAML_UNSIGNED( "revert", 1 ), YAML_PADDING( 3 ), @@ -484,7 +485,7 @@ static const struct YamlNode struct_ExpoData[] = { YAML_SIGNED_CUST( "weight", 8, in_read_weight, in_write_weight ), YAML_PADDING( 1 ), YAML_STRING("name", 6), - YAML_SIGNED( "offset", 8 ), + YAML_SIGNED_CUST( "offset", 8, in_read_weight, in_write_weight ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), YAML_END }; diff --git a/radio/src/storage/yaml/yaml_datastructs_x9e.cpp b/radio/src/storage/yaml/yaml_datastructs_x9e.cpp index 0488418f1..927510ceb 100644 --- a/radio/src/storage/yaml/yaml_datastructs_x9e.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_x9e.cpp @@ -374,6 +374,7 @@ static const struct YamlNode struct_string_24[] = { }; static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "version", 8 ), + YAML_CUSTOM("board",nullptr,w_board), YAML_PADDING( 16 ), YAML_ARRAY("calib", 48, 12, struct_CalibData, NULL), YAML_PADDING( 16 ), @@ -410,7 +411,7 @@ static const struct YamlNode struct_RadioData[] = { YAML_SIGNED_CUST( "beepLength", 3, r_5pos, w_5pos ), YAML_SIGNED_CUST( "hapticStrength", 3, r_5pos, w_5pos ), YAML_UNSIGNED( "gpsFormat", 1 ), - YAML_UNSIGNED( "unexpectedShutdown", 1 ), + YAML_PADDING( 1 ), YAML_UNSIGNED_CUST( "speakerPitch", 8, r_spPitch, w_spPitch ), YAML_SIGNED_CUST( "speakerVolume", 8, r_vol, w_vol ), YAML_SIGNED_CUST( "vBatMin", 8, r_vbat_min, w_vbat_min ), @@ -477,7 +478,7 @@ static const struct YamlNode struct_TimerData[] = { }; static const struct YamlNode struct_CurveRef[] = { YAML_UNSIGNED( "type", 8 ), - YAML_SIGNED( "value", 8 ), + YAML_SIGNED_CUST( "value", 8, in_read_weight, in_write_weight ), YAML_END }; static const struct YamlNode struct_MixData[] = { @@ -488,7 +489,7 @@ static const struct YamlNode struct_MixData[] = { YAML_UNSIGNED( "mixWarn", 2 ), YAML_ENUM("mltpx", 2, enum_MixerMultiplex), YAML_PADDING( 1 ), - YAML_SIGNED( "offset", 14 ), + YAML_SIGNED_CUST( "offset", 14, in_read_weight, in_write_weight ), YAML_SIGNED_CUST( "swtch", 9, r_swtchSrc, w_swtchSrc ), YAML_UNSIGNED_CUST( "flightModes", 9, r_flightModes, w_flightModes ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), @@ -501,10 +502,10 @@ static const struct YamlNode struct_MixData[] = { }; static const struct YamlNode struct_LimitData[] = { YAML_IDX, - YAML_SIGNED( "min", 11 ), - YAML_SIGNED( "max", 11 ), + YAML_SIGNED_CUST( "min", 11, in_read_weight, in_write_weight ), + YAML_SIGNED_CUST( "max", 11, in_read_weight, in_write_weight ), YAML_SIGNED( "ppmCenter", 10 ), - YAML_SIGNED( "offset", 11 ), + YAML_SIGNED_CUST( "offset", 11, in_read_weight, in_write_weight ), YAML_UNSIGNED( "symetrical", 1 ), YAML_UNSIGNED( "revert", 1 ), YAML_PADDING( 3 ), @@ -523,7 +524,7 @@ static const struct YamlNode struct_ExpoData[] = { YAML_SIGNED_CUST( "weight", 8, in_read_weight, in_write_weight ), YAML_PADDING( 1 ), YAML_STRING("name", 6), - YAML_SIGNED( "offset", 8 ), + YAML_SIGNED_CUST( "offset", 8, in_read_weight, in_write_weight ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), YAML_END }; diff --git a/radio/src/storage/yaml/yaml_datastructs_x9lite.cpp b/radio/src/storage/yaml/yaml_datastructs_x9lite.cpp index 10faef18a..ad3a9be0e 100644 --- a/radio/src/storage/yaml/yaml_datastructs_x9lite.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_x9lite.cpp @@ -315,6 +315,7 @@ static const struct YamlNode struct_string_24[] = { }; static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "version", 8 ), + YAML_CUSTOM("board",nullptr,w_board), YAML_PADDING( 16 ), YAML_ARRAY("calib", 48, 5, struct_CalibData, NULL), YAML_PADDING( 16 ), @@ -351,7 +352,7 @@ static const struct YamlNode struct_RadioData[] = { YAML_SIGNED_CUST( "beepLength", 3, r_5pos, w_5pos ), YAML_SIGNED_CUST( "hapticStrength", 3, r_5pos, w_5pos ), YAML_UNSIGNED( "gpsFormat", 1 ), - YAML_UNSIGNED( "unexpectedShutdown", 1 ), + YAML_PADDING( 1 ), YAML_UNSIGNED_CUST( "speakerPitch", 8, r_spPitch, w_spPitch ), YAML_SIGNED_CUST( "speakerVolume", 8, r_vol, w_vol ), YAML_SIGNED_CUST( "vBatMin", 8, r_vbat_min, w_vbat_min ), @@ -415,7 +416,7 @@ static const struct YamlNode struct_TimerData[] = { }; static const struct YamlNode struct_CurveRef[] = { YAML_UNSIGNED( "type", 8 ), - YAML_SIGNED( "value", 8 ), + YAML_SIGNED_CUST( "value", 8, in_read_weight, in_write_weight ), YAML_END }; static const struct YamlNode struct_MixData[] = { @@ -426,7 +427,7 @@ static const struct YamlNode struct_MixData[] = { YAML_UNSIGNED( "mixWarn", 2 ), YAML_ENUM("mltpx", 2, enum_MixerMultiplex), YAML_PADDING( 1 ), - YAML_SIGNED( "offset", 14 ), + YAML_SIGNED_CUST( "offset", 14, in_read_weight, in_write_weight ), YAML_SIGNED_CUST( "swtch", 9, r_swtchSrc, w_swtchSrc ), YAML_UNSIGNED_CUST( "flightModes", 9, r_flightModes, w_flightModes ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), @@ -439,10 +440,10 @@ static const struct YamlNode struct_MixData[] = { }; static const struct YamlNode struct_LimitData[] = { YAML_IDX, - YAML_SIGNED( "min", 11 ), - YAML_SIGNED( "max", 11 ), + YAML_SIGNED_CUST( "min", 11, in_read_weight, in_write_weight ), + YAML_SIGNED_CUST( "max", 11, in_read_weight, in_write_weight ), YAML_SIGNED( "ppmCenter", 10 ), - YAML_SIGNED( "offset", 11 ), + YAML_SIGNED_CUST( "offset", 11, in_read_weight, in_write_weight ), YAML_UNSIGNED( "symetrical", 1 ), YAML_UNSIGNED( "revert", 1 ), YAML_PADDING( 3 ), @@ -461,7 +462,7 @@ static const struct YamlNode struct_ExpoData[] = { YAML_SIGNED_CUST( "weight", 8, in_read_weight, in_write_weight ), YAML_PADDING( 1 ), YAML_STRING("name", 6), - YAML_SIGNED( "offset", 8 ), + YAML_SIGNED_CUST( "offset", 8, in_read_weight, in_write_weight ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), YAML_END }; diff --git a/radio/src/storage/yaml/yaml_datastructs_x9lites.cpp b/radio/src/storage/yaml/yaml_datastructs_x9lites.cpp index d1b807e11..24fac20a7 100644 --- a/radio/src/storage/yaml/yaml_datastructs_x9lites.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_x9lites.cpp @@ -323,6 +323,7 @@ static const struct YamlNode struct_string_24[] = { }; static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "version", 8 ), + YAML_CUSTOM("board",nullptr,w_board), YAML_PADDING( 16 ), YAML_ARRAY("calib", 48, 5, struct_CalibData, NULL), YAML_PADDING( 16 ), @@ -359,7 +360,7 @@ static const struct YamlNode struct_RadioData[] = { YAML_SIGNED_CUST( "beepLength", 3, r_5pos, w_5pos ), YAML_SIGNED_CUST( "hapticStrength", 3, r_5pos, w_5pos ), YAML_UNSIGNED( "gpsFormat", 1 ), - YAML_UNSIGNED( "unexpectedShutdown", 1 ), + YAML_PADDING( 1 ), YAML_UNSIGNED_CUST( "speakerPitch", 8, r_spPitch, w_spPitch ), YAML_SIGNED_CUST( "speakerVolume", 8, r_vol, w_vol ), YAML_SIGNED_CUST( "vBatMin", 8, r_vbat_min, w_vbat_min ), @@ -425,7 +426,7 @@ static const struct YamlNode struct_TimerData[] = { }; static const struct YamlNode struct_CurveRef[] = { YAML_UNSIGNED( "type", 8 ), - YAML_SIGNED( "value", 8 ), + YAML_SIGNED_CUST( "value", 8, in_read_weight, in_write_weight ), YAML_END }; static const struct YamlNode struct_MixData[] = { @@ -436,7 +437,7 @@ static const struct YamlNode struct_MixData[] = { YAML_UNSIGNED( "mixWarn", 2 ), YAML_ENUM("mltpx", 2, enum_MixerMultiplex), YAML_PADDING( 1 ), - YAML_SIGNED( "offset", 14 ), + YAML_SIGNED_CUST( "offset", 14, in_read_weight, in_write_weight ), YAML_SIGNED_CUST( "swtch", 9, r_swtchSrc, w_swtchSrc ), YAML_UNSIGNED_CUST( "flightModes", 9, r_flightModes, w_flightModes ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), @@ -449,10 +450,10 @@ static const struct YamlNode struct_MixData[] = { }; static const struct YamlNode struct_LimitData[] = { YAML_IDX, - YAML_SIGNED( "min", 11 ), - YAML_SIGNED( "max", 11 ), + YAML_SIGNED_CUST( "min", 11, in_read_weight, in_write_weight ), + YAML_SIGNED_CUST( "max", 11, in_read_weight, in_write_weight ), YAML_SIGNED( "ppmCenter", 10 ), - YAML_SIGNED( "offset", 11 ), + YAML_SIGNED_CUST( "offset", 11, in_read_weight, in_write_weight ), YAML_UNSIGNED( "symetrical", 1 ), YAML_UNSIGNED( "revert", 1 ), YAML_PADDING( 3 ), @@ -471,7 +472,7 @@ static const struct YamlNode struct_ExpoData[] = { YAML_SIGNED_CUST( "weight", 8, in_read_weight, in_write_weight ), YAML_PADDING( 1 ), YAML_STRING("name", 6), - YAML_SIGNED( "offset", 8 ), + YAML_SIGNED_CUST( "offset", 8, in_read_weight, in_write_weight ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), YAML_END }; diff --git a/radio/src/storage/yaml/yaml_datastructs_xlite.cpp b/radio/src/storage/yaml/yaml_datastructs_xlite.cpp index f42fab1a3..3478f6852 100644 --- a/radio/src/storage/yaml/yaml_datastructs_xlite.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_xlite.cpp @@ -320,6 +320,7 @@ static const struct YamlNode struct_string_24[] = { }; static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "version", 8 ), + YAML_CUSTOM("board",nullptr,w_board), YAML_PADDING( 16 ), YAML_ARRAY("calib", 48, 6, struct_CalibData, NULL), YAML_PADDING( 16 ), @@ -356,7 +357,7 @@ static const struct YamlNode struct_RadioData[] = { YAML_SIGNED_CUST( "beepLength", 3, r_5pos, w_5pos ), YAML_SIGNED_CUST( "hapticStrength", 3, r_5pos, w_5pos ), YAML_UNSIGNED( "gpsFormat", 1 ), - YAML_UNSIGNED( "unexpectedShutdown", 1 ), + YAML_PADDING( 1 ), YAML_UNSIGNED_CUST( "speakerPitch", 8, r_spPitch, w_spPitch ), YAML_SIGNED_CUST( "speakerVolume", 8, r_vol, w_vol ), YAML_SIGNED_CUST( "vBatMin", 8, r_vbat_min, w_vbat_min ), @@ -422,7 +423,7 @@ static const struct YamlNode struct_TimerData[] = { }; static const struct YamlNode struct_CurveRef[] = { YAML_UNSIGNED( "type", 8 ), - YAML_SIGNED( "value", 8 ), + YAML_SIGNED_CUST( "value", 8, in_read_weight, in_write_weight ), YAML_END }; static const struct YamlNode struct_MixData[] = { @@ -433,7 +434,7 @@ static const struct YamlNode struct_MixData[] = { YAML_UNSIGNED( "mixWarn", 2 ), YAML_ENUM("mltpx", 2, enum_MixerMultiplex), YAML_PADDING( 1 ), - YAML_SIGNED( "offset", 14 ), + YAML_SIGNED_CUST( "offset", 14, in_read_weight, in_write_weight ), YAML_SIGNED_CUST( "swtch", 9, r_swtchSrc, w_swtchSrc ), YAML_UNSIGNED_CUST( "flightModes", 9, r_flightModes, w_flightModes ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), @@ -446,10 +447,10 @@ static const struct YamlNode struct_MixData[] = { }; static const struct YamlNode struct_LimitData[] = { YAML_IDX, - YAML_SIGNED( "min", 11 ), - YAML_SIGNED( "max", 11 ), + YAML_SIGNED_CUST( "min", 11, in_read_weight, in_write_weight ), + YAML_SIGNED_CUST( "max", 11, in_read_weight, in_write_weight ), YAML_SIGNED( "ppmCenter", 10 ), - YAML_SIGNED( "offset", 11 ), + YAML_SIGNED_CUST( "offset", 11, in_read_weight, in_write_weight ), YAML_UNSIGNED( "symetrical", 1 ), YAML_UNSIGNED( "revert", 1 ), YAML_PADDING( 3 ), @@ -468,7 +469,7 @@ static const struct YamlNode struct_ExpoData[] = { YAML_SIGNED_CUST( "weight", 8, in_read_weight, in_write_weight ), YAML_PADDING( 1 ), YAML_STRING("name", 6), - YAML_SIGNED( "offset", 8 ), + YAML_SIGNED_CUST( "offset", 8, in_read_weight, in_write_weight ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), YAML_END }; diff --git a/radio/src/storage/yaml/yaml_datastructs_xlites.cpp b/radio/src/storage/yaml/yaml_datastructs_xlites.cpp index f7dabf4da..a9a7479bb 100644 --- a/radio/src/storage/yaml/yaml_datastructs_xlites.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_xlites.cpp @@ -322,6 +322,7 @@ static const struct YamlNode struct_string_24[] = { }; static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "version", 8 ), + YAML_CUSTOM("board",nullptr,w_board), YAML_PADDING( 16 ), YAML_ARRAY("calib", 48, 6, struct_CalibData, NULL), YAML_PADDING( 16 ), @@ -358,7 +359,7 @@ static const struct YamlNode struct_RadioData[] = { YAML_SIGNED_CUST( "beepLength", 3, r_5pos, w_5pos ), YAML_SIGNED_CUST( "hapticStrength", 3, r_5pos, w_5pos ), YAML_UNSIGNED( "gpsFormat", 1 ), - YAML_UNSIGNED( "unexpectedShutdown", 1 ), + YAML_PADDING( 1 ), YAML_UNSIGNED_CUST( "speakerPitch", 8, r_spPitch, w_spPitch ), YAML_SIGNED_CUST( "speakerVolume", 8, r_vol, w_vol ), YAML_SIGNED_CUST( "vBatMin", 8, r_vbat_min, w_vbat_min ), @@ -426,7 +427,7 @@ static const struct YamlNode struct_TimerData[] = { }; static const struct YamlNode struct_CurveRef[] = { YAML_UNSIGNED( "type", 8 ), - YAML_SIGNED( "value", 8 ), + YAML_SIGNED_CUST( "value", 8, in_read_weight, in_write_weight ), YAML_END }; static const struct YamlNode struct_MixData[] = { @@ -437,7 +438,7 @@ static const struct YamlNode struct_MixData[] = { YAML_UNSIGNED( "mixWarn", 2 ), YAML_ENUM("mltpx", 2, enum_MixerMultiplex), YAML_PADDING( 1 ), - YAML_SIGNED( "offset", 14 ), + YAML_SIGNED_CUST( "offset", 14, in_read_weight, in_write_weight ), YAML_SIGNED_CUST( "swtch", 9, r_swtchSrc, w_swtchSrc ), YAML_UNSIGNED_CUST( "flightModes", 9, r_flightModes, w_flightModes ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), @@ -450,10 +451,10 @@ static const struct YamlNode struct_MixData[] = { }; static const struct YamlNode struct_LimitData[] = { YAML_IDX, - YAML_SIGNED( "min", 11 ), - YAML_SIGNED( "max", 11 ), + YAML_SIGNED_CUST( "min", 11, in_read_weight, in_write_weight ), + YAML_SIGNED_CUST( "max", 11, in_read_weight, in_write_weight ), YAML_SIGNED( "ppmCenter", 10 ), - YAML_SIGNED( "offset", 11 ), + YAML_SIGNED_CUST( "offset", 11, in_read_weight, in_write_weight ), YAML_UNSIGNED( "symetrical", 1 ), YAML_UNSIGNED( "revert", 1 ), YAML_PADDING( 3 ), @@ -472,7 +473,7 @@ static const struct YamlNode struct_ExpoData[] = { YAML_SIGNED_CUST( "weight", 8, in_read_weight, in_write_weight ), YAML_PADDING( 1 ), YAML_STRING("name", 6), - YAML_SIGNED( "offset", 8 ), + YAML_SIGNED_CUST( "offset", 8, in_read_weight, in_write_weight ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), YAML_END }; diff --git a/radio/src/storage/yaml/yaml_datastructs_zorro.cpp b/radio/src/storage/yaml/yaml_datastructs_zorro.cpp index b4d09d03a..476bb6093 100644 --- a/radio/src/storage/yaml/yaml_datastructs_zorro.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_zorro.cpp @@ -328,6 +328,7 @@ static const struct YamlNode struct_string_24[] = { }; static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "version", 8 ), + YAML_CUSTOM("board",nullptr,w_board), YAML_PADDING( 16 ), YAML_ARRAY("calib", 48, 6, struct_CalibData, NULL), YAML_PADDING( 16 ), @@ -364,7 +365,7 @@ static const struct YamlNode struct_RadioData[] = { YAML_SIGNED_CUST( "beepLength", 3, r_5pos, w_5pos ), YAML_SIGNED_CUST( "hapticStrength", 3, r_5pos, w_5pos ), YAML_UNSIGNED( "gpsFormat", 1 ), - YAML_UNSIGNED( "unexpectedShutdown", 1 ), + YAML_PADDING( 1 ), YAML_UNSIGNED_CUST( "speakerPitch", 8, r_spPitch, w_spPitch ), YAML_SIGNED_CUST( "speakerVolume", 8, r_vol, w_vol ), YAML_SIGNED_CUST( "vBatMin", 8, r_vbat_min, w_vbat_min ), @@ -430,7 +431,7 @@ static const struct YamlNode struct_TimerData[] = { }; static const struct YamlNode struct_CurveRef[] = { YAML_UNSIGNED( "type", 8 ), - YAML_SIGNED( "value", 8 ), + YAML_SIGNED_CUST( "value", 8, in_read_weight, in_write_weight ), YAML_END }; static const struct YamlNode struct_MixData[] = { @@ -441,7 +442,7 @@ static const struct YamlNode struct_MixData[] = { YAML_UNSIGNED( "mixWarn", 2 ), YAML_ENUM("mltpx", 2, enum_MixerMultiplex), YAML_PADDING( 1 ), - YAML_SIGNED( "offset", 14 ), + YAML_SIGNED_CUST( "offset", 14, in_read_weight, in_write_weight ), YAML_SIGNED_CUST( "swtch", 9, r_swtchSrc, w_swtchSrc ), YAML_UNSIGNED_CUST( "flightModes", 9, r_flightModes, w_flightModes ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), @@ -454,10 +455,10 @@ static const struct YamlNode struct_MixData[] = { }; static const struct YamlNode struct_LimitData[] = { YAML_IDX, - YAML_SIGNED( "min", 11 ), - YAML_SIGNED( "max", 11 ), + YAML_SIGNED_CUST( "min", 11, in_read_weight, in_write_weight ), + YAML_SIGNED_CUST( "max", 11, in_read_weight, in_write_weight ), YAML_SIGNED( "ppmCenter", 10 ), - YAML_SIGNED( "offset", 11 ), + YAML_SIGNED_CUST( "offset", 11, in_read_weight, in_write_weight ), YAML_UNSIGNED( "symetrical", 1 ), YAML_UNSIGNED( "revert", 1 ), YAML_PADDING( 3 ), @@ -476,7 +477,7 @@ static const struct YamlNode struct_ExpoData[] = { YAML_SIGNED_CUST( "weight", 8, in_read_weight, in_write_weight ), YAML_PADDING( 1 ), YAML_STRING("name", 6), - YAML_SIGNED( "offset", 8 ), + YAML_SIGNED_CUST( "offset", 8, in_read_weight, in_write_weight ), YAML_STRUCT("curve", 16, struct_CurveRef, NULL), YAML_END }; diff --git a/radio/src/storage/yaml/yaml_parser.cpp b/radio/src/storage/yaml/yaml_parser.cpp index 743760ce8..682151353 100644 --- a/radio/src/storage/yaml/yaml_parser.cpp +++ b/radio/src/storage/yaml/yaml_parser.cpp @@ -40,6 +40,7 @@ void YamlParser::init(const YamlParserCalls* parser_calls, void* parser_ctx) calls = parser_calls; ctx = parser_ctx; reset(); + eof = false; } void YamlParser::reset() @@ -311,6 +312,11 @@ YamlParser::parse(const char* buffer, unsigned int size) c++; } // for each char + if ((state == ps_Val) && eof && node_found) { + // TODO: trim spaces at the end? + calls->set_attr(ctx, scratch_buf, scratch_len); + } + return CONTINUE_PARSING; } diff --git a/radio/src/storage/yaml/yaml_parser.h b/radio/src/storage/yaml/yaml_parser.h index bc62dbe7d..15b4b4907 100644 --- a/radio/src/storage/yaml/yaml_parser.h +++ b/radio/src/storage/yaml/yaml_parser.h @@ -73,6 +73,7 @@ class YamlParser uint8_t scratch_len; bool node_found; + bool eof; // tree iterator state const YamlParserCalls* calls; @@ -98,6 +99,8 @@ public: void init(const YamlParserCalls* parser_calls, void* parser_ctx); YamlResult parse(const char* buffer, unsigned int size); + + void set_eof() { eof = true; } }; #endif diff --git a/radio/src/storage/yaml/yaml_tree_walker.cpp b/radio/src/storage/yaml/yaml_tree_walker.cpp index b2e900327..7f2c806da 100644 --- a/radio/src/storage/yaml/yaml_tree_walker.cpp +++ b/radio/src/storage/yaml/yaml_tree_walker.cpp @@ -301,7 +301,7 @@ bool YamlTreeWalker::toParent() bool YamlTreeWalker::toChild() { const struct YamlNode* attr = getAttr(); - if (!attr + if (!attr || isIdxInvalid() || (attr->type != YDT_ARRAY && attr->type != YDT_UNION && !isArrayElmt())) { diff --git a/radio/src/targets/simu/CMakeLists.txt b/radio/src/targets/simu/CMakeLists.txt index 60f9a69b2..8f45df562 100644 --- a/radio/src/targets/simu/CMakeLists.txt +++ b/radio/src/targets/simu/CMakeLists.txt @@ -34,7 +34,7 @@ if(SIMU_LUA_COMPILER) endif() if(Qt5Widgets_FOUND) - set(SIMULATOR_FLAVOUR opentx-${FLAVOUR}) + set(SIMULATOR_FLAVOUR edgetx-${FLAVOUR}) set(SIMULATOR_TARGET ${SIMULATOR_FLAVOUR}-simulator) add_definitions(-DSIMULATOR_FLAVOUR="${SIMULATOR_FLAVOUR}") include_directories(${COMPANION_SRC_DIRECTORY} ${COMPANION_SRC_DIRECTORY}/simulation) @@ -52,7 +52,7 @@ if(Qt5Widgets_FOUND) COMMAND ${CMAKE_STRIP} $) endif() endif() - + # Introduced at 2.5 - TODO replace with a code change # When compiled shared simulators using libopenui and Companion have classes named MainWindow diff --git a/radio/src/targets/simu/opentxsimulator.cpp b/radio/src/targets/simu/opentxsimulator.cpp index a07be6d5c..51408d2eb 100644 --- a/radio/src/targets/simu/opentxsimulator.cpp +++ b/radio/src/targets/simu/opentxsimulator.cpp @@ -32,7 +32,7 @@ #define GET_SWITCH_BOOL(sw__) getSwitch((sw__), 0); -#define OTXS_DBG qDebug() << "(" << simuTimerMicros() << "us)" +#define ETXS_DBG qDebug() << "(" << simuTimerMicros() << "us)" int16_t g_anas[Analogs::NUM_ANALOGS]; QVector OpenTxSimulator::tracebackDevices; @@ -106,7 +106,7 @@ void OpenTxSimulator::init() if (isRunning()) return; - OTXS_DBG; + ETXS_DBG; if (!m_timer10ms) { // make sure we create & control the timer from current thread @@ -134,7 +134,7 @@ void OpenTxSimulator::start(const char * filename, bool tests) { if (isRunning()) return; - OTXS_DBG << "file:" << filename << "tests:" << tests; + ETXS_DBG << "file:" << filename << "tests:" << tests; QMutexLocker lckr(&m_mtxSimuMain); QMutexLocker slckr(&m_mtxSettings); @@ -150,7 +150,7 @@ void OpenTxSimulator::stop() { if (!isRunning()) return; - OTXS_DBG; + ETXS_DBG; setStopRequested(true); @@ -380,7 +380,7 @@ void OpenTxSimulator::setTrainerTimeout(uint16_t ms) void OpenTxSimulator::sendTelemetry(const QByteArray data) { - //OTXS_DBG << data; + //ETXS_DBG << data; sportProcessTelemetryPacket((uint8_t *)data.constData()); } diff --git a/radio/src/targets/simu/simufatfs.cpp b/radio/src/targets/simu/simufatfs.cpp index 92d2ac27e..5598217b0 100644 --- a/radio/src/targets/simu/simufatfs.cpp +++ b/radio/src/targets/simu/simufatfs.cpp @@ -124,23 +124,20 @@ bool redirectToSettingsDirectory(const std::string & path) * model (*.bin) files in /MODELS directory */ if (!simuSettingsDirectory.empty()) { -#if defined(COLORLCD) - if (path == RADIO_MODELSLIST_PATH || path == RADIO_SETTINGS_PATH -#if defined(SDCARD_YAML) - || path == MODELSLIST_YAML_PATH || path == RADIO_SETTINGS_YAML_PATH -#endif - ) { +#if defined(SDCARD_RAW) || defined(SDCARD_YAML) + if (path == MODELS_PATH || path == RADIO_PATH) return true; + #if !defined(EEPROM_RLC) + if (path == RADIO_MODELSLIST_PATH || path == RADIO_SETTINGS_PATH) return true; - } -#endif - if (startsWith(path, "/MODELS") - && (endsWith(path, MODELS_EXT) -#if defined(SDCARD_YAML) - || endsWith(path, YAML_EXT) -#endif - )) { + if (startsWith(path, MODELS_PATH) && endsWith(path, MODELS_EXT)) return true; - } + #endif +#endif +#if defined(SDCARD_YAML) + if (path == MODELSLIST_YAML_PATH || path == RADIO_SETTINGS_YAML_PATH) + return true; + if (startsWith(path, MODELS_PATH) && endsWith(path, YAML_EXT)) return true; +#endif } return false; }