diff --git a/.travis.yml b/.travis.yml index cd3f1e948..442466067 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,6 +33,7 @@ env: # - FLAVOR=X9D # - FLAVOR=X9D+ # - FLAVOR=X9E + - FLAVOR=T16 - FLAVOR=HORUS # - FLAVOR=X10 # - FLAVOR=X12Sr10 diff --git a/companion/src/CMakeLists.txt b/companion/src/CMakeLists.txt index 61309d394..16245c848 100644 --- a/companion/src/CMakeLists.txt +++ b/companion/src/CMakeLists.txt @@ -347,6 +347,8 @@ elseif(PCB STREQUAL X9D+ AND PCBREV STREQUAL 2019) set(FLAVOUR x9d+2019) elseif(PCB STREQUAL X10 AND PCBREV STREQUAL EXPRESS) set(FLAVOUR x10express) +elseif(PCB STREQUAL X10 AND PCBREV STREQUAL T16) + set(FLAVOUR t16) else() string(TOLOWER ${PCB} FLAVOUR) endif() diff --git a/companion/src/companion.qrc b/companion/src/companion.qrc index 2b4b18f71..567b52637 100644 --- a/companion/src/companion.qrc +++ b/companion/src/companion.qrc @@ -170,6 +170,17 @@ images/simulator/JumperT12/JumperT12-x.png images/simulator/JumperT12/JumperT12-center.png images/simulator/JumperT12/JumperT12-top.png + images/simulator/JumperT16/left.png + images/simulator/JumperT16/right.png + images/simulator/JumperT16/top.png + images/simulator/JumperT16/bottom.png + images/simulator/JumperT16/left_mdl.png + images/simulator/JumperT16/left_page.png + images/simulator/JumperT16/left_scrnsht.png + images/simulator/JumperT16/left_sys.png + images/simulator/JumperT16/left_tele.png + images/simulator/JumperT16/right_ent.png + images/simulator/JumperT16/right_rtn.png images/wizard/ailerons.png images/wizard/airbrakes.png images/wizard/elevons.png diff --git a/companion/src/firmwares/boards.cpp b/companion/src/firmwares/boards.cpp index 99094edf3..809bc159a 100644 --- a/companion/src/firmwares/boards.cpp +++ b/companion/src/firmwares/boards.cpp @@ -89,6 +89,8 @@ uint32_t Boards::getFourCC(Type board) return 0; case BOARD_JUMPER_T12: return 0x3D78746F; + case BOARD_JUMPER_T16: + return 0x3F78746F; case BOARD_UNKNOWN: break; } @@ -127,6 +129,7 @@ int Boards::getEEpromSize(Board::Type board) case BOARD_HORUS_X12S: case BOARD_X10: case BOARD_X10_EXPRESS: + case BOARD_JUMPER_T16: return 0; } @@ -162,6 +165,7 @@ int Boards::getFlashSize(Type board) case BOARD_HORUS_X12S: case BOARD_X10: case BOARD_X10_EXPRESS: + case BOARD_JUMPER_T16: return FSIZE_HORUS; case BOARD_UNKNOWN: return FSIZE_MAX; @@ -277,7 +281,7 @@ int Boards::getCapability(Board::Type board, Board::Capability capability) return 2; else if (IS_TARANIS_X9E(board)) return 4; - else if (IS_HORUS_X10(board)) + else if (IS_HORUS_X10(board) || IS_JUMPER_T16(board)) return 5; else if (IS_HORUS_X12S(board)) return 3; @@ -293,7 +297,7 @@ int Boards::getCapability(Board::Type board, Board::Capability capability) case Sliders: if (IS_HORUS_X12S(board) || IS_TARANIS_X9E(board)) return 4; - else if (IS_TARANIS_X9D(board) || IS_HORUS_X10(board)) + else if (IS_TARANIS_X9D(board) || IS_HORUS_X10(board) || IS_JUMPER_T16(board)) return 2; else return 0; @@ -458,7 +462,7 @@ QString Boards::getAnalogInputName(Board::Type board, int index) if (index < DIM(pots)) return pots[index]; } - else if (IS_HORUS_X10(board)) { + else if (IS_HORUS_X10(board) || IS_JUMPER_T16(board)) { const QString pots[] = { "S1", "6P", @@ -523,6 +527,8 @@ QString Boards::getBoardName(Board::Type board) return "Horus X10/X10S"; case BOARD_X10_EXPRESS: return "Horus X10 Express"; + case BOARD_JUMPER_T16: + return "Jumper T16"; default: return tr("Unknown"); } diff --git a/companion/src/firmwares/boards.h b/companion/src/firmwares/boards.h index 7a60ad4f4..b7af393b6 100644 --- a/companion/src/firmwares/boards.h +++ b/companion/src/firmwares/boards.h @@ -52,9 +52,10 @@ namespace Board { BOARD_TARANIS_X9LITE, BOARD_TARANIS_X9LITES, BOARD_JUMPER_T12, + BOARD_JUMPER_T16, }; - constexpr int BOARD_TYPE_MAX = BOARD_JUMPER_T12 ; + constexpr int BOARD_TYPE_MAX = BOARD_JUMPER_T16 ; enum PotType { @@ -223,6 +224,11 @@ inline bool IS_JUMPER_T12(Board::Type board) return board == Board::BOARD_JUMPER_T12; } +inline bool IS_JUMPER_T16(Board::Type board) +{ + return board == Board::BOARD_JUMPER_T16; +} + inline bool IS_TARANIS_XLITE(Board::Type board) { return board == Board::BOARD_TARANIS_XLITE || board == Board::BOARD_TARANIS_XLITES; @@ -285,7 +291,7 @@ inline bool IS_HORUS_X12S(Board::Type board) inline bool IS_HORUS(Board::Type board) { - return IS_HORUS_X12S(board) || IS_HORUS_X10(board); + return IS_HORUS_X12S(board) || IS_HORUS_X10(board) || IS_JUMPER_T16(board); } inline bool IS_HORUS_OR_TARANIS(Board::Type board) @@ -310,7 +316,7 @@ inline bool HAS_LARGE_LCD(Board::Type board) inline bool HAS_EXTERNAL_ANTENNA(Board::Type board) { - return (IS_HORUS(board) && board != Board::BOARD_X10_EXPRESS) || (IS_TARANIS_XLITE(board) && !IS_TARANIS_XLITES(board)); + return (board == Board::BOARD_X10 || board == Board::BOARD_HORUS_X12S || (IS_TARANIS_XLITE(board) && !IS_TARANIS_XLITES(board))); } #endif // _BOARDS_H_ diff --git a/companion/src/firmwares/generalsettings.cpp b/companion/src/firmwares/generalsettings.cpp index 4f8532cd4..22934cf57 100644 --- a/companion/src/firmwares/generalsettings.cpp +++ b/companion/src/firmwares/generalsettings.cpp @@ -88,7 +88,7 @@ GeneralSettings::GeneralSettings() vBatMin = -5; //8,5V vBatMax = -5; //11,5V } - else if (IS_TARANIS_XLITE(board) || IS_HORUS_X10(board)) { + else if (IS_TARANIS_XLITE(board) || IS_HORUS_X10(board) || IS_JUMPER_T16(board)) { // Lipo 2S vBatWarn = 66; vBatMin = -23; // 6.7V @@ -267,7 +267,7 @@ void GeneralSettings::setDefaultControlTypes(Board::Type board) sliderConfig[2] = Board::SLIDER_WITH_DETENT; sliderConfig[3] = Board::SLIDER_WITH_DETENT; } - else if (IS_TARANIS_X9(board) || IS_HORUS_X10(board)) { + else if (IS_TARANIS_X9(board) || IS_HORUS_X10(board) || IS_JUMPER_T16(board)) { sliderConfig[0] = Board::SLIDER_WITH_DETENT; sliderConfig[1] = Board::SLIDER_WITH_DETENT; } diff --git a/companion/src/firmwares/opentx/opentxinterface.cpp b/companion/src/firmwares/opentx/opentxinterface.cpp index 1ab1f3aba..7fcbb0cdc 100644 --- a/companion/src/firmwares/opentx/opentxinterface.cpp +++ b/companion/src/firmwares/opentx/opentxinterface.cpp @@ -68,6 +68,8 @@ const char * OpenTxEepromInterface::getName() return "OpenTX for Gruvin9x board / 9X"; case BOARD_JUMPER_T12: return "OpenTX for Jumper T12"; + case BOARD_JUMPER_T16: + return "OpenTX for Jumper T16"; case BOARD_TARANIS_X9D: return "OpenTX for FrSky Taranis X9D"; case BOARD_TARANIS_X9DP: @@ -770,18 +772,20 @@ bool OpenTxFirmware::isAvailable(PulsesProtocol proto, int port) return true; case PULSES_PXX_XJT_X16: case PULSES_PXX_XJT_LR12: - return !(IS_TARANIS_XLITES(board) || IS_TARANIS_X9LITE(board)); + return !(IS_TARANIS_XLITES(board) || IS_TARANIS_X9LITE(board) || IS_JUMPER_T16(board)); case PULSES_PXX_XJT_D8: - return !(IS_TARANIS_XLITES(board) || IS_TARANIS_X9LITE(board) || id.contains("eu")); + return !(IS_TARANIS_XLITES(board) || IS_TARANIS_X9LITE(board) || IS_JUMPER_T16(board) || id.contains("eu")); case PULSES_PPM: return id.contains("internalppm"); case PULSES_ACCESS_ISRM: case PULSES_ACCST_ISRM_D16: return IS_TARANIS_XLITES(board) || IS_TARANIS_X9LITE(board) || board == BOARD_TARANIS_X9DP_2019 || board == BOARD_X10_EXPRESS || (IS_HORUS(board) && id.contains("internalaccess")); + case PULSES_MULTIMODULE: + return id.contains("internalmulti"); default: return false; } - + case 1: switch (proto) { case PULSES_OFF: @@ -1291,6 +1295,12 @@ void registerOpenTxFirmwares() addOpenTxFontOptions(firmware); registerOpenTxFirmware(firmware); + /* Jumper T16 board */ + firmware = new OpenTxFirmware("opentx-t16", Firmware::tr("Jumper T16 / T16+"), BOARD_JUMPER_T16); + addOpenTxFrskyOptions(firmware); + firmware->addOption("internalmulti", Firmware::tr("Support for MULTI internal module")); + registerOpenTxFirmware(firmware); + /* 9XR-Pro */ firmware = new OpenTxFirmware("opentx-9xrpro", Firmware::tr("Turnigy 9XR-PRO"), BOARD_9XRPRO); addOpenTxArm9xOptions(firmware, false); diff --git a/companion/src/images/simulator/JumperT16/JumperT16.svg b/companion/src/images/simulator/JumperT16/JumperT16.svg new file mode 100644 index 000000000..649a506c4 --- /dev/null +++ b/companion/src/images/simulator/JumperT16/JumperT16.svg @@ -0,0 +1,2594 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + Activated button= black/opacity 40% + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SYS + SYS + RTN + RTN + MDL + MDL + PAGE + PAGE + TELE + TELE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/companion/src/images/simulator/JumperT16/bottom.png b/companion/src/images/simulator/JumperT16/bottom.png new file mode 100644 index 000000000..8f0d29f7e Binary files /dev/null and b/companion/src/images/simulator/JumperT16/bottom.png differ diff --git a/companion/src/images/simulator/JumperT16/left.png b/companion/src/images/simulator/JumperT16/left.png new file mode 100644 index 000000000..ed8f9e27f Binary files /dev/null and b/companion/src/images/simulator/JumperT16/left.png differ diff --git a/companion/src/images/simulator/JumperT16/left_mdl.png b/companion/src/images/simulator/JumperT16/left_mdl.png new file mode 100644 index 000000000..62f64d6f7 Binary files /dev/null and b/companion/src/images/simulator/JumperT16/left_mdl.png differ diff --git a/companion/src/images/simulator/JumperT16/left_page.png b/companion/src/images/simulator/JumperT16/left_page.png new file mode 100644 index 000000000..d135a3307 Binary files /dev/null and b/companion/src/images/simulator/JumperT16/left_page.png differ diff --git a/companion/src/images/simulator/JumperT16/left_scrnsht.png b/companion/src/images/simulator/JumperT16/left_scrnsht.png new file mode 100644 index 000000000..899f0a9c4 Binary files /dev/null and b/companion/src/images/simulator/JumperT16/left_scrnsht.png differ diff --git a/companion/src/images/simulator/JumperT16/left_sys.png b/companion/src/images/simulator/JumperT16/left_sys.png new file mode 100644 index 000000000..beed21ee5 Binary files /dev/null and b/companion/src/images/simulator/JumperT16/left_sys.png differ diff --git a/companion/src/images/simulator/JumperT16/left_tele.png b/companion/src/images/simulator/JumperT16/left_tele.png new file mode 100644 index 000000000..029506325 Binary files /dev/null and b/companion/src/images/simulator/JumperT16/left_tele.png differ diff --git a/companion/src/images/simulator/JumperT16/right.png b/companion/src/images/simulator/JumperT16/right.png new file mode 100644 index 000000000..290803879 Binary files /dev/null and b/companion/src/images/simulator/JumperT16/right.png differ diff --git a/companion/src/images/simulator/JumperT16/right_ent.png b/companion/src/images/simulator/JumperT16/right_ent.png new file mode 100644 index 000000000..8f4fdc769 Binary files /dev/null and b/companion/src/images/simulator/JumperT16/right_ent.png differ diff --git a/companion/src/images/simulator/JumperT16/right_rtn.png b/companion/src/images/simulator/JumperT16/right_rtn.png new file mode 100644 index 000000000..00114f2a7 Binary files /dev/null and b/companion/src/images/simulator/JumperT16/right_rtn.png differ diff --git a/companion/src/images/simulator/JumperT16/top.png b/companion/src/images/simulator/JumperT16/top.png new file mode 100644 index 000000000..3bc1784ee Binary files /dev/null and b/companion/src/images/simulator/JumperT16/top.png differ diff --git a/companion/src/simulation/CMakeLists.txt b/companion/src/simulation/CMakeLists.txt index 50d2da532..6d647aeac 100644 --- a/companion/src/simulation/CMakeLists.txt +++ b/companion/src/simulation/CMakeLists.txt @@ -12,6 +12,7 @@ set(simulation_SRCS simulateduiwidgetX10.cpp simulateduiwidgetX12.cpp simulateduiwidgetJumperT12.cpp + simulateduiwidgetJumperT16.cpp simulatorinterface.cpp simulatormainwindow.cpp simulatorstartupdialog.cpp @@ -34,6 +35,7 @@ set(simulation_UIS simulateduiwidgetX10.ui simulateduiwidgetX12.ui simulateduiwidgetJumperT12.ui + simulateduiwidgetJumperT16.ui simulatormainwindow.ui simulatorstartupdialog.ui simulatorwidget.ui diff --git a/companion/src/simulation/simulateduiwidget.h b/companion/src/simulation/simulateduiwidget.h index 94ad0e966..091596729 100644 --- a/companion/src/simulation/simulateduiwidget.h +++ b/companion/src/simulation/simulateduiwidget.h @@ -111,6 +111,7 @@ namespace Ui { class SimulatedUIWidgetX10; class SimulatedUIWidgetX12; class SimulatedUIWidgetJumperT12; + class SimulatedUIWidgetJumperT16; } class SimulatedUIWidget9X: public SimulatedUIWidget @@ -225,4 +226,17 @@ class SimulatedUIWidgetJumperT12: public SimulatedUIWidget Ui::SimulatedUIWidgetJumperT12 * ui; }; +class SimulatedUIWidgetJumperT16: public SimulatedUIWidget +{ + Q_OBJECT + + public: + explicit SimulatedUIWidgetJumperT16(SimulatorInterface * simulator, QWidget * parent = nullptr); + virtual ~SimulatedUIWidgetJumperT16(); + + private: + Ui::SimulatedUIWidgetJumperT16 * ui; +}; + + #endif // SIMULATEDUIWIDGET_H diff --git a/companion/src/simulation/simulateduiwidgetJumperT12.cpp b/companion/src/simulation/simulateduiwidgetJumperT12.cpp index e69f433d3..067108e69 100644 --- a/companion/src/simulation/simulateduiwidgetJumperT12.cpp +++ b/companion/src/simulation/simulateduiwidgetJumperT12.cpp @@ -8,7 +8,6 @@ SimulatedUIWidgetJumperT12::SimulatedUIWidgetJumperT12(SimulatorInterface *simul ui(new Ui::SimulatedUIWidgetJumperT12) { RadioUiAction * act; - QPolygon polygon; ui->setupUi(this); diff --git a/companion/src/simulation/simulateduiwidgetJumperT16.cpp b/companion/src/simulation/simulateduiwidgetJumperT16.cpp new file mode 100644 index 000000000..317fdb24c --- /dev/null +++ b/companion/src/simulation/simulateduiwidgetJumperT16.cpp @@ -0,0 +1,69 @@ +/* + * 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. + */ + +// NOTE: RadioUiAction(NUMBER,...): NUMBER relates to enum EnumKeys in the specific board.h + +#include "simulateduiwidget.h" +#include "ui_simulateduiwidgetJumperT16.h" + +SimulatedUIWidgetJumperT16::SimulatedUIWidgetJumperT16(SimulatorInterface *simulator, QWidget * parent): + SimulatedUIWidget(simulator, parent), + ui(new Ui::SimulatedUIWidgetJumperT16) +{ + RadioUiAction * act; + + ui->setupUi(this); + + // add actions in order of appearance on the help menu + + act = new RadioUiAction(3, QList() << Qt::Key_Up, SIMU_STR_HLP_KEY_UP, SIMU_STR_HLP_ACT_MDL); + addRadioWidget(ui->leftbuttons->addArea(QRect(10, 70, 80, 35), "JumperT16/left_mdl.png", act)); + + act = new RadioUiAction(6, QList() << Qt::Key_Left, SIMU_STR_HLP_KEY_LFT, SIMU_STR_HLP_ACT_SYS); + addRadioWidget(ui->leftbuttons->addArea(QRect(10, 10, 80, 35), "JumperT16/left_sys.png", act)); + + act = new RadioUiAction(5, QList() << Qt::Key_Right, SIMU_STR_HLP_KEY_RGT, SIMU_STR_HLP_ACT_TELE); + addRadioWidget(ui->leftbuttons->addArea(QRect(10, 190, 80, 35), "JumperT16/left_tele.png", act)); + + act = new RadioUiAction(4, QList() << Qt::Key_Down << Qt::Key_Delete << Qt::Key_Escape << Qt::Key_Backspace, + SIMU_STR_HLP_KEY_DN % "
" % SIMU_STR_HLP_KEYS_EXIT, SIMU_STR_HLP_ACT_RTN); + addRadioWidget(ui->rightbuttons->addArea(QRect(35, 10, 80, 35), "JumperT16/right_rtn.png", act)); + + act = new RadioUiAction(1, QList() << Qt::Key_PageDown, SIMU_STR_HLP_KEY_PGDN, SIMU_STR_HLP_ACT_PGDN); + addRadioWidget(ui->leftbuttons->addArea(QRect(10, 131, 80, 35), "JumperT16/left_page.png", act)); + + m_scrollUpAction = new RadioUiAction(-1, QList() << Qt::Key_Minus, SIMU_STR_HLP_KEY_MIN % "|" % SIMU_STR_HLP_MOUSE_UP, SIMU_STR_HLP_ACT_ROT_LFT); + m_scrollDnAction = new RadioUiAction(-1, QList() << Qt::Key_Plus << Qt::Key_Equal, SIMU_STR_HLP_KEY_PLS % "|" % SIMU_STR_HLP_MOUSE_DN, SIMU_STR_HLP_ACT_ROT_RGT); + connectScrollActions(); + + 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(45, 70, 100, 160), "JumperT16/right_ent.png", m_mouseMidClickAction)); + + addRadioWidget(ui->leftbuttons->addArea(QRect(10, 252, 30, 30), "JumperT16/left_scrnsht.png", m_screenshotAction)); + + m_backlightColors << QColor(47, 123, 227); + + setLcd(ui->lcd); +} + +SimulatedUIWidgetJumperT16::~SimulatedUIWidgetJumperT16() +{ + delete ui; +} diff --git a/companion/src/simulation/simulateduiwidgetJumperT16.ui b/companion/src/simulation/simulateduiwidgetJumperT16.ui new file mode 100644 index 000000000..02085d7e7 --- /dev/null +++ b/companion/src/simulation/simulateduiwidgetJumperT16.ui @@ -0,0 +1,197 @@ + + + SimulatedUIWidgetJumperT16 + + + + 0 + 0 + 825 + 292 + + + + + 0 + 0 + + + + + 825 + 292 + + + + + 825 + 292 + + + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 174 + 292 + + + + + 174 + 292 + + + + background:url(:/images/simulator/JumperT16/right.png) + + + + + + + + 0 + 0 + + + + + 480 + 272 + + + + + 480 + 272 + + + + + 5 + + + + + + + + + 0 + 0 + + + + + 174 + 292 + + + + + 174 + 292 + + + + true + + + background:url(:/images/simulator/JumperT16/left.png); + + + + + + + + 0 + 0 + + + + + 480 + 10 + + + + + 480 + 10 + + + + + 5 + + + + background:url(:/images/simulator/JumperT16/top.png) + + + + + + + + 0 + 0 + + + + + 480 + 10 + + + + + 480 + 10 + + + + + 5 + false + + + + background:url(:/images/simulator/JumperT16/bottom.png) + + + + + + + + LcdWidget + QWidget +
lcdwidget.h
+ 1 +
+ + ButtonsWidget + QWidget +
buttonswidget.h
+ 1 +
+
+ + +
diff --git a/companion/src/simulation/simulatorstartupdialog.cpp b/companion/src/simulation/simulatorstartupdialog.cpp index 07766b7da..57272bf99 100644 --- a/companion/src/simulation/simulatorstartupdialog.cpp +++ b/companion/src/simulation/simulatorstartupdialog.cpp @@ -86,7 +86,7 @@ void SimulatorStartupDialog::changeEvent(QEvent *e) // FIXME : need a better way to check for this bool SimulatorStartupDialog::usesCategorizedStorage(const QString & name) { - return name.contains(QRegExp("(x12|x10|horus)", Qt::CaseInsensitive)); + return name.contains(QRegExp("(x12|x10|horus|t16)", Qt::CaseInsensitive)); } bool SimulatorStartupDialog::usesCategorizedStorage() diff --git a/companion/src/simulation/simulatorwidget.cpp b/companion/src/simulation/simulatorwidget.cpp index e5c7e2903..f823769aa 100644 --- a/companion/src/simulation/simulatorwidget.cpp +++ b/companion/src/simulation/simulatorwidget.cpp @@ -87,7 +87,10 @@ SimulatorWidget::SimulatorWidget(QWidget * parent, SimulatorInterface * simulato break; case Board::BOARD_JUMPER_T12: radioUiWidget = new SimulatedUIWidgetJumperT12(simulator, this); - break; + break; + case Board::BOARD_JUMPER_T16: + radioUiWidget = new SimulatedUIWidgetJumperT16(simulator, this); + break; default: radioUiWidget = new SimulatedUIWidget9X(simulator, this); break; diff --git a/launchpad/common/rules b/launchpad/common/rules index 67b06466b..cf96b0fda 100755 --- a/launchpad/common/rules +++ b/launchpad/common/rules @@ -27,6 +27,7 @@ build: cd $(BUILDDIR); cmake $(COMMON_OPTIONS) $(STM32_OPTIONS) -DPCB=X9E ../ ; make libsimulator cd $(BUILDDIR); cmake $(COMMON_OPTIONS) $(STM32_OPTIONS) -DPCB=X12S ../ ; make libsimulator cd $(BUILDDIR); cmake $(COMMON_OPTIONS) $(STM32_OPTIONS) -DPCB=JUMPERT12 ../ ; make libsimulator + cd $(BUILDDIR); cmake $(COMMON_OPTIONS) $(STM32_OPTIONS) -DPCB=JUMPERT16 ../ ; make libsimulator make -C $(BUILDDIR) companion22 simulator22 diff --git a/radio/sdcard/horus/THEMES/Darkblue/t16.bmp b/radio/sdcard/horus/THEMES/Darkblue/t16.bmp new file mode 100755 index 000000000..ac0d16cf6 Binary files /dev/null and b/radio/sdcard/horus/THEMES/Darkblue/t16.bmp differ diff --git a/radio/sdcard/horus/THEMES/Default/t16.bmp b/radio/sdcard/horus/THEMES/Default/t16.bmp new file mode 100755 index 000000000..ac0d16cf6 Binary files /dev/null and b/radio/sdcard/horus/THEMES/Default/t16.bmp differ diff --git a/radio/src/dataconstants.h b/radio/src/dataconstants.h index 0052b0f6a..f4bc25566 100644 --- a/radio/src/dataconstants.h +++ b/radio/src/dataconstants.h @@ -208,20 +208,28 @@ enum TrainerMode { #if defined(BLUETOOTH) #define TRAINER_MODE_MAX() TRAINER_MODE_SLAVE_BLUETOOTH +#elif defined(RADIO_T16) + #define TRAINER_MODE_MAX() TRAINER_MODE_SLAVE #elif defined(PCBX7) || defined(PCBXLITE) #define TRAINER_MODE_MAX() TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE #else #define TRAINER_MODE_MAX() HAS_WIRELESS_TRAINER_HARDWARE() ? TRAINER_MODE_MASTER_BATTERY_COMPARTMENT : TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE #endif -#if defined(PCBTARANIS) || defined(PCBHORUS) +#if defined(HARDWARE_INTERNAL_MODULE) #define IS_INTERNAL_MODULE_ENABLED() (g_model.moduleData[INTERNAL_MODULE].type != MODULE_TYPE_NONE) -#elif defined(PCBSKY9X) +#else #define IS_INTERNAL_MODULE_ENABLED() (false) #endif #define IS_EXTERNAL_MODULE_ENABLED() (g_model.moduleData[EXTERNAL_MODULE].type != MODULE_TYPE_NONE) +#if defined(HARDWARE_INTERNAL_MODULE) + #define IS_MODULE_ENABLED(moduleIdx) (moduleIdx==INTERNAL_MODULE ? IS_INTERNAL_MODULE_ENABLED() : moduleIdx==EXTERNAL_MODULE ? IS_EXTERNAL_MODULE_ENABLED() : false) +#else + #define IS_MODULE_ENABLED(moduleIdx) (moduleIdx==EXTERNAL_MODULE ? IS_EXTERNAL_MODULE_ENABLED() : false) +#endif + enum UartModes { #if defined(CLI) || defined(DEBUG) UART_MODE_DEBUG, diff --git a/radio/src/fifo.h b/radio/src/fifo.h index 35daef7ef..9aff60f57 100644 --- a/radio/src/fifo.h +++ b/radio/src/fifo.h @@ -77,11 +77,6 @@ class Fifo return (next == ridx); } - void flush() - { - while (!isEmpty()); - } - uint32_t size() const { return (N + widx - ridx) & (N - 1); diff --git a/radio/src/gui/128x64/model_setup.cpp b/radio/src/gui/128x64/model_setup.cpp index b89afc152..b70edf616 100644 --- a/radio/src/gui/128x64/model_setup.cpp +++ b/radio/src/gui/128x64/model_setup.cpp @@ -176,9 +176,6 @@ enum MenuModelSetupItems { #define SW_WARN_ROWS uint8_t(NAVIGATION_LINE_BY_LINE|(getSwitchWarningsCount()-1)), uint8_t(getSwitchWarningsCount() > MAX_SWITCH_PER_LINE ? TITLE_ROW : HIDDEN_ROW) #endif -#define IF_INTERNAL_MODULE_ON(x) (IS_INTERNAL_MODULE_ENABLED()? (uint8_t)(x) : HIDDEN_ROW) -#define IF_EXTERNAL_MODULE_ON(x) (IS_EXTERNAL_MODULE_ENABLED()? (uint8_t)(x) : HIDDEN_ROW) - #if defined(INTERNAL_MODULE_PXX1) #define INTERNAL_MODULE_TYPE_ROWS ((isModuleXJT(INTERNAL_MODULE) || isModulePXX2(INTERNAL_MODULE)) ? (uint8_t)1 : (uint8_t)0) // Module type + RF protocols #else @@ -191,8 +188,6 @@ enum MenuModelSetupItems { #define OUTPUT_TYPE_ROW #endif -#define PORT_CHANNELS_ROWS(x) (x==EXTERNAL_MODULE ? EXTERNAL_MODULE_CHANNELS_ROWS : 0) - inline uint8_t EXTERNAL_MODULE_TYPE_ROW() { if (isModuleXJT(EXTERNAL_MODULE) || isModuleR9MNonAccess(EXTERNAL_MODULE) || isModuleDSM2(EXTERNAL_MODULE)) @@ -283,7 +278,7 @@ void onBluetoothConnectMenu(const char * result) #define INTERNAL_MODULE_ROWS \ LABEL(InternalModule), \ INTERNAL_MODULE_TYPE_ROWS, \ - INTERNAL_MODULE_CHANNELS_ROWS, \ + MODULE_CHANNELS_ROWS(INTERNAL_MODULE), \ IF_NOT_ACCESS_MODULE_RF(INTERNAL_MODULE, IF_INTERNAL_MODULE_ON(isModuleRxNumAvailable(INTERNAL_MODULE) ? (uint8_t)2 : (uint8_t)1)), \ IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 0), /* RxNum */ \ EXTERNAL_ANTENNA_ROW \ @@ -334,13 +329,13 @@ void menuModelSetup(event_t event) LABEL(ExternalModule), EXTERNAL_MODULE_TYPE_ROW(), MULTIMODULE_SUBTYPE_ROWS(EXTERNAL_MODULE) - EXTERNAL_MODULE_POWER_ROW, - MULTIMODULE_STATUS_ROWS - EXTERNAL_MODULE_CHANNELS_ROWS, - IF_NOT_ACCESS_MODULE_RF(EXTERNAL_MODULE, EXTERNAL_MODULE_BIND_ROWS), // line reused for PPM: PPM settings + 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 - IF_NOT_PXX2_MODULE(EXTERNAL_MODULE, EXTERNAL_MODULE_OPTION_ROW), - MULTIMODULE_MODULE_ROWS + IF_NOT_PXX2_MODULE(EXTERNAL_MODULE, MODULE_OPTION_ROW(EXTERNAL_MODULE)), + MULTIMODULE_MODULE_ROWS(EXTERNAL_MODULE) FAILSAFE_ROWS(EXTERNAL_MODULE), IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 1), // Range check and Register buttons IF_PXX2_MODULE(EXTERNAL_MODULE, 0), // Module options @@ -355,13 +350,13 @@ void menuModelSetup(event_t event) LABEL(ExternalModule), EXTERNAL_MODULE_TYPE_ROW(), MULTIMODULE_SUBTYPE_ROWS(EXTERNAL_MODULE) - MULTIMODULE_STATUS_ROWS - EXTERNAL_MODULE_CHANNELS_ROWS, - EXTERNAL_MODULE_BIND_ROWS, + MULTIMODULE_STATUS_ROWS(EXTERNAL_MODULE) + MODULE_CHANNELS_ROWS(EXTERNAL_MODULE), + MODULE_BIND_ROWS(EXTERNAL_MODULE), OUTPUT_TYPE_ROW - EXTERNAL_MODULE_OPTION_ROW, - MULTIMODULE_MODULE_ROWS - EXTERNAL_MODULE_POWER_ROW, + MODULE_OPTION_ROW(EXTERNAL_MODULE), + MULTIMODULE_MODULE_ROWS(EXTERNAL_MODULE) + MODULE_POWER_ROW(EXTERNAL_MODULE), FAILSAFE_ROWS(EXTERNAL_MODULE), EXTRA_MODULE_ROWS TRAINER_ROWS @@ -1066,26 +1061,24 @@ void menuModelSetup(event_t event) uint8_t moduleIdx = CURRENT_MODULE_EDITED(k); ModuleData & moduleData = g_model.moduleData[moduleIdx]; lcdDrawTextAlignedLeft(y, STR_CHANNELRANGE); - if ((int8_t)PORT_CHANNELS_ROWS(moduleIdx) >= 0) { - lcdDrawText(MODEL_SETUP_2ND_COLUMN, y, STR_CH, menuHorizontalPosition==0 ? attr : 0); - lcdDrawNumber(lcdLastRightPos, y, moduleData.channelsStart+1, LEFT | (menuHorizontalPosition==0 ? attr : 0)); - lcdDrawChar(lcdLastRightPos, y, '-'); - lcdDrawNumber(lcdLastRightPos + FW+1, y, moduleData.channelsStart+sentModuleChannels(moduleIdx), LEFT | (menuHorizontalPosition==1 ? attr : 0)); - const char * delay = getModuleDelay(moduleIdx); - if (delay) - lcdDrawText(lcdLastRightPos+4, y, delay, SMLSIZE); - if (attr && s_editMode > 0) { - switch (menuHorizontalPosition) { - case 0: - CHECK_INCDEC_MODELVAR_ZERO(event, moduleData.channelsStart, 32-8-moduleData.channelsCount); - break; - case 1: - CHECK_INCDEC_MODELVAR_CHECK(event, moduleData.channelsCount, -4, min(maxModuleChannels_M8(moduleIdx), 32-8-moduleData.channelsStart), moduleData.type == MODULE_TYPE_ISRM_PXX2 ? isPxx2IsrmChannelsCountAllowed : nullptr); - if (checkIncDec_Ret && moduleData.type == MODULE_TYPE_PPM) { - setDefaultPpmFrameLength(moduleIdx); - } - break; - } + lcdDrawText(MODEL_SETUP_2ND_COLUMN, y, STR_CH, menuHorizontalPosition==0 ? attr : 0); + lcdDrawNumber(lcdLastRightPos, y, moduleData.channelsStart+1, LEFT | (menuHorizontalPosition==0 ? attr : 0)); + lcdDrawChar(lcdLastRightPos, y, '-'); + lcdDrawNumber(lcdLastRightPos + FW+1, y, moduleData.channelsStart+sentModuleChannels(moduleIdx), LEFT | (menuHorizontalPosition==1 ? attr : 0)); + const char * delay = getModuleDelay(moduleIdx); + if (delay) + lcdDrawText(lcdLastRightPos+4, y, delay, SMLSIZE); + if (attr && s_editMode > 0) { + switch (menuHorizontalPosition) { + case 0: + CHECK_INCDEC_MODELVAR_ZERO(event, moduleData.channelsStart, 32-8-moduleData.channelsCount); + break; + case 1: + CHECK_INCDEC_MODELVAR_CHECK(event, moduleData.channelsCount, -4, min(maxModuleChannels_M8(moduleIdx), 32-8-moduleData.channelsStart), moduleData.type == MODULE_TYPE_ISRM_PXX2 ? isPxx2IsrmChannelsCountAllowed : nullptr); + if (checkIncDec_Ret && moduleData.type == MODULE_TYPE_PPM) { + setDefaultPpmFrameLength(moduleIdx); + } + break; } } break; @@ -1270,8 +1263,8 @@ void menuModelSetup(event_t event) lcdDrawText(MODEL_SETUP_2ND_COLUMN+MODEL_SETUP_RANGE_OFS+xOffsetBind, y, STR_MODULE_RANGE, l_posHorz==2 ? attr : 0); uint8_t newFlag = 0; #if defined(MULTIMODULE) - if (multiBindStatus == MULTI_BIND_FINISHED) { - multiBindStatus = MULTI_NORMAL_OPERATION; + if (getMultiBindStatus(moduleIdx) == MULTI_BIND_FINISHED) { + setMultiBindStatus(moduleIdx, MULTI_NORMAL_OPERATION); s_editMode = 0; } #endif @@ -1321,7 +1314,7 @@ void menuModelSetup(event_t event) #if defined(MULTIMODULE) if (newFlag == MODULE_MODE_BIND) { - multiBindStatus = MULTI_BIND_INITIATED; + setMultiBindStatus(moduleIdx, MULTI_BIND_INITIATED); } #endif @@ -1532,7 +1525,7 @@ void menuModelSetup(event_t event) lcdDrawTextAlignedLeft(y, STR_MODULE_STATUS); char statusText[64]; - multiModuleStatus.getStatusString(statusText); + getMultiModuleStatus(EXTERNAL_MODULE).getStatusString(statusText); lcdDrawText(MODEL_SETUP_2ND_COLUMN, y, statusText); break; } @@ -1541,7 +1534,7 @@ void menuModelSetup(event_t event) lcdDrawTextAlignedLeft(y, STR_MODULE_SYNC); char statusText[64]; - multiSyncStatus.getRefreshString(statusText); + getMultiSyncStatus(EXTERNAL_MODULE).getRefreshString(statusText); lcdDrawText(MODEL_SETUP_2ND_COLUMN, y, statusText); break; } diff --git a/radio/src/gui/212x64/model_setup.cpp b/radio/src/gui/212x64/model_setup.cpp index 4637d8634..5ae189763 100644 --- a/radio/src/gui/212x64/model_setup.cpp +++ b/radio/src/gui/212x64/model_setup.cpp @@ -230,8 +230,6 @@ void editTimerCountdown(int timerIdx, coord_t y, LcdFlags attr, event_t event) #define INTERNAL_MODULE_TYPE_ROWS (0) // Module type + RF protocols #endif -#define PORT_CHANNELS_ROWS(x) (x==INTERNAL_MODULE ? INTERNAL_MODULE_CHANNELS_ROWS : (x==EXTERNAL_MODULE ? EXTERNAL_MODULE_CHANNELS_ROWS : 1)) - #define TRAINER_CHANNELS_ROW (IS_SLAVE_TRAINER() ? (uint8_t)1 : HIDDEN_ROW) #define TRAINER_PPM_PARAMS_ROW (g_model.trainerData.mode == TRAINER_MODE_SLAVE ? (uint8_t)2 : HIDDEN_ROW) #define TRAINER_BLUETOOTH_M_ROW ((bluetooth.distantAddr[0] == '\0' || bluetooth.state == BLUETOOTH_STATE_CONNECTED) ? (uint8_t)0 : (uint8_t)1) @@ -352,7 +350,7 @@ void menuModelSetup(event_t event) LABEL(InternalModule), INTERNAL_MODULE_TYPE_ROWS, - INTERNAL_MODULE_CHANNELS_ROWS, + MODULE_CHANNELS_ROWS(INTERNAL_MODULE), IF_NOT_ACCESS_MODULE_RF(INTERNAL_MODULE, IF_INTERNAL_MODULE_ON(isModuleFailsafeAvailable(INTERNAL_MODULE) ? (uint8_t)2 : (uint8_t)1)), IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 0), // RxNum for ACCESS IF_INTERNAL_MODULE_ON(FAILSAFE_ROWS(INTERNAL_MODULE)), // Failsafe @@ -364,13 +362,13 @@ void menuModelSetup(event_t event) LABEL(ExternalModule), EXTERNAL_MODULE_TYPE_ROW(), - MULTIMODULE_STATUS_ROWS - EXTERNAL_MODULE_CHANNELS_ROWS, - IF_NOT_ACCESS_MODULE_RF(EXTERNAL_MODULE, EXTERNAL_MODULE_BIND_ROWS), + MULTIMODULE_STATUS_ROWS(EXTERNAL_MODULE) + MODULE_CHANNELS_ROWS(EXTERNAL_MODULE), + IF_NOT_ACCESS_MODULE_RF(EXTERNAL_MODULE, MODULE_BIND_ROWS(EXTERNAL_MODULE)), IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 0), // RxNum for ACCESS - IF_NOT_PXX2_MODULE(EXTERNAL_MODULE, EXTERNAL_MODULE_OPTION_ROW), - MULTIMODULE_MODULE_ROWS - EXTERNAL_MODULE_POWER_ROW, + IF_NOT_PXX2_MODULE(EXTERNAL_MODULE, MODULE_OPTION_ROW(EXTERNAL_MODULE)), + MULTIMODULE_MODULE_ROWS(EXTERNAL_MODULE) + MODULE_POWER_ROW(EXTERNAL_MODULE), FAILSAFE_ROWS(EXTERNAL_MODULE), IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 1), // Range check and Register buttons IF_PXX2_MODULE(EXTERNAL_MODULE, 0), // Module options @@ -1019,7 +1017,7 @@ void menuModelSetup(event_t event) uint8_t moduleIdx = CURRENT_MODULE_EDITED(k); ModuleData & moduleData = g_model.moduleData[moduleIdx]; lcdDrawTextAlignedLeft(y, STR_CHANNELRANGE); - if ((int8_t)PORT_CHANNELS_ROWS(moduleIdx) >= 0) { + if ((int8_t)MODULE_CHANNELS_ROWS(moduleIdx) >= 0) { lcdDrawText(MODEL_SETUP_2ND_COLUMN, y, STR_CH, menuHorizontalPosition==0 ? attr : 0); lcdDrawNumber(lcdLastRightPos, y, moduleData.channelsStart+1, LEFT | (menuHorizontalPosition==0 ? attr : 0)); lcdDrawChar(lcdLastRightPos, y, '-'); @@ -1144,8 +1142,8 @@ void menuModelSetup(event_t event) lcdDrawText(MODEL_SETUP_2ND_COLUMN+MODEL_SETUP_RANGE_OFS+xOffsetBind, y, STR_MODULE_RANGE, l_posHorz==2 ? attr : 0); uint8_t newFlag = 0; #if defined(MULTIMODULE) - if (multiBindStatus == MULTI_BIND_FINISHED) { - multiBindStatus = MULTI_NORMAL_OPERATION; + if (getMultiBindStatus(moduleIdx) == MULTI_BIND_FINISHED) { + setMultiBindStatus(moduleIdx, MULTI_NORMAL_OPERATION); s_editMode = 0; } #endif @@ -1178,7 +1176,7 @@ void menuModelSetup(event_t event) moduleState[moduleIdx].mode = newFlag; #if defined(MULTIMODULE) if (newFlag == MODULE_MODE_BIND) - multiBindStatus = MULTI_BIND_INITIATED; + setMultiBindStatus(moduleIdx, MULTI_BIND_INITIATED); #endif } } @@ -1317,7 +1315,7 @@ void menuModelSetup(event_t event) { lcdDrawTextAlignedLeft(y, STR_MODULE_STATUS); char statusText[64]; - multiModuleStatus.getStatusString(statusText); + getMultiModuleStatus(EXTERNAL_MODULE).getStatusString(statusText); lcdDrawText(MODEL_SETUP_2ND_COLUMN, y, statusText); break; } @@ -1326,7 +1324,7 @@ void menuModelSetup(event_t event) { lcdDrawTextAlignedLeft(y, STR_MODULE_SYNC); char statusText[64]; - multiSyncStatus.getRefreshString(statusText); + getMultiSyncStatus(EXTERNAL_MODULE).getRefreshString(statusText); lcdDrawText(MODEL_SETUP_2ND_COLUMN, y, statusText); break; } diff --git a/radio/src/gui/480x272/model_setup.cpp b/radio/src/gui/480x272/model_setup.cpp index c759bfb77..ed166cb1e 100644 --- a/radio/src/gui/480x272/model_setup.cpp +++ b/radio/src/gui/480x272/model_setup.cpp @@ -66,22 +66,31 @@ enum MenuModelSetupItems { #if defined(PXX2) ITEM_MODEL_SETUP_REGISTRATION_ID, #endif - +#if defined(HARDWARE_INTERNAL_MODULE) ITEM_MODEL_SETUP_INTERNAL_MODULE_LABEL, ITEM_MODEL_SETUP_INTERNAL_MODULE_TYPE, +#if defined(INTERNAL_MODULE_MULTI) + 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_BIND, ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_MODEL_NUM, + ITEM_MODEL_SETUP_INTERNAL_MODULE_OPTIONS, +#if defined(INTERNAL_MODULE_MULTI) + ITEM_MODEL_SETUP_INTERNAL_MODULE_AUTOBIND, +#endif #if defined(INTERNAL_MODULE_PXX1) && defined(EXTERNAL_ANTENNA) ITEM_MODEL_SETUP_INTERNAL_MODULE_ANTENNA, #endif + ITEM_MODEL_SETUP_INTERNAL_MODULE_POWER, ITEM_MODEL_SETUP_INTERNAL_MODULE_FAILSAFE, ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_REGISTER_RANGE, ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_OPTIONS, ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_RECEIVER_1, ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_RECEIVER_2, ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_RECEIVER_3, - +#endif ITEM_MODEL_SETUP_EXTERNAL_MODULE_LABEL, ITEM_MODEL_SETUP_EXTERNAL_MODULE_TYPE, #if defined(MULTIMODULE) @@ -122,7 +131,11 @@ enum MenuModelSetupItems { #define MODEL_SETUP_SLIDPOT_SPACING 45 #define CURRENT_MODULE_EDITED(k) (k >= ITEM_MODEL_SETUP_EXTERNAL_MODULE_LABEL ? EXTERNAL_MODULE : INTERNAL_MODULE) +#if defined(HARDWARE_INTERNAL_MODULE) #define CURRENT_RECEIVER_EDITED(k) (k - (k >= ITEM_MODEL_SETUP_EXTERNAL_MODULE_LABEL ? ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_RECEIVER_1 : ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_RECEIVER_1)) +#else +#define CURRENT_RECEIVER_EDITED(k) (EXTERNAL_MODULE) +#endif #include "common/stdlcd/model_setup_pxx1.cpp" @@ -468,19 +481,15 @@ int getSwitchWarningsCount() #define IF_ACCESS_MODULE_RF(module, xxx) (isModuleRFAccess(module) ? (uint8_t)(xxx) : HIDDEN_ROW) #define IF_NOT_ACCESS_MODULE_RF(module, xxx) (isModuleRFAccess(module) ? HIDDEN_ROW : (uint8_t)(xxx)) -#define INTERNAL_MODULE_TYPE_ROWS ((isModuleXJT(INTERNAL_MODULE) || isModulePXX2(INTERNAL_MODULE)) ? (uint8_t)1 : (uint8_t)0) // Module type + RF protocols - -#define MODULE_CHANNELS_ROWS(x) (x==INTERNAL_MODULE ? INTERNAL_MODULE_CHANNELS_ROWS : (x==EXTERNAL_MODULE ? EXTERNAL_MODULE_CHANNELS_ROWS : 1)) - #define TIMER_ROWS(x) NAVIGATION_LINE_BY_LINE|1, 0, 0, 0, g_model.timers[x].countdownBeep != COUNTDOWN_SILENT ? (uint8_t)1 : (uint8_t)0 -inline uint8_t EXTERNAL_MODULE_TYPE_ROW() +inline uint8_t MODULE_TYPE_ROWS(int moduleIdx) { - if (isModuleXJT(EXTERNAL_MODULE) || isModuleR9MNonAccess(EXTERNAL_MODULE) || isModuleDSM2(EXTERNAL_MODULE)) + if (isModuleXJT(moduleIdx) || isModuleR9MNonAccess(moduleIdx) || isModuleDSM2(moduleIdx) || isModulePXX2(moduleIdx)) return 1; #if defined(MULTIMODULE) - else if (isModuleMultimodule(EXTERNAL_MODULE)) { - return 1 + MULTIMODULE_RFPROTO_COLUMNS(EXTERNAL_MODULE); + else if (isModuleMultimodule(moduleIdx)) { + return 1 + MULTIMODULE_RFPROTO_COLUMNS(moduleIdx); } #endif else @@ -495,6 +504,7 @@ inline uint8_t EXTERNAL_MODULE_TYPE_ROW() #define TIMERS_ROWS TIMER_ROWS(0), TIMER_ROWS(1), TIMER_ROWS(2) #endif +#if defined(BLUETOOTH) #define TRAINER_CHANNELS_ROW (g_model.trainerData.mode == TRAINER_MODE_SLAVE ? (uint8_t)1 : (g_model.trainerData.mode == TRAINER_MODE_SLAVE_BLUETOOTH ? (uint8_t)0 : HIDDEN_ROW)) #define TRAINER_PPM_PARAMS_ROW (g_model.trainerData.mode == TRAINER_MODE_SLAVE ? (uint8_t)2 : HIDDEN_ROW) #define IF_BT_TRAINER_ON(x) (g_eeGeneral.bluetoothMode == BLUETOOTH_TRAINER ? (uint8_t)(x) : HIDDEN_ROW) @@ -502,6 +512,11 @@ inline uint8_t EXTERNAL_MODULE_TYPE_ROW() #define TRAINER_BLUETOOTH_S_ROW (bluetooth.distantAddr[0] == '\0' ? HIDDEN_ROW : LABEL()) #define TRAINER_BLUETOOTH_ROW (g_model.trainerData.mode == TRAINER_MODE_MASTER_BLUETOOTH ? TRAINER_BLUETOOTH_M_ROW : (g_model.trainerData.mode == TRAINER_MODE_SLAVE_BLUETOOTH ? TRAINER_BLUETOOTH_S_ROW : HIDDEN_ROW)) #define TRAINER_ROWS LABEL(Trainer), 0, IF_BT_TRAINER_ON(TRAINER_BLUETOOTH_ROW), TRAINER_CHANNELS_ROW, TRAINER_PPM_PARAMS_ROW +#else +#define TRAINER_CHANNELS_ROW (g_model.trainerData.mode == TRAINER_MODE_SLAVE ? (uint8_t)1 : HIDDEN_ROW) +#define TRAINER_PPM_PARAMS_ROW (HIDDEN_ROW) +#define TRAINER_ROWS LABEL(Trainer), 0, TRAINER_CHANNELS_ROW, TRAINER_PPM_PARAMS_ROW +#endif #if defined(PXX2) #define REGISTRATION_ID_ROWS uint8_t((isDefaultModelRegistrationID() || (warningText && popupFunc == runPopupRegister)) ? HIDDEN_ROW : READONLY_ROW), @@ -527,11 +542,35 @@ void onModelAntennaSwitchConfirm(const char * result) #define EXTERNAL_ANTENNA_ROW #endif +#if defined(HARDWARE_INTERNAL_MODULE) + #define INTERNAL_MODULE_ROWS \ + LABEL(InternalModule), \ + MODULE_TYPE_ROWS(INTERNAL_MODULE), \ + MULTIMODULE_STATUS_ROWS(INTERNAL_MODULE) \ + MODULE_CHANNELS_ROWS(INTERNAL_MODULE), \ + IF_NOT_ACCESS_MODULE_RF(INTERNAL_MODULE, IF_INTERNAL_MODULE_ON(IF_INTERNAL_MODULE_ON(isModuleRxNumAvailable(INTERNAL_MODULE) ? (uint8_t)2 : (uint8_t)1))), \ + IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 0), \ + MODULE_OPTION_ROW(INTERNAL_MODULE), \ + MULTIMODULE_MODULE_ROWS(INTERNAL_MODULE) \ + EXTERNAL_ANTENNA_ROW \ + MODULE_POWER_ROW(INTERNAL_MODULE), \ + IF_INTERNAL_MODULE_ON(FAILSAFE_ROWS(INTERNAL_MODULE)), \ + IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 1), /* Range check and Register buttons */ \ + IF_PXX2_MODULE(INTERNAL_MODULE, 0), /* Module options */ \ + IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 0), /* Receiver 1 */ \ + IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 0), /* Receiver 2 */ \ + IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 0), /* Receiver 3 */ +#else + #define INTERNAL_MODULE_ROWS +#endif + + bool menuModelSetup(event_t event) { bool CURSOR_ON_CELL = (menuHorizontalPosition >= 0); int8_t old_editMode = s_editMode; + MENU(STR_MENUSETUP, MODEL_ICONS, menuTabModel, MENU_MODEL_SETUP, ITEM_MODEL_SETUP_MAX, { 0, // Model name 0, // Model bitmap @@ -559,28 +598,17 @@ bool menuModelSetup(event_t event) REGISTRATION_ID_ROWS - LABEL(InternalModule), - INTERNAL_MODULE_TYPE_ROWS, - INTERNAL_MODULE_CHANNELS_ROWS, - IF_NOT_ACCESS_MODULE_RF(INTERNAL_MODULE, IF_INTERNAL_MODULE_ON(IF_INTERNAL_MODULE_ON(isModuleRxNumAvailable(INTERNAL_MODULE) ? (uint8_t)2 : (uint8_t)1))), - IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 0), // RxNum - EXTERNAL_ANTENNA_ROW - IF_INTERNAL_MODULE_ON(FAILSAFE_ROWS(INTERNAL_MODULE)), - IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 1), /* Range check and Register buttons */ \ - IF_PXX2_MODULE(INTERNAL_MODULE, 0), /* Module options */ \ - IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 0), /* Receiver 1 */ \ - IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 0), /* Receiver 2 */ \ - IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 0), /* Receiver 3 */ + INTERNAL_MODULE_ROWS LABEL(ExternalModule), - EXTERNAL_MODULE_TYPE_ROW(), - MULTIMODULE_STATUS_ROWS - EXTERNAL_MODULE_CHANNELS_ROWS, - IF_NOT_ACCESS_MODULE_RF(EXTERNAL_MODULE, EXTERNAL_MODULE_BIND_ROWS), + MODULE_TYPE_ROWS(EXTERNAL_MODULE), + MULTIMODULE_STATUS_ROWS(EXTERNAL_MODULE) + MODULE_CHANNELS_ROWS(EXTERNAL_MODULE), + IF_NOT_ACCESS_MODULE_RF(EXTERNAL_MODULE, MODULE_BIND_ROWS(EXTERNAL_MODULE)), IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 0), // RxNum for ACCESS - IF_NOT_PXX2_MODULE(EXTERNAL_MODULE, EXTERNAL_MODULE_OPTION_ROW), - MULTIMODULE_MODULE_ROWS - EXTERNAL_MODULE_POWER_ROW, + IF_NOT_PXX2_MODULE(EXTERNAL_MODULE, MODULE_OPTION_ROW(EXTERNAL_MODULE)), + MULTIMODULE_MODULE_ROWS(EXTERNAL_MODULE) + MODULE_POWER_ROW(EXTERNAL_MODULE), FAILSAFE_ROWS(EXTERNAL_MODULE), IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 1), // Range check and Register buttons IF_PXX2_MODULE(EXTERNAL_MODULE, 0), // Module options @@ -613,7 +641,7 @@ bool menuModelSetup(event_t event) if (mstate_tab[j] == HIDDEN_ROW) k++; } - + uint8_t moduleIdx = CURRENT_MODULE_EDITED(k); LcdFlags blink = ((s_editMode>0) ? BLINK|INVERS : INVERS); LcdFlags attr = (sub == k ? blink : 0); @@ -945,10 +973,12 @@ bool menuModelSetup(event_t event) if (attr) g_model.noGlobalFunctions = !checkIncDecModel(event, !g_model.noGlobalFunctions, 0, 1); break; +#if defined(HARDWARE_INTERNAL_MODULE) case ITEM_MODEL_SETUP_INTERNAL_MODULE_LABEL: lcdDrawText(MENUS_MARGIN_LEFT, y, STR_INTERNALRF); break; +#if !defined(INTERNAL_MODULE_MULTI) case ITEM_MODEL_SETUP_INTERNAL_MODULE_TYPE: lcdDrawText(MENUS_MARGIN_LEFT + INDENT_WIDTH, y, STR_MODE); lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_INTERNAL_MODULE_PROTOCOLS, g_model.moduleData[INTERNAL_MODULE].type, menuHorizontalPosition==0 ? attr : 0); @@ -976,6 +1006,7 @@ bool menuModelSetup(event_t event) } } break; +#endif #if defined(INTERNAL_MODULE_PXX1) && defined(EXTERNAL_ANTENNA) case ITEM_MODEL_SETUP_INTERNAL_MODULE_ANTENNA: @@ -993,111 +1024,124 @@ bool menuModelSetup(event_t event) } break; #endif - +#endif case ITEM_MODEL_SETUP_EXTERNAL_MODULE_LABEL: lcdDrawText(MENUS_MARGIN_LEFT, y, STR_EXTERNALRF); break; +#if defined(INTERNAL_MODULE_MULTI) + case ITEM_MODEL_SETUP_INTERNAL_MODULE_TYPE: +#endif case ITEM_MODEL_SETUP_EXTERNAL_MODULE_TYPE: lcdDrawText(MENUS_MARGIN_LEFT + INDENT_WIDTH, y, STR_MODE); - lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_EXTERNAL_MODULE_PROTOCOLS, g_model.moduleData[EXTERNAL_MODULE].type, menuHorizontalPosition==0 ? attr : 0); - if (isModuleXJT(EXTERNAL_MODULE)) - lcdDrawTextAtIndex(MODEL_SETUP_3RD_COLUMN, y, STR_XJT_ACCST_RF_PROTOCOLS, 1+g_model.moduleData[EXTERNAL_MODULE].subType, (menuHorizontalPosition==1 ? attr : 0)); - else if (isModuleDSM2(EXTERNAL_MODULE)) - lcdDrawTextAtIndex(MODEL_SETUP_3RD_COLUMN, y, STR_DSM_PROTOCOLS, g_model.moduleData[EXTERNAL_MODULE].rfProtocol, (menuHorizontalPosition==1 ? attr : 0)); - else if (isModuleR9MNonAccess(EXTERNAL_MODULE)) - lcdDrawTextAtIndex(MODEL_SETUP_3RD_COLUMN, y, STR_R9M_REGION, g_model.moduleData[EXTERNAL_MODULE].subType, (menuHorizontalPosition==1 ? attr : 0)); + lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_EXTERNAL_MODULE_PROTOCOLS, g_model.moduleData[moduleIdx].type, menuHorizontalPosition==0 ? attr : 0); + if (isModuleXJT(moduleIdx)) + lcdDrawTextAtIndex(MODEL_SETUP_3RD_COLUMN, y, STR_XJT_ACCST_RF_PROTOCOLS, 1+g_model.moduleData[moduleIdx].subType, (menuHorizontalPosition==1 ? attr : 0)); + else if (isModuleDSM2(moduleIdx)) + lcdDrawTextAtIndex(MODEL_SETUP_3RD_COLUMN, y, STR_DSM_PROTOCOLS, g_model.moduleData[moduleIdx].rfProtocol, (menuHorizontalPosition==1 ? attr : 0)); + else if (isModuleR9MNonAccess(moduleIdx)) + lcdDrawTextAtIndex(MODEL_SETUP_3RD_COLUMN, y, STR_R9M_REGION, g_model.moduleData[moduleIdx].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) { + 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[EXTERNAL_MODULE].subType, menuHorizontalPosition==3 ? 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[EXTERNAL_MODULE].subType, menuHorizontalPosition==2 ? attr : 0); + lcdDrawTextAtIndex(MODEL_SETUP_4TH_COLUMN, y, pdef->subTypeString, g_model.moduleData[moduleIdx].subType, menuHorizontalPosition==2 ? attr : 0); } } #endif + if (attr && menuHorizontalPosition == 0 && moduleIdx == EXTERNAL_MODULE) { + if (s_editMode > 0) + EXTERNAL_MODULE_OFF(); + else + EXTERNAL_MODULE_ON(); + } if (attr) { if (s_editMode > 0) { switch (menuHorizontalPosition) { case 0: { - uint8_t moduleType = checkIncDec(event, g_model.moduleData[EXTERNAL_MODULE].type, MODULE_TYPE_NONE, MODULE_TYPE_MAX, EE_MODEL, isExternalModuleAvailable); +#if defined(HARDWARE_INTERNAL_MODULE) + IsValueAvailable checkFun = moduleIdx == 0 ? isInternalModuleAvailable : isExternalModuleAvailable; +#else + IsValueAvailable checkFun = isExternalModuleAvailable; +#endif + uint8_t moduleType = checkIncDec(event, g_model.moduleData[moduleIdx].type, MODULE_TYPE_NONE, MODULE_TYPE_MAX, EE_MODEL, checkFun); if (checkIncDec_Ret) { - setModuleType(EXTERNAL_MODULE, moduleType); + setModuleType(moduleIdx, moduleType); } break; } - case 1: - if (isModuleDSM2(EXTERNAL_MODULE)) - CHECK_INCDEC_MODELVAR(event, g_model.moduleData[EXTERNAL_MODULE].rfProtocol, DSM2_PROTO_LP45, DSM2_PROTO_DSMX); + if (isModuleDSM2(moduleIdx)) + CHECK_INCDEC_MODELVAR(event, g_model.moduleData[moduleIdx].rfProtocol, DSM2_PROTO_LP45, DSM2_PROTO_DSMX); #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); + 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(event, multiRfProto, MODULE_SUBTYPE_MULTI_FIRST, MODULE_SUBTYPE_MULTI_LAST); 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].subType = 0; + 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].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) { - g_model.moduleData[EXTERNAL_MODULE].multi.autoBindMode = 1; + if (g_model.moduleData[moduleIdx].getMultiProtocol(true) == MODULE_SUBTYPE_MULTI_DSM2) { + g_model.moduleData[moduleIdx].multi.autoBindMode = 1; } else { - g_model.moduleData[EXTERNAL_MODULE].multi.autoBindMode = 0; + g_model.moduleData[moduleIdx].multi.autoBindMode = 0; } - g_model.moduleData[EXTERNAL_MODULE].multi.optionValue = 0; + g_model.moduleData[moduleIdx].multi.optionValue = 0; } } #endif - else if (isModuleR9MNonAccess(EXTERNAL_MODULE)) { - g_model.moduleData[EXTERNAL_MODULE].subType = checkIncDec(event, g_model.moduleData[EXTERNAL_MODULE].subType, MODULE_SUBTYPE_R9M_FCC, + else if (isModuleR9MNonAccess(moduleIdx)) { + g_model.moduleData[moduleIdx].subType = checkIncDec(event, g_model.moduleData[moduleIdx].subType, MODULE_SUBTYPE_R9M_FCC, MODULE_SUBTYPE_R9M_LAST, EE_MODEL, isR9MModeAvailable); } else { - CHECK_INCDEC_MODELVAR(event, g_model.moduleData[EXTERNAL_MODULE].subType, MODULE_SUBTYPE_PXX1_ACCST_D16, MODULE_SUBTYPE_PXX1_LAST); + CHECK_INCDEC_MODELVAR(event, g_model.moduleData[moduleIdx].subType, MODULE_SUBTYPE_PXX1_ACCST_D16, MODULE_SUBTYPE_PXX1_LAST); } if (checkIncDec_Ret) { - g_model.moduleData[EXTERNAL_MODULE].channelsStart = 0; - g_model.moduleData[EXTERNAL_MODULE].channelsCount = defaultModuleChannels_M8(EXTERNAL_MODULE); + g_model.moduleData[moduleIdx].channelsStart = 0; + g_model.moduleData[moduleIdx].channelsCount = defaultModuleChannels_M8(moduleIdx); } break; #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)); + 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[EXTERNAL_MODULE].getMultiProtocol(false)); + const mm_protocol_definition *pdef = getMultiProtocolDefinition(g_model.moduleData[moduleIdx].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[moduleIdx].subType, 0, pdef->maxSubtype); } break; case 3: // Custom protocol, third column is subtype - CHECK_INCDEC_MODELVAR(event, g_model.moduleData[EXTERNAL_MODULE].subType, 0, 7); + CHECK_INCDEC_MODELVAR(event, g_model.moduleData[moduleIdx].subType, 0, 7); break; #endif } } #if POPUP_LEVEL > 1 else if (old_editMode > 0) { - if (isModuleR9MNonAccess(EXTERNAL_MODULE)) { - if (g_model.moduleData[EXTERNAL_MODULE].subType > MODULE_SUBTYPE_R9M_EU) { + if (isModuleR9MNonAccess(moduleIdx)) { + if (g_model.moduleData[moduleIdx].subType > MODULE_SUBTYPE_R9M_EU) { POPUP_WARNING(STR_MODULE_PROTOCOL_FLEX_WARN_LINE1); SET_WARNING_INFO(STR_MODULE_PROTOCOL_WARN_LINE2, sizeof(TR_MODULE_PROTOCOL_WARN_LINE2) - 1, 0); } #if POPUP_LEVEL >= 3 - else if (g_model.moduleData[EXTERNAL_MODULE].subType == MODULE_SUBTYPE_R9M_EU) { + else if (g_model.moduleData[moduleIdx].subType == MODULE_SUBTYPE_R9M_EU) { POPUP_WARNING(STR_MODULE_PROTOCOL_EU_WARN_LINE1); SET_WARNING_INFO(STR_MODULE_PROTOCOL_WARN_LINE2, sizeof(TR_MODULE_PROTOCOL_WARN_LINE2) - 1, 0); } @@ -1111,11 +1155,11 @@ bool menuModelSetup(event_t event) #endif } break; - +#if defined(HARDWARE_INTERNAL_MODULE) case ITEM_MODEL_SETUP_INTERNAL_MODULE_CHANNELS: +#endif case ITEM_MODEL_SETUP_EXTERNAL_MODULE_CHANNELS: { - uint8_t moduleIdx = CURRENT_MODULE_EDITED(k); ModuleData & moduleData = g_model.moduleData[moduleIdx]; lcdDrawText(MENUS_MARGIN_LEFT, y, STR_CHANNELRANGE); if ((int8_t)MODULE_CHANNELS_ROWS(moduleIdx) >= 0) { @@ -1141,7 +1185,6 @@ bool menuModelSetup(event_t event) } break; } - case ITEM_MODEL_SETUP_TRAINER_LABEL: lcdDrawText(MENUS_MARGIN_LEFT, y, STR_TRAINER); break; @@ -1149,12 +1192,15 @@ bool menuModelSetup(event_t event) case ITEM_MODEL_SETUP_TRAINER_MODE: lcdDrawText(MENUS_MARGIN_LEFT + INDENT_WIDTH, y, STR_MODE); g_model.trainerData.mode = editChoice(MODEL_SETUP_2ND_COLUMN, y, STR_VTRAINERMODES, g_model.trainerData.mode, 0, TRAINER_MODE_MAX(), attr, event); +#if defined(BLUETOOTH) if (attr && checkIncDec_Ret) { bluetooth.state = BLUETOOTH_STATE_OFF; bluetooth.distantAddr[0] = 0; } +#endif break; +#if defined(BLUETOOTH) case ITEM_MODEL_SETUP_TRAINER_BLUETOOTH: if (g_model.trainerData.mode == TRAINER_MODE_MASTER_BLUETOOTH) { if (attr) { @@ -1194,6 +1240,7 @@ bool menuModelSetup(event_t event) } } break; +#endif case ITEM_MODEL_SETUP_TRAINER_CHANNELS: lcdDrawText(MENUS_MARGIN_LEFT, y, STR_CHANNELRANGE); @@ -1242,10 +1289,11 @@ bool menuModelSetup(event_t event) break; #endif +#if defined(HARDWARE_INTERNAL_MODULE) case ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_MODEL_NUM: +#endif case ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_MODEL_NUM: { - uint8_t moduleIdx = CURRENT_MODULE_EDITED(k); lcdDrawText(MENUS_MARGIN_LEFT + INDENT_WIDTH, y, STR_RECEIVER_NUM); lcdDrawNumber(MODEL_SETUP_2ND_COLUMN, y, g_model.header.modelId[moduleIdx], attr | LEADING0 | LEFT, 2); if (attr) { @@ -1261,11 +1309,11 @@ bool menuModelSetup(event_t event) } } break; - +#if defined(HARDWARE_INTERNAL_MODULE) case ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_REGISTER_RANGE: +#endif case ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_REGISTER_RANGE: { - uint8_t moduleIdx = CURRENT_MODULE_EDITED(k); lcdDrawText(MENUS_MARGIN_LEFT + INDENT_WIDTH, y, STR_MODULE); drawButton(MODEL_SETUP_2ND_COLUMN, y, STR_REGISTER, (menuHorizontalPosition == 0 ? attr : 0)); drawButton(MODEL_SETUP_2ND_COLUMN + MODEL_SETUP_SET_FAILSAFE_OFS, y, STR_MODULE_RANGE, (menuHorizontalPosition == 1 ? attr : 0)); @@ -1288,8 +1336,9 @@ bool menuModelSetup(event_t event) } } break; - +#if defined(HARDWARE_INTERNAL_MODULE) case ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_OPTIONS: +#endif case ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_OPTIONS: lcdDrawText(MENUS_MARGIN_LEFT + INDENT_WIDTH, y, STR_OPTIONS); drawButton(MODEL_SETUP_2ND_COLUMN, y, STR_SET, attr); @@ -1298,15 +1347,15 @@ bool menuModelSetup(event_t event) pushMenu(menuModelModuleOptions); } break; - +#if defined(HARDWARE_INTERNAL_MODULE) case ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_RECEIVER_1: case ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_RECEIVER_2: case ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_RECEIVER_3: +#endif case ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_RECEIVER_1: case ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_RECEIVER_2: case ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_RECEIVER_3: { - uint8_t moduleIdx = CURRENT_MODULE_EDITED(k); uint8_t receiverIdx = CURRENT_RECEIVER_EDITED(k); ModuleInformation & moduleInformation = reusableBuffer.moduleSetup.pxx2.moduleInformation; @@ -1382,11 +1431,11 @@ bool menuModelSetup(event_t event) } } break; - +#if defined(HARDWARE_INTERNAL_MODULE) case ITEM_MODEL_SETUP_INTERNAL_MODULE_NOT_ACCESS_BIND: +#endif case ITEM_MODEL_SETUP_EXTERNAL_MODULE_NOT_ACCESS_BIND: { - uint8_t moduleIdx = CURRENT_MODULE_EDITED(k); ModuleData & moduleData = g_model.moduleData[moduleIdx]; if (isModulePPM(moduleIdx)) { lcdDrawText(MENUS_MARGIN_LEFT, y, STR_PPMFRAME); @@ -1454,8 +1503,8 @@ bool menuModelSetup(event_t event) drawButton(MODEL_SETUP_2ND_COLUMN+MODEL_SETUP_RANGE_OFS+xOffsetBind, y, STR_MODULE_RANGE, (moduleState[moduleIdx].mode == MODULE_MODE_RANGECHECK ? BUTTON_ON : BUTTON_OFF) | (l_posHorz==2 ? attr : 0)); uint8_t newFlag = 0; #if defined(MULTIMODULE) - if (multiBindStatus == MULTI_BIND_FINISHED) { - multiBindStatus = MULTI_NORMAL_OPERATION; + if (getMultiBindStatus(moduleIdx) == MULTI_BIND_FINISHED) { + setMultiBindStatus(moduleIdx, MULTI_NORMAL_OPERATION); s_editMode = 0; } #endif @@ -1488,17 +1537,17 @@ bool menuModelSetup(event_t event) moduleState[moduleIdx].mode = newFlag; #if defined(MULTIMODULE) if (newFlag == MODULE_MODE_BIND) - multiBindStatus = MULTI_BIND_INITIATED; + setMultiBindStatus(moduleIdx, MULTI_BIND_INITIATED); #endif } } break; } - +#if defined(HARDWARE_INTERNAL_MODULE) case ITEM_MODEL_SETUP_INTERNAL_MODULE_FAILSAFE: +#endif case ITEM_MODEL_SETUP_EXTERNAL_MODULE_FAILSAFE: { - uint8_t moduleIdx = CURRENT_MODULE_EDITED(k); ModuleData & moduleData = g_model.moduleData[moduleIdx]; lcdDrawText(MENUS_MARGIN_LEFT, y, STR_FAILSAFE); lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_VFAILSAFE, moduleData.failsafeMode, menuHorizontalPosition==0 ? attr : 0); @@ -1536,15 +1585,16 @@ bool menuModelSetup(event_t event) } break; } - +#if defined(HARDWARE_INTERNAL_MODULE) + case ITEM_MODEL_SETUP_INTERNAL_MODULE_OPTIONS: +#endif case ITEM_MODEL_SETUP_EXTERNAL_MODULE_OPTIONS: { - uint8_t moduleIdx = CURRENT_MODULE_EDITED(k); #if defined(MULTIMODULE) 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[moduleIdx].getMultiProtocol(true); const mm_protocol_definition *pdef = getMultiProtocolDefinition(multi_proto); if (pdef->optionsstr) lcdDrawText(MENUS_MARGIN_LEFT + INDENT_WIDTH, y, pdef->optionsstr); @@ -1580,13 +1630,14 @@ bool menuModelSetup(event_t event) } break; } - +#if defined(HARDWARE_INTERNAL_MODULE) + case ITEM_MODEL_SETUP_INTERNAL_MODULE_POWER: +#endif case ITEM_MODEL_SETUP_EXTERNAL_MODULE_POWER: { - uint8_t moduleIdx = CURRENT_MODULE_EDITED(k); if (isModuleR9MNonAccess(moduleIdx)) { lcdDrawText(MENUS_MARGIN_LEFT, y, STR_RFPOWER); - if(isModuleR9M_FCC_VARIANT(moduleIdx)) { + 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) CHECK_INCDEC_MODELVAR(event, g_model.moduleData[moduleIdx].pxx.power, 0, R9M_FCC_POWER_MAX); @@ -1596,7 +1647,7 @@ bool menuModelSetup(event_t event) if (attr) CHECK_INCDEC_MODELVAR(event, g_model.moduleData[moduleIdx].pxx.power, 0, R9M_LBT_POWER_MAX); if (attr && s_editMode == 0 && reusableBuffer.moduleSetup.r9mPower != g_model.moduleData[moduleIdx].pxx.power) { - if((reusableBuffer.moduleSetup.r9mPower + g_model.moduleData[moduleIdx].pxx.power) < 5) { //switching between mode 2 and 3 does not require rebind + if ((reusableBuffer.moduleSetup.r9mPower + g_model.moduleData[moduleIdx].pxx.power) < 5) { //switching between mode 2 and 3 does not require rebind POPUP_WARNING(STR_WARNING); SET_WARNING_INFO(STR_REBIND, sizeof(TR_REBIND), 0); } @@ -1607,39 +1658,49 @@ bool menuModelSetup(event_t event) #if defined(MULTIMODULE) else if (isModuleMultimodule(moduleIdx)) { lcdDrawText(MENUS_MARGIN_LEFT, y, STR_MULTI_LOWPOWER); - g_model.moduleData[EXTERNAL_MODULE].multi.lowPowerMode = editCheckBox(g_model.moduleData[EXTERNAL_MODULE].multi.lowPowerMode, MODEL_SETUP_2ND_COLUMN, y, attr, event); + g_model.moduleData[moduleIdx].multi.lowPowerMode = editCheckBox(g_model.moduleData[moduleIdx].multi.lowPowerMode, MODEL_SETUP_2ND_COLUMN, y, attr, event); } #endif } - break; + break; #if defined(MULTIMODULE) +#if defined(INTERNAL_MODULE_MULTI) + case ITEM_MODEL_SETUP_INTERNAL_MODULE_AUTOBIND: +#endif case ITEM_MODEL_SETUP_EXTERNAL_MODULE_AUTOBIND: - if (g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(true) == MODULE_SUBTYPE_MULTI_DSM2) + if (g_model.moduleData[moduleIdx].getMultiProtocol(true) == 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[EXTERNAL_MODULE].multi.autoBindMode = editCheckBox(g_model.moduleData[EXTERNAL_MODULE].multi.autoBindMode, MODEL_SETUP_2ND_COLUMN, y, attr, event); + g_model.moduleData[moduleIdx].multi.autoBindMode = editCheckBox(g_model.moduleData[moduleIdx].multi.autoBindMode, MODEL_SETUP_2ND_COLUMN, y, attr, event); break; - - case ITEM_MODEL_SETUP_EXTERNAL_MODULE_STATUS: { +#if defined(INTERNAL_MODULE_MULTI) + case ITEM_MODEL_SETUP_INTERNAL_MODULE_STATUS: +#endif + case ITEM_MODEL_SETUP_EXTERNAL_MODULE_STATUS: + { lcdDrawText(MENUS_MARGIN_LEFT, y, STR_MODULE_STATUS); char statusText[64]; - multiModuleStatus.getStatusString(statusText); + getMultiModuleStatus(moduleIdx).getStatusString(statusText); lcdDrawText(MODEL_SETUP_2ND_COLUMN, y, statusText); break; - - case ITEM_MODEL_SETUP_EXTERNAL_MODULE_SYNCSTATUS: { + } +#if defined(INTERNAL_MODULE_MULTI) + case ITEM_MODEL_SETUP_INTERNAL_MODULE_SYNCSTATUS: +#endif + case ITEM_MODEL_SETUP_EXTERNAL_MODULE_SYNCSTATUS: + { lcdDrawText(MENUS_MARGIN_LEFT, y, STR_MODULE_SYNC); char statusText[64]; - multiSyncStatus.getRefreshString(statusText); + getMultiSyncStatus(moduleIdx).getRefreshString(statusText); lcdDrawText(MODEL_SETUP_2ND_COLUMN, y, statusText); break; - } } #endif + } } @@ -1656,7 +1717,7 @@ bool menuModelSetup(event_t event) case ITEM_MODEL_SETUP_NAME: mod_cell->setModelName(g_model.header.name); break; - +#if defined(HARDWARE_INTERNAL_MODULE) case ITEM_MODEL_SETUP_INTERNAL_MODULE_NOT_ACCESS_BIND: if (menuHorizontalPosition != 0) break; @@ -1664,7 +1725,7 @@ bool menuModelSetup(event_t event) mod_cell->setRfData(&g_model); checkModelIdUnique(INTERNAL_MODULE); break; - +#endif case ITEM_MODEL_SETUP_EXTERNAL_MODULE_NOT_ACCESS_BIND: if (menuHorizontalPosition != 0) break; @@ -1672,6 +1733,7 @@ bool menuModelSetup(event_t event) mod_cell->setRfData(&g_model); if (g_model.moduleData[EXTERNAL_MODULE].type != MODULE_TYPE_NONE) checkModelIdUnique(EXTERNAL_MODULE); + break; } } } diff --git a/radio/src/gui/480x272/radio_hardware.cpp b/radio/src/gui/480x272/radio_hardware.cpp index db5fbc759..89a5aabff 100644 --- a/radio/src/gui/480x272/radio_hardware.cpp +++ b/radio/src/gui/480x272/radio_hardware.cpp @@ -55,10 +55,11 @@ enum MenuRadioHardwareItems { ITEM_RADIO_HARDWARE_BATTERY_CALIB, ITEM_RADIO_HARDWARE_RTC_BATTERY, ITEM_RADIO_HARDWARE_SERIAL_BAUDRATE, +#if defined(BLUETOOTH) ITEM_RADIO_HARDWARE_BLUETOOTH_MODE, ITEM_RADIO_HARDWARE_BLUETOOTH_PAIRING_CODE, ITEM_RADIO_HARDWARE_BLUETOOTH_NAME, - +#endif #if defined(INTERNAL_MODULE_PXX1) && defined(EXTERNAL_ANTENNA) ITEM_RADIO_HARDWARE_EXTERNAL_ANTENNA, #endif @@ -77,7 +78,11 @@ enum MenuRadioHardwareItems { #define POTS_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 #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 -#define BLUETOOTH_ROWS 0, uint8_t(g_eeGeneral.bluetoothMode != BLUETOOTH_TELEMETRY ? HIDDEN_ROW : -1), uint8_t(g_eeGeneral.bluetoothMode == BLUETOOTH_OFF ? -1 : 0) +#if defined(BLUETOOTH) + #define BLUETOOTH_ROWS 0, uint8_t(g_eeGeneral.bluetoothMode != BLUETOOTH_TELEMETRY ? HIDDEN_ROW : -1), uint8_t(g_eeGeneral.bluetoothMode == BLUETOOTH_OFF ? -1 : 0), +#else + #define BLUETOOTH_ROWS +#endif // TODO should be moved to the HAL #define SWITCH_TYPE_MAX(sw) ((MIXSRC_SF-MIXSRC_FIRST_SWITCH == sw || MIXSRC_SH-MIXSRC_FIRST_SWITCH == sw || MIXSRC_SI-MIXSRC_FIRST_SWITCH == sw || MIXSRC_SJ-MIXSRC_FIRST_SWITCH == sw) ? SWITCH_2POS : SWITCH_3POS) @@ -121,7 +126,7 @@ bool menuRadioHardware(event_t event) 0, /* max baudrate */ - BLUETOOTH_ROWS, + BLUETOOTH_ROWS EXTERNAL_ANTENNA_ROW @@ -270,7 +275,7 @@ bool menuRadioHardware(event_t event) } } break; - +#if defined(BLUETOOTH) case ITEM_RADIO_HARDWARE_BLUETOOTH_MODE: lcdDrawText(MENUS_MARGIN_LEFT, y, STR_BLUETOOTH); g_eeGeneral.bluetoothMode = editChoice(HW_SETTINGS_COLUMN+50, y, STR_BLUETOOTH_MODES, g_eeGeneral.bluetoothMode, BLUETOOTH_OFF, BLUETOOTH_TRAINER, attr, event); @@ -285,6 +290,7 @@ bool menuRadioHardware(event_t event) lcdDrawText(MENUS_MARGIN_LEFT, y, STR_NAME); editName(HW_SETTINGS_COLUMN+50, y, g_eeGeneral.bluetoothName, LEN_BLUETOOTH_NAME, event, attr); break; +#endif #if defined(INTERNAL_MODULE_PXX1) && defined(EXTERNAL_ANTENNA) case ITEM_RADIO_HARDWARE_EXTERNAL_ANTENNA: diff --git a/radio/src/gui/480x272/radio_sdmanager.cpp b/radio/src/gui/480x272/radio_sdmanager.cpp index 4c82c42fe..0534e6bbf 100644 --- a/radio/src/gui/480x272/radio_sdmanager.cpp +++ b/radio/src/gui/480x272/radio_sdmanager.cpp @@ -19,7 +19,8 @@ */ #include -#include +#include "io/frsky_firmware_update.h" +#include "io/multi_firmware_update.h" #include "opentx.h" #include "storage/modelslist.h" @@ -173,6 +174,18 @@ void onSdManagerMenu(const char * result) FrskyDeviceFirmwareUpdate device(SPORT_MODULE); device.flashFirmware(lfn); } +#if defined(MULTIMODULE) +#if defined(INTERNAL_MODULE_MULTI) + else if (result == STR_FLASH_INTERNAL_MULTI) { + getSelectionFullPath(lfn); + multiFlashFirmware(INTERNAL_MODULE, lfn); + } +#endif + else if (result == STR_FLASH_EXTERNAL_MULTI) { + getSelectionFullPath(lfn); + multiFlashFirmware(EXTERNAL_MODULE, lfn); + } +#endif #if defined(LUA) else if (result == STR_EXECUTE_FILE) { getSelectionFullPath(lfn); @@ -258,9 +271,22 @@ bool menuRadioSdManager(event_t _event) POPUP_MENU_ADD_ITEM(STR_FLASH_INTERNAL_MODULE); POPUP_MENU_ADD_ITEM(STR_FLASH_EXTERNAL_MODULE); } - else if (!READ_ONLY() && !strcasecmp(ext, UPDATE_FIRMWARE_EXT)) { +#if defined(MULTIMODULE) + else if (!READ_ONLY() && !strcasecmp(ext, MULTI_FIRMWARE_EXT)) { + TCHAR lfn[_MAX_LFN + 1]; + getSelectionFullPath(lfn); + MultiFirmwareInformation information; + if (information.readMultiFirmwareInformation(line) == nullptr) { +#if defined(INTERNAL_MODULE_MULTI) + POPUP_MENU_ADD_ITEM(STR_FLASH_INTERNAL_MULTI); +#endif + POPUP_MENU_ADD_ITEM(STR_FLASH_EXTERNAL_MULTI); + } +#endif + } + else if (!READ_ONLY() && !strcasecmp(ext, FRSKY_FIRMWARE_EXT)) { FrSkyFirmwareInformation information; - if (readFirmwareInformation(line, information) == nullptr) { + if (readFrSkyFirmwareInformation(line, information) == nullptr) { if (information.productFamily == FIRMWARE_FAMILY_INTERNAL_MODULE) POPUP_MENU_ADD_ITEM(STR_FLASH_INTERNAL_MODULE); if (information.productFamily == FIRMWARE_FAMILY_EXTERNAL_MODULE) diff --git a/radio/src/gui/480x272/themes/default.cpp b/radio/src/gui/480x272/themes/default.cpp index d444a6994..84b23e168 100644 --- a/radio/src/gui/480x272/themes/default.cpp +++ b/radio/src/gui/480x272/themes/default.cpp @@ -176,7 +176,9 @@ class DefaultTheme: public Theme calibTrackpBackground = BitmapBuffer::load(getThemePath("trackp_background.png")); delete calibHorus; -#if defined(PCBX10) +#if defined(RADIO_T16) + calibHorus = BitmapBuffer::load(getThemePath("t16.bmp")); +#elif defined(PCBX10) if(STICKS_PWM_ENABLED()) { calibHorus = BitmapBuffer::load(getThemePath("X10S.bmp")); } diff --git a/radio/src/gui/common/stdlcd/radio_sdmanager.cpp b/radio/src/gui/common/stdlcd/radio_sdmanager.cpp index 797717314..763fdcada 100644 --- a/radio/src/gui/common/stdlcd/radio_sdmanager.cpp +++ b/radio/src/gui/common/stdlcd/radio_sdmanager.cpp @@ -20,6 +20,7 @@ #include "opentx.h" #include "io/frsky_firmware_update.h" +#include "io/multi_firmware_update.h" #define NODE_TYPE(fname) fname[SD_SCREEN_FILE_LENGTH+1] #define IS_DIRECTORY(fname) ((bool)(!NODE_TYPE(fname))) @@ -219,6 +220,16 @@ void onSdManagerMenu(const char * result) FrskyDeviceFirmwareUpdate device(SPORT_MODULE); device.flashFirmware(lfn); } +#if defined(INTERNAL_MODULE_MULTI) + else if (result == STR_FLASH_INTERNAL_MULTI) { + getSelectionFullPath(lfn); + multiFlashFirmware(INTERNAL_MODULE, lfn); + } +#endif + else if (result == STR_FLASH_EXTERNAL_MULTI) { + getSelectionFullPath(lfn); + multiFlashFirmware(EXTERNAL_MODULE, lfn); + } #if defined(BLUETOOTH) else if (result == STR_FLASH_BLUETOOTH_MODULE) { getSelectionFullPath(lfn); @@ -340,6 +351,9 @@ void menuRadioSdManager(event_t _event) break; } #endif + TCHAR lfn[_MAX_LFN + 1]; + getSelectionFullPath(lfn); + if (SD_CARD_PRESENT() && s_editMode <= 0) { killEvents(_event); int index = menuVerticalPosition - HEADER_LINE - menuVerticalOffset; @@ -364,10 +378,19 @@ void menuRadioSdManager(event_t _event) POPUP_MENU_ADD_ITEM(STR_EXECUTE_FILE); } #endif +#if defined(MULTIMODULE) && !defined(DISABLE_MULTI_UPDATE) + if (!READ_ONLY() && !strcasecmp(ext, MULTI_FIRMWARE_EXT)) { + MultiFirmwareInformation information; + if (information.readMultiFirmwareInformation(line) == nullptr) { +#if defined(INTERNAL_MODULE_MULTI) + POPUP_MENU_ADD_ITEM(STR_FLASH_INTERNAL_MULTI); +#endif + POPUP_MENU_ADD_ITEM(STR_FLASH_EXTERNAL_MULTI); + } + } +#endif #if defined(PCBTARANIS) - else if (!READ_ONLY() && !strcasecmp(ext, FIRMWARE_EXT)) { - TCHAR lfn[_MAX_LFN + 1]; - getSelectionFullPath(lfn); + if (!READ_ONLY() && !strcasecmp(ext, FIRMWARE_EXT)) { if (isBootloader(lfn)) { POPUP_MENU_ADD_ITEM(STR_FLASH_BOOTLOADER); } @@ -378,9 +401,9 @@ void menuRadioSdManager(event_t _event) POPUP_MENU_ADD_ITEM(STR_FLASH_INTERNAL_MODULE); POPUP_MENU_ADD_ITEM(STR_FLASH_EXTERNAL_MODULE); } - else if (!READ_ONLY() && !strcasecmp(ext, UPDATE_FIRMWARE_EXT)) { + else if (!READ_ONLY() && !strcasecmp(ext, FRSKY_FIRMWARE_EXT)) { FrSkyFirmwareInformation information; - if (readFirmwareInformation(line, information) == nullptr) { + if (readFrSkyFirmwareInformation(line, information) == nullptr) { if (information.productFamily == FIRMWARE_FAMILY_INTERNAL_MODULE) POPUP_MENU_ADD_ITEM(STR_FLASH_INTERNAL_MODULE); if (information.productFamily == FIRMWARE_FAMILY_EXTERNAL_MODULE) diff --git a/radio/src/gui/gui_common.cpp b/radio/src/gui/gui_common.cpp index 52dc9fd18..3d0c6c1f7 100644 --- a/radio/src/gui/gui_common.cpp +++ b/radio/src/gui/gui_common.cpp @@ -567,6 +567,13 @@ bool isInternalModuleAvailable(int moduleType) if (moduleType == MODULE_TYPE_NONE) return true; +#if defined(INTERNAL_MODULE_MULTI) + if (moduleType == MODULE_TYPE_MULTIMODULE) + return true; + else + return false; +#endif + if (moduleType == MODULE_TYPE_XJT_PXX1) { #if defined(PXX1) && defined(INTERNAL_MODULE_PXX1) return !isModuleUsingSport(EXTERNAL_MODULE, g_model.moduleData[EXTERNAL_MODULE].type); @@ -584,7 +591,6 @@ bool isInternalModuleAvailable(int moduleType) return true; #endif } - return false; } #endif diff --git a/radio/src/gui/gui_common.h b/radio/src/gui/gui_common.h index b941d2ec9..9f4d12894 100644 --- a/radio/src/gui/gui_common.h +++ b/radio/src/gui/gui_common.h @@ -116,10 +116,33 @@ void drawFatalErrorScreen(const char * message); void runFatalErrorScreen(const char * message); #endif +#define IF_INTERNAL_MODULE_ON(x) (IS_INTERNAL_MODULE_ENABLED() ? (uint8_t)(x) : HIDDEN_ROW) +#define IF_MODULE_ON(moduleIndex, x) (IS_MODULE_ENABLED(moduleIndex) ? (uint8_t)(x) : HIDDEN_ROW) + // model_setup Defines that are used in all uis in the same way -#define INTERNAL_MODULE_CHANNELS_ROWS IF_INTERNAL_MODULE_ON((uint8_t)1) -#define EXTERNAL_MODULE_CHANNELS_ROWS IF_EXTERNAL_MODULE_ON((isModuleDSM2(EXTERNAL_MODULE) || isModuleCrossfire(EXTERNAL_MODULE) || isModuleSBUS(EXTERNAL_MODULE) || (isModuleMultimodule(EXTERNAL_MODULE) && g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(true) != MODULE_SUBTYPE_MULTI_DSM2)) ? (uint8_t)0 : (uint8_t)1) -#define EXTERNAL_MODULE_BIND_ROWS (isModuleXJTD8(EXTERNAL_MODULE) || isModuleSBUS(EXTERNAL_MODULE)) ? (uint8_t)1 : (isModulePPM(EXTERNAL_MODULE) || isModulePXX1(EXTERNAL_MODULE) || isModulePXX2(EXTERNAL_MODULE) || isModuleDSM2(EXTERNAL_MODULE) || isModuleMultimodule(EXTERNAL_MODULE)) ? (uint8_t)2 : HIDDEN_ROW + +inline uint8_t MODULE_BIND_ROWS(int moduleIdx) +{ + if (isModuleXJTD8(moduleIdx) || isModuleSBUS(moduleIdx)) + return 1; + + if (isModulePPM(moduleIdx) || isModulePXX1(moduleIdx) || isModulePXX2(moduleIdx) || isModuleDSM2(moduleIdx) || isModuleMultimodule(moduleIdx)) + return 2; + else + return HIDDEN_ROW; +} + +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)) + return 0; + else + return 1; +} + #if defined(MULTIMODULE) // When using packed, the pointer in here end up not being aligned, which clang and gcc complain about @@ -132,9 +155,9 @@ struct mm_protocol_definition { const char *optionsstr; }; const mm_protocol_definition *getMultiProtocolDefinition (uint8_t protocol); -#define MULTIMODULE_STATUS_ROWS isModuleMultimodule(EXTERNAL_MODULE) ? TITLE_ROW : HIDDEN_ROW, (isModuleMultimodule(EXTERNAL_MODULE) && multiSyncStatus.isValid()) ? TITLE_ROW : HIDDEN_ROW, -#define MULTIMODULE_MODULE_ROWS isModuleMultimodule(EXTERNAL_MODULE) ? (uint8_t) 0 : HIDDEN_ROW, -#define MULTIMODULE_MODE_ROWS(x) (g_model.moduleData[x].multi.customProto) ? (uint8_t) 3 :MULTIMODULE_HAS_SUBTYPE(g_model.moduleData[x].getMultiProtocol(true)) ? (uint8_t)2 : (uint8_t)1 +#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 bool MULTIMODULE_HAS_SUBTYPE(uint8_t moduleIdx) { return getMultiProtocolDefinition(moduleIdx)->maxSubtype > 0; @@ -147,21 +170,21 @@ inline uint8_t MULTIMODULE_RFPROTO_COLUMNS(uint8_t moduleIdx) return (g_model.moduleData[moduleIdx].multi.customProto ? (uint8_t) 2 : MULTIMODULE_HAS_SUBTYPE(g_model.moduleData[moduleIdx].getMultiProtocol(true)) ? (uint8_t) 1 : 0); #endif } -#define MULTIMODULE_SUBTYPE_ROWS(x) isModuleMultimodule(x) ? MULTIMODULE_RFPROTO_COLUMNS(x) : HIDDEN_ROW, -#define MULTIMODULE_HASOPTIONS(x) (getMultiProtocolDefinition(x)->optionsstr != nullptr) -#define MULTIMODULE_OPTIONS_ROW (isModuleMultimodule(EXTERNAL_MODULE) && MULTIMODULE_HASOPTIONS(g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(true))) ? (uint8_t) 0: HIDDEN_ROW +#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 #else -#define MULTIMODULE_STATUS_ROWS -#define MULTIMODULE_MODULE_ROWS -#define MULTIMODULE_SUBTYPE_ROWS(x) -#define MULTIMODULE_MODE_ROWS(x) (uint8_t)0 -#define MULTIMODULE_OPTIONS_ROW HIDDEN_ROW +#define MULTIMODULE_STATUS_ROWS(moduleIdx) +#define MULTIMODULE_MODULE_ROWS(moduleIdx) +#define MULTIMODULE_SUBTYPE_ROWS(moduleIdx) +#define MULTIMODULE_MODE_ROWS(moduleIdx) (uint8_t)0 +#define MULTIMODULE_OPTIONS_ROW(moduleIdx) HIDDEN_ROW #endif -#define FAILSAFE_ROWS(x) isModuleFailsafeAvailable(x) ? (g_model.moduleData[x].failsafeMode==FAILSAFE_CUSTOM ? (uint8_t)1 : (uint8_t)0) : HIDDEN_ROW -#define EXTERNAL_MODULE_OPTION_ROW (isModuleR9MNonAccess(EXTERNAL_MODULE) || isModuleSBUS(EXTERNAL_MODULE) ? TITLE_ROW : MULTIMODULE_OPTIONS_ROW) -#define EXTERNAL_MODULE_POWER_ROW (isModuleMultimodule(EXTERNAL_MODULE) || isModuleR9MNonAccess(EXTERNAL_MODULE)) ? (isModuleR9MLiteNonPro(EXTERNAL_MODULE) ? (isModuleR9M_FCC_VARIANT(EXTERNAL_MODULE) ? READONLY_ROW : (uint8_t)0) : (uint8_t)0) : HIDDEN_ROW +#define FAILSAFE_ROWS(moduleIdx) isModuleFailsafeAvailable(moduleIdx) ? (g_model.moduleData[moduleIdx].failsafeMode==FAILSAFE_CUSTOM ? (uint8_t)1 : (uint8_t)0) : HIDDEN_ROW +#define MODULE_OPTION_ROW(moduleIdx) (isModuleR9MNonAccess(moduleIdx) || isModuleSBUS(moduleIdx) ? TITLE_ROW : MULTIMODULE_OPTIONS_ROW(moduleIdx)) +#define MODULE_POWER_ROW(moduleIdx) (isModuleMultimodule(moduleIdx) || isModuleR9MNonAccess(moduleIdx)) ? (isModuleR9MLiteNonPro(moduleIdx) ? (isModuleR9M_FCC_VARIANT(moduleIdx) ? READONLY_ROW : (uint8_t)0) : (uint8_t)0) : HIDDEN_ROW void editStickHardwareSettings(coord_t x, coord_t y, int idx, event_t event, LcdFlags flags); diff --git a/radio/src/io/frsky_firmware_update.cpp b/radio/src/io/frsky_firmware_update.cpp index 889139990..d8a8933e9 100644 --- a/radio/src/io/frsky_firmware_update.cpp +++ b/radio/src/io/frsky_firmware_update.cpp @@ -33,7 +33,7 @@ #define PRIM_END_DOWNLOAD 0x83 #define PRIM_DATA_CRC_ERR 0x84 -const char * readFirmwareInformation(const char * filename, FrSkyFirmwareInformation & data) +const char * readFrSkyFirmwareInformation(const char * filename, FrSkyFirmwareInformation & data) { FIL file; UINT count; @@ -305,7 +305,7 @@ const char * FrskyDeviceFirmwareUpdate::doFlashFirmware(const char * filename) } const char * ext = getFileExtension(filename); - if (ext && !strcasecmp(ext, UPDATE_FIRMWARE_EXT)) { + if (ext && !strcasecmp(ext, FRSKY_FIRMWARE_EXT)) { if (f_read(&file, &information, sizeof(FrSkyFirmwareInformation), &count) != FR_OK || count != sizeof(FrSkyFirmwareInformation)) { f_close(&file); return "Format error"; @@ -321,7 +321,7 @@ const char * FrskyDeviceFirmwareUpdate::doFlashFirmware(const char * filename) if (module == INTERNAL_MODULE && information.productId == FIRMWARE_ID_XJT) { INTERNAL_MODULE_ON(); RTOS_WAIT_MS(1); - intmoduleSerialStart(38400, true); + intmoduleSerialStart(38400, true, USART_Parity_No, USART_StopBits_1, USART_WordLength_8b); GPIO_SetBits(INTMODULE_BOOTCMD_GPIO, INTMODULE_BOOTCMD_GPIO_PIN); result = uploadFileToHorusXJT(filename, &file); GPIO_ResetBits(INTMODULE_BOOTCMD_GPIO, INTMODULE_BOOTCMD_GPIO_PIN); @@ -336,7 +336,7 @@ const char * FrskyDeviceFirmwareUpdate::doFlashFirmware(const char * filename) // this ifdef can be removed if we use .frsk instead of .frk // theorically it should be possible to use an ISRM module in an XLite case INTERNAL_MODULE: - intmoduleSerialStart(57600, true); + intmoduleSerialStart(57600, true, USART_Parity_No, USART_StopBits_1, USART_WordLength_8b); break; #endif diff --git a/radio/src/io/frsky_firmware_update.h b/radio/src/io/frsky_firmware_update.h index 9d3dcc820..a229edb27 100644 --- a/radio/src/io/frsky_firmware_update.h +++ b/radio/src/io/frsky_firmware_update.h @@ -53,7 +53,7 @@ PACK(struct FrSkyFirmwareInformation { uint16_t crc; }); -const char * readFirmwareInformation(const char * filename, FrSkyFirmwareInformation & data); +const char * readFrSkyFirmwareInformation(const char * filename, FrSkyFirmwareInformation & data); class FrskyDeviceFirmwareUpdate { enum State { diff --git a/radio/src/io/multi_firmware_update.cpp b/radio/src/io/multi_firmware_update.cpp new file mode 100644 index 000000000..dcc6d6e7b --- /dev/null +++ b/radio/src/io/multi_firmware_update.cpp @@ -0,0 +1,447 @@ +/* + * 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. + */ + +#if !defined(DISABLE_MULTI_UPDATE) +#include "opentx.h" +#include "multi_firmware_update.h" +#include "stk500.h" +#include "debug.h" + +#define UPDATE_MULTI_EXT_BIN ".bin" + +//#define DEBUG_EXT_MODULE_FLASH + +class MultiFirmwareUpdateDriver +{ + public: + MultiFirmwareUpdateDriver() = default; + const char* flashFirmware(FIL* file, const char* label) const; + + protected: + virtual void init() const = 0; + virtual bool getByte(uint8_t& byte) const = 0; + virtual void sendByte(uint8_t byte) const = 0; + virtual void clear() const = 0; + + private: + bool getRxByte(uint8_t& byte) const; + bool checkRxByte(uint8_t byte) const; + const char * waitForInitialSync() const; + const char * getDeviceSignature(uint8_t* signature) const; + const char * loadAddress(uint32_t offset) const; + const char * progPage(uint8_t* buffer, uint16_t size) const; +}; + +#if defined(INTERNAL_MODULE_MULTI) + +class MultiInternalUpdateDriver: public MultiFirmwareUpdateDriver +{ + public: + MultiInternalUpdateDriver() = default; + + protected: + void init() const override + { + INTERNAL_MODULE_ON(); + intmoduleSerialStart(57600, true, USART_Parity_No, USART_StopBits_1, USART_WordLength_8b); + } + + bool getByte(uint8_t& byte) const override + { + return intmoduleFifo.pop(byte); + } + + void sendByte(uint8_t byte) const override + { + intmoduleSendByte(byte); + } + + void clear() const override + { + intmoduleFifo.clear(); + } +}; + +static const MultiInternalUpdateDriver multiInternalUpdateDriver; + +#endif + +class MultiExternalUpdateDriver: public MultiFirmwareUpdateDriver +{ + public: + MultiExternalUpdateDriver() = default; + + protected: + void init() const override + { +#if !defined(EXTMODULE_USART) + GPIO_InitTypeDef GPIO_InitStructure; + GPIO_InitStructure.GPIO_Pin = EXTMODULE_TX_GPIO_PIN; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; + GPIO_Init(EXTMODULE_TX_GPIO, &GPIO_InitStructure); +#endif + + EXTERNAL_MODULE_ON(); + telemetryPortInit(57600, TELEMETRY_SERIAL_DEFAULT); + } + + bool getByte(uint8_t& byte) const override + { + return telemetryGetByte(&byte); + } + + void sendByte(uint8_t byte) const override + { + extmoduleSendInvertedByte(byte); + } + + void clear() const override + { + telemetryClearFifo(); + } +}; + +static const MultiExternalUpdateDriver multiExternalUpdateDriver; + +bool MultiFirmwareUpdateDriver::getRxByte(uint8_t& byte) const +{ + uint16_t time; + + time = getTmr2MHz() ; + while ( (uint16_t) (getTmr2MHz() - time) < 25000 ) { // 12.5mS + + if (getByte(byte)) { +#if defined(DEBUG_EXT_MODULE_FLASH) + TRACE("[RX] 0x%X", byte); +#endif + return true; + } + } + + byte = 0; + return false; +} + +bool MultiFirmwareUpdateDriver::checkRxByte(uint8_t byte) const +{ + uint8_t rxchar; + return getRxByte(rxchar) ? rxchar == byte : false; +} + +const char * MultiFirmwareUpdateDriver::waitForInitialSync() const +{ + clear(); + + uint8_t byte; + int retries = 1000; + do { + // Send sync request + sendByte(STK_GET_SYNC); + sendByte(CRC_EOP); + + getRxByte(byte); + wdt_reset(); + + } while((byte != STK_INSYNC) && --retries); + + if (!retries) { + return "NoSync"; + } + + if (byte != STK_INSYNC) { + return "NoSync"; + } + + if (!checkRxByte(STK_OK)) { + return "NoSync"; + } + + return nullptr; +} + +const char * MultiFirmwareUpdateDriver::getDeviceSignature(uint8_t* signature) const +{ + // Read signature + sendByte(STK_READ_SIGN); + sendByte(CRC_EOP); + + if (!checkRxByte(STK_INSYNC)) + return "NoSync"; + + for (uint8_t i=0; i<4; i++) { + if (!getRxByte(signature[i])) { + return "NoSignature"; + } + } + + return nullptr; +} + +const char * MultiFirmwareUpdateDriver::loadAddress(uint32_t offset) const +{ + sendByte(STK_LOAD_ADDRESS); + sendByte(offset & 0xFF); // low byte + sendByte(offset >> 8); // high byte + sendByte(CRC_EOP); + + if (!checkRxByte(STK_INSYNC) || !checkRxByte(STK_OK)) { + return "NoSync"; + } + + return nullptr; +} + +const char * MultiFirmwareUpdateDriver::progPage(uint8_t* buffer, uint16_t size) const +{ + sendByte(STK_PROG_PAGE); + // page size 256 + sendByte(1); + sendByte(0); + // flash/eeprom flag + sendByte(0); + + // #if defined(DEBUG_EXT_MODULE_FLASH) + // TRACE("writing at 0x%X", writeOffset << 1); + // #endif + + for (uint16_t i=0; i < size; i++) { + sendByte(buffer[i]); + } + sendByte(CRC_EOP); + + if (!checkRxByte(STK_INSYNC)) + return "NoSync"; + + uint8_t byte; + uint8_t retries = 4; + do { + getRxByte(byte); + wdt_reset(); + } while(!byte && --retries); + + if (!retries || (byte != STK_OK)) + return "NoPageSync"; + + return nullptr; +} + +const char * MultiFirmwareUpdateDriver::flashFirmware(FIL* file, const char* label) const +{ + const char* result = nullptr; + init(); + + /* wait 500ms for power on */ + watchdogSuspend(500); + RTOS_WAIT_MS(500); + + result = waitForInitialSync(); + if (result != nullptr) + return result; + + unsigned char signature[4]; // 3 bytes signature + STK_OK + result = getDeviceSignature(signature); + if (result != nullptr) + return result; + + uint8_t buffer[256]; // page size = 256 + uint32_t writeOffset = 0x1000; // start offset (word address) + + while (!f_eof(file)) { + + drawProgressScreen(label, STR_WRITING, file->fptr, file->obj.objsize); + + UINT count=0; + memclear(buffer, 256); + if (f_read(file, buffer, 256, &count) != FR_OK) { + result = "Error reading file"; + break; + } + + if (!count) + break; + + clear(); + + result = loadAddress(writeOffset); + if (result != nullptr) { + break; + } + + result = progPage(buffer, 256); + if (result != nullptr) { + break; + } + + writeOffset += 128; // page / 2 + } + + if (f_eof(file)) { + drawProgressScreen(label, STR_WRITING, file->fptr, file->obj.objsize); + } + + sendByte(STK_LEAVE_PROGMODE); + sendByte(CRC_EOP); + + // eat last sync byte + checkRxByte(STK_INSYNC); + + return result; +} + +// example : multi-stm-bcsid-01020176 +#define MULTI_SIGN_SIZE 24 +#define MULTI_SIGN_BOOTLOADER_SUPPORT_OFFSET 10 +#define MULTI_SIGN_BOOTLOADER_CHECK_OFFSET 11 +#define MULTI_SIGN_TELEM_TYPE_OFFSET 12 +#define MULTI_SIGN_TELEM_INVERSION_OFFSET 13 +#define MULTI_SIGN_VERSION_OFFSET 15 + +const char * MultiFirmwareInformation::readMultiFirmwareInformation(const char * filename) +{ + FIL file; + f_open(&file, filename, FA_READ); + char buffer[MULTI_SIGN_SIZE]; + UINT count; + + f_lseek(&file, f_size(&file) - MULTI_SIGN_SIZE); + if (f_read(&file, buffer, MULTI_SIGN_SIZE, &count) != FR_OK || count != MULTI_SIGN_SIZE) { + return "Error reading file"; + } + + if(!memcmp(buffer, "multi-stm", 9)) + boardType = FIRMWARE_MULTI_STM; + else if (!memcmp(buffer, "multi-avr", 9)) + boardType = FIRMWARE_MULTI_AVR; + else if (!memcmp(buffer, "multi-orx", 9)) + boardType = FIRMWARE_MULTI_ORX; + else + return "Wrong format"; + + if(buffer[MULTI_SIGN_BOOTLOADER_SUPPORT_OFFSET] == 'b') + optibootSupport = true; + else + optibootSupport = false; + + if(buffer[MULTI_SIGN_BOOTLOADER_CHECK_OFFSET] == 'c') + bootloaderCheck = true; + else + bootloaderCheck = false; + + if(buffer[MULTI_SIGN_TELEM_TYPE_OFFSET] == 't') + telemetryType = FIRMWARE_MULTI_TELEM_MULTI; + else if (buffer[MULTI_SIGN_TELEM_TYPE_OFFSET] == 's') + telemetryType = FIRMWARE_MULTI_TELEM_STATUS; + else + telemetryType = FIRMWARE_MULTI_TELEM_NONE; + + if(buffer[MULTI_SIGN_TELEM_INVERSION_OFFSET] == 'i') + telemetryInversion = true; + else + telemetryInversion = false; + + return nullptr; +} + + + + +const char * multiFlashFirmware(uint8_t moduleIdx, const char * filename) +{ + FIL file; + const char * result = nullptr; + + const char * ext = getFileExtension(filename); + if (ext && strcasecmp(ext, UPDATE_MULTI_EXT_BIN)) { + return "Wrong file extension"; + } + + if (f_open(&file, filename, FA_READ) != FR_OK) { + return "Error opening file"; + } + + pausePulses(); + +#if defined(INTERNAL_MODULE_MULTI) + uint8_t intPwr = IS_INTERNAL_MODULE_ON(); + INTERNAL_MODULE_OFF(); +#endif + + uint8_t extPwr = IS_EXTERNAL_MODULE_ON(); + EXTERNAL_MODULE_OFF(); + + SPORT_UPDATE_POWER_OFF(); + + drawProgressScreen(getBasename(filename), STR_DEVICE_RESET, 0, 0); + + /* wait 2s off */ + watchdogSuspend(2000); + RTOS_WAIT_MS(2000); + + // TODO: real update here + const MultiFirmwareUpdateDriver* driver = &multiExternalUpdateDriver; +#if defined(INTERNAL_MODULE_MULTI) + if (moduleIdx == INTERNAL_MODULE) + driver = &multiInternalUpdateDriver; +#endif + + result = driver->flashFirmware(&file, getBasename(filename)); + f_close(&file); + + AUDIO_PLAY(AU_SPECIAL_SOUND_BEEP1 ); + BACKLIGHT_ENABLE(); + + if (result) { + POPUP_WARNING(STR_FIRMWARE_UPDATE_ERROR); + SET_WARNING_INFO(result, strlen(result), 0); + } + else { + POPUP_INFORMATION(STR_FIRMWARE_UPDATE_SUCCESS); + } + + INTERNAL_MODULE_OFF(); + EXTERNAL_MODULE_OFF(); + SPORT_UPDATE_POWER_OFF(); + + /* wait 2s off */ + watchdogSuspend(2000); + RTOS_WAIT_MS(2000); + telemetryClearFifo(); + +#if defined(INTERNAL_MODULE_MULTI) + if (intPwr) { + INTERNAL_MODULE_ON(); + setupPulsesInternalModule(); + } +#endif + + if (extPwr) { + EXTERNAL_MODULE_ON(); + setupPulsesExternalModule(); + } + + //state = SPORT_IDLE; + resumePulses(); + + return result; +} +#endif \ No newline at end of file diff --git a/radio/src/io/multi_firmware_update.h b/radio/src/io/multi_firmware_update.h new file mode 100644 index 000000000..45c6f8e91 --- /dev/null +++ b/radio/src/io/multi_firmware_update.h @@ -0,0 +1,96 @@ +/* + * 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 OPENTX_MULTI_FIRMWARE_H +#define OPENTX_MULTI_FIRMWARE_H + +/* Signature format is multi-[board type]-[bootloader support][check for bootloader][multi telemetry type][telemetry inversion][debug]-[firmware version] + Where: + [board type] is avr, stm, or orx + [bootloader support] b for optiboot (AVR) / USB (STM) or u (unsupported) + [check for bootloader] is c (CHECK_FOR_BOOTLOADER) or u (undefined) + [telemetry type] is t (MULTI_TELEMETRY), s (MULTI_STATUS), or u (undefined) for neither + [telemetry inversion] is i (INVERT_TELEMETRY) or u (undefined) + [firmware version] is the version padded to two bytes per segment, without seperators e.g. 01020176 + + For example: REM multi-stm-bcsid-01020176 +*/ + +class MultiFirmwareInformation { + public: + enum MultiFirmwareBoardType { + FIRMWARE_MULTI_STM, + FIRMWARE_MULTI_AVR, + FIRMWARE_MULTI_ORX, + }; + + enum MultiFirmwareTelemetryType { + FIRMWARE_MULTI_TELEM_MULTI, + FIRMWARE_MULTI_TELEM_STATUS, + FIRMWARE_MULTI_TELEM_NONE, + }; + + bool isMultiStmFirmware() const + { + return boardType == FIRMWARE_MULTI_STM; + } + + bool isMultiAvrFirmware() const + { + return boardType == FIRMWARE_MULTI_AVR; + } + + bool isMultiOrxFirmware() const + { + return boardType == FIRMWARE_MULTI_ORX; + } + + bool isMultiWithBootloaderFirmware() const + { + return optibootSupport; + } + + bool isMultiInternalFirmware() const + { + return (boardType == FIRMWARE_MULTI_STM && telemetryInversion == false && optibootSupport == true && telemetryType == FIRMWARE_MULTI_TELEM_STATUS); + } + + bool isMultiExternalFirmware() const + { + return (telemetryInversion == false && optibootSupport == true && telemetryType == FIRMWARE_MULTI_TELEM_STATUS); + } + + const char * readMultiFirmwareInformation(const char * filename); + + private: + uint8_t boardType; + uint8_t optibootSupport; + uint8_t bootloaderCheck; + uint8_t telemetryType; + uint8_t telemetryInversion; + uint8_t firmwareVersionMajor; + uint8_t firmwareVersionMinor; + uint8_t firmwareVersionRevision; + uint8_t firmwareVersionSubRevision; +}; + +const char* multiFlashFirmware(uint8_t module, const char * filename); + +#endif //OPENTX_MULTI_FIRMWARE_H diff --git a/radio/src/io/stk500.h b/radio/src/io/stk500.h new file mode 100644 index 000000000..ca0dd91df --- /dev/null +++ b/radio/src/io/stk500.h @@ -0,0 +1,39 @@ +/* STK500 constants list, from AVRDUDE */ +#define STK_OK 0x10 +#define STK_FAILED 0x11 // Not used +#define STK_UNKNOWN 0x12 // Not used +#define STK_NODEVICE 0x13 // Not used +#define STK_INSYNC 0x14 // ' ' +#define STK_NOSYNC 0x15 // Not used +#define ADC_CHANNEL_ERROR 0x16 // Not used +#define ADC_MEASURE_OK 0x17 // Not used +#define PWM_CHANNEL_ERROR 0x18 // Not used +#define PWM_ADJUST_OK 0x19 // Not used +#define CRC_EOP 0x20 // 'SPACE' +#define STK_GET_SYNC 0x30 // '0' +#define STK_GET_SIGN_ON 0x31 // '1' +#define STK_SET_PARAMETER 0x40 // '@' +#define STK_GET_PARAMETER 0x41 // 'A' +#define STK_SET_DEVICE 0x42 // 'B' +#define STK_SET_DEVICE_EXT 0x45 // 'E' +#define STK_ENTER_PROGMODE 0x50 // 'P' +#define STK_LEAVE_PROGMODE 0x51 // 'Q' +#define STK_CHIP_ERASE 0x52 // 'R' +#define STK_CHECK_AUTOINC 0x53 // 'S' +#define STK_LOAD_ADDRESS 0x55 // 'U' +#define STK_UNIVERSAL 0x56 // 'V' +#define STK_PROG_FLASH 0x60 // '`' +#define STK_PROG_DATA 0x61 // 'a' +#define STK_PROG_FUSE 0x62 // 'b' +#define STK_PROG_LOCK 0x63 // 'c' +#define STK_PROG_PAGE 0x64 // 'd' +#define STK_PROG_FUSE_EXT 0x65 // 'e' +#define STK_READ_FLASH 0x70 // 'p' +#define STK_READ_DATA 0x71 // 'q' +#define STK_READ_FUSE 0x72 // 'r' +#define STK_READ_LOCK 0x73 // 's' +#define STK_READ_PAGE 0x74 // 't' +#define STK_READ_SIGN 0x75 // 'u' +#define STK_READ_OSCCAL 0x76 // 'v' +#define STK_READ_FUSE_EXT 0x77 // 'w' +#define STK_READ_OSCCAL_EXT 0x78 // 'x' diff --git a/radio/src/lua/CMakeLists.txt b/radio/src/lua/CMakeLists.txt index 751d4716a..f0ed96e94 100644 --- a/radio/src/lua/CMakeLists.txt +++ b/radio/src/lua/CMakeLists.txt @@ -26,4 +26,5 @@ if(PYTHONINTERP_FOUND) add_lua_export_target(x10 ${LUA_INCLUDES} -DPCBHORUS -DPCBX10) add_lua_export_target(x12s ${LUA_INCLUDES} -DPCBHORUS -DPCBX12S) add_lua_export_target(t12 ${LUA_INCLUDES} -DPCBTARANIS -DPCBX7 -DRADIO_T12) + add_lua_export_target(t16 ${LUA_INCLUDES} -DPCBHORUS -DPCBX10 -DRADIO_T16) endif() diff --git a/radio/src/lua/api_general.cpp b/radio/src/lua/api_general.cpp index e69ea7060..9dec737d3 100644 --- a/radio/src/lua/api_general.cpp +++ b/radio/src/lua/api_general.cpp @@ -27,6 +27,8 @@ #if defined(PCBX12S) #include "lua/lua_exports_x12s.inc" // this line must be after lua headers +#elif defined(RADIO_T16) + #include "lua/lua_exports_t16.inc" #elif defined(PCBX10) #include "lua/lua_exports_x10.inc" #elif defined(PCBX9E) diff --git a/radio/src/opentx.cpp b/radio/src/opentx.cpp index 16419655d..8191cccfa 100644 --- a/radio/src/opentx.cpp +++ b/radio/src/opentx.cpp @@ -1512,7 +1512,7 @@ void doMixerCalculations() static uint8_t countRangecheck = 0; for (uint8_t i=0; i= MODULE_MODE_BEEP_FIRST || multiModuleStatus.isBinding()) { + if (moduleState[i].mode >= MODULE_MODE_BEEP_FIRST || getMultiModuleStatus(i).isBinding()) { #else if (moduleState[i].mode >= MODULE_MODE_BEEP_FIRST) { #endif @@ -1862,7 +1862,7 @@ void opentxInit() sportStopSendByteLoop(); if (f_stat(AUTOUPDATE_FILENAME, nullptr) == FR_OK) { FrSkyFirmwareInformation information; - if (readFirmwareInformation(AUTOUPDATE_FILENAME, information) == nullptr) { + if (readFrSkyFirmwareInformation(AUTOUPDATE_FILENAME, information) == nullptr) { #if defined(BLUETOOTH) if (information.productFamily == FIRMWARE_FAMILY_BLUETOOTH_CHIP) { if (bluetooth.flashFirmware(AUTOUPDATE_FILENAME) == nullptr) diff --git a/radio/src/opentx.h b/radio/src/opentx.h index a2c3d86ca..5d2266202 100644 --- a/radio/src/opentx.h +++ b/radio/src/opentx.h @@ -544,6 +544,8 @@ bool setTrimValue(uint8_t phase, uint8_t idx, int trim); #if defined(PCBSKY9X) #define ROTARY_ENCODER_GRANULARITY (2 << g_eeGeneral.rotarySteps) +#elif defined(RADIO_T16) + #define ROTARY_ENCODER_GRANULARITY (1) #else #define ROTARY_ENCODER_GRANULARITY (2) #endif diff --git a/radio/src/options.h b/radio/src/options.h index 1038af319..e7ddb0caf 100644 --- a/radio/src/options.h +++ b/radio/src/options.h @@ -56,6 +56,9 @@ static const char * options[] = { #if defined(INTERNAL_MODULE_PPM) "internalppm", #endif +#if defined(INTERNAL_MODULE_MULTI) + "internalmulti", +#endif #if defined(MULTIMODULE) "multimodule", #endif diff --git a/radio/src/pulses/modules_helpers.h b/radio/src/pulses/modules_helpers.h index 3bc69e3bc..6a2a6a34b 100644 --- a/radio/src/pulses/modules_helpers.h +++ b/radio/src/pulses/modules_helpers.h @@ -34,7 +34,7 @@ #if defined(MULTIMODULE) inline bool isModuleMultimodule(uint8_t idx) { - return idx == EXTERNAL_MODULE && g_model.moduleData[EXTERNAL_MODULE].type == MODULE_TYPE_MULTIMODULE; + return g_model.moduleData[idx].type == MODULE_TYPE_MULTIMODULE; } inline bool isModuleMultimoduleDSM2(uint8_t idx) @@ -350,8 +350,10 @@ inline bool isModuleFailsafeAvailable(uint8_t idx) return g_model.moduleData[idx].subType == MODULE_SUBTYPE_PXX1_ACCST_D16; #if defined(MULTIMODULE) - if (isModuleMultimodule(idx)) - return multiModuleStatus.isValid() && multiModuleStatus.supportsFailsafe(); + if (isModuleMultimodule(idx)){ + MultiModuleStatus& status = getMultiModuleStatus(idx); + return status.isValid() && status.supportsFailsafe(); + } #endif if (isModuleR9M(idx)) diff --git a/radio/src/pulses/multi.cpp b/radio/src/pulses/multi.cpp index a84bb04a1..9ceb57886 100644 --- a/radio/src/pulses/multi.cpp +++ b/radio/src/pulses/multi.cpp @@ -31,27 +31,38 @@ #define MULTI_CHANS 16 #define MULTI_CHAN_BITS 11 -static void sendFrameProtocolHeader(uint8_t port, bool failsafe); +static void sendFrameProtocolHeader(uint8_t moduleIdx, bool failsafe); -void sendChannels(uint8_t port); +void sendChannels(uint8_t moduleIdx); -static void sendSetupFrame() +static void sendMulti(uint8_t moduleIdx, uint8_t b) +{ +#if defined(INTERNAL_MODULE_MULTI) + if (moduleIdx == INTERNAL_MODULE) { + intmodulePulsesData.multi.sendByte(b); + } + else +#endif + sendByteSbus(b); +} + +static void sendSetupFrame(uint8_t moduleIdx) { // Old multi firmware will mark config messsages as invalid frame and throw them away - sendByteSbus('M'); - sendByteSbus('P'); - sendByteSbus(0x80); // Module Configuration - sendByteSbus(1); // 1 byte data + 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 - sendByteSbus(config); + sendMulti(moduleIdx, config); } -static void sendFailsafeChannels(uint8_t port) +static void sendFailsafeChannels(uint8_t moduleIdx) { uint32_t bits = 0; uint8_t bitsavailable = 0; @@ -60,61 +71,72 @@ static void sendFailsafeChannels(uint8_t port) int16_t failsafeValue = g_model.failsafeChannels[i]; int pulseValue; - if (g_model.moduleData[port].failsafeMode == FAILSAFE_HOLD) { + if (g_model.moduleData[moduleIdx].failsafeMode == FAILSAFE_HOLD) { pulseValue = 2047; } - else if (g_model.moduleData[port].failsafeMode == FAILSAFE_NOPULSES) { + else if (g_model.moduleData[moduleIdx].failsafeMode == FAILSAFE_NOPULSES) { pulseValue = 0; } else { - failsafeValue += 2 * PPM_CH_CENTER(g_model.moduleData[port].channelsStart + i) - 2 * PPM_CENTER; + failsafeValue += 2 * PPM_CH_CENTER(g_model.moduleData[moduleIdx].channelsStart + i) - 2 * PPM_CENTER; pulseValue = limit(1, (failsafeValue * 800 / 1000) + 1024, 2047); } bits |= pulseValue << bitsavailable; bitsavailable += MULTI_CHAN_BITS; while (bitsavailable >= 8) { - sendByteSbus((uint8_t) (bits & 0xff)); + sendMulti(moduleIdx, (uint8_t) (bits & 0xff)); bits >>= 8; bitsavailable -= 8; } } } -void setupPulsesMultimodule() +void setupPulsesMulti(uint8_t moduleIdx) { - static int counter = 0; + static int counter[2] = {0,0}; //TODO + // 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); + sendFailsafeChannels(moduleIdx); + } + else { + // Normal Frame + sendFrameProtocolHeader(moduleIdx, false); + sendChannels(moduleIdx); + } +} + +void setupPulsesMultiExternalModule() +{ #if defined(PPM_PIN_SERIAL) extmodulePulsesData.dsm2.serialByte = 0 ; extmodulePulsesData.dsm2.serialBitCount = 0 ; #else - extmodulePulsesData.dsm2.rest = multiSyncStatus.getAdjustedRefreshRate(); + extmodulePulsesData.dsm2.rest = getMultiSyncStatus(EXTERNAL_MODULE).getAdjustedRefreshRate(); extmodulePulsesData.dsm2.index = 0; #endif extmodulePulsesData.dsm2.ptr = extmodulePulsesData.dsm2.pulses; - // Every 1000 cycles (=9s) send a config packet that configures the multimodule (inversion, telemetry type) - counter++; - if (counter % 1000 == 500) { - sendSetupFrame(); - } - else if (counter % 1000 == 0 && g_model.moduleData[EXTERNAL_MODULE].failsafeMode != FAILSAFE_NOT_SET && g_model.moduleData[EXTERNAL_MODULE].failsafeMode != FAILSAFE_RECEIVER) { - sendFrameProtocolHeader(EXTERNAL_MODULE, true); - sendFailsafeChannels(EXTERNAL_MODULE); - } - else { - // Normal Frame - sendFrameProtocolHeader(EXTERNAL_MODULE, false); - sendChannels(EXTERNAL_MODULE); - } - + setupPulsesMulti(EXTERNAL_MODULE); putDsm2Flush(); } +#if defined(INTERNAL_MODULE_MULTI) +void setupPulsesMultiInternalModule() +{ + intmodulePulsesData.multi.initFrame(); + setupPulsesMulti(INTERNAL_MODULE); +} +#endif -void sendChannels(uint8_t port) +void sendChannels(uint8_t moduleIdx) { uint32_t bits = 0; uint8_t bitsavailable = 0; @@ -123,7 +145,7 @@ void sendChannels(uint8_t port) // Range for pulses (channelsOutputs) is [-1024:+1024] for [-100%;100%] // Multi uses [204;1843] as [-100%;100%] for (int i = 0; i < MULTI_CHANS; i++) { - int channel = g_model.moduleData[port].channelsStart + i; + int channel = g_model.moduleData[moduleIdx].channelsStart + i; int value = channelOutputs[channel] + 2 * PPM_CH_CENTER(channel) - 2 * PPM_CENTER; // Scale to 80% @@ -133,36 +155,36 @@ void sendChannels(uint8_t port) bits |= value << bitsavailable; bitsavailable += MULTI_CHAN_BITS; while (bitsavailable >= 8) { - sendByteSbus((uint8_t) (bits & 0xff)); + sendMulti(moduleIdx, (uint8_t) (bits & 0xff)); bits >>= 8; bitsavailable -= 8; } } } -void sendFrameProtocolHeader(uint8_t port, bool failsafe) +void sendFrameProtocolHeader(uint8_t moduleIdx, bool failsafe) {// byte 1+2, protocol information // Our enumeration starts at 0 - int type = g_model.moduleData[port].getMultiProtocol(false) + 1; - int subtype = g_model.moduleData[port].subType; - int8_t optionValue = g_model.moduleData[port].multi.optionValue; + int type = g_model.moduleData[moduleIdx].getMultiProtocol(false) + 1; + int subtype = g_model.moduleData[moduleIdx].subType; + int8_t optionValue = g_model.moduleData[moduleIdx].multi.optionValue; uint8_t protoByte = 0; - if (moduleState[port].mode == MODULE_MODE_BIND) + if (moduleState[moduleIdx].mode == MODULE_MODE_BIND) protoByte |= MULTI_SEND_BIND; - else if (moduleState[port].mode == MODULE_MODE_RANGECHECK) + else if (moduleState[moduleIdx].mode == MODULE_MODE_RANGECHECK) protoByte |= MULTI_SEND_RANGECHECK; // rfProtocol - if (g_model.moduleData[port].getMultiProtocol(true) == MODULE_SUBTYPE_MULTI_DSM2) { + if (g_model.moduleData[moduleIdx].getMultiProtocol(true) == MODULE_SUBTYPE_MULTI_DSM2) { // Autobinding should always be done in DSMX 11ms - if (g_model.moduleData[port].multi.autoBindMode && moduleState[port].mode == MODULE_MODE_BIND) + 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(EXTERNAL_MODULE); + optionValue = sentModuleChannels(moduleIdx); } @@ -175,7 +197,7 @@ void sendFrameProtocolHeader(uint8_t port, bool failsafe) if (type >= 25) type = type + 1; - if (g_model.moduleData[port].getMultiProtocol(true) == MODULE_SUBTYPE_MULTI_FRSKY) { + if (g_model.moduleData[moduleIdx].getMultiProtocol(true) == MODULE_SUBTYPE_MULTI_FRSKY) { if (subtype == MM_RF_FRSKY_SUBTYPE_D8) { //D8 type = 3; @@ -199,12 +221,12 @@ void sendFrameProtocolHeader(uint8_t port, 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[port].getMultiProtocol(false) == MODULE_SUBTYPE_MULTI_FS_AFHDS2A) + if (g_model.moduleData[moduleIdx].getMultiProtocol(false) == MODULE_SUBTYPE_MULTI_FS_AFHDS2A) optionValue = optionValue | 0x80; // For custom protocol send unmodified type byte - if (g_model.moduleData[port].getMultiProtocol(true) == MM_RF_CUSTOM_SELECTED) - type = g_model.moduleData[port].getMultiProtocol(false); + if (g_model.moduleData[moduleIdx].getMultiProtocol(true) == MM_RF_CUSTOM_SELECTED) + type = g_model.moduleData[moduleIdx].getMultiProtocol(false); uint8_t headerByte = 0x54; @@ -213,24 +235,24 @@ void sendFrameProtocolHeader(uint8_t port, bool failsafe) // header, byte 0, 0x55 for proto 0-31 0x54 for 32-63 if (type <= 31) - sendByteSbus(headerByte+1); + sendMulti(moduleIdx, headerByte+1); else - sendByteSbus(headerByte); + sendMulti(moduleIdx, headerByte); // protocol byte protoByte |= (type & 0x1f); - if (g_model.moduleData[port].getMultiProtocol(true) != MODULE_SUBTYPE_MULTI_DSM2) - protoByte |= (g_model.moduleData[port].multi.autoBindMode << 6); + if (g_model.moduleData[moduleIdx].getMultiProtocol(true) != MODULE_SUBTYPE_MULTI_DSM2) + protoByte |= (g_model.moduleData[moduleIdx].multi.autoBindMode << 6); - sendByteSbus(protoByte); + sendMulti(moduleIdx, protoByte); // byte 2, subtype, powermode, model id - sendByteSbus((uint8_t) ((g_model.header.modelId[port] & 0x0f) + sendMulti(moduleIdx, (uint8_t) ((g_model.header.modelId[moduleIdx] & 0x0f) | ((subtype & 0x7) << 4) - | (g_model.moduleData[port].multi.lowPowerMode << 7)) + | (g_model.moduleData[moduleIdx].multi.lowPowerMode << 7)) ); // byte 3 - sendByteSbus((uint8_t) optionValue); + sendMulti(moduleIdx, (uint8_t) optionValue); } diff --git a/radio/src/pulses/multi.h b/radio/src/pulses/multi.h new file mode 100644 index 000000000..d3f088b7d --- /dev/null +++ b/radio/src/pulses/multi.h @@ -0,0 +1,41 @@ +/* + * 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 _MULTI_PULSES_H_ +#define _MULTI_PULSES_H_ + +#include "pulses_common.h" + +class UartMultiPulses: public DataBuffer +{ + public: + void initFrame() + { + initBuffer(); + } + + void sendByte(uint8_t b) + { + if (getSize() < 64) + *ptr++ = b; + } +}; + +#endif diff --git a/radio/src/pulses/pulses.cpp b/radio/src/pulses/pulses.cpp index cec72d8a0..e771d4e90 100755 --- a/radio/src/pulses/pulses.cpp +++ b/radio/src/pulses/pulses.cpp @@ -269,7 +269,7 @@ void setupPulsesExternalModule(uint8_t protocol) #if defined(MULTIMODULE) case PROTOCOL_CHANNELS_MULTIMODULE: - setupPulsesMultimodule(); + setupPulsesMultiExternalModule(); scheduleNextMixerCalculation(EXTERNAL_MODULE, MULTIMODULE_PERIOD); break; #endif @@ -306,10 +306,17 @@ void enablePulsesInternalModule(uint8_t protocol) #if defined(PXX2) case PROTOCOL_CHANNELS_PXX2_HIGHSPEED: - intmoduleSerialStart(PXX2_HIGHSPEED_BAUDRATE, true); + intmoduleSerialStart(PXX2_HIGHSPEED_BAUDRATE, true, USART_Parity_No, USART_StopBits_1, USART_WordLength_8b); break; #endif +#if defined(INTERNAL_MODULE_MULTI) + case PROTOCOL_CHANNELS_MULTIMODULE: + intmodulePulsesData.multi.initFrame(); + intmoduleSerialStart(MULTIMODULE_BAUDRATE, true, USART_Parity_Even, USART_StopBits_2, USART_WordLength_9b); + intmoduleTimerStart(MULTIMODULE_PERIOD); + break; +#endif default: break; } @@ -355,6 +362,13 @@ void setupPulsesInternalModule(uint8_t protocol) break; #endif +#if defined(INTERNAL_MODULE_MULTI) + case PROTOCOL_CHANNELS_MULTIMODULE: + setupPulsesMultiInternalModule(); + scheduleNextMixerCalculation(INTERNAL_MODULE, MULTIMODULE_PERIOD); + break; +#endif + default: break; } diff --git a/radio/src/pulses/pulses.h b/radio/src/pulses/pulses.h index e2aa1664a..9fa17a196 100644 --- a/radio/src/pulses/pulses.h +++ b/radio/src/pulses/pulses.h @@ -24,8 +24,9 @@ #include "definitions.h" #include "dataconstants.h" #include "pulses_common.h" -#include "pulses/pxx1.h" -#include "pulses/pxx2.h" +#include "pxx1.h" +#include "pxx2.h" +#include "multi.h" #include "modules_helpers.h" #include "ff.h" @@ -248,6 +249,10 @@ union InternalModulePulsesData { Pxx2Pulses pxx2; #endif +#if defined(INTERNAL_MODULE_MULTI) //&& defined(INTMODULE_USART) + UartMultiPulses multi; +#endif + #if defined(INTERNAL_MODULE_PPM) PpmPulsesData ppm; #endif @@ -294,11 +299,14 @@ union TrainerPulsesData { extern TrainerPulsesData trainerPulsesData; +#if defined(HARDWARE_INTERNAL_MODULE) bool setupPulsesInternalModule(); +#endif bool setupPulsesExternalModule(); void setupPulsesDSM2(); void setupPulsesCrossfire(); -void setupPulsesMultimodule(); +void setupPulsesMultiExternalModule(); +void setupPulsesMultiInternalModule(); void setupPulsesSbus(); void setupPulsesPPMInternalModule(); void setupPulsesPPMExternalModule(); diff --git a/radio/src/pulses/pxx2.cpp b/radio/src/pulses/pxx2.cpp index b32eede0c..baa421de7 100644 --- a/radio/src/pulses/pxx2.cpp +++ b/radio/src/pulses/pxx2.cpp @@ -469,7 +469,7 @@ const char * Pxx2OtaUpdate::doFlashFirmware(const char * filename) uint32_t size; const char * ext = getFileExtension(filename); - if (ext && !strcasecmp(ext, UPDATE_FIRMWARE_EXT)) { + if (ext && !strcasecmp(ext, FRSKY_FIRMWARE_EXT)) { FrSkyFirmwareInformation * information = (FrSkyFirmwareInformation *) buffer; if (f_read(&file, buffer, sizeof(FrSkyFirmwareInformation), &count) != FR_OK || count != sizeof(FrSkyFirmwareInformation)) { f_close(&file); diff --git a/radio/src/sdcard.h b/radio/src/sdcard.h index 0b518eb24..3f7ed8eda 100644 --- a/radio/src/sdcard.h +++ b/radio/src/sdcard.h @@ -70,7 +70,8 @@ const char RADIO_SETTINGS_PATH[] = RADIO_PATH "/radio.bin"; #define FIRMWARE_EXT ".bin" #define EEPROM_EXT ".bin" #define SPORT_FIRMWARE_EXT ".frk" -#define UPDATE_FIRMWARE_EXT ".frsk" +#define FRSKY_FIRMWARE_EXT ".frsk" +#define MULTI_FIRMWARE_EXT ".bin" #define LEN_FILE_EXTENSION_MAX 5 // longest used, including the dot, excluding null term. @@ -125,6 +126,8 @@ const char * getBasename(const char * path); #if defined(PCBX12S) #define OTX_FOURCC 0x3478746F // otx for X12S +#elif defined(RADIO_T16) + #define OTX_FOURCC 0x3F78746F // otx for Jumper T16 #elif defined(PCBX10) #define OTX_FOURCC 0x3778746F // otx for X10 #elif defined(PCBX9E) diff --git a/radio/src/storage/conversions/conversions_218_219.cpp b/radio/src/storage/conversions/conversions_218_219.cpp index f6076917d..bba32aef0 100644 --- a/radio/src/storage/conversions/conversions_218_219.cpp +++ b/radio/src/storage/conversions/conversions_218_219.cpp @@ -124,9 +124,11 @@ void convertModelData_218_to_219(ModelData &model) memclear(&newModel.header.bitmap[10], 4); memcpy(newModel.timers, oldModel.timers, offsetof(ModelData_v218, mixData) - offsetof(ModelData_v218, timers)); +#if defined(BLUETOOTH) // trainer battery compartment removed if (newModel.trainerData.mode >= TRAINER_MODE_MASTER_BLUETOOTH) newModel.trainerData.mode -= 1; +#endif #endif memclear(newModel.mixData, sizeof(ModelData_v219) - offsetof(ModelData_v219, mixData)); diff --git a/radio/src/targets/common/arm/CMakeLists.txt b/radio/src/targets/common/arm/CMakeLists.txt index 9b488138c..04d30f936 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/multi.cpp) + set(SRC ${SRC} pulses/multi.cpp telemetry/spektrum.cpp telemetry/flysky_ibus.cpp telemetry/multi.cpp io/multi_firmware_update.cpp) endif() if(CROSSFIRE) diff --git a/radio/src/targets/common/arm/stm32/adc_driver.cpp b/radio/src/targets/common/arm/stm32/adc_driver.cpp index 36d0e5a60..49887799e 100644 --- a/radio/src/targets/common/arm/stm32/adc_driver.cpp +++ b/radio/src/targets/common/arm/stm32/adc_driver.cpp @@ -22,8 +22,10 @@ #if defined(SIMU) // not needed +#elif defined(RADIO_T16) + const int8_t adcDirection[NUM_ANALOGS] = {1,-1,1,-1, 1,1,1, -1,1, -1,1}; #elif defined(PCBX10) - const int8_t adcDirection[NUM_ANALOGS] = {1,-1,1,-1, -1,1,-1, 1,1, 1, -1}; + const int8_t adcDirection[NUM_ANALOGS] = {1,-1,1,-1, -1,1,-1, 1,1, 1, -1}; #elif defined(PCBX9E) #if defined(HORUS_STICKS) const int8_t adcDirection[NUM_ANALOGS] = {1,-1,1,-1, -1,-1,-1,1, -1,1,-1, -1,-1,-1}; diff --git a/radio/src/targets/common/arm/stm32/audio_dac_driver.cpp b/radio/src/targets/common/arm/stm32/audio_dac_driver.cpp index fd1e83183..2962731b7 100644 --- a/radio/src/targets/common/arm/stm32/audio_dac_driver.cpp +++ b/radio/src/targets/common/arm/stm32/audio_dac_driver.cpp @@ -95,8 +95,14 @@ void audioConsumeCurrentBuffer() nextBuffer = audioQueue.buffersFifo.getNextFilledBuffer(); if (nextBuffer) { #if defined(AUDIO_MUTE_GPIO_PIN) - // un-mute - GPIO_ResetBits(AUDIO_MUTE_GPIO, AUDIO_MUTE_GPIO_PIN); + // if muted + if (GPIO_ReadOutputDataBit(AUDIO_MUTE_GPIO, AUDIO_MUTE_GPIO_PIN)) { + // ..un-mute + GPIO_ResetBits(AUDIO_MUTE_GPIO, AUDIO_MUTE_GPIO_PIN); +#if defined(AUDIO_UNMUTE_DELAY) + RTOS_WAIT_MS(AUDIO_UNMUTE_DELAY); +#endif + } #endif AUDIO_DMA_Stream->CR &= ~DMA_SxCR_EN ; // Disable DMA channel AUDIO_DMA->HIFCR = DMA_HIFCR_CTCIF5 | DMA_HIFCR_CHTIF5 | DMA_HIFCR_CTEIF5 | DMA_HIFCR_CDMEIF5 | DMA_HIFCR_CFEIF5 ; // Write ones to clear bits diff --git a/radio/src/targets/common/arm/stm32/aux_serial_driver.cpp b/radio/src/targets/common/arm/stm32/aux_serial_driver.cpp index 1f22abc48..9499e24f9 100644 --- a/radio/src/targets/common/arm/stm32/aux_serial_driver.cpp +++ b/radio/src/targets/common/arm/stm32/aux_serial_driver.cpp @@ -20,6 +20,7 @@ #include "opentx.h" +#if defined(AUX_SERIAL) uint8_t auxSerialMode = 0; Fifo auxSerialTxFifo; AuxSerialRxFifo auxSerialRxFifo __DMA (AUX_SERIAL_DMA_Stream_RX); @@ -183,4 +184,5 @@ extern "C" void AUX_SERIAL_USART_IRQHandler(void) } #endif } -#endif \ No newline at end of file +#endif +#endif // AUX_SERIAL diff --git a/radio/src/targets/common/arm/stm32/intmodule_serial_driver.cpp b/radio/src/targets/common/arm/stm32/intmodule_serial_driver.cpp index 8102b5eee..e2f01f586 100755 --- a/radio/src/targets/common/arm/stm32/intmodule_serial_driver.cpp +++ b/radio/src/targets/common/arm/stm32/intmodule_serial_driver.cpp @@ -39,14 +39,20 @@ void intmoduleStop() USART_DeInit(INTMODULE_USART); GPIO_ResetBits(INTMODULE_GPIO, INTMODULE_TX_GPIO_PIN | INTMODULE_RX_GPIO_PIN); + +#if defined(INTERNAL_MODULE_MULTI) + // stop pulses timer + INTMODULE_TIMER->DIER &= ~TIM_DIER_CC2IE; + INTMODULE_TIMER->CR1 &= ~TIM_CR1_CEN; +#endif } void intmodulePxx1SerialStart() { - intmoduleSerialStart(INTMODULE_PXX1_SERIAL_BAUDRATE, false); + intmoduleSerialStart(INTMODULE_PXX1_SERIAL_BAUDRATE, false, USART_Parity_No, USART_StopBits_1, USART_WordLength_8b); } -void intmoduleSerialStart(uint32_t baudrate, uint8_t rxEnable) +void intmoduleSerialStart(uint32_t baudrate, uint8_t rxEnable, uint16_t parity, uint16_t stopBits, uint16_t wordLength) { INTERNAL_MODULE_ON(); @@ -71,9 +77,9 @@ void intmoduleSerialStart(uint32_t baudrate, uint8_t rxEnable) USART_DeInit(INTMODULE_USART); USART_InitTypeDef USART_InitStructure; USART_InitStructure.USART_BaudRate = baudrate; - USART_InitStructure.USART_Parity = USART_Parity_No; - USART_InitStructure.USART_StopBits = USART_StopBits_1; - USART_InitStructure.USART_WordLength = USART_WordLength_8b; + USART_InitStructure.USART_Parity = parity; + USART_InitStructure.USART_StopBits = stopBits; + USART_InitStructure.USART_WordLength = wordLength; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; USART_Init(INTMODULE_USART, &USART_InitStructure); @@ -87,6 +93,28 @@ void intmoduleSerialStart(uint32_t baudrate, uint8_t rxEnable) } } +#if defined(INTERNAL_MODULE_MULTI) +void intmoduleTimerStart(uint32_t periodMs) +{ + // Timer + INTMODULE_TIMER->CR1 &= ~TIM_CR1_CEN; + INTMODULE_TIMER->PSC = INTMODULE_TIMER_FREQ / 2000000 - 1; // 0.5uS (2Mhz) + INTMODULE_TIMER->ARR = periodMs * 2000; + INTMODULE_TIMER->CCR2 = (periodMs - 1) * 2000; + INTMODULE_TIMER->CCER = TIM_CCER_CC3E; + INTMODULE_TIMER->CCMR2 = 0; + INTMODULE_TIMER->EGR = 1; // Restart + + INTMODULE_TIMER->CCMR2 = TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3M_0; // Toggle CC1 o/p + INTMODULE_TIMER->SR &= ~TIM_SR_CC2IF; // Clear flag + INTMODULE_TIMER->DIER |= TIM_DIER_CC2IE; // Enable this interrupt + INTMODULE_TIMER->CR1 |= TIM_CR1_CEN; + + NVIC_EnableIRQ(INTMODULE_TIMER_IRQn); + NVIC_SetPriority(INTMODULE_TIMER_IRQn, 7); +} +#endif + #define USART_FLAG_ERRORS (USART_FLAG_ORE | USART_FLAG_NE | USART_FLAG_FE | USART_FLAG_PE) extern "C" void INTMODULE_USART_IRQHandler(void) { @@ -98,7 +126,6 @@ extern "C" void INTMODULE_USART_IRQHandler(void) intmoduleFifo.errors++; } else { - hardwareOptions.pxx2Enabled = true; intmoduleFifo.push(data); } status = INTMODULE_USART->SR; @@ -152,5 +179,20 @@ void intmoduleSendNextFrame() intmoduleSendBuffer(intmodulePulsesData.pxx_uart.getData(), intmodulePulsesData.pxx_uart.getSize()); break; #endif + +#if defined(INTERNAL_MODULE_MULTI) + case PROTOCOL_CHANNELS_MULTIMODULE: + intmoduleSendBuffer(intmodulePulsesData.multi.getData(), intmodulePulsesData.multi.getSize()); + break; +#endif } } + +#if defined(INTERNAL_MODULE_MULTI) +extern "C" void INTMODULE_TIMER_IRQHandler() +{ + INTMODULE_TIMER->SR &= ~TIM_SR_CC2IF; // clear flag + setupPulsesInternalModule(); + intmoduleSendNextFrame(); +} +#endif diff --git a/radio/src/targets/common/arm/stm32/rotary_encoder_driver.cpp b/radio/src/targets/common/arm/stm32/rotary_encoder_driver.cpp index fc028d3b5..e457de7d7 100644 --- a/radio/src/targets/common/arm/stm32/rotary_encoder_driver.cpp +++ b/radio/src/targets/common/arm/stm32/rotary_encoder_driver.cpp @@ -71,6 +71,27 @@ void rotaryEncoderInit() void rotaryEncoderCheck() { +#if defined(RADIO_T16) + static uint8_t state = 0; + uint8_t pins = ROTARY_ENCODER_POSITION(); + + if (pins != (state & 0x03) && !(readKeys() & (1 << KEY_ENTER))) { + if ((pins & 0x01) ^ ((pins & 0x02) >> 1)) { + if ((state & 0x03) == 3) + ++rotencValue; + else + --rotencValue; + } + else + { + if ((state & 0x03) == 3) + --rotencValue; + else if ((state & 0x03) == 0) + ++rotencValue; + } + state &= ~0x03 ; + state |= pins ; +#else uint8_t newPosition = ROTARY_ENCODER_POSITION(); if (newPosition != rotencPosition && !(readKeys() & (1 << KEY_ENTER))) { if ((rotencPosition & 0x01) ^ ((newPosition & 0x02) >> 1)) { @@ -80,6 +101,7 @@ void rotaryEncoderCheck() ++rotencValue; } rotencPosition = newPosition; +#endif #if !defined(BOOT) if (g_eeGeneral.backlightMode & e_backlight_mode_keys) { backlightOn(); @@ -127,4 +149,4 @@ extern "C" void ROTARY_ENCODER_TIMER_IRQHandler(void) ROTARY_ENCODER_TIMER->SR &= ~TIM_SR_UIF; ROTARY_ENCODER_TIMER->CR1 = 0; rotaryEncoderCheck(); -} \ No newline at end of file +} diff --git a/radio/src/targets/horus/CMakeLists.txt b/radio/src/targets/horus/CMakeLists.txt index 118426265..065e4d6ba 100644 --- a/radio/src/targets/horus/CMakeLists.txt +++ b/radio/src/targets/horus/CMakeLists.txt @@ -44,15 +44,23 @@ if (PCB STREQUAL X10) set(FLAVOUR x10express) option(INTERNAL_MODULE_PXX1 "Support for PXX1 internal module" OFF) option(INTERNAL_MODULE_PXX2 "Support for PXX2 internal module" ON) + set(BLUETOOTH ON) + elseif (PCBREV STREQUAL T16) + set(FLAVOUR t16) + set(LUA_EXPORT lua_export_t16) + add_definitions(-DRADIO_T16) + option(INTERNAL_MODULE_MULTI "Support for MULTI internal module" OFF) else() set(FLAVOUR x10) option(INTERNAL_MODULE_PXX1 "Support for PXX1 internal module" ON) option(INTERNAL_MODULE_PXX2 "Support for PXX2 internal module" OFF) + set(BLUETOOTH ON) endif() elseif (PCB STREQUAL X12S) option(INTERNAL_MODULE_PXX1 "Support for PXX1 internal module" ON) option(INTERNAL_MODULE_PXX2 "Support for PXX2 internal module" OFF) set(FLAVOUR x12s) + set(BLUETOOTH ON) set(PCBREV "13" CACHE STRING "PCB Revision") if(${PCBREV} GREATER 10) option(INTERNAL_GPS "Internal GPS installed" YES) @@ -91,14 +99,21 @@ if(NOT UNEXPECTED_SHUTDOWN) endif() if(INTERNAL_MODULE_PXX1) + add_definitions(-DHARDWARE_INTERNAL_MODULE) add_definitions(-DINTERNAL_MODULE_PXX1) endif() if(INTERNAL_MODULE_PXX2) set(PXX2 ON) + add_definitions(-DHARDWARE_INTERNAL_MODULE) add_definitions(-DINTERNAL_MODULE_PXX2) endif() +if(INTERNAL_MODULE_MULTI) + add_definitions(-DHARDWARE_INTERNAL_MODULE) + add_definitions(-DINTERNAL_MODULE_MULTI) +endif() + include_directories(${RADIO_SRC_DIRECTORY}/fonts/480x272 gui/${GUI_DIR} gui/${GUI_DIR}/layouts) file(GLOB THEMES_SRC RELATIVE ${RADIO_SRC_DIRECTORY}/gui/480x272 ${RADIO_SRC_DIRECTORY}/gui/480x272/themes/*.cpp) @@ -163,10 +178,15 @@ set(TARGET_SRC ../common/arm/stm32/heartbeat_driver.cpp ../common/arm/stm32/timers_driver.cpp ../common/arm/stm32/intmodule_serial_driver.cpp - ../common/arm/stm32/bluetooth_driver.cpp ../common/arm/stm32/rotary_encoder_driver.cpp ) +if(BLUETOOTH) + add_definitions(-DBLUETOOTH) + set(TARGET_SRC ${TARGET_SRC} ../common/arm/stm32/bluetooth_driver.cpp) + set(SRC ${SRC} bluetooth.cpp) +endif() + set(FIRMWARE_TARGET_SRC ${FIRMWARE_TARGET_SRC} ${LCD_DRIVER} @@ -179,12 +199,10 @@ set(FIRMWARE_TARGET_SRC ../common/arm/loadboot.cpp ) -add_definitions(-DBLUETOOTH) - set(SRC ${SRC} - bluetooth.cpp io/frsky_firmware_update.cpp + io/multi_firmware_update.cpp ) set(STM32LIB_SRC @@ -202,4 +220,3 @@ if(PYTHONINTERP_FOUND) DEPENDS ${RADIO_DIRECTORY}/src/datastructs.h ${RADIO_DIRECTORY}/util/generate_datacopy.py ) endif() - diff --git a/radio/src/targets/horus/board.h b/radio/src/targets/horus/board.h index 13717068a..fb12142a0 100644 --- a/radio/src/targets/horus/board.h +++ b/radio/src/targets/horus/board.h @@ -59,7 +59,7 @@ extern uint16_t sessionTimer; #define SLAVE_MODE() (g_model.trainerData.mode == TRAINER_MODE_SLAVE) -#if defined(PCBX10) +#if defined(PCBX10) && !defined(RADIO_T16) #define TRAINER_CONNECTED() (GPIO_ReadInputDataBit(TRAINER_DETECT_GPIO, TRAINER_DETECT_GPIO_PIN) == Bit_SET) #else #define TRAINER_CONNECTED() (GPIO_ReadInputDataBit(TRAINER_DETECT_GPIO, TRAINER_DETECT_GPIO_PIN) == Bit_RESET) @@ -173,7 +173,10 @@ void SDRAM_Init(); void init_intmodule_heartbeat(); void check_intmodule_heartbeat(); -void intmoduleSerialStart(uint32_t baudrate, uint8_t rxEnable); +void intmoduleSerialStart(uint32_t baudrate, uint8_t rxEnable, uint16_t parity, uint16_t stopBits, uint16_t wordLength); +#if defined(INTERNAL_MODULE_MULTI) +void intmoduleTimerStart(uint32_t periodMs); +#endif void intmoduleSendByte(uint8_t byte); void intmoduleSendBuffer(const uint8_t * data, uint8_t size); void intmoduleSendNextFrame(); @@ -182,6 +185,7 @@ void extmoduleSerialStart(uint32_t baudrate, uint32_t period_half_us, bool inver void extmoduleInvertedSerialStart(uint32_t baudrate); void extmoduleSendBuffer(const uint8_t * data, uint8_t size); void extmoduleSendNextFrame(); +void extmoduleSendInvertedByte(uint8_t byte); // Trainer driver void init_trainer_ppm(); @@ -507,6 +511,8 @@ void backlightEnable(uint8_t dutyCycle = 0); #define BACKLIGHT_LEVEL_MAX 100 #if defined(PCBX12S) #define BACKLIGHT_LEVEL_MIN 5 +#elif defined(RADIO_T16) +#define BACKLIGHT_LEVEL_MIN 1 #else #define BACKLIGHT_LEVEL_MIN 46 #endif @@ -521,6 +527,10 @@ void usbJoystickUpdate(); #define USB_NAME "FrSky Horus" #define USB_MANUFACTURER 'F', 'r', 'S', 'k', 'y', ' ', ' ', ' ' /* 8 bytes */ #define USB_PRODUCT 'H', 'o', 'r', 'u', 's', ' ', ' ', ' ' /* 8 Bytes */ +#elif defined(RADIO_T16) + #define USB_NAME "Jumper T16" + #define USB_MANUFACTURER 'J', 'u', 'm', 'p', 'e', 'r', ' ', ' ' /* 8 bytes */ + #define USB_PRODUCT 'T', '1', '6', ' ', ' ', ' ', ' ', ' ' /* 8 Bytes */ #elif defined(PCBX10) #define USB_NAME "FrSky X10" #define USB_MANUFACTURER 'F', 'r', 'S', 'k', 'y', ' ', ' ', ' ' /* 8 bytes */ @@ -554,7 +564,7 @@ void telemetryPortSetDirectionInput(); void telemetryPortSetDirectionOutput(); void sportSendByte(uint8_t byte); void sportSendBuffer(const uint8_t * buffer, uint32_t count); -uint8_t telemetryGetByte(uint8_t * byte); +bool telemetryGetByte(uint8_t * byte); void telemetryClearFifo(); extern uint32_t telemetryErrors; @@ -605,6 +615,7 @@ void bluetoothDisable(); extern DMAFifo<512> telemetryFifo; typedef DMAFifo<32> AuxSerialRxFifo; extern AuxSerialRxFifo auxSerialRxFifo; +extern volatile uint32_t externalModulePort; #endif #endif // _BOARD_H_ diff --git a/radio/src/targets/horus/extmodule_driver.cpp b/radio/src/targets/horus/extmodule_driver.cpp index 5c628edf1..0da9e46a5 100644 --- a/radio/src/targets/horus/extmodule_driver.cpp +++ b/radio/src/targets/horus/extmodule_driver.cpp @@ -350,6 +350,38 @@ void extmoduleSendNextFrame() } } +void extmoduleSendInvertedByte(uint8_t byte) +{ + uint16_t time; + uint32_t i; + + __disable_irq(); + time = getTmr2MHz(); + GPIO_SetBits(EXTMODULE_TX_GPIO, EXTMODULE_TX_GPIO_PIN); + while ((uint16_t) (getTmr2MHz() - time) < 34) { + // wait + } + time += 34; + for (i = 0 ; i < 8 ; i += 1) { + if (byte & 1) { + GPIO_ResetBits(EXTMODULE_TX_GPIO, EXTMODULE_TX_GPIO_PIN); + } + else { + GPIO_SetBits(EXTMODULE_TX_GPIO, EXTMODULE_TX_GPIO_PIN); + } + byte >>= 1 ; + while ((uint16_t) (getTmr2MHz() - time) < 35) { + // wait + } + time += 35 ; + } + GPIO_ResetBits(EXTMODULE_TX_GPIO, EXTMODULE_TX_GPIO_PIN); + __enable_irq() ; // No need to wait for the stop bit to complete + while ((uint16_t) (getTmr2MHz() - time) < 34) { + // wait + } +} + extern "C" void EXTMODULE_TIMER_DMA_IRQHandler() { if (!DMA_GetITStatus(EXTMODULE_TIMER_DMA_STREAM, EXTMODULE_TIMER_DMA_FLAG_TC)) diff --git a/radio/src/targets/horus/hal.h b/radio/src/targets/horus/hal.h index 5c07cb7b5..18acb1602 100644 --- a/radio/src/targets/horus/hal.h +++ b/radio/src/targets/horus/hal.h @@ -183,10 +183,17 @@ #define TRIMS_GPIO_PIN_RVU GPIO_Pin_12 // PJ.12 #define TRIMS_GPIO_REG_RHR GPIOD->IDR #define TRIMS_GPIO_PIN_RHR GPIO_Pin_7 // PD.07 - #define TRIMS_GPIO_REG_LSU GPIOJ->IDR - #define TRIMS_GPIO_PIN_LSU GPIO_Pin_8 // PJ.08 - #define TRIMS_GPIO_REG_LSD GPIOD->IDR - #define TRIMS_GPIO_PIN_LSD GPIO_Pin_13 // PD.13 + #if defined(RADIO_T16) + #define TRIMS_GPIO_REG_LSU GPIOD->IDR + #define TRIMS_GPIO_PIN_LSU GPIO_Pin_13 // PD.13 + #define TRIMS_GPIO_REG_LSD GPIOJ->IDR + #define TRIMS_GPIO_PIN_LSD GPIO_Pin_8 // PJ.08 + #else + #define TRIMS_GPIO_REG_LSU GPIOJ->IDR + #define TRIMS_GPIO_PIN_LSU GPIO_Pin_8 // PJ.08 + #define TRIMS_GPIO_REG_LSD GPIOD->IDR + #define TRIMS_GPIO_PIN_LSD GPIO_Pin_13 // PD.13 + #endif #define TRIMS_GPIO_REG_RSU GPIOB->IDR #define TRIMS_GPIO_PIN_RSU GPIO_Pin_14 // PB.14 #define TRIMS_GPIO_REG_RSD GPIOB->IDR @@ -281,8 +288,12 @@ #define ADC_DMA_Stream DMA2_Stream0 #define ADC_SET_DMA_FLAGS() ADC_DMA->LIFCR = (DMA_LIFCR_CTCIF0 | DMA_LIFCR_CHTIF0 | DMA_LIFCR_CTEIF0 | DMA_LIFCR_CDMEIF0 | DMA_LIFCR_CFEIF0) #define ADC_TRANSFER_COMPLETE() (ADC_DMA->LISR & DMA_LISR_TCIF0) +#if defined(RADIO_T16) + #define ADC_VREF_PREC2 300 +#else #define ADC_VREF_PREC2 250 #endif +#endif // Power #define PWR_RCC_AHB1Periph RCC_AHB1Periph_GPIOJ @@ -525,6 +536,10 @@ #define AUDIO_DMA DMA1 #endif +#if defined(RADIO_T16) + #define AUDIO_UNMUTE_DELAY 150 +#endif + // I2C Bus #define I2C_RCC_AHB1Periph RCC_AHB1Periph_GPIOB #define I2C_RCC_APB1Periph RCC_APB1Periph_I2C1 @@ -563,9 +578,9 @@ #define HAPTIC_TIMER_COMPARE_VALUE HAPTIC_GPIO_TIMER->CCR2 #endif -// Internal Module -#define HARDWARE_INTERNAL_MODULE +#if !defined(RADIO_T16) #define EXTERNAL_ANTENNA +#endif #define INTMODULE_RCC_AHB1Periph (RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_DMA2) #define INTMODULE_PWR_GPIO GPIOA #define INTMODULE_PWR_GPIO_PIN GPIO_Pin_8 // PA.08 diff --git a/radio/src/targets/horus/telemetry_driver.cpp b/radio/src/targets/horus/telemetry_driver.cpp index 8b782f759..2ca7c6c0a 100644 --- a/radio/src/targets/horus/telemetry_driver.cpp +++ b/radio/src/targets/horus/telemetry_driver.cpp @@ -254,7 +254,7 @@ extern "C" void TELEMETRY_USART_IRQHandler(void) } // TODO we should have telemetry in an higher layer, functions above should move to a sport_driver.cpp -uint8_t telemetryGetByte(uint8_t * byte) +bool telemetryGetByte(uint8_t * byte) { #if defined(PCBX12S) if (telemetryFifoMode & TELEMETRY_SERIAL_WITHOUT_DMA) diff --git a/radio/src/targets/sky9x/CMakeLists.txt b/radio/src/targets/sky9x/CMakeLists.txt index 08b120ad8..b2bf06065 100644 --- a/radio/src/targets/sky9x/CMakeLists.txt +++ b/radio/src/targets/sky9x/CMakeLists.txt @@ -10,6 +10,7 @@ set(TARGET_DIR sky9x) set(FIRMWARE_DEPENDENCIES ${FIRMWARE_DEPENDENCIES} 9x_bitmaps) set(PPM_LIMITS_SYMETRICAL YES) set(PXX1 YES) +add_definitions(-DDISABLE_MULTI_UPDATE) if(PCB STREQUAL 9XRPRO) add_definitions(-Dat91sam3s8 -DREVX) diff --git a/radio/src/targets/taranis/CMakeLists.txt b/radio/src/targets/taranis/CMakeLists.txt index 65ba8c975..bbd0b8a64 100644 --- a/radio/src/targets/taranis/CMakeLists.txt +++ b/radio/src/targets/taranis/CMakeLists.txt @@ -1,12 +1,13 @@ option(SHUTDOWN_CONFIRMATION "Shutdown confirmation" OFF) option(LCD_DUAL_BUFFER "Dual LCD Buffer" OFF) -option(INTERNAL_MODULE_PPM "Support for PPM internal module hack" OFF) -option(INTERNAL_MODULE_PXX1 "Support for PXX1 internal module replacement" OFF) option(PXX1 "PXX1 protocol support" ON) option(PXX2 "PXX2 protocol support" OFF) +option(INTERNAL_MODULE_PPM "Support for PPM internal module" OFF) option(AUTOUPDATE "Auto update internal chips from SD" OFF) if(PCB STREQUAL X9E) + option(INTERNAL_MODULE_PXX1 "Support for PXX1 internal module" ON) + option(INTERNAL_MODULE_PXX2 "Support for PXX2 internal module" OFF) set(PWR_BUTTON "PRESS" CACHE STRING "Pwr button type (PRESS/SWITCH)") set(STICKS "STANDARD" CACHE STRING "Sticks type (STANDARD/HORUS)") set(CPU_TYPE STM32F4) @@ -49,6 +50,8 @@ elseif(PCB STREQUAL X9D+) set(PCBREV 2014 CACHE STRING "PCB Revision") add_definitions(-DPCBREV=${PCBREV}) if (${PCBREV} STREQUAL 2019) + option(INTERNAL_MODULE_PXX1 "Support for PXX1 internal module" OFF) + option(INTERNAL_MODULE_PXX2 "Support for PXX2 internal module" ON) set(PWR_BUTTON "PRESS" CACHE STRING "Pwr button type (PRESS/SWITCH)") set(CPU_TYPE STM32F4) set(CPU_TYPE_FULL STM32F407xE) # for size report @@ -64,6 +67,8 @@ elseif(PCB STREQUAL X9D+) set(PXX_FREQUENCY "HIGH") set(FLAVOUR x9d+2019) else() + option(INTERNAL_MODULE_PXX1 "Support for PXX1 internal module" ON) + option(INTERNAL_MODULE_PXX2 "Support for PXX2 internal module" OFF) set(CPU_TYPE STM32F2) set(CPU_TYPE_FULL STM32F205xE) # for size report set(LINKER_SCRIPT targets/taranis/stm32f2_flash.ld) @@ -72,6 +77,8 @@ elseif(PCB STREQUAL X9D+) set(FLAVOUR x9d+) endif() elseif(PCB STREQUAL X9D) + option(INTERNAL_MODULE_PXX1 "Support for PXX1 internal module" ON) + option(INTERNAL_MODULE_PXX2 "Support for PXX2 internal module" OFF) set(CPU_TYPE STM32F2) set(CPU_TYPE_FULL STM32F205xE) # for size report set(LINKER_SCRIPT targets/taranis/stm32f2_flash.ld) @@ -101,6 +108,8 @@ elseif(PCB STREQUAL X7) add_definitions(-DRADIO_T12) add_definitions(-DEEPROM_VARIANT=0x4001) else() + option(INTERNAL_MODULE_PXX1 "Support for PXX1 internal module" ON) + option(INTERNAL_MODULE_PXX2 "Support for PXX2 internal module" OFF) set(LUA_EXPORT lua_export_x7) set(FLAVOUR x7) set(NAVIGATION_TYPE x7) @@ -116,6 +125,8 @@ elseif(PCB STREQUAL X7) set(GVAR_SCREEN model_gvars.cpp) set(STATUS_LEDS YES) elseif(PCB STREQUAL X9LITE) + option(INTERNAL_MODULE_PXX1 "Support for PXX1 internal module" OFF) + option(INTERNAL_MODULE_PXX2 "Support for PXX2 internal module" ON) set(PXX_FREQUENCY "HIGH") set(PWR_BUTTON "PRESS" CACHE STRING "Pwr button type (PRESS/SWITCH)") set(CPU_TYPE STM32F2) @@ -137,6 +148,8 @@ elseif(PCB STREQUAL X9LITE) set(GVAR_SCREEN model_gvars.cpp) set(STATUS_LEDS YES) elseif(PCB STREQUAL X9LITES) + option(INTERNAL_MODULE_PXX1 "Support for PXX1 internal module" OFF) + option(INTERNAL_MODULE_PXX2 "Support for PXX2 internal module" ON) set(PXX_FREQUENCY "HIGH") set(PWR_BUTTON "PRESS" CACHE STRING "Pwr button type (PRESS/SWITCH)") set(CPU_TYPE STM32F2) @@ -158,6 +171,8 @@ elseif(PCB STREQUAL X9LITES) set(GVAR_SCREEN model_gvars.cpp) set(STATUS_LEDS YES) elseif(PCB STREQUAL XLITE) + option(INTERNAL_MODULE_PXX1 "Support for PXX1 internal module" ON) + option(INTERNAL_MODULE_PXX2 "Support for PXX2 internal module" OFF) set(PXX_FREQUENCY "HIGH" CACHE STRING "PXX frequency (LOW / HIGH)") # always use HIGH except on some prototype boards set(PWR_BUTTON "PRESS" CACHE STRING "Pwr button type (PRESS/SWITCH)") set(CPU_TYPE STM32F2) @@ -178,6 +193,8 @@ elseif(PCB STREQUAL XLITE) set(GVAR_SCREEN model_gvars.cpp) set(STATUS_LEDS YES) elseif(PCB STREQUAL XLITES) + option(INTERNAL_MODULE_PXX1 "Support for PXX1 internal module" OFF) + option(INTERNAL_MODULE_PXX2 "Support for PXX2 internal module" ON) set(PXX_FREQUENCY "HIGH") set(PWR_BUTTON "PRESS" CACHE STRING "Pwr button type (PRESS/SWITCH)") set(CPU_TYPE STM32F2) @@ -266,6 +283,7 @@ add_definitions(-DAUDIO -DVOICE -DRTCLOCK) set(SRC ${SRC} io/frsky_firmware_update.cpp + io/multi_firmware_update.cpp ) set(GUI_SRC @@ -322,12 +340,20 @@ if(LCD_DUAL_BUFFER) add_definitions(-DLCD_DUAL_BUFFER) endif() -if(INTERNAL_MODULE_PPM) - add_definitions(-DINTERNAL_MODULE_PPM) -endif() - if(INTERNAL_MODULE_PXX1) + add_definitions(-DHARDWARE_INTERNAL_MODULE) add_definitions(-DINTERNAL_MODULE_PXX1) endif() +if(INTERNAL_MODULE_PXX2) + set(PXX2 ON) + add_definitions(-DHARDWARE_INTERNAL_MODULE) + add_definitions(-DINTERNAL_MODULE_PXX2) +endif() + +if(INTERNAL_MODULE_PPM) + add_definitions(-DHARDWARE_INTERNAL_MODULE) + add_definitions(-DINTERNAL_MODULE_PPM) +endif() + set(FIRMWARE_DEPENDENCIES ${FIRMWARE_DEPENDENCIES} ${BITMAPS_TARGET}) diff --git a/radio/src/targets/taranis/board.h b/radio/src/targets/taranis/board.h index dae1b0f0f..b5c242b00 100644 --- a/radio/src/targets/taranis/board.h +++ b/radio/src/targets/taranis/board.h @@ -121,7 +121,7 @@ uint32_t isBootloaderStart(const uint8_t * buffer); #define IS_INTERNAL_MODULE_ON() (GPIO_ReadInputDataBit(INTMODULE_PWR_GPIO, INTMODULE_PWR_GPIO_PIN) == Bit_SET) #endif -void intmoduleSerialStart(uint32_t baudrate, uint8_t rxEnable); +void intmoduleSerialStart(uint32_t baudrate, uint8_t rxEnable, uint16_t parity, uint16_t stopBits, uint16_t wordLength); void intmoduleSendByte(uint8_t byte); void intmoduleSendBuffer(const uint8_t * data, uint8_t size); void intmoduleSendNextFrame(); @@ -130,6 +130,7 @@ void extmoduleSerialStart(uint32_t baudrate, uint32_t period_half_us, bool inver void extmoduleInvertedSerialStart(uint32_t baudrate); void extmoduleSendBuffer(const uint8_t * data, uint8_t size); void extmoduleSendNextFrame(); +void extmoduleSendInvertedByte(uint8_t byte); // Trainer driver #define SLAVE_MODE() (g_model.trainerData.mode == TRAINER_MODE_SLAVE) @@ -670,7 +671,7 @@ void sportSendByte(uint8_t byte); void sportSendByteLoop(uint8_t byte); void sportStopSendByteLoop(); void sportSendBuffer(const uint8_t * buffer, uint32_t count); -uint8_t telemetryGetByte(uint8_t * byte); +bool telemetryGetByte(uint8_t * byte); void telemetryClearFifo(); extern uint32_t telemetryErrors; diff --git a/radio/src/targets/taranis/extmodule_driver.cpp b/radio/src/targets/taranis/extmodule_driver.cpp index 3ab23f3e9..19bd04525 100644 --- a/radio/src/targets/taranis/extmodule_driver.cpp +++ b/radio/src/targets/taranis/extmodule_driver.cpp @@ -309,6 +309,38 @@ void extmoduleSendNextFrame() } } +void extmoduleSendInvertedByte(uint8_t byte) +{ + uint16_t time; + uint32_t i; + + __disable_irq(); + time = getTmr2MHz(); + GPIO_SetBits(EXTMODULE_TX_GPIO, EXTMODULE_TX_GPIO_PIN); + while ((uint16_t) (getTmr2MHz() - time) < 34) { + // wait + } + time += 34; + for (i = 0 ; i < 8 ; i += 1) { + if (byte & 1) { + GPIO_ResetBits(EXTMODULE_TX_GPIO, EXTMODULE_TX_GPIO_PIN); + } + else { + GPIO_SetBits(EXTMODULE_TX_GPIO, EXTMODULE_TX_GPIO_PIN); + } + byte >>= 1 ; + while ((uint16_t) (getTmr2MHz() - time) < 35) { + // wait + } + time += 35 ; + } + GPIO_ResetBits(EXTMODULE_TX_GPIO, EXTMODULE_TX_GPIO_PIN); + __enable_irq() ; // No need to wait for the stop bit to complete + while ((uint16_t) (getTmr2MHz() - time) < 34) { + // wait + } +} + extern "C" void EXTMODULE_TIMER_DMA_STREAM_IRQHandler() { if (!DMA_GetITStatus(EXTMODULE_TIMER_DMA_STREAM, EXTMODULE_TIMER_DMA_FLAG_TC)) diff --git a/radio/src/targets/taranis/hal.h b/radio/src/targets/taranis/hal.h index 5b58b1267..89fee14d2 100644 --- a/radio/src/targets/taranis/hal.h +++ b/radio/src/targets/taranis/hal.h @@ -929,17 +929,9 @@ #endif // Internal Module -#if !defined(RADIO_T12) - #define HARDWARE_INTERNAL_MODULE -#endif #if defined(PCBXLITE) #define EXTERNAL_ANTENNA #endif -#if defined(PCBXLITES) || defined(PCBX9LITE) || (defined(PCBX9DP) && PCBREV >= 2019) - #define INTERNAL_MODULE_PXX2 -#else - #define INTERNAL_MODULE_PXX1 -#endif #if defined(PCBXLITE) || defined(PCBX9LITE) #define INTMODULE_RCC_APB1Periph 0 #define INTMODULE_RCC_APB2Periph RCC_APB2Periph_USART1 diff --git a/radio/src/targets/taranis/telemetry_driver.cpp b/radio/src/targets/taranis/telemetry_driver.cpp index ec6da0c86..b439dc906 100644 --- a/radio/src/targets/taranis/telemetry_driver.cpp +++ b/radio/src/targets/taranis/telemetry_driver.cpp @@ -218,7 +218,7 @@ extern "C" void TELEMETRY_USART_IRQHandler(void) } // TODO we should have telemetry in an higher layer, functions above should move to a sport_driver.cpp -uint8_t telemetryGetByte(uint8_t * byte) +bool telemetryGetByte(uint8_t * byte) { #if defined(AUX_SERIAL) if (telemetryProtocol == PROTOCOL_TELEMETRY_FRSKY_D_SECONDARY) { diff --git a/radio/src/telemetry/flysky_ibus.cpp b/radio/src/telemetry/flysky_ibus.cpp index cebb60e78..208df3cac 100644 --- a/radio/src/telemetry/flysky_ibus.cpp +++ b/radio/src/telemetry/flysky_ibus.cpp @@ -133,35 +133,35 @@ void processFlySkyPacket(const uint8_t *packet) } } -void processFlySkyTelemetryData(uint8_t data) +void processFlySkyTelemetryData(uint8_t data, uint8_t* rxBuffer, uint8_t& rxBufferCount) { - if (telemetryRxBufferCount == 0 && data != 0xAA) { + if (rxBufferCount == 0 && data != 0xAA) { TRACE("[IBUS] invalid start byte 0x%02X", data); return; } - if (telemetryRxBufferCount < TELEMETRY_RX_PACKET_SIZE) { - telemetryRxBuffer[telemetryRxBufferCount++] = data; + if (rxBufferCount < TELEMETRY_RX_PACKET_SIZE) { + rxBuffer[rxBufferCount++] = data; } else { - TRACE("[IBUS] array size %d error", telemetryRxBufferCount); - telemetryRxBufferCount = 0; + TRACE("[IBUS] array size %d error", rxBufferCount); + rxBufferCount = 0; } - if (telemetryRxBufferCount >= FLYSKY_TELEMETRY_LENGTH) { + if (rxBufferCount >= FLYSKY_TELEMETRY_LENGTH) { // debug print the content of the packets #if 0 debugPrintf("[IBUS] Packet 0x%02X rssi 0x%02X: ", - telemetryRxBuffer[0], telemetryRxBuffer[1]); + rxBuffer[0], rxBuffer[1]); for (int i=0; i<7; i++) { - debugPrintf("[%02X %02X %02X%02X] ", telemetryRxBuffer[i*4+2], telemetryRxBuffer[i*4 + 3], - telemetryRxBuffer[i*4 + 4], telemetryRxBuffer[i*4 + 5]); + debugPrintf("[%02X %02X %02X%02X] ", rxBuffer[i*4+2], rxBuffer[i*4 + 3], + rxBuffer[i*4 + 4], rxBuffer[i*4 + 5]); } debugPrintf("\r\n"); #endif - processFlySkyPacket(telemetryRxBuffer+1); - telemetryRxBufferCount = 0; + processFlySkyPacket(rxBuffer+1); + rxBufferCount = 0; } } diff --git a/radio/src/telemetry/flysky_ibus.h b/radio/src/telemetry/flysky_ibus.h index 71726d64c..f952f7968 100644 --- a/radio/src/telemetry/flysky_ibus.h +++ b/radio/src/telemetry/flysky_ibus.h @@ -21,7 +21,7 @@ #ifndef _FLYSKY_IBUS_H #define _FLYSKY_IBUS_H -void processFlySkyTelemetryData(uint8_t data); +void processFlySkyTelemetryData(uint8_t data, uint8_t* rxBuffer, uint8_t& rxBufferCount); void flySkySetDefault(int index, uint16_t id, uint8_t subId, uint8_t instance); // Used by multi protocol diff --git a/radio/src/telemetry/multi.cpp b/radio/src/telemetry/multi.cpp index 87944a862..c8e4c7867 100644 --- a/radio/src/telemetry/multi.cpp +++ b/radio/src/telemetry/multi.cpp @@ -21,11 +21,6 @@ #include "telemetry.h" #include "multi.h" -MultiModuleStatus multiModuleStatus; -MultiModuleSyncStatus multiSyncStatus; -uint8_t multiBindStatus = MULTI_NORMAL_OPERATION; - - enum MultiPacketTypes : uint8_t { MultiStatus = 1, FrSkySportTelemtry, @@ -51,53 +46,142 @@ enum MultiBufferState : uint8_t { MultiStatusOrFrskyData }; -MultiBufferState guessProtocol() + +#if defined(INTERNAL_MODULE_MULTI) + +static MultiModuleStatus multiModuleStatus[NUM_MODULES] = { MultiModuleStatus(), MultiModuleStatus() }; +static MultiModuleSyncStatus multiSyncStatus[NUM_MODULES] = { MultiModuleSyncStatus(), MultiModuleSyncStatus() }; +static uint8_t multiBindStatus[NUM_MODULES] = { MULTI_NORMAL_OPERATION, MULTI_NORMAL_OPERATION }; + +static MultiBufferState multiTelemetryBufferState[NUM_MODULES]; + +MultiModuleStatus& getMultiModuleStatus(uint8_t module) { - if (g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(false) == MODULE_SUBTYPE_MULTI_DSM2) + return multiModuleStatus[module]; +} + +MultiModuleSyncStatus& getMultiSyncStatus(uint8_t module) +{ + return multiSyncStatus[module]; +} + +uint8_t getMultiBindStatus(uint8_t module) +{ + return multiBindStatus[module]; +} + +void setMultiBindStatus(uint8_t module, uint8_t bindStatus) +{ + multiBindStatus[module] = bindStatus; +} + +MultiBufferState getMultiTelemetryBufferState(uint8_t module) +{ + return multiTelemetryBufferState[module]; +} + +void setMultiTelemetryBufferState(uint8_t module, MultiBufferState state) +{ + multiTelemetryBufferState[module] = state; +} + +// Use additional telemetry buffer +uint8_t intTelemetryRxBuffer[TELEMETRY_RX_PACKET_SIZE]; +uint8_t intTelemetryRxBufferCount; + +#else // !INTERNAL_MODULE_MULTI + +static MultiModuleStatus multiModuleStatus; +static MultiModuleSyncStatus multiSyncStatus; +static uint8_t multiBindStatus = MULTI_NORMAL_OPERATION; + +static MultiBufferState multiTelemetryBufferState; + +MultiModuleStatus& getMultiModuleStatus(uint8_t) +{ + return multiModuleStatus; +} + +MultiModuleSyncStatus& getMultiSyncStatus(uint8_t) +{ + return multiSyncStatus; +} + +uint8_t getMultiBindStatus(uint8_t) +{ + return multiBindStatus; +} + +void setMultiBindStatus(uint8_t, uint8_t bindStatus) +{ + multiBindStatus = bindStatus; +} + +MultiBufferState getMultiTelemetryBufferState(uint8_t) +{ + return multiTelemetryBufferState; +} + +void setMultiTelemetryBufferState(uint8_t, MultiBufferState state) +{ + multiTelemetryBufferState = state; +} + +#endif // INTERNAL_MODULE_MULTI + + +static MultiBufferState guessProtocol(uint8_t module) +{ + if (g_model.moduleData[module].getMultiProtocol(false) == MODULE_SUBTYPE_MULTI_DSM2) return SpektrumTelemetryFallback; - else if (g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(false) == MODULE_SUBTYPE_MULTI_FS_AFHDS2A) + else if (g_model.moduleData[module].getMultiProtocol(false) == MODULE_SUBTYPE_MULTI_FS_AFHDS2A) return FlyskyTelemetryFallback; else return FrskyTelemetryFallback; } -static void processMultiStatusPacket(const uint8_t *data) +static void processMultiStatusPacket(const uint8_t *data, uint8_t module) { + MultiModuleStatus& status = getMultiModuleStatus(module); + // At least two status packets without bind flag - bool wasBinding = (multiModuleStatus.isBinding()); + bool wasBinding = status.isBinding(); - multiModuleStatus.flags = data[0]; - multiModuleStatus.major = data[1]; - multiModuleStatus.minor = data[2]; - multiModuleStatus.revision = data[3]; - multiModuleStatus.patch = data[4]; - multiModuleStatus.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 (wasBinding && !multiModuleStatus.isBinding() && multiBindStatus == MULTI_BIND_INITIATED) - multiBindStatus = MULTI_BIND_FINISHED; + if (wasBinding && !status.isBinding() && getMultiBindStatus(module) == MULTI_BIND_INITIATED) + setMultiBindStatus(module, MULTI_BIND_FINISHED); } -static void processMultiSyncPacket(const uint8_t *data) +static void processMultiSyncPacket(const uint8_t *data, uint8_t module) { - multiSyncStatus.lastUpdate = get_tmr10ms(); - multiSyncStatus.interval = data[4]; - multiSyncStatus.target = data[5]; + MultiModuleSyncStatus& status = getMultiSyncStatus(module); + + status.lastUpdate = get_tmr10ms(); + status.interval = data[4]; + status.target = data[5]; #if !defined(PPM_PIN_SERIAL) - auto oldlag = multiSyncStatus.inputLag; + auto oldlag = status.inputLag; (void) oldlag; #endif - multiSyncStatus.calcAdjustedRefreshRate(data[0] << 8 | data[1], data[2] << 8 | data[3]); + status.calcAdjustedRefreshRate(data[0] << 8 | data[1], data[2] << 8 | data[3]); #if !defined(PPM_PIN_SERIAL) - TRACE("MP ADJ: rest: %d, lag %04d, diff: %04d target: %d, interval: %d, Refresh: %d, intAdjRefresh: %d, adjRefresh %d\r\n", extmodulePulsesData.dsm2.rest, - multiSyncStatus.inputLag, oldlag-multiSyncStatus.inputLag, multiSyncStatus.target, multiSyncStatus.interval, multiSyncStatus.refreshRate, multiSyncStatus.adjustedRefreshRate/50, - multiSyncStatus.getAdjustedRefreshRate()); + TRACE("MP ADJ: rest: %d, lag %04d, diff: %04d target: %d, interval: %d, Refresh: %d, intAdjRefresh: %d, adjRefresh %d\r\n", + module == EXTERNAL_MODULE ? extmodulePulsesData.dsm2.rest : 0, + status.inputLag, oldlag-status.inputLag, status.target, status.interval, status.refreshRate, status.adjustedRefreshRate/50, + status.getAdjustedRefreshRate()); #endif } -static void processMultiTelemetryPaket(const uint8_t *packet) +static void processMultiTelemetryPaket(const uint8_t *packet, uint8_t module) { uint8_t type = packet[0]; uint8_t len = packet[1]; @@ -107,12 +191,12 @@ static void processMultiTelemetryPaket(const uint8_t *packet) switch (type) { case MultiStatus: if (len >= 5) - processMultiStatusPacket(data); + processMultiStatusPacket(data, module); break; case DSMBindPacket: if (len >= 10) - processDSMBindPacket(data); + processDSMBindPacket(module, data); break; case SpektrumTelemetry: @@ -147,7 +231,7 @@ static void processMultiTelemetryPaket(const uint8_t *packet) case InputSync: if (len >= 6) - processMultiSyncPacket(data); + processMultiSyncPacket(data, module); else TRACE("[MP] Received input sync len %d < 6", len); break; @@ -294,9 +378,11 @@ void MultiModuleStatus::getStatusString(char *statusText) { if (!isValid()) { #if defined(PCBTARANIS) || defined(PCBHORUS) +#if !defined(INTERNAL_MODULE_MULTI) if (IS_INTERNAL_MODULE_ENABLED()) strcpy(statusText, STR_DISABLE_INTERNAL); else +#endif #endif strcpy(statusText, STR_MODULE_NO_TELEMETRY); return; @@ -333,50 +419,71 @@ void MultiModuleStatus::getStatusString(char *statusText) strcat(statusText, STR_MODULE_BINDING); } - -static MultiBufferState multiTelemetryBufferState; - -static void processMultiTelemetryByte(const uint8_t data) +static uint8_t* getRxBuffer(uint8_t moduleIdx) { - if (telemetryRxBufferCount < TELEMETRY_RX_PACKET_SIZE) { - telemetryRxBuffer[telemetryRxBufferCount++] = data; +#if defined(INTERNAL_MODULE_MULTI) + if (moduleIdx == INTERNAL_MODULE) + return intTelemetryRxBuffer; +#endif + return telemetryRxBuffer; +} + +static uint8_t& getRxBufferCount(uint8_t moduleIdx) +{ +#if defined(INTERNAL_MODULE_MULTI) + if (moduleIdx == INTERNAL_MODULE) + return intTelemetryRxBufferCount; +#endif + return telemetryRxBufferCount; +} + +static void processMultiTelemetryByte(const uint8_t data, uint8_t module) +{ + uint8_t* rxBuffer = getRxBuffer(module); + uint8_t& rxBufferCount = getRxBufferCount(module); + + if (rxBufferCount < TELEMETRY_RX_PACKET_SIZE) { + rxBuffer[rxBufferCount++] = data; } else { - TRACE("[MP] array size %d error", telemetryRxBufferCount); - multiTelemetryBufferState = NoProtocolDetected; + TRACE("[MP] array size %d error", rxBufferCount); + setMultiTelemetryBufferState(module, NoProtocolDetected); } // Length field does not count the header - if (telemetryRxBufferCount >= 2 && telemetryRxBuffer[1] == telemetryRxBufferCount - 2) { + if (rxBufferCount >= 2 && rxBuffer[1] == rxBufferCount - 2) { // debug print the content of the packet #if 0 debugPrintf("[MP] Packet type %02X len 0x%02X: ", - telemetryRxBuffer[0], telemetryRxBuffer[1]); - for (int i=0; i<(telemetryRxBufferCount+3)/4; i++) { - debugPrintf("[%02X%02X %02X%02X] ", telemetryRxBuffer[i*4+2], telemetryRxBuffer[i*4 + 3], - telemetryRxBuffer[i*4 + 4], telemetryRxBuffer[i*4 + 5]); + rxBuffer[0], rxBuffer[1]); + for (int i=0; i<(rxBufferCount+3)/4; i++) { + debugPrintf("[%02X%02X %02X%02X] ", rxBuffer[i*4+2], rxBuffer[i*4 + 3], + rxBuffer[i*4 + 4], rxBuffer[i*4 + 5]); } debugPrintf("\r\n"); #endif // Packet is complete, process it - processMultiTelemetryPaket(telemetryRxBuffer); - multiTelemetryBufferState = NoProtocolDetected; + processMultiTelemetryPaket(rxBuffer, module); + setMultiTelemetryBufferState(module, NoProtocolDetected); } } -void processMultiTelemetryData(const uint8_t data) +void processMultiTelemetryData(uint8_t data, uint8_t module) { - // debugPrintf("State: %d, byte received %02X, buflen: %d\r\n", multiTelemetryBufferState, data, telemetryRxBufferCount); - switch (multiTelemetryBufferState) { + uint8_t* rxBuffer = getRxBuffer(module); + uint8_t& rxBufferCount = getRxBufferCount(module); + + debugPrintf("State: %d, byte received %02X, buflen: %d\r\n", multiTelemetryBufferState, data, rxBufferCount); + switch (getMultiTelemetryBufferState(module)) { case NoProtocolDetected: if (data == 'M') { - multiTelemetryBufferState = MultiFirstByteReceived; + setMultiTelemetryBufferState(module, MultiFirstByteReceived); } else if (data == 0xAA || data == 0x7e) { - multiTelemetryBufferState = guessProtocol(); + setMultiTelemetryBufferState(module, guessProtocol(module)); // Process the first byte by the protocol - processMultiTelemetryData(data); + processMultiTelemetryData(data, module); } else { TRACE("[MP] invalid start byte 0x%02X", data); @@ -384,91 +491,92 @@ void processMultiTelemetryData(const uint8_t data) break; case FrskyTelemetryFallback: - multiTelemetryBufferState = FrskyTelemetryFallbackFirstByte; + setMultiTelemetryBufferState(module, FrskyTelemetryFallbackFirstByte); processFrskyTelemetryData(data); break; case FrskyTelemetryFallbackFirstByte: if (data == 'M') { - multiTelemetryBufferState = MultiStatusOrFrskyData; + setMultiTelemetryBufferState(module, MultiStatusOrFrskyData); } else { processFrskyTelemetryData(data); if (data != 0x7e) - multiTelemetryBufferState = FrskyTelemetryFallbackNextBytes; + setMultiTelemetryBufferState(module, FrskyTelemetryFallbackNextBytes); } break; case FrskyTelemetryFallbackNextBytes: processFrskyTelemetryData(data); - if (data == 0x7e) + if (data == 0x7e) { // end of packet or start of new packet - multiTelemetryBufferState = FrskyTelemetryFallbackFirstByte; + setMultiTelemetryBufferState(module, FrskyTelemetryFallbackFirstByte); + } break; case FlyskyTelemetryFallback: - processFlySkyTelemetryData(data); - if (telemetryRxBufferCount == 0) - multiTelemetryBufferState = NoProtocolDetected; + processFlySkyTelemetryData(data, rxBuffer, rxBufferCount); + if (rxBufferCount == 0) { + setMultiTelemetryBufferState(module, NoProtocolDetected); + } break; case SpektrumTelemetryFallback: - processSpektrumTelemetryData(data); - if (telemetryRxBufferCount == 0) - multiTelemetryBufferState = NoProtocolDetected; + processSpektrumTelemetryData(module, data,rxBuffer, rxBufferCount); + if (rxBufferCount == 0) { + setMultiTelemetryBufferState(module, NoProtocolDetected); + } break; case MultiFirstByteReceived: - telemetryRxBufferCount = 0; + rxBufferCount = 0; if (data == 'P') { - multiTelemetryBufferState = ReceivingMultiProtocol; + setMultiTelemetryBufferState(module, ReceivingMultiProtocol); } else if (data >= 5 && data <= 10) { // Protocol indented for er9x/ersky9, accept only 5-10 as packet length to have // a bit of validation - multiTelemetryBufferState = ReceivingMultiStatus; - processMultiTelemetryData(data); + setMultiTelemetryBufferState(module, ReceivingMultiStatus); + processMultiTelemetryData(data, module); } else { TRACE("[MP] invalid second byte 0x%02X", data); - multiTelemetryBufferState = NoProtocolDetected; + setMultiTelemetryBufferState(module, NoProtocolDetected); } break; case ReceivingMultiProtocol: - processMultiTelemetryByte(data); + processMultiTelemetryByte(data, module); break; case MultiStatusOrFrskyData: // Check len byte if it makes sense for multi if (data >= 5 && data <= 10) { - multiTelemetryBufferState = ReceivingMultiStatus; - telemetryRxBufferCount = 0; + setMultiTelemetryBufferState(module, ReceivingMultiStatus); + rxBufferCount = 0; } else { - multiTelemetryBufferState = FrskyTelemetryFallbackNextBytes; - processMultiTelemetryData('M'); + setMultiTelemetryBufferState(module, FrskyTelemetryFallbackNextBytes); + processMultiTelemetryData('M', module); } - processMultiTelemetryData(data); + processMultiTelemetryData(data, module); break; case ReceivingMultiStatus: - telemetryRxBuffer[telemetryRxBufferCount++] = data; - if (telemetryRxBufferCount > 5 && telemetryRxBuffer[0] == telemetryRxBufferCount-1) { - processMultiStatusPacket(telemetryRxBuffer+1); - telemetryRxBufferCount = 0; - multiTelemetryBufferState = NoProtocolDetected; + rxBuffer[rxBufferCount++] = data; + if (rxBufferCount > 5 && rxBuffer[0] == rxBufferCount-1) { + processMultiStatusPacket(rxBuffer+1, module); + rxBufferCount = 0; + setMultiTelemetryBufferState(module, NoProtocolDetected); } - if (telemetryRxBufferCount > 10) { + if (rxBufferCount > 10) { // too long ignore - TRACE("Overlong multi status packet detected ignoring, wanted %d", telemetryRxBuffer[0]); - telemetryRxBufferCount =0; - multiTelemetryBufferState = NoProtocolDetected; + TRACE("Overlong multi status packet detected ignoring, wanted %d", rxBuffer[0]); + rxBufferCount =0; + setMultiTelemetryBufferState(module, NoProtocolDetected); } - - + break; } - } diff --git a/radio/src/telemetry/multi.h b/radio/src/telemetry/multi.h index 1b439ea24..a538df303 100644 --- a/radio/src/telemetry/multi.h +++ b/radio/src/telemetry/multi.h @@ -82,9 +82,7 @@ Type 0x06 Flysky AFHDS2 telemetry data */ - - -void processMultiTelemetryData(uint8_t data); +void processMultiTelemetryData(uint8_t data, uint8_t module); // This should be put into the Module definition if other modules gain this functionality struct MultiModuleSyncStatus { @@ -107,7 +105,7 @@ struct MultiModuleSyncStatus { }; -extern MultiModuleSyncStatus multiSyncStatus; +MultiModuleSyncStatus& getMultiSyncStatus(uint8_t module); struct MultiModuleStatus { @@ -131,13 +129,15 @@ struct MultiModuleStatus { inline bool inputDetected() { return (bool) (flags & 0x01); } }; -extern MultiModuleStatus multiModuleStatus; +MultiModuleStatus& getMultiModuleStatus(uint8_t module); + enum MultiBindStatus : uint8_t { MULTI_NORMAL_OPERATION, MULTI_BIND_INITIATED, MULTI_BIND_FINISHED, }; -extern uint8_t multiBindStatus; +uint8_t getMultiBindStatus(uint8_t module); +void setMultiBindStatus(uint8_t module, uint8_t bindStatus); #endif //OPENTX_MULTI_H diff --git a/radio/src/telemetry/spektrum.cpp b/radio/src/telemetry/spektrum.cpp index 41b27b88c..ae5435845 100644 --- a/radio/src/telemetry/spektrum.cpp +++ b/radio/src/telemetry/spektrum.cpp @@ -370,28 +370,27 @@ void processSpektrumPacket(const uint8_t *packet) LemonRX+Sat+tele 0xb2 07 1 */ -void processDSMBindPacket(const uint8_t *packet) +void processDSMBindPacket(uint8_t module, const uint8_t *packet) { uint32_t debugval; - if (g_model.moduleData[EXTERNAL_MODULE].type == MODULE_TYPE_MULTIMODULE && g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(true) == MODULE_SUBTYPE_MULTI_DSM2 - && g_model.moduleData[EXTERNAL_MODULE].multi.autoBindMode) { + if (g_model.moduleData[module].type == MODULE_TYPE_MULTIMODULE && g_model.moduleData[module].getMultiProtocol(true) == MODULE_SUBTYPE_MULTI_DSM2 + && g_model.moduleData[module].multi.autoBindMode) { int channels = packet[5]; // Only sets channel etc when in DSM multi mode - g_model.moduleData[EXTERNAL_MODULE].channelsCount = channels - 8; + g_model.moduleData[module].channelsCount = channels - 8; // bool use11ms = (packet[8] & 0x10) ; if (packet[6] >= 0xb2) - g_model.moduleData[EXTERNAL_MODULE].subType = MM_RF_DSM2_SUBTYPE_DSMX_11; + g_model.moduleData[module].subType = MM_RF_DSM2_SUBTYPE_DSMX_11; else if (packet[6] >= 0xa2) - g_model.moduleData[EXTERNAL_MODULE].subType = MM_RF_DSM2_SUBTYPE_DSMX_22; + g_model.moduleData[module].subType = MM_RF_DSM2_SUBTYPE_DSMX_22; else if (packet[6] >= 0x12) - g_model.moduleData[EXTERNAL_MODULE].subType = MM_RF_DSM2_SUBTYPE_DSM2_11; + g_model.moduleData[module].subType = MM_RF_DSM2_SUBTYPE_DSM2_11; else - g_model.moduleData[EXTERNAL_MODULE].subType = MM_RF_DSM2_SUBTYPE_DSM2_22; + g_model.moduleData[module].subType = MM_RF_DSM2_SUBTYPE_DSM2_22; storageDirty(EE_MODEL); - } debugval = packet[7] << 24 | packet[6] << 16 | packet[5] << 8 | packet[4]; @@ -400,45 +399,45 @@ void processDSMBindPacket(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[EXTERNAL_MODULE].type == MODULE_TYPE_MULTIMODULE && g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(true) == MODULE_SUBTYPE_MULTI_DSM2 && moduleState[EXTERNAL_MODULE].mode == MODULE_MODE_BIND) { - multiBindStatus=MULTI_BIND_FINISHED; + 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) { + setMultiBindStatus(module, MULTI_BIND_FINISHED); } } -void processSpektrumTelemetryData(uint8_t data) +void processSpektrumTelemetryData(uint8_t module, uint8_t data, uint8_t* rxBuffer, uint8_t& rxBufferCount) { - if (telemetryRxBufferCount == 0 && data != 0xAA) { + if (rxBufferCount == 0 && data != 0xAA) { TRACE("[SPK] invalid start byte 0x%02X", data); return; } - if (telemetryRxBufferCount < TELEMETRY_RX_PACKET_SIZE) { - telemetryRxBuffer[telemetryRxBufferCount++] = data; + if (rxBufferCount < TELEMETRY_RX_PACKET_SIZE) { + rxBuffer[rxBufferCount++] = data; } else { - TRACE("[SPK] array size %d error", telemetryRxBufferCount); - telemetryRxBufferCount = 0; + TRACE("[SPK] array size %d error", rxBufferCount); + rxBufferCount = 0; } - if (telemetryRxBuffer[1] == 0x80 && telemetryRxBufferCount >= DSM_BIND_PACKET_LENGTH) { - processDSMBindPacket(telemetryRxBuffer+2); - telemetryRxBufferCount = 0; + if (rxBuffer[1] == 0x80 && rxBufferCount >= DSM_BIND_PACKET_LENGTH) { + processDSMBindPacket(module, rxBuffer+2); + rxBufferCount = 0; return; } - if (telemetryRxBufferCount >= SPEKTRUM_TELEMETRY_LENGTH) { + if (rxBufferCount >= SPEKTRUM_TELEMETRY_LENGTH) { // Debug print content of Telemetry to console #if 0 debugPrintf("[SPK] Packet 0x%02X rssi 0x%02X: ic2 0x%02x, %02x: ", - telemetryRxBuffer[0], telemetryRxBuffer[1], telemetryRxBuffer[2], telemetryRxBuffer[3]); + rxBuffer[0], rxBuffer[1], rxBuffer[2], rxBuffer[3]); for (int i=4; i