diff --git a/companion/src/CMakeLists.txt b/companion/src/CMakeLists.txt index 6d9e04d63e8..bdfe7d900d6 100644 --- a/companion/src/CMakeLists.txt +++ b/companion/src/CMakeLists.txt @@ -139,6 +139,22 @@ else() message(STATUS "Qt lupdate not found, 'translations' target will not be availabe.") endif() +############# Import radio hardware definitions ############### + +set(HWDEFS_DIR "${CMAKE_CURRENT_BINARY_DIR}/../../radio/src") +set(HWDEFS_TMPL "${COMPANION_SRC_DIRECTORY}/hwdefs.qrc.in") +set(HWDEFS_PHDR "HWDEF_JSON_LIST") +set(HWDEFS_QRC "${CMAKE_CURRENT_BINARY_DIR}/hwdefs.qrc") +set(HWDEFS_CMD "${COMPANION_SRC_DIRECTORY}/../util/generate_hwdefs_qrc.py") + +add_custom_command(OUTPUT ${HWDEFS_QRC} + COMMAND ${HWDEFS_CMD} -d ${HWDEFS_DIR} + -t ${HWDEFS_TMPL} + -p ${HWDEFS_PHDR} + -o ${HWDEFS_QRC} + DEPENDS ${HWDEFS_TMPL} + ) + ############# Common lib ############### set(common_SRCS @@ -157,6 +173,7 @@ set(common_MOC_HDRS set(common_RESOURCES companion.qrc ${TRANSLATIONS_QRC} + ${HWDEFS_QRC} ) qt5_wrap_cpp(common_SRCS ${common_MOC_HDRS}) diff --git a/companion/src/companion.cpp b/companion/src/companion.cpp index 1f367ae1e45..004c7ba0a18 100644 --- a/companion/src/companion.cpp +++ b/companion/src/companion.cpp @@ -39,6 +39,7 @@ #include "storage.h" #include "translations.h" #include "helpers.h" +#include "boardfactories.h" #ifdef __APPLE__ #include @@ -231,6 +232,8 @@ int main(int argc, char *argv[]) } #endif + Q_INIT_RESOURCE(hwdefs); + gBoardFactories = new BoardFactories(); registerStorageFactories(); registerOpenTxFirmwares(); SimulatorLoader::registerSimulators(); @@ -264,6 +267,7 @@ int main(int argc, char *argv[]) SimulatorLoader::unregisterSimulators(); unregisterOpenTxFirmwares(); unregisterStorageFactories(); + gBoardFactories->unregisterBoardFactories(); #if defined(JOYSTICKS) || defined(SIMU_AUDIO) SDL_Quit(); diff --git a/companion/src/constants.h b/companion/src/constants.h index 85c4da333eb..d62af94043a 100644 --- a/companion/src/constants.h +++ b/companion/src/constants.h @@ -37,18 +37,24 @@ #define CPN_MAX_MODULES 2 #define CPN_MAX_STICKS Board::STICK_AXIS_COUNT #define CPN_MAX_TRIMS Board::TRIM_AXIS_COUNT -#define CPN_MAX_POTS 8 -#define CPN_MAX_SLIDERS 4 #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_SLIDERS + CPN_MAX_MOUSE_ANALOGS + CPN_MAX_GYRO_ANALOGS) +#define CPN_MAX_SWITCHES_FLEX 4 // v2.10 cmake parameter FLEXSW +#define CPN_MAX_SWITCHES_FUNCTION 6 +#define CPN_MAX_SWITCHES_STD 20 +#define CPN_MAX_SWITCHES (CPN_MAX_SWITCHES_STD + CPN_MAX_SWITCHES_FLEX + CPN_MAX_SWITCHES_FUNCTION) #define CPN_MAX_SENSORS 60 #define CPN_MAX_SCRIPTS 9 #define CPN_MAX_SCRIPT_INPUTS 10 #define CPN_MAX_SPACEMOUSE 6 +#define CPN_MAX_INPUTS 32 // v2.10 replaces CPN_MAX_ANALOGS - the value is abitary as radio ADC refactor is still a WIP + +// pre v2.10 +#define CPN_MAX_POTS 8 +#define CPN_MAX_SLIDERS 4 +#define CPN_MAX_MOUSE_ANALOGS 2 +#define CPN_MAX_GYRO_ANALOGS 2 +#define CPN_MAX_ANALOGS (CPN_MAX_STICKS + CPN_MAX_POTS + CPN_MAX_SLIDERS + CPN_MAX_MOUSE_ANALOGS + CPN_MAX_GYRO_ANALOGS) +// ========= #define CPN_STR_APP_NAME QCoreApplication::translate("Companion", "EdgeTX Companion") #define CPN_STR_SIMU_NAME QCoreApplication::translate("Companion", "EdgeTX Simulator") diff --git a/companion/src/datamodels/compounditemmodels.cpp b/companion/src/datamodels/compounditemmodels.cpp index 8d462166e9a..c908620c402 100644 --- a/companion/src/datamodels/compounditemmodels.cpp +++ b/companion/src/datamodels/compounditemmodels.cpp @@ -50,6 +50,8 @@ QString AbstractItemModel::idToString(const int value) return "CurveRefType"; case IMID_CurveRefFunc: return "CurveRefFunc"; + case IMID_FlexSwitches: + return "FlexSwitches"; default: return "Custom"; } @@ -108,13 +110,12 @@ RawSourceItemModel::RawSourceItemModel(const GeneralSettings * const generalSett for (int i = 0; i < firmware->getCapability(LuaScripts); i++) addItems(SOURCE_TYPE_LUA_OUTPUT, RawSource::ScriptsGroup, firmware->getCapability(LuaOutputsPerScript), i * 16); addItems(SOURCE_TYPE_VIRTUAL_INPUT, RawSource::InputsGroup, firmware->getCapability(VirtualInputs)); - addItems(SOURCE_TYPE_STICK, RawSource::SourcesGroup, board->getCapability(Board::MaxAnalogs)); + addItems(SOURCE_TYPE_STICK, RawSource::SourcesGroup, board->getCapability(Board::Inputs)); addItems(SOURCE_TYPE_TRIM, RawSource::TrimsGroup, board->getCapability(Board::NumTrims)); addItems(SOURCE_TYPE_SPACEMOUSE, RawSource::SourcesGroup, CPN_MAX_SPACEMOUSE); addItems(SOURCE_TYPE_MIN, RawSource::SourcesGroup, 1); addItems(SOURCE_TYPE_MAX, RawSource::SourcesGroup, 1); addItems(SOURCE_TYPE_SWITCH, RawSource::SwitchesGroup, board->getCapability(Board::Switches)); - addItems(SOURCE_TYPE_FUNCTIONSWITCH, RawSource::SwitchesGroup, board->getCapability(Board::FunctionSwitches)); addItems(SOURCE_TYPE_CUSTOM_SWITCH, RawSource::SwitchesGroup, firmware->getCapability(LogicalSwitches)); addItems(SOURCE_TYPE_CYC, RawSource::SourcesGroup, CPN_MAX_CYC); addItems(SOURCE_TYPE_PPM, RawSource::SourcesGroup, firmware->getCapability(TrainerInputs)); @@ -175,13 +176,11 @@ RawSwitchItemModel::RawSwitchItemModel(const GeneralSettings * const generalSett addItems(SWITCH_TYPE_VIRTUAL, -firmware->getCapability(LogicalSwitches)); addItems(SWITCH_TYPE_TRIM, -board->getCapability(Board::NumTrimSwitches)); addItems(SWITCH_TYPE_MULTIPOS_POT, -(board->getCapability(Board::MultiposPots) * board->getCapability(Board::MultiposPotsPositions))); - addItems(SWITCH_TYPE_FUNCTIONSWITCH, -board->getCapability(Board::NumFunctionSwitchesPositions)); - addItems(SWITCH_TYPE_SWITCH, -board->getCapability(Board::SwitchPositions)); + addItems(SWITCH_TYPE_SWITCH, -board->getCapability(Board::SwitchesPositions)); // Ascending switch direction (including zero) addItems(SWITCH_TYPE_NONE, 1); - addItems(SWITCH_TYPE_SWITCH, board->getCapability(Board::SwitchPositions)); - addItems(SWITCH_TYPE_FUNCTIONSWITCH, board->getCapability(Board::NumFunctionSwitchesPositions)); + addItems(SWITCH_TYPE_SWITCH, board->getCapability(Board::SwitchesPositions)); addItems(SWITCH_TYPE_MULTIPOS_POT, board->getCapability(Board::MultiposPots) * board->getCapability(Board::MultiposPotsPositions)); addItems(SWITCH_TYPE_TRIM, board->getCapability(Board::NumTrimSwitches)); addItems(SWITCH_TYPE_VIRTUAL, firmware->getCapability(LogicalSwitches)); @@ -571,6 +570,57 @@ PrecisionItemModel::PrecisionItemModel(const int minDecimals, const int maxDecim } } +// +// FlexSwitchesItemModel +// + +FlexSwitchesItemModel::FlexSwitchesItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, + Firmware * firmware, const Boards * const board, const Board::Type boardType) : + AbstractDynamicItemModel(generalSettings, modelData, firmware, board, boardType) +{ + setId(IMID_FlexSwitches); + + if (!generalSettings) + return; + + setUpdateMask(IMUE_FunctionSwitches); + const int count = Boards::getCapability(boardType, Board::Inputs); + + { + QStandardItem * modelItem = new QStandardItem(); + modelItem->setData(-1, IMDR_Id); + modelItem->setText(tr("None")); + modelItem->setData(true, IMDR_Available); + appendRow(modelItem); + } + + for (int i = 0; i < count; ++i) { + QStandardItem * modelItem = new QStandardItem(); + modelItem->setData(i, IMDR_Id); + setDynamicItemData(modelItem, i); + appendRow(modelItem); + } +} + +void FlexSwitchesItemModel::setDynamicItemData(QStandardItem * item, const int value) const +{ + item->setText(Boards::getInputName(value, boardType)); + item->setData(generalSettings->isInputFlexSwitchAvailable(value), IMDR_Available); +} + +void FlexSwitchesItemModel::update(const int event) +{ + if (doUpdate(event)) { + emit aboutToBeUpdated(); + + for (int i = 1; i < rowCount(); ++i) { // skip None + setDynamicItemData(item(i), item(i)->data(IMDR_Id).toInt()); + } + + emit updateComplete(); + } +} + // // CompoundItemModelFactory // @@ -623,6 +673,9 @@ void CompoundItemModelFactory::addItemModel(const int id) case AbstractItemModel::IMID_CurveRefFunc: registerItemModel(new CurveRefFuncItemModel(generalSettings, modelData, firmware, board, boardType)); break; + case AbstractItemModel::IMID_FlexSwitches: + registerItemModel(new FlexSwitchesItemModel(generalSettings, modelData, firmware, board, boardType)); + break; default: qDebug() << "Error: unknown item model: id"; break; diff --git a/companion/src/datamodels/compounditemmodels.h b/companion/src/datamodels/compounditemmodels.h index ede23bb3420..65adfed2dec 100644 --- a/companion/src/datamodels/compounditemmodels.h +++ b/companion/src/datamodels/compounditemmodels.h @@ -45,6 +45,7 @@ class AbstractItemModel: public QStandardItemModel IMID_TeleSource, IMID_CurveRefType, IMID_CurveRefFunc, + IMID_FlexSwitches, IMID_ReservedCount, IMID_Custom }; @@ -332,6 +333,22 @@ class PrecisionItemModel : public AbstractStaticItemModel virtual ~PrecisionItemModel() {}; }; +class FlexSwitchesItemModel: public AbstractDynamicItemModel +{ + Q_OBJECT + public: + explicit FlexSwitchesItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, + Firmware * firmware, const Boards * const board, const Board::Type boardType); + virtual ~FlexSwitchesItemModel() {}; + + public slots: + virtual void update(const int event = IMUE_SystemRefresh) override; + + protected: + virtual void setDynamicItemData(QStandardItem * item, const int value) const; +}; + + // // CompoundItemModelFactory // diff --git a/companion/src/firmwares/CMakeLists.txt b/companion/src/firmwares/CMakeLists.txt index 2f25f38aaf9..43658773056 100644 --- a/companion/src/firmwares/CMakeLists.txt +++ b/companion/src/firmwares/CMakeLists.txt @@ -3,6 +3,8 @@ project(firmwares) set(${PROJECT_NAME}_NAMES adjustmentreference + boardfactories + boardjson boards curvedata curvereference diff --git a/companion/src/firmwares/boardfactories.cpp b/companion/src/firmwares/boardfactories.cpp new file mode 100644 index 00000000000..4fb0d0136dd --- /dev/null +++ b/companion/src/firmwares/boardfactories.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * 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 "boardfactories.h" + +BoardFactories* gBoardFactories = nullptr; + +BoardFactories::BoardFactories() : + m_default(nullptr) +{ + if (registerBoard(Board::BOARD_UNKNOWN, "")) + m_default = instance(Board::BOARD_UNKNOWN); +} + +BoardFactories::~BoardFactories() +{ + unregisterBoardFactories(); +} + +BoardJson* BoardFactories::instance(Board::Type board) const +{ + for (auto *registeredFactory : registeredBoardFactories) { + if (registeredFactory->instance()->board() == board) + return registeredFactory->instance(); + } + + return m_default; +} + +// Registering firmware triggers registering the associated board +bool BoardFactories::registerBoard(Board::Type board, QString hwdefn) +{ + if (board < Board::BOARD_UNKNOWN || board >= Board::BOARD_TYPE_COUNT) + return false; + + if (m_default || board != Board::BOARD_UNKNOWN) { + BoardJson* regboard = instance(board); + + if (regboard->board() == board) { + if (regboard->hwdefn() == hwdefn) { + //qDebug() << "Warning - Board" << Boards::getBoardName(regboard->board()) << "already registered"; + return true; + } + else { + qDebug() << "Error - Board" << Boards::getBoardName(regboard->board()) << "already registered with" + << regboard->hwdefn() << "hwdefn!"; + return false; + } + } + } + + BoardFactory *bf = new BoardFactory(board, hwdefn); + if (bf->instance()->loadDefinition()) { + if (registerBoardFactory(bf)) { + qDebug() << "Registered board:" << (board != Board::BOARD_UNKNOWN ? Boards::getBoardName(board) : "UNKNOWN (default)"); + return true; + } + else + delete bf; + } + else + delete bf; + + return false; +} + +bool BoardFactories::registerBoardFactory(BoardFactory * factory) +{ + registeredBoardFactories.append(factory); + return true; +} + +void BoardFactories::unregisterBoardFactories() +{ + for (auto *registeredFactory : registeredBoardFactories) + delete registeredFactory; +} diff --git a/companion/src/firmwares/boardfactories.h b/companion/src/firmwares/boardfactories.h new file mode 100644 index 00000000000..5036514cba5 --- /dev/null +++ b/companion/src/firmwares/boardfactories.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * 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 "boardjson.h" + +class BoardFactory +{ + public: + explicit BoardFactory(Board::Type board, QString hwdefn) : + m_instance(new BoardJson(board, hwdefn)) + {} + + virtual ~BoardFactory() {} + + BoardJson* instance() const { return m_instance; } + + private: + BoardJson *m_instance; +}; + +class BoardFactories +{ + public: + explicit BoardFactories(); + virtual ~BoardFactories(); + + BoardJson* instance(Board::Type board) const; + + bool registerBoard(Board::Type board, QString hwdefn); + bool registerBoardFactory(BoardFactory * factory); + void unregisterBoardFactories(); + + private: + QList registeredBoardFactories; + + BoardJson *m_default; +}; + +extern BoardFactories* gBoardFactories; diff --git a/companion/src/firmwares/boardjson.cpp b/companion/src/firmwares/boardjson.cpp new file mode 100644 index 00000000000..3cd71160e62 --- /dev/null +++ b/companion/src/firmwares/boardjson.cpp @@ -0,0 +1,991 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * 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 "boardjson.h" +#include "datahelpers.h" +#include "constants.h" + +#include + +static const StringTagMappingTable inputTypesLookupTable = { + {std::to_string(Board::AIT_NONE), "NONE"}, + {std::to_string(Board::AIT_STICK), "STICK"}, + {std::to_string(Board::AIT_FLEX), "FLEX"}, + {std::to_string(Board::AIT_VBAT), "VBAT"}, + {std::to_string(Board::AIT_RTC_BAT), "RTC_BAT"}, + {std::to_string(Board::AIT_SWITCH), "SWITCH"}, +}; + +static const StringTagMappingTable flexTypesLookupTable = { + {std::to_string(Board::FLEX_NONE), "NONE"}, + {std::to_string(Board::FLEX_POT), "POT"}, + {std::to_string(Board::FLEX_POT_CENTER), "POT_CENTER"}, + {std::to_string(Board::FLEX_SLIDER), "SLIDER"}, + {std::to_string(Board::FLEX_MULTIPOS), "MULTIPOS"}, + {std::to_string(Board::FLEX_AXIS_X), "AXIS_X"}, + {std::to_string(Board::FLEX_AXIS_Y), "AXIS_Y"}, + {std::to_string(Board::FLEX_SWITCH), "SWITCH"}, +}; + +static const StringTagMappingTable switchTypesLookupTable = { + {std::to_string(Board::SWITCH_NOT_AVAILABLE), "NONE"}, + {std::to_string(Board::SWITCH_TOGGLE), "TOGGLE"}, + {std::to_string(Board::SWITCH_2POS), "2POS"}, + {std::to_string(Board::SWITCH_3POS), "3POS"}, + {std::to_string(Board::SWITCH_FUNC), "FSWITCH"}, +}; + +static const StringTagMappingTable stickNamesLookupTable = { + {QCoreApplication::translate("BoardJson", "Rud").toStdString(), "LH"}, // air + {QCoreApplication::translate("BoardJson", "Ele").toStdString(), "LV"}, // air + {QCoreApplication::translate("BoardJson", "Thr").toStdString(), "RV"}, // air + {QCoreApplication::translate("BoardJson", "Ail").toStdString(), "RH"}, // air + {QCoreApplication::translate("BoardJson", "ST").toStdString(), "ST"}, // surface + {QCoreApplication::translate("BoardJson", "TH").toStdString(), "TH"}, // surface +}; + +BoardJson::BoardJson(Board::Type board, QString hwdefn) : + m_board(board), + m_hwdefn(hwdefn), + m_inputs(new InputsTable), + m_switches(new SwitchesTable), + m_trims(new TrimsTable), + m_inputCnt({0, 0, 0, 0, 0, 0, 0, 0, 0}), + m_switchCnt({0, 0, 0}) +{ + +} + +BoardJson::~BoardJson() +{ + delete m_inputs; + delete m_switches; + delete m_trims; +} + +// static +void BoardJson::afterLoadFixups(Board::Type board, InputsTable * inputs, SwitchesTable * switches) +{ + // TODO json files do not contain gyro defs + // Radio cmake directive IMU is currently used + if (IS_TARANIS_XLITES(board) || IS_FAMILY_HORUS_OR_T16(board)) { + if (getInputIndex(inputs, "TILT_X", Board::LVT_TAG) < 0) { + InputDefn defn; + defn.type = AIT_FLEX; + defn.tag = "TILT_X"; + defn.name = "Tltx"; + defn.shortName = "X"; + defn.flexType = FLEX_AXIS_X; + defn.inverted = false; + defn.cfgYaml = Board::LVT_TAG; + defn.refYaml = Board::LVT_TAG; // non-default + inputs->insert(inputs->end(), defn); + } + + if (getInputIndex(inputs, "TILT_Y", Board::LVT_TAG) < 0) { + InputDefn defn; + defn.type = AIT_FLEX; + defn.tag = "TILT_Y"; + defn.name = "Tlty"; + defn.shortName = "Y"; + defn.flexType = FLEX_AXIS_Y; + defn.inverted = false; + defn.cfgYaml = Board::LVT_TAG; + defn.refYaml = Board::LVT_TAG; // non-default + inputs->insert(inputs->end(), defn); + } + } + + // Flex switches are not listed in json file + int count = IS_RADIOMASTER_TX16S(board) ? 2 : 0; + + for (int i = 1; i <= count; i++) { + QString tag = QString("FL%1").arg(i); + if (getSwitchIndex(switches, tag, Board::LVT_TAG) < 0) { + SwitchDefn defn; + defn.tag = tag.toStdString(); + defn.name = defn.tag; + switches->insert(switches->end(), defn); + } + } +} + +// called from Boards::getCapability if no capability match +// WARNING - potential for infinite loop if Boards::getCapability(m_board, capability) called from here!!!!! +const int BoardJson::getCapability(const Board::Capability capability) const +{ + switch (capability) { + case Board::FlexInputs: + return (m_inputCnt.flexGyroAxes + + m_inputCnt.flexJoystickAxes + + m_inputCnt.flexPots + + m_inputCnt.flexSliders + + m_inputCnt.flexSwitches); + + case Board::FlexSwitches: + return m_switchCnt.flex; + + case Board::FunctionSwitches: + return m_switchCnt.func; + + case Board::GyroAxes: + return m_inputCnt.flexGyroAxes; + + case Board::Gyros: + return getCapability(Board::GyroAxes) / 2; + + case Board::HasRTC: + return m_inputCnt.rtcbat; + + case Board::HasVBat: + return m_inputCnt.vbat; + + case Board::Inputs: + return m_inputs->size(); + + case Board::InputSwitches: + return m_inputCnt.switches; + + case Board::MultiposPots: + // assumes every input has potential to be one + // index used for mapping 6 pos switches back to input + return getCapability(Board::Inputs); + + case Board::MultiposPotsPositions: + return 6; + + case Board::NumFunctionSwitchesPositions: + return getCapability(Board::FunctionSwitches) * 3; + + case Board::NumTrims: + return m_trims->size(); + + case Board::NumTrimSwitches: + return getCapability(Board::NumTrims) * 2; + + case Board::Pots: + return m_inputCnt.flexPots; + + case Board::Sliders: + return m_inputCnt.flexSliders; + + case Board::StandardSwitches: + return m_switchCnt.std; + + case Board::Sticks: + return m_inputCnt.sticks; + + case Board::Switches: + return (m_switchCnt.std + + m_switchCnt.flex + + m_switchCnt.func); + + case Board::SwitchesPositions: + return getCapability(Board::Switches) * 3; + + default: + return 0; + } +} + +const int BoardJson::getInputIndex(const QString val, Board::LookupValueType lvt) const +{ + return getInputIndex(m_inputs, val, lvt); +} + +// static +int BoardJson::getInputIndex(const InputsTable * inputs, QString val, Board::LookupValueType lvt) +{ + for (int i = 0; i < (int)inputs->size(); i++) { + if ((lvt == Board::LVT_TAG && inputs->at(i).tag.c_str() == val) || + (lvt == Board::LVT_NAME && inputs->at(i).name.c_str() == val)) + return i; + } + + return -1; +} + +const QString BoardJson::getInputName(int index) const +{ + return getInputName(m_inputs, index); +} + +// static +QString BoardJson::getInputName(const InputsTable * inputs, int index) +{ + if (index > -1 && index < (int)inputs->size()) + return inputs->at(index).name.c_str(); + + return CPN_STR_UNKNOWN_ITEM; +} + +const QString BoardJson::getInputTag(int index) const +{ + return getInputTag(m_inputs, index); +} + +// static +QString BoardJson::getInputTag(const InputsTable * inputs, int index) +{ + if (index > -1 && index < (int)inputs->size()) + return inputs->at(index).tag.c_str(); + + return CPN_STR_UNKNOWN_ITEM; +} + +const int BoardJson::getInputYamlIndex(const QString val, YamlLookupType ylt) const +{ + for (int i = 0; i < (int)m_inputs->size(); i++) { + Board::LookupValueType type = (ylt == YLT_CONFIG ? m_inputs->at(i).cfgYaml : m_inputs->at(i).refYaml); + QString tmp = (type == Board::LVT_NAME ? getInputName(m_inputs, i) : getInputTag(m_inputs, i)); + if (val == tmp) + return getInputIndex(m_inputs, val, type); + } + + return -1; +} + +const QString BoardJson::getInputYamlName(int index, YamlLookupType ylt) const +{ + if (index > -1 && index < (int)m_inputs->size()) { + if (ylt == YLT_CONFIG) + return m_inputs->at(index).cfgYaml == Board::LVT_NAME ? getInputName(m_inputs, index) : getInputTag(m_inputs, index); + else + return m_inputs->at(index).refYaml == Board::LVT_NAME ? getInputName(m_inputs, index) : getInputTag(m_inputs, index); + } + + return CPN_STR_UNKNOWN_ITEM; +} + +const int BoardJson::getInputsCalibrated() const +{ + return getInputsCalibrated(m_inputs); +} + +// static +int BoardJson::getInputsCalibrated(const InputsTable * inputs) +{ + unsigned int cnt = 0; + + for (const auto &defn : *inputs) { + if (isInputCalibrated(defn)) cnt++; + } + + return cnt; +} + +const int BoardJson::getInputTagOffset(QString tag) +{ + return getInputTagOffset(m_inputs, tag); +} + +// static +int BoardJson::getInputTagOffset(const InputsTable * inputs, QString tag) +{ + for (int i = 0; i < (int)inputs->size(); i++) { + if (tag == inputs->at(i).tag.c_str()) + return i; + } + + return 0; +} + +const int BoardJson::getInputPotIndex(int index) +{ + if (getCapability(Board::Pots) > 0) + return getInputTagOffset(m_inputs, QString("P%1").arg(index)); + + return -1; +} + +const int BoardJson::getInputSliderIndex(int index) +{ + if (getCapability(Board::Sliders) > 0) + return getInputTagOffset(m_inputs, QString("SL%1").arg(index)); + + return -1; +} + +const int BoardJson::getInputTypeOffset(Board::AnalogInputType type) +{ + return getInputTypeOffset(m_inputs, type); +} + +// static +int BoardJson::getInputTypeOffset(const InputsTable * inputs, Board::AnalogInputType type) +{ + for (int i = 0; i < (int)inputs->size(); i++) { + if (type == inputs->at(i).type) + return i; + } + + return 0; +} + +const Board::InputInfo BoardJson::getInputInfo(int index) const +{ + return getInputInfo(m_inputs, index); +} + +// static +Board::InputInfo BoardJson::getInputInfo(const InputsTable * inputs, int index) +{ + Board::InputInfo info; + + if (index >= 0 && index < (int)inputs->size()) { + InputDefn defn = inputs->at(index); + info.type = defn.type; + info.tag = defn.tag; + info.name = defn.name; + info.shortName = defn.shortName; + info.flexType = defn.flexType; + info.inverted = defn.inverted; + } + + return info; +} + +// static +int BoardJson::getNumericSuffix(const std::string str) +{ + std::string suffix = std::string(); + + for (int i = 0; i < (int)str.size(); i++) { + if (str.substr(i, 1) >= "0" && str.substr(i, 1) <= "9") + suffix.append(str.substr(i, 1)); + } + + if (!suffix.empty()) + return std::stoi(suffix); + + return -1; +} + +const int BoardJson::getSwitchIndex(const QString val, Board::LookupValueType lvt) const +{ + return getSwitchIndex(m_switches, val, lvt); +} + +// static +int BoardJson::getSwitchIndex(const SwitchesTable * switches, QString val, Board::LookupValueType lvt) +{ + for (int i = 0; i < (int)switches->size(); i++) { + if ((lvt == Board::LVT_TAG && switches->at(i).tag.c_str() == val) || + (lvt == Board::LVT_NAME && switches->at(i).name.c_str() == val)) + return i; + } + + return -1; +} + +const Board::SwitchInfo BoardJson::getSwitchInfo(int index) const +{ + return getSwitchInfo(m_switches, index); +} + +// static +Board::SwitchInfo BoardJson::getSwitchInfo(const SwitchesTable * switches, int index) +{ + Board::SwitchInfo info; + + if (index >= 0 && index < (int)switches->size()) { + SwitchDefn defn = switches->at(index); + info.type = defn.type; + info.tag = defn.tag; + info.name = defn.name; + info.inverted = defn.inverted; + } + + return info; +} + +const QString BoardJson::getSwitchName(int index) const +{ + return getSwitchName(m_switches, index); +} + +// static +QString BoardJson::getSwitchName(const SwitchesTable * switches, int index) +{ + if (index > -1 && index < (int)switches->size()) + return switches->at(index).name.c_str(); + + return CPN_STR_UNKNOWN_ITEM; +} + +const QString BoardJson::getSwitchTag(int index) const +{ + return getSwitchTag(m_switches, index); +} + +// static +QString BoardJson::getSwitchTag(const SwitchesTable * switches, int index) +{ + if (index > -1 && index < (int)switches->size()) + return switches->at(index).tag.c_str(); + + return CPN_STR_UNKNOWN_ITEM; +} + +const int BoardJson::getSwitchTagNum(int index) const +{ + return getSwitchTagNum(m_switches, index); +} + +// static +int BoardJson::getSwitchTagNum(const SwitchesTable * switches, int index) +{ + if (index > -1 && index < (int)switches->size()) + return getNumericSuffix(switches->at(index).tag.c_str()); + + return -1; +} + +const int BoardJson::getSwitchYamlIndex(const QString val, YamlLookupType ylt) const +{ + for (int i = 0; i < (int)m_switches->size(); i++) { + Board::LookupValueType type = (ylt == YLT_CONFIG ? m_switches->at(i).cfgYaml : m_switches->at(i).refYaml); + QString tmp = (type == Board::LVT_NAME ? getSwitchName(m_switches, i) : getSwitchTag(m_switches, i)); + if (val == tmp) + return getSwitchIndex(m_switches, val, type); + } + + return -1; +} + +const QString BoardJson::getSwitchYamlName(int index, YamlLookupType ylt) const +{ + if (index > -1 && index < (int)m_switches->size()) { + if (ylt == YLT_CONFIG) + return m_switches->at(index).cfgYaml == Board::LVT_NAME ? getSwitchName(m_switches, index) : getSwitchTag(m_switches, index); + else + return m_switches->at(index).refYaml == Board::LVT_NAME ? getSwitchName(m_switches, index) : getSwitchTag(m_switches, index); + } + + return CPN_STR_UNKNOWN_ITEM; +} + +const int BoardJson::getTrimIndex(const QString val, Board::LookupValueType lvt) const +{ + return getTrimIndex(m_trims, val, lvt); +} + +// static +int BoardJson::getTrimIndex(const TrimsTable * trims, QString val, Board::LookupValueType lvt) +{ + for (int i = 0; i < (int)trims->size(); i++) { + if ((lvt == Board::LVT_TAG && trims->at(i).tag.c_str() == val) || + (lvt == Board::LVT_NAME && trims->at(i).name.c_str() == val)) + return i; + } + + return -1; +} + +const QString BoardJson::getTrimName(int index) const +{ + return getTrimName(m_trims, index); +} + +// static +QString BoardJson::getTrimName(const TrimsTable * trims, int index) +{ + if (index > -1 && index < (int)trims->size()) + return trims->at(index).name.c_str(); + + return CPN_STR_UNKNOWN_ITEM; +} + +const QString BoardJson::getTrimTag(int index) const +{ + return getTrimTag(m_trims, index); +} + +// static +QString BoardJson::getTrimTag(const TrimsTable * trims, int index) +{ + if (index > -1 && index < (int)trims->size()) + return trims->at(index).tag.c_str(); + + return CPN_STR_UNKNOWN_ITEM; +} + +const int BoardJson::getTrimYamlIndex(const QString val, YamlLookupType ylt) const +{ + for (int i = 0; i < (int)m_trims->size(); i++) { + Board::LookupValueType type = (ylt == YLT_CONFIG ? m_trims->at(i).cfgYaml : m_trims->at(i).refYaml); + QString tmp = (type == Board::LVT_NAME ? getTrimName(m_trims, i) : getTrimTag(m_trims, i)); + if (val == tmp) + return getTrimIndex(m_trims, val, type); + } + + return -1; +} + +const QString BoardJson::getTrimYamlName(int index, YamlLookupType ylt) const +{ + if (index > -1 && index < (int)m_trims->size()) { + if (ylt == YLT_CONFIG) + return m_trims->at(index).cfgYaml == Board::LVT_NAME ? getTrimName(m_trims, index) : getTrimTag(m_trims, index); + else + return m_trims->at(index).refYaml == Board::LVT_NAME ? getTrimName(m_trims, index) : getTrimTag(m_trims, index); + } + + return CPN_STR_UNKNOWN_ITEM; +} + +const bool BoardJson::isInputAvailable(int index) const +{ + return isInputAvailable(m_inputs->at(index)); +} + +// static +bool BoardJson::isInputAvailable(const InputDefn & defn) +{ + return (defn.type == Board::AIT_STICK || + (defn.type == Board::AIT_FLEX && defn.flexType != Board::FLEX_NONE && !isInputFlexJoystickAxis(defn))); +} + +const bool BoardJson::isInputCalibrated(int index) const +{ + return isInputCalibrated(m_inputs->at(index)); +} + +// static +bool BoardJson::isInputCalibrated(const InputDefn & defn) +{ + return (isInputStick(defn) || isInputFlexPot(defn) || isInputFlexSlider(defn)); +} + +const bool BoardJson::isInputConfigurable(int index) const +{ + return isInputConfigurable(m_inputs->at(index)); +} + +// static +bool BoardJson::isInputConfigurable(const InputDefn & defn) +{ + return (isInputStick(defn) || isInputFlexPot(defn) || isInputFlexSlider(defn)); +} + +const bool BoardJson::isInputIgnored(int index) const +{ + return isInputIgnored(m_inputs->at(index)); +} + +// static +bool BoardJson::isInputIgnored(const InputDefn & defn) +{ + return (isInputFlexJoystickAxis(defn) || isInputSwitch(defn)); +} + +// static +bool BoardJson::isInputFlex(const InputDefn & defn) +{ + return defn.type == Board::AIT_FLEX; +} + +// static +bool BoardJson::isInputFlexGyroAxis(const InputDefn & defn) +{ + const char* val = defn.tag.data(); + + return (defn.type == Board::AIT_FLEX && defn.tag.size() > 5 && + val[0] == 'T' && val[1] == 'I' && val[2] == 'L' && val[3] == 'T' && val[4] == '_' && (val[5] == 'X' || val[5] == 'Y')); +} + +// static +bool BoardJson::isInputFlexJoystickAxis(const InputDefn & defn) +{ + const char* val = defn.tag.data(); + + return (defn.type == Board::AIT_FLEX && defn.tag.size() > 2 && + val[0] == 'J' && val[1] == 'S' && (val[2] == 'x' || val[2] == 'y')); +} + +const bool BoardJson::isInputFlexPot(int index) const +{ + return isInputFlexPot(m_inputs->at(index)); +} + +// static +bool BoardJson::isInputFlexPot(const InputDefn & defn) +{ + const char* val = defn.tag.data(); + size_t len = defn.tag.size(); + + return (defn.type == Board::AIT_FLEX && + ((len > 1 && val[0] == 'P' && val[1] >= '0' && val[1] <= '9') || + (len > 3 && val[0] == 'E' && val[1] == 'X' && val[2] == 'T' && val[3] >= '0' && val[3] <= '9'))); +} + +// static +bool BoardJson::isInputFlexPotMultipos(const InputDefn & defn) +{ + return defn.type == Board::AIT_FLEX && defn.flexType == Board::FLEX_MULTIPOS; +} + +// static +bool BoardJson::isInputFlexSlider(const InputDefn & defn) +{ + const char* val = defn.tag.data(); + + return (defn.type == Board::AIT_FLEX && defn.tag.size() > 2 && + val[0] == 'S' && val[1] == 'L' && val[2] >= '0' && val[2] <= '9'); +} + +// static +bool BoardJson::isInputFlexSwitch(const InputDefn & defn) +{ + return defn.type == Board::AIT_FLEX && defn.flexType == Board::FLEX_SWITCH; +} + +// static +bool BoardJson::isInputRTCBat(const InputDefn & defn) +{ + return defn.type == Board::AIT_RTC_BAT; +} + +const bool BoardJson::isInputStick(int index) const +{ + return isInputStick(m_inputs->at(index)); +} + +// static +bool BoardJson::isInputStick(const InputDefn & defn) +{ + return defn.type == Board::AIT_STICK; +} + +const bool BoardJson::isInputSwitch(int index) const +{ + return isInputSwitch(m_inputs->at(index)); +} + +// static +bool BoardJson::isInputSwitch(const InputDefn & defn) +{ + return defn.type == Board::AIT_SWITCH; +} + +// static +bool BoardJson::isInputVBat(const InputDefn & defn) +{ + return defn.type == Board::AIT_VBAT; +} + +const bool BoardJson::isSwitchConfigurable(int index) const +{ + if (index >= 0 && index < getCapability(Board::Switches)) { + SwitchDefn &defn = m_switches->at(index); + if (isSwitchStd(defn)) + return true; + + if (isSwitchFlex(defn)) { + int sfx = getNumericSuffix(defn.tag); + if (sfx > 0 && sfx <= getCapability(Board::FlexSwitches)) + return true; + } + } + + return false; +} + +// static +bool BoardJson::isSwitchStd(const SwitchDefn & defn) +{ + return !(isSwitchFlex(defn) || isSwitchFunc(defn)); +} + +const bool BoardJson::isSwitchFlex(int index) const +{ + return isSwitchFlex(m_switches->at(index)); +} + +// static +bool BoardJson::isSwitchFlex(const SwitchDefn & defn) +{ + const char* val = defn.tag.data(); + + return (defn.tag.size() > 2 && + val[0] == 'F' && val[1] == 'L' && val[2] >= '0' && val[2] <= '9'); +} + +const bool BoardJson::isSwitchFunc(int index) const +{ + return isSwitchFunc(m_switches->at(index)); +} + +// static +bool BoardJson::isSwitchFunc(const SwitchDefn & defn) +{ + return defn.type == Board::SWITCH_FUNC; +} + +bool BoardJson::loadDefinition() +{ + // safety net for BoardFactory::instance + if (m_board == Board::BOARD_UNKNOWN) + return true; + + if (!loadFile(m_board, m_hwdefn, m_inputs, m_switches, m_trims)) + return false; + + afterLoadFixups(m_board, m_inputs, m_switches); + + setInputCounts(m_inputs, m_inputCnt); + setSwitchCounts(m_switches, m_switchCnt); + + // json files do not normally specify stick labels so load legacy labels + for (int i = 0; i < getCapability(Board::Sticks); i++) { + if (m_inputs->at(i).name.empty()) + m_inputs->at(i).name = DataHelpers::getStringTagMappingName(stickNamesLookupTable, m_inputs->at(i).tag.c_str()); + } + + qDebug() << "Board:" << Boards::getBoardName(m_board) << + "inputs:" << getCapability(Board::Inputs) << + "sticks:" << getCapability(Board::Sticks) << + "pots:" << getCapability(Board::Pots) << + "sliders:" << getCapability(Board::Sliders) << + "gyro axes:" << getCapability(Board::GyroAxes) << + "joystick axes:" << getCapability(Board::JoystickAxes) << + "flex inputs:" << getCapability(Board::FlexInputs) << + "input switches:" << getCapability(Board::InputSwitches) << + "trims:" << getCapability(Board::NumTrims) << + "std switches:" << getCapability(Board::StandardSwitches) << + "flex switches:" << getCapability(Board::FlexSwitches) << + "func switches:" << getCapability(Board::FunctionSwitches) << + "rtcbat:" << getCapability(Board::HasRTC) << + "vbat:" << getCapability(Board::HasVBat); + + return true; +} + +// static +bool BoardJson::loadFile(Board::Type board, QString hwdefn, InputsTable * inputs, SwitchesTable * switches, TrimsTable * trims) +{ + if (board == Board::BOARD_UNKNOWN) { + return false; + } + + // required because of the way the Firmware class is used + if (hwdefn.isEmpty()) { + return false; + } + + QString path = QString(":/hwdefs/%1.json").arg(hwdefn); + QFile file(path); + + if (!file.exists()) { + QMessageBox::critical(nullptr, tr("Load Board Hardware Definition"), + tr("Board: %1\nError: Unable to load file %2").arg(Boards::getBoardName(board)).arg(path)); + return false; + } + + if (!file.open(QIODevice::ReadOnly)) { + QMessageBox::critical(nullptr, tr("Load Board Hardware Definition"), + tr("Board: %1\nError: Unable to open file %2").arg(Boards::getBoardName(board)).arg(path)); + return false; + } + + QByteArray buffer = file.readAll(); + file.close(); + + if (buffer.isEmpty()) { + QMessageBox::critical(nullptr, tr("Load Board Hardware Definition"), + tr("Board: %1\nError: Unable to read file %2").arg(Boards::getBoardName(board)).arg(path)); + return false; + } + + QJsonParseError res; + QJsonDocument *json = new QJsonDocument(); + *json = QJsonDocument::fromJson(buffer, &res); + + if (res.error || json->isNull() || !json->isObject()) { + QMessageBox::critical(nullptr, tr("Load Board Hardware Definition"), + tr("Board: %1\nError: %2 is not a valid json formatted file.\nError code: %3\nError description: %4").arg(Boards::getBoardName(board)).arg(path).arg(res.error).arg(res.errorString())); + delete json; + return false; + } + + const QJsonObject &obj = json->object(); + + if (obj.value("adc_inputs").isObject()) { + const QJsonObject &adcinputs = obj.value("adc_inputs").toObject(); + + if (adcinputs.value("inputs").isArray()) { + const QJsonArray &in = adcinputs.value("inputs").toArray(); + + for (const QJsonValue &input : in) + { + if (input.isObject()) { + const QJsonObject &o = input.toObject(); + InputDefn defn; + + if (!o.value("name").isUndefined()) + defn.tag = o.value("name").toString().toStdString(); + + if (!o.value("type").isUndefined()) { + std::string type = o.value("type").toString().toStdString(); + defn.type = (AnalogInputType)DataHelpers::getStringTagMappingIndex(inputTypesLookupTable, type.c_str()); + if (defn.type == AIT_STICK) + defn.refYaml = LVT_NAME; + } + + if (!o.value("inverted").isUndefined()) + defn.inverted = o.value("inverted").toBool(); + + if (!o.value("label").isUndefined()) + defn.name = o.value("label").toString().toStdString(); + + if (!o.value("short_label").isUndefined()) + defn.shortName = o.value("short_label").toString().toStdString(); + + if (!o.value("default").isUndefined()) { + std::string dflt = o.value("default").toString().toStdString(); + if (defn.type == AIT_FLEX) { + int idx = DataHelpers::getStringTagMappingIndex(flexTypesLookupTable, dflt.c_str()); + defn.flexType = (FlexType)(idx < 0 ? FLEX_NONE : idx); + } + } + + inputs->insert(inputs->end(), defn); + +// qDebug() << "name:" << defn.name.c_str() << +// "type:" << defn.stype.c_str() << ">" << +// DataHelpers::getStringNameMappingTag(inputTypesLookupTable, std::to_string(defn.type).c_str()).c_str() << +// "label:" << defn.label.c_str() << "short:" << defn.shortLabel.c_str() << "inverted:" << defn.inverted << +// "dflt:" << defn.dflt.c_str() << ">" << +// DataHelpers::getStringNameMappingTag(flexTypesLookupTable, std::to_string(defn.flexType).c_str()).c_str(); + } + } + } + } + + if (obj.value("switches").isArray()) { + const QJsonArray &swtchs = obj.value("switches").toArray(); + + for (const QJsonValue &swtch : swtchs) + { + if (swtch.isObject()) { + const QJsonObject &o = swtch.toObject(); + SwitchDefn sw; + + if (!o.value("name").isUndefined()) { + sw.name = o.value("name").toString().toStdString(); + sw.tag = sw.name; + } + + if (!o.value("type").isUndefined()) { + std::string type = o.value("type").toString().toStdString(); + int idx = DataHelpers::getStringTagMappingIndex(switchTypesLookupTable, type.c_str()); + sw.type = idx < 0 ? Board::SWITCH_NOT_AVAILABLE : (Board::SwitchType)idx; + } + + if (!o.value("flags").isUndefined()) + sw.flags = o.value("flags").toInt(); + + if (!o.value("inverted").isUndefined()) + sw.inverted = o.value("inverted").toBool(); + + if (!o.value("default").isUndefined()) { + std::string dflt = o.value("default").toString().toStdString(); + int idx = DataHelpers::getStringTagMappingIndex(switchTypesLookupTable, dflt.c_str()); + sw.dflt = idx < 0 ? Board::SWITCH_NOT_AVAILABLE : (Board::SwitchType)idx; + } + + if (o.value("display").isArray()) { + const QJsonArray &d = obj.value("display").toArray(); + sw.display.x = (unsigned int)d.at(0).toInt(0); + sw.display.y = (unsigned int)d.at(1).toInt(0); + } + + switches->insert(switches->end(), sw); + +// qDebug() << "name:" << sw.name.c_str() << "type:" << sw.stype.c_str() << ">" << Boards::switchTypeToString(sw.type) << +// "flags:" << sw.flags << "default:" << sw.sdflt.c_str() << ">" << Boards::switchTypeToString(sw.dflt) << +// "inverted:" << sw.inverted << "display:" << QString("%1").arg(sw.display.x) << "," << QString("%1").arg(sw.display.y); + } + } + } + + if (obj.value("trims").isArray()) { + const QJsonArray &trms = obj.value("trims").toArray(); + + for (const QJsonValue &trm : trms) + { + if (trm.isObject()) { + const QJsonObject &o = trm.toObject(); + TrimDefn t; + + if (!o.value("name").isUndefined()) { + t.name = o.value("name").toString().toStdString(); + t.tag = t.name; + } + + trims->insert(trims->end(), t); + +// qDebug() << "name:" << t.name.c_str(); + } + } + } + + delete json; + return true; +} + +// static +void BoardJson::setInputCounts(const InputsTable * inputs, InputCounts & inputCounts) +{ + for (const auto &defn : *inputs) { + if (isInputStick(defn)) + inputCounts.sticks++; + else if (isInputFlexPot(defn)) + inputCounts.flexPots++; + else if (isInputFlexSlider(defn)) + inputCounts.flexSliders++; + else if (isInputFlexGyroAxis(defn)) + inputCounts.flexGyroAxes++; + else if (isInputFlexJoystickAxis(defn)) + inputCounts.flexJoystickAxes++; + else if (isInputFlexSwitch(defn)) + inputCounts.flexSwitches++; + else if (isInputRTCBat(defn)) + inputCounts.rtcbat++; + else if (isInputVBat(defn)) + inputCounts.vbat++; + else if (isInputSwitch(defn)) + inputCounts.switches++; + } +} + +// static +void BoardJson::setSwitchCounts(const SwitchesTable * switches, SwitchCounts & switchCounts) +{ + for (const auto &swtch : *switches) { + if (isSwitchStd(swtch)) + switchCounts.std++; + else if (isSwitchFlex(swtch)) + switchCounts.flex++; + else if (isSwitchFunc(swtch)) + switchCounts.func++; + } +} diff --git a/companion/src/firmwares/boardjson.h b/companion/src/firmwares/boardjson.h new file mode 100644 index 00000000000..ed1af245e19 --- /dev/null +++ b/companion/src/firmwares/boardjson.h @@ -0,0 +1,214 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * 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 "boards.h" + +#include + +#include +#include + +using namespace Board; + +class BoardJson +{ + Q_DECLARE_TR_FUNCTIONS(BoardJson) + + public: + enum YamlLookupType { + YLT_CONFIG, + YLT_REF + }; + + struct InputDefn { + Board::AnalogInputType type = AIT_NONE; + std::string tag = ""; + std::string name = ""; + std::string shortName = ""; + Board::FlexType flexType = FLEX_NONE; + bool inverted = false; + Board::LookupValueType cfgYaml = Board::LVT_TAG; + Board::LookupValueType refYaml = Board::LVT_TAG; + + InputDefn() = default; + }; + + typedef std::vector InputsTable; + + struct Display { + unsigned int x = 0; + unsigned int y = 0; + }; + + struct SwitchDefn { + Board::SwitchType type = Board::SWITCH_NOT_AVAILABLE; + std::string tag = ""; + std::string name = ""; + int flags = 0; + bool inverted = false; + Board::SwitchType dflt = Board::SWITCH_NOT_AVAILABLE; + Display display; + Board::LookupValueType cfgYaml = Board::LVT_TAG; + Board::LookupValueType refYaml = Board::LVT_NAME; + + SwitchDefn() = default; + }; + + typedef std::vector SwitchesTable; + + struct TrimDefn { + std::string tag = ""; + std::string name = ""; + Board::LookupValueType cfgYaml = Board::LVT_TAG; + Board::LookupValueType refYaml = Board::LVT_NAME; + + TrimDefn() = default; + }; + + typedef std::vector TrimsTable; + + explicit BoardJson(Board::Type board, QString hwdefn); + virtual ~BoardJson(); + + Board::Type board() const { return m_board; } + QString hwdefn() const { return m_hwdefn; } + + bool loadDefinition(); + + const int getCapability(const Board::Capability capability) const; + const int getInputsCalibrated() const; + + const int getInputIndex(const QString val, Board::LookupValueType lvt) const; + const Board::InputInfo getInputInfo(int index) const; + const QString getInputName(int index) const; + const int getInputPotIndex(int index); + const int getInputSliderIndex(int index); + const QString getInputTag(int index) const; + const int getInputTagOffset(QString tag); + const int getInputTypeOffset(Board::AnalogInputType type); + const int getInputYamlIndex(const QString val, YamlLookupType ylt) const; + const QString getInputYamlName(int index, YamlLookupType ylt) const; + + const bool isInputAvailable(int index) const; + const bool isInputCalibrated(int index) const; + const bool isInputConfigurable(int index) const; + const bool isInputIgnored(int index) const; + const bool isInputFlexPot(int index) const; + const bool isInputFlexSwitch(int index) const; + const bool isInputStick(int index) const; + const bool isInputSwitch(int index) const; + + const int getSwitchIndex(const QString val, Board::LookupValueType lvt) const; + const Board::SwitchInfo getSwitchInfo(int index) const; + const QString getSwitchName(int index) const; + const QString getSwitchTag(int index) const; + const int getSwitchTagNum(int index) const; + const int getSwitchYamlIndex(const QString val, YamlLookupType ylt) const; + const QString getSwitchYamlName(int index, YamlLookupType ylt) const; + + const int getTrimIndex(const QString val, Board::LookupValueType lvt) const; + const QString getTrimName(int index) const; + const QString getTrimTag(int index) const; + const int getTrimYamlIndex(const QString val, YamlLookupType ylt) const; + const QString getTrimYamlName(int index, YamlLookupType ylt) const; + + const bool isSwitchConfigurable(int index) const; + const bool isSwitchFlex(int index) const; + const bool isSwitchFunc(int index) const; +private: + Board::Type m_board; + QString m_hwdefn; + + InputsTable *m_inputs; + SwitchesTable *m_switches; + TrimsTable *m_trims; + + struct InputCounts { + unsigned int flexGyroAxes; + unsigned int flexJoystickAxes; + unsigned int flexPots; + unsigned int flexSliders; + unsigned int flexSwitches; + unsigned int rtcbat; + unsigned int sticks; + unsigned int switches; + unsigned int vbat; + }; + + InputCounts m_inputCnt; + + struct SwitchCounts { + unsigned int std; + unsigned int flex; + unsigned int func; + }; + + SwitchCounts m_switchCnt; + + static bool loadFile(Board::Type board, QString hwdefn, InputsTable * inputs, SwitchesTable * switches, TrimsTable * trims); + static void afterLoadFixups(Board::Type board, InputsTable * inputs, SwitchesTable * switches); + + static int getInputsCalibrated(const InputsTable * inputs); + + static int getInputIndex(const InputsTable * inputs, QString val, Board::LookupValueType lvt); + static Board::InputInfo getInputInfo(const InputsTable * inputs, int index); + static QString getInputName(const InputsTable * inputs, int index); + static QString getInputTag(const InputsTable * inputs, int index); + static int getInputTagOffset(const InputsTable * inputs, QString tag); + static int getInputTypeOffset(const InputsTable * inputs, Board::AnalogInputType type); + + static int getSwitchIndex(const SwitchesTable * switches, QString val, Board::LookupValueType lvt); + static Board::SwitchInfo getSwitchInfo(const SwitchesTable * switches, int index); + static QString getSwitchName(const SwitchesTable * switches, int index); + static QString getSwitchTag(const SwitchesTable * switches, int index); + static int getSwitchTagNum(const SwitchesTable * switches, int index); + + static int getTrimIndex(const TrimsTable * trims, QString val, Board::LookupValueType lvt); + static QString getTrimName(const TrimsTable * trims, int index); + static QString getTrimTag(const TrimsTable * trims, int index); + + static bool isInputAvailable(const InputDefn & defn); + static bool isInputCalibrated(const InputDefn & defn); + static bool isInputConfigurable(const InputDefn & defn); + static bool isInputFlex(const InputDefn & defn); + static bool isInputFlexGyroAxis(const InputDefn & defn); + static bool isInputFlexJoystickAxis(const InputDefn & defn); + static bool isInputFlexPot(const InputDefn & defn); + static bool isInputFlexPotMultipos(const InputDefn & defn); + static bool isInputFlexSlider(const InputDefn & defn); + static bool isInputFlexSwitch(const InputDefn & defn); + static bool isInputIgnored(const InputDefn & defn); + static bool isInputRTCBat(const InputDefn & defn); + static bool isInputStick(const InputDefn & defn); + static bool isInputSwitch(const InputDefn & defn); + static bool isInputVBat(const InputDefn & defn); + + static bool isSwitchStd(const SwitchDefn & defn); + static bool isSwitchFlex(const SwitchDefn & defn); + static bool isSwitchFunc(const SwitchDefn & defn); + + static void setInputCounts(const InputsTable * inputs, InputCounts & inputCounts); + static void setSwitchCounts(const SwitchesTable * switches, SwitchCounts & switchCounts); + + static int getNumericSuffix(const std::string str); +}; diff --git a/companion/src/firmwares/boards.cpp b/companion/src/firmwares/boards.cpp index f7f2be15615..eff64a744c0 100644 --- a/companion/src/firmwares/boards.cpp +++ b/companion/src/firmwares/boards.cpp @@ -23,6 +23,8 @@ #include "compounditemmodels.h" #include "moduledata.h" #include "helpers.h" +#include "boardfactories.h" +#include "generalsettings.h" // TODO remove all those constants // Update: These are now all only used within this class. @@ -41,14 +43,57 @@ #define FSIZE_HORUS (2048*1024) #define FSIZE_MAX FSIZE_HORUS +// pre v2.10 +static const StringTagMappingTable legacyTrimSourcesLut = { + {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"}, + {std::to_string(TRIM_AXIS_T5), "TrimT5"}, + {std::to_string(TRIM_AXIS_T6), "TrimT6"}, + {std::to_string(TRIM_AXIS_T7), "TrimT7"}, + {std::to_string(TRIM_AXIS_T8), "TrimT8"}, +}; + +static const StringTagMappingTable trimSwitchesLut = { + {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"}, + {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"}, + {std::to_string(TRIM_SW_T7_INC), "TrimT7Up"}, + {std::to_string(TRIM_SW_T7_DEC), "TrimT7Down"}, + {std::to_string(TRIM_SW_T8_INC), "TrimT8Up"}, + {std::to_string(TRIM_SW_T8_DEC), "TrimT8Down"}, +}; + using namespace Board; +Boards::Boards(Board::Type board) : + legacyTrimSourcesLookupTable(legacyTrimSourcesLut), + trimSwitchesLookupTable(trimSwitchesLut), + rawSwitchTypesLookupTable(RawSwitch::getRawSwitchTypesLookupTable()), + rawSourceSpecialTypesLookupTable(RawSource::getSpecialTypesLookupTable()), + rawSourceCyclicLookupTable(RawSource::getCyclicLookupTable()) +{ + setBoardType(board); +} + void Boards::setBoardType(const Type & board) { - if (board >= BOARD_UNKNOWN && board <= BOARD_TYPE_MAX) + if (board < BOARD_TYPE_MAX) m_boardType = board; else m_boardType = BOARD_UNKNOWN; + + m_boardJson = getBoardJson(m_boardType); } uint32_t Boards::getFourCC(Type board) @@ -218,391 +263,18 @@ int Boards::getFlashSize(Type board) } } -SwitchInfo Boards::getSwitchInfo(Board::Type board, int index) -{ - if (index < 0) - return {SWITCH_NOT_AVAILABLE, CPN_STR_UNKNOWN_ITEM}; - - if (IS_TARANIS_XLITES(board)) { - const Board::SwitchInfo switches[] = { - {SWITCH_3POS, "SA"}, - {SWITCH_3POS, "SB"}, - {SWITCH_2POS, "SC"}, - {SWITCH_2POS, "SD"}, - {SWITCH_TOGGLE, "SE"}, - {SWITCH_TOGGLE, "SF"} - }; - if (index < DIM(switches)) - return switches[index]; - } - else if (IS_JUMPER_TPROV2(board)) { - const Board::SwitchInfo switches[] = { - {SWITCH_3POS, "SA"}, - {SWITCH_3POS, "SB"}, - {SWITCH_2POS, "SC"}, - {SWITCH_2POS, "SD"}, - {SWITCH_2POS, "SE"}, - {SWITCH_2POS, "SF"}, - }; - if (index < DIM(switches)) - return switches[index]; - } - else if (IS_TARANIS_XLITE(board) || IS_JUMPER_TLITE(board) || IS_JUMPER_TPROV1(board) || IS_BETAFPV_LR3PRO(board)) { - const Board::SwitchInfo switches[] = { - {SWITCH_3POS, "SA"}, - {SWITCH_3POS, "SB"}, - {SWITCH_2POS, "SC"}, - {SWITCH_2POS, "SD"} - }; - if (index < DIM(switches)) - return switches[index]; - } - else if (board == BOARD_TARANIS_X7_ACCESS) { - const Board::SwitchInfo switches[] = { - {SWITCH_3POS, "SA"}, - {SWITCH_3POS, "SB"}, - {SWITCH_3POS, "SC"}, - {SWITCH_3POS, "SD"}, - {SWITCH_2POS, "SF"}, - {SWITCH_TOGGLE, "SH"}, - {SWITCH_2POS, "SI"} - }; - if (index < DIM(switches)) - return switches[index]; - } - else if (board == BOARD_TARANIS_X7) { - const Board::SwitchInfo switches[] = { - {SWITCH_3POS, "SA"}, - {SWITCH_3POS, "SB"}, - {SWITCH_3POS, "SC"}, - {SWITCH_3POS, "SD"}, - {SWITCH_2POS, "SF"}, - {SWITCH_TOGGLE, "SH"}, - {SWITCH_2POS, "SI"}, - {SWITCH_2POS, "SJ"} - }; - if (index < DIM(switches)) - return switches[index]; - } - else if (IS_RADIOMASTER_TX12(board)) { - const Board::SwitchInfo switches[] = { - {SWITCH_TOGGLE, "SA"}, - {SWITCH_3POS, "SB"}, - {SWITCH_3POS, "SC"}, - {SWITCH_TOGGLE, "SD"}, - {SWITCH_3POS, "SE"}, - {SWITCH_3POS, "SF"}, - {SWITCH_2POS, "SI"}, - {SWITCH_2POS, "SJ"} - }; - if (index < DIM(switches)) - return switches[index]; - } - else if (IS_RADIOMASTER_TX12_MK2(board)) { - const Board::SwitchInfo switches[] = { - {SWITCH_TOGGLE, "SA"}, - {SWITCH_3POS, "SB"}, - {SWITCH_3POS, "SC"}, - {SWITCH_TOGGLE, "SD"}, - {SWITCH_3POS, "SE"}, - {SWITCH_3POS, "SF"} - }; - if (index < DIM(switches)) - return switches[index]; - } - else if (IS_RADIOMASTER_ZORRO(board)) { - const Board::SwitchInfo switches[] = { - {SWITCH_TOGGLE, "SA"}, - {SWITCH_3POS, "SB"}, - {SWITCH_3POS, "SC"}, - {SWITCH_TOGGLE, "SD"}, - {SWITCH_2POS, "SE"}, - {SWITCH_2POS, "SF"}, - {SWITCH_TOGGLE, "SG"}, - {SWITCH_TOGGLE, "SH"} - }; - if (index < DIM(switches)) - return switches[index]; - } - else if (IS_RADIOMASTER_BOXER(board)) { - const Board::SwitchInfo switches[] = { - {SWITCH_2POS, "SA"}, - {SWITCH_3POS, "SB"}, - {SWITCH_3POS, "SC"}, - {SWITCH_3POS, "SD"}, - {SWITCH_2POS, "SE"}, - {SWITCH_TOGGLE, "SF"} - }; - if (index < DIM(switches)) - return switches[index]; - } - else if (IS_RADIOMASTER_POCKET(board)) { - const Board::SwitchInfo switches[] = { - {SWITCH_2POS, "SA"}, - {SWITCH_3POS, "SB"}, - {SWITCH_3POS, "SC"}, - {SWITCH_2POS, "SD"}, - {SWITCH_TOGGLE, "SE"} - }; - if (index < DIM(switches)) - return switches[index]; - } - else if (IS_RADIOMASTER_T8(board)) { - const Board::SwitchInfo switches[] = { - {SWITCH_TOGGLE, "SA"}, - {SWITCH_3POS, "SB"}, - {SWITCH_3POS, "SC"}, - {SWITCH_TOGGLE, "SD"} - }; - if (index < DIM(switches)) - return switches[index]; - } - else if (IS_IFLIGHT_COMMANDO8(board)) { - const Board::SwitchInfo switches[] = { - {SWITCH_2POS, "SA"}, - {SWITCH_3POS, "SB"}, - {SWITCH_3POS, "SC"}, - {SWITCH_2POS, "SD"} - }; - if (index < DIM(switches)) - return switches[index]; - } - else if (IS_JUMPER_T12(board)) { - const Board::SwitchInfo switches[] = { - {SWITCH_3POS, "SA"}, - {SWITCH_3POS, "SB"}, - {SWITCH_3POS, "SC"}, - {SWITCH_3POS, "SD"}, - {SWITCH_2POS, "SG"}, - {SWITCH_2POS, "SH"} - }; - if (index < DIM(switches)) - return switches[index]; - } - else if (IS_JUMPER_T20(board)) { - const Board::SwitchInfo switches[] = { - {SWITCH_2POS, "SA"}, - {SWITCH_2POS, "SB"}, - {SWITCH_3POS, "SC"}, - {SWITCH_3POS, "SD"}, - {SWITCH_2POS, "SE"}, - {SWITCH_2POS, "SF"}, - {SWITCH_TOGGLE, "SG"}, - {SWITCH_TOGGLE, "SH"}, - {SWITCH_TOGGLE, "SI"}, - {SWITCH_TOGGLE, "SJ"}, - }; - if (index < DIM(switches)) - return switches[index]; - } - else if (IS_FLYSKY_NV14(board)) { - const Board::SwitchInfo switches[] = { - {SWITCH_2POS, "SA"}, - {SWITCH_3POS, "SB"}, - {SWITCH_TOGGLE, "SC"}, - {SWITCH_2POS, "SD"}, - {SWITCH_TOGGLE, "SE"}, - {SWITCH_3POS, "SF"}, - {SWITCH_3POS, "SG"}, - {SWITCH_TOGGLE, "SH"} - }; - if (index < DIM(switches)) - return switches[index]; - } - else if (IS_FLYSKY_EL18(board)) { - const Board::SwitchInfo switches[] = { - {SWITCH_2POS, "SA"}, - {SWITCH_3POS, "SB"}, - {SWITCH_3POS, "SC"}, - {SWITCH_2POS, "SD"}, - {SWITCH_2POS, "SE"}, - {SWITCH_3POS, "SF"}, - {SWITCH_3POS, "SG"}, - {SWITCH_TOGGLE, "SH"} - }; - if (index < DIM(switches)) - return switches[index]; - } - else if (IS_FLYSKY_PL18(board)) { - const Board::SwitchInfo switches[] = { - {SWITCH_2POS, "SA"}, - {SWITCH_3POS, "SB"}, - {SWITCH_2POS, "SC"}, - {SWITCH_3POS, "SD"}, - {SWITCH_3POS, "SE"}, - {SWITCH_2POS, "SF"}, - {SWITCH_3POS, "SG"}, - {SWITCH_3POS, "SH"} - }; - if (index < DIM(switches)) - return switches[index]; - } - else if (IS_FAMILY_HORUS_OR_T16(board)) { - const Board::SwitchInfo switches[] = { - {SWITCH_3POS, "SA"}, - {SWITCH_3POS, "SB"}, - {SWITCH_3POS, "SC"}, - {SWITCH_3POS, "SD"}, - {SWITCH_3POS, "SE"}, - {SWITCH_2POS, "SF"}, - {SWITCH_3POS, "SG"}, - {SWITCH_TOGGLE, "SH"}, - {SWITCH_2POS, "SI"}, - {SWITCH_2POS, "SJ"} - }; - if (index < DIM(switches)) - return switches[index]; - } - else if (IS_TARANIS(board)) { - const Board::SwitchInfo switches[] = { - {SWITCH_3POS, "SA"}, - {SWITCH_3POS, "SB"}, - {SWITCH_3POS, "SC"}, - {SWITCH_3POS, "SD"}, - {SWITCH_3POS, "SE"}, - {SWITCH_2POS, "SF"}, - {SWITCH_3POS, "SG"}, - {SWITCH_TOGGLE, "SH"}, - {board == Board::BOARD_TARANIS_X9DP_2019 ? SWITCH_TOGGLE : SWITCH_3POS, "SI"}, - {SWITCH_3POS, "SJ"}, - {SWITCH_3POS, "SK"}, - {SWITCH_3POS, "SL"}, - {SWITCH_3POS, "SM"}, - {SWITCH_3POS, "SN"}, - {SWITCH_3POS, "SO"}, - {SWITCH_3POS, "SP"}, - {SWITCH_3POS, "SQ"}, - {SWITCH_3POS, "SR"} - }; - if (index < DIM(switches)) - return switches[index]; - } - else { - const Board::SwitchInfo switches[] = { - {SWITCH_3POS, "3POS"}, - {SWITCH_2POS, "THR"}, - {SWITCH_2POS, "RUD"}, - {SWITCH_2POS, "ELE"}, - {SWITCH_2POS, "AIL"}, - {SWITCH_2POS, "GEA"}, - {SWITCH_TOGGLE, "TRN"} - }; - if (index < DIM(switches)) - return switches[index]; - } - - return {SWITCH_NOT_AVAILABLE, CPN_STR_UNKNOWN_ITEM}; -} - +// static int Boards::getCapability(Board::Type board, Board::Capability capability) { + // TODO investigate usage of any that should be covered in BoardJson::getCapability or are no longer required + // some could be used when importing pre v2.10 configurations switch (capability) { - case Sticks: - return 4; - - case Pots: - if (IS_TARANIS_X9LITE(board) || IS_RADIOMASTER_POCKET(board)) - return 1; - else if (IS_JUMPER_TLITE(board) || IS_BETAFPV_LR3PRO(board) || IS_IFLIGHT_COMMANDO8(board)) - return 0; - else if (IS_RADIOMASTER_BOXER(board)) - return 3; - else if (IS_TARANIS_SMALL(board) || IS_JUMPER_TPRO(board) || IS_FLYSKY_NV14(board) || IS_JUMPER_T20(board)) - return 2; - else if (IS_TARANIS_X9E(board)) - return 4; - else if (IS_HORUS_X10(board) || IS_FAMILY_T16(board)) - return 7; - else if (IS_HORUS_X12S(board)) - return 3; - else if (IS_FLYSKY_PL18(board)) - return 3; - else - return 3; - case FactoryInstalledPots: if (IS_TARANIS_X9(board)) return 2; else return getCapability(board, Pots); - case Sliders: - if (IS_HORUS_X12S(board) || IS_TARANIS_X9E(board) || IS_JUMPER_T20(board)) - return 4; - else if (IS_TARANIS_X9D(board) || IS_HORUS_X10(board) || IS_FAMILY_T16(board) || IS_FLYSKY_PL18(board)) - return 2; - else - return 0; - - case MouseAnalogs: - if (IS_FAMILY_HORUS_OR_T16(board)) - return 2; - else - return 0; - - case GyroAnalogs: - if (IS_TARANIS_XLITES(board) || IS_FAMILY_HORUS_OR_T16(board)) - return 2; - else - return 0; - - case MaxAnalogs: - return getCapability(board, Board::Sticks) + getCapability(board, Board::Pots) + getCapability(board, Board::Sliders) + - getCapability(board, Board::MouseAnalogs) + getCapability(board, Board::GyroAnalogs); - - case MultiposPots: - if (IS_HORUS_OR_TARANIS(board) && !(IS_FLYSKY_NV14(board) || IS_FLYSKY_EL18(board) || IS_FLYSKY_PL18(board))) - return getCapability(board, Board::Pots); - else - return 0; - - case MultiposPotsPositions: - return IS_HORUS_OR_TARANIS(board) ? 6 : 0; - - case Board::Switches: - if (IS_TARANIS_X9E(board)) - return 18; - else if (board == Board::BOARD_TARANIS_X9LITE) - return 5; - else if (board == Board::BOARD_TARANIS_X9LITES) - return 7; - else if (board == BOARD_TARANIS_X7_ACCESS) - return 7; - else if (board == BOARD_TARANIS_X7) - return 8; - else if (board == BOARD_JUMPER_TLITE || board == BOARD_JUMPER_TLITE_F4 || - board == BOARD_JUMPER_TPRO || board == BOARD_BETAFPV_LR3PRO || - board == BOARD_IFLIGHT_COMMANDO8) - return 4; - else if (board == BOARD_JUMPER_TPROV2) - return 6; - else if (board == BOARD_FLYSKY_NV14 || board == BOARD_FLYSKY_EL18) - return 8; - else if (board == BOARD_FLYSKY_PL18) - return 8; - else if (board == BOARD_RADIOMASTER_TX12_MK2 || board == BOARD_RADIOMASTER_BOXER || board == BOARD_JUMPER_TPRO) - return 6; - else if (board == BOARD_RADIOMASTER_POCKET) - return 5; - else if (IS_FAMILY_T12(board)) - return 8; - else if (IS_TARANIS_XLITE(board)) - return 6; - else if (board == Board::BOARD_TARANIS_X9DP_2019) - return 9; - else if (IS_TARANIS(board)) - return 8; - else if (IS_FAMILY_HORUS_OR_T16(board) || IS_JUMPER_T20(board)) - return 10; - else - return 7; - - case FunctionSwitches: - if (board == BOARD_JUMPER_TPRO || board == BOARD_JUMPER_TPROV2 || board == BOARD_JUMPER_T20) - return 6; - else - return 0; - case FactoryInstalledSwitches: if (IS_TARANIS_X9E(board)) return 8; @@ -621,61 +293,26 @@ int Boards::getCapability(Board::Type board, Board::Capability capability) else return getCapability(board, Board::Switches); - case SwitchPositions: - if (IS_HORUS_OR_TARANIS(board) || IS_FLYSKY_NV14(board) || IS_FLYSKY_EL18(board) || IS_FLYSKY_PL18(board)) - return getCapability(board, Board::Switches) * 3; - else - return 9; - - case NumFunctionSwitchesPositions: - return getCapability(board, Board::FunctionSwitches) * 3; - - - case NumTrims: - if (IS_FLYSKY_PL18(board)) - return 8; - else if (IS_FAMILY_HORUS_OR_T16(board) && !IS_FLYSKY_NV14(board)) - return 6; - else if (IS_IFLIGHT_COMMANDO8(board)) - return 0; - else if (IS_JUMPER_T20(board)) - return 8; - else - return 4; - - case NumTrimSwitches: - return getCapability(board, Board::NumTrims) * 2; - - case HasRTC: - return IS_STM32(board) ? true : false; + case HasAudioMuteGPIO: + // All color lcd (including NV14 and EL18) except Horus X12S + // TX12, TX12MK2, ZORRO, BOXER, T8, TLITE, TPRO, LR3PRO, COMMANDO8 + return (IS_FAMILY_HORUS_OR_T16(board) && !IS_HORUS_X12S(board)) || IS_FAMILY_T12(board); case HasColorLcd: - return IS_FAMILY_HORUS_OR_T16(board) || IS_FLYSKY_NV14(board) || IS_FLYSKY_PL18(board); - - case HasSDCard: - return IS_STM32(board); - - case HasInternalModuleSupport: - return (IS_STM32(board) && !IS_TARANIS_X9(board)); + return IS_FAMILY_HORUS_OR_T16(board); case HasExternalModuleSupport: return (IS_STM32(board) && !IS_RADIOMASTER_T8(board)); - case HasAudioMuteGPIO: - // All color lcd (including NV14 and EL18) except Horus X12S - // TX12, TX12MK2, ZORRO, BOXER, T8, TLITE, TPRO, LR3PRO, COMMANDO8 - return (IS_FAMILY_HORUS_OR_T16(board) && !IS_HORUS_X12S(board)) || IS_FAMILY_T12(board); + case HasInternalModuleSupport: + return (IS_STM32(board) && !IS_TARANIS_X9(board)); case HasLedStripGPIO: // No current radio do support that feature return false; - case SportMaxBaudRate: - if (IS_FAMILY_T16(board) || IS_FLYSKY_NV14(board) || IS_FLYSKY_EL18(board) || IS_FLYSKY_PL18(board) ||IS_TARANIS_X7_ACCESS(board) || - (IS_TARANIS(board) && !IS_TARANIS_XLITE(board) && !IS_TARANIS_X7(board) && !IS_TARANIS_X9LITE(board))) - return 400000; // 400K and higher - else - return 250000; // less than 400K + case HasSDCard: + return IS_STM32(board); case HasTrainerModuleCPPM: return (getCapability(board, HasTrainerModuleSBUS) || IS_FAMILY_HORUS_OR_T16(board)); @@ -686,8 +323,19 @@ int Boards::getCapability(Board::Type board, Board::Capability capability) IS_RADIOMASTER_TX12_MK2(board) || IS_RADIOMASTER_BOXER(board) || IS_RADIOMASTER_POCKET(board)) || (getCapability(board, HasExternalModuleSupport) && (IS_TARANIS(board) && !IS_FAMILY_T12(board)))); + case MaxAnalogs: + return getCapability(board, Board::Sticks) + getCapability(board, Board::Pots) + getCapability(board, Board::Sliders) + + getCapability(board, Board::JoystickAxes) + getCapability(board, Board::GyroAxes); + + case SportMaxBaudRate: + if (IS_FAMILY_T16(board) || IS_FLYSKY_NV14(board) || IS_FLYSKY_EL18(board) || IS_TARANIS_X7_ACCESS(board) || + (IS_TARANIS(board) && !IS_TARANIS_XLITE(board) && !IS_TARANIS_X7(board) && !IS_TARANIS_X9LITE(board))) + return 400000; // 400K and higher + else + return 250000; // less than 400K + default: - return 0; + return getBoardJson(board)->getCapability(capability); } } @@ -707,219 +355,123 @@ QString Boards::getAxisName(int index) return CPN_STR_UNKNOWN_ITEM; } -StringTagMappingTable Boards::getAnalogNamesLookupTable(Board::Type board, const QString strVersion) +// mapping json tag (1st entry) to legacy tag (2nd entry) +// json tag then used to find inputs index +// only used to decode pre v2.10 yaml configs +StringTagMappingTable Boards::getLegacyAnalogsLookupTable(Board::Type board) { - SemanticVersion version(strVersion); - SemanticVersion adcVersion(QString(CPN_ADC_REFACTOR_VERSION)); - StringTagMappingTable tbl; - if (getBoardCapability(board, Board::Sticks)) { - if (version < adcVersion) { - tbl.insert(tbl.end(), { - {tr("Rud").toStdString(), "Rud"}, - {tr("Ele").toStdString(), "Ele"}, - {tr("Thr").toStdString(), "Thr"}, - {tr("Ail").toStdString(), "Ail"}, - }); - } else { - tbl.insert(tbl.end(), { - {tr("Rud").toStdString(), "LH", 0}, - {tr("Ele").toStdString(), "LV", 1}, - {tr("Thr").toStdString(), "RH", 2}, - {tr("Ail").toStdString(), "RV", 3}, - }); - } - } + tbl.insert(tbl.end(), { + {tr("LH").toStdString(), "Rud"}, + {tr("LV").toStdString(), "Ele"}, + {tr("RV").toStdString(), "Thr"}, + {tr("RH").toStdString(), "Ail"}, + }); + + tbl.insert(tbl.end(), { - if (IS_SKY9X(board)) { + {tr("JSx").toStdString(), "MOUSE1"}, + {tr("JSy").toStdString(), "MOUSE2"}, + {tr("JSx").toStdString(), "JSx"}, + {tr("JSy").toStdString(), "JSy"}, + {tr("TILT_X").toStdString(), "TILT_X"}, + {tr("TILT_Y").toStdString(), "TILT_Y"}, + {tr("TILT_X").toStdString(), "GYRO1"}, + {tr("TILT_Y").toStdString(), "GYRO2"}, + }); + + if (IS_TARANIS_X9LITE(board)) { tbl.insert(tbl.end(), { - {tr("P1").toStdString(), "P1"}, - {tr("P2").toStdString(), "P2"}, - {tr("P3").toStdString(), "P3"}, - }); - } else if (IS_TARANIS_X9LITE(board)) { - if (version < adcVersion) { - tbl.insert(tbl.end(), { - {tr("S1").toStdString(), "S1"}, - {tr("POT1").toStdString(), "POT1"}, - }); - } else { - tbl.insert(tbl.end(), { - {tr("S1").toStdString(), "P1", 4}, + {tr("SL1").toStdString(), "S1"}, + {tr("P1").toStdString(), "POT1"}, }); - } } else if (IS_TARANIS_X9E(board)) { - if (version < adcVersion) { - tbl.insert(tbl.end(), { - {tr("F1").toStdString(), "POT1"}, - {tr("F2").toStdString(), "POT2"}, - {tr("F3").toStdString(), "POT3"}, - {tr("F4").toStdString(), "POT4"}, - {tr("S1").toStdString(), "SLIDER1"}, - {tr("S2").toStdString(), "SLIDER2"}, - {tr("LS").toStdString(), "SLIDER3"}, - {tr("RS").toStdString(), "SLIDER4"}, - }); - } else { - tbl.insert(tbl.end(), { - {tr("F1").toStdString(), "P1", 4}, - {tr("F2").toStdString(), "P2", 5}, - {tr("S1").toStdString(), "SL3", 8}, - {tr("S2").toStdString(), "SL4", 9}, - {tr("LS").toStdString(), "SL1", 6}, - {tr("RS").toStdString(), "SL2", 7}, - }); - } + tbl.insert(tbl.end(), { + {tr("P1").toStdString(), "POT1"}, + {tr("P2").toStdString(), "POT2"}, + {tr("P3").toStdString(), "POT3"}, + {tr("P4").toStdString(), "POT4"}, + {tr("SL1").toStdString(), "SLIDER1"}, + {tr("SL2").toStdString(), "SLIDER2"}, + {tr("SL3").toStdString(), "SLIDER3"}, + {tr("SL4").toStdString(), "SLIDER4"}, + }); } else if (IS_TARANIS_XLITES(board)) { - if (version < adcVersion) { - tbl.insert(tbl.end(), { - {tr("S1").toStdString(), "POT1"}, - {tr("S2").toStdString(), "POT2"}, - {tr("TltX").toStdString(), "TILT_X"}, - {tr("TltY").toStdString(), "TILT_Y"}, - }); - } else { - tbl.insert(tbl.end(), { - {tr("S1").toStdString(), "P1", 4}, - {tr("S2").toStdString(), "P2", 5}, - {tr("TltX").toStdString(), "TILT_X", 6}, - {tr("TltY").toStdString(), "TILT_Y", 7}, - }); - } + tbl.insert(tbl.end(), { + {tr("P1").toStdString(), "POT1"}, + {tr("P2").toStdString(), "POT2"}, + }); } else if (IS_RADIOMASTER_BOXER(board)) { tbl.insert(tbl.end(), { - {tr("S1").toStdString(), "POT1"}, - {tr("S2").toStdString(), "POT2"}, - {tr("S3").toStdString(), "POT3"}, + {tr("P1").toStdString(), "POT1"}, + {tr("P2").toStdString(), "POT2"}, + {tr("P3").toStdString(), "POT3"}, }); } else if (IS_RADIOMASTER_POCKET(board)) { tbl.insert(tbl.end(), { - {tr("S1").toStdString(), "P1", 4}, + {tr("P1").toStdString(), "P1"}, }); } else if ((IS_TARANIS_SMALL(board) && !IS_JUMPER_TLITE(board) && !IS_JUMPER_T20(board)) || IS_FLYSKY_NV14(board) || IS_FLYSKY_EL18(board)) { - if (version < adcVersion) { - tbl.insert(tbl.end(), { - {tr("S1").toStdString(), "POT1"}, - {tr("S2").toStdString(), "POT2"}, - }); - } else { - tbl.insert(tbl.end(), { - {tr("S1").toStdString(), "P1", 4}, - {tr("S2").toStdString(), "P2", 5}, - }); - } + tbl.insert(tbl.end(), { + {tr("P1").toStdString(), "POT1"}, + {tr("P2").toStdString(), "POT2"}, + }); } else if (IS_TARANIS_X9(board)) { - if (version < adcVersion) { - tbl.insert(tbl.end(), { - {tr("S1").toStdString(), "POT1"}, - {tr("S2").toStdString(), "POT2"}, - {tr("S3").toStdString(), "POT3"}, - {tr("LS").toStdString(), "SLIDER1"}, - {tr("RS").toStdString(), "SLIDER2"}, - }); - } else { - tbl.insert(tbl.end(), { - {tr("S1").toStdString(), "P1", 4}, - {tr("S2").toStdString(), "P2", 5}, - {tr("S3").toStdString(), "P3", 6}, - {tr("LS").toStdString(), "SL1", 7}, - {tr("RS").toStdString(), "SL2", 8}, - }); - } + tbl.insert(tbl.end(), { + {tr("P1").toStdString(), "POT1"}, + {tr("P2").toStdString(), "POT2"}, + {tr("P3").toStdString(), "POT3"}, + {tr("SL1").toStdString(), "SLIDER1"}, + {tr("SL2").toStdString(), "SLIDER2"}, + }); } else if (IS_HORUS_X12S(board)) { - if (version < adcVersion) { - tbl.insert(tbl.end(), { - {tr("S1").toStdString(), "S1"}, - {tr("6P").toStdString(), "6POS"}, - {tr("S2").toStdString(), "S2"}, - {tr("L1").toStdString(), "S3"}, - {tr("L2").toStdString(), "S4"}, - {tr("LS").toStdString(), "LS"}, - {tr("RS").toStdString(), "RS"}, - {tr("JSx").toStdString(), "MOUSE1"}, - {tr("JSy").toStdString(), "MOUSE2"}, - {tr("TltX").toStdString(), "TILT_X"}, - {tr("TltY").toStdString(), "TILT_Y"}, - }); - } else { - tbl.insert(tbl.end(), { - {tr("S1").toStdString(), "P1", 4}, - {tr("6POS").toStdString(), "P2", 5}, - {tr("S2").toStdString(), "P3", 6}, - {tr("L1").toStdString(), "SL3", 9}, - {tr("L2").toStdString(), "SL4", 10}, - {tr("LS").toStdString(), "SL1", 7}, - {tr("RS").toStdString(), "SL2", 8}, - {tr("JSx").toStdString(), "JSx", 11}, - {tr("JSy").toStdString(), "JSy", 12}, - {tr("TltX").toStdString(), "TILT_X", 13}, - {tr("TltY").toStdString(), "TILT_Y", 14}, - }); - } + tbl.insert(tbl.end(), { + {tr("P1").toStdString(), "S1"}, + {tr("P2").toStdString(), "6POS"}, + {tr("P3").toStdString(), "S2"}, + {tr("P4").toStdString(), "S3"}, + {tr("P5").toStdString(), "S4"}, + {tr("SL1").toStdString(), "LS"}, + {tr("SL2").toStdString(), "RS"}, + }); } else if (IS_FLYSKY_PL18(board)) { tbl.insert(tbl.end(), { - {tr("VRA").toStdString(), "POT1"}, - {tr("VRB").toStdString(), "POT2"}, - {tr("VRC").toStdString(), "POT3"}, - {tr("LS").toStdString(), "LS"}, - {tr("RS").toStdString(), "RS"}, + {tr("P1").toStdString(), "POT1"}, + {tr("P2").toStdString(), "POT2"}, + {tr("P3").toStdString(), "POT3"}, + {tr("SL1").toStdString(), "LS"}, + {tr("SL2").toStdString(), "RS"}, }); } else if (IS_HORUS_X10(board) || IS_FAMILY_T16(board)) { - if (version < adcVersion) { - tbl.insert(tbl.end(), { - {tr("S1").toStdString(), "S1"}, - {tr("6P").toStdString(), "6POS"}, - {tr("S2").toStdString(), "S2"}, - {tr("EX1").toStdString(), "EXT1"}, - {tr("EX2").toStdString(), "EXT2"}, - {tr("EX3").toStdString(), "EXT3"}, - {tr("EX4").toStdString(), "EXT4"}, - {tr("LS").toStdString(), "LS"}, - {tr("RS").toStdString(), "RS"}, - {tr("JSx").toStdString(), "MOUSE1"}, - {tr("JSy").toStdString(), "MOUSE2"}, - {tr("TltX").toStdString(), "TILT_X"}, - {tr("TltY").toStdString(), "TILT_Y"}, - }); - } else { - tbl.insert(tbl.end(), { - {tr("S1").toStdString(), "P1", 4}, - {tr("6POS").toStdString(), "P2", 5}, - {tr("S2").toStdString(), "P3", 6}, - {tr("EXT1").toStdString(), "EXT1", 9}, - {tr("EXT2").toStdString(), "EXT2", 10}, - {tr("EXT3").toStdString(), "EXT3", 11}, - {tr("EXT4").toStdString(), "EXT4", 12}, - {tr("LS").toStdString(), "SL1", 7}, - {tr("RS").toStdString(), "SL2", 8}, - {tr("JSx").toStdString(), "JSx", 13}, - {tr("JSy").toStdString(), "JSy", 14}, - {tr("TltX").toStdString(), "TILT_X", 15}, - {tr("TltY").toStdString(), "TILT_Y", 16}, - }); - } + tbl.insert(tbl.end(), { + {tr("P1").toStdString(), "S1"}, + {tr("P2").toStdString(), "6POS"}, + {tr("P3").toStdString(), "S2"}, + {tr("EXT1").toStdString(), "EXT1"}, + {tr("EXT2").toStdString(), "EXT2"}, + {tr("EXT3").toStdString(), "EXT3"}, + {tr("EXT4").toStdString(), "EXT4"}, + {tr("SL1").toStdString(), "LS"}, + {tr("SL2").toStdString(), "RS"}, + }); } else if (IS_JUMPER_T20(board)) { tbl.insert(tbl.end(), { - {tr("S1").toStdString(), "P1", 4}, - {tr("S2").toStdString(), "P2", 5}, - {tr("S3").toStdString(), "SL1", 6}, - {tr("S4").toStdString(), "SL2", 7}, - {tr("SL").toStdString(), "SL3", 8}, - {tr("SR").toStdString(), "SL4", 9}, + {tr("P1").toStdString(), "P1"}, + {tr("P2").toStdString(), "P2"}, + {tr("SL1").toStdString(), "SL1"}, + {tr("SL2").toStdString(), "SL2"}, + {tr("SL3").toStdString(), "SL3"}, + {tr("SL4").toStdString(), "SL4"}, }); } return tbl; } -QString Boards::getAnalogInputName(Board::Type board, int index) +std::string Boards::getLegacyAnalogMappedInputTag(const char * legacytag, Board::Type board) { - const StringTagMappingTable& lut = getAnalogNamesLookupTable(board); - if (index < (int)lut.size()) - return QString::fromStdString(lut[index].name); - - return CPN_STR_UNKNOWN_ITEM; + return DataHelpers::getStringTagMappingName(getLegacyAnalogsLookupTable(board == Board::BOARD_UNKNOWN ? getCurrentBoard() : board), legacytag); } bool Boards::isBoardCompatible(Type board1, Type board2) @@ -1002,42 +554,6 @@ QString Boards::getBoardName(Board::Type board) return "BETAFPV LR3PRO"; case BOARD_IFLIGHT_COMMANDO8: return "iFlight Commando 8"; - // not supported yet - //case BOARD_FLYSKY_EL18: - // return "FlySky EL18"; - default: - return CPN_STR_UNKNOWN_ITEM; - } -} - -// static -QString Boards::potTypeToString(int value) -{ - switch(value) { - case POT_NONE: - return tr("None"); - case POT_WITH_DETENT: - return tr("Pot with detent"); - case POT_MULTIPOS_SWITCH: - return tr("Multi pos switch"); - case POT_WITHOUT_DETENT: - return tr("Pot without detent"); - case POT_SLIDER_WITH_DETENT: - return tr("slider"); - default: - return CPN_STR_UNKNOWN_ITEM; - } -} - - -// static -QString Boards::sliderTypeToString(int value) -{ - switch(value) { - case SLIDER_NONE: - return tr("None"); - case SLIDER_WITH_DETENT: - return tr("Slider with detent"); default: return CPN_STR_UNKNOWN_ITEM; } @@ -1055,128 +571,28 @@ QString Boards::switchTypeToString(int value) return tr("2 Positions"); case SWITCH_3POS: return tr("3 Positions"); + case SWITCH_FUNC: + return tr("Function"); default: return CPN_STR_UNKNOWN_ITEM; } } -// static -AbstractStaticItemModel * Boards::potTypeItemModel() -{ - AbstractStaticItemModel * mdl = new AbstractStaticItemModel(); - mdl->setName(AIM_BOARDS_POT_TYPE); - - for (int i = 0; i < POT_TYPE_COUNT; i++) { - mdl->appendToItemList(potTypeToString(i), i); - } - - mdl->loadItemList(); - return mdl; -} - -// static -AbstractStaticItemModel * Boards::sliderTypeItemModel() -{ - AbstractStaticItemModel * mdl = new AbstractStaticItemModel(); - mdl->setName(AIM_BOARDS_SLIDER_TYPE); - - for (int i = 0; i < SLIDER_TYPE_COUNT; i++) { - mdl->appendToItemList(sliderTypeToString(i), i); - } - - mdl->loadItemList(); - return mdl; -} - // static AbstractStaticItemModel * Boards::switchTypeItemModel() { AbstractStaticItemModel * mdl = new AbstractStaticItemModel(); mdl->setName(AIM_BOARDS_SWITCH_TYPE); - for (int i = 0; i < SWITCH_TYPE_COUNT; i++) { - mdl->appendToItemList(switchTypeToString(i), i, true, 0, (i < SWITCH_3POS ? SwitchTypeFlag2Pos : SwitchTypeFlag3Pos)); + for (int i = 0; i < SWITCH_FUNC; i++) { // Function not required in lists + mdl->appendToItemList(switchTypeToString(i), i, true, 0, + (i == SWITCH_NOT_AVAILABLE ? SwitchTypeFlagNone : (i < SWITCH_3POS ? SwitchTypeFlag2Pos : SwitchTypeFlag3Pos))); } 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"}, - }); - -if (getCapability(board, Board::NumTrims) > 6) - tbl.insert(tbl.end(), { - {std::to_string(TRIM_SW_T7_INC), "TrimT7Up"}, - {std::to_string(TRIM_SW_T7_DEC), "TrimT7Down"}, - {std::to_string(TRIM_SW_T8_INC), "TrimT8Up"}, - {std::to_string(TRIM_SW_T8_DEC), "TrimT8Down"}, - }); - - 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"}, - }); - - if (getCapability(board, Board::NumTrims) > 6) - tbl.insert(tbl.end(), { - {std::to_string(TRIM_AXIS_T7), "TrimT7"}, - {std::to_string(TRIM_AXIS_T8), "TrimT8"}, - }); - return tbl; -} - QList Boards::getSupportedInternalModules(Board::Type board) { QList modules; @@ -1311,26 +727,189 @@ AbstractStaticItemModel * Boards::externalModuleSizeItemModel() return mdl; } -// EdgeTX 2.10.0 ADC refactor changed order of pots and sliders that affected interpretation of model warnings -// This conversion needs to be revisited when Companion is refactored to use ADC radio defns -// Make ADC orders backwards compatible - -// the values below are based on radio\src\util\hw_defns\pots_config.py - -// static -int Boards::adcPotsBeforeSliders(Board::Type board, SemanticVersion version) +QString Boards::flexTypeToString(int value) { - if (version >= SemanticVersion(CPN_ADC_REFACTOR_VERSION)) { - if (IS_TARANIS_X9(board) || IS_FAMILY_HORUS(board) || IS_FAMILY_T16(board) || IS_RADIOMASTER_BOXER(board)) - return 3; - else if (IS_TARANIS_X9LITE(board)) - return 1; - else if (IS_JUMPER_TLITE(board) || IS_BETAFPV_LR3PRO(board) || IS_IFLIGHT_COMMANDO8(board)) - return 0; - else - return 2; + switch(value) { + case FLEX_NONE: + return tr("None"); + case FLEX_POT: + return tr("Pot"); + case FLEX_POT_CENTER: + return tr("Pot with detent"); + case FLEX_SLIDER: + return tr("Slider"); + case FLEX_MULTIPOS: + return tr("Multipos Switch"); + case FLEX_AXIS_X: + return tr("Axis X"); + case FLEX_AXIS_Y: + return tr("Axis Y"); + case FLEX_SWITCH: + return tr("Switch"); + default: + return CPN_STR_UNKNOWN_ITEM; } - else { - return getCapability(board, Board::Pots); +} + +AbstractStaticItemModel * Boards::flexTypeItemModel() +{ + AbstractStaticItemModel * mdl = new AbstractStaticItemModel(); + mdl->setName(AIM_BOARDS_FLEX_TYPE); + + for (int i = 0; i < FLEX_TYPE_COUNT; i++) { + mdl->appendToItemList(flexTypeToString(i), i, true, 0, (i == (int)FLEX_SWITCH ? FlexTypeFlagSwitch : FlexTypeFlagNotSwitch)); } + + mdl->loadItemList(); + return mdl; +} + +BoardJson* Boards::getBoardJson(Board::Type board) +{ + return gBoardFactories->instance(board == Board::BOARD_UNKNOWN ? getCurrentBoard() : board); +} + +Board::InputInfo Boards::getInputInfo(int index, Board::Type board) +{ + return getBoardJson(board)->getInputInfo(index); +} + +int Boards::getInputIndex(QString val, Board::LookupValueType lvt, Board::Type board) +{ + return getBoardJson(board)->getInputIndex(val, lvt); +} + +QString Boards::getInputName(int index, Board::Type board) +{ + return getBoardJson(board)->getInputName(index); +} + +int Boards::getInputPotIndex(int index, Board::Type board) +{ + return getBoardJson(board)->getInputPotIndex(index); +} + +int Boards::getInputSliderIndex(int index, Board::Type board) +{ + return getBoardJson(board)->getInputSliderIndex(index); +} + +QString Boards::getInputTag(int index, Board::Type board) +{ + return getBoardJson(board)->getInputTag(index); +} + +int Boards::getInputTagOffset(QString tag, Board::Type board) +{ + return getBoardJson(board)->getInputTagOffset(tag); +} + +int Boards::getInputTypeOffset(Board::AnalogInputType type, Board::Type board) +{ + return getBoardJson(board)->getInputTypeOffset(type); +} + +int Boards::getInputYamlIndex(QString val, int ylt, Board::Type board) +{ + return getBoardJson(board)->getInputYamlIndex(val, (BoardJson::YamlLookupType)ylt); +} + +QString Boards::getInputYamlName(int index, int ylt, Board::Type board) +{ + return getBoardJson(board)->getInputYamlName(index, (BoardJson::YamlLookupType)ylt); +} + +int Boards::getInputsCalibrated(Board::Type board) +{ + return getBoardJson(board)->getInputsCalibrated(); +} + +Board::SwitchInfo Boards::getSwitchInfo(int index, Board::Type board) +{ + return getBoardJson(board)->getSwitchInfo(index); +} + +int Boards::getSwitchIndex(QString val, Board::LookupValueType lvt, Board::Type board) +{ + return getBoardJson(board)->getSwitchIndex(val, lvt); +} + +QString Boards::getSwitchName(int index, Board::Type board) +{ + return getBoardJson(board)->getSwitchName(index); +} + +QString Boards::getSwitchTag(int index, Board::Type board) +{ + return getBoardJson(board)->getSwitchTag(index); +} + +int Boards::getSwitchTagNum(int index, Board::Type board) +{ + return getBoardJson(board)->getSwitchTagNum(index); +} + +int Boards::getSwitchYamlIndex(QString val, int ylt, Board::Type board) +{ + return getBoardJson(board)->getSwitchYamlIndex(val, (BoardJson::YamlLookupType)ylt); +} + +QString Boards::getSwitchYamlName(int index, int ylt, Board::Type board) +{ + return getBoardJson(board)->getSwitchYamlName(index, (BoardJson::YamlLookupType)ylt); +} + +int Boards::getTrimYamlIndex(QString val, int ylt, Board::Type board) +{ + return getBoardJson(board)->getTrimYamlIndex(val, (BoardJson::YamlLookupType)ylt); +} + +QString Boards::getTrimYamlName(int index, int ylt, Board::Type board) +{ + return getBoardJson(board)->getTrimYamlName(index, (BoardJson::YamlLookupType)ylt); +} + +bool Boards::isInputAvailable(int index, Board::Type board) +{ + return getBoardJson(board)->isInputAvailable(index); +} + +bool Boards::isInputCalibrated(int index, Board::Type board) +{ + return getBoardJson(board)->isInputCalibrated(index); +} + +bool Boards::isInputConfigurable(int index, Board::Type board) +{ + return getBoardJson(board)->isInputConfigurable(index); +} + +bool Boards::isInputIgnored(int index, Board::Type board) +{ + return getBoardJson(board)->isInputIgnored(index); +} + +bool Boards::isInputPot(int index, Board::Type board) +{ + return getBoardJson(board)->isInputFlexPot(index); +} + +bool Boards::isInputStick(int index, Board::Type board) +{ + return getBoardJson(board)->isInputStick(index); +} + +bool Boards::isSwitchConfigurable(int index, Board::Type board) +{ + return getBoardJson(board)->isSwitchConfigurable(index); +} + +bool Boards::isSwitchFlex(int index, Board::Type board) +{ + return getBoardJson(board)->isSwitchFlex(index); +} + +bool Boards::isSwitchFunc(int index, Board::Type board) +{ + return getBoardJson(board)->isSwitchFunc(index); } diff --git a/companion/src/firmwares/boards.h b/companion/src/firmwares/boards.h index b853436bdfe..d2135dece44 100644 --- a/companion/src/firmwares/boards.h +++ b/companion/src/firmwares/boards.h @@ -27,12 +27,15 @@ class AbstractStaticItemModel; class SemanticVersion; +class BoardJson; +class GeneralSettings; // identiying names of static abstract item models constexpr char AIM_BOARDS_POT_TYPE[] {"boards.pottype"}; constexpr char AIM_BOARDS_SLIDER_TYPE[] {"boards.slidertype"}; constexpr char AIM_BOARDS_SWITCH_TYPE[] {"boards.switchtype"}; constexpr char AIM_BOARDS_MODULE_SIZE[] {"boards.extmodulesize"}; +constexpr char AIM_BOARDS_FLEX_TYPE[] {"boards.flextype"}; // TODO create a Board class with all these functions @@ -104,6 +107,7 @@ namespace Board { SWITCH_TOGGLE, SWITCH_2POS, SWITCH_3POS, + SWITCH_FUNC, SWITCH_TYPE_COUNT }; @@ -149,39 +153,41 @@ namespace Board { }; enum Capability { - Sticks, - Pots, FactoryInstalledPots, - Sliders, - MouseAnalogs, - GyroAnalogs, + FactoryInstalledSwitches, + FlexInputs, + FlexSwitches, + FunctionSwitches, + Gyros, + GyroAxes, + HasAudioMuteGPIO, + HasColorLcd, + HasExternalModuleSupport, + HasInternalModuleSupport, + HasIntModuleHeartbeatGPIO, + HasLedStripGPIO, + HasRTC, + HasSDCard, + HasTrainerModuleCPPM, + HasTrainerModuleSBUS, + HasVBat, MaxAnalogs, + Inputs, + InputSwitches, + Joysticks, + JoystickAxes, MultiposPots, MultiposPotsPositions, - Switches, - FunctionSwitches, - SwitchPositions, NumFunctionSwitchesPositions, - FactoryInstalledSwitches, NumTrims, NumTrimSwitches, - HasRTC, - HasColorLcd, - HasSDCard, - HasInternalModuleSupport, - HasExternalModuleSupport, - HasAudioMuteGPIO, + Pots, + Sliders, SportMaxBaudRate, - HasIntModuleHeartbeatGPIO, - HasTrainerModuleCPPM, - HasTrainerModuleSBUS, - HasLedStripGPIO - }; - - struct SwitchInfo - { - SwitchType config; - QString name; + StandardSwitches, + Sticks, + Switches, + SwitchesPositions, }; struct SwitchPosition { @@ -195,10 +201,12 @@ namespace Board { }; enum SwitchTypeMasks { - SwitchTypeFlag2Pos = 0x01, - SwitchTypeFlag3Pos = 0x02, - SwitchTypeContext2Pos = SwitchTypeFlag2Pos, - SwitchTypeContext3Pos = SwitchTypeFlag2Pos | SwitchTypeFlag3Pos + SwitchTypeFlagNone = 1 << 1, + SwitchTypeFlag2Pos = 1 << 2, + SwitchTypeFlag3Pos = 1 << 3, + SwitchTypeContextNone = SwitchTypeFlagNone, + SwitchTypeContext2Pos = SwitchTypeContextNone | SwitchTypeFlag2Pos, + SwitchTypeContext3Pos = SwitchTypeContext2Pos | SwitchTypeFlag3Pos }; enum ExternalModuleSizes { @@ -209,6 +217,72 @@ namespace Board { EXTMODSIZE_COUNT }; + enum AnalogInputType + { + AIT_NONE, + AIT_STICK, + AIT_FLEX, + AIT_VBAT, + AIT_RTC_BAT, + AIT_SWITCH, + }; + + enum FlexType { + FLEX_NONE = 0, + FLEX_POT, + FLEX_POT_CENTER, + FLEX_SLIDER, + FLEX_MULTIPOS, + FLEX_AXIS_X, + FLEX_AXIS_Y, + FLEX_SWITCH, + FLEX_TYPE_COUNT + }; + + enum FlexTypeMasks { + FlexTypeFlagNotSwitch = 1 << 1, + FlexTypeFlagSwitch = 1 << 2, + FlexTypeContextNoSwitch = FlexTypeFlagNotSwitch, + FlexTypeContextSwitch = FlexTypeContextNoSwitch | FlexTypeFlagSwitch + }; + + enum LookupValueType { + LVT_TAG = 0, + LVT_NAME + }; + + struct InputInfo { + InputInfo() : + type(AIT_NONE), + tag(""), + name(""), + shortName(""), + flexType(FLEX_NONE), + inverted(false) + {} + + AnalogInputType type; + std::string tag; + std::string name; + std::string label; + std::string shortName; + FlexType flexType; + bool inverted; + }; + + struct SwitchInfo { + SwitchInfo() : + type(SWITCH_NOT_AVAILABLE), + tag(""), + name(""), + inverted(false) + {} + + SwitchType type; + std::string tag; + std::string name; + bool inverted; + }; } class Boards @@ -217,10 +291,8 @@ class Boards public: - Boards(Board::Type board) - { - setBoardType(board); - } + Boards(Board::Type board); + virtual ~Boards() {} void setBoardType(const Board::Type & board); Board::Type getBoardType() const { return m_boardType; } @@ -228,43 +300,85 @@ class Boards const uint32_t getFourCC() const { return getFourCC(m_boardType); } const int getEEpromSize() const { return getEEpromSize(m_boardType); } const int getFlashSize() const { return getFlashSize(m_boardType); } - const Board::SwitchInfo getSwitchInfo(int index) const { return getSwitchInfo(m_boardType, index); } const int getCapability(Board::Capability capability) const { return getCapability(m_boardType, capability); } - const QString getAnalogInputName(int index) const { return getAnalogInputName(m_boardType, index); } const bool isBoardCompatible(Board::Type board2) const { return isBoardCompatible(m_boardType, board2); } static uint32_t getFourCC(Board::Type board); 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, const QString strVersion = "0.0.0"); - 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 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 int getDefaultInternalModules(Board::Type board); static int getDefaultExternalModuleSize(Board::Type board); static QString externalModuleSizeToString(int value); static AbstractStaticItemModel * externalModuleSizeItemModel(); - // TODO replace when refactored to support json defns - static int adcPotsBeforeSliders(Board::Type board, SemanticVersion version); - - protected: - - Board::Type m_boardType; + static BoardJson* getBoardJson(Board::Type board = Board::BOARD_UNKNOWN); + + static int getInputsCalibrated(Board::Type board = Board::BOARD_UNKNOWN); + + static Board::InputInfo getInputInfo(int index, Board::Type board = Board::BOARD_UNKNOWN); + static int getInputIndex(QString val, Board::LookupValueType lvt, Board::Type board = Board::BOARD_UNKNOWN); + static QString getInputName(int index, Board::Type board = Board::BOARD_UNKNOWN); + static int getInputPotIndex(int index, Board::Type board = Board::BOARD_UNKNOWN); + static int getInputSliderIndex(int index, Board::Type board = Board::BOARD_UNKNOWN); + static QString getInputTag(int index, Board::Type board = Board::BOARD_UNKNOWN); + static int getInputTagOffset(QString tag, Board::Type board = Board::BOARD_UNKNOWN); + static int getInputTypeOffset(Board::AnalogInputType type, Board::Type board = Board::BOARD_UNKNOWN); + static int getInputYamlIndex(QString val, int ylt, Board::Type board = Board::BOARD_UNKNOWN); + static QString getInputYamlName(int index, int ylt, Board::Type board = Board::BOARD_UNKNOWN); + + static Board::SwitchInfo getSwitchInfo(int index, Board::Type board = Board::BOARD_UNKNOWN); + static int getSwitchIndex(QString val, Board::LookupValueType lvt, Board::Type board = Board::BOARD_UNKNOWN); + static QString getSwitchName(int index, Board::Type board = Board::BOARD_UNKNOWN); + static QString getSwitchTag(int index, Board::Type board = Board::BOARD_UNKNOWN); + static int getSwitchTagNum(int index, Board::Type board = Board::BOARD_UNKNOWN); + static int getSwitchYamlIndex(QString val, int ylt, Board::Type board = Board::BOARD_UNKNOWN); + static QString getSwitchYamlName(int index, int ylt, Board::Type board = Board::BOARD_UNKNOWN); + + static int getTrimYamlIndex(QString val, int ylt, Board::Type board = Board::BOARD_UNKNOWN); + static QString getTrimYamlName(int index, int ylt, Board::Type board = Board::BOARD_UNKNOWN); + + STRINGTAGMAPPINGFUNCS(legacyTrimSourcesLookupTable, LegacyTrimSource); + STRINGTAGMAPPINGFUNCS(trimSwitchesLookupTable, TrimSwitch); + STRINGTAGMAPPINGFUNCS(rawSwitchTypesLookupTable, RawSwitchType); + STRINGTAGMAPPINGFUNCS(rawSourceSpecialTypesLookupTable, RawSourceSpecialType); + STRINGTAGMAPPINGFUNCS(rawSourceCyclicLookupTable, RawSourceCyclic); + + static bool isInputAvailable(int index, Board::Type board = Board::BOARD_UNKNOWN); + static bool isInputCalibrated(int index, Board::Type board = Board::BOARD_UNKNOWN); + static bool isInputConfigurable(int index, Board::Type board = Board::BOARD_UNKNOWN); + static bool isInputIgnored(int index, Board::Type board = Board::BOARD_UNKNOWN); + static bool isInputPot(int index, Board::Type board = Board::BOARD_UNKNOWN); + static bool isInputStick(int index, Board::Type board = Board::BOARD_UNKNOWN); + + static bool isSwitchConfigurable(int index, Board::Type board = Board::BOARD_UNKNOWN); + static bool isSwitchFlex(int index, Board::Type board = Board::BOARD_UNKNOWN); + static bool isSwitchFunc(int index, Board::Type board = Board::BOARD_UNKNOWN); + + static QString flexTypeToString(int value); + static AbstractStaticItemModel * flexTypeItemModel(); + + static std::string getLegacyAnalogMappedInputTag(const char * legacytag, Board::Type board = Board::BOARD_UNKNOWN); + + private: + + Board::Type m_boardType = Board::BOARD_UNKNOWN; + BoardJson* m_boardJson = nullptr; + + const StringTagMappingTable legacyTrimSourcesLookupTable; + const StringTagMappingTable trimSwitchesLookupTable; + const StringTagMappingTable rawSwitchTypesLookupTable; + const StringTagMappingTable rawSourceSpecialTypesLookupTable; + const StringTagMappingTable rawSourceCyclicLookupTable; + + static StringTagMappingTable getLegacyAnalogsLookupTable(Board::Type board = Board::BOARD_UNKNOWN); }; // temporary aliases for transition period, use Boards class instead. diff --git a/companion/src/firmwares/customfunctiondata.cpp b/companion/src/firmwares/customfunctiondata.cpp index 6110e97812d..e1fdf250e1f 100644 --- a/companion/src/firmwares/customfunctiondata.cpp +++ b/companion/src/firmwares/customfunctiondata.cpp @@ -64,7 +64,7 @@ QString CustomFunctionData::funcToString(const AssignFunc func, const ModelData if (func >= FuncOverrideCH1 && func <= FuncOverrideCHLast) return tr("Override %1").arg(RawSource(SOURCE_TYPE_CH, func).toString(model)); else if (func == FuncTrainer) - return tr("Trainer Sticks"); + return tr("Trainer Axis"); else if (func == FuncTrainerRUD) return tr("Trainer RUD"); else if (func == FuncTrainerELE) diff --git a/companion/src/firmwares/datahelpers.cpp b/companion/src/firmwares/datahelpers.cpp index 8dc6237e29a..6af4bd406d2 100644 --- a/companion/src/firmwares/datahelpers.cpp +++ b/companion/src/firmwares/datahelpers.cpp @@ -92,25 +92,48 @@ std::string DataHelpers::getStringTagMappingTag(const StringTagMappingTable& lut return std::string(); } -int DataHelpers::getStringTagMappingSeq(const StringTagMappingTable& lut, unsigned int index) +std::string DataHelpers::getStringNameMappingTag(const StringTagMappingTable& lut, const char * name) { - if (index < lut.size()) - return lut[index].seq; + auto it = + find_if(lut.begin(), lut.end(), [=](const StringTagMapping& elmt) { + if (elmt.name == name) return true; + return false; + }); - return -1; + if (it != lut.end()) { + return it->tag; + } + + return std::string(); } -std::string DataHelpers::getStringSeqMappingTag(const StringTagMappingTable& lut, unsigned int seq) +std::string DataHelpers::getStringTagMappingName(const StringTagMappingTable& lut, const char * tag) { - const auto it = + auto it = find_if(lut.begin(), lut.end(), [=](const StringTagMapping& elmt) { - if (elmt.seq == seq) return true; + if (elmt.tag == tag) return true; return false; }); if (it != lut.end()) { - return it->tag; + return it->name; } return std::string(); } + +QString DataHelpers::getCompositeName(const QString defaultName, const QString customName, const bool prefixCustom) +{ + QString result; + + if (customName.trimmed().isEmpty() || prefixCustom) + result = defaultName; + + if (!customName.trimmed().isEmpty()) { + if (prefixCustom) + result.append(":"); + result.append(customName.trimmed()); + } + + return result; +} diff --git a/companion/src/firmwares/datahelpers.h b/companion/src/firmwares/datahelpers.h index b4512b7ccf9..b59097e6fd2 100644 --- a/companion/src/firmwares/datahelpers.h +++ b/companion/src/firmwares/datahelpers.h @@ -27,23 +27,22 @@ struct StringTagMapping { std::string name; std::string tag; - unsigned int seq; StringTagMapping() = default; StringTagMapping(const char* name) : - name(name), tag(name), seq(0) + name(name), tag(name) { } StringTagMapping(const std::string& name) : - name(name), tag(name), seq(0) + name(name), tag(name) { } - StringTagMapping(const char* name, const char* tag, const unsigned int seq = 0) : - name(name), tag(tag), seq(seq) + StringTagMapping(const char* name, const char* tag) : + name(name), tag(tag) { } - StringTagMapping(const std::string& name, const std::string& tag, const unsigned int seq = 0) : - name(name), tag(tag), seq(seq) + StringTagMapping(const std::string& name, const std::string& tag) : + name(name), tag(tag) { } }; @@ -59,33 +58,14 @@ typedef std::vector StringTagMappingTable; inline std::string name##Tag (unsigned int index) \ { \ return DataHelpers::getStringTagMappingTag(tbl, index); \ - } - -#define STRINGTAGMAPPINGFUNCS_ADC_HELPER(tbl, tbladc, name) \ - STRINGTAGMAPPINGFUNCS_HELPER(tbl, name) \ - \ - inline int name##IndexADC (const char * tag) \ - { \ - return DataHelpers::getStringTagMappingIndex(tbladc, tag); \ - } \ - \ - inline std::string name##TagADC (unsigned int index) \ - { \ - return DataHelpers::getStringTagMappingTag(tbladc, index); \ - } \ - \ - inline int name##SeqADC (unsigned int index) \ - { \ - return DataHelpers::getStringTagMappingSeq(tbladc, index); \ } \ \ - inline std::string name##SeqTagADC (unsigned int seq) \ + inline std::string name##Name (const char * tag) \ { \ - return DataHelpers::getStringSeqMappingTag(tbladc, seq); \ + return DataHelpers::getStringTagMappingName(tbl, tag); \ } #define STRINGTAGMAPPINGFUNCS(tbl, name) STRINGTAGMAPPINGFUNCS_HELPER(tbl, get##name) -#define STRINGTAGMAPPINGFUNCS_ADC(tbl, tbladc, name) STRINGTAGMAPPINGFUNCS_ADC_HELPER(tbl, tbladc, get##name) class FieldRange { @@ -132,6 +112,7 @@ namespace DataHelpers 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); - int getStringTagMappingSeq(const StringTagMappingTable& lut, unsigned int index); - std::string getStringSeqMappingTag(const StringTagMappingTable& lut, unsigned int seq); + std::string getStringNameMappingTag(const StringTagMappingTable& lut, const char * name); + std::string getStringTagMappingName(const StringTagMappingTable& lut, const char * tag); + QString getCompositeName(const QString defaultName, const QString customName, const bool prefixCustom); } diff --git a/companion/src/firmwares/edgetx/yaml_calibdata.cpp b/companion/src/firmwares/edgetx/yaml_calibdata.cpp index 44519e7a079..9677b231f15 100644 --- a/companion/src/firmwares/edgetx/yaml_calibdata.cpp +++ b/companion/src/firmwares/edgetx/yaml_calibdata.cpp @@ -20,39 +20,39 @@ #include "yaml_calibdata.h" #include "eeprominterface.h" +#include "boardjson.h" YamlCalibData::YamlCalibData() { memset(calib, 0, sizeof(calib)); } -YamlCalibData::YamlCalibData(const int* calibMid, const int* calibSpanNeg, - const int* calibSpanPos) +YamlCalibData::YamlCalibData(const GeneralSettings::InputConfig* rhs) { - for (int i = 0; i < CPN_MAX_ANALOGS; i++) { - int seq = getCurrentFirmware()->getAnalogInputSeqADC(i); - if (seq >= 0 && seq < CPN_MAX_ANALOGS) { - calib[seq].mid = calibMid[i]; - calib[seq].spanNeg = calibSpanNeg[i]; - calib[seq].spanPos = calibSpanPos[i]; + for (int i = 0; i < Boards::getCapability(getCurrentBoard(), Board::Inputs); i++) { + if (Boards::isInputCalibrated(i)) { + calib[i].mid = rhs[i].calib.mid; + calib[i].spanNeg = rhs[i].calib.spanNeg; + calib[i].spanPos = rhs[i].calib.spanPos; } } } -void YamlCalibData::copy(int* calibMid, int* calibSpanNeg, - int* calibSpanPos) const +void YamlCalibData::copy(GeneralSettings::InputConfig* rhs) 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; + for (int i = 0; i < Boards::getCapability(getCurrentBoard(), Board::Inputs); i++) { + if (Boards::isInputCalibrated(i)) { + rhs[i].calib.mid = calib[i].mid; + rhs[i].calib.spanNeg = calib[i].spanNeg; + rhs[i].calib.spanPos = calib[i].spanPos; + } } } namespace YAML { -Node convert::encode(const CalibData& rhs) +Node convert::encode(const GeneralSettings::InputCalib& rhs) { Node node; node["mid"] = rhs.mid; @@ -61,7 +61,7 @@ Node convert::encode(const CalibData& rhs) return node; } -bool convert::decode(const Node& node, CalibData& rhs) +bool convert::decode(const Node& node, GeneralSettings::InputCalib& rhs) { if (!node.IsMap()) return false; node["mid"] >> rhs.mid; @@ -73,22 +73,15 @@ bool convert::decode(const Node& node, CalibData& rhs) Node convert::encode(const YamlCalibData& rhs) { Node node; - auto fw = getCurrentFirmware(); - auto board = fw->getBoard(); - const auto* calibIdxLut = fw->getAnalogIndexNamesLookupTableADC(); - const int calibs = Boards::getCapability(board, Board::Sticks) + - Boards::getCapability(board, Board::Pots) + - Boards::getCapability(board, Board::Sliders); - for (int i = 0; i < calibs; i++) { - for (int j = 0; j < (int)calibIdxLut->size(); j++) { - int seq = getCurrentFirmware()->getAnalogInputSeqADC(j); - if (seq == i) { - std::string tag = getCurrentFirmware()->getAnalogInputTagADC(j); - node[tag] = rhs.calib[seq]; - break; - } + const int analogs = Boards::getCapability(getCurrentBoard(), Board::Inputs); + + for (int i = 0; i < analogs; i++) { + if (Boards::isInputCalibrated(i)) { + std::string tag = Boards::getInputYamlName(i, BoardJson::YLT_CONFIG).toStdString(); + node[tag] = rhs.calib[i]; } } + return node; } @@ -99,16 +92,16 @@ bool convert::decode(const Node& node, YamlCalibData& rhs) for (const auto& kv : node) { std::string tag; kv.first >> tag; - int idx = 0; if (radioSettingsVersion < SemanticVersion(QString(CPN_ADC_REFACTOR_VERSION))) - idx = getCurrentFirmware()->getAnalogInputIndex(tag.c_str()); - else - idx = getCurrentFirmware()->getAnalogInputIndexADC(tag.c_str()); + tag = Boards::getLegacyAnalogMappedInputTag(tag.c_str()); + + int idx = Boards::getInputYamlIndex(tag.c_str(), BoardJson::YLT_CONFIG); if (idx >= 0) kv.second >> rhs.calib[idx]; } + return true; } diff --git a/companion/src/firmwares/edgetx/yaml_calibdata.h b/companion/src/firmwares/edgetx/yaml_calibdata.h index be8f379812b..f6cebd68b1f 100644 --- a/companion/src/firmwares/edgetx/yaml_calibdata.h +++ b/companion/src/firmwares/edgetx/yaml_calibdata.h @@ -21,26 +21,20 @@ #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]; + GeneralSettings::InputCalib calib[CPN_MAX_ANALOGS]; YamlCalibData(); - YamlCalibData(const int* calibMid, const int* calibSpanNeg, const int* calibSpanPos); - void copy(int* calibMid, int* calibSpanNeg, int* calibSpanPos) const; + YamlCalibData(const GeneralSettings::InputConfig* rhs); + void copy(GeneralSettings::InputConfig* rhs) const; }; namespace YAML { template <> -struct convert { - static Node encode(const CalibData& rhs); - static bool decode(const Node& node, CalibData& rhs); +struct convert { + static Node encode(const GeneralSettings::InputCalib& rhs); + static bool decode(const Node& node, GeneralSettings::InputCalib& rhs); }; template <> diff --git a/companion/src/firmwares/edgetx/yaml_customfunctiondata.cpp b/companion/src/firmwares/edgetx/yaml_customfunctiondata.cpp index 87f4ec1f931..cc903f40e52 100644 --- a/companion/src/firmwares/edgetx/yaml_customfunctiondata.cpp +++ b/companion/src/firmwares/edgetx/yaml_customfunctiondata.cpp @@ -321,6 +321,11 @@ bool convert::decode(const Node& node, case FuncBacklight: { std::string src_str; getline(def, src_str, ','); + if (def_str.size() >= 4 && def_str.substr(0, 4) == "lua(") { + std::string tmp_str; + getline(def, tmp_str, ','); + src_str += ("," + tmp_str); + } rhs.param = YamlRawSourceDecode(src_str).toValue(); } break; case FuncAdjustGV1: { diff --git a/companion/src/firmwares/edgetx/yaml_generalsettings.cpp b/companion/src/firmwares/edgetx/yaml_generalsettings.cpp index 5172835d767..0543e2b7812 100644 --- a/companion/src/firmwares/edgetx/yaml_generalsettings.cpp +++ b/companion/src/firmwares/edgetx/yaml_generalsettings.cpp @@ -43,7 +43,7 @@ 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_all = e_backlight_mode_keys + e_backlight_mode_sticks, e_backlight_mode_on }; @@ -165,7 +165,7 @@ Node convert::encode(const GeneralSettings& rhs) std::string strboard = fw->getFlavour().toStdString(); node["board"] = strboard; - YamlCalibData calib(rhs.calibMid, rhs.calibSpanNeg, rhs.calibSpanPos); + YamlCalibData calib(rhs.inputConfig); node["calib"] = calib; node["currModel"] = rhs.currModelIndex; @@ -263,49 +263,27 @@ Node convert::encode(const GeneralSettings& rhs) } Node sticksConfig; - sticksConfig = YamlStickConfig(rhs.stickName); + sticksConfig = YamlStickConfig(rhs.inputConfig); if (sticksConfig && sticksConfig.IsMap()) { node["sticksConfig"] = sticksConfig; } + Node potsConfig; + potsConfig = YamlPotConfig(rhs.inputConfig); + if (potsConfig && potsConfig.IsMap()) { + node["potsConfig"] = potsConfig; + } + Node switchConfig; - switchConfig = YamlSwitchConfig(rhs.switchName, rhs.switchConfig); + switchConfig = YamlSwitchConfig(rhs.switchConfig); if (switchConfig && switchConfig.IsMap()) { node["switchConfig"] = switchConfig; } - // TODO revisit when Companion refactored for adc - // adc encoding requires pots and sliders to be merged in a prescribed sequence as defined in radio json - int maxPots = CPN_MAX_POTS + CPN_MAX_SLIDERS; - char potName[maxPots][HARDWARE_NAME_LEN + 1]; - unsigned int potConfig[maxPots]; - - const int sticks = Boards::getCapability(board, Board::Sticks); - int adcoffset = sticks; - int seq = 0; - - for (int i = 0; i < Boards::getCapability(board, Board::Pots); i++) { - seq = getCurrentFirmware()->getAnalogInputSeqADC(adcoffset + i) - sticks; - if (seq >= 0 && seq < maxPots) { - strcpy(potName[seq], rhs.potName[i]); - potConfig[seq] = rhs.potConfig[i]; - } - } - - adcoffset += Boards::getCapability(board, Board::Pots); - - for (int i = 0; i < Boards::getCapability(board, Board::Sliders); i++) { - seq = getCurrentFirmware()->getAnalogInputSeqADC(adcoffset + i) - sticks; - if (seq >= 0 && seq < maxPots) { - strcpy(potName[seq], rhs.sliderName[i]); - potConfig[seq] = ((rhs.sliderConfig[i] == Board::SLIDER_WITH_DETENT) ? Board::POT_SLIDER_WITH_DETENT : Board::POT_NONE); - } - } - - Node potsConfig; - potsConfig = YamlPotConfig(potName, potConfig); - if (potsConfig && potsConfig.IsMap()) { - node["potsConfig"] = potsConfig; + Node flexSwitches; + flexSwitches = YamlSwitchesFlex(rhs.switchConfig); + if (flexSwitches && flexSwitches.IsMap()) { + node["flexSwitches"] = flexSwitches; } node["ownerRegistrationID"] = rhs.registrationId; @@ -323,6 +301,7 @@ Node convert::encode(const GeneralSettings& rhs) // Radio level tabs control (global settings) if (hasColorLcd) node["radioThemesDisabled"] = (int)rhs.radioThemesDisabled; + node["radioGFDisabled"] = (int)rhs.radioGFDisabled; node["radioTrainerDisabled"] = (int)rhs.radioTrainerDisabled; // Model level tabs control (global setting) @@ -389,7 +368,6 @@ bool convert::decode(const Node& node, GeneralSettings& rhs) node["board"] >> flavour; auto fw = getCurrentFirmware(); - auto board = fw->getBoard(); qDebug() << "Settings version:" << rhs.semver << "File flavour:" << flavour.c_str() << "Firmware flavour:" << fw->getFlavour(); @@ -419,7 +397,7 @@ bool convert::decode(const Node& node, GeneralSettings& rhs) YamlCalibData calib; node["calib"] >> calib; - calib.copy(rhs.calibMid, rhs.calibSpanNeg, rhs.calibSpanPos); + calib.copy(rhs.inputConfig); node["currModel"] >> rhs.currModelIndex; node["currModelFilename"] >> rhs.currModelFilename; @@ -547,39 +525,29 @@ bool convert::decode(const Node& node, GeneralSettings& rhs) YamlStickConfig stickConfig; node["sticksConfig"] >> stickConfig; - stickConfig.copy(rhs.stickName); - - YamlSwitchConfig switchConfig; - node["switchConfig"] >> switchConfig; - switchConfig.copy(rhs.switchName, rhs.switchConfig); - - // TODO: revisit when Companion refactored to support adc - // adc pots and sliders decoded into a single array but Compapanion has separate arrays - int maxPots = CPN_MAX_POTS + CPN_MAX_SLIDERS; // must match YamlPotConfig declaration - char potName[maxPots][HARDWARE_NAME_LEN + 1]; - unsigned int potConfig[maxPots]; + stickConfig.copy(rhs.inputConfig); YamlPotConfig potsConfig; node["potsConfig"] >> potsConfig; - potsConfig.copy(potName, potConfig); - - int numPots = Boards::getCapability(board, Board::Pots); + potsConfig.copy(rhs.inputConfig); - for (int i = 0; i < numPots; i++) { - strcpy(rhs.potName[i], potName[i]); - rhs.potConfig[i] = potConfig[i]; - } - - if (radioSettingsVersion < SemanticVersion(QString(CPN_ADC_REFACTOR_VERSION))) { + // for parsing pre v2.10 config - this is not encoded + if (node["slidersConfig"]) { YamlSliderConfig slidersConfig; node["slidersConfig"] >> slidersConfig; - slidersConfig.copy(rhs.sliderName, rhs.sliderConfig); + slidersConfig.copy(rhs.inputConfig); } - else { - for (int i = 0; i < Boards::getCapability(board, Board::Sliders); i++) { - strcpy(rhs.sliderName[i], potName[numPots + i]); - rhs.sliderConfig[i] = ((potConfig[numPots + i] == Board::POT_SLIDER_WITH_DETENT) ? Board::SLIDER_WITH_DETENT : Board::SLIDER_NONE); - } + + YamlSwitchConfig switchConfig; + node["switchConfig"] >> switchConfig; + switchConfig.copy(rhs.switchConfig); + + // MUST be parsed after switchConfig + if (node["flexSwitches"]) { + YamlSwitchesFlex flexSwitches; + node["flexSwitches"] >> flexSwitches; + // merge + flexSwitches.copy(rhs.switchConfig); } node["ownerRegistrationID"] >> rhs.registrationId; @@ -612,6 +580,9 @@ bool convert::decode(const Node& node, GeneralSettings& rhs) node["modelCustomScriptsDisabled"] >> rhs.modelCustomScriptsDisabled; node["modelTelemetryDisabled"] >> rhs.modelTelemetryDisabled; + // fix ups + rhs.validateFlexSwitches(); + return true; } } // namespace YAML diff --git a/companion/src/firmwares/edgetx/yaml_logicalswitchdata.cpp b/companion/src/firmwares/edgetx/yaml_logicalswitchdata.cpp index 9128718c0a0..fad87f41f7d 100644 --- a/companion/src/firmwares/edgetx/yaml_logicalswitchdata.cpp +++ b/companion/src/firmwares/edgetx/yaml_logicalswitchdata.cpp @@ -116,7 +116,7 @@ Node convert::encode(const LogicalSwitchData& rhs) node["delay"] = rhs.delay; node["duration"] = rhs.duration; node["andsw"] = YamlRawSwitchEncode(RawSwitch(rhs.andsw)); - + return node; } @@ -161,6 +161,11 @@ bool convert::decode(const Node& node, case LS_FAMILY_VCOMP: { std::string src_str; getline(def, src_str, ','); + if (def_str.size() >= 4 && def_str.substr(0, 4) == "lua(") { + std::string tmp_str; + getline(def, tmp_str, ','); + src_str += ("," + tmp_str); + } rhs.val1 = YamlRawSourceDecode(src_str).toValue(); getline(def, src_str); rhs.val2 = YamlRawSourceDecode(src_str).toValue(); @@ -178,6 +183,11 @@ bool convert::decode(const Node& node, default: { std::string src_str; getline(def, src_str, ','); + if (def_str.size() >= 4 && def_str.substr(0, 4) == "lua(") { + std::string tmp_str; + getline(def, tmp_str, ','); + src_str += ("," + tmp_str); + } rhs.val1 = YamlRawSourceDecode(src_str).toValue(); def >> rhs.val2; } break; diff --git a/companion/src/firmwares/edgetx/yaml_modeldata.cpp b/companion/src/firmwares/edgetx/yaml_modeldata.cpp index be3bc8f6823..0084071e1e9 100644 --- a/companion/src/firmwares/edgetx/yaml_modeldata.cpp +++ b/companion/src/firmwares/edgetx/yaml_modeldata.cpp @@ -155,40 +155,12 @@ struct YamlThrTrace { } }; -// EdgeTX 2.10.0 ADC refactor changed order of pots and sliders that affected interpretation of model warnings -// This conversion needs to be revisited when Companion is refactored to use ADC radio defns -// Make ADC orders backwards compatible - -// the values below are based on radio\src\util\hw_defns\pots_config.py - -int adcPotsBeforeSliders() -{ - auto board = getCurrentBoard(); - - if (version >= SemanticVersion("2.10.0")) { - if (IS_TARANIS_X9(board) || IS_FAMILY_HORUS(board) || IS_FAMILY_T16(board) || IS_RADIOMASTER_BOXER(board)) - return 3; - else if (IS_TARANIS_X9LITE(board)) - return 1; - else if (IS_JUMPER_TLITE(board) || IS_BETAFPV_LR3PRO(board) || IS_IFLIGHT_COMMANDO8(board)) - return 0; - else - return 2; - } - else { - return Boards::getCapability(board, Board::Pots); - } -} - struct YamlPotsWarnEnabled { unsigned int value; const Board::Type board = getCurrentBoard(); const int maxradio = 8 * (int)(Boards::getCapability(board, Board::HasColorLcd) ? sizeof(uint16_t) : sizeof(uint8_t)); - const int maxcpn = CPN_MAX_POTS + CPN_MAX_SLIDERS; - const int slidersStart = Boards::adcPotsBeforeSliders(board, modelSettingsVersion); - const int numpots = Boards::getCapability(board, Board::Pots); - const int offset = numpots - slidersStart; + const int maxcpn = Boards::getCapability(board, Board::FlexInputs); YamlPotsWarnEnabled() = default; @@ -196,37 +168,17 @@ struct YamlPotsWarnEnabled { { value = 0; - int idx = 0; - - for (int i = 0; i < maxcpn; i++) { - if (i < slidersStart) - idx = i; - else if (i >= numpots) - idx = i - offset; - else - continue; - if (idx >= 0 && idx < maxradio) { - value |= (*(potsWarnEnabled + i)) << idx; - //qDebug() << "i:" << i << "idx:" << idx << "value:" << *(potsWarnEnabled + i); - } + for (int i = 0; i < maxcpn && i < maxradio; i++) { + value |= (*(potsWarnEnabled + i)) << i; } } void toCpn(bool * potsWarnEnabled) { - memset(potsWarnEnabled, 0, sizeof(bool) * maxcpn); - - int idx = 0; - - for (int i = 0; i < maxradio; i++) { - if (i >= slidersStart) - idx = i + offset; - else - idx = i; - if (idx >= 0 && idx <= maxcpn) { - *(potsWarnEnabled + idx) = (bool)((value >> i) & 1); - //qDebug() << "i:" << i << "idx:" << idx << "value:" << (bool)((value >> i) & 1); - } + memset(potsWarnEnabled, 0, sizeof(bool) * CPN_MAX_INPUTS); + + for (int i = 0; i < maxradio && i < maxcpn; i++) { + *(potsWarnEnabled + i) = (bool)((value >> i) & 1); } } }; @@ -234,48 +186,26 @@ struct YamlPotsWarnEnabled { struct YamlBeepANACenter { unsigned int value; - const Board::Type board = getCurrentBoard(); const int maxradio = 8 * (int)sizeof(uint16_t); - const int numstickspots = CPN_MAX_STICKS + Boards::getCapability(board, Board::Pots); - const int maxcpn = numstickspots + getBoardCapability(board, Board::Sliders); - const int slidersStart = CPN_MAX_STICKS + Boards::adcPotsBeforeSliders(board, modelSettingsVersion); - const int offset = numstickspots - slidersStart; + const int maxcpn = 8 * (int)sizeof(unsigned int); YamlBeepANACenter() = default; YamlBeepANACenter(unsigned int beepANACenter) { value = 0; - int idx = 0; - - for (int i = 0; i < maxcpn; i++) { - if (i < slidersStart) - idx = i; - else if (i >= numstickspots) - idx = i - offset; - else - continue; - if (idx >= 0 && idx < maxradio) { - Helpers::setBitmappedValue(value, Helpers::getBitmappedValue(beepANACenter, i), idx); - //qDebug() << "i:" << i << "bit:" << Helpers::getBitmappedValue(beepANACenter, i) << "idx:" << idx << "value:" << value; - } + + for (int i = 0; i < maxcpn && i < maxradio; i++) { + Helpers::setBitmappedValue(value, Helpers::getBitmappedValue(beepANACenter, i), i); } } unsigned int toCpn() { unsigned int beepANACenter = 0; - int idx = 0; - - for (int i = 0; i < maxradio; i++) { - if (i >= slidersStart) - idx = i + offset; - else - idx = i; - if (idx >= 0 && idx < maxcpn) { - Helpers::setBitmappedValue(beepANACenter, Helpers::getBitmappedValue(value, i), idx); - //qDebug() << "i:" << i << "bit:" << Helpers::getBitmappedValue(value, i) << "idx:" << idx << "beepANACenter:" << beepANACenter; - } + + for (int i = 0; i < maxradio && i < maxcpn; i++) { + Helpers::setBitmappedValue(beepANACenter, Helpers::getBitmappedValue(value, i), i); } return beepANACenter; @@ -303,7 +233,7 @@ struct YamlSwitchWarningState { 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); + std::string tag = Boards::getSwitchTag(i).toStdString(); const char *sw = tag.data(); if (tag.size() >= 2 && sw[0] == 'S') { @@ -341,7 +271,7 @@ struct YamlSwitchWarningState { } std::string sw = std::string("S") + (char)c; - int index = getCurrentFirmware()->getSwitchesIndex(sw.c_str()); + int index = Boards::getSwitchIndex(sw.c_str(), Board::LVT_NAME); if (index < 0) { ss.ignore(); continue; @@ -1009,11 +939,11 @@ Node convert::encode(const ModelData& rhs) node["thrTrimSw"] = rhs.thrTrimSwitch; node["potsWarnMode"] = potsWarningModeLut << rhs.potsWarningMode; - node["jitterFilter"] = globalOnOffFilterLut << rhs.jitterFilter; - YamlPotsWarnEnabled potsWarnEnabled(&rhs.potsWarnEnabled[0]); node["potsWarnEnabled"] = potsWarnEnabled.value; + node["jitterFilter"] = globalOnOffFilterLut << rhs.jitterFilter; + 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]; @@ -1123,7 +1053,7 @@ Node convert::encode(const ModelData& rhs) node["functionSwitchStartConfig"] = rhs.functionSwitchStartConfig; node["functionSwitchLogicalState"] = rhs.functionSwitchLogicalState; - for (int i = 0; i < CPN_MAX_FUNCTION_SWITCHES; i++) { + for (int i = 0; i < CPN_MAX_SWITCHES_FUNCTION; i++) { if (strlen(rhs.functionSwitchNames[i]) > 0) { node["switchNames"][std::to_string(i)]["val"] = rhs.functionSwitchNames[i]; } diff --git a/companion/src/firmwares/edgetx/yaml_rawsource.cpp b/companion/src/firmwares/edgetx/yaml_rawsource.cpp index d7a6d065ff3..1ff6d0a1e93 100644 --- a/companion/src/firmwares/edgetx/yaml_rawsource.cpp +++ b/companion/src/firmwares/edgetx/yaml_rawsource.cpp @@ -20,6 +20,7 @@ #include "yaml_rawsource.h" #include "eeprominterface.h" +#include "boardjson.h" static const YamlLookupTable spacemouseLut = { { 0, "SPACEMOUSE_A" }, @@ -33,6 +34,8 @@ static const YamlLookupTable spacemouseLut = { std::string YamlRawSourceEncode(const RawSource& rhs) { + Board::Type board = getCurrentBoard(); + Boards b = Boards(board); std::string src_str; char c = 'A'; switch (rhs.type) { @@ -47,10 +50,10 @@ std::string YamlRawSourceEncode(const RawSource& rhs) src_str += ")"; break; case SOURCE_TYPE_STICK: - src_str = getCurrentFirmware()->getAnalogInputTag(rhs.index); + src_str = Boards::getInputYamlName(rhs.index, BoardJson::YLT_REF).toStdString(); break; case SOURCE_TYPE_TRIM: - src_str = getCurrentFirmware()->getTrimSourcesTag(rhs.index); + src_str = Boards::getTrimYamlName(rhs.index, BoardJson::YLT_REF).toStdString(); break; case SOURCE_TYPE_MIN: src_str += "MIN"; @@ -59,21 +62,15 @@ std::string YamlRawSourceEncode(const RawSource& rhs) src_str += "MAX"; break; case SOURCE_TYPE_SWITCH: - src_str += getCurrentFirmware()->getSwitchesTag(rhs.index); + src_str += Boards::getSwitchYamlName(rhs.index, BoardJson::YLT_REF).toStdString(); break; case SOURCE_TYPE_CUSTOM_SWITCH: src_str += "ls("; src_str += std::to_string(rhs.index + 1); src_str += ")"; break; - case SOURCE_TYPE_FUNCTIONSWITCH: - if (Boards::getCapability(getCurrentBoard(), Board::FunctionSwitches)) { - src_str += "SW"; - src_str += std::to_string(rhs.index + 1); - } - break; case SOURCE_TYPE_CYC: - src_str = getCurrentFirmware()->getRawSourceCyclicTag(rhs.index); + src_str = b.getRawSourceCyclicTag(rhs.index); break; case SOURCE_TYPE_PPM: src_str += "tr("; @@ -91,7 +88,7 @@ std::string YamlRawSourceEncode(const RawSource& rhs) src_str += ")"; break; case SOURCE_TYPE_SPECIAL: - src_str = getCurrentFirmware()->getRawSourceSpecialTypesTag(rhs.index); + src_str = b.getRawSourceSpecialTypeTag(rhs.index); break; case SOURCE_TYPE_TELEMETRY: src_str = "tele("; @@ -122,6 +119,8 @@ std::string YamlRawSourceEncode(const RawSource& rhs) RawSource YamlRawSourceDecode(const std::string& src_str) { + Board::Type board = getCurrentBoard(); + Boards b = Boards(board); RawSource rhs; const char* val = src_str.data(); size_t val_len = src_str.size(); @@ -133,32 +132,19 @@ RawSource YamlRawSourceDecode(const std::string& src_str) 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 = getCurrentFirmware()->getSwitchesIndex(src_str.c_str()); - if (idx >= 0 && idx < CPN_MAX_SWITCHES) { - rhs = RawSource(SOURCE_TYPE_SWITCH, idx); - } else if (IS_JUMPER_TPRO(getCurrentBoard())) { - int numSw = Boards::getCapability(getCurrentBoard(), Board::Switches); - idx = val[1] - 'A'; - idx -= numSw; + } else if ((val_len == 2 && + val[0] == 'S' && + val[1] >= 'A' && val[1] <= 'Z') || + (val_len == 3 && ( + (val[0] == 'F' && val[1] == 'L') || + (val[0] == 'S' && val[1] == 'W')) && + val[2] >= '1' && val[2] <= '9')) { - if(idx >= 0 and idx < Boards::getCapability(getCurrentBoard(), Board::FunctionSwitches)) { - rhs = RawSource(SOURCE_TYPE_FUNCTIONSWITCH, idx); - } + int idx = Boards::getSwitchYamlIndex(src_str.c_str(), BoardJson::YLT_REF); + if (idx >= 0) { + rhs = RawSource(SOURCE_TYPE_SWITCH, idx); } - } else if (val_len == 3 - && val[0] == 'S' - && val[1] == 'W' - && (val[2] >= '1' && val[2] <= '6') - && Boards::getCapability(getCurrentBoard(), Board::FunctionSwitches)) { - // Customisable switches - int idx = val[2] - '1'; - rhs = RawSource(SOURCE_TYPE_FUNCTIONSWITCH, idx); } else if (val_len > 4 && val[0] == 'l' && @@ -185,6 +171,7 @@ RawSource YamlRawSourceDecode(const std::string& src_str) if (ls > 0 && ls <= CPN_MAX_LOGICAL_SWITCHES) rhs = RawSource(SOURCE_TYPE_CUSTOM_SWITCH, ls - 1); + // appears depreciated - maybe early support for T20 as SWn the current std and no match in encode } else if (val_len > 3 && val[0] == 'f' && val[1] == 's' && @@ -193,8 +180,11 @@ RawSource YamlRawSourceDecode(const std::string& src_str) std::stringstream src(src_str.substr(3)); int fs = 0; src >> fs; - if (fs > 0 && fs <= CPN_MAX_FUNCTION_SWITCHES) - rhs = RawSource(SOURCE_TYPE_FUNCTIONSWITCH, fs - 1); + if (fs > 0) { + int fsidx = Boards::getSwitchYamlIndex(QString("SW%1").arg(fs), BoardJson::YLT_REF); + if (fsidx >= 0) + rhs = RawSource(SOURCE_TYPE_SWITCH, fsidx); + } } else if (val_len > 3 && val[0] == 't' && @@ -257,58 +247,73 @@ RawSource YamlRawSourceDecode(const std::string& src_str) } else { YAML::Node node(src_str); + + if (node.IsScalar() && node.as() == "MAX") { + rhs.type = SOURCE_TYPE_MAX; + rhs.index = 0; + return rhs; + } + + if (node.IsScalar() && node.as() == "MIN") { + rhs.type = SOURCE_TYPE_MIN; + rhs.index = 0; + return rhs; + } + std::string ana_str; node >> ana_str; - // 2.8 conversion of GYRO1 and GYRO2 to TILT_X and TILT_Y respectively - if (ana_str.size() == 5) { - if (ana_str.substr(0, 5) == "GYRO1") { - ana_str = "TILT_X"; - } else if (ana_str.substr(0, 5) == "GYRO2") { - ana_str = "TILT_Y"; - } + if (radioSettingsVersion < SemanticVersion(QString(CPN_ADC_REFACTOR_VERSION))) { + ana_str = Boards::getLegacyAnalogMappedInputTag(ana_str.c_str()); + int idx = Boards::getInputIndex(ana_str.c_str(), Board::LVT_TAG); + if (idx >= 0 && Boards::isInputStick(idx)) + ana_str = Boards::getInputName(idx).toStdString(); } - int ana_idx = getCurrentFirmware()->getAnalogInputIndex(ana_str.c_str()); - if (ana_idx < 0) - ana_idx = getCurrentFirmware()->getAnalogInputIndexADC(ana_str.c_str()); + int ana_idx = Boards::getInputYamlIndex(ana_str.c_str(), BoardJson::YLT_REF); if (ana_idx >= 0) { rhs.type = SOURCE_TYPE_STICK; rhs.index = ana_idx; + return rhs; + } + + std::string trim_str; + node >> trim_str; + + if (radioSettingsVersion < SemanticVersion(QString(CPN_ADC_REFACTOR_VERSION))) { + int idx = b.getLegacyTrimSourceIndex(src_str.c_str()); + if (idx >= 0) + trim_str = Boards::getTrimYamlName(idx, BoardJson::YLT_REF).toStdString(); } - int trm_idx = getCurrentFirmware()->getTrimSourcesIndex(src_str.c_str()); + int trm_idx = Boards::getTrimYamlIndex(trim_str.c_str(), BoardJson::YLT_REF); 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; + return rhs; } std::string special_str; node >> special_str; - // 2.10 conversion of TIMERx to Tmrx - if (special_str.size() == 6) { - if (special_str.substr(0, 6) == "TIMER1") { - special_str = "Tmr1"; - } - else if (special_str.substr(0, 6) == "TIMER2") { - special_str = "Tmr2"; - } - else if (special_str.substr(0, 6) == "TIMER3") { - special_str = "Tmr3"; + if (radioSettingsVersion < SemanticVersion(QString(CPN_ADC_REFACTOR_VERSION))) { + if (special_str.size() == 6 && special_str.substr(0, 5) == "TIMER") { + special_str = "Tmr" + special_str.substr(5, 1); } } - int sp_idx = getCurrentFirmware()->getRawSourceSpecialTypesIndex(special_str.c_str()); + int sp_idx = b.getRawSourceSpecialTypeIndex(special_str.c_str()); if (sp_idx >= 0) { rhs.type = SOURCE_TYPE_SPECIAL; rhs.index = sp_idx; + return rhs; + } + + int cyc_idx = b.getRawSourceCyclicIndex(src_str.c_str()); + if (cyc_idx >= 0) { + rhs.type = SOURCE_TYPE_CYC; + rhs.index = cyc_idx; + return rhs; } if (node.IsScalar() && node.as().size() == 12 && node.as().substr(0, 11) == "SPACEMOUSE_") { @@ -317,18 +322,9 @@ RawSource YamlRawSourceDecode(const std::string& src_str) if (sm_idx >= 0) { rhs.type = SOURCE_TYPE_SPACEMOUSE; rhs.index = sm_idx; + return rhs; } } - - if (node.IsScalar() && node.as() == "MIN") { - rhs.type = SOURCE_TYPE_MIN; - rhs.index = 0; - } - - if (node.IsScalar() && node.as() == "MAX") { - rhs.type = SOURCE_TYPE_MAX; - rhs.index = 0; - } } return rhs; diff --git a/companion/src/firmwares/edgetx/yaml_rawswitch.cpp b/companion/src/firmwares/edgetx/yaml_rawswitch.cpp index c5072ce7f7f..e42a26b1852 100644 --- a/companion/src/firmwares/edgetx/yaml_rawswitch.cpp +++ b/companion/src/firmwares/edgetx/yaml_rawswitch.cpp @@ -20,9 +20,12 @@ #include "yaml_rawswitch.h" #include "eeprominterface.h" +#include "boardjson.h" std::string YamlRawSwitchEncode(const RawSwitch& rhs) { + Board::Type board = getCurrentBoard(); + Boards b = Boards(board); std::string sw_str; int32_t sval = rhs.index; if (rhs.index < 0) { @@ -30,11 +33,11 @@ std::string YamlRawSwitchEncode(const RawSwitch& rhs) sw_str += "!"; } - int multiposcnt = Boards::getCapability(getCurrentBoard(), Board::MultiposPotsPositions); + int multiposcnt = Boards::getCapability(board, Board::MultiposPotsPositions); switch (rhs.type) { case SWITCH_TYPE_SWITCH: - sw_str += getCurrentFirmware()->getSwitchesTag((sval - 1) / 3); + sw_str += Boards::getSwitchYamlName((sval - 1) / 3, BoardJson::YLT_REF).toStdString(); sw_str += std::to_string((sval - 1) % 3); break; @@ -43,22 +46,14 @@ std::string YamlRawSwitchEncode(const RawSwitch& rhs) sw_str += std::to_string(sval); break; - case SWITCH_TYPE_FUNCTIONSWITCH: - if (Boards::getCapability(getCurrentBoard(), Board::FunctionSwitches)) { - sw_str += "SW"; - sw_str += std::to_string(1 + ((sval - 1) / 3)); - sw_str += std::to_string((sval - 1) % 3); - } - break; - case SWITCH_TYPE_MULTIPOS_POT: sw_str += "6P"; - sw_str += std::to_string((sval - 1) / multiposcnt); + sw_str += std::to_string((sval - 1) / multiposcnt - Boards::getCapability(board, Board::Sticks)); sw_str += std::to_string((sval - 1) % multiposcnt); break; case SWITCH_TYPE_TRIM: - sw_str += getCurrentFirmware()->getTrimSwitchesTag(sval - 1); + sw_str += b.getTrimSwitchTag(sval - 1); break; case SWITCH_TYPE_FLIGHT_MODE: @@ -72,7 +67,7 @@ std::string YamlRawSwitchEncode(const RawSwitch& rhs) break; default: - sw_str += getCurrentFirmware()->getRawSwitchTypesTag(rhs.type); + sw_str += b.getRawSwitchTypeTag(rhs.type); break; } return sw_str; @@ -80,6 +75,8 @@ std::string YamlRawSwitchEncode(const RawSwitch& rhs) RawSwitch YamlRawSwitchDecode(const std::string& sw_str) { + Board::Type board = getCurrentBoard(); + Boards b = Boards(board); RawSwitch rhs; // constructor sets to SWITCH_TYPE_NONE const char* val = sw_str.data(); size_t val_len = sw_str.size(); @@ -99,7 +96,7 @@ RawSwitch YamlRawSwitchDecode(const std::string& sw_str) sw_str_tmp = sw_str_tmp.substr(1); } - int multiposcnt = Boards::getCapability(getCurrentBoard(), Board::MultiposPotsPositions); + const int multiposcnt = Boards::getCapability(board, Board::MultiposPotsPositions); // TODO: validate all expected numeric chars are numeric not just first @@ -110,12 +107,33 @@ RawSwitch YamlRawSwitchDecode(const std::string& sw_str) rhs = RawSwitch(SWITCH_TYPE_VIRTUAL, sw_idx); } + // format 6Piip where ii = input index - number sticks and p = pos index 0-5 } else if (val_len > 3 && val[0] == '6' && val[1] == 'P' && (val[2] >= '0' && val[2] <= '9') && - (val[3] >= '0' && val[3] < (multiposcnt + '0'))) { + (val[val_len - 1] >= '0' && val[val_len - 1] < (multiposcnt + '0'))) { + + RawSwitchType mp_type = SWITCH_TYPE_MULTIPOS_POT; + int mp_index = 0; + int mp_input_index = 0; - rhs = RawSwitch(SWITCH_TYPE_MULTIPOS_POT, - (val[2] - '0') * multiposcnt + (val[3] - '0') + 1); + try { + mp_input_index = std::stoi(sw_str_tmp.substr(2, val_len - 3)); + + if (radioSettingsVersion < SemanticVersion(QString(CPN_ADC_REFACTOR_VERSION))) { + if (IS_HORUS_X10(board) || IS_FAMILY_T16(board)) { + if (mp_input_index > 2) + mp_input_index += 2; + } + } + + mp_index = (mp_input_index + Boards::getCapability(board, Board::Sticks)) * multiposcnt + (val[val_len - 1] - '0') + 1; + + } catch(...) { + mp_type = SWITCH_TYPE_NONE; + mp_index = 0; + } + + rhs = RawSwitch(mp_type, mp_index); } else if (val_len == 3 && val[0] == 'F' && val[1] == 'M' && (val[2] >= '0' && val[2] <= '9')) { @@ -133,41 +151,29 @@ RawSwitch YamlRawSwitchDecode(const std::string& sw_str) } else if (sw_str_tmp.substr(0, 4) == std::string("Trim")) { - int tsw_idx = getCurrentFirmware()->getTrimSwitchesIndex(sw_str_tmp.c_str()); + int tsw_idx = b.getTrimSwitchIndex(sw_str_tmp.c_str()); if (tsw_idx >= 0) { rhs.type = SWITCH_TYPE_TRIM; rhs.index = tsw_idx + 1; } - } else if (val_len >= 3 && val[0] == 'S' && val[1] == 'W' && - (val[2] >= '1' && val[2] <= '6') && - (val[3] >= '0' && val[3] <= '2') && - Boards::getCapability(getCurrentBoard(), Board::FunctionSwitches)) { - // Customisable switches - int idx = val[2] - '1'; - idx = idx * 3 + (val[3] - '0' + 1); - rhs = RawSwitch(SWITCH_TYPE_FUNCTIONSWITCH, 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); - } else if (IS_JUMPER_TPRO(getCurrentBoard())) { - int numSw = Boards::getCapability(getCurrentBoard(), Board::Switches); - int idx = val[1] - 'A'; - idx = idx - numSw; + } else if ((val_len >= 4 && ( + (val[0] == 'F' && val[1] == 'L') || + (val[0] == 'S' && val[1] == 'W')) && + val[2] >= '1' && val[2] <= '9' && + val[val_len - 1] >= '0' && val[val_len - 1] <= '2') || + (val_len >= 3 && val[0] == 'S' && + val[1] >= 'A' && val[1] <= 'Z' && + val[2] >= '0' && val[2] <= '2')) { - if(idx >= 0 and idx < Boards::getCapability(getCurrentBoard(), Board::FunctionSwitches)) { - idx = idx * 3 + (val[2] - '0' + 1); - rhs = RawSwitch(SWITCH_TYPE_FUNCTIONSWITCH, idx); - } + int sw_idx = Boards::getSwitchYamlIndex(sw_str_tmp.substr(0, val_len - 1).c_str(), BoardJson::YLT_REF); + if (sw_idx >= 0) { + rhs.type = SWITCH_TYPE_SWITCH; + rhs.index = sw_idx * 3 + (val[val_len - 1] - '0' + 1); } } else { - int sw_type = getCurrentFirmware()->getRawSwitchTypesIndex(sw_str_tmp.c_str()); + int sw_type = b.getRawSwitchTypeIndex(sw_str_tmp.c_str()); if (sw_type >= 0) { rhs.type = (RawSwitchType)sw_type; if (rhs.type == SWITCH_TYPE_TELEMETRY || rhs.type == SWITCH_TYPE_TRAINER || rhs.type == SWITCH_TYPE_ACT || rhs.type == SWITCH_TYPE_ONE) diff --git a/companion/src/firmwares/edgetx/yaml_switchconfig.cpp b/companion/src/firmwares/edgetx/yaml_switchconfig.cpp index 0ea5f48df1b..0eeca324ff2 100644 --- a/companion/src/firmwares/edgetx/yaml_switchconfig.cpp +++ b/companion/src/firmwares/edgetx/yaml_switchconfig.cpp @@ -22,6 +22,8 @@ #include "boards.h" #include "eeprominterface.h" +#include "generalsettings.h" +#include "boardjson.h" const YamlLookupTable switchConfigLut = { {Board::SWITCH_NOT_AVAILABLE, "none"}, @@ -30,131 +32,388 @@ const YamlLookupTable switchConfigLut = { {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"}, - {Board::POT_SLIDER_WITH_DETENT, "slider"}, -}; - -const YamlLookupTable slidersLut = { - {0, "LS"}, - {1, "RS"}, + {Board::FLEX_NONE, "none"}, + {Board::FLEX_POT, "without_detent"}, + {Board::FLEX_POT_CENTER, "with_detent"}, + {Board::FLEX_SLIDER, "slider"}, + {Board::FLEX_MULTIPOS, "multipos_switch"}, + {Board::FLEX_AXIS_X, "axis_x"}, + {Board::FLEX_AXIS_Y, "axis_y"}, + {Board::FLEX_SWITCH, "switch"}, }; +// pre v2.10 const YamlLookupTable sliderConfigLut = { {Board::SLIDER_NONE, "none"}, {Board::SLIDER_WITH_DETENT, "with_detent"}, }; -int YamlStickLookup::name2idx(const std::string& name) +// pre v2.10 +const YamlLookupTable sticksLut = { + {0, "Rud"}, + {1, "Ele"}, + {2, "Thr"}, + {3, "Ali"}, +}; + +YamlPotConfig::YamlPotConfig(const GeneralSettings::InputConfig* rhs) { - try { - int idx = std::stoi(name); - if (idx < 4) { - return idx; - } - } catch(...) {} + for (int i = 0; i < Boards::getCapability(getCurrentBoard(), Board::Inputs); i++) { + if (Boards::isInputConfigurable(i)) { + config[i].tag = Boards::getInputYamlName(i, BoardJson::YLT_CONFIG).toStdString(); + config[i].type = rhs[i].type; + memcpy(config[i].name, rhs[i].name, sizeof(HARDWARE_NAME_LEN)); + config[i].flexType = rhs[i].flexType; + config[i].inverted = rhs[i].inverted; + } + } +} - return -1; +void YamlPotConfig::copy(GeneralSettings::InputConfig* rhs) const +{ + for (int i = 0; i < Boards::getCapability(getCurrentBoard(), Board::Inputs); i++) { + if (config[i].type == (unsigned int)Board::AIT_FLEX) { + memcpy(rhs[i].name, config[i].name, sizeof(HARDWARE_NAME_LEN)); + rhs[i].flexType = (Board::FlexType)config[i].flexType; + rhs[i].inverted = config[i].inverted; + } + } } -std::string YamlStickLookup::idx2name(unsigned int idx) +void YamlSliderConfig::copy(GeneralSettings::InputConfig* rhs) const { - if (idx < 4) { - return std::to_string(idx); + for (int i = 0; i < Boards::getCapability(getCurrentBoard(), Board::Inputs); i++) { + if (config[i].type == (unsigned int)Board::AIT_FLEX) { + memcpy(rhs[i].name, config[i].name, sizeof(HARDWARE_NAME_LEN)); + rhs[i].flexType = (Board::FlexType)config[i].flexType; + rhs[i].inverted = config[i].inverted; } + } +} + +YamlStickConfig::YamlStickConfig(const GeneralSettings::InputConfig* rhs) +{ + for (int i = 0; i < Boards::getCapability(getCurrentBoard(), Board::Inputs); i++) { + config[i].tag = std::to_string(i); + config[i].type = rhs[i].type; + memcpy(config[i].name, rhs[i].name, sizeof(HARDWARE_NAME_LEN)); + } +} - return std::string(); +void YamlStickConfig::copy(GeneralSettings::InputConfig* rhs) const +{ + for (int i = 0; i < Boards::getCapability(getCurrentBoard(), Board::Inputs); i++) { + if (config[i].type == (unsigned int)Board::AIT_STICK) { + memcpy(rhs[i].name, config[i].name, sizeof(HARDWARE_NAME_LEN)); + } + } } -int YamlSwitchLookup::name2idx(const std::string& name) +YamlSwitchConfig::YamlSwitchConfig(const GeneralSettings::SwitchConfig* rhs) { - auto fw = getCurrentFirmware(); - int idx = fw->getSwitchesIndex(name.c_str()); - if (idx < 0) return -1; + for (int i = 0; i < Boards::getCapability(getCurrentBoard(), Board::Switches); i++) { + config[i].tag = Boards::getSwitchYamlName(i, BoardJson::YLT_CONFIG).toStdString(); + config[i].type = rhs[i].type; + memcpy(config[i].name, rhs[i].name, sizeof(HARDWARE_NAME_LEN)); + // config[i].inverted = rhs[i].inverted; + } +} - return idx; +void YamlSwitchConfig::copy(GeneralSettings::SwitchConfig* rhs) const +{ + for (int i = 0; i < Boards::getCapability(getCurrentBoard(), Board::Switches); i++) { + if (config[i].type != (unsigned int)Board::SWITCH_NOT_AVAILABLE) { + memcpy(rhs[i].name, config[i].name, sizeof(HARDWARE_NAME_LEN)); + rhs[i].type = (Board::SwitchType)config[i].type; + // rhs[i].inverted = config[i].inverted; + } + } } -std::string YamlSwitchLookup::idx2name(unsigned int idx) +YamlSwitchesFlex::YamlSwitchesFlex(const GeneralSettings::SwitchConfig* rhs) { - auto fw = getCurrentFirmware(); - unsigned int switches = Boards::getCapability(fw->getBoard(), Board::Switches); - if (idx >= switches) return std::string(); + for (int i = 0; i < Boards::getCapability(getCurrentBoard(), Board::Switches); i++) { + if (Boards::isSwitchFlex(i) && rhs[i].inputIdx != SWITCH_INPUTINDEX_NONE) { + int idx = Boards::getSwitchTagNum(i) - 1; + if (idx >= 0 && idx < CPN_MAX_SWITCHES_FLEX) { + config[idx].tag = Boards::getSwitchYamlName(i, BoardJson::YLT_CONFIG).toStdString(); + config[idx].channel = Boards::getInputYamlName(rhs[i].inputIdx, BoardJson::YLT_CONFIG).toStdString(); + } + } + } +} - return fw->getSwitchesTag(idx); +void YamlSwitchesFlex::copy(GeneralSettings::SwitchConfig* rhs) const +{ + for (int i = 0; i < Boards::getCapability(getCurrentBoard(), Board::FlexSwitches); i++) { + int idx = Boards::getSwitchYamlIndex(config[i].tag.c_str(), BoardJson::YLT_CONFIG); + rhs[idx].inputIdx = config[i].inputIndx; + } } -int YamlPotLookup::name2idx(const std::string& name) +namespace YAML { - auto fw = getCurrentFirmware(); - int idx = 0; - if (radioSettingsVersion < SemanticVersion(QString(CPN_ADC_REFACTOR_VERSION))) - idx = fw->getAnalogInputIndex(name.c_str()); +Node convert::encode(const InputConfig& rhs) +{ + Node node; + node["name"] = rhs.name; + + if (rhs.type != Board::AIT_STICK) { + node["type"] = potConfigLut << rhs.flexType; + node["inv"] = (int)rhs.inverted; + } + + return node; +} + +bool convert::decode(const Node& node, InputConfig& rhs) +{ + if (!node.IsMap()) return false; + + node["name"] >> rhs.name; + node["type"] >> potConfigLut >> rhs.flexType; + node["inv"] >> rhs.inverted; + + if (radioSettingsVersion < SemanticVersion(QString(CPN_ADC_REFACTOR_VERSION))) { + int idx = Boards::getInputYamlIndex(rhs.tag.c_str(), BoardJson::YLT_CONFIG); + if (idx >= 0) { + Board::InputInfo info = Boards::getInputInfo(idx); + rhs.inverted = info.inverted; + } else - idx = fw->getAnalogInputIndexADC(name.c_str()); + rhs.inverted = false; + } - if (idx < 0) return idx; + return true; +} - int sticks = Boards::getCapability(fw->getBoard(), Board::Sticks); - if (idx < sticks) return -1; - idx -= sticks; +Node convert::encode(const SwitchConfig& rhs) +{ + Node node; + node["type"] = switchConfigLut << rhs.type; + node["name"] = rhs.name; + // node["inv"] = (int)rhs.inverted; in hwdef json but not implemented in radio yaml + return node; +} + +bool convert::decode(const Node& node, SwitchConfig& rhs) +{ + if (!node.IsMap()) return false; - int pots = Boards::getCapability(fw->getBoard(), Board::Pots); - int sliders = Boards::getCapability(fw->getBoard(), Board::Sliders); - if (idx >= pots + sliders) return -1; + node["type"] >> switchConfigLut >> rhs.type; + node["name"] >> rhs.name; + // node["inv"] >> rhs.inverted; in hwdef json but not implemented in radio yaml - return idx; + if (radioSettingsVersion < SemanticVersion(QString(CPN_ADC_REFACTOR_VERSION))) { + int idx = Boards::getSwitchYamlIndex(rhs.tag.c_str(), BoardJson::YLT_CONFIG); + if (idx >= 0) { + Board::SwitchInfo info = Boards::getSwitchInfo(idx); + rhs.inverted = info.inverted; + } + } + + return true; } -std::string YamlPotLookup::idx2name(unsigned int idx) +Node convert::encode(const SwitchFlex& rhs) { - auto fw = getCurrentFirmware(); - auto board = fw->getBoard(); - unsigned int pots = Boards::getCapability(board, Board::Pots) + Boards::getCapability(board, Board::Sliders); - if (idx >= pots) return std::string(); + Node node; + node["channel"] = rhs.channel; + return node; +} - unsigned int sticks = Boards::getCapability(board, Board::Sticks); - return fw->getAnalogInputSeqTagADC(idx + sticks); +bool convert::decode(const Node& node, SwitchFlex& rhs) +{ + if (!node.IsMap()) return false; + + node["channel"] >> rhs.channel; + rhs.inputIndx = Boards::getInputYamlIndex(rhs.channel.c_str(), BoardJson::YLT_CONFIG); + + return true; +} + +Node convert::encode(const YamlPotConfig& rhs) +{ + Node node; + const int maxcnt = Boards::getCapability(getCurrentBoard(), Board::Inputs); + + for (int i = 0; i < maxcnt; i++) { + if (rhs.config[i].type == (unsigned int)Board::AIT_FLEX && rhs.config[i].flexType != (unsigned int)Board::FLEX_NONE) { + std::string tag = rhs.config[i].tag; + node[tag] = rhs.config[i]; + } + } + + return node; } -int YamlSliderLookup::name2idx(const std::string& name) +bool convert::decode(const Node& node, YamlPotConfig& rhs) { - auto fw = getCurrentFirmware(); - int idx = 0; + if (!node.IsMap()) return false; + + const int maxcnt = Boards::getCapability(getCurrentBoard(), Board::Inputs); + + for (const auto& kv : node) { + std::string tag; + kv.first >> tag; if (radioSettingsVersion < SemanticVersion(QString(CPN_ADC_REFACTOR_VERSION))) - idx = fw->getAnalogInputIndex(name.c_str()); - else - idx = fw->getAnalogInputIndexADC(name.c_str()); + tag = Boards::getLegacyAnalogMappedInputTag(tag.c_str()); - if (idx < 0) return idx; + int idx = Boards::getInputYamlIndex(tag.c_str(), BoardJson::YLT_CONFIG); - int sticks = Boards::getCapability(fw->getBoard(), Board::Sticks); - if (idx < sticks) return -1; - idx -= sticks; + if (idx >= 0 && idx < maxcnt) { + kv.second >> rhs.config[idx]; + rhs.config[idx].tag = tag; + rhs.config[idx].type = Board::AIT_FLEX; + } + } + + return true; +} + +// +bool convert::decode(const Node& node, YamlSliderConfig& rhs) +{ + if (!node.IsMap()) return false; + + const int maxcnt = Boards::getCapability(getCurrentBoard(), Board::Inputs); + + if (Boards::getCapability(getCurrentBoard(), Board::Sliders) < 1) + return true; + + int i = 1; + + for (const auto& kv : node) { + std::string tag; + kv.first >> tag; + int idx = Boards::getInputSliderIndex(i); + + if (idx >= 0 && idx < maxcnt) { + kv.second >> rhs.config[idx]; + rhs.config[idx].tag = Boards::getInputTag(idx).toStdString(); + rhs.config[idx].type = Board::AIT_FLEX; + } + + i++; + } + + return true; +} - int pots = Boards::getCapability(fw->getBoard(), Board::Pots); - if (idx < pots) return -1; - idx -= pots; +Node convert::encode(const YamlStickConfig& rhs) +{ + Node node; + const int maxcnt = Boards::getCapability(getCurrentBoard(), Board::Inputs); - int sliders = Boards::getCapability(fw->getBoard(), Board::Sliders); - if (idx >= sliders) return -1; + for (int i = 0; i < maxcnt; i++) { + if (rhs.config[i].type == (unsigned int)Board::AIT_STICK) { + std::string tag = rhs.config[i].tag; + node[tag] = rhs.config[i]; + } + } - return idx; + return node; } -std::string YamlSliderLookup::idx2name(unsigned int idx) +bool convert::decode(const Node& node, YamlStickConfig& rhs) { - auto fw = getCurrentFirmware(); - unsigned int sliders = Boards::getCapability(fw->getBoard(), Board::Sliders); - if (idx >= sliders) return std::string(); + if (!node.IsMap()) return false; + + const int maxcnt = Boards::getCapability(getCurrentBoard(), Board::Inputs); - unsigned int sticks = Boards::getCapability(fw->getBoard(), Board::Sticks); - unsigned int pots = Boards::getCapability(fw->getBoard(), Board::Pots); - return fw->getAnalogInputTag(idx + pots + sticks); + for (const auto& kv : node) { + std::string tag; + kv.first >> tag; + + if (!tag.empty()) { + int idx = std::stoi(tag); + + if (idx >= 0 && idx < maxcnt) { + kv.second >> rhs.config[idx]; + rhs.config[idx].tag = tag; + rhs.config[idx].type = Board::AIT_STICK; + } + } + } + + return true; } + +Node convert::encode(const YamlSwitchConfig& rhs) +{ + Node node; + const int maxcnt = Boards::getCapability(getCurrentBoard(), Board::Switches); + + for (int i = 0; i < maxcnt; i++) { + if (rhs.config[i].type != Board::SWITCH_NOT_AVAILABLE) { + std::string tag = Boards::getSwitchYamlName(i, BoardJson::YLT_CONFIG).toStdString(); + node[tag] = rhs.config[i]; + } + } + + return node; +} + +bool convert::decode(const Node& node, YamlSwitchConfig& rhs) +{ + if (!node.IsMap()) return false; + + const int maxcnt = Boards::getCapability(getCurrentBoard(), Board::Switches); + + for (const auto& kv : node) { + std::string tag; + kv.first >> tag; + int idx = Boards::getSwitchYamlIndex(tag.c_str(), BoardJson::YLT_CONFIG); + + if (idx >= 0 && idx < maxcnt) { + kv.second >> rhs.config[idx]; + rhs.config[idx].tag = tag; + } + } + + return true; +} + +Node convert::encode(const YamlSwitchesFlex& rhs) +{ + Node node; + const int maxcnt = Boards::getCapability(getCurrentBoard(), Board::FlexSwitches); + + for (int i = 0; i < maxcnt; i++) { + if (!rhs.config[i].tag.empty()) + node[rhs.config[i].tag] = rhs.config[i]; + } + + return node; +} + +bool convert::decode(const Node& node, YamlSwitchesFlex& rhs) +{ + if (!node.IsMap()) return false; + + const int maxcnt = Boards::getCapability(getCurrentBoard(), Board::FlexSwitches); + + for (const auto& kv : node) { + std::string tag; + kv.first >> tag; + + const char* val = tag.data(); + size_t len = tag.size(); + + if (len > 2 && val[0] == 'F' && val[1] == 'L' && val[2] > '0' && val[2] <= '9') { + int idx = std::stoi(tag.substr(2, len - 2)) - 1; + + if (idx >= 0 && idx < maxcnt) { + kv.second >> rhs.config[idx]; + rhs.config[idx].tag = tag; + } + } + } + + return true; +} + +} // namespace YAML diff --git a/companion/src/firmwares/edgetx/yaml_switchconfig.h b/companion/src/firmwares/edgetx/yaml_switchconfig.h index 50d2765ff7b..25f64a58095 100644 --- a/companion/src/firmwares/edgetx/yaml_switchconfig.h +++ b/companion/src/firmwares/edgetx/yaml_switchconfig.h @@ -24,139 +24,65 @@ #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)); +class GeneralSettings; + +#define ENCODE_DECODE_CONFIG(cfgstruct) \ + namespace YAML \ + { \ + template <> \ + struct convert { \ + static Node encode(const cfgstruct& rhs); \ + static bool decode(const Node& node, cfgstruct& rhs); \ + }; \ } -}; - -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)); +#define INPUT_SWITCH_CONFIG(name, cfgsize, cfgstruct, gsstruct) \ + struct name { \ + cfgstruct config[cfgsize]; \ + \ + name() = default; \ + name(const GeneralSettings::gsstruct* rhs); \ + void copy(GeneralSettings::gsstruct* rhs) const; \ + }; \ + \ + namespace YAML \ + { \ + template <> \ + struct convert { \ + static Node encode(const name& rhs); \ + static bool decode(const Node& node, name& rhs); \ + }; \ } - 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)); - } +struct InputConfig { + std::string tag = std::string(); + unsigned int type = 0; + char name[HARDWARE_NAME_LEN + 1] = {'\0'}; + unsigned int flexType = 0; + bool inverted = false; }; -// 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; +ENCODE_DECODE_CONFIG(InputConfig) -// S1: -// type: with_detent -// name: -struct YamlPotLookup { - static int name2idx(const std::string& name); - static std::string idx2name(unsigned int idx); +struct SwitchConfig { + std::string tag = std::string(); + char name[HARDWARE_NAME_LEN + 1] = {'\0'}; + unsigned int type = 0; + bool inverted = false; }; -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; +ENCODE_DECODE_CONFIG(SwitchConfig) -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; - } +struct SwitchFlex { + std::string tag = std::string(); + std::string channel = std::string(); + int inputIndx = SWITCH_INPUTINDEX_NONE; }; -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 +ENCODE_DECODE_CONFIG(SwitchFlex) + +INPUT_SWITCH_CONFIG(YamlPotConfig, CPN_MAX_INPUTS, InputConfig, InputConfig) +INPUT_SWITCH_CONFIG(YamlSliderConfig, CPN_MAX_INPUTS, InputConfig, InputConfig) +INPUT_SWITCH_CONFIG(YamlStickConfig, CPN_MAX_INPUTS, InputConfig, InputConfig) +INPUT_SWITCH_CONFIG(YamlSwitchConfig, CPN_MAX_SWITCHES, SwitchConfig, SwitchConfig) +INPUT_SWITCH_CONFIG(YamlSwitchesFlex, CPN_MAX_SWITCHES_FLEX, SwitchFlex, SwitchConfig) diff --git a/companion/src/firmwares/eeprominterface.cpp b/companion/src/firmwares/eeprominterface.cpp index 54ed8e1c382..8319101f3f3 100644 --- a/companion/src/firmwares/eeprominterface.cpp +++ b/companion/src/firmwares/eeprominterface.cpp @@ -21,6 +21,7 @@ #include "eeprominterface.h" #include "firmwares/opentx/opentxeeprom.h" #include "firmwareinterface.h" +#include "boardfactories.h" #include #include @@ -119,6 +120,21 @@ QString EEPROMInterface::getEepromWarnings(unsigned long errorsFound) * Firmware */ +Firmware::Firmware(Firmware * base, const QString & id, const QString & name, Board::Type board, + const QString & downloadId, const QString & simulatorId, const QString & hwdefnId) : + id(id), + name(name), + board(board), + variantBase(0), + base(base), + eepromInterface(nullptr), + downloadId(downloadId), + simulatorId(simulatorId), + hwdefnId(hwdefnId) +{ + gBoardFactories->registerBoard(board, hwdefnId); +} + // static QVector Firmware::registeredFirmwares; Firmware * Firmware::defaultVariant = nullptr; diff --git a/companion/src/firmwares/eeprominterface.h b/companion/src/firmwares/eeprominterface.h index 665598ae544..22a5af6b38e 100644 --- a/companion/src/firmwares/eeprominterface.h +++ b/companion/src/firmwares/eeprominterface.h @@ -286,29 +286,14 @@ class Firmware typedef QList OptionsList; - explicit Firmware(const QString & id, const QString & name, Board::Type board, const QString & downloadId = QString(), const QString & simulatorId = QString()) : - Firmware(nullptr, id, name, board, downloadId, simulatorId) + explicit Firmware(const QString & id, const QString & name, Board::Type board, const QString & downloadId = QString(), + const QString & simulatorId = QString(), const QString & hwdefnId = QString()) : + Firmware(nullptr, id, name, board, downloadId, simulatorId, hwdefnId) { } - explicit Firmware(Firmware * base, const QString & id, const QString & name, Board::Type board, const QString & downloadId = QString(), const QString & simulatorId = QString()) : - id(id), - name(name), - board(board), - variantBase(0), - base(base), - eepromInterface(nullptr), - downloadId(downloadId), - simulatorId(simulatorId), - analogInputNamesLookupTable(Boards::getAnalogNamesLookupTable(board)), - analogInputNamesLookupTableADC(Boards::getAnalogNamesLookupTable(board, QString(CPN_ADC_REFACTOR_VERSION))), - switchesLookupTable(Boards::getSwitchesLookupTable(board)), - trimSwitchesLookupTable(Boards::getTrimSwitchesLookupTable(board)), - trimSourcesLookupTable(Boards::getTrimSourcesLookupTable(board)), - rawSwitchTypesLookupTable(RawSwitch::getRawSwitchTypesLookupTable()), - rawSourceSpecialTypesLookupTable(RawSource::getSpecialTypesLookupTable()), - rawSourceCyclicLookupTable(RawSource::getCyclicLookupTable()) - { - } + explicit Firmware(Firmware * base, const QString & id, const QString & name, Board::Type board, + const QString & downloadId = QString(), const QString & simulatorId = QString(), + const QString & hwdefnId = QString()); virtual ~Firmware() { } @@ -431,26 +416,9 @@ class Firmware return getFirmwareForId(FIRMWARE_ID_PREFIX + flavour); } - const StringTagMappingTable* getAnalogIndexNamesLookupTable() - { - return &analogInputNamesLookupTable; - } - - const StringTagMappingTable* getAnalogIndexNamesLookupTableADC() - { - return &analogInputNamesLookupTableADC; - } - - STRINGTAGMAPPINGFUNCS_ADC(analogInputNamesLookupTable, analogInputNamesLookupTableADC, AnalogInput); - STRINGTAGMAPPINGFUNCS(switchesLookupTable, Switches); - STRINGTAGMAPPINGFUNCS(trimSwitchesLookupTable, TrimSwitches); - STRINGTAGMAPPINGFUNCS(trimSourcesLookupTable, TrimSources); - STRINGTAGMAPPINGFUNCS(rawSwitchTypesLookupTable, RawSwitchTypes); - STRINGTAGMAPPINGFUNCS(rawSourceSpecialTypesLookupTable, RawSourceSpecialTypes); - STRINGTAGMAPPINGFUNCS(rawSourceCyclicLookupTable, RawSourceCyclic); - const QString getDownloadId() { return getFirmwareBase()->downloadId.isEmpty() ? getFlavour() : getFirmwareBase()->downloadId; } const QString getSimulatorId() { return getFirmwareBase()->simulatorId.isEmpty() ? getId() : getFirmwareBase()->simulatorId; } + const QString getHwDefnId() { return getFirmwareBase()->hwdefnId.isEmpty() ? getFlavour() : getFirmwareBase()->hwdefnId; } protected: QString id; @@ -461,16 +429,7 @@ class Firmware EEPROMInterface * eepromInterface; QString downloadId; QString simulatorId; - - // used by YAML encode and decode - const StringTagMappingTable analogInputNamesLookupTable; - const StringTagMappingTable analogInputNamesLookupTableADC; - const StringTagMappingTable switchesLookupTable; - const StringTagMappingTable trimSwitchesLookupTable; - const StringTagMappingTable trimSourcesLookupTable; - const StringTagMappingTable rawSwitchTypesLookupTable; - const StringTagMappingTable rawSourceSpecialTypesLookupTable; - const StringTagMappingTable rawSourceCyclicLookupTable; + QString hwdefnId; QList languages; //QList ttslanguages; diff --git a/companion/src/firmwares/generalsettings.cpp b/companion/src/firmwares/generalsettings.cpp index 9e7688c99ca..e369d04e60f 100644 --- a/companion/src/firmwares/generalsettings.cpp +++ b/companion/src/firmwares/generalsettings.cpp @@ -32,53 +32,147 @@ const uint8_t chout_ar[] = { // First number is 0..23 -> template setup, Second 4,1,2,3 , 4,1,3,2 , 4,2,1,3 , 4,2,3,1 , 4,3,1,2 , 4,3,2,1 }; -bool GeneralSettings::switchPositionAllowedTaranis(int index) const +bool GeneralSettings::switchPositionAllowed(int index) const { if (index == 0) return true; div_t qr = div(abs(index) - 1, 3); - if (index < 0 && switchConfig[qr.quot] != Board::SWITCH_3POS) + if (index < 0 && switchConfig[qr.quot].type != Board::SWITCH_3POS) return false; else if (qr.rem == 1) - return switchConfig[qr.quot] == Board::SWITCH_3POS; + return switchConfig[qr.quot].type == Board::SWITCH_3POS; else - return switchConfig[qr.quot] != Board::SWITCH_NOT_AVAILABLE; + return switchConfig[qr.quot].type != Board::SWITCH_NOT_AVAILABLE; } -bool GeneralSettings::switchSourceAllowedTaranis(int index) const +bool GeneralSettings::switchSourceAllowed(int index) const { - return switchConfig[index] != Board::SWITCH_NOT_AVAILABLE; + return switchConfig[index].type != Board::SWITCH_NOT_AVAILABLE; } -bool GeneralSettings::isPotAvailable(int index) const +bool GeneralSettings::isInputAvailable(int index) const { - int numPots = Boards::getCapability(getCurrentBoard(), Board::Pots); - if (getCurrentFirmware()->getCapability(HasFlySkyGimbals)) - numPots -= 2; + Board::Type board = getCurrentBoard(); - if (index < 0 || index >= numPots) + if (index < 0 || index >= Boards::getCapability(board, Board::Inputs)) return false; - return potConfig[index] != Board::POT_NONE; + + const InputConfig &config = inputConfig[index]; + + return (config.type == Board::AIT_STICK || + (config.type == Board::AIT_FLEX && config.flexType != Board::FLEX_NONE)); } -bool GeneralSettings::isSliderAvailable(int index) const +bool GeneralSettings::isInputFlexSwitchAvailable(int index) const { - if (index < 0 || index >= Boards::getCapability(getCurrentBoard(), Board::Sliders)) + Board::Type board = getCurrentBoard(); + + if (index < 0 || index >= Boards::getCapability(board, Board::Inputs)) return false; - return sliderConfig[index] != Board::SLIDER_NONE; + + const InputConfig &config = inputConfig[index]; + + return (config.type == Board::AIT_FLEX && config.flexType == Board::FLEX_SWITCH); } -bool GeneralSettings::isMultiPosPot(int index) const +bool GeneralSettings::isInputMultiPosPot(int index) const { - if (isPotAvailable(index)) { - if (potConfig[index] == Board::POT_MULTIPOS_SWITCH) - return true; + if (isInputAvailable(index)) { + const InputConfig &config = inputConfig[index]; + + return (config.type == Board::AIT_FLEX && + config.flexType == Board::FLEX_MULTIPOS); } + return false; } +bool GeneralSettings::isInputPot(int index) const +{ + if (isInputAvailable(index)) { + const InputConfig &config = inputConfig[index]; + + return (config.type == Board::AIT_FLEX && + (config.flexType == Board::FLEX_POT || + config.flexType == Board::FLEX_POT_CENTER || + config.flexType == Board::FLEX_MULTIPOS)); + } + + return false; +} + +bool GeneralSettings::isInputSlider(int index) const +{ + if (isInputAvailable(index)) { + const InputConfig &config = inputConfig[index]; + + return (config.type == Board::AIT_FLEX && + config.flexType == Board::FLEX_SLIDER); + } + return false; +} + +bool GeneralSettings::isInputStick(int index) const +{ + if (isInputAvailable(index)) { + const InputConfig &config = inputConfig[index]; + + return config.type == Board::AIT_STICK; + } + + return false; +} + +// pre v2.10 support +// post refactor clean up - where do we call this from? +bool GeneralSettings::isMultiPosPot(int index) const +{ + return isInputMultiPosPot(Boards::getInputPotIndex(index)); +} + +// pre v2.10 support +// post refactor clean up - where do we call this from? +bool GeneralSettings::isPotAvailable(int index) const +{ + return isInputPot(Boards::getInputPotIndex(index)); +} + +// pre v2.10 support +// post refactor clean up - where do we call this from? +bool GeneralSettings::isSliderAvailable(int index) const +{ + return isInputSlider(Boards::getInputSliderIndex(index)); +} + +bool GeneralSettings::isSwitchAvailable(int index) const +{ + if (index < 0 || index >= Boards::getCapability(getCurrentBoard(), Board::Switches)) + return false; + + const SwitchConfig &config = switchConfig[index]; + + return config.type != Board::SWITCH_NOT_AVAILABLE; +} + +bool GeneralSettings::isSwitchFlex(int index) const +{ + return Boards::isSwitchFlex(index); +} + +bool GeneralSettings::unassignedInputFlexSwitches() const +{ + Board::Type board = getCurrentBoard(); + int cnt = 0; + + for (int i = 0; i < Boards::getCapability(board, Board::Inputs); i++) { + if (inputConfig[i].flexType == Board::FLEX_SWITCH) + cnt++; + } + return cnt < Boards::getCapability(board, Board::FlexSwitches); +} + void GeneralSettings::clear() { memset(reinterpret_cast(this), 0, sizeof(GeneralSettings)); @@ -119,18 +213,6 @@ void GeneralSettings::init() setDefaultControlTypes(board); - for (int i = 0; i < CPN_MAX_ANALOGS; ++i) { - if ((i >= CPN_MAX_STICKS) && (i < CPN_MAX_STICKS + CPN_MAX_POTS) && (potConfig[i-CPN_MAX_STICKS] == Board::POT_MULTIPOS_SWITCH)) { - calibMid[i] = 773;; - calibSpanNeg[i] = 5388; - calibSpanPos[i] = 9758; - } else { - calibMid[i] = 0x200; - calibSpanNeg[i] = 0x180; - calibSpanPos[i] = 0x180; - } - } - backlightMode = 3; // keys and sticks backlightDelay = 2; // 2 * 5 = 10 secs inactivityTimer = 10; @@ -174,7 +256,6 @@ void GeneralSettings::init() stickMode = g.profile[g.sessionId()].defaultMode(); QString t_calib = g.profile[g.sessionId()].stickPotCalib(); - int potsnum = getBoardCapability(getCurrentBoard(), Board::Pots); if (!t_calib.isEmpty()) { QString t_trainercalib=g.profile[g.sessionId()].trainerCalib(); int8_t t_txVoltageCalibration=(int8_t)g.profile[g.sessionId()].txVoltageCalibration(); @@ -188,34 +269,32 @@ void GeneralSettings::init() QString t_SpeakerSet=g.profile[g.sessionId()].speaker(); QString t_CountrySet=g.profile[g.sessionId()].countryCode(); - if ((t_calib.length()==(CPN_MAX_STICKS+potsnum)*12) && (t_trainercalib.length()==16)) { + if ((t_calib.length() == (Boards::getInputsCalibrated() * 12)) && (t_trainercalib.length() == 16)) { QString Byte; int16_t byte16; bool ok; - for (int i=0; i<(CPN_MAX_STICKS+potsnum); i++) { - Byte=t_calib.mid(i*12,4); - byte16=(int16_t)Byte.toInt(&ok,16); - if (ok) - calibMid[i]=byte16; - Byte=t_calib.mid(4+i*12,4); - byte16=(int16_t)Byte.toInt(&ok,16); - if (ok) - calibSpanNeg[i]=byte16; - Byte=t_calib.mid(8+i*12,4); - byte16=(int16_t)Byte.toInt(&ok,16); - if (ok) - calibSpanPos[i]=byte16; + for (int i = 0; i < Boards::getCapability(board, Board::Inputs); i++) { + if (Boards::isInputCalibrated(i)) { + Byte = t_calib.mid(i * 12, 4); + byte16 = (int16_t)Byte.toInt(&ok, 16); + if (ok) inputConfig[i].calib.mid = byte16; + Byte = t_calib.mid(4 + i * 12, 4); + byte16 = (int16_t)Byte.toInt(&ok, 16); + if (ok) inputConfig[i].calib.spanNeg = byte16; + Byte = t_calib.mid(8 + i * 12, 4); + byte16 = (int16_t)Byte.toInt(&ok, 16); + if (ok) inputConfig[i].calib.spanPos = byte16; + } } - for (int i=0; i<4; i++) { - Byte=t_trainercalib.mid(i*4,4); - byte16=(int16_t)Byte.toInt(&ok,16); - if (ok) - trainer.calib[i]=byte16; + for (int i = 0; i < Boards::getCapability(board, Board::Sticks); i++) { + Byte = t_trainercalib.mid(i * 4, 4); + byte16 = (int16_t)Byte.toInt(&ok, 16); + if (ok) trainer.calib[i] = byte16; } - txCurrentCalibration=t_txCurrentCalibration; - txVoltageCalibration=t_txVoltageCalibration; - vBatWarn=t_vBatWarn; - PPM_Multiplier=t_PPM_Multiplier; + txCurrentCalibration = t_txCurrentCalibration; + txVoltageCalibration = t_txVoltageCalibration; + vBatWarn = t_vBatWarn; + PPM_Multiplier = t_PPM_Multiplier; stickMode = t_stickMode; } if ((t_DisplaySet.length()==6) && (t_BeeperSet.length()==4) && (t_HapticSet.length()==6) && (t_SpeakerSet.length()==6)) { @@ -278,76 +357,37 @@ void GeneralSettings::init() void GeneralSettings::setDefaultControlTypes(Board::Type board) { - for (int i=0; i= CPN_MAX_STICKS) return -1; else - return chout_ar[4*templateSetup + channel] - 1; + return chout_ar[4 * templateSetup + channel] - 1; } RawSource GeneralSettings::getDefaultSource(unsigned int channel) const @@ -370,7 +410,7 @@ RawSource GeneralSettings::getDefaultSource(unsigned int channel) const int GeneralSettings::getDefaultChannel(unsigned int stick) const { - for (int i=0; i<4; i++){ + for (int i = 0; i < 4; i++){ if (getDefaultStick(i) == (int)stick) return i; } @@ -383,10 +423,8 @@ void GeneralSettings::convert(RadioDataConversionState & cstate) cstate.setOrigin(tr("Radio Settings")); - setDefaultControlTypes(cstate.toType); // start with default switches/pots/sliders - - cstate.setComponent("Hardware"); - cstate.setItemType("Int. Module"); + cstate.setComponent(tr("Hardware")); + cstate.setSubComp(tr("Internal Module")); RadioDataConversionState::LogField oldData(internalModule, ModuleData::typeToString(internalModule)); if (internalModule != MODULE_TYPE_NONE && (int)internalModule != g.currentProfile().defaultInternalModule()) { @@ -394,66 +432,97 @@ void GeneralSettings::convert(RadioDataConversionState & cstate) cstate.setInvalid(oldData); } - // Try to intelligently copy any custom control names - - // SE and SG are skipped on X7 board - if (IS_TARANIS_X7(cstate.toType)) { - if (IS_TARANIS_X9(cstate.fromType) || IS_FAMILY_HORUS_OR_T16(cstate.fromType)) { - strncpy(switchName[4], switchName[5], sizeof(switchName[4])); - strncpy(switchName[5], switchName[7], sizeof(switchName[5])); - } - } - else if (IS_TARANIS_X7(cstate.fromType)) { - if (IS_TARANIS_X9(cstate.toType) || IS_FAMILY_HORUS_OR_T16(cstate.toType)) { - strncpy(switchName[5], switchName[4], sizeof(switchName[5])); - strncpy(switchName[7], switchName[5], sizeof(switchName[7])); - } - } - - if (IS_FAMILY_T12(cstate.toType)) { - if (IS_TARANIS_X9(cstate.fromType) || IS_FAMILY_HORUS_OR_T16(cstate.fromType)) { - strncpy(switchName[4], switchName[5], sizeof(switchName[0])); - strncpy(switchName[5], switchName[7], sizeof(switchName[0])); - } - } - - else if (IS_FAMILY_T12(cstate.fromType)) { - if (IS_TARANIS_X9(cstate.toType) || IS_FAMILY_HORUS_OR_T16(cstate.toType)) { - strncpy(switchName[5], switchName[4], sizeof(switchName[0])); - strncpy(switchName[7], switchName[5], sizeof(switchName[0])); + // Try to intelligently copy any custom controls + // step 1 clear current config + memset(&inputConfig[0], '0', sizeof(InputConfig) * CPN_MAX_INPUTS); + memset(&switchConfig[0], '0', sizeof(SwitchConfig) * CPN_MAX_SWITCHES); + // step 2 load default config + setDefaultControlTypes(cstate.toType); + // step 3 copy matching config based on tags + cstate.setSubComp(tr("Axis & Pots")); + + for (int i = 0; i < Boards::getCapability(cstate.fromType, Board::Inputs); i++) { + if (Boards::isInputConfigurable(i, cstate.fromType)) { + cstate.setItemType(Boards::isInputStick(i, cstate.fromType) ? tr("Axis") : tr("Pot")); + RadioDataConversionState::LogField oldData(i, Boards::getInputName(i, cstate.fromType)); + const int idx = Boards::getInputIndex(Boards::getInputTag(i, cstate.fromType), Board::LVT_TAG, cstate.toType); + + if (idx > -1) { + const InputConfig &fromcfg = cstate.fromGS()->inputConfig[i]; + InputConfig &tocfg = inputConfig[idx]; + strncpy(tocfg.name, fromcfg.name, sizeof(inputConfig[0].name)); + tocfg.type = fromcfg.type; + + if (tocfg.type == Board::AIT_FLEX && !Boards::getCapability(cstate.toType, Board::FlexSwitches) && + fromcfg.flexType == Board::FLEX_SWITCH) { + cstate.withComponentField(Boards::getInputName(i, cstate.fromType)); + RadioDataConversionState::LogField oldFT(i, Boards::flexTypeToString(fromcfg.flexType)); + tocfg.flexType = Board::FLEX_NONE; + cstate.setConverted(oldFT, RadioDataConversionState::LogField(i, Boards::flexTypeToString(tocfg.flexType))); + } + else + tocfg.flexType = fromcfg.flexType; + + tocfg.inverted = fromcfg.inverted; + // do not copy calibration - use defaults as safer + } + else if (cstate.fromGS()->inputConfig[i].type == Board::AIT_FLEX && cstate.fromGS()->inputConfig[i].flexType != Board::FLEX_NONE) { + cstate.setInvalid(oldData); + } } } - // LS and RS sliders are after 2 aux sliders on X12 and X9E - if ((IS_HORUS_X12S(cstate.toType) || IS_TARANIS_X9E(cstate.toType)) && !IS_HORUS_X12S(cstate.fromType) && !IS_TARANIS_X9E(cstate.fromType)) { - strncpy(sliderName[0], sliderName[2], sizeof(sliderName[0])); - strncpy(sliderName[1], sliderName[3], sizeof(sliderName[1])); - } - else if (!IS_TARANIS_X9E(cstate.toType) && !IS_HORUS_X12S(cstate.toType) && (IS_HORUS_X12S(cstate.fromType) || IS_TARANIS_X9E(cstate.fromType))) { - strncpy(sliderName[2], sliderName[0], sizeof(sliderName[2])); - strncpy(sliderName[3], sliderName[1], sizeof(sliderName[3])); - } - - if (IS_FAMILY_HORUS_OR_T16(cstate.toType)) { - // 6P switch is only on Horus (by default) - if (cstate.fromBoard.getCapability(Board::FactoryInstalledPots) == 2) { - strncpy(potName[2], potName[1], sizeof(potName[2])); - potName[1][0] = '\0'; + cstate.setSubComp(tr("Switches")); + + for (int i = 0; i < Boards::getCapability(cstate.fromType, Board::Switches); i++) { + if (Boards::isSwitchConfigurable(i, cstate.fromType)) { + cstate.setItemType(Boards::isSwitchFlex(i, cstate.fromType) ? tr("Flex Switch") : + Boards::isSwitchFunc(i, cstate.fromType) ? tr("Function Switch") : tr("Switch")); + RadioDataConversionState::LogField oldData(i, Boards::getSwitchName(i, cstate.fromType)); + const int idx = Boards::getSwitchIndex(Boards::getSwitchTag(i, cstate.fromType), Board::LVT_TAG, cstate.toType); + + if (idx > -1) { + const SwitchConfig &fromcfg = cstate.fromGS()->switchConfig[i]; + SwitchConfig &tocfg = switchConfig[idx]; + strncpy(tocfg.name, fromcfg.name, sizeof(switchConfig[0].name)); + + if (Boards::getSwitchInfo(i, cstate.fromType).type > Boards::getSwitchInfo(idx, cstate.toType).type) { + cstate.withComponentField(Boards::getSwitchName(i, cstate.fromType)); + RadioDataConversionState::LogField oldSWT(i, Boards::switchTypeToString(fromcfg.type)); + tocfg.type = Board::SWITCH_NOT_AVAILABLE; + cstate.setConverted(oldSWT, RadioDataConversionState::LogField(i, Boards::switchTypeToString(fromcfg.type))); + } + else + tocfg.type = fromcfg.type; + + tocfg.inverted = fromcfg.inverted; + + if (fromcfg.inputIdx != SWITCH_INPUTINDEX_NONE) { + if (!Boards::getCapability(cstate.toType, Board::FlexSwitches) || + Boards::getInputIndex(Boards::getInputTag(fromcfg.inputIdx, cstate.fromType), Board::LVT_TAG, cstate.toType) < 0) { + cstate.withComponentField(Boards::getSwitchName(i, cstate.fromType)); + RadioDataConversionState::LogField oldFT(i, Boards::getInputName(fromcfg.inputIdx, cstate.fromType)); + tocfg.inputIdx = SWITCH_INPUTINDEX_NONE; + cstate.setConverted(oldFT, RadioDataConversionState::LogField(i, tr("None"))); + } + else + tocfg.inputIdx = fromcfg.inputIdx; + } + } + else if (cstate.fromGS()->switchConfig[i].type != Board::SWITCH_NOT_AVAILABLE) { + cstate.setInvalid(oldData); + } } } if (IS_TARANIS(cstate.toType)) { - // No S3 pot on Taranis boards by default - if (cstate.fromBoard.getCapability(Board::FactoryInstalledPots) > 2) - strncpy(potName[1], potName[2], sizeof(potName[1])); - contrast = qBound(getCurrentFirmware()->getCapability(MinContrast), contrast, getCurrentFirmware()->getCapability(MaxContrast)); } // TODO: Would be nice at this point to have GUI pause and ask the user to set up any custom hardware they have on the destination radio. // Convert all global functions (do this after HW adjustments) - for (int i=0; i= 0) { + inputConfig[idx].type = Board::AIT_FLEX; + strncpy(inputConfig[idx].name, potName[i], HARDWARE_NAME_LEN); + int ft = std::stoi(DataHelpers::getStringTagMappingTag(potTypesConversionTable, potConfig[i])); + if (ft > -1) + inputConfig[idx].flexType = (Board::FlexType)ft; + } + } + + for (int i = 0; i < CPN_MAX_SLIDERS && i < Boards::getCapability(board, Board::Sliders); i++) { + int idx = Boards::getInputSliderIndex(i, board); + if (idx >= 0) { + inputConfig[idx].type = Board::AIT_FLEX; + strncpy(inputConfig[idx].name, sliderName[i], HARDWARE_NAME_LEN); + int ft = std::stoi(DataHelpers::getStringTagMappingTag(sliderTypesConversionTable, sliderConfig[i])); + if (ft > -1) + inputConfig[idx].flexType = (Board::FlexType)ft; + } + } + + for (int i = 0; i < CPN_MAX_ANALOGS && i < Boards::getInputsCalibrated(board); i++) { + inputConfig[i].calib.mid = calibMid[i]; + inputConfig[i].calib.spanNeg = calibSpanNeg[i]; + inputConfig[i].calib.spanPos = calibSpanPos[i]; + } + + for (int i = 0; i < CPN_MAX_SWITCHES && i < Boards::getCapability(board, Board::Switches); i++) { + switchConfig[i].type = (Board::SwitchType)swtchConfig[i]; + strncpy(switchConfig[i].name, swtchName[i], HARDWARE_NAME_LEN); + } + + return true; +} + +void GeneralSettings::validateFlexSwitches() +{ + for (int i = 0; i < CPN_MAX_SWITCHES_FLEX; i++) { + if (inputConfig[switchConfig[i].inputIdx].flexType != Board::FLEX_SWITCH) + switchConfig[i].inputIdx = -1; + + int idx = Boards::getSwitchIndex(QString("FL%1").arg(i), Board::LVT_TAG); + if (idx >= 0) { + if (switchConfig[idx].type == Board::SWITCH_NOT_AVAILABLE) + switchConfig[i].inputIdx = -1; + } + } +} + /* TrainerMix */ diff --git a/companion/src/firmwares/generalsettings.h b/companion/src/firmwares/generalsettings.h index 8e2d6a2f6e3..36e22c88556 100644 --- a/companion/src/firmwares/generalsettings.h +++ b/companion/src/firmwares/generalsettings.h @@ -103,6 +103,7 @@ constexpr int TTS_LANGUAGE_LEN {2}; constexpr int HARDWARE_NAME_LEN {3}; constexpr int REGISTRATION_ID_LEN {8}; constexpr int SELECTED_THEME_NAME_LEN {26}; +constexpr int SWITCH_INPUTINDEX_NONE {-1}; class GeneralSettings { Q_DECLARE_TR_FUNCTIONS(GeneralSettings) @@ -200,9 +201,6 @@ class GeneralSettings { char semver[8 + 1]; unsigned int version; unsigned int variant; - int calibMid[CPN_MAX_ANALOGS]; - int calibSpanNeg[CPN_MAX_ANALOGS]; - int calibSpanPos[CPN_MAX_ANALOGS]; unsigned int currModelIndex; char currModelFilename[CURR_MODEL_FILENAME_LEN + 1]; unsigned int contrast; @@ -287,13 +285,6 @@ class GeneralSettings { unsigned int backlightColor; bool modelQuickSelect; CustomFunctionData customFn[CPN_MAX_SPECIAL_FUNCTIONS]; - 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_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]; char registrationId[REGISTRATION_ID_LEN + 1]; int gyroMax; @@ -319,11 +310,74 @@ class GeneralSettings { bool modelCustomScriptsDisabled; bool modelTelemetryDisabled; - bool switchPositionAllowedTaranis(int index) const; - bool switchSourceAllowedTaranis(int index) const; + // v 2.10 ADC refactor + // earlier version data is read into legacy structs to maintain older version compatibility + // post reading the legacy structs are manipulated into the new structs + // An opportunity was taken group related structs + // Companion gui only references the new structs + + // pre v2.10 legacy + // TODO remove when importing and conversion no longer neceesary + int calibMid[CPN_MAX_ANALOGS]; + int calibSpanNeg[CPN_MAX_ANALOGS]; + int calibSpanPos[CPN_MAX_ANALOGS]; + char swtchName[CPN_MAX_SWITCHES][HARDWARE_NAME_LEN + 1]; + unsigned int swtchConfig[CPN_MAX_SWITCHES]; + char stickName[CPN_MAX_STICKS][HARDWARE_NAME_LEN + 1]; + 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]; + + // =================================================================================== + // IMPORTANT: starting v2.10 this function MUST be called after importing non-yaml formats + // yaml conversion is performed on the fly + bool convertLegacyConfiguration(Board::Type board); + // =================================================================================== + + // default values are retrieved from the radio json file + + struct InputCalib { + int mid; + int spanNeg; + int spanPos; + }; + + struct InputConfig { + Board::AnalogInputType type; + char name[HARDWARE_NAME_LEN + 1]; + Board::FlexType flexType; + bool inverted; + InputCalib calib; + }; + + InputConfig inputConfig[CPN_MAX_INPUTS]; + + struct SwitchConfig { + char name[HARDWARE_NAME_LEN + 1]; + Board::SwitchType type; + bool inverted; + int inputIdx; // used if switch tag = FLn, value -1 = none selected + }; + + SwitchConfig switchConfig[CPN_MAX_SWITCHES]; + + bool switchPositionAllowed(int index) const; + bool switchSourceAllowed(int index) const; + + bool isInputAvailable(int index) const; + bool isInputMultiPosPot(int index) const; + bool isInputPot(int index) const; + bool isInputSlider(int index) const; + bool isInputStick(int index) const; + bool isInputFlexSwitchAvailable(int index) const; bool isPotAvailable(int index) const; bool isSliderAvailable(int index) const; + bool isSwitchAvailable(int index) const; + bool isSwitchFlex(int index) const; bool isMultiPosPot(int index) const; + bool unassignedInputFlexSwitches() const; + QString antennaModeToString() const; QString bluetoothModeToString() const; QString serialPortModeToString(int port_nr) const; @@ -347,4 +401,6 @@ class GeneralSettings { static AbstractStaticItemModel * stickDeadZoneItemModel(); static AbstractStaticItemModel * uartSampleModeItemModel(); static AbstractStaticItemModel * hatsModeItemModel(bool radio_setup = true); + + void validateFlexSwitches(); }; diff --git a/companion/src/firmwares/modeldata.cpp b/companion/src/firmwares/modeldata.cpp index b8a7ee96b94..e5cdcdb73e5 100644 --- a/companion/src/firmwares/modeldata.cpp +++ b/companion/src/firmwares/modeldata.cpp @@ -387,25 +387,28 @@ int ModelData::getChannelsMax(bool forceExtendedLimits) const } bool ModelData::isFunctionSwitchPositionAvailable(int index) const - { - if (index == 0) - return true; +{ + if (index == 0) + return true; - div_t qr = div(abs(index) - 1, 3); - int fs = getFuncSwitchConfig(qr.quot); + div_t qr = div(abs(index) - 1, 3); + int fs = getFuncSwitchConfig(qr.quot); - if (qr.rem == 1) { - return false; - } - else { - return fs != Board::SWITCH_NOT_AVAILABLE; - } - } + if (qr.rem == 1) { + return false; + } + else { + return fs != Board::SWITCH_NOT_AVAILABLE; + } +} - bool ModelData::isFunctionSwitchSourceAllowed(int index) const - { - return (int)getFuncSwitchConfig(index) != Board::SWITCH_NOT_AVAILABLE; - } +bool ModelData::isFunctionSwitchSourceAllowed(int index) const +{ + if (index >= 0 && index < Boards::getCapability(getCurrentBoard(), Board::FunctionSwitches)) + return (int)getFuncSwitchConfig(index) != Board::SWITCH_NOT_AVAILABLE; + + return false; +} bool ModelData::isAvailable(const RawSwitch & swtch) const @@ -421,9 +424,6 @@ bool ModelData::isAvailable(const RawSwitch & swtch) const else if (swtch.type == SWITCH_TYPE_SENSOR) { return strlen(sensorData[index].label) > 0; } - else if (swtch.type == SWITCH_TYPE_FUNCTIONSWITCH) { - return isFunctionSwitchPositionAvailable(index + 1); - } else { return true; } @@ -1500,15 +1500,14 @@ QString ModelData::thrTraceSrcToString() const QString ModelData::thrTraceSrcToString(const int index) const { - Firmware * firmware = getCurrentFirmware(); - const Boards board = Boards(getCurrentBoard()); - const int pscnt = board.getCapability(Board::Pots) + board.getCapability(Board::Sliders); + const Board::Type board = getCurrentBoard(); + const int pscnt = Boards::getCapability(board, Board::Pots) + Boards::getCapability(board, Board::Sliders); if (index == 0) return tr("THR"); else if (index <= pscnt) - return board.getAnalogInputName(index + board.getCapability(Board::Sticks) - 1); - else if (index <= pscnt + firmware->getCapability(Outputs)) + return Boards::getInputName(index + Boards::getCapability(board, Board::Sticks) - 1, board); + else if (index <= pscnt + getCurrentFirmware()->getCapability(Outputs)) return RawSource(SOURCE_TYPE_CH, index - pscnt - 1).toString(this); return QString(CPN_STR_UNKNOWN_ITEM); @@ -1516,18 +1515,18 @@ QString ModelData::thrTraceSrcToString(const int index) const int ModelData::thrTraceSrcCount() const { - const Boards board = Boards(getCurrentBoard()); Firmware * firmware = getCurrentFirmware(); + const Board::Type board = firmware->getBoard(); - return 1 + board.getCapability(Board::Pots) + board.getCapability(Board::Sliders) + firmware->getCapability(Outputs); + return 1 + Boards::getCapability(board, Board::Pots) + Boards::getCapability(board, Board::Sliders) + firmware->getCapability(Outputs); } bool ModelData::isThrTraceSrcAvailable(const GeneralSettings * generalSettings, const int index) const { - const Boards board = Boards(getCurrentBoard()); + const Board::Type board = getCurrentBoard(); - if (index > 0 && index <= board.getCapability(Board::Pots) + board.getCapability(Board::Sliders)) - return RawSource(SOURCE_TYPE_STICK, index + board.getCapability(Board::Sticks) - 1).isAvailable(this, generalSettings, board.getBoardType()); + if (index > 0 && index <= Boards::getCapability(board, Board::Pots) + Boards::getCapability(board, Board::Sliders)) + return RawSource(SOURCE_TYPE_STICK, index + Boards::getCapability(board, Board::Sticks) - 1).isAvailable(this, generalSettings, board); else return true; } @@ -1705,7 +1704,7 @@ AbstractStaticItemModel * ModelData::trainerModeItemModel(const GeneralSettings unsigned int ModelData::getFuncSwitchConfig(unsigned int index) const { - if (index < CPN_MAX_FUNCTION_SWITCHES) + if (index < CPN_MAX_SWITCHES_FUNCTION) return Helpers::getBitmappedValue(functionSwitchConfig, index, 2); else return FUNC_SWITCH_CONFIG_NONE; @@ -1713,7 +1712,7 @@ AbstractStaticItemModel * ModelData::trainerModeItemModel(const GeneralSettings void ModelData::setFuncSwitchConfig(unsigned int index, unsigned int value) { - if (index < CPN_MAX_FUNCTION_SWITCHES) + if (index < CPN_MAX_SWITCHES_FUNCTION) Helpers::setBitmappedValue(functionSwitchConfig, value, index, 2); } @@ -1748,7 +1747,7 @@ AbstractStaticItemModel * ModelData::trainerModeItemModel(const GeneralSettings unsigned int ModelData::getFuncSwitchGroup(unsigned int index) const { - if (index < CPN_MAX_FUNCTION_SWITCHES) + if (index < CPN_MAX_SWITCHES_FUNCTION) return Helpers::getBitmappedValue(functionSwitchGroup, index, 2); else return 0; @@ -1756,13 +1755,13 @@ AbstractStaticItemModel * ModelData::trainerModeItemModel(const GeneralSettings void ModelData::setFuncSwitchGroup(unsigned int index, unsigned int value) { - if (index < CPN_MAX_FUNCTION_SWITCHES) + if (index < CPN_MAX_SWITCHES_FUNCTION) Helpers::setBitmappedValue(functionSwitchGroup, value, index, 2); } unsigned int ModelData::getFuncSwitchAlwaysOnGroup(unsigned int index) const { - if (index < CPN_MAX_FUNCTION_SWITCHES) { + if (index < CPN_MAX_SWITCHES_FUNCTION) { unsigned int grp = getFuncSwitchGroup(index); unsigned int switchcnt = Boards::getCapability(getCurrentFirmware()->getBoard(), Board::FunctionSwitches); return Helpers::getBitmappedValue(functionSwitchGroup, grp, 1, 2 * switchcnt); @@ -1773,7 +1772,7 @@ AbstractStaticItemModel * ModelData::trainerModeItemModel(const GeneralSettings void ModelData::setFuncSwitchAlwaysOnGroup(unsigned int index, unsigned int value) { - if (index < CPN_MAX_FUNCTION_SWITCHES) { + if (index < CPN_MAX_SWITCHES_FUNCTION) { unsigned int grp = getFuncSwitchGroup(index); unsigned int switchcnt = Boards::getCapability(getCurrentFirmware()->getBoard(), Board::FunctionSwitches); Helpers::setBitmappedValue(functionSwitchGroup, value, grp, 1, 2 * switchcnt); @@ -1782,7 +1781,7 @@ AbstractStaticItemModel * ModelData::trainerModeItemModel(const GeneralSettings unsigned int ModelData::getFuncSwitchStart(unsigned int index) const { - if (index < CPN_MAX_FUNCTION_SWITCHES) + if (index < CPN_MAX_SWITCHES_FUNCTION) return Helpers::getBitmappedValue(functionSwitchStartConfig, index, 2); else return FUNC_SWITCH_START_INACTIVE; @@ -1790,7 +1789,7 @@ AbstractStaticItemModel * ModelData::trainerModeItemModel(const GeneralSettings void ModelData::setFuncSwitchStart(unsigned int index, unsigned int value) { - if (index < CPN_MAX_FUNCTION_SWITCHES) + if (index < CPN_MAX_SWITCHES_FUNCTION) Helpers::setBitmappedValue(functionSwitchStartConfig, value, index, 2); } diff --git a/companion/src/firmwares/modeldata.h b/companion/src/firmwares/modeldata.h index ec65605f511..80f220dc4ce 100644 --- a/companion/src/firmwares/modeldata.h +++ b/companion/src/firmwares/modeldata.h @@ -163,8 +163,8 @@ class ModelData { unsigned int switchWarningEnable; unsigned int thrTrimSwitch; unsigned int potsWarningMode; - bool potsWarnEnabled[CPN_MAX_POTS + CPN_MAX_SLIDERS]; - int potsWarnPosition[CPN_MAX_POTS + CPN_MAX_SLIDERS]; + bool potsWarnEnabled[CPN_MAX_INPUTS]; + int potsWarnPosition[CPN_MAX_INPUTS]; bool displayChecklist; GVarData gvarData[CPN_MAX_GVARS]; @@ -230,7 +230,7 @@ class ModelData { unsigned int functionSwitchGroup; unsigned int functionSwitchStartConfig; unsigned int functionSwitchLogicalState; - char functionSwitchNames[CPN_MAX_FUNCTION_SWITCHES][HARDWARE_NAME_LEN + 1]; + char functionSwitchNames[CPN_MAX_SWITCHES_FUNCTION][HARDWARE_NAME_LEN + 1]; // Custom USB joytsick mapping unsigned int usbJoystickExtMode; diff --git a/companion/src/firmwares/opentx/opentxeeprom.cpp b/companion/src/firmwares/opentx/opentxeeprom.cpp index b7c44f0988e..ce52b4aad49 100644 --- a/companion/src/firmwares/opentx/opentxeeprom.cpp +++ b/companion/src/firmwares/opentx/opentxeeprom.cpp @@ -69,11 +69,11 @@ inline int MAX_SWITCHES_SOURCE(Board::Type board, int version) inline int MAX_SWITCHES_POSITION(Board::Type board, int version) { if (IS_JUMPER_TPRO(board)) - return Boards::getCapability(board, Board::SwitchPositions); + return Boards::getCapability(board, Board::SwitchesPositions); else if (IS_HORUS_OR_TARANIS(board)) return MAX_SWITCHES(board, version) * 3; else - return Boards::getCapability(board, Board::SwitchPositions); + return Boards::getCapability(board, Board::SwitchesPositions); } inline int MAX_FUNCTIONSWITCHES(Board::Type board, int version) @@ -196,7 +196,7 @@ inline int MAX_GYRO_ANALOGS(Board::Type board, int version) return 0; } - return Boards::getCapability(board, Board::GyroAnalogs); + return Boards::getCapability(board, Board::GyroAxes); } #define MAX_ROTARY_ENCODERS(board) 0 @@ -3173,7 +3173,7 @@ OpenTxGeneralData::OpenTxGeneralData(GeneralSettings & generalData, Board::Type if (IS_FAMILY_HORUS_OR_T16(board)) { for (int i=0; i(this, generalData.switchConfig[i])); + internalField.Append(new UnsignedField<2>(this, generalData.swtchConfig[i])); else internalField.Append(new SpareBitsField<2>(this)); } @@ -3231,9 +3231,9 @@ OpenTxGeneralData::OpenTxGeneralData(GeneralSettings & generalData, Board::Type if (IS_FAMILY_HORUS_OR_T16(board)) { for (int i = 0; i < MAX_SWITCHES(board, version); ++i) { if (version >= 220) - internalField.Append(new CharField<3>(this, generalData.switchName[i], "Switch name")); + internalField.Append(new CharField<3>(this, generalData.swtchName[i], "Switch name")); else - internalField.Append(new ZCharField<3>(this, generalData.switchName[i], "Switch name")); + internalField.Append(new ZCharField<3>(this, generalData.swtchName[i], "Switch name")); } for (int i = 0; i < CPN_MAX_STICKS; ++i) { if (version >= 220) @@ -3261,15 +3261,15 @@ OpenTxGeneralData::OpenTxGeneralData(GeneralSettings & generalData, Board::Type else if (IS_TARANIS(board)) { for (int i = 0; i < SWITCHES_CONFIG_SIZE(board, version) / 2; i++) { if (i < MAX_SWITCHES(board, version)) - internalField.Append(new UnsignedField<2>(this, generalData.switchConfig[i])); + internalField.Append(new UnsignedField<2>(this, generalData.swtchConfig[i])); else internalField.Append(new SpareBitsField<2>(this)); } for (int i = 0; i < MAX_SWITCHES(board, version); ++i) { if (version >= 220) - internalField.Append(new CharField<3>(this, generalData.switchName[i], "Switch name")); + internalField.Append(new CharField<3>(this, generalData.swtchName[i], "Switch name")); else - internalField.Append(new ZCharField<3>(this, generalData.switchName[i], "Switch name")); + internalField.Append(new ZCharField<3>(this, generalData.swtchName[i], "Switch name")); } for (int i = 0; i < CPN_MAX_STICKS; ++i) { if (version >= 220) diff --git a/companion/src/firmwares/opentx/opentxinterface.cpp b/companion/src/firmwares/opentx/opentxinterface.cpp index 192fb4c32b7..ca9b74a2a44 100644 --- a/companion/src/firmwares/opentx/opentxinterface.cpp +++ b/companion/src/firmwares/opentx/opentxinterface.cpp @@ -840,11 +840,6 @@ QString OpenTxFirmware::getCapabilityStr(::Capability capability) } } -QString OpenTxFirmware::getAnalogInputName(unsigned int index) -{ - return Boards::getAnalogInputName(board, index); -} - QTime OpenTxFirmware::getMaxTimerStart() { if (IS_HORUS_OR_TARANIS(board)) @@ -1501,22 +1496,22 @@ void registerOpenTxFirmwares() registerOpenTxFirmware(firmware); addOpenTxRfOptions(firmware, FLEX + AFHDS2A + AFHDS3); - /* 9XR-Pro */ - firmware = new OpenTxFirmware(FIRMWAREID("9xrpro"), Firmware::tr("Turnigy 9XR-PRO"), BOARD_9XRPRO); - addOpenTxArm9xOptions(firmware, false); - registerOpenTxFirmware(firmware, true); - - /* ar9x board */ - 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(FIRMWAREID("sky9x"), Firmware::tr("9X with Sky9x board"), BOARD_SKY9X); - addOpenTxArm9xOptions(firmware); - registerOpenTxFirmware(firmware, true); +// /* 9XR-Pro */ +// firmware = new OpenTxFirmware(FIRMWAREID("9xrpro"), Firmware::tr("Turnigy 9XR-PRO"), BOARD_9XRPRO); +// addOpenTxArm9xOptions(firmware, false); +// registerOpenTxFirmware(firmware, true); +// +// /* ar9x board */ +// 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(FIRMWAREID("sky9x"), Firmware::tr("9X with Sky9x board"), BOARD_SKY9X); +// addOpenTxArm9xOptions(firmware); +// registerOpenTxFirmware(firmware, true); Firmware::sortRegisteredFirmwares(); Firmware::setDefaultVariant(Firmware::getFirmwareForFlavour("tx16s")); diff --git a/companion/src/firmwares/opentx/opentxinterface.h b/companion/src/firmwares/opentx/opentxinterface.h index c4e64d26b64..086450e3898 100644 --- a/companion/src/firmwares/opentx/opentxinterface.h +++ b/companion/src/firmwares/opentx/opentxinterface.h @@ -88,13 +88,15 @@ class OpenTxFirmware: public Firmware public: OpenTxFirmware(const QString & id, OpenTxFirmware * parent): - Firmware(parent, id, parent->getName(), parent->getBoard(), parent->getDownloadId(), parent->getSimulatorId()) + Firmware(parent, id, parent->getName(), parent->getBoard(), + parent->getDownloadId(), parent->getSimulatorId(), parent->getHwDefnId()) { setEEpromInterface(parent->getEEpromInterface()); } - OpenTxFirmware(const QString & id, const QString & name, const Board::Type board, const QString & downloadId = QString(), const QString & simulatorId = QString()): - Firmware(id, name, board, downloadId, simulatorId) + OpenTxFirmware(const QString & id, const QString & name, const Board::Type board, + const QString & downloadId = QString(), const QString & simulatorId = QString(), const QString & hwdefnId = QString()): + Firmware(id, name, board, downloadId, simulatorId, hwdefnId) { // Note: these align with the radio NOT computer locales - TODO harmonise with ISO and one list!!! addLanguage("en"); @@ -131,7 +133,11 @@ class OpenTxFirmware: public Firmware virtual QString getCapabilityStr(Capability); - virtual QString getAnalogInputName(unsigned int index); + virtual QString getAnalogInputName(unsigned int index) + { + qDebug() << "WARNING: Depreciate function called. Always returns empty string!"; + return QString(); + } virtual QTime getMaxTimerStart(); diff --git a/companion/src/firmwares/rawsource.cpp b/companion/src/firmwares/rawsource.cpp index fd6936930b0..62c8e9ebc4e 100644 --- a/companion/src/firmwares/rawsource.cpp +++ b/companion/src/firmwares/rawsource.cpp @@ -126,7 +126,7 @@ RawSourceRange RawSource::getRange(const ModelData * model, const GeneralSetting return result; } -QString RawSource::toString(const ModelData * model, const GeneralSettings * const generalSettings, Board::Type board) const +QString RawSource::toString(const ModelData * model, const GeneralSettings * const generalSettings, Board::Type board, bool prefixCustomName) const { if (board == Board::BOARD_UNKNOWN) { board = getCurrentBoard(); @@ -146,12 +146,14 @@ QString RawSource::toString(const ModelData * model, const GeneralSettings * con static const QString rotary[] = { tr("REa"), tr("REb") }; - if (index<0) { + if (index < 0) { return QString(CPN_STR_UNKNOWN_ITEM); } QString result; - int genAryIdx = 0; + QString dfltName; + QString custName; + switch (type) { case SOURCE_TYPE_NONE: return QString(CPN_STR_NONE_ITEM); @@ -168,17 +170,10 @@ QString RawSource::toString(const ModelData * model, const GeneralSettings * con return tr("LUA%1%2").arg(index / 16 + 1).arg(QChar('a' + index % 16)); case SOURCE_TYPE_STICK: - if (generalSettings) { - if (isPot(&genAryIdx)) - result = QString(generalSettings->potName[genAryIdx]); - else if (isSlider(&genAryIdx)) - result = QString(generalSettings->sliderName[genAryIdx]); - else if (isStick(&genAryIdx)) - result = QString(generalSettings->stickName[genAryIdx]); - } - if (result.trimmed().isEmpty()) - result = Boards::getAnalogInputName(board, index); - return result; + dfltName = Boards::getInputName(index, board); + if (generalSettings) + custName = QString(generalSettings->inputConfig[index].name).trimmed(); + return DataHelpers::getCompositeName(dfltName, custName, prefixCustomName); case SOURCE_TYPE_TRIM: return (Boards::getCapability(board, Board::NumTrims) == 2 ? CHECK_IN_ARRAY(trims2, index) : CHECK_IN_ARRAY(trims, index)); @@ -193,18 +188,20 @@ QString RawSource::toString(const ModelData * model, const GeneralSettings * con return tr("MAX"); case SOURCE_TYPE_SWITCH: - if (generalSettings) - result = QString(generalSettings->switchName[index]).trimmed(); - if (result.isEmpty()) - result = Boards::getSwitchInfo(board, index).name; - return result; + dfltName = Boards::getSwitchInfo(index, board).name.c_str(); + if (Boards::isSwitchFunc(index, board)) { + if (model) { + int fsindex = Boards::getSwitchTagNum(index, board) - 1; + custName = QString(model->functionSwitchNames[fsindex]).trimmed(); + } + } + else { + if (generalSettings) { + custName = QString(generalSettings->switchConfig[index].name).trimmed(); + } + } - case SOURCE_TYPE_FUNCTIONSWITCH: - if (model) - result = QString(model->functionSwitchNames[index]).trimmed(); - if (result.isEmpty()) - result = tr("SW%1").arg(index + 1); - return result; + return DataHelpers::getCompositeName(dfltName, custName, prefixCustomName); case SOURCE_TYPE_CUSTOM_SWITCH: return RawSwitch(SWITCH_TYPE_VIRTUAL, index + 1).toString(); @@ -217,15 +214,16 @@ QString RawSource::toString(const ModelData * model, const GeneralSettings * con case SOURCE_TYPE_CH: if (model) - return model->limitData[index].nameToString(index); - else + result = QString(model->limitData[index].nameToString(index)).trimmed(); + if (result.isEmpty()) return LimitData().nameToString(index); + return result; case SOURCE_TYPE_SPECIAL: if (index >= SOURCE_TYPE_SPECIAL_FIRST_TIMER && index <= SOURCE_TYPE_SPECIAL_LAST_TIMER) { if (model) - result = model->timers[index - SOURCE_TYPE_SPECIAL_FIRST_TIMER].nameToString(index - SOURCE_TYPE_SPECIAL_FIRST_TIMER); - else + result = QString(model->timers[index - SOURCE_TYPE_SPECIAL_FIRST_TIMER].nameToString(index - SOURCE_TYPE_SPECIAL_FIRST_TIMER)).trimmed(); + if (result.isEmpty()) result = TimerData().nameToString(index - SOURCE_TYPE_SPECIAL_FIRST_TIMER); } else @@ -237,8 +235,8 @@ QString RawSource::toString(const ModelData * model, const GeneralSettings * con { div_t qr = div(index, 3); if (model) - result = model->sensorData[qr.quot].nameToString(qr.quot); - else + result = QString(model->sensorData[qr.quot].nameToString(qr.quot)).trimmed(); + if (result.isEmpty()) result = SensorData().nameToString(qr.quot); if (qr.rem) result += (qr.rem == 1 ? "-" : "+"); @@ -247,9 +245,10 @@ QString RawSource::toString(const ModelData * model, const GeneralSettings * con case SOURCE_TYPE_GVAR: if (model) - return model->gvarData[index].nameToString(index); - else - return GVarData().nameToString(index); + result = QString(model->gvarData[index].nameToString(index)).trimmed(); + if (result.isEmpty()) + result = GVarData().nameToString(index); + return result; case SOURCE_TYPE_SPACEMOUSE: return tr("sm%1").arg(QChar('A' + index)); @@ -259,46 +258,12 @@ QString RawSource::toString(const ModelData * model, const GeneralSettings * con } } -bool RawSource::isStick(int * stickIndex, Board::Type board) const +bool RawSource::isStick(Board::Type board) const { if (board == Board::BOARD_UNKNOWN) board = getCurrentBoard(); if (type == SOURCE_TYPE_STICK && index < Boards::getCapability(board, Board::Sticks)) { - if (stickIndex) - *stickIndex = index; - return true; - } - return false; -} - -bool RawSource::isPot(int * potsIndex, Board::Type board) const -{ - if (board == Board::BOARD_UNKNOWN) - board = getCurrentBoard(); - - Boards b(board); - if (type == SOURCE_TYPE_STICK && - index >= b.getCapability(Board::Sticks) && - index < b.getCapability(Board::Sticks) + b.getCapability(Board::Pots)) { - if (potsIndex) - *potsIndex = index - b.getCapability(Board::Sticks); - return true; - } - return false; -} - -bool RawSource::isSlider(int * sliderIndex, Board::Type board) const -{ - if (board == Board::BOARD_UNKNOWN) - board = getCurrentBoard(); - - Boards b(board); - if (type == SOURCE_TYPE_STICK && - index >= b.getCapability(Board::Sticks) + b.getCapability(Board::Pots) && - index < b.getCapability(Board::Sticks) + b.getCapability(Board::Pots) + b.getCapability(Board::Sliders)) { - if (sliderIndex) - *sliderIndex = index - b.getCapability(Board::Sticks) - b.getCapability(Board::Pots); return true; } return false; @@ -316,16 +281,12 @@ bool RawSource::isAvailable(const ModelData * const model, const GeneralSettings Boards b(board); - if (type == SOURCE_TYPE_STICK && index >= b.getCapability(Board::MaxAnalogs)) + if (type == SOURCE_TYPE_STICK && index >= b.getCapability(Board::Inputs)) return false; if (type == SOURCE_TYPE_SWITCH && index >= b.getCapability(Board::Switches)) return false; - if (type == SOURCE_TYPE_FUNCTIONSWITCH) - if (!model || index >= b.getCapability(Board::FunctionSwitches)) - return false; - if (type == SOURCE_TYPE_SPECIAL && index >= SOURCE_TYPE_SPECIAL_FIRST_RESERVED && index <= SOURCE_TYPE_SPECIAL_LAST_RESERVED) return false; @@ -334,7 +295,8 @@ bool RawSource::isAvailable(const ModelData * const model, const GeneralSettings model->timers[index - SOURCE_TYPE_SPECIAL_FIRST_TIMER].isModeOff()) return false; - if (type == SOURCE_TYPE_FUNCTIONSWITCH && !model->isFunctionSwitchSourceAllowed(index)) + if (type == SOURCE_TYPE_SWITCH && b.isSwitchFunc(index, board) && + !model->isFunctionSwitchSourceAllowed(b.getSwitchTagNum(index, board) - 1)) return false; if (type == SOURCE_TYPE_VIRTUAL_INPUT && !model->isInputValid(index)) @@ -357,13 +319,25 @@ bool RawSource::isAvailable(const ModelData * const model, const GeneralSettings } if (gs) { - int gsIdx = 0; - if (type == SOURCE_TYPE_STICK && ((isPot(&gsIdx) && !gs->isPotAvailable(gsIdx)) || (isSlider(&gsIdx) && !gs->isSliderAvailable(gsIdx)))) - return false; + if (type == SOURCE_TYPE_STICK) { + if (!gs->isInputAvailable(index)) + return false; + if (gs->inputConfig[index].flexType == Board::FLEX_SWITCH) + return false; + } - if (type == SOURCE_TYPE_SWITCH && IS_HORUS_OR_TARANIS(board) && !gs->switchSourceAllowedTaranis(index)) + if (type == SOURCE_TYPE_SWITCH && !b.isSwitchFunc(index, board) && IS_HORUS_OR_TARANIS(board) && + !gs->switchSourceAllowed(index)) return false; } + else { + if (type == SOURCE_TYPE_STICK) { + if (!Boards::isInputAvailable(index, board)) + return false; + if (Boards::getInputInfo(index, board).flexType == Board::FLEX_SWITCH) + return false; + } + } if (type == SOURCE_TYPE_TRIM && index >= b.getCapability(Board::NumTrims)) return false; @@ -380,81 +354,22 @@ bool RawSource::isAvailable(const ModelData * const model, const GeneralSettings RawSource RawSource::convert(RadioDataConversionState & cstate) { cstate.setItemType(tr("SRC"), 1); - RadioDataConversionState::EventType evt = RadioDataConversionState::EVT_NONE; RadioDataConversionState::LogField oldData(index, toString(cstate.fromModel(), cstate.fromGS(), cstate.fromType)); - if (type == SOURCE_TYPE_STICK) { - QStringList fromStickList(getStickList(cstate.fromBoard)); - QStringList toStickList(getStickList(cstate.toBoard)); - if (oldData.id < fromStickList.count()) - index = toStickList.indexOf(fromStickList.at(oldData.id)); - else - index = -1; - // perform forced mapping - } - - if (type == SOURCE_TYPE_SWITCH) { - QStringList fromSwitchList(getSwitchList(cstate.fromBoard)); - QStringList toSwitchList(getSwitchList(cstate.toBoard)); - // index set to -1 if no match found - if (oldData.id < fromSwitchList.count()) - index = toSwitchList.indexOf(fromSwitchList.at(oldData.id)); - else - index = -1; - // perform forced mapping - if (index < 0) { - if (IS_TARANIS_X7(cstate.toType) && (IS_TARANIS_X9(cstate.fromType) || IS_FAMILY_HORUS_OR_T16(cstate.fromType))) { - // No SE and SG on X7 board - index = toSwitchList.indexOf("SD"); - if (index >= 0) - evt = RadioDataConversionState::EVT_CVRT; - } - else if (IS_FAMILY_T12(cstate.toType) && (IS_TARANIS_X9(cstate.fromType) || IS_FAMILY_HORUS_OR_T16(cstate.fromType))) { - // No SE and SG on T12 board - index = toSwitchList.indexOf("SD"); - if (index >= 0) - evt = RadioDataConversionState::EVT_CVRT; - } - } - } + if (type == SOURCE_TYPE_STICK) + index = Boards::getInputIndex(Boards::getInputTag(oldData.id, cstate.fromType), Board::LVT_TAG, cstate.toType); + else if (type == SOURCE_TYPE_SWITCH) + index = Boards::getSwitchIndex(Boards::getSwitchTag(oldData.id, cstate.fromType), Board::LVT_TAG, cstate.toType); // final validation (we do not pass model to isAvailable() because we don't know what has or hasn't been converted) - if (index < 0 || !isAvailable(NULL, cstate.toGS(), cstate.toType)) { + if (index < 0 || !isAvailable(nullptr, cstate.toGS(), cstate.toType)) { cstate.setInvalid(oldData); - // no source is safer than an invalid one - clear(); - } - else if (evt == RadioDataConversionState::EVT_CVRT) { - cstate.setConverted(oldData, RadioDataConversionState::LogField(index, toString(cstate.toModel(), cstate.toGS(), cstate.toType))); - } - else if (oldData.id != index) { - // provide info by default if anything changed - cstate.setMoved(oldData, RadioDataConversionState::LogField(index, toString(cstate.toModel(), cstate.toGS(), cstate.toType))); + clear(); // no source is safer than an invalid one } return *this; } -QStringList RawSource::getStickList(Boards board) const -{ - QStringList ret; - - for (int i = 0; i < board.getCapability(Board::MaxAnalogs); i++) { - ret.append(board.getAnalogInputName(i)); - } - return ret; -} - -QStringList RawSource::getSwitchList(Boards board) const -{ - QStringList ret; - - for (int i = 0; i < board.getCapability(Board::Switches); i++) { - ret.append(board.getSwitchInfo(i).name); - } - return ret; -} - // static StringTagMappingTable RawSource::getSpecialTypesLookupTable() { diff --git a/companion/src/firmwares/rawsource.h b/companion/src/firmwares/rawsource.h index 7e3876491fd..a931c0c3c42 100644 --- a/companion/src/firmwares/rawsource.h +++ b/companion/src/firmwares/rawsource.h @@ -18,8 +18,7 @@ * GNU General Public License for more details. */ -#ifndef RAWSOURCE_H -#define RAWSOURCE_H +#pragma once #include "boards.h" #include "constants.h" @@ -164,13 +163,13 @@ enum RawSourceType { SOURCE_TYPE_NONE, SOURCE_TYPE_VIRTUAL_INPUT, SOURCE_TYPE_LUA_OUTPUT, - SOURCE_TYPE_STICK, // and POTS + SOURCE_TYPE_STICK, // and POTS and Flex pots TODO rename to more appropriate SOURCE_TYPE_ROTARY_ENCODER, SOURCE_TYPE_TRIM, SOURCE_TYPE_MIN, SOURCE_TYPE_MAX, SOURCE_TYPE_SWITCH, - SOURCE_TYPE_FUNCTIONSWITCH, + SOURCE_TYPE_FUNCTIONSWITCH, // v2.10 only used for reading binary files SOURCE_TYPE_CUSTOM_SWITCH, SOURCE_TYPE_CYC, SOURCE_TYPE_PPM, @@ -267,17 +266,13 @@ class RawSource { } RawSource convert(RadioDataConversionState & cstate); - QString toString(const ModelData * model = NULL, const GeneralSettings * const generalSettings = NULL, Board::Type board = Board::BOARD_UNKNOWN) const; + QString toString(const ModelData * model = nullptr, const GeneralSettings * const generalSettings = nullptr, Board::Type board = Board::BOARD_UNKNOWN, bool prefixCustomName = true) const; RawSourceRange getRange(const ModelData * model, const GeneralSettings & settings, unsigned int flags=0) const; - bool isStick(int * potsIndex = NULL, Board::Type board = Board::BOARD_UNKNOWN) const; - bool isPot(int * potsIndex = NULL, Board::Type board = Board::BOARD_UNKNOWN) const; - bool isSlider(int * sliderIndex = NULL, Board::Type board = Board::BOARD_UNKNOWN) const; + bool isStick(Board::Type board = Board::BOARD_UNKNOWN) const; bool isTimeBased(Board::Type board = Board::BOARD_UNKNOWN) const; - bool isAvailable(const ModelData * const model = NULL, const GeneralSettings * const gs = NULL, Board::Type board = Board::BOARD_UNKNOWN) const; + bool isAvailable(const ModelData * const model = nullptr, const GeneralSettings * const gs = nullptr, Board::Type board = Board::BOARD_UNKNOWN) const; bool isSet() const { return type != SOURCE_TYPE_NONE || index != 0; } void clear() { type = SOURCE_TYPE_NONE; index = 0; } - QStringList getStickList(Boards board) const; - QStringList getSwitchList(Boards board) const; static StringTagMappingTable getSpecialTypesLookupTable(); static StringTagMappingTable getCyclicLookupTable(); @@ -291,6 +286,6 @@ class RawSource { RawSourceType type; int index; -}; -#endif // RAWSOURCE_H + private: +}; diff --git a/companion/src/firmwares/rawswitch.cpp b/companion/src/firmwares/rawswitch.cpp index d0b3502b3ed..de8825c2650 100644 --- a/companion/src/firmwares/rawswitch.cpp +++ b/companion/src/firmwares/rawswitch.cpp @@ -24,7 +24,7 @@ #include "radiodata.h" #include "radiodataconversionstate.h" -QString RawSwitch::toString(Board::Type board, const GeneralSettings * const generalSettings, const ModelData * const modelData) const +QString RawSwitch::toString(Board::Type board, const GeneralSettings * const generalSettings, const ModelData * const modelData, bool prefixCustomName) const { if (board == Board::BOARD_UNKNOWN) { board = getCurrentBoard(); @@ -37,14 +37,14 @@ QString RawSwitch::toString(Board::Type board, const GeneralSettings * const gen }; static const QString trimsSwitches[] = { - tr("RudTrim Left"), tr("RudTrim Right"), - tr("EleTrim Down"), tr("EleTrim Up"), - tr("ThrTrim Down"), tr("ThrTrim Up"), - tr("AilTrim Left"), tr("AilTrim Right"), - tr("Trim 5 Down"), tr("Trim 5 Up"), - tr("Trim 6 Down"), tr("Trim 6 Up"), - tr("Trim 7 Down"), tr("Trim 7 Up"), - tr("Trim 8 Down"), tr("Trim 8 Up") + tr("Rud-"), tr("Rud+"), + tr("Ele-"), tr("Ele+"), + tr("Thr-"), tr("Thr+"), + tr("Ail-"), tr("Ail+"), + tr("T5-"), tr("T5+"), + tr("T6-"), tr("T6+"), + tr("T7-"), tr("T7+"), + tr("T8-"), tr("T8+") }; static const QString trimsSwitches2[] = { @@ -71,16 +71,26 @@ QString RawSwitch::toString(Board::Type board, const GeneralSettings * const gen } else { QString swName; + QString custName; div_t qr; switch(type) { case SWITCH_TYPE_SWITCH: if (IS_HORUS_OR_TARANIS(board)) { qr = div(index - 1, 3); - if (generalSettings) - swName = QString(generalSettings->switchName[qr.quot]).trimmed(); - if (swName.isEmpty()) - swName = Boards::getSwitchInfo(board, qr.quot).name; - return swName + directionIndicators.at(qr.rem > -1 && qr.rem < directionIndicators.size() ? qr.rem : 1); + swName = Boards::getSwitchInfo(qr.quot, board).name.c_str(); + if (Boards::isSwitchFunc(qr.quot, board)) { + if (modelData) { + int fsindex = Boards::getSwitchTagNum(qr.quot, board) - 1; + custName = QString(modelData->functionSwitchNames[fsindex]).trimmed(); + } + } + else { + if (generalSettings) { + custName = QString(generalSettings->switchConfig[qr.quot].name).trimmed(); + } + } + return DataHelpers::getCompositeName(swName, custName, prefixCustomName) + + directionIndicators.at(qr.rem > -1 && qr.rem < directionIndicators.size() ? qr.rem : 1); } else { return CHECK_IN_ARRAY(switches9X, index - 1); @@ -88,35 +98,26 @@ QString RawSwitch::toString(Board::Type board, const GeneralSettings * const gen case SWITCH_TYPE_VIRTUAL: if (modelData) - return modelData->logicalSw[index].nameToString(index-1); + return modelData->logicalSw[index].nameToString(index - 1); else - return LogicalSwitchData().nameToString(index-1); - - case SWITCH_TYPE_FUNCTIONSWITCH: - if (!Boards::getCapability(board, Board::FunctionSwitches)) - return CPN_STR_UNKNOWN_ITEM; - qr = div(index - 1, 3); - if (modelData) - swName = QString(modelData->functionSwitchNames[qr.quot]).trimmed(); - if (swName.isEmpty()) - swName = tr("SW%1").arg(qr.quot + 1); - return swName + directionIndicators.at(qr.rem > -1 && qr.rem < directionIndicators.size() ? qr.rem : 1); + return LogicalSwitchData().nameToString(index - 1); case SWITCH_TYPE_MULTIPOS_POT: if (!Boards::getCapability(board, Board::MultiposPotsPositions)) return CPN_STR_UNKNOWN_ITEM; qr = div(index - 1, Boards::getCapability(board, Board::MultiposPotsPositions)); - if (generalSettings && qr.quot < (int)DIM(generalSettings->potConfig)) - swName = QString(generalSettings->potName[qr.quot]); + if (generalSettings && qr.quot < (int)DIM(generalSettings->inputConfig)) + swName = QString(generalSettings->inputConfig[qr.quot].name); if (swName.isEmpty()) - swName = Boards::getAnalogInputName(board, qr.quot + Boards::getCapability(board, Board::Sticks)); + swName = Boards::getInputName(qr.quot, board); return swName + "_" + QString::number(qr.rem + 1); case SWITCH_TYPE_TRIM: - return (Boards::getCapability(board, Board::NumTrims) == 2 ? CHECK_IN_ARRAY(trimsSwitches2, index-1) : CHECK_IN_ARRAY(trimsSwitches, index-1)); + return (Boards::getCapability(board, Board::NumTrims) == 2 ? + CHECK_IN_ARRAY(trimsSwitches2, index - 1) : CHECK_IN_ARRAY(trimsSwitches, index - 1)); case SWITCH_TYPE_ROTARY_ENCODER: - return CHECK_IN_ARRAY(rotaryEncoders, index-1); + return CHECK_IN_ARRAY(rotaryEncoders, index - 1); case SWITCH_TYPE_ON: return tr("ON"); @@ -132,7 +133,7 @@ QString RawSwitch::toString(Board::Type board, const GeneralSettings * const gen case SWITCH_TYPE_FLIGHT_MODE: if (modelData) - return modelData->flightModeData[index-1].nameToString(index - 1); + return modelData->flightModeData[index - 1].nameToString(index - 1); else return FlightModeData().nameToString(index - 1); @@ -144,9 +145,9 @@ QString RawSwitch::toString(Board::Type board, const GeneralSettings * const gen case SWITCH_TYPE_SENSOR: if (modelData) - return modelData->sensorData[index-1].nameToString(index-1); + return modelData->sensorData[index - 1].nameToString(index - 1); else - return SensorData().nameToString(index-1); + return SensorData().nameToString(index - 1); case SWITCH_TYPE_TELEMETRY: return tr("Telemetry"); @@ -166,33 +167,36 @@ bool RawSwitch::isAvailable(const ModelData * const model, const GeneralSettings board = getCurrentBoard(); Boards b(board); + div_t sw; - if (type == SWITCH_TYPE_SWITCH && abs(index) > b.getCapability(Board::SwitchPositions)) + if (type == SWITCH_TYPE_SWITCH && abs(index) > b.getCapability(Board::SwitchesPositions)) return false; - if (type == SWITCH_TYPE_FUNCTIONSWITCH) { - if (!model || abs(index) > b.getCapability(Board::NumFunctionSwitchesPositions)) - return false; - else if (!model->isFunctionSwitchPositionAvailable(abs(index))) - return false; - } - if (type == SWITCH_TYPE_TRIM && abs(index) > b.getCapability(Board::NumTrimSwitches)) return false; + if (type == SWITCH_TYPE_SWITCH) + sw = div(abs(index) - 1, 3); + if (gs) { - if (type == SWITCH_TYPE_SWITCH && IS_HORUS_OR_TARANIS(board) && !gs->switchPositionAllowedTaranis(abs(index))) + if (type == SWITCH_TYPE_SWITCH && !b.isSwitchFunc(sw.quot, board) && !gs->switchPositionAllowed(abs(index))) return false; if (type == SWITCH_TYPE_MULTIPOS_POT) { - int pot = div(abs(index) - 1, b.getCapability(Board::MultiposPotsPositions)).quot; - if (!gs->isPotAvailable(pot) || gs->potConfig[pot] != Board::POT_MULTIPOS_SWITCH) + int idx = div(abs(index) - 1, b.getCapability(Board::MultiposPotsPositions)).quot; + if (!gs->isInputAvailable(idx) || gs->inputConfig[idx].flexType != Board::FLEX_MULTIPOS) return false; } } - if (model && !model->isAvailable(*this)) - return false; + if (model) { + if (type == SWITCH_TYPE_SWITCH && b.isSwitchFunc(sw.quot, board)) { + int fsindex = (((Boards::getSwitchTagNum(sw.quot, board) - 1) * 3) + sw.rem + 1) * ( index < 0 ? -1 : 1); + return model->isFunctionSwitchPositionAvailable(fsindex); + } + else + return model->isAvailable(*this); + } return true; } @@ -203,67 +207,27 @@ RawSwitch RawSwitch::convert(RadioDataConversionState & cstate) return *this; cstate.setItemType(tr("SW"), 2); - RadioDataConversionState::EventType evt = RadioDataConversionState::EVT_NONE; RadioDataConversionState::LogField oldData(index, toString(cstate.fromType, cstate.fromGS(), cstate.fromModel())); int newIdx = 0; if (type == SWITCH_TYPE_SWITCH) { - div_t swtch = div(abs(index) - 1, 3); // rawsource index - QStringList fromSwitchList(getSwitchList(cstate.fromBoard)); - QStringList toSwitchList(getSwitchList(cstate.toBoard)); - // set to -1 if no match found - if (swtch.quot < fromSwitchList.count()) - newIdx = toSwitchList.indexOf(fromSwitchList.at(swtch.quot)); - else - newIdx = -1; - // perform forced mapping - if (newIdx < 0) { - if (IS_TARANIS_X7(cstate.toType) && (IS_TARANIS_X9(cstate.fromType) || IS_FAMILY_HORUS_OR_T16(cstate.fromType))) { - // No SE and SG on X7 board - newIdx = toSwitchList.indexOf("SD"); - if (newIdx >= 0) - evt = RadioDataConversionState::EVT_CVRT; - } - else if (IS_FAMILY_T12(cstate.toType) && (IS_TARANIS_X9(cstate.fromType) || IS_FAMILY_HORUS_OR_T16(cstate.fromType))) { - // No SE and SG on T12 board - newIdx = toSwitchList.indexOf("SD"); - if (newIdx >= 0) - evt = RadioDataConversionState::EVT_CVRT; - } - } + div_t swtch = div(abs(index) - 1, 3); + newIdx = Boards::getSwitchIndex(Boards::getSwitchTag(swtch.quot, cstate.fromType), Board::LVT_TAG, cstate.toType); if (newIdx >= 0) index = (newIdx * 3 + 1 + swtch.rem) * (index < 0 ? -1 : 1); - } // SWITCH_TYPE_SWITCH + } // final validation (we do not pass model to isAvailable() because we don't know what has or hasn't been converted) - if (newIdx < 0 || !isAvailable(NULL, cstate.toGS(), cstate.toType)) { + if (newIdx < 0 || !isAvailable(nullptr, cstate.toGS(), cstate.toType)) { cstate.setInvalid(oldData); - // no switch is safer than an invalid one - clear(); - } - else if (evt == RadioDataConversionState::EVT_CVRT) { - cstate.setConverted(oldData, RadioDataConversionState::LogField(index, toString(cstate.toType, cstate.toGS(), cstate.toModel()))); - } - else if (oldData.id != index) { - // provide info by default if anything changed - cstate.setMoved(oldData, RadioDataConversionState::LogField(index, toString(cstate.toType, cstate.toGS(), cstate.toModel()))); + clear(); // no switch is safer than an invalid one } return *this; } -QStringList RawSwitch::getSwitchList(Boards board) const -{ - QStringList ret; - - for (int i = 0; i < board.getCapability(Board::Switches); i++) { - ret.append(board.getSwitchInfo(i).name); - } - return ret; -} - // static StringTagMappingTable RawSwitch::getRawSwitchTypesLookupTable() { @@ -272,7 +236,7 @@ StringTagMappingTable RawSwitch::getRawSwitchTypesLookupTable() tbl.insert(tbl.end(), { {std::to_string(SWITCH_TYPE_NONE), "NONE"}, {std::to_string(SWITCH_TYPE_SWITCH), "Sxn"}, - {std::to_string(SWITCH_TYPE_FUNCTIONSWITCH), "Sxn"}, + {std::to_string(SWITCH_TYPE_FUNCTIONSWITCH), "FSn"}, {std::to_string(SWITCH_TYPE_VIRTUAL), "Ln"}, {std::to_string(SWITCH_TYPE_MULTIPOS_POT), "6Pn"}, {std::to_string(SWITCH_TYPE_TRIM), "Trim"}, diff --git a/companion/src/firmwares/rawswitch.h b/companion/src/firmwares/rawswitch.h index 4943cc3d49b..5da8b3d9f52 100644 --- a/companion/src/firmwares/rawswitch.h +++ b/companion/src/firmwares/rawswitch.h @@ -34,7 +34,7 @@ class RadioDataConversionState; enum RawSwitchType { SWITCH_TYPE_NONE, SWITCH_TYPE_SWITCH, - SWITCH_TYPE_FUNCTIONSWITCH, + SWITCH_TYPE_FUNCTIONSWITCH, // depreciated kept to preserve following enums SWITCH_TYPE_VIRTUAL, SWITCH_TYPE_MULTIPOS_POT, SWITCH_TYPE_TRIM, @@ -86,11 +86,10 @@ class RawSwitch { } RawSwitch convert(RadioDataConversionState & cstate); - QString toString(Board::Type board = Board::BOARD_UNKNOWN, const GeneralSettings * const generalSettings = NULL, const ModelData * const modelData = NULL) const; - bool isAvailable(const ModelData * const model = NULL, const GeneralSettings * const gs = NULL, Board::Type board = Board::BOARD_UNKNOWN) const; + QString toString(Board::Type board = Board::BOARD_UNKNOWN, const GeneralSettings * const generalSettings = nullptr, const ModelData * const modelData = nullptr, bool prefixCustomName = true) const; + bool isAvailable(const ModelData * const model = nullptr, const GeneralSettings * const gs = nullptr, Board::Type board = Board::BOARD_UNKNOWN) const; 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 { diff --git a/companion/src/generaledit/calibration.cpp b/companion/src/generaledit/calibration.cpp index d955e0e6b3c..931ff16d9b5 100644 --- a/companion/src/generaledit/calibration.cpp +++ b/companion/src/generaledit/calibration.cpp @@ -25,38 +25,37 @@ CalibrationPanel::CalibrationPanel(QWidget * parent, GeneralSettings & generalSettings, Firmware * firmware): GeneralPanel(parent, generalSettings, firmware) { - Board::Type board = getCurrentBoard(); - int rows = Boards::getCapability(board, Board::MaxAnalogs); + int maxrows = Boards::getInputsCalibrated(); + int maxinputs = Boards::getCapability(getCurrentBoard(), Board::Inputs); QStringList headerLabels; headerLabels << "" << tr("Negative span") << tr("Mid value") << tr("Positive span"); - TableLayout * tableLayout = new TableLayout(this, rows, headerLabels); + TableLayout * tableLayout = new TableLayout(this, maxrows, headerLabels); - 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)) + for (int i = 0, row = 0; i < maxinputs; i++) { + if (!Boards::isInputCalibrated(i)) continue; + GeneralSettings::InputCalib &calib = generalSettings.inputConfig[i].calib; + int col = 0; row++; QLabel * label = new QLabel(this); - label->setText(firmware->getAnalogInputName(i)); + label->setText(Boards::getInputName(i)); tableLayout->addWidget(i, col++, label); QLineEdit * leNeg = new QLineEdit(this); - leNeg->setText(QString("%1").arg(generalSettings.calibSpanNeg[i])); + leNeg->setText(QString("%1").arg(calib.spanNeg)); leNeg->setReadOnly(true); tableLayout->addWidget(i, col++, leNeg); QLineEdit * leMid = new QLineEdit(this); - leMid->setText(QString("%1").arg(generalSettings.calibMid[i])); + leMid->setText(QString("%1").arg(calib.mid)); leMid->setReadOnly(true); tableLayout->addWidget(i, col++, leMid); QLineEdit * lePos = new QLineEdit(this); - lePos->setText(QString("%1").arg(generalSettings.calibSpanPos[i])); + lePos->setText(QString("%1").arg(calib.spanPos)); lePos->setReadOnly(true); tableLayout->addWidget(i, col++, lePos); } @@ -65,5 +64,5 @@ CalibrationPanel::CalibrationPanel(QWidget * parent, GeneralSettings & generalSe tableLayout->resizeColumnsToContents(); tableLayout->setColumnWidth(0, QString(15, ' ')); tableLayout->pushColumnsLeft(headerLabels.count()); - tableLayout->pushRowsUp(rows + 1); + tableLayout->pushRowsUp(maxrows + 1); } diff --git a/companion/src/generaledit/generaledit.cpp b/companion/src/generaledit/generaledit.cpp index 814e74dce7e..22ca0e502c0 100644 --- a/companion/src/generaledit/generaledit.cpp +++ b/companion/src/generaledit/generaledit.cpp @@ -114,17 +114,18 @@ void GeneralEdit::on_tabWidget_currentChanged(int index) void GeneralEdit::on_calretrieve_PB_clicked() { Board::Type board = getCurrentBoard(); - int profile_id=ui->profile_CB->itemData(ui->profile_CB->currentIndex()).toInt(); - QString calib=g.profile[profile_id].stickPotCalib(); - int potsnum=getBoardCapability(board, Board::Pots)+getBoardCapability(board, Board::Sliders); - int numSwPots=getBoardCapability(board, Board::Switches)+getBoardCapability(board, Board::Pots)+getBoardCapability(board, Board::Sliders); + int profile_id = ui->profile_CB->itemData(ui->profile_CB->currentIndex()).toInt(); + QString calib = g.profile[profile_id].stickPotCalib(); + int ttlSticks = getBoardCapability(board, Board::Sticks); + int ttlInputs = getBoardCapability(board, Board::Inputs); + int ttlSwitches = getBoardCapability(board, Board::Switches); if (calib.isEmpty()) { return; } else { QString trainercalib = g.profile[profile_id].trainerCalib(); QString hwtypes = g.profile[profile_id].controlTypes(); - QString controlNames=g.profile[profile_id].controlNames(); + QString controlNames = g.profile[profile_id].controlNames(); int8_t txVoltageCalibration = (int8_t)g.profile[profile_id].txVoltageCalibration(); int8_t txCurrentCalibration = (int8_t)g.profile[profile_id].txCurrentCalibration(); int8_t PPM_Multiplier = (int8_t)g.profile[profile_id].ppmMultiplier(); @@ -136,74 +137,60 @@ void GeneralEdit::on_calretrieve_PB_clicked() QString SpeakerSet = g.profile[profile_id].speaker(); QString CountrySet = g.profile[profile_id].countryCode(); - if ((calib.length()==(CPN_MAX_STICKS+potsnum)*12) && (trainercalib.length()==16)) { + if ((calib.length() == (Boards::getInputsCalibrated() * 12)) && (trainercalib.length() == 16)) { QString Byte; int16_t byte16; bool ok; - for (int i=0; i<(CPN_MAX_STICKS+potsnum); i++) { - Byte=calib.mid(i*12,4); - byte16=(int16_t)Byte.toInt(&ok,16); - if (ok) generalSettings.calibMid[i]=byte16; - Byte=calib.mid(4+i*12,4); - byte16=(int16_t)Byte.toInt(&ok,16); - if (ok) generalSettings.calibSpanNeg[i]=byte16; - Byte=calib.mid(8+i*12,4); - byte16=(int16_t)Byte.toInt(&ok,16); - if (ok) generalSettings.calibSpanPos[i]=byte16; + for (int i = 0; i < ttlInputs; i++) { + if (Boards::isInputCalibrated(i)) { + Byte = calib.mid(i * 12, 4); + byte16 = (int16_t)Byte.toInt(&ok, 16); + if (ok) generalSettings.inputConfig[i].calib.mid = byte16; + Byte = calib.mid(4 + i * 12, 4); + byte16 = (int16_t)Byte.toInt(&ok, 16); + if (ok) generalSettings.inputConfig[i].calib.spanNeg = byte16; + Byte = calib.mid(8 + i * 12, 4); + byte16 = (int16_t)Byte.toInt(&ok, 16); + if (ok) generalSettings.inputConfig[i].calib.spanPos = byte16; + } } - for (int i=0; i<4; i++) { - Byte=trainercalib.mid(i*4,4); - byte16=(int16_t)Byte.toInt(&ok,16); - if (ok) generalSettings.trainer.calib[i]=byte16; + for (int i = 0; i < ttlSticks; i++) { + Byte = trainercalib.mid(i * 4, 4); + byte16 = (int16_t)Byte.toInt(&ok, 16); + if (ok) generalSettings.trainer.calib[i] = byte16; } - generalSettings.txCurrentCalibration=txCurrentCalibration; - generalSettings.txVoltageCalibration=txVoltageCalibration; + generalSettings.txCurrentCalibration = txCurrentCalibration; + generalSettings.txVoltageCalibration = txVoltageCalibration; generalSettings.vBatWarn=vBatWarn; if (getCurrentFirmware()->getCapability(HasBatMeterRange)) { generalSettings.vBatMin = (int8_t) g.profile[profile_id].vBatMin(); generalSettings.vBatMax = (int8_t) g.profile[profile_id].vBatMax(); } - generalSettings.PPM_Multiplier=PPM_Multiplier; + generalSettings.PPM_Multiplier = PPM_Multiplier; } else { QMessageBox::critical(this, CPN_STR_TTL_WARNING, tr("Wrong data in profile, radio calibration was not retrieved")); } - if (hwtypes.length()==numSwPots) { + if (hwtypes.length() == ttlSwitches + ttlInputs) { QString Byte; int16_t byte16; QByteArray qba; - int16_t offset; bool ok; - for (int i=0; iprofile_CB->itemData(ui->profile_CB->currentIndex()).toInt(); + Board::Type board = getCurrentBoard(); + int profile_id = ui->profile_CB->itemData(ui->profile_CB->currentIndex()).toInt(); - QString name=g.profile[profile_id].name(); - int potsnum=getBoardCapability(getCurrentBoard(), Board::Pots)+getBoardCapability(getCurrentBoard(), Board::Sliders); + QString name = g.profile[profile_id].name(); if (name.isEmpty()) { ui->calstore_PB->setDisabled(true); return; } else { - QString calib=g.profile[profile_id].stickPotCalib(); - QString hwtypes=g.profile[profile_id].controlTypes(); - QString controlNames=g.profile[profile_id].controlNames(); + QString calib = g.profile[profile_id].stickPotCalib(); + QString hwtypes = g.profile[profile_id].controlTypes(); + QString controlNames = g.profile[profile_id].controlNames(); if (!(calib.isEmpty())) { int ret = QMessageBox::question(this, CPN_STR_APP_NAME, tr("Do you want to store calibration in %1 profile
overwriting existing calibration?").arg(name) , @@ -277,34 +264,34 @@ void GeneralEdit::on_calstore_PB_clicked() return; } } + + int ttlSticks = getBoardCapability(board, Board::Sticks); + int ttlInputs = getBoardCapability(board, Board::Inputs); + int ttlSwitches = getBoardCapability(board, Board::Switches); calib.clear(); - for (int i=0; i< (CPN_MAX_STICKS+potsnum); i++) { - calib.append(QString("%1").arg((uint16_t)generalSettings.calibMid[i], 4, 16, QChar('0'))); - calib.append(QString("%1").arg((uint16_t)generalSettings.calibSpanNeg[i], 4, 16, QChar('0'))); - calib.append(QString("%1").arg((uint16_t)generalSettings.calibSpanPos[i], 4, 16, QChar('0'))); + + for (int i = 0; i < ttlInputs; i++) { + if (Boards::isInputCalibrated(i)) { + calib.append(QString("%1").arg((uint16_t)generalSettings.inputConfig[i].calib.mid, 4, 16, QChar('0'))); + calib.append(QString("%1").arg((uint16_t)generalSettings.inputConfig[i].calib.spanNeg, 4, 16, QChar('0'))); + calib.append(QString("%1").arg((uint16_t)generalSettings.inputConfig[i].calib.spanPos, 4, 16, QChar('0'))); + } } g.profile[profile_id].stickPotCalib( calib ); calib.clear(); - for (int i=0; i< 4; i++) { + for (int i = 0; i < ttlSticks; i++) { calib.append(QString("%1").arg((uint16_t)generalSettings.trainer.calib[i], 4, 16, QChar('0'))); } g.profile[profile_id].trainerCalib( calib ); hwtypes.clear(); controlNames.clear(); - for (int i=0; i #include #include -constexpr char FIM_SWITCHTYPE2POS[] {"Switch Type 2 Pos"}; -constexpr char FIM_SWITCHTYPE3POS[] {"Switch Type 3 Pos"}; -constexpr char FIM_INTERNALMODULES[] {"Internal Modules"}; -constexpr char FIM_AUX1SERIALMODES[] {"AUX1 Modes"}; -constexpr char FIM_AUX2SERIALMODES[] {"AUX2 Modes"}; -constexpr char FIM_VCPSERIALMODES[] {"VCP Modes"}; +constexpr char FIM_SWITCHTYPENONE[] {"Switch Type None"}; +constexpr char FIM_SWITCHTYPE2POS[] {"Switch Type 2 Pos"}; +constexpr char FIM_SWITCHTYPE3POS[] {"Switch Type 3 Pos"}; +constexpr char FIM_INTERNALMODULES[] {"Internal Modules"}; +constexpr char FIM_AUX1SERIALMODES[] {"AUX1 Modes"}; +constexpr char FIM_AUX2SERIALMODES[] {"AUX2 Modes"}; +constexpr char FIM_VCPSERIALMODES[] {"VCP Modes"}; +constexpr char FIM_FLEXSWITCHES[] {"Flex Switches"}; +constexpr char FIM_FLEXTYPE_SWITCH[] {"Flex Type Switch"}; +constexpr char FIM_FLEXTYPE_NOSWITCH[] {"Flex Type No Switch"}; class ExclusiveComboGroup: public QObject { - static constexpr auto _role = Qt::UserRole + 500; - - QList combos; - std::function filter; - -public: - ExclusiveComboGroup(QObject *parent, std::function filter) : - QObject(parent), filter(std::move(filter)) - { - } - - void addCombo(QComboBox *comboBox) - { - connect(comboBox, QOverload::of(&QComboBox::activated), - [=](int index) { this->handleActivated(comboBox, index); }); - combos.append(comboBox); - } + public: + ExclusiveComboGroup(QObject *parent, std::function filter) : + QObject(parent), filter(std::move(filter)) + { + } - void handleActivated(QComboBox* target, int index) { - auto data = target->itemData(index); - auto targetidx = combos.indexOf(target); - for (auto combo : combos) { - if (target == combo) continue; - auto view = dynamic_cast(combo->view()); - Q_ASSERT(view); - - auto previous = combo->findData(targetidx, _role); - if (previous >= 0) { - view->setRowHidden(previous, false); - combo->setItemData(previous, QVariant(), _role); - } - if (!filter(data)) { - auto idx = combo->findData(data); - if (idx >= 0) { - view->setRowHidden(idx, true); - combo->setItemData(idx, targetidx, _role); + typedef QList ComboBoxes; + + ComboBoxes* getComboBoxes() + { + return &combos; + } + + void addCombo(QComboBox *comboBox) + { + connect(comboBox, QOverload::of(&QComboBox::activated), + [=](int index) { this->handleActivated(comboBox, index); }); + combos.append(comboBox); + } + + void handleActivated(QComboBox* target, int index) { + auto data = target->itemData(index); + auto targetidx = combos.indexOf(target); + for (auto combo : combos) { + if (target == combo) continue; + auto view = dynamic_cast(combo->view()); + Q_ASSERT(view); + + auto previous = combo->findData(targetidx, _role); + if (previous >= 0) { + view->setRowHidden(previous, false); + combo->setItemData(previous, QVariant(), _role); + } + if (!filter(data)) { + auto idx = combo->findData(data); + if (idx >= 0) { + view->setRowHidden(idx, true); + combo->setItemData(idx, targetidx, _role); + } } } } - } + + private: + static constexpr auto _role = Qt::UserRole + 500; + + ComboBoxes combos; + std::function filter; + }; HardwarePanel::HardwarePanel(QWidget * parent, GeneralSettings & generalSettings, Firmware * firmware, CompoundItemModelFactory * sharedItemModels): @@ -88,13 +103,17 @@ HardwarePanel::HardwarePanel(QWidget * parent, GeneralSettings & generalSettings editorItemModels(sharedItemModels), serialPortUSBVCP(nullptr), params(new QList), - row(0) + row(0), + exclFlexSwitchesGroup(nullptr) { - editorItemModels->registerItemModel(Boards::potTypeItemModel()); - editorItemModels->registerItemModel(Boards::sliderTypeItemModel()); - int id = editorItemModels->registerItemModel(Boards::switchTypeItemModel()); - tabFilteredModels = new FilteredItemModelFactory(); + + int id = editorItemModels->registerItemModel(Boards::flexTypeItemModel()); + tabFilteredModels->registerItemModel(new FilteredItemModel(editorItemModels->getItemModel(id), Board::FlexTypeContextSwitch), FIM_FLEXTYPE_SWITCH); + tabFilteredModels->registerItemModel(new FilteredItemModel(editorItemModels->getItemModel(id), Board::FlexTypeContextNoSwitch), FIM_FLEXTYPE_NOSWITCH); + + id = editorItemModels->registerItemModel(Boards::switchTypeItemModel()); + tabFilteredModels->registerItemModel(new FilteredItemModel(editorItemModels->getItemModel(id), Board::SwitchTypeContextNone), FIM_SWITCHTYPENONE); tabFilteredModels->registerItemModel(new FilteredItemModel(editorItemModels->getItemModel(id), Board::SwitchTypeContext2Pos), FIM_SWITCHTYPE2POS); tabFilteredModels->registerItemModel(new FilteredItemModel(editorItemModels->getItemModel(id), Board::SwitchTypeContext3Pos), FIM_SWITCHTYPE3POS); @@ -110,13 +129,15 @@ HardwarePanel::HardwarePanel(QWidget * parent, GeneralSettings & generalSettings id = editorItemModels->registerItemModel(ModuleData::internalModuleItemModel()); tabFilteredModels->registerItemModel(new FilteredItemModel(editorItemModels->getItemModel(id)), FIM_INTERNALMODULES); + editorItemModels->addItemModel(AbstractItemModel::IMID_FlexSwitches); + grid = new QGridLayout(this); int count; - addSection(tr("Sticks")); + addSection(tr("Axis")); count = Boards::getCapability(board, Board::Sticks); - if (count) { + if (count > 0) { for (int i = 0; i < count; i++) { addStick(i); } @@ -131,28 +152,33 @@ HardwarePanel::HardwarePanel(QWidget * parent, GeneralSettings & generalSettings addParams(); } - count = Boards::getCapability(board, Board::Pots); - count -= firmware->getCapability(HasFlySkyGimbals) ? 2 : 0; + count = Boards::getCapability(board, Board::Inputs); + if (count > 0) { addSection(tr("Pots")); - for (int i = 0; i < count; i++) { - addPot(i); - } - } - - count = Boards::getCapability(board, Board::Sliders); - if (count) { - addSection(tr("Sliders")); - for (int i = 0; i < count; i++) { - addSlider(i); + for (int i = Boards::getCapability(board, Board::Sticks); i < count; i++) { + if (Boards::isInputConfigurable(i, board)) + addFlex(i); } } count = Boards::getCapability(board, Board::Switches); + if (count) { + // All values except -1 (None) are mutually exclusive + exclFlexSwitchesGroup = new ExclusiveComboGroup( + this, [=](const QVariant &value) { return value == -1; }); + addSection(tr("Switches")); - for (int i = 0; i < count; i++) { - addSwitch(i); + for (int i = 0; i < count && i < CPN_MAX_SWITCHES; i++) { + if (Boards::isSwitchConfigurable(i, board)) + addSwitch(i); + } + + // if multiple combo boxes force update to lists + if (exclFlexSwitchesGroup->getComboBoxes()->count() > 1) { + QComboBox *cb = exclFlexSwitchesGroup->getComboBoxes()->at(0); + exclFlexSwitchesGroup->handleActivated(cb, cb->currentIndex()); } } @@ -383,62 +409,109 @@ void HardwarePanel::on_internalModuleChanged() void HardwarePanel::addStick(int index) { - addLabel(Boards::getAnalogInputName(board, index)); + GeneralSettings::InputConfig &config = generalSettings.inputConfig[index]; + + addLabel(Boards::getInputName(index, board)); AutoLineEdit *name = new AutoLineEdit(this); - name->setField(generalSettings.stickName[index], HARDWARE_NAME_LEN, this); + name->setField(config.name, HARDWARE_NAME_LEN, this); params->append(name); addParams(); } -void HardwarePanel::addPot(int index) +void HardwarePanel::addFlex(int index) { - addLabel(Boards::getAnalogInputName(board, Boards::getCapability(board, Board::Sticks) + index)); + GeneralSettings::InputConfig &config = generalSettings.inputConfig[index]; + + addLabel(Boards::getInputName(index, board)); AutoLineEdit *name = new AutoLineEdit(this); - name->setField(generalSettings.potName[index], HARDWARE_NAME_LEN, this); + name->setField(config.name, HARDWARE_NAME_LEN, this); params->append(name); AutoComboBox *type = new AutoComboBox(this); - type->setModel(editorItemModels->getItemModel(AIM_BOARDS_POT_TYPE)); - type->setField(generalSettings.potConfig[index], this); - params->append(type); - - addParams(); -} + setFlexTypeModel(type, index); + int & flexType = (int &)config.flexType; + type->setField(flexType, this); -void HardwarePanel::addSlider(int index) -{ - addLabel(Boards::getAnalogInputName(board, Boards::getCapability(board, Board::Sticks) + - Boards::getCapability(board, Board::Pots) + index)); + connect(type, &AutoComboBox::currentDataChanged, [=] (int val) { + AbstractItemModel *mdl = editorItemModels->getItemModel(AbstractItemModel::IMID_FlexSwitches); + if (mdl) + mdl->update(AbstractItemModel::IMUE_FunctionSwitches); + emit InputFlexTypeChanged(); + }); - AutoLineEdit *name = new AutoLineEdit(this); - name->setField(generalSettings.sliderName[index], HARDWARE_NAME_LEN, this); - params->append(name); + connect(this, &HardwarePanel::InputFlexTypeChanged, [=]() { setFlexTypeModel(type, index); }); - AutoComboBox *type = new AutoComboBox(this); - type->setModel(editorItemModels->getItemModel(AIM_BOARDS_SLIDER_TYPE)); - type->setField(generalSettings.sliderConfig[index], this); params->append(type); + AutoCheckBox *inverted = new AutoCheckBox(this); + inverted->setField(config.inverted, this); + params->append(inverted); + addParams(); } +void HardwarePanel::setFlexTypeModel(AutoComboBox * cb, int index) +{ + cb->setModel((generalSettings.inputConfig[index].flexType == Board::FLEX_SWITCH || generalSettings.unassignedInputFlexSwitches()) ? + tabFilteredModels->getItemModel(FIM_FLEXTYPE_SWITCH) : + tabFilteredModels->getItemModel(FIM_FLEXTYPE_NOSWITCH)); +} + void HardwarePanel::addSwitch(int index) { - addLabel(Boards::getSwitchInfo(board, index).name); + GeneralSettings::SwitchConfig &config = generalSettings.switchConfig[index]; + Board::SwitchInfo info = Boards::getSwitchInfo(index); + + addLabel(Boards::getSwitchName(index)); AutoLineEdit *name = new AutoLineEdit(this); - name->setField(generalSettings.switchName[index], HARDWARE_NAME_LEN, this); + name->setField(config.name, HARDWARE_NAME_LEN, this); params->append(name); + AutoComboBox *input = nullptr; + + if (generalSettings.isSwitchFlex(index)) { + int id = tabFilteredModels->registerItemModel( + new FilteredItemModel(editorItemModels->getItemModel(AbstractItemModel::IMID_FlexSwitches)), + QString("%1 %2").arg(FIM_FLEXSWITCHES).arg(index)); + input = new AutoComboBox(this); + input->setModel(tabFilteredModels->getItemModel(id)); + input->setField(config.inputIdx, this); + exclFlexSwitchesGroup->addCombo(input); + params->append(input); + } + AutoComboBox *type = new AutoComboBox(this); - Board::SwitchInfo switchInfo = Boards::getSwitchInfo(board, index); - type->setModel(switchInfo.config < Board::SWITCH_3POS ? tabFilteredModels->getItemModel(FIM_SWITCHTYPE2POS) : - tabFilteredModels->getItemModel(FIM_SWITCHTYPE3POS)); - type->setField(generalSettings.switchConfig[index], this); + type->setSizeAdjustPolicy(QComboBox::AdjustToContents); + + if (generalSettings.isSwitchFlex(index)) + if (config.type == Board::SWITCH_NOT_AVAILABLE) + type->setModel(tabFilteredModels->getItemModel(FIM_SWITCHTYPENONE)); + else + type->setModel(tabFilteredModels->getItemModel(FIM_SWITCHTYPE3POS)); + else if (info.type < Board::SWITCH_3POS) + type->setModel(tabFilteredModels->getItemModel(FIM_SWITCHTYPE2POS)); + else + type->setModel(tabFilteredModels->getItemModel(FIM_SWITCHTYPE3POS)); + + int & swtype = (int &)config.type; + type->setField(swtype, this); params->append(type); + if (generalSettings.isSwitchFlex(index)) { + connect(input, &AutoComboBox::currentDataChanged, [=] (int val) { + if (val < 0) { + generalSettings.switchConfig[index].type = Board::SWITCH_NOT_AVAILABLE; + type->setModel(tabFilteredModels->getItemModel(FIM_SWITCHTYPENONE)); + type->updateValue(); + } + else + type->setModel(tabFilteredModels->getItemModel(FIM_SWITCHTYPE3POS)); + }); + } + addParams(); } diff --git a/companion/src/generaledit/hardware.h b/companion/src/generaledit/hardware.h index 5493a831cdd..44a33c74473 100644 --- a/companion/src/generaledit/hardware.h +++ b/companion/src/generaledit/hardware.h @@ -26,6 +26,7 @@ class CompoundItemModelFactory; class FilteredItemModelFactory; class QGridLayout; class AutoComboBox; +class ExclusiveComboGroup; class HardwarePanel : public GeneralPanel { @@ -37,6 +38,7 @@ class HardwarePanel : public GeneralPanel signals: void internalModuleChanged(); + void InputFlexTypeChanged(); private slots: void on_internalModuleChanged(); @@ -55,15 +57,16 @@ class HardwarePanel : public GeneralPanel AutoComboBox *antennaMode; QList *params; int row; + ExclusiveComboGroup *exclFlexSwitchesGroup; void addStick(int index); - void addPot(int index); - void addSlider(int index); + void addFlex(int index); void addSwitch(int index); void addLabel(QString text); void addLine(); void addParams(); void addSection(QString text); + void setFlexTypeModel(AutoComboBox * cb, int index); void updateSerialPortUSBVCP(); }; diff --git a/companion/src/generaledit/trainer.cpp b/companion/src/generaledit/trainer.cpp index 997f5f45690..2c25f1b9d25 100644 --- a/companion/src/generaledit/trainer.cpp +++ b/companion/src/generaledit/trainer.cpp @@ -35,8 +35,7 @@ TrainerPanel::TrainerPanel(QWidget * parent, GeneralSettings & generalSettings, int modeid = editorItemModels->registerItemModel(TrainerMix::modeItemModel()); int srcid = editorItemModels->registerItemModel(TrainerMix::srcItemModel()); - Board::Type board = getCurrentBoard(); - const int stickcnt = Boards::getCapability(board, Board::Sticks); + const int stickcnt = Boards::getCapability(getCurrentBoard(), Board::Sticks); const FieldRange weightrng = TrainerMix::getWeightRange(); @@ -50,9 +49,9 @@ TrainerPanel::TrainerPanel(QWidget * parent, GeneralSettings & generalSettings, addLabel(tr("Weight"), row, 2); addLabel(tr("Source"), row++, 3); - for (int i = 0; i < 4; i++, row++) { // TODO constant + for (int i = 0; i < CPN_MAX_STICKS; i++, row++) { col = 0; - addLabel(Boards::getAnalogInputName(board, i), row, col++); + addLabel(Boards::getInputName(i), row, col++); AutoComboBox *mode = new AutoComboBox(this); mode->setModel(editorItemModels->getItemModel(modeid)); diff --git a/companion/src/hwdefs.qrc.in b/companion/src/hwdefs.qrc.in new file mode 100644 index 00000000000..fedbddd9c6a --- /dev/null +++ b/companion/src/hwdefs.qrc.in @@ -0,0 +1,6 @@ + + + +@HWDEF_JSON_LIST@ + + diff --git a/companion/src/modeledit/flightmodes.cpp b/companion/src/modeledit/flightmodes.cpp index 2012a033095..cbd2dd70655 100644 --- a/companion/src/modeledit/flightmodes.cpp +++ b/companion/src/modeledit/flightmodes.cpp @@ -85,7 +85,7 @@ FlightModePanel::FlightModePanel(QWidget * parent, ModelData & model, int phaseI // The trims QString labels[CPN_MAX_TRIMS]; for(int i = 0; i < CPN_MAX_STICKS; i++) { - labels[i] = firmware->getAnalogInputName(i); + labels[i] = Boards::getInputName(i); } labels[4] = "T5"; // TODO firmware function labels[5] = "T6"; // TODO firmware function diff --git a/companion/src/modeledit/mixerdialog.cpp b/companion/src/modeledit/mixerdialog.cpp index 7da9758fd2d..225078db028 100644 --- a/companion/src/modeledit/mixerdialog.cpp +++ b/companion/src/modeledit/mixerdialog.cpp @@ -36,6 +36,8 @@ MixerDialog::MixerDialog(QWidget *parent, ModelData & model, MixData * mixdata, { ui->setupUi(this); + Board::Type board = firmware->getBoard(); + dialogFilteredItemModels = new FilteredItemModelFactory(); int id; @@ -84,7 +86,7 @@ MixerDialog::MixerDialog(QWidget *parent, ModelData & model, MixData * mixdata, if (!firmware->getCapability(VirtualInputs)) { for(int i = 0; i < CPN_MAX_STICKS; i++) { - ui->trimCB->addItem(firmware->getAnalogInputName(i)); + ui->trimCB->addItem(Boards::getInputName(i, board)); } } diff --git a/companion/src/modeledit/setup.cpp b/companion/src/modeledit/setup.cpp index d0911ccf99f..4f29c37ea14 100644 --- a/companion/src/modeledit/setup.cpp +++ b/companion/src/modeledit/setup.cpp @@ -1603,10 +1603,13 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge // Beep Center checkboxes prevFocus = ui->trimsDisplay; - int analogs = CPN_MAX_STICKS + getBoardCapability(board, Board::Pots) + getBoardCapability(board, Board::Sliders); - int genAryIdx = 0; - for (int i = 0; i < analogs + firmware->getCapability(RotaryEncoders); i++) { - RawSource src((i < analogs) ? SOURCE_TYPE_STICK : SOURCE_TYPE_ROTARY_ENCODER, (i < analogs) ? i : analogs - i); + + const int ttlSticks = Boards::getBoardCapability(board, Board::Sticks); + const int ttlFlexInputs = Boards::getBoardCapability(board, Board::FlexInputs); + const int ttlInputs = ttlSticks + ttlFlexInputs; + + for (int i = 0; i < ttlInputs + firmware->getCapability(RotaryEncoders); i++) { + RawSource src((i < ttlInputs) ? SOURCE_TYPE_STICK : SOURCE_TYPE_ROTARY_ENCODER, (i < ttlInputs) ? i : ttlInputs - i); QCheckBox * checkbox = new QCheckBox(this); checkbox->setProperty("index", i); checkbox->setText(src.toString(&model, &generalSettings)); @@ -1614,25 +1617,24 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge connect(checkbox, SIGNAL(toggled(bool)), this, SLOT(onBeepCenterToggled(bool))); centerBeepCheckboxes << checkbox; if (IS_HORUS_OR_TARANIS(board)) { - if (src.isPot(&genAryIdx) && (!generalSettings.isPotAvailable(genAryIdx) || generalSettings.isMultiPosPot(genAryIdx))) { - checkbox->hide(); - } - else if (src.isSlider(&genAryIdx) && !generalSettings.isSliderAvailable(genAryIdx)) { + if (!(generalSettings.isInputAvailable(i) && + (generalSettings.isInputStick(i) || (generalSettings.isInputPot(i) && !generalSettings.isInputMultiPosPot(i)) || + generalSettings.isInputSlider(i)))) checkbox->hide(); - } } QWidget::setTabOrder(prevFocus, checkbox); prevFocus = checkbox; } // Startup switches warnings - for (int i = 0; i < getBoardCapability(board, Board::Switches); i++) { - 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) { + for (int i = 0; i < Boards::getBoardCapability(board, Board::Switches); i++) { + GeneralSettings::SwitchConfig &swcfg = generalSettings.switchConfig[i]; + + if (Boards::isSwitchFunc(i, board) || !generalSettings.isSwitchAvailable(i) || swcfg.type == Board::SWITCH_TOGGLE) { model.switchWarningEnable |= (1 << i); continue; } + RawSource src(RawSourceType::SOURCE_TYPE_SWITCH, i); QLabel * label = new QLabel(this); QSlider * slider = new QSlider(this); @@ -1649,7 +1651,7 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge slider->setPageStep(1); slider->setTickInterval(1); label->setText(src.toString(&model, &generalSettings)); - slider->setMaximum(switchInfo.config == Board::SWITCH_3POS ? 2 : 1); + slider->setMaximum(swcfg.type == Board::SWITCH_3POS ? 2 : 1); cb->setProperty("index", i); ui->switchesStartupLayout->addWidget(label, 0, i + 1); ui->switchesStartupLayout->setAlignment(label, Qt::AlignCenter); @@ -1668,23 +1670,18 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge // Pot warnings prevFocus = ui->potWarningMode; - int count = getBoardCapability(board, Board::Pots) + getBoardCapability(board, Board::Sliders); - if (IS_HORUS_OR_TARANIS(board) && count > 0) { - for (int i = 0; i < count; i++) { - RawSource src(SOURCE_TYPE_STICK, CPN_MAX_STICKS + i); + if (IS_HORUS_OR_TARANIS(board) && ttlInputs > 0) { + for (int i = ttlSticks; i < ttlInputs; i++) { + RawSource src(SOURCE_TYPE_STICK, i); QCheckBox * cb = new QCheckBox(this); - cb->setProperty("index", i); + cb->setProperty("index", i - ttlSticks); cb->setText(src.toString(&model, &generalSettings)); - ui->potWarningLayout->addWidget(cb, 0, i + 1); + ui->potWarningLayout->addWidget(cb, 0, i - ttlSticks + 1); connect(cb, SIGNAL(toggled(bool)), this, SLOT(potWarningToggled(bool))); potWarningCheckboxes << cb; - if (src.isPot(&genAryIdx) && !generalSettings.isPotAvailable(genAryIdx)) { - cb->hide(); - } - else if (src.isSlider(&genAryIdx) && !generalSettings.isSliderAvailable(genAryIdx)) { + if (!(generalSettings.isInputAvailable(i) && (generalSettings.isInputPot(i) || generalSettings.isInputSlider(i)))) cb->hide(); - } QWidget::setTabOrder(prevFocus, cb); prevFocus = cb; } @@ -1916,7 +1913,7 @@ void SetupPanel::updateStartupSwitches() bool enabled = !(model->switchWarningEnable & (1 << index)); if (IS_HORUS_OR_TARANIS(firmware->getBoard())) { value = (switchStates >> (2 * index)) & 0x03; - if (generalSettings.switchConfig[index] != Board::SWITCH_3POS && value == 2) { + if (generalSettings.switchConfig[index].type != Board::SWITCH_3POS && value == 2) { value = 1; } } @@ -1955,7 +1952,7 @@ void SetupPanel::startupSwitchEdited(int value) model->switchWarningStates &= ~mask; - if (IS_HORUS_OR_TARANIS(firmware->getBoard()) && generalSettings.switchConfig[index] != Board::SWITCH_3POS) { + if (IS_HORUS_OR_TARANIS(firmware->getBoard()) && generalSettings.switchConfig[index].type != Board::SWITCH_3POS) { if (value == 1) { value = 2; } @@ -1989,12 +1986,14 @@ void SetupPanel::updatePotWarnings() { lock = true; ui->potWarningMode->setCurrentIndex(model->potsWarningMode); + for (int i = 0; i < potWarningCheckboxes.size(); i++) { QCheckBox *checkbox = potWarningCheckboxes[i]; int index = checkbox->property("index").toInt(); checkbox->setChecked(model->potsWarnEnabled[index]); checkbox->setDisabled(model->potsWarningMode == 0); } + lock = false; } diff --git a/companion/src/modeledit/setup.ui b/companion/src/modeledit/setup.ui index de0498958ab..95da3907dd6 100644 --- a/companion/src/modeledit/setup.ui +++ b/companion/src/modeledit/setup.ui @@ -6,7 +6,7 @@ 0 0 - 1024 + 1046 435 @@ -393,7 +393,7 @@ - Manual + ON diff --git a/companion/src/modelprinter.cpp b/companion/src/modelprinter.cpp index ebe6d52ddae..ae5f5f0579f 100644 --- a/companion/src/modelprinter.cpp +++ b/companion/src/modelprinter.cpp @@ -268,12 +268,12 @@ QString ModelPrinter::printHeliSwashType () QString ModelPrinter::printCenterBeep() { QStringList strl; - Board::Type board = firmware->getBoard(); - int analogs = CPN_MAX_STICKS + getBoardCapability(board, Board::Pots) + getBoardCapability(board, Board::Sliders); + Board::Type board = getCurrentBoard(); + int inputs = Boards::getBoardCapability(board, Board::Inputs); - for (int i=0; i < analogs + firmware->getCapability(RotaryEncoders); i++) { - RawSource src((i < analogs) ? SOURCE_TYPE_STICK : SOURCE_TYPE_ROTARY_ENCODER, (i < analogs) ? i : analogs - i); + for (int i = 0; i < inputs + firmware->getCapability(RotaryEncoders); i++) { if (model.beepANACenter & (0x01 << i)) { + RawSource src((i < inputs) ? SOURCE_TYPE_STICK : SOURCE_TYPE_ROTARY_ENCODER, (i < inputs) ? i : inputs - i); strl << src.toString(&model, &generalSettings); } } @@ -507,20 +507,25 @@ QString ModelPrinter::printLogicalSwitchLine(int idx) { QString result = ""; const LogicalSwitchData & ls = model.logicalSw[idx]; - const QString sw1Name = RawSwitch(ls.val1).toString(getCurrentBoard(), &generalSettings); - const QString sw2Name = RawSwitch(ls.val2).toString(getCurrentBoard(), &generalSettings); if (ls.isEmpty()) return result; + QString sw1Name; + QString sw2Name; + if (ls.andsw!=0) { result +="( "; } switch (ls.getFunctionFamily()) { case LS_FAMILY_EDGE: - result += tr("Edge") + QString("(%1, [%2:%3])").arg(sw1Name).arg(ValToTim(ls.val2)).arg(ls.val3<0 ? tr("instant") : QString("%1").arg(ValToTim(ls.val2+ls.val3))); + sw1Name = RawSwitch(ls.val1).toString(getCurrentBoard(), &generalSettings); + result += tr("Edge") + QString("(%1, [%2:%3])").arg(sw1Name).arg(ValToTim(ls.val2)).arg(ls.val3 < 0 ? + tr("instant") : (ls.val3 == 0 ? tr("infinite") : QString("%1").arg(ValToTim(ls.val2 + ls.val3)))); break; case LS_FAMILY_STICKY: + sw1Name = RawSwitch(ls.val1).toString(getCurrentBoard(), &generalSettings); + sw2Name = RawSwitch(ls.val2).toString(getCurrentBoard(), &generalSettings); result += tr("Sticky") + QString("(%1, %2)").arg(sw1Name).arg(sw2Name); break; case LS_FAMILY_TIMER: @@ -553,9 +558,12 @@ QString ModelPrinter::printLogicalSwitchLine(int idx) else result += tr(" missing"); result += QString::number(range.step * (ls.val2 /*TODO+ source.getRawOffset(model)*/) + range.offset); + result += range.unit; break; } case LS_FAMILY_VBOOL: + sw1Name = RawSwitch(ls.val1).toString(getCurrentBoard(), &generalSettings); + sw2Name = RawSwitch(ls.val2).toString(getCurrentBoard(), &generalSettings); result += sw1Name; switch (ls.func) { case LS_FN_AND: @@ -603,8 +611,12 @@ QString ModelPrinter::printLogicalSwitchLine(int idx) result += " foo "; break; } - if (ls.val2) - result += RawSource(ls.val2).toString(&model, &generalSettings); + if (ls.val2) { + RawSource source = RawSource(ls.val2); + RawSourceRange range = source.getRange(&model, generalSettings); + result += source.toString(&model, &generalSettings); + result += range.unit; + } else result += "0"; break; @@ -737,25 +749,24 @@ QString ModelPrinter::printSettingsOther() QString ModelPrinter::printSwitchWarnings() { QStringList str; - Boards board = firmware->getBoard(); + Board::Type board = getCurrentBoard(); uint64_t switchStates = model.switchWarningStates; uint64_t value; - for (int idx=0; idx> (2*idx)) & 0x03; + if (!(model.switchWarningEnable & (1 << i))) { + if (IS_HORUS_OR_TARANIS(board)) { + value = (switchStates >> (2 * i)) & 0x03; } else { - value = (idx==0 ? switchStates & 0x3 : switchStates & 0x1); - switchStates >>= (idx==0 ? 2 : 1); + value = (i == 0 ? switchStates & 0x3 : switchStates & 0x1); + switchStates >>= (i == 0 ? 2 : 1); } - str += RawSwitch(SWITCH_TYPE_SWITCH, 1+idx*3+value).toString(board.getBoardType(), &generalSettings, &model); + str += RawSwitch(SWITCH_TYPE_SWITCH, 1 + i * 3 + value).toString(board, &generalSettings, &model); } } return (str.isEmpty() ? tr("None") : str.join(" ")) ; @@ -763,19 +774,20 @@ QString ModelPrinter::printSwitchWarnings() QString ModelPrinter::printPotWarnings() { - QStringList str; - int genAryIdx = 0; - Boards board = firmware->getBoard(); + Board::Type board = getCurrentBoard(); + QStringList str = { printLabelValue(tr("Mode"), printPotsWarningMode()) }; + if (model.potsWarningMode) { - for (int i=0; igetBoard(); - int chnstart = board.getCapability(Board::Pots)+board.getCapability(Board::Sliders); + Board::Type board = firmware->getBoard(); + int pscnt = Boards::getCapability(board, Board::Pots) + Boards::getCapability(board, Board::Sliders); + if (idx == 0) return "THR"; - else if (idx < (chnstart+1)) - return firmware->getAnalogInputName(idx+board.getCapability(Board::Sticks)-1); - else - return RawSource(SOURCE_TYPE_CH, idx-chnstart-1).toString(&model, &generalSettings); + else if (idx <= pscnt) + return Boards::getInputName(idx + Boards::getCapability(board, Board::Sticks) - 1, board); + else if (idx <= pscnt + getCurrentFirmware()->getCapability(Outputs)) + return RawSource(SOURCE_TYPE_CH, idx - pscnt - 1).toString(&model, &generalSettings); + + return QString(CPN_STR_UNKNOWN_ITEM); } QString ModelPrinter::printTrimsDisplayMode() diff --git a/companion/src/shared/CMakeLists.txt b/companion/src/shared/CMakeLists.txt index 66a72590afa..77f2f47efe8 100644 --- a/companion/src/shared/CMakeLists.txt +++ b/companion/src/shared/CMakeLists.txt @@ -2,6 +2,8 @@ project(shared) set(${PROJECT_NAME}_NAMES + autobitmappedcheckbox + autobitmappedcombobox autobitsetcheckbox autocheckbox autocombobox diff --git a/companion/src/shared/autobitmappedcheckbox.cpp b/companion/src/shared/autobitmappedcheckbox.cpp new file mode 100644 index 00000000000..f599b517ed1 --- /dev/null +++ b/companion/src/shared/autobitmappedcheckbox.cpp @@ -0,0 +1,103 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * 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 "autobitmappedcheckbox.h" + +AutoBitMappedCheckBox::AutoBitMappedCheckBox(QWidget * parent): + QCheckBox(parent), + AutoWidget(), + m_field(nullptr), + m_invert(false) +{ + setBits(); + connect(this, &QCheckBox::toggled, this, &AutoBitMappedCheckBox::onToggled); +} + +AutoBitMappedCheckBox::~AutoBitMappedCheckBox() +{ +} + +void AutoBitMappedCheckBox::setField(int & field, GenericPanel * panel, bool invert) +{ + m_field = &field; + m_invert = invert; + setPanel(panel); + updateValue(); +} + +void AutoBitMappedCheckBox::setField(unsigned int & field, GenericPanel * panel, bool invert) +{ + m_field = (int *)&field; + m_invert = invert; + setPanel(panel); + updateValue(); +} + +void AutoBitMappedCheckBox::setInvert(bool invert) +{ + m_invert = invert; + updateValue(); +} + +void AutoBitMappedCheckBox::setBits(const unsigned int numBits, const unsigned int offsetBits, + const unsigned int index, const unsigned int indexBits) +{ + m_bits = numBits; + m_offsetBits = offsetBits; + m_index = index; + m_indexBits = indexBits; + + if (m_offsetBits + m_bits > m_indexBits) + m_indexBits = m_offsetBits + m_bits; +} + +void AutoBitMappedCheckBox::onToggled(bool checked) +{ + if (m_field && !lock()) { + const bool val = m_invert ? !checked : checked; + unsigned int fieldmask = (bitmask() << shiftbits()); + *m_field = (*m_field & ~fieldmask) | (val << shiftbits()); + emit currentDataChanged(val); + dataChanged(); + } +} + +void AutoBitMappedCheckBox::updateValue() +{ + if (m_field) { + setLock(true); + bool val = (bool)((*m_field >> shiftbits()) & bitmask()); + setChecked(m_invert ? !val : val); + setLock(false); + } +} + +unsigned int AutoBitMappedCheckBox::shiftbits() +{ + return m_indexBits * m_index + m_offsetBits; +} + +unsigned int AutoBitMappedCheckBox::bitmask() +{ + int mask = -1; + mask = ~(mask << m_bits); + return (unsigned int)mask; +} diff --git a/companion/src/shared/autobitmappedcheckbox.h b/companion/src/shared/autobitmappedcheckbox.h new file mode 100644 index 00000000000..fc5d1cce699 --- /dev/null +++ b/companion/src/shared/autobitmappedcheckbox.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * 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 "autowidget.h" + +#include + +class AutoBitMappedCheckBox : public QCheckBox, public AutoWidget +{ + Q_OBJECT + + public: + explicit AutoBitMappedCheckBox(QWidget * parent = nullptr); + virtual ~AutoBitMappedCheckBox(); + + virtual void updateValue() override; + + void setField(int & field, GenericPanel * panel = nullptr, bool invert = false); + void setField(unsigned int & field, GenericPanel * panel = nullptr, bool invert = false); + void setInvert(bool invert); + void setBits(const unsigned int numBits = 1, const unsigned int offsetBits = 0, const unsigned int index = 0, + const unsigned int indexBits = 1); + + signals: + void currentDataChanged(bool value); + + protected slots: + void onToggled(bool checked); + + private: + int *m_field; + bool m_invert; + unsigned int m_index; + unsigned int m_indexBits; + unsigned int m_bits; + unsigned int m_offsetBits; + + unsigned int shiftbits(); + unsigned int bitmask(); +}; diff --git a/companion/src/shared/autobitmappedcombobox.cpp b/companion/src/shared/autobitmappedcombobox.cpp new file mode 100644 index 00000000000..8cbe1c0a554 --- /dev/null +++ b/companion/src/shared/autobitmappedcombobox.cpp @@ -0,0 +1,206 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * 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 "autobitmappedcombobox.h" + +AutoBitMappedComboBox::AutoBitMappedComboBox(QWidget * parent): + QComboBox(parent), + AutoWidget(), + m_field(nullptr), + m_next(0), + m_hasModel(false), + m_rawSource(nullptr), + m_rawSwitch(nullptr) +{ + setBits(); + connect(this, QOverload::of(&QComboBox::currentIndexChanged), this, &AutoBitMappedComboBox::onCurrentIndexChanged); +} + +AutoBitMappedComboBox::~AutoBitMappedComboBox() +{ +} + +void AutoBitMappedComboBox::clear() +{ + if (m_hasModel) + return; + + setLock(true); + QComboBox::clear(); + m_next = 0; + setLock(false); +} + +void AutoBitMappedComboBox::insertItems(int index, const QStringList & items) +{ + if (m_hasModel) + return; + + foreach(QString item, items) { + addItem(item); + } +} + +void AutoBitMappedComboBox::addItem(const QString & item) +{ + if (m_hasModel) + return; + + addItem(item, m_next++); +} + +void AutoBitMappedComboBox::addItem(const QString & item, int value) +{ + if (m_hasModel) + return; + + setLock(true); + QComboBox::addItem(item, value); + setLock(false); + updateValue(); +} + +void AutoBitMappedComboBox::setField(unsigned int & field, GenericPanel * panel) +{ + m_field = (int *)&field; + m_rawSource = nullptr; + m_rawSwitch = nullptr; + setFieldInit(panel); +} + +void AutoBitMappedComboBox::setField(int & field, GenericPanel * panel) +{ + m_field = &field; + m_rawSource = nullptr; + m_rawSwitch = nullptr; + setFieldInit(panel); +} + +void AutoBitMappedComboBox::setField(RawSource & field, GenericPanel * panel) +{ + m_rawSource = &field; + m_rawSwitch = nullptr; + m_field = nullptr; + setFieldInit(panel); +} + +void AutoBitMappedComboBox::setField(RawSwitch & field, GenericPanel * panel) +{ + m_rawSwitch = &field; + m_rawSource = nullptr; + m_field = nullptr; + setFieldInit(panel); +} + +void AutoBitMappedComboBox::setFieldInit(GenericPanel * panel) +{ + setPanel(panel); + updateValue(); +} + +void AutoBitMappedComboBox::setBits(const unsigned int numBits, const unsigned int offsetBits, + const unsigned int index, const unsigned int indexBits) +{ + m_bits = numBits; + m_offsetBits = offsetBits; + m_index = index; + m_indexBits = indexBits; + + if (m_offsetBits + m_bits > m_indexBits) + m_indexBits = m_offsetBits + m_bits; +} + +void AutoBitMappedComboBox::setModel(QAbstractItemModel * model) +{ + setLock(true); + QComboBox::setModel(model); + setLock(false); + m_hasModel = true; + updateValue(); +} + +void AutoBitMappedComboBox::setAutoIndexes() +{ + if (m_hasModel) + return; + + for (int i = 0; i < count(); ++i) + setItemData(i, i); + updateValue(); +} + +void AutoBitMappedComboBox::updateValue() +{ + if (!m_field && !m_rawSource && !m_rawSwitch) + return; + + setLock(true); + + if (m_field) { + int val = (*m_field >> shiftbits()) & bitmask(); + setCurrentIndex(findData(val)); + } + else if (m_rawSource) + setCurrentIndex(findData(m_rawSource->toValue())); + else if (m_rawSwitch) + setCurrentIndex(findData(m_rawSwitch->toValue())); + + setLock(false); +} + +void AutoBitMappedComboBox::onCurrentIndexChanged(int index) +{ + if (lock() || index < 0) + return; + + bool ok; + const int val = itemData(index).toInt(&ok); + if (!ok) + return; + + if (m_field && *m_field != val) { + unsigned int fieldmask = (bitmask() << shiftbits()); + *m_field = (*m_field & ~fieldmask) | (val << shiftbits()); + } + else if (m_rawSource && m_rawSource->toValue() != val) { + *m_rawSource = RawSource(val); + } + else if (m_rawSwitch && m_rawSwitch->toValue() != val) { + *m_rawSwitch = RawSwitch(val); + } + else + return; + + emit currentDataChanged(val); + dataChanged(); +} + +unsigned int AutoBitMappedComboBox::shiftbits() +{ + return m_indexBits * m_index + m_offsetBits; +} + +unsigned int AutoBitMappedComboBox::bitmask() +{ + int mask = -1; + mask = ~(mask << m_bits); + return (unsigned int)mask; +} diff --git a/companion/src/shared/autobitmappedcombobox.h b/companion/src/shared/autobitmappedcombobox.h new file mode 100644 index 00000000000..0a0168cafe2 --- /dev/null +++ b/companion/src/shared/autobitmappedcombobox.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * 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 "autowidget.h" +#include "rawsource.h" +#include "rawswitch.h" + +#include + +class AutoBitMappedComboBox : public QComboBox, public AutoWidget +{ + Q_OBJECT + + public: + explicit AutoBitMappedComboBox(QWidget * parent = nullptr); + virtual ~AutoBitMappedComboBox(); + + // QComboBox + virtual void addItem(const QString & item); + virtual void addItem(const QString & item, int value); + virtual void insertItems(int index, const QStringList & items); + // AutoWidget + virtual void updateValue() override; + + void clear(); + + void setBits(const unsigned int numBits = 1, const unsigned int offsetBits = 0, const unsigned int index = 0, + const unsigned int indexBits = 1); + void setField(unsigned int & field, GenericPanel * panel = nullptr); + void setField(int & field, GenericPanel * panel = nullptr); + void setField(RawSource & field, GenericPanel * panel = nullptr); + void setField(RawSwitch & field, GenericPanel * panel = nullptr); + + void setAutoIndexes(); + void setModel(QAbstractItemModel * model); + + signals: + void currentDataChanged(int value); + + protected slots: + void onCurrentIndexChanged(int index); + + private: + int *m_field; + int m_next; + bool m_hasModel; + RawSource *m_rawSource; + RawSwitch *m_rawSwitch; + unsigned int m_index; + unsigned int m_indexBits; + unsigned int m_bits; + unsigned int m_offsetBits; + + unsigned int shiftbits(); + unsigned int bitmask(); + + void setFieldInit(GenericPanel * panel); +}; diff --git a/companion/src/shared/autowidgets.h b/companion/src/shared/autowidgets.h index b2619acdbf5..21fe00a77be 100644 --- a/companion/src/shared/autowidgets.h +++ b/companion/src/shared/autowidgets.h @@ -30,3 +30,5 @@ #include "autoslider.h" #include "autospinbox.h" #include "autotimeedit.h" +#include "autobitmappedcheckbox.h" +#include "autobitmappedcombobox.h" diff --git a/companion/src/simulation/joystickdialog.cpp b/companion/src/simulation/joystickdialog.cpp index b7c004c413a..c408baa3441 100644 --- a/companion/src/simulation/joystickdialog.cpp +++ b/companion/src/simulation/joystickdialog.cpp @@ -82,8 +82,8 @@ void joystickDialog::loadGrid() } memset(sliders, 0, sizeof(sliders)); - memset(sticks, 0, sizeof(sliders)); - memset(invert, 0, sizeof(sliders)); + memset(sticks, 0, sizeof(sticks)); + memset(invert, 0, sizeof(invert)); int row = 0; int col = 0; @@ -151,29 +151,19 @@ void joystickDialog::populateSourceCombo(QComboBox * cb) Board::Type m_board = getCurrentBoard(); GeneralSettings radioSettings = GeneralSettings(); - int ttlSticks = Boards::getCapability(m_board, Board::Sticks); - int ttlKnobs = Boards::getCapability(m_board, Board::Pots); - int ttlFaders = Boards::getCapability(m_board, Board::Sliders); + int ttlInputs = Boards::getCapability(m_board, Board::Inputs); cb->clear(); cb->addItem(tr("Not Assigned"), -1); - for (i=0; i < ttlSticks; ++i) { - wname = Boards::getAxisName(i); - cb->addItem(wname, i); - } - - for (i = 0; i < ttlKnobs; ++i) { - if (radioSettings.isPotAvailable(i)) { - wname = RawSource(RawSourceType::SOURCE_TYPE_STICK, ttlSticks + i).toString(nullptr, &radioSettings); - cb->addItem(wname, i + ttlSticks); - } - } - - for (i = 0; i < ttlFaders; ++i) { - if (radioSettings.isSliderAvailable(i)) { - wname = RawSource(RawSourceType::SOURCE_TYPE_STICK, ttlSticks + ttlKnobs + i).toString(nullptr, &radioSettings); - cb->addItem(wname, i + ttlSticks + ttlKnobs); + for (i = 0; i < ttlInputs; ++i) { + if (radioSettings.isInputAvailable(i) && + (radioSettings.isInputStick(i) || radioSettings.isInputPot(i) || radioSettings.isInputSlider(i))) { + if (radioSettings.isInputStick(i)) + wname = Boards::getAxisName(i); + else + wname = RawSource(RawSourceType::SOURCE_TYPE_STICK, i).toString(nullptr, &radioSettings); + cb->addItem(wname, i); } } } @@ -192,12 +182,12 @@ void joystickDialog::populateButtonCombo(QComboBox * cb) cb->clear(); cb->addItem(tr("Not Assigned"), -1); - Board::SwitchType swcfg; + Board::SwitchType swtype; for (i = 0; i < ttlSwitches; ++i) { - if (radioSettings.switchConfig[i] != Board::SWITCH_NOT_AVAILABLE) { - swcfg = Board::SwitchType(radioSettings.switchConfig[i]); + if (radioSettings.switchConfig[i].type != Board::SWITCH_NOT_AVAILABLE) { + swtype = Board::SwitchType(radioSettings.switchConfig[i].type); wname = RawSource(RawSourceType::SOURCE_TYPE_SWITCH, i).toString(nullptr, &radioSettings); - if (swcfg == Board::SWITCH_3POS) { + if (swtype == Board::SWITCH_3POS) { cb->addItem(wname + CPN_STR_SW_INDICATOR_UP, i | JS_BUTTON_3POS_UP); cb->addItem(wname + CPN_STR_SW_INDICATOR_DN, i | JS_BUTTON_3POS_DN); } else { diff --git a/companion/src/simulation/simulatorwidget.cpp b/companion/src/simulation/simulatorwidget.cpp index 36f30b2586c..1373e1c6f1f 100644 --- a/companion/src/simulation/simulatorwidget.cpp +++ b/companion/src/simulation/simulatorwidget.cpp @@ -575,8 +575,7 @@ void SimulatorWidget::setupRadioWidgets() int i, midpos; const int ttlSticks = Boards::getCapability(m_board, Board::Sticks); const int ttlSwitches = Boards::getCapability(m_board, Board::Switches); - const int ttlKnobs = Boards::getCapability(m_board, Board::Pots); - const int ttlFaders = Boards::getCapability(m_board, Board::Sliders); + const int ttlInputs = Boards::getCapability(m_board, Board::Inputs); const int extraTrims = Boards::getCapability(m_board, Board::NumTrims) - ttlSticks; // First clear out any existing widgets. @@ -604,11 +603,11 @@ void SimulatorWidget::setupRadioWidgets() // switches Board::SwitchType swcfg; for (i = 0; i < ttlSwitches; ++i) { - if (radioSettings.switchConfig[i] == Board::SWITCH_NOT_AVAILABLE) + if (!radioSettings.isSwitchAvailable(i) || Boards::isSwitchFunc(i)) continue; - swcfg = Board::SwitchType(radioSettings.switchConfig[i]); - wname = RawSource(RawSourceType::SOURCE_TYPE_SWITCH, i).toString(nullptr, &radioSettings); + swcfg = Board::SwitchType(radioSettings.switchConfig[i].type); + wname = RawSource(RawSourceType::SOURCE_TYPE_SWITCH, i).toString(nullptr, &radioSettings, Board::BOARD_UNKNOWN, false); RadioSwitchWidget * sw = new RadioSwitchWidget(swcfg, wname, -1, ui->radioWidgetsHT); sw->setIndex(i); ui->radioWidgetsHTLayout->addWidget(sw); @@ -619,12 +618,12 @@ void SimulatorWidget::setupRadioWidgets() midpos = (int)floorf(m_radioWidgets.size() / 2.0f); // pots in middle of switches - for (i = 0; i < ttlKnobs; ++i) { - if (!radioSettings.isPotAvailable(i)) + for (i = 0; i < ttlInputs; ++i) { + if (!(radioSettings.isInputAvailable(i) && radioSettings.isInputPot(i))) continue; - wname = RawSource(RawSourceType::SOURCE_TYPE_STICK, ttlSticks + i).toString(nullptr, &radioSettings); - RadioKnobWidget * pot = new RadioKnobWidget(Board::PotType(radioSettings.potConfig[i]), wname, 0, ui->radioWidgetsHT); + wname = RawSource(RawSourceType::SOURCE_TYPE_STICK, i).toString(nullptr, &radioSettings, Board::BOARD_UNKNOWN, false); + RadioKnobWidget * pot = new RadioKnobWidget(radioSettings.inputConfig[i].flexType, wname, 0, ui->radioWidgetsHT); pot->setIndex(i); ui->radioWidgetsHTLayout->insertWidget(midpos++, pot); m_radioWidgets.append(pot); @@ -632,15 +631,15 @@ void SimulatorWidget::setupRadioWidgets() // faders between sticks int fc = extraTrims / 2; // leave space for any extra trims - for (i = 0; i < ttlFaders; ++i) { - if (!radioSettings.isSliderAvailable(i)) + + for (i = 0; i < ttlInputs; ++i) { + if (!(radioSettings.isInputAvailable(i) && radioSettings.isInputSlider(i))) continue; - wname = RawSource(RawSourceType::SOURCE_TYPE_STICK, ttlSticks + ttlKnobs + i).toString(nullptr, &radioSettings); + wname = RawSource(RawSourceType::SOURCE_TYPE_STICK, i).toString(nullptr, &radioSettings, Board::BOARD_UNKNOWN, false); RadioFaderWidget * sl = new RadioFaderWidget(wname, 0, ui->radioWidgetsVC); sl->setIndex(i); ui->VCGridLayout->addWidget(sl, 0, fc++, 1, 1); - m_radioWidgets.append(sl); } @@ -648,7 +647,7 @@ void SimulatorWidget::setupRadioWidgets() int tc = 0; int tridx = ttlSticks; for (i = 0; i < extraTrims; i += 1, tridx += 1) { - wname = RawSource(RawSourceType::SOURCE_TYPE_TRIM, tridx).toString(nullptr, &radioSettings); + wname = RawSource(RawSourceType::SOURCE_TYPE_TRIM, tridx).toString(nullptr, &radioSettings, Board::BOARD_UNKNOWN, false); wname = wname.left(1) % wname.right(1); RadioTrimWidget * tw = new RadioTrimWidget(Qt::Vertical, ui->radioWidgetsVC); tw->setIndices(tridx, tridx * 2, tridx * 2 + 1); @@ -814,17 +813,25 @@ void SimulatorWidget::onPhaseChanged(qint32 phase, const QString & name) setWindowTitle(windowName + tr(" - Flight Mode %1 (#%2)").arg(name).arg(phase)); } -void SimulatorWidget::onRadioWidgetValueChange(const RadioWidget::RadioWidgetType type, const int index, int value) +void SimulatorWidget::onRadioWidgetValueChange(const RadioWidget::RadioWidgetType type, int index, int value) { //qDebug() << type << index << value; if (!simulator || index < 0) return; SimulatorInterface::InputSourceType inpType = SimulatorInterface::INPUT_SRC_NONE; + GeneralSettings::SwitchConfig *cfg = nullptr; switch (type) { case RadioWidget::RADIO_WIDGET_SWITCH : - inpType = SimulatorInterface::INPUT_SRC_SWITCH; + cfg = &radioSettings.switchConfig[index]; + if (cfg->inputIdx != SWITCH_INPUTINDEX_NONE) { + inpType = SimulatorInterface::INPUT_SRC_STICK; + index = cfg->inputIdx; + value = value * 1024; + } + else + inpType = SimulatorInterface::INPUT_SRC_SWITCH; break; case RadioWidget::RADIO_WIDGET_KNOB : diff --git a/companion/src/simulation/simulatorwidget.h b/companion/src/simulation/simulatorwidget.h index 08ec1d7c357..3c3d4545ff9 100644 --- a/companion/src/simulation/simulatorwidget.h +++ b/companion/src/simulation/simulatorwidget.h @@ -110,7 +110,7 @@ class SimulatorWidget : public QWidget void onSimulatorHeartbeat(qint32 loops, qint64 timestamp); void onPhaseChanged(qint32 phase, const QString & name); void onSimulatorError(const QString & error); - void onRadioWidgetValueChange(const RadioWidget::RadioWidgetType type, const int index, int value); + void onRadioWidgetValueChange(const RadioWidget::RadioWidgetType type, int index, int value); void onjoystickAxisValueChanged(int axis, int value); void onjoystickButtonValueChanged(int button, bool state); diff --git a/companion/src/simulation/widgets/radioknobwidget.h b/companion/src/simulation/widgets/radioknobwidget.h index 590e0742eba..c125298f665 100644 --- a/companion/src/simulation/widgets/radioknobwidget.h +++ b/companion/src/simulation/widgets/radioknobwidget.h @@ -18,8 +18,7 @@ * GNU General Public License for more details. */ -#ifndef _RADIOKNOBWIDGET_H_ -#define _RADIOKNOBWIDGET_H_ +#pragma once #include "radiowidget.h" #include "boards.h" @@ -38,23 +37,23 @@ class RadioKnobWidget : public RadioWidget public: - explicit RadioKnobWidget(Board::PotType type = Board::POT_WITH_DETENT, QWidget * parent = Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags()) : + explicit RadioKnobWidget(Board::FlexType type = Board::FLEX_POT_CENTER, QWidget * parent = Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags()) : RadioWidget(parent, f) { init(type); } - explicit RadioKnobWidget(Board::PotType type, const QString & labelText, int value = 0, QWidget * parent = Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags()) : + explicit RadioKnobWidget(Board::FlexType type, const QString & labelText, int value = 0, QWidget * parent = Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags()) : RadioWidget(labelText, value, parent, f) { init(type); } - void init(Board::PotType potType) + void init(Board::FlexType potType) { m_type = RADIO_WIDGET_KNOB; - m_stepSize = (potType == Board::POT_MULTIPOS_SWITCH) ? 2048 / 5 : 1; + m_stepSize = (potType == Board::FLEX_MULTIPOS) ? 2048 / 5 : 1; m_toolTip = tr("

Value (input): %1

"); if (m_stepSize == 1) @@ -88,7 +87,7 @@ class RadioKnobWidget : public RadioWidget } m_dial->setValue(m_value); - + connect(m_dial, &QDial::valueChanged, this, &RadioKnobWidget::setValueFromDial); connect(this, &RadioWidget::valueChanged, m_dial, &QDial::setValue); @@ -157,6 +156,3 @@ class RadioKnobWidget : public RadioWidget QString m_toolTip; }; - - -#endif // _RADIOKNOBWIDGET_H_ diff --git a/companion/src/simulator.cpp b/companion/src/simulator.cpp index 518fa19f915..253b9e331f7 100644 --- a/companion/src/simulator.cpp +++ b/companion/src/simulator.cpp @@ -41,6 +41,7 @@ #include "storage.h" #include "translations.h" #include "version.h" +#include "boardfactories.h" using namespace Simulator; @@ -276,6 +277,8 @@ int main(int argc, char *argv[]) } #endif + Q_INIT_RESOURCE(hwdefs); + gBoardFactories = new BoardFactories(); registerStorageFactories(); registerOpenTxFirmwares(); SimulatorLoader::registerSimulators(); @@ -293,7 +296,7 @@ int main(int argc, char *argv[]) simOptions.firmwareId = g.profile[profileId].fwType(); } - // do not used saved simulatorId always refresh + // DO NOT use saved simulatorId as could be changed in later releases simOptions.simulatorId = SimulatorLoader::findSimulatorByName(Firmware::getFirmwareForId(simOptions.firmwareId)->getSimulatorId()); if (simOptions.dataFolder.isEmpty()) @@ -343,6 +346,11 @@ int main(int argc, char *argv[]) g.sessionId(profileId); g.simuLastProfId(profileId); + // TODO: fix this in Firmware and Boards refactor + // Append a dummy variant to firmware name to force the Board Type to be registered + Firmware * simfw = Firmware::getFirmwareForId(simOptions.firmwareId + "-simulator"); + delete simfw; + // Set global firmware environment Firmware::setCurrentVariant(Firmware::getFirmwareForId(simOptions.firmwareId)); //qDebug() << "current firmware:" << getCurrentFirmware()->getId(); @@ -375,6 +383,7 @@ int finish(int exitCode) SimulatorLoader::unregisterSimulators(); unregisterOpenTxFirmwares(); unregisterStorageFactories(); + gBoardFactories->unregisterBoardFactories(); #if defined(JOYSTICKS) || defined(SIMU_AUDIO) SDL_Quit(); diff --git a/companion/src/storage/labeled.cpp b/companion/src/storage/labeled.cpp index 2c28758f96f..3927c38c88a 100644 --- a/companion/src/storage/labeled.cpp +++ b/companion/src/storage/labeled.cpp @@ -72,8 +72,11 @@ bool LabelsStorageFormat::loadBin(RadioData & radioData) return false; } + board = loadInterface->getBoard(); + radioData.generalSettings.convertLegacyConfiguration(board); + QByteArray modelsListBuffer; if (!loadFile(modelsListBuffer, "RADIO/models.txt")) { setError(tr("Cannot extract RADIO/models.txt")); diff --git a/companion/util/generate_hwdefs_qrc.py b/companion/util/generate_hwdefs_qrc.py new file mode 100755 index 00000000000..7d9085430e3 --- /dev/null +++ b/companion/util/generate_hwdefs_qrc.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 + +import argparse +import glob +from os import path + +def main(jsondir, template, placeholder, output): + if not path.isdir(jsondir): + raise Exception(jsondir + " is not a directory") + + try: + tmplt = open(template, "r") + except: + raise Exception("Unable to open template file " + template) + + try: + qrc = open(output, "w") + except: + raise Exception("Unable to open " + output + " for writing") + + line = tmplt.readline() + + while placeholder not in line and line != '': + qrc.write(line) + line = tmplt.readline() + + for f in sorted(glob.iglob(path.join(jsondir, '*.json'), recursive = False)): + fname = path.basename(f) + qrc.write(' ' + f + '' + '\n') + + line = tmplt.readline() + + while line != '': + qrc.write(line) + line = tmplt.readline() + + tmplt.close() + qrc.close() + + +if __name__ == "__main__": + + parser = argparse.ArgumentParser(description='Generate hardware definitions resource file') + parser.add_argument('-d', metavar='json files directory', required=True) + parser.add_argument('-t', metavar='template file', required=True) + parser.add_argument('-p', metavar='placeholder', required=True) + parser.add_argument('-o', metavar='qrc file', required=True) + + args = parser.parse_args() + + main(args.d, args.t, args.p, args.o) diff --git a/radio/src/targets/simu/opentxsimulator.cpp b/radio/src/targets/simu/opentxsimulator.cpp index 2d09262868b..a37188294df 100644 --- a/radio/src/targets/simu/opentxsimulator.cpp +++ b/radio/src/targets/simu/opentxsimulator.cpp @@ -252,18 +252,9 @@ void OpenTxSimulator::setInputValue(int type, uint8_t index, int16_t value) switch (type) { case INPUT_SRC_ANALOG : case INPUT_SRC_STICK : - setAnalogValue(index, value); - break; case INPUT_SRC_KNOB : - setAnalogValue(index + adcGetInputOffset(ADC_INPUT_FLEX), value); - break; case INPUT_SRC_SLIDER : - // TODO redo this when Companion refactored to use radio json adc files - //setAnalogValue(index + adcGetInputOffset(ADC_INPUT_FLEX), value); - static const int slideroffset = adcGetInputIdx("SL1", 3); - //qDebug() << "SL1:" << slideroffset; - if (slideroffset >= 0) - setAnalogValue(index + slideroffset, value); + setAnalogValue(index, value); break; case INPUT_SRC_TXVIN : if (adcGetMaxInputs(ADC_INPUT_VBAT) > 0) {