diff --git a/companion/src/eeprominterface.cpp b/companion/src/eeprominterface.cpp index 7ecd5535e..8d14f6e61 100644 --- a/companion/src/eeprominterface.cpp +++ b/companion/src/eeprominterface.cpp @@ -1830,3 +1830,32 @@ SimulatorInterface *GetCurrentFirmwareSimulator() else return NULL; } + +unsigned int getNumSubtypes(MultiModuleRFProtocols type) { + switch (type) { + case MM_RF_PROTO_HISKY: + case MM_RF_PROTO_DSM2: + case MM_RF_PROTO_SYMAX: + case MM_RF_PROTO_KN: + return 2; + + case MM_RF_PROTO_FRSKY: + case MM_RF_PROTO_CG023: + case MM_RF_PROTO_MT99XX: + return 3; + + case MM_RF_PROTO_FLYSKY: + case MM_RF_PROTO_MJXQ: + return 4; + + case MM_RF_PROTO_YD717: + return 5; + + case MM_RF_PROTO_CX10: + case MM_RF_PROTO_CUSTOM: + return 8; + default: + return 1; + } + +} \ No newline at end of file diff --git a/companion/src/eeprominterface.h b/companion/src/eeprominterface.h index 79ca36573..84427584f 100644 --- a/companion/src/eeprominterface.h +++ b/companion/src/eeprominterface.h @@ -849,9 +849,38 @@ enum PulsesProtocol { PULSES_PXX_XJT_LR12, PULSES_PXX_DJT, PULSES_CROSSFIRE, + PULSES_MULTIMODULE, PULSES_PROTOCOL_LAST }; +enum MultiModuleRFProtocols { + MM_RF_PROTO_FLYSKY=0, + MM_RF_PROTO_FIRST=MM_RF_PROTO_FLYSKY, + MM_RF_PROTO_HUBSAN, + MM_RF_PROTO_FRSKY, + MM_RF_PROTO_HISKY, + MM_RF_PROTO_V2X2, + MM_RF_PROTO_DSM2, + MM_RF_PROTO_DEVO, + MM_RF_PROTO_YD717, + MM_RF_PROTO_KN, + MM_RF_PROTO_SYMAX, + MM_RF_PROTO_SLT, + MM_RF_PROTO_CX10, + MM_RF_PROTO_CG023, + MM_RF_PROTO_BAYANG, + MM_RF_PROTO_ESky, + MM_RF_PROTO_MT99XX, + MM_RF_PROTO_MJXQ, + MM_RF_PROTO_SHENQI, + MM_RF_PROTO_FY326, + MM_RF_PROTO_SFHSS, + MM_RF_PROTO_CUSTOM, + MM_RF_PROTO_LAST= MM_RF_PROTO_CUSTOM +}; + +unsigned int getNumSubtypes(MultiModuleRFProtocols type); + enum TrainerProtocol { TRAINER_MASTER_JACK, TRAINER_SLAVE_JACK, @@ -865,19 +894,39 @@ class ModuleData { ModuleData() { clear(); } unsigned int modelId; int protocol; - int subprotocol; + unsigned int subType; + bool invertedSerial; unsigned int channelsStart; int channelsCount; // 0=8 channels unsigned int failsafeMode; int failsafeChannels[C9X_NUM_CHNOUT]; - struct { - int delay; - bool pulsePol; // false = positive - bool outputType; // false = open drain, true = push pull - int frameLength; - } ppm; + + // By pure coincidence the struct are unions with the same datatype in Companion + // and the firmware itself. If this changes the multi struct needs it own logic in the eeprom interface + union { + struct { + int delay; + bool pulsePol; // false = positive + bool outputType; // false = open drain, true = push pull + int frameLength; + } ppm; + struct { + int rfProtocol; + bool autoBindMode; + bool lowPowerMode; + int optionValue; + } multi; + }; + + // Currently the Eeprom read/write code does not work with unions + // define a hack for the multi rf Protocol to get the real numbers here + // (reverse the int => ms logic of the ppm delay) + int getMultiRfProtocol () { return (multi.rfProtocol - 300) / 50; } + void setMultiRfProtocol (int val) { multi.rfProtocol = 300 + 50 * val; } + void clear() { memset(this, 0, sizeof(ModuleData)); } QString polarityToString() const { return ppm.pulsePol ? QObject::tr("Positive") : QObject::tr("Negative"); } // TODO ModelPrinter + }; #define C9X_MAX_SCRIPTS 7 @@ -1632,9 +1681,9 @@ class Firmware { } virtual int getCapability(const Capability) = 0; - + virtual QTime getMaxTimerStart() = 0; - + virtual bool isTelemetrySourceAvailable(int source) = 0; virtual int isAvailable(PulsesProtocol proto, int port=0) = 0; diff --git a/companion/src/firmwares/opentx/opentxeeprom.h b/companion/src/firmwares/opentx/opentxeeprom.h index 973704fb6..62a06758a 100644 --- a/companion/src/firmwares/opentx/opentxeeprom.h +++ b/companion/src/firmwares/opentx/opentxeeprom.h @@ -83,6 +83,7 @@ class ProtocolsConversionTable: public ConversionTable } if (IS_TARANIS(board)) { addConversion(PULSES_CROSSFIRE, val++); + addConversion(PULSES_MULTIMODULE, val++); } } }; diff --git a/companion/src/firmwares/opentx/opentxinterface.cpp b/companion/src/firmwares/opentx/opentxinterface.cpp index d58715375..c45407355 100644 --- a/companion/src/firmwares/opentx/opentxinterface.cpp +++ b/companion/src/firmwares/opentx/opentxinterface.cpp @@ -865,6 +865,8 @@ int OpenTxFirmware::isAvailable(PulsesProtocol proto, int port) case PULSES_DSMX: case PULSES_CROSSFIRE: return 1; + case PULSES_MULTIMODULE: + return id.contains("multimodule") ? 1 : 0; default: return 0; } @@ -1148,6 +1150,7 @@ void addOpenTxTaranisOptions(OpenTxFirmware * firmware) firmware->addOption("mixersmon", QObject::tr("Adds mixers output view to the CHANNELS MONITOR screen, pressing [ENT] switches between the views")); firmware->addOption("eu", QObject::tr("Removes D8 and LR12 FrSky protocols that are not legal for use in the EU on radios sold after Jan 1st, 2015")); firmware->addOption("internalppm", QObject::tr("Support for PPM internal module hack")); + firmware->addOption("multimodule", QObject::tr("Support for the DIY-Multiprotocol-TX-Module")); } void addOpenTxLcdOptions(OpenTxFirmware * firmware) @@ -1196,6 +1199,8 @@ void registerOpenTxFirmwares() firmware->addOption("noheli", QObject::tr("Disable HELI menu and cyclic mix support")); firmware->addOption("nogvars", QObject::tr("Disable Global variables")); firmware->addOption("lua", QObject::tr("Support for Lua model scripts")); + /* untested */ + //firmware->addOption("multimodule", QObject::tr("Support for the DIY-Multiprotocol-TX-Module")); addOpenTxCommonOptions(firmware); firmwares.push_back(firmware); diff --git a/companion/src/modeledit/setup.cpp b/companion/src/modeledit/setup.cpp index f615a5102..cb2424ee3 100644 --- a/companion/src/modeledit/setup.cpp +++ b/companion/src/modeledit/setup.cpp @@ -181,6 +181,11 @@ ModulePanel::ModulePanel(QWidget *parent, ModelData & model, ModuleData & module } } + for (int i=0; i<=MM_RF_PROTO_LAST; i++) + { + ui->multiProtocol->addItem(ModelPrinter::printMultiRfProtocol(i), (QVariant) i); + } + if (firmware->getCapability(HasFailsafe)) { for (int i=0; ippmFrameLength->setMaximum(firmware->getCapability(PPMFrameLength)); ui->ppmFrameLength->setValue(22.5+((double)module.ppm.frameLength)*0.5); + // Multi settings fields + ui->label_multiProtocol->setVisible(mask & MASK_MULTIMODULE); + ui->multiProtocol->setVisible(mask & MASK_MULTIMODULE); + ui->multiProtocol->setCurrentIndex(module.getMultiRfProtocol()); + ui->label_multiSubType->setVisible(mask & MASK_MULTIMODULE); + ui->multiSubType->setVisible(mask & MASK_MULTIMODULE); + + if (mask & MASK_MULTIMODULE) { + int numEntries = getNumSubtypes(static_cast(module.getMultiRfProtocol())); + // Removes extra items + ui->multiSubType->setMaxCount(numEntries); + for (int i=0; i < numEntries; i++) { + if (i < ui->multiSubType->count()) + ui->multiSubType->setItemText(i, ModelPrinter::printMultiSubType(module.getMultiRfProtocol(), i)); + else + ui->multiSubType->addItem(ModelPrinter::printMultiSubType(module.getMultiRfProtocol(), i), (QVariant) i); + } + } + ui->multiSubType->setCurrentIndex(module.subType); + + ui->cb_autoBind->setVisible(mask & MASK_MULTIMODULE); + ui->cb_autoBind->setChecked(module.multi.autoBindMode ? Qt::Checked : Qt::Unchecked); + ui->cb_lowPower->setVisible(mask & MASK_MULTIMODULE); + ui->cb_lowPower->setChecked(module.multi.lowPowerMode ? Qt::Checked : Qt::Unchecked); + + if (firmware->getCapability(HasFailsafe)) { ui->label_failsafeMode->setVisible(mask & MASK_FAILSAFES); ui->failsafeMode->setVisible(mask & MASK_FAILSAFES); @@ -435,6 +470,39 @@ void ModulePanel::onFailsafeComboIndexChanged(int index) } } +void ModulePanel::on_multiProtocol_currentIndexChanged(int index) +{ + if (!lock) { + lock=true; + module.setMultiRfProtocol(index); + unsigned int maxSubTypes = getNumSubtypes(static_cast(index)); + module.subType = std::min(module.subType, maxSubTypes -1); + update(); + emit modified(); + lock = false; + } +} + +void ModulePanel::on_multiSubType_currentIndexChanged(int index) +{ + if (!lock) { + lock=true; + module.subType = index; + update(); + emit modified(); + lock = false; + } +} + +void ModulePanel::on_autoBind_stateChanged(int state) +{ + module.multi.autoBindMode = (state == Qt::Checked); +} +void ModulePanel::on_lowPower_stateChanged(int state) +{ + module.multi.lowPowerMode = (state == Qt::Checked); +} + void ModulePanel::updateFailsafe(int channel) { int failsafeValue = module.failsafeChannels[channel]; diff --git a/companion/src/modeledit/setup.h b/companion/src/modeledit/setup.h index 4c0261d89..4fd32530d 100644 --- a/companion/src/modeledit/setup.h +++ b/companion/src/modeledit/setup.h @@ -65,6 +65,10 @@ class ModulePanel : public ModelPanel void on_failsafeMode_currentIndexChanged(int value); void onFailsafeComboIndexChanged(int index); void onFailsafeSpinChanged(double value); + void on_multiProtocol_currentIndexChanged(int index); + void on_multiSubType_currentIndexChanged(int index); + void on_autoBind_stateChanged(int state); + void on_lowPower_stateChanged(int state); private: ModuleData & module; diff --git a/companion/src/modeledit/setup_module.ui b/companion/src/modeledit/setup_module.ui index ed8c4c0c3..c0c40aca8 100644 --- a/companion/src/modeledit/setup_module.ui +++ b/companion/src/modeledit/setup_module.ui @@ -534,6 +534,26 @@ + + + + Multi Radio Protocol + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 125 + 16777215 + + + + @@ -571,6 +591,37 @@ + + + + SubType + + + + + + + + 125 + 16777215 + + + + + + + + Autobind + + + + + + + Low Power + + + diff --git a/companion/src/modelprinter.cpp b/companion/src/modelprinter.cpp index b0faaba26..1b2aff514 100644 --- a/companion/src/modelprinter.cpp +++ b/companion/src/modelprinter.cpp @@ -98,15 +98,72 @@ QString ModelPrinter::printModuleProtocol(unsigned int protocol) "LP45", "DSM2", "DSMX", "PPM16", "PPMsim", "FrSky XJT (D16)", "FrSky XJT (D8)", "FrSky XJT (LR12)", "FrSky DJT", - "Crossfire" + "Crossfire", + "DIY Multiprotocol Module" }; return CHECK_IN_ARRAY(strings, protocol); } -QString ModelPrinter::printModule(int idx) +QString ModelPrinter::printMultiRfProtocol(int rfProtocol) { - const ModuleData & module = model.moduleData[idx]; + static const char *strings[] = { + "FlySky", "Hubsan", "FrSky", "Hisky", "V2x2", "DSM", "Devo", "YD717", "KN", "SymaX", "SLT", "CX10", "CG023", + "Bayang", "ESky", "MT99XX", "MJXQ", "Shenqi", "FY326", "SFHSS", "Custom" + }; + if (rfProtocol > MM_RF_PROTO_CUSTOM) + return "Custom - proto " + QString::number(rfProtocol & 0x1f); + else + return CHECK_IN_ARRAY(strings, rfProtocol); +} + +QString ModelPrinter::printMultiSubType(int rfProtocol, int subType) { + /* custom protocols */ + if (rfProtocol >= MM_RF_PROTO_CUSTOM) { + static const char *custom_subtype_strings[] = {"Subtype 0","Subtype 1","Subtype 2","Subtype 3","Subtype 4","Subtype 5","Subtype 6","Subtype 7"}; + return CHECK_IN_ARRAY(custom_subtype_strings, subType); + } + switch (rfProtocol) { + case MM_RF_PROTO_FLYSKY: + static const char *flysky_strings[] = {"Standard","V9x9","V6x6","V912"}; + return CHECK_IN_ARRAY(flysky_strings, subType); + case MM_RF_PROTO_FRSKY: + static const char *frsky_strings[] = {"D16", "D8", "D16 8ch"}; + return CHECK_IN_ARRAY(frsky_strings, subType); + case MM_RF_PROTO_HISKY: + static const char *hisky_strings[] = { "HiSky", "HK310" }; + return CHECK_IN_ARRAY(hisky_strings, subType); + case MM_RF_PROTO_DSM2: + static const char *dsm2_strings[] = {"DSM2", "DSMX"}; + return CHECK_IN_ARRAY(dsm2_strings, subType); + case MM_RF_PROTO_YD717: + static const char *yd717_strings[] = {"YD717", "Skywalker", "Syma X2", "XINXUN", "NIHUI"}; + return CHECK_IN_ARRAY(yd717_strings, subType); + case MM_RF_PROTO_SYMAX: + static const char *symax_strings[] = {"Standard", "Syma X5C"}; + return CHECK_IN_ARRAY(symax_strings, subType); + case MM_RF_PROTO_CX10: + static const char *cx10_strings[] = {"Green", "Blue", "DM007", "Q282", "JC3015a", "JC3015b", "MK33041", "Q242"}; + return CHECK_IN_ARRAY(cx10_strings, subType); + case MM_RF_PROTO_CG023: + static const char *cg023_strings[] = {"CG023", "YD829", "H3 3D"}; + return CHECK_IN_ARRAY(cg023_strings, subType); + case MM_RF_PROTO_KN: + static const char* kn_strings[] = {"WLtoys", "FeiLun"}; + return CHECK_IN_ARRAY(kn_strings, subType); + case MM_RF_PROTO_MT99XX: + static const char* mt99_strings[] = {"MT99","H7","YZ"}; + return CHECK_IN_ARRAY(mt99_strings, subType); + case MM_RF_PROTO_MJXQ: + static const char* mjxq_strings[] = {"WLH08", "X600", "X800", "H26D"}; + return CHECK_IN_ARRAY(mjxq_strings, subType); + default: + return "DEFAULT"; + } +} + +QString ModelPrinter::printModule(int idx) { + const ModuleData &module = model.moduleData[idx]; if (module.protocol == PULSES_OFF) return printModuleProtocol(module.protocol); else if (module.protocol == PULSES_PPM) @@ -116,6 +173,8 @@ QString ModelPrinter::printModule(int idx) if (module.protocol != PULSES_PXX_XJT_D8) { result += " " + tr("Receiver number(%1)").arg(module.modelId); } + if (module.protocol == PULSES_MULTIMODULE) + result += " " + tr("radio Protocol %1, subType %2, option value %3").arg(printMultiRfProtocol(module.multi.rfProtocol)).arg(printMultiSubType(module.multi.rfProtocol, module.subType)).arg(module.multi.optionValue); return result; } } diff --git a/companion/src/modelprinter.h b/companion/src/modelprinter.h index 6bc7ba114..8f46dc619 100644 --- a/companion/src/modelprinter.h +++ b/companion/src/modelprinter.h @@ -38,6 +38,8 @@ class ModelPrinter: public QObject QString printTrimIncrementMode(); QString printThrottleTrimMode(); static QString printModuleProtocol(unsigned int protocol); + static QString printMultiRfProtocol(int rfProtocol); + static QString printMultiSubType(int rfProtocol, int subType); QString printFlightModeSwitch(int index); QString printFlightModeName(int index); QString printFlightModes(unsigned int flightModes); diff --git a/radio/util/fwoptions.py b/radio/util/fwoptions.py index 8f6c91fe4..5bfa4dde9 100755 --- a/radio/util/fwoptions.py +++ b/radio/util/fwoptions.py @@ -254,7 +254,8 @@ options_taranis = { "internalppm": ("TARANIS_INTERNAL_PPM", "YES", "NO"), "shutdownconfirm": ("SHUTDOWN_CONFIRMATION", "YES", "NO"), "timer3": ("TIMERS", "3", "2"), - "eu": ("SUPPORT_D16_EU_ONLY", "YES", "NO") + "eu": ("SUPPORT_D16_EU_ONLY", "YES", "NO"), + "multimodule": ("MULTIMODULE", "YES", "NO") } options_taranisplus = { @@ -273,7 +274,8 @@ options_taranisplus = { "internalppm": ("TARANIS_INTERNAL_PPM", "YES", "NO"), "shutdownconfirm": ("SHUTDOWN_CONFIRMATION", "YES", "NO"), "timer3": ("TIMERS", "3", None), - "eu": ("SUPPORT_D16_EU_ONLY", "YES", "NO") + "eu": ("SUPPORT_D16_EU_ONLY", "YES", "NO"), + "multimodule": ("MULTIMODULE", "YES", "NO") } options_taranisx9e = { @@ -293,7 +295,8 @@ options_taranisx9e = { "shutdownconfirm": ("SHUTDOWN_CONFIRMATION", "YES", "NO"), "timer3": ("TIMERS", "3", None), "eu": ("SUPPORT_D16_EU_ONLY", "YES", "NO"), - "horussticks": ("STICKS", "HORUS", "STANDARD") + "horussticks": ("STICKS", "HORUS", "STANDARD"), + "multimodule": ("MULTIMODULE", "YES", "NO") } options_horus = { @@ -307,5 +310,6 @@ options_horus = { "massstorage": ("USB", "MASSSTORAGE", None), "cli": ("USB", "SERIAL", None), "timer3": ("TIMERS", "3", "2"), - "eu": ("SUPPORT_D16_EU_ONLY", "YES", "NO") + "eu": ("SUPPORT_D16_EU_ONLY", "YES", "NO"), + "multimodule": ("MULTIMODULE", "YES", "NO") }