From 95c035ed73d1166b12979032de2c3ad7084e9b33 Mon Sep 17 00:00:00 2001 From: 3djc Date: Thu, 30 Aug 2018 10:37:51 +0200 Subject: [PATCH] Support for non certified firmwares (#6118) * Support new r9m firmwares * More future proof, thx Kilrah * (significant) typo * Companion part * Make support a compilation option * Fix compilation for normal users * Warning popup for usability tests * Better implementation * All sizes * Cosmetics * Flex is EU+/AU+ only * [Companion] Handle "flexr9m" option in module settings UI (to match radio UI, including warning msg); Move some "toString" functions out of ModelPrinter into ModuleData/Multiprotocols; "Future-proof" available R9M power options based on "stdr9m" fw option; Fix missing "Hitec" MM protocol name; Fix printing of R9M-EU power level in ModelPrinter. * Cosmetics * Rename R9M flex option * Move failsafe further back to prevent nav oddity --- companion/src/constants.h | 2 + companion/src/firmwares/eeprominterface.h | 4 +- companion/src/firmwares/moduledata.cpp | 99 ++++++++++++ companion/src/firmwares/moduledata.h | 16 +- companion/src/firmwares/multiprotocols.cpp | 21 +++ companion/src/firmwares/multiprotocols.h | 10 +- .../src/firmwares/opentx/opentxinterface.cpp | 5 + companion/src/modeledit/setup.cpp | 94 ++++-------- companion/src/modeledit/setup.h | 2 +- companion/src/modeledit/setup_module.ui | 52 ++++++- companion/src/modelprinter.cpp | 143 +++--------------- companion/src/modelprinter.h | 7 +- radio/src/CMakeLists.txt | 5 + radio/src/gui/128x64/model_setup.cpp | 20 ++- radio/src/gui/212x64/model_setup.cpp | 13 +- radio/src/gui/480x272/model_setup.cpp | 17 ++- radio/src/gui/gui_common.h | 3 +- radio/src/gui/gui_common_arm.cpp | 8 + radio/src/myeeprom.h | 5 +- radio/src/pulses/pulses_arm.h | 8 +- radio/src/pulses/pxx_arm.cpp | 4 +- radio/src/translations.cpp | 2 + radio/src/translations.h | 2 + radio/src/translations/cz.h.txt | 2 + radio/src/translations/de.h.txt | 2 + radio/src/translations/en.h.txt | 2 + radio/src/translations/es.h.txt | 2 + radio/src/translations/fi.h.txt | 2 + radio/src/translations/fr.h.txt | 2 + radio/src/translations/it.h.txt | 2 + radio/src/translations/nl.h.txt | 2 + radio/src/translations/pl.h.txt | 2 + radio/src/translations/pt.h.txt | 2 + radio/src/translations/se.h.txt | 2 + radio/util/fwoptions.py | 18 ++- 35 files changed, 349 insertions(+), 233 deletions(-) diff --git a/companion/src/constants.h b/companion/src/constants.h index 9e35a57cc..6d372f828 100644 --- a/companion/src/constants.h +++ b/companion/src/constants.h @@ -73,6 +73,8 @@ #define CPN_STR_APP_SETTINGS_FILES CPN_STR_APP_SETTINGS % " " % CPN_STR_FILES #define CPN_STR_APP_SETTINGS_FILTER CPN_STR_APP_SETTINGS_FILES % " (*.ini)" +#define CPN_STR_UNKNOWN_ITEM "???" + #define CPN_STR_SW_INDICATOR_UP QCoreApplication::translate("RawSwitch", "\xE2\x86\x91") // Switch up position indicator: Up arrow, or similar. #define CPN_STR_SW_INDICATOR_DN QCoreApplication::translate("RawSwitch", "\xE2\x86\x93") // Switch down position indicator: Down arrow, or similar. #define CPN_STR_SW_INDICATOR_NEUT QCoreApplication::translate("RawSwitch", "-") // Switch neutral (middle) position indicator. diff --git a/companion/src/firmwares/eeprominterface.h b/companion/src/firmwares/eeprominterface.h index ee83fa7b7..9355ba467 100644 --- a/companion/src/firmwares/eeprominterface.h +++ b/companion/src/firmwares/eeprominterface.h @@ -107,6 +107,8 @@ enum Capability { HasFailsafe, HasSoundMixer, NumModules, + HasModuleR9MFlex, + HasModuleR9MMini, PPMCenter, PPMUnitMicroseconds, SYMLimits, @@ -414,7 +416,7 @@ inline int calcRESXto100(int x) return divRoundClosest(x*100, 1024); } -#define CHECK_IN_ARRAY(T, index) ((unsigned int)index < DIM(T) ? T[(unsigned int)index] : "???") +#define CHECK_IN_ARRAY(T, index) ((unsigned int)index < DIM(T) ? T[(unsigned int)index] : CPN_STR_UNKNOWN_ITEM) extern QList eepromInterfaces; diff --git a/companion/src/firmwares/moduledata.cpp b/companion/src/firmwares/moduledata.cpp index 9fdccb61f..ba9a8d843 100644 --- a/companion/src/firmwares/moduledata.cpp +++ b/companion/src/firmwares/moduledata.cpp @@ -19,6 +19,8 @@ */ #include "moduledata.h" +#include "eeprominterface.h" +#include "multiprotocols.h" #include "radiodataconversionstate.h" void ModuleData::convert(RadioDataConversionState & cstate) @@ -27,3 +29,100 @@ void ModuleData::convert(RadioDataConversionState & cstate) clear(); } } + +QString ModuleData::rfProtocolToString() const +{ + switch (protocol) { + case PULSES_MULTIMODULE: + return Multiprotocols::protocolToString((int)multi.rfProtocol, multi.customProto); + + default: + return CPN_STR_UNKNOWN_ITEM; + } +} + +QString ModuleData::subTypeToString(int type) const +{ + static const char * strings[] = { + "FCC", + "EU", + "EU+", + "AU+" + }; + + if (type < 0) + type = subType; + + switch (protocol) { + case PULSES_MULTIMODULE: + return Multiprotocols::subTypeToString(multi.customProto ? MM_RF_CUSTOM_SELECTED : (int)multi.rfProtocol, (unsigned)type); + + case PULSES_PXX_R9M: + return CHECK_IN_ARRAY(strings, type); + + default: + return CPN_STR_UNKNOWN_ITEM; + } +} + +QString ModuleData::powerValueToString(Firmware * fw) const +{ + const QStringList & strRef = powerValueStrings(subType, fw); + // EU module with telemetry can only be < 100/200mW. + if (pxx.sport_out && subType == MODULE_SUBTYPE_R9M_EU && pxx.power > 1) + return CPN_STR_UNKNOWN_ITEM; + + return strRef.value(pxx.power, CPN_STR_UNKNOWN_ITEM); +} + +// static +QString ModuleData::indexToString(int index, Firmware * fw) +{ + if (index < 0) + return tr("Trainer Port"); + + if (fw->getCapability(NumModules) > 1) { + if (IS_HORUS_OR_TARANIS(fw->getBoard())) + return index == 0 ? tr("Internal Radio System") : tr("External Radio Module"); + if (index > 0) + return tr("Extra Radio System"); + } + return tr("Radio System"); +} + +// static +QString ModuleData::protocolToString(unsigned protocol) +{ + static const char * strings[] = { + "OFF", + "PPM", + "Silverlit A", "Silverlit B", "Silverlit C", + "CTP1009", + "LP45", "DSM2", "DSMX", + "PPM16", "PPMsim", + "FrSky XJT (D16)", "FrSky XJT (D8)", "FrSky XJT (LR12)", "FrSky DJT", + "Crossfire", + "DIY Multiprotocol Module", + "FrSky R9M Module", + "SBUS output at VBat" + }; + + return CHECK_IN_ARRAY(strings, protocol); +} + +// static +QStringList ModuleData::powerValueStrings(int subType, Firmware * fw) +{ + static const QStringList strings[] = { + { tr("10mW - 16CH"), tr("100mW - 16CH"), tr("500mW - 16CH"), tr("1W - 16CH") }, // full-size FCC + { tr("25mW - 8CH"), tr("25mW - 16CH"), tr("200mW - 16CH (no telemetry)"), tr("500mW - 16CH (no telemetry)") }, // full-size EU + { tr("100mW - 16CH") }, // mini FCC + { tr("25mW - 8CH"), tr("25mW - 16CH"), tr("100mW - 16CH (no telemetry)") } // mini EU + }; + int strIdx = 0; + if (subType == MODULE_SUBTYPE_R9M_EU) + strIdx += 1; + if (fw->getCapability(HasModuleR9MMini)) + strIdx += 2; + return strings[strIdx]; +} diff --git a/companion/src/firmwares/moduledata.h b/companion/src/firmwares/moduledata.h index 4cdeb6e99..8e1fa4d47 100644 --- a/companion/src/firmwares/moduledata.h +++ b/companion/src/firmwares/moduledata.h @@ -25,6 +25,7 @@ #include +class Firmware; class RadioDataConversionState; enum PulsesProtocol { @@ -101,8 +102,11 @@ enum TrainerProtocol { }; enum R9MSubTypes { - R9M_FCC, - R9M_LBT + MODULE_SUBTYPE_R9M_FCC, + MODULE_SUBTYPE_R9M_EU, + MODULE_SUBTYPE_R9M_EUPLUS, + MODULE_SUBTYPE_R9M_AUPLUS, + MODULE_SUBTYPE_R9M_LAST=MODULE_SUBTYPE_R9M_AUPLUS }; class ModuleData { @@ -145,8 +149,14 @@ class ModuleData { void clear() { memset(this, 0, sizeof(ModuleData)); } - QString polarityToString() const { return ppm.pulsePol ? tr("Positive") : tr("Negative"); } // TODO ModelPrinter void convert(RadioDataConversionState & cstate); + QString polarityToString() const { return ppm.pulsePol ? tr("Positive") : tr("Negative"); } + QString rfProtocolToString() const; + QString subTypeToString(int type = -1) const; + QString powerValueToString(Firmware * fw) const; + static QString indexToString(int index, Firmware * fw); + static QString protocolToString(unsigned protocol); + static QStringList powerValueStrings(int subType, Firmware * fw); }; #endif // MODULEDATA_H diff --git a/companion/src/firmwares/multiprotocols.cpp b/companion/src/firmwares/multiprotocols.cpp index 6a8d17b3c..aad5108f2 100644 --- a/companion/src/firmwares/multiprotocols.cpp +++ b/companion/src/firmwares/multiprotocols.cpp @@ -127,3 +127,24 @@ const Multiprotocols::MultiProtocolDefinition & Multiprotocols::getProtocol(int Q_ASSERT(protocols.rbegin()->protocol == 0xfe); return *protocols.rbegin(); } + +// static +QString Multiprotocols::protocolToString(int protocol, bool custom) +{ + static const QStringList strings({ + "FlySky", "Hubsan", "FrSky", "Hisky", "V2x2", "DSM", "Devo", "YD717", "KN", "SymaX", "SLT", "CX10", "CG023", + "Bayang", "ESky", "MT99XX", "MJXQ", "Shenqi", "FY326", "SFHSS", "J6 PRO","FQ777","Assan","Hontai","OLRS", + "FlySky AFHDS2A", "Q2x2", "Walkera", "Q303", "GW008", "DM002", "CABELL", "Esky 150", "H8 3D", "Corona", "CFlie", "Hitec" + }); + + if (protocol == MM_RF_CUSTOM_SELECTED || custom) + return tr("Custom - proto %1)").arg(protocol); + else + return strings.value(protocol, CPN_STR_UNKNOWN_ITEM); +} + +// static +QString Multiprotocols::subTypeToString(int protocol, unsigned subType) +{ + return tr(qPrintable(multiProtocols.getProtocol(protocol).subTypeStrings.value(subType, CPN_STR_UNKNOWN_ITEM))); +} diff --git a/companion/src/firmwares/multiprotocols.h b/companion/src/firmwares/multiprotocols.h index ea174cc28..9eded65b6 100644 --- a/companion/src/firmwares/multiprotocols.h +++ b/companion/src/firmwares/multiprotocols.h @@ -22,14 +22,14 @@ #define OPENTX_MULTI_H #include -#include -#include -#include +#include #define MM_RF_CUSTOM_SELECTED 0xff class Multiprotocols { + Q_DECLARE_TR_FUNCTIONS(Multiprotocols) + public: struct radio_mm_definition { @@ -46,7 +46,7 @@ class Multiprotocols const QStringList subTypeStrings; const QString optionsstr; - unsigned int numSubytes() const + unsigned int numSubTypes() const { return (unsigned int) subTypeStrings.length(); } @@ -72,6 +72,8 @@ class Multiprotocols } const MultiProtocolDefinition &getProtocol(int protocol) const; + static QString protocolToString(int protocol, bool custom = false); + static QString subTypeToString(int protocol, unsigned subType); private: diff --git a/companion/src/firmwares/opentx/opentxinterface.cpp b/companion/src/firmwares/opentx/opentxinterface.cpp index 8a33a926d..0f21488d6 100644 --- a/companion/src/firmwares/opentx/opentxinterface.cpp +++ b/companion/src/firmwares/opentx/opentxinterface.cpp @@ -611,6 +611,10 @@ int OpenTxFirmware::getCapability(::Capability capability) return (IS_ARM(board) ? 32 : 0); case NumModules: return (IS_ARM(board) ? 2 : 1); + case HasModuleR9MFlex: + return id.contains("flexr9m"); + case HasModuleR9MMini: + return IS_TARANIS_XLITE(board) && !id.contains("stdr9m"); case HasPPMStart: return (IS_ARM(board) ? true : false); case HastxCurrentCalibration: @@ -1083,6 +1087,7 @@ void addOpenTxFrskyOptions(OpenTxFirmware * firmware) firmware->addOption("nogvars", QCoreApplication::translate("Firmware", "Disable Global variables")); firmware->addOption("lua", QCoreApplication::translate("Firmware", "Enable Lua custom scripts screen")); firmware->addOption("luac", QCoreApplication::translate("Firmware", "Enable Lua compiler")); + firmware->addOption("flexr9m", QCoreApplication::translate("Firmware", "Enable non certified firmwares")); } void addOpenTxTaranisOptions(OpenTxFirmware * firmware) diff --git a/companion/src/modeledit/setup.cpp b/companion/src/modeledit/setup.cpp index 9f9665662..4f817ad51 100644 --- a/companion/src/modeledit/setup.cpp +++ b/companion/src/modeledit/setup.cpp @@ -189,9 +189,8 @@ ModulePanel::ModulePanel(QWidget * parent, ModelData & model, ModuleData & modul ui->setupUi(this); - QString label; + ui->label_module->setText(ModuleData::indexToString(moduleIdx, firmware)); if (moduleIdx < 0) { - label = tr("Trainer Port"); if (IS_HORUS(firmware->getBoard())) { ui->trainerMode->setItemData(TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE, 0, Qt::UserRole - 1); ui->trainerMode->setItemData(TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE, 0, Qt::UserRole - 1); @@ -209,25 +208,7 @@ ModulePanel::ModulePanel(QWidget * parent, ModelData & model, ModuleData & modul else { ui->label_trainerMode->hide(); ui->trainerMode->hide(); - if (firmware->getCapability(NumModules) > 1) { - if (IS_HORUS_OR_TARANIS(firmware->getBoard())) { - if (moduleIdx == 0) - label = tr("Internal Radio System"); - else - label = tr("External Radio Module"); - } - else { - if (moduleIdx == 0) - label = tr("Radio System"); - else - label = tr("Extra Radio System"); - } - } - else { - label = tr("Radio System"); - } } - ui->label_module->setText(label); // The protocols available on this board for (int i=0; igetBoard()) && i == PULSES_PXX_R9M) //TODO remove when mini are handled as a different module type ui->protocol->addItem("FrSky R9M Mini", (QVariant) i); else - ui->protocol->addItem(ModelPrinter::printModuleProtocol(i), (QVariant) i); + ui->protocol->addItem(ModuleData::protocolToString(i), i); if (i == module.protocol) ui->protocol->setCurrentIndex(ui->protocol->count()-1); } } for (int i=0; i<=MM_RF_PROTO_LAST; i++) { - ui->multiProtocol->addItem(ModelPrinter::printMultiRfProtocol(i, false), (QVariant) i); + ui->multiProtocol->addItem(Multiprotocols::protocolToString(i), i); } ui->btnGrpValueType->setId(ui->optPercent, FAILSAFE_DISPLAY_PERCENT); @@ -255,6 +236,7 @@ ModulePanel::ModulePanel(QWidget * parent, ModelData & model, ModuleData & modul update(); connect(ui->protocol, static_cast(&QComboBox::currentIndexChanged), this, &ModulePanel::onProtocolChanged); + connect(ui->multiSubType, static_cast(&QComboBox::currentIndexChanged), this, &ModulePanel::onSubTypeChanged); connect(ui->multiProtocol, static_cast(&QComboBox::currentIndexChanged), this, &ModulePanel::onMultiProtocolChanged); connect(this, &ModulePanel::channelsRangeChanged, this, &ModulePanel::setupFailsafes); connect(ui->btnGrpValueType, static_cast(&QButtonGroup::buttonClicked), this, &ModulePanel::onFailsafesDisplayValueTypeChanged); @@ -368,8 +350,10 @@ void ModulePanel::setupFailsafes() void ModulePanel::update() { + const PulsesProtocol protocol = (PulsesProtocol)module.protocol; + const Board::Type board = firmware->getBoard(); + const Multiprotocols::MultiProtocolDefinition & pdef = multiProtocols.getProtocol(module.multi.rfProtocol); unsigned int mask = 0; - PulsesProtocol protocol = (PulsesProtocol)module.protocol; unsigned int max_rx_num = 63; if (moduleIdx >= 0) { @@ -384,7 +368,7 @@ void ModulePanel::update() mask |= MASK_CHANNELS_RANGE | MASK_CHANNELS_COUNT; if (protocol==PULSES_PXX_XJT_X16 || protocol==PULSES_PXX_XJT_LR12 || protocol==PULSES_PXX_R9M) mask |= MASK_RX_NUMBER; - if ((IS_HORUS(firmware->getBoard()) || IS_TARANIS_XLITE(firmware->getBoard())) && moduleIdx==0) + if ((IS_HORUS(board) || IS_TARANIS_XLITE(board)) && moduleIdx==0) mask |= MASK_ANTENNA; break; case PULSES_LP45: @@ -400,7 +384,7 @@ void ModulePanel::update() break; case PULSES_PPM: mask |= MASK_PPM_FIELDS | MASK_SBUSPPM_FIELDS| MASK_CHANNELS_RANGE| MASK_CHANNELS_COUNT; - if (IS_9XRPRO(firmware->getBoard())) { + if (IS_9XRPRO(board)) { mask |= MASK_OPEN_DRAIN; } break; @@ -415,9 +399,9 @@ void ModulePanel::update() mask |= MASK_CHANNELS_COUNT; else module.channelsCount = 16; - if (multiProtocols.getProtocol(module.multi.rfProtocol).optionsstr != nullptr) + if (pdef.optionsstr != nullptr) mask |= MASK_MULTIOPTION; - if (multiProtocols.getProtocol(module.multi.rfProtocol).hasFailsafe) + if (pdef.hasFailsafe) mask |= MASK_FAILSAFES; break; case PULSES_OFF: @@ -426,7 +410,7 @@ void ModulePanel::update() break; } } - else if (IS_HORUS_OR_TARANIS(firmware->getBoard())) { + else if (IS_HORUS_OR_TARANIS(board)) { if (model->trainerMode == TRAINER_SLAVE_JACK) { mask |= MASK_PPM_FIELDS | MASK_CHANNELS_RANGE | MASK_CHANNELS_COUNT; } @@ -473,7 +457,7 @@ void ModulePanel::update() // Antenna selection on Horus and xlite ui->label_antenna->setVisible(mask & MASK_ANTENNA); ui->antennaMode->setVisible(mask & MASK_ANTENNA); - if IS_HORUS_X12S(firmware->getBoard()) { + if IS_HORUS_X12S(board) { ui->antennaMode->setItemText(1,tr("Ext. + Int")); } else { @@ -484,36 +468,13 @@ void ModulePanel::update() // R9M options ui->r9mPower->setVisible(mask & MASK_R9M); ui->label_r9mPower->setVisible(mask & MASK_R9M); - ui->warning_r9mPower->setVisible((mask & MASK_R9M) && module.subType == R9M_LBT); + ui->warning_r9mPower->setVisible((mask & MASK_R9M) && module.subType == MODULE_SUBTYPE_R9M_EU); + ui->warning_r9mFlex->setVisible((mask & MASK_R9M) && module.subType > MODULE_SUBTYPE_R9M_EU); if (mask & MASK_R9M) { const QSignalBlocker blocker(ui->r9mPower); ui->r9mPower->clear(); - Board::Type board = firmware->getBoard(); - if (IS_TARANIS_XLITE(board)) { - if (module.subType == R9M_FCC) { - ui->r9mPower->addItem(tr("100 mW - 16CH")); - } - else { - ui->r9mPower->addItem(tr("25 mW - 8CH")); - ui->r9mPower->addItem(tr("25 mW - 16CH")); - ui->r9mPower->addItem(tr("100 mW - 16CH, no telemetry")); - } - } - else { - if (module.subType == R9M_FCC) { - ui->r9mPower->addItem(tr("10 mW - 16CH")); - ui->r9mPower->addItem(tr("100 mW - 16CH")); - ui->r9mPower->addItem(tr("500 mW - 16CH")); - ui->r9mPower->addItem(tr("1000 mW - 16CH")); - } - else { - ui->r9mPower->addItem(tr("25 mW - 8CH")); - ui->r9mPower->addItem(tr("25 mW - 16CH")); - ui->r9mPower->addItem(tr("200 mW - 16CH")); - ui->r9mPower->addItem(tr("500 mW - 16CH")); - } - } + ui->r9mPower->addItems(ModuleData::powerValueStrings(module.subType, firmware)); ui->r9mPower->setCurrentIndex(module.pxx.power); } @@ -522,14 +483,17 @@ void ModulePanel::update() ui->multiSubType->setVisible(mask & MASK_SUBTYPES); if (mask & MASK_SUBTYPES) { unsigned numEntries = 2; // R9M FCC/EU + unsigned i = 0; if (mask & MASK_MULTIMODULE) - numEntries = (module.multi.customProto ? 8 : multiProtocols.getProtocol(module.multi.rfProtocol).numSubytes()); - + numEntries = (module.multi.customProto ? 8 : pdef.numSubTypes()); + else if (firmware->getCapability(HasModuleR9MFlex)) + i = 2; + numEntries += i; const QSignalBlocker blocker(ui->multiSubType); ui->multiSubType->clear(); - for (unsigned i=0; i < numEntries; i++) - ui->multiSubType->addItem(ModelPrinter::printModuleSubType(protocol, i, module.multi.rfProtocol, module.multi.customProto), i); - ui->multiSubType->setCurrentIndex(module.subType); + for ( ; i < numEntries; i++) + ui->multiSubType->addItem(module.subTypeToString(i), i); + ui->multiSubType->setCurrentIndex(ui->multiSubType->findData(module.subType)); } // Multi settings fields @@ -547,7 +511,6 @@ void ModulePanel::update() } if (mask & MASK_MULTIOPTION) { - auto pdef = multiProtocols.getProtocol(module.multi.rfProtocol); ui->optionValue->setMinimum(pdef.getOptionMin()); ui->optionValue->setMaximum(pdef.getOptionMax()); ui->optionValue->setValue(module.multi.optionValue); @@ -703,7 +666,7 @@ void ModulePanel::onMultiProtocolChanged(int index) if (!lock && module.multi.rfProtocol != (unsigned)index) { lock=true; module.multi.rfProtocol = (unsigned int) index; - unsigned int maxSubTypes = multiProtocols.getProtocol(index).numSubytes(); + unsigned int maxSubTypes = multiProtocols.getProtocol(index).numSubTypes(); if (module.multi.customProto) maxSubTypes=8; module.subType = std::min(module.subType, maxSubTypes -1); @@ -721,11 +684,12 @@ void ModulePanel::on_optionValue_editingFinished() } } -void ModulePanel::on_multiSubType_currentIndexChanged(int index) +void ModulePanel::onSubTypeChanged() { - if (!lock && module.subType != (unsigned)index) { + const unsigned type = ui->multiSubType->currentData().toUInt(); + if (!lock && module.subType != type) { lock=true; - module.subType = index; + module.subType = type; update(); emit modified(); lock = false; diff --git a/companion/src/modeledit/setup.h b/companion/src/modeledit/setup.h index fa70f922a..f9c815ef2 100644 --- a/companion/src/modeledit/setup.h +++ b/companion/src/modeledit/setup.h @@ -84,7 +84,7 @@ class ModulePanel : public ModelPanel void on_rxNumber_editingFinished(); void on_failsafeMode_currentIndexChanged(int value); void onMultiProtocolChanged(int index); - void on_multiSubType_currentIndexChanged(int index); + void onSubTypeChanged(); void on_autoBind_stateChanged(int state); void on_lowPower_stateChanged(int state); void on_r9mPower_currentIndexChanged(int index); diff --git a/companion/src/modeledit/setup_module.ui b/companion/src/modeledit/setup_module.ui index 87abbf264..4e94e0424 100644 --- a/companion/src/modeledit/setup_module.ui +++ b/companion/src/modeledit/setup_module.ui @@ -620,7 +620,7 @@ - + @@ -636,7 +636,7 @@ - + @@ -674,7 +674,7 @@ - + @@ -690,7 +690,7 @@ - + @@ -728,6 +728,50 @@ + + + + + + + + + 198 + 17 + 36 + + + + + + + + + 198 + 17 + 36 + + + + + + + + + 106 + 104 + 100 + + + + + + + + WARNING: Requires non-certified R9M firmware! + + + diff --git a/companion/src/modelprinter.cpp b/companion/src/modelprinter.cpp index 9d3b1214d..91a81eaa2 100644 --- a/companion/src/modelprinter.cpp +++ b/companion/src/modelprinter.cpp @@ -143,7 +143,7 @@ QString ModelPrinter::printBoolean(const bool val, const int typ) case BOOLEAN_ONOFF: return (val ? tr("ON") : tr("OFF")); default: - return tr("???"); + return CPN_STR_UNKNOWN_ITEM; } } @@ -180,94 +180,6 @@ QString ModelPrinter::printTrimIncrementMode() } } -QString ModelPrinter::printModuleProtocol(unsigned int protocol) -{ - static const char * strings[] = { - "OFF", - "PPM", - "Silverlit A", "Silverlit B", "Silverlit C", - "CTP1009", - "LP45", "DSM2", "DSMX", - "PPM16", "PPMsim", - "FrSky XJT (D16)", "FrSky XJT (D8)", "FrSky XJT (LR12)", "FrSky DJT", - "Crossfire", - "DIY Multiprotocol Module", - "FrSky R9M Module", - "SBUS output at VBat" - }; - - return CHECK_IN_ARRAY(strings, protocol); -} - -QString ModelPrinter::printMultiRfProtocol(int rfProtocol, bool custom) -{ - static const char * strings[] = { - "FlySky", "Hubsan", "FrSky", "Hisky", "V2x2", "DSM", "Devo", "YD717", "KN", "SymaX", "SLT", "CX10", "CG023", - "Bayang", "ESky", "MT99XX", "MJXQ", "Shenqi", "FY326", "SFHSS", "J6 PRO","FQ777","Assan","Hontai","OLRS", - "FlySky AFHDS2A", "Q2x2", "Walkera", "Q303", "GW008", "DM002", "CABELL", "Esky 150", "H8 3D", "Corona", "CFlie" - }; - if (custom) - return QObject::tr("Custom - proto %1)").arg(QString::number(rfProtocol)); - else - return CHECK_IN_ARRAY(strings, rfProtocol); -} - -QString ModelPrinter::printMultiSubType(unsigned rfProtocol, bool custom, unsigned int subType) { - /* custom protocols */ - - if (custom) - rfProtocol = MM_RF_CUSTOM_SELECTED; - - Multiprotocols::MultiProtocolDefinition pdef = multiProtocols.getProtocol(rfProtocol); - - if (subType < (unsigned int) pdef.subTypeStrings.size()) - return qApp->translate("Multiprotocols", qPrintable(pdef.subTypeStrings[subType])); - else - return "???"; -} - -QString ModelPrinter::printR9MPowerValue(unsigned subType, unsigned val, bool telem) -{ - QStringList strFCC; - QStringList strLBT; - - if (IS_TARANIS_XLITE(firmware->getBoard())) { - strFCC = QStringList() << tr("100mW - 16CH"); - strLBT = QStringList() << tr("25mW - 8CH") << tr("25mW - 16CH") << tr("100mW 16CH"); - } - else { - strFCC = QStringList() << tr("10mW") << tr("100mW") << tr("500mW") << tr("1W"); - strLBT = QStringList() << tr("25mW - 8CH") << tr("25mW - 16CH") << tr("200mW 16CH") << tr("500mW 16CH"); - } - - - if (subType == R9M_FCC && (int)val < strFCC.size()) - return strFCC.at(val); - else if (subType == R9M_LBT) - return (telem ? strLBT.at(0) : strLBT.at(1)); - else - return "???"; -} - -QString ModelPrinter::printModuleSubType(unsigned protocol, unsigned subType, unsigned rfProtocol, bool custom) -{ - static const char * strings[] = { - "FCC", - "LBT(EU)" - }; - - switch (protocol) { - case PULSES_MULTIMODULE: - return printMultiSubType(rfProtocol, custom, subType); - - case PULSES_PXX_R9M: - return CHECK_IN_ARRAY(strings, subType); - - default: - return "???"; - } -} - QString ModelPrinter::printModule(int idx) { QStringList str; @@ -286,7 +198,7 @@ QString ModelPrinter::printModule(int idx) result = str.join(" "); } else { - str << printLabelValue(tr("Protocol"), printModuleProtocol(module.protocol)); + str << printLabelValue(tr("Protocol"), ModuleData::protocolToString(module.protocol)); if (module.protocol) { str << printLabelValue(tr("Channels"), QString("%1-%2").arg(module.channelsStart + 1).arg(module.channelsStart + module.channelsCount)); if (module.protocol == PULSES_PPM || module.protocol == PULSES_SBUS) { @@ -300,13 +212,13 @@ QString ModelPrinter::printModule(int idx) str << printLabelValue(tr("Receiver"), QString::number(module.modelId)); } if (module.protocol == PULSES_MULTIMODULE) { - str << printLabelValue(tr("Radio protocol"), printMultiRfProtocol(module.multi.rfProtocol, module.multi.customProto)); - str << printLabelValue(tr("Subtype"), printMultiSubType(module.multi.rfProtocol, module.multi.customProto, module.subType)); + str << printLabelValue(tr("Radio protocol"), module.rfProtocolToString()); + str << printLabelValue(tr("Subtype"), module.subTypeToString()); str << printLabelValue(tr("Option value"), QString::number(module.multi.optionValue)); } if (module.protocol == PULSES_PXX_R9M) { - str << printLabelValue(tr("Sub Type"), printModuleSubType(module.protocol, module.subType)); - str << printLabelValue(tr("RF Output Power"), printR9MPowerValue(module.subType, module.pxx.power, module.pxx.sport_out)); + str << printLabelValue(tr("Sub Type"), module.subTypeToString()); + str << printLabelValue(tr("RF Output Power"), module.powerValueToString(firmware)); str << printLabelValue(tr("Telemetry"), printBoolean(module.pxx.sport_out, BOOLEAN_ENABLEDISABLE)); } } @@ -339,7 +251,7 @@ QString ModelPrinter::printTrainerMode() result = tr("Master/SBUS in battery compartment"); break; default: - result = tr("????"); + result = CPN_STR_UNKNOWN_ITEM; } return result; } @@ -358,7 +270,7 @@ QString ModelPrinter::printHeliSwashType () case HELI_SWASH_TYPE_NONE: return tr("Off"); default: - return "???"; + return CPN_STR_UNKNOWN_ITEM; } } @@ -987,7 +899,7 @@ QString ModelPrinter::printPotsWarningMode() case 2: return tr("Auto"); default: - return tr("????"); + return CPN_STR_UNKNOWN_ITEM; } } @@ -1031,7 +943,7 @@ QString ModelPrinter::printFailsafeMode(unsigned int fsmode) case FAILSAFE_RECEIVER: return tr("Receiver"); default: - return tr("???"); + return CPN_STR_UNKNOWN_ITEM; } } @@ -1047,7 +959,7 @@ QString ModelPrinter::printTimerCountdownBeep(unsigned int countdownBeep) case TimerData::COUNTDOWN_HAPTIC: return tr("Haptic"); default: - return tr("???"); + return CPN_STR_UNKNOWN_ITEM; } } @@ -1061,7 +973,7 @@ QString ModelPrinter::printTimerPersistent(unsigned int persistent) case 2: return tr("Manual reset"); default: - return tr("???"); + return CPN_STR_UNKNOWN_ITEM; } } @@ -1097,26 +1009,13 @@ QString ModelPrinter::printTrimsDisplayMode() case 2: return tr("Always"); default: - return tr("???"); + return CPN_STR_UNKNOWN_ITEM; } } QString ModelPrinter::printModuleType(int idx) { - if (idx < 0) - return tr("Trainer Port"); - else if (firmware->getCapability(NumModules) > 1) - if (IS_HORUS_OR_TARANIS(firmware->getBoard())) - if (idx == 0) - return tr("Internal Radio System"); - else - return tr("External Radio Module"); - else if (idx == 0) - return tr("Radio System"); - else - return tr("Extra Radio System"); - else - return tr("Radio System"); + return ModuleData::indexToString(idx, firmware); } QString ModelPrinter::printPxxPower(int power) @@ -1173,7 +1072,7 @@ QString ModelPrinter::printTelemetryProtocol(unsigned int val) case 2: return tr("FrSky D (cable)"); default: - return tr("???"); + return CPN_STR_UNKNOWN_ITEM; } } @@ -1207,7 +1106,7 @@ QString ModelPrinter::printVarioSource(unsigned int val) case TELEMETRY_VARIO_SOURCE_A2: return tr("A2"); default: - return tr("???"); + return CPN_STR_UNKNOWN_ITEM; } } @@ -1232,7 +1131,7 @@ QString ModelPrinter::printVoltsSource(unsigned int val) case TELEMETRY_VOLTS_SOURCE_CELLS: return tr("Cells"); default: - return tr("???"); + return CPN_STR_UNKNOWN_ITEM; } } @@ -1252,7 +1151,7 @@ QString ModelPrinter::printCurrentSource(unsigned int val) case TELEMETRY_CURRENT_SOURCE_FAS: return tr("FAS"); default: - return tr("???"); + return CPN_STR_UNKNOWN_ITEM; } } @@ -1274,7 +1173,7 @@ QString ModelPrinter::printSensorType(unsigned int val) case SensorData::TELEM_TYPE_CALCULATED: return tr("Calculated"); default: - return tr("???"); + return CPN_STR_UNKNOWN_ITEM; } } @@ -1300,7 +1199,7 @@ QString ModelPrinter::printSensorFormula(unsigned int val) case SensorData::TELEM_FORMULA_DIST: return tr("Distance"); default: - return tr("???"); + return CPN_STR_UNKNOWN_ITEM; } } @@ -1518,7 +1417,7 @@ QString ModelPrinter::printTelemetryScreenType(unsigned int val) case TelemetryScreenEnum::TELEMETRY_SCREEN_SCRIPT: return tr("Script"); default: - return tr("???"); + return CPN_STR_UNKNOWN_ITEM; } } diff --git a/companion/src/modelprinter.h b/companion/src/modelprinter.h index fd1df94a2..053ce85a9 100644 --- a/companion/src/modelprinter.h +++ b/companion/src/modelprinter.h @@ -37,7 +37,7 @@ class CurveImage public: CurveImage(); void drawCurve(const CurveData & curve, QColor color); - const QImage & get() const { return image; }; + const QImage & get() const { return image; } protected: int size; @@ -57,11 +57,6 @@ class ModelPrinter: public QObject QString printEEpromSize(); QString printTrimIncrementMode(); QString printThrottle(); - static QString printModuleProtocol(unsigned int protocol); - static QString printMultiRfProtocol(int rfProtocol, bool custom); - QString printR9MPowerValue(unsigned subType, unsigned val, bool telem); - static QString printMultiSubType(unsigned rfProtocol, bool custom, unsigned int subType); - static QString printModuleSubType(unsigned protocol, unsigned subType, unsigned rfProtocol = 0, bool custom = false); QString printFlightModeSwitch(const RawSwitch & swtch); QString printFlightModeName(int index); QString printFlightModes(unsigned int flightModes); diff --git a/radio/src/CMakeLists.txt b/radio/src/CMakeLists.txt index 35b9922fd..b620c7f86 100644 --- a/radio/src/CMakeLists.txt +++ b/radio/src/CMakeLists.txt @@ -46,6 +46,7 @@ option(TRACE_LUA_INTERNALS "Turn on traces for Lua internals" OFF) option(FRSKY_STICKS "Reverse sticks for FrSky sticks" OFF) option(NANO "Use nano newlib and binalloc") option(NIGHTLY_BUILD_WARNING "Warn this is a nightly build" OFF) +option(MODULE_R9M_FLEX_FW "Add R9M options for non certified firmwwares" OFF) # since we reset all default CMAKE compiler flags for firmware builds, provide an alternate way for user to specify additional flags. set(FIRMWARE_C_FLAGS "" CACHE STRING "Additional flags for firmware target c compiler (note: all CMAKE_C_FLAGS[_*] are ignored for firmware/bootloader).") @@ -311,6 +312,10 @@ if(NIGHTLY_BUILD_WARNING) add_definitions(-DNIGHTLY_BUILD_WARNING) endif(NIGHTLY_BUILD_WARNING) +if(MODULE_R9M_FLEX_FW) + add_definitions(-DMODULE_R9M_FLEX_FW) +endif() + set(SRC ${SRC} opentx.cpp diff --git a/radio/src/gui/128x64/model_setup.cpp b/radio/src/gui/128x64/model_setup.cpp index 4647a225f..1c88ae28a 100644 --- a/radio/src/gui/128x64/model_setup.cpp +++ b/radio/src/gui/128x64/model_setup.cpp @@ -92,7 +92,6 @@ enum MenuModelSetupItems { #if defined(PCBSKY9X) && defined(REVX) ITEM_MODEL_EXTERNAL_MODULE_OUTPUT_TYPE, #endif - ITEM_MODEL_EXTERNAL_MODULE_FAILSAFE, ITEM_MODEL_EXTERNAL_MODULE_OPTIONS, #if defined(MULTIMODULE) ITEM_MODEL_EXTERNAL_MODULE_AUTOBIND, @@ -103,6 +102,7 @@ enum MenuModelSetupItems { ITEM_MODEL_EXTRA_MODULE_CHANNELS, ITEM_MODEL_EXTRA_MODULE_BIND, #endif + ITEM_MODEL_EXTERNAL_MODULE_FAILSAFE, #if defined(PCBX7) ITEM_MODEL_TRAINER_LABEL, ITEM_MODEL_TRAINER_MODE, @@ -272,11 +272,11 @@ void menuModelSetup(event_t event) EXTERNAL_MODULE_CHANNELS_ROWS, EXTERNAL_MODULE_BIND_ROWS(), OUTPUT_TYPE_ROWS() - FAILSAFE_ROWS(EXTERNAL_MODULE), EXTERNAL_MODULE_OPTION_ROW, MULTIMODULE_MODULE_ROWS EXTERNAL_MODULE_POWER_ROW, EXTRA_MODULE_ROWS + FAILSAFE_ROWS(EXTERNAL_MODULE), TRAINER_ROWS }); #else MENU_TAB({ HEADER_LINE_COLUMNS 0, TIMER_ROWS, TIMER_ROWS, TIMER_ROWS, 0, 1, 0, 0, 0, 0, 0, LABEL(PreflightCheck), 0, 0, NUM_SWITCHES-1, NUM_STICKS+NUM_POTS+NUM_SLIDERS+NUM_ROTARY_ENCODERS-1, 0, @@ -287,11 +287,11 @@ void menuModelSetup(event_t event) EXTERNAL_MODULE_CHANNELS_ROWS, EXTERNAL_MODULE_BIND_ROWS(), OUTPUT_TYPE_ROWS() - FAILSAFE_ROWS(EXTERNAL_MODULE), EXTERNAL_MODULE_OPTION_ROW, MULTIMODULE_MODULE_ROWS EXTERNAL_MODULE_POWER_ROW, EXTRA_MODULE_ROWS + FAILSAFE_ROWS(EXTERNAL_MODULE), TRAINER_ROWS }); #endif @@ -757,8 +757,16 @@ void menuModelSetup(event_t event) case 1: if (isModuleDSM2(EXTERNAL_MODULE)) CHECK_INCDEC_MODELVAR(event, g_model.moduleData[EXTERNAL_MODULE].rfProtocol, DSM2_PROTO_LP45, DSM2_PROTO_DSMX); - else if (isModuleR9M(EXTERNAL_MODULE)) - CHECK_INCDEC_MODELVAR(event, g_model.moduleData[EXTERNAL_MODULE].subType, MODULE_SUBTYPE_R9M_FCC, MODULE_SUBTYPE_R9M_LBT); + else if (isModuleR9M(EXTERNAL_MODULE)) { + uint8_t newR9MType = checkIncDec(event, g_model.moduleData[EXTERNAL_MODULE].subType, MODULE_SUBTYPE_R9M_FCC, MODULE_SUBTYPE_R9M_LAST, EE_MODEL, isR9MModeAvailable); + if (newR9MType != g_model.moduleData[EXTERNAL_MODULE].subType && newR9MType > MODULE_SUBTYPE_R9M_EU) { + POPUP_WARNING(STR_R9MFLEXWARN1); + const char * w = STR_R9MFLEXWARN2; + SET_WARNING_INFO(w, strlen(w), 0); + } + g_model.moduleData[EXTERNAL_MODULE].subType = newR9MType; + } + #if defined(MULTIMODULE) else if (isModuleMultimodule(EXTERNAL_MODULE)) { int multiRfProto = g_model.moduleData[EXTERNAL_MODULE].multi.customProto == 1 ? MM_RF_PROTO_CUSTOM : g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(false); @@ -1204,7 +1212,7 @@ void menuModelSetup(event_t event) uint8_t moduleIdx = CURRENT_MODULE_EDITED(k); if (isModuleR9M(moduleIdx)) { lcdDrawTextAlignedLeft(y, TR_MULTI_RFPOWER); - if (isModuleR9M_FCC(moduleIdx)) { + if (IS_MODULE_R9M_FCC_VARIANT(moduleIdx)) { g_model.moduleData[moduleIdx].pxx.power = min((uint8_t)g_model.moduleData[moduleIdx].pxx.power, (uint8_t)R9M_FCC_POWER_MAX); // Lite FCC has only one setting #if defined(PCBXLITE) && !defined(MODULE_R9M_FULLSIZE) // R9M lite FCC has only one power value, so displayed for info only lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_R9M_FCC_POWER_VALUES, g_model.moduleData[moduleIdx].pxx.power, LEFT); diff --git a/radio/src/gui/212x64/model_setup.cpp b/radio/src/gui/212x64/model_setup.cpp index 7ea13ad9a..ec5c94b7c 100644 --- a/radio/src/gui/212x64/model_setup.cpp +++ b/radio/src/gui/212x64/model_setup.cpp @@ -771,8 +771,15 @@ void menuModelSetup(event_t event) case 1: if (isModuleDSM2(EXTERNAL_MODULE)) CHECK_INCDEC_MODELVAR(event, g_model.moduleData[EXTERNAL_MODULE].rfProtocol, DSM2_PROTO_LP45, DSM2_PROTO_DSMX); - else if (isModuleR9M(EXTERNAL_MODULE)) - CHECK_INCDEC_MODELVAR(event, g_model.moduleData[EXTERNAL_MODULE].subType, MODULE_SUBTYPE_R9M_FCC, MODULE_SUBTYPE_R9M_LBT); + else if (isModuleR9M(EXTERNAL_MODULE)) { + uint8_t newR9MType = checkIncDec(event, g_model.moduleData[EXTERNAL_MODULE].subType, MODULE_SUBTYPE_R9M_FCC, MODULE_SUBTYPE_R9M_LAST, EE_MODEL, isR9MModeAvailable); + if (newR9MType != g_model.moduleData[EXTERNAL_MODULE].subType && newR9MType > MODULE_SUBTYPE_R9M_EU) { + POPUP_WARNING(STR_R9MFLEXWARN1); + const char * w = STR_R9MFLEXWARN2; + SET_WARNING_INFO(w, strlen(w), 0); + } + g_model.moduleData[EXTERNAL_MODULE].subType = newR9MType; + } #if defined(MULTIMODULE) else if (isModuleMultimodule(EXTERNAL_MODULE)) { int multiRfProto = g_model.moduleData[EXTERNAL_MODULE].multi.customProto == 1 ? MM_RF_PROTO_CUSTOM : g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(false); @@ -1143,7 +1150,7 @@ void menuModelSetup(event_t event) uint8_t moduleIdx = CURRENT_MODULE_EDITED(k); if (isModuleR9M(moduleIdx)) { lcdDrawTextAlignedLeft(y, TR_MULTI_RFPOWER); - if(isModuleR9M_FCC(moduleIdx)) { + if(IS_MODULE_R9M_FCC_VARIANT(moduleIdx)) { lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_R9M_FCC_POWER_VALUES, g_model.moduleData[moduleIdx].pxx.power, LEFT | attr); if (attr) CHECK_INCDEC_MODELVAR(event, g_model.moduleData[moduleIdx].pxx.power, 0, R9M_FCC_POWER_MAX); diff --git a/radio/src/gui/480x272/model_setup.cpp b/radio/src/gui/480x272/model_setup.cpp index ef2f254ca..d449cc25f 100644 --- a/radio/src/gui/480x272/model_setup.cpp +++ b/radio/src/gui/480x272/model_setup.cpp @@ -293,7 +293,7 @@ bool menuModelSetup(event_t event) if (event == EVT_ENTRY) { reusableBuffer.modelsetup.r9mPower = g_model.moduleData[EXTERNAL_MODULE].pxx.power; } - + if (menuEvent) { moduleFlag[0] = 0; moduleFlag[1] = 0; @@ -728,8 +728,15 @@ bool menuModelSetup(event_t event) case 1: if (isModuleDSM2(EXTERNAL_MODULE)) CHECK_INCDEC_MODELVAR(event, g_model.moduleData[EXTERNAL_MODULE].rfProtocol, DSM2_PROTO_LP45, DSM2_PROTO_DSMX); - else if (isModuleR9M(EXTERNAL_MODULE)) - CHECK_INCDEC_MODELVAR(event, g_model.moduleData[EXTERNAL_MODULE].subType, MODULE_SUBTYPE_R9M_FCC, MODULE_SUBTYPE_R9M_LBT); + else if (isModuleR9M(EXTERNAL_MODULE)) { + uint8_t newR9MType = checkIncDec(event, g_model.moduleData[EXTERNAL_MODULE].subType, MODULE_SUBTYPE_R9M_FCC, MODULE_SUBTYPE_R9M_LAST, EE_MODEL, isR9MModeAvailable); + if (newR9MType != g_model.moduleData[EXTERNAL_MODULE].subType && newR9MType > MODULE_SUBTYPE_R9M_EU) { + POPUP_WARNING(STR_R9MFLEXWARN1); + const char * w = STR_R9MFLEXWARN2; + SET_WARNING_INFO(w, strlen(w), 0); + } + g_model.moduleData[EXTERNAL_MODULE].subType = newR9MType; + } #if defined(MULTIMODULE) else if (isModuleMultimodule(EXTERNAL_MODULE)) { int multiRfProto = g_model.moduleData[EXTERNAL_MODULE].multi.customProto == 1 ? MM_RF_PROTO_CUSTOM : g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(false); @@ -1082,7 +1089,7 @@ bool menuModelSetup(event_t event) uint8_t moduleIdx = CURRENT_MODULE_EDITED(k); if (isModuleR9M(moduleIdx)) { lcdDrawText(MENUS_MARGIN_LEFT, y, STR_MULTI_RFPOWER); - if(isModuleR9M_FCC(moduleIdx)) { + if(IS_MODULE_R9M_FCC_VARIANT(moduleIdx)) { lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_R9M_FCC_POWER_VALUES, g_model.moduleData[moduleIdx].pxx.power, LEFT | attr); if (attr) CHECK_INCDEC_MODELVAR(event, g_model.moduleData[moduleIdx].pxx.power, 0, R9M_FCC_POWER_MAX); @@ -1170,7 +1177,7 @@ bool menuModelSetup(event_t event) } } } - + return true; } diff --git a/radio/src/gui/gui_common.h b/radio/src/gui/gui_common.h index bec8e1d6b..2303a6341 100644 --- a/radio/src/gui/gui_common.h +++ b/radio/src/gui/gui_common.h @@ -53,6 +53,7 @@ bool isSwitchAvailableInLogicalSwitches(int swtch); bool isSwitchAvailableInCustomFunctions(int swtch); bool isSwitchAvailableInMixes(int swtch); bool isSwitchAvailableInTimers(int swtch); +bool isR9MModeAvailable(int mode); bool isModuleAvailable(int module); bool isRfProtocolAvailable(int protocol); bool isTelemetryProtocolAvailable(int protocol); @@ -155,7 +156,7 @@ const mm_protocol_definition *getMultiProtocolDefinition (uint8_t protocol); #define FAILSAFE_ROWS(x) ((isModuleXJT(x) && HAS_RF_PROTOCOL_FAILSAFE(g_model.moduleData[x].rfProtocol)) || MULTIMODULE_HASFAILSAFE(x) || isModuleR9M(x)) ? (g_model.moduleData[x].failsafeMode==FAILSAFE_CUSTOM ? (uint8_t)1 : (uint8_t)0) : HIDDEN_ROW #define EXTERNAL_MODULE_OPTION_ROW (isModuleR9M(EXTERNAL_MODULE) || isModuleSBUS(EXTERNAL_MODULE) ? TITLE_ROW : MULTIMODULE_OPTIONS_ROW) -#define EXTERNAL_MODULE_POWER_ROW (isModuleMultimodule(EXTERNAL_MODULE) || isModuleR9M(EXTERNAL_MODULE)) ? (uint8_t) 0 : HIDDEN_ROW +#define EXTERNAL_MODULE_POWER_ROW (isModuleMultimodule(EXTERNAL_MODULE) || isModuleR9M(EXTERNAL_MODULE)) ? (IS_MODULE_R9M_FCC_VARIANT(EXTERNAL_MODULE) ? TITLE_ROW : (uint8_t) 0) : HIDDEN_ROW void editStickHardwareSettings(coord_t x, coord_t y, int idx, event_t event, LcdFlags flags); diff --git a/radio/src/gui/gui_common_arm.cpp b/radio/src/gui/gui_common_arm.cpp index db231bef5..44a0d6f89 100644 --- a/radio/src/gui/gui_common_arm.cpp +++ b/radio/src/gui/gui_common_arm.cpp @@ -486,6 +486,14 @@ bool isSourceAvailableInResetSpecialFunction(int index) } } +bool isR9MModeAvailable(int mode) +{ +#if defined(MODULE_R9M_FLEX_FW) + return mode >= MODULE_SUBTYPE_R9M_EUPLUS; +#else + return mode <= MODULE_SUBTYPE_R9M_EU; +#endif +} bool isModuleAvailable(int module) { diff --git a/radio/src/myeeprom.h b/radio/src/myeeprom.h index 7b930848c..c8a2d9af0 100644 --- a/radio/src/myeeprom.h +++ b/radio/src/myeeprom.h @@ -357,7 +357,10 @@ enum XJTRFProtocols { enum R9MSubTypes { MODULE_SUBTYPE_R9M_FCC, - MODULE_SUBTYPE_R9M_LBT, + MODULE_SUBTYPE_R9M_EU, + MODULE_SUBTYPE_R9M_EUPLUS, + MODULE_SUBTYPE_R9M_AUPLUS, + MODULE_SUBTYPE_R9M_LAST=MODULE_SUBTYPE_R9M_AUPLUS }; enum MultiModuleRFProtocols { diff --git a/radio/src/pulses/pulses_arm.h b/radio/src/pulses/pulses_arm.h index 060700448..7063b90ad 100644 --- a/radio/src/pulses/pulses_arm.h +++ b/radio/src/pulses/pulses_arm.h @@ -216,8 +216,8 @@ inline void SEND_FAILSAFE_1S() void setCustomFailsafe(uint8_t moduleIndex); #if defined(PCBXLITE) && !defined(MODULE_R9M_FULLSIZE) -#define LEN_R9M_REGION "\007" -#define TR_R9M_REGION "FCC\0 ""LBT(EU)" +#define LEN_R9M_REGION "\003" +#define TR_R9M_REGION "FCC""EU\0""EU+""AU+" #define LEN_R9M_FCC_POWER_VALUES "\010" #define LEN_R9M_LBT_POWER_VALUES "\015" #define TR_R9M_FCC_POWER_VALUES "(100 mW)" @@ -240,8 +240,8 @@ enum R9MLBTPowerValues { #else -#define LEN_R9M_REGION "\007" -#define TR_R9M_REGION "FCC\0 ""LBT(EU)" +#define LEN_R9M_REGION "\003" +#define TR_R9M_REGION "FCC""EU\0""EU+""AU+" #define LEN_R9M_FCC_POWER_VALUES "\006" #define LEN_R9M_LBT_POWER_VALUES "\013" #define TR_R9M_FCC_POWER_VALUES "10 mW\0" "100 mW" "500 mW" "1 W\0" diff --git a/radio/src/pulses/pxx_arm.cpp b/radio/src/pulses/pxx_arm.cpp index cf229aeb3..790f4e8dd 100644 --- a/radio/src/pulses/pxx_arm.cpp +++ b/radio/src/pulses/pxx_arm.cpp @@ -412,7 +412,9 @@ inline void setupFramePXX(uint8_t port, uint8_t sendUpperChannels) extra_flags |= (g_model.moduleData[port].pxx.receiver_telem_off << 1); extra_flags |= (g_model.moduleData[port].pxx.receiver_channel_9_16 << 2); if (isModuleR9M(port)) { - extra_flags |= (min(g_model.moduleData[port].pxx.power, isModuleR9M_FCC(port) ? (uint8_t)R9M_FCC_POWER_MAX : (uint8_t)R9M_LBT_POWER_MAX) << 3); + extra_flags |= (min(g_model.moduleData[port].pxx.power, IS_MODULE_R9M_FCC_VARIANT(port) ? (uint8_t)R9M_FCC_POWER_MAX : (uint8_t)R9M_LBT_POWER_MAX) << 3); + if(IS_MODULE_R9M_EUPLUS(port)) + extra_flags |= (1 << 6); } // Disable S.PORT if internal module is active diff --git a/radio/src/translations.cpp b/radio/src/translations.cpp index 784b47c05..6648f1729 100644 --- a/radio/src/translations.cpp +++ b/radio/src/translations.cpp @@ -582,6 +582,8 @@ const char STR_BLCOLOR[] = TR_BLCOLOR; const char STR_ANTENNASELECTION[] = TR_ANTENNASELECTION; const char STR_ANTENNACONFIRM1[] = TR_ANTENNACONFIRM1; const char STR_ANTENNACONFIRM2[] = TR_ANTENNACONFIRM2; + const char STR_R9MFLEXWARN1[] PROGMEM = TR_R9MFLEXWARN1; + const char STR_R9MFLEXWARN2[] PROGMEM = TR_R9MFLEXWARN2; const char STR_SET[] = TR_SET; const char STR_PREFLIGHT[] = TR_PREFLIGHT; const char STR_CHECKLIST[] = TR_CHECKLIST; diff --git a/radio/src/translations.h b/radio/src/translations.h index 652661d68..2ec3981dd 100644 --- a/radio/src/translations.h +++ b/radio/src/translations.h @@ -841,6 +841,8 @@ extern const char STR_BLCOLOR[]; extern const char STR_ANTENNASELECTION[]; extern const char STR_ANTENNACONFIRM1[]; extern const char STR_ANTENNACONFIRM2[]; + extern const char STR_R9MFLEXWARN1[]; + extern const char STR_R9MFLEXWARN2[]; extern const char STR_SET[]; extern const char STR_PREFLIGHT[]; extern const char STR_CHECKLIST[]; diff --git a/radio/src/translations/cz.h.txt b/radio/src/translations/cz.h.txt index 3e96174e1..f8868bc5e 100644 --- a/radio/src/translations/cz.h.txt +++ b/radio/src/translations/cz.h.txt @@ -973,6 +973,8 @@ #define TR_ANTENNASELECTION TR(INDENT "Antenna", INDENT "Volba antény") #define TR_ANTENNACONFIRM1 "Opravdu přepnout?" #define TR_ANTENNACONFIRM2 TR("Check antenna", "Ujisti se že je anténa připojena!") +#define TR_R9MFLEXWARN1 "Requires non" +#define TR_R9MFLEXWARN2 "certified R9M firm." #define TR_LOWALARM INDENT "Nízký Alarm" #define TR_CRITICALALARM INDENT "Kritický Alarm" #define TR_RSSIALARM_WARN TR("RSSI","TELEMETRY RSSI") diff --git a/radio/src/translations/de.h.txt b/radio/src/translations/de.h.txt index b9597aa7f..eb60f2f3b 100644 --- a/radio/src/translations/de.h.txt +++ b/radio/src/translations/de.h.txt @@ -978,6 +978,8 @@ #define TR_ANTENNASELECTION TR(INDENT "Antenna", INDENT "Antenne auswählen") #define TR_ANTENNACONFIRM1 "Ant. umschalten" #define TR_ANTENNACONFIRM2 TR("Check antenna", "Ist eine externe Antenne installiert?") +#define TR_R9MFLEXWARN1 "Requires non" +#define TR_R9MFLEXWARN2 "certified R9M firm." #define TR_LOWALARM INDENT "Warnungsschwelle" #define TR_CRITICALALARM INDENT "Kritischer Alarm" #define TR_RSSIALARM_WARN "Telemetry" diff --git a/radio/src/translations/en.h.txt b/radio/src/translations/en.h.txt index 9bb5ecd6e..e1fe3c037 100644 --- a/radio/src/translations/en.h.txt +++ b/radio/src/translations/en.h.txt @@ -981,6 +981,8 @@ #define TR_ANTENNASELECTION TR(INDENT "Antenna", TR(INDENT "Antenna", INDENT "Antenna selection")) #define TR_ANTENNACONFIRM1 "Really switch?" #define TR_ANTENNACONFIRM2 TR("Check antenna", "Make sure antenna is installed!") +#define TR_R9MFLEXWARN1 "Requires non" +#define TR_R9MFLEXWARN2 "certified R9M firm." #define TR_LOWALARM INDENT "Low alarm" #define TR_CRITICALALARM INDENT "Critical alarm" #define TR_RSSIALARM_WARN "RSSI" diff --git a/radio/src/translations/es.h.txt b/radio/src/translations/es.h.txt index c12dce7b5..4b6d20d3e 100644 --- a/radio/src/translations/es.h.txt +++ b/radio/src/translations/es.h.txt @@ -984,6 +984,8 @@ #define TR_ANTENNASELECTION TR(INDENT "Antenna", TR(INDENT "Antenna", INDENT "Antenna selection")) #define TR_ANTENNACONFIRM1 "Really switch?" #define TR_ANTENNACONFIRM2 TR("Check antenna", "Make sure antenna is installed!") +#define TR_R9MFLEXWARN1 "Requires non" +#define TR_R9MFLEXWARN2 "certified R9M firm." #define TR_LOWALARM INDENT "Alarma baja" #define TR_CRITICALALARM INDENT "Alarma Critica" #define TR_RSSIALARM_WARN TR("RSSI","TELEMETRY RSSI") diff --git a/radio/src/translations/fi.h.txt b/radio/src/translations/fi.h.txt index 659ffc79d..9c514d70b 100644 --- a/radio/src/translations/fi.h.txt +++ b/radio/src/translations/fi.h.txt @@ -976,6 +976,8 @@ #define TR_ANTENNASELECTION TR(INDENT "Antenna", TR(INDENT "Antenna", INDENT "Antenna selection")) #define TR_ANTENNACONFIRM1 "Really switch?" #define TR_ANTENNACONFIRM2 TR("Check antenna", "Make sure antenna is installed!") +#define TR_R9MFLEXWARN1 "Requires non" +#define TR_R9MFLEXWARN2 "certified R9M firm." #define TR_LOWALARM INDENT "Low Alarm" #define TR_CRITICALALARM INDENT "Critical Alarm" #define TR_RSSIALARM_WARN TR("RSSI","TELEMETRY RSSI") diff --git a/radio/src/translations/fr.h.txt b/radio/src/translations/fr.h.txt index c23d05e2b..7d03ed5df 100644 --- a/radio/src/translations/fr.h.txt +++ b/radio/src/translations/fr.h.txt @@ -988,6 +988,8 @@ #define TR_ANTENNASELECTION TR(INDENT "Antenne", INDENT "Choix antenne") #define TR_ANTENNACONFIRM1 "Vraiment changer?" #define TR_ANTENNACONFIRM2 TR("Vérif antenne", "Installer l'antenne d'abord!") +#define TR_R9MFLEXWARN1 "Requires non" +#define TR_R9MFLEXWARN2 "certified R9M firm." #define TR_LOWALARM INDENT "Alarme basse" #define TR_CRITICALALARM INDENT "Alarme critique" #define TR_RSSIALARM_WARN TR("RSSI", "TELEMETRIE") diff --git a/radio/src/translations/it.h.txt b/radio/src/translations/it.h.txt index f503d13c7..068feba07 100644 --- a/radio/src/translations/it.h.txt +++ b/radio/src/translations/it.h.txt @@ -978,6 +978,8 @@ #define TR_ANTENNASELECTION TR(INDENT "Antenna", INDENT "Antenna selection") #define TR_ANTENNACONFIRM1 "Really switch?" #define TR_ANTENNACONFIRM2 TR("Check antenna", "Make sure antenna is installed!") +#define TR_R9MFLEXWARN1 "Requires non" +#define TR_R9MFLEXWARN2 "certified R9M firm." #define TR_LOWALARM INDENT "Allarme Basso" #define TR_CRITICALALARM INDENT "Allarme Critico" #define TR_RSSIALARM_WARN TR("RSSI","TELEMETRY RSSI") diff --git a/radio/src/translations/nl.h.txt b/radio/src/translations/nl.h.txt index 524c45176..8873c3e89 100644 --- a/radio/src/translations/nl.h.txt +++ b/radio/src/translations/nl.h.txt @@ -979,6 +979,8 @@ #define TR_ANTENNASELECTION TR(INDENT "Antenna", INDENT "Antenna selection") #define TR_ANTENNACONFIRM1 "Antennes wisselen?" #define TR_ANTENNACONFIRM2 TR("Check antenna", "Is er zeker een antenne geplaatst!") +#define TR_R9MFLEXWARN1 "Requires non" +#define TR_R9MFLEXWARN2 "certified R9M firm." #define TR_LOWALARM INDENT "Waarschuwing" #define TR_CRITICALALARM INDENT "Kritiek Alarm" #define TR_RSSIALARM_WARN TR("RSSI","TELEMETRY RSSI") diff --git a/radio/src/translations/pl.h.txt b/radio/src/translations/pl.h.txt index accf211cc..6e0ddf296 100644 --- a/radio/src/translations/pl.h.txt +++ b/radio/src/translations/pl.h.txt @@ -979,6 +979,8 @@ #define TR_ANTENNASELECTION TR(INDENT "Antenna", INDENT "Antenna selection") #define TR_ANTENNACONFIRM1 "Really switch?" #define TR_ANTENNACONFIRM2 TR("Check antenna", "Make sure antenna is installed!") +#define TR_R9MFLEXWARN1 "Requires non" +#define TR_R9MFLEXWARN2 "certified R9M firm." #define TR_LOWALARM INDENT "Alarm niski" #define TR_CRITICALALARM INDENT "Alarm krytyczny" #define TR_RSSIALARM_WARN TR("RSSI","TELEMETRY RSSI") diff --git a/radio/src/translations/pt.h.txt b/radio/src/translations/pt.h.txt index e8288bb94..6653d2f51 100644 --- a/radio/src/translations/pt.h.txt +++ b/radio/src/translations/pt.h.txt @@ -983,6 +983,8 @@ #define TR_ANTENNASELECTION TR(INDENT "Antenna", INDENT "Antenna selection") #define TR_ANTENNACONFIRM1 "Really switch?" #define TR_ANTENNACONFIRM2 TR("Check antenna", "Make sure antenna is installed!") +#define TR_R9MFLEXWARN1 "Requires non" +#define TR_R9MFLEXWARN2 "certified R9M firm." #define TR_LOWALARM INDENT "Low Alarm" #define TR_CRITICALALARM INDENT "Critical Alarm" #define TR_RSSIALARM_WARN TR("RSSI","TELEMETRY RSSI") diff --git a/radio/src/translations/se.h.txt b/radio/src/translations/se.h.txt index 1d5b0386e..e69ac9069 100644 --- a/radio/src/translations/se.h.txt +++ b/radio/src/translations/se.h.txt @@ -990,6 +990,8 @@ #define TR_ANTENNASELECTION TR(INDENT "Antenna", INDENT "Antenna selection") #define TR_ANTENNACONFIRM1 "Really switch?" #define TR_ANTENNACONFIRM2 TR("Check antenna", "Make sure antenna is installed!") +#define TR_R9MFLEXWARN1 "Requires non" +#define TR_R9MFLEXWARN2 "certified R9M firm." #define TR_LOWALARM INDENT "Låg-alarm" #define TR_CRITICALALARM INDENT "Kritiskt alarm" #define TR_RSSIALARM_WARN TR("RSSI","TELEMETRY RSSI") diff --git a/radio/util/fwoptions.py b/radio/util/fwoptions.py index b103c9e10..3e16c3b4f 100755 --- a/radio/util/fwoptions.py +++ b/radio/util/fwoptions.py @@ -78,7 +78,8 @@ options_taranis = { "internalppm": ("TARANIS_INTERNAL_PPM", "YES", "NO"), "shutdownconfirm": ("SHUTDOWN_CONFIRMATION", "YES", "NO"), "eu": ("SUPPORT_D16_EU_ONLY", "YES", "NO"), - "multimodule": ("MULTIMODULE", "YES", "NO") + "multimodule": ("MULTIMODULE", "YES", "NO"), + "flexr9m": ("MODULE_R9M_FLEX_FW", "YES", None) } options_taranisplus = { @@ -95,7 +96,8 @@ options_taranisplus = { "internalppm": ("TARANIS_INTERNAL_PPM", "YES", "NO"), "shutdownconfirm": ("SHUTDOWN_CONFIRMATION", "YES", "NO"), "eu": ("SUPPORT_D16_EU_ONLY", "YES", "NO"), - "multimodule": ("MULTIMODULE", "YES", "NO") + "multimodule": ("MULTIMODULE", "YES", "NO"), + "flexr9m": ("MODULE_R9M_FLEX_FW", "YES", None) } options_xlite = { @@ -111,7 +113,8 @@ options_xlite = { "shutdownconfirm": ("SHUTDOWN_CONFIRMATION", "YES", "NO"), "eu": ("SUPPORT_D16_EU_ONLY", "YES", "NO"), "multimodule": ("MULTIMODULE", "YES", "NO"), - "stdr9m": ("MODULE_R9M_FULLSIZE", "YES", None) + "stdr9m": ("MODULE_R9M_FULLSIZE", "YES", None), + "flexr9m": ("MODULE_R9M_FLEX_FW", "YES", None) } options_taranisx9e = { @@ -128,7 +131,8 @@ options_taranisx9e = { "shutdownconfirm": ("SHUTDOWN_CONFIRMATION", "YES", "NO"), "eu": ("SUPPORT_D16_EU_ONLY", "YES", "NO"), "horussticks": ("STICKS", "HORUS", "STANDARD"), - "multimodule": ("MULTIMODULE", "YES", "NO") + "multimodule": ("MULTIMODULE", "YES", "NO"), + "flexr9m": ("MODULE_R9M_FLEX_FW", "YES", None) } options_x12s = { @@ -142,7 +146,8 @@ options_x12s = { "nooverridech": ("OVERRIDE_CHANNEL_FUNCTION", "NO", "YES"), "eu": ("SUPPORT_D16_EU_ONLY", "YES", "NO"), "multimodule": ("MULTIMODULE", "YES", "NO"), - "pcbdev": ("PCBREV", "10", None) + "pcbdev": ("PCBREV", "10", None), + "flexr9m": ("MODULE_R9M_FLEX_FW", "YES", None) } options_x10 = { @@ -155,5 +160,6 @@ options_x10 = { "faichoice": ("FAI", "CHOICE", None), "nooverridech": ("OVERRIDE_CHANNEL_FUNCTION", "NO", "YES"), "eu": ("SUPPORT_D16_EU_ONLY", "YES", "NO"), - "multimodule": ("MULTIMODULE", "YES", "NO") + "multimodule": ("MULTIMODULE", "YES", "NO"), + "flexr9m": ("MODULE_R9M_FLEX_FW", "YES", None) }