From f4f04c1827507172694d9b1ddd711e4f9f4a0d92 Mon Sep 17 00:00:00 2001 From: 3djc Date: Tue, 10 Oct 2023 05:04:52 +0200 Subject: [PATCH] feat: Support for MPM DSM clone mode (#3974) --- radio/src/MultiProtoDefs.h | 1 + radio/src/gui/128x64/model_setup.cpp | 17 ++- radio/src/gui/212x64/model_setup.cpp | 138 +++++++++++++----------- radio/src/gui/colorlcd/mpm_settings.cpp | 30 ++++++ radio/src/gui/colorlcd/mpm_settings.h | 2 + radio/src/gui/gui_common.h | 9 +- radio/src/pulses/modules_helpers.h | 17 +++ radio/src/pulses/multi.cpp | 2 + radio/src/translations.cpp | 3 +- radio/src/translations.h | 3 +- radio/src/translations/untranslated.h | 3 +- 11 files changed, 150 insertions(+), 75 deletions(-) diff --git a/radio/src/MultiProtoDefs.h b/radio/src/MultiProtoDefs.h index 6f837f83c..934b96b85 100644 --- a/radio/src/MultiProtoDefs.h +++ b/radio/src/MultiProtoDefs.h @@ -175,6 +175,7 @@ enum ModuleSubtypeMulti { // #define BAYANG_OPTION_TELEMETRY_NAMES "Off","On","Off+Aux","On+Aux" #define DSM2_OPTION_SERVOFREQ_NAMES "22ms","11ms" +#define DSM_CLONE_NAMES "Normal","Cloned" // // Common list of protocols the MPM doesn't allow to be selected (not sent by MPM protocol scan) diff --git a/radio/src/gui/128x64/model_setup.cpp b/radio/src/gui/128x64/model_setup.cpp index 44b721057..befe290db 100644 --- a/radio/src/gui/128x64/model_setup.cpp +++ b/radio/src/gui/128x64/model_setup.cpp @@ -487,7 +487,7 @@ void editTimerCountdown(int timerIdx, coord_t y, LcdFlags attr, event_t event) MULTIMODULE_MODULE_ROWS(INTERNAL_MODULE) /* ITEM_MODEL_SETUP_INTERNAL_MODULE_AUTOBIND */ \ EXTERNAL_ANTENNA_ROW /* ITEM_MODEL_SETUP_INTERNAL_MODULE_ANTENNA */ \ MODULE_POWER_ROW(INTERNAL_MODULE), /* ITEM_MODEL_SETUP_INTERNAL_MODULE_POWER */ \ - IF_INTERNAL_MODULE_ON(FAILSAFE_ROWS(INTERNAL_MODULE)), /* ITEM_MODEL_SETUP_INTERNAL_MODULE_FAILSAFE */ \ + IF_INTERNAL_MODULE_ON(FAILSAFE_ROW(INTERNAL_MODULE)), /* ITEM_MODEL_SETUP_INTERNAL_MODULE_FAILSAFE */ \ IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 1), /* ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_REGISTER_RANGE */ \ IF_PXX2_MODULE(INTERNAL_MODULE, 0), /* ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_OPTIONS */ \ IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 0), /* ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_RECEIVER_1 */ \ @@ -515,7 +515,7 @@ void editTimerCountdown(int timerIdx, coord_t y, LcdFlags attr, event_t event) MODULE_POWER_ROW(EXTERNAL_MODULE), \ IF_NOT_PXX2_MODULE(EXTERNAL_MODULE, MODULE_OPTION_ROW(EXTERNAL_MODULE)), \ MULTIMODULE_MODULE_ROWS(EXTERNAL_MODULE) \ - FAILSAFE_ROWS(EXTERNAL_MODULE), /* ITEM_MODEL_SETUP_EXTERNAL_MODULE_FAILSAFE */ \ + FAILSAFE_ROW(EXTERNAL_MODULE), /* ITEM_MODEL_SETUP_EXTERNAL_MODULE_FAILSAFE */ \ IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 1), /* Range check and Register buttons */ \ IF_PXX2_MODULE(EXTERNAL_MODULE, 0), /* Module options */ \ IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 0), /* Receiver 1 */ \ @@ -1397,7 +1397,11 @@ void menuModelSetup(event_t event) #endif { lcdDrawTextAlignedLeft(y, STR_SUBTYPE); - lcdDrawMultiSubProtocolString(MODEL_SETUP_2ND_COLUMN, y, moduleIdx, g_model.moduleData[moduleIdx].subType, attr); + lcdDrawMultiSubProtocolString(MODEL_SETUP_2ND_COLUMN, y, moduleIdx, g_model.moduleData[moduleIdx].subType, menuHorizontalPosition == 0 ? attr : 0); + int8_t optionValue = (g_model.moduleData[moduleIdx].multi.optionValue & 0x04) >> 2; + if (isMultiProtocolDSMCloneAvailable(moduleIdx)) { + lcdDrawTextAtIndex(LCD_W, y, STR_MULTI_DSM_CLONE, optionValue, RIGHT | (menuHorizontalPosition == 1 ? attr : 0)); + } if (attr && s_editMode > 0) { switch (menuHorizontalPosition) { case 0:{ @@ -1407,6 +1411,13 @@ void menuModelSetup(event_t event) } break; } + case 1:{ + CHECK_INCDEC_MODELVAR(event, optionValue, 0, 1); + if (checkIncDec_Ret) { + g_model.moduleData[moduleIdx].multi.optionValue = (g_model.moduleData[moduleIdx].multi.optionValue & 0xFB) + (optionValue << 2); + } + break; + } } } } diff --git a/radio/src/gui/212x64/model_setup.cpp b/radio/src/gui/212x64/model_setup.cpp index 0796686f4..eceda5c15 100644 --- a/radio/src/gui/212x64/model_setup.cpp +++ b/radio/src/gui/212x64/model_setup.cpp @@ -126,6 +126,7 @@ enum MenuModelSetupItems { #endif #if defined (MULTIMODULE) ITEM_MODEL_SETUP_EXTERNAL_MODULE_PROTOCOL, + ITEM_MODEL_SETUP_EXTERNAL_MODULE_DSM_CLONED, ITEM_MODEL_SETUP_EXTERNAL_MODULE_STATUS, ITEM_MODEL_SETUP_EXTERNAL_MODULE_SYNCSTATUS, #endif @@ -509,72 +510,73 @@ void menuModelSetup(event_t event) MENU_TAB({ HEADER_LINE_COLUMNS - 0, // Model name - 0, // Model image + 0, // ITEM_MODEL_SETUP_NAME + 0, // ITEM_MODEL_SETUP_BITMAP TIMERS_ROWS, TOPLCD_ROWS - 0, // Extended limits - 1, // Extended trims - 0, // Show trims - 0, // Trims step + 0, // ITEM_MODEL_SETUP_EXTENDED_LIMITS + 1, // ITEM_MODEL_SETUP_EXTENDED_TRIMS + 0, // ITEM_MODEL_SETUP_DISPLAY_TRIMS + 0, // ITEM_MODEL_SETUP_TRIM_INC - 0, // Throttle section - THROTTLE_ROW(0), // Throttle reverse - THROTTLE_ROW(0), // Throttle trace source - THROTTLE_ROW(0), // Throttle trim - THROTTLE_ROW(0), // Throttle trim switch + 0, // ITEM_MODEL_SETUP_THROTTLE_LABEL + THROTTLE_ROW(0), // ITEM_MODEL_SETUP_THROTTLE_REVERSED + THROTTLE_ROW(0), // ITEM_MODEL_SETUP_THROTTLE_TRACE + THROTTLE_ROW(0), // ITEM_MODEL_SETUP_THROTTLE_TRIM + THROTTLE_ROW(0), // ITEM_MODEL_SETUP_THROTTLE_TRIM_SWITCH - 0, // Preflight section - PREFLIGHT_ROW(0), // Checklist - PREFLIGHT_ROW(0), // Checklist interactive - PREFLIGHT_ROW(0), // Throttle warning - PREFLIGHT_ROW(0), // Custom position for throttle warning enable - PREFLIGHT_ROW(0), // Custom position for throttle warning value - SW_WARN_ROWS, // Switch warning - POT_WARN_ROWS, // Pot warning + 0, // ITEM_MODEL_SETUP_PREFLIGHT_LABEL + PREFLIGHT_ROW(0), // ITEM_MODEL_SETUP_CHECKLIST_DISPLAY + PREFLIGHT_ROW(0), // ITEM_MODEL_SETUP_CHECKLIST_INTERACTIVE + PREFLIGHT_ROW(0), // ITEM_MODEL_SETUP_THROTTLE_WARNING + PREFLIGHT_ROW(0), // ITEM_MODEL_SETUP_CUSTOM_THROTTLE_WARNING + PREFLIGHT_ROW(0), // ITEM_MODEL_SETUP_CUSTOM_THROTTLE_WARNING_VALUE + SW_WARN_ROWS, // ITEM_MODEL_SETUP_SWITCHES_WARNING1 + POT_WARN_ROWS, // ITEM_MODEL_SETUP_POTS_WARNING - uint8_t(NAVIGATION_LINE_BY_LINE | (adcGetInputOffset(ADC_INPUT_POT + 1) - 1)), // Center beeps + uint8_t(NAVIGATION_LINE_BY_LINE | (adcGetInputOffset(ADC_INPUT_POT + 1) - 1)), // ITEM_MODEL_SETUP_BEEP_CENTER - 0, // ADC Jitter filter + 0, // ITEM_MODEL_SETUP_USE_JITTER_FILTER - REGISTRATION_ID_ROWS + REGISTRATION_ID_ROWS // ITEM_MODEL_SETUP_REGISTRATION_ID - LABEL(InternalModule), - INTERNAL_MODULE_TYPE_ROWS, - MODULE_CHANNELS_ROWS(INTERNAL_MODULE), - IF_ALLOW_RACING_MODE(INTERNAL_MODULE), - IF_NOT_ACCESS_MODULE_RF(INTERNAL_MODULE, MODULE_BIND_ROWS(INTERNAL_MODULE)), // RxNum, [Bind] and [Range] buttons - IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 0), // RxNum for ACCESS - IF_INTERNAL_MODULE_ON(FAILSAFE_ROWS(INTERNAL_MODULE)), // Failsafe - IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 1), // [Range] and [Register] buttons - IF_PXX2_MODULE(INTERNAL_MODULE, 0), // Module options - IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 0), // Receiver 1 - IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 0), // Receiver 2 - IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 0), // Receiver 3 + LABEL(InternalModule), // ITEM_MODEL_SETUP_INTERNAL_MODULE_LABEL + INTERNAL_MODULE_TYPE_ROWS, // ITEM_MODEL_SETUP_INTERNAL_MODULE_TYPE + MODULE_CHANNELS_ROWS(INTERNAL_MODULE), // ITEM_MODEL_SETUP_INTERNAL_MODULE_CHANNELS + IF_ALLOW_RACING_MODE(INTERNAL_MODULE), // ITEM_MODEL_SETUP_INTERNAL_MODULE_RACING_MODE + IF_NOT_ACCESS_MODULE_RF(INTERNAL_MODULE, MODULE_BIND_ROWS(INTERNAL_MODULE)), // ITEM_MODEL_SETUP_INTERNAL_MODULE_NOT_ACCESS_RXNUM_BIND_RANGE + IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 0), // ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_MODEL_NUM + IF_INTERNAL_MODULE_ON(FAILSAFE_ROW(INTERNAL_MODULE)), // ITEM_MODEL_SETUP_INTERNAL_MODULE_FAILSAFE + IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 1), // ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_REGISTER_RANGE + IF_PXX2_MODULE(INTERNAL_MODULE, 0), // ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_OPTIONS + IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 0), // ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_RECEIVER_1 + IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 0), // ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_RECEIVER_2 + IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 0), // ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_RECEIVER_3 - LABEL(ExternalModule), - EXTERNAL_MODULE_TYPE_ROW(), - IF_MODULE_BAUDRATE_ADJUST(EXTERNAL_MODULE, 0), // Baudrate - IF_MODULE_SYNCED(EXTERNAL_MODULE, 0), // Sync rate + errors - MULTIMODULE_TYPE_ROW(EXTERNAL_MODULE) - MULTIMODULE_STATUS_ROWS(EXTERNAL_MODULE) - AFHDS3_MODE_ROWS(EXTERNAL_MODULE) - MODULE_CHANNELS_ROWS(EXTERNAL_MODULE), - IF_NOT_ACCESS_MODULE_RF(EXTERNAL_MODULE, MODULE_BIND_ROWS(EXTERNAL_MODULE)), - IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 0), // RxNum for ACCESS - IF_NOT_PXX2_MODULE(EXTERNAL_MODULE, MODULE_OPTION_ROW(EXTERNAL_MODULE)), - MULTIMODULE_MODULE_ROWS(EXTERNAL_MODULE) - AFHDS3_MODULE_ROWS(EXTERNAL_MODULE) - MODULE_POWER_ROW(EXTERNAL_MODULE), - FAILSAFE_ROWS(EXTERNAL_MODULE), - IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 1), // Range check and Register buttons - IF_PXX2_MODULE(EXTERNAL_MODULE, 0), // Module options - IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 0), // Receiver 1 - IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 0), // Receiver 2 - IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 0), // Receiver 3 + LABEL(ExternalModule), // ITEM_MODEL_SETUP_EXTERNAL_MODULE_LABEL - 37 + EXTERNAL_MODULE_TYPE_ROW(), // ITEM_MODEL_SETUP_EXTERNAL_MODULE_TYPE + IF_MODULE_BAUDRATE_ADJUST(EXTERNAL_MODULE, 0), // ITEM_MODEL_SETUP_EXTERNAL_MODULE_BAUDRATE + IF_MODULE_SYNCED(EXTERNAL_MODULE, 0), // ITEM_MODEL_SETUP_EXTERNAL_MODULE_SERIALSTATUS + MULTIMODULE_TYPE_ROW(EXTERNAL_MODULE) // ITEM_MODEL_SETUP_EXTERNAL_MODULE_PROTOCOL + MULTIMODULE_DSM_CLONED_RAW(EXTERNAL_MODULE), // ITEM_MODEL_SETUP_EXTERNAL_MODULE_DSM_CLONED + MULTIMODULE_STATUS_ROWS(EXTERNAL_MODULE) // ITEM_MODEL_SETUP_EXTERNAL_MODULE_STATUS + ITEM_MODEL_SETUP_EXTERNAL_MODULE_SYNCSTATUS + AFHDS3_MODE_ROWS(EXTERNAL_MODULE) // ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_MODE + ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_STATUS + ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_POWER_STATUS + MODULE_CHANNELS_ROWS(EXTERNAL_MODULE), // ITEM_MODEL_SETUP_EXTERNAL_MODULE_CHANNELS + IF_NOT_ACCESS_MODULE_RF(EXTERNAL_MODULE, MODULE_BIND_ROWS(EXTERNAL_MODULE)), // ITEM_MODEL_SETUP_EXTERNAL_MODULE_NOT_ACCESS_RXNUM_BIND_RANGE + IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 0), // ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_MODEL_NUM + IF_NOT_PXX2_MODULE(EXTERNAL_MODULE, MODULE_OPTION_ROW(EXTERNAL_MODULE)), // ITEM_MODEL_SETUP_EXTERNAL_MODULE_OPTIONS + MULTIMODULE_MODULE_ROWS(EXTERNAL_MODULE) // ITEM_MODEL_SETUP_EXTERNAL_MODULE_AUTOBIND + (ITEM_MODEL_SETUP_EXTERNAL_MODULE_DISABLE_TELEM) + ITEM_MODEL_SETUP_EXTERNAL_MODULE_DISABLE_MAPPING + AFHDS3_MODULE_ROWS(EXTERNAL_MODULE) // ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_RX_FREQ + ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_ACTUAL_POWER + MODULE_POWER_ROW(EXTERNAL_MODULE), // ITEM_MODEL_SETUP_EXTERNAL_MODULE_POWER + FAILSAFE_ROW(EXTERNAL_MODULE), // ITEM_MODEL_SETUP_EXTERNAL_MODULE_FAILSAFE + IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 1), // ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_REGISTER_RANGE + IF_PXX2_MODULE(EXTERNAL_MODULE, 0), // ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_OPTIONS + IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 0), // ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_RECEIVER_1 + IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 0), // ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_RECEIVER_2 + IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 0), // ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_RECEIVER_3 TRAINER_ROWS, @@ -1203,17 +1205,6 @@ void menuModelSetup(event_t event) pulsesModuleSettingsUpdate(EXTERNAL_MODULE); } break; - -#if defined(MULTIMODULE) - case 2: - CHECK_INCDEC_MODELVAR( - event, g_model.moduleData[EXTERNAL_MODULE].subType, 0, - getMaxMultiSubtype(EXTERNAL_MODULE)); - if (checkIncDec_Ret) { - resetMultiProtocolsOptions(EXTERNAL_MODULE); - } - break; -#endif } } #if POPUP_LEVEL > 1 @@ -1243,6 +1234,23 @@ void menuModelSetup(event_t event) } break; +#if defined(MULTIMODULE) + case ITEM_MODEL_SETUP_EXTERNAL_MODULE_DSM_CLONED: { + int8_t optionValue = + (g_model.moduleData[EXTERNAL_MODULE].multi.optionValue & 0x04) >> 2; + lcdDrawText(INDENT_WIDTH / 2, y, STR_SUBTYPE); + lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_MULTI_DSM_CLONE, optionValue, attr | LEFT); + + if (attr && s_editMode > 0) { + CHECK_INCDEC_MODELVAR(event, optionValue, 0, 1); + if (checkIncDec_Ret) { + g_model.moduleData[EXTERNAL_MODULE].multi.optionValue = (g_model.moduleData[EXTERNAL_MODULE].multi.optionValue & 0xFB) + (optionValue << 2); + } + } + break; + } +#endif + #if defined(CROSSFIRE) || defined(GHOST) case ITEM_MODEL_SETUP_EXTERNAL_MODULE_BAUDRATE: { ModuleData &moduleData = g_model.moduleData[EXTERNAL_MODULE]; diff --git a/radio/src/gui/colorlcd/mpm_settings.cpp b/radio/src/gui/colorlcd/mpm_settings.cpp index 5b561f411..46ca45bcf 100644 --- a/radio/src/gui/colorlcd/mpm_settings.cpp +++ b/radio/src/gui/colorlcd/mpm_settings.cpp @@ -227,6 +227,28 @@ void MPMSubtype::update(const MultiRfProtocols::RfProto* rfProto, uint8_t module lv_event_send(choice->getLvObj(), LV_EVENT_VALUE_CHANGED, &stop); } +struct MPMDSMCloned : public FormWindow::Line { + MPMDSMCloned(FormWindow* form, FlexGridLayout* layout, uint8_t moduleIdx); + void update() const { lv_event_send(choice->getLvObj(), LV_EVENT_VALUE_CHANGED, nullptr); } + + private: + Choice* choice; +}; + +MPMDSMCloned::MPMDSMCloned(FormWindow* form, FlexGridLayout *layout, uint8_t moduleIdx) : + FormWindow::Line(form, layout) +{ + if (layout) layout->resetPos(); + new StaticText(this, rect_t{}, STR_SUBTYPE, 0, COLOR_THEME_PRIMARY1); + + auto md = &g_model.moduleData[moduleIdx]; + choice = new Choice(this, rect_t{}, STR_MULTI_DSM_CLONE, 0, 1, 0, 0); + + choice->setGetValueHandler(GET_DEFAULT((md->multi.optionValue & 0x04) >> 2)); + choice->setSetValueHandler(SET_VALUE( + md->multi.optionValue, (md->multi.optionValue & 0xFB) + (newValue << 2))); +} + struct MPMServoRate : public FormWindow::Line { MPMServoRate(FormWindow* form, FlexGridLayout* layout, uint8_t moduleIdx); void update() const { lv_event_send(choice->getLvObj(), LV_EVENT_VALUE_CHANGED, nullptr); } @@ -329,6 +351,7 @@ MultimoduleSettings::MultimoduleSettings(Window *parent, lv_obj_add_event_cb(st_line->getLvObj(), update_mpm_settings, LV_EVENT_VALUE_CHANGED, this); + cl_line = new MPMDSMCloned(this, &grid, moduleIdx); opt_line = new MPMProtoOption(this, &grid); sr_line = new MPMServoRate(this, &grid, moduleIdx); ab_line = new MPMAutobind(this, &grid, moduleIdx); @@ -370,6 +393,13 @@ void MultimoduleSettings::update() ab_line->update(); } + if (isMultiProtocolDSMCloneAvailable(moduleIdx)) { + lv_obj_clear_flag(cl_line->getLvObj(), LV_OBJ_FLAG_HIDDEN); + cl_line->update(); + } else { + lv_obj_add_flag(cl_line->getLvObj(), LV_OBJ_FLAG_HIDDEN); + } + lp_mode->update(); #if defined(MANUFACTURER_FRSKY) disable_telem->update(); diff --git a/radio/src/gui/colorlcd/mpm_settings.h b/radio/src/gui/colorlcd/mpm_settings.h index 15692e1f8..30d385a8a 100644 --- a/radio/src/gui/colorlcd/mpm_settings.h +++ b/radio/src/gui/colorlcd/mpm_settings.h @@ -29,6 +29,7 @@ class ToggleSwitch; struct ModuleData; struct MPMProtoOption; struct MPMSubtype; +struct MPMDSMCloned; struct MPMServoRate; struct MPMAutobind; struct MPMChannelMap; @@ -40,6 +41,7 @@ class MultimoduleSettings : public FormWindow, public ModuleOptions MPMSubtype* st_line; MPMProtoOption* opt_line; + MPMDSMCloned* cl_line; MPMServoRate* sr_line; MPMAutobind* ab_line; ToggleSwitch* lp_mode; diff --git a/radio/src/gui/gui_common.h b/radio/src/gui/gui_common.h index 44d4269f3..8bfd49e79 100644 --- a/radio/src/gui/gui_common.h +++ b/radio/src/gui/gui_common.h @@ -297,7 +297,10 @@ inline bool MULTIMODULE_HAS_SUBTYPE(uint8_t moduleIdx) inline uint8_t MULTIMODULE_RFPROTO_COLUMNS(uint8_t moduleIdx) { #if LCD_W < 212 - return (MULTIMODULE_HAS_SUBTYPE(moduleIdx) ? (uint8_t) 0 : HIDDEN_ROW); + if (g_model.moduleData[moduleIdx].multi.rfProtocol == MODULE_SUBTYPE_MULTI_DSM2) + return (MULTIMODULE_HAS_SUBTYPE(moduleIdx) ? (uint8_t) 1 : HIDDEN_ROW); + else + return (MULTIMODULE_HAS_SUBTYPE(moduleIdx) ? (uint8_t) 0 : HIDDEN_ROW); #else return (MULTIMODULE_HAS_SUBTYPE(moduleIdx) ? (uint8_t) 1 : 0); #endif @@ -324,6 +327,7 @@ inline uint8_t MULTIMODULE_HASOPTIONS(uint8_t moduleIdx) #else #define MULTIMODULE_MODULE_ROWS(moduleIdx) (MULTIMODULE_PROTOCOL_KNOWN(moduleIdx) && !IS_RX_MULTI(moduleIdx)) ? (uint8_t) 0 : HIDDEN_ROW, MULTI_DISABLE_CHAN_MAP_ROW(moduleIdx), // AUTOBIND, DISABLE CN.MAP #endif +#define MULTIMODULE_DSM_CLONED_RAW(moduleIdx) isMultiProtocolDSMCloneAvailable(moduleIdx) ? (uint8_t) 0 : HIDDEN_ROW #define MULTIMODULE_TYPE_ROW(moduleIdx) isModuleMultimodule(moduleIdx) ? MULTIMODULE_RFPROTO_COLUMNS(moduleIdx) : HIDDEN_ROW, #define MULTIMODULE_STATUS_ROWS(moduleIdx) isModuleMultimodule(moduleIdx) ? TITLE_ROW : HIDDEN_ROW, (isModuleMultimodule(moduleIdx) && getModuleSyncStatus(moduleIdx).isValid()) ? TITLE_ROW : HIDDEN_ROW, #define MULTIMODULE_MODE_ROWS(moduleIdx) (g_model.moduleData[moduleIdx].multi.customProto) ? (uint8_t) 3 : MULTIMODULE_HAS_SUBTYPE(moduleIdx) ? (uint8_t)2 : (uint8_t)1 @@ -333,6 +337,7 @@ inline uint8_t MULTIMODULE_HASOPTIONS(uint8_t moduleIdx) #define MODULE_POWER_ROW(moduleIdx) (MULTIMODULE_PROTOCOL_KNOWN(moduleIdx) || isModuleR9MNonAccess(moduleIdx) || isModuleAFHDS3(moduleIdx)) ? (isModuleR9MLiteNonPro(moduleIdx) ? (isModuleR9M_FCC_VARIANT(moduleIdx) ? READONLY_ROW : (uint8_t)0) : (uint8_t)0) : HIDDEN_ROW #else +#define MULTIMODULE_DSM_CLONED_RAW(moduleIdx) #define MULTIMODULE_TYPE_ROWS(moduleIdx) #define MULTIMODULE_STATUS_ROWS(moduleIdx) #define MULTIMODULE_MODULE_ROWS(moduleIdx) @@ -354,7 +359,7 @@ inline uint8_t MULTIMODULE_HASOPTIONS(uint8_t moduleIdx) #define AFHDS3_MODULE_ROWS(moduleIdx) #endif -#define FAILSAFE_ROWS(moduleIdx) isModuleFailsafeAvailable(moduleIdx) ? (g_model.moduleData[moduleIdx].failsafeMode==FAILSAFE_CUSTOM ? (uint8_t)1 : (uint8_t)0) : HIDDEN_ROW +#define FAILSAFE_ROW(moduleIdx) isModuleFailsafeAvailable(moduleIdx) ? (g_model.moduleData[moduleIdx].failsafeMode==FAILSAFE_CUSTOM ? (uint8_t)1 : (uint8_t)0) : HIDDEN_ROW inline uint8_t MODULE_OPTION_ROW(uint8_t moduleIdx) { if(isModuleR9MNonAccess(moduleIdx) || isModuleSBUS(moduleIdx)) diff --git a/radio/src/pulses/modules_helpers.h b/radio/src/pulses/modules_helpers.h index 808ddbcb0..6fb1aa766 100644 --- a/radio/src/pulses/modules_helpers.h +++ b/radio/src/pulses/modules_helpers.h @@ -628,6 +628,23 @@ inline bool isModuleFailsafeAvailable(uint8_t moduleIdx) return false; } +#if defined(MULTIMODULE) +constexpr int32_t MULTI_DSM_CLONE_VERSION = (1 << 24) | (3 << 16) | (3 << 8) | 30; + +inline bool isMultiProtocolDSMCloneAvailable(uint8_t moduleIdx) +{ + if (!isModuleMultimodule(moduleIdx)) + return false; + + MultiModuleStatus &status = getMultiModuleStatus(moduleIdx); + if (status.isValid() && ((status.major << 24) | (status.minor << 16) | (status.revision << 8) | status.patch) < MULTI_DSM_CLONE_VERSION) { + return false; + } + + return g_model.moduleData[moduleIdx].multi.rfProtocol == MODULE_SUBTYPE_MULTI_DSM2; +} +#endif + inline bool isModuleBindRangeAvailable(uint8_t moduleIdx) { return isModulePXX2(moduleIdx) || isModulePXX1(moduleIdx) || diff --git a/radio/src/pulses/multi.cpp b/radio/src/pulses/multi.cpp index 94a6da0a5..e1c55a679 100644 --- a/radio/src/pulses/multi.cpp +++ b/radio/src/pulses/multi.cpp @@ -361,6 +361,8 @@ void sendFrameProtocolHeader(uint8_t*& p_buf, uint8_t module, bool failsafe) optionValue = 0x00; if (g_model.moduleData[module].multi.optionValue & 0x02) optionValue |= 0x40; // 11ms servo refresh + if (g_model.moduleData[module].multi.optionValue & 0x04) + optionValue |= 0x20; // Cloned optionValue |= sentModuleChannels(module); //add number of channels } diff --git a/radio/src/translations.cpp b/radio/src/translations.cpp index 0a49935ab..da9545a0b 100644 --- a/radio/src/translations.cpp +++ b/radio/src/translations.cpp @@ -112,6 +112,7 @@ ISTR(MULTI_PROTOCOLS); ISTR(MULTI_POWER); ISTR(MULTI_BAYANG_OPTIONS); ISTR(MULTI_DSM_OPTIONS); +ISTR(MULTI_DSM_CLONE); ISTR(MULTI_WBUS_MODE); #endif @@ -913,9 +914,7 @@ const char STR_AFHDS3_ONE_TO_ONE_TELEMETRY[] =TR_AFHDS3_ONE_TO_ONE_TELEMETRY; const char STR_AFHDS3_ONE_TO_MANY[] = TR_AFHDS3_ONE_TO_MANY; #endif -#if LCD_W < 212 const char STR_SUBTYPE[] = TR_SUBTYPE; -#endif const char STR_BACKUP_MODEL[] = TR_BACKUP_MODEL; const char STR_RESTORE_MODEL[] = TR_RESTORE_MODEL; diff --git a/radio/src/translations.h b/radio/src/translations.h index 4aae4ec82..67007816e 100644 --- a/radio/src/translations.h +++ b/radio/src/translations.h @@ -213,6 +213,7 @@ extern const char* const STR_MULTI_PROTOCOLS[]; extern const char* const STR_MULTI_POWER[]; extern const char* const STR_MULTI_BAYANG_OPTIONS[]; extern const char* const STR_MULTI_DSM_OPTIONS[]; +extern const char* const STR_MULTI_DSM_CLONE[]; extern const char* const STR_MULTI_WBUS_MODE[]; extern const char* const STR_SPORT_MODES[]; extern const char* const STR_FSGROUPS[]; @@ -565,9 +566,7 @@ extern const char STR_MODULE_SYNC[]; extern const char STR_MULTI_SERVOFREQ[]; extern const char STR_MULTI_MAX_THROW[]; extern const char STR_MULTI_RFCHAN[]; -#if LCD_W < 212 extern const char STR_SUBTYPE[]; -#endif #if defined(DSM2) || defined(PXX) extern const char STR_RECEIVER_NUM[]; diff --git a/radio/src/translations/untranslated.h b/radio/src/translations/untranslated.h index b61497675..2c4cf218b 100644 --- a/radio/src/translations/untranslated.h +++ b/radio/src/translations/untranslated.h @@ -91,7 +91,8 @@ #define TR_MULTI_PROTOCOLS PROTO_NAMES #define TR_MULTI_BAYANG_OPTIONS BAYANG_OPTION_TELEMETRY_NAMES -#define TR_MULTI_DSM_OPTIONS DSM2_OPTION_SERVOFREQ_NAMES +#define TR_MULTI_DSM_OPTIONS DSM2_OPTION_SERVOFREQ_NAMES +#define TR_MULTI_DSM_CLONE DSM_CLONE_NAMES #define TR_MULTI_POWER "1.6mW","2.0mW","2.5mW","3.2mW","4.0mW","5.0mW","6.3mW","7.9mW","10mW","13mW","16mW","20mW","25mW","32mW","40mW","50mW" #define TR_MULTI_WBUS_MODE "WBUS","PPM"