diff --git a/radio/src/gui/colorlcd/access_settings.cpp b/radio/src/gui/colorlcd/access_settings.cpp index 2e26ea264ec..b2fe0ad725f 100644 --- a/radio/src/gui/colorlcd/access_settings.cpp +++ b/radio/src/gui/colorlcd/access_settings.cpp @@ -707,27 +707,105 @@ void RxOptions::checkEvents() Dialog::checkEvents(); } -#define CH_ENABLE_SPORT 4 -#define CH_ENABLE_SBUS 5 - static uint8_t getShiftedChannel(int8_t moduleIdx, int ch) { return g_model.moduleData[moduleIdx].channelsStart + ch; } -static std::string getChannelText(int8_t moduleIdx, uint8_t pin, int val) +class OutputMappingChoice : public Choice { - uint8_t ch = getShiftedChannel(moduleIdx, val); - uint8_t channelsMax = sentModuleChannels(moduleIdx) - 1; - if (val <= channelsMax) { - return std::string("CH") + std::to_string(ch + 1); - } else if (pin == CH_ENABLE_SPORT) { - return std::string("S.PORT"); - } else if (pin == CH_ENABLE_SBUS) { - return std::string("SBUS"); + protected: + uint32_t capabilities; + uint8_t ch_offset; + uint8_t channels; + uint8_t rx_pin; + + int getOutputMapping() + { + auto& hwSettings = getPXX2HardwareAndSettingsBuffer(); + return hwSettings.receiverSettings.outputsMapping[rx_pin]; } - return std::string(); -} + + void setOutputMapping(int val) + { + auto& hwSettings = getPXX2HardwareAndSettingsBuffer(); + hwSettings.receiverSettings.outputsMapping[rx_pin] = val; + } + + std::string getChannelText(int val) + { + if (val < channels) { + return std::string("CH") + std::to_string(ch_offset + val + 1); + } + return std::string(); + } + + void addMenuItem(int item, Menu* menu, int val, int& selectedIx) + { + menu->addLineBuffered(textHandler(item), [=]() { setValue(item); }); + if (item == val) { selectedIx = menu->count() - 1; } + } + + public: + OutputMappingChoice(Window* parent, uint32_t capabilities, uint8_t rx_model_id, + uint8_t module, uint8_t channels, uint8_t output_pin) : + Choice(parent, rect_t{}, 0, channels - 1, + std::bind(&OutputMappingChoice::getOutputMapping, this), + std::bind(&OutputMappingChoice::setOutputMapping, this, + std::placeholders::_1), 0), + capabilities(capabilities), + ch_offset(getShiftedChannel(module, 0)), + channels(channels), + rx_pin(output_pin) + { + if (isPXX2ReceiverOptionAvailable(rx_model_id, RECEIVER_OPTION_D_TELE_PORT)) { + setTextHandler([=] (int val) { + switch(val) { + case CH_MAP_SBUS_IN: + return std::string(STR_SBUSIN); + case CH_MAP_SBUS_OUT: + return std::string(STR_SBUSOUT); + case CH_MAP_SPORT: + return std::string(STR_SPORT); + case CH_MAP_FBUS: + return std::string(STR_FBUS); + default: + return getChannelText(val); + } + }); + setFillMenuHandler([=](Menu* menu, int val, int& selectedIx) { + if (output_pin == 0) { + addMenuItem(CH_MAP_SBUS_IN, menu, val, selectedIx); + } + addMenuItem(CH_MAP_SBUS_OUT, menu, val, selectedIx); + addMenuItem(CH_MAP_SPORT, menu, val, selectedIx); + addMenuItem(CH_MAP_FBUS, menu, val, selectedIx); + }); + return; + } + + if (capabilities & (1 << RECEIVER_CAPABILITY_ENABLE_PWM_CH5_CH6)) { + if (CH_ENABLE_SPORT == output_pin) { + setTextHandler([=] (int val) { + if (val == channels) return std::string(STR_SPORT); + return getChannelText(val); + }); + setMax(channels); + return; + } else if (CH_ENABLE_SBUS == output_pin) { + setTextHandler([=] (int val) { + if (val == channels) return std::string(STR_SBUSOUT); + return getChannelText(val); + }); + setMax(channels); + return; + } + } + + setTextHandler(std::bind(&OutputMappingChoice::getChannelText, this, + std::placeholders::_1)); + } +}; void RxOptions::update() { @@ -736,8 +814,8 @@ void RxOptions::update() auto& hwSettings = getPXX2HardwareAndSettingsBuffer(); auto& rxInfo = hwSettings.modules[moduleIdx].receivers[receiverIdx].information; - // uint8_t receiverModelId = rxInfo.modelID; - uint8_t receiverVariant = rxInfo.variant; + uint8_t rxModelId = rxInfo.modelID; + uint8_t rxVariant = rxInfo.variant; uint8_t capabilities = rxInfo.capabilities; FlexGridLayout grid(line_col_dsc, line_row_dsc, 2); @@ -775,7 +853,7 @@ void RxOptions::update() hwSettings.receiverSettings.telemetryDisabled = val; }); - if (isModuleR9MAccess(moduleIdx) && receiverVariant == PXX2_VARIANT_EU && + if (isModuleR9MAccess(moduleIdx) && rxVariant == PXX2_VARIANT_EU && hwSettings.moduleSettings.txPower > 14 /*25mW*/) { // read only field in this case tele25mw->disable(); @@ -828,48 +906,29 @@ void RxOptions::update() }); } + if (capabilities & (1 << RECEIVER_CAPABILITY_SBUS24)) { + line = form->newLine(&grid); + new StaticText(line, rect_t{}, STR_SBUS24); + new CheckBox( + line, rect_t{}, + []() { + auto& hwSettings = getPXX2HardwareAndSettingsBuffer(); + return hwSettings.receiverSettings.sbus24; + }, + [](int val) { + auto& hwSettings = getPXX2HardwareAndSettingsBuffer(); + hwSettings.receiverSettings.sbus24 = val; + }); + } + auto outputsCount = min(16, hwSettings.receiverSettings.outputsCount); for (uint8_t i = 0; i < outputsCount; i++) { line = form->newLine(&grid); std::string i_str = std::to_string(i+1); new StaticText(line, rect_t{}, std::string(STR_PIN) + i_str); - uint8_t channelsMax = sentModuleChannels(moduleIdx) - 1; - uint8_t selectionMax = channelsMax; - if (capabilities & (1 << RECEIVER_CAPABILITY_ENABLE_PWM_CH5_CH6) - && (CH_ENABLE_SPORT == i || CH_ENABLE_SBUS == i)) { - selectionMax++; - } - - //uint8_t mapping = hwSettings.receiverSettings.outputsMapping[i]; - // uint8_t channel = getShiftedChannel(moduleIdx, mapping); - - // TODO - // auto r = grid.getFieldSlot(2, 1); - // if (r.h > BAR_HEIGHT) { - // r.y += (r.h - BAR_HEIGHT)/2; - // r.h = BAR_HEIGHT; - // } - // auto chBar = new OutputChannelBar(form, r, channel); - - auto chDn = new Choice( - line, rect_t{}, 0, selectionMax, - [=]() { - auto& hwSettings = getPXX2HardwareAndSettingsBuffer(); - return hwSettings.receiverSettings.outputsMapping[i]; - }, - [=](int val) { - auto& hwSettings = getPXX2HardwareAndSettingsBuffer(); - hwSettings.receiverSettings.outputsMapping[i] = val; - // if (val <= channelsMax) { - // chBar->setChannel(getShiftedChannel(moduleIdx, val)); - // lv_obj_clear_flag(chBar->getLvObj(), LV_OBJ_FLAG_HIDDEN); - // } else { - // lv_obj_add_flag(chBar->getLvObj(), LV_OBJ_FLAG_HIDDEN); - // } - }); - chDn->setTextHandler( - [=](int val) { return getChannelText(moduleIdx, i, val); }); + uint8_t channels = sentModuleChannels(moduleIdx); + new OutputMappingChoice(line, capabilities, rxModelId, moduleIdx, channels, i); } line = form->newLine(&grid); diff --git a/radio/src/gui/colorlcd/radio_sdmanager.cpp b/radio/src/gui/colorlcd/radio_sdmanager.cpp index 42efff17416..77cd0400953 100644 --- a/radio/src/gui/colorlcd/radio_sdmanager.cpp +++ b/radio/src/gui/colorlcd/radio_sdmanager.cpp @@ -193,7 +193,7 @@ class FrskyOtaFlashDialog : public Dialog if (reusableBuffer.sdManager.otaUpdateInformation.step == BIND_INFO_REQUEST) { uint8_t modelId = reusableBuffer.sdManager.otaUpdateInformation.receiverInformation.modelID; - if (isPXX2ReceiverOptionAvailable(modelId, RECEIVER_OPTION_OTA)) { + if (isPXX2ReceiverOptionAvailable(modelId, RECEIVER_OPTION_OTA_TO_UPDATE_SELF)) { char *tmp = strAppend(reusableBuffer.sdManager.otaReceiverVersion, TR_CURRENT_VERSION); tmp = strAppendUnsigned(tmp, 1 + reusableBuffer.sdManager.otaUpdateInformation.receiverInformation.swVersion.major); *tmp++ = '.'; diff --git a/radio/src/gui/common/stdlcd/model_receiver_options.cpp b/radio/src/gui/common/stdlcd/model_receiver_options.cpp index dba24e2bb5c..8b1a06d5951 100644 --- a/radio/src/gui/common/stdlcd/model_receiver_options.cpp +++ b/radio/src/gui/common/stdlcd/model_receiver_options.cpp @@ -49,6 +49,7 @@ enum { ITEM_RECEIVER_SETTINGS_TELEMETRY, ITEM_RECEIVER_SETTINGS_TELEMETRY_25MW, ITEM_RECEIVER_SETTINGS_SPORT_MODE, + ITEM_RECEIVER_SETTINGS_SBUS24, ITEM_RECEIVER_SETTINGS_CAPABILITY_NOT_SUPPORTED1, ITEM_RECEIVER_SETTINGS_CAPABILITY_NOT_SUPPORTED2, ITEM_RECEIVER_SETTINGS_PINMAP_FIRST @@ -57,9 +58,6 @@ enum { #define IS_RECEIVER_CAPABILITY_ENABLED(capability) (reusableBuffer.hardwareAndSettings.modules[g_moduleIdx].receivers[receiverId].information.capabilities & (1 << capability)) #define IF_RECEIVER_CAPABILITY(capability, count) uint8_t(IS_RECEIVER_CAPABILITY_ENABLED(capability) ? count : HIDDEN_ROW) -#define CH_ENABLE_SPORT 4 -#define CH_ENABLE_SBUS 5 - bool isSPortModeAvailable(int mode) { uint8_t receiverId = reusableBuffer.hardwareAndSettings.receiverSettings.receiverId; @@ -78,8 +76,17 @@ void menuModelReceiverOptions(event_t event) if (event == EVT_ENTRY) { // reusableBuffer.hardwareSettings should have been cleared before calling this menu #if defined(SIMU) - reusableBuffer.hardwareAndSettings.receiverSettings.state = PXX2_SETTINGS_OK; - reusableBuffer.hardwareAndSettings.receiverSettings.outputsCount = 8; + auto& hwSettings = getPXX2HardwareAndSettingsBuffer(); + memclear(&hwSettings, sizeof(hwSettings)); + hwSettings.moduleSettings.state = PXX2_SETTINGS_OK; + hwSettings.receiverSettings.state = PXX2_SETTINGS_OK; + moduleState[g_moduleIdx].mode = MODULE_MODE_NORMAL; + auto& rxInfo = hwSettings.modules[0].receivers[0].information; + rxInfo.capabilities = 0x62; + hwSettings.receiverSettings.outputsCount = 6; + for (int i=0; i<6; i++) { + hwSettings.receiverSettings.outputsMapping[i] = i; + } #endif } @@ -88,13 +95,14 @@ void menuModelReceiverOptions(event_t event) uint8_t receiverVariant = reusableBuffer.hardwareAndSettings.modules[g_moduleIdx].receivers[receiverId].information.variant; SUBMENU_NOTITLE(ITEM_RECEIVER_SETTINGS_PINMAP_FIRST + outputsCount, { - 0, // PWM rate - isModuleR9MAccess(g_moduleIdx) && receiverVariant == PXX2_VARIANT_EU && reusableBuffer.hardwareAndSettings.moduleSettings.txPower > 14 /*25mW*/ ? READONLY_ROW : (uint8_t)0, // Telemetry - IF_RECEIVER_CAPABILITY(RECEIVER_CAPABILITY_TELEMETRY_25MW, 0), - uint8_t((IS_RECEIVER_CAPABILITY_ENABLED(RECEIVER_CAPABILITY_FPORT) || IS_RECEIVER_CAPABILITY_ENABLED(RECEIVER_CAPABILITY_FPORT2)) ? 0 : HIDDEN_ROW), - uint8_t(reusableBuffer.hardwareAndSettings.modules[g_moduleIdx].receivers[receiverId].information.capabilityNotSupported ? READONLY_ROW : HIDDEN_ROW), - uint8_t(reusableBuffer.hardwareAndSettings.modules[g_moduleIdx].receivers[receiverId].information.capabilityNotSupported ? READONLY_ROW : HIDDEN_ROW), - 0 // channels ... + 0, // ITEM_RECEIVER_SETTINGS_PWM_RATE + isModuleR9MAccess(g_moduleIdx) && receiverVariant == PXX2_VARIANT_EU && reusableBuffer.hardwareAndSettings.moduleSettings.txPower > 14 /*25mW*/ ? READONLY_ROW : (uint8_t)0, // ITEM_RECEIVER_SETTINGS_TELEMETRY + IF_RECEIVER_CAPABILITY(RECEIVER_CAPABILITY_TELEMETRY_25MW, 0), // ITEM_RECEIVER_SETTINGS_TELEMETRY_25MW + uint8_t((IS_RECEIVER_CAPABILITY_ENABLED(RECEIVER_CAPABILITY_FPORT) || IS_RECEIVER_CAPABILITY_ENABLED(RECEIVER_CAPABILITY_FPORT2)) ? 0 : HIDDEN_ROW), // ITEM_RECEIVER_SETTINGS_SPORT_MODE + uint8_t(IS_RECEIVER_CAPABILITY_ENABLED(RECEIVER_CAPABILITY_SBUS24) ? 0 : HIDDEN_ROW), // ITEM_RECEIVER_SETTINGS_SBUS24 + uint8_t(reusableBuffer.hardwareAndSettings.modules[g_moduleIdx].receivers[receiverId].information.capabilityNotSupported ? READONLY_ROW : HIDDEN_ROW), // ITEM_RECEIVER_SETTINGS_CAPABILITY_NOT_SUPPORTED1 + uint8_t(reusableBuffer.hardwareAndSettings.modules[g_moduleIdx].receivers[receiverId].information.capabilityNotSupported ? READONLY_ROW : HIDDEN_ROW), // ITEM_RECEIVER_SETTINGS_CAPABILITY_NOT_SUPPORTED2 + 0 // ITEM_RECEIVER_SETTINGS_PINMAP_FIRST ... }); if (menuEvent) { @@ -188,6 +196,13 @@ void menuModelReceiverOptions(event_t event) break; } + case ITEM_RECEIVER_SETTINGS_SBUS24: + reusableBuffer.hardwareAndSettings.receiverSettings.sbus24 = editCheckBox(reusableBuffer.hardwareAndSettings.receiverSettings.sbus24, RECEIVER_OPTIONS_2ND_COLUMN, y, STR_SBUS24, attr, event); + if (attr && checkIncDec_Ret) { + reusableBuffer.hardwareAndSettings.receiverSettings.dirty = RECEIVER_SETTINGS_DIRTY; + } + break; + case ITEM_RECEIVER_SETTINGS_CAPABILITY_NOT_SUPPORTED1: lcdDrawText(LCD_W/2, y+1, STR_MORE_OPTIONS_AVAILABLE, SMLSIZE|CENTERED); break; @@ -201,42 +216,74 @@ void menuModelReceiverOptions(event_t event) { uint8_t pin = i - ITEM_RECEIVER_SETTINGS_PINMAP_FIRST; if (pin < reusableBuffer.hardwareAndSettings.receiverSettings.outputsCount) { - uint8_t & mapping = reusableBuffer.hardwareAndSettings.receiverSettings.outputsMapping[pin]; - uint8_t channel = g_model.moduleData[g_moduleIdx].channelsStart + mapping; + uint8_t mapping = reusableBuffer.hardwareAndSettings.receiverSettings.outputsMapping[pin]; lcdDrawText(0, y, STR_PIN); lcdDrawNumber(lcdLastRightPos + 1, y, pin + 1); uint8_t channelMax = sentModuleChannels(g_moduleIdx) - 1; uint8_t selectionMax = channelMax; - if (IS_RECEIVER_CAPABILITY_ENABLED(RECEIVER_CAPABILITY_ENABLE_PWM_CH5_CH6)) { - if (CH_ENABLE_SPORT == pin || CH_ENABLE_SBUS == pin) - selectionMax += 1; + if (mapping <= channelMax) { + uint8_t channel = g_model.moduleData[g_moduleIdx].channelsStart + mapping; + putsChn(7 * FW, y, channel + 1, attr); + } - if (CH_ENABLE_SPORT == pin && selectionMax == channel) { - lcdDrawText(7 * FW, y, "S.PORT", attr); + if (isPXX2ReceiverOptionAvailable(receiverModelId, RECEIVER_OPTION_D_TELE_PORT)) { + if (mapping == CH_MAP_SPORT) { + lcdDrawText(7 * FW, y, STR_SPORT, attr); + mapping = channelMax + 1; + } else if (mapping == CH_MAP_SBUS_OUT) { + lcdDrawText(7 * FW, y, STR_SBUSOUT, attr); + mapping = channelMax + 2; + } else if (mapping == CH_MAP_FBUS) { + lcdDrawText(7 * FW, y, STR_FBUS, attr); + mapping = channelMax + 3; } - else if (CH_ENABLE_SBUS == pin && selectionMax == channel) { - lcdDrawText(7 * FW, y, "SBUS", attr); + if (pin == 0) { + selectionMax = channelMax + 4; + if (mapping == CH_MAP_SBUS_IN) { + lcdDrawText(7 * FW, y, STR_SBUSIN, attr); + mapping = selectionMax; + } } else { - putsChn(7 * FW, y, channel + 1, attr); + selectionMax = channelMax + 3; + } + } else if (IS_RECEIVER_CAPABILITY_ENABLED(RECEIVER_CAPABILITY_ENABLE_PWM_CH5_CH6)) { + if (CH_ENABLE_SPORT == pin) { + if (++selectionMax == mapping) { + lcdDrawText(7 * FW, y, STR_SPORT, attr); + } + } else if (CH_ENABLE_SBUS == pin) { + if (++selectionMax == mapping) { + lcdDrawText(7 * FW, y, STR_SBUSOUT, attr); + } } - } - else { - putsChn(7 * FW, y, channel + 1, attr); } // Channel if (attr) { mapping = checkIncDec(event, mapping, 0, selectionMax); if (checkIncDec_Ret) { + if (isPXX2ReceiverOptionAvailable(receiverModelId, RECEIVER_OPTION_D_TELE_PORT)) { + if (mapping == channelMax + 1) { + mapping = CH_MAP_SPORT; + } else if (mapping == channelMax + 2) { + mapping = CH_MAP_SBUS_OUT; + } else if (mapping == channelMax + 3) { + mapping = CH_MAP_FBUS; + } else if (mapping == channelMax + 4) { + mapping = CH_MAP_SBUS_IN; + } + } + reusableBuffer.hardwareAndSettings.receiverSettings.outputsMapping[pin] = mapping; reusableBuffer.hardwareAndSettings.receiverSettings.dirty = RECEIVER_SETTINGS_DIRTY; } } // Bargraph - if (channel <= channelMax) { + if (mapping <= channelMax) { + uint8_t channel = g_model.moduleData[g_moduleIdx].channelsStart + mapping; int32_t channelValue = channelOutputs[channel]; #if !(defined(PCBX7) || defined(PCBX9LITE) || defined(PCBX9LITES)) // X7/X9 LCD doesn't like too many horizontal lines lcdDrawRect(RECEIVER_OPTIONS_2ND_COLUMN, y + 2, wbar + 1, 4); diff --git a/radio/src/gui/common/stdlcd/radio_sdmanager.cpp b/radio/src/gui/common/stdlcd/radio_sdmanager.cpp index badbbb7ecee..b636d46cc91 100644 --- a/radio/src/gui/common/stdlcd/radio_sdmanager.cpp +++ b/radio/src/gui/common/stdlcd/radio_sdmanager.cpp @@ -98,7 +98,7 @@ void onUpdateStateChanged() { if (reusableBuffer.sdManager.otaUpdateInformation.step == BIND_INFO_REQUEST) { uint8_t modelId = reusableBuffer.sdManager.otaUpdateInformation.receiverInformation.modelID; - if (isPXX2ReceiverOptionAvailable(modelId, RECEIVER_OPTION_OTA)) { + if (isPXX2ReceiverOptionAvailable(modelId, RECEIVER_OPTION_OTA_TO_UPDATE_SELF)) { POPUP_CONFIRMATION(getPXX2ReceiverName(modelId), onUpdateConfirmation); char *tmp = strAppend(reusableBuffer.sdManager.otaReceiverVersion, TR_CURRENT_VERSION); tmp = strAppendUnsigned(tmp, 1 + reusableBuffer.sdManager.otaUpdateInformation.receiverInformation.swVersion.major); diff --git a/radio/src/pulses/pxx2.cpp b/radio/src/pulses/pxx2.cpp index 688d6c0dc1e..780e7d1d2d8 100644 --- a/radio/src/pulses/pxx2.cpp +++ b/radio/src/pulses/pxx2.cpp @@ -80,44 +80,100 @@ bool isPXX2ModuleOptionAvailable(uint8_t modelId, uint8_t option) } /* Receiver options order: - * - OTA (0x01) + * - 2.4G (0x01) + * - 900M (0x02) + * - OTA to update self (0x04) + * - OTA to update sensors (0x08) + * - Tandem Receiver (0x10) + * - Twin Receiver (0x20) + * - Dynamic Telemetry Port (0x40) */ static const uint8_t PXX2ReceiverOptions[] = { #if defined(SIMU) - 0b11111111, // None = display all options on SIMU + 0b11111111, // None = display all options on SIMU #else - 0b00000000, // None = display all options on SIMU + 0b00000000, // None #endif - 0b11111110, // X8R - 0b11111110, // RX8R - 0b11111110, // RX8R-PRO - 0b11111111, // RX6R - 0b11111111, // RX4R - 0b11111111, // G-RX8 - 0b11111111, // G-RX6 - 0b11111110, // X6R - 0b11111110, // X4R - 0b11111110, // X4R-SB - 0b11111110, // XSR - 0b11111110, // XSR-M - 0b11111111, // RXSR - 0b11111110, // S6R - 0b11111110, // S8R - 0b11111110, // XM - 0b11111110, // XM+ - 0b11111110, // XMR - 0b11111110, // R9 - 0b11111110, // R9-SLIM - 0b11111110, // R9-SLIM+ - 0b11111110, // R9-MINI - 0b11111110, // R9-MM - 0b11111111, // R9-STAB+OTA - 0b11111111, // R9-MINI+OTA - 0b11111111, // R9-MM+OTA - 0b11111111, // R9-SLIM+OTA - 0b11111111, // ARCHER-X - 0b11111111, // R9MX - 0b11111111, // R9SX + 0b00000001, // X8R + 0b00000001, // RX8R + 0b00000001, // RX8R-PRO + 0b00001001, // RX6R, flash sensors by OTA + 0b00001001, // RX4R, flash sensors by OTA + 0b00001001, // G-RX8, flash sensors by OTA + 0b00001001, // G-RX6, flash sensors by OTA + 0b00000001, // X6R + 0b00000001, // X4R + 0b00000001, // X4R-SB + 0b00000001, // XSR + 0b00000001, // XSR-M + 0b00001001, // RXSR, flash sensors by OTA + 0b00000001, // S6R + 0b00000001, // S8R + 0b00000001, // XM + 0b00000001, // XM+ + 0b00000001, // XMR + 0b00000010, // R9 + 0b00000010, // R9-SLIM + 0b00000010, // R9-SLIM+ + 0b00000010, // R9-MINI + 0b00000010, // R9-MM + 0b00001110, // R9-STAB+OTA, flash self + sensors by OTA + 0b00001110, // R9-MINI+OTA, flash self + sensors by OTA + 0b00001110, // R9-MM+OTA, flash self + sensors by OTA + 0b00001110, // R9-SLIM+OTA, flash self + sensors by OTA + 0b00001101, // ARCHER-X, flash self + sensors by OTA + 0b00001110, // R9MX, flash self + sensors by OTA + 0b00001110, // R9SX, flash self + sensors by OTA + 0b00010100, // TDMX, flash self by OTA + 0b01010100, // TDR18, flash self by OTA + 0b01010100, // TDR10, flash self by OTA + 0b00010100, // TDR6, flash self by OTA + 0b01010100, // TDR12 + 0b01010100, // TDSR12 + 0b01010100, // TDSR18 + 0b00010100, // 0x26 + 0b00010100, + 0b00010100, + 0b00010100, + 0b00010100, // 0x2A + 0b00010100, + 0b00010100, + 0b00010100, + 0b00010100, + 0b00010100, // 0x2F + 0b00010100, // reserve 0x23 ~ 0x30 for TD Receivers + 0b00100100, // TWMX, flash self by OTA + 0b01100100, // TWSR12, flash self by OTA + 0b01100100, // TWR12, flash self by OTA + 0b00100100, // TWGR6, flash self by OTA + 0b00100100, // TWGR8 + 0b00100100, // TWR6 + 0b00100100, // TWR8 + 0b00100100, // TWGR6FB + 0b00100100, // TWR6FB + 0b00100100, // 0x3A + 0b00100100, + 0b00100100, + 0b00100100, + 0b00100100, + 0b00100100, // reserve 0x38 ~ 0x3F for TW Receivers + 0b01001101, // SR10-plus + 0b01001101, // R10-plus + 0b00001101, // GR8-plus + 0b00001101, // R8-plus + 0b00001101, // SR8-plus + 0b00001101, // GR6-plus + 0b00001101, // R6-plus + 0b00001101, // R6M (ESC DC) + 0b00001101, // RS-plus + 0b00001101, // RS Mini + 0b00001101, // R6FB + 0b00001101, // GR6FB + 0b01001101, // SR12-plus + 0b01001101, // R12-plus + 0b00001101, // R6 Mini E + 0b00001101, // SR6 Mini + 0b00001101, // SR6 Mini E }; uint8_t getPXX2ReceiverOptions(uint8_t modelId) @@ -413,10 +469,12 @@ void Pxx2Pulses::setupReceiverSettingsFrame(uint8_t module, int16_t* channels, u flag1 |= PXX2_RX_SETTINGS_FLAG1_ENABLE_PWM_CH5_CH6; if (reusableBuffer.hardwareAndSettings.receiverSettings.fport2) flag1 |= PXX2_RX_SETTINGS_FLAG1_FPORT2; + if (reusableBuffer.hardwareAndSettings.receiverSettings.sbus24) + flag1 |= PXX2_RX_SETTINGS_FLAG1_SBUS24; Pxx2Transport::addByte(flag1); uint8_t outputsCount = min(24, reusableBuffer.hardwareAndSettings.receiverSettings.outputsCount); for (int i = 0; i < outputsCount; i++) { - Pxx2Transport::addByte(min(23, reusableBuffer.hardwareAndSettings.receiverSettings.outputsMapping[i])); + Pxx2Transport::addByte(reusableBuffer.hardwareAndSettings.receiverSettings.outputsMapping[i]); } } reusableBuffer.hardwareAndSettings.receiverSettings.timeout = get_tmr10ms() + 200/*next try in 2s*/; diff --git a/radio/src/pulses/pxx2.h b/radio/src/pulses/pxx2.h index 6235a2915be..2aebd94c83d 100644 --- a/radio/src/pulses/pxx2.h +++ b/radio/src/pulses/pxx2.h @@ -55,6 +55,7 @@ #define PXX2_RX_SETTINGS_FLAG1_TELEMETRY_DISABLED (1 << 7) #define PXX2_RX_SETTINGS_FLAG1_READONLY (1 << 6) +#define PXX2_RX_SETTINGS_FLAG1_SBUS24 (1 << 5) #define PXX2_RX_SETTINGS_FLAG1_FASTPWM (1 << 4) #define PXX2_RX_SETTINGS_FLAG1_FPORT (1 << 3) #define PXX2_RX_SETTINGS_FLAG1_TELEMETRY_25MW (1 << 2) @@ -70,6 +71,16 @@ #define PXX2_AUTH_REFUSED_FLAG 0xA5 +// Channel mapping constants +#define CH_ENABLE_SPORT 4 +#define CH_ENABLE_SBUS 5 + +#define CH_MAP_SPORT 0x40 +#define CH_MAP_SBUS_OUT 0x80 +#define CH_MAP_SBUS_IN 0xA0 +#define CH_MAP_FBUS 0xC0 + + enum PXX2ModuleModelID { PXX2_MODULE_NONE, PXX2_MODULE_XJT, @@ -106,7 +117,13 @@ enum ModuleCapabilities { const char * getPXX2ReceiverName(uint8_t modelId); enum { - RECEIVER_OPTION_OTA, + RECEIVER_OPTION_24G, + RECEIVER_OPTION_900M, + RECEIVER_OPTION_OTA_TO_UPDATE_SELF, + RECEIVER_OPTION_OTA_TO_UPDATE_OTHER, + RECEIVER_OPTION_TANDEM, + RECEIVER_OPTION_TWIN, + RECEIVER_OPTION_D_TELE_PORT, }; uint8_t getPXX2ReceiverOptions(uint8_t modelId); @@ -118,6 +135,7 @@ enum ReceiverCapabilities { RECEIVER_CAPABILITY_ENABLE_PWM_CH5_CH6, RECEIVER_CAPABILITY_FPORT2, RECEIVER_CAPABILITY_RACING_MODE, + RECEIVER_CAPABILITY_SBUS24, RECEIVER_CAPABILITY_COUNT }; @@ -230,6 +248,7 @@ class ReceiverSettings { uint8_t fport; uint8_t enablePwmCh5Ch6; uint8_t fport2; + uint8_t sbus24; uint8_t outputsCount; uint8_t outputsMapping[24]; }; diff --git a/radio/src/telemetry/frsky_defs.h b/radio/src/telemetry/frsky_defs.h index c7e8864fd91..2372bf2d934 100644 --- a/radio/src/telemetry/frsky_defs.h +++ b/radio/src/telemetry/frsky_defs.h @@ -102,6 +102,8 @@ #define ACCY_LAST_ID 0x071F #define ACCZ_FIRST_ID 0x0720 #define ACCZ_LAST_ID 0x072F +#define ANGLE_FIRST_ID 0x0730 +#define ANGLE_LAST_ID 0x073F #define GPS_LONG_LATI_FIRST_ID 0x0800 #define GPS_LONG_LATI_LAST_ID 0x080F #define GPS_ALT_FIRST_ID 0x0820 diff --git a/radio/src/telemetry/frsky_pxx2.cpp b/radio/src/telemetry/frsky_pxx2.cpp index 66a575331f7..e657e2f7d30 100644 --- a/radio/src/telemetry/frsky_pxx2.cpp +++ b/radio/src/telemetry/frsky_pxx2.cpp @@ -39,8 +39,8 @@ static const char * const PXX2ModulesNames[] = { "ISRM-PRO", "ISRM-S", "R9M", - "R9MLite", - "R9MLite-PRO", + "R9M Lite", + "R9M Lite Pro", "ISRM-N", "ISRM-S-X9", "ISRM-S-X10E", @@ -58,37 +58,87 @@ const char * getPXX2ModuleName(uint8_t modelId) } static const char * const PXX2ReceiversNames[] = { - "---", - "X8R", - "RX8R", - "RX8R-PRO", - "RX6R", - "RX4R", - "G-RX8", - "G-RX6", - "X6R", - "X4R", - "X4R-SB", - "XSR", - "XSR-M", - "RXSR", - "S6R", - "S8R", - "XM", - "XM+", - "XMR", - "R9", - "R9-SLIM", - "R9-SLIM+", - "R9-MINI", - "R9-MM", - "R9-STAB", // R9-STAB has OTA - "R9-MINI-OTA", // this one has OTA (different bootloader) - "R9-MM-OTA", // this one has OTA (different bootloader) - "R9-SLIM+-OTA", // this one has OTA (different bootloader) - "Archer-X", // this one has OTA (internal module) - "R9MX", // this one has OTA - "R9SX", // this one has OTA + "---", + "X8R", + "RX8R", + "RX8R Pro", + "RX6R", + "RX4R", + "G-RX8", + "G-RX6", + "X6R", + "X4R", + "X4R SB", + "XSR", + "XSR M", + "RXSR", + "S6R", + "S8R", + "XM", + "XM+", + "XMR", + "R9", + "R9 SLIM", + "R9 SLIM+", + "R9 MINI", + "R9 MM", + "R9 Stab", + "R9 Mini OTA", + "R9 MM OTA", + "R9 SLIM+ OTA", + "Archer X", + "R9MX", + "R9SX", + "---", + "---", + "---", + "---", + "---", + "---", + "---", + "---", + "---", + "---", + "---", + "---", + "---", + "---", + "---", + "---", + "---", + "---", + "---", + "---", + "---", + "---", + "---", + "---", + "---", + "---", + "---", + "---", + "---", + "---", + "---", + "---", + "---", + "SR10 Plus", // 0x40 + "R10 Plus", + "GR8 Plus", + "R8 Plus", + "SR8 Plus", + "GR6 Plus", + "R6 Plus", + "R6M (ESC DC)", + "Rs Plus", + "RS Mini", + "R6FB", + "GR6FB", + "SR12 Plus", + "R12 Plus", + "R6 Mini ESC", + "SR6 Mini", + "SR6 Mini ESC", // 0x50 }; const char * getPXX2ReceiverName(uint8_t modelId) @@ -120,7 +170,7 @@ static void processGetHardwareInfoFrame(uint8_t module, const uint8_t * frame) POPUP_WARNING(STR_MODULE_UPGRADE_ALERT); } } - else if (index < PXX2_MAX_RECEIVERS_PER_MODULE && modelId < DIM(PXX2ReceiversNames)) { + else if (index < PXX2_MAX_RECEIVERS_PER_MODULE) { memcpy(&destination->receivers[index].information, &frame[4], length); destination->receivers[index].timestamp = get_tmr10ms(); if (destination->receivers[index].information.capabilities & ~((1 << RECEIVER_CAPABILITY_COUNT) - 1)) @@ -174,6 +224,9 @@ static void processReceiverSettingsFrame(uint8_t module, const uint8_t * frame) if (frame[4] & PXX2_RX_SETTINGS_FLAG1_FPORT2) destination->fport2 = 1; + if (frame[4] & PXX2_RX_SETTINGS_FLAG1_SBUS24) + destination->sbus24 = 1; + uint8_t outputsCount = min(16, frame[0] - 4); destination->outputsCount = outputsCount; for (uint8_t pin = 0; pin < outputsCount; pin++) { diff --git a/radio/src/telemetry/frsky_sport.cpp b/radio/src/telemetry/frsky_sport.cpp index df5ee5e61be..cf5641711a7 100644 --- a/radio/src/telemetry/frsky_sport.cpp +++ b/radio/src/telemetry/frsky_sport.cpp @@ -52,6 +52,8 @@ const FrSkySportSensor sportSensors[] = { { ACCX_FIRST_ID, ACCX_LAST_ID, 0, STR_SENSOR_ACCX, UNIT_G, 3 }, { ACCY_FIRST_ID, ACCY_LAST_ID, 0, STR_SENSOR_ACCY, UNIT_G, 3 }, { ACCZ_FIRST_ID, ACCZ_LAST_ID, 0, STR_SENSOR_ACCZ, UNIT_G, 3 }, + { ANGLE_FIRST_ID, ANGLE_LAST_ID, 0, STR_SENSOR_ROLL, UNIT_DEGREE, 2 }, + { ANGLE_FIRST_ID, ANGLE_LAST_ID, 1, STR_SENSOR_PITCH, UNIT_DEGREE, 2 }, { CURR_FIRST_ID, CURR_LAST_ID, 0, STR_SENSOR_CURR, UNIT_AMPS, 1 }, { VFAS_FIRST_ID, VFAS_LAST_ID, 0, STR_SENSOR_VFAS, UNIT_VOLTS, 2 }, { AIR_SPEED_FIRST_ID, AIR_SPEED_LAST_ID, 0, STR_SENSOR_ASPD, UNIT_KTS, 1 }, @@ -415,6 +417,10 @@ void sportProcessTelemetryPacketWithoutCrc(uint8_t module, uint8_t origin, const servosState = newServosState; } } + else if (dataId >= ANGLE_FIRST_ID && dataId <= ANGLE_LAST_ID) { + sportProcessTelemetryPacket(dataId, 0, instance, data & 0xFFFFu); + sportProcessTelemetryPacket(dataId, 1, instance, data >> 16u); + } else { sportProcessTelemetryPacket(dataId, 0, instance, data); } diff --git a/radio/src/thirdparty/libopenui/src/choice.cpp b/radio/src/thirdparty/libopenui/src/choice.cpp index 908b59c723a..6a3fca792be 100644 --- a/radio/src/thirdparty/libopenui/src/choice.cpp +++ b/radio/src/thirdparty/libopenui/src/choice.cpp @@ -223,6 +223,9 @@ void Choice::fillMenu(Menu *menu, const FilterFct& filter) if (value == i) { selectedIx = count; } ++count; } + if (fillMenuHandler) { + fillMenuHandler(menu, value, selectedIx); + } menu->updateLines(); if (selectedIx >= 0) { menu->select(selectedIx); } } diff --git a/radio/src/thirdparty/libopenui/src/choice.h b/radio/src/thirdparty/libopenui/src/choice.h index 1aec0761603..e3dca075a26 100644 --- a/radio/src/thirdparty/libopenui/src/choice.h +++ b/radio/src/thirdparty/libopenui/src/choice.h @@ -84,6 +84,11 @@ class Choice: public ChoiceBase { void onClicked() override; + void setFillMenuHandler(std::function handler) + { + fillMenuHandler = std::move(handler); + } + void setBeforeDisplayMenuHandler(std::function handler) { beforeDisplayMenuHandler = std::move(handler); @@ -179,6 +184,7 @@ class Choice: public ChoiceBase { std::function _setValue; std::function isValueAvailable; std::function textHandler; + std::function fillMenuHandler; std::function beforeDisplayMenuHandler; typedef std::function FilterFct; diff --git a/radio/src/translations/untranslated.h b/radio/src/translations/untranslated.h index 4f1148a9558..a7cb5b6dedb 100644 --- a/radio/src/translations/untranslated.h +++ b/radio/src/translations/untranslated.h @@ -128,7 +128,13 @@ #define TR_XJT_ACCST_RF_PROTOCOLS "D16","D8","LR12" #define TR_ISRM_RF_PROTOCOLS "ACCESS","D16","LR12" -#define TR_SPORT_MODES "S.PORT","F.PORT","FBUS(FPORT2)" +// ACCESS STUFF +#define STR_SBUSIN "SBUS in" +#define STR_SBUSOUT "SBUS out" +#define STR_SPORT "S.PORT" +#define STR_FBUS "FBUS" +#define STR_SBUS24 "SBUS24" +#define TR_SPORT_MODES STR_SPORT,"F.PORT",STR_FBUS #define TR_R9M_PXX2_RF_PROTOCOLS "ACCESS","FCC","EU","Flex" #define TR_R9M_REGION "FCC","EU","868MHz","915MHz" #define TR_R9M_LITE_FCC_POWER_VALUES "(100mW)"