From 3a7e00663527fd2f2a1762e2fc0b8b1bc0d69a0e Mon Sep 17 00:00:00 2001 From: 3djc Date: Fri, 15 Nov 2019 16:20:24 +0100 Subject: [PATCH] Support new Multi 1.3 features (#7077) --- companion/src/firmwares/moduledata.cpp | 4 +- companion/src/firmwares/moduledata.h | 3 +- companion/src/firmwares/multiprotocols.cpp | 5 +- companion/src/firmwares/multiprotocols.h | 3 +- .../src/firmwares/opentx/opentxeeprom.cpp | 16 +- companion/src/modeledit/setup.cpp | 26 ++- companion/src/modeledit/setup.h | 2 + companion/src/modeledit/setup_module.ui | 18 +- .../horus/SCRIPTS/TOOLS/Graupner HoTT.lua | 132 ++++++++++++ .../SCRIPTS/TOOLS/Graupner HoTT.lua | 132 ++++++++++++ .../SCRIPTS/TOOLS/Graupner HoTT.lua | 132 ++++++++++++ radio/src/dataconstants.h | 1 + radio/src/datastructs.h | 12 +- radio/src/gui/128x64/lcd.h | 1 + radio/src/gui/128x64/model_setup.cpp | 87 ++++---- radio/src/gui/128x64/model_telemetry.cpp | 4 +- radio/src/gui/212x64/lcd.h | 1 + radio/src/gui/212x64/model_setup.cpp | 48 ++--- radio/src/gui/212x64/model_telemetry.cpp | 4 +- radio/src/gui/480x272/lcd.cpp | 31 +++ radio/src/gui/480x272/lcd.h | 3 +- radio/src/gui/480x272/model_setup.cpp | 108 ++++++---- radio/src/gui/480x272/model_telemetry.cpp | 4 +- .../gui/480x272/radio_spectrum_analyser.cpp | 22 +- .../src/gui/common/stdlcd/draw_functions.cpp | 31 +++ radio/src/gui/common/stdlcd/draw_functions.h | 3 +- radio/src/gui/gui_common.cpp | 132 ++++++++---- radio/src/gui/gui_common.h | 94 ++++++++- radio/src/lua/api_general.cpp | 40 +++- radio/src/opentx.h | 1 + radio/src/pulses/modules_constants.h | 7 +- radio/src/pulses/modules_helpers.h | 12 +- radio/src/pulses/multi.cpp | 198 ++++++++++++++---- radio/src/pulses/multi.h | 2 + radio/src/storage/modelslist.cpp | 2 +- radio/src/storage/storage_common.cpp | 9 + radio/src/targets/common/arm/CMakeLists.txt | 2 +- radio/src/telemetry/hott.cpp | 184 ++++++++++++++++ radio/src/telemetry/hott.h | 29 +++ radio/src/telemetry/multi.cpp | 191 +++++++++++------ radio/src/telemetry/multi.h | 33 ++- radio/src/telemetry/spektrum.cpp | 4 +- radio/src/telemetry/telemetry.h | 10 +- radio/src/telemetry/telemetry_sensors.cpp | 3 + radio/src/translations.cpp | 5 + radio/src/translations.h | 5 + radio/src/translations/cz.h.txt | 9 +- radio/src/translations/de.h.txt | 9 +- radio/src/translations/en.h.txt | 9 +- radio/src/translations/es.h.txt | 9 +- radio/src/translations/fi.h.txt | 9 +- radio/src/translations/fr.h.txt | 9 +- radio/src/translations/it.h.txt | 11 +- radio/src/translations/nl.h.txt | 9 +- radio/src/translations/pl.h.txt | 9 +- radio/src/translations/pt.h.txt | 9 +- radio/src/translations/se.h.txt | 9 +- 57 files changed, 1542 insertions(+), 355 deletions(-) create mode 100644 radio/sdcard/horus/SCRIPTS/TOOLS/Graupner HoTT.lua create mode 100644 radio/sdcard/taranis-x7/SCRIPTS/TOOLS/Graupner HoTT.lua create mode 100644 radio/sdcard/taranis-x9/SCRIPTS/TOOLS/Graupner HoTT.lua create mode 100644 radio/src/telemetry/hott.cpp create mode 100644 radio/src/telemetry/hott.h diff --git a/companion/src/firmwares/moduledata.cpp b/companion/src/firmwares/moduledata.cpp index b4457345a..a227dd5b8 100644 --- a/companion/src/firmwares/moduledata.cpp +++ b/companion/src/firmwares/moduledata.cpp @@ -86,7 +86,7 @@ QString ModuleData::rfProtocolToString() const { switch (protocol) { case PULSES_MULTIMODULE: - return Multiprotocols::protocolToString((int)multi.rfProtocol, multi.customProto); + return Multiprotocols::protocolToString((int)multi.rfProtocol); default: return CPN_STR_UNKNOWN_ITEM; @@ -107,7 +107,7 @@ QString ModuleData::subTypeToString(int type) const switch (protocol) { case PULSES_MULTIMODULE: - return Multiprotocols::subTypeToString(multi.customProto ? MM_RF_CUSTOM_SELECTED : (int)multi.rfProtocol, (unsigned)type); + return Multiprotocols::subTypeToString((int)multi.rfProtocol, (unsigned)type); case PULSES_PXX_R9M: return CHECK_IN_ARRAY(strings, type); diff --git a/companion/src/firmwares/moduledata.h b/companion/src/firmwares/moduledata.h index 8f3f8cd53..6d6795c58 100644 --- a/companion/src/firmwares/moduledata.h +++ b/companion/src/firmwares/moduledata.h @@ -164,9 +164,10 @@ class ModuleData { struct Multi { unsigned int rfProtocol; + bool disableTelemetry; + bool disableMapping; bool autoBindMode; bool lowPowerMode; - bool customProto; int optionValue; } multi; diff --git a/companion/src/firmwares/multiprotocols.cpp b/companion/src/firmwares/multiprotocols.cpp index 73f9ea69f..f1b37bae0 100644 --- a/companion/src/firmwares/multiprotocols.cpp +++ b/companion/src/firmwares/multiprotocols.cpp @@ -172,5 +172,8 @@ QString Multiprotocols::protocolToString(int protocol, bool custom) // static QString Multiprotocols::subTypeToString(int protocol, unsigned subType) { - return tr(qPrintable(multiProtocols.getProtocol(protocol).subTypeStrings.value(subType, CPN_STR_UNKNOWN_ITEM))); + if (protocol > MODULE_SUBTYPE_MULTI_LAST) + return tr(qPrintable(QString::number(subType))); + else + 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 9eded65b6..42a6cfc9c 100644 --- a/companion/src/firmwares/multiprotocols.h +++ b/companion/src/firmwares/multiprotocols.h @@ -23,6 +23,7 @@ #include #include +#include "moduledata.h" #define MM_RF_CUSTOM_SELECTED 0xff @@ -48,7 +49,7 @@ class Multiprotocols unsigned int numSubTypes() const { - return (unsigned int) subTypeStrings.length(); + return protocol > MODULE_SUBTYPE_MULTI_LAST ? 8 : (unsigned int) subTypeStrings.length(); } int getOptionMin() const; diff --git a/companion/src/firmwares/opentx/opentxeeprom.cpp b/companion/src/firmwares/opentx/opentxeeprom.cpp index 80b56f16f..10df6d7a3 100644 --- a/companion/src/firmwares/opentx/opentxeeprom.cpp +++ b/companion/src/firmwares/opentx/opentxeeprom.cpp @@ -2037,9 +2037,10 @@ class ModuleUnionField: public UnionField { rfProtExtra(0) { ModuleData::Multi& multi = module.multi; - internalField.Append(new UnsignedField<2>(this, rfProtExtra)); - internalField.Append(new SpareBitsField<3>(this)); - internalField.Append(new BoolField<1>(this, multi.customProto)); + internalField.Append(new UnsignedField<3>(this, rfProtExtra)); + internalField.Append(new BoolField<1>(this, multi.disableTelemetry)); + internalField.Append(new BoolField<1>(this, multi.disableMapping)); + internalField.Append(new SpareBitsField<1>(this)); internalField.Append(new BoolField<1>(this, multi.autoBindMode)); internalField.Append(new BoolField<1>(this, multi.lowPowerMode)); internalField.Append(new SignedField<8>(this, multi.optionValue)); @@ -2052,12 +2053,17 @@ class ModuleUnionField: public UnionField { void beforeExport() override { - rfProtExtra = (module.multi.rfProtocol >> 4) & 0x03; + if (module.multi.rfProtocol > MODULE_SUBTYPE_MULTI_LAST) + module.multi.rfProtocol += 3; + rfProtExtra = (module.multi.rfProtocol & 0x70) >> 4; + module.multi.rfProtocol &= 0x0f; } void afterImport() override { - module.multi.rfProtocol = (rfProtExtra & 0x3) << 4 | (module.rfProtocol & 0xf); + module.multi.rfProtocol = (rfProtExtra << 4) + (module.rfProtocol & 0xf); + if (module.multi.rfProtocol > MODULE_SUBTYPE_MULTI_LAST) + module.multi.rfProtocol -= 3; } private: diff --git a/companion/src/modeledit/setup.cpp b/companion/src/modeledit/setup.cpp index c996bc374..297fb704b 100644 --- a/companion/src/modeledit/setup.cpp +++ b/companion/src/modeledit/setup.cpp @@ -227,6 +227,9 @@ ModulePanel::ModulePanel(QWidget * parent, ModelData & model, ModuleData & modul continue; ui->multiProtocol->addItem(Multiprotocols::protocolToString(i), i); } + for (int i=MODULE_SUBTYPE_MULTI_LAST + 1; i <= 124; i++) { + ui->multiProtocol->addItem(QString::number(i + 3), i); + } ui->btnGrpValueType->setId(ui->optPercent, FAILSAFE_DISPLAY_PERCENT); ui->btnGrpValueType->setId(ui->optUs, FAILSAFE_DISPLAY_USEC); @@ -469,14 +472,14 @@ void ModulePanel::update() break; case PULSES_MULTIMODULE: mask |= MASK_CHANNELS_RANGE | MASK_RX_NUMBER | MASK_MULTIMODULE | MASK_SUBTYPES; - max_rx_num = 15; + max_rx_num = 63; if (module.multi.rfProtocol == MODULE_SUBTYPE_MULTI_DSM2) mask |= MASK_CHANNELS_COUNT; else module.channelsCount = 16; if (pdef.optionsstr != nullptr) mask |= MASK_MULTIOPTION; - if (pdef.hasFailsafe) + if (pdef.hasFailsafe || (module.multi.rfProtocol == MODULE_SUBTYPE_MULTI_FRSKY && (module.subType == 0 || module.subType == 2 || module.subType > 3 ))) mask |= MASK_FAILSAFES; break; case PULSES_OFF: @@ -565,7 +568,7 @@ void ModulePanel::update() unsigned i = 0; switch(protocol){ case PULSES_MULTIMODULE: - numEntries = (module.multi.customProto ? 8 : pdef.numSubTypes()); + numEntries = (module.multi.rfProtocol > MODULE_SUBTYPE_MULTI_LAST ? 8 : pdef.numSubTypes()); break; case PULSES_PXX_R9M: if (firmware->getCapability(HasModuleR9MFlex)) @@ -587,11 +590,15 @@ void ModulePanel::update() ui->multiProtocol->setVisible(mask & MASK_MULTIMODULE); ui->label_option->setVisible(mask & MASK_MULTIOPTION); ui->optionValue->setVisible(mask & MASK_MULTIOPTION); + ui->disableTelem->setVisible(mask & MASK_MULTIMODULE); + ui->disableChMap->setVisible(mask & MASK_MULTIMODULE); ui->autoBind->setVisible(mask & MASK_MULTIMODULE); ui->lowPower->setVisible(mask & MASK_MULTIMODULE); if (mask & MASK_MULTIMODULE) { ui->multiProtocol->setCurrentIndex(ui->multiProtocol->findData(module.multi.rfProtocol)); + ui->disableTelem->setChecked(module.multi.disableTelemetry); + ui->disableChMap->setChecked(module.multi.disableMapping); ui->autoBind->setChecked(module.multi.autoBindMode); ui->lowPower->setChecked(module.multi.lowPowerMode); } @@ -763,7 +770,7 @@ void ModulePanel::onMultiProtocolChanged(int index) lock=true; module.multi.rfProtocol = (unsigned int)rfProtocol; unsigned int maxSubTypes = multiProtocols.getProtocol(index).numSubTypes(); - if (module.multi.customProto) + if (rfProtocol > MODULE_SUBTYPE_MULTI_LAST) maxSubTypes=8; module.subType = std::min(module.subType, maxSubTypes -1); module.channelsCount = getMaxChannelCount(); @@ -793,10 +800,21 @@ void ModulePanel::onSubTypeChanged() } } +void ModulePanel::on_disableTelem_stateChanged(int state) +{ + module.multi.disableTelemetry = (state == Qt::Checked); +} + +void ModulePanel::on_disableChMap_stateChanged(int state) +{ + module.multi.disableMapping = (state == Qt::Checked); +} + 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); diff --git a/companion/src/modeledit/setup.h b/companion/src/modeledit/setup.h index 3edb1efd8..586cba07d 100644 --- a/companion/src/modeledit/setup.h +++ b/companion/src/modeledit/setup.h @@ -86,6 +86,8 @@ class ModulePanel : public ModelPanel void onMultiProtocolChanged(int index); void onSubTypeChanged(); void on_autoBind_stateChanged(int state); + void on_disableChMap_stateChanged(int state); + void on_disableTelem_stateChanged(int state); void on_lowPower_stateChanged(int state); void on_r9mPower_currentIndexChanged(int index); void setChannelFailsafeValue(const int channel, const int value, quint8 updtSb = 0); diff --git a/companion/src/modeledit/setup_module.ui b/companion/src/modeledit/setup_module.ui index 5ed3f9e11..6a2d43ce5 100644 --- a/companion/src/modeledit/setup_module.ui +++ b/companion/src/modeledit/setup_module.ui @@ -7,7 +7,7 @@ 0 0 1075 - 434 + 438 @@ -937,7 +937,7 @@ - + Qt::Horizontal @@ -950,6 +950,20 @@ + + + + Disable Telemetry + + + + + + + Disable Ch. Map + + + diff --git a/radio/sdcard/horus/SCRIPTS/TOOLS/Graupner HoTT.lua b/radio/sdcard/horus/SCRIPTS/TOOLS/Graupner HoTT.lua new file mode 100644 index 000000000..ff6a3254c --- /dev/null +++ b/radio/sdcard/horus/SCRIPTS/TOOLS/Graupner HoTT.lua @@ -0,0 +1,132 @@ +---- ######################################################################### +---- # # +---- # Copyright (C) OpenTX # +-----# # +---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html # +---- # # +---- # This program is free software; you can redistribute it and/or modify # +---- # it under the terms of the GNU General Public License version 2 as # +---- # published by the Free Software Foundation. # +---- # # +---- # This program is distributed in the hope that it will be useful # +---- # but WITHOUT ANY WARRANTY; without even the implied warranty of # +---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +---- # GNU General Public License for more details. # +---- # # +---- ######################################################################### + + +--############################################################################### +-- Multi buffer for HoTT description +-- To start operation: +-- Write "HoTT" at address 0..3 +-- Write 0xFF at address 4 will request the buffer to be cleared +-- Write 0xDF at address 5 +-- Read buffer from address 6 access the RX text for 168 bytes, 21 caracters +-- by 8 lines +-- Write at address 5 sends an order to the RX: 0xDF=start, 0xD7=prev page, +-- 0xDE=next page, 0xD9=enter, 0xDD=next or 0xDB=prev +-- Write at address 4 the value 0xFF will request the buffer to be cleared +-- !! Before exiting the script must write 0 at address 0 for normal operation !! +--############################################################################### + +local function HoTT_Release() + multiBuffer( 0, 0 ) +end + +local function HoTT_Draw_LCD() + local i + local value + local line + local result + local offset=0 + + lcd.clear() + + if LCD_W == 480 then + --Draw title + lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR) + lcd.drawText(1, 5, "Graupner HoTT RX configuration", MENU_TITLE_COLOR) + --Draw RX Menu + if multiBuffer( 4 ) == 0xFF then + lcd.drawText(10,50,"No HoTT telemetry...", BLINK) + else + for line = 0, 7, 1 do + for i = 0, 21-1, 1 do + value=multiBuffer( line*21+6+i ) + if value > 0x80 then + value = value - 0x80 + lcd.drawText(10+i*16,32+16*line,string.char(value).." ",INVERS) + else + lcd.drawText(10+i*16,32+16*line,string.char(value)) + end + end + end + end + else + --Draw RX Menu on LCD_W=128 + if multiBuffer( 4 ) == 0xFF then + lcd.drawText(2,17,"No HoTT telemetry...",SMLSIZE) + else + for line = 0, 7, 1 do + for i = 0, 21-1, 1 do + value=multiBuffer( line*21+6+i ) + if value > 0x80 then + value = value - 0x80 + lcd.drawText(2+i*6,1+8*line,string.char(value).." ",SMLSIZE+INVERS) + else + lcd.drawText(2+i*6,1+8*line,string.char(value),SMLSIZE) + end + end + end + end + end +end + +-- Init +local function HoTT_Init() + --Set protocol to talk to + multiBuffer( 0, string.byte('H') ) + --test if value has been written + if multiBuffer( 0 ) ~= string.byte('H') then + error("Not enough memory!") + return 2 + end + multiBuffer( 1, string.byte('o') ) + multiBuffer( 2, string.byte('T') ) + multiBuffer( 3, string.byte('T') ) + --Request init of the RX buffer + multiBuffer( 4, 0xFF ) + --Request RX to send the config menu + multiBuffer( 5, 0xDF ) +end + +-- Main +local function HoTT_Run(event) + if event == nil then + error("Cannot be run as a model script!") + return 2 + elseif event == EVT_VIRTUAL_EXIT then + HoTT_Release() + return 2 + else + if event == EVT_VIRTUAL_PREV_PAGE then + killEvents(event); + multiBuffer( 5, 0xD7 ) + elseif event == EVT_VIRTUAL_NEXT_PAGE then + multiBuffer( 5, 0xDE ) + elseif event == EVT_VIRTUAL_ENTER then + multiBuffer( 5, 0xD9 ) + elseif event == EVT_VIRTUAL_NEXT then + multiBuffer( 5, 0xDD ) + elseif event == EVT_VIRTUAL_PREV then + multiBuffer( 5, 0xDB ) + else + multiBuffer( 5, 0xDF ) + end + HoTT_Draw_LCD() + return 0 + end +end + +return { init=HoTT_Init, run=HoTT_Run } diff --git a/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/Graupner HoTT.lua b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/Graupner HoTT.lua new file mode 100644 index 000000000..ff6a3254c --- /dev/null +++ b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/Graupner HoTT.lua @@ -0,0 +1,132 @@ +---- ######################################################################### +---- # # +---- # Copyright (C) OpenTX # +-----# # +---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html # +---- # # +---- # This program is free software; you can redistribute it and/or modify # +---- # it under the terms of the GNU General Public License version 2 as # +---- # published by the Free Software Foundation. # +---- # # +---- # This program is distributed in the hope that it will be useful # +---- # but WITHOUT ANY WARRANTY; without even the implied warranty of # +---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +---- # GNU General Public License for more details. # +---- # # +---- ######################################################################### + + +--############################################################################### +-- Multi buffer for HoTT description +-- To start operation: +-- Write "HoTT" at address 0..3 +-- Write 0xFF at address 4 will request the buffer to be cleared +-- Write 0xDF at address 5 +-- Read buffer from address 6 access the RX text for 168 bytes, 21 caracters +-- by 8 lines +-- Write at address 5 sends an order to the RX: 0xDF=start, 0xD7=prev page, +-- 0xDE=next page, 0xD9=enter, 0xDD=next or 0xDB=prev +-- Write at address 4 the value 0xFF will request the buffer to be cleared +-- !! Before exiting the script must write 0 at address 0 for normal operation !! +--############################################################################### + +local function HoTT_Release() + multiBuffer( 0, 0 ) +end + +local function HoTT_Draw_LCD() + local i + local value + local line + local result + local offset=0 + + lcd.clear() + + if LCD_W == 480 then + --Draw title + lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR) + lcd.drawText(1, 5, "Graupner HoTT RX configuration", MENU_TITLE_COLOR) + --Draw RX Menu + if multiBuffer( 4 ) == 0xFF then + lcd.drawText(10,50,"No HoTT telemetry...", BLINK) + else + for line = 0, 7, 1 do + for i = 0, 21-1, 1 do + value=multiBuffer( line*21+6+i ) + if value > 0x80 then + value = value - 0x80 + lcd.drawText(10+i*16,32+16*line,string.char(value).." ",INVERS) + else + lcd.drawText(10+i*16,32+16*line,string.char(value)) + end + end + end + end + else + --Draw RX Menu on LCD_W=128 + if multiBuffer( 4 ) == 0xFF then + lcd.drawText(2,17,"No HoTT telemetry...",SMLSIZE) + else + for line = 0, 7, 1 do + for i = 0, 21-1, 1 do + value=multiBuffer( line*21+6+i ) + if value > 0x80 then + value = value - 0x80 + lcd.drawText(2+i*6,1+8*line,string.char(value).." ",SMLSIZE+INVERS) + else + lcd.drawText(2+i*6,1+8*line,string.char(value),SMLSIZE) + end + end + end + end + end +end + +-- Init +local function HoTT_Init() + --Set protocol to talk to + multiBuffer( 0, string.byte('H') ) + --test if value has been written + if multiBuffer( 0 ) ~= string.byte('H') then + error("Not enough memory!") + return 2 + end + multiBuffer( 1, string.byte('o') ) + multiBuffer( 2, string.byte('T') ) + multiBuffer( 3, string.byte('T') ) + --Request init of the RX buffer + multiBuffer( 4, 0xFF ) + --Request RX to send the config menu + multiBuffer( 5, 0xDF ) +end + +-- Main +local function HoTT_Run(event) + if event == nil then + error("Cannot be run as a model script!") + return 2 + elseif event == EVT_VIRTUAL_EXIT then + HoTT_Release() + return 2 + else + if event == EVT_VIRTUAL_PREV_PAGE then + killEvents(event); + multiBuffer( 5, 0xD7 ) + elseif event == EVT_VIRTUAL_NEXT_PAGE then + multiBuffer( 5, 0xDE ) + elseif event == EVT_VIRTUAL_ENTER then + multiBuffer( 5, 0xD9 ) + elseif event == EVT_VIRTUAL_NEXT then + multiBuffer( 5, 0xDD ) + elseif event == EVT_VIRTUAL_PREV then + multiBuffer( 5, 0xDB ) + else + multiBuffer( 5, 0xDF ) + end + HoTT_Draw_LCD() + return 0 + end +end + +return { init=HoTT_Init, run=HoTT_Run } diff --git a/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/Graupner HoTT.lua b/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/Graupner HoTT.lua new file mode 100644 index 000000000..ff6a3254c --- /dev/null +++ b/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/Graupner HoTT.lua @@ -0,0 +1,132 @@ +---- ######################################################################### +---- # # +---- # Copyright (C) OpenTX # +-----# # +---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html # +---- # # +---- # This program is free software; you can redistribute it and/or modify # +---- # it under the terms of the GNU General Public License version 2 as # +---- # published by the Free Software Foundation. # +---- # # +---- # This program is distributed in the hope that it will be useful # +---- # but WITHOUT ANY WARRANTY; without even the implied warranty of # +---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +---- # GNU General Public License for more details. # +---- # # +---- ######################################################################### + + +--############################################################################### +-- Multi buffer for HoTT description +-- To start operation: +-- Write "HoTT" at address 0..3 +-- Write 0xFF at address 4 will request the buffer to be cleared +-- Write 0xDF at address 5 +-- Read buffer from address 6 access the RX text for 168 bytes, 21 caracters +-- by 8 lines +-- Write at address 5 sends an order to the RX: 0xDF=start, 0xD7=prev page, +-- 0xDE=next page, 0xD9=enter, 0xDD=next or 0xDB=prev +-- Write at address 4 the value 0xFF will request the buffer to be cleared +-- !! Before exiting the script must write 0 at address 0 for normal operation !! +--############################################################################### + +local function HoTT_Release() + multiBuffer( 0, 0 ) +end + +local function HoTT_Draw_LCD() + local i + local value + local line + local result + local offset=0 + + lcd.clear() + + if LCD_W == 480 then + --Draw title + lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR) + lcd.drawText(1, 5, "Graupner HoTT RX configuration", MENU_TITLE_COLOR) + --Draw RX Menu + if multiBuffer( 4 ) == 0xFF then + lcd.drawText(10,50,"No HoTT telemetry...", BLINK) + else + for line = 0, 7, 1 do + for i = 0, 21-1, 1 do + value=multiBuffer( line*21+6+i ) + if value > 0x80 then + value = value - 0x80 + lcd.drawText(10+i*16,32+16*line,string.char(value).." ",INVERS) + else + lcd.drawText(10+i*16,32+16*line,string.char(value)) + end + end + end + end + else + --Draw RX Menu on LCD_W=128 + if multiBuffer( 4 ) == 0xFF then + lcd.drawText(2,17,"No HoTT telemetry...",SMLSIZE) + else + for line = 0, 7, 1 do + for i = 0, 21-1, 1 do + value=multiBuffer( line*21+6+i ) + if value > 0x80 then + value = value - 0x80 + lcd.drawText(2+i*6,1+8*line,string.char(value).." ",SMLSIZE+INVERS) + else + lcd.drawText(2+i*6,1+8*line,string.char(value),SMLSIZE) + end + end + end + end + end +end + +-- Init +local function HoTT_Init() + --Set protocol to talk to + multiBuffer( 0, string.byte('H') ) + --test if value has been written + if multiBuffer( 0 ) ~= string.byte('H') then + error("Not enough memory!") + return 2 + end + multiBuffer( 1, string.byte('o') ) + multiBuffer( 2, string.byte('T') ) + multiBuffer( 3, string.byte('T') ) + --Request init of the RX buffer + multiBuffer( 4, 0xFF ) + --Request RX to send the config menu + multiBuffer( 5, 0xDF ) +end + +-- Main +local function HoTT_Run(event) + if event == nil then + error("Cannot be run as a model script!") + return 2 + elseif event == EVT_VIRTUAL_EXIT then + HoTT_Release() + return 2 + else + if event == EVT_VIRTUAL_PREV_PAGE then + killEvents(event); + multiBuffer( 5, 0xD7 ) + elseif event == EVT_VIRTUAL_NEXT_PAGE then + multiBuffer( 5, 0xDE ) + elseif event == EVT_VIRTUAL_ENTER then + multiBuffer( 5, 0xD9 ) + elseif event == EVT_VIRTUAL_NEXT then + multiBuffer( 5, 0xDD ) + elseif event == EVT_VIRTUAL_PREV then + multiBuffer( 5, 0xDB ) + else + multiBuffer( 5, 0xDF ) + end + HoTT_Draw_LCD() + return 0 + end +end + +return { init=HoTT_Init, run=HoTT_Run } diff --git a/radio/src/dataconstants.h b/radio/src/dataconstants.h index d433541dc..46bb4dbaa 100644 --- a/radio/src/dataconstants.h +++ b/radio/src/dataconstants.h @@ -268,6 +268,7 @@ enum TelemetryProtocol PROTOCOL_TELEMETRY_SPEKTRUM, PROTOCOL_TELEMETRY_FLYSKY_IBUS, PROTOCOL_TELEMETRY_HITEC, + PROTOCOL_TELEMETRY_HOTT, PROTOCOL_TELEMETRY_MULTIMODULE, PROTOCOL_TELEMETRY_LAST=PROTOCOL_TELEMETRY_MULTIMODULE, PROTOCOL_TELEMETRY_LUA diff --git a/radio/src/datastructs.h b/radio/src/datastructs.h index 46950cf9d..5733c7f86 100644 --- a/radio/src/datastructs.h +++ b/radio/src/datastructs.h @@ -418,6 +418,7 @@ PACK(struct TrainerModuleData { // Only used in case switch and if statements as "virtual" protocol #define MM_RF_CUSTOM_SELECTED 0xff +#define MULTI_MAX_PROTOCOLS 127 // rfProtocol:4 + rfProtocolExtra:3 PACK(struct ModuleData { uint8_t type:4; // TODO some refactoring is needed, rfProtocol is only used by DSM2 and MULTI, it could be merged with subType @@ -436,8 +437,9 @@ PACK(struct ModuleData { int8_t frameLength; } ppm; NOBACKUP(struct { - uint8_t rfProtocolExtra:2; - uint8_t spare1:3; + uint8_t rfProtocolExtra:3; + uint8_t disableTelemetry:1; + uint8_t disableMapping:1; uint8_t customProto:1; uint8_t autoBindMode:1; uint8_t lowPowerMode:1; @@ -464,15 +466,13 @@ PACK(struct ModuleData { }; // Helper functions to set both of the rfProto protocol at the same time - NOBACKUP(inline uint8_t getMultiProtocol(bool returnCustom) { - if (returnCustom && multi.customProto) - return MM_RF_CUSTOM_SELECTED; + NOBACKUP(inline uint8_t getMultiProtocol() { return ((uint8_t) (rfProtocol & 0x0f)) + (multi.rfProtocolExtra << 4); }) NOBACKUP(inline void setMultiProtocol(uint8_t proto) { rfProtocol = (uint8_t) (proto & 0x0f); - multi.rfProtocolExtra = (proto & 0x30) >> 4; + multi.rfProtocolExtra = (proto & 0x70) >> 4; }) }); diff --git a/radio/src/gui/128x64/lcd.h b/radio/src/gui/128x64/lcd.h index b0e16cbd3..1bbfc4b5b 100644 --- a/radio/src/gui/128x64/lcd.h +++ b/radio/src/gui/128x64/lcd.h @@ -183,6 +183,7 @@ uint8_t * lcdLoadBitmap(uint8_t * dest, const char * filename, uint8_t width, ui #define BLINK_ON_PHASE (0) #else #define BLINK_ON_PHASE (g_blinkTmr10ms & (1<<6)) + #define SLOW_BLINK_ON_PHASE (g_blinkTmr10ms & (1<<7)) #endif inline display_t getPixel(uint8_t x, uint8_t y) diff --git a/radio/src/gui/128x64/model_setup.cpp b/radio/src/gui/128x64/model_setup.cpp index f0e8f9bce..ef212292e 100644 --- a/radio/src/gui/128x64/model_setup.cpp +++ b/radio/src/gui/128x64/model_setup.cpp @@ -103,7 +103,6 @@ enum MenuModelSetupItems { #if defined(MULTIMODULE) ITEM_MODEL_SETUP_EXTERNAL_MODULE_SUBTYPE, #endif - ITEM_MODEL_SETUP_EXTERNAL_MODULE_POWER, #if defined(MULTIMODULE) ITEM_MODEL_SETUP_EXTERNAL_MODULE_STATUS, ITEM_MODEL_SETUP_EXTERNAL_MODULE_SYNCSTATUS, @@ -114,9 +113,12 @@ enum MenuModelSetupItems { #if defined(PCBSKY9X) && defined(REVX) ITEM_MODEL_SETUP_EXTERNAL_MODULE_OUTPUT_TYPE, #endif + ITEM_MODEL_SETUP_EXTERNAL_MODULE_POWER, ITEM_MODEL_SETUP_EXTERNAL_MODULE_OPTIONS, #if defined(MULTIMODULE) ITEM_MODEL_SETUP_EXTERNAL_MODULE_AUTOBIND, + ITEM_MODEL_SETUP_EXTERNAL_MODULE_DISABLE_TELEM, + ITEM_MODEL_SETUP_EXTERNAL_MODULE_DISABLE_MAPPING, #endif ITEM_MODEL_SETUP_EXTERNAL_MODULE_FAILSAFE, ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_REGISTER_RANGE, @@ -329,11 +331,11 @@ void menuModelSetup(event_t event) LABEL(ExternalModule), EXTERNAL_MODULE_TYPE_ROW(), MULTIMODULE_SUBTYPE_ROWS(EXTERNAL_MODULE) - MODULE_POWER_ROW(EXTERNAL_MODULE), MULTIMODULE_STATUS_ROWS(EXTERNAL_MODULE) MODULE_CHANNELS_ROWS(EXTERNAL_MODULE), IF_NOT_ACCESS_MODULE_RF(EXTERNAL_MODULE, MODULE_BIND_ROWS(EXTERNAL_MODULE)), // line reused for PPM: PPM settings IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 0), // RxNum + 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), @@ -867,11 +869,8 @@ void menuModelSetup(event_t event) lcdDrawTextAtIndex(lcdNextPos + 3, y, STR_R9M_REGION, g_model.moduleData[EXTERNAL_MODULE].subType, (menuHorizontalPosition==1 ? attr : 0)); #if defined(MULTIMODULE) else if (isModuleMultimodule(EXTERNAL_MODULE)) { - int multi_rfProto = g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(false); - if (g_model.moduleData[EXTERNAL_MODULE].multi.customProto) - lcdDrawText(lcdNextPos + 3, y, STR_MULTI_CUSTOM, menuHorizontalPosition==1 ? attr : 0); - else - lcdDrawTextAtIndex(lcdNextPos + 3, y, STR_MULTI_PROTOCOLS, multi_rfProto, menuHorizontalPosition==1 ? attr : 0); + int multi_rfProto = g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(); + lcdDrawMultiProtocolString(lcdNextPos + 3, y, EXTERNAL_MODULE, multi_rfProto, menuHorizontalPosition == 1 ? attr : 0); } #endif if (attr && menuHorizontalPosition == 0) { @@ -914,15 +913,13 @@ void menuModelSetup(event_t event) #if defined(MULTIMODULE) else if (isModuleMultimodule(EXTERNAL_MODULE)) { - int multiRfProto = g_model.moduleData[EXTERNAL_MODULE].multi.customProto == 1 ? MODULE_SUBTYPE_MULTI_CUSTOM : g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(false); - CHECK_INCDEC_MODELVAR_CHECK(event, multiRfProto, MODULE_SUBTYPE_MULTI_FIRST, MODULE_SUBTYPE_MULTI_LAST, isMultiProtocolSelectable); + int multiRfProto = g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(); + CHECK_INCDEC_MODELVAR_CHECK(event, multiRfProto, MODULE_SUBTYPE_MULTI_FIRST, MULTI_MAX_PROTOCOLS, isMultiProtocolSelectable); if (checkIncDec_Ret) { - g_model.moduleData[EXTERNAL_MODULE].multi.customProto = (multiRfProto == MODULE_SUBTYPE_MULTI_CUSTOM); - if (!g_model.moduleData[EXTERNAL_MODULE].multi.customProto) - g_model.moduleData[EXTERNAL_MODULE].setMultiProtocol(multiRfProto); + g_model.moduleData[EXTERNAL_MODULE].setMultiProtocol(multiRfProto); g_model.moduleData[EXTERNAL_MODULE].subType = 0; // Sensible default for DSM2 (same as for ppm): 7ch@22ms + Autodetect settings enabled - if (g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(true) == MODULE_SUBTYPE_MULTI_DSM2) { + if (g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol() == MODULE_SUBTYPE_MULTI_DSM2) { g_model.moduleData[EXTERNAL_MODULE].multi.autoBindMode = 1; } else { @@ -969,29 +966,13 @@ void menuModelSetup(event_t event) case ITEM_MODEL_SETUP_EXTERNAL_MODULE_SUBTYPE: { lcdDrawTextAlignedLeft(y, STR_SUBTYPE); - uint8_t multi_rfProto = g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(true); - const mm_protocol_definition * pdef = getMultiProtocolDefinition(multi_rfProto); - - if (multi_rfProto == MM_RF_CUSTOM_SELECTED) { - lcdDrawNumber(MODEL_SETUP_2ND_COLUMN, y, g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(false), (menuHorizontalPosition == 0 ? attr : 0), 2); - lcdDrawNumber(MODEL_SETUP_2ND_COLUMN + 3 * FW, y, g_model.moduleData[EXTERNAL_MODULE].subType, (menuHorizontalPosition == 1 ? attr : 0), 2); - } - else { - if (pdef->subTypeString != nullptr) - lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, pdef->subTypeString, g_model.moduleData[EXTERNAL_MODULE].subType, attr); - } + lcdDrawMultiSubProtocolString(MODEL_SETUP_2ND_COLUMN, y, EXTERNAL_MODULE, g_model.moduleData[EXTERNAL_MODULE].subType, attr); if (attr && s_editMode > 0) { switch (menuHorizontalPosition) { - case 0: - if (multi_rfProto == MM_RF_CUSTOM_SELECTED) - g_model.moduleData[EXTERNAL_MODULE].setMultiProtocol(checkIncDec(event, g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(false), 0, 63, EE_MODEL)); - else if (pdef->maxSubtype > 0) - CHECK_INCDEC_MODELVAR(event, g_model.moduleData[EXTERNAL_MODULE].subType, 0, pdef->maxSubtype); - break; - case 1: - // Custom protocol, third column is subtype - CHECK_INCDEC_MODELVAR(event, g_model.moduleData[EXTERNAL_MODULE].subType, 0, 7); + case 0:{ + CHECK_INCDEC_MODELVAR(event, g_model.moduleData[EXTERNAL_MODULE].subType, 0, getMaxMultiSubtype(EXTERNAL_MODULE)); break; + } } } } @@ -1438,10 +1419,27 @@ void menuModelSetup(event_t event) if (isModuleMultimodule(moduleIdx)) { int optionValue = g_model.moduleData[moduleIdx].multi.optionValue; - const uint8_t multi_proto = g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(true); - const mm_protocol_definition * pdef = getMultiProtocolDefinition(multi_proto); - if (pdef->optionsstr) - lcdDrawText(INDENT_WIDTH, y, pdef->optionsstr); + const uint8_t multi_proto = g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(); + if (multi_proto < MODULE_SUBTYPE_MULTI_LAST) { + const mm_protocol_definition * pdef = getMultiProtocolDefinition(multi_proto); + if (pdef->optionsstr) { + lcdDrawText(INDENT_WIDTH, y, pdef->optionsstr); + if (attr && pdef->optionsstr == STR_MULTI_RFTUNE) { + lcdDrawText(MODEL_SETUP_2ND_COLUMN + 23, y, "RSSI(", LEFT); + lcdDrawNumber(lcdLastRightPos, y, TELEMETRY_RSSI(), LEFT); + lcdDrawText(lcdLastRightPos, y, ")", LEFT); + } + } + } + else { + MultiModuleStatus &status = getMultiModuleStatus(moduleIdx); + lcdDrawText(INDENT_WIDTH, y, mm_options_strings::options[status.optionDisp]); + if (attr && status.optionDisp == 2) { + lcdDrawText(MODEL_SETUP_2ND_COLUMN + 23, y, "RSSI(", LEFT); + lcdDrawNumber(lcdLastRightPos, y, TELEMETRY_RSSI(), LEFT); + lcdDrawText(lcdLastRightPos, y, ")", LEFT); + } + } if (multi_proto == MODULE_SUBTYPE_MULTI_FS_AFHDS2A) optionValue = 50 + 5 * optionValue; @@ -1456,11 +1454,6 @@ void menuModelSetup(event_t event) } else { CHECK_INCDEC_MODELVAR(event, g_model.moduleData[moduleIdx].multi.optionValue, -128, 127); - if (pdef->optionsstr == STR_MULTI_RFTUNE) { - lcdDrawText(MODEL_SETUP_2ND_COLUMN + 23, y, "RSSI(", LEFT); - lcdDrawNumber(lcdLastRightPos, y, TELEMETRY_RSSI(), LEFT); - lcdDrawText(lcdLastRightPos, y, ")", LEFT); - } } } } @@ -1555,12 +1548,20 @@ void menuModelSetup(event_t event) #if defined(MULTIMODULE) case ITEM_MODEL_SETUP_EXTERNAL_MODULE_AUTOBIND: - if (g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(true) == MODULE_SUBTYPE_MULTI_DSM2) + if (g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol() == MODULE_SUBTYPE_MULTI_DSM2) g_model.moduleData[EXTERNAL_MODULE].multi.autoBindMode = editCheckBox(g_model.moduleData[EXTERNAL_MODULE].multi.autoBindMode, MODEL_SETUP_2ND_COLUMN, y, STR_MULTI_DSM_AUTODTECT, attr, event); else g_model.moduleData[EXTERNAL_MODULE].multi.autoBindMode = editCheckBox(g_model.moduleData[EXTERNAL_MODULE].multi.autoBindMode, MODEL_SETUP_2ND_COLUMN, y, STR_MULTI_AUTOBIND, attr, event); break; + case ITEM_MODEL_SETUP_EXTERNAL_MODULE_DISABLE_TELEM: + g_model.moduleData[EXTERNAL_MODULE].multi.disableTelemetry = editCheckBox(g_model.moduleData[EXTERNAL_MODULE].multi.disableTelemetry, MODEL_SETUP_2ND_COLUMN, y, INDENT TR_DISABLE_TELEM, attr, event); + break; + + case ITEM_MODEL_SETUP_EXTERNAL_MODULE_DISABLE_MAPPING: + g_model.moduleData[EXTERNAL_MODULE].multi.disableMapping = editCheckBox(g_model.moduleData[EXTERNAL_MODULE].multi.disableMapping, MODEL_SETUP_2ND_COLUMN, y, INDENT TR_DISABLE_CH_MAP, attr, event); + break; + case ITEM_MODEL_SETUP_EXTERNAL_MODULE_STATUS: { lcdDrawTextAlignedLeft(y, STR_MODULE_STATUS); diff --git a/radio/src/gui/128x64/model_telemetry.cpp b/radio/src/gui/128x64/model_telemetry.cpp index 12617e855..652b89c4f 100644 --- a/radio/src/gui/128x64/model_telemetry.cpp +++ b/radio/src/gui/128x64/model_telemetry.cpp @@ -237,8 +237,8 @@ void menuModelTelemetry(event_t event) case ITEM_TELEMETRY_RSSI_LABEL: #if defined(MULTIMODULE) - if (telemetryProtocol == PROTOCOL_TELEMETRY_MULTIMODULE && g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(false) == MODULE_SUBTYPE_MULTI_FS_AFHDS2A) - lcdDrawTextAlignedLeft(y, "RSNR"); + if (telemetryProtocol == PROTOCOL_TELEMETRY_MULTIMODULE && (g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol() == MODULE_SUBTYPE_MULTI_FS_AFHDS2A || g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol() == MODULE_SUBTYPE_MULTI_HOTT)) + lcdDrawTextAlignedLeft(y, "RQly"); else lcdDrawTextAlignedLeft(y, "RSSI"); #else diff --git a/radio/src/gui/212x64/lcd.h b/radio/src/gui/212x64/lcd.h index 5c2e86410..c4e427771 100644 --- a/radio/src/gui/212x64/lcd.h +++ b/radio/src/gui/212x64/lcd.h @@ -174,6 +174,7 @@ uint8_t * lcdLoadBitmap(uint8_t * dest, const char * filename, uint16_t width, u #define BLINK_ON_PHASE (0) #else #define BLINK_ON_PHASE (g_blinkTmr10ms & (1<<6)) + #define SLOW_BLINK_ON_PHASE (g_blinkTmr10ms & (1<<7)) #endif inline display_t getPixel(unsigned int x, unsigned int y) diff --git a/radio/src/gui/212x64/model_setup.cpp b/radio/src/gui/212x64/model_setup.cpp index 5d96d50c8..5a9e29e15 100644 --- a/radio/src/gui/212x64/model_setup.cpp +++ b/radio/src/gui/212x64/model_setup.cpp @@ -107,6 +107,8 @@ enum MenuModelSetupItems { ITEM_MODEL_SETUP_EXTERNAL_MODULE_OPTIONS, #if defined(MULTIMODULE) ITEM_MODEL_SETUP_EXTERNAL_MODULE_AUTOBIND, + ITEM_MODEL_SETUP_EXTERNAL_MODULE_DISABLE_TELEM, + ITEM_MODEL_SETUP_EXTERNAL_MODULE_DISABLE_MAPPING, #endif ITEM_MODEL_SETUP_EXTERNAL_MODULE_POWER, ITEM_MODEL_SETUP_EXTERNAL_MODULE_FAILSAFE, @@ -815,21 +817,11 @@ void menuModelSetup(event_t event) lcdDrawTextAtIndex(lcdNextPos + 3, y, STR_R9M_REGION, g_model.moduleData[EXTERNAL_MODULE].subType, (menuHorizontalPosition==1 ? attr : 0)); #if defined(MULTIMODULE) else if (isModuleMultimodule(EXTERNAL_MODULE)) { - uint8_t multi_rfProto = g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(false); - + uint8_t multi_rfProto = g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(); // Do not use MODEL_SETUP_3RD_COLUMN here since some the protocol string are so long that we cannot afford the 2 spaces (+6) here - if (g_model.moduleData[EXTERNAL_MODULE].multi.customProto) { - lcdDrawText(lcdNextPos + 3, y, STR_MULTI_CUSTOM, menuHorizontalPosition == 1 ? attr : 0); - lcdDrawNumber(lcdNextPos + 3, y, g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(false), menuHorizontalPosition == 2 ? attr : 0, 2); - lcdDrawNumber(lcdNextPos + 3, y, g_model.moduleData[EXTERNAL_MODULE].subType, menuHorizontalPosition == 3 ? attr : 0, 2); - } - else { - lcdDrawTextAtIndex(lcdNextPos + 3, y, STR_MULTI_PROTOCOLS, multi_rfProto, menuHorizontalPosition==1 ? attr : 0); - const mm_protocol_definition * pdef = getMultiProtocolDefinition(multi_rfProto); - if (pdef->subTypeString) { - lcdDrawTextAtIndex(lcdNextPos + 3, y, pdef->subTypeString, g_model.moduleData[EXTERNAL_MODULE].subType, menuHorizontalPosition==2 ? attr : 0); - } - } + lcdDrawMultiProtocolString(lcdNextPos + 3, y, EXTERNAL_MODULE, multi_rfProto, menuHorizontalPosition == 1 ? attr : 0); + if (MULTIMODULE_HAS_SUBTYPE(EXTERNAL_MODULE)) + lcdDrawMultiSubProtocolString(lcdNextPos + 3, y, EXTERNAL_MODULE, g_model.moduleData[EXTERNAL_MODULE].subType, menuHorizontalPosition==2 ? attr : 0); } #endif if (attr && menuHorizontalPosition == 0) { @@ -858,15 +850,13 @@ void menuModelSetup(event_t event) } #if defined(MULTIMODULE) else if (isModuleMultimodule(EXTERNAL_MODULE)) { - int multiRfProto = g_model.moduleData[EXTERNAL_MODULE].multi.customProto == 1 ? MODULE_SUBTYPE_MULTI_CUSTOM : g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(false); - CHECK_INCDEC_MODELVAR_CHECK(event, multiRfProto, MODULE_SUBTYPE_MULTI_FIRST, MODULE_SUBTYPE_MULTI_LAST, isMultiProtocolSelectable); + int multiRfProto = g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(); + CHECK_INCDEC_MODELVAR_CHECK(event, multiRfProto, MODULE_SUBTYPE_MULTI_FIRST, MULTI_MAX_PROTOCOLS, isMultiProtocolSelectable); if (checkIncDec_Ret) { - g_model.moduleData[EXTERNAL_MODULE].multi.customProto = (multiRfProto == MODULE_SUBTYPE_MULTI_CUSTOM); - if (!g_model.moduleData[EXTERNAL_MODULE].multi.customProto) - g_model.moduleData[EXTERNAL_MODULE].setMultiProtocol(multiRfProto); + g_model.moduleData[EXTERNAL_MODULE].setMultiProtocol(multiRfProto); g_model.moduleData[EXTERNAL_MODULE].subType = 0; // Sensible default for DSM2 (same as for ppm): 7ch@22ms + Autodetect settings enabled - if (g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(true) == MODULE_SUBTYPE_MULTI_DSM2) { + if (g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol() == MODULE_SUBTYPE_MULTI_DSM2) { g_model.moduleData[EXTERNAL_MODULE].multi.autoBindMode = 1; } else { @@ -895,13 +885,11 @@ void menuModelSetup(event_t event) #if defined(MULTIMODULE) case 2: if (g_model.moduleData[EXTERNAL_MODULE].multi.customProto) { - g_model.moduleData[EXTERNAL_MODULE].setMultiProtocol(checkIncDec(event, g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(false), 0, 63, EE_MODEL)); + g_model.moduleData[EXTERNAL_MODULE].setMultiProtocol(checkIncDec(event, g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(), 0, MULTI_MAX_PROTOCOLS, EE_MODEL)); break; } else { - const mm_protocol_definition * pdef = getMultiProtocolDefinition(g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(false)); - if (pdef->maxSubtype > 0) - CHECK_INCDEC_MODELVAR(event, g_model.moduleData[EXTERNAL_MODULE].subType, 0, pdef->maxSubtype); + CHECK_INCDEC_MODELVAR(event, g_model.moduleData[EXTERNAL_MODULE].subType, 0, getMaxMultiSubtype(EXTERNAL_MODULE)); } break; @@ -1243,7 +1231,7 @@ void menuModelSetup(event_t event) if (isModuleMultimodule(moduleIdx)) { int optionValue = g_model.moduleData[moduleIdx].multi.optionValue; - const uint8_t multi_proto = g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(true); + const uint8_t multi_proto = g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(); const mm_protocol_definition *pdef = getMultiProtocolDefinition(multi_proto); if (pdef->optionsstr) lcdDrawText(INDENT_WIDTH, y, pdef->optionsstr); @@ -1317,12 +1305,20 @@ void menuModelSetup(event_t event) #if defined (MULTIMODULE) case ITEM_MODEL_SETUP_EXTERNAL_MODULE_AUTOBIND: - if (g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(true) == MODULE_SUBTYPE_MULTI_DSM2) + if (g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol() == MODULE_SUBTYPE_MULTI_DSM2) g_model.moduleData[EXTERNAL_MODULE].multi.autoBindMode = editCheckBox(g_model.moduleData[EXTERNAL_MODULE].multi.autoBindMode, MODEL_SETUP_2ND_COLUMN, y, STR_MULTI_DSM_AUTODTECT, attr, event); else g_model.moduleData[EXTERNAL_MODULE].multi.autoBindMode = editCheckBox(g_model.moduleData[EXTERNAL_MODULE].multi.autoBindMode, MODEL_SETUP_2ND_COLUMN, y, STR_MULTI_AUTOBIND, attr, event); break; + case ITEM_MODEL_SETUP_EXTERNAL_MODULE_DISABLE_TELEM: + g_model.moduleData[EXTERNAL_MODULE].multi.disableTelemetry = editCheckBox(g_model.moduleData[EXTERNAL_MODULE].multi.disableTelemetry, MODEL_SETUP_2ND_COLUMN, y, INDENT TR_DISABLE_TELEM, attr, event); + break; + + case ITEM_MODEL_SETUP_EXTERNAL_MODULE_DISABLE_MAPPING: + g_model.moduleData[EXTERNAL_MODULE].multi.disableMapping = editCheckBox(g_model.moduleData[EXTERNAL_MODULE].multi.disableMapping, MODEL_SETUP_2ND_COLUMN, y, INDENT TR_DISABLE_CH_MAP, attr, event); + break; + case ITEM_MODEL_SETUP_EXTERNAL_MODULE_STATUS: { lcdDrawTextAlignedLeft(y, STR_MODULE_STATUS); diff --git a/radio/src/gui/212x64/model_telemetry.cpp b/radio/src/gui/212x64/model_telemetry.cpp index 1f5223640..439c68f0b 100644 --- a/radio/src/gui/212x64/model_telemetry.cpp +++ b/radio/src/gui/212x64/model_telemetry.cpp @@ -228,8 +228,8 @@ void menuModelTelemetry(event_t event) case ITEM_TELEMETRY_RSSI_LABEL: #if defined(MULTIMODULE) - if (telemetryProtocol == PROTOCOL_TELEMETRY_MULTIMODULE && g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(false) == MODULE_SUBTYPE_MULTI_FS_AFHDS2A) - lcdDrawTextAlignedLeft(y, "RSNR"); + if (telemetryProtocol == PROTOCOL_TELEMETRY_MULTIMODULE && (g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol() == MODULE_SUBTYPE_MULTI_FS_AFHDS2A || g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol() == MODULE_SUBTYPE_MULTI_HOTT)) + lcdDrawTextAlignedLeft(y, "RQly"); else lcdDrawTextAlignedLeft(y, "RSSI"); #else diff --git a/radio/src/gui/480x272/lcd.cpp b/radio/src/gui/480x272/lcd.cpp index eed5ed6d8..f139eaa5c 100644 --- a/radio/src/gui/480x272/lcd.cpp +++ b/radio/src/gui/480x272/lcd.cpp @@ -432,6 +432,37 @@ void lcdDrawBlackOverlay() lcdDrawFilledRect(0, 0, LCD_W, LCD_H, SOLID, OVERLAY_COLOR | OPACITY(8)); } +#if defined(MULTIMODULE) +void lcdDrawMultiProtocolString(coord_t x, coord_t y, uint8_t moduleIdx, uint8_t protocol, LcdFlags flags) +{ + if (protocol <= MODULE_SUBTYPE_MULTI_LAST) { + lcdDrawTextAtIndex(x, y, STR_MULTI_PROTOCOLS, protocol, flags); + } + else { + MultiModuleStatus &status = getMultiModuleStatus(moduleIdx); + if (status.protocolName[0] && status.isValid()) + lcdDrawText(x, y, status.protocolName, flags); + else + lcdDrawNumber(x, y, protocol + 3, flags); // Convert because of OpenTX FrSky fidling (OpenTX protocol tables and Multiprotocol tables don't match) + } +} + +void lcdDrawMultiSubProtocolString(coord_t x, coord_t y, uint8_t moduleIdx, uint8_t subType, LcdFlags flags) +{ + const mm_protocol_definition *pdef = getMultiProtocolDefinition(g_model.moduleData[moduleIdx].getMultiProtocol()); + if (subType <= pdef->maxSubtype && pdef->subTypeString != nullptr) { + lcdDrawTextAtIndex(x, y, pdef->subTypeString, subType, flags); + } + else { + MultiModuleStatus &status = getMultiModuleStatus(moduleIdx); + if (status.protocolName[0] && status.isValid()) + lcdDrawText(x, y, status.protocolSubName, flags); + else + lcdDrawNumber(x, y, subType, flags); + } +} +#endif + #if defined(SIMU) BitmapBuffer _lcd(BMP_RGB565, LCD_W, LCD_H, displayBuf); BitmapBuffer * lcd = &_lcd; diff --git a/radio/src/gui/480x272/lcd.h b/radio/src/gui/480x272/lcd.h index 455eca8d2..c66865d85 100644 --- a/radio/src/gui/480x272/lcd.h +++ b/radio/src/gui/480x272/lcd.h @@ -115,8 +115,9 @@ extern display_t displayBuf[DISPLAY_BUFFER_SIZE]; extern coord_t lcdNextPos; void lcdDrawChar(coord_t x, coord_t y, char c, LcdFlags flags=0); - void lcdDrawTextAtIndex(coord_t x, coord_t y, const char * s, uint8_t idx, LcdFlags flags=0); +void lcdDrawMultiProtocolString(coord_t x, coord_t y, uint8_t moduleIdx, uint8_t protocol, LcdFlags flags=0); +void lcdDrawMultiSubProtocolString(coord_t x, coord_t y, uint8_t moduleIdx, uint8_t subType, LcdFlags flags); inline void lcdClear() { diff --git a/radio/src/gui/480x272/model_setup.cpp b/radio/src/gui/480x272/model_setup.cpp index 8b6d66b6e..c70ea488c 100644 --- a/radio/src/gui/480x272/model_setup.cpp +++ b/radio/src/gui/480x272/model_setup.cpp @@ -69,13 +69,19 @@ enum MenuModelSetupItems { #if defined(HARDWARE_INTERNAL_MODULE) ITEM_MODEL_SETUP_INTERNAL_MODULE_LABEL, ITEM_MODEL_SETUP_INTERNAL_MODULE_TYPE, +#if defined(MULTIMODULE) ITEM_MODEL_SETUP_INTERNAL_MODULE_STATUS, ITEM_MODEL_SETUP_INTERNAL_MODULE_SYNCSTATUS, +#endif ITEM_MODEL_SETUP_INTERNAL_MODULE_CHANNELS, ITEM_MODEL_SETUP_INTERNAL_MODULE_NOT_ACCESS_RXNUM_BIND_RANGE, ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_MODEL_NUM, ITEM_MODEL_SETUP_INTERNAL_MODULE_OPTIONS, +#if defined(MULTIMODULE) ITEM_MODEL_SETUP_INTERNAL_MODULE_AUTOBIND, + ITEM_MODEL_SETUP_INTERNAL_MODULE_DISABLE_TELEM, + ITEM_MODEL_SETUP_INTERNAL_MODULE_DISABLE_MAPPING, +#endif #if defined(INTERNAL_MODULE_PXX1) && defined(EXTERNAL_ANTENNA) ITEM_MODEL_SETUP_INTERNAL_MODULE_ANTENNA, #endif @@ -99,6 +105,8 @@ enum MenuModelSetupItems { ITEM_MODEL_SETUP_EXTERNAL_MODULE_OPTIONS, #if defined(MULTIMODULE) ITEM_MODEL_SETUP_EXTERNAL_MODULE_AUTOBIND, + ITEM_MODEL_SETUP_EXTERNAL_MODULE_DISABLE_TELEM, + ITEM_MODEL_SETUP_EXTERNAL_MODULE_DISABLE_MAPPING, #endif ITEM_MODEL_SETUP_EXTERNAL_MODULE_POWER, ITEM_MODEL_SETUP_EXTERNAL_MODULE_FAILSAFE, @@ -563,6 +571,8 @@ void onModelAntennaSwitchConfirm(const char * result) IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 0), /* ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_MODEL_NUM*/ \ MODULE_OPTION_ROW(INTERNAL_MODULE), /* ITEM_MODEL_SETUP_INTERNAL_MODULE_OPTIONS */ \ MULTIMODULE_MODULE_ROWS(INTERNAL_MODULE) /* ITEM_MODEL_SETUP_INTERNAL_MODULE_AUTOBIND */ \ + /* ITEM_MODEL_SETUP_INTERNAL_MODULE_DISABLE_TELEM */ \ + /* ITEM_MODEL_SETUP_INTERNAL_MODULE_DISABLE_MAPPING */ \ 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 */ \ @@ -1060,18 +1070,10 @@ bool menuModelSetup(event_t event) lcdDrawTextAtIndex(MODEL_SETUP_3RD_COLUMN, y, STR_R9M_REGION, g_model.moduleData[moduleIdx].subType, (menuHorizontalPosition==1 ? attr : 0)); #if defined(MULTIMODULE) else if (isModuleMultimodule(moduleIdx)) { - int multi_rfProto = g_model.moduleData[moduleIdx].getMultiProtocol(false); - if (g_model.moduleData[moduleIdx].multi.customProto) { - lcdDrawText(MODEL_SETUP_3RD_COLUMN, y, STR_MULTI_CUSTOM, menuHorizontalPosition == 1 ? attr : 0); - lcdDrawNumber(MODEL_SETUP_4TH_COLUMN, y, multi_rfProto, menuHorizontalPosition==2 ? attr : 0, 2); - lcdDrawNumber(MODEL_SETUP_4TH_COLUMN + MODEL_SETUP_BIND_OFS, y, g_model.moduleData[moduleIdx].subType, menuHorizontalPosition==3 ? attr : 0, 2); - } - else { - const mm_protocol_definition * pdef = getMultiProtocolDefinition(multi_rfProto); - lcdDrawTextAtIndex(MODEL_SETUP_3RD_COLUMN, y, STR_MULTI_PROTOCOLS, multi_rfProto, menuHorizontalPosition == 1 ? attr : 0); - if (pdef->subTypeString != nullptr) - lcdDrawTextAtIndex(MODEL_SETUP_4TH_COLUMN, y, pdef->subTypeString, g_model.moduleData[moduleIdx].subType, menuHorizontalPosition==2 ? attr : 0); - } + int multi_rfProto = g_model.moduleData[moduleIdx].getMultiProtocol(); + lcdDrawMultiProtocolString(MODEL_SETUP_3RD_COLUMN, y, moduleIdx, multi_rfProto, menuHorizontalPosition == 1 ? attr : 0); + if (MULTIMODULE_HAS_SUBTYPE(EXTERNAL_MODULE)) + lcdDrawMultiSubProtocolString(MODEL_SETUP_4TH_COLUMN, y, moduleIdx, g_model.moduleData[moduleIdx].subType, menuHorizontalPosition==2 ? attr : 0); } #endif if (attr && menuHorizontalPosition == 0 && moduleIdx == EXTERNAL_MODULE) { @@ -1110,21 +1112,21 @@ bool menuModelSetup(event_t event) CHECK_INCDEC_MODELVAR(event, g_model.moduleData[moduleIdx].rfProtocol, DSM2_PROTO_LP45, DSM2_PROTO_DSMX); #if defined(MULTIMODULE) else if (isModuleMultimodule(moduleIdx)) { - int multiRfProto = g_model.moduleData[moduleIdx].multi.customProto == 1 ? MODULE_SUBTYPE_MULTI_CUSTOM : g_model.moduleData[moduleIdx].getMultiProtocol(false); - CHECK_INCDEC_MODELVAR_CHECK(event, multiRfProto, MODULE_SUBTYPE_MULTI_FIRST, MODULE_SUBTYPE_MULTI_LAST, isMultiProtocolSelectable); + int multiRfProto = g_model.moduleData[moduleIdx].getMultiProtocol(); + CHECK_INCDEC_MODELVAR_CHECK(event, multiRfProto, MODULE_SUBTYPE_MULTI_FIRST, MULTI_MAX_PROTOCOLS, isMultiProtocolSelectable); if (checkIncDec_Ret) { - g_model.moduleData[moduleIdx].multi.customProto = (multiRfProto == MODULE_SUBTYPE_MULTI_CUSTOM); - if (!g_model.moduleData[moduleIdx].multi.customProto) - g_model.moduleData[moduleIdx].setMultiProtocol(multiRfProto); + g_model.moduleData[moduleIdx].setMultiProtocol(multiRfProto); g_model.moduleData[moduleIdx].subType = 0; // Sensible default for DSM2 (same as for ppm): 7ch@22ms + Autodetect settings enabled - if (g_model.moduleData[moduleIdx].getMultiProtocol(true) == MODULE_SUBTYPE_MULTI_DSM2) { + if (g_model.moduleData[moduleIdx].getMultiProtocol() == MODULE_SUBTYPE_MULTI_DSM2) { g_model.moduleData[moduleIdx].multi.autoBindMode = 1; } else { g_model.moduleData[moduleIdx].multi.autoBindMode = 0; } g_model.moduleData[moduleIdx].multi.optionValue = 0; + g_model.moduleData[moduleIdx].multi.disableTelemetry = 0; + g_model.moduleData[moduleIdx].multi.disableMapping = 0; } } #endif @@ -1142,20 +1144,10 @@ bool menuModelSetup(event_t event) break; #if defined(MULTIMODULE) - case 2: - if (g_model.moduleData[moduleIdx].multi.customProto) { - g_model.moduleData[moduleIdx].setMultiProtocol(checkIncDec(event, g_model.moduleData[moduleIdx].getMultiProtocol(false), 0, 63, EE_MODEL)); - break; - } else { - const mm_protocol_definition *pdef = getMultiProtocolDefinition(g_model.moduleData[moduleIdx].getMultiProtocol(false)); - if (pdef->maxSubtype > 0) - CHECK_INCDEC_MODELVAR(event, g_model.moduleData[moduleIdx].subType, 0, pdef->maxSubtype); - } - break; - case 3: - // Custom protocol, third column is subtype - CHECK_INCDEC_MODELVAR(event, g_model.moduleData[moduleIdx].subType, 0, 7); + case 2: { + CHECK_INCDEC_MODELVAR(event, g_model.moduleData[moduleIdx].subType, 0, getMaxMultiSubtype(moduleIdx)); break; + } #endif } } @@ -1627,11 +1619,23 @@ bool menuModelSetup(event_t event) if (isModuleMultimodule(moduleIdx)) { int optionValue = g_model.moduleData[moduleIdx].multi.optionValue; - const uint8_t multi_proto = g_model.moduleData[moduleIdx].getMultiProtocol(true); - const mm_protocol_definition *pdef = getMultiProtocolDefinition(multi_proto); - if (pdef->optionsstr) - lcdDrawText(MENUS_MARGIN_LEFT + INDENT_WIDTH, y, pdef->optionsstr); - + const uint8_t multi_proto = g_model.moduleData[moduleIdx].getMultiProtocol(); + if (multi_proto < MODULE_SUBTYPE_MULTI_LAST) { + const mm_protocol_definition * pdef = getMultiProtocolDefinition(multi_proto); + if (pdef->optionsstr) { + lcdDrawText(MENUS_MARGIN_LEFT + INDENT_WIDTH, y, pdef->optionsstr); + if (attr && pdef->optionsstr == STR_MULTI_RFTUNE) { + lcdDrawNumber(LCD_W - 10, y, TELEMETRY_RSSI(), RIGHT, 0, "RSSI(", ")"); + } + } + } + else { + MultiModuleStatus &status = getMultiModuleStatus(moduleIdx); + lcdDrawText(MENUS_MARGIN_LEFT + INDENT_WIDTH, y, mm_options_strings::options[status.optionDisp]); + if (attr && status.optionDisp == 2) { + lcdDrawNumber(LCD_W - 10, y, TELEMETRY_RSSI(), RIGHT, 0, "RSSI(", ")"); + } + } if (multi_proto == MODULE_SUBTYPE_MULTI_FS_AFHDS2A) optionValue = 50 + 5 * optionValue; @@ -1643,11 +1647,17 @@ bool menuModelSetup(event_t event) else if (multi_proto == MODULE_SUBTYPE_MULTI_OLRS) { CHECK_INCDEC_MODELVAR(event, g_model.moduleData[moduleIdx].multi.optionValue, -1, 7); } + else if (multi_proto == MODULE_SUBTYPE_MULTI_DSM2) { + CHECK_INCDEC_MODELVAR(event, g_model.moduleData[moduleIdx].multi.optionValue, 0, 1); + } + else if (multi_proto == MODULE_SUBTYPE_MULTI_BAYANG) { + CHECK_INCDEC_MODELVAR(event, g_model.moduleData[moduleIdx].multi.optionValue, 0, 3); + } + else if (multi_proto == MODULE_SUBTYPE_MULTI_XN297DP) { + CHECK_INCDEC_MODELVAR(event, g_model.moduleData[moduleIdx].multi.optionValue, -1, 84); + } else { CHECK_INCDEC_MODELVAR(event, g_model.moduleData[moduleIdx].multi.optionValue, -128, 127); - if (pdef->optionsstr == STR_MULTI_RFTUNE) { - lcdDrawNumber(LCD_W - 10, y, TELEMETRY_RSSI(), RIGHT, 0, "RSSI(", ")"); - } } } } @@ -1671,7 +1681,7 @@ bool menuModelSetup(event_t event) case ITEM_MODEL_SETUP_EXTERNAL_MODULE_POWER: { if (isModuleR9MNonAccess(moduleIdx)) { - lcdDrawText(MENUS_MARGIN_LEFT, y, STR_RFPOWER); + lcdDrawText(MENUS_MARGIN_LEFT + INDENT_WIDTH, y, STR_RFPOWER); if (isModuleR9M_FCC_VARIANT(moduleIdx)) { lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_R9M_FCC_POWER_VALUES, g_model.moduleData[moduleIdx].pxx.power, LEFT | attr); if (attr) @@ -1704,13 +1714,29 @@ bool menuModelSetup(event_t event) case ITEM_MODEL_SETUP_INTERNAL_MODULE_AUTOBIND: #endif case ITEM_MODEL_SETUP_EXTERNAL_MODULE_AUTOBIND: - if (g_model.moduleData[moduleIdx].getMultiProtocol(true) == MODULE_SUBTYPE_MULTI_DSM2) + if (g_model.moduleData[moduleIdx].getMultiProtocol() == MODULE_SUBTYPE_MULTI_DSM2) lcdDrawText(MENUS_MARGIN_LEFT, y, STR_MULTI_DSM_AUTODTECT); else lcdDrawText(MENUS_MARGIN_LEFT, y, STR_MULTI_AUTOBIND); g_model.moduleData[moduleIdx].multi.autoBindMode = editCheckBox(g_model.moduleData[moduleIdx].multi.autoBindMode, MODEL_SETUP_2ND_COLUMN, y, attr, event); break; +#if defined(HARDWARE_INTERNAL_MODULE) + case ITEM_MODEL_SETUP_INTERNAL_MODULE_DISABLE_TELEM: +#endif + case ITEM_MODEL_SETUP_EXTERNAL_MODULE_DISABLE_TELEM: + lcdDrawText(MENUS_MARGIN_LEFT + INDENT_WIDTH, y, STR_DISABLE_TELEM); + g_model.moduleData[moduleIdx].multi.disableTelemetry = editCheckBox(g_model.moduleData[moduleIdx].multi.disableTelemetry, MODEL_SETUP_2ND_COLUMN, y, attr, event); + break; + +#if defined(HARDWARE_INTERNAL_MODULE) + case ITEM_MODEL_SETUP_INTERNAL_MODULE_DISABLE_MAPPING: +#endif + case ITEM_MODEL_SETUP_EXTERNAL_MODULE_DISABLE_MAPPING: + lcdDrawText(MENUS_MARGIN_LEFT + INDENT_WIDTH, y, STR_DISABLE_CH_MAP); + g_model.moduleData[moduleIdx].multi.disableMapping = editCheckBox(g_model.moduleData[moduleIdx].multi.disableMapping, MODEL_SETUP_2ND_COLUMN, y, attr, event); + break; + #if defined(HARDWARE_INTERNAL_MODULE) case ITEM_MODEL_SETUP_INTERNAL_MODULE_STATUS: #endif diff --git a/radio/src/gui/480x272/model_telemetry.cpp b/radio/src/gui/480x272/model_telemetry.cpp index 6bcf4ed20..82138dff3 100644 --- a/radio/src/gui/480x272/model_telemetry.cpp +++ b/radio/src/gui/480x272/model_telemetry.cpp @@ -220,8 +220,8 @@ bool menuModelTelemetry(event_t event) #if defined(MULTIMODULE) if (!IS_INTERNAL_MODULE_ON() && g_model.moduleData[EXTERNAL_MODULE].type == MODULE_TYPE_MULTIMODULE && - g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(false) == MODULE_SUBTYPE_MULTI_FS_AFHDS2A) - lcdDrawText(MENUS_MARGIN_LEFT, y, "RSNR"); + (g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol() == MODULE_SUBTYPE_MULTI_FS_AFHDS2A || g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol() == MODULE_SUBTYPE_MULTI_HOTT )) + lcdDrawText(MENUS_MARGIN_LEFT, y, "RQly"); else #endif lcdDrawText(MENUS_MARGIN_LEFT, y, "RSSI"); diff --git a/radio/src/gui/480x272/radio_spectrum_analyser.cpp b/radio/src/gui/480x272/radio_spectrum_analyser.cpp index 7a64ebd37..4903fdfa8 100644 --- a/radio/src/gui/480x272/radio_spectrum_analyser.cpp +++ b/radio/src/gui/480x272/radio_spectrum_analyser.cpp @@ -39,7 +39,11 @@ coord_t getAverage(uint8_t number, const uint8_t * value) return sum / number; } -#define SPECTRUM_ROW (isModuleMultimodule(g_moduleIdx) ? READONLY_ROW : (uint8_t)0) +#if defined(INTERNAL_MODULE_MULTI) + #define SPECTRUM_ROW (g_moduleIdx == INTERNAL_MODULE ? READONLY_ROW : isModuleMultimodule(g_moduleIdx) ? READONLY_ROW : (uint8_t)0) +#else + #define SPECTRUM_ROW (isModuleMultimodule(g_moduleIdx) ? READONLY_ROW : (uint8_t)0) +#endif bool menuRadioSpectrumAnalyser(event_t event) { @@ -54,8 +58,12 @@ bool menuRadioSpectrumAnalyser(event_t event) lcdRefresh(); if (isModulePXX2(g_moduleIdx)) moduleState[g_moduleIdx].readModuleInformation(&reusableBuffer.moduleSetup.pxx2.moduleInformation, PXX2_HW_INFO_TX_ID, PXX2_HW_INFO_TX_ID); - else if (isModuleMultimodule((g_moduleIdx))) - moduleState[g_moduleIdx].mode = MODULE_MODE_NORMAL; + else if (isModuleMultimodule(g_moduleIdx)) { + if (reusableBuffer.spectrumAnalyser.moduleOFF) + setModuleType(INTERNAL_MODULE, MODULE_TYPE_NONE); + else + moduleState[g_moduleIdx].mode = MODULE_MODE_NORMAL; + } /* wait 1s to resume normal operation before leaving */ watchdogSuspend(1000); RTOS_WAIT_MS(1000); @@ -71,9 +79,15 @@ bool menuRadioSpectrumAnalyser(event_t event) } return false; } - memclear(&reusableBuffer.spectrumAnalyser, sizeof(reusableBuffer.spectrumAnalyser)); +#if defined(INTERNAL_MODULE_MULTI) + if (g_moduleIdx == INTERNAL_MODULE && g_model.moduleData[INTERNAL_MODULE].type == MODULE_TYPE_NONE) { + reusableBuffer.spectrumAnalyser.moduleOFF = true; + setModuleType(INTERNAL_MODULE, MODULE_TYPE_MULTIMODULE); + } +#endif + if (isModuleR9MAccess(g_moduleIdx)) { reusableBuffer.spectrumAnalyser.spanDefault = 20; reusableBuffer.spectrumAnalyser.spanMax = 40; diff --git a/radio/src/gui/common/stdlcd/draw_functions.cpp b/radio/src/gui/common/stdlcd/draw_functions.cpp index 3608abc62..b37c674ed 100644 --- a/radio/src/gui/common/stdlcd/draw_functions.cpp +++ b/radio/src/gui/common/stdlcd/draw_functions.cpp @@ -21,6 +21,37 @@ #include "opentx.h" #include +void lcdDrawMultiProtocolString(coord_t x, coord_t y, uint8_t moduleIdx, uint8_t protocol, LcdFlags flags) +{ + if (protocol <= MODULE_SUBTYPE_MULTI_LAST) { + lcdDrawTextAtIndex(x, y, STR_MULTI_PROTOCOLS, protocol, flags); + return; + } + else { + MultiModuleStatus &status = getMultiModuleStatus(moduleIdx); + if (status.protocolName[0] && status.isValid()) + lcdDrawText(x, y, status.protocolName, flags); + else + lcdDrawNumber(x, y, protocol + 3, flags); // Convert because of OpenTX FrSky fidling (OpenTX protocol tables and Multiprotocol tables don't match) + } +} + +void lcdDrawMultiSubProtocolString(coord_t x, coord_t y, uint8_t moduleIdx, uint8_t subType, LcdFlags flags) +{ + const mm_protocol_definition *pdef = getMultiProtocolDefinition(g_model.moduleData[moduleIdx].getMultiProtocol()); + if (subType <= pdef->maxSubtype && pdef->subTypeString != nullptr) { + lcdDrawTextAtIndex(x, y, pdef->subTypeString, subType, flags); + return; + } + else { + MultiModuleStatus &status = getMultiModuleStatus(moduleIdx); + if (status.protocolName[0] && status.isValid()) + lcdDrawText(x, y, status.protocolSubName, flags); + else + lcdDrawNumber(x, y, subType, flags); + } +} + void drawStringWithIndex(coord_t x, coord_t y, const char * str, uint8_t idx, LcdFlags flags) { if (flags & RIGHT) { diff --git a/radio/src/gui/common/stdlcd/draw_functions.h b/radio/src/gui/common/stdlcd/draw_functions.h index 855b8600c..acf4a949f 100644 --- a/radio/src/gui/common/stdlcd/draw_functions.h +++ b/radio/src/gui/common/stdlcd/draw_functions.h @@ -22,7 +22,8 @@ #define _STDLCD_DRAW_FUNCTIONS_H_ #include "lcd.h" - +void lcdDrawMultiProtocolString(coord_t x, coord_t y, uint8_t moduleIdx, uint8_t protocol, LcdFlags flags = 0); +void lcdDrawMultiSubProtocolString(coord_t x, coord_t y, uint8_t moduleIdx, uint8_t subType, LcdFlags flags = 0); void drawStringWithIndex(coord_t x, coord_t y, const char * str, uint8_t idx, LcdFlags att=0); void drawValueWithUnit(coord_t x, coord_t y, int val, uint8_t unit, LcdFlags att=0); diff --git a/radio/src/gui/gui_common.cpp b/radio/src/gui/gui_common.cpp index 655b885c2..9af725566 100644 --- a/radio/src/gui/gui_common.cpp +++ b/radio/src/gui/gui_common.cpp @@ -780,6 +780,37 @@ int getFirstAvailable(int min, int max, IsValueAvailable isValueAvailable) return retval; } #if defined(MULTIMODULE) + +// This maps OpenTX multi type with Pascal's Multi type +uint8_t convertMultiProtocol(uint8_t moduleIdx, uint8_t type) +{ + + // 15 for Multimodule is FrskyX or D16 which we map as a subprotocol of 3 (FrSky) + // all protos > frskyx are therefore also off by one + if (type >= 15) + type = type + 1; + + // 25 is again a FrSky protocol (FrskyV) so shift again + if (type >= 25) + type = type + 1; + + if (type == MODULE_SUBTYPE_MULTI_FRSKY) { + int subtype = g_model.moduleData[moduleIdx].subType; + if (subtype == MM_RF_FRSKY_SUBTYPE_D8) { + //D8 + type = 3; + } + else if (subtype == MM_RF_FRSKY_SUBTYPE_V8) { + //V8 + type = 25; + } + else { + type = 15; + } + } + return type; +} + // Third row is number of subtypes -1 (max valid subtype) #define NO_SUBTYPE nullptr @@ -804,7 +835,7 @@ const char STR_SUBTYPE_SYMAX[] = "\003""Std""X5C"; const char STR_SUBTYPE_SLT[] = "\006""V1_6ch""V2_8ch""Q100\0 ""Q200\0 ""MR100\0"; const char STR_SUBTYPE_CX10[] = "\007""Green\0 ""Blue\0 ""DM007\0 ""-\0 ""JC3015a""JC3015b""MK33041"; const char STR_SUBTYPE_CG023[] = "\005""Std\0 ""YD829"; -const char STR_SUBTYPE_BAYANG[] = "\007""Std\0 ""H8S3D\0 ""X16 AH\0 ""IRDrone""DHD D4"; +const char STR_SUBTYPE_BAYANG[] = "\007""Std\0 ""H8S3D\0 ""X16 AH\0""IRDrone""DHD D4"; const char STR_SUBTYPE_MT99[] = "\006""MT99\0 ""H7\0 ""YZ\0 ""LS\0 ""FY805"; const char STR_SUBTYPE_MJXQ[] = "\007""WLH08\0 ""X600\0 ""X800\0 ""H26D\0 ""E010\0 ""H26WH\0 ""Phoenix"; const char STR_SUBTYPE_FY326[] = "\005""Std\0 ""FY319"; @@ -825,53 +856,66 @@ const char STR_SUBTYPE_REDPINE[] = "\004""Fast""Slow"; const char STR_SUBTYPE_POTENSIC[] = "\003""A20"; const char STR_SUBTYPE_ZSX[] = "\007""280JJRC"; const char STR_SUBTYPE_FLYZONE[] = "\005""FZ410"; -const char STR_SUBTYPE_FRSKYX_RX[] = "\003""FCC""LBT"; + +const char* mm_options_strings::options[] = { + nullptr, + STR_MULTI_OPTION, + STR_MULTI_RFTUNE, + STR_MULTI_VIDFREQ, + STR_MULTI_FIXEDID, + STR_MULTI_TELEMETRY, + STR_MULTI_SERVOFREQ, + STR_MULTI_MAX_THROW, + STR_MULTI_RFCHAN +}; const mm_protocol_definition multi_protocols[] = { - - {MODULE_SUBTYPE_MULTI_FLYSKY, 4, false, STR_SUBTYPE_FLYSKY, nullptr}, - {MODULE_SUBTYPE_MULTI_HUBSAN, 2, false, STR_SUBTYPE_HUBSAN, STR_MULTI_VIDFREQ}, - {MODULE_SUBTYPE_MULTI_FRSKY, 5, false, STR_SUBTYPE_FRSKY, STR_MULTI_RFTUNE}, - {MODULE_SUBTYPE_MULTI_HISKY, 1, false, STR_SUBTYPE_HISKY, nullptr}, - {MODULE_SUBTYPE_MULTI_V2X2, 1, false, STR_SUBTYPE_V2X2, nullptr}, - {MODULE_SUBTYPE_MULTI_DSM2, 3, false, STR_SUBTYPE_DSM, nullptr}, - {MODULE_SUBTYPE_MULTI_DEVO, 4, false, STR_SUBTYPE_DEVO, STR_MULTI_FIXEDID}, - {MODULE_SUBTYPE_MULTI_YD717, 4, false, STR_SUBTYPE_YD717, nullptr}, - {MODULE_SUBTYPE_MULTI_KN, 1, false, STR_SUBTYPE_KN, nullptr}, - {MODULE_SUBTYPE_MULTI_SYMAX, 1, false, STR_SUBTYPE_SYMAX, nullptr}, - {MODULE_SUBTYPE_MULTI_SLT, 4, false, STR_SUBTYPE_SLT, nullptr}, - {MODULE_SUBTYPE_MULTI_CX10, 6, false, STR_SUBTYPE_CX10, nullptr}, - {MODULE_SUBTYPE_MULTI_CG023, 1, false, STR_SUBTYPE_CG023, nullptr}, - {MODULE_SUBTYPE_MULTI_BAYANG, 4, false, STR_SUBTYPE_BAYANG, STR_MULTI_TELEMETRY}, - {MODULE_SUBTYPE_MULTI_MT99XX, 4, false, STR_SUBTYPE_MT99, nullptr}, - {MODULE_SUBTYPE_MULTI_MJXQ, 6, false, STR_SUBTYPE_MJXQ, STR_MULTI_RFTUNE}, - {MODULE_SUBTYPE_MULTI_FY326, 1, false, STR_SUBTYPE_FY326, nullptr}, - {MODULE_SUBTYPE_MULTI_SFHSS, 0, true, NO_SUBTYPE, STR_MULTI_RFTUNE}, - {MODULE_SUBTYPE_MULTI_HONTAI, 3, false, STR_SUBTYPE_HONTAI, nullptr}, - {MODULE_SUBTYPE_MULTI_OLRS, 0, false, NO_SUBTYPE, STR_RFPOWER}, - {MODULE_SUBTYPE_MULTI_FS_AFHDS2A, 3, true, STR_SUBTYPE_AFHDS2A, STR_MULTI_SERVOFREQ}, - {MODULE_SUBTYPE_MULTI_Q2X2, 2, false, STR_SUBTYPE_Q2X2, nullptr}, - {MODULE_SUBTYPE_MULTI_WK_2X01, 5, false, STR_SUBTYPE_WK2x01, nullptr}, - {MODULE_SUBTYPE_MULTI_Q303, 3, false, STR_SUBTYPE_Q303, nullptr}, - {MODULE_SUBTYPE_MULTI_CABELL, 7, false, STR_SUBTYPE_CABELL, STR_MULTI_OPTION}, - {MODULE_SUBTYPE_MULTI_H83D, 3, false, STR_SUBTYPE_H83D, nullptr}, - {MODULE_SUBTYPE_MULTI_CORONA, 2, false, STR_SUBTYPE_CORONA, STR_MULTI_RFTUNE}, - {MODULE_SUBTYPE_MULTI_HITEC, 2, false, STR_SUBTYPE_HITEC, STR_MULTI_RFTUNE}, - {MODULE_SUBTYPE_MULTI_BUGS_MINI, 1, false, STR_SUBTYPE_BUGS_MINI, nullptr}, - {MODULE_SUBTYPE_MULTI_TRAXXAS, 0, false, STR_SUBTYPE_TRAXXAS, nullptr}, - {MODULE_SUBTYPE_MULTI_E01X, 2, false, STR_SUBTYPE_E01X, STR_MULTI_OPTION}, - {MODULE_SUBTYPE_MULTI_V911S, 0, false, NO_SUBTYPE, STR_MULTI_RFTUNE}, - {MODULE_SUBTYPE_MULTI_GD00X, 1, false, STR_SUBTYPE_GD00X, STR_MULTI_RFTUNE}, - {MODULE_SUBTYPE_MULTI_KF606, 0, false, NO_SUBTYPE, STR_MULTI_RFTUNE}, - {MODULE_SUBTYPE_MULTI_REDPINE, 1, false, STR_SUBTYPE_REDPINE, STR_MULTI_RFTUNE}, - {MODULE_SUBTYPE_MULTI_POTENSIC, 0, false, STR_SUBTYPE_POTENSIC, nullptr}, - {MODULE_SUBTYPE_MULTI_ZSX, 0, false, STR_SUBTYPE_ZSX, nullptr}, - {MODULE_SUBTYPE_MULTI_FLYZONE, 0, false, STR_SUBTYPE_FLYZONE, nullptr}, - {MODULE_SUBTYPE_MULTI_FRSKYX_RX, 1, false, STR_SUBTYPE_FRSKYX_RX, STR_MULTI_RFTUNE}, - {MM_RF_CUSTOM_SELECTED, 7, true, NO_SUBTYPE, STR_MULTI_OPTION}, +// Protocol as defined in pulses\modules_constants.h, number of sub_protocols - 1, Failsafe supported, Disable channel mapping supported, Subtype string, Option type + {MODULE_SUBTYPE_MULTI_FLYSKY, 4, false, true, STR_SUBTYPE_FLYSKY, nullptr}, + {MODULE_SUBTYPE_MULTI_HUBSAN, 2, false, false, STR_SUBTYPE_HUBSAN, STR_MULTI_VIDFREQ}, + {MODULE_SUBTYPE_MULTI_FRSKY, 5, false, false, STR_SUBTYPE_FRSKY, STR_MULTI_RFTUNE}, + {MODULE_SUBTYPE_MULTI_HISKY, 1, false, true, STR_SUBTYPE_HISKY, nullptr}, + {MODULE_SUBTYPE_MULTI_V2X2, 1, false, false, STR_SUBTYPE_V2X2, nullptr}, + {MODULE_SUBTYPE_MULTI_DSM2, 3, false, true, STR_SUBTYPE_DSM, STR_MULTI_MAX_THROW}, + {MODULE_SUBTYPE_MULTI_DEVO, 4, false, true, STR_SUBTYPE_DEVO, STR_MULTI_FIXEDID}, + {MODULE_SUBTYPE_MULTI_YD717, 4, false, false, STR_SUBTYPE_YD717, nullptr}, + {MODULE_SUBTYPE_MULTI_KN, 1, false, false, STR_SUBTYPE_KN, nullptr}, + {MODULE_SUBTYPE_MULTI_SYMAX, 1, false, false, STR_SUBTYPE_SYMAX, nullptr}, + {MODULE_SUBTYPE_MULTI_SLT, 4, false, true, STR_SUBTYPE_SLT, nullptr}, + {MODULE_SUBTYPE_MULTI_CX10, 6, false, false, STR_SUBTYPE_CX10, nullptr}, + {MODULE_SUBTYPE_MULTI_CG023, 1, false, false, STR_SUBTYPE_CG023, nullptr}, + {MODULE_SUBTYPE_MULTI_BAYANG, 4, false, false, STR_SUBTYPE_BAYANG, STR_MULTI_TELEMETRY}, + {MODULE_SUBTYPE_MULTI_MT99XX, 4, false, false, STR_SUBTYPE_MT99, nullptr}, + {MODULE_SUBTYPE_MULTI_MJXQ, 6, false, false, STR_SUBTYPE_MJXQ, STR_MULTI_RFTUNE}, + {MODULE_SUBTYPE_MULTI_FY326, 1, false, false, STR_SUBTYPE_FY326, nullptr}, + {MODULE_SUBTYPE_MULTI_SFHSS, 0, true, true, NO_SUBTYPE, STR_MULTI_RFTUNE}, + {MODULE_SUBTYPE_MULTI_HONTAI, 3, false, false, STR_SUBTYPE_HONTAI, nullptr}, + {MODULE_SUBTYPE_MULTI_OLRS, 0, false, false, NO_SUBTYPE, STR_RFPOWER}, + {MODULE_SUBTYPE_MULTI_FS_AFHDS2A, 3, true, true, STR_SUBTYPE_AFHDS2A, STR_MULTI_SERVOFREQ}, + {MODULE_SUBTYPE_MULTI_Q2X2, 2, false, false, STR_SUBTYPE_Q2X2, nullptr}, + {MODULE_SUBTYPE_MULTI_WK_2X01, 5, false, true, STR_SUBTYPE_WK2x01, nullptr}, + {MODULE_SUBTYPE_MULTI_Q303, 3, false, false, STR_SUBTYPE_Q303, nullptr}, + {MODULE_SUBTYPE_MULTI_CABELL, 7, false, false, STR_SUBTYPE_CABELL, STR_MULTI_OPTION}, + {MODULE_SUBTYPE_MULTI_H83D, 3, false, false, STR_SUBTYPE_H83D, nullptr}, + {MODULE_SUBTYPE_MULTI_CORONA, 2, false, false, STR_SUBTYPE_CORONA, STR_MULTI_RFTUNE}, + {MODULE_SUBTYPE_MULTI_HITEC, 2, false, false, STR_SUBTYPE_HITEC, STR_MULTI_RFTUNE}, + {MODULE_SUBTYPE_MULTI_BUGS_MINI, 1, false, false, STR_SUBTYPE_BUGS_MINI, nullptr}, + {MODULE_SUBTYPE_MULTI_TRAXXAS, 0, false, false, STR_SUBTYPE_TRAXXAS, nullptr}, + {MODULE_SUBTYPE_MULTI_E01X, 2, false, false, STR_SUBTYPE_E01X, STR_MULTI_OPTION}, + {MODULE_SUBTYPE_MULTI_V911S, 0, false, false, NO_SUBTYPE, STR_MULTI_RFTUNE}, + {MODULE_SUBTYPE_MULTI_GD00X, 1, false, false, STR_SUBTYPE_GD00X, STR_MULTI_RFTUNE}, + {MODULE_SUBTYPE_MULTI_KF606, 0, false, false, NO_SUBTYPE, STR_MULTI_RFTUNE}, + {MODULE_SUBTYPE_MULTI_REDPINE, 1, false, false, STR_SUBTYPE_REDPINE, STR_MULTI_RFTUNE}, + {MODULE_SUBTYPE_MULTI_POTENSIC, 0, false, false, STR_SUBTYPE_POTENSIC, nullptr}, + {MODULE_SUBTYPE_MULTI_ZSX, 0, false, false, STR_SUBTYPE_ZSX, nullptr}, + {MODULE_SUBTYPE_MULTI_FLYZONE, 0, false, false, STR_SUBTYPE_FLYZONE, nullptr}, + {MODULE_SUBTYPE_MULTI_FRSKYX_RX, 0, false, false, NO_SUBTYPE, STR_MULTI_RFTUNE}, + {MODULE_SUBTYPE_MULTI_ESky, 0, false, true, NO_SUBTYPE, nullptr}, + {MODULE_SUBTYPE_MULTI_J6PRO, 0, false, true, NO_SUBTYPE, nullptr}, + {MM_RF_CUSTOM_SELECTED, 7, true, true, NO_SUBTYPE, STR_MULTI_OPTION}, // Sentinel and default for protocols not listed above (MM_RF_CUSTOM is 0xff) - {0xfe, 0, false, NO_SUBTYPE, nullptr} + {0xfe, 0, false, true, NO_SUBTYPE, nullptr} }; #undef NO_SUBTYPE diff --git a/radio/src/gui/gui_common.h b/radio/src/gui/gui_common.h index d846f0567..297808555 100644 --- a/radio/src/gui/gui_common.h +++ b/radio/src/gui/gui_common.h @@ -153,7 +153,7 @@ inline uint8_t MODULE_CHANNELS_ROWS(int moduleIdx) if (!IS_MODULE_ENABLED(moduleIdx)) return HIDDEN_ROW; - if (isModuleDSM2(moduleIdx) || isModuleCrossfire(moduleIdx) || isModuleSBUS(moduleIdx) || (isModuleMultimodule(moduleIdx) && g_model.moduleData[moduleIdx].getMultiProtocol(true) != MODULE_SUBTYPE_MULTI_DSM2)) + if (isModuleDSM2(moduleIdx) || isModuleCrossfire(moduleIdx) || isModuleSBUS(moduleIdx) || (isModuleMultimodule(moduleIdx) && g_model.moduleData[moduleIdx].getMultiProtocol() != MODULE_SUBTYPE_MULTI_DSM2)) return 0; else return 1; @@ -163,17 +163,60 @@ inline uint8_t MODULE_CHANNELS_ROWS(int moduleIdx) #if defined(MULTIMODULE) // When using packed, the pointer in here end up not being aligned, which clang and gcc complain about // Keep the order of the fields that the so that the size stays small +struct mm_options_strings { + static const char* options[]; +}; + struct mm_protocol_definition { uint8_t protocol; uint8_t maxSubtype; bool failsafe; + bool disable_ch_mapping; const char *subTypeString; const char *optionsstr; }; + const mm_protocol_definition *getMultiProtocolDefinition (uint8_t protocol); -#define MULTIMODULE_STATUS_ROWS(moduleIdx) isModuleMultimodule(moduleIdx) ? TITLE_ROW : HIDDEN_ROW, (isModuleMultimodule(moduleIdx) && getMultiSyncStatus(moduleIdx).isValid()) ? TITLE_ROW : HIDDEN_ROW, -#define MULTIMODULE_MODULE_ROWS(moduleIdx) isModuleMultimodule(moduleIdx) ? (uint8_t) 0 : HIDDEN_ROW, -#define MULTIMODULE_MODE_ROWS(moduleIdx) (g_model.moduleData[moduleIdx].multi.customProto) ? (uint8_t) 3 :MULTIMODULE_HAS_SUBTYPE(g_model.moduleData[moduleIdx].getMultiProtocol(true)) ? (uint8_t)2 : (uint8_t)1 + +inline uint8_t getMaxMultiSubtype(uint8_t moduleIdx) +{ + MultiModuleStatus &status = getMultiModuleStatus(moduleIdx); + const mm_protocol_definition *pdef = getMultiProtocolDefinition(g_model.moduleData[moduleIdx].getMultiProtocol()); + + if (g_model.moduleData[moduleIdx].getMultiProtocol() == MODULE_SUBTYPE_MULTI_FRSKY) { + return 5; + } + + if (g_model.moduleData[moduleIdx].getMultiProtocol() > MODULE_SUBTYPE_MULTI_LAST) { + if (status.isValid()) + return (status.protocolSubNbr == 0 ? 0 : status.protocolSubNbr - 1); + else + return 7; + } + else { + return max((uint8_t )(status.protocolSubNbr == 0 ? 0 : status.protocolSubNbr - 1), pdef->maxSubtype); + } +} + +inline uint8_t MULTI_DISABLE_CHAN_MAP_ROW(uint8_t moduleIdx) +{ + if (!isModuleMultimodule(moduleIdx)) + return HIDDEN_ROW; + + uint8_t protocol = g_model.moduleData[moduleIdx].getMultiProtocol(); + if (protocol < MODULE_SUBTYPE_MULTI_LAST) { + const mm_protocol_definition * pdef = getMultiProtocolDefinition(protocol); + if (pdef->disable_ch_mapping) + return 0; + } + + MultiModuleStatus &status = getMultiModuleStatus(moduleIdx); + if (status.supportsDisableMapping() && status.isValid()) { + return 0; + } + + return HIDDEN_ROW; +} inline bool isMultiProtocolSelectable(int protocol) { @@ -182,19 +225,52 @@ inline bool isMultiProtocolSelectable(int protocol) inline bool MULTIMODULE_HAS_SUBTYPE(uint8_t moduleIdx) { - return getMultiProtocolDefinition(moduleIdx)->maxSubtype > 0; + MultiModuleStatus &status = getMultiModuleStatus(moduleIdx); + + if (g_model.moduleData[moduleIdx].getMultiProtocol() == MODULE_SUBTYPE_MULTI_FRSKY) { + return true; + } + + if (status.isValid()) { + return status.protocolSubNbr > 0; + } + else + { + if (g_model.moduleData[moduleIdx].getMultiProtocol() > MODULE_SUBTYPE_MULTI_LAST) + return true; + else + return getMultiProtocolDefinition(g_model.moduleData[moduleIdx].getMultiProtocol())->maxSubtype > 0; + } } + inline uint8_t MULTIMODULE_RFPROTO_COLUMNS(uint8_t moduleIdx) { #if LCD_W < 212 - return (g_model.moduleData[moduleIdx].multi.customProto ? (uint8_t) 1 : MULTIMODULE_HAS_SUBTYPE(g_model.moduleData[moduleIdx].getMultiProtocol(true)) ? (uint8_t) 0 : HIDDEN_ROW); + return (MULTIMODULE_HAS_SUBTYPE(moduleIdx) ? (uint8_t) 0 : HIDDEN_ROW); #else - return (g_model.moduleData[moduleIdx].multi.customProto ? (uint8_t) 2 : MULTIMODULE_HAS_SUBTYPE(g_model.moduleData[moduleIdx].getMultiProtocol(true)) ? (uint8_t) 1 : 0); + return (MULTIMODULE_HAS_SUBTYPE(moduleIdx) ? (uint8_t) 1 : 0); #endif } + +inline uint8_t MULTIMODULE_HASOPTIONS(uint8_t moduleIdx) +{ + if (!isModuleMultimodule(moduleIdx)) + return false; + + uint8_t protocol = g_model.moduleData[moduleIdx].getMultiProtocol(); + if (protocol < MODULE_SUBTYPE_MULTI_LAST) { + return getMultiProtocolDefinition(protocol)->optionsstr != nullptr; + } + + MultiModuleStatus &status = getMultiModuleStatus(moduleIdx); + return status.optionDisp; +} + +#define MULTIMODULE_MODULE_ROWS(moduleIdx) isModuleMultimodule(moduleIdx) ? (uint8_t) 0 : HIDDEN_ROW, isModuleMultimodule(moduleIdx) ? (uint8_t) 0 : HIDDEN_ROW, MULTI_DISABLE_CHAN_MAP_ROW(moduleIdx), // AUTOBIND, DISABLE TELEM, DISABLE CN.MAP +#define MULTIMODULE_STATUS_ROWS(moduleIdx) isModuleMultimodule(moduleIdx) ? TITLE_ROW : HIDDEN_ROW, (isModuleMultimodule(moduleIdx) && getMultiSyncStatus(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 #define MULTIMODULE_SUBTYPE_ROWS(moduleIdx) isModuleMultimodule(moduleIdx) ? MULTIMODULE_RFPROTO_COLUMNS(moduleIdx) : HIDDEN_ROW, -#define MULTIMODULE_HASOPTIONS(moduleIdx) (getMultiProtocolDefinition(moduleIdx)->optionsstr != nullptr) -#define MULTIMODULE_OPTIONS_ROW(moduleIdx) (isModuleMultimodule(moduleIdx) && MULTIMODULE_HASOPTIONS(g_model.moduleData[moduleIdx].getMultiProtocol(true))) ? (uint8_t) 0: HIDDEN_ROW +#define MULTIMODULE_OPTIONS_ROW(moduleIdx) (isModuleMultimodule(moduleIdx) && MULTIMODULE_HASOPTIONS(moduleIdx)) ? (uint8_t) 0: HIDDEN_ROW #else #define MULTIMODULE_STATUS_ROWS(moduleIdx) diff --git a/radio/src/lua/api_general.cpp b/radio/src/lua/api_general.cpp index 514f0cc2f..ea2ce80a4 100644 --- a/radio/src/lua/api_general.cpp +++ b/radio/src/lua/api_general.cpp @@ -24,6 +24,7 @@ #include "stamp.h" #include "lua_api.h" #include "telemetry/frsky.h" +#include "telemetry/multi.h" #if defined(PCBX12S) #include "lua/lua_exports_x12s.inc" // this line must be after lua headers @@ -442,7 +443,7 @@ When called without parameters, it will only return the status of the output buf static int luaSportTelemetryPush(lua_State * L) { - if (telemetryProtocol != PROTOCOL_TELEMETRY_FRSKY_SPORT) { + if (!IS_FRSKY_SPORT_PROTOCOL()) { lua_pushboolean(L, false); return 1; } @@ -1506,6 +1507,40 @@ static int luaResetGlobalTimer(lua_State * L) return 0; } +/*luadoc +@function multiBuffer(address[,value]) + +This function reads/writes the Multi protocol buffer to interact with a protocol². + +@param address to read/write in the buffer +@param (optional): value to write in the buffer + +@retval buffer value (number) + +@status current Introduced in 2.3.2 +*/ +#if defined(MULTIMODULE) +uint8_t * Multi_Buffer = nullptr; + +static int luaMultiBuffer(lua_State * L) +{ + uint8_t address = luaL_checkunsigned(L, 1); + if (!Multi_Buffer) + Multi_Buffer = (uint8_t *) malloc(MULTI_BUFFER_SIZE); + + if (!Multi_Buffer || address >= MULTI_BUFFER_SIZE) { + lua_pushinteger(L, 0); + return 0; + } + uint16_t value = luaL_optunsigned(L, 2, 0x100); + if (value < 0x100) { + Multi_Buffer[address] = value; + } + lua_pushinteger(L, Multi_Buffer[address]); + return 1; +} +#endif + /*luadoc @function serialWrite(str) @param str (string) String to be written to the serial port. @@ -1586,6 +1621,9 @@ const luaL_Reg opentxLib[] = { #if defined(CROSSFIRE) { "crossfireTelemetryPop", luaCrossfireTelemetryPop }, { "crossfireTelemetryPush", luaCrossfireTelemetryPush }, +#endif +#if defined(MULTIMODULE) + { "multiBuffer", luaMultiBuffer }, #endif { "serialWrite", luaSerialWrite }, { nullptr, nullptr } /* sentinel */ diff --git a/radio/src/opentx.h b/radio/src/opentx.h index afb35eeb4..383e20ae1 100644 --- a/radio/src/opentx.h +++ b/radio/src/opentx.h @@ -1198,6 +1198,7 @@ union ReusableBuffer uint16_t freqMax; uint16_t freqMin; uint8_t dirty; + uint8_t moduleOFF; } spectrumAnalyser; struct { diff --git a/radio/src/pulses/modules_constants.h b/radio/src/pulses/modules_constants.h index 34c1c2fb8..05331d34f 100644 --- a/radio/src/pulses/modules_constants.h +++ b/radio/src/pulses/modules_constants.h @@ -100,9 +100,8 @@ enum ModuleSubtypeR9M { /* Multi module */ enum ModuleSubtypeMulti { - MODULE_SUBTYPE_MULTI_CUSTOM = -1, - MODULE_SUBTYPE_MULTI_FIRST = MODULE_SUBTYPE_MULTI_CUSTOM, - MODULE_SUBTYPE_MULTI_FLYSKY=0, + MODULE_SUBTYPE_MULTI_FIRST = 0, + MODULE_SUBTYPE_MULTI_FLYSKY = MODULE_SUBTYPE_MULTI_FIRST, MODULE_SUBTYPE_MULTI_HUBSAN, MODULE_SUBTYPE_MULTI_FRSKY, MODULE_SUBTYPE_MULTI_HISKY, @@ -158,6 +157,8 @@ enum ModuleSubtypeMulti { MODULE_SUBTYPE_MULTI_AFHDS2A_RX, MODULE_SUBTYPE_MULTI_LAST = MODULE_SUBTYPE_MULTI_AFHDS2A_RX }; +#define MODULE_SUBTYPE_MULTI_HOTT 57-3 +#define MODULE_SUBTYPE_MULTI_XN297DP 63-3 enum MMDSM2Subtypes { MM_RF_DSM2_SUBTYPE_DSM2_22, diff --git a/radio/src/pulses/modules_helpers.h b/radio/src/pulses/modules_helpers.h index aaf367c00..31641f993 100644 --- a/radio/src/pulses/modules_helpers.h +++ b/radio/src/pulses/modules_helpers.h @@ -39,7 +39,7 @@ inline bool isModuleMultimodule(uint8_t idx) inline bool isModuleMultimoduleDSM2(uint8_t idx) { - return isModuleMultimodule(idx) && g_model.moduleData[idx].getMultiProtocol(true) == MODULE_SUBTYPE_MULTI_DSM2; + return isModuleMultimodule(idx) && g_model.moduleData[idx].getMultiProtocol() == MODULE_SUBTYPE_MULTI_DSM2; } #else inline bool isModuleMultimodule(uint8_t) @@ -378,7 +378,15 @@ inline uint8_t getMaxRxNum(uint8_t idx) #if defined(MULTIMODULE) if (isModuleMultimodule(idx)) - return g_model.moduleData[idx].getMultiProtocol(true) == MODULE_SUBTYPE_MULTI_OLRS ? 4 : 15; + { + switch (g_model.moduleData[idx].getMultiProtocol()) { + case MODULE_SUBTYPE_MULTI_OLRS: + return 4; + case MODULE_SUBTYPE_MULTI_BUGS: + case MODULE_SUBTYPE_MULTI_BUGS_MINI: + return 15; + } + } #endif return 63; diff --git a/radio/src/pulses/multi.cpp b/radio/src/pulses/multi.cpp index 7c686546f..2b66155c9 100644 --- a/radio/src/pulses/multi.cpp +++ b/radio/src/pulses/multi.cpp @@ -19,6 +19,7 @@ */ #include "opentx.h" +#include "multi.h" // for the MULTI protocol definition // see https://github.com/pascallanger/DIY-Multiprotocol-TX-Module @@ -31,9 +32,59 @@ #define MULTI_CHANS 16 #define MULTI_CHAN_BITS 11 -static void sendFrameProtocolHeader(uint8_t moduleIdx, bool failsafe); +#define MULTI_NORMAL 0x00 +#define MULTI_FAILSAFE 0x01 +#define MULTI_DATA 0x02 +static void sendFrameProtocolHeader(uint8_t moduleIdx, bool failsafe); void sendChannels(uint8_t moduleIdx); +#if defined(LUA) +static void sendSport(uint8_t moduleIdx); +static void sendHott(uint8_t moduleIdx); +#endif + +void multiPatchCustom(uint8_t moduleIdx) +{ + if (g_model.moduleData[moduleIdx].multi.customProto) { + uint8_t type = g_model.moduleData[moduleIdx].getMultiProtocol() - 1; // custom where starting at 1, otx list at 0 + int subtype = g_model.moduleData[moduleIdx].subType; + + g_model.moduleData[moduleIdx].multi.customProto = 0; + + if (type == 2) { // multi PROTO_FRSKYD + g_model.moduleData[moduleIdx].subType = 1; // D8 + return; + } + else if (type == 14) { // multi PROTO_FRSKYX + g_model.moduleData[moduleIdx].setMultiProtocol(2); + switch (subtype) { + case 0: //D16-16 + g_model.moduleData[moduleIdx].subType = 0; + break; + case 1: //D16-8 + g_model.moduleData[moduleIdx].subType = 2; + break; + case 2: //EU-16 + g_model.moduleData[moduleIdx].subType = 4; + break; + case 3: //EU-8 + g_model.moduleData[moduleIdx].subType = 5; + break; + } + return; + } + else if (type == 24) { // multi PROTO_FRSKYV + g_model.moduleData[moduleIdx].setMultiProtocol(2); + g_model.moduleData[moduleIdx].subType = 3; + return; + } + if (type > 14) + type -= 1; + if (type > 24) + type -= 1; + g_model.moduleData[moduleIdx].setMultiProtocol(type); + } +} static void sendMulti(uint8_t moduleIdx, uint8_t b) { @@ -46,22 +97,6 @@ static void sendMulti(uint8_t moduleIdx, uint8_t b) sendByteSbus(b); } -static void sendSetupFrame(uint8_t moduleIdx) -{ - // Old multi firmware will mark config messsages as invalid frame and throw them away - sendMulti(moduleIdx, 'M'); - sendMulti(moduleIdx, 'P'); - sendMulti(moduleIdx, 0x80); // Module Configuration - sendMulti(moduleIdx, 1); // 1 byte data - uint8_t config = 0x01 | 0x02; // inversion + multi_telemetry -#if !defined(PPM_PIN_SERIAL) - // TODO why PPM_PIN_SERIAL would change MULTI protocol? - config |= 0x04; // input synchronsisation -#endif - - sendMulti(moduleIdx, config); -} - static void sendFailsafeChannels(uint8_t moduleIdx) { uint32_t bits = 0; @@ -95,21 +130,64 @@ static void sendFailsafeChannels(uint8_t moduleIdx) void setupPulsesMulti(uint8_t moduleIdx) { static int counter[2] = {0,0}; //TODO + static uint8_t invert[2] = {0x00, //internal +#if defined(PCBTARANIS) || defined(PCBHORUS) + 0x08 //external +#else + 0x00 //external +#endif + }; + uint8_t type=MULTI_NORMAL; + + // Failsafe packets + if (counter[moduleIdx] % 1000 == 0 && g_model.moduleData[moduleIdx].failsafeMode != FAILSAFE_NOT_SET && g_model.moduleData[moduleIdx].failsafeMode != FAILSAFE_RECEIVER) { + type|=MULTI_FAILSAFE; + } + + // Invert telemetry if needed + if (invert[moduleIdx] & 0x80 && !g_model.moduleData[moduleIdx].multi.disableTelemetry) { + if (getMultiModuleStatus(moduleIdx).isValid()) { + invert[moduleIdx] &= 0x08; // Telemetry received, stop searching + } + else if (counter[moduleIdx] % 100 == 0) { + invert[moduleIdx] ^= 0x08; // Try inverting telemetry + } + } - // Every 1000 cycles (=9s) send a config packet that configures the multimodule (inversion, telemetry type) counter[moduleIdx]++; - if (counter[moduleIdx] % 1000 == 500) { - sendSetupFrame(moduleIdx); - } - else if (counter[moduleIdx] % 1000 == 0 && g_model.moduleData[moduleIdx].failsafeMode != FAILSAFE_NOT_SET && g_model.moduleData[moduleIdx].failsafeMode != FAILSAFE_RECEIVER) { - sendFrameProtocolHeader(moduleIdx, true); + + // Send header + sendFrameProtocolHeader(moduleIdx, type&MULTI_FAILSAFE); + + // Send channels + if (type & MULTI_FAILSAFE) sendFailsafeChannels(moduleIdx); - } - else { - // Normal Frame - sendFrameProtocolHeader(moduleIdx, false); + else sendChannels(moduleIdx); + + // Multi V1.3.X.X -> Send byte 26, Protocol (bits 7 & 6), RX_Num (bits 5 & 4), invert, not used, disable telemetry, disable mapping + sendMulti(moduleIdx, (uint8_t) (((g_model.moduleData[moduleIdx].getMultiProtocol()+3)&0xC0) + | (g_model.header.modelId[moduleIdx] & 0x30) + | (invert[moduleIdx] & 0x08) + //| 0x04 // Future use + | (g_model.moduleData[moduleIdx].multi.disableTelemetry << 1) + | g_model.moduleData[moduleIdx].multi.disableMapping)); + + // Multi V1.3.X.X -> Send protocol additional data: max 9 bytes +#if defined(LUA) + if (getMultiModuleStatus(moduleIdx).isValid()) { + MultiModuleStatus &status = getMultiModuleStatus(moduleIdx); + if (status.minor >= 3 && !(status.flags & 0x80)) { //Version 1.3.x.x or more and Buffer not full + // SPort send + if (IS_D16_MULTI(moduleIdx) && outputTelemetryBuffer.destination == TELEMETRY_ENDPOINT_SPORT && outputTelemetryBuffer.size) { + sendSport(moduleIdx); //8 bytes of additional data + } + else if (IS_HOTT_MULTI(moduleIdx)) { + sendHott(moduleIdx); //1 byte of additional data + } + } } + #endif } void setupPulsesMultiExternalModule() @@ -166,7 +244,7 @@ void sendFrameProtocolHeader(uint8_t moduleIdx, bool failsafe) {// byte 1+2, protocol information // Our enumeration starts at 0 - int type = g_model.moduleData[moduleIdx].getMultiProtocol(false) + 1; + int type = g_model.moduleData[moduleIdx].getMultiProtocol() + 1; int subtype = g_model.moduleData[moduleIdx].subType; int8_t optionValue = g_model.moduleData[moduleIdx].multi.optionValue; @@ -186,16 +264,18 @@ void sendFrameProtocolHeader(uint8_t moduleIdx, bool failsafe) protoByte |= MULTI_SEND_RANGECHECK; // rfProtocol - if (g_model.moduleData[moduleIdx].getMultiProtocol(true) == MODULE_SUBTYPE_MULTI_DSM2) { + if (g_model.moduleData[moduleIdx].getMultiProtocol() == MODULE_SUBTYPE_MULTI_DSM2) { // Autobinding should always be done in DSMX 11ms if (g_model.moduleData[moduleIdx].multi.autoBindMode && moduleState[moduleIdx].mode == MODULE_MODE_BIND) subtype = MM_RF_DSM2_SUBTYPE_AUTO; // Multi module in DSM mode wants the number of channels to be used as option value - optionValue = sentModuleChannels(moduleIdx); - - } + if (optionValue) + optionValue = 0x80 | sentModuleChannels(moduleIdx); // Max throw + else + optionValue = sentModuleChannels(moduleIdx); +} // 15 for Multimodule is FrskyX or D16 which we map as a subprotocol of 3 (FrSky) // all protos > frskyx are therefore also off by one @@ -206,7 +286,7 @@ void sendFrameProtocolHeader(uint8_t moduleIdx, bool failsafe) if (type >= 25) type = type + 1; - if (g_model.moduleData[moduleIdx].getMultiProtocol(true) == MODULE_SUBTYPE_MULTI_FRSKY) { + if (g_model.moduleData[moduleIdx].getMultiProtocol() == MODULE_SUBTYPE_MULTI_FRSKY) { if (subtype == MM_RF_FRSKY_SUBTYPE_D8) { //D8 type = 3; @@ -230,28 +310,27 @@ void sendFrameProtocolHeader(uint8_t moduleIdx, bool failsafe) // Set the highest bit of option byte in AFHDS2A protocol to instruct MULTI to passthrough telemetry bytes instead // of sending Frsky D telemetry - if (g_model.moduleData[moduleIdx].getMultiProtocol(false) == MODULE_SUBTYPE_MULTI_FS_AFHDS2A) + if (g_model.moduleData[moduleIdx].getMultiProtocol() == MODULE_SUBTYPE_MULTI_FS_AFHDS2A) optionValue = optionValue | 0x80; // For custom protocol send unmodified type byte - if (g_model.moduleData[moduleIdx].getMultiProtocol(true) == MM_RF_CUSTOM_SELECTED) - type = g_model.moduleData[moduleIdx].getMultiProtocol(false); + if (g_model.moduleData[moduleIdx].getMultiProtocol() == MM_RF_CUSTOM_SELECTED) + type = g_model.moduleData[moduleIdx].getMultiProtocol(); - uint8_t headerByte = 0x54; + uint8_t headerByte = 0x55; + // header, byte 0, 0x55 for proto 0-31, 0x54 for proto 32-63 + if (type & 0x20) + headerByte &= 0xFE; + if (failsafe) - headerByte = 0x56; - - // header, byte 0, 0x55 for proto 0-31 0x54 for 32-63 - if (type <= 31) - sendMulti(moduleIdx, headerByte+1); - else - sendMulti(moduleIdx, headerByte); + headerByte |= 0x02; + sendMulti(moduleIdx, headerByte); // protocol byte protoByte |= (type & 0x1f); - if (g_model.moduleData[moduleIdx].getMultiProtocol(true) != MODULE_SUBTYPE_MULTI_DSM2) + if (g_model.moduleData[moduleIdx].getMultiProtocol() != MODULE_SUBTYPE_MULTI_DSM2) protoByte |= (g_model.moduleData[moduleIdx].multi.autoBindMode << 6); sendMulti(moduleIdx, protoByte); @@ -265,3 +344,32 @@ void sendFrameProtocolHeader(uint8_t moduleIdx, bool failsafe) // byte 3 sendMulti(moduleIdx, (uint8_t) optionValue); } + +#if defined(LUA) +void sendSport(uint8_t moduleIdx) +{ + // example: B7 30 30 0C 80 00 00 00 13 + uint8_t j=0; + + // unstuff and remove crc + for (uint8_t i = 0; i < outputTelemetryBuffer.size - 1 && j < 8; i++, j++) { + if (outputTelemetryBuffer.data[i] == BYTESTUFF) { + i++; + sendMulti(moduleIdx, outputTelemetryBuffer.data[i] ^ STUFF_MASK); + } + else { + sendMulti(moduleIdx, outputTelemetryBuffer.data[i]); + } + } + + outputTelemetryBuffer.reset(); // empty buffer +} + +void sendHott(uint8_t moduleIdx) +{ + if (Multi_Buffer && memcmp(Multi_Buffer, "HoTT", 4) == 0 && Multi_Buffer[5] >= 0xD7 && Multi_Buffer[5] <= 0xDF) { + // HoTT Lua script is running + sendMulti(moduleIdx, Multi_Buffer[5]); + } +} +#endif diff --git a/radio/src/pulses/multi.h b/radio/src/pulses/multi.h index d3f088b7d..a19e526eb 100644 --- a/radio/src/pulses/multi.h +++ b/radio/src/pulses/multi.h @@ -23,6 +23,8 @@ #include "pulses_common.h" +void multiPatchCustom(uint8_t moduleIdx); + class UartMultiPulses: public DataBuffer { public: diff --git a/radio/src/storage/modelslist.cpp b/radio/src/storage/modelslist.cpp index be4a38adb..e5e35d896 100644 --- a/radio/src/storage/modelslist.cpp +++ b/radio/src/storage/modelslist.cpp @@ -158,7 +158,7 @@ void ModelCell::setRfModuleData(uint8_t moduleIdx, ModuleData* modData) } else { // do we care here about MM_RF_CUSTOM_SELECTED? probably not... - moduleData[moduleIdx].rfProtocol = modData->getMultiProtocol(false); + moduleData[moduleIdx].rfProtocol = modData->getMultiProtocol(); } } diff --git a/radio/src/storage/storage_common.cpp b/radio/src/storage/storage_common.cpp index 9817777d0..d0742ee92 100644 --- a/radio/src/storage/storage_common.cpp +++ b/radio/src/storage/storage_common.cpp @@ -19,6 +19,7 @@ */ #include "opentx.h" +#include "pulses/multi.h" uint8_t storageDirtyMsk; tmr10ms_t storageDirtyTime10ms; @@ -125,11 +126,19 @@ void postModelLoad(bool alarms) if (!isInternalModuleAvailable(g_model.moduleData[INTERNAL_MODULE].type)) { memclear(&g_model.moduleData[INTERNAL_MODULE], sizeof(ModuleData)); } +#if defined(MULTIMODULE) + else if (isModuleMultimodule(INTERNAL_MODULE)) + multiPatchCustom(INTERNAL_MODULE); +#endif #endif if (!isExternalModuleAvailable(g_model.moduleData[EXTERNAL_MODULE].type)) { memclear(&g_model.moduleData[EXTERNAL_MODULE], sizeof(ModuleData)); } +#if defined(MULTIMODULE) + else if (isModuleMultimodule(EXTERNAL_MODULE)) + multiPatchCustom(EXTERNAL_MODULE); +#endif AUDIO_FLUSH(); flightReset(false); diff --git a/radio/src/targets/common/arm/CMakeLists.txt b/radio/src/targets/common/arm/CMakeLists.txt index 063eb54fc..2fd540afd 100644 --- a/radio/src/targets/common/arm/CMakeLists.txt +++ b/radio/src/targets/common/arm/CMakeLists.txt @@ -143,7 +143,7 @@ endif() if(MULTIMODULE) add_definitions(-DMULTIMODULE) - set(SRC ${SRC} pulses/multi.cpp telemetry/spektrum.cpp telemetry/flysky_ibus.cpp telemetry/hitec.cpp telemetry/multi.cpp io/multi_firmware_update.cpp) + set(SRC ${SRC} pulses/multi.cpp telemetry/spektrum.cpp telemetry/flysky_ibus.cpp telemetry/hitec.cpp telemetry/hott.cpp telemetry/multi.cpp io/multi_firmware_update.cpp) endif() if(CROSSFIRE) diff --git a/radio/src/telemetry/hott.cpp b/radio/src/telemetry/hott.cpp new file mode 100644 index 000000000..fab1fb555 --- /dev/null +++ b/radio/src/telemetry/hott.cpp @@ -0,0 +1,184 @@ +/* + * Copyright (C) OpenTX + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "opentx.h" + +/* Telemetry +packet[0] = TX RSSI value +packet[1] = TX LQI value +packet[2] = frame number +packet[3-12] telemetry data + +The frame number takes the following values: 0x00, 0x01, 0x02, 0x03 and 0x04. The frames can be present or not, they also do not have to follow each others. +Here is a description of the telemetry data for each frame number: +- frame 0x00 +[3] = [12] = ?? +[4] = RX_Voltage*10 in V +[5] = Temperature-20 in °C +[6] = RX_RSSI +[7] = RX_LQI ?? +[8] = RX_STR ?? +[9,10] = [10]*256+[9]=max lost packet time in ms, max value seems 2s=0x7D0 +[11] = 0x00 ?? +- frame 0x01 Unknown +- frame 0x02 Unknown +- frame 0x03 Unknown +- frame 0x04 Unknown +*/ + +struct HottSensor +{ + const uint16_t id; + const char * name; + const TelemetryUnit unit; + const uint8_t precision; +}; + +// telemetry frames +enum +{ + HOTT_FRAME_00 = 0x00, + HOTT_FRAME_01 = 0x01, + HOTT_FRAME_02 = 0x02, + HOTT_FRAME_03 = 0x03, + HOTT_FRAME_04 = 0x04, +}; + +#define HOTT_TELEM_NORMAL 0x00 +#define HOTT_TELEM_BIND 0x40 +#define HOTT_TELEM_MENU 0x80 + +// telemetry sensors ID +enum +{ + HOTT_ID_RX_VOLTAGE = 0x0004,// RX_Batt Voltage + HOTT_ID_TEMP1 = 0x0005, // RX Temperature sensor + TX_RSSI_ID = 0xFF00, // Pseudo id outside 1 byte range of Hott sensors + TX_LQI_ID = 0xFF01, // Pseudo id outside 1 byte range of Hott sensors + RX_RSSI_ID = 0xFF02, // Pseudo id outside 1 byte range of Hott sensors + RX_LQI_ID = 0xFF03, // Pseudo id outside 1 byte range of Hott sensors +}; + +const HottSensor hottSensors[] = { + //frame 00 + {HOTT_ID_RX_VOLTAGE, ZSTR_BATT, UNIT_VOLTS, 1}, // RX_Batt Voltage + {HOTT_ID_TEMP1, ZSTR_TEMP1, UNIT_CELSIUS, 0}, // RX Temperature sensor + //frame 01 + //frame 02 + //frame 03 + //frame 04 + {TX_RSSI_ID, ZSTR_TX_RSSI, UNIT_RAW, 0}, // Pseudo id outside 1 byte range of Hott sensors + {TX_LQI_ID, ZSTR_TX_QUALITY, UNIT_RAW, 0}, // Pseudo id outside 1 byte range of Hott sensors + {RX_RSSI_ID, ZSTR_RSSI, UNIT_DB, 0}, // RX RSSI + {RX_LQI_ID, ZSTR_RX_QUALITY, UNIT_RAW, 0}, // RX LQI + {0x00, NULL, UNIT_RAW, 0}, // sentinel +}; + +const HottSensor * getHottSensor(uint16_t id) +{ + for (const HottSensor * sensor = hottSensors; sensor->id; sensor++) { + if (id == sensor->id) + return sensor; + } + return nullptr; +} + +void processHottPacket(const uint8_t * packet) +{ + // Set TX RSSI Value + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, TX_RSSI_ID, 0, 0, packet[0]>>1, UNIT_RAW, 0); + // Set TX LQI Value + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, TX_LQI_ID, 0, 0, packet[1], UNIT_RAW, 0); + +#if defined(LUA) + #define HOTT_MENU_NBR_PAGE 0x13 + // Config menu consists of the different telem pages put all together + // [3] = config mennu page 0x00 to 0x12. + // Page X [4] = seems like all the telem pages with the same value are going together to make the full config menu text. Seen so far 'a', 'b', 'c', 'd' + // Page X [5..13] = 9 ascii chars to be displayed, char is highlighted when ascii|0x80 + // Screen display is 21 characters large which means that once the first 21 chars are filled go to the begining of the next line + // Menu commands are sent through TX packets: + // packet[28]= 0xXF=>no key press, 0xXD=>down, 0xXB=>up, 0xX9=>enter, 0xXE=>right, 0xX7=>left with X=0 or D + // packet[29]= 0xX1/0xX9 with X=0 or X counting 0,1,1,2,2,..,9,9 + if (Multi_Buffer && memcmp(Multi_Buffer, "HoTT", 4) == 0) { + // HoTT Lua script is running + if (Multi_Buffer[4] == 0xFF) { + // Init + memset(&Multi_Buffer[6], ' ', HOTT_MENU_NBR_PAGE * 9); // Clear text buffer + } + + if (packet[3] < HOTT_MENU_NBR_PAGE && Multi_Buffer[5] >= 0xD7 && Multi_Buffer[5] <= 0xDF) { + Multi_Buffer[4] = packet[4]; // Store current menu being received + memcpy(&Multi_Buffer[6 + packet[3] * 9], &packet[5], 9); // Store the received page in the buffer + } + return; + } +#endif + + const HottSensor * sensor; + int32_t value; + + if (packet[2] == HOTT_TELEM_NORMAL) { + switch (packet[3]) { + case HOTT_FRAME_00: + // RX_VOLT + value = packet[5]; + sensor = getHottSensor(HOTT_ID_RX_VOLTAGE); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_RX_VOLTAGE, 0, 0, value, sensor->unit, sensor->precision); + // RX_TEMP + value = packet[6] - 20; + sensor = getHottSensor(HOTT_ID_TEMP1); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_TEMP1, 0, 0, value, sensor->unit, sensor->precision); + // RX_RSSI + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, RX_RSSI_ID, 0, 0, packet[7], UNIT_DB, 0); + // RX_LQI + telemetryData.rssi.set(packet[8]); + if (packet[8] > 0) + telemetryStreaming = TELEMETRY_TIMEOUT10ms; + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, RX_LQI_ID, 0, 0, packet[8], UNIT_RAW, 0); + break; + + default: + // unknown + value = (packet[7] << 24) | (packet[6] << 16) | (packet[5] << 8) | packet[4]; + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, 0xFE00 | packet[3], 0, 0, value, UNIT_RAW, 0); + break; + } + } +} + +void hottSetDefault(int index, uint16_t id, uint8_t subId, uint8_t instance) +{ + TelemetrySensor &telemetrySensor = g_model.telemetrySensors[index]; + telemetrySensor.id = id; + telemetrySensor.subId = subId; + telemetrySensor.instance = instance; + + const HottSensor * sensor = getHottSensor(id); + if (sensor) { + TelemetryUnit unit = sensor->unit; + uint8_t prec = min(2, sensor->precision); + telemetrySensor.init(sensor->name, unit, prec); + if (unit == UNIT_RPMS) { + telemetrySensor.custom.ratio = 1; + telemetrySensor.custom.offset = 1; + } + } + else { + telemetrySensor.init(id); + } + + storageDirty(EE_MODEL); +} diff --git a/radio/src/telemetry/hott.h b/radio/src/telemetry/hott.h new file mode 100644 index 000000000..797601d11 --- /dev/null +++ b/radio/src/telemetry/hott.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) OpenTX + * + * Based on code named + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _HOTT_H +#define _HOTT_H + +void hottSetDefault(int index, uint16_t id, uint8_t subId, uint8_t instance); + +// Used by multi protocol +void processHottPacket(const uint8_t * packet); + +#endif diff --git a/radio/src/telemetry/multi.cpp b/radio/src/telemetry/multi.cpp index c07a98494..2a3f7050c 100644 --- a/radio/src/telemetry/multi.cpp +++ b/radio/src/telemetry/multi.cpp @@ -39,7 +39,8 @@ enum MultiPacketTypes : uint8_t HitecTelemetry, SpectrumScannerPacket, FlyskyIBusTelemetryAC, - MultiRxChannels + MultiRxChannels, + HottTelemetry, }; enum MultiBufferState : uint8_t @@ -65,6 +66,7 @@ static MultiModuleSyncStatus multiSyncStatus[NUM_MODULES] = {MultiModuleSyncStat static uint8_t multiBindStatus[NUM_MODULES] = {MULTI_NORMAL_OPERATION, MULTI_NORMAL_OPERATION}; static MultiBufferState multiTelemetryBufferState[NUM_MODULES]; +static uint16_t multiTelemetryLastRxTS[NUM_MODULES]; MultiModuleStatus &getMultiModuleStatus(uint8_t module) { @@ -96,6 +98,11 @@ void setMultiTelemetryBufferState(uint8_t module, MultiBufferState state) multiTelemetryBufferState[module] = state; } +static uint16_t& getMultiTelemetryLastRxTS(uint8_t module) +{ + return multiTelemetryLastRxTS[module]; +} + // Use additional telemetry buffer uint8_t intTelemetryRxBuffer[TELEMETRY_RX_PACKET_SIZE]; uint8_t intTelemetryRxBufferCount; @@ -107,6 +114,7 @@ static MultiModuleSyncStatus multiSyncStatus; static uint8_t multiBindStatus = MULTI_NORMAL_OPERATION; static MultiBufferState multiTelemetryBufferState; +static uint16_t multiTelemetryLastRxTS; MultiModuleStatus& getMultiModuleStatus(uint8_t) { @@ -138,6 +146,11 @@ void setMultiTelemetryBufferState(uint8_t, MultiBufferState state) multiTelemetryBufferState = state; } +uint16_t& getMultiTelemetryLastRxTS(uint8_t module) +{ + return multiTelemetryLastRxTS; +} + #endif // INTERNAL_MODULE_MULTI @@ -150,9 +163,9 @@ static MultiBufferState guessProtocol(uint8_t module) } #endif - if (g_model.moduleData[moduleIdx].getMultiProtocol(false) == MODULE_SUBTYPE_MULTI_DSM2) + if (g_model.moduleData[moduleIdx].getMultiProtocol() == MODULE_SUBTYPE_MULTI_DSM2) return SpektrumTelemetryFallback; - else if (g_model.moduleData[module].getMultiProtocol(false) == MODULE_SUBTYPE_MULTI_FS_AFHDS2A) + else if (g_model.moduleData[module].getMultiProtocol() == MODULE_SUBTYPE_MULTI_FS_AFHDS2A) return FlyskyTelemetryFallback; else return FrskyTelemetryFallback; @@ -196,20 +209,38 @@ static void processMultiScannerPacket(const uint8_t *data) } } -static void processMultiStatusPacket(const uint8_t * data, uint8_t module) +static void processMultiStatusPacket(const uint8_t * data, uint8_t module, uint8_t len) { MultiModuleStatus &status = getMultiModuleStatus(module); // At least two status packets without bind flag bool wasBinding = status.isBinding(); + status.lastUpdate = get_tmr10ms(); status.flags = data[0]; status.major = data[1]; status.minor = data[2]; status.revision = data[3]; status.patch = data[4]; - status.lastUpdate = get_tmr10ms(); - + if (len < 6) { + status.ch_order = 0xFF; + } + else { + status.ch_order = data[5]; + if (len >= 24) { + status.protocolNext = data[6]; + status.protocolPrev = data[7]; + memcpy(status.protocolName, &data[8], 7); + status.protocolName[7] = 0; + status.protocolSubNbr = data[15] & 0x0F; + memcpy(status.protocolSubName, &data[16], 8); + status.protocolSubName[8] = 0; + status.optionDisp = data[15] >> 4; + } + else { + status.protocolName[0] = 0; + } + } if (getMultiModuleStatus(module).requiresFailsafeCheck) { getMultiModuleStatus(module).requiresFailsafeCheck = false; if (getMultiModuleStatus(module).supportsFailsafe() && g_model.moduleData[module].failsafeMode == FAILSAFE_NOT_SET) @@ -289,7 +320,7 @@ static void processMultiTelemetryPaket(const uint8_t * packet, uint8_t module) switch (type) { case MultiStatus: if (len >= 5) - processMultiStatusPacket(data, module); + processMultiStatusPacket(data, module, len); break; case DSMBindPacket: @@ -327,6 +358,13 @@ static void processMultiTelemetryPaket(const uint8_t * packet, uint8_t module) TRACE("[MP] Received Hitec telemetry len %d < 8", len); break; + case HottTelemetry: + if (len >= 14) + processHottPacket(data); + else + TRACE("[MP] Received HoTT telemetry len %d < 14", len); + break; + case FrSkyHubTelemetry: if (len >= 4) frskyDProcessPacket(data); @@ -382,17 +420,7 @@ static void processMultiTelemetryPaket(const uint8_t * packet, uint8_t module) } } -// sprintf does not work AVR ARM -// use a small helper function -static void appendInt(char * buf, uint32_t val) -{ - while (*buf) - buf++; - - strAppendUnsigned(buf, val); -} - -#define MIN_REFRESH_RATE 7000 +#define MIN_REFRESH_RATE 5500 void MultiModuleSyncStatus::calcAdjustedRefreshRate(uint16_t newRefreshRate, uint16_t newInputLag) { @@ -444,8 +472,8 @@ void MultiModuleSyncStatus::calcAdjustedRefreshRate(uint16_t newRefreshRate, uin adjustedRefreshRate = (adjustedRefreshRate + perframeps); // Safeguards - if (adjustedRefreshRate < 6 * 1000 * 1000) - adjustedRefreshRate = 6 * 1000 * 1000; + if (adjustedRefreshRate < MIN_REFRESH_RATE * 1000) + adjustedRefreshRate = MIN_REFRESH_RATE * 1000; if (adjustedRefreshRate > 30 * 1000 * 1000) adjustedRefreshRate = 30 * 1000 * 1000; @@ -454,12 +482,11 @@ void MultiModuleSyncStatus::calcAdjustedRefreshRate(uint16_t newRefreshRate, uin static uint8_t counter; -uint16_t MultiModuleSyncStatus::getAdjustedRefreshRate() +const uint16_t MultiModuleSyncStatus::getAdjustedRefreshRate() { if (!isValid() || refreshRate == 0) return 18000; - counter = (uint8_t) (counter + 1 % 10); uint16_t rate = (uint16_t) ((adjustedRefreshRate + counter * 50) / 500); // Check how far off we are from our target, positive means we are too slow, negative we are too fast @@ -471,37 +498,27 @@ uint16_t MultiModuleSyncStatus::getAdjustedRefreshRate() return rate; } - -static void prependSpaces(char * buf, int val) -{ - while (*buf) - buf++; - - int k = 10000; - while (val / k == 0 && k > 0) { - *buf = ' '; - buf++; - k /= 10; - } - *buf = '\0'; -} - void MultiModuleSyncStatus::getRefreshString(char * statusText) { if (!isValid()) { return; } - strcpy(statusText, "L "); - prependSpaces(statusText, inputLag); - appendInt(statusText, inputLag); - strcat(statusText, "ns R "); - prependSpaces(statusText, adjustedRefreshRate / 1000); - appendInt(statusText, (uint32_t) (adjustedRefreshRate / 1000)); - strcat(statusText, "ns"); + char * tmp = statusText; +#if defined(DEBUG) + *tmp++ = 'L'; + tmp = strAppendUnsigned(tmp, inputLag, 5); + tmp = strAppend(tmp, "us R "); + tmp = strAppendUnsigned(tmp, (uint32_t) (adjustedRefreshRate / 1000), 5); + tmp = strAppend(tmp, "us"); +#else + tmp = strAppend(tmp, "Sync at "); + tmp = strAppendUnsigned(tmp, (uint32_t) (adjustedRefreshRate / 1000000)); + tmp = strAppend(tmp, " ms"); +#endif } -void MultiModuleStatus::getStatusString(char * statusText) +void MultiModuleStatus::getStatusString(char * statusText) const { if (!isValid()) { #if defined(PCBTARANIS) || defined(PCBHORUS) @@ -531,19 +548,46 @@ void MultiModuleStatus::getStatusString(char * statusText) return; } + if (major == 1 && minor < 3 && SLOW_BLINK_ON_PHASE) { + strcpy(statusText, STR_MODULE_UPGRADE); + } + else { + char * tmp = statusText; + *tmp++ = 'V'; + tmp = strAppendUnsigned(tmp, major); + *tmp++ = '.'; + tmp = strAppendUnsigned(tmp, minor); + *tmp++ = '.'; + tmp = strAppendUnsigned(tmp, revision); + *tmp++ = '.'; + tmp = strAppendUnsigned(tmp, patch); - strcpy(statusText, "V"); - appendInt(statusText, major); - strcat(statusText, "."); - appendInt(statusText, minor); - strcat(statusText, "."); - appendInt(statusText, revision); - strcat(statusText, "."); - appendInt(statusText, patch); - strcat(statusText, " "); - - if (isBinding()) - strcat(statusText, STR_MODULE_BINDING); + if (isBinding()) { + strcpy(tmp, " " TR_MODULE_BINDING); + } + else if (ch_order != 0xFF) { + uint8_t temp = ch_order; + *tmp++ = ' '; + for (uint8_t i = 0; i < 4; i++) { + switch (temp & 0x03) { + case 0: + *tmp++ = 'A'; + break; + case 1: + *tmp++ = 'E'; + break; + case 2: + *tmp++ = 'T'; + break; + case 3: + *tmp++ = 'R'; + break; + } + temp >>= 2; + } + *tmp = '\0'; + } + } } static uint8_t * getRxBuffer(uint8_t moduleIdx) @@ -600,7 +644,14 @@ void processMultiTelemetryData(uint8_t data, uint8_t module) uint8_t * rxBuffer = getRxBuffer(module); uint8_t &rxBufferCount = getRxBufferCount(module); - //debugPrintf("State: %d, byte received %02X, buflen: %d\r\n", multiTelemetryBufferState, data, rxBufferCount); + uint16_t &lastRxTS = getMultiTelemetryLastRxTS(module); + uint16_t nowMs = (uint16_t)RTOS_GET_MS(); + if (nowMs - lastRxTS > 15) + setMultiTelemetryBufferState(module, NoProtocolDetected); + lastRxTS = nowMs; + + // debugPrintf("State: %d, byte received %02X, buflen: %d\r\n", getMultiTelemetryBufferState(module), data, rxBufferCount); + switch (getMultiTelemetryBufferState(module)) { case NoProtocolDetected: if (data == 'M') { @@ -691,16 +742,22 @@ void processMultiTelemetryData(uint8_t data, uint8_t module) break; case ReceivingMultiStatus: - rxBuffer[rxBufferCount++] = data; - if (rxBufferCount > 5 && rxBuffer[0] == rxBufferCount - 1) { - processMultiStatusPacket(rxBuffer + 1, module); - rxBufferCount = 0; - setMultiTelemetryBufferState(module, NoProtocolDetected); + if (rxBufferCount < TELEMETRY_RX_PACKET_SIZE) { + rxBuffer[rxBufferCount++] = data; + if (rxBufferCount > 5 && rxBuffer[0] == rxBufferCount - 1) { + processMultiStatusPacket(rxBuffer + 1, module, rxBuffer[0]); + rxBufferCount = 0; + setMultiTelemetryBufferState(module, NoProtocolDetected); + } + if (rxBufferCount > 24) { + // too long ignore + TRACE("Overlong multi status packet detected ignoring, wanted %d", rxBuffer[0]); + rxBufferCount = 0; + setMultiTelemetryBufferState(module, NoProtocolDetected); + } } - if (rxBufferCount > 10) { - // too long ignore - TRACE("Overlong multi status packet detected ignoring, wanted %d", rxBuffer[0]); - rxBufferCount = 0; + else { + TRACE("[MP] array size %d error", rxBufferCount); setMultiTelemetryBufferState(module, NoProtocolDetected); } break; diff --git a/radio/src/telemetry/multi.h b/radio/src/telemetry/multi.h index 83f3de6fb..e9b9ada15 100644 --- a/radio/src/telemetry/multi.h +++ b/radio/src/telemetry/multi.h @@ -21,6 +21,9 @@ #ifndef OPENTX_MULTI_H #define OPENTX_MULTI_H +#define MULTI_BUFFER_SIZE 177 +extern uint8_t * Multi_Buffer; + /* Multiprotocol telemetry definition @@ -93,23 +96,21 @@ void processMultiTelemetryData(uint8_t data, uint8_t module); // This should be put into the Module definition if other modules gain this functionality struct MultiModuleSyncStatus { - uint32_t adjustedRefreshRate; // in ps + uint32_t adjustedRefreshRate = 9000 * 1000; // in ps tmr10ms_t lastUpdate; uint16_t refreshRate; uint16_t inputLag; uint8_t interval; uint8_t target; - inline bool isValid() {return (get_tmr10ms() - lastUpdate < 100);} - void getRefreshString(char* refreshText); - uint16_t getAdjustedRefreshRate(); - void calcAdjustedRefreshRate(uint16_t newRefreshRate, uint16_t newInputLag); - - MultiModuleSyncStatus() { - // Initialise to a valid value - adjustedRefreshRate=9000 * 1000; + inline bool isValid() const + { + return (get_tmr10ms() - lastUpdate < 100); } - + + void getRefreshString(char * refreshText); + const uint16_t getAdjustedRefreshRate(); + void calcAdjustedRefreshRate(uint16_t newRefreshRate, uint16_t newInputLag); }; MultiModuleSyncStatus& getMultiSyncStatus(uint8_t module); @@ -121,14 +122,24 @@ struct MultiModuleStatus { uint8_t minor; uint8_t revision; uint8_t patch; + uint8_t ch_order; uint8_t flags; uint8_t requiresFailsafeCheck; tmr10ms_t lastUpdate; - void getStatusString(char* statusText); + uint8_t protocolPrev = 0; + uint8_t protocolNext = 0; + char protocolName[8] = {0}; + uint8_t protocolSubNbr = 0; + char protocolSubName[9] = {0}; + uint8_t optionDisp = 0; + + void getStatusString(char * statusText) const; inline bool isValid() const { return (bool)(get_tmr10ms() - lastUpdate < 200); } + inline bool isBufferFull() const { return (bool) (flags & 0x80); } + inline bool supportsDisableMapping() const { return (bool) (flags & 0x40); } inline bool supportsFailsafe() const { return (bool) (flags & 0x20); } inline bool isWaitingforBind() const { return (bool) (flags & 0x10); } inline bool isBinding() const { return (bool) (flags & 0x08); } diff --git a/radio/src/telemetry/spektrum.cpp b/radio/src/telemetry/spektrum.cpp index ae5435845..29229cf2b 100644 --- a/radio/src/telemetry/spektrum.cpp +++ b/radio/src/telemetry/spektrum.cpp @@ -373,7 +373,7 @@ void processSpektrumPacket(const uint8_t *packet) void processDSMBindPacket(uint8_t module, const uint8_t *packet) { uint32_t debugval; - if (g_model.moduleData[module].type == MODULE_TYPE_MULTIMODULE && g_model.moduleData[module].getMultiProtocol(true) == MODULE_SUBTYPE_MULTI_DSM2 + if (g_model.moduleData[module].type == MODULE_TYPE_MULTIMODULE && g_model.moduleData[module].getMultiProtocol() == MODULE_SUBTYPE_MULTI_DSM2 && g_model.moduleData[module].multi.autoBindMode) { int channels = packet[5]; @@ -399,7 +399,7 @@ void processDSMBindPacket(uint8_t module, const uint8_t *packet) setTelemetryValue(PROTOCOL_TELEMETRY_SPEKTRUM, (I2C_PSEUDO_TX << 8) + 4, 0, 0, debugval, UNIT_RAW, 0); /* Finally stop binding as the rx just told us that it is bound */ - if (g_model.moduleData[module].type == MODULE_TYPE_MULTIMODULE && g_model.moduleData[module].getMultiProtocol(true) == MODULE_SUBTYPE_MULTI_DSM2 && moduleState[module].mode == MODULE_MODE_BIND) { + if (g_model.moduleData[module].type == MODULE_TYPE_MULTIMODULE && g_model.moduleData[module].getMultiProtocol() == MODULE_SUBTYPE_MULTI_DSM2 && moduleState[module].mode == MODULE_MODE_BIND) { setMultiBindStatus(module, MULTI_BIND_FINISHED); } } diff --git a/radio/src/telemetry/telemetry.h b/radio/src/telemetry/telemetry.h index 442ec7e43..6041e5660 100644 --- a/radio/src/telemetry/telemetry.h +++ b/radio/src/telemetry/telemetry.h @@ -27,6 +27,7 @@ #include "spektrum.h" #include "flysky_ibus.h" #include "hitec.h" + #include "hott.h" #include "multi.h" #endif @@ -104,8 +105,13 @@ void frskyDSetDefault(int index, uint16_t id); extern uint8_t telemetryProtocol; #if defined (MULTIMODULE) -#define IS_D16_MULTI() ((g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(false) == MODULE_SUBTYPE_MULTI_FRSKY) && (g_model.moduleData[EXTERNAL_MODULE].subType == MM_RF_FRSKY_SUBTYPE_D16 || g_model.moduleData[EXTERNAL_MODULE].subType == MM_RF_FRSKY_SUBTYPE_D16_8CH)) -#define IS_FRSKY_SPORT_PROTOCOL() (telemetryProtocol == PROTOCOL_TELEMETRY_FRSKY_SPORT || (telemetryProtocol == PROTOCOL_TELEMETRY_MULTIMODULE && IS_D16_MULTI())) +#define IS_D16_MULTI(module) ((g_model.moduleData[module].getMultiProtocol() == MODULE_SUBTYPE_MULTI_FRSKY) && (g_model.moduleData[module].subType == MM_RF_FRSKY_SUBTYPE_D16 || g_model.moduleData[module].subType == MM_RF_FRSKY_SUBTYPE_D16_8CH || g_model.moduleData[module].subType == MM_RF_FRSKY_SUBTYPE_D16_LBT || g_model.moduleData[module].subType == MM_RF_FRSKY_SUBTYPE_D16_LBT_8CH)) +#define IS_HOTT_MULTI(module) (g_model.moduleData[module].getMultiProtocol() == MODULE_SUBTYPE_MULTI_HOTT) +#if defined(HARDWARE_INTERNAL_MODULE) +#define IS_FRSKY_SPORT_PROTOCOL() (telemetryProtocol == PROTOCOL_TELEMETRY_FRSKY_SPORT || (telemetryProtocol == PROTOCOL_TELEMETRY_MULTIMODULE && (IS_D16_MULTI(INTERNAL_MODULE)||IS_D16_MULTI(EXTERNAL_MODULE)))) +#else +#define IS_FRSKY_SPORT_PROTOCOL() (telemetryProtocol == PROTOCOL_TELEMETRY_FRSKY_SPORT || (telemetryProtocol == PROTOCOL_TELEMETRY_MULTIMODULE && IS_D16_MULTI(EXTERNAL_MODULE))) +#endif #else #define IS_FRSKY_SPORT_PROTOCOL() (telemetryProtocol == PROTOCOL_TELEMETRY_FRSKY_SPORT) #endif diff --git a/radio/src/telemetry/telemetry_sensors.cpp b/radio/src/telemetry/telemetry_sensors.cpp index 868396536..dc9742b55 100644 --- a/radio/src/telemetry/telemetry_sensors.cpp +++ b/radio/src/telemetry/telemetry_sensors.cpp @@ -530,6 +530,9 @@ int setTelemetryValue(TelemetryProtocol protocol, uint16_t id, uint8_t subId, ui case PROTOCOL_TELEMETRY_HITEC: hitecSetDefault(index, id, subId, instance); break; + case PROTOCOL_TELEMETRY_HOTT: + hottSetDefault(index, id, subId, instance); + break; #endif #if defined(LUA) case PROTOCOL_TELEMETRY_LUA: diff --git a/radio/src/translations.cpp b/radio/src/translations.cpp index ca01833ce..2824a461c 100644 --- a/radio/src/translations.cpp +++ b/radio/src/translations.cpp @@ -665,6 +665,8 @@ const char STR_MULTI_VIDFREQ[] = TR_MULTI_VIDFREQ; const char STR_MULTI_OPTION[] = TR_MULTI_OPTION; const char STR_MULTI_FIXEDID[] = TR_MULTI_FIXEDID; const char STR_MULTI_AUTOBIND[] = TR_MULTI_AUTOBIND; +const char STR_DISABLE_CH_MAP[] = TR_DISABLE_CH_MAP; +const char STR_DISABLE_TELEM[] = TR_DISABLE_TELEM; const char STR_MULTI_DSM_AUTODTECT[] = TR_MULTI_DSM_AUTODTECT; const char STR_MULTI_LOWPOWER[] = TR_MULTI_LOWPOWER; const char STR_MODULE_NO_SERIAL_MODE[] = TR_MODULE_NO_SERIAL_MODE; @@ -672,10 +674,13 @@ const char STR_MODULE_NO_INPUT[] = TR_MODULE_NO_INPUT; const char STR_MODULE_WAITFORBIND[] = TR_MODULE_WAITFORBIND; const char STR_MODULE_NO_TELEMETRY[] = TR_MODULE_NO_TELEMETRY; const char STR_MODULE_BINDING[] = TR_MODULE_BINDING; +const char STR_MODULE_UPGRADE[] = TR_MODULE_UPGRADE; const char STR_PROTOCOL_INVALID[] = TR_PROTOCOL_INVALID; const char STR_MODULE_STATUS[] = TR_MODULE_STATUS; const char STR_MODULE_SYNC[] = TR_MODULE_SYNC; const char STR_MULTI_SERVOFREQ[] = TR_MULTI_SERVOFREQ; +const char STR_MULTI_MAX_THROW[] = TR_MULTI_MAX_THROW; +const char STR_MULTI_RFCHAN[] = TR_MULTI_RFCHAN; const char STR_NEEDS_FILE[] = TR_NEEDS_FILE; const char STR_EXT_MULTI_SPEC[] = TR_EXT_MULTI_SPEC; const char STR_INT_MULTI_SPEC[] = TR_INT_MULTI_SPEC; diff --git a/radio/src/translations.h b/radio/src/translations.h index d6f6304e1..5405bad76 100644 --- a/radio/src/translations.h +++ b/radio/src/translations.h @@ -390,6 +390,8 @@ extern const char STR_MULTI_VIDFREQ[]; extern const char STR_MULTI_RFTUNE[]; extern const char STR_MULTI_TELEMETRY[]; extern const char STR_MULTI_AUTOBIND[]; +extern const char STR_DISABLE_CH_MAP[]; +extern const char STR_DISABLE_TELEM[]; extern const char STR_MULTI_DSM_AUTODTECT[]; extern const char STR_MULTI_LOWPOWER[]; extern const char STR_MODULE_NO_SERIAL_MODE[]; @@ -397,10 +399,13 @@ extern const char STR_MODULE_NO_INPUT[]; extern const char STR_MODULE_WAITFORBIND[]; extern const char STR_MODULE_NO_TELEMETRY[]; extern const char STR_MODULE_BINDING[]; +extern const char STR_MODULE_UPGRADE[]; extern const char STR_PROTOCOL_INVALID[]; extern const char STR_MODULE_STATUS[]; 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 diff --git a/radio/src/translations/cz.h.txt b/radio/src/translations/cz.h.txt index 16df119e0..8cd04159d 100644 --- a/radio/src/translations/cz.h.txt +++ b/radio/src/translations/cz.h.txt @@ -630,7 +630,9 @@ #define TR_RFPOWER INDENT "Výkon RF" #define TR_MULTI_FIXEDID TR("FixedID", "Fixed ID") #define TR_MULTI_OPTION TR(INDENT "Možnosti", INDENT "Hodnota") -#define TR_MULTI_AUTOBIND TR(INDENT "Autobind",INDENT "Bind při zapnutí") +#define TR_MULTI_AUTOBIND TR(INDENT "Bind Ch.",INDENT "Bind při zapnutí") +#define TR_DISABLE_CH_MAP TR("No Ch. map", "Disable Ch. map") +#define TR_DISABLE_TELEM TR("No Telem", "Disable Telemetry") #define TR_MULTI_DSM_AUTODTECT TR(INDENT "Autodetekce", INDENT "Formát autodetekce") #define TR_MULTI_LOWPOWER TR(INDENT "Nízký výkon", INDENT "Režim nízkého výkonu") #define TR_MODULE_TELEMETRY TR(INDENT "S.Port", INDENT "S.Port link") @@ -641,6 +643,7 @@ #define TR_MODULE_NO_TELEMETRY TR3("Bez telemetrie", "Bez MULTI_TELEMETIE", "Nedetekována MULTI_TELEMETRIE") #define TR_MODULE_WAITFORBIND "Párovat při zavedení protokolu" #define TR_MODULE_BINDING TR("Bind...","Párování") +#define TR_MODULE_UPGRADE "Module upgrade required" #define TR_REBIND "Nutno přepárovat" #define TR_REG_OK "Registrace ok" #define TR_BIND_OK "Úspěšné párovaní" @@ -650,8 +653,10 @@ #define TR_BINDING_CH9_16_TELEM_OFF "k9-16 telem vyp" #define TR_PROTOCOL_INVALID TR("Špat. protokol", "Špatný protokol") #define TR_MODULE_STATUS TR(INDENT "Stav", INDENT "Stav modulu") -#define TR_MODULE_SYNC TR(INDENT "Synchro", INDENT "Synchro modulu") +#define TR_MODULE_SYNC TR(INDENT "Sync", INDENT "Proto Sync Status") #define TR_MULTI_SERVOFREQ TR(INDENT "Frekv. serva", INDENT "Obnovovací frequence serva") +#define TR_MULTI_MAX_THROW TR("Max. Throw", "Enable max. throw") +#define TR_MULTI_RFCHAN TR("RF Channel", "Select RF channel") #define TR_SYNCMENU "[Sync]" #define TR_LIMIT INDENT"Limit" #define TR_MINRSSI "Min Rssi" diff --git a/radio/src/translations/de.h.txt b/radio/src/translations/de.h.txt index 3101178c8..74deb9772 100644 --- a/radio/src/translations/de.h.txt +++ b/radio/src/translations/de.h.txt @@ -632,7 +632,9 @@ #define TR_RFPOWER INDENT "RF Power" #define TR_MULTI_FIXEDID TR("FixedID", "Fixed ID") #define TR_MULTI_OPTION TR(INDENT "Option", INDENT "Optionswert") -#define TR_MULTI_AUTOBIND TR(INDENT "Autobind",INDENT "Bind on channel") +#define TR_MULTI_AUTOBIND TR(INDENT "Bind Ch.",INDENT "Bind on channel") +#define TR_DISABLE_CH_MAP TR("No Ch. map", "Disable Ch. map") +#define TR_DISABLE_TELEM TR("No Telem", "Disable Telemetry") #define TR_MULTI_DSM_AUTODTECT TR(INDENT "Autodetect", INDENT "Autodetect format") #define TR_MULTI_LOWPOWER TR(INDENT "Low power", INDENT "Low power mode") #define TR_MODULE_TELEMETRY TR(INDENT "S.Port", INDENT "S.Port link") @@ -643,6 +645,7 @@ #define TR_MODULE_NO_TELEMETRY TR3( "No telmetry", "No MULTI_TELEMETRY", "No telemetry (enable MULTI_TELEMETRY)") #define TR_MODULE_WAITFORBIND "Bind to load protocol" #define TR_MODULE_BINDING "Binding" +#define TR_MODULE_UPGRADE "Module upgrade required" #define TR_REBIND "Rebinding required" #define TR_REG_OK "Registration ok" #define TR_BIND_OK "Bind successful" @@ -652,8 +655,10 @@ #define TR_BINDING_CH9_16_TELEM_OFF "Ch9-16 Telem OFF" #define TR_PROTOCOL_INVALID TR("Prot. invalid", "Protocol invalid") #define TR_MODULE_STATUS TR(INDENT "Status", INDENT "Module Status") -#define TR_MODULE_SYNC TR(INDENT "Sync", INDENT "Module Sync") +#define TR_MODULE_SYNC TR(INDENT "Sync", INDENT "Proto Sync Status") #define TR_MULTI_SERVOFREQ TR(INDENT "Servo rate", INDENT "Servo update rate") +#define TR_MULTI_MAX_THROW TR("Max. Throw", "Enable max. throw") +#define TR_MULTI_RFCHAN TR("RF Channel", "Select RF channel") #define TR_SYNCMENU "Sync [MENU]" #define TR_LIMIT INDENT "Grenzen" #define TR_MINRSSI "Min. RSSI" diff --git a/radio/src/translations/en.h.txt b/radio/src/translations/en.h.txt index 7501715f8..5015e69eb 100644 --- a/radio/src/translations/en.h.txt +++ b/radio/src/translations/en.h.txt @@ -631,7 +631,9 @@ #define TR_RFPOWER "RF Power" #define TR_MULTI_FIXEDID TR("FixedID", "Fixed ID") #define TR_MULTI_OPTION TR("Option", "Option value") -#define TR_MULTI_AUTOBIND TR(INDENT "Autobind",INDENT "Bind on channel") +#define TR_MULTI_AUTOBIND TR(INDENT "Bind Ch.",INDENT "Bind on channel") +#define TR_DISABLE_CH_MAP TR("No Ch. map", "Disable Ch. map") +#define TR_DISABLE_TELEM TR("No Telem", "Disable Telemetry") #define TR_MULTI_DSM_AUTODTECT TR(INDENT "Autodetect", INDENT "Autodetect format") #define TR_MULTI_LOWPOWER TR(INDENT "Low power", INDENT "Low power mode") #define TR_MODULE_TELEMETRY TR(INDENT "S.Port", INDENT "S.Port link") @@ -642,6 +644,7 @@ #define TR_MODULE_NO_TELEMETRY TR3("No telemetry", "No MULTI_TELEMETRY", "No MULTI_TELEMETRY detected") #define TR_MODULE_WAITFORBIND "Bind to load protocol" #define TR_MODULE_BINDING TR("Bind...","Binding") +#define TR_MODULE_UPGRADE "Module upgrade required" #define TR_REBIND "Rebinding required" #define TR_REG_OK "Registration ok" #define TR_BIND_OK "Bind successful" @@ -651,8 +654,10 @@ #define TR_BINDING_CH9_16_TELEM_OFF "Ch9-16 Telem OFF" #define TR_PROTOCOL_INVALID TR("Prot. invalid", "Protocol invalid") #define TR_MODULE_STATUS TR(INDENT "Status", INDENT "Module Status") -#define TR_MODULE_SYNC TR(INDENT "Sync", INDENT "Module Sync") +#define TR_MODULE_SYNC TR(INDENT "Sync", INDENT "Proto Sync Status") #define TR_MULTI_SERVOFREQ TR("Servo rate", "Servo update rate") +#define TR_MULTI_MAX_THROW TR("Max. Throw", "Enable max. throw") +#define TR_MULTI_RFCHAN TR("RF Channel", "Select RF channel") #define TR_SYNCMENU "[Sync]" #define TR_LIMIT INDENT "Limit" #define TR_MINRSSI "Min Rssi" diff --git a/radio/src/translations/es.h.txt b/radio/src/translations/es.h.txt index f206f7590..ec4b603e6 100644 --- a/radio/src/translations/es.h.txt +++ b/radio/src/translations/es.h.txt @@ -655,7 +655,9 @@ #define TR_RFPOWER "RF Power" #define TR_MULTI_FIXEDID TR("FixedID", "Fixed ID") #define TR_MULTI_OPTION TR("Option", "Option value") -#define TR_MULTI_AUTOBIND TR(INDENT "Autobind",INDENT "Bind on channel") +#define TR_MULTI_AUTOBIND TR(INDENT "Bind Ch.",INDENT "Bind on channel") +#define TR_DISABLE_CH_MAP TR("No Ch. map", "Disable Ch. map") +#define TR_DISABLE_TELEM TR("No Telem", "Disable Telemetry") #define TR_MULTI_DSM_AUTODTECT TR(INDENT "Autodetect", INDENT "Autodetect format") #define TR_MULTI_LOWPOWER TR(INDENT "Low power", INDENT "Low power mode") #define TR_MODULE_TELEMETRY TR(INDENT "S.Port", INDENT "S.Port link") @@ -666,6 +668,7 @@ #define TR_MODULE_NO_TELEMETRY TR3( "No telmetry", "No MULTI_TELEMETRY", "No telemetry (enable MULTI_TELEMETRY)") #define TR_MODULE_WAITFORBIND "Bind to load protocol" #define TR_MODULE_BINDING "Binding" +#define TR_MODULE_UPGRADE "Module upgrade required" #define TR_REBIND "Rebinding required" #define TR_REG_OK "Registration ok" #define TR_BIND_OK "Bind successful" @@ -675,8 +678,10 @@ #define TR_BINDING_CH9_16_TELEM_OFF "Ch9-16 Telem OFF" #define TR_PROTOCOL_INVALID TR("Prot. invalid", "Protocol invalid") #define TR_MODULE_STATUS TR(INDENT "Status", INDENT "Module Status") -#define TR_MODULE_SYNC TR(INDENT "Sync", INDENT "Module Sync") +#define TR_MODULE_SYNC TR(INDENT "Sync", INDENT "Proto Sync Status") #define TR_MULTI_SERVOFREQ TR("Servo rate", "Servo update rate") +#define TR_MULTI_MAX_THROW TR("Max. Throw", "Enable max. throw") +#define TR_MULTI_RFCHAN TR("RF Channel", "Select RF channel") #define TR_SYNCMENU "Sync " TR_ENTER #define TR_LIMIT INDENT"Limite" #define TR_MINRSSI "Min Rssi" diff --git a/radio/src/translations/fi.h.txt b/radio/src/translations/fi.h.txt index 32ffc35e1..60b79b0b3 100644 --- a/radio/src/translations/fi.h.txt +++ b/radio/src/translations/fi.h.txt @@ -649,7 +649,9 @@ #define TR_RFPOWER "RF Power" #define TR_MULTI_FIXEDID TR("FixedID", "Fixed ID") #define TR_MULTI_OPTION TR("Option", "Option value") -#define TR_MULTI_AUTOBIND TR(INDENT "Autobind",INDENT "Bind on channel") +#define TR_MULTI_AUTOBIND TR(INDENT "Bind Ch.",INDENT "Bind on channel") +#define TR_DISABLE_CH_MAP TR("No Ch. map", "Disable Ch. map") +#define TR_DISABLE_TELEM TR("No Telem", "Disable Telemetry") #define TR_MULTI_DSM_AUTODTECT TR(INDENT "Autodetect", INDENT "Autodetect format") #define TR_MULTI_LOWPOWER TR(INDENT "Low power", INDENT "Low power mode") #define TR_MODULE_TELEMETRY TR(INDENT "S.Port", INDENT "S.Port link") @@ -660,6 +662,7 @@ #define TR_MODULE_NO_TELEMETRY TR3( "No telmetry", "No MULTI_TELEMETRY", "No telemetry (enable MULTI_TELEMETRY)") #define TR_MODULE_WAITFORBIND "Bind to load protocol" #define TR_MODULE_BINDING "Binding" +#define TR_MODULE_UPGRADE "Module upgrade required" #define TR_REBIND "Rebinding required" #define TR_REG_OK "Registration ok" #define TR_BIND_OK "Bind successful" @@ -669,8 +672,10 @@ #define TR_BINDING_CH9_16_TELEM_OFF "Ch9-16 Telem OFF" #define TR_PROTOCOL_INVALID TR("Prot. invalid", "Protocol invalid") #define TR_MODULE_STATUS TR(INDENT "Status", INDENT "Module Status") -#define TR_MODULE_SYNC TR(INDENT "Sync", INDENT "Module Sync") +#define TR_MODULE_SYNC TR(INDENT "Sync", INDENT "Proto Sync Status") #define TR_MULTI_SERVOFREQ TR("Servo rate", "Servo update rate") +#define TR_MULTI_MAX_THROW TR("Max. Throw", "Enable max. throw") +#define TR_MULTI_RFCHAN TR("RF Channel", "Select RF channel") #define TR_SYNCMENU "[Sync]" #define TR_LIMIT INDENT"Limit" #define TR_MINRSSI "Min Rssi" diff --git a/radio/src/translations/fr.h.txt b/radio/src/translations/fr.h.txt index 66aa7d733..c0b7766ac 100644 --- a/radio/src/translations/fr.h.txt +++ b/radio/src/translations/fr.h.txt @@ -652,7 +652,9 @@ #define TR_RFPOWER TR(INDENT "Puiss. RF", INDENT "Puissance RF") #define TR_MULTI_FIXEDID "ID fixe" #define TR_MULTI_OPTION TR(INDENT "Option", INDENT "Option perso") -#define TR_MULTI_AUTOBIND TR(INDENT "Bind auto", INDENT "Bind automatique") +#define TR_MULTI_AUTOBIND TR(INDENT "Bind voie", INDENT "Bind sur voie") +#define TR_DISABLE_CH_MAP TR("No Ch. map", "Désact réorg voies") +#define TR_DISABLE_TELEM TR("No Telem", "Désact Télémétrie") #define TR_MULTI_DSM_AUTODTECT TR(INDENT "Autodét.", INDENT "Autodétection") #define TR_MULTI_LOWPOWER TR(INDENT "Basse puis.", INDENT "Mode basse puiss.") #define TR_MODULE_TELEMETRY TR(INDENT "S.Port", INDENT "Lien S.Port") @@ -663,6 +665,7 @@ #define TR_MODULE_NO_TELEMETRY TR3("Pas de télm.", "Télémétrie absente", "Télémétrie absente(act. MULTI_TELEMETRY)") #define TR_MODULE_WAITFORBIND "Binder d'abord" #define TR_MODULE_BINDING "Bind..." +#define TR_MODULE_UPGRADE "Mise à jour requise" #define TR_REBIND "Rebind requis" #define TR_REG_OK "Enregistr. ok" #define TR_BIND_OK "Bind ok" @@ -672,8 +675,10 @@ #define TR_BINDING_CH9_16_TELEM_OFF "Ch9-16 Télem OFF" #define TR_PROTOCOL_INVALID TR("Sél. invalide", "Protocole invalide") #define TR_MODULE_STATUS TR(INDENT "Etat", INDENT "Etat module") -#define TR_MODULE_SYNC TR(INDENT "Sync", INDENT "Module Sync") +#define TR_MODULE_SYNC TR(INDENT "Sync", INDENT "Proto Sync Status") #define TR_MULTI_SERVOFREQ TR(INDENT "Fréq.servo", INDENT "Fréquence servos") +#define TR_MULTI_MAX_THROW TR("Max. Throw", "Enable max. throw") +#define TR_MULTI_RFCHAN TR("RF Channel", "Select RF channel") #define TR_SYNCMENU "Sync [MENU]" #define TR_LIMIT INDENT "Limite" #define TR_MINRSSI "RSSI Min." diff --git a/radio/src/translations/it.h.txt b/radio/src/translations/it.h.txt index de8b173cb..730c1ddae 100644 --- a/radio/src/translations/it.h.txt +++ b/radio/src/translations/it.h.txt @@ -649,9 +649,11 @@ #define TR_MULTI_TELEMETRY "Telemetria" #define TR_MULTI_VIDFREQ TR("Freq. video", "Frequenza video") #define TR_RFPOWER "Potenza RF" -#define TR_MULTI_FIXEDID TR("FixedID", "Fixed ID") -#define TR_MULTI_OPTION TR("Opzione", "Opzione valore") -#define TR_MULTI_AUTOBIND TR(INDENT "Autoassoc.",INDENT "Associa automat.") +#define TR_MULTI_FIXEDID TR(INDENT"ID fisso", INDENT"ID Fisso") +#define TR_MULTI_OPTION TR(INDENT"Opzione", INDENT"Opzione valore") +#define TR_MULTI_AUTOBIND TR(INDENT "Ass. Ch.",INDENT "Associa al canale") +#define TR_DISABLE_CH_MAP TR("No Ch. map", "Disab. mappa Ch.") +#define TR_DISABLE_TELEM TR("No Telem", "Telem. disabil.") #define TR_MULTI_DSM_AUTODTECT TR(INDENT "Trova autom.", INDENT "Autoril. il formato") #define TR_MULTI_LOWPOWER TR(INDENT "Bassa pot.", INDENT "Modo bassa potenza") #define TR_MODULE_TELEMETRY TR(INDENT "S.Port", INDENT "Link S.Port") @@ -662,6 +664,7 @@ #define TR_MODULE_NO_TELEMETRY TR3("No telemetria", "MULTI_TELEMETRY disattivato", "Nessuna telem. (abilita MULTI_TELEMETRY)") #define TR_MODULE_WAITFORBIND "Associa per caricare il protocollo" #define TR_MODULE_BINDING "Associa" +#define TR_MODULE_UPGRADE "Richiede agg. modulo" #define TR_REBIND "Richiede associazione" #define TR_REG_OK "Registrazione ok" #define TR_BIND_OK "Associazione riuscita" @@ -673,6 +676,8 @@ #define TR_MODULE_STATUS TR(INDENT "Stato", INDENT "Stato del modulo") #define TR_MODULE_SYNC TR(INDENT "Sinc.", INDENT "Sinc. del modulo") #define TR_MULTI_SERVOFREQ TR("Servo rate", "Aggiorna servo rate") +#define TR_MULTI_MAX_THROW TR("Escurs. mass.", "Abilita escurs. mass.") +#define TR_MULTI_RFCHAN TR("Canale RF", "Selez. canale RF") #define TR_SYNCMENU "[Sync]" #define TR_LIMIT INDENT "Limiti" #define TR_MINRSSI "Min. RSSI" diff --git a/radio/src/translations/nl.h.txt b/radio/src/translations/nl.h.txt index c5fe2af62..348bfd018 100644 --- a/radio/src/translations/nl.h.txt +++ b/radio/src/translations/nl.h.txt @@ -637,7 +637,9 @@ #define TR_RFPOWER "RF Power" #define TR_MULTI_FIXEDID TR("FixedID", "Fixed ID") #define TR_MULTI_OPTION TR("Option", "Option value") -#define TR_MULTI_AUTOBIND TR(INDENT "Autobind",INDENT "Bind on channel") +#define TR_MULTI_AUTOBIND TR(INDENT "Bind Ch.",INDENT "Bind on channel") +#define TR_DISABLE_CH_MAP TR("No Ch. map", "Disable Ch. map") +#define TR_DISABLE_TELEM TR("No Telem", "Disable Telemetry") #define TR_MULTI_DSM_AUTODTECT TR(INDENT "Autodetect", INDENT "Autodetect format") #define TR_MULTI_LOWPOWER TR(INDENT "Low power", INDENT "Low power mode") #define TR_MODULE_TELEMETRY TR(INDENT "S.Port", INDENT "S.Port link") @@ -648,6 +650,7 @@ #define TR_MODULE_NO_TELEMETRY TR3( "No telmetry", "No MULTI_TELEMETRY", "No telemetry (enable MULTI_TELEMETRY)") #define TR_MODULE_WAITFORBIND "Bind to load protocol" #define TR_MODULE_BINDING "Binding" +#define TR_MODULE_UPGRADE "Module upgrade required" #define TR_REBIND "Rebinding required" #define TR_REG_OK "Registration ok" #define TR_BIND_OK "Bind successful" @@ -657,8 +660,10 @@ #define TR_BINDING_CH9_16_TELEM_OFF "Ch9-16 Telem OFF" #define TR_PROTOCOL_INVALID TR("Prot. invalid", "Protocol invalid") #define TR_MODULE_STATUS TR(INDENT "Status", INDENT "Module Status") -#define TR_MODULE_SYNC TR(INDENT "Sync", INDENT "Module Sync") +#define TR_MODULE_SYNC TR(INDENT "Sync", INDENT "Proto Sync Status") #define TR_MULTI_SERVOFREQ TR("Servo rate", "Servo update rate") +#define TR_MULTI_MAX_THROW TR("Max. Throw", "Enable max. throw") +#define TR_MULTI_RFCHAN TR("RF Channel", "Select RF channel") #define TR_SYNCMENU "Sync [MENU]" #define TR_LIMIT INDENT "Grenzen" #define TR_MINRSSI "Min. RSSI" diff --git a/radio/src/translations/pl.h.txt b/radio/src/translations/pl.h.txt index 631004600..d1e15a50d 100644 --- a/radio/src/translations/pl.h.txt +++ b/radio/src/translations/pl.h.txt @@ -650,7 +650,9 @@ #define TR_RFPOWER "RF Power" #define TR_MULTI_FIXEDID TR("FixedID", "Fixed ID") #define TR_MULTI_OPTION TR("Option", "Option value") -#define TR_MULTI_AUTOBIND TR(INDENT "Autobind",INDENT "Bind on channel") +#define TR_MULTI_AUTOBIND TR(INDENT "Bind Ch.",INDENT "Bind on channel") +#define TR_DISABLE_CH_MAP TR("No Ch. map", "Disable Ch. map") +#define TR_DISABLE_TELEM TR("No Telem", "Disable Telemetry") #define TR_MULTI_DSM_AUTODTECT TR(INDENT "Autodetect", INDENT "Autodetect format") #define TR_MULTI_LOWPOWER TR(INDENT "Low power", INDENT "Low power mode") #define TR_MODULE_TELEMETRY TR(INDENT "S.Port", INDENT "S.Port link") @@ -661,6 +663,7 @@ #define TR_MODULE_NO_TELEMETRY TR3( "No telmetry", "No MULTI_TELEMETRY", "No telemetry (enable MULTI_TELEMETRY)") #define TR_MODULE_WAITFORBIND "Bind to load protocol" #define TR_MODULE_BINDING "Binding" +#define TR_MODULE_UPGRADE "Module upgrade required" #define TR_REBIND "Rebinding required" #define TR_REG_OK "Registration ok" #define TR_BIND_OK "Bind successful" @@ -670,8 +673,10 @@ #define TR_BINDING_CH9_16_TELEM_OFF "Ch9-16 Telem OFF" #define TR_PROTOCOL_INVALID TR("Prot. invalid", "Protocol invalid") #define TR_MODULE_STATUS TR(INDENT "Status", INDENT "Module Status") -#define TR_MODULE_SYNC TR(INDENT "Sync", INDENT "Module Sync") +#define TR_MODULE_SYNC TR(INDENT "Sync", INDENT "Proto Sync Status") #define TR_MULTI_SERVOFREQ TR("Servo rate", "Servo update rate") +#define TR_MULTI_MAX_THROW TR("Max. Throw", "Enable max. throw") +#define TR_MULTI_RFCHAN TR("RF Channel", "Select RF channel") #define TR_SYNCMENU "[Synch]" #define TR_LIMIT INDENT "Limit" #define TR_MINRSSI "Min Rssi" diff --git a/radio/src/translations/pt.h.txt b/radio/src/translations/pt.h.txt index 2ba46aa02..ceeea2d6b 100644 --- a/radio/src/translations/pt.h.txt +++ b/radio/src/translations/pt.h.txt @@ -641,7 +641,9 @@ #define TR_RFPOWER "RF Power" #define TR_MULTI_FIXEDID TR("FixedID", "Fixed ID") #define TR_MULTI_OPTION TR("Option", "Option value") -#define TR_MULTI_AUTOBIND TR(INDENT "Autobind",INDENT "Bind on channel") +#define TR_MULTI_AUTOBIND TR(INDENT "Bind Ch.",INDENT "Bind on channel") +#define TR_DISABLE_CH_MAP TR("No Ch. map", "Disable Ch. map") +#define TR_DISABLE_TELEM TR("No Telem", "Disable Telemetry") #define TR_MULTI_DSM_AUTODTECT TR(INDENT "Autodetect", INDENT "Autodetect format") #define TR_MULTI_LOWPOWER TR(INDENT "Low power", INDENT "Low power mode") #define TR_MODULE_TELEMETRY TR(INDENT "S.Port", INDENT "S.Port link") @@ -652,6 +654,7 @@ #define TR_MODULE_NO_TELEMETRY TR3( "No telmetry", "No MULTI_TELEMETRY", "No telemetry (enable MULTI_TELEMETRY)") #define TR_MODULE_WAITFORBIND "Bind to load protocol" #define TR_MODULE_BINDING "Binding" +#define TR_MODULE_UPGRADE "Module upgrade required" #define TR_REBIND "Rebinding required" #define TR_REG_OK "Registration ok" #define TR_BIND_OK "Bind successful" @@ -661,8 +664,10 @@ #define TR_BINDING_CH9_16_TELEM_OFF "Ch9-16 Telem OFF" #define TR_PROTOCOL_INVALID TR("Prot. invalid", "Protocol invalid") #define TR_MODULE_STATUS TR(INDENT "Status", INDENT "Module Status") -#define TR_MODULE_SYNC TR(INDENT "Sync", INDENT "Module Sync") +#define TR_MODULE_SYNC TR(INDENT "Sync", INDENT "Proto Sync Status") #define TR_MULTI_SERVOFREQ TR("Servo rate", "Servo update rate") +#define TR_MULTI_MAX_THROW TR("Max. Throw", "Enable max. throw") +#define TR_MULTI_RFCHAN TR("RF Channel", "Select RF channel") #define TR_LIMIT INDENT"Limite" #define TR_MINRSSI "Min Rssi" #define TR_LATITUDE "Latitude" diff --git a/radio/src/translations/se.h.txt b/radio/src/translations/se.h.txt index 10fa01140..310ed655a 100644 --- a/radio/src/translations/se.h.txt +++ b/radio/src/translations/se.h.txt @@ -650,7 +650,9 @@ #define TR_RFPOWER "RF Power" #define TR_MULTI_FIXEDID TR("FixedID", "Fixed ID") #define TR_MULTI_OPTION TR("Option", "Option value") -#define TR_MULTI_AUTOBIND TR(INDENT "Autobind",INDENT "Bind on channel") +#define TR_MULTI_AUTOBIND TR(INDENT "Bind Ch.",INDENT "Bind on channel") +#define TR_DISABLE_CH_MAP TR("No Ch. map", "Disable Ch. map") +#define TR_DISABLE_TELEM TR("No Telem", "Disable Telemetry") #define TR_MULTI_DSM_AUTODTECT TR(INDENT "Autodetect", INDENT "Autodetect format") #define TR_MULTI_LOWPOWER TR(INDENT "Low power", INDENT "Low power mode") #define TR_MODULE_TELEMETRY TR(INDENT "S.Port", INDENT "S.Port link") @@ -661,6 +663,7 @@ #define TR_MODULE_NO_TELEMETRY TR3( "No telmetry", "No MULTI_TELEMETRY", "No telemetry (enable MULTI_TELEMETRY)") #define TR_MODULE_WAITFORBIND "Bind to load protocol" #define TR_MODULE_BINDING "Binding" +#define TR_MODULE_UPGRADE "Module upgrade required" #define TR_REBIND "Rebinding required" #define TR_REG_OK "Registration ok" #define TR_BIND_OK "Bind successful" @@ -670,8 +673,10 @@ #define TR_BINDING_CH9_16_TELEM_OFF "Ch9-16 Telem OFF" #define TR_PROTOCOL_INVALID TR("Prot. invalid", "Protocol invalid") #define TR_MODULE_STATUS TR(INDENT "Status", INDENT "Module Status") -#define TR_MODULE_SYNC TR(INDENT "Sync", INDENT "Module Sync") +#define TR_MODULE_SYNC TR(INDENT "Sync", INDENT "Proto Sync Status") #define TR_MULTI_SERVOFREQ TR("Servo rate", "Servo update rate") +#define TR_MULTI_MAX_THROW TR("Max. Throw", "Enable max. throw") +#define TR_MULTI_RFCHAN TR("RF Channel", "Select RF channel") #define TR_LIMIT INDENT "Nivå" #define TR_MINRSSI "Min Rssi" #define TR_LATITUDE "Breddgrad"