diff --git a/companion/src/CMakeLists.txt b/companion/src/CMakeLists.txt
index 6914f667c..9c98e519d 100644
--- a/companion/src/CMakeLists.txt
+++ b/companion/src/CMakeLists.txt
@@ -323,6 +323,8 @@ elseif(PCB STREQUAL X7 AND PCBREV STREQUAL T12)
set(FLAVOUR t12)
elseif(PCB STREQUAL X7 AND PCBREV STREQUAL TLITE)
set(FLAVOUR tlite)
+elseif(PCB STREQUAL X7 AND PCBREV STREQUAL TPRO)
+ set(FLAVOUR tpro)
elseif(PCB STREQUAL X7 AND PCBREV STREQUAL TX12)
set(FLAVOUR tx12)
elseif(PCB STREQUAL X7 AND PCBREV STREQUAL ZORRO)
diff --git a/companion/src/companion.qrc b/companion/src/companion.qrc
index c34fcd295..9bdbdee8b 100644
--- a/companion/src/companion.qrc
+++ b/companion/src/companion.qrc
@@ -188,6 +188,10 @@
images/simulator/JumperTLITE/right_top.png
images/simulator/JumperTLITE/right_bottom.png
images/simulator/JumperTLITE/top.png
+ images/simulator/JumperTPRO/bottom.png
+ images/simulator/JumperTPRO/left.png
+ images/simulator/JumperTPRO/right.png
+ images/simulator/JumperTPRO/top.png
images/simulator/TX12/left.png
images/simulator/TX12/left-pageup.png
images/simulator/TX12/left-pagedn.png
diff --git a/companion/src/constants.h b/companion/src/constants.h
index 63ba0a9b1..b06792a91 100644
--- a/companion/src/constants.h
+++ b/companion/src/constants.h
@@ -43,6 +43,7 @@
#define CPN_MAX_POTS (CPN_MAX_KNOBS + CPN_MAX_SLIDERS)
#define CPN_MAX_CYC 3
#define CPN_MAX_SWITCHES 32
+#define CPN_MAX_FUNCTION_SWITCHES 6
#define CPN_MAX_MOUSE_ANALOGS 2
#define CPN_MAX_GYRO_ANALOGS 2
#define CPN_MAX_ANALOGS (CPN_MAX_STICKS + CPN_MAX_POTS + CPN_MAX_MOUSE_ANALOGS + CPN_MAX_GYRO_ANALOGS)
diff --git a/companion/src/firmwares/boards.cpp b/companion/src/firmwares/boards.cpp
index 18605ea10..af164355c 100644
--- a/companion/src/firmwares/boards.cpp
+++ b/companion/src/firmwares/boards.cpp
@@ -82,6 +82,8 @@ uint32_t Boards::getFourCC(Type board)
return 0x3D78746F;
case BOARD_JUMPER_TLITE:
return 0x4278746F;
+ case BOARD_JUMPER_TPRO:
+ return 0x4678746F;
case BOARD_JUMPER_T16:
return 0x3F78746F;
case BOARD_JUMPER_T18:
@@ -121,6 +123,7 @@ int Boards::getEEpromSize(Board::Type board)
case BOARD_TARANIS_X9E:
case BOARD_JUMPER_T12:
case BOARD_JUMPER_TLITE:
+ case BOARD_JUMPER_TPRO:
case BOARD_RADIOMASTER_TX12:
case BOARD_RADIOMASTER_T8:
case BOARD_RADIOMASTER_ZORRO:
@@ -160,6 +163,7 @@ int Boards::getFlashSize(Type board)
case BOARD_TARANIS_X9E:
case BOARD_JUMPER_T12:
case BOARD_JUMPER_TLITE:
+ case BOARD_JUMPER_TPRO:
case BOARD_RADIOMASTER_TX12:
case BOARD_RADIOMASTER_ZORRO:
case BOARD_RADIOMASTER_T8:
@@ -196,7 +200,7 @@ SwitchInfo Boards::getSwitchInfo(Board::Type board, int index)
if (index < DIM(switches))
return switches[index];
}
- else if (IS_TARANIS_XLITE(board) || IS_JUMPER_TLITE(board)) {
+ else if (IS_TARANIS_XLITE(board) || IS_JUMPER_TLITE(board) || IS_JUMPER_TPRO(board)) {
const Board::SwitchInfo switches[] = {
{SWITCH_3POS, "SA"},
{SWITCH_3POS, "SB"},
@@ -365,7 +369,7 @@ int Boards::getCapability(Board::Type board, Board::Capability capability)
return 1;
else if (IS_JUMPER_TLITE(board))
return 0;
- else if (IS_TARANIS_SMALL(board))
+ else if (IS_TARANIS_SMALL(board) || IS_JUMPER_TPRO(board))
return 2;
else if (IS_TARANIS_X9E(board))
return 4;
@@ -427,7 +431,7 @@ int Boards::getCapability(Board::Type board, Board::Capability capability)
return 7;
else if (board == BOARD_TARANIS_X7)
return 8;
- else if (board == BOARD_JUMPER_TLITE)
+ else if (board == BOARD_JUMPER_TLITE || board == BOARD_JUMPER_TPRO)
return 4;
else if (board == BOARD_FLYSKY_NV14)
return 8;
@@ -447,7 +451,7 @@ int Boards::getCapability(Board::Type board, Board::Capability capability)
case FactoryInstalledSwitches:
if (IS_TARANIS_X9E(board))
return 8;
- else if (IS_JUMPER_TLITE(board))
+ else if (IS_JUMPER_TLITE(board) || IS_JUMPER_TPRO(board))
return 4;
else if(IS_RADIOMASTER_ZORRO(board))
return 8;
@@ -479,6 +483,9 @@ int Boards::getCapability(Board::Type board, Board::Capability capability)
case HasColorLcd:
return IS_FAMILY_HORUS_OR_T16(board);
+ case NumFunctionSwitches:
+ return IS_JUMPER_TPRO(board) ? 6 : 0;
+
default:
return 0;
}
@@ -645,6 +652,8 @@ QString Boards::getBoardName(Board::Type board)
return "Jumper T12";
case BOARD_JUMPER_TLITE:
return "Jumper T-Lite";
+ case BOARD_JUMPER_TPRO:
+ return "Jumper T-Pro";
case BOARD_JUMPER_T16:
return "Jumper T16";
case BOARD_JUMPER_T18:
diff --git a/companion/src/firmwares/boards.h b/companion/src/firmwares/boards.h
index 2bc37a458..ea0476bda 100644
--- a/companion/src/firmwares/boards.h
+++ b/companion/src/firmwares/boards.h
@@ -63,6 +63,7 @@ namespace Board {
BOARD_JUMPER_TLITE,
BOARD_FLYSKY_NV14,
BOARD_RADIOMASTER_ZORRO,
+ BOARD_JUMPER_TPRO,
BOARD_TYPE_COUNT,
BOARD_TYPE_MAX = BOARD_TYPE_COUNT - 1
};
@@ -143,7 +144,8 @@ namespace Board {
NumTrims,
NumTrimSwitches,
HasRTC,
- HasColorLcd
+ HasColorLcd,
+ NumFunctionSwitches
};
struct SwitchInfo
@@ -237,6 +239,11 @@ inline bool IS_JUMPER_TLITE(Board::Type board)
return board == Board::BOARD_JUMPER_TLITE;
}
+inline bool IS_JUMPER_TPRO(Board::Type board)
+{
+ return board == Board::BOARD_JUMPER_TPRO;
+}
+
inline bool IS_JUMPER_T16(Board::Type board)
{
return board == Board::BOARD_JUMPER_T16;
@@ -335,7 +342,7 @@ inline bool IS_TARANIS_X9E(Board::Type board)
inline bool IS_TARANIS_SMALL(Board::Type board)
{
- return IS_TARANIS_X7(board) || IS_TARANIS_XLITE(board) || IS_TARANIS_X9LITE(board) || IS_FAMILY_T12(board);
+ return IS_TARANIS_X7(board) || IS_TARANIS_XLITE(board) || IS_TARANIS_X9LITE(board) || IS_FAMILY_T12(board) || IS_JUMPER_TPRO(board);
}
inline bool IS_TARANIS(Board::Type board)
diff --git a/companion/src/firmwares/eepromimportexport.h b/companion/src/firmwares/eepromimportexport.h
index 965810731..bcb66ab65 100644
--- a/companion/src/firmwares/eepromimportexport.h
+++ b/companion/src/firmwares/eepromimportexport.h
@@ -568,7 +568,7 @@ class TransformedField: public DataField {
virtual void afterImport() = 0;
- int dump(int level, int offset) override
+ int dump(int level=0, int offset=0) override
{
beforeExport();
return field.dump(level, offset);
diff --git a/companion/src/firmwares/eeprominterface.h b/companion/src/firmwares/eeprominterface.h
index 02ab4884d..099501c9d 100644
--- a/companion/src/firmwares/eeprominterface.h
+++ b/companion/src/firmwares/eeprominterface.h
@@ -162,7 +162,8 @@ enum Capability {
HasAntennaChoice,
HasADCJitterFilter,
HasTelemetryBaudrate,
- TopBarZones
+ TopBarZones,
+ FunctionSwitches
};
class EEPROMInterface
diff --git a/companion/src/firmwares/modeldata.cpp b/companion/src/firmwares/modeldata.cpp
index e6b12ca5e..a5aa59b10 100644
--- a/companion/src/firmwares/modeldata.cpp
+++ b/companion/src/firmwares/modeldata.cpp
@@ -212,6 +212,17 @@ void ModelData::setDefaultMixes(const GeneralSettings & settings)
}
}
+void ModelData::setDefaultFunctionSwitches(int functionSwitchCount)
+{
+ if (functionSwitchCount == 0)
+ return;
+
+ for (int i = 0; i < functionSwitchCount; i++) {
+ functionSwitchConfig |= (Board::SWITCH_2POS << 2 * i);
+ functionSwitchGroup |= (1 << 2 * i);
+ }
+}
+
void ModelData::setDefaultValues(unsigned int id, const GeneralSettings & settings)
{
clear();
@@ -221,6 +232,7 @@ void ModelData::setDefaultValues(unsigned int id, const GeneralSettings & settin
moduleData[i].modelId = id + 1;
}
setDefaultMixes(settings);
+ setDefaultFunctionSwitches(getCurrentFirmware()->getCapability(FunctionSwitches));
}
int ModelData::getTrimValue(int phaseIdx, int trimIdx)
diff --git a/companion/src/firmwares/modeldata.h b/companion/src/firmwares/modeldata.h
index fbdd8f9c7..454ab9d2e 100644
--- a/companion/src/firmwares/modeldata.h
+++ b/companion/src/firmwares/modeldata.h
@@ -145,6 +145,7 @@ class ModelData {
bool potsWarnEnabled[CPN_MAX_POTS];
int potsWarnPosition[CPN_MAX_POTS];
bool displayChecklist;
+
GVarData gvarData[CPN_MAX_GVARS];
MavlinkData mavlink;
unsigned int telemetryProtocol;
@@ -170,10 +171,18 @@ class ModelData {
char registrationId[8+1];
+ // Function switches
+ unsigned int functionSwitchConfig;
+ unsigned int functionSwitchGroup;
+ unsigned int functionSwitchStartConfig;
+ unsigned int functionSwitchLogicalState;
+ char functionSwitchNames[CPN_MAX_FUNCTION_SWITCHES][HARDWARE_NAME_LEN + 1];
+
void clear();
bool isEmpty() const;
void setDefaultInputs(const GeneralSettings & settings);
void setDefaultMixes(const GeneralSettings & settings);
+ void setDefaultFunctionSwitches(int functionSwitchCount);
void setDefaultValues(unsigned int id, const GeneralSettings & settings);
int getTrimValue(int phaseIdx, int trimIdx);
diff --git a/companion/src/firmwares/opentx/opentxeeprom.cpp b/companion/src/firmwares/opentx/opentxeeprom.cpp
index df8b9263a..421138999 100644
--- a/companion/src/firmwares/opentx/opentxeeprom.cpp
+++ b/companion/src/firmwares/opentx/opentxeeprom.cpp
@@ -51,6 +51,9 @@ inline int MAX_SWITCHES(Board::Type board, int version)
if (IS_TARANIS_X7(board))
return 8;
+ if (IS_JUMPER_TPRO(board))
+ return 10;
+
return Boards::getCapability(board, Board::Switches);
}
@@ -81,6 +84,13 @@ inline int MAX_POTS(Board::Type board, int version)
return Boards::getCapability(board, Board::Pots);
}
+inline int MAX_FUNCTION_SWITCHES(Board::Type board, int version)
+{
+ if (IS_JUMPER_TPRO(board))
+ return 6;
+ return 0;
+}
+
inline int MAX_POTS_STORAGE(Board::Type board, int version)
{
if (version <= 218 && IS_FAMILY_HORUS_OR_T16(board))
@@ -2630,17 +2640,17 @@ OpenTxModelData::OpenTxModelData(ModelData & modelData, Board::Type board, unsig
internalField.Append(new LimitField(this, modelData.limitData[i], board, version));
for (int i=0; i(this, modelData.thrTraceSrc, "Throttle Source"));
@@ -2836,6 +2846,16 @@ OpenTxModelData::OpenTxModelData(ModelData & modelData, Board::Type board, unsig
else if (version >= 219) {
internalField.Append(new ZCharField<8>(this, modelData.registrationId, "ACCESS Registration ID"));
}
+
+ if (IS_JUMPER_TPRO(board)) {
+ internalField.Append(new UnsignedField<16>(this, modelData.functionSwitchConfig));
+ internalField.Append(new UnsignedField<16>(this, modelData.functionSwitchGroup));
+ internalField.Append(new UnsignedField<16>(this, modelData.functionSwitchStartConfig));
+ internalField.Append(new UnsignedField<8>(this, modelData.functionSwitchLogicalState));
+ for (int i=0; i < MAX_FUNCTION_SWITCHES(board, version); ++i) {
+ internalField.Append(new ZCharField<3>(this, modelData.functionSwitchNames[i], "Function switch name"));
+ }
+ }
}
void OpenTxModelData::beforeExport()
diff --git a/companion/src/firmwares/opentx/opentxeeprom.h b/companion/src/firmwares/opentx/opentxeeprom.h
index c3f188eea..5ad907871 100644
--- a/companion/src/firmwares/opentx/opentxeeprom.h
+++ b/companion/src/firmwares/opentx/opentxeeprom.h
@@ -40,6 +40,7 @@
#define JUMPER_TLITE_VARIANT 0x4003
#define RADIOMASTER_T8_VARIANT 0x4004
#define RADIOMASTER_ZORRO_VARIANT 0x4006
+#define JUMPER_TPRO_VARIANT 0x4005
class OpenTxGeneralData: public TransformedField {
public:
diff --git a/companion/src/firmwares/opentx/opentxinterface.cpp b/companion/src/firmwares/opentx/opentxinterface.cpp
index 59c6bab33..940d57456 100644
--- a/companion/src/firmwares/opentx/opentxinterface.cpp
+++ b/companion/src/firmwares/opentx/opentxinterface.cpp
@@ -62,6 +62,8 @@ const char * OpenTxEepromInterface::getName()
return "OpenTX for Jumper T12";
case BOARD_JUMPER_TLITE:
return "OpenTX for Jumper T-Lite";
+ case BOARD_JUMPER_TPRO:
+ return "OpenTX for Jumper T-Pro";
case BOARD_JUMPER_T16:
return "OpenTX for Jumper T16";
case BOARD_JUMPER_T18:
@@ -347,6 +349,9 @@ int OpenTxEepromInterface::save(uint8_t * eeprom, const RadioData & radioData, u
else if (IS_JUMPER_TLITE(board)) {
variant |= JUMPER_TLITE_VARIANT;
}
+ else if (IS_JUMPER_TPRO(board)) {
+ variant |= JUMPER_TPRO_VARIANT;
+ }
else if (IS_RADIOMASTER_TX12(board)) {
variant |= RADIOMASTER_TX12_VARIANT;
}
@@ -752,6 +757,9 @@ int OpenTxFirmware::getCapability(::Capability capability)
return IS_HORUS_OR_TARANIS(board) ? true : false;
case TopBarZones:
return getCapability(LcdWidth) > getCapability(LcdHeight) ? 4 : 2;
+ case FunctionSwitches:
+ return IS_JUMPER_TPRO(board) ? 6 : 0;
+
default:
return 0;
}
@@ -1025,6 +1033,11 @@ bool OpenTxEepromInterface::checkVariant(unsigned int version, unsigned int vari
variantError = true;
}
}
+ else if (IS_JUMPER_TPRO(board)) {
+ if (variant != JUMPER_TPRO_VARIANT) {
+ variantError = true;
+ }
+ }
else if (IS_RADIOMASTER_TX12(board)) {
if (variant != RADIOMASTER_TX12_VARIANT) {
variantError = true;
@@ -1371,6 +1384,16 @@ void registerOpenTxFirmwares()
registerOpenTxFirmware(firmware);
addOpenTxRfOptions(firmware, FLEX);
+ /* Jumper T-Pro board */
+ firmware = new OpenTxFirmware("opentx-tpro", QCoreApplication::translate("Firmware", "Jumper T-Pro"), BOARD_JUMPER_TPRO);
+ addOpenTxCommonOptions(firmware);
+ firmware->addOption("noheli", Firmware::tr("Disable HELI menu and cyclic mix support"));
+ firmware->addOption("nogvars", Firmware::tr("Disable Global variables"));
+ firmware->addOption("lua", Firmware::tr("Enable Lua custom scripts screen"));
+ addOpenTxFontOptions(firmware);
+ registerOpenTxFirmware(firmware);
+ addOpenTxRfOptions(firmware, FLEX);
+
/* Jumper T16 board */
firmware = new OpenTxFirmware("opentx-t16", Firmware::tr("Jumper T16 / T16+ / T16 Pro"), BOARD_JUMPER_T16);
addOpenTxFrskyOptions(firmware);
diff --git a/companion/src/images/simulator/JumperTPRO/bottom.png b/companion/src/images/simulator/JumperTPRO/bottom.png
new file mode 100644
index 000000000..185b5ac36
Binary files /dev/null and b/companion/src/images/simulator/JumperTPRO/bottom.png differ
diff --git a/companion/src/images/simulator/JumperTPRO/left.png b/companion/src/images/simulator/JumperTPRO/left.png
new file mode 100644
index 000000000..efcfb5e98
Binary files /dev/null and b/companion/src/images/simulator/JumperTPRO/left.png differ
diff --git a/companion/src/images/simulator/JumperTPRO/right.png b/companion/src/images/simulator/JumperTPRO/right.png
new file mode 100644
index 000000000..e30e90a91
Binary files /dev/null and b/companion/src/images/simulator/JumperTPRO/right.png differ
diff --git a/companion/src/images/simulator/JumperTPRO/top.png b/companion/src/images/simulator/JumperTPRO/top.png
new file mode 100644
index 000000000..7cf5226ff
Binary files /dev/null and b/companion/src/images/simulator/JumperTPRO/top.png differ
diff --git a/companion/src/modeledit/CMakeLists.txt b/companion/src/modeledit/CMakeLists.txt
index 73f0acf92..7404f821e 100644
--- a/companion/src/modeledit/CMakeLists.txt
+++ b/companion/src/modeledit/CMakeLists.txt
@@ -45,6 +45,7 @@ set(modeledit_HDRS
set(modeledit_UIS
setup_timer.ui
setup_module.ui
+ setup_function_switches.ui
flightmode.ui
telemetry_customscreen.ui
telemetry_sensor.ui
diff --git a/companion/src/modeledit/setup.cpp b/companion/src/modeledit/setup.cpp
index 9b4222d50..30cf3bbe2 100644
--- a/companion/src/modeledit/setup.cpp
+++ b/companion/src/modeledit/setup.cpp
@@ -22,6 +22,7 @@
#include "ui_setup.h"
#include "ui_setup_timer.h"
#include "ui_setup_module.h"
+#include "ui_setup_function_switches.h"
#include "appdata.h"
#include "modelprinter.h"
#include "multiprotocols.h"
@@ -982,6 +983,170 @@ void ModulePanel::onClearAccessRxClicked()
}
}
+/******************************************************************************/
+FunctionSwitchesPanel::FunctionSwitchesPanel(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware):
+ ModelPanel(parent, model, generalSettings, firmware),
+ ui(new Ui::FunctionSwitches)
+{
+ ui->setupUi(this);
+
+ lock = true;
+
+ QRegExp rx(CHAR_FOR_NAMES_REGEX);
+
+ switchcnt = Boards::getCapability(firmware->getBoard(), Board::NumFunctionSwitches);
+
+ for (int i = 0; i < switchcnt; i++) {
+ QLabel * lblSwitchId = new QLabel(this);
+ lblSwitchId->setText(tr("SW%1").arg(i + 1));
+
+ AutoLineEdit * aleName = new AutoLineEdit(this);
+ aleName->setProperty("index", i);
+ aleName->setValidator(new QRegExpValidator(rx, this));
+ aleName->setField((char *)model.functionSwitchNames[i], 3);
+
+ // TODO itemmodel
+ QComboBox * cboConfig = new QComboBox(this);
+ cboConfig->setProperty("index", i);
+ cboConfig->addItem(tr("NONE"));
+ cboConfig->addItem(tr("TOGGLE"));
+ cboConfig->addItem(tr("2POS"));
+
+ // TODO itemmodel
+ QComboBox * cboStartPosn = new QComboBox(this);
+ cboStartPosn->setProperty("index", i);
+ cboStartPosn->addItem(CPN_STR_SW_INDICATOR_UP);
+ cboStartPosn->addItem(CPN_STR_SW_INDICATOR_DN);
+ cboStartPosn->addItem("=");
+
+ QSpinBox * sbGroup = new QSpinBox(this);
+ sbGroup->setProperty("index", i);
+ sbGroup->setMaximum(3);
+
+ int row = 0;
+ int coloffset = 1;
+ ui->gridSwitches->addWidget(lblSwitchId, row++, i + coloffset);
+ ui->gridSwitches->addWidget(aleName, row++, i + coloffset);
+ ui->gridSwitches->addWidget(cboConfig, row++, i + coloffset);
+ ui->gridSwitches->addWidget(cboStartPosn, row++, i + coloffset);
+ ui->gridSwitches->addWidget(sbGroup, row++, i + coloffset);
+
+ connect(cboConfig, QOverload::of(&QComboBox::currentIndexChanged), this, &FunctionSwitchesPanel::on_configCurrentIndexChanged);
+ connect(cboStartPosn, QOverload::of(&QComboBox::currentIndexChanged), this, &FunctionSwitchesPanel::on_startPosnCurrentIndexChanged);
+ connect(sbGroup, QOverload::of(&QSpinBox::valueChanged), this, &FunctionSwitchesPanel::on_groupChanged);
+
+ aleNames << aleName;
+ cboConfigs << cboConfig;
+ cboStartupPosns << cboStartPosn;
+ sbGroups << sbGroup;
+ }
+
+ update();
+
+ lock = false;
+}
+
+FunctionSwitchesPanel::~FunctionSwitchesPanel()
+{
+ delete ui;
+}
+
+void FunctionSwitchesPanel::update()
+{
+ for (int i = 0; i < switchcnt; i++) {
+ update(i);
+ }
+}
+
+void FunctionSwitchesPanel::update(int index)
+{
+ lock = true;
+
+ for (int i = 0; i < switchcnt; i++) {
+ aleNames[i]->update();
+ cboConfigs[i]->setCurrentIndex((model->functionSwitchConfig >> (2 * i)) & 0x03);
+ cboStartupPosns[i]->setCurrentIndex((model->functionSwitchStartConfig >> (2 * i)) & 0x03);
+ sbGroups[i]->setValue((model->functionSwitchGroup >> (2 * i)) & 0x03);
+
+ if (cboConfigs[i]->currentIndex() < 2)
+ cboStartupPosns[i]->setEnabled(false);
+ else
+ cboStartupPosns[i]->setEnabled(true);
+
+ if (cboConfigs[i]->currentIndex() < 1)
+ sbGroups[i]->setEnabled(false);
+ else
+ sbGroups[i]->setEnabled(true);
+ }
+
+ lock = false;
+}
+
+void FunctionSwitchesPanel::on_configCurrentIndexChanged(int index)
+{
+ if (!sender())
+ return;
+
+ QComboBox * cb = qobject_cast(sender());
+
+ if (cb && !lock) {
+ lock = true;
+ bool ok = false;
+ int i = sender()->property("index").toInt(&ok);
+ if (ok && ((model->functionSwitchConfig >> (2 * i)) & 0x03) != (unsigned int)index) {
+ unsigned int mask = ((unsigned int) 0x03 << (2 * i));
+ model->functionSwitchConfig = (model->functionSwitchConfig & ~ mask) | ((unsigned int) index << (2 * i));
+ if (index < 2)
+ model->functionSwitchStartConfig = (model->functionSwitchStartConfig & ~ mask) | ((unsigned int) 0 << (2 * i));
+ if (index < 1)
+ model->functionSwitchGroup = (model->functionSwitchGroup & ~ mask) | ((unsigned int) 0 << (2 * i));
+ update(i);
+ emit modified();
+ }
+ lock = false;
+ }
+}
+
+void FunctionSwitchesPanel::on_startPosnCurrentIndexChanged(int index)
+{
+ if (!sender())
+ return;
+
+ QComboBox * cb = qobject_cast(sender());
+
+ if (cb && !lock) {
+ lock = true;
+ bool ok = false;
+ int i = sender()->property("index").toInt(&ok);
+ if (ok && ((model->functionSwitchStartConfig >> (2 * i)) & 0x03) != (unsigned int)index) {
+ unsigned int mask = ((unsigned int) 0x03 << (2 * i));
+ model->functionSwitchStartConfig = (model->functionSwitchStartConfig & ~ mask) | ((unsigned int) index << (2 * i));
+ emit modified();
+ }
+ lock = false;
+ }
+}
+
+void FunctionSwitchesPanel::on_groupChanged(int value)
+{
+ if (!sender())
+ return;
+
+ QSpinBox * sb = qobject_cast(sender());
+
+ if (sb && !lock) {
+ lock = true;
+ bool ok = false;
+ int i = sender()->property("index").toInt(&ok);
+ if (ok && ((model->functionSwitchGroup >> (2 * i)) & 0x03) != (unsigned int)value) {
+ unsigned int mask = ((unsigned int) 0x03 << (2 * i));
+ model->functionSwitchGroup = (model->functionSwitchGroup & ~ mask) | ((unsigned int) value << (2 * i));
+ emit modified();
+ }
+ lock = false;
+ }
+}
+
/******************************************************************************/
SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware,
@@ -1221,6 +1386,11 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge
ui->trimsDisplay->setField(model.trimsDisplay, this);
+ if (Boards::getCapability(firmware->getBoard(), Board::NumFunctionSwitches) > 0)
+ ui->functionSwitchesLayout->addWidget(new FunctionSwitchesPanel(this, model, generalSettings, firmware));
+ //else
+ // ui->functionSwitchesLayout->hide();
+
for (int i = firmware->getCapability(NumFirstUsableModule); i < firmware->getCapability(NumModules); i++) {
modules[i] = new ModulePanel(this, model, model.moduleData[i], generalSettings, firmware, i);
ui->modulesLayout->addWidget(modules[i]);
diff --git a/companion/src/modeledit/setup.h b/companion/src/modeledit/setup.h
index 824b28acb..c63932237 100644
--- a/companion/src/modeledit/setup.h
+++ b/companion/src/modeledit/setup.h
@@ -31,8 +31,11 @@ namespace Ui {
class Setup;
class Timer;
class Module;
+ class FunctionSwitches;
}
+class AutoLineEdit;
+
class TimerPanel : public ModelPanel
{
Q_OBJECT
@@ -128,6 +131,31 @@ class ModulePanel : public ModelPanel
void updateFailsafeUI(unsigned channel, quint8 updtSb);
};
+class FunctionSwitchesPanel : public ModelPanel
+{
+ Q_OBJECT
+
+ public:
+ FunctionSwitchesPanel(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware);
+ virtual ~FunctionSwitchesPanel();
+
+ virtual void update();
+ void update(int index);
+
+ private slots:
+ void on_configCurrentIndexChanged(int index);
+ void on_startPosnCurrentIndexChanged(int index);
+ void on_groupChanged(int value);
+
+ private:
+ Ui::FunctionSwitches * ui;
+ QVector aleNames;
+ QVector cboConfigs;
+ QVector cboStartupPosns;
+ QVector sbGroups;
+ int switchcnt;
+};
+
class SetupPanel : public ModelPanel
{
Q_OBJECT
diff --git a/companion/src/modeledit/setup.ui b/companion/src/modeledit/setup.ui
index ee0ec28a3..51aae4f1e 100644
--- a/companion/src/modeledit/setup.ui
+++ b/companion/src/modeledit/setup.ui
@@ -7,7 +7,7 @@
0
0
1007
- 405
+ 435
@@ -630,6 +630,9 @@ If this is checked the throttle will be reversed. Idle will be forward, trim wi
+ -
+
+
-
diff --git a/companion/src/modeledit/setup_function_switches.ui b/companion/src/modeledit/setup_function_switches.ui
new file mode 100644
index 000000000..acfd88e5d
--- /dev/null
+++ b/companion/src/modeledit/setup_function_switches.ui
@@ -0,0 +1,121 @@
+
+
+ FunctionSwitches
+
+
+
+ 0
+ 0
+ 231
+ 140
+
+
+
+ Form
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
-
+
+
+
+ 75
+ true
+
+
+
+ Function Switches
+
+
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop
+
+
+
+ -
+
+
+ QLayout::SetMinimumSize
+
+
-
+
+
+ Type
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Group
+
+
+
+ -
+
+
+ Start
+
+
+
+ -
+
+
+ Name
+
+
+
+ -
+
+
+
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+
+
+
+
+
diff --git a/companion/src/simulation/CMakeLists.txt b/companion/src/simulation/CMakeLists.txt
index cc605abbb..091867696 100644
--- a/companion/src/simulation/CMakeLists.txt
+++ b/companion/src/simulation/CMakeLists.txt
@@ -14,6 +14,7 @@ set(simulation_SRCS
simulateduiwidgetX12.cpp
simulateduiwidgetJumperT12.cpp
simulateduiwidgetJumperTLITE.cpp
+ simulateduiwidgetJumperTPRO.cpp
simulateduiwidgetJumperT16.cpp
simulateduiwidgetJumperT18.cpp
simulateduiwidgetTX12.cpp
@@ -46,6 +47,7 @@ set(simulation_UIS
simulateduiwidgetX12.ui
simulateduiwidgetJumperT12.ui
simulateduiwidgetJumperTLITE.ui
+ simulateduiwidgetJumperTPRO.ui
simulateduiwidgetJumperT16.ui
simulateduiwidgetJumperT18.ui
simulateduiwidgetTX12.ui
diff --git a/companion/src/simulation/simulateduiwidget.h b/companion/src/simulation/simulateduiwidget.h
index 579ad567f..187a60660 100644
--- a/companion/src/simulation/simulateduiwidget.h
+++ b/companion/src/simulation/simulateduiwidget.h
@@ -113,6 +113,7 @@ namespace Ui {
class SimulatedUIWidgetX12;
class SimulatedUIWidgetJumperT12;
class SimulatedUIWidgetJumperTLITE;
+ class SimulatedUIWidgetJumperTPRO;
class SimulatedUIWidgetJumperT16;
class SimulatedUIWidgetJumperT18;
class SimulatedUIWidgetTX16S;
@@ -258,6 +259,18 @@ class SimulatedUIWidgetJumperTLITE: public SimulatedUIWidget
Ui::SimulatedUIWidgetJumperTLITE * ui;
};
+class SimulatedUIWidgetJumperTPRO: public SimulatedUIWidget
+{
+ Q_OBJECT
+
+ public:
+ explicit SimulatedUIWidgetJumperTPRO(SimulatorInterface * simulator, QWidget * parent = NULL);
+ virtual ~SimulatedUIWidgetJumperTPRO();
+
+ private:
+ Ui::SimulatedUIWidgetJumperTPRO * ui;
+};
+
class SimulatedUIWidgetJumperT16: public SimulatedUIWidget
{
Q_OBJECT
diff --git a/companion/src/simulation/simulateduiwidgetJumperTPRO.cpp b/companion/src/simulation/simulateduiwidgetJumperTPRO.cpp
new file mode 100644
index 000000000..e46c7fbad
--- /dev/null
+++ b/companion/src/simulation/simulateduiwidgetJumperTPRO.cpp
@@ -0,0 +1,54 @@
+#include "simulateduiwidget.h"
+#include "ui_simulateduiwidgetJumperTPRO.h"
+
+// NOTE: RadioUiAction(NUMBER,...): NUMBER relates to enum EnumKeys in the specific board.h
+
+SimulatedUIWidgetJumperTPRO::SimulatedUIWidgetJumperTPRO(SimulatorInterface *simulator, QWidget * parent):
+ SimulatedUIWidget(simulator, parent),
+ ui(new Ui::SimulatedUIWidgetJumperTPRO)
+{
+ RadioUiAction * act;
+
+ ui->setupUi(this);
+
+ act = new RadioUiAction(0, QList() << Qt::Key_PageUp << Qt::Key_Up, SIMU_STR_HLP_KEYS_GO_UP, SIMU_STR_HLP_ACT_MENU_ICN);
+ addRadioWidget(ui->leftbuttons->addArea(QRect(70, 85, 110, 90), "JumperTPRO/left.png", act));
+
+ act = new RadioUiAction(3, QList() << Qt::Key_PageDown << Qt::Key_Down, SIMU_STR_HLP_KEYS_GO_DN, SIMU_STR_HLP_ACT_PAGE);
+ addRadioWidget(ui->leftbuttons->addArea(QRect(53, 174, 110, 90), "JumperTPRO/left.png", act));
+
+ act = new RadioUiAction(1, QList() << Qt::Key_Delete << Qt::Key_Escape << Qt::Key_Backspace, SIMU_STR_HLP_KEYS_EXIT, SIMU_STR_HLP_ACT_EXIT);
+ addRadioWidget(ui->leftbuttons->addArea(QRect(11, 257, 110, 90), "JumperTPRO/left.png", act));
+
+ m_mouseMidClickAction = new RadioUiAction(2, QList() << Qt::Key_Enter << Qt::Key_Return, SIMU_STR_HLP_KEYS_ACTIVATE, SIMU_STR_HLP_ACT_ROT_DN);
+ addRadioWidget(ui->rightbuttons->addArea(QRect(10, 96, 200, 220), "JumperTPRO/right.png", m_mouseMidClickAction));
+
+ //addRadioWidget(ui->leftbuttons->addArea(QRect(10, 65, 70, 50), "JumperTPRO/left_scrnshot.png", m_screenshotAction));
+
+ m_backlightColors << QColor(215, 243, 255); // X7 Blue
+ m_backlightColors << QColor(166,247,159);
+ m_backlightColors << QColor(247,159,166);
+ m_backlightColors << QColor(255,195,151);
+ m_backlightColors << QColor(247,242,159);
+
+ setLcd(ui->lcd);
+
+ QString css = "#radioUiWidget {"
+ "background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:1,"
+ "stop:0 rgba(255, 255, 255, 255),"
+ "stop:0.757062 rgba(241, 238, 238, 255),"
+ "stop:1 rgba(247, 245, 245, 255));"
+ "}";
+
+ QTimer * tim = new QTimer(this);
+ tim->setSingleShot(true);
+ connect(tim, &QTimer::timeout, [this, css]() {
+ emit customStyleRequest(css);
+ });
+ tim->start(100);
+}
+
+SimulatedUIWidgetJumperTPRO::~SimulatedUIWidgetJumperTPRO()
+{
+ delete ui;
+}
diff --git a/companion/src/simulation/simulateduiwidgetJumperTPRO.ui b/companion/src/simulation/simulateduiwidgetJumperTPRO.ui
new file mode 100644
index 000000000..5a77f11ff
--- /dev/null
+++ b/companion/src/simulation/simulateduiwidgetJumperTPRO.ui
@@ -0,0 +1,258 @@
+
+
+ SimulatedUIWidgetJumperTPRO
+
+
+
+ 0
+ 0
+ 725
+ 389
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 725
+ 389
+
+
+
+
+ 501
+ 310
+
+
+
+ Jumper T-Pro Simulator
+
+
+ background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(255, 255, 255, 255), stop:0.757062 rgba(241, 238, 238, 255), stop:1 rgba(247, 245, 245, 255));
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 234
+ 368
+
+
+
+
+ 234
+ 368
+
+
+
+ background:url(:/images/simulator/JumperTPRO/left.png);
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 256
+ 231
+
+
+
+
+ 256
+ 231
+
+
+
+ background-color: rgb(215, 243, 255);
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 236
+ 368
+
+
+
+
+ 236
+ 368
+
+
+
+ background:url(:/images/simulator/JumperTPRO/right.png)
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 255
+ 85
+
+
+
+
+ 255
+ 85
+
+
+
+ background:url(:/images/simulator/JumperTPRO/top.png)
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 255
+ 131
+
+
+
+
+ 255
+ 131
+
+
+
+ background:url(:/images/simulator/JumperTPRO/bottom.png)
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 10
+
+
+
+
+ 16777215
+ 12
+
+
+
+
+ 0
+ 12
+
+
+
+ background-color: rgb(255, 255, 255);
+
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 10
+
+
+
+
+ 16777215
+ 10
+
+
+
+ background-color: rgb(247, 245, 245);
+
+
+
+
+
+
+
+
+
+
+ LcdWidget
+ QWidget
+
+ 1
+
+
+ ButtonsWidget
+ QWidget
+
+ 1
+
+
+
+
+
diff --git a/companion/src/simulation/simulatorwidget.cpp b/companion/src/simulation/simulatorwidget.cpp
index b087c7055..8f3ef08c2 100644
--- a/companion/src/simulation/simulatorwidget.cpp
+++ b/companion/src/simulation/simulatorwidget.cpp
@@ -94,6 +94,9 @@ SimulatorWidget::SimulatorWidget(QWidget * parent, SimulatorInterface * simulato
case Board::BOARD_JUMPER_TLITE:
radioUiWidget = new SimulatedUIWidgetJumperTLITE(simulator, this);
break;
+ case Board::BOARD_JUMPER_TPRO:
+ radioUiWidget = new SimulatedUIWidgetJumperTPRO(simulator, this);
+ break;
case Board::BOARD_JUMPER_T16:
radioUiWidget = new SimulatedUIWidgetJumperT16(simulator, this);
break;
diff --git a/radio/src/dataconstants.h b/radio/src/dataconstants.h
index fd108bf56..268dcb9a5 100644
--- a/radio/src/dataconstants.h
+++ b/radio/src/dataconstants.h
@@ -419,7 +419,12 @@ enum SwitchSources {
SWSRC_SD2,
#endif
-#if defined(STORAGE_SWITCH_E)
+#if defined(FUNCTION_SWITCHES) && defined(RADIO_TPRO)
+ SWSRC_FIRST_FUNCTION_SWITCH,
+ SWSRC_SE0 = SWSRC_FIRST_FUNCTION_SWITCH,
+ SWSRC_SE1,
+ SWSRC_SE2,
+#elif defined(STORAGE_SWITCH_E)
SWSRC_SE0,
SWSRC_SE1,
SWSRC_SE2,
@@ -569,7 +574,7 @@ enum SwitchSources {
SWSRC_INVERT SKIP = SWSRC_COUNT+1,
};
-#if NUM_SWITCHES >= 8
+#if NUM_SWITCHES - NUM_FUNCTIONS_SWITCHES >= 8
#define SWSRC_TRAINER SWSRC_SH2
#else
#define SWSRC_TRAINER SWSRC_LAST_SWITCH,
@@ -786,11 +791,15 @@ enum MixSources {
static_assert(MIXSRC_FIRST_LOGICAL_SWITCH == MIXSRC_FIRST_SWITCH + STORAGE_NUM_SWITCHES, "Wrong switches definition in MIXSRC list");
#endif
-#define MIXSRC_FIRST (MIXSRC_NONE + 1)
-#define MIXSRC_LAST MIXSRC_LAST_CH
-#define MIXSRC_LAST_SWITCH (MIXSRC_FIRST_SWITCH + STORAGE_NUM_SWITCHES - 1)
-#define INPUTSRC_FIRST MIXSRC_Rud
-#define INPUTSRC_LAST MIXSRC_LAST_TELEM
+#define MIXSRC_FIRST (MIXSRC_NONE + 1)
+#define MIXSRC_LAST MIXSRC_LAST_CH
+#define MIXSRC_LAST_SWITCH (MIXSRC_FIRST_SWITCH + STORAGE_NUM_SWITCHES - 1)
+#define INPUTSRC_FIRST MIXSRC_Rud
+#define INPUTSRC_LAST MIXSRC_LAST_TELEM
+#if defined(FUNCTION_SWITCHES)
+#define MIXSRC_LAST_REGULAR_SWITCH (MIXSRC_FIRST_SWITCH + NUM_REGULAR_SWITCHES - 1)
+#define MIXSRC_FIRST_FS_SWITCH (MIXSRC_LAST_REGULAR_SWITCH + 1)
+#endif
enum BacklightMode {
e_backlight_mode_off = 0,
diff --git a/radio/src/datastructs.h b/radio/src/datastructs.h
index 5cc4c4319..8da911cf5 100644
--- a/radio/src/datastructs.h
+++ b/radio/src/datastructs.h
@@ -121,6 +121,9 @@ static inline void check_struct()
#elif defined(PCBXLITE)
CHKSIZE(RadioData, 858);
CHKSIZE(ModelData, 6159);
+#elif defined(RADIO_TPRO)
+ CHKSIZE(RadioData, 841);
+ CHKSIZE(ModelData, 6184);
#elif defined(PCBX7)
CHKSIZE(RadioData, 864);
CHKSIZE(ModelData, 6159);
diff --git a/radio/src/datastructs_private.h b/radio/src/datastructs_private.h
index e062e926d..c4453ee69 100644
--- a/radio/src/datastructs_private.h
+++ b/radio/src/datastructs_private.h
@@ -616,6 +616,17 @@ PACK(struct CustomScreenData {
#define SCRIPT_DATA
#endif
+#if defined(FUNCTION_SWITCHES) && NUM_FUNCTIONS_SWITCHES < 8
+ #define FUNCTION_SWITCHS_FIELDS \
+ uint16_t functionSwitchConfig; \
+ uint16_t functionSwitchGroup; \
+ uint16_t functionSwitchStartConfig; \
+ uint8_t functionSwitchLogicalState; \
+ char switchNames[NUM_FUNCTIONS_SWITCHES][LEN_SWITCH_NAME];
+#else
+ #define FUNCTION_SWITCHS_FIELDS
+#endif
+
PACK(struct PartialModel {
ModelHeader header;
TimerData timers[MAX_TIMERS];
@@ -683,6 +694,8 @@ PACK(struct ModelData {
char modelRegistrationID[PXX2_LEN_REGISTRATION_ID];
+ FUNCTION_SWITCHS_FIELDS
+
bool isTrainerTraineeEnable() const
{
#if defined(PCBNV14)
@@ -794,7 +807,7 @@ PACK(struct TrainerData {
uint8_t backlightColor; \
CUST_ARRAY(sticksConfig, struct_sticksConfig, stick_name_valid); \
swconfig_t switchConfig ARRAY(2,struct_switchConfig,nullptr); \
- char switchNames[STORAGE_NUM_SWITCHES][LEN_SWITCH_NAME] SKIP; \
+ char switchNames[STORAGE_NUM_SWITCHES - NUM_FUNCTIONS_SWITCHES][LEN_SWITCH_NAME] SKIP; \
char anaNames[NUM_STICKS+STORAGE_NUM_POTS+STORAGE_NUM_SLIDERS][LEN_ANA_NAME] SKIP; \
BLUETOOTH_FIELDS
#else
diff --git a/radio/src/gui/128x64/model_setup.cpp b/radio/src/gui/128x64/model_setup.cpp
index f6a6c6160..9460b4a74 100644
--- a/radio/src/gui/128x64/model_setup.cpp
+++ b/radio/src/gui/128x64/model_setup.cpp
@@ -39,7 +39,7 @@ uint8_t g_moduleIdx;
uint8_t getSwitchWarningsCount()
{
uint8_t count = 0;
- for (int i=0; ipersistent = editChoice(MODEL_SETUP_2ND_COLUMN, y, STR_PERSISTENT, STR_VPERSISTENT, timer->persistent, 0, 2, attr, event);
break;
}
+#if defined(FUNCTION_SWITCHES)
+ case ITEM_MODEL_SETUP_LABEL:
+ lcdDrawTextAlignedLeft(y, "Function Switches");
+ break;
+
+ case ITEM_MODEL_SETUP_SW1:
+ case ITEM_MODEL_SETUP_SW2:
+ case ITEM_MODEL_SETUP_SW3:
+ case ITEM_MODEL_SETUP_SW4:
+ case ITEM_MODEL_SETUP_SW5:
+ case ITEM_MODEL_SETUP_SW6:
+ {
+ int index = k - ITEM_MODEL_SETUP_SW1;
+ int config = FSWITCH_CONFIG(index);
+ lcdDrawTextAtIndex(INDENT_WIDTH, y, STR_VSRCRAW, MIXSRC_FIRST_SWITCH + NUM_REGULAR_SWITCHES - MIXSRC_Rud + index + 1, menuHorizontalPosition < 0 ? attr : 0);
+ if (ZEXIST(g_model.switchNames[index]) || (attr && s_editMode > 0 && menuHorizontalPosition == 0))
+ editName(35, y, g_model.switchNames[index], LEN_SWITCH_NAME, event, true, menuHorizontalPosition == 0 ? attr : 0, old_editMode);
+ else
+ lcdDrawMMM(35, y, menuHorizontalPosition == 0 ? attr : 0);
+ config = editChoice(30 + 5*FW, y, "", STR_SWTYPES, config, SWITCH_NONE, SWITCH_2POS, menuHorizontalPosition == 1 ? attr : 0, event);
+ if (attr && checkIncDec_Ret) {
+ swconfig_t mask = (swconfig_t)0x03 << (2*index);
+ g_model.functionSwitchConfig = (g_model.functionSwitchConfig & ~mask) | ((swconfig_t(config) & 0x03) << (2*index));
+ }
+
+ config = FSWITCH_GROUP(index);
+ config = editChoice(30 + 15*FW, y, "", STR_FSGROUPS, config, 0, 3, menuHorizontalPosition == 2 ? attr : 0, event);
+ if (attr && checkIncDec_Ret && menuHorizontalPosition == 2) {
+ swconfig_t mask = (swconfig_t) 0x03 << (2 * index);
+ g_model.functionSwitchGroup = (g_model.functionSwitchGroup & ~mask) | ((swconfig_t(config) & 0x03) << (2 * index));
+ }
+ break;
+ }
+
+ case ITEM_MODEL_SETUP_FS_STARTUP:
+ {
+ char c;
+ lcdDrawText(0, y, INDENT "Start", menuHorizontalPosition < 0 ? attr : 0);
+ for (uint8_t i = 0; i < NUM_FUNCTIONS_SWITCHES; i++) {
+ uint8_t startPos = (g_model.functionSwitchStartConfig >> 2 * i) & 0x03;
+ c = "\300\301="[(g_model.functionSwitchStartConfig >> 2 * i) & 0x03];
+ lcdDrawNumber(MODEL_SETUP_2ND_COLUMN - (2 + FW) + i * 2 * FW, y, i + 1, 0);
+ lcdDrawChar(lcdNextPos, y, c, attr && (menuHorizontalPosition == i) ? (s_editMode ? INVERS + BLINK : INVERS) : 0);
+ if (attr && menuHorizontalPosition == i) {
+ CHECK_INCDEC_MODELVAR(event, startPos, 0, 2);
+ }
+ if (attr && checkIncDec_Ret) {
+ swconfig_t mask = (swconfig_t)0x03 << (2*i);
+ g_model.functionSwitchStartConfig = (g_model.functionSwitchStartConfig & ~mask) | ((swconfig_t(startPos) & 0x03) << (2*i));
+ storageDirty(EE_MODEL);
+ }
+ }
+ break;
+ }
+#endif
case ITEM_MODEL_SETUP_EXTENDED_LIMITS:
g_model.extendedLimits = editCheckBox(g_model.extendedLimits, MODEL_SETUP_2ND_COLUMN, y, STR_ELIMITS, attr, event);
break;
@@ -724,7 +796,7 @@ void menuModelSetup(event_t event)
}
int current = 0;
- for (int i = 0; i < NUM_SWITCHES; i++) {
+ for (int i = 0; i < NUM_SWITCHES - NUM_FUNCTIONS_SWITCHES; i++) {
if (SWITCH_WARNING_ALLOWED(i)) {
div_t qr = div(current, MAX_SWITCH_PER_LINE);
if (!READ_ONLY() && event == EVT_KEY_BREAK(KEY_ENTER) && attr &&
diff --git a/radio/src/gui/128x64/radio_diagkeys.cpp b/radio/src/gui/128x64/radio_diagkeys.cpp
index 02f9b4b86..2452b900b 100644
--- a/radio/src/gui/128x64/radio_diagkeys.cpp
+++ b/radio/src/gui/128x64/radio_diagkeys.cpp
@@ -41,7 +41,7 @@ void menuRadioDiagKeys(event_t event)
lcdDrawText(14*FW, MENU_HEADER_HEIGHT + 1, STR_VTRIM);
- for (uint8_t i=0; i<9; i++) {
+ for (uint8_t i=0; i<10; i++) {
coord_t y;
if (i < NUM_TRIMS_KEYS) {
@@ -69,10 +69,19 @@ void menuRadioDiagKeys(event_t event)
drawSwitch(8*FW, y, i+1, 0);
displaySwitchState(11*FW+2, y, i);
}
+#elif (NUM_SWITCHES > 6)
+ if (i < NUM_SWITCHES) {
+ if (SWITCH_EXISTS(i)) {
+ y = (i > 4) ? FH*(i-4) : MENU_HEADER_HEIGHT + FH*i;
+ getvalue_t val = getValue(MIXSRC_FIRST_SWITCH+i);
+ getvalue_t sw = ((val < 0) ? 3*i+1 : ((val == 0) ? 3*i+2 : 3*i+3));
+ drawSwitch(i > 4 ? 11*FW-5: 8*FW-9, y, sw, 0, false);
+ }
+ }
#else
if (i < NUM_SWITCHES) {
if (SWITCH_EXISTS(i)) {
- y = (NUM_SWITCHES > 6 ? 0 : MENU_HEADER_HEIGHT) + FH*i;
+ y = (NUM_SWITCHES - NUM_FUNCTIONS_SWITCHES > 6 ? 0 : MENU_HEADER_HEIGHT) + FH*i;
getvalue_t val = getValue(MIXSRC_FIRST_SWITCH+i);
getvalue_t sw = ((val < 0) ? 3*i+1 : ((val == 0) ? 3*i+2 : 3*i+3));
drawSwitch(8*FW+4, y, sw, 0);
@@ -81,8 +90,18 @@ void menuRadioDiagKeys(event_t event)
#endif
}
+#if defined(FUNCTION_SWITCHES) && defined(DEBUG)
+ lcdDrawText(LCD_W / 2 , LCD_H - 2 * FH, "Phys");
+ lcdDrawText(LCD_W / 2 , LCD_H - 1 * FH, "Log");
+
+ for (uint8_t i = 0; i < NUM_FUNCTIONS_SWITCHES; i++) {
+ lcdDrawNumber(LCD_W / 2 + 20 + (i + 1) * FW , LCD_H - 2 * FH, getFSPhysicalState(i));
+ lcdDrawNumber(LCD_W / 2 + 20 + (i + 1) * FW , LCD_H - 1 * FH, getFSLogicalState(i));
+ }
+#endif
+
#if defined(ROTARY_ENCODER_NAVIGATION)
- coord_t y = MENU_HEADER_HEIGHT + 1 + FH*KEY_COUNT;
+ coord_t y = LCD_H - FH - 1;
lcdDrawText(0, y, STR_ROTARY_ENCODER);
lcdDrawNumber(5*FW+FWNUM+2, y, rotencValue / ROTARY_ENCODER_GRANULARITY, RIGHT);
#endif
diff --git a/radio/src/gui/128x64/view_main.cpp b/radio/src/gui/128x64/view_main.cpp
index 471dc7168..35039c4a7 100644
--- a/radio/src/gui/128x64/view_main.cpp
+++ b/radio/src/gui/128x64/view_main.cpp
@@ -660,7 +660,7 @@ void menuMainView(event_t event)
}
}
#elif defined(PCBTARANIS)
- uint8_t switches = min(NUM_SWITCHES, 6);
+ uint8_t switches = min(NUM_SWITCHES- NUM_FUNCTIONS_SWITCHES, 6);
for (int i = 0; i < switches; ++i) {
if (SWITCH_EXISTS(i)) {
uint8_t x = 2 * FW - 2, y = 4 * FH + i * FH + 1;
diff --git a/radio/src/gui/common/stdlcd/radio_hardware.cpp b/radio/src/gui/common/stdlcd/radio_hardware.cpp
index 48bb47246..67de15c46 100644
--- a/radio/src/gui/common/stdlcd/radio_hardware.cpp
+++ b/radio/src/gui/common/stdlcd/radio_hardware.cpp
@@ -55,6 +55,7 @@ enum {
ITEM_RADIO_HARDWARE_SB,
ITEM_RADIO_HARDWARE_SC,
ITEM_RADIO_HARDWARE_SD,
+#if !defined(RADIO_TPRO)
#if defined(HARDWARE_SWITCH_E)
ITEM_RADIO_HARDWARE_SE,
#endif
@@ -73,6 +74,7 @@ enum {
#if defined(HARDWARE_SWITCH_J)
ITEM_RADIO_HARDWARE_SJ,
#endif
+#endif
#if defined(HARDWARE_SWITCH_K)
ITEM_RADIO_HARDWARE_SK,
ITEM_RADIO_HARDWARE_SL,
@@ -154,6 +156,8 @@ enum {
#if defined(PCBX9E)
#define SWITCHES_ROWS NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1
+#elif defined(RADIO_TPRO)
+ #define SWITCHES_ROWS NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1
#elif defined(RADIO_T12)
#define SWITCHES_ROWS NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|HIDDEN_ROW, NAVIGATION_LINE_BY_LINE|HIDDEN_ROW
#elif NUM_SWITCHES == 9
@@ -432,6 +436,7 @@ void menuRadioHardware(event_t event)
case ITEM_RADIO_HARDWARE_SB:
case ITEM_RADIO_HARDWARE_SC:
case ITEM_RADIO_HARDWARE_SD:
+#if !defined(RADIO_TPRO)
#if defined(HARDWARE_SWITCH_E)
case ITEM_RADIO_HARDWARE_SE:
#endif
@@ -450,6 +455,7 @@ void menuRadioHardware(event_t event)
#if defined(HARDWARE_SWITCH_J)
case ITEM_RADIO_HARDWARE_SJ:
#endif
+#endif
#if defined(HARDWARE_SWITCH_K)
case ITEM_RADIO_HARDWARE_SK:
case ITEM_RADIO_HARDWARE_SL:
diff --git a/radio/src/hal/adc_driver.cpp b/radio/src/hal/adc_driver.cpp
index a7e5dc6c9..a02c3a78b 100644
--- a/radio/src/hal/adc_driver.cpp
+++ b/radio/src/hal/adc_driver.cpp
@@ -59,6 +59,8 @@ const etx_hal_adc_driver_t* etx_hal_adc_driver = nullptr;
const int8_t adcDirection[NUM_ANALOGS] = {-1,1,-1,1, -1,-1, 1, 1};
#elif defined(RADIO_ZORRO)
const int8_t adcDirection[NUM_ANALOGS] = {-1, 1, 1, -1, -1, 1, 1, 1};
+#elif defined(RADIO_TPRO)
+ const int8_t adcDirection[NUM_ANALOGS] = {1,-1,1,-1, 1,1, 1, 1};
#elif defined(PCBX7)
const int8_t adcDirection[NUM_ANALOGS] = {-1,1,-1,1, 1,1, 1, 1};
#elif defined(PCBX9LITE)
diff --git a/radio/src/lua/CMakeLists.txt b/radio/src/lua/CMakeLists.txt
index 8a75d379c..685778108 100644
--- a/radio/src/lua/CMakeLists.txt
+++ b/radio/src/lua/CMakeLists.txt
@@ -30,6 +30,7 @@ if(PYTHONINTERP_FOUND)
add_lua_export_target(x12s ${LUA_INCLUDES} -DPCBHORUS -DPCBX12S)
add_lua_export_target(t12 ${LUA_INCLUDES} -DPCBTARANIS -DPCBX7 -DRADIO_T12)
add_lua_export_target(tlite ${LUA_INCLUDES} -DPCBTARANIS -DPCBX7 -DRADIO_TLITE)
+ add_lua_export_target(tpro ${LUA_INCLUDES} -DPCBTARANIS -DPCBX7 -DRADIO_TPRO)
add_lua_export_target(tx12 ${LUA_INCLUDES} -DPCBTARANIS -DPCBX7 -DRADIO_TX12)
add_lua_export_target(zorro ${LUA_INCLUDES} -DPCBTARANIS -DPCBX7 -DRADIO_ZORRO)
add_lua_export_target(t8 ${LUA_INCLUDES} -DPCBTARANIS -DPCBX7 -DRADIO_T8)
diff --git a/radio/src/lua/api_general.cpp b/radio/src/lua/api_general.cpp
index 8ac29f153..354cdd1c8 100644
--- a/radio/src/lua/api_general.cpp
+++ b/radio/src/lua/api_general.cpp
@@ -50,6 +50,8 @@
#include "lua/lua_exports_t12.inc"
#elif defined(RADIO_TLITE)
#include "lua/lua_exports_tlite.inc"
+#elif defined(RADIO_TPRO)
+ #include "lua/lua_exports_tpro.inc"
#elif defined(RADIO_TX12)
#include "lua/lua_exports_tx12.inc"
#elif defined(RADIO_ZORRO)
diff --git a/radio/src/mixer.cpp b/radio/src/mixer.cpp
index 92214f605..cdb90e6df 100644
--- a/radio/src/mixer.cpp
+++ b/radio/src/mixer.cpp
@@ -348,6 +348,20 @@ getvalue_t getValue(mixsrc_t i)
// TODO : find a better define
#if defined(PCBFRSKY) || defined(PCBFLYSKY)
+#if defined(FUNCTION_SWITCHES)
+ else if (i >= MIXSRC_FIRST_SWITCH && i <= MIXSRC_LAST_REGULAR_SWITCH) {
+ mixsrc_t sw = i - MIXSRC_FIRST_SWITCH;
+ if (SWITCH_EXISTS(sw)) {
+ return (switchState(3*sw) ? -1024 : (IS_CONFIG_3POS(sw) && switchState(3*sw+1) ? 0 : 1024));
+ }
+ else {
+ return 0;
+ }
+ }
+ else if (i >= MIXSRC_FIRST_FS_SWITCH && i <= MIXSRC_LAST_SWITCH) {
+ return getFSLogicalState(i - MIXSRC_FIRST_SWITCH - NUM_REGULAR_SWITCHES) ? +1024 : -1024;
+ }
+#else
else if (i >= MIXSRC_FIRST_SWITCH && i <= MIXSRC_LAST_SWITCH) {
mixsrc_t sw = i - MIXSRC_FIRST_SWITCH;
if (SWITCH_EXISTS(sw)) {
@@ -357,6 +371,7 @@ getvalue_t getValue(mixsrc_t i)
return 0;
}
}
+#endif
#else
else if (i == MIXSRC_3POS) {
return (getSwitch(SW_ID0+1) ? -1024 : (getSwitch(SW_ID1+1) ? 0 : 1024));
diff --git a/radio/src/model_init.cpp b/radio/src/model_init.cpp
index 492ccb190..ce3b3cf7b 100644
--- a/radio/src/model_init.cpp
+++ b/radio/src/model_init.cpp
@@ -114,6 +114,13 @@ void applyDefaultTemplate()
setDefaultModelRegistrationID();
+#if defined(FUNCTION_SWITCHES)
+ g_model.functionSwitchConfig = DEFAULT_FS_CONFIG;
+ g_model.functionSwitchGroup = DEFAULT_FS_GROUPS;
+ g_model.functionSwitchStartConfig = DEFAULT_FS_STARTUP_CONFIG;
+ g_model.functionSwitchLogicalState = 0;
+#endif
+
#if defined(COLORLCD)
//TODO: not sure yet we need it here
loadDefaultLayout();
diff --git a/radio/src/myeeprom.h b/radio/src/myeeprom.h
index 958e529a3..a8117e792 100644
--- a/radio/src/myeeprom.h
+++ b/radio/src/myeeprom.h
@@ -83,9 +83,18 @@
#if defined(PCBFRSKY) || defined(PCBNV14)
#define SWITCH_CONFIG(x) (bfGet(g_eeGeneral.switchConfig, 2*(x), 2))
+#if defined(FUNCTION_SWITCHES)
+ #define FSWITCH_CONFIG(x) (bfGet(g_model.functionSwitchConfig, 2*(x), 2))
+ #define FSWITCH_GROUP(x) (bfGet(g_model.functionSwitchGroup, 2*(x), 2))
+ #define IS_SWITCH_FS(x) (x >= NUM_REGULAR_SWITCHES)
+ #define SWITCH_EXISTS(x) (IS_SWITCH_FS(x) ? true : (FSWITCH_CONFIG(x) != SWITCH_NONE))
+ #define IS_CONFIG_3POS(x) (IS_SWITCH_FS(x) ? (FSWITCH_CONFIG(x - NUM_REGULAR_SWITCHES) == SWITCH_3POS) : (SWITCH_CONFIG(x) == SWITCH_3POS))
+ #define IS_CONFIG_TOGGLE(x) (IS_SWITCH_FS(x) ? (FSWITCH_CONFIG(x - NUM_REGULAR_SWITCHES) == SWITCH_TOGGLE) : (SWITCH_CONFIG(x) == SWITCH_TOGGLE))
+#else
#define SWITCH_EXISTS(x) (SWITCH_CONFIG(x) != SWITCH_NONE)
#define IS_CONFIG_3POS(x) (SWITCH_CONFIG(x) == SWITCH_3POS)
#define IS_CONFIG_TOGGLE(x) (SWITCH_CONFIG(x) == SWITCH_TOGGLE)
+#endif
#define SWITCH_WARNING_ALLOWED(x) (SWITCH_EXISTS(x) && !IS_CONFIG_TOGGLE(x))
#else
#define IS_CONFIG_3POS(x) IS_3POS(x)
diff --git a/radio/src/opentx.cpp b/radio/src/opentx.cpp
index f358af4a4..16895d2c6 100644
--- a/radio/src/opentx.cpp
+++ b/radio/src/opentx.cpp
@@ -171,6 +171,10 @@ void per10ms()
readKeysAndTrims();
+#if defined(FUNCTION_SWITCHES)
+ evalFunctionSwitches();
+#endif
+
#if defined(ROTARY_ENCODER_NAVIGATION)
if (IS_ROTARY_ENCODER_NAVIGATION_ENABLE()) {
static rotenc_t rePreviousValue;
@@ -372,7 +376,6 @@ uint16_t evalChkSum()
return sum;
}
-
bool isInputRecursive(int index)
{
ExpoData * line = expoAddress(0);
@@ -1414,6 +1417,12 @@ void opentxStart(const uint8_t startOptions = OPENTX_START_DEFAULT_ARGS)
ALERT(STR_TEST_WARNING, TR_TEST_NOTSAFE, AU_ERROR);
#endif
+#if defined(FUNCTION_SWITCHES)
+ if (!UNEXPECTED_SHUTDOWN()) {
+ setFSStartupPosition();
+ }
+#endif
+
#if defined(GUI)
if (calibration_needed) {
#if defined(LIBOPENUI)
diff --git a/radio/src/opentx_constants.h b/radio/src/opentx_constants.h
index 4b6559a65..bcb934df5 100644
--- a/radio/src/opentx_constants.h
+++ b/radio/src/opentx_constants.h
@@ -41,6 +41,12 @@ enum SliderConfig {
SLIDER_WITH_DETENT,
};
+enum fsStartPositionType {
+ FS_START_UP,
+ FS_START_DOWN,
+ FS_START_PREVIOUS
+};
+
enum CalibrationState {
CALIB_START,
CALIB_SET_MIDPOINT,
diff --git a/radio/src/sdcard.h b/radio/src/sdcard.h
index 2ac4f5dc6..43896b690 100644
--- a/radio/src/sdcard.h
+++ b/radio/src/sdcard.h
@@ -152,6 +152,8 @@ const char * getBasename(const char * path);
#define OTX_FOURCC 0x3D78746F // otx for Jumper T12
#elif defined(RADIO_TLITE)
#define OTX_FOURCC 0x4278746F // otx for Jumper TLite
+#elif defined(RADIO_TPRO)
+ #define OTX_FOURCC 0x4678746F // otx for Jumper TPro
#elif defined(RADIO_TX12)
#define OTX_FOURCC 0x4178746F // otx for Radiomaster TX12
#elif defined(RADIO_ZORRO)
diff --git a/radio/src/simu.cpp b/radio/src/simu.cpp
index 53410cb2e..e88309434 100644
--- a/radio/src/simu.cpp
+++ b/radio/src/simu.cpp
@@ -445,7 +445,14 @@ void OpenTxSim::updateKeysAndSwitches(bool start)
SWITCH_KEY(C, 2, 3);
SWITCH_KEY(D, 3, 3);
- #if defined(HARDWARE_SWITCH_G) && defined(HARDWARE_SWITCH_H)
+ #if defined(RADIO_TPRO)
+ SWITCH_KEY(1, 4, 2);
+ SWITCH_KEY(2, 5, 2);
+ SWITCH_KEY(3, 6, 2);
+ SWITCH_KEY(4, 7, 2);
+ SWITCH_KEY(5, 8, 2);
+ SWITCH_KEY(6, 9, 2);
+ #elif defined(HARDWARE_SWITCH_G) && defined(HARDWARE_SWITCH_H)
SWITCH_KEY(E, 4, 3);
SWITCH_KEY(F, 5, 2);
SWITCH_KEY(G, 6, 3);
diff --git a/radio/src/storage/conversions/CMakeLists.txt b/radio/src/storage/conversions/CMakeLists.txt
index 601482530..75ec49ad2 100644
--- a/radio/src/storage/conversions/CMakeLists.txt
+++ b/radio/src/storage/conversions/CMakeLists.txt
@@ -1,8 +1,11 @@
set(STORAGE_CONVERSIONS 219)
-if(PCB STREQUAL X7 AND PCBREV STREQUAL ZORRO)
- set(STORAGE_CONVERSIONS 221)
+if(PCB STREQUAL X7)
+ if(PCBREV STREQUAL ZORRO OR PCBREV STREQUAL TPRO)
+ set(STORAGE_CONVERSIONS 221)
+ endif()
endif()
+message("Storage conversion: ${STORAGE_CONVERSIONS}")
if(STORAGE_CONVERSIONS)
add_definitions(-DSTORAGE_CONVERSIONS=${STORAGE_CONVERSIONS})
diff --git a/radio/src/storage/conversions/conversions_219_220.cpp b/radio/src/storage/conversions/conversions_219_220.cpp
index d65d528af..efbaaa7c7 100644
--- a/radio/src/storage/conversions/conversions_219_220.cpp
+++ b/radio/src/storage/conversions/conversions_219_220.cpp
@@ -35,6 +35,8 @@
#include
#endif
+#if STORAGE_CONVERSIONS < 220
+
//
// Summary of all changes between 219 & 220
//
@@ -349,3 +351,5 @@ const char* convertRadioData_219_to_220()
return nullptr;
}
#endif
+
+#endif
diff --git a/radio/src/storage/conversions/conversions_220_221.cpp b/radio/src/storage/conversions/conversions_220_221.cpp
index 634f8b960..7a1981c82 100644
--- a/radio/src/storage/conversions/conversions_220_221.cpp
+++ b/radio/src/storage/conversions/conversions_220_221.cpp
@@ -44,6 +44,8 @@ namespace yaml_conv_220 {
const YamlNode* get_partialmodel_nodes();
};
+#if STORAGE_CONVERSIONS < 221
+
#if defined(STORAGE_MODELSLIST)
void patchFilenameToYaml(char* str);
@@ -184,3 +186,5 @@ const char* convertRadioData_220_to_221()
}
#endif
+
+#endif
diff --git a/radio/src/storage/conversions/yaml/dataconstants_220.h b/radio/src/storage/conversions/yaml/dataconstants_220.h
index aefde174c..a520dd2d2 100644
--- a/radio/src/storage/conversions/yaml/dataconstants_220.h
+++ b/radio/src/storage/conversions/yaml/dataconstants_220.h
@@ -92,6 +92,8 @@
#if defined(PCBXLITES) || defined(PCBXLITE)
#define STORAGE_NUM_SWITCHES 6
+#elif defined(RADIO_TPRO)
+#define STORAGE_NUM_SWITCHES 10
#elif defined(RADIO_TLITE) || defined(RADIO_FAMILY_JUMPER_T12) || defined(RADIO_TX12) || defined(RADIO_T8) || defined(PCBX7ACCESS) || defined(PCBX7)
#define STORAGE_NUM_SWITCHES 8
#elif defined(PCBX9LITES)
diff --git a/radio/src/storage/conversions/yaml/datastructs_220.h b/radio/src/storage/conversions/yaml/datastructs_220.h
index 2e5392317..b99edaf6e 100644
--- a/radio/src/storage/conversions/yaml/datastructs_220.h
+++ b/radio/src/storage/conversions/yaml/datastructs_220.h
@@ -999,6 +999,9 @@ static inline void check_struct()
#elif defined(PCBXLITE)
CHKSIZE(RadioData, 859);
CHKSIZE(ModelData, 6157);
+#elif defined(RADIO_TPRO)
+ CHKSIZE(RadioData, 860);
+ CHKSIZE(ModelData, 6157);
#elif defined(PCBX7)
CHKSIZE(RadioData, 865);
CHKSIZE(ModelData, 6157);
diff --git a/radio/src/strhelpers.cpp b/radio/src/strhelpers.cpp
index 291e109ae..885201f86 100644
--- a/radio/src/strhelpers.cpp
+++ b/radio/src/strhelpers.cpp
@@ -444,20 +444,20 @@ int getRawSwitchIdx(char sw)
char getRawSwitchFromIdx(int idx)
{
-#if defined(PCBX7) && !defined(RADIO_TX12) && !defined(RADIO_ZORRO)
+#if defined(PCBX7) && !defined(RADIO_TX12) && !defined(RADIO_ZORRO) && !defined(RADIO_TPRO)
if (idx >= 5)
return 'H' + idx - 5;
else if (idx == 4)
-#if defined(RADIO_T12)
+ #if defined(RADIO_T12)
return 'G';
-#else
+ #else
return 'F';
-#endif
+ #endif
else
return 'A' + idx;
#else
return 'A' + idx;
-#endif
+#endif
}
char *getSwitchName(char *dest, swsrc_t idx)
@@ -467,6 +467,13 @@ char *getSwitchName(char *dest, swsrc_t idx)
dest =
strAppend(dest, g_eeGeneral.switchNames[swinfo.quot], LEN_SWITCH_NAME);
} else {
+#if defined(FUNCTIONS_SWITCHES)
+ if (swinfo.quot >= NUM_REGULAR_SWITCHES) {
+ *dest++ = 'W';
+ *dest++ = '1' + swinfo.quot - 4;
+ return dest;
+ }
+#endif
*dest++ = 'S';
*dest++ = getRawSwitchFromIdx(swinfo.quot);
}
diff --git a/radio/src/switches.cpp b/radio/src/switches.cpp
index 5d77bb168..3d9ccad3f 100644
--- a/radio/src/switches.cpp
+++ b/radio/src/switches.cpp
@@ -70,6 +70,85 @@ uint8_t potsPos[NUM_XPOTS];
#define SWITCH_POSITION(sw) (switchesPos & ((MASK_CFN_TYPE)1<<(sw)))
#define POT_POSITION(sw) ((potsPos[(sw)/XPOTS_MULTIPOS_COUNT] & 0x0f) == ((sw) % XPOTS_MULTIPOS_COUNT))
+#if defined(FUNCTION_SWITCHES)
+// Non pushed : SWSRC_Sx0 = -1024 = Sx(up) = state 0
+// Pushed : SWSRC_Sx2 = +1024 = Sx(down) = state 1
+
+uint8_t fsPreviousState = 0;
+
+void setFSStartupPosition()
+{
+ for (uint8_t i = 0; i < NUM_FUNCTIONS_SWITCHES; i++) {
+ uint8_t startPos = (g_model.functionSwitchStartConfig >> 2 * i) & 0x03;
+ switch(startPos) {
+ case FS_START_DOWN:
+ g_model.functionSwitchLogicalState &= ~(1 << i); // clear state
+ break;
+
+ case FS_START_UP:
+ g_model.functionSwitchLogicalState |= 1 << i;
+ break;
+
+ case FS_START_PREVIOUS:
+ default:
+ // Do nothing, use existing g_model.functionSwitchLogicalState value
+ break;
+ }
+ }
+}
+
+uint8_t getFSLogicalState(uint8_t index)
+{
+ return (uint8_t )(bfSingleBitGet(g_model.functionSwitchLogicalState, index) >> (index));
+}
+
+uint8_t getFSPhysicalState(uint8_t index)
+{
+ return switchState(((index + NUM_REGULAR_SWITCHES) * 3) + 2) ? 1 : 0;
+}
+
+uint8_t getFSPreviousPhysicalState(uint8_t index)
+{
+ return (uint8_t )(bfSingleBitGet(fsPreviousState, index) >> (index));
+}
+
+void evalFunctionSwitches()
+{
+ for (uint8_t i = 0; i < NUM_FUNCTIONS_SWITCHES; i++) {
+ if (FSWITCH_CONFIG(i) == SWITCH_NONE) {
+ fsLedOff(i);
+ continue;
+ }
+
+ uint8_t physicalState = getFSPhysicalState(i);
+ if (physicalState != getFSPreviousPhysicalState(i)) { // FS was moved
+ if (FSWITCH_CONFIG(i) == SWITCH_2POS && physicalState == 1) {
+ g_model.functionSwitchLogicalState ^= 1 << i; // Toggle bit
+ }
+ else if (FSWITCH_CONFIG(i) == SWITCH_TOGGLE) {
+ g_model.functionSwitchLogicalState ^= (physicalState ^ g_model.functionSwitchLogicalState) & (1 << i); // Set bit to switch value
+ }
+ if (FSWITCH_GROUP(i) && physicalState == 1) { // switch is in a group, other in group need to be turned off
+ for (uint8_t j = 0; j < NUM_FUNCTIONS_SWITCHES; j++) {
+ if (i == j)
+ continue;
+ if (FSWITCH_GROUP(j) == FSWITCH_GROUP(i)) {
+ g_model.functionSwitchLogicalState &= ~(1 << j); // clear state
+ }
+ }
+ }
+ fsPreviousState ^= 1 << i; // Toggle state
+ storageDirty(EE_MODEL);
+ }
+
+ if (getFSLogicalState(i))
+ fsLedOn(i);
+ else
+ fsLedOff(i);
+ }
+}
+#endif
+
div_t switchInfo(int switchPosition)
{
return div(switchPosition-SWSRC_FIRST_SWITCH, 3);
@@ -133,6 +212,11 @@ void getSwitchesPosition(bool startup)
CHECK_2POS(SW_SA);
CHECK_3POS(0, SW_SB);
CHECK_3POS(1, SW_SC);
+#elif defined(RADIO_TPRO)
+ CHECK_3POS(0, SW_SA);
+ CHECK_3POS(1, SW_SB);
+ CHECK_2POS(SW_SC);
+ CHECK_2POS(SW_SD);
#else
CHECK_3POS(0, SW_SA);
CHECK_3POS(1, SW_SB);
@@ -165,6 +249,13 @@ void getSwitchesPosition(bool startup)
CHECK_2POS(SW_SD);
CHECK_3POS(2, SW_SE);
CHECK_3POS(3, SW_SF);
+#elif defined(RADIO_TPRO)
+ CHECK_2POS(SW_SE);
+ CHECK_2POS(SW_SF);
+ CHECK_2POS(SW_SG);
+ CHECK_2POS(SW_SH);
+ CHECK_2POS(SW_SI);
+ CHECK_2POS(SW_SJ);
#elif defined(PCBX7)
CHECK_3POS(3, SW_SD);
#if defined(RADIO_T12)
@@ -456,8 +547,8 @@ bool getSwitch(swsrc_t swtch, uint8_t flags)
result = latencyToggleSwitch;
}
#endif
- else if (cs_idx <= SWSRC_LAST_SWITCH) {
-#if defined(PCBFRSKY)
+ else if (cs_idx <= (SWSRC_LAST_SWITCH - 3 * NUM_FUNCTIONS_SWITCHES)) {
+#if defined(PCBFRSKY) || defined(PCBFLYSKY)
if (flags & GETSWITCH_MIDPOS_DELAY)
result = SWITCH_POSITION(cs_idx-SWSRC_FIRST_SWITCH);
else
@@ -465,8 +556,14 @@ bool getSwitch(swsrc_t swtch, uint8_t flags)
#else
result = switchState(cs_idx-SWSRC_FIRST_SWITCH);
#endif
-
}
+#if defined(FUNCTION_SWITCHES)
+ else if (cs_idx <= SWSRC_LAST_SWITCH) {
+ div_t qr = div(cs_idx - 3 * NUM_FUNCTIONS_SWITCHES, 3);
+ auto value = getFSLogicalState(qr.quot + 1);
+ result = qr.rem == -2 ? 1 - value : value;
+ }
+#endif
#if NUM_XPOTS > 0
else if (cs_idx <= SWSRC_LAST_MULTIPOS_SWITCH) {
result = POT_POSITION(cs_idx-SWSRC_FIRST_MULTIPOS_SWITCH);
@@ -526,13 +623,14 @@ void evalLogicalSwitches(bool isCurrentFlightmode)
}
swarnstate_t switches_states = 0;
+uint8_t fsswitches_states = 0;
swsrc_t getMovedSwitch()
{
static tmr10ms_t s_move_last_time = 0;
swsrc_t result = 0;
// Switches
- for (int i = 0; i < NUM_SWITCHES; i++) {
+ for (int i = 0; i < NUM_SWITCHES - NUM_FUNCTIONS_SWITCHES; i++) {
if (SWITCH_EXISTS(i)) {
swarnstate_t mask = ((swarnstate_t) 0x07 << (i * 3));
uint8_t prev = (switches_states & mask) >> (i * 3);
@@ -544,6 +642,20 @@ swsrc_t getMovedSwitch()
}
}
}
+
+#if defined(FUNCTION_SWITCHES)
+ for (int i = 0; i < NUM_FUNCTIONS_SWITCHES; i++) {
+ if (FSWITCH_CONFIG(i) != SWITCH_NONE) {
+ auto prev = (uint8_t )(bfSingleBitGet(fsswitches_states, i) >> (i));
+ uint8_t next = getFSLogicalState(i);
+ if (prev != next) {
+ switches_states ^= (-next ^ switches_states) & (1 << i);
+ result = 2 + (3 * (i + NUM_REGULAR_SWITCHES)) + next;
+ }
+ }
+ }
+#endif
+
// Multipos
for (int i = 0; i < NUM_XPOTS; i++) {
if (IS_POT_MULTIPOS(POT1 + i)) {
diff --git a/radio/src/targets/horus/board.h b/radio/src/targets/horus/board.h
index f9e1873f3..7450b124a 100644
--- a/radio/src/targets/horus/board.h
+++ b/radio/src/targets/horus/board.h
@@ -304,6 +304,10 @@ enum EnumSwitchesPositions
#define STORAGE_NUM_SWITCHES_POSITIONS (STORAGE_NUM_SWITCHES * 3)
+#if !defined(NUM_FUNCTIONS_SWITCHES)
+#define NUM_FUNCTIONS_SWITCHES 0
+#endif
+
void keysInit();
uint32_t switchState(uint8_t index);
uint32_t readKeys();
diff --git a/radio/src/targets/nv14/board.h b/radio/src/targets/nv14/board.h
index c70100315..0677593b3 100644
--- a/radio/src/targets/nv14/board.h
+++ b/radio/src/targets/nv14/board.h
@@ -235,6 +235,10 @@ enum EnumSwitchesPositions
#define STORAGE_NUM_SWITCHES_POSITIONS (STORAGE_NUM_SWITCHES * 3)
+#if !defined(NUM_FUNCTIONS_SWITCHES)
+#define NUM_FUNCTIONS_SWITCHES 0
+#endif
+
void monitorInit();
void keysInit();
uint8_t keyState(uint8_t index);
diff --git a/radio/src/targets/sky9x/board.h b/radio/src/targets/sky9x/board.h
index e12be5f6d..7ac83b00b 100644
--- a/radio/src/targets/sky9x/board.h
+++ b/radio/src/targets/sky9x/board.h
@@ -57,6 +57,10 @@ void rotaryEncoderEnd();
#define STORAGE_NUM_SWITCHES NUM_SWITCHES
#define NUM_SWITCHES_POSITIONS 9
+#if !defined(NUM_FUNCTIONS_SWITCHES)
+#define NUM_FUNCTIONS_SWITCHES 0
+#endif
+
enum EnumKeys
{
KEY_MENU,
diff --git a/radio/src/targets/taranis/CMakeLists.txt b/radio/src/targets/taranis/CMakeLists.txt
index 15ff14c05..599d77188 100644
--- a/radio/src/targets/taranis/CMakeLists.txt
+++ b/radio/src/targets/taranis/CMakeLists.txt
@@ -138,6 +138,20 @@ elseif(PCB STREQUAL X7)
add_definitions(-DRADIO_FAMILY_JUMPER_T12)
add_definitions(-DEEPROM_VARIANT=0x4001)
add_definitions(-DMANUFACTURER_JUMPER)
+ elseif(PCBREV STREQUAL TPRO)
+ set(DEFAULT_INTERNAL_MODULE MULTIMODULE CACHE STRING "Default internal module")
+ set(INTERNAL_MODULE_SERIAL YES)
+ set(FLAVOUR tpro)
+ set(NAVIGATION_TYPE x7)
+ set(CPU_TYPE STM32F2)
+ set(ROTARY_ENCODER YES)
+ set(CPU_TYPE_FULL STM32F205xE) # for size report
+ set(LINKER_SCRIPT targets/taranis/stm32f2_flash.ld)
+ set(LUA_EXPORT lua_export_tpro)
+ add_definitions(-DFUNCTION_SWITCHES)
+ add_definitions(-DRADIO_TPRO)
+ add_definitions(-DEEPROM_VARIANT=0x4005)
+ add_definitions(-DMANUFACTURER_JUMPER)
elseif(PCBREV STREQUAL TLITE)
set(DEFAULT_INTERNAL_MODULE MULTIMODULE CACHE STRING "Default internal module")
set(INTERNAL_MODULE_SERIAL YES)
diff --git a/radio/src/targets/taranis/board.h b/radio/src/targets/taranis/board.h
index 01df37927..2b7c918f8 100644
--- a/radio/src/targets/taranis/board.h
+++ b/radio/src/targets/taranis/board.h
@@ -38,7 +38,7 @@ void rotaryEncoderInit();
void rotaryEncoderCheck();
#endif
-#if defined(RADIO_ZORRO)
+#if defined(RADIO_ZORRO) || defined(RADIO_TPRO)
#define ROTARY_ENCODER_INVERT
#endif
@@ -330,7 +330,16 @@ enum EnumSwitches
SW_SE,
SW_SF,
SW_SG,
- SW_SH
+ SW_SH,
+ SW_SI,
+ SW_SJ,
+ SW_SK,
+ SW_SL,
+ SW_SM,
+ SW_SO,
+ SW_SP,
+ SW_SQ,
+ SW_SR,
};
#if defined(RADIO_TX12)
#define IS_3POS(x) ((x) != SW_SA && (x) != SW_SD)
@@ -353,22 +362,22 @@ enum EnumSwitchesPositions
SW_SD0,
SW_SD1,
SW_SD2,
-#if defined(PCBX9) || defined(PCBXLITES) || defined(PCBX9LITES) || defined(RADIO_TX12) || defined(RADIO_ZORRO)
+#if defined(HARDWARE_SWITCH_E)
SW_SE0,
SW_SE1,
SW_SE2,
#endif
-#if defined(PCBX9D) || defined(PCBX9DP) || defined(PCBX9E) || (defined(PCBX7) && !defined(RADIO_T12)) || defined(PCBXLITES) || defined(PCBX9LITES) || defined(RADIO_T8) || defined(RADIO_ZORRO)
+#if defined(HARDWARE_SWITCH_F)
SW_SF0,
SW_SF1,
SW_SF2,
#endif
-#if defined(PCBX9D) || defined(PCBX9DP) || defined(PCBX9E) || defined(PCBX9LITES) || defined(RADIO_T12) || defined(RADIO_ZORRO)
+#if defined(HARDWARE_SWITCH_G)
SW_SG0,
SW_SG1,
SW_SG2,
#endif
-#if defined(PCBX9D) || defined(PCBX9DP) || defined(PCBX9E) || (defined(PCBX7) && !defined(RADIO_TX12)) || defined(RADIO_T8) || defined(RADIO_ZORRO)
+#if defined(HARDWARE_SWITCH_H)
SW_SH0,
SW_SH1,
SW_SH2,
@@ -440,6 +449,16 @@ enum EnumSwitchesPositions
#define STORAGE_NUM_SWITCHES 8
#define DEFAULT_SWITCH_CONFIG (SWITCH_2POS << 6) + (SWITCH_2POS << 4) + (SWITCH_3POS << 2) + (SWITCH_3POS << 0);
#define DEFAULT_POTS_CONFIG (0)
+#elif defined(RADIO_TPRO)
+ #define NUM_SWITCHES 10
+ #define NUM_FUNCTIONS_SWITCHES 6
+ #define NUM_REGULAR_SWITCHES (NUM_SWITCHES - NUM_FUNCTIONS_SWITCHES)
+ #define STORAGE_NUM_SWITCHES 10
+ #define DEFAULT_SWITCH_CONFIG (SWITCH_TOGGLE << 6) + (SWITCH_TOGGLE << 4) + (SWITCH_3POS << 2) + (SWITCH_3POS << 0);
+ #define DEFAULT_FS_CONFIG (SWITCH_2POS << 10) + (SWITCH_2POS << 8) + (SWITCH_2POS << 6) + (SWITCH_2POS << 4) + (SWITCH_2POS << 2) + (SWITCH_2POS << 0)
+ #define DEFAULT_FS_GROUPS (1 << 10) + (1 << 8) + (1 << 6) + (1 << 4) + (1 << 2) + (1 << 0) // Set all FS to group 1 to act like a 6pos
+ #define DEFAULT_FS_STARTUP_CONFIG ((FS_START_PREVIOUS << 10) + (FS_START_PREVIOUS << 8) + (FS_START_PREVIOUS << 6) + (FS_START_PREVIOUS << 4) + (FS_START_PREVIOUS << 2) + (FS_START_PREVIOUS << 0)) // keep last state by default
+ #define DEFAULT_POTS_CONFIG (POT_WITHOUT_DETENT << 0) + (POT_WITH_DETENT << 2); // S1 = pot without detent, S2 = pot with detent
#elif defined(RADIO_FAMILY_JUMPER_T12)
#define NUM_SWITCHES 8
#define STORAGE_NUM_SWITCHES NUM_SWITCHES
@@ -500,17 +519,24 @@ enum EnumSwitchesPositions
#define DEFAULT_SLIDERS_CONFIG (SLIDER_WITH_DETENT << 1) + (SLIDER_WITH_DETENT << 0)
#endif
+#if !defined(NUM_FUNCTIONS_SWITCHES)
+ #define NUM_FUNCTIONS_SWITCHES 0
+#endif
+
#define STORAGE_NUM_SWITCHES_POSITIONS (STORAGE_NUM_SWITCHES * 3)
void keysInit();
uint32_t switchState(uint8_t index);
-#if defined(RADIO_ZORRO)
-static const uint8_t switchReOrder[] = {1, 0, 4, 2, 3, 5};
-#else
-static const uint8_t switchReOrder[] = {0, 1, 2, 3, 4, 5};
-#endif
uint32_t readKeys();
uint32_t readTrims();
+#if defined(FUNCTION_SWITCHES)
+extern uint8_t fsPreviousState;
+void evalFunctionSwitches();
+void setFSStartupPosition();
+uint8_t getFSLogicalState(uint8_t index);
+uint8_t getFSPhysicalState(uint8_t index);
+#endif
+
#define TRIMS_PRESSED() (readTrims())
#define KEYS_PRESSED() (readKeys())
@@ -926,6 +952,10 @@ void ledOff();
void ledRed();
void ledGreen();
void ledBlue();
+#if defined(FUNCTION_SWITCHES)
+void fsLedOff(uint8_t);
+void fsLedOn(uint8_t);
+#endif
// LCD driver
#if defined(PCBX9D) || defined(PCBX9DP) || defined(PCBX9E)
@@ -942,7 +972,7 @@ void ledBlue();
#define IS_LCD_RESET_NEEDED() true
#define LCD_CONTRAST_MIN 10
#define LCD_CONTRAST_MAX 30
-#if defined(RADIO_TX12) || defined(RADIO_FAMILY_JUMPER_T12)
+#if defined(RADIO_TX12) || defined(RADIO_TPRO) || defined(RADIO_FAMILY_JUMPER_T12) || defined(RADIO_TPRO)
#define LCD_CONTRAST_DEFAULT 25
#else
#define LCD_CONTRAST_DEFAULT 15
diff --git a/radio/src/targets/taranis/hal.h b/radio/src/targets/taranis/hal.h
index 4db84712d..ea2bec79b 100644
--- a/radio/src/targets/taranis/hal.h
+++ b/radio/src/targets/taranis/hal.h
@@ -53,7 +53,7 @@
#define KEYS_GPIO_PIN_LEFT GPIO_Pin_12 // PE.12
#define KEYS_GPIO_REG_RIGHT GPIOE->IDR
#define KEYS_GPIO_PIN_RIGHT GPIO_Pin_13 // PE.13
-#elif defined(RADIO_FAMILY_JUMPER_T12)
+#elif defined(RADIO_FAMILY_JUMPER_T12) && !defined(RADIO_TPRO)
#define KEYS_GPIO_REG_EXIT GPIOD->IDR
#define KEYS_GPIO_PIN_EXIT GPIO_Pin_2 // PD.02
#define KEYS_GPIO_REG_ENTER GPIOE->IDR
@@ -174,7 +174,7 @@
#define ROTARY_ENCODER_EXTI_PortSource EXTI_PortSourceGPIOE
#define ROTARY_ENCODER_EXTI_PinSource1 EXTI_PinSource10
#define ROTARY_ENCODER_EXTI_PinSource2 EXTI_PinSource11
-#elif defined(RADIO_X7) || defined(RADIO_X7ACCESS)
+#elif defined(RADIO_X7) || defined(RADIO_X7ACCESS) || defined(RADIO_TPRO)
#define ROTARY_ENCODER_NAVIGATION
#define ROTARY_ENCODER_GPIO GPIOE
#define ROTARY_ENCODER_GPIO_PIN_A GPIO_Pin_9 // PE.09
@@ -368,6 +368,13 @@
#define HARDWARE_SWITCH_A
#define SWITCHES_GPIO_REG_A GPIOE->IDR
#define SWITCHES_GPIO_PIN_A GPIO_Pin_14 // PE.14
+#elif defined(RADIO_TPRO)
+ #define STORAGE_SWITCH_A
+ #define HARDWARE_SWITCH_A
+ #define SWITCHES_GPIO_REG_A_L GPIOE->IDR
+ #define SWITCHES_GPIO_PIN_A_L GPIO_Pin_13 // PE.13
+ #define SWITCHES_GPIO_REG_A_H GPIOE->IDR
+ #define SWITCHES_GPIO_PIN_A_H GPIO_Pin_7 // PE.07
#elif defined(PCBX7)
#define STORAGE_SWITCH_A
#define HARDWARE_SWITCH_A
@@ -405,7 +412,7 @@
#define SWITCHES_GPIO_PIN_B_L GPIO_Pin_7 // PE.07
#define SWITCHES_GPIO_REG_B_H GPIOE->IDR
#define SWITCHES_GPIO_PIN_B_H GPIO_Pin_13 // PE.13
-#elif defined(RADIO_TLITE)
+#elif defined(RADIO_TLITE) || defined(RADIO_TPRO)
#define STORAGE_SWITCH_B
#define HARDWARE_SWITCH_B
#define SWITCHES_GPIO_REG_B_L GPIOE->IDR
@@ -470,7 +477,7 @@
#define SWITCHES_GPIO_PIN_C_L GPIO_Pin_2 // PE.02
#define SWITCHES_GPIO_REG_C_H GPIOE->IDR
#define SWITCHES_GPIO_PIN_C_H GPIO_Pin_1 // PE.01
-#elif defined(RADIO_TLITE)
+#elif defined(RADIO_TLITE) || defined(RADIO_TPRO)
#define STORAGE_SWITCH_C
#define HARDWARE_SWITCH_C
#define SWITCHES_GPIO_REG_C GPIOE->IDR
@@ -527,7 +534,7 @@
#define HARDWARE_SWITCH_D
#define SWITCHES_GPIO_REG_D GPIOE->IDR
#define SWITCHES_GPIO_PIN_D GPIO_Pin_8 // PE.08
-#elif defined(RADIO_TLITE)
+#elif defined(RADIO_TLITE) || defined(RADIO_TPRO)
#define STORAGE_SWITCH_D
#define HARDWARE_SWITCH_D
#define SWITCHES_GPIO_REG_D GPIOD->IDR
@@ -585,6 +592,12 @@
#define SWITCHES_GPIO_PIN_E_H GPIO_Pin_13 // PE.13
#define SWITCHES_GPIO_REG_E_L GPIOE->IDR
#define SWITCHES_GPIO_PIN_E_L GPIO_Pin_7 // PE.07
+#elif defined(RADIO_TPRO)
+ // SW1
+ #define STORAGE_SWITCH_E
+ #define HARDWARE_SWITCH_E
+ #define SWITCHES_GPIO_REG_E GPIOG->IDR
+ #define SWITCHES_GPIO_PIN_E GPIO_Pin_7 // PG.07
#elif defined(PCBX7)
// no SWE
#else
@@ -628,7 +641,13 @@
#define SWITCHES_GPIO_PIN_F_L GPIO_Pin_1 // PE.01
#define SWITCHES_GPIO_REG_F_H GPIOE->IDR
#define SWITCHES_GPIO_PIN_F_H GPIO_Pin_2 // PE.02
-#elif defined(RADIO_T8) || defined(RADIO_TLITE)
+#elif defined(RADIO_TPRO)
+ // SW2
+ #define STORAGE_SWITCH_F
+ #define HARDWARE_SWITCH_F
+ #define SWITCHES_GPIO_REG_F GPIOG->IDR
+ #define SWITCHES_GPIO_PIN_F GPIO_Pin_6 // PG.06
+#elif defined(RADIO_T8) || defined(RADIO_TLITE) || defined(RADIO_TPRO)
// no SWF
#define STORAGE_SWITCH_F
#elif defined(RADIO_T12)
@@ -662,6 +681,12 @@
#define HARDWARE_SWITCH_G
#define SWITCHES_GPIO_REG_G GPIOE->IDR
#define SWITCHES_GPIO_PIN_G GPIO_Pin_14 // PE.14
+#elif defined(RADIO_TPRO)
+ // SW3
+ #define STORAGE_SWITCH_G
+ #define HARDWARE_SWITCH_G
+ #define SWITCHES_GPIO_REG_G GPIOG->IDR
+ #define SWITCHES_GPIO_PIN_G GPIO_Pin_5 // PG.05
#elif defined(PCBX7) || defined(PCBXLITE) || defined(PCBX9LITE) || defined(RADIO_T8)
// no SWG
#else
@@ -689,7 +714,13 @@
#define STORAGE_SWITCH_H
// no SWH
#elif defined(RADIO_TX12)
-#elif defined(RADIO_TLITE)
+#elif defined(RADIO_TPRO)
+ // SW4
+ #define STORAGE_SWITCH_H
+ #define HARDWARE_SWITCH_H
+ #define SWITCHES_GPIO_REG_H GPIOG->IDR
+ #define SWITCHES_GPIO_PIN_H GPIO_Pin_4 // PG.04
+#elif defined(RADIO_TLITE) || defined(RADIO_TPRO)
// no SWH
#define STORAGE_SWITCH_H
#elif defined(PCBX7)
@@ -740,6 +771,17 @@
#define STORAGE_SWITCH_J
#elif defined(RADIO_ZORRO)
// No I/J
+#elif defined(RADIO_TPRO)
+ // SW5
+ #define STORAGE_SWITCH_I
+ #define HARDWARE_SWITCH_I
+ #define SWITCHES_GPIO_REG_I GPIOG->IDR
+ #define SWITCHES_GPIO_PIN_I GPIO_Pin_3 // PG.03
+ // SW6
+ #define STORAGE_SWITCH_J
+ #define HARDWARE_SWITCH_J
+ #define SWITCHES_GPIO_REG_J GPIOG->IDR
+ #define SWITCHES_GPIO_PIN_J GPIO_Pin_2 // PG.02
#elif defined(PCBX7)
#define STORAGE_SWITCH_I
#define HARDWARE_SWITCH_I
@@ -849,6 +891,13 @@
#define KEYS_GPIOB_PINS (GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_4 | GPIO_Pin_5)
#define KEYS_GPIOC_PINS (GPIO_Pin_4 | GPIO_Pin_5)
#define KEYS_GPIOE_PINS (GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14)
+#elif defined(RADIO_TPRO)
+ #define KEYS_RCC_AHB1Periph (RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_GPIOE | RCC_AHB1Periph_GPIOG)
+ #define KEYS_GPIOA_PINS (GPIO_Pin_5)
+ #define KEYS_GPIOC_PINS (GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3)
+ #define KEYS_GPIOD_PINS (GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_7 | GPIO_Pin_11 | GPIO_Pin_14 | GPIO_Pin_15)
+ #define KEYS_GPIOE_PINS (GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15)
+ #define KEYS_GPIOG_PINS (GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7)
#elif defined(RADIO_FAMILY_JUMPER_T12)
#define KEYS_RCC_AHB1Periph (RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_GPIOE)
#define KEYS_GPIOA_PINS GPIO_Pin_5
@@ -1067,6 +1116,30 @@
#define ADC_GPIOC_PINS ADC_GPIO_PIN_BATT
#define ADC_CHANNEL_BATT ADC_Channel_10
#define ADC_VREF_PREC2 330
+#elif defined(RADIO_TPRO)
+ #define HARDWARE_POT1
+ #define HARDWARE_POT2
+ #define ADC_RCC_AHB1Periph (RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_DMA2)
+ #define ADC_RCC_APB1Periph 0
+ #define ADC_RCC_APB2Periph RCC_APB2Periph_ADC1
+ #define ADC_GPIO_PIN_STICK_RV GPIO_Pin_0 // PA.00
+ #define ADC_GPIO_PIN_STICK_RH GPIO_Pin_1 // PA.01
+ #define ADC_GPIO_PIN_STICK_LV GPIO_Pin_2 // PA.02
+ #define ADC_GPIO_PIN_STICK_LH GPIO_Pin_3 // PA.03
+ #define ADC_CHANNEL_STICK_RV ADC_Channel_0 // ADC1_IN0
+ #define ADC_CHANNEL_STICK_RH ADC_Channel_1 // ADC1_IN1
+ #define ADC_CHANNEL_STICK_LV ADC_Channel_2 // ADC1_IN2
+ #define ADC_CHANNEL_STICK_LH ADC_Channel_3 // ADC1_IN3
+ #define ADC_GPIO_PIN_POT1 GPIO_Pin_0 // PB.00
+ #define ADC_GPIO_PIN_POT2 GPIO_Pin_6 // PA.06
+ #define ADC_GPIO_PIN_BATT GPIO_Pin_0 // PC.00
+ #define ADC_GPIOA_PINS (ADC_GPIO_PIN_STICK_RV | ADC_GPIO_PIN_STICK_RH | ADC_GPIO_PIN_STICK_LH | ADC_GPIO_PIN_STICK_LV | ADC_GPIO_PIN_POT2)
+ #define ADC_GPIOB_PINS ADC_GPIO_PIN_POT1
+ #define ADC_GPIOC_PINS ADC_GPIO_PIN_BATT
+ #define ADC_CHANNEL_POT1 ADC_Channel_6
+ #define ADC_CHANNEL_POT2 ADC_Channel_8
+ #define ADC_CHANNEL_BATT ADC_Channel_10
+ #define ADC_VREF_PREC2 330
#elif defined(PCBX7)
#define HARDWARE_POT1
#define HARDWARE_POT2
@@ -1244,6 +1317,19 @@
#define LED_BLUE_GPIO_PIN GPIO_Pin_6 // PE.06
#endif
+#if defined(FUNCTION_SWITCHES)
+ #define FS_RCC_AHB1Periph RCC_AHB1Periph_GPIOF
+ #define GPIO_FSLED_GPIO_ON GPIO_SetBits
+ #define GPIO_FSLED_GPIO_OFF GPIO_ResetBits
+ #define FSLED_GPIO GPIOF
+ #define FSLED_GPIO_PIN_1 GPIO_Pin_5
+ #define FSLED_GPIO_PIN_2 GPIO_Pin_4
+ #define FSLED_GPIO_PIN_3 GPIO_Pin_3
+ #define FSLED_GPIO_PIN_4 GPIO_Pin_2
+ #define FSLED_GPIO_PIN_5 GPIO_Pin_1
+ #define FSLED_GPIO_PIN_6 GPIO_Pin_0
+#endif
+
// Internal Module
#if defined(PCBXLITE)
#define EXTERNAL_ANTENNA
@@ -1362,7 +1448,7 @@
#define INTMODULE_DMA_STREAM_IRQHandler DMA2_Stream5_IRQHandler
#define INTMODULE_DMA_FLAG_TC DMA_IT_TCIF5
#define INTMODULE_TIMER_FREQ (PERI2_FREQUENCY * TIMER_MULT_APB2)
-#elif (defined(RADIO_FAMILY_JUMPER_T12) && defined(HARDWARE_INTERNAL_MODULE)) || defined(RADIO_TX12) || defined(RADIO_ZORRO) || defined(RADIO_T8)
+#elif (defined(RADIO_FAMILY_JUMPER_T12) && defined(HARDWARE_INTERNAL_MODULE)) || defined(RADIO_TX12) || defined(RADIO_ZORRO) || defined(RADIO_T8) || defined(RADIO_TPRO)
#define INTMODULE_RCC_AHB1Periph (RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_DMA1)
#define INTMODULE_RCC_APB1Periph (RCC_APB1Periph_USART3 | RCC_APB1Periph_TIM2)
#define INTMODULE_RCC_APB2Periph 0
@@ -1612,7 +1698,7 @@
#define TELEMETRY_EXTI_IRQn EXTI9_5_IRQn
#define TELEMETRY_EXTI_TRIGGER EXTI_Trigger_Rising
-#if defined(RADIO_X7) || defined(RADIO_X7ACCESS) || defined(RADIO_TX12) || defined(RADIO_ZORRO) || defined(RADIO_T8)
+#if defined(RADIO_X7) || defined(RADIO_X7ACCESS) || defined(RADIO_TX12) || defined(RADIO_ZORRO) || defined(RADIO_T8) || defined(RADIO_TPRO)
#define TELEMETRY_EXTI_REUSE_INTERRUPT_ROTARY_ENCODER
#elif defined(PCBXLITE) || defined(PCBX9LITE) || defined(RADIO_X9DP2019)
#define TELEMETRY_EXTI_IRQHandler EXTI9_5_IRQHandler
@@ -1724,7 +1810,7 @@
#define INTMODULE_HEARTBEAT_EXTI_IRQHandler EXTI1_IRQHandler
#elif defined(RADIO_ZORRO)
#define INTMODULE_HEARTBEAT_RCC_AHB1Periph 0
-#elif defined(RADIO_X7) || defined(RADIO_TX12)
+#elif defined(RADIO_X7) || defined(RADIO_TX12) || defined(RADIO_TPRO)
#define INTMODULE_HEARTBEAT
#define INTMODULE_HEARTBEAT_REUSE_INTERRUPT_ROTARY_ENCODER
#define INTMODULE_HEARTBEAT_RCC_AHB1Periph RCC_AHB1Periph_GPIOC
@@ -1912,7 +1998,7 @@
#define KEYS_BACKLIGHT_RCC_AHB1Periph 0
// LCD driver
-#if defined(RADIO_TX12) || defined(RADIO_ZORRO) || defined(RADIO_FAMILY_JUMPER_T12) || defined(RADIO_T8)
+#if defined(RADIO_TX12) || defined(RADIO_ZORRO) || defined(RADIO_FAMILY_JUMPER_T12) || defined(RADIO_T8) || defined(RADIO_TPRO)
#define LCD_VERTICAL_INVERT
#endif
#if defined(PCBX9E)
@@ -2116,12 +2202,12 @@
#define AUDIO_SPEAKER_ENABLE_GPIO_PIN GPIO_Pin_14 // PD.14
#define HEADPHONE_TRAINER_SWITCH_GPIO GPIOD
#define HEADPHONE_TRAINER_SWITCH_GPIO_PIN GPIO_Pin_9 // PD.09
-#elif defined(RADIO_TX12) || defined(RADIO_ZORRO) || defined(RADIO_T8) || defined(RADIO_TLITE)
+#elif defined(RADIO_TX12) || defined(RADIO_ZORRO) || defined(RADIO_T8) || defined(RADIO_TLITE) || defined(RADIO_TPRO)
#define AUDIO_RCC_AHB1Periph (RCC_AHB1Periph_GPIOE | RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_DMA1)
#define AUDIO_MUTE_GPIO GPIOE
#define AUDIO_MUTE_GPIO_PIN GPIO_Pin_12 // PE.12
#define AUDIO_MUTE_DELAY 500 // ms
-#if defined(RADIO_TLITE)
+#if defined(RADIO_TLITE) || defined(RADIO_TPRO)
#define AUDIO_UNMUTE_DELAY 250 // ms
#else
#define AUDIO_UNMUTE_DELAY 150 // ms
diff --git a/radio/src/targets/taranis/keys_driver.cpp b/radio/src/targets/taranis/keys_driver.cpp
index 3dc4260eb..1d5d3fccf 100644
--- a/radio/src/targets/taranis/keys_driver.cpp
+++ b/radio/src/targets/taranis/keys_driver.cpp
@@ -210,7 +210,7 @@ uint32_t switchState(uint8_t index)
ADD_2POS_CASE(A);
ADD_3POS_CASE(B, 1);
ADD_3POS_CASE(C, 2);
-#elif defined(RADIO_TLITE)
+#elif defined(RADIO_TLITE) || defined(RADIO_TPRO)
ADD_3POS_CASE(A, 0);
ADD_3POS_CASE(B, 1);
ADD_2POS_CASE(C);
@@ -256,6 +256,13 @@ uint32_t switchState(uint8_t index)
ADD_2POS_CASE(D);
#elif defined(RADIO_TLITE)
// Only 4 switches
+#elif defined(RADIO_TPRO)
+ ADD_2POS_CASE(E);
+ ADD_2POS_CASE(F);
+ ADD_2POS_CASE(G);
+ ADD_2POS_CASE(H);
+ ADD_2POS_CASE(I);
+ ADD_2POS_CASE(J);
#elif defined(PCBX7)
ADD_3POS_CASE(D, 3);
#if defined(RADIO_T12)
diff --git a/radio/src/targets/taranis/lcd_driver_spi.cpp b/radio/src/targets/taranis/lcd_driver_spi.cpp
index 53ac9ac25..e3f9069c8 100644
--- a/radio/src/targets/taranis/lcd_driver_spi.cpp
+++ b/radio/src/targets/taranis/lcd_driver_spi.cpp
@@ -21,7 +21,7 @@
#include "opentx.h"
-#if defined(RADIO_FAMILY_JUMPER_T12) || defined(RADIO_TX12) || defined(RADIO_ZORRO) || defined(RADIO_T8)
+#if defined(RADIO_FAMILY_JUMPER_T12) || defined(RADIO_TX12) || defined(RADIO_ZORRO) || defined(RADIO_T8) || defined(RADIO_TPRO)
#define LCD_CONTRAST_OFFSET -10
#else
#define LCD_CONTRAST_OFFSET 160
diff --git a/radio/src/targets/taranis/led_driver.cpp b/radio/src/targets/taranis/led_driver.cpp
index 04033c655..0b6824cf0 100644
--- a/radio/src/targets/taranis/led_driver.cpp
+++ b/radio/src/targets/taranis/led_driver.cpp
@@ -43,8 +43,32 @@ void ledInit()
GPIO_InitStructure.GPIO_Pin = LED_BLUE_GPIO_PIN;
GPIO_Init(LED_BLUE_GPIO, &GPIO_InitStructure);
#endif
+
+#if defined(FUNCTION_SWITCHES)
+ RCC_AHB1PeriphClockCmd(FS_RCC_AHB1Periph, ENABLE);
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
+ GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
+ GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
+ GPIO_InitStructure.GPIO_Pin = FSLED_GPIO_PIN_1 | FSLED_GPIO_PIN_2 | FSLED_GPIO_PIN_3 | FSLED_GPIO_PIN_4 | FSLED_GPIO_PIN_5 | FSLED_GPIO_PIN_6;
+ GPIO_Init(FSLED_GPIO, &GPIO_InitStructure);
+#endif
}
+#if defined(FUNCTION_SWITCHES)
+constexpr uint32_t fsLeds[] = {FSLED_GPIO_PIN_1, FSLED_GPIO_PIN_2, FSLED_GPIO_PIN_3, FSLED_GPIO_PIN_4, FSLED_GPIO_PIN_5, FSLED_GPIO_PIN_6};
+
+void fsLedOff(uint8_t index)
+{
+ GPIO_FSLED_GPIO_OFF(FSLED_GPIO, fsLeds[index]);
+}
+
+void fsLedOn(uint8_t index)
+{
+ GPIO_FSLED_GPIO_ON(FSLED_GPIO, fsLeds[index]);
+}
+#endif
+
void ledOff()
{
#if defined(LED_RED_GPIO)
diff --git a/radio/src/translations.cpp b/radio/src/translations.cpp
index 418d4b639..d54529847 100644
--- a/radio/src/translations.cpp
+++ b/radio/src/translations.cpp
@@ -94,6 +94,7 @@ ISTR(CRSF_BAUDRATE);
ISTR(PPM_POL);
ISTR(SBUS_INVERSION_VALUES);
ISTR(SPORT_MODES);
+ISTR(FSGROUPS);
#if defined(PCBSKY9X) && defined(REVX)
ISTR(VOUTPUT_TYPE);
diff --git a/radio/src/translations.h b/radio/src/translations.h
index f1c16e9a2..e37110dbb 100644
--- a/radio/src/translations.h
+++ b/radio/src/translations.h
@@ -178,6 +178,7 @@ extern const char STR_MULTI_POWER[];
extern const char STR_MULTI_TELEMETRY_MODE[];
extern const char STR_MULTI_WBUS_MODE[];
extern const char STR_SPORT_MODES[];
+extern const char STR_FSGROUPS[];
extern const char STR_AFHDS3_ONE_TO_ONE_TELEMETRY[];
extern const char STR_AFHDS3_ONE_TO_MANY[];
diff --git a/radio/src/translations/untranslated.h b/radio/src/translations/untranslated.h
index fca9c7ecd..2d3936df5 100644
--- a/radio/src/translations/untranslated.h
+++ b/radio/src/translations/untranslated.h
@@ -40,9 +40,20 @@
#elif defined(PCBXLITE)
#define TR_POTS_VSRCRAW STR_CHAR_POT"S1\0" STR_CHAR_POT"S2\0"
#define TR_SW_VSRCRAW STR_CHAR_SWITCH"SA\0" STR_CHAR_SWITCH"SB\0" STR_CHAR_SWITCH"SC\0" STR_CHAR_SWITCH"SD\0" STR_CHAR_SWITCH"SE\0" STR_CHAR_SWITCH"SF\0"
-#elif defined(RADIO_FAMILY_JUMPER_T12)
+#elif defined(RADIO_TPRO)
#define TR_POTS_VSRCRAW STR_CHAR_POT"S1\0" STR_CHAR_POT"S2\0"
- #define TR_SW_VSRCRAW STR_CHAR_SWITCH"SA\0" STR_CHAR_SWITCH"SB\0" STR_CHAR_SWITCH"SC\0" STR_CHAR_SWITCH"SD\0" STR_CHAR_SWITCH"SG\0" STR_CHAR_SWITCH"SH\0" STR_CHAR_SWITCH"SI\0" STR_CHAR_SWITCH"SJ\0"
+#define TR_SW_VSRCRAW \
+ STR_CHAR_SWITCH \
+ "SA\0" STR_CHAR_SWITCH "SB\0" STR_CHAR_SWITCH "SC\0" STR_CHAR_SWITCH \
+ "SD\0" STR_CHAR_SWITCH "SW1" STR_CHAR_SWITCH "SW2" STR_CHAR_SWITCH \
+ "SW3" STR_CHAR_SWITCH "SW4" STR_CHAR_SWITCH "SW5" STR_CHAR_SWITCH "SW6"
+#elif defined(RADIO_FAMILY_JUMPER_T12)
+#define TR_POTS_VSRCRAW STR_CHAR_POT "S1\0" STR_CHAR_POT "S2\0"
+#define TR_SW_VSRCRAW \
+ STR_CHAR_SWITCH "SA\0" STR_CHAR_SWITCH "SB\0" STR_CHAR_SWITCH \
+ "SC\0" STR_CHAR_SWITCH "SD\0" STR_CHAR_SWITCH \
+ "SG\0" STR_CHAR_SWITCH "SH\0" STR_CHAR_SWITCH \
+ "SI\0" STR_CHAR_SWITCH "SJ\0"
#elif defined(RADIO_TX12)
#define TR_POTS_VSRCRAW STR_CHAR_POT "S1\0" STR_CHAR_POT "S2\0"
#define TR_SW_VSRCRAW STR_CHAR_SWITCH "SA\0" STR_CHAR_SWITCH "SB\0" STR_CHAR_SWITCH "SC\0" STR_CHAR_SWITCH "SD\0" STR_CHAR_SWITCH "SE\0" STR_CHAR_SWITCH "SF\0" STR_CHAR_SWITCH "SI\0" STR_CHAR_SWITCH "SJ\0"
@@ -372,3 +383,7 @@
#define TR_EDIT_THEME "EDIT THEME"
#define TR_DETAILS "Details"
#define TR_THEME_EDITOR "THEMES"
+
+#define LEN_FSGROUPS "\001"
+#define TR_FSGROUPS "-""1""2""3"
+
diff --git a/tools/build-jumper.py b/tools/build-jumper.py
index cfce0920c..8e7d9e171 100755
--- a/tools/build-jumper.py
+++ b/tools/build-jumper.py
@@ -14,6 +14,11 @@ boards = {
"PCBREV": "TLITE",
"DEFAULT_MODE": "2",
},
+ "TPRO": {
+ "PCB": "X7",
+ "PCBREV": "TPRO",
+ "DEFAULT_MODE": "2",
+ },
"T12": {
"PCB": "X7",
"PCBREV": "T12",