diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index 777209761..efad3ce27 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -7,6 +7,7 @@
+
diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
index 6e6eec114..79ee123c2 100644
--- a/.idea/codeStyles/codeStyleConfig.xml
+++ b/.idea/codeStyles/codeStyleConfig.xml
@@ -1,6 +1,5 @@
-
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
index 6a8432377..909cf534d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -16,6 +16,8 @@ addons:
- libmpc3
- libfox-1.6-dev
- libgtest-dev
+ - lib32stdc++6
+ - libclang-common-6.0-dev
- clang-6.0
- python3-pip
@@ -44,6 +46,8 @@ before_install:
- sudo ln -s /opt/gcc-arm-none-eabi/bin/arm-none-eabi-size /usr/bin/arm-none-eabi-size
- sudo apt-get install --yes --force-yes -qq qt${QT_BASE}base qt${QT_BASE}multimedia qt${QT_BASE}svg qt${QT_BASE}tools; source /opt/qt${QT_BASE}/bin/qt${QT_BASE}-env.sh
- sudo ln -sf /usr/bin/python3 /usr/bin/python
+ - python3 -m pip install pip==20.3.3
+ - sudo apt-get install python3-setuptools
- python3 -m pip install pillow clang
script:
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 18d2bc919..8d23900bc 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2,11 +2,11 @@ project(OpenTX)
set(VERSION_MAJOR "2")
set(VERSION_MINOR "3")
-set(VERSION_REVISION "10")
+set(VERSION_REVISION "12")
set(VERSION_SUFFIX $ENV{OPENTX_VERSION_SUFFIX})
set(VERSION_FAMILY ${VERSION_MAJOR}.${VERSION_MINOR})
set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_REVISION}${VERSION_SUFFIX})
-set(SDCARD_REVISION "0029")
+set(SDCARD_REVISION "0036")
set(SDCARD_VERSION ${VERSION_MAJOR}.${VERSION_MINOR}V${SDCARD_REVISION})
cmake_minimum_required(VERSION 2.8)
diff --git a/CREDITS.txt b/CREDITS.txt
index 9a6bc797e..f4f2c3cb9 100644
--- a/CREDITS.txt
+++ b/CREDITS.txt
@@ -1,6 +1,7 @@
[Main developers]
Bertrand Songis (bsongis)
André Bernet (kilrah)
+JC D. (3djc)
Michael Blandford
Damjan Adamic (projectkk2glider)
Franck Aguerre (jivarofad)
@@ -9,6 +10,7 @@ Martin Hotař (mhotar)
Maxim (Max) Paperno (mpaperno)
Arne Schwabe (schwabe)
Daniel Gorbea (dgatf)
+Neil Horne (elecpower)
[Translators]
[fr] Sebastien Charpentier (LapinFou)
@@ -32,6 +34,7 @@ Michael Byrne
FlySky (monthly)
JumperRC (monthly)
RadioMaster (monthly)
+HappyModel (monthly)
Aloft Hobbies
Jonathan Modellismo
WsTech
@@ -1838,3 +1841,400 @@ Laurence Gerrard
Nico Wagner
Christoph Rössner
Ruben Flores
+Jim Cukla
+Lee Taylor
+Stefan Kuster
+Barry Wright
+Steven Gilley
+Lloyd Evans
+Nolan O'Hearne
+Jeffrey James N Buffie
+James Houck
+Andreas Arlt
+William Walker
+Salvador Munoz Vinas
+Chris Geiger Photography
+John F Smith
+Robert Zecha
+Fernando Martins
+Martin Brungard
+Paul Witko
+Michael Campbell
+Stuart Posnett
+PK Doddema
+Leonard MacKey
+Andrew Peterson
+Dominik Sedlacek
+Ronald Hellstern
+Vicente Suarez
+Patrick Geerts
+Rossi Giampaolo
+Jose Luis Franco Torres
+Bart Sillen
+Antonio Moreno
+Carolina Carcione
+Lonnie Misner
+John Eppling
+Phillip Elliott
+Robin Bayer
+Jurij Peternel
+George Aandahl
+Guy Dangerfield
+Thomas Limpert
+Ismael G Zapater
+Alan Hall
+Bradley Goodwin
+Paul Dittman
+John Johnson
+Liam Mahoney
+Joseph Carr
+Fiorenzo Agnelli
+Brian Ramsey
+Angelo Movio
+Weldon Parks
+Simon Brink
+Weldon Parks
+Ralf Herzenbruch
+Ashley Pearce
+SneakIT
+Soaring Stuff
+Jörg Lemnitz
+Johann Gross
+Mark Gibson
+Rendall Assoc
+Cozyn Holdings Pty Ltd
+Tim Karsten
+Nick Hesson
+Laurent Lapassade
+Peter Deacon
+Gilles Dando
+Philippe Desrichard
+Jón Haase
+Michael Hansen
+Sylvain Vanston
+Helmut Nemecek
+Alexander Mathis
+Jay Watkins
+Patrice Oudjaoudi
+Didier Hochedez
+Robert Hunter
+Christophe Gilsoul
+Lincoln Roberts
+Johan Jurriens
+Michael Ledward
+Dave Waldesbuehl
+Dale Rhoads
+Denis Kelly
+SBEurope LTD
+Jean-Louis Mouche
+Grant Mills
+Fernando Rimoldi
+Jim Cukla
+Tomas Kirnak
+Raymond Henderson
+James Jewitt
+Martin Sauter
+Philip Hawkey
+Lonnie Misner
+Michael Hirschauer
+Brian Bracken
+Stuart Olson
+Terry McKinley
+Miklos Turcsin
+Edward Skerness
+Stefano Perinetti
+Toni Marchante
+Stuart Olson
+Peter Campbell
+Keith Wood
+Leo Duflou
+Michael Florey
+Gerhard Weixelbaumer
+Peter K Lehotsky
+Elisha Jones
+Joerg Sattler
+paul42
+Pascal Heg
+Bjorn Sorenssen
+Chris Payne
+Pascal Afflard
+Robert Boboryko
+Chris Whitehead
+David Bradley
+Ian Lever
+Phillip Barber
+Jan Bronee
+N Haasnoot
+Rick Smith
+Randall Grant
+Patrick Degouy
+Piotr Zdanowski
+David Gardner
+TMac FPV
+Bernard Thompson
+Mark Sutton
+Darren J Crane
+Michael Keyes
+Magnus Borg
+David Lorentzen
+Antony Smith
+Aleksandr Sarkisov
+Johannes Kuhne
+Kathleen Cilluffo
+David Hoffmann
+Alan Porter
+Arlé Mooldijk
+Tenbones
+Kim Bitsch Lauridsen
+Arthur Costerus
+Peter Harvey
+John Simpson
+Landy de los Santos
+Graham Ridley
+Schenk Peter
+Joseph Rex
+Richard Honeywell
+Roy Nixon
+Andrew Shewan
+David Bradley
+Alan Micklethwaite
+Susan Siegel
+Stephen Evans
+William Hallman
+Franck Michel
+László Gajcsi (monthly)
+Danny Koch
+Robert Martin
+Gavin Meerwald
+Frédéric Maix
+Frank Steinberg
+Kevin Berkefeld
+Marccos Colon
+Kerry Reynolds
+Kim Jeppesen
+Arthur Peters
+Andrew Lowes
+Anthony Hallo
+Bill Hill
+Gerard Falaise
+Kevin Raynor
+Lorenzo gh
+Jan Landeweer
+David Bland
+Manuel Spoerri
+Jeff Jacobs
+David Thorne
+Maddox Philip
+James Jewitt
+Justin Digby
+John Magnuson (monthly)
+Holger Lippert
+Hubert Huber
+David Blum
+Noam Kfir
+Mats gårdstad friberg
+Jesper Frickmann
+Alan Bunker
+Emanuel Kircher
+Barry Andersen
+Gabriel Formanek
+Timothy Justiniano
+Kelvin Garcia Urbina
+Jan Lau
+Choon Wei Jonathan Tan
+Daniel Navas
+Ray Moss
+Markus Frielingsdorf
+Michael Hirschauer
+Jesse Frey
+Philipp Koch
+Robert Rubio
+Dennis G Miller
+Leonardo Garcia Osuna
+Antonio Carrasco Pastor
+Musa Pinar
+Jens Moder
+Josef de Beer
+Chad Mofford
+Pim Pouw
+Kenth Jonsson
+Gordon Westfall
+Jean-Michel Saves
+Roberto Orsello
+Luboš Konvalinka
+Lawrence Dorn
+Michael Dittmann
+Bernd Schmiedel
+Raoul Piccioli
+Uwe Probst
+Glendon Satchell
+Trevor Collins
+Horst Grashauser
+Miguel José Cárdenas Herrera
+Mike Jennings
+José Bernardo
+Carlos Dangle
+Gordon Evans
+Pablo Peinado Abad
+Carl Payne
+Adam Sosnowski
+Гасак Сергей
+SaltCtyRacingFPV
+Georg Bernhardt
+James Mildenhall
+Dave Plummer
+Ivan Mokris
+Patrick Daniels
+Stuart Olson
+Cory Znebel
+Andrey Yarovoy
+Christian Pons
+Burt Pickard-Richardson
+Michal Mesaros
+Conrad Young
+Martin Mathes
+Jens Rainer Hansen
+Mark Trible
+Marc Dubois
+Alan Wilkins
+Daniel Hryciuk
+Thomas Fox
+Sidney B Harden
+Augustas Sereika
+David Belletete
+Karl-Heinz Behn
+Lena Hjort
+Jan Langhorst
+Alberto Scotti
+John Rock
+Adam Kouse
+Ricardo Martins
+Noel Irwin
+Christoph Rausch
+Anthony Hrabusicky
+Sergio Tondini
+Aldo Visentin
+Greg Wilson
+Mark Sutton
+Lukas Kana
+Peter Newman
+Kevin Cave
+Arold Reinders
+Jason Plant
+John Beech
+Ian Parris
+Danny Music
+Eric Bissonnette
+Riso LTD
+William Booth
+Ferenc Kunkli
+Offer Shmuely
+Troy Atneosen
+Long Technologies
+John Jaugilas
+Jan-Hinrich Klee
+Hans-Reinhard Mette
+Alejandro Casals Oliver
+David Homewood
+John Dunning
+Konrad Helbach
+Bernard Delpy
+Raymond Ellsworth
+Bogdan Musial
+Гасак Сергей
+Philip Garcia
+Helder Simoes
+Thomas Blanchin
+Jean-Luc Mesnier
+Michael Bajer
+David Homewood
+Marc Sanders
+Буров Александр
+Rudy T'Jolleyn
+Jay Watkins
+Blaz Vodopivec
+David De Salvo
+Willem Verschoren
+Dennis Kathrens
+Alan Aucote
+Richard Jerome Danstrom
+David Garcia-Mendia
+Mark Jones
+John Zseleczky
+Xiao Sun
+Glenn Harvey
+Albrecht Friebel
+Gunter Klemke
+Travis McCarthy
+Franz Zier
+Ian Contessa
+Sean Sadler
+Richard F Janczak
+Mateusz Dziadosz
+Thomas Merchant
+M L Perkins
+Stefano Boggia
+Новоселов Юрий
+James Rhodes
+Peter Gaskill
+Jacques Temey
+Anthony Challis
+Gerard Falaise
+George McGinnis
+Antoine Soulie
+Tjeerd Jager
+Bertold Van den Bergh
+Stefanie Zerbe
+James Mandelbaum
+Javier J. Cordovez
+Jess Barkley
+Schneider Modell
+Michael Hasselgaard
+Thomas Young
+Непочатов Алексей
+Thomas Goebel
+Joseph Macias
+Paw Melin-Nielsen
+Liam O'Brien
+Ronald B Backman
+Corvus Inspection Services Inc
+Stuart Posnett
+Clark Emerick
+Helmut Sippel
+Jhon Lennon Silva do Nascimento
+Peter McCarthy
+Bob Brown
+Claude Lawyer
+Peter Fithern
+Michael Hoffman
+Tim Smith
+OpenSki Institute
+Simon Melov
+Richard Podolsky
+James Wilson
+John Norrbin
+James Goins
+Phillip Nguyen
+Jeffrey M Engel
+Richard Marotto
+Greg Bell
+Scott Geer
+Thomas Abshier
+Ernst Camenzind
+Radomir Sterba
+Ignacio Barrio
+Bradley Murchie
+Emmanuel Balintec
+Rowell Torres
+Christopher Kokis
+Ken Bryan
+Eric Yoder
+Olav Roth
+Rowell Torres
+Christopher Kokis
+Ken Bryan
+Glenn Noonan
+Michael Jakob
+Dean Berg
+David Hankins
+Gary Cripps
diff --git a/companion/src/CMakeLists.txt b/companion/src/CMakeLists.txt
index 3cf15d85f..3853466d9 100644
--- a/companion/src/CMakeLists.txt
+++ b/companion/src/CMakeLists.txt
@@ -343,6 +343,12 @@ if(PCB STREQUAL X7 AND PCBREV STREQUAL ACCESS)
set(FLAVOUR x7access)
elseif(PCB STREQUAL X7 AND PCBREV STREQUAL T12)
set(FLAVOUR t12)
+elseif(PCB STREQUAL X7 AND PCBREV STREQUAL TLITE)
+ set(FLAVOUR tlite)
+elseif(PCB STREQUAL X7 AND PCBREV STREQUAL TX12)
+ set(FLAVOUR tx12)
+elseif(PCB STREQUAL X7 AND PCBREV STREQUAL T8)
+ set(FLAVOUR t8)
elseif(PCB STREQUAL X9D+ AND PCBREV STREQUAL 2019)
set(FLAVOUR x9d+2019)
elseif(PCB STREQUAL X10 AND PCBREV STREQUAL EXPRESS)
@@ -513,6 +519,8 @@ IF(APPLE)
# Use a non standard Info.plist that adds Retina support flags
set_target_properties(${COMPANION_NAME} PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${PROJECT_SOURCE_DIR}/companion/targets/mac/MacOSXBundleInfo.plist.in)
set_target_properties(${SIMULATOR_NAME} PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${PROJECT_SOURCE_DIR}/companion/targets/mac/MacOSXBundleInfo.plist.in)
+
+ set(MACOSX_BUNDLE_GUI_IDENTIFIER "org.opentx.companion")
INSTALL(TARGETS ${COMPANION_NAME}
BUNDLE DESTINATION . COMPONENT Runtime
diff --git a/companion/src/companion.qrc b/companion/src/companion.qrc
index cddc2fa3e..c76418135 100644
--- a/companion/src/companion.qrc
+++ b/companion/src/companion.qrc
@@ -179,6 +179,39 @@
images/simulator/JumperT12/JumperT12-x.png
images/simulator/JumperT12/JumperT12-center.png
images/simulator/JumperT12/JumperT12-top.png
+ images/simulator/JumperTLITE/bottom.png
+ images/simulator/JumperTLITE/bottom_right.png
+ images/simulator/JumperTLITE/bottom_left.png
+ images/simulator/JumperTLITE/left.png
+ images/simulator/JumperTLITE/left_top.png
+ images/simulator/JumperTLITE/left_bottom.png
+ images/simulator/JumperTLITE/right.png
+ images/simulator/JumperTLITE/right_top.png
+ images/simulator/JumperTLITE/right_bottom.png
+ images/simulator/JumperTLITE/top.png
+ images/simulator/TX12/left.png
+ images/simulator/TX12/left-pageup.png
+ images/simulator/TX12/left-pagedn.png
+ images/simulator/TX12/left-rtn.png
+ images/simulator/TX12/left-sys.png
+ images/simulator/TX12/left-tele.png
+ images/simulator/TX12/right.png
+ images/simulator/TX12/right-ent.png
+ images/simulator/TX12/right-mdl.png
+ images/simulator/TX12/bottom.png
+ images/simulator/TX12/top.png
+ images/simulator/T8/left.png
+ images/simulator/T8/left-pageup.png
+ images/simulator/T8/left-pagedn.png
+ images/simulator/T8/left-rtn.png
+ images/simulator/T8/left-sys.png
+ images/simulator/T8/right.png
+ images/simulator/T8/right-ent.png
+ images/simulator/T8/right-mdl.png
+ images/simulator/T8/right-up.png
+ images/simulator/T8/right-dn.png
+ images/simulator/T8/bottom.png
+ images/simulator/T8/top.png
images/simulator/JumperT16/left.png
images/simulator/JumperT16/right.png
images/simulator/JumperT16/top.png
diff --git a/companion/src/constants.h b/companion/src/constants.h
index d2d32a745..b635f2d23 100644
--- a/companion/src/constants.h
+++ b/companion/src/constants.h
@@ -71,6 +71,7 @@
#define CPN_STR_APP_SETTINGS_FILTER CPN_STR_APP_SETTINGS_FILES % " (*.ini)"
#define CPN_STR_UNKNOWN_ITEM "???"
+#define CPN_STR_NONE_ITEM "----"
#define CPN_STR_SW_INDICATOR_UP QCoreApplication::translate("RawSwitch", "\xE2\x86\x91") // Switch up position indicator: Up arrow, or similar.
#define CPN_STR_SW_INDICATOR_DN QCoreApplication::translate("RawSwitch", "\xE2\x86\x93") // Switch down position indicator: Down arrow, or similar.
diff --git a/companion/src/datamodels/CMakeLists.txt b/companion/src/datamodels/CMakeLists.txt
index beb7d4d2d..446f161b3 100644
--- a/companion/src/datamodels/CMakeLists.txt
+++ b/companion/src/datamodels/CMakeLists.txt
@@ -1,12 +1,12 @@
set(datamodels_SRCS
- rawitemdatamodels.cpp
- rawitemfilteredmodel.cpp
+ compounditemmodels.cpp
+ filtereditemmodels.cpp
)
set(datamodels_HDRS
- rawitemdatamodels.h
- rawitemfilteredmodel.h
+ compounditemmodels.h
+ filtereditemmodels.h
)
qt5_wrap_cpp(datamodels_SRCS ${datamodels_HDRS})
diff --git a/companion/src/datamodels/compounditemmodels.cpp b/companion/src/datamodels/compounditemmodels.cpp
new file mode 100644
index 000000000..2f04a34fb
--- /dev/null
+++ b/companion/src/datamodels/compounditemmodels.cpp
@@ -0,0 +1,758 @@
+/*
+ * 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.
+ */
+
+#include "compounditemmodels.h"
+#include "generalsettings.h"
+#include "eeprominterface.h"
+#include "modeldata.h"
+#include "adjustmentreference.h"
+
+// static
+QString AbstractItemModel::idToString(const int value)
+{
+ switch (value) {
+ case IMID_Unknown:
+ return "Unknown";
+ case IMID_RawSource:
+ return "RawSource";
+ case IMID_RawSwitch:
+ return "RawSwitch";
+ case IMID_Curve:
+ return "Curve";
+ case IMID_GVarRef:
+ return "GVarRef";
+ case IMID_ThrSource:
+ return "ThrSource";
+ case IMID_CustomFuncAction:
+ return "CustomFuncAction";
+ case IMID_CustomFuncResetParam:
+ return "CustomFuncResetParam";
+ case IMID_TeleSource:
+ return "TeleSource";
+ case IMID_RssiSource:
+ return "RssiSource";
+ case IMID_CurveRefType:
+ return "CurveRefType";
+ case IMID_CurveRefFunc:
+ return "CurveRefFunc";
+ default:
+ return "Custom";
+ }
+}
+
+// static
+void AbstractItemModel::dumpItemModelContents(AbstractItemModel * itemModel)
+{
+ if (itemModel) {
+ qDebug() << "id:" << itemModel->getId() << "name:" << itemModel->getName();
+
+ for (int i = 0; i < itemModel->rowCount(); ++i) {
+ qDebug() << "row:" << i
+ << "text:" << itemModel->data(itemModel->index(i, 0), Qt::DisplayRole).toString()
+ << "id:" << itemModel->data(itemModel->index(i, 0), AbstractItemModel::IMDR_Id).toInt()
+ << "avail:" << itemModel->data(itemModel->index(i, 0), AbstractItemModel::IMDR_Available).toBool()
+ << "flags:" << itemModel->data(itemModel->index(i, 0), AbstractItemModel::IMDR_Flags).toInt()
+ << "type:" << itemModel->data(itemModel->index(i, 0), AbstractItemModel::IMDR_Type).toInt();
+ }
+ }
+ else
+ qDebug() << "Error: model not of class AbstractItemModel";
+}
+
+//
+// AbstractStaticItemModel
+//
+
+void AbstractStaticItemModel::loadItemList()
+{
+ foreach (const ListItem *item, itemList) {
+ QStandardItem * modelItem = new QStandardItem();
+ modelItem->setText(item->text);
+ modelItem->setData(item->id, IMDR_Id);
+ modelItem->setData(item->type, IMDR_Type);
+ modelItem->setData(item->flags, IMDR_Flags);
+ modelItem->setData(item->isAvailable, IMDR_Available);
+ appendRow(modelItem);
+ }
+
+ itemList.clear();
+};
+
+//
+// RawSourceItemModel
+//
+
+RawSourceItemModel::RawSourceItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData,
+ Firmware * firmware, const Boards * const board, const Board::Type boardType) :
+ AbstractDynamicItemModel(generalSettings, modelData, firmware, board, boardType)
+{
+ setId(IMID_RawSource);
+ setUpdateMask(IMUE_All &~ (IMUE_Curves | IMUE_Scripts));
+
+ addItems(SOURCE_TYPE_NONE, RawSource::NoneGroup, 1);
+ for (int i = 0; i < firmware->getCapability(LuaScripts); i++)
+ addItems(SOURCE_TYPE_LUA_OUTPUT, RawSource::ScriptsGroup, firmware->getCapability(LuaOutputsPerScript), i * 16);
+ addItems(SOURCE_TYPE_VIRTUAL_INPUT, RawSource::InputsGroup, firmware->getCapability(VirtualInputs));
+ addItems(SOURCE_TYPE_STICK, RawSource::SourcesGroup, board->getCapability(Board::MaxAnalogs));
+ addItems(SOURCE_TYPE_TRIM, RawSource::TrimsGroup, board->getCapability(Board::NumTrims));
+ addItems(SOURCE_TYPE_MAX, RawSource::SourcesGroup, 1);
+ addItems(SOURCE_TYPE_SWITCH, RawSource::SwitchesGroup, board->getCapability(Board::Switches));
+ addItems(SOURCE_TYPE_CUSTOM_SWITCH, RawSource::SwitchesGroup, firmware->getCapability(LogicalSwitches));
+ addItems(SOURCE_TYPE_CYC, RawSource::SourcesGroup, CPN_MAX_CYC);
+ addItems(SOURCE_TYPE_PPM, RawSource::SourcesGroup, firmware->getCapability(TrainerInputs));
+ addItems(SOURCE_TYPE_CH, RawSource::SourcesGroup, firmware->getCapability(Outputs));
+ addItems(SOURCE_TYPE_SPECIAL, RawSource::TelemGroup, 5);
+ addItems(SOURCE_TYPE_TELEMETRY, RawSource::TelemGroup, firmware->getCapability(Sensors) * 3);
+ addItems(SOURCE_TYPE_GVAR, RawSource::GVarsGroup, firmware->getCapability(Gvars));
+}
+
+void RawSourceItemModel::setDynamicItemData(QStandardItem * item, const RawSource & src) const
+{
+ item->setText(src.toString(modelData, generalSettings, boardType));
+ item->setData(src.isAvailable(modelData, generalSettings, boardType), IMDR_Available);
+}
+
+void RawSourceItemModel::addItems(const RawSourceType & type, const int group, const int count, const int start)
+{
+ for (int i = start; i < start + count; i++) {
+ const RawSource src = RawSource(type, i);
+ QStandardItem * modelItem = new QStandardItem();
+ modelItem->setData(src.toValue(), IMDR_Id);
+ modelItem->setData(type, IMDR_Type);
+ modelItem->setData(group, IMDR_Flags);
+ setDynamicItemData(modelItem, src);
+ appendRow(modelItem);
+ }
+}
+
+void RawSourceItemModel::update(const int event)
+{
+ if (doUpdate(event)) {
+ emit aboutToBeUpdated();
+
+ for (int i = 0; i < rowCount(); ++i)
+ setDynamicItemData(item(i), RawSource(item(i)->data(IMDR_Id).toInt()));
+
+ emit updateComplete();
+ }
+}
+
+//
+// RawSwitchItemModel
+//
+
+RawSwitchItemModel::RawSwitchItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData,
+ Firmware * firmware, const Boards * const board, const Board::Type boardType) :
+ AbstractDynamicItemModel(generalSettings, modelData, firmware, board, boardType)
+{
+ setId(IMID_RawSwitch);
+ setUpdateMask(IMUE_FlightModes | IMUE_LogicalSwitches | IMUE_TeleSensors);
+
+ // Descending switch direction: NOT (!) switches
+ addItems(SWITCH_TYPE_ACT, -1);
+ addItems(SWITCH_TYPE_SENSOR, -firmware->getCapability(Sensors));
+ addItems(SWITCH_TYPE_TELEMETRY, -1);
+ addItems(SWITCH_TYPE_FLIGHT_MODE, -firmware->getCapability(FlightModes));
+ addItems(SWITCH_TYPE_VIRTUAL, -firmware->getCapability(LogicalSwitches));
+ addItems(SWITCH_TYPE_TRIM, -board->getCapability(Board::NumTrimSwitches));
+ addItems(SWITCH_TYPE_MULTIPOS_POT, -(board->getCapability(Board::MultiposPots) * board->getCapability(Board::MultiposPotsPositions)));
+ addItems(SWITCH_TYPE_SWITCH, -board->getCapability(Board::SwitchPositions));
+
+ // Ascending switch direction (including zero)
+ addItems(SWITCH_TYPE_TIMER_MODE, 5);
+ addItems(SWITCH_TYPE_NONE, 1);
+ addItems(SWITCH_TYPE_SWITCH, board->getCapability(Board::SwitchPositions));
+ addItems(SWITCH_TYPE_MULTIPOS_POT, board->getCapability(Board::MultiposPots) * board->getCapability(Board::MultiposPotsPositions));
+ addItems(SWITCH_TYPE_TRIM, board->getCapability(Board::NumTrimSwitches));
+ addItems(SWITCH_TYPE_VIRTUAL, firmware->getCapability(LogicalSwitches));
+ addItems(SWITCH_TYPE_FLIGHT_MODE, firmware->getCapability(FlightModes));
+ addItems(SWITCH_TYPE_TELEMETRY, 1);
+ addItems(SWITCH_TYPE_SENSOR, firmware->getCapability(Sensors));
+ addItems(SWITCH_TYPE_ON, 1);
+ addItems(SWITCH_TYPE_ONE, 1);
+ addItems(SWITCH_TYPE_ACT, 1);
+}
+
+void RawSwitchItemModel::setDynamicItemData(QStandardItem * item, const RawSwitch & rsw) const
+{
+ item->setText(rsw.toString(boardType, generalSettings, modelData));
+ item->setData(rsw.isAvailable(modelData, generalSettings, boardType), IMDR_Available);
+}
+
+void RawSwitchItemModel::addItems(const RawSwitchType & type, int count)
+{
+ // Most RawSwitch() indices are one-based (vs. typical zero); these are exceptions to the rule:
+ const static QVector rawSwitchIndexBaseZeroTypes = QVector() << SWITCH_TYPE_NONE << SWITCH_TYPE_ON << SWITCH_TYPE_OFF << SWITCH_TYPE_TIMER_MODE;
+ // handle exceptions in RawSwitch() index values
+ const short rawIdxAdj = rawSwitchIndexBaseZeroTypes.contains(type) ? -1 : 0;
+
+ // determine cotext flags
+ int context = RawSwitch::AllSwitchContexts;
+ switch (type) {
+ case SWITCH_TYPE_FLIGHT_MODE:
+ context &= ~RawSwitch::MixesContext;
+ // fallthrough
+ case SWITCH_TYPE_VIRTUAL:
+ case SWITCH_TYPE_SENSOR:
+ context &= ~RawSwitch::GlobalFunctionsContext;
+ break;
+
+ case SWITCH_TYPE_TIMER_MODE:
+ context = RawSwitch::TimersContext;
+ break;
+
+ case SWITCH_TYPE_NONE:
+ context &= ~RawSwitch::TimersContext;
+ break;
+
+ case SWITCH_TYPE_ON:
+ case SWITCH_TYPE_ONE:
+ context = RawSwitch::SpecialFunctionsContext | RawSwitch::GlobalFunctionsContext;
+ break;
+
+ default:
+ break;
+ }
+
+ int i = (count < 0 ? count : 1);
+ count = (i < 0 ? 0 : count + i);
+ for ( ; i < count; ++i) {
+ RawSwitch rs(type, i + rawIdxAdj);
+ QStandardItem * modelItem = new QStandardItem();
+ modelItem->setData(rs.toValue(), IMDR_Id);
+ modelItem->setData(type, IMDR_Type);
+ modelItem->setData(context, IMDR_Flags);
+ setDynamicItemData(modelItem, rs);
+ appendRow(modelItem);
+ }
+}
+
+void RawSwitchItemModel::update(const int event)
+{
+ if (doUpdate(event)) {
+ emit aboutToBeUpdated();
+
+ for (int i = 0; i < rowCount(); ++i)
+ setDynamicItemData(item(i), RawSwitch(item(i)->data(IMDR_Id).toInt()));
+
+ emit updateComplete();
+ }
+}
+
+//
+// CurveItemModel
+//
+
+CurveItemModel::CurveItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData,
+ Firmware * firmware, const Boards * const board, const Board::Type boardType) :
+ AbstractDynamicItemModel(generalSettings, modelData, firmware, board, boardType)
+{
+ setId(IMID_Curve);
+
+ if (!modelData)
+ return;
+
+ setUpdateMask(IMUE_Curves);
+
+ const int count = firmware->getCapability(NumCurves);
+
+ for (int i = -count ; i <= count; ++i) {
+ QStandardItem * modelItem = new QStandardItem();
+ modelItem->setData(i, IMDR_Id);
+ modelItem->setData(i < 0 ? IMDG_Negative : i > 0 ? IMDG_Positive : IMDG_None, IMDR_Flags);
+ setDynamicItemData(modelItem, i);
+ appendRow(modelItem);
+ }
+}
+
+void CurveItemModel::setDynamicItemData(QStandardItem * item, const int value) const
+{
+ CurveReference cr = CurveReference(CurveReference::CURVE_REF_CUSTOM, value);
+ item->setText(cr.toString(modelData, false));
+ item->setData(cr.isAvailable(), IMDR_Available);
+}
+
+void CurveItemModel::update(const int event)
+{
+ if (doUpdate(event)) {
+ emit aboutToBeUpdated();
+
+ for (int i = 0; i < rowCount(); ++i)
+ setDynamicItemData(item(i), item(i)->data(IMDR_Id).toInt());
+
+ emit updateComplete();
+ }
+}
+
+//
+// GVarReferenceItemModel
+//
+
+GVarReferenceItemModel::GVarReferenceItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData,
+ Firmware * firmware, const Boards * const board, const Board::Type boardType) :
+ AbstractDynamicItemModel(generalSettings, modelData, firmware, board, boardType)
+{
+ setId(IMID_GVarRef);
+
+ if (!modelData)
+ return;
+
+ setUpdateMask(IMUE_GVars | IMUE_FlightModes | IMUE_LogicalSwitches);
+
+ const int count = firmware->getCapability(Gvars);
+
+ if (count > 0) {
+ addItems(-count);
+ addItems(count);
+ }
+}
+
+void GVarReferenceItemModel::addItems(int count)
+{
+ int i = (count < 0 ? count : 1);
+ count = (i < 0 ? 0 : count + i);
+ for ( ; i < count; ++i) {
+ QStandardItem * modelItem = new QStandardItem();
+ AdjustmentReference ar(AdjustmentReference::ADJUST_REF_GVAR, i);
+ modelItem->setData(ar.toValue(), IMDR_Id);
+ modelItem->setData(i < 0 ? IMDG_Negative : i > 0 ? IMDG_Positive : IMDG_None, IMDR_Flags);
+ setDynamicItemData(modelItem, ar);
+ appendRow(modelItem);
+ }
+}
+
+void GVarReferenceItemModel::setDynamicItemData(QStandardItem * item, const AdjustmentReference & ar) const
+{
+ item->setText(ar.toString(modelData, false));
+ item->setData(ar.isAvailable(), IMDR_Available);
+}
+
+void GVarReferenceItemModel::update(const int event)
+{
+ if (doUpdate(event)) {
+ emit aboutToBeUpdated();
+
+ for (int i = 0; i < rowCount(); ++i)
+ setDynamicItemData(item(i), AdjustmentReference(item(i)->data(IMDR_Id).toInt()));
+
+ emit updateComplete();
+ }
+}
+
+//
+// ThrottleSourceItemModel
+//
+
+ThrottleSourceItemModel::ThrottleSourceItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData,
+ Firmware * firmware, const Boards * const board, const Board::Type boardType) :
+ AbstractDynamicItemModel(generalSettings, modelData, firmware, board, boardType)
+{
+ setId(IMID_ThrSource);
+
+ if (!modelData)
+ return;
+
+ setUpdateMask(IMUE_Timers | IMUE_Inputs | IMUE_TeleSensors);
+
+ for (int i = 0; i < modelData->thrTraceSrcCount(); i++) {
+ QStandardItem * modelItem = new QStandardItem();
+ modelItem->setData(i, IMDR_Id);
+ setDynamicItemData(modelItem, i);
+ appendRow(modelItem);
+ }
+}
+
+void ThrottleSourceItemModel::setDynamicItemData(QStandardItem * item, const int value) const
+{
+ item->setText(modelData->thrTraceSrcToString(value));
+ item->setData(modelData->isThrTraceSrcAvailable(generalSettings, value), IMDR_Available);
+}
+
+void ThrottleSourceItemModel::update(const int event)
+{
+ if (doUpdate(event)) {
+ emit aboutToBeUpdated();
+
+ for (int i = 0; i < rowCount(); ++i)
+ setDynamicItemData(item(i), item(i)->data(IMDR_Id).toInt());
+
+ emit updateComplete();
+ }
+}
+
+//
+// CustomFuncActionItemModel
+//
+
+CustomFuncActionItemModel::CustomFuncActionItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData,
+ Firmware * firmware, const Boards * const board, const Board::Type boardType) :
+ AbstractDynamicItemModel(generalSettings, modelData, firmware, board, boardType)
+{
+ setId(IMID_CustomFuncAction);
+ setUpdateMask(IMUE_All &~ (IMUE_Curves | IMUE_Scripts));
+
+ for (int i = 0; i < AssignFunc::FuncCount; i++) {
+ QStandardItem * modelItem = new QStandardItem();
+ modelItem->setData(i, IMDR_Id);
+ modelItem->setData(CustomFunctionData::funcContext(i), IMDR_Flags);
+ setDynamicItemData(modelItem, i);
+ appendRow(modelItem);
+ }
+}
+
+void CustomFuncActionItemModel::setDynamicItemData(QStandardItem * item, const int value) const
+{
+ item->setText(CustomFunctionData::funcToString((AssignFunc)value, modelData));
+ item->setData(CustomFunctionData::isFuncAvailable(value), IMDR_Available);
+}
+
+void CustomFuncActionItemModel::update(const int event)
+{
+ if (doUpdate(event)) {
+ emit aboutToBeUpdated();
+
+ for (int i = 0; i < rowCount(); ++i)
+ setDynamicItemData(item(i), item(i)->data(IMDR_Id).toInt());
+
+ emit updateComplete();
+ }
+}
+
+//
+// CustomFuncResetParamItemModel
+//
+
+CustomFuncResetParamItemModel::CustomFuncResetParamItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData,
+ Firmware * firmware, const Boards * const board, const Board::Type boardType) :
+ AbstractDynamicItemModel(generalSettings, modelData, firmware, board, boardType)
+{
+ setId(IMID_CustomFuncResetParam);
+ setUpdateMask(IMUE_TeleSensors | IMUE_Timers);
+
+ for (int i = 0; i < CustomFunctionData::resetParamCount(); i++) {
+ QStandardItem * modelItem = new QStandardItem();
+ modelItem->setData(i, IMDR_Id);
+ setDynamicItemData(modelItem, i);
+ appendRow(modelItem);
+ }
+}
+
+void CustomFuncResetParamItemModel::setDynamicItemData(QStandardItem * item, const int value) const
+{
+ item->setText(CustomFunctionData::resetToString(value, modelData));
+ item->setData(CustomFunctionData::isResetParamAvailable(value, modelData), IMDR_Available);
+}
+
+void CustomFuncResetParamItemModel::update(const int event)
+{
+ if (doUpdate(event)) {
+ emit aboutToBeUpdated();
+
+ for (int i = 0; i < rowCount(); ++i)
+ setDynamicItemData(item(i), item(i)->data(IMDR_Id).toInt());
+
+ emit updateComplete();
+ }
+}
+
+//
+// TelemetrySourceItemModel
+//
+
+TelemetrySourceItemModel::TelemetrySourceItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData,
+ Firmware * firmware, const Boards * const board, const Board::Type boardType) :
+ AbstractDynamicItemModel(generalSettings, modelData, firmware, board, boardType)
+{
+ setId(IMID_TeleSource);
+
+ if (!modelData)
+ return;
+
+ setUpdateMask(IMUE_TeleSensors | IMUE_Modules);
+ const int count = firmware->getCapability(Sensors);
+
+ for (int i = -count; i <= count; ++i) {
+ QStandardItem * modelItem = new QStandardItem();
+ modelItem->setData(i, IMDR_Id);
+ modelItem->setData(i < 0 ? IMDG_Negative : i > 0 ? IMDG_Positive : IMDG_None, IMDR_Flags);
+ setDynamicItemData(modelItem, i);
+ appendRow(modelItem);
+ }
+}
+
+void TelemetrySourceItemModel::setDynamicItemData(QStandardItem * item, const int value) const
+{
+ item->setText(SensorData::sourceToString(modelData, value));
+ item->setData(SensorData::isSourceAvailable(modelData, value), IMDR_Available);
+}
+
+void TelemetrySourceItemModel::update(const int event)
+{
+ if (doUpdate(event)) {
+ emit aboutToBeUpdated();
+
+ for (int i = 0; i < rowCount(); ++i) {
+ setDynamicItemData(item(i), item(i)->data(IMDR_Id).toInt());
+ }
+
+ emit updateComplete();
+ }
+}
+
+//
+// RssiSourceItemModel
+//
+
+RssiSourceItemModel::RssiSourceItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData,
+ Firmware * firmware, const Boards * const board, const Board::Type boardType) :
+ AbstractDynamicItemModel(generalSettings, modelData, firmware, board, boardType)
+{
+ setId(IMID_RssiSource);
+
+ if (!modelData)
+ return;
+
+ setUpdateMask(IMUE_TeleSensors | IMUE_Modules);
+
+ for (int i = 0; i <= firmware->getCapability(Sensors); ++i) {
+ QStandardItem * modelItem = new QStandardItem();
+ modelItem->setData(i, IMDR_Id);
+ modelItem->setData(i < 0 ? IMDG_Negative : i > 0 ? IMDG_Positive : IMDG_None, IMDR_Flags);
+ setDynamicItemData(modelItem, i);
+ appendRow(modelItem);
+ }
+}
+
+void RssiSourceItemModel::setDynamicItemData(QStandardItem * item, const int value) const
+{
+ item->setText(SensorData::rssiSensorToString(modelData, value));
+ item->setData(SensorData::isRssiSensorAvailable(modelData, value), IMDR_Available);
+}
+
+void RssiSourceItemModel::update(const int event)
+{
+ if (doUpdate(event)) {
+ emit aboutToBeUpdated();
+
+ for (int i = 0; i < rowCount(); ++i) {
+ setDynamicItemData(item(i), item(i)->data(IMDR_Id).toInt());
+ }
+
+ emit updateComplete();
+ }
+}
+
+//
+// CurveRefTypeItemModel
+//
+
+CurveRefTypeItemModel::CurveRefTypeItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData,
+ Firmware * firmware, const Boards * const board, const Board::Type boardType) :
+ AbstractStaticItemModel(generalSettings, modelData, firmware, board, boardType)
+{
+ setId(IMID_CurveRefType);
+
+ for (int i = 0; i <= CurveReference::MAX_CURVE_REF_TYPE; i++) {
+ QStandardItem * modelItem = new QStandardItem();
+ modelItem->setText(CurveReference::typeToString((CurveReference::CurveRefType)i));
+ modelItem->setData(i, IMDR_Id);
+ modelItem->setData(CurveReference::isTypeAvailable((CurveReference::CurveRefType)i), IMDR_Available);
+ appendRow(modelItem);
+ }
+}
+
+//
+// CurveRefFuncItemModel
+//
+
+CurveRefFuncItemModel::CurveRefFuncItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData,
+ Firmware * firmware, const Boards * const board, const Board::Type boardType) :
+ AbstractStaticItemModel(generalSettings, modelData, firmware, board, boardType)
+{
+ setId(IMID_CurveRefFunc);
+
+ for (int i = 1; i <= CurveReference::functionCount(); i++) {
+ QStandardItem * modelItem = new QStandardItem();
+ modelItem->setText(CurveReference::functionToString(i));
+ modelItem->setData(i, IMDR_Id);
+ modelItem->setData(CurveReference::isFunctionAvailable(i), IMDR_Available);
+ appendRow(modelItem);
+ }
+}
+
+//
+// PrecisionItemModel
+//
+
+PrecisionItemModel::PrecisionItemModel(const int minDecimals, const int maxDecimals, const QString suffix, const bool placeholders) :
+ AbstractStaticItemModel()
+{
+ for (int i = minDecimals, j = maxDecimals; j >= 0; i++, j--) {
+ QString str = QString("0.%1").arg(QString(i, '0'));
+ if (placeholders)
+ str.append(QString(j, '_'));
+ if (!suffix.isEmpty())
+ str.append(QString(" %1").arg(suffix));
+ QStandardItem * modelItem = new QStandardItem();
+ modelItem->setText(str);
+ modelItem->setData(i, IMDR_Id);
+ modelItem->setData(true, IMDR_Available);
+ appendRow(modelItem);
+ }
+}
+
+//
+// CompoundItemModelFactory
+//
+
+CompoundItemModelFactory::CompoundItemModelFactory(const GeneralSettings * const generalSettings, const ModelData * const modelData) :
+ generalSettings(generalSettings),
+ modelData(modelData)
+{
+ firmware = getCurrentFirmware();
+ board = new Boards(getCurrentBoard());
+ boardType = getCurrentBoard();
+}
+
+CompoundItemModelFactory::~CompoundItemModelFactory()
+{
+ unregisterItemModels();
+ delete board;
+}
+
+void CompoundItemModelFactory::addItemModel(const int id)
+{
+ switch (id) {
+ case AbstractItemModel::IMID_RawSource:
+ registerItemModel(new RawSourceItemModel(generalSettings, modelData, firmware, board, boardType));
+ break;
+ case AbstractItemModel::IMID_RawSwitch:
+ registerItemModel(new RawSwitchItemModel(generalSettings, modelData, firmware, board, boardType));
+ break;
+ case AbstractItemModel::IMID_Curve:
+ registerItemModel(new CurveItemModel(generalSettings, modelData, firmware, board, boardType));
+ break;
+ case AbstractItemModel::IMID_GVarRef:
+ registerItemModel(new GVarReferenceItemModel(generalSettings, modelData, firmware, board, boardType));
+ break;
+ case AbstractItemModel::IMID_ThrSource:
+ registerItemModel(new ThrottleSourceItemModel(generalSettings, modelData, firmware, board, boardType));
+ break;
+ case AbstractItemModel::IMID_CustomFuncAction:
+ registerItemModel(new CustomFuncActionItemModel(generalSettings, modelData, firmware, board, boardType));
+ break;
+ case AbstractItemModel::IMID_CustomFuncResetParam:
+ registerItemModel(new CustomFuncResetParamItemModel(generalSettings, modelData, firmware, board, boardType));
+ break;
+ case AbstractItemModel::IMID_TeleSource:
+ registerItemModel(new TelemetrySourceItemModel(generalSettings, modelData, firmware, board, boardType));
+ break;
+ case AbstractItemModel::IMID_RssiSource:
+ registerItemModel(new RssiSourceItemModel(generalSettings, modelData, firmware, board, boardType));
+ break;
+ case AbstractItemModel::IMID_CurveRefType:
+ registerItemModel(new CurveRefTypeItemModel(generalSettings, modelData, firmware, board, boardType));
+ break;
+ case AbstractItemModel::IMID_CurveRefFunc:
+ registerItemModel(new CurveRefFuncItemModel(generalSettings, modelData, firmware, board, boardType));
+ break;
+ default:
+ qDebug() << "Error: unknown item model: id";
+ break;
+ }
+}
+
+int CompoundItemModelFactory::registerItemModel(AbstractItemModel * itemModel)
+{
+ if (itemModel) {
+ if (!isItemModelRegistered(itemModel->getId())) {
+ setSourceId(itemModel);
+ registeredItemModels.append(itemModel);
+ return itemModel->getId();
+ }
+ else
+ return itemModel->getId();
+ }
+ return -1;
+}
+
+void CompoundItemModelFactory::unregisterItemModels()
+{
+ foreach (AbstractItemModel *itemModel, registeredItemModels) {
+ delete itemModel;
+ }
+}
+
+void CompoundItemModelFactory::unregisterItemModel(const int id)
+{
+ AbstractItemModel * itemModel = getItemModel(id);
+ if (itemModel)
+ delete itemModel;
+}
+
+AbstractItemModel * CompoundItemModelFactory::getItemModel(const int id) const
+{
+ foreach (AbstractItemModel * itemModel, registeredItemModels) {
+ if (itemModel->getId() == id)
+ return itemModel;
+ }
+
+ return nullptr;
+}
+
+AbstractItemModel * CompoundItemModelFactory::getItemModel(const QString name) const
+{
+ foreach (AbstractItemModel * itemModel, registeredItemModels) {
+ if (itemModel->getName() == name)
+ return itemModel;
+ }
+
+ return nullptr;
+}
+
+bool CompoundItemModelFactory::isItemModelRegistered(const int id) const
+{
+ foreach (AbstractItemModel * itemModel, registeredItemModels) {
+ if (itemModel->getId() == id)
+ return true;
+ }
+
+ return false;
+}
+
+void CompoundItemModelFactory::update(const int event)
+{
+ foreach (AbstractItemModel * itemModel, registeredItemModels) {
+ itemModel->update(event);
+ }
+}
+
+void CompoundItemModelFactory::dumpAllItemModelContents() const
+{
+ foreach (AbstractItemModel * itemModel, registeredItemModels) {
+ AbstractItemModel::dumpItemModelContents(itemModel);
+ }
+}
+
+void CompoundItemModelFactory::setSourceId(AbstractItemModel * itemModel)
+{
+ if (itemModel && itemModel->getId() == AbstractItemModel::IMID_Unknown)
+ itemModel->setId(AbstractItemModel::IMID_ReservedCount + registeredItemModels.count());
+}
diff --git a/companion/src/datamodels/compounditemmodels.h b/companion/src/datamodels/compounditemmodels.h
new file mode 100644
index 000000000..d5a7c5f27
--- /dev/null
+++ b/companion/src/datamodels/compounditemmodels.h
@@ -0,0 +1,380 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "rawsource.h"
+#include "rawswitch.h"
+
+#include
+
+class GeneralSettings;
+class ModelData;
+class AdjustmentReference;
+
+class AbstractItemModel: public QStandardItemModel
+{
+ Q_OBJECT
+ public:
+ enum ItemModelId {
+ IMID_Unknown,
+ IMID_RawSource,
+ IMID_RawSwitch,
+ IMID_Curve,
+ IMID_GVarRef,
+ IMID_ThrSource,
+ IMID_CustomFuncAction,
+ IMID_CustomFuncResetParam,
+ IMID_TeleSource,
+ IMID_RssiSource,
+ IMID_CurveRefType,
+ IMID_CurveRefFunc,
+ IMID_ReservedCount,
+ IMID_Custom
+ };
+ Q_ENUM(ItemModelId)
+
+ enum ItemModelDataRoles {
+ IMDR_Id = Qt::UserRole,
+ IMDR_Type,
+ IMDR_Flags,
+ IMDR_Available
+ };
+ Q_ENUM(ItemModelDataRoles)
+
+ enum ItemModelDataGroups {
+ IMDG_None = 0x01,
+ IMDG_Negative = 0x02,
+ IMDG_Positive = 0x04
+ };
+ Q_ENUM(ItemModelDataGroups)
+
+ enum ItemModelUpdateEvent {
+ IMUE_None = 0,
+ IMUE_SystemRefresh = 1 << 0,
+ IMUE_Channels = 1 << 1,
+ IMUE_Curves = 1 << 2,
+ IMUE_FlightModes = 1 << 3,
+ IMUE_GVars = 1 << 4,
+ IMUE_Inputs = 1 << 5,
+ IMUE_LogicalSwitches = 1 << 6,
+ IMUE_Scripts = 1 << 7,
+ IMUE_TeleSensors = 1 << 8,
+ IMUE_Timers = 1 << 9,
+ IMUE_Modules = 1 << 10,
+ IMUE_All = IMUE_SystemRefresh | IMUE_Channels | IMUE_Curves | IMUE_FlightModes | IMUE_GVars | IMUE_Inputs |
+ IMUE_LogicalSwitches | IMUE_Scripts | IMUE_TeleSensors | IMUE_Timers | IMUE_Modules
+ };
+ Q_ENUM(ItemModelUpdateEvent)
+
+ explicit AbstractItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData,
+ Firmware * firmware, const Boards * const board, const Board::Type boardType) :
+ QStandardItemModel(nullptr),
+ generalSettings(generalSettings),
+ modelData(modelData),
+ firmware(firmware),
+ board(board),
+ boardType(boardType),
+ m_id(IMID_Unknown),
+ m_name(""),
+ m_updateMask(IMUE_None)
+ {}
+
+ virtual ~AbstractItemModel() {}
+
+ void setId(int id) { m_id = id; }
+ int getId () const { return m_id; }
+ bool isReservedModelId() const { return m_id > IMID_Unknown && m_id < IMID_ReservedCount; }
+ void setName(QString name) { m_name = name; }
+ QString getName() const { return isReservedModelId() ? idToString(m_id) : m_name; }
+ void setUpdateMask(const int mask) { m_updateMask = mask; }
+ int getUpdateMask() const { return m_updateMask; }
+
+ inline bool doUpdate(const int event) const { return m_updateMask & event; }
+
+ AbstractItemModel * getItemModel(const int id) const;
+
+ static void dumpItemModelContents(AbstractItemModel * itemModel);
+
+ public slots:
+ virtual void update(const int event = IMUE_SystemRefresh) = 0;
+
+ protected:
+ const GeneralSettings * generalSettings;
+ const ModelData * modelData;
+ Firmware * firmware;
+ const Boards * board;
+ const Board::Type boardType;
+
+ private:
+ int m_id = IMID_Unknown;
+ QString m_name = "";
+ int m_updateMask = IMUE_None;
+
+ static QString idToString(const int value);
+};
+
+class AbstractStaticItemModel: public AbstractItemModel
+{
+ Q_OBJECT
+ public:
+ explicit AbstractStaticItemModel(const GeneralSettings * const generalSettings = nullptr, const ModelData * const modelData = nullptr,
+ Firmware * firmware = nullptr, const Boards * const board = nullptr,
+ const Board::Type boardType = Board::BOARD_UNKNOWN) :
+ AbstractItemModel(generalSettings, modelData, firmware, board, boardType) {}
+ virtual ~AbstractStaticItemModel() {};
+
+ inline void appendToItemList(QString text, int id, bool isAvailable = true, int type = 0, int flags = 0)
+ { itemList.append(new ListItem(text, id, isAvailable, type, flags)); }
+
+ void loadItemList();
+
+ public slots:
+ virtual void update(const int event) override final {}
+
+ protected:
+ struct ListItem
+ {
+ QString text;
+ int id;
+ bool isAvailable;
+ int type;
+ int flags;
+
+ ListItem() {}
+ ListItem(QString p_text, int p_id, bool p_isAvailable, int p_type, int p_flags) :
+ text(p_text), id(p_id), isAvailable(p_isAvailable), type(p_type), flags(p_flags) {}
+ };
+
+ QVector itemList;
+};
+
+class AbstractDynamicItemModel: public AbstractItemModel
+{
+ Q_OBJECT
+ public:
+ explicit AbstractDynamicItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData,
+ Firmware * firmware, const Boards * const board, const Board::Type boardType) :
+ AbstractItemModel(generalSettings, modelData, firmware, board, boardType) {}
+ virtual ~AbstractDynamicItemModel() {};
+
+ public slots:
+ virtual void update(const int event = IMUE_SystemRefresh) {}
+
+ signals:
+ void aboutToBeUpdated();
+ void updateComplete();
+};
+
+class RawSourceItemModel: public AbstractDynamicItemModel
+{
+ Q_OBJECT
+ public:
+ explicit RawSourceItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData,
+ Firmware * firmware, const Boards * const board, const Board::Type boardType);
+ virtual ~RawSourceItemModel() {};
+
+ public slots:
+ virtual void update(const int event = IMUE_SystemRefresh) override;
+
+ protected:
+ virtual void setDynamicItemData(QStandardItem * item, const RawSource & src) const;
+ void addItems(const RawSourceType & type, const int group, const int count, const int start = 0);
+};
+
+class RawSwitchItemModel: public AbstractDynamicItemModel
+{
+ Q_OBJECT
+ public:
+ explicit RawSwitchItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData,
+ Firmware * firmware, const Boards * const board, const Board::Type boardType);
+ virtual ~RawSwitchItemModel() {};
+
+ public slots:
+ virtual void update(const int event = IMUE_SystemRefresh) override;
+
+ protected:
+ virtual void setDynamicItemData(QStandardItem * item, const RawSwitch & rsw) const;
+ void addItems(const RawSwitchType & type, int count);
+};
+
+class CurveItemModel: public AbstractDynamicItemModel
+{
+ Q_OBJECT
+ public:
+ explicit CurveItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData,
+ Firmware * firmware, const Boards * const board, const Board::Type boardType);
+ virtual ~CurveItemModel() {};
+
+ public slots:
+ virtual void update(const int event = IMUE_SystemRefresh) override;
+
+ protected:
+ virtual void setDynamicItemData(QStandardItem * item, const int value) const;
+};
+
+class GVarReferenceItemModel: public AbstractDynamicItemModel
+{
+ Q_OBJECT
+ public:
+ explicit GVarReferenceItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData,
+ Firmware * firmware, const Boards * const board, const Board::Type boardType);
+ virtual ~GVarReferenceItemModel() {};
+
+ public slots:
+ virtual void update(const int event = IMUE_SystemRefresh) override;
+
+ protected:
+ virtual void setDynamicItemData(QStandardItem * item, const AdjustmentReference & ar) const;
+ void addItems(int count);
+};
+
+class ThrottleSourceItemModel: public AbstractDynamicItemModel
+{
+ Q_OBJECT
+ public:
+ explicit ThrottleSourceItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData,
+ Firmware * firmware, const Boards * const board, const Board::Type boardType);
+ virtual ~ThrottleSourceItemModel() {};
+
+ public slots:
+ virtual void update(const int event = IMUE_SystemRefresh) override;
+
+ protected:
+ virtual void setDynamicItemData(QStandardItem * item, const int value) const;
+};
+
+class CustomFuncActionItemModel: public AbstractDynamicItemModel
+{
+ Q_OBJECT
+ public:
+ explicit CustomFuncActionItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData,
+ Firmware * firmware, const Boards * const board, const Board::Type boardType);
+ virtual ~CustomFuncActionItemModel() {};
+
+ public slots:
+ virtual void update(const int event = IMUE_SystemRefresh) override;
+
+ protected:
+ virtual void setDynamicItemData(QStandardItem * item, const int value) const;
+};
+
+class CustomFuncResetParamItemModel: public AbstractDynamicItemModel
+{
+ Q_OBJECT
+ public:
+ explicit CustomFuncResetParamItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData,
+ Firmware * firmware, const Boards * const board, const Board::Type boardType);
+ virtual ~CustomFuncResetParamItemModel() {};
+
+ public slots:
+ virtual void update(const int event = IMUE_SystemRefresh) override;
+
+ protected:
+ virtual void setDynamicItemData(QStandardItem * item, const int value) const;
+};
+
+class TelemetrySourceItemModel: public AbstractDynamicItemModel
+{
+ Q_OBJECT
+ public:
+ explicit TelemetrySourceItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData,
+ Firmware * firmware, const Boards * const board, const Board::Type boardType);
+ virtual ~TelemetrySourceItemModel() {};
+
+ public slots:
+ virtual void update(const int event = IMUE_SystemRefresh) override;
+
+ protected:
+ virtual void setDynamicItemData(QStandardItem * item, const int value) const;
+};
+
+class RssiSourceItemModel: public AbstractDynamicItemModel
+{
+ Q_OBJECT
+ public:
+ explicit RssiSourceItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData,
+ Firmware * firmware, const Boards * const board, const Board::Type boardType);
+ virtual ~RssiSourceItemModel() {};
+
+ public slots:
+ virtual void update(const int event = IMUE_SystemRefresh) override;
+
+ protected:
+ virtual void setDynamicItemData(QStandardItem * item, const int value) const;
+};
+
+class CurveRefTypeItemModel : public AbstractStaticItemModel
+{
+ Q_OBJECT
+ public:
+ explicit CurveRefTypeItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData,
+ Firmware * firmware, const Boards * const board, const Board::Type boardType);
+ virtual ~CurveRefTypeItemModel() {};
+};
+
+class CurveRefFuncItemModel : public AbstractStaticItemModel
+{
+ Q_OBJECT
+ public:
+ explicit CurveRefFuncItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData,
+ Firmware * firmware, const Boards * const board, const Board::Type boardType);
+ virtual ~CurveRefFuncItemModel() {};
+};
+
+class PrecisionItemModel : public AbstractStaticItemModel
+{
+ Q_OBJECT
+ public:
+ explicit PrecisionItemModel(const int minDecimals, const int maxDecimals, const QString suffix = "", const bool placeholders = false);
+ virtual ~PrecisionItemModel() {};
+};
+
+//
+// CompoundItemModelFactory
+//
+
+class CompoundItemModelFactory
+{
+ public:
+ CompoundItemModelFactory(const GeneralSettings * const generalSettings, const ModelData * const modelData);
+ virtual ~CompoundItemModelFactory();
+
+ void addItemModel(const int id);
+ int registerItemModel(AbstractItemModel * itemModel);
+ void unregisterItemModels();
+ void unregisterItemModel(const int id);
+ bool isItemModelRegistered(const int id) const;
+ AbstractItemModel * getItemModel(const int id) const;
+ AbstractItemModel * getItemModel(const QString name) const;
+ void update(const int event = AbstractItemModel::IMUE_SystemRefresh);
+ void dumpAllItemModelContents() const;
+
+ protected:
+ const GeneralSettings * generalSettings;
+ const ModelData * modelData;
+ Firmware * firmware;
+ Boards * board;
+ Board::Type boardType;
+ QVector registeredItemModels;
+
+ private:
+ void setSourceId(AbstractItemModel * itemModel);
+};
diff --git a/companion/src/datamodels/filtereditemmodels.cpp b/companion/src/datamodels/filtereditemmodels.cpp
new file mode 100644
index 000000000..4f4e27262
--- /dev/null
+++ b/companion/src/datamodels/filtereditemmodels.cpp
@@ -0,0 +1,252 @@
+/*
+ * 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.
+ */
+
+#include "filtereditemmodels.h"
+
+FilteredItemModel::FilteredItemModel(AbstractItemModel * sourceModel, int flags) :
+ QSortFilterProxyModel(nullptr),
+ filterFlags(0),
+ m_id(0),
+ m_name("")
+{
+ setFilterRole(AbstractItemModel::IMDR_Available);
+ setFilterKeyColumn(0);
+ setFilterFlags(flags);
+ setDynamicSortFilter(true);
+ setSourceModel(sourceModel);
+
+ AbstractDynamicItemModel * itemModel = qobject_cast(sourceModel);
+ if (itemModel) {
+ connect(itemModel, &AbstractDynamicItemModel::aboutToBeUpdated, this, &FilteredItemModel::onAboutToBeUpdated);
+ connect(itemModel, &AbstractDynamicItemModel::updateComplete, this, &FilteredItemModel::onUpdateComplete);
+ }
+}
+
+void FilteredItemModel::setFilterFlags(int flags)
+{
+ if (filterFlags != flags) {
+ filterFlags = flags;
+ invalidateFilter();
+ }
+}
+
+bool FilteredItemModel::filterAcceptsRow(int sourceRow, const QModelIndex & sourceParent) const
+{
+ const QModelIndex & srcIdx = sourceModel()->index(sourceRow, 0, sourceParent);
+ if (!srcIdx.isValid() || !sourceModel()->data(srcIdx, filterRole()).toBool())
+ return false;
+
+ if (!filterFlags)
+ return true;
+
+ bool ok;
+ const int flags = sourceModel()->data(srcIdx, AbstractItemModel::IMDR_Flags).toInt(&ok);
+ return (ok && (!flags || (filterFlags & flags)));
+}
+
+void FilteredItemModel::update() const
+{
+ AbstractDynamicItemModel * itemModel = qobject_cast(sourceModel());
+ if (itemModel)
+ itemModel->update();
+}
+
+void FilteredItemModel::onAboutToBeUpdated()
+{
+ emit aboutToBeUpdated();
+}
+
+void FilteredItemModel::onUpdateComplete()
+{
+ emit updateComplete();
+}
+
+// static
+void FilteredItemModel::dumpItemModelContents(FilteredItemModel * itemModel)
+{
+ if (itemModel) {
+ qDebug() << "id:" << itemModel->getId() << "name:" << itemModel->getName();
+
+ for (int i = 0; i < itemModel->rowCount(); ++i) {
+ qDebug() << "row:" << i
+ << "text:" << itemModel->data(itemModel->index(i, 0), Qt::DisplayRole).toString()
+ << "id:" << itemModel->data(itemModel->index(i, 0), AbstractItemModel::IMDR_Id).toInt()
+ << "avail:" << itemModel->data(itemModel->index(i, 0), AbstractItemModel::IMDR_Available).toBool()
+ << "flags:" << itemModel->data(itemModel->index(i, 0), AbstractItemModel::IMDR_Flags).toInt()
+ << "type:" << itemModel->data(itemModel->index(i, 0), AbstractItemModel::IMDR_Type).toInt();
+ }
+ }
+ else
+ qDebug() << "Error: model not of class FilteredItemModel";
+}
+
+//
+// FilteredItemModelFactory
+//
+
+FilteredItemModelFactory::FilteredItemModelFactory()
+{
+}
+
+FilteredItemModelFactory::~FilteredItemModelFactory()
+{
+ unregisterItemModels();
+}
+
+int FilteredItemModelFactory::registerItemModel(FilteredItemModel * itemModel, const QString name, const int id)
+{
+ if (itemModel) {
+ if (isItemModelRegistered(name)) {
+ qDebug() << "Error: item model already registered with name:" << name;
+ return 0;
+ }
+ else if (id > -1 && isItemModelRegistered(id)) {
+ qDebug() << "Error: item model already registered with id:" << id;
+ return 0;
+ }
+ else {
+ int fid = id;
+ if (fid < 0) {
+ fid = registeredItemModels.count() + 1;
+ AbstractItemModel * mdl = qobject_cast(itemModel->sourceModel());
+ if (mdl) {
+ fid += mdl->getId() * 128;
+ }
+ }
+ itemModel->setId(fid);
+ itemModel->setName(name);
+ registeredItemModels.append(itemModel);
+ return fid;
+ }
+ }
+
+ qDebug() << "Error: invalid filtered item model pointer";
+ return 0;
+}
+
+void FilteredItemModelFactory::unregisterItemModels()
+{
+ foreach (FilteredItemModel * itemModel, registeredItemModels) {
+ delete itemModel;
+ }
+}
+
+void FilteredItemModelFactory::unregisterItemModel(const int id)
+{
+ FilteredItemModel * itemModel = getItemModel(id);
+ if (itemModel)
+ delete itemModel;
+}
+
+bool FilteredItemModelFactory::isItemModelRegistered(const int id) const
+{
+ return getItemModel(id);
+}
+
+bool FilteredItemModelFactory::isItemModelRegistered(const QString name) const
+{
+ return getItemModel(name);
+}
+
+FilteredItemModel * FilteredItemModelFactory::getItemModel(const int id) const
+{
+ foreach (FilteredItemModel * itemModel, registeredItemModels) {
+ if (itemModel->getId() == id)
+ return itemModel;
+ }
+
+ return nullptr;
+}
+
+FilteredItemModel * FilteredItemModelFactory::getItemModel(const QString name) const
+{
+ foreach (FilteredItemModel * itemModel, registeredItemModels) {
+ if (itemModel->getName() == name)
+ return itemModel;
+ }
+
+ return nullptr;
+}
+
+void FilteredItemModelFactory::update()
+{
+ foreach (FilteredItemModel * itemModel, registeredItemModels) {
+ itemModel->update();
+ }
+}
+
+void FilteredItemModelFactory::dumpItemModelContents(const int id) const
+{
+ FilteredItemModel::dumpItemModelContents(getItemModel(id));
+}
+
+void FilteredItemModelFactory::dumpItemModelContents(const QString name) const
+{
+ FilteredItemModel::dumpItemModelContents(getItemModel(name));
+}
+
+void FilteredItemModelFactory::dumpAllItemModelContents() const
+{
+ foreach (FilteredItemModel * itemModel, registeredItemModels) {
+ FilteredItemModel::dumpItemModelContents(itemModel);
+ }
+}
+
+//
+// CurveRefFilteredFactory
+//
+
+CurveRefFilteredFactory::CurveRefFilteredFactory(CompoundItemModelFactory * sharedItemModels, const int curveFlags, const int gvarRefFlags)
+{
+ if (!sharedItemModels) {
+ qDebug() << "Error: invalid compound item model factory pointer";
+ return;
+ }
+
+ registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_Curve), curveFlags),
+ fidToString(CRFIM_CURVE), CRFIM_CURVE);
+ registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_GVarRef), gvarRefFlags),
+ fidToString(CRFIM_GVARREF), CRFIM_GVARREF);
+ registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_CurveRefType)),
+ fidToString(CRFIM_TYPE), CRFIM_TYPE);
+ registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_CurveRefFunc)),
+ fidToString(CRFIM_FUNC), CRFIM_FUNC);
+}
+
+CurveRefFilteredFactory::~CurveRefFilteredFactory()
+{
+}
+
+// static
+QString CurveRefFilteredFactory::fidToString(const int value)
+{
+ switch(value) {
+ case CRFIM_CURVE:
+ return "Curves";
+ case CRFIM_GVARREF:
+ return "Global Variables";
+ case CRFIM_TYPE:
+ return "Types";
+ case CRFIM_FUNC:
+ return "Functions";
+ default:
+ return CPN_STR_UNKNOWN_ITEM;
+ }
+}
diff --git a/companion/src/datamodels/filtereditemmodels.h b/companion/src/datamodels/filtereditemmodels.h
new file mode 100644
index 000000000..24668704d
--- /dev/null
+++ b/companion/src/datamodels/filtereditemmodels.h
@@ -0,0 +1,115 @@
+/*
+ * 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 FILTEREDITEMMODELS_H
+#define FILTEREDITEMMODELS_H
+
+#include "compounditemmodels.h"
+
+#include
+#include
+#include
+
+class FilteredItemModel: public QSortFilterProxyModel
+{
+ Q_OBJECT
+ public:
+ enum DataFilters {
+ AllFilter = AbstractItemModel::IMDG_Negative | AbstractItemModel::IMDG_None | AbstractItemModel::IMDG_Positive,
+ AllExcludeNoneFilter = AllFilter &~ AbstractItemModel::IMDG_None,
+ NegativeFilter = AbstractItemModel::IMDG_Negative | AbstractItemModel::IMDG_None,
+ NegativeExcludeNoneFilter = AbstractItemModel::IMDG_Negative,
+ PositiveFilter = AbstractItemModel::IMDG_Positive | AbstractItemModel::IMDG_None,
+ PositiveExcludeNoneFilter = AbstractItemModel::IMDG_Positive
+ };
+ Q_ENUM(DataFilters)
+
+ explicit FilteredItemModel(AbstractItemModel * sourceModel, int flags);
+ explicit FilteredItemModel(AbstractItemModel * sourceModel) :
+ FilteredItemModel(sourceModel, 0) {}
+ virtual ~FilteredItemModel() {};
+
+ void setId(int id) { m_id = id; }
+ int getId() const { return m_id; };
+ void setName(QString name) { m_name = name; }
+ QString getName() const { return m_name; }
+
+ static void dumpItemModelContents(FilteredItemModel * itemModel);
+
+ public slots:
+ void setFilterFlags(int flags);
+ void update() const;
+ void onAboutToBeUpdated();
+ void onUpdateComplete();
+
+ signals:
+ void aboutToBeUpdated();
+ void updateComplete();
+
+ protected:
+ bool filterAcceptsRow(int sourceRow, const QModelIndex & sourceParent) const override;
+
+ int filterFlags;
+
+ private:
+ int m_id = 0;
+ QString m_name = "";
+};
+
+class FilteredItemModelFactory
+{
+ public:
+ explicit FilteredItemModelFactory();
+ virtual ~FilteredItemModelFactory();
+
+ int registerItemModel(FilteredItemModel * itemModel, const QString name, const int id = -1);
+ void unregisterItemModels();
+ void unregisterItemModel(const int id);
+ bool isItemModelRegistered(const int id) const;
+ bool isItemModelRegistered(const QString name) const;
+ FilteredItemModel * getItemModel(const int id) const;
+ FilteredItemModel * getItemModel(const QString name) const;
+ void update();
+
+ void dumpItemModelContents(const int id) const;
+ void dumpItemModelContents(const QString name) const;
+ void dumpAllItemModelContents() const;
+
+ protected:
+ QVector registeredItemModels;
+};
+
+class CurveRefFilteredFactory : public FilteredItemModelFactory
+{
+ public:
+ enum FilteredItemModelId {
+ CRFIM_CURVE,
+ CRFIM_GVARREF,
+ CRFIM_TYPE,
+ CRFIM_FUNC
+ };
+
+ explicit CurveRefFilteredFactory(CompoundItemModelFactory * sharedItemModels, const int curveFlags = 0, const int gvarRefFlags = 0);
+ virtual ~CurveRefFilteredFactory();
+
+ static QString fidToString(const int value);
+};
+
+#endif // FILTEREDITEMMODELS_H
diff --git a/companion/src/datamodels/rawitemdatamodels.cpp b/companion/src/datamodels/rawitemdatamodels.cpp
deleted file mode 100644
index 1cba1c180..000000000
--- a/companion/src/datamodels/rawitemdatamodels.cpp
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * 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.
- */
-
-#include "rawitemdatamodels.h"
-#include "generalsettings.h"
-#include "eeprominterface.h"
-#include "modeldata.h"
-
-RawSourceItemModel::RawSourceItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, QObject * parent) :
- AbstractRawItemDataModel(generalSettings, modelData, parent)
-{
- const Boards board = Boards(getCurrentBoard());
- Firmware * fw = getCurrentFirmware();
-
- addItems(SOURCE_TYPE_NONE, RawSource::NoneGroup, 1);
- for (int i=0; i < fw->getCapability(LuaScripts); i++)
- addItems(SOURCE_TYPE_LUA_OUTPUT, RawSource::ScriptsGroup, fw->getCapability(LuaOutputsPerScript), i * 16);
- addItems(SOURCE_TYPE_VIRTUAL_INPUT, RawSource::InputsGroup, fw->getCapability(VirtualInputs));
- addItems(SOURCE_TYPE_STICK, RawSource::SourcesGroup, board.getCapability(Board::MaxAnalogs));
- addItems(SOURCE_TYPE_ROTARY_ENCODER, RawSource::SourcesGroup, fw->getCapability(RotaryEncoders));
- addItems(SOURCE_TYPE_TRIM, RawSource::TrimsGroup, board.getCapability(Board::NumTrims));
- addItems(SOURCE_TYPE_MAX, RawSource::SourcesGroup, 1);
- addItems(SOURCE_TYPE_SWITCH, RawSource::SwitchesGroup, board.getCapability(Board::Switches));
- addItems(SOURCE_TYPE_CUSTOM_SWITCH, RawSource::SwitchesGroup, fw->getCapability(LogicalSwitches));
- addItems(SOURCE_TYPE_CYC, RawSource::SourcesGroup, CPN_MAX_CYC);
- addItems(SOURCE_TYPE_PPM, RawSource::SourcesGroup, fw->getCapability(TrainerInputs));
- addItems(SOURCE_TYPE_CH, RawSource::SourcesGroup, fw->getCapability(Outputs));
- addItems(SOURCE_TYPE_SPECIAL, RawSource::TelemGroup, 5);
- addItems(SOURCE_TYPE_TELEMETRY, RawSource::TelemGroup, CPN_MAX_SENSORS * 3);
- addItems(SOURCE_TYPE_GVAR, RawSource::GVarsGroup, fw->getCapability(Gvars));
-}
-
-void RawSourceItemModel::setDynamicItemData(QStandardItem * item, const RawSource & src) const
-{
- Board::Type board = getCurrentBoard();
- item->setText(src.toString(modelData, generalSettings, board));
- item->setData(src.isAvailable(modelData, generalSettings, board), IsAvailableRole);
-}
-
-void RawSourceItemModel::addItems(const RawSourceType & type, const int group, const int count, const int start)
-{
- for (int i = start; i < start + count; i++) {
- const RawSource src = RawSource(type, i);
- QStandardItem * modelItem = new QStandardItem();
- modelItem->setData(src.toValue(), ItemIdRole);
- modelItem->setData(type, ItemTypeRole);
- modelItem->setData(group, ItemFlagsRole);
- setDynamicItemData(modelItem, src);
- appendRow(modelItem);
- }
-}
-
-void RawSourceItemModel::update() const
-{
- for (int i=0; i < rowCount(); ++i)
- setDynamicItemData(item(i), RawSource(item(i)->data(ItemIdRole).toInt()));
-}
-
-
-//
-// RawSwitchItemModel
-//
-
-RawSwitchItemModel::RawSwitchItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, QObject * parent) :
- AbstractRawItemDataModel(generalSettings, modelData, parent)
-{
- Boards board = Boards(getCurrentBoard());
- Firmware * fw = getCurrentFirmware();
-
- // Descending switch direction: NOT (!) switches
- addItems(SWITCH_TYPE_ACT, -1);
- addItems(SWITCH_TYPE_SENSOR, -CPN_MAX_SENSORS);
- addItems(SWITCH_TYPE_TELEMETRY, -1);
- addItems(SWITCH_TYPE_FLIGHT_MODE, -fw->getCapability(FlightModes));
- addItems(SWITCH_TYPE_VIRTUAL, -fw->getCapability(LogicalSwitches));
- addItems(SWITCH_TYPE_ROTARY_ENCODER, -fw->getCapability(RotaryEncoders));
- addItems(SWITCH_TYPE_TRIM, -board.getCapability(Board::NumTrimSwitches));
- addItems(SWITCH_TYPE_MULTIPOS_POT, -(board.getCapability(Board::MultiposPots) * board.getCapability(Board::MultiposPotsPositions)));
- addItems(SWITCH_TYPE_SWITCH, -board.getCapability(Board::SwitchPositions));
-
- // Ascending switch direction (including zero)
- addItems(SWITCH_TYPE_TIMER_MODE, 5);
- addItems(SWITCH_TYPE_NONE, 1);
- addItems(SWITCH_TYPE_SWITCH, board.getCapability(Board::SwitchPositions));
- addItems(SWITCH_TYPE_MULTIPOS_POT, board.getCapability(Board::MultiposPots) * board.getCapability(Board::MultiposPotsPositions));
- addItems(SWITCH_TYPE_TRIM, board.getCapability(Board::NumTrimSwitches));
- addItems(SWITCH_TYPE_ROTARY_ENCODER, fw->getCapability(RotaryEncoders));
- addItems(SWITCH_TYPE_VIRTUAL, fw->getCapability(LogicalSwitches));
- addItems(SWITCH_TYPE_FLIGHT_MODE, fw->getCapability(FlightModes));
- addItems(SWITCH_TYPE_TELEMETRY, 1);
- addItems(SWITCH_TYPE_SENSOR, CPN_MAX_SENSORS);
- addItems(SWITCH_TYPE_ON, 1);
- addItems(SWITCH_TYPE_ONE, 1);
- addItems(SWITCH_TYPE_ACT, 1);
-}
-
-void RawSwitchItemModel::setDynamicItemData(QStandardItem * item, const RawSwitch & rsw) const
-{
- const Board::Type board = getCurrentBoard();
- item->setText(rsw.toString(board, generalSettings, modelData));
- item->setData(rsw.isAvailable(modelData, generalSettings, board), IsAvailableRole);
-}
-
-void RawSwitchItemModel::addItems(const RawSwitchType & type, int count)
-{
- // Most RawSwitch() indices are one-based (vs. typical zero); these are exceptions to the rule:
- const static QVector rawSwitchIndexBaseZeroTypes = QVector() << SWITCH_TYPE_NONE << SWITCH_TYPE_ON << SWITCH_TYPE_OFF << SWITCH_TYPE_TIMER_MODE;
- // handle exceptions in RawSwitch() index values
- const short rawIdxAdj = rawSwitchIndexBaseZeroTypes.contains(type) ? -1 : 0;
-
- // determine cotext flags
- int context = RawSwitch::AllSwitchContexts;
- switch (type) {
- case SWITCH_TYPE_FLIGHT_MODE:
- context &= ~RawSwitch::MixesContext;
- // fallthrough
- case SWITCH_TYPE_VIRTUAL:
- case SWITCH_TYPE_SENSOR:
- context &= ~RawSwitch::GlobalFunctionsContext;
- break;
-
- case SWITCH_TYPE_TIMER_MODE:
- context = RawSwitch::TimersContext;
- break;
-
- case SWITCH_TYPE_NONE:
- context &= ~RawSwitch::TimersContext;
- break;
-
- case SWITCH_TYPE_ON:
- case SWITCH_TYPE_ONE:
- context = RawSwitch::SpecialFunctionsContext | RawSwitch::GlobalFunctionsContext;
- break;
-
- default:
- break;
- }
-
- int i = (count < 0 ? count : 1);
- count = (i < 0 ? 0 : count + i);
- for ( ; i < count; ++i) {
- RawSwitch rs(type, i + rawIdxAdj);
- QStandardItem * modelItem = new QStandardItem();
- modelItem->setData(rs.toValue(), ItemIdRole);
- modelItem->setData(type, ItemTypeRole);
- modelItem->setData(context, ItemFlagsRole);
- setDynamicItemData(modelItem, rs);
- appendRow(modelItem);
- }
-}
-
-void RawSwitchItemModel::update() const
-{
- for (int i=0; i < rowCount(); ++i)
- setDynamicItemData(item(i), RawSwitch(item(i)->data(ItemIdRole).toInt()));
-}
diff --git a/companion/src/datamodels/rawitemdatamodels.h b/companion/src/datamodels/rawitemdatamodels.h
deleted file mode 100644
index 59eb6025e..000000000
--- a/companion/src/datamodels/rawitemdatamodels.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * 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 RAWITEMDATAMODELS_H
-#define RAWITEMDATAMODELS_H
-
-#include "rawsource.h"
-#include "rawswitch.h"
-
-#include
-
-class GeneralSettings;
-class ModelData;
-
-class AbstractRawItemDataModel: public QStandardItemModel
-{
- Q_OBJECT
- public:
- enum DataRoles { ItemIdRole = Qt::UserRole, ItemTypeRole, ItemFlagsRole, IsAvailableRole };
- Q_ENUM(DataRoles)
-
- explicit AbstractRawItemDataModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, QObject * parent = nullptr) :
- QStandardItemModel(parent),
- generalSettings(generalSettings),
- modelData(modelData)
- {}
-
- public slots:
- virtual void update() const = 0;
-
- protected:
- const GeneralSettings * generalSettings;
- const ModelData * modelData;
-};
-
-
-class RawSourceItemModel: public AbstractRawItemDataModel
-{
- Q_OBJECT
- public:
- explicit RawSourceItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, QObject * parent = nullptr);
-
- public slots:
- void update() const override;
-
- protected:
- void setDynamicItemData(QStandardItem * item, const RawSource & src) const;
- void addItems(const RawSourceType & type, const int group, const int count, const int start = 0);
-};
-
-
-class RawSwitchItemModel: public AbstractRawItemDataModel
-{
- Q_OBJECT
- public:
- explicit RawSwitchItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, QObject * parent = nullptr);
-
- public slots:
- void update() const override;
-
- protected:
- void setDynamicItemData(QStandardItem * item, const RawSwitch & rsw) const;
- void addItems(const RawSwitchType & type, int count);
-};
-
-
-#endif // RAWITEMDATAMODELS_H
diff --git a/companion/src/datamodels/rawitemfilteredmodel.cpp b/companion/src/datamodels/rawitemfilteredmodel.cpp
deleted file mode 100644
index 1de9e26b2..000000000
--- a/companion/src/datamodels/rawitemfilteredmodel.cpp
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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.
- */
-
-#include "rawitemfilteredmodel.h"
-#include "rawitemdatamodels.h"
-
-RawItemFilteredModel::RawItemFilteredModel(QAbstractItemModel * sourceModel, int flags, QObject * parent) :
- QSortFilterProxyModel(parent),
- filterFlags(0)
-{
- setFilterRole(AbstractRawItemDataModel::IsAvailableRole);
- setFilterKeyColumn(0);
- setFilterFlags(flags);
- setDynamicSortFilter(true);
- setSourceModel(sourceModel);
-}
-
-void RawItemFilteredModel::setFilterFlags(int flags)
-{
- if (filterFlags != flags) {
- filterFlags = flags;
- invalidateFilter();
- }
-}
-
-bool RawItemFilteredModel::filterAcceptsRow(int sourceRow, const QModelIndex & sourceParent) const
-{
- const QModelIndex & srcIdx = sourceModel()->index(sourceRow, 0, sourceParent);
- if (!srcIdx.isValid() || !sourceModel()->data(srcIdx, filterRole()).toBool())
- return false;
-
- if (!filterFlags)
- return true;
-
- bool ok;
- const int flags = sourceModel()->data(srcIdx, AbstractRawItemDataModel::ItemFlagsRole).toInt(&ok);
- return (ok && (!flags || (filterFlags & flags)));
-}
-
-void RawItemFilteredModel::update() const
-{
- AbstractRawItemDataModel * model = qobject_cast(sourceModel());
- if (model)
- model->update();
-}
-
-
-RawSourceFilterItemModel::RawSourceFilterItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, int flags, QObject * parent) :
- RawItemFilteredModel(new RawSourceItemModel(generalSettings, modelData, parent), flags, parent)
-{
-}
-
-
-RawSwitchFilterItemModel::RawSwitchFilterItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, int context, QObject * parent) :
- RawItemFilteredModel(new RawSwitchItemModel(generalSettings, modelData, parent), context, parent)
-{
-}
diff --git a/companion/src/datamodels/rawitemfilteredmodel.h b/companion/src/datamodels/rawitemfilteredmodel.h
deleted file mode 100644
index 2d95dff71..000000000
--- a/companion/src/datamodels/rawitemfilteredmodel.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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 RAWITEMFILTEREDMODEL_H
-#define RAWITEMFILTEREDMODEL_H
-
-#include
-
-class GeneralSettings;
-class ModelData;
-class RawSourceItemModel;
-class RawSwitchItemModel;
-
-class RawItemFilteredModel: public QSortFilterProxyModel
-{
- Q_OBJECT
- public:
- explicit RawItemFilteredModel(QAbstractItemModel * sourceModel, int flags, QObject * parent = nullptr);
- explicit RawItemFilteredModel(QAbstractItemModel * sourceModel, QObject * parent = nullptr) : RawItemFilteredModel(sourceModel, 0, parent) {}
-
- public slots:
- void setFilterFlags(int flags);
- void update() const;
-
- protected:
- bool filterAcceptsRow(int sourceRow, const QModelIndex & sourceParent) const override;
-
- int filterFlags;
-};
-
-
-// The specialized "convenience" types below can go away once centralalized RawSource/RawSwitch item models are established.
-// These proxy classes will automatically create a source model of the corresponding type.
-
-class RawSwitchFilterItemModel: public RawItemFilteredModel
-{
- Q_OBJECT
- public:
- using RawItemFilteredModel::RawItemFilteredModel;
-
- explicit RawSwitchFilterItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, int context, QObject * parent = nullptr);
-};
-
-
-class RawSourceFilterItemModel: public RawItemFilteredModel
-{
- Q_OBJECT
- public:
- using RawItemFilteredModel::RawItemFilteredModel;
-
- explicit RawSourceFilterItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, int flags, QObject * parent = nullptr);
-
- explicit RawSourceFilterItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, QObject * parent = nullptr) :
- RawSourceFilterItemModel(generalSettings, modelData, 0, parent) {}
-};
-
-#endif // RAWITEMFILTEREDMODEL_H
diff --git a/companion/src/dialogs/filesyncdialog.cpp b/companion/src/dialogs/filesyncdialog.cpp
index 3927a3ffd..30026c931 100644
--- a/companion/src/dialogs/filesyncdialog.cpp
+++ b/companion/src/dialogs/filesyncdialog.cpp
@@ -39,6 +39,8 @@
#include
#include
#include
+#include
+#include
FileSyncDialog::FileSyncDialog(QWidget * parent, const SyncProcess::SyncOptions & syncOptions) :
QDialog(parent),
diff --git a/companion/src/firmwares/CMakeLists.txt b/companion/src/firmwares/CMakeLists.txt
index 1b99964fa..b79d8fd42 100644
--- a/companion/src/firmwares/CMakeLists.txt
+++ b/companion/src/firmwares/CMakeLists.txt
@@ -2,27 +2,34 @@
set(firmwares_SRCS
adjustmentreference.cpp
boards.cpp
+ curvedata.cpp
curvereference.cpp
customfunctiondata.cpp
eeprominterface.cpp
generalsettings.cpp
gvardata.cpp
- io_data.cpp
+ input_data.cpp
+ flightmodedata.cpp
+ heli_data.cpp
logicalswitchdata.cpp
+ mixdata.cpp
modeldata.cpp
moduledata.cpp
multiprotocols.cpp
+ output_data.cpp
radiodata.cpp
radiodataconversionstate.cpp
rawsource.cpp
rawswitch.cpp
sensordata.cpp
telem_data.cpp
+ timerdata.cpp
afhds3.cpp
ersky9x/ersky9xeeprom.cpp
ersky9x/ersky9xinterface.cpp
opentx/opentxeeprom.cpp
opentx/opentxinterface.cpp
+ datahelpers.cpp
)
string(REPLACE ".cpp" ".h" firmwares_HDRS "${firmwares_SRCS}")
@@ -32,8 +39,14 @@ list(APPEND firmwares_HDRS
moduledata.h
)
+set(firmwares_QT
+ curvereference.h
+ )
+
+qt5_wrap_cpp(firmwares_SRCS ${firmwares_QT})
+
add_library(firmwares ${firmwares_SRCS} ${firmwares_HDRS})
-target_link_libraries(firmwares ${CPN_COMMON_LIB} Qt5::Core Qt5::Xml Qt5::Widgets)
+target_link_libraries(firmwares ${CPN_COMMON_LIB} datamodels Qt5::Core Qt5::Xml Qt5::Widgets)
target_include_directories(firmwares
PRIVATE
${CMAKE_SOURCE_DIR}
diff --git a/companion/src/firmwares/adjustmentreference.cpp b/companion/src/firmwares/adjustmentreference.cpp
index 7181e15dd..ae487effa 100644
--- a/companion/src/firmwares/adjustmentreference.cpp
+++ b/companion/src/firmwares/adjustmentreference.cpp
@@ -19,7 +19,7 @@
*/
#include "adjustmentreference.h"
-#include "radiodata.h" // for ModelData
+#include "modeldata.h"
AdjustmentReference::AdjustmentReference(int value)
{
@@ -76,3 +76,8 @@ QString AdjustmentReference::toString(const ModelData * model, const bool sign)
}
return ret;
}
+
+const bool AdjustmentReference::isAvailable() const
+{
+ return true;
+}
diff --git a/companion/src/firmwares/adjustmentreference.h b/companion/src/firmwares/adjustmentreference.h
index 2a7b7e141..9377cd5e8 100644
--- a/companion/src/firmwares/adjustmentreference.h
+++ b/companion/src/firmwares/adjustmentreference.h
@@ -45,6 +45,7 @@ class AdjustmentReference {
bool isSet() const { return type != ADJUST_REF_VALUE || value != 0; }
bool isValid(const int value) const;
QString toString(const ModelData * model = nullptr, const bool sign = false) const;
+ const bool isAvailable() const;
inline const int toValue() const
{
diff --git a/companion/src/firmwares/boards.cpp b/companion/src/firmwares/boards.cpp
index a39fe3369..a201d50ed 100644
--- a/companion/src/firmwares/boards.cpp
+++ b/companion/src/firmwares/boards.cpp
@@ -79,17 +79,21 @@ uint32_t Boards::getFourCC(Type board)
return 0x3278746F;
case BOARD_JUMPER_T12:
return 0x3D78746F;
+ case BOARD_JUMPER_TLITE:
+ return 0x4278746F;
case BOARD_JUMPER_T16:
return 0x3F78746F;
case BOARD_JUMPER_T18:
return 0x4078746F;
case BOARD_RADIOMASTER_TX16S:
return 0x3878746F;
- case BOARD_UNKNOWN:
- break;
+ case BOARD_RADIOMASTER_TX12:
+ return 0x4178746F;
+ case BOARD_RADIOMASTER_T8:
+ return 0x4378746F;
+ default:
+ return 0;
}
-
- return 0;
}
int Boards::getEEpromSize(Board::Type board)
@@ -111,6 +115,9 @@ int Boards::getEEpromSize(Board::Type board)
case BOARD_TARANIS_X9DP_2019:
case BOARD_TARANIS_X9E:
case BOARD_JUMPER_T12:
+ case BOARD_JUMPER_TLITE:
+ case BOARD_RADIOMASTER_TX12:
+ case BOARD_RADIOMASTER_T8:
return EESIZE_TARANIS;
case BOARD_UNKNOWN:
return EESIZE_MAX;
@@ -121,9 +128,9 @@ int Boards::getEEpromSize(Board::Type board)
case BOARD_JUMPER_T18:
case BOARD_RADIOMASTER_TX16S:
return 0;
+ default:
+ return 0;
}
-
- return 0;
}
int Boards::getFlashSize(Type board)
@@ -145,6 +152,9 @@ int Boards::getFlashSize(Type board)
case BOARD_TARANIS_X9DP_2019:
case BOARD_TARANIS_X9E:
case BOARD_JUMPER_T12:
+ case BOARD_JUMPER_TLITE:
+ case BOARD_RADIOMASTER_TX12:
+ case BOARD_RADIOMASTER_T8:
return FSIZE_TARANIS;
case BOARD_HORUS_X12S:
case BOARD_X10:
@@ -177,7 +187,7 @@ SwitchInfo Boards::getSwitchInfo(Board::Type board, int index)
if (index < DIM(switches))
return switches[index];
}
- else if (IS_TARANIS_XLITE(board)) {
+ else if (IS_TARANIS_XLITE(board) || IS_JUMPER_TLITE(board)) {
const Board::SwitchInfo switches[] = {
{SWITCH_3POS, "SA"},
{SWITCH_3POS, "SB"},
@@ -187,7 +197,20 @@ SwitchInfo Boards::getSwitchInfo(Board::Type board, int index)
if (index < DIM(switches))
return switches[index];
}
- else if (IS_TARANIS_X7(board)) {
+ else if (board == BOARD_TARANIS_X7_ACCESS) {
+ const Board::SwitchInfo switches[] = {
+ {SWITCH_3POS, "SA"},
+ {SWITCH_3POS, "SB"},
+ {SWITCH_3POS, "SC"},
+ {SWITCH_3POS, "SD"},
+ {SWITCH_2POS, "SF"},
+ {SWITCH_TOGGLE, "SH"},
+ {SWITCH_2POS, "SI"}
+ };
+ if (index < DIM(switches))
+ return switches[index];
+ }
+ else if (board == BOARD_TARANIS_X7) {
const Board::SwitchInfo switches[] = {
{SWITCH_3POS, "SA"},
{SWITCH_3POS, "SB"},
@@ -201,6 +224,30 @@ SwitchInfo Boards::getSwitchInfo(Board::Type board, int index)
if (index < DIM(switches))
return switches[index];
}
+ else if (IS_RADIOMASTER_TX12(board)) {
+ const Board::SwitchInfo switches[] = {
+ {SWITCH_TOGGLE, "SA"},
+ {SWITCH_3POS, "SB"},
+ {SWITCH_3POS, "SC"},
+ {SWITCH_TOGGLE, "SD"},
+ {SWITCH_3POS, "SE"},
+ {SWITCH_3POS, "SF"},
+ {SWITCH_2POS, "SI"},
+ {SWITCH_2POS, "SJ"}
+ };
+ if (index < DIM(switches))
+ return switches[index];
+ }
+ else if (IS_RADIOMASTER_T8(board)) {
+ const Board::SwitchInfo switches[] = {
+ {SWITCH_TOGGLE, "SA"},
+ {SWITCH_3POS, "SB"},
+ {SWITCH_3POS, "SC"},
+ {SWITCH_TOGGLE, "SD"}
+ };
+ if (index < DIM(switches))
+ return switches[index];
+ }
else if (IS_JUMPER_T12(board)) {
const Board::SwitchInfo switches[] = {
{SWITCH_3POS, "SA"},
@@ -213,7 +260,23 @@ SwitchInfo Boards::getSwitchInfo(Board::Type board, int index)
if (index < DIM(switches))
return switches[index];
}
- else if (IS_HORUS_OR_TARANIS(board)) {
+ else if (IS_FAMILY_HORUS_OR_T16(board)) {
+ const Board::SwitchInfo switches[] = {
+ {SWITCH_3POS, "SA"},
+ {SWITCH_3POS, "SB"},
+ {SWITCH_3POS, "SC"},
+ {SWITCH_3POS, "SD"},
+ {SWITCH_3POS, "SE"},
+ {SWITCH_2POS, "SF"},
+ {SWITCH_3POS, "SG"},
+ {SWITCH_TOGGLE, "SH"},
+ {SWITCH_2POS, "SI"},
+ {SWITCH_2POS, "SJ"}
+ };
+ if (index < DIM(switches))
+ return switches[index];
+ }
+ else if (IS_TARANIS(board)) {
const Board::SwitchInfo switches[] = {
{SWITCH_3POS, "SA"},
{SWITCH_3POS, "SB"},
@@ -263,7 +326,9 @@ int Boards::getCapability(Board::Type board, Board::Capability capability)
case Pots:
if (IS_TARANIS_X9LITE(board))
return 1;
- else if (IS_TARANIS_SMALL(board) || IS_JUMPER_T12(board))
+ else if (IS_JUMPER_TLITE(board))
+ return 0;
+ else if (IS_TARANIS_SMALL(board))
return 2;
else if (IS_TARANIS_X9E(board))
return 4;
@@ -289,7 +354,7 @@ int Boards::getCapability(Board::Type board, Board::Capability capability)
return 0;
case MouseAnalogs:
- if (IS_FAMILY_HORUS_OR_T16(board))
+ if (IS_HORUS_X12S(board))
return 2;
else
return 0;
@@ -316,10 +381,14 @@ int Boards::getCapability(Board::Type board, Board::Capability capability)
return 5;
else if (board == Board::BOARD_TARANIS_X9LITES)
return 7;
- else if (IS_TARANIS_X7(board))
+ else if (board == BOARD_TARANIS_X7_ACCESS)
+ return 7;
+ else if (board == BOARD_TARANIS_X7)
+ return 8;
+ else if (board == BOARD_JUMPER_TLITE)
+ return 4;
+ else if (IS_FAMILY_T12(board))
return 8;
- else if (IS_JUMPER_T12(board))
- return 6;
else if (IS_TARANIS_XLITE(board))
return 6;
else if (board == Board::BOARD_TARANIS_X9DP_2019)
@@ -334,7 +403,11 @@ int Boards::getCapability(Board::Type board, Board::Capability capability)
case FactoryInstalledSwitches:
if (IS_TARANIS_X9E(board))
return 8;
- if (IS_HORUS_X12S(board))
+ else if (IS_JUMPER_TLITE(board))
+ return 4;
+ else if (IS_FAMILY_T12(board))
+ return 6;
+ else if (IS_HORUS_X12S(board))
return 8;
else
return getCapability(board, Switches);
@@ -479,8 +552,6 @@ QString Boards::getBoardName(Board::Type board)
return "Taranis X7/X7S";
case BOARD_TARANIS_X7_ACCESS:
return "Taranis X7/X7S Access";
- case BOARD_JUMPER_T12:
- return "Jumper T12";
case BOARD_TARANIS_XLITE:
return "Taranis X-Lite";
case BOARD_TARANIS_XLITES:
@@ -509,12 +580,20 @@ QString Boards::getBoardName(Board::Type board)
return "Horus X10/X10S";
case BOARD_X10_EXPRESS:
return "Horus X10/X10S Express";
+ case BOARD_JUMPER_T12:
+ return "Jumper T12";
+ case BOARD_JUMPER_TLITE:
+ return "Jumper T-Lite";
case BOARD_JUMPER_T16:
return "Jumper T16";
case BOARD_JUMPER_T18:
return "Jumper T18";
case BOARD_RADIOMASTER_TX16S:
return "Radiomaster TX16S";
+ case BOARD_RADIOMASTER_TX12:
+ return "Radiomaster TX12";
+ case BOARD_RADIOMASTER_T8:
+ return "Radiomaster T8";
default:
return tr("Unknown");
}
diff --git a/companion/src/firmwares/boards.h b/companion/src/firmwares/boards.h
index 2ecf3c2fe..e55aeae37 100644
--- a/companion/src/firmwares/boards.h
+++ b/companion/src/firmwares/boards.h
@@ -52,10 +52,13 @@ namespace Board {
BOARD_JUMPER_T16,
BOARD_RADIOMASTER_TX16S,
BOARD_JUMPER_T18,
+ BOARD_RADIOMASTER_TX12,
+ BOARD_RADIOMASTER_T8,
+ BOARD_JUMPER_TLITE,
+ BOARD_TYPE_COUNT,
+ BOARD_TYPE_MAX = BOARD_TYPE_COUNT - 1
};
- constexpr int BOARD_TYPE_MAX = BOARD_JUMPER_T18;
-
enum PotType
{
POT_NONE,
@@ -203,6 +206,11 @@ inline bool IS_JUMPER_T12(Board::Type board)
return board == Board::BOARD_JUMPER_T12;
}
+inline bool IS_JUMPER_TLITE(Board::Type board)
+{
+ return board == Board::BOARD_JUMPER_TLITE;
+}
+
inline bool IS_JUMPER_T16(Board::Type board)
{
return board == Board::BOARD_JUMPER_T16;
@@ -218,11 +226,26 @@ inline bool IS_RADIOMASTER_TX16S(Board::Type board)
return board == Board::BOARD_RADIOMASTER_TX16S;
}
+inline bool IS_RADIOMASTER_TX12(Board::Type board)
+{
+ return board == Board::BOARD_RADIOMASTER_TX12;
+}
+
+inline bool IS_RADIOMASTER_T8(Board::Type board)
+{
+ return board == Board::BOARD_RADIOMASTER_T8;
+}
+
inline bool IS_FAMILY_T16(Board::Type board)
{
return board == Board::BOARD_JUMPER_T16 || board == Board::BOARD_RADIOMASTER_TX16S || board == Board::BOARD_JUMPER_T18;
}
+inline bool IS_FAMILY_T12(Board::Type board)
+{
+ return board == Board::BOARD_JUMPER_T12 || board == Board::BOARD_RADIOMASTER_TX12 || board == Board::BOARD_RADIOMASTER_T8 || board == Board::BOARD_JUMPER_TLITE;
+}
+
inline bool IS_TARANIS_XLITE(Board::Type board)
{
return board == Board::BOARD_TARANIS_XLITE || board == Board::BOARD_TARANIS_XLITES;
@@ -273,14 +296,14 @@ inline bool IS_TARANIS_X9E(Board::Type board)
return board == Board::BOARD_TARANIS_X9E;
}
-inline bool IS_TARANIS(Board::Type board)
-{
- return IS_TARANIS_X9(board) || IS_TARANIS_X7(board) || IS_TARANIS_X9LITE(board) || IS_TARANIS_XLITE(board) || IS_JUMPER_T12(board);
-}
-
inline bool IS_TARANIS_SMALL(Board::Type board)
{
- return IS_TARANIS_X7(board) || IS_TARANIS_XLITE(board) || IS_TARANIS_X9LITE(board) || IS_JUMPER_T12(board);
+ return IS_TARANIS_X7(board) || IS_TARANIS_XLITE(board) || IS_TARANIS_X9LITE(board) || IS_FAMILY_T12(board);
+}
+
+inline bool IS_TARANIS(Board::Type board)
+{
+ return IS_TARANIS_X9(board) || IS_TARANIS_SMALL(board);
}
inline bool IS_HORUS_X10(Board::Type board)
diff --git a/companion/src/firmwares/curvedata.cpp b/companion/src/firmwares/curvedata.cpp
new file mode 100644
index 000000000..c32eac4cc
--- /dev/null
+++ b/companion/src/firmwares/curvedata.cpp
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+#include "curvedata.h"
+#include "radiodata.h"
+
+CurveData::CurveData()
+{
+ clear();
+}
+
+void CurveData::clear(int count)
+{
+ memset(reinterpret_cast(this), 0, sizeof(CurveData));
+ this->count = count;
+}
+
+bool CurveData::isEmpty() const
+{
+ for (int i = 0; i < count; i++) {
+ if (points[i].y != 0) {
+ return false;
+ }
+ }
+ return true;
+}
+
+QString CurveData::nameToString(const int idx) const
+{
+ return RadioData::getElementName(tr("CV"), idx + 1, name);
+}
diff --git a/companion/src/firmwares/curvedata.h b/companion/src/firmwares/curvedata.h
new file mode 100644
index 000000000..cb083375e
--- /dev/null
+++ b/companion/src/firmwares/curvedata.h
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "constants.h"
+
+#include
+
+class CurvePoint {
+ public:
+ int8_t x;
+ int8_t y;
+};
+
+#define CURVEDATA_NAME_LEN 6
+
+class CurveData {
+ Q_DECLARE_TR_FUNCTIONS(CurveData)
+
+ public:
+ enum CurveType {
+ CURVE_TYPE_STANDARD,
+ CURVE_TYPE_CUSTOM,
+ CURVE_TYPE_LAST = CURVE_TYPE_CUSTOM
+ };
+
+ CurveData();
+
+ CurveType type;
+ bool smooth;
+ int count;
+ CurvePoint points[CPN_MAX_POINTS];
+ char name[CURVEDATA_NAME_LEN + 1];
+
+ void clear(int count = 5);
+ bool isEmpty() const;
+ QString nameToString(const int idx) const;
+};
diff --git a/companion/src/firmwares/curvereference.cpp b/companion/src/firmwares/curvereference.cpp
index 578d7e72b..926c2d2ae 100644
--- a/companion/src/firmwares/curvereference.cpp
+++ b/companion/src/firmwares/curvereference.cpp
@@ -19,45 +19,269 @@
*/
#include "curvereference.h"
+#include "adjustmentreference.h"
+#include "helpers.h"
+#include "modeldata.h"
+#include "filtereditemmodels.h"
-#include "helpers.h" // for Helpers::getAdjustmentString()
-#include "radiodata.h" // for ModelData
-
-QString CurveReference::toString(const ModelData * model, bool verbose) const
+const QString CurveReference::toString(const ModelData * model, bool verbose) const
{
- if (value == 0) {
- return "----";
- }
+ if (value == 0)
+ return CPN_STR_NONE_ITEM;
QString ret;
unsigned idx = abs(value) - 1;
switch(type) {
case CURVE_REF_DIFF:
- ret = tr("Diff(%1)").arg(Helpers::getAdjustmentString(value, model));
- break;
-
case CURVE_REF_EXPO:
- ret = tr("Expo(%1)").arg(Helpers::getAdjustmentString(value, model));
+ ret = AdjustmentReference(value).toString(model);
break;
-
case CURVE_REF_FUNC:
- ret = QString("x>0" "x<0" "|x|" "f>0" "f<0" "|f|").mid(3*(value-1), 3);
- if (verbose)
- ret = tr("Function(%1)").arg(ret);
+ ret = functionToString(value);
break;
-
- default:
+ case CURVE_REF_CUSTOM:
if (model)
ret = model->curves[idx].nameToString(idx);
else
ret = CurveData().nameToString(idx);
- if (verbose)
- ret = tr("Curve(%1)").arg(ret);
if (value < 0)
ret.prepend(CPN_STR_SW_INDICATOR_REV);
break;
+ default:
+ return CPN_STR_UNKNOWN_ITEM;
+ }
+
+ if (verbose)
+ ret = tr(qPrintable(QString(typeToString(type) + "(%1)").arg(ret)));
+
+ return ret;
+}
+
+const bool CurveReference::isValueNumber() const
+{
+ return (type == CURVE_REF_DIFF || type == CURVE_REF_EXPO) && AdjustmentReference(value).type == AdjustmentReference::ADJUST_REF_VALUE;
+}
+
+const bool CurveReference::isAvailable() const
+{
+ return true;
+}
+
+// static
+int CurveReference::getDefaultValue(const CurveRefType type, const bool isGVar)
+{
+ if (isGVar && (type == CURVE_REF_DIFF || type == CURVE_REF_EXPO))
+ return AdjustmentReference(AdjustmentReference::ADJUST_REF_GVAR, 1).toValue();
+ else if (type == CURVE_REF_FUNC)
+ return 1;
+ else
+ return 0;
+}
+
+// static
+QString CurveReference::typeToString(const CurveRefType type)
+{
+ const QStringList strl = { tr("Diff"), tr("Expo") , tr("Func"), tr("Curve") };
+ int idx = (int)type;
+
+ if (idx < 0 || idx >= strl.count())
+ return CPN_STR_UNKNOWN_ITEM;
+
+ return strl.at(idx);
+}
+
+// static
+QString CurveReference::functionToString(const int value)
+{
+ const QStringList strl = { "x>0", "x<0", "|x|", "f>0", "f<0", "|f|" };
+ int idx = value - 1;
+
+ if (idx < 0 || idx >= strl.count())
+ return CPN_STR_UNKNOWN_ITEM;
+
+ return strl.at(idx);
+}
+
+// static
+bool CurveReference::isTypeAvailable(const CurveRefType type)
+{
+ bool ret = false;
+ Firmware * fw = getCurrentFirmware();
+
+ switch(type) {
+ case CURVE_REF_DIFF:
+ if (fw->getCapability(HasInputDiff))
+ ret = true;
+ break;
+ case CURVE_REF_EXPO:
+ if (fw->getCapability(HasMixerExpo))
+ ret = true;
+ break;
+ case CURVE_REF_FUNC:
+ case CURVE_REF_CUSTOM:
+ ret = true;
+ break;
}
return ret;
}
+
+// static
+bool CurveReference::isFunctionAvailable(const int value)
+{
+ return true;
+}
+
+// static
+int CurveReference::functionCount()
+{
+ return 6;
+}
+
+
+/*
+ * CurveReferenceUIManager
+*/
+
+CurveReferenceUIManager::CurveReferenceUIManager(QComboBox * curveTypeCB, QCheckBox * curveGVarCB, QSpinBox * curveValueSB,
+ QComboBox * curveValueCB, CurveReference & curveRef, const ModelData & model,
+ CurveRefFilteredFactory * curveRefFilteredFactory, QObject * parent) :
+ QObject(parent),
+ curveTypeCB(curveTypeCB),
+ curveGVarCB(curveGVarCB),
+ curveValueSB(curveValueSB),
+ curveValueCB(curveValueCB),
+ curveRef(curveRef),
+ model(model),
+ lock(false),
+ filteredModelFactory(curveRefFilteredFactory)
+{
+ hasCapabilityGvars = getCurrentFirmware()->getCapability(Gvars);
+
+ if (curveTypeCB) {
+ curveTypeCB->setModel(filteredModelFactory->getItemModel(CurveRefFilteredFactory::CRFIM_TYPE));
+ curveTypeCB->setCurrentIndex(curveTypeCB->findData((int)curveRef.type));
+ connect(curveTypeCB, SIGNAL(currentIndexChanged(int)), this, SLOT(typeChanged(int)));
+ }
+
+ if (curveGVarCB)
+ connect(curveGVarCB, SIGNAL(stateChanged(int)), this, SLOT(gvarCBChanged(int)));
+
+ if (curveValueSB) {
+ curveValueSB->setMinimum(-100);
+ curveValueSB->setMaximum(100);
+ connect(curveValueSB, SIGNAL(editingFinished()), this, SLOT(valueSBChanged()));
+ }
+
+ if (curveValueCB) {
+ curveValueCB->setSizeAdjustPolicy(QComboBox::AdjustToContents);
+ curveValueCB->setMaxVisibleItems(10);
+ connect(curveValueCB, SIGNAL(currentIndexChanged(int)), this, SLOT(valueCBChanged()));
+ }
+
+ update();
+}
+
+CurveReferenceUIManager::~CurveReferenceUIManager()
+{
+ delete filteredModelFactory;
+}
+
+#define CURVE_REF_UI_GVAR_SHOW (1<<0)
+#define CURVE_REF_UI_VALUE_SHOW (1<<1)
+#define CURVE_REF_UI_REF_SHOW (1<<2)
+
+void CurveReferenceUIManager::update()
+{
+ lock = true;
+ int widgetsMask = 0;
+
+ if (curveRef.type == CurveReference::CURVE_REF_DIFF || curveRef.type == CurveReference::CURVE_REF_EXPO) {
+ if (hasCapabilityGvars)
+ widgetsMask |= CURVE_REF_UI_GVAR_SHOW;
+ if (curveRef.isValueNumber()) {
+ curveGVarCB->setChecked(false);
+ curveValueSB->setValue(curveRef.value);
+ widgetsMask |= CURVE_REF_UI_VALUE_SHOW;
+ }
+ else {
+ curveGVarCB->setChecked(true);
+ widgetsMask |= CURVE_REF_UI_REF_SHOW;
+ }
+ }
+ else {
+ widgetsMask |= CURVE_REF_UI_REF_SHOW;
+ }
+
+ if(curveTypeCB) {
+ curveTypeCB->setCurrentIndex(curveTypeCB->findData(curveRef.type));
+ curveTypeCB->show();
+ }
+ if(curveGVarCB)
+ curveGVarCB->setVisible(widgetsMask & CURVE_REF_UI_GVAR_SHOW);
+ if(curveValueSB)
+ curveValueSB->setVisible(widgetsMask & CURVE_REF_UI_VALUE_SHOW);
+ if(curveValueCB) {
+ if (curveRef.isValueReference())
+ populateValueCB(curveValueCB);
+ curveValueCB->setVisible(widgetsMask & CURVE_REF_UI_REF_SHOW);
+ }
+
+ lock = false;
+}
+
+void CurveReferenceUIManager::gvarCBChanged(int state)
+{
+ if (!lock) {
+ curveRef.value = CurveReference::getDefaultValue(curveRef.type, state);
+ update();
+ }
+}
+
+void CurveReferenceUIManager::typeChanged(int value)
+{
+ if (!lock) {
+ CurveReference::CurveRefType type = (CurveReference::CurveRefType)curveTypeCB->itemData(curveTypeCB->currentIndex()).toInt();
+ curveRef = CurveReference(type, CurveReference::getDefaultValue(type));
+ update();
+ }
+}
+
+void CurveReferenceUIManager::valueSBChanged()
+{
+ if (!lock) {
+ curveRef.value = curveValueSB->value();
+ update();
+ }
+}
+
+void CurveReferenceUIManager::valueCBChanged()
+{
+ if (!lock) {
+ curveRef.value = curveValueCB->itemData(curveValueCB->currentIndex()).toInt();
+ update();
+ }
+}
+
+void CurveReferenceUIManager::populateValueCB(QComboBox * cb)
+{
+ if (cb) {
+ switch (curveRef.type) {
+ case CurveReference::CURVE_REF_DIFF:
+ case CurveReference::CURVE_REF_EXPO:
+ cb->setModel(filteredModelFactory->getItemModel(CurveRefFilteredFactory::CRFIM_GVARREF));
+ break;
+ case CurveReference::CURVE_REF_FUNC:
+ cb->setModel(filteredModelFactory->getItemModel(CurveRefFilteredFactory::CRFIM_FUNC));
+ break;
+ case CurveReference::CURVE_REF_CUSTOM:
+ cb->setModel(filteredModelFactory->getItemModel(CurveRefFilteredFactory::CRFIM_CURVE));
+ break;
+ default:
+ break;
+ }
+
+ cb->setCurrentIndex(cb->findData(curveRef.value));
+ }
+}
diff --git a/companion/src/firmwares/curvereference.h b/companion/src/firmwares/curvereference.h
index cb5be4e73..c4482c742 100644
--- a/companion/src/firmwares/curvereference.h
+++ b/companion/src/firmwares/curvereference.h
@@ -22,35 +22,101 @@
#define CURVEREFERENCE_H
#include
+#include
+#include
+#include
+#include
+
class ModelData;
+class CurveRefFilteredFactory;
class CurveReference {
+
Q_DECLARE_TR_FUNCTIONS(CurveReference)
public:
+
enum CurveRefType {
CURVE_REF_DIFF,
CURVE_REF_EXPO,
CURVE_REF_FUNC,
- CURVE_REF_CUSTOM
+ CURVE_REF_CUSTOM,
+ MAX_CURVE_REF_TYPE = CURVE_REF_CUSTOM
+ };
+
+ enum CurveRefGroups {
+ NoneGroup = 0x001,
+ NegativeGroup = 0x002,
+ PositiveGroup = 0x004,
+
+ AllCurveRefGroups = NoneGroup | NegativeGroup | PositiveGroup,
+ PositiveCurveRefGroups = AllCurveRefGroups &~ NegativeGroup
};
CurveReference() { clear(); }
-
- CurveReference(CurveRefType type, int value):
- type(type),
- value(value)
- {
- }
+ CurveReference(CurveRefType type, int value) : type(type), value(value) { ; }
void clear() { memset(this, 0, sizeof(CurveReference)); }
+ const bool isEmpty() const { return type == CURVE_REF_DIFF && value == 0; }
+ const bool isSet() const { return !isEmpty(); }
+ const bool isValueNumber() const;
+ const bool isValueReference() const { return !isValueNumber(); }
+ const QString toString(const ModelData * model = nullptr, bool verbose = true) const;
+ const bool isAvailable() const;
CurveRefType type;
int value;
- QString toString(const ModelData * model = NULL, bool verbose = true) const;
- bool isSet() const { return type != CURVE_REF_DIFF || value != 0; }
+ bool operator == ( const CurveReference & other) const {
+ return (this->type == other.type) && (this->value == other.value);
+ }
+
+ bool operator != ( const CurveReference & other) const {
+ return (this->type != other.type) || (this->value != other.value);
+ }
+
+ static int getDefaultValue(const CurveRefType type, const bool isGVar = false);
+ static QString typeToString(const CurveRefType type);
+ static QString functionToString(const int value);
+ static bool isTypeAvailable(const CurveRefType type);
+ static bool isFunctionAvailable(const int value);
+ static int functionCount();
+};
+
+class CurveReferenceUIManager : public QObject {
+
+ Q_OBJECT
+
+ public:
+ explicit CurveReferenceUIManager(QComboBox *curveTypeCB, QCheckBox *curveGVarCB, QSpinBox *curveValueSB, QComboBox *curveValueCB,
+ CurveReference & curve, const ModelData & model, CurveRefFilteredFactory * curveRefFilteredFactory,
+ QObject * parent = nullptr);
+
+ explicit CurveReferenceUIManager(QComboBox *curveValueCB, CurveReference & curve, const ModelData & model,
+ CurveRefFilteredFactory * curveRefFilteredFactory, QObject * parent = nullptr) :
+ CurveReferenceUIManager(nullptr, nullptr, nullptr, curveValueCB, curve, model, curveRefFilteredFactory, parent) {}
+
+ virtual ~CurveReferenceUIManager();
+
+ protected slots:
+ void gvarCBChanged(int);
+ void typeChanged(int);
+ void valueSBChanged();
+ void valueCBChanged();
+ void update();
+
+ private:
+ QComboBox *curveTypeCB;
+ QCheckBox *curveGVarCB;
+ QSpinBox *curveValueSB;
+ QComboBox *curveValueCB;
+ CurveReference & curveRef;
+ const ModelData & model;
+ bool lock;
+ bool hasCapabilityGvars;
+ CurveRefFilteredFactory *filteredModelFactory;
+ void populateValueCB(QComboBox * cb);
};
#endif // CURVEREFERENCE_H
diff --git a/companion/src/firmwares/customfunctiondata.cpp b/companion/src/firmwares/customfunctiondata.cpp
index 3248f1fa4..98157cae2 100644
--- a/companion/src/firmwares/customfunctiondata.cpp
+++ b/companion/src/firmwares/customfunctiondata.cpp
@@ -22,6 +22,17 @@
#include "eeprominterface.h"
#include "radiodata.h"
#include "radiodataconversionstate.h"
+#include "compounditemmodels.h"
+
+void CustomFunctionData::convert(RadioDataConversionState & cstate)
+{
+ cstate.setComponent(tr("CFN"), 8);
+ cstate.setSubComp(nameToString(cstate.subCompIdx, (cstate.toModel() ? false : true)));
+ swtch.convert(cstate);
+ if (func == FuncVolume || func == FuncBacklight || func == FuncPlayValue || (func >= FuncAdjustGV1 && func <= FuncAdjustGVLast && adjustMode == 1)) {
+ param = RawSource(param).convert(cstate.withComponentField("PARAM")).toValue();
+ }
+}
void CustomFunctionData::clear()
{
@@ -36,17 +47,24 @@ bool CustomFunctionData::isEmpty() const
return (swtch.type == SWITCH_TYPE_NONE);
}
-QString CustomFunctionData::nameToString(int index, bool globalContext) const
+// static
+QString CustomFunctionData::nameToString(const int index, const bool globalContext)
{
- return RadioData::getElementName((globalContext ? tr("GF") : tr("SF")), index+1, 0, true);
+ return RadioData::getElementName((globalContext ? tr("GF") : tr("SF")), index + 1, 0, true);
}
QString CustomFunctionData::funcToString(const ModelData * model) const
{
- if (func >= FuncOverrideCH1 && func <= FuncOverrideCH32)
+ return funcToString(func, model);
+}
+
+// static
+QString CustomFunctionData::funcToString(const AssignFunc func, const ModelData * model)
+{
+ if (func >= FuncOverrideCH1 && func <= FuncOverrideCHLast)
return tr("Override %1").arg(RawSource(SOURCE_TYPE_CH, func).toString(model));
else if (func == FuncTrainer)
- return tr("Trainer");
+ return tr("Trainer Sticks");
else if (func == FuncTrainerRUD)
return tr("Trainer RUD");
else if (func == FuncTrainerELE)
@@ -65,8 +83,8 @@ QString CustomFunctionData::funcToString(const ModelData * model) const
return tr("Haptic");
else if (func == FuncReset)
return tr("Reset");
- else if (func >= FuncSetTimer1 && func <= FuncSetTimer3)
- return tr("Set Timer %1").arg(func-FuncSetTimer1+1);
+ else if (func >= FuncSetTimer1 && func <= FuncSetTimerLast)
+ return tr("Set %1").arg(RawSource(SOURCE_TYPE_SPECIAL, SOURCE_TYPE_SPECIAL_TIMER1_IDX + func - FuncSetTimer1).toString(model));
else if (func == FuncVario)
return tr("Vario");
else if (func == FuncPlayPrompt)
@@ -76,7 +94,7 @@ QString CustomFunctionData::funcToString(const ModelData * model) const
else if (func == FuncPlayValue)
return tr("Play Value");
else if (func == FuncPlayScript)
- return tr("Play Script");
+ return tr("Lua Script");
else if (func == FuncLogs)
return tr("SD Logs");
else if (func == FuncVolume)
@@ -90,106 +108,44 @@ QString CustomFunctionData::funcToString(const ModelData * model) const
else if (func == FuncBackgroundMusicPause)
return tr("Background Music Pause");
else if (func >= FuncAdjustGV1 && func <= FuncAdjustGVLast)
- return tr("Adjust %1").arg(RawSource(SOURCE_TYPE_GVAR, func-FuncAdjustGV1).toString(model));
- else if (func == FuncSetFailsafeInternalModule)
- return tr("SetFailsafe Int. Module");
- else if (func == FuncSetFailsafeExternalModule)
- return tr("SetFailsafe Ext. Module");
+ return tr("Adjust %1").arg(RawSource(SOURCE_TYPE_GVAR, func - FuncAdjustGV1).toString(model));
+ else if (func == FuncSetFailsafe)
+ return tr("Set Failsafe");
else if (func == FuncRangeCheckInternalModule)
- return tr("RangeCheck Int. Module");
+ return tr("Range Check Int. Module");
else if (func == FuncRangeCheckExternalModule)
- return tr("RangeCheck Ext. Module");
+ return tr("Range Check Ext. Module");
else if (func == FuncBindInternalModule)
return tr("Bind Int. Module");
else if (func == FuncBindExternalModule)
return tr("Bind Ext. Module");
else {
- return QString("???"); // Highlight unknown functions with output of question marks.(BTW should not happen that we do not know what a function is)
+ return QString(CPN_STR_UNKNOWN_ITEM);
}
}
-void CustomFunctionData::populateResetParams(const ModelData * model, QComboBox * b, unsigned int value = 0)
-{
- int val = 0;
- Firmware * firmware = Firmware::getCurrentVariant();
-
- b->addItem(tr("Timer1"), val++);
- b->addItem(tr("Timer2"), val++);
- b->addItem( tr("Timer3"), val++);
- b->addItem(tr("Flight"), val++);
- b->addItem(tr("Telemetry"), val++);
- int reCount = firmware->getCapability(RotaryEncoders);
- if (reCount == 1) {
- b->addItem(tr("Rotary Encoder"), val++);
- }
- else if (reCount == 2) {
- b->addItem(tr("REa"), val++);
- b->addItem(tr("REb"), val++);
- }
- if ((int)value < b->count()) {
- b->setCurrentIndex(value);
- }
- if (model) {
- for (unsigned i=0; isensorData[i].isAvailable()) {
- RawSource item = RawSource(SOURCE_TYPE_TELEMETRY, 3*i);
- b->addItem(item.toString(model), val+i);
- if (value == val+i) {
- b->setCurrentIndex(b->count()-1);
- }
- }
- }
- }
-}
-
-void CustomFunctionData::populatePlaySoundParams(QStringList & qs)
-{
- qs <<"Beep 1" << "Beep 2" << "Beep 3" << "Warn1" << "Warn2" << "Cheep" << "Ratata" << "Tick" << "Siren" << "Ring" ;
- qs << "SciFi" << "Robot" << "Chirp" << "Tada" << "Crickt" << "AlmClk" ;
-}
-
-void CustomFunctionData::populateHapticParams(QStringList & qs)
-{
- qs << "0" << "1" << "2" << "3";
-}
-
QString CustomFunctionData::paramToString(const ModelData * model) const
{
QStringList qs;
if (func <= FuncInstantTrim) {
return QString("%1").arg(param);
}
- else if (func==FuncLogs) {
- return QString("%1").arg(param/10.0) + tr("s");
+ else if (func == FuncLogs) {
+ return QString("%1").arg(param / 10.0) + tr("s");
}
- else if (func==FuncPlaySound) {
- CustomFunctionData::populatePlaySoundParams(qs);
- if (param>=0 && param<(int)qs.count())
- return qs.at(param);
- else
- return tr("Inconsistent parameter");
+ else if (func == FuncPlaySound) {
+ return playSoundToString(param);
}
- else if (func==FuncPlayHaptic) {
- CustomFunctionData::populateHapticParams(qs);
- if (param>=0 && param<(int)qs.count())
- return qs.at(param);
- else
- return tr("Inconsistent parameter");
+ else if (func == FuncPlayHaptic) {
+ return harpicToString(param);
}
- else if (func==FuncReset) {
- QComboBox cb;
- CustomFunctionData::populateResetParams(model, &cb);
- int pos = cb.findData(param);
- if (pos >= 0)
- return cb.itemText(pos);
- else
- return tr("Inconsistent parameter");
+ else if (func == FuncReset) {
+ return resetToString(param, model);
}
- else if ((func==FuncVolume)|| (func==FuncPlayValue)) {
- RawSource item(param);
- return item.toString(model);
+ else if (func == FuncVolume || func == FuncPlayValue || func == FuncBacklight) {
+ return RawSource(param).toString(model);
}
- else if ((func==FuncPlayPrompt) || (func==FuncPlayBoth)) {
+ else if (func == FuncPlayPrompt || func == FuncPlayBoth) {
if ( getCurrentFirmware()->getCapability(VoicesAsNumbers)) {
return QString("%1").arg(param);
}
@@ -197,19 +153,17 @@ QString CustomFunctionData::paramToString(const ModelData * model) const
return paramarm;
}
}
- else if ((func>=FuncAdjustGV1) && (func= FuncAdjustGV1 && func < FuncCount) {
switch (adjustMode) {
case FUNC_ADJUST_GVAR_CONSTANT:
- return tr("Value ")+QString("%1").arg(param);
+ return gvarAdjustModeToString(adjustMode) + QString(" %1").arg(param);
case FUNC_ADJUST_GVAR_SOURCE:
case FUNC_ADJUST_GVAR_GVAR:
return RawSource(param).toString();
case FUNC_ADJUST_GVAR_INCDEC:
- float val;
- QString unit;
- val = param * model->gvarData[func - FuncAdjustGV1].multiplierGet();
- unit = model->gvarData[func - FuncAdjustGV1].unitToString();
- return QString("Increment: %1%2").arg(val).arg(unit);
+ const float val = param * model->gvarData[func - FuncAdjustGV1].multiplierGet();
+ const QString unit = model->gvarData[func - FuncAdjustGV1].unitToString();
+ return gvarAdjustModeToString(adjustMode) + QString(": %1%2").arg(val).arg(unit);
}
}
return "";
@@ -217,25 +171,31 @@ QString CustomFunctionData::paramToString(const ModelData * model) const
QString CustomFunctionData::repeatToString() const
{
- if (repeatParam == -1) {
- return tr("played once, not during startup");
+ return repeatToString(repeatParam);
+}
+
+// static
+QString CustomFunctionData::repeatToString(const int value)
+{
+ if (value == -1) {
+ return tr("Played once, not during startup");
}
- else if (repeatParam == 0) {
- return "";
+ else if (value == 0) {
+ return tr("No repeat");
}
else {
- unsigned int step = 1;
- return tr("repeat(%1s)").arg(step*repeatParam);
+ return tr("Repeat %1s").arg(value);
}
}
QString CustomFunctionData::enabledToString() const
{
- if ((func>=FuncOverrideCH1 && func<=FuncOverrideCH32) ||
- (func>=FuncAdjustGV1 && func<=FuncAdjustGVLast) ||
- (func==FuncReset) ||
- (func>=FuncSetTimer1 && func<=FuncSetTimer2) ||
- (func==FuncVolume) ||
+ if ((func >= FuncOverrideCH1 && func <= FuncOverrideCHLast) ||
+ (func >= FuncAdjustGV1 && func <= FuncAdjustGVLast) ||
+ (func == FuncReset) ||
+ (func >= FuncSetTimer1 && func <= FuncSetTimerLast) ||
+ (func == FuncVolume) ||
+ (func == FuncBacklight) ||
(func <= FuncInstantTrim)) {
if (!enabled) {
return tr("DISABLED");
@@ -244,12 +204,197 @@ QString CustomFunctionData::enabledToString() const
return "";
}
-void CustomFunctionData::convert(RadioDataConversionState & cstate)
+// static
+bool CustomFunctionData::isFuncAvailable(const int index)
{
- cstate.setComponent(tr("CFN"), 8);
- cstate.setSubComp(nameToString(cstate.subCompIdx, (cstate.toModel() ? false : true)));
- swtch.convert(cstate);
- if (func == FuncVolume || func == FuncPlayValue || (func >= FuncAdjustGV1 && func <= FuncAdjustGVLast && adjustMode == 1)) {
- param = RawSource(param).convert(cstate.withComponentField("PARAM")).toValue();
+ Firmware * fw = getCurrentFirmware();
+
+ bool ret = (((index >= FuncOverrideCH1 && index <= FuncOverrideCHLast) && !fw->getCapability(SafetyChannelCustomFunction)) ||
+ ((index == FuncVolume || index == FuncBackgroundMusic || index == FuncBackgroundMusicPause) && !fw->getCapability(HasVolume)) ||
+ ((index == FuncPlayScript && !IS_HORUS_OR_TARANIS(fw->getBoard()))) ||
+ ((index == FuncPlayHaptic) && !fw->getCapability(Haptic)) ||
+ ((index == FuncPlayBoth) && !fw->getCapability(HasBeeper)) ||
+ ((index == FuncLogs) && !fw->getCapability(HasSDLogs)) ||
+ ((index >= FuncSetTimer1 && index <= FuncSetTimerLast) && index > FuncSetTimer1 + fw->getCapability(Timers)) ||
+ ((index == FuncScreenshot) && !IS_HORUS_OR_TARANIS(fw->getBoard())) ||
+ ((index >= FuncRangeCheckInternalModule && index <= FuncBindExternalModule) && !fw->getCapability(DangerousFunctions)) ||
+ ((index >= FuncAdjustGV1 && index <= FuncAdjustGVLast) && !fw->getCapability(Gvars))
+ );
+ return !ret;
+}
+
+// static
+int CustomFunctionData::funcContext(const int index)
+{
+ int ret = AllFunctionContexts;
+
+ if ((index >= FuncOverrideCH1 && index <= FuncOverrideCHLast) ||
+ (index >= FuncRangeCheckInternalModule && index <= FuncBindExternalModule) ||
+ (index >= FuncAdjustGV1 && index <= FuncAdjustGVLast))
+ ret &= ~GlobalFunctionsContext;
+
+ return ret;
+}
+
+// static
+QString CustomFunctionData::resetToString(const int value, const ModelData * model)
+{
+ Firmware * firmware = getCurrentFirmware();
+ int step = CPN_MAX_TIMERS;
+
+ if (value < step) {
+ if (value < firmware->getCapability(Timers))
+ return RawSource(SOURCE_TYPE_SPECIAL, value + SOURCE_TYPE_SPECIAL_TIMER1_IDX).toString(model);
+ else
+ return QString(CPN_STR_UNKNOWN_ITEM);
+ }
+
+ if (value < ++step)
+ return tr("Flight");
+
+ if (value < ++step)
+ return tr("Telemetry");
+
+ if (value < step + firmware->getCapability(Sensors))
+ return RawSource(SOURCE_TYPE_TELEMETRY, 3 * (value - step)).toString(model);
+
+ return QString(CPN_STR_UNKNOWN_ITEM);
+}
+
+// static
+int CustomFunctionData::resetParamCount()
+{
+ Firmware * firmware = getCurrentFirmware();
+
+ return CPN_MAX_TIMERS + 2 + firmware->getCapability(Sensors);
+}
+
+// static
+bool CustomFunctionData::isResetParamAvailable(const int index, const ModelData * model)
+{
+ Firmware * firmware = getCurrentFirmware();
+
+ if (index < CPN_MAX_TIMERS) {
+ if (index < firmware->getCapability(Timers))
+ return true;
+ else
+ return false;
+ }
+ else if (index < CPN_MAX_TIMERS + 2)
+ return true;
+ else if (model && index < resetParamCount())
+ return model->sensorData[index - (CPN_MAX_TIMERS + 2)].isAvailable();
+
+ return false;
+}
+
+QString CustomFunctionData::harpicToString() const
+{
+ return harpicToString(param);
+}
+
+// static
+QString CustomFunctionData::harpicToString(const int value)
+{
+ return QString("%1").arg(value);
+}
+
+// static
+QStringList CustomFunctionData::playSoundStringList()
+{
+ return QStringList({ tr("Beep 1"), tr("Beep 2"), tr("Beep 3"), tr("Warn 1"), tr("Warn 2"), tr("Cheep"), tr("Ratata"), tr("Tick"),
+ tr("Siren"), tr("Ring"), tr("Sci Fi"), tr("Robot"), tr("Chirp"), tr("Tada"), tr("Cricket"), tr("Alarm Clock") });
+}
+
+QString CustomFunctionData::playSoundToString() const
+{
+ return playSoundToString(param);
+}
+
+// static
+QString CustomFunctionData::playSoundToString(const int value)
+{
+ const QStringList strl = playSoundStringList();
+ if (value < strl.count())
+ return strl.at(value);
+ else
+ return QString(CPN_STR_UNKNOWN_ITEM);
+}
+
+QString CustomFunctionData::gvarAdjustModeToString() const
+{
+ return gvarAdjustModeToString(adjustMode);
+}
+
+// static
+QString CustomFunctionData::gvarAdjustModeToString(const int value)
+{
+ switch (value) {
+ case FUNC_ADJUST_GVAR_CONSTANT:
+ return tr("Value");
+ case FUNC_ADJUST_GVAR_SOURCE:
+ return tr("Source");
+ case FUNC_ADJUST_GVAR_GVAR:
+ return tr("Global Variable");
+ case FUNC_ADJUST_GVAR_INCDEC:
+ return tr("Inc/Decrement");
+ default:
+ return QString(CPN_STR_UNKNOWN_ITEM);
}
}
+
+// static
+AbstractStaticItemModel * CustomFunctionData::repeatItemModel()
+{
+ AbstractStaticItemModel * mdl = new AbstractStaticItemModel();
+ mdl->setName("customfunctiondata.repeat");
+
+ for (int i = -1; i <= 60; i++) {
+ mdl->appendToItemList(repeatToString(i), i);
+ }
+
+ mdl->loadItemList();
+ return mdl;
+}
+
+// static
+AbstractStaticItemModel * CustomFunctionData::playSoundItemModel()
+{
+ AbstractStaticItemModel * mdl = new AbstractStaticItemModel();
+ mdl->setName("customfunctiondata.playsound");
+
+ for (int i = 0; i < playSoundStringList().count(); i++) {
+ mdl->appendToItemList(playSoundToString(i), i);
+ }
+
+ mdl->loadItemList();
+ return mdl;
+}
+
+// static
+AbstractStaticItemModel * CustomFunctionData::harpicItemModel()
+{
+ AbstractStaticItemModel * mdl = new AbstractStaticItemModel();
+ mdl->setName("customfunctiondata.harpic");
+
+ for (int i = 0; i <= 3; i++) {
+ mdl->appendToItemList(harpicToString(i), i);
+ }
+
+ mdl->loadItemList();
+ return mdl;
+}
+
+// static
+AbstractStaticItemModel * CustomFunctionData::gvarAdjustModeItemModel()
+{
+ AbstractStaticItemModel * mdl = new AbstractStaticItemModel();
+ mdl->setName("customfunctiondata.gvaradjustmode");
+
+ for (int i = 0; i < FUNC_ADJUST_GVAR_COUNT; i++) {
+ mdl->appendToItemList(gvarAdjustModeToString(i), i);
+ }
+
+ mdl->loadItemList();
+ return mdl;
+}
diff --git a/companion/src/firmwares/customfunctiondata.h b/companion/src/firmwares/customfunctiondata.h
index 9150035c5..d5a08a96f 100644
--- a/companion/src/firmwares/customfunctiondata.h
+++ b/companion/src/firmwares/customfunctiondata.h
@@ -18,8 +18,7 @@
* GNU General Public License for more details.
*/
-#ifndef CUSTOMFUNCTIONDATA_H
-#define CUSTOMFUNCTIONDATA_H
+#pragma once
#include "boards.h"
#include "constants.h"
@@ -32,10 +31,12 @@ class Firmware;
class ModelData;
class GeneralSettings;
class RadioDataConversionState;
+class AbstractStaticItemModel;
enum AssignFunc {
FuncOverrideCH1 = 0,
- FuncOverrideCH32 = FuncOverrideCH1+CPN_MAX_CHNOUT-1,
+ FuncOverrideCHLast = FuncOverrideCH1 + CPN_MAX_CHNOUT - 1,
+ FuncOverrideCH32 = FuncOverrideCHLast, // TODO remove
FuncTrainer,
FuncTrainerRUD,
FuncTrainerELE,
@@ -47,8 +48,9 @@ enum AssignFunc {
FuncPlayHaptic,
FuncReset,
FuncSetTimer1,
- FuncSetTimer2,
- FuncSetTimer3,
+ FuncSetTimer2, // TODO remove
+ FuncSetTimer3, // TODO remove
+ FuncSetTimerLast = FuncSetTimer1 + CPN_MAX_TIMERS - 1,
FuncVario,
FuncPlayPrompt,
FuncPlayBoth,
@@ -61,9 +63,8 @@ enum AssignFunc {
FuncBackgroundMusic,
FuncBackgroundMusicPause,
FuncAdjustGV1,
- FuncAdjustGVLast = FuncAdjustGV1+CPN_MAX_GVARS-1,
- FuncSetFailsafeInternalModule,
- FuncSetFailsafeExternalModule,
+ FuncAdjustGVLast = FuncAdjustGV1 + CPN_MAX_GVARS - 1,
+ FuncSetFailsafe,
FuncRangeCheckInternalModule,
FuncRangeCheckExternalModule,
FuncBindInternalModule,
@@ -77,14 +78,23 @@ enum GVarAdjustModes
FUNC_ADJUST_GVAR_CONSTANT,
FUNC_ADJUST_GVAR_SOURCE,
FUNC_ADJUST_GVAR_GVAR,
- FUNC_ADJUST_GVAR_INCDEC
+ FUNC_ADJUST_GVAR_INCDEC,
+ FUNC_ADJUST_GVAR_COUNT
};
class CustomFunctionData {
Q_DECLARE_TR_FUNCTIONS(CustomFunctionData)
public:
- CustomFunctionData(AssignFunc func=FuncOverrideCH1) { clear(); this->func = func; }
+ enum CustomFunctionContext
+ {
+ GlobalFunctionsContext = 0x01,
+ SpecialFunctionsContext = 0x02,
+
+ AllFunctionContexts = GlobalFunctionsContext | SpecialFunctionsContext
+ };
+
+ CustomFunctionData(AssignFunc func = FuncOverrideCH1) { clear(); this->func = func; }
RawSwitch swtch;
AssignFunc func;
int param;
@@ -93,21 +103,33 @@ class CustomFunctionData {
unsigned int adjustMode;
int repeatParam;
- void clear();
- bool isEmpty() const;
- QString nameToString(int index, bool globalContext = false) const;
- QString funcToString(const ModelData * model = NULL) const;
- QString paramToString(const ModelData * model) const;
- QString repeatToString() const;
- QString enabledToString() const;
-
- static void populateResetParams(const ModelData * model, QComboBox * b, unsigned int value);
- static void populatePlaySoundParams(QStringList & qs);
- static void populateHapticParams(QStringList & qs);
-
void convert(RadioDataConversionState & cstate);
+ void clear();
+ bool isEmpty() const;
+ QString funcToString(const ModelData * model = nullptr) const;
+ QString paramToString(const ModelData * model = nullptr) const;
+ QString repeatToString() const;
+ QString enabledToString() const;
+ QString playSoundToString() const;
+ QString harpicToString() const;
+ QString gvarAdjustModeToString() const;
+
+ static QString nameToString(const int index, const bool globalContext = false);
+ static QString funcToString(const AssignFunc func, const ModelData * model = nullptr);
+ static bool isFuncAvailable(const int index);
+ static int funcContext(const int index);
+ static QString resetToString(const int value, const ModelData * model = nullptr);
+ static int resetParamCount();
+ static bool isResetParamAvailable(const int index, const ModelData * model = nullptr);
+ static QString repeatToString(const int value);
+ static QStringList playSoundStringList();
+ static QString playSoundToString(const int value);
+ static QString harpicToString(const int value);
+ static QStringList gvarAdjustModeStringList();
+ static QString gvarAdjustModeToString(const int value);
+ static AbstractStaticItemModel * repeatItemModel();
+ static AbstractStaticItemModel * playSoundItemModel();
+ static AbstractStaticItemModel * harpicItemModel();
+ static AbstractStaticItemModel * gvarAdjustModeItemModel();
};
-
-
-#endif // CUSTOMFUNCTIONDATA_H
diff --git a/companion/src/firmwares/datahelpers.cpp b/companion/src/firmwares/datahelpers.cpp
new file mode 100644
index 000000000..8ae759a1b
--- /dev/null
+++ b/companion/src/firmwares/datahelpers.cpp
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+#include "datahelpers.h"
+
+QString DataHelpers::boolToString(const bool value, const BoolFormat format)
+{
+ static const char *strings[] = {
+ QT_TRANSLATE_NOOP("DataHelpers", "Disabled"),
+ QT_TRANSLATE_NOOP("DataHelpers", "Enabled"),
+ QT_TRANSLATE_NOOP("DataHelpers", "OFF"),
+ QT_TRANSLATE_NOOP("DataHelpers", "ON"),
+ QT_TRANSLATE_NOOP("DataHelpers", "False"),
+ QT_TRANSLATE_NOOP("DataHelpers", "True"),
+ QT_TRANSLATE_NOOP("DataHelpers", "N"),
+ QT_TRANSLATE_NOOP("DataHelpers", "Y"),
+ QT_TRANSLATE_NOOP("DataHelpers", "No"),
+ QT_TRANSLATE_NOOP("DataHelpers", "Yes")
+ };
+
+ return QCoreApplication::translate("DataHelpers", strings[format * 2 + value]);
+}
+
+QString DataHelpers::getElementName(const QString & prefix, const unsigned int index, const char * name, const bool padding)
+{
+ QString result = prefix;
+ result.append(padding ? QString("%1").arg(index, 2, 10, QChar('0')) : QString("%1").arg(index));
+ if (name && QString(name).trimmed().length() > 0)
+ result.append(":" + QString(name).trimmed());
+
+ return result;
+}
+
+QString DataHelpers::timeToString(const int value, const unsigned int mask)
+{
+ bool negative = value < 0 ? true : false;
+ int val = abs(value);
+
+ QString result = QString("%1").arg(negative ? "-" : ((mask & TIMESTR_MASK_PADSIGN) ? " " : ""));
+
+ if (mask & TIMESTR_MASK_HRSMINS) {
+ int hours = val / 3600;
+ if (hours > 0 || (mask & TIMESTR_MASK_ZEROHRS)) {
+ val -= hours * 3600;
+ result.append(QString("%1:").arg(hours, 2, 10, QLatin1Char('0')));
+ }
+ }
+
+ int minutes = val / 60;
+ int seconds = val % 60;
+ result.append(QString("%1:%2").arg(minutes, 2, 10, QLatin1Char('0')).arg(seconds, 2, 10, QLatin1Char('0')));
+ return result;
+}
diff --git a/companion/src/firmwares/datahelpers.h b/companion/src/firmwares/datahelpers.h
new file mode 100644
index 000000000..ccd3b0f64
--- /dev/null
+++ b/companion/src/firmwares/datahelpers.h
@@ -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.
+ */
+
+#pragma once
+
+#include
+
+class FieldRange
+{
+ public:
+ FieldRange():
+ decimals(0),
+ min(0.0),
+ max(0.0),
+ step(1.0),
+ offset(0.0),
+ prefix(""),
+ unit("")
+ {
+ }
+
+ float getValue(int value) { return float(value) * step; }
+
+ int decimals;
+ double min;
+ double max;
+ double step;
+ double offset;
+ QString prefix;
+ QString unit;
+};
+
+
+constexpr unsigned int TIMESTR_MASK_HRSMINS { 1 << 1 };
+constexpr unsigned int TIMESTR_MASK_ZEROHRS { 1 << 2 };
+constexpr unsigned int TIMESTR_MASK_PADSIGN { 1 << 3 };
+
+namespace DataHelpers
+{
+ enum BoolFormat {
+ BOOL_FMT_ENABLEDISABLE,
+ BOOL_FMT_ONOFF,
+ BOOL_FMT_TRUEFALSE,
+ BOOL_FMT_YN,
+ BOOL_FMT_YESNO
+ };
+
+ QString boolToString(const bool value, const BoolFormat format);
+ QString getElementName(const QString & prefix, const unsigned int index, const char * name = 0, const bool padding = false);
+ QString timeToString(const int value, const unsigned int mask);
+
+}
diff --git a/companion/src/firmwares/eeprominterface.h b/companion/src/firmwares/eeprominterface.h
index b3680b4ba..6cd62f287 100644
--- a/companion/src/firmwares/eeprominterface.h
+++ b/companion/src/firmwares/eeprominterface.h
@@ -151,6 +151,7 @@ enum Capability {
DangerousFunctions,
HasModelCategories,
HasSwitchableJack,
+ HasSportConnector,
PwrButtonPress,
Sensors
};
diff --git a/companion/src/firmwares/io_data.cpp b/companion/src/firmwares/flightmodedata.cpp
similarity index 56%
rename from companion/src/firmwares/io_data.cpp
rename to companion/src/firmwares/flightmodedata.cpp
index a958750d8..c0a268e96 100644
--- a/companion/src/firmwares/io_data.cpp
+++ b/companion/src/firmwares/flightmodedata.cpp
@@ -18,121 +18,17 @@
* GNU General Public License for more details.
*/
-#include "io_data.h"
-
-#include "radiodata.h" // for RadioData::getElementName
+#include "flightmodedata.h"
+#include "radiodata.h"
#include "radiodataconversionstate.h"
-/*
- * ExpoData
- */
-
-void ExpoData::convert(RadioDataConversionState & cstate)
+void FlightModeData::convert(RadioDataConversionState & cstate)
{
- cstate.setComponent(tr("INP"), 3);
- cstate.setSubComp(RawSource(SOURCE_TYPE_VIRTUAL_INPUT, chn).toString(cstate.fromModel(), cstate.fromGS(), cstate.fromType) % tr(" (@%1)").arg(cstate.subCompIdx));
- srcRaw.convert(cstate);
+ cstate.setComponent("FMD", 2);
+ cstate.setSubComp(nameToString(cstate.subCompIdx));
swtch.convert(cstate);
}
-bool ExpoData::isEmpty() const
-{
- return (chn == 0 && mode == INPUT_MODE_NONE);
-}
-
-/*
- * MixData
- */
-
-void MixData::convert(RadioDataConversionState & cstate)
-{
- cstate.setComponent(tr("MIX"), 4);
- cstate.setSubComp(RawSource(SOURCE_TYPE_CH, destCh-1).toString(cstate.fromModel(), cstate.fromGS(), cstate.fromType) % tr(" (@%1)").arg(cstate.subCompIdx));
- srcRaw.convert(cstate);
- swtch.convert(cstate);
-}
-
-bool MixData::isEmpty() const
-{
- return (destCh == 0);
-}
-
-/*
- * LimitData
- */
-
-QString LimitData::minToString() const
-{
- return QString::number((qreal)min/10);
-}
-
-QString LimitData::maxToString() const
-{
- return QString::number((qreal)max/10);
-}
-
-QString LimitData::revertToString() const
-{
- return revert ? tr("INV") : tr("NOR");
-}
-
-QString LimitData::nameToString(int index) const
-{
- return RadioData::getElementName(tr("CH"), index + 1, name);
-}
-
-QString LimitData::offsetToString() const
-{
- return QString::number((qreal)offset/10, 'f', 1);
-}
-
-void LimitData::clear()
-{
- memset(reinterpret_cast(this), 0, sizeof(LimitData));
- min = -1000;
- max = +1000;
-}
-
-bool LimitData::isEmpty() const
-{
- return (min == -1000 && max == 1000 && !revert && !offset && !ppmCenter && !symetrical && name[0] == '\0' && !curve.isSet());
-}
-
-/*
- * CurveData
- */
-
-CurveData::CurveData()
-{
- clear();
-}
-
-void CurveData::clear(int count)
-{
- memset(this, 0, sizeof(CurveData));
- this->count = count;
-}
-
-bool CurveData::isEmpty() const
-{
- for (int i=0; i(this), 0, sizeof(FlightModeData));
@@ -149,13 +45,6 @@ QString FlightModeData::nameToString(int phaseIdx) const
return RadioData::getElementName(tr("FM"), phaseIdx, name); // names are zero-based, FM0, FM1, etc
}
-void FlightModeData::convert(RadioDataConversionState & cstate)
-{
- cstate.setComponent("FMD", 2);
- cstate.setSubComp(nameToString(cstate.subCompIdx));
- swtch.convert(cstate);
-}
-
bool FlightModeData::isEmpty(int phaseIdx) const
{
if (name[0] != '\0' || swtch.isSet() || fadeIn != 0 || fadeOut != 0)
diff --git a/companion/src/firmwares/flightmodedata.h b/companion/src/firmwares/flightmodedata.h
new file mode 100644
index 000000000..8578d04e5
--- /dev/null
+++ b/companion/src/firmwares/flightmodedata.h
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "constants.h"
+#include "rawswitch.h"
+
+#include
+
+class RadioDataConversionState;
+
+#define FLIGHTMODE_NAME_LEN 10
+#define RENC_MAX_VALUE 1024
+#define RENC_MIN_VALUE -RENC_MAX_VALUE
+
+class FlightModeData {
+ Q_DECLARE_TR_FUNCTIONS(FlightModeData)
+
+ public:
+ FlightModeData() { clear(0); }
+
+ int trimMode[CPN_MAX_TRIMS];
+ int trimRef[CPN_MAX_TRIMS];
+ int trim[CPN_MAX_TRIMS];
+ RawSwitch swtch;
+ char name[FLIGHTMODE_NAME_LEN + 1];
+ unsigned int fadeIn;
+ unsigned int fadeOut;
+ int rotaryEncoders[CPN_MAX_ENCODERS];
+ int gvars[CPN_MAX_GVARS];
+
+ void convert(RadioDataConversionState & cstate);
+ void clear(const int phaseIdx);
+ bool isEmpty(int phaseIdx) const;
+ QString nameToString(int phaseIdx) const;
+ bool isGVarEmpty(int phaseIdx, int gvIdx) const;
+ bool isREncEmpty(int phaseIdx, int reIdx) const;
+ int linkedFlightModeZero(int phaseIdx, int maxOwnValue) const;
+ int linkedGVarFlightModeZero(int phaseIdx) const;
+ int linkedREncFlightModeZero(int phaseIdx) const;
+};
diff --git a/companion/src/firmwares/generalsettings.cpp b/companion/src/firmwares/generalsettings.cpp
index f307dbf26..f9df851b2 100644
--- a/companion/src/firmwares/generalsettings.cpp
+++ b/companion/src/firmwares/generalsettings.cpp
@@ -94,6 +94,12 @@ GeneralSettings::GeneralSettings()
vBatMin = -23; // 6.7V
vBatMax = -37; // 8.3V
}
+ else if (IS_JUMPER_TLITE(board)) {
+ // 1S Li-Ion
+ vBatWarn = 32;
+ vBatMin = -60; //3V
+ vBatMax = -78; //4.2V
+ }
else if (IS_TARANIS(board)) {
// NI-MH 7.2V, X9D, X9D+ and X7
vBatWarn = 65;
@@ -239,6 +245,10 @@ void GeneralSettings::setDefaultControlTypes(Board::Type board)
switchConfig[i] = Boards::getSwitchInfo(board, i).config;
}
+ // TLite does not have pots or sliders
+ if (IS_JUMPER_TLITE(board))
+ return;
+
// TODO: move to Boards, like with switches
if (IS_FAMILY_HORUS_OR_T16(board)) {
potConfig[0] = Board::POT_WITH_DETENT;
@@ -253,11 +263,11 @@ void GeneralSettings::setDefaultControlTypes(Board::Type board)
potConfig[0] = Board::POT_WITHOUT_DETENT;
potConfig[1] = Board::POT_WITH_DETENT;
}
- else if (IS_TARANIS(board)) {
+ else if (IS_FAMILY_T12(board)) {
potConfig[0] = Board::POT_WITH_DETENT;
potConfig[1] = Board::POT_WITH_DETENT;
}
- else if (IS_JUMPER_T12(board)) {
+ else if (IS_TARANIS(board)) {
potConfig[0] = Board::POT_WITH_DETENT;
potConfig[1] = Board::POT_WITH_DETENT;
}
@@ -329,14 +339,14 @@ void GeneralSettings::convert(RadioDataConversionState & cstate)
}
}
- if (IS_JUMPER_T12(cstate.toType)) {
+ if (IS_FAMILY_T12(cstate.toType)) {
if (IS_TARANIS_X9(cstate.fromType) || IS_FAMILY_HORUS_OR_T16(cstate.fromType)) {
strncpy(switchName[4], switchName[5], sizeof(switchName[0]));
strncpy(switchName[5], switchName[7], sizeof(switchName[0]));
}
}
- else if (IS_JUMPER_T12(cstate.fromType)) {
+ else if (IS_FAMILY_T12(cstate.fromType)) {
if (IS_TARANIS_X9(cstate.toType) || IS_FAMILY_HORUS_OR_T16(cstate.toType)) {
strncpy(switchName[5], switchName[4], sizeof(switchName[0]));
strncpy(switchName[7], switchName[5], sizeof(switchName[0]));
diff --git a/companion/src/firmwares/generalsettings.h b/companion/src/firmwares/generalsettings.h
index cdb72d9c8..f7b28931d 100644
--- a/companion/src/firmwares/generalsettings.h
+++ b/companion/src/firmwares/generalsettings.h
@@ -103,6 +103,7 @@ class GeneralSettings {
bool disableRssiPoweroffAlarm;
unsigned int usbMode;
unsigned int jackMode;
+ bool sportPower;
BeeperMode hapticMode;
unsigned int stickMode; // TODO enum
int timezone;
diff --git a/companion/src/firmwares/heli_data.cpp b/companion/src/firmwares/heli_data.cpp
new file mode 100644
index 000000000..b1fb7b36e
--- /dev/null
+++ b/companion/src/firmwares/heli_data.cpp
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+#include "heli_data.h"
diff --git a/companion/src/firmwares/heli_data.h b/companion/src/firmwares/heli_data.h
new file mode 100644
index 000000000..734b29928
--- /dev/null
+++ b/companion/src/firmwares/heli_data.h
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "rawsource.h"
+
+#include
+
+class SwashRingData {
+ Q_DECLARE_TR_FUNCTIONS(SwashRingData)
+
+ public:
+ SwashRingData() { clear(); }
+
+ int elevatorWeight;
+ int aileronWeight;
+ int collectiveWeight;
+ unsigned int type;
+ RawSource collectiveSource;
+ RawSource aileronSource;
+ RawSource elevatorSource;
+ unsigned int value;
+
+ void clear() { memset(reinterpret_cast(this), 0, sizeof(SwashRingData)); }
+};
+
diff --git a/companion/src/firmwares/input_data.cpp b/companion/src/firmwares/input_data.cpp
new file mode 100644
index 000000000..9b9ecfe20
--- /dev/null
+++ b/companion/src/firmwares/input_data.cpp
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+#include "input_data.h"
+#include "radiodataconversionstate.h"
+
+void ExpoData::convert(RadioDataConversionState & cstate)
+{
+ cstate.setComponent(tr("INP"), 3);
+ cstate.setSubComp(RawSource(SOURCE_TYPE_VIRTUAL_INPUT, chn).toString(cstate.fromModel(), cstate.fromGS(), cstate.fromType) % tr(" (@%1)").arg(cstate.subCompIdx));
+ srcRaw.convert(cstate);
+ swtch.convert(cstate);
+}
+
+bool ExpoData::isEmpty() const
+{
+ return (chn == 0 && mode == INPUT_MODE_NONE);
+}
diff --git a/companion/src/firmwares/input_data.h b/companion/src/firmwares/input_data.h
new file mode 100644
index 000000000..27b6b6282
--- /dev/null
+++ b/companion/src/firmwares/input_data.h
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "curvereference.h"
+#include "rawsource.h"
+#include "rawswitch.h"
+
+#include
+
+class RadioDataConversionState;
+
+enum InputMode {
+ INPUT_MODE_NONE,
+ INPUT_MODE_POS,
+ INPUT_MODE_NEG,
+ INPUT_MODE_BOTH
+};
+
+#define EXPODATA_NAME_LEN 10
+
+class ExpoData {
+ Q_DECLARE_TR_FUNCTIONS(ExpoData)
+
+ public:
+ ExpoData() { clear(); }
+
+ RawSource srcRaw;
+ unsigned int scale;
+ unsigned int mode; // InputMode
+ unsigned int chn;
+ RawSwitch swtch;
+ unsigned int flightModes; // -5=!FP4, 0=normal, 5=FP4
+ int weight;
+ int offset;
+ CurveReference curve;
+ int carryTrim;
+ char name[EXPODATA_NAME_LEN + 1];
+
+ void convert(RadioDataConversionState & cstate);
+ void clear() { memset(reinterpret_cast(this), 0, sizeof(ExpoData)); }
+ bool isEmpty() const;
+};
diff --git a/companion/src/firmwares/io_data.h b/companion/src/firmwares/io_data.h
deleted file mode 100644
index b70b174ea..000000000
--- a/companion/src/firmwares/io_data.h
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * 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 IO_DATA_H
-#define IO_DATA_H
-
-#include "constants.h"
-#include "curvereference.h"
-#include "rawsource.h"
-#include "rawswitch.h"
-
-#include
-
-class RadioDataConversionState;
-
-enum InputMode {
- INPUT_MODE_NONE,
- INPUT_MODE_POS,
- INPUT_MODE_NEG,
- INPUT_MODE_BOTH
-};
-
-#define EXPODATA_NAME_LEN 10
-
-class ExpoData {
- Q_DECLARE_TR_FUNCTIONS(ExpoData)
-
- public:
- ExpoData() { clear(); }
- RawSource srcRaw;
- unsigned int scale;
- unsigned int mode; // InputMode
- unsigned int chn;
- RawSwitch swtch;
- unsigned int flightModes; // -5=!FP4, 0=normal, 5=FP4
- int weight;
- int offset;
- CurveReference curve;
- int carryTrim;
- char name[EXPODATA_NAME_LEN+1];
- void clear() { memset(reinterpret_cast(this), 0, sizeof(ExpoData)); }
- void convert(RadioDataConversionState & cstate);
- bool isEmpty() const;
-};
-
-enum MltpxValue {
- MLTPX_ADD=0,
- MLTPX_MUL=1,
- MLTPX_REP=2
-};
-
-#define MIXDATA_NAME_LEN 10
-
-class MixData {
- Q_DECLARE_TR_FUNCTIONS(MixData)
-
- public:
- MixData() { clear(); }
- void convert(RadioDataConversionState & cstate);
-
- unsigned int destCh; // 1..CPN_MAX_CHNOUT
- RawSource srcRaw;
- int weight;
- RawSwitch swtch;
- CurveReference curve; //0=symmetrisch
- unsigned int delayUp;
- unsigned int delayDown;
- unsigned int speedUp; // Servogeschwindigkeit aus Tabelle (10ms Cycle)
- unsigned int speedDown; // 0 nichts
- int carryTrim;
- bool noExpo;
- MltpxValue mltpx; // multiplex method 0=+ 1=* 2=replace
- unsigned int mixWarn; // mixer warning
- unsigned int flightModes; // -5=!FP4, 0=normal, 5=FP4
- int sOffset;
- char name[MIXDATA_NAME_LEN+1];
-
- void clear() { memset(reinterpret_cast(this), 0, sizeof(MixData)); }
- bool isEmpty() const;
-};
-
-#define LIMITDATA_NAME_LEN 6
-
-class LimitData {
- Q_DECLARE_TR_FUNCTIONS(LimitData)
-
- public:
- LimitData() { clear(); }
- int min;
- int max;
- bool revert;
- int offset;
- int ppmCenter;
- bool symetrical;
- int failsafe;
- char name[LIMITDATA_NAME_LEN + 1];
- CurveReference curve;
- QString minToString() const;
- QString maxToString() const;
- QString offsetToString() const;
- QString revertToString() const;
- QString nameToString(int index) const;
- void clear();
- bool isEmpty() const;
-};
-
-class CurvePoint {
- public:
- int8_t x;
- int8_t y;
-};
-
-#define CURVEDATA_NAME_LEN 6
-
-class CurveData {
- Q_DECLARE_TR_FUNCTIONS(CurveData)
-
- public:
- enum CurveType {
- CURVE_TYPE_STANDARD,
- CURVE_TYPE_CUSTOM,
- CURVE_TYPE_LAST = CURVE_TYPE_CUSTOM
- };
-
- CurveData();
- void clear(int count = 5);
- bool isEmpty() const;
- QString nameToString(const int idx) const;
-
- CurveType type;
- bool smooth;
- int count;
- CurvePoint points[CPN_MAX_POINTS];
- char name[CURVEDATA_NAME_LEN+1];
-};
-
-#define FLIGHTMODE_NAME_LEN 10
-#define RENC_MAX_VALUE 1024
-#define RENC_MIN_VALUE -RENC_MAX_VALUE
-
-class FlightModeData {
- Q_DECLARE_TR_FUNCTIONS(FlightModeData)
-
- public:
- FlightModeData() { clear(0); }
- int trimMode[CPN_MAX_TRIMS];
- int trimRef[CPN_MAX_TRIMS];
- int trim[CPN_MAX_TRIMS];
- RawSwitch swtch;
- char name[FLIGHTMODE_NAME_LEN+1];
- unsigned int fadeIn;
- unsigned int fadeOut;
- int rotaryEncoders[CPN_MAX_ENCODERS];
- int gvars[CPN_MAX_GVARS];
- void clear(const int phaseIdx);
- QString nameToString(int phaseIdx) const;
- void convert(RadioDataConversionState & cstate);
- bool isEmpty(int phaseIdx) const;
- bool isGVarEmpty(int phaseIdx, int gvIdx) const;
- bool isREncEmpty(int phaseIdx, int reIdx) const;
- int linkedFlightModeZero(int phaseIdx, int maxOwnValue) const;
- int linkedGVarFlightModeZero(int phaseIdx) const;
- int linkedREncFlightModeZero(int phaseIdx) const;
-};
-
-class SwashRingData {
- Q_DECLARE_TR_FUNCTIONS(SwashRingData)
-
- public:
- SwashRingData() { clear(); }
- int elevatorWeight;
- int aileronWeight;
- int collectiveWeight;
- unsigned int type;
- RawSource collectiveSource;
- RawSource aileronSource;
- RawSource elevatorSource;
- unsigned int value;
- void clear() { memset(reinterpret_cast(this), 0, sizeof(SwashRingData)); }
-};
-
-#endif // IO_DATA_H
diff --git a/companion/src/firmwares/mixdata.cpp b/companion/src/firmwares/mixdata.cpp
new file mode 100644
index 000000000..ac2893a4d
--- /dev/null
+++ b/companion/src/firmwares/mixdata.cpp
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+#include "mixdata.h"
+#include "radiodataconversionstate.h"
+
+void MixData::convert(RadioDataConversionState & cstate)
+{
+ cstate.setComponent(tr("MIX"), 4);
+ cstate.setSubComp(RawSource(SOURCE_TYPE_CH, destCh-1).toString(cstate.fromModel(), cstate.fromGS(), cstate.fromType) % tr(" (@%1)").arg(cstate.subCompIdx));
+ srcRaw.convert(cstate);
+ swtch.convert(cstate);
+}
+
+bool MixData::isEmpty() const
+{
+ return (destCh == 0);
+}
diff --git a/companion/src/firmwares/mixdata.h b/companion/src/firmwares/mixdata.h
new file mode 100644
index 000000000..dc81298f0
--- /dev/null
+++ b/companion/src/firmwares/mixdata.h
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "curvereference.h"
+#include "rawsource.h"
+#include "rawswitch.h"
+
+#include
+
+class RadioDataConversionState;
+
+enum MltpxValue {
+ MLTPX_ADD,
+ MLTPX_MUL,
+ MLTPX_REP
+};
+
+#define MIXDATA_NAME_LEN 10
+
+class MixData {
+ Q_DECLARE_TR_FUNCTIONS(MixData)
+
+ public:
+ MixData() { clear(); }
+
+ unsigned int destCh; // 1..CPN_MAX_CHNOUT
+ RawSource srcRaw;
+ int weight;
+ RawSwitch swtch;
+ CurveReference curve;
+ unsigned int delayUp;
+ unsigned int delayDown;
+ unsigned int speedUp;
+ unsigned int speedDown;
+ int carryTrim;
+ bool noExpo;
+ MltpxValue mltpx;
+ unsigned int mixWarn;
+ unsigned int flightModes; // -5=!FP4, 0=normal, 5=FP4
+ int sOffset;
+ char name[MIXDATA_NAME_LEN + 1];
+
+ void convert(RadioDataConversionState & cstate);
+ void clear() { memset(reinterpret_cast(this), 0, sizeof(MixData)); }
+ bool isEmpty() const;
+};
diff --git a/companion/src/firmwares/modeldata.cpp b/companion/src/firmwares/modeldata.cpp
index 3add6de8b..679e90f5f 100644
--- a/companion/src/firmwares/modeldata.cpp
+++ b/companion/src/firmwares/modeldata.cpp
@@ -27,26 +27,6 @@
#include "helpers.h"
#include "adjustmentreference.h"
-/*
- * TimerData
- */
-
-void TimerData::convert(RadioDataConversionState & cstate)
-{
- cstate.setComponent(tr("TMR"), 1);
- cstate.setSubComp(tr("Timer %1").arg(cstate.subCompIdx + 1));
- mode.convert(cstate);
-}
-
-bool TimerData::isEmpty()
-{
- return (mode == RawSwitch(SWITCH_TYPE_TIMER_MODE, 0) && name[0] == '\0' && minuteBeep == 0 && countdownBeep == COUNTDOWN_SILENT && val == 0 && persistent == 0 /*&& pvalue == 0*/);
-}
-
-/*
- * ModelData
- */
-
ModelData::ModelData()
{
clear();
@@ -527,6 +507,8 @@ int ModelData::updateReference()
Firmware *fw = getCurrentFirmware();
+ updRefInfo.occurences = 1;
+
switch (updRefInfo.type)
{
case REF_UPD_TYPE_CHANNEL:
@@ -561,6 +543,7 @@ int ModelData::updateReference()
updRefInfo.srcType = SOURCE_TYPE_TELEMETRY;
updRefInfo.swtchType = SWITCH_TYPE_SENSOR;
updRefInfo.maxindex = fw->getCapability(Sensors);
+ updRefInfo.occurences = 3;
break;
case REF_UPD_TYPE_TIMER:
updRefInfo.srcType = SOURCE_TYPE_SPECIAL;
@@ -651,6 +634,8 @@ int ModelData::updateReference()
}
}
}
+ if (updRefInfo.type == REF_UPD_TYPE_CHANNEL)
+ sortMixes();
//s1.report("Mixes");
for (int i = 0; i < CPN_MAX_CHNOUT; i++) {
@@ -668,41 +653,56 @@ int ModelData::updateReference()
LogicalSwitchData *lsd = &logicalSw[i];
if (!lsd->isEmpty()) {
bool clearlsd = false;
+ int oldval1;
+ int oldval2;
CSFunctionFamily family = lsd->getFunctionFamily();
switch(family) {
case LS_FAMILY_VOFS:
- updateSourceIntRef(lsd->val1);
- if (lsd->val1 == 0)
- clearlsd = true;
+ if (lsd->val1 != 0) {
+ updateSourceIntRef(lsd->val1);
+ if (lsd->val1 == 0)
+ clearlsd = true;
+ }
break;
case LS_FAMILY_STICKY:
case LS_FAMILY_VBOOL:
- updateSwitchIntRef(lsd->val1);
- updateSwitchIntRef(lsd->val2);
- if (lsd->val1 == 0 && lsd->val2 == 0)
+ oldval1 = lsd->val1;
+ oldval2 = lsd->val2;
+ if (lsd->val1 != 0)
+ updateSwitchIntRef(lsd->val1);
+ if (lsd->val2 != 0)
+ updateSwitchIntRef(lsd->val2);
+ if (lsd->val1 == 0 && lsd->val2 == 0 && ((lsd->val1 != oldval1 && oldval2 == 0) || (lsd->val2 != oldval2 && oldval1 == 0)))
clearlsd = true;
break;
case LS_FAMILY_EDGE:
- updateSwitchIntRef(lsd->val1);
- if (lsd->val1 == 0)
- clearlsd = true;
+ if (lsd->val1 != 0) {
+ updateSwitchIntRef(lsd->val1);
+ if (lsd->val1 == 0)
+ clearlsd = true;
+ }
break;
case LS_FAMILY_VCOMP:
- updateSourceIntRef(lsd->val1);
- updateSourceIntRef(lsd->val2);
- if (lsd->val1 == 0 && lsd->val2 == 0)
+ oldval1 = lsd->val1;
+ oldval2 = lsd->val2;
+ if (lsd->val1 != 0)
+ updateSourceIntRef(lsd->val1);
+ if (lsd->val2 != 0)
+ updateSourceIntRef(lsd->val2);
+ if (lsd->val1 == 0 && lsd->val2 == 0 && ((lsd->val1 != oldval1 && oldval2 == 0) || (lsd->val2 != oldval2 && oldval1 == 0)))
clearlsd = true;
break;
default:
break;
}
- if (clearlsd) {
+
+ if (lsd->andsw != 0)
+ updateSwitchIntRef(lsd->andsw);
+
+ if (clearlsd && lsd->andsw == 0) {
lsd->clear();
appendUpdateReferenceParams(REF_UPD_TYPE_LOGICAL_SWITCH, REF_UPD_ACT_CLEAR, i);
}
- else {
- updateSwitchIntRef(lsd->andsw);
- }
}
}
//s1.report("Logical Switches");
@@ -713,11 +713,15 @@ int ModelData::updateReference()
updateAssignFunc(cfd);
if (!cfd->isEmpty()) {
updateSwitchRef(cfd->swtch);
- if (cfd->func == FuncVolume || cfd->func == FuncPlayValue || (cfd->func >= FuncAdjustGV1 && cfd->func <= FuncAdjustGVLast && (cfd->adjustMode == FUNC_ADJUST_GVAR_GVAR || cfd->adjustMode == FUNC_ADJUST_GVAR_SOURCE))) {
+ if (cfd->func == FuncVolume || cfd->func == FuncBacklight || cfd->func == FuncPlayValue ||
+ (cfd->func >= FuncAdjustGV1 && cfd->func <= FuncAdjustGVLast && (cfd->adjustMode == FUNC_ADJUST_GVAR_GVAR || cfd->adjustMode == FUNC_ADJUST_GVAR_SOURCE))) {
updateSourceIntRef(cfd->param);
if (cfd->param == 0)
cfd->clear();
}
+ else if (cfd->func == FuncReset) {
+ updateResetParam(cfd);
+ }
}
}
}
@@ -762,15 +766,35 @@ int ModelData::updateReference()
//s1.report("Telemetry");
}
- // TODO maybe less risk to leave it up to the user??
- /*
for (int i = 0; i < CPN_MAX_SENSORS; i++) {
SensorData *sd = &sensorData[i];
- if (sd->isAvailable() && sd->type == SensorData::TELEM_TYPE_CALCULATED) {
+ if (!sd->isEmpty() && sd->type == SensorData::TELEM_TYPE_CALCULATED) {
+ if (sd->formula == SensorData::TELEM_FORMULA_CELL) {
+ updateTelemetryRef(sd->source);
+ if (sd->source == 0) {
+ sd->clear();
+ appendUpdateReferenceParams(REF_UPD_TYPE_SENSOR, REF_UPD_ACT_CLEAR, i);
+ }
+ }
+ else if (sd->formula == SensorData::TELEM_FORMULA_DIST) {
+ updateTelemetryRef(sd->gps);
+ updateTelemetryRef(sd->alt);
+ }
+ else if (sd->formula == SensorData::TELEM_FORMULA_CONSUMPTION || sd->formula == SensorData::TELEM_FORMULA_TOTALIZE) {
+ updateTelemetryRef(sd->amps);
+ if (sd->amps == 0) {
+ sd->clear();
+ appendUpdateReferenceParams(REF_UPD_TYPE_SENSOR, REF_UPD_ACT_CLEAR, i);
+ }
+ }
+ else {
+ for (unsigned int i = 0; i < 4; i++) {
+ updateTelemetryRef(sd->sources[i]);
+ }
+ }
}
}
- s1.report("Telemetry Sensors");
- */
+ //s1.report("Telemetry Sensors");
// TODO needs lua incorporated into Companion as script needs to be parsed to determine if input field is source or value
/*
@@ -806,10 +830,13 @@ void ModelData::updateTypeIndexRef(R & curRef, const T type, const int idxAdj, c
newRef.type = curRef.type;
newRef.index = abs(curRef.index);
+ div_t idx = div(newRef.index, updRefInfo.occurences);
+ div_t newidx;
+
switch (updRefInfo.action)
{
case REF_UPD_ACT_CLEAR:
- if (newRef.index != (updRefInfo.index1 + idxAdj))
+ if (idx.quot != (updRefInfo.index1 + idxAdj))
return;
if (defClear)
newRef.clear();
@@ -819,25 +846,26 @@ void ModelData::updateTypeIndexRef(R & curRef, const T type, const int idxAdj, c
}
break;
case REF_UPD_ACT_SHIFT:
- if (newRef.index < (updRefInfo.index1 + idxAdj))
+ if (idx.quot < (updRefInfo.index1 + idxAdj))
return;
- newRef.index += updRefInfo.shift;
+ newRef.index = ((idx.quot + updRefInfo.shift) * updRefInfo.occurences) + idx.rem;
+ newidx = div(newRef.index, updRefInfo.occurences);
- if (newRef.index < (updRefInfo.index1 + idxAdj) || newRef.index > (updRefInfo.maxindex + idxAdj)) {
+ if (newidx.quot < (updRefInfo.index1 + idxAdj) || newidx.quot > (updRefInfo.maxindex + idxAdj)) {
if (defClear)
newRef.clear();
else {
newRef.type = (T)defType;
- newRef.index = defIndex;
+ newRef.index = defIndex + idxAdj;
}
}
break;
case REF_UPD_ACT_SWAP:
- if (newRef.index == updRefInfo.index1 + idxAdj)
- newRef.index = updRefInfo.index2 + idxAdj;
- else if (newRef.index == updRefInfo.index2 + idxAdj)
- newRef.index = updRefInfo.index1 + idxAdj;
+ if (idx.quot == updRefInfo.index1 + idxAdj)
+ newRef.index = ((updRefInfo.index2 + idxAdj) * updRefInfo.occurences) + idx.rem;
+ else if (idx.quot == updRefInfo.index2 + idxAdj)
+ newRef.index = ((updRefInfo.index1 + idxAdj) * updRefInfo.occurences) + idx.rem;
break;
default:
qDebug() << "Error - unhandled action:" << updRefInfo.action;
@@ -886,7 +914,7 @@ void ModelData::updateTypeValueRef(R & curRef, const T type, const int idxAdj, c
newRef.clear();
else {
newRef.type = (T)defType;
- newRef.value = defValue;
+ newRef.value = defValue + idxAdj;
}
}
break;
@@ -940,7 +968,7 @@ void ModelData::updateAssignFunc(CustomFunctionData * cfd)
{
const int invalidateRef = -1;
int newRef = (int)cfd->func;
- int idxAdj;
+ int idxAdj = 0;
switch (updRefInfo.type)
{
@@ -957,7 +985,7 @@ void ModelData::updateAssignFunc(CustomFunctionData * cfd)
case REF_UPD_TYPE_TIMER:
if (cfd->func < FuncSetTimer1 || cfd->func > FuncSetTimer3) // TODO refactor to FuncSetTimerLast
return;
- idxAdj = FuncSetTimer1 - 2; // reverse earlier offset requiured for rawsource
+ idxAdj = FuncSetTimer1 - 2; // reverse earlier offset required for rawsource
break;
default:
return;
@@ -1070,7 +1098,7 @@ void ModelData::updateFlightModeFlags(unsigned int & curRef)
switch (updRefInfo.action)
{
case REF_UPD_ACT_CLEAR:
- flag[updRefInfo.index1] = false;
+ flag[updRefInfo.index1] = true;
break;
case REF_UPD_ACT_SHIFT:
if(updRefInfo.shift < 0) {
@@ -1078,7 +1106,7 @@ void ModelData::updateFlightModeFlags(unsigned int & curRef)
if (i - updRefInfo.shift <= updRefInfo.maxindex)
flag[i] = flag[i - updRefInfo.shift];
else
- flag[i] = false;
+ flag[i] = true;
}
}
else {
@@ -1086,7 +1114,7 @@ void ModelData::updateFlightModeFlags(unsigned int & curRef)
if (i - updRefInfo.shift >= updRefInfo.index1)
flag[i] = flag[i - updRefInfo.shift];
else
- flag[i] = false;
+ flag[i] = true;
}
}
break;
@@ -1115,13 +1143,14 @@ void ModelData::updateFlightModeFlags(unsigned int & curRef)
}
}
-void ModelData::updateTelemetryRef(unsigned int & curRef)
+void ModelData::updateTelemetryRef(int & curRef)
{
if (updRefInfo.type != REF_UPD_TYPE_SENSOR)
return;
const int idxAdj = 1;
int newRef = curRef;
+
switch (updRefInfo.action)
{
case REF_UPD_ACT_CLEAR:
@@ -1149,13 +1178,23 @@ void ModelData::updateTelemetryRef(unsigned int & curRef)
return;
}
- if (curRef != static_cast(newRef)) {
+ if (curRef != newRef) {
//qDebug() << "Updated reference:" << curRef << " -> " << newRef;
curRef = newRef;
updRefInfo.updcnt++;
}
}
+void ModelData::updateTelemetryRef(unsigned int & curRef)
+{
+ int newRef = (int)curRef;
+ updateTelemetryRef(newRef);
+
+ if (curRef != static_cast(newRef)) {
+ curRef = (unsigned int)newRef;
+ }
+}
+
void ModelData::updateModuleFailsafes(ModuleData * md)
{
if (updRefInfo.type != REF_UPD_TYPE_CHANNEL)
@@ -1289,3 +1328,225 @@ void ModelData::removeMix(const int idx)
memmove(&mixData[idx], &mixData[idx + 1], (CPN_MAX_MIXERS - (idx + 1)) * sizeof(MixData));
mixData[CPN_MAX_MIXERS - 1].clear();
}
+
+void ModelData::sortMixes()
+{
+ unsigned int lastchn = 0;
+ bool sortreq = false;
+
+ for (int i = 0; i < CPN_MAX_MIXERS; i++) {
+ MixData *md = &mixData[i];
+ if (!md->isEmpty()) {
+ if (md->destCh < lastchn) {
+ sortreq = true;
+ break;
+ }
+ else
+ lastchn = md->destCh;
+ }
+ }
+
+ if (!sortreq)
+ return;
+
+ // QMap automatically sorts based on key
+ QMap map;
+ for (int i = 0; i < CPN_MAX_MIXERS; i++) {
+ MixData *md = &mixData[i];
+ if (!md->isEmpty()) {
+ // destCh may not be unique so build a compound sort key
+ map.insert(md->destCh * (CPN_MAX_MIXERS + 1) + i, i);
+ }
+ }
+
+ MixData sortedMixData[CPN_MAX_MIXERS];
+ int destidx = 0;
+
+ QMap::const_iterator i;
+ for (i = map.constBegin(); i != map.constEnd(); ++i) {
+ memcpy(&sortedMixData[destidx], &mixData[i.value()], sizeof(MixData));
+ destidx++;
+ }
+
+ memcpy(&mixData[0], &sortedMixData[0], CPN_MAX_MIXERS * sizeof(MixData));
+}
+
+void ModelData::updateResetParam(CustomFunctionData * cfd)
+{
+ if (cfd->func != FuncReset)
+ return;
+
+ const int invalidateRef = -1;
+ int newRef = cfd->param;
+ int idxAdj = 0;
+ Firmware *firmware = getCurrentFirmware();
+
+ switch (updRefInfo.type)
+ {
+ case REF_UPD_TYPE_TIMER:
+ if (cfd->param < 0 || cfd->param > 2)
+ return;
+ idxAdj = -2; // reverse earlier offset required for rawsource
+ break;
+ case REF_UPD_TYPE_SENSOR:
+ idxAdj = 5/*3 Timers + Flight + Telemetery*/ + firmware->getCapability(RotaryEncoders);
+ if (cfd->param < idxAdj || cfd->param > (idxAdj + firmware->getCapability(Sensors)))
+ return;
+ break;
+ default:
+ return;
+ }
+
+ switch (updRefInfo.action)
+ {
+ case REF_UPD_ACT_CLEAR:
+ if (newRef != (updRefInfo.index1 + idxAdj))
+ return;
+ newRef = invalidateRef;
+ break;
+ case REF_UPD_ACT_SHIFT:
+ if (newRef < (updRefInfo.index1 + idxAdj))
+ return;
+
+ newRef += updRefInfo.shift;
+
+ if (newRef < (updRefInfo.index1 + idxAdj) || newRef > (updRefInfo.maxindex + idxAdj))
+ newRef = invalidateRef;
+ break;
+ case REF_UPD_ACT_SWAP:
+ if (newRef == updRefInfo.index1 + idxAdj)
+ newRef = updRefInfo.index2 + idxAdj;
+ else if (newRef == updRefInfo.index2 + idxAdj)
+ newRef = updRefInfo.index1 + idxAdj;
+ break;
+ default:
+ qDebug() << "Error - unhandled action:" << updRefInfo.action;
+ return;
+ }
+
+ if (newRef == invalidateRef) {
+ cfd->clear();
+ //qDebug() << "Function cleared";
+ updRefInfo.updcnt++;
+ }
+ else if (cfd->param != newRef) {
+ //qDebug() << "Updated reference:" << cfd->param << " -> " << newRef;
+ cfd->param = newRef;
+ updRefInfo.updcnt++;
+ }
+}
+
+QString ModelData::thrTraceSrcToString() const
+{
+ return thrTraceSrcToString((int)thrTraceSrc);
+}
+
+QString ModelData::thrTraceSrcToString(const int index) const
+{
+ Firmware * firmware = getCurrentFirmware();
+ const Boards board = Boards(getCurrentBoard());
+ const int pscnt = board.getCapability(Board::Pots) + board.getCapability(Board::Sliders);
+
+ if (index == 0)
+ return tr("THR");
+ else if (index <= pscnt)
+ return board.getAnalogInputName(index + board.getCapability(Board::Sticks) - 1);
+ else if (index <= pscnt + firmware->getCapability(Outputs))
+ return RawSource(SOURCE_TYPE_CH, index - pscnt - 1).toString(this);
+
+ return QString(CPN_STR_UNKNOWN_ITEM);
+}
+
+int ModelData::thrTraceSrcCount() const
+{
+ const Boards board = Boards(getCurrentBoard());
+ Firmware * firmware = getCurrentFirmware();
+
+ return 1 + board.getCapability(Board::Pots) + board.getCapability(Board::Sliders) + firmware->getCapability(Outputs);
+}
+
+bool ModelData::isThrTraceSrcAvailable(const GeneralSettings * generalSettings, const int index) const
+{
+ const Boards board = Boards(getCurrentBoard());
+
+ if (index > 0 && index <= board.getCapability(Board::Pots) + board.getCapability(Board::Sliders))
+ return RawSource(SOURCE_TYPE_STICK, index + board.getCapability(Board::Sticks) - 1).isAvailable(this, generalSettings, board.getBoardType());
+ else
+ return true;
+}
+
+void ModelData::limitsClear(const int index)
+{
+ if (index < 0 || index >= CPN_MAX_CHNOUT)
+ return;
+
+ if (!limitData[index].isEmpty()) {
+ limitData[index].clear();
+ updateAllReferences(REF_UPD_TYPE_CHANNEL, REF_UPD_ACT_CLEAR, index);
+ }
+}
+
+void ModelData::limitsClearAll()
+{
+ for (int i = 0; i < CPN_MAX_CHNOUT; i++) {
+ limitsClear(i);
+ }
+}
+
+void ModelData::limitsDelete(const int index)
+{
+ if (index < 0 || index >= CPN_MAX_CHNOUT)
+ return;
+
+ memmove(&limitData[index], &limitData[index + 1], (CPN_MAX_CHNOUT - (index + 1)) * sizeof(LimitData));
+ limitData[CPN_MAX_CHNOUT - 1].clear();
+ updateAllReferences(REF_UPD_TYPE_CHANNEL, REF_UPD_ACT_SHIFT, index, 0, -1);
+}
+
+void ModelData::limitsGet(const int index, QByteArray & data)
+{
+ if (index < 0 || index >= CPN_MAX_CHNOUT)
+ return;
+
+ data.append((char*)&limitData[index], sizeof(LimitData));
+}
+
+void ModelData::limitsInsert(const int index)
+{
+ if (index < 0 || index >= CPN_MAX_CHNOUT)
+ return;
+
+ memmove(&limitData[index + 1], &limitData[index], (CPN_MAX_CHNOUT - (index + 1)) * sizeof(LimitData));
+ limitData[index].clear();
+ updateAllReferences(REF_UPD_TYPE_CHANNEL, REF_UPD_ACT_SHIFT, index, 0, 1);
+}
+
+void ModelData::limitsMove(const int index, const int offset)
+{
+ if (index + offset < 0 || index + offset >= CPN_MAX_CHNOUT)
+ return;
+
+ int idx1 = index;
+ int idx2;
+ const int direction = offset < 0 ? -1 : 1;
+ const int cnt = abs(offset);
+
+ for (int i = 1; i <= cnt; i++) {
+ idx2 = idx1 + direction;
+ LimitData tmp = limitData[idx2];
+ LimitData *d1 = &limitData[idx1];
+ LimitData *d2 = &limitData[idx2];
+ memcpy(d2, d1, sizeof(LimitData));
+ memcpy(d1, &tmp, sizeof(LimitData));
+ updateAllReferences(REF_UPD_TYPE_CHANNEL, REF_UPD_ACT_SWAP, idx1, idx2);
+ idx1 += direction;
+ }
+}
+
+void ModelData::limitsSet(const int index, const QByteArray & data)
+{
+ if (index < 0 || index >= CPN_MAX_CHNOUT || data.size() < (int)sizeof(LimitData))
+ return;
+
+ memcpy(&limitData[index], data.constData(), sizeof(LimitData));
+}
diff --git a/companion/src/firmwares/modeldata.h b/companion/src/firmwares/modeldata.h
index df5c6d33d..f834a0779 100644
--- a/companion/src/firmwares/modeldata.h
+++ b/companion/src/firmwares/modeldata.h
@@ -18,17 +18,22 @@
* GNU General Public License for more details.
*/
-#ifndef MODELDATA_H
-#define MODELDATA_H
+#pragma once
#include "constants.h"
+#include "curvedata.h"
#include "customfunctiondata.h"
#include "gvardata.h"
-#include "io_data.h"
+#include "flightmodedata.h"
+#include "heli_data.h"
+#include "input_data.h"
#include "logicalswitchdata.h"
+#include "mixdata.h"
#include "moduledata.h"
+#include "output_data.h"
#include "sensordata.h"
#include "telem_data.h"
+#include "timerdata.h"
#include
@@ -51,32 +56,6 @@ class RSSIAlarmData {
}
};
-#define TIMER_NAME_LEN 8
-
-class TimerData {
- Q_DECLARE_TR_FUNCTIONS(TimerData)
-
- public:
- enum CountDownMode {
- COUNTDOWN_SILENT,
- COUNTDOWN_BEEPS,
- COUNTDOWN_VOICE,
- COUNTDOWN_HAPTIC
- };
- TimerData() { clear(); }
- RawSwitch mode;
- char name[TIMER_NAME_LEN+1];
- bool minuteBeep;
- unsigned int countdownBeep;
- unsigned int val;
- unsigned int persistent;
- int pvalue;
- void clear() { memset(reinterpret_cast(this), 0, sizeof(TimerData)); mode = RawSwitch(SWITCH_TYPE_TIMER_MODE, 0); }
- void convert(RadioDataConversionState & cstate);
- bool isEmpty();
- bool isModeOff() { return mode == RawSwitch(SWITCH_TYPE_TIMER_MODE, 0); }
-};
-
#define CPN_MAX_SCRIPTS 9
#define CPN_MAX_SCRIPT_INPUTS 10
class ScriptData {
@@ -181,6 +160,7 @@ class ModelData {
unsigned int thrTraceSrc;
uint64_t switchWarningStates;
unsigned int switchWarningEnable;
+ unsigned int thrTrimSwitch;
unsigned int potsWarningMode;
bool potsWarnEnabled[CPN_MAX_POTS];
int potsWarnPosition[CPN_MAX_POTS];
@@ -281,6 +261,18 @@ class ModelData {
bool hasExpoChildren(const int index);
bool hasExpoSiblings(const int index);
void removeMix(const int idx);
+ QString thrTraceSrcToString() const;
+ QString thrTraceSrcToString(const int index) const;
+ int thrTraceSrcCount() const;
+ bool isThrTraceSrcAvailable(const GeneralSettings * generalSettings, const int index) const;
+
+ void limitsClear(const int index);
+ void limitsClearAll();
+ void limitsDelete(const int index);
+ void limitsGet(const int index, QByteArray & data);
+ void limitsInsert(const int index);
+ void limitsMove(const int index, const int offset);
+ void limitsSet(const int index, const QByteArray & data);
protected:
void removeGlobalVar(int & var);
@@ -297,6 +289,7 @@ class ModelData {
int shift;
int updcnt;
int maxindex;
+ int occurences;
RawSourceType srcType;
RawSwitchType swtchType;
};
@@ -314,6 +307,7 @@ class ModelData {
void updateDestCh(MixData * md);
void updateLimitCurveRef(CurveReference & crv);
void updateFlightModeFlags(unsigned int & flags);
+ void updateTelemetryRef(int & idx);
void updateTelemetryRef(unsigned int & idx);
void updateModuleFailsafes(ModuleData * md);
inline void updateSourceRef(RawSource & src) { updateTypeIndexRef(src, updRefInfo.srcType); }
@@ -333,6 +327,6 @@ class ModelData {
if (value != swtch.toValue())
value = swtch.toValue();
}
+ void sortMixes();
+ void updateResetParam(CustomFunctionData * cfd);
};
-
-#endif // MODELDATA_H
diff --git a/companion/src/firmwares/moduledata.cpp b/companion/src/firmwares/moduledata.cpp
index c899632af..49a079d79 100644
--- a/companion/src/firmwares/moduledata.cpp
+++ b/companion/src/firmwares/moduledata.cpp
@@ -45,19 +45,6 @@ bool ModuleData::isPxx2Module() const
}
}
-bool ModuleData::isPxx1Module() const
-{
- switch(protocol){
- case PULSES_PXX_XJT_X16:
- case PULSES_PXX_R9M:
- case PULSES_PXX_R9M_LITE:
- case PULSES_PXX_R9M_LITE_PRO:
- return true;
- default:
- return false;
- }
-}
-
bool ModuleData::supportRxNum() const
{
switch (protocol) {
@@ -66,6 +53,7 @@ bool ModuleData::supportRxNum() const
case PULSES_PXX_R9M_LITE:
case PULSES_PXX_R9M_LITE_PRO:
case PULSES_MULTIMODULE:
+ case PULSES_CROSSFIRE:
case PULSES_ACCESS_ISRM:
case PULSES_ACCST_ISRM_D16:
case PULSES_ACCESS_R9M:
@@ -160,7 +148,8 @@ QString ModuleData::protocolToString(unsigned protocol)
"FrSky ACCESS R9M Lite",
"FrSky ACCESS R9M Lite Pro",
"FrSky XJT lite (D16)", "FrSky XJT lite (D8)", "FrSky XJT lite (LR12)",
- "AFHDS3"
+ "AFHDS3",
+ "ImmersionRC Ghost"
};
return CHECK_IN_ARRAY(strings, protocol);
@@ -221,6 +210,7 @@ int ModuleData::getMaxChannelCount()
case PULSES_XJT_LITE_X16:
case PULSES_PXX_XJT_X16:
case PULSES_CROSSFIRE:
+ case PULSES_GHOST:
case PULSES_SBUS:
case PULSES_PPM:
return 16;
diff --git a/companion/src/firmwares/moduledata.h b/companion/src/firmwares/moduledata.h
index d3e851879..8acec18b0 100644
--- a/companion/src/firmwares/moduledata.h
+++ b/companion/src/firmwares/moduledata.h
@@ -59,6 +59,7 @@ enum PulsesProtocol {
PULSES_XJT_LITE_D8,
PULSES_XJT_LITE_LR12,
PULSES_AFHDS3,
+ PULSES_GHOST,
PULSES_PROTOCOL_LAST
};
@@ -83,7 +84,7 @@ enum MultiModuleRFProtocols {
MODULE_SUBTYPE_MULTI_MJXQ,
MODULE_SUBTYPE_MULTI_SHENQI,
MODULE_SUBTYPE_MULTI_FY326,
- MODULE_SUBTYPE_MULTI_SFHSS,
+ MODULE_SUBTYPE_MULTI_FUTABA,
MODULE_SUBTYPE_MULTI_J6PRO,
MODULE_SUBTYPE_MULTI_FQ777,
MODULE_SUBTYPE_MULTI_ASSAN,
@@ -114,7 +115,7 @@ enum MultiModuleRFProtocols {
MODULE_SUBTYPE_MULTI_REDPINE,
MODULE_SUBTYPE_MULTI_POTENSIC,
MODULE_SUBTYPE_MULTI_ZSX,
- MODULE_SUBTYPE_MULTI_FLYZONE,
+ MODULE_SUBTYPE_MULTI_HEIGHT,
MODULE_SUBTYPE_MULTI_SCANNER,
MODULE_SUBTYPE_MULTI_FRSKYX_RX,
MODULE_SUBTYPE_MULTI_AFHDS2A_RX,
@@ -134,7 +135,15 @@ enum MultiModuleRFProtocols {
MODULE_SUBTYPE_MULTI_DSM_RX,
MODULE_SUBTYPE_MULTI_JJRC345,
MODULE_SUBTYPE_MULTI_Q90C,
- MODULE_SUBTYPE_MULTI_LAST = MODULE_SUBTYPE_MULTI_Q90C
+ MODULE_SUBTYPE_MULTI_KYOSHO,
+ MODULE_SUBTYPE_MULTI_RLINK,
+ MODULE_SUBTYPE_MULTI_ELRS,
+ MODULE_SUBTYPE_MULTI_REALACC,
+ MODULE_SUBTYPE_MULTI_OMP,
+ MODULE_SUBTYPE_MULTI_MLINK,
+ MODULE_SUBTYPE_MULTI_WFLY2,
+ MODULE_SUBTYPE_MULTI_E016HV2,
+ MODULE_SUBTYPE_MULTI_LAST = MODULE_SUBTYPE_MULTI_E016HV2
};
enum TrainerProtocol {
@@ -206,12 +215,12 @@ class ModuleData {
struct Access {
unsigned int receivers;
char receiverName[PXX2_MAX_RECEIVERS_PER_MODULE][PXX2_LEN_RX_NAME+1];
+ unsigned int racingMode;
} access;
void clear() { memset(this, 0, sizeof(ModuleData)); }
void convert(RadioDataConversionState & cstate);
bool isPxx2Module() const;
- bool isPxx1Module() const;
bool supportRxNum() const;
QString polarityToString() const { return ppm.pulsePol ? tr("Positive") : tr("Negative"); }
QString rfProtocolToString() const;
diff --git a/companion/src/firmwares/multiprotocols.cpp b/companion/src/firmwares/multiprotocols.cpp
index c8c18e6e5..1aedbc7d5 100644
--- a/companion/src/firmwares/multiprotocols.cpp
+++ b/companion/src/firmwares/multiprotocols.cpp
@@ -55,8 +55,9 @@ static const QStringList STR_SUBTYPE_ESky {"Standard", "ET4"};
static const QStringList STR_SUBTYPE_MT99 {"MT99", "H7", "YZ", "LS", "FY805"};
static const QStringList STR_SUBTYPE_MJXQ {"WLH08", "X600", "X800", "H26D", "E010", "H26WH", "Phoenix"};
static const QStringList STR_SUBTYPE_FY326 {"Standard", "FY319"};
+static const QStringList STR_SUBTYPE_FUTABA {"SFHSS"};
static const QStringList STR_SUBTYPE_HONTAI {"Standard", "JJRC X1", "X5C1 Clone", "FQ777_951"};
-static const QStringList STR_SUBTYPE_AFHDS2A {"PWM and IBUS", "PPM and IBUS", "PWM and SBUS", "PPM and SBUS"};
+static const QStringList STR_SUBTYPE_AFHDS2A {"PWM and IBUS", "PPM and IBUS", "PWM and SBUS", "PPM and SBUS", "PWM and IBUS16", "PPM and IBUS16"};
static const QStringList STR_SUBTYPE_Q2X2 {"Q222", "Q242", "Q282"};
static const QStringList STR_SUBTYPE_WK2x01 {"WK2801", "WK2401", "W6_5_1", "W6_6_1", "W6_HEL", "W6_HEL_I"};
static const QStringList STR_SUBTYPE_Q303 {"Standard", "CX35", "CX10D", "CX10WD"};
@@ -65,7 +66,7 @@ static const QStringList STR_SUBTYPE_ESKY150 {"4 Channel", "7 Channel"};
static const QStringList STR_SUBTYPE_H83D {"H8 Mini 3D", "H20H", "H20 Mini", "H30 Mini"};
static const QStringList STR_SUBTYPE_CORONA {"Corona V1", "Corona V2", "Flydream V3"};
static const QStringList STR_SUBTYPE_HITEC {"Optima", "Optima Hub Telem", "Minima"};
-static const QStringList STR_SUBTYPE_WFLY {"WFR0xS"};
+static const QStringList STR_SUBTYPE_WFLY {"WFR0x"};
static const QStringList STR_SUBTYPE_BUGS_MINI {"Standard", "Bugs 3H"};
static const QStringList STR_SUBTYPE_TRAXXAS {"6519 RX"};
static const QStringList STR_SUBTYPE_E01X {"E012", "E015", "E016H"};
@@ -75,18 +76,24 @@ static const QStringList STR_SUBTYPE_V761 {"3 Channel", "4 Channel"};
static const QStringList STR_SUBTYPE_REDPINE {"Fast", "Slow"};
static const QStringList STR_SUBTYPE_POTENSIC {"A20 Firefly"};
static const QStringList STR_SUBTYPE_ZSX {"JJRC ZSX-280"};
-static const QStringList STR_SUBTYPE_FLYZONE {"FZ-410 TX"};
+static const QStringList STR_SUBTYPE_HEIGHT {"5 Channel", "8 Channel"};
static const QStringList STR_SUBTYPE_FRSKYX_RX {"RX", "Clone TX"};
static const QStringList STR_SUBTYPE_HOTT {"Sync", "No_Sync"};
static const QStringList STR_SUBTYPE_FX816 {"P38"};
static const QStringList STR_SUBTYPE_PELIKAN {"Pro", "Lite"};
static const QStringList STR_SUBTYPE_XK {"X450", "X420"};
static const QStringList STR_SUBTYPE_XN297DUMP {"250K", "1M", "2M", "AUTO", "NRF"};
-static const QStringList STR_SUBTYPE_FRSKYX2 {"D16", "D16 8ch", "D16 EU-LBT", "D16 EU-LBT 8ch", "D16 Cloned"};
-static const QStringList STR_SUBTYPE_FRSKYR9 {"915 MHz", "868 MHz", "915 MHz 8-Channel", "868 MHz 8-Channel"};
+static const QStringList STR_SUBTYPE_FRSKYX2 {"D16", "D16 8ch", "D16 EU-LBT", "D16 EU-LBT 8ch", "Cloned", "Cloned 8ch"};
+static const QStringList STR_SUBTYPE_FRSKYR9 {"915 MHz", "868 MHz", "915 MHz 8-Channel", "868 MHz 8-Channel", "FCC", "---", "FCC 8-Channel"};
static const QStringList STR_SUBTYPE_PROPEL {"74-Z"};
static const QStringList STR_SUBTYPE_FRSKYL {"LR12", "LR12 6-Channel"};
static const QStringList STR_SUBTYPE_ESKY150V2 {"150 V2"};
+static const QStringList STR_SUBTYPE_JJRC345 {"Standard", "SkyTumbler"};
+static const QStringList STR_SUBTYPE_KYOSHO {"FHSS", "Hype"};
+static const QStringList STR_SUBTYPE_RLINK {"Surface", "Air", "DumboRC"};
+static const QStringList STR_SUBTYPE_ELRS {"Not Available WIP"};
+static const QStringList STR_SUBTYPE_REALACC {"R11"};
+static const QStringList STR_SUBTYPE_WFLY2 {"RF20x"};
static const QStringList NO_SUBTYPE {STR_MULTI_DEFAULT};
@@ -112,11 +119,11 @@ const Multiprotocols multiProtocols {
{MODULE_SUBTYPE_MULTI_MT99XX, 4, false, STR_SUBTYPE_MT99, nullptr},
{MODULE_SUBTYPE_MULTI_MJXQ, 6, false, STR_SUBTYPE_MJXQ, STR_MULTI_RFTUNE},
{MODULE_SUBTYPE_MULTI_FY326, 1, false, STR_SUBTYPE_FY326, nullptr},
- {MODULE_SUBTYPE_MULTI_SFHSS, 0, true, NO_SUBTYPE, STR_MULTI_RFTUNE},
+ {MODULE_SUBTYPE_MULTI_FUTABA, 0, true, STR_SUBTYPE_FUTABA, STR_MULTI_RFTUNE},
{MODULE_SUBTYPE_MULTI_J6PRO, 0, false, NO_SUBTYPE, nullptr},
{MODULE_SUBTYPE_MULTI_HONTAI, 3, false, STR_SUBTYPE_HONTAI, nullptr},
{MODULE_SUBTYPE_MULTI_OLRS, 0, false, NO_SUBTYPE, STR_MULTI_RFPOWER},
- {MODULE_SUBTYPE_MULTI_FS_AFHDS2A, 3, true, STR_SUBTYPE_AFHDS2A, STR_MULTI_SERVOFREQ},
+ {MODULE_SUBTYPE_MULTI_FS_AFHDS2A, 5, true, STR_SUBTYPE_AFHDS2A, STR_MULTI_SERVOFREQ},
{MODULE_SUBTYPE_MULTI_Q2X2, 2, false, STR_SUBTYPE_Q2X2, nullptr},
{MODULE_SUBTYPE_MULTI_WK_2X01, 5, false, STR_SUBTYPE_WK2x01, nullptr},
{MODULE_SUBTYPE_MULTI_Q303, 3, false, STR_SUBTYPE_Q303, nullptr},
@@ -136,20 +143,28 @@ const Multiprotocols multiProtocols {
{MODULE_SUBTYPE_MULTI_REDPINE, 1, false, STR_SUBTYPE_REDPINE, STR_MULTI_RFTUNE},
{MODULE_SUBTYPE_MULTI_POTENSIC, 0, false, STR_SUBTYPE_POTENSIC, nullptr},
{MODULE_SUBTYPE_MULTI_ZSX, 0, false, STR_SUBTYPE_ZSX, nullptr},
- {MODULE_SUBTYPE_MULTI_FLYZONE, 0, false, STR_SUBTYPE_FLYZONE, nullptr},
+ {MODULE_SUBTYPE_MULTI_HEIGHT, 1, false, STR_SUBTYPE_HEIGHT, nullptr},
{MODULE_SUBTYPE_MULTI_FRSKYX_RX, 1, false, STR_SUBTYPE_FRSKYX_RX, STR_MULTI_RFTUNE},
{MODULE_SUBTYPE_MULTI_HOTT, 1, true, STR_SUBTYPE_HOTT, STR_MULTI_RFTUNE},
{MODULE_SUBTYPE_MULTI_FX816, 0, false, STR_SUBTYPE_FX816, nullptr},
{MODULE_SUBTYPE_MULTI_PELIKAN, 1, false, STR_SUBTYPE_PELIKAN, nullptr},
{MODULE_SUBTYPE_MULTI_XK, 1, false, STR_SUBTYPE_XK, STR_MULTI_RFTUNE},
{MODULE_SUBTYPE_MULTI_XN297DUMP, 4, false, STR_SUBTYPE_XN297DUMP, nullptr},
- {MODULE_SUBTYPE_MULTI_FRSKYX2, 4, true, STR_SUBTYPE_FRSKYX2, STR_MULTI_RFTUNE},
- {MODULE_SUBTYPE_MULTI_FRSKY_R9, 3, true, STR_SUBTYPE_FRSKYR9, nullptr},
+ {MODULE_SUBTYPE_MULTI_FRSKYX2, 5, true, STR_SUBTYPE_FRSKYX2, STR_MULTI_RFTUNE},
+ {MODULE_SUBTYPE_MULTI_FRSKY_R9, 6, true, STR_SUBTYPE_FRSKYR9, nullptr},
{MODULE_SUBTYPE_MULTI_PROPEL, 0, false, STR_SUBTYPE_PROPEL, nullptr},
{MODULE_SUBTYPE_MULTI_FRSKYL, 1, false, STR_SUBTYPE_FRSKYL, STR_MULTI_RFTUNE},
{MODULE_SUBTYPE_MULTI_SKYARTEC, 0, false, NO_SUBTYPE, STR_MULTI_RFTUNE},
{MODULE_SUBTYPE_MULTI_ESKY150V2, 0, false, STR_SUBTYPE_ESKY150V2, STR_MULTI_RFTUNE},
+ {MODULE_SUBTYPE_MULTI_JJRC345, 1, false, STR_SUBTYPE_JJRC345, nullptr},
{MODULE_SUBTYPE_MULTI_Q90C, 0, false, NO_SUBTYPE, STR_MULTI_RFTUNE},
+ {MODULE_SUBTYPE_MULTI_KYOSHO, 1, false, STR_SUBTYPE_KYOSHO, nullptr},
+ {MODULE_SUBTYPE_MULTI_RLINK, 2, false, STR_SUBTYPE_RLINK, STR_MULTI_RFTUNE},
+ {MODULE_SUBTYPE_MULTI_ELRS, 0, false, STR_SUBTYPE_ELRS, nullptr},
+ {MODULE_SUBTYPE_MULTI_REALACC, 0, false, STR_SUBTYPE_REALACC, nullptr},
+ {MODULE_SUBTYPE_MULTI_OMP, 0, false, NO_SUBTYPE, STR_MULTI_RFTUNE},
+ {MODULE_SUBTYPE_MULTI_WFLY2, 0, false, STR_SUBTYPE_WFLY2, STR_MULTI_OPTION},
+ {MODULE_SUBTYPE_MULTI_E016HV2, 0, false, NO_SUBTYPE, STR_MULTI_RFTUNE},
{MM_RF_CUSTOM_SELECTED, 7, true, STR_SUBTYPE_CUSTOM, STR_MULTI_OPTION},
// Sentinel and default for protocols not listed above (MM_RF_CUSTOM is 0xff)
@@ -189,12 +204,13 @@ QString Multiprotocols::protocolToString(int protocol, bool custom)
{
static const QStringList strings({
"FlySky", "Hubsan", "FrSky", "Hisky", "V2x2", "DSM", "Devo", "YD717", "KN", "SymaX", "SLT", "CX10", "CG023",
- "Bayang", "ESky", "MT99XX", "MJXQ", "Shenqi", "FY326", "SFHSS", "J6 PRO","FQ777","Assan","Hontai","Open LRS",
+ "Bayang", "ESky", "MT99XX", "MJXQ", "Shenqi", "FY326", "Futaba", "J6 PRO","FQ777","Assan","Hontai","Open LRS",
"FlySky AFHDS2A", "Q2x2", "WK2x01", "Q303", "GW008", "DM002", "Cabell", "ESky 150", "H8 3D", "Corona", "CFlie",
"Hitec", "Wfly", "Bugs", "Bugs Mini", "Traxxas", "NCC-1701-A", "E01X", "WL Heli V911S", "GD00X", "Volantex V761",
- "KFPlan KF606", "Redpine", "Potensic", "ZSX", "FlyZone", "Scanner", "FrSky RX", "FlySky AFHDS2A RX", "HoTT", "Fx816",
+ "KFPlan KF606", "Redpine", "Potensic", "ZSX", "Height", "Scanner", "FrSky RX", "FlySky AFHDS2A RX", "HoTT", "Fx816",
"Bayang RX", "Pelikan", "Tiger", "XK", "XN297 Dump", "FrSky X 2.1", "FrSky R9", "Propel", "FrSky L", "Skyartec",
- "ESky 150v2", "DSM RX", "JJRC345", "Q90C"
+ "ESky 150v2", "DSM RX", "JJRC345", "Q90C", "Kyosho", "RadioLink", "ExpressLRS", "Realacc", "OMP", "M-Link", "Wfly 2",
+ "E016H v2"
});
return strings.value(protocol, CPN_STR_UNKNOWN_ITEM);
diff --git a/companion/src/firmwares/opentx/opentxeeprom.cpp b/companion/src/firmwares/opentx/opentxeeprom.cpp
index b7e4d8644..59caa99dd 100644
--- a/companion/src/firmwares/opentx/opentxeeprom.cpp
+++ b/companion/src/firmwares/opentx/opentxeeprom.cpp
@@ -45,7 +45,10 @@ inline int MAX_SWITCHES(Board::Type board, int version)
if (IS_TARANIS_X9D(board))
return 9;
- if (IS_JUMPER_T12(board))
+ if (IS_FAMILY_T12(board))
+ return 8;
+
+ if (IS_TARANIS_X7(board))
return 8;
return Boards::getCapability(board, Board::Switches);
@@ -73,6 +76,8 @@ inline int MAX_POTS(Board::Type board, int version)
{
if (version <= 218 && IS_FAMILY_HORUS_OR_T16(board))
return 3;
+ if (IS_FAMILY_T12(board))
+ return 2;
return Boards::getCapability(board, Board::Pots);
}
@@ -82,6 +87,8 @@ inline int MAX_POTS_STORAGE(Board::Type board, int version)
return 3;
if (version >= 219 && IS_FAMILY_HORUS_OR_T16(board))
return 5;
+ if (IS_FAMILY_T12(board))
+ return 2;
return Boards::getCapability(board, Board::Pots);
}
@@ -89,6 +96,8 @@ inline int MAX_POTS_SOURCES(Board::Type board, int version)
{
if (version <= 218 && IS_FAMILY_HORUS_OR_T16(board))
return 5;
+ if (IS_FAMILY_T12(board))
+ return 2;
return Boards::getCapability(board, Board::Pots);
}
@@ -128,6 +137,14 @@ inline int SWITCHES_CONFIG_SIZE(Board::Type board, int version)
return 16;
}
+inline int MAX_MOUSE_ANALOG_SOURCES(Board::Type board, int version)
+{
+ if (IS_FAMILY_HORUS_OR_T16(board))
+ return 2;
+ else
+ return 0;
+}
+
#define MAX_ROTARY_ENCODERS(board) 0
#define MAX_FLIGHT_MODES(board, version) 9
#define MAX_TIMERS(board, version) 3
@@ -300,7 +317,7 @@ class SourcesConversionTable: public ConversionTable {
}
}
- for (int i=0; i= CPN_MAX_STICKS + MAX_POTS_STORAGE(board, version))
offset += 2;
@@ -1398,8 +1415,7 @@ class CustomFunctionsConversionTable: public ConversionTable {
addConversion(FuncAdjustGV1+i, val);
val++;
addConversion(FuncVolume, val++);
- addConversion(FuncSetFailsafeInternalModule, val);
- addConversion(FuncSetFailsafeExternalModule, val++);
+ addConversion(FuncSetFailsafe, val++);
addConversion(FuncRangeCheckInternalModule, val);
addConversion(FuncRangeCheckExternalModule, val++);
addConversion(FuncBindInternalModule, val);
@@ -1512,9 +1528,6 @@ class ArmCustomFunctionField: public TransformedField {
*((uint16_t *)_param) = fn.param;
*((uint8_t *)(_param+3)) = fn.func - FuncSetTimer1;
}
- else if (fn.func >= FuncSetFailsafeInternalModule && fn.func <= FuncSetFailsafeExternalModule) {
- *((uint16_t *)_param) = fn.func - FuncSetFailsafeInternalModule;
- }
else if (fn.func >= FuncRangeCheckInternalModule && fn.func <= FuncRangeCheckExternalModule) {
*((uint16_t *)_param) = fn.func - FuncRangeCheckInternalModule;
}
@@ -1536,7 +1549,7 @@ class ArmCustomFunctionField: public TransformedField {
value = fn.param;
*((uint16_t *)_param) = value;
}
- else if (fn.func == FuncPlayValue || fn.func == FuncVolume) {
+ else if (fn.func == FuncPlayValue || fn.func == FuncVolume || fn.func == FuncBacklight) {
unsigned int value;
sourcesConversionTable->exportValue(fn.param, (int &)value);
*((uint16_t *)_param) = value;
@@ -1579,7 +1592,7 @@ class ArmCustomFunctionField: public TransformedField {
else if (fn.func == FuncPlayPrompt || fn.func == FuncBackgroundMusic || fn.func == FuncPlayScript) {
memcpy(fn.paramarm, _param, sizeof(fn.paramarm));
}
- else if (fn.func == FuncVolume) {
+ else if (fn.func == FuncVolume || fn.func == FuncBacklight) {
sourcesConversionTable->importValue(value, (int &)fn.param);
}
else if (fn.func >= FuncAdjustGV1 && fn.func <= FuncAdjustGVLast) {
@@ -2145,15 +2158,16 @@ class ModuleUnionField: public UnionField {
module(module)
{
internalField.Append(new UnsignedField<3>(this, module.access.receivers));
- internalField.Append(new SpareBitsField<5>(this));
+ internalField.Append(new SpareBitsField<4>(this));
+ internalField.Append(new UnsignedField<1>(this, module.access.racingMode));
- for (int i=0; i(this, receiverName[i]));
memset(receiverName, 0, sizeof(receiverName));
}
- bool select(const unsigned int& attr) const override
+ bool select(const unsigned int & attr) const override
{
return attr >= PULSES_ACCESS_ISRM && attr <= PULSES_ACCESS_R9M_LITE_PRO;
}
@@ -2298,7 +2312,8 @@ OpenTxModelData::OpenTxModelData(ModelData & modelData, Board::Type board, unsig
internalField.Append(new UnsignedField<2>(this, modelData.timers[i].countdownBeep));
internalField.Append(new BoolField<1>(this, modelData.timers[i].minuteBeep));
internalField.Append(new UnsignedField<2>(this, modelData.timers[i].persistent));
- internalField.Append(new SpareBitsField<3>(this));
+ internalField.Append(new SignedField<2>(this, modelData.timers[i].countdownStart));
+ internalField.Append(new UnsignedField<1>(this, modelData.timers[i].direction));
if (HAS_LARGE_LCD(board))
internalField.Append(new ZCharField<8>(this, modelData.timers[i].name, "Timer name"));
else
@@ -2413,7 +2428,8 @@ OpenTxModelData::OpenTxModelData(ModelData & modelData, Board::Type board, unsig
internalField.Append(new UnsignedField<2>(this, modelData.potsWarningMode));
}
else {
- internalField.Append(new SpareBitsField<6>(this));
+ internalField.Append(new SpareBitsField<3>(this));
+ internalField.Append(new UnsignedField<3>(this, modelData.thrTrimSwitch));
internalField.Append(new UnsignedField<2>(this, modelData.potsWarningMode));
}
@@ -2569,7 +2585,7 @@ OpenTxGeneralData::OpenTxGeneralData(GeneralSettings & generalData, Board::Type
generalData(generalData),
board(board),
version(version),
- inputsCount(CPN_MAX_STICKS + MAX_POTS_STORAGE(board, version) + MAX_SLIDERS_STORAGE(board, version) + Boards::getCapability(board, Board::MouseAnalogs))
+ inputsCount(CPN_MAX_STICKS + MAX_POTS_STORAGE(board, version) + MAX_SLIDERS_STORAGE(board, version) + MAX_MOUSE_ANALOG_SOURCES(board, version))
{
qCDebug(eepromImport) << QString("OpenTxGeneralData::OpenTxGeneralData(board: %1, version:%2, variant:%3)").arg(board).arg(version).arg(variant);
@@ -2711,7 +2727,7 @@ OpenTxGeneralData::OpenTxGeneralData(GeneralSettings & generalData, Board::Type
internalField.Append(new BoolField<1>(this, generalData.disableRssiPoweroffAlarm));
internalField.Append(new UnsignedField<2>(this, generalData.usbMode));
internalField.Append(new UnsignedField<2>(this, generalData.jackMode));
- internalField.Append(new SpareBitsField<1>(this));
+ internalField.Append(new BoolField<1>(this, generalData.sportPower));
}
else {
internalField.Append(new SpareBitsField<7>(this));
diff --git a/companion/src/firmwares/opentx/opentxeeprom.h b/companion/src/firmwares/opentx/opentxeeprom.h
index 29d5b0b93..c3395693d 100644
--- a/companion/src/firmwares/opentx/opentxeeprom.h
+++ b/companion/src/firmwares/opentx/opentxeeprom.h
@@ -36,6 +36,9 @@
#define TARANIS_X9LITE_VARIANT 0x0800
#define TARANIS_X9LITES_VARIANT 0x0801
#define JUMPER_T12_VARIANT 0x4001
+#define RADIOMASTER_TX12_VARIANT 0x4002
+#define JUMPER_TLITE_VARIANT 0x4003
+#define RADIOMASTER_T8_VARIANT 0x4004
class OpenTxGeneralData: public TransformedField {
public:
@@ -96,7 +99,7 @@ class ProtocolsConversionTable: public ConversionTable
addConversion(PULSES_ACCESS_R9M, val++);
addConversion(PULSES_PXX_R9M_LITE, val++);
addConversion(PULSES_ACCESS_R9M_LITE, val++);
- addConversion(PULSES_PXX_R9M_LITE_PRO, val++);
+ addConversion(PULSES_GHOST, val++);
addConversion(PULSES_ACCESS_R9M_LITE_PRO, val++);
addConversion(PULSES_SBUS, val++);
@@ -104,6 +107,7 @@ class ProtocolsConversionTable: public ConversionTable
addConversion(PULSES_XJT_LITE_X16, val);
addConversion(PULSES_XJT_LITE_D8, val);
addConversion(PULSES_XJT_LITE_LR12, val++);
+
if (version >= 219) {
addConversion(PULSES_AFHDS3, val++);
}
diff --git a/companion/src/firmwares/opentx/opentxinterface.cpp b/companion/src/firmwares/opentx/opentxinterface.cpp
index 75aab7b64..1190062c5 100644
--- a/companion/src/firmwares/opentx/opentxinterface.cpp
+++ b/companion/src/firmwares/opentx/opentxinterface.cpp
@@ -60,12 +60,18 @@ const char * OpenTxEepromInterface::getName()
switch (board) {
case BOARD_JUMPER_T12:
return "OpenTX for Jumper T12";
+ case BOARD_JUMPER_TLITE:
+ return "OpenTX for Jumper T-Lite";
case BOARD_JUMPER_T16:
return "OpenTX for Jumper T16";
case BOARD_JUMPER_T18:
return "OpenTX for Jumper T18";
case BOARD_RADIOMASTER_TX16S:
return "OpenTX for Radiomaster TX16S";
+ case BOARD_RADIOMASTER_TX12:
+ return "OpenTX for Radiomaster TX12";
+ case BOARD_RADIOMASTER_T8:
+ return "OpenTX for Radiomaster T8";
case BOARD_TARANIS_X9D:
return "OpenTX for FrSky Taranis X9D";
case BOARD_TARANIS_X9DP:
@@ -334,7 +340,15 @@ int OpenTxEepromInterface::save(uint8_t * eeprom, const RadioData & radioData, u
else if (IS_JUMPER_T12(board)) {
variant |= JUMPER_T12_VARIANT;
}
-
+ else if (IS_JUMPER_TLITE(board)) {
+ variant |= JUMPER_TLITE_VARIANT;
+ }
+ else if (IS_RADIOMASTER_TX12(board)) {
+ variant |= RADIOMASTER_TX12_VARIANT;
+ }
+ else if (IS_RADIOMASTER_T8(board)) {
+ variant |= RADIOMASTER_T8_VARIANT;
+ }
OpenTxGeneralData generator((GeneralSettings &)radioData.generalSettings, board, version, variant);
// generator.dump();
QByteArray data;
@@ -520,7 +534,7 @@ int OpenTxFirmware::getCapability(::Capability capability)
case MaxVolume:
return 23;
case MaxContrast:
- if (IS_TARANIS_SMALL(board) || IS_JUMPER_T12(board))
+ if (IS_TARANIS_SMALL(board))
return 30;
else
return 45;
@@ -540,7 +554,7 @@ int OpenTxFirmware::getCapability(::Capability capability)
case Simulation:
return 1;
case NumCurves:
- return (HAS_LARGE_LCD(board) ? 32 : 16);
+ return 32;
case HasMixerNames:
return (IS_TARANIS_X9(board) ? 8 : 6);
case HasExpoNames:
@@ -615,7 +629,7 @@ int OpenTxFirmware::getCapability(::Capability capability)
case LcdWidth:
if (IS_FAMILY_HORUS_OR_T16(board))
return 480;
- else if (IS_TARANIS_SMALL(board) || IS_JUMPER_T12(board))
+ else if (IS_TARANIS_SMALL(board))
return 128;
else if (IS_TARANIS(board))
return 212;
@@ -629,7 +643,7 @@ int OpenTxFirmware::getCapability(::Capability capability)
case LcdDepth:
if (IS_FAMILY_HORUS_OR_T16(board))
return 16;
- else if (IS_TARANIS_SMALL(board) || IS_JUMPER_T12(board))
+ else if (IS_TARANIS_SMALL(board))
return 1;
else if (IS_TARANIS(board))
return 4;
@@ -679,6 +693,12 @@ int OpenTxFirmware::getCapability(::Capability capability)
return TARANIS_XLITE_VARIANT;
else if (IS_JUMPER_T12(board))
return JUMPER_T12_VARIANT;
+ else if (IS_JUMPER_TLITE(board))
+ return JUMPER_TLITE_VARIANT;
+ else if (IS_RADIOMASTER_TX12(board))
+ return RADIOMASTER_TX12_VARIANT;
+ else if (IS_RADIOMASTER_T8(board))
+ return RADIOMASTER_T8_VARIANT;
else
return 0;
case MavlinkTelemetry:
@@ -696,6 +716,8 @@ int OpenTxFirmware::getCapability(::Capability capability)
return IS_FAMILY_HORUS_OR_T16(board);
case HasSwitchableJack:
return IS_TARANIS_XLITES(board);
+ case HasSportConnector:
+ return IS_ACCESS_RADIO(board, id) || IS_TARANIS_X7(board) || IS_HORUS_X10(board) || IS_TARANIS_XLITE(board);
case PwrButtonPress:
return IS_HORUS_OR_TARANIS(board) && (board!=Board::BOARD_TARANIS_X9D) && (board!=Board::BOARD_TARANIS_X9DP);
case Sensors:
@@ -731,14 +753,14 @@ bool OpenTxFirmware::isAvailable(PulsesProtocol proto, int port)
return true;
case PULSES_PXX_XJT_X16:
case PULSES_PXX_XJT_LR12:
- return !IS_ACCESS_RADIO(board, id) && !IS_FAMILY_T16(board) && !IS_JUMPER_T12(board);
+ return !IS_ACCESS_RADIO(board, id) && !IS_FAMILY_T16(board) && !IS_FAMILY_T12(board);
case PULSES_PXX_XJT_D8:
- return !(IS_ACCESS_RADIO(board, id) || id.contains("eu")) && !IS_FAMILY_T16(board) && !IS_JUMPER_T12(board);
+ return !(IS_ACCESS_RADIO(board, id) || id.contains("eu")) && !IS_FAMILY_T16(board) && !IS_FAMILY_T12(board);
case PULSES_ACCESS_ISRM:
case PULSES_ACCST_ISRM_D16:
return IS_ACCESS_RADIO(board, id);
case PULSES_MULTIMODULE:
- return id.contains("internalmulti") || IS_RADIOMASTER_TX16S(board) || IS_JUMPER_T18(board);
+ return id.contains("internalmulti") || IS_RADIOMASTER_TX16S(board) || IS_JUMPER_T18(board) || IS_RADIOMASTER_TX12(board) || IS_JUMPER_TLITE(board);
default:
return false;
}
@@ -760,16 +782,17 @@ bool OpenTxFirmware::isAvailable(PulsesProtocol proto, int port)
case PULSES_MULTIMODULE:
case PULSES_CROSSFIRE:
case PULSES_AFHDS3:
+ case PULSES_GHOST:
return true;
case PULSES_ACCESS_R9M:
- return IS_TARANIS_XLITE(board) || IS_TARANIS_X9LITE(board) || board == BOARD_TARANIS_X9DP_2019 || board == BOARD_X10_EXPRESS || (IS_FAMILY_HORUS_OR_T16(board) && id.contains("internalaccess"));
+ return IS_ACCESS_RADIO(board, id) || (IS_FAMILY_HORUS_OR_T16(board) && id.contains("externalaccessmod"));
case PULSES_PXX_R9M_LITE:
case PULSES_ACCESS_R9M_LITE:
case PULSES_ACCESS_R9M_LITE_PRO:
case PULSES_XJT_LITE_X16:
case PULSES_XJT_LITE_D8:
case PULSES_XJT_LITE_LR12:
- return (IS_TARANIS_XLITE(board) || IS_TARANIS_X9LITE(board));
+ return (IS_TARANIS_XLITE(board) || IS_TARANIS_X9LITE(board) || IS_JUMPER_TLITE(board));
default:
return false;
}
@@ -940,6 +963,21 @@ bool OpenTxEepromInterface::checkVariant(unsigned int version, unsigned int vari
variantError = true;
}
}
+ else if (IS_JUMPER_TLITE(board)) {
+ if (variant != JUMPER_TLITE_VARIANT) {
+ variantError = true;
+ }
+ }
+ else if (IS_RADIOMASTER_TX12(board)) {
+ if (variant != RADIOMASTER_TX12_VARIANT) {
+ variantError = true;
+ }
+ }
+ else if (IS_RADIOMASTER_T8(board)) {
+ if (variant != RADIOMASTER_T8_VARIANT) {
+ variantError = true;
+ }
+ }
else if (IS_TARANIS(board)) {
if (variant != 0) {
variantError = true;
@@ -1188,19 +1226,19 @@ void registerOpenTxFirmwares()
firmware->addOption("horussticks", Firmware::tr("Horus gimbals installed (Hall sensors)"));
addOpenTxTaranisOptions(firmware);
registerOpenTxFirmware(firmware);
- addOpenTxRfOptions(firmware, EU + FLEX + AFHDS3);
+ addOpenTxRfOptions(firmware, EU + FLEX);
/* FrSky X9-Lite board */
firmware = new OpenTxFirmware("opentx-x9lite", Firmware::tr("FrSky Taranis X9-Lite"), BOARD_TARANIS_X9LITE);
addOpenTxTaranisOptions(firmware);
registerOpenTxFirmware(firmware);
- addOpenTxRfOptions(firmware, FLEX + AFHDS3);
+ addOpenTxRfOptions(firmware, FLEX);
/* FrSky X9-LiteS board */
firmware = new OpenTxFirmware("opentx-x9lites", Firmware::tr("FrSky Taranis X9-Lite S"), BOARD_TARANIS_X9LITES);
addOpenTxTaranisOptions(firmware);
registerOpenTxFirmware(firmware);
- addOpenTxRfOptions(firmware, FLEX + AFHDS3);
+ addOpenTxRfOptions(firmware, FLEX);
/* FrSky X7 board */
firmware = new OpenTxFirmware("opentx-x7", Firmware::tr("FrSky Taranis X7 / X7S"), BOARD_TARANIS_X7);
@@ -1218,7 +1256,7 @@ void registerOpenTxFirmwares()
firmware = new OpenTxFirmware("opentx-xlites", Firmware::tr("FrSky Taranis X-Lite S/PRO"), BOARD_TARANIS_XLITES);
addOpenTxTaranisOptions(firmware);
registerOpenTxFirmware(firmware);
- addOpenTxRfOptions(firmware, FLEX + AFHDS3);
+ addOpenTxRfOptions(firmware, FLEX);
/* FrSky X-Lite board */
firmware = new OpenTxFirmware("opentx-xlite", Firmware::tr("FrSky Taranis X-Lite"), BOARD_TARANIS_XLITE);
@@ -1231,6 +1269,7 @@ void registerOpenTxFirmwares()
firmware = new OpenTxFirmware("opentx-x10", Firmware::tr("FrSky Horus X10 / X10S"), BOARD_X10);
addOpenTxFrskyOptions(firmware);
firmware->addOption("internalaccess", Firmware::tr("Support for ACCESS internal module replacement"));
+ firmware->addOption("externalaccessmod", Firmware::tr("Support hardware mod: R9M ACCESS"));
registerOpenTxFirmware(firmware);
addOpenTxRfOptions(firmware, EU + FLEX);
@@ -1244,6 +1283,7 @@ void registerOpenTxFirmwares()
firmware = new OpenTxFirmware("opentx-x12s", Firmware::tr("FrSky Horus X12S"), BOARD_HORUS_X12S);
addOpenTxFrskyOptions(firmware);
firmware->addOption("internalaccess", Firmware::tr("Support for ACCESS internal module replacement"));
+ firmware->addOption("externalaccessmod", Firmware::tr("Support hardware mod: R9M ACCESS"));
firmware->addOption("pcbdev", Firmware::tr("Use ONLY with first DEV pcb version"));
registerOpenTxFirmware(firmware);
addOpenTxRfOptions(firmware, EU + FLEX);
@@ -1257,29 +1297,63 @@ void registerOpenTxFirmwares()
firmware->addOption("internalmulti", Firmware::tr("Support for MULTI internal module"));
addOpenTxFontOptions(firmware);
registerOpenTxFirmware(firmware);
- addOpenTxRfOptions(firmware, FLEX + AFHDS3);
+ addOpenTxRfOptions(firmware, FLEX);
+
+ /* Jumper T-Lite board */
+ firmware = new OpenTxFirmware("opentx-tlite", QCoreApplication::translate("Firmware", "Jumper T-Lite"), BOARD_JUMPER_TLITE);
+ addOpenTxCommonOptions(firmware);
+ firmware->addOption("noheli", Firmware::tr("Disable HELI menu and cyclic mix support"));
+ firmware->addOption("nogvars", Firmware::tr("Disable Global variables"));
+ firmware->addOption("lua", Firmware::tr("Enable Lua custom scripts screen"));
+ addOpenTxFontOptions(firmware);
+ registerOpenTxFirmware(firmware);
+ addOpenTxRfOptions(firmware, FLEX);
/* Jumper T16 board */
firmware = new OpenTxFirmware("opentx-t16", Firmware::tr("Jumper T16 / T16+ / T16 Pro"), BOARD_JUMPER_T16);
addOpenTxFrskyOptions(firmware);
firmware->addOption("internalmulti", Firmware::tr("Support for MULTI internal module"));
firmware->addOption("bluetooth", Firmware::tr("Support for bluetooth module"));
+ firmware->addOption("externalaccessmod", Firmware::tr("Support hardware mod: R9M ACCESS"));
addOpenTxRfOptions(firmware, FLEX);
registerOpenTxFirmware(firmware);
+ /* Radiomaster TX12 board */
+ firmware = new OpenTxFirmware("opentx-tx12", QCoreApplication::translate("Firmware", "Radiomaster TX12"), BOARD_RADIOMASTER_TX12);
+ addOpenTxCommonOptions(firmware);
+ firmware->addOption("noheli", Firmware::tr("Disable HELI menu and cyclic mix support"));
+ firmware->addOption("nogvars", Firmware::tr("Disable Global variables"));
+ firmware->addOption("lua", Firmware::tr("Enable Lua custom scripts screen"));
+ addOpenTxFontOptions(firmware);
+ registerOpenTxFirmware(firmware);
+ addOpenTxRfOptions(firmware, FLEX);
+
+ /* Radiomaster T8 board */
+ firmware = new OpenTxFirmware("opentx-t8", QCoreApplication::translate("Firmware", "Radiomaster T8"), BOARD_RADIOMASTER_T8);
+ addOpenTxCommonOptions(firmware);
+ firmware->addOption("noheli", Firmware::tr("Disable HELI menu and cyclic mix support"));
+ firmware->addOption("nogvars", Firmware::tr("Disable Global variables"));
+ firmware->addOption("lua", Firmware::tr("Enable Lua custom scripts screen"));
+ addOpenTxFontOptions(firmware);
+ registerOpenTxFirmware(firmware);
+ addOpenTxRfOptions(firmware, NONE);
+ firmware->addOption("bindkey", Firmware::tr("Allow bind using bind key"));
+
/* Radiomaster TX16S board */
- firmware = new OpenTxFirmware("opentx-tx16s", Firmware::tr("Radiomaster TX16s / TX16s Hall / TX16s Masterfire"), BOARD_RADIOMASTER_TX16S);
+ firmware = new OpenTxFirmware("opentx-tx16s", Firmware::tr("Radiomaster TX16S / SE / Hall / Masterfire"), BOARD_RADIOMASTER_TX16S);
addOpenTxFrskyOptions(firmware);
addOpenTxRfOptions(firmware, FLEX);
static const Firmware::Option opt_bt("bluetooth", Firmware::tr("Support for bluetooth module"));
static const Firmware::Option opt_internal_gps("internalgps", Firmware::tr("Support internal GPS"));
firmware->addOptionsGroup({opt_bt, opt_internal_gps});
+ firmware->addOption("externalaccessmod", Firmware::tr("Support hardware mod: R9M ACCESS"));
registerOpenTxFirmware(firmware);
/* Jumper T18 board */
firmware = new OpenTxFirmware("opentx-t18", Firmware::tr("Jumper T18"), BOARD_JUMPER_T18);
addOpenTxFrskyOptions(firmware);
firmware->addOption("bluetooth", Firmware::tr("Support for bluetooth module"));
+ firmware->addOption("externalaccessmod", Firmware::tr("Support hardware mod: R9M ACCESS"));
registerOpenTxFirmware(firmware);
addOpenTxRfOptions(firmware, FLEX);
diff --git a/companion/src/firmwares/output_data.cpp b/companion/src/firmwares/output_data.cpp
new file mode 100644
index 000000000..d5cc585ee
--- /dev/null
+++ b/companion/src/firmwares/output_data.cpp
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+#include "output_data.h"
+#include "radiodata.h"
+#include "radiodataconversionstate.h"
+
+void LimitData::clear()
+{
+ memset(reinterpret_cast(this), 0, sizeof(LimitData));
+ min = -1000;
+ max = +1000;
+}
+
+bool LimitData::isEmpty() const
+{
+ LimitData tmp;
+ return !memcmp(this, &tmp, sizeof(LimitData));
+}
+
+QString LimitData::minToString() const
+{
+ return QString::number((qreal)min / 10);
+}
+
+QString LimitData::maxToString() const
+{
+ return QString::number((qreal)max / 10);
+}
+
+QString LimitData::revertToString() const
+{
+ return revert ? tr("INV") : tr("NOR");
+}
+
+QString LimitData::nameToString(int index) const
+{
+ return RadioData::getElementName(tr("CH"), index + 1, name);
+}
+
+QString LimitData::offsetToString() const
+{
+ return QString::number((qreal)offset / 10, 'f', 1);
+}
diff --git a/companion/src/firmwares/output_data.h b/companion/src/firmwares/output_data.h
new file mode 100644
index 000000000..423f03e49
--- /dev/null
+++ b/companion/src/firmwares/output_data.h
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "curvereference.h"
+
+#include
+
+#define LIMITDATA_NAME_LEN 6
+
+class LimitData {
+ Q_DECLARE_TR_FUNCTIONS(LimitData)
+
+ public:
+ LimitData() { clear(); }
+
+ int min;
+ int max;
+ bool revert;
+ int offset;
+ int ppmCenter;
+ bool symetrical;
+ int failsafe;
+ char name[LIMITDATA_NAME_LEN + 1];
+ CurveReference curve;
+
+ void clear();
+ bool isEmpty() const;
+ QString minToString() const;
+ QString maxToString() const;
+ QString offsetToString() const;
+ QString revertToString() const;
+ QString nameToString(int index) const;
+};
diff --git a/companion/src/firmwares/radiodata.cpp b/companion/src/firmwares/radiodata.cpp
index 8054e5b1a..c833281fd 100644
--- a/companion/src/firmwares/radiodata.cpp
+++ b/companion/src/firmwares/radiodata.cpp
@@ -22,23 +22,6 @@
#include "radiodataconversionstate.h"
#include "eeprominterface.h"
-// static
-QString RadioData::getElementName(const QString & prefix, unsigned int index, const char * name, bool padding)
-{
- QString result = prefix;
- if (padding)
- result += QString("%1").arg(index, 2, 10, QChar('0'));
- else
- result += QString("%1").arg(index);
- if (name) {
- QString trimmed = QString(name).trimmed();
- if (trimmed.length() > 0) {
- result += ":" + QString(name).trimmed();
- }
- }
- return result;
-}
-
RadioData::RadioData()
{
models.resize(getCurrentFirmware()->getCapability(Models));
diff --git a/companion/src/firmwares/radiodata.h b/companion/src/firmwares/radiodata.h
index 29d29e4eb..d289f1846 100644
--- a/companion/src/firmwares/radiodata.h
+++ b/companion/src/firmwares/radiodata.h
@@ -1,9 +1,10 @@
-#ifndef _RADIODATA_H_
-#define _RADIODATA_H_
+#pragma once
#include "generalsettings.h"
#include "modeldata.h"
+#include "datahelpers.h" // required for getElementName
+
#include
class RadioDataConversionState;
@@ -32,10 +33,10 @@ class RadioData {
void fixModelFilenames();
QString getNextModelFilename();
- static QString getElementName(const QString & prefix, unsigned int index, const char * name = 0, bool padding = false);
+ // leave here until all calls repointed
+ static QString getElementName(const QString & prefix, unsigned int index, const char * name = 0, bool padding = false)
+ { return DataHelpers::getElementName(prefix, index, name, padding); }
protected:
void fixModelFilename(unsigned int index);
};
-
-#endif // _RADIODATA_H_
diff --git a/companion/src/firmwares/rawsource.cpp b/companion/src/firmwares/rawsource.cpp
index 1cb5bcfbb..898c0ca4a 100644
--- a/companion/src/firmwares/rawsource.cpp
+++ b/companion/src/firmwares/rawsource.cpp
@@ -60,7 +60,7 @@ RawSourceRange RawSource::getRange(const ModelData * model, const GeneralSetting
result.min = -30000 * result.step;
result.max = +30000 * result.step;
result.decimals = sensor.prec;
- result.unit = sensor.unitString();
+ result.unit = SensorData::unitToString(qr.quot);
break;
}
@@ -140,32 +140,17 @@ QString RawSource::toString(const ModelData * model, const GeneralSettings * con
tr("Batt"), tr("Time"), tr("Timer1"), tr("Timer2"), tr("Timer3"),
};
- static const QString telemetry[] = {
- tr("Batt"), tr("Time"), tr("Timer1"), tr("Timer2"), tr("Timer3"),
- tr("RAS"), tr("RSSI Tx"), tr("RSSI Rx"),
- tr("A1"), tr("A2"), tr("A3"), tr("A4"),
- tr("Alt"), tr("Rpm"), tr("Fuel"), tr("T1"), tr("T2"),
- tr("Speed"), tr("Dist"), tr("GPS Alt"),
- tr("Cell"), tr("Cells"), tr("Vfas"), tr("Curr"), tr("Cnsp"), tr("Powr"),
- tr("AccX"), tr("AccY"), tr("AccZ"),
- tr("Hdg "), tr("VSpd"), tr("AirSpeed"), tr("dTE"),
- tr("A1-"), tr("A2-"), tr("A3-"), tr("A4-"),
- tr("Alt-"), tr("Alt+"), tr("Rpm+"), tr("T1+"), tr("T2+"), tr("Speed+"), tr("Dist+"), tr("AirSpeed+"),
- tr("Cell-"), tr("Cells-"), tr("Vfas-"), tr("Curr+"), tr("Powr+"),
- tr("ACC"), tr("GPS Time"),
- };
-
static const QString rotary[] = { tr("REa"), tr("REb") };
if (index<0) {
- return tr("???");
+ return QString(CPN_STR_UNKNOWN_ITEM);
}
QString result;
int genAryIdx = 0;
switch (type) {
case SOURCE_TYPE_NONE:
- return tr("----");
+ return QString(CPN_STR_NONE_ITEM);
case SOURCE_TYPE_VIRTUAL_INPUT:
{
@@ -176,7 +161,7 @@ QString RawSource::toString(const ModelData * model, const GeneralSettings * con
}
case SOURCE_TYPE_LUA_OUTPUT:
- return tr("LUA%1%2").arg(index/16+1).arg(QChar('a'+index%16));
+ return tr("LUA%1%2").arg(index / 16 + 1).arg(QChar('a' + index % 16));
case SOURCE_TYPE_STICK:
if (generalSettings) {
@@ -208,10 +193,10 @@ QString RawSource::toString(const ModelData * model, const GeneralSettings * con
return result;
case SOURCE_TYPE_CUSTOM_SWITCH:
- return RawSwitch(SWITCH_TYPE_VIRTUAL, index+1).toString();
+ return RawSwitch(SWITCH_TYPE_VIRTUAL, index + 1).toString();
case SOURCE_TYPE_CYC:
- return tr("CYC%1").arg(index+1);
+ return tr("CYC%1").arg(index + 1);
case SOURCE_TYPE_PPM:
return RadioData::getElementName(tr("TR", "as in Trainer"), index + 1);
@@ -223,7 +208,16 @@ QString RawSource::toString(const ModelData * model, const GeneralSettings * con
return LimitData().nameToString(index);
case SOURCE_TYPE_SPECIAL:
- return CHECK_IN_ARRAY(special, index);
+ if (index >= SOURCE_TYPE_SPECIAL_TIMER1_IDX && index <= SOURCE_TYPE_SPECIAL_TIMER1_IDX + CPN_MAX_TIMERS - 1) {
+ if (model)
+ result = model->timers[index - SOURCE_TYPE_SPECIAL_TIMER1_IDX].nameToString(index - SOURCE_TYPE_SPECIAL_TIMER1_IDX);
+ else
+ result = TimerData().nameToString(index - SOURCE_TYPE_SPECIAL_TIMER1_IDX);
+ }
+ else
+ result = CHECK_IN_ARRAY(special, index);
+
+ return result;
case SOURCE_TYPE_TELEMETRY:
{
@@ -244,7 +238,7 @@ QString RawSource::toString(const ModelData * model, const GeneralSettings * con
return GVarData().nameToString(index);
default:
- return tr("???");
+ return QString(CPN_STR_UNKNOWN_ITEM);
}
}
@@ -347,111 +341,40 @@ RawSource RawSource::convert(RadioDataConversionState & cstate)
RadioDataConversionState::LogField oldData(index, toString(cstate.fromModel(), cstate.fromGS(), cstate.fromType));
if (type == SOURCE_TYPE_STICK) {
- if (cstate.toBoard.getCapability(Board::Sliders)) {
- if (index >= cstate.fromBoard.getCapability(Board::Sticks) + cstate.fromBoard.getCapability(Board::Pots)) {
- // 1st slider alignment
- index += cstate.toBoard.getCapability(Board::Pots) - cstate.fromBoard.getCapability(Board::Pots);
- }
-
- if (isSlider(0, cstate.fromType)) {
- // LS and RS sliders are after 2 aux sliders on X12 and X9E
- if ((IS_HORUS_X12S(cstate.toType) || IS_TARANIS_X9E(cstate.toType)) && !IS_HORUS_X12S(cstate.fromType) && !IS_TARANIS_X9E(cstate.fromType)) {
- if (index >= 7) {
- index += 2; // LS/RS to LS/RS
- }
- }
- else if (!IS_TARANIS_X9E(cstate.toType) && !IS_HORUS_X12S(cstate.toType) && (IS_HORUS_X12S(cstate.fromType) || IS_TARANIS_X9E(cstate.fromType))) {
- if (index >= 7 && index <= 8) {
- index += 2; // aux sliders to spare analogs (which may not exist, this is validated later)
- evt = RadioDataConversionState::EVT_CVRT;
- }
- else if (index >= 9 && index <= 10) {
- index -= 2; // LS/RS to LS/RS
- }
- }
- }
- }
-
- if (IS_TARANIS(cstate.toType) && IS_FAMILY_HORUS_OR_T16(cstate.fromType)) {
- if (index == 6)
- index = 5; // pot S2 to S2
- else if (index == 5)
- index = -1; // 6P on Horus doesn't exist on Taranis
- }
- else if (IS_FAMILY_HORUS_OR_T16(cstate.toType) && IS_TARANIS(cstate.fromType) && index == 5)
- {
- index = 6; // pot S2 to S2
- }
-
- } // SOURCE_TYPE_STICK
+ QStringList fromStickList(getStickList(cstate.fromBoard));
+ QStringList toStickList(getStickList(cstate.toBoard));
+ index = toStickList.indexOf(fromStickList.at(oldData.id));
+ // index set to -1 if no match found
+ // perform forced mapping
+ }
if (type == SOURCE_TYPE_SWITCH) {
- // SWI to SWR don't exist on !X9E board
- if (!IS_TARANIS_X9E(cstate.toType) && IS_TARANIS_X9E(cstate.fromType)) {
- if (index >= 8) {
- index = index % 8;
- evt = RadioDataConversionState::EVT_CVRT;
+ QStringList fromSwitchList(getSwitchList(cstate.fromBoard));
+ QStringList toSwitchList(getSwitchList(cstate.toBoard));
+ index = toSwitchList.indexOf(fromSwitchList.at(oldData.id));
+ // index set to -1 if no match found
+ // perform forced mapping
+ if (index < 0) {
+ if (IS_TARANIS_X7(cstate.toType) && (IS_TARANIS_X9(cstate.fromType) || IS_FAMILY_HORUS_OR_T16(cstate.fromType))) {
+ // No SE and SG on X7 board
+ index = toSwitchList.indexOf("SD");
+ if (index >= 0)
+ evt = RadioDataConversionState::EVT_CVRT;
+ }
+ else if (IS_FAMILY_T12(cstate.toType) && (IS_TARANIS_X9(cstate.fromType) || IS_FAMILY_HORUS_OR_T16(cstate.fromType))) {
+ // No SE and SG on T12 board
+ index = toSwitchList.indexOf("SD");
+ if (index >= 0)
+ evt = RadioDataConversionState::EVT_CVRT;
}
}
-
- if (IS_TARANIS_X7(cstate.toType) && (IS_TARANIS_X9(cstate.fromType) || IS_FAMILY_HORUS_OR_T16(cstate.fromType))) {
- // No SE and SG on X7 board
- if (index == 4 || index == 6) {
- index = 3; // SG and SE to SD
- evt = RadioDataConversionState::EVT_CVRT;
- }
- else if (index == 5) {
- index = 4; // SF to SF
- }
- else if (index == 7) {
- index = 5; // SH to SH
- }
- }
- else if (IS_JUMPER_T12(cstate.toType) && (IS_TARANIS_X9(cstate.fromType) || IS_FAMILY_HORUS_OR_T16(cstate.fromType))) {
- // No SE and SG on T12 board
- if (index == 4 || index == 6) {
- index = 3; // SG and SE to SD
- evt = RadioDataConversionState::EVT_CVRT;
- }
- else if (index == 5) {
- index = 4; // SF to SF
- }
- else if (index == 7) {
- index = 5; // SH to SH
- }
- }
- // Compensate for SE and SG on X9/Horus board if converting from X7
- else if ((IS_TARANIS_X9(cstate.toType) || IS_FAMILY_HORUS_OR_T16(cstate.toType)) && IS_TARANIS_X7(cstate.fromType)) {
- if (index == 4) {
- index = 5; // SF to SF
- }
- else if (index == 5) {
- index = 7; // SH to SH
- }
- }
- else if ((IS_TARANIS_X9(cstate.toType) || IS_FAMILY_HORUS_OR_T16(cstate.toType)) && IS_JUMPER_T12(cstate.fromType)) {
- if (index == 4) {
- index = 5; // SF to SF
- }
- else if (index == 5) {
- index = 7; // SH to SH
- }
- }
- else if ((IS_TARANIS_X9(cstate.toType) || IS_FAMILY_HORUS_OR_T16(cstate.toType)) && IS_JUMPER_T12(cstate.fromType)) {
- if (index == 4) {
- index = 5; // SF to SF
- }
- else if (index == 5) {
- index = 7; // SH to SH
- }
- }
- } // SOURCE_TYPE_SWITCH
+ }
// final validation (we do not pass model to isAvailable() because we don't know what has or hasn't been converted)
- if (!isAvailable(NULL, cstate.toGS(), cstate.toType)) {
+ if (index < 0 || !isAvailable(NULL, cstate.toGS(), cstate.toType)) {
cstate.setInvalid(oldData);
- index = -1; // TODO: better way to flag invalid sources?
- type = MAX_SOURCE_TYPE;
+ // no source is safer than an invalid one
+ clear();
}
else if (evt == RadioDataConversionState::EVT_CVRT) {
cstate.setConverted(oldData, RadioDataConversionState::LogField(index, toString(cstate.toModel(), cstate.toGS(), cstate.toType)));
@@ -463,3 +386,23 @@ RawSource RawSource::convert(RadioDataConversionState & cstate)
return *this;
}
+
+QStringList RawSource::getStickList(Boards board) const
+{
+ QStringList ret;
+
+ for (int i = 0; i < board.getCapability(Board::MaxAnalogs); i++) {
+ ret.append(board.getAnalogInputName(i));
+ }
+ return ret;
+}
+
+QStringList RawSource::getSwitchList(Boards board) const
+{
+ QStringList ret;
+
+ for (int i = 0; i < board.getCapability(Board::Switches); i++) {
+ ret.append(board.getSwitchInfo(i).name);
+ }
+ return ret;
+}
diff --git a/companion/src/firmwares/rawsource.h b/companion/src/firmwares/rawsource.h
index b3220dbd3..a7d293173 100644
--- a/companion/src/firmwares/rawsource.h
+++ b/companion/src/firmwares/rawsource.h
@@ -178,6 +178,9 @@ enum RawSourceType {
MAX_SOURCE_TYPE
};
+constexpr int SOURCE_TYPE_STICK_THR_IDX { 3 }; // TODO is there a function to determine index?
+constexpr int SOURCE_TYPE_SPECIAL_TIMER1_IDX { 2 }; // TODO temp const until Timers own source type
+
class RawSourceRange
{
Q_DECLARE_TR_FUNCTIONS(RawSourceRange)
@@ -252,6 +255,8 @@ class RawSource {
bool isAvailable(const ModelData * const model = NULL, const GeneralSettings * const gs = NULL, Board::Type board = Board::BOARD_UNKNOWN) const;
bool isSet() const { return type != SOURCE_TYPE_NONE || index != 0; }
void clear() { type = SOURCE_TYPE_NONE; index = 0; }
+ QStringList getStickList(Boards board) const;
+ QStringList getSwitchList(Boards board) const;
bool operator == ( const RawSource & other) const {
return (this->type == other.type) && (this->index == other.index);
diff --git a/companion/src/firmwares/rawswitch.cpp b/companion/src/firmwares/rawswitch.cpp
index a689ceea7..7aef46922 100644
--- a/companion/src/firmwares/rawswitch.cpp
+++ b/companion/src/firmwares/rawswitch.cpp
@@ -59,7 +59,7 @@ QString RawSwitch::toString(Board::Type board, const GeneralSettings * const gen
tr("THs"), tr("TH%"), tr("THt")
};
- const QStringList directionIndicators = QStringList()
+ static const QStringList directionIndicators = QStringList()
<< CPN_STR_SW_INDICATOR_UP
<< CPN_STR_SW_INDICATOR_NEUT
<< CPN_STR_SW_INDICATOR_DN;
@@ -184,77 +184,39 @@ RawSwitch RawSwitch::convert(RadioDataConversionState & cstate)
RadioDataConversionState::EventType evt = RadioDataConversionState::EVT_NONE;
RadioDataConversionState::LogField oldData(index, toString(cstate.fromType, cstate.fromGS(), cstate.fromModel()));
+ int newIdx = 0;
+
if (type == SWITCH_TYPE_SWITCH) {
- int srcIdx = div(abs(index)-1, 3).quot; // raw source index
- int delta = 0;
-
- // SWI to SWR don't exist on !X9E board
- if (!IS_TARANIS_X9E(cstate.toType) && IS_TARANIS_X9E(cstate.fromType)) {
- if (srcIdx > 7) {
- index %= 24;
- evt = RadioDataConversionState::EVT_CVRT;
- }
- }
-
- // No SE and SG on X7 board
- if (IS_TARANIS_X7(cstate.toType) && (IS_TARANIS_X9(cstate.fromType) || IS_FAMILY_HORUS_OR_T16(cstate.fromType))) {
- if (srcIdx == 4 || srcIdx == 5) {
- delta = 3; // SE to SD & SF to SF
- if (srcIdx == 4)
+ div_t swtch = div(abs(index) - 1, 3); // rawsource index
+ QStringList fromSwitchList(getSwitchList(cstate.fromBoard));
+ QStringList toSwitchList(getSwitchList(cstate.toBoard));
+ // set to -1 if no match found
+ newIdx = toSwitchList.indexOf(fromSwitchList.at(swtch.quot));
+ // perform forced mapping
+ if (newIdx < 0) {
+ if (IS_TARANIS_X7(cstate.toType) && (IS_TARANIS_X9(cstate.fromType) || IS_FAMILY_HORUS_OR_T16(cstate.fromType))) {
+ // No SE and SG on X7 board
+ newIdx = toSwitchList.indexOf("SD");
+ if (newIdx >= 0)
evt = RadioDataConversionState::EVT_CVRT;
}
- else if (srcIdx == 6) {
- delta = 9; // SG to SD
- evt = RadioDataConversionState::EVT_CVRT;
- }
- else if (srcIdx == 7) {
- delta = 6; // SH to SH
- }
- }
- else if (IS_JUMPER_T12(cstate.toType) && (IS_TARANIS_X9(cstate.fromType) || IS_FAMILY_HORUS_OR_T16(cstate.fromType))) {
- if (srcIdx == 4 || srcIdx == 5) {
- delta = 3; // SE to SD & SF to SF
- if (srcIdx == 4)
+ else if (IS_FAMILY_T12(cstate.toType) && (IS_TARANIS_X9(cstate.fromType) || IS_FAMILY_HORUS_OR_T16(cstate.fromType))) {
+ // No SE and SG on T12 board
+ newIdx = toSwitchList.indexOf("SD");
+ if (newIdx >= 0)
evt = RadioDataConversionState::EVT_CVRT;
}
- else if (srcIdx == 6) {
- delta = 9; // SG to SD
- evt = RadioDataConversionState::EVT_CVRT;
- }
- else if (srcIdx == 7) {
- delta = 6; // SH to SH
- }
- }
- // Compensate for SE and SG on X9/Horus board if converting from X7
- else if ((IS_TARANIS_X9(cstate.toType) || IS_FAMILY_HORUS_OR_T16(cstate.toType)) && IS_TARANIS_X7(cstate.fromType)) {
- if (srcIdx == 4) {
- delta = -3; // SF to SF
- }
- else if (srcIdx == 5) {
- delta = -6; // SH to SH
- }
- }
- else if ((IS_TARANIS_X9(cstate.toType) || IS_FAMILY_HORUS_OR_T16(cstate.toType)) && IS_JUMPER_T12(cstate.fromType)) {
- if (srcIdx == 4) {
- delta = -3; // SF to SF
- }
- else if (srcIdx == 5) {
- delta = -6; // SH to SH
- }
}
- if (index < 0) {
- delta = -delta; // invert for !switch
- }
-
- index -= delta;
-
+ if (newIdx >= 0)
+ index = (newIdx * 3 + 1 + swtch.rem) * (index < 0 ? -1 : 1);
} // SWITCH_TYPE_SWITCH
// final validation (we do not pass model to isAvailable() because we don't know what has or hasn't been converted)
- if (!isAvailable(NULL, cstate.toGS(), cstate.toType)) {
+ if (newIdx < 0 || !isAvailable(NULL, cstate.toGS(), cstate.toType)) {
cstate.setInvalid(oldData);
- type = MAX_SWITCH_TYPE; // TODO: better way to flag invalid switches?
+ // no switch is safer than an invalid one
+ clear();
}
else if (evt == RadioDataConversionState::EVT_CVRT) {
cstate.setConverted(oldData, RadioDataConversionState::LogField(index, toString(cstate.toType, cstate.toGS(), cstate.toModel())));
@@ -266,3 +228,13 @@ RawSwitch RawSwitch::convert(RadioDataConversionState & cstate)
return *this;
}
+
+QStringList RawSwitch::getSwitchList(Boards board) const
+{
+ QStringList ret;
+
+ for (int i = 0; i < board.getCapability(Board::Switches); i++) {
+ ret.append(board.getSwitchInfo(i).name);
+ }
+ return ret;
+}
diff --git a/companion/src/firmwares/rawswitch.h b/companion/src/firmwares/rawswitch.h
index d79ac0aa6..7c0707a6a 100644
--- a/companion/src/firmwares/rawswitch.h
+++ b/companion/src/firmwares/rawswitch.h
@@ -89,6 +89,7 @@ class RawSwitch {
bool isAvailable(const ModelData * const model = NULL, const GeneralSettings * const gs = NULL, Board::Type board = Board::BOARD_UNKNOWN) const;
bool isSet() const { return type != SWITCH_TYPE_NONE || index != 0; }
void clear() { type = SWITCH_TYPE_NONE; index = 0; }
+ QStringList getSwitchList(Boards board) const;
bool operator== ( const RawSwitch& other) const {
return (this->type == other.type) && (this->index == other.index);
diff --git a/companion/src/firmwares/sensordata.cpp b/companion/src/firmwares/sensordata.cpp
index 0a7e7eada..ae602bd0d 100644
--- a/companion/src/firmwares/sensordata.cpp
+++ b/companion/src/firmwares/sensordata.cpp
@@ -19,9 +19,9 @@
*/
#include "sensordata.h"
-
-#include "radiodata.h"
#include "modeldata.h"
+#include "eeprominterface.h"
+#include "compounditemmodels.h"
void SensorData::updateUnit()
{
@@ -31,9 +31,322 @@ void SensorData::updateUnit()
}
}
-QString SensorData::unitString() const
+QString SensorData::nameToString(int index) const
{
- switch (unit) {
+ return DataHelpers::getElementName(tr("TELE"), index + 1, label);
+}
+
+QString SensorData::getOrigin(const ModelData * model) const
+{
+ if (type != TELEM_TYPE_CUSTOM || !id)
+ return QString();
+
+ const ModuleData & module = model->moduleData[moduleIdx];
+ if (module.isPxx2Module() && rxIdx <= 2 && module.access.receivers & (1 << rxIdx)) {
+ return QString(module.access.receiverName[rxIdx]);
+ }
+ else {
+ return QString();
+ }
+}
+
+bool SensorData::isEmpty() const
+{
+ return (!isAvailable() && type == 0 && id == 0 && subid == 0 && instance == 0 && rxIdx == 0 && moduleIdx == 0 && unit == 0 && ratio == 0 && prec == 0 && offset == 0 && autoOffset == 0 && filter == 0 && onlyPositive == 0 && logs == 0);
+}
+
+QString SensorData::idToString() const
+{
+ return idToString(id);
+}
+
+QString SensorData::typeToString() const
+{
+ return typeToString(type);
+}
+
+QString SensorData::formulaToString() const
+{
+ return formulaToString(formula);
+}
+
+QString SensorData::cellIndexToString() const
+{
+ return cellIndexToString(index);
+}
+
+QString SensorData::unitToString() const
+{
+ return unitToString(unit);
+}
+
+QString SensorData::precToString() const
+{
+ return precToString(prec);
+}
+
+int SensorData::getMask() const
+{
+ int mask = 0;
+
+ if (type == TELEM_TYPE_CALCULATED) {
+ if (formula < TELEM_FORMULA_CELL)
+ mask |= SENSOR_ISCONFIGURABLE | SENSOR_HAS_POSITIVE;
+ if (formula == TELEM_FORMULA_DIST)
+ mask |= SENSOR_HAS_GPS;
+ if (formula == TELEM_FORMULA_CELL)
+ mask |= SENSOR_HAS_CELLS;
+ if (formula == TELEM_FORMULA_CONSUMPTION)
+ mask |= SENSOR_HAS_CONSUMPTION;
+ if (formula <= TELEM_FORMULA_MULTIPLY)
+ mask |= SENSOR_HAS_SOURCES_12;
+ if (formula < TELEM_FORMULA_MULTIPLY)
+ mask |= SENSOR_HAS_SOURCES_34;
+ if (formula == TELEM_FORMULA_TOTALIZE)
+ mask |= SENSOR_HAS_TOTALIZE;
+ }
+ else {
+ if (unit < UNIT_FIRST_VIRTUAL)
+ mask |= (SENSOR_ISCONFIGURABLE | SENSOR_HAS_RATIO | SENSOR_HAS_POSITIVE);
+ }
+
+ if (mask & SENSOR_ISCONFIGURABLE && unit != UNIT_FAHRENHEIT)
+ mask |= SENSOR_HAS_PRECISION;
+
+ return mask;
+}
+
+constexpr char FMT_LABEL[] { "%1: " };
+constexpr char FMT_VALUE[] { "%1 " };
+constexpr char FMT_LABEL_VALUE[] { "%1: %2 " };
+
+QString SensorData::paramsToString(const ModelData * model) const
+{
+ if (!isAvailable())
+ return "";
+
+ QString str;
+ int mask = getMask();
+
+ if (type == TELEM_TYPE_CALCULATED) {
+ str.append(QString(FMT_LABEL_VALUE).arg(tr("Formula")).arg(formulaToString()));
+ }
+ else {
+ str.append(QString(FMT_LABEL_VALUE).arg(tr("Id")).arg(idToString()));
+ str.append(QString(FMT_LABEL_VALUE).arg(tr("Instance")).arg(instance));
+ }
+
+ if (mask & SENSOR_HAS_CELLS) {
+ str.append(QString(FMT_LABEL_VALUE).arg(tr("Sensor")).arg(sourceToString(model, source)));
+ str.append(QString(FMT_VALUE).arg(cellIndexToString()));
+ }
+
+ if (mask & SENSOR_HAS_SOURCES_12) {
+ str.append(QString(FMT_LABEL).arg(tr("Sources")));
+ for (int i = 0; i < 4; i++) {
+ if (i < 2 || mask & SENSOR_HAS_SOURCES_34) {
+ str.append(QString(FMT_VALUE).arg(sourceToString(model, sources[i])));
+ }
+ }
+ }
+
+ if (mask & SENSOR_HAS_CONSUMPTION || mask & SENSOR_HAS_TOTALIZE)
+ str.append(QString(FMT_LABEL_VALUE).arg(tr("Sensor")).arg(sourceToString(model, amps)));
+
+ if (mask & SENSOR_HAS_GPS) {
+ str.append(QString(FMT_LABEL_VALUE).arg(tr("GPS")).arg(sourceToString(model, gps)));
+ str.append(QString(FMT_LABEL_VALUE).arg(tr("Alt")).arg(sourceToString(model, alt)));
+ }
+
+ if (mask & SENSOR_ISCONFIGURABLE)
+ str.append(QString(FMT_LABEL_VALUE).arg(tr("Unit")).arg(unitToString()));
+
+ if (mask & SENSOR_HAS_PRECISION)
+ str.append(QString(FMT_LABEL_VALUE).arg(tr("Precision")).arg(precToString()));
+
+ if (mask & SENSOR_HAS_RATIO) {
+ if (unit != UNIT_RPMS) {
+ int precsn = prec == 0 ? 1 : pow(10, prec);
+ str.append(QString(FMT_LABEL_VALUE).arg(tr("Ratio")).arg((float)ratio / 10));
+ str.append(QString(FMT_LABEL_VALUE).arg(tr("Offset")).arg(QString::number((float)offset / precsn, 'f', prec)));
+ str.append(QString(FMT_LABEL_VALUE).arg(tr("Auto Offset")).arg(DataHelpers::boolToString(autoOffset, DataHelpers::BOOL_FMT_YN)));
+ }
+ else {
+ str.append(QString(FMT_LABEL_VALUE).arg(tr("Blades")).arg(ratio)); // TODO refactor to dedicated RPMS field
+ str.append(QString(FMT_LABEL_VALUE).arg(tr("Multiplier")).arg(offset)); // TODO refactor to dedicated RPMS field
+ }
+ }
+
+ if (mask & SENSOR_ISCONFIGURABLE)
+ str.append(QString(FMT_LABEL_VALUE).arg(tr("Filter")).arg(DataHelpers::boolToString(filter, DataHelpers::BOOL_FMT_YN)));
+
+ if (type == TELEM_TYPE_CALCULATED)
+ str.append(QString(FMT_LABEL_VALUE).arg(tr("Persist")).arg(DataHelpers::boolToString(persistent, DataHelpers::BOOL_FMT_YN)));
+
+ if (mask & SENSOR_HAS_POSITIVE)
+ str.append(QString(FMT_LABEL_VALUE).arg(tr("Positive")).arg(DataHelpers::boolToString(onlyPositive, DataHelpers::BOOL_FMT_YN)));
+
+ str.append(QString(FMT_LABEL_VALUE).arg(tr("Log")).arg(DataHelpers::boolToString(logs, DataHelpers::BOOL_FMT_YN)));
+
+ return str;
+}
+
+FieldRange SensorData::getRatioRange() const
+{
+ FieldRange result;
+
+ if (unit == SensorData::UNIT_RPMS) {
+ result.decimals = 0;
+ result.max = 30000;
+ result.min = 1;
+ result.step = 1;
+ }
+ else {
+ result.decimals = 1;
+ result.max = 30000;
+ result.min = 0;
+ result.step = 0.1;
+ }
+
+ return result;
+}
+
+FieldRange SensorData::getOffsetRange() const
+{
+ FieldRange result;
+
+ if (unit == SensorData::UNIT_RPMS) {
+ result.decimals = 0;
+ result.max = 30000;
+ result.min = 1;
+ result.step = 1;
+ }
+ else {
+ result.decimals = prec;
+ result.max = 30000.0f / powf(10.0f, prec);
+ result.min = -result.max;
+ result.step = pow(0.1, prec);
+ }
+
+ return result;
+}
+
+void SensorData::formulaChanged()
+{
+ switch (formula) {
+ case TELEM_FORMULA_CELL:
+ prec = 2;
+ unit = UNIT_VOLTS;
+ break;
+ case TELEM_FORMULA_CONSUMPTION:
+ prec = 0;
+ unit = UNIT_MAH;
+ break;
+ case TELEM_FORMULA_DIST:
+ prec = 0;
+ unit = UNIT_METERS;
+ break;
+ }
+}
+
+void SensorData::unitChanged()
+{
+ if (unit == UNIT_FAHRENHEIT)
+ prec = 0;
+}
+
+// static
+QString SensorData::idToString(const int value)
+{
+ return QString::number(value, 16).toUpper();
+}
+
+// static
+QString SensorData::typeToString(const int value)
+{
+ switch(value) {
+ case TELEM_TYPE_CUSTOM:
+ return tr("Custom");
+ case TELEM_TYPE_CALCULATED:
+ return tr("Calculated");
+ default:
+ return CPN_STR_UNKNOWN_ITEM;
+ }
+}
+
+// static
+QString SensorData::formulaToString(const int value)
+{
+ switch(value) {
+ case TELEM_FORMULA_ADD:
+ return tr("Add");
+ case TELEM_FORMULA_AVERAGE:
+ return tr("Average");
+ case TELEM_FORMULA_MIN:
+ return tr("Minimum");
+ case TELEM_FORMULA_MAX:
+ return tr("Maximum");
+ case TELEM_FORMULA_MULTIPLY:
+ return tr("Multiply");
+ case TELEM_FORMULA_TOTALIZE:
+ return tr("Totalize");
+ case TELEM_FORMULA_CELL:
+ return tr("Cell");
+ case TELEM_FORMULA_CONSUMPTION:
+ return tr("Consumption");
+ case TELEM_FORMULA_DIST:
+ return tr("Distance");
+ default:
+ return CPN_STR_UNKNOWN_ITEM;
+ }
+}
+
+// static
+QString SensorData::cellIndexToString(const int value)
+{
+ if (value == TELEM_CELL_INDEX_LOWEST)
+ return tr("Lowest");
+ if (value > TELEM_CELL_INDEX_LOWEST && value < TELEM_CELL_INDEX_HIGHEST)
+ return tr("Cell %1").arg(value - TELEM_CELL_INDEX_LOWEST);
+ if (value== TELEM_CELL_INDEX_HIGHEST)
+ return tr("Highest");
+ if (value == TELEM_CELL_INDEX_DELTA)
+ return tr("Delta");
+ return CPN_STR_UNKNOWN_ITEM;
+}
+
+// static
+QString SensorData::precToString(const int value)
+{
+ return QString("0.%1").arg(QString(value, '0'));
+}
+
+// static
+QString SensorData::sourceToString(const ModelData * model, const int index, const bool sign)
+{
+ if (model) {
+ const QString prfx = sign ? index < 0 ? "-" : "+" : "";
+
+ if (abs(index) > 0) {
+ const SensorData &sd = model->sensorData[abs(index) - 1];
+ if (sd.type == SensorData::TELEM_TYPE_CUSTOM)
+ return QString("%1%2 (%3)").arg(prfx).arg(sd.label).arg(sd.getOrigin(model));
+ else
+ return QString("%1%2").arg(prfx).arg(sd.label);
+ }
+ else
+ return CPN_STR_NONE_ITEM;
+ }
+
+ return "";
+}
+
+// static
+QString SensorData::unitToString(const int value)
+{
+ switch (value) {
+ case UNIT_RAW:
+ return tr("Raw (-)");
case UNIT_VOLTS:
return tr("V");
case UNIT_AMPS:
@@ -84,26 +397,118 @@ QString SensorData::unitString() const
return tr("V");
case UNIT_MILLILITERS_PER_MINUTE:
return tr("ml/minute");
+ case UNIT_HERZ:
+ return tr("Hertz");
+ case UNIT_MS:
+ return tr("mS");
+ case UNIT_US:
+ return tr("uS");
default:
- return "";
+ return CPN_STR_UNKNOWN_ITEM;
}
}
-QString SensorData::nameToString(int index) const
+// static
+bool SensorData::isSourceAvailable(const ModelData * model, const int index)
{
- return RadioData::getElementName(tr("TELE"), index + 1, label);
+ Firmware * firmware = getCurrentFirmware();
+ const int sensorcnt = firmware->getCapability(Sensors);
+ const int i = abs(index);
+
+ if (model && sensorcnt > 0 && i <= sensorcnt) {
+ if (i > 0)
+ return model->sensorData[i - 1].isAvailable();
+ else
+ return true;
+ }
+
+ return false;
}
-QString SensorData::getOrigin(const ModelData * model) const
+#define RSSI_ID 0xF101
+
+// static
+bool SensorData::isRssiSensorAvailable(const ModelData * model, const int value)
{
- if (type != TELEM_TYPE_CUSTOM || !id)
- return QString();
-
- const ModuleData & module = model->moduleData[moduleIdx];
- if (module.isPxx2Module() && rxIdx <= 2 && module.access.receivers & (1 << rxIdx)) {
- return QString(module.access.receiverName[rxIdx]);
- }
+ if (value == 0)
+ return true;
else {
- return QString();
+ const SensorData &sensor = model->sensorData[abs(value) - 1];
+ return (sensor.isAvailable() && sensor.id == RSSI_ID);
}
}
+
+// static
+QString SensorData::rssiSensorToString(const ModelData * model, const int value)
+{
+ if (value == 0)
+ return tr("(default)");
+ else
+ return sourceToString(model, value);
+}
+
+// static
+AbstractStaticItemModel * SensorData::typeItemModel()
+{
+ AbstractStaticItemModel * mdl = new AbstractStaticItemModel();
+ mdl->setName("sensordata.type");
+
+ for (int i = 0; i <= TELEM_TYPE_LAST; i++) {
+ mdl->appendToItemList(typeToString(i), i);
+ }
+
+ mdl->loadItemList();
+ return mdl;
+}
+
+// static
+AbstractStaticItemModel * SensorData::formulaItemModel()
+{
+ AbstractStaticItemModel * mdl = new AbstractStaticItemModel();
+ mdl->setName("sensordata.formula");
+
+ for (int i = 0; i <= TELEM_FORMULA_LAST; i++) {
+ mdl->appendToItemList(formulaToString(i), i);
+ }
+
+ mdl->loadItemList();
+ return mdl;
+}
+
+// static
+AbstractStaticItemModel * SensorData::cellIndexItemModel()
+{
+ AbstractStaticItemModel * mdl = new AbstractStaticItemModel();
+ mdl->setName("sensordata.cellindex");
+
+ for (int i = 0; i <= TELEM_CELL_INDEX_LAST; i++) {
+ mdl->appendToItemList(cellIndexToString(i), i);
+ }
+
+ mdl->loadItemList();
+ return mdl;
+}
+
+// static
+AbstractStaticItemModel * SensorData::unitItemModel()
+{
+ AbstractStaticItemModel * mdl = new AbstractStaticItemModel();
+ mdl->setName("sensordata.unit");
+
+ for (int i = 0; i <= UNIT_MAX; i++) {
+ QString str = unitToString(i);
+ if (str != CPN_STR_UNKNOWN_ITEM)
+ mdl->appendToItemList(str, i);
+ }
+
+ mdl->loadItemList();
+ return mdl;
+}
+
+// static
+PrecisionItemModel * SensorData::precisionItemModel()
+{
+ PrecisionItemModel * mdl = new PrecisionItemModel(0, 2);
+ mdl->setName("sensordata.precision");
+ return mdl;
+}
diff --git a/companion/src/firmwares/sensordata.h b/companion/src/firmwares/sensordata.h
index 3f995ea3e..8a032cec5 100644
--- a/companion/src/firmwares/sensordata.h
+++ b/companion/src/firmwares/sensordata.h
@@ -18,16 +18,32 @@
* GNU General Public License for more details.
*/
-#ifndef SENSORDATA_H
-#define SENSORDATA_H
+#pragma once
+
+#include "datahelpers.h"
#include
-constexpr int CPN_MAX_SENSORS = 60;
+constexpr int CPN_MAX_SENSORS { 60 };
+constexpr int SENSOR_LABEL_LEN { 4 };
+
+constexpr int SENSOR_ISCONFIGURABLE { 1 << 1 };
+constexpr int SENSOR_HAS_GPS { 1 << 2 };
+constexpr int SENSOR_HAS_CELLS { 1 << 3 };
+constexpr int SENSOR_HAS_CONSUMPTION { 1 << 4 };
+constexpr int SENSOR_HAS_RATIO { 1 << 5 };
+constexpr int SENSOR_HAS_TOTALIZE { 1 << 6 };
+constexpr int SENSOR_HAS_SOURCES_12 { 1 << 7 };
+constexpr int SENSOR_HAS_SOURCES_34 { 1 << 8 };
+constexpr int SENSOR_HAS_POSITIVE { 1 << 9 };
+constexpr int SENSOR_HAS_PRECISION { 1 << 10 };
class ModelData;
+class AbstractStaticItemModel;
+class PrecisionItemModel;
class SensorData {
+
Q_DECLARE_TR_FUNCTIONS(SensorData)
public:
@@ -35,7 +51,8 @@ class SensorData {
enum
{
TELEM_TYPE_CUSTOM,
- TELEM_TYPE_CALCULATED
+ TELEM_TYPE_CALCULATED,
+ TELEM_TYPE_LAST = TELEM_TYPE_CALCULATED
};
enum
@@ -62,6 +79,7 @@ class SensorData {
TELEM_CELL_INDEX_6,
TELEM_CELL_INDEX_HIGHEST,
TELEM_CELL_INDEX_DELTA,
+ TELEM_CELL_INDEX_LAST = TELEM_CELL_INDEX_DELTA
};
enum
@@ -94,10 +112,10 @@ class SensorData {
UNIT_MILLILITERS,
UNIT_FLOZ,
UNIT_MILLILITERS_PER_MINUTE,
- UNIT_MAX = UNIT_MILLILITERS_PER_MINUTE,
- UNIT_SPARE1,
- UNIT_SPARE2,
- UNIT_SPARE3,
+ UNIT_HERZ,
+ UNIT_MS,
+ UNIT_US,
+ UNIT_MAX = UNIT_US,
UNIT_SPARE4,
UNIT_SPARE5,
UNIT_SPARE6,
@@ -133,7 +151,7 @@ class SensorData {
unsigned int moduleIdx;
unsigned int persistentValue;
unsigned int formula;
- char label[4+1];
+ char label[SENSOR_LABEL_LEN + 1];
unsigned int unit;
unsigned int prec;
bool autoOffset;
@@ -162,10 +180,37 @@ class SensorData {
bool isAvailable() const { return strlen(label) > 0; }
void updateUnit();
- QString unitString() const;
QString nameToString(int index) const;
QString getOrigin(const ModelData* model) const;
void clear() { memset(this, 0, sizeof(SensorData)); }
-};
+ bool isEmpty() const;
+ QString idToString() const;
+ QString typeToString() const;
+ QString formulaToString() const;
+ QString cellIndexToString() const;
+ QString unitToString() const;
+ QString precToString() const;
+ int getMask() const;
+ QString paramsToString(const ModelData * model) const;
+ FieldRange getRatioRange() const;
+ FieldRange getOffsetRange() const;
+ void formulaChanged();
+ void unitChanged();
-#endif // SENSORDATA_H
+ static QString sourceToString(const ModelData * model, const int index, const bool sign = false);
+ static bool isSourceAvailable(const ModelData * model, const int index);
+ static QString idToString(const int value);
+ static QString typeToString(const int value);
+ static QString formulaToString(const int value);
+ static QString cellIndexToString(const int value);
+ static QString unitToString(const int value);
+ static QString precToString(const int value);
+ static bool isRssiSensorAvailable(const ModelData * model, const int value);
+ static QString rssiSensorToString(const ModelData * model, const int value);
+
+ static AbstractStaticItemModel * typeItemModel();
+ static AbstractStaticItemModel * formulaItemModel();
+ static AbstractStaticItemModel * cellIndexItemModel();
+ static AbstractStaticItemModel * unitItemModel();
+ static PrecisionItemModel * precisionItemModel();
+};
diff --git a/companion/src/firmwares/timerdata.cpp b/companion/src/firmwares/timerdata.cpp
new file mode 100644
index 000000000..9034ed7e0
--- /dev/null
+++ b/companion/src/firmwares/timerdata.cpp
@@ -0,0 +1,188 @@
+/*
+ * 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.
+ */
+
+#include "timerdata.h"
+#include "radiodataconversionstate.h"
+#include "compounditemmodels.h"
+
+void TimerData::convert(RadioDataConversionState & cstate)
+{
+ cstate.setComponent(tr("TMR"), 1);
+ cstate.setSubComp(tr("Timer %1").arg(cstate.subCompIdx + 1));
+ mode.convert(cstate);
+}
+
+void TimerData::clear()
+{
+ memset(reinterpret_cast(this), 0, sizeof(TimerData));
+ mode = RawSwitch(SWITCH_TYPE_TIMER_MODE, 0);
+}
+
+bool TimerData::isEmpty()
+{
+ return (mode == RawSwitch(SWITCH_TYPE_TIMER_MODE, 0) && name[0] == '\0' && minuteBeep == 0 && countdownBeep == COUNTDOWNBEEP_SILENT && val == 0 && persistent == 0 /*&& pvalue == 0*/);
+}
+
+bool TimerData::isModeOff()
+{
+ return mode == RawSwitch(SWITCH_TYPE_TIMER_MODE, 0);
+}
+
+QString TimerData::nameToString(int index) const
+{
+ return DataHelpers::getElementName(tr("TMR", "as in Timer"), index + 1, name);
+}
+
+QString TimerData::countdownBeepToString() const
+{
+ return countdownBeepToString(countdownBeep);
+}
+
+QString TimerData::countdownStartToString() const
+{
+ if (countdownBeep == COUNTDOWNBEEP_SILENT)
+ return "";
+ else
+ return countdownStartToString(countdownStart);
+}
+
+QString TimerData::persistentToString(const bool verbose) const
+{
+ return persistentToString(persistent, verbose);
+}
+
+QString TimerData::pvalueToString() const
+{
+ return pvalueToString(pvalue);
+}
+
+QString TimerData::valToString() const
+{
+ return valToString(val);
+}
+
+void TimerData::countdownBeepChanged()
+{
+ if (countdownBeep == COUNTDOWNBEEP_SILENT)
+ countdownStart = 0;
+}
+
+// static
+QString TimerData::countdownBeepToString(const int value)
+{
+ switch(value) {
+ case COUNTDOWNBEEP_SILENT:
+ return tr("Silent");
+ case COUNTDOWNBEEP_BEEPS:
+ return tr("Beeps");
+ case COUNTDOWNBEEP_VOICE:
+ return tr("Voice");
+ case COUNTDOWNBEEP_HAPTIC:
+ return tr("Haptic");
+ default:
+ return CPN_STR_UNKNOWN_ITEM;
+ }
+}
+
+// static
+QString TimerData::countdownStartToString(const int value)
+{
+ switch(value) {
+ case COUNTDOWNSTART_5:
+ return tr("5s");
+ case COUNTDOWNSTART_10:
+ return tr("10s");
+ case COUNTDOWNSTART_20:
+ return tr("20s");
+ case COUNTDOWNSTART_30:
+ return tr("30s");
+ default:
+ return CPN_STR_UNKNOWN_ITEM;
+ }
+}
+
+// static
+QString TimerData::persistentToString(const int value, const bool verbose)
+{
+ switch(value) {
+ case PERSISTENT_NOT:
+ return verbose ? tr("Not persistent") : tr("NOT");
+ case PERSISTENT_FLIGHT:
+ return verbose ? tr("Persistent (flight)") : tr("Flight");
+ case PERSISTENT_MANUALRESET:
+ return verbose ? tr("Persistent (manual reset)") : tr("Manual reset");
+ default:
+ return CPN_STR_UNKNOWN_ITEM;
+ }
+}
+
+// static
+QString TimerData::pvalueToString(const int value)
+{
+ return DataHelpers::timeToString(value, TIMESTR_MASK_HRSMINS | TIMESTR_MASK_ZEROHRS);
+}
+
+// static
+QString TimerData::valToString(const int value)
+{
+ return DataHelpers::timeToString(value, TIMESTR_MASK_HRSMINS | TIMESTR_MASK_ZEROHRS);
+}
+
+// static
+AbstractStaticItemModel * TimerData::countdownBeepItemModel()
+{
+ AbstractStaticItemModel * mdl = new AbstractStaticItemModel();
+ mdl->setName(AIM_TIMER_COUNTDOWNBEEP);
+
+ for (int i = 0; i < COUNTDOWNBEEP_COUNT; i++) {
+ mdl->appendToItemList(countdownBeepToString(i), i);
+ }
+
+ mdl->loadItemList();
+ return mdl;
+}
+
+// static
+AbstractStaticItemModel * TimerData::countdownStartItemModel()
+{
+ AbstractStaticItemModel * mdl = new AbstractStaticItemModel();
+ mdl->setName(AIM_TIMER_COUNTDOWNSTART);
+
+ for (int i = COUNTDOWNSTART_LAST; i >= COUNTDOWNSTART_FIRST; i--) {
+ mdl->appendToItemList(countdownStartToString(i), i);
+ }
+
+ mdl->loadItemList();
+ return mdl;
+}
+
+// static
+AbstractStaticItemModel * TimerData::persistentItemModel()
+{
+ AbstractStaticItemModel * mdl = new AbstractStaticItemModel();
+ mdl->setName(AIM_TIMER_PERSISTENT);
+
+ for (int i = 0; i < PERSISTENT_COUNT; i++) {
+ mdl->appendToItemList(persistentToString(i), i);
+ }
+
+ mdl->loadItemList();
+ return mdl;
+}
diff --git a/companion/src/firmwares/timerdata.h b/companion/src/firmwares/timerdata.h
new file mode 100644
index 000000000..07cc1eedd
--- /dev/null
+++ b/companion/src/firmwares/timerdata.h
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "rawswitch.h"
+#include "datahelpers.h"
+
+#include
+
+class RadioDataConversionState;
+class AbstractStaticItemModel;
+
+constexpr char AIM_TIMER_COUNTDOWNBEEP[] {"timerdata.countdownBeep"};
+constexpr char AIM_TIMER_COUNTDOWNSTART[] {"timerdata.countdownStart"};
+constexpr char AIM_TIMER_PERSISTENT[] {"timerdata.persistent"};
+
+constexpr int TIMER_NAME_LEN {8};
+
+class TimerData {
+ Q_DECLARE_TR_FUNCTIONS(TimerData)
+
+ public:
+ enum CountDownBeepType {
+ COUNTDOWNBEEP_SILENT,
+ COUNTDOWNBEEP_BEEPS,
+ COUNTDOWNBEEP_VOICE,
+ COUNTDOWNBEEP_HAPTIC,
+ COUNTDOWNBEEP_COUNT
+ };
+
+ enum CountDownStart {
+ COUNTDOWNSTART_30 = -2,
+ COUNTDOWNSTART_FIRST = COUNTDOWNSTART_30,
+ COUNTDOWNSTART_20,
+ COUNTDOWNSTART_10,
+ COUNTDOWNSTART_5,
+ COUNTDOWNSTART_LAST = COUNTDOWNSTART_5
+ };
+
+ enum PersistentType {
+ PERSISTENT_NOT,
+ PERSISTENT_FLIGHT,
+ PERSISTENT_MANUALRESET,
+ PERSISTENT_COUNT
+ };
+
+ TimerData() { clear(); }
+
+ RawSwitch mode;
+ char name[TIMER_NAME_LEN + 1];
+ bool minuteBeep;
+ unsigned int countdownBeep;
+ unsigned int val;
+ unsigned int persistent;
+ int countdownStart;
+ unsigned int direction;
+ int pvalue;
+
+ void convert(RadioDataConversionState & cstate);
+ void clear();
+ bool isEmpty();
+ bool isModeOff();
+ QString nameToString(int index) const;
+ QString countdownBeepToString() const;
+ QString countdownStartToString() const;
+ QString persistentToString(const bool verbose = true) const;
+ QString pvalueToString() const;
+ QString valToString() const;
+ void countdownBeepChanged();
+
+ static QString countdownBeepToString(const int value);
+ static QString countdownStartToString(const int value);
+ static QString persistentToString(const int value, const bool verbose = true);
+ static QString pvalueToString(const int value);
+ static QString valToString(const int value);
+ static AbstractStaticItemModel * countdownBeepItemModel();
+ static AbstractStaticItemModel * countdownStartItemModel();
+ static AbstractStaticItemModel * persistentItemModel();
+
+};
diff --git a/companion/src/flashfirmwaredialog.cpp b/companion/src/flashfirmwaredialog.cpp
index 4650cd4c0..fc45a89ff 100644
--- a/companion/src/flashfirmwaredialog.cpp
+++ b/companion/src/flashfirmwaredialog.cpp
@@ -275,11 +275,12 @@ void FlashFirmwareDialog::startFlash(const QString &filename)
ProgressDialog progressDialog(this, tr("Write Firmware to Radio"), CompanionIcon("write_flash.png"));
// check hardware compatibility if requested
+ bool checkPassed = true;
if (g.checkHardwareCompatibility()) {
QString tempFirmware = generateProcessUniqueTempFileName("flash-check.bin");
if (!readFirmware(tempFirmware, progressDialog.progress())) {
QMessageBox::warning(this, tr("Firmware check failed"), tr("Could not check firmware from radio"));
- return;
+ checkPassed = false;
}
FirmwareInterface previousFirmware(tempFirmware);
qunlink(tempFirmware);
@@ -291,41 +292,44 @@ void FlashFirmwareDialog::startFlash(const QString &filename)
qDebug() << "startFlash: removing temporary file" << filename;
qunlink(filename);
}
- return;
+ checkPassed = false;
}
}
- // backup if requested
- bool result = true;
- QString backupFilename;
- QString backupPath;
- if (backup) {
- backupPath = g.profile[g.id()].pBackupDir();
- if (backupPath.isEmpty()) {
- backupPath=g.backupDir();
+ if (checkPassed) {
+ // backup if requested
+ bool result = true;
+ QString backupFilename;
+ QString backupPath;
+ if (backup) {
+ backupPath = g.profile[g.id()].pBackupDir();
+ if (backupPath.isEmpty()) {
+ backupPath=g.backupDir();
+ }
+ backupFilename = backupPath + "/backup-" + QDateTime().currentDateTime().toString("yyyy-MM-dd-HHmmss") + ".bin";
+ result = readEeprom(backupFilename, progressDialog.progress());
+ sleep(2);
}
- backupFilename = backupPath + "/backup-" + QDateTime().currentDateTime().toString("yyyy-MM-dd-HHmmss") + ".bin";
- result = readEeprom(backupFilename, progressDialog.progress());
- sleep(2);
+
+ // flash
+ result = (result && writeFirmware(filename, progressDialog.progress()));
+
+ // restore if backup requested
+ if (backup && result) {
+ sleep(2);
+ QString restoreFilename = generateProcessUniqueTempFileName("restore.bin");
+ if (!convertEEprom(backupFilename, restoreFilename, filename)) {
+ QMessageBox::warning(this, tr("Conversion failed"), tr("Cannot convert Models and Settings for use with this firmware, original data will be used"));
+ restoreFilename = backupFilename;
+ }
+ if (!writeEeprom(restoreFilename, progressDialog.progress())) {
+ QMessageBox::warning(this, tr("Restore failed"), tr("Could not restore Models and Settings to Radio. The models and settings data file can be found at: %1").arg(backupFilename));
+ }
+ }
+
+ progressDialog.progress()->setInfo(tr("Flashing done"));
}
-
- // flash
- result = (result && writeFirmware(filename, progressDialog.progress()));
-
- // restore if backup requested
- if (backup && result) {
- sleep(2);
- QString restoreFilename = generateProcessUniqueTempFileName("restore.bin");
- if (!convertEEprom(backupFilename, restoreFilename, filename)) {
- QMessageBox::warning(this, tr("Conversion failed"), tr("Cannot convert Models and Settings for use with this firmware, original data will be used"));
- restoreFilename = backupFilename;
- }
- if (!writeEeprom(restoreFilename, progressDialog.progress())) {
- QMessageBox::warning(this, tr("Restore failed"), tr("Could not restore Models and Settings to Radio. The models and settings data file can be found at: %1").arg(backupFilename));
- }
- }
-
- progressDialog.progress()->setInfo(tr("Flashing done"));
+
progressDialog.exec();
if (isTempFileName(filename)) {
diff --git a/companion/src/generaledit/CMakeLists.txt b/companion/src/generaledit/CMakeLists.txt
index 827c37ddf..2c458c719 100644
--- a/companion/src/generaledit/CMakeLists.txt
+++ b/companion/src/generaledit/CMakeLists.txt
@@ -28,4 +28,4 @@ qt5_wrap_ui(generaledit_SRCS ${generaledit_UIS})
qt5_wrap_cpp(generaledit_SRCS ${generaledit_HDRS})
add_library(generaledit ${generaledit_SRCS})
-target_link_libraries(generaledit PRIVATE ${CPN_COMMON_LIB} Qt5::Multimedia)
+target_link_libraries(generaledit PRIVATE datamodels ${CPN_COMMON_LIB} Qt5::Multimedia)
diff --git a/companion/src/generaledit/generaledit.cpp b/companion/src/generaledit/generaledit.cpp
index 34d090e65..e80038f9f 100644
--- a/companion/src/generaledit/generaledit.cpp
+++ b/companion/src/generaledit/generaledit.cpp
@@ -28,6 +28,7 @@
#include "hardware.h"
#include "../modeledit/customfunctions.h"
#include "verticalscrollarea.h"
+#include "compounditemmodels.h"
GeneralEdit::GeneralEdit(QWidget * parent, RadioData & radioData, Firmware * firmware) :
QDialog(parent),
@@ -55,8 +56,14 @@ GeneralEdit::GeneralEdit(QWidget * parent, RadioData & radioData, Firmware * fir
}
}
+ sharedItemModels = new CompoundItemModelFactory(&generalSettings, nullptr);
+ sharedItemModels->addItemModel(AbstractItemModel::IMID_RawSource);
+ sharedItemModels->addItemModel(AbstractItemModel::IMID_RawSwitch);
+ sharedItemModels->addItemModel(AbstractItemModel::IMID_CustomFuncAction);
+ sharedItemModels->addItemModel(AbstractItemModel::IMID_CustomFuncResetParam);
+
addTab(new GeneralSetupPanel(this, generalSettings, firmware), tr("Setup"));
- addTab(new CustomFunctionsPanel(this, NULL, generalSettings, firmware), tr("Global Functions"));
+ addTab(new CustomFunctionsPanel(this, nullptr, generalSettings, firmware, sharedItemModels), tr("Global Functions"));
addTab(new TrainerPanel(this, generalSettings, firmware), tr("Trainer"));
addTab(new HardwarePanel(this, generalSettings, firmware), tr("Hardware"));
addTab(new CalibrationPanel(this, generalSettings, firmware), tr("Calibration"));
@@ -67,6 +74,7 @@ GeneralEdit::GeneralEdit(QWidget * parent, RadioData & radioData, Firmware * fir
GeneralEdit::~GeneralEdit()
{
delete ui;
+ delete sharedItemModels;
}
void GeneralEdit::closeEvent(QCloseEvent *event)
diff --git a/companion/src/generaledit/generaledit.h b/companion/src/generaledit/generaledit.h
index 1c1d096a5..b2e6caa82 100644
--- a/companion/src/generaledit/generaledit.h
+++ b/companion/src/generaledit/generaledit.h
@@ -25,6 +25,8 @@
#include "eeprominterface.h"
#include "genericpanel.h"
+class CompoundItemModelFactory;
+
namespace Ui {
class GeneralEdit;
}
@@ -56,7 +58,7 @@ class GeneralEdit : public QDialog
void getGeneralSwitchDefPos(int i, bool val);
void setSwitchDefPos();
void updateVarioPitchRange();
-
+
signals:
void modified();
@@ -71,7 +73,7 @@ class GeneralEdit : public QDialog
QVector panels;
void addTab(GenericPanel *panel, QString text);
void closeEvent(QCloseEvent *event);
-
+ CompoundItemModelFactory *sharedItemModels;
};
#endif // _GENERALEDIT_H_
diff --git a/companion/src/generaledit/generalsetup.cpp b/companion/src/generaledit/generalsetup.cpp
index 16ef5b271..5404a8ccb 100644
--- a/companion/src/generaledit/generalsetup.cpp
+++ b/companion/src/generaledit/generalsetup.cpp
@@ -158,7 +158,7 @@ ui(new Ui::GeneralSetup)
ui->usbModeLabel->hide();
ui->usbModeCB->hide();
}
-
+
if (firmware->getCapability(HasSwitchableJack)) {
ui->jackModeCB->setCurrentIndex(generalSettings.jackMode);
}
@@ -266,7 +266,7 @@ ui(new Ui::GeneralSetup)
ui->pwrOnDelayLabel->hide();
ui->pwrOnDelay->hide();
}
-
+
setValues();
lock = false;
@@ -505,13 +505,13 @@ void GeneralSetupPanel::on_splashScreenDuration_currentIndexChanged(int index)
emit modified();
}
-void GeneralSetupPanel::on_pwrOnDelay_valueChanged()
+void GeneralSetupPanel::on_pwrOnDelay_valueChanged(int)
{
generalSettings.pwrOnSpeed = 2 - ui->pwrOnDelay->value();
emit modified();
}
-void GeneralSetupPanel::on_pwrOffDelay_valueChanged()
+void GeneralSetupPanel::on_pwrOffDelay_valueChanged(int)
{
generalSettings.pwrOffSpeed = 2 - ui->pwrOffDelay->value();
emit modified();
@@ -650,7 +650,7 @@ void GeneralSetupPanel::on_backlightautoSB_editingFinished()
}
}
-void GeneralSetupPanel::on_switchesDelay_valueChanged()
+void GeneralSetupPanel::on_switchesDelay_valueChanged(int)
{
generalSettings.switchesDelay = (ui->switchesDelay->value() / 10) - 15;
emit modified();
diff --git a/companion/src/generaledit/generalsetup.h b/companion/src/generaledit/generalsetup.h
index 34aeaaa71..43e098aee 100644
--- a/companion/src/generaledit/generalsetup.h
+++ b/companion/src/generaledit/generalsetup.h
@@ -65,7 +65,7 @@ class GeneralSetupPanel : public GeneralPanel
void on_mavbaud_CB_currentIndexChanged(int index);
void on_voiceLang_CB_currentIndexChanged(int index);
void stickReverseEdited();
- void on_switchesDelay_valueChanged();
+ void on_switchesDelay_valueChanged(int);
void on_blAlarm_ChkB_stateChanged();
void unlockSwitchEdited();
void on_beepVolume_SL_valueChanged();
@@ -89,8 +89,8 @@ class GeneralSetupPanel : public GeneralPanel
void on_contrastSB_editingFinished();
void on_registrationId_editingFinished();
- void on_pwrOnDelay_valueChanged();
- void on_pwrOffDelay_valueChanged();
+ void on_pwrOnDelay_valueChanged(int);
+ void on_pwrOffDelay_valueChanged(int);
private:
Ui::GeneralSetup *ui;
diff --git a/companion/src/generaledit/generalsetup.ui b/companion/src/generaledit/generalsetup.ui
index 7353b9c4b..422eddc7d 100644
--- a/companion/src/generaledit/generalsetup.ui
+++ b/companion/src/generaledit/generalsetup.ui
@@ -1527,7 +1527,7 @@ Mode 4:
Battery warning voltage.
This is the threashhold where the battery warning sounds.
-Acceptable values are 5v..10v
+Acceptable values are 3v..12v
@@ -1539,7 +1539,7 @@ Acceptable values are 5v..10v
1
- 4.000000000000000
+ 3.000000000000000
12.000000000000000
@@ -1679,7 +1679,7 @@ Acceptable values are 5v..10v
1
- 4.000000000000000
+ 3.000000000000000
16.000000000000000
@@ -1708,7 +1708,7 @@ Acceptable values are 5v..10v
1
- 4.000000000000000
+ 3.000000000000000
16.000000000000000
diff --git a/companion/src/generaledit/hardware.cpp b/companion/src/generaledit/hardware.cpp
index 78d0ec75d..9d2e8e452 100644
--- a/companion/src/generaledit/hardware.cpp
+++ b/companion/src/generaledit/hardware.cpp
@@ -47,7 +47,15 @@ void HardwarePanel::setupSwitchType(int index, QLabel * label, AutoLineEdit * na
label->setText("SJ");
}
}
- if (IS_JUMPER_T12(board)) {
+ else if (IS_RADIOMASTER_TX12(board)) {
+ if (index == 6) {
+ label->setText("SI");
+ }
+ else if (index == 7) {
+ label->setText("SJ");
+ }
+ }
+ else if (IS_FAMILY_T12(board)) {
if (index == 4) {
label->setText("SG");
}
@@ -101,6 +109,15 @@ void HardwarePanel::setupSliderType(int index, QLabel *label, AutoLineEdit *name
}
}
+bool HardwarePanel::isSwitch3Pos(int idx)
+{
+ Board::Type board = firmware->getBoard();
+ Board::SwitchInfo switchInfo = Boards::getSwitchInfo(board, idx);
+
+ switchInfo.config = Board::SwitchType(generalSettings.switchConfig[idx]);
+ return switchInfo.config == Board::SWITCH_3POS;
+};
+
HardwarePanel::HardwarePanel(QWidget * parent, GeneralSettings & generalSettings, Firmware * firmware):
GeneralPanel(parent, generalSettings, firmware),
ui(new Ui::Hardware)
@@ -127,6 +144,14 @@ HardwarePanel::HardwarePanel(QWidget * parent, GeneralSettings & generalSettings
ui->potsTypeSeparator_1->hide();
ui->potsTypeSeparator_2->hide();
}
+
+ if (firmware->getCapability(HasSportConnector)) {
+ ui->sportPower->setChecked(generalSettings.sportPower);
+ }
+ else {
+ ui->sportPower->hide();
+ ui->sportPowerLabel->hide();
+ }
setupPotType(0, ui->pot1Label, ui->pot1Name, ui->pot1Type);
setupPotType(1, ui->pot2Label, ui->pot2Name, ui->pot2Type);
@@ -139,17 +164,17 @@ HardwarePanel::HardwarePanel(QWidget * parent, GeneralSettings & generalSettings
setupSliderType(2, ui->ls2Label, ui->ls2Name, ui->ls2Type);
setupSliderType(3, ui->rs2Label, ui->rs2Name, ui->rs2Type);
- setupSwitchType(0, ui->saLabel, ui->saName, ui->saType);
- setupSwitchType(1, ui->sbLabel, ui->sbName, ui->sbType);
- setupSwitchType(2, ui->scLabel, ui->scName, ui->scType);
- setupSwitchType(3, ui->sdLabel, ui->sdName, ui->sdType);
- setupSwitchType(4, ui->seLabel, ui->seName, ui->seType);
- setupSwitchType(5, ui->sfLabel, ui->sfName, ui->sfType, false); //switch does not support 3POS
- setupSwitchType(6, ui->sgLabel, ui->sgName, ui->sgType);
- setupSwitchType(7, ui->shLabel, ui->shName, ui->shType, false); //switch does not support 3POS
- setupSwitchType(8, ui->siLabel, ui->siName, ui->siType);
- setupSwitchType(9, ui->sjLabel, ui->sjName, ui->sjType);
- setupSwitchType(10, ui->skLabel, ui->skName, ui->skType);
+ setupSwitchType(0, ui->saLabel, ui->saName, ui->saType, isSwitch3Pos(0));
+ setupSwitchType(1, ui->sbLabel, ui->sbName, ui->sbType, isSwitch3Pos(1));
+ setupSwitchType(2, ui->scLabel, ui->scName, ui->scType, isSwitch3Pos(2));
+ setupSwitchType(3, ui->sdLabel, ui->sdName, ui->sdType, isSwitch3Pos(3));
+ setupSwitchType(4, ui->seLabel, ui->seName, ui->seType, isSwitch3Pos(4));
+ setupSwitchType(5, ui->sfLabel, ui->sfName, ui->sfType, isSwitch3Pos(5));
+ setupSwitchType(6, ui->sgLabel, ui->sgName, ui->sgType, isSwitch3Pos(6));
+ setupSwitchType(7, ui->shLabel, ui->shName, ui->shType, isSwitch3Pos(7));
+ setupSwitchType(8, ui->siLabel, ui->siName, ui->siType, isSwitch3Pos(8));
+ setupSwitchType(9, ui->sjLabel, ui->sjName, ui->sjType, isSwitch3Pos(9));
+ setupSwitchType(10, ui->skLabel, ui->skName, ui->skType); // Here starts X9E, only 3 switches
setupSwitchType(11, ui->slLabel, ui->slName, ui->slType);
setupSwitchType(12, ui->smLabel, ui->smName, ui->smType);
setupSwitchType(13, ui->snLabel, ui->snName, ui->snType);
@@ -232,6 +257,11 @@ void HardwarePanel::on_filterEnable_stateChanged()
generalSettings.jitterFilter = !ui->filterEnable->isChecked();
}
+void HardwarePanel::on_sportPower_stateChanged()
+{
+ generalSettings.sportPower = ui->sportPower->isChecked();
+}
+
void HardwarePanel::on_rtcCheckDisable_stateChanged()
{
generalSettings.rtcCheckDisable = !ui->rtcCheckDisable->isChecked();
diff --git a/companion/src/generaledit/hardware.h b/companion/src/generaledit/hardware.h
index 8101b784c..3b63a1d77 100644
--- a/companion/src/generaledit/hardware.h
+++ b/companion/src/generaledit/hardware.h
@@ -50,6 +50,7 @@ class HardwarePanel : public GeneralPanel
void on_txVoltageCalibration_editingFinished();
void on_filterEnable_stateChanged();
void on_rtcCheckDisable_stateChanged();
+ void on_sportPower_stateChanged();
void on_serialPortMode_currentIndexChanged(int index);
@@ -62,6 +63,7 @@ class HardwarePanel : public GeneralPanel
Ui::Hardware *ui;
void setValues();
+ bool isSwitch3Pos(int idx);
};
#endif // _HARDWARE_H_
diff --git a/companion/src/generaledit/hardware.ui b/companion/src/generaledit/hardware.ui
index 45e8e8da6..5224ed785 100644
--- a/companion/src/generaledit/hardware.ui
+++ b/companion/src/generaledit/hardware.ui
@@ -23,6 +23,315 @@
6
+ -
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
-
+
+ OFF
+
+
+ -
+
+ S-Port Mirror
+
+
+ -
+
+ Telemetry
+
+
+ -
+
+ SBUS Trainer
+
+
+ -
+
+ Debug
+
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+ Thr
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+ 3
+
+
+
+ -
+
+
+ -
+
+
+ 3
+
+
+
+ -
+
+
+ SD
+
+
+
+ -
+
+
+ 3
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+ -
+
+
+ -
+
+
+
+ 0
+ 10
+
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
+ SO
+
+
+
+ -
+
+
+ -49
+
+
+ 49
+
+
+
+ -
+
+
+ 3
+
+
+
+ -
+
+
+ RS
+
+
+
+ -
+
+
+ 3
+
+
+
+ -
+
+
+ Ail
+
+
+
+ -
+
+
+ S4
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+
+ -9999
+
+
+ 9999
+
+
+
+ -
+
+
+ LS2
+
+
+
+ -
+
+
+ Antenna
+
+
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
+
+
+
+ -
+
+
+ PPM 1
+
+
+
+ -
+
+
+ LS
+
+
+
+ -
+
+
+ Rud
+
+
+
+ -
+
+
+ Serial Port
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+ SP
+
+
+
+ -
+
+
+ 3
+
+
+
+ -
+
+
+ RS2
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+ -
+
+
+ SH
+
+
+
+ -
+
+
+
+
+
+
+
+
+
-
@@ -30,6 +339,13 @@
+ -
+
+
+ SE
+
+
+
-
@@ -43,22 +359,35 @@
- -
-
-
- SC
+
-
+
+
+ 1
+
+
+ 5.000000000000000
+
+
+ 1.000000000000000
- -
-
+
-
+
+
+ S2
+
+
+
+ -
+
3
- -
-
+
-
+
@@ -76,6 +405,463 @@
+ -
+
+
+ SJ
+
+
+
+ -
+
+
+ PPM 2
+
+
+
+ -
+
+
+ 3
+
+
+
+ -
+
+
+ SG
+
+
+
+ -
+
+
+ S5
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+ 3
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+ 0
+ 10
+
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
+ Current Offset
+
+
+
+ -
+
+
+ SK
+
+
+
+ -
+
+
+ 3
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+ -
+
+
+ ADC Filter
+
+
+
+ -
+
+
+ 3
+
+
+
+ -
+
+
+ 3
+
+
+
+ -
+
+
+ SF
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+ -
+
+
+ S3
+
+
+
+ -
+
+
+ 3
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+ 3
+
+
+
+ -
+
+
+ SB
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+ SI
+
+
+
+ -
+
+
+ SQ
+
+
+
+ -
+
+
+ Ele
+
+
+
+ -
+
+
+ 3
+
+
+
+ -
+
+
+ 3
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+ -
+
+
+ 3
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+ 3
+
+
+
+ -
+
+
+ 3
+
+
+
+ -
+
+
+ -
+
+
+ SA
+
+
+
+ -
+
+
+ 3
+
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+ SR
+
+
+
+ -
+
+
+ 3
+
+
+
+ -
+
+
+ PPM Multiplier
+
+
+
+ -
+
+
+ S1
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Bluetooth
+
+
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
+
+
+
+ -
+
+
+ PPM 4
+
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+
+
+
+ v
+
+
+ 1
+
+
+ -9.900000000000000
+
+
+ 9.900000000000000
+
+
+ 0.100000000000000
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+ 3
+
+
+
+ -
+
+
+ 3
+
+
+
-
@@ -134,31 +920,76 @@
- -
-
-
- 3
-
-
-
- -
-
+
-
+
- SR
+ PPM 3
- -
-
+
-
+
- S4
+ RTC Batt Check
- -
-
-
- 3
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+ SL
+
+
+
+ -
+
+
+
+
+
+
+
+
+
@@ -169,26 +1000,50 @@
- -
-
-
- -49
-
-
- 49
+
-
+
+
+ 3
- -
-
-
-
- 0
- 10
-
+
-
+
+
+
-
- Qt::Horizontal
+
+
+
+
+
+
+
+ -9999
+
+
+ 9999
+
+
+
+ -
+
+
+ 3
+
+
+
+ -
+
+
+ SC
+
+
+
+ -
+
+
+ 3
@@ -211,26 +1066,6 @@
- -
-
-
-
- 0
- 10
-
-
-
- Qt::Horizontal
-
-
-
- -
-
-
- RS2
-
-
-
-
@@ -244,778 +1079,6 @@
- -
-
-
- 3
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Bluetooth
-
-
- Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
-
-
-
- -
-
-
- Current Offset
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
- PPM 2
-
-
-
- -
-
-
- 3
-
-
-
- -
-
-
- SD
-
-
-
- -
-
-
- 3
-
-
-
- -
-
-
- -
-
-
- 3
-
-
-
- -
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
- 3
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
- SJ
-
-
-
- -
-
-
- SA
-
-
-
- -
-
-
- S1
-
-
-
- -
-
-
- S3
-
-
-
- -
-
-
- SP
-
-
-
- -
-
-
- SF
-
-
-
- -
-
-
- LS
-
-
-
- -
-
-
- 3
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
- 3
-
-
-
- -
-
-
- 3
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
- 3
-
-
-
- -
-
-
- 3
-
-
-
- -
-
-
- 1
-
-
- 5.000000000000000
-
-
- 1.000000000000000
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
- 3
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
- Battery Offset
-
-
-
- -
-
-
- Serial Port
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- SG
-
-
-
- -
-
-
- S2
-
-
-
- -
-
-
- Ele
-
-
-
- -
-
-
- SI
-
-
-
- -
-
-
- 3
-
-
-
- -
-
-
- 3
-
-
-
- -
-
-
- SL
-
-
-
- -
-
-
- SQ
-
-
-
- -
-
-
- 3
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
- 3
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
- SO
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -9999
-
-
- 9999
-
-
-
- -
-
-
- PPM 1
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
- PPM 4
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -9999
-
-
- 9999
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
- SB
-
-
-
- -
-
-
- 3
-
-
-
- -
-
-
-
-
-
- v
-
-
- 1
-
-
- -9.900000000000000
-
-
- 9.900000000000000
-
-
- 0.100000000000000
-
-
-
- -
-
-
- PPM Multiplier
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
- 3
-
-
-
- -
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
- Rud
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
- ADC Filter
-
-
-
- -
-
-
- 3
-
-
-
- -
-
-
- 3
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
- S5
-
-
-
- -
-
-
- Antenna
-
-
- Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
-
-
-
- -
-
-
- PPM 3
-
-
-
- -
-
-
- Ail
-
-
-
- -
-
-
- SK
-
-
-
- -
-
-
- SE
-
-
-
- -
-
-
- LS2
-
-
-
- -
-
-
- 3
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
- 3
-
-
-
- -
-
-
- Thr
-
-
-
- -
-
-
- 3
-
-
-
- -
-
-
- SH
-
-
-
-
@@ -1029,64 +1092,8 @@
- -
-
-
- 3
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
- OFF
-
-
- -
-
- S-Port Mirror
-
-
- -
-
- Telemetry
-
-
- -
-
- SBUS Trainer
-
-
- -
-
- Debug
-
-
-
-
- -
-
-
- RS
-
-
-
- -
-
+
-
+
3
@@ -1099,10 +1106,10 @@
- -
-
-
- 3
+
-
+
+
+ Battery Offset
@@ -1113,17 +1120,24 @@
- -
-
-
-
+
-
+
+
+ 3
- -
-
+
-
+
- RTC Batt Check
+ S.Port Power
+
+
+
+ -
+
+
+
diff --git a/companion/src/helpers.cpp b/companion/src/helpers.cpp
index 2b0f62503..c1cd7de79 100644
--- a/companion/src/helpers.cpp
+++ b/companion/src/helpers.cpp
@@ -32,6 +32,7 @@
#include "simulatorinterface.h"
#include "simulatormainwindow.h"
#include "storage/sdcard.h"
+#include "filtereditemmodels.h"
#include
#include
@@ -117,7 +118,8 @@ void CompanionIcon::addImage(const QString & baseimage, Mode mode, State state)
* GVarGroup
*/
-GVarGroup::GVarGroup(QCheckBox * weightGV, QAbstractSpinBox * weightSB, QComboBox * weightCB, int & weight, const ModelData & model, const int deflt, const int mini, const int maxi, const double step, bool allowGvars):
+GVarGroup::GVarGroup(QCheckBox * weightGV, QAbstractSpinBox * weightSB, QComboBox * weightCB, int & weight, const ModelData & model,
+ const int deflt, const int mini, const int maxi, const double step, FilteredItemModel * gvarModel):
QObject(),
weightGV(weightGV),
weightSB(weightSB),
@@ -131,8 +133,8 @@ GVarGroup::GVarGroup(QCheckBox * weightGV, QAbstractSpinBox * weightSB, QComboBo
step(step),
lock(true)
{
- if (allowGvars && getCurrentFirmware()->getCapability(Gvars)) {
- Helpers::populateGVCB(*weightCB, weight, model);
+ if (gvarModel && gvarModel->rowCount() > 0) {
+ weightCB->setModel(gvarModel);
connect(weightGV, SIGNAL(stateChanged(int)), this, SLOT(gvarCBChanged(int)));
connect(weightCB, SIGNAL(currentIndexChanged(int)), this, SLOT(valuesChanged()));
}
@@ -152,12 +154,19 @@ GVarGroup::GVarGroup(QCheckBox * weightGV, QAbstractSpinBox * weightSB, QComboBo
void GVarGroup::gvarCBChanged(int state)
{
- weightCB->setVisible(state);
- if (weightSB)
+ if (!lock) {
+ weightCB->setVisible(state);
+ if (weightGV->isChecked()) {
+ // set CB to +GV1
+ int cnt = getCurrentFirmware()->getCapability(Gvars);
+ if (weightCB->count() > cnt)
+ weightCB->setCurrentIndex(cnt);
+ else
+ weightCB->setCurrentIndex(0);
+ }
weightSB->setVisible(!state);
- else
- weightSB->setVisible(!state);
- valuesChanged();
+ valuesChanged();
+ }
}
void GVarGroup::valuesChanged()
@@ -168,7 +177,7 @@ void GVarGroup::valuesChanged()
else if (sb)
weight = sb->value();
else
- weight = round(dsb->value()/step);
+ weight = round(dsb->value() / step);
emit valueChanged();
}
@@ -180,7 +189,7 @@ void GVarGroup::setWeight(int val)
int tval;
- if (val>maxi || val maxi || val < mini) {
tval = deflt;
weightGV->setChecked(true);
weightSB->hide();
@@ -210,215 +219,10 @@ void GVarGroup::setWeight(int val)
lock = false;
}
-
-/*
- * CurveGroup
-*/
-
-CurveGroup::CurveGroup(QComboBox * curveTypeCB, QCheckBox * curveGVarCB, QComboBox * curveValueCB, QSpinBox * curveValueSB, CurveReference & curve, const ModelData & model, unsigned int flags):
- QObject(),
- curveTypeCB(curveTypeCB),
- curveGVarCB(curveGVarCB),
- curveValueCB(curveValueCB),
- curveValueSB(curveValueSB),
- curve(curve),
- model(model),
- flags(flags),
- lock(false),
- lastType(-1)
-{
- if (!(flags & HIDE_DIFF)) curveTypeCB->addItem(tr("Diff"), 0);
- if (!(flags & HIDE_EXPO)) curveTypeCB->addItem(tr("Expo"), 1);
- curveTypeCB->addItem(tr("Func"), 2);
- curveTypeCB->addItem(tr("Curve"), 3);
-
- curveValueCB->setMaxVisibleItems(10);
-
- connect(curveTypeCB, SIGNAL(currentIndexChanged(int)), this, SLOT(typeChanged(int)));
- connect(curveGVarCB, SIGNAL(stateChanged(int)), this, SLOT(gvarCBChanged(int)));
- connect(curveValueCB, SIGNAL(currentIndexChanged(int)), this, SLOT(valuesChanged()));
- connect(curveValueSB, SIGNAL(editingFinished()), this, SLOT(valuesChanged()));
-
- update();
-}
-
-void CurveGroup::update()
-{
- lock = true;
-
- int found = curveTypeCB->findData(curve.type);
- if (found < 0) found = 0;
- curveTypeCB->setCurrentIndex(found);
-
- if (curve.type == CurveReference::CURVE_REF_DIFF || curve.type == CurveReference::CURVE_REF_EXPO) {
- curveGVarCB->setVisible(getCurrentFirmware()->getCapability(Gvars));
- if (curve.value > 100 || curve.value < -100) {
- curveGVarCB->setChecked(true);
- if (lastType != CurveReference::CURVE_REF_DIFF && lastType != CurveReference::CURVE_REF_EXPO) {
- lastType = curve.type;
- Helpers::populateGVCB(*curveValueCB, curve.value, model);
- }
- curveValueCB->show();
- curveValueSB->hide();
- }
- else {
- curveGVarCB->setChecked(false);
- curveValueSB->setMinimum(-100);
- curveValueSB->setMaximum(100);
- curveValueSB->setValue(curve.value);
- curveValueSB->show();
- curveValueCB->hide();
- }
- }
- else {
- curveGVarCB->hide();
- curveValueSB->hide();
- curveValueCB->show();
- switch (curve.type) {
- case CurveReference::CURVE_REF_FUNC:
- if (lastType != curve.type) {
- lastType = curve.type;
- curveValueCB->clear();
- for (int i=0; i<=6/*TODO constant*/; i++) {
- curveValueCB->addItem(CurveReference(CurveReference::CURVE_REF_FUNC, i).toString(&model, false));
- }
- }
- curveValueCB->setCurrentIndex(curve.value);
- break;
- case CurveReference::CURVE_REF_CUSTOM:
- {
- int numcurves = getCurrentFirmware()->getCapability(NumCurves);
- if (lastType != curve.type) {
- lastType = curve.type;
- curveValueCB->clear();
- for (int i= ((flags & HIDE_NEGATIVE_CURVES) ? 0 : -numcurves); i<=numcurves; i++) {
- curveValueCB->addItem(CurveReference(CurveReference::CURVE_REF_CUSTOM, i).toString(&model, false), i);
- if (i == curve.value) {
- curveValueCB->setCurrentIndex(curveValueCB->count() - 1);
- }
- }
- }
- break;
- }
- default:
- break;
- }
- }
-
- lock = false;
-}
-
-void CurveGroup::gvarCBChanged(int state)
-{
- if (!lock) {
- if (state) {
- curve.value = 10000+1; // TODO constant in EEpromInterface ...
- lastType = -1; // quickfix for issue #3518: force refresh of curveValueCB at next update() to set current index to GV1
- }
- else {
- curve.value = 0; // TODO could be better
- }
-
- update();
- }
-}
-
-void CurveGroup::typeChanged(int value)
-{
- if (!lock) {
- int type = curveTypeCB->itemData(curveTypeCB->currentIndex()).toInt();
- switch (type) {
- case 0:
- curve = CurveReference(CurveReference::CURVE_REF_DIFF, 0);
- break;
- case 1:
- curve = CurveReference(CurveReference::CURVE_REF_EXPO, 0);
- break;
- case 2:
- curve = CurveReference(CurveReference::CURVE_REF_FUNC, 0);
- break;
- case 3:
- curve = CurveReference(CurveReference::CURVE_REF_CUSTOM, 0);
- break;
- }
-
- update();
- }
-}
-
-void CurveGroup::valuesChanged()
-{
- if (!lock) {
- switch (curveTypeCB->itemData(curveTypeCB->currentIndex()).toInt()) {
- case 0:
- case 1:
- {
- int value;
- if (curveGVarCB->isChecked())
- value = curveValueCB->itemData(curveValueCB->currentIndex()).toInt();
- else
- value = curveValueSB->value();
- curve = CurveReference(curveTypeCB->itemData(curveTypeCB->currentIndex()).toInt() == 0 ? CurveReference::CURVE_REF_DIFF : CurveReference::CURVE_REF_EXPO, value);
- break;
- }
- case 2:
- curve = CurveReference(CurveReference::CURVE_REF_FUNC, curveValueCB->currentIndex());
- break;
- case 3:
- curve = CurveReference(CurveReference::CURVE_REF_CUSTOM, curveValueCB->itemData(curveValueCB->currentIndex()).toInt());
- break;
- }
-
- update();
- }
-}
-
-
/*
* Helpers namespace functions
*/
-void Helpers::populateGVCB(QComboBox & b, int value, const ModelData & model)
-{
- int count = getCurrentFirmware()->getCapability(Gvars);
-
- b.clear();
-
- for (int i=-count; i<=-1; i++) {
- int16_t gval = (int16_t)(-10000+i);
- b.addItem("-" + RawSource(SOURCE_TYPE_GVAR, abs(i)-1).toString(&model), gval);
- }
-
- for (int i=1; i<=count; i++) {
- int16_t gval = (int16_t)(10000+i);
- b.addItem(RawSource(SOURCE_TYPE_GVAR, i-1).toString(&model), gval);
- }
-
- b.setCurrentIndex(b.findData(value));
- if (b.currentIndex() == -1)
- b.setCurrentIndex(count);
-}
-
-// Returns Diff/Expo/Weight/Offset adjustment value as either a percentage or a global variable name.
-QString Helpers::getAdjustmentString(int16_t val, const ModelData * model, bool sign)
-{
- QString ret;
- if (val >= -10000 && val <= 10000) {
- ret = "%1%";
- if (sign && val > 0)
- ret.prepend("+");
- ret = ret.arg(val);
- }
- else {
- ret = RawSource(SOURCE_TYPE_GVAR, abs(val) - 10001).toString(model);
- if (val < 0)
- ret.prepend("-");
- else if (sign)
- ret.prepend("+");
- }
- return ret;
-}
-
// TODO: Move lookup to GVarData class (w/out combobox)
void Helpers::populateGvarUseCB(QComboBox * b, unsigned int phase)
{
@@ -742,7 +546,8 @@ GpsCoord extractGpsCoordinates(const QString & position)
return result;
}
-TableLayout::TableLayout(QWidget * parent, int rowCount, const QStringList & headerLabels)
+TableLayout::TableLayout(QWidget * parent, int rowCount, const QStringList & headerLabels) :
+ QObject(parent)
{
#if defined(TABLE_LAYOUT)
tableWidget = new QTableWidget(parent);
diff --git a/companion/src/helpers.h b/companion/src/helpers.h
index 8a7399c56..8bb1cc6b8 100644
--- a/companion/src/helpers.h
+++ b/companion/src/helpers.h
@@ -18,8 +18,7 @@
* GNU General Public License for more details.
*/
-#ifndef _HELPERS_H_
-#define _HELPERS_H_
+#pragma once
#include "eeprominterface.h"
#include
@@ -60,12 +59,15 @@ class CompanionIcon: public QIcon {
void addImage(const QString &baseimage, Mode mode = Normal, State state = Off);
};
+class FilteredItemModel;
+
class GVarGroup: public QObject {
Q_OBJECT
public:
- GVarGroup(QCheckBox * weightGV, QAbstractSpinBox * weightSB, QComboBox * weightCB, int & weight, const ModelData & model, const int deflt, const int mini, const int maxi, const double step=1.0, bool allowGVars=true);
+ GVarGroup(QCheckBox * weightGV, QAbstractSpinBox * weightSB, QComboBox * weightCB, int & weight, const ModelData & model,
+ const int deflt, const int mini, const int maxi, const double step = 1.0, FilteredItemModel * gvarModel = nullptr);
void setWeight(int val);
@@ -98,40 +100,9 @@ class GVarGroup: public QObject {
bool lock;
};
-#define HIDE_DIFF 0x01
-#define HIDE_EXPO 0x02
-#define HIDE_NEGATIVE_CURVES 0x04
-
-class CurveGroup : public QObject {
-
- Q_OBJECT
-
- public:
- CurveGroup(QComboBox *curveTypeCB, QCheckBox *curveGVarCB, QComboBox *curveValueCB, QSpinBox *curveValueSB, CurveReference & curve, const ModelData & model, unsigned int flags=0);
- void update();
-
- protected slots:
- void gvarCBChanged(int);
- void typeChanged(int);
- void valuesChanged();
-
- protected:
- QComboBox *curveTypeCB;
- QCheckBox *curveGVarCB;
- QComboBox *curveValueCB;
- QSpinBox *curveValueSB;
- CurveReference & curve;
- const ModelData & model;
- unsigned int flags;
- bool lock;
- int lastType;
-};
-
namespace Helpers
{
void populateGvarUseCB(QComboBox *b, unsigned int phase);
- void populateGVCB(QComboBox & b, int value, const ModelData & model);
- QString getAdjustmentString(int16_t val, const ModelData * model = NULL, bool sign = false);
void populateFileComboBox(QComboBox * b, const QSet & set, const QString & current);
void getFileComboBoxValue(QComboBox * b, char * dest, int length);
@@ -208,8 +179,9 @@ private:
GpsCoord extractGpsCoordinates(const QString & position);
-class TableLayout
+class TableLayout: public QObject
{
+ Q_OBJECT
public:
TableLayout(QWidget * parent, int rowCount, const QStringList & headerLabels);
// ~TableLayout() ;
@@ -263,5 +235,3 @@ private:
};
extern Stopwatch gStopwatch;
-
-#endif // _HELPERS_H_
diff --git a/companion/src/images/simulator/JumperTLITE/bottom.png b/companion/src/images/simulator/JumperTLITE/bottom.png
new file mode 100644
index 000000000..d7e3f42fc
Binary files /dev/null and b/companion/src/images/simulator/JumperTLITE/bottom.png differ
diff --git a/companion/src/images/simulator/JumperTLITE/bottom_left.png b/companion/src/images/simulator/JumperTLITE/bottom_left.png
new file mode 100644
index 000000000..e6332207c
Binary files /dev/null and b/companion/src/images/simulator/JumperTLITE/bottom_left.png differ
diff --git a/companion/src/images/simulator/JumperTLITE/bottom_right.png b/companion/src/images/simulator/JumperTLITE/bottom_right.png
new file mode 100644
index 000000000..ee5912547
Binary files /dev/null and b/companion/src/images/simulator/JumperTLITE/bottom_right.png differ
diff --git a/companion/src/images/simulator/JumperTLITE/center_LCD.png b/companion/src/images/simulator/JumperTLITE/center_LCD.png
new file mode 100644
index 000000000..f3249de16
Binary files /dev/null and b/companion/src/images/simulator/JumperTLITE/center_LCD.png differ
diff --git a/companion/src/images/simulator/JumperTLITE/left.png b/companion/src/images/simulator/JumperTLITE/left.png
new file mode 100644
index 000000000..eb54a3967
Binary files /dev/null and b/companion/src/images/simulator/JumperTLITE/left.png differ
diff --git a/companion/src/images/simulator/JumperTLITE/left_bottom.png b/companion/src/images/simulator/JumperTLITE/left_bottom.png
new file mode 100644
index 000000000..60e4d30a7
Binary files /dev/null and b/companion/src/images/simulator/JumperTLITE/left_bottom.png differ
diff --git a/companion/src/images/simulator/JumperTLITE/left_top.png b/companion/src/images/simulator/JumperTLITE/left_top.png
new file mode 100644
index 000000000..5ded766e0
Binary files /dev/null and b/companion/src/images/simulator/JumperTLITE/left_top.png differ
diff --git a/companion/src/images/simulator/JumperTLITE/right.png b/companion/src/images/simulator/JumperTLITE/right.png
new file mode 100644
index 000000000..6c455081f
Binary files /dev/null and b/companion/src/images/simulator/JumperTLITE/right.png differ
diff --git a/companion/src/images/simulator/JumperTLITE/right_bottom.png b/companion/src/images/simulator/JumperTLITE/right_bottom.png
new file mode 100644
index 000000000..55c1e5f5f
Binary files /dev/null and b/companion/src/images/simulator/JumperTLITE/right_bottom.png differ
diff --git a/companion/src/images/simulator/JumperTLITE/right_top.png b/companion/src/images/simulator/JumperTLITE/right_top.png
new file mode 100644
index 000000000..6e83d354e
Binary files /dev/null and b/companion/src/images/simulator/JumperTLITE/right_top.png differ
diff --git a/companion/src/images/simulator/JumperTLITE/top.png b/companion/src/images/simulator/JumperTLITE/top.png
new file mode 100644
index 000000000..d90d836d8
Binary files /dev/null and b/companion/src/images/simulator/JumperTLITE/top.png differ
diff --git a/companion/src/images/simulator/T8/bottom.png b/companion/src/images/simulator/T8/bottom.png
new file mode 100644
index 000000000..055c7db62
Binary files /dev/null and b/companion/src/images/simulator/T8/bottom.png differ
diff --git a/companion/src/images/simulator/T8/left-pagedn.png b/companion/src/images/simulator/T8/left-pagedn.png
new file mode 100644
index 000000000..6b290e368
Binary files /dev/null and b/companion/src/images/simulator/T8/left-pagedn.png differ
diff --git a/companion/src/images/simulator/T8/left-pageup.png b/companion/src/images/simulator/T8/left-pageup.png
new file mode 100644
index 000000000..c155649a1
Binary files /dev/null and b/companion/src/images/simulator/T8/left-pageup.png differ
diff --git a/companion/src/images/simulator/T8/left-rtn.png b/companion/src/images/simulator/T8/left-rtn.png
new file mode 100644
index 000000000..95cc700f6
Binary files /dev/null and b/companion/src/images/simulator/T8/left-rtn.png differ
diff --git a/companion/src/images/simulator/T8/left-sys.png b/companion/src/images/simulator/T8/left-sys.png
new file mode 100644
index 000000000..7943ed93d
Binary files /dev/null and b/companion/src/images/simulator/T8/left-sys.png differ
diff --git a/companion/src/images/simulator/T8/left.png b/companion/src/images/simulator/T8/left.png
new file mode 100644
index 000000000..ff25c9543
Binary files /dev/null and b/companion/src/images/simulator/T8/left.png differ
diff --git a/companion/src/images/simulator/T8/right-dn.png b/companion/src/images/simulator/T8/right-dn.png
new file mode 100644
index 000000000..82a383576
Binary files /dev/null and b/companion/src/images/simulator/T8/right-dn.png differ
diff --git a/companion/src/images/simulator/T8/right-ent.png b/companion/src/images/simulator/T8/right-ent.png
new file mode 100644
index 000000000..8c3be3a56
Binary files /dev/null and b/companion/src/images/simulator/T8/right-ent.png differ
diff --git a/companion/src/images/simulator/T8/right-mdl.png b/companion/src/images/simulator/T8/right-mdl.png
new file mode 100644
index 000000000..f385c652e
Binary files /dev/null and b/companion/src/images/simulator/T8/right-mdl.png differ
diff --git a/companion/src/images/simulator/T8/right-up.png b/companion/src/images/simulator/T8/right-up.png
new file mode 100644
index 000000000..5e3bd39ed
Binary files /dev/null and b/companion/src/images/simulator/T8/right-up.png differ
diff --git a/companion/src/images/simulator/T8/right.png b/companion/src/images/simulator/T8/right.png
new file mode 100644
index 000000000..1016d8de5
Binary files /dev/null and b/companion/src/images/simulator/T8/right.png differ
diff --git a/companion/src/images/simulator/T8/top.png b/companion/src/images/simulator/T8/top.png
new file mode 100644
index 000000000..962119223
Binary files /dev/null and b/companion/src/images/simulator/T8/top.png differ
diff --git a/companion/src/images/simulator/TX12/bottom.png b/companion/src/images/simulator/TX12/bottom.png
new file mode 100644
index 000000000..52a35bceb
Binary files /dev/null and b/companion/src/images/simulator/TX12/bottom.png differ
diff --git a/companion/src/images/simulator/TX12/left-pagedn.png b/companion/src/images/simulator/TX12/left-pagedn.png
new file mode 100755
index 000000000..3f83d370c
Binary files /dev/null and b/companion/src/images/simulator/TX12/left-pagedn.png differ
diff --git a/companion/src/images/simulator/TX12/left-pageup.png b/companion/src/images/simulator/TX12/left-pageup.png
new file mode 100755
index 000000000..203fd73e7
Binary files /dev/null and b/companion/src/images/simulator/TX12/left-pageup.png differ
diff --git a/companion/src/images/simulator/TX12/left-rtn.png b/companion/src/images/simulator/TX12/left-rtn.png
new file mode 100755
index 000000000..8269d8853
Binary files /dev/null and b/companion/src/images/simulator/TX12/left-rtn.png differ
diff --git a/companion/src/images/simulator/TX12/left-sys.png b/companion/src/images/simulator/TX12/left-sys.png
new file mode 100755
index 000000000..472b412eb
Binary files /dev/null and b/companion/src/images/simulator/TX12/left-sys.png differ
diff --git a/companion/src/images/simulator/TX12/left-tele.png b/companion/src/images/simulator/TX12/left-tele.png
new file mode 100755
index 000000000..d7971d791
Binary files /dev/null and b/companion/src/images/simulator/TX12/left-tele.png differ
diff --git a/companion/src/images/simulator/TX12/left.png b/companion/src/images/simulator/TX12/left.png
new file mode 100755
index 000000000..e7f5522c1
Binary files /dev/null and b/companion/src/images/simulator/TX12/left.png differ
diff --git a/companion/src/images/simulator/TX12/right-ent.png b/companion/src/images/simulator/TX12/right-ent.png
new file mode 100755
index 000000000..8534cceb2
Binary files /dev/null and b/companion/src/images/simulator/TX12/right-ent.png differ
diff --git a/companion/src/images/simulator/TX12/right-mdl.png b/companion/src/images/simulator/TX12/right-mdl.png
new file mode 100755
index 000000000..4343626ea
Binary files /dev/null and b/companion/src/images/simulator/TX12/right-mdl.png differ
diff --git a/companion/src/images/simulator/TX12/right.png b/companion/src/images/simulator/TX12/right.png
new file mode 100755
index 000000000..0f33cae7c
Binary files /dev/null and b/companion/src/images/simulator/TX12/right.png differ
diff --git a/companion/src/images/simulator/TX12/top.png b/companion/src/images/simulator/TX12/top.png
new file mode 100644
index 000000000..ceb68a4c1
Binary files /dev/null and b/companion/src/images/simulator/TX12/top.png differ
diff --git a/companion/src/mainwindow.cpp b/companion/src/mainwindow.cpp
index 50574ecd5..23c5f71b7 100644
--- a/companion/src/mainwindow.cpp
+++ b/companion/src/mainwindow.cpp
@@ -130,15 +130,9 @@ MainWindow::MainWindow():
else {
if (!g.previousVersion().isEmpty())
g.warningId(g.warningId() | AppMessages::MSG_UPGRADED);
+
if (g.promptProfile()) {
- QTimer::singleShot(updateDelay, this, SLOT(chooseProfile())); // add an extra second to give mainwindow time to load
- updateDelay += 5000; // give user time to select profile before warnings
- }
- else {
- if (checkProfileRadioExists(g.sessionId()))
- QTimer::singleShot(updateDelay, this, SLOT(doAutoUpdates()));
- else
- g.warningId(g.warningId() | AppMessages::MSG_NO_RADIO_TYPE);
+ chooseProfile();
}
}
QTimer::singleShot(updateDelay, this, SLOT(displayWarnings()));
@@ -184,6 +178,11 @@ MainWindow::MainWindow():
if (printing) {
QTimer::singleShot(0, this, SLOT(autoClose()));
}
+
+ if (checkProfileRadioExists(g.sessionId()))
+ QTimer::singleShot(updateDelay, this, SLOT(doAutoUpdates()));
+ else
+ g.warningId(g.warningId() | AppMessages::MSG_NO_RADIO_TYPE);
}
MainWindow::~MainWindow()
@@ -1586,7 +1585,7 @@ void MainWindow::updateWindowActions()
QString scut;
if (++count < 10)
scut = tr("Alt+%1").arg(count);
- QAction * act = addActToGroup(windowsListActions, "", "", "window_ptr", qVariantFromValue(win), QVariant(), scut);
+ QAction * act = addActToGroup(windowsListActions, "", "", "window_ptr", QVariant::fromValue(win), QVariant(), scut);
act->setChecked(win == mdiArea->activeSubWindow());
updateWindowActionTitle(win, act);
}
@@ -1805,10 +1804,8 @@ void MainWindow::chooseProfile()
connect(pcd, &ProfileChooserDialog::profileChanged, this, &MainWindow::loadProfileId);
pcd->exec();
delete pcd;
- // doi here as need to wait until dialog dismissed and current radio type is set
- if (checkProfileRadioExists(g.sessionId()))
- doAutoUpdates();
- else
+
+ if (!checkProfileRadioExists(g.sessionId()))
g.warningId(g.warningId() | AppMessages::MSG_NO_RADIO_TYPE);
}
}
diff --git a/companion/src/modeledit/channels.cpp b/companion/src/modeledit/channels.cpp
index 0cde45109..806ea144e 100644
--- a/companion/src/modeledit/channels.cpp
+++ b/companion/src/modeledit/channels.cpp
@@ -20,43 +20,33 @@
#include "channels.h"
#include "helpers.h"
+#include "filtereditemmodels.h"
-LimitsGroup::LimitsGroup(Firmware * firmware, TableLayout * tableLayout, int row, int col, int & value, const ModelData & model, int min, int max, int deflt, ModelPanel * panel):
+LimitsGroup::LimitsGroup(Firmware * firmware, TableLayout * tableLayout, int row, int col, int & value, const ModelData & model,
+ int min, int max, int deflt, FilteredItemModel * gvarModel, ModelPanel * panel):
firmware(firmware),
spinbox(new QDoubleSpinBox()),
- value(value),
- displayStep(0.1)
+ value(value)
{
- Board::Type board = firmware->getBoard();
- bool allowGVars = IS_HORUS_OR_TARANIS(board);
- int internalStep = 1;
-
spinbox->setProperty("index", row);
spinbox->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
spinbox->setAccelerated(true);
+ spinbox->setDecimals(1);
if (firmware->getCapability(PPMUnitMicroseconds)) {
displayStep = 0.512;
- spinbox->setDecimals(1);
spinbox->setSuffix("us");
}
else {
- spinbox->setDecimals(0);
+ displayStep = 0.1;
spinbox->setSuffix("%");
}
- if (deflt == 0 /*it's the offset*/) {
- spinbox->setDecimals(1);
- }
- else {
- internalStep *= 10;
- }
-
- spinbox->setSingleStep(displayStep * internalStep);
+ spinbox->setSingleStep(displayStep);
spinbox->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
QHBoxLayout *horizontalLayout = new QHBoxLayout();
- QCheckBox *gv = new QCheckBox(tr("GV"));
+ gv = new QCheckBox(tr("GV"));
gv->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
horizontalLayout->addWidget(gv);
QComboBox *cb = new QComboBox();
@@ -64,7 +54,7 @@ LimitsGroup::LimitsGroup(Firmware * firmware, TableLayout * tableLayout, int row
horizontalLayout->addWidget(cb);
horizontalLayout->addWidget(spinbox);
tableLayout->addLayout(row, col, horizontalLayout);
- gvarGroup = new GVarGroup(gv, spinbox, cb, value, model, deflt, min, max, displayStep, allowGVars);
+ gvarGroup = new GVarGroup(gv, spinbox, cb, value, model, deflt, min, max, displayStep, gvarModel);
QObject::connect(gvarGroup, &GVarGroup::valueChanged, panel, &ModelPanel::modified);
}
@@ -83,27 +73,33 @@ void LimitsGroup::updateMinMax(int max)
if (spinbox->maximum() == 0) {
spinbox->setMinimum(-max * displayStep);
gvarGroup->setMinimum(-max);
- if (value < -max) {
+ if (!gv->isChecked() && value < -max) {
value = -max;
}
}
if (spinbox->minimum() == 0) {
spinbox->setMaximum(max * displayStep);
gvarGroup->setMaximum(max);
- if (value > max) {
+ if (!gv->isChecked() && value > max) {
value = max;
}
}
}
-Channels::Channels(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware):
- ModelPanel(parent, model, generalSettings, firmware)
+ChannelsPanel::ChannelsPanel(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CompoundItemModelFactory * sharedItemModels):
+ ModelPanel(parent, model, generalSettings, firmware),
+ sharedItemModels(sharedItemModels)
{
- Stopwatch s1("Channels");
-
chnCapability = firmware->getCapability(Outputs);
int channelNameMaxLen = firmware->getCapability(ChannelsName);
+ dialogFilteredItemModels = new FilteredItemModelFactory();
+
+ int crvid = dialogFilteredItemModels->registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_Curve)), "Curve");
+ connectItemModelEvents(dialogFilteredItemModels->getItemModel(crvid));
+
+ int gvid = dialogFilteredItemModels->registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_GVarRef)), "GVarRef");
+
QStringList headerLabels;
headerLabels << "#";
if (channelNameMaxLen > 0) {
@@ -118,8 +114,6 @@ Channels::Channels(QWidget * parent, ModelData & model, GeneralSettings & genera
headerLabels << tr("Linear Subtrim");
TableLayout *tableLayout = new TableLayout(this, chnCapability, headerLabels);
- s1.report("header");
-
for (int i = 0; i < chnCapability; i++) {
int col = 0;
@@ -146,13 +140,13 @@ Channels::Channels(QWidget * parent, ModelData & model, GeneralSettings & genera
}
// Channel offset
- chnOffset[i] = new LimitsGroup(firmware, tableLayout, i, col++, model.limitData[i].offset, model, -1000, 1000, 0, this);
+ chnOffset[i] = new LimitsGroup(firmware, tableLayout, i, col++, model.limitData[i].offset, model, -1000, 1000, 0, dialogFilteredItemModels->getItemModel(gvid), this);
// Channel min
- chnMin[i] = new LimitsGroup(firmware, tableLayout, i, col++, model.limitData[i].min, model, -model.getChannelsMax() * 10, 0, -1000, this);
+ chnMin[i] = new LimitsGroup(firmware, tableLayout, i, col++, model.limitData[i].min, model, -model.getChannelsMax() * 10, 0, -1000, dialogFilteredItemModels->getItemModel(gvid), this);
// Channel max
- chnMax[i] = new LimitsGroup(firmware, tableLayout, i, col++, model.limitData[i].max, model, 0, model.getChannelsMax() * 10, 1000, this);
+ chnMax[i] = new LimitsGroup(firmware, tableLayout, i, col++, model.limitData[i].max, model, 0, model.getChannelsMax() * 10, 1000, dialogFilteredItemModels->getItemModel(gvid), this);
// Channel inversion
invCB[i] = new QComboBox(this);
@@ -165,6 +159,7 @@ Channels::Channels(QWidget * parent, ModelData & model, GeneralSettings & genera
if (IS_HORUS_OR_TARANIS(firmware->getBoard())) {
curveCB[i] = new QComboBox(this);
curveCB[i]->setProperty("index", i);
+ curveCB[i]->setModel(dialogFilteredItemModels->getItemModel(crvid));
connect(curveCB[i], SIGNAL(currentIndexChanged(int)), this, SLOT(curveEdited()));
tableLayout->addWidget(i, col++, curveCB[i]);
}
@@ -193,15 +188,13 @@ Channels::Channels(QWidget * parent, ModelData & model, GeneralSettings & genera
}
}
update();
- s1.report("add elements");
disableMouseScrolling();
tableLayout->resizeColumnsToContents();
tableLayout->pushRowsUp(chnCapability+1);
- s1.report("end");
}
-Channels::~Channels()
+ChannelsPanel::~ChannelsPanel()
{
// compiler warning if delete[]
for (int i = 0; i < CPN_MAX_CHNOUT; i++) {
@@ -214,9 +207,10 @@ Channels::~Channels()
delete centerSB[i];
delete symlimitsChk[i];
}
+ delete dialogFilteredItemModels;
}
-void Channels::symlimitsEdited()
+void ChannelsPanel::symlimitsEdited()
{
if (!lock) {
QCheckBox *ckb = qobject_cast(sender());
@@ -226,29 +220,31 @@ void Channels::symlimitsEdited()
}
}
-void Channels::nameEdited()
+void ChannelsPanel::nameEdited()
{
if (!lock) {
QLineEdit *le = qobject_cast(sender());
int index = le->property("index").toInt();
- strcpy(model->limitData[index].name, le->text().toLatin1());
- emit modified();
+ if (model->limitData[index].name != le->text()) {
+ strcpy(model->limitData[index].name, le->text().toLatin1());
+ updateItemModels();
+ emit modified();
+ }
}
}
-void Channels::refreshExtendedLimits()
+void ChannelsPanel::refreshExtendedLimits()
{
- int channelMax = model->getChannelsMax();
+ int channelMax = model->getChannelsMax() * 10;
for (int i = 0 ; i < CPN_MAX_CHNOUT; i++) {
- chnOffset[i]->updateMinMax(10 * channelMax);
- chnMin[i]->updateMinMax(10 * channelMax);
- chnMax[i]->updateMinMax(10 * channelMax);
+ chnMin[i]->updateMinMax(channelMax);
+ chnMax[i]->updateMinMax(channelMax);
}
emit modified();
}
-void Channels::invEdited()
+void ChannelsPanel::invEdited()
{
if (!lock) {
QComboBox *cb = qobject_cast(sender());
@@ -258,17 +254,20 @@ void Channels::invEdited()
}
}
-void Channels::curveEdited()
+void ChannelsPanel::curveEdited()
{
if (!lock) {
QComboBox *cb = qobject_cast(sender());
int index = cb->property("index").toInt();
- model->limitData[index].curve = CurveReference(CurveReference::CURVE_REF_CUSTOM, cb->itemData(cb->currentIndex()).toInt());
- emit modified();
+ // ignore unnecessary updates that could be triggered by updates to the data model
+ if (model->limitData[index].curve != CurveReference(CurveReference::CURVE_REF_CUSTOM, cb->itemData(cb->currentIndex()).toInt())) {
+ model->limitData[index].curve = CurveReference(CurveReference::CURVE_REF_CUSTOM, cb->itemData(cb->currentIndex()).toInt());
+ emit modified();
+ }
}
}
-void Channels::ppmcenterEdited()
+void ChannelsPanel::ppmcenterEdited()
{
if (!lock) {
QSpinBox *sb = qobject_cast(sender());
@@ -278,82 +277,79 @@ void Channels::ppmcenterEdited()
}
}
-void Channels::update()
+void ChannelsPanel::update()
{
for (int i = 0; i < chnCapability; i++) {
updateLine(i);
}
}
-void Channels::updateLine(int i)
+void ChannelsPanel::updateLine(int i)
{
lock = true;
+ LimitData &chn = model->limitData[i];
+
if (firmware->getCapability(ChannelsName) > 0) {
- name[i]->setText(model->limitData[i].name);
+ name[i]->setText(chn.name);
}
- chnOffset[i]->setValue(model->limitData[i].offset);
- chnMin[i]->setValue(model->limitData[i].min);
- chnMax[i]->setValue(model->limitData[i].max);
- invCB[i]->setCurrentIndex((model->limitData[i].revert) ? 1 : 0);
+ chnOffset[i]->setValue(chn.offset);
+ chnMin[i]->setValue(chn.min);
+ chnMax[i]->setValue(chn.max);
+ invCB[i]->setCurrentIndex((chn.revert) ? 1 : 0);
if (IS_HORUS_OR_TARANIS(firmware->getBoard())) {
- int numcurves = firmware->getCapability(NumCurves);
- curveCB[i]->clear();
- for (int j = -numcurves; j <= numcurves; j++) {
- curveCB[i]->addItem(CurveReference(CurveReference::CURVE_REF_CUSTOM, j).toString(model, false), j);
- }
- curveCB[i]->setCurrentIndex(model->limitData[i].curve.value + numcurves);
+ curveCB[i]->setCurrentIndex(curveCB[i]->findData(chn.curve.value));
}
if (firmware->getCapability(PPMCenter)) {
- centerSB[i]->setValue(model->limitData[i].ppmCenter + 1500);
+ centerSB[i]->setValue(chn.ppmCenter + 1500);
}
if (firmware->getCapability(SYMLimits)) {
- symlimitsChk[i]->setChecked(model->limitData[i].symetrical);
+ symlimitsChk[i]->setChecked(chn.symetrical);
}
lock = false;
}
-void Channels::cmPaste()
+void ChannelsPanel::cmPaste()
{
QByteArray data;
if (hasClipboardData(&data)) {
- memcpy(&model->limitData[selectedIndex], data.constData(), sizeof(LimitData));
+ model->limitsSet(selectedIndex, data);
updateLine(selectedIndex);
- emit modified();
+ updateItemModels();
}
}
-void Channels::cmDelete()
+void ChannelsPanel::cmDelete()
{
if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Delete Channel. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
return;
- memmove(&model->limitData[selectedIndex], &model->limitData[selectedIndex + 1], (CPN_MAX_CHNOUT - (selectedIndex + 1)) * sizeof(LimitData));
- model->limitData[chnCapability - 1].clear();
- model->updateAllReferences(ModelData::REF_UPD_TYPE_CHANNEL, ModelData::REF_UPD_ACT_SHIFT, selectedIndex, 0, -1);
-
+ model->limitsDelete(selectedIndex);
for (int i = selectedIndex; i < chnCapability; i++) {
updateLine(i);
}
- emit modified();
+ updateItemModels();
}
-void Channels::cmCopy()
+void ChannelsPanel::cmCopy()
{
QByteArray data;
- data.append((char*)&model->limitData[selectedIndex], sizeof(LimitData));
+ model->limitsGet(selectedIndex, data);
QMimeData *mimeData = new QMimeData;
mimeData->setData(MIMETYPE_CHANNEL, data);
QApplication::clipboard()->setMimeData(mimeData,QClipboard::Clipboard);
}
-void Channels::cmCut()
+void ChannelsPanel::cmCut()
{
+ if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Cut Channel. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
+ return;
+
cmCopy();
- cmClear();
+ cmClear(false);
}
-void Channels::onCustomContextMenuRequested(QPoint pos)
+void ChannelsPanel::onCustomContextMenuRequested(QPoint pos)
{
QLabel *label = (QLabel *)sender();
selectedIndex = label->property("index").toInt();
@@ -375,7 +371,7 @@ void Channels::onCustomContextMenuRequested(QPoint pos)
contextMenu.exec(globalPos);
}
-bool Channels::hasClipboardData(QByteArray * data) const
+bool ChannelsPanel::hasClipboardData(QByteArray * data) const
{
const QClipboard * clipboard = QApplication::clipboard();
const QMimeData * mimeData = clipboard->mimeData();
@@ -387,75 +383,88 @@ bool Channels::hasClipboardData(QByteArray * data) const
return false;
}
-bool Channels::insertAllowed() const
+bool ChannelsPanel::insertAllowed() const
{
return ((selectedIndex < chnCapability - 1) && (model->limitData[chnCapability - 1].isEmpty()));
}
-bool Channels::moveDownAllowed() const
+bool ChannelsPanel::moveDownAllowed() const
{
return selectedIndex < chnCapability - 1;
}
-bool Channels::moveUpAllowed() const
+bool ChannelsPanel::moveUpAllowed() const
{
return selectedIndex > 0;
}
-void Channels::cmMoveUp()
+void ChannelsPanel::cmMoveUp()
{
- swapData(selectedIndex, selectedIndex - 1);
-}
-
-void Channels::cmMoveDown()
-{
- swapData(selectedIndex, selectedIndex + 1);
-}
-
-void Channels::cmClear()
-{
- if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear Channel. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
- return;
-
- model->limitData[selectedIndex].clear();
- model->updateAllReferences(ModelData::REF_UPD_TYPE_CHANNEL, ModelData::REF_UPD_ACT_CLEAR, selectedIndex);
+ model->limitsMove(selectedIndex, -1);
+ updateLine(selectedIndex - 1);
updateLine(selectedIndex);
- emit modified();
+ updateItemModels();
}
-void Channels::cmClearAll()
+void ChannelsPanel::cmMoveDown()
+{
+ model->limitsMove(selectedIndex, 1);
+ updateLine(selectedIndex);
+ updateLine(selectedIndex + 1);
+ updateItemModels();
+}
+
+void ChannelsPanel::cmClear(bool prompt)
+{
+ if (prompt) {
+ if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear Channel. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
+ return;
+ }
+
+ model->limitsClear(selectedIndex);
+ updateLine(selectedIndex);
+ updateItemModels();
+}
+
+void ChannelsPanel::cmClearAll()
{
if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear all Channels. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
return;
- for (int i = 0; i < chnCapability; i++) {
- model->limitData[i].clear();
- model->updateAllReferences(ModelData::REF_UPD_TYPE_CHANNEL, ModelData::REF_UPD_ACT_CLEAR, i);
+ model->limitsClearAll();
+ update();
+ updateItemModels();
+}
+
+void ChannelsPanel::cmInsert()
+{
+ model->limitsInsert(selectedIndex);
+ for (int i = selectedIndex; i < chnCapability; i++) {
updateLine(i);
}
- emit modified();
+
+ updateItemModels();
}
-void Channels::cmInsert()
+void ChannelsPanel::connectItemModelEvents(const FilteredItemModel * itemModel)
+{
+ connect(itemModel, &FilteredItemModel::aboutToBeUpdated, this, &ChannelsPanel::onItemModelAboutToBeUpdated);
+ connect(itemModel, &FilteredItemModel::updateComplete, this, &ChannelsPanel::onItemModelUpdateComplete);
+}
+
+void ChannelsPanel::onItemModelAboutToBeUpdated()
+{
+ lock = true;
+}
+
+void ChannelsPanel::onItemModelUpdateComplete()
{
- memmove(&model->limitData[selectedIndex + 1], &model->limitData[selectedIndex], (CPN_MAX_CHNOUT - (selectedIndex + 1)) * sizeof(LimitData));
- model->limitData[selectedIndex].clear();
- model->updateAllReferences(ModelData::REF_UPD_TYPE_CHANNEL, ModelData::REF_UPD_ACT_SHIFT, selectedIndex, 0, 1);
update();
- emit modified();
+ lock = false;
}
-void Channels::swapData(int idx1, int idx2)
+void ChannelsPanel::updateItemModels()
{
- if ((idx1 != idx2) && (!model->limitData[idx1].isEmpty() || !model->limitData[idx2].isEmpty())) {
- LimitData chntmp = model->limitData[idx2];
- LimitData *chn1 = &model->limitData[idx1];
- LimitData *chn2 = &model->limitData[idx2];
- memcpy(chn2, chn1, sizeof(LimitData));
- memcpy(chn1, &chntmp, sizeof(LimitData));
- model->updateAllReferences(ModelData::REF_UPD_TYPE_CHANNEL, ModelData::REF_UPD_ACT_SWAP, idx1, idx2);
- updateLine(idx1);
- updateLine(idx2);
- emit modified();
- }
+ sharedItemModels->update(AbstractItemModel::IMUE_Channels);
+ emit modified();
}
diff --git a/companion/src/modeledit/channels.h b/companion/src/modeledit/channels.h
index caa0fca38..5d7600718 100644
--- a/companion/src/modeledit/channels.h
+++ b/companion/src/modeledit/channels.h
@@ -18,14 +18,16 @@
* GNU General Public License for more details.
*/
-#ifndef _CHANNELS_H_
-#define _CHANNELS_H_
+#pragma once
#include "helpers.h"
#include "modeledit.h"
#include
+class CompoundItemModelFactory;
+class FilteredItemModelFactory;
+
constexpr char MIMETYPE_CHANNEL[] = "application/x-companion-channel";
class GVarGroup;
@@ -35,7 +37,8 @@ class LimitsGroup
Q_DECLARE_TR_FUNCTIONS(LimitsGroup)
public:
- LimitsGroup(Firmware * firmware, TableLayout * tableLayout, int row, int col, int & value, const ModelData & model, int min, int max, int deflt, ModelPanel * panel=NULL);
+ LimitsGroup(Firmware * firmware, TableLayout * tableLayout, int row, int col, int & value, const ModelData & model,
+ int min, int max, int deflt, FilteredItemModel * gvarModel, ModelPanel * panel = nullptr);
~LimitsGroup();
void setValue(int val);
@@ -47,15 +50,17 @@ class LimitsGroup
GVarGroup *gvarGroup;
int &value;
double displayStep;
+ QCheckBox *gv;
};
-class Channels : public ModelPanel
+class ChannelsPanel : public ModelPanel
{
Q_OBJECT
public:
- Channels(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware);
- ~Channels();
+ ChannelsPanel(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware,
+ CompoundItemModelFactory * sharedItemModels);
+ virtual ~ChannelsPanel();
public slots:
void refreshExtendedLimits();
@@ -75,16 +80,17 @@ class Channels : public ModelPanel
void cmMoveUp();
void cmMoveDown();
void cmInsert();
- void cmClear();
+ void cmClear(bool prompt = true);
void cmClearAll();
void onCustomContextMenuRequested(QPoint pos);
+ void onItemModelAboutToBeUpdated();
+ void onItemModelUpdateComplete();
private:
bool hasClipboardData(QByteArray * data = nullptr) const;
bool insertAllowed() const;
bool moveDownAllowed() const;
bool moveUpAllowed() const;
- void swapData(int idx1, int idx2);
QLineEdit *name[CPN_MAX_CHNOUT];
LimitsGroup *chnOffset[CPN_MAX_CHNOUT];
LimitsGroup *chnMin[CPN_MAX_CHNOUT];
@@ -95,6 +101,8 @@ class Channels : public ModelPanel
QCheckBox *symlimitsChk[CPN_MAX_CHNOUT];
int selectedIndex;
int chnCapability;
+ CompoundItemModelFactory *sharedItemModels;
+ void updateItemModels();
+ void connectItemModelEvents(const FilteredItemModel * itemModel);
+ FilteredItemModelFactory *dialogFilteredItemModels;
};
-
-#endif // _CHANNELS_H_
diff --git a/companion/src/modeledit/curves.cpp b/companion/src/modeledit/curves.cpp
index 5759e60e6..7f8b80219 100644
--- a/companion/src/modeledit/curves.cpp
+++ b/companion/src/modeledit/curves.cpp
@@ -23,6 +23,7 @@
#include "node.h"
#include "edge.h"
#include "helpers.h"
+#include "filtereditemmodels.h"
#define GFX_MARGIN 16
@@ -108,10 +109,12 @@ float curveSymmetricalX(float x, float coeff, float yMin, float yMid, float yMax
return y;
}
-Curves::Curves(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware):
+CurvesPanel::CurvesPanel(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware,
+ CompoundItemModelFactory * sharedItemModels):
ModelPanel(parent, model, generalSettings, firmware),
ui(new Ui::Curves),
- currentCurve(0)
+ currentCurve(0),
+ sharedItemModels(sharedItemModels)
{
ui->setupUi(this);
@@ -230,12 +233,12 @@ Curves::Curves(QWidget * parent, ModelData & model, GeneralSettings & generalSet
lock = false;
}
-Curves::~Curves()
+CurvesPanel::~CurvesPanel()
{
delete ui;
}
-void Curves::editCurve()
+void CurvesPanel::editCurve()
{
QPushButton *button = (QPushButton *)sender();
int index = button->property("index").toInt();
@@ -243,7 +246,7 @@ void Curves::editCurve()
update();
}
-void Curves::plotCurve(bool checked)
+void CurvesPanel::plotCurve(bool checked)
{
QCheckBox *chk = (QCheckBox *)sender();
int index = chk->property("index").toInt();
@@ -251,7 +254,7 @@ void Curves::plotCurve(bool checked)
updateCurve();
}
-void Curves::update()
+void CurvesPanel::update()
{
lock = true;
@@ -266,12 +269,12 @@ void Curves::update()
lock = false;
}
-void Curves::setCurrentCurve(int index)
+void CurvesPanel::setCurrentCurve(int index)
{
currentCurve = index;
}
-void Curves::updateCurveType()
+void CurvesPanel::updateCurveType()
{
lock = true;
@@ -297,7 +300,7 @@ void Curves::updateCurveType()
lock = false;
}
-void Curves::updateCurve()
+void CurvesPanel::updateCurve()
{
lock = true;
@@ -371,7 +374,7 @@ void Curves::updateCurve()
lock = false;
}
-void Curves::updateCurvePoints()
+void CurvesPanel::updateCurvePoints()
{
lock = true;
@@ -405,18 +408,19 @@ void Curves::updateCurvePoints()
lock = false;
}
-void Curves::onPointEdited()
+void CurvesPanel::onPointEdited()
{
if (!lock) {
int index = sender()->property("index").toInt();
model->curves[currentCurve].points[index].x = spnx[index]->value();
model->curves[currentCurve].points[index].y = spny[index]->value();
updateCurve();
+ updateCurvePoints();
emit modified();
}
}
-void Curves::onNodeMoved(int x, int y)
+void CurvesPanel::onNodeMoved(int x, int y)
{
if (!lock) {
lock = true;
@@ -434,20 +438,20 @@ void Curves::onNodeMoved(int x, int y)
}
}
-void Curves::onNodeFocus()
+void CurvesPanel::onNodeFocus()
{
int index = sender()->property("index").toInt();
spny[index]->setFocus();
}
-void Curves::onNodeUnfocus()
+void CurvesPanel::onNodeUnfocus()
{
int index = sender()->property("index").toInt();
spny[index]->clearFocus();
updateCurve();
}
-bool Curves::allowCurveType(int points, CurveData::CurveType type)
+bool CurvesPanel::allowCurveType(int points, CurveData::CurveType type)
{
int totalpoints = 0;
for (int i = 0; i < maxCurves; i++) {
@@ -465,7 +469,7 @@ bool Curves::allowCurveType(int points, CurveData::CurveType type)
}
}
-void Curves::on_curvePoints_currentIndexChanged(int index)
+void CurvesPanel::on_curvePoints_currentIndexChanged(int index)
{
if (!lock) {
int numpoints = ((QComboBox *)sender())->itemData(index).toInt();
@@ -488,7 +492,7 @@ void Curves::on_curvePoints_currentIndexChanged(int index)
}
}
-void Curves::on_curveCustom_currentIndexChanged(int index)
+void CurvesPanel::on_curveCustom_currentIndexChanged(int index)
{
if (!lock) {
CurveData::CurveType type = (CurveData::CurveType)index;
@@ -512,20 +516,23 @@ void Curves::on_curveCustom_currentIndexChanged(int index)
}
}
-void Curves::on_curveSmooth_currentIndexChanged(int index)
+void CurvesPanel::on_curveSmooth_currentIndexChanged(int index)
{
model->curves[currentCurve].smooth = index;
update();
}
-void Curves::on_curveName_editingFinished()
+void CurvesPanel::on_curveName_editingFinished()
{
- memset(model->curves[currentCurve].name, 0, sizeof(model->curves[currentCurve].name));
- strcpy(model->curves[currentCurve].name, ui->curveName->text().toLatin1());
- emit modified();
+ if (ui->curveName->text() != model->curves[currentCurve].name) {
+ memset(model->curves[currentCurve].name, 0, sizeof(model->curves[currentCurve].name));
+ strcpy(model->curves[currentCurve].name, ui->curveName->text().toLatin1());
+ updateItemModels();
+ emit modified();
+ }
}
-void Curves::resizeEvent(QResizeEvent *event)
+void CurvesPanel::resizeEvent(QResizeEvent *event)
{
QRect qr = ui->curvePreview->contentsRect();
ui->curvePreview->scene()->setSceneRect(GFX_MARGIN, GFX_MARGIN, qr.width() - GFX_MARGIN * 2, qr.height() - GFX_MARGIN * 2);
@@ -533,7 +540,7 @@ void Curves::resizeEvent(QResizeEvent *event)
ModelPanel::resizeEvent(event);
}
-void Curves::on_curveType_currentIndexChanged(int index)
+void CurvesPanel::on_curveType_currentIndexChanged(int index)
{
unsigned int flags = templates[index].flags;
ui->curveCoeffLabel->setVisible(flags & CURVE_COEFF_ENABLE);
@@ -547,7 +554,7 @@ void Curves::on_curveType_currentIndexChanged(int index)
ui->yMin->setValue(-100);
}
-void Curves::addTemplate(QString name, unsigned int flags, curveFunction function)
+void CurvesPanel::addTemplate(QString name, unsigned int flags, curveFunction function)
{
CurveCreatorTemplate tmpl;
tmpl.name = name;
@@ -557,7 +564,7 @@ void Curves::addTemplate(QString name, unsigned int flags, curveFunction functio
ui->curveType->addItem(name);
}
-void Curves::on_curveApply_clicked()
+void CurvesPanel::on_curveApply_clicked()
{
int index = ui->curveType->currentIndex();
int numpoints = model->curves[currentCurve].count;
@@ -594,14 +601,14 @@ void Curves::on_curveApply_clicked()
emit modified();
}
-void Curves::onPointSizeEdited()
+void CurvesPanel::onPointSizeEdited()
{
if (!lock) {
update();
}
}
-void Curves::onNodeDelete()
+void CurvesPanel::onNodeDelete()
{
int index = sender()->property("index").toInt();
int numpoints = model->curves[currentCurve].count;
@@ -619,7 +626,7 @@ void Curves::onNodeDelete()
}
}
-void Curves::onSceneNewPoint(int x, int y)
+void CurvesPanel::onSceneNewPoint(int x, int y)
{
if ((model->curves[currentCurve].type == CurveData::CURVE_TYPE_CUSTOM) && (model->curves[currentCurve].count < CPN_MAX_POINTS)) {
int newidx = 0;
@@ -650,7 +657,7 @@ void Curves::onSceneNewPoint(int x, int y)
}
}
-void Curves::onCustomContextMenuRequested(QPoint pos)
+void CurvesPanel::onCustomContextMenuRequested(QPoint pos)
{
QPushButton *button = (QPushButton *)sender();
selectedIndex = button->property("index").toInt();
@@ -672,7 +679,7 @@ void Curves::onCustomContextMenuRequested(QPoint pos)
contextMenu.exec(globalPos);
}
-bool Curves::hasClipboardData(QByteArray * data) const
+bool CurvesPanel::hasClipboardData(QByteArray * data) const
{
const QClipboard * clipboard = QApplication::clipboard();
const QMimeData * mimeData = clipboard->mimeData();
@@ -684,33 +691,36 @@ bool Curves::hasClipboardData(QByteArray * data) const
return false;
}
-bool Curves::insertAllowed() const
+bool CurvesPanel::insertAllowed() const
{
return ((selectedIndex < maxCurves - 1) && (model->curves[maxCurves - 1].isEmpty()));
}
-bool Curves::moveDownAllowed() const
+bool CurvesPanel::moveDownAllowed() const
{
return selectedIndex < maxCurves - 1;
}
-bool Curves::moveUpAllowed() const
+bool CurvesPanel::moveUpAllowed() const
{
return selectedIndex > 0;
}
-void Curves::cmClear()
+void CurvesPanel::cmClear(bool prompt)
{
- if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear Curve. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
- return;
+ if (prompt) {
+ if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear Curve. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
+ return;
+ }
model->curves[selectedIndex].clear();
model->updateAllReferences(ModelData::REF_UPD_TYPE_CURVE, ModelData::REF_UPD_ACT_CLEAR, selectedIndex);
update();
+ updateItemModels();
emit modified();
}
-void Curves::cmClearAll()
+void CurvesPanel::cmClearAll()
{
if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear all Curves. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
return;
@@ -720,10 +730,11 @@ void Curves::cmClearAll()
model->updateAllReferences(ModelData::REF_UPD_TYPE_CURVE, ModelData::REF_UPD_ACT_CLEAR, i);
}
update();
+ updateItemModels();
emit modified();
}
-void Curves::cmCopy()
+void CurvesPanel::cmCopy()
{
QByteArray data;
data.append((char*)&model->curves[selectedIndex], sizeof(CurveData));
@@ -732,13 +743,15 @@ void Curves::cmCopy()
QApplication::clipboard()->setMimeData(mimeData,QClipboard::Clipboard);
}
-void Curves::cmCut()
+void CurvesPanel::cmCut()
{
+ if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Cut Curve. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
+ return;
cmCopy();
- cmClear();
+ cmClear(false);
}
-void Curves::cmDelete()
+void CurvesPanel::cmDelete()
{
if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Delete Curve. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
return;
@@ -747,40 +760,43 @@ void Curves::cmDelete()
model->curves[maxCurves - 1].clear();
model->updateAllReferences(ModelData::REF_UPD_TYPE_CURVE, ModelData::REF_UPD_ACT_SHIFT, selectedIndex, 0, -1);
update();
+ updateItemModels();
emit modified();
}
-void Curves::cmInsert()
+void CurvesPanel::cmInsert()
{
memmove(&model->curves[selectedIndex + 1], &model->curves[selectedIndex], (CPN_MAX_CURVES - (selectedIndex + 1)) * sizeof(CurveData));
model->curves[selectedIndex].clear();
model->updateAllReferences(ModelData::REF_UPD_TYPE_CURVE, ModelData::REF_UPD_ACT_SHIFT, selectedIndex, 0, 1);
update();
+ updateItemModels();
emit modified();
}
-void Curves::cmMoveDown()
+void CurvesPanel::cmMoveDown()
{
swapData(selectedIndex, selectedIndex + 1);
}
-void Curves::cmMoveUp()
+void CurvesPanel::cmMoveUp()
{
swapData(selectedIndex, selectedIndex - 1);
}
-void Curves::cmPaste()
+void CurvesPanel::cmPaste()
{
QByteArray data;
if (hasClipboardData(&data)) {
CurveData *cd = &model->curves[selectedIndex];
memcpy(cd, data.constData(), sizeof(CurveData));
update();
+ updateItemModels();
emit modified();
}
}
-void Curves::swapData(int idx1, int idx2)
+void CurvesPanel::swapData(int idx1, int idx2)
{
if ((idx1 != idx2) && (!model->curves[idx1].isEmpty() || !model->curves[idx2].isEmpty())) {
CurveData cdtmp = model->curves[idx2];
@@ -790,10 +806,16 @@ void Curves::swapData(int idx1, int idx2)
memcpy(cd1, &cdtmp, sizeof(CurveData));
model->updateAllReferences(ModelData::REF_UPD_TYPE_CURVE, ModelData::REF_UPD_ACT_SWAP, idx1, idx2);
update();
+ updateItemModels();
emit modified();
}
}
+void CurvesPanel::updateItemModels()
+{
+ sharedItemModels->update(AbstractItemModel::IMUE_Curves);
+}
+
CustomScene::CustomScene(QGraphicsView * view) :
QGraphicsScene(view)
{
diff --git a/companion/src/modeledit/curves.h b/companion/src/modeledit/curves.h
index d9a5364a6..c66f79cb7 100644
--- a/companion/src/modeledit/curves.h
+++ b/companion/src/modeledit/curves.h
@@ -26,6 +26,8 @@
#include
#include
+class CompoundItemModelFactory;
+
constexpr char MIMETYPE_CURVE[] = "application/x-companion-curve";
namespace Ui {
@@ -54,13 +56,13 @@ class CustomScene : public QGraphicsScene
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent * event) override;
};
-class Curves : public ModelPanel
+class CurvesPanel : public ModelPanel
{
Q_OBJECT
public:
- Curves(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware);
- virtual ~Curves();
+ CurvesPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CompoundItemModelFactory * sharedItemModels);
+ virtual ~CurvesPanel();
virtual void update();
@@ -81,7 +83,7 @@ class Curves : public ModelPanel
void onPointSizeEdited();
void onNodeDelete();
void onCustomContextMenuRequested(QPoint pos);
- void cmClear();
+ void cmClear(bool prompt = true);
void cmClearAll();
void cmCopy();
void cmCut();
@@ -119,6 +121,8 @@ class Curves : public ModelPanel
bool moveDownAllowed() const;
bool moveUpAllowed() const;
void swapData(int idx1, int idx2);
+ CompoundItemModelFactory * sharedItemModels;
+ void updateItemModels();
};
#endif // _CURVES_H_
diff --git a/companion/src/modeledit/customfunctions.cpp b/companion/src/modeledit/customfunctions.cpp
index 6b8456eb2..c773e90e5 100644
--- a/companion/src/modeledit/customfunctions.cpp
+++ b/companion/src/modeledit/customfunctions.cpp
@@ -19,71 +19,61 @@
*/
#include "customfunctions.h"
-#include "rawitemfilteredmodel.h"
#include "helpers.h"
#include "appdata.h"
#include
-RepeatComboBox::RepeatComboBox(QWidget *parent, int & repeatParam):
- QComboBox(parent),
- repeatParam(repeatParam)
-{
- unsigned int step = 1;
- int value = repeatParam/step;
-
- setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed);
-
- if (step == 1) {
- addItem(tr("Played once, not during startup"), -1);
- value++;
- }
-
- addItem(tr("No repeat"), 0);
-
- for (unsigned int i=step; i<=60; i+=step) {
- addItem(tr("%1s").arg(i), i);
- }
-
- setCurrentIndex(value);
-
- connect(this, SIGNAL(currentIndexChanged(int)), this, SLOT(onIndexChanged(int)));
-}
-
-void RepeatComboBox::onIndexChanged(int index)
-{
- repeatParam = itemData(index).toInt();
- emit modified();
-}
-
-void RepeatComboBox::update()
-{
- unsigned int step = 1;
- int value = repeatParam/step;
- if (step == 1) {
- value++;
- }
- setCurrentIndex(value);
-}
-
-CustomFunctionsPanel::CustomFunctionsPanel(QWidget * parent, ModelData * model, GeneralSettings & generalSettings, Firmware * firmware):
+CustomFunctionsPanel::CustomFunctionsPanel(QWidget * parent, ModelData * model, GeneralSettings & generalSettings, Firmware * firmware,
+ CompoundItemModelFactory * sharedItemModels):
GenericPanel(parent, model, generalSettings, firmware),
functions(model ? model->customFn : generalSettings.customFn),
mediaPlayerCurrent(-1),
- mediaPlayer(nullptr)
+ mediaPlayer(nullptr),
+ modelsUpdateCnt(0)
{
- Stopwatch s1("CustomFunctionsPanel - populate");
lock = true;
fswCapability = model ? firmware->getCapability(CustomFunctions) : firmware->getCapability(GlobalFunctions);
- rawSwitchItemModel = new RawSwitchFilterItemModel(&generalSettings, model, model ? RawSwitch::SpecialFunctionsContext : RawSwitch::GlobalFunctionsContext, this);
- rawSrcAllItemModel = new RawSourceFilterItemModel(&generalSettings, model, this);
- rawSrcInputsItemModel = new RawSourceFilterItemModel(rawSrcAllItemModel->sourceModel(), RawSource::InputSourceGroups, this);
- rawSrcGVarsItemModel = new RawSourceFilterItemModel(rawSrcAllItemModel->sourceModel(), RawSource::GVarsGroup, this);
+ tabModelFactory = new CompoundItemModelFactory(&generalSettings, model);
+ playSoundId = tabModelFactory->registerItemModel(CustomFunctionData::playSoundItemModel());
+ harpicId = tabModelFactory->registerItemModel(CustomFunctionData::harpicItemModel());
+ repeatId = tabModelFactory->registerItemModel(CustomFunctionData::repeatItemModel());
+ gvarAdjustModeId = tabModelFactory->registerItemModel(CustomFunctionData::gvarAdjustModeItemModel());
+
+ tabFilterFactory = new FilteredItemModelFactory();
+
+ funcActionsId = tabFilterFactory->registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_CustomFuncAction),
+ model ? CustomFunctionData::AllFunctionContexts : CustomFunctionData::GlobalFunctionsContext),
+ "Function Actions");
+ connectItemModelEvents(tabFilterFactory->getItemModel(funcActionsId));
+
+ funcResetParamId = tabFilterFactory->registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_CustomFuncResetParam)),
+ "Reset Params");
+ connectItemModelEvents(tabFilterFactory->getItemModel(funcResetParamId));
+
+ rawSwitchId = tabFilterFactory->registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_RawSwitch),
+ model ? RawSwitch::SpecialFunctionsContext : RawSwitch::GlobalFunctionsContext),
+ "RawSwitch");
+ connectItemModelEvents(tabFilterFactory->getItemModel(rawSwitchId));
+
+ rawSourceAllId = tabFilterFactory->registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_RawSource)),
+ "RawSource All");
+ connectItemModelEvents(tabFilterFactory->getItemModel(rawSourceAllId));
+
+ rawSourceInputsId = tabFilterFactory->registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_RawSource),
+ RawSource::InputSourceGroups),
+ "RawSource Inputs");
+ connectItemModelEvents(tabFilterFactory->getItemModel(rawSourceInputsId));
+
+ rawSourceGVarsId = tabFilterFactory->registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_RawSource),
+ RawSource::GVarsGroup),
+ "RawSource GVars");
+ connectItemModelEvents(tabFilterFactory->getItemModel(rawSourceGVarsId));
if (!firmware->getCapability(VoicesAsNumbers)) {
tracksSet = getFilesSet(getSoundsPath(generalSettings), QStringList() << "*.wav" << "*.WAV", firmware->getCapability(VoicesMaxLength));
- for (int i=0; igetBoard())) {
scriptsSet = getFilesSet(g.profile[g.id()].sdPath() + "/SCRIPTS/FUNCTIONS", QStringList() << "*.lua", firmware->getCapability(VoicesMaxLength));
- for (int i=0; isetContextMenuPolicy(Qt::CustomContextMenu);
@@ -123,38 +110,32 @@ CustomFunctionsPanel::CustomFunctionsPanel(QWidget * parent, ModelData * model,
label->setMouseTracking(true);
label->setProperty("index", i);
if (model)
- label->setText(tr("SF%1").arg(i+1));
+ label->setText(tr("SF%1").arg(i + 1));
else
- label->setText(tr("GF%1").arg(i+1));
+ label->setText(tr("GF%1").arg(i + 1));
label->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
connect(label, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(onCustomContextMenuRequested(QPoint)));
tableLayout->addWidget(i, 0, label);
- // s1.report("label");
// The switch
fswtchSwtch[i] = new QComboBox(this);
- fswtchSwtch[i]->setModel(rawSwitchItemModel);
- fswtchSwtch[i]->setCurrentIndex(fswtchSwtch[i]->findData(functions[i].swtch.toValue()));
fswtchSwtch[i]->setProperty("index", i);
+ fswtchSwtch[i]->setModel(tabFilterFactory->getItemModel(rawSwitchId));
+ fswtchSwtch[i]->setCurrentIndex(fswtchSwtch[i]->findData(functions[i].swtch.toValue()));
fswtchSwtch[i]->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Minimum);
+ fswtchSwtch[i]->setSizeAdjustPolicy(QComboBox::AdjustToContents);
fswtchSwtch[i]->setMaxVisibleItems(10);
connect(fswtchSwtch[i], SIGNAL(currentIndexChanged(int)), this, SLOT(customFunctionEdited()));
tableLayout->addWidget(i, 1, fswtchSwtch[i]);
- // s1.report("switch");
// The function
fswtchFunc[i] = new QComboBox(this);
- if (!i) {
- populateFuncCB(fswtchFunc[i], functions[i].func);
- }
- else {
- fswtchFunc[i]->setModel(fswtchFunc[0]->model());
- fswtchFunc[i]->setCurrentIndex(fswtchFunc[i]->findData(functions[i].func));
- }
fswtchFunc[i]->setProperty("index", i);
+ fswtchFunc[i]->setModel(tabFilterFactory->getItemModel(funcActionsId));
+ fswtchFunc[i]->setCurrentIndex(fswtchFunc[i]->findData(functions[i].func));
+ fswtchFunc[i]->setSizeAdjustPolicy(QComboBox::AdjustToContents);
connect(fswtchFunc[i], SIGNAL(currentIndexChanged(int)), this, SLOT(functionEdited()));
tableLayout->addWidget(i, 2, fswtchFunc[i]);
- // s1.report("func");
// The parameters
QHBoxLayout * paramLayout = new QHBoxLayout();
@@ -162,15 +143,15 @@ CustomFunctionsPanel::CustomFunctionsPanel(QWidget * parent, ModelData * model,
fswtchGVmode[i] = new QComboBox(this);
fswtchGVmode[i]->setProperty("index", i);
- populateGVmodeCB(fswtchGVmode[i], functions[i].adjustMode);
+ fswtchGVmode[i]->setModel(tabModelFactory->getItemModel(gvarAdjustModeId));
fswtchGVmode[i]->setSizeAdjustPolicy(QComboBox::AdjustToContents);
connect(fswtchGVmode[i], SIGNAL(currentIndexChanged(int)), this, SLOT(customFunctionEdited()));
paramLayout->addWidget(fswtchGVmode[i]);
fswtchParamGV[i] = new QCheckBox(this);
fswtchParamGV[i]->setProperty("index", i);
- fswtchParamGV[i]->setText("GV");
- fswtchParamGV[i]->setSizePolicy(QSizePolicy::Minimum,QSizePolicy::Minimum);
+ fswtchParamGV[i]->setText(tr("GV"));
+ fswtchParamGV[i]->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
connect(fswtchParamGV[i], SIGNAL(stateChanged(int)), this, SLOT(customFunctionEdited()));
paramLayout->addWidget(fswtchParamGV[i]);
@@ -198,19 +179,9 @@ CustomFunctionsPanel::CustomFunctionsPanel(QWidget * parent, ModelData * model,
fswtchParamArmT[i]->setEditable(true);
fswtchParamArmT[i]->setSizeAdjustPolicy(QComboBox::AdjustToContents);
paramLayout->addWidget(fswtchParamArmT[i]);
-
connect(fswtchParamArmT[i], SIGNAL(currentIndexChanged(int)), this, SLOT(customFunctionEdited()));
connect(fswtchParamArmT[i], SIGNAL(editTextChanged ( const QString)), this, SLOT(customFunctionEdited()));
- fswtchBLcolor[i] = new QSlider(this);
- fswtchBLcolor[i]->setProperty("index", i);
- fswtchBLcolor[i]->setMinimum(0);
- fswtchBLcolor[i]->setMaximum(100);
- fswtchBLcolor[i]->setSingleStep(1);
- fswtchBLcolor[i]->setOrientation(Qt::Horizontal);
- paramLayout->addWidget(fswtchBLcolor[i]);
- connect(fswtchBLcolor[i], SIGNAL(sliderReleased()), this, SLOT(customFunctionEdited()));
-
playBT[i] = new QToolButton(this);
playBT[i]->setProperty("index", i);
playBT[i]->setIcon(playIcon);
@@ -220,47 +191,37 @@ CustomFunctionsPanel::CustomFunctionsPanel(QWidget * parent, ModelData * model,
QHBoxLayout * repeatLayout = new QHBoxLayout();
tableLayout->addLayout(i, 4, repeatLayout);
- fswtchRepeat[i] = new RepeatComboBox(this, functions[i].repeatParam);
- repeatLayout->addWidget(fswtchRepeat[i], i+1);
- connect(fswtchRepeat[i], SIGNAL(modified()), this, SLOT(onChildModified()));
+ fswtchRepeat[i] = new QComboBox(this);
+ fswtchRepeat[i]->setProperty("index", i);
+ fswtchRepeat[i]->setModel(tabModelFactory->getItemModel(repeatId));
+ fswtchRepeat[i]->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed);
+ fswtchRepeat[i]->setSizeAdjustPolicy(QComboBox::AdjustToContents);
+ repeatLayout->addWidget(fswtchRepeat[i], i + 1);
+ connect(fswtchRepeat[i], SIGNAL(currentIndexChanged(int)), this, SLOT(customFunctionEdited()));
fswtchEnable[i] = new QCheckBox(this);
fswtchEnable[i]->setProperty("index", i);
fswtchEnable[i]->setText(tr("ON"));
fswtchEnable[i]->setFixedWidth(200);
- repeatLayout->addWidget(fswtchEnable[i], i+1);
+ repeatLayout->addWidget(fswtchEnable[i], i + 1);
connect(fswtchEnable[i], SIGNAL(stateChanged(int)), this, SLOT(customFunctionEdited()));
}
- s1.report("add items");
-
disableMouseScrolling();
- s1.report("disableMouseScrolling");
-
- lock = false;
+ tableLayout->resizeColumnsToContents();
+ tableLayout->setColumnWidth(3, 300);
+ tableLayout->pushRowsUp(fswCapability + 1);
update();
- s1.report("update");
- tableLayout->resizeColumnsToContents();
- s1.report("resizeColumnsToContents");
- tableLayout->setColumnWidth(3, 300);
- tableLayout->pushRowsUp(fswCapability+1);
- s1.report("end");
+ lock = false;
}
CustomFunctionsPanel::~CustomFunctionsPanel()
{
if (mediaPlayer)
stopSound(mediaPlayerCurrent);
-}
-
-void CustomFunctionsPanel::updateDataModels()
-{
- const bool oldLock = lock;
- lock = true;
- rawSwitchItemModel->update();
- rawSrcAllItemModel->update();
- lock = oldLock;
+ delete tabModelFactory;
+ delete tabFilterFactory;
}
void CustomFunctionsPanel::onMediaPlayerStateChanged(QMediaPlayer::State state)
@@ -340,9 +301,9 @@ void CustomFunctionsPanel::toggleSound(bool play)
#define CUSTOM_FUNCTION_ENABLE (1<<6)
#define CUSTOM_FUNCTION_REPEAT (1<<7)
#define CUSTOM_FUNCTION_PLAY (1<<8)
-#define CUSTOM_FUNCTION_BL_COLOR (1<<9)
#define CUSTOM_FUNCTION_SHOW_FUNC (1<<10)
+
void CustomFunctionsPanel::customFunctionEdited()
{
if (!lock) {
@@ -369,162 +330,152 @@ void CustomFunctionsPanel::functionEdited()
}
}
-void CustomFunctionsPanel::onChildModified()
-{
- emit modified();
-}
-
void CustomFunctionsPanel::refreshCustomFunction(int i, bool modified)
{
- CustomFunctionData & cfn = functions[i];
- AssignFunc func = (AssignFunc)fswtchFunc[i]->currentData().toInt();
+ CustomFunctionData & cfn = functions[i];
+ AssignFunc func = (AssignFunc)fswtchFunc[i]->currentData().toInt();
- unsigned int widgetsMask = 0;
- if (modified) {
- cfn.swtch = RawSwitch(fswtchSwtch[i]->currentData().toInt());
- cfn.func = func;
- cfn.enabled = fswtchEnable[i]->isChecked();
- }
+ unsigned int widgetsMask = 0;
+ if (modified) {
+ cfn.swtch = RawSwitch(fswtchSwtch[i]->currentData().toInt());
+ cfn.func = func;
+ cfn.enabled = fswtchEnable[i]->isChecked();
+ }
+ else {
+ fswtchSwtch[i]->setCurrentIndex(fswtchSwtch[i]->findData(cfn.swtch.toValue()));
+ fswtchFunc[i]->setCurrentIndex(fswtchFunc[i]->findData(cfn.func));
+ }
- if (!cfn.isEmpty()) {
- widgetsMask |= CUSTOM_FUNCTION_SHOW_FUNC;
+ if (!cfn.isEmpty()) {
+ widgetsMask |= CUSTOM_FUNCTION_SHOW_FUNC;
- if (func >= FuncOverrideCH1 && func <= FuncOverrideCH32) {
- if (model) {
- int channelsMax = model->getChannelsMax(true);
- fswtchParam[i]->setDecimals(0);
- fswtchParam[i]->setSingleStep(1);
- fswtchParam[i]->setMinimum(-channelsMax);
- fswtchParam[i]->setMaximum(channelsMax);
- if (modified) {
- cfn.param = fswtchParam[i]->value();
- }
- fswtchParam[i]->setValue(cfn.param);
- widgetsMask |= CUSTOM_FUNCTION_NUMERIC_PARAM | CUSTOM_FUNCTION_ENABLE;
+ if (func >= FuncOverrideCH1 && func <= FuncOverrideCH32) {
+ if (model) {
+ int channelsMax = model->getChannelsMax(true);
+ fswtchParam[i]->setDecimals(0);
+ fswtchParam[i]->setSingleStep(1);
+ fswtchParam[i]->setMinimum(-channelsMax);
+ fswtchParam[i]->setMaximum(channelsMax);
+ if (modified) {
+ cfn.param = fswtchParam[i]->value();
}
+ fswtchParam[i]->setValue(cfn.param);
+ widgetsMask |= CUSTOM_FUNCTION_NUMERIC_PARAM | CUSTOM_FUNCTION_ENABLE;
}
- else if (func == FuncLogs) {
- fswtchParam[i]->setDecimals(1);
- fswtchParam[i]->setMinimum(0);
- fswtchParam[i]->setMaximum(25.5);
- fswtchParam[i]->setSingleStep(0.1);
+ }
+ else if (func == FuncLogs) {
+ fswtchParam[i]->setDecimals(1);
+ fswtchParam[i]->setMinimum(0);
+ fswtchParam[i]->setMaximum(25.5);
+ fswtchParam[i]->setSingleStep(0.1);
+ if (modified)
+ cfn.param = fswtchParam[i]->value() * 10.0;
+ fswtchParam[i]->setValue(cfn.param / 10.0);
+ widgetsMask |= CUSTOM_FUNCTION_NUMERIC_PARAM;
+ }
+ else if (func >= FuncAdjustGV1 && func <= FuncAdjustGVLast) {
+ int gvidx = func - FuncAdjustGV1;
+ if (modified)
+ cfn.adjustMode = fswtchGVmode[i]->currentData().toInt();
+ fswtchGVmode[i]->setCurrentIndex(fswtchGVmode[i]->findData(cfn.adjustMode));
+ widgetsMask |= CUSTOM_FUNCTION_GV_MODE | CUSTOM_FUNCTION_ENABLE;
+ if (cfn.adjustMode == FUNC_ADJUST_GVAR_CONSTANT || cfn.adjustMode == FUNC_ADJUST_GVAR_INCDEC) {
if (modified)
- cfn.param = fswtchParam[i]->value()*10.0;
- fswtchParam[i]->setValue(cfn.param/10.0);
- widgetsMask |= CUSTOM_FUNCTION_NUMERIC_PARAM;
- }
- else if (func >= FuncAdjustGV1 && func <= FuncAdjustGVLast) {
- int gvidx = func - FuncAdjustGV1;
- if (modified)
- cfn.adjustMode = fswtchGVmode[i]->currentIndex();
- fswtchGVmode[i]->setCurrentIndex(cfn.adjustMode);
- widgetsMask |= CUSTOM_FUNCTION_GV_MODE | CUSTOM_FUNCTION_ENABLE;
- if (cfn.adjustMode == FUNC_ADJUST_GVAR_CONSTANT || cfn.adjustMode == FUNC_ADJUST_GVAR_INCDEC) {
- if (modified)
- cfn.param = fswtchParam[i]->value() * model->gvarData[gvidx].multiplierSet();
- fswtchParam[i]->setDecimals(model->gvarData[gvidx].prec);
- fswtchParam[i]->setSingleStep(model->gvarData[gvidx].multiplierGet());
- fswtchParam[i]->setSuffix(model->gvarData[gvidx].unitToString());
- if (cfn.adjustMode==FUNC_ADJUST_GVAR_INCDEC) {
- double rng = abs(model->gvarData[gvidx].getMax() - model->gvarData[gvidx].getMin());
- rng *= model->gvarData[gvidx].multiplierGet();
- fswtchParam[i]->setMinimum(-rng);
- fswtchParam[i]->setMaximum(rng);
- }
- else {
- fswtchParam[i]->setMinimum(model->gvarData[gvidx].getMinPrec());
- fswtchParam[i]->setMaximum(model->gvarData[gvidx].getMaxPrec());
- }
- fswtchParam[i]->setValue(cfn.param * model->gvarData[gvidx].multiplierGet());
- widgetsMask |= CUSTOM_FUNCTION_NUMERIC_PARAM;
+ cfn.param = fswtchParam[i]->value() * model->gvarData[gvidx].multiplierSet();
+ fswtchParam[i]->setDecimals(model->gvarData[gvidx].prec);
+ fswtchParam[i]->setSingleStep(model->gvarData[gvidx].multiplierGet());
+ fswtchParam[i]->setSuffix(model->gvarData[gvidx].unitToString());
+ if (cfn.adjustMode == FUNC_ADJUST_GVAR_INCDEC) {
+ double rng = abs(model->gvarData[gvidx].getMax() - model->gvarData[gvidx].getMin());
+ rng *= model->gvarData[gvidx].multiplierGet();
+ fswtchParam[i]->setMinimum(-rng);
+ fswtchParam[i]->setMaximum(rng);
}
else {
- if (modified)
- cfn.param = fswtchParamT[i]->currentData().toInt();
- populateFuncParamCB(fswtchParamT[i], func, cfn.param, cfn.adjustMode);
- widgetsMask |= CUSTOM_FUNCTION_SOURCE_PARAM;
+ fswtchParam[i]->setMinimum(model->gvarData[gvidx].getMinPrec());
+ fswtchParam[i]->setMaximum(model->gvarData[gvidx].getMaxPrec());
}
+ fswtchParam[i]->setValue(cfn.param * model->gvarData[gvidx].multiplierGet());
+ widgetsMask |= CUSTOM_FUNCTION_NUMERIC_PARAM;
}
- else if (func == FuncReset) {
+ else {
+ if (modified)
+ cfn.param = fswtchParamT[i]->currentData().toInt();
+ populateFuncParamCB(fswtchParamT[i], func, cfn.param, cfn.adjustMode);
+ widgetsMask |= CUSTOM_FUNCTION_SOURCE_PARAM;
+ }
+ }
+ else if (func == FuncReset) {
+ if (modified)
+ cfn.param = fswtchParamT[i]->currentData().toInt();
+ populateFuncParamCB(fswtchParamT[i], func, cfn.param);
+ widgetsMask |= CUSTOM_FUNCTION_SOURCE_PARAM | CUSTOM_FUNCTION_ENABLE;
+ }
+ else if (func >= FuncSetTimer1 && func <= FuncSetTimer3) {
+ if (modified)
+ cfn.param = fswtchParamTime[i]->timeInSeconds();
+ RawSourceRange range = RawSource(SOURCE_TYPE_SPECIAL, func - FuncSetTimer1 + 2).getRange(model, generalSettings);
+ fswtchParamTime[i]->setTimeRange((int)range.min, (int)range.max);
+ fswtchParamTime[i]->setTime(cfn.param);
+ widgetsMask |= CUSTOM_FUNCTION_TIME_PARAM | CUSTOM_FUNCTION_ENABLE;
+ }
+ else if (func >= FuncSetFailsafe && func <= FuncBindExternalModule) {
+ widgetsMask |= CUSTOM_FUNCTION_ENABLE;
+ }
+ else if (func == FuncVolume || func == FuncBacklight) {
+ if (modified)
+ cfn.param = fswtchParamT[i]->currentData().toInt();
+ populateFuncParamCB(fswtchParamT[i], func, cfn.param);
+ widgetsMask |= CUSTOM_FUNCTION_SOURCE_PARAM | CUSTOM_FUNCTION_ENABLE;
+ }
+ else if (func == FuncPlaySound || func == FuncPlayHaptic || func == FuncPlayValue || func == FuncPlayPrompt || func == FuncPlayBoth || func == FuncBackgroundMusic) {
+ if (func != FuncBackgroundMusic) {
+ if (modified)
+ cfn.repeatParam = fswtchRepeat[i]->currentData().toInt();
+ widgetsMask |= CUSTOM_FUNCTION_REPEAT;
+ fswtchRepeat[i]->setCurrentIndex(fswtchRepeat[i]->findData(cfn.repeatParam));
+ }
+ if (func == FuncPlayValue) {
if (modified)
cfn.param = fswtchParamT[i]->currentData().toInt();
populateFuncParamCB(fswtchParamT[i], func, cfn.param);
- widgetsMask |= CUSTOM_FUNCTION_SOURCE_PARAM | CUSTOM_FUNCTION_ENABLE;
+ widgetsMask |= CUSTOM_FUNCTION_SOURCE_PARAM | CUSTOM_FUNCTION_REPEAT;
}
- else if (func >= FuncSetTimer1 && func <= FuncSetTimer3) {
- if (modified)
- cfn.param = fswtchParamTime[i]->timeInSeconds();
- RawSourceRange range = RawSource(SOURCE_TYPE_SPECIAL, func - FuncSetTimer1 + 2).getRange(model, generalSettings);
- fswtchParamTime[i]->setTimeRange((int)range.min, (int)range.max);
- fswtchParamTime[i]->setTime(cfn.param);
- widgetsMask |= CUSTOM_FUNCTION_TIME_PARAM | CUSTOM_FUNCTION_ENABLE;
- }
- else if (func >= FuncSetFailsafeInternalModule && func <= FuncBindExternalModule) {
- widgetsMask |= CUSTOM_FUNCTION_ENABLE;
- }
- else if (func == FuncVolume) {
- if (modified)
- cfn.param = fswtchParamT[i]->currentData().toInt();
- populateFuncParamCB(fswtchParamT[i], func, cfn.param);
- widgetsMask |= CUSTOM_FUNCTION_SOURCE_PARAM | CUSTOM_FUNCTION_ENABLE;
- }
- else if (func == FuncPlaySound || func == FuncPlayHaptic || func == FuncPlayValue || func == FuncPlayPrompt || func == FuncPlayBoth || func == FuncBackgroundMusic) {
- if (func != FuncBackgroundMusic) {
- widgetsMask |= CUSTOM_FUNCTION_REPEAT;
- fswtchRepeat[i]->update();
- }
- if (func == FuncPlayValue) {
- if (modified)
- cfn.param = fswtchParamT[i]->currentData().toInt();
- populateFuncParamCB(fswtchParamT[i], func, cfn.param);
- widgetsMask |= CUSTOM_FUNCTION_SOURCE_PARAM | CUSTOM_FUNCTION_REPEAT;
- }
- else if (func == FuncPlayPrompt || func == FuncPlayBoth) {
- if (firmware->getCapability(VoicesAsNumbers)) {
- fswtchParam[i]->setDecimals(0);
- fswtchParam[i]->setSingleStep(1);
- fswtchParam[i]->setMinimum(0);
- if (func == FuncPlayPrompt) {
- widgetsMask |= CUSTOM_FUNCTION_NUMERIC_PARAM | CUSTOM_FUNCTION_REPEAT | CUSTOM_FUNCTION_GV_TOOGLE;
- }
- else {
- widgetsMask |= CUSTOM_FUNCTION_NUMERIC_PARAM | CUSTOM_FUNCTION_REPEAT;
- fswtchParamGV[i]->setChecked(false);
- }
- fswtchParam[i]->setMaximum(func == FuncPlayBoth ? 254 : 255);
- if (modified) {
- if (fswtchParamGV[i]->isChecked()) {
- fswtchParam[i]->setMinimum(1);
- cfn.param = std::min(fswtchParam[i]->value(),5.0)+(fswtchParamGV[i]->isChecked() ? 250 : 0);
- }
- else {
- cfn.param = fswtchParam[i]->value();
- }
- }
- if (cfn.param>250 && (func!=FuncPlayBoth)) {
- fswtchParamGV[i]->setChecked(true);
- fswtchParam[i]->setValue(cfn.param-250);
- fswtchParam[i]->setMaximum(5);
- }
- else {
- fswtchParamGV[i]->setChecked(false);
- fswtchParam[i]->setValue(cfn.param);
- }
- if (cfn.param < 251)
- widgetsMask |= CUSTOM_FUNCTION_PLAY;
+ else if (func == FuncPlayPrompt || func == FuncPlayBoth) {
+ if (firmware->getCapability(VoicesAsNumbers)) {
+ fswtchParam[i]->setDecimals(0);
+ fswtchParam[i]->setSingleStep(1);
+ fswtchParam[i]->setMinimum(0);
+ if (func == FuncPlayPrompt) {
+ widgetsMask |= CUSTOM_FUNCTION_NUMERIC_PARAM | CUSTOM_FUNCTION_REPEAT | CUSTOM_FUNCTION_GV_TOOGLE;
}
else {
- widgetsMask |= CUSTOM_FUNCTION_FILE_PARAM;
- if (modified) {
- Helpers::getFileComboBoxValue(fswtchParamArmT[i], cfn.paramarm, firmware->getCapability(VoicesMaxLength));
+ widgetsMask |= CUSTOM_FUNCTION_NUMERIC_PARAM | CUSTOM_FUNCTION_REPEAT;
+ fswtchParamGV[i]->setChecked(false);
+ }
+ fswtchParam[i]->setMaximum(func == FuncPlayBoth ? 254 : 255);
+ if (modified) {
+ if (fswtchParamGV[i]->isChecked()) {
+ fswtchParam[i]->setMinimum(1);
+ cfn.param = std::min(fswtchParam[i]->value(), 5.0) + (fswtchParamGV[i]->isChecked() ? 250 : 0);
}
- Helpers::populateFileComboBox(fswtchParamArmT[i], tracksSet, cfn.paramarm);
- if (fswtchParamArmT[i]->currentText() != "----") {
- widgetsMask |= CUSTOM_FUNCTION_PLAY;
+ else {
+ cfn.param = fswtchParam[i]->value();
}
}
+ if (cfn.param > 250 && (func != FuncPlayBoth)) {
+ fswtchParamGV[i]->setChecked(true);
+ fswtchParam[i]->setValue(cfn.param - 250);
+ fswtchParam[i]->setMaximum(5);
+ }
+ else {
+ fswtchParamGV[i]->setChecked(false);
+ fswtchParam[i]->setValue(cfn.param);
+ }
+ if (cfn.param < 251)
+ widgetsMask |= CUSTOM_FUNCTION_PLAY;
}
- else if (func == FuncBackgroundMusic) {
+ else {
widgetsMask |= CUSTOM_FUNCTION_FILE_PARAM;
if (modified) {
Helpers::getFileComboBoxValue(fswtchParamArmT[i], cfn.paramarm, firmware->getCapability(VoicesMaxLength));
@@ -534,66 +485,69 @@ void CustomFunctionsPanel::refreshCustomFunction(int i, bool modified)
widgetsMask |= CUSTOM_FUNCTION_PLAY;
}
}
- else if (func == FuncPlaySound) {
- if (modified)
- cfn.param = (uint8_t)fswtchParamT[i]->currentIndex();
- populateFuncParamCB(fswtchParamT[i], func, cfn.param);
- widgetsMask |= CUSTOM_FUNCTION_SOURCE_PARAM;
- }
- else if (func == FuncPlayHaptic) {
- if (modified)
- cfn.param = (uint8_t)fswtchParamT[i]->currentIndex();
- populateFuncParamCB(fswtchParamT[i], func, cfn.param);
- widgetsMask |= CUSTOM_FUNCTION_SOURCE_PARAM;
- }
}
- else if (func == FuncPlayScript) {
+ else if (func == FuncBackgroundMusic) {
widgetsMask |= CUSTOM_FUNCTION_FILE_PARAM;
if (modified) {
- Helpers::getFileComboBoxValue(fswtchParamArmT[i], cfn.paramarm, 8);
+ Helpers::getFileComboBoxValue(fswtchParamArmT[i], cfn.paramarm, firmware->getCapability(VoicesMaxLength));
}
- Helpers::populateFileComboBox(fswtchParamArmT[i], scriptsSet, cfn.paramarm);
- }
- else if (func == FuncBacklight && IS_TARANIS_PLUS(getCurrentBoard())) {
- if (modified)
- cfn.param = (uint8_t)fswtchBLcolor[i]->value();
- fswtchBLcolor[i]->setValue(cfn.param);
- widgetsMask |= CUSTOM_FUNCTION_BL_COLOR;
- }
- else {
- if (modified)
- cfn.param = fswtchParam[i]->value();
- fswtchParam[i]->setDecimals(0);
- fswtchParam[i]->setSingleStep(1);
- fswtchParam[i]->setValue(cfn.param);
- if (func <= FuncInstantTrim) {
- widgetsMask |= CUSTOM_FUNCTION_ENABLE;
+ Helpers::populateFileComboBox(fswtchParamArmT[i], tracksSet, cfn.paramarm);
+ if (fswtchParamArmT[i]->currentText() != "----") {
+ widgetsMask |= CUSTOM_FUNCTION_PLAY;
}
}
+ else if (func == FuncPlaySound) {
+ if (modified)
+ cfn.param = (uint8_t)fswtchParamT[i]->currentIndex();
+ populateFuncParamCB(fswtchParamT[i], func, cfn.param);
+ widgetsMask |= CUSTOM_FUNCTION_SOURCE_PARAM;
+ }
+ else if (func == FuncPlayHaptic) {
+ if (modified)
+ cfn.param = (uint8_t)fswtchParamT[i]->currentIndex();
+ populateFuncParamCB(fswtchParamT[i], func, cfn.param);
+ widgetsMask |= CUSTOM_FUNCTION_SOURCE_PARAM;
+ }
}
+ else if (func == FuncPlayScript) {
+ widgetsMask |= CUSTOM_FUNCTION_FILE_PARAM;
+ if (modified) {
+ Helpers::getFileComboBoxValue(fswtchParamArmT[i], cfn.paramarm, 8);
+ }
+ Helpers::populateFileComboBox(fswtchParamArmT[i], scriptsSet, cfn.paramarm);
+ }
+ else {
+ if (modified)
+ cfn.param = fswtchParam[i]->value();
+ fswtchParam[i]->setDecimals(0);
+ fswtchParam[i]->setSingleStep(1);
+ fswtchParam[i]->setValue(cfn.param);
+ if (func <= FuncInstantTrim) {
+ widgetsMask |= CUSTOM_FUNCTION_ENABLE;
+ }
+ }
+ }
- fswtchFunc[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_SHOW_FUNC);
- fswtchParam[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_NUMERIC_PARAM);
- fswtchParamTime[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_TIME_PARAM);
- fswtchParamGV[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_GV_TOOGLE);
- fswtchParamT[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_SOURCE_PARAM);
- fswtchParamArmT[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_FILE_PARAM);
- fswtchEnable[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_ENABLE);
- if (widgetsMask & CUSTOM_FUNCTION_ENABLE)
- fswtchEnable[i]->setChecked(cfn.enabled);
- else
- fswtchEnable[i]->setChecked(false);
- fswtchRepeat[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_REPEAT);
- fswtchGVmode[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_GV_MODE);
- fswtchBLcolor[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_BL_COLOR);
- playBT[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_PLAY);
+ fswtchFunc[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_SHOW_FUNC);
+ fswtchParam[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_NUMERIC_PARAM);
+ fswtchParamTime[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_TIME_PARAM);
+ fswtchParamGV[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_GV_TOOGLE);
+ fswtchParamT[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_SOURCE_PARAM);
+ fswtchParamArmT[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_FILE_PARAM);
+ fswtchEnable[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_ENABLE);
+ if (widgetsMask & CUSTOM_FUNCTION_ENABLE)
+ fswtchEnable[i]->setChecked(cfn.enabled);
+ else
+ fswtchEnable[i]->setChecked(false);
+ fswtchRepeat[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_REPEAT);
+ fswtchGVmode[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_GV_MODE);
+ playBT[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_PLAY);
}
void CustomFunctionsPanel::update()
{
- updateDataModels();
lock = true;
- for (int i=0; iclear();
- for (unsigned int i=0; i=FuncOverrideCH1 && i<=FuncOverrideCH32) && (!model || !firmware->getCapability(SafetyChannelCustomFunction))) ||
- ((i==FuncVolume || i==FuncBackgroundMusic || i==FuncBackgroundMusicPause) && !firmware->getCapability(HasVolume)) ||
- ((i==FuncPlayScript && !IS_HORUS_OR_TARANIS(firmware->getBoard()))) ||
- ((i==FuncPlayHaptic) && !firmware->getCapability(Haptic)) ||
- ((i==FuncPlayBoth) && !firmware->getCapability(HasBeeper)) ||
- ((i==FuncLogs) && !firmware->getCapability(HasSDLogs)) ||
- ((i==FuncSetTimer3) && firmware->getCapability(Timers) < 3) ||
- ((i==FuncScreenshot) && !IS_HORUS_OR_TARANIS(firmware->getBoard())) ||
- ((i>=FuncRangeCheckInternalModule && i<=FuncBindExternalModule) && (!model || !firmware->getCapability(DangerousFunctions))) ||
- ((i>=FuncAdjustGV1 && i<=FuncAdjustGVLast) && (!model || !firmware->getCapability(Gvars)))
- ) {
- // skipped
- continue;
- }
- else {
- b->addItem(CustomFunctionData(AssignFunc(i)).funcToString(model), i);
- if (i == value) {
- b->setCurrentIndex(b->count()-1);
- }
- }
- }
-}
-
-void CustomFunctionsPanel::populateGVmodeCB(QComboBox *b, unsigned int value)
-{
- b->clear();
- b->addItem(tr("Value"));
- b->addItem(tr("Source"));
- b->addItem(tr("GVAR"));
- b->addItem(tr("Increment"));
- b->setCurrentIndex(value);
-}
-
void CustomFunctionsPanel::populateFuncParamCB(QComboBox *b, uint function, unsigned int value, unsigned int adjustmode)
{
QStringList qs;
b->setModel(new QStandardItemModel(b)); // clear combo box but not any shared item model
- if (function==FuncPlaySound) {
- CustomFunctionData::populatePlaySoundParams(qs);
- b->addItems(qs);
- b->setCurrentIndex(value);
- }
- else if (function==FuncPlayHaptic) {
- CustomFunctionData::populateHapticParams(qs);
- b->addItems(qs);
- b->setCurrentIndex(value);
- }
- else if (function==FuncReset) {
- CustomFunctionData::populateResetParams(model, b, value);
- }
- else if (function==FuncVolume) {
- b->setModel(rawSrcInputsItemModel);
+ if (function == FuncPlaySound) {
+ b->setModel(tabModelFactory->getItemModel(playSoundId));
b->setCurrentIndex(b->findData(value));
}
- else if (function==FuncPlayValue) {
- b->setModel(rawSrcAllItemModel);
+ else if (function == FuncPlayHaptic) {
+ b->setModel(tabModelFactory->getItemModel(harpicId));
b->setCurrentIndex(b->findData(value));
}
- else if (function>=FuncAdjustGV1 && function<=FuncAdjustGVLast) {
+ else if (function == FuncReset) {
+ b->setModel(tabFilterFactory->getItemModel(funcResetParamId));
+ b->setCurrentIndex(b->findData(value));
+ }
+ else if (function == FuncVolume || function == FuncBacklight) {
+ b->setModel(tabFilterFactory->getItemModel(rawSourceInputsId));
+ b->setCurrentIndex(b->findData(value));
+ }
+ else if (function == FuncPlayValue) {
+ b->setModel(tabFilterFactory->getItemModel(rawSourceAllId));
+ b->setCurrentIndex(b->findData(value));
+ }
+ else if (function >= FuncAdjustGV1 && function <= FuncAdjustGVLast) {
switch (adjustmode) {
case 1:
- b->setModel(rawSrcInputsItemModel);
+ b->setModel(tabFilterFactory->getItemModel(rawSourceInputsId));
b->setCurrentIndex(b->findData(value));
+ if (b->currentIndex() < 0)
+ b->setCurrentIndex(0);
break;
case 2:
- b->setModel(rawSrcGVarsItemModel);
+ b->setModel(tabFilterFactory->getItemModel(rawSourceGVarsId));
b->setCurrentIndex(b->findData(value));
+ if (b->currentIndex() < 0)
+ b->setCurrentIndex(0);
break;
}
}
@@ -749,10 +671,12 @@ void CustomFunctionsPanel::cmMoveDown()
swapData(selectedIndex, selectedIndex + 1);
}
-void CustomFunctionsPanel::cmClear()
+void CustomFunctionsPanel::cmClear(bool prompt)
{
- if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear Special Function. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
- return;
+ if (prompt) {
+ if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear Function. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
+ return;
+ }
functions[selectedIndex].clear();
resetCBsAndRefresh(selectedIndex);
@@ -761,10 +685,10 @@ void CustomFunctionsPanel::cmClear()
void CustomFunctionsPanel::cmClearAll()
{
- if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear all Special Functions. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
+ if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear all Functions. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
return;
- for (int i=0; icurves[fswCapability - 1].isEmpty()));
+ return ((selectedIndex < fswCapability - 1) && (functions[fswCapability - 1].isEmpty()));
}
bool CustomFunctionsPanel::moveDownAllowed() const
@@ -832,3 +756,29 @@ bool CustomFunctionsPanel::moveUpAllowed() const
{
return selectedIndex > 0;
}
+
+void CustomFunctionsPanel::connectItemModelEvents(FilteredItemModel * itemModel)
+{
+ connect(itemModel, &FilteredItemModel::aboutToBeUpdated, this, &CustomFunctionsPanel::onItemModelAboutToBeUpdated);
+ connect(itemModel, &FilteredItemModel::updateComplete, this, &CustomFunctionsPanel::onItemModelUpdateComplete);
+}
+
+void CustomFunctionsPanel::onItemModelAboutToBeUpdated()
+{
+ lock = true;
+ modelsUpdateCnt++;
+}
+
+void CustomFunctionsPanel::onItemModelUpdateComplete()
+{
+ modelsUpdateCnt--;
+ if (modelsUpdateCnt < 1) {
+ lock = true;
+ for (int i = 0; i < fswCapability; i++) {
+ fswtchSwtch[i]->setCurrentIndex(fswtchSwtch[i]->findData(functions[i].swtch.toValue()));
+ fswtchFunc[i]->setCurrentIndex(fswtchFunc[i]->findData(functions[i].func));
+ }
+ update();
+ lock = false;
+ }
+}
diff --git a/companion/src/modeledit/customfunctions.h b/companion/src/modeledit/customfunctions.h
index 1c93f3e96..87775246d 100644
--- a/companion/src/modeledit/customfunctions.h
+++ b/companion/src/modeledit/customfunctions.h
@@ -18,45 +18,26 @@
* GNU General Public License for more details.
*/
-#ifndef _CUSTOMFUNCTIONS_H_
-#define _CUSTOMFUNCTIONS_H_
+#pragma once
#include "modeledit.h"
#include "eeprominterface.h"
+#include "compounditemmodels.h"
+#include "filtereditemmodels.h"
#include
-class RawSourceFilterItemModel;
-class RawSwitchFilterItemModel;
class TimerEdit;
constexpr char MIMETYPE_CUSTOM_FUNCTION[] = "application/x-companion-custom-function";
-class RepeatComboBox: public QComboBox
-{
- Q_OBJECT
-
- public:
- RepeatComboBox(QWidget * parent, int & repeatParam);
- void update();
-
- signals:
- void modified();
-
- private slots:
- void onIndexChanged(int);
-
- protected:
- int & repeatParam;
-};
-
class CustomFunctionsPanel : public GenericPanel
{
Q_OBJECT
public:
- CustomFunctionsPanel(QWidget *parent, ModelData * model, GeneralSettings & generalSettings, Firmware * firmware);
- ~CustomFunctionsPanel();
+ CustomFunctionsPanel(QWidget *parent, ModelData * model, GeneralSettings & generalSettings, Firmware * firmware, CompoundItemModelFactory * sharedItemModels);
+ virtual ~CustomFunctionsPanel();
virtual void update();
@@ -64,12 +45,10 @@ class CustomFunctionsPanel : public GenericPanel
CustomFunctionData * functions;
private slots:
- void updateDataModels();
void customFunctionEdited();
void functionEdited();
void onCustomContextMenuRequested(QPoint pos);
void refreshCustomFunction(int index, bool modified=false);
- void onChildModified();
bool playSound(int index);
void stopSound(int index);
void toggleSound(bool play);
@@ -82,12 +61,12 @@ class CustomFunctionsPanel : public GenericPanel
void cmMoveUp();
void cmMoveDown();
void cmInsert();
- void cmClear();
+ void cmClear(bool prompt = true);
void cmClearAll();
+ void onItemModelAboutToBeUpdated();
+ void onItemModelUpdateComplete();
private:
- void populateFuncCB(QComboBox *b, unsigned int value);
- void populateGVmodeCB(QComboBox *b, unsigned int value);
void populateFuncParamCB(QComboBox *b, uint function, unsigned int value, unsigned int adjustmode=0);
bool hasClipboardData(QByteArray * data = nullptr) const;
bool insertAllowed() const;
@@ -95,10 +74,20 @@ class CustomFunctionsPanel : public GenericPanel
bool moveUpAllowed() const;
void swapData(int idx1, int idx2);
void resetCBsAndRefresh(int idx);
- RawSwitchFilterItemModel * rawSwitchItemModel;
- RawSourceFilterItemModel * rawSrcAllItemModel;
- RawSourceFilterItemModel * rawSrcInputsItemModel;
- RawSourceFilterItemModel * rawSrcGVarsItemModel;
+ void connectItemModelEvents(FilteredItemModel * itemModel);
+
+ CompoundItemModelFactory * tabModelFactory;
+ FilteredItemModelFactory * tabFilterFactory;
+ int funcActionsId;
+ int funcResetParamId;
+ int rawSwitchId;
+ int rawSourceAllId;
+ int rawSourceInputsId;
+ int rawSourceGVarsId;
+ int playSoundId;
+ int harpicId;
+ int repeatId;
+ int gvarAdjustModeId;
QSet tracksSet;
QSet scriptsSet;
@@ -112,14 +101,11 @@ class CustomFunctionsPanel : public GenericPanel
QComboBox * fswtchParamT[CPN_MAX_SPECIAL_FUNCTIONS];
QComboBox * fswtchParamArmT[CPN_MAX_SPECIAL_FUNCTIONS];
QCheckBox * fswtchEnable[CPN_MAX_SPECIAL_FUNCTIONS];
- RepeatComboBox * fswtchRepeat[CPN_MAX_SPECIAL_FUNCTIONS];
+ QComboBox * fswtchRepeat[CPN_MAX_SPECIAL_FUNCTIONS];
QComboBox * fswtchGVmode[CPN_MAX_SPECIAL_FUNCTIONS];
- QSlider * fswtchBLcolor[CPN_MAX_SPECIAL_FUNCTIONS];
QMediaPlayer * mediaPlayer;
int selectedIndex;
int fswCapability;
-
+ int modelsUpdateCnt;
};
-
-#endif // _CUSTOMFUNCTIONS_H_
diff --git a/companion/src/modeledit/expodialog.cpp b/companion/src/modeledit/expodialog.cpp
index 95aaeca66..be549144c 100644
--- a/companion/src/modeledit/expodialog.cpp
+++ b/companion/src/modeledit/expodialog.cpp
@@ -20,11 +20,11 @@
#include "expodialog.h"
#include "ui_expodialog.h"
-#include "rawitemfilteredmodel.h"
+#include "filtereditemmodels.h"
#include "helpers.h"
ExpoDialog::ExpoDialog(QWidget *parent, ModelData & model, ExpoData *expoData, GeneralSettings & generalSettings,
- Firmware * firmware, QString & inputName) :
+ Firmware * firmware, QString & inputName, CompoundItemModelFactory * sharedItemModels) :
QDialog(parent),
ui(new Ui::ExpoDialog),
model(model),
@@ -36,9 +36,13 @@ ExpoDialog::ExpoDialog(QWidget *parent, ModelData & model, ExpoData *expoData, G
lock(false)
{
ui->setupUi(this);
- QLabel * lb_fp[CPN_MAX_FLIGHT_MODES] = {ui->lb_FP0,ui->lb_FP1,ui->lb_FP2,ui->lb_FP3,ui->lb_FP4,ui->lb_FP5,ui->lb_FP6,ui->lb_FP7,ui->lb_FP8 };
- QCheckBox * tmp[CPN_MAX_FLIGHT_MODES] = {ui->cb_FP0,ui->cb_FP1,ui->cb_FP2,ui->cb_FP3,ui->cb_FP4,ui->cb_FP5,ui->cb_FP6,ui->cb_FP7,ui->cb_FP8 };
- for (int i=0; ilb_FP0, ui->lb_FP1, ui->lb_FP2, ui->lb_FP3, ui->lb_FP4, ui->lb_FP5, ui->lb_FP6, ui->lb_FP7, ui->lb_FP8 };
+ QCheckBox * tmp[CPN_MAX_FLIGHT_MODES] = {ui->cb_FP0, ui->cb_FP1, ui->cb_FP2, ui->cb_FP3, ui->cb_FP4, ui->cb_FP5, ui->cb_FP6, ui->cb_FP7, ui->cb_FP8 };
+ for (int i = 0; i < CPN_MAX_FLIGHT_MODES; i++) {
cb_fp[i] = tmp[i];
}
@@ -46,20 +50,27 @@ ExpoDialog::ExpoDialog(QWidget *parent, ModelData & model, ExpoData *expoData, G
setWindowTitle(tr("Edit %1").arg(RawSource(srcType, ed->chn).toString(&model, &generalSettings)));
QRegExp rx(CHAR_FOR_NAMES_REGEX);
- gvWeightGroup = new GVarGroup(ui->weightGV, ui->weightSB, ui->weightCB, ed->weight, model, 100, -100, 100);
- gvOffsetGroup = new GVarGroup(ui->offsetGV, ui->offsetSB, ui->offsetCB, ed->offset, model, 0, -100, 100);
+ id = dialogFilteredItemModels->registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_GVarRef)), "GVarRef");
+ gvWeightGroup = new GVarGroup(ui->weightGV, ui->weightSB, ui->weightCB, ed->weight, model, 100, -100, 100, 1.0,
+ dialogFilteredItemModels->getItemModel(id));
+ gvOffsetGroup = new GVarGroup(ui->offsetGV, ui->offsetSB, ui->offsetCB, ed->offset, model, 0, -100, 100, 1.0,
+ dialogFilteredItemModels->getItemModel(id));
- curveGroup = new CurveGroup(ui->curveTypeCB, ui->curveGVarCB, ui->curveValueCB, ui->curveValueSB, ed->curve, model,
- firmware->getCapability(HasInputDiff) ? 0 : (HIDE_DIFF | HIDE_NEGATIVE_CURVES));
+ curveRefFilteredItemModels = new CurveRefFilteredFactory(sharedItemModels,
+ firmware->getCapability(HasInputDiff) ? 0 : FilteredItemModel::PositiveFilter);
+ curveGroup = new CurveReferenceUIManager(ui->curveTypeCB, ui->curveGVarCB, ui->curveValueSB, ui->curveValueCB, ed->curve, model,
+ curveRefFilteredItemModels, this);
- ui->switchesCB->setModel(new RawSwitchFilterItemModel(&generalSettings, &model, RawSwitch::MixesContext, this));
+ id = dialogFilteredItemModels->registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_RawSwitch),
+ RawSwitch::MixesContext), "RawSwitch");
+ ui->switchesCB->setModel(dialogFilteredItemModels->getItemModel(id));
ui->switchesCB->setCurrentIndex(ui->switchesCB->findData(ed->swtch.toValue()));
- ui->sideCB->setCurrentIndex(ed->mode-1);
+ ui->sideCB->setCurrentIndex(ed->mode - 1);
if (!firmware->getCapability(FlightModes)) {
ui->label_phases->hide();
- for (int i=0; ihide();
cb_fp[i]->hide();
}
@@ -69,13 +80,13 @@ ExpoDialog::ExpoDialog(QWidget *parent, ModelData & model, ExpoData *expoData, G
ui->label_phases->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->label_phases, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(label_phases_customContextMenuRequested(const QPoint &)));
int mask = 1;
- for (int i=0; iflightModes & mask) == 0) {
cb_fp[i]->setChecked(true);
}
mask <<= 1;
}
- for (int i=firmware->getCapability(FlightModes); igetCapability(FlightModes); i < CPN_MAX_FLIGHT_MODES; i++) {
lb_fp[i]->hide();
cb_fp[i]->hide();
}
@@ -83,9 +94,11 @@ ExpoDialog::ExpoDialog(QWidget *parent, ModelData & model, ExpoData *expoData, G
if (firmware->getCapability(VirtualInputs)) {
ui->inputName->setMaxLength(firmware->getCapability(InputsLength));
- ui->sourceCB->setModel(new RawSourceFilterItemModel(&generalSettings, &model, (RawSource::InputSourceGroups & ~RawSource::InputsGroup) | RawSource::TelemGroup, this));
+ id = dialogFilteredItemModels->registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_RawSource),
+ (RawSource::InputSourceGroups & ~RawSource::NoneGroup & ~RawSource::InputsGroup) | RawSource::TelemGroup),
+ "RawSource");
+ ui->sourceCB->setModel(dialogFilteredItemModels->getItemModel(id));
ui->sourceCB->setCurrentIndex(ui->sourceCB->findData(ed->srcRaw.toValue()));
- ui->sourceCB->removeItem(0);
ui->inputName->setValidator(new QRegExpValidator(rx, this));
ui->inputName->setText(inputName);
}
@@ -98,8 +111,8 @@ ExpoDialog::ExpoDialog(QWidget *parent, ModelData & model, ExpoData *expoData, G
ui->trimCB->hide();
}
- for(int i=0; i < getBoardCapability(getCurrentBoard(), Board::NumTrims); i++) {
- ui->trimCB->addItem(RawSource(SOURCE_TYPE_TRIM, i).toString(), i+1);
+ for(int i = 0; i < getBoardCapability(getCurrentBoard(), Board::NumTrims); i++) {
+ ui->trimCB->addItem(RawSource(SOURCE_TYPE_TRIM, i).toString(), i + 1);
}
ui->trimCB->setCurrentIndex(1 - ed->carryTrim);
@@ -124,7 +137,7 @@ ExpoDialog::ExpoDialog(QWidget *parent, ModelData & model, ExpoData *expoData, G
connect(ui->trimCB, SIGNAL(currentIndexChanged(int)), this, SLOT(valuesChanged()));
connect(ui->switchesCB, SIGNAL(currentIndexChanged(int)), this, SLOT(valuesChanged()));
connect(ui->sideCB, SIGNAL(currentIndexChanged(int)), this, SLOT(valuesChanged()));
- for (int i=0; igetCapability(VirtualInputs)) {
@@ -136,10 +149,10 @@ ExpoDialog::ExpoDialog(QWidget *parent, ModelData & model, ExpoData *expoData, G
ExpoDialog::~ExpoDialog()
{
+ delete ui;
delete gvWeightGroup;
delete gvOffsetGroup;
- delete curveGroup;
- delete ui;
+ delete dialogFilteredItemModels;
}
void ExpoDialog::updateScale()
@@ -181,7 +194,7 @@ void ExpoDialog::valuesChanged()
}
ed->flightModes = 0;
- for (int i=CPN_MAX_FLIGHT_MODES-1; i>=0 ; i--) {
+ for (int i = CPN_MAX_FLIGHT_MODES - 1; i >= 0 ; i--) {
if (!cb_fp[i]->checkState()) {
ed->flightModes++;
}
@@ -212,7 +225,7 @@ void ExpoDialog::label_phases_customContextMenuRequested(const QPoint & pos)
void ExpoDialog::fmClearAll()
{
lock = true;
- for (int i=0; isetChecked(false);
}
lock = false;
@@ -222,7 +235,7 @@ void ExpoDialog::fmClearAll()
void ExpoDialog::fmSetAll()
{
lock = true;
- for (int i=0; isetChecked(true);
}
lock = false;
@@ -232,7 +245,7 @@ void ExpoDialog::fmSetAll()
void ExpoDialog::fmInvertAll()
{
lock = true;
- for (int i=0; isetChecked(!cb_fp[i]->isChecked());
}
lock = false;
diff --git a/companion/src/modeledit/expodialog.h b/companion/src/modeledit/expodialog.h
index e1355e147..f4980d344 100644
--- a/companion/src/modeledit/expodialog.h
+++ b/companion/src/modeledit/expodialog.h
@@ -26,7 +26,10 @@
#include "modelprinter.h"
class GVarGroup;
-class CurveGroup;
+class CompoundItemModelFactory;
+class FilteredItemModelFactory;
+class CurveRefFilteredFactory;
+class CurveReferenceUIManager;
namespace Ui {
class ExpoDialog;
@@ -36,8 +39,8 @@ class ExpoDialog : public QDialog {
Q_OBJECT
public:
ExpoDialog(QWidget *parent, ModelData & model, ExpoData *expodata, GeneralSettings & generalSettings,
- Firmware * firmware, QString & inputName);
- ~ExpoDialog();
+ Firmware * firmware, QString & inputName, CompoundItemModelFactory * sharedItemModels);
+ virtual ~ExpoDialog();
protected:
void updateScale();
@@ -59,10 +62,12 @@ class ExpoDialog : public QDialog {
QString & inputName;
GVarGroup * gvWeightGroup;
GVarGroup * gvOffsetGroup;
- CurveGroup * curveGroup;
+ CurveReferenceUIManager * curveGroup;
ModelPrinter modelPrinter;
bool lock;
QCheckBox * cb_fp[CPN_MAX_FLIGHT_MODES];
+ FilteredItemModelFactory *dialogFilteredItemModels;
+ CurveRefFilteredFactory *curveRefFilteredItemModels;
};
#endif // _EXPODIALOG_H_
diff --git a/companion/src/modeledit/flightmodes.cpp b/companion/src/modeledit/flightmodes.cpp
index 1634aed3a..224d69965 100644
--- a/companion/src/modeledit/flightmodes.cpp
+++ b/companion/src/modeledit/flightmodes.cpp
@@ -20,18 +20,19 @@
#include "flightmodes.h"
#include "ui_flightmode.h"
-#include "rawitemfilteredmodel.h"
+#include "filtereditemmodels.h"
#include "helpers.h"
#include "customdebug.h"
-FlightModePanel::FlightModePanel(QWidget * parent, ModelData & model, int phaseIdx, GeneralSettings & generalSettings, Firmware * firmware, RawSwitchFilterItemModel * switchModel):
+FlightModePanel::FlightModePanel(QWidget * parent, ModelData & model, int phaseIdx, GeneralSettings & generalSettings, Firmware * firmware,
+ FilteredItemModel * rawSwitchFilteredModel):
ModelPanel(parent, model, generalSettings, firmware),
ui(new Ui::FlightMode),
phaseIdx(phaseIdx),
- phase(model.flightModeData[phaseIdx]),
- rawSwitchItemModel(NULL)
+ phase(model.flightModeData[phaseIdx])
{
ui->setupUi(this);
+ connectItemModelEvents(rawSwitchFilteredModel);
ui->labelName->setContextMenuPolicy(Qt::CustomContextMenu);
ui->labelName->setToolTip(tr("Popup menu available"));
@@ -56,8 +57,8 @@ FlightModePanel::FlightModePanel(QWidget * parent, ModelData & model, int phaseI
// Flight mode switch
if (phaseIdx > 0) {
- ui->swtch->setModel(switchModel);
- connect(ui->swtch, SIGNAL(activated(int)), this, SLOT(phaseSwitchChanged(int)));
+ ui->swtch->setModel(rawSwitchFilteredModel);
+ connect(ui->swtch, SIGNAL(currentIndexChanged(int)), this, SLOT(phaseSwitch_currentIndexChanged(int)));
}
else {
ui->swtch->hide();
@@ -316,8 +317,6 @@ void FlightModePanel::update()
for (int i = 0; i < reCount; i++) {
updateRotaryEncoder(i);
}
-
- emit nameModified();
}
void FlightModePanel::updateGVar(int index)
@@ -390,17 +389,18 @@ void FlightModePanel::phaseName_editingFinished()
{
QLineEdit *lineEdit = qobject_cast(sender());
strcpy(phase.name, lineEdit->text().toLatin1());
+ emit phaseNameChanged();
emit modified();
- emit nameModified();
}
-void FlightModePanel::phaseSwitchChanged(int index)
+void FlightModePanel::phaseSwitch_currentIndexChanged(int index)
{
if (!lock) {
bool ok;
const RawSwitch rs(ui->swtch->itemData(index).toInt(&ok));
if (ok && phase.swtch.toValue() != rs.toValue()) {
phase.swtch = rs;
+ emit phaseSwitchChanged();
emit modified();
}
}
@@ -457,7 +457,7 @@ void FlightModePanel::phaseGVValue_editingFinished()
QDoubleSpinBox *spinBox = qobject_cast(sender());
int gvar = spinBox->property("index").toInt();
phase.gvars[gvar] = spinBox->value() * model->gvarData[gvar].multiplierSet();
- emit datachanged();
+ updateGVar(gvar);
emit modified();
}
}
@@ -469,7 +469,7 @@ void FlightModePanel::GVName_editingFinished()
int gvar = lineedit->property("index").toInt();
memset(&model->gvarData[gvar].name, 0, sizeof(model->gvarData[gvar].name));
strcpy(model->gvarData[gvar].name, lineedit->text().toLatin1());
- emit datachanged();
+ emit gvNameChanged();
emit modified();
}
}
@@ -488,7 +488,7 @@ void FlightModePanel::phaseGVUse_currentIndexChanged(int index)
}
if (model->isGVarLinkedCircular(phaseIdx, gvar))
QMessageBox::warning(this, "Companion", tr("Warning: Global variable links back to itself. Flight Mode 0 value used."));
- emit datachanged();
+ updateGVar(gvar);
emit modified();
lock = false;
}
@@ -500,7 +500,7 @@ void FlightModePanel::phaseGVUnit_currentIndexChanged(int index)
QComboBox *comboBox = qobject_cast(sender());
int gvar = comboBox->property("index").toInt();
model->gvarData[gvar].unit = index;
- emit datachanged();
+ updateGVar(gvar);
emit modified();
}
}
@@ -511,7 +511,7 @@ void FlightModePanel::phaseGVPrec_currentIndexChanged(int index)
QComboBox *comboBox = qobject_cast(sender());
int gvar = comboBox->property("index").toInt();
model->gvarData[gvar].prec = index;
- emit datachanged();
+ updateGVar(gvar);
emit modified();
}
}
@@ -534,7 +534,7 @@ void FlightModePanel::phaseGVMin_editingFinished()
}
}
}
- emit datachanged();
+ updateGVar(gvar);
emit modified();
}
}
@@ -557,7 +557,7 @@ void FlightModePanel::phaseGVMax_editingFinished()
}
}
}
- emit datachanged();
+ updateGVar(gvar);
emit modified();
}
}
@@ -708,10 +708,12 @@ bool FlightModePanel::moveUpAllowed() const
return phaseIdx > 0;
}
-void FlightModePanel::cmClear()
+void FlightModePanel::cmClear(bool prompt)
{
- if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear Flight Mode. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
- return;
+ if (prompt) {
+ if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear Flight Mode. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
+ return;
+ }
phase.clear(phaseIdx);
@@ -739,7 +741,8 @@ void FlightModePanel::cmClear()
model->updateAllReferences(ModelData::REF_UPD_TYPE_FLIGHT_MODE, ModelData::REF_UPD_ACT_CLEAR, phaseIdx);
- emit datachanged();
+ update();
+ emit phaseDataChanged();
emit modified();
}
@@ -765,7 +768,7 @@ void FlightModePanel::cmClearAll()
model->updateAllReferences(ModelData::REF_UPD_TYPE_GLOBAL_VARIABLE, ModelData::REF_UPD_ACT_CLEAR, i);
}
- emit datachanged();
+ emit phaseDataChanged();
emit modified();
}
@@ -780,8 +783,10 @@ void FlightModePanel::cmCopy()
void FlightModePanel::cmCut()
{
+ if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Cut Flight Mode. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
+ return;
cmCopy();
- cmClear();
+ cmClear(false);
}
void FlightModePanel::cmDelete()
@@ -842,7 +847,7 @@ void FlightModePanel::cmDelete()
model->updateAllReferences(ModelData::REF_UPD_TYPE_FLIGHT_MODE, ModelData::REF_UPD_ACT_SHIFT, phaseIdx, 0, -1);
- emit datachanged();
+ emit phaseDataChanged();
emit modified();
}
@@ -893,7 +898,7 @@ void FlightModePanel::cmInsert()
model->updateAllReferences(ModelData::REF_UPD_TYPE_FLIGHT_MODE, ModelData::REF_UPD_ACT_SHIFT, phaseIdx, 0, 1);
- emit datachanged();
+ emit phaseDataChanged();
emit modified();
}
@@ -942,7 +947,7 @@ void FlightModePanel::cmPaste()
}
}
- emit datachanged();
+ emit phaseDataChanged();
emit modified();
}
}
@@ -1031,7 +1036,7 @@ void FlightModePanel::swapData(int idx1, int idx2)
}
model->updateAllReferences(ModelData::REF_UPD_TYPE_FLIGHT_MODE, ModelData::REF_UPD_ACT_SWAP, idx1, idx2);
- emit datachanged();
+ emit phaseDataChanged();
emit modified();
}
@@ -1059,7 +1064,7 @@ void FlightModePanel::gvOnCustomContextMenuRequested(QPoint pos)
bool FlightModePanel::gvHasClipboardData() const
{
- if (gvHasDefnClipboardData() || gvHasValueClipboardData())
+ if ((phaseIdx == 0 && gvHasDefnClipboardData() && gvHasAllValuesClipboardData()) || (phaseIdx > 0 && gvHasValueClipboardData()))
return true;
return false;
}
@@ -1092,6 +1097,20 @@ bool FlightModePanel::gvHasValueClipboardData(QByteArray * data) const
return false;
}
+bool FlightModePanel::gvHasAllValuesClipboardData(QByteArray * data) const
+{
+ const QClipboard * clipboard = QApplication::clipboard();
+ const QMimeData * mimeData = clipboard->mimeData();
+ if (phaseIdx == 0 && mimeData->hasFormat(MIMETYPE_GVAR_ALL_VALUES)) {
+ if (data) {
+ data->clear();
+ data->append(mimeData->data(MIMETYPE_GVAR_ALL_VALUES));
+ }
+ return true;
+ }
+ return false;
+}
+
bool FlightModePanel::gvDeleteAllowed() const
{
return phaseIdx == 0;
@@ -1124,11 +1143,13 @@ bool FlightModePanel::gvMoveUpAllowed() const
return (phaseIdx == 0 && gvIdx > 0);
}
-void FlightModePanel::gvCmClear()
+void FlightModePanel::gvCmClear(bool prompt)
{
if (phaseIdx == 0) {
- if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear selected Global Variable across all Flight Modes. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
- return;
+ if (prompt) {
+ if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear Global Variable across all Flight Modes. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
+ return;
+ }
model->gvarData[gvIdx].clear();
for (int i = 0; i < fmCount; i++) {
model->flightModeData[i].gvars[gvIdx] = model->flightModeData[i].linkedGVarFlightModeZero(i);
@@ -1136,9 +1157,14 @@ void FlightModePanel::gvCmClear()
model->updateAllReferences(ModelData::REF_UPD_TYPE_GLOBAL_VARIABLE, ModelData::REF_UPD_ACT_CLEAR, gvIdx);
}
else {
+ if (prompt) {
+ if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear Global Variable. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
+ return;
+ }
phase.gvars[gvIdx] = phase.linkedGVarFlightModeZero(phaseIdx);
}
- emit datachanged();
+ updateGVar(gvIdx);
+ emit gvNameChanged();
emit modified();
}
@@ -1162,7 +1188,10 @@ void FlightModePanel::gvCmClearAll()
phase.gvars[i] = phase.linkedGVarFlightModeZero(phaseIdx);
}
}
- emit datachanged();
+ for (int i = 0; i < gvCount; i++) {
+ updateGVar(i);
+ }
+ emit gvNameChanged();
emit modified();
}
@@ -1173,38 +1202,58 @@ void FlightModePanel::gvCmCopy()
if (phaseIdx == 0) {
data.append((char*)&model->gvarData[gvIdx], sizeof(GVarData));
mimeData->setData(MIMETYPE_GVAR_PARAMS, data);
+ QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard);
+
+ data.clear();
+ for (int j = 0; j < fmCount; j++) {
+ data.append((char*)&model->flightModeData[j].gvars[gvIdx], sizeof(phase.gvars[0]));
+ }
+ mimeData->setData(MIMETYPE_GVAR_ALL_VALUES, data);
+ QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard);
+
+ mimeData->removeFormat(MIMETYPE_GVAR_VALUE);
+ QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard);
}
else {
mimeData->removeFormat(MIMETYPE_GVAR_PARAMS);
+ QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard);
+
+ mimeData->removeFormat(MIMETYPE_GVAR_ALL_VALUES);
+ QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard);
+
+ data.clear();
+ int val = phase.gvars[gvIdx];
+ if (model->isGVarLinked(phaseIdx, gvIdx))
+ val = GVAR_MAX_VALUE + 1 + model->getGVarFlightModeIndex(phaseIdx, gvIdx); // store index in case paste is to another flight mode
+ data.setNum(val);
+ mimeData->setData(MIMETYPE_GVAR_VALUE, data);
+ QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard);
}
- QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard);
- int val = phase.gvars[gvIdx];
- if (model->isGVarLinked(phaseIdx, gvIdx))
- val = GVAR_MAX_VALUE + 1 + model->getGVarFlightModeIndex(phaseIdx, gvIdx); // store index in case paste is to another flight mode
- data.setNum(val);
- mimeData->setData(MIMETYPE_GVAR_VALUE, data);
- QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard);
}
void FlightModePanel::gvCmCut()
{
- gvCmCopy();
- if (phaseIdx > 0) {
- gvCmClear();
+ if (phaseIdx == 0) {
+ if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Cut Global Variable across all Flight Modes. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
+ return;
}
else {
- model->gvarData[gvIdx].clear();
- phase.gvars[gvIdx] = 0;
- model->updateAllReferences(ModelData::REF_UPD_TYPE_GLOBAL_VARIABLE, ModelData::REF_UPD_ACT_CLEAR, gvIdx);
- emit datachanged();
- emit modified();
+ if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Cut Global Variable. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
+ return;
}
+
+ gvCmCopy();
+ gvCmClear(false);
}
void FlightModePanel::gvCmDelete()
{
if (phaseIdx > 0)
return;
+
+ if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Delete Global Variable. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
+ return;
+
int maxidx = gvCount - 1;
for (int i = gvIdx; i < maxidx; i++) {
memcpy(&model->gvarData[i], &model->gvarData[i + 1], sizeof(GVarData));
@@ -1217,8 +1266,13 @@ void FlightModePanel::gvCmDelete()
for (int j = 0; j < fmCount; j++) {
model->flightModeData[j].gvars[maxidx] = model->flightModeData[j].linkedGVarFlightModeZero(j);
}
+
model->updateAllReferences(ModelData::REF_UPD_TYPE_GLOBAL_VARIABLE, ModelData::REF_UPD_ACT_SHIFT, gvIdx, 0, -1);
- emit datachanged();
+
+ for (int i = 0; i < gvCount; i++) {
+ updateGVar(i);
+ }
+ emit gvNameChanged();
emit modified();
}
@@ -1235,7 +1289,10 @@ void FlightModePanel::gvCmInsert()
model->flightModeData[j].gvars[gvIdx] = model->flightModeData[j].linkedGVarFlightModeZero(j);
}
model->updateAllReferences(ModelData::REF_UPD_TYPE_GLOBAL_VARIABLE, ModelData::REF_UPD_ACT_SHIFT, gvIdx, 0, 1);
- emit datachanged();
+ for (int i = 0; i < gvCount; i++) {
+ updateGVar(i);
+ }
+ emit gvNameChanged();
emit modified();
}
@@ -1254,11 +1311,20 @@ void FlightModePanel::gvCmMoveUp()
void FlightModePanel::gvCmPaste()
{
QByteArray data;
- if (phaseIdx == 0 && gvHasDefnClipboardData(&data)) {
- GVarData *gvd = &model->gvarData[gvIdx];
- memcpy(gvd, data.constData(), sizeof(GVarData));
+ if (phaseIdx == 0) {
+ if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Paste to selected Global Variable across all Flight Modes. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
+ return;
+ if (gvHasDefnClipboardData(&data)) {
+ memcpy(&model->gvarData[gvIdx], data.constData(), sizeof(GVarData));
+ }
+ if (gvHasAllValuesClipboardData(&data)) {
+ for (int j = 0; j < fmCount; j++) {
+ int *gvar = &model->flightModeData[j].gvars[gvIdx];
+ memcpy(gvar, data.mid(j * sizeof(phase.gvars[0]), sizeof(phase.gvars[0])).constData(), sizeof(phase.gvars[0]));
+ }
+ }
}
- if (gvHasValueClipboardData(&data)) {
+ else if (gvHasValueClipboardData(&data)) {
int val = data.toInt();
if (val > GVAR_MAX_VALUE) {
if (phaseIdx > 0)
@@ -1269,7 +1335,8 @@ void FlightModePanel::gvCmPaste()
else
phase.gvars[gvIdx] = val;
}
- emit datachanged();
+ updateGVar(gvIdx);
+ emit gvNameChanged();
emit modified();
}
@@ -1287,37 +1354,65 @@ void FlightModePanel::gvSwapData(int idx1, int idx2)
model->flightModeData[j].gvars[idx1] = valtmp;
}
model->updateAllReferences(ModelData::REF_UPD_TYPE_GLOBAL_VARIABLE, ModelData::REF_UPD_ACT_SWAP, idx1, idx2);
- emit datachanged();
+ updateGVar(idx1);
+ updateGVar(idx2);
+ emit gvNameChanged();
emit modified();
}
}
+void FlightModePanel::connectItemModelEvents(const FilteredItemModel * itemModel)
+{
+ connect(itemModel, &FilteredItemModel::aboutToBeUpdated, this, &FlightModePanel::onItemModelAboutToBeUpdated);
+ connect(itemModel, &FilteredItemModel::updateComplete, this, &FlightModePanel::onItemModelUpdateComplete);
+}
+
+void FlightModePanel::onItemModelAboutToBeUpdated()
+{
+ lock = true;
+}
+
+void FlightModePanel::onItemModelUpdateComplete()
+{
+ update();
+ lock = false;
+}
+
/**********************************************************/
-FlightModesPanel::FlightModesPanel(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware):
+FlightModesPanel::FlightModesPanel(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware,
+ CompoundItemModelFactory * sharedItemModels):
ModelPanel(parent, model, generalSettings, firmware),
- modesCount(firmware->getCapability(FlightModes))
+ sharedItemModels(sharedItemModels)
{
+ rawSwitchFilteredModel = new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_RawSwitch), RawSwitch::MixesContext);
+ connectItemModelEvents(rawSwitchFilteredModel);
- RawSwitchFilterItemModel * swModel = new RawSwitchFilterItemModel(&generalSettings, &model, RawSwitch::MixesContext, this);
- connect(this, &FlightModesPanel::updated, swModel, &RawSwitchFilterItemModel::update);
+ modesCount = firmware->getCapability(FlightModes);
QGridLayout * gridLayout = new QGridLayout(this);
tabWidget = new QTabWidget(this);
for (int i = 0; i < modesCount; i++) {
- FlightModePanel * tab = new FlightModePanel(tabWidget, model, i, generalSettings, firmware, swModel);
+ FlightModePanel * tab = new FlightModePanel(tabWidget, model, i, generalSettings, firmware, rawSwitchFilteredModel);
tab->setProperty("index", i);
- connect(tab, &FlightModePanel::datachanged, this, &FlightModesPanel::update);
- connect(tab, &FlightModePanel::modified, this, &FlightModesPanel::modified);
- connect(tab, &FlightModePanel::nameModified, this, &FlightModesPanel::onPhaseNameChanged);
- connect(this, &FlightModesPanel::updated, tab, &FlightModePanel::update);
+ connect(tab, &FlightModePanel::modified, this, &FlightModesPanel::modified);
+ connect(tab, &FlightModePanel::phaseDataChanged, this, &FlightModesPanel::onPhaseNameChanged);
+ connect(tab, &FlightModePanel::phaseNameChanged, this, &FlightModesPanel::onPhaseNameChanged);
+ connect(tab, &FlightModePanel::phaseSwitchChanged, this, &FlightModesPanel::updateItemModels);
+ connect(tab, &FlightModePanel::gvNameChanged, this, &FlightModesPanel::updateItemModels);
+
+ connect(this, &FlightModesPanel::updated, tab, &FlightModePanel::update);
tabWidget->addTab(tab, getTabName(i));
+ panels << tab;
}
+ connect(tabWidget, &QTabWidget::currentChanged, this, &FlightModesPanel::onTabIndexChanged);
gridLayout->addWidget(tabWidget, 0, 0, 1, 1);
+ onTabIndexChanged(0);
}
FlightModesPanel::~FlightModesPanel()
{
+ delete rawSwitchFilteredModel;
}
QString FlightModesPanel::getTabName(int index)
@@ -1338,9 +1433,36 @@ void FlightModesPanel::onPhaseNameChanged()
{
int index = sender()->property("index").toInt();
tabWidget->setTabText(index, getTabName(index));
+ updateItemModels();
}
void FlightModesPanel::update()
{
emit updated();
}
+
+void FlightModesPanel::connectItemModelEvents(const FilteredItemModel * itemModel)
+{
+ connect(itemModel, &FilteredItemModel::aboutToBeUpdated, this, &FlightModesPanel::onItemModelAboutToBeUpdated);
+ connect(itemModel, &FilteredItemModel::updateComplete, this, &FlightModesPanel::onItemModelUpdateComplete);
+}
+
+void FlightModesPanel::onItemModelAboutToBeUpdated()
+{
+}
+
+void FlightModesPanel::onItemModelUpdateComplete()
+{
+}
+
+void FlightModesPanel::updateItemModels()
+{
+ sharedItemModels->update(AbstractItemModel::IMUE_FlightModes);
+ sharedItemModels->update(AbstractItemModel::IMUE_GVars);
+}
+
+void FlightModesPanel::onTabIndexChanged(int index)
+{
+ if (index < panels.size())
+ panels.at(index)->update();
+}
diff --git a/companion/src/modeledit/flightmodes.h b/companion/src/modeledit/flightmodes.h
index 1986f1e46..33fd87e8a 100644
--- a/companion/src/modeledit/flightmodes.h
+++ b/companion/src/modeledit/flightmodes.h
@@ -24,11 +24,13 @@
#include "modeledit.h"
#include "eeprominterface.h"
-class RawSwitchFilterItemModel;
+class CompoundItemModelFactory;
+class FilteredItemModel;
constexpr char MIMETYPE_FLIGHTMODE[] = "application/x-companion-flightmode";
constexpr char MIMETYPE_GVAR_PARAMS[] = "application/x-companion-gvar-params";
constexpr char MIMETYPE_GVAR_VALUE[] = "application/x-companion-gvar-value";
+constexpr char MIMETYPE_GVAR_ALL_VALUES[] = "application/x-companion-gvar-all-values";
namespace Ui {
class FlightMode;
@@ -39,18 +41,21 @@ class FlightModePanel : public ModelPanel
Q_OBJECT
public:
- FlightModePanel(QWidget *parent, ModelData &model, int modeIdx, GeneralSettings & generalSettings, Firmware * firmware, RawSwitchFilterItemModel * switchModel);
+ FlightModePanel(QWidget *parent, ModelData &model, int modeIdx, GeneralSettings & generalSettings, Firmware * firmware,
+ FilteredItemModel * rawSwitchFilteredModel);
virtual ~FlightModePanel();
virtual void update();
signals:
- void nameModified();
- void datachanged();
+ void gvNameChanged();
+ void phaseDataChanged();
+ void phaseNameChanged();
+ void phaseSwitchChanged();
private slots:
void phaseName_editingFinished();
- void phaseSwitchChanged(int index);
+ void phaseSwitch_currentIndexChanged(int index);
void phaseFadeIn_editingFinished();
void phaseFadeOut_editingFinished();
void phaseTrimUse_currentIndexChanged(int index);
@@ -67,7 +72,7 @@ class FlightModePanel : public ModelPanel
void phaseREValue_editingFinished();
void phaseREUse_currentIndexChanged(int index);
void onCustomContextMenuRequested(QPoint pos);
- void cmClear();
+ void cmClear(bool prompt = true);
void cmClearAll();
void cmCopy();
void cmCut();
@@ -77,7 +82,7 @@ class FlightModePanel : public ModelPanel
void cmMoveDown();
void cmMoveUp();
void gvOnCustomContextMenuRequested(QPoint pos);
- void gvCmClear();
+ void gvCmClear(bool prompt = true);
void gvCmClearAll();
void gvCmCopy();
void gvCmCut();
@@ -86,6 +91,8 @@ class FlightModePanel : public ModelPanel
void gvCmPaste();
void gvCmMoveDown();
void gvCmMoveUp();
+ void onItemModelAboutToBeUpdated();
+ void onItemModelUpdateComplete();
private:
Ui::FlightMode *ui;
@@ -110,7 +117,6 @@ class FlightModePanel : public ModelPanel
QVector trimsUse;
QVector trimsValue;
QVector trimsSlider;
- RawSwitchFilterItemModel * rawSwitchItemModel;
Board::Type board;
void trimUpdate(unsigned int trim);
@@ -127,11 +133,13 @@ class FlightModePanel : public ModelPanel
bool gvHasClipboardData() const;
bool gvHasDefnClipboardData(QByteArray * data = nullptr) const;
bool gvHasValueClipboardData(QByteArray * data = nullptr) const;
+ bool gvHasAllValuesClipboardData(QByteArray * data = nullptr) const;
bool gvDeleteAllowed() const;
bool gvInsertAllowed() const;
bool gvMoveDownAllowed() const;
bool gvMoveUpAllowed() const;
void gvSwapData(int idx1, int idx2);
+ void connectItemModelEvents(const FilteredItemModel * itemModel);
};
class FlightModesPanel : public ModelPanel
@@ -139,7 +147,7 @@ class FlightModesPanel : public ModelPanel
Q_OBJECT
public:
- FlightModesPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware);
+ FlightModesPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CompoundItemModelFactory * sharedItemModels);
virtual ~FlightModesPanel();
public slots:
@@ -150,13 +158,20 @@ class FlightModesPanel : public ModelPanel
private slots:
void onPhaseNameChanged();
+ void onTabIndexChanged(int index);
+ void onItemModelAboutToBeUpdated();
+ void onItemModelUpdateComplete();
private:
QString getTabName(int index);
int modesCount;
QTabWidget *tabWidget;
-
+ CompoundItemModelFactory *sharedItemModels;
+ FilteredItemModel *rawSwitchFilteredModel;
+ QVector panels;
+ void updateItemModels();
+ void connectItemModelEvents(const FilteredItemModel * itemModel);
};
#endif // _FLIGHTMODES_H_
diff --git a/companion/src/modeledit/heli.cpp b/companion/src/modeledit/heli.cpp
index c0a4e39d8..ef86c5793 100644
--- a/companion/src/modeledit/heli.cpp
+++ b/companion/src/modeledit/heli.cpp
@@ -21,21 +21,26 @@
#include "heli.h"
#include "ui_heli.h"
#include "helpers.h"
-#include "rawitemfilteredmodel.h"
+#include "filtereditemmodels.h"
-HeliPanel::HeliPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware):
+HeliPanel::HeliPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CompoundItemModelFactory * sharedItemModels):
ModelPanel(parent, model, generalSettings, firmware),
ui(new Ui::Heli)
{
ui->setupUi(this);
- rawSourceItemModel = new RawSourceFilterItemModel(&generalSettings, &model, RawSource::InputSourceGroups, this);
+ rawSourceFilteredModel = new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_RawSource), RawSource::InputSourceGroups);
+ connectItemModelEvents(rawSourceFilteredModel);
connect(ui->swashType, SIGNAL(currentIndexChanged(int)), this, SLOT(edited()));
connect(ui->swashRingVal, SIGNAL(editingFinished()), this, SLOT(edited()));
+ ui->swashCollectiveSource->setModel(rawSourceFilteredModel);
connect(ui->swashCollectiveSource, SIGNAL(currentIndexChanged(int)), this, SLOT(edited()));
+
if (firmware->getCapability(VirtualInputs)) {
+ ui->swashAileronSource->setModel(rawSourceFilteredModel);
connect(ui->swashAileronSource, SIGNAL(currentIndexChanged(int)), this, SLOT(edited()));
+ ui->swashElevatorSource->setModel(rawSourceFilteredModel);
connect(ui->swashElevatorSource, SIGNAL(currentIndexChanged(int)), this, SLOT(edited()));
connect(ui->swashAileronWeight, SIGNAL(editingFinished()), this, SLOT(edited()));
connect(ui->swashElevatorWeight, SIGNAL(editingFinished()), this, SLOT(edited()));
@@ -64,29 +69,18 @@ HeliPanel::HeliPanel(QWidget *parent, ModelData & model, GeneralSettings & gener
HeliPanel::~HeliPanel()
{
delete ui;
-}
-
-void HeliPanel::updateDataModels()
-{
- const bool oldLock = lock;
- lock = true;
- rawSourceItemModel->update();
- lock = oldLock;
+ delete rawSourceFilteredModel;
}
void HeliPanel::update()
{
lock = true;
- updateDataModels();
ui->swashType->setCurrentIndex(model->swashRingData.type);
- ui->swashCollectiveSource->setModel(rawSourceItemModel);
ui->swashCollectiveSource->setCurrentIndex(ui->swashCollectiveSource->findData(model->swashRingData.collectiveSource.toValue()));
ui->swashRingVal->setValue(model->swashRingData.value);
if (firmware->getCapability(VirtualInputs)) {
- ui->swashElevatorSource->setModel(rawSourceItemModel);
ui->swashElevatorSource->setCurrentIndex(ui->swashElevatorSource->findData(model->swashRingData.elevatorSource.toValue()));
- ui->swashAileronSource->setModel(rawSourceItemModel);
ui->swashAileronSource->setCurrentIndex(ui->swashAileronSource->findData(model->swashRingData.aileronSource.toValue()));
ui->swashElevatorWeight->setValue(model->swashRingData.elevatorWeight);
ui->swashAileronWeight->setValue(model->swashRingData.aileronWeight);
@@ -122,3 +116,20 @@ void HeliPanel::edited()
emit modified();
}
}
+
+void HeliPanel::connectItemModelEvents(const FilteredItemModel * itemModel)
+{
+ connect(itemModel, &FilteredItemModel::aboutToBeUpdated, this, &HeliPanel::onItemModelAboutToBeUpdated);
+ connect(itemModel, &FilteredItemModel::updateComplete, this, &HeliPanel::onItemModelUpdateComplete);
+}
+
+void HeliPanel::onItemModelAboutToBeUpdated()
+{
+ lock = true;
+}
+
+void HeliPanel::onItemModelUpdateComplete()
+{
+ update();
+ lock = false;
+}
diff --git a/companion/src/modeledit/heli.h b/companion/src/modeledit/heli.h
index 5a27c7c26..eb3c7d54e 100644
--- a/companion/src/modeledit/heli.h
+++ b/companion/src/modeledit/heli.h
@@ -23,7 +23,8 @@
#include "modeledit.h"
-class RawSourceFilterItemModel;
+class CompoundItemModelFactory;
+class FilteredItemModel;
namespace Ui {
class Heli;
@@ -34,17 +35,19 @@ class HeliPanel : public ModelPanel
Q_OBJECT
public:
- HeliPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware);
- ~HeliPanel();
+ HeliPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CompoundItemModelFactory * sharedItemModels);
+ virtual ~HeliPanel();
void update();
private slots:
- void updateDataModels();
void edited();
+ void onItemModelAboutToBeUpdated();
+ void onItemModelUpdateComplete();
private:
Ui::Heli *ui;
- RawSourceFilterItemModel * rawSourceItemModel;
+ FilteredItemModel * rawSourceFilteredModel;
+ void connectItemModelEvents(const FilteredItemModel * itemModel);
};
#endif // _HELI_H_
diff --git a/companion/src/modeledit/inputs.cpp b/companion/src/modeledit/inputs.cpp
index 806de54fc..1f7fd2b0b 100644
--- a/companion/src/modeledit/inputs.cpp
+++ b/companion/src/modeledit/inputs.cpp
@@ -21,12 +21,20 @@
#include "inputs.h"
#include "expodialog.h"
#include "helpers.h"
+#include "filtereditemmodels.h"
-InputsPanel::InputsPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware):
+InputsPanel::InputsPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CompoundItemModelFactory * sharedItemModels):
ModelPanel(parent, model, generalSettings, firmware),
expoInserted(false),
- modelPrinter(firmware, generalSettings, model)
+ modelPrinter(firmware, generalSettings, model),
+ sharedItemModels(sharedItemModels),
+ modelsUpdateCnt(0)
{
+ connectItemModelEvents(AbstractItemModel::IMID_RawSource);
+ connectItemModelEvents(AbstractItemModel::IMID_RawSwitch);
+ connectItemModelEvents(AbstractItemModel::IMID_Curve);
+ connectItemModelEvents(AbstractItemModel::IMID_GVarRef);
+
inputsCount = firmware->getCapability(VirtualInputs);
if (inputsCount == 0)
inputsCount = CPN_MAX_STICKS;
@@ -180,13 +188,14 @@ void InputsPanel::gm_openExpo(int index)
if (firmware->getCapability(VirtualInputs))
inputName = model->inputNames[ed.chn];
- ExpoDialog *g = new ExpoDialog(this, *model, &ed, generalSettings, firmware, inputName);
- if (g->exec()) {
+ ExpoDialog *dlg = new ExpoDialog(this, *model, &ed, generalSettings, firmware, inputName, sharedItemModels);
+ if (dlg->exec()) {
model->expoData[index] = ed;
if (firmware->getCapability(VirtualInputs))
strncpy(model->inputNames[ed.chn], inputName.toLatin1().data(), INPUT_NAME_LEN);
- emit modified();
update();
+ updateItemModels();
+ emit modified();
}
else {
if (expoInserted) {
@@ -195,6 +204,7 @@ void InputsPanel::gm_openExpo(int index)
expoInserted=false;
update();
}
+ delete dlg;
}
int InputsPanel::getExpoIndex(unsigned int dch)
@@ -227,26 +237,28 @@ void InputsPanel::setSelectedByExpoList(QList list)
}
}
-void InputsPanel::exposDelete(bool ask)
+void InputsPanel::exposDelete(bool prompt)
{
QList list = createExpoListFromSelected();
if (list.isEmpty())
return;
- QMessageBox::StandardButton ret = QMessageBox::No;
-
- if (ask)
- ret = QMessageBox::warning(this, CPN_STR_APP_NAME, tr("Delete selected Inputs. Are you sure?"), QMessageBox::Yes | QMessageBox::No);
-
- if ((ret == QMessageBox::Yes) || (!ask)) {
- exposDeleteList(list, ask);
- emit modified();
- update();
+ if (prompt) {
+ if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Delete selected Input lines. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
+ return;
}
+
+ exposDeleteList(list, prompt);
+ update();
+ updateItemModels();
+ emit modified();
}
void InputsPanel::exposCut()
{
+ if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Cut selected Input lines. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
+ return;
+
exposCopy();
exposDelete(false);
}
@@ -312,12 +324,12 @@ void InputsPanel::pasteExpoMimeData(const QMimeData * mimeData, int destIdx)
i += sizeof(ExpoData);
}
- emit modified();
update();
+ updateItemModels();
+ emit modified();
}
}
-
void InputsPanel::exposPaste()
{
const QClipboard *clipboard = QApplication::clipboard();
@@ -339,6 +351,9 @@ void InputsPanel::expoOpen(QListWidgetItem *item)
if (!item)
item = ExposlistWidget->currentItem();
+ if (item == nullptr)
+ return;
+
int idx = item->data(Qt::UserRole).toByteArray().at(0);
if (idx < 0) {
int ch = -idx - 1;
@@ -356,7 +371,11 @@ void InputsPanel::expoOpen(QListWidgetItem *item)
void InputsPanel::expoAdd()
{
- int index = ExposlistWidget->currentItem()->data(Qt::UserRole).toByteArray().at(0);
+ QListWidgetItem *item = ExposlistWidget->currentItem();
+ if (item == nullptr)
+ return;
+
+ int index = item->data(Qt::UserRole).toByteArray().at(0);
if (index < 0) { // if empty then return relevant index
expoOpen();
@@ -481,8 +500,9 @@ void InputsPanel::moveExpoList(bool down)
}
}
if (mod) {
- emit modified();
update();
+ updateItemModels();
+ emit modified();
}
setSelectedByExpoList(highlightList);
}
@@ -515,13 +535,14 @@ void InputsPanel::exposDeleteList(QList list, bool clearName)
void InputsPanel::clearExpos()
{
- if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear all Inputs. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
+ if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear all Input lines. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
model->clearInputs();
for (int i = 0; i < inputsCount; i++) {
model->updateAllReferences(ModelData::REF_UPD_TYPE_INPUT, ModelData::REF_UPD_ACT_CLEAR, i);
}
- emit modified();
update();
+ updateItemModels();
+ emit modified();
}
}
@@ -559,30 +580,35 @@ bool InputsPanel::cmInputMoveUpAllowed() const
void InputsPanel::cmInputClear()
{
- if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear Input. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
+ if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear all lines for the selected Input. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
return;
for (int i = CPN_MAX_EXPOS - 1; i >= 0; i--) {
ExpoData *ed = &model->expoData[i];
- if ((int)ed->chn == inputIdx)
- model->removeInput(i);
+ if (!ed->isEmpty()) {
+ if ((int)ed->chn == inputIdx)
+ model->removeInput(i);
+ }
}
model->updateAllReferences(ModelData::REF_UPD_TYPE_INPUT, ModelData::REF_UPD_ACT_CLEAR, inputIdx);
update();
+ updateItemModels();
emit modified();
}
void InputsPanel::cmInputDelete()
{
- if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Delete Input. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
+ if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Delete all lines for the selected Input. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
return;
- for (int i = 0; i < CPN_MAX_EXPOS; i++) {
+ for (int i = CPN_MAX_EXPOS - 1; i >= 0; i--) {
ExpoData *ed = &model->expoData[i];
- if ((int)ed->chn == inputIdx)
- model->removeInput(i);
- else if ((int)ed->chn > inputIdx)
- ed->chn--;
+ if (!ed->isEmpty()) {
+ if ((int)ed->chn == inputIdx)
+ model->removeInput(i);
+ else if ((int)ed->chn > inputIdx)
+ ed->chn--;
+ }
}
for (int i = inputIdx; i < inputsCount; i++) {
@@ -592,6 +618,7 @@ void InputsPanel::cmInputDelete()
model->updateAllReferences(ModelData::REF_UPD_TYPE_INPUT, ModelData::REF_UPD_ACT_SHIFT, inputIdx, 0, -1);
update();
+ updateItemModels();
emit modified();
}
@@ -610,6 +637,7 @@ void InputsPanel::cmInputInsert()
model->updateAllReferences(ModelData::REF_UPD_TYPE_INPUT, ModelData::REF_UPD_ACT_SHIFT, inputIdx, 0, 1);
update();
+ updateItemModels();
emit modified();
}
@@ -671,6 +699,7 @@ void InputsPanel::cmInputSwapData(int idx1, int idx2)
model->updateAllReferences(ModelData::REF_UPD_TYPE_INPUT, ModelData::REF_UPD_ACT_SWAP, idx1, idx2);
update();
+ updateItemModels();
emit modified();
}
@@ -705,3 +734,32 @@ int InputsPanel::getInputIndexFromSelected()
}
return idx;
}
+
+void InputsPanel::connectItemModelEvents(const int id)
+{
+ AbstractDynamicItemModel * itemModel = qobject_cast(sharedItemModels->getItemModel(id));
+ if (itemModel) {
+ connect(itemModel, &AbstractDynamicItemModel::aboutToBeUpdated, this, &InputsPanel::onItemModelAboutToBeUpdated);
+ connect(itemModel, &AbstractDynamicItemModel::updateComplete, this, &InputsPanel::onItemModelUpdateComplete);
+ }
+}
+
+void InputsPanel::onItemModelAboutToBeUpdated()
+{
+ lock = true;
+ modelsUpdateCnt++;
+}
+
+void InputsPanel::onItemModelUpdateComplete()
+{
+ modelsUpdateCnt--;
+ if (modelsUpdateCnt < 1) {
+ update();
+ lock = false;
+ }
+}
+
+void InputsPanel::updateItemModels()
+{
+ sharedItemModels->update(AbstractItemModel::IMUE_Inputs);
+}
diff --git a/companion/src/modeledit/inputs.h b/companion/src/modeledit/inputs.h
index 884573fef..9b360ec19 100644
--- a/companion/src/modeledit/inputs.h
+++ b/companion/src/modeledit/inputs.h
@@ -25,6 +25,9 @@
#include "mixerslistwidget.h"
#include "modelprinter.h"
+class CompoundItemModelFactory;
+class FilteredItemModel;
+
constexpr char MIMETYPE_EXPO[] = "application/x-companion-expo";
class InputsPanel : public ModelPanel
@@ -32,7 +35,7 @@ class InputsPanel : public ModelPanel
Q_OBJECT
public:
- InputsPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware);
+ InputsPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CompoundItemModelFactory * sharedItemModels);
virtual ~InputsPanel();
virtual void update();
@@ -46,7 +49,7 @@ class InputsPanel : public ModelPanel
void expolistWidget_customContextMenuRequested(QPoint pos);
void expolistWidget_doubleClicked(QModelIndex index);
void expolistWidget_KeyPress(QKeyEvent *event);
- void exposDelete(bool ask=true);
+ void exposDelete(bool prompt = true);
void exposCut();
void exposCopy();
void exposPaste();
@@ -59,6 +62,8 @@ class InputsPanel : public ModelPanel
void cmInputInsert();
void cmInputMoveDown();
void cmInputMoveUp();
+ void onItemModelAboutToBeUpdated();
+ void onItemModelUpdateComplete();
private:
bool expoInserted;
@@ -67,6 +72,8 @@ class InputsPanel : public ModelPanel
ModelPrinter modelPrinter;
int selectedIdx;
int inputIdx;
+ CompoundItemModelFactory *sharedItemModels;
+ int modelsUpdateCnt;
int getExpoIndex(unsigned int dch);
bool gm_insertExpo(int idx);
@@ -87,6 +94,8 @@ class InputsPanel : public ModelPanel
bool isExpoIndex(const int index);
int getIndexFromSelected();
int getInputIndexFromSelected();
+ void updateItemModels();
+ void connectItemModelEvents(const int id);
};
#endif // _INPUTS_H_
diff --git a/companion/src/modeledit/logicalswitches.cpp b/companion/src/modeledit/logicalswitches.cpp
index 63a2ae22f..499df9e49 100644
--- a/companion/src/modeledit/logicalswitches.cpp
+++ b/companion/src/modeledit/logicalswitches.cpp
@@ -19,21 +19,25 @@
*/
#include "logicalswitches.h"
-#include "rawitemfilteredmodel.h"
+#include "filtereditemmodels.h"
#include "helpers.h"
#include
-LogicalSwitchesPanel::LogicalSwitchesPanel(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware):
+LogicalSwitchesPanel::LogicalSwitchesPanel(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware,
+ CompoundItemModelFactory * sharedItemModels):
ModelPanel(parent, model, generalSettings, firmware),
- selectedIndex(0)
+ sharedItemModels(sharedItemModels),
+ selectedIndex(0),
+ modelsUpdateCnt(0)
{
- Stopwatch s1("LogicalSwitchesPanel");
-
- rawSwitchItemModel = new RawSwitchFilterItemModel(&generalSettings, &model, RawSwitch::LogicalSwitchesContext, this);
+ rawSwitchFilteredModel = new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_RawSwitch),
+ RawSwitch::LogicalSwitchesContext);
+ connectItemModelEvents(rawSwitchFilteredModel);
const int srcGroups = firmware->getCapability(GvarsInCS) ? 0 : (RawSource::AllSourceGroups & ~RawSource::GVarsGroup);
- rawSourceItemModel = new RawSourceFilterItemModel(&generalSettings, &model, srcGroups, this);
+ rawSourceFilteredModel = new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_RawSource), srcGroups);
+ connectItemModelEvents(rawSourceFilteredModel);
lsCapability = firmware->getCapability(LogicalSwitches);
lsCapabilityExt = firmware->getCapability(LogicalSwitchesExt);
@@ -45,16 +49,13 @@ LogicalSwitchesPanel::LogicalSwitchesPanel(QWidget * parent, ModelData & model,
}
TableLayout * tableLayout = new TableLayout(this, lsCapability, headerLabels);
- s1.report("header");
-
const int channelsMax = model.getChannelsMax(true);
- lock = true;
- for (int i=0; isetProperty("index", i);
- label->setText(RawSwitch(SWITCH_TYPE_VIRTUAL, i+1).toString());
+ label->setText(RawSwitch(SWITCH_TYPE_VIRTUAL, i + 1).toString());
label->setContextMenuPolicy(Qt::CustomContextMenu);
label->setToolTip(tr("Popup menu available"));
label->setMouseTracking(true);
@@ -123,7 +124,8 @@ LogicalSwitchesPanel::LogicalSwitchesPanel(QWidget * parent, ModelData & model,
// AND
cbAndSwitch[i] = new QComboBox(this);
cbAndSwitch[i]->setProperty("index", i);
- populateAndSwitchCB(cbAndSwitch[i]);
+ cbAndSwitch[i]->setModel(rawSwitchFilteredModel);
+ cbAndSwitch[i]->setVisible(true);
connect(cbAndSwitch[i], SIGNAL(currentIndexChanged(int)), this, SLOT(onAndSwitchChanged(int)));
tableLayout->addWidget(i, 4, cbAndSwitch[i]);
@@ -152,72 +154,65 @@ LogicalSwitchesPanel::LogicalSwitchesPanel(QWidget * parent, ModelData & model,
}
}
- s1.report("added elements");
-
disableMouseScrolling();
- lock = false;
- update();
tableLayout->resizeColumnsToContents();
tableLayout->pushRowsUp(lsCapability+1);
- s1.report("end");
}
LogicalSwitchesPanel::~LogicalSwitchesPanel()
{
-}
-
-void LogicalSwitchesPanel::updateDataModels()
-{
- const bool oldLock = lock;
- lock = true;
- rawSwitchItemModel->update();
- rawSourceItemModel->update();
- lock = oldLock;
+ delete rawSourceFilteredModel;
+ delete rawSwitchFilteredModel;
}
void LogicalSwitchesPanel::onFunctionChanged()
{
- int i = sender()->property("index").toInt();
- unsigned newFunc = cbFunction[i]->currentData().toUInt();
+ if (!lock) {
+ int i = sender()->property("index").toInt();
+ unsigned newFunc = cbFunction[i]->currentData().toUInt();
- if (model->logicalSw[i].func == newFunc)
- return;
+ if (model->logicalSw[i].func == newFunc)
+ return;
- const unsigned oldFunc = model->logicalSw[i].func;
- CSFunctionFamily oldFuncFamily = model->logicalSw[i].getFunctionFamily();
- model->logicalSw[i].func = newFunc;
- CSFunctionFamily newFuncFamily = model->logicalSw[i].getFunctionFamily();
-
- if (oldFuncFamily != newFuncFamily) {
- model->logicalSw[i].clear();
+ unsigned oldFunc = model->logicalSw[i].func;
+ CSFunctionFamily oldFuncFamily = model->logicalSw[i].getFunctionFamily();
model->logicalSw[i].func = newFunc;
- if (newFuncFamily == LS_FAMILY_TIMER) {
- model->logicalSw[i].val1 = -119;
- model->logicalSw[i].val2 = -119;
+ CSFunctionFamily newFuncFamily = model->logicalSw[i].getFunctionFamily();
+
+ if (oldFuncFamily != newFuncFamily || newFunc == LS_FN_OFF) {
+ model->logicalSw[i].clear();
+ model->logicalSw[i].func = newFunc;
+ if (newFuncFamily == LS_FAMILY_TIMER) {
+ model->logicalSw[i].val1 = -119;
+ model->logicalSw[i].val2 = -119;
+ }
+ else if (newFuncFamily == LS_FAMILY_EDGE) {
+ model->logicalSw[i].val2 = -129;
+ }
}
- else if (newFuncFamily == LS_FAMILY_EDGE) {
- model->logicalSw[i].val2 = -129;
- }
- }
- if (bool(oldFunc) != bool(newFunc))
- update();
- else
+
updateLine(i);
- emit modified();
+ if (oldFunc == LS_FN_OFF || newFunc == LS_FN_OFF)
+ updateItemModels();
+
+ emit modified();
+ }
}
void LogicalSwitchesPanel::onV1Changed(int value)
{
if (!lock) {
int i = sender()->property("index").toInt();
- model->logicalSw[i].val1 = cbSource1[i]->itemData(value).toInt();
- if (model->logicalSw[i].getFunctionFamily() == LS_FAMILY_VOFS) {
- if (!offsetChangedAt(i))
- updateLine(i);
- }
- else {
- emit modified();
+ if (model->logicalSw[i].val1 != cbSource1[i]->itemData(value).toInt()) {
+ model->logicalSw[i].val1 = cbSource1[i]->itemData(value).toInt();
+ if (model->logicalSw[i].getFunctionFamily() == LS_FAMILY_VOFS) {
+ if (!offsetChangedAt(i))
+ updateLine(i);
+ }
+ else {
+ emit modified();
+ }
}
}
}
@@ -226,8 +221,10 @@ void LogicalSwitchesPanel::onV2Changed(int value)
{
if (!lock) {
int i = sender()->property("index").toInt();
- model->logicalSw[i].val2 = cbSource2[i]->itemData(value).toInt();
- emit modified();
+ if (model->logicalSw[i].val2 != cbSource2[i]->itemData(value).toInt()) {
+ model->logicalSw[i].val2 = cbSource2[i]->itemData(value).toInt();
+ emit modified();
+ }
}
}
@@ -235,8 +232,10 @@ void LogicalSwitchesPanel::onAndSwitchChanged(int value)
{
if (!lock) {
int index = sender()->property("index").toInt();
- model->logicalSw[index].andsw = cbAndSwitch[index]->itemData(value).toInt();
- emit modified();
+ if (model->logicalSw[index].andsw != cbAndSwitch[index]->itemData(value).toInt()) {
+ model->logicalSw[index].andsw = cbAndSwitch[index]->itemData(value).toInt();
+ emit modified();
+ }
}
}
@@ -244,7 +243,7 @@ void LogicalSwitchesPanel::onDurationChanged(double duration)
{
if (!lock) {
int index = sender()->property("index").toInt();
- model->logicalSw[index].duration = (uint8_t)round(duration*10);
+ model->logicalSw[index].duration = (uint8_t)round(duration * 10);
emit modified();
}
}
@@ -253,7 +252,7 @@ void LogicalSwitchesPanel::onDelayChanged(double delay)
{
if (!lock) {
int index = sender()->property("index").toInt();
- model->logicalSw[index].delay = (uint8_t)round(delay*10);
+ model->logicalSw[index].delay = (uint8_t)round(delay * 10);
emit modified();
}
}
@@ -326,9 +325,9 @@ void LogicalSwitchesPanel::updateTimerParam(QDoubleSpinBox *sb, int timer, doubl
sb->setMinimum(minimum);
sb->setMaximum(175);
float value = ValToTim(timer);
- if (value>=60)
+ if (value >= 60)
sb->setSingleStep(1);
- else if (value>=2)
+ else if (value >= 2)
sb->setSingleStep(0.5);
else
sb->setSingleStep(0.1);
@@ -347,16 +346,14 @@ void LogicalSwitchesPanel::updateTimerParam(QDoubleSpinBox *sb, int timer, doubl
void LogicalSwitchesPanel::updateLine(int i)
{
+ const bool savelock = lock;
lock = true;
- unsigned int mask;
+ unsigned int mask = 0;
cbFunction[i]->setCurrentIndex(cbFunction[i]->findData(model->logicalSw[i].func));
cbAndSwitch[i]->setCurrentIndex(cbAndSwitch[i]->findData(RawSwitch(model->logicalSw[i].andsw).toValue()));
- if (!model->logicalSw[i].func) {
- mask = 0;
- }
- else {
+ if (!model->logicalSw[i].isEmpty()) {
mask = LINE_ENABLED | DELAY_ENABLED | DURATION_ENABLED;
switch (model->logicalSw[i].getFunctionFamily())
@@ -367,7 +364,7 @@ void LogicalSwitchesPanel::updateLine(int i)
RawSource source = RawSource(model->logicalSw[i].val1);
RawSourceRange range = source.getRange(model, generalSettings, model->logicalSw[i].getRangeFlags());
double value = range.step * model->logicalSw[i].val2 + range.offset; /* TODO+source.getRawOffset(model)*/
- cbSource1[i]->setModel(rawSourceItemModel);
+ cbSource1[i]->setModel(rawSourceFilteredModel);
cbSource1[i]->setCurrentIndex(cbSource1[i]->findData(source.toValue()));
if (source.isTimeBased()) {
mask |= VALUE_TO_VISIBLE;
@@ -396,27 +393,27 @@ void LogicalSwitchesPanel::updateLine(int i)
case LS_FAMILY_STICKY: // no break
case LS_FAMILY_VBOOL:
mask |= SOURCE1_VISIBLE | SOURCE2_VISIBLE;
- cbSource1[i]->setModel(rawSwitchItemModel);
+ cbSource1[i]->setModel(rawSwitchFilteredModel);
cbSource1[i]->setCurrentIndex(cbSource1[i]->findData(model->logicalSw[i].val1));
- cbSource2[i]->setModel(rawSwitchItemModel);
+ cbSource2[i]->setModel(rawSwitchFilteredModel);
cbSource2[i]->setCurrentIndex(cbSource2[i]->findData(model->logicalSw[i].val2));
break;
case LS_FAMILY_EDGE:
mask |= SOURCE1_VISIBLE | VALUE2_VISIBLE | VALUE3_VISIBLE;
mask &= ~DELAY_ENABLED;
- cbSource1[i]->setModel(rawSwitchItemModel);
+ cbSource1[i]->setModel(rawSwitchFilteredModel);
cbSource1[i]->setCurrentIndex(cbSource1[i]->findData(model->logicalSw[i].val1));
updateTimerParam(dsbOffset[i], model->logicalSw[i].val2, 0.0);
- updateTimerParam(dsbOffset2[i], model->logicalSw[i].val2+model->logicalSw[i].val3, ValToTim(TimToVal(dsbOffset[i]->value())-1));
+ updateTimerParam(dsbOffset2[i], model->logicalSw[i].val2 + model->logicalSw[i].val3, ValToTim(TimToVal(dsbOffset[i]->value()) - 1));
dsbOffset2[i]->setSuffix((model->logicalSw[i].val3) ? "" : tr(" (infinite)"));
break;
case LS_FAMILY_VCOMP:
mask |= SOURCE1_VISIBLE | SOURCE2_VISIBLE;
- cbSource1[i]->setModel(rawSourceItemModel);
+ cbSource1[i]->setModel(rawSourceFilteredModel);
cbSource1[i]->setCurrentIndex(cbSource1[i]->findData(model->logicalSw[i].val1));
- cbSource2[i]->setModel(rawSourceItemModel);
+ cbSource2[i]->setModel(rawSourceFilteredModel);
cbSource2[i]->setCurrentIndex(cbSource2[i]->findData(model->logicalSw[i].val2));
break;
@@ -439,12 +436,12 @@ void LogicalSwitchesPanel::updateLine(int i)
dsbDuration[i]->setVisible(mask & DURATION_ENABLED);
dsbDelay[i]->setVisible(mask & DELAY_ENABLED);
if (mask & DURATION_ENABLED)
- dsbDuration[i]->setValue(model->logicalSw[i].duration/10.0);
+ dsbDuration[i]->setValue(model->logicalSw[i].duration / 10.0);
if (mask & DELAY_ENABLED)
- dsbDelay[i]->setValue(model->logicalSw[i].delay/10.0);
+ dsbDelay[i]->setValue(model->logicalSw[i].delay / 10.0);
}
- lock = false;
+ lock = savelock;
}
void LogicalSwitchesPanel::populateFunctionCB(QComboBox *b)
@@ -475,7 +472,7 @@ void LogicalSwitchesPanel::populateFunctionCB(QComboBox *b)
};
b->clear();
- for (int i=0; isetMaxVisibleItems(10);
}
-void LogicalSwitchesPanel::populateAndSwitchCB(QComboBox *b)
-{
- b->setModel(rawSwitchItemModel);
- b->setVisible(true);
-}
-
void LogicalSwitchesPanel::update()
{
- updateDataModels();
- for (int i=0; ilogicalSw[selectedIndex], data.constData(), sizeof(LogicalSwitchData));
- updateDataModels();
updateLine(selectedIndex);
+ updateItemModels();
emit modified();
}
}
@@ -519,6 +509,7 @@ void LogicalSwitchesPanel::cmDelete()
model->updateAllReferences(ModelData::REF_UPD_TYPE_LOGICAL_SWITCH, ModelData::REF_UPD_ACT_SHIFT, selectedIndex, 0, -1);
update();
+ updateItemModels();
emit modified();
}
@@ -528,16 +519,17 @@ void LogicalSwitchesPanel::cmCopy()
data.append((char*)&model->logicalSw[selectedIndex], sizeof(LogicalSwitchData));
QMimeData *mimeData = new QMimeData;
mimeData->setData(MIMETYPE_LOGICAL_SWITCH, data);
- QApplication::clipboard()->setMimeData(mimeData,QClipboard::Clipboard);
+ QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard);
}
void LogicalSwitchesPanel::cmCut()
{
+ if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Cut Logical Switch. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
+ return;
cmCopy();
- cmClear();
+ cmClear(false);
}
-// TODO make something generic here!
void LogicalSwitchesPanel::onCustomContextMenuRequested(QPoint pos)
{
QLabel *label = (QLabel *)sender();
@@ -597,11 +589,17 @@ void LogicalSwitchesPanel::cmMoveDown()
swapData(selectedIndex, selectedIndex + 1);
}
-void LogicalSwitchesPanel::cmClear()
+void LogicalSwitchesPanel::cmClear(bool prompt)
{
+ if (prompt) {
+ if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear Logical Switch. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
+ return;
+ }
+
model->logicalSw[selectedIndex].clear();
model->updateAllReferences(ModelData::REF_UPD_TYPE_LOGICAL_SWITCH, ModelData::REF_UPD_ACT_CLEAR, selectedIndex);
- update();
+ updateLine(selectedIndex);
+ updateItemModels();
emit modified();
}
@@ -610,11 +608,12 @@ void LogicalSwitchesPanel::cmClearAll()
if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear all Logical Switches. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
return;
- for (int i=0; ilogicalSw[i].clear();
model->updateAllReferences(ModelData::REF_UPD_TYPE_LOGICAL_SWITCH, ModelData::REF_UPD_ACT_CLEAR, i);
}
update();
+ updateItemModels();
emit modified();
}
@@ -624,6 +623,7 @@ void LogicalSwitchesPanel::cmInsert()
model->logicalSw[selectedIndex].clear();
model->updateAllReferences(ModelData::REF_UPD_TYPE_LOGICAL_SWITCH, ModelData::REF_UPD_ACT_SHIFT, selectedIndex, 0, 1);
update();
+ updateItemModels();
emit modified();
}
@@ -636,7 +636,36 @@ void LogicalSwitchesPanel::swapData(int idx1, int idx2)
memcpy(lsw2, lsw1, sizeof(LogicalSwitchData));
memcpy(lsw1, &lstmp, sizeof(LogicalSwitchData));
model->updateAllReferences(ModelData::REF_UPD_TYPE_LOGICAL_SWITCH, ModelData::REF_UPD_ACT_SWAP, idx1, idx2);
- update();
+ updateLine(idx1);
+ updateLine(idx2);
+ updateItemModels();
emit modified();
}
}
+
+void LogicalSwitchesPanel::updateItemModels()
+{
+ lock = true;
+ sharedItemModels->update(AbstractItemModel::IMUE_LogicalSwitches);
+}
+
+void LogicalSwitchesPanel::connectItemModelEvents(const FilteredItemModel * itemModel)
+{
+ connect(itemModel, &FilteredItemModel::aboutToBeUpdated, this, &LogicalSwitchesPanel::onItemModelAboutToBeUpdated);
+ connect(itemModel, &FilteredItemModel::updateComplete, this, &LogicalSwitchesPanel::onItemModelUpdateComplete);
+}
+
+void LogicalSwitchesPanel::onItemModelAboutToBeUpdated()
+{
+ lock = true;
+ modelsUpdateCnt++;
+}
+
+void LogicalSwitchesPanel::onItemModelUpdateComplete()
+{
+ modelsUpdateCnt--;
+ if (modelsUpdateCnt < 1) {
+ update();
+ lock = false;
+ }
+}
diff --git a/companion/src/modeledit/logicalswitches.h b/companion/src/modeledit/logicalswitches.h
index 2aea300c5..f1c2f8397 100644
--- a/companion/src/modeledit/logicalswitches.h
+++ b/companion/src/modeledit/logicalswitches.h
@@ -24,8 +24,8 @@
#include "modeledit.h"
#include "radiodata.h"
-class RawSwitchFilterItemModel;
-class RawSourceFilterItemModel;
+class CompoundItemModelFactory;
+class FilteredItemModel;
class TimerEdit;
constexpr char MIMETYPE_LOGICAL_SWITCH[] = "application/x-companion-logical-switch";
@@ -35,13 +35,12 @@ class LogicalSwitchesPanel : public ModelPanel
Q_OBJECT
public:
- LogicalSwitchesPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware);
+ LogicalSwitchesPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CompoundItemModelFactory * sharedItemModels);
virtual ~LogicalSwitchesPanel();
virtual void update();
private slots:
- void updateDataModels();
void onFunctionChanged();
void onV1Changed(int value);
void onV2Changed(int value);
@@ -59,8 +58,10 @@ class LogicalSwitchesPanel : public ModelPanel
void cmMoveUp();
void cmMoveDown();
void cmInsert();
- void cmClear();
+ void cmClear(bool prompt = true);
void cmClearAll();
+ void onItemModelAboutToBeUpdated();
+ void onItemModelUpdateComplete();
private:
QComboBox * cbFunction[CPN_MAX_LOGICAL_SWITCHES];
@@ -73,11 +74,11 @@ class LogicalSwitchesPanel : public ModelPanel
QDoubleSpinBox * dsbDelay[CPN_MAX_LOGICAL_SWITCHES];
QComboBox * cbSource1[CPN_MAX_LOGICAL_SWITCHES];
QComboBox * cbSource2[CPN_MAX_LOGICAL_SWITCHES];
- RawSwitchFilterItemModel * rawSwitchItemModel;
- RawSourceFilterItemModel * rawSourceItemModel;
+ CompoundItemModelFactory * sharedItemModels;
+ FilteredItemModel * rawSwitchFilteredModel;
+ FilteredItemModel * rawSourceFilteredModel;
int selectedIndex;
void populateFunctionCB(QComboBox *b);
- void populateAndSwitchCB(QComboBox *b);
void updateTimerParam(QDoubleSpinBox *sb, int timer, double minimum=0);
int lsCapability;
int lsCapabilityExt;
@@ -86,6 +87,9 @@ class LogicalSwitchesPanel : public ModelPanel
bool insertAllowed() const;
bool moveDownAllowed() const;
bool moveUpAllowed() const;
+ int modelsUpdateCnt;
+ void updateItemModels();
+ void connectItemModelEvents(const FilteredItemModel * itemModel);
};
#endif // _LOGICALSWITCHES_H_
diff --git a/companion/src/modeledit/mixerdialog.cpp b/companion/src/modeledit/mixerdialog.cpp
index 1b17e9471..6cc39ffd1 100644
--- a/companion/src/modeledit/mixerdialog.cpp
+++ b/companion/src/modeledit/mixerdialog.cpp
@@ -21,10 +21,11 @@
#include "mixerdialog.h"
#include "ui_mixerdialog.h"
#include "radiodata.h"
-#include "rawitemfilteredmodel.h"
+#include "filtereditemmodels.h"
#include "helpers.h"
-MixerDialog::MixerDialog(QWidget *parent, ModelData & model, MixData * mixdata, GeneralSettings & generalSettings, Firmware * firmware) :
+MixerDialog::MixerDialog(QWidget *parent, ModelData & model, MixData * mixdata, GeneralSettings & generalSettings, Firmware * firmware,
+ CompoundItemModelFactory * sharedItemModels) :
QDialog(parent),
ui(new Ui::MixerDialog),
model(model),
@@ -34,25 +35,37 @@ MixerDialog::MixerDialog(QWidget *parent, ModelData & model, MixData * mixdata,
lock(false)
{
ui->setupUi(this);
+
+ dialogFilteredItemModels = new FilteredItemModelFactory();
+ int id;
+
QRegExp rx(CHAR_FOR_NAMES_REGEX);
- QLabel * lb_fp[CPN_MAX_FLIGHT_MODES] = {ui->lb_FP0,ui->lb_FP1,ui->lb_FP2,ui->lb_FP3,ui->lb_FP4,ui->lb_FP5,ui->lb_FP6,ui->lb_FP7,ui->lb_FP8 };
- QCheckBox * tmp[CPN_MAX_FLIGHT_MODES] = {ui->cb_FP0,ui->cb_FP1,ui->cb_FP2,ui->cb_FP3,ui->cb_FP4,ui->cb_FP5,ui->cb_FP6,ui->cb_FP7,ui->cb_FP8 };
- for (int i=0; ilb_FP0, ui->lb_FP1, ui->lb_FP2, ui->lb_FP3, ui->lb_FP4, ui->lb_FP5, ui->lb_FP6, ui->lb_FP7, ui->lb_FP8 };
+ QCheckBox * tmp[CPN_MAX_FLIGHT_MODES] = {ui->cb_FP0, ui->cb_FP1, ui->cb_FP2, ui->cb_FP3, ui->cb_FP4, ui->cb_FP5, ui->cb_FP6, ui->cb_FP7, ui->cb_FP8 };
+ for (int i = 0; i < CPN_MAX_FLIGHT_MODES; i++) {
cb_fp[i] = tmp[i];
}
- this->setWindowTitle(tr("DEST -> %1").arg(RawSource(SOURCE_TYPE_CH, md->destCh-1).toString(&model, &generalSettings)));
+ this->setWindowTitle(tr("DEST -> %1").arg(RawSource(SOURCE_TYPE_CH, md->destCh - 1).toString(&model, &generalSettings)));
- ui->sourceCB->setModel(new RawSourceFilterItemModel(&generalSettings, &model, RawSource::InputSourceGroups | RawSource::ScriptsGroup, this));
+ id = dialogFilteredItemModels->registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_RawSource),
+ (RawSource::InputSourceGroups & ~RawSource::NoneGroup) | RawSource::ScriptsGroup),
+ "RawSource");
+ ui->sourceCB->setModel(dialogFilteredItemModels->getItemModel(id));
ui->sourceCB->setCurrentIndex(ui->sourceCB->findData(md->srcRaw.toValue()));
- ui->sourceCB->removeItem(0);
int limit = firmware->getCapability(OffsetWeight);
+ id = dialogFilteredItemModels->registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_GVarRef)), "GVarRef");
- gvWeightGroup = new GVarGroup(ui->weightGV, ui->weightSB, ui->weightCB, md->weight, model, 100, -limit, limit);
- gvOffsetGroup = new GVarGroup(ui->offsetGV, ui->offsetSB, ui->offsetCB, md->sOffset, model, 0, -limit, limit);
- curveGroup = new CurveGroup(ui->curveTypeCB, ui->curveGVarCB, ui->curveValueCB, ui->curveValueSB,
- md->curve, model, firmware->getCapability(HasMixerExpo) ? 0 : HIDE_EXPO);
+ gvWeightGroup = new GVarGroup(ui->weightGV, ui->weightSB, ui->weightCB, md->weight, model, 100, -limit, limit, 1.0,
+ dialogFilteredItemModels->getItemModel(id));
+ gvOffsetGroup = new GVarGroup(ui->offsetGV, ui->offsetSB, ui->offsetCB, md->sOffset, model, 0, -limit, limit, 1.0,
+ dialogFilteredItemModels->getItemModel(id));
+
+ curveRefFilteredItemModels = new CurveRefFilteredFactory(sharedItemModels,
+ firmware->getCapability(HasMixerExpo) ? 0 : FilteredItemModel::PositiveFilter);
+ curveGroup = new CurveReferenceUIManager(ui->curveTypeCB, ui->curveGVarCB, ui->curveValueSB, ui->curveValueCB, md->curve, model,
+ curveRefFilteredItemModels, this);
ui->MixDR_CB->setChecked(md->noExpo == 0);
@@ -62,7 +75,7 @@ MixerDialog::MixerDialog(QWidget *parent, ModelData & model, MixData * mixdata,
}
if (!firmware->getCapability(VirtualInputs)) {
- for(int i=0; i < CPN_MAX_STICKS; i++) {
+ for(int i = 0; i < CPN_MAX_STICKS; i++) {
ui->trimCB->addItem(firmware->getAnalogInputName(i));
}
}
@@ -82,7 +95,7 @@ MixerDialog::MixerDialog(QWidget *parent, ModelData & model, MixData * mixdata,
if (!firmware->getCapability(FlightModes)) {
ui->label_phases->hide();
- for (int i=0; ihide();
cb_fp[i]->hide();
}
@@ -92,40 +105,42 @@ MixerDialog::MixerDialog(QWidget *parent, ModelData & model, MixData * mixdata,
ui->label_phases->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->label_phases, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(label_phases_customContextMenuRequested(const QPoint &)));
int mask = 1;
- for (int i=0; iflightModes & mask) == 0) {
cb_fp[i]->setChecked(true);
}
mask <<= 1;
}
- for (int i=firmware->getCapability(FlightModes); igetCapability(FlightModes); i < CPN_MAX_FLIGHT_MODES; i++) {
lb_fp[i]->hide();
cb_fp[i]->hide();
}
}
- ui->switchesCB->setModel(new RawSwitchFilterItemModel(&generalSettings, &model, RawSwitch::MixesContext, this));
+ id = dialogFilteredItemModels->registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_RawSwitch),
+ RawSwitch::MixesContext), "RawSwitch");
+ ui->switchesCB->setModel(dialogFilteredItemModels->getItemModel(id));
ui->switchesCB->setCurrentIndex(ui->switchesCB->findData(md->swtch.toValue()));
ui->warningCB->setCurrentIndex(md->mixWarn);
ui->mltpxCB->setCurrentIndex(md->mltpx);
int scale=firmware->getCapability(SlowScale);
float range=firmware->getCapability(SlowRange);
- ui->slowDownSB->setMaximum(range/scale);
- ui->slowDownSB->setSingleStep(1.0/scale);
- ui->slowDownSB->setDecimals((scale==1 ? 0 :1));
+ ui->slowDownSB->setMaximum(range / scale);
+ ui->slowDownSB->setSingleStep(1.0 / scale);
+ ui->slowDownSB->setDecimals((scale == 1 ? 0 : 1));
ui->slowDownSB->setValue((float)md->speedDown/scale);
- ui->slowUpSB->setMaximum(range/scale);
- ui->slowUpSB->setSingleStep(1.0/scale);
- ui->slowUpSB->setDecimals((scale==1 ? 0 :1));
+ ui->slowUpSB->setMaximum(range / scale);
+ ui->slowUpSB->setSingleStep(1.0 / scale);
+ ui->slowUpSB->setDecimals((scale == 1 ? 0 : 1));
ui->slowUpSB->setValue((float)md->speedUp/scale);
- ui->delayDownSB->setMaximum(range/scale);
- ui->delayDownSB->setSingleStep(1.0/scale);
- ui->delayDownSB->setDecimals((scale==1 ? 0 :1));
- ui->delayDownSB->setValue((float)md->delayDown/scale);
- ui->delayUpSB->setMaximum(range/scale);
- ui->delayUpSB->setSingleStep(1.0/scale);
- ui->delayUpSB->setDecimals((scale==1 ? 0 :1));
- ui->delayUpSB->setValue((float)md->delayUp/scale);
+ ui->delayDownSB->setMaximum(range / scale);
+ ui->delayDownSB->setSingleStep(1.0 / scale);
+ ui->delayDownSB->setDecimals((scale == 1 ? 0 : 1));
+ ui->delayDownSB->setValue((float)md->delayDown / scale);
+ ui->delayUpSB->setMaximum(range / scale);
+ ui->delayUpSB->setSingleStep(1.0 / scale);
+ ui->delayUpSB->setDecimals((scale == 1 ? 0 : 1));
+ ui->delayUpSB->setValue((float)md->delayUp / scale);
QTimer::singleShot(0, this, SLOT(shrink()));
valuesChanged();
@@ -147,10 +162,10 @@ MixerDialog::MixerDialog(QWidget *parent, ModelData & model, MixData * mixdata,
MixerDialog::~MixerDialog()
{
+ delete ui;
delete gvWeightGroup;
delete gvOffsetGroup;
- delete curveGroup;
- delete ui;
+ delete dialogFilteredItemModels;
}
void MixerDialog::changeEvent(QEvent *e)
@@ -176,20 +191,20 @@ void MixerDialog::valuesChanged()
ui->MixDR_CB->setEnabled(drVisible);
ui->label_MixDR->setEnabled(drVisible);
}
- md->carryTrim = -(ui->trimCB->currentIndex()-1);
+ md->carryTrim = -(ui->trimCB->currentIndex() - 1);
md->noExpo = ui->MixDR_CB->checkState() ? 0 : 1;
md->swtch = RawSwitch(ui->switchesCB->itemData(ui->switchesCB->currentIndex()).toInt());
md->mixWarn = ui->warningCB->currentIndex();
md->mltpx = (MltpxValue)ui->mltpxCB->currentIndex();
int scale = firmware->getCapability(SlowScale);
- md->delayDown = round(ui->delayDownSB->value()*scale);
- md->delayUp = round(ui->delayUpSB->value()*scale);
- md->speedDown = round(ui->slowDownSB->value()*scale);
- md->speedUp = round(ui->slowUpSB->value()*scale);
+ md->delayDown = round(ui->delayDownSB->value() * scale);
+ md->delayUp = round(ui->delayUpSB->value() * scale);
+ md->speedDown = round(ui->slowDownSB->value() * scale);
+ md->speedUp = round(ui->slowUpSB->value() * scale);
strcpy(md->name, ui->mixerName->text().toLatin1());
md->flightModes = 0;
- for (int i=CPN_MAX_FLIGHT_MODES-1; i>=0 ; i--) {
+ for (int i = CPN_MAX_FLIGHT_MODES - 1; i >= 0 ; i--) {
if (!cb_fp[i]->checkState()) {
md->flightModes++;
}
@@ -220,7 +235,7 @@ void MixerDialog::label_phases_customContextMenuRequested(const QPoint & pos)
void MixerDialog::fmClearAll()
{
lock = true;
- for (int i=0; isetChecked(false);
}
lock = false;
@@ -230,7 +245,7 @@ void MixerDialog::fmClearAll()
void MixerDialog::fmSetAll()
{
lock = true;
- for (int i=0; isetChecked(true);
}
lock = false;
@@ -240,7 +255,7 @@ void MixerDialog::fmSetAll()
void MixerDialog::fmInvertAll()
{
lock = true;
- for (int i=0; isetChecked(!cb_fp[i]->isChecked());
}
lock = false;
diff --git a/companion/src/modeledit/mixerdialog.h b/companion/src/modeledit/mixerdialog.h
index 93f061d0d..04ff1aeaf 100644
--- a/companion/src/modeledit/mixerdialog.h
+++ b/companion/src/modeledit/mixerdialog.h
@@ -25,7 +25,10 @@
#include "eeprominterface.h"
class GVarGroup;
-class CurveGroup;
+class CompoundItemModelFactory;
+class FilteredItemModelFactory;
+class CurveRefFilteredFactory;
+class CurveReferenceUIManager;
namespace Ui {
class MixerDialog;
@@ -34,7 +37,8 @@ namespace Ui {
class MixerDialog : public QDialog {
Q_OBJECT
public:
- MixerDialog(QWidget *parent, ModelData & model, MixData *mixdata, GeneralSettings & generalSettings, Firmware * firmware);
+ MixerDialog(QWidget *parent, ModelData & model, MixData *mixdata, GeneralSettings & generalSettings, Firmware * firmware,
+ CompoundItemModelFactory * sharedItemModels);
~MixerDialog();
protected:
@@ -57,8 +61,10 @@ class MixerDialog : public QDialog {
bool lock;
GVarGroup * gvWeightGroup;
GVarGroup * gvOffsetGroup;
- CurveGroup * curveGroup;
+ CurveReferenceUIManager * curveGroup;
QCheckBox * cb_fp[CPN_MAX_FLIGHT_MODES];
+ FilteredItemModelFactory *dialogFilteredItemModels;
+ CurveRefFilteredFactory *curveRefFilteredItemModels;
};
#endif // _MIXERDIALOG_H_
diff --git a/companion/src/modeledit/mixes.cpp b/companion/src/modeledit/mixes.cpp
index c92105ec6..023888760 100644
--- a/companion/src/modeledit/mixes.cpp
+++ b/companion/src/modeledit/mixes.cpp
@@ -20,13 +20,21 @@
#include "mixes.h"
#include "helpers.h"
+#include "filtereditemmodels.h"
-MixesPanel::MixesPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware):
+MixesPanel::MixesPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CompoundItemModelFactory * sharedItemModels):
ModelPanel(parent, model, generalSettings, firmware),
mixInserted(false),
highlightedSource(0),
- modelPrinter(firmware, generalSettings, model)
+ modelPrinter(firmware, generalSettings, model),
+ sharedItemModels(sharedItemModels),
+ modelsUpdateCnt(0)
{
+ connectItemModelEvents(AbstractItemModel::IMID_RawSource);
+ connectItemModelEvents(AbstractItemModel::IMID_RawSwitch);
+ connectItemModelEvents(AbstractItemModel::IMID_Curve);
+ connectItemModelEvents(AbstractItemModel::IMID_GVarRef);
+
QGridLayout * mixesLayout = new QGridLayout(this);
mixersListWidget = new MixersListWidget(this, false); // TODO enum
@@ -175,8 +183,8 @@ void MixesPanel::gm_openMix(int index)
MixData mixd(model->mixData[index]);
- MixerDialog *g = new MixerDialog(this, *model, &mixd, generalSettings, firmware);
- if(g->exec()) {
+ MixerDialog *dlg = new MixerDialog(this, *model, &mixd, generalSettings, firmware, sharedItemModels);
+ if(dlg->exec()) {
model->mixData[index] = mixd;
emit modified();
update();
@@ -188,6 +196,7 @@ void MixesPanel::gm_openMix(int index)
mixInserted = false;
update();
}
+ delete dlg;
}
int MixesPanel::getMixerIndex(unsigned int dch)
@@ -253,28 +262,27 @@ void MixesPanel::setSelectedByMixList(QList list)
}
-void MixesPanel::mixersDelete(bool ask)
+void MixesPanel::mixersDelete(bool prompt)
{
QList list = createMixListFromSelected();
- if(list.isEmpty()) return;
+ if(list.isEmpty())
+ return;
- QMessageBox::StandardButton ret = QMessageBox::No;
-
- if(ask) {
- ret = QMessageBox::warning(this, "companion",
- tr("Delete Selected Mixes?"),
- QMessageBox::Yes | QMessageBox::No);
+ if (prompt) {
+ if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Delete selected Mix lines. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
+ return;
}
- if ((ret == QMessageBox::Yes) || (!ask)) {
- mixersDeleteList(list);
- emit modified();
- update();
- }
+ mixersDeleteList(list);
+ emit modified();
+ update();
}
void MixesPanel::mixersCut()
{
+ if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Cut selected Mix lines. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
+ return;
+
mixersCopy();
mixersDelete(false);
}
@@ -346,7 +354,11 @@ void MixesPanel::mixersDuplicate()
void MixesPanel::mixerOpen()
{
- int idx = mixersListWidget->currentItem()->data(Qt::UserRole).toByteArray().at(0);
+ QListWidgetItem *item = mixersListWidget->currentItem();
+ if (item == nullptr)
+ return;
+
+ int idx = item->data(Qt::UserRole).toByteArray().at(0);
if(idx < 0) {
int i = -idx;
idx = getMixerIndex(i); //get mixer index to insert
@@ -363,7 +375,11 @@ void MixesPanel::mixerOpen()
void MixesPanel::mixerHighlight()
{
- int idx = mixersListWidget->currentItem()->data(Qt::UserRole).toByteArray().at(0);
+ QListWidgetItem *item = mixersListWidget->currentItem();
+ if (item == nullptr)
+ return;
+
+ int idx = item->data(Qt::UserRole).toByteArray().at(0);
int dest;
if (idx<0) {
dest = -idx;
@@ -530,3 +546,27 @@ void MixesPanel::clearMixes()
update();
}
}
+
+void MixesPanel::connectItemModelEvents(const int id)
+{
+ AbstractDynamicItemModel * itemModel = qobject_cast(sharedItemModels->getItemModel(id));
+ if (itemModel) {
+ connect(itemModel, &AbstractDynamicItemModel::aboutToBeUpdated, this, &MixesPanel::onItemModelAboutToBeUpdated);
+ connect(itemModel, &AbstractDynamicItemModel::updateComplete, this, &MixesPanel::onItemModelUpdateComplete);
+ }
+}
+
+void MixesPanel::onItemModelAboutToBeUpdated()
+{
+ lock = true;
+ modelsUpdateCnt++;
+}
+
+void MixesPanel::onItemModelUpdateComplete()
+{
+ modelsUpdateCnt--;
+ if (modelsUpdateCnt < 1) {
+ update();
+ lock = false;
+ }
+}
diff --git a/companion/src/modeledit/mixes.h b/companion/src/modeledit/mixes.h
index 46a51a21a..c298df11a 100644
--- a/companion/src/modeledit/mixes.h
+++ b/companion/src/modeledit/mixes.h
@@ -26,12 +26,15 @@
#include "mixerdialog.h"
#include "modelprinter.h"
+class CompoundItemModelFactory;
+class FilteredItemModel;
+
class MixesPanel : public ModelPanel
{
Q_OBJECT
public:
- MixesPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware);
+ MixesPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CompoundItemModelFactory * sharedItemModels);
virtual ~MixesPanel();
virtual void update();
@@ -39,7 +42,7 @@ class MixesPanel : public ModelPanel
private slots:
// TODO all slots?
void clearMixes();
- void mixersDelete(bool ask=true);
+ void mixersDelete(bool prompt = true);
void mixersCut();
void mixersCopy();
void mixersPaste();
@@ -50,7 +53,6 @@ class MixesPanel : public ModelPanel
void moveMixDown();
void mixerHighlight();
-
void mixerlistWidget_customContextMenuRequested(QPoint pos);
void mixerlistWidget_doubleClicked(QModelIndex index);
void mixerlistWidget_KeyPress(QKeyEvent *event);
@@ -58,11 +60,16 @@ class MixesPanel : public ModelPanel
void mimeMixerDropped(int index, const QMimeData *data, Qt::DropAction action);
void pasteMixerMimeData(const QMimeData * mimeData, int destIdx);
+ void onItemModelAboutToBeUpdated();
+ void onItemModelUpdateComplete();
+
private:
MixersListWidget * mixersListWidget;
bool mixInserted;
unsigned int highlightedSource;
ModelPrinter modelPrinter;
+ CompoundItemModelFactory *sharedItemModels;
+ int modelsUpdateCnt;
int getMixerIndex(unsigned int dch);
bool gm_insertMix(int idx);
@@ -74,6 +81,7 @@ class MixesPanel : public ModelPanel
void setSelectedByMixList(QList list);
void AddMixerLine(int dest);
QString getMixerText(int dest, bool newChannel);
+ void connectItemModelEvents(const int id);
};
#endif // _MIXES_H_
diff --git a/companion/src/modeledit/modeledit.cpp b/companion/src/modeledit/modeledit.cpp
index af3166c7f..146bc01f0 100644
--- a/companion/src/modeledit/modeledit.cpp
+++ b/companion/src/modeledit/modeledit.cpp
@@ -33,6 +33,7 @@
#include "customfunctions.h"
#include "telemetry.h"
#include "appdata.h"
+#include "compounditemmodels.h"
ModelEdit::ModelEdit(QWidget * parent, RadioData & radioData, int modelId, Firmware * firmware) :
QDialog(parent),
@@ -48,39 +49,74 @@ ModelEdit::ModelEdit(QWidget * parent, RadioData & radioData, int modelId, Firmw
setWindowIcon(CompanionIcon("edit.png"));
restoreGeometry(g.modelEditGeo());
ui->pushButton->setIcon(CompanionIcon("simulate.png"));
- SetupPanel * setupPanel = new SetupPanel(this, radioData.models[modelId], radioData.generalSettings, firmware);
+
+ GeneralSettings &generalSettings = radioData.generalSettings;
+ ModelData &model = radioData.models[modelId];
+
+ sharedItemModels = new CompoundItemModelFactory(&generalSettings, &model);
+ sharedItemModels->addItemModel(AbstractItemModel::IMID_RawSource);
+ sharedItemModels->addItemModel(AbstractItemModel::IMID_RawSwitch);
+ sharedItemModels->addItemModel(AbstractItemModel::IMID_Curve);
+ sharedItemModels->addItemModel(AbstractItemModel::IMID_GVarRef);
+ sharedItemModels->addItemModel(AbstractItemModel::IMID_ThrSource);
+ sharedItemModels->addItemModel(AbstractItemModel::IMID_CustomFuncAction);
+ sharedItemModels->addItemModel(AbstractItemModel::IMID_CustomFuncResetParam);
+ sharedItemModels->addItemModel(AbstractItemModel::IMID_TeleSource);
+ sharedItemModels->addItemModel(AbstractItemModel::IMID_RssiSource);
+ sharedItemModels->addItemModel(AbstractItemModel::IMID_CurveRefType);
+ sharedItemModels->addItemModel(AbstractItemModel::IMID_CurveRefFunc);
+
+ s1.report("Init");
+
+ SetupPanel * setupPanel = new SetupPanel(this, model, generalSettings, firmware, sharedItemModels);
addTab(setupPanel, tr("Setup"));
- if (firmware->getCapability(Heli))
- addTab(new HeliPanel(this, radioData.models[modelId], radioData.generalSettings, firmware), tr("Heli"));
- addTab(new FlightModesPanel(this, radioData.models[modelId], radioData.generalSettings, firmware), tr("Flight Modes"));
- addTab(new InputsPanel(this, radioData.models[modelId], radioData.generalSettings, firmware), tr("Inputs"));
- s1.report("inputs");
- addTab(new MixesPanel(this, radioData.models[modelId], radioData.generalSettings, firmware), tr("Mixes"));
+ s1.report("Setup");
+
+ if (firmware->getCapability(Heli)) {
+ addTab(new HeliPanel(this, model, generalSettings, firmware, sharedItemModels), tr("Heli"));
+ s1.report("Heli");
+ }
+
+ addTab(new FlightModesPanel(this, model, generalSettings, firmware, sharedItemModels), tr("Flight Modes"));
+ s1.report("Flight Modes");
+
+ addTab(new InputsPanel(this, model, generalSettings, firmware, sharedItemModels), tr("Inputs"));
+ s1.report("Inputs");
+
+ addTab(new MixesPanel(this, model, generalSettings, firmware, sharedItemModels), tr("Mixes"));
s1.report("Mixes");
- Channels * chnPanel = new Channels(this, radioData.models[modelId], radioData.generalSettings, firmware);
- addTab(chnPanel, tr("Outputs"));
+
+ ChannelsPanel * channelsPanel = new ChannelsPanel(this, model, generalSettings, firmware, sharedItemModels);
+ addTab(channelsPanel, tr("Outputs"));
s1.report("Outputs");
- addTab(new Curves(this, radioData.models[modelId], radioData.generalSettings, firmware), tr("Curves"));
- addTab(new LogicalSwitchesPanel(this, radioData.models[modelId], radioData.generalSettings, firmware), tr("Logical Switches"));
- s1.report("LS");
- addTab(new CustomFunctionsPanel(this, &radioData.models[modelId], radioData.generalSettings, firmware), tr("Special Functions"));
- s1.report("CF");
- if (firmware->getCapability(Telemetry))
- addTab(new TelemetryPanel(this, radioData.models[modelId], radioData.generalSettings, firmware), tr("Telemetry"));
- onTabIndexChanged(ui->tabWidget->currentIndex()); // make sure to trigger update on default tab panel
+ addTab(new CurvesPanel(this, model, generalSettings, firmware, sharedItemModels), tr("Curves"));
+ s1.report("Curves");
- connect(setupPanel, &SetupPanel::extendedLimitsToggled, chnPanel, &Channels::refreshExtendedLimits);
+ addTab(new LogicalSwitchesPanel(this, model, generalSettings, firmware, sharedItemModels), tr("Logical Switches"));
+ s1.report("Logical Switches");
+
+ addTab(new CustomFunctionsPanel(this, &model, generalSettings, firmware, sharedItemModels), tr("Special Functions"));
+ s1.report("Special Functions");
+
+ if (firmware->getCapability(Telemetry)) {
+ addTab(new TelemetryPanel(this, model, generalSettings, firmware, sharedItemModels), tr("Telemetry"));
+ s1.report("Telemetry");
+ }
+
+ connect(setupPanel, &SetupPanel::extendedLimitsToggled, channelsPanel, &ChannelsPanel::refreshExtendedLimits);
connect(ui->tabWidget, &QTabWidget::currentChanged, this, &ModelEdit::onTabIndexChanged);
connect(ui->pushButton, &QPushButton::clicked, this, &ModelEdit::launchSimulation);
- s1.report("end");
+ onTabIndexChanged(ui->tabWidget->currentIndex()); // make sure to trigger update on default tab panel
+
gStopwatch.report("ModelEdit end constructor");
}
ModelEdit::~ModelEdit()
{
delete ui;
+ delete sharedItemModels;
}
void ModelEdit::closeEvent(QCloseEvent *event)
diff --git a/companion/src/modeledit/modeledit.h b/companion/src/modeledit/modeledit.h
index 969ae85d7..0bd4af9d8 100644
--- a/companion/src/modeledit/modeledit.h
+++ b/companion/src/modeledit/modeledit.h
@@ -25,6 +25,7 @@
#include "genericpanel.h"
class RadioData;
+class CompoundItemModelFactory;
namespace Ui {
class ModelEdit;
@@ -59,11 +60,12 @@ class ModelEdit : public QDialog
private:
Ui::ModelEdit *ui;
int modelId;
- RadioData & radioData;
- Firmware * firmware;
+ RadioData &radioData;
+ Firmware *firmware;
QVector panels;
+ CompoundItemModelFactory *sharedItemModels;
- void addTab(GenericPanel *panel, QString text);
+ void addTab(GenericPanel * panel, QString text);
void launchSimulation();
};
diff --git a/companion/src/modeledit/setup.cpp b/companion/src/modeledit/setup.cpp
index 898596a6c..de6609591 100644
--- a/companion/src/modeledit/setup.cpp
+++ b/companion/src/modeledit/setup.cpp
@@ -22,7 +22,6 @@
#include "ui_setup.h"
#include "ui_setup_timer.h"
#include "ui_setup_module.h"
-#include "rawitemfilteredmodel.h"
#include "appdata.h"
#include "modelprinter.h"
#include "multiprotocols.h"
@@ -31,55 +30,61 @@
#include
-TimerPanel::TimerPanel(QWidget *parent, ModelData & model, TimerData & timer, GeneralSettings & generalSettings, Firmware * firmware, QWidget * prevFocus, RawSwitchFilterItemModel * switchModel):
+constexpr char FIM_TIMERSWITCH[] {"Timer Switch"};
+constexpr char FIM_THRSOURCE[] {"Throttle Source"};
+
+TimerPanel::TimerPanel(QWidget * parent, ModelData & model, TimerData & timer, GeneralSettings & generalSettings, Firmware * firmware,
+ QWidget * prevFocus, FilteredItemModelFactory * panelFilteredModels, CompoundItemModelFactory * panelItemModels):
ModelPanel(parent, model, generalSettings, firmware),
timer(timer),
- ui(new Ui::Timer)
+ ui(new Ui::Timer),
+ modelsUpdateCnt(0)
{
-
ui->setupUi(this);
+ connectItemModelEvents(panelFilteredModels->getItemModel(FIM_TIMERSWITCH));
lock = true;
// Name
int length = firmware->getCapability(TimersName);
- if (length == 0) {
+ if (length == 0)
ui->name->hide();
+ else {
+ ui->name->setField(timer.name, length, this);
+ connect(ui->name, SIGNAL(currentDataChanged()), this, SLOT(onNameChanged()));
+ }
+
+ ui->value->setField(timer.val, this);
+ ui->value->setMaximumTime(firmware->getMaxTimerStart());
+
+ ui->mode->setModel(panelFilteredModels->getItemModel(FIM_TIMERSWITCH));
+ ui->mode->setField(timer.mode, this);
+
+ ui->countdownBeep->setModel(panelItemModels->getItemModel(AIM_TIMER_COUNTDOWNBEEP));
+ ui->countdownBeep->setField(timer.countdownBeep, this);
+ connect(ui->countdownBeep, SIGNAL(currentDataChanged(int)), this, SLOT(onCountdownBeepChanged(int)));
+
+ ui->minuteBeep->setField(timer.minuteBeep, this);
+
+ if (firmware->getCapability(PermTimers)) {
+ ui->persistent->setModel(panelItemModels->getItemModel(AIM_TIMER_PERSISTENT));
+ ui->persistent->setField(timer.persistent, this);
}
else {
- ui->name->setMaxLength(length);
- //ui->name->setText(timer.name);
- }
-
- // Mode
- ui->mode->setModel(switchModel);
- ui->mode->setCurrentIndex(ui->mode->findData(timer.mode.toValue()));
- connect(ui->mode, SIGNAL(activated(int)), this, SLOT(onModeChanged(int)));
-
- if (!firmware->getCapability(PermTimers)) {
ui->persistent->hide();
ui->persistentValue->hide();
}
- ui->countdownBeep->setField(timer.countdownBeep, this);
- ui->countdownBeep->addItem(tr("Silent"), TimerData::COUNTDOWN_SILENT);
- ui->countdownBeep->addItem(tr("Beeps"), TimerData::COUNTDOWN_BEEPS);
- ui->countdownBeep->addItem(tr("Voice"), TimerData::COUNTDOWN_VOICE);
- ui->countdownBeep->addItem(tr("Haptic"), TimerData::COUNTDOWN_HAPTIC);
-
- ui->value->setMaximumTime(firmware->getMaxTimerStart());
-
- ui->persistent->setField(timer.persistent, this);
- ui->persistent->addItem(tr("Not persistent"), 0);
- ui->persistent->addItem(tr("Persistent (flight)"), 1);
- ui->persistent->addItem(tr("Persistent (manual reset)"), 2);
+ ui->countdownStart->setModel(panelItemModels->getItemModel(AIM_TIMER_COUNTDOWNSTART));
+ ui->countdownStart->setField(timer.countdownStart, this);
disableMouseScrolling();
QWidget::setTabOrder(prevFocus, ui->name);
QWidget::setTabOrder(ui->name, ui->value);
QWidget::setTabOrder(ui->value, ui->mode);
QWidget::setTabOrder(ui->mode, ui->countdownBeep);
- QWidget::setTabOrder(ui->countdownBeep, ui->minuteBeep);
+ QWidget::setTabOrder(ui->countdownBeep, ui->countdownStart);
+ QWidget::setTabOrder(ui->countdownStart, ui->minuteBeep);
QWidget::setTabOrder(ui->minuteBeep, ui->persistent);
update();
@@ -94,32 +99,28 @@ TimerPanel::~TimerPanel()
void TimerPanel::update()
{
lock = true;
- ui->name->setText(timer.name);
- int hour = timer.val / 3600;
- int min = (timer.val - (hour * 3600)) / 60;
- int sec = (timer.val - (hour * 3600)) % 60;
+ ui->name->updateValue();
+ ui->mode->updateValue();
+ ui->value->updateValue();
+ ui->countdownBeep->updateValue();
+ ui->minuteBeep->updateValue();
+ ui->countdownStart->updateValue();
- ui->mode->setCurrentIndex(ui->mode->findData(timer.mode.toValue()));
- ui->value->setTime(QTime(hour, min, sec));
+ if (timer.countdownBeep == TimerData::COUNTDOWNBEEP_SILENT) {
+ ui->countdownStartLabel->setEnabled(false);
+ ui->countdownStart->setEnabled(false);
+ }
+ else {
+ ui->countdownStartLabel->setEnabled(true);
+ ui->countdownStart->setEnabled(true);
+ }
if (firmware->getCapability(PermTimers)) {
- int sign = 1;
- int pvalue = timer.pvalue;
- if (pvalue < 0) {
- pvalue = -pvalue;
- sign = -1;
- }
- int hours = pvalue / 3600;
- pvalue -= hours * 3600;
- int minutes = pvalue / 60;
- int seconds = pvalue % 60;
- ui->persistentValue->setText(QString(" %1(%2:%3:%4)").arg(sign<0 ? "-" :" ").arg(hours, 2, 10, QLatin1Char('0')).arg(minutes, 2, 10, QLatin1Char('0')).arg(seconds, 2, 10, QLatin1Char('0')));
+ ui->persistent->updateValue();
+ ui->persistentValue->setText(timer.pvalueToString());
}
- ui->countdownBeep->updateValue();
- ui->minuteBeep->setChecked(timer.minuteBeep);
- ui->persistent->updateValue();
lock = false;
}
@@ -128,46 +129,36 @@ QWidget * TimerPanel::getLastFocus()
return ui->persistent;
}
-void TimerPanel::on_value_editingFinished()
+void TimerPanel::connectItemModelEvents(const FilteredItemModel * itemModel)
{
- if (!lock) {
- unsigned val = ui->value->time().hour()*3600 + ui->value->time().minute()*60 + ui->value->time().second();
- if (timer.val != val) {
- timer.val = val;
- emit modified();
- }
+ connect(itemModel, &FilteredItemModel::aboutToBeUpdated, this, &TimerPanel::onItemModelAboutToBeUpdated);
+ connect(itemModel, &FilteredItemModel::updateComplete, this, &TimerPanel::onItemModelUpdateComplete);
+}
+
+void TimerPanel::onItemModelAboutToBeUpdated()
+{
+ lock = true;
+ modelsUpdateCnt++;
+}
+
+void TimerPanel::onItemModelUpdateComplete()
+{
+ modelsUpdateCnt--;
+ if (modelsUpdateCnt < 1) {
+ update();
+ lock = false;
}
}
-void TimerPanel::onModeChanged(int index)
+void TimerPanel::onNameChanged()
{
- if (!lock) {
- bool ok;
- const RawSwitch rs(ui->mode->itemData(index).toInt(&ok));
- if (ok && timer.mode.toValue() != rs.toValue()) {
- timer.mode = rs;
- emit modified();
- }
- }
+ emit nameChanged();
}
-void TimerPanel::on_minuteBeep_toggled(bool checked)
+void TimerPanel::onCountdownBeepChanged(int index)
{
- if (!lock) {
- timer.minuteBeep = checked;
- emit modified();
- }
-}
-
-void TimerPanel::on_name_editingFinished()
-{
- if (!lock) {
- if (QString(timer.name) != ui->name->text()) {
- int length = ui->name->maxLength();
- strncpy(timer.name, ui->name->text().toLatin1(), length);
- emit modified();
- }
- }
+ timer.countdownBeepChanged();
+ update();
}
/******************************************************************************/
@@ -191,6 +182,7 @@ void TimerPanel::on_name_editingFinished()
#define MASK_ACCESS (1<<13)
#define MASK_RX_FREQ (1<<14)
#define MASK_RF_POWER (1<<15)
+#define MASK_RF_RACING_MODE (1<<16)
quint8 ModulePanel::failsafesValueDisplayType = ModulePanel::FAILSAFE_DISPLAY_PERCENT;
@@ -237,19 +229,19 @@ ModulePanel::ModulePanel(QWidget * parent, ModelData & model, ModuleData & modul
}
// The protocols available on this board
- for (unsigned int i=0; iisAvailable((PulsesProtocol) i, moduleIdx)) {
ui->protocol->addItem(ModuleData::protocolToString(i), i);
if (i == module.protocol)
- ui->protocol->setCurrentIndex(ui->protocol->count()-1);
+ ui->protocol->setCurrentIndex(ui->protocol->count() - 1);
}
}
- for (int i=0; i<=MODULE_SUBTYPE_MULTI_LAST; i++) {
+ for (int i = 0; i <= MODULE_SUBTYPE_MULTI_LAST; i++) {
if (i == MODULE_SUBTYPE_MULTI_SCANNER)
continue;
ui->multiProtocol->addItem(Multiprotocols::protocolToString(i), i);
}
- for (int i=MODULE_SUBTYPE_MULTI_LAST + 1; i <= 124; i++) {
+ for (int i = MODULE_SUBTYPE_MULTI_LAST + 1; i <= 124; i++) {
ui->multiProtocol->addItem(QString::number(i + 3), i);
}
@@ -327,7 +319,7 @@ void ModulePanel::setupFailsafes()
else {
QLabel * label = new QLabel(this);
label->setProperty("index", i);
- label->setText(QString::number(i+1));
+ label->setText(QString::number(i + 1));
QComboBox * combo = new QComboBox(this);
combo->setProperty("index", i);
@@ -380,9 +372,9 @@ void ModulePanel::setupFailsafes()
void ModulePanel::update()
{
- const PulsesProtocol protocol = (PulsesProtocol)module.protocol;
- const Board::Type board = firmware->getBoard();
- const Multiprotocols::MultiProtocolDefinition & pdef = multiProtocols.getProtocol(module.multi.rfProtocol);
+ const auto protocol = (PulsesProtocol)module.protocol;
+ const auto board = firmware->getBoard();
+ const auto & pdef = multiProtocols.getProtocol(module.multi.rfProtocol);
unsigned int mask = 0;
unsigned int max_rx_num = 63;
@@ -415,6 +407,8 @@ void ModulePanel::update()
mask |= MASK_RX_NUMBER | MASK_ACCESS;
if (moduleIdx == 0 && HAS_EXTERNAL_ANTENNA(board) && generalSettings.antennaMode == 0 /* per model */)
mask |= MASK_ANTENNA;
+ if (protocol == PULSES_ACCESS_ISRM && module.channelsCount == 8)
+ mask |= MASK_RF_RACING_MODE;
break;
case PULSES_LP45:
case PULSES_DSM2:
@@ -424,6 +418,8 @@ void ModulePanel::update()
max_rx_num = 20;
break;
case PULSES_CROSSFIRE:
+ mask |= MASK_CHANNELS_RANGE | MASK_RX_NUMBER;
+ case PULSES_GHOST:
mask |= MASK_CHANNELS_RANGE;
module.channelsCount = 16;
break;
@@ -454,8 +450,6 @@ void ModulePanel::update()
mask |= MASK_CHANNELS_RANGE| MASK_CHANNELS_COUNT | MASK_FAILSAFES;
mask |= MASK_SUBTYPES | MASK_RX_FREQ | MASK_RF_POWER;
break;
- case PULSES_OFF:
- break;
default:
break;
}
@@ -504,7 +498,7 @@ void ModulePanel::update()
ui->ppmFrameLength->setVisible(mask & MASK_SBUSPPM_FIELDS);
ui->ppmFrameLength->setMinimum(module.channelsCount * (model->extendedLimits ? 2.250 : 2)+3.5);
ui->ppmFrameLength->setMaximum(firmware->getCapability(PPMFrameLength));
- ui->ppmFrameLength->setValue(22.5+((double)module.ppm.frameLength)*0.5);
+ ui->ppmFrameLength->setValue(22.5 + ((double)module.ppm.frameLength) * 0.5);
// Antenna mode on Horus and XLite
if (mask & MASK_ANTENNA) {
@@ -519,6 +513,14 @@ void ModulePanel::update()
ui->antennaMode->hide();
}
+ if (mask & MASK_RF_RACING_MODE) {
+ ui->racingMode->show();
+ ui->racingMode->setChecked(module.access.racingMode);
+ }
+ else {
+ ui->racingMode->hide();
+ }
+
// R9M options
ui->r9mPower->setVisible(mask & MASK_RF_POWER);
ui->label_r9mPower->setVisible(mask & MASK_RF_POWER);
@@ -598,17 +600,17 @@ void ModulePanel::update()
ui->registrationIdLabel->setVisible(mask & MASK_ACCESS);
ui->registrationId->setVisible(mask & MASK_ACCESS);
- ui->rx1Label->setVisible((mask & MASK_ACCESS) && (module.access.receivers & (1<<0)));
- ui->clearRx1->setVisible((mask & MASK_ACCESS) && (module.access.receivers & (1<<0)));
- ui->rx1->setVisible((mask & MASK_ACCESS) && (module.access.receivers & (1<<0)));
+ ui->rx1Label->setVisible((mask & MASK_ACCESS) && (module.access.receivers & (1 << 0)));
+ ui->clearRx1->setVisible((mask & MASK_ACCESS) && (module.access.receivers & (1 << 0)));
+ ui->rx1->setVisible((mask & MASK_ACCESS) && (module.access.receivers & (1 << 0)));
- ui->rx2Label->setVisible((mask & MASK_ACCESS) && (module.access.receivers & (1<<1)));
- ui->clearRx2->setVisible((mask & MASK_ACCESS) && (module.access.receivers & (1<<1)));
- ui->rx2->setVisible((mask & MASK_ACCESS) && (module.access.receivers & (1<<1)));
+ ui->rx2Label->setVisible((mask & MASK_ACCESS) && (module.access.receivers & (1 << 1)));
+ ui->clearRx2->setVisible((mask & MASK_ACCESS) && (module.access.receivers & (1 << 1)));
+ ui->rx2->setVisible((mask & MASK_ACCESS) && (module.access.receivers & (1 << 1)));
- ui->rx3Label->setVisible((mask & MASK_ACCESS) && (module.access.receivers & (1<<2)));
- ui->clearRx3->setVisible((mask & MASK_ACCESS) && (module.access.receivers & (1<<2)));
- ui->rx3->setVisible((mask & MASK_ACCESS) && (module.access.receivers & (1<<2)));
+ ui->rx3Label->setVisible((mask & MASK_ACCESS) && (module.access.receivers & (1 << 2)));
+ ui->clearRx3->setVisible((mask & MASK_ACCESS) && (module.access.receivers & (1 << 2)));
+ ui->rx3->setVisible((mask & MASK_ACCESS) && (module.access.receivers & (1 << 2)));
// Failsafes
ui->label_failsafeMode->setVisible(mask & MASK_FAILSAFES);
@@ -664,6 +666,7 @@ void ModulePanel::onProtocolChanged(int index)
module.protocol = ui->protocol->itemData(index).toInt();
module.channelsCount = module.getMaxChannelCount();
update();
+ emit updateItemModels();
emit modified();
}
}
@@ -701,8 +704,8 @@ void ModulePanel::on_channelsCount_editingFinished()
{
if (!lock && module.channelsCount != ui->channelsCount->value()) {
module.channelsCount = ui->channelsCount->value();
- update();
emit channelsRangeChanged();
+ update();
emit modified();
}
}
@@ -711,8 +714,8 @@ void ModulePanel::on_channelsStart_editingFinished()
{
if (!lock && module.channelsStart != (unsigned)ui->channelsStart->value() - 1) {
module.channelsStart = (unsigned)ui->channelsStart->value() - 1;
- update();
emit channelsRangeChanged();
+ update();
emit modified();
}
}
@@ -736,7 +739,7 @@ void ModulePanel::on_rxNumber_editingFinished()
void ModulePanel::on_ppmFrameLength_editingFinished()
{
- int val = (ui->ppmFrameLength->value()-22.5) / 0.5;
+ int val = (ui->ppmFrameLength->value() - 22.5) / 0.5;
if (module.ppm.frameLength != val) {
module.ppm.frameLength = val;
emit modified();
@@ -760,10 +763,11 @@ void ModulePanel::onMultiProtocolChanged(int index)
module.multi.rfProtocol = (unsigned int)rfProtocol;
unsigned int maxSubTypes = multiProtocols.getProtocol(index).numSubTypes();
if (rfProtocol > MODULE_SUBTYPE_MULTI_LAST)
- maxSubTypes=8;
- module.subType = std::min(module.subType, maxSubTypes -1);
+ maxSubTypes = 8;
+ module.subType = std::min(module.subType, maxSubTypes - 1);
module.channelsCount = module.getMaxChannelCount();
update();
+ emit updateItemModels();
emit modified();
lock = false;
}
@@ -808,6 +812,11 @@ void ModulePanel::on_disableChMap_stateChanged(int state)
module.multi.disableMapping = (state == Qt::Checked);
}
+void ModulePanel::on_racingMode_stateChanged(int state)
+{
+ module.access.racingMode = (state == Qt::Checked);
+}
+
void ModulePanel::on_autoBind_stateChanged(int state)
{
module.multi.autoBindMode = (state == Qt::Checked);
@@ -955,19 +964,19 @@ void ModulePanel::onClearAccessRxClicked()
QPushButton *button = qobject_cast(sender());
if (button == ui->clearRx1) {
- module.access.receivers &= ~(1<<0);
+ module.access.receivers &= ~(1 << 0);
ui->rx1->clear();
update();
emit modified();
}
else if (button == ui->clearRx2) {
- module.access.receivers &= ~(1<<1);
+ module.access.receivers &= ~(1 << 1);
ui->rx2->clear();
update();
emit modified();
}
else if (button == ui->clearRx3) {
- module.access.receivers &= ~(1<<2);
+ module.access.receivers &= ~(1 << 2);
ui->rx3->clear();
update();
emit modified();
@@ -976,17 +985,35 @@ void ModulePanel::onClearAccessRxClicked()
/******************************************************************************/
-SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware):
+SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware,
+ CompoundItemModelFactory * sharedItemModels) :
ModelPanel(parent, model, generalSettings, firmware),
- ui(new Ui::Setup)
+ ui(new Ui::Setup),
+ sharedItemModels(sharedItemModels)
{
- Board::Type board = firmware->getBoard();
+ ui->setupUi(this);
lock = true;
- memset(modules, 0, sizeof(modules));
+ panelFilteredModels = new FilteredItemModelFactory();
- ui->setupUi(this);
+ panelFilteredModels->registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_RawSwitch),
+ RawSwitch::TimersContext),
+ FIM_TIMERSWITCH);
+ connectItemModelEvents(panelFilteredModels->getItemModel(FIM_TIMERSWITCH));
+
+ panelFilteredModels->registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_ThrSource)),
+ FIM_THRSOURCE);
+ connectItemModelEvents(panelFilteredModels->getItemModel(FIM_THRSOURCE));
+
+ panelItemModels = new CompoundItemModelFactory(&generalSettings, &model);
+ panelItemModels->registerItemModel(TimerData::countdownBeepItemModel());
+ panelItemModels->registerItemModel(TimerData::countdownStartItemModel());
+ panelItemModels->registerItemModel(TimerData::persistentItemModel());
+
+ Board::Type board = firmware->getBoard();
+
+ memset(modules, 0, sizeof(modules));
QRegExp rx(CHAR_FOR_NAMES_REGEX);
ui->name->setValidator(new QRegExpValidator(rx, this));
@@ -1005,7 +1032,7 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge
foreach ( QString file, qd.entryList(filters, QDir::Files) ) {
QFileInfo fi(file);
QString temp = fi.fileName();
- if (!items.contains(temp) && temp.length() <= 6+4) {
+ if (!items.contains(temp) && temp.length() <= 6 + 4) {
items.append(temp);
}
}
@@ -1015,7 +1042,7 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge
foreach (QString file, qd.entryList(filters, QDir::Files)) {
QFileInfo fi(file);
QString temp = fi.completeBaseName();
- if (!items.contains(temp) && temp.length() <= 10+4) {
+ if (!items.contains(temp) && temp.length() <= 10 + 4) {
items.append(temp);
}
}
@@ -1028,7 +1055,7 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge
foreach (QString file, items) {
ui->image->addItem(file);
if (file == model.bitmap) {
- ui->image->setCurrentIndex(ui->image->count()-1);
+ ui->image->setCurrentIndex(ui->image->count() - 1);
QString fileName = path;
fileName.append(model.bitmap);
if (!IS_FAMILY_HORUS_OR_T16(board))
@@ -1060,18 +1087,16 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge
}
QWidget * prevFocus = ui->image;
- RawSwitchFilterItemModel * swModel = new RawSwitchFilterItemModel(&generalSettings, &model, RawSwitch::TimersContext, this);
- connect(this, &SetupPanel::updated, swModel, &RawSwitchFilterItemModel::update);
timersCount = firmware->getCapability(Timers);
for (int i = 0; i < CPN_MAX_TIMERS; i++) {
if (i < timersCount) {
- timers[i] = new TimerPanel(this, model, model.timers[i], generalSettings, firmware, prevFocus, swModel);
+ timers[i] = new TimerPanel(this, model, model.timers[i], generalSettings, firmware, prevFocus, panelFilteredModels, panelItemModels);
ui->gridLayout->addWidget(timers[i], 1+i, 1);
connect(timers[i], &TimerPanel::modified, this, &SetupPanel::modified);
+ connect(timers[i], &TimerPanel::nameChanged, this, &SetupPanel::onTimerNameChanged);
connect(this, &SetupPanel::updated, timers[i], &TimerPanel::update);
- connect(this, &SetupPanel::timerUpdated, timers[i], &TimerPanel::update);
prevFocus = timers[i]->getLastFocus();
// TODO more reliable method required
QLabel *label = findChild(QString("label_timer%1").arg(i + 1));
@@ -1093,7 +1118,7 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge
if (firmware->getCapability(HasTopLcd)) {
ui->toplcdTimer->setField(model.toplcdTimer, this);
for (int i = 0; i < CPN_MAX_TIMERS; i++) {
- if (itoplcdTimer->addItem(tr("Timer %1").arg(i + 1), i);
}
}
@@ -1103,6 +1128,9 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge
ui->toplcdTimer->hide();
}
+ ui->throttleSource->setModel(panelFilteredModels->getItemModel(FIM_THRSOURCE));
+ ui->throttleSource->setField(model.thrTraceSrc, this);
+
if (!firmware->getCapability(HasDisplayText)) {
ui->displayText->hide();
ui->editText->hide();
@@ -1116,12 +1144,12 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge
prevFocus = ui->trimsDisplay;
int analogs = CPN_MAX_STICKS + getBoardCapability(board, Board::Pots) + getBoardCapability(board, Board::Sliders);
int genAryIdx = 0;
- for (int i=0; i < analogs + firmware->getCapability(RotaryEncoders); i++) {
+ for (int i = 0; i < analogs + firmware->getCapability(RotaryEncoders); i++) {
RawSource src((i < analogs) ? SOURCE_TYPE_STICK : SOURCE_TYPE_ROTARY_ENCODER, (i < analogs) ? i : analogs - i);
QCheckBox * checkbox = new QCheckBox(this);
checkbox->setProperty("index", i);
checkbox->setText(src.toString(&model, &generalSettings));
- ui->centerBeepLayout->addWidget(checkbox, 0, i+1);
+ ui->centerBeepLayout->addWidget(checkbox, 0, i + 1);
connect(checkbox, SIGNAL(toggled(bool)), this, SLOT(onBeepCenterToggled(bool)));
centerBeepCheckboxes << checkbox;
if (IS_HORUS_OR_TARANIS(board)) {
@@ -1137,7 +1165,7 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge
}
// Startup switches warnings
- for (int i=0; isetText(src.toString(&model, &generalSettings));
slider->setMaximum(switchInfo.config == Board::SWITCH_3POS ? 2 : 1);
cb->setProperty("index", i);
- ui->switchesStartupLayout->addWidget(label, 0, i+1);
+ ui->switchesStartupLayout->addWidget(label, 0, i + 1);
ui->switchesStartupLayout->setAlignment(label, Qt::AlignCenter);
- ui->switchesStartupLayout->addWidget(slider, 1, i+1);
+ ui->switchesStartupLayout->addWidget(slider, 1, i + 1);
ui->switchesStartupLayout->setAlignment(slider, Qt::AlignCenter);
- ui->switchesStartupLayout->addWidget(cb, 2, i+1);
+ ui->switchesStartupLayout->addWidget(cb, 2, i + 1);
ui->switchesStartupLayout->setAlignment(cb, Qt::AlignCenter);
connect(slider, SIGNAL(valueChanged(int)), this, SLOT(startupSwitchEdited(int)));
connect(cb, SIGNAL(toggled(bool)), this, SLOT(startupSwitchToggled(bool)));
@@ -1179,12 +1207,12 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge
// Pot warnings
prevFocus = ui->potWarningMode;
if (IS_HORUS_OR_TARANIS(board)) {
- for (int i=0; isetProperty("index", i);
cb->setText(src.toString(&model, &generalSettings));
- ui->potWarningLayout->addWidget(cb, 0, i+1);
+ ui->potWarningLayout->addWidget(cb, 0, i + 1);
connect(cb, SIGNAL(toggled(bool)), this, SLOT(potWarningToggled(bool)));
potWarningCheckboxes << cb;
if (src.isPot(&genAryIdx) && !generalSettings.isPotAvailable(genAryIdx)) {
@@ -1208,6 +1236,7 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge
modules[i] = new ModulePanel(this, model, model.moduleData[i], generalSettings, firmware, i);
ui->modulesLayout->addWidget(modules[i]);
connect(modules[i], &ModulePanel::modified, this, &SetupPanel::modified);
+ connect(modules[i], &ModulePanel::updateItemModels, this, &SetupPanel::onModuleUpdateItemModels);
connect(this, &SetupPanel::extendedLimitsToggled, modules[i], &ModulePanel::onExtendedLimitsToggled);
}
@@ -1233,6 +1262,8 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge
SetupPanel::~SetupPanel()
{
delete ui;
+ delete panelFilteredModels;
+ delete panelItemModels;
}
void SetupPanel::on_extendedLimits_toggled(bool checked)
@@ -1262,14 +1293,14 @@ void SetupPanel::on_extendedTrims_toggled(bool checked)
void SetupPanel::on_trimIncrement_currentIndexChanged(int index)
{
- model->trimInc = index-2;
+ model->trimInc = index - 2;
emit modified();
}
-void SetupPanel::on_throttleSource_currentIndexChanged(int index)
+void SetupPanel::on_throttleTrimSwitch_currentIndexChanged(int index)
{
if (!lock) {
- model->thrTraceSrc = ui->throttleSource->currentData().toUInt();
+ model->thrTrimSwitch = ui->throttleTrimSwitch->currentData().toUInt();
emit modified();
}
}
@@ -1324,25 +1355,26 @@ void SetupPanel::on_image_currentIndexChanged(int index)
}
}
-void SetupPanel::populateThrottleSourceCB()
+void SetupPanel::populateThrottleTrimSwitchCB()
{
Board::Type board = firmware->getBoard();
lock = true;
- ui->throttleSource->clear();
- ui->throttleSource->addItem(tr("THR"), 0);
-
- int idx=1;
- for (int i=0; ithrottleSource->addItem(firmware->getAnalogInputName(4+i), idx);
- }
- }
- for (int i=0; igetCapability(Outputs); i++, idx++) {
- ui->throttleSource->addItem(RawSource(SOURCE_TYPE_CH, i).toString(model, &generalSettings), idx);
+ ui->throttleTrimSwitch->clear();
+ int idx=0;
+ QString trim;
+ for (int i=0; ithrottleTrimSwitch->addItem(trim, idx);
}
- int thrTraceSrcIdx = ui->throttleSource->findData(model->thrTraceSrc);
- ui->throttleSource->setCurrentIndex(thrTraceSrcIdx);
+ int thrTrimSwitchIdx = ui->throttleTrimSwitch->findData(model->thrTrimSwitch);
+ ui->throttleTrimSwitch->setCurrentIndex(thrTrimSwitchIdx);
lock = false;
}
@@ -1350,7 +1382,8 @@ void SetupPanel::update()
{
ui->name->setText(model->name);
ui->throttleReverse->setChecked(model->throttleReversed);
- populateThrottleSourceCB();
+ ui->throttleSource->updateValue();
+ populateThrottleTrimSwitchCB();
ui->throttleWarning->setChecked(!model->disableThrottleWarning);
ui->trimIncrement->setCurrentIndex(model->trimInc+2);
ui->throttleTrim->setChecked(model->thrTrim);
@@ -1366,7 +1399,7 @@ void SetupPanel::update()
updatePotWarnings();
}
- for (int i=0; iupdate();
}
@@ -1377,7 +1410,7 @@ void SetupPanel::update()
void SetupPanel::updateBeepCenter()
{
- for (int i=0; isetChecked(model->beepANACenter & (0x01 << i));
}
}
@@ -1389,20 +1422,20 @@ void SetupPanel::updateStartupSwitches()
uint64_t switchStates = model->switchWarningStates;
uint64_t value;
- for (int i=0; iproperty("index").toInt();
bool enabled = !(model->switchWarningEnable & (1 << index));
if (IS_HORUS_OR_TARANIS(firmware->getBoard())) {
- value = (switchStates >> (2*index)) & 0x03;
+ value = (switchStates >> (2 * index)) & 0x03;
if (generalSettings.switchConfig[index] != Board::SWITCH_3POS && value == 2) {
value = 1;
}
}
else {
- value = (i==0 ? switchStates & 0x3 : switchStates & 0x1);
- switchStates >>= (i==0 ? 2 : 1);
+ value = (i == 0 ? switchStates & 0x3 : switchStates & 0x1);
+ switchStates >>= (i == 0 ? 2 : 1);
}
slider->setValue(value);
slider->setEnabled(enabled);
@@ -1428,7 +1461,7 @@ void SetupPanel::startupSwitchEdited(int value)
mask = 0x03;
}
else {
- shift = index+1;
+ shift = index + 1;
mask = 0x01ull << shift;
}
}
@@ -1469,7 +1502,7 @@ void SetupPanel::updatePotWarnings()
{
lock = true;
ui->potWarningMode->setCurrentIndex(model->potsWarningMode);
- for (int i=0; iproperty("index").toInt();
checkbox->setChecked(!model->potsWarnEnabled[index]);
@@ -1590,14 +1623,16 @@ bool SetupPanel::moveTimerUpAllowed() const
return selectedTimerIndex > 0;
}
-void SetupPanel::cmTimerClear()
+void SetupPanel::cmTimerClear(bool prompt)
{
- if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear Timer. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
- return;
+ if (prompt) {
+ if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear Timer. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
+ return;
+ }
model->timers[selectedTimerIndex].clear();
model->updateAllReferences(ModelData::REF_UPD_TYPE_TIMER, ModelData::REF_UPD_ACT_CLEAR, selectedTimerIndex);
- emit timerUpdated();
+ updateItemModels();
emit modified();
}
@@ -1610,7 +1645,7 @@ void SetupPanel::cmTimerClearAll()
model->timers[i].clear();
model->updateAllReferences(ModelData::REF_UPD_TYPE_TIMER, ModelData::REF_UPD_ACT_CLEAR, i);
}
- emit timerUpdated();
+ updateItemModels();
emit modified();
}
@@ -1625,8 +1660,10 @@ void SetupPanel::cmTimerCopy()
void SetupPanel::cmTimerCut()
{
+ if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Cut Timer. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
+ return;
cmTimerCopy();
- cmTimerClear();
+ cmTimerClear(false);
}
void SetupPanel::cmTimerDelete()
@@ -1642,7 +1679,7 @@ void SetupPanel::cmTimerDelete()
}
model->timers[maxidx].clear();
model->updateAllReferences(ModelData::REF_UPD_TYPE_TIMER, ModelData::REF_UPD_ACT_SHIFT, selectedTimerIndex, 0, -1);
- emit timerUpdated();
+ updateItemModels();
emit modified();
}
@@ -1655,7 +1692,7 @@ void SetupPanel::cmTimerInsert()
}
model->timers[selectedTimerIndex].clear();
model->updateAllReferences(ModelData::REF_UPD_TYPE_TIMER, ModelData::REF_UPD_ACT_SHIFT, selectedTimerIndex, 0, 1);
- emit timerUpdated();
+ updateItemModels();
emit modified();
}
@@ -1675,7 +1712,7 @@ void SetupPanel::cmTimerPaste()
if (hasTimerClipboardData(&data)) {
TimerData *td = &model->timers[selectedTimerIndex];
memcpy(td, data.constData(), sizeof(TimerData));
- emit timerUpdated();
+ updateItemModels();
emit modified();
}
}
@@ -1689,7 +1726,37 @@ void SetupPanel::swapTimerData(int idx1, int idx2)
memcpy(td2, td1, sizeof(TimerData));
memcpy(td1, &tdtmp, sizeof(TimerData));
model->updateAllReferences(ModelData::REF_UPD_TYPE_TIMER, ModelData::REF_UPD_ACT_SWAP, idx1, idx2);
- emit timerUpdated();
+ updateItemModels();
emit modified();
}
}
+
+void SetupPanel::onTimerNameChanged()
+{
+ updateItemModels();
+}
+
+void SetupPanel::connectItemModelEvents(const FilteredItemModel * itemModel)
+{
+ connect(itemModel, &FilteredItemModel::aboutToBeUpdated, this, &SetupPanel::onItemModelAboutToBeUpdated);
+ connect(itemModel, &FilteredItemModel::updateComplete, this, &SetupPanel::onItemModelUpdateComplete);
+}
+
+void SetupPanel::onItemModelAboutToBeUpdated()
+{
+}
+
+void SetupPanel::onItemModelUpdateComplete()
+{
+}
+
+void SetupPanel::updateItemModels()
+{
+ sharedItemModels->update(AbstractItemModel::IMUE_Timers);
+ emit updated();
+}
+
+void SetupPanel::onModuleUpdateItemModels()
+{
+ sharedItemModels->update(AbstractItemModel::IMUE_Modules);
+}
diff --git a/companion/src/modeledit/setup.h b/companion/src/modeledit/setup.h
index fbd56ed86..955f2189b 100644
--- a/companion/src/modeledit/setup.h
+++ b/companion/src/modeledit/setup.h
@@ -18,16 +18,15 @@
* GNU General Public License for more details.
*/
-#ifndef _SETUP_H_
-#define _SETUP_H_
+#pragma once
#include "modeledit.h"
#include "eeprominterface.h"
+#include "compounditemmodels.h"
+#include "filtereditemmodels.h"
constexpr char MIMETYPE_TIMER[] = "application/x-companion-timer";
-class RawSwitchFilterItemModel;
-
namespace Ui {
class Setup;
class Timer;
@@ -39,21 +38,27 @@ class TimerPanel : public ModelPanel
Q_OBJECT
public:
- TimerPanel(QWidget *parent, ModelData & model, TimerData & timer, GeneralSettings & generalSettings, Firmware * firmware, QWidget *prevFocus, RawSwitchFilterItemModel * switchModel);
+ TimerPanel(QWidget * parent, ModelData & model, TimerData & timer, GeneralSettings & generalSettings, Firmware * firmware,
+ QWidget * prevFocus, FilteredItemModelFactory * panelFilteredModels, CompoundItemModelFactory * panelItemModels);
virtual ~TimerPanel();
virtual void update();
QWidget * getLastFocus();
private slots:
- void onModeChanged(int index);
- void on_value_editingFinished();
- void on_minuteBeep_toggled(bool checked);
- void on_name_editingFinished();
+ void onNameChanged();
+ void onItemModelAboutToBeUpdated();
+ void onItemModelUpdateComplete();
+ void onCountdownBeepChanged(int index);
+
+ signals:
+ void nameChanged();
private:
TimerData & timer;
Ui::Timer * ui;
+ void connectItemModelEvents(const FilteredItemModel * itemModel);
+ int modelsUpdateCnt;
};
class ModulePanel : public ModelPanel
@@ -72,6 +77,7 @@ class ModulePanel : public ModelPanel
signals:
void channelsRangeChanged();
void failsafeModified(unsigned index);
+ void updateItemModels();
private slots:
void setupFailsafes();
@@ -89,6 +95,7 @@ class ModulePanel : public ModelPanel
void onSubTypeChanged();
void on_autoBind_stateChanged(int state);
void on_disableChMap_stateChanged(int state);
+ void on_racingMode_stateChanged(int state);
void on_disableTelem_stateChanged(int state);
void on_lowPower_stateChanged(int state);
void on_r9mPower_currentIndexChanged(int index);
@@ -125,7 +132,7 @@ class SetupPanel : public ModelPanel
Q_OBJECT
public:
- SetupPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware);
+ SetupPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CompoundItemModelFactory * sharedItemModels);
virtual ~SetupPanel();
virtual void update();
@@ -133,11 +140,10 @@ class SetupPanel : public ModelPanel
signals:
void extendedLimitsToggled();
void updated();
- void timerUpdated();
private slots:
void on_name_editingFinished();
- void on_throttleSource_currentIndexChanged(int index);
+ void on_throttleTrimSwitch_currentIndexChanged(int index);
void on_throttleTrim_toggled(bool checked);
void on_extendedLimits_toggled(bool checked);
void on_extendedTrims_toggled(bool checked);
@@ -154,7 +160,7 @@ class SetupPanel : public ModelPanel
void on_potWarningMode_currentIndexChanged(int index);
void on_editText_clicked();
void onTimerCustomContextMenuRequested(QPoint pos);
- void cmTimerClear();
+ void cmTimerClear(bool prompt = true);
void cmTimerClearAll();
void cmTimerCopy();
void cmTimerCut();
@@ -163,6 +169,10 @@ class SetupPanel : public ModelPanel
void cmTimerPaste();
void cmTimerMoveDown();
void cmTimerMoveUp();
+ void onTimerNameChanged();
+ void onItemModelAboutToBeUpdated();
+ void onItemModelUpdateComplete();
+ void onModuleUpdateItemModels();
private:
Ui::Setup *ui;
@@ -170,12 +180,12 @@ class SetupPanel : public ModelPanel
QVector startupSwitchesCheckboxes;
QVector potWarningCheckboxes;
QVector centerBeepCheckboxes;
- ModulePanel * modules[CPN_MAX_MODULES+1];
+ ModulePanel * modules[CPN_MAX_MODULES + 1];
TimerPanel * timers[CPN_MAX_TIMERS];
void updateStartupSwitches();
void updatePotWarnings();
void updateBeepCenter();
- void populateThrottleSourceCB();
+ void populateThrottleTrimSwitchCB();
int timersCount;
int selectedTimerIndex;
bool hasTimerClipboardData(QByteArray * data = nullptr) const;
@@ -183,6 +193,9 @@ class SetupPanel : public ModelPanel
bool moveTimerDownAllowed() const;
bool moveTimerUpAllowed() const;
void swapTimerData(int idx1, int idx2);
+ CompoundItemModelFactory * sharedItemModels;
+ void updateItemModels();
+ void connectItemModelEvents(const FilteredItemModel * itemModel);
+ CompoundItemModelFactory * panelItemModels;
+ FilteredItemModelFactory * panelFilteredModels;
};
-
-#endif // _SETUP_H_
diff --git a/companion/src/modeledit/setup.ui b/companion/src/modeledit/setup.ui
index fc499ad63..ee0ec28a3 100644
--- a/companion/src/modeledit/setup.ui
+++ b/companion/src/modeledit/setup.ui
@@ -6,7 +6,7 @@
0
0
- 893
+ 1007
405
@@ -32,22 +32,6 @@
- -
-
-
-
- 50
- false
-
-
-
- Top LCD Timer
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
-
-
@@ -149,6 +133,106 @@
+ -
+
+
+
+ 75
+ true
+
+
+
+ Model
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+
+ 50
+ false
+
+
+
+ Timer 3
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
-
+
+
+
+ 50
+ false
+
+
+
+ Throttle Source
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+
+ 50
+ false
+
+
+
+ Trim Step
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+
+ 50
+ false
+
+
+
+ Trims Display
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+
+
+ -
+
+
+
+ 50
+ false
+
+
+
+ Top LCD Timer
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
-
@@ -171,6 +255,66 @@
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ -
+
+
-
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
+
+ 50
+ false
+
+
+
+ Timer 2
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
-
-
@@ -275,44 +419,8 @@
- -
-
-
-
- 75
- true
-
-
-
- Model
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
-
-
- -
-
+
-
+
Qt::Horizontal
@@ -334,86 +442,13 @@
- -
-
-
- Qt::Horizontal
-
-
-
-
-
-
-
-
-
- Qt::LeftToRight
-
-
- Display Checklist
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
- Never
-
-
- -
-
- On change
-
-
- -
-
- Always
-
-
-
-
- -
-
-
- Qt::LeftToRight
-
-
- Throttle Trim Idle Only
-
-
-
- -
-
-
- Global Functions
-
-
-
- -
-
-
- Qt::LeftToRight
-
-
- Throttle Warning
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
+
+
+ 6
+
+
-
+
-
@@ -450,6 +485,81 @@
+ -
+
+
+
+ 0
+ 0
+
+
+
-
+
+ Never
+
+
+ -
+
+ On change
+
+
+ -
+
+ Always
+
+
+
+
+ -
+
+
+ Qt::LeftToRight
+
+
+ Throttle Warning
+
+
+
+ -
+
+
+ Qt::LeftToRight
+
+
+ Display Checklist
+
+
+
+ -
+
+
+ Global Functions
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Edit Checklist...
+
+
+
+ -
+
+
+ Qt::LeftToRight
+
+
+ Throttle Trim Idle Only
+
+
+
-
@@ -466,16 +576,10 @@ If this is checked the throttle will be reversed. Idle will be forward, trim wi
- -
-
-
-
- 0
- 0
-
-
+
-
+
- Edit Checklist...
+ Throttle trim switch
@@ -499,7 +603,17 @@ If this is checked the throttle will be reversed. Idle will be forward, trim wi
- -
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ -
Qt::Horizontal
@@ -514,107 +628,6 @@ If this is checked the throttle will be reversed. Idle will be forward, trim wi
- -
-
-
-
-
-
-
- 50
- false
-
-
-
- Throttle Source
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- 50
- false
-
-
-
- Trim Step
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- 50
- false
-
-
-
- Trims Display
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- -
-
-
-
- 50
- false
-
-
-
- Timer 2
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- 50
- false
-
-
-
- Timer 3
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
diff --git a/companion/src/modeledit/setup_module.ui b/companion/src/modeledit/setup_module.ui
index 654af2a54..652975acd 100644
--- a/companion/src/modeledit/setup_module.ui
+++ b/companion/src/modeledit/setup_module.ui
@@ -1077,7 +1077,21 @@
- -
+
-
+
+
+ Disable Telemetry
+
+
+
+ -
+
+
+ Racing Mode
+
+
+
+ -
Qt::Horizontal
@@ -1090,13 +1104,6 @@
- -
-
-
- Disable Telemetry
-
-
-
-
diff --git a/companion/src/modeledit/setup_timer.ui b/companion/src/modeledit/setup_timer.ui
index b6b920a10..67b929bdb 100644
--- a/companion/src/modeledit/setup_timer.ui
+++ b/companion/src/modeledit/setup_timer.ui
@@ -9,7 +9,7 @@
0
0
- 675
+ 874
33
@@ -20,11 +20,20 @@
6
-
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
0
-
-
+
80
@@ -34,7 +43,7 @@
-
-
+
true
@@ -47,7 +56,7 @@
-
-
+
-
@@ -60,7 +69,17 @@
-
-
+
+
+ Start
+
+
+
+ -
+
+
+ -
+
Minute Call
@@ -97,6 +116,21 @@
QComboBox
+
+ AutoLineEdit
+ QLineEdit
+
+
+
+ AutoCheckBox
+ QCheckBox
+
+
+
+ AutoTimeEdit
+ QTimeEdit
+
+
diff --git a/companion/src/modeledit/telemetry.cpp b/companion/src/modeledit/telemetry.cpp
index 99915eae5..bb32790b8 100644
--- a/companion/src/modeledit/telemetry.cpp
+++ b/companion/src/modeledit/telemetry.cpp
@@ -24,34 +24,46 @@
#include "ui_telemetry_sensor.h"
#include "helpers.h"
#include "appdata.h"
-#include "rawitemfilteredmodel.h"
#include
+constexpr char FIM_RAWSOURCE[] {"Raw Source"};
+constexpr char FIM_TELEALLSRC[] {"Tele All Source"};
+constexpr char FIM_TELEPOSSRC[] {"Tele Pos Source"};
+constexpr char FIM_SENSORTYPE[] {"Sensor.Type"};
+constexpr char FIM_SENSORFORMULA[] {"Sensor.Formula"};
+constexpr char FIM_SENSORCELLINDEX[] {"Sensor.CellIndex"};
+constexpr char FIM_SENSORUNIT[] {"Sensor.Unit"};
+constexpr char FIM_SENSORPRECISION[] {"Sensor.Precision"};
+constexpr char FIM_RSSISOURCE[] {"Rssi Source"};
-/******************************************************/
-
-TelemetryCustomScreen::TelemetryCustomScreen(QWidget *parent, ModelData & model, FrSkyScreenData & screen, GeneralSettings & generalSettings, Firmware * firmware, RawSourceFilterItemModel * srcModel):
+TelemetryCustomScreen::TelemetryCustomScreen(QWidget *parent, ModelData & model, FrSkyScreenData & screen, GeneralSettings & generalSettings,
+ Firmware * firmware, const bool & parentLock, FilteredItemModelFactory * panelFilteredItemModels):
ModelPanel(parent, model, generalSettings, firmware),
ui(new Ui::TelemetryCustomScreen),
- screen(screen)
+ screen(screen),
+ modelsUpdateCnt(0),
+ parentLock(parentLock)
{
ui->setupUi(this);
- for (int l=0; l<4; l++) {
- for (int c=0; cgetCapability(TelemetryCustomScreensFieldsPerLine); c++) {
+ FilteredItemModel * rawSourceFilteredModel = panelFilteredItemModels->getItemModel(FIM_RAWSOURCE);
+ connectItemModelEvents(rawSourceFilteredModel);
+
+ for (int l = 0; l < firmware->getCapability(TelemetryCustomScreensLines); l++) {
+ for (int c = 0; c < firmware->getCapability(TelemetryCustomScreensFieldsPerLine); c++) {
fieldsCB[l][c] = new QComboBox(this);
- fieldsCB[l][c]->setProperty("index", c + (l<<8));
- fieldsCB[l][c]->setModel(srcModel);
+ fieldsCB[l][c]->setProperty("index", c + (l << 8));
+ fieldsCB[l][c]->setModel(rawSourceFilteredModel);
ui->screenNumsLayout->addWidget(fieldsCB[l][c], l, c, 1, 1);
connect(fieldsCB[l][c], SIGNAL(activated(int)), this, SLOT(customFieldChanged(int)));
}
}
- for (int l=0; l<4; l++) {
+ for (int l = 0; l < firmware->getCapability(TelemetryCustomScreensBars); l++) {
barsCB[l] = new QComboBox(this);
barsCB[l]->setProperty("index", l);
- barsCB[l]->setModel(srcModel);
+ barsCB[l]->setModel(rawSourceFilteredModel);
connect(barsCB[l], SIGNAL(activated(int)), this, SLOT(barSourceChanged(int)));
ui->screenBarsLayout->addWidget(barsCB[l], l, 0, 1, 1);
@@ -100,7 +112,7 @@ TelemetryCustomScreen::TelemetryCustomScreen(QWidget *parent, ModelData & model,
lock = false;
if (IS_TARANIS(firmware->getBoard())) {
- QSet scriptsSet = getFilesSet(g.profile[g.id()].sdPath() + "/SCRIPTS/TELEMETRY", QStringList() << "*.lua", 8);
+ QSet scriptsSet = getFilesSet(g.profile[g.id()].sdPath() + "/SCRIPTS/TELEMETRY", QStringList() << "*.lua", 6);
Helpers::populateFileComboBox(ui->scriptName, scriptsSet, screen.body.script.filename);
connect(ui->scriptName, SIGNAL(currentIndexChanged(int)), this, SLOT(scriptNameEdited()));
connect(ui->scriptName, SIGNAL(editTextChanged ( const QString)), this, SLOT(scriptNameEdited()));
@@ -122,18 +134,18 @@ void TelemetryCustomScreen::update()
ui->screenNums->setVisible(screen.type == TELEMETRY_SCREEN_NUMBERS);
ui->screenBars->setVisible(screen.type == TELEMETRY_SCREEN_BARS);
- for (int l=0; l<4; l++) {
- for (int c=0; cgetCapability(TelemetryCustomScreensFieldsPerLine); c++) {
+ for (int l = 0; l < firmware->getCapability(TelemetryCustomScreensLines); l++) {
+ for (int c = 0; c < firmware->getCapability(TelemetryCustomScreensFieldsPerLine); c++) {
fieldsCB[l][c]->setCurrentIndex(fieldsCB[l][c]->findData(screen.body.lines[l].source[c].toValue()));
}
}
- for (int l=0; l<4; l++) {
+ for (int l = 0; l < firmware->getCapability(TelemetryCustomScreensBars); l++) {
barsCB[l]->setCurrentIndex(barsCB[l]->findData(screen.body.bars[l].source.toValue()));
}
if (screen.type == TELEMETRY_SCREEN_BARS) {
- for (int i=0; i<4; i++) {
+ for (int i = 0; i < firmware->getCapability(TelemetryCustomScreensBars); i++) {
updateBar(i);
}
}
@@ -204,7 +216,7 @@ void TelemetryCustomScreen::updateBar(int line)
void TelemetryCustomScreen::on_screenType_currentIndexChanged(int index)
{
- if (!lock) {
+ if (!isLocked()) {
memset(reinterpret_cast(&screen.body), 0, sizeof(screen.body));
update();
emit modified();
@@ -213,7 +225,7 @@ void TelemetryCustomScreen::on_screenType_currentIndexChanged(int index)
void TelemetryCustomScreen::scriptNameEdited()
{
- if (!lock) {
+ if (!isLocked()) {
lock = true;
Helpers::getFileComboBoxValue(ui->scriptName, screen.body.script.filename, 8);
emit modified();
@@ -223,7 +235,7 @@ void TelemetryCustomScreen::scriptNameEdited()
void TelemetryCustomScreen::customFieldChanged(int value)
{
- if (lock || !sender() || !qobject_cast(sender()))
+ if (isLocked() || !sender() || !qobject_cast(sender()))
return;
bool ok;
@@ -239,7 +251,7 @@ void TelemetryCustomScreen::customFieldChanged(int value)
void TelemetryCustomScreen::barSourceChanged(int value)
{
- if (lock || !sender() || !qobject_cast(sender()))
+ if (isLocked() || !sender() || !qobject_cast(sender()))
return;
bool ok;
@@ -257,7 +269,7 @@ void TelemetryCustomScreen::barSourceChanged(int value)
void TelemetryCustomScreen::barMinChanged(double value)
{
- if (!lock) {
+ if (!isLocked()) {
int line = sender()->property("index").toInt();
screen.body.bars[line].barMin = round(value / minSB[line]->singleStep());
// TODO set min (maxSB)
@@ -267,7 +279,7 @@ void TelemetryCustomScreen::barMinChanged(double value)
void TelemetryCustomScreen::barMaxChanged(double value)
{
- if (!lock) {
+ if (!isLocked()) {
int line = sender()->property("index").toInt();
screen.body.bars[line].barMax = round((value) / maxSB[line]->singleStep());
// TODO set max (minSB)
@@ -277,7 +289,7 @@ void TelemetryCustomScreen::barMaxChanged(double value)
void TelemetryCustomScreen::barTimeChanged()
{
- if (!lock) {
+ if (!isLocked()) {
int line = sender()->property("index").toInt();
int & valRef = (sender()->property("type").toString() == "min" ? screen.body.bars[line].barMin : screen.body.bars[line].barMax);
TimerEdit * te = qobject_cast(sender());
@@ -290,30 +302,73 @@ void TelemetryCustomScreen::barTimeChanged()
}
}
+void TelemetryCustomScreen::connectItemModelEvents(const FilteredItemModel * itemModel)
+{
+ connect(itemModel, &FilteredItemModel::aboutToBeUpdated, this, &TelemetryCustomScreen::onItemModelAboutToBeUpdated);
+ connect(itemModel, &FilteredItemModel::updateComplete, this, &TelemetryCustomScreen::onItemModelUpdateComplete);
+}
+
+void TelemetryCustomScreen::onItemModelAboutToBeUpdated()
+{
+ lock = true;
+ modelsUpdateCnt++;
+}
+
+void TelemetryCustomScreen::onItemModelUpdateComplete()
+{
+ modelsUpdateCnt--;
+ if (modelsUpdateCnt < 1) {
+ // leave updating to parent
+ lock = false;
+ }
+}
+
/******************************************************/
-TelemetrySensorPanel::TelemetrySensorPanel(QWidget *parent, SensorData & sensor, int sensorIndex, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware):
+TelemetrySensorPanel::TelemetrySensorPanel(QWidget *parent, SensorData & sensor, int sensorIndex, int sensorCapability, ModelData & model,
+ GeneralSettings & generalSettings, Firmware * firmware, const bool & parentLock,
+ FilteredItemModelFactory * panelFilteredItemModels) :
ModelPanel(parent, model, generalSettings, firmware),
ui(new Ui::TelemetrySensor),
sensor(sensor),
- lock(false),
sensorIndex(sensorIndex),
- selectedIndex(0)
+ selectedIndex(0),
+ sensorCapability(sensorCapability),
+ modelsUpdateCnt(0),
+ parentLock(parentLock)
{
ui->setupUi(this);
+ FilteredItemModel * fltmdl;
+
+ connectItemModelEvents(panelFilteredItemModels->getItemModel(FIM_TELEALLSRC));
+ connectItemModelEvents(panelFilteredItemModels->getItemModel(FIM_TELEPOSSRC));
+
+ lock = true;
ui->numLabel->setText(tr("TELE%1").arg(sensorIndex + 1));
ui->numLabel->setProperty("index", sensorIndex);
ui->numLabel->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
QFontMetrics *f = new QFontMetrics(QFont());
QSize sz;
sz = f->size(Qt::TextSingleLine, "TELE00");
+ delete f;
ui->numLabel->setMinimumWidth(sz.width());
ui->numLabel->setContextMenuPolicy(Qt::CustomContextMenu);
ui->numLabel->setToolTip(tr("Popup menu available"));
ui->numLabel->setMouseTracking(true);
connect(ui->numLabel, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(on_customContextMenuRequested(QPoint)));
+ ui->name->setField(sensor.label, SENSOR_LABEL_LEN);
+ connect(ui->name, SIGNAL(currentDataChanged()), this, SLOT(on_nameDataChanged()));
ui->id->setField(sensor.id, this);
ui->instance->setField(sensor.instance, this);
+ ui->type->setModel(panelFilteredItemModels->getItemModel(FIM_SENSORTYPE));
+ ui->type->setField(sensor.type);
+ connect(ui->type, SIGNAL(currentDataChanged(int)), this, SLOT(update()));
+ ui->formula->setModel(panelFilteredItemModels->getItemModel(FIM_SENSORFORMULA));
+ ui->formula->setField(sensor.formula);
+ connect(ui->formula, SIGNAL(currentDataChanged(int)), this, SLOT(on_formulaDataChanged()));
+ ui->unit->setModel(panelFilteredItemModels->getItemModel(FIM_SENSORUNIT));
+ ui->unit->setField(sensor.unit);
+ connect(ui->unit, SIGNAL(currentDataChanged(int)), this, SLOT(on_unitDataChanged()));
ui->ratio->setField(sensor.ratio, this);
ui->offset->setField(sensor.offset, this);
ui->autoOffset->setField(sensor.autoOffset, this);
@@ -321,21 +376,31 @@ TelemetrySensorPanel::TelemetrySensorPanel(QWidget *parent, SensorData & sensor,
ui->logs->setField(sensor.logs, this);
ui->persistent->setField(sensor.persistent, this);
ui->onlyPositive->setField(sensor.onlyPositive, this);
+ fltmdl = panelFilteredItemModels->getItemModel(FIM_TELEPOSSRC);
+ ui->gpsSensor->setModel(fltmdl);
ui->gpsSensor->setField(sensor.gps, this);
+ ui->altSensor->setModel(fltmdl);
ui->altSensor->setField(sensor.alt, this);
+ ui->ampsSensor->setModel(fltmdl);
ui->ampsSensor->setField(sensor.amps, this);
+ ui->cellsSensor->setModel(fltmdl);
ui->cellsSensor->setField(sensor.source, this);
- ui->cellsIndex->addItem(tr("Lowest"), SensorData::TELEM_CELL_INDEX_LOWEST);
- for (int i = 1; i <= 6; i++)
- ui->cellsIndex->addItem(tr("Cell %1").arg(i), i);
- ui->cellsIndex->addItem(tr("Highest"), SensorData::TELEM_CELL_INDEX_HIGHEST);
- ui->cellsIndex->addItem(tr("Delta"), SensorData::TELEM_CELL_INDEX_DELTA);
+ ui->cellsIndex->setModel(panelFilteredItemModels->getItemModel(FIM_SENSORCELLINDEX));
ui->cellsIndex->setField(sensor.index);
+ fltmdl = panelFilteredItemModels->getItemModel(FIM_TELEALLSRC);
+ ui->source1->setModel(fltmdl);
ui->source1->setField(sensor.sources[0], this);
+ ui->source2->setModel(fltmdl);
ui->source2->setField(sensor.sources[1], this);
+ ui->source3->setModel(fltmdl);
ui->source3->setField(sensor.sources[2], this);
+ ui->source4->setModel(fltmdl);
ui->source4->setField(sensor.sources[3], this);
- ui->prec->setField(sensor.prec, 0, 2, false, "", this);
+ ui->prec->setModel(panelFilteredItemModels->getItemModel(FIM_SENSORPRECISION));
+ ui->prec->setField(sensor.prec);
+ connect(ui->prec, SIGNAL(currentDataChanged(int)), this, SLOT(on_precDataChanged()));
+ lock = false;
+
update();
}
@@ -346,19 +411,13 @@ TelemetrySensorPanel::~TelemetrySensorPanel()
void TelemetrySensorPanel::update()
{
- bool isConfigurable = false;
- bool gpsFieldsDisplayed = false;
- bool cellsFieldsDisplayed = false;
- bool consFieldsDisplayed = false;
- bool ratioFieldsDisplayed = false;
- bool totalizeFieldsDisplayed = false;
- bool sources12FieldsDisplayed = false;
- bool sources34FieldsDisplayed = false;
-
lock = true;
- ui->name->setText(sensor.label);
- ui->type->setCurrentIndex(sensor.type);
- ui->unit->setCurrentIndex(sensor.unit);
+ int mask = sensor.getMask();
+
+ ui->name->updateValue();
+ ui->type->updateValue();
+ ui->formula->updateValue();
+ ui->unit->updateValue();
ui->id->updateValue();
ui->instance->updateValue();
ui->ratio->updateValue();
@@ -384,22 +443,11 @@ void TelemetrySensorPanel::update()
ui->originLabel->hide();
ui->origin->hide();
ui->formula->show();
- ui->formula->setCurrentIndex(sensor.formula);
- isConfigurable = (sensor.formula < SensorData::TELEM_FORMULA_CELL);
- gpsFieldsDisplayed = (sensor.formula == SensorData::TELEM_FORMULA_DIST);
- cellsFieldsDisplayed = (sensor.formula == SensorData::TELEM_FORMULA_CELL);
- consFieldsDisplayed = (sensor.formula == SensorData::TELEM_FORMULA_CONSUMPTION);
- sources12FieldsDisplayed = (sensor.formula <= SensorData::TELEM_FORMULA_MULTIPLY);
- sources34FieldsDisplayed = (sensor.formula < SensorData::TELEM_FORMULA_MULTIPLY);
- totalizeFieldsDisplayed = (sensor.formula == SensorData::TELEM_FORMULA_TOTALIZE);
- updateSourcesComboBox(ui->source1, true);
- updateSourcesComboBox(ui->source2, true);
- updateSourcesComboBox(ui->source3, true);
- updateSourcesComboBox(ui->source4, true);
- updateSourcesComboBox(ui->gpsSensor, false);
- updateSourcesComboBox(ui->altSensor, false);
- updateSourcesComboBox(ui->ampsSensor, false);
- updateSourcesComboBox(ui->cellsSensor, false);
+ ui->formula->setCurrentIndex(ui->formula->findData(sensor.formula));
+ ui->source1->updateValue();
+ ui->source2->updateValue();
+ ui->source3->updateValue();
+ ui->source4->updateValue();
}
else {
ui->idLabel->show();
@@ -410,154 +458,78 @@ void TelemetrySensorPanel::update()
ui->originLabel->setVisible(!origin.isEmpty());
ui->origin->setVisible(!origin.isEmpty());
ui->origin->setText(origin);
-
ui->formula->hide();
- isConfigurable = sensor.unit < SensorData::UNIT_FIRST_VIRTUAL;
- ratioFieldsDisplayed = (sensor.unit < SensorData::UNIT_FIRST_VIRTUAL);
- if (sensor.unit == SensorData::UNIT_RPMS) {
- if (ui->ratio->decimals()) {
- ui->ratio->setDecimals(0);
- ui->ratio->setMaximum(30000);
- ui->ratio->setMinimum(1);
- ui->ratio->setSingleStep(1);
- ui->offset->setDecimals(0);
- ui->offset->setMaximum(30000);
- ui->offset->setMinimum(1);
- ui->offset->setSingleStep(1);
- }
- }
- else {
- if (!ui->ratio->decimals()) {
- ui->ratio->setDecimals(1);
- ui->ratio->setMaximum(3000);
- ui->ratio->setMinimum(0);
- ui->ratio->setSingleStep(0.1);
- }
- if (ui->offset->decimals() != (int)sensor.prec) {
- ui->offset->setDecimals(sensor.prec);
- ui->offset->setMaximum(30000.0f / powf(10.0f, sensor.prec));
- ui->offset->setMinimum(-ui->offset->maximum());
- ui->offset->setSingleStep(pow(0.1, sensor.prec));
- }
- }
+ FieldRange rng = sensor.getRatioRange();
+ ui->ratio->setDecimals(rng.decimals);
+ ui->ratio->setMaximum(rng.max);
+ ui->ratio->setMinimum(rng.min);
+ ui->ratio->setSingleStep(rng.step);
+ rng = sensor.getOffsetRange();
+ ui->offset->setDecimals(rng.decimals);
+ ui->offset->setMaximum(rng.max);
+ ui->offset->setMinimum(rng.min);
+ ui->offset->setSingleStep(rng.step);
}
- ui->ratioLabel->setVisible(ratioFieldsDisplayed && sensor.unit != SensorData::UNIT_RPMS);
- ui->bladesLabel->setVisible(sensor.unit == SensorData::UNIT_RPMS);
- ui->ratio->setVisible(ratioFieldsDisplayed);
- ui->offsetLabel->setVisible(ratioFieldsDisplayed && sensor.unit != SensorData::UNIT_RPMS);
- ui->multiplierLabel->setVisible(sensor.unit == SensorData::UNIT_RPMS);
- ui->offset->setVisible(ratioFieldsDisplayed);
- ui->precLabel->setVisible(isConfigurable && sensor.unit != SensorData::UNIT_FAHRENHEIT);
- ui->prec->setVisible(isConfigurable && sensor.unit != SensorData::UNIT_FAHRENHEIT);
- ui->unit->setVisible((sensor.type == SensorData::TELEM_TYPE_CALCULATED && (sensor.formula == SensorData::TELEM_FORMULA_DIST)) || isConfigurable);
- ui->gpsSensorLabel->setVisible(gpsFieldsDisplayed);
- ui->gpsSensor->setVisible(gpsFieldsDisplayed);
- ui->altSensorLabel->setVisible(gpsFieldsDisplayed);
- ui->altSensor->setVisible(gpsFieldsDisplayed);
- ui->ampsSensorLabel->setVisible(consFieldsDisplayed || totalizeFieldsDisplayed);
- ui->ampsSensor->setVisible(consFieldsDisplayed || totalizeFieldsDisplayed);
- ui->cellsSensorLabel->setVisible(cellsFieldsDisplayed);
- ui->cellsSensor->setVisible(cellsFieldsDisplayed);
- ui->cellsIndex->setVisible(cellsFieldsDisplayed);
- ui->source1->setVisible(sources12FieldsDisplayed);
- ui->source2->setVisible(sources12FieldsDisplayed);
- ui->source3->setVisible(sources34FieldsDisplayed);
- ui->source4->setVisible(sources34FieldsDisplayed);
- ui->autoOffset->setVisible(sensor.unit != SensorData::UNIT_RPMS && isConfigurable);
- ui->filter->setVisible(isConfigurable);
- ui->persistent->setVisible(sensor.type == SensorData::TELEM_TYPE_CALCULATED);
+ ui->ratioLabel->setVisible(mask & SENSOR_HAS_RATIO && sensor.unit != SensorData::UNIT_RPMS);
+ ui->bladesLabel->setVisible(mask & SENSOR_HAS_RATIO && sensor.unit == SensorData::UNIT_RPMS);
+ ui->ratio->setVisible(mask & SENSOR_HAS_RATIO);
+
+ ui->offsetLabel->setVisible(mask & SENSOR_HAS_RATIO && sensor.unit != SensorData::UNIT_RPMS);
+ ui->multiplierLabel->setVisible(mask & SENSOR_HAS_RATIO && sensor.unit == SensorData::UNIT_RPMS);
+ ui->offset->setVisible(mask & SENSOR_HAS_RATIO);
+
+ ui->precLabel->setVisible(mask & SENSOR_HAS_PRECISION);
+ ui->prec->setVisible(mask & SENSOR_HAS_PRECISION);
+
+ ui->unit->setVisible(mask & SENSOR_ISCONFIGURABLE);
+
+ ui->gpsSensorLabel->setVisible(mask & SENSOR_HAS_GPS);
+ ui->gpsSensor->setVisible(mask & SENSOR_HAS_GPS);
+
+ ui->altSensorLabel->setVisible(mask & SENSOR_HAS_GPS);
+ ui->altSensor->setVisible(mask & SENSOR_HAS_GPS);
+
+ ui->ampsSensorLabel->setVisible(mask & SENSOR_HAS_CONSUMPTION || mask & SENSOR_HAS_TOTALIZE);
+ ui->ampsSensor->setVisible(mask & SENSOR_HAS_CONSUMPTION || mask & SENSOR_HAS_TOTALIZE);
+
+ ui->cellsSensorLabel->setVisible(mask & SENSOR_HAS_CELLS);
+ ui->cellsSensor->setVisible(mask & SENSOR_HAS_CELLS);
+ ui->cellsIndex->setVisible(mask & SENSOR_HAS_CELLS);
+
+ ui->source1->setVisible(mask & SENSOR_HAS_SOURCES_12);
+ ui->source2->setVisible(mask & SENSOR_HAS_SOURCES_12);
+ ui->source3->setVisible(mask & SENSOR_HAS_SOURCES_34);
+ ui->source4->setVisible(mask & SENSOR_HAS_SOURCES_34);
+
+ ui->autoOffset->setEnabled(mask & SENSOR_HAS_RATIO && sensor.unit != SensorData::UNIT_RPMS);
+ ui->onlyPositive->setEnabled(mask & SENSOR_HAS_POSITIVE);
+ ui->filter->setEnabled(mask & SENSOR_ISCONFIGURABLE);
+ ui->persistent->setEnabled(sensor.type == SensorData::TELEM_TYPE_CALCULATED);
lock = false;
}
-void populateTelemetrySourcesComboBox(AutoComboBox * cb, const ModelData * model, bool negative)
+void TelemetrySensorPanel::on_nameDataChanged()
{
- cb->clear();
- if (negative) {
- for (int i=-CPN_MAX_SENSORS; i<0; ++i) {
- const SensorData& sensor = model->sensorData[-i-1];
- if (sensor.isAvailable()) {
- if (sensor.type == SensorData::TELEM_TYPE_CUSTOM)
- cb->addItem(QString("-%1 (%2)").arg(sensor.label, sensor.getOrigin(model)), i);
- else
- cb->addItem(QString("-%1").arg(sensor.label), i);
- }
- }
- }
- cb->addItem("---", 0);
- for (unsigned i=1; i<=CPN_MAX_SENSORS; ++i) {
- const SensorData& sensor = model->sensorData[i-1];
- if (sensor.isAvailable()) {
- if (sensor.type == SensorData::TELEM_TYPE_CUSTOM)
- cb->addItem(QString("%1 (%2)").arg(sensor.label, sensor.getOrigin(model)), i);
- else
- cb->addItem(QString("%1").arg(sensor.label), i);
- }
- }
+ emit dataModified();
}
-void TelemetrySensorPanel::updateSourcesComboBox(AutoComboBox * cb, bool negative)
+void TelemetrySensorPanel::on_formulaDataChanged()
{
- populateTelemetrySourcesComboBox(cb, model, negative);
+ sensor.formulaChanged();
+ update();
}
-void TelemetrySensorPanel::on_name_editingFinished()
+void TelemetrySensorPanel::on_unitDataChanged()
{
- if (!lock) {
- strcpy(sensor.label, ui->name->text().toLatin1());
- emit dataModified();
- emit modified();
- }
+ sensor.unitChanged();
+ update();
}
-void TelemetrySensorPanel::on_type_currentIndexChanged(int index)
+void TelemetrySensorPanel::on_precDataChanged()
{
- if (!lock) {
- sensor.type = index;
- update();
- emit modified();
- }
-}
-
-void TelemetrySensorPanel::on_formula_currentIndexChanged(int index)
-{
- if (!lock) {
- sensor.formula = index;
- if (sensor.formula == SensorData::TELEM_FORMULA_CELL) {
- sensor.prec = 2;
- sensor.unit = SensorData::UNIT_VOLTS;
- }
- else if (sensor.formula == SensorData::TELEM_FORMULA_CONSUMPTION) {
- sensor.prec = 0;
- sensor.unit = SensorData::UNIT_MAH;
- }
- else if (sensor.formula == SensorData::TELEM_FORMULA_DIST) {
- sensor.prec = 0;
- sensor.unit = SensorData::UNIT_METERS;
- }
- emit dataModified();
- emit modified();
- }
-}
-
-void TelemetrySensorPanel::on_unit_currentIndexChanged(int index)
-{
- if (!lock) {
- sensor.unit = index;
- if (sensor.unit == SensorData::UNIT_FAHRENHEIT) {
- sensor.prec = 0;
- }
- update();
- emit modified();
- }
-}
-
-void TelemetrySensorPanel::on_prec_valueChanged()
-{
- if (!lock) {
- update();
- }
+ update();
}
void TelemetrySensorPanel::on_customContextMenuRequested(QPoint pos)
@@ -572,6 +544,11 @@ void TelemetrySensorPanel::on_customContextMenuRequested(QPoint pos)
contextMenu.addAction(CompanionIcon("paste.png"), tr("Paste"),this,SLOT(cmPaste()))->setEnabled(hasClipboardData());
contextMenu.addAction(CompanionIcon("clear.png"), tr("Clear"),this,SLOT(cmClear()));
contextMenu.addSeparator();
+ contextMenu.addAction(CompanionIcon("arrow-right.png"), tr("Insert"),this,SLOT(cmInsert()))->setEnabled(insertAllowed());
+ contextMenu.addAction(CompanionIcon("arrow-left.png"), tr("Delete"),this,SLOT(cmDelete()));
+ contextMenu.addAction(CompanionIcon("moveup.png"), tr("Move Up"),this,SLOT(cmMoveUp()))->setEnabled(moveUpAllowed());
+ contextMenu.addAction(CompanionIcon("movedown.png"), tr("Move Down"),this,SLOT(cmMoveDown()))->setEnabled(moveDownAllowed());
+ contextMenu.addSeparator();
contextMenu.addAction(CompanionIcon("clear.png"), tr("Clear All"),this,SLOT(cmClearAll()));
contextMenu.exec(globalPos);
@@ -589,6 +566,21 @@ bool TelemetrySensorPanel::hasClipboardData(QByteArray * data) const
return false;
}
+bool TelemetrySensorPanel::insertAllowed() const
+{
+ return ((selectedIndex < sensorCapability - 1) && (model->sensorData[sensorCapability - 1].isEmpty()));
+}
+
+bool TelemetrySensorPanel::moveDownAllowed() const
+{
+ return selectedIndex < sensorCapability - 1;
+}
+
+bool TelemetrySensorPanel::moveUpAllowed() const
+{
+ return selectedIndex > 0;
+}
+
void TelemetrySensorPanel::cmCopy()
{
QByteArray data;
@@ -600,8 +592,11 @@ void TelemetrySensorPanel::cmCopy()
void TelemetrySensorPanel::cmCut()
{
+ if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Cut Telemetry Sensor. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
+ return;
+
cmCopy();
- cmClear();
+ cmClear(false);
}
void TelemetrySensorPanel::cmPaste()
@@ -610,18 +605,19 @@ void TelemetrySensorPanel::cmPaste()
if (hasClipboardData(&data)) {
memcpy(&sensor, data.constData(), sizeof(SensorData));
emit dataModified();
- emit modified();
}
}
-void TelemetrySensorPanel::cmClear()
+void TelemetrySensorPanel::cmClear(bool prompt)
{
- if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear Telemetry Sensor. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
- return;
+ if (prompt) {
+ if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear Telemetry Sensor. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
+ return;
+ }
sensor.clear();
+ model->updateAllReferences(ModelData::REF_UPD_TYPE_SENSOR, ModelData::REF_UPD_ACT_CLEAR, selectedIndex);
emit dataModified();
- emit modified();
}
void TelemetrySensorPanel::cmClearAll()
@@ -632,48 +628,139 @@ void TelemetrySensorPanel::cmClearAll()
emit clearAllSensors();
}
+void TelemetrySensorPanel::cmInsert()
+{
+ emit insertSensor(selectedIndex);
+}
+
+void TelemetrySensorPanel::cmDelete()
+{
+ emit deleteSensor(selectedIndex);
+}
+
+void TelemetrySensorPanel::cmMoveUp()
+{
+ emit moveUpSensor(selectedIndex);
+}
+
+void TelemetrySensorPanel::cmMoveDown()
+{
+ emit moveDownSensor(selectedIndex);
+}
+
+void TelemetrySensorPanel::connectItemModelEvents(const FilteredItemModel * itemModel)
+{
+ connect(itemModel, &FilteredItemModel::aboutToBeUpdated, this, &TelemetrySensorPanel::onItemModelAboutToBeUpdated);
+ connect(itemModel, &FilteredItemModel::updateComplete, this, &TelemetrySensorPanel::onItemModelUpdateComplete);
+}
+
+void TelemetrySensorPanel::onItemModelAboutToBeUpdated()
+{
+ lock = true;
+ modelsUpdateCnt++;
+}
+
+void TelemetrySensorPanel::onItemModelUpdateComplete()
+{
+ modelsUpdateCnt--;
+ if (modelsUpdateCnt < 1) {
+ // leave updating to parent
+ lock = false;
+ }
+}
+
/******************************************************/
-TelemetryPanel::TelemetryPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware):
+TelemetryPanel::TelemetryPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware,
+ CompoundItemModelFactory * sharedItemModels):
ModelPanel(parent, model, generalSettings, firmware),
- ui(new Ui::Telemetry)
+ ui(new Ui::Telemetry),
+ sharedItemModels(sharedItemModels),
+ modelsUpdateCnt(0)
{
ui->setupUi(this);
+ panelItemModels = new CompoundItemModelFactory(&generalSettings, &model);
+ panelFilteredItemModels = new FilteredItemModelFactory();
+ int id;
+
+ id = panelFilteredItemModels->registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_RawSource)),
+ FIM_RAWSOURCE);
+ connectItemModelEvents(id);
+
+ id = panelFilteredItemModels->registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_TeleSource)),
+ FIM_TELEALLSRC);
+ connectItemModelEvents(id);
+
+ id = panelFilteredItemModels->registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_TeleSource),
+ FilteredItemModel::PositiveFilter),
+ FIM_TELEPOSSRC);
+ connectItemModelEvents(id);
+
+
+ id = panelFilteredItemModels->registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_RssiSource)),
+ FIM_RSSISOURCE);
+ connectItemModelEvents(id);
+
+ id = panelItemModels->registerItemModel(SensorData::typeItemModel());
+ panelFilteredItemModels->registerItemModel(new FilteredItemModel(panelItemModels->getItemModel(id)), FIM_SENSORTYPE);
+
+ id = panelItemModels->registerItemModel(SensorData::formulaItemModel());
+ panelFilteredItemModels->registerItemModel(new FilteredItemModel(panelItemModels->getItemModel(id)), FIM_SENSORFORMULA);
+
+ id = panelItemModels->registerItemModel(SensorData::cellIndexItemModel());
+ panelFilteredItemModels->registerItemModel(new FilteredItemModel(panelItemModels->getItemModel(id)), FIM_SENSORCELLINDEX);
+
+ id = panelItemModels->registerItemModel(SensorData::unitItemModel());
+ panelFilteredItemModels->registerItemModel(new FilteredItemModel(panelItemModels->getItemModel(id)), FIM_SENSORUNIT);
+
+ id = panelItemModels->registerItemModel(SensorData::precisionItemModel());
+ panelFilteredItemModels->registerItemModel(new FilteredItemModel(panelItemModels->getItemModel(id)), FIM_SENSORPRECISION);
+
+ sensorCapability = firmware->getCapability(Sensors);
+ if (sensorCapability > CPN_MAX_SENSORS) // TODO should be role of getCapability
+ sensorCapability = CPN_MAX_SENSORS;
+
if (firmware->getCapability(NoTelemetryProtocol)) {
model.frsky.usrProto = 1;
}
+ ui->varioSource->setModel(panelFilteredItemModels->getItemModel(FIM_TELEPOSSRC));
ui->varioSource->setField(model.frsky.varioSource, this);
ui->varioCenterSilent->setField(model.frsky.varioCenterSilent, this);
ui->A1GB->hide();
ui->A2GB->hide();
- for (unsigned i= 0; i < CPN_MAX_SENSORS; ++i) {
- TelemetrySensorPanel * panel = new TelemetrySensorPanel(this, model.sensorData[i], i, model, generalSettings, firmware);
+
+ for (int i = 0; i < sensorCapability; ++i) {
+ TelemetrySensorPanel * panel = new TelemetrySensorPanel(this, model.sensorData[i], i, sensorCapability, model, generalSettings,
+ firmware, lock, panelFilteredItemModels);
ui->sensorsLayout->addWidget(panel);
sensorPanels[i] = panel;
- connect(panel, SIGNAL(dataModified()), this, SLOT(update()));
+ connect(panel, SIGNAL(dataModified()), this, SLOT(on_dataModifiedSensor()));
connect(panel, SIGNAL(modified()), this, SLOT(onModified()));
connect(panel, SIGNAL(clearAllSensors()), this, SLOT(on_clearAllSensors()));
+ connect(panel, SIGNAL(insertSensor(int)), this, SLOT(on_insertSensor(int)));
+ connect(panel, SIGNAL(deleteSensor(int)), this, SLOT(on_deleteSensor(int)));
+ connect(panel, SIGNAL(moveUpSensor(int)), this, SLOT(on_moveUpSensor(int)));
+ connect(panel, SIGNAL(moveDownSensor(int)), this, SLOT(on_moveDownSensor(int)));
}
if (IS_TARANIS_X9(firmware->getBoard())) {
+ ui->voltsSource->setModel(panelFilteredItemModels->getItemModel(FIM_TELEPOSSRC));
ui->voltsSource->setField(model.frsky.voltsSource, this);
+ ui->altitudeSource->setModel(panelFilteredItemModels->getItemModel(FIM_TELEPOSSRC));
ui->altitudeSource->setField(model.frsky.altitudeSource, this);
}
else {
ui->topbarGB->hide();
}
- RawSourceFilterItemModel * srcModel = (new RawSourceFilterItemModel(&generalSettings, &model, this));
- connect(this, &TelemetryPanel::updated, srcModel, &RawSourceFilterItemModel::update);
-
for (int i = 0; i < firmware->getCapability(TelemetryCustomScreens); i++) {
- TelemetryCustomScreen * tab = new TelemetryCustomScreen(this, model, model.frsky.screens[i], generalSettings, firmware, srcModel);
- ui->customScreens->addTab(tab, tr("Telemetry screen %1").arg(i+1));
+ TelemetryCustomScreen * tab = new TelemetryCustomScreen(this, model, model.frsky.screens[i], generalSettings, firmware, lock,
+ panelFilteredItemModels);
+ ui->customScreens->addTab(tab, tr("Telemetry screen %1").arg(i + 1));
telemetryCustomScreens[i] = tab;
connect(tab, &TelemetryCustomScreen::modified, this, &TelemetryPanel::onModified);
- connect(this, &TelemetryPanel::updated, tab, &TelemetryCustomScreen::update);
}
disableMouseScrolling();
@@ -684,10 +771,14 @@ TelemetryPanel::TelemetryPanel(QWidget *parent, ModelData & model, GeneralSettin
TelemetryPanel::~TelemetryPanel()
{
delete ui;
+ delete panelFilteredItemModels;
+ delete panelItemModels;
}
void TelemetryPanel::update()
{
+ lock = true;
+
if (IS_HORUS_OR_TARANIS(firmware->getBoard())) {
if (model->moduleData[0].protocol == PULSES_OFF && model->moduleData[1].protocol == PULSES_PPM) {
ui->telemetryProtocol->setEnabled(true);
@@ -697,129 +788,97 @@ void TelemetryPanel::update()
ui->telemetryProtocol->setCurrentIndex(0);
}
- populateTelemetrySourcesComboBox(ui->rssiSourceCB, model, false);
- populateTelemetrySourcesComboBox(ui->voltsSource, model, false);
- populateTelemetrySourcesComboBox(ui->altitudeSource, model, false);
- populateTelemetrySourcesComboBox(ui->varioSource, model, false);
+ ui->rssiSourceCB->updateValue();
+ ui->voltsSource->updateValue();
+ ui->altitudeSource->updateValue();
+ ui->varioSource->updateValue();
}
- for (unsigned i=0; iupdate();
}
- emit updated();
+ for (int i = 0; i < firmware->getCapability(TelemetryCustomScreens); i++) {
+ telemetryCustomScreens[i]->update();
+ }
+
+ lock = false;
}
void TelemetryPanel::setup()
{
- QString firmware_id = g.profile[g.id()].fwType();
+ lock = true;
- lock = true;
+ ui->telemetryProtocol->addItem(tr("FrSky S.PORT"), 0);
+ ui->telemetryProtocol->addItem(tr("FrSky D"), 1);
+ if (IS_9XRPRO(firmware->getBoard()) ||
+ (IS_TARANIS(firmware->getBoard()) && generalSettings.auxSerialMode == 2)) {
+ ui->telemetryProtocol->addItem(tr("FrSky D (cable)"), 2);
+ }
+ ui->telemetryProtocol->setCurrentIndex(model->telemetryProtocol);
+ ui->ignoreSensorIds->setField(model->frsky.ignoreSensorIds, this);
+ ui->disableTelemetryAlarms->setField(model->rssiAlarms.disabled);
- ui->telemetryProtocol->addItem(tr("FrSky S.PORT"), 0);
- ui->telemetryProtocol->addItem(tr("FrSky D"), 1);
- if (IS_9XRPRO(firmware->getBoard()) ||
- (IS_TARANIS(firmware->getBoard()) && generalSettings.auxSerialMode == 2)) {
- ui->telemetryProtocol->addItem(tr("FrSky D (cable)"), 2);
- }
- ui->telemetryProtocol->setCurrentIndex(model->telemetryProtocol);
- ui->ignoreSensorIds->setField(model->frsky.ignoreSensorIds, this);
- ui->disableTelemetryAlarms->setField(model->rssiAlarms.disabled);
+ ui->rssiAlarmWarningSB->setRange(45 - 30, 45 + 30);
+ ui->rssiAlarmWarningSB->setValue(model->rssiAlarms.warning);
+ ui->rssiAlarmCriticalSB->setRange(42 - 30, 42 + 30);
+ ui->rssiAlarmCriticalSB->setValue(model->rssiAlarms.critical);
- ui->rssiAlarmWarningSB->setValue(model->rssiAlarms.warning);
- ui->rssiAlarmCriticalSB->setValue(model->rssiAlarms.critical);
+ ui->rssiSourceLabel->show();
+ ui->rssiSourceLabel->setText(tr("Source"));
+ ui->rssiSourceCB->setModel(panelFilteredItemModels->getItemModel(FIM_RSSISOURCE));
+ ui->rssiSourceCB->setField(model->rssiSource, this);
+ ui->rssiSourceCB->show();
- ui->rssiSourceLabel->show();
- ui->rssiSourceLabel->setText(tr("Source"));
- ui->rssiSourceCB->setField(model->rssiSource, this);
- ui->rssiSourceCB->show();
- populateTelemetrySourcesComboBox(ui->rssiSourceCB, model, false);
+ ui->rssiAlarmWarningCB->hide();
+ ui->rssiAlarmCriticalCB->hide();
+ ui->rssiAlarmWarningLabel->setText(tr("Low Alarm"));
+ ui->rssiAlarmCriticalLabel->setText(tr("Critical Alarm"));
- ui->rssiAlarmWarningCB->hide();
- ui->rssiAlarmCriticalCB->hide();
- ui->rssiAlarmWarningLabel->setText(tr("Low Alarm"));
- ui->rssiAlarmCriticalLabel->setText(tr("Critical Alarm"));
-
- int varioCap = firmware->getCapability(HasVario);
- if (!varioCap) {
- ui->varioLimitMax_DSB->hide();
+ if (!firmware->getCapability(HasVario)) {
+ ui->varioLimitMax_DSB->hide();
+ ui->varioLimitMin_DSB->hide();
+ ui->varioLimitCenterMin_DSB->hide();
+ ui->varioLimitCenterMax_DSB->hide();
+ ui->varioLimit_label->hide();
+ ui->VarioLabel_1->hide();
+ ui->VarioLabel_2->hide();
+ ui->VarioLabel_3->hide();
+ ui->VarioLabel_4->hide();
+ ui->varioSource->hide();
+ ui->varioSource_label->hide();
+ }
+ else {
+ if (!firmware->getCapability(HasVarioSink)) {
ui->varioLimitMin_DSB->hide();
ui->varioLimitCenterMin_DSB->hide();
- ui->varioLimitCenterMax_DSB->hide();
- ui->varioLimit_label->hide();
ui->VarioLabel_1->hide();
ui->VarioLabel_2->hide();
- ui->VarioLabel_3->hide();
- ui->VarioLabel_4->hide();
- ui->varioSource->hide();
- ui->varioSource_label->hide();
- }
- else {
- if (!firmware->getCapability(HasVarioSink)) {
- ui->varioLimitMin_DSB->hide();
- ui->varioLimitCenterMin_DSB->hide();
- ui->VarioLabel_1->hide();
- ui->VarioLabel_2->hide();
- }
- ui->varioLimitMin_DSB->setValue(model->frsky.varioMin-10);
- ui->varioLimitMax_DSB->setValue(model->frsky.varioMax+10);
- ui->varioLimitCenterMax_DSB->setValue((model->frsky.varioCenterMax/10.0)+0.5);
- ui->varioLimitCenterMin_DSB->setValue((model->frsky.varioCenterMin/10.0)-0.5);
}
+ ui->varioLimitMin_DSB->setValue(model->frsky.varioMin - 10);
+ ui->varioLimitMax_DSB->setValue(model->frsky.varioMax + 10);
+ ui->varioLimitCenterMax_DSB->setValue((model->frsky.varioCenterMax / 10.0) + 0.5);
+ ui->varioLimitCenterMin_DSB->setValue((model->frsky.varioCenterMin / 10.0) - 0.5);
+ }
- ui->altimetryGB->setVisible(firmware->getCapability(HasVario)),
- ui->frskyProtoCB->setDisabled(firmware->getCapability(NoTelemetryProtocol));
+ ui->altimetryGB->setVisible(firmware->getCapability(HasVario)),
+ ui->frskyProtoCB->setDisabled(firmware->getCapability(NoTelemetryProtocol));
- if (firmware->getCapability(Telemetry)) {
- ui->frskyProtoCB->addItem(tr("Winged Shadow How High"));
- }
- else {
- ui->frskyProtoCB->addItem(tr("Winged Shadow How High (not supported)"));
- }
+ if (firmware->getCapability(Telemetry)) {
+ ui->frskyProtoCB->addItem(tr("Winged Shadow How High"));
+ }
+ else {
+ ui->frskyProtoCB->addItem(tr("Winged Shadow How High (not supported)"));
+ }
- ui->variousGB->hide();
+ ui->variousGB->hide();
- lock = false;
-}
-
-void TelemetryPanel::populateVarioSource()
-{
- AutoComboBox * cb = ui->varioSource;
- cb->setField(model->frsky.varioSource, this);
- cb->addItem(tr("Alti"), TELEMETRY_VARIO_SOURCE_ALTI);
- cb->addItem(tr("Alti+"), TELEMETRY_VARIO_SOURCE_ALTI_PLUS);
- cb->addItem(tr("VSpeed"), TELEMETRY_VARIO_SOURCE_VSPEED);
- cb->addItem(tr("A1"), TELEMETRY_VARIO_SOURCE_A1);
- cb->addItem(tr("A2"), TELEMETRY_VARIO_SOURCE_A2);
-}
-
-void TelemetryPanel::populateVoltsSource()
-{
- AutoComboBox * cb = ui->frskyVoltCB;
- cb->setField(model->frsky.voltsSource, this);
- cb->addItem(tr("A1"), TELEMETRY_VOLTS_SOURCE_A1);
- cb->addItem(tr("A2"), TELEMETRY_VOLTS_SOURCE_A2);
- cb->addItem(tr("A3"), TELEMETRY_VOLTS_SOURCE_A3);
- cb->addItem(tr("A4"), TELEMETRY_VOLTS_SOURCE_A4);
- cb->addItem(tr("FAS"), TELEMETRY_VOLTS_SOURCE_FAS);
- cb->addItem(tr("Cells"), TELEMETRY_VOLTS_SOURCE_CELLS);
-}
-
-void TelemetryPanel::populateCurrentSource()
-{
- AutoComboBox * cb = ui->frskyCurrentCB;
- cb->setField(model->frsky.currentSource, this);
- cb->addItem(tr("---"), TELEMETRY_CURRENT_SOURCE_NONE);
- cb->addItem(tr("A1"), TELEMETRY_CURRENT_SOURCE_A1);
- cb->addItem(tr("A2"), TELEMETRY_CURRENT_SOURCE_A2);
- cb->addItem(tr("A3"), TELEMETRY_CURRENT_SOURCE_A3);
- cb->addItem(tr("A4"), TELEMETRY_CURRENT_SOURCE_A4);
- cb->addItem(tr("FAS"), TELEMETRY_CURRENT_SOURCE_FAS);
+ lock = false;
}
void TelemetryPanel::on_telemetryProtocol_currentIndexChanged(int index)
{
- if (!lock) {
+ if (!isLocked()) {
model->telemetryProtocol = index;
emit modified();
}
@@ -832,7 +891,7 @@ void TelemetryPanel::onModified()
void TelemetryPanel::on_bladesCount_editingFinished()
{
- if (!lock) {
+ if (!isLocked()) {
model->frsky.blades = ui->bladesCount->value();
emit modified();
}
@@ -840,9 +899,9 @@ void TelemetryPanel::on_bladesCount_editingFinished()
void TelemetryPanel::on_frskyProtoCB_currentIndexChanged(int index)
{
- if (!lock) {
+ if (!isLocked()) {
model->frsky.usrProto = index;
- for (int i=0; igetCapability(TelemetryCustomScreens); i++)
+ for (int i = 0; i < firmware->getCapability(TelemetryCustomScreens); i++)
telemetryCustomScreens[i]->update();
emit modified();
}
@@ -850,75 +909,159 @@ void TelemetryPanel::on_frskyProtoCB_currentIndexChanged(int index)
void TelemetryPanel::on_rssiAlarmWarningSB_editingFinished()
{
- model->rssiAlarms.warning= ui->rssiAlarmWarningSB->value();
- emit modified();
+ if (!isLocked()) {
+ model->rssiAlarms.warning= ui->rssiAlarmWarningSB->value();
+ emit modified();
+ }
}
void TelemetryPanel::on_rssiAlarmCriticalSB_editingFinished()
{
- model->rssiAlarms.critical = ui->rssiAlarmCriticalSB->value();
- emit modified();
+ if (!isLocked()) {
+ model->rssiAlarms.critical = ui->rssiAlarmCriticalSB->value();
+ emit modified();
+ }
}
void TelemetryPanel::on_varioLimitMin_DSB_editingFinished()
{
- model->frsky.varioMin = round(ui->varioLimitMin_DSB->value()+10);
- emit modified();
+ if (!isLocked()) {
+ model->frsky.varioMin = round(ui->varioLimitMin_DSB->value() + 10);
+ emit modified();
+ }
}
void TelemetryPanel::on_varioLimitMax_DSB_editingFinished()
{
- model->frsky.varioMax = round(ui->varioLimitMax_DSB->value()-10);
- emit modified();
+ if (!isLocked()) {
+ model->frsky.varioMax = round(ui->varioLimitMax_DSB->value() - 10);
+ emit modified();
+ }
}
void TelemetryPanel::on_varioLimitCenterMin_DSB_editingFinished()
{
- if (!lock) {
- if (ui->varioLimitCenterMin_DSB->value()>ui->varioLimitCenterMax_DSB->value()) {
+ if (!isLocked()) {
+ if (ui->varioLimitCenterMin_DSB->value() > ui->varioLimitCenterMax_DSB->value()) {
ui->varioLimitCenterMax_DSB->setValue(ui->varioLimitCenterMin_DSB->value());
}
- model->frsky.varioCenterMin = round((ui->varioLimitCenterMin_DSB->value()+0.5)*10);
+ model->frsky.varioCenterMin = round((ui->varioLimitCenterMin_DSB->value() + 0.5) * 10);
emit modified();
}
}
void TelemetryPanel::on_varioLimitCenterMax_DSB_editingFinished()
{
- if (!lock) {
- if (ui->varioLimitCenterMin_DSB->value()>ui->varioLimitCenterMax_DSB->value()) {
+ if (!isLocked()) {
+ if (ui->varioLimitCenterMin_DSB->value() > ui->varioLimitCenterMax_DSB->value()) {
ui->varioLimitCenterMax_DSB->setValue(ui->varioLimitCenterMin_DSB->value());
}
- model->frsky.varioCenterMax = round((ui->varioLimitCenterMax_DSB->value()-0.5)*10);
+ model->frsky.varioCenterMax = round((ui->varioLimitCenterMax_DSB->value() - 0.5) * 10);
emit modified();
}
}
void TelemetryPanel::on_fasOffset_DSB_editingFinished()
{
- model->frsky.fasOffset = ui->fasOffset_DSB->value() * 10;
- emit modified();
+ if (!isLocked()) {
+ model->frsky.fasOffset = ui->fasOffset_DSB->value() * 10;
+ emit modified();
+ }
}
void TelemetryPanel::on_mahCount_SB_editingFinished()
{
- model->frsky.storedMah = ui->mahCount_SB->value();
- emit modified();
+ if (!isLocked()) {
+ model->frsky.storedMah = ui->mahCount_SB->value();
+ emit modified();
+ }
}
void TelemetryPanel::on_mahCount_ChkB_toggled(bool checked)
{
- model->frsky.mAhPersistent = checked;
- ui->mahCount_SB->setDisabled(!checked);
- emit modified();
+ if (!isLocked()) {
+ model->frsky.mAhPersistent = checked;
+ ui->mahCount_SB->setDisabled(!checked);
+ emit modified();
+ }
}
void TelemetryPanel::on_clearAllSensors()
{
for (int i = 0; i < CPN_MAX_SENSORS; i++) {
model->sensorData[i].clear();
+ model->updateAllReferences(ModelData::REF_UPD_TYPE_SENSOR, ModelData::REF_UPD_ACT_CLEAR, i);
}
- update();
+ on_dataModifiedSensor();
+}
+
+void TelemetryPanel::on_insertSensor(int selectedIndex)
+{
+ memmove(&model->sensorData[selectedIndex + 1], &model->sensorData[selectedIndex], (CPN_MAX_SENSORS - (selectedIndex + 1)) * sizeof(SensorData));
+ model->sensorData[selectedIndex].clear();
+ model->updateAllReferences(ModelData::REF_UPD_TYPE_SENSOR, ModelData::REF_UPD_ACT_SHIFT, selectedIndex, 0, 1);
+ on_dataModifiedSensor();
+}
+
+void TelemetryPanel::on_deleteSensor(int selectedIndex)
+{
+ if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Delete Sensor. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
+ return;
+
+ memmove(&model->sensorData[selectedIndex], &model->sensorData[selectedIndex + 1], (CPN_MAX_SENSORS - (selectedIndex + 1)) * sizeof(SensorData));
+ model->sensorData[CPN_MAX_SENSORS - 1].clear();
+ model->updateAllReferences(ModelData::REF_UPD_TYPE_SENSOR, ModelData::REF_UPD_ACT_SHIFT, selectedIndex, 0, -1);
+ on_dataModifiedSensor();
+}
+
+void TelemetryPanel::on_moveUpSensor(int selectedIndex)
+{
+ swapData(selectedIndex, selectedIndex - 1);
+}
+
+void TelemetryPanel::on_moveDownSensor(int selectedIndex)
+{
+ swapData(selectedIndex, selectedIndex + 1);
+}
+
+void TelemetryPanel::swapData(int idx1, int idx2)
+{
+ if ((idx1 != idx2) && (!model->sensorData[idx1].isEmpty() || !model->sensorData[idx2].isEmpty())) {
+ SensorData sdtmp = model->sensorData[idx2];
+ SensorData *sd1 = &model->sensorData[idx1];
+ SensorData *sd2 = &model->sensorData[idx2];
+ memcpy(sd2, sd1, sizeof(SensorData));
+ memcpy(sd1, &sdtmp, sizeof(SensorData));
+ model->updateAllReferences(ModelData::REF_UPD_TYPE_SENSOR, ModelData::REF_UPD_ACT_SWAP, idx1, idx2);
+ on_dataModifiedSensor();
+ }
+}
+
+void TelemetryPanel::on_dataModifiedSensor()
+{
+ sharedItemModels->update(AbstractItemModel::IMUE_TeleSensors);
emit modified();
}
+
+void TelemetryPanel::connectItemModelEvents(const int id)
+{
+ FilteredItemModel * itemModel = panelFilteredItemModels->getItemModel(id);
+ connect(itemModel, &FilteredItemModel::aboutToBeUpdated, this, &TelemetryPanel::onItemModelAboutToBeUpdated);
+ connect(itemModel, &FilteredItemModel::updateComplete, this, &TelemetryPanel::onItemModelUpdateComplete);
+}
+
+void TelemetryPanel::onItemModelAboutToBeUpdated()
+{
+ lock = true;
+ modelsUpdateCnt++;
+}
+
+void TelemetryPanel::onItemModelUpdateComplete()
+{
+ modelsUpdateCnt--;
+ if (modelsUpdateCnt < 1) {
+ update();
+ lock = false;
+ }
+}
diff --git a/companion/src/modeledit/telemetry.h b/companion/src/modeledit/telemetry.h
index 28dc7643c..3f04bebf6 100644
--- a/companion/src/modeledit/telemetry.h
+++ b/companion/src/modeledit/telemetry.h
@@ -18,16 +18,15 @@
* GNU General Public License for more details.
*/
-#ifndef _TELEMETRY_H_
-#define _TELEMETRY_H_
+#pragma once
#include "modeledit.h"
#include "eeprominterface.h"
+#include "filtereditemmodels.h"
-constexpr char MIMETYPE_TELE_SENSOR[] = "application/x-companion-tele-sensor";
+constexpr char MIMETYPE_TELE_SENSOR[] {"application/x-companion-tele-sensor"};
class AutoComboBox;
-class RawSourceFilterItemModel;
class TimerEdit;
namespace Ui {
@@ -41,7 +40,8 @@ class TelemetryCustomScreen: public ModelPanel
Q_OBJECT
public:
- TelemetryCustomScreen(QWidget *parent, ModelData & model, FrSkyScreenData & screen, GeneralSettings & generalSettings, Firmware * firmware, RawSourceFilterItemModel * srcModel);
+ TelemetryCustomScreen(QWidget *parent, ModelData & model, FrSkyScreenData & screen, GeneralSettings & generalSettings, Firmware * firmware,
+ const bool & parentLock, FilteredItemModelFactory * panelFilteredItemModels);
~TelemetryCustomScreen();
void update();
@@ -53,6 +53,8 @@ class TelemetryCustomScreen: public ModelPanel
void barMinChanged(double value);
void barMaxChanged(double value);
void barTimeChanged();
+ void onItemModelAboutToBeUpdated();
+ void onItemModelUpdateComplete();
private:
void updateBar(int line);
@@ -64,6 +66,11 @@ class TelemetryCustomScreen: public ModelPanel
QDoubleSpinBox * maxSB[4];
TimerEdit * minTime[4];
TimerEdit * maxTime[4];
+ int modelsUpdateCnt;
+ const bool &parentLock;
+
+ inline bool isLocked() { return lock | parentLock; }
+ void connectItemModelEvents(const FilteredItemModel * itemModel);
};
class TelemetrySensorPanel: public ModelPanel
@@ -71,37 +78,53 @@ class TelemetrySensorPanel: public ModelPanel
Q_OBJECT
public:
- TelemetrySensorPanel(QWidget *parent, SensorData & sensor, int sensorIndex, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware);
+ TelemetrySensorPanel(QWidget *parent, SensorData & sensor, int sensorIndex, int sensorCapability, ModelData & model,
+ GeneralSettings & generalSettings, Firmware * firmware, const bool & parentLock,
+ FilteredItemModelFactory * panelFilteredItemModels);
~TelemetrySensorPanel();
void update();
signals:
void dataModified();
void clearAllSensors();
+ void insertSensor(int index);
+ void deleteSensor(int index);
+ void moveUpSensor(int index);
+ void moveDownSensor(int index);
protected slots:
- void on_name_editingFinished();
- void on_type_currentIndexChanged(int index);
- void on_formula_currentIndexChanged(int index);
- void on_unit_currentIndexChanged(int index);
- void on_prec_valueChanged();
void on_customContextMenuRequested(QPoint pos);
bool hasClipboardData(QByteArray * data = nullptr) const;
void cmCopy();
void cmCut();
void cmPaste();
- void cmClear();
+ void cmClear(bool prompt = true);
void cmClearAll();
-
- protected:
- void updateSourcesComboBox(AutoComboBox * cb, bool negative);
+ void cmInsert();
+ void cmDelete();
+ void cmMoveUp();
+ void cmMoveDown();
+ void onItemModelAboutToBeUpdated();
+ void onItemModelUpdateComplete();
+ void on_nameDataChanged();
+ void on_formulaDataChanged();
+ void on_unitDataChanged();
+ void on_precDataChanged();
private:
Ui::TelemetrySensor * ui;
SensorData & sensor;
- bool lock = false;
int sensorIndex = 0;
int selectedIndex = 0;
+ int sensorCapability;
+ bool insertAllowed() const;
+ bool moveDownAllowed() const;
+ bool moveUpAllowed() const;
+ int modelsUpdateCnt;
+ const bool &parentLock;
+
+ inline bool isLocked() { return lock | parentLock; }
+ void connectItemModelEvents(const FilteredItemModel * itemModel);
};
class TelemetryPanel : public ModelPanel
@@ -109,7 +132,8 @@ class TelemetryPanel : public ModelPanel
Q_OBJECT
public:
- TelemetryPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware);
+ TelemetryPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware,
+ CompoundItemModelFactory * sharedItemModels);
virtual ~TelemetryPanel();
virtual void update();
@@ -131,17 +155,27 @@ class TelemetryPanel : public ModelPanel
void on_mahCount_SB_editingFinished();
void on_mahCount_ChkB_toggled(bool checked);
void on_clearAllSensors();
+ void on_insertSensor(int index);
+ void on_deleteSensor(int index);
+ void on_moveUpSensor(int index);
+ void on_moveDownSensor(int index);
+ void on_dataModifiedSensor();
+ void onItemModelAboutToBeUpdated();
+ void onItemModelUpdateComplete();
private:
Ui::Telemetry *ui;
- TelemetryCustomScreen * telemetryCustomScreens[4];
- TelemetrySensorPanel * sensorPanels[CPN_MAX_SENSORS];
+ TelemetryCustomScreen *telemetryCustomScreens[4];
+ TelemetrySensorPanel *sensorPanels[CPN_MAX_SENSORS];
+ int sensorCapability;
+ CompoundItemModelFactory *sharedItemModels;
+ CompoundItemModelFactory *panelItemModels;
+ FilteredItemModelFactory *panelFilteredItemModels;
+ int modelsUpdateCnt;
void setup();
void telBarUpdate();
- void populateVoltsSource();
- void populateCurrentSource();
- void populateVarioSource();
+ void swapData(int idx1, int idx2);
+ void connectItemModelEvents(const int id);
+ inline bool isLocked() { return lock; }
};
-
-#endif // _TELEMETRY_H_
diff --git a/companion/src/modeledit/telemetry_sensor.ui b/companion/src/modeledit/telemetry_sensor.ui
index 12af2cf06..e70cc7aa2 100644
--- a/companion/src/modeledit/telemetry_sensor.ui
+++ b/companion/src/modeledit/telemetry_sensor.ui
@@ -40,7 +40,7 @@
-
-
+
0
@@ -59,23 +59,13 @@
-
-
+
0
0
-
-
-
- Custom
-
-
- -
-
- Calculated
-
-
-
@@ -147,7 +137,7 @@
-
-
+
0
@@ -175,58 +165,13 @@
-
-
+
0
0
-
-
-
- Add
-
-
- -
-
- Average
-
-
- -
-
- Min
-
-
- -
-
- Max
-
-
- -
-
- Multiply
-
-
- -
-
- Totalize
-
-
- -
-
- Cell
-
-
- -
-
- Consumption
-
-
- -
-
- Dist
-
-
-
@@ -412,138 +357,13 @@
-
-
+
0
0
-
-
-
- Raw (-)
-
-
- -
-
- V
-
-
- -
-
- A
-
-
- -
-
- mA
-
-
- -
-
- kt
-
-
- -
-
- m/s
-
-
- -
-
- ft/s
-
-
- -
-
- km/h
-
-
- -
-
- mph
-
-
- -
-
- m
-
-
- -
-
- ft
-
-
- -
-
- °C
-
-
- -
-
- °F
-
-
- -
-
- %
-
-
- -
-
- mAh
-
-
- -
-
- W
-
-
- -
-
- mW
-
-
- -
-
- dBm
-
-
- -
-
- RPM
-
-
- -
-
- g
-
-
- -
-
- °
-
-
- -
-
- Rad
-
-
- -
-
- mL
-
-
- -
-
- US fl.Oz.
-
-
- -
-
- ml/min
-
-
-
@@ -560,7 +380,7 @@
-
-
+
-
@@ -720,9 +540,9 @@
- AutoPrecisionComboBox
- QComboBox
-
+ AutoLineEdit
+ QLineEdit
+
diff --git a/companion/src/modelprinter.cpp b/companion/src/modelprinter.cpp
index bd56876c6..1d7df4f93 100644
--- a/companion/src/modelprinter.cpp
+++ b/companion/src/modelprinter.cpp
@@ -23,8 +23,8 @@
#include "multiprotocols.h"
#include "boards.h"
#include "helpers_html.h"
-#include "multiprotocols.h"
#include "appdata.h"
+#include "adjustmentreference.h"
#include
#include
@@ -212,7 +212,7 @@ QString ModelPrinter::printModule(int idx)
str << printLabelValue(tr("Delay"), QString("%1us").arg(module.ppm.delay));
}
else {
- if (!(module.protocol == PULSES_PXX_XJT_D8 || module.protocol == PULSES_CROSSFIRE || module.protocol == PULSES_SBUS)) {
+ if (!(module.protocol == PULSES_PXX_XJT_D8 || module.protocol == PULSES_CROSSFIRE || module.protocol == PULSES_GHOST || module.protocol == PULSES_SBUS)) {
str << printLabelValue(tr("Receiver"), QString::number(module.modelId));
}
if (module.protocol == PULSES_MULTIMODULE) {
@@ -298,27 +298,6 @@ QString ModelPrinter::printCenterBeep()
return (strl.isEmpty() ? tr("None") : strl.join(" "));
}
-QString ModelPrinter::printTimer(int idx)
-{
- return printTimer(model.timers[idx]);
-}
-
-QString ModelPrinter::printTimer(const TimerData & timer)
-{
- QStringList result;
- if (firmware->getCapability(TimersName) && timer.name[0])
- result += tr("Name") + QString("(%1)").arg(timer.name);
- result += printTimeValue(timer.val, MASK_TIMEVALUE_HRSMINS | MASK_TIMEVALUE_ZEROHRS);
- result += timer.mode.toString();
- if (timer.countdownBeep)
- result += tr("Countdown") + QString("(%1)").arg(printTimerCountdownBeep(timer.countdownBeep));
- if (timer.minuteBeep)
- result += tr("Minute call");
- if (timer.persistent)
- result += tr("Persistent") + QString("(%1)").arg(printTimerPersistent(timer.persistent));
- return result.join(", ");
-}
-
QString ModelPrinter::printTrim(int flightModeIndex, int stickIndex)
{
const FlightModeData & fm = model.flightModeData[flightModeIndex];
@@ -397,7 +376,7 @@ QString ModelPrinter::printInputLine(const ExpoData & input)
str += input.srcRaw.toString(&model, &generalSettings).toHtmlEscaped();
}
- str += " " + tr("Weight").toHtmlEscaped() + QString("(%1)").arg(Helpers::getAdjustmentString(input.weight, &model, true).toHtmlEscaped());
+ str += " " + tr("Weight(%1)").arg(AdjustmentReference(input.weight).toString(&model, true)).toHtmlEscaped();
if (input.curve.value)
str += " " + input.curve.toString(&model).toHtmlEscaped();
@@ -406,19 +385,18 @@ QString ModelPrinter::printInputLine(const ExpoData & input)
str += " " + flightModesStr.toHtmlEscaped();
if (input.swtch.type != SWITCH_TYPE_NONE)
- str += " " + tr("Switch").toHtmlEscaped() + QString("(%1)").arg(input.swtch.toString(getCurrentBoard(), &generalSettings)).toHtmlEscaped();
+ str += " " + tr("Switch(%1)").arg(input.swtch.toString(getCurrentBoard(), &generalSettings)).toHtmlEscaped();
if (firmware->getCapability(VirtualInputs)) {
- if (input.carryTrim>0)
- str += " " + tr("NoTrim").toHtmlEscaped();
- else if (input.carryTrim<0)
- str += " " + RawSource(SOURCE_TYPE_TRIM, (-(input.carryTrim)-1)).toString(&model, &generalSettings).toHtmlEscaped();
+ if (input.carryTrim > 0)
+ str += " " + tr("NoTrim");
+ else if (input.carryTrim < 0)
+ str += " " + RawSource(SOURCE_TYPE_TRIM, (-(input.carryTrim) - 1)).toString(&model, &generalSettings).toHtmlEscaped();
}
if (input.offset)
- str += " " + tr("Offset(%1)").arg(Helpers::getAdjustmentString(input.offset, &model)).toHtmlEscaped();
-
+ str += " " + tr("Offset(%1)").arg(AdjustmentReference(input.offset).toString(&model)).toHtmlEscaped();
if (firmware->getCapability(HasExpoNames) && input.name[0])
str += QString(" [%1]").arg(input.name).toHtmlEscaped();
@@ -441,7 +419,7 @@ QString ModelPrinter::printMixerLine(const MixData & mix, bool showMultiplex, in
}
// highlight source if needed
QString source = mix.srcRaw.toString(&model, &generalSettings).toHtmlEscaped();
- if ( (mix.srcRaw.type == SOURCE_TYPE_CH) && (mix.srcRaw.index+1 == (int)highlightedSource) ) {
+ if ( (mix.srcRaw.type == SOURCE_TYPE_CH) && (mix.srcRaw.index + 1 == (int)highlightedSource) ) {
source = "" + source + "";
}
str += " " + source;
@@ -449,35 +427,35 @@ QString ModelPrinter::printMixerLine(const MixData & mix, bool showMultiplex, in
if (mix.mltpx == MLTPX_MUL && !showMultiplex)
str += " " + tr("MULT!").toHtmlEscaped();
else
- str += " " + tr("Weight") + QString("(%1)").arg(Helpers::getAdjustmentString(mix.weight, &model, true)).toHtmlEscaped();
+ str += " " + tr("Weight(%1)").arg(AdjustmentReference(mix.weight).toString(&model, true)).toHtmlEscaped();
QString flightModesStr = printFlightModes(mix.flightModes);
if (!flightModesStr.isEmpty())
str += " " + flightModesStr.toHtmlEscaped();
if (mix.swtch.type != SWITCH_TYPE_NONE)
- str += " " + tr("Switch") + QString("(%1)").arg(mix.swtch.toString(getCurrentBoard(), &generalSettings)).toHtmlEscaped();
+ str += " " + tr("Switch(%1)").arg(mix.swtch.toString(getCurrentBoard(), &generalSettings)).toHtmlEscaped();
if (mix.carryTrim > 0)
- str += " " + tr("NoTrim").toHtmlEscaped();
+ str += " " + tr("NoTrim");
else if (mix.carryTrim < 0)
str += " " + RawSource(SOURCE_TYPE_TRIM, (-(mix.carryTrim)-1)).toString(&model, &generalSettings);
if (firmware->getCapability(HasNoExpo) && mix.noExpo)
str += " " + tr("No DR/Expo").toHtmlEscaped();
if (mix.sOffset)
- str += " " + tr("Offset") + QString("(%1)").arg(Helpers::getAdjustmentString(mix.sOffset, &model)).toHtmlEscaped();
+ str += " " + tr("Offset(%1)").arg(AdjustmentReference(mix.sOffset).toString(&model)).toHtmlEscaped();
if (mix.curve.value)
str += " " + mix.curve.toString(&model).toHtmlEscaped();
int scale = firmware->getCapability(SlowScale);
if (scale == 0)
scale = 1;
if (mix.delayDown || mix.delayUp)
- str += " " + tr("Delay") + QString("(u%1:d%2)").arg((double)mix.delayUp/scale).arg((double)mix.delayDown/scale).toHtmlEscaped();
+ str += " " + tr("Delay(u%1:d%2)").arg((double)mix.delayUp / scale).arg((double)mix.delayDown / scale).toHtmlEscaped();
if (mix.speedDown || mix.speedUp)
- str += " " + tr("Slow") + QString("(u%1:d%2)").arg((double)mix.speedUp/scale).arg((double)mix.speedDown/scale).toHtmlEscaped();
+ str += " " + tr("Slow(u%1:d%2)").arg((double)mix.speedUp / scale).arg((double)mix.speedDown / scale).toHtmlEscaped();
if (mix.mixWarn)
- str += " " + tr("Warn") + QString("(%1)").arg(mix.mixWarn).toHtmlEscaped();
+ str += " " + tr("Warn(%1)").arg(mix.mixWarn).toHtmlEscaped();
if (firmware->getCapability(HasMixerNames) && mix.name[0])
str += QString(" [%1]").arg(mix.name).toHtmlEscaped();
return str;
@@ -497,13 +475,13 @@ QString ModelPrinter::printFlightModes(unsigned int flightModes)
{
int numFlightModes = firmware->getCapability(FlightModes);
if (numFlightModes && flightModes) {
- if (flightModes == (unsigned int)(1<getCapability(FlightModes);
if (numFlightModes && flightModes) {
- if (flightModes == (unsigned int)(1<getCapability(TimersName) && model.timers[idx].name[0])
- result.append(":" + QString(model.timers[idx].name));
-
- return result;
-}
-
-QString ModelPrinter::printTimerTimeValue(unsigned int val)
-{
- return printTimeValue(val, MASK_TIMEVALUE_HRSMINS | MASK_TIMEVALUE_ZEROHRS);
-}
-
-QString ModelPrinter::printTimerMinuteBeep(bool mb)
-{
- return printBoolean(mb, BOOLEAN_YESNO);
-}
-
QString ModelPrinter::printTelemetryProtocol(unsigned int val)
{
switch (val) {
@@ -1072,17 +1000,6 @@ QString ModelPrinter::printRssiAlarmsDisabled(bool mb)
return printBoolean(!mb, BOOLEAN_ENABLEDISABLE);
}
-QString ModelPrinter::printTelemetrySource(int val)
-{
- QStringList strings = QStringList() << tr("None");
-
- for (unsigned i=1; i<=CPN_MAX_SENSORS; ++i) {
- strings << QString("%1").arg(model.sensorData[i-1].label);
- }
-
- return QString("%1%2").arg((val < 0 ? "-" : "")).arg(strings.value(abs(val)));
-}
-
QString ModelPrinter::printVarioSource(unsigned int val)
{
switch (val) {
@@ -1156,246 +1073,6 @@ QString ModelPrinter::printIgnoreSensorIds(bool mb)
return printBoolean(mb, BOOLEAN_ENABLEDISABLE);
}
-QString ModelPrinter::printSensorType(unsigned int val)
-{
- switch (val) {
- case SensorData::TELEM_TYPE_CUSTOM:
- return tr("Custom");
- case SensorData::TELEM_TYPE_CALCULATED:
- return tr("Calculated");
- default:
- return CPN_STR_UNKNOWN_ITEM;
- }
-}
-
-QString ModelPrinter::printSensorFormula(unsigned int val)
-{
- switch (val) {
- case SensorData::TELEM_FORMULA_ADD:
- return tr("Add");
- case SensorData::TELEM_FORMULA_AVERAGE:
- return tr("Average");
- case SensorData::TELEM_FORMULA_MIN:
- return tr("Min");
- case SensorData::TELEM_FORMULA_MAX:
- return tr("Max");
- case SensorData::TELEM_FORMULA_MULTIPLY:
- return tr("Multiply");
- case SensorData::TELEM_FORMULA_TOTALIZE:
- return tr("Totalise");
- case SensorData::TELEM_FORMULA_CELL:
- return tr("Cell");
- case SensorData::TELEM_FORMULA_CONSUMPTION:
- return tr("Consumption");
- case SensorData::TELEM_FORMULA_DIST:
- return tr("Distance");
- default:
- return CPN_STR_UNKNOWN_ITEM;
- }
-}
-
-QString ModelPrinter::printSensorCells(unsigned int val)
-{
- QStringList strings;
-
- strings << tr("Lowest");
- for (int i=1; i<=6; i++)
- strings << tr("Cell %1").arg(i);
- strings << tr("Highest") << tr("Delta");
-
- return strings.value(val);
-}
-
-QString ModelPrinter::printSensorTypeCond(unsigned int idx)
-{
- if (!model.sensorData[idx].isAvailable())
- return "";
- else
- return printSensorType(model.sensorData[idx].type);
-}
-
-QString ModelPrinter::printSensorDetails(unsigned int idx)
-{
- QString str = "";
- SensorData sensor = model.sensorData[idx];
-
- if (!sensor.isAvailable())
- return str;
-
- bool isConfigurable = false;
- bool gpsFieldsPrinted = false;
- bool cellsFieldsPrinted = false;
- bool consFieldsPrinted = false;
- bool ratioFieldsPrinted = false;
- bool totalizeFieldsPrinted = false;
- bool sources12FieldsPrinted = false;
- bool sources34FieldsPrinted = false;
-
- str.append(doTableCell(printSensorTypeCond(idx)));
-
- QString tc = "";
- if (sensor.type == SensorData::TELEM_TYPE_CALCULATED) {
- isConfigurable = (sensor.formula < SensorData::TELEM_FORMULA_CELL);
- gpsFieldsPrinted = (sensor.formula == SensorData::TELEM_FORMULA_DIST);
- cellsFieldsPrinted = (sensor.formula == SensorData::TELEM_FORMULA_CELL);
- consFieldsPrinted = (sensor.formula == SensorData::TELEM_FORMULA_CONSUMPTION);
- sources12FieldsPrinted = (sensor.formula <= SensorData::TELEM_FORMULA_MULTIPLY);
- sources34FieldsPrinted = (sensor.formula < SensorData::TELEM_FORMULA_MULTIPLY);
- totalizeFieldsPrinted = (sensor.formula == SensorData::TELEM_FORMULA_TOTALIZE);
-
- tc.append(printLabelValue(tr("Formula"), printSensorFormula(sensor.formula)));
- }
- else {
- isConfigurable = sensor.unit < SensorData::UNIT_FIRST_VIRTUAL;
- ratioFieldsPrinted = (sensor.unit < SensorData::UNIT_FIRST_VIRTUAL);
-
- tc.append(printLabelValue(tr("Id"), QString::number(sensor.id,16).toUpper()));
- tc.append(printLabelValue(tr("Instance"), QString::number(sensor.instance)));
- }
- if (cellsFieldsPrinted) {
- tc.append(printLabelValue(tr("Sensor"), QString("%1 > %2").arg(printTelemetrySource(sensor.source), false).arg(printSensorCells(sensor.index))));
- }
- if (sources12FieldsPrinted) {
- QStringList srcs;
- for (int i=0;i<4;i++) {
- if (i < 2 || sources34FieldsPrinted) {
- srcs << printTelemetrySource(sensor.sources[i]);
- }
- }
- tc.append(printLabelValues(tr("Sources"), srcs));
- }
- if (consFieldsPrinted || totalizeFieldsPrinted)
- tc.append(printLabelValue(tr("Sensor"), printTelemetrySource(sensor.amps)));
- if (gpsFieldsPrinted) {
- tc.append(printLabelValue(tr("GPS"), printTelemetrySource(sensor.gps)));
- tc.append(printLabelValue(tr("Alt."), printTelemetrySource(sensor.alt)));
- }
- if (ratioFieldsPrinted && sensor.unit == SensorData::UNIT_RPMS) {
- tc.append(printLabelValue(tr("Blades"), QString::number(sensor.ratio)));
- tc.append(printLabelValue(tr("Multi."), QString::number(sensor.offset)));
- }
- str.append(doTableCell(tc));
-
- tc = sensor.unitString();
- tc = tc.trimmed() == "" ? "-" : tc;
- str.append(doTableCell(tc));
-
- if (isConfigurable && sensor.unit != SensorData::UNIT_FAHRENHEIT)
- tc = QString::number(sensor.prec);
- else
- tc = "";
- str.append(doTableCell(tc));
-
- if (!ratioFieldsPrinted) {
- str.append(doTableCell(""));
- str.append(doTableCell(""));
- }
- else if (sensor.unit != SensorData::UNIT_RPMS) {
- int prec = sensor.prec == 0 ? 1 : pow(10, sensor.prec);
- str.append(doTableCell(QString::number((float)sensor.ratio / prec)));
- str.append(doTableCell(QString::number((float)sensor.offset / prec)));
- }
-
- if (sensor.unit != SensorData::UNIT_RPMS && isConfigurable)
- str.append(doTableCell(printBoolean(sensor.autoOffset, BOOLEAN_YN)));
- else
- str.append(doTableCell(""));
-
- if (isConfigurable)
- str.append(doTableCell(printBoolean(sensor.filter, BOOLEAN_YN)));
- else
- str.append(doTableCell(""));
-
- if (sensor.type == SensorData::TELEM_TYPE_CALCULATED)
- str.append(doTableCell(printBoolean(sensor.persistent, BOOLEAN_YN)));
- else
- str.append(doTableCell(""));
-
- str.append(doTableCell(printBoolean(sensor.onlyPositive, BOOLEAN_YN)));
- str.append(doTableCell(printBoolean(sensor.logs, BOOLEAN_YN), false));
- return str;
-}
-
-QString ModelPrinter::printSensorParams(unsigned int idx)
-{
- QString str = "";
- SensorData sensor = model.sensorData[idx];
-
- if (!sensor.isAvailable())
- return str;
-
- bool isConfigurable = false;
- bool gpsFieldsPrinted = false;
- bool cellsFieldsPrinted = false;
- bool consFieldsPrinted = false;
- bool ratioFieldsPrinted = false;
- bool totalizeFieldsPrinted = false;
- bool sources12FieldsPrinted = false;
- bool sources34FieldsPrinted = false;
-
- if (sensor.type == SensorData::TELEM_TYPE_CALCULATED) {
- isConfigurable = (sensor.formula < SensorData::TELEM_FORMULA_CELL);
- gpsFieldsPrinted = (sensor.formula == SensorData::TELEM_FORMULA_DIST);
- cellsFieldsPrinted = (sensor.formula == SensorData::TELEM_FORMULA_CELL);
- consFieldsPrinted = (sensor.formula == SensorData::TELEM_FORMULA_CONSUMPTION);
- sources12FieldsPrinted = (sensor.formula <= SensorData::TELEM_FORMULA_MULTIPLY);
- sources34FieldsPrinted = (sensor.formula < SensorData::TELEM_FORMULA_MULTIPLY);
- totalizeFieldsPrinted = (sensor.formula == SensorData::TELEM_FORMULA_TOTALIZE);
-
- str.append(printLabelValue(tr("F"), printSensorFormula(sensor.formula)));
- }
- else {
- isConfigurable = sensor.unit < SensorData::UNIT_FIRST_VIRTUAL;
- ratioFieldsPrinted = (sensor.unit < SensorData::UNIT_FIRST_VIRTUAL);
-
- str.append(printLabelValue(tr("Id"), QString::number(sensor.id,16).toUpper()));
- str.append(printLabelValue(tr("Inst"), QString::number(sensor.instance)));
- }
- if (cellsFieldsPrinted) {
- str.append(printLabelValue(tr("Sensor"), QString("%1 %2").arg(printTelemetrySource(sensor.source), false).arg(printSensorCells(sensor.index))));
- }
- if (sources12FieldsPrinted) {
- QStringList srcs;
- for (int i=0;i<4;i++) {
- if (i < 2 || sources34FieldsPrinted) {
- srcs << printTelemetrySource(sensor.sources[i]);
- }
- }
- str.append(printLabelValues(tr("Sources"), srcs));
- }
- if (consFieldsPrinted || totalizeFieldsPrinted)
- str.append(printLabelValue(tr("Sensor"), printTelemetrySource(sensor.amps)));
- if (gpsFieldsPrinted) {
- str.append(printLabelValue(tr("GPS"), printTelemetrySource(sensor.gps)));
- str.append(printLabelValue(tr("Alt"), printTelemetrySource(sensor.alt)));
- }
- QString u = sensor.unitString();
- u = u.trimmed() == "" ? "-" : u;
- str.append(printLabelValue(tr("Unit"), u));
- if (isConfigurable && sensor.unit != SensorData::UNIT_FAHRENHEIT)
- str.append(printLabelValue(tr("Prec"), QString::number(sensor.prec)));
- if (ratioFieldsPrinted) {
- if (sensor.unit != SensorData::UNIT_RPMS) {
- int prec = sensor.prec == 0 ? 1 : pow(10, sensor.prec);
- str.append(printLabelValue(tr("Ratio"), QString::number((float)sensor.ratio / prec)));
- str.append(printLabelValue(tr("Offset"), QString::number((float)sensor.offset / prec)));
- }
- else if (sensor.unit == SensorData::UNIT_RPMS) {
- str.append(printLabelValue(tr("Blades"), QString::number(sensor.ratio)));
- str.append(printLabelValue(tr("Multi"), QString::number(sensor.offset)));
- }
- }
- if (sensor.unit != SensorData::UNIT_RPMS && isConfigurable)
- str.append(printLabelValue(tr("A/Offset"), printBoolean(sensor.autoOffset, BOOLEAN_YN)));
- if (isConfigurable)
- str.append(printLabelValue(tr("Filter"), printBoolean(sensor.filter, BOOLEAN_YN)));
- if (sensor.type == SensorData::TELEM_TYPE_CALCULATED)
- str.append(printLabelValue(tr("Persist"), printBoolean(sensor.persistent, BOOLEAN_YN)));
- str.append(printLabelValue(tr("Positive"), printBoolean(sensor.onlyPositive, BOOLEAN_YN)));
- str.append(printLabelValue(tr("Log"), printBoolean(sensor.logs, BOOLEAN_YN), false));
- return str;
-}
-
QString ModelPrinter::printTelemetryScreenType(unsigned int val)
{
switch (val) {
diff --git a/companion/src/modelprinter.h b/companion/src/modelprinter.h
index cef007063..8be56bd64 100644
--- a/companion/src/modelprinter.h
+++ b/companion/src/modelprinter.h
@@ -18,8 +18,7 @@
* GNU General Public License for more details.
*/
-#ifndef _MODELPRINTER_H_
-#define _MODELPRINTER_H_
+#pragma once
#include
#include
@@ -68,8 +67,6 @@ class ModelPrinter: public QObject
QString printTrim(int flightModeIndex, int stickIndex);
QString printGlobalVar(int flightModeIndex, int gvarIndex);
QString printRotaryEncoder(int flightModeIndex, int reIndex);
- QString printTimer(int idx);
- QString printTimer(const TimerData & timer);
QString printInputName(int idx);
QString printInputLine(int idx);
QString printInputLine(const ExpoData & ed);
@@ -105,30 +102,18 @@ class ModelPrinter: public QObject
QString printFailsafe(int idx);
QString printFailsafeMode(unsigned int fsmode);
QString printFailsafeValue(int val);
- QString printTimerCountdownBeep(unsigned int countdownBeep);
- QString printTimerPersistent(unsigned int persistent);
QString printPPMFrameLength(int ppmFL);
- QString printTimerName(int idx);
QString printTimeValue(const int value, const unsigned int mask);
- QString printTimerMinuteBeep(bool mb);
- QString printTimerTimeValue(unsigned int val);
QString printTelemetryProtocol(unsigned int val);
QString printLabelValue(const QString & lbl, const QString & val, const bool sep = false);
QString printLabelValues(const QString & lbl, const QStringList & vals, const bool sep = false);
QString printRssiAlarmsDisabled(bool mb);
- QString printTelemetrySource(int val);
QString printVarioSource(unsigned int val);
QString printVarioCenterSilent(bool mb);
QString printVoltsSource(unsigned int val);
QString printCurrentSource(unsigned int val);
QString printMahPersistent(bool mb);
QString printIgnoreSensorIds(bool mb);
- QString printSensorType(unsigned int val);
- QString printSensorFormula(unsigned int val);
- QString printSensorCells(unsigned int val);
- QString printSensorTypeCond(unsigned int idx);
- QString printSensorParams(unsigned int idx);
- QString printSensorDetails(unsigned int idx);
QString printTelemetryScreenType(unsigned int val);
QString printTelemetryScreen(unsigned int idx, unsigned int line, unsigned int width);
QString printChecklist();
@@ -139,5 +124,3 @@ class ModelPrinter: public QObject
const ModelData & model;
};
-
-#endif // _MODELPRINTER_H_
diff --git a/companion/src/multimodelprinter.cpp b/companion/src/multimodelprinter.cpp
index 9d57e1f62..0ebef1884 100644
--- a/companion/src/multimodelprinter.cpp
+++ b/companion/src/multimodelprinter.cpp
@@ -310,7 +310,9 @@ QString MultiModelPrinter::printSetup()
MultiColumns columns(modelPrinterMap.size());
columns.appendSectionTableStart();
ROWLABELCOMPARECELL(tr("Name"), 20, model->name, 80);
- ROWLABELCOMPARECELL(tr("EEprom Size"), 0, modelPrinter->printEEpromSize(), 0);
+ if (!IS_FAMILY_HORUS_OR_T16(firmware->getBoard())) {
+ ROWLABELCOMPARECELL(tr("EEprom Size"), 0, modelPrinter->printEEpromSize(), 0);
+ }
if (firmware->getCapability(ModelImage)) {
ROWLABELCOMPARECELL(tr("Model Image"), 0, model->bitmap, 0);
}
@@ -332,18 +334,19 @@ QString MultiModelPrinter::printTimers()
QString str;
MultiColumns columns(modelPrinterMap.size());
columns.appendSectionTableStart();
- columns.appendRowHeader(QStringList() << tr("Timers") << tr("Time") << tr("Switch") << tr("Countdown") << tr("Min.call") << tr("Persist"));
+ columns.appendRowHeader(QStringList() << tr("Timers") << tr("Time") << tr("Switch") << tr("Countdown") << tr("Start") << tr("Min.call") << tr("Persist"));
for (int i=0; igetCapability(Timers); i++) {
columns.appendRowStart();
columns.appendCellStart(20, true);
- COMPARE(modelPrinter->printTimerName(i));
+ COMPARE(model->timers[i].nameToString(i));
columns.appendCellEnd(true);
- COMPARECELLWIDTH(modelPrinter->printTimerTimeValue(model->timers[i].val), 15);
- COMPARECELLWIDTH(model->timers[i].mode.toString(), 15);
- COMPARECELLWIDTH(modelPrinter->printTimerCountdownBeep(model->timers[i].countdownBeep), 15);
- COMPARECELLWIDTH(modelPrinter->printTimerMinuteBeep(model->timers[i].minuteBeep), 15);
- COMPARECELLWIDTH(modelPrinter->printTimerPersistent(model->timers[i].persistent), 20);
+ COMPARECELLWIDTH(model->timers[i].valToString(), 10);
+ COMPARECELLWIDTH(model->timers[i].mode.toString(), 10);
+ COMPARECELLWIDTH(model->timers[i].countdownBeepToString(), 10);
+ COMPARECELLWIDTH(model->timers[i].countdownStartToString(), 10);
+ COMPARECELLWIDTH(DataHelpers::boolToString(model->timers[i].minuteBeep, DataHelpers::BOOL_FMT_YESNO), 10);
+ COMPARECELLWIDTH(model->timers[i].persistentToString(false), 15);
columns.appendRowEnd();
}
columns.appendTableEnd();
@@ -775,7 +778,7 @@ QString MultiModelPrinter::printTelemetry()
if (firmware->getCapability(HasVario)) {
columns.appendRowStart(tr("Altimetry"), 20);
if (IS_HORUS_OR_TARANIS(firmware->getBoard())) {
- LABELCOMPARECELL(tr("Vario source"), modelPrinter->printTelemetrySource(model->frsky.varioSource), 80);
+ LABELCOMPARECELL(tr("Vario source"), SensorData::sourceToString(model, model->frsky.varioSource), 80);
}
else {
LABELCOMPARECELL(tr("Vario source"), modelPrinter->printVarioSource(model->frsky.varioSource), 80);
@@ -799,8 +802,8 @@ QString MultiModelPrinter::printTelemetry()
if (IS_HORUS_OR_TARANIS(firmware->getBoard())) {
columns.appendRowStart(tr("Top Bar"), 20);
columns.appendCellStart(80);
- COMPARESTRING(tr("Volts source"), modelPrinter->printTelemetrySource(model->frsky.voltsSource), true);
- COMPARESTRING(tr("Altitude source"), modelPrinter->printTelemetrySource(model->frsky.altitudeSource), false);
+ COMPARESTRING(tr("Volts source"), SensorData::sourceToString(model, model->frsky.voltsSource), true);
+ COMPARESTRING(tr("Altitude source"), SensorData::sourceToString(model, model->frsky.altitudeSource), false);
columns.appendCellEnd();
columns.appendRowEnd();
}
@@ -820,9 +823,9 @@ QString MultiModelPrinter::printSensors()
int count = 0;
columns.appendSectionTableStart();
columns.appendRowHeader(QStringList() << tr("Name") << tr("Type") << tr("Parameters"));
- for (unsigned i=0; isensorData[i].isAvailable()) {
tsEmpty = false;
break;
@@ -834,8 +837,8 @@ QString MultiModelPrinter::printSensors()
columns.appendCellStart(20, true);
COMPARE(model->sensorData[i].nameToString(i));
columns.appendCellEnd(true);
- COMPARECELLWIDTH(modelPrinter->printSensorTypeCond(i), 15);
- COMPARECELLWIDTH(modelPrinter->printSensorParams(i), 65);
+ COMPARECELLWIDTH(model->sensorData[i].isAvailable() ? model->sensorData[i].typeToString() : "", 15);
+ COMPARECELLWIDTH(model->sensorData[i].paramsToString(model), 65);
columns.appendRowEnd();
}
}
diff --git a/companion/src/profilechooser.cpp b/companion/src/profilechooser.cpp
index 17a9570e5..a8942652e 100644
--- a/companion/src/profilechooser.cpp
+++ b/companion/src/profilechooser.cpp
@@ -28,6 +28,7 @@ ProfileChooserDialog::ProfileChooserDialog(QWidget * parent):
{
ui->setupUi(this);
setWindowIcon(QIcon(":/icon.png"));
+ setWindowFlags(Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint);
QComboBox *prof = ui->cboProfiles;
prof->clear();
diff --git a/companion/src/shared/CMakeLists.txt b/companion/src/shared/CMakeLists.txt
index 2fbbafbf9..ffd5942bf 100644
--- a/companion/src/shared/CMakeLists.txt
+++ b/companion/src/shared/CMakeLists.txt
@@ -16,6 +16,7 @@ set(shared_HDRS
genericpanel.h
hexspinbox.h
autoprecisioncombobox.h
+ autotimeedit.h
)
qt5_wrap_cpp(shared_SRCS ${shared_HDRS})
diff --git a/companion/src/shared/autobitsetcheckbox.h b/companion/src/shared/autobitsetcheckbox.h
index 6274e0117..af831948e 100644
--- a/companion/src/shared/autobitsetcheckbox.h
+++ b/companion/src/shared/autobitsetcheckbox.h
@@ -18,8 +18,7 @@
* GNU General Public License for more details.
*/
-#ifndef AUTOBITSETCHECKBOX_H
-#define AUTOBITSETCHECKBOX_H
+#pragma once
#include
#include "genericpanel.h"
@@ -35,7 +34,8 @@ class AutoBitsetCheckBox: public QCheckBox
Q_PROPERTY(int toggleMask READ toggleMask WRITE setToggleMask)
public:
- explicit AutoBitsetCheckBox(QWidget *parent = nullptr) : AutoBitsetCheckBox(QString(), parent) {}
+ explicit AutoBitsetCheckBox(QWidget *parent = nullptr) :
+ AutoBitsetCheckBox(QString(), parent) {}
explicit AutoBitsetCheckBox(const QString &text, QWidget *parent = nullptr) :
QCheckBox(text, parent)
{
@@ -43,26 +43,32 @@ class AutoBitsetCheckBox: public QCheckBox
}
// int field constructors
- explicit AutoBitsetCheckBox(int & field, int bitmask, const QString &text = QString(), QWidget *parent = nullptr) : AutoBitsetCheckBox(field, bitmask, false, text, parent) {}
- explicit AutoBitsetCheckBox(int & field, int bitmask, bool invert, const QString &text = QString(), QWidget *parent = nullptr) : QCheckBox(text, parent)
+ explicit AutoBitsetCheckBox(int & field, int bitmask, const QString &text = QString(), QWidget *parent = nullptr) :
+ AutoBitsetCheckBox(field, bitmask, false, text, parent) {}
+ explicit AutoBitsetCheckBox(int & field, int bitmask, bool invert, const QString &text = QString(), QWidget *parent = nullptr) :
+ QCheckBox(text, parent)
{
setField(field, bitmask, invert);
init();
}
- explicit AutoBitsetCheckBox(int & field, int bitmask, int toggleMask, const QString &text = QString(), QWidget *parent = nullptr) : QCheckBox(text, parent)
+ explicit AutoBitsetCheckBox(int & field, int bitmask, int toggleMask, const QString &text = QString(), QWidget *parent = nullptr) :
+ QCheckBox(text, parent)
{
setField(field, bitmask, false, toggleMask);
init();
}
// unsigned field constructors
- explicit AutoBitsetCheckBox(unsigned & field, int bitmask, const QString &text = QString(), QWidget *parent = nullptr) : AutoBitsetCheckBox(field, bitmask, false, text, parent) {}
- explicit AutoBitsetCheckBox(unsigned & field, int bitmask, bool invert, const QString &text = QString(), QWidget *parent = nullptr) : QCheckBox(text, parent)
+ explicit AutoBitsetCheckBox(unsigned & field, int bitmask, const QString &text = QString(), QWidget *parent = nullptr) :
+ AutoBitsetCheckBox(field, bitmask, false, text, parent) {}
+ explicit AutoBitsetCheckBox(unsigned & field, int bitmask, bool invert, const QString &text = QString(), QWidget *parent = nullptr) :
+ QCheckBox(text, parent)
{
setField(field, bitmask, invert);
init();
}
- explicit AutoBitsetCheckBox(unsigned & field, int bitmask, int toggleMask, const QString &text = QString(), QWidget *parent = nullptr) : QCheckBox(text, parent)
+ explicit AutoBitsetCheckBox(unsigned & field, int bitmask, int toggleMask, const QString &text = QString(), QWidget *parent = nullptr) :
+ QCheckBox(text, parent)
{
setField(field, bitmask, false, toggleMask);
init();
@@ -105,6 +111,8 @@ class AutoBitsetCheckBox: public QCheckBox
void updateValue()
{
+ if (m_panel && m_panel->lock)
+ return;
if (!m_field)
return;
const bool oldLock = setLocked(true);
@@ -174,5 +182,3 @@ class AutoBitsetCheckBox: public QCheckBox
bool m_lock = false;
GenericPanel * m_panel = nullptr;
};
-
-#endif // AUTOBITSETCHECKBOX_H
diff --git a/companion/src/shared/autocheckbox.h b/companion/src/shared/autocheckbox.h
index df99278a2..1c1a7207c 100644
--- a/companion/src/shared/autocheckbox.h
+++ b/companion/src/shared/autocheckbox.h
@@ -18,57 +18,64 @@
* GNU General Public License for more details.
*/
-#ifndef _AUTOCHECKBOX_H_
-#define _AUTOCHECKBOX_H_
+#pragma once
#include
-#include "modeledit/modeledit.h"
+#include "genericpanel.h"
class AutoCheckBox: public QCheckBox
{
Q_OBJECT
public:
- explicit AutoCheckBox(QWidget *parent = 0):
+ explicit AutoCheckBox(QWidget * parent = nullptr):
QCheckBox(parent),
- field(NULL),
- panel(NULL),
+ field(nullptr),
+ panel(nullptr),
lock(false)
{
connect(this, SIGNAL(toggled(bool)), this, SLOT(onToggled(bool)));
}
- void setField(bool & field, ModelPanel * panel=NULL)
+ void setField(bool & field, GenericPanel * panel = nullptr)
{
this->field = &field;
this->panel = panel;
updateValue();
}
+ void setEnabled(bool enabled)
+ {
+ QCheckBox::setEnabled(enabled);
+ }
+
void updateValue()
{
- lock = true;
if (field) {
+ lock = true;
setChecked(*field);
+ lock = false;
}
- lock = false;
}
+ signals:
+ void currentDataChanged(bool value);
+
protected slots:
void onToggled(bool checked)
{
+ if (panel && panel->lock)
+ return;
if (field && !lock) {
*field = checked;
- if (panel) {
+ emit currentDataChanged(checked);
+ if (panel)
emit panel->modified();
- }
}
}
protected:
- bool * field;
- ModelPanel * panel;
- bool lock;
+ bool *field = nullptr;
+ GenericPanel *panel = nullptr;
+ bool lock = false;
};
-
-#endif // _AUTOCHECKBOX_H_
diff --git a/companion/src/shared/autocombobox.h b/companion/src/shared/autocombobox.h
index fcb1845ac..ca6054555 100644
--- a/companion/src/shared/autocombobox.h
+++ b/companion/src/shared/autocombobox.h
@@ -18,78 +18,134 @@
* GNU General Public License for more details.
*/
-#ifndef _AUTOCOMBOBOX_H_
-#define _AUTOCOMBOBOX_H_
+#pragma once
#include
#include "genericpanel.h"
+#include "rawsource.h"
+#include "rawswitch.h"
class AutoComboBox: public QComboBox
{
Q_OBJECT
public:
- explicit AutoComboBox(QWidget *parent = nullptr):
- QComboBox(parent)
+ explicit AutoComboBox(QWidget * parent = nullptr):
+ QComboBox(parent),
+ field(nullptr),
+ panel(nullptr),
+ next(0),
+ lock(false),
+ hasModel(false),
+ rawSource(nullptr),
+ rawSwitch(nullptr)
{
connect(this, SIGNAL(currentIndexChanged(int)), this, SLOT(onCurrentIndexChanged(int)));
}
void clear()
{
- lock = true;
- QComboBox::clear();
- next = 0;
- lock = false;
+ if (!hasModel) {
+ lock = true;
+ QComboBox::clear();
+ next = 0;
+ lock = false;
+ }
}
virtual void insertItems(int index, const QStringList & items)
{
- foreach(QString item, items) {
- addItem(item);
+ if (!hasModel) {
+ foreach(QString item, items) {
+ addItem(item);
+ }
}
}
virtual void addItem(const QString & item)
{
- addItem(item, next++);
+ if (!hasModel)
+ addItem(item, next++);
}
virtual void addItem(const QString & item, int value)
{
- lock = true;
- QComboBox::addItem(item, value);
- lock = false;
- updateValue();
+ if (!hasModel) {
+ lock = true;
+ QComboBox::addItem(item, value);
+ lock = false;
+ updateValue();
+ }
}
- void setField(unsigned int & field, GenericPanel * panel=nullptr)
+ void setField(unsigned int & field, GenericPanel * panel = nullptr)
{
this->field = (int *)&field;
+ this->rawSource = nullptr;
+ this->rawSwitch = nullptr;
this->panel = panel;
updateValue();
}
- void setField(int & field, GenericPanel * panel=nullptr)
+ void setField(int & field, GenericPanel * panel = nullptr)
{
this->field = &field;
+ this->rawSource = nullptr;
+ this->rawSwitch = nullptr;
this->panel = panel;
updateValue();
}
+ void setField(RawSource & field, GenericPanel * panel = nullptr)
+ {
+ this->rawSource = &field;
+ this->rawSwitch = nullptr;
+ this->field = nullptr;
+ this->panel = panel;
+ updateValue();
+ }
+
+ void setField(RawSwitch & field, GenericPanel * panel = nullptr)
+ {
+ this->rawSwitch = &field;
+ this->rawSource = nullptr;
+ this->field = nullptr;
+ this->panel = panel;
+ updateValue();
+ }
+
+ void setModel(QAbstractItemModel * model)
+ {
+ lock = true;
+ QComboBox::setModel(model);
+ lock = false;
+ hasModel = true;
+ updateValue();
+ }
+
void setAutoIndexes()
{
- for (int i=0; itoValue()));
+ else if (rawSwitch)
+ setCurrentIndex(findData(rawSwitch->toValue()));
+
lock = false;
}
@@ -99,20 +155,39 @@ class AutoComboBox: public QComboBox
protected slots:
void onCurrentIndexChanged(int index)
{
- const int val = itemData(index).toInt();
- if (field && !lock) {
+ if (panel && panel->lock)
+ return;
+ if (lock || index < 0)
+ return;
+
+ bool ok;
+ const int val = itemData(index).toInt(&ok);
+ if (!ok)
+ return;
+
+ if (field && *field != val) {
*field = val;
- if (panel)
- emit panel->modified();
}
+ else if (rawSource && rawSource->toValue() != val) {
+ *rawSource = RawSource(val);
+ }
+ else if (rawSwitch && rawSwitch->toValue() != val) {
+ *rawSwitch = RawSwitch(val);
+ }
+ else
+ return;
+
emit currentDataChanged(val);
+ if (panel)
+ emit panel->modified();
}
protected:
- int * field = nullptr;
- GenericPanel * panel = nullptr;
+ int *field = nullptr;
+ GenericPanel *panel = nullptr;
int next = 0;
bool lock = false;
+ bool hasModel = false;
+ RawSource *rawSource = nullptr;
+ RawSwitch *rawSwitch = nullptr;
};
-
-#endif // _AUTOCOMBOBOX_H_
diff --git a/companion/src/shared/autodoublespinbox.h b/companion/src/shared/autodoublespinbox.h
index 17188243b..a6466269e 100644
--- a/companion/src/shared/autodoublespinbox.h
+++ b/companion/src/shared/autodoublespinbox.h
@@ -18,11 +18,10 @@
* GNU General Public License for more details.
*/
-#ifndef _AUTODOUBLESPINBOX_H_
-#define _AUTODOUBLESPINBOX_H_
+#pragma once
#include
-#include "modeledit/modeledit.h"
+#include "genericpanel.h"
#if __GNUC__
#include
#endif
@@ -32,23 +31,23 @@ class AutoDoubleSpinBox: public QDoubleSpinBox
Q_OBJECT
public:
- explicit AutoDoubleSpinBox(QWidget *parent = 0):
+ explicit AutoDoubleSpinBox(QWidget * parent = nullptr):
QDoubleSpinBox(parent),
- field(NULL),
- panel(NULL),
+ field(nullptr),
+ panel(nullptr),
lock(false)
{
connect(this, SIGNAL(valueChanged(double)), this, SLOT(onValueChanged(double)));
}
- void setField(int & field, ModelPanel * panel=NULL)
+ void setField(int & field, GenericPanel * panel = nullptr)
{
this->field = &field;
this->panel = panel;
updateValue();
}
- void setField(unsigned int & field, ModelPanel * panel=NULL)
+ void setField(unsigned int & field, GenericPanel * panel = nullptr)
{
this->field = (int *)&field;
this->panel = panel;
@@ -58,7 +57,9 @@ class AutoDoubleSpinBox: public QDoubleSpinBox
void updateValue()
{
if (field) {
- setValue(float(*field)/multiplier());
+ lock = true;
+ setValue(float(*field) / multiplier());
+ lock = false;
}
}
@@ -81,11 +82,17 @@ class AutoDoubleSpinBox: public QDoubleSpinBox
}
}
+ signals:
+ void currentDataChanged(double value);
+
protected slots:
void onValueChanged(double value)
{
+ if (panel && panel->lock)
+ return;
if (field && !lock) {
*field = round(value * multiplier());
+ emit currentDataChanged(value);
if (panel) {
emit panel->modified();
}
@@ -93,9 +100,7 @@ class AutoDoubleSpinBox: public QDoubleSpinBox
}
protected:
- int * field;
- ModelPanel * panel;
- bool lock;
+ int * field = nullptr;
+ GenericPanel * panel = nullptr;
+ bool lock = false;
};
-
-#endif // _AUTODOUBLESPINBOX_H_
diff --git a/companion/src/shared/autohexspinbox.h b/companion/src/shared/autohexspinbox.h
index 7db76d2a3..40cc24da4 100644
--- a/companion/src/shared/autohexspinbox.h
+++ b/companion/src/shared/autohexspinbox.h
@@ -18,27 +18,26 @@
* GNU General Public License for more details.
*/
-#ifndef _AUTOHEXSPINBOX_H_
-#define _AUTOHEXSPINBOX_H_
+#pragma once
#include "hexspinbox.h"
-#include "modeledit/modeledit.h"
+#include "genericpanel.h"
class AutoHexSpinBox: public HexSpinBox
{
Q_OBJECT
public:
- explicit AutoHexSpinBox(QWidget *parent = 0):
+ explicit AutoHexSpinBox(QWidget * parent = nullptr):
HexSpinBox(parent),
- field(NULL),
- panel(NULL),
+ field(nullptr),
+ panel(nullptr),
lock(false)
{
connect(this, SIGNAL(valueChanged(int)), this, SLOT(onValueChanged(int)));
}
- void setField(unsigned int & field, ModelPanel * panel=NULL)
+ void setField(unsigned int & field, GenericPanel * panel = nullptr)
{
this->field = &field;
this->panel = panel;
@@ -48,15 +47,23 @@ class AutoHexSpinBox: public HexSpinBox
void updateValue()
{
if (field) {
+ lock = true;
setValue(*field);
+ lock = false;
}
}
+ signals:
+ void currentDataChanged(int value);
+
protected slots:
void onValueChanged(int value)
{
+ if (panel && panel->lock)
+ return;
if (field && !lock) {
*field = value;
+ emit currentDataChanged(value);
if (panel) {
emit panel->modified();
}
@@ -64,9 +71,7 @@ class AutoHexSpinBox: public HexSpinBox
}
protected:
- unsigned int * field;
- ModelPanel * panel;
- bool lock;
+ unsigned int * field = nullptr;
+ GenericPanel * panel = nullptr;
+ bool lock = false;
};
-
-#endif // _AUTOHEXSPINBOX_H_
diff --git a/companion/src/shared/autolineedit.h b/companion/src/shared/autolineedit.h
index 36d848972..b2815796c 100644
--- a/companion/src/shared/autolineedit.h
+++ b/companion/src/shared/autolineedit.h
@@ -18,8 +18,7 @@
* GNU General Public License for more details.
*/
-#ifndef _AUTOLINEEDIT_H_
-#define _AUTOLINEEDIT_H_
+#pragma once
#include
#include
@@ -30,11 +29,11 @@ class AutoLineEdit: public QLineEdit
Q_OBJECT
public:
- explicit AutoLineEdit(QWidget *parent = nullptr, bool updateOnChange = false):
+ explicit AutoLineEdit(QWidget * parent = nullptr, bool updateOnChange = false):
QLineEdit(parent),
field(NULL),
- strField(NULL),
- panel(NULL),
+ strField(nullptr),
+ panel(nullptr),
lock(false)
{
if (updateOnChange)
@@ -71,9 +70,14 @@ class AutoLineEdit: public QLineEdit
lock = false;
}
+ signals:
+ void currentDataChanged();
+
protected slots:
void onEdited()
{
+ if (panel && panel->lock)
+ return;
if (lock)
return;
@@ -84,15 +88,15 @@ class AutoLineEdit: public QLineEdit
else
return;
+ emit currentDataChanged();
+
if (panel)
emit panel->modified();
}
protected:
char * field;
- QString * strField;
- GenericPanel * panel;
- bool lock;
+ QString * strField = nullptr;
+ GenericPanel * panel = nullptr;
+ bool lock = false;
};
-
-#endif // _AUTOLINEEDIT_H_
diff --git a/companion/src/shared/autoprecisioncombobox.h b/companion/src/shared/autoprecisioncombobox.h
index 4e143f286..72dd89406 100644
--- a/companion/src/shared/autoprecisioncombobox.h
+++ b/companion/src/shared/autoprecisioncombobox.h
@@ -18,8 +18,7 @@
* GNU General Public License for more details.
*/
-#ifndef _AUTOPRECISIONCOMBOBOX_H_
-#define _AUTOPRECISIONCOMBOBOX_H_
+#pragma once
#include "genericpanel.h"
@@ -124,7 +123,7 @@ class AutoPrecisionComboBox: public QComboBox
if (*m_field != val) {
*m_field = rangecheckDecimals(val);
updateValue();
- emit valueChanged();
+ emit currentDataChanged(value);
}
}
@@ -135,7 +134,7 @@ class AutoPrecisionComboBox: public QComboBox
if (*m_field != value) {
*m_field = rangecheckDecimals(value);
updateValue();
- emit valueChanged();
+ emit currentDataChanged((int)value);
}
}
@@ -161,7 +160,7 @@ class AutoPrecisionComboBox: public QComboBox
}
signals:
- void valueChanged();
+ void currentDataChanged(int index);
protected slots:
void init()
@@ -204,13 +203,13 @@ class AutoPrecisionComboBox: public QComboBox
void onCurrentIndexChanged(int index)
{
- if (index < 0)
+ if (index < 0 || (m_panel && m_panel->lock) || m_lock)
return;
- if (m_field && !m_lock) {
+ if (m_field) {
*m_field = itemData(index).toUInt();
+ emit currentDataChanged(index);
if (m_panel)
emit m_panel->modified();
- emit valueChanged();
}
}
@@ -253,5 +252,3 @@ class AutoPrecisionComboBox: public QComboBox
QString m_suffix = "";
bool m_lock = false;
};
-
-#endif // _AUTOPRECISIONCOMBOBOX_H_
diff --git a/companion/src/shared/autotimeedit.h b/companion/src/shared/autotimeedit.h
new file mode 100644
index 000000000..2ba75d70e
--- /dev/null
+++ b/companion/src/shared/autotimeedit.h
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include
+#include "genericpanel.h"
+
+class AutoTimeEdit: public QTimeEdit
+{
+ Q_OBJECT
+
+ public:
+ explicit AutoTimeEdit(QWidget * parent = nullptr):
+ QTimeEdit(parent),
+ field(nullptr),
+ panel(nullptr),
+ lock(false)
+ {
+ connect(this, SIGNAL(timeChanged(QTime)), this, SLOT(onTimeChanged(QTime)));
+ }
+
+ void setField(unsigned int & field, GenericPanel * panel = nullptr)
+ {
+ this->field = &field;
+ this->panel = panel;
+ updateValue();
+ }
+
+ void setMinimumTime(const QTime time)
+ {
+ QTimeEdit::setMinimumTime(time);
+ }
+
+ void setMaximumTime(const QTime time)
+ {
+ QTimeEdit::setMaximumTime(time);
+ }
+
+ void setEnabled(bool enabled)
+ {
+ QTimeEdit::setEnabled(enabled);
+ }
+
+ void updateValue()
+ {
+ if (field) {
+ lock = true;
+ int hour = *field / 3600;
+ int min = (*field - (hour * 3600)) / 60;
+ int sec = (*field - (hour * 3600)) % 60;
+ setTime(QTime(hour, min, sec));
+ lock = false;
+ }
+ }
+
+ signals:
+ void currentDataChanged(unsigned int value);
+
+ protected slots:
+ void onTimeChanged(QTime time)
+ {
+ if (panel && panel->lock)
+ return;
+ if (!field || lock)
+ return;
+
+ unsigned int val = time.hour() * 3600 + time.minute() * 60 + time.second();
+ if (*field != val) {
+ *field = val;
+ emit currentDataChanged(val);
+ if (panel)
+ emit panel->modified();
+ }
+ }
+
+ protected:
+ unsigned int *field = nullptr;
+ GenericPanel *panel = nullptr;
+ bool lock = false;
+};
+
diff --git a/companion/src/shared/genericpanel.h b/companion/src/shared/genericpanel.h
index 5351355b6..88c7f841b 100644
--- a/companion/src/shared/genericpanel.h
+++ b/companion/src/shared/genericpanel.h
@@ -18,8 +18,7 @@
* GNU General Public License for more details.
*/
-#ifndef _GENERICPANEL_H_
-#define _GENERICPANEL_H_
+#pragma once
#include
@@ -40,6 +39,8 @@ class GenericPanel : public QWidget
friend class AutoLineEdit;
friend class GVarGroup;
friend class AutoPrecisionComboBox;
+ friend class AutoBitsetCheckBox;
+ friend class AutoTimeEdit;
public:
GenericPanel(QWidget *parent, ModelData * model, GeneralSettings & generalSettings, Firmware * firmware);
@@ -65,5 +66,3 @@ class GenericPanel : public QWidget
void setFocusFilter(QWidget * w);
void disableMouseScrolling();
};
-
-#endif // _GENERICPANEL_H_
diff --git a/companion/src/shared/hexspinbox.h b/companion/src/shared/hexspinbox.h
index fc404d98a..204cc8a55 100644
--- a/companion/src/shared/hexspinbox.h
+++ b/companion/src/shared/hexspinbox.h
@@ -18,8 +18,7 @@
* GNU General Public License for more details.
*/
-#ifndef _HEXSPINBOX_H_
-#define _HEXSPINBOX_H_
+#pragma once
#include
@@ -40,5 +39,3 @@ class HexSpinBox : public QSpinBox
private:
QRegExpValidator *validator;
};
-
-#endif // _HEXSPINBOX_H_
diff --git a/companion/src/shared/verticalscrollarea.h b/companion/src/shared/verticalscrollarea.h
index 36f564dd7..d409a18ca 100644
--- a/companion/src/shared/verticalscrollarea.h
+++ b/companion/src/shared/verticalscrollarea.h
@@ -18,8 +18,7 @@
* GNU General Public License for more details.
*/
-#ifndef _VERTICALSCROLLAREA_H_
-#define _VERTICALSCROLLAREA_H_
+#pragma once
#include
@@ -36,6 +35,3 @@ class VerticalScrollArea : public QScrollArea
private:
GenericPanel * panel;
};
-
-#endif // _VERTICALSCROLLAREA_H_
-
diff --git a/companion/src/simulation/CMakeLists.txt b/companion/src/simulation/CMakeLists.txt
index a03090888..d3c39d4fe 100644
--- a/companion/src/simulation/CMakeLists.txt
+++ b/companion/src/simulation/CMakeLists.txt
@@ -13,8 +13,11 @@ set(simulation_SRCS
simulateduiwidgetX10.cpp
simulateduiwidgetX12.cpp
simulateduiwidgetJumperT12.cpp
+ simulateduiwidgetJumperTLITE.cpp
simulateduiwidgetJumperT16.cpp
simulateduiwidgetJumperT18.cpp
+ simulateduiwidgetTX12.cpp
+ simulateduiwidgetT8.cpp
simulateduiwidgetTX16S.cpp
simulatorinterface.cpp
simulatormainwindow.cpp
@@ -39,8 +42,11 @@ set(simulation_UIS
simulateduiwidgetX10.ui
simulateduiwidgetX12.ui
simulateduiwidgetJumperT12.ui
+ simulateduiwidgetJumperTLITE.ui
simulateduiwidgetJumperT16.ui
simulateduiwidgetJumperT18.ui
+ simulateduiwidgetTX12.ui
+ simulateduiwidgetT8.ui
simulateduiwidgetTX16S.ui
simulatormainwindow.ui
simulatorstartupdialog.ui
diff --git a/companion/src/simulation/simulateduiwidget.h b/companion/src/simulation/simulateduiwidget.h
index 8419840c5..f9d92ecd7 100644
--- a/companion/src/simulation/simulateduiwidget.h
+++ b/companion/src/simulation/simulateduiwidget.h
@@ -112,9 +112,12 @@ namespace Ui {
class SimulatedUIWidgetX10;
class SimulatedUIWidgetX12;
class SimulatedUIWidgetJumperT12;
+ class SimulatedUIWidgetJumperTLITE;
class SimulatedUIWidgetJumperT16;
class SimulatedUIWidgetJumperT18;
class SimulatedUIWidgetTX16S;
+ class SimulatedUIWidgetTX12;
+ class SimulatedUIWidgetT8;
}
class SimulatedUIWidget9X: public SimulatedUIWidget
@@ -241,6 +244,18 @@ class SimulatedUIWidgetJumperT12: public SimulatedUIWidget
Ui::SimulatedUIWidgetJumperT12 * ui;
};
+class SimulatedUIWidgetJumperTLITE: public SimulatedUIWidget
+{
+ Q_OBJECT
+
+ public:
+ explicit SimulatedUIWidgetJumperTLITE(SimulatorInterface * simulator, QWidget * parent = NULL);
+ virtual ~SimulatedUIWidgetJumperTLITE();
+
+ private:
+ Ui::SimulatedUIWidgetJumperTLITE * ui;
+};
+
class SimulatedUIWidgetJumperT16: public SimulatedUIWidget
{
Q_OBJECT
@@ -265,6 +280,30 @@ class SimulatedUIWidgetJumperT18: public SimulatedUIWidget
Ui::SimulatedUIWidgetJumperT18 * ui;
};
+class SimulatedUIWidgetTX12: public SimulatedUIWidget
+{
+ Q_OBJECT
+
+ public:
+ explicit SimulatedUIWidgetTX12(SimulatorInterface * simulator, QWidget * parent = nullptr);
+ virtual ~SimulatedUIWidgetTX12();
+
+ private:
+ Ui::SimulatedUIWidgetTX12 * ui;
+};
+
+class SimulatedUIWidgetT8: public SimulatedUIWidget
+{
+Q_OBJECT
+
+public:
+ explicit SimulatedUIWidgetT8(SimulatorInterface * simulator, QWidget * parent = nullptr);
+ virtual ~SimulatedUIWidgetT8();
+
+private:
+ Ui::SimulatedUIWidgetT8 * ui;
+};
+
class SimulatedUIWidgetTX16S: public SimulatedUIWidget
{
Q_OBJECT
diff --git a/companion/src/simulation/simulateduiwidgetJumperTLITE.cpp b/companion/src/simulation/simulateduiwidgetJumperTLITE.cpp
new file mode 100644
index 000000000..2d5540837
--- /dev/null
+++ b/companion/src/simulation/simulateduiwidgetJumperTLITE.cpp
@@ -0,0 +1,60 @@
+#include "simulateduiwidget.h"
+#include "ui_simulateduiwidgetJumperTLITE.h"
+
+// NOTE: RadioUiAction(NUMBER,...): NUMBER relates to enum EnumKeys in the specific board.h
+
+SimulatedUIWidgetJumperTLITE::SimulatedUIWidgetJumperTLITE(SimulatorInterface *simulator, QWidget * parent):
+ SimulatedUIWidget(simulator, parent),
+ ui(new Ui::SimulatedUIWidgetJumperTLITE)
+{
+ RadioUiAction * act;
+
+ ui->setupUi(this);
+
+ act = new RadioUiAction(3, QList() << Qt::Key_Up << Qt::Key_PageUp, SIMU_STR_HLP_KEYS_GO_UP, SIMU_STR_HLP_ACT_UP);
+ addRadioWidget(ui->rightbuttons->addArea(QRect(40, 15, 70, 50), "JumperTLITE/right_top.png", act));
+
+ act = new RadioUiAction(2, QList() << Qt::Key_Down << Qt::Key_PageDown, SIMU_STR_HLP_KEYS_GO_DN, SIMU_STR_HLP_ACT_DN);
+ addRadioWidget(ui->rightbuttons->addArea(QRect(47, 65, 70, 50), "JumperTLITE/right_bottom.png", act));
+
+ act = new RadioUiAction(4, QList() << Qt::Key_Right << Qt::Key_Plus, SIMU_STR_HLP_KEY_RGT % "|" % SIMU_STR_HLP_KEY_PLS, SIMU_STR_HLP_ACT_PLS);
+ addRadioWidget(ui->bottombuttons->addArea(QRect(150, 73, 80, 30), "JumperTLITE/bottom_right.png", act));
+
+ act = new RadioUiAction(5, QList() << Qt::Key_Left << Qt::Key_Minus, SIMU_STR_HLP_KEY_LFT % "|" % SIMU_STR_HLP_KEY_MIN, SIMU_STR_HLP_ACT_MIN);
+ addRadioWidget(ui->bottombuttons->addArea(QRect(24, 73, 80, 30), "JumperTLITE/bottom_left.png", act));
+
+ m_mouseMidClickAction = new RadioUiAction(1, QList() << Qt::Key_Enter << Qt::Key_Return, SIMU_STR_HLP_KEYS_ACTIVATE, SIMU_STR_HLP_ACT_ENT);
+ addRadioWidget(ui->leftbuttons->addArea(QRect(5, 15, 70, 50), "JumperTLITE/left_top.png", m_mouseMidClickAction));
+
+ act = new RadioUiAction(0, QList() << Qt::Key_Delete << Qt::Key_Escape << Qt::Key_Backspace, SIMU_STR_HLP_KEYS_EXIT, SIMU_STR_HLP_ACT_EXIT);
+ addRadioWidget(ui->leftbuttons->addArea(QRect(10, 65, 70, 50), "JumperTLITE/left_bottom.png", act));
+
+ //addRadioWidget(ui->leftbuttons->addArea(QRect(10, 65, 70, 50), "JumperTLITE/left_scrnshot.png", m_screenshotAction));
+
+ m_backlightColors << QColor(215, 243, 255); // X7 Blue
+ m_backlightColors << QColor(166,247,159);
+ m_backlightColors << QColor(247,159,166);
+ m_backlightColors << QColor(255,195,151);
+ m_backlightColors << QColor(247,242,159);
+
+ setLcd(ui->lcd);
+
+ QString css = "#radioUiWidget {"
+ "background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:1,"
+ "stop:0 rgba(255, 255, 255, 255),"
+ "stop:0.757062 rgba(241, 238, 238, 255),"
+ "stop:1 rgba(247, 245, 245, 255));"
+ "}";
+
+ QTimer * tim = new QTimer(this);
+ tim->setSingleShot(true);
+ connect(tim, &QTimer::timeout, [this, css]() {
+ emit customStyleRequest(css);
+ });
+ tim->start(100);
+}
+
+SimulatedUIWidgetJumperTLITE::~SimulatedUIWidgetJumperTLITE()
+{
+ delete ui;
+}
diff --git a/companion/src/simulation/simulateduiwidgetJumperTLITE.ui b/companion/src/simulation/simulateduiwidgetJumperTLITE.ui
new file mode 100644
index 000000000..407b3954d
--- /dev/null
+++ b/companion/src/simulation/simulateduiwidgetJumperTLITE.ui
@@ -0,0 +1,258 @@
+
+
+ SimulatedUIWidgetJumperTLITE
+
+
+
+ 0
+ 0
+ 501
+ 310
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 501
+ 310
+
+
+
+
+ 501
+ 310
+
+
+
+ Jumper T-Lite Simulator
+
+
+ background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(255, 255, 255, 255), stop:0.757062 rgba(241, 238, 238, 255), stop:1 rgba(247, 245, 245, 255));
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 122
+ 287
+
+
+
+
+ 122
+ 287
+
+
+
+ background:url(:/images/simulator/JumperTLITE/left.png);
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 800
+ 155
+
+
+
+
+ 800
+ 155
+
+
+
+ background-color: rgb(215, 243, 255);
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 122
+ 287
+
+
+
+
+ 122
+ 287
+
+
+
+ background:url(:/images/simulator/JumperTLITE/right.png)
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 258
+ 26
+
+
+
+
+ 258
+ 26
+
+
+
+ background:url(:/images/simulator/JumperTLITE/top.png)
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 258
+ 106
+
+
+
+
+ 258
+ 106
+
+
+
+ background:url(:/images/simulator/JumperTLITE/bottom.png)
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 10
+
+
+
+
+ 16777215
+ 12
+
+
+
+
+ 0
+ 12
+
+
+
+ background-color: rgb(255, 255, 255);
+
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 10
+
+
+
+
+ 16777215
+ 10
+
+
+
+ background-color: rgb(247, 245, 245);
+
+
+
+
+
+
+
+
+
+
+ LcdWidget
+ QWidget
+
+ 1
+
+
+ ButtonsWidget
+ QWidget
+
+ 1
+
+
+
+
+
diff --git a/companion/src/simulation/simulateduiwidgetT8.cpp b/companion/src/simulation/simulateduiwidgetT8.cpp
new file mode 100644
index 000000000..ed86889d7
--- /dev/null
+++ b/companion/src/simulation/simulateduiwidgetT8.cpp
@@ -0,0 +1,67 @@
+#include "simulateduiwidget.h"
+#include "ui_simulateduiwidgetT8.h"
+
+// NOTE: RadioUiAction(NUMBER,...): NUMBER relates to enum EnumKeys in the specific board.h
+
+SimulatedUIWidgetT8::SimulatedUIWidgetT8(SimulatorInterface *simulator, QWidget * parent):
+ SimulatedUIWidget(simulator, parent),
+ ui(new Ui::SimulatedUIWidgetT8)
+{
+ RadioUiAction * act;
+
+ ui->setupUi(this);
+
+ // add actions in order of appearance on the help menu
+
+ act = new RadioUiAction(5, QList() << Qt::Key_Up, SIMU_STR_HLP_KEY_UP, SIMU_STR_HLP_ACT_MDL);
+ addRadioWidget(ui->rightbuttons->addArea(QRect(25, 40, 35, 20), "T8/right-mdl.png", act));
+
+ act = new RadioUiAction(6, QList() << Qt::Key_Enter << Qt::Key_Return, SIMU_STR_HLP_KEYS_GO_UP, SIMU_STR_HLP_ACT_UP);
+ addRadioWidget(ui->rightbuttons->addArea(QRect(25, 90, 35, 20), "T8/right-up.png", act));
+
+ act = new RadioUiAction(7, QList() << Qt::Key_Enter << Qt::Key_Return, SIMU_STR_HLP_KEYS_GO_DN, SIMU_STR_HLP_ACT_DN);
+ addRadioWidget(ui->rightbuttons->addArea(QRect(25, 135, 35, 20), "T8/right-dn.png", act));
+
+ act = new RadioUiAction(1, QList() << Qt::Key_Enter << Qt::Key_Return, SIMU_STR_HLP_KEYS_ACTIVATE, SIMU_STR_HLP_ACT_ENT);
+ addRadioWidget(ui->rightbuttons->addArea(QRect(25, 180, 35, 20), "T8/right-ent.png", act));
+
+ act = new RadioUiAction(4, QList() << Qt::Key_Left, SIMU_STR_HLP_KEY_LFT, SIMU_STR_HLP_ACT_SYS);
+ addRadioWidget(ui->leftbuttons->addArea(QRect(60, 45, 35, 20), "T8/left-sys.png", act));
+
+ act = new RadioUiAction(0, QList() << Qt::Key_Down << Qt::Key_Delete << Qt::Key_Escape << Qt::Key_Backspace, SIMU_STR_HLP_KEYS_EXIT, SIMU_STR_HLP_ACT_EXIT);
+ addRadioWidget(ui->leftbuttons->addArea(QRect(60, 85, 35, 20), "T8/left-rtn.png", act));
+
+ act = new RadioUiAction(3, QList() << Qt::Key_PageDown, SIMU_STR_HLP_KEY_PGDN, SIMU_STR_HLP_ACT_PGDN);
+ addRadioWidget(ui->leftbuttons->addArea(QRect(60, 135, 35, 20), "T8/left-pagedn.png", act));
+
+ act = new RadioUiAction(2, QList() << Qt::Key_PageUp, SIMU_STR_HLP_KEY_PGUP, SIMU_STR_HLP_ACT_PGUP);
+ addRadioWidget(ui->leftbuttons->addArea(QRect(60, 180, 35, 20), "T8/left-pageup.png", act));
+
+
+ m_backlightColors << QColor(215, 243, 255); // X7 Blue
+ m_backlightColors << QColor(166,247,159);
+ m_backlightColors << QColor(247,159,166);
+ m_backlightColors << QColor(255,195,151);
+ m_backlightColors << QColor(247,242,159);
+
+ setLcd(ui->lcd);
+
+ QString css = "#radioUiWidget {"
+ "background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:1,"
+ "stop:0 rgba(255, 255, 255, 255),"
+ "stop:0.757062 rgba(241, 238, 238, 255),"
+ "stop:1 rgba(247, 245, 245, 255));"
+ "}";
+
+ QTimer * tim = new QTimer(this);
+ tim->setSingleShot(true);
+ connect(tim, &QTimer::timeout, [this, css]() {
+ emit customStyleRequest(css);
+ });
+ tim->start(100);
+}
+
+SimulatedUIWidgetT8::~SimulatedUIWidgetT8()
+{
+ delete ui;
+}
diff --git a/companion/src/simulation/simulateduiwidgetT8.ui b/companion/src/simulation/simulateduiwidgetT8.ui
new file mode 100644
index 000000000..6370888ea
--- /dev/null
+++ b/companion/src/simulation/simulateduiwidgetT8.ui
@@ -0,0 +1,258 @@
+
+
+ SimulatedUIWidgetT8
+
+
+
+ 0
+ 0
+ 480
+ 300
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 480
+ 300
+
+
+
+
+ 480
+ 300
+
+
+
+ Radiomaster T8 Simulator
+
+
+ background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(255, 255, 255, 255), stop:0.757062 rgba(241, 238, 238, 255), stop:1 rgba(247, 245, 245, 255));
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 113
+ 280
+
+
+
+
+ 113
+ 280
+
+
+
+ background:url(:/images/simulator/T8/left.png);
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 254
+ 158
+
+
+
+
+ 254
+ 158
+
+
+
+ background-color: rgb(215, 243, 255);
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 113
+ 280
+
+
+
+
+ 113
+ 280
+
+
+
+ background:url(:/images/simulator/T8/right.png)
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 254
+ 35
+
+
+
+
+ 254
+ 35
+
+
+
+ background:url(:/images/simulator/T8/top.png)
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 254
+ 113
+
+
+
+
+ 254
+ 113
+
+
+
+ background:url(:/images/simulator/T8/bottom.png)
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 10
+
+
+
+
+ 16777215
+ 12
+
+
+
+
+ 0
+ 12
+
+
+
+ background-color: rgb(255, 255, 255);
+
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 10
+
+
+
+
+ 16777215
+ 10
+
+
+
+ background-color: rgb(247, 245, 245);
+
+
+
+
+
+
+
+
+
+
+ LcdWidget
+ QWidget
+
+ 1
+
+
+ ButtonsWidget
+ QWidget
+
+ 1
+
+
+
+
+
diff --git a/companion/src/simulation/simulateduiwidgetTX12.cpp b/companion/src/simulation/simulateduiwidgetTX12.cpp
new file mode 100644
index 000000000..8e7c518f0
--- /dev/null
+++ b/companion/src/simulation/simulateduiwidgetTX12.cpp
@@ -0,0 +1,67 @@
+#include "simulateduiwidget.h"
+#include "ui_simulateduiwidgetTX12.h"
+
+// NOTE: RadioUiAction(NUMBER,...): NUMBER relates to enum EnumKeys in the specific board.h
+
+SimulatedUIWidgetTX12::SimulatedUIWidgetTX12(SimulatorInterface *simulator, QWidget * parent):
+ SimulatedUIWidget(simulator, parent),
+ ui(new Ui::SimulatedUIWidgetTX12)
+{
+ RadioUiAction * act;
+
+ ui->setupUi(this);
+
+ // add actions in order of appearance on the help menu
+
+ act = new RadioUiAction(5, QList() << Qt::Key_Up, SIMU_STR_HLP_KEY_UP, SIMU_STR_HLP_ACT_MDL);
+ addRadioWidget(ui->rightbuttons->addArea(QRect(60, 5, 90, 60), "TX12/right-mdl.png", act));
+
+ m_mouseMidClickAction = new RadioUiAction(1, QList() << Qt::Key_Enter << Qt::Key_Return, SIMU_STR_HLP_KEYS_ACTIVATE, SIMU_STR_HLP_ACT_ROT_DN);
+ addRadioWidget(ui->rightbuttons->addArea(QRect(45, 100, 70, 120), "TX12/right-ent.png", m_mouseMidClickAction));
+
+ act = new RadioUiAction(4, QList() << Qt::Key_Left, SIMU_STR_HLP_KEY_LFT, SIMU_STR_HLP_ACT_SYS);
+ addRadioWidget(ui->leftbuttons->addArea(QRect(35, 5, 80, 50), "TX12/left-sys.png", act));
+
+ act = new RadioUiAction(6, QList() << Qt::Key_Right, SIMU_STR_HLP_KEY_RGT, SIMU_STR_HLP_ACT_TELE);
+ addRadioWidget(ui->leftbuttons->addArea(QRect(90, 210, 80, 35), "TX12/left-tele.png", act));
+
+ act = new RadioUiAction(3, QList() << Qt::Key_PageDown, SIMU_STR_HLP_KEY_PGDN, SIMU_STR_HLP_ACT_PGDN);
+ addRadioWidget(ui->leftbuttons->addArea(QRect(75, 125, 80, 35), "TX12/left-pagedn.png", act));
+
+ act = new RadioUiAction(2, QList() << Qt::Key_PageUp, SIMU_STR_HLP_KEY_PGUP, SIMU_STR_HLP_ACT_PGUP);
+ addRadioWidget(ui->leftbuttons->addArea(QRect(80, 170, 80, 35), "TX12/left-pageup.png", act));
+
+ act = new RadioUiAction(0, QList() << Qt::Key_Down << Qt::Key_Delete << Qt::Key_Escape << Qt::Key_Backspace, SIMU_STR_HLP_KEYS_EXIT, SIMU_STR_HLP_ACT_EXIT);
+ addRadioWidget(ui->leftbuttons->addArea(QRect(70, 85, 80, 35), "TX12/left-rtn.png", act));
+
+ m_scrollUpAction = new RadioUiAction(-1, QList() << Qt::Key_Minus << Qt::Key_Equal << Qt::Key_Left, SIMU_STR_HLP_KEYS_GO_LFT, SIMU_STR_HLP_ACT_ROT_LFT);
+ m_scrollDnAction = new RadioUiAction(-1, QList() << Qt::Key_Plus << Qt::Key_Right, SIMU_STR_HLP_KEYS_GO_RGT, SIMU_STR_HLP_ACT_ROT_RGT);
+ connectScrollActions();
+
+ m_backlightColors << QColor(215, 243, 255); // X7 Blue
+ m_backlightColors << QColor(166,247,159);
+ m_backlightColors << QColor(247,159,166);
+ m_backlightColors << QColor(255,195,151);
+ m_backlightColors << QColor(247,242,159);
+
+ setLcd(ui->lcd);
+
+ QString css = "#radioUiWidget {"
+ "background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:1,"
+ "stop:0 rgba(255, 255, 255, 255),"
+ "stop:0.757062 rgba(241, 238, 238, 255),"
+ "stop:1 rgba(247, 245, 245, 255));"
+ "}";
+
+ QTimer * tim = new QTimer(this);
+ tim->setSingleShot(true);
+ connect(tim, &QTimer::timeout, [this, css]() {
+ emit customStyleRequest(css);
+ });
+ tim->start(100);
+}
+
+SimulatedUIWidgetTX12::~SimulatedUIWidgetTX12()
+{
+ delete ui;
+}
diff --git a/companion/src/simulation/simulateduiwidgetTX12.ui b/companion/src/simulation/simulateduiwidgetTX12.ui
new file mode 100644
index 000000000..8d51ba2e6
--- /dev/null
+++ b/companion/src/simulation/simulateduiwidgetTX12.ui
@@ -0,0 +1,258 @@
+
+
+ SimulatedUIWidgetTX12
+
+
+
+ 0
+ 0
+ 641
+ 272
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 641
+ 272
+
+
+
+
+ 641
+ 272
+
+
+
+ Taranis TX12 Simulator
+
+
+ background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(255, 255, 255, 255), stop:0.757062 rgba(241, 238, 238, 255), stop:1 rgba(247, 245, 245, 255));
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 196
+ 253
+
+
+
+
+ 196
+ 253
+
+
+
+ background:url(:/images/simulator/TX12/left.png);
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 256
+ 128
+
+
+
+
+ 424
+ 128
+
+
+
+ background-color: rgb(215, 243, 255);
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 189
+ 253
+
+
+
+
+ 189
+ 253
+
+
+
+ background:url(:/images/simulator/TX12/right.png)
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 261
+ 101
+
+
+
+
+ 261
+ 101
+
+
+
+ background:url(:/images/simulator/TX12/top.png)
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 261
+ 24
+
+
+
+
+ 261
+ 24
+
+
+
+ background:url(:/images/simulator/TX12/bottom.png)
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 10
+
+
+
+
+ 16777215
+ 12
+
+
+
+
+ 0
+ 12
+
+
+
+ background-color: rgb(255, 255, 255);
+
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 10
+
+
+
+
+ 16777215
+ 10
+
+
+
+ background-color: rgb(247, 245, 245);
+
+
+
+
+
+
+
+
+
+
+ LcdWidget
+ QWidget
+
+ 1
+
+
+ ButtonsWidget
+ QWidget
+
+ 1
+
+
+
+
+
diff --git a/companion/src/simulation/simulatorwidget.cpp b/companion/src/simulation/simulatorwidget.cpp
index f70813442..b4160a579 100644
--- a/companion/src/simulation/simulatorwidget.cpp
+++ b/companion/src/simulation/simulatorwidget.cpp
@@ -91,12 +91,21 @@ SimulatorWidget::SimulatorWidget(QWidget * parent, SimulatorInterface * simulato
case Board::BOARD_JUMPER_T12:
radioUiWidget = new SimulatedUIWidgetJumperT12(simulator, this);
break;
+ case Board::BOARD_JUMPER_TLITE:
+ radioUiWidget = new SimulatedUIWidgetJumperTLITE(simulator, this);
+ break;
case Board::BOARD_JUMPER_T16:
radioUiWidget = new SimulatedUIWidgetJumperT16(simulator, this);
break;
case Board::BOARD_JUMPER_T18:
radioUiWidget = new SimulatedUIWidgetJumperT18(simulator, this);
break;
+ case Board::BOARD_RADIOMASTER_TX12:
+ radioUiWidget = new SimulatedUIWidgetTX12(simulator, this);
+ break;
+ case Board::BOARD_RADIOMASTER_T8:
+ radioUiWidget = new SimulatedUIWidgetT8(simulator, this);
+ break;
case Board::BOARD_RADIOMASTER_TX16S:
radioUiWidget = new SimulatedUIWidgetTX16S(simulator, this);
break;
diff --git a/companion/src/translations.cpp b/companion/src/translations.cpp
index 76d63b425..415d00ba8 100644
--- a/companion/src/translations.cpp
+++ b/companion/src/translations.cpp
@@ -48,6 +48,7 @@ QStringList const Translations::getAvailableTranslations()
<< "ru_RU"
<< "sv_SE"
<< "zh_CN"
+ << "zh_TW"
<< "ja_JP" ;
}
return locales;
diff --git a/companion/src/translations/companion_es.ts b/companion/src/translations/companion_es.ts
index bdd44458d..de7f3cf00 100644
--- a/companion/src/translations/companion_es.ts
+++ b/companion/src/translations/companion_es.ts
@@ -94,57 +94,57 @@
AppPreferencesDialog
-
-
+
+
Edit Settings
Editar ajustes
-
-
+
+
Radio Profile
Perfil de radio
-
-
+
+
Default Channel Order
Orden prederterminado canales
-
-
+
+
Build Options
Opciones del firmware
-
-
+
+
Menu Language
Lenguaje de los menús
-
-
+
+
Default Stick Mode
Modo prederterminado sticks
-
-
+
+
Select Image
Seleccionar imagen
-
-
+
+
Mode selection:
Mode 1:
@@ -186,729 +186,736 @@ Modo 4:
-
-
+
+
Mode 1 (RUD ELE THR AIL)
Modo 1 (RUD ELE THR AIL)
-
-
+
+
Mode 2 (RUD THR ELE AIL)
Modo 2 (RUD THR ELE AIL)
-
-
+
+
Mode 3 (AIL ELE THR RUD)
Modo 3 (AIL ELE THR RUD)
-
-
+
+
Mode 4 (AIL THR ELE RUD)
Modo 4 (AIL THR ELE RUD)
-
-
+
+
Splash Screen
Pantalla de inicio
-
-
-
-
+
+
+
+
The profile specific folder, if set, will override general Backup folder
La carpeta específica del perfil, si está fijada, anulará la carpeta de copia de seguridad general
-
-
+
+
Backup folder
Carpeta de copia de seguridad
-
-
+
+
If set it will override the application general setting
Si está fijado anulará los ajustes generales de la aplicación>
-
-
+
+
if set, will override general backup enable
si está fijado anulará la copia de seguridad general>
-
-
+
+
<html><head/><body><p>Channel order</p><p><br/></p><p>Defines the order of the default mixes created on a new model.</p></body></html>
<html><head/><body><p>Orden de los canales</p><p><br/></p><p>Define el orden por defecto de las mezclas en un nuevo modelo</p></body></html>
-
-
+
+
R E T A
-
-
+
+
R E A T
-
-
+
+
R T E A
-
-
+
+
R T A E
-
-
+
+
R A E T
-
-
+
+
R A T E
-
-
+
+
E R T A
-
-
+
+
E R A T
-
-
+
+
E T R A
-
-
+
+
E T A R
-
-
+
+
E A R T
-
-
+
+
E A T R
-
-
+
+
T R E A
-
-
+
+
T R A E
-
-
+
+
T E R A
-
-
+
+
T E A R
-
-
+
+
T A R E
-
-
+
+
T A E R
-
-
+
+
A R E T
-
-
+
+
A R T E
-
-
+
+
A E R T
-
-
+
+
A E T R
-
-
+
+
A T R E
-
-
+
+
A T E R
-
-
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
-
+
+
+
Select Folder
Selecciona carpeta
-
-
-
+
+
+
+ Show splash screen
+ Mostrar pantalla de inicio
+
+
+
+
+
Select Executable
Selecciona ejecutable
-
-
-
+
+
+
Release channel
Canal de distribución
-
-
-
+
+
+
Releases (stable)
Releases (estable)
-
-
-
+
+
+
Release candidates (testing)
Release candidates (testing)
-
-
-
+
+
+
Nightly builds (unstable)
Nightly builds (inestable)
-
-
-
+
+
+
Simulator Volume Gain
Ganancia de volumen del simulador
-
-
-
+
+
+
Simulator controls
Controles de simulador
-
-
-
+
+
+
Save switch/pot positions on simulator exit
Guardar las posiciones de interruptores/pots al salir del simulador
-
-
-
+
+
+
Clear saved positions
Limpiar las posiciones guardadas
-
-
+
+
Profile Name
Nombre de perfil
-
-
+
+
Clear Image
Limpiar imagen
-
-
+
+
Append version number to FW file name
Agregar el número de versión al nombre de archivo de firmware
-
-
+
+
Offer to write FW to Tx after download
Ofrecer grabar el firmware al Tx después de la descarga
-
-
+
+
Radio Type
Tipo de radio
-
-
+
+
Other Settings
Otros ajustes
-
-
+
+
General Settings
Ajustes generales
-
-
+
+
SD Structure path
Estructura de archivos SD
-
-
+
+
Application Settings
Ajustes de la aplicación
-
-
-
- Show splash screen when Companion starts
- Mostrar pantalla de inicio cuando Companion comience
-
-
-
-
-
+
+
+
Automatic check for Companion updates
Comprobar automáticamente actualizaciones de Companion
-
-
-
-
-
+
+
+
+
+
Enable automatic backup before writing firmware
Activar copia de seguridad automática antes de escribir el firmware
-
-
-
+
+
+
Automatic check for OpenTX firmware updates
Comprobar automáticamente actualizaciones del firmware OpenTX
-
-
-
+
+
+
Splash Screen Library
Librería de pantallas de inicio
-
-
-
+
+
+
Google Earth Executable
Ejecutable Google Earth
-
-
-
+
+
+
Only show user splash images
Mostrar sólo pantallas de inicio de usuario
-
-
-
+
+
+
Show user and companion splash images
Mostrar pantallas de inicio de usuario y companion
-
-
-
+
+
+
User Splash Screens
Pantallas de inicio de usuario
-
-
-
+
+
+
Automatic Backup Folder
Carpeta copia de seguridad automática
-
-
-
+
+
+
Simulator Settings
Ajustes del simulador
-
-
-
+
+
+
Simulator BackLight
Luz de fondo del simulador
-
-
-
+
+
+
Enable
Activado
-
-
-
+
+
+
most recently used files
ficheros usados recientemente
-
-
-
+
+
+
Startup Settings
Ajustes de inicio
-
-
-
+
+
+
Remember
Recordar
-
-
-
+
+
+
Output Logs Folder
Carpeta de reportes
-
-
-
+
+
+
<html><head/><body><p>This option maintains the behaviour from older OpenTx versions where empty model slots are preserved when a model is deleted or moved. </p><p>When this option is de-selected, the other models may be re-arranged to fill the gap left by the removed model.</p></body></html>
<html><head/><body><p>Esta opción mantiene el comportamiento de las versiones anteriores de OpenTx donde se conservan los slots de modelos vacíos cuando se elimina o mueve un modelo. </p><p>Cuando esta opción no está seleccionada, los otros modelos pueden reordenarse para llenar el hueco dejado por el modelo borrado.</p></body></html>
-
-
-
+
+
+
Remove empty model slots when deleting models (only applies for radios w/out categories)
Eliminar los slots vacíos cuando se borran modelos (sólo aplica a radios sin categorías)
-
+
Use model wizard
Usar el asistente de modelos
-
+
Open model editor
Abrir el editor de modelos
-
+
Just create the model
Sólo crear el modelo
-
-
-
+
+
+
Debug Output Logging
Reporte de depuración
-
-
-
+
+
+
<html><head/><body><p>Keep a log of all debugging messages generated by the desktop Companion/Simulator applications. An OpenTX developer may request this to help diagnose an issue.</p></body></html>
<html><head/><body><p>Mantiene un reporte para todos los mensajes de depuración generados por las aplicaciones Companion/Simulador. Un desarrollador de OpenTX los puede requerir para ayudar a diagnosticar el problema.</p></body></html>
-
-
-
+
+
+
Application (Companion/Simulator)
Aplicación (Companion/simulador)
-
-
-
+
+
+
<html><head/><body><p>Keep a log of all messages generated by the radio firmware when running in Simulator. This is the same information one would also see in the Simulator <span style=" font-style:italic;">Debug Output</span> window.</p></body></html>
<html><head/><body><p>Mantiene un log para todos los mensajes generados por el firmware de la radio mientras se ejecuta en el simulador. Esta es la misma información que se vería en el simulador <span style=" font-style:italic;">Salida de depuración</span> ventana.</p></body></html>
-
-
-
+
+
+
Radio Firmware (in Simulator)
Radio firmware (en simulador)
-
-
-
+
+
+
Action on New Model
Accioń en nuevo modelo
-
-
-
+
+
+
+ Prompt for radio profile
+ Preguntar por perfil de radio
+
+
+
+
+
Blue
Azul
-
-
-
+
+
+
Green
Verde
-
-
-
+
+
+
Red
Rojo
-
-
-
+
+
+
Orange
Naranja
-
-
-
+
+
+
Yellow
Amarillo
-
-
-
+
+
+
Screenshot capture folder
Carpeta de capturas de pantalla
-
-
-
+
+
+
Joystick
Joystick
-
-
-
+
+
+
Calibrate
Calibrar
-
-
-
+
+
+
Only capture to clipboard
Sólo capturar al portapapeles
-
+
My Radio
Mi radio
-
+
<p><b>You cannot switch Radio Type or change Build Options while there are unsaved file changes. What do you wish to do?</b></p> <ul><li><i>Save All</i> - Save any open file(s) before saving Settings.<li><li><i>Reset</i> - Revert to the previous Radio Type and Build Options before saving Settings.</li><li><i>Cancel</i> - Return to the Settings editor dialog.</li></ul>
<p><b>No puedes cambiar el tipo de radio o las opciones del firmware mientras hay cambios sin guardar ¿Qué quieres hacer?</b></p> <ul><li><i>Guardar todo</i> - Guardar los archivos abiertos andtes de guardar los ajustes.<li><li><i>Resetear</i> - Volver al tipo de radio y opciones de firmware anteriores antes de salvar los los ajustes.</li><li><i>Cancelar</i> - Volver a la ventana de edición de ajustes.</li></ul>
-
+
Select your snapshot folder
Selecciona la carpeta de capturas
-
+
Note: Nightly builds are not available in this version, Release/RC update channel will be used.
Nota: No hay nightly builds para esta versión, se usará el canal Release/RC.
-
-
+
+
No joysticks found
No se han encontrado joysticks
-
+
EMPTY: No radio settings stored in profile
VACÍO: No se han guardado ajustes en el perfil de tu radio
-
+
AVAILABLE: Radio settings of unknown age
DISPONIBLE:Ajustes de radio de antigüedad desconocida
-
+
AVAILABLE: Radio settings stored %1
DISPONIBLE: Ajustes de radio guardados %1
-
+
Select your library folder
Selecciona tu carpeta de librerías
-
-
+
+
Select your Models and Settings backup folder
Selecciona la carpeta de seguridad de tus modelos y ajustes
-
+
Select a folder for application logs
Selecciona una carpeta para los reportes de la aplicación
-
+
Select Google Earth executable
Selecciona el ejecutable de Google Earth
-
+
Select the folder replicating your SD structure
Selecciona la carpeta que replica la estructura de tu tarjeta SD
-
+
Open Image to load
Abre imagen para cargar
-
+
Images (%1)
Imágenes (%1)
@@ -948,58 +955,58 @@ Modo 4:
Boards
-
+
Left Horizontal
Izquierda horizontal
-
+
Left Vertical
Izquierda vertical
-
+
Right Vertical
Derecha vertical
-
+
Right Horizontal
Derecha horizontal
-
+
Aux. 1
-
+
Aux. 2
-
-
+
+
Unknown
Desconocido
-
+
Rud
-
+
Ele
-
+
Thr
-
+
Ail
@@ -1046,112 +1053,132 @@ Modo 4:
- Channels
+ ChannelsPanel
-
+
Name
Nombre
-
- Min
- Mín
-
-
-
- Max
- Máx
-
-
-
+
Subtrim
-
+
+ Min
+
+
+
+
+ Max
+
+
+
+
Direction
Dirección
-
+
Curve
Curva
-
+
PPM Center
Centro PPM
-
+
Linear Subtrim
Subtrim lineal
-
+
CH%1
-
+
Popup menu available
Menú emergente disponible
-
+
---
-
+
INV
-
+
+ Delete Channel. Are you sure?
+ Borrar canal ¿Estás seguro?
+
+
+
+ Cut Channel. Are you sure?
+ Cortar canal ¿Estás seguro?
+
+
+
Copy
Copiar
-
+
Cut
Cortar
-
+
Paste
Pegar
-
+
Clear
Limpiar
-
+
Insert
Insertar
-
+
Delete
Borrar
-
+
Move Up
Mover arriba
-
+
Move Down
Mover abajo
-
+
Clear All
Limpiar todo
+
+
+ Clear Channel. Are you sure?
+ Limpiar canal ¿Estás seguro?
+
+
+
+ Clear all Channels. Are you sure?
+ Limpiar todos los canales ¿Estás seguro?
+
ChecklistDialog
@@ -1592,7 +1619,7 @@ Si tienes un archivo de backup, puedes importar en su lugar.
CurveData
-
+
CV
@@ -1767,81 +1794,119 @@ Si tienes un archivo de backup, puedes importar en su lugar.
Curve name
Nombre de la curva
+
+
+ CurvesPanel
-
+
Curve %1
Curva %1
-
+
Popup menu available
- Menú desplegable disponible
+ Menú emergente disponible
-
+
%1 points
%1 puntos
-
+
Linear
Lineal
-
+
Single Expo
Expo único
-
+
Symmetrical f(x)=-f(-x)
Simétricas f(x)=-f(-x)
-
+
Symmetrical f(x)=f(-x)
Simétricas f(x)=f(-x)
-
- Copy
- Copiar
-
-
-
- Paste
- Pegar
-
-
-
- Clear
- Limpiar
-
-
-
- Clear all curves
- Limpiar todas las curvas
-
-
-
- Are you sure you want to reset curve %1?
- ¿Seguro que quieres resetear todas la curva %1?
-
-
-
- Are you sure you want to reset all curves?
- ¿Seguro que quiere resetear todas las curvas?
-
-
-
+
Editing curve %1
Edición de curva %1
-
+
Not enough free points in EEPROM to store the curve.
No hay suficientes puntos libres en la EEPROM para guardar la curva.
+
+
+ Copy
+ Copiar
+
+
+
+ Cut
+ Cortar
+
+
+
+ Paste
+ Pegar
+
+
+
+ Clear
+ Limpiar
+
+
+
+ Insert
+ Insertar
+
+
+
+ Delete
+ Borrar
+
+
+
+ Move Up
+ Mover arriba
+
+
+
+ Move Down
+ Mover abajo
+
+
+
+ Clear All
+ Limpiar todo
+
+
+
+ Clear Curve. Are you sure?
+ Limpiar curva ¿Estás seguro?
+
+
+
+ Clear all Curves. Are you sure?
+ Limpiar todas las curvas ¿Estás seguro?
+
+
+
+ Cut Curve. Are you sure?
+ Cortar curva ¿Estás seguro?
+
+
+
+ Delete Curve. Are you sure?
+ Borrar curva ¿Estás seguro?
+
CustomFunctionData
@@ -1862,8 +1927,8 @@ Si tienes un archivo de backup, puedes importar en su lugar.
- Trainer
- Entrenador
+ Trainer Sticks
+ Sticks entrenador
@@ -2006,79 +2071,79 @@ Si tienes un archivo de backup, puedes importar en su lugar.
Bind módulo externo
-
+
Timer1
Temporizador 1
-
+
Timer2
Temporizador 2
-
+
Timer3
Temporizador 3
-
+
Flight
Vuelo
-
+
Telemetry
Telemetría
-
+
Rotary Encoder
Codificador rotativo
-
+
REa
-
+
REb
-
+
s
-
-
-
+
+
+
<font color=red><b>Inconsistent parameter</b></font>
<font color=red><b>Parámetro Inconsistente</b></font>
-
+
Value
Valor
-
+
played once, not during startup
reproducido una vez, no durante el inicio
-
+
repeat(%1s)
repetir(%1s)
-
+
DISABLED
DESABILITADO
-
+
CFN
@@ -2086,122 +2151,144 @@ Si tienes un archivo de backup, puedes importar en su lugar.
CustomFunctionsPanel
-
+
Switch
Interruptor
-
+
Action
Acción
-
+
Parameters
Parámetros
-
+
Enable
Activar
-
+
Popup menu available
Menú deplegable disponible
-
+
SF%1
-
+
GF%1
-
+
ON
-
+
Error occurred while trying to play sound, possibly the file is already opened. (Err: %1 [%2])
Ha ocurrido un error al reproducir el sonido, posiblemente el archivo ya está abierto. (Err: %1 [%2])
-
+
Unable to find or open sound file:
%1
No se puede encontrar o abrir el archivo de sonido:
%1
-
+
+ Delete Function. Are you sure?
+ Borrar función ¿Estás seguro?
+
+
+
+
+ Cut Special Function. Are you sure?
+ Cortar función especial ¿Estás seguro?
+
+
+
+
Copy
Copiar
-
+
Cut
Cortar
-
+
Paste
Pegar
-
+
Clear
Limpiar
-
+
Insert
Insertar
-
+
Delete
Borrar
-
+
Move Up
Mover arriba
-
+
Move Down
Mover abajo
-
+
Clear All
Limpiar todo
-
+
Value
Valor
-
+
Source
Fuente
-
+
GVAR
-
+
Increment
Incremento
+
+
+ Clear Function. Are you sure?
+ Limpiar función ¿Estás seguro?
+
+
+
+ Clear all Functions. Are you sure?
+ Limpiar todas funciones ¿Estás seguro?
+
CustomizeSplashDialog
@@ -2400,48 +2487,48 @@ Si tienes un archivo de backup, puedes importar en su lugar.
Error de conversión en el campo %1
-
+
Switch
Interruptor
-
+
Switch
Interruptor
-
+
cannot be exported on this board!
no puede ser exportada en esta placa!
-
+
Source
Fuente
-
+
Source %1 cannot be exported on this board!
¡La fuente %1 no puede ser exportada a esta placa!
-
+
OpenTX only accepts %1 points in all curves
OpenTX sólo acepta %1 puntos en todas las curvas
-
+
OpenTx only accepts %1 points in all curves
OpenTX sólo acepta %1 puntos en todas las curvas
-
-
+
+
OpenTX on this board doesn't accept this function
OpenTX en esta placa no acepta esa función
-
+
OpenTX doesn't accept this radio protocol
OpenTX no acepta este protocolo de radio
@@ -2452,6 +2539,7 @@ Si tienes un archivo de backup, puedes importar en su lugar.
+
Debug Output
Salida de depuración
@@ -2459,6 +2547,7 @@ Si tienes un archivo de backup, puedes importar en su lugar.
+
<html><head/><body><p>Enable or disable the filter. If the button won't stay enabled, it is likely there is a syntax error in the Regular Expression entered.</p></body></html>
<html><head/><body><p>Activa/desactiva el filtro. Si el botón no permanece activo, probablemente hay un error de sintaxis en la expresión introducida.</p></body></html>
@@ -2466,6 +2555,7 @@ Si tienes un archivo de backup, puedes importar en su lugar.
+
Filter:
Filtro:
@@ -2473,6 +2563,7 @@ Si tienes un archivo de backup, puedes importar en su lugar.
+
<html><head/><body><p>Enter filter text here. Click the help/info button for details about using the filter. </p><p>
To <b>remove a remembered entry</b> from the filter list, first choose it, and then press <code>Shift-Delete</code> (or <code>Shift-Backspace</code>) key combination.</p></body></html>
<html><head/><body><p>Introduce fitro de texto aquí. Presiona el botón de ayuda/info para detalles acerca del uso del filtro. </p><p>
@@ -2482,6 +2573,7 @@ Para <b>eliminar una entrada recordada</b> desde la lista de filtros
+
Buffer:
Buffer:
@@ -2489,6 +2581,7 @@ Para <b>eliminar una entrada recordada</b> desde la lista de filtros
+
Number of lines to keep in display.
Número de líneas a mantener en display.
@@ -2496,6 +2589,7 @@ Para <b>eliminar una entrada recordada</b> desde la lista de filtros
+
Filter &Help
&Ayuda filtros
@@ -2503,6 +2597,7 @@ Para <b>eliminar una entrada recordada</b> desde la lista de filtros
+
Show information about using the filter.
Muestra información acerca del uso de filtros.
@@ -2510,6 +2605,7 @@ Para <b>eliminar una entrada recordada</b> desde la lista de filtros
+
Word &Wrap
Ajuste de &línea
@@ -2517,6 +2613,7 @@ Para <b>eliminar una entrada recordada</b> desde la lista de filtros
+
Toggle word wrapping on/off.
Habilita/desabilita ajuste de línea.
@@ -2524,6 +2621,7 @@ Para <b>eliminar una entrada recordada</b> desde la lista de filtros
+
&Clear
&Limpiar
@@ -2531,6 +2629,7 @@ Para <b>eliminar una entrada recordada</b> desde la lista de filtros
+
Clear the output window of all text.
Limpia de texto la ventana de salida.
@@ -2538,6 +2637,7 @@ Para <b>eliminar una entrada recordada</b> desde la lista de filtros
+
Enable &Filter
Habilitar &filtro
@@ -2545,6 +2645,7 @@ Para <b>eliminar una entrada recordada</b> desde la lista de filtros
+
Turn the filter on/off.
Apaga/enciende el filtro.
@@ -2598,69 +2699,54 @@ Para <b>eliminar una entrada recordada</b> desde la lista de filtros
- - Eeprom is not from Th9X
- - Eeprom no es de Th9X
-
-
-
- - Eeprom is not from Gruvin9X
- - Eeprom no es de Gruvin9X
-
-
-
- Eeprom is not from ErSky9X
- Eeprom no es de ErSky9X
-
- - Eeprom is not from Er9X
- - Eeprom no es de Er9X
-
-
-
+
- Eeprom size is invalid
- Tamaño de eeprom no es válido
-
+
- Eeprom file system is invalid
- Sistema de archivos de eeprom no es válido
-
+
- Eeprom is from a unknown board
- Eeprom es de una placa desconocida
-
+
- Eeprom is from the wrong board
- Eeprom es de una placa errónea
-
+
- Eeprom backup not supported
- Backup de Eeprom no soportado
-
+
- Something that couldn't be guessed, sorry
- Algo que no pudo ser adivinado, lo siento
-
+
Warning:
Advertencia:
-
-
+
+
- Your radio probably uses a wrong firmware,
eeprom size is 4096 but only the first 2048 are used
Tu radio probablemente usa un firmware erróneo,
el tamaño de la eeprom es de 4096 pero sólo los primeros 2048 son usados
-
+
- Your eeprom is from an old version of OpenTX, upgrading!
To keep your original file as a backup, please choose File -> Save As specifying a different name.
Tu eeprom es de una vesión anterior de OpenTX, actualizando!
@@ -2864,27 +2950,27 @@ Si está en blanco entonces las entradas son consideradas ON todo el tiempo.TODO
-
+
Edit %1
Editar %1
-
+
Popup menu available
Disponible menú desplegable
-
+
Clear All
Limpiar todo
-
+
Set All
Fijar todo
-
+
Invert All
Invertir todo
@@ -3253,277 +3339,275 @@ Vacío significa incluir todos. Comodines ?, *, y [...] aceptados.
Firmware
-
+
Channel values displayed in us
Visualiza los valores de canal en us
-
+
No OverrideCH functions available
Sin funciones OverrideCH
-
+
Possibility to enable FAI MODE (no telemetry) at field
Posibilidad de habilitar el MODO FAI (sin telemetría)
-
+
FAI MODE (no telemetry) always enabled
MODO FAI (sin telemetría) siempre activado
-
+
Removes D8 FrSky protocol support which is not legal for use in the EU on radios sold after Jan 1st, 2015
Elimina el soporte para el protocolo D8 FrSky el cual no es de uso legal en EU en radios vendidas después del 1 de enero de 2015
-
-
+
+
+
Disable HELI menu and cyclic mix support
Desactiva el menú de HELI y el soporte de mezcla de cíclico
-
-
+
+
+
Disable Global variables
Desactiva las variables globales
-
-
+
+
+
Enable Lua custom scripts screen
Habilita la pantalla de Lua custom scripts
-
+
Use alternative SQT5 font
Usa la fuente alternativa SQT5
-
+
Pots use in menus navigation
Usa potenciómetros en los menús de navegación
-
+
FrSky Taranis X9D+
-
- Support for PPM internal module hack
- Soporte para el hack de PPM del módulo interno
-
-
-
+
Enable non certified firmwares
Habilita firmware no certificado
-
-
+
+ Enable AFHDS3 support
+ Habilitar soporte AFHDS3
+
+
+
+
Disable RAS (SWR)
Desactiva RAS (SWR)
-
+
FrSky Taranis X9D+ 2019
-
+
FrSky Taranis X9D
-
+
Haptic module installed
Módulo haptic instalado
-
+
FrSky Taranis X9E
-
+
Confirmation before radio shutdown
Confirmar antes de apagar la radio
-
+
Horus gimbals installed (Hall sensors)
Gimbals Horus instalados (sensores Hall)
-
+
FrSky Taranis X9-Lite
-
+
FrSky Taranis X7 / X7S
-
+
FrSky Taranis X-Lite S/PRO
-
+
FrSky Taranis X-Lite
-
+
FrSky Horus X10 / X10S
-
+
+
+
+
+
+ Support hardware mod: R9M ACCESS
+ Soporte mod hardware: R9M ACCESS
+
+
+
FrSky Horus X10 Express / X10S Express
-
+
FrSky Horus X12S
-
+
Use ONLY with first DEV pcb version
Usar SÓLO con la primera versión DEV pcb
-
+
Jumper T12 / T12 Pro
-
-
+
+
Support for MULTI internal module
Soporte para módulo interno MULTI
-
+
Jumper T16 / T16+ / T16 Pro
-
-
+
+
+
Support for bluetooth module
Soporte para módulo bluetooth
-
- Radiomaster TX16s / TX16s Hall / TX16s Masterfire
+
+ Radiomaster TX12
-
+
+ Radiomaster TX16S / SE / Hall / Masterfire
+
+
+
+
+ Support internal GPS
+ Soporte GPS interno
+
+
+
+ Jumper T18
+
+
+
+
Turnigy 9XR-PRO
-
+
Enable HELI menu and cyclic mix support
Activar menú HELI y el soporte de mezcla de cíclico
-
+
Global variables
Variables globales
-
+
In model setup menus automatically set source by moving the control
En el menú de ajuste de modelo se selecciona automáticamente el origen del control moviéndolo
-
+
In model setup menus automatically set switch by moving the control
En el menú de ajuste de modelo se selecciona automáticamente el interruptor de control moviéndolo
-
+
No graphical check boxes and sliders
Sin casillas de verificación ni sliders gráficos
-
+
Battery graph
Gráfico batería
-
+
Don't use bold font for highlighting active items
No usar la fuente negrita para destacar elementos activos
-
+
FrSky Taranis X9-Lite S
-
+
FrSky Taranis X7 / X7S Access
FrSky Taranis X7 / X7S Access
-
-
+
+
Support for ACCESS internal module replacement
Soporte para módulo interno ACCESS de reemplazo
-
- Turnigy 9XR with m128 chip
- Turnigy 9XR con chip m128
-
-
-
- Turnigy 9XR
-
-
-
-
- 9X with stock board
- 9X con placa de stock
-
-
-
+
Enable resetting values by pressing up and down at the same time
Activar el reseteo de valores presionando arriva y abajo al mismo tiempo
-
- 9X with stock board and m128 chip
- 9X con placa de stock y chip m128
-
-
-
+
9X with AR9X board
9X con placa AR9X
-
+
9X with Sky9x board
9X con placa Sky9x
-
-
- 9X with Gruvin9x board
- 9X con placa Gruvin9x
-
-
-
- DIY MEGA2560 radio
-
-
FirmwarePreferencesDialog
@@ -3848,62 +3932,62 @@ Vacío significa incluir todos. Comodines ?, *, y [...] aceptados.
Escribir al TX
-
+
Open Firmware File
Abrir archivo de firmware
-
+
%1 may not be a valid firmware file
%1 puede no ser un archivo de firmware válido
-
+
The firmware file is not valid.
El archivo de firmware no es válido.
-
+
There is no start screen image in the firmware file.
No hay imagen de pantalla de inicio en el archivo de firmware.
-
+
Profile image %1 is invalid.
El perfil de imagen %1 no es válido.
-
+
Open image file to use as radio start screen
Abrir archivo de imagen para usar de pantalla de inicio de la radio
-
+
Images (%1)
Imágenes (%1)
-
+
Image could not be loaded from %1
La imagen no puede ser cargada desde %1
-
+
The library image could not be loaded
La librería de imágen no puede ser cargada
-
+
Splash image not found
Imagen de inicio no encontrada
-
+
Cannot save customized firmware
No se puede guardar el firmware personalizado
-
+
Write Firmware to Radio
Escribir firmware a la radio
@@ -3924,27 +4008,27 @@ Vacío significa incluir todos. Comodines ?, *, y [...] aceptados.
¡El nuevo firmware no es compatible con el instalado actualmente!
-
+
Conversion failed
Coversión fallida
-
+
Cannot convert Models and Settings for use with this firmware, original data will be used
No se puede convertir los modelos y ajustes para usar con este firmware, se usarán los datos originales
-
+
Restore failed
Restauración fallida
-
+
Could not restore Models and Settings to Radio. The models and settings data file can be found at: %1
No se ha podido restaurar los modelos y ajustes a la radio. Los datos de los modelos y ajustes se pueden encontrar en: %1
-
+
Flashing done
Flashing hecho
@@ -3957,42 +4041,42 @@ Vacío significa incluir todos. Comodines ?, *, y [...] aceptados.
Ejecutable %1 no encontrado
-
+
Writing...
Escribiendo...
-
+
Reading...
Leyendo...
-
+
Verifying...
Verificando...
-
+
unknown
desconocido
-
+
ie: OpenTX for 9X board or OpenTX for 9XR board
Esto es: OpenTX para placas 9x o OpenTX para placas 9XR
-
+
ie: OpenTX for M128 / 9X board or OpenTX for 9XR board with M128 chip
Esto es: OpenTX para placas M128 / 9x o OpenTX para placas 9XR con el chip M128
-
+
ie: OpenTX for Gruvin9X board
Esto es: OpenTX para placas Gruvin9x
-
+
Your radio uses a %1 CPU!!!
Please check advanced burn options to set the correct cpu type.
@@ -4001,7 +4085,7 @@ Please check advanced burn options to set the correct cpu type.
Por favor comprueba en las opciones avanzadas de grabado el tipo correcto de cpu.
-
+
Your radio uses a %1 CPU!!!
Please select an appropriate firmware type to program it.
@@ -4010,7 +4094,7 @@ Please select an appropriate firmware type to program it.
Por favor elige el tipo de firmware apropiado para programarlo.
-
+
You are currently using:
%1
@@ -4019,22 +4103,22 @@ Actualmente estás usando:
%1
-
+
Your radio does not seem connected to USB or the driver is not initialized!!!.
¡¡¡La radio no parece estar conectada al USB o el controlador no está inicializado!!!
-
+
Flashing done (exit code = %1)
Flashing hecho (código salida = %1)
-
+
Flashing done with errors
Flashing hecho con errores
-
+
FUSES: Low=%1 High=%2 Ext=%3
FUSIBLES: Low=%1 High=%2 Ext=%3
@@ -4087,7 +4171,7 @@ Actualmente estás usando:
FlightModeData
-
+
FM
@@ -4095,37 +4179,38 @@ Actualmente estás usando:
FlightModePanel
-
+
Rotary Encoder %1
Codificador rotativo %1
-
+
Name
Nombre
-
+
Value source
Valor fuente
-
+
Value
Valor
-
+
GVAR%1
-
+
Popup enabled
Menú desplegable activado
-
+
+
Popup menu available
Menú desplegable disponible
@@ -4150,67 +4235,174 @@ Actualmente estás usando:
Usar trim para modo de vuelo %1 + trim propio con compensador
-
+
Unit
Unidad
-
+
Prec
-
+
Min
Mín
-
+
Max
Máx
-
+
0._
-
+
0.0
-
-
- &Clear
- &Limpiar
+
+ Warning: Global variable links back to itself. Flight Mode 0 value used.
+ Atención: Variable global linkada a si misma. Usado valor del modo de vuelo 0
-
-
+
+ Warning: Rotary encoder links back to itself. Flight Mode 0 value used.
+ Atención: Rotary encoder linkado a si mismo. Usado valor del modo de vuelo 0
+
+
+
+
+ Copy
+ Copiar
+
+
+
+
+ Cut
+ Cortar
+
+
+
+
+ Paste
+ Pegar
+
+
+
+
+ Insert
+ Insertar
+
+
+
+
+ Delete
+ Borrar
+
+
+
+
+ Move Up
+ Mover arriba
+
+
+
+
+ Move Down
+ Mover abajo
+
+
+
+
+ Clear All
+ Limpiar todo
+
+
+
+ Clear Flight Mode. Are you sure?
+ Limpiar modo de vuelo ¿Estás seguro?
+
+
+
+ Clear all Flight Modes. Are you sure?
+ Limpiar todos los modos de vuelo ¿Estás seguro?
+
+
+
+ Cut Flight Mode. Are you sure?
+ Cortar modo de vuelo ¿Estás seguro?
+
+
+
+ Delete Flight Mode. Are you sure?
+ Borrar modo de vuelo ¿Estás seguro?
+
+
+
+ Clear Global Variable across all Flight Modes. Are you sure?
+ Limpiar variable global para todos los modos de vuelo ¿Estás seguro?
+
+
+
+ Clear Global Variable. Are you sure?
+ Limpiar variable global ¿Estás seguro?
+
+
+
+ Clear all Global Variables for all Flight Modes. Are you sure?
+ Limpiar todas las variables globales para todos los modos de vuelo ¿Estás seguro?
+
+
+
+ Clear all Global Variables for this Flight Mode. Are you sure?
+ Limpiar todas las variables globales para este modo de vuelo ¿Estás seguro?
+
+
+
+ Cut Global Variable across all Flight Modes. Are you sure?
+ Cortar variable global para todos los modos de vuelo ¿Estás seguro?
+
+
+
+ Cut Global Variable. Are you sure?
+ Cortar variable global ¿Estás seguro?
+
+
+
+ Delete Global Variable. Are you sure?
+ Borrar variable global ¿Estás seguro?
+
+
+
+ Paste to selected Global Variable across all Flight Modes. Are you sure?
+ Pegar a la variable global en todos los modos de vuelo ¿Estás seguro?
+
+
+
+
Clear
Limpiar
-
-
- Clear all current Flight Mode properties?
- ¿Limpiar todas las propiedades del modo de vuelo actual?
-
FlightModesPanel
-
+
Flight Mode %1
Modo de vuelo %1
-
+
(%1)
-
+
(default)
(predeterminado)
@@ -4269,15 +4461,11 @@ Actualmente estás usando:
FusesDialog
-
-
Fuses
Fusibles
-
-
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
p, li { white-space: pre-wrap; }
@@ -4307,15 +4495,11 @@ p, li { white-space: pre-wrap; }
-
-
Read Fuses
Leer fusibles
-
-
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
p, li { white-space: pre-wrap; }
@@ -4349,8 +4533,6 @@ p, li { white-space: pre-wrap; }
-
-
Reset Fuses
EEPROM - PROTECT
Resetear fusibles
@@ -4358,8 +4540,6 @@ EEPROM - PROTEGIDA
-
-
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
p, li { white-space: pre-wrap; }
@@ -4393,8 +4573,6 @@ p, li { white-space: pre-wrap; }
-
-
Reset Fuses
EEPROM - DELETE
Resetear fusibles
@@ -4402,8 +4580,6 @@ EEPROM - BORRAR
-
-
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
p, li { white-space: pre-wrap; }
@@ -4494,12 +4670,12 @@ These will be relevant for all models in the same EEPROM.
Estos puede ser relevantes para todos los modelos en el mismo EEPROM.
-
+
Setup
Configuración
-
+
Trainer
Entrenador
@@ -4518,42 +4694,42 @@ Estos puede ser relevantes para todos los modelos en el mismo EEPROM.Recuperar calib. y ajustes hw de un perfil
-
+
Global Functions
Funciones globales
-
+
Hardware
Hardware
-
+
Calibration
Calibración
-
+
Wrong data in profile, radio calibration was not retrieved
Datos incorrectos en el perfil, la cablibración de la radio no se ha recuperado
-
+
Wrong data in profile, Switch/pot config not retrieved
Datos erróneos en el perfil, configuración de interruptor/pot no se ha recuperado
-
+
Wrong data in profile, hw related parameters were not retrieved
Datos incorrectos en el perfil, los parámetros de hw no se han recuperado
-
+
Do you want to store calibration in %1 profile<br>overwriting existing calibration?
¿Quieres guardar la calibración en el perfil %1<br>¿Sobreescribir la calibración existente?
-
+
Calibration and HW parameters saved.
Calibración y parámetros de HW guardados.
@@ -4561,7 +4737,7 @@ Estos puede ser relevantes para todos los modelos en el mismo EEPROM.
GeneralSettings
-
+
Radio Settings
Ajustes de radio
@@ -4570,300 +4746,300 @@ Estos puede ser relevantes para todos los modelos en el mismo EEPROM.GeneralSetup
-
-
+
+
Form
Form
-
-
+
+
Readonly Unlock
Desactivar sólo lectura
-
-
+
+
SC
-
-
+
+
SE
-
-
+
+
SA
-
-
+
+
SF
-
-
+
+
SH
-
-
+
+
SD
-
-
+
+
SB
-
-
+
+
SG
-
-
-
+
+
+
Timeshift from UTC
Zona horaria UTC
-
-
-
+
+
+
Voice Language
Lenguaje de las voces
-
-
-
+
+
+
Country Code
Código país
-
-
-
+
+
+
Stick reverse
Invertir stick
-
-
-
+
+
+
FAI Mode
Modo FAI
-
-
-
+
+
+
Adjust RTC
Ajustar RTC
-
-
-
+
+
+
Vario pitch at max
Tono de vario al máx
-
-
-
-
-
-
+
+
+
+
+
+
Hz
-
-
-
+
+
+
Speaker Volume
Volumen altavoz
-
-
-
+
+
+
Backlight Switch
Interruptor de luz de fondo
-
-
-
+
+
+
Sound Mode
Modo sonido
-
-
-
+
+
+
Color 1
-
-
-
+
+
+
Color 2
-
-
-
+
+
+
Speaker Pitch (spkr only)
Tono altavoz(sólo alt)
-
-
-
+
+
+
If this value is not 0, any keypress will turn on the backlight and turn it off after the specified number of seconds.
Si este valor no es 0, cualquier pulsación encenderá la pantalla y se apagará despues de un número determinado de segundos.
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
sec
seg
-
-
-
+
+
+
Backlight color
Color de pantalla
-
-
-
+
+
+
Beeper
Beeper
-
-
-
+
+
+
Speaker
Altavoz
-
-
-
+
+
+
BeeperVoice
VozBeeper
-
-
-
+
+
+
SpeakerVoice
VozAltavoz
-
-
-
+
+
+
Beep volume
Volumen beep
-
-
-
+
+
+
Wav volume
Volumen wav
-
-
-
+
+
+
Vario volume
Volumen vario
-
-
-
+
+
+
Background volume
Volumen de fondo
-
-
-
-
-
-
+
+
+
+
+
+
ms
-
-
-
+
+
+
Backlight Auto OFF after
Auto apagado de pantalla después de
-
-
-
+
+
+
Backlight flash on alarm
Pantalla parpadea con alarma
-
-
-
+
+
+
Vario pitch at zero
Tono de vario en cero
-
-
-
+
+
+
Vario repeat at zero
Vario repite en cero
-
-
-
+
+
+
This is the switch selectrion for turning on the backlight (if installed).
@@ -4872,12 +5048,12 @@ Estos puede ser relevantes para todos los modelos en el mismo EEPROM.
-
-
-
-
-
-
+
+
+
+
+
+
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
p, li { white-space: pre-wrap; }
@@ -4892,58 +5068,58 @@ p, li { white-space: pre-wrap; }
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Los valores pueden ser 20-45</span></p></body></html>
-
-
-
+
+
+
Backlight Brightness
Brillo pantalla
-
-
-
+
+
+
RotEnc Navigation
Navegación RotEnc
-
-
-
+
+
+
Automatically adjust the radio's clock if a GPS is connected to telemetry.
Ajusta automáticamente el reloj de la radio si se conecta un GPS a la telemetría.
-
-
-
+
+
+
America
América
-
-
-
+
+
+
Japan
Japón
-
-
-
+
+
+
Europe
Europa
-
-
-
+
+
+
Backlight OFF Brightness
Brillo luz de fondo OFF
-
-
-
+
+
+
Mode selection:
Mode 1:
@@ -4984,486 +5160,493 @@ Modo 4:
-
-
-
+
+
+
Mode 1 (RUD ELE THR AIL)
Modo 1 (RUD ELE THR AIL)
-
-
-
+
+
+
Mode 2 (RUD THR ELE AIL)
Modo 2 (RUD THR ELE AIL)
-
-
-
+
+
+
Mode 3 (AIL ELE THR RUD)
Modo 3 (AIL ELE THR RUD)
-
-
-
+
+
+
Mode 4 (AIL THR ELE RUD)
Modo 4 (AIL THR ELE RUD)
-
-
-
+
+
+
<html><head/><body><p>Channel order</p><p><br/></p><p>Defines the order of the default mixes created on a new model.</p></body></html>
<html><head/><body><p>Orden de los canales</p><p><br/></p><p>Define el orden por defecto de las mezclas en un nuevo modelo</p></body></html>
-
-
-
+
+
+
If you enable FAI, only RSSI and RxBt sensors will keep working. This function cannot be disabled by the radio.
Si activas FAI, sólo los sensores RSSI y RxBt seguirán funcionando. Esta función no puede ser deshabilitada en la radio.
-
-
-
+
+
+
RSSI Poweroff Warning
Aviso RSSI al apagado
-
-
-
+
+
+
Low EEPROM Warning
Advertencia de poca EEPROM
-
-
-
+
+
+
Owner Registration ID
ID de propietario
-
-
-
+
+
+
+ Keys Backlight
+ Teclas luz de fondo
+
+
+
+
+
R E T A
-
-
-
+
+
+
R E A T
-
-
-
+
+
+
R T E A
-
-
-
+
+
+
R T A E
-
-
-
+
+
+
R A E T
-
-
-
+
+
+
R A T E
-
-
-
+
+
+
E R T A
-
-
-
+
+
+
E R A T
-
-
-
+
+
+
E T R A
-
-
-
+
+
+
E T A R
-
-
-
+
+
+
E A R T
-
-
-
+
+
+
E A T R
-
-
-
+
+
+
T R E A
-
-
-
+
+
+
T R A E
-
-
-
+
+
+
T E R A
-
-
-
+
+
+
T E A R
-
-
-
+
+
+
T A R E
-
-
-
+
+
+
T A E R
-
-
-
+
+
+
A R E T
-
-
-
+
+
+
A R T E
-
-
-
+
+
+
A E R T
-
-
-
+
+
+
A E T R
-
-
-
+
+
+
A T R E
-
-
-
+
+
+
A T E R
-
-
-
+
+
+
Power On Delay
Retraso de encendido
-
-
-
+
+
+
Jack Mode
Modo jack
-
-
-
+
+
+
Audio
-
-
-
+
+
+
Trainer
Entrenador
-
-
-
+
+
+
DMS
-
-
-
+
+
+
USB Mode
Modo USB
-
-
-
+
+
+
Power Off Delay
Retraso de apagado
-
-
-
-
-
-
+
+
+
+
+
+
Ask on Connect
Preguntar al conectar
-
-
-
+
+
+
Joystick (HID)
Joystick (HID)
-
-
-
+
+
+
USB Mass Storage
Almacenamiento USB
-
-
-
+
+
+
USB Serial (CDC)
USB Serial (CDC)
-
-
-
+
+
+
Stick Mode
Modo sticks
-
-
-
+
+
+
Metric
Métrico
-
-
-
+
+
+
Imperial
Imperial
-
-
-
+
+
+
Default Channel Order
Orden prederterminado canales
-
-
-
+
+
+
GPS Coordinates
Coordenadas GPS
-
-
-
+
+
+
Min
Mín
-
-
-
-
-
-
+
+
+
+
+
+
v
-
-
-
+
+
+
Max
Máx
-
-
-
+
+
+
Inactivity Timer
Tiempo de inactividad
-
-
-
+
+
+
Show Splash Screen on Startup
Mostrar pantalla de inicio al encender
-
-
-
+
+
+
Contrast
Contraste
-
-
-
+
+
+
Battery Meter Range
Medidor de rango de batería
-
-
-
+
+
+
Haptic Strength
Fuerza de haptic
-
-
-
+
+
+
LCD Display Type
Tipo de pantalla LCD
-
-
-
+
+
+
"No Sound" Warning
Aviso "sin sonido"
-
-
-
+
+
+
Battery Warning
Aviso de batería
-
-
-
+
+
+
Haptic Length
Duración haptic
-
-
-
+
+
+
MAVLink Baud Rate
Velocidad de transmisión MAVLink
-
-
-
-
-
-
+
+
+
+
+
+
Quiet
Silencio
-
-
-
+
+
+
Only Alarms
Sólo alarmas
-
-
-
-
-
-
+
+
+
+
+
+
No Keys
No teclas
-
-
-
-
-
-
+
+
+
+
+
+
All
Todo
-
-
-
+
+
+
Battery warning voltage.
This is the threashhold where the battery warning sounds.
@@ -5474,172 +5657,172 @@ Este es el umbral cuando la batería emite sonidos de aviso.
Los valores aceptables son 5v..10v
-
-
-
+
+
+
Standard
Estándar
-
-
-
+
+
+
Optrex
-
-
-
+
+
+
If not zero will sound beeps if the transmitter has been left without inputs for the specified number of minutes.
Si no es cero emitirá sonidos si el transmisor se deja sin pulsaciones durante el número específico de minutos.
-
-
-
+
+
+
nnnnnnNN
-
-
-
+
+
+
min
-
-
-
-
-
-
+
+
+
+
+
+
Show splash screen on startup
Mostrar pantalla de inicio al encender
-
-
-
+
+
+
---
-
-
-
+
+
+
2s
-
-
-
+
+
+
3s
-
-
-
+
+
+
4s
-
-
-
+
+
+
6s
-
-
-
+
+
+
8s
-
-
-
+
+
+
10s
-
-
-
+
+
+
15s
-
-
-
+
+
+
4800 Baud
-
-
-
+
+
+
9600 Baud
-
-
-
+
+
+
14400 Baud
-
-
-
+
+
+
19200 Baud
-
-
-
+
+
+
38400 Baud
-
-
-
+
+
+
57600 Baud
-
-
-
+
+
+
76800 Baud
-
-
-
+
+
+
115200 Baud
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
p, li { white-space: pre-wrap; }
@@ -5664,101 +5847,101 @@ p, li { white-space: pre-wrap; }
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Aviso de silencio - te alertará si el beeper está en modo silencio (0)</p></body></html>
-
-
-
-
-
-
+
+
+
+
+
+
X-Short
X-Corto
-
-
-
-
-
-
+
+
+
+
+
+
Short
Corto
-
-
-
-
-
-
+
+
+
+
+
+
Normal
-
-
-
-
-
-
+
+
+
+
+
+
Long
Largo
-
-
-
-
-
-
+
+
+
+
+
+
X-Long
X-Largo
-
-
-
+
+
+
NMEA
-
-
-
+
+
+
Play Delay (switch mid position)
Retardo de reproducción (interruptor en posición media)
-
-
-
+
+
+
Measurement Units
Unidades de medida
-
-
-
+
+
+
Haptic Mode
Modo haptic
-
-
-
+
+
+
Beeper Length
Duración del beeper
-
-
-
+
+
+
Beeper Mode
Modo beeper
-
-
-
+
+
+
Beeper volume
0 - Quiet. No beeps at all.
@@ -5769,15 +5952,15 @@ p, li { white-space: pre-wrap; }
Volumen beeper
0 - Silencio. Ningun tipo de beep.
-1 - No teclas. Los beeps suenan normal pero las teclas de menu no sonarán.
+1 - No teclas. Los beeps suenan normal pero las teclas de menú no sonarán.
2 - Normal.
3 - Alto.
4 - Extra Alto.
-
-
-
+
+
+
Alarms Only
Sólo alarmas
@@ -5785,127 +5968,127 @@ p, li { white-space: pre-wrap; }
GeneralSetupPanel
-
+
OFF
-
+
Keys
Teclas
-
+
Sticks
Sticks
-
+
Keys + Sticks
Teclas + Sticks
-
+
ON
-
+
English
Inglés
-
+
Dutch
Holandés
-
+
French
Francés
-
+
Italian
Italiano
-
+
German
Alemán
-
+
Czech
Checo
-
+
Slovak
Eslovaco
-
+
Spanish
Español
-
+
Polish
Polaco
-
+
Portuguese
Portugués
-
+
Russian
Ruso
-
+
Swedish
Sueco
-
+
Hungarian
Húngaro
-
+
No
-
+
RotEnc A
-
+
Rot Enc B
-
+
Rot Enc C
-
+
Rot Enc D
-
+
Rot Enc E
-
+
If you enable FAI, only RSSI and RxBt sensors will keep working.
This function cannot be disabled by the radio.
Are you sure ?
@@ -5936,357 +6119,363 @@ Esta función no puede ser deshabilitada en la radio.
Hardware
-
+
Form
Form
-
-
+
+
SQ
-
-
+
+
SR
-
-
+
+
LS2
-
-
+
+
SP
-
-
+
+
SO
-
-
+
+
S4
-
-
+
+
RS
-
-
+
+
SB
-
-
+
+
PPM 2
-
-
+
+
OFF
-
-
+
+
S-Port Mirror
- S-Port
+
-
-
+
+
Telemetry
Telemetría
-
-
+
+
SBUS Trainer
Entrenador SBUS
-
-
+
+
Debug
Depuración
-
-
+
+
RTC Batt Check
Check Batería RTC
-
-
+
+
+ S.Port Power
+
+
+
+
+
Rud
-
-
+
+
PPM 3
-
-
+
+
S1
-
-
+
+
S2
-
-
+
+
S3
-
-
+
+
PPM 1
-
-
+
+
Serial Port
Puerto Serie
-
-
+
+
v
-
-
+
+
PPM Multiplier
Multiplicador PPM
-
-
+
+
Current Offset
Offset actual
-
-
+
+
PPM 4
-
-
+
+
SA
-
-
+
+
Ele
-
-
+
+
Antenna
Antena
-
-
+
+
S5
-
-
+
+
Ail
-
-
+
+
Thr
-
-
+
+
SC
-
-
+
+
LS
-
-
+
+
SD
-
-
+
+
Battery Offset
Offset batería
-
-
+
+
SE
-
-
+
+
SF
-
-
+
+
SG
-
-
+
+
SH
-
-
+
+
SI
-
-
+
+
SJ
-
-
+
+
SK
-
-
+
+
SL
-
-
+
+
SM
-
-
+
+
SN
-
-
+
+
RS2
-
-
+
+
Bluetooth
Bluetooth
-
-
+
+
ADC Filter
Filtro ADC
-
-
+
+
Device Name:
Nombre dispositivo:
@@ -6296,8 +6485,8 @@ Esta función no puede ser deshabilitada en la radio.
HardwarePanel
-
-
+
+
None
Ninguno
@@ -6317,67 +6506,67 @@ Esta función no puede ser deshabilitada en la radio.
3 posiciones
-
+
Pot with detent
Pos con fijador
-
+
Multipos switch
Interruptor multipos
-
+
Pot without detent
Pot sin fijador
-
+
Slider with detent
Slider con fijador
-
+
OFF
-
+
Enabled
Activado
-
+
Telemetry
Telemetría
-
+
Trainer
Entrenador
-
+
Internal
Interno
-
+
Ask
Preguntar
-
+
Per model
Por modelo
-
+
Internal + External
Interno + Externo
-
+
External
Externo
@@ -6531,139 +6720,177 @@ Esta función no puede ser deshabilitada en la radio.
InputsPanel
-
-
+
+
+
Move Up
Mover arriba
-
-
+
+
Ctrl+Up
Ctrl+Arriba
-
-
+
+
+
Move Down
Mover abajo
-
-
+
+
Ctrl+Down
Ctrl+Abajo
-
+
Clear All Inputs
Limpiar todas las entradas
-
- Not enough available inputs!
- ¡No hay disponibles suficientes entradas!
+
+ Not enough available Inputs!
+ ¡No hay suficientes entradas!
-
- Delete Selected Inputs?
- ¿Borrar las entradas seleccionadas?
+
+ Delete selected Input lines. Are you sure?
+ Borrar las líneas de entrada seleccionadas ¿Estás seguro?
-
+
+ Cut selected Input lines. Are you sure?
+ Cortar las líneas de entrada seleccionadas ¿Estás seguro?
+
+
+
+ Lines
+ Líneas
+
+
+
&Add
&Añadir
-
+
Ctrl+A
-
+
&Edit
&Editar
-
+
Enter
Intro
-
+
&Delete
&Borrar
-
+
+
Delete
Borrar
-
+
&Copy
&Copiar
-
+
Ctrl+C
-
+
&Cut
C&ortar
-
+
Ctrl+X
-
+
&Paste
&Pegar
-
+
Ctrl+V
-
+
Du&plicate
&Duplicar
-
+
Ctrl+U
-
- Clear Inputs?
- ¿Limpiar entradas?
+
+ Input
+ Entrada
-
- Really clear all the inputs?
- ¿Seguro que quieres limpiar todas las entradas?
+
+ Insert
+ Insertar
+
+
+
+ Clear
+ Limpiar
+
+
+
+ Clear All
+ Limpiar todo
+
+
+
+ Clear all Input lines. Are you sure?
+ Limpiar todas las líneas de entrada ¿Estás seguro?
+
+
+
+ Clear all lines for the selected Inputs. Are you sure?
+ Limpiar todas las líneas para las entradas seleccionadas¿Estás seguro?
+
+
+
+ Delete all lines for the selected Inputs. Are you sure?
+ Borrar todas las líneas para las entradas seleccionadas ¿Estás seguro?
LimitData
-
+
INV
-
+
NOR
-
+
CH
@@ -6671,7 +6898,7 @@ Esta función no puede ser deshabilitada en la radio.
LimitsGroup
-
+
GV
@@ -6802,69 +7029,114 @@ Esta función no puede ser deshabilitada en la radio.
LogicalSwitchesPanel
-
+
V1
-
+
V2
-
+
Duration
Duración
-
+
Delay
Retardo
-
+
Function
Función
-
+
AND Switch
Interruptor AND
-
+
Popup menu available
Menú emergente disponible
-
+
(instant)
(instante)
-
+
(infinite)
(infinito)
-
- &Delete
- &Borrar
+
+ Delete Logical Switch. Are you sure?
+ Borrar interruptor lógico ¿Estás seguro?
-
- &Copy
- &Copiar
+
+ Cut Logical Switch. Are you sure?
+ Cortar interruptor lógico ¿Estás seguro?
-
- &Cut
- C&ortar
+
+ Copy
+ Copiar
-
- &Paste
- &Pegar
+
+ Cut
+ Cortar
+
+
+
+ Paste
+ Pegar
+
+
+
+ Clear
+ Limpiar
+
+
+
+ Insert
+ Insertar
+
+
+
+ Delete
+ Borrar
+
+
+
+ Move Up
+ Mover arriba
+
+
+
+ Move Down
+ Mover abajo
+
+
+
+ Clear All
+ Limpiar todo
+
+
+
+ Clear Logical Switch. Are you sure?
+ Limpiar interruptor lógico ¿Estás seguro?
+
+
+
+ Clear all Logical Switches. Are you sure?
+ Limpiar todos los interruptores lógicos ¿Estás seguro?
@@ -7063,24 +7335,24 @@ Las columnas para altitud "GAlt" y para velocidad "GSpd" son
MainWindow
-
+
File loaded
Archivo cargado
-
-
+
+
Save As
Guardar como
-
-
+
+
No updates available at this time.
No hay actualizaciones disponibles ahora.
-
+
Checking for updates
Comprobando actualizaciones
@@ -7096,184 +7368,174 @@ Las columnas para altitud "GAlt" y para velocidad "GSpd" son
¿Quieres ejecutar el instalador?
-
-
+
+
File saved
Archivo guardado
-
+
Read Models and Settings From Radio
Leer los modelos y ajustes de la radio
-
+
Save Radio Backup to File
Guardar copia de seguridad de la radio a un archivo
-
+
Read Radio Firmware to File
Leer el firmware de la radio a un archivo
-
+
OpenTX Home Page: <a href='%1'>%1</a>
OpenTX Home Page: <a href='%1'>%1</a>
-
+
If you've found this program useful, please support by <a href='%1'>donating</a>
Si has encontrado este programa útl, por favor ayuda con una <a href='%1'>donación</a>
-
+
New release available
Nueva versión disponible
-
+
Error opening file %1:
%2.
Error abriendo el archivo %1:
%2.
-
+
Compilation server too busy, try later
Servidor de compilación demasiado ocupado, inténtalo más tarde
-
+
Unknown server failure, try later
Fallo desconocido de servidor, inténtalo más tarde
-
-
+
+
Yes
Sí
-
-
+
+
No
-
-
+
+
Release Notes
Notas de la versión
-
-
+
+
Open Models and Settings file
Abre archivo de modelos y ajustes
-
+
New
Nuevo
-
+
Open...
Abrir...
-
+
Save
Guardar
-
+
Save As...
Guardar como...
-
+
Compare models
Comparar modelos
-
+
Exit the application
Sale de la aplicación
-
- List available programmers
- Lista de programadores disponibles
-
-
-
- Show fuses dialog
- Muestra ventane de fusibles
-
-
-
+
Show the application's About box
Muestra la ventana de aplicación Acerca de
-
+
Set Menu Language
Lenguaje
-
+
Write
Escribir
-
+
%2
-
+
Alt+%1
-
+
New Radio
Nueva radio
-
+
A new version of Companion is available (version %1)<br>Would you like to download it?
Una nueva versión de Companion está disponible (versión %1),<br>¿Te gustaría descargarla?
-
+
Do you want to write the firmware to the radio now ?
¿Te gustaría escribir el firmware en la radio ahora?
-
+
The new theme will be loaded the next time you start Companion.
El nuevo tema será cargado la próxima vez que inicies Companion.
-
+
About Companion
Acerca de Companion
-
+
A monochrome black icon theme
Tema de icono monocromo negro
-
+
A monochrome white icon theme
Tema de icono monocromo blanco
-
+
A monochrome blue icon theme
Tema de icono monocromo azul
@@ -7288,12 +7550,12 @@ Las columnas para altitud "GAlt" y para velocidad "GSpd" son
¿Quieres abrir la imagen del disco para instalar la nueva versioń?
-
+
A new release of Companion is available, please check the <a href='%1'>OpenTX website!</a>
Una nueva versión de Companion está disponible, por favor visita <a href='%1'>OpenTX website!</a>
-
+
There are unsaved file changes which you may lose when switching radio types.
Do you wish to continue?
@@ -7302,387 +7564,387 @@ Do you wish to continue?
¿Quieres continuar?
-
+
No local SD structure path configured!
¡No configurada la ruta a la estructura SD local!
-
+
No Radio or SD card detected!
¡No radio o tarjeta SD detectada!
-
+
Close
Cerrar
-
+
Close Models and Settings file
Cierra el archivo de modelos y ajustes
-
+
List of recently used files
Lista de los archivos recientes
-
+
Radio Profiles
Perfiles de radio
-
+
Create or Select Radio Profiles
Crea o selecciona perfiles de radio
-
+
Release notes...
Notas de la versión...
-
+
Show release notes
Muestra notas de la versión
-
+
Create a new Radio Settings Profile
Crea un nuevo perfil de ajustes de radio
-
+
Copy Current Radio Profile
Copiar el perfil de radio actual
-
+
Duplicate current Radio Settings Profile
Duplica el perfil de radio actual
-
+
Delete Current Radio Profile...
Borrar el perfil de radio actual...
-
+
Delete the current Radio Settings Profile
Borra los ajustes actuales del perfil de radio actual
-
+
Export Application Settings..
Exportar ajustes aplicación...
-
+
Save all the current %1 and Simulator settings (including radio profiles) to a file.
Guarda los ajustes actuales de %1 y del simulador (incluyendo perfiles de radio) a un archivo
-
+
Import Application Settings..
Importar ajustes de la aplicación...
-
+
Load %1 and Simulator settings from a prevously exported settings file.
Carga los ajustes de %1 y del simulador desde un fichero de ajustes exportado previamente
-
+
Use tabs to arrange open windows.
Usa las pestañas para organizar las ventanas abiertas
-
+
Tabbed Windows
Ventanas con pestañas
-
+
Tile Windows
Ventanas en cascada
-
+
Arrange open windows across all the available space.
Organiza las ventanas en todo el espacio disponible
-
+
Cascade Windows
Ventanas en cascada
-
+
Arrange all open windows in a stack.
Organiza todas las ventanas abiertas en una cascada
-
+
Close All Windows
Cierra todas las ventanas
-
+
Closes all open files (prompts to save if necessary.
Cierra todos los archivos abiertos (pregunta guardar si es necesario)
-
+
Window
Ventana
-
+
Ctrl+Shift+S
-
+
Ctrl+Alt+L
-
+
Ctrl+Alt+D
-
+
Ctrl+Alt+R
-
+
Small
Pequeño
-
+
Use small toolbar icons
Usa iconos pequeños en la barra de herramientas
-
+
Use normal size toolbar icons
Usa iconos normales en la barra de herramientas
-
+
Normal
Normal
-
+
Use big toolbar icons
Usa iconos grandes en la barra de herramientas
-
+
Big
Grande
-
+
Use huge toolbar icons
Usa iconos extra grandes en la barra de herramientas
-
+
Huge
Extra Grande
-
+
- Copy
- Copiar
-
+
Companion :: Open files warning
Companion :: advertencia de archivos abiertos
-
+
Please save or close modified file(s) before deleting the active profile.
Por favor guarda o cierra los archivos modificados antes de borrar el perfil activo.
-
+
Not possible to remove profile
No se puede eliminar el perfil
-
+
The default profile can not be removed.
El perfil prederterminado no se puede eliminar.
-
+
Confirm Delete Profile
Confirma borrar perfil
-
+
Are you sure you wish to delete the "%1" radio profile? There is no way to undo this action!
¿Seguro que quieres borrar el perfil de radio "%1"? ¡Esta acción no se puede deshacer!
-
+
Please save or close all modified files before importing settings
Por favor guarda o cierra todos los archivos modificados antes de importar ajustes
-
+
<html><p>%1 and Simulator settings can be imported (restored) from a previosly saved export (backup) file. This will replace current settings with any settings found in the file.</p><p>An automatic backup of the current settings will be attempted. But if the current settings are useful then it is recommended that you make a manual backup first.</p><p>For best results when importing settings, <b>close any other %1 windows you may have open, and make sure the standalone Simulator application is not running.</p><p>Do you wish to continue?</p></html>
<html><p>Los ajustes de %1 y del simulador pueden ser importados (restaurar) desde archvo exportado previamente (copia de seguridad). Esto reemplazará los ajustes actuales con los ajustes del archivo.</p><p>Se realizará automáticamente una copia de seguridad de los ajustes actuales. Pero si los ajustes actuales son útiles se recomienda que hagas una copia de seguridad manual primero.</p><p>Para los mejores resultados al importar ajustes, <b>cierra otras ventanas de %1 que tengas abiertas, y asegúrate que la aplicación del simulador no se está ejecutando.</p><p>¿Quieres continuar?</p></html>
-
+
Confirm Settings Import
Confirma importar ajustes
-
+
Select %1:
Selecciona %1
-
+
backup
copia de seguridad
-
+
Press the 'Ignore' button to continue anyway.
Presiona el botón de 'Ignorar' para continuar de todos modos.
-
+
The settings could not be imported.
Los ajustes no han podido ser importados.
-
+
<html><p>New settings have been imported from:<br> %1.</p><p>%2 will now re-initialize.</p><p>Note that you may need to close and restart %2 before some settings like language and icon theme take effect.</p>
<html><p>Nuevos ajustes han sido importados desde:<br> %1.</p><p>%2 ahora se reiniciará.</p><p>Ten en cuenta que puedes necesitar cerrar y reiniciar %2 antes de que algunos ajustes como el lenguaje y el tema de iconos se hagan efectivos.</p>
-
+
<p>The previous settings were backed up to:<br> %1</p>
<p>Los ajustes anteriores fueron guardados en:<br> %1</p>
-
+
Not enough flash available on this board for all the selected options
No hay suficiente flash en esta placa para todas las opciones seleccionadas
-
+
Compilation server temporary failure, try later
Fallo temporal del servidor de compilación, intentalo más tarde
-
+
Compilation error
Error de compilación
-
+
Invalid firmware
Firmware no válido
-
+
Invalid board
Placa no válida
-
+
Invalid language
Lenguaje no válido
-
+
Some text will not be translated until the next time you start Companion. Please note that some translations may not be complete.
Algunos textos no serán traducidos hasta que reinicie Companion. Por favor ten en cuenta que algunas traducciones no están completas.
-
+
Models and Settings read
Lee modelos y ajustes
-
+
No Companion release candidates are currently being served for this version, please switch release channel
Actualmente no hay release candidates de Companion disponibles para esta versión, por favor cambia el canal de distribución
-
+
No nightly Companion builds are currently being served for this version, please switch release channel
Actualmente no hay nightly builds de Companion disponibles para esta versión, por favor cambia el canal de distribución
-
+
No Companion release builds are currently being served for this version, please switch release channel
Actualmente no hay distribuciones de Companion disponibles para esta versión, por favor cambia el canal de distribución
-
+
Companion update check failed, new version information not found.
El chequeo de la actualización de Companion ha fallado, la información de la nueva versión no se ha encontrado.
-
+
No firmware release candidates are currently being served for this version, please switch release channel
Actualmente no hay releases candidates de firmware disponibles para esta versión, por favor cambia el canal de distribución
-
+
No firmware nightly builds are currently being served for this version, please switch release channel
Actualmente no hay nightly builds de firmware disponibles para esta versión, por favor cambia el canal de distribución
-
+
No firmware release builds are currently being served for this version, please switch release channel
Actualmente no hay distribuciones de firmware disponibles para esta versión, por favor cambia el canal de distribución
-
+
Release candidate builds are now available for this version, would you like to switch to using them?
Ya hay disponibles release candidates para esta versión, ¿quieres cambiar para usarlas?
-
+
Channel changed to RC, please restart the download process
Canal cambiado a RC, por favor reinicia el proceso de descarga
-
+
Official release builds are now available for this version, would you like to switch to using them?
Ya hay disponibles distribuciones oficiales para esta versión, ¿quieres cambiar para usarlas?
-
+
Channel changed to Release, please restart the download process
Canal cambiado a Release, por favor reinicia el proceso de descarga
-
+
This radio (%1) is not currently available in this firmware release channel
Actualmente la radio (%1) no está disponible en este canal de distribución
-
+
Firmware update check failed, new version information not found or invalid.
El chequeo de la actualización del firmware ha fallado, la información de la versión no se ha encontrado o no es válida.
-
+
Firmware %1 does not seem to have ever been downloaded.
Version %2 is available.
Do you want to download it now?
@@ -7695,110 +7957,110 @@ La versión %2 está disponible.
Te recomendamos que revises las notas de la versión usando el botón de abajo para los ver cambios que puedan ser importantes para tí.
-
-
+
+
Do you want to download version %1 now ?
¿Quieres descargar ahora la versión %1?
-
+
Ignore this version %1?
¿Ignorar esta versión %1?
-
+
Local Folder
Carpeta local
-
+
Radio Folder
Carpeta de radio
-
-
+
+
This function is not yet implemented
Esta función aún no está implementada
-
+
The OpenTX Companion project was originally forked from <a href='%1'>eePe</a>
El proyecto OpenTX Companion se ha bifurcado originalmente desde <a href='%1'>eePe</a>
-
+
Copyright OpenTX Team
Derechos de autor del equipo OpenTX
-
+
Create a new Models and Settings file
Crea un nuevo archivo de modelos y ajustes
-
-
+
+
Save Models and Settings file
Guarda el archivo de modelos y ajustes
-
+
Exit
Salir
-
+
Use default system language.
Usa el lenguaje predeterminado del sistema.
-
+
Use %1 language (some translations may not be complete).
Usa lenguaje %1 (algunas traducciones pueden no estar completas)
-
+
Classical
Clásico
-
+
The classic companion9x icon theme
Tema de iconos clásicos de companion9x
-
+
Yerico
Yerico
-
+
Yellow round honey sweet icon theme
Tema de iconos amarillo miel redondo
-
+
Monochrome
Monocromo
-
+
MonoWhite
MonoBlanco
-
+
MonoBlue
MonoAzul
-
+
System language
Lenguaje del sistema
-
+
A new version of %1 firmware is available:
- current is %2
- newer is %3
@@ -7815,228 +8077,218 @@ We recommend you view the release notes using the button below to learn about an
Te recomendamos que revises las notas de la versión usando el botón de abajo para los ver cambios que puedan ser importantes para tí.
-
-
+
+
Synchronize SD
Sincronizar SD
-
+
OpenTX Companion %1 - Radio: %2 - Profile: %3
OpenTX Companion %1 - Radio: %2 - Perfil: %3
-
+
About...
Acerca de...
-
+
View Log File...
Ver archivo de registro...
-
+
Open and view log file
Abre el archivo de registro
-
+
Settings...
Ajustes...
-
+
Edit Settings
Edita ajustes
-
+
Download...
Descargar...
-
+
Download firmware and voice files
Descarga los archivos de firmware y voces
-
+
Check for Updates...
Comprobar actualizaciones...
-
+
Check OpenTX and Companion updates
Comprueba las actualizaciones de OpenTX y Companion
-
+
Compare Models...
Comparar modelos...
-
+
Edit Radio Splash Image...
Editar imagen de inicio de la radio...
-
+
Edit the splash image of your Radio
Editar la imagen de inicio de tu radio
-
- List programmers...
- Lista de programadores...
-
-
-
- Fuses...
- Fusibles...
-
-
-
-
+
+
Read Firmware from Radio
Leer firmware de la radio
-
+
Read firmware from Radio
Leer firmware de la radio
-
+
Write Firmware to Radio
Escribir firmware a la radio
-
+
Write firmware to Radio
Escribir firmware a la radio
-
+
Add Radio Profile
Añadir perfil de radio
-
+
Manuals and other Documents
Manuales y otros documentos
-
+
Open the OpenTX document page in a web browser
Abre la página de documentación de OpenTX en un navegador
-
+
Write Models and Settings To Radio
Escribir modelos y ajustes a la radio
-
+
Write Models and Settings to Radio
Escribir modelos y ajustes a la radio
-
-
+
+
Read Models and Settings from Radio
Leer los modelos y ajustes de la radio
-
+
Configure Communications...
Configurar comunicaciones...
-
+
Configure software for communicating with the Radio
Configura software para la comunicación con la radio
-
+
Write Backup to Radio
Escribir copia de seguridad a la radio
-
+
Write Backup from file to Radio
Escribir copia de seguridad desde un archivo a la radio
-
+
Backup Radio to File
Copia de seguridad de la radio a un archivo
-
+
Save a complete backup file of all settings and model data in the Radio
Guardar una copia de seguridad completa de todos los datos de ajustes y modelos en la radio
-
+
Contributors...
Contribuidores...
-
+
A tribute to those who have contributed to OpenTX and Companion
Un tributo a aquellos que han contribuido en OpenTX y Companion
-
+
SD card synchronization
Sincronización de la tarjeta SD
-
+
Recent Files
Archivos recientes
-
+
Set Icon Theme
Tema de iconos
-
+
Set Icon Size
Tamaño de iconos
-
-
+
+
File
Archivo
-
-
+
+
Edit
Editar
-
+
Settings
Ajustes
-
+
Read/Write
Leer/Escribir
-
-
+
+
Help
Ayuda
-
+
Ready
Listo
@@ -8423,12 +8675,12 @@ Do you want to save your changes?
MixData
-
+
MIX
-
+
(@%1)
@@ -8712,27 +8964,27 @@ Esto determina cómo los valores de mezcla son añadidos.
Abajo
-
+
DEST -> %1
-
+
Click to access popup menu
Pulsa para acceder el menú emergente
-
+
Clear All
Limpiar todo
-
+
Set All
Fijar todo
-
+
Invert All
Ivertir todo
@@ -8763,131 +9015,136 @@ Esto determina cómo los valores de mezcla son añadidos.
MixesPanel
-
-
+
+
Move Up
Mover arriba
-
-
+
+
Ctrl+Up
Ctrl+Arriba
-
-
+
+
Move Down
Mover abajo
-
-
+
+
Ctrl+Down
Ctrl+Abajo
-
+
Clear Mixes
Limpiar mezclas
-
+
Not enough available mixers!
¡No hay suficientes mezclas disponibles!
-
- Delete Selected Mixes?
- ¿Borrar las mezclas seleccionadas?
+
+ Delete selected Mix lines. Are you sure?
+ Borrar líneas de mixes seleccionadas ¿Estás seguro?
-
+
+ Cut selected Mix lines. Are you sure?
+ Cortar líneas de mixes seleccionadas ¿Estás seguro?
+
+
+
&Add
&Añadir
-
+
Ctrl+A
-
+
&Edit
&Editar
-
+
Enter
Intro
-
+
&Toggle highlight
&Seleccionar palanca
-
+
Ctrl+T
-
+
&Delete
&Borrar
-
+
Delete
Borrar
-
+
&Copy
&Copiar
-
+
Ctrl+C
-
+
Ctrl+X
-
+
C&ut
C&ortar
-
+
&Paste
&Pegar
-
+
Ctrl+V
-
+
Du&plicate
&Duplicar
-
+
Ctrl+U
-
+
Clear Mixes?
¿Limpiar mezclas?
-
+
Really clear all the mixes?
¿Seguro que quieres limpiar todas las mezclas?
@@ -8895,12 +9152,12 @@ Esto determina cómo los valores de mezcla son añadidos.
ModelData
-
+
Model:
Modelo:
-
+
Throttle Source
Fuente del acelerador
@@ -8915,52 +9172,52 @@ Esto determina cómo los valores de mezcla son añadidos.
Mensaje
-
+
Setup
Ajustes
-
+
Heli
Heli
-
+
Inputs
Entradas
-
+
Logical Switches
Interruptor lógicos
-
+
Mixes
Mezclas
-
+
Outputs
Salidas
-
+
Curves
Curvas
-
+
Special Functions
Funciones especiales
-
+
Telemetry
Telemetría
-
+
Flight Modes
Fases de vuelo
@@ -8975,784 +9232,784 @@ Esto determina cómo los valores de mezcla son añadidos.
ModelPrinter
-
+
Exponential
Exponencial
-
+
Extra Fine
Extra Fino
-
+
Fine
Fino
-
+
Medium
Medio
-
+
Coarse
Duro
-
+
Unknown
Desconocido
-
+
Slave/Jack
Slave/Jack
-
+
Master/SBUS Module
Módulo Master/SBUS
-
+
Master/CPPM Module
Módulo Master/CPPM
-
+
Master/SBUS in battery compartment
Master/SBUS en compartimento de la batería
-
+
Master/Jack
-
+
Enable
Activar
-
+
Disable
Desactivar
-
+
True
Verdadero
-
+
False
Falso
-
+
Yes
Sí
-
+
No
-
+
Y
-
+
N
-
+
ON
-
-
-
-
+
+
+
+
OFF
-
+
bytes
-
-
+
+
Mode
Modo
-
-
+
+
Channels
Canales
-
-
+
+
Frame length
Longitud frame
-
+
PPM delay
Retardo PPM
-
-
+
+
Polarity
Polaridad
-
+
Protocol
Protocolo
-
-
-
+
+
+
Delay
Retardo
-
-
+
+
Receiver
Receptor
-
+
Radio protocol
Protocolo radio
-
+
Subtype
Subtipo
-
+
Option value
Valor opción
-
+
Sub Type
Sub tipo
-
+
+
RF Output Power
Potencia de salida RF
-
+
+ Output Type
+ Tipo de salida
+
+
+
+ RX Output Frequency
+ Frecuencia de salida del RX
+
+
+
90
-
+
120
-
+
120X
-
+
140
-
+
MULT!
-
-
+
+
Offset
-
+
Slow
Lento
-
+
Warn
Aviso
-
+
Flight modes
Modos de vuelo
-
+
Flight mode
Modo de vuelo
-
+
All
Todo
-
+
Edge
Borde
-
+
Sticky
Pegajoso
-
+
Timer
Temporizador
-
+
missing
falta
-
+
Duration
Duración
-
+
Extended Limits
Límites extendidos
-
+
Display Checklist
Mostrar lista de verificación
-
+
Global Functions
Funciones globales
-
+
Manual
Manual
-
+
Auto
Auto
-
+
Failsafe Mode
Modo failsafe
-
-
+
+
Hold
Mantener
-
+
No Pulse
Sin pulsos
-
+
Not set
No fijado
-
+
No pulses
Sin pulsos
-
+
Silent
Silencio
-
+
Beeps
Beeps
-
+
Voice
Voz
-
+
Haptic
Haptic
-
+
Flight
Vuelo
-
+
Manual reset
Reset manual
-
+
Step
Paso
-
+
Display
Mostrar
-
+
Extended
Extendido
-
+
Never
Nunca
-
+
On Change
Al cambiar
-
+
Always
Siempre
-
-
-
+
+
+
Source
Fuente
-
+
Trim idle only
Trim sólo al ralentí
-
+
Warning
Aviso
-
+
Reversed
Invertido
-
+
Tmr
Temporiz.
-
+
FrSky S.PORT
-
+
FrSky D
-
+
FrSky D (cable)
-
+
Alti
-
+
Alti+
-
+
VSpeed
Veloc. vert.
-
-
-
-
- A1
-
-
- A2
+ A1
+
- A3
+ A2
- A4
+ A3
- FAS
+ A4
+
+ FAS
+
+
+
+
Cells
Celdas
-
+
Calculated
Calculado
-
+
Add
Sumar
-
+
Average
Media
-
-
+
+
Min
Mínimo
-
-
+
+
Max
Máximo
-
+
Multiply
Multiplicar
-
+
Totalise
Total
-
+
Cell
Celda
-
+
Consumption
Consumo
-
+
Distance
Distancia
-
+
Lowest
Menor
-
+
Cell %1
Celda %1
-
+
Highest
Mayor
-
+
Delta
-
- Formula
- Fórmula
+
+ Auto Offset
+
-
-
+
+ 0.
+
+
+
+
+ 0.0
+
+
+
+
+ 0.00
+
+
+
+
Id
-
- Instance
- Instancia
-
-
-
-
-
-
+
+
Sensor
-
-
+
Sources
Fuentes
-
-
+
GPS
GPS
-
- Alt.
-
-
-
-
-
+
Blades
Palas
-
- Multi.
-
-
-
-
+
F
-
+
Inst
-
+
Alt
-
+
Unit
Unidad
-
+
Prec
-
+
Ratio
-
+
Multi
-
- A/Offset
-
-
-
-
+
Filter
Filtro
-
+
Persist
Persist.
-
+
Positive
Positivo
-
+
Log
Reporte
-
+
Numbers
Números
-
+
Bars
Barras
-
+
Script
Script
-
+
Filename
Nombre archivo
-
+
Error: Unable to open or read file!
Error: ¡No se puede abrir o leer el archivo!
-
+
Persistent
Persistente
-
+
Off
-
-
-
-
-
-
+
+
+
+
+
+
None
Ninguno
-
+
Name
Nombre
-
+
Countdown
Cuenta atrás
-
+
Minute call
Cada minuto
-
-
-
+
+
+
FM%1
-
+
FM%1%2
-
+
FM%1+%2
-
-
+
+
Weight
Peso
-
-
+
+
Switch
Interruptor
-
-
+
+
NoTrim
-
+
No DR/Expo
-
+
Offset(%1)
-
+
Disabled in all flight modes
Desactivado en todos los modos de vuelo
-
+
instant
instante
-
-
-
+
+
+
Custom
Personalizado
-
+
Standard
Estándar
@@ -9788,353 +10045,367 @@ Esto determina cómo los valores de mezcla son añadidos.
Module
-
-
-
+
+
+
Failsafe Mode
Modo failsafe
-
-
+
+
Start
Comenzar
-
-
-
+
+
+
PPM delay
Retardo PPM
-
-
-
+
+
+
Negative
Negativo
-
-
-
+
+
+
Positive
Positivo
-
-
-
+
+
+
Polarity
Polaridad
-
-
-
+
+
+
Trainer Mode
Modo entrenador
-
-
-
+
+
+
PPM Frame Length
Longitud trama PPM
-
-
-
+
+
+
CH
-
-
-
+
+
+
Antenna
Antena
-
-
-
+
+
+
Option value
Valor opción
-
-
-
+
+
+
RF Output Power
Potencia de salida de RF
-
-
-
+
+
+
Low Power
Baja potencia
-
-
-
+
+
+
us
-
-
-
+
+
+
Multi Radio Protocol
Multi Radio protocol
-
-
-
+
+
+
Sub Type
Sub tipo
-
-
-
+
+
+
Master/Jack
Master/Jack
-
-
-
+
+
+
Slave/Jack
Slave/Jack
-
-
-
+
+
+
Master/SBUS Module
Módulo Master/SBUS
-
-
-
+
+
+
Master/CPPM Module
Módulo Master/CPPM
-
-
-
+
+
+
Master/SBUS in battery compartment
Master/SBUS en compartimento de la batería
-
-
-
+
+
+
Show values in:
Muestra valores en:
-
-
-
+
+
+
%
abbreviation for percent
-
-
-
+
+
+
μs
abbreviation for microseconds
-
-
-
+
+
+
ms
-
-
-
+
+
+
Receiver 1
Receptor 1
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
X
-
-
-
+
+
+
Receiver 2
Receptor 2
-
-
-
+
+
+
Receiver 3
Receptor 3
-
-
-
+
+
+
WARNING: changing RF Output Power needs RE-BIND
AVISO: cambiar potencia salida de RF requiere RE-BIND
-
-
-
+
+
+
Channels
Canales
-
-
-
+
+
+
+ RX Frequency
+ Frecuencia RX
+
+
+
+
+
+ Hz
+
+
+
+
+
+
Registration ID
Registro ID
-
-
-
+
+
+
WARNING: Requires non-certified firmware!
AVISO: ¡Requiere firmware no certificado!
-
-
-
+
+
+
Not set
No fijado
-
-
-
+
+
+
Hold
Mantener
-
-
-
+
+
+
Custom
Personalizado
-
-
-
+
+
+
No Pulses
Sin Pulsos
-
-
-
+
+
+
Receiver
Receptor
-
-
-
+
+
+
Master/Bluetooth
Master/Bluetooth
-
-
-
+
+
+
Slave/Bluetooth
Slave/Bluetooth
-
-
-
+
+
+
Master/Multi
Master/Multi
-
-
-
+
+
+
Disable Telemetry
Desactivar telemetría
-
-
-
+
+
+
Disable Ch. Map
Desactivar mapa canales
-
-
-
+
+
+
Failsafe Positions
Posiciones failsafe
-
-
-
+
+
+
Protocol
Protocolo
-
-
-
+
+
+
Receiver No.
Receptor Nº.
-
-
-
+
+
+
Output type
Tipo de salida
-
-
-
+
+
+
Open Drain
-
-
-
+
+
+
Push Pull
@@ -10142,133 +10413,153 @@ Esto determina cómo los valores de mezcla son añadidos.
ModuleData
-
+
Positive
Positivo
-
+
Negative
Negativo
-
+
Trainer Port
Puerto entrenador
-
+
Internal Radio System
Sistema de radio interno
-
+
External Radio Module
Módulo externo de radio
-
+
Extra Radio System
Sistema de radio extra
-
+
Radio System
Sistema de radio
-
+
10mW - 16CH
-
-
+
+
100mW - 16CH
-
+
500mW - 16CH
-
+
Auto <= 1W - 16CH
-
-
+
+
25mW - 8CH
-
-
+
+
25mW - 16CH
-
+
200mW - 16CH (no telemetry)
200mW - 16CH (sin telemetría)
-
+
500mW - 16CH (no telemetry)
500mW - 16CH (sin telemetría)
-
+
100mW - 16CH (no telemetry)
100mW - 16CH (sin telemetría)
+
+
+ 25 mW
+
+
+
+
+ 100 mW
+
+
+
+
+ 500 mW
+
+
+
+
+ 1 W
+
+
+
+
+ 2 W
+
+
ModulePanel
-
+
Value
Valor
-
+
Hold
Mantener
-
+
No Pulse
Sin pulsos
-
+
Ask
Preguntar
-
+
Internal
Interno
-
+
Internal + External
Interno + Externo
-
+
External
Externo
-
- Autodetect Format
- Autodetectar formato
-
-
-
+
Bind on channel
Bind con canal
@@ -10276,44 +10567,44 @@ Esto determina cómo los valores de mezcla son añadidos.
MultiModelPrinter
-
+
Input
Entrada
-
+
Weight
Peso
-
+
Long. cyc
Cíc. long.
-
+
Lateral cyc
Cíc. lateral
-
+
Collective
Colectivo
-
+
Flight modes
Modos de vuelo
-
-
+
+
Flight mode
Modo de vuelo
-
-
+
+
Switch
Interruptores
@@ -10323,401 +10614,349 @@ Esto determina cómo los valores de mezcla son añadidos.
-
+
EEprom Size
Tamaño EEprom
-
+
Model Image
Imagen del modelo
-
+
Throttle
Acelerador
-
+
Trims
-
+
Center Beep
Beep en centro
-
+
Switch Warnings
Avisos interruptores
-
+
Pot Warnings
Avisos potenciómetros
-
+
Other
Otro
-
+
Timers
Temporizadores
-
+
Time
Hora
-
+
Countdown
Cuenta atrás
-
+
Modules
Módulos
-
+
Trainer port
Puerto entrenador
-
+
Helicopter
Helicóptero
-
+
Swash
-
-
+
+
Type
Tipo
-
+
Ring
-
+
Protocol
Protocolo
-
+
Low
Bajo
-
+
Critical
Crítico
-
+
Telemetry audio
Audio telemetría
-
+
Altimetry
Altímetro
-
-
+
+
Vario source
Fuente variómetro
-
+
Vario limits >
Límites variómetro
-
+
Sink max
Descenso máx
-
+
Sink min
Descenso mín
-
+
Climb min
Ascenso mín
-
+
Climb max
Ascenso máx
-
+
Center silent
Centro silencio
-
+
Top Bar
Barra superior
-
-
+
Volts source
Fuente de voltage
-
+
Altitude source
Fuente de altitud
-
- Various
- Varios
-
-
-
- Serial protocol
- Protocolo serie
-
-
-
- FAS offset
-
-
-
-
- mAh count
- Valor mAh
-
-
-
- Persistent mAh
- mAh persistente
-
-
-
- Current source
- Fuente actual
-
-
-
- Blades
- Palas
-
-
-
+
Parameters
Parámetros
-
+
Telemetry Sensors
Sensores de telemetría
-
+
Telemetry Screens
Pantallas de telemetría
-
+
GF%1
-
+
Global Functions
Funciones globales
-
+
Checklist
Lista de verificación
-
-
+
+
GV%1
-
+
RE%1
-
+
Channel
Canal
-
-
+
+
Name
Nombre
-
+
Prec
-
+
Popup
Emergente
-
+
Outputs
Salidas
-
+
Subtrim
-
+
Direct
Directo
-
+
Curve
Curva
-
+
PPM
-
+
Linear
Lineal
-
+
Telemetry
Telemetría
-
- Offset
-
-
-
-
-
+
+
Min
Mín
-
+
Min.call
Cada min
-
+
Persist
Persistente
-
+
F.In
Atn. entr.
-
+
F.Out
Atn.sal.
-
+
Global vars
Vars globales
-
-
+
+
Max
Máx
-
+
Global Variables
Variables globales
-
+
Inputs
Entradas
-
+
Mixers
Mezclas
-
+
Curves
Curvas
-
+
L%1
-
+
Logical Switches
Interruptores lógicos
-
+
SF%1
-
+
Special Functions
Funciones especiales
-
- Analogs
- Analógicos
-
-
-
-
+
Unit
Unidad
-
- Scale
- Escala
-
-
-
+
RSSI Alarms
Alarmas RSSI
@@ -10741,13 +10980,13 @@ Esto determina cómo los valores de mezcla son añadidos.
- Telemetry
- Telemetría
+ RF power
+
- Radio output power
- Potencia de salida radio
+ Telemetry
+ Telemetría
@@ -10796,22 +11035,22 @@ Esto determina cómo los valores de mezcla son añadidos.
OpenTxEepromInterface
-
+
Unknown error
Error desconocido
-
+
... plus %1 errors
... más %1 errores
-
+
Cannot write radio settings
No se pueden escribir los ajustes de la radio
-
+
Cannot write model %1
No se puede escribir el modelo %1
@@ -10924,6 +11163,23 @@ Esto determina cómo los valores de mezcla son añadidos.
Archivos ODF (*.odt);;Archivos PDF (*.pdf);;Archivos HTML(*.htm *.html);;Todos los Archivos (*)
+
+ ProfileChooserDialog
+
+
+
+
+ Select Profile
+ Seleccionar perfil
+
+
+
+
+
+ Profile
+ Perfil
+
+
ProgressDialog
@@ -11079,25 +11335,20 @@ Esto determina cómo los valores de mezcla son añadidos.
RadioInterface
-
+
Cannot write file %1:
%2.
No se puede escribir el archivo %1:
%2.
-
- <b><u>WARNING!</u></b><br>This will reset the fuses of %1 to the factory settings.<br>Writing fuses can mess up your radio.<br>Do this only if you are sure they are wrong!<br>Are you sure you want to continue?
- <b><u>¡AVISO!</u></b><br>Esto reseteará los fusibles de %1 a los ajustes de fábrica.<br>Escribir los fusibles puede estropear tu radio.<br>¡Haz esto sólo si estás seguro que están mal!<br>¿Estás seguro de continuar?
-
-
-
-
+
+
Could not delete temporary file: %1
No se puede borrar el archivo temporal: %1
-
+
Unable to find radio SD card!
¡No se puede encontrar la tarjeta SD de la radio!
@@ -11145,6 +11396,7 @@ Esto determina cómo los valores de mezcla son añadidos.
+
Form
@@ -11152,6 +11404,7 @@ Esto determina cómo los valores de mezcla son añadidos.
+
View:
Vista:
@@ -11159,6 +11412,7 @@ Esto determina cómo los valores de mezcla son añadidos.
+
Logical Switches
Interruptores lógicos
@@ -11166,6 +11420,7 @@ Esto determina cómo los valores de mezcla son añadidos.
+
Global Variables
Variables globales
@@ -11173,6 +11428,7 @@ Esto determina cómo los valores de mezcla son añadidos.
+
Channel Outputs
Salidas canales
@@ -11180,6 +11436,7 @@ Esto determina cómo los valores de mezcla son añadidos.
+
Mix Outputs
Salidas mixes
@@ -11187,6 +11444,7 @@ Esto determina cómo los valores de mezcla son añadidos.
+
L
o
g
@@ -11203,6 +11461,7 @@ o
+
G
l
o
@@ -11215,6 +11474,7 @@ l
+
C
h
a
@@ -11235,6 +11495,7 @@ s
+
M
i
x
@@ -11264,439 +11525,131 @@ s
RawSource
-
-
-
-
+
V
-
-
-
-
+
+
s
-
- ft
-
-
-
-
-
- m
-
-
-
-
- °C
-
-
-
-
- °
-
-
-
-
- %
-
-
-
-
-
- mph
-
-
-
-
-
- km/h
-
-
-
-
- m/s
-
-
-
-
- A
-
-
-
-
- mAh
-
-
-
-
- W
-
-
-
-
- g
-
-
-
-
+
TrmR
-
+
TrmE
-
+
TrmT
-
+
TrmA
-
+
Trm5
-
+
Trm6
-
+
TrmH
-
+
TrmV
-
-
+
Batt
Batería
-
-
+
Time
Hora
-
-
+
Timer1
Temporizador1
-
-
+
Timer2
Temporizador 2
-
-
+
Timer3
Temporizador 3
-
- RAS
-
-
-
-
- RSSI Tx
-
-
-
-
- RSSI Rx
-
-
-
-
- A1
-
-
-
-
- A2
-
-
-
-
- A3
-
-
-
-
- A4
-
-
-
-
- Alt
-
-
-
-
- Rpm
-
-
-
-
- Fuel
- Combustible
-
-
-
- T1
-
-
-
-
- T2
-
-
-
-
- Speed
- Velocidad
-
-
-
- Dist
- Distancia
-
-
-
- GPS Alt
-
-
-
-
- Cell
- Celda
-
-
-
- Cells
- Celdas
-
-
-
- Vfas
-
-
-
-
- Curr
-
-
-
-
- Cnsp
- Cons
-
-
-
- Powr
-
-
-
-
- AccX
-
-
-
-
- AccY
-
-
-
-
- AccZ
-
-
-
-
- Hdg
-
-
-
-
- VSpd
- VelocVert
-
-
-
- AirSpeed
- VelocAire
-
-
-
- dTE
-
-
-
-
- A1-
-
-
-
-
- A2-
-
-
-
-
- A3-
-
-
-
-
- A4-
-
-
-
-
- Alt-
-
-
-
-
- Alt+
-
-
-
-
- Rpm+
-
-
-
-
- T1+
-
-
-
-
- T2+
-
-
-
-
- Speed+
- Velocidad+
-
-
-
- Dist+
-
-
-
-
- AirSpeed+
- VelocAire+
-
-
-
- Cell-
- Celda-
-
-
-
- Cells-
- Celdas-
-
-
-
- Vfas-
-
-
-
-
- Curr+
-
-
-
-
- Powr+
-
-
-
-
- ACC
-
-
-
-
- GPS Time
- Hora GPS
-
-
-
+
REa
-
+
REb
-
-
+
+
???
-
+
----
-
+
I
as in Input
-
+
LUA%1%2
-
+
MAX
-
+
CYC%1
-
+
TR
as in Trainer
-
+
SRC
@@ -12065,7 +12018,22 @@ s
ml/minuto
-
+
+ Hertz
+
+
+
+
+ mS
+
+
+
+
+ uS
+
+
+
+
TELE
@@ -12073,226 +12041,233 @@ s
Setup
-
-
-
+
+
+
Center beep
Centro beep
-
-
-
+
+
+
OFF
-
-
-
+
+
+
Model Image
Imagen del modelo
-
-
-
+
+
+
Exponential
Exponencial
-
-
-
+
+
+
Throttle Trim Idle Only
Trim acel. ralentí
-
-
-
+
+
+
Extra Fine
Extra Fino
-
-
-
+
+
+
Fine
Fino
-
-
-
+
+
+
Medium
Medio
-
-
-
+
+
+
Coarse
Grueso
-
-
-
+
+
+
Display Checklist
Lista de verific.
-
-
-
+
+
+
Timer 2
Temporizador 2
-
-
+
+
Timer 1
Temporizador 1
-
-
-
+
+
+
Timer 3
Temporizador 3
-
-
-
+
+
+
Never
Nunca
-
-
-
+
+
+
Top LCD Timer
Temp. LCD superior
-
-
-
+
+
+
On change
Al cambiar
-
-
-
+
+
+
Always
Siempre
-
-
-
+
+
+
Global Functions
Funcs. globales
-
-
-
+
+
+
Edit Checklist...
Lista de verific...
-
-
-
+
+
+
Throttle Source
Fuente acelerador
-
-
-
+
+
+
Trim Step
Paso de trim
-
-
-
+
+
+
Trims Display
Mostrar trims
-
-
-
+
+
+
Warnings
Avisos
-
-
-
+
+
+
Switch Warnings
Avisos interruptores
-
-
-
+
+
+
Pot Warnings
Avisos Potenciómetros
-
-
-
+
+
+
Manual
Manual
-
-
-
+
+
+
Auto
-
-
-
+
+
+
Model
Modelo
-
-
-
+
+
+
+ Throttle trim switch
+
+
+
+
+
+
Extended Limits
Límites extendidos
-
-
-
+
+
+
Extended Trims
Trims extendidos
-
-
-
+
+
+
Throttle Warning
Aviso acelerador
-
-
-
+
+
+
Reverse throttle operation.
If this is checked the throttle will be reversed. Idle will be forward, trim will also be reversed and the throttle warning will be reversed as well.
@@ -12303,9 +12278,9 @@ Si está marcado el acelerador será invertido. El ralentí será delante, el t
-
-
-
+
+
+
Reverse Throttle
Invertir acelerador
@@ -12313,25 +12288,95 @@ Si está marcado el acelerador será invertido. El ralentí será delante, el t
SetupPanel
-
+
+ Popup menu available
+ Menú emergente disponible
+
+
+
Timer %1
Temporizador %1
-
+
THR
-
+
Profile Settings
Ajustes de perfil
-
+
SD structure path not specified or invalid
Ruta de la SD no especificada o no válida
+
+
+ Copy
+ Copiar
+
+
+
+ Cut
+ Cortar
+
+
+
+ Paste
+ Pegar
+
+
+
+ Clear
+ Limpiar
+
+
+
+ Insert
+ Insertar
+
+
+
+ Delete
+ Borrar
+
+
+
+ Move Up
+ Mover arriba
+
+
+
+ Move Down
+ Mover abajo
+
+
+
+ Clear All
+ Limpiar todo
+
+
+
+ Clear Timer. Are you sure?
+ Limpiar timer ¿Estás seguro?
+
+
+
+ Clear all Timers. Are you sure?
+ Limpiar todos los timers ¿Estás seguro?
+
+
+
+ Cut Timer. Are you sure?
+ Cortar timer ¿Estás seguro?
+
+
+
+ Delete Timer. Are you sure?
+ Borrar timer ¿Estás seguro?
+
SimpleTailPage
@@ -12680,6 +12725,7 @@ Perfil ID: [%1]; Radio ID: [%2]
+
OpenTx Simulator
Simulador de OpenTX
@@ -12687,6 +12733,7 @@ Perfil ID: [%1]; Radio ID: [%2]
+
View
Vista
@@ -12694,6 +12741,7 @@ Perfil ID: [%1]; Radio ID: [%2]
+
Radio Window
Ventana de radio
@@ -12701,6 +12749,7 @@ Perfil ID: [%1]; Radio ID: [%2]
+
Reload...
Recargar...
@@ -12708,6 +12757,7 @@ Perfil ID: [%1]; Radio ID: [%2]
+
Tools
Herramientas
@@ -12715,6 +12765,7 @@ Perfil ID: [%1]; Radio ID: [%2]
+
Toolbar
Barra de herramientas
@@ -12722,6 +12773,7 @@ Perfil ID: [%1]; Radio ID: [%2]
+
Reload Lua Scripts
Recarga scripts Lua
@@ -12729,6 +12781,7 @@ Perfil ID: [%1]; Radio ID: [%2]
+
Reload the Lua environment on the simulated radio.
Recarga el entorno Lua en la simulación de la radio.
@@ -12736,6 +12789,7 @@ Perfil ID: [%1]; Radio ID: [%2]
+
F7
@@ -12743,6 +12797,7 @@ Perfil ID: [%1]; Radio ID: [%2]
+
Reload Radio Data
Recarga datos de radio
@@ -12750,6 +12805,7 @@ Perfil ID: [%1]; Radio ID: [%2]
+
Reload all radio data without restarting the simulator.
Recarga todos los datos de la radio sin reiniciar el simulador.
@@ -12757,6 +12813,7 @@ Perfil ID: [%1]; Radio ID: [%2]
+
F9
@@ -12764,6 +12821,7 @@ Perfil ID: [%1]; Radio ID: [%2]
+
Key Mapping
Mapa de teclas
@@ -12771,6 +12829,7 @@ Perfil ID: [%1]; Radio ID: [%2]
+
Show keyboard maping reference.
Muestra el mapa de teclas.
@@ -12778,6 +12837,7 @@ Perfil ID: [%1]; Radio ID: [%2]
+
F1
@@ -12785,6 +12845,7 @@ Perfil ID: [%1]; Radio ID: [%2]
+
Joystick Settings
Ajustes joystick
@@ -12792,6 +12853,7 @@ Perfil ID: [%1]; Radio ID: [%2]
+
Open joystick configuration settings dialog.
Abre la configuracíon de ajustes del joystick.
@@ -12799,6 +12861,7 @@ Perfil ID: [%1]; Radio ID: [%2]
+
F3
@@ -12806,6 +12869,7 @@ Perfil ID: [%1]; Radio ID: [%2]
+
LCD Screenshot
Captura LCD
@@ -12813,6 +12877,7 @@ Perfil ID: [%1]; Radio ID: [%2]
+
Save a screenshot of the current simulated LCD screen.
Guarda una captura de la simulación de la pantalla LCD.
@@ -12820,6 +12885,7 @@ Perfil ID: [%1]; Radio ID: [%2]
+
F8
@@ -12827,6 +12893,7 @@ Perfil ID: [%1]; Radio ID: [%2]
+
Dock In Main Window
Anclar en la ventana principal
@@ -12834,6 +12901,7 @@ Perfil ID: [%1]; Radio ID: [%2]
+
Show the radio in the main window or as a separate "floating" window.
Muestra la radio en la ventana principal o en una ventana "flotante" separada.
@@ -12841,6 +12909,7 @@ Perfil ID: [%1]; Radio ID: [%2]
+
Menu Bar
Barra superior
@@ -12848,6 +12917,7 @@ Perfil ID: [%1]; Radio ID: [%2]
+
Show or hide the top menu bar.
Muestra u oculta la barra superior.
@@ -12855,6 +12925,7 @@ Perfil ID: [%1]; Radio ID: [%2]
+
Alt+M
Alt+M
@@ -12862,6 +12933,7 @@ Perfil ID: [%1]; Radio ID: [%2]
+
Constrain Width
Restringir ancho
@@ -12869,6 +12941,7 @@ Perfil ID: [%1]; Radio ID: [%2]
+
Set radio widget width to be a fixed size.
Fija el ancho de widget de la radio a un tamaño fijo.
@@ -12876,6 +12949,7 @@ Perfil ID: [%1]; Radio ID: [%2]
+
Constrain Height
Restringir alto
@@ -12883,6 +12957,7 @@ Perfil ID: [%1]; Radio ID: [%2]
+
Set radio widget height to be a fixed size.
Fija el alto de widget de la radio a un tamaño fijo.
@@ -12965,6 +13040,7 @@ Perfil ID: [%1]; Radio ID: [%2]
+
OpenTX Simulator - Startup Options
Simulador de OpenTX - Opciones de arranque
@@ -12972,6 +13048,7 @@ Perfil ID: [%1]; Radio ID: [%2]
+
Simulator Startup Options:
Opciones de arranque del simulador:
@@ -12979,6 +13056,7 @@ Perfil ID: [%1]; Radio ID: [%2]
+
Radio Profile:
Perfil de radio:
@@ -12986,6 +13064,7 @@ Perfil ID: [%1]; Radio ID: [%2]
+
Existing radio profiles are shown here.<br />
Create or edit profiles using the Companion application.
Los perfiles de radio existentes se muestran aquí.<br />
@@ -12995,6 +13074,7 @@ Crea o edita perfiles usando la aplicación de Companion.
+
Radio Type:
Tipo de radio:
@@ -13002,6 +13082,7 @@ Crea o edita perfiles usando la aplicación de Companion.
+
Existing radio simulators are shown here.<br />
The radio type specified in the selected profile is used by default.
Los simuladores de radio existentes se muestran aquí.<br />
@@ -13011,6 +13092,7 @@ Por defecto se us el tipo de radio especificado en en perfil seleccionado.
+
Data Source:
Origen de datos:
@@ -13018,6 +13100,7 @@ Por defecto se us el tipo de radio especificado en en perfil seleccionado.
+
Data File:
Archivo de datos:
@@ -13025,6 +13108,7 @@ Por defecto se us el tipo de radio especificado en en perfil seleccionado.
+
Data Folder:
Carpeta de datos:
@@ -13032,6 +13116,7 @@ Por defecto se us el tipo de radio especificado en en perfil seleccionado.
+
SD Image Path:
Ruta de la imagen SD:
@@ -13039,6 +13124,7 @@ Por defecto se us el tipo de radio especificado en en perfil seleccionado.
+
Radio data (.bin/.eeprom/.otx) image file to use. A new file with a default image will be created if necessary.<br />
<b>NOTE</b>: any existing EEPROM data incompatible with the selected radio type may be overwritten!
Archivo de datos de la radio (.bin/.eeprom/.otx) a usar. Un nuevo archivo con imange predeterminada se creará si es necesario.<br />
@@ -13048,6 +13134,7 @@ Por defecto se us el tipo de radio especificado en en perfil seleccionado.
+
Select data file...
Selecciona archivo de datos...
@@ -13061,6 +13148,9 @@ Por defecto se us el tipo de radio especificado en en perfil seleccionado.
+
+
+
...
@@ -13068,6 +13158,7 @@ Por defecto se us el tipo de radio especificado en en perfil seleccionado.
+
Directory containing RADIO and MODELS folders to use.<br />
New folder(s) with default radio/model will be created here if necessary.
Directorio conteniendo RADIO y MODELOS a usar.<br />
@@ -13077,6 +13168,7 @@ Nuevas carpeta(s) con radio/modelo predeterminado se crearán aquí si es necesa
+
Select data folder...
Selecciona carpeta de datos...
@@ -13084,6 +13176,7 @@ Nuevas carpeta(s) con radio/modelo predeterminado se crearán aquí si es necesa
+
Directory containing the SD card image to use.<br/>
The default is configured in the chosen Radio Profile.
Directorio que contiene la imagen de la tarjeta SD a usar.<br/>
@@ -13093,6 +13186,7 @@ El predeterminado es configurado en el Perfil de radio seleccionado.
+
Select SD card image folder...
Selecciona la carpeta de la imagen de la tarjeta SD...
@@ -13100,6 +13194,7 @@ El predeterminado es configurado en el Perfil de radio seleccionado.
+
Select which of the data sources (File/Folder/SD Card) you would like to start the simulator with.
Selecciona el origen de datos (Archivo/carpeta/tarjata SD) con el que quieres iniciar el simulador.
@@ -13107,6 +13202,7 @@ El predeterminado es configurado en el Perfil de radio seleccionado.
+
File
Archivo
@@ -13114,6 +13210,7 @@ El predeterminado es configurado en el Perfil de radio seleccionado.
+
Folder
Carpeta
@@ -13121,6 +13218,7 @@ El predeterminado es configurado en el Perfil de radio seleccionado.
+
SD Path
Ruta SD
@@ -13151,6 +13249,7 @@ El predeterminado es configurado en el Perfil de radio seleccionado.
+
Companion Simulator
Simulador Companion
@@ -13160,62 +13259,62 @@ El predeterminado es configurado en el Perfil de radio seleccionado.Simulador radio (%1)
-
+
Could not determine startup data source.
No se pueden determinar los datos de arranque.
-
+
Could not load data, possibly wrong format.
No se puede cargar datos, posiblemente formato erróneo.
-
+
Data Load Error
Error de carga de de datos
-
+
Invalid startup data provided. Plese specify a proper file/path.
Datos de inicio inválidos. Por favor specifica un archivo/ruta válido.
-
+
Simulator Startup Error
Error de arranque del simulador
-
+
Error saving data: could open file for writing: '%1'
Error salvando datos: no se puede abrir el archivo como escritura: '%1'
-
+
Error saving data: could not get data from simulator interface.
Error salvando datos: no se puede obtener datos de la interfaz del simulador.
-
+
An unexpected error occurred while attempting to save radio data to file '%1'.
Ha ocurrido un error inesperado al intentar guardar los datos de la radio al archivo '%1'.
-
+
Data Save Error
Error de guardado de datos
-
+
Radio firmware error: %1
Error del firmware de la radio: %1
-
+
- Flight Mode %1 (#%2)
- Modo de vuelo %1 (#%2)
-
+
Cannot open joystick, joystick disabled
No se puede abrir el joystick, joystick desactivado
@@ -13852,167 +13951,110 @@ Demasiados errores, abortando.
TelemetryAnalog
-
-
Unit
Unidad
-
-
Max Value
Valor máx
-
-
Alarm 1
Alarma 1
-
-
-
-
----
-
-
-
-
Yellow
Amarillo
-
-
-
-
Orange
Naranja
-
-
-
-
Red
Rojo
-
-
-
-
<
-
-
-
-
>
-
-
Alarm 2
Alarma 2
-
-
Offset
-
-
Volts (V)
Voltios (V)
-
-
Amps (A)
Amperios (A)
-
-
Speed (m/s or ft/s)
Velocidad (m/s o pies/s)
-
-
Raw (-)
-
-
Speed (km/h or miles/h)
Velocidad (km/h o millas/h)
-
-
Meters (m or ft)
Metros (m o pies)
-
-
Temp (°)
-
-
Fuel (%)
Combustible (%)
-
-
mAmps (mA)
miliAmperios (mA)
-
-
- Range
- Rango
-
TelemetryCustomScreen
@@ -14024,22 +14066,22 @@ Demasiados errores, abortando.
Personalizar tipo pantalla
-
+
None
Ninguno
-
+
Numbers
Números
-
+
Bars
Barras
-
+
Script
Script
@@ -14075,107 +14117,112 @@ Demasiados errores, abortando.
TelemetryPanel
-
+
FrSky S.PORT
-
+
FrSky D
-
+
FrSky D (cable)
-
+
Telemetry screen %1
Pantalla telemetría %1
-
+
Source
Fuente
-
+
Low Alarm
Alarma baja
-
+
Critical Alarm
Alarma crítica
-
+
Winged Shadow How High
-
+
Winged Shadow How High (not supported)
Winged Shadow How High (no soportado)
-
+
Alti
-
+
Alti+
-
+
VSpeed
VelocVert
-
-
-
+
+
+
A1
-
-
-
+
+
+
A2
-
-
+
+
A3
-
-
+
+
A4
-
-
+
+
FAS
-
+
Cells
Celdas
-
+
---
+
+
+ Delete Sensor. Are you sure?
+ Borrar sensor ¿Estás seguro?
+
TelemetrySensor
@@ -14596,67 +14643,92 @@ Demasiados errores, abortando.
TelemetrySensorPanel
-
+
TELE%1
-
+
Popup menu available
Menú desplegable disponible
-
+
Lowest
Menor
-
+
Cell %1
Celda %1
-
+
Highest
Mayor
-
+
Delta
-
+
Copy
Copiar
-
+
Cut
Cortar
-
+
Paste
Pegar
-
+
Clear
Limpiar
-
+
+ Insert
+ Insertar
+
+
+
+ Delete
+ Borrar
+
+
+
+ Move Up
+ Mover arriba
+
+
+
+ Move Down
+ Mover abajo
+
+
+
Clear All
Limpiar todo
-
+
+ Cut Telemetry Sensor. Are you sure?
+ Cortar sensor de telemetría ¿Estás seguro?
+
+
+
Clear Telemetry Sensor. Are you sure?
Limpiar el sensor de telemetría ¿Estás seguro?
-
+
Clear all Telemetry Sensors. Are you sure?
Limpiar todos los sensores de telemetría ¿Estás seguro?
@@ -14667,6 +14739,7 @@ Demasiados errores, abortando.
+
Telemetry Simulator
Simulador de telemetría
@@ -14674,6 +14747,7 @@ Demasiados errores, abortando.
+
VFAS
@@ -14681,6 +14755,7 @@ Demasiados errores, abortando.
+
RSSI
@@ -14688,6 +14763,7 @@ Demasiados errores, abortando.
+
A1
@@ -14695,6 +14771,7 @@ Demasiados errores, abortando.
+
A2
@@ -14702,6 +14779,7 @@ Demasiados errores, abortando.
+
Simulate
Simular
@@ -14709,6 +14787,7 @@ Demasiados errores, abortando.
+
Replay SD Log File
Reproducir archivo SD de reporte
@@ -14716,6 +14795,7 @@ Demasiados errores, abortando.
+
Replay rate
Velocidad de reproducción
@@ -14723,6 +14803,7 @@ Demasiados errores, abortando.
+
Load
Cargar
@@ -14730,6 +14811,7 @@ Demasiados errores, abortando.
+
|>
@@ -14737,6 +14819,7 @@ Demasiados errores, abortando.
+
<|
@@ -14744,6 +14827,7 @@ Demasiados errores, abortando.
+
>
@@ -14751,6 +14835,7 @@ Demasiados errores, abortando.
+
<-
@@ -14758,6 +14843,7 @@ Demasiados errores, abortando.
+
X
@@ -14765,6 +14851,7 @@ Demasiados errores, abortando.
+
Row #
Timestamp
Col #
@@ -14774,6 +14861,7 @@ Tiempo
+
1/5x
@@ -14781,6 +14869,7 @@ Tiempo
+
5x
@@ -14788,6 +14877,7 @@ Tiempo
+
No Log File Currently Loaded
Actualmente no hay cargado archivo de reporte
@@ -14795,6 +14885,7 @@ Tiempo
+
RAS
@@ -14808,6 +14899,9 @@ Tiempo
+
+
+
V / ratio
@@ -14815,6 +14909,7 @@ Tiempo
+
Db
@@ -14822,6 +14917,7 @@ Tiempo
+
RxBt
@@ -14865,6 +14961,19 @@ Tiempo
+
+
+
+
+
+
+
+
+
+
+
+
+
<html><head/><body><p><br/></p></body></html>
@@ -14872,6 +14981,7 @@ Tiempo
+
Tmp1
Temporizador 1
@@ -14879,6 +14989,7 @@ Tiempo
+
A3
@@ -14886,6 +14997,7 @@ Tiempo
+
A4
@@ -14893,6 +15005,7 @@ Tiempo
+
Tmp2
Temporizador 2
@@ -14900,6 +15013,7 @@ Tiempo
+
Fuel
Combustible
@@ -14910,6 +15024,8 @@ Tiempo
+
+
°C
@@ -14917,6 +15033,7 @@ Tiempo
+
ml
@@ -14924,6 +15041,7 @@ Tiempo
+
%
@@ -14934,6 +15052,8 @@ Tiempo
+
+
Meters
Metros
@@ -14941,6 +15061,7 @@ Tiempo
+
Alt
@@ -14948,6 +15069,7 @@ Tiempo
+
VSpd
VelocVertical
@@ -14955,6 +15077,7 @@ Tiempo
+
m/s
@@ -14962,6 +15085,7 @@ Tiempo
+
Fuel Qty
Cant. combust.
@@ -14972,6 +15096,8 @@ Tiempo
+
+
km/h
@@ -14979,6 +15105,7 @@ Tiempo
+
Hdg
@@ -14986,6 +15113,7 @@ Tiempo
+
ASpd
VelocAire
@@ -14999,6 +15127,9 @@ Tiempo
+
+
+
G
@@ -15006,6 +15137,7 @@ Tiempo
+
GPS
@@ -15013,6 +15145,7 @@ Tiempo
+
Lat,Lon
(dec.deg.)
@@ -15021,6 +15154,7 @@ Tiempo
+
AccX
@@ -15028,6 +15162,7 @@ Tiempo
+
dd-MM-yyyy
hh:mm:ss
@@ -15036,6 +15171,7 @@ hh:mm:ss
+
Date
Fecha
@@ -15043,6 +15179,7 @@ hh:mm:ss
+
Amps
@@ -15050,6 +15187,7 @@ hh:mm:ss
+
AccZ
@@ -15057,6 +15195,7 @@ hh:mm:ss
+
GAlt
@@ -15067,6 +15206,8 @@ hh:mm:ss
+
+
Volts
Voltios
@@ -15074,6 +15215,7 @@ hh:mm:ss
+
Cels
Celdas
@@ -15081,6 +15223,7 @@ hh:mm:ss
+
Curr
@@ -15088,6 +15231,7 @@ hh:mm:ss
+
AccY
@@ -15095,6 +15239,7 @@ hh:mm:ss
+
GSpd
VelocTierra
@@ -15102,6 +15247,7 @@ hh:mm:ss
+
Degrees
Grados
@@ -15109,6 +15255,7 @@ hh:mm:ss
+
Setting RSSI to zero simulates telemetry and radio link loss.
Fijando RSSI a cero simula pérdida de telemetría y conexión con la radio.
@@ -15116,6 +15263,7 @@ hh:mm:ss
+
Set RSSI to zero when paused.
Fijar RSSI a cero en pausa.
@@ -15123,6 +15271,7 @@ hh:mm:ss
+
Stop sending telemetry data when the Telemetry Simulator window is hidden.
Para de enviar datos de telemetría cuado el simulador esté oculto.
@@ -15130,6 +15279,7 @@ hh:mm:ss
+
Pause simulation when hidden.
Pausar simulación cuando se oculte.
@@ -15140,6 +15290,8 @@ hh:mm:ss
+
+
RPM
@@ -15147,6 +15299,7 @@ hh:mm:ss
+
When enabled, sends any non-blank values as simulated telemetry data.
Cuando está activado, envía valores no vacíos como datos de telemetría simulados.
@@ -15204,15 +15357,21 @@ hh:mm:ss
TimerData
-
+
TMR
-
+
Timer %1
Temporizador %1
+
+
+ TMR
+ as in Timer
+
+
TimerEdit
@@ -15242,37 +15401,37 @@ CTRL + scroll o AV/RE PÁG para cambiar el tiempo en pasos grandes.
TimerPanel
-
+
Silent
Silencio
-
+
Beeps
-
+
Voice
Voz
-
+
Haptic
-
+
Not persistent
No persistente
-
+
Persistent (flight)
Persistente (vuelo)
-
+
Persistent (manual reset)
Persistente (reset manual)
@@ -15494,6 +15653,7 @@ CTRL + scroll o AV/RE PÁG para cambiar el tiempo en pasos grandes.
+
Trainer simulator
Simulador de entrenador
@@ -15916,126 +16076,66 @@ CTRL + scroll o AV/RE PÁG para cambiar el tiempo en pasos grandes.
burnConfigDialog
-
-
-
-
- AVRDUDE Location
- Ubicación AVRDUDE
-
-
-
-
-
- Location of AVRDUDE executable
- Locatioon of AVRDUDE executable
- Ubicación del ejecutable AVRDUDE
-
-
-
+
+
Programmer Configuration
Configuration AVRDUDE / SAM-BA
Configuración del programador
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
The location of the AVRDUDE executable.
The location of the AVRDUDE.EXE executable.
La ubicación del ejecutable AVRDUDE.
-
-
-
+
+
+
DFU-Util Location
Ubicación de la utilidad DFU
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
Use this button to browse and look for the AVRDUDE executable file.
Usa este botón para explorar y ver el archivo ejecutable de AVRDUDE.
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
Browse...
Explorar...
-
-
-
- Programmer
- Programador
-
-
-
-
-
- Programmer used for communicating with the controller.
-Please consult the programmer's documentation and the AVRDUDE documentation to select the appropriate programmer.
- Programador usado para la comunicación con el controlador.
-Por favor consulta la documentacion del programador y la documentación de AVRDUDE para elegir el programador adecuado.
-
-
-
-
-
- List all available programmers.
- Lista todos los programadores disponibles.
-
-
-
-
-
- List Available
- Listado disponibles
-
-
-
-
-
-
-
-
+
+
+
Extra arguments that will be passed to AVRDUDE on every call
Argumentos extra que deben pasar a AVRDUDE en cada llamada
-
-
-
-
-
-
+
+
+
Extra arguments used in AVRDUDE.
This can be used for providing extra information to AVRDUDE.
@@ -16046,157 +16146,91 @@ Esto se puede utilizar para proporcionar información adicional para AVRDUDE.
Por favor solamente usa esto si sabes lo que estás haciendo. No hay control de errores y podría paralizar tu controlador.
-
-
-
- Extra Arguments
- Argumentos extra
-
-
-
-
-
- Show AVRDUDE help
- Mostrar la ayuda de AVRDUDE
-
-
-
-
-
- Show Help
- Mostrar ayuda
-
-
-
-
-
- Communication port to the programmer.
-
- Puerto de comunicaciones al programador.
-
-
-
-
-
- MCU
-
-
-
-
-
-
+
+
+
at91sam3s8-9xr
-
-
-
+
+
+
Alternate device
Dispositivo alternativo
-
-
-
+
+
+
Use advanced controls
Usar controles avanzados
-
-
-
-
-
-
+
+
+
Port
Puerto
-
-
-
+
+
+
SAM-BA Location
Ubicación SAM-BA
-
-
-
-
-
-
+
+
+
+
+
+
Location of sam-ba executable
Ubicación del ejecutable sam-ba
-
-
-
+
+
+
ARM MCU
-
-
-
+
+
+
sam-ba serial port
Puerto serie sam-ba
-
+
DFU-UTIL Configuration
Configuración DFU-UTIL
-
+
SAM-BA Configuration
Configuración SAM-BA
-
- AVRDUDE Configuration
- Configuración AVRDUDE
-
-
-
-
-
+
+
Select Location
Seleccionar ubicación
-
- List available programmers
- Lista de programadores disponibles
-
-
-
- Avrdude help
- Ayuda Avrdude
-
-
-
- <b><u>WARNING!</u></b><br>Normally CPU type is automatically selected according to the chosen firmware.<br>If you change the CPU type the resulting eeprom could be inconsistent.
- <b><u>¡AVISO!</u></b><br>Normalmente el tipo de CPU es automáticamente elegida para el tipo de firmware.<br>Si cambias el tipo de CPU el eeprom resultante podría ser inconsistente.
-
-
-
-
-
-
-
-
+
+
+
CPU of your TX
CPU de tu TX
-
-
-
-
-
-
+
+
+
CPU present on your 9x radio
Should be m64 for stock radios
m2560 for v4.1 boards
@@ -16211,6 +16245,7 @@ m2560 para las placas v4.1
+
Configure Joystick
Configurar joystick
@@ -16218,6 +16253,7 @@ m2560 para las placas v4.1
+
Ch2
@@ -16225,6 +16261,7 @@ m2560 para las placas v4.1
+
Ch1
@@ -16232,6 +16269,7 @@ m2560 para las placas v4.1
+
Ch4
@@ -16239,6 +16277,7 @@ m2560 para las placas v4.1
+
Ch6
@@ -16246,6 +16285,7 @@ m2560 para las placas v4.1
+
Ch3
@@ -16253,6 +16293,7 @@ m2560 para las placas v4.1
+
Ch5
@@ -16260,6 +16301,7 @@ m2560 para las placas v4.1
+
Ch7
@@ -16267,6 +16309,7 @@ m2560 para las placas v4.1
+
Ch8
@@ -16274,6 +16317,7 @@ m2560 para las placas v4.1
+
Instructions
Instrucciones
@@ -16281,6 +16325,7 @@ m2560 para las placas v4.1
+
Enable
Activar
@@ -16288,6 +16333,7 @@ m2560 para las placas v4.1
+
Cancel
Cancelar
@@ -16295,6 +16341,7 @@ m2560 para las placas v4.1
+
Back
Atrás
@@ -16302,6 +16349,7 @@ m2560 para las placas v4.1
+
Start
Inicio
@@ -16314,6 +16362,7 @@ m2560 para las placas v4.1
+
Ok
diff --git a/companion/src/translations/companion_fr.ts b/companion/src/translations/companion_fr.ts
index fff65e6d9..2a6eea996 100644
--- a/companion/src/translations/companion_fr.ts
+++ b/companion/src/translations/companion_fr.ts
@@ -95,7 +95,7 @@
Edit Settings
- Éditer les paramètres
+ Éditer les préférences
@@ -488,7 +488,7 @@ Manche Droit: Profondeur, Direction
Automatic Backup Folder
- Dossier de sauvegardes automatiques
+ Dossier des sauvegardes automatiques
@@ -743,58 +743,58 @@ Manche Droit: Profondeur, Direction
Boards
-
+
Left Horizontal
Gauche Horizontal
-
+
Left Vertical
Gauche Vertical
-
+
Right Vertical
Droit Vertical
-
+
Right Horizontal
Droit Horizontal
-
+
Aux. 1
-
+
Aux. 2
-
-
+
+
Unknown
Inconnu
-
+
Rud
Dir
-
+
Ele
Prf
-
+
Thr
Gaz
-
+
Ail
@@ -841,124 +841,129 @@ Manche Droit: Profondeur, Direction
- Channels
+ ChannelsPanel
-
+
Name
Nom
-
+
+ Subtrim
+ Subtrim
+
+
+
Min
-
+
Max
-
- Subtrim
-
-
-
-
+
Direction
-
+
Curve
Courbe
-
+
PPM Center
Neutre PPM
-
+
Linear Subtrim
Subtrim linéaire
-
+
CH%1
VOIE%1
-
+
Popup menu available
Menu contextuel disponible
-
+
---
-
+
INV
-
+
Delete Channel. Are you sure?
Supprimer la Voie. Êtes-vous sûr?
-
+
+ Cut Channel. Are you sure?
+ Couper la Voie. Êtes-vous sûr?
+
+
+
Copy
Copier
-
+
Cut
Couper
-
+
Paste
Coller
-
+
Clear
Effacer
-
+
Insert
Insérer
-
+
Delete
Supprimer
-
+
Move Up
Monter
-
+
Move Down
Descendre
-
+
Clear All
Effacer Tout
-
+
Clear Channel. Are you sure?
Effacer la Voie. Êtes-vous sûr?
-
+
Clear all Channels. Are you sure?
Effacer toutes les Voies. Êtes-vous sûr?
@@ -1113,37 +1118,37 @@ Manche Droit: Profondeur, Direction
<p> Le type de radio sélectionnée dans le profil n'existe pas. Utilisez plutôt le type par défaut. </p> <p><b>Veuillez mettre à jour les paramètres de votre profil!</b></p>
-
+
Select or create a file for exported Settings:
Sélectionnez ou créez un fichier pour les paramètres exportés:
-
+
Press the 'Retry' button to choose another file.
Appuyez sur le bouton 'Réessayer' pour choisir un autre fichier.
-
+
Simulator for this firmware is not yet available
Le simulateur n'est pas encore disponible pour ce firmware
-
+
Uknown error during Simulator startup.
Erreur inconnue pendant le démarrage du simulateur.
-
+
Simulator Error
Erreur Simulateur
-
+
Data Load Error
Erreur de chargement des données
-
+
Error occurred while starting simulator.
Une erreur s'est produite lors du démarrage du simulateur.
@@ -1376,57 +1381,34 @@ Si vous avez un fichier de sauvegarde des paramètres, vous pouvez l'import
CurveData
-
+
CV
CB
- CurveGroup
+ CurveReference
-
+
Diff
-
+
Expo
-
+
Func
Fonc
-
+
Curve
Courbe
-
- CurveReference
-
-
- Diff(%1)
-
-
-
-
- Expo(%1)
-
-
-
-
- Function(%1)
- Fonction(%1)
-
-
-
- Curve(%1)
- Courbe(%1)
-
-
Curves
@@ -1515,348 +1497,414 @@ Si vous avez un fichier de sauvegarde des paramètres, vous pouvez l'import
Curve name
Nom de la courbe
+
+
+ CurvesPanel
-
+
Curve %1
Courbe %1
-
+
Popup menu available
Menu contextuel disponible
-
+
%1 points
-
+
Linear
Linéaire
-
+
Single Expo
Expo simple
-
+
Symmetrical f(x)=-f(-x)
Symétrique f(x)=-f(-x)
-
+
Symmetrical f(x)=f(-x)
Symétrique f(x)=f(-x)
-
- Copy
- Copier
-
-
-
- Cut
- Couper
-
-
-
- Paste
- Coller
-
-
-
- Clear
- Effacer
-
-
-
- Insert
- Insérer
-
-
-
- Delete
- Supprimer
-
-
-
- Move Up
- Monter
-
-
-
- Move Down
- Descendre
-
-
-
- Clear All
- Effacer Tout
-
-
-
- Clear Curve. Are you sure?
- Effacer la Courbe. Êtes-vous sûr?
-
-
-
- Clear all Curves. Are you sure?
- Effacer toutes les Courbes. Êtes-vous sûr?
-
-
-
- Delete Curve. Are you sure?
- Supprimer la Courbe. Êtes-vous sûr?
-
-
-
+
Editing curve %1
Édition de la courbe %1
-
+
Not enough free points in EEPROM to store the curve.
Pas assez de points disponibles en mémoire pour enregistrer la courbe.
+
+
+ Copy
+ Copier
+
+
+
+ Cut
+ Couper
+
+
+
+ Paste
+ Coller
+
+
+
+ Clear
+ Effacer
+
+
+
+ Insert
+ Insérer
+
+
+
+ Delete
+ Supprimer
+
+
+
+ Move Up
+ Monter
+
+
+
+ Move Down
+ Descendre
+
+
+
+ Clear All
+ Effacer Tout
+
+
+
+ Clear Curve. Are you sure?
+ Effacer la Courbe. Êtes-vous sûr?
+
+
+
+ Clear all Curves. Are you sure?
+ Effacer toutes les Courbes. Êtes-vous sûr?
+
+
+
+ Cut Curve. Are you sure?
+ Couper la Courbe. Êtes-vous sûr?
+
+
+
+ Delete Curve. Are you sure?
+ Supprimer la Courbe. Êtes-vous sûr?
+
CustomFunctionData
-
+
GF
FG
-
+
SF
FS
-
+
Override %1
Remplacer %1
-
- Trainer
- Écolage Manches
+
+ Trainer Sticks
+ Manches Écolage
-
+
Trainer RUD
Écolage Direction
-
+
Trainer ELE
Écolage Profondeur
-
+
Trainer THR
Écolage Gaz
-
+
Trainer AIL
Écolage Ailerons
-
+
Trainer Channels
Écolage Channels
-
+
Instant Trim
Trims instantanés
-
+
Play Sound
Jouer Son
-
+
Haptic
Vibreur
-
+
Reset
Remise à zéro
-
- Set Timer %1
- Définir chrono %1
+
+ Set %1
+ Activer %1
-
+
Vario
-
+
Play Track
Jouer fichier
-
+
Play Both
Jouer les deux
-
+
Play Value
Lire valeur
-
- Play Script
- Exécuter script
+
+ Lua Script
+ Script Lua
-
+
+ Range Check Int. Module
+ Test Portée Module Int.
+
+
+
+ Range Check Ext. Module
+ Test Portée Module Ext.
+
+
+
+ Beep 1
+
+
+
+
+ Beep 2
+
+
+
+
+ Beep 3
+
+
+
+
+ Warn 1
+ Alerte 1
+
+
+
+ Warn 2
+ Alerte 2
+
+
+
+ Cheep
+ Piauler
+
+
+
+ Ratata
+
+
+
+
+ Tick
+ Tic-tac
+
+
+
+ Siren
+ Sirène
+
+
+
+ Ring
+ Sonner
+
+
+
+ Sci Fi
+
+
+
+
+ Robot
+
+
+
+
+ Chirp
+ Gazouiller
+
+
+
+ Tada
+
+
+
+
+ Cricket
+ Criquet
+
+
+
+ Alarm Clock
+ Réveil
+
+
+
+ Value
+ Valeur
+
+
+
+ Source
+
+
+
+
+ Global Variable
+ Variable Globale
+
+
+
+ Inc/Decrement
+ Inc/Décrémenter
+
+
+
SD Logs
Logs SD
-
+
Volume
-
+
Backlight
Rétroéclairage
-
+
Screenshot
Capture d'écran
-
+
Background Music
Musique de fond
-
+
Background Music Pause
Pause musique de fond
-
+
Adjust %1
Ajuster %1
-
- SetFailsafe Int. Module
- Définir failsafe module interne
+
+ Set Failsafe
+ Définir Failsafe
-
- SetFailsafe Ext. Module
- Définir failsafe module externe
-
-
-
- RangeCheck Int. Module
- Test portée module interne
-
-
-
- RangeCheck Ext. Module
- Test portée module externe
-
-
-
+
Bind Int. Module
Bind module interne
-
+
Bind Ext. Module
Bind module externe
-
- Timer1
- Chrono 1
+
+ Played once, not during startup
+ Lu une fois, mais pas à la mise en route
-
- Timer2
- Chrono 2
+
+ No repeat
+ Lu une fois
-
- Timer3
- Chrono 3
+
+ Repeat %1s
+ Répéter %1s
-
+
Flight
Vol
-
+
Telemetry
Télémétrie
-
- Rotary Encoder
- Sélecteur Rotatif
-
-
-
- REa
-
-
-
-
- REb
-
-
-
-
+
s
-
-
-
- <font color=red><b>Inconsistent parameter</b></font>
- <font color=red><b>Paramètre inconsistant</b></font>
-
-
-
- Value
- Valeur
-
-
-
- played once, not during startup
- !1x Lu une fois, mais pas à la mise en route
-
-
-
- repeat(%1s)
- Répéter chaque %1s
-
-
-
+
DISABLED
DESACTIVE
-
+
CFN
FPN
@@ -1864,136 +1912,121 @@ Si vous avez un fichier de sauvegarde des paramètres, vous pouvez l'import
CustomFunctionsPanel
-
+
Switch
Interrupteur
-
+
Action
-
+
Parameters
Paramètres
-
- Enable
- Actif
-
-
-
+
Popup menu available
Menu contextuel disponible
-
+
SF%1
FS%1
-
+
GF%1
FG%1
-
+
+ GV
+ VG
+
+
+
ON
-
+
Error occurred while trying to play sound, possibly the file is already opened. (Err: %1 [%2])
Une erreur s'est produite lors de la lecture du son, le fichier est peut-être déjà ouvert. (Err: %1 [%2])
-
+
Unable to find or open sound file:
%1
Impossible de trouver ou d'ouvrir le fichier son:
%1
-
- Delete Special Function. Are you sure?
- Supprimer la Fonction Spéciale. Êtes-vous sûr?
+
+ Delete Function. Are you sure?
+ Supprimer la Fonction. Êtes-vous sûr?
-
+
+ Cut Special Function. Are you sure?
+ Couper la Fonction. Êtes-vous sûr?
+
+
+
Copy
Copier
-
+
Cut
Couper
-
+
Paste
Coller
-
+
Clear
Effacer
-
+
Insert
Insérer
-
+
Delete
Supprimer
-
+
Move Up
Monter
-
+
Move Down
Descendre
-
+
Clear All
Effacer Tout
-
- Value
- Valeur
+
+ Clear Function. Are you sure?
+ Effacer la Fonction. Êtes-vous sûr?
-
- Source
- Source
-
-
-
- GVAR
- VG
-
-
-
- Increment
- Incrément
-
-
-
- Clear Special Function. Are you sure?
- Effacer la Fonction Spéciale. Êtes-vous sûr?
-
-
-
- Clear all Special Functions. Are you sure?
- Supprimer toutes les Fonctions Spéciales. Êtes-vous sûr?
+
+ Clear all Functions. Are you sure?
+ Effacer toutes les Fonctions. Êtes-vous sûr?
@@ -2159,52 +2192,105 @@ Si vous avez un fichier de sauvegarde des paramètres, vous pouvez l'import
Erreur de conversion du champ %1
-
+
Switch
Interrupteur
-
+
Switch
L'interrupteur
-
+
cannot be exported on this board!
n'est pas supporté sur cette carte !
-
+
Source
-
+
Source %1 cannot be exported on this board!
La source %1 n'est pas supportée sur cette plateforme !
-
+
OpenTX only accepts %1 points in all curves
OpenTX n'accepte que %1 points au maximum entre toutes les courbes
-
+
OpenTx only accepts %1 points in all curves
OpenTX n'accepte que %1 points au maximum entre toutes les courbes
-
-
+
+
OpenTX on this board doesn't accept this function
OpenTX ne supporte pas cette fonction sur cette carte
-
+
OpenTX doesn't accept this radio protocol
OpenTX ne supporte pas ce protocole radio
+
+ DataHelpers
+
+
+ Disabled
+ Désactivé
+
+
+
+ Enabled
+ Activé
+
+
+
+ OFF
+
+
+
+
+ ON
+
+
+
+
+ False
+ Faux
+
+
+
+ True
+ Vrai
+
+
+
+ N
+
+
+
+
+ Y
+ O
+
+
+
+ No
+ Non
+
+
+
+ Yes
+ Oui
+
+
DebugOutput
@@ -2327,62 +2413,47 @@ Pour <b>retirer un filtre de l'historique</b>, sélectionnez-le
- - Eeprom is not from Th9X
- - L'EEPROM n'est pas une EEPROM TX9X
-
-
-
- - Eeprom is not from Gruvin9X
- - L'EEPROM n'est pas une EEPROM Gruvin9X
-
-
-
- Eeprom is not from ErSky9X
- L'EEPROM n'est pas une EEPROM ErSky9X
-
- - Eeprom is not from Er9X
- - L'EEPROM n'est pas une EEPROM Er9X
-
-
-
+
- Eeprom size is invalid
- La taille de l'EEPROM est invalide
-
+
- Eeprom file system is invalid
- Le système de fichier de l'EEPROM est invalide
-
+
- Eeprom is from a unknown board
- L'EEPROM ne correspond à aucune carte supportée
-
+
- Eeprom is from the wrong board
- L'EEPROM ne correspond pas au type de radio sélectionné
-
+
- Eeprom backup not supported
- Sauvegarde d'EEPROM non supportée
-
+
- Something that couldn't be guessed, sorry
- Erreur inconnue
-
+
Warning:
Avertissement:
-
-
+
+
- Your radio probably uses a wrong firmware,
eeprom size is 4096 but only the first 2048 are used
- Le firmware de la radio est probablement incorrect,
@@ -2390,7 +2461,7 @@ la taille de l'EEPROM est de 4096 mais seulement 2048 bytes sont utilisés.
Vérifier la sélection (M64/M128)
-
+
- Your eeprom is from an old version of OpenTX, upgrading!
To keep your original file as a backup, please choose File -> Save As specifying a different name.
- Votre eeprom provient d'une ancienne version d'OpenTX, mettez à niveau!
@@ -2426,12 +2497,12 @@ Vérifier la sélection (M64/M128)
ExpoData
-
+
INP
ENT
-
+
(@%1)
@@ -2446,7 +2517,7 @@ Vérifier la sélection (M64/M128)
Flight modes
- Phases de vol
+ Phases de Vol
@@ -2548,27 +2619,27 @@ Si vide, la ligne est toujours active.
Les 2
-
+
Edit %1
Éditer %1
-
+
Popup menu available
Menu contextuel disponible
-
+
Clear All
Effacer Tout
-
+
Set All
Définir Tout
-
+
Invert All
Inverser Tout
@@ -2657,129 +2728,129 @@ Si vide, la ligne est toujours active.
FileSyncDialog
-
+
Synchronize Files
Synchroniser les fichiers
-
+
Are you sure you wish to abort the sync?
Êtes-vous sûr de vouloir annuler la synchronisation?
-
+
Source Folder:
Dosssier "Local":
-
+
Destination Folder:
Dossier "Radio":
-
+
%1%2 Both directions, to destination folder first
%1%2 Bidirectionnel, en commençant par "Radio"
-
+
%1%2 Both directions, to source folder first
%1%2 Bidirectionnel, en commençant par "Local"
-
+
%1 Only from source folder to destination folder
%1 Uniquement de "Local" vers "Radio"
-
+
%1 Only from destination folder to source folder
%1 Uniquement de "Radio" vers "Local"
-
+
How to handle overwriting files which already exist in the destination folder.
Comment gérer l'écrasement des fichiers qui existent déjà dans le dossier de destination.
-
+
Copy only if newer and different (compare contents)
Copiez seulement si "plus récent et différent" (comparez le contenu)
-
+
Copy only if newer (do not compare contents)
Copier uniquement si "plus récent" (ne pas comparer le contenu)
-
+
Copy only if different (ignore file time stamps)
Copier uniquement si "différent" (ignorer l'horodatage des fichiers)
-
+
Always copy (force overwite existing files)
Toujours copier (écraser tous les fichiers existants)
-
+
Any size
Toutes tailles
-
+
Skip files larger than this size. Enter zero for unlimited.
Ignorer tous les fichiers plus grands que cette taille. Entrez 0 pour illimité.
-
+
Minimum reporting level. Events of this type and of higher importance are shown.
WARNING: High log rates may make the user interface temporarily unresponsive.
Niveau de rapport au minimum. Les événements de ce type et d'une plus grande importance sont indiqués.
ATTENTION: un taux de rapport élevé peut rendre l'interface utilisateur temporairement inutilisable.
-
+
Skipped
Sauté
-
+
Created
Créé
-
+
Updated
Mis à jour
-
+
Errors Only
Erreur seulement
-
+
Test-run only
Essai
-
+
Run as normal but do not actually copy anything. Useful for verifying results before real sync.
Exécutez normalement, mais ne rien copier. Utile pour vérifier les résultats avant la synchronisation réelle.
-
+
Log Level:
Niveau de rapport:
-
+
Filters:
Filtres:
-
+
The "Include" filter will only copy files which match the pattern(s).
The "Exclude" filter will skip files matching the filter pattern(s).
The Include filter is evaluated first.
@@ -2788,148 +2859,148 @@ Le filtre "Exclure" ignorera les fichiers correspondant à la (aux) r
Le filtre "Inclure" est évalué en premier.
-
+
One or more file pattern(s) to exclude, separated by commas.
Blank means exclude none. ?, *, and [...] wildcards accepted.
Une ou plusieurs règle(s) de fichier(s) à exclure, séparés par des virgules.
Blanc signifie "exclure aucun".Les métacaractères ?, * et [...] sont acceptés.
-
+
One or more file pattern(s) to include, separated by commas.
Blank means include all. ?, *, and [...] wildcards accepted.
Une ou plusieurs règle(s) de fichier(s) à inclure, séparés par des virgules.
Blanc signifie "inclure tous".Les métacaractères ?, * et [...] sont acceptés.
-
+
Include:
Inclure:
-
+
Exclude:
Exclure:
-
+
Case sensitive
Sensible aux majuscules et minuscules
-
-
+
+
Follow links
Suivez les liens
-
+
Include hidden
Inclure fichier/dossier caché
-
+
Recursive
Récursif
-
+
Skip empty
Sauter vide
-
+
Apply filters
Appliquer les filtres
-
+
Filter Options:
Options des Filtres:
-
+
Folder Options:
Options des Dossiers:
-
-
+
+
Options
-
+
Show extra options
Afficher les options supplémentaires
-
+
Reset to defaults
Réinitialiser les paramètres par défaut
-
+
Close
Fermer
-
+
Sync. Direction:
Direction de la synchro.:
-
+
Existing Files:
Fichiers existants:
-
+
Max. File Size:
Taille Max Fichier:
-
+
MB
Mo
-
+
KB
ko
-
+
Abort
Annuler
-
+
Start
Démarrer
-
+
Total: <b>%1</b>; Created: <b>%2</b>; Updated: <b>%3</b>; Skipped: <b>%4</b>; Errors: <font color=%6><b>%5</b></font>;
Total: <b>%1</b>; Créé(s): <b>%2</b>; Mis à jour: <b>%3</b>; Sauté(s): <b>%4</b>; Erreur(s): <font color=%6><b>%5</b></font>;
-
+
Current: <b>%1</b> of
Courant: <b>%1</b> de
-
+
Source folder not found.
Dosssier "Local" non trouvé.
-
+
Destination folder not found.
Dosssier "Radio" non trouvé.
-
+
Source and destination folders are the same.
Les dossiers "Local" et "Radio" sont les mêmes.
@@ -2937,282 +3008,296 @@ Blanc signifie "inclure tous".Les métacaractères ?, * et [...] sont
Firmware
-
+
Channel values displayed in us
Positions de voies affichées en µs
-
+
No OverrideCH functions available
Désactive la fonction spéciale "Remplacer VOIExx"
-
+
Possibility to enable FAI MODE (no telemetry) at field
Possibilité d'activer le mode FAI (télémétrie désactivée) sur le terrain
-
+
FAI MODE (no telemetry) always enabled
Mode FAI (télémétrie toujours désactivée)
-
+
Removes D8 FrSky protocol support which is not legal for use in the EU on radios sold after Jan 1st, 2015
Masque le protocole D8. Légalement obligatoire sur les radios Européennes importées après le 1er janvier 2015
-
-
+
+
+
+
+
Disable HELI menu and cyclic mix support
Supprimer le menu HELICO et les mixages cycliques
-
-
+
+
+
+
+
Disable Global variables
Supprimer le support des variables globales
-
-
+
+
+
+
+
Enable Lua custom scripts screen
Activer l'écran des scripts Lua personnalisés
-
- Support for PPM internal module hack
- Support du remplacement du module interne par un module PPM
-
-
-
+
Use alternative SQT5 font
Utiliser la police alternative SQT5
-
-
+
+
Disable RAS (SWR)
Désactiver le RAS (SWR). Utile uniquement pour les X9D+ avec un RAS/SWR non fonctionnel
-
+
Pots use in menus navigation
Support de la navigation dans les menus avec les POTS
-
+
+ Enable AFHDS3 support
+ Activer le support du AFHDS3
+
+
+
FrSky Taranis X9D+
-
+
FrSky Taranis X9D+ 2019
-
+
FrSky Taranis X9D
-
+
Haptic module installed
Module vibreur installé
-
+
FrSky Taranis X9E
-
+
Confirmation before radio shutdown
Confirmation avant l'arrêt de la radio
-
+
Horus gimbals installed (Hall sensors)
Manches Horus à effet HALL installés
-
+
FrSky Taranis X9-Lite
-
+
FrSky Taranis X9-Lite S
-
+
FrSky Taranis X7 / X7S
-
+
FrSky Taranis X7 / X7S Access
-
+
FrSky Taranis X-Lite S/PRO
-
+
FrSky Taranis X-Lite
-
+
FrSky Horus X10 / X10S
-
-
+
+
Support for ACCESS internal module replacement
Prise en charge du module de remplacement interne ACCESS
-
+
+
+
+
+
+ Support hardware mod: R9M ACCESS
+ Prise en charge du mod hardware: R9M ACCESS
+
+
+
FrSky Horus X10 Express / X10S Express
-
+
FrSky Horus X12S
-
+
Use ONLY with first DEV pcb version
Exclusivement pour les Horus DEV
-
-
+
+
Support for MULTI internal module
Prise en charge du module MULTI interne
-
-
+
+ Jumper T-Lite
+
+
+
+
+
+
Support for bluetooth module
Prise en charge du module Bluetooth
-
- Radiomaster TX16s / TX16s Hall / TX16s Masterfire
+
+ Radiomaster T8
-
+
+ Allow bind using bind key
+ Autoriser l'appairage avec le bouton"bind"
+
+
+
Support internal GPS
Prise en charge du GPS interne
-
+
+ Jumper T18
+
+
+
+
Turnigy 9XR-PRO
-
+
Enable HELI menu and cyclic mix support
Activer le menu hélico et les mixages CCPM
-
+
Global variables
Variables globales
-
+
Enable non certified firmwares
Activer les firmwares non certifiés
-
+
In model setup menus automatically set source by moving the control
Sélectionner les sources des mixeurs en bougeant le contrôle désiré
-
+
In model setup menus automatically set switch by moving the control
Sélectionner les interrupteurs en bougeant le contrôle désiré
-
+
No graphical check boxes and sliders
Pas de cases à cocher et de curseurs graphiques
-
+
Battery graph
Graphique de la batterie
-
+
Don't use bold font for highlighting active items
Ne pas mettre les lignes actives en gras
-
- Turnigy 9XR with m128 chip
- Turnigy 9XR avec une puce m128
-
-
-
- Turnigy 9XR
-
-
-
-
- 9X with stock board
- 9X avec carte mère d'origine
-
-
-
+
Enable resetting values by pressing up and down at the same time
Permet la remise à zéro des valeurs en pressant haut-bas en même temps, valeur min avec gauche/bas, valeur max avec haut/droite, inversion avec gauche/droite
-
- 9X with stock board and m128 chip
- Carte 9x avec un chip m128
+
+ Radiomaster TX12
+
-
+
+ Radiomaster TX16S / SE / Hall / Masterfire
+
+
+
+
9X with AR9X board
9X avec carte AR9X
-
+
Jumper T12 / T12 Pro
-
+
Jumper T16 / T16+ / T16 Pro
-
+
9X with Sky9x board
9X avec carte Sky9x
-
-
- 9X with Gruvin9x board
- 9X avec carte Gruvin9x
-
-
-
- DIY MEGA2560 radio
- Radio DIY à base de MEGA2560
-
FirmwarePreferencesDialog
@@ -3471,62 +3556,62 @@ Blanc signifie "inclure tous".Les métacaractères ?, * et [...] sont
Transférer
-
+
Open Firmware File
Sélectionner le firmware
-
+
%1 may not be a valid firmware file
%1 ne semble pas être un firmware valide
-
+
The firmware file is not valid.
Le firmware est invalide.
-
+
There is no start screen image in the firmware file.
Aucun écran d'accueil trouvé dans le firmware.
-
+
Profile image %1 is invalid.
L'image du profil %1 est invalide.
-
+
Open image file to use as radio start screen
Ouvrir l'image à utiliser comme écran d'accueil
-
+
Images (%1)
Images (%1)
-
+
Image could not be loaded from %1
L'image %1 n'a pu être chargée
-
+
The library image could not be loaded
L'image n'a pu être chargée depuis la bibliothèque
-
+
Splash image not found
Ecran d'accueil sélectionné introuvable
-
+
Cannot save customized firmware
Impossible d'enregistrer le firmware personnalisé
-
+
Write Firmware to Radio
Transférer le firmware à la radio
@@ -3547,27 +3632,27 @@ Blanc signifie "inclure tous".Les métacaractères ?, * et [...] sont
Le nouveau firmware ne correspond pas à la version installée, vérifiez le type de radio !
-
+
Conversion failed
La conversion a échoué
-
+
Cannot convert Models and Settings for use with this firmware, original data will be used
Impossible de convertir les paramètres et modèles pour ce firmware, les données originales vont être utilisées
-
+
Restore failed
Echec de la restauration
-
+
Could not restore Models and Settings to Radio. The models and settings data file can be found at: %1
Impossible de restaurer les paramètres et modèles sur la radio. Le fichier peut être récupéré ici: %1
-
+
Flashing done
Programmation terminée
@@ -3580,42 +3665,42 @@ Blanc signifie "inclure tous".Les métacaractères ?, * et [...] sont
Exécutable %1 introuvable
-
+
Writing...
Ecriture...
-
+
Reading...
Lecture...
-
+
Verifying...
Vérification...
-
+
unknown
inconnu
-
+
ie: OpenTX for 9X board or OpenTX for 9XR board
ex: OpenTX pour carte d'origine 9x ou OpenTX pour 9XR
-
+
ie: OpenTX for M128 / 9X board or OpenTX for 9XR board with M128 chip
ex:. OpenTX pour carte d'origine 9x avec m128 ou OpenTX pour 9XR avec m128
-
+
ie: OpenTX for Gruvin9X board
ex: OpenTX pour carte gruvin9x
-
+
Your radio uses a %1 CPU!!!
Please check advanced burn options to set the correct cpu type.
@@ -3624,7 +3709,7 @@ Please check advanced burn options to set the correct cpu type.
Vérifiez les options de programmateur et choisissez le bon type de processeur.
-
+
Your radio uses a %1 CPU!!!
Please select an appropriate firmware type to program it.
@@ -3633,7 +3718,7 @@ Please select an appropriate firmware type to program it.
Veuillez choisir le firmware approprié.
-
+
You are currently using:
%1
@@ -3642,22 +3727,22 @@ Vous utilisez actuellement:
%1
-
+
Your radio does not seem connected to USB or the driver is not initialized!!!.
Votre radio ne semble pas être connectée en USB, ou le pilote n'est pas initialisé !!!.
-
+
Flashing done (exit code = %1)
Terminé (code de sortie = %1)
-
+
Flashing done with errors
Terminé avec des erreurs
-
+
FUSES: Low=%1 High=%2 Ext=%3
Fusibles: Bas=%1 Haut=%2 Ext=%3
@@ -3698,7 +3783,7 @@ Vous utilisez actuellement:
FlightModeData
-
+
FM
PV
@@ -3706,47 +3791,47 @@ Vous utilisez actuellement:
FlightModePanel
-
+
Rotary Encoder %1
Sélecteur Rotatif %1
-
+
Name
Nom
-
+
Value source
Source valeur
-
+
Value
Valeur
-
+
Unit
-
+
Prec
-
+
Min
Min
-
+
Max
Max
-
+
GVAR%1
VG%1
@@ -3762,126 +3847,156 @@ Vous utilisez actuellement:
-
+
Copy
Copier
-
+
Cut
Couper
-
+
Paste
Coller
-
+
Insert
Insérer
-
+
Delete
Supprimer
-
+
Move Up
Monter
-
+
Move Down
Descendre
-
+
Clear All
Effacer Tout
-
+
Clear Flight Mode. Are you sure?
Effacer la Phase de Vol. Êtes-vous sûr?
-
+
Clear all Flight Modes. Are you sure?
Effacer toutes les Phases de Vol. Êtes-vous sûr?
-
+
+ Cut Flight Mode. Are you sure?
+ Couper la Phase de Vol. Êtes-vous sûr?
+
+
+
Delete Flight Mode. Are you sure?
Supprimer la Phase de Vol. Êtes-vous sûr?
-
- Clear selected Global Variable across all Flight Modes. Are you sure?
- Effacer les Variables Globales selectionnées à travers toutes les Phases de Vol. Êtes-vous sûr?
+
+ Clear Global Variable across all Flight Modes. Are you sure?
+ Effacer la Variable Globale pour toutes les Phases de Vol. Êtes-vous sûr?
-
+
+ Clear Global Variable. Are you sure?
+ Effacer la Variable Globale. Êtes-vous sûr?
+
+
+
+ Cut Global Variable across all Flight Modes. Are you sure?
+ Couper la Variable Globale pour toutes les Phases de Vol. Êtes-vous sûr?
+
+
+
+ Cut Global Variable. Are you sure?
+ Couper la Variable Globale. Êtes-vous sûr?
+
+
+
+ Delete Global Variable. Are you sure?
+ Supprimer la Variable Globale. Êtes-vous sûr?
+
+
+
+ Paste to selected Global Variable across all Flight Modes. Are you sure?
+ Coller la Variable Globale pour toutes les Phases de Vol. Êtes-vous sûr?
+
+
+
Clear all Global Variables for all Flight Modes. Are you sure?
Effacer toutes les Variables Globales pour toutes les Phases de Vol. Êtes-vous sûr?
-
+
Clear all Global Variables for this Flight Mode. Are you sure?
Effacer toutes les Variables Globales pour cette Phase de Vol. Êtes-vous sûr?
-
+
Popup enabled
Indication activée
-
-
+
+
Popup menu available
Menu contextuel disponible
-
+
Trim disabled
Trim désactivé
-
+
Own Trim
Valeur indépendante
-
+
Use Trim from Flight mode %1
Utiliser le trim de la phase de vol %1
-
+
Use Trim from Flight mode %1 + Own Trim as an offset
Utiliser le trim de la phase de vol %1 + une valeur indépendante additionnée
-
+
0._
-
+
0.0
-
+
Clear
Effacer
@@ -3889,17 +4004,17 @@ Vous utilisez actuellement:
FlightModesPanel
-
+
Flight Mode %1
Phase de vol %1
-
+
(%1)
-
+
(default)
(par défaut)
@@ -4139,12 +4254,12 @@ p, li { white-space: pre-wrap; }
VG
-
+
Own value
Valeur indépendante
-
+
Flight mode %1 value
Valeur de la phase de vol %1
@@ -4152,7 +4267,7 @@ p, li { white-space: pre-wrap; }
GeneralEdit
-
+
Setup
Configuration
@@ -4169,57 +4284,57 @@ These will be relevant for all models in the same EEPROM.
Communs à tous les modèles d'une même EEPROM.
-
+
Trainer
Écolage
Store calib. and hw settings in selected profile
- Sauver étalonnage et paramètres hw dans profil
+ Sauver paramètres Radio dans profil
Retrieve calib. and hw settings from profile
- Lire étalonnage et paramètres hw du profil
+ Lire paramètres Radio depuis profil
-
+
Global Functions
Fonctions globales
-
+
Hardware
Matériel
-
+
Calibration
-
+
Wrong data in profile, radio calibration was not retrieved
Données du profil erronnées, l'étalonnage n'a pas été lu
-
+
Wrong data in profile, Switch/pot config not retrieved
Données incorecte, Interrupteurs/Pot non trouvés
-
+
Wrong data in profile, hw related parameters were not retrieved
Données du profil erronnées, les paramètres hw n'ont pas été lus
-
+
Do you want to store calibration in %1 profile<br>overwriting existing calibration?
Voulez-vous stocker l'étalonnage dans le profil %1<br> et écraser l'étalonnage existant ?
-
+
Calibration and HW parameters saved.
Etalonnage et paramètres hw enregistrés avec succès.
@@ -4227,7 +4342,7 @@ Communs à tous les modèles d'une même EEPROM.
GeneralSettings
-
+
Radio Settings
Paramètres de la radio
@@ -4285,169 +4400,169 @@ Communs à tous les modèles d'une même EEPROM.
-
+
Timeshift from UTC
Décalage horaire (UTC)
-
+
Voice Language
Langue des voix
-
+
Country Code
Zone géographique RF
-
+
Stick reverse
Inversion des manches
-
+
FAI Mode
Mode FAI
-
+
Adjust RTC
Ajuster l'heure par GPS
-
+
Vario pitch at max
Tonalité du vario au max
-
-
+
+
Hz
-
+
Speaker Volume
Volume haut-parleur
-
+
Backlight Switch
Inter de rétroéclairage
-
+
Sound Mode
Mode Son
-
+
Color 1
Couleur 1
-
+
Color 2
Couleur 2
-
+
Speaker Pitch (spkr only)
Tonalité (HP uniquement)
-
+
If this value is not 0, any keypress will turn on the backlight and turn it off after the specified number of seconds.
Si cette valeur est différente de 0, l'appui sur une touche de navigation déclenche le rétroéclairage qui s'éteint après la durée spécifiée (en secondes).
-
-
-
+
+
+
sec
-
+
Backlight color
Couleur du rétroéclairage
-
+
Beeper
Bipeur
-
+
Speaker
Haut-parleur
-
+
BeeperVoice
Bipeur/Voix
-
+
SpeakerVoice
Haut-parleur/Voix
-
+
Beep volume
Volume des bips
-
+
Wav volume
Volume des fichiers audio
-
+
Vario volume
Volume du variomètre
-
+
Background volume
Volume de la musique d'ambiance
-
-
+
+
ms
-
+
Backlight Auto OFF after
Arrêt rétroéclairage après
-
+
Backlight flash on alarm
Clignotement rétroécl. alarmes
-
+
Vario pitch at zero
Tonalité du vario à 0
-
+
Vario repeat at zero
Répétition du vario à 0
-
+
This is the switch selectrion for turning on the backlight (if installed).
Interrupteur déclenchant le rétroéclairage' (si installé).
-
-
+
+
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
p, li { white-space: pre-wrap; }
@@ -4462,42 +4577,42 @@ p, li { white-space: pre-wrap; }
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Plage de valeurs: 20...45</span></p></body></html>
-
+
Backlight Brightness
Luminosité du rétroéclairage
-
+
RotEnc Navigation
Navigation sélecteur rotatif
-
+
Automatically adjust the radio's clock if a GPS is connected to telemetry.
Régle automatique l'heure de la radio si un GPS est présent.
-
+
America
Amérique
-
+
Japan
Japon
-
+
Europe
-
+
Backlight OFF Brightness
Luminosité écran éteint
-
+
Mode selection:
Mode 1:
@@ -4538,462 +4653,467 @@ Mode 4:
-
+
Mode 1 (RUD ELE THR AIL)
Mode 1 (DIR PRF GAZ AIL)
-
+
Mode 2 (RUD THR ELE AIL)
Mode 2 (DIR GAZ PRF AIL)
-
+
Mode 3 (AIL ELE THR RUD)
Mode 3 (AIL PRF GAZ DIR)
-
+
Mode 4 (AIL THR ELE RUD)
Mode 4 (AIL GAZ PRF DIR)
-
+
<html><head/><body><p>Channel order</p><p><br/></p><p>Defines the order of the default mixes created on a new model.</p></body></html>
<html><head/><body><p>Ordre des voies</p><p><br/></p><p>Détermine l'ordre des mixages par défaut sur un nouveau modèle.</p></body></html>
-
+
If you enable FAI, only RSSI and RxBt sensors will keep working. This function cannot be disabled by the radio.
Si vous activez l'option FAI, seuls les capteurs RSSI et BtRx vont fonctionner. Cette fonction ne peut pas être désactivée sur la radio.
-
+
Owner Registration ID
Enregistrement ID du propriétaire
-
+
+ Keys Backlight
+ Rétroéclairage des touches
+
+
+
R E T A
D P G A
-
+
R E A T
D P A G
-
+
R T E A
D G P A
-
+
R T A E
D G A P
-
+
R A E T
D A P G
-
+
R A T E
D A G P
-
+
E R T A
P D G A
-
+
E R A T
P D A G
-
+
E T R A
P G D A
-
+
E T A R
P G A D
-
+
E A R T
P A D G
-
+
E A T R
P A G D
-
+
T R E A
G D P A
-
+
T R A E
G D A P
-
+
T E R A
G P D A
-
+
T E A R
G P A D
-
+
T A R E
G A D P
-
+
T A E R
G A P D
-
+
A R E T
A D P G
-
+
A R T E
A D G P
-
+
A E R T
A P D G
-
+
A E T R
A P G D
-
+
A T R E
A G D P
-
+
A T E R
A G P D
-
+
+ Battery warning voltage.
+This is the threashhold where the battery warning sounds.
+
+Acceptable values are 3v..12v
+ Tension d'alerte de batterie.
+Seuil auquel se déclenche l'alarme de batterie.
+
+Plage de valeurs: 3v...12v
+
+
+
Power Off Delay
Délai mise hors tension
-
+
USB Mode
Mode USB
-
+
Jack Mode
Mode Jack
-
+
Audio
-
+
Trainer
Écolage
-
-
+
+
Ask on Connect
Demander à la connexion
-
+
Joystick (HID)
-
+
USB Mass Storage
Stockage USB (SD)
-
+
USB Serial (CDC)
Port série USB (Debug)
-
+
Stick Mode
Mode
-
+
Metric
Métrique
-
+
Imperial
Impérial
-
+
Default Channel Order
Ordre des voies par défaut
-
+
GPS Coordinates
Coordonnées GPS
-
+
Min
-
-
+
+
v
-
+
Max
-
+
RSSI Poweroff Warning
Vérifier RSSI à l'extinction
-
+
DMS
-
+
Inactivity Timer
Alerte d'inactivité
-
+
Show Splash Screen on Startup
Afficher l'écran de démarrage
-
+
Contrast
Contraste
-
+
Battery Meter Range
Plage de l'indicateur de batterie
-
+
Haptic Strength
Puissance vibreur
-
+
LCD Display Type
Type de LCD
-
+
"No Sound" Warning
Alerte "son coupé"
-
+
Battery Warning
Alerte batterie
-
+
Haptic Length
Durée vibreur
-
+
MAVLink Baud Rate
Baudrate Mavlink
-
-
+
+
Quiet
Mode silencieux
-
+
Only Alarms
Seulement les alarmes
-
-
+
+
No Keys
Touches silencieuses
-
-
+
+
All
Tous
-
- Battery warning voltage.
-This is the threashhold where the battery warning sounds.
-
-Acceptable values are 5v..10v
- Tension d'alerte de batterie.
-Seuil auquel se déclenche l'alarme de batterie.
-
-Plage de valeurs: 5v...10v
-
-
-
+
Standard
-
+
Optrex
-
+
If not zero will sound beeps if the transmitter has been left without inputs for the specified number of minutes.
Si différent de 0, émission d'un bip sonore régulier si aucune action n'a été effectuée sur l'émetteur depuis le temps spécifié (en minutes).
Réinitialisation en agissant sur n'importe lequel des manches / touches de navigation.
-
+
nnnnnnNN
-
+
min
-
+
Power On Delay
Délai mise sous tension
-
-
+
+
Show splash screen on startup
Affiche l'écran d'accueil au démarrage
-
+
---
-
+
2s
-
+
3s
-
+
4s
-
+
6s
-
+
8s
-
+
10s
-
+
15s
-
+
4800 Baud
-
+
9600 Baud
-
+
14400 Baud
-
+
19200 Baud
-
+
38400 Baud
-
+
57600 Baud
-
+
76800 Baud
-
+
115200 Baud
-
-
-
+
+
+
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
p, li { white-space: pre-wrap; }
@@ -5018,72 +5138,72 @@ p, li { white-space: pre-wrap; }
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Alerte mode silencieux - Avertissement si les bips sont désactivés</p></body></html>
-
-
+
+
X-Short
Très court
-
-
+
+
Short
Court
-
-
+
+
Normal
-
-
+
+
Long
-
-
+
+
X-Long
Très long
-
+
Low EEPROM Warning
Avertissement EEPROM faible
-
+
NMEA
-
+
Play Delay (switch mid position)
Délai position centrale inters
-
+
Measurement Units
Unités de mesure
-
+
Haptic Mode
Mode du vibreur
-
+
Beeper Length
Durée des bips
-
+
Beeper Mode
Paramètre des bips
-
+
Beeper volume
0 - Quiet. No beeps at all.
@@ -5100,7 +5220,7 @@ Long : bips plus longs.
Extra long : bips extra longs.
-
+
Alarms Only
Seulement les Alarmes
@@ -5108,127 +5228,127 @@ Extra long : bips extra longs.
GeneralSetupPanel
-
+
OFF
-
+
Keys
Touches
-
+
Sticks
Manches
-
+
Keys + Sticks
Touches + manches
-
+
ON
-
+
English
Anglais
-
+
Dutch
Hollandais
-
+
French
Français
-
+
Italian
Italien
-
+
German
Allemand
-
+
Czech
Tchèque
-
+
Slovak
Slovaque
-
+
Spanish
Espagnol
-
+
Polish
Polonais
-
+
Portuguese
Portugais
-
+
Swedish
Suédois
-
+
Hungarian
Hongrois
-
+
Russian
Russe
-
+
No
Non
-
+
RotEnc A
Sel.Rot. A
-
+
Rot Enc B
Sel.Rot. B
-
+
Rot Enc C
Sel.Rot. C
-
+
Rot Enc D
Sel.Rot. D
-
+
Rot Enc E
Sel.Rot. E
-
+
If you enable FAI, only RSSI and RxBt sensors will keep working.
This function cannot be disabled by the radio.
Are you sure ?
@@ -5263,252 +5383,257 @@ Cette fonction ne peut pas être désactivée sur la radio.
Formulaire
-
+
SQ
-
+
SR
-
+
LS2
-
+
SP
-
+
SO
-
+
S4
-
+
RS
-
+
SB
-
+
PPM 2
-
+
Antenna
Antenne
-
+
OFF
Eteint
-
+
S-Port Mirror
Recopie S. Port
-
+
Telemetry
Télémetrie
-
+
SBUS Trainer
Écolage SBUS
-
+
Debug
Débogage
-
+
RTC Batt Check
Vérif Batterie RTC
-
+
+ S.Port Power
+ Alimentation S.Port
+
+
+
S5
-
+
Rud
Dir
-
+
PPM 3
-
+
S1
-
+
S2
-
+
S3
-
+
PPM 1
-
+
Serial Port
Port série
-
+
v
-
+
PPM Multiplier
Coeff. multiplicateur PPM
-
+
Current Offset
Correction courant
-
+
PPM 4
-
+
SA
-
+
Ele
Prf
-
+
Ail
Ail
-
+
Thr
Gaz
-
+
SC
-
+
LS
-
+
SD
-
+
Battery Offset
Correction tension
-
+
SE
-
+
SF
-
+
SG
-
+
SH
-
+
SI
-
+
SJ
-
+
SK
-
+
SL
-
+
SM
-
+
SN
-
+
RS2
-
+
Bluetooth
-
+
ADC Filter
Filtre ADC
-
+
Device Name:
Nom de l'appareil:
@@ -5517,8 +5642,8 @@ Cette fonction ne peut pas être désactivée sur la radio.
HardwarePanel
-
-
+
+
None
Aucun
@@ -5538,67 +5663,67 @@ Cette fonction ne peut pas être désactivée sur la radio.
3 Positions
-
+
Pot with detent
Potentiomètre avec centre
-
+
Multipos switch
Inter multiposition
-
+
Pot without detent
Potentiomètre sans centre
-
+
Slider with detent
Curseur avec centre
-
+
OFF
-
+
Enabled
Activé
-
+
Telemetry
Télémétrie
-
+
Trainer
Écolage
-
+
Internal
Interne
-
+
Ask
Demander
-
+
Per model
Par modèle
-
+
Internal + External
Interne + Externe
-
+
External
Externe
@@ -5653,12 +5778,12 @@ Cette fonction ne peut pas être désactivée sur la radio.
Long. cyc
- Cyc. longitudinal
+ Cyclique longitudinal
Lateral cyc
- Cyc. latéral
+ Cyclique latéral
@@ -5724,172 +5849,177 @@ Cette fonction ne peut pas être désactivée sur la radio.
InputsPanel
-
-
-
+
+
+
Move Up
Monter
-
-
+
+
Ctrl+Up
Ctrl+Haut
-
-
-
+
+
+
Move Down
Descendre
-
-
+
+
Ctrl+Down
Ctrl+Bas
-
+
Clear All Inputs
Effacer toutes les entrées
-
+
Not enough available Inputs!
Pas assez d'Entrées disponibles!
-
- Delete selected Inputs. Are you sure?
- Supprimer les Entrées selectionnés. Êtes-vous sûr?
+
+ Delete selected Input lines. Are you sure?
+ Supprimer les lignes Entrée sélectionnées. Êtes-vous sûr?
-
+
+ Cut selected Input lines. Are you sure?
+ Couper les lignes Entrée sélectionnées. Êtes-vous sûr?
+
+
+
Lines
Linéaire
-
+
&Add
&Ajouter
-
+
Ctrl+A
Ctrl+A
-
+
&Edit
&Édition
-
+
Enter
Entrée
-
+
&Delete
&Supprimer
-
-
+
+
Delete
Supprimer
-
+
&Copy
&Copier
-
+
Ctrl+C
-
+
&Cut
&Couper
-
+
Ctrl+X
-
+
&Paste
&Coller
-
+
Ctrl+V
-
+
Du&plicate
Du&pliquer
-
+
Ctrl+U
-
+
Input
Entrée
-
+
Insert
Insérer
-
+
Clear
Effacer
-
+
Clear All
Effacer Tout
-
- Clear all Inputs. Are you sure?
- Effacer toutes les Entrées. Êtes-vous sûr?
+
+ Clear all Input lines. Are you sure?
+ Effacer toutes les lignes Entrée. Êtes-vous sûr?
-
- Clear Input. Are you sure?
- Effacer l'Entrée. Êtes-vous sûr?
+
+ Clear all lines for the selected Input. Are you sure?
+ Effacer toutes les lignes Entrée sélectionnées. Êtes-vous sûr?
-
- Delete Input. Are you sure?
- Supprimer l'Entrée. Êtes-vous sûr?
+
+ Delete all lines for the selected Input. Are you sure?
+ Supprimer toutes les lignes Entrée sélectionnées. Êtes-vous sûr?
LimitData
-
+
INV
-
+
NOR
-
+
CH
VOIE
@@ -5897,7 +6027,7 @@ Cette fonction ne peut pas être désactivée sur la radio.
LimitsGroup
-
+
GV
VG
@@ -6028,102 +6158,112 @@ Cette fonction ne peut pas être désactivée sur la radio.
LogicalSwitchesPanel
-
+
V1
-
+
V2
-
+
Duration
Durée
-
+
Delay
Délai
-
+
Function
Fonction
-
+
AND Switch
ET supplémentaire
-
+
Popup menu available
Menu contextuel disponible
-
+
(instant)
-
+
(infinite)
(infini)
-
+
Delete Logical Switch. Are you sure?
Supprimer l'Interrupteur Logique. Êtes-vous sûr?
-
+
+ Cut Logical Switch. Are you sure?
+ Couper l'Interrupteur Logique. Êtes-vous sûr?
+
+
+
Copy
Copier
-
+
Cut
Couper
-
+
Paste
Coller
-
+
Clear
Effacer
-
+
Insert
Insérer
-
+
Delete
Supprimer
-
+
Move Up
Monter
-
+
Move Down
Descendre
-
+
Clear All
Effacer Tout
-
+
+ Clear Logical Switch. Are you sure?
+ Effacer l'Interrupteur Logique. Êtes-vous sûr?
+
+
+
Clear all Logical Switches. Are you sure?
Effacer tous les Interrupteurs Logiques. Êtes-vous sûr?
@@ -6305,79 +6445,74 @@ Les colonnes contenant l'altitude "GAlt" et la vitesse "GSpd
MainWindow
-
-
+
+
Edit
Édition
-
-
+
+
File
Fichier
-
+
New release available
Nouvelle version disponible
-
+
Error opening file %1:
%2.
Erreur à l'ouverture du fichier %1:
%2.
-
+
Compilation server too busy, try later
Serveur de compilation surchargé, veuillez réessayer plus tard
-
+
Unknown server failure, try later
Erreur inconnue du serveur de compilation, veuillez réessayer plus tard
-
+
Do you want to write the firmware to the radio now ?
Voulez vous transférer le firmware à la radio maintenant ?
-
-
+
+
Yes
Oui
-
-
+
+
No
Non
-
-
+
+
Release Notes
Notes de version
-
+
Compare models
Comparer les modèles
-
- Show fuses dialog
- Afficher les paramètres des fusibles
-
-
-
+
A monochrome black icon theme
Thème avec icônes monochromes noires
-
+
A new version of %1 firmware is available:
- current is %2
- newer is %3
@@ -6394,511 +6529,501 @@ Voulez vous la télécharger maintenant ?
Nous recommandons de lire attentivement les notes de version à l'aide du bouton ci-dessous, celles-ci peuvent contenir des infos importantes concernant les changements effectués depuis la version précédente.
-
-
+
+
Synchronize SD
Synchroniser la carte SD
-
+
New
Nouveau
-
+
Open...
Ouvrir...
-
+
A monochrome white icon theme
Thème avec icônes monochromes blanches
-
+
A monochrome blue icon theme
Thème avec icônes monochromes bleues
-
+
Small
Petites
-
+
Use small toolbar icons
Petites icônes de barre d'outils
-
+
Use normal size toolbar icons
Icônes de barre d'outils normales
-
+
Normal
Normales
-
+
Use big toolbar icons
Grosses icônes de barre d'outils
-
+
Big
Grandes
-
+
Use huge toolbar icons
Immenses icônes de barre d'outils
-
+
Huge
Immenses
-
- List programmers...
- Lister les programmateurs...
-
-
-
- Fuses...
- Fusibles...
-
-
-
-
+
+
Read Firmware from Radio
Lire le firmware de la radio
-
+
Read firmware from Radio
Lire le firmware de la radio
-
+
Write Firmware to Radio
Transférer le firmware à la radio
-
+
Write firmware to Radio
Transférer le firmware à la radio
-
+
Add Radio Profile
Ajouter un profil de radio
-
+
Manuals and other Documents
Manuels et documents
-
+
Open the OpenTX document page in a web browser
Ouvre la page de documentation d'OpenTX dans un navigateur
-
+
Write Models and Settings To Radio
Transférer les paramètres et modèles vers la radio
-
+
Write Models and Settings to Radio
Transférer les paramètres et modèles vers la radio
-
-
+
+
Read Models and Settings from Radio
Lire les paramètres et modèles depuis la radio
-
+
OpenTX Companion %1 - Radio: %2 - Profile: %3
OpenTX Companion %1 - Radio: %2 - Profil: %3
-
+
List of recently used files
Liste des fichiers récemment utilisés
-
+
Radio Profiles
Profil radio
-
+
Create or Select Radio Profiles
Créer ou Sélectionner un profil radio
-
+
Configure Communications...
Configurer les communications...
-
+
Configure software for communicating with the Radio
Configurer le programme gérant les communications avec la radio
-
+
Write Backup to Radio
Transférer une sauvegarde à la radio
-
+
Write Backup from file to Radio
Transférer une sauvegarde à la radio
-
+
Backup Radio to File
Sauvegarder la radio
-
+
Save a complete backup file of all settings and model data in the Radio
Créer une copie de sauvegarde de tous les paramètres et modèles de la radio
-
+
Contributors...
Contributeurs...
-
+
A tribute to those who have contributed to OpenTX and Companion
Remerciements à tout ceux qui ont contribué à OpenTX et Companion
-
+
SD card synchronization
Synchronisation de la carte SD
-
+
Recent Files
Fichiers récents
-
+
Set Icon Theme
Choisir le thème d'icônes
-
+
Set Icon Size
Choisir la taille des icônes
-
+
Write
Ecrire
-
+
A new version of Companion is available (version %1)<br>Would you like to download it?
Une nouvelle version de Companion est disponible (version %1)<br>Voulez-vous la télécharger ?
-
+
OpenTX Home Page: <a href='%1'>%1</a>
Page d'accueil d'OpenTX: <a href='%1'>%1</a>
-
+
If you've found this program useful, please support by <a href='%1'>donating</a>
Si vous trouvez ce programme utile, merci de le supporter par une <a href='%1'>donation</a>
-
+
Ready
Prêt
-
+
Show the application's About box
Afficher la fenêtre "A propos" de l'application
-
-
+
+
File loaded
Fichier chargé
-
-
+
+
Open Models and Settings file
Ouvrir un fichier de paramètres et modèles
-
-
+
+
File saved
Fichier sauvegardé
-
+
Read Models and Settings From Radio
Lire les paramètres et modèles depuis la radio
-
+
Not enough flash available on this board for all the selected options
Pas assez de place disponible pour les options sélectionnées
-
+
Compilation server temporary failure, try later
Erreur de compilation sur le serveur, veuillez réessayer plus tard
-
+
Compilation error
Erreur de compilation
-
+
Invalid firmware
Firmware invalide
-
+
Invalid board
Carte non valide
-
+
Invalid language
Language non valide
-
+
Some text will not be translated until the next time you start Companion. Please note that some translations may not be complete.
Certains textes ne seront pas traduits avant le prochain redémarrage de Companion. Veuillez noter que certaines traductions peuvent ne pas être complètes.
-
+
Models and Settings read
Lecture des modèles et paramètres
-
+
Companion update check failed, new version information not found.
La vérification de mise à jour de Companion a échoué, les infos sur une nouvelle version sont introuvables.
-
+
Firmware update check failed, new version information not found or invalid.
La vérification de mise à jour du Firmware a échoué, les infos sur une nouvelle version sont introuvables ou invalides.
-
+
Local Folder
Dossier "Local"
-
+
Radio Folder
Dossier "Radio"
-
-
+
+
This function is not yet implemented
Cette fonction n'est pas implémentée pour l'instant
-
+
Save Radio Backup to File
Sauvegarder la radio
-
+
Read Radio Firmware to File
Sauvegarder le firmware de la radio
-
+
The OpenTX Companion project was originally forked from <a href='%1'>eePe</a>
Le projet OpenTX Companion a été créé à partir d'<a href='%1'>eePe</a>
-
+
Copyright OpenTX Team
-
+
Create a new Models and Settings file
Créer un nouveau fichier de paramètres et modèles
-
-
+
+
Save Models and Settings file
Enregistrer le fichier de paramètres et modèles
-
+
Save
Enregistrer
-
+
Save As...
Enregistrer sous...
-
+
Close
Fermer
-
+
Close Models and Settings file
Fermer le fichier de paramètres et modèles
-
+
Exit the application
Quitter l'application
-
+
Exit
Quitter
-
+
Create a new Radio Settings Profile
Créer un nouveau profil de paramètres et modèles
-
+
Copy Current Radio Profile
Copier le profil radio actuel
-
+
Duplicate current Radio Settings Profile
Dupliquer les paramètres radio du profil actuel
-
+
Delete the current Radio Settings Profile
Supprimer les paramètres radio du profil actuel
-
+
Use default system language.
Utiliser le langage système par défaut.
-
+
Use %1 language (some translations may not be complete).
Utiliser la langue %1 (certaines traductions peuvent être incomplètes).
-
+
Classical
Classique
-
+
Diskimage (*.dmg)
Image disque (*.dmg)
-
+
Would you like to open the disk image to install the new version?
Voulez-vous ouvrir l'image disque afin d'installer la nouvelle version ?
-
+
Executable (*.exe)
Exécutable (*.exe)
-
-
+
+
Would you like to launch the installer?
Voulez-vous lancer l'installateur ?
-
+
No Companion release candidates are currently being served for this version, please switch release channel
Aucune version "candidate" de Companion n'est actuellement disponible sur ce serveur, veuillez commuter sur le canal "officiel"
-
+
No nightly Companion builds are currently being served for this version, please switch release channel
Aucune version "nightly" de Companion n'est actuellement disponible sur ce serveur, veuillez commuter sur le canal "officiel"
-
+
No Companion release builds are currently being served for this version, please switch release channel
Aucune version "officielle" de Companion n'est actuellement disponible sur ce serveur, veuillez commuter sur le canal "candidate" ou "nightly"
-
+
A new release of Companion is available, please check the <a href='%1'>OpenTX website!</a>
Une nouvelle version de Companion est disponible, vérifiez le site OpenTX <a href='%1'> !</a>
-
+
No firmware release candidates are currently being served for this version, please switch release channel
Aucun firmware "candidate" n'est actuellement disponible sur ce serveur, veuillez commuter sur le canal "officiel"
-
+
No firmware nightly builds are currently being served for this version, please switch release channel
Aucun firmware "nightly" n'est actuellement disponible sur ce serveur, veuillez commuter sur le canal "officiel"
-
+
No firmware release builds are currently being served for this version, please switch release channel
Aucun firmware "officiel" n'est actuellement disponible sur ce serveur, veuillez commuter sur le canal "candidate" ou "nightly"
-
+
Release candidate builds are now available for this version, would you like to switch to using them?
Une version "candidate" est maintenant disponible pour cette version, voulez-vous commuter de canal afin de l'utiliser?
-
+
Channel changed to RC, please restart the download process
Canal commuté sur "candidate", veuillez redémarrer le processus de téléchargement
-
+
Official release builds are now available for this version, would you like to switch to using them?
Une version "officielle" est maintenant disponible pour cette version, voulez-vous commuter de canal afin de l'utiliser?
-
+
Channel changed to Release, please restart the download process
Canal commuté sur "officiel", veuillez redémarrer le processus de téléchargement
-
+
This radio (%1) is not currently available in this firmware release channel
Le firmware pour cette radio (%1) n'est actuellement pas disponible dans le canal "officiel"
-
+
Firmware %1 does not seem to have ever been downloaded.
Version %2 is available.
Do you want to download it now?
@@ -6911,18 +7036,18 @@ Voulez-vous le télécharger maintenant?
Nous vous recommandons de consulter les notes de mise à jour à l'aide du bouton ci-dessous pour en savoir plus sur les modifications susceptibles de vous intéresser.
-
-
+
+
Do you want to download version %1 now ?
Voulez-vous télécharger la version %1 maintenant?
-
+
Ignore this version %1?
Ignorer cette version %1?
-
+
There are unsaved file changes which you may lose when switching radio types.
Do you wish to continue?
@@ -6931,355 +7056,350 @@ Do you wish to continue?
Êtes-vous sûr de vouloir continuer ?
-
+
No local SD structure path configured!
Aucun chemin de configuré pour la structure SD en local !
-
+
No Radio or SD card detected!
Pas de Radio ou carte SD de détectée !
-
+
Release notes...
Notes de version...
-
+
Show release notes
Afficher les notes de version
-
+
Delete Current Radio Profile...
Supprimer le profil radio actuel...
-
+
Export Application Settings..
Exporter Préférences Application...
-
+
Save all the current %1 and Simulator settings (including radio profiles) to a file.
Enregistrez tous les paramètres actuels %1 et du simulateur (y compris les profils radio) dans un fichier.
-
+
Import Application Settings..
Importer les paramètres de l'application...
-
+
Load %1 and Simulator settings from a prevously exported settings file.
Charger les paramètres %1 et les paramètres de Simulation depuis un fichier précédemment exporté.
-
+
Tabbed Windows
Fenêtres à onglets
-
+
Use tabs to arrange open windows.
Utilisez les onglets pour organiser les fenêtres ouvertes.
-
+
Tile Windows
Titre de la fenêtre
-
+
Arrange open windows across all the available space.
Disposez les fenêtres ouvertes sur tout l'espace disponible.
-
+
Cascade Windows
Fenêtres en cascade
-
+
Arrange all open windows in a stack.
Organisez toutes les fenêtres ouvertes dans une pile.
-
+
Close All Windows
Fermer toutes les fenêtres
-
+
Closes all open files (prompts to save if necessary.
Fermer tous les fichiers ouverts (proposer de sauvegarder si nécessaire).
-
+
Window
Fenêtre
-
+
Ctrl+Shift+S
-
+
Ctrl+Alt+L
-
+
Ctrl+Alt+D
-
+
Ctrl+Alt+R
-
+
The classic companion9x icon theme
Thème d'icônes classique de Companion
-
+
Yerico
-
+
Yellow round honey sweet icon theme
Thème d'icônes rondes jaunes
-
+
Monochrome
-
+
MonoWhite
Monochrome Blanc
-
+
Alt+%1
-
+
- Copy
- Copier
-
+
Companion :: Open files warning
Companion::Ouvrir les fichiers d'avertissement
-
+
Please save or close modified file(s) before deleting the active profile.
Veuillez sauvegarder ou fermer le(s) fichier(s) modifié(s) avant de supprimer le profil actif.
-
+
Not possible to remove profile
Impossible de supprimer le profil
-
+
The default profile can not be removed.
Le profil par défaut ne peut pas être supprimé.
-
+
Confirm Delete Profile
Confirmer la suppression du profil
-
+
Are you sure you wish to delete the "%1" radio profile? There is no way to undo this action!
Etes-vous sûr de vouloir supprimer le profil radio %1? Cette action est irréversible!
-
+
Please save or close all modified files before importing settings
Veuillez sauvegarder ou fermer tous les fichiers modifiés avant d'importer les paramètres
-
+
<html><p>%1 and Simulator settings can be imported (restored) from a previosly saved export (backup) file. This will replace current settings with any settings found in the file.</p><p>An automatic backup of the current settings will be attempted. But if the current settings are useful then it is recommended that you make a manual backup first.</p><p>For best results when importing settings, <b>close any other %1 windows you may have open, and make sure the standalone Simulator application is not running.</p><p>Do you wish to continue?</p></html>
<html><p>%1 et les paramètres du simulateur peuvent être importés (restaurés) à partir d’un fichier d’exportation (sauvegarde) préalablement sauvegardé. Ceci remplacera les paramètres actuels par tous les paramètres trouvés dans le fichier.</p><p>Une sauvegarde automatique des paramètres actuels sera tentée. Mais si les paramètres actuels sont utiles, il est recommandé de commencer par une sauvegarde manuelle.</p><p>Pour obtenir de meilleurs résultats lors de l'importation des paramètres,<b> fermez les autres fenêtres %1 que vous avez éventuellement ouvertes et assurez-vous que l'application autonome Simulator n'est pas en cours d'exécution. </p><p>Souhaitez-vous continuer? </p></html>
-
+
Confirm Settings Import
Confirmer les paramètres d'importation
-
+
Select %1:
Sélectionnez %1:
-
+
backup
sauvegarde
-
+
Press the 'Ignore' button to continue anyway.
Appuyez sur le bouton 'Ignorer' pour continuer quand même.
-
+
The settings could not be imported.
Les paramètres n'ont pas pu être importés.
-
+
<html><p>New settings have been imported from:<br> %1.</p><p>%2 will now re-initialize.</p><p>Note that you may need to close and restart %2 before some settings like language and icon theme take effect.</p>
<html><p>Les nouveaux paramètres ont été importés depuis:<br> %1. </p><p>%2 sera maintenant réinitialisé.</p><p>Notez que vous devrez peut-être fermer et redémarrer %2 avant que certains paramètres tels que la langue et le thème d’icône prennent effet.</p>
-
+
<p>The previous settings were backed up to:<br> %1</p>
<p>Les paramètres précédents ont été sauvegardés sous:<br> %1 </p>
-
+
MonoBlue
Monochrome Bleu
-
+
System language
Langue du système
-
+
About...
A propos...
-
+
View Log File...
Ouvrir un Log...
-
+
Open and view log file
Ouvrir et visualiser un log
-
+
Settings...
Préférences...
-
+
Edit Settings
Éditer les préférences
-
+
Download...
Télécharger...
-
+
Download firmware and voice files
Télécharger firmware et fichiers son
-
+
Check for Updates...
Vérifier les mises à jour...
-
+
Check OpenTX and Companion updates
Vérifier les mises à jour d'OpenTX et Companion
-
+
Compare Models...
Comparer 2 modèles...
-
+
Edit Radio Splash Image...
Éditer l'écran d'accueil de la radio...
-
+
Edit the splash image of your Radio
Éditer l'écran d'accueil de la radio
-
- List available programmers
- Lister les programmateurs supportés
-
-
-
-
+
+
Save As
Enregistrer Sous
-
-
+
+
No updates available at this time.
Aucune mise à jour disponible.
-
-
+
+
Help
Aide
-
+
Checking for updates
Recherche de mises à jour
-
+
The new theme will be loaded the next time you start Companion.
Le nouveau thème sera utilisé lors du prochain lancement de Companion.
-
+
About Companion
A propos de Companion
-
+
Set Menu Language
Choisir la langue des menus
-
+
Settings
Paramètres
-
+
Read/Write
Transfert
-
+
%2
-
+
New Radio
Nouvelle radio
@@ -7406,7 +7526,7 @@ Do you wish to continue?
Edit Radio Settings
- Éditer paramètres radio
+ Éditer Paramètres Radio
@@ -7421,7 +7541,7 @@ Do you wish to continue?
Simulate Radio
- Simuler radio
+ Simuler Radio
@@ -7668,12 +7788,12 @@ Enregistrer les changements ?
MixData
-
+
MIX
-
+
(@%1)
@@ -7870,27 +7990,27 @@ Mixage actif par défaut si non-renseigné.
Nom
-
+
DEST -> %1
-
+
Click to access popup menu
Cliquez pour accéder au menu contextuel
-
+
Clear All
Effacer Tout
-
+
Set All
Définir Tout
-
+
Invert All
Inverser Tout
@@ -7902,7 +8022,7 @@ Mixage actif par défaut si non-renseigné.
Flight modes
- Phases de vol
+ Phases de Vol
@@ -7936,131 +8056,136 @@ Mixage actif par défaut si non-renseigné.
MixesPanel
-
-
+
+
Move Up
Monter
-
-
+
+
Ctrl+Up
Ctrl+Haut
-
-
+
+
Move Down
Descendre
-
-
+
+
Ctrl+Down
Ctrl+Bas
-
+
Clear Mixes
Effacer tous les mixages
-
+
Not enough available mixers!
Plus de mixages disponibles !
-
- Delete Selected Mixes?
- Supprimer les mixages sélectionnés ?
+
+ Delete selected Mix lines. Are you sure?
+ Supprimer les lignes Mixeur sélectionnées. Êtes-vous sûr?
-
+
+ Cut selected Mix lines. Are you sure?
+ Couper les lignes Mixeur sélectionnées. Êtes-vous sûr?
+
+
+
&Add
&Ajouter
-
+
Ctrl+A
-
+
&Edit
&Édition
-
+
Enter
Entrée
-
+
Ctrl+T
-
+
&Toggle highlight
&(Dé)sélectionner
-
+
&Delete
&Supprimer
-
+
Delete
Supprimer
-
+
&Copy
&Copier
-
+
Ctrl+C
-
+
Ctrl+X
-
+
C&ut
&Couper
-
+
&Paste
&Coller
-
+
Ctrl+V
-
+
Du&plicate
&Dupliquer
-
+
Ctrl+U
-
+
Clear Mixes?
Effacer tous les mixages ?
-
+
Really clear all the mixes?
Êtes-vous sûr de vraiment vouloir effacer tous les mixages ?
@@ -8068,15 +8193,20 @@ Mixage actif par défaut si non-renseigné.
ModelData
-
+
Model:
Modèle:
-
+
Throttle Source
Source des gaz
+
+
+ THR
+ GAZ
+
ModelEdit
@@ -8086,32 +8216,32 @@ Mixage actif par défaut si non-renseigné.
Simulation
-
+
Heli
- Paramètres hélico
+ Paramètres Hélico
-
+
Inputs
Entrées
-
+
Mixes
Mixages
-
+
Logical Switches
- Inters logiques
+ Inters Logiques
-
+
Setup
Configuration
-
+
Curves
Courbes
@@ -8121,22 +8251,22 @@ Mixage actif par défaut si non-renseigné.
Dialogue
-
+
Flight Modes
- Phases de vol
+ Phases de Vol
-
+
Outputs
Sorties
-
+
Special Functions
- Fonctions spéciales
+ Fonctions Spéciales
-
+
Telemetry
Télémesure
@@ -8174,27 +8304,27 @@ Mixage actif par défaut si non-renseigné.
Inconnu
-
+
Slave/Jack
Elève/Jack
-
+
Master/SBUS Module
Maître/SBUS module
-
+
Master/CPPM Module
Maître/CPPM Module
-
+
Master/SBUS in battery compartment
Maître/SBUS compartiment batterie
-
+
Master/Jack
Maître/Jack
@@ -8235,9 +8365,8 @@ Mixage actif par défaut si non-renseigné.
-
-
-
+
+
OFF
@@ -8248,7 +8377,7 @@ Mixage actif par défaut si non-renseigné.
-
+
Mode
@@ -8282,14 +8411,13 @@ Mixage actif par défaut si non-renseigné.
-
-
+
Delay
Délai
-
+
Receiver
Récepteur
@@ -8315,581 +8443,362 @@ Mixage actif par défaut si non-renseigné.
+
RF Output Power
Puissance RF
-
+
+ Output Type
+ Type de sortie
+
+
+
+ RX Output Frequency
+ Fréquence de sortie du RX
+
+
+
90
-
+
120
-
+
120X
-
+
140
-
+
+
+ Weight(%1)
+ Ratio(%1)
+
+
+
+
+ Switch(%1)
+ Inter(%1)
+
+
+
MULT!
-
-
- Offset
- Décalage
+
+ Delay(u%1:d%2)
+ Délai(h%1:b%2)
-
- Slow
- Ralenti
+
+ Slow(u%1:d%2)
+ Ralenti(h%1:b%2)
-
- Warn
- Attn
+
+ Warn(%1)
+ Alerte(%1)
-
+
Flight modes
- Phases de vol
+ Phases de Vol
-
+
Flight mode
Phase de vol
-
+
All
Tous
-
+
Edge
Flanc
-
+
Sticky
Bistable
-
+
Timer
Chrono
-
+
missing
absent
-
+
Duration
Durée
-
+
Extended Limits
Limites étendues
-
+
Display Checklist
Afficher la checklist
-
+
Global Functions
Fonctions globales
-
+
Manual
Manuel
-
+
Auto
-
+
Failsafe Mode
Mode Failsafe
-
-
+
+
Hold
Maintien
-
+
No Pulse
Pas d'impulsion
-
+
Not set
Non défini
-
+
No pulses
Pas d'impulsions
-
- Silent
- Aucun
-
-
-
- Beeps
- Bips
-
-
-
- Voice
- Voix
-
-
-
- Haptic
- Vibreur
-
-
-
- Flight
- Vol
-
-
-
- Manual reset
- RAZ manuelle
-
-
-
+
Step
Pas
-
+
Display
Affichage
-
+
Extended
Étendu
-
+
Never
Jamais
-
+
On Change
Sur changement
-
+
Always
Toujours
-
-
-
+
+
+
Source
-
+
Trim idle only
Trim ralenti uniquement
-
+
Warning
Avertissement
-
+
Reversed
Inversé
-
- Tmr
- Chrono
-
-
-
+
FrSky S.PORT
-
+
FrSky D
-
+
FrSky D (cable)
FrSky D (câble)
-
+
Alti
Alt
-
+
Alti+
Alt+
-
+
VSpeed
Vitesse verticale
-
-
-
+
+
+
A1
-
-
-
+
+
+
A2
-
-
+
+
A3
-
-
+
+
A4
-
-
+
+
FAS
-
+
Cells
Velm
-
- Calculated
- Calculé
-
-
-
- Add
- Addition
-
-
-
- Average
- Moyenne
-
-
-
-
+
Min
-
-
+
Max
-
- Multiply
- Multiplication
-
-
-
- Totalise
-
-
-
-
- Cell
- Element LiPo
-
-
-
- Consumption
- Consommation
-
-
-
- Distance
-
-
-
-
- Lowest
- Min
-
-
-
- Cell %1
- Elém. %1
-
-
-
- Highest
- Max
-
-
-
- Delta
-
-
-
-
- Formula
- Formule
-
-
-
-
- Id
-
-
-
-
- Instance
-
-
-
-
-
-
-
- Sensor
- Capteur
-
-
-
-
- Sources
-
-
-
-
-
- GPS
-
-
-
-
- Alt.
-
-
-
-
-
- Blades
- Pales
-
-
-
- Multi.
-
-
-
-
- F
-
-
-
-
- Inst
-
-
-
-
- Alt
- Altitude
-
-
-
- Unit
- Unité
-
-
-
- Prec
-
-
-
-
- Ratio
-
-
-
-
- Multi
-
-
-
-
- A/Offset
-
-
-
-
- Filter
- Filtre
-
-
-
- Persist
-
-
-
-
- Positive
-
-
-
-
- Log
-
-
-
-
+
Numbers
Chiffres
-
+
Bars
Barres
-
+
Script
-
+
Filename
Nom de fichier
-
+
Error: Unable to open or read file!
Erreur: Impossible d'ouvrir ou de lire le fichier!
-
- Persistent
- Persistant
-
-
-
+
Off
-
-
-
-
-
-
+
+
+
+
+
None
Aucun
-
- Name
- Nom
-
-
-
- Countdown
- Compte à rebours
-
-
-
- Minute call
- Annonces minutes
-
-
-
-
-
+
+
+
FM%1
PV%1
-
+
FM%1%2
PV%1%2
-
+
FM%1+%2
PV%1+%2
-
-
- Weight
- Ratio
-
-
-
-
- Switch
- Inter
-
-
-
-
+
+
NoTrim
Pas de trim
-
+
No DR/Expo
Pas d'expo/DR
-
+
+
Offset(%1)
Décalage(%1)
@@ -8904,24 +8813,23 @@ Mixage actif par défaut si non-renseigné.
-
+
Disabled in all flight modes
Désactivé pour toutes les phases de vol
-
+
instant
immédiat
-
-
-
+
+
Custom
Prédéfini
-
+
Standard
@@ -8957,7 +8865,7 @@ Mixage actif par défaut si non-renseigné.
Module
-
+
Failsafe Mode
Mode Failsafe
@@ -8967,241 +8875,251 @@ Mixage actif par défaut si non-renseigné.
1ère voie
-
+
PPM delay
Impulsion
-
+
Negative
Négative
-
+
Positive
-
+
Polarity
Polarité
-
+
Trainer Mode
Mode écolage
-
+
PPM Frame Length
Longueur de trame PPM
-
+
CH
VOIE
-
+
Antenna
Antenne
-
+
Option value
-
+
us
µs
-
+
Master/Jack
Maître/Jack
-
+
Slave/Jack
Elève/Jack
-
+
Master/SBUS Module
Maître/SBUS module
-
+
Master/CPPM Module
Maître/CPPM Module
-
+
Master/SBUS in battery compartment
Maître/SBUS dans compartiment batterie
-
+
RF Output Power
Puissance RF
-
+
Sub Type
Sous-Type
-
+
Master/Bluetooth
Maître/Bluetooth
-
+
Slave/Bluetooth
Elève/Bluetooth
-
+
Master/Multi
Maître/Multi
-
+
Disable Telemetry
Désactiver la télémétrie
-
+
Disable Ch. Map
Désactiver "Mapping" des VOIES
-
+
Show values in:
Afficher les valeurs en:
-
+
%
abbreviation for percent
-
+
μs
abbreviation for microseconds
-
+
ms
-
+
Receiver 1
Récepteur 1
-
-
-
+
+
+
X
-
+
Receiver 2
Récepteur 2
-
+
Receiver 3
Récepteur 3
-
+
WARNING: changing RF Output Power needs RE-BIND
ATTENTION: RE-BIND nécessaire pour tout changement de puissance RF
-
+
Channels
Nb de voies
-
+
+ RX Frequency
+ Fréquence RX
+
+
+
+ Hz
+
+
+
+
Not set
Non défini
-
+
Hold
Maintien
-
+
Custom
Prédéfini
-
+
No Pulses
Pas d'impulsions
-
+
Receiver
Récepteur
-
+
WARNING: Requires non-certified firmware!
ATTENTION: Nécessite un firmware non certifié!
-
+
Registration ID
ID d'enregistrement
-
+
Failsafe Positions
Positions Failsafe
-
+
Protocol
Protocole
-
+
Multi Radio Protocol
Protocole Multi
-
+
Receiver No.
Récepteur No.
-
+
Output type
Type de sortie
-
+
Open Drain
-
+
Push Pull
-
+
Low Power
Puissance Réduite
@@ -9209,131 +9127,151 @@ Mixage actif par défaut si non-renseigné.
ModuleData
-
+
Positive
-
+
Negative
Négative
-
+
Trainer Port
Port écolage
-
+
Internal Radio System
Module HF interne
-
+
External Radio Module
Module HF externe
-
+
Extra Radio System
Module HF supplémentaire
-
+
Radio System
Module HF
-
+
10mW - 16CH
10mW - 16 VOIES
-
-
+
+
100mW - 16CH
100mW - 16 VOIES
-
+
500mW - 16CH
500mW - 16 VOIES
-
+
Auto <= 1W - 16CH
Auto <= 1W - 16 VOIES
-
-
+
+
25mW - 8CH
25mW - 8 VOIES
-
-
+
+
25mW - 16CH
25mW - 16 VOIES
-
+
200mW - 16CH (no telemetry)
200mW - 16 VOIES (pas de télémétrie)
-
+
500mW - 16CH (no telemetry)
500mW - 16 VOIES (pas de télémétrie)
-
+
100mW - 16CH (no telemetry)
100mW - 16 VOIES (pas de télémétrie)
+
+
+ 25 mW
+
+
+
+
+ 100 mW
+
+
+
+
+ 500 mW
+
+
+
+
+ 1 W
+
+
+
+
+ 2 W
+
+
ModulePanel
-
+
Value
Valeur
-
+
Hold
Maintien
-
+
No Pulse
Pas d'impulsion
-
+
Ask
Demander
-
+
Internal
Interne
-
+
Internal + External
Interne + Externe
-
+
External
Externe
-
-
- Autodetect Format
- Format Détection auto
-
Bind on channel
@@ -9343,132 +9281,127 @@ Mixage actif par défaut si non-renseigné.
MultiModelPrinter
-
+
Input
Entrée
-
+
Weight
Ratio
-
+
Long. cyc
- Cyc. longitudinal
+ Cyclique longitudinal
-
+
Lateral cyc
- Cyc. latéral
+ Cyclique latéral
-
+
Collective
Source du pas collectif
-
+
Flight modes
- Phases de vol
+ Phases de Vol
-
-
+
+
Flight mode
Phase de vol
-
-
+
+
Switch
Inter
-
-
+
+
GV%1
VG%1
-
+
RE%1
-
+
Channel
Voie
-
+
Direct
-
+
Curve
Courbe
-
+
PPM
-
+
Linear
Linéaire
-
+
Telemetry
Télémétrie
-
- Offset
- Décalage
-
-
-
-
+
+
Min
-
+
Timers
Chronos
-
+
Time
Temps
-
+
Countdown
Compte à rebours
-
+
Modules
-
+
Outputs
Sorties
-
+
Subtrim
Subtrim
-
-
+
+
Max
@@ -9479,312 +9412,270 @@ Mixage actif par défaut si non-renseigné.
-
-
+
+
Name
Nom
-
+
EEprom Size
Taille EEPROM
-
+
Model Image
Image du modèle
-
+
Throttle
Gaz
-
+
Trims
-
+
Center Beep
Bip Centrer
-
+
Switch Warnings
Positions des interrupteurs
-
+
Pot Warnings
Positions des potentiomètres
-
+
Other
Autre
-
+
Min.call
Annonces minutes
-
+
Persist
Persistant
-
+
+ Start
+ Démarrer
+
+
+
Trainer port
Port écolage
-
+
Helicopter
Hélicoptère
-
+
Swash
Cyclique
-
-
+
+
Type
-
+
Ring
Plateau
-
+
F.In
Fondu en entrée
-
+
F.Out
Fondu en sortie
-
+
Global vars
Variables globales
-
+
Prec
-
+
Popup
-
+
Global Variables
Variables globales
-
+
Inputs
Entrées
-
+
Mixers
Mixages
-
+
Curves
Courbes
-
+
L%1
-
+
Logical Switches
- Inters logiques
+ Inters Logiques
-
+
SF%1
FS%1
-
+
Special Functions
- Fonctions spéciales
+ Fonctions Spéciales
-
+
Protocol
Protocole
-
+
Low
Faible
-
+
Critical
Critique
-
+
Telemetry audio
Audio télémétrie
-
+
Altimetry
Altimétrie
-
-
+
+
Vario source
Source vario
-
+
Vario limits >
Limites vario >
-
+
Sink max
Chute max
-
+
Sink min
Chute min
-
+
Climb min
Pompe min
-
+
Climb max
Pompe max
-
+
Center silent
Silence centrer
-
+
Top Bar
Barre de titre de l'écran d'accueil
-
-
+
Volts source
Source de la tension
-
+
Altitude source
Source de l'altitude
-
- Various
- Divers
-
-
-
- Serial protocol
- Protocole série
-
-
-
- FAS offset
- Décalage FAS
-
-
-
- mAh count
- Compteur mAh
-
-
-
- Persistent mAh
- Mémorisation des mAh
-
-
-
- Current source
- Source de mesure de courant
-
-
-
- Blades
- Pales
-
-
-
+
Parameters
Paramètres
-
+
Telemetry Sensors
Capteurs Télémétrie
-
+
Telemetry Screens
Écrans Télémétrie
-
+
GF%1
FG%1
-
+
Global Functions
Fonctions globales
-
+
Checklist
-
- Analogs
- Analogiques
-
-
-
-
+
Unit
Unité
-
- Scale
- Echelle
-
-
-
+
RSSI Alarms
Alarmes RSSI
@@ -9808,13 +9699,13 @@ Mixage actif par défaut si non-renseigné.
- Telemetry
- Télémetrie
+ RF power
+ Puissance HF
- Radio output power
- Puissance de sortie
+ Telemetry
+ Télémetrie
@@ -9863,22 +9754,22 @@ Mixage actif par défaut si non-renseigné.
OpenTxEepromInterface
-
+
Unknown error
Erreur inconnue
-
+
... plus %1 errors
... plus %1 erreurs
-
+
Cannot write radio settings
Impossible d'écrire les paramètres de la radio
-
+
Cannot write model %1
Impossible d'écrire le modèle %1
@@ -10026,12 +9917,12 @@ Mixage actif par défaut si non-renseigné.
QObject
-
+
WARNING
ATTENTION
-
+
<p>Importing JumperTX data into OpenTX 2.3 is <b>not supported and dangerous.</b></p> <p>It is unfortunately not possible for us to differentiate JumperTX data from legitimate FrSky X10 data, but <b>You should only continue here if the file you opened comes from a real FrSky X10.</b></p> <p>Do you really want to continue?</p>
<p>L'importation de données JumperTX dans OpenTX 2.3 est <b> non prise en charge et dangereuse.</b></p> <p>Il n'est malheureusement pas possible pour nous de différencier les données JumperTX des données légitimes FrSky X10, donc <b>Vous devez continuer uniquement si le fichier que vous avez ouvert provient d’une véritable radio FrSky X10.</b></p> <p>Voulez-vous vraiment continuer?</p>
@@ -10039,7 +9930,7 @@ Mixage actif par défaut si non-renseigné.
RadioData
-
+
Models
Modeles
@@ -10145,25 +10036,20 @@ Mixage actif par défaut si non-renseigné.
RadioInterface
-
+
Cannot write file %1:
%2.
Impossible d'écrire le fichier %1:
%2.
-
- <b><u>WARNING!</u></b><br>This will reset the fuses of %1 to the factory settings.<br>Writing fuses can mess up your radio.<br>Do this only if you are sure they are wrong!<br>Are you sure you want to continue?
- <b><u>AVERTISSEMENT !</u></b><br>Ceci réinitialisera les fusibles %1 à leur valeur par défaut.<br>Modifier les fusibles peut entraîner le blocage de votre émetteur.<br>Ne l'effectuer que si vous êtes certain qu'ils sont incorrects !<br>Etes-vous sûr de vouloir continuer ?
-
-
-
-
+
+
Could not delete temporary file: %1
Impossible d'effacer le fichier temporaire %1
-
+
Unable to find radio SD card!
Impossible de trouver la carte SD de la radio!
@@ -10303,439 +10189,120 @@ E
RawSource
-
-
-
-
+
V
-
-
-
-
+
+
s
-
- ft
-
-
-
-
-
- m
-
-
-
-
- °C
-
-
-
-
- °
-
-
-
-
- %
-
-
-
-
-
- mph
-
-
-
-
-
- km/h
-
-
-
-
- m/s
-
-
-
-
- A
-
-
-
-
- mAh
-
-
-
-
- W
-
-
-
-
- g
-
-
-
-
+
TrmR
TrmD
-
+
TrmE
TrmP
-
+
TrmT
TrmG
-
+
TrmA
TrmA
-
+
Trm5
-
+
Trm6
-
+
TrmH
-
+
TrmV
-
-
+
Batt
-
-
+
Time
Temps
-
-
+
Timer1
Chrono 1
-
-
+
Timer2
Chrono 2
-
-
+
Timer3
Chrono 3
-
- RSSI Tx
-
-
-
-
- RSSI Rx
-
-
-
-
- RAS
-
-
-
-
- A1
-
-
-
-
- A2
-
-
-
-
- A3
-
-
-
-
- A4
-
-
-
-
- Alt
- Altitude
-
-
-
- Rpm
-
-
-
-
- Fuel
- Carburant
-
-
-
- T1
-
-
-
-
- T2
-
-
-
-
- Speed
- Vitesse
-
-
-
- Dist
- Distance
-
-
-
- GPS Alt
- Altitude GPS
-
-
-
- Cell
- Element LiPo
-
-
-
- Cells
- Velm
-
-
-
- Vfas
- Vfas
-
-
-
- Curr
- Courant
-
-
-
- Cnsp
- Consommation
-
-
-
- Powr
- Puissance
-
-
-
- AccX
-
-
-
-
- AccY
-
-
-
-
- AccZ
-
-
-
-
- Hdg
- Cap
-
-
-
- VSpd
- Vitesse Verticale
-
-
-
- AirSpeed
- Vitesse Air
-
-
-
- dTE
-
-
-
-
- A1-
-
-
-
-
- A2-
-
-
-
-
- A3-
-
-
-
-
- A4-
-
-
-
-
- Alt-
-
-
-
-
- Alt+
-
-
-
-
- Rpm+
-
-
-
-
- T1+
-
-
-
-
- T2+
-
-
-
-
- Speed+
- Vit+
-
-
-
- Dist+
-
-
-
-
- AirSpeed+
- VitA+
-
-
-
- Cell-
- Elem-
-
-
-
- Cells-
- Velm-
-
-
-
- Vfas-
-
-
-
-
- Curr+
- Cour+
-
-
-
- Powr+
- Puis+
-
-
-
- ACC
-
-
-
-
- GPS Time
- Heure GPS
-
-
-
+
REa
-
+
REb
-
-
- ???
-
-
-
-
- ----
-
-
-
-
+
I
as in Input
E
-
+
LUA%1%2
-
+
MAX
-
+
CYC%1
-
+
TR
as in Trainer
-
+
SRC
@@ -10743,22 +10310,22 @@ E
RawSwitch
-
+
↑
-
+
↓
-
+
-
-
+
!
@@ -10927,24 +10494,6 @@ E
Notes de version d'OpenTX
-
- RepeatComboBox
-
-
- Played once, not during startup
- 1x Lu une fois, mais pas à la mise en route
-
-
-
- No repeat
- 1x Lu une fois
-
-
-
- %1s
-
-
-
RudderPage
@@ -10983,191 +10532,382 @@ E
SensorData
-
-
+
+ Raw (-)
+ Chiffres bruts (-)
+
+
+
+
V
-
+
A
-
+
mA
-
+
kts
-
+
m/s
-
+
km/h
-
+
mph
-
+
m
-
+
f
-
+
°C
-
+
°F
-
+
%
-
+
mAh
-
+
W
-
+
mW
-
+
dB
-
+
rpms
-
+
g
-
+
°
-
+
Rad
-
+
hours
heures
-
+
minutes
-
+
seconds
secondes
-
+
ml/minute
-
+
+ Hertz
+
+
+
+
+ mS
+
+
+
+
+ uS
+
+
+
+
TELE
+
+
+ Formula
+ Formule
+
+
+
+ Id
+
+
+
+
+ Instance
+
+
+
+
+
+ Sensor
+ Capteur
+
+
+
+ Sources
+
+
+
+
+ GPS
+
+
+
+
+ Alt
+ Altitude
+
+
+
+ Unit
+ Unité
+
+
+
+ Precision
+ Précision
+
+
+
+ Ratio
+
+
+
+
+ Offset
+ Décalage
+
+
+
+ Auto Offset
+
+
+
+
+ Blades
+ Pales
+
+
+
+ Multiplier
+ Multiplicateur
+
+
+
+ Filter
+ Filtre
+
+
+
+ Persist
+ Persistant
+
+
+
+ Positive
+
+
+
+
+ Log
+
+
+
+
+ Custom
+ Prédéfini
+
+
+
+ Calculated
+ Calculé
+
+
+
+ Add
+ Addition
+
+
+
+ Average
+ Moyenne
+
+
+
+ Minimum
+
+
+
+
+ Maximum
+
+
+
+
+ Multiply
+ Multiplication
+
+
+
+ Totalize
+ Totalisation
+
+
+
+ Cell
+ Element LiPo
+
+
+
+ Consumption
+ Consommation
+
+
+
+ Distance
+
+
+
+
+ Lowest
+ Min
+
+
+
+ Cell %1
+ Elément %1
+
+
+
+ Highest
+ Max
+
+
+
+ Delta
+
+
+
+
+ (default)
+ (défaut)
+
Setup
-
+
Center beep
Bip de centrage
-
+
OFF
-
+
Model Image
Image du modèle
-
+
Exponential
Exponentiel
-
+
Throttle Trim Idle Only
Trim ralenti uniquement
-
+
Timer 3
Chrono 3
-
+
Extra Fine
Extra fin
-
+
Fine
Fin
-
+
Medium
Moyen
-
+
Coarse
Grossier
-
+
Display Checklist
Afficher la checklist
-
+
Timer 2
Chrono 2
@@ -11177,97 +10917,102 @@ E
Chrono 1
-
+
Never
Jamais
-
+
On change
Au changement
-
+
Always
Toujours
-
+
Global Functions
Fonctions globales
-
+
Edit Checklist...
Éditer Checklist...
-
+
Throttle Source
Source des gaz
-
+
Trim Step
Pas des trims
-
+
Trims Display
Affichage des trims
-
+
Warnings
Avertissements
-
+
Top LCD Timer
Chrono LCD supérieur
-
+
Switch Warnings
Positions des interrupteurs
-
+
Pot Warnings
Positions des potentiomètres
-
+
Manual
Manuel
-
+
Auto
-
+
Model
Modèle
-
+
+ Throttle trim switch
+ Inter trim gaz
+
+
+
Extended Limits
Limites étendues
-
+
Extended Trims
Trims étendus
-
+
Throttle Warning
Alerte gaz
-
+
Reverse throttle operation.
If this is checked the throttle will be reversed. Idle will be forward, trim will also be reversed and the throttle warning will be reversed as well.
@@ -11278,7 +11023,7 @@ Si cette option est cochée, la voie des gaz est inversée: le ralenti est &apo
-
+
Reverse Throttle
Gaz inversés
@@ -11286,87 +11031,87 @@ Si cette option est cochée, la voie des gaz est inversée: le ralenti est &apo
SetupPanel
-
+
Popup menu available
Menu contextuel disponible
-
+
Timer %1
Chrono %1
-
- THR
- GAZ
-
-
-
+
Profile Settings
Paramètres du profil
-
+
SD structure path not specified or invalid
Chemin de la structure SD non spécifié ou invalide
-
+
Copy
Copier
-
+
Cut
Couper
-
+
Paste
Coller
-
+
Clear
Effacer
-
+
Insert
Insérer
-
+
Delete
Supprimer
-
+
Move Up
Monter
-
+
Move Down
Descendre
-
+
Clear All
Effacer Tout
-
+
Clear Timer. Are you sure?
Effacer le Chrono. Êtes-vous sûr?
-
+
Clear all Timers. Are you sure?
Effacer tous les Chronos. Êtes-vous sûr?
-
+
+ Cut Timer. Are you sure?
+ Couper le Chrono. Êtes-vous sûr?
+
+
+
Delete Timer. Are you sure?
Supprimer le Chrono. Êtes-vous sûr?
@@ -12090,62 +11835,62 @@ La valeur par défaut est configurée dans le profil radio sélectionné.Simulateur Radio (%1)
-
+
Could not determine startup data source.
Impossible de déterminer les données source.
-
+
Could not load data, possibly wrong format.
Impossible de charger les données, mauvais format.
-
+
Data Load Error
Erreur de lecture des données
-
+
Invalid startup data provided. Plese specify a proper file/path.
Données de démarrage fournies non valides. Veuillez spécifier un fichier/chemin approprié.
-
+
Simulator Startup Error
Erreur de démarrage du simulateur
-
+
Error saving data: could open file for writing: '%1'
Erreur de sauvegarde des données: impossible d'écrire le fichier '%1'
-
+
Error saving data: could not get data from simulator interface.
Erreur de sauvegarde des données: impossible de récupérer les données depuis l'interface de simulation.
-
+
An unexpected error occurred while attempting to save radio data to file '%1'.
Une erreur inattendue s'est produite lors de l'enregistrement des données radio dans le fichier '%1'.
-
+
Data Save Error
Erreur de sauvegarde des données
-
+
Cannot open joystick, joystick disabled
Impossible d'accéder au Joystick, Joystick désactivé
-
+
Radio firmware error: %1
Erreur firmware radio: %1
-
+
- Flight Mode %1 (#%2)
- Phase de Vol %1 (#%2)
@@ -12791,11 +12536,6 @@ Trop d'erreurs, abandon.
mAmps (mA)
Courant (mA)
-
-
- Range
- Plage
-
TelemetryCustomScreen
@@ -12805,22 +12545,22 @@ Trop d'erreurs, abandon.
Type d'écran personnalisé
-
+
None
Aucun
-
+
Numbers
Chiffres
-
+
Bars
Barres
-
+
Script
@@ -12848,106 +12588,54 @@ Trop d'erreurs, abandon.
TelemetryPanel
-
+
FrSky S.PORT
-
+
FrSky D
-
+
FrSky D (cable)
FrSky D (câble)
-
+
Telemetry screen %1
Ecran de télémesure %1
-
+
Source
-
+
Low Alarm
Alarme basse
-
+
Critical Alarm
Alarme critique
-
+
Winged Shadow How High
-
+
Winged Shadow How High (not supported)
Winged Shadow How High (non supporté)
-
- Alti
- Alt
-
-
-
- Alti+
- Alt+
-
-
-
- VSpeed
- Vitesse verticale
-
-
-
-
-
- A1
-
-
-
-
-
-
- A2
-
-
-
-
-
- A3
-
-
-
-
-
- A4
-
-
-
-
-
- FAS
-
-
-
-
- Cells
- Velm
-
-
-
- ---
-
+
+ Delete Sensor. Are you sure?
+ Supprimer le Capteur. Êtes-vous sûr?
@@ -12963,279 +12651,99 @@ Trop d'erreurs, abandon.
-
- Custom
- Prédéfini
-
-
-
- Calculated
- Calculé
-
-
-
+
Id
-
+
Instance
-
+
Rx
-
- Add
- Addition
-
-
-
- Average
- Moyenne
-
-
-
- Min
-
-
-
-
- Max
-
-
-
-
- Multiply
- Multiplication
-
-
-
- Totalize
- Totalisation
-
-
-
- Cell
- Element LiPo
-
-
-
- Consumption
- Consommation
-
-
-
- Dist
- Distance
-
-
-
+
Cells Sensor :
Capteur d'éléments:
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
---
-
+
GPS Sensor :
Capteur GPS:
-
+
Alt. Sensor :
Capteur d'altitude:
-
+
Sensor :
Capteur:
-
- V
-
-
-
-
- A
-
-
-
-
- mA
-
-
-
-
- kt
-
-
-
-
- m/s
-
-
-
-
- ft/s
-
-
-
-
- km/h
-
-
-
-
- mph
-
-
-
-
- m
-
-
-
-
- ft
-
-
-
-
- °C
-
-
-
-
- °F
-
-
-
-
- %
-
-
-
-
- mAh
-
-
-
-
- W
-
-
-
-
- mW
-
-
-
-
- dBm
-
-
-
-
- g
-
-
-
-
- °
-
-
-
-
- Rad
-
-
-
-
- mL
-
-
-
-
- US fl.Oz.
-
-
-
-
- Raw (-)
- Chiffres bruts (-)
-
-
-
- RPM
- Tours/minute
-
-
-
- ml/min
-
-
-
-
+
Precision
Précision
-
+
Ratio
-
+
Blades
Pales
-
+
Offset
Décalage
-
+
Multiplier
Multiplicateur
-
+
Auto Offset
Offset auto
-
+
Filter
Filtre
-
+
Persistent
Persistant
-
+
Positive
-
+
Logs
@@ -13243,67 +12751,72 @@ Trop d'erreurs, abandon.
TelemetrySensorPanel
-
+
TELE%1
-
+
Popup menu available
Menu contextuel disponible
-
- Lowest
- Min
-
-
-
- Cell %1
- Elém. %1
-
-
-
- Highest
- Max
-
-
-
- Delta
-
-
-
-
+
Copy
Copier
-
+
Cut
Couper
-
+
Paste
Coller
-
+
Clear
Effacer
-
+
+ Insert
+ Insérer
+
+
+
+ Delete
+ Supprimer
+
+
+
+ Move Up
+ Monter
+
+
+
+ Move Down
+ Descendre
+
+
+
Clear All
Effacer Tout
-
+
+ Cut Telemetry Sensor. Are you sure?
+ Couper le capteur de télémétrie. Êtes-vous sûr?
+
+
+
Clear Telemetry Sensor. Are you sure?
Effacer le capteur de télémétrie. Êtes-vous sûr?
-
+
Clear all Telemetry Sensors. Are you sure?
Effacez tous les capteurs de télémétrie. Êtes-vous sûr?
@@ -13673,12 +13186,17 @@ hh:mm:ss
Timer
-
+
Countdown
Compte à rebours
-
+
+ Start
+ Démarrer
+
+
+
Minute Call
Annonces minutes
@@ -13686,15 +13204,91 @@ hh:mm:ss
TimerData
-
+
TMR
-
+
Timer %1
Chrono %1
+
+
+ TMR
+ as in Timer
+
+
+
+
+ Silent
+ Aucun
+
+
+
+ Beeps
+ Bips
+
+
+
+ Voice
+ Voix
+
+
+
+ Haptic
+ Vibreur
+
+
+
+ 5s
+
+
+
+
+ 10s
+
+
+
+
+ 20s
+
+
+
+
+ 30s
+
+
+
+
+ Not persistent
+ Non persistant
+
+
+
+ NOT
+
+
+
+
+ Persistent (flight)
+ Persistant (vol)
+
+
+
+ Flight
+ Vol
+
+
+
+ Persistent (manual reset)
+ Persistant (RAZ manuelle)
+
+
+
+ Manual reset
+ RAZ manuelle
+
TimerEdit
@@ -13721,44 +13315,6 @@ Utilisez CTRL + le défilement de la souris ou les touches PAGE HAUT/PAGE BAS po
-
- TimerPanel
-
-
- Silent
- Aucun
-
-
-
- Beeps
- Bips
-
-
-
- Voice
- Voix
-
-
-
- Haptic
- Vibreur
-
-
-
- Not persistent
- Non persistant
-
-
-
- Persistent (flight)
- Persistant (vol)
-
-
-
- Persistent (manual reset)
- Persistant (RAZ manuelle)
-
-
Trainer
@@ -14309,128 +13865,68 @@ Extra long : bips extra longs.
burnConfigDialog
-
-
+
Port
-
- List all available programmers.
- Lister tous les programmateurs supportés.
-
-
-
-
-
-
+
+
+
The location of the AVRDUDE executable.
The location of the AVRDUDE.EXE executable.
Chemin d'accès de l'exécutable AVRDUDE.
-
+
DFU-Util Location
Chemin de DFU-UTIL
-
-
-
+
+
Use this button to browse and look for the AVRDUDE executable file.
Utiliser ce bouton pour parcourir à la recherche du fichier exécutable AVRDUDE.EXE.
-
- Programmer used for communicating with the controller.
-Please consult the programmer's documentation and the AVRDUDE documentation to select the appropriate programmer.
- Programmateur utilisé pour la communication avec le contrôleur.
-Consulter la documentation du programmateur utilisé et celle d'AVRDUDE pour effectuer le choix approprié.
-
-
-
- Communication port to the programmer.
-
- Port de communication pour le programmateur.
-
-
-
-
- MCU
- Processeur
-
-
-
+
at91sam3s8-9xr
-
+
Alternate device
Dispositif alternatif
-
+
Use advanced controls
Utiliser les contrôles avancés
-
- Extra Arguments
- Paramètres supplémentaires
-
-
-
- Show Help
- Aide
-
-
-
-
-
+
+
Browse...
Parcourir...
-
+
DFU-UTIL Configuration
Configuration de DFU-UTIL
-
+
SAM-BA Configuration
Configuration de SAM-BA
-
-
-
+
+
Select Location
Choisir l'emplacement
-
- List available programmers
- Lister les programmateurs supportés
-
-
-
- Avrdude help
- Aide d'AVRDUDE
-
-
-
- <b><u>WARNING!</u></b><br>Normally CPU type is automatically selected according to the chosen firmware.<br>If you change the CPU type the resulting eeprom could be inconsistent.
- <b><u>ATTENTION !</u></b><br>Le type de processeur est normalement choisi automatiquement pour le firmware sélectionné.<br>Si vous le changez, l'EEPROM peut être corrompue lors du transfert.
-
-
-
- List Available
- Affiche Liste
-
-
-
-
+
Extra arguments used in AVRDUDE.
This can be used for providing extra information to AVRDUDE.
@@ -14440,16 +13936,6 @@ Permet de fournir des informations supplémentaires à AVRDUDE.
A n'utiliser qu'en connaissance de cause: il n'y a pas de contrôle d'erreur et votre programmateur pourrait être endommagé.
-
-
- AVRDUDE Location
- Emplacement d'AVRDUDE
-
-
-
- Show AVRDUDE help
- Affiche l'aide d'AVRDUDE
-
Programmer Configuration
@@ -14457,58 +13943,40 @@ A n'utiliser qu'en connaissance de cause: il n'y a pas de contrô
Configuration du programmateur
-
-
+
Extra arguments that will be passed to AVRDUDE on every call
Paramètres complémentaires passés à chaque appel d'AVRDUDE
-
- AVRDUDE Configuration
- Configuration d'AVRDUDE
-
-
-
- Location of AVRDUDE executable
- Chemin d'accès de l'exécutable AVRDUDE
-
-
-
- Programmer
- Programmateur
-
-
-
-
+
CPU of your TX
CPU de l'émetteur
-
-
+
CPU present on your 9x radio
Should be m64 for stock radios
m2560 for v4.1 boards
CPU de l'émetteur. Devrait être m64 pour les cartes d'origine, m2560 pour les cartes Gruvin9x v4.x
-
+
SAM-BA Location
Emplacement de SAM-BA
-
-
+
+
Location of sam-ba executable
Emplacement de l'exécutable SAM-BA
-
+
ARM MCU
Processeur ARM
-
+
sam-ba serial port
Port série de SAM-BA
diff --git a/companion/src/translations/companion_ja.ts b/companion/src/translations/companion_ja.ts
index da32c47fc..d423959d4 100644
--- a/companion/src/translations/companion_ja.ts
+++ b/companion/src/translations/companion_ja.ts
@@ -730,58 +730,58 @@ Mode 4:
Boards
-
+
Left Horizontal
左・横
-
+
Left Vertical
左・縦
-
+
Right Vertical
右・縦
-
+
Right Horizontal
右・横
-
+
Aux. 1
AUX. 1
-
+
Aux. 2
AUX. 2
-
-
+
+
Unknown
不明
-
+
Rud
ラダー
-
+
Ele
エレベーター
-
+
Thr
スロットル
-
+
Ail
エルロン
@@ -828,44 +828,44 @@ Mode 4:
- Channels
+ ChannelsPanel
-
+
Name
名称
-
+
Subtrim
サブトリム
-
+
Min
最小
-
+
Max
最大
-
+
Direction
方向
-
+
Curve
カーブ
-
+
PPM Center
PPM センター
-
+
Linear Subtrim
線形サブトリム
@@ -890,62 +890,67 @@ Mode 4:
リバース
-
+
Delete Channel. Are you sure?
チャンネルを削除します。よろしいですか?
-
+
+ Cut Channel. Are you sure?
+ チャンネルを切り取ります。よろしいですか?
+
+
+
Copy
コピー
-
+
Cut
切り取り
-
+
Paste
貼り付け
-
+
Clear
消去
-
+
Insert
挿入
-
+
Delete
削除
-
+
Move Up
上へ移動
-
+
Move Down
下へ移動
-
+
Clear All
すべて消去
-
+
Clear Channel. Are you sure?
チャンネルを消去します。よろしいですか?
-
+
Clear all Channels. Are you sure?
チャンネルをすべて消去します。よろしいですか?
@@ -1085,37 +1090,37 @@ Mode 4:
送信機と機体モデルの設定
-
+
Select or create a file for exported Settings:
エクスポートした設定ファイルを選択または作成します:
-
+
Press the 'Retry' button to choose another file.
別のファイルを選択するには『再試行』ボタンを押してください。
-
+
Simulator for this firmware is not yet available
このファームウェアのシミュレータはまだ利用できません
-
+
Uknown error during Simulator startup.
シミュレータ起動中に不明なエラーが発生しました。
-
+
Simulator Error
シミュレータ エラー
-
+
Data Load Error
データロード エラー
-
+
Error occurred while starting simulator.
シミュレータ起動中にエラーが発生しました。
@@ -1371,51 +1376,28 @@ If you have a settings backup file, you may import that instead.
- CurveGroup
+ CurveReference
-
+
Diff
差分
-
+
Expo
エクスポ
-
+
Func
機能
-
+
Curve
カーブ
-
- CurveReference
-
-
- Diff(%1)
- 差分(%1)
-
-
-
- Expo(%1)
- エクスポ(%1)
-
-
-
- Function(%1)
- 機能(%1)
-
-
-
- Curve(%1)
- カーブ(%1)
-
-
Curves
@@ -1504,108 +1486,116 @@ If you have a settings backup file, you may import that instead.
Point size
点のサイズ
+
+
+ CurvesPanel
-
+
Curve %1
カーブ %1
-
+
Popup menu available
利用可能なポップアップメニュー
-
+
%1 points
%1 点
-
+
Linear
線形
-
+
Single Expo
シングルエクスポ
-
+
Symmetrical f(x)=-f(-x)
対称 f(x)=-f(-x)
-
+
Symmetrical f(x)=f(-x)
対称 f(x)=f(-x)
-
+
Editing curve %1
カーブ %1 編集
-
+
Not enough free points in EEPROM to store the curve.
EEPROMにカーブを保存する十分な空き容量がありません。
-
+
Copy
コピー
-
+
Cut
切り取り
-
+
Paste
貼り付け
-
+
Clear
消去
-
+
Insert
挿入
-
+
Delete
削除
-
+
Move Up
上へ移動
-
+
Move Down
下へ移動
-
+
Clear All
すべて消去
-
+
Clear Curve. Are you sure?
カーブを消去します。よろしいですか?
-
+
Clear all Curves. Are you sure?
カーブをすべて消去します。よろしいですか?
-
+
+ Cut Curve. Are you sure?
+ カーブを切り取ります。よろしいですか?
+
+
+
Delete Curve. Are you sure?
カーブを削除します。よろしいですか?
@@ -1629,8 +1619,8 @@ If you have a settings backup file, you may import that instead.
- Trainer
- トレーナー
+ Trainer Sticks
+ トレーナー Sticks
@@ -1679,8 +1669,13 @@ If you have a settings backup file, you may import that instead.
- Set Timer %1
- 設定: タイマー %1
+ Set %1
+ 設定 %1
+
+
+
+ Set Failsafe
+ フェイルセーフ設定
@@ -1740,60 +1735,35 @@ If you have a settings backup file, you may import that instead.
Adjust %1
- アジャスト %1
-
-
-
- SetFailsafe Int. Module
- 設定: フェイルセーフ 内部モジュール
+ 調整 %1
- SetFailsafe Ext. Module
- 設定: フェイルセーフ 外部モジュール
-
-
-
RangeCheck Int. Module
レンジチェック 内部モジュール
-
+
RangeCheck Ext. Module
レンジチェック 外部モジュール
-
+
Bind Int. Module
バインド 内部モジュール
-
+
Bind Ext. Module
バインド 外部モジュール
-
- Timer1
- タイマー1
-
-
-
- Timer2
- タイマー2
-
-
-
- Timer3
- タイマー3
-
-
-
+
Flight
フライト
-
+
Telemetry
テレメトリー
@@ -1813,39 +1783,39 @@ If you have a settings backup file, you may import that instead.
エンコーダ再生b
-
+
s
s
-
-
-
+
+
+
<font color=red><b>Inconsistent parameter</b></font>
<font color=red><b>矛盾しているパラメータ</b></font>
-
+
Value
値
-
+
played once, not during startup
起動時以外 1回実行
-
+
repeat(%1s)
リピート(%1s)
-
+
DISABLED
無効
-
+
CFN
CFN
@@ -1853,134 +1823,139 @@ If you have a settings backup file, you may import that instead.
CustomFunctionsPanel
-
+
Switch
スイッチ
-
+
Action
実行
-
+
Parameters
パラメータ
-
+
Enable
有効
-
+
Popup menu available
利用可能なポップアップメニュー
-
+
SF%1
SF%1
-
+
GF%1
GF%1
-
+
ON
ON
-
+
Error occurred while trying to play sound, possibly the file is already opened. (Err: %1 [%2])
サウンド再生中にエラーが発生しました。おそらくファイルは既に開かれています (Err: %1 [%2])
-
+
Unable to find or open sound file:
%1
音源ファイルが見つからない、または開けません。
%1
-
- Delete Special Function. Are you sure?
- スペシャルファンクションを削除します。よろしいですか?
+
+ Delete Function. Are you sure?
+ ファンクションを削除します。よろしいですか?
-
+
+ Cut Special Function. Are you sure?
+ ファンクションを切り取ります。よろしいですか?
+
+
+
+ Clear Function. Are you sure?
+ ファンクションを消去します。よろしいですか?
+
+
+
+ Clear all Functions. Are you sure?
+ ファンクションをすべて消去します。よろしいですか?
+
+
+
Copy
コピー
-
+
Cut
切り取り
-
+
Paste
貼り付け
-
+
Clear
消去
-
+
Insert
挿入
-
+
Delete
削除
-
+
Move Up
上へ移動
-
+
Move Down
下へ移動
-
+
Clear All
すべて消去
-
- Clear Special Function. Are you sure?
- スペシャルファンクションを消去します。よろしいですか?
-
-
-
- Clear all Special Functions. Are you sure?
- スペシャルファンクションをすべて消去します。よろしいですか?
-
-
-
+
Value
値
-
+
Source
選択元
-
+
GVAR
GVAR
-
+
Increment
増加
@@ -2148,48 +2123,48 @@ If you have a settings backup file, you may import that instead.
フィールド %1 変換エラー
-
+
Switch
スイッチ
-
+
Switch
スイッチ
-
+
cannot be exported on this board!
このボードにエクスポートできません!
-
+
Source
選択元
-
+
Source %1 cannot be exported on this board!
このボードでは選択元 %1 をエクスポートできません!
-
+
OpenTX only accepts %1 points in all curves
OpenTXはすべてのカーブで %1 点のみを許容します
-
+
OpenTx only accepts %1 points in all curves
OpenTxはすべてのカーブで %1 点のみを許容します
-
-
+
+
OpenTX on this board doesn't accept this function
このボード上のOpenTXはこの機能を受け付けません
-
+
OpenTX doesn't accept this radio protocol
OpenTXはこの送信機プロトコルを受け付けません
@@ -2204,18 +2179,18 @@ If you have a settings backup file, you may import that instead.
<html><head/><body><p>Enable or disable the filter. If the button won't stay enabled, it is likely there is a syntax error in the Regular Expression entered.</p></body></html>
- <html><head/><body><p>フィルタを有効または無効にします。ボタンが有効にならない場合は、入力した正規表現に構文エラーがある可能性があります。</p></body></html>
+ <html><head/><body><p>フィルターを有効または無効にします。ボタンが有効にならない場合は、入力した正規表現に構文エラーがある可能性があります。</p></body></html>
Filter:
- フィルタ:
+ フィルター:
<html><head/><body><p>Enter filter text here. Click the help/info button for details about using the filter. </p><p>
To <b>remove a remembered entry</b> from the filter list, first choose it, and then press <code>Shift-Delete</code> (or <code>Shift-Backspace</code>) key combination.</p></body></html>
- <html><head/><body><p>ここにフィルタテキストを入力してください。フィルタの使用方法の詳細は、help / info ボタンをクリックしてください。</p><p>
+ <html><head/><body><p>ここにフィルタテキストを入力してください。フィルターの使用方法の詳細は、help / info ボタンをクリックしてください。</p><p>
フィルタリストから<b>保存したエントリを削除</b>するには、選択してから<code>Shift+Delete</code> (または<code>Shift+Backspace</code>) キーを押してください。</p></body></html>
@@ -2231,12 +2206,12 @@ To <b>remove a remembered entry</b> from the filter list, first cho
Filter &Help
- フィルタ &ヘルプ
+ フィルター &ヘルプ
Show information about using the filter.
- フィルタの使用に関する情報を表示します。
+ フィルターの使用に関する情報を表示します。
@@ -2261,22 +2236,22 @@ To <b>remove a remembered entry</b> from the filter list, first cho
Enable &Filter
- 有効 &フィルタ
+ 有効 &フィルター
Turn the filter on/off.
- フィルタをON / OFFします。
+ フィルターをON / OFFします。
<html><head><style>kbd {background-color: palette(alternate-base); font-size: large; white-space: nowrap;}</style></head><body><p>The filter supports two syntax types: basic matching with common wildcards as well as full Perl-style (<code>pcre</code>) Regular Expressions.</p><p>By default a filter will only show lines which match (<b>inclusive</b>). To make an <b>exclusive</b> filter which removes matching lines, prefix the filter expression with a <kbd>!</kbd> (exclamation mark).</p><p>To use <b>Regular Expressions</b> (RegEx), prefix the filter text with a <kbd>/</kbd> (slash) or <kbd>^</kbd> (up caret). <ul><li>Put the <kbd>/</kbd> or <kbd>^</kbd> after the exclusive <kbd>!</kbd> indicator if you're using one.</li><li>By default the match is case-sensitive. To make it insensitive, add the typical <kbd>/i</kbd> (slash i) operator at the end of your RegEx.</li><li>If you use a caret (^) to denote a RegEx, it will become part of the Reg. Ex. (that is, matches from start of line).</li><li>If the RegEx is invalid, the filter edit field should show a red border and you will not be able to enable the filter.</li><li>A useful resource for testing REs (with a full reference) can be found at <a href="http://www.regexr.com/">http://www.regexr.com/</a></li></ul></p><p>To use <b>basic matching</b> just type any text.<ul><li>Wildcards: <kbd>*</kbd> (asterisk) matches zero or more of any character(s), and <kbd>?</kbd> (question mark) matches any single character.</li><li>The match is always case-insensitive.</li><li>The match always starts from the beginning of a log line. To ignore characters at the start, use a leading <kbd>*</kbd> wildcard.</li><li>A trailing <kbd>*</kbd> is always implied (that is, matches anything to the end of the log line). To avoid this, use a RegEx.</li><li>You can match literal wildcard characters by prefixing them with a <kbd>\</kbd> (backslash) character (eg. "foo\*bar" matches "foo*bar").</li></ul></p><p>After <b>editing text</b>, press ENTER or TAB key (or click anywhere outside the box) to update the filter.</p><p>To <b>remove an entry</b> from the filter selector list, first choose it, and while in the line editor press <kbd>Shift-Delete</kbd> (or <kbd>Shift-Backspace</kbd>) key combination. The default filters cannot be removed. Up to 50 filters are stored.</p></body></html>
- <html><head><style>kbd {background-color: palette(alternate-base); font-size: large; white-space: nowrap;}</style></head><body><p>フィルタは2つのシンタックスタイプをサポートしています: 一般的なワイルドカードを用いた完全一致、そして完全なPerlスタイル (<code>pcre</code>) 正規表現です。初期値ではフィルタは一致する (<b>包括的</b>) な行のみを表示します。一致する行を削除する<b>排他的</b>フィルタを作成するには、フィルタ式の先頭に<kbd>!</kbd>(Exclamationマーク)を付けます。</p><p>To use <b>Regular Expressions</b> (RegEx), prefix the filter text with a <kbd>/</kbd> (slash) or <kbd>^</kbd> (up caret). <b>正規表現</b> (RegEx)を使用するには、フィルタテキストの先頭に<kbd>/</kbd> (スラッシュ) または<kbd>^</kbd>(アップキャレット)を付けます。<ul><li>既に <kbd>/</kbd> または <kbd>^</kbd> を使用している場合は、 <kbd>!</kbd> の後ろに置きます。</li><li>初期値では大文字と小文字が区別されます。それを鈍感にするには、正規表現の最後に典型的な <kbd>/i</kbd> (スラッシュ+i)演算子を追加します。</li> <li> 正規表現を表すためにキャレット『^』を使用すると、それは正規表現の一部になります。例(つまり、行頭から一致します。)</li> <li> 正規表現が無効な場合、フィルタ編集フィールドには赤い枠が表示されフィルタを有効にすることはできません。</li> <li> 正規表現のテストに役立つリソース(参考文献)は、<a href="http://www.regexr.com/"> http://www.regexr.com/にあります。</a></li> </ul></p><p><b>標準一致 basic matching</b> を使用するには、テキストを入力するだけです。<ul><li>ワイルドカード: <kbd>*</kbd> (アスタリスク)は0個以上の任意の文字に一致し、 <kbd>?</kbd> (クエスチョンマーク) は任意の1文字に一致します。</li><li>この一致では常に大文字と小文字が区別されません。</li><li>一致は常にログの先頭行から始まります。 先頭の文字を無視するには、先頭に<kbd>*</kbd>ワイルドカードを使用します。</li><li>末尾の <kbd>*</kbd> は常に暗黙的に指定されます。(つまり、ログ末尾行までが対象) これを回避するには、正規表現を使用します。</li><li>リテラルワイルドカード文字の前に <kbd>\</kbd> (バックスラッシュ) 文字を付けることで一致させることができます。(例: "foo\*bar"は"foo*bar"と一致)</li></ul></p><p><b>テキスト編集</b>後、EnterまたはTabキーを押して (またはボックスの外側をクリックし) フィルタを更新します。</p><p>フィルタセレクタリストから<b>エントリー削除</b>をするには、まずエントリーを選択しエディタで<kbd>Shift+Delete</kbd> (または<kbd>Shift+Backspace</kbd>) を押します。デフォルトのフィルタは削除できません。また最大50個のフィルタが保存されています。</p></body></html>
+ <html><head><style>kbd {background-color: palette(alternate-base); font-size: large; white-space: nowrap;}</style></head><body><p>フィルターは2つのシンタックスタイプをサポートしています: 一般的なワイルドカードを用いた完全一致、そして完全なPerlスタイル (<code>pcre</code>) 正規表現です。初期値ではフィルターは一致する (<b>包括的</b>) な行のみを表示します。一致する行を削除する<b>排他的</b>フィルターを作成するには、フィルター式の先頭に<kbd>!</kbd>(Exclamationマーク)を付けます。</p><p>To use <b>Regular Expressions</b> (RegEx), prefix the filter text with a <kbd>/</kbd> (slash) or <kbd>^</kbd> (up caret). <b>正規表現</b> (RegEx)を使用するには、フィルターテキストの先頭に<kbd>/</kbd> (スラッシュ) または<kbd>^</kbd>(アップキャレット)を付けます。<ul><li>既に <kbd>/</kbd> または <kbd>^</kbd> を使用している場合は、 <kbd>!</kbd> の後ろに置きます。</li><li>初期値では大文字と小文字が区別されます。それを鈍感にするには、正規表現の最後に典型的な <kbd>/i</kbd> (スラッシュ+i)演算子を追加します。</li> <li> 正規表現を表すためにキャレット『^』を使用すると、それは正規表現の一部になります。例(つまり、行頭から一致します。)</li> <li> 正規表現が無効な場合、フィルター編集フィールドには赤い枠が表示されフィルターを有効にすることはできません。</li> <li> 正規表現のテストに役立つリソース(参考文献)は、<a href="http://www.regexr.com/"> http://www.regexr.com/にあります。</a></li> </ul></p><p><b>標準一致 basic matching</b> を使用するには、テキストを入力するだけです。<ul><li>ワイルドカード: <kbd>*</kbd> (アスタリスク)は0個以上の任意の文字に一致し、 <kbd>?</kbd> (クエスチョンマーク) は任意の1文字に一致します。</li><li>この一致では常に大文字と小文字が区別されません。</li><li>一致は常にログの先頭行から始まります。 先頭の文字を無視するには、先頭に<kbd>*</kbd>ワイルドカードを使用します。</li><li>末尾の <kbd>*</kbd> は常に暗黙的に指定されます。(つまり、ログ末尾行までが対象) これを回避するには、正規表現を使用します。</li><li>リテラルワイルドカード文字の前に <kbd>\</kbd> (バックスラッシュ) 文字を付けることで一致させることができます。(例: "foo\*bar"は"foo*bar"と一致)</li></ul></p><p><b>テキスト編集</b>後、EnterまたはTabキーを押して (またはボックスの外側をクリックし) フィルターを更新します。</p><p>フィルターセレクタリストから<b>エントリー削除</b>をするには、まずエントリーを選択しエディタで<kbd>Shift+Delete</kbd> (または<kbd>Shift+Backspace</kbd>) を押します。デフォルトのフィルターは削除できません。また最大50個のフィルターが保存されています。</p></body></html>
Debug Console Filter Help
- デバッグコンソールフィルタ ヘルプ
+ デバッグコンソールフィルター ヘルプ
@@ -2316,69 +2291,54 @@ To <b>remove a remembered entry</b> from the filter list, first cho
- - Eeprom is not from Th9X
- - EEPROMはTh9Xからのものではありません
-
-
-
- - Eeprom is not from Gruvin9X
- - EEPROMはGruvin9Xからのものではありません
-
-
-
- Eeprom is not from ErSky9X
- EEPROMはErSky9Xからのものではありません
-
- - Eeprom is not from Er9X
- - EEPROMはEr9Xからのものではありません
-
-
-
+
- Eeprom size is invalid
- EEPROMサイズが無効です
-
+
- Eeprom file system is invalid
- EEPROMファイルシステムが無効です
-
+
- Eeprom is from a unknown board
- EEPROMは不明なボードからのものです
-
+
- Eeprom is from the wrong board
- EEPROMは間違ったボードからのものです
-
+
- Eeprom backup not supported
- EEPROMバックアップはサポートされていません
-
+
- Something that couldn't be guessed, sorry
- 推測できない問題が起きています。申し訳ありません
-
+
Warning:
警告:
-
-
+
+
- Your radio probably uses a wrong firmware,
eeprom size is 4096 but only the first 2048 are used
- この送信機は、おそらく間違ったファームウェアを適用しています。
EEPROMサイズは4096ですが、最初の2048しか使用されません
-
+
- Your eeprom is from an old version of OpenTX, upgrading!
To keep your original file as a backup, please choose File -> Save As specifying a different name.
- このEEPROMは古いバージョンのOpenTXでアップグレードしています。
@@ -2536,12 +2496,12 @@ If blank then the input is considered to be "ON" all the time.ミキサー選択元
-
+
Edit %1
編集 %1
-
+
Popup menu available
利用可能なポップアップメニュー
@@ -2925,282 +2885,296 @@ Blank means include all. ?, *, and [...] wildcards accepted.
Firmware
-
+
Channel values displayed in us
表示されるチャンネル値
-
+
No OverrideCH functions available
使用可能な上書きチャンネル機能はありません
-
+
Possibility to enable FAI MODE (no telemetry) at field
フィールドでFAIモード (テレメトリーなし) を有効にする可能性
-
+
FAI MODE (no telemetry) always enabled
FAIモード (テレメトリーなし) を常に有効
-
+
Removes D8 FrSky protocol support which is not legal for use in the EU on radios sold after Jan 1st, 2015
2015/01/01以降に販売された送信機に対し、EUでの使用に適さないD8 FrSkyプロトコルサポートを削除
-
+
Enable non certified firmwares
認定されていないファームウェアを有効にする
-
-
+
+
+
+
+
Disable HELI menu and cyclic mix support
HELIメニューとサイクリックミックスサポートを無効にする
-
-
+
+
+
+
+
Disable Global variables
グローバル変数を無効にする
-
-
+
+
+
+
+
Enable Lua custom scripts screen
Luaカスタムスクリプト画面を有効にする
-
+
Use alternative SQT5 font
SQT5 代替フォントを使用する
-
+
Pots use in menus navigation
メニューナビゲーションでダイヤルを使用
-
+
FrSky Taranis X9D+
FrSky Taranis X9D+
-
- Support for PPM internal module hack
- PPM内部モジュールハックのサポート
-
-
-
-
+
+
Disable RAS (SWR)
RAS (SWR)を無効にする
-
+
FrSky Taranis X9D+ 2019
-
+
FrSky Taranis X9D
FrSky Taranis X9D
-
+
Haptic module installed
タッチパネル対応モジュールをインストール
-
+
FrSky Taranis X9E
FrSky Taranis X9E
-
+
Confirmation before radio shutdown
送信機シャットダウン前の確認
-
+
Horus gimbals installed (Hall sensors)
Horusジンバル (ホールセンサー) をインストール
-
+
FrSky Taranis X9-Lite
FrSky Taranis X9-Lite
-
+
FrSky Taranis X9-Lite S
-
+
FrSky Taranis X7 / X7S
FrSky Taranis X7 / X7S
-
+
FrSky Taranis X-Lite S/PRO
FrSky Taranis X-Lite S/PRO
-
+
FrSky Taranis X-Lite
FrSky Taranis X-Lite
-
+
FrSky Horus X10 / X10S
FrSky Horus X10 / X10S
-
+
+
+
+
+
+ Support hardware mod: R9M ACCESS
+ ハードウェアモジュールサポート: R9M ACCESS
+
+
+
FrSky Horus X12S
FrSky Horus X12S
-
+
Use ONLY with first DEV pcb version
初期DEV pcbバージョンでのみ使用
-
-
+
+
Support for MULTI internal module
MULTI内部モジュールのサポート
-
-
+
+ Jumper T-Lite
+ Jumper T-Lite
+
+
+
+
+
Support for bluetooth module
Bluetoothモジュールのサポート
-
+
+ Radiomaster TX12
+ Radiomaster TX12
+
+
+
+ Radiomaster T8
+ Radiomaster T8
+
+
+
+ Allow bind using bind key
+ バインドキーを使用したバインドを許可
+
+
+
+ Radiomaster TX16S / SE / Hall / Masterfire
+ Radiomaster TX16S / SE / Hall / Masterfire
+
+
+
+ Jumper T18
+ Jumper T18
+
+
+
Turnigy 9XR-PRO
Turnigy 9XR-PRO
-
+
Enable HELI menu and cyclic mix support
HELIメニューとサイクリックミックスのサポートを有効にする
-
+
+ Enable AFHDS3 support
+ AFHDS3サポート 有効
+
+
+
Global variables
グローバル変数
-
+
In model setup menus automatically set source by moving the control
モデル設定メニューでは、コントローラーを動かし自動的に選択元を設定します
-
+
In model setup menus automatically set switch by moving the control
モデル設定メニューでは、コントローラーを動かし自動的にスイッチを設定します
-
+
No graphical check boxes and sliders
グラフィカルなチェックボックスとスライダーはありません
-
+
Battery graph
バッテリーグラフ
-
+
Don't use bold font for highlighting active items
有効なアイテムを強調表示するために太字フォントを使用しない
-
+
FrSky Taranis X7 / X7S Access
FrSky Taranis X7 / X7S ACCESS
-
-
+
+
Support for ACCESS internal module replacement
ACCESS内部モジュール変更のサポート
-
- Turnigy 9XR with m128 chip
- Turnigy 9XR m128チップ搭載
-
-
-
- Turnigy 9XR
- Turnigy 9XR
-
-
-
- 9X with stock board
- 9X ストックボード
-
-
-
+
Enable resetting values by pressing up and down at the same time
上下に同時に押し、値のリセットを有効にする
-
- 9X with stock board and m128 chip
- 9X ストックボード+m128 chip
-
-
-
+
9X with AR9X board
9X AR9Xボード
-
+
FrSky Horus X10 Express / X10S Express
FrSky Horus X10 Express / X10S Express
-
+
Jumper T12 / T12 Pro
Jumper T12 / T12 Pro
-
+
Jumper T16 / T16+ / T16 Pro
Jumper T16 / T16+ / T16 Pro
-
- Radiomaster TX16s / TX16s Hall / TX16s Masterfire
- Radiomaster TX16s / TX16s Hall / TX16s Masterfire
-
-
-
+
Support internal GPS
内蔵GPSサポート
-
+
9X with Sky9x board
9X Sky9Xボード
-
-
- 9X with Gruvin9x board
- 9X Gruvin9X
-
-
-
- DIY MEGA2560 radio
- DIY MEGA2560 送信機
-
FirmwarePreferencesDialog
@@ -3459,62 +3433,62 @@ Blank means include all. ?, *, and [...] wildcards accepted.
書き込み
-
+
Open Firmware File
FWファイルを開く
-
+
%1 may not be a valid firmware file
%1 は有効なファームウェアファイルでない可能性があります
-
+
The firmware file is not valid.
ファームウェアファイルが無効です。
-
+
There is no start screen image in the firmware file.
ファームウェアファイルに起動画面のイメージがありません。
-
+
Profile image %1 is invalid.
プロファイルイメージ %1 が無効です。
-
+
Open image file to use as radio start screen
送信機の起動画面として使用するイメージファイルを開く
-
+
Images (%1)
イメージ (%1)
-
+
Image could not be loaded from %1
イメージを %1からロードできませんでした
-
+
The library image could not be loaded
ライブラリイメージを読み込めませんでした
-
+
Splash image not found
起動イメージが見つかりません
-
+
Cannot save customized firmware
カスタマイズされたファームウェアを保存できません
-
+
Write Firmware to Radio
送信機にファームウェアを書き込みます
@@ -3535,27 +3509,27 @@ Blank means include all. ?, *, and [...] wildcards accepted.
新しいファームウェアは現在インストールされているものと互換性がありません!
-
+
Conversion failed
変換に失敗しました
-
+
Cannot convert Models and Settings for use with this firmware, original data will be used
このファームウェアで使用するためにモデルと設定を変換することはできません。元のデータが使用されます
-
+
Restore failed
復元に失敗しました
-
+
Could not restore Models and Settings to Radio. The models and settings data file can be found at: %1
モデルと設定を送信機に復元できませんでした。モデルと設定データファイルは %1 にあります
-
+
Flashing done
書き込み完了
@@ -3568,42 +3542,42 @@ Blank means include all. ?, *, and [...] wildcards accepted.
実行可能ファイル %1 が見つかりません
-
+
Writing...
書き込み中...
-
+
Reading...
読み込み中...
-
+
Verifying...
確認中...
-
+
unknown
不明
-
+
ie: OpenTX for 9X board or OpenTX for 9XR board
例: 9Xボード用のOpenTXまたは9XRボード用のOpenTX
-
+
ie: OpenTX for M128 / 9X board or OpenTX for 9XR board with M128 chip
例: M128 / 9Xボード用のOpenTXまたはM128チップ搭載 9XRボード用のOpenTX
-
+
ie: OpenTX for Gruvin9X board
例: Gruvin9Xボード用OpenTX
-
+
Your radio uses a %1 CPU!!!
Please check advanced burn options to set the correct cpu type.
@@ -3612,7 +3586,7 @@ Please check advanced burn options to set the correct cpu type.
正しいCPUタイプを設定するには、詳細書き込みオプションを確認してください。
-
+
Your radio uses a %1 CPU!!!
Please select an appropriate firmware type to program it.
@@ -3621,7 +3595,7 @@ Please select an appropriate firmware type to program it.
適切なファームウェアタイプを選択してください。
-
+
You are currently using:
%1
@@ -3630,22 +3604,22 @@ You are currently using:
%1
-
+
Your radio does not seem connected to USB or the driver is not initialized!!!.
お使いの送信機がUSBに接続されていないか、ドライバが初期化されていません。
-
+
Flashing done (exit code = %1)
書き込み完了 (終了コード= %1 )
-
+
Flashing done with errors
エラーを含んだ書き込み完了
-
+
FUSES: Low=%1 High=%2 Ext=%3
FUSES: Low=%1 High=%2 Ext=%3
@@ -3694,88 +3668,88 @@ You are currently using:
FlightModePanel
-
-
+
+
Popup menu available
利用可能なポップアップメニュー
-
+
Trim disabled
トリム 無効
-
+
Own Trim
独自トリム
-
+
Use Trim from Flight mode %1
フライトモードからトリムを使用してください %1
-
+
Use Trim from Flight mode %1 + Own Trim as an offset
フライトモードからトリムを使用してください %1+オフセット独自トリム
-
+
Rotary Encoder %1
ロータリーエンコーダ %1
-
+
Name
名称
-
+
Value source
元値
-
+
Value
値
-
+
Unit
ユニット
-
+
Prec
-
+
Min
最小
-
+
Max
最大
-
+
Popup enabled
ポップアップ有効
-
+
GVAR%1
-
+
0._
-
+
0.0
0.0
@@ -3791,85 +3765,115 @@ You are currently using:
-
+
Copy
コピー
-
+
Cut
切り取り
-
+
Paste
貼り付け
-
+
Insert
挿入
-
+
Delete
削除
-
+
Move Up
上へ移動
-
+
Move Down
下へ移動
-
+
Clear All
すべて消去
-
+
Clear Flight Mode. Are you sure?
フライトモードを消去します。よろしいですか?
-
+
Clear all Flight Modes. Are you sure?
フライトモードをすべて消去します。よろしいですか?
-
+
+ Cut Flight Mode. Are you sure?
+ フライトモードを切り取ります。よろしいですか?
+
+
+
Delete Flight Mode. Are you sure?
フライトモードを削除します。よろしいですか?
-
- Clear selected Global Variable across all Flight Modes. Are you sure?
- すべてのフライトモードの選択したグローバル変数を消去します。よろしいですか?
+
+ Clear Global Variable across all Flight Modes. Are you sure?
+ すべてのフライトモードのグローバル変数を消去します。よろしいですか?
-
+
+ Clear Global Variable. Are you sure?
+ グローバル変数を消去します。よろしいですか?
+
+
+
+ Cut Global Variable across all Flight Modes. Are you sure?
+ すべてのフライトモードのグローバル変数を切り取ります。よろしいですか?
+
+
+
+ Cut Global Variable. Are you sure?
+ グローバル変数を切り取ります。よろしいですか?
+
+
+
+ Delete Global Variable. Are you sure?
+ グローバル変数を削除します。よろしいですか?
+
+
+
+ Paste to selected Global Variable across all Flight Modes. Are you sure?
+ すべてのフライトモードで選択したグローバル変数を貼り付けます。よろしいですか?
+
+
+
Clear all Global Variables for all Flight Modes. Are you sure?
すべてのフライトモードのすべてのグローバル変数を消去します。よろしいですか?
-
+
Clear all Global Variables for this Flight Mode. Are you sure?
このフライトモードのすべてのグローバル変数を消去します。よろしいですか?
-
+
Clear
消去
@@ -3877,17 +3881,17 @@ You are currently using:
FlightModesPanel
-
+
Flight Mode %1
フライトモード %1
-
+
(%1)
(%1)
-
+
(default)
(初期値)
@@ -4127,12 +4131,12 @@ p, li { white-space: pre-wrap; }
-
+
Own value
独自トリム
-
+
Flight mode %1 value
フライトモード %1 値
@@ -4162,52 +4166,52 @@ These will be relevant for all models in the same EEPROM.
これらは同じEEPROM内のすべてのモデルに関連します。
-
+
Setup
セットアップ
-
+
Global Functions
グローバルファンクション
-
+
Trainer
トレーナー
-
+
Hardware
ハードウェア
-
+
Calibration
校正
-
+
Wrong data in profile, radio calibration was not retrieved
プロファイルデータが正しくなく、送信機校正情報が取得できませんでした
-
+
Wrong data in profile, Switch/pot config not retrieved
プロファイルデータが正しくなく、スイッチ/ダイヤル構成が取得できませんでした
-
+
Wrong data in profile, hw related parameters were not retrieved
プロファイルデータが正しくなく、HW関連パラメーターが取得できませんでした
-
+
Do you want to store calibration in %1 profile<br>overwriting existing calibration?
既存の校正情報を上書きして %1 プロファイルに校正情報を保存しますか?
-
+
Calibration and HW parameters saved.
校正情報とHWパラメータが保存されました。
@@ -4215,7 +4219,7 @@ These will be relevant for all models in the same EEPROM.
GeneralSettings
-
+
Radio Settings
送信機設定
@@ -4273,161 +4277,161 @@ These will be relevant for all models in the same EEPROM.
SG
-
+
Stick reverse
スティック リバース
-
+
Country Code
地域
-
+
If you enable FAI, only RSSI and RxBt sensors will keep working. This function cannot be disabled by the radio.
FAIを有効にすると、RSSIとRxBtセンサーのみが機能し続けます。この機能を送信機側で無効にすることはできません。
-
+
FAI Mode
FAIモード
-
+
Automatically adjust the radio's clock if a GPS is connected to telemetry.
GPSがテレメトリーに接続されている場合、自動的に送信機側の内蔵時計を調整します。
-
+
Adjust RTC
- 時計調整
+ 内蔵時計調整
-
+
Speaker Volume
スピーカー音量
-
-
+
+
Hz
Hz
-
+
Vario pitch at max
バリオピッチ 最大
-
+
Backlight Switch
バックライトスイッチ
-
+
Color 1
カラー 1
-
+
Color 2
カラー 2
-
+
Sound Mode
サウンドモード
-
+
If this value is not 0, any keypress will turn on the backlight and turn it off after the specified number of seconds.
この値が0以外の場合、キーを押すとバックライトが点灯し、指定秒数を経過すると消灯します。
-
-
-
+
+
+
sec
秒
-
+
Backlight color
バックライトカラー
-
+
Speaker Pitch (spkr only)
再生ピッチ (対応機のみ)
-
+
Beeper
ビープ
-
+
Speaker
スピーカー
-
+
BeeperVoice
ビープ音声
-
+
SpeakerVoice
スピーカー音声
-
+
Beep volume
ビープ音量
-
+
Wav volume
WAV音量
-
+
Vario volume
バリオVOL
-
+
Background volume
バックグランドVOL
-
-
+
+
ms
ms
-
+
Backlight flash on alarm
アラーム時ライト点滅
-
+
Vario pitch at zero
バリオピッチ ゼロ
-
+
Vario repeat at zero
バリオリピート ゼロ
-
+
Backlight Auto OFF after
バックライト 自動消灯
-
+
This is the switch selectrion for turning on the backlight (if installed).
@@ -4436,8 +4440,8 @@ These will be relevant for all models in the same EEPROM.
-
-
+
+
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
p, li { white-space: pre-wrap; }
@@ -4452,49 +4456,49 @@ p, li { white-space: pre-wrap; }
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">値は20~45です</span></p></body></html>
-
+
RotEnc Navigation
Rot Enc ナビゲーション
-
+
Backlight Brightness
バックライト 明るさ
-
+
America
アメリカ
-
+
Japan
日本
-
+
Europe
ヨーロッパ
-
+
Voice Language
音声言語
-
+
Timeshift from UTC
UTC 時差
-
+
Backlight OFF Brightness
バックライトOFF 明るさ
-
-
-
+
+
+
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
p, li { white-space: pre-wrap; }
@@ -4519,12 +4523,12 @@ p, li { white-space: pre-wrap; }
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">サイレントモード警告 - ビープ音が消音(0)に設定されていると警告します</p></body></html>
-
+
RSSI Poweroff Warning
RSSI 信号切断 警告
-
+
Beeper volume
0 - Quiet. No beeps at all.
@@ -4541,221 +4545,221 @@ p, li { white-space: pre-wrap; }
4 - より大きい音量。
-
-
+
+
Quiet
消音
-
+
Alarms Only
アラームのみ
-
-
+
+
No Keys
キーなし
-
-
+
+
All
すべて
-
+
Beeper Mode
ビープ モード
-
+
Jack Mode
Jackモード
-
+
Audio
音声
-
+
Trainer
トレーナー
-
-
+
+
X-Short
より短い
-
-
+
+
Short
短い
-
-
+
+
Normal
通常
-
-
+
+
Long
長い
-
-
+
+
X-Long
より長い
-
+
Beeper Length
ビープ音の長さ
-
+
Haptic Mode
タッチパネルモード
-
+
Measurement Units
計量単位
-
+
Play Delay (switch mid position)
遅延動作 (スイッチ中央)
-
+
NMEA
-
+
4800 Baud
-
+
9600 Baud
-
+
14400 Baud
-
+
19200 Baud
-
+
38400 Baud
-
+
57600 Baud
-
+
76800 Baud
-
+
115200 Baud
-
-
+
+
Show splash screen on startup
起動時、起動イメージ表示
-
+
nnnnnnNN
nnnnnnNN
-
+
Power On Delay
起動時間
-
+
---
---
-
+
2s
2秒
-
+
3s
3秒
-
+
4s
4秒
-
+
6s
6秒
-
+
8s
8秒
-
+
10s
10秒
-
+
15s
15秒
-
+
If not zero will sound beeps if the transmitter has been left without inputs for the specified number of minutes.
指定された時間(分)入力がないまま送信機が放置されると、ゼロでない場合はビープ音が鳴ります。
-
+
min
分
-
+
Standard
標準
-
+
Optrex
オプトレックス(京セラ)
-
+
Battery warning voltage.
This is the threashhold where the battery warning sounds.
@@ -4765,243 +4769,248 @@ Acceptable values are 5v..10v
許容値は5~10vです
-
+
Only Alarms
アラームのみ
-
+
MAVLink Baud Rate
MAVLink ボーレート
-
+
Haptic Length
タッチパネル長押し
-
+
Battery Warning
バッテリー警告
-
+
"No Sound" Warning
【無音】警告
-
+
LCD Display Type
液晶ディスプレイタイプ
-
+
Haptic Strength
タッチパネル感度
-
+
Battery Meter Range
バッテリーメーター範囲
-
+
Contrast
コントラスト
-
+
Show Splash Screen on Startup
起動時、起動イメージ表示
-
+
Low EEPROM Warning
- EEPROM残量警告
+ EEPROM 残量警告
-
+
Inactivity Timer
非アクティブタイマー
-
+
Min
最小
-
-
+
+
v
v
-
+
Max
最大
-
+
GPS Coordinates
GPS座標
-
+
Default Channel Order
初期チャンネルマップ
-
+
Metric
メートル法
-
+
Imperial
ヤード・ポンド法
-
+
Stick Mode
スティックモード
-
+
<html><head/><body><p>Channel order</p><p><br/></p><p>Defines the order of the default mixes created on a new model.</p></body></html>
<html><head/><body><p>チャンネルマップ</p><p><br/></p><p>モデル作成された際の初期チャンネルマッピングを定義します</p></body></html>
-
+
Owner Registration ID
オーナー登録ID
-
+
+ Keys Backlight
+ キー バックライト
+
+
+
R E T A
↔RUD ↕ELE ↕THR ↔AIL [R E T A]
-
+
R E A T
↔RUD ↕ELE ↔AIL ↕THR [R E A T]
-
+
R T E A
↔RUD ↕THR ↕ELE ↔AIL [R T E A]
-
+
R T A E
↔RUD ↕THR ↔AIL ↕ELE [R T A E]
-
+
R A E T
↔RUD ↔AIL ↕ELE ↕THR [R A E T]
-
+
R A T E
↔RUD ↔AIL ↕THR ↕ELE [R A T E]
-
+
E R T A
↕ELE ↔RUD ↕THR ↔AIL [E R T A]
-
+
E R A T
↕ELE ↔RUD ↔AIL ↕THR [E R A T]
-
+
E T R A
↕ELE ↕THR ↔RUD ↔AIL [E T R A]
-
+
E T A R
↕ELE ↕THR ↔AIL ↔RUD [E T A R]
-
+
E A R T
↕ELE ↔AIL ↔RUD ↕THR [E A R T]
-
+
E A T R
↕ELE ↔AIL ↕THR ↔RUD [E A T R]
-
+
T R E A
↕THR ↔RUD ↕ELE ↔AIL [T R E A]
-
+
T R A E
↕THR ↔RUD ↔AIL ↕ELE [T R A E]
-
+
T E R A
↕THR ↕ELE ↔RUD ↔AIL [T E R A]
-
+
T E A R
↕THR ↕ELE ↔AIL ↔RUD [T E A R]
-
+
T A R E
↕THR ↔AIL ↔RUD ↕ELE [T A R E]
-
+
T A E R
↕THR ↔AIL ↕ELE ↔RUD [T A E R]
-
+
A R E T
↔AIL ↔RUD ↕ELE ↕THR [A R E T]
-
+
A R T E
↔AIL ↔RUD ↕THR ↕ELE [A R T E]
-
+
A E R T
↔AIL ↕ELE ↔RUD ↕THR [A E R T]
-
+
A E T R
↔AIL ↕ELE ↕THR ↔RUD [A E T R]
-
+
A T R E
↔AIL ↕THR ↔RUD ↕ELE [A T R E]
-
+
A T E R
↔AIL ↕THR ↕ELE ↔RUD [A T E R]
-
+
Power Off Delay
終了時間
-
+
Mode selection:
Mode 1:
@@ -5042,53 +5051,53 @@ Mode 4:
-
+
Mode 1 (RUD ELE THR AIL)
モード1 (左:エレベーター・ラダー 右:スロットル・エルロン)
-
+
Mode 2 (RUD THR ELE AIL)
モード2 (左:スロットル・ラダー 右:エレベーター・エルロン)
-
+
Mode 3 (AIL ELE THR RUD)
モード3 (左:エレベーター・エルロン 右:スロットル・ラダー)
-
+
Mode 4 (AIL THR ELE RUD)
モード4 (左:スロットル・エルロン 右:エレベーター・ラダー)
-
+
DMS
-
+
USB Mode
USBモード
-
-
+
+
Ask on Connect
接続毎に確認
-
+
Joystick (HID)
ジョイスティック (HID)
-
+
USB Mass Storage
USBストレージ
-
+
USB Serial (CDC)
USBシリアル (CDC)
@@ -5096,127 +5105,127 @@ Mode 4:
GeneralSetupPanel
-
+
OFF
OFF
-
+
Keys
キー
-
+
Sticks
スティック
-
+
Keys + Sticks
キー+スティック
-
+
ON
ON
-
+
English
-
+
Dutch
-
+
French
-
+
Italian
-
+
German
-
+
Czech
-
+
Slovak
-
+
Spanish
-
+
Polish
-
+
Portuguese
-
+
Russian
-
+
Swedish
-
+
Hungarian
-
+
No
いいえ
-
+
RotEnc A
Rot Enc A
-
+
Rot Enc B
-
+
Rot Enc C
-
+
Rot Enc D
-
+
Rot Enc E
-
+
If you enable FAI, only RSSI and RxBt sensors will keep working.
This function cannot be disabled by the radio.
Are you sure ?
@@ -5251,252 +5260,257 @@ Are you sure ?
フォーム
-
+
SQ
SQ
-
+
SR
SR
-
+
LS2
LS2
-
+
SP
SP
-
+
SO
SO
-
+
S4
S4
-
+
RS
RS
-
+
SB
SB
-
+
PPM 2
PPM 2
-
+
Antenna
アンテナ
-
+
S5
S5
-
+
OFF
OFF
-
+
S-Port Mirror
S-Port ミラー
-
+
Telemetry
テレメトリー
-
+
SBUS Trainer
SBUS トレーナー
-
+
Debug
デバッグ
-
+
RTC Batt Check
- RTC Battチェック
+ 内蔵電池チェック
-
+
+ S.Port Power
+ S.Port 出力
+
+
+
Rud
ラダー
-
+
PPM 3
PPM 3
-
+
S1
S1
-
+
S2
S2
-
+
S3
S3
-
+
PPM 1
PPM 1
-
+
Serial Port
シリアルポート
-
+
v
v
-
+
PPM Multiplier
PPM 乗算
-
+
Current Offset
現在のオフセット
-
+
PPM 4
PPM 4
-
+
SA
SA
-
+
Ele
エレベーター
-
+
Ail
エルロン
-
+
Thr
スロットル
-
+
SC
SC
-
+
LS
LS
-
+
SD
SD
-
+
Battery Offset
バッテリーオフセット
-
+
SE
SE
-
+
SF
SF
-
+
SG
SG
-
+
SH
SH
-
+
SI
SI
-
+
SJ
SJ
-
+
SK
SK
-
+
SL
SL
-
+
SM
SM
-
+
SN
SN
-
+
RS2
RS2
-
+
Bluetooth
Bluetooth
-
+
ADC Filter
- ADCフィルタ
+ ADCフィルター
-
+
Device Name:
デバイス名:
@@ -5505,8 +5519,8 @@ Are you sure ?
HardwarePanel
-
-
+
+
None
なし
@@ -5526,67 +5540,67 @@ Are you sure ?
3 ポジション
-
+
Pot with detent
ダイヤル (ノッチあり)
-
+
Multipos switch
マルチPosスイッチ
-
+
Pot without detent
ダイヤル (ノッチなし)
-
+
Slider with detent
スライダー (ノッチあり)
-
+
OFF
OFF
-
+
Enabled
有効
-
+
Telemetry
テレメトリー
-
+
Trainer
トレーナー
-
+
Internal
内部
-
+
Ask
確認
-
+
Per model
Per モデル
-
+
Internal + External
内部 + 外部
-
+
External
外部
@@ -5712,156 +5726,161 @@ Are you sure ?
InputsPanel
-
-
-
+
+
+
Move Up
上へ移動
-
-
+
+
Ctrl+Up
-
-
-
+
+
+
Move Down
下へ移動
-
-
+
+
Ctrl+Down
-
+
Clear All Inputs
すべての入力項目を消去
-
+
Not enough available Inputs!
入力項目が不足しています!
-
- Delete selected Inputs. Are you sure?
- 選択した入力項目を削除します。よろしいですか?
+
+ Delete selected Input lines. Are you sure?
+ 選択したInput行を削除します。よろしいですか?
-
+
+ Cut selected Input lines. Are you sure?
+ 選択したInput行を切り取ります。よろしいですか?
+
+
+
Lines
直線
-
+
&Add
&追加
-
+
Ctrl+A
-
+
&Edit
&編集
-
+
Enter
Enter
-
+
&Delete
&削除
-
-
+
+
Delete
削除
-
+
&Copy
&コピー
-
+
Ctrl+C
-
+
&Cut
&切り取り
-
+
Ctrl+X
-
+
&Paste
&貼り付け
-
+
Ctrl+V
-
+
Du&plicate
&複製
-
+
Ctrl+U
-
+
Input
入力
-
+
Insert
挿入
-
+
Clear
消去
-
+
Clear All
すべて消去
-
- Clear all Inputs. Are you sure?
- すべての入力項目を消去します。よろしいですか?
+
+ Clear all Input lines. Are you sure?
+ すべてのInput行を消去します。よろしいですか?
-
- Clear Input. Are you sure?
- 入力項目を消去します。よろしいですか?
+
+ Clear all lines for the selected Inputs. Are you sure?
+ 選択したすべてのInput行を消去します。よろしいですか?
-
- Delete Input. Are you sure?
- 入力項目を削除します。よろしいですか?
+
+ Delete all lines for the selected Inputs. Are you sure?
+ 選択したすべてのInput行を削除します。よろしいですか?
@@ -5885,7 +5904,7 @@ Are you sure ?
LimitsGroup
-
+
GV
@@ -6016,102 +6035,112 @@ Are you sure ?
LogicalSwitchesPanel
-
+
Function
機能
-
+
V1
-
+
V2
-
+
AND Switch
& スイッチ
-
+
Duration
期間
-
+
Delay
遅延
-
+
Popup menu available
利用可能なポップアップメニュー
-
+
(instant)
(瞬間)
-
+
(infinite)
(無制限)
-
+
Delete Logical Switch. Are you sure?
論理スイッチを削除します。よろしいですか?
-
+
+ Cut Logical Switch. Are you sure?
+ 論理スイッチを切り取ります。よろしいですか?
+
+
+
Copy
コピー
-
+
Cut
切り取り
-
+
Paste
貼り付け
-
+
Clear
消去
-
+
Insert
挿入
-
+
Delete
削除
-
+
Move Up
上へ移動
-
+
Move Down
下へ移動
-
+
Clear All
すべて消去
-
+
+ Clear Logical Switch. Are you sure?
+ 論理スイッチを消去します。よろしいですか?
+
+
+
Clear all Logical Switches. Are you sure?
論理スイッチをすべて消去します。よろしいですか?
@@ -6293,123 +6322,123 @@ The columns for altitude "GAlt" and for speed "GSpd" are opt
MainWindow
-
+
Diskimage (*.dmg)
ディスクイメージ (*.dmg)
-
+
Would you like to open the disk image to install the new version?
新しいバージョンをインストールするためにディスクイメージを開きますか?
-
+
Executable (*.exe)
実行ファイル (*.exe)
-
-
+
+
Would you like to launch the installer?
インストーラを起動しますか?
-
-
+
+
File loaded
ファイルがロードされました
-
+
Checking for updates
アップデートの確認
-
+
A new version of Companion is available (version %1)<br>Would you like to download it?
Companionの新しいバージョンがあります。 (version %1)<br>ダウンロードしますか?
-
-
+
+
Save As
名前を付けて保存
-
+
New release available
新リリースが利用可能
-
+
A new release of Companion is available, please check the <a href='%1'>OpenTX website!</a>
Companionの新リリースが利用可能です。<a href='%1'>OpenTX Webサイト</a>をチェックしてください
-
-
+
+
No updates available at this time.
現時点で利用可能なアップデートはありません。
-
+
Error opening file %1:
%2.
ファイル %1 を開くときにエラーが発生しました:
%2.
-
+
Not enough flash available on this board for all the selected options
選択されたすべてのオプションに対してこのボードでは十分な書き込みが行えません
-
+
Compilation server temporary failure, try later
コンパイルサーバが一時的に失敗しました。後程お試しください
-
+
Compilation server too busy, try later
コンパイルサーバがビジー状態です。後程お試しください
-
+
Compilation error
コンパイルエラー
-
+
Invalid firmware
無効なファームウェア
-
+
Invalid board
無効なボード
-
+
Invalid language
無効な言語
-
+
Unknown server failure, try later
不明なサーバの障害です。後程お試しください
-
+
Do you want to write the firmware to the radio now ?
今すぐファームウェアを送信機に書き込みますか?
-
+
Firmware update check failed, new version information not found or invalid.
ファームウェアアップデートの確認に失敗しました。新しいバージョン情報が見つからないか、または無効です。
-
+
Firmware %1 does not seem to have ever been downloaded.
Version %2 is available.
Do you want to download it now?
@@ -6422,31 +6451,31 @@ We recommend you view the release notes using the button below to learn about an
重要な変更については、下のボタンをクリックしてリリースノートを参照することをお勧めします。
-
-
+
+
Yes
はい
-
-
+
+
No
いいえ
-
-
+
+
Release Notes
リリースノート
-
-
+
+
Do you want to download version %1 now ?
今すぐバージョン %1 をダウンロードしますか?
-
+
A new version of %1 firmware is available:
- current is %2
- newer is %3
@@ -6463,29 +6492,29 @@ We recommend you view the release notes using the button below to learn about an
重要な変更については、下のボタンをクリックしてリリースノートを参照することをお勧めします。
-
+
Ignore this version %1?
このバージョン %1 を無視しますか?
-
+
The new theme will be loaded the next time you start Companion.
次回Companionを起動したときに、新しいテーマがロードされます。
-
-
+
+
Open Models and Settings file
機体モデルと設定ファイルを開く
-
-
+
+
File saved
ファイル 保存
-
+
There are unsaved file changes which you may lose when switching radio types.
Do you wish to continue?
@@ -6494,780 +6523,760 @@ Do you wish to continue?
そのまま続けますか?
-
-
+
+
Synchronize SD
SDカードを同期する
-
+
No local SD structure path configured!
SDカード保存先パスが設定されていません!
-
+
No Companion release candidates are currently being served for this version, please switch release channel
現在このバージョンのCompanion RC版は提供されていません。リリース状態を切り替えてください
-
+
No nightly Companion builds are currently being served for this version, please switch release channel
現在、このバージョンのCompanion ナイトリービルド版は提供されていません。リリース状態を切り替えてください
-
+
No Companion release builds are currently being served for this version, please switch release channel
このバージョンのCompanion リリース版は現在提供されていません。リリース状態を切り替えてください
-
+
Companion update check failed, new version information not found.
Companionアップデートの確認に失敗しました。新しいバージョン情報が見つかりません。
-
+
No firmware release candidates are currently being served for this version, please switch release channel
現在、このバージョンのファームウェア RC版は提供されていません。リリース状態を切り替えてください
-
+
No firmware nightly builds are currently being served for this version, please switch release channel
現在、このバージョンのファームウェア ナイトリービルド版は提供されていません。リリース状態を切り替えてください
-
+
No firmware release builds are currently being served for this version, please switch release channel
現在、このバージョンのファームウェア リリース版は提供されていません。リリース状態を切り替えてください
-
+
Release candidate builds are now available for this version, would you like to switch to using them?
RC版はこのバージョンで利用可能になりました。それらに切り替えますか?
-
+
Channel changed to RC, please restart the download process
リリース状態をRC版に変更しました。ダウンロードプロセスを再起動してください
-
+
Official release builds are now available for this version, would you like to switch to using them?
このバージョンの公式リリース版が利用可能になりました。それらに切り替えますか?
-
+
Channel changed to Release, please restart the download process
リリース状態をリリース版に変更しました。ダウンロードプロセスを再起動してください
-
+
This radio (%1) is not currently available in this firmware release channel
この送信機 (%1) は、現在このファームウェアリリース状態では利用できません
-
+
No Radio or SD card detected!
送信機またはSDカードが検出されませんでした!
-
+
Local Folder
ローカルフォルダ
-
+
Radio Folder
送信機フォルダ
-
-
+
+
Read Firmware from Radio
送信機からファームウェアを読み込み
-
-
+
+
Read Models and Settings from Radio
送信機から機体モデルや設定を読み込み
-
+
Models and Settings read
機体モデルと設定の読み込み
-
-
+
+
This function is not yet implemented
この機能はまだ実装されていません
-
+
Save Radio Backup to File
送信機のバックアップをファイルに保存
-
+
Read Radio Firmware to File
送信機ファームウェアからファイルへの読み込み
-
+
OpenTX Home Page: <a href='%1'>%1</a>
OpenTX ホームページ: <a href='%1'>%1</a>
-
+
The OpenTX Companion project was originally forked from <a href='%1'>eePe</a>
OpenTX Companionプロジェクトは元々<a href='%1'>eePe</a>から派生しました
-
+
If you've found this program useful, please support by <a href='%1'>donating</a>
このプログラムが役に立つと感じた場合は、<a href='%1'>寄付</a>でのサポートをお願いします
-
+
Copyright OpenTX Team
Copyright OpenTX Team
-
+
About Companion
Companionについて
-
+
OpenTX Companion %1 - Radio: %2 - Profile: %3
OpenTX Companion %1 - 送信機: %2 - プロファイル: %3
-
+
New
新規
-
+
Create a new Models and Settings file
新規モデルと設定ファイルを作成します
-
+
Open...
開く...
-
+
Save
保存
-
-
+
+
Save Models and Settings file
機体モデルと設定ファイルを保存します
-
+
Save As...
名前を付けて保存...
-
+
Close
閉じる
-
+
Close Models and Settings file
機体モデルと設定ファイルを閉じます
-
+
Exit
終了
-
+
Exit the application
アプリケーションを終了します
-
+
About...
バージョン情報...
-
+
Show the application's About box
アプリケーションのバージョン情報を表示します
-
+
Recent Files
最近使用したファイル
-
+
List of recently used files
最近使用したファイルを一覧表示
-
+
Radio Profiles
送信機プロファイル
-
+
Create or Select Radio Profiles
送信機プロファイルを作成または選択します
-
+
View Log File...
ログファイルを表示...
-
+
Open and view log file
ログファイルを開いて表示します
-
+
Settings...
設定...
-
+
Edit Settings
設定を編集します
-
+
Download...
ダウンロード...
-
+
Download firmware and voice files
ファームウェアと音声ファイルをダウンロードします
-
+
Check for Updates...
アップデートのチェック...
-
+
Check OpenTX and Companion updates
OpenTXとCompanionのアップデートを確認します
-
+
Release notes...
リリースノート...
-
+
Show release notes
リリースノートを表示します
-
+
Compare Models...
機体モデルを比較...
-
+
Compare models
機体モデルを比較します
-
+
Edit Radio Splash Image...
送信機の起動イメージを編集...
-
+
Edit the splash image of your Radio
送信機の起動イメージを編集します
-
- List programmers...
- プログラムを一覧表示...
-
-
-
- List available programmers
- 利用可能なプログラムを一覧表示します
-
-
-
- Fuses...
- ヒューズ...
-
-
-
- Show fuses dialog
- ヒューズダイアログを表示します
-
-
-
+
Read firmware from Radio
送信機からファームウェアを読み込み
-
+
Write Firmware to Radio
送信機にファームウェアを書き込み
-
+
Write firmware to Radio
送信機にファームウェアを書き込み
-
+
SD card synchronization
SDカードの同期
-
+
Manuals and other Documents
マニュアルと他の文書
-
+
Open the OpenTX document page in a web browser
WebブラウザでOpenTXドキュメントページを開く
-
+
Write Models and Settings To Radio
機体モデルと設定を送信機に書き込み
-
+
Write Models and Settings to Radio
機体モデルと設定を送信機に書き込み
-
+
Read Models and Settings From Radio
送信機から機体モデルや設定を読み込み
-
+
Configure Communications...
送信機疎通を設定...
-
+
Configure software for communicating with the Radio
送信機と疎通するためのソフトウェアを設定します
-
+
Write Backup to Radio
送信機からバックアップを書き出す
-
+
Write Backup from file to Radio
送信機ファイルからバックアップを書き出します
-
+
Backup Radio to File
ファイルを送信機にバックアップ
-
+
Save a complete backup file of all settings and model data in the Radio
すべての設定とモデルデータの完全なバックアップファイルを送信機に保存します
-
+
Contributors...
貢献者...
-
+
A tribute to those who have contributed to OpenTX and Companion
OpenTXとCompanionに貢献した人々への賛辞
-
+
Add Radio Profile
送信機プロファイルの追加
-
+
Create a new Radio Settings Profile
新しい送信機設定プロファイルを作成します
-
+
Copy Current Radio Profile
現在の送信機プロファイルをコピー
-
+
Duplicate current Radio Settings Profile
現在の送信機設定プロファイルを複製します
-
+
Delete Current Radio Profile...
現在の送信機プロファイルを削除...
-
+
Delete the current Radio Settings Profile
現在の送信機設定プロファイルを削除します
-
+
Export Application Settings..
アプリケーション設定のエクスポート..
-
+
Save all the current %1 and Simulator settings (including radio profiles) to a file.
現在のすべての%1およびシミュレータ設定(送信機プロファイル含)をファイルに保存します。
-
+
Import Application Settings..
アプリケーション設定をインポート..
-
+
Load %1 and Simulator settings from a prevously exported settings file.
以前にエクスポートした設定ファイルから%1とシミュレーション設定を読み込みます。
-
+
Tabbed Windows
タブ付きウィンドウ
-
+
Use tabs to arrange open windows.
開いているウィンドウを並べ替えるのにタブを使用します。
-
+
Tile Windows
ウィンドウのタイトル
-
+
Arrange open windows across all the available space.
利用可能なすべてのスペースに開いているウィンドウを配置します。
-
+
Cascade Windows
ウィンドウを重ねる
-
+
Arrange all open windows in a stack.
開いているウィンドウをすべて重ねて配置します。
-
+
Close All Windows
すべてのウィンドウを閉じる
-
+
Closes all open files (prompts to save if necessary.
開いているファイルをすべて閉じます (必要に応じ保存を求められます)。
-
-
+
+
Edit
編集
-
-
+
+
File
ファイル
-
+
Settings
設定
-
+
Set Icon Theme
アイコンテーマ設定
-
+
Set Icon Size
アイコンサイズ設定
-
+
Read/Write
読み込み/書き込み
-
+
Window
ウィンドウ
-
-
+
+
Help
ヘルプ
-
+
Write
書き込み
-
+
Some text will not be translated until the next time you start Companion. Please note that some translations may not be complete.
次にCompanionを起動するまで一部のテキストは翻訳されません。いくつかの翻訳は完全ではないかもしれませんのでご注意ください。
-
+
Ctrl+Shift+S
-
+
Ctrl+Alt+L
-
+
Ctrl+Alt+D
-
+
Ctrl+Alt+R
-
+
Classical
クラシック
-
+
The classic companion9x icon theme
クラシック Companion9x アイコンテーマ
-
+
Yerico
イェリコ
-
+
Yellow round honey sweet icon theme
Yellow round honey sweet アイコンテーマ
-
+
Monochrome
モノクローム
-
+
A monochrome black icon theme
A monochrome black アイコンテーマ
-
+
MonoBlue
モノブルー
-
+
A monochrome blue icon theme
A monochrome blue アイコンテーマ
-
+
MonoWhite
モノホワイト
-
+
A monochrome white icon theme
A monochrome white アイコンテーマ
-
+
Small
小サイズ
-
+
Use small toolbar icons
小サイズのツールバーアイコンを使用
-
+
Normal
標準サイズ
-
+
Use normal size toolbar icons
標準サイズのツールバーアイコンを使用
-
+
Big
大サイズ
-
+
Use big toolbar icons
大サイズのツールバーアイコンを使用
-
+
Huge
特大サイズ
-
+
Use huge toolbar icons
特大サイズのツールバーアイコンを使用
-
+
Set Menu Language
メニュー言語を設定
-
+
System language
システム言語
-
+
Use default system language.
デフォルトのシステム言語を使用します。
-
+
Use %1 language (some translations may not be complete).
%1言語を使用します (一部の翻訳が不完全な場合あり)。
-
+
Ready
準備完了
-
+
%2
%2
-
+
Alt+%1
-
+
New Radio
新規 送信機
-
+
- Copy
- コピー
-
+
Companion :: Open files warning
Companion :: ファイルを開くときの警告
-
+
Please save or close modified file(s) before deleting the active profile.
有効なプロファイルを削除する前に、変更したファイルを保存するか閉じてください。
-
+
Not possible to remove profile
プロファイルを削除できません
-
+
The default profile can not be removed.
デフォルトプロファイルは削除できません。
-
+
Confirm Delete Profile
プロファイル削除の確認
-
+
Are you sure you wish to delete the "%1" radio profile? There is no way to undo this action!
『%1』送信機プロファイルを削除してもよろしいですか?この操作を元に戻すことはできません!
-
+
Please save or close all modified files before importing settings
設定をインポートする前に、変更したファイルをすべて保存するか閉じてください
-
+
<html><p>%1 and Simulator settings can be imported (restored) from a previosly saved export (backup) file. This will replace current settings with any settings found in the file.</p><p>An automatic backup of the current settings will be attempted. But if the current settings are useful then it is recommended that you make a manual backup first.</p><p>For best results when importing settings, <b>close any other %1 windows you may have open, and make sure the standalone Simulator application is not running.</p><p>Do you wish to continue?</p></html>
<html><p>%1とシミュレータの設定は、以前に保存したエクスポート(バックアップ)ファイルからインポート(復元)できます。これにより、現在の設定がファイル内の設定に置き換えられます。</p><p>現在の設定の自動バックアップが実行されます。ただし、現在の設定が便利な場合は、まず手動バックアップを作成することをお勧めします。</p><p>設定をインポートし最良の結果を得るには、<b>開いている%1ウィンドウをすべて閉じます。スタンドアロンのシミュレーターアプリケーションが実行されていません。</p><p>続行しますか?</p></html>
-
+
Confirm Settings Import
設定のインポートの確認
-
+
Select %1:
%1を選択:
-
+
backup
バックアップ
-
+
Press the 'Ignore' button to continue anyway.
とにかく続行するには『無視』ボタンを押してください。
-
+
The settings could not be imported.
設定をインポートできませんでした。
-
+
<html><p>New settings have been imported from:<br> %1.</p><p>%2 will now re-initialize.</p><p>Note that you may need to close and restart %2 before some settings like language and icon theme take effect.</p>
<html><p>新しい設定は次の場所からインポートされました。<br>%1.</p><p>%2は再初期化されます。</p><p>場合によっては閉じて再起動する必要があります。言語やアイコンテーマなどの設定が有効になる前に%2が発生しました。</p>
-
+
<p>The previous settings were backed up to:<br> %1</p>
<p>以前の設定は次の場所にバックアップされました:<br> %1</p>
@@ -7866,27 +7875,27 @@ If blank then the mix is considered to be "ON" all the time.
空白の場合、ミックスは常に『オン』と見なします。
-
+
DEST -> %1
-
+
Click to access popup menu
クリックしてポップアップメニューにアクセス
-
+
Clear All
すべて消去
-
+
Set All
すべて設定
-
+
Invert All
すべてリバース
@@ -7917,131 +7926,136 @@ If blank then the mix is considered to be "ON" all the time.
MixesPanel
-
-
+
+
Move Up
上へ移動
-
-
+
+
Ctrl+Up
-
-
+
+
Move Down
下へ移動
-
-
+
+
Ctrl+Down
-
+
Clear Mixes
ミキサーを消去
-
+
Not enough available mixers!
ミキサー項目が足りません!
-
- Delete Selected Mixes?
- 選択したミキサーを削除しますか?
+
+ Delete selected Mix lines. Are you sure?
+ 選択したMix行を削除します。よろしいですか?
-
+
+ Cut selected Mix lines. Are you sure?
+ 選択したMix行を切り取ります。よろしいですか?
+
+
+
&Add
&追加
-
+
Ctrl+A
-
+
&Edit
&編集
-
+
Enter
Enter
-
+
&Toggle highlight
&ハイライト切替
-
+
Ctrl+T
-
+
&Delete
&削除
-
+
Delete
削除
-
+
&Copy
&コピー
-
+
Ctrl+C
-
+
C&ut
&切り取り
-
+
Ctrl+X
-
+
&Paste
&貼り付け
-
+
Ctrl+V
-
+
Du&plicate
&複製
-
+
Ctrl+U
-
+
Clear Mixes?
ミキサーを消去しますか?
-
+
Really clear all the mixes?
すべてのミキサーを本当に消去しますか?
@@ -8049,15 +8063,20 @@ If blank then the mix is considered to be "ON" all the time.
ModelData
-
+
Model:
機体モデル:
-
+
Throttle Source
スロットル値
+
+
+ THR
+ THR
+
ModelEdit
@@ -8072,52 +8091,52 @@ If blank then the mix is considered to be "ON" all the time.
シミュレート
-
+
Setup
セットアップ
-
+
Heli
ヘリ
-
+
Flight Modes
フライトモード
-
+
Inputs
入力
-
+
Mixes
ミキサー
-
+
Outputs
出力
-
+
Curves
カーブ
-
+
Logical Switches
論理スイッチ
-
+
Special Functions
スペシャルファンクション
-
+
Telemetry
テレメトリー
@@ -8171,9 +8190,9 @@ If blank then the mix is considered to be "ON" all the time.
-
-
-
+
+
+
OFF
OFF
@@ -8214,7 +8233,7 @@ If blank then the mix is considered to be "ON" all the time.
-
+
Mode
モード
@@ -8248,14 +8267,13 @@ If blank then the mix is considered to be "ON" all the time.
-
-
+
Delay
遅延
-
+
Receiver
受信機
@@ -8281,628 +8299,463 @@ If blank then the mix is considered to be "ON" all the time.
+
RF Output Power
送信出力
-
+
+ Output Type
+ 出力タイプ
+
+
+
+ RX Output Frequency
+ 受信出力周波数
+
+
+
Master/Jack
マスター/Jack
-
+
Slave/Jack
スレーブ/Jack
-
+
Master/SBUS Module
マスター/SBUSモジュール
-
+
Master/CPPM Module
マスター/CPPMモジュール
-
+
Master/SBUS in battery compartment
マスター/バッテリーカバー内SBUB
-
+
90
90
-
+
120
120
-
+
120X
120X
-
+
140
140
-
+
Off
OFF
-
-
-
-
-
-
+
+
+
+
+
None
なし
-
+
Name
名称
-
+
Countdown
カウントダウン
-
+
Minute call
音声時報
-
+
Persistent
持続
-
-
-
+
+
+
FM%1
-
+
FM%1%2
-
+
FM%1+%2
-
-
- Weight
- ウェイト
-
-
-
-
- Switch
- スイッチ
-
-
-
-
+
+
NoTrim
トリムなし
-
+
+
Offset(%1)
オフセット(%1)
-
+
MULT!
複数!
-
+
No DR/Expo
DR/Expoなし
-
-
- Offset
- オフセット
+
+
+ Weight(%1)
+ ウェイト(%1)
-
- Slow
- ゆっくり
+
+
+ Switch(%1)
+ スイッチ(%1)
- Warn
- 警告
+ Delay(u%1:d%2)
+ 遅延(u%1:d%2)
-
+
+ Slow(u%1:d%2)
+ 速度低下(u%1:d%2)
+
+
+
+ Warn(%1)
+ 警告(%1)
+
+
+
Disabled in all flight modes
すべてのフライトモードを無効
-
+
Flight modes
フライトモード
-
+
Flight mode
フライトモード
-
+
All
すべて
-
+
Edge
Edge:端
-
+
instant
簡易
-
+
Sticky
Sticky:追尾
-
+
Timer
タイマー
-
+
missing
間違い
-
+
Duration
期間
-
-
-
+
+
Custom
カスタム
-
+
Standard
標準
-
+
Extended Limits
拡張制限
-
+
Display Checklist
ディスプレイ チェックリスト
-
+
Global Functions
グローバルファンクション
-
+
Manual
手動
-
+
Auto
自動
-
+
Failsafe Mode
フェイルセーフモード
-
-
+
+
Hold
ホールド
-
+
No Pulse
パルスなし
-
+
Not set
セットなし
-
+
No pulses
パルスなし
-
+
Silent
消音
-
+
Beeps
ビープ
-
+
Voice
音声
-
+
Haptic
タッチパネル
-
+
Flight
フライト
-
+
Manual reset
手動リセット
-
+
Step
ステップ
-
+
Display
ディスプレイ
-
+
Extended
拡張
-
+
Never
なし
-
+
On Change
変更
-
+
Always
常に
-
-
-
+
+
+
Source
選択元
-
+
Trim idle only
トリムアイドルのみ
-
+
Warning
警告
-
+
Reversed
リバース
-
+
Tmr
Tmr
-
+
FrSky S.PORT
-
+
FrSky D
-
+
FrSky D (cable)
-
+
Alti
-
+
Alti+
-
+
VSpeed
-
-
-
+
+
+
A1
-
-
-
+
+
+
A2
-
-
+
+
A3
-
-
+
+
A4
-
-
+
+
FAS
-
+
Cells
セル
-
- Calculated
- 計算値
-
-
-
- Add
- 追加
-
-
-
- Average
- 平均
-
-
-
-
+
Min
最小
-
-
+
Max
最大
-
- Multiply
- 乗算
-
-
-
- Totalise
- 合計
-
-
-
- Cell
- セル
-
-
-
- Consumption
- 消費
-
-
-
- Distance
- 距離
-
-
-
- Lowest
- より低く
-
-
-
- Cell %1
- セル %1
-
-
-
- Highest
- より高く
-
-
-
- Delta
- 差分
-
-
-
- Formula
- 定式
-
-
-
-
- Id
-
-
-
-
- Instance
- インスタンス
-
-
-
-
-
-
- Sensor
- センサー
-
-
-
-
- Sources
- 選択元
-
-
-
-
- GPS
- GPS
-
-
-
- Alt.
- Alt.
-
-
-
-
- Blades
- ブレード
-
-
-
- Multi.
- マルチ.
-
-
-
- F
-
-
-
-
- Inst
-
-
-
-
- Alt
-
-
-
-
- Unit
-
-
-
-
- Prec
- 精度
-
-
-
- Ratio
- レシオ
-
-
-
- Multi
- マルチ
-
-
-
- A/Offset
- A/オフセット
-
-
-
- Filter
- フィルタ
-
-
-
- Persist
- 持続
-
-
-
- Positive
- ノーマル
-
-
-
- Log
- ログ
-
-
-
+
Numbers
ナンバー
-
+
Bars
バー
-
+
Script
スクリプト
-
+
Filename
ファイル名
-
+
Error: Unable to open or read file!
エラー: ファイルを開けないか、読み取れません!
@@ -8943,245 +8796,255 @@ If blank then the mix is considered to be "ON" all the time.
スタート
-
+
CH
-
+
Receiver No.
受信機 No.
-
+
Polarity
極性
-
+
Negative
リバース
-
+
Positive
ノーマル
-
+
RF Output Power
送信出力
-
+
Receiver 1
受信機 1
-
-
-
+
+
+
X
X
-
+
Receiver 2
受信機 2
-
+
Receiver 3
受信機 3
-
+
Low Power
- 低パワー
+ 低出力
-
+
WARNING: changing RF Output Power needs RE-BIND
警告: 送信出力を変更するには再バインドが必要です
-
+
Channels
チャンネル
-
+
PPM delay
PPM 遅延
-
+
us
-
+
PPM Frame Length
PPM フレーム長
-
+
ms
ms
-
+
Antenna
アンテナ
-
+
Output type
出力タイプ
-
+
Open Drain
オープン ドレン
-
+
Push Pull
プッシュ プル
-
+
Option value
オプション値
-
+
+ RX Frequency
+ 受信周波数
+
+
+
+ Hz
+ Hz
+
+
+
Protocol
プロトコル
-
+
Registration ID
登録ID
-
+
Multi Radio Protocol
マルチプロトコル
-
+
Sub Type
サブタイプ
-
+
Failsafe Mode
フェイルセーフモード
-
+
Not set
設定なし
-
+
Hold
ホールド
-
+
Custom
カスタム
-
+
No Pulses
パルスなし
-
+
Receiver
受信機
-
+
Trainer Mode
トレーナーモード
-
+
Master/Jack
マスター/Jack
-
+
Slave/Jack
スレーブ/Jack
-
+
Master/SBUS Module
マスター/SBUSモジュール
-
+
Master/CPPM Module
マスター/CPPMモジュール
-
+
Master/SBUS in battery compartment
マスター/バッテリーカバー内SBUB
-
+
WARNING: Requires non-certified firmware!
警告: 未認定のR9Mファームウェアが必要です!
-
+
Master/Bluetooth
マスター/Bluetooth
-
+
Slave/Bluetooth
スレーブ/Bluetooth
-
+
Master/Multi
マスター/Multi
-
+
Disable Telemetry
テレメトリー無効
-
+
Disable Ch. Map
チャンネルマップ無効
-
+
Failsafe Positions
フェイルセーフポジション
-
+
Show values in:
値の表示:
-
+
%
abbreviation for percent
-
+
μs
abbreviation for microseconds
@@ -9190,85 +9053,110 @@ If blank then the mix is considered to be "ON" all the time.
ModuleData
-
+
Trainer Port
トレーナーポート
-
+
Internal Radio System
内部送信システム
-
+
External Radio Module
外部送信モジュール
-
+
Extra Radio System
追加送信システム
-
+
Radio System
送信システム
-
+
10mW - 16CH
-
-
+
+
100mW - 16CH
-
+
500mW - 16CH
-
+
Auto <= 1W - 16CH
-
-
+
+
25mW - 8CH
-
-
+
+
25mW - 16CH
-
+
200mW - 16CH (no telemetry)
200mW - 16CH (テレメトリーなし)
-
+
500mW - 16CH (no telemetry)
500mW - 16CH (テレメトリーなし)
-
+
100mW - 16CH (no telemetry)
100mW - 16CH (テレメトリーなし)
-
+
+ 25 mW
+ 25 mW
+
+
+
+ 100 mW
+ 100 mW
+
+
+
+ 500 mW
+ 500 mW
+
+
+
+ 1 W
+ 1 W
+
+
+
+ 2 W
+ 2 W
+
+
+
Positive
ノーマル
-
+
Negative
リバース
@@ -9276,47 +9164,42 @@ If blank then the mix is considered to be "ON" all the time.
ModulePanel
-
+
Value
値
-
+
Hold
ホールド
-
+
No Pulse
パルスなし
-
+
Ask
確認
-
+
Internal
内部
-
+
Internal + External
内部 + 外部
-
+
External
外部
-
- Autodetect Format
- フォーマット自動検出
-
-
-
+
Bind on channel
チャンネルへバインド
@@ -9330,442 +9213,390 @@ If blank then the mix is considered to be "ON" all the time.
-
-
+
+
Name
名称
-
+
EEprom Size
EEPROMサイズ
-
+
Model Image
モデルイメージ
-
+
Throttle
スロットル
-
+
Trims
トリム
-
+
Center Beep
センター ビープ
-
+
Switch Warnings
スイッチ警告
-
+
Pot Warnings
ダイヤル警告
-
+
Other
その他
-
+
Timers
タイマー
-
+
Time
時間
-
-
+
+
Switch
スイッチ
-
+
Countdown
カウントダウン
-
+
Min.call
音声時報
-
+
Persist
持続
-
+
Modules
モジュール
-
+
Trainer port
トレーナーポート
-
+
Helicopter
ヘリコプター
-
+
Swash
Swash
-
-
+
+
Type
タイプ
-
+
Ring
リング
-
+
Input
入力
-
+
Weight
ウェイト
-
+
Long. cyc
長周期
-
+
Lateral cyc
側面周期
-
+
Collective
コレクティブ
-
+
Flight modes
フライトモード
-
-
+
+
Flight mode
フライトモード
-
+
F.In
F.In
-
+
F.Out
F.Out
-
+
Global vars
グローバル変数
-
-
+
+
GV%1
GV%1
-
+
RE%1
RE%1
-
-
+
Unit
ユニット
-
+
Prec
精度
-
-
+
+
Min
最小
-
-
+
+
Max
最大
-
+
Popup
ポップアップ
-
+
Outputs
出力
-
+
Channel
チャンネル
-
+
Subtrim
サブトリム
-
+
Direct
ダイレクト
-
+
Curve
カーブ
-
+
PPM
PPM
-
+
Linear
線形
-
+
Global Variables
グローバル変数
-
+
Inputs
入力
-
+
Mixers
ミキサー
-
+
Curves
カーブ
-
+
L%1
L%1
-
+
Logical Switches
論理スイッチ
-
+
SF%1
SF%1
-
+
Special Functions
スペシャルファンクション
-
+
Telemetry
テレメトリー
-
- Analogs
- アナログ
-
-
-
- Scale
- スケール
-
-
-
- Offset
- オフセット
-
-
-
+
Protocol
プロトコル
-
+
RSSI Alarms
RSSIアラーム
-
+
Low
低
-
+
Critical
クリティカル
-
+
Telemetry audio
テレメトリー音源
-
+
Altimetry
高度計
-
-
+
+
Vario source
バリオ 元値
-
+
Vario limits >
バリオ リミット値 >
-
+
Sink max
Sink 最大
-
+
Sink min
Sink 最小
-
+
Climb min
クライム 最小
-
+
Climb max
クライム 最大
-
+
Center silent
センター サイレント
-
+
Top Bar
トップバー
-
-
+
Volts source
ボルト 元値
-
+
Altitude source
高度 元値
-
- Various
- その他の設定
-
-
-
- Serial protocol
- シリアル プロトコル
-
-
-
- FAS offset
- FAS オフセット
-
-
-
- mAh count
- mAh カウント
-
-
-
- Persistent mAh
- 持続 mAh
-
-
-
- Current source
- 現在の元値
-
-
-
- Blades
- ブレード
-
-
-
+
Parameters
パラメータ
-
+
Telemetry Sensors
テレメトリーセンサー
-
+
Telemetry Screens
テレメトリースクリーン
-
+
GF%1
GF%1
-
+
Global Functions
グローバルファンクション
-
+
Checklist
チェックリスト
@@ -9789,13 +9620,13 @@ If blank then the mix is considered to be "ON" all the time.
- Telemetry
- テレメトリー
+ RF power
+ 送信出力
- Radio output power
- 送信機 送信出力
+ Telemetry
+ テレメトリー
@@ -9844,22 +9675,22 @@ If blank then the mix is considered to be "ON" all the time.
OpenTxEepromInterface
-
+
Unknown error
不明のエラー
-
+
... plus %1 errors
...追加 %1 エラー
-
+
Cannot write radio settings
送信機設定を書き込めません
-
+
Cannot write model %1
機体モデル %1 を書き込めません
@@ -10007,12 +9838,12 @@ If blank then the mix is considered to be "ON" all the time.
QObject
-
+
WARNING
警告
-
+
<p>Importing JumperTX data into OpenTX 2.3 is <b>not supported and dangerous.</b></p> <p>It is unfortunately not possible for us to differentiate JumperTX data from legitimate FrSky X10 data, but <b>You should only continue here if the file you opened comes from a real FrSky X10.</b></p> <p>Do you really want to continue?</p>
<p>JumperTXデータをOpenTX 2.3にインポートすることは<b>サポート対象外となり危険な行為です。</b></p> <p>残念ながら、JumperTXデータを正当なFrSky X10データと区別することができませんが、<b>開いたファイルが実際のFrSky X10で生成されたものである場合にのみ、続行する事ができます。</b></p> <p>本当に続行しますか?</p>
@@ -10126,25 +9957,20 @@ If blank then the mix is considered to be "ON" all the time.
RadioInterface
-
+
Cannot write file %1:
%2.
ファイルを書き込めません %1:
%2.
-
- <b><u>WARNING!</u></b><br>This will reset the fuses of %1 to the factory settings.<br>Writing fuses can mess up your radio.<br>Do this only if you are sure they are wrong!<br>Are you sure you want to continue?
- <b><u>WARNING!</u></b><br>これにより %1 のヒューズが工場出荷時の設定にリセットされます。<br>ヒューズを作成すると送信機が故障する可能性があります。<br>操作が間違っているかと思います!<br>本当に続行しても宜しいですか?
-
-
-
-
+
+
Could not delete temporary file: %1
一時ファイルを削除できませんでした: %1
-
+
Unable to find radio SD card!
送信機のSDカードが見つかりません!
@@ -10287,439 +10113,120 @@ X
RawSource
-
-
-
-
+
V
V
-
-
-
-
+
+
s
s
-
- ft
-
-
-
-
-
- m
-
-
-
-
- °C
-
-
-
-
- °
-
-
-
-
- %
-
-
-
-
-
- mph
-
-
-
-
-
- km/h
-
-
-
-
- m/s
-
-
-
-
- A
-
-
-
-
- mAh
-
-
-
-
- W
-
-
-
-
- g
-
-
-
-
+
TrmR
トリムR
-
+
TrmE
トリムE
-
+
TrmT
トリムT
-
+
TrmA
トリムA
-
+
Trm5
トリム5
-
+
Trm6
トリム6
-
+
TrmH
トリム横
-
+
TrmV
トリム縦
-
-
+
Batt
-
-
+
Time
時間
-
-
+
Timer1
タイマー1
-
-
+
Timer2
タイマー2
-
-
+
Timer3
タイマー3
-
- RAS
-
-
-
-
- RSSI Tx
- RSSI送信
-
-
-
- RSSI Rx
- RSSI受信
-
-
-
- A1
-
-
-
-
- A2
-
-
-
-
- A3
-
-
-
-
- A4
-
-
-
-
- Alt
-
-
-
-
- Rpm
- RPM
-
-
-
- Fuel
- 燃料
-
-
-
- T1
-
-
-
-
- T2
-
-
-
-
- Speed
- 速度
-
-
-
- Dist
-
-
-
-
- GPS Alt
-
-
-
-
- Cell
- セル
-
-
-
- Cells
- セル
-
-
-
- Vfas
-
-
-
-
- Curr
-
-
-
-
- Cnsp
-
-
-
-
- Powr
-
-
-
-
- AccX
-
-
-
-
- AccY
-
-
-
-
- AccZ
-
-
-
-
- Hdg
-
-
-
-
- VSpd
-
-
-
-
- AirSpeed
- エアスピード
-
-
-
- dTE
-
-
-
-
- A1-
-
-
-
-
- A2-
-
-
-
-
- A3-
-
-
-
-
- A4-
-
-
-
-
- Alt-
-
-
-
-
- Alt+
-
-
-
-
- Rpm+
- RPM+
-
-
-
- T1+
-
-
-
-
- T2+
-
-
-
-
- Speed+
- 速度+
-
-
-
- Dist+
-
-
-
-
- AirSpeed+
- エアスピード+
-
-
-
- Cell-
- セル-
-
-
-
- Cells-
- セル-
-
-
-
- Vfas-
-
-
-
-
- Curr+
-
-
-
-
- Powr+
-
-
-
-
- ACC
-
-
-
-
- GPS Time
-
-
-
-
+
REa
エンコーダ再生a
-
+
REb
エンコーダ再生b
-
-
- ???
-
-
-
-
- ----
-
-
-
-
+
I
as in Input
-
+
LUA%1%2
-
+
MAX
最大
-
+
CYC%1
-
+
TR
as in Trainer
-
+
SRC
@@ -10727,22 +10234,22 @@ X
RawSwitch
-
+
↑
-
+
↓
-
+
-
-
+
!
@@ -10967,131 +10474,327 @@ X
SensorData
-
-
+
+ Formula
+ 定式
+
+
+
+ Id
+ ID
+
+
+
+ Instance
+ インスタンス
+
+
+
+
+ Sensor
+ センサー
+
+
+
+ Sources
+ 選択元
+
+
+
+ GPS
+ GPS
+
+
+
+ Alt
+ 高度
+
+
+
+ Unit
+ ユニット
+
+
+
+ Precision
+ 精度
+
+
+
+ Ratio
+ レシオ
+
+
+
+ Offset
+ オフセット
+
+
+
+ Auto Offset
+ 自動オフセット
+
+
+
+ Blades
+ ブレード
+
+
+
+ Multiplier
+ 乗算
+
+
+
+ Filter
+ フィルター
+
+
+
+ Persist
+ 持続
+
+
+
+ Positive
+ ノーマル
+
+
+
+ Log
+ ログ
+
+
+
+ Custom
+ カスタム
+
+
+
+ Calculated
+ 計算値
+
+
+
+ Add
+ 追加
+
+
+
+ Average
+ 平均
+
+
+
+ Minimum
+ 最低値
+
+
+
+ Maximum
+ 最大値
+
+
+
+ Multiply
+ 乗算
+
+
+
+ Totalize
+ 合計
+
+
+
+ Cell
+ セル
+
+
+
+ Consumption
+ 消費
+
+
+
+ Distance
+ 距離
+
+
+
+ Lowest
+ より低く
+
+
+
+ Cell %1
+ セル %1
+
+
+
+ Highest
+ より高く
+
+
+
+ Delta
+ 差分
+
+
+
+ Raw (-)
+ Raw (-)
+
+
+
+
V
V
-
+
A
-
+
mA
-
+
kts
-
+
m/s
-
+
km/h
-
+
mph
-
+
m
-
+
f
-
+
°C
-
+
°F
-
+
%
-
+
mAh
-
+
W
-
+
mW
-
+
dB
-
+
rpms
-
+
g
-
+
°
-
+
Rad
-
+
hours
-
+
minutes
-
+
seconds
-
+
ml/minute
-
+
+ Hertz
+
+
+
+
+ mS
+
+
+
+
+ uS
+
+
+
+
TELE
+
+
+ Y
+ Y
+
+
+
+ N
+ N
+
Setup
@@ -11101,117 +10804,117 @@ X
タイマー 1
-
+
Top LCD Timer
液晶タイマー
-
+
Model Image
モデルイメージ
-
+
Warnings
警告
-
+
Switch Warnings
スイッチ警告
-
+
Pot Warnings
ダイヤル警告
-
+
OFF
OFF
-
+
Manual
手動
-
+
Auto
自動
-
+
Model
機体モデル
-
+
Center beep
センター ビープ
-
+
Display Checklist
チェックリスト表示
-
+
Never
なし
-
+
On change
変更
-
+
Always
常に
-
+
Throttle Trim Idle Only
THRトリムアイドル
-
+
Global Functions
グローバルファンクション
-
+
Throttle Warning
スロットル警告
-
+
Exponential
エクスポ
-
+
Extra Fine
極細
-
+
Fine
細かめ
-
+
Medium
中間
-
+
Coarse
粗め
-
+
Reverse throttle operation.
If this is checked the throttle will be reversed. Idle will be forward, trim will also be reversed and the throttle warning will be reversed as well.
@@ -11220,47 +10923,52 @@ If this is checked the throttle will be reversed. Idle will be forward, trim wi
これがチェックされている場合、スロットル操作が逆になります。アイドルは前方になり、トリムもまた逆になり、スロットル警告も逆になります。
-
+
Reverse Throttle
スロットル リバース
-
+
Edit Checklist...
チェックリストの編集...
-
+
+ Throttle trim switch
+ スロットル トリムスイッチ
+
+
+
Extended Trims
拡張トリム
-
+
Extended Limits
拡張制限
-
+
Throttle Source
スロットル値
-
+
Trim Step
トリム間隔
-
+
Trims Display
トリム表示
-
+
Timer 2
タイマー 2
-
+
Timer 3
タイマー 3
@@ -11268,87 +10976,92 @@ If this is checked the throttle will be reversed. Idle will be forward, trim wi
SetupPanel
-
+
Popup menu available
利用可能なポップアップメニュー
-
+
Timer %1
タイマー %1
-
+
THR
-
+
Profile Settings
プロファイル設定
-
+
SD structure path not specified or invalid
SDカード保存先パスが指定されていないか無効です
-
+
Copy
コピー
-
+
Cut
切り取り
-
+
Paste
貼り付け
-
+
Clear
消去
-
+
Insert
挿入
-
+
Delete
削除
-
+
Move Up
上へ移動
-
+
Move Down
下へ移動
-
+
Clear All
すべて消去
-
+
Clear Timer. Are you sure?
タイマーを消去します。よろしいですか?
-
+
Clear all Timers. Are you sure?
タイマーをすべて消去します。よろしいですか?
-
+
+ Cut Timer. Are you sure?
+ タイマーを切り取ります。よろしいですか?
+
+
+
Delete Timer. Are you sure?
タイマーを削除します。よろしいですか?
@@ -12074,62 +11787,62 @@ The default is configured in the chosen Radio Profile.
送信機シミュレータ (%1)
-
+
Could not determine startup data source.
起動データ元を特定できませんでした。
-
+
Could not load data, possibly wrong format.
データをロードできません、フォーマットが間違っている可能性があります。
-
+
Data Load Error
データロード エラー
-
+
Invalid startup data provided. Plese specify a proper file/path.
無効なスタートアップデータが提供されました。正しいファイル/パスを指定してください。
-
+
Simulator Startup Error
シミュレータ スタートアップ エラー
-
+
Error saving data: could open file for writing: '%1'
データ保存エラー: 書き込み用にファイルを開くことができました: 「%1」
-
+
Error saving data: could not get data from simulator interface.
データ保存エラー: シミュレータのインターフェイスからデータを取得できませんでした。
-
+
An unexpected error occurred while attempting to save radio data to file '%1'.
送信機データをファイル「%1」に保存しようとしたときに予期せぬエラーが発生しました。
-
+
Data Save Error
データ保存 エラー
-
+
Cannot open joystick, joystick disabled
スティックが接続不可、もしくはスティックが無効です
-
+
Radio firmware error: %1
送信機 ファームウェア エラー: %1
-
+
- Flight Mode %1 (#%2)
- フライトモード %1 (#%2)
@@ -12773,11 +12486,6 @@ Too many errors, giving up.
mAmps (mA)
ミリアンペア (mA)
-
-
- Range
- レンジ
-
TelemetryCustomScreen
@@ -12807,22 +12515,22 @@ Too many errors, giving up.
最大
-
+
None
なし
-
+
Numbers
ナンバー
-
+
Bars
バー
-
+
Script
スクリプト
@@ -12830,106 +12538,54 @@ Too many errors, giving up.
TelemetryPanel
-
+
Telemetry screen %1
テレメトリースクリーン %1
-
+
FrSky S.PORT
-
+
FrSky D
-
+
FrSky D (cable)
-
+
Source
信号元
-
+
Low Alarm
低アラーム
-
+
Critical Alarm
クリティカルアラーム
-
+
Winged Shadow How High
Winged Shadow How High
-
+
Winged Shadow How High (not supported)
Winged Shadow How High (サポートなし)
-
- Alti
-
-
-
-
- Alti+
-
-
-
-
- VSpeed
-
-
-
-
-
-
- A1
-
-
-
-
-
-
- A2
-
-
-
-
-
- A3
-
-
-
-
-
- A4
-
-
-
-
-
- FAS
-
-
-
-
- Cells
- セル
-
-
-
- ---
- ---
+
+ Delete Sensor. Are you sure?
+ テレメトリーセンサーを削除します。よろしいですか?
@@ -12945,279 +12601,99 @@ Too many errors, giving up.
TELE##
-
- Custom
- カスタム
-
-
-
- Calculated
- 計算値
-
-
-
+
Id
ID
-
+
Instance
インスタンス
-
+
Rx
受信
-
- Add
- 追加
-
-
-
- Average
- 平均
-
-
-
- Min
- 最小
-
-
-
- Max
- 最大
-
-
-
- Multiply
- 乗算
-
-
-
- Totalize
- 合計
-
-
-
- Cell
- セル
-
-
-
- Consumption
- 消費
-
-
-
- Dist
- 距離
-
-
-
+
Cells Sensor :
セル センサー :
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
---
---
-
+
GPS Sensor :
GPS センサー :
-
+
Alt. Sensor :
高度 センサー :
-
+
Sensor :
センサー :
-
- Raw (-)
- Raw (-)
-
-
-
- V
- V
-
-
-
- A
-
-
-
-
- mA
-
-
-
-
- kt
-
-
-
-
- m/s
-
-
-
-
- ft/s
-
-
-
-
- km/h
-
-
-
-
- mph
-
-
-
-
- m
- 分
-
-
-
- ft
-
-
-
-
- °C
-
-
-
-
- °F
-
-
-
-
- %
-
-
-
-
- mAh
-
-
-
-
- W
-
-
-
-
- mW
-
-
-
-
- dBm
-
-
-
-
- RPM
-
-
-
-
- g
-
-
-
-
- °
-
-
-
-
- Rad
-
-
-
-
- mL
-
-
-
-
- US fl.Oz.
-
-
-
-
- ml/min
-
-
-
-
+
Precision
精度
-
+
Ratio
レシオ
-
+
Blades
ブレード
-
+
Offset
オフセット
-
+
Multiplier
乗算
-
+
Auto Offset
自動オフセット
-
+
Filter
- フィルタ
+ フィルター
-
+
Persistent
持続
-
+
Positive
ノーマル
-
+
Logs
ログ
@@ -13225,67 +12701,72 @@ Too many errors, giving up.
TelemetrySensorPanel
-
+
TELE%1
-
+
Popup menu available
利用可能なポップアップメニュー
-
- Lowest
- より低く
-
-
-
- Cell %1
- セル %1
-
-
-
- Highest
- より高く
-
-
-
- Delta
- 差分
-
-
-
+
Copy
コピー
-
+
Cut
切り取り
-
+
Paste
貼り付け
-
+
Clear
消去
-
+
+ Insert
+ 挿入
+
+
+
+ Delete
+ 削除
+
+
+
+ Move Up
+ 上へ移動
+
+
+
+ Move Down
+ 下へ移動
+
+
+
Clear All
すべて消去
-
+
+ Cut Telemetry Sensor. Are you sure?
+ テレメトリーセンサーを切り取ります。よろしいですか?
+
+
+
Clear Telemetry Sensor. Are you sure?
テレメトリーセンサーを消去します。よろしいですか?
-
+
Clear all Telemetry Sensors. Are you sure?
テレメトリーセンサーのすべてを消去します。よろしいですか?
@@ -13654,12 +13135,12 @@ hh:mm:ss
Timer
-
+
Countdown
カウントダウン
-
+
Minute Call
音声時報
@@ -13669,13 +13150,19 @@ hh:mm:ss
TMR
-
+ TMR
Timer %1
タイマー %1
+
+
+ TMR
+ as in Timer
+ TMR
+
TimerEdit
@@ -13705,37 +13192,37 @@ CTRL+スクロールまたはPAGE UP/DOWNキーを押すと、大きなステ
TimerPanel
-
+
Silent
消音
-
+
Beeps
ビープ
-
+
Voice
音声
-
+
Haptic
タッチパネル
-
+
Not persistent
持続なし
-
+
Persistent (flight)
持続 (フライト)
-
+
Persistent (manual reset)
持続 (手動リセット)
@@ -14114,7 +13601,7 @@ CTRL+スクロールまたはPAGE UP/DOWNキーを押すと、大きなステ
Has your helicopter got an adjustable gyro for the tail?
- このヘリコプターはテールのアジャストジャイロを実装しましたか?
+ このヘリコプターはテールのジャイロ調整を実装しましたか?
@@ -14297,74 +13784,42 @@ CTRL+スクロールまたはPAGE UP/DOWNキーを押すと、大きなステ
プログラムの設定
-
-
+
+
Location of sam-ba executable
sam-ba実行ファイル場所
-
-
-
-
+
+
+
The location of the AVRDUDE executable.
AVRDUDE実行ファイル場所.
-
+
DFU-Util Location
DFU-Utiltyの場所
-
- Location of AVRDUDE executable
- AVRDUDE実行ファイル場所
-
-
-
-
-
+
+
Use this button to browse and look for the AVRDUDE executable file.
AVRDUDE実行ファイルを参照・検索するには、このボタンを押してください。
-
-
-
+
+
Browse...
参照...
-
- Programmer
- プログラム
-
-
-
- Programmer used for communicating with the controller.
-Please consult the programmer's documentation and the AVRDUDE documentation to select the appropriate programmer.
- コントローラとの通信に使用されるプログラムです。
-適切なプログラムを選択するには、プログラム側の資料とAVRDUDEの資料を参照してください。
-
-
-
- List all available programmers.
- 利用可能なプログラムを一覧表示します。
-
-
-
- List Available
- 一覧表示
-
-
-
-
+
Extra arguments that will be passed to AVRDUDE on every call
すべての呼び出しでAVRDUDEに渡される追加引数
-
-
+
Extra arguments used in AVRDUDE.
This can be used for providing extra information to AVRDUDE.
@@ -14375,51 +13830,17 @@ Please only use this if you know what you are doing. There are no error checks
こちらは自己責任においてご利用ください。エラーチェックは行われません。不具合がある場合コントローラが制御不能となる可能性があります。
-
- Extra Arguments
- 追加引数
-
-
-
- Show AVRDUDE help
- AVRDUDEのヘルプを表示します
-
-
-
- Show Help
- ヘルプを表示
-
-
-
- Communication port to the programmer.
-
- プログラムへの通信ポートです。
-
-
-
-
+
Port
ポート
-
- AVRDUDE Location
- AVRDUDEの場所
-
-
-
- MCU
- MCU
-
-
-
-
+
CPU of your TX
送信機のCPU
-
-
+
CPU present on your 9x radio
Should be m64 for stock radios
m2560 for v4.1 boards
@@ -14428,72 +13849,51 @@ m2560 for v4.1 boards
v4.1ボード用m2560
-
+
at91sam3s8-9xr
at91sam3s8-9xr
-
+
SAM-BA Location
SAM-BAの場所
-
+
ARM MCU
ARM MCU
-
+
sam-ba serial port
sam-ba シリアルポート
-
+
Alternate device
代替デバイス
-
+
Use advanced controls
詳細設定を使用
-
+
DFU-UTIL Configuration
DFU-Utility 設定
-
+
SAM-BA Configuration
SAM-BA 設定
-
- AVRDUDE Configuration
- AVRDUDE 設定
-
-
-
-
-
+
+
Select Location
場所の選択
-
-
- List available programmers
- 利用可能なプログラムを一覧表示します
-
-
-
- Avrdude help
- Avrdude ヘルプ
-
-
-
- <b><u>WARNING!</u></b><br>Normally CPU type is automatically selected according to the chosen firmware.<br>If you change the CPU type the resulting eeprom could be inconsistent.
- <b><u>警告!</u></b><br>通常CPUタイプは、選択されたファームウェアによって自動的に選択されます。<br>CPUタイプを変更すると、その結果EEPROMに矛盾が生じる可能性があります。
-
joystickDialog
diff --git a/companion/src/translations/companion_zh_TW.ts b/companion/src/translations/companion_zh_TW.ts
new file mode 100644
index 000000000..54b71926b
--- /dev/null
+++ b/companion/src/translations/companion_zh_TW.ts
@@ -0,0 +1,21736 @@
+
+
+
+
+ AileronsPage
+
+
+ No
+ 模型嚮導中副翼連線方式的設定
+ 没有副翼
+
+
+
+ Yes, controlled by a single channel
+ 模型嚮導中副翼連線方式的設定
+ 有副翼,使用一個接收機通道控制
+
+
+
+ Yes, controlled by two channels
+ 模型嚮導中副翼連線方式的設定
+ 有副翼,使用兩個接收機通道控制
+
+
+
+ <br>First Aileron Channel:
+ <br>第一個副翼通道:
+
+
+
+ Second Aileron Channel:
+ 第二個副翼通道:
+
+
+
+ AirbrakesPage
+
+
+ No
+ 沒有空氣剎車
+
+
+
+ Yes, controlled by a single channel
+ 有空氣剎車,使用一個通道控制
+
+
+
+ Yes, controlled by two channels
+ 有空氣剎車,使用兩個通道控制
+
+
+
+ <br>First Airbrake Channel:
+ <br>第一個空氣剎車通道:
+
+
+
+ Second Airbrake Channel:
+ 第二個空氣剎車通道:
+
+
+
+ AppData
+
+
+ Application Settings have been saved to
+ %1
+
+
+
+
+ Could not save Application Settings to file "%1"
+
+
+
+
+ because the file could not be saved (check access permissions).
+
+
+
+
+ for unknown reasons.
+
+
+
+
+ AppMessages
+
+
+ Show this message again at next startup?
+
+
+
+
+ AppPreferencesDialog
+
+
+
+
+
+
+
+
+
+ Edit Settings
+ 此之後位置在主菜單中的settings-->settings
+ 首選項
+
+
+
+
+
+
+
+
+
+
+ Radio Profile
+ 遙控器檔案可以有多個,對應不同的遙控器
+ 遙控器檔案
+
+
+
+
+
+
+
+
+
+
+ Profile Name
+ 檔案名稱
+
+
+
+
+
+
+
+
+
+
+ Radio Type
+ 遙控器型號
+
+
+
+
+
+
+
+
+
+
+ Menu Language
+ 遙控器檔案中
+ 菜單語言
+
+
+
+
+
+
+
+
+
+
+ Build Options
+ 編譯選項
+
+
+
+
+
+
+
+
+
+
+ Splash Screen
+ 遙控器檔案中
+ 開機畫面
+
+
+
+
+
+
+
+
+
+
+ Other Settings
+ 其他設置
+
+
+
+
+
+
+
+
+
+
+ SD Structure path
+ SD卡目錄
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ The profile specific folder, if set, will override general Backup folder
+ 制定檔案目錄,如果設定此目錄,將代替默認備份目錄
+
+
+
+
+
+
+
+
+
+
+ Backup folder
+ 備份目錄
+
+
+
+
+
+
+
+
+
+
+ If set it will override the application general setting
+ 如果設置將會代替程序一般設定
+
+
+
+
+
+
+
+
+
+
+ if set, will override general backup enable
+ 如果設定將會覆蓋一般備份允許選項
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Enable automatic backup before writing firmware
+ 寫入韌體前允許自動備份
+
+
+
+
+
+
+
+
+
+
+ General Settings
+ 一般設定
+
+
+
+
+
+
+
+
+
+
+ Default Stick Mode
+ 默認搖桿模式
+
+
+
+
+
+
+
+
+
+
+ Mode selection:
+
+Mode 1:
+ Left stick: Elevator, Rudder
+ Right stick: Throttle, Aileron
+
+Mode 2:
+ Left stick: Throttle, Rudder
+ Right stick: Elevator, Aileron
+
+Mode 3:
+ Left stick: Elevator, Aileron
+ Right stick: Throttle, Rudder
+
+Mode 4:
+ Left stick: Throttle, Aileron
+ Right stick: Elevator, Rudder
+
+
+ 遙控器檔案中
+ 模式選擇:
+
+日本手 (左手升降方向-右手油門副翼)
+美國手 (左手油門方向-右手升降副翼)
+中國手 (左手升降副翼-右手油門方向)
+日本手 (左手油門副翼-右手升降方向)
+
+
+
+
+
+
+
+
+
+
+
+
+ Mode 1 (RUD ELE THR AIL)
+ 遥控器档案中
+ MODE1 日本手 ↕升降↔方向 ↕油門↔副翼
+
+
+
+
+
+
+
+
+
+
+ Mode 2 (RUD THR ELE AIL)
+ MODE2 美國手 ↕油門↔方向 ↕升降↔副翼
+
+
+
+
+
+
+
+
+
+
+ Mode 3 (AIL ELE THR RUD)
+ MODE3 中國手 ↕升降↔副翼 ↕油門↔方向
+
+
+
+
+
+
+
+
+
+
+ Mode 4 (AIL THR ELE RUD)
+ MODE4 模式4 ↕油門↔副翼 ↕升降↔方向
+
+
+
+
+
+
+
+
+
+
+ Default Channel Order
+ 遙控器檔案中
+ 默認通道順序
+
+
+
+
+
+
+
+
+
+
+ <html><head/><body><p>Channel order</p><p><br/></p><p>Defines the order of the default mixes created on a new model.</p></body></html>
+ <html><head/><body><p>通道順序</p><p><br/></p><p>定義了新建模型時默認設置的通道順序</p></body></html>
+
+
+
+
+
+
+
+
+
+
+ R E T A
+ 方向 升降 油門 副翼 [R E T A]
+
+
+
+
+
+
+
+
+
+
+ R E A T
+ 方向 升降 副翼 油門 [R E A T]
+
+
+
+
+
+
+
+
+
+
+ R T E A
+ 方向 油門 升降 副翼 [R T E A]
+
+
+
+
+
+
+
+
+
+
+ R T A E
+ 方向 油門 副翼 升降 [R T A E]
+
+
+
+
+
+
+
+
+
+
+ R A E T
+ 方向 副翼 升降 油門 [R A E T]
+
+
+
+
+
+
+
+
+
+
+ R A T E
+ 方向 副翼 油門 升降 [R A T E]
+
+
+
+
+
+
+
+
+
+
+ E R T A
+ 升降 方向 油門 副翼 [E R T A]
+
+
+
+
+
+
+
+
+
+
+ E R A T
+ 升降 方向 副翼 油門 [E R A T]
+
+
+
+
+
+
+
+
+
+
+ E T R A
+ 升降 油門 方向 副翼 [E T R A]
+
+
+
+
+
+
+
+
+
+
+ E T A R
+ 升降 油門 副翼 方向 [E T A R]
+
+
+
+
+
+
+
+
+
+
+ E A R T
+ 升降 副翼 方向 油門 [E A R T]
+
+
+
+
+
+
+
+
+
+
+ E A T R
+ 升降 副翼 油門 方向 [E A T R]
+
+
+
+
+
+
+
+
+
+
+ T R E A
+ 油門 方向 升降 副翼 [T R E A]
+
+
+
+
+
+
+
+
+
+
+ T R A E
+ 油門 方向 副翼 升降 [T R A E]
+
+
+
+
+
+
+
+
+
+
+ T E R A
+ 油門 升降 方向 副翼 [T E R A]
+
+
+
+
+
+
+
+
+
+
+ T E A R
+ 油門 升降 副翼 方向 [T E A R]
+
+
+
+
+
+
+
+
+
+
+ T A R E
+ 油門 副翼 方向 升降 [T A R E]
+
+
+
+
+
+
+
+
+
+
+ T A E R
+ 油門 副翼 升降 方向 [T A E R]
+
+
+
+
+
+
+
+
+
+
+ A R E T
+ 副翼 方向 升降 油門 [A R E T]
+
+
+
+
+
+
+
+
+
+
+ A R T E
+ 副翼 方向 油門 升降 [A R T E]
+
+
+
+
+
+
+
+
+
+
+ A E R T
+ 副翼 升降 方向 油門 [A E R T]
+
+
+
+
+
+
+
+
+
+
+ A E T R
+ 副翼 升降 油門 方向 [A E T R]
+
+
+
+
+
+
+
+
+
+
+ A T R E
+ 副翼 油門 方向 升降 [A T R E]
+
+
+
+
+
+
+
+
+
+
+ A T E R
+ 副翼 油門 升降 方向 [A T E R]
+
+
+
+
+
+
+
+
+
+
+ Append version number to FW file name
+ 將版本號添加到韌體文件的文件名中
+
+
+
+
+
+
+
+
+
+
+ Offer to write FW to Tx after download
+ 下載完成後提示將韌體寫入到遙控器
+
+
+
+
+
+
+
+
+
+
+ Action on New Model
+
+
+
+
+
+
+
+
+
+
+
+ Screenshot capture folder
+
+
+
+
+
+
+
+
+
+
+
+ Clear Image
+ 清除圖片
+
+
+
+
+
+
+
+
+
+
+ Select Image
+ 遙控器檔案中
+ 選擇圖片
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Select Folder
+ 選擇目錄
+
+
+
+
+
+
+
+
+
+
+ Application Settings
+ 程序首選項
+
+
+
+
+
+
+
+
+
+
+ Automatic check for Companion updates
+ 自動檢查 Companion 版本更新
+
+
+
+
+
+
+
+
+
+
+ most recently used files
+
+
+
+
+
+
+
+
+
+
+
+ Startup Settings
+
+
+
+
+
+
+
+
+
+
+
+ Remember
+
+
+
+
+
+
+
+
+
+
+
+ Show splash screen when Companion starts
+ Companion 啟動時顯示啟動畫面
+
+
+
+
+
+
+
+
+
+
+ Automatic check for OpenTX firmware updates
+ 自動檢查 OpenTX 韌體版本更新
+
+
+
+
+
+
+
+
+
+
+ Output Logs Folder
+
+
+
+
+
+
+
+
+
+
+
+ <html><head/><body><p>This option maintains the behaviour from older OpenTx versions where empty model slots are preserved when a model is deleted or moved. </p><p>When this option is de-selected, the other models may be re-arranged to fill the gap left by the removed model.</p></body></html>
+
+
+
+
+
+
+
+
+
+
+
+ Remove empty model slots when deleting models (only applies for radios w/out categories)
+
+
+
+
+
+
+
+
+
+
+
+ Use model wizard
+
+
+
+
+
+
+
+
+
+
+
+ Open model editor
+
+
+
+
+
+
+
+
+
+
+
+ Just create the model
+
+
+
+
+
+
+
+
+
+
+
+ Debug Output Logging
+
+
+
+
+
+
+
+
+
+
+
+ <html><head/><body><p>Keep a log of all debugging messages generated by the desktop Companion/Simulator applications. An OpenTX developer may request this to help diagnose an issue.</p></body></html>
+
+
+
+
+
+
+
+
+
+
+
+ Application (Companion/Simulator)
+
+
+
+
+
+
+
+
+
+
+
+ <html><head/><body><p>Keep a log of all messages generated by the radio firmware when running in Simulator. This is the same information one would also see in the Simulator <span style=" font-style:italic;">Debug Output</span> window.</p></body></html>
+
+
+
+
+
+
+
+
+
+
+
+ Radio Firmware (in Simulator)
+
+
+
+
+
+
+
+
+
+
+
+ Splash Screen Library
+ 開機畫面圖片庫
+
+
+
+
+
+
+
+
+
+
+ Google Earth Executable
+ Google Earch 可執行文件
+
+
+
+
+
+
+
+
+
+
+ User Splash Screens
+ 自定義開機畫面
+
+
+
+
+
+
+
+
+
+
+ Automatic Backup Folder
+ 自動備份目錄
+
+
+
+
+
+
+
+
+
+
+ Only show user splash images
+ 只顯示自定義開機畫面
+
+
+
+
+
+
+
+
+
+
+ Show user and companion splash images
+ 顯示自定義和系統開機畫面
+
+
+
+
+
+
+
+
+
+
+ Select Executable
+ 選擇可執行文件
+
+
+
+
+
+
+
+ Release channel
+
+
+
+
+
+
+
+
+ Releases (stable)
+
+
+
+
+
+
+
+
+ Release candidates (testing)
+
+
+
+
+
+
+
+
+ Nightly builds (unstable)
+
+
+
+
+
+
+
+
+
+
+
+ Simulator Settings
+ 模擬器設置
+
+
+
+
+
+
+
+
+
+
+ Calibrate
+ 校準
+
+
+
+
+
+
+
+
+
+
+ Blue
+ 藍色
+
+
+
+
+
+
+
+
+
+
+ Green
+ 綠色
+
+
+
+
+
+
+
+
+
+
+ Red
+ 紅色
+
+
+
+
+
+
+
+
+
+
+ Orange
+ 橙色
+
+
+
+
+
+
+
+
+
+
+ Yellow
+ 黄色
+
+
+
+
+
+
+
+
+
+
+ Only capture to clipboard
+ 只截圖到剪貼板中
+
+
+
+
+
+
+
+
+
+
+ Enable
+ 使用遊戲桿
+
+
+
+
+
+
+
+
+
+
+ Joystick
+ 遊戲桿
+
+
+
+
+
+
+
+
+
+
+ Simulator BackLight
+ 模擬器背光顏色
+
+
+
+
+
+
+
+
+
+
+ Remember simulator switch values
+ 關閉模擬器後記憶開關位置
+
+
+
+
+
+
+
+
+
+
+ Simulator Volume Gain
+ 模擬器音量調節
+
+
+
+ My Radio
+ 我的遙控器
+
+
+
+ <p><b>You cannot switch Radio Type or change Build Options while there are unsaved file changes. What do you wish to do?</b></p> <ul><li><i>Save All</i> - Save any open file(s) before saving Settings.<li><li><i>Reset</i> - Revert to the previous Radio Type and Build Options before saving Settings.</li><li><i>Cancel</i> - Return to the Settings editor dialog.</li></ul>
+
+
+
+
+ Select your snapshot folder
+ 選擇你的快照目錄
+
+
+
+ Note: Nightly builds are not available in this version, Release/RC update channel will be used.
+
+
+
+
+
+ No joysticks found
+ 找不到遊戲桿
+
+
+
+ EMPTY: No radio settings stored in profile
+ 空白:在遙控器檔案中找不到遙控器設定
+
+
+
+ AVAILABLE: Radio settings of unknown age
+ 允許:不明日期的遙控器設定
+
+
+
+ AVAILABLE: Radio settings stored %1
+ 允許:遙控器設定保存到 %1
+
+
+
+ Select your library folder
+ 對話框標題欄
+ 選擇你的圖片庫文件夾
+
+
+
+
+ Select your Models and Settings backup folder
+ 對話框標題欄
+ 選擇你的模型和設定備份文件夾
+
+
+
+ Select a folder for application logs
+
+
+
+
+ Select Google Earth executable
+ 對話框標題欄
+ 選擇 Google Earth 可執行文件
+
+
+
+ Select the folder replicating your SD structure
+ 對話框標題欄
+ 選擇模擬SD卡目錄結構的電腦文件夾
+
+
+
+ Open Image to load
+ 打開圖片並載入
+
+
+
+ Images (%1)
+ 圖片 (%1)
+
+
+
+
+
+ Use releases (stable)
+
+
+
+
+ Use release candidates (testing)
+
+
+
+
+
+
+ Use nightly builds (unstable)
+
+
+
+
+
+ Use releases and release candidates (testing)
+
+
+
+
+ BinEepromFormat
+
+
+ Error reading %1: %2
+
+
+
+
+ Cannot save EEPROM
+
+
+
+
+ Cannot open file %1:
+%2.
+
+
+
+
+ Error writing file %1:
+%2.
+ 寫入文件錯誤 %1:
+%2.
+
+
+
+ Invalid binary EEPROM file %1
+
+
+
+
+ Boards
+
+
+ Left Horizontal
+ 左搖桿水平方向
+
+
+
+ Left Vertical
+ 左搖桿垂直方向
+
+
+
+ Right Vertical
+ 右搖桿上下方向
+
+
+
+ Right Horizontal
+ 右搖桿水平方向
+
+
+
+ Aux. 1
+
+
+
+
+ Aux. 2
+
+
+
+
+
+ Unknown
+ 未知[Unknown]
+
+
+
+ Rud
+
+
+
+
+ Ele
+
+
+
+
+ Thr
+
+
+
+
+ Ail
+
+
+
+
+ CalibrationPanel
+
+
+ Negative span
+ 負範圍
+
+
+
+ Mid value
+ 中值
+
+
+
+ Positive span
+ 正範圍
+
+
+
+ CategorizedStorageFormat
+
+
+ Can't extract RADIO/radio.bin
+
+
+
+
+ Can't extract RADIO/models.txt
+
+
+
+
+ Can't extract %1
+
+
+
+
+ Error loading models
+
+
+
+
+ Channels
+
+
+ Name
+ 在舵機設置頁面中
+ 通道名稱 [Name]
+
+
+
+ Subtrim
+ 在舵機設置頁面中
+ 舵機中位 [Subtrim]
+
+
+
+ Min
+ 在舵機設置頁面中
+ 舵機下限 [Min]
+
+
+
+ Max
+ 在舵機設置頁面中
+ 舵機上限 [Max]
+
+
+
+ Direction
+ 在舵機設置頁面中
+ 舵機反向 [Dir]
+
+
+
+ Curve
+ 在舵機設置頁面中
+ 舵機曲線 [Curve]
+
+
+
+ PPM Center
+ 在舵機設置頁面中
+ PPM中位脈寬
+
+
+
+ Linear Subtrim
+ 在舵機設置頁面中
+ 線性微調 [Linear]
+
+
+
+ CH%1
+ 在舵機設置頁面中
+ 通道%1
+
+
+
+ Popup menu available
+
+
+
+
+ ---
+ 在舵機設置頁面中 表示舵機正向
+ 正向 [→]
+
+
+
+ INV
+ 在舵機設置頁面中
+ 反向 [←]
+
+
+
+ &Copy
+
+
+
+
+ &Cut
+ 剪下 (&C)
+
+
+
+ &Paste
+ 貼上 (&P)
+
+
+
+ &Delete
+ 删除 (&D)
+
+
+
+ ChecklistDialog
+
+
+
+
+
+
+
+
+
+ Edit Checklist
+
+
+
+
+
+
+
+
+
+
+
+ Line nn, Col nn
+
+
+
+
+
+
+
+
+
+
+
+ &Import...
+
+
+
+
+
+
+
+
+
+
+
+ &Cancel
+
+
+
+
+
+
+
+
+
+
+
+ &OK
+
+
+
+
+
+
+
+
+
+
+
+ Please note, the maximum width displayable is radio model limited. Also, renaming the model will break the link to this checklist file.
+
+
+
+
+
+
+
+
+
+
+
+ File: unknown
+
+
+
+
+ Open Checklist
+
+
+
+
+ Checklist Files (*.txt)
+
+
+
+
+
+
+
+
+ Model Checklist
+
+
+
+
+ Cannot open file for writing %1:
+%2.
+
+
+
+
+ Cannot write to file %1:
+%2.
+
+
+
+
+ Cannot write file %1:
+%2.
+ 無法寫入文件 %1:
+%2.
+
+
+
+ Cannot open file %1:
+%2.
+
+
+
+
+ Cannot read file %1:
+%2.
+
+
+
+
+ Line %1, Col %2
+
+
+
+
+ Companion
+
+
+ OpenTX Companion
+
+
+
+
+ Information
+ 信息
+
+
+
+ Warning
+ 啟用時蜂鳴 [Warning]
+
+
+
+ Error
+ 錯誤
+
+
+
+ Application Settings
+ 程序首選項
+
+
+
+ files
+
+
+
+
+ Radio and Models settings
+
+
+
+
+ Select or create a file for exported Settings:
+
+
+
+
+ Press the 'Retry' button to choose another file.
+
+
+
+
+ Simulator for this firmware is not yet available
+ 模擬器現在還不支持此版韌體
+
+
+
+ Uknown error during Simulator startup.
+
+
+
+
+ Simulator Error
+
+
+
+
+ Data Load Error
+
+
+
+
+ Error occurred while starting simulator.
+
+
+
+
+ <p><b>Welcome to OpenTX %1.</b></p><p>As the first step, please configure the initial Radio Profile by selecting your Radio Type, Menu Language, and Build Options.</p><p>You may also want to take this time to review the other available options in the displayed Settings dialog.</p><p>After saving your settings, we recommend you download the latest firmware for your radio by using the <i>File -> Download</i> menu option.</p><p>Please visit <a href='http://www.open-tx.org'>open-tx.org</a> for latest news, updates and documentation. Thank you for choosing OpenTX!</p>- The OpenTX Team.
+
+
+
+
+ <p><b>Thank you for upgrading to OpenTX %1.</b></p><p>This is a major upgrade that adds and modifies a lot of things, so please make sure that you read release notes carefully to learn about the changes, and thoroughly check each of your models for proper function.</p><p>Please visit <a href='http://www.open-tx.org'>open-tx.org</a> for release notes and other documentation.</p>- The OpenTX Team.
+
+
+
+
+ <p>The radio type in the selected profile does not exist. Using the default type instead.</p> <p><b>Please update your profile settings!</b></p>
+
+
+
+
+ The saved settings could not be imported, please try again or continue with current settings.
+
+
+
+
+ Import from File
+
+
+
+
+ Import from v%1
+
+
+
+
+ Do not import
+
+
+
+
+ We have found possible Companion settings backup file(s).
+Do you want to import settings from a file?
+
+
+
+
+ Import settings from a file, or start with current values.
+
+
+
+
+ We have found existing settings for Companion version: %1.
+Do you want to import them?
+
+If you have a settings backup file, you may import that instead.
+
+
+
+
+ Select %1:
+
+
+
+
+ Save application settings to file...
+
+
+
+
+ Load application settings from file or previous version...
+
+
+
+
+ Reset ALL application settings to default and remove radio profiles...
+
+
+
+
+ Exit before settings initialization and application startup.
+
+
+
+
+ Print version number and exit.
+
+
+
+
+ Print this help text.
+
+
+
+
+ Reset ALL application settings to default values and remove radio profiles, are you sure?
+
+
+
+
+ Would you like to perform a backup first?
+
+
+
+
+ Application settings were reset and saved.
+
+
+
+
+ settings
+
+
+
+
+ CompareDialog
+
+
+
+
+
+
+
+
+
+ Compare Models
+ Compare 模型對比對話框
+ 比較模型參數
+
+
+
+
+
+
+
+
+
+
+ To compare models, drag and drop them anywhere in this window.
+
+
+
+
+
+
+
+
+
+
+
+ Close
+ Compare 模型對比對話框
+ 关闭
+
+
+
+
+
+
+
+
+
+
+ Style
+
+
+
+
+
+
+
+
+
+
+
+ Print
+ Compare 模型對比對話框
+ 打印
+
+
+
+
+
+
+
+
+
+
+ Print to file
+ Compare 模型對比對話框
+ 列印到文件
+
+
+
+ Unnamed Model %1
+
+
+
+
+ Click to remove this model.
+
+
+
+
+ Print Document
+ Compare 模型對比對話框
+ 列印到文檔
+
+
+
+ Select PDF output file
+ Compare 模型對比對話框
+ 選擇PDF輸出文件
+
+
+
+ ConclusionPage
+
+
+ OK, I understand.
+ ConclusionPage 模型配置頁面最後確認按鈕中使用
+ 好的, 我知道。
+
+
+
+ CopyProcess
+
+
+ Write error
+ CopyProcess
+ 寫入錯誤
+
+
+
+ Cannot write %1 (reason: %2)
+ CopyProcess
+ 無法寫入 %1 (原因: %2)
+
+
+
+ Cannot open %1 (reason: %2)
+ CopyProcess
+ 無法打開 %1 (原因: %2)
+
+
+
+ CreditsDialog
+
+
+ OpenTX Contributors
+ OpenTX 貢獻者
+
+
+
+ Honors go to Rafal Tomczak (RadioClone), Thomas Husterer (th9x) and Erez Raviv (er9x and eePe)
+ 榮譽給予 Rafal Tomczak (RadioClone), Thomas Husterer (th9x) 和 Erez Raviv (er9x and eePe)
+
+
+
+ OpenTX Blacklist
+ OpenTX 黑名單
+
+
+
+ Main developers
+
+
+
+
+ Translators
+
+
+
+
+ Companies and projects who have donated to OpenTX
+ 曾經給予OpenTX捐贈的公司和項目
+
+
+
+ People who have donated to OpenTX
+ 曾經給予OpenTX捐贈的個人
+
+
+
+ Other contributors
+ 其他貢獻者
+
+
+
+ monthly
+ 每月
+
+
+
+ CurveData
+
+
+ CV
+
+
+
+
+ CurveGroup
+
+
+ Diff
+ 用於INPUT和MIXER曲線選擇項
+ 差動曲線 [Diff]
+
+
+
+ Expo
+ 用於INPUT和MIXER曲線選擇項
+ 指數曲線 [Expo]
+
+
+
+ Func
+ 用於INPUT和MIXER曲線選擇項
+ 其他曲線 [Func]
+
+
+
+ Curve
+ 用於INPUT和MIXER曲線選擇項
+ 多點曲線 [Cstm]
+
+
+
+ CurveReference
+
+
+ Diff(%1)
+
+
+
+
+ Expo(%1)
+
+
+
+
+ Function(%1)
+
+
+
+
+ Curve(%1)
+
+
+
+
+ Curves
+
+
+
+
+
+
+
+
+
+ Curve name
+ 曲線名稱 [Name]
+
+
+
+
+
+
+
+
+
+
+ Fixed X
+ 均勻間距 [Standard]
+
+
+
+
+
+
+
+
+
+
+ Custom X
+ 自定間距 [Custom]
+
+
+
+
+
+
+
+
+
+
+ Lines
+ 折線
+
+
+
+
+
+
+
+
+
+
+ Smooth
+ 平滑 [Smooth]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Curve type
+ 曲線類型
+
+
+
+
+
+
+
+
+
+
+ Curve Creator
+ 曲線生成器
+
+
+
+
+
+
+
+
+
+
+ Y at X=0
+ 曲線中央的高度
+
+
+
+
+
+
+
+
+
+
+ Point size
+
+
+
+
+
+
+
+
+
+
+
+ Y at X=100
+ 曲線最右側高度
+
+
+
+
+
+
+
+
+
+
+ Both
+ 兩側
+
+
+
+
+
+
+
+
+
+
+ x>0
+ 僅創建右側曲線
+
+
+
+
+
+
+
+
+
+
+ x<0
+ 僅創建左側曲線
+
+
+
+
+
+
+
+
+
+
+ Apply
+ 應用
+
+
+
+
+
+
+
+
+
+
+ Side
+ 僅創建單側曲線
+
+
+
+
+
+
+
+
+
+
+ Y at X=-100
+ 曲線最左側高度
+
+
+
+
+
+
+
+
+
+
+ Coefficient
+ 彎曲係數
+
+
+
+ Curve %1
+ 曲線 %1
+
+
+
+ Popup menu available
+
+
+
+
+ %1 points
+ %1 點
+
+
+
+ Linear
+ 直線
+
+
+
+ Single Expo
+ 非對稱指數曲線
+
+
+
+ Symmetrical f(x)=-f(-x)
+ 左右中心對稱
+
+
+
+ Symmetrical f(x)=f(-x)
+ 左右鏡像對稱
+
+
+
+ Editing curve %1
+ 編輯曲線 %1
+
+
+
+ Not enough free points in EEPROM to store the curve.
+ EEPROM中沒有足夠的空餘曲線點存儲空間.
+
+
+
+ Copy
+ 複製
+
+
+
+ Paste
+ 貼上
+
+
+
+ Clear
+ curve
+ 清除
+
+
+
+ Clear all curves
+ 清除所有曲線
+
+
+
+ Are you sure you want to reset curve %1?
+ 你確定想要重置曲線%1嗎?
+
+
+
+ Are you sure you want to reset all curves?
+ 你確定想要重置全部曲線嗎?
+
+
+
+ CustomFunctionData
+
+
+ GF
+
+
+
+
+ SF
+
+
+
+
+ Override %1
+ 鎖定通道值 %1 [Override]
+
+
+
+ Trainer
+ 教練功能
+
+
+
+ Trainer RUD
+ 教練開關 方向 [Trainer RUD]
+
+
+
+ Trainer ELE
+ 教練開關 升降 [Trainer ELE]
+
+
+
+ Trainer THR
+ 教練開關 油門 [Trainer THR]
+
+
+
+ Trainer AIL
+ 教練開關 副翼 [Trainer AIL]
+
+
+
+ Instant Trim
+ 操縱杆位變微調 [Instant Trim]
+
+
+
+ Play Sound
+ 播放蜂鳴 [Play Sound]
+
+
+
+ Haptic
+ 震動 [Haptic]
+
+
+
+ Reset
+ 重設
+
+
+
+ Set Timer %1
+ 設定計時器%1 [Set Timer]
+
+
+
+ Vario
+ 開啟 Vario 聲音 [Vario]
+
+
+
+ Play Track
+ 播放聲音文件 [Play Track]
+
+
+
+ Play Both
+ 播放同時振動 [Play Both]
+
+
+
+ Play Value
+ 播放數值 [Play Value]
+
+
+
+ Play Script
+ 運行腳本 [Play Script]
+
+
+
+ SD Logs
+ SD Log 記錄 [SD Logs]
+
+
+
+ Volume
+ 音量 [Volume]
+
+
+
+ Backlight
+ 背光 [Backlight]
+
+
+
+ Screenshot
+ 截屏 [Screenshot]
+
+
+
+ Background Music
+ 背景音樂播放 [Bg Music]
+
+
+
+ Background Music Pause
+ 背景音樂暫停 [Bg Music Pause]
+
+
+
+ Adjust %1
+
+
+
+
+ SetFailsafe Int. Module
+ 啟動內置高頻頭失控保護 [SetFailsafe Int]
+
+
+
+ SetFailsafe Ext. Module
+ 啟動外置高頻頭失控保護 [SetFailsafe Ext]
+
+
+
+ RangeCheck Int. Module
+ 內置高頻頭拉距測試
+
+
+
+ RangeCheck Ext. Module
+ 外置高頻頭拉距測試
+
+
+
+ Bind Int. Module
+ 內置高頻頭對頻
+
+
+
+ Bind Ext. Module
+ 外置高頻頭對頻
+
+
+
+ Timer1
+ 計時器1 [Timer1]
+
+
+
+ Timer2
+ 計時器2 [Timer2]
+
+
+
+ Timer3
+ 計時器3 [Timer3]
+
+
+
+ Flight
+ 飛行 [Flight]
+
+
+
+ Telemetry
+
+
+
+
+ Rotary Encoder
+ 旋轉編碼器 [Rotary Encoder]
+
+
+
+ REa
+
+
+
+
+ REb
+
+
+
+
+ s
+
+
+
+
+
+
+ <font color=red><b>Inconsistent parameter</b></font>
+ <font color=red><b>不一致的參數</b></font>
+
+
+
+ Value
+ 值
+
+
+
+ played once, not during startup
+ 播放一次但開機時不播放
+
+
+
+ repeat(%1s)
+ 每%1秒重複
+
+
+
+ DISABLED
+ 禁用
+
+
+
+ CFN
+
+
+
+
+ CustomFunctionsPanel
+
+
+ Switch
+ CustomFunctionPanel
+ 啟動開關
+
+
+
+ Action
+ CustomFunctionPanel
+ 功能
+
+
+
+ Parameters
+ CustomFunctionPanel
+ 参数
+
+
+
+ Enable
+ CustomFunctionPanel
+ 是否啟用
+
+
+
+ Popup menu available
+
+
+
+
+ SF%1
+ CustomFunctionPanel
+ SF%1
+
+
+
+ GF%1
+ CustomFunctionPanel
+ GF%1
+
+
+
+ ON
+ CustomFunctionPanel
+ 啟用
+
+
+
+ Error occurred while trying to play sound, possibly the file is already opened. (Err: %1 [%2])
+
+
+
+
+ Unable to find or open sound file:
+%1
+
+
+
+
+ Value
+ 设为
+
+
+
+ Source
+
+
+
+
+ GVAR
+ GVAR
+
+
+
+ Increment
+ 增加
+
+
+
+ &Copy
+ CustomFunctionPanel
+ 複製 (&C)
+
+
+
+ &Cut
+ CustomFunctionPanel
+ 剪下 (&C)
+
+
+
+ &Paste
+ CustomFunctionPanel
+ 貼上 (&P)
+
+
+
+ &Delete
+ CustomFunctionPanel
+ 删除 (&D)
+
+
+
+ CustomizeSplashDialog
+
+
+
+
+
+
+
+
+
+ Transmitter Splash Screen Editor
+ 遙控器開機畫面編輯器
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Invert
+ 底片效果
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Open Splash Library
+ 打開開機圖片庫
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ...
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Load Profile
+ 載入遙控文檔
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Load FW
+ 載入韌體
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Load Pict
+ 載入圖片文件
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Save
+ 保存
+
+
+
+ Open Firmware File
+ 打開韌體文件
+
+
+
+ FW: %1
+ 韌體: %1
+
+
+
+ Pict: %1
+ 圖片: %1
+
+
+
+ Profile image
+ 檔案圖片
+
+
+
+ Can not load embedded image from firmware file %1.
+ 不能從韌體文件 %1 中載入內嵌圖片 .
+
+
+
+ Open Image to load
+ 打開圖片文件以載入
+
+
+
+ Images (%1)
+ 圖片 (%1)
+
+
+
+ Cannot load the image file %1.
+ 不能打開圖片文件 %1.
+
+
+
+ Cannot load profile image %1.
+ 不能打開遙控器文檔中圖片 %1.
+
+
+
+ Cannot load the library image %1.
+ 不能從開機圖片庫中載入圖片 %1.
+
+
+
+ File Saved
+ 文件已保存
+
+
+
+ The image was saved to the file %1
+ 圖片已經保存到 %1
+
+
+
+ Image Refresh Error
+ 圖片刷新錯誤
+
+
+
+ Failed to refresh image from file %1
+ 無法從文件 %1 中刷新圖片
+
+
+
+ File Save Error
+ 文件保存錯誤
+
+
+
+ Failed to write image to %1
+ 無法寫入文件 %1
+
+
+
+ CyclicPage
+
+
+ 90
+ 90
+
+
+
+ 120
+ 120
+
+
+
+ 120x
+ 120x
+
+
+
+ 140
+ 140
+
+
+
+ DataField
+
+
+ Conversion error on field %1
+
+
+
+
+ Switch
+
+
+
+
+ Switch
+ 啟動開關
+
+
+
+ cannot be exported on this board!
+ 無法輸出到這個主板!
+
+
+
+ Source
+
+
+
+
+ Source %1 cannot be exported on this board!
+ 源 %1 無法輸出到這個主板!
+
+
+
+ OpenTX only accepts %1 points in all curves
+ OpenTX只允許最大%1點曲線
+
+
+
+ OpenTx only accepts %1 points in all curves
+ OpenTX只允許最大%1點曲線
+
+
+
+
+ OpenTX on this board doesn't accept this function
+ OpenTX在這個主板上不支持此項功能
+
+
+
+ OpenTX doesn't accept this radio protocol
+ OpenTX 不接受此遙控器協議
+
+
+
+ DebugOutput
+
+
+
+
+
+
+
+
+
+
+
+ Debug Output
+ Debug 輸出
+
+
+
+
+
+
+
+
+
+
+
+
+ <html><head/><body><p>Enable or disable the filter. If the button won't stay enabled, it is likely there is a syntax error in the Regular Expression entered.</p></body></html>
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Filter:
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <html><head/><body><p>Enter filter text here. Click the help/info button for details about using the filter. </p><p>
+To <b>remove a remembered entry</b> from the filter list, first choose it, and then press <code>Shift-Delete</code> (or <code>Shift-Backspace</code>) key combination.</p></body></html>
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Buffer:
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Number of lines to keep in display.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Filter &Help
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Show information about using the filter.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Word &Wrap
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Toggle word wrapping on/off.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ &Clear
+ (&C)清除
+
+
+
+
+
+
+
+
+
+
+
+
+ Clear the output window of all text.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Enable &Filter
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Turn the filter on/off.
+
+
+
+
+ <html><head><style>kbd {background-color: palette(alternate-base); font-size: large; white-space: nowrap;}</style></head><body><p>The filter supports two syntax types: basic matching with common wildcards as well as full Perl-style (<code>pcre</code>) Regular Expressions.</p><p>By default a filter will only show lines which match (<b>inclusive</b>). To make an <b>exclusive</b> filter which removes matching lines, prefix the filter expression with a <kbd>!</kbd> (exclamation mark).</p><p>To use <b>Regular Expressions</b> (RegEx), prefix the filter text with a <kbd>/</kbd> (slash) or <kbd>^</kbd> (up caret). <ul><li>Put the <kbd>/</kbd> or <kbd>^</kbd> after the exclusive <kbd>!</kbd> indicator if you're using one.</li><li>By default the match is case-sensitive. To make it insensitive, add the typical <kbd>/i</kbd> (slash i) operator at the end of your RegEx.</li><li>If you use a caret (^) to denote a RegEx, it will become part of the Reg. Ex. (that is, matches from start of line).</li><li>If the RegEx is invalid, the filter edit field should show a red border and you will not be able to enable the filter.</li><li>A useful resource for testing REs (with a full reference) can be found at <a href="http://www.regexr.com/">http://www.regexr.com/</a></li></ul></p><p>To use <b>basic matching</b> just type any text.<ul><li>Wildcards: <kbd>*</kbd> (asterisk) matches zero or more of any character(s), and <kbd>?</kbd> (question mark) matches any single character.</li><li>The match is always case-insensitive.</li><li>The match always starts from the beginning of a log line. To ignore characters at the start, use a leading <kbd>*</kbd> wildcard.</li><li>A trailing <kbd>*</kbd> is always implied (that is, matches anything to the end of the log line). To avoid this, use a RegEx.</li><li>You can match literal wildcard characters by prefixing them with a <kbd>\</kbd> (backslash) character (eg. "foo\*bar" matches "foo*bar").</li></ul></p><p>After <b>editing text</b>, press ENTER or TAB key (or click anywhere outside the box) to update the filter.</p><p>To <b>remove an entry</b> from the filter selector list, first choose it, and while in the line editor press <kbd>Shift-Delete</kbd> (or <kbd>Shift-Backspace</kbd>) key combination. The default filters cannot be removed. Up to 50 filters are stored.</p></body></html>
+
+
+
+
+ Debug Console Filter Help
+
+
+
+
+ DownloadDialog
+
+
+
+
+
+
+
+
+
+ Downloading:
+ 下載中:
+
+
+
+ Unable to save the file %1: %2.
+ 無法保存文件 %1:
+%2.
+
+
+
+ Download failed: %1.
+ 下載失敗:%1.
+
+
+
+ EEPROMInterface
+
+
+ Possible causes for this:
+ 可能導致這樣的原因:
+
+
+
+ - Eeprom is from a newer version of OpenTX
+ - Eeprom 來自 OpenTX 的新版本
+
+
+
+ - Eeprom is not from OpenTX
+ - Eeprom 不是來自 OpenTX
+
+
+
+ - Eeprom is not from Th9X
+ - Eeprom 不是來自 Th9x
+
+
+
+ - Eeprom is not from Gruvin9X
+ - Eeprom 不是來自 Gruvin9x
+
+
+
+ - Eeprom is not from ErSky9X
+ - Eeprom 不是來自 ErSky9X
+
+
+
+ - Eeprom is not from Er9X
+ - Eeprom 不是來自 Er9x
+
+
+
+ - Eeprom size is invalid
+ - Eeprom 文件大小錯誤
+
+
+
+ - Eeprom file system is invalid
+ - Eeprom 文件系统錯誤
+
+
+
+ - Eeprom is from a unknown board
+ - Eeprom 來自未知的主板
+
+
+
+ - Eeprom is from the wrong board
+ - Eeprom 來自錯誤的主板
+
+
+
+ - Eeprom backup not supported
+ - 不支持 Eeprom 備份
+
+
+
+ - Something that couldn't be guessed, sorry
+ - 抱歉,無法找出確定原因
+
+
+
+ Warning:
+ 警告:
+
+
+
+
+ - Your radio probably uses a wrong firmware,
+ eeprom size is 4096 but only the first 2048 are used
+ - 你的遙控器可能使用了錯誤的韌體,
+ eeprom 大小為4096但僅前半部分的2048被使用
+
+
+
+ - Your eeprom is from an old version of OpenTX, upgrading!
+ To keep your original file as a backup, please choose File -> Save As specifying a different name.
+
+
+
+
+ EepeFormat
+
+
+ Unable to open %1: %2
+
+
+
+
+ Invalid EEPROM file %1
+
+
+
+
+ ElevonsPage
+
+
+ <br>First Elevon Channel:
+ <br>指定第1個升降副翼舵機通道:
+
+
+
+ Second Elevon Channel:
+ <br>指定第2個升降副翼舵機通道:
+
+
+
+ ExpoData
+
+
+ INP
+
+
+
+
+ (@%1)
+
+
+
+
+ ExpoDialog
+
+
+
+
+
+
+
+
+
+ Flight modes
+ Inputs對話框
+ 飛行模式 [Modes]
+
+
+
+
+
+
+
+
+
+
+ Input name
+ Inputs對話框
+ 輸入名稱 [Input]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GV
+ Inputs對話框
+ GV
+
+
+
+
+
+
+
+
+
+
+ Source for the mixer.
+ Inputs對話框
+ 混控的輸入源.
+
+
+
+
+
+
+
+
+
+
+ Weight
+ Inputs對話框
+ 比例 [Weight]
+
+
+
+
+
+
+
+
+
+
+ Switch
+ Inputs對話框
+ 啟用開關 [Switch]
+
+
+
+
+
+
+
+
+
+
+ Switch used to enable the line.
+If blank then the input is considered to be "ON" all the time.
+ Inputs對話框
+ 啟用開關
+不選擇則默認一直啟用.
+
+
+
+
+
+
+
+
+
+
+ Stick Side
+ Inputs對話框
+ 搖桿作用於 [Side]
+
+
+
+
+
+
+
+
+
+
+ NEG
+ Inputs對話框
+ 負側 [NEG]
+
+
+
+
+
+
+
+
+
+
+ POS
+ Inputs對話框
+ 正侧 [POS]
+
+
+
+
+
+
+
+
+
+
+ ALL
+ Inputs對話框
+ 兩側 [ALL]
+
+
+
+
+
+
+
+
+
+
+ Scale
+ Inputs對話框
+ 縮放 [Scale]
+
+
+
+
+
+
+
+
+
+
+ Include Trim
+ Inputs對話框
+ 微調 [Trim]
+
+
+
+
+
+
+
+
+
+
+ No
+ Inputs對話框
+ 不使用 [OFF]
+
+
+
+
+
+
+
+
+
+
+ Yes
+ Inputs對話框
+ 使用 [On]
+
+
+
+
+
+
+
+
+
+
+ Curve
+ Inputs對話框
+ 曲線 [Curve]
+
+
+
+
+
+
+
+
+
+
+ Curve applied to the source.
+ Inputs對話框
+ 作用於輸入源的曲線.
+
+
+
+
+
+
+
+
+
+
+ Source
+ Inputs對話框
+ 輸入來源 [Source]
+
+
+
+
+
+
+
+
+
+
+ Line name
+ Inputs對話框
+ 此條名稱 [Line]
+
+
+
+
+
+
+
+
+
+
+ Offset
+ Inputs對話框
+ 偏移 [Offset]
+
+
+
+
+
+
+
+
+
+
+ The source for the mixer
+ Inputs對話框
+ 混控的輸入源
+
+
+
+ Edit %1
+ Inputs對話框
+ 編輯 %1
+
+
+
+ Popup menu available
+
+
+
+
+ Clear All
+
+
+
+
+ Set All
+
+
+
+
+ Invert All
+
+
+
+
+ ExportableTableView
+
+
+ Select All
+
+
+
+
+ Copy selection as TAB-delimited text
+
+
+
+
+ Copy selection as cooma-delimited text (CSV)
+
+
+
+
+ Copy selection as pipe-delimited text
+
+
+
+
+ Copy selection as HTML
+
+
+
+
+ Save selection to file
+
+
+
+
+ Tab-delimited text
+
+
+
+
+ Comma-delimited text
+
+
+
+
+ Pipe-delimited text
+
+
+
+
+ HTML
+
+
+
+
+ Save to file
+
+
+
+
+ FblPage
+
+
+ Throttle Channel:
+ 油門通道 [Throttle]:
+
+
+
+ Yaw Channel:
+ 偏航通道 [Yaw]:
+
+
+
+ Pitch Channel:
+ 仰俯通道 [Pitch]:
+
+
+
+ Roll Channel:
+ 滾轉通道 [Roll]:
+
+
+
+ FileSyncDialog
+
+
+ Synchronize Files
+
+
+
+
+ Are you sure you wish to abort the sync?
+
+
+
+
+ Source Folder:
+
+
+
+
+ Destination Folder:
+
+
+
+
+ %1%2 Both directions, to destination folder first
+
+
+
+
+ %1%2 Both directions, to source folder first
+
+
+
+
+ %1 Only from source folder to destination folder
+
+
+
+
+ %1 Only from destination folder to source folder
+
+
+
+
+ How to handle overwriting files which already exist in the destination folder.
+
+
+
+
+ Copy only if newer and different (compare contents)
+
+
+
+
+ Copy only if newer (do not compare contents)
+
+
+
+
+ Copy only if different (ignore file time stamps)
+
+
+
+
+ Always copy (force overwite existing files)
+
+
+
+
+ Any size
+
+
+
+
+ Skip files larger than this size. Enter zero for unlimited.
+
+
+
+
+ Minimum reporting level. Events of this type and of higher importance are shown.
+WARNING: High log rates may make the user interface temporarily unresponsive.
+
+
+
+
+ Skipped
+
+
+
+
+ Created
+
+
+
+
+ Updated
+
+
+
+
+ Errors Only
+
+
+
+
+ Test-run only
+
+
+
+
+ Run as normal but do not actually copy anything. Useful for verifying results before real sync.
+
+
+
+
+ Log Level:
+
+
+
+
+ Filters:
+
+
+
+
+ The "Include" filter will only copy files which match the pattern(s).
+The "Exclude" filter will skip files matching the filter pattern(s).
+The Include filter is evaluated first.
+
+
+
+
+ One or more file pattern(s) to exclude, separated by commas.
+Blank means exclude none. ?, *, and [...] wildcards accepted.
+
+
+
+
+ One or more file pattern(s) to include, separated by commas.
+Blank means include all. ?, *, and [...] wildcards accepted.
+
+
+
+
+ Include:
+
+
+
+
+ Exclude:
+
+
+
+
+ Case sensitive
+
+
+
+
+
+ Follow links
+
+
+
+
+ Include hidden
+
+
+
+
+ Recursive
+
+
+
+
+ Skip empty
+
+
+
+
+ Apply filters
+
+
+
+
+ Filter Options:
+
+
+
+
+ Folder Options:
+
+
+
+
+
+ Options
+
+
+
+
+ Show extra options
+
+
+
+
+ Reset to defaults
+
+
+
+
+ Close
+ 關閉
+
+
+
+ Sync. Direction:
+
+
+
+
+ Existing Files:
+
+
+
+
+ Max. File Size:
+
+
+
+
+ MB
+
+
+
+
+ KB
+
+
+
+
+ Abort
+
+
+
+
+ Start
+ 開始通道 [CH]
+
+
+
+ Total: <b>%1</b>; Created: <b>%2</b>; Updated: <b>%3</b>; Skipped: <b>%4</b>; Errors: <font color=%6><b>%5</b></font>;
+
+
+
+
+ Current: <b>%1</b> of
+
+
+
+
+ Source folder not found.
+
+
+
+
+ Destination folder not found.
+
+
+
+
+ Source and destination folders are the same.
+
+
+
+
+ Firmware
+
+
+ Channel values displayed in us
+ 通道值顯示為微秒
+
+
+
+ No OverrideCH functions available
+ 不允許鎖定通道值功能
+
+
+
+ Possibility to enable FAI MODE (no telemetry) at field
+ 可選擇啟用 FAI 模式 (沒有回傳)
+
+
+
+ FAI MODE (no telemetry) always enabled
+ 一直啟用 FAI 模式 (沒有回傳)
+
+
+
+ Removes D8 FrSky protocol support which is not legal for use in the EU on radios sold after Jan 1st, 2015
+ 移除 D8 FrSky 協議支持,因為在20151月1日後在歐洲銷售的遙控器中使用此協議是不合法的
+
+
+
+
+ Disable HELI menu and cyclic mix support
+ 禁用直升機菜單和CCPM混控菜單
+
+
+
+
+ Disable Global variables
+ 禁用GV[Global variables]功能
+
+
+
+
+ Enable Lua custom scripts screen
+
+
+
+
+ Use alternative SQT5 font
+ 使用 另一個 SQT5 font
+
+
+
+ Pots use in menus navigation
+ 使用旋鈕進行菜單導航
+
+
+
+ FrSky Taranis X9D+
+ FrSky Taranis X9D+
+
+
+
+ Support for PPM internal module hack
+ 支持 hack PPM內置高頻頭
+
+
+
+ Enable non certified firmwares
+
+
+
+
+ Disable RAS (SWR)
+
+
+
+
+ FrSky Taranis X9D+ 2019
+
+
+
+
+ FrSky Taranis X9D
+ FrSky Taranis X9D
+
+
+
+ Haptic module installed
+ 振動模塊已經安裝
+
+
+
+ FrSky Taranis X9E
+ FrSky Taranis X9E
+
+
+
+ Confirmation before radio shutdown
+ 遙控器關機前確認
+
+
+
+ Horus gimbals installed (Hall sensors)
+ Horus 搖桿已安裝 (霍爾傳感器)
+
+
+
+ FrSky Taranis X9-Lite
+
+
+
+
+
+ Support for auto update on boot
+
+
+
+
+ FrSky Taranis X7 / X7S
+
+
+
+
+ FrSky Taranis X-Lite S/PRO
+
+
+
+
+ FrSky Taranis X-Lite
+
+
+
+
+ FrSky Horus X10 / X10S
+
+
+
+
+ FrSky Horus X12S
+
+
+
+
+ Use ONLY with first DEV pcb version
+ 只用與 DEV pcb 版本
+
+
+
+ Turnigy 9XR-PRO
+ Turnigy 9XR-PRO
+
+
+
+ Enable HELI menu and cyclic mix support
+ 允許直升機菜單和斜盤混控支持
+
+
+
+ Global variables
+ GV [Global variables]
+
+
+
+ In model setup menus automatically set source by moving the control
+ 在模型配置菜單通過移動搖桿自動設置源
+
+
+
+ In model setup menus automatically set switch by moving the control
+ 在模型配置菜單通過撥動開關自動設置源
+
+
+
+ No graphical check boxes and sliders
+ 無圖形選擇框和滑桿
+
+
+
+ Battery graph
+ 電池圖標
+
+
+
+ Don't use bold font for highlighting active items
+ 不使用粗體高亮活動項目
+
+
+
+
+ Support for ACCESS internal module replacement
+
+
+
+
+ FrSky Horus X10 Express
+
+
+
+
+ Jumper T12
+
+
+
+
+ Enable non certified R9M firmwares
+
+
+
+
+ Turnigy 9XR with m128 chip
+ Turnigy 9XR (m128芯片)
+
+
+
+ Turnigy 9XR
+ Turnigy 9XR
+
+
+
+ 9X with stock board
+ 9X (原装主板)
+
+
+
+ Enable resetting values by pressing up and down at the same time
+ 允許通過同時按上下鍵重設數值
+
+
+
+ 9X with stock board and m128 chip
+ 9X (原裝主板和m128芯片)
+
+
+
+ 9X with AR9X board
+ 9X (AR9X主板)
+
+
+
+ 9X with Sky9x board
+ 9X (Sky9x主板)
+
+
+
+ 9X with Gruvin9x board
+ 9X (Gruvin9x主板)
+
+
+
+ DIY MEGA2560 radio
+ DIY的 MEGA2560 遥控器
+
+
+
+ FirmwarePreferencesDialog
+
+
+
+
+
+
+
+
+
+ Downloads
+ FirmwarePref
+ 下載
+
+
+
+
+
+
+
+
+
+
+ Check for updates
+ FirmwarePref
+ 檢查更新
+
+
+
+
+
+
+
+
+
+
+ Firmware
+ FirmwarePref
+ 韌體類型
+
+
+
+
+
+
+
+
+
+
+ Download firmware
+
+
+
+
+
+
+
+
+
+
+
+ Download SD contents
+
+
+
+
+
+
+
+
+
+
+
+ Latest Download
+ FirmwarePref
+ 最後下載的韌體版本
+
+
+
+ Unknown
+ 未知[Unknown]
+
+
+
+ FlapsPage
+
+
+ No
+ FlapsPage
+ 没有襟翼
+
+
+
+ Yes, controlled by a single channel
+ 有襟翼, 使用一個單通道控制
+
+
+
+ Yes, controlled by two channels
+ 有襟翼, 使用兩個通道控制
+
+
+
+ <br>First Flap Channel:
+ <br>第一個襟翼通道:
+
+
+
+ Second Flap Channel:
+ 第二個襟翼通道:
+
+
+
+ FlashEEpromDialog
+
+
+
+
+
+
+
+
+
+
+ Write Models and Settings to Radio
+ 將模型和設置寫入到遙控器
+
+
+
+
+
+
+
+
+
+
+ Load...
+ 加載...
+
+
+
+
+
+
+
+
+
+
+ Current Profile
+ 當前文檔
+
+
+
+
+
+
+
+
+
+
+ Allows Companion to write to older version of the firmware
+ 允許 Companion 寫入舊版本的韌體
+
+
+
+
+
+
+
+
+
+
+ Check Firmware compatibility
+ 檢查韌體兼容性
+
+
+
+
+
+
+
+
+
+
+ <html><head/><body><p>Saves a dated copy of your eeprom to the backup folder you specified in the Companion settings before writing the current model to the radio.</p></body></html>
+ 寫入前備份
+
+
+
+
+
+
+
+
+
+
+ Backup before Write
+ 寫入前備份
+
+
+
+
+
+
+
+
+
+
+ <html><head/><body><p>Modify calibration parameters using settings from current profile</p></body></html>
+ <html><head/><body><p>用當前檔案的設置修改校準參數</p></body></html>
+
+
+
+
+
+
+
+
+
+
+ Patch calibration setting from profile
+ 依照當前檔案修改校準參數
+
+
+
+
+
+
+
+
+
+
+ <html><head/><body><p>Modify HW parameters using settings from current profile</p></body></html>
+ <html><head/><body><p>用當前檔案的設置修改硬件參數</p></body></html>
+
+
+
+
+
+
+
+
+
+
+ Patch HW settings from profile
+ 依照當前檔案修改硬件參數
+
+
+
+
+
+
+
+
+
+
+ Cancel
+ 取消
+
+
+
+
+
+
+
+
+
+
+ Write to TX
+ 寫入到遙控器
+
+
+
+ Current profile: %1
+ 當前檔案: %1
+
+
+
+ Choose Radio Backup file
+ 選擇遙控器備份文件
+
+
+
+ Wrong radio calibration data in profile, Settings not patched
+ 此文檔包含錯誤的遙控器校準數據.設置沒有修改
+
+
+
+ Wrong radio setting data in profile, Settings not patched
+ 此文檔包含錯誤的遙控器設置數據.設置沒有修改
+
+
+
+ Cannot write file %1:
+%2.
+ 無法寫入文件 %1:
+%2.
+
+
+
+ Error writing file %1:
+%2.
+ 寫入文件錯誤 %1:
+%2.
+
+
+
+ The radio firmware belongs to another product family, check file and preferences!
+ 這個遙控器韌體屬於其他產品,檢查文件和配置!
+
+
+
+ The radio firmware is outdated, please upgrade!
+ 這個遙控器韌體已經過期, 請升級!
+
+
+
+ Cannot check Models and Settings compatibility! Continue anyway?
+ 無法檢查模型和設置兼容性! 仍然繼續麼?
+
+
+
+ FlashFirmwareDialog
+
+
+
+
+
+
+
+
+
+ Flash Firmware
+ 燒錄韌體
+
+
+
+
+
+
+
+
+
+
+ Load...
+ 加載...
+
+
+
+
+
+
+
+
+
+
+ Date & Time
+ 日期 & 時間
+
+
+
+
+
+
+
+
+
+
+ Variant
+ 變體
+
+
+
+
+
+
+
+
+
+
+ Version
+ 版本
+
+
+
+
+
+
+
+
+
+
+ Use profile start screen
+ 使用文檔中的開始畫面
+
+
+
+
+
+
+
+
+
+
+ Use firmware start screen
+ 使用韌體中的開始畫面
+
+
+
+
+
+
+
+
+
+
+ Use library start screen
+ 使用圖片庫中的開始畫面
+
+
+
+
+
+
+
+
+
+
+ Use another start screen
+ 使用其他開始畫面
+
+
+
+
+
+
+
+
+
+
+ Allows Companion to write to older version of the firmware
+ 允許 Companion 寫入舊版本的韌體
+
+
+
+
+
+
+
+
+
+
+ Check Hardware compatibility
+ 檢查硬件兼容性
+
+
+
+
+
+
+
+
+
+
+ Backup and restore Models and Settings
+ 備份和恢復模型和設置
+
+
+
+
+
+
+
+
+
+
+ Cancel
+ 取消
+
+
+
+
+
+
+
+
+
+
+ Write to TX
+ 寫入到遙控器
+
+
+
+ Open Firmware File
+ 打開韌體文件
+
+
+
+ %1 may not be a valid firmware file
+ %1 可能是非法的韌體文件
+
+
+
+ The firmware file is not valid.
+ 韌體文件非法.
+
+
+
+ There is no start screen image in the firmware file.
+ 韌體中沒有開機畫面.
+
+
+
+ Profile image %1 is invalid.
+ 檔案圖片 %1 无效.
+
+
+
+ Open image file to use as radio start screen
+ 打開圖片文件用作遙控器開機畫面
+
+
+
+ Images (%1)
+ 圖片 (%1)
+
+
+
+ Image could not be loaded from %1
+ 圖片無法從 %1 中加載
+
+
+
+ The library image could not be loaded
+ 圖片庫中的圖片無法被加載
+
+
+
+ Splash image not found
+ 無法找到開機畫面圖片
+
+
+
+ Cannot save customized firmware
+ 無法保存定制韌體
+
+
+
+ Write Firmware to Radio
+ 寫入韌體到遙控器
+
+
+
+
+ Firmware check failed
+ 韌體檢查失敗
+
+
+
+ Could not check firmware from radio
+ 無法檢查遙控器中的韌體
+
+
+
+ New firmware is not compatible with the one currently installed!
+ 新的韌體於當前安裝的韌體不兼容!
+
+
+
+ Conversion failed
+ 轉換失敗
+
+
+
+ Cannot convert Models and Settings for use with this firmware, original data will be used
+ 無法轉換此韌體中的模型和設置, 將使用原始數據
+
+
+
+ Restore failed
+ 恢復失敗
+
+
+
+ Could not restore Models and Settings to Radio. The models and settings data file can be found at: %1
+ 無法將模型和設置恢復到遙控器. 模型和設置數據可以在 %1 中找到
+
+
+
+ Flashing done
+ 燒錄完成
+
+
+
+ FlashProcess
+
+
+ Executable %1 not found
+ FlashProcess
+ 未找到可執行文件 %1
+
+
+
+ Writing...
+ FlashProcess
+ 寫入中...
+
+
+
+ Reading...
+ FlashProcess
+ 讀取中...
+
+
+
+ Verifying...
+ FlashProcess
+ 驗證中...
+
+
+
+ unknown
+ FlashProcess
+ 未知
+
+
+
+ ie: OpenTX for 9X board or OpenTX for 9XR board
+ 例如: OpenTX for 9X 主板 或 OpenTX for 9XR 主板
+
+
+
+ ie: OpenTX for M128 / 9X board or OpenTX for 9XR board with M128 chip
+ 例如: OpenTX for M128 / 9X 主板 或 帶有M128芯片的OpenTX for 9XR 主板
+
+
+
+ ie: OpenTX for Gruvin9X board
+ 例如: OpenTX for Gruvin9X 主板
+
+
+
+ Your radio uses a %1 CPU!!!
+
+Please check advanced burn options to set the correct cpu type.
+ 你的遙控器使用 %1 CPU!!!
+
+請檢查高級燒錄選項設置正確的cpu型號.
+
+
+
+ Your radio uses a %1 CPU!!!
+
+Please select an appropriate firmware type to program it.
+ 你的遥控器使用 %1 CPU!!!
+
+請選擇合適的用來編程它的固件類型.
+
+
+
+
+You are currently using:
+ %1
+
+你當前正在使用:
+ %1
+
+
+
+ Your radio does not seem connected to USB or the driver is not initialized!!!.
+ 你的遙控器似乎沒有連接到到USB端口,或沒有安裝驅動程序!!!.
+
+
+
+ Flashing done (exit code = %1)
+ 燒錄完成 (退出碼 = %1)
+
+
+
+ Flashing done with errors
+ 燒錄完成但包含錯誤
+
+
+
+ FUSES: Low=%1 High=%2 Ext=%3
+ 熔絲位: Low=%1 High=%2 Ext=%3
+
+
+
+ FlightMode
+
+
+
+
+
+
+
+
+
+ Fade In
+ FlightMode
+ 切入秒數 [Fade In]
+
+
+
+
+
+
+
+
+
+
+ Fade Out
+ FlightMode
+ 切出秒數 [Fade In]
+
+
+
+
+
+
+
+
+
+
+ Name
+ FlightMode
+ 名稱 [Name]
+
+
+
+
+
+
+
+
+
+
+ Switch
+ FlightMode
+ 啟用開關 [Switch]
+
+
+
+ FlightModeData
+
+
+ FM
+
+
+
+
+ FlightModePanel
+
+
+ Rotary Encoder %1
+
+
+
+
+ Name
+
+
+
+
+ Value source
+
+
+
+
+ Value
+ 设为
+
+
+
+ GVAR%1
+ 全局變量[GV] %1
+
+
+
+ Popup enabled
+ 屏幕彈窗提示
+
+
+
+ Popup menu available
+
+
+
+
+ Trim disabled
+ 不使用微調
+
+
+
+ Own Trim
+ 使用單獨的微調值
+
+
+
+ Use Trim from Flight mode %1
+ 使用 FM%1 的微調值
+
+
+
+ Use Trim from Flight mode %1 + Own Trim as an offset
+ 使用 FM%1 的微調值 + 單獨的微調偏移值
+
+
+
+ Unit
+
+
+
+
+ Prec
+
+
+
+
+ Min
+
+
+
+
+ Max
+
+
+
+
+ 0._
+
+
+
+
+ 0.0
+ 0.0
+
+
+
+
+ &Clear
+ (&C)清除
+
+
+
+
+ Clear
+ 清除
+
+
+
+ Clear all current Flight Mode properties?
+ 是否清除所有的飛行模式屬性?
+
+
+
+ FlightModesPanel
+
+
+ Flight Mode %1
+ 用於FM設定
+ 飛行模式[FM] %1
+
+
+
+ (%1)
+ FlightModePanel
+ (%1)
+
+
+
+ (default)
+ FlightModePanel
+ (默認)
+
+
+
+ FlybarSelectionPage
+
+
+ Has Flybar
+ 有副翼
+
+
+
+ Flybarless
+ 無副翼
+
+
+
+ Flybar:
+ 副翼:
+
+
+
+ FrSkyAlarmData
+
+
+ Yellow
+
+
+
+
+ Orange
+
+
+
+
+ Red
+
+
+
+
+ FrSkyChannelData
+
+
+
+ V
+
+
+
+
+ ---
+ 正向 [→]
+
+
+
+ FusesDialog
+
+
+
+
+
+
+
+
+
+ Fuses
+ 熔絲位
+
+
+
+
+
+
+
+
+
+
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">Reads the current fuses in the AVR controller.</span></p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8pt;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">Proper states for </span><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">AtMega 64 </span><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">:</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">EEPROM erase fuse not set: 0E, 81, FF</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">EEPROM erase fuse set: 0E, 89, FF</span></p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8pt;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">Proper states for AtMega 2560 :</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">EEPROM erase fuse not set: D7, 11, FC</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">EEPROM erase fuse set: D7, 19, FC</span></p></body></html>
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">读取当前AVR控制器中的熔丝位.</span></p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8pt;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">Proper states for </span><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">AtMega 64 </span><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">:</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">EEPROM 删除熔丝位 [erase fuse] 未设定 [not set]: 0E, 81, FF</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">EEPROM 删除熔丝位 [erase fuse] 已设定 [set]: 0E, 89, FF</span></p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8pt;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">Proper states for AtMega 2560 :</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">EEPROM 删除熔丝位 [erase fuse] 未设定 [not set]: D7, 11, FC</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">EEPROM 删除熔丝位 [erase fuse] 已设定 [set]: D7, 19, FC</span></p></body></html>
+
+
+
+
+
+
+
+
+
+
+ Read Fuses
+ 讀取熔絲位
+
+
+
+
+
+
+
+
+
+
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt; font-weight:600; text-decoration: underline;">Reset Fuses</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">Fuses in the AVR tell it how to behave. Pressing this button sets the fuses to the default parameters needed in the FW. These parameters are different for stock and 4.1 MB, please verify you selected the appropriate processor type in preferences.</span></p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8pt;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">This button also sets the "EEPROM protect" Fuse.</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">This prevents erasing of the EEPROM when the flash memory is written.</span></p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8pt;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt; font-weight:600; text-decoration: underline;">WARNING</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">Setting fuses can lead to problems and even a total lockout from your controller. Do this only if you know what you are doing.</span></p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8pt;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">When in doubt consult either the project's page or the 9xforum (http://9xforums.com/forum/)</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">If you do get locked out - google lookup for "dealing with Fuse Bricks".</span></p></body></html>
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt; font-weight:600; text-decoration: underline;">重设熔丝位</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">熔丝指示AVR如何运行. 按此按钮将熔丝设置成固件需要的默认参数. 这些参数和 stock 与 4.1 MB中的不一样, 请检查你在偏好选项中选择了合适的处理器类型.</span></p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8pt;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">这个按钮设置 "EEPROM protect" 熔丝.</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">当 Flash 存储器被写入时这会保护 EEPROM 不被删除.</span></p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8pt;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt; font-weight:600; text-decoration: underline;">警告</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">设置熔丝位可导致问题发生,严重的甚至导致你的遥控器无法开机. 只有当你知道自己在做什么时才可以操作.</span></p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8pt;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">如果有疑问请咨询合适的项目主页或 9xforum (http://9xforums.com/forum/)</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">如果你的遥控器无法开机 - 在google 中搜索 "dealing with Fuse Bricks".</span></p></body></html>
+
+
+
+
+
+
+
+
+
+
+ Reset Fuses
+EEPROM - PROTECT
+ 重設熔絲位
+EEPROM - PROTECT
+
+
+
+
+
+
+
+
+
+
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt; font-weight:600; text-decoration: underline;">Reset Fuses</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">Fuses in the AVR tell it how to behave. Pressing this button sets the fuses to the default parameters needed in the </span><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">FW. These parameters are different for stock and 4.1 MB, please verify you selected the appropriate processor type in preferences.</span></p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8pt;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">This button also clears the "EEPROM protect" Fuse.</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">This causes erasing of the EEPROM when the flash memory is written.</span></p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8pt;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt; font-weight:600; text-decoration: underline;">WARNING</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">Setting fuses can lead to problems and even a total lockout from your controller. Do this only if you know what you are doing.</span></p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8pt;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">When in doubt consult either the project's page or the 9xforum (http://9xforums.com/forum/)</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">If you do get locked out - google lookup for "dealing with Fuse Bricks".</span></p></body></html>
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt; font-weight:600; text-decoration: underline;">重设熔丝位</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">熔丝指示AVR如何运行. 按此按钮将熔丝设置成固件需要的默认参数. 这些参数和 stock 与 4.1 MB中的不一样, 请检查你在偏好选项中选择了合适的处理器类型.</span></p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8pt;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">这个按钮清除 "EEPROM protect" 熔丝.</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">当 Flash 存储器被写入时 EEPROM 将会被删除.</span></p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8pt;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt; font-weight:600; text-decoration: underline;">警告</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">设置熔丝位可导致问题发生,严重的甚至导致你的遥控器无法开机. 只有当你知道自己在做什么时才可以操作.</span></p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8pt;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">如果有疑问请咨询合适的项目主页或 9xforum (http://9xforums.com/forum/)</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">如果你的遥控器无法开机 - 在google 中搜索 "dealing with Fuse Bricks".</span></p></body></html>
+
+
+
+
+
+
+
+
+
+
+ Reset Fuses
+EEPROM - DELETE
+ 重設熔絲位
+EEPROM - DELETE
+
+
+
+
+
+
+
+
+
+
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;">
+<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600; text-decoration: underline;">WARNING</span></p>
+<p align="center" style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600; text-decoration: underline;"></p>
+<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Changing the fuses can mess up your radio.</p>
+<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Proceed only if you know what you are doing.</p></body></html>
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;">
+<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600; text-decoration: underline;">警告</span></p>
+<p align="center" style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600; text-decoration: underline;"></p>
+<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">改变熔丝位可能使你的遥控器变砖.</p>
+<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">只有当你知道自己在做什么时才进行操作.</p></body></html>
+
+
+
+
+ Reset Radio Fuses
+ 重設遙控器熔絲位
+
+
+
+ Read Fuses from Radio
+ 從遙控器中讀取熔絲位
+
+
+
+ GVarData
+
+
+ %
+
+
+
+
+ ?
+
+
+
+
+ 0._
+
+
+
+
+ 0.0
+ 0.0
+
+
+
+ ?.?
+
+
+
+
+ GV
+ GV
+
+
+
+ Own value
+ 使用單獨的取值
+
+
+
+ Flight mode %1 value
+ 使用FM%1值
+
+
+
+ GeneralEdit
+
+
+
+
+
+
+
+
+
+ Radio settings
+
+
+
+
+
+
+
+
+
+
+
+ Retrieve calib. and hw settings from profile
+ 從遙控器檔案中讀取校準和硬件設定
+
+
+
+
+
+
+
+
+
+
+ Store calib. and hw settings in selected profile
+ 存儲校準和硬件設定到選擇的遙控器檔案
+
+
+
+
+
+
+
+
+
+
+ General settings used throught the transmitter.
+These will be relevant for all models in the same EEPROM.
+ 遙控器一般設定, 用在整個遙控器上
+對相同的EEPROM, 對所有模型這些設置都是相同的.
+
+
+
+ Setup
+ General Edit????
+ 設定
+
+
+
+ Global Functions
+ General Edit
+ 全局功能
+
+
+
+ Trainer
+ General Edit
+ 教練功能
+
+
+
+ Hardware
+ General Edit????
+ 硬件
+
+
+
+ Calibration
+ General Edit
+ 校準
+
+
+
+ Wrong data in profile, radio calibration was not retrieved
+ 此文檔包含錯誤的數據. 未讀取遙控器校準數據
+
+
+
+ Wrong data in profile, Switch/pot config not retrieved
+ 此文檔包含錯誤的數據. 未讀取開關/旋鈕配置
+
+
+
+ Wrong data in profile, hw related parameters were not retrieved
+ 此文檔包含錯誤的數據. 未讀取硬件相關參數
+
+
+
+ Do you want to store calibration in %1 profile<br>overwriting existing calibration?
+ 你想要存儲校準數據到 %1 檔案<br>覆蓋當前已經存在的校準數據麼?
+
+
+
+ Calibration and HW parameters saved.
+ 校準數據和硬件參數已經存儲.
+
+
+
+ GeneralSettings
+
+
+ Radio Settings
+
+
+
+
+ GeneralSetup
+
+
+
+
+
+
+
+
+
+ Form
+ GeneralSetup????
+ 表單
+
+
+
+
+
+
+
+
+
+
+ Readonly Unlock
+ 只讀解鎖 [Readonly Unlock]
+
+
+
+
+
+
+
+
+
+
+ SC
+
+
+
+
+
+
+
+
+
+
+
+ SE
+
+
+
+
+
+
+
+
+
+
+
+ SA
+
+
+
+
+
+
+
+
+
+
+
+ SF
+
+
+
+
+
+
+
+
+
+
+
+ SH
+
+
+
+
+
+
+
+
+
+
+
+ SD
+
+
+
+
+
+
+
+
+
+
+
+ SB
+
+
+
+
+
+
+
+
+
+
+
+ SG
+
+
+
+
+
+
+
+
+
+
+
+ Timeshift from UTC
+ 依照UTC調整時間 [From UTC]
+
+
+
+
+
+
+
+
+
+
+ Voice Language
+ 語音語言 [Voice Language]
+
+
+
+
+
+
+
+
+
+
+ Country Code
+ 國家代碼 [Country Code]
+
+
+
+
+
+
+
+
+
+
+ Stick reverse
+ 反向搖桿 [Stick Reverse]
+
+
+
+
+
+
+
+
+
+
+ FAI Mode
+ FAI 模式 [FAI Mode]
+
+
+
+
+
+
+
+
+
+
+ Automatically adjust the radio's clock if a GPS is connected to telemetry.
+ 如果安裝有GPS回傳則自動調整遙控器時鐘.
+
+
+
+
+
+
+
+
+
+
+ Adjust RTC
+ 自動調整時鐘
+
+
+
+
+
+
+
+
+
+
+ Vario pitch at max
+ 最大上升率時Vario音調 [Max]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Hz
+
+
+
+
+
+
+
+
+
+
+
+ Speaker Volume
+ 喇叭音量 [Volume]
+
+
+
+
+
+
+
+
+
+
+ Backlight Switch
+ 背光開關 [Switch]
+
+
+
+
+
+
+
+
+
+
+ Sound Mode
+ 聲音模式 [Sound Mode]
+
+
+
+
+
+
+
+
+
+
+ Color 1
+ 顏色 1
+
+
+
+
+
+
+
+
+
+
+ Color 2
+ 顏色 2
+
+
+
+
+
+
+
+
+
+
+ Speaker Pitch (spkr only)
+ 喇叭音調 (僅喇叭) [Pitch]
+
+
+
+
+
+
+
+
+
+
+ If this value is not 0, any keypress will turn on the backlight and turn it off after the specified number of seconds.
+ 如果值非0, 任何按鍵將會開啟背光, 並在所設定秒數後關閉.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sec
+ 秒
+
+
+
+
+
+
+
+
+
+
+ Backlight color
+ 背光顏色 [Color]
+
+
+
+
+
+
+
+
+
+
+ Beeper
+ 蜂鳴器
+
+
+
+
+
+
+
+
+
+
+ Speaker
+ 喇叭
+
+
+
+
+
+
+
+
+
+
+ BeeperVoice
+ 蜂鳴器和語音
+
+
+
+
+
+
+
+
+
+
+ SpeakerVoice
+ 喇叭和語音
+
+
+
+
+
+
+
+
+
+
+ Beep volume
+ 蜂鳴器音量
+
+
+
+
+
+
+
+
+
+
+ Wav volume
+ WAV播放音量
+
+
+
+
+
+
+
+
+
+
+ Vario volume
+ Vario音量
+
+
+
+
+
+
+
+
+
+
+ Background volume
+ 背景音樂音量
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ms
+ 毫秒
+
+
+
+
+
+
+
+
+
+
+ Backlight Auto OFF after
+ 背光自動關閉時間 [Duration]
+
+
+
+
+
+
+
+
+
+
+ Backlight flash on alarm
+ 警告時背光閃爍 [Alarm]
+
+
+
+
+
+
+
+
+
+
+ Vario pitch at zero
+ 升降率為0時Vario音調 [Zero]
+
+
+
+
+
+
+
+
+
+
+ Vario repeat at zero
+ 升降率0時Vario重複率 [Repeat]
+
+
+
+
+
+
+
+
+
+
+ This is the switch selectrion for turning on the backlight (if installed).
+
+
+ !!!! 英文selection
+ 這個開關用來開啟背光 (如果遙控器有背光).
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">LCD Screen Contrast</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Values can be 20-45</span></p></body></html>
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">LCD 显示屏对比度</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">取值范围 20-45</span></p></body></html>
+
+
+
+
+
+
+
+
+
+
+ Backlight Brightness
+ 背光亮度 [Brightness]
+
+
+
+
+
+
+
+
+
+
+ RotEnc Navigation
+ 旋轉編碼器導航 [RotEnc]
+
+
+
+
+
+
+
+
+
+
+ America
+ 美國
+
+
+
+
+
+
+
+
+
+
+ Japan
+ 日本
+
+
+
+
+
+
+
+
+
+
+ Europe
+ 歐洲
+
+
+
+
+
+
+
+
+
+
+ Backlight OFF Brightness
+
+
+
+
+
+
+
+
+
+
+
+ Mode selection:
+
+Mode 1:
+ Left stick: Elevator, Rudder
+ Right stick: Throttle, Aileron
+
+Mode 2:
+ Left stick: Throttle, Rudder
+ Right stick: Elevator, Aileron
+
+Mode 3:
+ Left stick: Elevator, Aileron
+ Right stick: Throttle, Rudder
+
+Mode 4:
+ Left stick: Throttle, Aileron
+ Right stick: Elevator, Rudder
+
+
+ 遙控器模式[MODE]選擇:
+
+MODE1 日本手:
+ 左手: 升降方向
+ 右手: 油門副翼
+
+MODE2 美國手:
+ 左手: 油門方向
+ 右手: 升降副翼
+
+MODE3 中國手:
+ 左手: 升降副翼
+ 右手: 油門方向
+
+MODE4 模式4:
+ 左手: 油門副翼
+ 右手: 升降方向
+
+
+
+
+
+
+
+
+
+
+
+
+ Mode 1 (RUD ELE THR AIL)
+ MODE1 日本手↕升降↔方向 ↕油門↔副翼
+
+
+
+
+
+
+
+
+
+
+ Mode 2 (RUD THR ELE AIL)
+ MODE2 美國手↕油門↔方向 ↕升降↔副翼
+
+
+
+
+
+
+
+
+
+
+ Mode 3 (AIL ELE THR RUD)
+ MODE3 中國手↕升降↔副翼 ↕油門↔方向
+
+
+
+
+
+
+
+
+
+
+ Mode 4 (AIL THR ELE RUD)
+ MODE4 模式4 ↕油門↔副翼 ↕升降↔方向
+
+
+
+
+
+
+
+
+
+
+ <html><head/><body><p>Channel order</p><p><br/></p><p>Defines the order of the default mixes created on a new model.</p></body></html>
+ <html><head/><body><p>通道順序</p><p><br/></p><p>定义了当新的混控创建时默认的通道顺序.</p></body></html>
+
+
+
+
+
+
+
+
+
+
+ If you enable FAI, only RSSI and RxBt sensors will keep working. This function cannot be disabled by the radio.
+
+
+
+
+
+
+
+
+
+
+
+ RSSI Poweroff Warning
+
+
+
+
+
+
+
+
+
+
+
+ Low EEPROM Warning
+
+
+
+
+
+
+
+
+ Owner Registration ID
+
+
+
+
+
+
+
+
+ aaaaaaAA
+
+
+
+
+
+
+
+
+
+
+
+ R E T A
+ 方向 升降 油門 副翼 [R E T A]
+
+
+
+
+
+
+
+
+
+
+ R E A T
+ 方向 升降 副翼 油門 [R E A T]
+
+
+
+
+
+
+
+
+
+
+ R T E A
+ 方向 油門 升降 副翼 [R T E A]
+
+
+
+
+
+
+
+
+
+
+ R T A E
+ 方向 油門 副翼 升降 [R T A E]
+
+
+
+
+
+
+
+
+
+
+ R A E T
+ 方向 副翼 升降 油門 [R A E T]
+
+
+
+
+
+
+
+
+
+
+ R A T E
+ 方向 副翼 油門 升降 [R A T E]
+
+
+
+
+
+
+
+
+
+
+ E R T A
+ 升降 方向 油門 副翼 [E R T A]
+
+
+
+
+
+
+
+
+
+
+ E R A T
+ 升降 方向 副翼 油門 [E R A T]
+
+
+
+
+
+
+
+
+
+
+ E T R A
+ 升降 油門 方向 副翼 [E T R A]
+
+
+
+
+
+
+
+
+
+
+ E T A R
+ 升降 油門 副翼 方向 [E T A R]
+
+
+
+
+
+
+
+
+
+
+ E A R T
+ 升降 副翼 方向 油門 [E A R T]
+
+
+
+
+
+
+
+
+
+
+ E A T R
+ 升降 副翼 油門 方向 [E A T R]
+
+
+
+
+
+
+
+
+
+
+ T R E A
+ 油門 方向 升降 副翼 [T R E A]
+
+
+
+
+
+
+
+
+
+
+ T R A E
+ 油門 方向 副翼 升降 [T R A E]
+
+
+
+
+
+
+
+
+
+
+ T E R A
+ 油門 升降 方向 副翼 [T E R A]
+
+
+
+
+
+
+
+
+
+
+ T E A R
+ 油門 升降 副翼 方向 [T E A R]
+
+
+
+
+
+
+
+
+
+
+ T A R E
+ 油門 副翼 方向 升降 [T A R E]
+
+
+
+
+
+
+
+
+
+
+ T A E R
+ 油門 副翼 升降 方向 [T A E R]
+
+
+
+
+
+
+
+
+
+
+ A R E T
+ 副翼 方向 升降 油門 [A R E T]
+
+
+
+
+
+
+
+
+
+
+ A R T E
+ 副翼 方向 油門 升降 [A R T E]
+
+
+
+
+
+
+
+
+
+
+ A E R T
+ 副翼 升降 方向 油門 [A E R T]
+
+
+
+
+
+
+
+
+
+
+ A E T R
+ 副翼 升降 油門 方向 [A E T R]
+
+
+
+
+
+
+
+
+
+
+ A T R E
+ 副翼 油門 方向 升降 [A T R E]
+
+
+
+
+
+
+
+
+
+
+ A T E R
+ 副翼 油門 升降 方向 [A T E R]
+
+
+
+
+
+
+
+ Power On Delay
+
+
+
+
+
+
+
+
+
+
+
+ Jack Mode
+
+
+
+
+
+
+
+
+
+
+
+ Audio
+
+
+
+
+
+
+
+
+
+
+
+ Trainer
+ 教練功能
+
+
+
+
+
+
+
+
+
+
+ DMS
+
+
+
+
+
+
+
+
+
+
+
+ USB Mode
+
+
+
+
+
+
+
+
+ Power Off Delay
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Ask on Connect
+
+
+
+
+
+
+
+
+
+
+
+ Joystick (HID)
+
+
+
+
+
+
+
+
+
+
+
+ USB Mass Storage
+
+
+
+
+
+
+
+
+
+
+
+ USB Serial (CDC)
+
+
+
+
+
+
+
+
+
+
+
+ Stick Mode
+ 摇杆模式 [MODE]
+
+
+
+
+
+
+
+
+
+
+ Metric
+ 公制 [Metric]
+
+
+
+
+
+
+
+
+
+
+ Imperial
+ 英制 [Imperial]
+
+
+
+
+
+
+
+
+
+
+ Default Channel Order
+ 默認通道順序[Default Ch Order]
+
+
+
+
+
+
+
+
+
+
+ GPS Coordinates
+ GPS坐標格式 [GPS Coordinates]
+
+
+
+
+
+
+
+
+
+
+ Min
+ GeneralEdit
+ 最小
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ v
+ GeneralEdit
+ v
+
+
+
+
+
+
+
+
+
+
+ Max
+ GeneralEdit
+ 最大
+
+
+
+
+
+
+
+
+
+
+ Inactivity Timer
+ 忘記關機定時器 [Inactivity]
+
+
+
+
+
+
+
+
+
+
+ Show Splash Screen on Startup
+ 顯示開機畫面 [Splash Screen]
+
+
+
+
+
+
+
+
+
+
+ Contrast
+ 顯示屏對比度 [Contrast]
+
+
+
+
+
+
+
+
+
+
+ Battery Meter Range
+ 遙控器電池圖標範圍 [Range]
+
+
+
+
+
+
+
+
+
+
+ Haptic Strength
+ 振動強度 [Haptic Strength]
+
+
+
+
+
+
+
+
+
+
+ LCD Display Type
+ LCD顯示屏類型 [LCD Disp Type]
+
+
+
+
+
+
+
+
+
+
+ "No Sound" Warning
+ 當靜音時 開機警告 [Sound Off]
+
+
+
+
+
+
+
+
+
+
+ Battery Warning
+ 遙控器電量警告 [Battery Low]
+
+
+
+
+
+
+
+
+
+
+ Haptic Length
+ 振動時長 [Haptic Length]
+
+
+
+
+
+
+
+
+
+
+ MAVLink Baud Rate
+ MAVLink 波特率 [Baud Rate]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Quiet
+ GeneralEdit
+ 禁用 [Quiet]
+
+
+
+
+
+
+
+
+
+
+ Only Alarms
+ GeneralEdit
+ 只有警告 [Alarm]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No Keys
+ GeneralEdit
+ 忽略按鍵 [NoKey]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ All
+ GeneralEdit
+ 開啟 [All]
+
+
+
+
+
+
+
+
+
+
+ Battery warning voltage.
+This is the threashhold where the battery warning sounds.
+
+Acceptable values are 5v..10v
+ 遙控器電池警告電壓
+當電壓低於此數值時電量警告響起
+
+允許值是5V - 10V
+
+
+
+
+
+
+
+
+
+
+ Standard
+ 標準LCD [Standard]
+
+
+
+
+
+
+
+
+
+
+ Optrex
+ GeneralEdit
+ 光王LCD [Optrex]
+
+
+
+
+
+
+
+
+
+
+ If not zero will sound beeps if the transmitter has been left without inputs for the specified number of minutes.
+
+
+
+
+
+
+
+
+
+
+
+ min
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Show splash screen on startup
+
+
+
+
+
+
+
+
+
+
+
+ ---
+ GeneralEdit
+
+
+
+
+
+
+
+
+
+
+
+ 2s
+ GeneralEdit
+
+
+
+
+
+
+
+
+
+
+
+ 3s
+ GeneralEdit
+
+
+
+
+
+
+
+
+
+
+
+ 4s
+ GeneralEdit
+
+
+
+
+
+
+
+
+
+
+
+ 6s
+ GeneralEdit
+
+
+
+
+
+
+
+
+
+
+
+ 8s
+
+
+
+
+
+
+
+
+
+
+
+ 10s
+
+
+
+
+
+
+
+
+
+
+
+ 15s
+
+
+
+
+
+
+
+
+
+
+
+ 4800 Baud
+ GeneralEdit
+
+
+
+
+
+
+
+
+
+
+
+ 9600 Baud
+
+
+
+
+
+
+
+
+
+
+
+ 14400 Baud
+
+
+
+
+
+
+
+
+
+
+
+ 19200 Baud
+
+
+
+
+
+
+
+
+
+
+
+ 38400 Baud
+
+
+
+
+
+
+
+
+
+
+
+ 57600 Baud
+
+
+
+
+
+
+
+
+
+
+
+ 76800 Baud
+
+
+
+
+
+
+
+
+
+
+
+ 115200 Baud
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" text-decoration: underline;">Warnings</span></p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">These will define startup warnings.</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Throttle warning - will alert if the throttle is not at idle during startup</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Switch warning - will alert if switches are not in their defaul position</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Memory warning - will alert if there's not a lot of memory left</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Silent mode warning - will alert you if the beeper is set to quiet (0)</p></body></html>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ X-Short
+ GeneralEdit
+ 極短
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Short
+ GeneralEdit
+ 較短
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Normal
+ 正常
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Long
+ GeneralEdit
+ 較長
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ X-Long
+ 極長
+
+
+
+
+
+
+
+
+
+
+ NMEA
+ GeneralEdit
+
+
+
+
+
+
+
+
+
+
+
+ Play Delay (switch mid position)
+ 開關撥過中檔時播音延遲 [Delay]
+
+
+
+
+
+
+
+
+
+
+ Measurement Units
+ 單位制 [Units]
+
+
+
+
+
+
+
+
+
+
+ Haptic Mode
+ GeneralEdit
+ 振動 [Haptic Mode]
+
+
+
+
+
+
+
+
+
+
+ Beeper Length
+ 蜂鳴時長 [Beep Length]
+
+
+
+
+
+
+
+
+
+
+ Beeper Mode
+ 蜂鳴音 [Beep Mode]
+
+
+
+
+
+
+
+
+
+
+ Beeper volume
+
+0 - Quiet. No beeps at all.
+1 - No Keys. Normal beeps but menu keys do not beep.
+2 - Normal.
+3 - Loud.
+4 - Extra loud.
+
+
+
+
+
+
+
+
+
+
+
+ Alarms Only
+ GeneralEdit
+ 只有警告 [Alarm]
+
+
+
+ Power On Speed
+
+
+
+
+ Power Off Speed
+
+
+
+
+ GeneralSetupPanel
+
+
+ OFF
+
+
+
+
+ Keys
+ 按鍵 [Keys]
+
+
+
+ Sticks
+ 摇杆 [Sticks]
+
+
+
+ Keys + Sticks
+ 按鍵和搖桿 [Keys + Sticks]
+
+
+
+ ON
+ 啟用
+
+
+
+ English
+ 英語
+
+
+
+ Dutch
+ 荷蘭語
+
+
+
+ French
+ 法語
+
+
+
+ Italian
+ 意大利語
+
+
+
+ German
+ 德語
+
+
+
+ Czech
+ 捷克語
+
+
+
+ Slovak
+ 慢動作 [Slow]
+
+
+
+ Spanish
+ 西班牙語
+
+
+
+ Polish
+ 波蘭語
+
+
+
+ Portuguese
+ 葡萄牙語
+
+
+
+ Russian
+
+
+
+
+ Swedish
+ 瑞典語
+
+
+
+ Hungarian
+ 匈牙利語
+
+
+
+ No
+
+
+
+
+ RotEnc A
+ 旋轉編碼器A
+
+
+
+ Rot Enc B
+ 旋轉編碼器B
+
+
+
+ Rot Enc C
+ 旋轉編碼器C
+
+
+
+ Rot Enc D
+ 旋轉編碼器D
+
+
+
+ Rot Enc E
+ 旋轉編碼器E
+
+
+
+ If you enable FAI, only RSSI and RxBt sensors will keep working.
+This function cannot be disabled by the radio.
+Are you sure ?
+
+
+
+
+ GyroPage
+
+
+ No
+ Gyropage
+ 無陀螺儀
+
+
+
+ Yes, controled by a switch
+ 有陀螺儀, 通過開關控制感度
+
+
+
+ Yes, controlled by a pot
+ 有陀螺儀, 通過旋鈕控制感度
+
+
+
+ Hardware
+
+
+
+
+
+
+
+
+
+ Form
+ Hardware
+ 表單
+
+
+
+
+
+
+
+
+
+
+ SQ
+
+
+
+
+
+
+
+
+
+
+
+ SR
+
+
+
+
+
+
+
+
+
+
+
+ LS2
+ LS2 滑桿
+
+
+
+
+
+
+
+
+
+
+ SP
+
+
+
+
+
+
+
+
+
+
+
+ SO
+
+
+
+
+
+
+
+
+
+
+
+ S4
+ S4 旋鈕
+
+
+
+
+
+
+
+
+
+
+ RS
+ RS 滑桿
+
+
+
+
+
+
+
+
+
+
+ SB
+
+
+
+
+
+
+
+
+
+
+
+ PPM 2
+ 教練口訊號2 [PPM 2]
+
+
+
+
+
+
+
+
+
+
+ OFF
+ 關閉 [OFF]
+
+
+
+
+
+
+
+
+
+
+ S-Port Mirror
+ S-Port 鏡像 [S-Port Mirror]
+
+
+
+
+
+
+
+
+
+
+ Telemetry
+ 回傳 [Telemetry]
+
+
+
+
+
+
+
+
+
+
+ SBUS Trainer
+ SBUS 教練功能 [SBUS Trainer]
+
+
+
+
+
+
+
+
+
+
+ Debug
+ 除錯 [Debug]
+
+
+
+
+
+
+
+
+
+
+ Rud
+ Rud 搖桿
+
+
+
+
+
+
+
+
+
+
+ PPM 3
+ 教練口訊號3 [PPM 3]
+
+
+
+
+
+
+
+
+
+
+ S1
+ S1 旋鈕
+
+
+
+
+
+
+
+
+
+
+ S2
+ S2 旋鈕
+
+
+
+
+
+
+
+
+
+
+ S3
+ S3 旋鈕
+
+
+
+
+
+
+
+
+
+
+ PPM 1
+ 教練口訊號1 [PPM 1]
+
+
+
+
+
+
+
+
+
+
+ Serial Port
+ 串口 [Serial Port]
+
+
+
+
+
+
+
+
+
+
+ v
+
+
+
+
+
+
+
+
+
+
+
+ PPM Multiplier
+ 教練口訊號係數 [PPM Multiplier]
+
+
+
+
+
+
+
+
+
+
+ Current Offset
+ 當前修正 [Offset]
+
+
+
+
+
+
+
+
+
+
+ PPM 4
+ 教練口訊號4 [PPM 4]
+
+
+
+
+
+
+
+
+
+
+ SA
+
+
+
+
+
+
+
+
+
+
+
+ Ele
+ Ele 搖桿
+
+
+
+
+
+
+ Antenna
+
+
+
+
+
+
+
+
+
+ S5
+ S5 旋鈕
+
+
+
+
+
+
+
+
+
+
+ Ail
+ Ail 搖桿
+
+
+
+
+
+
+
+
+
+
+ Thr
+ Thr 搖桿
+
+
+
+
+
+
+
+
+
+
+ SC
+
+
+
+
+
+
+
+
+
+
+
+ LS
+ LS 滑桿
+
+
+
+
+
+
+
+
+
+
+ SD
+
+
+
+
+
+
+
+
+
+
+
+ Battery Offset
+ 控電電壓修正 [Battery Offset]
+
+
+
+
+
+
+
+
+
+
+ SE
+
+
+
+
+
+
+
+
+
+
+
+ SF
+
+
+
+
+
+
+
+
+
+
+
+ SG
+
+
+
+
+
+
+
+
+
+
+
+ SH
+
+
+
+
+
+
+
+
+
+
+
+ SI
+
+
+
+
+
+
+
+
+
+
+
+ SJ
+
+
+
+
+
+
+
+
+
+
+
+ SK
+
+
+
+
+
+
+
+
+
+
+
+ SL
+
+
+
+
+
+
+
+
+
+
+
+ SM
+
+
+
+
+
+
+
+
+
+
+
+ SN
+
+
+
+
+
+
+
+
+
+
+
+ RS2
+ RS2 滑桿
+
+
+
+
+
+
+
+
+
+
+ Bluetooth
+ 藍牙 [Bluetooth]
+
+
+
+
+
+
+
+
+
+
+ ADC Filter
+
+
+
+
+
+
+
+
+
+
+
+ Device Name:
+
+
+
+
+ HardwarePanel
+
+
+
+
+ None
+ 无
+
+
+
+ 2 Positions Toggle
+ 2段彈簧開關
+
+
+
+ 2 Positions
+ 2段開關
+
+
+
+ 3 Positions
+ 3段開關
+
+
+
+ Pot with detent
+ 有中位旋鈕
+
+
+
+ Multipos switch
+ 多段開關
+
+
+
+ Pot without detent
+ 無中位旋鈕
+
+
+
+ Slider with detent
+ 有中位滑桿
+
+
+
+ OFF
+
+
+
+
+ Enabled
+
+
+
+
+ Telemetry
+
+
+
+
+ Trainer
+ 教練功能
+
+
+
+ Internal
+
+
+
+
+ Ask
+
+
+
+
+ Per model
+
+
+
+
+ Internal + External
+
+
+
+
+ External
+
+
+
+
+ Heli
+
+
+
+
+
+
+
+
+
+ Off
+ 禁用
+
+
+
+
+
+
+
+
+
+
+ 120
+
+
+
+
+
+
+
+
+
+
+
+ 120X
+
+
+
+
+
+
+
+
+
+
+
+ 140
+
+
+
+
+
+
+
+
+
+
+
+ 90
+
+
+
+
+
+
+
+
+
+
+
+ Invert Elevator
+ 升降反向 [Ele]
+
+
+
+
+
+
+
+
+
+
+ Invert Aileron
+ 副翼反向 [Ail]
+
+
+
+
+
+
+
+
+
+
+ Invert Collective
+ 總距反向 {Col]
+
+
+
+
+
+
+
+
+
+
+ Long. cyc
+ 縱向循環螺距 [Long]
+
+
+
+
+
+
+
+
+
+
+ Invert
+ 反向 [Invert]
+
+
+
+
+
+
+
+
+
+
+ Swash Ring
+ 斜盤限位 [Swach RIng]
+
+
+
+
+
+
+
+
+
+
+ Swash Type
+ 斜盤類型 [Swach Type]
+
+
+
+
+
+
+
+
+
+
+ Lateral cyc
+ 橫向循環螺距 [Lateral]
+
+
+
+
+
+
+
+
+
+
+ Collective
+ 總距 [Collective]
+
+
+
+ HeliPage
+
+
+ Throttle Channel:
+ 油門通道 [Throttle]:
+
+
+
+ Yaw Channel:
+ 偏航通道 [Yaw]:
+
+
+
+ Pitch Channel:
+ 仰俯通道 [Pitch]:
+
+
+
+ Roll Channel:
+ 滾轉通道 [Roll]:
+
+
+
+ HexEepromFormat
+
+
+ Invalid EEPROM File %1
+ 無效的 EEPROM 文件 %1
+
+
+
+ Cannot open file %1:
+%2.
+
+
+
+
+ Error writing file %1:
+%2.
+ 寫入文件錯誤 %1:
+%2.
+
+
+
+ InputsPanel
+
+
+
+ Move Up
+ 上移
+
+
+
+
+ Ctrl+Up
+ Ctrl+Up
+
+
+
+
+ Move Down
+ 下移
+
+
+
+
+ Ctrl+Down
+ Ctrl+Down
+
+
+
+ Clear All Inputs
+ 清除所有輸入
+
+
+
+ Not enough available inputs!
+ 沒有足夠的可用輸入!
+
+
+
+ Delete Selected Inputs?
+ 刪除選擇的輸入?
+
+
+
+ &Add
+ 添加 (&A)
+
+
+
+ Ctrl+A
+
+
+
+
+ &Edit
+ 編輯 (&E)
+
+
+
+ Enter
+ InputPanel
+ 確定
+
+
+
+ &Delete
+ 删除 (&D)
+
+
+
+ Delete
+ 删除
+
+
+
+ &Copy
+ 複製 (&C)
+
+
+
+ Ctrl+C
+
+
+
+
+ &Cut
+ 剪下 (&C)
+
+
+
+ Ctrl+X
+
+
+
+
+ &Paste
+ 貼上 (&P)
+
+
+
+ Ctrl+V
+
+
+
+
+ Du&plicate
+ 克隆 (&P)
+
+
+
+ Ctrl+U
+
+
+
+
+ Clear Inputs?
+ 清除輸入?
+
+
+
+ Really clear all the inputs?
+ 確定清除所有輸入麼?
+
+
+
+ LimitData
+
+
+ INV
+ 反向 [←]
+
+
+
+ NOR
+ 或非
+
+
+
+ CH
+
+
+
+
+ LimitsGroup
+
+
+ GV
+ GV
+
+
+
+ LogicalSwitchData
+
+
+ ---
+ 正向 [→]
+
+
+
+ a>x
+ 數值1 > 數值2 a>x
+
+
+
+ a<x
+ 數值1 < 數值2 a<x
+
+
+
+ |a|>x
+ |數值1| > 數值2 |a|>x
+
+
+
+ |a|<x
+ |數值1| < 數值 2 |a|<x
+
+
+
+ AND
+ 與運算 AND
+
+
+
+ OR
+ 或運算 OR
+
+
+
+ XOR
+ 異或運算 XOR
+
+
+
+ a=b
+ 數值1 = 數值2 a=b
+
+
+
+ a!=b
+ 數值1 != 數值2 a!=b
+
+
+
+ a>b
+ 數值1 > 數值2 a>b
+
+
+
+ a<b
+ 數值1 < 數值2 a<b
+
+
+
+ a>=b
+ 數值1 ≥ 數值2 a>=b
+
+
+
+ a<=b
+ 數值1 ≤ 數值2 a<=b
+
+
+
+ d>=x
+ 數值1變動 ≥ 數值2 d>=x
+
+
+
+ |d|>=x
+ |數值1變動| ≥ 數值2 d>=x
+
+
+
+ a=x
+ 數值1 = 數值2 a=x
+
+
+
+ a~x
+ 數值1 ≈ 數值2 a~x
+
+
+
+ Timer
+ 定時開關 Timer
+
+
+
+ Sticky
+ 粘滞键 Sticky
+
+
+
+ Edge
+ 邊沿觸發 EDGE
+
+
+
+ Unknown
+ 未知[Unknown]
+
+
+
+ L
+
+
+
+
+ LSW
+
+
+
+
+ LogicalSwitchesPanel
+
+
+ Function
+ LogicalSwitchPanel
+ 運算方式 [Function]
+
+
+
+ V1
+ LogicalSwitchPanel
+ 數值1 [V1]
+
+
+
+ V2
+ LogicalSwitchPanel
+ 數值2 [V2]
+
+
+
+ AND Switch
+ 與開關 [AND Sw]
+
+
+
+ Duration
+ LogicalSwitchPanel
+ 持續時間 [Duration]
+
+
+
+ Delay
+ LogicalSwitchPanel
+ 延遲 [Delay]
+
+
+
+ Popup menu available
+
+
+
+
+ (infinite)
+
+
+
+
+ (instant)
+ LogicalSwitchPanel 邊沿觸發使用
+ (立刻 [instant])
+
+
+
+ &Copy
+ 複製 (&C)
+
+
+
+ &Cut
+ LogicalSwitchPanel
+ 剪下 (&C)
+
+
+
+ &Paste
+ LogicalSwitchPanel
+ 貼上 (&P)
+
+
+
+ &Delete
+ LogicalSwitchPanel
+ 刪除 (&D)
+
+
+
+ LogsDialog
+
+
+
+
+
+
+
+
+
+ Companion Log Viewer
+ Companion Log 查看器
+
+
+
+
+
+
+
+
+
+
+ Fly sessions
+ LogsDialog
+ 飛行起落
+
+
+
+
+
+
+
+
+
+
+ Save session CSV
+
+
+
+
+
+
+
+
+
+
+
+ Zoom
+ 縮放
+
+
+
+
+
+
+
+
+
+
+ X
+
+
+
+
+
+
+
+
+
+
+
+ Y
+
+
+
+
+
+
+
+
+
+
+
+ Reset
+ 重設
+
+
+
+
+
+
+
+
+
+
+ Filename
+ 文件名
+
+
+
+
+
+
+
+
+
+
+ Open LogFile
+ 打開 Log 文件
+
+
+
+ Telemetry logs
+ 回傳 logs
+
+
+
+ Time (hh:mm:ss)
+ 時間 (hh:mm:ss)
+
+
+
+ Plot Title Change
+ 改變繪製標題
+
+
+
+ New plot title:
+ 新的繪製標題:
+
+
+
+ Axis Label Change
+ 改變坐標軸標籤
+
+
+
+ New axis label:
+ 新的坐標軸標題:
+
+
+
+ Graph Name Change
+ 改變圖表的名稱
+
+
+
+ New graph name:
+ 新的圖表名稱:
+
+
+
+ Error: no GPS data found
+
+
+
+
+ The column containing GPS coordinates must be named "GPS".
+
+The columns for altitude "GAlt" and for speed "GSpd" are optional
+ 包含 GPS 坐標的列必須起名為 "GPS".
+
+包含高度的列 "GAlt" 和包含速度的列 "GSpd" 是可選的
+
+
+
+ Cannot write file %1:
+%2.
+ 無法寫入文件 %1:
+%2.
+
+
+
+ Cursor A: %1 m
+ 光標 A: %1 m
+
+
+
+ Cursor B: %1 m
+ 光標 B: %1 m
+
+
+
+ Time delta: %1
+ 時間偏移: %1
+
+
+
+ Climb rate: %1 m/s
+ 升降速率: %1 m/s
+
+
+
+ Select your log file
+ 選擇你的 log 文件
+
+
+
+ Available fields
+ 可用項目
+
+
+
+ The selected logfile contains %1 invalid lines out of %2 total lines
+ 選擇的 Log 文件共有 %2 條記錄, 其中 %1 條記錄無效
+
+
+
+ total duration
+ 總持續時間
+
+
+
+ duration
+ 持續時間
+
+
+
+ (L1)
+ (L1)
+
+
+
+ (R1)
+
+
+
+
+ (L2)
+
+
+
+
+ (R2)
+
+
+
+
+ MainWindow
+
+
+
+ File loaded
+ 文件已載入
+
+
+
+ Checking for updates
+ 檢查更新中
+
+
+
+ A new version of Companion is available (version %1)<br>Would you like to download it?
+ 有新版本的 Companion 可用. (版本号 %1)<br>你希望現在就下載麼?
+
+
+
+
+ Save As
+ 另存為
+
+
+
+ Executable (*.exe)
+ 可執行文件 (*.exe)
+
+
+
+ New release available
+ 有新版本發布
+
+
+
+
+ No updates available at this time.
+ 目前沒有更新的韌體版本發布.
+
+
+
+
+ Would you like to launch the installer?
+ 你希望打開安裝軟體嗎?
+
+
+
+ Error opening file %1:
+%2.
+ 打開文件錯誤 %1:
+%2.
+
+
+
+ Not enough flash available on this board for all the selected options
+ 此主板上沒有足夠的Flash用來存儲所有所選選項
+
+
+
+ Compilation server temporary failure, try later
+ 編譯服務器臨時不可用, 請稍後再試
+
+
+
+ Compilation server too busy, try later
+ 編譯服務器太忙, 請稍後再試
+
+
+
+ Compilation error
+ 編譯錯誤
+
+
+
+ Invalid firmware
+ 無效的韌體
+
+
+
+ Invalid board
+ 無效的主板
+
+
+
+ Invalid language
+ 無效的語言
+
+
+
+ Unknown server failure, try later
+ 未知服務器失效, 請稍後再試
+
+
+
+ Do you want to write the firmware to the radio now ?
+ 你希望現在就將韌體寫入到遙控器嗎?
+
+
+
+
+ Yes
+ MainWindow
+ 是
+
+
+
+
+ No
+ MainWindow
+ 否
+
+
+
+
+ Release Notes
+ 版本發布說明
+
+
+
+ A new version of %1 firmware is available:
+ - current is %2
+ - newer is %3
+
+Do you want to download it now?
+
+We recommend you view the release notes using the button below to learn about any changes that may be important to you.
+ 有新版本的 %1 韌體版本可用:
+ - 目前版本是 %2
+ - 新的版本是 %3
+
+你希望現在下載嗎 ?
+
+我們建議你使用下面的按鈕查看版本發布說明, 以便了解對你來說重要的更新項目.
+
+
+
+ The new theme will be loaded the next time you start Companion.
+ 新的主題將在重新打開程序後使用.
+
+
+
+
+ Open Models and Settings file
+ 打開模型和配置文件
+
+
+
+
+ File saved
+ 文件已保存
+
+
+
+
+ Synchronize SD
+ 同步SD卡
+
+
+
+
+ Read Firmware from Radio
+ 從遙控器中讀取韌體
+
+
+
+ Write Firmware to Radio
+ 將韌體寫入遙控器
+
+
+
+
+ Read Models and Settings from Radio
+ 從遙控器中讀取模型和配置
+
+
+
+ Write Models and Settings to Radio
+ 將模型和配置寫入遙控器
+
+
+
+ Save Radio Backup to File
+ 保存遙控器備份到文件
+
+
+
+ Some text will not be translated until the next time you start Companion. Please note that some translations may not be complete.
+
+
+
+
+ Models and Settings read
+
+
+
+
+ Diskimage (*.dmg)
+
+
+
+
+ Would you like to open the disk image to install the new version?
+
+
+
+
+ A new release of Companion is available, please check the <a href='%1'>OpenTX website!</a>
+
+
+
+
+ There are unsaved file changes which you may lose when switching radio types.
+
+Do you wish to continue?
+
+
+
+
+ No local SD structure path configured!
+
+
+
+
+ No Radio or SD card detected!
+
+
+
+
+
+ This function is not yet implemented
+
+
+
+
+ Read Radio Firmware to File
+ 讀取遙控器韌體並保存到文件
+
+
+
+ OpenTX Home Page: <a href='%1'>%1</a>
+ OpenTX 網站主頁: <a href='%1'>%1</a>
+
+
+
+ The OpenTX Companion project was originally forked from <a href='%1'>eePe</a>
+ OpenTX Companion項目起初分支於 <a href='%1'>eePe</a>
+
+
+
+ If you've found this program useful, please support by <a href='%1'>donating</a>
+ 如果你覺得此程序有用, 請通過<a href='%1'>捐贈</a>支持
+
+
+
+ Copyright OpenTX Team
+ 版權所有 OpenTX Team
+
+
+
+ About Companion
+ 關於 Companion
+
+
+
+ OpenTX Companion %1 - Radio: %2 - Profile: %3
+ OpenTX Companion %1 - 遙控器: %2 - 檔案: %3
+
+
+
+ New
+ MainWindow
+ 新建配置文件
+
+
+
+ Create a new Models and Settings file
+ 建立新的模型和設置文件
+
+
+
+ Open...
+ 打開...
+
+
+
+ Save
+ 保存
+
+
+
+
+ Save Models and Settings file
+ 保存模型和配置文件
+
+
+
+ Save As...
+ 另存為...
+
+
+
+ Close
+ 關閉
+
+
+
+ Close Models and Settings file
+
+
+
+
+ Exit
+ 退出
+
+
+
+ Exit the application
+ 退出軟體
+
+
+
+ - Copy
+
+
+
+
+ Companion :: Open files warning
+
+
+
+
+ Please save or close modified file(s) before deleting the active profile.
+
+
+
+
+ Not possible to remove profile
+ 不能移除遙控器檔案
+
+
+
+ The default profile can not be removed.
+ 默認遙控器檔案無法被移除.
+
+
+
+ Confirm Delete Profile
+
+
+
+
+ Are you sure you wish to delete the "%1" radio profile? There is no way to undo this action!
+
+
+
+
+ Classical
+ 經典
+
+
+
+ The classic companion9x icon theme
+ 經典 companion9x 圖標主題
+
+
+
+ Yerico
+ Yerico圖標主題
+
+
+
+ Yellow round honey sweet icon theme
+ 黃色圓潤甜蜜圖標主題
+
+
+
+ Monochrome
+ 單色黑白
+
+
+
+ A monochrome black icon theme
+ 黑色圖標的黑白主題
+
+
+
+ MonoWhite
+ 單色白色
+
+
+
+ A monochrome white icon theme
+ 白色圖標的黑白主題
+
+
+
+ MonoBlue
+ 單色藍色
+
+
+
+ No Companion release candidates are currently being served for this version, please switch release channel
+
+
+
+
+ No nightly Companion builds are currently being served for this version, please switch release channel
+
+
+
+
+ No Companion release builds are currently being served for this version, please switch release channel
+
+
+
+
+ Companion update check failed, new version information not found.
+
+
+
+
+ No firmware release candidates are currently being served for this version, please switch release channel
+
+
+
+
+ No firmware nightly builds are currently being served for this version, please switch release channel
+
+
+
+
+ No firmware release builds are currently being served for this version, please switch release channel
+
+
+
+
+ Release candidate builds are now available for this version, would you like to switch to using them?
+
+
+
+
+ Channel changed to RC, please restart the download process
+
+
+
+
+ Official release builds are now available for this version, would you like to switch to using them?
+
+
+
+
+ Channel changed to Release, please restart the download process
+
+
+
+
+ This radio (%1) is not currently available in this firmware release channel
+
+
+
+
+ Firmware update check failed, new version information not found or invalid.
+
+
+
+
+ Firmware %1 does not seem to have ever been downloaded.
+Version %2 is available.
+Do you want to download it now?
+
+We recommend you view the release notes using the button below to learn about any changes that may be important to you.
+
+
+
+
+
+ Do you want to download version %1 now ?
+
+
+
+
+ Ignore this version %1?
+
+
+
+
+ Local Folder
+
+
+
+
+ Radio Folder
+
+
+
+
+ List of recently used files
+
+
+
+
+ Radio Profiles
+
+
+
+
+ Create or Select Radio Profiles
+
+
+
+
+ Release notes...
+
+
+
+
+ Show release notes
+
+
+
+
+ Create a new Radio Settings Profile
+
+
+
+
+ Copy Current Radio Profile
+
+
+
+
+ Duplicate current Radio Settings Profile
+
+
+
+
+ Delete Current Radio Profile...
+
+
+
+
+ Delete the current Radio Settings Profile
+
+
+
+
+ Export Application Settings..
+
+
+
+
+ Save all the current %1 and Simulator settings (including radio profiles) to a file.
+
+
+
+
+ Import Application Settings..
+
+
+
+
+ Load %1 and Simulator settings from a prevously exported settings file.
+
+
+
+
+ Tabbed Windows
+
+
+
+
+ Use tabs to arrange open windows.
+
+
+
+
+ Tile Windows
+
+
+
+
+ Arrange open windows across all the available space.
+
+
+
+
+ Cascade Windows
+
+
+
+
+ Arrange all open windows in a stack.
+
+
+
+
+ Close All Windows
+
+
+
+
+ Closes all open files (prompts to save if necessary.
+
+
+
+
+ Window
+
+
+
+
+ Ctrl+Shift+S
+
+
+
+
+ Ctrl+Alt+L
+
+
+
+
+ Ctrl+Alt+D
+
+
+
+
+ Ctrl+Alt+R
+
+
+
+
+ A monochrome blue icon theme
+ 藍色圖標的黑白主題
+
+
+
+ Small
+ 小
+
+
+
+ Use small toolbar icons
+ 使用小的工具欄圖標
+
+
+
+ Normal
+ MainWindow
+ 普通
+
+
+
+ Use normal size toolbar icons
+ 使用普通大小的工具欄圖標
+
+
+
+ Big
+ 大
+
+
+
+ Use big toolbar icons
+ 使用大工具欄圖標
+
+
+
+ Huge
+ 超大
+
+
+
+ Use huge toolbar icons
+ 使用特大的工具欄圖標
+
+
+
+ System language
+ 使用系統語言
+
+
+
+ Please save or close all modified files before importing settings
+
+
+
+
+ <html><p>%1 and Simulator settings can be imported (restored) from a previosly saved export (backup) file. This will replace current settings with any settings found in the file.</p><p>An automatic backup of the current settings will be attempted. But if the current settings are useful then it is recommended that you make a manual backup first.</p><p>For best results when importing settings, <b>close any other %1 windows you may have open, and make sure the standalone Simulator application is not running.</p><p>Do you wish to continue?</p></html>
+
+
+
+
+ Confirm Settings Import
+
+
+
+
+ Select %1:
+
+
+
+
+ backup
+
+
+
+
+ Press the 'Ignore' button to continue anyway.
+
+
+
+
+ The settings could not be imported.
+
+
+
+
+ <html><p>New settings have been imported from:<br> %1.</p><p>%2 will now re-initialize.</p><p>Note that you may need to close and restart %2 before some settings like language and icon theme take effect.</p>
+
+
+
+
+ <p>The previous settings were backed up to:<br> %1</p>
+
+
+
+
+ About...
+ 关于...
+
+
+
+ Show the application's About box
+ 顯示軟體的關於對話框
+
+
+
+ View Log File...
+ 查看 Log 文件...
+
+
+
+ Open and view log file
+ 打開和查看 Log 文件
+
+
+
+ Settings...
+ 設置...
+
+
+
+ Edit Settings
+ 編輯設定
+
+
+
+ Download...
+ 下載...
+
+
+
+ Download firmware and voice files
+ 下載韌體和語音文件
+
+
+
+ Check for Updates...
+ 檢查更新...
+
+
+
+ Check OpenTX and Companion updates
+ 檢查 OpenTX 和 Companion 更新
+
+
+
+ Compare Models...
+ 比較模型...
+
+
+
+ Compare models
+ 比較模型參數
+
+
+
+ Edit Radio Splash Image...
+ 編輯遙控器開機畫面...
+
+
+
+ Edit the splash image of your Radio
+ 編輯你的遙控器的開機畫面
+
+
+
+ List programmers...
+ 列出編程器...
+
+
+
+ List available programmers
+ 列出可用的編程器
+
+
+
+ Fuses...
+ 熔絲位...
+
+
+
+ Show fuses dialog
+ 顯示熔絲位對話框
+
+
+
+ Read firmware from Radio
+ 從遙控器中讀取韌體
+
+
+
+ Write firmware to Radio
+ 將韌體寫入遙控器
+
+
+
+ Add Radio Profile
+ 添加遙控器檔案
+
+
+
+ Manuals and other Documents
+ 使用說明書和其他文檔
+
+
+
+ Open the OpenTX document page in a web browser
+ 在網路瀏覽器中打開OpenTX文檔主頁
+
+
+
+ Write Models and Settings To Radio
+ 將模型和配置寫入遙控器
+
+
+
+ Read Models and Settings From Radio
+ 從遙控器中讀取模型和配置
+
+
+
+ Configure Communications...
+ 配置通訊...
+
+
+
+ Configure software for communicating with the Radio
+ 配置與遙控器通訊的軟件
+
+
+
+ Write Backup to Radio
+ 將備份寫入遙控器
+
+
+
+ Write Backup from file to Radio
+ 將備份文件寫入到遙控器
+
+
+
+ Backup Radio to File
+ 備份遙控器到文件
+
+
+
+ Save a complete backup file of all settings and model data in the Radio
+ 保存一個包含所有遙控器設置和模型數據的備份文件
+
+
+
+ Contributors...
+ 貢獻者...
+
+
+
+ A tribute to those who have contributed to OpenTX and Companion
+ 向所有對OpenTX和Companion做出過貢獻的人致敬
+
+
+
+ SD card synchronization
+ 同步SD卡
+
+
+
+ Use default system language.
+
+
+
+
+ Use %1 language (some translations may not be complete).
+
+
+
+
+ Recent Files
+ 最近使用的文件
+
+
+
+ Set Menu Language
+ 設置菜單語言
+
+
+
+ Set Icon Theme
+ 設置程序圖標
+
+
+
+ Set Icon Size
+ 設置圖標大小
+
+
+
+
+ File
+ 文件
+
+
+
+
+ Edit
+ 編輯
+
+
+
+ Settings
+ 設置
+
+
+
+ Read/Write
+ 讀/寫
+
+
+
+
+ Help
+ 幫助
+
+
+
+ Write
+ 寫入
+
+
+
+ Ready
+ 已準備好
+
+
+
+ %2
+
+
+
+
+ Alt+%1
+
+
+
+
+ New Radio
+ 新的遙控器
+
+
+
+ MdiChild
+
+
+ Delete
+ 刪除
+
+
+
+ Move to Category
+
+
+
+
+ Alt+S
+
+
+
+
+ Do you want to overwrite radio general settings?
+ 你希望覆蓋遙控器一般設定嗎?
+
+
+
+ Alt+Shift+E
+
+
+
+
+ Ctrl+Alt+C
+
+
+
+
+ Ctrl+Alt+V
+
+
+
+
+ Alt+Shift+S
+
+
+
+
+ Alt+C
+
+
+
+
+ Alt+A
+
+
+
+
+ Alt+R
+
+
+
+
+ Alt+W
+
+
+
+
+ Alt+U
+
+
+
+
+ %n Model(s)
+ As in "Copy 3 Models" or "Cut 1 Model" or "Delete 3 Models" action).
+
+
+
+
+
+
+ %n Model(s)
+ As in "Paste 3 Models" or "Insert 1 Model."
+
+
+
+
+
+
+ %n Category(ies)
+ As in "Delete 3 Categories" or "Delete 1 Category."
+
+
+
+
+
+
+ Nothing selected
+
+
+
+
+ Rename Category
+
+
+
+
+ Edit Model
+
+
+
+
+ Cut
+
+
+
+
+ Copy
+ 複製
+
+
+
+ Paste
+ 貼上
+
+
+
+ Insert
+
+
+
+
+ Edit Radio Settings
+
+
+
+
+ Copy Radio Settings
+
+
+
+
+ Paste Radio Settings
+
+
+
+
+ Simulate Radio
+
+
+
+
+ Add Category
+
+
+
+
+ Category
+
+
+
+
+ Add Model
+
+
+
+
+ Model
+ 模型名稱 [Model Name]
+
+
+
+ Restore from Backup
+
+
+
+
+ Model Wizard
+ 模型嚮導
+
+
+
+ Set as Default
+
+
+
+
+ Print Model
+
+
+
+
+ Simulate Model
+
+
+
+
+ Duplicate Model
+
+
+
+
+ Show Category Actions Toolbar
+
+
+
+
+ Show Radio Actions Toolbar
+
+
+
+
+ Show Model Actions Toolbar
+
+
+
+
+ free bytes
+ 剩餘空間 (Bytes)
+
+
+
+ New category
+ Translators do NOT use accent for this, this is the default category name on Horus.
+
+
+
+
+ Category index out of range.
+
+
+
+
+ Cannot delete the last category.
+
+
+
+
+ This category is not empty!
+
+
+
+
+ Cannot insert model, last model in list would be deleted.
+
+
+
+
+ Cannot add model, could not find an available model slot.
+
+
+
+
+ New model
+ Translators: do NOT use accents here, this is a default model name.
+
+
+
+
+ Cannot paste model, out of available model slots.
+
+
+
+
+ You are replacing an existing model, are you sure?
+
+
+
+
+ Delete %n selected model(s)?
+
+
+
+
+
+
+ Delete %n selected category(ies)?
+
+
+
+
+
+
+ Cannot duplicate model, could not find an available model slot.
+
+
+
+
+ Editing model %1:
+ 編輯模型 %1:
+
+
+
+ <p><b>Currently selected radio type (%1) is not compatible with file %3 (from %2), models and settings need to be converted.</b></p>
+
+
+
+
+ Unable to find Horus radio SD card!
+
+
+
+
+ Models and Settings written
+
+
+
+
+ Unable to find file %1!
+ 無法找到文件 %1!
+
+
+
+ Error opening file %1:
+%2.
+ 打開文件錯誤 %1:
+%2.
+
+
+
+ Error reading file %1:
+%2.
+ 打開文件錯誤 %1:
+%2.
+
+
+
+ Save As
+ 另存為
+
+
+
+ %1 has been modified.
+Do you want to save your changes?
+ %1已經修改.
+想要保存修改嗎?
+
+
+
+ Do you wish to continue with the conversion?
+
+
+
+
+ Choose <i>Apply</i> to convert the file, or <i>Close</i> to close it without conversion.
+
+
+
+
+ <b>The conversion generated some important messages, please review them below.</b>
+
+
+
+
+ Companion :: Conversion Result for %1
+
+
+
+
+ Cannot write temporary file!
+
+
+
+
+ Open backup Models and Settings file
+ 打開備份的模型和設置文件
+
+
+
+ Invalid binary backup File %1
+ 無效的二進製備份文件 %1
+
+
+
+ MixData
+
+
+ MIX
+
+
+
+
+ (@%1)
+
+
+
+
+ MixerDialog
+
+
+
+
+
+
+
+ Dialog
+ 對話框
+
+
+
+
+
+
+
+
+
+
+ Delay
+ 延遲 [Delay]
+
+
+
+
+
+
+
+
+
+
+ Slow
+ 慢動作 [Slow]
+
+
+
+
+
+
+
+
+
+
+ Up
+ 正向 [Up]
+
+
+
+
+
+
+
+
+
+
+ Down
+ 負向 [Dn]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600; text-decoration: underline;">Delay ans Slow</span></p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600; text-decoration: underline;"></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">These values control the speed and delay of the output of the mix. </p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If Delay is not zero the actuation of the mix will be delayed by the specified amount of seconds.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If Slow is not zero then the speed of the mix will be set by the value specified -> the value states the number of seconds it takes to transit from -100 to 100.</p></body></html>
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600; text-decoration: underline;">延迟和慢动作</span></p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600; text-decoration: underline;"></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">这些数值控制混控输出的延迟和慢动作 </p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">如果延迟值不为0, 混控的输出将延迟指定的秒数</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">如果慢动作值不为0, 混控的输出将按照指定的速度慢动作 -> 所设定数值为舵机从 -100% 运动到 +100%所需要时间.</p></body></html>
+
+
+
+
+
+
+
+
+
+
+ Include Trim
+ 微調 [Trim]
+
+
+
+
+
+
+
+
+
+
+ Offset
+ 偏移 [Offset]
+
+
+
+
+
+
+
+
+
+
+ Weight
+ 比例 [Weight]
+
+
+
+
+
+
+
+
+
+
+ Name
+ 名稱 [Name]
+
+
+
+
+
+
+
+
+
+
+ Source
+ 第一次出現 Mixer的主頁條目概覽中
+ 輸入源 [Source]
+
+
+
+
+
+
+
+
+
+
+ Multiplex
+ 混控方式 [Multiplex]
+
+
+
+
+
+
+
+
+
+
+ Warning
+ 啟用時蜂鳴 [Warning]
+
+
+
+
+
+
+
+
+
+
+ The curve used by the mix
+ 此混控使用的曲線
+
+
+
+
+
+
+
+
+
+
+ Include DR/Expo
+ 使用 DR/Expo
+
+
+
+
+
+
+
+
+
+
+ Flight modes
+ 飛行模式 [Modes]
+
+
+
+
+
+
+
+
+
+
+ Switch
+ 開啟開關 [Switch]
+
+
+
+
+
+
+
+
+
+
+ Mixer warning.
+Setting this value will cause a beep to be emmitted when this value is active.
+ 混控警告
+當本條混控啟用時發出蜂鳴.
+
+
+
+
+
+
+
+
+
+
+ OFF
+ 1聲蜂鳴 [1]
+ 關閉 [OFF]
+
+
+
+
+
+
+
+
+
+
+ 1 Beep
+ 1聲蜂鳴 [1]
+
+
+
+
+
+
+
+
+
+
+ 2 Beep
+ 2聲蜂鳴 [2]
+
+
+
+
+
+
+
+
+
+
+ 3 Beep
+ 3聲蜂鳴 [3]
+
+
+
+
+
+
+
+
+
+
+ No
+ 禁用微調 用在FM設定中
+ 不使用 [OFF]
+
+
+
+
+
+
+
+
+
+
+ Yes
+ 不使用 [OFF]
+ 使用 [On]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GV
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ The source for the mixer
+ 混控的輸入源
+
+
+
+
+
+
+
+
+
+
+ Multiplexer
+
+This determines how mixer values are added.
+
+"+" means the value of the current mix is added to the previous mixes in the same channel.
+"*" means the value of the current mix is amultiplied with the previous mixes in the same channel.
+"R" means the value replaces the previous values. If the switch is off the value will be ignored.
+ 混控方式
+
+規定了混控值如何混合
+
+"+"表示本混控值將會與此通道中的上條2混控 值相加.
+
+"*"表示本混控值將會與此通道中的上條混控值相乘.
+
+"R"表示本混控值將會取代此通道中的上條混控
+如果開關關閉此條混控將會被忽略.
+
+
+
+
+
+
+
+
+
+
+ ADD
+ 與前一行的輸出值相加後輸出 [Add]
+
+
+
+
+
+
+
+
+
+
+ MULTIPLY
+ 與前一行的輸出值相乘後輸出 [Multiply]
+
+
+
+
+
+
+
+
+
+
+ REPLACE
+ 與前一行的輸出值相乘後輸出 [Multiply]
+ 取代前一行的輸出值 [Replace]
+
+
+
+
+
+
+
+
+
+
+ Curve
+ 曲線 [Curve]
+
+
+
+
+
+
+
+
+
+
+ Switch used by the mix.
+If blank then the mix is considered to be "ON" all the time.
+ 用來開啟此條混控的開關
+如果不設定開啟開關則默認此條混控一直啟用.
+
+
+
+ DEST -> %1
+
+
+
+
+ Click to access popup menu
+
+
+
+
+ Clear All
+
+
+
+
+ Set All
+
+
+
+
+ Invert All
+
+
+
+
+
+ FullScreenDialog
+
+
+
+
+ MixersListWidget
+
+
+ Increase font size
+
+
+
+
+ Decrease font size
+
+
+
+
+ Default font size
+
+
+
+
+ Ctrl+0
+
+
+
+
+ MixesPanel
+
+
+
+ Move Up
+ 向上移動此行
+
+
+
+
+ Ctrl+Up
+
+
+
+
+
+ Move Down
+ 向下移動此行
+
+
+
+
+ Ctrl+Down
+ Ctrl+Dn
+
+
+
+ Clear Mixes
+ 清除本頁所有混控
+
+
+
+ Not enough available mixers!
+ 無空白混控存儲位置!
+
+
+
+ Delete Selected Mixes?
+ 是否刪除選擇的混控?
+
+
+
+ &Add
+ 添加 (&A)
+
+
+
+ Ctrl+A
+
+
+
+
+ &Edit
+ 編輯 (&E)
+
+
+
+ Enter
+ 確定
+
+
+
+ &Toggle highlight
+ 切換高亮 (&T)
+
+
+
+ Ctrl+T
+
+
+
+
+ &Delete
+ 删除 (&D)
+
+
+
+ Delete
+ 删除
+
+
+
+ &Copy
+ 複製 (&C)
+
+
+
+ Ctrl+C
+
+
+
+
+ C&ut
+ 剪下 (&C)
+
+
+
+ Ctrl+X
+
+
+
+
+ &Paste
+ 貼上 (&P)
+
+
+
+ Ctrl+V
+
+
+
+
+ Du&plicate
+ 克隆 (&P)
+
+
+
+ Ctrl+U
+
+
+
+
+ Clear Mixes?
+ 清除混控?
+
+
+
+ Really clear all the mixes?
+ 是否真的刪除所有混控?
+
+
+
+ ModelData
+
+
+ Model:
+
+
+
+
+ Throttle Source
+ 設為油門桿 [Thr Source]
+
+
+
+ ModelEdit
+
+
+
+
+
+
+
+ Dialog
+ 對話框
+
+
+
+
+
+
+
+
+
+
+ Simulate
+ 遙控器模擬器
+
+
+
+ Setup
+ 設置 Setup
+
+
+
+ Heli
+ 直升機 Heli
+
+
+
+ Flight Modes
+ 飛行模式 FM
+
+
+
+ Inputs
+ 輸入 Inputs
+
+
+
+ Mixes
+ !!!! mixes-->mixer
+ 混控 Mixer
+
+
+
+ Outputs
+ 輸出 Outputs
+
+
+
+ Curves
+ ModelEdit
+ 曲線 Curves
+
+
+
+ Logical Switches
+ 邏輯開關 Logical Sw
+
+
+
+ Special Functions
+ 特殊功能 Special Func
+
+
+
+ Telemetry
+ 回傳設置 Tele
+
+
+
+
+ FullScreenDialog
+
+
+
+
+ ModelPrinter
+
+
+ Exponential
+ 指微調的步長
+ 先小後大 [Exp]
+
+
+
+ Extra Fine
+ 很小 [Extra Fine]
+
+
+
+ Fine
+ 小 [Fine]
+
+
+
+ Medium
+ 中等 [Medium]
+
+
+
+ Coarse
+ 大 [Coarse]
+
+
+
+ Unknown
+ Model Printer
+ 未知[Unknown]
+
+
+
+ Slave/Jack
+ 教練從機/教練線插口 [Slave/Jack]
+
+
+
+ Master/SBUS Module
+ 教練主機/SBUS 模塊 [Master/SBUS]
+
+
+
+ Master/CPPM Module
+ 教練主機/CPPM 模塊 [Master/CPPM]
+
+
+
+ Master/SBUS in battery compartment
+ 教练主机/SBUS 电池盒中插座
+
+
+
+ Master/Jack
+ 教练主机/教练线插口 [Master/Jack]
+
+
+
+ Enable
+
+
+
+
+ Disable
+
+
+
+
+ True
+
+
+
+
+ False
+
+
+
+
+ Yes
+
+
+
+
+ No
+
+
+
+
+ Y
+
+
+
+
+ N
+
+
+
+
+ ON
+ 啟用
+
+
+
+
+
+
+ OFF
+
+
+
+
+ bytes
+
+
+
+
+
+ Mode
+ 模式
+
+
+
+
+ Channels
+ 通道數 [Channels]
+
+
+
+
+ Frame length
+
+
+
+
+ PPM delay
+ PPM 延遲 [Delay]
+
+
+
+
+ Polarity
+ 極性 [Polarity]
+
+
+
+ Protocol
+
+
+
+
+
+
+ Delay
+
+
+
+
+
+ Receiver
+ 接收機設置[Reciever]
+
+
+
+ Radio protocol
+
+
+
+
+ Subtype
+
+
+
+
+ Option value
+
+
+
+
+ Sub Type
+
+
+
+
+ RF Output Power
+
+
+
+
+ 90
+
+
+
+
+ 120
+
+
+
+
+ 120X
+
+
+
+
+ 140
+
+
+
+
+ Off
+ Model Printer
+ 关闭
+
+
+
+
+
+
+
+
+ None
+ 无
+
+
+
+ Name
+
+
+
+
+ Countdown
+ 倒數報數
+
+
+
+ Minute call
+
+
+
+
+ MULT!
+
+
+
+
+
+ Offset
+
+
+
+
+ Slow
+ 慢動作 [Slow]
+
+
+
+ Warn
+
+
+
+
+ Flight modes
+
+
+
+
+ Flight mode
+ 飛行模式 [Modes]
+
+
+
+ All
+ 開啟 [All]
+
+
+
+ Edge
+ 邊沿觸發 EDGE
+
+
+
+ Sticky
+ 粘滯鍵 Sticky
+
+
+
+ Timer
+ 定時開關 Timer
+
+
+
+ missing
+
+
+
+
+ Duration
+ 持續時間 [Duration]
+
+
+
+ Extended Limits
+ 舵機上下限擴展
+[Extended Limits]
+
+
+
+ Display Checklist
+ 顯示檢查單
+[Checklist]
+
+
+
+ Global Functions
+
+
+
+
+ Manual
+ 手動 [Manual]
+
+
+
+ Auto
+ 用關機位置 [Auto]
+
+
+
+ Failsafe Mode
+ 失控保護方式 [Failsafe Mode]
+
+
+
+
+ Hold
+
+
+
+
+ No Pulse
+ 不輸出脈衝 [No Pulse]
+
+
+
+ Not set
+ 未設置
+
+
+
+ No pulses
+
+
+
+
+ Silent
+ 静音 [Silent]
+
+
+
+ Beeps
+ 蜂鳴 [Beeps]
+
+
+
+ Voice
+ 語音 [Voice]
+
+
+
+ Haptic
+ 振動 [Haptic]
+
+
+
+ Flight
+ 飛行 [Flight]
+
+
+
+ Manual reset
+
+
+
+
+ Step
+
+
+
+
+ Display
+
+
+
+
+ Extended
+
+
+
+
+ Never
+ 從不 [Never]
+
+
+
+ On Change
+
+
+
+
+ Always
+ 一直 [Always]
+
+
+
+
+
+ Source
+
+
+
+
+ Trim idle only
+
+
+
+
+ Warning
+ 啟用時蜂鳴 [Warning]
+
+
+
+ Reversed
+
+
+
+
+ Tmr
+
+
+
+
+ FrSky S.PORT
+
+
+
+
+ FrSky D
+
+
+
+
+ FrSky D (cable)
+
+
+
+
+ Alti
+ 高度
+
+
+
+ Alti+
+ 最大高度
+
+
+
+ VSpeed
+ 垂直速度
+
+
+
+
+
+ A1
+ A1 模擬值1
+
+
+
+
+
+ A2
+ A2 模擬值2
+
+
+
+
+ A3
+ A3 模擬值3
+
+
+
+
+ A4
+ A4 模擬值4
+
+
+
+
+ FAS
+ FAS
+
+
+
+ Cells
+ 鋰電總電壓
+
+
+
+ Calculated
+ 運算
+
+
+
+ Add
+ 加
+
+
+
+ Average
+ 平均值
+
+
+
+
+ Min
+
+
+
+
+
+ Max
+
+
+
+
+ Multiply
+ 乘以
+
+
+
+ Totalise
+
+
+
+
+ Cell
+ 鋰電單片電壓
+
+
+
+ Consumption
+ 消耗
+
+
+
+ Distance
+
+
+
+
+ Lowest
+ 最低
+
+
+
+ Cell %1
+ 第%1片
+
+
+
+ Highest
+ 最高
+
+
+
+ Delta
+ 每片電壓差
+
+
+
+ Formula
+
+
+
+
+
+ Id
+
+
+
+
+ Instance
+ 對象
+
+
+
+
+
+
+ Sensor
+
+
+
+
+
+ Sources
+
+
+
+
+
+ GPS
+
+
+
+
+ Alt.
+
+
+
+
+
+ Blades
+ 旋翼數
+
+
+
+ Multi.
+
+
+
+
+ F
+
+
+
+
+ Inst
+
+
+
+
+ Alt
+ Alt 高度
+
+
+
+ Unit
+
+
+
+
+ Prec
+
+
+
+
+ Ratio
+ 比例
+
+
+
+ Multi
+
+
+
+
+ A/Offset
+
+
+
+
+ Filter
+ 過濾器
+
+
+
+ Persist
+
+
+
+
+ Positive
+
+
+
+
+ Log
+
+
+
+
+ Numbers
+ 數字
+
+
+
+ Bars
+ 條狀圖
+
+
+
+ Script
+ 腳本
+
+
+
+ Filename
+ 文件名
+
+
+
+ Error: Unable to open or read file!
+
+
+
+
+ Persistent
+ 保持[Persistent]
+
+
+
+
+
+ FM%1
+
+
+
+
+ FM%1%2
+
+
+
+
+ FM%1+%2
+
+
+
+
+
+ Weight
+ 比例 [Weight]
+
+
+
+
+ Switch
+ 啟用開[Switch]
+
+
+
+
+ NoTrim
+ 不使用微調[Notrim]
+
+
+
+ Offset(%1)
+ 偏移[Offse](%1)
+
+
+
+ No DR/Expo
+ 不使用 DR/Expo
+
+
+
+ Disabled in all flight modes
+ 在所有飛行模式中禁用
+
+
+
+ instant
+ 立刻執行[instant]
+
+
+
+
+
+ Custom
+ 自定義[Custom]
+
+
+
+ Standard
+ 標準[Standard]
+
+
+
+ ModelSelectionPage
+
+
+ Plane
+ 固定翼
+
+
+
+ Multirotor
+ 多軸
+
+
+
+ Helicopter
+ 直升機
+
+
+
+ Model Name:
+ 模型名稱:
+
+
+
+ Model Type:
+ 模型種類:
+
+
+
+ Module
+
+
+
+
+
+
+
+
+
+ CH
+ 通道
+
+
+
+
+
+
+
+
+
+
+ Failsafe Mode
+ 失控保護方式 [Failsafe Mode]
+
+
+
+
+
+
+
+
+
+
+ Start
+ 開始通道 [CH]
+
+
+
+
+
+
+
+
+
+
+ PPM delay
+ PPM 延遲 [Delay]
+
+
+
+
+
+
+
+
+
+
+ us
+ 微秒
+
+
+
+
+
+
+
+
+
+
+ Negative
+ 負 [Negative]
+
+
+
+
+
+
+
+
+
+
+ Positive
+ 正 [Positive]
+
+
+
+
+
+
+
+
+
+
+ RF Output Power
+
+
+
+
+
+
+
+
+
+
+
+ Antenna
+
+
+
+
+
+
+
+
+
+
+
+ Option value
+
+
+
+
+
+
+
+
+
+
+
+ Sub Type
+
+
+
+
+
+
+
+
+
+
+
+ Master/Jack
+ 教練主機/教練線插口 [Master/Jack]
+
+
+
+
+
+
+
+
+
+
+ Slave/Jack
+ 教練從機/教練線插口 [Slave/Jack]
+
+
+
+
+
+
+
+
+
+
+ Master/SBUS Module
+ 教練主機/SBUS 模組 [Master/SBUS]
+
+
+
+
+
+
+
+
+
+
+ Master/CPPM Module
+ 教練主機/CPPM 模組 [Master/CPPM]
+
+
+
+
+
+
+
+
+
+
+ Master/SBUS in battery compartment
+ 教練主機/SBUS 電池盒中插座
+
+
+
+
+
+
+
+
+
+
+ Show values in:
+
+
+
+
+
+
+
+
+
+
+
+ %
+ abbreviation for percent
+
+
+
+
+
+
+
+
+
+
+
+ μs
+ abbreviation for microseconds
+
+
+
+
+
+
+
+
+
+
+
+ Polarity
+ 極性 [Polarity]
+
+
+
+
+
+
+
+
+
+
+ Trainer Mode
+ 教練功能模式 [Trainer Mode]
+
+
+
+
+
+
+
+
+
+
+ ms
+ 毫秒
+
+
+
+
+
+
+
+
+
+
+ PPM Frame Length
+ PPM幀長 [Frame Length]
+
+
+
+
+
+
+
+
+
+
+ Channels
+ 通道數 [Channels]
+
+
+
+
+
+
+
+ Receiver 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ X
+
+
+
+
+
+
+
+
+ Receiver 2
+
+
+
+
+
+
+
+
+ Receiver 3
+
+
+
+
+
+
+
+
+
+
+
+ WARNING: changing RF Output Power needs RE-BIND
+
+
+
+
+
+
+
+
+ Registration ID
+
+
+
+
+
+
+
+
+
+
+
+ WARNING: Requires non-certified firmware!
+
+
+
+
+
+
+
+
+
+
+
+ Not set
+ 未設置
+
+
+
+
+
+
+
+
+
+
+ Hold
+ 自定義 [Custom]]]]]
+ 保持 [Hold]
+
+
+
+
+
+
+
+
+
+
+ Custom
+ 自定義 [Custom]]]]]
+ 自定義 [Custom]
+
+
+
+
+
+
+
+
+
+
+ No Pulses
+ 自定義 [Custom]]]]]
+ 不輸出脈衝 [No Puls]
+
+
+
+
+
+
+
+
+
+
+ Receiver
+ 自定義 [Custom]]]]]
+ 接收機設置[Reciever]
+
+
+
+
+
+
+
+
+
+
+ Failsafe Positions
+ 失控保護位置 [F.s. Positons]
+
+
+
+
+
+
+
+
+
+
+ Protocol
+ 遙控器發射協議 [Protocol]
+
+
+
+
+
+
+
+
+
+
+ Multi Radio Protocol
+ 多遙控協議 [Multi Protocal]
+
+
+
+
+
+
+
+
+
+
+ Receiver No.
+ 接收機編號 [Receiver No.].
+
+
+
+
+
+
+
+
+
+
+ Output type
+ 輸出類型 [Output type]
+
+
+
+
+
+
+
+
+
+
+ Open Drain
+ 開漏輸出 [Open Drain]
+
+
+
+
+
+
+
+
+
+
+ Push Pull
+ 推挽輸出 [Push Pull]
+
+
+
+
+
+
+
+
+
+
+ Bind on startup
+ 開機時對頻[Bind]
+
+
+
+
+
+
+
+
+
+
+ Low Power
+ 低功率[Range]
+
+
+
+
+
+
+ Internal
+
+
+
+
+
+
+
+ Ext. + Int.
+
+
+
+
+ ModuleData
+
+
+ Positive
+
+
+
+
+ Negative
+ 负 [Negative]
+
+
+
+ Trainer Port
+ 教練功能 [Trainer Port]
+
+
+
+ Internal Radio System
+ 內置高頻頭 [Internal RF]
+
+
+
+ External Radio Module
+ 外置高頻頭 [External RF]
+
+
+
+ Extra Radio System
+ 附加高頻頭 [Extra RF]
+
+
+
+ Radio System
+ 高頻頭 [Radio System]
+
+
+
+ 10mW - 16CH
+
+
+
+
+
+ 100mW - 16CH
+
+
+
+
+ 500mW - 16CH
+
+
+
+
+ Auto <= 1W - 16CH
+
+
+
+
+
+ 25mW - 8CH
+
+
+
+
+
+ 25mW - 16CH
+
+
+
+
+ 200mW - 16CH (no telemetry)
+
+
+
+
+ 500mW - 16CH (no telemetry)
+
+
+
+
+ 100mW - 16CH (no telemetry)
+
+
+
+
+ ModulePanel
+
+
+ Value
+ 自定義回傳中使用
+ 設為
+
+
+
+ Hold
+ 保持 [Hold]
+
+
+
+ No Pulse
+ 不輸出脈衝 [No Pulse]
+
+
+
+ Ask
+
+
+
+
+ Internal
+
+
+
+
+ Internal + External
+
+
+
+
+ External
+
+
+
+
+ MultiModelPrinter
+
+
+ Input
+ 輸入
+
+
+
+ Weight
+ 比例 [Weight]
+
+
+
+ Long. cyc
+ 縱向循環螺距 [Long]
+
+
+
+ Lateral cyc
+ 橫向循環螺距 [Lateral]
+
+
+
+ Collective
+ 總距 [Collective]
+
+
+
+ Flight modes
+ 飛行模式 [Modes]
+
+
+
+
+ Flight mode
+ 飛行模式 [Modes]
+
+
+
+
+ Switch
+ 啟用開關 [Switch]
+
+
+
+ General
+
+
+
+
+ EEprom Size
+
+
+
+
+ Model Image
+ 模型圖片 [Medel Image]
+
+
+
+ Throttle
+ 油門
+
+
+
+ Trims
+
+
+
+
+ Center Beep
+
+
+
+
+ Switch Warnings
+ 開關位置警告 [Switch Positions]
+
+
+
+ Pot Warnings
+ 旋鈕位置警告 [Pot Positions]
+
+
+
+ Other
+
+
+
+
+ Timers
+
+
+
+
+ Time
+ Time 當前時間
+
+
+
+ Countdown
+ 倒數報數
+
+
+
+ Modules
+
+
+
+
+ Trainer port
+
+
+
+
+ Helicopter
+ 直升機
+
+
+
+ Swash
+
+
+
+
+
+ Type
+
+
+
+
+ Ring
+
+
+
+
+ Protocol
+
+
+
+
+ Low
+
+
+
+
+ Critical
+
+
+
+
+ Telemetry audio
+
+
+
+
+ Altimetry
+ 高度計
+
+
+
+
+ Vario source
+ Vario 傳感器
+
+
+
+ Vario limits >
+
+
+
+
+ Sink max
+
+
+
+
+ Sink min
+
+
+
+
+ Climb min
+
+
+
+
+ Climb max
+
+
+
+
+ Center silent
+
+
+
+
+ Top Bar
+ 頂部橫條
+
+
+
+
+ Volts source
+ 電壓傳感器
+
+
+
+ Altitude source
+ 高度傳感器
+
+
+
+ Various
+ 不同的
+
+
+
+ Serial protocol
+
+
+
+
+ FAS offset
+
+
+
+
+ mAh count
+
+
+
+
+ Persistent mAh
+ 保持mAh
+
+
+
+ Current source
+ 當前源
+
+
+
+ Blades
+ 旋翼數
+
+
+
+ Parameters
+ 參數
+
+
+
+ Telemetry Sensors
+
+
+
+
+ Telemetry Screens
+
+
+
+
+ GF%1
+ GF%1
+
+
+
+ Global Functions
+
+
+
+
+ Checklist
+
+
+
+
+
+ GV%1
+
+
+
+
+ RE%1
+
+
+
+
+ Channel
+ 通道
+
+
+
+
+
+ Name
+ 名稱 [Name]
+
+
+
+ Prec
+
+
+
+
+ Popup
+
+
+
+
+ Outputs
+ 輸出 Outputs
+
+
+
+ Subtrim
+ 舵機中位 [Subtrim]
+
+
+
+ Direct
+
+
+
+
+ Curve
+
+
+
+
+ PPM
+
+
+
+
+ Linear
+ 直線
+
+
+
+ Telemetry
+
+
+
+
+ Offset
+ 偏移 [Offset]
+
+
+
+
+ Min
+ 舵機下限 [Min]
+
+
+
+ Min.call
+
+
+
+
+ Persist
+
+
+
+
+ F.In
+
+
+
+
+ F.Out
+
+
+
+
+ Global vars
+
+
+
+
+
+ Max
+ 舵機上限 [Max]
+
+
+
+ Global Variables
+ 全局變量 [Global Variables]
+
+
+
+ Inputs
+ 輸入
+
+
+
+ Mixers
+ 混控 [Mixers]
+
+
+
+ Curves
+ 多點曲線 [Curves]
+
+
+
+ L%1
+
+
+
+
+ Logical Switches
+ 邏輯開關 [Logical Sw]
+
+
+
+ SF%1
+
+
+
+
+ Special Functions
+ 特殊功能 [Special Func]
+
+
+
+ Analogs
+ 模擬量 [Analogs]
+
+
+
+
+ Unit
+ 單位 [Unit]
+
+
+
+ Scale
+ 縮放 [Scale]
+
+
+
+ RSSI Alarms
+ RSSI 警告 [RSSI Alarms]
+
+
+
+ Multiprotocols
+
+
+ Subtype
+
+
+
+
+ Video TX frequency
+
+
+
+
+ CC2500 frequency fine tune
+
+
+
+
+ Telemetry
+
+
+
+
+ Radio output power
+
+
+
+
+ Servo output frequency
+
+
+
+
+ Option value
+
+
+
+
+ Fixed ID value
+
+
+
+
+ DEFAULT
+
+
+
+
+ Custom - proto %1)
+
+
+
+
+ MultirotorPage
+
+
+ Throttle Channel:
+ 油門通道 [Throttle]:
+
+
+
+ Yaw Channel:
+ 偏航通道 [Yaw]:
+
+
+
+ Pitch Channel:
+ 仰俯通道 [Pitch]:
+
+
+
+ Roll Channel:
+ 滾轉通道 [Roll]:
+
+
+
+ OpenTxEepromInterface
+
+
+ Unknown error
+
+
+
+
+ ... plus %1 errors
+
+
+
+
+ Cannot write radio settings
+
+
+
+
+ Cannot write model %1
+
+
+
+
+ OptionsPage
+
+
+ Throttle Cut
+ 油門切斷 [Throttle Cut]
+
+
+
+ Throttle Timer
+ 油門計時器 [Throttle Timer]
+
+
+
+ Flight Timer
+ 飛行計時器 [Flight Timer]
+
+
+
+ OtxFormat
+
+
+ Error opening file %1:
+%2.
+ 打開文件錯誤 %1:
+%2.
+
+
+
+ Error opening OTX archive %1
+ 打開 OTX 存檔錯誤 %1. {1?}
+
+
+
+ Error initializing OTX archive writer
+ OTX 存檔寫入器初始化錯誤
+
+
+
+ Error writing file %1:
+%2.
+ 寫入文件錯誤 %1:
+%2.
+
+
+
+ Error creating OTX file %1:
+%2.
+ 創建 OTX 存檔 %1時出錯:
+%2.
+
+
+
+ Error creating OTX archive
+ 創建 OTX 存檔時出錯
+
+
+
+ Error adding %1 to OTX archive
+ 将 %1 加入到 OTX 存檔時出錯
+
+
+
+ PrintDialog
+
+
+
+
+
+
+
+
+
+ Close
+ 關閉
+
+
+
+
+
+
+
+
+
+
+ Style
+
+
+
+
+
+
+
+
+
+
+
+ Print
+ 打印
+
+
+
+
+
+
+
+
+
+
+ Print to file
+ 打印到文件
+
+
+
+ Print Document
+ 打印文檔
+
+
+
+ Select PDF output file
+ 選擇PDF輸出文件
+
+
+
+ ODF files (*.odt);;PDF Files(*.pdf);;HTML-Files (*.htm *.html);;All Files (*)
+ ODF 文件 (*.odt);;PDF 文件 (*.pdf);;HTML文件 (*.htm *.html);;所有文件 (*)
+
+
+
+ ProgressDialog
+
+
+
+
+
+
+
+
+
+ Flash Firmware
+ 燒錄韌體
+
+
+
+
+
+
+
+
+
+
+
+ Close
+ 關閉
+
+
+
+ Cancel
+ 取消
+
+
+
+ ProgressWidget
+
+
+
+
+
+
+
+
+
+ Show Details
+ 顯示詳情
+
+
+
+ RadioData
+
+
+ Models
+
+
+
+
+ RadioDataConversionState
+
+
+ is invalid
+
+
+
+
+ converted to
+
+
+
+
+ verify is
+
+
+
+
+ [DBG]
+
+
+
+
+ [NFO]
+
+
+
+
+ [WRN]
+
+
+
+
+ [CVT]
+
+
+
+
+ [ERR]
+
+
+
+
+ [INV]
+
+
+
+
+ Event
+
+
+
+
+ Origin
+
+
+
+
+ Comp
+
+
+
+
+ Sub-Component
+
+
+
+
+ Field
+
+
+
+
+ Type
+
+
+
+
+ Old
+
+
+
+
+ Action
+ 功能
+
+
+
+ New
+ 新建配置文件
+
+
+
+ Seq
+
+
+
+
+ RadioInterface
+
+
+ Cannot write file %1:
+%2.
+ 無法寫入文件 %1:
+%2.
+
+
+
+ <b><u>WARNING!</u></b><br>This will reset the fuses of %1 to the factory settings.<br>Writing fuses can mess up your radio.<br>Do this only if you are sure they are wrong!<br>Are you sure you want to continue?
+ <b><u>警告!</u></b><br>這將把 %1 的熔絲位恢復工廠設置<br>改變熔絲位可能使你的遙控器變磚.<br>只有當你確定它們是錯誤的時候才能進行此操作!<br>你確認要繼續嗎?
+
+
+
+
+ Could not delete temporary file: %1
+ 無法刪除臨時文件: %1
+
+
+
+ Unable to find Horus radio SD card!
+
+
+
+
+ RadioKnobWidget
+
+
+ <p>Value (input): <b>%1</b></p>
+
+
+
+
+ Right-double-click to reset to center.
+
+
+
+
+ RadioNotFoundDialog
+
+
+
+
+
+
+
+
+
+ No Radio Found
+ 未找到遙控器
+
+
+
+
+
+
+
+
+
+
+ <html><head/><body><p>No Radio was found!</p><p>Make sure that you hold the lower trim buttons towards the center while you turn it on.</p><p>Then connect the USB wire.</p><p><span style=" font-family:'arial,sans-serif'; font-size:13px; font-style:italic; color:#222222; background-color:#ffffff;">Note: if you have a Taranis that has not had the firmware upgraded to 2.0 then this version of Companion will not work.</span></p></body></html>
+ <html><head/><body><p>未找到遥控器!</p><p>先將這兩個微調按鈕同時保持撥向內側, 然後再打開遙控器.</p><p>開機後再插上USB線.</p><p><span style=" font-family:'arial,sans-serif'; font-size:13px; font-style:italic; color:#222222; background-color:#ffffff;">提示:如果你的X9D遙控器尚未升級到2.0版本, 則不能使用這個版本的 Compaion 軟體.</span></p></body></html>
+
+
+
+
+
+
+
+
+
+
+ OK
+
+
+
+
+ RadioOutputsWidget
+
+
+
+
+
+
+
+
+
+
+
+ Form
+ 表單
+
+
+
+
+
+
+
+
+
+
+
+
+ View:
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Logical Switches
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Global Variables
+ 全局變量 [Global Variables]
+
+
+
+
+
+
+
+
+
+
+
+
+ Channel Outputs
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Mix Outputs
+
+
+
+
+
+
+
+
+
+
+
+
+
+ L
+o
+g
+i
+c
+
+
+
+
+
+
+
+
+
+
+
+
+
+ G
+l
+o
+b
+a
+l
+
+
+
+
+
+
+
+
+
+
+
+
+
+ C
+h
+a
+n
+n
+e
+l
+s
+
+
+
+
+
+
+
+
+
+
+
+
+
+ M
+i
+x
+e
+s
+
+
+
+
+ FM%1
+
+
+
+
+ GV%1
+
+
+
+
+ RadioSwitchWidget
+
+
+ Latch/unlatch the momentary switch.
+
+
+
+
+ RawSource
+
+
+
+
+
+ V
+
+
+
+
+
+
+
+ s
+
+
+
+
+ ft
+
+
+
+
+
+ m
+
+
+
+
+ °C
+
+
+
+
+ °
+
+
+
+
+ %
+
+
+
+
+
+ mph
+
+
+
+
+
+ km/h
+
+
+
+
+ m/s
+
+
+
+
+ A
+
+
+
+
+ mAh
+
+
+
+
+ W
+
+
+
+
+ g
+
+
+
+
+ TrmR
+ TrmR 方向微調
+
+
+
+ TrmE
+ TrmE 升降微調
+
+
+
+ TrmT
+ TrmT 油門微調
+
+
+
+ TrmA
+ TrmA 副翼微調
+
+
+
+ Trm5
+
+
+
+
+ Trm6
+
+
+
+
+ TrmH
+
+
+
+
+ TrmV
+
+
+
+
+
+ Batt
+ Batt 控電電壓
+
+
+
+
+ Time
+ Time 當前時間
+
+
+
+
+ Timer1
+ 計時器1 [Timer1]
+
+
+
+
+ Timer2
+ 計時器2 [Timer2]
+
+
+
+
+ Timer3
+ 計時器3 [Timer3]
+
+
+
+ RAS
+
+
+
+
+ RSSI Tx
+ RSSI Tx 發射機RSSI
+
+
+
+ RSSI Rx
+ RSSI Rx 接收機RSSI
+
+
+
+ A1
+ A1 模擬值1
+
+
+
+ A2
+ A2 模擬值2
+
+
+
+ A3
+ A3 模擬值3
+
+
+
+ A4
+ A4 模擬值4
+
+
+
+ Alt
+ Alt 高度
+
+
+
+ Rpm
+ Rpm 轉速
+
+
+
+ Fuel
+ Fule 燃油
+
+
+
+ T1
+ T1 温度1
+
+
+
+ T2
+ T2 温度2
+
+
+
+ Speed
+ Speed 速度
+
+
+
+ Dist
+ 距離
+
+
+
+ GPS Alt
+ GPS Alt GPS高度
+
+
+
+ Cell
+ 鋰電單片電壓
+
+
+
+ Cells
+ 鋰電總電壓
+
+
+
+ Vfas
+ Vfas FAS傳感器電壓
+
+
+
+ Curr
+ Curr 電流
+
+
+
+ Cnsp
+ Cnsp 電池使用mAh
+
+
+
+ Powr
+ Powr 功率
+
+
+
+ AccX
+ AccX X軸加速度
+
+
+
+ AccY
+ AccY Y軸加速度
+
+
+
+ AccZ
+ AccZ Z軸加速度
+
+
+
+ Hdg
+ Hdg 航向角
+
+
+
+ VSpd
+ VSpd 垂直速度
+
+
+
+ AirSpeed
+ AirSpeed 空速
+
+
+
+ dTE
+ dTE 總能量變化
+
+
+
+ A1-
+ A1- 模擬值1-
+
+
+
+ A2-
+ A2- 模擬值2-
+
+
+
+ A3-
+ A3- 模擬值3-
+
+
+
+ A4-
+ A4- 模擬值4-
+
+
+
+ Alt-
+ Alt- 最小高度
+
+
+
+ Alt+
+ Alt+ 最大高度
+
+
+
+ Rpm+
+
+
+
+
+ T1+
+ T1+ 温度1+
+
+
+
+ T2+
+ T2+ 温度2+
+
+
+
+ Speed+
+
+
+
+
+ Dist+
+
+
+
+
+ AirSpeed+
+
+
+
+
+ Cell-
+
+
+
+
+ Cells-
+
+
+
+
+ Vfas-
+
+
+
+
+ Curr+
+
+
+
+
+ Powr+
+
+
+
+
+ ACC
+ ACC 加速度
+
+
+
+ GPS Time
+ GPS Time GPS時間
+
+
+
+ REa
+
+
+
+
+ REb
+
+
+
+
+
+ ???
+
+
+
+
+ ----
+
+
+
+
+ I
+ as in Input
+
+
+
+
+ LUA%1%2
+
+
+
+
+ MAX
+ MAX 最大
+
+
+
+ CYC%1
+ CYC%1 循環螺距
+
+
+
+ TR
+ as in Trainer
+
+
+
+
+ SRC
+
+
+
+
+ RawSwitch
+
+
+ ↑
+
+
+
+
+ ↓
+
+
+
+
+ -
+
+
+
+
+ !
+
+
+
+
+ RudTrim Left
+ RudTrim Left 方向微調←
+
+
+
+ RudTrim Right
+ RudTrim Right 方向微調→
+
+
+
+ EleTrim Down
+ EleTrim Down 升降微調↓
+
+
+
+ EleTrim Up
+ EleTrim Up 升降微調↑
+
+
+
+ ThrTrim Down
+ ThrTrim Down 油門微調↓
+
+
+
+ ThrTrim Up
+ ThrTrim Up 油門微調↑
+
+
+
+ AilTrim Left
+ AilTrim Left 副翼微調←
+
+
+
+ AilTrim Right
+ AilTrim Right 副翼微調→
+
+
+
+ Trim 5 Down
+
+
+
+
+ Trim 5 Up
+
+
+
+
+ Trim 6 Down
+
+
+
+
+ Trim 6 Up
+
+
+
+
+ TrmH Left
+
+
+
+
+ TrmH Right
+
+
+
+
+ TrmV Down
+
+
+
+
+ TrmV Up
+
+
+
+
+ REa
+
+
+
+
+ REb
+
+
+
+
+
+ OFF
+
+
+
+
+
+ ON
+ 啟用
+
+
+
+ THs
+ THs 油門激活
+
+
+
+ TH%
+ TH% 油門比例
+
+
+
+ THt
+ THt 油門計時
+
+
+
+
+ ???
+
+
+
+
+ One
+ One 單次
+
+
+
+ ----
+
+
+
+
+ Telemetry
+
+
+
+
+ SW
+
+
+
+
+ ReleaseNotesDialog
+
+
+ Companion Release Notes
+ Companion 版本發布說明
+
+
+
+ ReleaseNotesFirmwareDialog
+
+
+ OpenTX Release Notes
+ OpenTx 版本發布說明
+
+
+
+ RepeatComboBox
+
+
+ Played once, not during startup
+ 播放一次但開機時不播放 [!1x]
+
+
+
+ No repeat
+ 播放一次 [1x]
+
+
+
+ %1s
+ 每%1秒播放一次
+
+
+
+ RudderPage
+
+
+ No
+ RudderPage
+ 没有方向舵
+
+
+
+ Yes
+ RudderPage
+ 有方向舵
+
+
+
+ <br>Rudder Channel:
+ <br>方向舵通道:
+
+
+
+ SdcardFormat
+
+
+ Error opening file %1:
+%2.
+ 打開文件錯誤 %1:
+%2.
+
+
+
+ Error opening file %1 in write mode:
+%2.
+
+
+
+
+ SensorData
+
+
+
+ V
+
+
+
+
+ A
+
+
+
+
+ mA
+
+
+
+
+ kts
+
+
+
+
+ m/s
+
+
+
+
+ km/h
+
+
+
+
+ mph
+
+
+
+
+ m
+
+
+
+
+ f
+
+
+
+
+ °C
+
+
+
+
+ °F
+
+
+
+
+ %
+
+
+
+
+ mAh
+
+
+
+
+ W
+
+
+
+
+ mW
+
+
+
+
+ dB
+
+
+
+
+ rpms
+
+
+
+
+ g
+
+
+
+
+ °
+
+
+
+
+ Rad
+
+
+
+
+ hours
+ 小时
+
+
+
+ minutes
+ 分
+
+
+
+ seconds
+ 秒
+
+
+
+ TELE
+
+
+
+
+ Internal
+
+
+
+
+ External
+
+
+
+
+ Setup
+
+
+
+
+
+
+
+
+
+ Timer 1
+ 計時器 1 [Timer 1]
+
+
+
+
+
+
+
+
+
+
+ Top LCD Timer
+ 頂部 LCD 計時器
+
+
+
+
+
+
+
+
+
+
+ Model Image
+ 模型圖片 [Medel Image]
+
+
+
+
+
+
+
+
+
+
+ Warnings
+ 警告 [Warnings]
+
+
+
+
+
+
+
+
+
+
+ Switch Warnings
+ 開關位置警告 [Switch Positions]
+
+
+
+
+
+
+
+
+
+
+ Pot Warnings
+ 旋鈕位置警告 [Pot Positions]
+
+
+
+
+
+
+
+
+
+
+ OFF
+ 關閉 [OFF]
+
+
+
+
+
+
+
+
+
+
+ Manual
+ 手動 [Manual]
+
+
+
+
+
+
+
+
+
+
+ Auto
+ 用關機位置 [Auto]
+
+
+
+
+
+
+
+
+
+
+ Model
+ 模型名稱 [Model Name]
+
+
+
+
+
+
+
+
+
+
+ Center beep
+ 回中蜂鳴 [Center Beep]
+
+
+
+
+
+
+
+
+
+
+ Edit Checklist...
+
+
+
+
+
+
+
+
+
+
+
+ Extended Trims
+ 微調範圍擴展
+[Extended Trims]
+
+
+
+
+
+
+
+
+
+
+ Display Checklist
+ 顯示檢查單
+[Checklist]
+
+
+
+
+
+
+
+
+
+
+ Extended Limits
+ 舵機上下限擴展
+[Extended Limits]
+
+
+
+
+
+
+
+
+
+
+ Reverse throttle operation.
+If this is checked the throttle will be reversed. Idle will be forward, trim will also be reversed and the throttle warning will be reversed as well.
+
+
+ 將油門桿反向
+如果選中這個選項, 油門桿將會反向. 油門桿向前關閉油門, 油門桿向前打開油門. 油門微調同時會被反向 .油門桿警告同時也反向動作 .
+
+
+
+
+
+
+
+
+
+
+
+
+ Reverse Throttle
+ 油門桿反向
+{Reverse]
+
+
+
+
+
+
+
+
+
+
+ Throttle Trim Idle Only
+ 油門微調只改變怠速
+[Trim Idle]
+
+
+
+
+
+
+
+
+
+
+ Throttle Warning
+ 油門杆位置警告
+[Throttle State]
+
+
+
+
+
+
+
+
+
+
+ Exponential
+ 先小後大 [Exp]
+
+
+
+
+
+
+
+
+
+
+ Extra Fine
+ 很小 [Extra Fine]
+
+
+
+
+
+
+
+
+
+
+ Fine
+ 較小 [Fine]
+
+
+
+
+
+
+
+
+
+
+ Medium
+ 中等 [Medium]
+
+
+
+
+
+
+
+
+
+
+ Coarse
+ 較大 [Coarse]
+
+
+
+
+
+
+
+
+
+
+ Never
+ 微調從不顯示在LCD顯示屏上
+ 从不 [Never]
+
+
+
+
+
+
+
+
+
+
+ On change
+ ????意思是說微調在撥動微調開關時才在LCD顯示屏上顯示
+ 調整時 [On change]
+
+
+
+
+
+
+
+
+
+
+ Always
+ 微調一直顯示在LCD顯示屏上
+ 一直 [Always]
+
+
+
+
+
+
+
+
+
+
+ Global Functions
+ 全局功能
+[Global Functions]
+
+
+
+
+
+
+
+
+
+
+ Throttle Source
+ 設為油門桿 [Thr Source]
+
+
+
+
+
+
+
+
+
+
+ Trim Step
+ 微調步幅 [Trim Step]
+
+
+
+
+
+
+
+
+
+
+ Trims Display
+ 微調顯示 [Trims Display]
+
+
+
+
+
+
+
+
+
+
+ Timer 2
+ 計時器 2 [Timer 2]
+
+
+
+
+
+
+
+
+
+
+ Timer 3
+ 計時器 3 [Timer 3]
+
+
+
+ SetupPanel
+
+
+ Timer %1
+ 計時器[Timer] %1
+
+
+
+ THR
+ 油門
+
+
+
+ Profile Settings
+
+
+
+
+ SD structure path not specified or invalid
+
+
+
+
+ SimpleTailPage
+
+
+ Elevator Channel:
+ 升降舵通道:
+
+
+
+ SimulatedUIWidget
+
+
+ screenshot
+ Simulator LCD screenshot file name prefix
+
+
+
+
+ ENTER
+
+
+
+
+ S
+
+
+
+
+ PG-UP
+
+
+
+
+ PG-DN
+
+
+
+
+ DEL
+
+
+
+
+ BKSP
+
+
+
+
+ ESC
+
+
+
+
+ INS
+
+
+
+
+ <font size=+3>+</font>
+
+
+
+
+ <font size=+3>-</font>
+
+
+
+
+ <font size=+3>←</font>
+
+
+
+
+ <font size=+3>→</font>
+
+
+
+
+ <font size=+3>↑</font>
+
+
+
+
+ <font size=+3>↓</font>
+
+
+
+
+ <font size=+3>⚆</font>
+
+
+
+
+ <font size=+3>↶</font>
+
+
+
+
+ <font size=+3>↷</font>
+
+
+
+
+ <font size=+3>⇆</font>
+
+
+
+
+
+ <font size=+3>⇓</font>
+
+
+
+
+ <font size=+3>⇑</font>
+
+
+
+
+ <font size=+3>⇕</font>
+
+
+
+
+ <img src='qrc:/images/simulator/icons/svg/mouse.svg' width=20 height=18 />
+
+
+
+
+ <img src='qrc:/images/simulator/icons/svg/arrow_click.svg' width=18 height=18 />
+
+
+
+
+ <pre>[ MENU ]</pre>
+
+
+
+
+ <pre>[ PAGE ]</pre>
+
+
+
+
+ <pre>[ EXIT ]</pre>
+
+
+
+
+ <pre>[ ENT ]</pre>
+
+
+
+
+ <pre>[ SHIFT ]</pre>
+
+
+
+
+ <pre>[ UP ]</pre>
+
+
+
+
+ <pre>[ DN ]</pre>
+
+
+
+
+ <pre>[ <font size=+2>+</font> ]</pre>
+
+
+
+
+ <pre>[ <font size=+2>-</font> ]</pre>
+
+
+
+
+ <pre>[ PgUp ]</pre>
+
+
+
+
+ <pre>[ PgDn ]</pre>
+
+
+
+
+ <pre>[ MDL ]</pre>
+
+
+
+
+ <pre>[ RTN ]</pre>
+
+
+
+
+ <pre>[ SYS ]</pre>
+
+
+
+
+ <pre>[ TELE ]</pre>
+
+
+
+
+ <font size=+3>≡</font>
+
+
+
+
+ SimulatorMain
+
+
+ OpenTx Simulator
+
+
+
+
+ Available profiles:
+ 可用檔案:
+
+
+
+ ID:
+
+
+
+
+ Name:
+
+
+
+
+ Available radios:
+ 可用的遥控器:
+
+
+
+ Radio profile ID or Name to use for simulator.
+ 用於模擬器的遙控器檔案 ID 或名稱.
+
+
+
+ profile
+
+
+
+
+ Radio type to simulate (usually defined in profile).
+ 模擬的遙控器類型 (一般在遙控器檔案中定義).
+
+
+
+ radio
+
+
+
+
+ Directory containing the SD card image to use. The default is configured in the chosen Radio Profile.
+
+
+
+
+ path
+
+
+
+
+ Data source type to use (applicable to Horus only). One of:
+
+
+
+
+ type
+
+
+
+
+ data-source
+
+
+
+
+ Radio data (.bin/.eeprom/.otx) image file to use OR data folder path (for Horus-style radios).
+NOTE: any existing EEPROM data incompatible with the selected radio type may be overwritten!
+
+
+
+
+ [data-source]
+
+
+
+
+ Error: Profile ID %1 was not found.
+
+
+
+
+ Unrecognized startup data source type: %1
+
+
+
+
+ WARNING: couldn't initialize SDL:
+%1
+ 警告: 無法初始化 SDL:
+%1
+
+
+
+ ERROR: No simulator libraries available.
+ 錯誤:沒有可用的模擬器庫.
+
+
+
+ ERROR: Couldn't start simulator, missing radio/profile/data file/folder.
+ Profile ID: [%1]; Radio ID: [%2];
+Data File: [%3]
+
+
+
+
+ ERROR: Radio profile or simulator firmware not found.
+Profile ID: [%1]; Radio ID: [%2]
+ 錯誤: 未找到遙控器檔案或模擬器韌體.
+檔案 ID: [%1]; 遥控器 ID: [%2]
+
+
+
+ Uknown error during Simulator startup.
+
+
+
+
+ SimulatorMainWindow
+
+
+
+
+
+
+
+
+
+
+
+ OpenTx Simulator
+
+
+
+
+
+
+
+
+
+
+
+
+
+ View
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Radio Window
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Reload...
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Tools
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Toolbar
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Reload Lua Scripts
+ 載入 Lua 腳本
+
+
+
+
+
+
+
+
+
+
+
+
+ Reload the Lua environment on the simulated radio.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ F7
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Reload Radio Data
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Reload all radio data without restarting the simulator.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ F9
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Key Mapping
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Show keyboard maping reference.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ F1
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Joystick Settings
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Open joystick configuration settings dialog.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ F3
+
+
+
+
+
+
+
+
+
+
+
+
+
+ LCD Screenshot
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Save a screenshot of the current simulated LCD screen.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ F8
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Dock In Main Window
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Show the radio in the main window or as a separate "floating" window.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Menu Bar
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Show or hide the top menu bar.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Alt+M
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Constrain Width
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Set radio widget width to be a fixed size.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Constrain Height
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Set radio widget height to be a fixed size.
+
+
+
+
+ ERROR: Failed to create simulator interface, possibly missing or bad library.
+
+
+
+
+ Alt+T
+
+
+
+
+ Radio Outputs
+
+
+
+
+ F2
+
+
+
+
+ Telemetry Simulator
+ 回傳模擬器
+
+
+
+ F4
+
+
+
+
+ Trainer Simulator
+
+
+
+
+ F5
+
+
+
+
+ Debug Output
+ Debug 輸出
+
+
+
+ F6
+
+
+
+
+ <b>Simulator Controls:</b>
+
+
+
+
+ <tr><th>Key/Mouse</th><th>Action</th></tr>
+ note: must match html layout of each table row (keyTemplate).
+
+
+
+
+ <tr><td><kbd>%1</kbd></td><td>%2</td></tr>
+ note: must match html layout of help text table header.
+
+
+
+
+ Simulator Help
+ 模擬器幫助
+
+
+
+ SimulatorStartupDialog
+
+
+
+
+
+
+
+
+
+
+
+ OpenTX Simulator - Startup Options
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Simulator Startup Options:
+ 模擬器啟動選項:
+
+
+
+
+
+
+
+
+
+
+
+
+ Radio Profile:
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Existing radio profiles are shown here.<br />
+Create or edit profiles using the Companion application.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Radio Type:
+ 遙控器型號:
+
+
+
+
+
+
+
+
+
+
+
+
+ Existing radio simulators are shown here.<br />
+The radio type specified in the selected profile is used by default.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Data Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Data File:
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Data Folder:
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SD Image Path:
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Radio data (.bin/.eeprom/.otx) image file to use. A new file with a default image will be created if necessary.<br />
+<b>NOTE</b>: any existing EEPROM data incompatible with the selected radio type may be overwritten!
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Select data file...
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ...
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Directory containing RADIO and MODELS folders to use.<br />
+New folder(s) with default radio/model will be created here if necessary.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Select data folder...
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Directory containing the SD card image to use.<br/>
+The default is configured in the chosen Radio Profile.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Select SD card image folder...
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Select which of the data sources (File/Folder/SD Card) you would like to start the simulator with.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ File
+ 文件
+
+
+
+
+
+
+
+
+
+
+
+
+ Folder
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SD Path
+
+
+
+
+ All files (*.*)
+ 所有文件 (*.*)
+
+
+
+ Select a data file
+
+
+
+
+ Select Data Directory
+
+
+
+
+ Select SD Card Image Folder
+
+
+
+
+ SimulatorWidget
+
+
+
+
+
+
+
+
+
+
+
+ Companion Simulator
+ Companion 模擬器
+
+
+
+ Radio Simulator (%1)
+
+
+
+
+ Could not determine startup data source.
+
+
+
+
+ Could not load data, possibly wrong format.
+
+
+
+
+ Data Load Error
+
+
+
+
+ Invalid startup data provided. Plese specify a proper file/path.
+
+
+
+
+ Simulator Startup Error
+
+
+
+
+ Error saving data: could open file for writing: '%1'
+
+
+
+
+ Error saving data: could not get data from simulator interface.
+
+
+
+
+ An unexpected error occurred while attempting to save radio data to file '%1'.
+
+
+
+
+ Data Save Error
+
+
+
+
+ Radio firmware error: %1
+
+
+
+
+ - Flight Mode %1 (#%2)
+
+
+
+
+ Cannot open joystick, joystick disabled
+ 無法打開遊戲桿, 遊戲桿功能禁用
+
+
+
+ SliderWidget
+
+
+ Right-double-click to reset to center.
+
+
+
+
+ <p>Value (input): <b>%1</b></p>
+
+
+
+
+ SplashLibraryDialog
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ...
+
+
+
+
+ Splash Library - page %1 of %2
+ 開機圖片庫 - 第%1頁/共%2頁
+
+
+
+ Invalid image in library %1
+ 圖片庫 %1 中的圖片無效
+
+
+
+ No valid image found in library, check your settings
+ 在圖片庫中沒有找到有效的圖片, 請檢查你的設置
+
+
+
+ StandardPage
+
+
+ Channel %1
+ 通道 %1
+
+
+
+ Storage
+
+
+ Unable to find file %1!
+ 無法找到文件 %1!
+
+
+
+ StyleEditDialog
+
+
+
+
+
+
+
+
+
+
+
+
+ Style Sheet Editor
+
+
+
+
+
+
+
+
+
+
+
+ &Reset to default
+
+
+
+
+
+
+
+
+
+
+
+ &Cancel
+
+
+
+
+
+
+
+
+
+
+
+ &OK
+
+
+
+
+
+
+
+
+
+
+
+ This feature does not validate your changes and assumes you are familiar with CSS syntax for QT.
+
+
+
+
+ Cannot retrieve style %1
+Error: %2
+
+
+
+
+ Cannot retrieve default style %1
+Error: %2
+
+
+
+
+ Cannot update custom style %1
+Error: %2
+
+
+
+
+ Stylesheet
+
+
+ Style sheet data read from '%1'
+
+
+
+
+ Style sheet data unable to be read from '%1'
+
+
+
+
+ Cannot create folder '%1'
+
+
+
+
+ Cannot open file for writing '%1': Error: %2
+
+
+
+
+ Cannot write to file '%1': Error: %2
+
+
+
+
+ Cannot flush buffer for file '%1': Error: %2
+
+
+
+
+ Style sheet written to '%1'
+
+
+
+
+ Custom style sheet deleted: '%1'
+
+
+
+
+ Unable to delete custom style sheet: '%1'
+
+
+
+
+ SyncProcess
+
+
+ [TEST RUN]
+
+
+
+
+ Synchronization failed, nothing found to copy.
+
+
+
+
+ Skipping large file: %1 (%2KB)
+
+
+
+
+ Creating directory: %1
+
+
+
+
+ Could not create directory: %1
+
+
+
+
+ Gathering file information for %1...
+
+
+
+
+ No files found in %1
+
+
+
+
+ Synchronization aborted at %1 of %2 files.
+
+
+
+
+ Synchronization finished with %1 files in %2m %3s.
+
+
+
+
+ Synchronizing: %1
+ To: %2
+
+
+
+
+ Starting synchronization:
+ %1 -> %2
+
+
+
+
+
+
+Too many errors, giving up.
+
+
+
+
+ Skipping filtered file: %1
+
+
+
+
+ Skipping linked file: %1
+
+
+
+
+ Aborted synchronization of:
+
+
+
+
+ Finished synchronizing:
+
+
+
+
+ Created: %1; Updated: %2; Skipped: %3; Errors: %4;
+
+
+
+
+ Directory exists: %1
+
+
+
+
+ At least one of the file modification dates is in the future, error on: %1
+
+
+
+
+ Skipping older file: %1
+
+
+
+
+ Could not open source file '%1': %2
+
+
+
+
+ Could not open destination file '%1': %2
+
+
+
+
+ Skipping identical file: %1
+
+
+
+
+ Replacing file: %1
+
+
+
+
+ Creating file: %1
+
+
+
+
+ Could not delete destination file '%1': %2
+
+
+
+
+ Copy failed: '%1' to '%2': %3
+
+
+
+
+ TailPage
+
+
+ Rudder Channel:
+ 方向舵通道:
+
+
+
+ Elevator Channel:
+ 升降舵通道:
+
+
+
+ Only one channel still available!<br>You probably should configure your model without using the wizard.
+ 只剩一個通道可用!<br>可能你需要不使用嚮導來配置模型.
+
+
+
+ TailSelectionPage
+
+
+ Elevator and Rudder
+ 升降舵和方向舵
+
+
+
+ Only Elevator
+ 只有升降舵
+
+
+
+ V-tail
+ V尾
+
+
+
+ Tail Type:
+ 尾翼類型:
+
+
+
+ Telemetry
+
+
+
+
+
+
+
+
+
+ Protocol
+ 協議
+
+
+
+
+
+
+
+
+
+
+ Alarm 1
+ 警告 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ----
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Yellow
+ 黄色警告
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Orange
+ 橙色警告
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Red
+ 红色警告
+
+
+
+
+
+
+
+
+
+
+ Alarm 2
+ 警告 2
+
+
+
+
+
+
+
+
+
+
+ RSSI
+
+
+
+
+
+
+
+
+
+
+
+ Disable telemetry audio warnings
+
+
+
+
+
+
+
+
+
+ Source
+
+
+
+
+
+
+
+
+
+
+
+ A1
+ A1 模擬值1
+
+
+
+
+
+
+
+
+
+
+ A2
+ A2 模擬值2
+
+
+
+
+
+
+
+
+
+
+ Sink Max
+ 最大下降率
+
+
+
+
+
+
+
+
+
+
+ Climb Max
+ 最大爬升
+
+
+
+
+
+
+
+
+
+
+ Sink Min
+ 最小下降率
+
+
+
+
+
+
+
+
+
+
+ Climb Min
+ 最小爬升
+
+
+
+
+
+
+
+
+
+
+ Center Silent
+ 中間靜音
+
+
+
+
+
+
+
+
+
+
+ Vario limits
+ Vario 限值
+
+
+
+
+
+
+
+
+
+
+ Vario source
+ Vario 傳感器
+
+
+
+
+
+
+
+
+
+
+ Altimetry
+ 高度計
+
+
+
+
+
+
+
+
+
+
+ Altitude source
+ 高度傳感器
+
+
+
+
+
+
+
+
+
+
+ Volts source
+ 電壓傳感器
+
+
+
+
+
+
+
+
+
+
+ Top Bar
+ 頂部橫條
+
+
+
+
+
+
+
+
+
+
+ Volt source
+ 電壓傳感器
+
+
+
+
+
+
+
+
+
+
+ Current source
+ 當前源
+
+
+
+
+
+
+
+
+
+
+ Blades
+ 旋翼數
+
+
+
+
+
+
+
+
+
+
+ mAh count
+
+
+
+
+
+
+
+
+
+
+
+ mAh
+
+
+
+
+
+
+
+
+
+
+
+ A
+
+
+
+
+
+
+
+
+
+
+
+ FAS Offset
+ FAS偏移
+
+
+
+
+
+
+
+
+
+
+ Persistent mAh
+ 保持mAh
+
+
+
+
+
+
+
+
+
+
+ Various
+ ????
+ 不同的
+
+
+
+
+
+
+
+
+
+
+ Serial Protocol
+ 串口協議
+
+
+
+
+
+
+
+
+
+
+ None
+
+
+
+
+
+
+
+
+
+
+
+ FrSky Sensor Hub
+ FrSky Sensor Hub
+
+
+
+
+
+
+
+
+
+
+ Sensors
+ 傳感器
+
+
+
+
+
+
+
+
+
+
+ Disable multi sensor handling
+ 禁止多傳感器處理
+
+
+
+ TelemetryAnalog
+
+
+
+
+
+
+
+
+
+ Unit
+ 單位
+
+
+
+
+
+
+
+
+
+
+ Max Value
+ 最大值
+
+
+
+
+
+
+
+
+
+
+ Alarm 1
+ 警告 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ----
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Yellow
+ 黄色警告
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Orange
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Red
+ 红色警告
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+
+
+
+
+
+
+
+
+
+
+
+ Alarm 2
+ 警告 2
+
+
+
+
+
+
+
+
+
+
+ Offset
+
+
+
+
+
+
+
+
+
+
+
+ Volts (V)
+ 電壓 (V)
+
+
+
+
+
+
+
+
+
+
+ Amps (A)
+ 電流 (A)
+
+
+
+
+
+
+
+
+
+
+ Speed (m/s or ft/s)
+ 速度 (m/s or ft/s)
+
+
+
+
+
+
+
+
+
+
+ Raw (-)
+ 原始值 (-)
+
+
+
+
+
+
+
+
+
+
+ Speed (km/h or miles/h)
+ 速度 ( km/h 或 miles/h)
+
+
+
+
+
+
+
+
+
+
+ Meters (m or ft)
+ 高度 (米或英尺)
+
+
+
+
+
+
+
+
+
+
+ Temp (°)
+ 温度 (°)
+
+
+
+
+
+
+
+
+
+
+ Fuel (%)
+ 油量 (%)
+
+
+
+
+
+
+
+
+
+
+ mAmps (mA)
+ 電流 (mA)
+
+
+
+ Range
+ 範圍
+
+
+
+ TelemetryCustomScreen
+
+
+
+
+
+
+
+
+
+ Custom Screen Type
+ 自定義屏幕類型
+
+
+
+
+
+
+
+
+
+
+ Min
+ 最小
+
+
+
+
+
+
+
+
+
+
+ Source
+ 來源
+
+
+
+
+
+
+
+
+
+
+ Gauge
+ 儀錶盤
+
+
+
+
+
+
+
+
+
+
+ Max
+ 最大
+
+
+
+ None
+ 回傳屏幕設置中的選項
+ 無
+
+
+
+ Numbers
+ 數字
+
+
+
+ Bars
+ 條狀圖
+
+
+
+ Script
+ 脚本
+
+
+
+ TelemetryPanel
+
+
+ Telemetry screen %1
+ 回傳屏幕 %1
+
+
+
+ FrSky S.PORT
+
+
+
+
+ FrSky D
+
+
+
+
+ FrSky D (cable)
+
+
+
+
+ Source
+
+
+
+
+ Low Alarm
+ 低警告
+
+
+
+ Critical Alarm
+ 緊急警告
+
+
+
+ Winged Shadow How High
+
+
+
+
+ Winged Shadow How High (not supported)
+ Winged Shadow How High (不支持)
+
+
+
+ Alti
+ 高度
+
+
+
+ Alti+
+ 最大高度
+
+
+
+ VSpeed
+ 垂直速度
+
+
+
+
+
+ A1
+ A1 模擬值1
+
+
+
+
+
+ A2
+ A2 模擬值2
+
+
+
+
+ A3
+ A3 模擬值3
+
+
+
+
+ A4
+ A4 模擬值4
+
+
+
+
+ FAS
+ FAS
+
+
+
+ Cells
+ 鋰電總電壓
+
+
+
+ ---
+
+
+
+
+ TelemetrySensor
+
+
+
+
+
+
+
+
+
+ Form
+ 表單
+
+
+
+
+
+
+
+
+
+
+ Custom
+ 自定義
+
+
+
+
+
+
+
+
+
+
+ Calculated
+ 運算
+
+
+
+
+
+
+
+
+
+
+ Id
+
+
+
+
+
+
+
+
+
+
+
+ Instance
+ 對象
+
+
+
+
+
+
+
+ Rx
+
+
+
+
+
+
+
+
+ Mod.
+
+
+
+
+
+
+
+
+
+
+
+ Add
+ 加
+
+
+
+
+
+
+
+
+
+
+ Average
+ 平均值
+
+
+
+
+
+
+
+
+
+
+ Min
+ 最小
+
+
+
+
+
+
+
+
+
+
+ Max
+ 最大
+
+
+
+
+
+
+
+
+
+
+ Multiply
+ 乘以
+
+
+
+
+
+
+
+
+
+
+ Totalize
+ 總計
+
+
+
+
+
+
+
+
+
+
+ Cell
+ 鋰電單片電壓
+
+
+
+
+
+
+
+
+
+
+ Consumption
+ 消耗
+
+
+
+
+
+
+
+
+
+
+ Dist
+ 距離
+
+
+
+
+
+
+
+
+
+
+ Cells Sensor :
+ 鋰電電壓傳感器 :
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ---
+
+
+
+
+
+
+
+
+
+
+
+ GPS Sensor :
+ GPS 傳感器 :
+
+
+
+
+
+
+
+
+
+
+ Alt. Sensor :
+ 高度傳感器 :
+
+
+
+
+
+
+
+
+
+
+ Sensor :
+ 傳感器 :
+
+
+
+
+
+
+
+
+
+
+ Raw (-)
+ 原始值 (-)
+
+
+
+
+
+
+
+
+
+
+ V
+
+
+
+
+
+
+
+
+
+
+
+ A
+
+
+
+
+
+
+
+
+
+
+
+ mA
+
+
+
+
+
+
+
+
+
+
+
+ kt
+
+
+
+
+
+
+
+
+
+
+
+ m/s
+
+
+
+
+
+
+
+
+
+
+
+ ft/s
+
+
+
+
+
+
+
+
+
+
+
+ km/h
+
+
+
+
+
+
+
+
+
+
+
+ mph
+
+
+
+
+
+
+
+
+
+
+
+ m
+
+
+
+
+
+
+
+
+
+
+
+ ft
+
+
+
+
+
+
+
+
+
+
+
+ °C
+
+
+
+
+
+
+
+
+
+
+
+ °F
+
+
+
+
+
+
+
+
+
+
+
+ %
+
+
+
+
+
+
+
+
+
+
+
+ mAh
+
+
+
+
+
+
+
+
+
+
+
+ W
+
+
+
+
+
+
+
+
+
+
+
+ mW
+
+
+
+
+
+
+
+
+
+
+
+ dBm
+
+
+
+
+
+
+
+
+
+
+
+ RPM
+
+
+
+
+
+
+
+
+
+
+
+ g
+
+
+
+
+
+
+
+
+
+
+
+ °
+
+
+
+
+
+
+
+
+
+
+
+ Rad
+
+
+
+
+
+
+
+
+
+
+
+ mL
+
+
+
+
+
+
+
+
+
+
+
+ US fl.Oz.
+
+
+
+
+
+
+
+
+
+
+
+ Precision
+ 精確度
+
+
+
+
+
+
+
+
+
+
+ Ratio
+ 比例
+
+
+
+
+
+
+
+
+
+
+ Blades
+ 旋翼數
+
+
+
+
+
+
+
+
+
+
+ Offset
+ 偏移
+
+
+
+
+
+
+
+
+
+
+ Multiplier
+ 係數
+
+
+
+
+
+
+
+
+
+
+ Auto Offset
+ 自動偏移
+
+
+
+
+
+
+
+
+
+
+ Filter
+ 過濾器
+
+
+
+
+
+
+
+
+
+
+ Persistent
+ 保持
+
+
+
+
+
+
+
+
+
+
+ Positive
+ 正向
+
+
+
+
+
+
+
+
+
+
+ Logs
+ LOG記錄
+
+
+
+ TelemetrySensorPanel
+
+
+ Lowest
+ 最低
+
+
+
+ Cell %1
+ 第%1片
+
+
+
+ Highest
+ 最高
+
+
+
+ Delta
+ 每片電壓差
+
+
+
+ TelemetrySimulator
+
+
+
+
+
+
+
+
+
+
+
+ Telemetry Simulator
+ 回傳模擬器
+
+
+
+
+
+
+
+
+
+
+
+
+ When enabled, sends any non-blank values as simulated telemetry data.
+ 如果允许 =, 發送任何非空值作為回傳模擬數據.
+
+
+
+
+
+
+
+
+
+
+
+
+ Simulate
+ 模擬
+
+
+
+
+
+
+
+
+
+
+
+
+ Replay SD Log File
+ 重播 SD Log 文件
+
+
+
+
+
+
+
+
+
+
+
+
+ Replay rate
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |>
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <|
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <-
+
+
+
+
+
+
+
+
+
+
+
+
+
+ X
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1/5x
+ 1/5x
+
+
+
+
+
+
+
+
+
+
+
+
+ 5x
+ 5x
+
+
+
+
+
+
+
+
+
+
+
+
+ No Log File Currently Loaded
+ 現在沒有載入任何 log 文件
+
+
+
+
+
+
+
+
+
+
+
+
+ Setting RSSI to zero simulates telemetry and radio link loss.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Set RSSI to zero when paused.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Stop sending telemetry data when the Telemetry Simulator window is hidden.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Pause simulation when hidden.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Load
+ 載入
+
+
+
+
+
+
+
+
+
+
+
+
+ Row #
+Timestamp
+ 行數
+時間戳
+
+
+
+
+
+
+
+
+
+
+
+
+ RxBt
+ RxBt 接收機電壓
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ V / ratio
+ 伏 / 比值
+
+
+
+
+
+
+
+
+
+
+
+
+ RAS
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <html><head/><body><p><br/></p></body></html>
+
+
+
+
+
+
+
+
+
+
+
+
+
+ VFAS
+ VFAS FAS傳感器電壓
+
+
+
+
+
+
+
+
+
+
+
+
+ Lat,Lon
+(dec.deg.)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ dd-MM-yyyy
+hh:mm:ss
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Volts
+ V
+
+
+
+
+
+
+
+
+
+
+
+
+ RSSI
+ RSSI 信號強度
+
+
+
+
+
+
+
+
+
+
+
+
+ Db
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Curr
+ Curr 電流
+
+
+
+
+
+
+
+
+
+
+
+
+ Amps
+ A
+
+
+
+
+
+
+
+
+
+
+
+
+ Cels
+ Cells 鋰電電壓
+
+
+
+
+
+
+
+
+
+
+
+
+ A1
+ A1 模擬值1
+
+
+
+
+
+
+
+
+
+
+
+
+ A2
+ A2 模擬值2
+
+
+
+
+
+
+
+
+
+
+
+
+ ASpd
+ ASpd 空速
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ km/h
+
+
+
+
+
+
+
+
+
+
+
+
+
+ A3
+ A3 模擬值3
+
+
+
+
+
+
+
+
+
+
+
+
+ GAlt
+ GALT GPS高度
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Meters
+ m
+
+
+
+
+
+
+
+
+
+
+
+
+ A4
+ A4 模擬值4
+
+
+
+
+
+
+
+
+
+
+
+
+ GSpd
+ GSpd GPS速度
+
+
+
+
+
+
+
+
+
+
+
+
+ Tmp1
+ Tmp1 温度1
+
+
+
+
+
+
+
+
+
+
+
+
+ Hdg
+ Hdg 航向角
+
+
+
+
+
+
+
+
+
+
+
+
+ Degrees
+ °
+
+
+
+
+
+
+
+
+
+
+
+
+ Tmp2
+ Tmp2 温度2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ °C
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Date
+ Date 日期
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ RPM
+ Rpm
+
+
+
+
+
+
+
+
+
+
+
+
+ GPS
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Fuel
+ Fule 燃油
+
+
+
+
+
+
+
+
+
+
+
+
+ %
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AccX
+ AccX X軸加速度
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ G
+ G
+
+
+
+
+
+
+
+
+
+
+
+
+ Fuel Qty
+ Fule Qty 油量
+
+
+
+
+
+
+
+
+
+
+
+
+ ml
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AccY
+ AccY Y軸加速度
+
+
+
+
+
+
+
+
+
+
+
+
+ VSpd
+ VSpd 垂直速度
+
+
+
+
+
+
+
+
+
+
+
+
+ m/s
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AccZ
+ AccZ Z軸加速度
+
+
+
+
+
+
+
+
+
+
+
+
+ Alt
+ Alt 高度
+
+
+
+ Log File
+ Log 文件
+
+
+
+ LOG Files (*.csv)
+ LOG文件 (*.csv)
+
+
+
+ ERROR - invalid file
+ 錯誤 無效的文件
+
+
+
+ ThrottlePage
+
+
+ Yes
+ 使用油門通道
+
+
+
+ No
+ 不使用油門通道
+
+
+
+ <br>Throttle Channel:
+ <br>油門通道:
+
+
+
+ Timer
+
+
+
+
+
+
+
+
+
+ Countdown
+ 倒數報數
+
+
+
+
+
+
+
+
+
+
+ Minute Call
+ 分鐘提示
+
+
+
+ TimerData
+
+
+ TMR
+
+
+
+
+ Timer %1
+ 計時器[Timer] %1
+
+
+
+ TimerEdit
+
+
+ Use mouse scroll or UP/DOWN arrow keys to change time in small steps.
+CTRL + scroll or PAGE UP/DOWN keys to change time in larger steps.
+
+
+
+
+ m
+
+
+
+
+ h
+
+
+
+
+ s
+
+
+
+
+ TimerPanel
+
+
+ Silent
+ 静音 [Silent]
+
+
+
+ Beeps
+ 蜂鳴 [Beeps]
+
+
+
+ Voice
+ 語音 [Voice]
+
+
+
+ Haptic
+ 振動 [Haptic]
+
+
+
+ Not persistent
+ 關機不記憶 [Not persistent]
+
+
+
+ Persistent (flight)
+ 關機記憶 隨Flight重設 [Flight]
+
+
+
+ Persistent (manual reset)
+ 關機記憶 手動重設 [manual reset]
+
+
+
+ Trainer
+
+
+
+
+
+
+
+
+
+ Form
+ 表單
+
+
+
+
+
+
+
+
+
+
+ Mode
+ 模式
+
+
+
+
+
+
+
+
+
+
+ Input
+ 輸入
+
+
+
+
+
+
+
+
+
+
+ Weight
+ 比例
+
+
+
+
+
+
+
+
+
+
+ Rud
+ 方向通道
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Beeper volume
+
+0 - Quiet. No beeps at all.
+1 - No Keys. Normal beeps but menu keys do not beep.
+2 - Normal.
+3 - Loud.
+4 - Extra loud.
+ 蜂鳴音量
+
+0 - 靜音 沒有蜂鳴聲
+1 - 除菜單鍵外都有有蜂鳴聲.
+2 - 普通音量.
+3 - 大音量.
+4 - 超大音量.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Off
+ 關閉
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ += (Sum)
+ += (相加)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ := (Replace)
+ := (取代)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ chn1
+ 通道1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ chn2
+ 通道2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ chn3
+ 通道3
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ chn4
+ 通道4
+
+
+
+
+
+
+
+
+
+
+ Ele
+ 升降通道
+
+
+
+
+
+
+
+
+
+
+ Thr
+ 油門通道
+
+
+
+
+
+
+
+
+
+
+ Ail
+ 副翼通道
+
+
+
+ TrainerSimulator
+
+
+
+
+
+
+
+
+
+
+
+ Trainer simulator
+ 教練功能模擬
+
+
+
+ TreeModel
+
+
+ Index
+ 模型編號
+
+
+
+ Name
+
+
+
+
+ Size
+ 佔用內存
+
+
+
+ RX #
+
+
+
+
+ Models
+ Translators do NOT use accent for this, this is the default category name on Horus.
+
+
+
+
+ Model %1
+ Translators: do NOT use accents here, this is a default model name.
+
+
+
+
+ VTailPage
+
+
+ First Tail Channel:
+ 第一個V尾通道:
+
+
+
+ Second Tail Channel:
+ 第二個V尾通道:
+
+
+
+ VirtualJoystickWidget
+
+
+ Hld Y
+
+
+
+
+ Hold Vertical stick position.
+
+
+
+
+ Fix Y
+ 固定 Y
+
+
+
+ Prevent Vertical movement of stick.
+
+
+
+
+ Fix X
+ 固定 X
+
+
+
+ Prevent Horizontal movement of stick.
+
+
+
+
+ Hld X
+
+
+
+
+ Hold Horizontal stick position.
+
+
+
+
+ WingtypeSelectionPage
+
+
+ Standard Wing
+ 標準機翼
+
+
+
+ Flying Wing / Deltawing
+ 飛翼 / 三角翼
+
+
+
+ WizardDialog
+
+
+ Model Wizard
+ 模型嚮導
+
+
+
+ Model Type
+ 模型種類
+
+
+
+ Enter model name and model type.
+ 輸入模型名稱和模型種類.
+
+
+
+ Throttle
+ 油門
+
+
+
+ Has your model got a motor or an engine?
+ 你的模型裝有馬達或引擎嗎?
+
+
+
+ Wing Type
+ 機翼類型
+
+
+
+ Is your model a flying wing/deltawing or has it a standard wing configuration?
+ 你的模型是是標準機翼, 還是飛翼/三角翼?
+
+
+
+ Ailerons
+ 副翼
+
+
+
+ Has your model got ailerons?
+ 你的模型有副翼嗎?
+
+
+
+ Flaps
+ 襟翼
+
+
+
+ Has your model got flaps?
+ 你的模型有襟翼嗎?
+
+
+
+ Airbrakes
+ 空氣剎車
+
+
+
+ Has your model got airbrakes?
+ 你的模型有空氣剎車嗎?
+
+
+
+ Flying-wing / Delta-wing
+ 飛翼 / 三角翼
+
+
+
+ Select the elevons channels
+ 指定升降副翼通道
+
+
+
+ Rudder
+ 方向舵
+
+
+
+ Does your model have a rudder?
+ 你的模型有方向舵嗎?
+
+
+
+ Tail Type
+ 尾翼類型
+
+
+
+ Select which type of tail your model is equiped with.
+ 選擇你的飛機裝置何種尾翼類型.
+
+
+
+
+ Tail
+ 尾翼
+
+
+
+
+ Select channels for tail control.
+ 選擇尾翼通道.
+
+
+
+ V-Tail
+ V尾
+
+
+
+ Select elevator channel.
+ 選擇升降舵通道.
+
+
+
+ Cyclic
+ 傾斜盤
+
+
+
+ Which type of swash control is installed in your helicopter?
+ 你的直升機使用何種十字盤?
+
+
+
+ Tail Gyro
+ 鎖尾陀螺儀
+
+
+
+ Has your helicopter got an adjustable gyro for the tail?
+ 你的直升機裝有感度可調的鎖尾陀螺嗎?
+
+
+
+ Rotor Type
+ 旋翼類型
+
+
+
+ Has your helicopter got a flybar?
+ 你的直升機有副翼嗎?
+
+
+
+
+ Helicopter
+ 直升機
+
+
+
+
+ Select the controls for your helicopter
+ 選擇你的直升機的控制通道
+
+
+
+ Multirotor
+ 多軸
+
+
+
+ Select the control channels for your multirotor
+ 選擇你的多旋翼的控制通道
+
+
+
+ Model Options
+ 模型選項
+
+
+
+ Select additional options
+
+
+
+
+ Save Changes
+
+
+
+
+ Manually check the direction of each control surface and reverse any channels that make controls move in the wrong direction. Remove the propeller/propellers before you try to control your model for the first time.<br>Please note that continuing removes all old model settings!
+ 飛機通電後, 請人工檢查每個舵面的運動方向, 如果舵面運動方向錯誤請將此舵機設置成反向. 第一次通電前請卸下螺旋槳. <br>經常把不用的的模型配置刪除是好習慣!
+
+
+
+ Enter a name for your model and select model type.
+ 請輸入模型名字和模型種類.
+
+
+
+ Select the receiver channel that is connected to your ESC or throttle servo.<br><br>Throttle - Spektrum: CH1, Futaba: CH3
+ 選擇電調或油門舵機插在哪個通道上.<br><br>Spektrum接收機:通道1, Futaba接收機: 通道3
+
+
+
+ Most aircraft have a main wing and a tail with control surfaces. Flying wings and delta winged aircraft only have a single wing. The main control surface on a standard wing controls the roll of the aircraft. This surface is called an aileron.<br>The control surface of a delta wing controls both roll and pitch. This surface is called an elevon.
+ 大多數固定翼的控制舵面分別安裝在機翼和尾翼上. 飛翼或三角翼只有一個機翼. 一般固定翼的主機翼上的舵面控制飛機繞縱軸的滾轉, 這些舵面叫做副翼.<br>飛翼機翼後緣的舵面控制飛機繞縱軸的滾轉和繞橫軸的仰俯. 這些舵面叫做升降副翼.
+
+
+
+ Models use one or two channels to control the ailerons.<br>A so called Y-cable can be used to connect a single receiver channel to two separate aileron servos. If your servos are connected by a Y-cable you should select the single-servo option.<br><br>Aileron - Spektrum: CH2, Futaba: CH1
+ 模型使用一個或兩個通道來控制副翼.<br>如果使用一個通道, 則需要使用Y線來控制兩個副翼舵機.<br><br>副翼通道 - Spektrum接收機: 通道2, Futaba接收機: 通道1
+
+
+
+ This wizard assumes that your flaps are controlled by a switch. If your flaps are controlled by a potentiometer you can change that manually later.
+ 此嚮導假定你使用開關來控制襟翼. 如果你使用旋鈕控制襟翼, 你可以在嚮導完成後手動更改配置.
+
+
+
+ Air brakes are used to reduce the speed of advanced sail planes.<br>They are very uncommon on other types of planes.
+ 空氣剎車在高級滑翔機中用來降低空速, 它們很少見於普通固定翼中.
+
+
+
+ Models use two channels to control the elevons.<br>Select these two channels
+ 模型使用2個通道控制升降副翼 <br>選擇這兩個通道
+
+
+
+ Select the receiver channel that is connected to your rudder.<br><br>Rudder - Spektrum: CH4, Futaba: CH4
+ 選擇方向舵通道.<br><br>Spektrum接收機: 通道4, Futaba接收機: 通道4
+
+
+
+ Select the tail type of your plane.
+ 選擇你的飛機的尾翼類型.
+
+
+
+
+ Select the Rudder and Elevator channels.<br><br>Rudder - Spektrum: CH4, Futaba: CH4<br>Elevator - Spektrum: CH3, Futaba: CH2
+ 選擇方向舵或升降舵通道.<br><br>方向舵: Spektrum接收機: 通道4, Futaba接收機: 通道4<br>升降舵: Spektrum接收機: 通道3, Futaba接收機: 通道2
+
+
+
+ Select the Elevator channel.<br><br>Elevator - Spektrum: CH3, Futaba: CH2
+ 選擇升降舵通道.<br><br>Spektrum接收機: 通道3, Futaba接收機: 通道2
+
+
+
+
+
+
+
+
+
+ TBD.
+ TBD.
+
+
+
+ Select the control channels for your multirotor.<br><br>Throttle - Spektrum: CH1, Futaba: CH3<br>Yaw - Spektrum: CH4, Futaba: CH4<br>Pitch - Spektrum: CH3, Futaba: CH2<br>Roll - Spektrum: CH2, Futaba: CH1
+ 選擇你的多旋翼的控制通道.<br><br>油门 - Spektrum: 通道1, Futaba: 通道3<br>偏航 - Spektrum: 通道4, Futaba: 通道4<br>仰俯 - Spektrum: 通道3, Futaba: 通道2<br>滚转 - Spektrum: 通道2, Futaba: 通道1
+
+
+
+ There is no help available for the current page.
+ 當前頁面沒有幫助信息.
+
+
+
+ Model Wizard Help
+ 模型嚮導幫助
+
+
+
+ WizardPrinter
+
+
+ Plane
+ 固定翼
+
+
+
+ Multicopter
+ 多軸
+
+
+
+ Helicopter
+ 直升機
+
+
+
+ Model Name:
+ 模型名稱:
+
+
+
+ Model Type:
+ 模型種類:
+
+
+
+ Options:
+ 選項:
+
+
+
+ Channel %1:
+ 通道 %1:
+
+
+
+ burnConfigDialog
+
+
+
+
+
+
+
+
+
+ Programmer Configuration
+ 編程器配置
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Location of sam-ba executable
+ 定位 sam-ba 可執行文件
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ The location of the AVRDUDE executable.
+ AVRDUDE可執行文件位置.
+
+
+
+
+
+
+
+
+
+
+ DFU-Util Location
+ DFU-Util 軟體位置
+
+
+
+
+
+
+
+
+
+
+ Location of AVRDUDE executable
+ AVRDUDE可執行文件位置
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Use this button to browse and look for the AVRDUDE executable file.
+ 使用這個按鈕定位AVRDUDE可執行文件.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Browse...
+ 瀏覽...
+
+
+
+
+
+
+
+
+
+
+ Programmer
+ 編程器
+
+
+
+
+
+
+
+
+
+
+ Programmer used for communicating with the controller.
+Please consult the programmer's documentation and the AVRDUDE documentation to select the appropriate programmer.
+ 與遙控器通訊用的編程器.
+請參考編程器文檔和AVRDUDE文檔來選擇合適的編程器.
+
+
+
+
+
+
+
+
+
+
+ List all available programmers.
+ 列出所有可用的编程器.
+
+
+
+
+
+
+
+
+
+
+ List Available
+ 列出可用
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Extra arguments that will be passed to AVRDUDE on every call
+ 每次調用時將會把更多的參數將會傳到給AVRDUDE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Extra arguments used in AVRDUDE.
+This can be used for providing extra information to AVRDUDE.
+
+Please only use this if you know what you are doing. There are no error checks and you could cripple your controller.
+ 用於AVRDUDE的更多參數.
+可用來為AVRDUDE提供更多的信息.
+
+僅當你知道在做什麼時使用. 這裡不進行錯誤檢查所以你可能把遙控器變磚.
+
+
+
+
+
+
+
+
+
+
+ Extra Arguments
+ 更多參數
+
+
+
+
+
+
+
+
+
+
+ Show AVRDUDE help
+ 顯示AVRDUDE幫助
+
+
+
+
+
+
+
+
+
+
+ Show Help
+ 顯示幫助
+
+
+
+
+
+
+
+
+
+
+ Communication port to the programmer.
+
+ 編程器通訊端口.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Port
+ 端口
+
+
+
+
+
+
+
+
+
+
+ AVRDUDE Location
+ AVRDUDE 位置
+
+
+
+
+
+
+
+
+
+
+ MCU
+ MCU
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ CPU of your TX
+ 你的遥控器所用CPU
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ CPU present on your 9x radio
+Should be m64 for stock radios
+m2560 for v4.1 boards
+ 你的9x遙控器的CPU
+零售版遙控器應為m64
+v4.1版電路板應為m2560
+
+
+
+
+
+
+
+
+
+
+ at91sam3s8-9xr
+ at91sam3s8-9xr
+
+
+
+
+
+
+
+
+
+
+ SAM-BA Location
+ SAM-BA 位置
+
+
+
+
+
+
+
+
+
+
+ ARM MCU
+ ARM MCU
+
+
+
+
+
+
+
+
+
+
+ sam-ba serial port
+ sam-ba 串口
+
+
+
+
+
+
+
+
+
+
+ Alternate device
+ 其他設備
+
+
+
+
+
+
+
+
+
+
+ Use advanced controls
+ 使用高級控制項
+
+
+
+ DFU-UTIL Configuration
+ DFU-UTIL 配置
+
+
+
+ SAM-BA Configuration
+ SAM-BA 配置
+
+
+
+ AVRDUDE Configuration
+ AVRDUDE 配置
+
+
+
+
+
+ Select Location
+ 選擇位置
+
+
+
+ List available programmers
+ 列出可用的编程器
+
+
+
+ Avrdude help
+ AVRDUDE 幫助
+
+
+
+ <b><u>WARNING!</u></b><br>Normally CPU type is automatically selected according to the chosen firmware.<br>If you change the CPU type the resulting eeprom could be inconsistent.
+ <b><u>警告</u></b><br>一般來說CPU類型將會根據固件文件自動選擇<br>如果你更改CPU類型, EEPROM可能會不兼容.
+
+
+
+ joystickDialog
+
+
+
+
+
+
+
+
+
+
+
+ Configure Joystick
+ 配置遊戲桿
+
+
+
+
+
+
+
+
+
+
+
+
+ Ch2
+ 遊戲桿通道2
+
+
+
+
+
+
+
+
+
+
+
+
+ Ch1
+ 遊戲桿通道1
+
+
+
+
+
+
+
+
+
+
+
+
+ Ch4
+ 遊戲桿通道4
+
+
+
+
+
+
+
+
+
+
+
+
+ Ch6
+ 遊戲桿通道6
+
+
+
+
+
+
+
+
+
+
+
+
+ Ch3
+ 遊戲桿通道3
+
+
+
+
+
+
+
+
+
+
+
+
+ Ch5
+ 遊戲桿通道5
+
+
+
+
+
+
+
+
+
+
+
+
+ Ch7
+ 遊戲桿通道7
+
+
+
+
+
+
+
+
+
+
+
+
+ Ch8
+ 遊戲桿通道8
+
+
+
+
+
+
+
+
+
+
+
+
+ Instructions
+ 指令
+
+
+
+
+
+
+
+
+
+
+
+
+ Enable
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Cancel
+ 取消
+
+
+
+
+
+
+
+
+
+
+
+
+ Back
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Start
+ 開始通道 [CH]
+
+
+
+ Next
+ 下一步
+
+
+
+
+
+
+
+
+
+
+
+
+ Ok
+ 確定
+
+
+
+ Not Assigned
+
+
+
+
+ Stick
+
+
+
+
+ Knob/Slider %1
+
+
+
+
+ No joysticks found
+ 找不到遊戲桿
+
+
+
+ Cannot open joystick.
+ 找不到遊戲桿.
+
+
+
+ Press the Start button to start the stick range calibration procedure.
+You may change the channel assignments or inversion at any time.
+
+
+
+
+ Move sticks and pots in every direction making full movement
+Press Next when finished
+
+
+
+
+ Place sticks and pots in middle position.
+Press Next when done
+
+
+
+
+ Map joystick channels to controls using comboboxes.
+Press Next when done.
+
+
+
+
+ Check inversion checkbox to if necessary to reverse direction.
+Press Next when done.
+
+
+
+
+ Press OK to save configuration
+Press Cancel to abort joystick calibration without saving.
+
+
+
+
+ Calibration not complete, save anyway?
+
+
+
+
+ preferencesDialog
+
+
+ Preferences
+ 偏好設置
+
+
+
+ Simu BackLight
+ 模擬器背光
+
+
+
+ Simulator capture folder
+ 模擬器截圖保存目錄
+
+
+
+ Joystick
+ 遊戲桿
+
+
+
+ Remember simulator switches
+
+
+
+
+ Enable
+ 允许
+
+
+
+ Use clipboard only
+ 抓圖僅保存在剪貼板中
+
+
+
+ Calibrate
+ 校準
+
+
+
+ Blue
+ 藍色
+
+
+
+ Green
+ 绿色
+
+
+
+ Red
+ 红色
+
+
+
+ Orange
+ 橙色
+
+
+
+ Yellow
+ 黄色
+
+
+
+
+ Open Folder
+ 打開文件夾
+
+
+
+ Personal splash library
+ 個人開機畫面庫
+
+
+
+ Include companion splashes
+
+
+
+
+ Only user defined splashes
+ 只顯示用戶自定義啟動畫面
+
+
+
+ Splash library behaviour
+ 開機圖片庫行為
+
+
+
+ Custom TX splash screen
+ 自定義遙控器開機畫面
+
+
+
+ Open Image
+ 打開圖片
+
+
+
+
+ ...
+
+
+
+
+ Invert Pixels
+ 負片效果
+
+
+
diff --git a/radio/sdcard/horus/SCRIPTS/TOOLS/DSM FwdPrg.lua b/radio/sdcard/horus/SCRIPTS/TOOLS/DSM FwdPrg.lua
new file mode 100644
index 000000000..c756634d9
--- /dev/null
+++ b/radio/sdcard/horus/SCRIPTS/TOOLS/DSM FwdPrg.lua
@@ -0,0 +1,557 @@
+local toolName = "TNS|DSM Forward Programming|TNE"
+
+---- #########################################################################
+---- # #
+---- # Copyright (C) OpenTX #
+-----# #
+---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
+---- # #
+---- # This program is free software; you can redistribute it and/or modify #
+---- # it under the terms of the GNU General Public License version 2 as #
+---- # published by the Free Software Foundation. #
+---- # #
+---- # This program is distributed in the hope that it will be useful #
+---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
+---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
+---- # GNU General Public License for more details. #
+---- # #
+---- #########################################################################
+
+
+--###############################################################################
+-- Multi buffer for DSM description
+-- Multi_Buffer[0..2]=="DSM" -> Lua script is running
+-- Multi_Buffer[3]==0x70+len -> TX to RX data ready to be sent
+-- Multi_Buffer[4..9]=6 bytes of TX to RX data
+-- Multi_Buffer[10..25]=16 bytes of RX to TX data
+--
+-- To start operation:
+-- Write 0x00 at address 3
+-- Write 0x00 at address 10
+-- Write "DSM" at address 0..2
+--###############################################################################
+
+local RX_VERSION, WAIT_CMD, MENU_TITLE, MENU_LINES, MENU_VALUES, VALUE_CHANGING, VALUE_CHANGING_WAIT, VALUE_CHANGED = 0, 1, 2, 3, 4, 5, 6, 7
+local MENU, LIST_MENU_NOCHANGING, LIST_MENU2, PERCENTAGE_VALUE = 0x1C, 0x6C, 0x4C, 0xC0
+local Phase = RX_VERSION
+local Waiting_RX = 0
+local Text = {}
+local Retry=100
+local Blink = 0
+local Value_Changed=0
+
+local Menu = { Cur=nil, Id=nil, Title="", Prev=nil, PrevId=nil, Next=nil, NextId=nil, Back=nil, BackId=nil, CurLine=nil, SelLine=nil, EditLine=nil }
+local Line = {}
+local RX = { Name="", Version="" }
+
+local function conv_int16(number)
+ if number >= 0x8000 then
+ return number - 0x10000
+ end
+ return number
+end
+
+local function Get_Text(index)
+ out = Text[index]
+ if out == nil then -- unknown...
+ out = "Unknown_"..string.format("%X",index)
+ end
+ return out
+end
+
+local function DSM_Release()
+ multiBuffer( 0, 0 )
+end
+
+local function DSM_Send(...)
+ local arg = {...}
+ for i = 1 , #arg do
+ multiBuffer( 3+i, arg[i])
+ end
+ multiBuffer( 3, 0x70+#arg)
+end
+
+local function Value_Add(dir)
+ local line=Line[Menu.SelLine]
+ Speed = getRotEncSpeed()
+ if Speed == ROTENC_MIDSPEED then
+ line.Val = line.Val + (5 * dir)
+ elseif Speed == ROTENC_HIGHSPEED then
+ line.Val = line.Val + (15 * dir)
+ else
+ line.Val = line.Val + dir
+ end
+ if line.Val > line.Max then
+ line.Val = line.Max
+ elseif line.Val < line.Min then
+ line.Val = line.Min
+ end
+ if Line[Menu.SelLine].Type ~= LIST_MENU_NOCHANGING then
+ Phase = VALUE_CHANGING
+ Waiting_RX = 0
+ end
+end
+
+local function DSM_Menu(event)
+ local Speed = 0
+ if event == EVT_VIRTUAL_NEXT then
+ if Menu.EditLine == nil then
+ -- not changing a value
+ if Menu.SelLine ~= nil then
+ if Menu.SelLine < 7 then
+ local num = Menu.SelLine
+ for i = Menu.SelLine + 1, 6, 1 do
+ if Line[i].Type ~= nil and Line[i].Next ~= nil then
+ Menu.SelLine=i
+ break
+ end
+ end
+ if num == Menu.SelLine then
+ if Menu.Next ~= 0 then -- Next
+ Menu.SelLine = 7
+ elseif Menu.Prev ~= 0 then -- Prev
+ Menu.SelLine = 8
+ end
+ end
+ elseif Menu.Prev ~= 0 then -- Prev
+ Menu.SelLine = 8
+ end
+ end
+ else -- need to inc the value
+ Value_Add(1)
+ end
+ elseif event == EVT_VIRTUAL_PREV then
+ if Menu.EditLine == nil then
+ if Menu.SelLine ~= nil then
+ if Menu.SelLine == 8 and Menu.Next ~= 0 then
+ Menu.SelLine = 7
+ elseif Menu.SelLine > 0 then
+ if Menu.SelLine > 6 then
+ Menu.SelLine = 7
+ end
+ local num = Menu.SelLine
+ for i = Menu.SelLine-1, 0, -1 do
+ if Line[i].Type ~= nil and Line[i].Next ~= nil then
+ Menu.SelLine=i
+ break
+ end
+ end
+ if num == Menu.SelLine then -- Back
+ Menu.SelLine = -1
+ end
+ else
+ Menu.SelLine = -1 -- Back
+ end
+ end
+ else -- need to dec the value
+ Value_Add(-1)
+ end
+ elseif event == EVT_VIRTUAL_ENTER then
+ if Menu.SelLine == -1 then -- Back
+ Menu.Cur = Menu.Back
+ Menu.Id = Menu.BackId
+ Menu.SelLine = 0
+ Phase = MENU_TITLE
+ Waiting_RX = 0
+ elseif Menu.SelLine == 7 then -- Next
+ Menu.Cur = Menu.Next
+ Menu.Id = Menu.NextId
+ Menu.SelLine = 0
+ Phase = MENU_TITLE
+ Waiting_RX = 0
+ elseif Menu.SelLine == 8 then -- Prev
+ Menu.Cur = Menu.Prev
+ Menu.Id = Menu.PrevId
+ Menu.SelLine = 0
+ Phase = MENU_TITLE
+ Waiting_RX = 0
+ elseif Menu.SelLine ~= nil and Line[Menu.SelLine].Next ~= nil then
+ if Line[Menu.SelLine].Type == MENU then -- Next menu exist
+ Menu.Cur = Line[Menu.SelLine].Next
+ Menu.Id = Line[Menu.SelLine].NextId
+ Phase = MENU_TITLE
+ Waiting_RX = 0
+ else
+ -- value entry
+ if Menu.EditLine == Menu.SelLine then
+ Menu.EditLine = nil
+ Value_Changed = 0
+ Phase = VALUE_CHANGED
+ Waiting_RX = 0
+ else
+ Menu.EditLine = Menu.SelLine
+ end
+ end
+ end
+ end
+end
+
+local function DSM_Send_Receive()
+ if Waiting_RX == 0 then
+ Waiting_RX = 1
+ -- Need to send a request
+ if Phase == RX_VERSION then -- request RX version
+ DSM_Send(0x11,0x06,0x00,0x14,0x00,0x00)
+ elseif Phase == WAIT_CMD then -- keep connection open
+ DSM_Send(0x00,0x04,0x00,0x00)
+ elseif Phase == MENU_TITLE then -- request menu title
+ if Menu.Cur == nil then
+ DSM_Send(0x12,0x06,0x00,0x14,0x00,0x00) -- first menu only
+ Menu.Cur = 0
+ else
+ DSM_Send(0x16,0x06,Menu.Id,Menu.Cur,0x00,Menu.SelLine)
+ end
+ elseif Phase == MENU_LINES then -- request menu lines
+ if Menu.CurLine == nil then
+ DSM_Send(0x13,0x04,Menu.Id,Menu.Cur) -- line 0
+ elseif Menu.CurLine >= 0x80 then
+ local last_byte={0x40,0x01,0x02,0x04,0x00,0x00} -- unknown...
+ DSM_Send(0x20,0x06,Menu.CurLine-0x80,Menu.CurLine-0x80,0x00,last_byte[Menu.CurLine-0x80+1]) -- line X
+ else
+ DSM_Send(0x14,0x06,Menu.Id,Menu.Cur,0x00,Menu.CurLine) -- line X
+ end
+ elseif Phase == MENU_VALUES then -- request menu values
+ DSM_Send(0x15,0x06,Menu.Id,Menu.Cur,Line[Menu.CurLine].ValId,Menu.CurLine) -- line X
+ elseif Phase == VALUE_CHANGING then -- send value
+ local value=Line[Menu.SelLine].Val
+ if value < 0 then
+ value = 0x10000 + value
+ end
+ DSM_Send(0x18,0x06,Line[Menu.SelLine].ValId,Menu.SelLine,bit32.rshift(value,8),bit32.band(value,0xFF)) -- send current value
+ Phase = VALUE_CHANGING_WAIT
+ elseif Phase == VALUE_CHANGED then -- send value
+ if Value_Changed == 0 then
+ local value=Line[Menu.SelLine].Val
+ if value < 0 then
+ value = 0x10000 + value
+ end
+ DSM_Send(0x18,0x06,Line[Menu.SelLine].ValId,Menu.SelLine,bit32.rshift(value,8),bit32.band(value,0xFF)) -- send current value
+ Value_Changed = Value_Changed + 1
+ Waiting_RX = 0
+ elseif Value_Changed == 1 then
+ DSM_Send(0x19,0x06,Line[Menu.SelLine].ValId,Menu.SelLine) -- validate
+ -- Value_Changed = Value_Changed + 1
+ -- Waiting_RX = 0
+ --elseif Value_Changed == 2 then
+ -- DSM_Send(0x1B,0x06,0x10,Menu.SelLine) -- validate again?
+ -- Value_Changed = Value_Changed + 1
+ end
+ elseif Phase == VALUE_CHANGING_WAIT then
+ DSM_Send(0x1A,0x06,Line[Menu.SelLine].ValId,Menu.SelLine)
+ end
+ multiBuffer(10,0x00);
+ Retry = 50
+ elseif multiBuffer(10) == 0x09 then
+ -- Answer received
+ --if multiBuffer(11) == 0x00 then -- waiting for commands?
+ if multiBuffer(11) == 0x01 then -- read version
+ --ex: 0x09 0x01 0x00 0x15 0x02 0x22 0x01 0x00 0x14 0x00 0x00 0x00 0x00 0x00 0x00 0x00
+ RX.Name = Get_Text(multiBuffer(13))
+ RX.Version = multiBuffer(14).."."..multiBuffer(15).."."..multiBuffer(16)
+ Phase = MENU_TITLE
+ elseif multiBuffer(11) == 0x02 then -- read menu title
+ --ex: 0x09 0x02 0x4F 0x10 0xA5 0x00 0x00 0x00 0x50 0x10 0x10 0x10 0x00 0x00 0x00 0x00
+ Menu.Cur = multiBuffer(12)
+ Menu.Id = multiBuffer(13)
+ Menu.Title = Get_Text(multiBuffer(14)+multiBuffer(15)*256)
+ Menu.Prev = multiBuffer(16)
+ Menu.PrevId = multiBuffer(17)
+ Menu.Next = multiBuffer(18)
+ Menu.NextId = multiBuffer(19)
+ Menu.Back = multiBuffer(20)
+ Menu.BackId = multiBuffer(21)
+ for i = 0, 6 do -- clear menu
+ Line[i] = { Menu = nil, Id = nil, Type = nil, Text="", Next = nil, NextId = nil, ValLine = nil, ValId = nil, Min, Max, Def, Val, Unit, Step }
+ end
+ Menu.CurLine = nil
+ if Menu.Next ~= 0 then
+ Menu.SelLine = 7 -- highlight Next
+ else
+ Menu.SelLine = -1 -- highlight Back
+ end
+ Blink = 0
+ Phase = MENU_LINES
+ elseif multiBuffer(11) == 0x03 then -- read menu lines
+ --ex: 0x09 0x03 0x00 0x10 0x00 0x1C 0xF9 0x00 0x10 0x10 0x00 0x00 0x00 0x00 0x03 0x00
+ -- Menu Id line Type Text_idx Next V_Id Val_Min Val_Max Val_Def
+ --ex: 0x09 0x03 0x61 0x10 0x00 0x6C 0x50 0x00 0x00 0x10 0x36 0x00 0x49 0x00 0x36 0x00
+ Menu.CurLine = multiBuffer(14)
+ local line = Line[Menu.CurLine]
+ line.Menu = multiBuffer(12)
+ line.Id = multiBuffer(13) -- not quite sure yet
+ line.Type = multiBuffer(15) -- not quite sure yet: 1C is text menu only, 4C/6C is text followed by text list, C0 is text followed by percentage value
+ line.Text = Get_Text(multiBuffer(16)+multiBuffer(17)*256)
+ if multiBuffer(18) == Menu.Cur then
+ line.Next = nil
+ else
+ line.Next = multiBuffer(18) -- not quite sure yet: 1C=text menu=>next menu, others=>line number of the value
+ end
+ if Menu.SelLine == -1 and line.Next ~= nil then -- Auto select first line of the menu
+ Menu.SelLine = Menu.CurLine
+ end
+ line.NextId = multiBuffer(19) -- not quite sure yet
+ line.ValLine = multiBuffer(18) -- not quite sure yet
+ line.ValId = multiBuffer(19) -- not quite sure yet
+ line.Min = conv_int16(multiBuffer(20)+multiBuffer(21)*256)
+ line.Max = conv_int16(multiBuffer(22)+multiBuffer(23)*256)
+ line.Def = conv_int16(multiBuffer(24)+multiBuffer(25)*256)
+ if line.Type == MENU then
+ -- nothing to do on menu entries
+ elseif line.Type == LIST_MENU_NOCHANGING or line.Type == LIST_MENU2 then
+ line.Val = nil --line.Def - line.Min -- use default value not sure if needed
+ line.Def = line.Min -- pointer to the start of the list in Text
+ line.Max = line.Max - line.Min -- max index
+ line.Min = 0 -- min index
+ else -- default to numerical value
+ line.Val = nil --line.Def -- use default value not sure if needed
+ end
+ if line.Type ~= 0x1C then -- value to follow
+ line.Text = line.Text..":"
+ end
+ Phase = MENU_LINES
+ elseif multiBuffer(11) == 0x04 then -- read menu values
+ --ex: 0x09 0x04 0x53 0x10 0x00 0x10 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
+ -- Menu MeId line VaId Value
+ --ex: 0x09 0x04 0x61 0x10 0x02 0x10 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
+ Menu.CurLine = multiBuffer(14)
+ Line[Menu.CurLine].Val = conv_int16(multiBuffer(16)+multiBuffer(17)*256)
+ Phase = MENU_VALUES
+ elseif multiBuffer(11) == 0x05 then -- unknown... need to get through the lines...
+ Menu.CurLine = 0x80 + multiBuffer(12)
+ Phase = MENU_LINES
+ elseif multiBuffer(11) == 0x00 and Phase == VALUE_CHANGING then
+ Phase = VALUE_CHANGING_WAIT
+ end
+ -- Data processed
+ Waiting_RX = 0
+ multiBuffer(10,0x00)
+ Retry = 50
+ else
+ Retry = Retry - 1
+ if Retry <= 0 then
+ -- Retry the RX request
+ Retry = 50
+ Waiting_RX = 0
+ if Phase ~= RX_VERSION and Phase ~= VALUE_CHANGING_WAIT then
+ Phase = WAIT_CMD
+ end
+ end
+ end
+end
+
+local function DSM_Display()
+ lcd.clear()
+ if LCD_W == 480 then
+ --Draw title
+ lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR)
+ lcd.drawText(1, 5, "DSM Forward Programming", MENU_TITLE_COLOR)
+ --Draw RX Menu
+ if Phase == RX_VERSION then
+ lcd.drawText(10,50,"No compatible DSM RX...", BLINK)
+ else
+ if Menu.Title ~= nil then
+ local attrib=0;
+ lcd.drawText(80,32,Menu.Title,MIDSIZE)
+ for i = 0, 6 do
+ if i == Menu.SelLine then
+ attrib = INVERS
+ else
+ attrib = 0
+ end
+ if Line[i] ~= nil and Line[i].Type ~= nil then
+ if Line[i].Type ~= MENU then -- list/value
+ if Line[i].Val ~= nil then
+ local text=""
+ if Line[i].Type == LIST_MENU_NOCHANGING or Line[i].Type == LIST_MENU2 then
+ text = Get_Text(Line[i].Val+Line[i].Def)
+ elseif Line[i].Type == PERCENTAGE_VALUE then
+ text = Line[i].Val.." %"
+ else
+ text = Line[i].Val
+ end
+ if Menu.EditLine == Menu.SelLine then -- blink edited entry
+ Blink = Blink + 1
+ if Blink > 25 then
+ attrib = 0
+ if Blink > 50 then
+ Blink = 0
+ end
+ end
+ end
+ lcd.drawText(240,32+20*(i+2), text, attrib) -- display value
+ end
+ attrib = 0
+ end
+ lcd.drawText(10,32+20*(i+2), Line[i].Text, attrib) -- display text
+ end
+ end
+ if Menu.SelLine == -1 then
+ lcd.drawText(437,32, "Back", INVERS)
+ else
+ lcd.drawText(437,32, "Back", 0)
+ end
+ lcd.drawRectangle(437-5, 32-2, 47, 25)
+ if Menu.Next ~= 0 then
+ if Menu.SelLine == 7 then
+ lcd.drawText(437,220, "Next",INVERS)
+ else
+ lcd.drawText(437,220, "Next")
+ end
+ lcd.drawRectangle(437-5, 220-2, 47, 25)
+ end
+ if Menu.Prev ~= 0 then
+ if Menu.SelLine == 8 then
+ lcd.drawText(5,220, "Prev",INVERS)
+ else
+ lcd.drawText(5,220, "Prev")
+ end
+ lcd.drawRectangle(5-5, 220-2, 47, 25)
+ end
+ end
+ lcd.drawText(170,252, "RX "..RX.Name.." v"..RX.Version) -- display RX info
+ end
+ else
+ -- --Draw RX Menu on LCD_W=128
+ -- if multiBuffer( 4 ) == 0xFF then
+ -- lcd.drawText(2,17,"No compatible DSM RX...",SMLSIZE)
+ -- else
+ -- if Retry_128 ~= 0 then
+ -- --Intro page
+ -- Retry_128 = Retry_128 - 1
+ -- lcd.drawScreenTitle("DSM Forward Programming",0,0)
+ -- lcd.drawText(2,17,"Press Prev Page for previous Menu" ,SMLSIZE)
+ -- else
+ -- --Menu page
+ -- for line = 0, 7, 1 do
+ -- for i = 0, 21-1, 1 do
+ -- value=multiBuffer( line*21+6+i )
+ -- if value > 0x80 then
+ -- value = value - 0x80
+ -- lcd.drawText(2+i*6,1+8*line,string.char(value).." ",SMLSIZE+INVERS)
+ -- else
+ -- lcd.drawText(2+i*6,1+8*line,string.char(value),SMLSIZE)
+ -- end
+ -- end
+ -- end
+ -- end
+ -- end
+ end
+end
+
+-- Init
+local function DSM_Init()
+ --Set protocol to talk to
+ multiBuffer( 0, string.byte('D') )
+ --test if value has been written
+ if multiBuffer( 0 ) ~= string.byte('D') then
+ error("Not enough memory!")
+ return 2
+ end
+ --Init TX buffer
+ multiBuffer( 3, 0x00 )
+ --Init RX buffer
+ multiBuffer( 10, 0x00 )
+ --Init telemetry
+ multiBuffer( 0, string.byte('D') )
+ multiBuffer( 1, string.byte('S') )
+ multiBuffer( 2, string.byte('M') )
+
+ --Text to be displayed -> need to use a file instead?
+ --RX names--
+ Text[0x0014]="SPM4651T"
+ Text[0x0015]="AR637T"
+ --Lists--
+ Text[0x0036]="Throttle"
+ Text[0x0037]="Aileron"
+ Text[0x0038]="Elevator"
+ Text[0x0039]="Rudder"
+ Text[0x003A]="Gear"
+ for i=1,7 do -- 3B..41
+ Text[0x003A+i]="Aux"..i
+ end
+ for i=1,8 do -- 41..49
+ Text[0x0041+i]="XPlus-"..i
+ end
+ Text[0x004A]="Failsafe"
+ Text[0x004B]="Main Menu"
+ Text[0x004E]="Position"
+ Text[0x0050]="Outputs"
+ --Text[0x005E]="Inhibit"
+ Text[0x005F]="Hold Last"
+ Text[0x0060]="Preset"
+ --Text[0x0061]="Custom"
+ --Messages--
+ Text[0x0090]="Apply"
+ Text[0x0093]="Complete"
+ Text[0x0094]="Done"
+ Text[0x0097]="Factory Reset"
+ Text[0x009A]="Capture Failsafe Positions"
+ Text[0x009C]="Custom Failsafe"
+ Text[0x00A5]="First Time Setup"
+ Text[0x00F9]="Gyro settings"
+ Text[0x0100]="Make sure the model has been"
+ Text[0x0101]="configured, including wing type,"
+ Text[0x0102]="reversing, travel, trimmed, etc."
+ Text[0x0103]="before continuing setup."
+ Text[0x0104]=""
+ Text[0x0105]=""
+ Text[0x0106]="Any wing type, channel assignment,"
+ Text[0x0107]="subtrim, or servo reversing changes"
+ Text[0x0108]="require running through initial"
+ Text[0x0109]="setup again."
+ Text[0x010A]=""
+ Text[0x010B]=""
+
+ Text[0x019C]="Enter Receiver Bind Mode"
+ Text[0x020A]="Restore from Backup"
+ Text[0x0209]="Save to Backup"
+
+ Text[0x021A]="Set the model level,"
+ Text[0x021B]="and press Continue."
+ Text[0x021C]=""
+ Text[0x021D]=""
+
+ Text[0x021F]="Set the model on its nose,"
+ Text[0x0220]="and press Continue. If the"
+ Text[0x0221]="orientation on the next"
+ Text[0x0222]="screen is wrong go back"
+ Text[0x0223]="and try again."
+ Text[0x0224]="Continue"
+ Text[0x0229]="Set Orientation Manually"
+
+ Text[0x0227]="Other settings"
+ Text[0x022B]="WARNING!"
+ Text[0x022C]="This will reset the"
+ Text[0x022D]="configuration to factory"
+ Text[0x022E]="defaults. This does not"
+ Text[0x022F]="affect the backup config."
+ Text[0x0230]=""
+ Text[0x0231]="This will overwrite the"
+ Text[0x0232]="backup memory with your"
+ Text[0x0233]="current configuartion."
+ Text[0x0234]=""
+ Text[0x0235]=""
+ Text[0x0236]="This will overwrite the"
+ Text[0x0237]="current config with"
+ Text[0x0238]="that which is in"
+ Text[0x0239]="the backup memory."
+ Text[0x023A]=""
+end
+
+-- Main
+local function DSM_Run(event)
+ if event == nil then
+ error("Cannot be run as a model script!")
+ return 2
+ elseif event == EVT_VIRTUAL_EXIT then
+ DSM_Release()
+ return 2
+ else
+ DSM_Menu(event)
+ DSM_Send_Receive()
+ DSM_Display()
+ return 0
+ end
+end
+
+return { init=DSM_Init, run=DSM_Run }
diff --git a/radio/sdcard/horus/SCRIPTS/TOOLS/FrSky RB30_RB40.lua b/radio/sdcard/horus/SCRIPTS/TOOLS/FrSky RB30_RB40.lua
new file mode 100644
index 000000000..213faa6cf
--- /dev/null
+++ b/radio/sdcard/horus/SCRIPTS/TOOLS/FrSky RB30_RB40.lua
@@ -0,0 +1,464 @@
+--- - #########################################################################
+---- # #
+---- # Copyright (C) OpenTX #
+----- # #
+---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
+---- # #
+---- # This program is free software; you can redistribute it and/or modify #
+---- # it under the terms of the GNU General Public License version 2 as #
+---- # published by the Free Software Foundation. #
+---- # #
+---- # This program is distributed in the hope that it will be useful #
+---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
+---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
+---- # GNU General Public License for more details. #
+---- # #
+---- #########################################################################
+
+local version = "v1.01"
+
+local VALUE = 0
+local COMBO = 1
+
+local edit = false
+local page = 1
+local current = 1
+local refreshState = 0
+local refreshIndex = 0
+local pageOffset = 0
+local pages = {}
+local fields = {}
+local modifications = {}
+local margin = 1
+local spacing = 8
+local numberPerPage = 7
+
+local configFields = {
+ { "Self_stable mode", COMBO, 0x80, nil, { "disable", "enable"} },
+ { "Sbus out", COMBO, 0x81, nil, { "disable", "enable"} },
+ { "VOut1(V)", VALUE, 0xB2, nil, 50, 84},
+ { "VOut2(V)", VALUE, 0xB3, nil, 50, 84},
+}
+
+
+local failsafeFields = {
+ { "CH1 failsafe", VALUE, 0x82, 150, 80, 220},
+ { "CH2 failsafe", VALUE, 0x82, 150, 80, 220},
+ { "CH3 failsafe", VALUE, 0x83, 150, 80, 220},
+ { "CH4 failsafe", VALUE, 0x83, 150, 80, 220},
+ { "CH5 failsafe", VALUE, 0x84, 150, 80, 220},
+ { "CH6 failsafe", VALUE, 0x84, 150, 80, 220},
+ { "CH7 failsafe", VALUE, 0x85, 150, 80, 220},
+ { "CH8 failsafe", VALUE, 0x85, 150, 80, 220},
+ { "CH9 failsafe", VALUE, 0x86, 150, 80, 220},
+ { "CH10 failsafe", VALUE, 0x86, 150, 80, 220},
+ { "CH11 failsafe", VALUE, 0x87, 150, 80, 220},
+ { "CH12 failsafe", VALUE, 0x87, 150, 80, 220},
+ { "CH13 failsafe", VALUE, 0x88, 150, 80, 220},
+ { "CH14 failsafe", VALUE, 0x88, 150, 80, 220},
+ { "CH15 failsafe", VALUE, 0x89, 150, 80, 220},
+ { "CH16 failsafe", VALUE, 0x89, 150, 80, 220},
+ { "CH17 failsafe", VALUE, 0x8A, 150, 80, 220},
+ { "CH18 failsafe", VALUE, 0x8A, 150, 80, 220},
+ { "CH19 failsafe", VALUE, 0x8B, 150, 80, 220},
+ { "CH20 failsafe", VALUE, 0x8B, 150, 80, 220},
+ { "CH21 failsafe", VALUE, 0x8C, 150, 80, 220},
+ { "CH22 failsafe", VALUE, 0x8C, 150, 80, 220},
+ { "CH23 failsafe", VALUE, 0x8D, 150, 80, 220},
+ { "CH24 failsafe", VALUE, 0x8D, 150, 80, 220},
+}
+
+local rx1PinMapFields = {
+ { "CH1 RX1 map", VALUE, 0x8E, 1, 0, 16},
+ { "CH2 RX1 map", VALUE, 0x8E, 2, 0, 16},
+ { "CH3 RX1 map", VALUE, 0x8F, 3, 0, 16},
+ { "CH4 RX1 map", VALUE, 0x8F, 4, 0, 16},
+ { "CH5 RX1 map", VALUE, 0x90, 5, 0, 16},
+ { "CH6 RX1 map", VALUE, 0x90, 6, 0, 16},
+ { "CH7 RX1 map", VALUE, 0x91, 7, 0, 16},
+ { "CH8 RX1 map", VALUE, 0x91, 8, 0, 16},
+ { "CH9 RX1 map", VALUE, 0x92, 9, 0, 16},
+ { "CH10 RX1 map", VALUE, 0x92, 10, 0, 16},
+ { "CH11 RX1 map", VALUE, 0x93, 11, 0, 16},
+ { "CH12 RX1 map", VALUE, 0x93, 12, 0, 16},
+ { "CH13 RX1 map", VALUE, 0x94, 13, 0, 16},
+ { "CH14 RX1 map", VALUE, 0x94, 14, 0, 16},
+ { "CH15 RX1 map", VALUE, 0x95, 15, 0, 16},
+ { "CH16 RX1 map", VALUE, 0x95, 16, 0, 16},
+ { "CH17 RX1 map", VALUE, 0x96, 1, 0, 16},
+ { "CH18 RX1 map", VALUE, 0x96, 2, 0, 16},
+ { "CH19 RX1 map", VALUE, 0x97, 3, 0, 16},
+ { "CH20 RX1 map", VALUE, 0x97, 4, 0, 16},
+ { "CH21 RX1 map", VALUE, 0x98, 5, 0, 16},
+ { "CH22 RX1 map", VALUE, 0x98, 6, 0, 16},
+ { "CH23 RX1 map", VALUE, 0x99, 7, 0, 16},
+ { "CH24 RX1 map", VALUE, 0x99, 8, 0, 16},
+}
+
+local rx2PinMapFields = {
+ { "CH1 RX2 map", VALUE, 0x9A, 1, 0, 16},
+ { "CH2 RX2 map", VALUE, 0x9A, 2, 0, 16},
+ { "CH3 RX2 map", VALUE, 0x9B, 3, 0, 16},
+ { "CH4 RX2 map", VALUE, 0x9B, 4, 0, 16},
+ { "CH5 RX2 map", VALUE, 0x9C, 5, 0, 16},
+ { "CH6 RX2 map", VALUE, 0x9C, 6, 0, 16},
+ { "CH7 RX2 map", VALUE, 0x9D, 7, 0, 16},
+ { "CH8 RX2 map", VALUE, 0x9D, 8, 0, 16},
+ { "CH9 RX2 map", VALUE, 0x9E, 9, 0, 16},
+ { "CH10 RX2 map", VALUE, 0x9E, 10, 0, 16},
+ { "CH11 RX2 map", VALUE, 0x9F, 11, 0, 16},
+ { "CH12 RX2 map", VALUE, 0x9F, 12, 0, 16},
+ { "CH13 RX2 map", VALUE, 0xA0, 13, 0, 16},
+ { "CH14 RX2 map", VALUE, 0xA0, 14, 0, 16},
+ { "CH15 RX2 map", VALUE, 0xA1, 15, 0, 16},
+ { "CH16 RX2 map", VALUE, 0xA0, 16, 0, 16},
+ { "CH17 RX2 map", VALUE, 0xA2, 1, 0, 16},
+ { "CH18 RX2 map", VALUE, 0xA2, 2, 0, 16},
+ { "CH19 RX2 map", VALUE, 0xA3, 3, 0, 16},
+ { "CH20 RX2 map", VALUE, 0xA3, 4, 0, 16},
+ { "CH21 RX2 map", VALUE, 0xA4, 5, 0, 16},
+ { "CH22 RX2 map", VALUE, 0xA4, 6, 0, 16},
+ { "CH23 RX2 map", VALUE, 0xA5, 7, 0, 16},
+ { "CH24 RX2 map", VALUE, 0xA5, 8, 0, 16},
+}
+
+local rx3PinMapFields = {
+ { "CH1 RX3 map", VALUE, 0xA6, 1, 0, 16},
+ { "CH2 RX3 map", VALUE, 0xA6, 2, 0, 16},
+ { "CH3 RX3 map", VALUE, 0xA7, 3, 0, 16},
+ { "CH4 RX3 map", VALUE, 0xA7, 4, 0, 16},
+ { "CH5 RX3 map", VALUE, 0xA8, 5, 0, 16},
+ { "CH6 RX3 map", VALUE, 0xA8, 6, 0, 16},
+ { "CH7 RX3 map", VALUE, 0xA9, 7, 0, 16},
+ { "CH8 RX3 map", VALUE, 0xA9, 8, 0, 16},
+ { "CH9 RX3 map", VALUE, 0xAA, 9, 0, 16},
+ { "CH10 RX3 map", VALUE, 0xAA, 10, 0, 16},
+ { "CH11 RX3 map", VALUE, 0xAB, 11, 0, 16},
+ { "CH12 RX3 map", VALUE, 0xAB, 12, 0, 16},
+ { "CH13 RX3 map", VALUE, 0xAC, 13, 0, 16},
+ { "CH14 RX3 map", VALUE, 0xAC, 14, 0, 16},
+ { "CH15 RX3 map", VALUE, 0xAD, 15, 0, 16},
+ { "CH16 RX3 map", VALUE, 0xAD, 16, 0, 16},
+ { "CH17 RX3 map", VALUE, 0xAE, 1, 0, 16},
+ { "CH18 RX3 map", VALUE, 0xAE, 2, 0, 16},
+ { "CH19 RX3 map", VALUE, 0xAF, 3, 0, 16},
+ { "CH20 RX3 map", VALUE, 0xAF, 4, 0, 16},
+ { "CH21 RX3 map", VALUE, 0xB0, 5, 0, 16},
+ { "CH22 RX3 map", VALUE, 0xB0, 6, 0, 16},
+ { "CH23 RX3 map", VALUE, 0xB1, 7, 0, 16},
+ { "CH24 RX3 map", VALUE, 0xB1, 8, 0, 16},
+}
+
+
+
+
+local function drawScreenTitle(title, page, pages)
+ if math.fmod(math.floor(getTime() / 100), 10) == 0 then
+ title = version
+ end
+ if LCD_W == 480 then
+ lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR)
+ lcd.drawText(1, 5, title, MENU_TITLE_COLOR)
+ lcd.drawText(LCD_W - 40, 5, page .. "/" .. pages, MENU_TITLE_COLOR)
+ else
+ lcd.drawScreenTitle(title, page, pages)
+ end
+end
+
+-- Change display attribute to current field
+local function addField(step)
+ local field = fields[current]
+ local min, max
+ if field[2] == VALUE then
+ min = field[5]
+ max = field[6]
+ elseif field[2] == COMBO then
+ min = 0
+ max = #(field[5]) - 1
+ end
+ if page == 2 and step < 0 and field[4] == min then
+ field[4] = 0
+ elseif page == 2 and step > 0 and field[4] == 0 then
+ field[4] = min
+ else
+ if (step < 0 and field[4] > min) or (step > 0 and field[4] < max) then
+ field[4] = field[4] + step
+ end
+ end
+end
+
+-- Select the next or previous page
+local function selectPage(step)
+ local pagesNum = #pages
+ if configFields[1][4] == 1 then
+ pagesNum = 1
+ elseif configFields[2][4] == 1 then
+ pagesNum = pagesNum - 1
+ end
+ page = 1 + ((page + step - 1 + pagesNum) % pagesNum)
+ refreshIndex = 0
+ pageOffset = 0
+end
+
+-- Select the next or previous editable field
+local function selectField(step)
+ current = 1 + ((current + step - 1 + #fields) % #fields)
+ if current > numberPerPage + pageOffset then
+ pageOffset = current - numberPerPage
+ elseif current <= pageOffset then
+ pageOffset = current - 1
+ end
+end
+
+local function drawProgressBar()
+ if LCD_W == 480 then
+ local width = (300 * refreshIndex) / #fields
+ lcd.drawRectangle(100, 10, 300, 6)
+ lcd.drawFilledRectangle(102, 12, width, 2)
+ else
+ local width = (60 * refreshIndex) / #fields
+ lcd.drawRectangle(45, 1, 60, 6)
+ lcd.drawFilledRectangle(47, 3, width, 2)
+ end
+end
+
+-- Redraw the current page
+local function redrawFieldPage()
+ lcd.clear()
+
+ local pagesNum = #pages
+ if configFields[1][4] == 1 then
+ pagesNum = 1
+ elseif configFields[2][4] == 1 then
+ pagesNum = pagesNum - 1
+ end
+ drawScreenTitle("RB30/RB40", page, pagesNum)
+
+ if refreshIndex < #fields then
+ drawProgressBar()
+ end
+
+ for index = 1, numberPerPage, 1 do
+ local field = fields[pageOffset + index]
+ if field == nil then
+ break
+ end
+
+ local attr = current == (pageOffset + index) and ((edit == true and BLINK or 0) + INVERS) or 0
+
+ lcd.drawText(1, margin + spacing * index, field[1], attr)
+
+ if field[4] == nil then
+ lcd.drawText(LCD_W, margin + spacing * index, "---", RIGHT + attr)
+ else
+ if field[2] == VALUE then
+ if page == 2 then
+ if field[4] == 0 then
+ lcd.drawText(LCD_W, margin + spacing * index, "No pulse", RIGHT + attr)
+ else
+ lcd.drawNumber(LCD_W, margin + spacing * index, field[4] * 10, RIGHT + attr)
+ end
+ else
+ if field[4] == 0 then
+ lcd.drawText(LCD_W, margin + spacing * index, "No map", RIGHT + attr)
+ else
+ if field[3] == 0xB2 or field[3] == 0xB3 then
+ lcd.drawNumber(LCD_W, margin + spacing * index, field[4] , attr + RIGHT + PREC1)
+ else
+ lcd.drawNumber(LCD_W, margin + spacing * index, field[4], RIGHT + attr)
+ end
+ end
+ end
+ elseif field[2] == COMBO then
+ if field[4] >= 0 and field[4] < #(field[5]) then
+ lcd.drawText(LCD_W, margin + spacing * index, field[5][field[4] + 1], RIGHT + attr)
+ end
+ end
+ end
+ end
+end
+
+local function telemetryIdle(field)
+ return sportTelemetryPush(0x1C, 0x21, 0x0b80, field)
+end
+
+local function telemetryUnIdle(field)
+ return sportTelemetryPush(0x1C, 0x20, 0x0b80, field)
+end
+
+local function telemetryRead(field)
+ return sportTelemetryPush(0x1C, 0x30, 0x0b80, field)
+end
+
+local function telemetryWrite(field, value)
+ return sportTelemetryPush(0x1C, 0x31, 0x0b80, field + value * 256)
+end
+
+local telemetryPopTimeout = 0
+local function refreshNext()
+ if refreshState == 0 then
+ if #modifications > 0 then
+ telemetryWrite(modifications[1][1], modifications[1][2])
+ modifications[1] = nil
+ refreshIndex = 0
+ refreshState = 0
+ elseif refreshIndex < #fields then
+ local field = fields[refreshIndex + 1]
+ if page > 1 then
+ field = fields[refreshIndex + 2]
+ end
+ if telemetryRead(field[3]) == true then
+ refreshState = 1
+ telemetryPopTimeout = getTime() + 100 -- normal delay is 500ms
+ end
+ end
+ elseif refreshState == 1 then
+ local physicalId, primId, dataId, value = sportTelemetryPop()
+ if primId == 0x32 and (dataId >= 0x0b80 or dataId <= 0x0b8f) then
+ local fieldId = value % 256
+ local field = fields[refreshIndex + 1]
+ if fieldId == field[3] then
+ value = math.floor(value / 256)
+ if field[2] == COMBO then
+ fields[refreshIndex + 1][4] = value
+ else
+ fields[refreshIndex + 1][4] = value % 256
+ if page > 1 then
+ value = math.floor(value / 256)
+ fields[refreshIndex + 2][4] = value
+ end
+ end
+ if page > 1 then
+ refreshIndex = refreshIndex + 2
+ else
+ refreshIndex = refreshIndex + 1
+ end
+ refreshState = 0
+ end
+ elseif getTime() > telemetryPopTimeout then
+ fields[refreshIndex + 1][4] = nil
+ if page > 1 then
+ fields[refreshIndex + 2][4] = nil
+ refreshIndex = refreshIndex + 2
+ else
+ refreshIndex = refreshIndex + 1
+ end
+ refreshState = 0
+ end
+ end
+end
+
+local function updateField(field)
+ local value = field[4]
+ if field[2] == COMBO and #field == 6 then
+ value = field[6][1 + value]
+ elseif field[2] == VALUE and #field == 8 then
+ value = value + field[8] - field[5]
+ end
+
+ if page > 1 then
+ if current % 2 == 1 then
+ value = value + fields[current + 1][4] * 256
+ elseif current % 2 == 0 then
+ value = fields[current - 1][4] + value * 256
+ end
+ end
+ modifications[#modifications + 1] = { field[3], value }
+end
+
+-- Main
+local function runFieldsPage(event)
+ if event == EVT_VIRTUAL_EXIT then -- exit script
+ telemetryUnIdle(0x80)
+ return 2
+ elseif event == EVT_VIRTUAL_ENTER then -- toggle editing/selecting current field
+ if fields[current][4] ~= nil then
+ edit = not edit
+ if edit == false then
+ updateField(fields[current])
+ end
+ end
+ elseif edit then
+ if event == EVT_VIRTUAL_INC or event == EVT_VIRTUAL_INC_REPT then
+ addField(1)
+ elseif event == EVT_VIRTUAL_DEC or event == EVT_VIRTUAL_DEC_REPT then
+ addField(-1)
+ end
+ else
+ if event == EVT_VIRTUAL_NEXT then
+ selectField(1)
+ elseif event == EVT_VIRTUAL_PREV then
+ selectField(-1)
+ end
+ end
+ redrawFieldPage()
+ return 0
+end
+
+local function runConfigPage(event)
+ fields = configFields
+ return runFieldsPage(event)
+end
+
+local function runFailsafePage(event)
+ fields = failsafeFields
+ return runFieldsPage(event)
+end
+
+local function runRx1PinMapPage(event)
+ fields = rx1PinMapFields
+ return runFieldsPage(event)
+end
+
+local function runRx2PinMapPage(event)
+ fields = rx2PinMapFields
+ return runFieldsPage(event)
+end
+
+local function runRx3PinMapPage(event)
+ fields = rx3PinMapFields
+ return runFieldsPage(event)
+end
+
+-- Init
+local function init()
+ current, edit, refreshState, refreshIndex = 1, false, 0, 0
+ if LCD_W == 480 then
+ margin = 10
+ spacing = 20
+ numberPerPage = 12
+ end
+ pages = {
+ runConfigPage,
+ runFailsafePage,
+ runRx1PinMapPage,
+ runRx2PinMapPage,
+ runRx3PinMapPage
+ }
+ telemetryIdle(0x80)
+end
+
+-- Main
+local function run(event)
+ if event == nil then
+ error("Cannot be run as a model script!")
+ return 2
+ elseif event == EVT_VIRTUAL_NEXT_PAGE then
+ if edit == false then
+ selectPage(1)
+ end
+ elseif event == EVT_VIRTUAL_PREV_PAGE then
+ if edit == false then
+ killEvents(event)
+ selectPage(-1)
+ end
+ end
+
+ local result = pages[page](event)
+ refreshNext()
+
+ return result
+end
+
+return { init = init, run = run }
+
diff --git a/radio/sdcard/horus/SCRIPTS/TOOLS/MultiChan.txt b/radio/sdcard/horus/SCRIPTS/TOOLS/MultiChan.txt
index bf61d8ca6..b03b2c860 100644
--- a/radio/sdcard/horus/SCRIPTS/TOOLS/MultiChan.txt
+++ b/radio/sdcard/horus/SCRIPTS/TOOLS/MultiChan.txt
@@ -1,3 +1,47 @@
+24,0,Assan,Std,0,CH5,CH6,CH7,CH8
+14,0,Bayang,Std,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,n-a,n-a,AnAux1,AnAux2
+14,1,Bayang,H8S3D,1,Flip,RTH,Pict,Video,HLess,Invert,Rates
+14,2,Bayang,X16_AH,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf
+14,3,Bayang,IRDRONE,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf,EmStop
+14,4,Bayang,DHD_D4,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf,EmStop
+14,5,Bayang,QX100,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf,EmStop
+59,0,BayangRX,RX,1,AnAux1,AnAux2,Flip,RTH,Pict,Video
+41,0,Bugs,3-6-8,0,Arm,Angle,Flip,Pict,Video,LED
+42,0,BugsMini,Mini,0,Arm,Angle,Flip,Pict,Video,LED
+42,1,BugsMini,3H,0,Arm,Angle,Flip,Pict,Video,LED,AltHol
+34,0,Cabell,V3,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
+34,1,Cabell,V3Telem,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
+13,0,CG023,Std,1,Flip,Light,Pict,Video,HLess
+13,1,CG023,YD829,1,Flip,n-a,Pict,Video,HLess
+37,0,Corona,COR_V1,0,CH5,CH6,CH7,CH8
+37,1,Corona,COR_V2,0,CH5,CH6,CH7,CH8
+37,2,Corona,FD_V3,0,CH5,CH6,CH7,CH8
+12,0,CX10,Green,1,Flip,Rate
+12,1,CX10,Blue,1,Flip,Rate,Pict,Video
+12,2,CX10,DM007,1,Flip,Mode,Pict,Video,HLess
+12,4,CX10,JC3015_1,1,Flip,Mode,Pict,Video
+12,5,CX10,JC3015_2,1,Flip,Mode,LED,DFlip
+12,6,CX10,MK33041,1,Flip,Mode,Pict,Video,HLess,RTH
+7,0,Devo,8CH,0,CH5,CH6,CH7,CH8
+7,1,Devo,10CH,0,CH5,CH6,CH7,CH8,CH9,CH10
+7,2,Devo,12CH,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
+7,3,Devo,6CH,0,CH5,CH6
+7,4,Devo,7CH,0,CH5,CH6,CH7
+33,0,DM022,Std,1,Flip,LED,Cam1,Cam2,HLess,RTH,RLow
+6,0,DSM,2_22,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
+6,1,DSM,2_11,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
+6,2,DSM,X_22,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
+6,3,DSM,X_11,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
+6,4,DSM,AUTO,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
+70,0,DSM_RX,RX,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
+45,0,E01X,E012,1,n-a,Flip,n-a,HLess,RTH
+45,1,E01X,E015,1,Arm,Flip,LED,HLess,RTH
+45,2,E01X,E016H,1,Stop,Flip,n-a,HLess,RTH
+16,0,ESKY,Std,0,Gyro,Pitch
+16,1,ESKY,ET4,0,Gyro,Pitch
+35,0,ESKY150,4CH,0
+35,1,ESKY150,7CH,0,FMode,Aux6,Aux7
+69,0,ESKY150V2,Std,0,CH5_RA,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
1,0,Flysky,Flysky,0,CH5,CH6,CH7,CH8
1,1,Flysky,V9x9,1,Flip,Light,Pict,Video
1,2,Flysky,V6x6,1,Flip,Light,Pict,Video,HLess,RTH,XCAL,YCAL
@@ -7,15 +51,11 @@
28,1,Flysky_AFHDS2A,PPM_IBUS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
28,2,Flysky_AFHDS2A,PWM_SBUS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
28,3,Flysky_AFHDS2A,PPM_SBUS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
-53,0,Flyzone,FZ-410,0
-2,0,Hubsan,H107,1,Flip,Light,Pict,Video,HLess
-2,1,Hubsan,H301,0,RTH,Light,Stab,Video
-2,2,Hubsan,H501,0,RTH,Light,Pict,Video,HLess,GPS_H,ALT_H,Flip,FModes
-41,0,Bugs,3-6-8,0,Arm,Angle,Flip,Pict,Video,LED
-60,0,Pelikan,PRO_V4,0,CH5,CH6,CH7,CH8
-37,0,Corona,COR_V1,0,CH5,CH6,CH7,CH8
-37,1,Corona,COR_V2,0,CH5,CH6,CH7,CH8
-37,2,Corona,FD_V3,0,CH5,CH6,CH7,CH8
+28,4,Flysky_AFHDS2A,PWM_IB16,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
+28,5,Flysky_AFHDS2A,PPM_IB16,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
+56,0,Flysky2A_RX,RX,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
+53,0,Height,5ch,0,Gear
+53,1,Height,8ch,0,Gear,Gyro,Flap,Light
25,0,FrSkyV,V8,0,CH5,CH6,CH7,CH8
3,0,FrSkyD,D8,0,CH5,CH6,CH7,CH8
3,0,FrSkyD,D8Cloned,0,CH5,CH6,CH7,CH8
@@ -26,78 +66,50 @@
15,2,FrSkyX,D16_LBT,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
15,3,FrSkyX,D16_8CH_LBT,0,CH5,CH6,CH7,CH8
15,4,FrSkyX,D16Cloned,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
+15,5,FrSkyX,D16Cloned_8CH,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
64,0,FrSkyX2,D16_FCC,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
64,1,FrSkyX2,D16_8CH_FCC,0,CH5,CH6,CH7,CH8
64,2,FrSkyX2,D16_LBT,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
64,3,FrSkyX2,D16_8CH_LBT,1,CH5,CH6,CH7,CH8
64,4,FrSkyX2,D16Cloned,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
+64,5,FrSkyX2,D16Cloned_8CH,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
+65,0,FrSkyR9,R9_915,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
+65,1,FrSkyR9,R9_868,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
+65,2,FrSkyR9,R9_915_8CH,0,CH5,CH6,CH7,CH8
+65,3,FrSkyR9,R9_968_8CH,0,CH5,CH6,CH7,CH8
55,0,FrSkyRX,RX,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
55,1,FrSkyRX,CloneTX,0
-39,0,Hitec,Opt_Fw,0,CH5,CH6,CH7,CH8,CH9
-39,1,Hitec,Opt_Hub,0,CH5,CH6,CH7,CH8,CH9
-39,2,Hitec,Minima,0,CH5,CH6,CH7,CH8,CH9
-57,0,HoTT,Std,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
-21,0,SFHSS,Std,0,CH5,CH6,CH7,CH8
-68,0,Skyartec,Std,0,CH5,CH6,CH7
-7,0,Devo,8CH,0,CH5,CH6,CH7,CH8
-7,1,Devo,10CH,0,CH5,CH6,CH7,CH8,CH9,CH10
-7,2,Devo,12CH,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
-7,3,Devo,6CH,0,CH5,CH6
-7,4,Devo,7CH,0,CH5,CH6,CH7
-30,0,WK2x01,WK2801,0,CH5,CH6,CH7,CH8
-30,1,WK2x01,WK2401,0
-30,2,WK2x01,W6_5_1,0,Gear,Dis,Gyro
-30,3,WK2x01,W6_6_1,0,Gear,Col,Gyro
-30,4,WK2x01,W6HEL,0,Gear,Col,Gyro
-30,5,WK2x01,W6HEL_I,0,Gear,Col,Gyro
-6,0,DSM,2_22,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
-6,1,DSM,2_11,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
-6,2,DSM,X_22,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
-6,3,DSM,X_11,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
-22,0,J6Pro,Std,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
-22,0,WFLY,WFR0xS,0,CH5,CH6,CH7,CH8,CH9
-24,0,Assan,Std,0,CH5,CH6,CH7,CH8
-14,0,Bayang,Std,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,n-a,n-a,AnAux1,AnAux2
-14,1,Bayang,H8S3D,1,Flip,RTH,Pict,Video,HLess,Invert,Rates
-14,2,Bayang,X16_AH,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf
-14,3,Bayang,IRDRONE,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf,EmStop
-14,4,Bayang,DHD_D4,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf,EmStop
-59,0,BayangRX,RX,1,AnAux1,AnAux2,Flip,RTH,Pict,Video
-42,0,BugsMini,Mini,0,Arm,Angle,Flip,Pict,Video,LED
-42,1,BugsMini,3H,0,Arm,Angle,Flip,Pict,Video,LED,AltHol
-34,0,Cabell,V3,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
-34,1,Cabell,V3Telem,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
-13,0,CG023,Std,1,Flip,Light,Pict,Video,HLess
-13,1,CG023,YD829,1,Flip,n-a,Pict,Video,HLess
-12,0,CX10,Green,1,Flip,Rate
-12,1,CX10,Blue,1,Flip,Rate,Pict,Video
-12,2,CX10,DM007,1,Flip,Mode,Pict,Video,HLess
-12,4,CX10,JC3015_1,1,Flip,Mode,Pict,Video
-12,5,CX10,JC3015_2,1,Flip,Mode,LED,DFlip
-12,6,CX10,MK33041,1,Flip,Mode,Pict,Video,HLess,RTH
-33,0,DM022,Std,1,Flip,LED,Cam1,Cam2,HLess,RTH,RLow
-45,0,E01X,E012,1,n-a,Flip,n-a,HLess,RTH
-45,1,E01X,E015,1,Arm,Flip,LED,HLess,RTH
-45,2,E01X,E016H,1,Stop,Flip,n-a,HLess,RTH
-16,0,ESKY,Std,0,Gyro,Pitch
-16,1,ESKY,ET4,0,Gyro,Pitch
-35,0,ESKY150,4CH,0
-35,1,ESKY150,7CH,0,FMode,Aux6,Aux7
+58,0,FX816,P38,1
20,0,FY326,FY326,1,Flip,RTH,HLess,Expert,Calib
20,1,FY326,FY319,1,Flip,RTH,HLess,Expert,Calib
23,0,FY326,FY326,1,Flip,RTH,HLess,Expert
+47,0,GD00x,V1,1,Trim,LED,Rate
+47,1,GD00x,V2,1,Trim,LED,Rate
32,0,GW008,FY326,1,Flip
36,0,H8_3D,Std,1,Flip,Light,Pict,Video,RTH,FlMode,Cal1
36,1,H8_3D,H20H,1,Flip,Light,Pict,Video,Opt1,Opt2,Cal1,Cal2,Gimbal
36,2,H8_3D,H20,1,Flip,Light,Pict,Video,Opt1,Opt2,Cal1,Cal2,Gimbal
36,3,H8_3D,H30,1,Flip,Light,Pict,Video,Opt1,Opt2,Cal1,Cal2,Gimbal
4,0,Hisky,Std,0,Gear,Pitch,Gyro,CH8
-9,0,KN,WLToys,0,DRate,THold,IdleUp,Gyro,Ttrim,Atrim,Etrim
-9,1,KN,Feilun,0,DRate,THold,IdleUp,Gyro,Ttrim,Atrim,Etrim
+4,1,Hisky,HK310,0,Aux
+39,0,Hitec,Opt_Fw,0,CH5,CH6,CH7,CH8,CH9
+39,1,Hitec,Opt_Hub,0,CH5,CH6,CH7,CH8,CH9
+39,2,Hitec,Minima,0,CH5,CH6,CH7,CH8,CH9
26,0,Hontai,Std,1,Flip,LED,Pict,Video,HLess,RTH,Calib
26,1,Hontai,JJRCX1,1,Flip,Arm,Pict,Video,HLess,RTH,Calib
26,2,Hontai,X5C1,1,Flip,Arm,Pict,Video,HLess,RTH,Calib
26,3,Hontai,FQ777_951,1,Flip,Arm,Pict,Video,HLess,RTH,Calib
+57,0,HoTT,Sync,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
+57,1,HoTT,No_Sync,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
+2,0,Hubsan,H107,1,Flip,Light,Pict,Video,HLess
+2,1,Hubsan,H301,0,RTH,Light,Stab,Video
+2,2,Hubsan,H501,0,RTH,Light,Pict,Video,HLess,GPS_H,ALT_H,Flip,FModes
+22,0,J6Pro,Std,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
+71,0,JJRC345,Std,1,Flip,HLess,RTH
+49,0,KF606,Std,1,Trim
+9,0,KN,WLToys,0,DRate,THold,IdleUp,Gyro,Ttrim,Atrim,Etrim
+9,1,KN,Feilun,0,DRate,THold,IdleUp,Gyro,Ttrim,Atrim,Etrim
+73,0,Kyosho,Std,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
18,0,MJXQ,WHL08,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
18,1,MJXQ,X600,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
18,2,MJXQ,X800,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
@@ -111,6 +123,9 @@
17,3,MT99XX,LS,1,Flip,Invert,Pict,Video,HLess
17,4,MT99XX,FY805,1,Flip,n-a,n-a,n-a,HLess
44,0,NCC1701,Std,1,Warp
+77,0,OMP,M2,0,THold,IdleUp,6G_3D
+60,0,Pelikan,PRO_V4,0,CH5,CH6,CH7,CH8
+60,1,Pelikan,LITE_V4,0,CH5,CH6,CH7,CH8
51,0,Potensic,A20,1,TakLan,Emerg,Mode,HLess
66,0,Propel,74-Z,1,LEDs,RollCW,RolCCW,Fire,Weapon,Calib,AltHol,TakeOf,Land,Train
29,0,Q2x2,Q222,1,Flip,LED,Mod2,Mod1,HLess,RTH,XCal,YCal
@@ -120,8 +135,15 @@
31,1,Q303,C35,1,Arm,VTX,Pict,Video,n-a,RTH,Gimbal
31,2,Q303,CX10D,1,Arm,Flip
31,3,Q303,CX10WD,1,Arm,Flip
+72,0,Q90C,Std,0,FMode,VTX+
+74,0,RadioLink,Surface,0,CH5,CH6,CH7,CH8,FS_CH1,FS_CH2,FS_CH3,FS_CH4,FS_CH5,FS_CH6,FS_CH7,FS_CH8
+74,1,RadioLink,Air,0,CH5,CH6,CH7,CH8,FS_CH1,FS_CH2,FS_CH3,FS_CH4,FS_CH5,FS_CH6,FS_CH7,FS_CH8
+76,0,Realacc,R11,1,Flip,Light,Calib,HLess,RTH,UNK
50,0,Redpine,Fast,0,sCH5,sCH6,sCH7,sCH8,sCH9,sCH10,sCH11,sCH12,sCH13,sCH14,sCH15,sCH16
50,1,Redpine,Slow,0,sCH5,sCH6,sCH7,sCH8,sCH9,sCH10,sCH11,sCH12,sCH13,sCH14,sCH15,sCH16
+21,0,SFHSS,Std,0,CH5,CH6,CH7,CH8
+19,0,Shenqi,Cycle,1
+68,0,Skyartec,Std,0,CH5,CH6,CH7
11,0,SLT,V1,0,Gear,Pitch
11,1,SLT,V2,0,CH5,CH6,CH7,CH8
11,2,SLT,Q100,0,Rates,n-a,CH7,CH8,Mode,Flip,n-a,n-a,Calib
@@ -129,11 +151,21 @@
11,4,SLT,MR100,0,Rates,n-a,CH7,CH8,Mode,Flip,Video,Pict
10,0,Symax,Std,1,Flip,Rates,Pict,Video,HLess
10,1,Symax,X5C,1,Flip,Rates,Pict,Video,HLess
+61,0,Tiger,Std,1,Flip,Light
+43,0,Traxxas,6519,0
5,0,V2x2,Std,1,Flip,Light,Pict,Video,HLess,CalX,CalY
5,1,V2x2,JXD506,1,Flip,Light,Pict,Video,HLess,StaSto,Emerg,Cam_UD
-61,0,Tiger,Std,1,Flip,Light
-46,0,V911s,Std,1,Calib
-46,1,E119,Std,1,Calib
+48,0,V761,3CH,0,Gyro,Calib,Flip,RtnAct,Rtn
+48,1,V761,4CH,0,Gyro,Calib,Flip,RtnAct,Rtn
+46,0,V911s,V911s,1,Calib
+46,1,V911s,E119,1,Calib
+22,0,WFLY,WFR0xS,0,CH5,CH6,CH7,CH8,CH9
+30,0,WK2x01,WK2801,0,CH5,CH6,CH7,CH8
+30,1,WK2x01,WK2401,0
+30,2,WK2x01,W6_5_1,0,Gear,Dis,Gyro
+30,3,WK2x01,W6_6_1,0,Gear,Col,Gyro
+30,4,WK2x01,W6HEL,0,Gear,Col,Gyro
+30,5,WK2x01,W6HEL_I,0,Gear,Col,Gyro
62,0,XK,X450,1,FMode,TakeOf,Emerg,3D_6G,Pict,Video
62,1,XK,X420,1,FMode,TakeOf,Emerg,3D_6G,Pict,Video
8,0,YD717,Std,1,Flip,Light,Pict,Video,HLess
@@ -141,17 +173,4 @@
8,2,YD717,Simax4,1,Flip,Light,Pict,Video,HLess
8,3,YD717,XinXun,1,Flip,Light,Pict,Video,HLess
8,4,YD717,NiHui,1,Flip,Light,Pict,Video,HLess
-65,0,FrSkyR9,R9_915,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
-65,1,FrSkyR9,R9_868,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
-65,2,FrSkyR9,R9_915_8CH,0,CH5,CH6,CH7,CH8
-65,3,FrSkyR9,R9_968_8CH,0,CH5,CH6,CH7,CH8
-56,0,Flysky2A_RX,RX,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
-19,0,Shenqi,Cycle,1
-4,1,Hisky,HK310,0,Aux
-43,0,Traxxas,6519,0
52,0,ZSX,280,1,Light
-48,0,V761,Std,1,Gyro
-49,0,KF606,Std,1,Trim
-47,0,GD00x,V1,1,Trim,LED,Rate
-47,1,GD00x,V2,1,Trim,LED,Rate
-58,0,FX816,P38,1
diff --git a/radio/sdcard/horus/SCRIPTS/TOOLS/MultiChannelsUpdater.lua b/radio/sdcard/horus/SCRIPTS/TOOLS/MultiChannelsUpdater.lua
index 42de75e4f..14902b782 100644
--- a/radio/sdcard/horus/SCRIPTS/TOOLS/MultiChannelsUpdater.lua
+++ b/radio/sdcard/horus/SCRIPTS/TOOLS/MultiChannelsUpdater.lua
@@ -249,13 +249,13 @@ local function Multi_Init()
--Exceptions on first 4 channels...
local stick_names = { "Rud", "Ele", "Thr", "Ail" }
- if ( protocol == 4 and sub_protocol ==1 ) or protocol == 19 or protocol == 52 then -- Hisky/HK310, Shenqi, ZSX
+ if ( protocol == 4 and sub_protocol == 1 ) or protocol == 19 or protocol == 52 then -- Hisky/HK310, Shenqi, ZSX
stick_names[2] = "n-a"
stick_names[4] = "n-a"
elseif protocol == 43 then -- Traxxas
stick_names[2] = "Aux4"
stick_names[4] = "Aux3"
- elseif protocol == 48 then -- V761
+ elseif ( protocol == 48 and sub_protocol == 0 ) then -- V761 3CH
stick_names[4] = "n-a"
elseif protocol == 47 or protocol == 49 or protocol == 58 then -- GD00x, KF606, FX816
stick_names[1] = "n-a"
@@ -278,6 +278,15 @@ local function Multi_Init()
ch_order = math.floor(ch_order/4)
channel_names[bitand(ch_order,3)+1] = stick_names[1]
end
+
+ --Exceptions on first 4 channels...
+ if ( protocol == 73 or (protocol == 74 and sub_protocol == 0) ) then -- Kyosho or RadioLink Surface
+ channel_names[1] = "ST"
+ channel_names[2] = "THR"
+ channel_names[3] = "CH3"
+ channel_names[4] = "CH4"
+ end
+
--Check MultiChan.txt
local f = io.open("/SCRIPTS/TOOLS/MultiChan.txt", "r")
if f == nil then return end
diff --git a/radio/sdcard/horus/SCRIPTS/TOOLS/crossfire.lua b/radio/sdcard/horus/SCRIPTS/TOOLS/crossfire.lua
index 0f9b1a20f..b19bb5ee2 100644
--- a/radio/sdcard/horus/SCRIPTS/TOOLS/crossfire.lua
+++ b/radio/sdcard/horus/SCRIPTS/TOOLS/crossfire.lua
@@ -30,6 +30,11 @@ local function run(event)
return 2
end
+ if crossfireTelemetryPush() == nil then
+ error("Crossfire not available!")
+ return 2
+ end
+
chdir("/SCRIPTS/TOOLS/CROSSFIRE")
return "crossfire.lua"
end
diff --git a/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/icon.png b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/icon.png
new file mode 100755
index 000000000..b6b737047
Binary files /dev/null and b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/icon.png differ
diff --git a/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/arm.png b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/arm.png
new file mode 100755
index 000000000..33dcd7d91
Binary files /dev/null and b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/arm.png differ
diff --git a/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/background.png b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/background.png
new file mode 100755
index 000000000..e21f7bc81
Binary files /dev/null and b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/background.png differ
diff --git a/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/beeper.png b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/beeper.png
new file mode 100755
index 000000000..57c37f2fe
Binary files /dev/null and b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/beeper.png differ
diff --git a/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/mark_bg.png b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/mark_bg.png
new file mode 100755
index 000000000..fbe6b0ee2
Binary files /dev/null and b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/mark_bg.png differ
diff --git a/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/mode.png b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/mode.png
new file mode 100755
index 000000000..37a183020
Binary files /dev/null and b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/mode.png differ
diff --git a/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/pagedn.png b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/pagedn.png
new file mode 100755
index 000000000..0733ccfa1
Binary files /dev/null and b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/pagedn.png differ
diff --git a/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/pageup.png b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/pageup.png
new file mode 100755
index 000000000..0dbaa5202
Binary files /dev/null and b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/pageup.png differ
diff --git a/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/pitch.png b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/pitch.png
new file mode 100755
index 000000000..e691fded2
Binary files /dev/null and b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/pitch.png differ
diff --git a/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/roll.png b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/roll.png
new file mode 100755
index 000000000..9110a0d52
Binary files /dev/null and b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/roll.png differ
diff --git a/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/throttle.png b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/throttle.png
new file mode 100755
index 000000000..b4f796b0a
Binary files /dev/null and b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/throttle.png differ
diff --git a/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/yaw.png b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/yaw.png
new file mode 100755
index 000000000..3fc055bb3
Binary files /dev/null and b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/yaw.png differ
diff --git a/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/wizard.lua b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/wizard.lua
new file mode 100755
index 000000000..baf8461b5
--- /dev/null
+++ b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/wizard.lua
@@ -0,0 +1,411 @@
+---- #########################################################################
+---- # #
+---- # Copyright (C) OpenTX #
+-----# #
+-----# Credits: graphics by Radiomaster #
+-----# #
+---- # 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. #
+---- # #
+---- #########################################################################
+
+local VALUE = 0
+local COMBO = 1
+
+local edit = false
+local page = 1
+local current = 1
+local pages = {}
+local fields = {}
+local switches = {"SA", "SB", "SC", "SD", "SE", "SF", "SG"}
+
+-- load common Bitmaps
+local ImgMarkBg = Bitmap.open("img/mark_bg.png")
+local BackgroundImg = Bitmap.open("img/background.png")
+local ImgPageUp = Bitmap.open("img/pageup.png")
+local ImgPageDn = Bitmap.open("img/pagedn.png")
+
+
+-- Change display attribute to current field
+local function addField(step)
+ local field = fields[current]
+ local min, max
+ if field[3] == VALUE then
+ min = field[6]
+ max = field[7]
+ elseif field[3] == COMBO then
+ min = 0
+ max = #(field[6]) - 1
+ end
+ if (step < 0 and field[5] > min) or (step > 0 and field[5] < max) then
+ field[5] = field[5] + step
+ end
+end
+
+-- Select the next or previous page
+local function selectPage(step)
+ page = 1 + ((page + step - 1 + #pages) % #pages)
+ edit = false
+ current = 1
+end
+
+-- Select the next or previous editable field
+local function selectField(step)
+ repeat
+ current = 1 + ((current + step - 1 + #fields) % #fields)
+ until fields[current][4]==1
+end
+
+-- Redraw the current page
+local function redrawFieldsPage(event)
+
+ for index = 1, 10, 1 do
+ local field = fields[index]
+ if field == nil then
+ break
+ end
+
+ local attr = current == (index) and ((edit == true and BLINK or 0) + INVERS) or 0
+ attr = attr + TEXT_COLOR
+
+ if field[4] == 1 then
+ if field[3] == VALUE then
+ lcd.drawNumber(field[1], field[2], field[5], LEFT + attr)
+ elseif field[3] == COMBO then
+ if field[5] >= 0 and field[5] < #(field[6]) then
+ lcd.drawText(field[1],field[2], field[6][1+field[5]], attr)
+ end
+ end
+ end
+ end
+end
+
+local function updateField(field)
+ local value = field[5]
+end
+
+-- Main
+local function runFieldsPage(event)
+ if event == EVT_VIRTUAL_EXIT then -- exit script
+ return 2
+ elseif event == EVT_VIRTUAL_ENTER then -- toggle editing/selecting current field
+ if fields[current][5] ~= nil then
+ edit = not edit
+ if edit == false then
+ updateField(fields[current])
+ end
+ end
+ elseif edit then
+ if event == EVT_VIRTUAL_INC or event == EVT_VIRTUAL_INC_REPT then
+ addField(1)
+ elseif event == EVT_VIRTUAL_DEC or event == EVT_VIRTUAL_DEC_REPT then
+ addField(-1)
+ end
+ else
+ if event == EVT_VIRTUAL_NEXT then
+ selectField(1)
+ elseif event == EVT_VIRTUAL_PREV then
+ selectField(-1)
+ end
+ end
+ redrawFieldsPage(event)
+ return 0
+end
+
+-- set visibility flags starting with SECOND field of fields
+local function setFieldsVisible(...)
+ local arg={...}
+ local cnt = 2
+ for i,v in ipairs(arg) do
+ fields[cnt][4] = v
+ cnt = cnt + 1
+ end
+end
+
+-- draws one letter mark
+local function drawMark(x, y, name)
+ lcd.drawBitmap(ImgMarkBg, x, y)
+ lcd.drawText(x+8, y+3, name, TEXT_COLOR)
+end
+
+
+local ThrottleFields = {
+ {50, 50, COMBO, 1, 2, { "CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "CH7", "CH8" } },
+}
+
+local ThrottleBackground
+
+local function runThrottleConfig(event)
+ lcd.clear()
+ if ThrottleBackground == nil then
+ ThrottleBackground = Bitmap.open("img/throttle.png")
+ end
+ lcd.drawBitmap(ThrottleBackground, 0, 0)
+ lcd.drawBitmap(ImgPageDn, 455, 95)
+ fields = ThrottleFields
+ lcd.drawText(40, 20, "Assign Throttle channel", TEXT_COLOR)
+ lcd.drawFilledRectangle(40, 45, 100, 30, TEXT_BGCOLOR)
+ fields[1][4]=1
+ local result = runFieldsPage(event)
+ return result
+end
+
+local RollFields = {
+ {50, 50, COMBO, 1, 0, { "CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "CH7", "CH8" } },
+}
+
+local RollBackground
+
+local function runRollConfig(event)
+ lcd.clear()
+ if RollBackground == nil then
+ RollBackground = Bitmap.open("img/roll.png")
+ end
+ lcd.drawBitmap(RollBackground, 0, 0)
+ lcd.drawBitmap(ImgPageUp, 0, 95)
+ lcd.drawBitmap(ImgPageDn, 455, 95)
+ fields = RollFields
+ lcd.drawText(40, 20, "Assign Roll channel", TEXT_COLOR)
+ lcd.drawFilledRectangle(40, 45, 100, 30, TEXT_BGCOLOR)
+ fields[1][4]=1
+ local result = runFieldsPage(event)
+ return result
+end
+
+local PitchFields = {
+ {50, 50, COMBO, 1, 1, { "CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "CH7", "CH8" } },
+}
+
+local PitchBackground
+
+local function runPitchConfig(event)
+ lcd.clear()
+ if PitchBackground == nil then
+ PitchBackground = Bitmap.open("img/pitch.png")
+ end
+ lcd.drawBitmap(PitchBackground, 0, 0)
+ lcd.drawBitmap(ImgPageUp, 0, 95)
+ lcd.drawBitmap(ImgPageDn, 455, 95)
+ fields = PitchFields
+ lcd.drawText(40, 20, "Assign Pitch channel", TEXT_COLOR)
+ lcd.drawFilledRectangle(40, 45, 100, 30, TEXT_BGCOLOR)
+ fields[1][4]=1
+ local result = runFieldsPage(event)
+ return result
+end
+
+local YawFields = {
+ {50, 50, COMBO, 1, 3, { "CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "CH7", "CH8" } },
+}
+
+local YawBackground
+
+local function runYawConfig(event)
+ lcd.clear()
+ if YawBackground == nil then
+ YawBackground = Bitmap.open("img/yaw.png")
+ end
+ lcd.drawBitmap(YawBackground, 0, 0)
+ lcd.drawBitmap(ImgPageUp, 0, 95)
+ lcd.drawBitmap(ImgPageDn, 455, 95)
+ fields = YawFields
+ lcd.drawText(40, 20, "Assign Yaw channel", TEXT_COLOR)
+ lcd.drawFilledRectangle(40, 45, 100, 30, TEXT_BGCOLOR)
+ fields[1][4]=1
+ local result = runFieldsPage(event)
+ return result
+end
+
+local ArmFields = {
+ {50, 50, COMBO, 1, 5, { "SA", "SB", "SC", "SD", "SE", "SF"} },
+}
+
+local ArmBackground
+
+local function runArmConfig(event)
+ lcd.clear()
+ if ArmBackground == nil then
+ ArmBackground = Bitmap.open("img/arm.png")
+ end
+ lcd.drawBitmap(ArmBackground, 0, 0)
+ lcd.drawBitmap(ImgPageUp, 0, 95)
+ lcd.drawBitmap(ImgPageDn, 455, 95)
+ fields = ArmFields
+ lcd.drawText(40, 20, "Assign Arm switch", TEXT_COLOR)
+ lcd.drawFilledRectangle(40, 45, 100, 30, TEXT_BGCOLOR)
+ fields[1][4]=1
+ local result = runFieldsPage(event)
+ return result
+end
+
+local BeeperFields = {
+ {50, 50, COMBO, 1, 3, { "SA", "SB", "SC", "SD", "SE", "SF"} },
+}
+
+local BeeperBackground
+
+local function runBeeperConfig(event)
+ lcd.clear()
+ if BeeperBackground == nil then
+ BeeperBackground = Bitmap.open("img/beeper.png")
+ end
+ lcd.drawBitmap(BeeperBackground, 0, 0)
+ lcd.drawBitmap(ImgPageUp, 0, 95)
+ lcd.drawBitmap(ImgPageDn, 455, 95)
+ fields = BeeperFields
+ lcd.drawText(40, 20, "Assign Beeper switch", TEXT_COLOR)
+ lcd.drawFilledRectangle(40, 45, 100, 30, TEXT_BGCOLOR)
+ fields[1][4]=1
+ local result = runFieldsPage(event)
+ return result
+end
+
+local ModeFields = {
+ {50, 50, COMBO, 1, 0, { "SA", "SB", "SC", "SD", "SE", "SF"} },
+}
+
+local ModeBackground
+
+local function runModeConfig(event)
+ lcd.clear()
+ if ModeBackground == nil then
+ ModeBackground = Bitmap.open("img/mode.png")
+ end
+ lcd.drawBitmap(ModeBackground, 0, 0)
+ lcd.drawBitmap(ImgPageUp, 0, 95)
+ lcd.drawBitmap(ImgPageDn, 455, 95)
+ fields = ModeFields
+ lcd.drawText(40, 20, "Assign Mode switch", TEXT_COLOR)
+ lcd.drawFilledRectangle(40, 45, 100, 30, TEXT_BGCOLOR)
+ fields[1][4]=1
+ local result = runFieldsPage(event)
+ return result
+end
+
+local lineIndex
+local function drawNextChanelLine(text, text2)
+ lcd.drawText(40, lineIndex, text, TEXT_COLOR)
+ lcd.drawText(242, lineIndex, ": CH" .. text2 + 1, TEXT_COLOR)
+ lineIndex = lineIndex + 20
+end
+
+local function drawNextSwitchLine(text, text2)
+ lcd.drawText(40, lineIndex, text, TEXT_COLOR)
+ lcd.drawText(242, lineIndex, ": " ..switches[text2 + 1], TEXT_COLOR)
+ lineIndex = lineIndex + 20
+end
+
+
+local ConfigSummaryFields = {
+ {110, 250, COMBO, 1, 0, { "No, I need to change something", "Yes, all is well, create the model !"} },
+}
+
+local ImgSummary
+
+local function runConfigSummary(event)
+ lcd.clear()
+ if ImgSummary == nil then
+ ImgSummary = Bitmap.open("img/summary.png")
+ end
+ fields = ConfigSummaryFields
+ lcd.drawBitmap(BackgroundImg, 0, 0)
+ lcd.drawBitmap(ImgPageUp, 0, 95)
+ lcd.drawBitmap(ImgSummary, 300, 60)
+ lineIndex = 40
+ -- throttle
+ drawNextChanelLine("Throttle channel", ThrottleFields[1][5])
+ -- roll
+ drawNextChanelLine("Roll channel",RollFields[1][5])
+ -- pitch
+ drawNextChanelLine("Pitch channel",PitchFields[1][5])
+ -- yaw
+ drawNextChanelLine("Yaw channel",YawFields[1][5])
+ -- arm
+ drawNextSwitchLine("Arm switch",ArmFields[1][5])
+ -- beeper
+ drawNextSwitchLine("Beeper switch",BeeperFields[1][5])
+ -- mode
+ drawNextSwitchLine("Mode switch",ModeFields[1][5])
+
+ local result = runFieldsPage(event)
+ if(fields[1][5] == 1 and edit == false) then
+ selectPage(1)
+ end
+ return result
+end
+
+local function addMix(channel, input, name, weight, index)
+ local mix = { source=input, name=name }
+ if weight ~= nil then
+ mix.weight = weight
+ end
+ if index == nil then
+ index = 0
+ end
+ model.insertMix(channel, index, mix)
+end
+
+local function createModel(event)
+ lcd.clear()
+ lcd.drawBitmap(BackgroundImg, 0, 0)
+ lcd.drawBitmap(ImgSummary, 300, 60)
+ model.defaultInputs()
+ model.deleteMixes()
+ -- throttle
+ addMix(ThrottleFields[1][5], MIXSRC_FIRST_INPUT+defaultChannel(2), "Thr")
+ -- roll
+ addMix(RollFields[1][5], MIXSRC_FIRST_INPUT+defaultChannel(0), "Roll")
+ -- pitch
+ addMix(PitchFields[1][5], MIXSRC_FIRST_INPUT+defaultChannel(1), "Pitch")
+ -- yaw
+ addMix(YawFields[1][5], MIXSRC_FIRST_INPUT+defaultChannel(3), "Yaw")
+ addMix(4, MIXSRC_SA + ArmFields[1][5], "Arm")
+ addMix(5, MIXSRC_SA + BeeperFields[1][5], "Beeper")
+ addMix(6, MIXSRC_SA + ModeFields[1][5], "Mode")
+
+ lcd.drawText(70, 90, "Model successfully created !", TEXT_COLOR)
+ lcd.drawText(100, 130, "Press RTN to exit", TEXT_COLOR)
+ return 2
+end
+
+-- Init
+local function init()
+ current, edit = 1, false
+ pages = {
+ runThrottleConfig,
+ runRollConfig,
+ runPitchConfig,
+ runYawConfig,
+ runArmConfig,
+ runBeeperConfig,
+ runModeConfig,
+ runConfigSummary,
+ createModel,
+ }
+end
+
+-- Main
+local function run(event)
+ if event == nil then
+ error("Cannot be run as a model script!")
+ return 2
+ elseif event == EVT_VIRTUAL_NEXT_PAGE and page < #pages-1 then
+ selectPage(1)
+ elseif event == EVT_VIRTUAL_PREV_PAGE and page > 1 then
+ killEvents(event);
+ selectPage(-1)
+ end
+
+ local result = pages[page](event)
+ return result
+end
+
+return { init=init, run=run }
diff --git a/radio/sdcard/horus/THEMES/Flexi/X10.bmp b/radio/sdcard/horus/THEMES/Flexi/X10.bmp
new file mode 100755
index 000000000..32a730cde
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/X10.bmp differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/X10S.bmp b/radio/sdcard/horus/THEMES/Flexi/X10S.bmp
new file mode 100644
index 000000000..221e25ec4
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/X10S.bmp differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/asterisk.bmp b/radio/sdcard/horus/THEMES/Flexi/asterisk.bmp
new file mode 100644
index 000000000..3dd3cfef4
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/asterisk.bmp differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/busy.bmp b/radio/sdcard/horus/THEMES/Flexi/busy.bmp
new file mode 100644
index 000000000..8e6a8b7f7
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/busy.bmp differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/horus.bmp b/radio/sdcard/horus/THEMES/Flexi/horus.bmp
new file mode 100644
index 000000000..98bc631cd
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/horus.bmp differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_currentmenu_bg.png b/radio/sdcard/horus/THEMES/Flexi/mask_currentmenu_bg.png
new file mode 100644
index 000000000..715792023
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_currentmenu_bg.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_currentmenu_dot.png b/radio/sdcard/horus/THEMES/Flexi/mask_currentmenu_dot.png
new file mode 100644
index 000000000..6f76965a9
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_currentmenu_dot.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_currentmenu_shadow.png b/radio/sdcard/horus/THEMES/Flexi/mask_currentmenu_shadow.png
new file mode 100644
index 000000000..97bf6c577
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_currentmenu_shadow.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_library.png b/radio/sdcard/horus/THEMES/Flexi/mask_library.png
new file mode 100644
index 000000000..237883fc5
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_library.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_menu_model.png b/radio/sdcard/horus/THEMES/Flexi/mask_menu_model.png
new file mode 100644
index 000000000..9832267b7
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_menu_model.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_menu_radio.png b/radio/sdcard/horus/THEMES/Flexi/mask_menu_radio.png
new file mode 100644
index 000000000..6d93fbccc
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_menu_radio.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_menu_stats.png b/radio/sdcard/horus/THEMES/Flexi/mask_menu_stats.png
new file mode 100644
index 000000000..ebd482588
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_menu_stats.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_menu_theme.png b/radio/sdcard/horus/THEMES/Flexi/mask_menu_theme.png
new file mode 100644
index 000000000..3a9fc15e7
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_menu_theme.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_model_curves.png b/radio/sdcard/horus/THEMES/Flexi/mask_model_curves.png
new file mode 100644
index 000000000..6e1e19e8e
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_model_curves.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_model_flight_modes.png b/radio/sdcard/horus/THEMES/Flexi/mask_model_flight_modes.png
new file mode 100644
index 000000000..e963f0abb
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_model_flight_modes.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_model_gvars.png b/radio/sdcard/horus/THEMES/Flexi/mask_model_gvars.png
new file mode 100644
index 000000000..0b5015dac
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_model_gvars.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_model_heli.png b/radio/sdcard/horus/THEMES/Flexi/mask_model_heli.png
new file mode 100644
index 000000000..ecd93d2ff
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_model_heli.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_model_inputs.png b/radio/sdcard/horus/THEMES/Flexi/mask_model_inputs.png
new file mode 100644
index 000000000..720099c47
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_model_inputs.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_model_logical_switches.png b/radio/sdcard/horus/THEMES/Flexi/mask_model_logical_switches.png
new file mode 100644
index 000000000..5cd1e3834
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_model_logical_switches.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_model_lua_scripts.png b/radio/sdcard/horus/THEMES/Flexi/mask_model_lua_scripts.png
new file mode 100644
index 000000000..a20c1ccbd
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_model_lua_scripts.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_model_mixer.png b/radio/sdcard/horus/THEMES/Flexi/mask_model_mixer.png
new file mode 100644
index 000000000..009b360f1
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_model_mixer.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_model_outputs.png b/radio/sdcard/horus/THEMES/Flexi/mask_model_outputs.png
new file mode 100644
index 000000000..a209ae8d3
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_model_outputs.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_model_setup.png b/radio/sdcard/horus/THEMES/Flexi/mask_model_setup.png
new file mode 100644
index 000000000..afe526c8f
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_model_setup.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_model_special_functions.png b/radio/sdcard/horus/THEMES/Flexi/mask_model_special_functions.png
new file mode 100644
index 000000000..a12a2a50d
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_model_special_functions.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_model_telemetry.png b/radio/sdcard/horus/THEMES/Flexi/mask_model_telemetry.png
new file mode 100644
index 000000000..d95d3b25f
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_model_telemetry.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_monitor.png b/radio/sdcard/horus/THEMES/Flexi/mask_monitor.png
new file mode 100644
index 000000000..68ddd4516
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_monitor.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_monitor_channels1.png b/radio/sdcard/horus/THEMES/Flexi/mask_monitor_channels1.png
new file mode 100644
index 000000000..b886fc1bc
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_monitor_channels1.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_monitor_channels2.png b/radio/sdcard/horus/THEMES/Flexi/mask_monitor_channels2.png
new file mode 100644
index 000000000..4d0354e25
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_monitor_channels2.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_monitor_channels3.png b/radio/sdcard/horus/THEMES/Flexi/mask_monitor_channels3.png
new file mode 100644
index 000000000..d9ba27de7
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_monitor_channels3.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_monitor_channels4.png b/radio/sdcard/horus/THEMES/Flexi/mask_monitor_channels4.png
new file mode 100644
index 000000000..fb321151f
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_monitor_channels4.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_monitor_gvars.png b/radio/sdcard/horus/THEMES/Flexi/mask_monitor_gvars.png
new file mode 100644
index 000000000..55b488d1e
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_monitor_gvars.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_monitor_inver.png b/radio/sdcard/horus/THEMES/Flexi/mask_monitor_inver.png
new file mode 100644
index 000000000..64f251238
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_monitor_inver.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_monitor_lockch.png b/radio/sdcard/horus/THEMES/Flexi/mask_monitor_lockch.png
new file mode 100644
index 000000000..360923a09
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_monitor_lockch.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_monitor_logsw.png b/radio/sdcard/horus/THEMES/Flexi/mask_monitor_logsw.png
new file mode 100644
index 000000000..dc6355143
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_monitor_logsw.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_monitor_mixes1.png b/radio/sdcard/horus/THEMES/Flexi/mask_monitor_mixes1.png
new file mode 100644
index 000000000..7b0c71f60
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_monitor_mixes1.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_monitor_mixes2.png b/radio/sdcard/horus/THEMES/Flexi/mask_monitor_mixes2.png
new file mode 100644
index 000000000..f8c04780e
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_monitor_mixes2.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_mplex_add.png b/radio/sdcard/horus/THEMES/Flexi/mask_mplex_add.png
new file mode 100644
index 000000000..14f4ecc23
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_mplex_add.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_mplex_multi.png b/radio/sdcard/horus/THEMES/Flexi/mask_mplex_multi.png
new file mode 100644
index 000000000..bcf79695f
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_mplex_multi.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_mplex_replace.png b/radio/sdcard/horus/THEMES/Flexi/mask_mplex_replace.png
new file mode 100644
index 000000000..faccba0ea
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_mplex_replace.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_opentx.png b/radio/sdcard/horus/THEMES/Flexi/mask_opentx.png
new file mode 100644
index 000000000..df2b0b356
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_opentx.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_opentx_testmode.png b/radio/sdcard/horus/THEMES/Flexi/mask_opentx_testmode.png
new file mode 100644
index 000000000..b535cf8ee
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_opentx_testmode.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_radio_calibration.png b/radio/sdcard/horus/THEMES/Flexi/mask_radio_calibration.png
new file mode 100644
index 000000000..db696778b
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_radio_calibration.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_radio_global_functions.png b/radio/sdcard/horus/THEMES/Flexi/mask_radio_global_functions.png
new file mode 100644
index 000000000..3b3efefb5
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_radio_global_functions.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_radio_hardware.png b/radio/sdcard/horus/THEMES/Flexi/mask_radio_hardware.png
new file mode 100644
index 000000000..f51a1aee1
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_radio_hardware.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_radio_sd_browser.png b/radio/sdcard/horus/THEMES/Flexi/mask_radio_sd_browser.png
new file mode 100644
index 000000000..75b6a9296
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_radio_sd_browser.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_radio_setup.png b/radio/sdcard/horus/THEMES/Flexi/mask_radio_setup.png
new file mode 100644
index 000000000..0010a06ab
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_radio_setup.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_radio_spectrum_analyser.png b/radio/sdcard/horus/THEMES/Flexi/mask_radio_spectrum_analyser.png
new file mode 100755
index 000000000..2908833ec
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_radio_spectrum_analyser.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_radio_tools.png b/radio/sdcard/horus/THEMES/Flexi/mask_radio_tools.png
new file mode 100755
index 000000000..711d499de
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_radio_tools.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_radio_trainer.png b/radio/sdcard/horus/THEMES/Flexi/mask_radio_trainer.png
new file mode 100644
index 000000000..7a0b56970
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_radio_trainer.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_radio_version.png b/radio/sdcard/horus/THEMES/Flexi/mask_radio_version.png
new file mode 100644
index 000000000..8730f6c1a
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_radio_version.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_sbar_mixer.png b/radio/sdcard/horus/THEMES/Flexi/mask_sbar_mixer.png
new file mode 100644
index 000000000..154406419
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_sbar_mixer.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_sbar_output.png b/radio/sdcard/horus/THEMES/Flexi/mask_sbar_output.png
new file mode 100644
index 000000000..12d599823
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_sbar_output.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_sbar_to.png b/radio/sdcard/horus/THEMES/Flexi/mask_sbar_to.png
new file mode 100644
index 000000000..813610307
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_sbar_to.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_stats_analogs.png b/radio/sdcard/horus/THEMES/Flexi/mask_stats_analogs.png
new file mode 100644
index 000000000..96fc0c8a2
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_stats_analogs.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_stats_debug.png b/radio/sdcard/horus/THEMES/Flexi/mask_stats_debug.png
new file mode 100644
index 000000000..0dce13d46
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_stats_debug.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_stats_lua.png b/radio/sdcard/horus/THEMES/Flexi/mask_stats_lua.png
new file mode 100644
index 000000000..d1b54a4d6
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_stats_lua.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_stats_throttle_graph.png b/radio/sdcard/horus/THEMES/Flexi/mask_stats_throttle_graph.png
new file mode 100644
index 000000000..a3720a005
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_stats_throttle_graph.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_stats_timers.png b/radio/sdcard/horus/THEMES/Flexi/mask_stats_timers.png
new file mode 100644
index 000000000..78bf00064
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_stats_timers.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_stats_value.png b/radio/sdcard/horus/THEMES/Flexi/mask_stats_value.png
new file mode 100644
index 000000000..180f16e8c
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_stats_value.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_switches.png b/radio/sdcard/horus/THEMES/Flexi/mask_switches.png
new file mode 100644
index 000000000..4097ed751
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_switches.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_textline_curve.png b/radio/sdcard/horus/THEMES/Flexi/mask_textline_curve.png
new file mode 100644
index 000000000..050229393
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_textline_curve.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_textline_delay.png b/radio/sdcard/horus/THEMES/Flexi/mask_textline_delay.png
new file mode 100644
index 000000000..9b771a94a
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_textline_delay.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_textline_delayslow.png b/radio/sdcard/horus/THEMES/Flexi/mask_textline_delayslow.png
new file mode 100644
index 000000000..de2f7d1f7
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_textline_delayslow.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_textline_fm.png b/radio/sdcard/horus/THEMES/Flexi/mask_textline_fm.png
new file mode 100644
index 000000000..b9a2c4a32
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_textline_fm.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_textline_label.png b/radio/sdcard/horus/THEMES/Flexi/mask_textline_label.png
new file mode 100644
index 000000000..8be12e39b
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_textline_label.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_textline_slow.png b/radio/sdcard/horus/THEMES/Flexi/mask_textline_slow.png
new file mode 100644
index 000000000..1afbea37d
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_textline_slow.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_textline_switch.png b/radio/sdcard/horus/THEMES/Flexi/mask_textline_switch.png
new file mode 100644
index 000000000..7c7d646e4
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_textline_switch.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_theme_add_view.png b/radio/sdcard/horus/THEMES/Flexi/mask_theme_add_view.png
new file mode 100644
index 000000000..7e240372f
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_theme_add_view.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_theme_setup.png b/radio/sdcard/horus/THEMES/Flexi/mask_theme_setup.png
new file mode 100644
index 000000000..2a39d1e40
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_theme_setup.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_theme_view1.png b/radio/sdcard/horus/THEMES/Flexi/mask_theme_view1.png
new file mode 100644
index 000000000..9e67515ec
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_theme_view1.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_theme_view2.png b/radio/sdcard/horus/THEMES/Flexi/mask_theme_view2.png
new file mode 100644
index 000000000..45cec234d
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_theme_view2.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_theme_view3.png b/radio/sdcard/horus/THEMES/Flexi/mask_theme_view3.png
new file mode 100644
index 000000000..e5a776b06
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_theme_view3.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_theme_view4.png b/radio/sdcard/horus/THEMES/Flexi/mask_theme_view4.png
new file mode 100644
index 000000000..9064b9403
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_theme_view4.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_theme_view5.png b/radio/sdcard/horus/THEMES/Flexi/mask_theme_view5.png
new file mode 100644
index 000000000..724bcc141
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_theme_view5.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_theme_view6.png b/radio/sdcard/horus/THEMES/Flexi/mask_theme_view6.png
new file mode 100644
index 000000000..2aa43514b
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_theme_view6.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_theme_view7.png b/radio/sdcard/horus/THEMES/Flexi/mask_theme_view7.png
new file mode 100644
index 000000000..d6a0540f5
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_theme_view7.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/mask_theme_view8.png b/radio/sdcard/horus/THEMES/Flexi/mask_theme_view8.png
new file mode 100644
index 000000000..82dfd7875
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/mask_theme_view8.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/modelsel/icon_boat1.png b/radio/sdcard/horus/THEMES/Flexi/modelsel/icon_boat1.png
new file mode 100644
index 000000000..a9335c4bc
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/modelsel/icon_boat1.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/modelsel/icon_boat2.png b/radio/sdcard/horus/THEMES/Flexi/modelsel/icon_boat2.png
new file mode 100644
index 000000000..e3c899d18
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/modelsel/icon_boat2.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/modelsel/icon_default.png b/radio/sdcard/horus/THEMES/Flexi/modelsel/icon_default.png
new file mode 100644
index 000000000..6f3042c67
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/modelsel/icon_default.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/modelsel/icon_favorites.png b/radio/sdcard/horus/THEMES/Flexi/modelsel/icon_favorites.png
new file mode 100644
index 000000000..e4a37dacb
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/modelsel/icon_favorites.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/modelsel/icon_plane1.png b/radio/sdcard/horus/THEMES/Flexi/modelsel/icon_plane1.png
new file mode 100644
index 000000000..a49a50271
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/modelsel/icon_plane1.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/modelsel/icon_plane2.png b/radio/sdcard/horus/THEMES/Flexi/modelsel/icon_plane2.png
new file mode 100644
index 000000000..8305b4150
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/modelsel/icon_plane2.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/modelsel/icon_plane3.png b/radio/sdcard/horus/THEMES/Flexi/modelsel/icon_plane3.png
new file mode 100644
index 000000000..d998144b2
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/modelsel/icon_plane3.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/modelsel/mask_iconback.png b/radio/sdcard/horus/THEMES/Flexi/modelsel/mask_iconback.png
new file mode 100644
index 000000000..966f6b7f2
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/modelsel/mask_iconback.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/modelsel/mask_modelname.png b/radio/sdcard/horus/THEMES/Flexi/modelsel/mask_modelname.png
new file mode 100644
index 000000000..2edca73ea
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/modelsel/mask_modelname.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/modelsel/mask_modelqty.png b/radio/sdcard/horus/THEMES/Flexi/modelsel/mask_modelqty.png
new file mode 100644
index 000000000..9a38e4f13
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/modelsel/mask_modelqty.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/modelsel/mask_moveback.png b/radio/sdcard/horus/THEMES/Flexi/modelsel/mask_moveback.png
new file mode 100644
index 000000000..63f56df92
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/modelsel/mask_moveback.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/modelsel/mask_moveico.png b/radio/sdcard/horus/THEMES/Flexi/modelsel/mask_moveico.png
new file mode 100644
index 000000000..3662b9bb0
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/modelsel/mask_moveico.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/modelsel/mask_sdfree.png b/radio/sdcard/horus/THEMES/Flexi/modelsel/mask_sdfree.png
new file mode 100644
index 000000000..f0ae81982
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/modelsel/mask_sdfree.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/question.bmp b/radio/sdcard/horus/THEMES/Flexi/question.bmp
new file mode 100644
index 000000000..101d7ed53
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/question.bmp differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/shutdown.bmp b/radio/sdcard/horus/THEMES/Flexi/shutdown.bmp
new file mode 100755
index 000000000..be7034db7
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/shutdown.bmp differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/stick_background.png b/radio/sdcard/horus/THEMES/Flexi/stick_background.png
new file mode 100644
index 000000000..9f6d53d92
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/stick_background.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/stick_pointer.png b/radio/sdcard/horus/THEMES/Flexi/stick_pointer.png
new file mode 100644
index 000000000..0d75765f9
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/stick_pointer.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/t16.bmp b/radio/sdcard/horus/THEMES/Flexi/t16.bmp
new file mode 100755
index 000000000..9c78cb498
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/t16.bmp differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/t18.bmp b/radio/sdcard/horus/THEMES/Flexi/t18.bmp
new file mode 100755
index 000000000..c1220ca1b
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/t18.bmp differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/thumb.bmp b/radio/sdcard/horus/THEMES/Flexi/thumb.bmp
new file mode 100644
index 000000000..c0494a694
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/thumb.bmp differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/topleft.png b/radio/sdcard/horus/THEMES/Flexi/topleft.png
new file mode 100644
index 000000000..603bfe1cf
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/topleft.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/topmenu_opentx.bmp b/radio/sdcard/horus/THEMES/Flexi/topmenu_opentx.bmp
new file mode 100644
index 000000000..cbc7f8149
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/topmenu_opentx.bmp differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/trackp_background.png b/radio/sdcard/horus/THEMES/Flexi/trackp_background.png
new file mode 100644
index 000000000..5beada59e
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/trackp_background.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/tx16s.bmp b/radio/sdcard/horus/THEMES/Flexi/tx16s.bmp
new file mode 100644
index 000000000..bb44eda41
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/tx16s.bmp differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/wizard/background.png b/radio/sdcard/horus/THEMES/Flexi/wizard/background.png
new file mode 100644
index 000000000..6b31b2914
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/wizard/background.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/wizard/itembg.png b/radio/sdcard/horus/THEMES/Flexi/wizard/itembg.png
new file mode 100644
index 000000000..b899446b2
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/wizard/itembg.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/wizard/pgdn.png b/radio/sdcard/horus/THEMES/Flexi/wizard/pgdn.png
new file mode 100644
index 000000000..6a1377620
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/wizard/pgdn.png differ
diff --git a/radio/sdcard/horus/THEMES/Flexi/wizard/pgup.png b/radio/sdcard/horus/THEMES/Flexi/wizard/pgup.png
new file mode 100644
index 000000000..06fab5cac
Binary files /dev/null and b/radio/sdcard/horus/THEMES/Flexi/wizard/pgup.png differ
diff --git a/radio/sdcard/horus/WIDGETS/Ghost/img/background.png b/radio/sdcard/horus/WIDGETS/Ghost/img/background.png
new file mode 100644
index 000000000..887c022fa
Binary files /dev/null and b/radio/sdcard/horus/WIDGETS/Ghost/img/background.png differ
diff --git a/radio/sdcard/horus/WIDGETS/Ghost/img/green.png b/radio/sdcard/horus/WIDGETS/Ghost/img/green.png
new file mode 100644
index 000000000..27c3a85cc
Binary files /dev/null and b/radio/sdcard/horus/WIDGETS/Ghost/img/green.png differ
diff --git a/radio/sdcard/horus/WIDGETS/Ghost/img/orange.png b/radio/sdcard/horus/WIDGETS/Ghost/img/orange.png
new file mode 100644
index 000000000..6f926c44b
Binary files /dev/null and b/radio/sdcard/horus/WIDGETS/Ghost/img/orange.png differ
diff --git a/radio/sdcard/horus/WIDGETS/Ghost/img/red.png b/radio/sdcard/horus/WIDGETS/Ghost/img/red.png
new file mode 100644
index 000000000..86b8da84f
Binary files /dev/null and b/radio/sdcard/horus/WIDGETS/Ghost/img/red.png differ
diff --git a/radio/sdcard/horus/WIDGETS/Ghost/main.lua b/radio/sdcard/horus/WIDGETS/Ghost/main.lua
new file mode 100644
index 000000000..1e1c5c06d
--- /dev/null
+++ b/radio/sdcard/horus/WIDGETS/Ghost/main.lua
@@ -0,0 +1,100 @@
+---- #########################################################################
+---- # #
+---- # Copyright (C) OpenTX #
+-----# #
+---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
+---- # #
+---- # This program is free software; you can redistribute it and/or modify #
+---- # it under the terms of the GNU General Public License version 2 as #
+---- # published by the Free Software Foundation. #
+---- # #
+---- # This program is distributed in the hope that it will be useful #
+---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
+---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
+---- # GNU General Public License for more details. #
+---- # #
+---- #########################################################################
+
+local backgroundBitmap
+local orangeLed
+local greenLed
+local offsetX
+local offsetY
+local sensors = {}
+
+local options = {
+ { "VTX", BOOL, 0 },
+}
+
+local function getValues(wgt)
+ if wgt.options.VTX == 0 then
+ sensors[1] = string.format("%s", getValue("RFMD"))
+ sensors[2] = string.format("%d Hz", getValue("FRat"))
+ sensors[3] = string.format("%d %%", getValue("RQly"))
+ if (getValue("TPWR") == 0) then
+ sensors[4] = "Range"
+ else
+ sensors[4] = string.format("%d mW", getValue("TPWR"))
+ end
+ else
+ sensors[1] = string.format("%s", getValue("VBan"))
+ sensors[2] = string.format("%dMHz", getValue("VFrq"))
+ sensors[3] = string.format("CH: %d", getValue("VChn"))
+ sensors[4] = string.format("%d mW", getValue("VPwr"))
+ end
+end
+
+local function create(zone, options)
+ local wgt = { zone=zone, options=options}
+ backgroundBitmap = Bitmap.open("/WIDGETS/Ghost/img/background.png")
+ orangeLed = Bitmap.open("/WIDGETS/Ghost/img/orange.png")
+ greenLed = Bitmap.open("/WIDGETS/Ghost/img/green.png")
+ offsetX = (wgt.zone.w - 178) / 2
+ offsetY = (wgt.zone.h - 148) / 2
+ return wgt
+end
+
+local function update(wgt, options)
+ wgt.options = options
+end
+
+local function background(wgt)
+end
+
+function refresh(wgt)
+ -- runs onty on large enough zone
+ if wgt.zone.w < 180 or wgt.zone.h < 145 then
+ return
+ end
+
+ if backgroundBitmap ~= nil then
+ lcd.drawBitmap(backgroundBitmap, wgt.zone.x + offsetX, wgt.zone.y + offsetY)
+ end
+
+ if getRSSI() ~= 0 then
+ if getValue("RFMD") == "Pure" then
+ if orangeLed ~= nil then
+ lcd.drawBitmap(orangeLed, wgt.zone.x + offsetX + 143, wgt.zone.y + offsetY)
+ end
+ elseif greenLed ~= nil then
+ lcd.drawBitmap(greenLed, wgt.zone.x + offsetX + 143, wgt.zone.y + offsetY)
+ end
+
+ getValues(wgt)
+
+ -- RF Mode/Band
+ lcd.drawText(wgt.zone.x + offsetX + 75, wgt.zone.y + offsetY + 2, sensors[1], CENTER + DBLSIZE)
+
+ -- Frame rate / Frequency
+ lcd.drawText(wgt.zone.x + offsetX + 85, wgt.zone.y + offsetY + 35, sensors[2], CENTER + DBLSIZE)
+
+ -- RSSI / Channel
+ lcd.drawText(wgt.zone.x + offsetX + 85, wgt.zone.y + offsetY + 70, sensors[3], CENTER + DBLSIZE)
+
+ -- Transmit power
+ lcd.drawText(wgt.zone.x + offsetX + 85, wgt.zone.y + offsetY + 105, sensors[4], CENTER + DBLSIZE)
+ end
+
+end
+
+return { name="Ghost", options=options, create=create, update=update, refresh=refresh, background=background }
\ No newline at end of file
diff --git a/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/FrSky RB30_RB40.lua b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/FrSky RB30_RB40.lua
new file mode 100644
index 000000000..213faa6cf
--- /dev/null
+++ b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/FrSky RB30_RB40.lua
@@ -0,0 +1,464 @@
+--- - #########################################################################
+---- # #
+---- # Copyright (C) OpenTX #
+----- # #
+---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
+---- # #
+---- # This program is free software; you can redistribute it and/or modify #
+---- # it under the terms of the GNU General Public License version 2 as #
+---- # published by the Free Software Foundation. #
+---- # #
+---- # This program is distributed in the hope that it will be useful #
+---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
+---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
+---- # GNU General Public License for more details. #
+---- # #
+---- #########################################################################
+
+local version = "v1.01"
+
+local VALUE = 0
+local COMBO = 1
+
+local edit = false
+local page = 1
+local current = 1
+local refreshState = 0
+local refreshIndex = 0
+local pageOffset = 0
+local pages = {}
+local fields = {}
+local modifications = {}
+local margin = 1
+local spacing = 8
+local numberPerPage = 7
+
+local configFields = {
+ { "Self_stable mode", COMBO, 0x80, nil, { "disable", "enable"} },
+ { "Sbus out", COMBO, 0x81, nil, { "disable", "enable"} },
+ { "VOut1(V)", VALUE, 0xB2, nil, 50, 84},
+ { "VOut2(V)", VALUE, 0xB3, nil, 50, 84},
+}
+
+
+local failsafeFields = {
+ { "CH1 failsafe", VALUE, 0x82, 150, 80, 220},
+ { "CH2 failsafe", VALUE, 0x82, 150, 80, 220},
+ { "CH3 failsafe", VALUE, 0x83, 150, 80, 220},
+ { "CH4 failsafe", VALUE, 0x83, 150, 80, 220},
+ { "CH5 failsafe", VALUE, 0x84, 150, 80, 220},
+ { "CH6 failsafe", VALUE, 0x84, 150, 80, 220},
+ { "CH7 failsafe", VALUE, 0x85, 150, 80, 220},
+ { "CH8 failsafe", VALUE, 0x85, 150, 80, 220},
+ { "CH9 failsafe", VALUE, 0x86, 150, 80, 220},
+ { "CH10 failsafe", VALUE, 0x86, 150, 80, 220},
+ { "CH11 failsafe", VALUE, 0x87, 150, 80, 220},
+ { "CH12 failsafe", VALUE, 0x87, 150, 80, 220},
+ { "CH13 failsafe", VALUE, 0x88, 150, 80, 220},
+ { "CH14 failsafe", VALUE, 0x88, 150, 80, 220},
+ { "CH15 failsafe", VALUE, 0x89, 150, 80, 220},
+ { "CH16 failsafe", VALUE, 0x89, 150, 80, 220},
+ { "CH17 failsafe", VALUE, 0x8A, 150, 80, 220},
+ { "CH18 failsafe", VALUE, 0x8A, 150, 80, 220},
+ { "CH19 failsafe", VALUE, 0x8B, 150, 80, 220},
+ { "CH20 failsafe", VALUE, 0x8B, 150, 80, 220},
+ { "CH21 failsafe", VALUE, 0x8C, 150, 80, 220},
+ { "CH22 failsafe", VALUE, 0x8C, 150, 80, 220},
+ { "CH23 failsafe", VALUE, 0x8D, 150, 80, 220},
+ { "CH24 failsafe", VALUE, 0x8D, 150, 80, 220},
+}
+
+local rx1PinMapFields = {
+ { "CH1 RX1 map", VALUE, 0x8E, 1, 0, 16},
+ { "CH2 RX1 map", VALUE, 0x8E, 2, 0, 16},
+ { "CH3 RX1 map", VALUE, 0x8F, 3, 0, 16},
+ { "CH4 RX1 map", VALUE, 0x8F, 4, 0, 16},
+ { "CH5 RX1 map", VALUE, 0x90, 5, 0, 16},
+ { "CH6 RX1 map", VALUE, 0x90, 6, 0, 16},
+ { "CH7 RX1 map", VALUE, 0x91, 7, 0, 16},
+ { "CH8 RX1 map", VALUE, 0x91, 8, 0, 16},
+ { "CH9 RX1 map", VALUE, 0x92, 9, 0, 16},
+ { "CH10 RX1 map", VALUE, 0x92, 10, 0, 16},
+ { "CH11 RX1 map", VALUE, 0x93, 11, 0, 16},
+ { "CH12 RX1 map", VALUE, 0x93, 12, 0, 16},
+ { "CH13 RX1 map", VALUE, 0x94, 13, 0, 16},
+ { "CH14 RX1 map", VALUE, 0x94, 14, 0, 16},
+ { "CH15 RX1 map", VALUE, 0x95, 15, 0, 16},
+ { "CH16 RX1 map", VALUE, 0x95, 16, 0, 16},
+ { "CH17 RX1 map", VALUE, 0x96, 1, 0, 16},
+ { "CH18 RX1 map", VALUE, 0x96, 2, 0, 16},
+ { "CH19 RX1 map", VALUE, 0x97, 3, 0, 16},
+ { "CH20 RX1 map", VALUE, 0x97, 4, 0, 16},
+ { "CH21 RX1 map", VALUE, 0x98, 5, 0, 16},
+ { "CH22 RX1 map", VALUE, 0x98, 6, 0, 16},
+ { "CH23 RX1 map", VALUE, 0x99, 7, 0, 16},
+ { "CH24 RX1 map", VALUE, 0x99, 8, 0, 16},
+}
+
+local rx2PinMapFields = {
+ { "CH1 RX2 map", VALUE, 0x9A, 1, 0, 16},
+ { "CH2 RX2 map", VALUE, 0x9A, 2, 0, 16},
+ { "CH3 RX2 map", VALUE, 0x9B, 3, 0, 16},
+ { "CH4 RX2 map", VALUE, 0x9B, 4, 0, 16},
+ { "CH5 RX2 map", VALUE, 0x9C, 5, 0, 16},
+ { "CH6 RX2 map", VALUE, 0x9C, 6, 0, 16},
+ { "CH7 RX2 map", VALUE, 0x9D, 7, 0, 16},
+ { "CH8 RX2 map", VALUE, 0x9D, 8, 0, 16},
+ { "CH9 RX2 map", VALUE, 0x9E, 9, 0, 16},
+ { "CH10 RX2 map", VALUE, 0x9E, 10, 0, 16},
+ { "CH11 RX2 map", VALUE, 0x9F, 11, 0, 16},
+ { "CH12 RX2 map", VALUE, 0x9F, 12, 0, 16},
+ { "CH13 RX2 map", VALUE, 0xA0, 13, 0, 16},
+ { "CH14 RX2 map", VALUE, 0xA0, 14, 0, 16},
+ { "CH15 RX2 map", VALUE, 0xA1, 15, 0, 16},
+ { "CH16 RX2 map", VALUE, 0xA0, 16, 0, 16},
+ { "CH17 RX2 map", VALUE, 0xA2, 1, 0, 16},
+ { "CH18 RX2 map", VALUE, 0xA2, 2, 0, 16},
+ { "CH19 RX2 map", VALUE, 0xA3, 3, 0, 16},
+ { "CH20 RX2 map", VALUE, 0xA3, 4, 0, 16},
+ { "CH21 RX2 map", VALUE, 0xA4, 5, 0, 16},
+ { "CH22 RX2 map", VALUE, 0xA4, 6, 0, 16},
+ { "CH23 RX2 map", VALUE, 0xA5, 7, 0, 16},
+ { "CH24 RX2 map", VALUE, 0xA5, 8, 0, 16},
+}
+
+local rx3PinMapFields = {
+ { "CH1 RX3 map", VALUE, 0xA6, 1, 0, 16},
+ { "CH2 RX3 map", VALUE, 0xA6, 2, 0, 16},
+ { "CH3 RX3 map", VALUE, 0xA7, 3, 0, 16},
+ { "CH4 RX3 map", VALUE, 0xA7, 4, 0, 16},
+ { "CH5 RX3 map", VALUE, 0xA8, 5, 0, 16},
+ { "CH6 RX3 map", VALUE, 0xA8, 6, 0, 16},
+ { "CH7 RX3 map", VALUE, 0xA9, 7, 0, 16},
+ { "CH8 RX3 map", VALUE, 0xA9, 8, 0, 16},
+ { "CH9 RX3 map", VALUE, 0xAA, 9, 0, 16},
+ { "CH10 RX3 map", VALUE, 0xAA, 10, 0, 16},
+ { "CH11 RX3 map", VALUE, 0xAB, 11, 0, 16},
+ { "CH12 RX3 map", VALUE, 0xAB, 12, 0, 16},
+ { "CH13 RX3 map", VALUE, 0xAC, 13, 0, 16},
+ { "CH14 RX3 map", VALUE, 0xAC, 14, 0, 16},
+ { "CH15 RX3 map", VALUE, 0xAD, 15, 0, 16},
+ { "CH16 RX3 map", VALUE, 0xAD, 16, 0, 16},
+ { "CH17 RX3 map", VALUE, 0xAE, 1, 0, 16},
+ { "CH18 RX3 map", VALUE, 0xAE, 2, 0, 16},
+ { "CH19 RX3 map", VALUE, 0xAF, 3, 0, 16},
+ { "CH20 RX3 map", VALUE, 0xAF, 4, 0, 16},
+ { "CH21 RX3 map", VALUE, 0xB0, 5, 0, 16},
+ { "CH22 RX3 map", VALUE, 0xB0, 6, 0, 16},
+ { "CH23 RX3 map", VALUE, 0xB1, 7, 0, 16},
+ { "CH24 RX3 map", VALUE, 0xB1, 8, 0, 16},
+}
+
+
+
+
+local function drawScreenTitle(title, page, pages)
+ if math.fmod(math.floor(getTime() / 100), 10) == 0 then
+ title = version
+ end
+ if LCD_W == 480 then
+ lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR)
+ lcd.drawText(1, 5, title, MENU_TITLE_COLOR)
+ lcd.drawText(LCD_W - 40, 5, page .. "/" .. pages, MENU_TITLE_COLOR)
+ else
+ lcd.drawScreenTitle(title, page, pages)
+ end
+end
+
+-- Change display attribute to current field
+local function addField(step)
+ local field = fields[current]
+ local min, max
+ if field[2] == VALUE then
+ min = field[5]
+ max = field[6]
+ elseif field[2] == COMBO then
+ min = 0
+ max = #(field[5]) - 1
+ end
+ if page == 2 and step < 0 and field[4] == min then
+ field[4] = 0
+ elseif page == 2 and step > 0 and field[4] == 0 then
+ field[4] = min
+ else
+ if (step < 0 and field[4] > min) or (step > 0 and field[4] < max) then
+ field[4] = field[4] + step
+ end
+ end
+end
+
+-- Select the next or previous page
+local function selectPage(step)
+ local pagesNum = #pages
+ if configFields[1][4] == 1 then
+ pagesNum = 1
+ elseif configFields[2][4] == 1 then
+ pagesNum = pagesNum - 1
+ end
+ page = 1 + ((page + step - 1 + pagesNum) % pagesNum)
+ refreshIndex = 0
+ pageOffset = 0
+end
+
+-- Select the next or previous editable field
+local function selectField(step)
+ current = 1 + ((current + step - 1 + #fields) % #fields)
+ if current > numberPerPage + pageOffset then
+ pageOffset = current - numberPerPage
+ elseif current <= pageOffset then
+ pageOffset = current - 1
+ end
+end
+
+local function drawProgressBar()
+ if LCD_W == 480 then
+ local width = (300 * refreshIndex) / #fields
+ lcd.drawRectangle(100, 10, 300, 6)
+ lcd.drawFilledRectangle(102, 12, width, 2)
+ else
+ local width = (60 * refreshIndex) / #fields
+ lcd.drawRectangle(45, 1, 60, 6)
+ lcd.drawFilledRectangle(47, 3, width, 2)
+ end
+end
+
+-- Redraw the current page
+local function redrawFieldPage()
+ lcd.clear()
+
+ local pagesNum = #pages
+ if configFields[1][4] == 1 then
+ pagesNum = 1
+ elseif configFields[2][4] == 1 then
+ pagesNum = pagesNum - 1
+ end
+ drawScreenTitle("RB30/RB40", page, pagesNum)
+
+ if refreshIndex < #fields then
+ drawProgressBar()
+ end
+
+ for index = 1, numberPerPage, 1 do
+ local field = fields[pageOffset + index]
+ if field == nil then
+ break
+ end
+
+ local attr = current == (pageOffset + index) and ((edit == true and BLINK or 0) + INVERS) or 0
+
+ lcd.drawText(1, margin + spacing * index, field[1], attr)
+
+ if field[4] == nil then
+ lcd.drawText(LCD_W, margin + spacing * index, "---", RIGHT + attr)
+ else
+ if field[2] == VALUE then
+ if page == 2 then
+ if field[4] == 0 then
+ lcd.drawText(LCD_W, margin + spacing * index, "No pulse", RIGHT + attr)
+ else
+ lcd.drawNumber(LCD_W, margin + spacing * index, field[4] * 10, RIGHT + attr)
+ end
+ else
+ if field[4] == 0 then
+ lcd.drawText(LCD_W, margin + spacing * index, "No map", RIGHT + attr)
+ else
+ if field[3] == 0xB2 or field[3] == 0xB3 then
+ lcd.drawNumber(LCD_W, margin + spacing * index, field[4] , attr + RIGHT + PREC1)
+ else
+ lcd.drawNumber(LCD_W, margin + spacing * index, field[4], RIGHT + attr)
+ end
+ end
+ end
+ elseif field[2] == COMBO then
+ if field[4] >= 0 and field[4] < #(field[5]) then
+ lcd.drawText(LCD_W, margin + spacing * index, field[5][field[4] + 1], RIGHT + attr)
+ end
+ end
+ end
+ end
+end
+
+local function telemetryIdle(field)
+ return sportTelemetryPush(0x1C, 0x21, 0x0b80, field)
+end
+
+local function telemetryUnIdle(field)
+ return sportTelemetryPush(0x1C, 0x20, 0x0b80, field)
+end
+
+local function telemetryRead(field)
+ return sportTelemetryPush(0x1C, 0x30, 0x0b80, field)
+end
+
+local function telemetryWrite(field, value)
+ return sportTelemetryPush(0x1C, 0x31, 0x0b80, field + value * 256)
+end
+
+local telemetryPopTimeout = 0
+local function refreshNext()
+ if refreshState == 0 then
+ if #modifications > 0 then
+ telemetryWrite(modifications[1][1], modifications[1][2])
+ modifications[1] = nil
+ refreshIndex = 0
+ refreshState = 0
+ elseif refreshIndex < #fields then
+ local field = fields[refreshIndex + 1]
+ if page > 1 then
+ field = fields[refreshIndex + 2]
+ end
+ if telemetryRead(field[3]) == true then
+ refreshState = 1
+ telemetryPopTimeout = getTime() + 100 -- normal delay is 500ms
+ end
+ end
+ elseif refreshState == 1 then
+ local physicalId, primId, dataId, value = sportTelemetryPop()
+ if primId == 0x32 and (dataId >= 0x0b80 or dataId <= 0x0b8f) then
+ local fieldId = value % 256
+ local field = fields[refreshIndex + 1]
+ if fieldId == field[3] then
+ value = math.floor(value / 256)
+ if field[2] == COMBO then
+ fields[refreshIndex + 1][4] = value
+ else
+ fields[refreshIndex + 1][4] = value % 256
+ if page > 1 then
+ value = math.floor(value / 256)
+ fields[refreshIndex + 2][4] = value
+ end
+ end
+ if page > 1 then
+ refreshIndex = refreshIndex + 2
+ else
+ refreshIndex = refreshIndex + 1
+ end
+ refreshState = 0
+ end
+ elseif getTime() > telemetryPopTimeout then
+ fields[refreshIndex + 1][4] = nil
+ if page > 1 then
+ fields[refreshIndex + 2][4] = nil
+ refreshIndex = refreshIndex + 2
+ else
+ refreshIndex = refreshIndex + 1
+ end
+ refreshState = 0
+ end
+ end
+end
+
+local function updateField(field)
+ local value = field[4]
+ if field[2] == COMBO and #field == 6 then
+ value = field[6][1 + value]
+ elseif field[2] == VALUE and #field == 8 then
+ value = value + field[8] - field[5]
+ end
+
+ if page > 1 then
+ if current % 2 == 1 then
+ value = value + fields[current + 1][4] * 256
+ elseif current % 2 == 0 then
+ value = fields[current - 1][4] + value * 256
+ end
+ end
+ modifications[#modifications + 1] = { field[3], value }
+end
+
+-- Main
+local function runFieldsPage(event)
+ if event == EVT_VIRTUAL_EXIT then -- exit script
+ telemetryUnIdle(0x80)
+ return 2
+ elseif event == EVT_VIRTUAL_ENTER then -- toggle editing/selecting current field
+ if fields[current][4] ~= nil then
+ edit = not edit
+ if edit == false then
+ updateField(fields[current])
+ end
+ end
+ elseif edit then
+ if event == EVT_VIRTUAL_INC or event == EVT_VIRTUAL_INC_REPT then
+ addField(1)
+ elseif event == EVT_VIRTUAL_DEC or event == EVT_VIRTUAL_DEC_REPT then
+ addField(-1)
+ end
+ else
+ if event == EVT_VIRTUAL_NEXT then
+ selectField(1)
+ elseif event == EVT_VIRTUAL_PREV then
+ selectField(-1)
+ end
+ end
+ redrawFieldPage()
+ return 0
+end
+
+local function runConfigPage(event)
+ fields = configFields
+ return runFieldsPage(event)
+end
+
+local function runFailsafePage(event)
+ fields = failsafeFields
+ return runFieldsPage(event)
+end
+
+local function runRx1PinMapPage(event)
+ fields = rx1PinMapFields
+ return runFieldsPage(event)
+end
+
+local function runRx2PinMapPage(event)
+ fields = rx2PinMapFields
+ return runFieldsPage(event)
+end
+
+local function runRx3PinMapPage(event)
+ fields = rx3PinMapFields
+ return runFieldsPage(event)
+end
+
+-- Init
+local function init()
+ current, edit, refreshState, refreshIndex = 1, false, 0, 0
+ if LCD_W == 480 then
+ margin = 10
+ spacing = 20
+ numberPerPage = 12
+ end
+ pages = {
+ runConfigPage,
+ runFailsafePage,
+ runRx1PinMapPage,
+ runRx2PinMapPage,
+ runRx3PinMapPage
+ }
+ telemetryIdle(0x80)
+end
+
+-- Main
+local function run(event)
+ if event == nil then
+ error("Cannot be run as a model script!")
+ return 2
+ elseif event == EVT_VIRTUAL_NEXT_PAGE then
+ if edit == false then
+ selectPage(1)
+ end
+ elseif event == EVT_VIRTUAL_PREV_PAGE then
+ if edit == false then
+ killEvents(event)
+ selectPage(-1)
+ end
+ end
+
+ local result = pages[page](event)
+ refreshNext()
+
+ return result
+end
+
+return { init = init, run = run }
+
diff --git a/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/MultiChan.txt b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/MultiChan.txt
index bf61d8ca6..b03b2c860 100644
--- a/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/MultiChan.txt
+++ b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/MultiChan.txt
@@ -1,3 +1,47 @@
+24,0,Assan,Std,0,CH5,CH6,CH7,CH8
+14,0,Bayang,Std,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,n-a,n-a,AnAux1,AnAux2
+14,1,Bayang,H8S3D,1,Flip,RTH,Pict,Video,HLess,Invert,Rates
+14,2,Bayang,X16_AH,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf
+14,3,Bayang,IRDRONE,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf,EmStop
+14,4,Bayang,DHD_D4,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf,EmStop
+14,5,Bayang,QX100,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf,EmStop
+59,0,BayangRX,RX,1,AnAux1,AnAux2,Flip,RTH,Pict,Video
+41,0,Bugs,3-6-8,0,Arm,Angle,Flip,Pict,Video,LED
+42,0,BugsMini,Mini,0,Arm,Angle,Flip,Pict,Video,LED
+42,1,BugsMini,3H,0,Arm,Angle,Flip,Pict,Video,LED,AltHol
+34,0,Cabell,V3,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
+34,1,Cabell,V3Telem,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
+13,0,CG023,Std,1,Flip,Light,Pict,Video,HLess
+13,1,CG023,YD829,1,Flip,n-a,Pict,Video,HLess
+37,0,Corona,COR_V1,0,CH5,CH6,CH7,CH8
+37,1,Corona,COR_V2,0,CH5,CH6,CH7,CH8
+37,2,Corona,FD_V3,0,CH5,CH6,CH7,CH8
+12,0,CX10,Green,1,Flip,Rate
+12,1,CX10,Blue,1,Flip,Rate,Pict,Video
+12,2,CX10,DM007,1,Flip,Mode,Pict,Video,HLess
+12,4,CX10,JC3015_1,1,Flip,Mode,Pict,Video
+12,5,CX10,JC3015_2,1,Flip,Mode,LED,DFlip
+12,6,CX10,MK33041,1,Flip,Mode,Pict,Video,HLess,RTH
+7,0,Devo,8CH,0,CH5,CH6,CH7,CH8
+7,1,Devo,10CH,0,CH5,CH6,CH7,CH8,CH9,CH10
+7,2,Devo,12CH,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
+7,3,Devo,6CH,0,CH5,CH6
+7,4,Devo,7CH,0,CH5,CH6,CH7
+33,0,DM022,Std,1,Flip,LED,Cam1,Cam2,HLess,RTH,RLow
+6,0,DSM,2_22,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
+6,1,DSM,2_11,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
+6,2,DSM,X_22,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
+6,3,DSM,X_11,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
+6,4,DSM,AUTO,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
+70,0,DSM_RX,RX,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
+45,0,E01X,E012,1,n-a,Flip,n-a,HLess,RTH
+45,1,E01X,E015,1,Arm,Flip,LED,HLess,RTH
+45,2,E01X,E016H,1,Stop,Flip,n-a,HLess,RTH
+16,0,ESKY,Std,0,Gyro,Pitch
+16,1,ESKY,ET4,0,Gyro,Pitch
+35,0,ESKY150,4CH,0
+35,1,ESKY150,7CH,0,FMode,Aux6,Aux7
+69,0,ESKY150V2,Std,0,CH5_RA,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
1,0,Flysky,Flysky,0,CH5,CH6,CH7,CH8
1,1,Flysky,V9x9,1,Flip,Light,Pict,Video
1,2,Flysky,V6x6,1,Flip,Light,Pict,Video,HLess,RTH,XCAL,YCAL
@@ -7,15 +51,11 @@
28,1,Flysky_AFHDS2A,PPM_IBUS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
28,2,Flysky_AFHDS2A,PWM_SBUS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
28,3,Flysky_AFHDS2A,PPM_SBUS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
-53,0,Flyzone,FZ-410,0
-2,0,Hubsan,H107,1,Flip,Light,Pict,Video,HLess
-2,1,Hubsan,H301,0,RTH,Light,Stab,Video
-2,2,Hubsan,H501,0,RTH,Light,Pict,Video,HLess,GPS_H,ALT_H,Flip,FModes
-41,0,Bugs,3-6-8,0,Arm,Angle,Flip,Pict,Video,LED
-60,0,Pelikan,PRO_V4,0,CH5,CH6,CH7,CH8
-37,0,Corona,COR_V1,0,CH5,CH6,CH7,CH8
-37,1,Corona,COR_V2,0,CH5,CH6,CH7,CH8
-37,2,Corona,FD_V3,0,CH5,CH6,CH7,CH8
+28,4,Flysky_AFHDS2A,PWM_IB16,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
+28,5,Flysky_AFHDS2A,PPM_IB16,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
+56,0,Flysky2A_RX,RX,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
+53,0,Height,5ch,0,Gear
+53,1,Height,8ch,0,Gear,Gyro,Flap,Light
25,0,FrSkyV,V8,0,CH5,CH6,CH7,CH8
3,0,FrSkyD,D8,0,CH5,CH6,CH7,CH8
3,0,FrSkyD,D8Cloned,0,CH5,CH6,CH7,CH8
@@ -26,78 +66,50 @@
15,2,FrSkyX,D16_LBT,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
15,3,FrSkyX,D16_8CH_LBT,0,CH5,CH6,CH7,CH8
15,4,FrSkyX,D16Cloned,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
+15,5,FrSkyX,D16Cloned_8CH,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
64,0,FrSkyX2,D16_FCC,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
64,1,FrSkyX2,D16_8CH_FCC,0,CH5,CH6,CH7,CH8
64,2,FrSkyX2,D16_LBT,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
64,3,FrSkyX2,D16_8CH_LBT,1,CH5,CH6,CH7,CH8
64,4,FrSkyX2,D16Cloned,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
+64,5,FrSkyX2,D16Cloned_8CH,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
+65,0,FrSkyR9,R9_915,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
+65,1,FrSkyR9,R9_868,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
+65,2,FrSkyR9,R9_915_8CH,0,CH5,CH6,CH7,CH8
+65,3,FrSkyR9,R9_968_8CH,0,CH5,CH6,CH7,CH8
55,0,FrSkyRX,RX,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
55,1,FrSkyRX,CloneTX,0
-39,0,Hitec,Opt_Fw,0,CH5,CH6,CH7,CH8,CH9
-39,1,Hitec,Opt_Hub,0,CH5,CH6,CH7,CH8,CH9
-39,2,Hitec,Minima,0,CH5,CH6,CH7,CH8,CH9
-57,0,HoTT,Std,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
-21,0,SFHSS,Std,0,CH5,CH6,CH7,CH8
-68,0,Skyartec,Std,0,CH5,CH6,CH7
-7,0,Devo,8CH,0,CH5,CH6,CH7,CH8
-7,1,Devo,10CH,0,CH5,CH6,CH7,CH8,CH9,CH10
-7,2,Devo,12CH,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
-7,3,Devo,6CH,0,CH5,CH6
-7,4,Devo,7CH,0,CH5,CH6,CH7
-30,0,WK2x01,WK2801,0,CH5,CH6,CH7,CH8
-30,1,WK2x01,WK2401,0
-30,2,WK2x01,W6_5_1,0,Gear,Dis,Gyro
-30,3,WK2x01,W6_6_1,0,Gear,Col,Gyro
-30,4,WK2x01,W6HEL,0,Gear,Col,Gyro
-30,5,WK2x01,W6HEL_I,0,Gear,Col,Gyro
-6,0,DSM,2_22,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
-6,1,DSM,2_11,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
-6,2,DSM,X_22,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
-6,3,DSM,X_11,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
-22,0,J6Pro,Std,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
-22,0,WFLY,WFR0xS,0,CH5,CH6,CH7,CH8,CH9
-24,0,Assan,Std,0,CH5,CH6,CH7,CH8
-14,0,Bayang,Std,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,n-a,n-a,AnAux1,AnAux2
-14,1,Bayang,H8S3D,1,Flip,RTH,Pict,Video,HLess,Invert,Rates
-14,2,Bayang,X16_AH,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf
-14,3,Bayang,IRDRONE,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf,EmStop
-14,4,Bayang,DHD_D4,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf,EmStop
-59,0,BayangRX,RX,1,AnAux1,AnAux2,Flip,RTH,Pict,Video
-42,0,BugsMini,Mini,0,Arm,Angle,Flip,Pict,Video,LED
-42,1,BugsMini,3H,0,Arm,Angle,Flip,Pict,Video,LED,AltHol
-34,0,Cabell,V3,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
-34,1,Cabell,V3Telem,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
-13,0,CG023,Std,1,Flip,Light,Pict,Video,HLess
-13,1,CG023,YD829,1,Flip,n-a,Pict,Video,HLess
-12,0,CX10,Green,1,Flip,Rate
-12,1,CX10,Blue,1,Flip,Rate,Pict,Video
-12,2,CX10,DM007,1,Flip,Mode,Pict,Video,HLess
-12,4,CX10,JC3015_1,1,Flip,Mode,Pict,Video
-12,5,CX10,JC3015_2,1,Flip,Mode,LED,DFlip
-12,6,CX10,MK33041,1,Flip,Mode,Pict,Video,HLess,RTH
-33,0,DM022,Std,1,Flip,LED,Cam1,Cam2,HLess,RTH,RLow
-45,0,E01X,E012,1,n-a,Flip,n-a,HLess,RTH
-45,1,E01X,E015,1,Arm,Flip,LED,HLess,RTH
-45,2,E01X,E016H,1,Stop,Flip,n-a,HLess,RTH
-16,0,ESKY,Std,0,Gyro,Pitch
-16,1,ESKY,ET4,0,Gyro,Pitch
-35,0,ESKY150,4CH,0
-35,1,ESKY150,7CH,0,FMode,Aux6,Aux7
+58,0,FX816,P38,1
20,0,FY326,FY326,1,Flip,RTH,HLess,Expert,Calib
20,1,FY326,FY319,1,Flip,RTH,HLess,Expert,Calib
23,0,FY326,FY326,1,Flip,RTH,HLess,Expert
+47,0,GD00x,V1,1,Trim,LED,Rate
+47,1,GD00x,V2,1,Trim,LED,Rate
32,0,GW008,FY326,1,Flip
36,0,H8_3D,Std,1,Flip,Light,Pict,Video,RTH,FlMode,Cal1
36,1,H8_3D,H20H,1,Flip,Light,Pict,Video,Opt1,Opt2,Cal1,Cal2,Gimbal
36,2,H8_3D,H20,1,Flip,Light,Pict,Video,Opt1,Opt2,Cal1,Cal2,Gimbal
36,3,H8_3D,H30,1,Flip,Light,Pict,Video,Opt1,Opt2,Cal1,Cal2,Gimbal
4,0,Hisky,Std,0,Gear,Pitch,Gyro,CH8
-9,0,KN,WLToys,0,DRate,THold,IdleUp,Gyro,Ttrim,Atrim,Etrim
-9,1,KN,Feilun,0,DRate,THold,IdleUp,Gyro,Ttrim,Atrim,Etrim
+4,1,Hisky,HK310,0,Aux
+39,0,Hitec,Opt_Fw,0,CH5,CH6,CH7,CH8,CH9
+39,1,Hitec,Opt_Hub,0,CH5,CH6,CH7,CH8,CH9
+39,2,Hitec,Minima,0,CH5,CH6,CH7,CH8,CH9
26,0,Hontai,Std,1,Flip,LED,Pict,Video,HLess,RTH,Calib
26,1,Hontai,JJRCX1,1,Flip,Arm,Pict,Video,HLess,RTH,Calib
26,2,Hontai,X5C1,1,Flip,Arm,Pict,Video,HLess,RTH,Calib
26,3,Hontai,FQ777_951,1,Flip,Arm,Pict,Video,HLess,RTH,Calib
+57,0,HoTT,Sync,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
+57,1,HoTT,No_Sync,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
+2,0,Hubsan,H107,1,Flip,Light,Pict,Video,HLess
+2,1,Hubsan,H301,0,RTH,Light,Stab,Video
+2,2,Hubsan,H501,0,RTH,Light,Pict,Video,HLess,GPS_H,ALT_H,Flip,FModes
+22,0,J6Pro,Std,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
+71,0,JJRC345,Std,1,Flip,HLess,RTH
+49,0,KF606,Std,1,Trim
+9,0,KN,WLToys,0,DRate,THold,IdleUp,Gyro,Ttrim,Atrim,Etrim
+9,1,KN,Feilun,0,DRate,THold,IdleUp,Gyro,Ttrim,Atrim,Etrim
+73,0,Kyosho,Std,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
18,0,MJXQ,WHL08,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
18,1,MJXQ,X600,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
18,2,MJXQ,X800,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
@@ -111,6 +123,9 @@
17,3,MT99XX,LS,1,Flip,Invert,Pict,Video,HLess
17,4,MT99XX,FY805,1,Flip,n-a,n-a,n-a,HLess
44,0,NCC1701,Std,1,Warp
+77,0,OMP,M2,0,THold,IdleUp,6G_3D
+60,0,Pelikan,PRO_V4,0,CH5,CH6,CH7,CH8
+60,1,Pelikan,LITE_V4,0,CH5,CH6,CH7,CH8
51,0,Potensic,A20,1,TakLan,Emerg,Mode,HLess
66,0,Propel,74-Z,1,LEDs,RollCW,RolCCW,Fire,Weapon,Calib,AltHol,TakeOf,Land,Train
29,0,Q2x2,Q222,1,Flip,LED,Mod2,Mod1,HLess,RTH,XCal,YCal
@@ -120,8 +135,15 @@
31,1,Q303,C35,1,Arm,VTX,Pict,Video,n-a,RTH,Gimbal
31,2,Q303,CX10D,1,Arm,Flip
31,3,Q303,CX10WD,1,Arm,Flip
+72,0,Q90C,Std,0,FMode,VTX+
+74,0,RadioLink,Surface,0,CH5,CH6,CH7,CH8,FS_CH1,FS_CH2,FS_CH3,FS_CH4,FS_CH5,FS_CH6,FS_CH7,FS_CH8
+74,1,RadioLink,Air,0,CH5,CH6,CH7,CH8,FS_CH1,FS_CH2,FS_CH3,FS_CH4,FS_CH5,FS_CH6,FS_CH7,FS_CH8
+76,0,Realacc,R11,1,Flip,Light,Calib,HLess,RTH,UNK
50,0,Redpine,Fast,0,sCH5,sCH6,sCH7,sCH8,sCH9,sCH10,sCH11,sCH12,sCH13,sCH14,sCH15,sCH16
50,1,Redpine,Slow,0,sCH5,sCH6,sCH7,sCH8,sCH9,sCH10,sCH11,sCH12,sCH13,sCH14,sCH15,sCH16
+21,0,SFHSS,Std,0,CH5,CH6,CH7,CH8
+19,0,Shenqi,Cycle,1
+68,0,Skyartec,Std,0,CH5,CH6,CH7
11,0,SLT,V1,0,Gear,Pitch
11,1,SLT,V2,0,CH5,CH6,CH7,CH8
11,2,SLT,Q100,0,Rates,n-a,CH7,CH8,Mode,Flip,n-a,n-a,Calib
@@ -129,11 +151,21 @@
11,4,SLT,MR100,0,Rates,n-a,CH7,CH8,Mode,Flip,Video,Pict
10,0,Symax,Std,1,Flip,Rates,Pict,Video,HLess
10,1,Symax,X5C,1,Flip,Rates,Pict,Video,HLess
+61,0,Tiger,Std,1,Flip,Light
+43,0,Traxxas,6519,0
5,0,V2x2,Std,1,Flip,Light,Pict,Video,HLess,CalX,CalY
5,1,V2x2,JXD506,1,Flip,Light,Pict,Video,HLess,StaSto,Emerg,Cam_UD
-61,0,Tiger,Std,1,Flip,Light
-46,0,V911s,Std,1,Calib
-46,1,E119,Std,1,Calib
+48,0,V761,3CH,0,Gyro,Calib,Flip,RtnAct,Rtn
+48,1,V761,4CH,0,Gyro,Calib,Flip,RtnAct,Rtn
+46,0,V911s,V911s,1,Calib
+46,1,V911s,E119,1,Calib
+22,0,WFLY,WFR0xS,0,CH5,CH6,CH7,CH8,CH9
+30,0,WK2x01,WK2801,0,CH5,CH6,CH7,CH8
+30,1,WK2x01,WK2401,0
+30,2,WK2x01,W6_5_1,0,Gear,Dis,Gyro
+30,3,WK2x01,W6_6_1,0,Gear,Col,Gyro
+30,4,WK2x01,W6HEL,0,Gear,Col,Gyro
+30,5,WK2x01,W6HEL_I,0,Gear,Col,Gyro
62,0,XK,X450,1,FMode,TakeOf,Emerg,3D_6G,Pict,Video
62,1,XK,X420,1,FMode,TakeOf,Emerg,3D_6G,Pict,Video
8,0,YD717,Std,1,Flip,Light,Pict,Video,HLess
@@ -141,17 +173,4 @@
8,2,YD717,Simax4,1,Flip,Light,Pict,Video,HLess
8,3,YD717,XinXun,1,Flip,Light,Pict,Video,HLess
8,4,YD717,NiHui,1,Flip,Light,Pict,Video,HLess
-65,0,FrSkyR9,R9_915,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
-65,1,FrSkyR9,R9_868,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
-65,2,FrSkyR9,R9_915_8CH,0,CH5,CH6,CH7,CH8
-65,3,FrSkyR9,R9_968_8CH,0,CH5,CH6,CH7,CH8
-56,0,Flysky2A_RX,RX,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
-19,0,Shenqi,Cycle,1
-4,1,Hisky,HK310,0,Aux
-43,0,Traxxas,6519,0
52,0,ZSX,280,1,Light
-48,0,V761,Std,1,Gyro
-49,0,KF606,Std,1,Trim
-47,0,GD00x,V1,1,Trim,LED,Rate
-47,1,GD00x,V2,1,Trim,LED,Rate
-58,0,FX816,P38,1
diff --git a/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/MultiChannelsUpdater.lua b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/MultiChannelsUpdater.lua
index 42de75e4f..14902b782 100644
--- a/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/MultiChannelsUpdater.lua
+++ b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/MultiChannelsUpdater.lua
@@ -249,13 +249,13 @@ local function Multi_Init()
--Exceptions on first 4 channels...
local stick_names = { "Rud", "Ele", "Thr", "Ail" }
- if ( protocol == 4 and sub_protocol ==1 ) or protocol == 19 or protocol == 52 then -- Hisky/HK310, Shenqi, ZSX
+ if ( protocol == 4 and sub_protocol == 1 ) or protocol == 19 or protocol == 52 then -- Hisky/HK310, Shenqi, ZSX
stick_names[2] = "n-a"
stick_names[4] = "n-a"
elseif protocol == 43 then -- Traxxas
stick_names[2] = "Aux4"
stick_names[4] = "Aux3"
- elseif protocol == 48 then -- V761
+ elseif ( protocol == 48 and sub_protocol == 0 ) then -- V761 3CH
stick_names[4] = "n-a"
elseif protocol == 47 or protocol == 49 or protocol == 58 then -- GD00x, KF606, FX816
stick_names[1] = "n-a"
@@ -278,6 +278,15 @@ local function Multi_Init()
ch_order = math.floor(ch_order/4)
channel_names[bitand(ch_order,3)+1] = stick_names[1]
end
+
+ --Exceptions on first 4 channels...
+ if ( protocol == 73 or (protocol == 74 and sub_protocol == 0) ) then -- Kyosho or RadioLink Surface
+ channel_names[1] = "ST"
+ channel_names[2] = "THR"
+ channel_names[3] = "CH3"
+ channel_names[4] = "CH4"
+ end
+
--Check MultiChan.txt
local f = io.open("/SCRIPTS/TOOLS/MultiChan.txt", "r")
if f == nil then return end
diff --git a/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/crossfire.lua b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/crossfire.lua
index debf9056d..3e8a6930a 100644
--- a/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/crossfire.lua
+++ b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/crossfire.lua
@@ -30,6 +30,11 @@ local function run(event)
return 2
end
+ if crossfireTelemetryPush() == nil then
+ error("Crossfire not available!")
+ return 2
+ end
+
chdir("/SCRIPTS/TOOLS/CROSSFIRE")
return "crossfire.lua"
end
diff --git a/radio/sdcard/taranis-x7/SCRIPTS/WIZARD/delta.lua b/radio/sdcard/taranis-x7/SCRIPTS/WIZARD/delta.lua
index bcd9238f4..9cf7fdefd 100755
--- a/radio/sdcard/taranis-x7/SCRIPTS/WIZARD/delta.lua
+++ b/radio/sdcard/taranis-x7/SCRIPTS/WIZARD/delta.lua
@@ -52,10 +52,10 @@ end
local function fieldIncDec(event, value, max, force)
if edit or force==true then
- if event == EVT_VIRTUAL_PREV or event == EVT_VIRTUAL_PREV_REPT then
+ if event == EVT_VIRTUAL_INC then
value = (value + max)
dirty = true
- elseif event == EVT_VIRTUAL_NEXT or event == EVT_VIRTUAL_NEXT_REPT then
+ elseif event == EVT_VIRTUAL_DEC then
value = (value + max + 2)
dirty = true
end
@@ -93,11 +93,11 @@ local function navigate(event, fieldMax, prevPage, nextPage)
dirty = blinkChanged()
end
else
- if event == EVT_VIRTUAL_NEXT then
+ if event == EVT_VIRTUAL_NEXT_PAGE then
page = nextPage
field = 0
dirty = true
- elseif event == EVT_VIRTUAL_PREV then
+ elseif event == EVT_VIRTUAL_PREV_PAGE then
page = prevPage
field = 0
killEvents(event);
@@ -335,7 +335,7 @@ local function drawConfirmationMenu()
if rudderMode == 1 then
drawNextLine(x, y, "Rudder", rudCH1)
end
- lcd.drawText(48, LCD_H-8, "[Enter Long] to confirm", 0);
+ lcd.drawText(0, LCD_H-8, "[Enter Long] to confirm", 0);
lcd.drawFilledRectangle(0, LCD_H-9, LCD_W, 9, 0)
fieldsMax = 0
end
diff --git a/radio/sdcard/taranis-x7/SCRIPTS/WIZARD/multi.lua b/radio/sdcard/taranis-x7/SCRIPTS/WIZARD/multi.lua
index 321b7324f..fc65db204 100755
--- a/radio/sdcard/taranis-x7/SCRIPTS/WIZARD/multi.lua
+++ b/radio/sdcard/taranis-x7/SCRIPTS/WIZARD/multi.lua
@@ -99,11 +99,11 @@ local function navigate(event, fieldMax, prevPage, nextPage)
dirty = blinkChanged()
end
else
- if event == EVT_PAGE_BREAK or event == EVT_RIGHT_FIRST then
+ if event == EVT_VIRTUAL_NEXT_PAGE then
page = nextPage
field = 0
dirty = true
- elseif event == EVT_PAGE_LONG or event == EVT_LEFT_FIRST then
+ elseif event == EVT_VIRTUAL_PREV_PAGE then
page = prevPage
field = 0
killEvents(event);
@@ -171,6 +171,8 @@ local function init()
local ver, radio, maj, minor, rev = getVersion()
if string.match(radio, "x7") then
switches = {"SA", "SB", "SC", "SD", "SF", "SH"}
+ elseif string.match(radio, "tx12") then
+ switches = {"SA", "SB", "SC", "SD", "SE", "SF"}
else
switches = {"SA", "SB", "SC", "SD"}
end
diff --git a/radio/sdcard/taranis-x7/SCRIPTS/WIZARD/plane.lua b/radio/sdcard/taranis-x7/SCRIPTS/WIZARD/plane.lua
index 26282cdf7..d52c1f936 100755
--- a/radio/sdcard/taranis-x7/SCRIPTS/WIZARD/plane.lua
+++ b/radio/sdcard/taranis-x7/SCRIPTS/WIZARD/plane.lua
@@ -103,11 +103,11 @@ local function navigate(event, fieldMax, prevPage, nextPage)
dirty = blinkChanged()
end
else
- if event == EVT_PAGE_BREAK or event==EVT_RIGHT_BREAK then
+ if event == EVT_VIRTUAL_NEXT_PAGE then
page = nextPage
field = 0
dirty = true
- elseif event == EVT_PAGE_LONG or event==EVT_LEFT_BREAK then
+ elseif event == EVT_VIRTUAL_PREV_PAGE then
page = prevPage
field = 0
killEvents(event);
diff --git a/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/FrSky RB30_RB40.lua b/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/FrSky RB30_RB40.lua
new file mode 100644
index 000000000..213faa6cf
--- /dev/null
+++ b/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/FrSky RB30_RB40.lua
@@ -0,0 +1,464 @@
+--- - #########################################################################
+---- # #
+---- # Copyright (C) OpenTX #
+----- # #
+---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
+---- # #
+---- # This program is free software; you can redistribute it and/or modify #
+---- # it under the terms of the GNU General Public License version 2 as #
+---- # published by the Free Software Foundation. #
+---- # #
+---- # This program is distributed in the hope that it will be useful #
+---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
+---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
+---- # GNU General Public License for more details. #
+---- # #
+---- #########################################################################
+
+local version = "v1.01"
+
+local VALUE = 0
+local COMBO = 1
+
+local edit = false
+local page = 1
+local current = 1
+local refreshState = 0
+local refreshIndex = 0
+local pageOffset = 0
+local pages = {}
+local fields = {}
+local modifications = {}
+local margin = 1
+local spacing = 8
+local numberPerPage = 7
+
+local configFields = {
+ { "Self_stable mode", COMBO, 0x80, nil, { "disable", "enable"} },
+ { "Sbus out", COMBO, 0x81, nil, { "disable", "enable"} },
+ { "VOut1(V)", VALUE, 0xB2, nil, 50, 84},
+ { "VOut2(V)", VALUE, 0xB3, nil, 50, 84},
+}
+
+
+local failsafeFields = {
+ { "CH1 failsafe", VALUE, 0x82, 150, 80, 220},
+ { "CH2 failsafe", VALUE, 0x82, 150, 80, 220},
+ { "CH3 failsafe", VALUE, 0x83, 150, 80, 220},
+ { "CH4 failsafe", VALUE, 0x83, 150, 80, 220},
+ { "CH5 failsafe", VALUE, 0x84, 150, 80, 220},
+ { "CH6 failsafe", VALUE, 0x84, 150, 80, 220},
+ { "CH7 failsafe", VALUE, 0x85, 150, 80, 220},
+ { "CH8 failsafe", VALUE, 0x85, 150, 80, 220},
+ { "CH9 failsafe", VALUE, 0x86, 150, 80, 220},
+ { "CH10 failsafe", VALUE, 0x86, 150, 80, 220},
+ { "CH11 failsafe", VALUE, 0x87, 150, 80, 220},
+ { "CH12 failsafe", VALUE, 0x87, 150, 80, 220},
+ { "CH13 failsafe", VALUE, 0x88, 150, 80, 220},
+ { "CH14 failsafe", VALUE, 0x88, 150, 80, 220},
+ { "CH15 failsafe", VALUE, 0x89, 150, 80, 220},
+ { "CH16 failsafe", VALUE, 0x89, 150, 80, 220},
+ { "CH17 failsafe", VALUE, 0x8A, 150, 80, 220},
+ { "CH18 failsafe", VALUE, 0x8A, 150, 80, 220},
+ { "CH19 failsafe", VALUE, 0x8B, 150, 80, 220},
+ { "CH20 failsafe", VALUE, 0x8B, 150, 80, 220},
+ { "CH21 failsafe", VALUE, 0x8C, 150, 80, 220},
+ { "CH22 failsafe", VALUE, 0x8C, 150, 80, 220},
+ { "CH23 failsafe", VALUE, 0x8D, 150, 80, 220},
+ { "CH24 failsafe", VALUE, 0x8D, 150, 80, 220},
+}
+
+local rx1PinMapFields = {
+ { "CH1 RX1 map", VALUE, 0x8E, 1, 0, 16},
+ { "CH2 RX1 map", VALUE, 0x8E, 2, 0, 16},
+ { "CH3 RX1 map", VALUE, 0x8F, 3, 0, 16},
+ { "CH4 RX1 map", VALUE, 0x8F, 4, 0, 16},
+ { "CH5 RX1 map", VALUE, 0x90, 5, 0, 16},
+ { "CH6 RX1 map", VALUE, 0x90, 6, 0, 16},
+ { "CH7 RX1 map", VALUE, 0x91, 7, 0, 16},
+ { "CH8 RX1 map", VALUE, 0x91, 8, 0, 16},
+ { "CH9 RX1 map", VALUE, 0x92, 9, 0, 16},
+ { "CH10 RX1 map", VALUE, 0x92, 10, 0, 16},
+ { "CH11 RX1 map", VALUE, 0x93, 11, 0, 16},
+ { "CH12 RX1 map", VALUE, 0x93, 12, 0, 16},
+ { "CH13 RX1 map", VALUE, 0x94, 13, 0, 16},
+ { "CH14 RX1 map", VALUE, 0x94, 14, 0, 16},
+ { "CH15 RX1 map", VALUE, 0x95, 15, 0, 16},
+ { "CH16 RX1 map", VALUE, 0x95, 16, 0, 16},
+ { "CH17 RX1 map", VALUE, 0x96, 1, 0, 16},
+ { "CH18 RX1 map", VALUE, 0x96, 2, 0, 16},
+ { "CH19 RX1 map", VALUE, 0x97, 3, 0, 16},
+ { "CH20 RX1 map", VALUE, 0x97, 4, 0, 16},
+ { "CH21 RX1 map", VALUE, 0x98, 5, 0, 16},
+ { "CH22 RX1 map", VALUE, 0x98, 6, 0, 16},
+ { "CH23 RX1 map", VALUE, 0x99, 7, 0, 16},
+ { "CH24 RX1 map", VALUE, 0x99, 8, 0, 16},
+}
+
+local rx2PinMapFields = {
+ { "CH1 RX2 map", VALUE, 0x9A, 1, 0, 16},
+ { "CH2 RX2 map", VALUE, 0x9A, 2, 0, 16},
+ { "CH3 RX2 map", VALUE, 0x9B, 3, 0, 16},
+ { "CH4 RX2 map", VALUE, 0x9B, 4, 0, 16},
+ { "CH5 RX2 map", VALUE, 0x9C, 5, 0, 16},
+ { "CH6 RX2 map", VALUE, 0x9C, 6, 0, 16},
+ { "CH7 RX2 map", VALUE, 0x9D, 7, 0, 16},
+ { "CH8 RX2 map", VALUE, 0x9D, 8, 0, 16},
+ { "CH9 RX2 map", VALUE, 0x9E, 9, 0, 16},
+ { "CH10 RX2 map", VALUE, 0x9E, 10, 0, 16},
+ { "CH11 RX2 map", VALUE, 0x9F, 11, 0, 16},
+ { "CH12 RX2 map", VALUE, 0x9F, 12, 0, 16},
+ { "CH13 RX2 map", VALUE, 0xA0, 13, 0, 16},
+ { "CH14 RX2 map", VALUE, 0xA0, 14, 0, 16},
+ { "CH15 RX2 map", VALUE, 0xA1, 15, 0, 16},
+ { "CH16 RX2 map", VALUE, 0xA0, 16, 0, 16},
+ { "CH17 RX2 map", VALUE, 0xA2, 1, 0, 16},
+ { "CH18 RX2 map", VALUE, 0xA2, 2, 0, 16},
+ { "CH19 RX2 map", VALUE, 0xA3, 3, 0, 16},
+ { "CH20 RX2 map", VALUE, 0xA3, 4, 0, 16},
+ { "CH21 RX2 map", VALUE, 0xA4, 5, 0, 16},
+ { "CH22 RX2 map", VALUE, 0xA4, 6, 0, 16},
+ { "CH23 RX2 map", VALUE, 0xA5, 7, 0, 16},
+ { "CH24 RX2 map", VALUE, 0xA5, 8, 0, 16},
+}
+
+local rx3PinMapFields = {
+ { "CH1 RX3 map", VALUE, 0xA6, 1, 0, 16},
+ { "CH2 RX3 map", VALUE, 0xA6, 2, 0, 16},
+ { "CH3 RX3 map", VALUE, 0xA7, 3, 0, 16},
+ { "CH4 RX3 map", VALUE, 0xA7, 4, 0, 16},
+ { "CH5 RX3 map", VALUE, 0xA8, 5, 0, 16},
+ { "CH6 RX3 map", VALUE, 0xA8, 6, 0, 16},
+ { "CH7 RX3 map", VALUE, 0xA9, 7, 0, 16},
+ { "CH8 RX3 map", VALUE, 0xA9, 8, 0, 16},
+ { "CH9 RX3 map", VALUE, 0xAA, 9, 0, 16},
+ { "CH10 RX3 map", VALUE, 0xAA, 10, 0, 16},
+ { "CH11 RX3 map", VALUE, 0xAB, 11, 0, 16},
+ { "CH12 RX3 map", VALUE, 0xAB, 12, 0, 16},
+ { "CH13 RX3 map", VALUE, 0xAC, 13, 0, 16},
+ { "CH14 RX3 map", VALUE, 0xAC, 14, 0, 16},
+ { "CH15 RX3 map", VALUE, 0xAD, 15, 0, 16},
+ { "CH16 RX3 map", VALUE, 0xAD, 16, 0, 16},
+ { "CH17 RX3 map", VALUE, 0xAE, 1, 0, 16},
+ { "CH18 RX3 map", VALUE, 0xAE, 2, 0, 16},
+ { "CH19 RX3 map", VALUE, 0xAF, 3, 0, 16},
+ { "CH20 RX3 map", VALUE, 0xAF, 4, 0, 16},
+ { "CH21 RX3 map", VALUE, 0xB0, 5, 0, 16},
+ { "CH22 RX3 map", VALUE, 0xB0, 6, 0, 16},
+ { "CH23 RX3 map", VALUE, 0xB1, 7, 0, 16},
+ { "CH24 RX3 map", VALUE, 0xB1, 8, 0, 16},
+}
+
+
+
+
+local function drawScreenTitle(title, page, pages)
+ if math.fmod(math.floor(getTime() / 100), 10) == 0 then
+ title = version
+ end
+ if LCD_W == 480 then
+ lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR)
+ lcd.drawText(1, 5, title, MENU_TITLE_COLOR)
+ lcd.drawText(LCD_W - 40, 5, page .. "/" .. pages, MENU_TITLE_COLOR)
+ else
+ lcd.drawScreenTitle(title, page, pages)
+ end
+end
+
+-- Change display attribute to current field
+local function addField(step)
+ local field = fields[current]
+ local min, max
+ if field[2] == VALUE then
+ min = field[5]
+ max = field[6]
+ elseif field[2] == COMBO then
+ min = 0
+ max = #(field[5]) - 1
+ end
+ if page == 2 and step < 0 and field[4] == min then
+ field[4] = 0
+ elseif page == 2 and step > 0 and field[4] == 0 then
+ field[4] = min
+ else
+ if (step < 0 and field[4] > min) or (step > 0 and field[4] < max) then
+ field[4] = field[4] + step
+ end
+ end
+end
+
+-- Select the next or previous page
+local function selectPage(step)
+ local pagesNum = #pages
+ if configFields[1][4] == 1 then
+ pagesNum = 1
+ elseif configFields[2][4] == 1 then
+ pagesNum = pagesNum - 1
+ end
+ page = 1 + ((page + step - 1 + pagesNum) % pagesNum)
+ refreshIndex = 0
+ pageOffset = 0
+end
+
+-- Select the next or previous editable field
+local function selectField(step)
+ current = 1 + ((current + step - 1 + #fields) % #fields)
+ if current > numberPerPage + pageOffset then
+ pageOffset = current - numberPerPage
+ elseif current <= pageOffset then
+ pageOffset = current - 1
+ end
+end
+
+local function drawProgressBar()
+ if LCD_W == 480 then
+ local width = (300 * refreshIndex) / #fields
+ lcd.drawRectangle(100, 10, 300, 6)
+ lcd.drawFilledRectangle(102, 12, width, 2)
+ else
+ local width = (60 * refreshIndex) / #fields
+ lcd.drawRectangle(45, 1, 60, 6)
+ lcd.drawFilledRectangle(47, 3, width, 2)
+ end
+end
+
+-- Redraw the current page
+local function redrawFieldPage()
+ lcd.clear()
+
+ local pagesNum = #pages
+ if configFields[1][4] == 1 then
+ pagesNum = 1
+ elseif configFields[2][4] == 1 then
+ pagesNum = pagesNum - 1
+ end
+ drawScreenTitle("RB30/RB40", page, pagesNum)
+
+ if refreshIndex < #fields then
+ drawProgressBar()
+ end
+
+ for index = 1, numberPerPage, 1 do
+ local field = fields[pageOffset + index]
+ if field == nil then
+ break
+ end
+
+ local attr = current == (pageOffset + index) and ((edit == true and BLINK or 0) + INVERS) or 0
+
+ lcd.drawText(1, margin + spacing * index, field[1], attr)
+
+ if field[4] == nil then
+ lcd.drawText(LCD_W, margin + spacing * index, "---", RIGHT + attr)
+ else
+ if field[2] == VALUE then
+ if page == 2 then
+ if field[4] == 0 then
+ lcd.drawText(LCD_W, margin + spacing * index, "No pulse", RIGHT + attr)
+ else
+ lcd.drawNumber(LCD_W, margin + spacing * index, field[4] * 10, RIGHT + attr)
+ end
+ else
+ if field[4] == 0 then
+ lcd.drawText(LCD_W, margin + spacing * index, "No map", RIGHT + attr)
+ else
+ if field[3] == 0xB2 or field[3] == 0xB3 then
+ lcd.drawNumber(LCD_W, margin + spacing * index, field[4] , attr + RIGHT + PREC1)
+ else
+ lcd.drawNumber(LCD_W, margin + spacing * index, field[4], RIGHT + attr)
+ end
+ end
+ end
+ elseif field[2] == COMBO then
+ if field[4] >= 0 and field[4] < #(field[5]) then
+ lcd.drawText(LCD_W, margin + spacing * index, field[5][field[4] + 1], RIGHT + attr)
+ end
+ end
+ end
+ end
+end
+
+local function telemetryIdle(field)
+ return sportTelemetryPush(0x1C, 0x21, 0x0b80, field)
+end
+
+local function telemetryUnIdle(field)
+ return sportTelemetryPush(0x1C, 0x20, 0x0b80, field)
+end
+
+local function telemetryRead(field)
+ return sportTelemetryPush(0x1C, 0x30, 0x0b80, field)
+end
+
+local function telemetryWrite(field, value)
+ return sportTelemetryPush(0x1C, 0x31, 0x0b80, field + value * 256)
+end
+
+local telemetryPopTimeout = 0
+local function refreshNext()
+ if refreshState == 0 then
+ if #modifications > 0 then
+ telemetryWrite(modifications[1][1], modifications[1][2])
+ modifications[1] = nil
+ refreshIndex = 0
+ refreshState = 0
+ elseif refreshIndex < #fields then
+ local field = fields[refreshIndex + 1]
+ if page > 1 then
+ field = fields[refreshIndex + 2]
+ end
+ if telemetryRead(field[3]) == true then
+ refreshState = 1
+ telemetryPopTimeout = getTime() + 100 -- normal delay is 500ms
+ end
+ end
+ elseif refreshState == 1 then
+ local physicalId, primId, dataId, value = sportTelemetryPop()
+ if primId == 0x32 and (dataId >= 0x0b80 or dataId <= 0x0b8f) then
+ local fieldId = value % 256
+ local field = fields[refreshIndex + 1]
+ if fieldId == field[3] then
+ value = math.floor(value / 256)
+ if field[2] == COMBO then
+ fields[refreshIndex + 1][4] = value
+ else
+ fields[refreshIndex + 1][4] = value % 256
+ if page > 1 then
+ value = math.floor(value / 256)
+ fields[refreshIndex + 2][4] = value
+ end
+ end
+ if page > 1 then
+ refreshIndex = refreshIndex + 2
+ else
+ refreshIndex = refreshIndex + 1
+ end
+ refreshState = 0
+ end
+ elseif getTime() > telemetryPopTimeout then
+ fields[refreshIndex + 1][4] = nil
+ if page > 1 then
+ fields[refreshIndex + 2][4] = nil
+ refreshIndex = refreshIndex + 2
+ else
+ refreshIndex = refreshIndex + 1
+ end
+ refreshState = 0
+ end
+ end
+end
+
+local function updateField(field)
+ local value = field[4]
+ if field[2] == COMBO and #field == 6 then
+ value = field[6][1 + value]
+ elseif field[2] == VALUE and #field == 8 then
+ value = value + field[8] - field[5]
+ end
+
+ if page > 1 then
+ if current % 2 == 1 then
+ value = value + fields[current + 1][4] * 256
+ elseif current % 2 == 0 then
+ value = fields[current - 1][4] + value * 256
+ end
+ end
+ modifications[#modifications + 1] = { field[3], value }
+end
+
+-- Main
+local function runFieldsPage(event)
+ if event == EVT_VIRTUAL_EXIT then -- exit script
+ telemetryUnIdle(0x80)
+ return 2
+ elseif event == EVT_VIRTUAL_ENTER then -- toggle editing/selecting current field
+ if fields[current][4] ~= nil then
+ edit = not edit
+ if edit == false then
+ updateField(fields[current])
+ end
+ end
+ elseif edit then
+ if event == EVT_VIRTUAL_INC or event == EVT_VIRTUAL_INC_REPT then
+ addField(1)
+ elseif event == EVT_VIRTUAL_DEC or event == EVT_VIRTUAL_DEC_REPT then
+ addField(-1)
+ end
+ else
+ if event == EVT_VIRTUAL_NEXT then
+ selectField(1)
+ elseif event == EVT_VIRTUAL_PREV then
+ selectField(-1)
+ end
+ end
+ redrawFieldPage()
+ return 0
+end
+
+local function runConfigPage(event)
+ fields = configFields
+ return runFieldsPage(event)
+end
+
+local function runFailsafePage(event)
+ fields = failsafeFields
+ return runFieldsPage(event)
+end
+
+local function runRx1PinMapPage(event)
+ fields = rx1PinMapFields
+ return runFieldsPage(event)
+end
+
+local function runRx2PinMapPage(event)
+ fields = rx2PinMapFields
+ return runFieldsPage(event)
+end
+
+local function runRx3PinMapPage(event)
+ fields = rx3PinMapFields
+ return runFieldsPage(event)
+end
+
+-- Init
+local function init()
+ current, edit, refreshState, refreshIndex = 1, false, 0, 0
+ if LCD_W == 480 then
+ margin = 10
+ spacing = 20
+ numberPerPage = 12
+ end
+ pages = {
+ runConfigPage,
+ runFailsafePage,
+ runRx1PinMapPage,
+ runRx2PinMapPage,
+ runRx3PinMapPage
+ }
+ telemetryIdle(0x80)
+end
+
+-- Main
+local function run(event)
+ if event == nil then
+ error("Cannot be run as a model script!")
+ return 2
+ elseif event == EVT_VIRTUAL_NEXT_PAGE then
+ if edit == false then
+ selectPage(1)
+ end
+ elseif event == EVT_VIRTUAL_PREV_PAGE then
+ if edit == false then
+ killEvents(event)
+ selectPage(-1)
+ end
+ end
+
+ local result = pages[page](event)
+ refreshNext()
+
+ return result
+end
+
+return { init = init, run = run }
+
diff --git a/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/MultiChan.txt b/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/MultiChan.txt
index bf61d8ca6..b03b2c860 100644
--- a/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/MultiChan.txt
+++ b/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/MultiChan.txt
@@ -1,3 +1,47 @@
+24,0,Assan,Std,0,CH5,CH6,CH7,CH8
+14,0,Bayang,Std,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,n-a,n-a,AnAux1,AnAux2
+14,1,Bayang,H8S3D,1,Flip,RTH,Pict,Video,HLess,Invert,Rates
+14,2,Bayang,X16_AH,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf
+14,3,Bayang,IRDRONE,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf,EmStop
+14,4,Bayang,DHD_D4,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf,EmStop
+14,5,Bayang,QX100,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf,EmStop
+59,0,BayangRX,RX,1,AnAux1,AnAux2,Flip,RTH,Pict,Video
+41,0,Bugs,3-6-8,0,Arm,Angle,Flip,Pict,Video,LED
+42,0,BugsMini,Mini,0,Arm,Angle,Flip,Pict,Video,LED
+42,1,BugsMini,3H,0,Arm,Angle,Flip,Pict,Video,LED,AltHol
+34,0,Cabell,V3,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
+34,1,Cabell,V3Telem,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
+13,0,CG023,Std,1,Flip,Light,Pict,Video,HLess
+13,1,CG023,YD829,1,Flip,n-a,Pict,Video,HLess
+37,0,Corona,COR_V1,0,CH5,CH6,CH7,CH8
+37,1,Corona,COR_V2,0,CH5,CH6,CH7,CH8
+37,2,Corona,FD_V3,0,CH5,CH6,CH7,CH8
+12,0,CX10,Green,1,Flip,Rate
+12,1,CX10,Blue,1,Flip,Rate,Pict,Video
+12,2,CX10,DM007,1,Flip,Mode,Pict,Video,HLess
+12,4,CX10,JC3015_1,1,Flip,Mode,Pict,Video
+12,5,CX10,JC3015_2,1,Flip,Mode,LED,DFlip
+12,6,CX10,MK33041,1,Flip,Mode,Pict,Video,HLess,RTH
+7,0,Devo,8CH,0,CH5,CH6,CH7,CH8
+7,1,Devo,10CH,0,CH5,CH6,CH7,CH8,CH9,CH10
+7,2,Devo,12CH,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
+7,3,Devo,6CH,0,CH5,CH6
+7,4,Devo,7CH,0,CH5,CH6,CH7
+33,0,DM022,Std,1,Flip,LED,Cam1,Cam2,HLess,RTH,RLow
+6,0,DSM,2_22,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
+6,1,DSM,2_11,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
+6,2,DSM,X_22,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
+6,3,DSM,X_11,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
+6,4,DSM,AUTO,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
+70,0,DSM_RX,RX,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
+45,0,E01X,E012,1,n-a,Flip,n-a,HLess,RTH
+45,1,E01X,E015,1,Arm,Flip,LED,HLess,RTH
+45,2,E01X,E016H,1,Stop,Flip,n-a,HLess,RTH
+16,0,ESKY,Std,0,Gyro,Pitch
+16,1,ESKY,ET4,0,Gyro,Pitch
+35,0,ESKY150,4CH,0
+35,1,ESKY150,7CH,0,FMode,Aux6,Aux7
+69,0,ESKY150V2,Std,0,CH5_RA,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
1,0,Flysky,Flysky,0,CH5,CH6,CH7,CH8
1,1,Flysky,V9x9,1,Flip,Light,Pict,Video
1,2,Flysky,V6x6,1,Flip,Light,Pict,Video,HLess,RTH,XCAL,YCAL
@@ -7,15 +51,11 @@
28,1,Flysky_AFHDS2A,PPM_IBUS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
28,2,Flysky_AFHDS2A,PWM_SBUS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
28,3,Flysky_AFHDS2A,PPM_SBUS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
-53,0,Flyzone,FZ-410,0
-2,0,Hubsan,H107,1,Flip,Light,Pict,Video,HLess
-2,1,Hubsan,H301,0,RTH,Light,Stab,Video
-2,2,Hubsan,H501,0,RTH,Light,Pict,Video,HLess,GPS_H,ALT_H,Flip,FModes
-41,0,Bugs,3-6-8,0,Arm,Angle,Flip,Pict,Video,LED
-60,0,Pelikan,PRO_V4,0,CH5,CH6,CH7,CH8
-37,0,Corona,COR_V1,0,CH5,CH6,CH7,CH8
-37,1,Corona,COR_V2,0,CH5,CH6,CH7,CH8
-37,2,Corona,FD_V3,0,CH5,CH6,CH7,CH8
+28,4,Flysky_AFHDS2A,PWM_IB16,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
+28,5,Flysky_AFHDS2A,PPM_IB16,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
+56,0,Flysky2A_RX,RX,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
+53,0,Height,5ch,0,Gear
+53,1,Height,8ch,0,Gear,Gyro,Flap,Light
25,0,FrSkyV,V8,0,CH5,CH6,CH7,CH8
3,0,FrSkyD,D8,0,CH5,CH6,CH7,CH8
3,0,FrSkyD,D8Cloned,0,CH5,CH6,CH7,CH8
@@ -26,78 +66,50 @@
15,2,FrSkyX,D16_LBT,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
15,3,FrSkyX,D16_8CH_LBT,0,CH5,CH6,CH7,CH8
15,4,FrSkyX,D16Cloned,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
+15,5,FrSkyX,D16Cloned_8CH,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
64,0,FrSkyX2,D16_FCC,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
64,1,FrSkyX2,D16_8CH_FCC,0,CH5,CH6,CH7,CH8
64,2,FrSkyX2,D16_LBT,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
64,3,FrSkyX2,D16_8CH_LBT,1,CH5,CH6,CH7,CH8
64,4,FrSkyX2,D16Cloned,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
+64,5,FrSkyX2,D16Cloned_8CH,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
+65,0,FrSkyR9,R9_915,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
+65,1,FrSkyR9,R9_868,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
+65,2,FrSkyR9,R9_915_8CH,0,CH5,CH6,CH7,CH8
+65,3,FrSkyR9,R9_968_8CH,0,CH5,CH6,CH7,CH8
55,0,FrSkyRX,RX,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
55,1,FrSkyRX,CloneTX,0
-39,0,Hitec,Opt_Fw,0,CH5,CH6,CH7,CH8,CH9
-39,1,Hitec,Opt_Hub,0,CH5,CH6,CH7,CH8,CH9
-39,2,Hitec,Minima,0,CH5,CH6,CH7,CH8,CH9
-57,0,HoTT,Std,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
-21,0,SFHSS,Std,0,CH5,CH6,CH7,CH8
-68,0,Skyartec,Std,0,CH5,CH6,CH7
-7,0,Devo,8CH,0,CH5,CH6,CH7,CH8
-7,1,Devo,10CH,0,CH5,CH6,CH7,CH8,CH9,CH10
-7,2,Devo,12CH,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
-7,3,Devo,6CH,0,CH5,CH6
-7,4,Devo,7CH,0,CH5,CH6,CH7
-30,0,WK2x01,WK2801,0,CH5,CH6,CH7,CH8
-30,1,WK2x01,WK2401,0
-30,2,WK2x01,W6_5_1,0,Gear,Dis,Gyro
-30,3,WK2x01,W6_6_1,0,Gear,Col,Gyro
-30,4,WK2x01,W6HEL,0,Gear,Col,Gyro
-30,5,WK2x01,W6HEL_I,0,Gear,Col,Gyro
-6,0,DSM,2_22,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
-6,1,DSM,2_11,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
-6,2,DSM,X_22,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
-6,3,DSM,X_11,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
-22,0,J6Pro,Std,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
-22,0,WFLY,WFR0xS,0,CH5,CH6,CH7,CH8,CH9
-24,0,Assan,Std,0,CH5,CH6,CH7,CH8
-14,0,Bayang,Std,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,n-a,n-a,AnAux1,AnAux2
-14,1,Bayang,H8S3D,1,Flip,RTH,Pict,Video,HLess,Invert,Rates
-14,2,Bayang,X16_AH,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf
-14,3,Bayang,IRDRONE,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf,EmStop
-14,4,Bayang,DHD_D4,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf,EmStop
-59,0,BayangRX,RX,1,AnAux1,AnAux2,Flip,RTH,Pict,Video
-42,0,BugsMini,Mini,0,Arm,Angle,Flip,Pict,Video,LED
-42,1,BugsMini,3H,0,Arm,Angle,Flip,Pict,Video,LED,AltHol
-34,0,Cabell,V3,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
-34,1,Cabell,V3Telem,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
-13,0,CG023,Std,1,Flip,Light,Pict,Video,HLess
-13,1,CG023,YD829,1,Flip,n-a,Pict,Video,HLess
-12,0,CX10,Green,1,Flip,Rate
-12,1,CX10,Blue,1,Flip,Rate,Pict,Video
-12,2,CX10,DM007,1,Flip,Mode,Pict,Video,HLess
-12,4,CX10,JC3015_1,1,Flip,Mode,Pict,Video
-12,5,CX10,JC3015_2,1,Flip,Mode,LED,DFlip
-12,6,CX10,MK33041,1,Flip,Mode,Pict,Video,HLess,RTH
-33,0,DM022,Std,1,Flip,LED,Cam1,Cam2,HLess,RTH,RLow
-45,0,E01X,E012,1,n-a,Flip,n-a,HLess,RTH
-45,1,E01X,E015,1,Arm,Flip,LED,HLess,RTH
-45,2,E01X,E016H,1,Stop,Flip,n-a,HLess,RTH
-16,0,ESKY,Std,0,Gyro,Pitch
-16,1,ESKY,ET4,0,Gyro,Pitch
-35,0,ESKY150,4CH,0
-35,1,ESKY150,7CH,0,FMode,Aux6,Aux7
+58,0,FX816,P38,1
20,0,FY326,FY326,1,Flip,RTH,HLess,Expert,Calib
20,1,FY326,FY319,1,Flip,RTH,HLess,Expert,Calib
23,0,FY326,FY326,1,Flip,RTH,HLess,Expert
+47,0,GD00x,V1,1,Trim,LED,Rate
+47,1,GD00x,V2,1,Trim,LED,Rate
32,0,GW008,FY326,1,Flip
36,0,H8_3D,Std,1,Flip,Light,Pict,Video,RTH,FlMode,Cal1
36,1,H8_3D,H20H,1,Flip,Light,Pict,Video,Opt1,Opt2,Cal1,Cal2,Gimbal
36,2,H8_3D,H20,1,Flip,Light,Pict,Video,Opt1,Opt2,Cal1,Cal2,Gimbal
36,3,H8_3D,H30,1,Flip,Light,Pict,Video,Opt1,Opt2,Cal1,Cal2,Gimbal
4,0,Hisky,Std,0,Gear,Pitch,Gyro,CH8
-9,0,KN,WLToys,0,DRate,THold,IdleUp,Gyro,Ttrim,Atrim,Etrim
-9,1,KN,Feilun,0,DRate,THold,IdleUp,Gyro,Ttrim,Atrim,Etrim
+4,1,Hisky,HK310,0,Aux
+39,0,Hitec,Opt_Fw,0,CH5,CH6,CH7,CH8,CH9
+39,1,Hitec,Opt_Hub,0,CH5,CH6,CH7,CH8,CH9
+39,2,Hitec,Minima,0,CH5,CH6,CH7,CH8,CH9
26,0,Hontai,Std,1,Flip,LED,Pict,Video,HLess,RTH,Calib
26,1,Hontai,JJRCX1,1,Flip,Arm,Pict,Video,HLess,RTH,Calib
26,2,Hontai,X5C1,1,Flip,Arm,Pict,Video,HLess,RTH,Calib
26,3,Hontai,FQ777_951,1,Flip,Arm,Pict,Video,HLess,RTH,Calib
+57,0,HoTT,Sync,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
+57,1,HoTT,No_Sync,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
+2,0,Hubsan,H107,1,Flip,Light,Pict,Video,HLess
+2,1,Hubsan,H301,0,RTH,Light,Stab,Video
+2,2,Hubsan,H501,0,RTH,Light,Pict,Video,HLess,GPS_H,ALT_H,Flip,FModes
+22,0,J6Pro,Std,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
+71,0,JJRC345,Std,1,Flip,HLess,RTH
+49,0,KF606,Std,1,Trim
+9,0,KN,WLToys,0,DRate,THold,IdleUp,Gyro,Ttrim,Atrim,Etrim
+9,1,KN,Feilun,0,DRate,THold,IdleUp,Gyro,Ttrim,Atrim,Etrim
+73,0,Kyosho,Std,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
18,0,MJXQ,WHL08,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
18,1,MJXQ,X600,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
18,2,MJXQ,X800,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
@@ -111,6 +123,9 @@
17,3,MT99XX,LS,1,Flip,Invert,Pict,Video,HLess
17,4,MT99XX,FY805,1,Flip,n-a,n-a,n-a,HLess
44,0,NCC1701,Std,1,Warp
+77,0,OMP,M2,0,THold,IdleUp,6G_3D
+60,0,Pelikan,PRO_V4,0,CH5,CH6,CH7,CH8
+60,1,Pelikan,LITE_V4,0,CH5,CH6,CH7,CH8
51,0,Potensic,A20,1,TakLan,Emerg,Mode,HLess
66,0,Propel,74-Z,1,LEDs,RollCW,RolCCW,Fire,Weapon,Calib,AltHol,TakeOf,Land,Train
29,0,Q2x2,Q222,1,Flip,LED,Mod2,Mod1,HLess,RTH,XCal,YCal
@@ -120,8 +135,15 @@
31,1,Q303,C35,1,Arm,VTX,Pict,Video,n-a,RTH,Gimbal
31,2,Q303,CX10D,1,Arm,Flip
31,3,Q303,CX10WD,1,Arm,Flip
+72,0,Q90C,Std,0,FMode,VTX+
+74,0,RadioLink,Surface,0,CH5,CH6,CH7,CH8,FS_CH1,FS_CH2,FS_CH3,FS_CH4,FS_CH5,FS_CH6,FS_CH7,FS_CH8
+74,1,RadioLink,Air,0,CH5,CH6,CH7,CH8,FS_CH1,FS_CH2,FS_CH3,FS_CH4,FS_CH5,FS_CH6,FS_CH7,FS_CH8
+76,0,Realacc,R11,1,Flip,Light,Calib,HLess,RTH,UNK
50,0,Redpine,Fast,0,sCH5,sCH6,sCH7,sCH8,sCH9,sCH10,sCH11,sCH12,sCH13,sCH14,sCH15,sCH16
50,1,Redpine,Slow,0,sCH5,sCH6,sCH7,sCH8,sCH9,sCH10,sCH11,sCH12,sCH13,sCH14,sCH15,sCH16
+21,0,SFHSS,Std,0,CH5,CH6,CH7,CH8
+19,0,Shenqi,Cycle,1
+68,0,Skyartec,Std,0,CH5,CH6,CH7
11,0,SLT,V1,0,Gear,Pitch
11,1,SLT,V2,0,CH5,CH6,CH7,CH8
11,2,SLT,Q100,0,Rates,n-a,CH7,CH8,Mode,Flip,n-a,n-a,Calib
@@ -129,11 +151,21 @@
11,4,SLT,MR100,0,Rates,n-a,CH7,CH8,Mode,Flip,Video,Pict
10,0,Symax,Std,1,Flip,Rates,Pict,Video,HLess
10,1,Symax,X5C,1,Flip,Rates,Pict,Video,HLess
+61,0,Tiger,Std,1,Flip,Light
+43,0,Traxxas,6519,0
5,0,V2x2,Std,1,Flip,Light,Pict,Video,HLess,CalX,CalY
5,1,V2x2,JXD506,1,Flip,Light,Pict,Video,HLess,StaSto,Emerg,Cam_UD
-61,0,Tiger,Std,1,Flip,Light
-46,0,V911s,Std,1,Calib
-46,1,E119,Std,1,Calib
+48,0,V761,3CH,0,Gyro,Calib,Flip,RtnAct,Rtn
+48,1,V761,4CH,0,Gyro,Calib,Flip,RtnAct,Rtn
+46,0,V911s,V911s,1,Calib
+46,1,V911s,E119,1,Calib
+22,0,WFLY,WFR0xS,0,CH5,CH6,CH7,CH8,CH9
+30,0,WK2x01,WK2801,0,CH5,CH6,CH7,CH8
+30,1,WK2x01,WK2401,0
+30,2,WK2x01,W6_5_1,0,Gear,Dis,Gyro
+30,3,WK2x01,W6_6_1,0,Gear,Col,Gyro
+30,4,WK2x01,W6HEL,0,Gear,Col,Gyro
+30,5,WK2x01,W6HEL_I,0,Gear,Col,Gyro
62,0,XK,X450,1,FMode,TakeOf,Emerg,3D_6G,Pict,Video
62,1,XK,X420,1,FMode,TakeOf,Emerg,3D_6G,Pict,Video
8,0,YD717,Std,1,Flip,Light,Pict,Video,HLess
@@ -141,17 +173,4 @@
8,2,YD717,Simax4,1,Flip,Light,Pict,Video,HLess
8,3,YD717,XinXun,1,Flip,Light,Pict,Video,HLess
8,4,YD717,NiHui,1,Flip,Light,Pict,Video,HLess
-65,0,FrSkyR9,R9_915,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
-65,1,FrSkyR9,R9_868,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
-65,2,FrSkyR9,R9_915_8CH,0,CH5,CH6,CH7,CH8
-65,3,FrSkyR9,R9_968_8CH,0,CH5,CH6,CH7,CH8
-56,0,Flysky2A_RX,RX,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
-19,0,Shenqi,Cycle,1
-4,1,Hisky,HK310,0,Aux
-43,0,Traxxas,6519,0
52,0,ZSX,280,1,Light
-48,0,V761,Std,1,Gyro
-49,0,KF606,Std,1,Trim
-47,0,GD00x,V1,1,Trim,LED,Rate
-47,1,GD00x,V2,1,Trim,LED,Rate
-58,0,FX816,P38,1
diff --git a/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/MultiChannelsUpdater.lua b/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/MultiChannelsUpdater.lua
index 42de75e4f..14902b782 100644
--- a/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/MultiChannelsUpdater.lua
+++ b/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/MultiChannelsUpdater.lua
@@ -249,13 +249,13 @@ local function Multi_Init()
--Exceptions on first 4 channels...
local stick_names = { "Rud", "Ele", "Thr", "Ail" }
- if ( protocol == 4 and sub_protocol ==1 ) or protocol == 19 or protocol == 52 then -- Hisky/HK310, Shenqi, ZSX
+ if ( protocol == 4 and sub_protocol == 1 ) or protocol == 19 or protocol == 52 then -- Hisky/HK310, Shenqi, ZSX
stick_names[2] = "n-a"
stick_names[4] = "n-a"
elseif protocol == 43 then -- Traxxas
stick_names[2] = "Aux4"
stick_names[4] = "Aux3"
- elseif protocol == 48 then -- V761
+ elseif ( protocol == 48 and sub_protocol == 0 ) then -- V761 3CH
stick_names[4] = "n-a"
elseif protocol == 47 or protocol == 49 or protocol == 58 then -- GD00x, KF606, FX816
stick_names[1] = "n-a"
@@ -278,6 +278,15 @@ local function Multi_Init()
ch_order = math.floor(ch_order/4)
channel_names[bitand(ch_order,3)+1] = stick_names[1]
end
+
+ --Exceptions on first 4 channels...
+ if ( protocol == 73 or (protocol == 74 and sub_protocol == 0) ) then -- Kyosho or RadioLink Surface
+ channel_names[1] = "ST"
+ channel_names[2] = "THR"
+ channel_names[3] = "CH3"
+ channel_names[4] = "CH4"
+ end
+
--Check MultiChan.txt
local f = io.open("/SCRIPTS/TOOLS/MultiChan.txt", "r")
if f == nil then return end
diff --git a/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/crossfire.lua b/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/crossfire.lua
index 0f9b1a20f..b19bb5ee2 100644
--- a/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/crossfire.lua
+++ b/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/crossfire.lua
@@ -30,6 +30,11 @@ local function run(event)
return 2
end
+ if crossfireTelemetryPush() == nil then
+ error("Crossfire not available!")
+ return 2
+ end
+
chdir("/SCRIPTS/TOOLS/CROSSFIRE")
return "crossfire.lua"
end
diff --git a/radio/src/CMakeLists.txt b/radio/src/CMakeLists.txt
index 989457f92..b71d572ba 100644
--- a/radio/src/CMakeLists.txt
+++ b/radio/src/CMakeLists.txt
@@ -54,6 +54,7 @@ option(MODULE_PROTOCOL_FLEX "Add support for non certified FLEX modules" OFF)
option(MODULE_PROTOCOL_D8 "Add support for D8 modules" ON)
option(FRSKY_RELEASE "Used to build FrSky released firmware" OFF)
option(TBS_RELEASE "Used to build TBS released firmware" OFF)
+option(IMRC_RELEASE "Used to build IMRC released firmware" OFF)
option(ALLOW_TRAINER_MULTI "Allow multi trainer" OFF)
# since we reset all default CMAKE compiler flags for firmware builds, provide an alternate way for user to specify additional flags.
@@ -344,10 +345,18 @@ if(RADIOMASTER_RELEASE)
add_definitions(-DRADIOMASTER_RELEASE)
endif()
+if(RADIOMASTER_RTF_RELEASE)
+ add_definitions(-DRADIOMASTER_RTF_RELEASE)
+endif()
+
if(TBS_RELEASE)
add_definitions(-DTBS_RELEASE)
endif()
+if(IMRC_RELEASE)
+ add_definitions(-DIMRC_RELEASE)
+endif()
+
if(FRSKY_RELEASE)
add_definitions(-DFRSKY_RELEASE)
set(POPUP_LEVEL 3)
@@ -373,6 +382,7 @@ set(SRC
strhelpers.cpp
switches.cpp
mixer.cpp
+ mixer_scheduler.cpp
stamp.cpp
timers.cpp
trainer.cpp
diff --git a/radio/src/audio.cpp b/radio/src/audio.cpp
index c8417568d..04ff8a8b2 100644
--- a/radio/src/audio.cpp
+++ b/radio/src/audio.cpp
@@ -158,10 +158,10 @@ const char * const unitsFilenames[] = {
"ml",
"founce",
"mlpm",
- "spare1",
- "spare2",
- "spare3",
- "spare4",
+ "hertz",
+ "ms",
+ "us",
+ "km",
"spare5",
"spare6",
"spare7",
diff --git a/radio/src/cli.cpp b/radio/src/cli.cpp
index cb72b8076..8d64e7972 100644
--- a/radio/src/cli.cpp
+++ b/radio/src/cli.cpp
@@ -699,11 +699,11 @@ int cliTrace(const char ** argv)
int cliStackInfo(const char ** argv)
{
- serialPrint("[MAIN] %d available / %d", stackAvailable(), stackSize());
- serialPrint("[MENUS] %d available / %d", menusStack.available(), menusStack.size());
- serialPrint("[MIXER] %d available / %d", mixerStack.available(), mixerStack.size());
- serialPrint("[AUDIO] %d available / %d", audioStack.available(), audioStack.size());
- serialPrint("[CLI] %d available / %d", cliStack.available(), cliStack.size());
+ serialPrint("[MAIN] %d available / %d bytes", stackAvailable()*4, stackSize()*4);
+ serialPrint("[MENUS] %d available / %d bytes", menusStack.available()*4, menusStack.size());
+ serialPrint("[MIXER] %d available / %d bytes", mixerStack.available()*4, mixerStack.size());
+ serialPrint("[AUDIO] %d available / %d bytes", audioStack.available()*4, audioStack.size());
+ serialPrint("[CLI] %d available / %d bytes", cliStack.available()*4, cliStack.size());
return 0;
}
diff --git a/radio/src/crc.cpp b/radio/src/crc.cpp
index 26a1af500..c0be4d7fa 100644
--- a/radio/src/crc.cpp
+++ b/radio/src/crc.cpp
@@ -79,3 +79,48 @@ uint8_t crc8(const uint8_t * ptr, uint32_t len)
}
return crc;
}
+
+// CRC8 implementation with polynom = 0xBA
+const unsigned char crc8tab_BA[256] = {
+ 0x00, 0xBA, 0xCE, 0x74, 0x26, 0x9C, 0xE8, 0x52,
+ 0x4C, 0xF6, 0x82, 0x38, 0x6A, 0xD0, 0xA4, 0x1E,
+ 0x98, 0x22, 0x56, 0xEC, 0xBE, 0x04, 0x70, 0xCA,
+ 0xD4, 0x6E, 0x1A, 0xA0, 0xF2, 0x48, 0x3C, 0x86,
+ 0x8A, 0x30, 0x44, 0xFE, 0xAC, 0x16, 0x62, 0xD8,
+ 0xC6, 0x7C, 0x08, 0xB2, 0xE0, 0x5A, 0x2E, 0x94,
+ 0x12, 0xA8, 0xDC, 0x66, 0x34, 0x8E, 0xFA, 0x40,
+ 0x5E, 0xE4, 0x90, 0x2A, 0x78, 0xC2, 0xB6, 0x0C,
+ 0xAE, 0x14, 0x60, 0xDA, 0x88, 0x32, 0x46, 0xFC,
+ 0xE2, 0x58, 0x2C, 0x96, 0xC4, 0x7E, 0x0A, 0xB0,
+ 0x36, 0x8C, 0xF8, 0x42, 0x10, 0xAA, 0xDE, 0x64,
+ 0x7A, 0xC0, 0xB4, 0x0E, 0x5C, 0xE6, 0x92, 0x28,
+ 0x24, 0x9E, 0xEA, 0x50, 0x02, 0xB8, 0xCC, 0x76,
+ 0x68, 0xD2, 0xA6, 0x1C, 0x4E, 0xF4, 0x80, 0x3A,
+ 0xBC, 0x06, 0x72, 0xC8, 0x9A, 0x20, 0x54, 0xEE,
+ 0xF0, 0x4A, 0x3E, 0x84, 0xD6, 0x6C, 0x18, 0xA2,
+ 0xE6, 0x5C, 0x28, 0x92, 0xC0, 0x7A, 0x0E, 0xB4,
+ 0xAA, 0x10, 0x64, 0xDE, 0x8C, 0x36, 0x42, 0xF8,
+ 0x7E, 0xC4, 0xB0, 0x0A, 0x58, 0xE2, 0x96, 0x2C,
+ 0x32, 0x88, 0xFC, 0x46, 0x14, 0xAE, 0xDA, 0x60,
+ 0x6C, 0xD6, 0xA2, 0x18, 0x4A, 0xF0, 0x84, 0x3E,
+ 0x20, 0x9A, 0xEE, 0x54, 0x06, 0xBC, 0xC8, 0x72,
+ 0xF4, 0x4E, 0x3A, 0x80, 0xD2, 0x68, 0x1C, 0xA6,
+ 0xB8, 0x02, 0x76, 0xCC, 0x9E, 0x24, 0x50, 0xEA,
+ 0x48, 0xF2, 0x86, 0x3C, 0x6E, 0xD4, 0xA0, 0x1A,
+ 0x04, 0xBE, 0xCA, 0x70, 0x22, 0x98, 0xEC, 0x56,
+ 0xD0, 0x6A, 0x1E, 0xA4, 0xF6, 0x4C, 0x38, 0x82,
+ 0x9C, 0x26, 0x52, 0xE8, 0xBA, 0x00, 0x74, 0xCE,
+ 0xC2, 0x78, 0x0C, 0xB6, 0xE4, 0x5E, 0x2A, 0x90,
+ 0x8E, 0x34, 0x40, 0xFA, 0xA8, 0x12, 0x66, 0xDC,
+ 0x5A, 0xE0, 0x94, 0x2E, 0x7C, 0xC6, 0xB2, 0x08,
+ 0x16, 0xAC, 0xD8, 0x62, 0x30, 0x8A, 0xFE, 0x44
+};
+
+uint8_t crc8_BA(const uint8_t * ptr, uint32_t len)
+{
+ uint8_t crc = 0;
+ for (uint32_t i=0; i> 4;
})
+
+ NOBACKUP(inline uint8_t getChannelsCount() const
+ {
+ return channelsCount + 8;
+ })
});
/*
@@ -605,8 +613,9 @@ PACK(struct ModelData {
NOBACKUP(RssiAlarmData rssiAlarms);
- NOBACKUP(uint8_t spare1:6);
- NOBACKUP(uint8_t potsWarnMode:2);
+ uint8_t spare1:3;
+ uint8_t thrTrimSw:3;
+ uint8_t potsWarnMode:2;
ModuleData moduleData[NUM_MODULES];
int16_t failsafeChannels[MAX_OUTPUT_CHANNELS];
@@ -625,6 +634,20 @@ PACK(struct ModelData {
CUSTOM_SCREENS_DATA
char modelRegistrationID[PXX2_LEN_REGISTRATION_ID];
+
+
+ uint8_t getThrottleStickTrimSource() const
+ {
+ // The order here is TERA, so that 0 (default) means Throttle
+ switch (thrTrimSw) {
+ case 0:
+ return MIXSRC_TrimThr;
+ case 2:
+ return MIXSRC_TrimRud;
+ default:
+ return thrTrimSw + MIXSRC_FIRST_TRIM;
+ }
+ }
});
/*
diff --git a/radio/src/fonts/480x272/font_dblsize.png b/radio/src/fonts/480x272/font_dblsize.png
index b8d7d4717..1be293a2d 100644
Binary files a/radio/src/fonts/480x272/font_dblsize.png and b/radio/src/fonts/480x272/font_dblsize.png differ
diff --git a/radio/src/fonts/480x272/font_xxlsize.png b/radio/src/fonts/480x272/font_xxlsize.png
index cd38d5e6d..24a303309 100644
Binary files a/radio/src/fonts/480x272/font_xxlsize.png and b/radio/src/fonts/480x272/font_xxlsize.png differ
diff --git a/radio/src/functions.cpp b/radio/src/functions.cpp
index 0d1ebbf38..87d6ad199 100644
--- a/radio/src/functions.cpp
+++ b/radio/src/functions.cpp
@@ -340,7 +340,7 @@ void evalFunctions(const CustomFunctionData * functions, CustomFunctionsContext
#if defined(VARIO)
case FUNC_VARIO:
- newActiveFunctions |= (1 << FUNCTION_VARIO);
+ newActiveFunctions |= (1u << FUNCTION_VARIO);
break;
#endif
@@ -348,22 +348,46 @@ void evalFunctions(const CustomFunctionData * functions, CustomFunctionsContext
#if defined(SDCARD)
case FUNC_LOGS:
if (CFN_PARAM(cfn)) {
- newActiveFunctions |= (1 << FUNCTION_LOGS);
+ newActiveFunctions |= (1u << FUNCTION_LOGS);
logDelay = CFN_PARAM(cfn);
}
break;
#endif
case FUNC_BACKLIGHT:
- newActiveFunctions |= (1 << FUNCTION_BACKLIGHT);
+ {
+ newActiveFunctions |= (1u << FUNCTION_BACKLIGHT);
+ if (!CFN_PARAM(cfn)) { // When no source is set, backlight works like original backlight and turn on regardless of backlight settings
+ requiredBacklightBright = BACKLIGHT_FORCED_ON;
+ break;
+ }
+
+ getvalue_t raw = getValue(CFN_PARAM(cfn));
+#if defined(COLORLCD)
+ if (raw == -1024)
+ requiredBacklightBright = 100;
+ else
+ requiredBacklightBright = (1024 - raw) * (BACKLIGHT_LEVEL_MAX - BACKLIGHT_LEVEL_MIN) / 2048;
+#else
+ requiredBacklightBright = (1024 - raw) * 100 / 2048;
+#endif
break;
+ }
case FUNC_SCREENSHOT:
if (!(functionsContext.activeSwitches & switch_mask)) {
- mainRequestFlags |= (1 << REQUEST_SCREENSHOT);
+ mainRequestFlags |= (1u << REQUEST_SCREENSHOT);
}
break;
+#if defined(PXX2)
+ case FUNC_RACING_MODE:
+ if (isRacingModeEnabled()) {
+ newActiveFunctions |= (1u << FUNCTION_RACING_MODE);
+ }
+ break;
+#endif
+
#if defined(DEBUG)
case FUNC_TEST:
testFunc();
diff --git a/radio/src/globals.h b/radio/src/globals.h
index cf67dbc4a..f63dfefe0 100644
--- a/radio/src/globals.h
+++ b/radio/src/globals.h
@@ -50,6 +50,7 @@ extern uint8_t trimsDisplayMask;
extern uint16_t maxMixerDuration;
extern uint8_t requiredSpeakerVolume;
+extern uint8_t requiredBacklightBright;
enum MainRequest {
REQUEST_SCREENSHOT,
diff --git a/radio/src/gui/128x64/gui.h b/radio/src/gui/128x64/gui.h
index 1e48d6746..11f8faa0f 100644
--- a/radio/src/gui/128x64/gui.h
+++ b/radio/src/gui/128x64/gui.h
@@ -36,7 +36,6 @@
#define HEADER_LINE_COLUMNS 0,
#endif
-#define COLUMN_X 0
#define drawFieldLabel(x, y, str) lcdDrawTextAlignedLeft(y, str)
#define NUM_BODY_LINES (LCD_LINES-1)
@@ -217,6 +216,8 @@ extern int8_t s_copySrcRow;
extern int8_t s_copyTgtOfs;
extern uint8_t s_currIdx;
extern uint8_t s_currIdxSubMenu;
+extern uint16_t s_currSrcRaw;
+extern uint16_t s_currScale;
extern uint8_t s_copySrcIdx;
extern uint8_t s_copySrcCh;
extern int8_t s_currCh;
@@ -276,9 +277,6 @@ uint8_t getMixesCount();
void insertMix(uint8_t idx);
void deleteMix(uint8_t idx);
-typedef int (*FnFuncP) (int x);
-void drawFunction(FnFuncP fn, uint8_t offset=0);
-
void onSourceLongEnterPress(const char *result);
uint8_t switchToMix(uint8_t source);
diff --git a/radio/src/gui/128x64/lcd.h b/radio/src/gui/128x64/lcd.h
index c6b32dd3d..3a94f2365 100644
--- a/radio/src/gui/128x64/lcd.h
+++ b/radio/src/gui/128x64/lcd.h
@@ -181,8 +181,9 @@ uint8_t * lcdLoadBitmap(uint8_t * dest, const char * filename, uint8_t width, ui
#if defined(BOOT)
#define BLINK_ON_PHASE (0)
#else
- #define BLINK_ON_PHASE (g_blinkTmr10ms & (1<<6))
#define SLOW_BLINK_ON_PHASE (g_blinkTmr10ms & (1<<7))
+ #define BLINK_ON_PHASE (g_blinkTmr10ms & (1<<6))
+ #define FAST_BLINK_ON_PHASE (g_blinkTmr10ms & (1<<4))
#endif
inline display_t getPixel(uint8_t x, uint8_t y)
diff --git a/radio/src/gui/128x64/menu_model.cpp b/radio/src/gui/128x64/menu_model.cpp
index b6f5b3bb3..b98372bd3 100644
--- a/radio/src/gui/128x64/menu_model.cpp
+++ b/radio/src/gui/128x64/menu_model.cpp
@@ -46,3 +46,5 @@ void editSingleName(coord_t x, coord_t y, const char * label, char * name, uint8
uint8_t s_currIdx;
uint8_t s_currIdxSubMenu;
+uint16_t s_currSrcRaw;
+uint16_t s_currScale;
diff --git a/radio/src/gui/128x64/menus.h b/radio/src/gui/128x64/menus.h
index a1e980874..1dfa1d24d 100644
--- a/radio/src/gui/128x64/menus.h
+++ b/radio/src/gui/128x64/menus.h
@@ -74,6 +74,7 @@ void menuRadioTools(event_t event);
void menuRadioSpectrumAnalyser(event_t event);
void menuRadioPowerMeter(event_t event);
void menuRadioCalibration(event_t event);
+void menuGhostModuleConfig(event_t event);
static const MenuHandlerFunc menuTabGeneral[MENU_RADIO_PAGES_COUNT] = {
#if defined(RADIO_TOOLS)
diff --git a/radio/src/gui/128x64/model_curve_edit.cpp b/radio/src/gui/128x64/model_curve_edit.cpp
index 2dfdaf567..c2168ed02 100644
--- a/radio/src/gui/128x64/model_curve_edit.cpp
+++ b/radio/src/gui/128x64/model_curve_edit.cpp
@@ -165,20 +165,29 @@ void menuModelCurveOne(event_t event)
}
break;
-#if defined(NAVIGATION_X7)
- case EVT_KEY_LONG(KEY_MENU):
+#if defined(KEYS_GPIO_REG_MDL)
+ case EVT_KEY_FIRST(KEY_MODEL):
+ pushMenu(menuChannelsView);
+ killEvents(event);
+ break;
+#elif defined(NAVIGATION_X7)
+ case EVT_KEY_FIRST(KEY_MENU):
pushMenu(menuChannelsView);
killEvents(event);
break;
#elif defined(NAVIGATION_XLITE)
- case EVT_KEY_LONG(KEY_SHIFT):
- pushMenu(menuChannelsView);
- killEvents(event);
+ case EVT_KEY_FIRST(KEY_ENTER):
+ if (IS_SHIFT_PRESSED()) {
+ pushMenu(menuChannelsView);
+ killEvents(event);
+ }
break;
#endif
}
- drawCurve(0);
+ drawCurve();
+ if (s_currSrcRaw != MIXSRC_NONE)
+ drawCursor(applyCurrentCurve);
attr = (s_editMode > 0 ? INVERS|BLINK : INVERS);
for (uint8_t i=0; i<5+crv.points; i++) {
diff --git a/radio/src/gui/128x64/model_display.cpp b/radio/src/gui/128x64/model_display.cpp
index f138593e0..695be1777 100644
--- a/radio/src/gui/128x64/model_display.cpp
+++ b/radio/src/gui/128x64/model_display.cpp
@@ -242,10 +242,10 @@ void menuModelDisplay(event_t event)
}
break;
case 1:
- bar.barMin = checkIncDec(event, bar.barMin, barMin, bar.barMax, EE_MODEL|NO_INCDEC_MARKS);
+ bar.barMin = checkIncDec(event, bar.barMin, barMin, barMax, EE_MODEL|NO_INCDEC_MARKS);
break;
case 2:
- bar.barMax = checkIncDec(event, bar.barMax, bar.barMin, barMax, EE_MODEL|NO_INCDEC_MARKS);
+ bar.barMax = checkIncDec(event, bar.barMax, barMin, barMax, EE_MODEL|NO_INCDEC_MARKS);
break;
}
}
diff --git a/radio/src/gui/128x64/model_flightmodes.cpp b/radio/src/gui/128x64/model_flightmodes.cpp
index b1b408b4a..c8eac3b2b 100644
--- a/radio/src/gui/128x64/model_flightmodes.cpp
+++ b/radio/src/gui/128x64/model_flightmodes.cpp
@@ -64,13 +64,8 @@ void menuModelFlightModeOne(event_t event)
drawFlightMode(13*FW, 0, s_currIdx+1, (getFlightMode()==s_currIdx ? BOLD : 0));
#if defined(GVARS) && !defined(GVARS_IN_CURVES_SCREEN)
-#if defined(PCBTARANIS)
#define VERTICAL_SHIFT (ITEM_MODEL_FLIGHT_MODE_FADE_IN-ITEM_MODEL_FLIGHT_MODE_TRIMS)
static const uint8_t mstate_tab_fm1[] = {0, 3, 0, 0, (uint8_t)-1, 1, 1, 1, 1, 1, 1};
-#else
- #define VERTICAL_SHIFT (ITEM_MODEL_FLIGHT_MODE_FADE_IN-ITEM_MODEL_FLIGHT_MODE_SWITCH)
- static const uint8_t mstate_tab_fm1[] = {0, 0, 0, (uint8_t)-1, 1, 1, 1, 1, 1};
-#endif
static const uint8_t mstate_tab_others[] = {0, 0, 3, 0, 0, (uint8_t)-1, 2, 2, 2, 2, 2};
check(event, 0, NULL, 0, (s_currIdx == 0) ? mstate_tab_fm1 : mstate_tab_others, DIM(mstate_tab_others)-1, ITEM_MODEL_FLIGHT_MODE_MAX - HEADER_LINE - (s_currIdx==0 ? (ITEM_MODEL_FLIGHT_MODE_FADE_IN-ITEM_MODEL_FLIGHT_MODE_SWITCH-1) : 0));
diff --git a/radio/src/gui/128x64/model_input_edit.cpp b/radio/src/gui/128x64/model_input_edit.cpp
index a2423189b..ce76e0a89 100644
--- a/radio/src/gui/128x64/model_input_edit.cpp
+++ b/radio/src/gui/128x64/model_input_edit.cpp
@@ -21,7 +21,6 @@
#include "opentx.h"
#define EXPO_ONE_2ND_COLUMN (7*FW+3*FW+2)
-#define EXPO_ONE_FM_WIDTH (5*FW)
int expoFn(int x)
{
@@ -31,28 +30,6 @@ int expoFn(int x)
return anas[ed->chn];
}
-void drawFunction(FnFuncP fn, uint8_t offset)
-{
- lcdDrawVerticalLine(CURVE_CENTER_X-offset, 0/*TODO CURVE_CENTER_Y-CURVE_SIDE_WIDTH*/, CURVE_SIDE_WIDTH*2, 0xee);
- lcdDrawHorizontalLine(CURVE_CENTER_X-CURVE_SIDE_WIDTH-offset, CURVE_CENTER_Y, CURVE_SIDE_WIDTH*2, 0xee);
-
- coord_t prev_yv = (coord_t)-1;
-
- for (int xv=-CURVE_SIDE_WIDTH; xv<=CURVE_SIDE_WIDTH; xv++) {
- coord_t yv = (LCD_H-1) - (((uint16_t)RESX + fn(xv * (RESX/CURVE_SIDE_WIDTH))) / 2 * (LCD_H-1) / RESX);
- if (prev_yv != (coord_t)-1) {
- if (abs((int8_t)yv-prev_yv) <= 1) {
- lcdDrawPoint(CURVE_CENTER_X+xv-offset-1, prev_yv, FORCE);
- }
- else {
- uint8_t tmp = (prev_yv < yv ? 0 : 1);
- lcdDrawSolidVerticalLine(CURVE_CENTER_X+xv-offset-1, yv+tmp, prev_yv-yv);
- }
- }
- prev_yv = yv;
- }
-}
-
enum ExposFields {
EXPO_FIELD_INPUT_NAME,
EXPO_FIELD_LINE_NAME,
@@ -72,13 +49,18 @@ enum ExposFields {
void menuModelExpoOne(event_t event)
{
-#if defined(NAVIGATION_X7)
- if (event == EVT_KEY_LONG(KEY_MENU)) {
+#if defined(KEYS_GPIO_REG_MDL)
+ if (event == EVT_KEY_FIRST(KEY_MODEL)) {
+ pushMenu(menuChannelsView);
+ killEvents(event);
+ }
+#elif defined(NAVIGATION_X7)
+ if (event == EVT_KEY_FIRST(KEY_MENU)) {
pushMenu(menuChannelsView);
killEvents(event);
}
#elif defined(NAVIGATION_XLITE)
- if (event == EVT_KEY_LONG(KEY_SHIFT)) {
+ if (event == EVT_KEY_FIRST(KEY_ENTER) && IS_SHIFT_PRESSED()) {
pushMenu(menuChannelsView);
killEvents(event);
}
@@ -113,13 +95,15 @@ void menuModelExpoOne(event_t event)
case EXPO_FIELD_SOURCE:
lcdDrawTextAlignedLeft(y, STR_SOURCE);
drawSource(EXPO_ONE_2ND_COLUMN, y, ed->srcRaw, RIGHT|STREXPANDED|attr);
- if (attr) ed->srcRaw = checkIncDec(event, ed->srcRaw, INPUTSRC_FIRST, INPUTSRC_LAST, EE_MODEL|INCDEC_SOURCE|NO_INCDEC_MARKS, isSourceAvailableInInputs);
+ if (attr)
+ ed->srcRaw = checkIncDec(event, ed->srcRaw, INPUTSRC_FIRST, INPUTSRC_LAST, EE_MODEL|INCDEC_SOURCE|NO_INCDEC_MARKS, isSourceAvailableInInputs);
break;
case EXPO_FIELD_SCALE:
lcdDrawTextAlignedLeft(y, STR_SCALE);
- drawSensorCustomValue(EXPO_ONE_2ND_COLUMN, y, (ed->srcRaw - MIXSRC_FIRST_TELEM)/3, convertTelemValue(ed->srcRaw - MIXSRC_FIRST_TELEM + 1, ed->scale), attr);
- if (attr) ed->scale = checkIncDec(event, ed->scale, 0, maxTelemValue(ed->srcRaw - MIXSRC_FIRST_TELEM + 1), EE_MODEL);
+ drawSensorCustomValue(EXPO_ONE_2ND_COLUMN, y, (ed->srcRaw - MIXSRC_FIRST_TELEM)/3, convertTelemValue(ed->srcRaw - MIXSRC_FIRST_TELEM + 1, ed->scale), RIGHT | attr);
+ if (attr)
+ ed->scale = checkIncDec(event, ed->scale, 0, maxTelemValue(ed->srcRaw - MIXSRC_FIRST_TELEM + 1), EE_MODEL);
break;
case EXPO_FIELD_WEIGHT:
@@ -159,34 +143,20 @@ void menuModelExpoOne(event_t event)
break;
case EXPO_FIELD_TRIM:
- uint8_t not_stick = (ed->srcRaw > MIXSRC_Ail);
+ uint8_t notStick = (ed->srcRaw > MIXSRC_Ail);
int8_t carryTrim = -ed->carryTrim;
lcdDrawTextAlignedLeft(y, STR_TRIM);
- lcdDrawTextAtIndex(EXPO_ONE_2ND_COLUMN, y, STR_VMIXTRIMS, (not_stick && carryTrim == 0) ? 0 : carryTrim+1, RIGHT | (menuHorizontalPosition==0 ? attr : 0));
- if (attr) ed->carryTrim = -checkIncDecModel(event, carryTrim, not_stick ? TRIM_ON : -TRIM_OFF, -TRIM_LAST);
+ lcdDrawTextAtIndex(EXPO_ONE_2ND_COLUMN, y, STR_VMIXTRIMS, (notStick && carryTrim == 0) ? 0 : carryTrim+1, RIGHT | (menuHorizontalPosition==0 ? attr : 0));
+ if (attr)
+ ed->carryTrim = -checkIncDecModel(event, carryTrim, notStick ? TRIM_ON : -TRIM_OFF, -TRIM_LAST);
break;
}
y += FH;
}
drawFunction(expoFn);
-
- int x512 = getValue(ed->srcRaw);
- if (ed->srcRaw >= MIXSRC_FIRST_TELEM) {
- drawSensorCustomValue(LCD_W-FW, 6*FH, (ed->srcRaw - MIXSRC_FIRST_TELEM) / 3, x512, 0);
- if (ed->scale > 0) x512 = (x512 * 1024) / convertTelemValue(ed->srcRaw - MIXSRC_FIRST_TELEM + 1, ed->scale);
- }
- else {
- lcdDrawNumber(LCD_W-FW, 6*FH, calcRESXto1000(x512), RIGHT | PREC1);
- }
- x512 = limit(-1024, x512, 1024);
- int y512 = expoFn(x512);
- y512 = limit(-1024, y512, 1024);
- lcdDrawNumber(CURVE_CENTER_X-FWNUM, 1*FH, calcRESXto1000(y512), RIGHT | PREC1);
-
- x512 = CURVE_CENTER_X+x512/(RESX/CURVE_SIDE_WIDTH);
- y512 = (LCD_H-1) - ((y512+RESX)/2) * (LCD_H-1) / RESX;
-
- lcdDrawSolidVerticalLine(x512, y512-3, 3*2+1);
- lcdDrawSolidHorizontalLine(x512-3, y512, 3*2+1);
+ // those parameters are global so that they can be reused in the curve edit screen
+ s_currSrcRaw = ed->srcRaw;
+ s_currScale = ed->scale;
+ drawCursor(expoFn);
}
diff --git a/radio/src/gui/128x64/model_inputs_mixes.cpp b/radio/src/gui/128x64/model_inputs_mixes.cpp
deleted file mode 100644
index 953ee64b1..000000000
--- a/radio/src/gui/128x64/model_inputs_mixes.cpp
+++ /dev/null
@@ -1,849 +0,0 @@
-/*
- * 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.
- */
-
-#include "opentx.h"
-
-#define EXPO_ONE_2ND_COLUMN (7*FW+3*FW+2)
-#define EXPO_ONE_FM_WIDTH (5*FW)
-
-int expoFn(int x)
-{
- ExpoData *ed = expoAddress(s_currIdx);
- int16_t anas[MAX_INPUTS] = {0};
- anas[ed->chn] = x;
- applyExpos(anas, e_perout_mode_inactive_flight_mode);
- return anas[ed->chn];
-}
-
-void drawFunction(FnFuncP fn, uint8_t offset)
-{
- lcdDrawVerticalLine(CURVE_CENTER_X-offset, 0, LCD_H, 0xee);
- lcdDrawHorizontalLine(CURVE_CENTER_X-CURVE_SIDE_WIDTH-offset, CURVE_CENTER_Y, CURVE_SIDE_WIDTH*2, 0xee);
-
- coord_t prev_yv = (coord_t)-1;
-
- for (int8_t xv=-CURVE_SIDE_WIDTH; xv<=CURVE_SIDE_WIDTH; xv++) {
- coord_t yv = (LCD_H-1) - (((uint16_t)RESX + fn(xv * (RESX/CURVE_SIDE_WIDTH))) / 2 * (LCD_H-1) / RESX);
- if (prev_yv != (coord_t)-1) {
- if (abs((int8_t)yv-prev_yv) <= 1) {
- lcdDrawPoint(CURVE_CENTER_X+xv-offset-1, prev_yv, FORCE);
- }
- else {
- uint8_t tmp = (prev_yv < yv ? 0 : 1);
- lcdDrawSolidVerticalLine(CURVE_CENTER_X+xv-offset-1, yv+tmp, prev_yv-yv);
- }
- }
- prev_yv = yv;
- }
-}
-
-
-uint8_t getExpoMixCount(uint8_t expo)
-{
- uint8_t count = 0;
- uint8_t ch ;
-
- for(int8_t i=(expo ? MAX_EXPOS-1 : MAX_MIXERS-1); i>=0; i--) {
- ch = (expo ? EXPO_VALID(expoAddress(i)) : mixAddress(i)->srcRaw);
- if (ch != 0) {
- count++;
- }
- }
- return count;
-}
-
-bool reachExpoMixCountLimit(uint8_t expo)
-{
- // check mixers count limit
- if (getExpoMixCount(expo) >= (expo ? MAX_EXPOS : MAX_MIXERS)) {
- POPUP_WARNING(expo ? STR_NOFREEEXPO : STR_NOFREEMIXER);
- return true;
- }
- return false;
-}
-
-void deleteExpoMix(uint8_t expo, uint8_t idx)
-{
- pauseMixerCalculations();
- if (expo) {
- ExpoData *expo = expoAddress(idx);
- memmove(expo, expo+1, (MAX_EXPOS-(idx+1))*sizeof(ExpoData));
- memclear(&g_model.expoData[MAX_EXPOS-1], sizeof(ExpoData));
- }
- else {
- MixData *mix = mixAddress(idx);
- memmove(mix, mix+1, (MAX_MIXERS-(idx+1))*sizeof(MixData));
- memclear(&g_model.mixData[MAX_MIXERS-1], sizeof(MixData));
- }
- resumeMixerCalculations();
- storageDirty(EE_MODEL);
-}
-
-// TODO avoid this global s_currCh on ARM boards ...
-int8_t s_currCh;
-void insertExpoMix(uint8_t expo, uint8_t idx)
-{
- pauseMixerCalculations();
- if (expo) {
- ExpoData *expo = expoAddress(idx);
- memmove(expo+1, expo, (MAX_EXPOS-(idx+1))*sizeof(ExpoData));
- memclear(expo, sizeof(ExpoData));
- expo->mode = 3; // pos&neg
- expo->chn = s_currCh - 1;
- expo->weight = 100;
- }
- else {
- MixData *mix = mixAddress(idx);
- memmove(mix+1, mix, (MAX_MIXERS-(idx+1))*sizeof(MixData));
- memclear(mix, sizeof(MixData));
- mix->destCh = s_currCh-1;
- mix->srcRaw = (s_currCh > 4 ? MIXSRC_Rud - 1 + s_currCh : MIXSRC_Rud - 1 + channelOrder(s_currCh));
- mix->weight = 100;
- }
- resumeMixerCalculations();
- storageDirty(EE_MODEL);
-}
-
-void copyExpoMix(uint8_t expo, uint8_t idx)
-{
- pauseMixerCalculations();
- if (expo) {
- ExpoData *expo = expoAddress(idx);
- memmove(expo+1, expo, (MAX_EXPOS-(idx+1))*sizeof(ExpoData));
- }
- else {
- MixData *mix = mixAddress(idx);
- memmove(mix+1, mix, (MAX_MIXERS-(idx+1))*sizeof(MixData));
- }
- resumeMixerCalculations();
- storageDirty(EE_MODEL);
-}
-
-bool swapExpoMix(uint8_t expo, uint8_t &idx, uint8_t up)
-{
- void *x, *y;
- uint8_t size;
- int8_t tgt_idx = (up ? idx-1 : idx+1);
-
- if (expo) {
- x = (ExpoData *)expoAddress(idx);
-
- if (tgt_idx < 0) {
- if (((ExpoData *)x)->chn == 0)
- return false;
- ((ExpoData *)x)->chn--;
- return true;
- }
-
- if (tgt_idx == MAX_EXPOS) {
- if (((ExpoData *)x)->chn == MAX_INPUTS-1)
- return false;
- ((ExpoData *)x)->chn++;
- return true;
- }
-
- y = (ExpoData *)expoAddress(tgt_idx);
- if(((ExpoData *)x)->chn != ((ExpoData *)y)->chn || !EXPO_VALID((ExpoData *)y)) {
- if (up) {
- if (((ExpoData *)x)->chn>0) ((ExpoData *)x)->chn--;
- else return false;
- }
- else {
- if (((ExpoData *)x)->chnchn++;
- else return false;
- }
- return true;
- }
-
- size = sizeof(ExpoData);
- }
- else {
- x = (MixData *)mixAddress(idx);
-
- if (tgt_idx < 0) {
- if (((MixData *)x)->destCh == 0)
- return false;
- ((MixData *)x)->destCh--;
- return true;
- }
-
- if (tgt_idx == MAX_MIXERS) {
- if (((MixData *)x)->destCh == MAX_OUTPUT_CHANNELS-1)
- return false;
- ((MixData *)x)->destCh++;
- return true;
- }
-
- y = (MixData *)mixAddress(tgt_idx);
- uint8_t destCh = ((MixData *)x)->destCh;
- if(!((MixData *)y)->srcRaw || destCh != ((MixData *)y)->destCh) {
- if (up) {
- if (destCh>0) ((MixData *)x)->destCh--;
- else return false;
- }
- else {
- if (destChdestCh++;
- else return false;
- }
- return true;
- }
-
- size = sizeof(MixData);
- }
-
- pauseMixerCalculations();
- memswap(x, y, size);
- resumeMixerCalculations();
-
- idx = tgt_idx;
- return true;
-}
-
-enum ExposFields {
- EXPO_FIELD_NAME,
- EXPO_FIELD_WEIGHT,
- EXPO_FIELD_EXPO,
- EXPO_FIELD_CURVE,
- CASE_FLIGHT_MODES(EXPO_FIELD_FLIGHT_MODES)
- EXPO_FIELD_SWITCH,
- EXPO_FIELD_SIDE,
- EXPO_FIELD_MAX
-};
-
-#define CURVE_ROWS 0
-
-void menuModelExpoOne(event_t event)
-{
- ExpoData * ed = expoAddress(s_currIdx);
- drawSource(7*FW+FW/2, 0, MIXSRC_Rud+ed->chn, 0);
-
- SUBMENU(STR_MENUINPUTS, EXPO_FIELD_MAX, {0, 0, 0, CURVE_ROWS, CASE_FLIGHT_MODES((MAX_FLIGHT_MODES-1) | NAVIGATION_LINE_BY_LINE) 0 /*, ...*/});
-
- int8_t sub = menuVerticalPosition;
-
- coord_t y = MENU_HEADER_HEIGHT + 1;
-
- for (uint8_t i=0; i0 ? BLINK|INVERS : INVERS) : 0);
- switch (i) {
- case EXPO_FIELD_NAME:
- editSingleName(EXPO_ONE_2ND_COLUMN-sizeof(ed->name)*FW, y, STR_EXPONAME, ed->name, sizeof(ed->name), event, attr);
- break;
-
- case EXPO_FIELD_WEIGHT:
- lcdDrawTextAlignedLeft(y, STR_WEIGHT);
- ed->weight = GVAR_MENU_ITEM(EXPO_ONE_2ND_COLUMN, y, ed->weight, MIN_EXPO_WEIGHT, 100, attr, 0, event);
- break;
-
- case EXPO_FIELD_EXPO:
- lcdDrawTextAlignedLeft(y, STR_EXPO);
- if (ed->curveMode==MODE_EXPO || ed->curveParam==0) {
- ed->curveMode = MODE_EXPO;
- ed->curveParam = GVAR_MENU_ITEM(EXPO_ONE_2ND_COLUMN, y, ed->curveParam, -100, 100, attr, 0, event);
- }
- else {
- lcdDrawText(EXPO_ONE_2ND_COLUMN-3*FW, y, STR_NA, attr);
- }
- break;
-
- case EXPO_FIELD_CURVE:
- lcdDrawTextAlignedLeft(y, STR_CURVE);
- if (ed->curveMode!=MODE_EXPO || ed->curveParam==0) {
- drawCurveName(EXPO_ONE_2ND_COLUMN-3*FW, y, ed->curveParam, attr);
- if (attr) {
- CHECK_INCDEC_MODELVAR_ZERO(event, ed->curveParam, CURVE_BASE+MAX_CURVES-1);
- if (ed->curveParam) ed->curveMode = MODE_CURVE;
- if (ed->curveParam>=CURVE_BASE && event==EVT_KEY_LONG(KEY_ENTER)) {
- s_currIdxSubMenu = ed->curveParam - CURVE_BASE;
- pushMenu(menuModelCurveOne);
- }
- }
- }
- else {
- lcdDrawText(EXPO_ONE_2ND_COLUMN-3*FW, y, STR_NA, attr);
- }
- break;
-
-#if defined(FLIGHT_MODES)
- case EXPO_FIELD_FLIGHT_MODES:
- ed->flightModes = editFlightModes(EXPO_ONE_2ND_COLUMN-EXPO_ONE_FM_WIDTH, y, event, ed->flightModes, attr);
- break;
-#endif
-
- case EXPO_FIELD_SWITCH:
- ed->swtch = editSwitch(EXPO_ONE_2ND_COLUMN-3*FW, y, ed->swtch, attr, event);
- break;
-
- case EXPO_FIELD_SIDE:
- ed->mode = 4 - editChoice(EXPO_ONE_2ND_COLUMN-3*FW, y, STR_SIDE, STR_VCURVEFUNC, 4-ed->mode, 1, 3, attr, event);
- break;
- }
- y += FH;
- }
-
- drawFunction(expoFn);
-
- int16_t x512 = calibratedAnalogs[ed->chn];
- lcdDrawNumber(LCD_W-8, 6*FH, calcRESXto100(x512), 0);
- int16_t y512 = expoFn(x512);
- lcdDrawNumber(LCD_W-8-6*FW, 1*FH, calcRESXto100(y512), 0);
-
- x512 = CURVE_CENTER_X+x512/(RESX/CURVE_SIDE_WIDTH);
- y512 = (LCD_H-1) - ((y512+RESX)/2) * (LCD_H-1) / RESX;
-
- lcdDrawSolidVerticalLine(x512, y512-3, 3*2+1);
- lcdDrawSolidHorizontalLine(x512-3, y512, 3*2+1);
-}
-
-enum MixFields {
- MIX_FIELD_NAME,
- MIX_FIELD_SOURCE,
- MIX_FIELD_WEIGHT,
- MIX_FIELD_OFFSET,
- MIX_FIELD_TRIM,
- MIX_FIELD_CURVE,
- CASE_FLIGHT_MODES(MIX_FIELD_FLIGHT_PHASE)
- MIX_FIELD_SWITCH,
- MIX_FIELD_WARNING,
- MIX_FIELD_MLTPX,
- MIX_FIELD_DELAY_UP,
- MIX_FIELD_DELAY_DOWN,
- MIX_FIELD_SLOW_UP,
- MIX_FIELD_SLOW_DOWN,
- MIX_FIELD_COUNT
-};
-
-#define GAUGE_WIDTH 33
-#define GAUGE_HEIGHT 6
-void drawOffsetBar(uint8_t x, uint8_t y, MixData * md)
-{
- int offset = GET_GVAR(MD_OFFSET(md), GV_RANGELARGE_NEG, GV_RANGELARGE, mixerCurrentFlightMode);
- int weight = GET_GVAR(MD_WEIGHT(md), GV_RANGELARGE_NEG, GV_RANGELARGE, mixerCurrentFlightMode);
- int barMin = offset - weight;
- int barMax = offset + weight;
- if (y > 15) {
- lcdDrawNumber(x-((barMin >= 0) ? 2 : 3), y-6, barMin, TINSIZE|LEFT);
- lcdDrawNumber(x+GAUGE_WIDTH+1, y-6, barMax, TINSIZE);
- }
- if (weight < 0) {
- barMin = -barMin;
- barMax = -barMax;
- }
- if (barMin < -101)
- barMin = -101;
- if (barMax > 101)
- barMax = 101;
- lcdDrawHorizontalLine(x-2, y, GAUGE_WIDTH+2, DOTTED);
- lcdDrawHorizontalLine(x-2, y+GAUGE_HEIGHT, GAUGE_WIDTH+2, DOTTED);
- lcdDrawSolidVerticalLine(x-2, y+1, GAUGE_HEIGHT-1);
- lcdDrawSolidVerticalLine(x+GAUGE_WIDTH-1, y+1, GAUGE_HEIGHT-1);
- if (barMin <= barMax) {
- int8_t right = (barMax * GAUGE_WIDTH) / 200;
- int8_t left = ((barMin * GAUGE_WIDTH) / 200)-1;
- lcdDrawSolidFilledRect(x+GAUGE_WIDTH/2+left, y+2, right-left, GAUGE_HEIGHT-3);
- }
- lcdDrawSolidVerticalLine(x+GAUGE_WIDTH/2-1, y, GAUGE_HEIGHT+1);
- if (barMin == -101) {
- for (uint8_t i=0; i<3; ++i) {
- lcdDrawPoint(x+i, y+4-i);
- lcdDrawPoint(x+3+i, y+4-i);
- }
- }
- if (barMax == 101) {
- for (uint8_t i=0; i<3; ++i) {
- lcdDrawPoint(x+GAUGE_WIDTH-8+i, y+4-i);
- lcdDrawPoint(x+GAUGE_WIDTH-5+i, y+4-i);
- }
- }
-}
-#undef GAUGE_WIDTH
-#undef GAUGE_HEIGHT
-
-void menuModelMixOne(event_t event)
-{
- title(STR_MIXES);
- MixData * md2 = mixAddress(s_currIdx) ;
- putsChn(lcdLastRightPos+1*FW, 0, md2->destCh+1,0);
-
- SUBMENU_NOTITLE(MIX_FIELD_COUNT, {0, 0, 0, 0, 1, 1, CASE_FLIGHT_MODES((MAX_FLIGHT_MODES-1) | NAVIGATION_LINE_BY_LINE) 0, 0 /*, ...*/});
-
- int8_t sub = menuVerticalPosition;
- int8_t editMode = s_editMode;
-
- for (uint8_t k=0; k0 ? BLINK|INVERS : INVERS) : 0);
- switch (i) {
- case MIX_FIELD_NAME:
- editSingleName(COLUMN_X+MIXES_2ND_COLUMN, y, STR_MIXNAME, md2->name, sizeof(md2->name), event, attr);
- break;
- case MIX_FIELD_SOURCE:
- drawFieldLabel(COLUMN_X, y, STR_SOURCE);
- drawSource(COLUMN_X+MIXES_2ND_COLUMN, y, md2->srcRaw, STREXPANDED|attr);
- if (attr) CHECK_INCDEC_MODELSOURCE(event, md2->srcRaw, 1, MIXSRC_LAST);
- break;
- case MIX_FIELD_WEIGHT:
- drawFieldLabel(COLUMN_X, y, STR_WEIGHT);
- gvarWeightItem(COLUMN_X+MIXES_2ND_COLUMN, y, md2, attr|LEFT, event);
- break;
- case MIX_FIELD_OFFSET:
- {
- drawFieldLabel(COLUMN_X, y, STR_OFFSET);
- u_int8int16_t offset;
- MD_OFFSET_TO_UNION(md2, offset);
- offset.word = GVAR_MENU_ITEM(COLUMN_X+MIXES_2ND_COLUMN, y, offset.word, GV_RANGELARGE_OFFSET_NEG, GV_RANGELARGE_OFFSET, attr|LEFT, 0, event);
- MD_UNION_TO_OFFSET(offset, md2);
- drawOffsetBar(COLUMN_X+MIXES_2ND_COLUMN+22, y, md2);
- break;
- }
-
- case MIX_FIELD_TRIM:
- {
- uint8_t not_stick = (md2->srcRaw > NUM_STICKS);
- int8_t carryTrim = -md2->carryTrim;
- drawFieldLabel(COLUMN_X, y, STR_TRIM);
- lcdDrawTextAtIndex((not_stick ? COLUMN_X+MIXES_2ND_COLUMN : COLUMN_X+6*FW-3), y, STR_VMIXTRIMS, (not_stick && carryTrim == 0) ? 0 : carryTrim+1, menuHorizontalPosition==0 ? attr : 0);
- if (attr && menuHorizontalPosition==0 && (not_stick || editMode>0)) md2->carryTrim = -checkIncDecModel(event, carryTrim, not_stick ? TRIM_ON : -TRIM_OFF, -TRIM_AIL);
- if (!not_stick) {
- lcdDrawText(COLUMN_X+MIXES_2ND_COLUMN, y, STR_DREX);
- drawCheckBox(COLUMN_X+MIXES_2ND_COLUMN+DREX_CHBOX_OFFSET, y, !md2->noExpo, menuHorizontalPosition==1 ? attr : 0);
- if (attr && menuHorizontalPosition==1 && editMode>0) md2->noExpo = !checkIncDecModel(event, !md2->noExpo, 0, 1);
- }
- else if (attr) {
- REPEAT_LAST_CURSOR_MOVE();
- }
- break;
- }
-
- case MIX_FIELD_CURVE:
- {
- drawFieldLabel(COLUMN_X, y, STR_CURVE);
- int8_t curveParam = md2->curveParam;
- if (md2->curveMode == MODE_CURVE) {
- drawCurveName(COLUMN_X+MIXES_2ND_COLUMN, y, curveParam, attr);
- if (attr) {
- if (event==EVT_KEY_LONG(KEY_ENTER) && (curveParam<0 || curveParam>=CURVE_BASE)){
- s_currIdxSubMenu = (curveParam<0 ? -curveParam-1 : curveParam-CURVE_BASE);
- pushMenu(menuModelCurveOne);
- }
- else {
- CHECK_INCDEC_MODELVAR(event, md2->curveParam, -MAX_CURVES, CURVE_BASE+MAX_CURVES-1);
- if (md2->curveParam == 0)
- md2->curveMode = MODE_DIFFERENTIAL;
- }
- }
- }
- else {
- lcdDrawText(COLUMN_X+MIXES_2ND_COLUMN, y, "Diff", menuHorizontalPosition==0 ? attr : 0);
- md2->curveParam = GVAR_MENU_ITEM(COLUMN_X+MIXES_2ND_COLUMN+5*FW, y, curveParam, -100, 100, LEFT|(menuHorizontalPosition==1 ? attr : 0), 0, editMode>0 ? event : 0);
- if (attr && editMode>0 && menuHorizontalPosition==0) {
- int8_t tmp = 0;
- CHECK_INCDEC_MODELVAR(event, tmp, -1, 1);
- if (tmp != 0) {
- md2->curveMode = MODE_CURVE;
- md2->curveParam = tmp;
- }
- }
- }
- break;
- }
-#if defined(FLIGHT_MODES)
- case MIX_FIELD_FLIGHT_PHASE:
- md2->flightModes = editFlightModes(COLUMN_X+MIXES_2ND_COLUMN, y, event, md2->flightModes, attr);
- break;
-#endif
- case MIX_FIELD_SWITCH:
- md2->swtch = editSwitch(COLUMN_X+MIXES_2ND_COLUMN, y, md2->swtch, attr, event);
- break;
- case MIX_FIELD_WARNING:
- drawFieldLabel(COLUMN_X+MIXES_2ND_COLUMN, y, STR_MIXWARNING);
- if (md2->mixWarn)
- lcdDrawNumber(COLUMN_X+MIXES_2ND_COLUMN, y, md2->mixWarn, attr|LEFT);
- else
- lcdDrawText(COLUMN_X+MIXES_2ND_COLUMN, y, STR_OFF, attr);
- if (attr) CHECK_INCDEC_MODELVAR_ZERO(event, md2->mixWarn, 3);
- break;
- case MIX_FIELD_MLTPX:
- md2->mltpx = editChoice(COLUMN_X+MIXES_2ND_COLUMN, y, STR_MULTPX, STR_VMLTPX, md2->mltpx, 0, 2, attr, event);
- break;
- case MIX_FIELD_DELAY_UP:
- md2->delayUp = EDIT_DELAY(COLUMN_X, y, event, attr, STR_DELAYUP, md2->delayUp);
- break;
- case MIX_FIELD_DELAY_DOWN:
- md2->delayDown = EDIT_DELAY(COLUMN_X, y, event, attr, STR_DELAYDOWN, md2->delayDown);
- break;
- case MIX_FIELD_SLOW_UP:
- md2->speedUp = EDIT_DELAY(COLUMN_X, y, event, attr, STR_SLOWUP, md2->speedUp);
- break;
- case MIX_FIELD_SLOW_DOWN:
- md2->speedDown = EDIT_DELAY(COLUMN_X, y, event, attr, STR_SLOWDOWN, md2->speedDown);
- break;
- }
- }
-}
-
-#define _STR_MAX(x) "/" #x
-#define STR_MAX(x) _STR_MAX(x)
-
- #define EXPO_LINE_WEIGHT_POS 7*FW+1
- #define EXPO_LINE_EXPO_POS 10*FW+5
- #define EXPO_LINE_SWITCH_POS 11*FW+2
- #define EXPO_LINE_SIDE_POS 14*FW+2
- #define EXPO_LINE_SELECT_POS 24
- #define EXPO_LINE_FM_POS
- #define EXPO_LINE_NAME_POS LCD_W-LEN_EXPOMIX_NAME*FW
- #define MIX_LINE_SRC_POS 4*FW-1
- #define MIX_LINE_WEIGHT_POS 11*FW+3
- #define MIX_LINE_CURVE_POS 12*FW+2
- #define MIX_LINE_SWITCH_POS 16*FW
- #define MIX_LINE_DELAY_POS 19*FW+7
-
-void onExpoMixMenu(const char *result)
-{
- bool expo = (menuHandlers[menuLevel] == menuModelExposAll);
- uint8_t chn = (expo ? expoAddress(s_currIdx)->chn+1 : mixAddress(s_currIdx)->destCh+1);
-
- if (result == STR_EDIT) {
- pushMenu(expo ? menuModelExpoOne : menuModelMixOne);
- }
- else if (result == STR_INSERT_BEFORE || result == STR_INSERT_AFTER) {
- if (!reachExpoMixCountLimit(expo)) {
- s_currCh = chn;
- if (result == STR_INSERT_AFTER) { s_currIdx++; menuVerticalPosition++; }
- insertExpoMix(expo, s_currIdx);
- pushMenu(expo ? menuModelExpoOne : menuModelMixOne);
- }
- }
- else if (result == STR_COPY || result == STR_MOVE) {
- s_copyMode = (result == STR_COPY ? COPY_MODE : MOVE_MODE);
- s_copySrcIdx = s_currIdx;
- s_copySrcCh = chn;
- s_copySrcRow = menuVerticalPosition;
- }
- else if (result == STR_DELETE) {
- deleteExpoMix(expo, s_currIdx);
- }
-}
-
-void displayMixInfos(coord_t y, MixData *md)
-{
- if (md->curveParam) {
- if (md->curveMode == MODE_CURVE)
- drawCurveName(MIX_LINE_CURVE_POS, y, md->curveParam);
- else
- displayGVar(MIX_LINE_CURVE_POS+3*FW, y, md->curveParam, -100, 100);
- }
-
- if (md->swtch) {
- drawSwitch(MIX_LINE_SWITCH_POS, y, md->swtch);
- }
-}
-
-void displayMixLine(coord_t y, MixData * md)
-{
- if (md->name[0]) {
- lcdDrawSizedText(EXPO_LINE_NAME_POS, y, md->name, sizeof(md->name), ZCHAR);
- }
- else {
- displayMixInfos(y, md);
- }
-}
-
-void displayExpoInfos(coord_t y, ExpoData *ed)
-{
- if (ed->curveMode == MODE_CURVE)
- drawCurveName(EXPO_LINE_EXPO_POS-3*FW, y, ed->curveParam);
- else
- displayGVar(EXPO_LINE_EXPO_POS, y, ed->curveParam, -100, 100);
-
- drawSwitch(EXPO_LINE_SWITCH_POS, y, ed->swtch, 0);
-}
-
-void displayExpoLine(coord_t y, ExpoData *ed)
-{
- displayExpoInfos(y, ed);
-
- if (ed->name[0]) {
- lcdDrawSizedText(EXPO_LINE_NAME_POS, y, ed->name, sizeof(ed->name), ZCHAR);
- }
-}
-
-void menuModelExpoMix(uint8_t expo, event_t event)
-{
- uint8_t sub = menuVerticalPosition;
-
- if (s_editMode > 0)
- s_editMode = 0;
-
- uint8_t chn = (expo ? expoAddress(s_currIdx)->chn+1 : mixAddress(s_currIdx)->destCh+1);
-
- switch (event)
- {
- case EVT_ENTRY:
- case EVT_ENTRY_UP:
- s_copyMode = 0;
- s_copyTgtOfs = 0;
- break;
- case EVT_KEY_LONG(KEY_EXIT):
- if (s_copyMode && s_copyTgtOfs == 0) {
- deleteExpoMix(expo, s_currIdx);
- killEvents(event);
- event = 0;
- }
- // no break
-#if defined(ROTARY_ENCODER_NAVIGATION)
- case EVT_ROTARY_LONG:
- if (s_copyMode) {
- killEvents(event);
- }
-#endif
- case EVT_KEY_BREAK(KEY_EXIT):
- if (s_copyMode) {
- if (s_copyTgtOfs) {
- // cancel the current copy / move operation
- if (s_copyMode == COPY_MODE) {
- deleteExpoMix(expo, s_currIdx);
- }
- else {
- do {
- swapExpoMix(expo, s_currIdx, s_copyTgtOfs > 0);
- s_copyTgtOfs += (s_copyTgtOfs < 0 ? +1 : -1);
- } while (s_copyTgtOfs != 0);
- storageDirty(EE_MODEL);
- }
- menuVerticalPosition = s_copySrcRow;
- s_copyTgtOfs = 0;
- }
- s_copyMode = 0;
- event = 0;
- }
- break;
- case EVT_KEY_BREAK(KEY_ENTER):
- if (sub != 0 && (!s_currCh || (s_copyMode && !s_copyTgtOfs)) && !READ_ONLY()) {
- s_copyMode = (s_copyMode == COPY_MODE ? MOVE_MODE : COPY_MODE);
- s_copySrcIdx = s_currIdx;
- s_copySrcCh = chn;
- s_copySrcRow = sub;
- break;
- }
- // no break
-
- case EVT_KEY_LONG(KEY_ENTER):
- killEvents(event);
- if (s_copyTgtOfs) {
- s_copyMode = 0;
- s_copyTgtOfs = 0;
- }
- else if (sub != 0) {
- if (READ_ONLY()) {
- if (!s_currCh) {
- pushMenu(expo ? menuModelExpoOne : menuModelMixOne);
- return;
- }
- }
- else {
- if (s_copyMode) s_currCh = 0;
- if (s_currCh) {
- if (reachExpoMixCountLimit(expo)) break;
- insertExpoMix(expo, s_currIdx);
- pushMenu(expo ? menuModelExpoOne : menuModelMixOne);
- s_copyMode = 0;
- return;
- }
- else {
- event = 0;
- s_copyMode = 0;
- POPUP_MENU_ADD_ITEM(STR_EDIT);
- POPUP_MENU_ADD_ITEM(STR_INSERT_BEFORE);
- POPUP_MENU_ADD_ITEM(STR_INSERT_AFTER);
- POPUP_MENU_ADD_ITEM(STR_COPY);
- POPUP_MENU_ADD_ITEM(STR_MOVE);
- POPUP_MENU_ADD_ITEM(STR_DELETE);
- POPUP_MENU_START(onExpoMixMenu);
- }
- }
- }
- break;
- case EVT_KEY_LONG(KEY_LEFT):
- case EVT_KEY_LONG(KEY_RIGHT):
- if (s_copyMode && !s_copyTgtOfs) {
- if (reachExpoMixCountLimit(expo)) break;
- s_currCh = chn;
- if (event == EVT_KEY_LONG(KEY_RIGHT)) { s_currIdx++; menuVerticalPosition++; }
- insertExpoMix(expo, s_currIdx);
- pushMenu(expo ? menuModelExpoOne : menuModelMixOne);
- s_copyMode = 0;
- killEvents(event);
- return;
- }
- break;
-#if defined(ROTARY_ENCODER_NAVIGATION)
- case EVT_ROTARY_LEFT:
- case EVT_ROTARY_RIGHT:
-#endif
- case EVT_KEY_FIRST(KEY_UP):
- case EVT_KEY_REPT(KEY_UP):
- case EVT_KEY_FIRST(KEY_DOWN):
- case EVT_KEY_REPT(KEY_DOWN):
- if (s_copyMode) {
- uint8_t key = (event & 0x1f);
- uint8_t next_ofs = ((IS_ROTARY_LEFT(event) || key==KEY_UP) ? s_copyTgtOfs - 1 : s_copyTgtOfs + 1);
-
- if (s_copyTgtOfs==0 && s_copyMode==COPY_MODE) {
- // insert a mix on the same channel (just above / just below)
- if (reachExpoMixCountLimit(expo)) break;
- copyExpoMix(expo, s_currIdx);
- if (IS_ROTARY_RIGHT(event) || key==KEY_DOWN) s_currIdx++;
- else if (sub-menuVerticalOffset >= 6) menuVerticalOffset++;
- }
- else if (next_ofs==0 && s_copyMode==COPY_MODE) {
- // delete the mix
- deleteExpoMix(expo, s_currIdx);
- if (IS_ROTARY_LEFT(event) || key==KEY_UP) s_currIdx--;
- }
- else {
- // only swap the mix with its neighbor
- if (!swapExpoMix(expo, s_currIdx, IS_ROTARY_LEFT(event) || key==KEY_UP)) break;
- storageDirty(EE_MODEL);
- }
-
- s_copyTgtOfs = next_ofs;
- }
- break;
- }
-
- lcdDrawNumber(FW*max(sizeof(TR_MENUINPUTS), sizeof(TR_MIXES))+FW+FW/2, 0, getExpoMixCount(expo));
- lcdDrawText(FW*max(sizeof(TR_MENUINPUTS), sizeof(TR_MIXES))+FW+FW/2, 0, expo ? STR_MAX(MAX_EXPOS) : STR_MAX(MAX_MIXERS));
-
- SIMPLE_MENU(expo ? STR_MENUINPUTS : STR_MIXES, menuTabModel, expo ? MENU_MODEL_INPUTS : MENU_MODEL_MIXES, s_maxLines);
-
- sub = menuVerticalPosition;
- s_currCh = 0;
- uint8_t cur = 1;
- uint8_t i = 0;
-
- for (uint8_t ch=1; ch<=(expo ? MAX_INPUTS : MAX_OUTPUT_CHANNELS); ch++) {
- void *pointer = NULL; MixData * &md = (MixData * &)pointer; ExpoData * &ed = (ExpoData * &)pointer;
- coord_t y = MENU_HEADER_HEIGHT-FH+1+(cur-menuVerticalOffset)*FH;
- if (expo ? (ichn+1 == ch && EXPO_VALID(ed)) : (isrcRaw && md->destCh+1 == ch)) {
- if (menuVerticalOffset < cur && cur-menuVerticalOffset < LCD_LINES) {
- if (expo) {
- drawSource(0, y, MIXSRC_Rud+ch-1, 0);
- }
- else {
- putsChn(0, y, ch, 0); // show CHx
- }
- }
- uint8_t mixCnt = 0;
- do {
- if (s_copyMode) {
- if (s_copyMode == MOVE_MODE && menuVerticalOffset < cur && cur-menuVerticalOffset < 8 && s_copySrcCh == ch && s_copyTgtOfs != 0 && i == (s_copySrcIdx + (s_copyTgtOfs<0))) {
- lcdDrawRect(expo ? 18 : 22, y-1, expo ? LCD_W-18 : LCD_W-22, 9, DOTTED);
- cur++; y+=FH;
- }
- if (s_currIdx == i) {
- sub = menuVerticalPosition = cur;
- s_currCh = ch;
- }
- }
- else if (sub == cur) {
- s_currIdx = i;
- }
- if (menuVerticalOffset < cur && cur-menuVerticalOffset < 8) {
- uint8_t attr = ((s_copyMode || sub != cur) ? 0 : INVERS);
- if (expo) {
- ed->weight = GVAR_MENU_ITEM(EXPO_LINE_WEIGHT_POS, y, ed->weight, MIN_EXPO_WEIGHT, 100, attr | (isExpoActive(i) ? BOLD : 0), 0, event);
- displayExpoLine(y, ed);
- if (ed->mode!=3) {
- lcdDrawChar(EXPO_LINE_SIDE_POS, y, ed->mode == 2 ? 126 : 127);
- }
- }
- else {
- if (mixCnt > 0) lcdDrawTextAtIndex(FW, y, STR_VMLTPX2, md->mltpx, 0);
-
- drawSource(MIX_LINE_SRC_POS, y, md->srcRaw, 0);
-
- gvarWeightItem(MIX_LINE_WEIGHT_POS, y, md, attr | (isMixActive(i) ? BOLD : 0), event);
-
- displayMixLine(y, md);
-
- char cs = ' ';
- if (md->speedDown || md->speedUp)
- cs = 'S';
- if (md->delayUp || md->delayDown)
- cs = (cs =='S' ? '*' : 'D');
- lcdDrawChar(MIX_LINE_DELAY_POS, y, cs);
- }
- if (s_copyMode) {
- if ((s_copyMode==COPY_MODE || s_copyTgtOfs == 0) && s_copySrcCh == ch && i == (s_copySrcIdx + (s_copyTgtOfs<0))) {
- /* draw a border around the raw on selection mode (copy/move) */
- lcdDrawRect(expo ? EXPO_LINE_SELECT_POS : 22, y-1, expo ? (LCD_W-EXPO_LINE_SELECT_POS) : (LCD_W-22), 9, s_copyMode == COPY_MODE ? SOLID : DOTTED);
- }
- if (cur == sub) {
- /* invert the raw when it's the current one */
- lcdDrawSolidFilledRect(expo ? EXPO_LINE_SELECT_POS+1 : 23, y, expo ? (LCD_W-EXPO_LINE_SELECT_POS-2) : (LCD_W-24), 7);
- }
- }
- }
- cur++; y+=FH; mixCnt++; i++; if (expo) ed++; else md++;
- } while (expo ? (ichn+1 == ch && EXPO_VALID(ed)) : (isrcRaw && md->destCh+1 == ch));
- if (s_copyMode == MOVE_MODE && menuVerticalOffset < cur && cur-menuVerticalOffset < LCD_LINES && s_copySrcCh == ch && i == (s_copySrcIdx + (s_copyTgtOfs<0))) {
- lcdDrawRect(expo ? EXPO_LINE_SELECT_POS : 22, y-1, expo ? LCD_W-EXPO_LINE_SELECT_POS : LCD_W-22, 9, DOTTED);
- cur++; y+=FH;
- }
- }
- else {
- uint8_t attr = 0;
- if (sub == cur) {
- s_currIdx = i;
- s_currCh = ch;
- if (!s_copyMode) {
- attr = INVERS;
- }
- }
- if (menuVerticalOffset < cur && cur-menuVerticalOffset < LCD_LINES) {
- if (expo) {
- drawSource(0, y, MIXSRC_Rud+ch-1, attr);
- }
- else {
- putsChn(0, y, ch, attr); // show CHx
- }
- if (s_copyMode == MOVE_MODE && s_copySrcCh == ch) {
- lcdDrawRect(expo ? EXPO_LINE_SELECT_POS : 22, y-1, expo ? (LCD_W-EXPO_LINE_SELECT_POS) : (LCD_W-22), 9, DOTTED);
- }
- }
- cur++; y+=FH;
- }
- }
- s_maxLines = cur;
- if (sub >= s_maxLines-1) menuVerticalPosition = s_maxLines-1;
-}
-
-void menuModelExposAll(event_t event)
-{
- return menuModelExpoMix(1, event);
-}
-
-void menuModelMixAll(event_t event)
-{
- return menuModelExpoMix(0, event);
-}
diff --git a/radio/src/gui/128x64/model_mix_edit.cpp b/radio/src/gui/128x64/model_mix_edit.cpp
index a2180b6ac..281256f46 100644
--- a/radio/src/gui/128x64/model_mix_edit.cpp
+++ b/radio/src/gui/128x64/model_mix_edit.cpp
@@ -85,13 +85,18 @@ void drawOffsetBar(uint8_t x, uint8_t y, MixData * md)
void menuModelMixOne(event_t event)
{
-#if defined(NAVIGATION_X7)
- if (event == EVT_KEY_LONG(KEY_MENU)) {
+#if defined(KEYS_GPIO_REG_MDL)
+ if (event == EVT_KEY_FIRST(KEY_MODEL)) {
+ pushMenu(menuChannelsView);
+ killEvents(event);
+ }
+#elif defined(NAVIGATION_X7)
+ if (event == EVT_KEY_FIRST(KEY_MENU)) {
pushMenu(menuChannelsView);
killEvents(event);
}
#elif defined(NAVIGATION_XLITE)
- if (event == EVT_KEY_LONG(KEY_SHIFT)) {
+ if (event == EVT_KEY_FIRST(KEY_ENTER) && IS_SHIFT_PRESSED()) {
pushMenu(menuChannelsView);
killEvents(event);
}
@@ -150,6 +155,8 @@ void menuModelMixOne(event_t event)
case MIX_FIELD_CURVE:
lcdDrawTextAlignedLeft(y, STR_CURVE);
+ s_currSrcRaw = md2->srcRaw;
+ s_currScale = 0;
editCurveRef(MIXES_2ND_COLUMN, y, md2->curve, s_editMode > 0 ? event : 0, attr);
break;
diff --git a/radio/src/gui/128x64/model_select.cpp b/radio/src/gui/128x64/model_select.cpp
index d0184e5ea..bcf04117d 100644
--- a/radio/src/gui/128x64/model_select.cpp
+++ b/radio/src/gui/128x64/model_select.cpp
@@ -36,6 +36,10 @@ void onModelSelectMenu(const char * result)
int8_t sub = menuVerticalPosition;
if (result == STR_SELECT_MODEL || result == STR_CREATE_MODEL) {
+ if (!g_eeGeneral.disableRssiPoweroffAlarm) {
+ if (!confirmModelChange())
+ return;
+ }
selectModel(sub);
}
else if (result == STR_COPY_MODEL) {
@@ -79,7 +83,7 @@ void onModelSelectMenu(const char * result)
void menuModelSelect(event_t event)
{
event_t _event_ = event;
- if ((s_copyMode && EVT_KEY_MASK(event) == KEY_EXIT) || event == EVT_KEY_BREAK(KEY_EXIT) || IS_ROTARY_BREAK(event) || IS_ROTARY_LONG(event)) {
+ if ((s_copyMode && IS_KEY_EVT(event, KEY_EXIT)) || event == EVT_KEY_BREAK(KEY_EXIT) || IS_ROTARY_BREAK(event) || IS_ROTARY_LONG(event)) {
_event_ = 0;
}
@@ -199,7 +203,16 @@ void menuModelSelect(event_t event)
}
break;
-#if defined(NAVIGATION_X7)
+#if defined(KEYS_GPIO_REG_PAGEDN)
+ case EVT_KEY_FIRST(KEY_PAGEUP):
+ chainMenu(menuTabModel[DIM(menuTabModel)-1]);
+ killEvents(event);
+ break;
+
+ case EVT_KEY_FIRST(KEY_PAGEDN):
+ chainMenu(menuModelSetup);
+ break;
+#elif defined(KEYS_GPIO_REG_PAGE)
case EVT_KEY_LONG(KEY_PAGE):
chainMenu(menuTabModel[DIM(menuTabModel)-1]);
killEvents(event);
@@ -231,7 +244,7 @@ void menuModelSelect(event_t event)
#endif
#endif
-#if defined(NAVIGATION_X7)
+#if defined(ROTARY_ENCODER) && defined(NAVIGATION_X7)
case EVT_ROTARY_LEFT:
case EVT_ROTARY_RIGHT:
#endif
diff --git a/radio/src/gui/128x64/model_setup.cpp b/radio/src/gui/128x64/model_setup.cpp
index 4319ed8dc..52a28d497 100644
--- a/radio/src/gui/128x64/model_setup.cpp
+++ b/radio/src/gui/128x64/model_setup.cpp
@@ -66,6 +66,7 @@ enum MenuModelSetupItems {
ITEM_MODEL_SETUP_THROTTLE_REVERSED,
ITEM_MODEL_SETUP_THROTTLE_TRACE,
ITEM_MODEL_SETUP_THROTTLE_TRIM,
+ ITEM_MODEL_SETUP_THROTTLE_TRIM_SWITCH,
ITEM_MODEL_SETUP_PREFLIGHT_LABEL,
ITEM_MODEL_SETUP_CHECKLIST_DISPLAY,
ITEM_MODEL_SETUP_THROTTLE_WARNING,
@@ -91,6 +92,7 @@ enum MenuModelSetupItems {
ITEM_MODEL_SETUP_INTERNAL_MODULE_SYNCSTATUS,
#endif
ITEM_MODEL_SETUP_INTERNAL_MODULE_CHANNELS,
+ ITEM_MODEL_SETUP_INTERNAL_MODULE_RACING_MODE,
ITEM_MODEL_SETUP_INTERNAL_MODULE_NOT_ACCESS_RXNUM_BIND_RANGE,
ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_MODEL_NUM,
ITEM_MODEL_SETUP_INTERNAL_MODULE_OPTIONS,
@@ -110,7 +112,7 @@ enum MenuModelSetupItems {
ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_RECEIVER_2,
ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_RECEIVER_3,
#endif
-
+#if defined(HARDWARE_EXTERNAL_MODULE)
ITEM_MODEL_SETUP_EXTERNAL_MODULE_LABEL,
ITEM_MODEL_SETUP_EXTERNAL_MODULE_TYPE,
#if defined(MULTIMODULE)
@@ -128,9 +130,6 @@ enum MenuModelSetupItems {
ITEM_MODEL_SETUP_EXTERNAL_MODULE_CHANNELS,
ITEM_MODEL_SETUP_EXTERNAL_MODULE_NOT_ACCESS_RXNUM_BIND_RANGE,
ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_MODEL_NUM,
-#if defined(PCBSKY9X) && defined(REVX)
- ITEM_MODEL_SETUP_EXTERNAL_MODULE_OUTPUT_TYPE,
-#endif
#if defined(AFHDS3)
ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_RX_FREQ,
ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_ACTUAL_POWER,
@@ -150,11 +149,15 @@ enum MenuModelSetupItems {
ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_RECEIVER_2,
ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_RECEIVER_3,
+#if defined(PCBSKY9X) && defined(REVX)
+ ITEM_MODEL_SETUP_EXTERNAL_MODULE_OUTPUT_TYPE,
+#endif
#if defined(PCBSKY9X)
ITEM_MODEL_SETUP_EXTRA_MODULE_LABEL,
ITEM_MODEL_SETUP_EXTRA_MODULE_CHANNELS,
ITEM_MODEL_SETUP_EXTRA_MODULE_BIND,
#endif
+#endif
#if defined(PCBTARANIS)
ITEM_MODEL_SETUP_TRAINER_LABEL,
@@ -182,13 +185,16 @@ enum MenuModelSetupItems {
#define REGISTRATION_ID_ROWS
#endif
-#if defined(HARDWARE_INTERNAL_MODULE)
+#if defined(HARDWARE_INTERNAL_MODULE) && defined(HARDWARE_EXTERNAL_MODULE)
#define CURRENT_MODULE_EDITED(k) (k >= ITEM_MODEL_SETUP_EXTERNAL_MODULE_LABEL ? EXTERNAL_MODULE : 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))
#elif defined(PCBSKY9X)
- #define CURRENT_MODULE_EDITED(k) (k >= ITEM_MODEL_SETUP_EXTRA_MODULE_LABEL ? EXTRA_MODULE : EXTERNAL_MODULE)
+ #define CURRENT_MODULE_EDITED(k) (k >= ITEM_MODEL_SETUP_EXTRA_MODULE_LABEL ? EXTRA_MODULE : EXTERNAL_MODULE)
+#elif defined(HARDWARE_INTERNAL_MODULE)
+ #define CURRENT_MODULE_EDITED(k) (INTERNAL_MODULE)
+ #define CURRENT_RECEIVER_EDITED(k) (k - ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_RECEIVER_1)
#else
- #define CURRENT_MODULE_EDITED(k) (EXTERNAL_MODULE)
+ #define CURRENT_MODULE_EDITED(k) (EXTERNAL_MODULE)
#define CURRENT_RECEIVER_EDITED(k) (k - ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_RECEIVER_1)
#endif
@@ -206,8 +212,8 @@ enum MenuModelSetupItems {
#endif
#if defined(PCBSKY9X) && defined(REVX)
- #define OUTPUT_TYPE_ROW (isModulePPM(EXTERNAL_MODULE) ? (uint8_t)0 : HIDDEN_ROW),
-#elif defined(PCBSKY9X)
+ #define OUTPUT_TYPE_ROW (isModulePPM(EXTERNAL_MODULE) ? (uint8_t)0 : HIDDEN_ROW), // Output type (OpenDrain / PushPull)
+#else
#define OUTPUT_TYPE_ROW
#endif
@@ -231,7 +237,8 @@ inline uint8_t MODULE_SUBTYPE_ROWS(int moduleIdx)
}
#define POT_WARN_ROWS ((g_model.potsWarnMode) ? (uint8_t)(NUM_POTS+NUM_SLIDERS) : (uint8_t)0)
-#define TIMER_ROWS 2, 0, 0, 0, 0
+#define TIMER_ROWS(x) 2, 0, 0, 0, g_model.timers[x].countdownBeep != COUNTDOWN_SILENT ? (uint8_t)1 : (uint8_t)0
+#define TIMERS_ROWS TIMER_ROWS(0), TIMER_ROWS(1), TIMER_ROWS(2)
#if defined(PCBSKY9X)
#define EXTRA_MODULE_ROWS LABEL(ExtraModule), 1, 2,
@@ -301,6 +308,27 @@ void onBluetoothConnectMenu(const char * result)
}
#endif
+void editTimerCountdown(int timerIdx, coord_t y, LcdFlags attr, event_t event)
+{
+ TimerData & timer = g_model.timers[timerIdx];
+ lcdDrawTextAlignedLeft(y, STR_BEEPCOUNTDOWN);
+ lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_VBEEPCOUNTDOWN, timer.countdownBeep, (menuHorizontalPosition == 0 ? attr : 0));
+ if (timer.countdownBeep != COUNTDOWN_SILENT) {
+ lcdDrawNumber(MODEL_SETUP_2ND_COLUMN + 6 * FW, y, TIMER_COUNTDOWN_START(timerIdx), (menuHorizontalPosition == 1 ? attr : 0) | LEFT);
+ lcdDrawChar(lcdLastRightPos, y, 's');
+ }
+ if (attr && s_editMode > 0) {
+ switch (menuHorizontalPosition) {
+ case 0:
+ CHECK_INCDEC_MODELVAR(event, timer.countdownBeep, COUNTDOWN_SILENT, COUNTDOWN_COUNT - 1);
+ break;
+ case 1:
+ timer.countdownStart = -checkIncDecModel(event, -timer.countdownStart, -1, +2);
+ break;
+ }
+ }
+}
+
#include "common/stdlcd/model_setup_pxx1.cpp"
#if defined(PXX2)
@@ -318,6 +346,7 @@ void onBluetoothConnectMenu(const char * result)
MULTIMODULE_SUBTYPE_ROWS(INTERNAL_MODULE) /* ITEM_MODEL_SETUP_INTERNAL_MODULE_SUBTYPE */ \
MULTIMODULE_STATUS_ROWS(INTERNAL_MODULE) /* ITEM_MODEL_SETUP_INTERNAL_MODULE_STATUS, ITEM_MODEL_SETUP_INTERNAL_MODULE_SYNCSTATUS */ \
MODULE_CHANNELS_ROWS(INTERNAL_MODULE), /* ITEM_MODEL_SETUP_INTERNAL_MODULE_CHANNELS */ \
+ IF_ALLOW_RACING_MODE(INTERNAL_MODULE), /* ITEM_MODEL_SETUP_INTERNAL_MODULE_RACING_MODE */ \
IF_NOT_ACCESS_MODULE_RF(INTERNAL_MODULE, MODULE_BIND_ROWS(INTERNAL_MODULE)), /* *ITEM_MODEL_SETUP_INTERNAL_MODULE_NOT_ACCESS_RXNUM_BIND_RANGE */\
IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 0), /* ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_MODEL_NUM */ \
MODULE_OPTION_ROW(INTERNAL_MODULE), /* ITEM_MODEL_SETUP_INTERNAL_MODULE_OPTIONS */ \
@@ -334,19 +363,53 @@ void onBluetoothConnectMenu(const char * result)
#define INTERNAL_MODULE_ROWS
#endif
+#if defined(HARDWARE_EXTERNAL_MODULE)
+ #define EXTERNAL_MODULE_ROWS \
+ LABEL(ExternalModule), \
+ MODULE_TYPE_ROWS(EXTERNAL_MODULE), \
+ MULTIMODULE_TYPE_ROWS(EXTERNAL_MODULE) /* PROTOCOL */ \
+ MULTIMODULE_SUBTYPE_ROWS(EXTERNAL_MODULE) /* SUBTYPE */ \
+ MULTIMODULE_STATUS_ROWS(EXTERNAL_MODULE) \
+ AFHDS3_PROTOCOL_ROW(EXTERNAL_MODULE) \
+ AFHDS3_MODE_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 */ \
+ AFHDS3_MODULE_ROWS(EXTERNAL_MODULE) \
+ MODULE_POWER_ROW(EXTERNAL_MODULE), \
+ IF_NOT_PXX2_MODULE(EXTERNAL_MODULE, MODULE_OPTION_ROW(EXTERNAL_MODULE)), \
+ MULTIMODULE_MODULE_ROWS(EXTERNAL_MODULE) \
+ FAILSAFE_ROWS(EXTERNAL_MODULE), /* ITEM_MODEL_SETUP_EXTERNAL_MODULE_FAILSAFE */ \
+ IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 1), /* Range check and Register buttons */ \
+ IF_PXX2_MODULE(EXTERNAL_MODULE, 0), /* Module options */ \
+ IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 0), /* Receiver 1 */ \
+ IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 0), /* Receiver 2 */ \
+ IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 0), /* Receiver 3 */
+#else
+ #define EXTERNAL_MODULE_ROWS
+#endif
+
+#if defined(PCBTARANIS)
+ #define WARN_ROWS \
+ SW_WARN_ROWS, /* Switch warning */ \
+ POT_WARN_ROWS, /* Pot warning */
+#else
+ #define WARN_ROWS \
+ NUM_SWITCHES - 1, /* Switch warning */
+#endif
+
void menuModelSetup(event_t event)
{
int8_t old_editMode = s_editMode;
#if defined(PCBTARANIS)
int8_t old_posHorz = menuHorizontalPosition;
+#endif
MENU_TAB({
HEADER_LINE_COLUMNS
0,
- TIMER_ROWS,
- TIMER_ROWS,
- TIMER_ROWS,
+ TIMERS_ROWS,
0, // Extended limits
1, // Extended trims
0, // Show trims
@@ -354,12 +417,12 @@ void menuModelSetup(event_t event)
0, // Throttle reverse
0, // Throttle trace source
0, // Throttle trim
+ 0, // Throttle trim switch
LABEL(PreflightCheck),
0, // Checklist
0, // Throttle warning
- SW_WARN_ROWS, // Switch warning
- POT_WARN_ROWS, // Pot warning
+ WARN_ROWS
NUM_STICKS + NUM_POTS + NUM_SLIDERS - 1, // Center beeps
0, // Global functions
@@ -368,76 +431,14 @@ void menuModelSetup(event_t event)
INTERNAL_MODULE_ROWS
- LABEL(ExternalModule),
- MODULE_TYPE_ROWS(EXTERNAL_MODULE),
- MULTIMODULE_TYPE_ROWS(EXTERNAL_MODULE) // PROTOCOL
- MULTIMODULE_SUBTYPE_ROWS(EXTERNAL_MODULE) // SUBTYPE
- MULTIMODULE_STATUS_ROWS(EXTERNAL_MODULE)
- AFHDS3_PROTOCOL_ROW(EXTERNAL_MODULE)
- AFHDS3_MODE_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
- AFHDS3_MODULE_ROWS(EXTERNAL_MODULE)
- MODULE_POWER_ROW(EXTERNAL_MODULE),
- IF_NOT_PXX2_MODULE(EXTERNAL_MODULE, MODULE_OPTION_ROW(EXTERNAL_MODULE)),
- MULTIMODULE_MODULE_ROWS(EXTERNAL_MODULE)
- FAILSAFE_ROWS(EXTERNAL_MODULE), //ITEM_MODEL_SETUP_EXTERNAL_MODULE_FAILSAFE
- IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 1), // Range check and Register buttons
- IF_PXX2_MODULE(EXTERNAL_MODULE, 0), // Module options
- IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 0), // Receiver 1
- IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 0), // Receiver 2
- IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 0), // Receiver 3
+ EXTERNAL_MODULE_ROWS
- TRAINER_ROWS
- });
-#else
- MENU_TAB({
- HEADER_LINE_COLUMNS
- 0,
- TIMER_ROWS,
- TIMER_ROWS,
- TIMER_ROWS,
- 0, // Extended limits
- 1, // Extended trims
- 0, // Show trims
- 0, // Trims step
- 0, // Throttle reverse
- 0, // Throttle trace source
- 0, // Throttle trim
-
- LABEL(PreflightCheck),
- 0, // Checklist
- 0, // Throttle warning
- NUM_SWITCHES-1, // Switch warning
-
- NUM_STICKS+NUM_POTS+NUM_SLIDERS-1, // Center beeps
- 0, // Global functions
-
- LABEL(ExternalModule),
- MODULE_TYPE_ROWS(EXTERNAL_MODULE),
- MULTIMODULE_TYPE_ROWS(EXTERNAL_MODULE)
- MULTIMODULE_SUBTYPE_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)), // line reused for PPM: PPM settings
- IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 0), // RxNum
- 0, // Output type (OpenDrain / PushPull)
- MODULE_POWER_ROW(EXTERNAL_MODULE),
- IF_NOT_PXX2_MODULE(EXTERNAL_MODULE, MODULE_OPTION_ROW(EXTERNAL_MODULE)),
- MULTIMODULE_MODULE_ROWS(EXTERNAL_MODULE)
- FAILSAFE_ROWS(EXTERNAL_MODULE),
- IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 1), // Range check and Register buttons
- IF_PXX2_MODULE(EXTERNAL_MODULE, 0), // Module options
- IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 0), // Receiver 1
- IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 0), // Receiver 2
- IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 0), // Receiver 3
+ OUTPUT_TYPE_ROW
EXTRA_MODULE_ROWS
+
TRAINER_ROWS
});
-#endif
MENU_CHECK(menuTabModel, MENU_MODEL_SETUP, HEADER_LINE + ITEM_MODEL_SETUP_LINES_COUNT);
title(STR_MENUSETUP);
@@ -475,7 +476,7 @@ void menuModelSetup(event_t event)
}
uint8_t moduleIdx = CURRENT_MODULE_EDITED(k);
- LcdFlags blink = ((s_editMode>0) ? BLINK|INVERS : INVERS);
+ LcdFlags blink = ((s_editMode > 0) ? BLINK|INVERS : INVERS);
LcdFlags attr = (sub == k ? blink : 0);
switch (k) {
@@ -506,7 +507,7 @@ void menuModelSetup(event_t event)
timerMode += TMRMODE_COUNT-1;
timer->mode = timerMode;
#if defined(AUTOSWITCH)
- if (s_editMode>0) {
+ if (s_editMode > 0) {
int8_t val = timer->mode - (TMRMODE_COUNT-1);
int8_t switchVal = checkIncDecMovedSwitch(val);
if (val != switchVal) {
@@ -554,8 +555,7 @@ void menuModelSetup(event_t event)
case ITEM_MODEL_SETUP_TIMER2_COUNTDOWN_BEEP:
case ITEM_MODEL_SETUP_TIMER3_COUNTDOWN_BEEP:
{
- TimerData * timer = &g_model.timers[k>=ITEM_MODEL_SETUP_TIMER3 ? 2 : (k>=ITEM_MODEL_SETUP_TIMER2 ? 1 : 0)];
- timer->countdownBeep = editChoice(MODEL_SETUP_2ND_COLUMN, y, STR_BEEPCOUNTDOWN, STR_VBEEPCOUNTDOWN, timer->countdownBeep, COUNTDOWN_SILENT, COUNTDOWN_COUNT-1, attr, event);
+ editTimerCountdown(k>=ITEM_MODEL_SETUP_TIMER3 ? 2 : (k>=ITEM_MODEL_SETUP_TIMER2 ? 1 : 0), y, attr, event);
break;
}
@@ -617,6 +617,13 @@ void menuModelSetup(event_t event)
ON_OFF_MENU_ITEM(g_model.thrTrim, MODEL_SETUP_2ND_COLUMN, y, STR_TTRIM, attr, event);
break;
+ case ITEM_MODEL_SETUP_THROTTLE_TRIM_SWITCH:
+ lcdDrawTextAlignedLeft(y, STR_TTRIM_SW);
+ if (attr)
+ CHECK_INCDEC_MODELVAR_ZERO(event, g_model.thrTrimSw, NUM_TRIMS - 1);
+ drawSource(MODEL_SETUP_2ND_COLUMN, y, g_model.getThrottleStickTrimSource(), attr);
+ break;
+
case ITEM_MODEL_SETUP_PREFLIGHT_LABEL:
lcdDrawTextAlignedLeft(y, STR_PREFLIGHT);
break;
@@ -847,7 +854,7 @@ void menuModelSetup(event_t event)
#if !defined(INTERNAL_MODULE_MULTI)
case ITEM_MODEL_SETUP_INTERNAL_MODULE_TYPE:
{
- lcdDrawTextAlignedLeft(y, INDENT TR_MODE);
+ lcdDrawText(INDENT_WIDTH, y, STR_MODE);
#if defined(INTERNAL_MODULE_PXX1)
lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_INTERNAL_MODULE_PROTOCOLS, g_model.moduleData[INTERNAL_MODULE].type, menuHorizontalPosition==0 ? attr : 0);
if (isModuleXJT(INTERNAL_MODULE))
@@ -902,14 +909,18 @@ void menuModelSetup(event_t event)
break;
#endif
+#if defined(HARDWARE_EXTERNAL_MODULE)
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_LABEL:
lcdDrawTextAlignedLeft(y, STR_EXTERNALRF);
break;
+#endif
#if defined(INTERNAL_MODULE_MULTI)
case ITEM_MODEL_SETUP_INTERNAL_MODULE_TYPE:
#endif
+#if defined(HARDWARE_EXTERNAL_MODULE)
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_TYPE:
+#endif
lcdDrawTextAlignedLeft(y, INDENT TR_MODE);
lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_EXTERNAL_MODULE_PROTOCOLS, moduleIdx == EXTERNAL_MODULE ? reusableBuffer.moduleSetup.newType : g_model.moduleData[moduleIdx].type, menuHorizontalPosition==0 ? attr : 0);
if (isModuleXJT(moduleIdx))
@@ -1003,7 +1014,9 @@ void menuModelSetup(event_t event)
#if defined(HARDWARE_INTERNAL_MODULE)
case ITEM_MODEL_SETUP_INTERNAL_MODULE_PROTOCOL:
#endif
+#if defined(HARDWARE_EXTERNAL_MODULE)
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_PROTOCOL:
+#endif
{
lcdDrawTextAlignedLeft(y, TR_TYPE);
int multi_rfProto = g_model.moduleData[moduleIdx].getMultiProtocol();
@@ -1042,7 +1055,9 @@ void menuModelSetup(event_t event)
#if defined(HARDWARE_INTERNAL_MODULE)
case ITEM_MODEL_SETUP_INTERNAL_MODULE_SUBTYPE:
#endif
+#if defined(HARDWARE_EXTERNAL_MODULE)
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_SUBTYPE:
+#endif
{
lcdDrawTextAlignedLeft(y, STR_SUBTYPE);
lcdDrawMultiSubProtocolString(MODEL_SETUP_2ND_COLUMN, y, moduleIdx, g_model.moduleData[moduleIdx].subType, attr);
@@ -1063,7 +1078,7 @@ void menuModelSetup(event_t event)
#if defined(AFHDS3)
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS_PROTOCOL:
- lcdDrawTextAlignedLeft(y, TR_PROTO);
+ lcdDrawText(INDENT_WIDTH, y, STR_PROTOCOL);
lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_AFHDS3_PROTOCOLS, g_model.moduleData[EXTERNAL_MODULE].subType, attr);
if (attr && s_editMode > 0 && menuHorizontalPosition == 0) {
CHECK_INCDEC_MODELVAR(event, g_model.moduleData[moduleIdx].subType, AFHDS_SUBTYPE_FIRST, AFHDS_SUBTYPE_LAST);
@@ -1085,7 +1100,7 @@ void menuModelSetup(event_t event)
lcdDrawTextAlignedLeft(y, INDENT TR_MODE);
lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_VTRAINERMODES, g_model.trainerData.mode, attr);
if (attr) {
- g_model.trainerData.mode = checkIncDec(event, g_model.trainerData.mode, 0, TRAINER_MODE_MAX(), EE_MODEL, isTrainerModeAvailable);
+ g_model.trainerData.mode = checkIncDec(event, g_model.trainerData.mode, TRAINER_MODE_MIN(), TRAINER_MODE_MAX(), EE_MODEL, isTrainerModeAvailable);
#if defined(BLUETOOTH)
if (checkIncDec_Ret) {
bluetooth.state = BLUETOOTH_STATE_OFF;
@@ -1172,7 +1187,9 @@ void menuModelSetup(event_t event)
#if defined(PCBSKY9X)
case ITEM_MODEL_SETUP_EXTRA_MODULE_CHANNELS:
#endif
+#if defined(HARDWARE_EXTERNAL_MODULE)
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_CHANNELS:
+#endif
{
ModuleData & moduleData = g_model.moduleData[moduleIdx];
lcdDrawTextAlignedLeft(y, STR_CHANNELRANGE);
@@ -1199,6 +1216,16 @@ void menuModelSetup(event_t event)
break;
}
+#if defined(HARDWARE_INTERNAL_MODULE)
+ case ITEM_MODEL_SETUP_INTERNAL_MODULE_RACING_MODE:
+ {
+ ModuleData & moduleData = g_model.moduleData[moduleIdx];
+ lcdDrawText(INDENT_WIDTH, y, STR_RACING_MODE);
+ moduleData.pxx2.racingMode = editCheckBox(moduleData.pxx2.racingMode, MODEL_SETUP_2ND_COLUMN, y, "", attr, event);
+ break;
+ }
+#endif
+
#if defined(PCBX7) || defined(PCBX9LITE) || defined(PCBXLITE)
case ITEM_MODEL_SETUP_TRAINER_PPM_PARAMS:
lcdDrawTextAlignedLeft(y, STR_PPMFRAME);
@@ -1298,7 +1325,9 @@ void menuModelSetup(event_t event)
#if defined(HARDWARE_INTERNAL_MODULE)
case ITEM_MODEL_SETUP_INTERNAL_MODULE_NOT_ACCESS_RXNUM_BIND_RANGE:
#endif
+#if defined(HARDWARE_EXTERNAL_MODULE)
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_NOT_ACCESS_RXNUM_BIND_RANGE:
+#endif
{
ModuleData & moduleData = g_model.moduleData[moduleIdx];
if (isModulePPM(moduleIdx)) {
@@ -1345,15 +1374,12 @@ void menuModelSetup(event_t event)
if (isModuleRxNumAvailable(moduleIdx)) {
lcdDrawNumber(MODEL_SETUP_2ND_COLUMN, y, g_model.header.modelId[moduleIdx], (l_posHorz==0 ? attr : 0) | LEADING0|LEFT, 2);
bindButtonPos = lcdNextPos + 2;
- }
- else if (attr) {
- l_posHorz += 1;
- }
- if (isModuleBindRangeAvailable(moduleIdx)) {
if (attr && l_posHorz == 0) {
if (s_editMode > 0) {
CHECK_INCDEC_MODELVAR_ZERO(event, g_model.header.modelId[moduleIdx], getMaxRxNum(moduleIdx));
if (checkIncDec_Ret) {
+ if (isModuleCrossfire(moduleIdx))
+ moduleState[EXTERNAL_MODULE].counter = CRSF_FRAME_MODELID;
modelHeaders[g_eeGeneral.currModel].modelId[moduleIdx] = g_model.header.modelId[moduleIdx];
}
else if (event == EVT_KEY_LONG(KEY_ENTER)) {
@@ -1366,6 +1392,11 @@ void menuModelSetup(event_t event)
}
}
}
+ }
+ else if (attr) {
+ l_posHorz += 1;
+ }
+ if (isModuleBindRangeAvailable(moduleIdx)) {
lcdDrawText(bindButtonPos, y, STR_MODULE_BIND, l_posHorz == 1 ? attr : 0);
if (isModuleRangeAvailable(moduleIdx)) {
lcdDrawText(lcdNextPos + 2, y, STR_MODULE_RANGE, l_posHorz == 2 ? attr : 0);
@@ -1450,7 +1481,9 @@ void menuModelSetup(event_t event)
#if defined(HARDWARE_INTERNAL_MODULE)
case ITEM_MODEL_SETUP_INTERNAL_MODULE_FAILSAFE:
#endif
+#if defined(HARDWARE_EXTERNAL_MODULE)
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_FAILSAFE:
+#endif
{
ModuleData &moduleData = g_model.moduleData[moduleIdx];
lcdDrawTextAlignedLeft(y, STR_FAILSAFE);
@@ -1473,7 +1506,6 @@ void menuModelSetup(event_t event)
if (event == EVT_KEY_LONG(KEY_ENTER)) {
killEvents(event);
setCustomFailsafe(moduleIdx);
- storageDirty(EE_MODEL);
AUDIO_WARNING1();
SEND_FAILSAFE_NOW(moduleIdx);
}
@@ -1511,44 +1543,41 @@ void menuModelSetup(event_t event)
#if defined(HARDWARE_INTERNAL_MODULE)
case ITEM_MODEL_SETUP_INTERNAL_MODULE_OPTIONS:
#endif
+#if defined(HARDWARE_EXTERNAL_MODULE)
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_OPTIONS:
+#endif
{
#if defined(MULTIMODULE)
if (MULTIMODULE_PROTOCOL_KNOWN(moduleIdx)) {
+ const char * title = getMultiOptionTitle(moduleIdx);
+
+ lcdDrawText(INDENT_WIDTH, y, title);
+ if (title == STR_MULTI_RFTUNE) {
+ lcdDrawText(MODEL_SETUP_2ND_COLUMN + 23, y, "RSSI(", LEFT);
+ lcdDrawNumber(lcdLastRightPos, y, TELEMETRY_RSSI(), LEFT);
+ lcdDrawText(lcdLastRightPos, y, ")", LEFT);
+ }
+
int optionValue = g_model.moduleData[moduleIdx].multi.optionValue;
-
- MultiModuleStatus &status = getMultiModuleStatus(moduleIdx);
const uint8_t multi_proto = g_model.moduleData[moduleIdx].getMultiProtocol();
-
- if (status.isValid()) {
- MultiModuleStatus &status = getMultiModuleStatus(moduleIdx);
- lcdDrawText(INDENT_WIDTH, y, mm_options_strings::options[status.optionDisp]);
- if (attr && status.optionDisp == 2) {
- lcdDrawText(MODEL_SETUP_2ND_COLUMN + 23, y, "RSSI(", LEFT);
- lcdDrawNumber(lcdLastRightPos, y, TELEMETRY_RSSI(), LEFT);
- lcdDrawText(lcdLastRightPos, y, ")", LEFT);
- }
- }
- else {
- const mm_protocol_definition * pdef = getMultiProtocolDefinition(multi_proto);
- if (pdef->optionsstr) {
- lcdDrawText(INDENT_WIDTH, y, pdef->optionsstr);
- if (attr && pdef->optionsstr == STR_MULTI_RFTUNE) {
- lcdDrawText(MODEL_SETUP_2ND_COLUMN + 23, y, "RSSI(", LEFT);
- lcdDrawNumber(lcdLastRightPos, y, TELEMETRY_RSSI(), LEFT);
- lcdDrawText(lcdLastRightPos, y, ")", LEFT);
- }
- }
- }
-
int8_t min, max;
getMultiOptionValues(multi_proto, min, max);
- if (multi_proto == MODULE_SUBTYPE_MULTI_FS_AFHDS2A) {
+ if (title == STR_MULTI_RFPOWER) {
+ lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_MULTI_POWER, optionValue, LEFT | attr);
+ min = 0;
+ max = 15;
+ }
+ else if (title == STR_MULTI_TELEMETRY) {
+ lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_MULTI_TELEMETRY_MODE, optionValue, LEFT | attr);
+ }
+ else if (multi_proto == MODULE_SUBTYPE_MULTI_FS_AFHDS2A) {
lcdDrawNumber(MODEL_SETUP_2ND_COLUMN, y, 50 + 5 * optionValue, LEFT | attr);
}
- else if (multi_proto == MODULE_SUBTYPE_MULTI_FRSKY_R9) {
- lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_MULTI_POWER, optionValue, LEFT | attr);
+ else if (title == STR_MULTI_WBUS) {
+ lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_MULTI_WBUS_MODE, optionValue, LEFT | attr);
+ min = 0;
+ max = 1;
}
else if (multi_proto == MODULE_SUBTYPE_MULTI_DSM2) {
optionValue = optionValue & 0x01;
@@ -1590,7 +1619,9 @@ void menuModelSetup(event_t event)
#if defined(INTERNAL_MODULE_MULTI)
case ITEM_MODEL_SETUP_INTERNAL_MODULE_POWER:
#endif
+#if defined(HARDWARE_EXTERNAL_MODULE)
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_POWER:
+#endif
{
auto & module = g_model.moduleData[moduleIdx];
// Lite FCC / Lite FLEX / Lite Pro Flex
@@ -1675,7 +1706,9 @@ void menuModelSetup(event_t event)
#if defined(HARDWARE_INTERNAL_MODULE)
case ITEM_MODEL_SETUP_INTERNAL_MODULE_AUTOBIND:
#endif
+#if defined(HARDWARE_EXTERNAL_MODULE)
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_AUTOBIND:
+#endif
if (g_model.moduleData[moduleIdx].getMultiProtocol() == MODULE_SUBTYPE_MULTI_DSM2) {
int8_t value = (g_model.moduleData[moduleIdx].multi.optionValue & 0x02) >> 1;
lcdDrawText(INDENT_WIDTH, y, STR_MULTI_SERVOFREQ);
@@ -1696,13 +1729,17 @@ void menuModelSetup(event_t event)
#if defined(HARDWARE_INTERNAL_MODULE)
case ITEM_MODEL_SETUP_INTERNAL_MODULE_DISABLE_TELEM:
#endif
+#if defined(HARDWARE_EXTERNAL_MODULE)
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_DISABLE_TELEM:
+#endif
g_model.moduleData[moduleIdx].multi.disableTelemetry = editCheckBox(g_model.moduleData[moduleIdx].multi.disableTelemetry, MODEL_SETUP_2ND_COLUMN, y, INDENT TR_DISABLE_TELEM, attr, event);
break;
#if defined(HARDWARE_INTERNAL_MODULE)
case ITEM_MODEL_SETUP_INTERNAL_MODULE_DISABLE_MAPPING:
#endif
+#if defined(HARDWARE_EXTERNAL_MODULE)
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_DISABLE_MAPPING:
+#endif
g_model.moduleData[moduleIdx].multi.disableMapping = editCheckBox(g_model.moduleData[moduleIdx].multi.disableMapping, MODEL_SETUP_2ND_COLUMN, y, INDENT TR_DISABLE_CH_MAP, attr, event);
break;
#endif
@@ -1727,7 +1764,10 @@ void menuModelSetup(event_t event)
#if defined(HARDWARE_INTERNAL_MODULE)
case ITEM_MODEL_SETUP_INTERNAL_MODULE_STATUS:
#endif
- case ITEM_MODEL_SETUP_EXTERNAL_MODULE_STATUS: {
+#if defined(HARDWARE_EXTERNAL_MODULE)
+ case ITEM_MODEL_SETUP_EXTERNAL_MODULE_STATUS:
+#endif
+ {
lcdDrawTextAlignedLeft(y, STR_MODULE_STATUS);
char statusText[64];
@@ -1738,7 +1778,10 @@ void menuModelSetup(event_t event)
#if defined(HARDWARE_INTERNAL_MODULE)
case ITEM_MODEL_SETUP_INTERNAL_MODULE_SYNCSTATUS:
#endif
- case ITEM_MODEL_SETUP_EXTERNAL_MODULE_SYNCSTATUS: {
+#if defined(HARDWARE_EXTERNAL_MODULE)
+ case ITEM_MODEL_SETUP_EXTERNAL_MODULE_SYNCSTATUS:
+#endif
+ {
lcdDrawTextAlignedLeft(y, STR_MODULE_SYNC);
char statusText[64];
getModuleSyncStatusString(moduleIdx, statusText);
@@ -1836,11 +1879,13 @@ void menuModelSetup(event_t event)
checkModelIdUnique(g_eeGeneral.currModel, EXTRA_MODULE);
break;
#endif
+#if defined(HARDWARE_EXTERNAL_MODULE)
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_NOT_ACCESS_RXNUM_BIND_RANGE:
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_MODEL_NUM:
if (menuHorizontalPosition == 0)
checkModelIdUnique(g_eeGeneral.currModel, EXTERNAL_MODULE);
break;
+#endif
}
}
}
diff --git a/radio/src/gui/128x64/model_special_functions.cpp b/radio/src/gui/128x64/model_special_functions.cpp
index 2eaad8f2b..e74c8b21b 100644
--- a/radio/src/gui/128x64/model_special_functions.cpp
+++ b/radio/src/gui/128x64/model_special_functions.cpp
@@ -276,10 +276,12 @@ void menuSpecialFunctions(event_t event, CustomFunctionData * functions, CustomF
lcdDrawNumber(MODEL_SPECIAL_FUNC_3RD_COLUMN, y, val_displayed, attr|LEFT);
}
#endif // OVERRIDE_CHANNEL_FUNCTION
- else if (func >= FUNC_SET_FAILSAFE && func <= FUNC_BIND) {
+#if defined(DANGEROUS_MODULE_FUNCTIONS)
+ else if (func >= FUNC_RANGECHECK && func <= FUNC_BIND) {
val_max = NUM_MODULES-1;
lcdDrawTextAtIndex(MODEL_SPECIAL_FUNC_3RD_COLUMN, y, "\004Int.Ext.", CFN_PARAM(cfn), attr);
}
+#endif
else if (func == FUNC_SET_TIMER) {
getMixSrcRange(MIXSRC_FIRST_TIMER, val_min, val_max);
drawTimer(MODEL_SPECIAL_FUNC_3RD_COLUMN, y, val_displayed, attr|LEFT, attr);
@@ -338,6 +340,14 @@ void menuSpecialFunctions(event_t event, CustomFunctionData * functions, CustomF
INCDEC_ENABLE_CHECK(isSourceAvailable);
}
}
+ else if (func == FUNC_BACKLIGHT) {
+ val_max = MIXSRC_LAST_CH;
+ drawSource(MODEL_SPECIAL_FUNC_3RD_COLUMN, y, val_displayed, attr);
+ if (active) {
+ INCDEC_SET_FLAG(eeFlags | INCDEC_SOURCE);
+ INCDEC_ENABLE_CHECK(isSourceAvailable);
+ }
+ }
#if defined(SDCARD)
else if (func == FUNC_LOGS) {
if (val_displayed) {
diff --git a/radio/src/gui/128x64/model_telemetry.cpp b/radio/src/gui/128x64/model_telemetry.cpp
index 652b89c4f..3cc9c3e7e 100644
--- a/radio/src/gui/128x64/model_telemetry.cpp
+++ b/radio/src/gui/128x64/model_telemetry.cpp
@@ -236,14 +236,7 @@ void menuModelTelemetry(event_t event)
break;
case ITEM_TELEMETRY_RSSI_LABEL:
-#if defined(MULTIMODULE)
- if (telemetryProtocol == PROTOCOL_TELEMETRY_MULTIMODULE && (g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol() == MODULE_SUBTYPE_MULTI_FS_AFHDS2A || g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol() == MODULE_SUBTYPE_MULTI_HOTT))
- lcdDrawTextAlignedLeft(y, "RQly");
- else
- lcdDrawTextAlignedLeft(y, "RSSI");
-#else
- lcdDrawTextAlignedLeft(y, "RSSI");
-#endif
+ lcdDrawTextAlignedLeft(y, getRssiLabel());
break;
case ITEM_TELEMETRY_RSSI_SOURCE: {
diff --git a/radio/src/gui/128x64/radio_diagkeys.cpp b/radio/src/gui/128x64/radio_diagkeys.cpp
index a3d058c3e..803ff7eb7 100644
--- a/radio/src/gui/128x64/radio_diagkeys.cpp
+++ b/radio/src/gui/128x64/radio_diagkeys.cpp
@@ -49,10 +49,15 @@ void menuRadioDiagKeys(event_t event)
displayKeyState(i&1? 20*FW : 18*FW, y, TRM_BASE+i);
}
- if (i <= KEY_MAX) {
- y = MENU_HEADER_HEIGHT + 1 + FH*i;
+ if (i == 7) {
+ y = MENU_HEADER_HEIGHT + 1 + FH * 6;
+ lcdDrawTextAtIndex(8, y, STR_VKEYS, i, 0);
+ displayKeyState(lcdNextPos + 10, y, i);
+ }
+ else if (i <= KEY_MAX) {
+ y = MENU_HEADER_HEIGHT + 1 + FH * i;
lcdDrawTextAtIndex(0, y, STR_VKEYS, i, 0);
- displayKeyState(5*FW+2, y, i);
+ displayKeyState(5 * FW + 2, y, i);
}
#if defined(PCBSKY9X)
diff --git a/radio/src/gui/128x64/radio_setup.cpp b/radio/src/gui/128x64/radio_setup.cpp
index e3fd06bb3..26b80cb0f 100644
--- a/radio/src/gui/128x64/radio_setup.cpp
+++ b/radio/src/gui/128x64/radio_setup.cpp
@@ -79,13 +79,13 @@ enum {
ITEM_RADIO_SETUP_MEMORY_WARNING,
ITEM_RADIO_SETUP_ALARM_WARNING,
ITEM_RADIO_SETUP_RSSI_POWEROFF_ALARM,
- ITEM_RADIO_SETUP_BACKLIGHT_LABEL,
- ITEM_RADIO_SETUP_BACKLIGHT_MODE,
- ITEM_RADIO_SETUP_BACKLIGHT_DELAY,
- ITEM_RADIO_SETUP_BRIGHTNESS,
+ CASE_BACKLIGHT(ITEM_RADIO_SETUP_BACKLIGHT_LABEL)
+ CASE_BACKLIGHT(ITEM_RADIO_SETUP_BACKLIGHT_MODE)
+ CASE_BACKLIGHT(ITEM_RADIO_SETUP_BACKLIGHT_DELAY)
+ CASE_BACKLIGHT(ITEM_RADIO_SETUP_BRIGHTNESS)
CASE_PWM_BACKLIGHT(ITEM_RADIO_SETUP_BACKLIGHT_BRIGHTNESS_OFF)
CASE_PWM_BACKLIGHT(ITEM_RADIO_SETUP_BACKLIGHT_BRIGHTNESS_ON)
- ITEM_RADIO_SETUP_FLASH_BEEP,
+ CASE_BACKLIGHT(ITEM_RADIO_SETUP_FLASH_BEEP)
CASE_SPLASH_PARAM(ITEM_RADIO_SETUP_DISABLE_SPLASH)
CASE_PWR_BUTTON_PRESS(ITEM_RADIO_SETUP_PWR_ON_SPEED)
CASE_PWR_BUTTON_PRESS(ITEM_RADIO_SETUP_PWR_OFF_SPEED)
@@ -152,10 +152,14 @@ void menuRadioSetup(event_t event)
CASE_GYRO(0)
CASE_GYRO(0)
0, LABEL(ALARMS), 0, CASE_CAPACITY(0)
- 0, 0, 0, 0,
- LABEL(BACKLIGHT), 0, 0, 0, CASE_PWM_BACKLIGHT(0)
+ 0, 0, 0, 0, /* ITEM_RADIO_SETUP_INACTIVITY_ALARM ITEM_RADIO_SETUP_MEMORY_WARNING ITEM_RADIO_SETUP_ALARM_WARNING ITEM_RADIO_SETUP_RSSI_POWEROFF_ALARM */
+ CASE_BACKLIGHT(LABEL(BACKLIGHT))
+ CASE_BACKLIGHT(0)
+ CASE_BACKLIGHT(0)
+ CASE_BACKLIGHT(0)
CASE_PWM_BACKLIGHT(0)
- 0,
+ CASE_PWM_BACKLIGHT(0)
+ CASE_BACKLIGHT(0)
CASE_SPLASH_PARAM(0)
CASE_PWR_BUTTON_PRESS(0)
CASE_PWR_BUTTON_PRESS(0)
@@ -251,7 +255,7 @@ void menuRadioSetup(event_t event)
putsVolts(lcdLastRightPos+FW, y, 120+g_eeGeneral.vBatMax, (menuHorizontalPosition>0 ? attr : 0)|LEFT|NO_UNIT);
if (attr && s_editMode>0) {
if (menuHorizontalPosition==0)
- CHECK_INCDEC_GENVAR(event, g_eeGeneral.vBatMin, -50, g_eeGeneral.vBatMax+29); // min=4.0V
+ CHECK_INCDEC_GENVAR(event, g_eeGeneral.vBatMin, -60, g_eeGeneral.vBatMax+29); // min=3.0V
else
CHECK_INCDEC_GENVAR(event, g_eeGeneral.vBatMax, g_eeGeneral.vBatMin-29, +40); // max=16.0V
}
@@ -411,7 +415,7 @@ void menuRadioSetup(event_t event)
case ITEM_RADIO_SETUP_BATTERY_WARNING:
lcdDrawTextAlignedLeft(y, STR_BATTERYWARNING);
putsVolts(RADIO_SETUP_2ND_COLUMN, y, g_eeGeneral.vBatWarn, attr|LEFT);
- if(attr) CHECK_INCDEC_GENVAR(event, g_eeGeneral.vBatWarn, 40, 120); //4-12V
+ if(attr) CHECK_INCDEC_GENVAR(event, g_eeGeneral.vBatWarn, 30, 120); //3-12V
break;
case ITEM_RADIO_SETUP_MEMORY_WARNING:
@@ -450,6 +454,7 @@ void menuRadioSetup(event_t event)
if(attr) g_eeGeneral.inactivityTimer = checkIncDec(event, g_eeGeneral.inactivityTimer, 0, 250, EE_GENERAL); //0..250minutes
break;
+#if defined(BACKLIGHT_GPIO)
case ITEM_RADIO_SETUP_BACKLIGHT_LABEL:
lcdDrawTextAlignedLeft(y, STR_BACKLIGHT_LABEL);
break;
@@ -478,6 +483,7 @@ void menuRadioSetup(event_t event)
g_eeGeneral.backlightBright = 100 - b;
}
break;
+#endif
#if defined(PWM_BACKLIGHT)
case ITEM_RADIO_SETUP_BACKLIGHT_BRIGHTNESS_OFF:
diff --git a/radio/src/gui/128x64/view_about.cpp b/radio/src/gui/128x64/view_about.cpp
index aaec50b32..b168f91fb 100644
--- a/radio/src/gui/128x64/view_about.cpp
+++ b/radio/src/gui/128x64/view_about.cpp
@@ -42,7 +42,10 @@ enum AboutScreens {
#define ABOUT_X 2
#define ABOUT_INDENT 4
-#if defined(NAVIGATION_X7)
+#if defined(KEYS_GPIO_REG_PAGEDN)
+#define EVT_KEY_PREVIOUS_VIEW EVT_KEY_BREAK(KEY_PAGEUP)
+#define EVT_KEY_NEXT_VIEW EVT_KEY_BREAK(KEY_PAGEDN)
+#elif defined(NAVIGATION_X7)
#define EVT_KEY_PREVIOUS_VIEW EVT_KEY_LONG(KEY_PAGE)
#define EVT_KEY_NEXT_VIEW EVT_KEY_BREAK(KEY_PAGE)
#else
diff --git a/radio/src/gui/128x64/view_channels.cpp b/radio/src/gui/128x64/view_channels.cpp
index ccd8fc9b3..ffb4d9b33 100644
--- a/radio/src/gui/128x64/view_channels.cpp
+++ b/radio/src/gui/128x64/view_channels.cpp
@@ -26,7 +26,17 @@ constexpr coord_t CHANNEL_GAUGE_OFFSET = CHANNEL_VALUE_OFFSET;
constexpr coord_t CHANNEL_BAR_WIDTH = 70;
constexpr coord_t CHANNEL_PROPERTIES_OFFSET = CHANNEL_GAUGE_OFFSET + CHANNEL_BAR_WIDTH + 2;
-#if defined(NAVIGATION_X7)
+#if defined(RADIO_T8)
+#define EVT_KEY_PREVIOUS_VIEW EVT_KEY_BREAK(KEY_PAGEUP)
+#define EVT_KEY_NEXT_VIEW EVT_KEY_BREAK(KEY_PAGEDN)
+#define EVT_KEY_NEXT_PAGE EVT_KEY_BREAK(KEY_PLUS)
+#define EVT_KEY_PREVIOUS_PAGE EVT_KEY_BREAK(KEY_MINUS)
+#elif defined(NAVIGATION_X7_TX12)
+#define EVT_KEY_PREVIOUS_VIEW EVT_KEY_BREAK(KEY_PAGEUP)
+#define EVT_KEY_NEXT_VIEW EVT_KEY_BREAK(KEY_PAGEDN)
+#define EVT_KEY_NEXT_PAGE EVT_ROTARY_RIGHT
+#define EVT_KEY_PREVIOUS_PAGE EVT_ROTARY_LEFT
+#elif defined(NAVIGATION_X7)
#define EVT_KEY_PREVIOUS_VIEW EVT_KEY_LONG(KEY_PAGE)
#define EVT_KEY_NEXT_VIEW EVT_KEY_BREAK(KEY_PAGE)
#define EVT_KEY_NEXT_PAGE EVT_ROTARY_RIGHT
@@ -54,7 +64,7 @@ void menuChannelsViewCommon(event_t event)
memclear(&reusableBuffer.viewChannels, sizeof(reusableBuffer.viewChannels));
break;
- case EVT_KEY_FIRST(KEY_ENTER):
+ case EVT_KEY_BREAK(KEY_ENTER):
reusableBuffer.viewChannels.mixersView = !reusableBuffer.viewChannels.mixersView;
break;
}
diff --git a/radio/src/gui/128x64/view_main.cpp b/radio/src/gui/128x64/view_main.cpp
index a6f77528b..b3cea8de7 100644
--- a/radio/src/gui/128x64/view_main.cpp
+++ b/radio/src/gui/128x64/view_main.cpp
@@ -35,7 +35,6 @@
#define PHASE_FLAGS 0
#define VBATT_X (6*FW-1)
#define VBATT_Y (2*FH)
-#define VBATTUNIT_X (VBATT_X-1)
#define VBATTUNIT_Y (3*FH)
#define REBOOT_X (20*FW-3)
#define BAR_HEIGHT (BOX_WIDTH-1l) // don't remove the l here to force 16bits maths on 9X
@@ -94,8 +93,9 @@ void doMainScreenGraphics()
if (g_model.throttleReversed && CONVERT_MODE(2) == THR_STICK)
calibStickVert = -calibStickVert;
drawStick(RBOX_CENTERX, calibratedAnalogs[CONVERT_MODE(3)], calibStickVert);
-
+#if defined(HARDWARE_POT1)
drawPotsBars();
+#endif
}
void displayTrims(uint8_t phase)
@@ -184,8 +184,13 @@ void displayBattVoltage()
lcdDrawSolidFilledRect(VBATT_X - 25, VBATT_Y + 9, 21, 5);
lcdDrawSolidVerticalLine(VBATT_X - 4, VBATT_Y + 10, 3);
uint8_t count = GET_TXBATT_BARS(20);
- for (uint8_t i = 0; i < count; i += 2)
+ for (uint8_t i = 0; i < count; i += 2) {
+#if defined(USB_CHARGER)
+ if ((i >= count - 2) && usbChargerLed() && BLINK_ON_PHASE) // Blink last segment on charge
+ continue;
+#endif
lcdDrawSolidVerticalLine(VBATT_X - 24 + i, VBATT_Y + 10, 3);
+ }
if (!IS_TXBATT_WARNING() || BLINK_ON_PHASE)
lcdDrawSolidFilledRect(VBATT_X - 26, VBATT_Y, 24, 15);
#else
@@ -209,7 +214,25 @@ void displayVoltageOrAlarm()
#define displayVoltageOrAlarm() displayBattVoltage()
#endif
-#if defined(NAVIGATION_X7)
+#if defined(RADIO_T8)
+#define EVT_KEY_CONTEXT_MENU EVT_KEY_LONG(KEY_ENTER)
+#define EVT_KEY_PREVIOUS_VIEW EVT_KEY_BREAK(KEY_PAGEUP)
+#define EVT_KEY_NEXT_VIEW EVT_KEY_FIRST(KEY_PAGEDN)
+#define EVT_KEY_NEXT_PAGE EVT_KEY_FIRST(KEY_PLUS)
+#define EVT_KEY_PREVIOUS_PAGE EVT_KEY_FIRST(KEY_MINUS)
+#define EVT_KEY_MODEL_MENU EVT_KEY_LONG(KEY_MODEL)
+#define EVT_KEY_GENERAL_MENU EVT_KEY_LONG(KEY_SYS)
+#define EVT_KEY_TELEMETRY EVT_KEY_LONG(KEY_PAGEUP)
+#elif defined(NAVIGATION_X7_TX12)
+#define EVT_KEY_CONTEXT_MENU EVT_KEY_LONG(KEY_ENTER)
+#define EVT_KEY_PREVIOUS_VIEW EVT_KEY_FIRST(KEY_PAGEUP)
+#define EVT_KEY_NEXT_VIEW EVT_KEY_FIRST(KEY_PAGEDN)
+#define EVT_KEY_NEXT_PAGE EVT_ROTARY_RIGHT
+#define EVT_KEY_PREVIOUS_PAGE EVT_ROTARY_LEFT
+#define EVT_KEY_MODEL_MENU EVT_KEY_LONG(KEY_MODEL)
+#define EVT_KEY_GENERAL_MENU EVT_KEY_LONG(KEY_SYS)
+#define EVT_KEY_TELEMETRY EVT_KEY_FIRST(KEY_TELE)
+#elif defined(NAVIGATION_X7)
#define EVT_KEY_CONTEXT_MENU EVT_KEY_LONG(KEY_ENTER)
#define EVT_KEY_NEXT_VIEW EVT_KEY_BREAK(KEY_PAGE)
#define EVT_KEY_NEXT_PAGE EVT_ROTARY_RIGHT
@@ -397,6 +420,7 @@ void menuMainView(event_t event)
killEvents(event);
break;
+
case EVT_KEY_FIRST(KEY_EXIT):
#if defined(GVARS)
if (gvarDisplayTimer > 0) {
diff --git a/radio/src/gui/128x64/view_statistics.cpp b/radio/src/gui/128x64/view_statistics.cpp
index 2296e93b0..0765cf9b6 100644
--- a/radio/src/gui/128x64/view_statistics.cpp
+++ b/radio/src/gui/128x64/view_statistics.cpp
@@ -31,14 +31,21 @@ void menuStatisticsView(event_t event)
switch (event) {
case EVT_KEY_FIRST(KEY_UP):
-#if defined(NAVIGATION_X7)
+#if defined(KEYS_GPIO_REG_PAGEDN)
+ case EVT_KEY_BREAK(KEY_PAGEDN):
+#elif defined(NAVIGATION_X7)
case EVT_KEY_BREAK(KEY_PAGE):
#endif
+
chainMenu(menuStatisticsDebug);
break;
case EVT_KEY_FIRST(KEY_DOWN):
-#if defined(NAVIGATION_X7)
+#if defined(KEYS_GPIO_REG_PAGEUP)
+ case EVT_KEY_BREAK(KEY_PAGEUP):
+ killEvents(event);
+ chainMenu(menuStatisticsDebug2);
+#elif defined(NAVIGATION_X7)
case EVT_KEY_LONG(KEY_PAGE):
killEvents(event);
chainMenu(menuStatisticsDebug2);
@@ -133,7 +140,12 @@ void menuStatisticsDebug(event_t event)
break;
case EVT_KEY_FIRST(KEY_UP):
-#if defined(NAVIGATION_X7)
+#if defined(KEYS_GPIO_REG_PAGEDN)
+ case EVT_KEY_BREAK(KEY_PAGEDN):
+ disableVBatBridge();
+ chainMenu(menuStatisticsDebug2);
+ break;
+#elif defined(NAVIGATION_X7)
case EVT_KEY_BREAK(KEY_PAGE):
disableVBatBridge();
chainMenu(menuStatisticsDebug2);
@@ -141,7 +153,9 @@ void menuStatisticsDebug(event_t event)
#endif
case EVT_KEY_FIRST(KEY_DOWN):
-#if defined(NAVIGATION_X7)
+#if defined(KEYS_GPIO_REG_PAGEUP)
+ case EVT_KEY_BREAK(KEY_PAGEUP):
+#elif defined(NAVIGATION_X7)
case EVT_KEY_LONG(KEY_PAGE):
#endif
killEvents(event);
@@ -264,14 +278,18 @@ void menuStatisticsDebug2(event_t event)
break;
case EVT_KEY_FIRST(KEY_UP):
-#if defined(NAVIGATION_X7)
+#if defined(KEYS_GPIO_REG_PAGEDN)
+ case EVT_KEY_BREAK(KEY_PAGEDN):
+#elif defined(NAVIGATION_X7)
case EVT_KEY_BREAK(KEY_PAGE):
#endif
chainMenu(menuStatisticsView);
return;
case EVT_KEY_FIRST(KEY_DOWN):
-#if defined(NAVIGATION_X7)
+#if defined(KEYS_GPIO_REG_PAGEUP)
+ case EVT_KEY_BREAK(KEY_PAGEUP):
+#elif defined(NAVIGATION_X7)
case EVT_KEY_LONG(KEY_PAGE):
#endif
killEvents(event);
diff --git a/radio/src/gui/128x64/view_telemetry.cpp b/radio/src/gui/128x64/view_telemetry.cpp
index 86d369377..3b6835f64 100644
--- a/radio/src/gui/128x64/view_telemetry.cpp
+++ b/radio/src/gui/128x64/view_telemetry.cpp
@@ -68,27 +68,20 @@ bool displayGaugesTelemetryScreen(TelemetryScreenData & screen)
barMin = calc100toRESX(barMin);
barMax = calc100toRESX(barMax);
}
- if (source && barMax > barMin) {
+ if (source) {
uint8_t y = barHeight+6+i*(barHeight+6);
drawSource(0, y+barHeight/2-3, source, SMLSIZE);
lcdDrawRect(BAR_LEFT, y, BAR_WIDTH+1, barHeight+2);
getvalue_t value = getValue(source);
-
uint8_t thresholdX = 0;
-
-
- uint8_t width = barCoord(value, barMin, barMax);
-
+ uint8_t width = (barMin < barMax) ? barCoord(value, barMin, barMax) : 99 - barCoord(value, barMax, barMin);
uint8_t barShade = SOLID;
-
lcdDrawFilledRect(BAR_LEFT+1, y+1, width, barHeight, barShade);
-
for (uint8_t j=24; j<99; j+=25) {
if (j>thresholdX || j>width) {
lcdDrawSolidVerticalLine(j*BAR_WIDTH/100+BAR_LEFT+1, y+1, barHeight);
}
}
-
if (thresholdX) {
lcdDrawVerticalLine(BAR_LEFT+1+thresholdX, y-2, barHeight+3, DOTTED);
lcdDrawSolidHorizontalLine(BAR_LEFT+thresholdX, y-2, 3);
diff --git a/radio/src/gui/128x64/widgets.cpp b/radio/src/gui/128x64/widgets.cpp
index 36c31d3fd..398c994c6 100644
--- a/radio/src/gui/128x64/widgets.cpp
+++ b/radio/src/gui/128x64/widgets.cpp
@@ -67,7 +67,11 @@ void drawVerticalScrollbar(coord_t x, coord_t y, coord_t h, uint16_t offset, uin
void drawGauge(coord_t x, coord_t y, coord_t w, coord_t h, int32_t val, int32_t max)
{
+#if defined(PCBX7) || defined(PCBX9LITES) // X7 LCD doesn't like too many horizontal lines
+ h++;
+#else
lcdDrawRect(x, y, w+1, h);
+#endif
lcdDrawFilledRect(x+1, y+1, w-1, 4, SOLID, ERASE);
coord_t len = limit((uint8_t)1, uint8_t((abs(val) * w/2 + max/2) / max), uint8_t(w/2));
coord_t x0 = (val>0) ? x+w/2 : x+1+w/2-len;
diff --git a/radio/src/gui/212x64/gui.h b/radio/src/gui/212x64/gui.h
index 5968bd320..738c146ea 100644
--- a/radio/src/gui/212x64/gui.h
+++ b/radio/src/gui/212x64/gui.h
@@ -247,6 +247,8 @@ extern int8_t s_copySrcRow;
extern int8_t s_copyTgtOfs;
extern uint8_t s_currIdx;
extern uint8_t s_currIdxSubMenu;
+extern uint16_t s_currSrcRaw;
+extern uint16_t s_currScale;
extern uint8_t s_maxLines;
extern uint8_t s_copySrcIdx;
extern uint8_t s_copySrcCh;
@@ -284,9 +286,6 @@ void menuChannelsView(event_t event);
#define POS_HORZ_INIT(posVert) ((COLATTR(posVert) & NAVIGATION_LINE_BY_LINE) ? -1 : 0)
#define EDIT_MODE_INIT 0 // TODO enum
-typedef int (*FnFuncP) (int x);
-void drawFunction(FnFuncP fn, uint8_t offset=0);
-
void onSourceLongEnterPress(const char *result);
uint8_t switchToMix(uint8_t source);
diff --git a/radio/src/gui/212x64/menu_model.cpp b/radio/src/gui/212x64/menu_model.cpp
index f8058499b..5147bf7a2 100644
--- a/radio/src/gui/212x64/menu_model.cpp
+++ b/radio/src/gui/212x64/menu_model.cpp
@@ -68,3 +68,5 @@ void editSingleName(coord_t x, coord_t y, const char * label, char *name, uint8_
uint8_t s_currIdx;
uint8_t s_currIdxSubMenu;
+uint16_t s_currSrcRaw;
+uint16_t s_currScale;
diff --git a/radio/src/gui/212x64/menus.h b/radio/src/gui/212x64/menus.h
index bdfb8f591..f39cdc71b 100644
--- a/radio/src/gui/212x64/menus.h
+++ b/radio/src/gui/212x64/menus.h
@@ -76,6 +76,7 @@ void menuRadioTools(event_t event);
void menuRadioCalibration(event_t event);
void menuRadioSpectrumAnalyser(event_t event);
void menuRadioPowerMeter(event_t event);
+void menuGhostModuleConfig(event_t event);
extern const MenuHandlerFunc menuTabGeneral[MENU_RADIO_PAGES_COUNT];
diff --git a/radio/src/gui/212x64/model_curve_edit.cpp b/radio/src/gui/212x64/model_curve_edit.cpp
index 5cc622903..324847c3d 100644
--- a/radio/src/gui/212x64/model_curve_edit.cpp
+++ b/radio/src/gui/212x64/model_curve_edit.cpp
@@ -180,6 +180,8 @@ void menuModelCurveOne(event_t event)
}
drawCurve(FW);
+ if (s_currSrcRaw != MIXSRC_NONE)
+ drawCursor(applyCurrentCurve, FW);
uint8_t posY = FH+1;
attr = (s_editMode > 0 ? INVERS|BLINK : INVERS);
diff --git a/radio/src/gui/212x64/model_display.cpp b/radio/src/gui/212x64/model_display.cpp
index 0e1da16d5..ce47f5306 100644
--- a/radio/src/gui/212x64/model_display.cpp
+++ b/radio/src/gui/212x64/model_display.cpp
@@ -245,10 +245,10 @@ void menuModelDisplay(event_t event)
}
break;
case 1:
- bar.barMin = checkIncDec(event, bar.barMin, barMin, bar.barMax, EE_MODEL|NO_INCDEC_MARKS);
+ bar.barMin = checkIncDec(event, bar.barMin, barMin, barMax, EE_MODEL|NO_INCDEC_MARKS);
break;
case 2:
- bar.barMax = checkIncDec(event, bar.barMax, bar.barMin, barMax, EE_MODEL|NO_INCDEC_MARKS);
+ bar.barMax = checkIncDec(event, bar.barMax, barMin, barMax, EE_MODEL|NO_INCDEC_MARKS);
break;
}
}
diff --git a/radio/src/gui/212x64/model_input_edit.cpp b/radio/src/gui/212x64/model_input_edit.cpp
index 64b7b81db..49bea6834 100644
--- a/radio/src/gui/212x64/model_input_edit.cpp
+++ b/radio/src/gui/212x64/model_input_edit.cpp
@@ -30,28 +30,6 @@ int expoFn(int x)
return anas[ed->chn];
}
-void drawFunction(FnFuncP fn, uint8_t offset)
-{
- lcdDrawVerticalLine(CURVE_CENTER_X-offset, CURVE_CENTER_Y-CURVE_SIDE_WIDTH, CURVE_SIDE_WIDTH*2, 0xee);
- lcdDrawHorizontalLine(CURVE_CENTER_X-CURVE_SIDE_WIDTH-offset, CURVE_CENTER_Y, CURVE_SIDE_WIDTH*2, 0xee);
-
- coord_t prev_yv = (coord_t)-1;
-
- for (int xv=-CURVE_SIDE_WIDTH; xv<=CURVE_SIDE_WIDTH; xv++) {
- coord_t yv = (LCD_H-1) - (((uint16_t)RESX + fn(xv * (RESX/CURVE_SIDE_WIDTH))) / 2 * (LCD_H-1) / RESX);
- if (prev_yv != (coord_t)-1) {
- if (abs((int8_t)yv-prev_yv) <= 1) {
- lcdDrawPoint(CURVE_CENTER_X+xv-offset-1, prev_yv, FORCE);
- }
- else {
- uint8_t tmp = (prev_yv < yv ? 0 : 1);
- lcdDrawSolidVerticalLine(CURVE_CENTER_X+xv-offset-1, yv+tmp, prev_yv-yv);
- }
- }
- prev_yv = yv;
- }
-}
-
enum ExposFields {
EXPO_FIELD_INPUT_NAME,
EXPO_FIELD_LINE_NAME,
@@ -109,7 +87,15 @@ void menuModelExpoOne(event_t event)
case EXPO_FIELD_SOURCE:
lcdDrawTextAlignedLeft(y, STR_SOURCE);
drawSource(EXPO_ONE_2ND_COLUMN, y, ed->srcRaw, STREXPANDED|attr);
- if (attr) ed->srcRaw = checkIncDec(event, ed->srcRaw, INPUTSRC_FIRST, INPUTSRC_LAST, EE_MODEL|INCDEC_SOURCE|NO_INCDEC_MARKS, isSourceAvailableInInputs);
+ if (attr && menuHorizontalPosition==0)
+ ed->srcRaw = checkIncDec(event, ed->srcRaw, INPUTSRC_FIRST, INPUTSRC_LAST, EE_MODEL|INCDEC_SOURCE|NO_INCDEC_MARKS, isSourceAvailableInInputs);
+ if (ed->srcRaw >= MIXSRC_FIRST_TELEM) {
+ drawSensorCustomValue(EXPO_ONE_2ND_COLUMN+30, y, (ed->srcRaw - MIXSRC_FIRST_TELEM)/3, getValue(ed->srcRaw), LEFT|(menuHorizontalPosition==1?attr:0));
+ if (attr && menuHorizontalPosition == 1) ed->scale = checkIncDec(event, ed->scale, 0, maxTelemValue(ed->srcRaw - MIXSRC_FIRST_TELEM + 1), EE_MODEL);
+ }
+ else if (attr) {
+ menuHorizontalPosition = 0;
+ }
break;
case EXPO_FIELD_SCALE:
@@ -160,23 +146,8 @@ void menuModelExpoOne(event_t event)
}
drawFunction(expoFn);
-
- int x512 = getValue(ed->srcRaw);
- if (ed->srcRaw >= MIXSRC_FIRST_TELEM) {
- drawSensorCustomValue(LCD_W-8, 6*FH, (ed->srcRaw - MIXSRC_FIRST_TELEM) / 3, x512, 0);
- if (ed->scale > 0) x512 = (x512 * 1024) / convertTelemValue(ed->srcRaw - MIXSRC_FIRST_TELEM + 1, ed->scale);
- }
- else {
- lcdDrawNumber(LCD_W-8, 6*FH, calcRESXto1000(x512), RIGHT | PREC1);
- }
- x512 = limit(-1024, x512, 1024);
- int y512 = expoFn(x512);
- y512 = limit(-1024, y512, 1024);
- lcdDrawNumber(LCD_W-8-6*FW, 1*FH, calcRESXto1000(y512), RIGHT | PREC1);
-
- x512 = CURVE_CENTER_X+x512/(RESX/CURVE_SIDE_WIDTH);
- y512 = (LCD_H-1) - ((y512+RESX)/2) * (LCD_H-1) / RESX;
-
- lcdDrawSolidVerticalLine(x512, y512-3, 3*2+1);
- lcdDrawSolidHorizontalLine(x512-3, y512, 3*2+1);
+ // those parameters are global so that they can be reused in the curve edit screen
+ s_currSrcRaw = ed->srcRaw;
+ s_currScale = ed->scale;
+ drawCursor(expoFn);
}
diff --git a/radio/src/gui/212x64/model_mix_edit.cpp b/radio/src/gui/212x64/model_mix_edit.cpp
index 1faec6d69..749b0ed05 100644
--- a/radio/src/gui/212x64/model_mix_edit.cpp
+++ b/radio/src/gui/212x64/model_mix_edit.cpp
@@ -140,6 +140,8 @@ void menuModelMixOne(event_t event)
case MIX_FIELD_CURVE:
lcdDrawTextAlignedLeft(y, STR_CURVE);
+ s_currSrcRaw = md2->srcRaw;
+ s_currScale = 0;
editCurveRef(MIXES_2ND_COLUMN, y, md2->curve, event, attr);
break;
diff --git a/radio/src/gui/212x64/model_select.cpp b/radio/src/gui/212x64/model_select.cpp
index 8b396e1b4..d4223a3c1 100644
--- a/radio/src/gui/212x64/model_select.cpp
+++ b/radio/src/gui/212x64/model_select.cpp
@@ -28,6 +28,10 @@ void onModelSelectMenu(const char * result)
int8_t sub = menuVerticalPosition;
if (result == STR_SELECT_MODEL || result == STR_CREATE_MODEL) {
+ if (!g_eeGeneral.disableRssiPoweroffAlarm) {
+ if (!confirmModelChange())
+ return;
+ }
selectModel(sub);
}
else if (result == STR_COPY_MODEL) {
diff --git a/radio/src/gui/212x64/model_setup.cpp b/radio/src/gui/212x64/model_setup.cpp
index 36c7783bc..db9ccc996 100644
--- a/radio/src/gui/212x64/model_setup.cpp
+++ b/radio/src/gui/212x64/model_setup.cpp
@@ -66,6 +66,7 @@ enum MenuModelSetupItems {
ITEM_MODEL_SETUP_THROTTLE_REVERSED,
ITEM_MODEL_SETUP_THROTTLE_TRACE,
ITEM_MODEL_SETUP_THROTTLE_TRIM,
+ ITEM_MODEL_SETUP_THROTTLE_TRIM_SWITCH,
ITEM_MODEL_SETUP_PREFLIGHT_LABEL,
ITEM_MODEL_SETUP_CHECKLIST_DISPLAY,
ITEM_MODEL_SETUP_THROTTLE_WARNING,
@@ -86,6 +87,7 @@ enum MenuModelSetupItems {
ITEM_MODEL_SETUP_INTERNAL_MODULE_LABEL,
ITEM_MODEL_SETUP_INTERNAL_MODULE_TYPE,
ITEM_MODEL_SETUP_INTERNAL_MODULE_CHANNELS,
+ ITEM_MODEL_SETUP_INTERNAL_MODULE_RACING_MODE,
ITEM_MODEL_SETUP_INTERNAL_MODULE_NOT_ACCESS_RXNUM_BIND_RANGE,
ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_MODEL_NUM,
ITEM_MODEL_SETUP_INTERNAL_MODULE_FAILSAFE,
@@ -344,6 +346,7 @@ void menuModelSetup(event_t event)
0, // Thrxottle reverse
0, // Throttle trace source
0, // Throttle trim
+ 0, // Throttle trim switch
LABEL(PreflightCheck),
0, // Checklist
@@ -360,6 +363,7 @@ void menuModelSetup(event_t event)
LABEL(InternalModule),
INTERNAL_MODULE_TYPE_ROWS,
MODULE_CHANNELS_ROWS(INTERNAL_MODULE),
+ IF_ALLOW_RACING_MODE(INTERNAL_MODULE),
IF_NOT_ACCESS_MODULE_RF(INTERNAL_MODULE, MODULE_BIND_ROWS(INTERNAL_MODULE)), // RxNum, [Bind] and [Range] buttons
IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 0), // RxNum for ACCESS
IF_INTERNAL_MODULE_ON(FAILSAFE_ROWS(INTERNAL_MODULE)), // Failsafe
@@ -571,6 +575,13 @@ void menuModelSetup(event_t event)
ON_OFF_MENU_ITEM(g_model.thrTrim, MODEL_SETUP_2ND_COLUMN, y, STR_TTRIM, attr, event);
break;
+ case ITEM_MODEL_SETUP_THROTTLE_TRIM_SWITCH:
+ lcdDrawTextAlignedLeft(y, STR_TTRIM_SW);
+ if (attr)
+ CHECK_INCDEC_MODELVAR_ZERO(event, g_model.thrTrimSw, NUM_TRIMS - 1);
+ drawSource(MODEL_SETUP_2ND_COLUMN, y, g_model.getThrottleStickTrimSource(), attr);
+ break;
+
case ITEM_MODEL_SETUP_PREFLIGHT_LABEL:
lcdDrawTextAlignedLeft(y, STR_PREFLIGHT);
break;
@@ -1089,6 +1100,15 @@ void menuModelSetup(event_t event)
break;
}
+ case ITEM_MODEL_SETUP_INTERNAL_MODULE_RACING_MODE:
+ {
+ uint8_t moduleIdx = CURRENT_MODULE_EDITED(k);
+ ModuleData & moduleData = g_model.moduleData[moduleIdx];
+ lcdDrawText(INDENT_WIDTH, y, STR_RACING_MODE);
+ moduleData.pxx2.racingMode = editCheckBox(moduleData.pxx2.racingMode, MODEL_SETUP_2ND_COLUMN, y, "", attr, event);
+ break;
+ }
+
case ITEM_MODEL_SETUP_TRAINER_PPM_PARAMS:
lcdDrawTextAlignedLeft(y, STR_PPMFRAME);
lcdDrawNumber(MODEL_SETUP_2ND_COLUMN, y, (int16_t)g_model.trainerData.frameLength*5 + 225, (menuHorizontalPosition<=0 ? attr : 0) | PREC1|LEFT);
@@ -1160,15 +1180,12 @@ void menuModelSetup(event_t event)
if (isModuleRxNumAvailable(moduleIdx)) {
lcdDrawNumber(MODEL_SETUP_2ND_COLUMN, y, g_model.header.modelId[moduleIdx], (l_posHorz == 0 ? attr : 0) | LEADING0 | LEFT, 2);
bindButtonPos = lcdNextPos + FW;
- }
- else if (attr) {
- l_posHorz += 1;
- }
- if (isModuleBindRangeAvailable(moduleIdx)) {
if (attr && l_posHorz == 0) {
if (s_editMode > 0) {
CHECK_INCDEC_MODELVAR_ZERO(event, g_model.header.modelId[moduleIdx], getMaxRxNum(moduleIdx));
if (checkIncDec_Ret) {
+ if (isModuleCrossfire(moduleIdx))
+ moduleState[EXTERNAL_MODULE].counter = CRSF_FRAME_MODELID;
modelHeaders[g_eeGeneral.currModel].modelId[moduleIdx] = g_model.header.modelId[moduleIdx];
}
else if (event == EVT_KEY_LONG(KEY_ENTER)) {
@@ -1181,6 +1198,11 @@ void menuModelSetup(event_t event)
}
}
}
+ }
+ else if (attr) {
+ l_posHorz += 1;
+ }
+ if (isModuleBindRangeAvailable(moduleIdx)) {
lcdDrawText(bindButtonPos, y, STR_MODULE_BIND, l_posHorz == 1 ? attr : 0);
if (isModuleRangeAvailable(moduleIdx)) {
lcdDrawText(lcdNextPos + FW, y, STR_MODULE_RANGE, l_posHorz == 2 ? attr : 0);
@@ -1259,7 +1281,6 @@ void menuModelSetup(event_t event)
if (event == EVT_KEY_LONG(KEY_ENTER)) {
killEvents(event);
setCustomFailsafe(moduleIdx);
- storageDirty(EE_MODEL);
AUDIO_WARNING1();
SEND_FAILSAFE_NOW(moduleIdx);
}
@@ -1283,38 +1304,34 @@ void menuModelSetup(event_t event)
#if defined(MULTIMODULE)
if (MULTIMODULE_PROTOCOL_KNOWN(moduleIdx)) {
+ const char * title = getMultiOptionTitle(moduleIdx);
+
+ lcdDrawText(INDENT_WIDTH, y, title);
+ if (title == STR_MULTI_RFTUNE) {
+ lcdDrawText(MODEL_SETUP_2ND_COLUMN + 23, y, "RSSI(", LEFT);
+ lcdDrawNumber(lcdLastRightPos, y, TELEMETRY_RSSI(), LEFT);
+ lcdDrawText(lcdLastRightPos, y, ")", LEFT);
+ }
+
int optionValue = g_model.moduleData[moduleIdx].multi.optionValue;
-
- MultiModuleStatus &status = getMultiModuleStatus(moduleIdx);
- const uint8_t multi_proto = g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol();
- if (status.isValid()) {
- lcdDrawText(INDENT_WIDTH, y, mm_options_strings::options[status.optionDisp]);
- if (attr && status.optionDisp == 2) {
- lcdDrawText(MODEL_SETUP_3RD_COLUMN+22, y, "RSSI(", LEFT);
- lcdDrawNumber(lcdLastRightPos, y, TELEMETRY_RSSI(), LEFT);
- lcdDrawText(lcdLastRightPos, y, ")", LEFT);
- }
- }
- else {
- const mm_protocol_definition * pdef = getMultiProtocolDefinition(multi_proto);
- if (pdef->optionsstr)
- lcdDrawText(INDENT_WIDTH, y, pdef->optionsstr);
- if (pdef->optionsstr == STR_MULTI_RFTUNE) {
- lcdDrawText(MODEL_SETUP_3RD_COLUMN+22, y, "RSSI(", LEFT);
- lcdDrawNumber(lcdLastRightPos, y, TELEMETRY_RSSI(), LEFT);
- lcdDrawText(lcdLastRightPos, y, ")", LEFT);
- }
- }
-
+ const uint8_t multi_proto = g_model.moduleData[moduleIdx].getMultiProtocol();
int8_t min, max;
getMultiOptionValues(multi_proto, min, max);
- if (multi_proto == MODULE_SUBTYPE_MULTI_FS_AFHDS2A) {
- lcdDrawNumber(MODEL_SETUP_2ND_COLUMN, y, 50 + 5 * optionValue, LEFT | attr);
- }
- else if (multi_proto == MODULE_SUBTYPE_MULTI_FRSKY_R9) {
+ if (title == STR_MULTI_RFPOWER) {
lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_MULTI_POWER, optionValue, LEFT | attr);
}
+ else if (title == STR_MULTI_TELEMETRY) {
+ lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_MULTI_TELEMETRY_MODE, optionValue, LEFT | attr);
+ }
+ else if (title == STR_MULTI_WBUS) {
+ lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_MULTI_WBUS_MODE, optionValue, LEFT | attr);
+ min = 0;
+ max = 1;
+ }
+ else if (multi_proto == MODULE_SUBTYPE_MULTI_FS_AFHDS2A) {
+ lcdDrawNumber(MODEL_SETUP_2ND_COLUMN, y, 50 + 5 * optionValue, LEFT | attr);
+ }
else if (multi_proto == MODULE_SUBTYPE_MULTI_DSM2) {
optionValue = optionValue & 0x01;
editCheckBox(optionValue, MODEL_SETUP_2ND_COLUMN, y, "", LEFT | attr, event);
diff --git a/radio/src/gui/212x64/model_special_functions.cpp b/radio/src/gui/212x64/model_special_functions.cpp
index 7c2d1e139..703821cda 100644
--- a/radio/src/gui/212x64/model_special_functions.cpp
+++ b/radio/src/gui/212x64/model_special_functions.cpp
@@ -268,10 +268,12 @@ void menuSpecialFunctions(event_t event, CustomFunctionData * functions, CustomF
lcdDrawNumber(MODEL_SPECIAL_FUNC_3RD_COLUMN, y, val_displayed, attr|LEFT);
}
#endif
- else if (func >= FUNC_SET_FAILSAFE && func <= FUNC_BIND) {
+#if defined(DANGEROUS_MODULE_FUNCTIONS)
+ else if (func >= FUNC_RANGECHECK && func <= FUNC_BIND) {
val_max = NUM_MODULES-1;
lcdDrawTextAtIndex(MODEL_SPECIAL_FUNC_3RD_COLUMN, y, "\004Int.Ext.", CFN_PARAM(cfn), attr);
}
+#endif
else if (func == FUNC_SET_TIMER) {
getMixSrcRange(MIXSRC_FIRST_TIMER, val_min, val_max);
drawTimer(MODEL_SPECIAL_FUNC_3RD_COLUMN, y, val_displayed, attr|LEFT|TIMEHOUR, attr);
@@ -338,14 +340,14 @@ void menuSpecialFunctions(event_t event, CustomFunctionData * functions, CustomF
lcdDrawMMM(MODEL_SPECIAL_FUNC_3RD_COLUMN, y, attr);
}
}
-#if defined(PCBX9E) || defined(PCBX9DP)
else if (func == FUNC_BACKLIGHT) {
- drawSlider(MODEL_SPECIAL_FUNC_3RD_COLUMN, y, CFN_PARAM(cfn), 100, attr);
- if (active) INCDEC_SET_FLAG(eeFlags | NO_INCDEC_MARKS);
- val_min = 0;
- val_max = 100;
+ val_max = MIXSRC_LAST_CH;
+ drawSource(MODEL_SPECIAL_FUNC_3RD_COLUMN, y, val_displayed, attr);
+ if (active) {
+ INCDEC_SET_FLAG(eeFlags | INCDEC_SOURCE);
+ INCDEC_ENABLE_CHECK(isSourceAvailable);
+ }
}
-#endif
#if defined(GVARS)
else if (func == FUNC_ADJUST_GVAR) {
switch (CFN_GVAR_MODE(cfn)) {
diff --git a/radio/src/gui/212x64/model_telemetry.cpp b/radio/src/gui/212x64/model_telemetry.cpp
index 439c68f0b..033d1dbba 100644
--- a/radio/src/gui/212x64/model_telemetry.cpp
+++ b/radio/src/gui/212x64/model_telemetry.cpp
@@ -227,14 +227,7 @@ void menuModelTelemetry(event_t event)
break;
case ITEM_TELEMETRY_RSSI_LABEL:
-#if defined(MULTIMODULE)
- if (telemetryProtocol == PROTOCOL_TELEMETRY_MULTIMODULE && (g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol() == MODULE_SUBTYPE_MULTI_FS_AFHDS2A || g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol() == MODULE_SUBTYPE_MULTI_HOTT))
- lcdDrawTextAlignedLeft(y, "RQly");
- else
- lcdDrawTextAlignedLeft(y, "RSSI");
-#else
- lcdDrawTextAlignedLeft(y, "RSSI");
-#endif
+ lcdDrawTextAlignedLeft(y, getRssiLabel());
break;
case ITEM_TELEMETRY_RSSI_SOURCE: {
diff --git a/radio/src/gui/212x64/view_main.cpp b/radio/src/gui/212x64/view_main.cpp
index 659781ea6..aecee9f3d 100644
--- a/radio/src/gui/212x64/view_main.cpp
+++ b/radio/src/gui/212x64/view_main.cpp
@@ -27,7 +27,6 @@
#define MODELNAME_Y (11)
#define VBATT_X (MODELNAME_X+26)
#define VBATT_Y (FH+3)
-#define VBATTUNIT_X (VBATT_X-2)
#define VBATTUNIT_Y VBATT_Y
#define BITMAP_X ((LCD_W-64)/2)
#define BITMAP_Y (LCD_H/2)
diff --git a/radio/src/gui/212x64/view_telemetry.cpp b/radio/src/gui/212x64/view_telemetry.cpp
index fa8740667..e15fc5781 100644
--- a/radio/src/gui/212x64/view_telemetry.cpp
+++ b/radio/src/gui/212x64/view_telemetry.cpp
@@ -66,14 +66,14 @@ void displayGaugesTelemetryScreen(TelemetryScreenData & screen)
barMin = calc100toRESX(barMin);
barMax = calc100toRESX(barMax);
}
- if (source && barMax > barMin) {
+ if (source) {
int y = barHeight+6+i*(barHeight+6);
drawSource(0, y+barHeight-5, source, 0);
lcdDrawRect(BAR_LEFT, y, BAR_WIDTH+1, barHeight+2);
getvalue_t value = getValue(source);
drawSourceValue(BAR_LEFT+2+BAR_WIDTH, y+barHeight-5, source, LEFT);
uint8_t thresholdX = 0;
- int width = barCoord(value, barMin, barMax);
+ uint8_t width = (barMin < barMax) ? barCoord(value, barMin, barMax) : limit(0, 151 - barCoord(value, barMax, barMin), 151);
uint8_t barShade = SOLID;
lcdDrawFilledRect(BAR_LEFT+1, y+1, width, barHeight, barShade);
for (uint8_t j=24; j<99; j+=25) {
diff --git a/radio/src/gui/480x272/colors.h b/radio/src/gui/480x272/colors.h
index 5d5bf8131..eb6a2c074 100644
--- a/radio/src/gui/480x272/colors.h
+++ b/radio/src/gui/480x272/colors.h
@@ -29,6 +29,7 @@
#define ARGB(a, r, g, b) (uint16_t)((((a) & 0xF0) << 8) + (((r) & 0xF0) << 4) + (((g) & 0xF0) << 0) + (((b) & 0xF0) >> 4))
#define WHITE RGB(0xFF, 0xFF, 0xFF)
+#define LIGHTWHITE RGB(238, 234, 238)
#define BLACK RGB(0, 0, 0)
#define YELLOW RGB(0xF0, 0xD0, 0x10)
#define BLUE RGB(0x30, 0xA0, 0xE0)
@@ -38,6 +39,10 @@
#define RED RGB(229, 32, 30)
#define DARKRED RGB(160, 0, 6)
#define GREEN RGB(25, 150, 50)
+#define LIGHTBROWN RGB(156, 109, 32)
+#define DARKBROWN RGB(106, 72, 16)
+#define BRIGHTGREEN RGB(0, 180, 60)
+#define ORANGE RGB(229, 100, 30)
#define OPACITY_MAX 0x0F
#define OPACITY(x) ((x)<<24)
diff --git a/radio/src/gui/480x272/curves.cpp b/radio/src/gui/480x272/curves.cpp
index b18d15d4a..5b12fc2f7 100644
--- a/radio/src/gui/480x272/curves.cpp
+++ b/radio/src/gui/480x272/curves.cpp
@@ -94,3 +94,36 @@ void drawCurvePoint(int x, int y, LcdFlags color)
lcdDrawBitmapPattern(x, y, LBM_CURVE_POINT, color);
lcdDrawBitmapPattern(x, y, LBM_CURVE_POINT_CENTER, TEXT_BGCOLOR);
}
+
+void drawCursor(FnFuncP fn)
+{
+ char textx[5];
+ char texty[5];
+ int x = getValue(s_currSrcRaw);
+ if (s_currSrcRaw >= MIXSRC_FIRST_TELEM) {
+ strAppendUnsigned(textx, calcRESXto100(x));
+ // TODO drawSensorCustomValue(LCD_W-8, 6*FH, ed->srcRaw - MIXSRC_FIRST_TELEM, x);
+ if (s_currScale > 0)
+ x = (x * 1024) / convertTelemValue(s_currSrcRaw - MIXSRC_FIRST_TELEM + 1, s_currScale);
+ }
+ else {
+ strAppendSigned(textx, calcRESXto100(x));
+ }
+
+ x = limit(-1024, x, 1024);
+ int y = limit(-1024, fn(x), 1024);
+ strAppendSigned(texty, calcRESXto100(y));
+
+ x = divRoundClosest(x * CURVE_SIDE_WIDTH, RESX);
+ y = CURVE_CENTER_Y + getCurveYCoord(fn, x, CURVE_SIDE_WIDTH);
+
+ lcdDrawSolidFilledRect(CURVE_CENTER_X + x, CURVE_CENTER_Y - CURVE_SIDE_WIDTH, 2, 2 * CURVE_SIDE_WIDTH + 2, CURVE_CURSOR_COLOR);
+ lcdDrawSolidFilledRect(CURVE_CENTER_X - CURVE_SIDE_WIDTH-2, y-1, 2*CURVE_SIDE_WIDTH + 2, 2, CURVE_CURSOR_COLOR);
+ lcdDrawBitmapPattern(CURVE_CENTER_X + x - 4, y - 4, LBM_CURVE_POINT, CURVE_CURSOR_COLOR);
+ lcdDrawBitmapPattern(CURVE_CENTER_X + x - 4, y - 4, LBM_CURVE_POINT_CENTER, TEXT_BGCOLOR);
+
+ int left = limit(CURVE_CENTER_X - CURVE_SIDE_WIDTH, CURVE_CENTER_X - CURVE_COORD_WIDTH / 2 + x, CURVE_CENTER_X + CURVE_SIDE_WIDTH - CURVE_COORD_WIDTH + 2);
+ drawCurveCoord(left, CURVE_CENTER_Y + CURVE_SIDE_WIDTH + 2, textx);
+ int top = limit(CURVE_CENTER_Y - CURVE_SIDE_WIDTH - 1, -CURVE_COORD_HEIGHT / 2 + y, CURVE_CENTER_Y + CURVE_SIDE_WIDTH - CURVE_COORD_HEIGHT + 1);
+ drawCurveCoord(CURVE_CENTER_X-CURVE_SIDE_WIDTH - 37, top, texty);
+}
diff --git a/radio/src/gui/480x272/draw_functions.h b/radio/src/gui/480x272/draw_functions.h
index 0d872d87e..f4f672c72 100644
--- a/radio/src/gui/480x272/draw_functions.h
+++ b/radio/src/gui/480x272/draw_functions.h
@@ -74,7 +74,7 @@ void drawShutdownAnimation(uint32_t duration, uint32_t totalDuration, const char
// Main view standard widgets
void drawTopBar();
void drawMainPots();
-void drawTrims(uint8_t flightMode);
+void drawTrims(uint8_t flightMode, bool sliderdisplayed = true);
void drawReceiverName(coord_t x, coord_t y, uint8_t moduleIdx, uint8_t receiverIdx, LcdFlags flags);
diff --git a/radio/src/gui/480x272/layout.h b/radio/src/gui/480x272/layout.h
index bd5d562aa..0600ea30d 100644
--- a/radio/src/gui/480x272/layout.h
+++ b/radio/src/gui/480x272/layout.h
@@ -18,8 +18,7 @@
* GNU General Public License for more details.
*/
-#ifndef _LAYOUT_H_
-#define _LAYOUT_H_
+#pragma once
#include
#include "widgets_container.h"
@@ -122,5 +121,3 @@ Layout * loadLayout(const char * name, Layout::PersistentData * persistentData);
void loadCustomScreens();
std::list & getRegisteredLayouts();
-
-#endif // _LAYOUT_H_
diff --git a/radio/src/gui/480x272/layouts/layout4+2.cpp b/radio/src/gui/480x272/layouts/layout4+2.cpp
new file mode 100644
index 000000000..c9846ec04
--- /dev/null
+++ b/radio/src/gui/480x272/layouts/layout4+2.cpp
@@ -0,0 +1,111 @@
+/*
+ * 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.
+ */
+
+#include "opentx.h"
+
+#define HAS_TOPBAR() (persistentData->options[0].boolValue == true)
+#define HAS_FM() (persistentData->options[1].boolValue == true)
+#define HAS_SLIDERS() (persistentData->options[2].boolValue == true)
+#define HAS_TRIMS() (persistentData->options[3].boolValue == true)
+#define IS_MIRRORED() (persistentData->options[4].boolValue == true)
+
+const uint8_t LBM_LAYOUT_4P2[] = {
+#include "mask_layout4+2.lbm"
+};
+
+const ZoneOption OPTIONS_LAYOUT_4P2[] = {
+ { STR_TOP_BAR, ZoneOption::Bool },
+ { STR_FLIGHT_MODE, ZoneOption::Bool },
+ { STR_SLIDERS, ZoneOption::Bool },
+ { STR_TRIMS, ZoneOption::Bool },
+ { STR_MIRROR, ZoneOption::Bool },
+ { NULL, ZoneOption::Bool }
+};
+
+class Layout4P2: public Layout
+{
+ public:
+ Layout4P2(const LayoutFactory * factory, Layout::PersistentData * persistentData):
+ Layout(factory, persistentData)
+ {
+ }
+
+ virtual void create()
+ {
+ Layout::create();
+ persistentData->options[0].boolValue = true;
+ persistentData->options[1].boolValue = true;
+ persistentData->options[2].boolValue = true;
+ persistentData->options[3].boolValue = true;
+ persistentData->options[4].boolValue = false;
+ persistentData->options[5].boolValue = false;
+ }
+
+ virtual unsigned int getZonesCount() const
+ {
+ return 6;
+ }
+
+ virtual Zone getZone(unsigned int index) const
+ {
+ coord_t areaw = LCD_W - (HAS_SLIDERS() ? 55 : 8) - (HAS_TRIMS() ? 55 : 8);
+ coord_t areah = LCD_H - 4 - (HAS_TOPBAR() ? 55 : 8) - (HAS_SLIDERS() ? 26 : 4) - (HAS_TRIMS() ? 26 : 4);
+
+ Zone zone;
+ zone.x = IS_MIRRORED() ? ((index >= 4) ? (LCD_W - areaw) / 2 - 4 : 245) : ((index >= 4) ? 245 : (LCD_W - areaw) / 2 - 4);
+ zone.h = (index >= 4) ? (areah / 2) : (areah / 4) - 2;
+ zone.y = (index >= 4) ? (HAS_TOPBAR() ? 52 : 6) + (index == 5 ? zone.h + ((HAS_TRIMS() + HAS_SLIDERS() == 1) ? 8 : 10): 0): (HAS_TOPBAR() ? 52 : 6) + (index % 4) * (zone.h + 6);
+ zone.w = areaw / 2;
+
+ return zone;
+ }
+
+ virtual void refresh();
+};
+
+void Layout4P2::refresh()
+{
+ theme->drawBackground();
+
+ if (HAS_TOPBAR()) {
+ drawTopBar();
+ }
+
+ if (HAS_FM()) {
+ // Flight mode
+ lcdDrawSizedText(LCD_W / 2 - getTextWidth(g_model.flightModeData[mixerCurrentFlightMode].name, sizeof(g_model.flightModeData[mixerCurrentFlightMode].name),
+ ZCHAR | SMLSIZE) / 2, 232, g_model.flightModeData[mixerCurrentFlightMode].name,
+ sizeof(g_model.flightModeData[mixerCurrentFlightMode].name), ZCHAR | SMLSIZE);
+ }
+
+ if (HAS_SLIDERS()) {
+ // Pots and rear sliders positions
+ drawMainPots();
+ }
+
+ if (HAS_TRIMS()) {
+ // Trims
+ drawTrims(mixerCurrentFlightMode, HAS_SLIDERS());
+ }
+
+ Layout::refresh();
+}
+
+BaseLayoutFactory layout4P2("Layout4P2", LBM_LAYOUT_4P2, OPTIONS_LAYOUT_4P2);
\ No newline at end of file
diff --git a/radio/src/gui/480x272/layouts/mask_layout4+2.png b/radio/src/gui/480x272/layouts/mask_layout4+2.png
new file mode 100644
index 000000000..c441da1a3
Binary files /dev/null and b/radio/src/gui/480x272/layouts/mask_layout4+2.png differ
diff --git a/radio/src/gui/480x272/lcd.cpp b/radio/src/gui/480x272/lcd.cpp
index e2c660f73..45d8fe974 100644
--- a/radio/src/gui/480x272/lcd.cpp
+++ b/radio/src/gui/480x272/lcd.cpp
@@ -452,30 +452,31 @@ void lcdDrawBlackOverlay()
#if defined(MULTIMODULE)
void lcdDrawMultiProtocolString(coord_t x, coord_t y, uint8_t moduleIdx, uint8_t protocol, LcdFlags flags)
{
- if (protocol <= MODULE_SUBTYPE_MULTI_LAST) {
+ MultiModuleStatus & status = getMultiModuleStatus(moduleIdx);
+ if (status.protocolName[0] && status.isValid()) {
+ lcdDrawText(x, y, status.protocolName, flags);
+ }
+ else if (protocol <= MODULE_SUBTYPE_MULTI_LAST) {
lcdDrawTextAtIndex(x, y, STR_MULTI_PROTOCOLS, protocol, flags);
}
else {
- MultiModuleStatus &status = getMultiModuleStatus(moduleIdx);
- if (status.protocolName[0] && status.isValid())
- lcdDrawText(x, y, status.protocolName, flags);
- else
- lcdDrawNumber(x, y, protocol + 3, flags); // Convert because of OpenTX FrSky fidling (OpenTX protocol tables and Multiprotocol tables don't match)
+ lcdDrawNumber(x, y, protocol + 3, flags); // Convert because of OpenTX FrSky fidling (OpenTX protocol tables and Multiprotocol tables don't match)
}
}
void lcdDrawMultiSubProtocolString(coord_t x, coord_t y, uint8_t moduleIdx, uint8_t subType, LcdFlags flags)
{
- const mm_protocol_definition *pdef = getMultiProtocolDefinition(g_model.moduleData[moduleIdx].getMultiProtocol());
- if (subType <= pdef->maxSubtype && pdef->subTypeString != nullptr) {
+ MultiModuleStatus & status = getMultiModuleStatus(moduleIdx);
+ const mm_protocol_definition * pdef = getMultiProtocolDefinition(g_model.moduleData[moduleIdx].getMultiProtocol());
+
+ if (status.protocolName[0] && status.isValid()) {
+ lcdDrawText(x, y, status.protocolSubName, flags);
+ }
+ else if (subType <= pdef->maxSubtype && pdef->subTypeString != nullptr) {
lcdDrawTextAtIndex(x, y, pdef->subTypeString, subType, flags);
}
else {
- MultiModuleStatus &status = getMultiModuleStatus(moduleIdx);
- if (status.protocolName[0] && status.isValid())
- lcdDrawText(x, y, status.protocolSubName, flags);
- else
- lcdDrawNumber(x, y, subType, flags);
+ lcdDrawNumber(x, y, subType, flags);
}
}
#endif
diff --git a/radio/src/gui/480x272/menu_model.cpp b/radio/src/gui/480x272/menu_model.cpp
index 09ce6523f..f376e36a2 100644
--- a/radio/src/gui/480x272/menu_model.cpp
+++ b/radio/src/gui/480x272/menu_model.cpp
@@ -152,6 +152,8 @@ void editName(coord_t x, coord_t y, char * name, uint8_t size, event_t event, ui
uint8_t s_currIdx;
uint8_t s_currIdxSubMenu;
+uint16_t s_currSrcRaw;
+uint16_t s_currScale;
void copySelection(char * dst, const char * src, uint8_t size)
{
diff --git a/radio/src/gui/480x272/menus.h b/radio/src/gui/480x272/menus.h
index 290ff43ac..82227a3bc 100644
--- a/radio/src/gui/480x272/menus.h
+++ b/radio/src/gui/480x272/menus.h
@@ -224,6 +224,7 @@ bool menuRadioHardware(event_t event);
bool menuRadioCalibration(event_t event);
bool menuRadioSpectrumAnalyser(event_t event);
bool menuRadioPowerMeter(event_t event);
+bool menuGhostModuleConfig(event_t event);
extern const MenuHandlerFunc menuTabGeneral[MENU_RADIO_PAGES_COUNT];
@@ -460,6 +461,8 @@ extern int8_t s_copySrcRow;
extern int8_t s_copyTgtOfs;
extern uint8_t s_currIdx;
extern uint8_t s_currIdxSubMenu;
+extern uint16_t s_currSrcRaw;
+extern uint16_t s_currScale;
extern int8_t s_currCh;
extern uint8_t s_copySrcIdx;
extern uint8_t s_copySrcCh;
@@ -626,6 +629,7 @@ void readModelNotes();
typedef int (*FnFuncP) (int x);
void drawFunction(FnFuncP fn, int x, int y, int width);
+void drawCursor(FnFuncP fn);
void onSourceLongEnterPress(const char *result);
diff --git a/radio/src/gui/480x272/model_curves.cpp b/radio/src/gui/480x272/model_curves.cpp
index e53f9aad4..852e80f2e 100644
--- a/radio/src/gui/480x272/model_curves.cpp
+++ b/radio/src/gui/480x272/model_curves.cpp
@@ -203,6 +203,8 @@ bool menuModelCurveOne(event_t event)
drawCurve(CURVE_CENTER_X, CURVE_CENTER_Y, CURVE_SIDE_WIDTH);
drawCurveHorizontalScale();
if (menuVerticalPosition < ITEM_CURVE_COORDS1) drawCurveVerticalScale(CURVE_CENTER_X-CURVE_SIDE_WIDTH-15);
+ if (s_currSrcRaw != MIXSRC_NONE)
+ drawCursor(applyCurrentCurve);
coord_t posX = 47;
attr = (s_editMode > 0 ? INVERS|BLINK : INVERS);
@@ -324,6 +326,7 @@ bool menuModelCurvesAll(event_t event)
switch (event) {
case EVT_KEY_BREAK(KEY_ENTER):
if (!READ_ONLY()) {
+ s_currSrcRaw = MIXSRC_NONE;
pushMenu(menuModelCurveOne);
}
break;
diff --git a/radio/src/gui/480x272/model_inputs.cpp b/radio/src/gui/480x272/model_inputs.cpp
index c6a868df6..8f59cf94b 100644
--- a/radio/src/gui/480x272/model_inputs.cpp
+++ b/radio/src/gui/480x272/model_inputs.cpp
@@ -185,38 +185,11 @@ bool menuModelExpoOne(event_t event)
drawFunction(expoFn, CURVE_CENTER_X, CURVE_CENTER_Y, CURVE_SIDE_WIDTH);
drawCurveHorizontalScale();
- drawCurveVerticalScale(CURVE_CENTER_X-CURVE_SIDE_WIDTH-15);
-
- {
- char textx[5];
- char texty[5];
- int x = getValue(ed->srcRaw);
- if (ed->srcRaw >= MIXSRC_FIRST_TELEM) {
- strAppendUnsigned(textx, calcRESXto100(x));
- // TODO drawSensorCustomValue(LCD_W-8, 6*FH, ed->srcRaw - MIXSRC_FIRST_TELEM, x);
- if (ed->scale > 0) x = (x * 1024) / convertTelemValue(ed->srcRaw - MIXSRC_FIRST_TELEM + 1, ed->scale);
- }
- else {
- strAppendSigned(textx, calcRESXto100(x));
- }
-
- x = limit(-1024, x, 1024);
- int y = limit(-1024, expoFn(x), 1024);
- strAppendSigned(texty, calcRESXto100(y));
-
- x = divRoundClosest(x*CURVE_SIDE_WIDTH, RESX);
- y = CURVE_CENTER_Y + getCurveYCoord(expoFn, x, CURVE_SIDE_WIDTH);
-
- lcdDrawSolidFilledRect(CURVE_CENTER_X+x, CURVE_CENTER_Y-CURVE_SIDE_WIDTH, 2, 2*CURVE_SIDE_WIDTH+2, CURVE_CURSOR_COLOR);
- lcdDrawSolidFilledRect(CURVE_CENTER_X-CURVE_SIDE_WIDTH-2, y-1, 2*CURVE_SIDE_WIDTH+2, 2, CURVE_CURSOR_COLOR);
- lcdDrawBitmapPattern(CURVE_CENTER_X+x-4, y-4, LBM_CURVE_POINT, CURVE_CURSOR_COLOR);
- lcdDrawBitmapPattern(CURVE_CENTER_X+x-4, y-4, LBM_CURVE_POINT_CENTER, TEXT_BGCOLOR);
-
- int left = limit(CURVE_CENTER_X-CURVE_SIDE_WIDTH, CURVE_CENTER_X-CURVE_COORD_WIDTH/2+x, CURVE_CENTER_X+CURVE_SIDE_WIDTH-CURVE_COORD_WIDTH+2);
- drawCurveCoord(left, CURVE_CENTER_Y+CURVE_SIDE_WIDTH+2, textx);
- int top = limit(CURVE_CENTER_Y-CURVE_SIDE_WIDTH-1, -CURVE_COORD_HEIGHT/2+y, CURVE_CENTER_Y+CURVE_SIDE_WIDTH-CURVE_COORD_HEIGHT+1);
- drawCurveCoord(CURVE_CENTER_X-CURVE_SIDE_WIDTH-37, top, texty);
- }
+ drawCurveVerticalScale(CURVE_CENTER_X-CURVE_SIDE_WIDTH - 15);
+ // those parameters are global so that they can be reused in the curve edit screen
+ s_currSrcRaw = ed->srcRaw;
+ s_currScale = ed->scale;
+ drawCursor(expoFn);
for (uint8_t k=0; ksrcRaw = checkIncDec(event, ed->srcRaw, INPUTSRC_FIRST, INPUTSRC_LAST, EE_MODEL|INCDEC_SOURCE|NO_INCDEC_MARKS, isSourceAvailableInInputs);
if (ed->srcRaw >= MIXSRC_FIRST_TELEM) {
- drawSensorCustomValue(EXPO_ONE_2ND_COLUMN+75, y, (ed->srcRaw - MIXSRC_FIRST_TELEM)/3, convertTelemValue(ed->srcRaw - MIXSRC_FIRST_TELEM + 1, ed->scale), LEFT|(menuHorizontalPosition==1?attr:0));
+ drawSensorCustomValue(EXPO_ONE_2ND_COLUMN+75, y, (ed->srcRaw - MIXSRC_FIRST_TELEM)/3, getValue(ed->srcRaw), LEFT|(menuHorizontalPosition==1?attr:0));
if (attr && menuHorizontalPosition == 1) ed->scale = checkIncDec(event, ed->scale, 0, maxTelemValue(ed->srcRaw - MIXSRC_FIRST_TELEM + 1), EE_MODEL);
}
else if (attr) {
diff --git a/radio/src/gui/480x272/model_mixes.cpp b/radio/src/gui/480x272/model_mixes.cpp
index da1b74f78..150109204 100644
--- a/radio/src/gui/480x272/model_mixes.cpp
+++ b/radio/src/gui/480x272/model_mixes.cpp
@@ -207,10 +207,12 @@ bool menuModelMixOne(event_t event)
drawSource(MIXES_2ND_COLUMN, y, md2->srcRaw, attr);
if (attr) CHECK_INCDEC_MODELSOURCE(event, md2->srcRaw, 1, MIXSRC_LAST);
break;
+
case MIX_FIELD_WEIGHT:
lcdDrawText(MENUS_MARGIN_LEFT, y, STR_WEIGHT);
gvarWeightItem(MIXES_2ND_COLUMN, y, md2, attr|LEFT, event);
break;
+
case MIX_FIELD_OFFSET:
{
lcdDrawText(MENUS_MARGIN_LEFT, y, STR_OFFSET);
@@ -230,6 +232,8 @@ bool menuModelMixOne(event_t event)
break;
case MIX_FIELD_CURVE:
lcdDrawText(MENUS_MARGIN_LEFT, y, STR_CURVE);
+ s_currSrcRaw = md2->srcRaw;
+ s_currScale = 0;
editCurveRef(MIXES_2ND_COLUMN, y, md2->curve, event, attr);
break;
#if defined(FLIGHT_MODES)
diff --git a/radio/src/gui/480x272/model_outputs.cpp b/radio/src/gui/480x272/model_outputs.cpp
index 300f8909b..70ac2f76f 100644
--- a/radio/src/gui/480x272/model_outputs.cpp
+++ b/radio/src/gui/480x272/model_outputs.cpp
@@ -96,6 +96,14 @@ bool menuModelLimits(event_t event)
uint32_t sub = menuVerticalPosition;
+ if (sub < MAX_OUTPUT_CHANNELS) {
+#if defined(PPM_CENTER_ADJUSTABLE) || defined(PPM_UNIT_US)
+ lcdDrawNumber(LCD_W / 2, MENU_TITLE_TOP + 1, PPM_CH_CENTER(sub)+channelOutputs[sub]/2, MENU_TITLE_COLOR, 0, "", STR_US);
+#else
+ lcdDrawNumber(LCD_W / 2, MENU_TITLE_TOP + 1, calcRESXto1000(channelOutputs[sub]), PREC1 | MENU_TITLE_COLOR);
+#endif
+ }
+
if (sub=0) {
drawColumnHeader(STR_LIMITS_HEADERS, NULL, menuHorizontalPosition);
}
diff --git a/radio/src/gui/480x272/model_receiver_options.cpp b/radio/src/gui/480x272/model_receiver_options.cpp
index 90db6f7e3..0a2e2e4e6 100644
--- a/radio/src/gui/480x272/model_receiver_options.cpp
+++ b/radio/src/gui/480x272/model_receiver_options.cpp
@@ -47,7 +47,7 @@ enum {
ITEM_RECEIVER_SETTINGS_PWM_RATE,
ITEM_RECEIVER_SETTINGS_TELEMETRY,
ITEM_RECEIVER_SETTINGS_TELEMETRY_25MW,
- ITEM_RECEIVER_SETTINGS_SPORT_FPORT,
+ ITEM_RECEIVER_SETTINGS_SPORT_MODE,
ITEM_RECEIVER_SETTINGS_CAPABILITY_NOT_SUPPORTED1,
ITEM_RECEIVER_SETTINGS_CAPABILITY_NOT_SUPPORTED2,
ITEM_RECEIVER_SETTINGS_PINMAP_FIRST
@@ -59,6 +59,15 @@ enum {
#define CH_ENABLE_SPORT 4
#define CH_ENABLE_SBUS 5
+bool isSPortModeAvailable(int mode)
+{
+ uint8_t receiverId = reusableBuffer.hardwareAndSettings.receiverSettings.receiverId;
+ if (mode == 2 && !IS_RECEIVER_CAPABILITY_ENABLED(RECEIVER_CAPABILITY_FPORT2)) {
+ return false;
+ }
+ return true;
+}
+
bool menuModelReceiverOptions(event_t event)
{
const int lim = (g_model.extendedLimits ? (512 * LIMIT_EXT_PERCENT / 100) : 512) * 2;
@@ -81,7 +90,7 @@ bool menuModelReceiverOptions(event_t event)
0, // PWM rate
isModuleR9MAccess(g_moduleIdx) && receiverVariant == PXX2_VARIANT_EU && reusableBuffer.hardwareAndSettings.moduleSettings.txPower > 14 /*25mW*/ ? READONLY_ROW : (uint8_t)0, // Telemetry
IF_RECEIVER_CAPABILITY(RECEIVER_CAPABILITY_TELEMETRY_25MW, 0),
- IF_RECEIVER_CAPABILITY(RECEIVER_CAPABILITY_FPORT, 0),
+ uint8_t((IS_RECEIVER_CAPABILITY_ENABLED(RECEIVER_CAPABILITY_FPORT) || IS_RECEIVER_CAPABILITY_ENABLED(RECEIVER_CAPABILITY_FPORT2)) ? 0 : HIDDEN_ROW),
uint8_t(reusableBuffer.hardwareAndSettings.modules[g_moduleIdx].receivers[receiverId].information.capabilityNotSupported ? READONLY_ROW : HIDDEN_ROW),
uint8_t(reusableBuffer.hardwareAndSettings.modules[g_moduleIdx].receivers[receiverId].information.capabilityNotSupported ? READONLY_ROW : HIDDEN_ROW),
0 // channels ...
@@ -169,13 +178,19 @@ bool menuModelReceiverOptions(event_t event)
}
break;
- case ITEM_RECEIVER_SETTINGS_SPORT_FPORT:
- lcdDrawText(MENUS_MARGIN_LEFT, y, "F.Port");
- reusableBuffer.hardwareAndSettings.receiverSettings.fport = editCheckBox(reusableBuffer.hardwareAndSettings.receiverSettings.fport, RECEIVER_OPTIONS_2ND_COLUMN, y, attr, event);
- if (attr && checkIncDec_Ret) {
+ case ITEM_RECEIVER_SETTINGS_SPORT_MODE:
+ {
+ lcdDrawText(0, y, STR_PROTOCOL);
+ uint8_t portType = reusableBuffer.hardwareAndSettings.receiverSettings.fport | (reusableBuffer.hardwareAndSettings.receiverSettings.fport2 << 1);
+ lcdDrawTextAtIndex(LCD_W/2, y, STR_SPORT_MODES, portType, attr);
+ portType = checkIncDec(event, portType, 0, 2, EE_MODEL, isSPortModeAvailable);
+ if (checkIncDec_Ret) {
+ reusableBuffer.hardwareAndSettings.receiverSettings.fport = portType & 0x01;
+ reusableBuffer.hardwareAndSettings.receiverSettings.fport2 = (portType & 0x02) >> 1;
reusableBuffer.hardwareAndSettings.receiverSettings.dirty = RECEIVER_SETTINGS_DIRTY;
}
break;
+ }
case ITEM_RECEIVER_SETTINGS_CAPABILITY_NOT_SUPPORTED1:
lcdDrawText(LCD_W/2, y+1, STR_MORE_OPTIONS_AVAILABLE, SMLSIZE|CENTERED);
diff --git a/radio/src/gui/480x272/model_select.cpp b/radio/src/gui/480x272/model_select.cpp
index 36dac8ba8..33c9453fe 100644
--- a/radio/src/gui/480x272/model_select.cpp
+++ b/radio/src/gui/480x272/model_select.cpp
@@ -191,7 +191,6 @@ bool menuModelWizard(event_t event)
uint16_t x = WIZARD_LEFT_SPACING + (wizidx - first) * (WIZARD_SPACING + WIZARD_ICON_X);
strcpy(&wizpath[sizeof(WIZARD_PATH)], fno.fname);
strcpy(&wizpath[sizeof(WIZARD_PATH) + strlen(fno.fname)], "/icon.png");
- lcdDrawText(x + 10, WIZARD_TEXT_Y, fno.fname);
BitmapBuffer * background = BitmapBuffer::load(wizpath);
lcd->drawBitmap(x, WIZARD_ICON_Y, background);
if(wizidx == wizardSelected ) {
@@ -242,6 +241,11 @@ void onDeleteModelConfirm(const char * result)
void onModelSelectMenu(const char * result)
{
if (result == STR_SELECT_MODEL) {
+ if (!g_eeGeneral.disableRssiPoweroffAlarm) {
+ if (!confirmModelChange())
+ return;
+ }
+
// we store the latest changes if any
storageFlushCurrentModel();
storageCheck(true);
@@ -259,6 +263,10 @@ void onModelSelectMenu(const char * result)
deleteMode = MODE_DELETE_MODEL;
}
else if (result == STR_CREATE_MODEL) {
+ if (!g_eeGeneral.disableRssiPoweroffAlarm) {
+ if (!confirmModelChange())
+ return;
+ }
storageCheck(true);
modelslist.addModel(currentCategory, createModel());
selectMode = MODE_SELECT_MODEL;
diff --git a/radio/src/gui/480x272/model_setup.cpp b/radio/src/gui/480x272/model_setup.cpp
index 556b1f2bf..a181a458f 100644
--- a/radio/src/gui/480x272/model_setup.cpp
+++ b/radio/src/gui/480x272/model_setup.cpp
@@ -53,6 +53,7 @@ enum MenuModelSetupItems {
ITEM_MODEL_SETUP_THROTTLE_REVERSED,
ITEM_MODEL_SETUP_THROTTLE_TRACE,
ITEM_MODEL_SETUP_THROTTLE_TRIM,
+ ITEM_MODEL_SETUP_THROTTLE_TRIM_SWITCH,
ITEM_MODEL_SETUP_PREFLIGHT_LABEL,
ITEM_MODEL_SETUP_CHECKLIST_DISPLAY,
ITEM_MODEL_SETUP_THROTTLE_WARNING,
@@ -74,6 +75,7 @@ enum MenuModelSetupItems {
ITEM_MODEL_SETUP_INTERNAL_MODULE_SYNCSTATUS,
#endif
ITEM_MODEL_SETUP_INTERNAL_MODULE_CHANNELS,
+ ITEM_MODEL_SETUP_INTERNAL_MODULE_RACING_MODE,
ITEM_MODEL_SETUP_INTERNAL_MODULE_NOT_ACCESS_RXNUM_BIND_RANGE,
ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_MODEL_NUM,
ITEM_MODEL_SETUP_INTERNAL_MODULE_OPTIONS,
@@ -514,7 +516,7 @@ int getSwitchWarningsCount()
inline uint8_t MODULE_TYPE_ROWS(int moduleIdx)
{
- if (isModuleXJT(moduleIdx) || isModuleR9MNonAccess(moduleIdx) || isModuleDSM2(moduleIdx) || isModulePXX2(moduleIdx) || isModuleAFHDS3(moduleIdx))
+ if (isModuleXJT(moduleIdx) || isModuleR9MNonAccess(moduleIdx) || isModuleDSM2(moduleIdx) || isModuleISRM(moduleIdx) || isModuleAFHDS3(moduleIdx))
return 1;
#if defined(MULTIMODULE)
else if (isModuleMultimodule(moduleIdx)) {
@@ -576,7 +578,8 @@ void onModelAntennaSwitchConfirm(const char * result)
MODULE_TYPE_ROWS(INTERNAL_MODULE), /* ITEM_MODEL_SETUP_INTERNAL_MODULE_TYPE*/ \
MULTIMODULE_STATUS_ROWS(INTERNAL_MODULE) /* ITEM_MODEL_SETUP_INTERNAL_MODULE_STATUS, ITEM_MODEL_SETUP_INTERNAL_MODULE_SYNCSTATUS */ \
MODULE_CHANNELS_ROWS(INTERNAL_MODULE), /* ITEM_MODEL_SETUP_INTERNAL_MODULE_CHANNELS*/ \
- IF_NOT_ACCESS_MODULE_RF(INTERNAL_MODULE, IF_INTERNAL_MODULE_ON(IF_INTERNAL_MODULE_ON(isModuleRxNumAvailable(INTERNAL_MODULE) ? (uint8_t)2 : (uint8_t)1))), /* *ITEM_MODEL_SETUP_INTERNAL_MODULE_NOT_ACCESS_RXNUM_BIND_RANGE */\
+ IF_ALLOW_RACING_MODE(INTERNAL_MODULE), /* ITEM_MODEL_SETUP_INTERNAL_MODULE_RACING_MODE */ \
+ IF_NOT_ACCESS_MODULE_RF(INTERNAL_MODULE, MODULE_BIND_ROWS(INTERNAL_MODULE)), /* *ITEM_MODEL_SETUP_INTERNAL_MODULE_NOT_ACCESS_RXNUM_BIND_RANGE */\
IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 0), /* ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_MODEL_NUM*/ \
MODULE_OPTION_ROW(INTERNAL_MODULE), /* ITEM_MODEL_SETUP_INTERNAL_MODULE_OPTIONS */ \
MULTIMODULE_MODULE_ROWS(INTERNAL_MODULE) /* ITEM_MODEL_SETUP_INTERNAL_MODULE_AUTOBIND */ \
@@ -614,6 +617,7 @@ bool menuModelSetup(event_t event)
0, // Throttle reverse
0, // Throttle trace source
0, // Throttle trim
+ 0, // Throttle trim switch
LABEL(PreflightCheck),
0, // Display checklist
@@ -835,6 +839,13 @@ bool menuModelSetup(event_t event)
g_model.thrTrim = editCheckBox(g_model.thrTrim, MODEL_SETUP_2ND_COLUMN, y, attr, event);
break;
+ case ITEM_MODEL_SETUP_THROTTLE_TRIM_SWITCH:
+ lcdDrawText(MENUS_MARGIN_LEFT, y, STR_TTRIM_SW);
+ if (attr)
+ CHECK_INCDEC_MODELVAR_ZERO(event, g_model.thrTrimSw, NUM_TRIMS - 1);
+ drawSource(MODEL_SETUP_2ND_COLUMN, y, g_model.getThrottleStickTrimSource(), attr);
+ break;
+
case ITEM_MODEL_SETUP_PREFLIGHT_LABEL:
lcdDrawText(MENUS_MARGIN_LEFT, y, STR_PREFLIGHT);
break;
@@ -1238,6 +1249,17 @@ bool menuModelSetup(event_t event)
}
break;
}
+
+#if defined(HARDWARE_INTERNAL_MODULE)
+ case ITEM_MODEL_SETUP_INTERNAL_MODULE_RACING_MODE:
+ {
+ ModuleData & moduleData = g_model.moduleData[moduleIdx];
+ lcdDrawText(MENUS_MARGIN_LEFT + INDENT_WIDTH, y, STR_RACING_MODE);
+ moduleData.pxx2.racingMode = editCheckBox(moduleData.pxx2.racingMode, MODEL_SETUP_2ND_COLUMN, y, attr, event);
+ break;
+ }
+#endif
+
case ITEM_MODEL_SETUP_TRAINER_LABEL:
lcdDrawText(MENUS_MARGIN_LEFT, y, STR_TRAINER);
break;
@@ -1540,17 +1562,16 @@ bool menuModelSetup(event_t event)
lcdDrawText(MENUS_MARGIN_LEFT + INDENT_WIDTH, y, STR_RECEIVER);
int l_posHorz = menuHorizontalPosition;
coord_t bindButtonPos = MODEL_SETUP_2ND_COLUMN;
+ // RXNUM
if (isModuleRxNumAvailable(moduleIdx)) {
lcdDrawNumber(MODEL_SETUP_2ND_COLUMN, y, g_model.header.modelId[moduleIdx], (l_posHorz==0 ? attr : 0) | LEADING0 | LEFT, 2);
bindButtonPos += 40;
- }
- else if (attr) {
- l_posHorz += 1;
- }
- if (isModuleBindRangeAvailable(moduleIdx)) {
if (attr && l_posHorz == 0) {
if (s_editMode > 0) {
CHECK_INCDEC_MODELVAR_ZERO(event, g_model.header.modelId[moduleIdx], getMaxRxNum(moduleIdx));
+ if (checkIncDec_Ret && isModuleCrossfire(moduleIdx)) {
+ moduleState[EXTERNAL_MODULE].counter = CRSF_FRAME_MODELID;
+ }
if (event == EVT_KEY_LONG(KEY_ENTER)) {
killEvents(event);
uint8_t newVal = modelslist.findNextUnusedModelId(moduleIdx);
@@ -1561,11 +1582,17 @@ bool menuModelSetup(event_t event)
}
}
}
+ }
+ else if (attr) {
+ l_posHorz += 1;
+ }
+ // BIND - RANGE
+ if (isModuleBindRangeAvailable(moduleIdx)) {
drawButton(bindButtonPos, y, STR_MODULE_BIND, (moduleState[moduleIdx].mode == MODULE_MODE_BIND ? BUTTON_ON : BUTTON_OFF) | (l_posHorz==1 ? attr : 0));
if (isModuleRangeAvailable(moduleIdx)) {
drawButton(bindButtonPos + 80, y, STR_MODULE_RANGE, (moduleState[moduleIdx].mode == MODULE_MODE_RANGECHECK ? BUTTON_ON : BUTTON_OFF) | (l_posHorz==2 ? attr : 0));
}
- uint8_t newFlag = 0;
+ uint8_t newFlag = MODULE_MODE_NORMAL;
#if defined(MULTIMODULE)
if (getMultiBindStatus(moduleIdx) == MULTI_BIND_FINISHED) {
setMultiBindStatus(moduleIdx, MULTI_NORMAL_OPERATION);
@@ -1639,7 +1666,6 @@ bool menuModelSetup(event_t event)
if (event == EVT_KEY_LONG(KEY_ENTER)) {
killEvents(event);
setCustomFailsafe(moduleIdx);
- storageDirty(EE_MODEL);
AUDIO_WARNING1();
SEND_FAILSAFE_NOW(moduleIdx);
}
@@ -1662,34 +1688,33 @@ bool menuModelSetup(event_t event)
{
#if defined(MULTIMODULE)
if (MULTIMODULE_PROTOCOL_KNOWN(moduleIdx)) {
+ const char * title = getMultiOptionTitle(moduleIdx);
+
+ lcdDrawText(MENUS_MARGIN_LEFT + INDENT_WIDTH, y, title);
+ if (title == STR_MULTI_RFTUNE) {
+ lcdDrawNumber(LCD_W - 10, y, TELEMETRY_RSSI(), RIGHT, 0, "RSSI(", ")");
+ }
+
int optionValue = g_model.moduleData[moduleIdx].multi.optionValue;
-
- MultiModuleStatus &status = getMultiModuleStatus(moduleIdx);
const uint8_t multi_proto = g_model.moduleData[moduleIdx].getMultiProtocol();
- if (status.isValid()) {
- lcdDrawText(MENUS_MARGIN_LEFT + INDENT_WIDTH, y, mm_options_strings::options[status.optionDisp]);
- if (attr && status.optionDisp == 2) {
- lcdDrawNumber(LCD_W - 10, y, TELEMETRY_RSSI(), RIGHT, 0, "RSSI(", ")");
- }
- }
- else {
- const mm_protocol_definition * pdef = getMultiProtocolDefinition(multi_proto);
- if (pdef->optionsstr) {
- lcdDrawText(MENUS_MARGIN_LEFT + INDENT_WIDTH, y, pdef->optionsstr);
- if (attr && pdef->optionsstr == STR_MULTI_RFTUNE) {
- lcdDrawNumber(LCD_W - 10, y, TELEMETRY_RSSI(), RIGHT, 0, "RSSI(", ")");
- }
- }
- }
-
int8_t min, max;
getMultiOptionValues(multi_proto, min, max);
- if (multi_proto == MODULE_SUBTYPE_MULTI_FS_AFHDS2A) {
- lcdDrawNumber(MODEL_SETUP_2ND_COLUMN, y, 50 + 5 * optionValue, LEFT | attr);
- }
- else if (multi_proto == MODULE_SUBTYPE_MULTI_FRSKY_R9) {
+ if (title == STR_MULTI_RFPOWER) {
lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_MULTI_POWER, optionValue, LEFT | attr);
+ min = 0;
+ max = 15;
+ }
+ else if (title == STR_MULTI_TELEMETRY) {
+ lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_MULTI_TELEMETRY_MODE, optionValue, LEFT | attr);
+ }
+ else if (title == STR_MULTI_WBUS) {
+ lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_MULTI_WBUS_MODE, optionValue, LEFT | attr);
+ min = 0;
+ max = 1;
+ }
+ else if (multi_proto == MODULE_SUBTYPE_MULTI_FS_AFHDS2A) {
+ lcdDrawNumber(MODEL_SETUP_2ND_COLUMN, y, 50 + 5 * optionValue, LEFT | attr);
}
else if (multi_proto == MODULE_SUBTYPE_MULTI_DSM2) {
optionValue = optionValue & 0x01;
@@ -1701,6 +1726,7 @@ bool menuModelSetup(event_t event)
else
lcdDrawNumber(MODEL_SETUP_2ND_COLUMN, y, optionValue, LEFT | attr);
}
+
if (attr) {
CHECK_INCDEC_MODELVAR(event, optionValue, min, max);
if (checkIncDec_Ret) {
diff --git a/radio/src/gui/480x272/model_special_functions.cpp b/radio/src/gui/480x272/model_special_functions.cpp
index d8876a35d..712ab7ba2 100644
--- a/radio/src/gui/480x272/model_special_functions.cpp
+++ b/radio/src/gui/480x272/model_special_functions.cpp
@@ -333,6 +333,14 @@ bool menuSpecialFunctions(event_t event, CustomFunctionData * functions, CustomF
INCDEC_ENABLE_CHECK(isSourceAvailable);
}
}
+ else if (func == FUNC_BACKLIGHT) {
+ val_max = MIXSRC_LAST_CH;
+ drawSource(MODEL_SPECIAL_FUNC_3RD_COLUMN, y, val_displayed, attr);
+ if (active) {
+ INCDEC_SET_FLAG(eeFlags | INCDEC_SOURCE);
+ INCDEC_ENABLE_CHECK(isSourceAvailable);
+ }
+ }
else if (func == FUNC_LOGS) {
if (val_displayed) {
lcdDrawNumber(MODEL_SPECIAL_FUNC_3RD_COLUMN, y, val_displayed, attr|PREC1|LEFT, 0, NULL, "s");
diff --git a/radio/src/gui/480x272/model_telemetry.cpp b/radio/src/gui/480x272/model_telemetry.cpp
index 82138dff3..6454de138 100644
--- a/radio/src/gui/480x272/model_telemetry.cpp
+++ b/radio/src/gui/480x272/model_telemetry.cpp
@@ -217,14 +217,7 @@ bool menuModelTelemetry(event_t event)
break;
case ITEM_TELEMETRY_RSSI_LABEL:
-#if defined(MULTIMODULE)
- if (!IS_INTERNAL_MODULE_ON() &&
- g_model.moduleData[EXTERNAL_MODULE].type == MODULE_TYPE_MULTIMODULE &&
- (g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol() == MODULE_SUBTYPE_MULTI_FS_AFHDS2A || g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol() == MODULE_SUBTYPE_MULTI_HOTT ))
- lcdDrawText(MENUS_MARGIN_LEFT, y, "RQly");
- else
-#endif
- lcdDrawText(MENUS_MARGIN_LEFT, y, "RSSI");
+ lcdDrawText(MENUS_MARGIN_LEFT, y, getRssiLabel(), 0);
break;
case ITEM_TELEMETRY_RSSI_SOURCE: {
diff --git a/radio/src/gui/480x272/radio_calibration.cpp b/radio/src/gui/480x272/radio_calibration.cpp
index a81355b89..ab5576f44 100644
--- a/radio/src/gui/480x272/radio_calibration.cpp
+++ b/radio/src/gui/480x272/radio_calibration.cpp
@@ -57,6 +57,13 @@ void drawPots()
// The 2 main front sliders
drawVerticalSlider(125, 120, 120, calibratedAnalogs[CALIBRATED_SLIDER_FRONT_LEFT], -RESX, RESX, 40, OPTION_SLIDER_TICKS | OPTION_SLIDER_BIG_TICKS | OPTION_SLIDER_SQUARE_BUTTON);
drawVerticalSlider(LCD_W-125-12, 120, 120, calibratedAnalogs[CALIBRATED_SLIDER_FRONT_RIGHT], -RESX, RESX, 40, OPTION_SLIDER_TICKS | OPTION_SLIDER_BIG_TICKS | OPTION_SLIDER_SQUARE_BUTTON);
+#else
+ if (IS_POT_AVAILABLE(EXT1)) {
+ drawVerticalSlider(125, 120, 120, calibratedAnalogs[CALIBRATED_POT_EXT1], -RESX, RESX, 40, OPTION_SLIDER_TICKS | OPTION_SLIDER_BIG_TICKS | OPTION_SLIDER_SQUARE_BUTTON);
+ }
+ if (IS_POT_AVAILABLE(EXT2)) {
+ drawVerticalSlider(LCD_W-125-12, 120, 120, calibratedAnalogs[CALIBRATED_POT_EXT2], -RESX, RESX, 40, OPTION_SLIDER_TICKS | OPTION_SLIDER_BIG_TICKS | OPTION_SLIDER_SQUARE_BUTTON);
+ }
#endif
}
diff --git a/radio/src/gui/480x272/radio_diaganas.cpp b/radio/src/gui/480x272/radio_diaganas.cpp
index ae452f7ae..b971cdd2a 100644
--- a/radio/src/gui/480x272/radio_diaganas.cpp
+++ b/radio/src/gui/480x272/radio_diaganas.cpp
@@ -19,13 +19,13 @@
*/
#include "opentx.h"
-#if defined(RADIO_TX16S)
+#if defined(HARDWARE_TOUCH)
+#include "touch.h"
#include "tp_gt911.h"
#include
#endif
constexpr coord_t LEFT_NAME_COLUMN = MENUS_MARGIN_LEFT;
-constexpr coord_t RIGHT_NAME_COLUMN = LCD_W / 2;
constexpr coord_t ANA_OFFSET = 150;
bool menuRadioDiagAnalogs(event_t event)
@@ -71,7 +71,7 @@ bool menuRadioDiagAnalogs(event_t event)
lcdDrawText(MENUS_MARGIN_LEFT, MENU_CONTENT_TOP + 7 * FH, STR_TOUCH_PANEL);
}
- if (touchPanelEvent) {
+ if (touchPanelEventOccured()) {
touchPanelRead();
lcdDrawNumber(lcdNextPos + 1, MENU_CONTENT_TOP + 7 * FH, touchState.x);
lcdDrawText(lcdNextPos, MENU_CONTENT_TOP + 7 * FH, ", ");
diff --git a/radio/src/gui/480x272/radio_ghost_menu.cpp b/radio/src/gui/480x272/radio_ghost_menu.cpp
new file mode 100644
index 000000000..fbe6da7d1
--- /dev/null
+++ b/radio/src/gui/480x272/radio_ghost_menu.cpp
@@ -0,0 +1,121 @@
+/*
+ * 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.
+ */
+
+#include "opentx.h"
+
+bool menuGhostModuleConfig(event_t event)
+{
+ switch (event) {
+ case EVT_ENTRY:
+ memclear(&reusableBuffer.ghostMenu, sizeof(reusableBuffer.ghostMenu));
+ strAppend((char *) &reusableBuffer.ghostMenu.line[1].menuText, STR_WAITING_FOR_MODULE, 0);
+ reusableBuffer.ghostMenu.line[1].lineFlags = GHST_LINE_FLAGS_VALUE_EDIT;
+ reusableBuffer.ghostMenu.buttonAction = GHST_BTN_NONE;
+ reusableBuffer.ghostMenu.menuAction = GHST_MENU_CTRL_OPEN;
+ moduleState[EXTERNAL_MODULE].counter = GHST_MENU_CONTROL;
+ break;
+
+ case EVT_ROTARY_LEFT:
+ reusableBuffer.ghostMenu.buttonAction = GHST_BTN_JOYUP;
+ reusableBuffer.ghostMenu.menuAction = GHST_MENU_CTRL_NONE;
+ moduleState[EXTERNAL_MODULE].counter = GHST_MENU_CONTROL;
+ audioKeyPress();
+ break;
+
+ case EVT_ROTARY_RIGHT:
+ reusableBuffer.ghostMenu.buttonAction = GHST_BTN_JOYDOWN;
+ reusableBuffer.ghostMenu.menuAction = GHST_MENU_CTRL_NONE;
+ moduleState[EXTERNAL_MODULE].counter = GHST_MENU_CONTROL;
+ audioKeyPress();
+ break;
+
+ case EVT_KEY_FIRST(KEY_ENTER):
+ reusableBuffer.ghostMenu.buttonAction = GHST_BTN_JOYPRESS;
+ reusableBuffer.ghostMenu.menuAction = GHST_MENU_CTRL_NONE;
+ moduleState[EXTERNAL_MODULE].counter = GHST_MENU_CONTROL;
+ audioKeyPress();
+ break;
+
+ case EVT_KEY_BREAK(KEY_EXIT):
+ reusableBuffer.ghostMenu.buttonAction = GHST_BTN_JOYLEFT;
+ reusableBuffer.ghostMenu.menuAction = GHST_MENU_CTRL_NONE;
+ moduleState[EXTERNAL_MODULE].counter = GHST_MENU_CONTROL;
+ audioKeyPress();
+ break;
+
+ case EVT_KEY_LONG(KEY_EXIT):
+ menuVerticalOffset = 0;
+ memclear(&reusableBuffer.ghostMenu, sizeof(reusableBuffer.ghostMenu));
+ reusableBuffer.ghostMenu.buttonAction = GHST_BTN_NONE;
+ reusableBuffer.ghostMenu.menuAction = GHST_MENU_CTRL_CLOSE;
+ moduleState[EXTERNAL_MODULE].counter = GHST_MENU_CONTROL;
+ RTOS_WAIT_MS(10);
+ popMenu();
+ break;
+ }
+
+ if (reusableBuffer.ghostMenu.menuStatus == GHST_MENU_STATUS_UNOPENED) { // Handles situation where module is plugged after tools start
+ reusableBuffer.ghostMenu.buttonAction = GHST_BTN_NONE;
+ reusableBuffer.ghostMenu.menuAction = GHST_MENU_CTRL_OPEN;
+ moduleState[EXTERNAL_MODULE].counter = GHST_MENU_CONTROL;
+ }
+ else if (reusableBuffer.ghostMenu.menuStatus == GHST_MENU_STATUS_CLOSING) {
+ popMenu();
+ }
+
+ drawMenuTemplate(STR_GHOST_MENU_LABEL, ICON_OPENTX, nullptr, OPTION_MENU_NO_SCROLLBAR);
+
+ constexpr coord_t xOffset = 140;
+ constexpr coord_t xOffset2 = 260;
+ constexpr coord_t yOffset = 55;
+ constexpr coord_t lineSpacing = 25;
+ LcdFlags flags = 0;
+
+ for (uint8_t line = 0; line < GHST_MENU_LINES; line++) {
+ flags = 0;
+ if (reusableBuffer.ghostMenu.line[line].splitLine) {
+ if (reusableBuffer.ghostMenu.line[line].lineFlags & GHST_LINE_FLAGS_LABEL_SELECT)
+ flags = INVERS;
+ lcdDrawText(xOffset, yOffset + line * lineSpacing, reusableBuffer.ghostMenu.line[line].menuText, flags);
+
+ flags = 0;
+ if (reusableBuffer.ghostMenu.line[line].lineFlags & GHST_LINE_FLAGS_VALUE_SELECT)
+ flags |= INVERS;
+ if (reusableBuffer.ghostMenu.line[line].lineFlags & GHST_LINE_FLAGS_VALUE_EDIT)
+ flags |= BLINK;
+ lcdDrawText(xOffset2, yOffset + line * lineSpacing, &reusableBuffer.ghostMenu.line[line].menuText[reusableBuffer.ghostMenu.line[line].splitLine], flags);
+ }
+ else {
+ if (reusableBuffer.ghostMenu.line[line].lineFlags & GHST_LINE_FLAGS_LABEL_SELECT) {
+ lcdDrawText(xOffset, yOffset + line * lineSpacing, reusableBuffer.ghostMenu.line[line].menuText, INVERS);
+ }
+ else if (reusableBuffer.ghostMenu.line[line].lineFlags & GHST_LINE_FLAGS_VALUE_EDIT) {
+ if (BLINK_ON_PHASE) {
+ lcdDrawText(xOffset, yOffset + line * lineSpacing, reusableBuffer.ghostMenu.line[line].menuText, flags);
+ }
+ }
+ else {
+ lcdDrawText(xOffset, yOffset + line * lineSpacing, reusableBuffer.ghostMenu.line[line].menuText, flags);
+ }
+ }
+ }
+
+ return true;
+}
diff --git a/radio/src/gui/480x272/radio_hardware.cpp b/radio/src/gui/480x272/radio_hardware.cpp
index 8020bf983..8e63a79c6 100644
--- a/radio/src/gui/480x272/radio_hardware.cpp
+++ b/radio/src/gui/480x272/radio_hardware.cpp
@@ -126,7 +126,7 @@ void onHardwareAntennaSwitchConfirm(const char * result)
#define EXTERNAL_ANTENNA_ROW
#endif
-#if defined(CROSSFIRE) && SPORT_MAX_BAUDRATE < 400000
+#if (defined(CROSSFIRE) || defined(GHOST)) && (SPORT_MAX_BAUDRATE < 400000 || defined(DEBUG))
#define MAX_BAUDRATE_ROW 0
#else
#define MAX_BAUDRATE_ROW HIDDEN_ROW
@@ -325,7 +325,7 @@ bool menuRadioHardware(event_t event)
#if defined(BLUETOOTH)
case ITEM_RADIO_HARDWARE_BLUETOOTH_MODE:
lcdDrawText(MENUS_MARGIN_LEFT, y, STR_BLUETOOTH);
- g_eeGeneral.bluetoothMode = editChoice(HW_SETTINGS_COLUMN2, y, STR_BLUETOOTH_MODES, g_eeGeneral.bluetoothMode, BLUETOOTH_OFF, BLUETOOTH_TRAINER, attr, event);
+ g_eeGeneral.bluetoothMode = editChoice(HW_SETTINGS_COLUMN2, y, STR_BLUETOOTH_MODES, g_eeGeneral.bluetoothMode, BLUETOOTH_OFF, BLUETOOTH_MAX, attr, event);
break;
case ITEM_RADIO_HARDWARE_BLUETOOTH_PAIRING_CODE:
diff --git a/radio/src/gui/480x272/radio_sdmanager.cpp b/radio/src/gui/480x272/radio_sdmanager.cpp
index 708af82a2..64b123751 100644
--- a/radio/src/gui/480x272/radio_sdmanager.cpp
+++ b/radio/src/gui/480x272/radio_sdmanager.cpp
@@ -238,19 +238,29 @@ void onSdManagerMenu(const char * result)
#if defined(INTERNAL_MODULE_MULTI)
else if (result == STR_FLASH_INTERNAL_MULTI) {
getSelectionFullPath(lfn);
- multiFlashFirmware(INTERNAL_MODULE, lfn);
+ multiFlashFirmware(INTERNAL_MODULE, lfn, MULTI_TYPE_MULTIMODULE);
}
#endif
else if (result == STR_FLASH_EXTERNAL_MULTI) {
getSelectionFullPath(lfn);
- multiFlashFirmware(EXTERNAL_MODULE, lfn);
+ multiFlashFirmware(EXTERNAL_MODULE, lfn, MULTI_TYPE_MULTIMODULE);
+ }
+ else if (result == STR_FLASH_EXTERNAL_ELRS) {
+ getSelectionFullPath(lfn);
+ multiFlashFirmware(EXTERNAL_MODULE, lfn, MULTI_TYPE_ELRS);
}
#endif
#if defined(PXX2)
- else if (result == STR_FLASH_RECEIVER_OTA_BY_INTERNAL || result == STR_FLASH_RECEIVER_OTA_BY_EXTERNAL) {
+ else if (result == STR_FLASH_RECEIVER_BY_INTERNAL_MODULE_OTA || result == STR_FLASH_RECEIVER_BY_EXTERNAL_MODULE_OTA) {
memclear(&reusableBuffer.sdManager.otaUpdateInformation, sizeof(OtaUpdateInformation));
getSelectionFullPath(reusableBuffer.sdManager.otaUpdateInformation.filename);
- reusableBuffer.sdManager.otaUpdateInformation.module = result == STR_FLASH_RECEIVER_OTA_BY_INTERNAL ? INTERNAL_MODULE : EXTERNAL_MODULE;
+ reusableBuffer.sdManager.otaUpdateInformation.module = (result == STR_FLASH_RECEIVER_BY_INTERNAL_MODULE_OTA ? INTERNAL_MODULE : EXTERNAL_MODULE);
+ moduleState[reusableBuffer.sdManager.otaUpdateInformation.module].startBind(&reusableBuffer.sdManager.otaUpdateInformation, onUpdateStateChanged);
+ }
+ else if (result == STR_FLASH_FLIGHT_CONTROLLER_BY_INTERNAL_MODULE_OTA || result == STR_FLASH_FLIGHT_CONTROLLER_BY_EXTERNAL_MODULE_OTA) {
+ memclear(&reusableBuffer.sdManager.otaUpdateInformation, sizeof(OtaUpdateInformation));
+ getSelectionFullPath(reusableBuffer.sdManager.otaUpdateInformation.filename);
+ reusableBuffer.sdManager.otaUpdateInformation.module = (result == STR_FLASH_FLIGHT_CONTROLLER_BY_INTERNAL_MODULE_OTA ? INTERNAL_MODULE : EXTERNAL_MODULE);
moduleState[reusableBuffer.sdManager.otaUpdateInformation.module].startBind(&reusableBuffer.sdManager.otaUpdateInformation, onUpdateStateChanged);
}
#endif
@@ -365,24 +375,38 @@ bool menuRadioSdManager(event_t _event)
else if (!READ_ONLY() && !strcasecmp(ext, SPORT_FIRMWARE_EXT)) {
if (HAS_SPORT_UPDATE_CONNECTOR())
POPUP_MENU_ADD_ITEM(STR_FLASH_EXTERNAL_DEVICE);
+#if defined(INTERNAL_MODULE_PXX1) || defined(INTERNAL_MODULE_PXX2)
POPUP_MENU_ADD_ITEM(STR_FLASH_INTERNAL_MODULE);
+#endif
POPUP_MENU_ADD_ITEM(STR_FLASH_EXTERNAL_MODULE);
}
else if (!READ_ONLY() && !strcasecmp(ext, FRSKY_FIRMWARE_EXT)) {
FrSkyFirmwareInformation information;
if (readFrSkyFirmwareInformation(line, information) == nullptr) {
+#if defined(INTERNAL_MODULE_PXX1) || defined(INTERNAL_MODULE_PXX2)
if (information.productFamily == FIRMWARE_FAMILY_INTERNAL_MODULE)
POPUP_MENU_ADD_ITEM(STR_FLASH_INTERNAL_MODULE);
+#endif
if (information.productFamily == FIRMWARE_FAMILY_EXTERNAL_MODULE)
POPUP_MENU_ADD_ITEM(STR_FLASH_EXTERNAL_MODULE);
- if (HAS_SPORT_UPDATE_CONNECTOR() && (information.productFamily == FIRMWARE_FAMILY_RECEIVER || information.productFamily == FIRMWARE_FAMILY_SENSOR))
- POPUP_MENU_ADD_ITEM(STR_FLASH_EXTERNAL_DEVICE);
+ if (information.productFamily == FIRMWARE_FAMILY_RECEIVER || information.productFamily == FIRMWARE_FAMILY_SENSOR) {
+ if (HAS_SPORT_UPDATE_CONNECTOR()) {
+ POPUP_MENU_ADD_ITEM(STR_FLASH_EXTERNAL_DEVICE);
+ }
+ else {
+ POPUP_MENU_ADD_ITEM(STR_FLASH_EXTERNAL_MODULE);
+ }
+ }
#if defined(PXX2)
if (information.productFamily == FIRMWARE_FAMILY_RECEIVER) {
if (isReceiverOTAEnabledFromModule(INTERNAL_MODULE, information.productId))
- POPUP_MENU_ADD_ITEM(STR_FLASH_RECEIVER_OTA_BY_INTERNAL);
+ POPUP_MENU_ADD_ITEM(STR_FLASH_RECEIVER_BY_INTERNAL_MODULE_OTA);
if (isReceiverOTAEnabledFromModule(EXTERNAL_MODULE, information.productId))
- POPUP_MENU_ADD_ITEM(STR_FLASH_RECEIVER_OTA_BY_EXTERNAL);
+ POPUP_MENU_ADD_ITEM(STR_FLASH_RECEIVER_BY_EXTERNAL_MODULE_OTA);
+ }
+ if (information.productFamily == FIRMWARE_FAMILY_FLIGHT_CONTROLLER) {
+ POPUP_MENU_ADD_ITEM(STR_FLASH_FLIGHT_CONTROLLER_BY_INTERNAL_MODULE_OTA);
+ POPUP_MENU_ADD_ITEM(STR_FLASH_FLIGHT_CONTROLLER_BY_EXTERNAL_MODULE_OTA);
}
#endif
#if defined(BLUETOOTH)
@@ -417,6 +441,12 @@ bool menuRadioSdManager(event_t _event)
POPUP_MENU_ADD_ITEM(STR_FLASH_EXTERNAL_MULTI);
}
}
+
+ if (!READ_ONLY() && !strcasecmp(ext, ELRS_FIRMWARE_EXT)) {
+ TCHAR lfn[_MAX_LFN + 1];
+ getSelectionFullPath(lfn);
+ POPUP_MENU_ADD_ITEM(STR_FLASH_EXTERNAL_ELRS);
+ }
#endif
#if defined(LUA)
diff --git a/radio/src/gui/480x272/radio_tools.cpp b/radio/src/gui/480x272/radio_tools.cpp
index 21cabf522..3964337a1 100644
--- a/radio/src/gui/480x272/radio_tools.cpp
+++ b/radio/src/gui/480x272/radio_tools.cpp
@@ -132,6 +132,11 @@ bool menuRadioTools(event_t event)
addRadioModuleTool(index++, STR_POWER_METER_EXT, menuRadioPowerMeter, EXTERNAL_MODULE);
#endif
+#if defined(GHOST)
+ if (isModuleGhost(EXTERNAL_MODULE))
+ addRadioModuleTool(index++, "Ghost Menu", menuGhostModuleConfig, EXTERNAL_MODULE);
+#endif
+
if (index == 0) {
lcdDrawCenteredText(LCD_H/2, STR_NO_TOOLS);
}
diff --git a/radio/src/gui/480x272/radio_version.cpp b/radio/src/gui/480x272/radio_version.cpp
index 63301619a..6f8260056 100644
--- a/radio/src/gui/480x272/radio_version.cpp
+++ b/radio/src/gui/480x272/radio_version.cpp
@@ -92,6 +92,17 @@ bool menuRadioModulesVersion(event_t event)
y += FH;
continue;
}
+#if defined(HARDWARE_EXTERNAL_ACCESS_MOD)
+ if (isModuleMultimodule(INTERNAL_MODULE)) {
+ char statusText[64];
+ lcdDrawText(COLUMN2_X, y, "Multimodule");
+ y += FH;
+ getMultiModuleStatus(INTERNAL_MODULE).getStatusString(statusText);
+ lcdDrawText(COLUMN2_X, y, statusText);
+ y += FH;
+ continue;
+ }
+#endif
if (!isModulePXX2(INTERNAL_MODULE)) {
lcdDrawText(COLUMN2_X, y, STR_NO_INFORMATION);
y += FH;
diff --git a/radio/src/gui/480x272/screens_setup.cpp b/radio/src/gui/480x272/screens_setup.cpp
index e73afed68..8738d564a 100644
--- a/radio/src/gui/480x272/screens_setup.cpp
+++ b/radio/src/gui/480x272/screens_setup.cpp
@@ -614,6 +614,7 @@ bool menuScreenSetup(int index, event_t event)
ZoneOptionValue * value = currentScreen->getOptionValue(o);
if (editZoneOption(y, option, value, attr, EE_MODEL, event)) {
currentScreen->update();
+ loadCustomScreens();
}
}
else if (menuPageCount > 3 && o == optionsCount) {
diff --git a/radio/src/gui/480x272/theme.cpp b/radio/src/gui/480x272/theme.cpp
index 27756859a..39c8fe4d9 100644
--- a/radio/src/gui/480x272/theme.cpp
+++ b/radio/src/gui/480x272/theme.cpp
@@ -19,6 +19,9 @@
*/
#include "opentx.h"
+#include "storage/modelslist.h"
+
+extern ModelsList modelslist;
const BitmapBuffer * Theme::asterisk = NULL;
const BitmapBuffer * Theme::question = NULL;
@@ -138,6 +141,7 @@ Theme * getTheme(const char * name)
void loadTheme(Theme * new_theme)
{
TRACE("load theme %s", new_theme->getName());
+ modelslist.clear();
theme = new_theme;
theme->load();
}
diff --git a/radio/src/gui/480x272/themes/flexi.cpp b/radio/src/gui/480x272/themes/flexi.cpp
new file mode 100644
index 000000000..55de41628
--- /dev/null
+++ b/radio/src/gui/480x272/themes/flexi.cpp
@@ -0,0 +1,363 @@
+/*
+ * 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.
+ */
+
+#include "opentx.h"
+#include "storage/modelslist.h"
+
+const ZoneOption OPTIONS_THEME_FLEXI[] = {
+ { STR_BACKGROUND_COLOR, ZoneOption::Color, OPTION_VALUE_UNSIGNED(LIGHTWHITE) },
+ { STR_MAIN_COLOR, ZoneOption::Color, OPTION_VALUE_UNSIGNED(LIGHTBROWN) },
+ { STR_TEXT_COLOR, ZoneOption::Color, OPTION_VALUE_UNSIGNED(BLACK) },
+ { STR_BAR1_COLOR, ZoneOption::Color, OPTION_VALUE_UNSIGNED(ORANGE) },
+ { STR_BAR2_COLOR, ZoneOption::Color, OPTION_VALUE_UNSIGNED(BRIGHTGREEN) },
+ { NULL, ZoneOption::Bool }
+};
+
+class FlexiTheme: public Theme
+{
+ public:
+ FlexiTheme():
+ Theme("Flexi", OPTIONS_THEME_FLEXI)
+ {
+ }
+
+ void loadColors() const
+ {
+ lcdColorTable[TEXT_COLOR_INDEX] = BLACK;
+ lcdColorTable[TEXT_BGCOLOR_INDEX] = LIGHTWHITE;
+ lcdColorTable[TEXT_INVERTED_COLOR_INDEX] = LIGHTWHITE;
+ lcdColorTable[TEXT_INVERTED_BGCOLOR_INDEX] = DARKBROWN;
+ lcdColorTable[TEXT_STATUSBAR_COLOR_INDEX] = LIGHTWHITE;
+ lcdColorTable[LINE_COLOR_INDEX] = GREY;
+ lcdColorTable[SCROLLBOX_COLOR_INDEX] = DARKBROWN;
+ lcdColorTable[MENU_TITLE_BGCOLOR_INDEX] = LIGHTWHITE;
+ lcdColorTable[MENU_TITLE_COLOR_INDEX] = LIGHTWHITE;
+ lcdColorTable[MENU_TITLE_DISABLE_COLOR_INDEX] = LIGHTWHITE;
+ lcdColorTable[HEADER_COLOR_INDEX] = LIGHTGREY;
+ lcdColorTable[ALARM_COLOR_INDEX] = RED;
+ lcdColorTable[WARNING_COLOR_INDEX] = YELLOW;
+ lcdColorTable[TEXT_DISABLE_COLOR_INDEX] = GREY;
+ lcdColorTable[CURVE_AXIS_COLOR_INDEX] = LIGHTGREY;
+ lcdColorTable[CURVE_COLOR_INDEX] = RED;
+ lcdColorTable[CURVE_CURSOR_COLOR_INDEX] = DARKBROWN;
+ lcdColorTable[TITLE_BGCOLOR_INDEX] = DARKBROWN;
+ lcdColorTable[TRIM_BGCOLOR_INDEX] = LIGHTBROWN;
+ lcdColorTable[TRIM_SHADOW_COLOR_INDEX] = BLACK;
+ lcdColorTable[MAINVIEW_PANES_COLOR_INDEX] = LIGHTWHITE;
+ lcdColorTable[MAINVIEW_GRAPHICS_COLOR_INDEX] = DARKBROWN;
+ lcdColorTable[HEADER_BGCOLOR_INDEX] = DARKBROWN; // Top bar color
+ lcdColorTable[HEADER_ICON_BGCOLOR_INDEX] = LIGHTBROWN; // background OPENTX icon
+ lcdColorTable[HEADER_CURRENT_BGCOLOR_INDEX] = GREEN; // icons color
+ lcdColorTable[OVERLAY_COLOR_INDEX] = LIGHTWHITE;
+ lcdColorTable[BARGRAPH1_COLOR_INDEX] = ORANGE;
+ lcdColorTable[BARGRAPH2_COLOR_INDEX] = BRIGHTGREEN;
+ lcdColorTable[BARGRAPH_BGCOLOR_INDEX] = RGB(220, 220, 220);
+ }
+
+ void loadMenuIcon(uint8_t index, const char * filename) const
+ {
+ BitmapBuffer * mask = BitmapBuffer::loadMask(getThemePath(filename));
+ if (mask) {
+ menuIconNormal[index] = new BitmapBuffer(BMP_RGB565, mask->getWidth(), mask->getHeight());
+ if (menuIconNormal[index]) {
+ menuIconNormal[index]->clear(HEADER_BGCOLOR);
+ menuIconNormal[index]->drawMask(0, 0, mask, HEADER_CURRENT_BGCOLOR);
+ }
+ menuIconSelected[index] = new BitmapBuffer(BMP_RGB565, mask->getWidth(), mask->getHeight());
+ if (menuIconSelected[index]) {
+ menuIconSelected[index]->clear(HEADER_BGCOLOR);
+ menuIconSelected[index]->drawMask(0, 0, mask, MENU_TITLE_COLOR);
+ }
+ menuIconTitle[index] = new BitmapBuffer(BMP_RGB565, mask->getWidth(), mask->getHeight());
+ if (menuIconTitle[index]) {
+ menuIconTitle[index]->clear(HEADER_ICON_BGCOLOR);
+ menuIconTitle[index]->drawMask(0, 0, mask, MENU_TITLE_COLOR);
+ }
+ }
+ }
+
+ void loadMenusIcons() const
+ {
+ if (isAsteriskDisplayed())
+ loadMenuIcon(ICON_OPENTX, "mask_opentx_testmode.png");
+ else
+ loadMenuIcon(ICON_OPENTX, "mask_opentx.png");
+ loadMenuIcon(ICON_RADIO, "mask_menu_radio.png");
+ loadMenuIcon(ICON_RADIO_SETUP, "mask_radio_setup.png");
+ loadMenuIcon(ICON_RADIO_SD_MANAGER, "mask_radio_sd_browser.png");
+ loadMenuIcon(ICON_RADIO_TOOLS, "mask_radio_tools.png");
+ loadMenuIcon(ICON_RADIO_SPECTRUM_ANALYSER, "/mask_radio_spectrum_analyser.png");
+ loadMenuIcon(ICON_RADIO_GLOBAL_FUNCTIONS, "mask_radio_global_functions.png");
+ loadMenuIcon(ICON_RADIO_TRAINER, "mask_radio_trainer.png");
+ loadMenuIcon(ICON_RADIO_HARDWARE, "mask_radio_hardware.png");
+ loadMenuIcon(ICON_RADIO_VERSION, "mask_radio_version.png");
+ loadMenuIcon(ICON_MODEL, "mask_menu_model.png");
+ loadMenuIcon(ICON_MODEL_SETUP, "mask_model_setup.png");
+ loadMenuIcon(ICON_MODEL_HELI, "mask_model_heli.png");
+ loadMenuIcon(ICON_MODEL_FLIGHT_MODES, "mask_model_flight_modes.png");
+ loadMenuIcon(ICON_MODEL_INPUTS, "mask_model_inputs.png");
+ loadMenuIcon(ICON_MODEL_MIXER, "mask_model_mixer.png");
+ loadMenuIcon(ICON_MODEL_OUTPUTS, "mask_model_outputs.png");
+ loadMenuIcon(ICON_MODEL_CURVES, "mask_model_curves.png");
+ loadMenuIcon(ICON_MODEL_GVARS, "mask_model_gvars.png");
+ loadMenuIcon(ICON_MODEL_LOGICAL_SWITCHES, "mask_model_logical_switches.png");
+ loadMenuIcon(ICON_MODEL_SPECIAL_FUNCTIONS, "mask_model_special_functions.png");
+ loadMenuIcon(ICON_MODEL_LUA_SCRIPTS, "mask_model_lua_scripts.png");
+ loadMenuIcon(ICON_MODEL_TELEMETRY, "mask_model_telemetry.png");
+ loadMenuIcon(ICON_STATS, "mask_menu_stats.png");
+ loadMenuIcon(ICON_STATS_THROTTLE_GRAPH, "mask_stats_throttle_graph.png");
+ loadMenuIcon(ICON_STATS_TIMERS, "mask_stats_timers.png");
+ loadMenuIcon(ICON_STATS_ANALOGS, "mask_stats_analogs.png");
+ loadMenuIcon(ICON_STATS_DEBUG, "mask_stats_debug.png");
+ loadMenuIcon(ICON_THEME, "mask_menu_theme.png");
+ loadMenuIcon(ICON_THEME_SETUP, "mask_theme_setup.png");
+ loadMenuIcon(ICON_THEME_VIEW1, "mask_theme_view1.png");
+ loadMenuIcon(ICON_THEME_VIEW2, "mask_theme_view2.png");
+ loadMenuIcon(ICON_THEME_VIEW3, "mask_theme_view3.png");
+ loadMenuIcon(ICON_THEME_VIEW4, "mask_theme_view4.png");
+ loadMenuIcon(ICON_THEME_VIEW5, "mask_theme_view5.png");
+ loadMenuIcon(ICON_THEME_ADD_VIEW, "mask_theme_add_view.png");
+ loadMenuIcon(ICON_MONITOR, "mask_monitor.png");
+ loadMenuIcon(ICON_MONITOR_CHANNELS1, "mask_monitor_channels1.png");
+ loadMenuIcon(ICON_MONITOR_CHANNELS2, "mask_monitor_channels2.png");
+ loadMenuIcon(ICON_MONITOR_CHANNELS3, "mask_monitor_channels3.png");
+ loadMenuIcon(ICON_MONITOR_CHANNELS4, "mask_monitor_channels4.png");
+ loadMenuIcon(ICON_MONITOR_LOGICAL_SWITCHES, "/mask_monitor_logsw.png");
+ }
+
+ void loadThemeBitmaps() const
+ {
+ // Calibration screen
+ delete calibStick;
+ calibStick = BitmapBuffer::load(getThemePath("stick_pointer.png"));
+
+ delete calibStickBackground;
+ calibStickBackground = BitmapBuffer::load(getThemePath("stick_background.png"));
+
+ delete calibTrackpBackground;
+ calibTrackpBackground = BitmapBuffer::load(getThemePath("trackp_background.png"));
+
+ delete calibHorus;
+#if defined(RADIO_T16)
+ calibHorus = BitmapBuffer::load(getThemePath("t16.bmp"));
+#elif defined(RADIO_T18)
+ calibHorus = BitmapBuffer::load(getThemePath("t18.bmp"));
+#elif defined(RADIO_TX16S)
+ calibHorus = BitmapBuffer::load(getThemePath("tx16s.bmp"));
+#elif defined(PCBX10)
+ if(STICKS_PWM_ENABLED()) {
+ calibHorus = BitmapBuffer::load(getThemePath("X10S.bmp"));
+ }
+ else {
+ calibHorus = BitmapBuffer::load(getThemePath("X10.bmp"));
+ }
+#else
+ calibHorus = BitmapBuffer::load(getThemePath("horus.bmp"));
+#endif
+
+ // Channels monitor screen
+ delete chanMonLockedBitmap;
+ chanMonLockedBitmap = BitmapBuffer::loadMaskOnBackground("mask_monitor_lockch.png", TEXT_COLOR, TEXT_BGCOLOR);
+
+ delete chanMonInvertedBitmap;
+ chanMonInvertedBitmap = BitmapBuffer::loadMaskOnBackground("mask_monitor_inver.png", TEXT_COLOR, TEXT_BGCOLOR);
+
+ // Model Selection screen
+ delete modelselIconBitmap;
+ modelselIconBitmap = BitmapBuffer::loadMaskOnBackground("modelsel/mask_iconback.png", TITLE_BGCOLOR, TEXT_BGCOLOR);
+ if (modelselIconBitmap) {
+ BitmapBuffer * bitmap = BitmapBuffer::load(getThemePath("modelsel/icon_default.png"));
+ modelselIconBitmap->drawBitmap(20, 8, bitmap);
+ delete bitmap;
+ }
+
+ delete modelselSdFreeBitmap;
+ modelselSdFreeBitmap = BitmapBuffer::loadMaskOnBackground("modelsel/mask_sdfree.png", TEXT_COLOR, TEXT_BGCOLOR);
+
+ delete modelselModelQtyBitmap;
+ modelselModelQtyBitmap = BitmapBuffer::loadMaskOnBackground("modelsel/mask_modelqty.png", TEXT_COLOR, TEXT_BGCOLOR);
+
+ delete modelselModelNameBitmap;
+ modelselModelNameBitmap = BitmapBuffer::loadMaskOnBackground("modelsel/mask_modelname.png", TEXT_COLOR, TEXT_BGCOLOR);
+
+ delete modelselModelMoveBackground;
+ modelselModelMoveBackground = BitmapBuffer::loadMask(getThemePath("modelsel/mask_moveback.png"));
+
+ delete modelselModelMoveIcon;
+ modelselModelMoveIcon = BitmapBuffer::loadMask(getThemePath("modelsel/mask_moveico.png"));
+
+ delete modelselWizardBackground;
+ modelselWizardBackground = BitmapBuffer::load(getThemePath("wizard/background.png"));
+
+
+ // Mixer setup screen
+ delete mixerSetupMixerBitmap;
+ mixerSetupMixerBitmap = BitmapBuffer::loadMaskOnBackground("mask_sbar_mixer.png", MENU_TITLE_COLOR, HEADER_BGCOLOR);
+
+ delete mixerSetupToBitmap;
+ mixerSetupToBitmap = BitmapBuffer::loadMaskOnBackground("mask_sbar_to.png", TEXT_BGCOLOR, HEADER_BGCOLOR);
+
+ delete mixerSetupOutputBitmap;
+ mixerSetupOutputBitmap = BitmapBuffer::loadMaskOnBackground("mask_sbar_output.png", MENU_TITLE_COLOR, HEADER_BGCOLOR);
+
+ delete mixerSetupAddBitmap;
+ mixerSetupAddBitmap = BitmapBuffer::loadMaskOnBackground("mask_mplex_add.png", TEXT_COLOR, TEXT_BGCOLOR);
+
+ delete mixerSetupMultiBitmap;
+ mixerSetupMultiBitmap = BitmapBuffer::loadMaskOnBackground("mask_mplex_multi.png", TEXT_COLOR, TEXT_BGCOLOR);
+
+ delete mixerSetupReplaceBitmap;
+ mixerSetupReplaceBitmap = BitmapBuffer::loadMaskOnBackground("mask_mplex_replace.png", TEXT_COLOR, TEXT_BGCOLOR);
+
+ delete mixerSetupLabelBitmap;
+ mixerSetupLabelBitmap = BitmapBuffer::loadMaskOnBackground("mask_textline_label.png", TEXT_COLOR, TEXT_BGCOLOR);
+
+ delete mixerSetupCurveBitmap;
+ mixerSetupCurveBitmap = BitmapBuffer::loadMaskOnBackground("mask_textline_curve.png", TEXT_COLOR, TEXT_BGCOLOR);
+
+ delete mixerSetupSwitchBitmap;
+ mixerSetupSwitchBitmap = BitmapBuffer::loadMaskOnBackground("mask_textline_switch.png", TEXT_COLOR, TEXT_BGCOLOR);
+
+ delete mixerSetupSlowBitmap;
+ mixerSetupSlowBitmap = BitmapBuffer::loadMaskOnBackground("mask_textline_slow.png", TEXT_COLOR, TEXT_BGCOLOR);
+
+ delete mixerSetupDelayBitmap;
+ mixerSetupDelayBitmap = BitmapBuffer::loadMaskOnBackground("mask_textline_delay.png", TEXT_COLOR, TEXT_BGCOLOR);
+
+ delete mixerSetupDelaySlowBitmap;
+ mixerSetupDelaySlowBitmap = BitmapBuffer::loadMaskOnBackground("mask_textline_delayslow.png", TEXT_COLOR, TEXT_BGCOLOR);
+
+ delete mixerSetupFlightmodeBitmap;
+ mixerSetupFlightmodeBitmap = BitmapBuffer::loadMaskOnBackground("mask_textline_fm.png", TEXT_COLOR, TEXT_BGCOLOR);
+
+ delete topleftBitmap;
+ topleftBitmap = BitmapBuffer::loadMaskOnBackground("topleft.png", HEADER_ICON_BGCOLOR, TITLE_BGCOLOR);
+ }
+
+ virtual void load() const
+ {
+ Theme::load();
+ loadColors();
+ loadMenusIcons();
+ loadThemeBitmaps();
+ if (!backgroundBitmap) {
+ backgroundBitmap = BitmapBuffer::load(getThemePath("background.png"));
+ }
+ update();
+ }
+
+ virtual void update() const
+ {
+#define DARKER(x) ((x * 70) / 100)
+
+ uint32_t color = g_eeGeneral.themeData.options[1].unsignedValue;
+ uint32_t bgColor = globalData.unexpectedShutdown ? WHITE : g_eeGeneral.themeData.options[0].unsignedValue;
+ uint32_t textcolor = g_eeGeneral.themeData.options[2].unsignedValue;
+ uint32_t barcolor = g_eeGeneral.themeData.options[3].unsignedValue;
+ uint32_t bar2color = g_eeGeneral.themeData.options[4].unsignedValue;
+
+ lcdColorTable[TEXT_COLOR_INDEX] = textcolor;
+ lcdColorTable[TEXT_BGCOLOR_INDEX] = bgColor;
+ lcdColorTable[TEXT_INVERTED_COLOR_INDEX] = bgColor;
+ lcdColorTable[TEXT_INVERTED_BGCOLOR_INDEX] = color;
+ lcdColorTable[TEXT_STATUSBAR_COLOR_INDEX] = bgColor;
+ lcdColorTable[LINE_COLOR_INDEX] = GREY;
+ lcdColorTable[SCROLLBOX_COLOR_INDEX] = color;
+ lcdColorTable[MENU_TITLE_BGCOLOR_INDEX] = bgColor;
+ lcdColorTable[MENU_TITLE_COLOR_INDEX] = bgColor;
+ lcdColorTable[MENU_TITLE_DISABLE_COLOR_INDEX] = RGB(DARKER(GET_RED(bgColor)), DARKER(GET_GREEN(bgColor)), DARKER(GET_BLUE(bgColor)));
+ lcdColorTable[HEADER_COLOR_INDEX] = LIGHTGREY;
+ lcdColorTable[ALARM_COLOR_INDEX] = RED;
+ lcdColorTable[WARNING_COLOR_INDEX] = YELLOW;
+ lcdColorTable[TEXT_DISABLE_COLOR_INDEX] = GREY;
+ lcdColorTable[CURVE_AXIS_COLOR_INDEX] = LIGHTGREY;
+ lcdColorTable[CURVE_COLOR_INDEX] = RED;
+ lcdColorTable[CURVE_CURSOR_COLOR_INDEX] = color;
+ lcdColorTable[TITLE_BGCOLOR_INDEX] = color;
+ lcdColorTable[TRIM_BGCOLOR_INDEX] = color;
+ lcdColorTable[TRIM_SHADOW_COLOR_INDEX] = textcolor;
+ lcdColorTable[MAINVIEW_PANES_COLOR_INDEX] = bgColor;
+ lcdColorTable[MAINVIEW_GRAPHICS_COLOR_INDEX] = color;
+ lcdColorTable[HEADER_BGCOLOR_INDEX] = color; // Top bar color
+ lcdColorTable[HEADER_ICON_BGCOLOR_INDEX] = color; // background OPENTX icon
+ lcdColorTable[HEADER_CURRENT_BGCOLOR_INDEX] = RGB(DARKER(GET_RED(color)), DARKER(GET_GREEN(color)), DARKER(GET_BLUE(color))); // icons color
+ lcdColorTable[OVERLAY_COLOR_INDEX] = bgColor;
+ lcdColorTable[BARGRAPH1_COLOR_INDEX] = barcolor;
+ lcdColorTable[BARGRAPH2_COLOR_INDEX] = bar2color;
+ lcdColorTable[BARGRAPH_BGCOLOR_INDEX] = RGB(DARKER(GET_RED(bgColor)), DARKER(GET_GREEN(bgColor)), DARKER(GET_BLUE(bgColor)));
+
+ loadMenusIcons();
+ loadThemeBitmaps();
+ loadFontCache();
+ }
+
+ virtual void drawBackground() const
+ {
+ if (backgroundBitmap) {
+ lcd->drawBitmap(0, 0, backgroundBitmap);
+ }
+ else {
+ lcdSetColor(g_eeGeneral.themeData.options[0].unsignedValue);
+ lcdDrawSolidFilledRect(0, 0, LCD_W, LCD_H, CUSTOM_COLOR);
+ }
+ }
+ void drawTopbarBackground(uint8_t icon) const
+ {
+ if (topleftBitmap) {
+ lcd->drawBitmap(0, 0, topleftBitmap);
+ uint16_t width = topleftBitmap->getWidth();
+ lcd->drawSolidFilledRect(width, 0, LCD_W-width, MENU_HEADER_HEIGHT, HEADER_BGCOLOR);
+ }
+ else {
+ lcd->drawSolidFilledRect(0, 0, LCD_W, MENU_HEADER_HEIGHT, HEADER_BGCOLOR);
+ }
+
+
+ if (icon == ICON_OPENTX)
+ lcd->drawBitmap(4, 10, menuIconTitle[ICON_OPENTX]);
+ else
+ lcd->drawBitmap(5, 7, menuIconTitle[icon]);
+
+ drawTopbarDatetime();
+ }
+
+ virtual void drawMenuIcon(uint8_t index, uint8_t position, bool selected) const
+ {
+ lcd->drawBitmap(50+position*MENU_ICONS_SPACING, 7, selected ? menuIconSelected[index] : menuIconNormal[index]);
+ }
+
+ protected:
+ static const BitmapBuffer * backgroundBitmap;
+ static BitmapBuffer * topleftBitmap;
+ static BitmapBuffer * menuIconNormal[MENUS_ICONS_COUNT];
+ static BitmapBuffer * menuIconSelected[MENUS_ICONS_COUNT];
+ static BitmapBuffer * menuIconTitle[MENUS_ICONS_COUNT];
+};
+
+const BitmapBuffer * FlexiTheme::backgroundBitmap = NULL;
+BitmapBuffer * FlexiTheme::topleftBitmap = NULL;
+BitmapBuffer * FlexiTheme::menuIconNormal[MENUS_ICONS_COUNT] = { NULL };
+BitmapBuffer * FlexiTheme::menuIconSelected[MENUS_ICONS_COUNT] = { NULL };
+BitmapBuffer * FlexiTheme::menuIconTitle[MENUS_ICONS_COUNT] = { NULL };
+
+FlexiTheme FlexiTheme;
+#if defined(DEFAULT_THEME_FLEXI)
+ Theme * theme = &FlexiTheme;
+#endif
\ No newline at end of file
diff --git a/radio/src/gui/480x272/topbar.cpp b/radio/src/gui/480x272/topbar.cpp
index f78174aa8..e8027d047 100644
--- a/radio/src/gui/480x272/topbar.cpp
+++ b/radio/src/gui/480x272/topbar.cpp
@@ -61,6 +61,11 @@ void drawTopBar()
lcdDrawBitmapPattern(LCD_W-98, 8, LBM_TOPMENU_USB, MENU_TITLE_COLOR);
}
+ // Logs
+ if (isFunctionActive(FUNCTION_LOGS) && !usbPlugged() && BLINK_ON_PHASE) {
+ lcdDrawBitmapPattern(LCD_W-98, 6, LBM_DOT, MENU_TITLE_COLOR);
+ }
+
// RSSI
const uint8_t rssiBarsValue[] = {30, 40, 50, 60, 80};
const uint8_t rssiBarsHeight[] = {5, 10, 15, 21, 31};
diff --git a/radio/src/gui/480x272/view_about.cpp b/radio/src/gui/480x272/view_about.cpp
index 3f5e14660..ea3561188 100644
--- a/radio/src/gui/480x272/view_about.cpp
+++ b/radio/src/gui/480x272/view_about.cpp
@@ -128,7 +128,7 @@ bool menuAboutView(event_t event)
break;
case ABOUT_HARDWARE:
- lcdDrawText(ABOUT_X, MENU_CONTENT_TOP, "FrSky", INVERS);
+ lcdDrawText(ABOUT_X, MENU_CONTENT_TOP, STR_ABOUT_HARDWARE_1, INVERS);
lcdDrawText(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + FH, STR_ABOUT_HARDWARE_2);
lcdDrawText(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + 2*FH, STR_ABOUT_HARDWARE_3);
break;
diff --git a/radio/src/gui/480x272/view_main.cpp b/radio/src/gui/480x272/view_main.cpp
index cbc38b69b..91482e843 100644
--- a/radio/src/gui/480x272/view_main.cpp
+++ b/radio/src/gui/480x272/view_main.cpp
@@ -22,7 +22,7 @@
#define TRIM_LH_X 10
#define TRIM_LV_X 24
-#define TRIM_RV_X (LCD_W-35)
+#define TRIM_RV_X (LCD_W-36)
#define TRIM_RH_X (LCD_W-175)
#define TRIM_V_Y 55
#define TRIM_H_Y (LCD_H-37)
@@ -47,10 +47,10 @@ void drawMainPots()
drawVerticalSlider(LCD_W-18, TRIM_V_Y, 160, calibratedAnalogs[CALIBRATED_SLIDER_REAR_RIGHT], -RESX, RESX, 40, OPTION_SLIDER_TICKS | OPTION_SLIDER_BIG_TICKS | OPTION_SLIDER_SQUARE_BUTTON);
}
-void drawTrims(uint8_t flightMode)
+void drawTrims(uint8_t flightMode, bool sliderdisplayed)
{
for (uint8_t i=0; i<4; i++) {
- static const coord_t x[4] = { TRIM_LH_X, TRIM_LV_X, TRIM_RV_X, TRIM_RH_X };
+ coord_t x[4] = { TRIM_LH_X, sliderdisplayed ? TRIM_LV_X : 4, sliderdisplayed ? TRIM_RV_X : TRIM_RV_X + 18, TRIM_RH_X };
static uint8_t vert[4] = {0, 1, 1, 0};
unsigned int stickIndex = CONVERT_MODE(i);
coord_t xm = x[stickIndex];
@@ -76,15 +76,15 @@ void drawTrims(uint8_t flightMode)
}
else {
if (g_model.extendedTrims == 1) {
- drawHorizontalSlider(xm, TRIM_H_Y, 160, trim, TRIM_EXTENDED_MIN, TRIM_EXTENDED_MAX, 0, OPTION_SLIDER_EMPTY_BAR|OPTION_SLIDER_TRIM_BUTTON);
+ drawHorizontalSlider(xm, sliderdisplayed ? TRIM_H_Y : TRIM_H_Y + 22, 160, trim, TRIM_EXTENDED_MIN, TRIM_EXTENDED_MAX, 0, OPTION_SLIDER_EMPTY_BAR|OPTION_SLIDER_TRIM_BUTTON);
}
else {
- drawHorizontalSlider(xm, TRIM_H_Y, 160, trim, TRIM_MIN, TRIM_MAX, 0, OPTION_SLIDER_EMPTY_BAR|OPTION_SLIDER_TRIM_BUTTON);
+ drawHorizontalSlider(xm, sliderdisplayed ? TRIM_H_Y : TRIM_H_Y + 20, 160, trim, TRIM_MIN, TRIM_MAX, 0, OPTION_SLIDER_EMPTY_BAR|OPTION_SLIDER_TRIM_BUTTON);
}
if (g_model.displayTrims != DISPLAY_TRIMS_NEVER && trim != 0) {
if (g_model.displayTrims == DISPLAY_TRIMS_ALWAYS || (trimsDisplayTimer > 0 && (trimsDisplayMask & (1<0 ? -TRIM_LEN/2 : TRIM_LEN/2);
- lcdDrawNumber(x, TRIM_H_Y+2, trim, TINSIZE | CENTERED);
+ lcdDrawNumber(x, sliderdisplayed ? TRIM_H_Y + 2 : TRIM_H_Y + 22, trim, TINSIZE | CENTERED);
}
}
}
diff --git a/radio/src/gui/480x272/widgets/gauge.cpp b/radio/src/gui/480x272/widgets/gauge.cpp
index 2558f8319..23957fd20 100644
--- a/radio/src/gui/480x272/widgets/gauge.cpp
+++ b/radio/src/gui/480x272/widgets/gauge.cpp
@@ -49,14 +49,16 @@ void GaugeWidget::refresh()
uint16_t color = persistentData->options[3].unsignedValue;
int32_t value = getValue(index);
- int32_t value_in_range = value;
- if (value < min)
- value_in_range = min;
- else if (value > max)
- value_in_range = max;
- int w = divRoundClosest(zone.w * (value_in_range - min), (max - min));
- int percent = divRoundClosest(100 * (value_in_range - min), (max - min));
+ if (min > max) {
+ SWAP(min, max);
+ value = value - min - max;
+ }
+
+ value = limit(min, value, max);
+
+ int w = divRoundClosest(zone.w * (value - min), (max - min));
+ int percent = divRoundClosest(100 * (value - min), (max - min));
// Gauge label
drawSource(zone.x, zone.y, index, SMLSIZE | TEXT_INVERTED_COLOR);
diff --git a/radio/src/gui/480x272/widgets/modelbmp.cpp b/radio/src/gui/480x272/widgets/modelbmp.cpp
index 09e632ab3..b9d00f3f2 100644
--- a/radio/src/gui/480x272/widgets/modelbmp.cpp
+++ b/radio/src/gui/480x272/widgets/modelbmp.cpp
@@ -30,7 +30,7 @@ class ModelBitmapWidget: public Widget
{
}
- virtual ~ModelBitmapWidget()
+ ~ModelBitmapWidget() override
{
delete buffer;
}
diff --git a/radio/src/gui/480x272/widgets/outputs.cpp b/radio/src/gui/480x272/widgets/outputs.cpp
index 467657519..387f4f24b 100644
--- a/radio/src/gui/480x272/widgets/outputs.cpp
+++ b/radio/src/gui/480x272/widgets/outputs.cpp
@@ -89,7 +89,7 @@ const ZoneOption OutputsWidget::options[] = {
{ STR_FIRST_CHANNEL, ZoneOption::Integer, OPTION_VALUE_UNSIGNED(1), OPTION_VALUE_UNSIGNED(1), OPTION_VALUE_UNSIGNED(32) },
{ STR_FILL_BACKGROUND, ZoneOption::Bool, OPTION_VALUE_BOOL(false) },
{ STR_BG_COLOR, ZoneOption::Color, OPTION_VALUE_UNSIGNED(LIGHTGREY) },
- { NULL, ZoneOption::Bool }
+ { nullptr, ZoneOption::Bool }
};
diff --git a/radio/src/gui/480x272/widgets/value.cpp b/radio/src/gui/480x272/widgets/value.cpp
index c7fe6ce99..9f14f17e4 100644
--- a/radio/src/gui/480x272/widgets/value.cpp
+++ b/radio/src/gui/480x272/widgets/value.cpp
@@ -97,7 +97,7 @@ void ValueWidget::refresh()
if (field >= MIXSRC_FIRST_TIMER && field <= MIXSRC_LAST_TIMER) {
TimerState & timerState = timersStates[field-MIXSRC_FIRST_TIMER];
if (timerState.val < 0) {
- lcdSetColor(ALARM_COLOR_INDEX);
+ lcdSetColor(lcdColorTable[ALARM_COLOR_INDEX]);
}
drawSource(x+NUMBERS_PADDING, y+2, field, CUSTOM_COLOR);
drawSource(x+NUMBERS_PADDING + 1, y + 3, field, BLACK);
@@ -108,7 +108,7 @@ void ValueWidget::refresh()
if (field >= MIXSRC_FIRST_TELEM) {
TelemetryItem & telemetryItem = telemetryItems[(field-MIXSRC_FIRST_TELEM)/3]; // TODO macro to convert a source to a telemetry index
if (!telemetryItem.isAvailable() || telemetryItem.isOld()) {
- lcdSetColor(ALARM_COLOR_INDEX);
+ lcdSetColor(lcdColorTable[TEXT_DISABLE_COLOR_INDEX]);
}
}
diff --git a/radio/src/gui/480x272/widgets_container.h b/radio/src/gui/480x272/widgets_container.h
index c2fbd9cdd..21fa69bc4 100644
--- a/radio/src/gui/480x272/widgets_container.h
+++ b/radio/src/gui/480x272/widgets_container.h
@@ -80,7 +80,7 @@ class WidgetsContainer: public WidgetsContainerInterface
}
}
- virtual void createWidget(unsigned int index, const WidgetFactory * factory)
+ void createWidget(unsigned int index, const WidgetFactory * factory) override
{
if (widgets) {
memset(persistentData->zones[index].widgetName, 0, sizeof(persistentData->zones[index].widgetName));
@@ -123,9 +123,9 @@ class WidgetsContainer: public WidgetsContainerInterface
return &persistentData->options[index];
}
- virtual unsigned int getZonesCount() const = 0;
+ unsigned int getZonesCount() const override = 0;
- virtual Zone getZone(unsigned int index) const = 0;
+ Zone getZone(unsigned int index) const override = 0;
virtual void refresh()
{
diff --git a/radio/src/gui/common/colorlcd/draw_functions.cpp b/radio/src/gui/common/colorlcd/draw_functions.cpp
index 3fe07f0e6..15aef8e72 100644
--- a/radio/src/gui/common/colorlcd/draw_functions.cpp
+++ b/radio/src/gui/common/colorlcd/draw_functions.cpp
@@ -251,6 +251,10 @@ void drawSensorCustomValue(coord_t x, coord_t y, uint8_t sensor, int32_t value,
"Rx2 Lost",
"Rx1 NS",
"Rx2 NS",
+ "Rx3 FS",
+ "Rx3 LF",
+ "Rx3 Lost",
+ "Rx3 NS"
};
for (uint8_t i=0; imaxSubtype && pdef->subTypeString != nullptr) {
+ MultiModuleStatus & status = getMultiModuleStatus(moduleIdx);
+ const mm_protocol_definition * pdef = getMultiProtocolDefinition(g_model.moduleData[moduleIdx].getMultiProtocol());
+
+ if (status.protocolName[0] && status.isValid()) {
+ lcdDrawText(x, y, status.protocolSubName, flags);
+ }
+ else if (subType <= pdef->maxSubtype && pdef->subTypeString != nullptr) {
lcdDrawTextAtIndex(x, y, pdef->subTypeString, subType, flags);
- return;
}
else {
- MultiModuleStatus &status = getMultiModuleStatus(moduleIdx);
- if (status.protocolName[0] && status.isValid())
- lcdDrawText(x, y, status.protocolSubName, flags);
- else
- lcdDrawNumber(x, y, subType, flags);
+ lcdDrawNumber(x, y, subType, flags);
}
}
#endif
@@ -146,7 +145,7 @@ void editName(coord_t x, coord_t y, char * name, uint8_t size, event_t event, ui
if (c <= 0) v = -v;
}
else {
- v = checkIncDec(event, abs(v), '0', 'z', 0);
+ v = checkIncDec(event, abs(v), ' ', 'z', 0);
}
}
@@ -402,6 +401,10 @@ void drawSensorCustomValue(coord_t x, coord_t y, uint8_t sensor, int32_t value,
"Rx2 Lost",
"Rx1 NS",
"Rx2 NS",
+ "Rx3 FS",
+ "Rx3 LF",
+ "Rx3 Lost",
+ "Rx3 NS"
};
for (uint8_t i = 0; i < DIM(RXS_STATUS); i++) {
if (value & (1u << i)) {
diff --git a/radio/src/gui/common/stdlcd/draw_functions.h b/radio/src/gui/common/stdlcd/draw_functions.h
index 7755206e3..9a98999a6 100644
--- a/radio/src/gui/common/stdlcd/draw_functions.h
+++ b/radio/src/gui/common/stdlcd/draw_functions.h
@@ -45,4 +45,9 @@ void drawSleepBitmap();
void lcdDrawMMM(coord_t x, coord_t y, LcdFlags flags=0);
void drawTrimMode(coord_t x, coord_t y, uint8_t flightMode, uint8_t idx, LcdFlags att=0);
+typedef int (*FnFuncP) (int x);
+void drawFunction(FnFuncP fn, uint8_t offset = 0);
+void drawCursor(FnFuncP fn, uint8_t offset = 0);
+void drawCurve(coord_t offset = 0);
+
#endif // _STDLCD_DRAW_FUNCTIONS_H_
diff --git a/radio/src/gui/common/stdlcd/model_curves.cpp b/radio/src/gui/common/stdlcd/model_curves.cpp
index 6fd7c1d0b..f0bd5ab2c 100644
--- a/radio/src/gui/common/stdlcd/model_curves.cpp
+++ b/radio/src/gui/common/stdlcd/model_curves.cpp
@@ -61,6 +61,7 @@ void menuModelCurvesAll(event_t event)
case EVT_KEY_FIRST(KEY_ENTER):
if (CURVE_SELECTED() && !READ_ONLY()) {
s_currIdxSubMenu = sub;
+ s_currSrcRaw = MIXSRC_NONE;
pushMenu(menuModelCurveOne);
}
break;
@@ -140,9 +141,9 @@ void editCurveRef(coord_t x, coord_t y, CurveRef & curve, event_t event, LcdFlag
break;
case CURVE_REF_CUSTOM:
drawCurveName(x, y, curve.value, flags);
- if (active && menuHorizontalPosition==1) {
- if (event==EVT_KEY_LONG(KEY_ENTER) && curve.value!=0) {
- s_currIdxSubMenu = (curve.value<0 ? -curve.value-1 : curve.value-1);
+ if (active && menuHorizontalPosition == 1) {
+ if (event == EVT_KEY_LONG(KEY_ENTER) && curve.value != 0) {
+ s_currIdxSubMenu = abs(curve.value) - 1;
pushMenu(menuModelCurveOne);
}
else {
@@ -152,3 +153,48 @@ void editCurveRef(coord_t x, coord_t y, CurveRef & curve, event_t event, LcdFlag
break;
}
}
+
+void drawFunction(FnFuncP fn, uint8_t offset)
+{
+ lcdDrawVerticalLine(CURVE_CENTER_X - offset, CURVE_CENTER_Y-CURVE_SIDE_WIDTH, CURVE_SIDE_WIDTH * 2, 0xee);
+ lcdDrawHorizontalLine(CURVE_CENTER_X - CURVE_SIDE_WIDTH - offset, CURVE_CENTER_Y, CURVE_SIDE_WIDTH * 2, 0xee);
+
+ coord_t prev_yv = (coord_t) - 1;
+
+ for (int xv = -CURVE_SIDE_WIDTH; xv <= CURVE_SIDE_WIDTH; xv++) {
+ coord_t yv = (LCD_H - 1) - (((uint16_t)RESX + fn(xv * (RESX/CURVE_SIDE_WIDTH))) / 2 * (LCD_H - 1) / RESX);
+ if (prev_yv != (coord_t) - 1) {
+ if (abs((int8_t)yv-prev_yv) <= 1) {
+ lcdDrawPoint(CURVE_CENTER_X + xv - offset - 1, prev_yv, FORCE);
+ }
+ else {
+ uint8_t tmp = (prev_yv < yv ? 0 : 1);
+ lcdDrawSolidVerticalLine(CURVE_CENTER_X + xv - offset - 1, yv + tmp, prev_yv - yv);
+ }
+ }
+ prev_yv = yv;
+ }
+}
+
+void drawCursor(FnFuncP fn, uint8_t offset)
+{
+ int x512 = getValue(s_currSrcRaw);
+ if (s_currSrcRaw >= MIXSRC_FIRST_TELEM) {
+ if (s_currScale > 0)
+ x512 = (x512 * 1024) / convertTelemValue(s_currSrcRaw - MIXSRC_FIRST_TELEM + 1, s_currScale);
+ drawSensorCustomValue(LCD_W - FW - offset, 6 * FH, (s_currSrcRaw - MIXSRC_FIRST_TELEM) / 3, x512, 0);
+ }
+ else {
+ lcdDrawNumber(LCD_W - FW - offset, 6*FH, calcRESXto1000(x512), RIGHT | PREC1);
+ }
+ x512 = limit(-1024, x512, 1024);
+ int y512 = fn(x512);
+ y512 = limit(-1024, y512, 1024);
+ lcdDrawNumber(CURVE_CENTER_X - FWNUM - offset, 1*FH, calcRESXto1000(y512), RIGHT | PREC1);
+
+ x512 = CURVE_CENTER_X + x512/(RESX / CURVE_SIDE_WIDTH);
+ y512 = (LCD_H - 1) - ((y512 + RESX) / 2) * (LCD_H - 1) / RESX;
+
+ lcdDrawSolidVerticalLine(x512 - offset, y512-3, 3 * 2 + 1);
+ lcdDrawSolidHorizontalLine(x512 - 3 - offset, y512, 3 * 2 + 1);
+}
diff --git a/radio/src/gui/common/stdlcd/model_mixes.cpp b/radio/src/gui/common/stdlcd/model_mixes.cpp
index d5324e509..103083486 100644
--- a/radio/src/gui/common/stdlcd/model_mixes.cpp
+++ b/radio/src/gui/common/stdlcd/model_mixes.cpp
@@ -479,6 +479,13 @@ void menuModelMixAll(event_t event)
s_currCh = ch;
if (!s_copyMode) {
attr = INVERS;
+ displayHeaderChannelName(ch - 1);
+#if LCD_W >= 212
+ if (g_model.limitData[ch - 1].name[0] != '\0') {
+ coord_t xPos = MIX_HDR_GAUGE_POS_X - FWNUM * 5 - 50;
+ lcdDrawFilledRect(lcdNextPos, 0, lcdNextPos - xPos, MENU_HEADER_HEIGHT, SOLID, FILL_WHITE | GREY_DEFAULT);
+ }
+#endif
}
}
if (cur-menuVerticalOffset >= 0 && cur-menuVerticalOffset < NUM_BODY_LINES) {
diff --git a/radio/src/gui/common/stdlcd/model_receiver_options.cpp b/radio/src/gui/common/stdlcd/model_receiver_options.cpp
index 6ce66ee29..8516f61cf 100644
--- a/radio/src/gui/common/stdlcd/model_receiver_options.cpp
+++ b/radio/src/gui/common/stdlcd/model_receiver_options.cpp
@@ -47,7 +47,7 @@ enum {
ITEM_RECEIVER_SETTINGS_PWM_RATE,
ITEM_RECEIVER_SETTINGS_TELEMETRY,
ITEM_RECEIVER_SETTINGS_TELEMETRY_25MW,
- ITEM_RECEIVER_SETTINGS_SPORT_FPORT,
+ ITEM_RECEIVER_SETTINGS_SPORT_MODE,
ITEM_RECEIVER_SETTINGS_CAPABILITY_NOT_SUPPORTED1,
ITEM_RECEIVER_SETTINGS_CAPABILITY_NOT_SUPPORTED2,
ITEM_RECEIVER_SETTINGS_PINMAP_FIRST
@@ -59,6 +59,15 @@ enum {
#define CH_ENABLE_SPORT 4
#define CH_ENABLE_SBUS 5
+bool isSPortModeAvailable(int mode)
+{
+ uint8_t receiverId = reusableBuffer.hardwareAndSettings.receiverSettings.receiverId;
+ if (mode == 2 && !IS_RECEIVER_CAPABILITY_ENABLED(RECEIVER_CAPABILITY_FPORT2)) {
+ return false;
+ }
+ return true;
+}
+
void menuModelReceiverOptions(event_t event)
{
const int lim = (g_model.extendedLimits ? (512 * LIMIT_EXT_PERCENT / 100) : 512) * 2;
@@ -81,7 +90,7 @@ void menuModelReceiverOptions(event_t event)
0, // PWM rate
isModuleR9MAccess(g_moduleIdx) && receiverVariant == PXX2_VARIANT_EU && reusableBuffer.hardwareAndSettings.moduleSettings.txPower > 14 /*25mW*/ ? READONLY_ROW : (uint8_t)0, // Telemetry
IF_RECEIVER_CAPABILITY(RECEIVER_CAPABILITY_TELEMETRY_25MW, 0),
- IF_RECEIVER_CAPABILITY(RECEIVER_CAPABILITY_FPORT, 0),
+ uint8_t((IS_RECEIVER_CAPABILITY_ENABLED(RECEIVER_CAPABILITY_FPORT) || IS_RECEIVER_CAPABILITY_ENABLED(RECEIVER_CAPABILITY_FPORT2)) ? 0 : HIDDEN_ROW),
uint8_t(reusableBuffer.hardwareAndSettings.modules[g_moduleIdx].receivers[receiverId].information.capabilityNotSupported ? READONLY_ROW : HIDDEN_ROW),
uint8_t(reusableBuffer.hardwareAndSettings.modules[g_moduleIdx].receivers[receiverId].information.capabilityNotSupported ? READONLY_ROW : HIDDEN_ROW),
0 // channels ...
@@ -132,11 +141,11 @@ void menuModelReceiverOptions(event_t event)
lcdInvertLine(0);
if (reusableBuffer.hardwareAndSettings.receiverSettings.state == PXX2_SETTINGS_OK) {
- for (uint8_t k=0; k> 1;
reusableBuffer.hardwareAndSettings.receiverSettings.dirty = RECEIVER_SETTINGS_DIRTY;
}
break;
+ }
case ITEM_RECEIVER_SETTINGS_CAPABILITY_NOT_SUPPORTED1:
lcdDrawText(LCD_W/2, y+1, STR_MORE_OPTIONS_AVAILABLE, SMLSIZE|CENTERED);
diff --git a/radio/src/gui/common/stdlcd/radio_ghost_menu.cpp b/radio/src/gui/common/stdlcd/radio_ghost_menu.cpp
new file mode 100644
index 000000000..5b2d90dc6
--- /dev/null
+++ b/radio/src/gui/common/stdlcd/radio_ghost_menu.cpp
@@ -0,0 +1,123 @@
+/*
+ * 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.
+ */
+
+#include "opentx.h"
+
+void menuGhostModuleConfig(event_t event)
+{
+ switch (event) {
+ case EVT_ENTRY:
+ memclear(&reusableBuffer.ghostMenu, sizeof(reusableBuffer.ghostMenu));
+ strAppend((char *) &reusableBuffer.ghostMenu.line[1].menuText, STR_WAITING_FOR_MODULE, 0);
+ reusableBuffer.ghostMenu.line[1].lineFlags = GHST_LINE_FLAGS_VALUE_EDIT;
+ reusableBuffer.ghostMenu.buttonAction = GHST_BTN_NONE;
+ reusableBuffer.ghostMenu.menuAction = GHST_MENU_CTRL_OPEN;
+ moduleState[EXTERNAL_MODULE].counter = GHST_MENU_CONTROL;
+ break;
+
+#if defined(ROTARY_ENCODER_NAVIGATION)
+ case EVT_ROTARY_LEFT:
+#elif defined(KEYS_GPIO_REG_UP)
+ case EVT_KEY_BREAK(KEY_UP):
+#elif defined(KEYS_GPIO_REG_PLUS)
+ case EVT_KEY_BREAK(KEY_PLUS):
+#endif
+ reusableBuffer.ghostMenu.buttonAction = GHST_BTN_JOYUP;
+ reusableBuffer.ghostMenu.menuAction = GHST_MENU_CTRL_NONE;
+ moduleState[EXTERNAL_MODULE].counter = GHST_MENU_CONTROL;
+ audioKeyPress();
+ break;
+
+#if defined(ROTARY_ENCODER_NAVIGATION)
+ case EVT_ROTARY_RIGHT:
+#elif defined(KEYS_GPIO_REG_DOWN)
+ case EVT_KEY_BREAK(KEY_DOWN):
+#elif defined(KEYS_GPIO_REG_MINUS)
+ case EVT_KEY_BREAK(KEY_MINUS):
+#endif
+ reusableBuffer.ghostMenu.buttonAction = GHST_BTN_JOYDOWN;
+ reusableBuffer.ghostMenu.menuAction = GHST_MENU_CTRL_NONE;
+ moduleState[EXTERNAL_MODULE].counter = GHST_MENU_CONTROL;
+ audioKeyPress();
+ break;
+
+
+ case EVT_KEY_FIRST(KEY_ENTER):
+ reusableBuffer.ghostMenu.buttonAction = GHST_BTN_JOYPRESS;
+ reusableBuffer.ghostMenu.menuAction = GHST_MENU_CTRL_NONE;
+ moduleState[EXTERNAL_MODULE].counter = GHST_MENU_CONTROL;
+ audioKeyPress();
+ break;
+
+ case EVT_KEY_BREAK(KEY_EXIT):
+ reusableBuffer.ghostMenu.buttonAction = GHST_BTN_JOYLEFT;
+ reusableBuffer.ghostMenu.menuAction = GHST_MENU_CTRL_NONE;
+ moduleState[EXTERNAL_MODULE].counter = GHST_MENU_CONTROL;
+ audioKeyPress();
+ break;
+
+ case EVT_KEY_LONG(KEY_EXIT):
+ menuVerticalOffset = 0;
+ memclear(&reusableBuffer.ghostMenu, sizeof(reusableBuffer.ghostMenu));
+ reusableBuffer.ghostMenu.buttonAction = GHST_BTN_NONE;
+ reusableBuffer.ghostMenu.menuAction = GHST_MENU_CTRL_CLOSE;
+ moduleState[EXTERNAL_MODULE].counter = GHST_MENU_CONTROL;
+ RTOS_WAIT_MS(10);
+ popMenu();
+ break;
+ }
+
+ if (reusableBuffer.ghostMenu.menuStatus == GHST_MENU_STATUS_UNOPENED) { // Handles situation where module is plugged after tools start
+ reusableBuffer.ghostMenu.buttonAction = GHST_BTN_NONE;
+ reusableBuffer.ghostMenu.menuAction = GHST_MENU_CTRL_OPEN;
+ moduleState[EXTERNAL_MODULE].counter = GHST_MENU_CONTROL;
+ }
+ else if (reusableBuffer.ghostMenu.menuStatus == GHST_MENU_STATUS_CLOSING) {
+ popMenu();
+ }
+
+ constexpr coord_t xOffset = LCD_W / 3 - 15;
+ constexpr coord_t xOffset2 = LCD_W / 3 + LCD_W / 4;
+ constexpr coord_t yOffset = 6;
+ LcdFlags flags = 0;
+
+ for (uint8_t line = 0; line < GHST_MENU_LINES; line++) {
+ flags = 0;
+ if (reusableBuffer.ghostMenu.line[line].splitLine) {
+ if (reusableBuffer.ghostMenu.line[line].lineFlags & GHST_LINE_FLAGS_LABEL_SELECT)
+ flags = INVERS;
+ lcdDrawText(xOffset, yOffset + line * FH, reusableBuffer.ghostMenu.line[line].menuText, flags);
+
+ flags = 0;
+ if (reusableBuffer.ghostMenu.line[line].lineFlags & GHST_LINE_FLAGS_VALUE_SELECT)
+ flags |= INVERS;
+ if (reusableBuffer.ghostMenu.line[line].lineFlags & GHST_LINE_FLAGS_VALUE_EDIT)
+ flags |= BLINK;
+ lcdDrawText(xOffset2, yOffset + line * FH, &reusableBuffer.ghostMenu.line[line].menuText[reusableBuffer.ghostMenu.line[line].splitLine], flags);
+ }
+ else {
+ if (reusableBuffer.ghostMenu.line[line].lineFlags & GHST_LINE_FLAGS_LABEL_SELECT)
+ flags = INVERS;
+ if (reusableBuffer.ghostMenu.line[line].lineFlags & GHST_LINE_FLAGS_VALUE_EDIT)
+ flags |= BLINK;
+ lcdDrawText(xOffset, yOffset + line * FH, reusableBuffer.ghostMenu.line[line].menuText, flags);
+ }
+ }
+}
diff --git a/radio/src/gui/common/stdlcd/radio_hardware.cpp b/radio/src/gui/common/stdlcd/radio_hardware.cpp
index dde563d6a..7f38f692e 100644
--- a/radio/src/gui/common/stdlcd/radio_hardware.cpp
+++ b/radio/src/gui/common/stdlcd/radio_hardware.cpp
@@ -98,8 +98,10 @@ enum {
ITEM_RADIO_HARDWARE_STICK2,
ITEM_RADIO_HARDWARE_STICK3,
ITEM_RADIO_HARDWARE_STICK4,
+#if (NUM_POTS + NUM_SLIDERS) > 0
ITEM_RADIO_HARDWARE_LABEL_POTS,
ITEM_RADIO_HARDWARE_POT1,
+#endif
#if defined(HARDWARE_POT2)
ITEM_RADIO_HARDWARE_POT2,
#endif
@@ -162,7 +164,7 @@ enum {
ITEM_RADIO_HARDWARE_CAPACITY_CALIB,
#endif
-#if defined(CROSSFIRE) && SPORT_MAX_BAUDRATE < 400000
+#if (defined(CROSSFIRE) || defined(GHOST)) && SPORT_MAX_BAUDRATE < 400000
ITEM_RADIO_HARDWARE_SERIAL_BAUDRATE,
#endif
@@ -195,20 +197,22 @@ enum {
ITEM_RADIO_HARDWARE_MAX
};
-#if (NUM_POTS + NUM_SLIDERS) == 1
- #define POTS_ROWS NAVIGATION_LINE_BY_LINE|1
+#if (NUM_POTS + NUM_SLIDERS) == 0
+ #define POTS_ROWS
+#elif (NUM_POTS + NUM_SLIDERS) == 1
+ #define POTS_ROWS LABEL(Pots), NAVIGATION_LINE_BY_LINE|1,
#elif (NUM_POTS + NUM_SLIDERS) == 2
- #define POTS_ROWS NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1
+ #define POTS_ROWS LABEL(Pots), NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1,
#elif (NUM_POTS + NUM_SLIDERS) == 3
- #define POTS_ROWS NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1
+ #define POTS_ROWS LABEL(Pots), NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1,
#elif defined(PCBX9D) // TODO defined(STORAGE_POT3) && !defined(STORAGE_POT3)
- #define POTS_ROWS NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, HIDDEN_ROW, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1
+ #define POTS_ROWS LABEL(Pots), NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, HIDDEN_ROW, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1,
#elif (NUM_POTS + NUM_SLIDERS) == 4
- #define POTS_ROWS NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1
+ #define POTS_ROWS LABEL(Pots), NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1,
#elif (NUM_POTS + NUM_SLIDERS) == 5
- #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
+ #define POTS_ROWS LABEL(Pots), NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1,
#elif (NUM_POTS + NUM_SLIDERS) == 8
- #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, NAVIGATION_LINE_BY_LINE|1
+ #define POTS_ROWS LABEL(Pots), 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,
#endif
#if defined(PCBX9E)
@@ -238,20 +242,20 @@ enum {
#endif
#if defined(INTERNAL_MODULE_PXX1) && defined(EXTERNAL_ANTENNA)
-#define EXTERNAL_ANTENNA_ROW 0,
-void onHardwareAntennaSwitchConfirm(const char * result)
-{
- if (result == STR_OK) {
- // Switch to external antenna confirmation
- g_eeGeneral.antennaMode = reusableBuffer.radioHardware.antennaMode;
- storageDirty(EE_GENERAL);
+ #define EXTERNAL_ANTENNA_ROW 0,
+ void onHardwareAntennaSwitchConfirm(const char * result)
+ {
+ if (result == STR_OK) {
+ // Switch to external antenna confirmation
+ g_eeGeneral.antennaMode = reusableBuffer.radioHardware.antennaMode;
+ storageDirty(EE_GENERAL);
+ }
+ else {
+ reusableBuffer.radioHardware.antennaMode = g_eeGeneral.antennaMode;
+ }
}
- else {
- reusableBuffer.radioHardware.antennaMode = g_eeGeneral.antennaMode;
- }
-}
#else
-#define EXTERNAL_ANTENNA_ROW
+ #define EXTERNAL_ANTENNA_ROW
#endif
#if defined(PCBX9LITE)
@@ -262,6 +266,8 @@ void onHardwareAntennaSwitchConfirm(const char * result)
#define SWITCH_TYPE_MAX(sw) (SWITCH_3POS)
#elif defined(PCBX9E)
#define SWITCH_TYPE_MAX(sw) ((MIXSRC_SF - MIXSRC_FIRST_SWITCH == sw || MIXSRC_SH - MIXSRC_FIRST_SWITCH == sw) ? SWITCH_2POS : SWITCH_3POS)
+#elif defined(RADIO_TX12) || defined(RADIO_T8)
+ #define SWITCH_TYPE_MAX(sw) ((MIXSRC_SA - MIXSRC_FIRST_SWITCH == sw || MIXSRC_SD - MIXSRC_FIRST_SWITCH == sw) ? SWITCH_2POS : SWITCH_3POS)
#else
#define SWITCH_TYPE_MAX(sw) ((MIXSRC_SF - MIXSRC_FIRST_SWITCH == sw || MIXSRC_SH - MIXSRC_FIRST_SWITCH <= sw) ? SWITCH_2POS : SWITCH_3POS)
#endif
@@ -278,7 +284,7 @@ void onHardwareAntennaSwitchConfirm(const char * result)
#define TX_CAPACITY_MEASUREMENT_ROWS
#endif
-#if defined(CROSSFIRE) && SPORT_MAX_BAUDRATE < 400000
+#if (defined(CROSSFIRE) || defined(GHOST)) && (SPORT_MAX_BAUDRATE < 400000 || defined(DEBUG))
#define MAX_BAUD_ROWS 0,
#else
#define MAX_BAUD_ROWS
@@ -292,7 +298,7 @@ void onHardwareAntennaSwitchConfirm(const char * result)
#if LCD_W >= 212
#define HW_SETTINGS_COLUMN1 12*FW
- #define HW_SETTINGS_COLUMN2 (HW_SETTINGS_COLUMN1 + 6*FW)
+ #define HW_SETTINGS_COLUMN2 (20*FW - 3)
#else
#define HW_SETTINGS_COLUMN1 30
#define HW_SETTINGS_COLUMN2 (HW_SETTINGS_COLUMN1 + 5*FW)
@@ -324,31 +330,22 @@ void menuRadioHardware(event_t event)
0 /* stick 2 */,
0 /* stick 3 */,
0 /* stick 4 */,
- LABEL(Pots),
- POTS_ROWS,
+ POTS_ROWS
LABEL(Switches),
SWITCHES_ROWS,
-
0 /* battery calib */,
RTC_ROW
TX_CAPACITY_MEASUREMENT_ROWS
-
MAX_BAUD_ROWS
-
BLUETOOTH_ROWS
-
EXTERNAL_ANTENNA_ROW
-
AUX_SERIAL_ROWS
-
0 /* ADC filter */,
READONLY_ROW /* RAS */,
SPORT_POWER_ROWS
1 /* debugs */,
-
- 0,
-
- 0
+ 0 /* EEPROM backup */,
+ 0 /* Factory reset */
});
uint8_t sub = menuVerticalPosition - HEADER_LINE;
@@ -397,6 +394,7 @@ void menuRadioHardware(event_t event)
editStickHardwareSettings(HW_SETTINGS_COLUMN1, y, k - ITEM_RADIO_HARDWARE_STICK1, event, attr);
break;
+#if (NUM_POTS + NUM_SLIDERS) > 0
case ITEM_RADIO_HARDWARE_LABEL_POTS:
lcdDrawTextAlignedLeft(y, STR_POTS);
break;
@@ -448,6 +446,7 @@ void menuRadioHardware(event_t event)
g_eeGeneral.slidersConfig |= (potType << idx);
break;
}
+#endif
#endif
case ITEM_RADIO_HARDWARE_LABEL_SWITCHES:
@@ -544,7 +543,7 @@ void menuRadioHardware(event_t event)
break;
#endif
-#if defined(CROSSFIRE) && SPORT_MAX_BAUDRATE < 400000
+#if (defined(CROSSFIRE) || defined(GHOST)) && SPORT_MAX_BAUDRATE < 400000
case ITEM_RADIO_HARDWARE_SERIAL_BAUDRATE:
lcdDrawTextAlignedLeft(y, STR_MAXBAUDRATE);
lcdDrawNumber(HW_SETTINGS_COLUMN2, y, CROSSFIRE_BAUDRATES[g_eeGeneral.telemetryBaudrate], attr|LEFT);
@@ -569,7 +568,7 @@ void menuRadioHardware(event_t event)
lcdDrawTextAlignedLeft(y, STR_BLUETOOTH);
lcdDrawTextAtIndex(HW_SETTINGS_COLUMN2, y, STR_BLUETOOTH_MODES, g_eeGeneral.bluetoothMode, attr);
if (attr) {
- g_eeGeneral.bluetoothMode = checkIncDecGen(event, g_eeGeneral.bluetoothMode, BLUETOOTH_OFF, BLUETOOTH_TRAINER);
+ g_eeGeneral.bluetoothMode = checkIncDecGen(event, g_eeGeneral.bluetoothMode, BLUETOOTH_OFF, BLUETOOTH_MAX);
}
break;
diff --git a/radio/src/gui/common/stdlcd/radio_sdmanager.cpp b/radio/src/gui/common/stdlcd/radio_sdmanager.cpp
index ffb4ff0bd..8fe772898 100644
--- a/radio/src/gui/common/stdlcd/radio_sdmanager.cpp
+++ b/radio/src/gui/common/stdlcd/radio_sdmanager.cpp
@@ -224,12 +224,16 @@ void onSdManagerMenu(const char * result)
#if defined(INTERNAL_MODULE_MULTI)
else if (result == STR_FLASH_INTERNAL_MULTI) {
getSelectionFullPath(lfn);
- multiFlashFirmware(INTERNAL_MODULE, lfn);
+ multiFlashFirmware(INTERNAL_MODULE, lfn, MULTI_TYPE_MULTIMODULE);
}
#endif
else if (result == STR_FLASH_EXTERNAL_MULTI) {
getSelectionFullPath(lfn);
- multiFlashFirmware(EXTERNAL_MODULE, lfn);
+ multiFlashFirmware(EXTERNAL_MODULE, lfn, MULTI_TYPE_MULTIMODULE);
+ }
+ else if (result == STR_FLASH_EXTERNAL_ELRS) {
+ getSelectionFullPath(lfn);
+ multiFlashFirmware(EXTERNAL_MODULE, lfn, MULTI_TYPE_ELRS);
}
#endif
#if defined(BLUETOOTH)
@@ -246,10 +250,16 @@ void onSdManagerMenu(const char * result)
}
#endif
#if defined(PXX2)
- else if (result == STR_FLASH_RECEIVER_OTA_BY_INTERNAL || result == STR_FLASH_RECEIVER_OTA_BY_EXTERNAL) {
+ else if (result == STR_FLASH_RECEIVER_BY_INTERNAL_MODULE_OTA || result == STR_FLASH_RECEIVER_BY_EXTERNAL_MODULE_OTA) {
memclear(&reusableBuffer.sdManager.otaUpdateInformation, sizeof(OtaUpdateInformation));
getSelectionFullPath(reusableBuffer.sdManager.otaUpdateInformation.filename);
- reusableBuffer.sdManager.otaUpdateInformation.module = result == STR_FLASH_RECEIVER_OTA_BY_INTERNAL ? INTERNAL_MODULE : EXTERNAL_MODULE;
+ reusableBuffer.sdManager.otaUpdateInformation.module = (result == STR_FLASH_RECEIVER_BY_INTERNAL_MODULE_OTA ? INTERNAL_MODULE : EXTERNAL_MODULE);
+ moduleState[reusableBuffer.sdManager.otaUpdateInformation.module].startBind(&reusableBuffer.sdManager.otaUpdateInformation, onUpdateStateChanged);
+ }
+ else if (result == STR_FLASH_FLIGHT_CONTROLLER_BY_INTERNAL_MODULE_OTA || result == STR_FLASH_FLIGHT_CONTROLLER_BY_EXTERNAL_MODULE_OTA) {
+ memclear(&reusableBuffer.sdManager.otaUpdateInformation, sizeof(OtaUpdateInformation));
+ getSelectionFullPath(reusableBuffer.sdManager.otaUpdateInformation.filename);
+ reusableBuffer.sdManager.otaUpdateInformation.module = (result == STR_FLASH_FLIGHT_CONTROLLER_BY_INTERNAL_MODULE_OTA ? INTERNAL_MODULE : EXTERNAL_MODULE);
moduleState[reusableBuffer.sdManager.otaUpdateInformation.module].startBind(&reusableBuffer.sdManager.otaUpdateInformation, onUpdateStateChanged);
}
#endif
@@ -393,6 +403,12 @@ void menuRadioSdManager(event_t _event)
POPUP_MENU_ADD_ITEM(STR_FLASH_EXTERNAL_MULTI);
}
}
+
+ if (!READ_ONLY() && !strcasecmp(ext, ELRS_FIRMWARE_EXT)) {
+ TCHAR lfn[_MAX_LFN + 1];
+ getSelectionFullPath(lfn);
+ POPUP_MENU_ADD_ITEM(STR_FLASH_EXTERNAL_ELRS);
+ }
#endif
#if defined(PCBTARANIS)
if (!READ_ONLY() && !strcasecmp(ext, FIRMWARE_EXT)) {
@@ -403,14 +419,18 @@ void menuRadioSdManager(event_t _event)
else if (!READ_ONLY() && !strcasecmp(ext, SPORT_FIRMWARE_EXT)) {
if (HAS_SPORT_UPDATE_CONNECTOR())
POPUP_MENU_ADD_ITEM(STR_FLASH_EXTERNAL_DEVICE);
+#if defined(INTERNAL_MODULE_PXX1) || defined(INTERNAL_MODULE_PXX2)
POPUP_MENU_ADD_ITEM(STR_FLASH_INTERNAL_MODULE);
+#endif
POPUP_MENU_ADD_ITEM(STR_FLASH_EXTERNAL_MODULE);
}
else if (!READ_ONLY() && !strcasecmp(ext, FRSKY_FIRMWARE_EXT)) {
FrSkyFirmwareInformation information;
if (readFrSkyFirmwareInformation(line, information) == nullptr) {
+#if defined(INTERNAL_MODULE_PXX1) || defined(INTERNAL_MODULE_PXX2)
if (information.productFamily == FIRMWARE_FAMILY_INTERNAL_MODULE)
POPUP_MENU_ADD_ITEM(STR_FLASH_INTERNAL_MODULE);
+#endif
if (information.productFamily == FIRMWARE_FAMILY_EXTERNAL_MODULE)
POPUP_MENU_ADD_ITEM(STR_FLASH_EXTERNAL_MODULE);
if (information.productFamily == FIRMWARE_FAMILY_RECEIVER || information.productFamily == FIRMWARE_FAMILY_SENSOR) {
@@ -422,9 +442,13 @@ void menuRadioSdManager(event_t _event)
#if defined(PXX2)
if (information.productFamily == FIRMWARE_FAMILY_RECEIVER) {
if (isReceiverOTAEnabledFromModule(INTERNAL_MODULE, information.productId))
- POPUP_MENU_ADD_ITEM(STR_FLASH_RECEIVER_OTA_BY_INTERNAL);
+ POPUP_MENU_ADD_ITEM(STR_FLASH_RECEIVER_BY_INTERNAL_MODULE_OTA);
if (isReceiverOTAEnabledFromModule(EXTERNAL_MODULE, information.productId))
- POPUP_MENU_ADD_ITEM(STR_FLASH_RECEIVER_OTA_BY_EXTERNAL);
+ POPUP_MENU_ADD_ITEM(STR_FLASH_RECEIVER_BY_EXTERNAL_MODULE_OTA);
+ }
+ if (information.productFamily == FIRMWARE_FAMILY_FLIGHT_CONTROLLER) {
+ POPUP_MENU_ADD_ITEM(STR_FLASH_FLIGHT_CONTROLLER_BY_INTERNAL_MODULE_OTA);
+ POPUP_MENU_ADD_ITEM(STR_FLASH_FLIGHT_CONTROLLER_BY_EXTERNAL_MODULE_OTA);
}
#endif
#if defined(BLUETOOTH)
diff --git a/radio/src/gui/common/stdlcd/radio_tools.cpp b/radio/src/gui/common/stdlcd/radio_tools.cpp
index d5bfd12d4..056b80a59 100644
--- a/radio/src/gui/common/stdlcd/radio_tools.cpp
+++ b/radio/src/gui/common/stdlcd/radio_tools.cpp
@@ -129,6 +129,11 @@ void menuRadioTools(event_t event)
addRadioModuleTool(index++, STR_POWER_METER_EXT, menuRadioPowerMeter, EXTERNAL_MODULE);
#endif
+#if defined(GHOST)
+ if (isModuleGhost(EXTERNAL_MODULE))
+ addRadioModuleTool(index++, "Ghost Menu", menuGhostModuleConfig, EXTERNAL_MODULE);
+#endif
+
if (index == 0) {
lcdDrawCenteredText(LCD_H/2, STR_NO_TOOLS);
}
diff --git a/radio/src/gui/common/stdlcd/radio_version.cpp b/radio/src/gui/common/stdlcd/radio_version.cpp
index d6128ecb7..d3886f8e3 100644
--- a/radio/src/gui/common/stdlcd/radio_version.cpp
+++ b/radio/src/gui/common/stdlcd/radio_version.cpp
@@ -237,7 +237,7 @@ void menuRadioVersion(event_t event)
coord_t y = MENU_HEADER_HEIGHT + 2;
lcdDrawText(FW, y, vers_stamp, SMLSIZE);
- y += 4 * (FH - 1);
+ y += 5 * (FH - 1);
#if defined(COPROCESSOR)
lcdDrawText(FW, y, "COPR\037\033: ", SMLSIZE);
diff --git a/radio/src/gui/common/stdlcd/view_telemetry.cpp b/radio/src/gui/common/stdlcd/view_telemetry.cpp
index 61b506269..07a31442c 100644
--- a/radio/src/gui/common/stdlcd/view_telemetry.cpp
+++ b/radio/src/gui/common/stdlcd/view_telemetry.cpp
@@ -34,6 +34,9 @@ enum NavigationDirection {
#if defined(NAVIGATION_XLITE)
#define EVT_KEY_PREVIOUS_VIEW(evt) (evt == EVT_KEY_LONG(KEY_LEFT) && IS_SHIFT_PRESSED())
#define EVT_KEY_NEXT_VIEW(evt) (evt == EVT_KEY_LONG(KEY_RIGHT) && IS_SHIFT_PRESSED())
+#elif defined(KEYS_GPIO_REG_PAGEDN)
+ #define EVT_KEY_PREVIOUS_VIEW(evt) (evt == EVT_KEY_FIRST(KEY_PAGEUP))
+ #define EVT_KEY_NEXT_VIEW(evt) (evt == EVT_KEY_FIRST(KEY_PAGEDN))
#elif defined(NAVIGATION_X7) || defined(NAVIGATION_X9D)
#define EVT_KEY_PREVIOUS_VIEW(evt) (evt == EVT_KEY_LONG(KEY_PAGE))
#define EVT_KEY_NEXT_VIEW(evt) (evt == EVT_KEY_BREAK(KEY_PAGE))
diff --git a/radio/src/gui/gui_common.cpp b/radio/src/gui/gui_common.cpp
index b491d84b4..1bd84b21e 100644
--- a/radio/src/gui/gui_common.cpp
+++ b/radio/src/gui/gui_common.cpp
@@ -342,12 +342,6 @@ bool isSwitchAvailable(int swtch, SwitchContext context)
}
#endif
-#if defined(PCBSKY9X) && defined(REVX)
- if (swtch == SWSRC_REa) {
- return false;
- }
-#endif
-
if (swtch >= SWSRC_FIRST_LOGICAL_SWITCH && swtch <= SWSRC_LAST_LOGICAL_SWITCH) {
if (context == GeneralCustomFunctionsContext) {
return false;
@@ -390,6 +384,10 @@ bool isAux1ModeAvailable(int mode)
#if defined(AUX2_SERIAL)
if (mode == UART_MODE_SBUS_TRAINER)
return g_eeGeneral.aux2SerialMode != UART_MODE_SBUS_TRAINER;
+#if defined(RADIO_TX16S)
+ else
+ return (g_model.trainerData.mode != TRAINER_MODE_MASTER_BATTERY_COMPARTMENT || g_eeGeneral.aux2SerialMode == UART_MODE_SBUS_TRAINER);
+#endif
#endif
return true;
}
@@ -399,6 +397,10 @@ bool isAux2ModeAvailable(int mode)
#if defined(AUX_SERIAL)
if (mode == UART_MODE_SBUS_TRAINER)
return g_eeGeneral.auxSerialMode != UART_MODE_SBUS_TRAINER;
+#if defined(RADIO_TX16S)
+ else
+ return (g_model.trainerData.mode != TRAINER_MODE_MASTER_BATTERY_COMPARTMENT || g_eeGeneral.auxSerialMode == UART_MODE_SBUS_TRAINER);
+#endif
#endif
return true;
}
@@ -552,7 +554,7 @@ bool isPxx2IsrmChannelsCountAllowed(int channels)
bool isTrainerUsingModuleBay()
{
#if defined(PCBTARANIS)
- if (TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE <= g_model.trainerData.mode && g_model.trainerData.mode <= TRAINER_MODE_MASTER_BATTERY_COMPARTMENT)
+ if (TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE <= g_model.trainerData.mode && g_model.trainerData.mode <= TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE)
return true;
#endif
return false;
@@ -584,6 +586,14 @@ bool isModuleUsingSport(uint8_t moduleBay, uint8_t moduleType)
}
}
+bool areModulesConflicting(int intModuleType, int extModuleType)
+{
+ if (intModuleType == MODULE_TYPE_ISRM_PXX2)
+ return (extModuleType == MODULE_TYPE_GHOST);
+
+ return false;
+}
+
#if defined(HARDWARE_INTERNAL_MODULE)
bool isInternalModuleAvailable(int moduleType)
{
@@ -605,7 +615,7 @@ bool isInternalModuleAvailable(int moduleType)
if (moduleType == MODULE_TYPE_ISRM_PXX2) {
#if defined(PXX2) && defined(INTERNAL_MODULE_PXX2)
- return true;
+ return !areModulesConflicting(moduleType, g_model.moduleData[EXTERNAL_MODULE].type);
#endif
}
@@ -620,9 +630,6 @@ bool isInternalModuleAvailable(int moduleType)
bool isExternalModuleAvailable(int moduleType)
{
- if (moduleType == MODULE_TYPE_R9M_LITE_PRO_PXX1)
- return false;
-
#if !defined(HARDWARE_EXTERNAL_MODULE_SIZE_SML)
if (isModuleTypeR9MLite(moduleType) || moduleType == MODULE_TYPE_XJT_LITE_PXX2)
return false;
@@ -657,6 +664,11 @@ bool isExternalModuleAvailable(int moduleType)
return false;
#endif
+#if !defined(GHOST)
+ if (moduleType == MODULE_TYPE_GHOST)
+ return false;
+#endif
+
#if !defined(DSM2)
if (moduleType == MODULE_TYPE_DSM2)
return false;
@@ -673,6 +685,9 @@ bool isExternalModuleAvailable(int moduleType)
#endif
#if defined(HARDWARE_INTERNAL_MODULE)
+ if (areModulesConflicting(g_model.moduleData[INTERNAL_MODULE].type, moduleType))
+ return false;
+
if (isTrainerUsingModuleBay() || (isModuleUsingSport(EXTERNAL_MODULE, moduleType) && isModuleUsingSport(INTERNAL_MODULE, g_model.moduleData[INTERNAL_MODULE].type)))
return false;
#endif
@@ -697,6 +712,11 @@ bool isRfProtocolAvailable(int protocol)
return false;
}
#endif
+#if defined(GHOST)
+ if (protocol != MODULE_SUBTYPE_PXX1_OFF && g_model.moduleData[EXTERNAL_MODULE].type == MODULE_TYPE_GHOST) {
+ return false;
+ }
+#endif
#if !defined(MODULE_PROTOCOL_D8)
if (protocol == MODULE_SUBTYPE_PXX1_ACCST_D8) {
return false;
@@ -726,6 +746,10 @@ bool isTelemetryProtocolAvailable(int protocol)
return false;
}
+ if ( protocol== PROTOCOL_TELEMETRY_GHOST) {
+ return false;
+ }
+
#if !defined(MULTIMODULE)
if (protocol == PROTOCOL_TELEMETRY_SPEKTRUM || protocol == PROTOCOL_TELEMETRY_FLYSKY_IBUS || protocol == PROTOCOL_TELEMETRY_MULTIMODULE) {
return false;
@@ -761,7 +785,10 @@ bool isTrainerModeAvailable(int mode)
}
#endif
-#if defined(PCBTARANIS) && !defined(TRAINER_BATTERY_COMPARTMENT)
+#if defined(RADIO_TX16S) && defined(TRAINER_BATTERY_COMPARTMENT)
+ if (mode == TRAINER_MODE_MASTER_BATTERY_COMPARTMENT)
+ return (g_eeGeneral.auxSerialMode == UART_MODE_SBUS_TRAINER || g_eeGeneral.aux2SerialMode == UART_MODE_SBUS_TRAINER);
+#elif defined(PCBTARANIS) && !defined(TRAINER_BATTERY_COMPARTMENT)
if (mode == TRAINER_MODE_MASTER_BATTERY_COMPARTMENT)
return false;
#elif defined(PCBTARANIS)
@@ -805,6 +832,25 @@ bool modelHasNotes()
return false;
}
+bool confirmModelChange()
+{
+ if (TELEMETRY_STREAMING()) {
+ RAISE_ALERT(STR_MODEL, STR_MODEL_STILL_POWERED, STR_PRESS_ENTER_TO_CONFIRM, AU_MODEL_STILL_POWERED);
+ while (TELEMETRY_STREAMING()) {
+ RTOS_WAIT_MS(20);
+ if (readKeys() == (1 << KEY_ENTER)) {
+ killEvents(KEY_ENTER);
+ return true;
+ }
+ else if (readKeys() == (1 << KEY_EXIT)) {
+ killEvents(KEY_EXIT);
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
int getFirstAvailable(int min, int max, IsValueAvailable isValueAvailable)
{
int retval = 0;
@@ -898,8 +944,9 @@ const char STR_SUBTYPE_ESky[] = "\003""Std""ET4";
const char STR_SUBTYPE_MT99[] = "\006""MT99\0 ""H7\0 ""YZ\0 ""LS\0 ""FY805";
const char STR_SUBTYPE_MJXQ[] = "\007""WLH08\0 ""X600\0 ""X800\0 ""H26D\0 ""E010\0 ""H26WH\0 ""Phoenix";
const char STR_SUBTYPE_FY326[] = "\005""Std\0 ""FY319";
+const char STR_SUBTYPE_FUTABA[] = "\005""SFHSS";
const char STR_SUBTYPE_HONTAI[] = "\007""Std\0 ""JJRC X1""X5C1\0 ""FQ_951";
-const char STR_SUBTYPE_AFHDS2A[] = "\010""PWM,IBUS""PPM,IBUS""PWM,SBUS""PPM,SBUS";
+const char STR_SUBTYPE_AFHDS2A[] = "\010""PWM,IBUS""PPM,IBUS""PWM,SBUS""PPM,SBUS""PWM,IB16""PPM,IB16";
const char STR_SUBTYPE_Q2X2[] = "\004""Q222""Q242""Q282";
const char STR_SUBTYPE_WK2x01[] = "\006""WK2801""WK2401""W6_5_1""W6_6_1""W6_HeL""W6_HeI";
const char STR_SUBTYPE_Q303[] = "\006""Std\0 ""CX35\0 ""CX10D\0""CX10WD";
@@ -908,7 +955,7 @@ const char STR_SUBTYPE_ESKY150[] = "\003""4ch""7ch";
const char STR_SUBTYPE_H83D[] = "\007""Std\0 ""H20H\0 ""H20Mini""H30Mini";
const char STR_SUBTYPE_CORONA[] = "\005""V1\0 ""V2\0 ""FD V3";
const char STR_SUBTYPE_HITEC[] = "\007""Optima\0""Opt Hub""Minima\0";
-const char STR_SUBTYPE_WFLY[] = "\006""WFR0xS";
+const char STR_SUBTYPE_WFLY[] = "\005""WFR0x";
const char STR_SUBTYPE_BUGS_MINI[] = "\006""Std\0 ""Bugs3H";
const char STR_SUBTYPE_TRAXXAS[] = "\004""6519";
const char STR_SUBTYPE_E01X[] = "\005""E012\0""E015\0""E016H";
@@ -918,18 +965,24 @@ const char STR_SUBTYPE_V761[] = "\003""3ch""4ch";
const char STR_SUBTYPE_REDPINE[] = "\004""Fast""Slow";
const char STR_SUBTYPE_POTENSIC[] = "\003""A20";
const char STR_SUBTYPE_ZSX[] = "\007""280JJRC";
-const char STR_SUBTYPE_FLYZONE[] = "\005""FZ410";
+const char STR_SUBTYPE_HEIGHT[] = "\003""5ch""8ch";
const char STR_SUBTYPE_FRSKYX_RX[] = "\007""RX\0 ""CloneTX";
const char STR_SUBTYPE_HOTT[] = "\007""Sync\0 ""No_Sync";
const char STR_SUBTYPE_FX816[] = "\003""P38";
const char STR_SUBTYPE_PELIKAN[] = "\004""Pro\0""Lite";
const char STR_SUBTYPE_XK[] = "\004""X450""X420";
const char STR_SUBTYPE_XN297DUMP[] = "\004""250K""1M\0 ""2M\0 ""AUTO""NRF\0";
-const char STR_SUBTYPE_FRSKYX2[] = "\011""D16\0 ""D16 8ch\0 ""LBT(EU)\0 ""LBT 8ch\0 ""D16Cloned";
-const char STR_SUBTYPE_FRSKYR9[] = "\007""915MHz\0""868MHz\0""915 8ch""868 8ch";
+const char STR_SUBTYPE_FRSKYX2[] = "\010""D16\0 ""D16 8ch\0""LBT(EU)\0""LBT 8ch\0""Cloned\0 ""Clone8ch";
+const char STR_SUBTYPE_FRSKYR9[] = "\007""915MHz\0""868MHz\0""915 8ch""868 8ch""FCC\0 ""---\0 ""FCC 8ch";
const char STR_SUBTYPE_PROPEL[] = "\004""74-Z";
const char STR_SUBTYPE_FRSKYL[] = "\010""LR12\0 ""LR12 6ch";
const char STR_SUBTYPE_ESKY150V2[] = "\006""150 V2";
+const char STR_SUBTYPE_JJRC345[] = "\007""Std\0 ""SkyTmbr";
+const char STR_SUBTYPE_KYOSHO[] = "\004""FHSS""Hype";
+const char STR_SUBTYPE_RLINK[] = "\007""Surface""Air\0 ""DumboRC";
+const char STR_SUBTYPE_ELRS[] = "\007""N/A WIP";
+const char STR_SUBTYPE_REALACC[] = "\003""R11";
+const char STR_SUBTYPE_WFLY2[] = "\005""RF20x";
const char* mm_options_strings::options[] = {
nullptr,
@@ -941,9 +994,15 @@ const char* mm_options_strings::options[] = {
STR_MULTI_SERVOFREQ,
STR_MULTI_MAX_THROW,
STR_MULTI_RFCHAN,
- STR_MULTI_RFPOWER
+ STR_MULTI_RFPOWER,
+ STR_MULTI_WBUS
};
+const uint8_t getMaxMultiOptions()
+{
+ return DIM(mm_options_strings::options);
+}
+
const mm_protocol_definition multi_protocols[] = {
// Protocol as defined in pulses\modules_constants.h, number of sub_protocols - 1, Failsafe supported, Disable channel mapping supported, Subtype string, Option type
{MODULE_SUBTYPE_MULTI_FLYSKY, 4, false, true, STR_SUBTYPE_FLYSKY, nullptr},
@@ -964,11 +1023,11 @@ const mm_protocol_definition multi_protocols[] = {
{MODULE_SUBTYPE_MULTI_MT99XX, 4, false, false, STR_SUBTYPE_MT99, nullptr},
{MODULE_SUBTYPE_MULTI_MJXQ, 6, false, false, STR_SUBTYPE_MJXQ, STR_MULTI_RFTUNE},
{MODULE_SUBTYPE_MULTI_FY326, 1, false, false, STR_SUBTYPE_FY326, nullptr},
- {MODULE_SUBTYPE_MULTI_SFHSS, 0, true, true, NO_SUBTYPE, STR_MULTI_RFTUNE},
+ {MODULE_SUBTYPE_MULTI_FUTABA, 0, true, true, STR_SUBTYPE_FUTABA, STR_MULTI_RFTUNE},
{MODULE_SUBTYPE_MULTI_J6PRO, 0, false, true, NO_SUBTYPE, nullptr},
{MODULE_SUBTYPE_MULTI_HONTAI, 3, false, false, STR_SUBTYPE_HONTAI, nullptr},
{MODULE_SUBTYPE_MULTI_OLRS, 0, false, false, NO_SUBTYPE, STR_RFPOWER},
- {MODULE_SUBTYPE_MULTI_FS_AFHDS2A, 3, true, true, STR_SUBTYPE_AFHDS2A, STR_MULTI_SERVOFREQ},
+ {MODULE_SUBTYPE_MULTI_FS_AFHDS2A, 5, true, true, STR_SUBTYPE_AFHDS2A, STR_MULTI_SERVOFREQ},
{MODULE_SUBTYPE_MULTI_Q2X2, 2, false, false, STR_SUBTYPE_Q2X2, nullptr},
{MODULE_SUBTYPE_MULTI_WK_2X01, 5, false, true, STR_SUBTYPE_WK2x01, nullptr},
{MODULE_SUBTYPE_MULTI_Q303, 3, false, false, STR_SUBTYPE_Q303, nullptr},
@@ -988,20 +1047,28 @@ const mm_protocol_definition multi_protocols[] = {
{MODULE_SUBTYPE_MULTI_REDPINE, 1, false, false, STR_SUBTYPE_REDPINE, STR_MULTI_RFTUNE},
{MODULE_SUBTYPE_MULTI_POTENSIC, 0, false, false, STR_SUBTYPE_POTENSIC, nullptr},
{MODULE_SUBTYPE_MULTI_ZSX, 0, false, false, STR_SUBTYPE_ZSX, nullptr},
- {MODULE_SUBTYPE_MULTI_FLYZONE, 0, false, false, STR_SUBTYPE_FLYZONE, nullptr},
+ {MODULE_SUBTYPE_MULTI_HEIGHT, 1, false, false, STR_SUBTYPE_HEIGHT, nullptr},
{MODULE_SUBTYPE_MULTI_FRSKYX_RX, 1, false, false, STR_SUBTYPE_FRSKYX_RX, STR_MULTI_RFTUNE},
{MODULE_SUBTYPE_MULTI_HOTT, 1, true, false, STR_SUBTYPE_HOTT, STR_MULTI_RFTUNE},
{MODULE_SUBTYPE_MULTI_FX816, 0, false, false, STR_SUBTYPE_FX816, nullptr},
- {MODULE_SUBTYPE_MULTI_PELIKAN, 1, false, false, STR_SUBTYPE_PELIKAN, nullptr},
+ {MODULE_SUBTYPE_MULTI_PELIKAN, 1, false, true, STR_SUBTYPE_PELIKAN, nullptr},
{MODULE_SUBTYPE_MULTI_XK, 1, false, false, STR_SUBTYPE_XK, STR_MULTI_RFTUNE},
{MODULE_SUBTYPE_MULTI_XN297DUMP, 4, false, false, STR_SUBTYPE_XN297DUMP, STR_MULTI_RFCHAN},
- {MODULE_SUBTYPE_MULTI_FRSKYX2, 4, true, false, STR_SUBTYPE_FRSKYX2, STR_MULTI_RFTUNE},
- {MODULE_SUBTYPE_MULTI_FRSKY_R9, 3, true, false, STR_SUBTYPE_FRSKYR9, nullptr},
+ {MODULE_SUBTYPE_MULTI_FRSKYX2, 5, true, false, STR_SUBTYPE_FRSKYX2, STR_MULTI_RFTUNE},
+ {MODULE_SUBTYPE_MULTI_FRSKY_R9, 6, true, false, STR_SUBTYPE_FRSKYR9, nullptr},
{MODULE_SUBTYPE_MULTI_PROPEL, 0, false, false, STR_SUBTYPE_PROPEL, nullptr},
{MODULE_SUBTYPE_MULTI_FRSKYL, 1, false, false, STR_SUBTYPE_FRSKYL, STR_MULTI_RFTUNE},
{MODULE_SUBTYPE_MULTI_SKYARTEC, 0, false, false, NO_SUBTYPE, STR_MULTI_RFTUNE},
{MODULE_SUBTYPE_MULTI_ESKY150V2, 0, false, true, STR_SUBTYPE_ESKY150V2, STR_MULTI_RFTUNE},
+ {MODULE_SUBTYPE_MULTI_JJRC345, 1, false, false, STR_SUBTYPE_JJRC345, nullptr},
{MODULE_SUBTYPE_MULTI_Q90C, 0, false, false, NO_SUBTYPE, STR_MULTI_RFTUNE},
+ {MODULE_SUBTYPE_MULTI_KYOSHO, 1, false, true, STR_SUBTYPE_KYOSHO, nullptr},
+ {MODULE_SUBTYPE_MULTI_RLINK, 2, false, false, STR_SUBTYPE_RLINK, STR_MULTI_RFTUNE},
+ {MODULE_SUBTYPE_MULTI_ELRS, 0, false, false, STR_SUBTYPE_ELRS, nullptr},
+ {MODULE_SUBTYPE_MULTI_REALACC, 0, false, false, STR_SUBTYPE_REALACC, nullptr},
+ {MODULE_SUBTYPE_MULTI_OMP, 0, false, false, NO_SUBTYPE, STR_MULTI_RFTUNE},
+ {MODULE_SUBTYPE_MULTI_WFLY2, 0, false, false, STR_SUBTYPE_WFLY2, STR_MULTI_OPTION},
+ {MODULE_SUBTYPE_MULTI_E016HV2, 0, false, false, NO_SUBTYPE, STR_MULTI_RFTUNE},
{MM_RF_CUSTOM_SELECTED, 7, true, true, NO_SUBTYPE, STR_MULTI_OPTION},
// Sentinel and default for protocols not listed above (MM_RF_CUSTOM is 0xff)
@@ -1030,3 +1097,22 @@ void editStickHardwareSettings(coord_t x, coord_t y, int idx, event_t event, Lcd
else
lcdDrawMMM(x, y, flags);
}
+
+#if defined(MULTIMODULE)
+const char * getMultiOptionTitle(uint8_t moduleIdx)
+{
+ MultiModuleStatus &status = getMultiModuleStatus(moduleIdx);
+
+ if (status.isValid()) {
+ if (status.optionDisp >= getMaxMultiOptions()) {
+ status.optionDisp = 1; // Unknown options are defaulted to type 1 (basic option)
+ }
+ return mm_options_strings::options[status.optionDisp];
+ }
+ else {
+ const uint8_t multi_proto = g_model.moduleData[moduleIdx].getMultiProtocol();
+ const mm_protocol_definition * pdef = getMultiProtocolDefinition(multi_proto);
+ return pdef->optionsstr;
+ }
+}
+#endif
diff --git a/radio/src/gui/gui_common.h b/radio/src/gui/gui_common.h
index d1fdb8fa1..43c489d5f 100644
--- a/radio/src/gui/gui_common.h
+++ b/radio/src/gui/gui_common.h
@@ -99,6 +99,8 @@ bool isRssiSensorAvailable(int sensor);
bool modelHasNotes();
+bool confirmModelChange();
+
#if defined(COLORLCD)
bool isSwitch2POSWarningStateAvailable(int state);
#endif
@@ -126,8 +128,6 @@ void drawSourceValue(coord_t x, coord_t y, source_t channel, LcdFlags flags=0);
int convertMultiToOtx(int type);
-void drawCurve(coord_t offset=0);
-
#if defined(COLORLCD)
void drawStringWithIndex(coord_t x, coord_t y, const char * str, int idx, LcdFlags flags=0, const char * prefix=nullptr, const char * suffix=nullptr);
uint8_t editCheckBox(uint8_t value, coord_t x, coord_t y, LcdFlags flags, event_t event);
@@ -143,11 +143,14 @@ void runFatalErrorScreen(const char * message);
inline uint8_t MODULE_BIND_ROWS(int moduleIdx)
{
+ if (isModuleCrossfire(moduleIdx))
+ return 0;
+
if (isModuleMultimodule(moduleIdx)) {
- if (IS_RX_MULTI(moduleIdx))
- return 1;
- else
- return 2;
+ if (IS_RX_MULTI(moduleIdx))
+ return 1;
+ else
+ return 2;
}
else if (isModuleXJTD8(moduleIdx) || isModuleSBUS(moduleIdx) || isModuleAFHDS3(moduleIdx)) {
return 1;
@@ -173,7 +176,7 @@ inline uint8_t MODULE_CHANNELS_ROWS(int moduleIdx)
else
return 0;
}
- else if (isModuleDSM2(moduleIdx) || isModuleCrossfire(moduleIdx) || isModuleSBUS(moduleIdx)) {
+ else if (isModuleDSM2(moduleIdx) || isModuleCrossfire(moduleIdx) || isModuleGhost(moduleIdx) || isModuleSBUS(moduleIdx)) {
return 0;
}
else {
@@ -181,6 +184,34 @@ inline uint8_t MODULE_CHANNELS_ROWS(int moduleIdx)
}
}
+#if defined(PXX2)
+inline bool isRacingModeAllowed()
+{
+ return isModulePXX2(INTERNAL_MODULE) && g_model.moduleData[INTERNAL_MODULE].getChannelsCount() == 8;
+}
+
+inline bool isRacingModeEnabled()
+{
+ return isRacingModeAllowed() && g_model.moduleData[INTERNAL_MODULE].pxx2.racingMode;
+}
+
+inline uint8_t IF_ALLOW_RACING_MODE(int moduleIdx)
+{
+ if (!IS_MODULE_ENABLED(moduleIdx)) {
+ return HIDDEN_ROW;
+ }
+ else if (isRacingModeAllowed()) {
+ return 0;
+ }
+ return HIDDEN_ROW;
+}
+#else
+inline uint8_t IF_ALLOW_RACING_MODE(int)
+{
+ return HIDDEN_ROW;
+}
+#endif
+
#if defined(MULTIMODULE)
inline uint8_t MULTI_DISABLE_CHAN_MAP_ROW(uint8_t moduleIdx)
{
@@ -238,10 +269,12 @@ inline bool MULTIMODULE_HAS_SUBTYPE(uint8_t moduleIdx)
}
else
{
- if (g_model.moduleData[moduleIdx].getMultiProtocol() > MODULE_SUBTYPE_MULTI_LAST)
+ if (g_model.moduleData[moduleIdx].getMultiProtocol() > MODULE_SUBTYPE_MULTI_LAST) {
return true;
- else
- return getMultiProtocolDefinition(g_model.moduleData[moduleIdx].getMultiProtocol())->maxSubtype > 0;
+ }
+ else {
+ return getMultiProtocolDefinition(g_model.moduleData[moduleIdx].getMultiProtocol())->subTypeString != nullptr;
+ }
}
}
@@ -273,7 +306,7 @@ inline uint8_t MULTIMODULE_HASOPTIONS(uint8_t moduleIdx)
#define MULTIMODULE_MODULE_ROWS(moduleIdx) (MULTIMODULE_PROTOCOL_KNOWN(moduleIdx) && !IS_RX_MULTI(moduleIdx)) ? (uint8_t) 0 : HIDDEN_ROW, (MULTIMODULE_PROTOCOL_KNOWN(moduleIdx) && !IS_RX_MULTI(moduleIdx)) ? (uint8_t) 0 : HIDDEN_ROW, MULTI_DISABLE_CHAN_MAP_ROW(moduleIdx), // AUTOBIND, DISABLE TELEM, DISABLE CN.MAP
#define MULTIMODULE_TYPE_ROW(moduleIdx) isModuleMultimodule(moduleIdx) ? MULTIMODULE_RFPROTO_COLUMNS(moduleIdx) : HIDDEN_ROW,
-#define MULTIMODULE_STATUS_ROWS(moduleIdx) isModuleMultimodule(moduleIdx) ? TITLE_ROW : HIDDEN_ROW, (isModuleMultimodule(moduleIdx) && getMultiSyncStatus(moduleIdx).isValid()) ? TITLE_ROW : HIDDEN_ROW,
+#define MULTIMODULE_STATUS_ROWS(moduleIdx) isModuleMultimodule(moduleIdx) ? TITLE_ROW : HIDDEN_ROW, (isModuleMultimodule(moduleIdx) && getModuleSyncStatus(moduleIdx).isValid()) ? TITLE_ROW : HIDDEN_ROW,
#define MULTIMODULE_MODE_ROWS(moduleIdx) (g_model.moduleData[moduleIdx].multi.customProto) ? (uint8_t) 3 : MULTIMODULE_HAS_SUBTYPE(moduleIdx) ? (uint8_t)2 : (uint8_t)1
#define MULTIMODULE_TYPE_ROWS(moduleIdx) isModuleMultimodule(moduleIdx) ? (uint8_t) 0 : HIDDEN_ROW,
#define MULTIMODULE_SUBTYPE_ROWS(moduleIdx) isModuleMultimodule(moduleIdx) ? MULTIMODULE_RFPROTO_COLUMNS(moduleIdx) : HIDDEN_ROW,
@@ -293,9 +326,9 @@ inline uint8_t MULTIMODULE_HASOPTIONS(uint8_t moduleIdx)
#endif
#if defined(AFHDS3)
-#define AFHDS3_PROTOCOL_ROW(moduleIdx) isModuleAFHDS3(moduleIdx) ? TITLE_ROW : HIDDEN_ROW,
+#define AFHDS3_PROTOCOL_ROW(moduleIdx) isModuleAFHDS3(moduleIdx) ? uint8_t(0) : HIDDEN_ROW,
#define AFHDS3_MODE_ROWS(moduleIdx) isModuleAFHDS3(moduleIdx) ? TITLE_ROW : HIDDEN_ROW, isModuleAFHDS3(moduleIdx) ? TITLE_ROW : HIDDEN_ROW, isModuleAFHDS3(moduleIdx) ? TITLE_ROW : HIDDEN_ROW,
-#define AFHDS3_MODULE_ROWS(moduleIdx) isModuleAFHDS3(moduleIdx) ? (uint8_t) 0 : HIDDEN_ROW, isModuleAFHDS3(moduleIdx) ? (uint8_t) TITLE_ROW : HIDDEN_ROW,
+#define AFHDS3_MODULE_ROWS(moduleIdx) isModuleAFHDS3(moduleIdx) ? uint8_t(0) : HIDDEN_ROW, isModuleAFHDS3(moduleIdx) ? TITLE_ROW : HIDDEN_ROW,
#else
#define AFHDS3_PROTOCOL_ROW(moduleIdx)
#define AFHDS3_MODE_ROWS(moduleIdx)
@@ -313,6 +346,7 @@ inline uint8_t MODULE_OPTION_ROW(uint8_t moduleIdx) {
}
void editStickHardwareSettings(coord_t x, coord_t y, int idx, event_t event, LcdFlags flags);
+const char * getMultiOptionTitle(uint8_t moduleIdx);
const char * writeScreenshot();
diff --git a/radio/src/gui/navigation/navigation_9x.cpp b/radio/src/gui/navigation/navigation_9x.cpp
index bbc958c63..5e09cfdd1 100644
--- a/radio/src/gui/navigation/navigation_9x.cpp
+++ b/radio/src/gui/navigation/navigation_9x.cpp
@@ -82,7 +82,7 @@ int checkIncDec(event_t event, int val, int i_min, int i_max, unsigned int i_fla
}
#endif
- if (event==EVT_KEY_FIRST(KEY_RIGHT) || event==EVT_KEY_REPT(KEY_RIGHT) || (s_editMode>0 && (IS_ROTARY_RIGHT(event) || event==EVT_KEY_FIRST(KEY_UP) || event==EVT_KEY_REPT(KEY_UP)))) {
+ if ((s_editMode>0 && (IS_ROTARY_RIGHT(event) || event==EVT_KEY_FIRST(KEY_UP) || event==EVT_KEY_REPT(KEY_UP)))) {
do {
if (IS_KEY_REPT(event) && (i_flags & INCDEC_REP10)) {
newval += min(10, i_max-val);
@@ -98,7 +98,7 @@ int checkIncDec(event_t event, int val, int i_min, int i_max, unsigned int i_fla
AUDIO_KEY_ERROR();
}
}
- else if (event==EVT_KEY_FIRST(KEY_LEFT) || event==EVT_KEY_REPT(KEY_LEFT) || (s_editMode>0 && (IS_ROTARY_LEFT(event) || event==EVT_KEY_FIRST(KEY_DOWN) || event==EVT_KEY_REPT(KEY_DOWN)))) {
+ else if ((s_editMode>0 && (IS_ROTARY_LEFT(event) || event==EVT_KEY_FIRST(KEY_DOWN) || event==EVT_KEY_REPT(KEY_DOWN)))) {
do {
if (IS_KEY_REPT(event) && (i_flags & INCDEC_REP10)) {
newval -= min(10, val-i_min);
@@ -136,7 +136,7 @@ int checkIncDec(event_t event, int val, int i_min, int i_max, unsigned int i_fla
#if defined(AUTOSWITCH)
else {
uint8_t swtch = abs(getMovedSwitch());
- if (swtch) {
+ if (swtch && !IS_SWITCH_MULTIPOS(swtch)) {
newval = switchToMix(swtch);
}
}
diff --git a/radio/src/gui/navigation/navigation_horus.cpp b/radio/src/gui/navigation/navigation_horus.cpp
index d62d07810..9679ab6e7 100644
--- a/radio/src/gui/navigation/navigation_horus.cpp
+++ b/radio/src/gui/navigation/navigation_horus.cpp
@@ -137,7 +137,7 @@ int checkIncDec(event_t event, int val, int i_min, int i_max, unsigned int i_fla
#if defined(AUTOSWITCH)
else {
unsigned int swtch = abs(getMovedSwitch());
- if (swtch) {
+ if (swtch && !IS_SWITCH_MULTIPOS(swtch)) {
newval = switchToMix(swtch);
}
}
diff --git a/radio/src/gui/navigation/navigation_x7.cpp b/radio/src/gui/navigation/navigation_x7.cpp
index bc835a375..ecf00a02b 100644
--- a/radio/src/gui/navigation/navigation_x7.cpp
+++ b/radio/src/gui/navigation/navigation_x7.cpp
@@ -56,8 +56,11 @@ void onSwitchLongEnterPress(const char * result)
int checkIncDec(event_t event, int val, int i_min, int i_max, unsigned int i_flags, IsValueAvailable isValueAvailable, const CheckIncDecStops &stops)
{
int newval = val;
-
+#if defined(ROTARY_ENCODER_NAVIGATION)
if (s_editMode>0 && event==EVT_ROTARY_RIGHT) {
+#else
+ if (s_editMode>0 && (event==EVT_KEY_FIRST(KEY_PLUS) || event==EVT_KEY_REPT(KEY_PLUS))) {
+#endif
newval += min(rotencSpeed, i_max-val);
while (isValueAvailable && !isValueAvailable(newval) && newval<=i_max) {
newval++;
@@ -67,7 +70,11 @@ int checkIncDec(event_t event, int val, int i_min, int i_max, unsigned int i_fla
AUDIO_KEY_ERROR();
}
}
+#if defined(ROTARY_ENCODER_NAVIGATION)
else if (s_editMode>0 && event==EVT_ROTARY_LEFT) {
+#else
+ if (s_editMode>0 && (event==EVT_KEY_FIRST(KEY_MINUS) || event==EVT_KEY_REPT(KEY_MINUS))) {
+#endif
newval -= min(rotencSpeed, val-i_min);
while (isValueAvailable && !isValueAvailable(newval) && newval>=i_min) {
newval--;
@@ -99,7 +106,7 @@ int checkIncDec(event_t event, int val, int i_min, int i_max, unsigned int i_fla
#if defined(AUTOSWITCH)
else {
unsigned int swtch = abs(getMovedSwitch());
- if (swtch) {
+ if (swtch && !IS_SWITCH_MULTIPOS(swtch)) {
newval = switchToMix(swtch);
}
}
@@ -217,7 +224,11 @@ void check(event_t event, uint8_t curr, const MenuHandlerFunc * menuTab, uint8_t
if (menuTab) {
int cc = curr;
switch (event) {
+#if defined(KEYS_GPIO_REG_PAGEUP)
+ case EVT_KEY_FIRST(KEY_PAGEUP):
+#else
case EVT_KEY_LONG(KEY_PAGE):
+#endif
if (s_editMode>0)
break;
@@ -228,7 +239,11 @@ void check(event_t event, uint8_t curr, const MenuHandlerFunc * menuTab, uint8_t
killEvents(event);
break;
+#if defined(KEYS_GPIO_REG_PAGEDN)
+ case EVT_KEY_FIRST(KEY_PAGEDN):
+#else
case EVT_KEY_BREAK(KEY_PAGE):
+#endif
if (s_editMode>0)
break;
@@ -302,12 +317,14 @@ void check(event_t event, uint8_t curr, const MenuHandlerFunc * menuTab, uint8_t
}
}
break;
-
+#if defined(ROTARY_ENCODER_NAVIGATION)
case EVT_ROTARY_RIGHT:
- case EVT_KEY_FIRST(KEY_RIGHT):
AUDIO_KEY_PRESS();
// no break
- case EVT_KEY_REPT(KEY_RIGHT):
+#else
+ case EVT_KEY_FIRST(KEY_DOWN):
+ case EVT_KEY_REPT(KEY_DOWN):
+#endif
if (s_editMode > 0) break; // TODO it was !=
if ((COLATTR(l_posVert) & NAVIGATION_LINE_BY_LINE)) {
if (l_posHorz >= 0) {
@@ -333,12 +350,14 @@ void check(event_t event, uint8_t curr, const MenuHandlerFunc * menuTab, uint8_t
l_posHorz = POS_HORZ_INIT(l_posVert);
break;
-
+#if defined(ROTARY_ENCODER_NAVIGATION)
case EVT_ROTARY_LEFT:
- case EVT_KEY_FIRST(KEY_LEFT):
AUDIO_KEY_PRESS();
// no break
- case EVT_KEY_REPT(KEY_LEFT):
+#else
+ case EVT_KEY_FIRST(KEY_UP):
+ case EVT_KEY_REPT(KEY_UP):
+#endif
if (s_editMode > 0) break; // TODO it was !=
if ((COLATTR(l_posVert) & NAVIGATION_LINE_BY_LINE)) {
if (l_posHorz >= 0) {
diff --git a/radio/src/gui/navigation/navigation_x9d.cpp b/radio/src/gui/navigation/navigation_x9d.cpp
index a5d6fc332..2b3587cba 100644
--- a/radio/src/gui/navigation/navigation_x9d.cpp
+++ b/radio/src/gui/navigation/navigation_x9d.cpp
@@ -173,7 +173,7 @@ int checkIncDec(event_t event, int val, int i_min, int i_max, unsigned int i_fla
#if defined(AUTOSWITCH)
else {
unsigned int swtch = abs(getMovedSwitch());
- if (swtch) {
+ if (swtch && !IS_SWITCH_MULTIPOS(swtch)) {
newval = switchToMix(swtch);
}
}
diff --git a/radio/src/gui/navigation/navigation_xlite.cpp b/radio/src/gui/navigation/navigation_xlite.cpp
index 9cbafda8b..61d795e77 100644
--- a/radio/src/gui/navigation/navigation_xlite.cpp
+++ b/radio/src/gui/navigation/navigation_xlite.cpp
@@ -29,15 +29,6 @@ horzpos_t menuHorizontalPosition;
int8_t checkIncDec_Ret;
-#if defined(RADIO_T12)
-#define DBLKEYS_PRESSED_RGT_LFT(in) ((in & (KEYS_GPIO_PIN_RIGHT + KEYS_GPIO_PIN_LEFT)) == (KEYS_GPIO_PIN_RIGHT + KEYS_GPIO_PIN_LEFT))
-// set to 0
-#define DBLKEYS_PRESSED_UP_DWN(in) ((in & (KEYS_GPIO_PIN_UP + KEYS_GPIO_PIN_DOWN)) == (KEYS_GPIO_PIN_UP + KEYS_GPIO_PIN_DOWN))
-// set to max
-#define DBLKEYS_PRESSED_RGT_UP(in) ((in & (KEYS_GPIO_PIN_RIGHT + KEYS_GPIO_PIN_UP)) == (KEYS_GPIO_PIN_RIGHT + KEYS_GPIO_PIN_UP))
-// set to min
-#define DBLKEYS_PRESSED_LFT_DWN(in) ((in & (KEYS_GPIO_PIN_LEFT + KEYS_GPIO_PIN_DOWN)) == (KEYS_GPIO_PIN_LEFT + KEYS_GPIO_PIN_DOWN))
-#else
// invert the value
#define DBLKEYS_PRESSED_RGT_LFT(in) ((in & ((1<fptr, file->obj.objsize);
- UINT count=0;
+ UINT count = 0;
memclear(buffer, pageSize);
if (f_read(file, buffer, pageSize, &count) != FR_OK) {
result = "Error reading file";
@@ -384,24 +446,24 @@ const char * MultiFirmwareInformation::readV1Signature(const char * buffer)
else
return "Wrong format";
- if(buffer[MULTI_SIGN_BOOTLOADER_SUPPORT_OFFSET] == 'b')
+ if (buffer[MULTI_SIGN_BOOTLOADER_SUPPORT_OFFSET] == 'b')
optibootSupport = true;
else
optibootSupport = false;
- if(buffer[MULTI_SIGN_BOOTLOADER_CHECK_OFFSET] == 'c')
+ if (buffer[MULTI_SIGN_BOOTLOADER_CHECK_OFFSET] == 'c')
bootloaderCheck = true;
else
bootloaderCheck = false;
- if(buffer[MULTI_SIGN_TELEM_TYPE_OFFSET] == 't')
+ if (buffer[MULTI_SIGN_TELEM_TYPE_OFFSET] == 't')
telemetryType = FIRMWARE_MULTI_TELEM_MULTI_STATUS;
else if (buffer[MULTI_SIGN_TELEM_TYPE_OFFSET] == 's')
telemetryType = FIRMWARE_MULTI_TELEM_MULTI_TELEMETRY;
else
telemetryType = FIRMWARE_MULTI_TELEM_NONE;
- if(buffer[MULTI_SIGN_TELEM_INVERSION_OFFSET] == 'i')
+ if (buffer[MULTI_SIGN_TELEM_INVERSION_OFFSET] == 'i')
telemetryInversion = true;
else
telemetryInversion = false;
@@ -452,7 +514,7 @@ const char * MultiFirmwareInformation::readMultiFirmwareInformation(const char *
if (f_open(&file, filename, FA_READ) != FR_OK)
return "Error opening file";
- const char * err = readMultiFirmwareInformation(&file);
+ const char * err = readMultiFirmwareInformation(&file);
f_close(&file);
return err;
@@ -465,7 +527,7 @@ const char * MultiFirmwareInformation::readMultiFirmwareInformation(FIL * file)
if (f_size(file) < MULTI_SIGN_SIZE)
return "File too small";
-
+
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";
@@ -474,11 +536,11 @@ const char * MultiFirmwareInformation::readMultiFirmwareInformation(FIL * file)
if (!memcmp(buffer, "multi-x", 7)) {
return readV2Signature(buffer);
}
-
+
return readV1Signature(buffer);
}
-bool multiFlashFirmware(uint8_t moduleIdx, const char * filename)
+bool multiFlashFirmware(uint8_t moduleIdx, const char * filename, MultiModuleType type)
{
FIL file;
@@ -487,36 +549,40 @@ bool multiFlashFirmware(uint8_t moduleIdx, const char * filename)
return false;
}
- MultiFirmwareInformation firmwareFile;
- if (firmwareFile.readMultiFirmwareInformation(&file)) {
- f_close(&file);
- POPUP_WARNING("Not a valid file");
- return false;
- }
- f_lseek(&file, 0);
-
- if (moduleIdx == EXTERNAL_MODULE) {
- if (!firmwareFile.isMultiExternalFirmware()) {
+ if (type == MULTI_TYPE_MULTIMODULE) {
+ MultiFirmwareInformation firmwareFile;
+ if (firmwareFile.readMultiFirmwareInformation(&file)) {
f_close(&file);
- POPUP_WARNING(STR_NEEDS_FILE);
- SET_WARNING_INFO(STR_EXT_MULTI_SPEC, strlen(STR_EXT_MULTI_SPEC), 0);
+ POPUP_WARNING("Not a valid file");
return false;
}
- }
- else {
- if (!firmwareFile.isMultiInternalFirmware()) {
- f_close(&file);
- POPUP_WARNING(STR_NEEDS_FILE);
- SET_WARNING_INFO(STR_INT_MULTI_SPEC, strlen(STR_INT_MULTI_SPEC), 0);
- return false;
+ f_lseek(&file, 0);
+
+ if (moduleIdx == EXTERNAL_MODULE) {
+ if (!firmwareFile.isMultiExternalFirmware()) {
+ f_close(&file);
+ POPUP_WARNING(STR_NEEDS_FILE);
+ SET_WARNING_INFO(STR_EXT_MULTI_SPEC, strlen(STR_EXT_MULTI_SPEC), 0);
+ return false;
+ }
+ }
+ else {
+ if (!firmwareFile.isMultiInternalFirmware()) {
+ f_close(&file);
+ POPUP_WARNING(STR_NEEDS_FILE);
+ SET_WARNING_INFO(STR_INT_MULTI_SPEC, strlen(STR_INT_MULTI_SPEC), 0);
+ return false;
+ }
}
}
- const MultiFirmwareUpdateDriver* driver = &multiExternalUpdateDriver;
+ const MultiFirmwareUpdateDriver * driver = &multiExternalUpdateDriver;
#if defined(INTERNAL_MODULE_MULTI)
if (moduleIdx == INTERNAL_MODULE)
driver = &multiInternalUpdateDriver;
#endif
+ if (type == MULTI_TYPE_ELRS)
+ driver = &multiExtSportUpdateDriver;
pausePulses();
@@ -525,8 +591,10 @@ bool multiFlashFirmware(uint8_t moduleIdx, const char * filename)
INTERNAL_MODULE_OFF();
#endif
+#if defined(HARDWARE_EXTERNAL_MODULE)
uint8_t extPwr = IS_EXTERNAL_MODULE_ON();
EXTERNAL_MODULE_OFF();
+#endif
uint8_t spuPwr = IS_SPORT_UPDATE_POWER_ON();
SPORT_UPDATE_POWER_OFF();
@@ -540,7 +608,7 @@ bool multiFlashFirmware(uint8_t moduleIdx, const char * filename)
const char * result = driver->flashFirmware(&file, getBasename(filename));
f_close(&file);
- AUDIO_PLAY(AU_SPECIAL_SOUND_BEEP1 );
+ AUDIO_PLAY(AU_SPECIAL_SOUND_BEEP1);
BACKLIGHT_ENABLE();
if (result) {
@@ -563,7 +631,7 @@ bool multiFlashFirmware(uint8_t moduleIdx, const char * filename)
// reset telemetry protocol
telemetryInit(255);
-
+
#if defined(HARDWARE_INTERNAL_MODULE)
if (intPwr) {
INTERNAL_MODULE_ON();
@@ -571,10 +639,12 @@ bool multiFlashFirmware(uint8_t moduleIdx, const char * filename)
}
#endif
+#if defined(HARDWARE_EXTERNAL_MODULE)
if (extPwr) {
EXTERNAL_MODULE_ON();
setupPulsesExternalModule();
}
+#endif
if (spuPwr) {
SPORT_UPDATE_POWER_ON();
diff --git a/radio/src/io/multi_firmware_update.h b/radio/src/io/multi_firmware_update.h
index a4cb255fb..52a39243d 100644
--- a/radio/src/io/multi_firmware_update.h
+++ b/radio/src/io/multi_firmware_update.h
@@ -76,7 +76,7 @@ class MultiFirmwareInformation {
bool isMultiExternalFirmware() const
{
- return (telemetryInversion == true && optibootSupport == true && bootloaderCheck == true && telemetryType == FIRMWARE_MULTI_TELEM_MULTI_TELEMETRY);
+ return ((telemetryInversion == true || boardType == FIRMWARE_MULTI_STM ) && optibootSupport == true && bootloaderCheck == true && telemetryType == FIRMWARE_MULTI_TELEM_MULTI_TELEMETRY);
}
const char * readMultiFirmwareInformation(const char * filename);
@@ -101,6 +101,11 @@ class MultiFirmwareInformation {
const char * readV2Signature(const char * buffer);
};
-bool multiFlashFirmware(uint8_t module, const char * filename);
+enum MultiModuleType {
+ MULTI_TYPE_MULTIMODULE = 0,
+ MULTI_TYPE_ELRS,
+};
+
+bool multiFlashFirmware(uint8_t module, const char * filename, MultiModuleType type);
#endif //OPENTX_MULTI_FIRMWARE_H
diff --git a/radio/src/keys.h b/radio/src/keys.h
index e60e9dfe6..0d4bc37dc 100644
--- a/radio/src/keys.h
+++ b/radio/src/keys.h
@@ -46,14 +46,34 @@
// normal order of events is: FIRST, LONG, REPEAT, REPEAT, ..., BREAK
#define EVT_KEY_FIRST(key) ((key)|_MSK_KEY_FIRST) // fired when key is pressed
-#define EVT_KEY_LONG(key) ((key)|_MSK_KEY_LONG) // fired when key is held pressed for a while
#define EVT_KEY_REPT(key) ((key)|_MSK_KEY_REPT) // fired when key is held pressed long enough, fires multiple times with increasing speed
+#define EVT_KEY_LONG(key) ((key)|_MSK_KEY_LONG) // fired when key is held pressed for a while
#define EVT_KEY_BREAK(key) ((key)|_MSK_KEY_BREAK) // fired when key is released (short or long), but only if the event was not killed
-#define IS_KEY_FIRST(evt) (((evt) & _MSK_KEY_FLAGS) == _MSK_KEY_FIRST)
-#define IS_KEY_LONG(evt) (((evt) & _MSK_KEY_FLAGS) == _MSK_KEY_LONG)
-#define IS_KEY_REPT(evt) (((evt) & _MSK_KEY_FLAGS) == _MSK_KEY_REPT)
-#define IS_KEY_BREAK(evt) (((evt) & _MSK_KEY_FLAGS) == _MSK_KEY_BREAK)
+inline bool IS_KEY_FIRST(event_t evt)
+{
+ return (evt & _MSK_KEY_FLAGS) == _MSK_KEY_FIRST;
+}
+
+inline bool IS_KEY_REPT(event_t evt)
+{
+ return (evt & _MSK_KEY_FLAGS) == _MSK_KEY_REPT;
+}
+
+inline bool IS_KEY_LONG(event_t evt)
+{
+ return (evt & _MSK_KEY_FLAGS) == _MSK_KEY_LONG;
+}
+
+inline bool IS_KEY_BREAK(event_t evt)
+{
+ return (evt & _MSK_KEY_FLAGS) == _MSK_KEY_BREAK;
+}
+
+inline bool IS_KEY_EVT(event_t evt, uint8_t key)
+{
+ return (evt & _MSK_KEY_FLAGS) && (EVT_KEY_MASK(evt) == key);
+}
#if defined(PCBXLITE)
#define EVT_ROTARY_BREAK EVT_KEY_BREAK(KEY_ENTER)
@@ -62,6 +82,11 @@
#define EVT_ROTARY_RIGHT 0xDE00
#define IS_NEXT_EVENT(event) (event==EVT_KEY_FIRST(KEY_DOWN) || event==EVT_KEY_REPT(KEY_DOWN))
#define IS_PREVIOUS_EVENT(event) (event==EVT_KEY_FIRST(KEY_UP) || event==EVT_KEY_REPT(KEY_UP))
+#elif defined(RADIO_T8)
+ #define EVT_ROTARY_BREAK EVT_KEY_BREAK(KEY_ENTER)
+ #define EVT_ROTARY_LONG EVT_KEY_LONG(KEY_ENTER)
+ #define IS_NEXT_EVENT(event) (event==EVT_KEY_FIRST(KEY_DOWN) || event==EVT_KEY_REPT(KEY_DOWN))
+ #define IS_PREVIOUS_EVENT(event) (event==EVT_KEY_FIRST(KEY_UP) || event==EVT_KEY_REPT(KEY_UP))
#elif (defined(PCBHORUS) || defined(PCBTARANIS)) && defined(ROTARY_ENCODER_NAVIGATION)
#define EVT_ROTARY_BREAK EVT_KEY_BREAK(KEY_ENTER)
#define EVT_ROTARY_LONG EVT_KEY_LONG(KEY_ENTER)
diff --git a/radio/src/lua/CMakeLists.txt b/radio/src/lua/CMakeLists.txt
index 9c5a952bb..589b5d1c1 100644
--- a/radio/src/lua/CMakeLists.txt
+++ b/radio/src/lua/CMakeLists.txt
@@ -24,9 +24,13 @@ if(PYTHONINTERP_FOUND)
add_lua_export_target(xlite ${LUA_INCLUDES} -DPCBTARANIS -DPCBXLITE)
add_lua_export_target(xlites ${LUA_INCLUDES} -DPCBTARANIS -DPCBXLITES -DPCBXLITE -DGYRO)
add_lua_export_target(x9d ${LUA_INCLUDES} -DPCBTARANIS -DPCBX9D -DPCBX9)
+ add_lua_export_target(x9d+2019 ${LUA_INCLUDES} -DPCBTARANIS -DPCBX9D -DPCBX9 -DRADIO_X9DP2019)
add_lua_export_target(x9e ${LUA_INCLUDES} -DPCBTARANIS -DPCBX9E -DPCBX9)
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(tlite ${LUA_INCLUDES} -DPCBTARANIS -DPCBX7 -DRADIO_TLITE)
+ add_lua_export_target(tx12 ${LUA_INCLUDES} -DPCBTARANIS -DPCBX7 -DRADIO_TX12)
+ add_lua_export_target(t8 ${LUA_INCLUDES} -DPCBTARANIS -DPCBX7 -DRADIO_T8)
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 3ee1bf1ae..3c6f20d42 100644
--- a/radio/src/lua/api_general.cpp
+++ b/radio/src/lua/api_general.cpp
@@ -40,6 +40,12 @@
#include "lua/lua_exports_x7.inc"
#elif defined(RADIO_T12)
#include "lua/lua_exports_t12.inc"
+#elif defined(RADIO_TLITE)
+ #include "lua/lua_exports_tlite.inc"
+#elif defined(RADIO_TX12)
+ #include "lua/lua_exports_tx12.inc"
+#elif defined(RADIO_T8)
+ #include "lua/lua_exports_t8.inc"
#elif defined(PCBX9LITES)
#include "lua/lua_exports_x9lites.inc"
#elif defined(PCBX9LITE)
@@ -48,6 +54,8 @@
#include "lua/lua_exports_xlites.inc"
#elif defined(PCBXLITE)
#include "lua/lua_exports_xlite.inc"
+#elif defined(RADIO_X9DP2019)
+ #include "lua/lua_exports_x9d+2019.inc"
#elif defined(PCBTARANIS)
#include "lua/lua_exports_x9d.inc"
#endif
@@ -375,6 +383,26 @@ bool luaFindFieldByName(const char * name, LuaField & field, unsigned int flags)
return false; // not found
}
+/*luadoc
+@function getRotEncSpeed()
+
+Return rotary encoder current speed
+
+@retval number in list: ROTENC_LOWSPEED, ROTENC_MIDSPEED, ROTENC_HIGHSPEED
+ return 0 on radio without rotary encoder
+
+@status current Introduced in 2.3.10
+*/
+static int luaGetRotEncSpeed(lua_State * L)
+{
+#if defined(ROTARY_ENCODER_NAVIGATION)
+ lua_pushunsigned(L, rotencSpeed);
+#else
+ lua_pushunsigned(L, 0);
+#endif
+ return 1;
+}
+
/*luadoc
@function sportTelemetryPop()
@@ -847,7 +875,7 @@ Return the internal GPS position or nil if no valid hardware found
static int luaGetTxGPS(lua_State * L)
{
#if defined(INTERNAL_GPS)
- lua_createtable(L, 0, 7);
+ lua_createtable(L, 0, 8);
lua_pushtablenumber(L, "lat", gpsData.latitude * 0.000001);
lua_pushtablenumber(L, "lon", gpsData.longitude * 0.000001);
lua_pushtableinteger(L, "numsat", gpsData.numSat);
@@ -1383,7 +1411,10 @@ Get RSSI value as well as low and critical RSSI alarm levels (in dB)
*/
static int luaGetRSSI(lua_State * L)
{
- lua_pushunsigned(L, min((uint8_t)99, TELEMETRY_RSSI()));
+ if (TELEMETRY_STREAMING())
+ lua_pushunsigned(L, min((uint8_t)99, TELEMETRY_RSSI()));
+ else
+ lua_pushunsigned(L, 0);
lua_pushunsigned(L, g_model.rssiAlarms.getWarningRssi());
lua_pushunsigned(L, g_model.rssiAlarms.getCriticalRssi());
return 3;
@@ -1574,13 +1605,42 @@ static int luaMultiBuffer(lua_State * L)
}
#endif
+/*luadoc
+@function setSerialBaudrate(baudrate)
+@param baudrate Desired baurate
+
+Set baudrate for serial port(s) affected to LUA
+
+@status current Introduced in 2.3.12
+*/
+static int luaSetSerialBaudrate(lua_State * L)
+{
+#if defined(AUX_SERIAL) || defined(AUX2_SERIAL)
+ unsigned int baudrate = luaL_checkunsigned(L, 1);
+#endif
+
+#if defined(AUX_SERIAL)
+ if (auxSerialMode == UART_MODE_LUA) {
+ auxSerialStop();
+ auxSerialSetup(baudrate, false);
+ }
+#endif
+#if defined(AUX2_SERIAL)
+ if (aux2SerialMode == UART_MODE_LUA) {
+ aux2SerialStop();
+ aux2SerialSetup(baudrate, false);
+ }
+#endif
+ return 1;
+}
+
/*luadoc
@function serialWrite(str)
@param str (string) String to be written to the serial port.
Writes a string to the serial port. The string is allowed to contain any character, including 0.
-@status current Introduced in TODO
+@status current Introduced in 2.3.10
*/
static int luaSerialWrite(lua_State * L)
{
@@ -1590,21 +1650,22 @@ static int luaSerialWrite(lua_State * L)
if (!str || len < 1)
return 0;
-#if !defined(SIMU)
- #if defined(USB_SERIAL)
+#if defined(USB_SERIAL)
if (getSelectedUsbMode() == USB_SERIAL_MODE) {
size_t wr_len = len;
const char* p = str;
while(wr_len--) usbSerialPutc(*p++);
}
- #endif
- #if defined(AUX_SERIAL)
+#endif
+
+#if defined(AUX_SERIAL)
if (auxSerialMode == UART_MODE_LUA) {
size_t wr_len = len;
const char* p = str;
while(wr_len--) auxSerialPutc(*p++);
}
- #endif
+#endif
+
#if defined(AUX2_SERIAL)
if (aux2SerialMode == UART_MODE_LUA) {
size_t wr_len = len;
@@ -1612,9 +1673,6 @@ static int luaSerialWrite(lua_State * L)
while(wr_len--) aux2SerialPutc(*p++);
}
#endif
-#else
- debugPrintf("luaSerialWrite: %.*s",len,str);
-#endif
return 0;
}
@@ -1680,6 +1738,7 @@ const luaL_Reg opentxLib[] = {
{ "getVersion", luaGetVersion },
{ "getGeneralSettings", luaGetGeneralSettings },
{ "getGlobalTimer", luaGetGlobalTimer },
+ { "getRotEncSpeed", luaGetRotEncSpeed },
{ "getValue", luaGetValue },
{ "getRAS", luaGetRAS },
{ "getTxGPS", luaGetTxGPS },
@@ -1717,6 +1776,7 @@ const luaL_Reg opentxLib[] = {
#if defined(MULTIMODULE)
{ "multiBuffer", luaMultiBuffer },
#endif
+ { "setSerialBaudrate", luaSetSerialBaudrate },
{ "serialWrite", luaSerialWrite },
{ "serialRead", luaSerialRead },
{ nullptr, nullptr } /* sentinel */
@@ -1756,8 +1816,10 @@ const luaR_value_entry opentxConstants[] = {
{ "MIXSRC_SE", MIXSRC_SE },
{ "MIXSRC_SG", MIXSRC_SG },
#endif
-#if !defined(PCBXLITE) && !defined(PCBX9LITE)
+#if defined(HARDWARE_SWITCH_F)
{ "MIXSRC_SF", MIXSRC_SF },
+#endif
+#if defined(HARDWARE_SWITCH_H)
{ "MIXSRC_SH", MIXSRC_SH },
#endif
{ "MIXSRC_CH1", MIXSRC_CH1 },
@@ -1768,7 +1830,6 @@ const luaR_value_entry opentxConstants[] = {
{ "COLOR", ZoneOption::Color },
{ "BOOL", ZoneOption::Bool },
{ "STRING", ZoneOption::String },
- { "CUSTOM_COLOR", CUSTOM_COLOR },
{ "TEXT_COLOR", TEXT_COLOR },
{ "TEXT_BGCOLOR", TEXT_BGCOLOR },
{ "TEXT_INVERTED_COLOR", TEXT_INVERTED_COLOR },
@@ -1778,22 +1839,26 @@ const luaR_value_entry opentxConstants[] = {
{ "MENU_TITLE_BGCOLOR", MENU_TITLE_BGCOLOR },
{ "MENU_TITLE_COLOR", MENU_TITLE_COLOR },
{ "MENU_TITLE_DISABLE_COLOR", MENU_TITLE_DISABLE_COLOR },
+ { "HEADER_COLOR", HEADER_COLOR },
{ "ALARM_COLOR", ALARM_COLOR },
{ "WARNING_COLOR", WARNING_COLOR },
{ "TEXT_DISABLE_COLOR", TEXT_DISABLE_COLOR },
- { "HEADER_COLOR", HEADER_COLOR },
{ "CURVE_AXIS_COLOR", CURVE_AXIS_COLOR },
{ "CURVE_COLOR", CURVE_COLOR },
{ "CURVE_CURSOR_COLOR", CURVE_CURSOR_COLOR },
{ "TITLE_BGCOLOR", TITLE_BGCOLOR },
{ "TRIM_BGCOLOR", TRIM_BGCOLOR },
{ "TRIM_SHADOW_COLOR", TRIM_SHADOW_COLOR },
- { "MAINVIEW_PANES_COLOR", MAINVIEW_PANES_COLOR },
- { "MAINVIEW_GRAPHICS_COLOR", MAINVIEW_GRAPHICS_COLOR },
{ "HEADER_BGCOLOR", HEADER_BGCOLOR },
{ "HEADER_ICON_BGCOLOR", HEADER_ICON_BGCOLOR },
{ "HEADER_CURRENT_BGCOLOR", HEADER_CURRENT_BGCOLOR },
+ { "MAINVIEW_PANES_COLOR", MAINVIEW_PANES_COLOR },
+ { "MAINVIEW_GRAPHICS_COLOR", MAINVIEW_GRAPHICS_COLOR },
{ "OVERLAY_COLOR", OVERLAY_COLOR },
+ { "BARGRAPH1_COLOR", BARGRAPH1_COLOR },
+ { "BARGRAPH2_COLOR", BARGRAPH2_COLOR },
+ { "BARGRAPH_BGCOLOR", BARGRAPH_BGCOLOR },
+ { "CUSTOM_COLOR", CUSTOM_COLOR },
{ "MENU_HEADER_HEIGHT", MENU_HEADER_HEIGHT },
{ "WHITE", (double)WHITE },
{ "GREY", (double)GREY },
@@ -1814,7 +1879,10 @@ const luaR_value_entry opentxConstants[] = {
{ "EVT_VIRTUAL_NEXT", EVT_ROTARY_RIGHT },
{ "EVT_VIRTUAL_DEC", EVT_ROTARY_LEFT },
{ "EVT_VIRTUAL_INC", EVT_ROTARY_RIGHT },
-#elif defined(PCBX9D) || defined(PCBX9DP) // key reverted between field nav and value change
+ { "ROTENC_LOWSPEED", ROTENC_LOWSPEED },
+ { "ROTENC_MIDSPEED", ROTENC_MIDSPEED },
+ { "ROTENC_HIGHSPEED", ROTENC_HIGHSPEED },
+#elif defined(PCBX9D) || defined(PCBX9DP) || defined(RADIO_T8) // key reverted between field nav and value change
{ "EVT_VIRTUAL_PREV", EVT_KEY_FIRST(KEY_PLUS) },
{ "EVT_VIRTUAL_PREV_REPT", EVT_KEY_REPT(KEY_PLUS) },
{ "EVT_VIRTUAL_NEXT", EVT_KEY_FIRST(KEY_MINUS) },
@@ -1851,10 +1919,17 @@ const luaR_value_entry opentxConstants[] = {
{ "EVT_VIRTUAL_ENTER_LONG", EVT_KEY_LONG(KEY_ENTER) },
{ "EVT_VIRTUAL_EXIT", EVT_KEY_BREAK(KEY_EXIT) },
#elif defined(NAVIGATION_X7) || defined(NAVIGATION_X9D)
+#if defined(RADIO_TX12) || defined(RADIO_T8)
+ { "EVT_VIRTUAL_PREV_PAGE", EVT_KEY_BREAK(KEY_PAGEUP) },
+ { "EVT_VIRTUAL_NEXT_PAGE", EVT_KEY_BREAK(KEY_PAGEDN) },
+ { "EVT_VIRTUAL_MENU", EVT_KEY_BREAK(KEY_MODEL) },
+ { "EVT_VIRTUAL_MENU_LONG", EVT_KEY_LONG(KEY_MODEL) },
+#else
{ "EVT_VIRTUAL_PREV_PAGE", EVT_KEY_LONG(KEY_PAGE) },
{ "EVT_VIRTUAL_NEXT_PAGE", EVT_KEY_BREAK(KEY_PAGE) },
{ "EVT_VIRTUAL_MENU", EVT_KEY_BREAK(KEY_MENU) },
{ "EVT_VIRTUAL_MENU_LONG", EVT_KEY_LONG(KEY_MENU) },
+#endif
{ "EVT_VIRTUAL_ENTER", EVT_KEY_BREAK(KEY_ENTER) },
{ "EVT_VIRTUAL_ENTER_LONG", EVT_KEY_LONG(KEY_ENTER) },
{ "EVT_VIRTUAL_EXIT", EVT_KEY_BREAK(KEY_EXIT) },
@@ -1966,6 +2041,7 @@ const luaR_value_entry opentxConstants[] = {
{"UNIT_KMH", UNIT_KMH },
{"UNIT_MPH", UNIT_MPH },
{"UNIT_METERS", UNIT_METERS },
+ {"UNIT_KM", UNIT_KM },
{"UNIT_FEET", UNIT_FEET },
{"UNIT_CELSIUS", UNIT_CELSIUS },
{"UNIT_FAHRENHEIT", UNIT_FAHRENHEIT },
@@ -1981,6 +2057,9 @@ const luaR_value_entry opentxConstants[] = {
{"UNIT_MILLILITERS", UNIT_MILLILITERS },
{"UNIT_FLOZ", UNIT_FLOZ },
{"UNIT_MILLILITERS_PER_MINUTE", UNIT_MILLILITERS_PER_MINUTE },
+ {"UNIT_HERTZ", UNIT_HERTZ },
+ {"UNIT_MS", UNIT_MS },
+ {"UNIT_US", UNIT_US },
{"UNIT_HOURS", UNIT_HOURS },
{"UNIT_MINUTES", UNIT_MINUTES },
{"UNIT_SECONDS", UNIT_SECONDS },
diff --git a/radio/src/lua/api_lcd.cpp b/radio/src/lua/api_lcd.cpp
index bb9172e32..a4079387c 100644
--- a/radio/src/lua/api_lcd.cpp
+++ b/radio/src/lua/api_lcd.cpp
@@ -71,7 +71,8 @@ Reset the backlight timeout
*/
static int luaLcdResetBacklightTimeout(lua_State * L)
{
- if (!luaLcdAllowed) return 0;
+ if (!luaLcdAllowed)
+ return 0;
resetBacklightTimeout();
return 0;
}
@@ -95,7 +96,8 @@ bottom line is 63. Drawing on an existing black pixel produces white pixel (TODO
*/
static int luaLcdDrawPoint(lua_State *L)
{
- if (!luaLcdAllowed) return 0;
+ if (!luaLcdAllowed)
+ return 0;
int x = luaL_checkinteger(L, 1);
int y = luaL_checkinteger(L, 2);
LcdFlags att = luaL_optunsigned(L, 3, 0);
@@ -123,7 +125,8 @@ whole line will not be drawn (starting from OpenTX 2.1.5)
*/
static int luaLcdDrawLine(lua_State *L)
{
- if (!luaLcdAllowed) return 0;
+ if (!luaLcdAllowed)
+ return 0;
coord_t x1 = luaL_checkunsigned(L, 1);
coord_t y1 = luaL_checkunsigned(L, 2);
coord_t x2 = luaL_checkunsigned(L, 3);
@@ -228,7 +231,8 @@ See the [Appendix](../appendix/fonts.md) for available characters in each font s
*/
static int luaLcdDrawText(lua_State *L)
{
- if (!luaLcdAllowed) return 0;
+ if (!luaLcdAllowed)
+ return 0;
int x = luaL_checkinteger(L, 1);
int y = luaL_checkinteger(L, 2);
const char * s = luaL_checkstring(L, 3);
@@ -259,7 +263,8 @@ Display a value formatted as time at (x,y)
*/
static int luaLcdDrawTimer(lua_State *L)
{
- if (!luaLcdAllowed) return 0;
+ if (!luaLcdAllowed)
+ return 0;
int x = luaL_checkinteger(L, 1);
int y = luaL_checkinteger(L, 2);
int seconds = luaL_checkinteger(L, 3);
@@ -293,7 +298,8 @@ Display a number at (x,y)
*/
static int luaLcdDrawNumber(lua_State *L)
{
- if (!luaLcdAllowed) return 0;
+ if (!luaLcdAllowed)
+ return 0;
int x = luaL_checkinteger(L, 1);
int y = luaL_checkinteger(L, 2);
int val = luaL_checkinteger(L, 3);
@@ -321,7 +327,8 @@ See getValue()
*/
static int luaLcdDrawChannel(lua_State *L)
{
- if (!luaLcdAllowed) return 0;
+ if (!luaLcdAllowed)
+ return 0;
int x = luaL_checkinteger(L, 1);
int y = luaL_checkinteger(L, 2);
int channel = -1;
@@ -358,7 +365,8 @@ displays negated switch
*/
static int luaLcdDrawSwitch(lua_State *L)
{
- if (!luaLcdAllowed) return 0;
+ if (!luaLcdAllowed)
+ return 0;
int x = luaL_checkinteger(L, 1);
int y = luaL_checkinteger(L, 2);
int s = luaL_checkinteger(L, 3);
@@ -382,7 +390,8 @@ Displays the name of the corresponding input as defined by the source at (x,y)
*/
static int luaLcdDrawSource(lua_State *L)
{
- if (!luaLcdAllowed) return 0;
+ if (!luaLcdAllowed)
+ return 0;
int x = luaL_checkinteger(L, 1);
int y = luaL_checkinteger(L, 2);
int s = luaL_checkinteger(L, 3);
@@ -532,7 +541,8 @@ Omitting scale draws image in 1:1 scale and is faster than specifying 100 for sc
*/
static int luaLcdDrawBitmap(lua_State *L)
{
- if (!luaLcdAllowed) return 0;
+ if (!luaLcdAllowed)
+ return 0;
const BitmapBuffer * b = checkBitmap(L, 1);
if (b) {
@@ -564,7 +574,8 @@ Draw a bitmap at (x,y)
*/
static int luaLcdDrawPixmap(lua_State *L)
{
- if (!luaLcdAllowed) return 0;
+ if (!luaLcdAllowed)
+ return 0;
int x = luaL_checkinteger(L, 1);
int y = luaL_checkinteger(L, 2);
const char * filename = luaL_checkstring(L, 3);
@@ -597,7 +608,8 @@ Draw a rectangle from top left corner (x,y) of specified width and height
*/
static int luaLcdDrawRectangle(lua_State *L)
{
- if (!luaLcdAllowed) return 0;
+ if (!luaLcdAllowed)
+ return 0;
int x = luaL_checkinteger(L, 1);
int y = luaL_checkinteger(L, 2);
int w = luaL_checkinteger(L, 3);
@@ -629,7 +641,8 @@ Draw a solid rectangle from top left corner (x,y) of specified width and height
*/
static int luaLcdDrawFilledRectangle(lua_State *L)
{
- if (!luaLcdAllowed) return 0;
+ if (!luaLcdAllowed)
+ return 0;
int x = luaL_checkinteger(L, 1);
int y = luaL_checkinteger(L, 2);
int w = luaL_checkinteger(L, 3);
@@ -661,7 +674,8 @@ Draw a simple gauge that is filled based upon fill value
*/
static int luaLcdDrawGauge(lua_State *L)
{
- if (!luaLcdAllowed) return 0;
+ if (!luaLcdAllowed)
+ return 0;
int x = luaL_checkinteger(L, 1);
int y = luaL_checkinteger(L, 2);
int w = luaL_checkinteger(L, 3);
@@ -699,7 +713,8 @@ the right side of title bar. (i.e. idx=2, cnt=5, display `2/5`)
*/
static int luaLcdDrawScreenTitle(lua_State *L)
{
- if (!luaLcdAllowed) return 0;
+ if (!luaLcdAllowed)
+ return 0;
const char * str = luaL_checkstring(L, 1);
int idx = luaL_checkinteger(L, 2);
int cnt = luaL_checkinteger(L, 3);
@@ -739,7 +754,8 @@ Draw a combo box
*/
static int luaLcdDrawCombobox(lua_State *L)
{
- if (!luaLcdAllowed) return 0;
+ if (!luaLcdAllowed)
+ return 0;
int x = luaL_checkinteger(L, 1);
int y = luaL_checkinteger(L, 2);
int w = luaL_checkinteger(L, 3);
@@ -793,7 +809,6 @@ static int luaLcdDrawCombobox(lua_State *L)
Set a color for specific area
@param area (unsigned number) specific screen area in the list bellow
- * `CUSTOM_COLOR`
* `TEXT_COLOR`
* `TEXT_BGCOLOR`
* `TEXT_INVERTED_COLOR`
@@ -807,18 +822,22 @@ Set a color for specific area
* `ALARM_COLOR`
* `WARNING_COLOR`
* `TEXT_DISABLE_COLOR`
- * `HEADER_COLOR`
* `CURVE_AXIS_COLOR`
+ * `CURVE_COLOR`
* `CURVE_CURSOR_COLOR`
* `TITLE_BGCOLOR`
* `TRIM_BGCOLOR`
* `TRIM_SHADOW_COLOR`
- * `MAINVIEW_PANES_COLOR`
- * `MAINVIEW_GRAPHICS_COLOR`
* `HEADER_BGCOLOR`
* `HEADER_ICON_BGCOLOR`
* `HEADER_CURRENT_BGCOLOR`
+ * `MAINVIEW_PANES_COLOR`
+ * `MAINVIEW_GRAPHICS_COLOR`
* `OVERLAY_COLOR`
+ * `BARGRAPH1_COLOR`
+ * `BARGRAPH2_COLOR`
+ * `BARGRAPH_BGCOLOR`
+ * `CUSTOM_COLOR`
@param color (number) color in 5/6/5 rgb format. The following prefined colors are available
* `WHITE`
@@ -831,19 +850,40 @@ Set a color for specific area
* `RED`
* `DARKRED`
-@notice Only available on Horus
+@notice Only available on Colorlcd radios
@status current Introduced in 2.2.0
*/
static int luaLcdSetColor(lua_State *L)
{
- if (!luaLcdAllowed) return 0;
+ if (!luaLcdAllowed)
+ return 0;
unsigned int index = luaL_checkunsigned(L, 1) >> 16;
unsigned int color = luaL_checkunsigned(L, 2);
lcdColorTable[index] = color;
return 0;
}
+/*luadoc
+@function lcd.getColor(area)
+
+Get the color for specific area : see lcd.setColor for area list
+
+@notice Only available on Colorlcd radios
+
+@status current Introduced in 2.3.11
+*/
+
+static int luaLcdGetColor(lua_State *L)
+{
+ if (!luaLcdAllowed)
+ return 0;
+
+ unsigned int index = luaL_checkunsigned(L, 1) >> 16;
+ lua_pushunsigned(L, lcdColorTable[index]);
+ return 1;
+}
+
/*luadoc
@function lcd.RGB(r, g, b)
@@ -857,13 +897,14 @@ Returns a 5/6/5 rgb color code, that can be used with lcd.setColor
@retval number (integer) rgb color expressed in 5/6/5 format
-@notice Only available on Horus
+@notice Only available on Colorlcd radios
@status current Introduced in 2.2.0
*/
static int luaRGB(lua_State *L)
{
- if (!luaLcdAllowed) return 0;
+ if (!luaLcdAllowed)
+ return 0;
int r = luaL_checkinteger(L, 1);
int g = luaL_checkinteger(L, 2);
int b = luaL_checkinteger(L, 3);
@@ -890,6 +931,7 @@ const luaL_Reg lcdLib[] = {
#if defined(COLORLCD)
{ "drawBitmap", luaLcdDrawBitmap },
{ "setColor", luaLcdSetColor },
+ { "getColor", luaLcdGetColor },
{ "RGB", luaRGB },
#else
{ "getLastPos", luaLcdGetLastPos },
diff --git a/radio/src/lua/api_model.cpp b/radio/src/lua/api_model.cpp
index 8eea9d5ec..f19246e62 100644
--- a/radio/src/lua/api_model.cpp
+++ b/radio/src/lua/api_model.cpp
@@ -135,7 +135,7 @@ static int luaModelGetModule(lua_State *L)
lua_pushtableinteger(L, "subType", module.subType);
lua_pushtableinteger(L, "modelId", g_model.header.modelId[idx]);
lua_pushtableinteger(L, "firstChannel", module.channelsStart);
- lua_pushtableinteger(L, "channelsCount", module.channelsCount + 8);
+ lua_pushtableinteger(L, "channelsCount", module.getChannelsCount());
lua_pushtableinteger(L, "Type", module.type);
#if defined(MULTIMODULE)
if (module.type == MODULE_TYPE_MULTIMODULE) {
@@ -363,6 +363,136 @@ static int luaModelGetInputsCount(lua_State *L)
return 1;
}
+/*luadoc
+@function model.deleteFlightModes()
+
+Clear all flightModes
+
+@status current Introduced in 2.3.10
+*/
+static int luaModelDeleteFlightModes(lua_State *L)
+{
+ memset(g_model.flightModeData, 0, sizeof(g_model.flightModeData));
+ return 0;
+}
+
+/*luadoc
+@function model.getFlightMode(index)
+
+@param index (unsigned number) flight mode number (use 0 for FM0)
+
+Return input data for given input and line number
+
+@retval nil requested input or line does not exist
+
+@retval table input data:
+ * `name` (string) input line name
+ * `switch` (number) input switch index
+ * `fadeIn` (number) fade in value (in 0.1s)
+ * `fadeOut` (number) fade out value (in 0.1s)
+ * `trimsValues` (table) table of trim values:
+ * `key` is trim number (zero based)
+ * `value` is trim value
+ * `trimsModes` (table) table of trim mode:
+ * `key` is trim number (zero based)
+ * `value` is trim mode
+
+@status current Introduced in 2.3.10
+*/
+static int luaModelGetFlightMode(lua_State * L)
+{
+ unsigned int idx = luaL_checkunsigned(L, 1);
+ if (idx < MAX_FLIGHT_MODES) {
+ FlightModeData * fm = flightModeAddress(idx);
+ lua_newtable(L);
+ lua_pushtablezstring(L, "name", fm->name);
+ lua_pushtableinteger(L, "switch", fm->swtch);
+ lua_pushtableinteger(L, "fadeIn", fm->fadeIn);
+ lua_pushtableinteger(L, "fadeOut", fm->fadeOut);
+ lua_pushstring(L, "trimsValues");
+ lua_newtable(L);
+ for (uint8_t i = 0; i < NUM_TRIMS; i++) {
+ lua_pushinteger(L, i);
+ lua_pushinteger(L, fm->trim[i].value);
+ lua_settable(L, -3);
+ }
+ lua_settable(L, -3);
+ lua_pushstring(L, "trimsModes");
+ lua_newtable(L);
+ for (uint8_t i = 0; i < NUM_TRIMS; i++) {
+ lua_pushinteger(L, i);
+ lua_pushinteger(L, fm->trim[i].mode);
+ lua_settable(L, -3);
+ }
+ lua_settable(L, -3);
+ }
+ else {
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+/*luadoc
+@function model.setFlightMode(index, params)
+
+Set Flight mode parameters
+
+@param index (unsigned number) flight mode number (use 0 for FM0)
+
+@param params see model.getFlightMode return format for table format.
+
+@status current Introduced in 2.3.10
+*/
+static int luaModelSetFlightMode(lua_State * L)
+{
+ unsigned int flightMode = luaL_checkunsigned(L, 1);
+
+ if (flightMode >= MAX_FLIGHT_MODES) {
+ lua_pushinteger(L, 2);
+ return 1;
+ }
+ FlightModeData * fm = flightModeAddress(flightMode);
+ luaL_checktype(L, -1, LUA_TTABLE);
+ for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) {
+ luaL_checktype(L, -2, LUA_TSTRING); // key is string
+ const char * key = luaL_checkstring(L, -2);
+ if (!strcmp(key, "name")) {
+ const char * name = luaL_checkstring(L, -1);
+ str2zchar(fm->name, name, sizeof(fm->name));
+ }
+ else if (!strcmp(key, "switch")) {
+ fm->swtch = luaL_checkinteger(L, -1);
+ }
+ else if (!strcmp(key, "fadeIn")) {
+ fm->fadeIn = luaL_checkinteger(L, -1);
+ }
+ else if (!strcmp(key, "fadeOut")) {
+ fm->fadeOut = luaL_checkinteger(L, -1);
+ }
+ else if (!strcmp(key, "trimsValues")) {
+ luaL_checktype(L, -1, LUA_TTABLE);
+ uint8_t idx = 0;
+ for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1), idx++) {
+ int16_t val = luaL_checkinteger(L, -1);
+ if (idx < NUM_TRIMS)
+ fm->trim[idx].value = (val & 0x3FF);
+ }
+ }
+ else if (!strcmp(key, "trimsModes")) {
+ luaL_checktype(L, -1, LUA_TTABLE);
+ uint8_t idx = 0;
+ for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1), idx++) {
+ uint16_t val = luaL_checkinteger(L, -1);
+ if (idx < NUM_TRIMS)
+ fm->trim[idx].mode = (val & 0x1F);
+ }
+ }
+ }
+ storageDirty(EE_MODEL);
+ lua_pushinteger(L, 0);
+ return 1;
+}
+
/*luadoc
@function model.getInput(input, line)
@@ -376,6 +506,7 @@ Return input data for given input and line number
@retval table input data:
* `name` (string) input line name
+ * `inputName` (string) input input name
* `source` (number) input source index
* `weight` (number) input weight
* `offset` (number) input offset
@@ -383,8 +514,9 @@ Return input data for given input and line number
* `curveType` (number) curve type (function, expo, custom curve)
* `curveValue` (number) curve index
* `carryTrim` (boolean) input trims applied
+ * 'flightModes' (number) bit-mask of active flight modes
-@status current Introduced in 2.0.0, curveType/curveValue/carryTrim added in 2.3
+@status current Introduced in 2.0.0, curveType/curveValue/carryTrim added in 2.3, inputName added 2.3.10, flighmode reworked in 2.3.11
*/
static int luaModelGetInput(lua_State *L)
{
@@ -396,6 +528,7 @@ static int luaModelGetInput(lua_State *L)
ExpoData * expo = expoAddress(first+idx);
lua_newtable(L);
lua_pushtablezstring(L, "name", expo->name);
+ lua_pushtablezstring(L, "inputName", g_model.inputNames[chn]);
lua_pushtableinteger(L, "source", expo->srcRaw);
lua_pushtableinteger(L, "weight", expo->weight);
lua_pushtableinteger(L, "offset", expo->offset);
@@ -403,6 +536,7 @@ static int luaModelGetInput(lua_State *L)
lua_pushtableinteger(L, "curveType", expo->curve.type);
lua_pushtableinteger(L, "curveValue", expo->curve.value);
lua_pushtableinteger(L, "carryTrim", expo->carryTrim);
+ lua_pushtableinteger(L, "flightModes", expo->flightModes);
}
else {
lua_pushnil(L);
@@ -421,7 +555,7 @@ Insert an Input at specified line
@param value (table) input data, see model.getInput()
-@status current Introduced in 2.0.0, curveType/curveValue/carryTrim added in 2.3
+@status current Introduced in 2.0.0, curveType/curveValue/carryTrim added in 2.3, inputName added 2.3.10
*/
static int luaModelInsertInput(lua_State *L)
{
@@ -444,6 +578,10 @@ static int luaModelInsertInput(lua_State *L)
const char * name = luaL_checkstring(L, -1);
str2zchar(expo->name, name, sizeof(expo->name));
}
+ else if (!strcmp(key, "inputName")) {
+ const char * name = luaL_checkstring(L, -1);
+ str2zchar(g_model.inputNames[chn], name, LEN_INPUT_NAME);
+ }
else if (!strcmp(key, "source")) {
expo->srcRaw = luaL_checkinteger(L, -1);
}
@@ -465,6 +603,9 @@ static int luaModelInsertInput(lua_State *L)
else if (!strcmp(key, "carryTrim")) {
expo->carryTrim = lua_toboolean(L, -1);
}
+ else if (!strcmp(key, "flightModes")) {
+ expo->flightModes = luaL_checkinteger(L, -1);
+ }
}
}
@@ -997,7 +1138,7 @@ static int luaModelSetCurve(lua_State *L)
bool isX = !strcmp(key, "x");
for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) {
- int idx = luaL_checkinteger(L, -2)-1;
+ int idx = luaL_checkinteger(L, -2) - 1;
if (idx < 0 || idx > MAX_POINTS_PER_CURVE) {
lua_pushinteger(L, 4);
return 1;
@@ -1373,16 +1514,16 @@ Get Telemetry Sensor parameters
@param sensor (unsigned number) sensor number (use 0 for sensor 1)
-@retval nil requested logical switch does not exist
+@retval nil requested sensor does not exist
-@retval table logical switch data:
- * `func` (number) function index
- * `v1` (number) V1 value (index)
- * `v2` (number) V2 value (index or value)
- * `v3` (number) V3 value (index or value)
- * `and` (number) AND switch index
- * `delay` (number) delay (time in 1/10 s)
- * `duration` (number) duration (time in 1/10 s)
+@retval table with sensor data:
+ * `type` (number) 0 = custom, 1 = calculated
+ * `name` (string) Name
+ * `unit` (number) See list of units in the appendix of the OpenTX Lua Reference Guide
+ * `prec` (number) Number of decimals
+ * `id` (number) Only custom sensors
+ * `instance` (number) Only custom sensors
+ * `formula` (number) Only calculated sensors. 0 = Add etc. see list of formula choices in Companion popup
@status current Introduced in 2.3.0
*/
@@ -1410,6 +1551,28 @@ static int luaModelGetSensor(lua_State *L)
return 1;
}
+/*luadoc
+@function model.resetSensor(sensor)
+
+Reset Telemetry Sensor parameters
+
+@param sensor (unsigned number) sensor number (use 0 for sensor 1)
+
+@retval nil
+
+@status current Introduced in 2.3.11
+*/
+static int luaModelResetSensor(lua_State *L)
+{
+ unsigned int idx = luaL_checkunsigned(L, 1);
+ if (idx < MAX_TELEMETRY_SENSORS) {
+ telemetryItems[idx].clear();
+ }
+
+ lua_pushnil(L);
+ return 1;
+}
+
const luaL_Reg modelLib[] = {
{ "getInfo", luaModelGetInfo },
{ "setInfo", luaModelSetInfo },
@@ -1418,6 +1581,9 @@ const luaL_Reg modelLib[] = {
{ "getTimer", luaModelGetTimer },
{ "setTimer", luaModelSetTimer },
{ "resetTimer", luaModelResetTimer },
+ { "deleteFlightModes", luaModelDeleteFlightModes },
+ { "getFlightMode", luaModelGetFlightMode },
+ { "setFlightMode", luaModelSetFlightMode },
{ "getInputsCount", luaModelGetInputsCount },
{ "getInput", luaModelGetInput },
{ "insertInput", luaModelInsertInput },
@@ -1440,5 +1606,6 @@ const luaL_Reg modelLib[] = {
{ "getGlobalVariable", luaModelGetGlobalVariable },
{ "setGlobalVariable", luaModelSetGlobalVariable },
{ "getSensor", luaModelGetSensor },
+ { "resetSensor", luaModelResetSensor },
{ NULL, NULL } /* sentinel */
};
diff --git a/radio/src/lua/interface.cpp b/radio/src/lua/interface.cpp
index a0cef2c1d..81ac4472a 100644
--- a/radio/src/lua/interface.cpp
+++ b/radio/src/lua/interface.cpp
@@ -745,11 +745,23 @@ void displayLuaError(const char * title)
if (lua_warning_info[0]) {
char * split = strstr(lua_warning_info, ": ");
if (split) {
- lcdDrawSizedText(WARNING_LINE_X, WARNING_LINE_Y+FH+3, lua_warning_info, split-lua_warning_info, SMLSIZE);
- lcdDrawSizedText(WARNING_LINE_X, WARNING_LINE_Y+2*FH+2, split+2, lua_warning_info+LUA_WARNING_INFO_LEN-split, SMLSIZE);
+#if LCD_W == 128
+ if (strlen(split + 2) <= 20) {
+ lcdDrawSizedText(WARNING_LINE_X, WARNING_LINE_Y + FH + 3, lua_warning_info, split - lua_warning_info, SMLSIZE);
+ lcdDrawSizedText(WARNING_LINE_X, WARNING_LINE_Y + 2 * FH + 2, split + 2, strlen(split + 2), SMLSIZE);
+ }
+ else {
+ lcdDrawSizedText(WARNING_LINE_X, WARNING_LINE_Y + FH, lua_warning_info, split - lua_warning_info, SMLSIZE);
+ lcdDrawSizedText(WARNING_LINE_X, WARNING_LINE_Y + 2 * FH, split + 2, 20, SMLSIZE);
+ lcdDrawSizedText(WARNING_LINE_X, WARNING_LINE_Y + 3 * FH, split + 22, strlen(split + 22), SMLSIZE);
+ }
+#else
+ lcdDrawSizedText(WARNING_LINE_X, WARNING_LINE_Y + FH + 3, lua_warning_info, split - lua_warning_info, SMLSIZE);
+ lcdDrawSizedText(WARNING_LINE_X, WARNING_LINE_Y + 2 * FH + 2, split + 2, lua_warning_info + LUA_WARNING_INFO_LEN - split, SMLSIZE);
+#endif
}
else {
- lcdDrawSizedText(WARNING_LINE_X, WARNING_LINE_Y+FH+3, lua_warning_info, 40, SMLSIZE);
+ lcdDrawSizedText(WARNING_LINE_X, WARNING_LINE_Y + FH + 3, lua_warning_info, 40, SMLSIZE);
}
}
}
@@ -787,7 +799,11 @@ void luaError(lua_State * L, uint8_t error, bool acknowledge)
#if defined(SIMU)
if (!strncmp(msg, ".", 2)) msg += 1;
#endif
+#if LCD_W == 128
+ msg = strrchr(msg, '/') + 1;
+#else
if (!strncmp(msg, "/SCRIPTS/", 9)) msg += 9;
+#endif
strncpy(lua_warning_info, msg, LUA_WARNING_INFO_LEN);
lua_warning_info[LUA_WARNING_INFO_LEN] = '\0';
}
diff --git a/radio/src/lua/widgets.cpp b/radio/src/lua/widgets.cpp
index 4ab6b967e..1b04e9b7b 100644
--- a/radio/src/lua/widgets.cpp
+++ b/radio/src/lua/widgets.cpp
@@ -253,23 +253,23 @@ class LuaWidget: public Widget
LuaWidget(const WidgetFactory * factory, const Zone & zone, Widget::PersistentData * persistentData, int widgetData):
Widget(factory, zone, persistentData),
widgetData(widgetData),
- errorMessage(0)
+ errorMessage(nullptr)
{
}
- virtual ~LuaWidget()
+ ~LuaWidget() override
{
luaL_unref(lsWidgets, LUA_REGISTRYINDEX, widgetData);
- if (errorMessage) free(errorMessage);
+ free(errorMessage);
}
- virtual void update();
+ void update() override;
void refresh() override;
- virtual void background();
+ void background() override;
- virtual const char * getErrorMessage() const;
+ const char * getErrorMessage() const override;
protected:
int widgetData;
@@ -300,7 +300,7 @@ class LuaWidgetFactory: public WidgetFactory
{
}
- virtual Widget * create(const Zone & zone, Widget::PersistentData * persistentData, bool init=true) const
+ Widget * create(const Zone & zone, Widget::PersistentData * persistentData, bool init=true) const override
{
if (lsWidgets == 0) return 0;
if (init) {
diff --git a/radio/src/main.cpp b/radio/src/main.cpp
index 1490fb989..8ff9cd736 100644
--- a/radio/src/main.cpp
+++ b/radio/src/main.cpp
@@ -22,6 +22,8 @@
uint8_t currentSpeakerVolume = 255;
uint8_t requiredSpeakerVolume = 255;
+uint8_t currentBacklightBright = 0;
+uint8_t requiredBacklightBright = 0;
uint8_t mainRequestFlags = 0;
#if defined(STM32)
@@ -529,6 +531,10 @@ void perMain()
}
#endif
+#if defined(KEYS_GPIO_REG_BIND) && defined(BIND_KEY)
+ bindButtonHandler(evt);
+#endif
+
#if defined(GUI)
DEBUG_TIMER_START(debugTimerGuiMain);
guiMain(evt);
diff --git a/radio/src/mixer.cpp b/radio/src/mixer.cpp
index 0e75f94d7..4992e608f 100644
--- a/radio/src/mixer.cpp
+++ b/radio/src/mixer.cpp
@@ -527,26 +527,37 @@ int getStickTrimValue(int stick, int stickValue)
return 0;
int trim = trims[stick];
- if (stick == THR_STICK) {
- if (g_model.thrTrim) {
- int trimMin = g_model.extendedTrims ? 2*TRIM_EXTENDED_MIN : 2*TRIM_MIN;
- trim = ((g_model.throttleReversed ? (trim+trimMin) : (trim-trimMin)) * (RESX-stickValue)) >> (RESX_SHIFT+1);
- }
- if (g_model.throttleReversed) {
+ uint8_t thrTrimSw = g_model.getThrottleStickTrimSource() - MIXSRC_FIRST_TRIM;
+ if (stick == thrTrimSw) {
+ if (g_model.throttleReversed)
trim = -trim;
+ if (g_model.thrTrim) {
+ trim = (g_model.extendedTrims) ? 2*TRIM_EXTENDED_MAX + trim : 2*TRIM_MAX + trim;
+ trim = trim * (1024 - stickValue) / (2*RESX);
}
}
return trim;
}
-int getSourceTrimValue(int source, int stickValue=0)
+int getSourceTrimOrigin(int source)
{
if (source >= MIXSRC_Rud && source <= MIXSRC_Ail)
- return getStickTrimValue(source - MIXSRC_Rud, stickValue);
+ return source - MIXSRC_Rud;
else if (source >= MIXSRC_FIRST_INPUT && source <= MIXSRC_LAST_INPUT)
- return getStickTrimValue(virtualInputsTrims[source - MIXSRC_FIRST_INPUT], stickValue);
+ return virtualInputsTrims[source - MIXSRC_FIRST_INPUT];
else
+ return -1;
+}
+
+int getSourceTrimValue(int source, int stickValue=0)
+{
+ auto origin = getSourceTrimOrigin(source);
+ if (origin >= 0) {
+ return getStickTrimValue(origin, stickValue);
+ }
+ else {
return 0;
+ }
}
uint8_t mixerCurrentFlightMode;
@@ -741,13 +752,16 @@ void evalFlightModeMixes(uint8_t mode, uint8_t tick10ms)
}
if (applyOffsetAndCurve) {
-
- //========== TRIMS ================
- if (!(mode & e_perout_mode_notrims)) {
- if (md->carryTrim == 0) {
- v += getSourceTrimValue(md->srcRaw, v);
+ bool applyTrims = !(mode & e_perout_mode_notrims);
+ if (!applyTrims && g_model.thrTrim) {
+ auto origin = getSourceTrimOrigin(md->srcRaw);
+ if (origin == g_model.getThrottleStickTrimSource() - MIXSRC_FIRST_TRIM) {
+ applyTrims = true;
}
}
+ if (applyTrims && md->carryTrim == 0) {
+ v += getSourceTrimValue(md->srcRaw, v);
+ }
}
int32_t weight = GET_GVAR_PREC1(MD_WEIGHT(md), GV_RANGELARGE_NEG, GV_RANGELARGE, mixerCurrentFlightMode);
@@ -964,6 +978,7 @@ void evalMixes(uint8_t tick10ms)
// must be done before limits because of the applyLimit function: it checks for safety switches which would be not initialized otherwise
if (tick10ms) {
requiredSpeakerVolume = g_eeGeneral.speakerVolume + VOLUME_LEVEL_DEF;
+ requiredBacklightBright = g_eeGeneral.backlightBright;
if (!g_model.noGlobalFunctions) {
evalFunctions(g_eeGeneral.customFn, globalFunctionsContext);
diff --git a/radio/src/mixer_scheduler.cpp b/radio/src/mixer_scheduler.cpp
new file mode 100644
index 000000000..dcf95383b
--- /dev/null
+++ b/radio/src/mixer_scheduler.cpp
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+#include "opentx.h"
+#include "mixer_scheduler.h"
+
+#if !defined(SIMU)
+
+// Global trigger flag
+RTOS_FLAG_HANDLE mixerFlag;
+
+// Mixer schedule
+struct MixerSchedule {
+
+ // period in us
+ volatile uint16_t period;
+};
+
+static MixerSchedule mixerSchedules[NUM_MODULES];
+
+uint16_t getMixerSchedulerPeriod()
+{
+#if defined(HARDWARE_INTERNAL_MODULE)
+ if (mixerSchedules[INTERNAL_MODULE].period) {
+ return mixerSchedules[INTERNAL_MODULE].period;
+ }
+#endif
+#if defined(HARDWARE_EXTERNAL_MODULE)
+ if (mixerSchedules[EXTERNAL_MODULE].period) {
+ return mixerSchedules[EXTERNAL_MODULE].period;
+ }
+#endif
+ return MIXER_SCHEDULER_DEFAULT_PERIOD_US;
+}
+
+void mixerSchedulerInit()
+{
+ RTOS_CREATE_FLAG(mixerFlag);
+ memset(mixerSchedules, 0, sizeof(mixerSchedules));
+}
+
+void mixerSchedulerSetPeriod(uint8_t moduleIdx, uint16_t periodUs)
+{
+ if (periodUs > 0 && periodUs < MIN_REFRESH_RATE) {
+ periodUs = MIN_REFRESH_RATE;
+ }
+ else if (periodUs > 0 && periodUs > MAX_REFRESH_RATE) {
+ periodUs = MAX_REFRESH_RATE;
+ }
+
+ mixerSchedules[moduleIdx].period = periodUs;
+}
+
+bool mixerSchedulerWaitForTrigger(uint8_t timeoutMs)
+{
+ RTOS_CLEAR_FLAG(mixerFlag);
+ return RTOS_WAIT_FLAG(mixerFlag, timeoutMs);
+}
+
+void mixerSchedulerISRTrigger()
+{
+ RTOS_ISR_SET_FLAG(mixerFlag);
+}
+
+#endif
diff --git a/radio/src/mixer_scheduler.h b/radio/src/mixer_scheduler.h
new file mode 100644
index 000000000..601f3fcd7
--- /dev/null
+++ b/radio/src/mixer_scheduler.h
@@ -0,0 +1,84 @@
+/*
+ * 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 _MIXER_SCHEDULER_H_
+#define _MIXER_SCHEDULER_H_
+
+#define MIXER_SCHEDULER_DEFAULT_PERIOD_US 4000u // 4ms
+
+#define MIN_REFRESH_RATE 1750 /* us */
+#define MAX_REFRESH_RATE 25000 /* us */
+
+#if !defined(SIMU)
+
+// Call once to initialize the mixer scheduler
+void mixerSchedulerInit();
+
+// Configure and start the scheduler timer
+void mixerSchedulerStart();
+
+// Stop the scheduler timer
+void mixerSchedulerStop();
+
+// Set the timer counter to 0
+void mixerSchedulerResetTimer();
+
+// Set the scheduling period for a given module
+void mixerSchedulerSetPeriod(uint8_t moduleIdx, uint16_t periodUs);
+
+// Wait for the scheduler timer to trigger
+// returns true if timeout, false otherwise
+bool mixerSchedulerWaitForTrigger(uint8_t timeoutMs);
+
+// Enable the timer trigger
+void mixerSchedulerEnableTrigger();
+
+// Disable the timer trigger
+void mixerSchedulerDisableTrigger();
+
+// Fetch the current scheduling period
+uint16_t getMixerSchedulerPeriod();
+
+// Trigger mixer from an ISR
+void mixerSchedulerISRTrigger();
+
+#else
+
+#define mixerSchedulerInit()
+#define mixerSchedulerStart()
+#define mixerSchedulerStop()
+#define mixerSchedulerResetTimer()
+#define mixerSchedulerSetPeriod(m,p)
+
+static inline bool mixerSchedulerWaitForTrigger(uint8_t timeout)
+{
+ simuSleep(timeout);
+ return false;
+}
+
+#define mixerSchedulerEnableTrigger()
+#define mixerSchedulerDisableTrigger()
+
+#define getMixerSchedulerPeriod() (MIXER_SCHEDULER_DEFAULT_PERIOD_US)
+#define mixerSchedulerISRTrigger()
+
+#endif
+
+#endif
diff --git a/radio/src/myeeprom.h b/radio/src/myeeprom.h
index 952e94770..304012a0c 100644
--- a/radio/src/myeeprom.h
+++ b/radio/src/myeeprom.h
@@ -57,7 +57,7 @@
#define IS_HAPTIC_FUNC(func) (0)
#endif
-#define HAS_ENABLE_PARAM(func) ((func) < FUNC_FIRST_WITHOUT_ENABLE)
+#define HAS_ENABLE_PARAM(func) ((func) < FUNC_FIRST_WITHOUT_ENABLE || (func == FUNC_BACKLIGHT))
#define HAS_REPEAT_PARAM(func) (IS_PLAY_FUNC(func) || IS_HAPTIC_FUNC(func))
#define CFN_EMPTY(p) (!(p)->swtch)
diff --git a/radio/src/opentx.cpp b/radio/src/opentx.cpp
index 77bb1b894..68e6eb3bb 100644
--- a/radio/src/opentx.cpp
+++ b/radio/src/opentx.cpp
@@ -21,6 +21,10 @@
#include
#include "opentx.h"
+#if defined(PCBSKY9X)
+#include "audio_driver.h"
+#endif
+
RadioData g_eeGeneral;
ModelData g_model;
@@ -253,7 +257,7 @@ void memswap(void * a, void * b, uint8_t size)
void setDefaultOwnerId()
{
for (uint8_t i = 0; i < PXX2_LEN_REGISTRATION_ID; i++) {
- g_eeGeneral.ownerRegistrationID[i] = (cpu_uid[1 + i] & 0x3f) - 26;
+ g_eeGeneral.ownerRegistrationID[i] = (((uint8_t *)cpu_uid)[4 + i] & 0x3fu) - 26;
}
}
#endif
@@ -266,7 +270,9 @@ void generalDefault()
#if defined(PCBHORUS)
g_eeGeneral.blOffBright = 20;
-#else
+#endif
+
+#if defined(LCD_CONTRAST_DEFAULT)
g_eeGeneral.contrast = LCD_CONTRAST_DEFAULT;
#endif
@@ -328,6 +334,14 @@ void generalDefault()
setDefaultOwnerId();
#endif
+#if defined(RADIOMASTER_RTF_RELEASE)
+ // Those settings are for headless radio
+ g_eeGeneral.USBMode = USB_JOYSTICK_MODE;
+ g_eeGeneral.disableRtcWarning = 1;
+ g_eeGeneral.splashMode = 3; // Disable splash
+ g_eeGeneral.pwrOnSpeed = 1; // 1 second
+#endif
+
g_eeGeneral.chkSum = 0xFFFF;
}
@@ -517,6 +531,15 @@ void modelDefault(uint8_t id)
g_model.switchWarningState |= (1 << (3*i));
}
#endif
+
+#if defined(RADIOMASTER_RTF_RELEASE)
+ // Those settings are for headless radio
+ g_model.trainerData.mode = TRAINER_MODE_SLAVE;
+ g_model.moduleData[INTERNAL_MODULE].type = MODULE_TYPE_MULTIMODULE;
+ g_model.moduleData[INTERNAL_MODULE].setMultiProtocol(MODULE_SUBTYPE_MULTI_FRSKY);
+ g_model.moduleData[INTERNAL_MODULE].subType = MM_RF_FRSKY_SUBTYPE_D8;
+ g_model.moduleData[INTERNAL_MODULE].failsafeMode = FAILSAFE_NOPULSES;
+#endif
}
bool isInputRecursive(int index)
@@ -534,6 +557,8 @@ bool isInputRecursive(int index)
}
#if defined(AUTOSOURCE)
+constexpr int MULTIPOS_STEP_SIZE = (2 * RESX) / XPOTS_MULTIPOS_COUNT;
+
int8_t getMovedSource(GET_MOVED_SOURCE_PARAMS)
{
int8_t result = 0;
@@ -542,7 +567,7 @@ int8_t getMovedSource(GET_MOVED_SOURCE_PARAMS)
static int16_t inputsStates[MAX_INPUTS];
if (min <= MIXSRC_FIRST_INPUT) {
for (uint8_t i=0; i 512) {
+ if (abs(anas[i] - inputsStates[i]) > MULTIPOS_STEP_SIZE) {
if (!isInputRecursive(i)) {
result = MIXSRC_FIRST_INPUT+i;
break;
@@ -554,7 +579,7 @@ int8_t getMovedSource(GET_MOVED_SOURCE_PARAMS)
static int16_t sourcesStates[NUM_STICKS+NUM_POTS+NUM_SLIDERS+NUM_MOUSE_ANALOGS];
if (result == 0) {
for (uint8_t i=0; i 512) {
+ if (abs(calibratedAnalogs[i] - sourcesStates[i]) > MULTIPOS_STEP_SIZE) {
result = MIXSRC_Rud+i;
break;
}
@@ -689,12 +714,27 @@ void checkBacklight()
}
}
- bool backlightOn = (g_eeGeneral.backlightMode == e_backlight_mode_on || (g_eeGeneral.backlightMode != e_backlight_mode_off && lightOffCounter) || isFunctionActive(FUNCTION_BACKLIGHT));
- if (flashCounter) backlightOn = !backlightOn;
- if (backlightOn)
+ if (requiredBacklightBright == BACKLIGHT_FORCED_ON) {
+ currentBacklightBright = g_eeGeneral.backlightBright;
BACKLIGHT_ENABLE();
- else
- BACKLIGHT_DISABLE();
+ }
+ else {
+ bool backlightOn = ((g_eeGeneral.backlightMode == e_backlight_mode_on) ||
+ (g_eeGeneral.backlightMode != e_backlight_mode_off && lightOffCounter) ||
+ (g_eeGeneral.backlightMode == e_backlight_mode_off && isFunctionActive(FUNCTION_BACKLIGHT)));
+
+ if (flashCounter) {
+ backlightOn = !backlightOn;
+ }
+
+ if (backlightOn) {
+ currentBacklightBright = requiredBacklightBright;
+ BACKLIGHT_ENABLE();
+ }
+ else {
+ BACKLIGHT_DISABLE();
+ }
+ }
}
}
@@ -896,7 +936,7 @@ void checkAll()
checkFailsafe();
checkRSSIAlarmsDisabled();
-#if defined(SDCARD)
+#if defined(SDCARD) && !defined(RADIOMASTER_RTF_RELEASE)
checkSDVersion();
#endif
@@ -1098,7 +1138,7 @@ void checkTrims()
else {
phase = getTrimFlightMode(mixerCurrentFlightMode, idx);
before = getTrimValue(phase, idx);
- thro = (idx==THR_STICK && g_model.thrTrim);
+ thro = (idx == (g_model.getThrottleStickTrimSource() - MIXSRC_FIRST_TRIM) && g_model.thrTrim);
}
#else
phase = getTrimFlightMode(mixerCurrentFlightMode, idx);
@@ -1405,6 +1445,19 @@ void doMixerCalculations()
DEBUG_TIMER_START(debugTimerEvalMixes);
evalMixes(tick10ms);
DEBUG_TIMER_STOP(debugTimerEvalMixes);
+}
+
+void doMixerPeriodicUpdates()
+{
+ static tmr10ms_t lastTMR = 0;
+
+ tmr10ms_t tmr10ms = get_tmr10ms();
+
+ uint8_t tick10ms = (tmr10ms >= lastTMR ? tmr10ms - lastTMR : 1);
+ // handle tick10ms overrun
+ // correct overflow handling costs a lot of code; happens only each 11 min;
+ // therefore forget the exact calculation and use only 1 instead; good compromise
+ lastTMR = tmr10ms;
DEBUG_TIMER_START(debugTimerMixes10ms);
if (tick10ms) {
@@ -1653,28 +1706,40 @@ void opentxResume()
void instantTrim()
{
- int16_t anas_0[MAX_INPUTS];
+ int16_t anas_0[MAX_INPUTS];
evalInputs(e_perout_mode_notrainer | e_perout_mode_nosticks);
memcpy(anas_0, anas, sizeof(anas_0));
evalInputs(e_perout_mode_notrainer);
- for (uint8_t stick=0; sticksrcRaw-MIXSRC_Rud == stick) {
- delta = anas[ed->chn] - anas_0[ed->chn];
- break;
+ uint8_t trimFlightMode = getTrimFlightMode(mixerCurrentFlightMode, stick);
+ for (uint8_t i = 0; i < MAX_EXPOS; i++) {
+ ExpoData * expo = expoAddress(i);
+ if (!EXPO_VALID(expo))
+ break; // end of list
+ if (stick == expo->srcRaw - MIXSRC_FIRST_STICK) {
+ if (expo->carryTrim < 0) {
+ // only default trims will be taken into account
+ addTrim = false;
+ break;
+ }
+ auto newDelta = anas[expo->chn] - anas_0[expo->chn];
+ if (addTrim && delta != newDelta) {
+ // avoid 2 different delta values
+ addTrim = false;
+ break;
+ }
+ addTrim = true;
+ delta = newDelta;
}
}
- if (abs(delta) >= INSTANT_TRIM_MARGIN) {
+ if (addTrim && abs(delta) >= INSTANT_TRIM_MARGIN) {
int16_t trim = limit(TRIM_EXTENDED_MIN, (delta + trims[stick]) / 2, TRIM_EXTENDED_MAX);
- setTrimValue(trim_phase, stick, trim);
+ setTrimValue(trimFlightMode, stick, trim);
}
}
}
@@ -1715,7 +1780,8 @@ void copyTrimsToOffset(uint8_t ch)
int16_t output = applyLimits(ch, chans[ch]) - zero;
int16_t v = g_model.limitData[ch].offset;
- if (g_model.limitData[ch].revert) output = -output;
+ if (g_model.limitData[ch].revert)
+ output = -output;
v += (output * 125) / 128;
g_model.limitData[ch].offset = limit((int16_t)-1000, (int16_t)v, (int16_t)1000); // make sure the offset doesn't go haywire
@@ -1790,23 +1856,27 @@ void moveTrimsToOffsets() // copy state of 3 primary to subtrim
pauseMixerCalculations();
evalFlightModeMixes(e_perout_mode_noinput, 0); // do output loop - zero input sticks and trims
- for (uint8_t i=0; i
#include "definitions.h"
@@ -70,6 +69,12 @@
#define CASE_GYRO(x)
#endif
+#if defined(BACKLIGHT_GPIO)
+#define CASE_BACKLIGHT(x) x,
+#else
+#define CASE_BACKLIGHT(x)
+#endif
+
#if defined(LUA)
#define CASE_LUA(x) x,
#else
@@ -277,6 +282,12 @@ void memswap(void * a, void * b, uint8_t size);
#define IS_MULTIPOS_CALIBRATED(cal) (false)
#endif
+#if NUM_XPOTS > 0
+ #define IS_SWITCH_MULTIPOS(x) (SWSRC_FIRST_MULTIPOS_SWITCH <= (x) && (x) <= SWSRC_LAST_MULTIPOS_SWITCH)
+#else
+ #define IS_SWITCH_MULTIPOS(x) (false)
+#endif
+
#if defined(PWR_BUTTON_PRESS)
#define pwrOffPressed() pwrPressed()
#else
@@ -309,7 +320,7 @@ void memswap(void * a, void * b, uint8_t size);
#define MASK_CFN_TYPE uint64_t // current max = 64 function switches
#define MASK_FUNC_TYPE uint32_t // current max = 32 functions
-typedef struct {
+struct CustomFunctionsContext {
MASK_FUNC_TYPE activeFunctions;
MASK_CFN_TYPE activeSwitches;
tmr10ms_t lastFunctionTime[MAX_SPECIAL_FUNCTIONS];
@@ -323,7 +334,7 @@ typedef struct {
{
memclear(this, sizeof(*this));
}
-} CustomFunctionsContext;
+};
#include "strhelpers.h"
#include "gui.h"
@@ -383,6 +394,8 @@ inline bool SPLASH_NEEDED()
#define ROTENC_HIGHSPEED 50
#define ROTENC_DELAY_MIDSPEED 32
#define ROTENC_DELAY_HIGHSPEED 16
+#elif defined(RADIO_T8)
+ constexpr uint8_t rotencSpeed = 1;
#endif
constexpr uint8_t HEART_TIMER_10MS = 0x01;
@@ -438,6 +451,10 @@ extern uint8_t potsPos[NUM_XPOTS];
bool trimDown(uint8_t idx);
void readKeysAndTrims();
+#if defined(KEYS_GPIO_REG_BIND)
+void bindButtonHandler(event_t event);
+#endif
+
uint16_t evalChkSum();
void alert(const char * title, const char * msg, uint8_t sound);
@@ -484,9 +501,11 @@ extern uint32_t nextMixerTime[NUM_MODULES];
void evalFlightModeMixes(uint8_t mode, uint8_t tick10ms);
void evalMixes(uint8_t tick10ms);
void doMixerCalculations();
+void doMixerPeriodicUpdates();
void scheduleNextMixerCalculation(uint8_t module, uint32_t period_ms);
void checkTrims();
+extern uint8_t currentBacklightBright;
void perMain();
void per10ms();
@@ -538,6 +557,8 @@ bool setTrimValue(uint8_t phase, uint8_t idx, int trim);
#define ROTARY_ENCODER_GRANULARITY (2 << g_eeGeneral.rotarySteps)
#elif defined(RADIO_FAMILY_T16) && !defined(RADIO_T18)
#define ROTARY_ENCODER_GRANULARITY (1)
+#elif defined(RADIO_TX12)
+ #define ROTARY_ENCODER_GRANULARITY (1)
#else
#define ROTARY_ENCODER_GRANULARITY (2)
#endif
@@ -846,12 +867,13 @@ enum FunctionsActive {
FUNCTION_TRAINER_CHANNELS = FUNCTION_TRAINER_STICK1 + NUM_STICKS,
FUNCTION_INSTANT_TRIM,
FUNCTION_VARIO,
- FUNCTION_BACKLIGHT,
#if defined(SDCARD)
FUNCTION_LOGS,
#endif
FUNCTION_BACKGND_MUSIC,
FUNCTION_BACKGND_MUSIC_PAUSE,
+ FUNCTION_BACKLIGHT,
+ FUNCTION_RACING_MODE,
};
#define VARIO_FREQUENCY_ZERO 700/*Hz*/
@@ -996,7 +1018,13 @@ constexpr uint8_t OPENTX_START_NO_CHECKS = 0x04;
#if defined(STATUS_LEDS)
#define LED_ERROR_BEGIN() ledRed()
+#if defined(RADIO_T8)
+ // Because of green backlit logo, green is preferred on this radio
+ #define LED_ERROR_END() ledGreen()
+ #define LED_BIND() ledBlue()
+#else
#define LED_ERROR_END() ledBlue()
+#endif
#else
#define LED_ERROR_BEGIN()
#define LED_ERROR_END()
@@ -1125,6 +1153,15 @@ union ReusableBuffer
uint8_t moduleOFF;
} spectrumAnalyser;
+#if defined(GHOST)
+ struct {
+ GhostMenuData line[GHST_MENU_LINES + 1];
+ uint8_t menuStatus;
+ uint8_t menuAction;
+ uint8_t buttonAction;
+ } ghostMenu;
+#endif
+
struct {
uint32_t freq;
int16_t power;
@@ -1329,4 +1366,3 @@ inline bool isAsteriskDisplayed()
#include "thirdparty/libACCESS/libAccess.h"
#endif
-#endif // _OPENTX_H_
diff --git a/radio/src/options.h b/radio/src/options.h
index b9d2a0075..4f1a1a077 100644
--- a/radio/src/options.h
+++ b/radio/src/options.h
@@ -26,9 +26,15 @@ static const char * const options[] = {
#if defined(AUTOUPDATE)
"autoupdate",
#endif
+#if defined(BLUETOOTH)
+ "bluetooth",
+#endif
#if defined(CROSSFIRE)
"crossfire",
#endif
+#if defined(GHOST)
+ "ghost",
+#endif
#if !defined(MODULE_PROTOCOL_D8)
"eu",
#endif
@@ -41,6 +47,9 @@ static const char * const options[] = {
#if defined(MODULE_PROTOCOL_FLEX)
"flexr9m",
#endif
+#if defined(AFHDS3)
+ "afhds3",
+#endif
#if !defined(GVARS)
"nogvars",
#endif
@@ -85,6 +94,12 @@ static const char * const options[] = {
#endif
#if defined(SHUTDOWN_CONFIRMATION)
"shutdownconfirm",
+#endif
+#if defined(HARDWARE_EXTERNAL_ACCESS_MOD)
+ "externalaccessmod",
+#endif
+#if defined(BIND_KEY)
+ "bindkey",
#endif
nullptr //sentinel
};
diff --git a/radio/src/pulses/afhds3.h b/radio/src/pulses/afhds3.h
index fab057854..5eef56a4b 100644
--- a/radio/src/pulses/afhds3.h
+++ b/radio/src/pulses/afhds3.h
@@ -94,9 +94,6 @@ struct Data
void reset()
{
-#if !(defined(EXTMODULE_USART) && defined(EXTMODULE_TX_INVERT_GPIO))
- total = 0;
-#endif
pulsesSize = 0;
}
#if defined(EXTMODULE_USART) && defined(EXTMODULE_TX_INVERT_GPIO)
@@ -118,7 +115,6 @@ struct Data
return;
}
pulses[pulsesSize++] = v;
- total += v;
}
void sendByte(uint8_t b)
{
@@ -149,14 +145,7 @@ struct Data
//add remaining time of frame
void flush()
{
- uint16_t diff = AFHDS3_FRAME_HALF_US - total;
- pulses[pulsesSize - 1] += diff;
- //ensure 2 ms break
- if (pulses[pulsesSize - 1] < 4000)
- {
- pulses[pulsesSize - 1] = 4050;
- }
- total += diff;
+ pulses[pulsesSize - 1] = 60000;
}
const uint16_t* getData()
diff --git a/radio/src/pulses/crossfire.cpp b/radio/src/pulses/crossfire.cpp
index 5e4ffdb95..cbe4373e4 100644
--- a/radio/src/pulses/crossfire.cpp
+++ b/radio/src/pulses/crossfire.cpp
@@ -20,8 +20,30 @@
#include "opentx.h"
-#define CROSSFIRE_CH_CENTER 0x3E0
#define CROSSFIRE_CH_BITS 11
+#define CROSSFIRE_CENTER 0x3E0
+#if defined(PPM_CENTER_ADJUSTABLE)
+ #define CROSSFIRE_CENTER_CH_OFFSET(ch) ((2 * limitAddress(ch)->ppmCenter) + 1) // + 1 is for rouding
+#else
+ #define CROSSFIRE_CENTER_CH_OFFSET(ch) (0)
+#endif
+
+
+uint8_t createCrossfireModelIDFrame(uint8_t * frame)
+{
+ uint8_t * buf = frame;
+ *buf++ = UART_SYNC; /* device address */
+ *buf++ = 8; /* frame length */
+ *buf++ = COMMAND_ID; /* cmd type */
+ *buf++ = MODULE_ADDRESS; /* Destination Address */
+ *buf++ = RADIO_ADDRESS; /* Origin Address */
+ *buf++ = SUBCOMMAND_CRSF; /* sub command */
+ *buf++ = COMMAND_MODEL_SELECT_ID; /* command of set model/receiver id */
+ *buf++ = g_model.header.modelId[EXTERNAL_MODULE]; /* model ID */
+ *buf++ = crc8_BA(frame + 2, 6);
+ *buf++ = crc8(frame + 2, 7);
+ return buf - frame;
+}
// Range for pulses (channels output) is [-1024:+1024]
uint8_t createCrossfireChannelsFrame(uint8_t * frame, int16_t * pulses)
@@ -34,7 +56,7 @@ uint8_t createCrossfireChannelsFrame(uint8_t * frame, int16_t * pulses)
uint32_t bits = 0;
uint8_t bitsavailable = 0;
for (int i=0; i= 8) {
@@ -60,7 +82,13 @@ void setupPulsesCrossfire()
else
#endif
{
- extmodulePulsesData.crossfire.length = createCrossfireChannelsFrame(pulses, &channelOutputs[g_model.moduleData[EXTERNAL_MODULE].channelsStart]);
+ if (moduleState[EXTERNAL_MODULE].counter == CRSF_FRAME_MODELID) {
+ extmodulePulsesData.crossfire.length = createCrossfireModelIDFrame(pulses);
+ moduleState[EXTERNAL_MODULE].counter = CRSF_FRAME_MODELID_SENT;
+ }
+ else {
+ extmodulePulsesData.crossfire.length = createCrossfireChannelsFrame(pulses, &channelOutputs[g_model.moduleData[EXTERNAL_MODULE].channelsStart]);
+ }
}
}
}
diff --git a/radio/src/pulses/dsm2.cpp b/radio/src/pulses/dsm2.cpp
index 3612f60db..34a10b3d6 100644
--- a/radio/src/pulses/dsm2.cpp
+++ b/radio/src/pulses/dsm2.cpp
@@ -76,7 +76,6 @@ void _send_1(uint8_t v)
*extmodulePulsesData.dsm2.ptr++ = v - 1;
extmodulePulsesData.dsm2.index += 1;
- extmodulePulsesData.dsm2.rest -= v;
}
void sendByteDsm2(uint8_t b) // max 10 changes 0 10 10 10 10 1
@@ -101,9 +100,9 @@ void sendByteDsm2(uint8_t b) // max 10 changes 0 10 10 10 10 1
void putDsm2Flush()
{
if (extmodulePulsesData.dsm2.index & 1)
- *extmodulePulsesData.dsm2.ptr++ = extmodulePulsesData.dsm2.rest;
+ *extmodulePulsesData.dsm2.ptr++ = 60000;
else
- *(extmodulePulsesData.dsm2.ptr - 1) = extmodulePulsesData.dsm2.rest;
+ *(extmodulePulsesData.dsm2.ptr - 1) = 60000;
}
#endif
@@ -119,7 +118,6 @@ void setupPulsesDSM2()
extmodulePulsesData.dsm2.serialBitCount = 0 ;
#else
extmodulePulsesData.dsm2.index = 0;
- extmodulePulsesData.dsm2.rest = DSM2_PERIOD * 2000;
#endif
extmodulePulsesData.dsm2.ptr = extmodulePulsesData.dsm2.pulses;
diff --git a/radio/src/pulses/ghost.cpp b/radio/src/pulses/ghost.cpp
new file mode 100755
index 000000000..df4fa6f69
--- /dev/null
+++ b/radio/src/pulses/ghost.cpp
@@ -0,0 +1,122 @@
+/*
+ * 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.
+ */
+
+#include "opentx.h"
+
+uint8_t createGhostMenuControlFrame(uint8_t * frame, int16_t * pulses)
+{
+ uint8_t * buf = frame;
+#if SPORT_MAX_BAUDRATE < 400000
+ *buf++ = g_eeGeneral.telemetryBaudrate == GHST_TELEMETRY_RATE_400K ? GHST_ADDR_MODULE_SYM : GHST_ADDR_MODULE_ASYM;
+#else
+ *buf++ = GHST_ADDR_MODULE_SYM;
+#endif
+
+ *buf++ = GHST_UL_RC_CHANS_SIZE;
+ uint8_t * crc_start = buf;
+ *buf++ = GHST_UL_MENU_CTRL;
+ *buf++ = reusableBuffer.ghostMenu.buttonAction; // Joystick states, Up, Down, Left, Right, Press
+ *buf++ = reusableBuffer.ghostMenu.menuAction; // menu control, open, close, etc.
+
+ for (uint8_t i = 0; i < 8; i++)
+ *buf++ = 0; // padding to make this the same size as the pulses packet
+
+ *buf++ = crc8(crc_start, GHST_UL_RC_CHANS_SIZE - 1);
+
+ return buf - frame;
+}
+
+// Range for pulses (channels output) is [-1024:+1024]
+uint8_t createGhostChannelsFrame(uint8_t * frame, int16_t * pulses)
+{
+ static uint8_t lastGhostFrameId = GHST_UL_RC_CHANS_HS4_5TO8;
+ uint8_t ghostUpper4Offset = 0;
+
+ switch (lastGhostFrameId) {
+ case GHST_UL_RC_CHANS_HS4_5TO8:
+ ghostUpper4Offset = 0;
+ break;
+ case GHST_UL_RC_CHANS_HS4_9TO12:
+ ghostUpper4Offset = 4;
+ break;
+ case GHST_UL_RC_CHANS_HS4_13TO16:
+ ghostUpper4Offset = 8;
+ break;
+ }
+
+ uint8_t * buf = frame;
+#if SPORT_MAX_BAUDRATE < 400000
+ *buf++ = g_eeGeneral.telemetryBaudrate == GHST_TELEMETRY_RATE_400K ? GHST_ADDR_MODULE_SYM : GHST_ADDR_MODULE_ASYM;
+#else
+ *buf++ = GHST_ADDR_MODULE_SYM;
+#endif
+ *buf++ = GHST_UL_RC_CHANS_SIZE;
+ uint8_t * crc_start = buf;
+ *buf++ = lastGhostFrameId;
+
+ // first 4 high speed, 12 bit channels (11 relevant bits with openTx)
+ uint32_t bits = 0;
+ uint8_t bitsavailable = 0;
+ for (int i = 0; i < 4; i++) {
+ uint32_t value = limit(0, GHST_RC_CTR_VAL_12BIT + (((pulses[i] + 2 * PPM_CH_CENTER(i) - 2 * PPM_CENTER) << 3) / 5), 2 * GHST_RC_CTR_VAL_12BIT);
+ bits |= value << bitsavailable;
+ bitsavailable += GHST_CH_BITS_12;
+ while (bitsavailable >= 8) {
+ *buf++ = bits;
+ bits >>= 8;
+ bitsavailable -= 8;
+ }
+ }
+
+ // second 4 lower speed, 8 bit channels
+ for (int i = 4; i < 8; ++i) {
+ uint8_t channelIndex = i + ghostUpper4Offset;
+ *buf++ = limit(0, GHST_RC_CTR_VAL_8BIT + (((pulses[channelIndex] + 2 * PPM_CH_CENTER(channelIndex) - 2 * PPM_CENTER) >> 1) / 5), 2 * GHST_RC_CTR_VAL_8BIT);
+ }
+
+ *buf++ = crc8(crc_start, GHST_UL_RC_CHANS_SIZE - 1);
+
+ switch (lastGhostFrameId) {
+ case GHST_UL_RC_CHANS_HS4_5TO8:
+ lastGhostFrameId = GHST_UL_RC_CHANS_HS4_9TO12;
+ break;
+ case GHST_UL_RC_CHANS_HS4_9TO12:
+ lastGhostFrameId = GHST_UL_RC_CHANS_HS4_13TO16;
+ break;
+ case GHST_UL_RC_CHANS_HS4_13TO16:
+ lastGhostFrameId = GHST_UL_RC_CHANS_HS4_5TO8;
+ break;
+ }
+
+ return buf - frame;
+}
+
+void setupPulsesGhost()
+{
+ if (telemetryProtocol == PROTOCOL_TELEMETRY_GHOST) {
+ uint8_t * pulses = extmodulePulsesData.ghost.pulses;
+ if (moduleState[EXTERNAL_MODULE].counter == GHST_MENU_CONTROL)
+ extmodulePulsesData.ghost.length = createGhostMenuControlFrame(pulses, &channelOutputs[g_model.moduleData[EXTERNAL_MODULE].channelsStart]);
+ else
+ extmodulePulsesData.ghost.length = createGhostChannelsFrame(pulses, &channelOutputs[g_model.moduleData[EXTERNAL_MODULE].channelsStart]);
+
+ moduleState[EXTERNAL_MODULE].counter = GHST_FRAME_CHANNEL;
+ }
+}
diff --git a/radio/src/pulses/modules_constants.h b/radio/src/pulses/modules_constants.h
index 4f391243a..6fbec157e 100644
--- a/radio/src/pulses/modules_constants.h
+++ b/radio/src/pulses/modules_constants.h
@@ -29,11 +29,11 @@ enum ModuleType {
MODULE_TYPE_DSM2,
MODULE_TYPE_CROSSFIRE,
MODULE_TYPE_MULTIMODULE,
- MODULE_TYPE_R9M_PXX1,
- MODULE_TYPE_R9M_PXX2,
- MODULE_TYPE_R9M_LITE_PXX1,
- MODULE_TYPE_R9M_LITE_PXX2,
- MODULE_TYPE_R9M_LITE_PRO_PXX1, // Doesn't exist
+ MODULE_TYPE_R9M_PXX1, // R9M
+ MODULE_TYPE_R9M_PXX2, // R9M ACCESS
+ MODULE_TYPE_R9M_LITE_PXX1, //R9MLite
+ MODULE_TYPE_R9M_LITE_PXX2, //R9MLP
+ MODULE_TYPE_GHOST, // Replaces MODULE_TYPE_R9M_LITE_PRO_PXX1 which doesn't exist
MODULE_TYPE_R9M_LITE_PRO_PXX2,
MODULE_TYPE_SBUS,
MODULE_TYPE_XJT_LITE_PXX2,
@@ -121,7 +121,7 @@ enum ModuleSubtypeMulti {
MODULE_SUBTYPE_MULTI_MJXQ,
MODULE_SUBTYPE_MULTI_SHENQI,
MODULE_SUBTYPE_MULTI_FY326,
- MODULE_SUBTYPE_MULTI_SFHSS,
+ MODULE_SUBTYPE_MULTI_FUTABA,
MODULE_SUBTYPE_MULTI_J6PRO, //20
MODULE_SUBTYPE_MULTI_FQ777,
MODULE_SUBTYPE_MULTI_ASSAN,
@@ -152,7 +152,7 @@ enum ModuleSubtypeMulti {
MODULE_SUBTYPE_MULTI_REDPINE,
MODULE_SUBTYPE_MULTI_POTENSIC,
MODULE_SUBTYPE_MULTI_ZSX,
- MODULE_SUBTYPE_MULTI_FLYZONE, //50
+ MODULE_SUBTYPE_MULTI_HEIGHT, //50
MODULE_SUBTYPE_MULTI_SCANNER,
MODULE_SUBTYPE_MULTI_FRSKYX_RX,
MODULE_SUBTYPE_MULTI_AFHDS2A_RX,
@@ -172,7 +172,15 @@ enum ModuleSubtypeMulti {
MODULE_SUBTYPE_MULTI_DSM_RX,
MODULE_SUBTYPE_MULTI_JJRC345,
MODULE_SUBTYPE_MULTI_Q90C,
- MODULE_SUBTYPE_MULTI_LAST = MODULE_SUBTYPE_MULTI_Q90C
+ MODULE_SUBTYPE_MULTI_KYOSHO, //70
+ MODULE_SUBTYPE_MULTI_RLINK,
+ MODULE_SUBTYPE_MULTI_ELRS,
+ MODULE_SUBTYPE_MULTI_REALACC,
+ MODULE_SUBTYPE_MULTI_OMP,
+ MODULE_SUBTYPE_MULTI_MLINK, //75
+ MODULE_SUBTYPE_MULTI_WFLY2,
+ MODULE_SUBTYPE_MULTI_E016HV2,
+ MODULE_SUBTYPE_MULTI_LAST = MODULE_SUBTYPE_MULTI_E016HV2
};
#define MODULE_SUBTYPE_MULTI_XN297DP 63-3
@@ -195,6 +203,14 @@ enum MMRFrskySubtypes {
MM_RF_FRSKY_SUBTYPE_D16_CLONED
};
+enum MMRFrskyX2Subtypes {
+ MM_RF_FRSKYX2_SUBTYPE_D16,
+ MM_RF_FRSKYX2_SUBTYPE_D8,
+ MM_RF_FRSKYX2_SUBTYPE_D16_LBT,
+ MM_RF_FRSKYX2_SUBTYPE_D16_LBT_8CH,
+ MM_RF_FRSKYX2_SUBTYPE_D16_CLONED
+};
+
enum ModuleSubtypeDSM2 {
DSM2_PROTO_LP45,
DSM2_PROTO_DSM2,
diff --git a/radio/src/pulses/modules_helpers.h b/radio/src/pulses/modules_helpers.h
index e13eaf2fb..b2bd77de4 100644
--- a/radio/src/pulses/modules_helpers.h
+++ b/radio/src/pulses/modules_helpers.h
@@ -33,6 +33,7 @@
#endif
#define CROSSFIRE_CHANNELS_COUNT 16
+#define GHOST_CHANNELS_COUNT 12
#if defined(MULTIMODULE)
// When using packed, the pointer in here end up not being aligned, which clang and gcc complain about
@@ -41,6 +42,8 @@ struct mm_options_strings {
static const char* options[];
};
+const uint8_t getMaxMultiOptions();
+
struct mm_protocol_definition {
uint8_t protocol;
uint8_t maxSubtype;
@@ -150,6 +153,18 @@ inline bool isModuleCrossfire(uint8_t idx)
}
#endif
+#if defined(GHOST)
+inline bool isModuleGhost(uint8_t idx)
+{
+ return idx == EXTERNAL_MODULE && g_model.moduleData[EXTERNAL_MODULE].type == MODULE_TYPE_GHOST;
+}
+#else
+inline bool isModuleGhost(uint8_t idx)
+{
+ return false;
+}
+#endif
+
#if defined(PCBSKY9X)
inline bool isExtraModule(uint8_t idx)
{
@@ -178,7 +193,7 @@ inline bool isModulePPM(uint8_t moduleIdx)
inline bool isModuleTypeR9MNonAccess(uint8_t type)
{
- return type == MODULE_TYPE_R9M_PXX1 || type == MODULE_TYPE_R9M_LITE_PXX1 || type == MODULE_TYPE_R9M_LITE_PRO_PXX1;
+ return type == MODULE_TYPE_R9M_PXX1 || type == MODULE_TYPE_R9M_LITE_PXX1;
}
inline bool isModuleR9MNonAccess(uint8_t idx)
@@ -218,7 +233,7 @@ inline bool isModuleR9MLiteNonPro(uint8_t idx)
inline bool isModuleTypeR9MLitePro(uint8_t type)
{
- return type == MODULE_TYPE_R9M_LITE_PRO_PXX1 || type == MODULE_TYPE_R9M_LITE_PRO_PXX2;
+ return type == MODULE_TYPE_R9M_LITE_PRO_PXX2;
}
inline bool isModuleTypeR9MLite(uint8_t type)
@@ -271,9 +286,14 @@ inline bool isModulePXX1(uint8_t idx)
return isModuleTypePXX1(g_model.moduleData[idx].type);
}
+inline bool isModuleXJTLite(uint8_t idx)
+{
+ return g_model.moduleData[idx].type == MODULE_TYPE_XJT_LITE_PXX2;
+}
+
inline bool isModulePXX2(uint8_t idx)
{
- return isModuleISRM(idx) || isModuleR9MAccess(idx);
+ return isModuleISRM(idx) || isModuleR9MAccess(idx) || isModuleXJTLite(idx);
}
inline bool isModuleRFAccess(uint8_t idx)
@@ -304,24 +324,6 @@ inline bool isModuleAFHDS3(uint8_t idx)
return g_model.moduleData[idx].type == MODULE_TYPE_AFHDS3;
}
-inline bool isModulePxx2(uint8_t idx)
-{
- if (idx != EXTERNAL_MODULE)
- return false;
-#if defined(PXX2)
- #if defined(HARDWARE_EXTERNAL_MODULE_SIZE_SML)
- if (g_model.moduleData[idx].type == MODULE_TYPE_XJT_LITE_PXX2 ||
- g_model.moduleData[idx].type == MODULE_TYPE_R9M_LITE_PRO_PXX2)
- return true;
- #endif
- #if defined(HARDWARE_EXTERNAL_MODULE_SIZE_SML)
- if (g_model.moduleData[idx].type == MODULE_TYPE_R9M_LITE_PXX2)
- return true;
- #endif
-#endif
- return false;
-}
-
// order is the same as in enum Protocols in myeeprom.h (none, ppm, pxx, pxx2, dsm, crossfire, multi, r9m, r9m2, sbus)
//qba667 count is not matching!
static const int8_t maxChannelsModules[] = { 0, 8, 8, 16, -2, 8, 4, 8, 16, 8, 10}; // relative to 8!
@@ -384,6 +386,8 @@ inline int8_t sentModuleChannels(uint8_t idx)
{
if (isModuleCrossfire(idx))
return CROSSFIRE_CHANNELS_COUNT;
+ else if (isModuleGhost(idx))
+ return GHOST_CHANNELS_COUNT;
else if (isModuleMultimodule(idx) && !isModuleMultimoduleDSM2(idx))
return 16;
else if (isModuleSBUS(idx))
@@ -414,6 +418,9 @@ inline bool isModuleRxNumAvailable(uint8_t moduleIdx)
if (isModuleMultimodule(moduleIdx))
return true;
+ if (isModuleCrossfire(moduleIdx))
+ return true;
+
return false;
}
@@ -528,7 +535,7 @@ inline bool isTelemAllowedOnBind(uint8_t moduleIndex)
return true;
}
- if (g_model.moduleData[EXTERNAL_MODULE].type == MODULE_TYPE_R9M_PXX1 || g_model.moduleData[EXTERNAL_MODULE].type == MODULE_TYPE_R9M_LITE_PRO_PXX1) {
+ if (g_model.moduleData[EXTERNAL_MODULE].type == MODULE_TYPE_R9M_PXX1) {
if (isModuleR9M_LBT(EXTERNAL_MODULE))
return g_model.moduleData[EXTERNAL_MODULE].pxx.power < R9M_LBT_POWER_200_16CH_NOTELEM;
else
@@ -666,10 +673,6 @@ inline void getMultiOptionValues(int8_t multi_proto, int8_t & min, int8_t & max)
min = -1;
max = 84;
break;
- case MODULE_SUBTYPE_MULTI_FRSKY_R9:
- min = 0; // 10mW
- max = 5; // 300mW
- break;
default:
min = -128;
max = 127;
@@ -678,4 +681,20 @@ inline void getMultiOptionValues(int8_t multi_proto, int8_t & min, int8_t & max)
}
#endif
+inline const char * getRssiLabel()
+{
+#if defined(MULTIMODULE)
+ if (telemetryProtocol == PROTOCOL_TELEMETRY_MULTIMODULE && (g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol() == MODULE_SUBTYPE_MULTI_FS_AFHDS2A
+ || g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol() == MODULE_SUBTYPE_MULTI_HOTT)) {
+ return "RQly";
+ }
+#endif
+#if defined(GHOST)
+ if (telemetryProtocol == PROTOCOL_TELEMETRY_GHOST) {
+ return "RQly";
+ }
+#endif
+ return "RSSI";
+}
+
#endif // _MODULES_HELPERS_H_
diff --git a/radio/src/pulses/multi.cpp b/radio/src/pulses/multi.cpp
index c8170f217..37364199a 100644
--- a/radio/src/pulses/multi.cpp
+++ b/radio/src/pulses/multi.cpp
@@ -42,6 +42,7 @@ static void sendD16BindOption(uint8_t moduleIdx);
#if defined(LUA)
static void sendSport(uint8_t moduleIdx);
static void sendHott(uint8_t moduleIdx);
+static void sendDSM(uint8_t moduleIdx);
#endif
void multiPatchCustom(uint8_t moduleIdx)
@@ -107,15 +108,15 @@ static void sendFailsafeChannels(uint8_t moduleIdx)
int16_t failsafeValue = g_model.failsafeChannels[i];
int pulseValue;
- if (g_model.moduleData[moduleIdx].failsafeMode == FAILSAFE_HOLD) {
+ if (g_model.moduleData[moduleIdx].failsafeMode == FAILSAFE_HOLD || failsafeValue == FAILSAFE_CHANNEL_HOLD) {
pulseValue = 2047;
}
- else if (g_model.moduleData[moduleIdx].failsafeMode == FAILSAFE_NOPULSES) {
+ else if (g_model.moduleData[moduleIdx].failsafeMode == FAILSAFE_NOPULSES || failsafeValue == FAILSAFE_CHANNEL_NOPULSE) {
pulseValue = 0;
}
else {
failsafeValue += 2 * PPM_CH_CENTER(g_model.moduleData[moduleIdx].channelsStart + i) - 2 * PPM_CENTER;
- pulseValue = limit(1, (failsafeValue * 800 / 1000) + 1024, 2047);
+ pulseValue = limit(1, (failsafeValue * 800 / 1000) + 1024, 2046);
}
bits |= pulseValue << bitsavailable;
@@ -167,13 +168,18 @@ void setupPulsesMulti(uint8_t moduleIdx)
sendChannels(moduleIdx);
// Multi V1.3.X.X -> Send byte 26, Protocol (bits 7 & 6), RX_Num (bits 5 & 4), invert, not used, disable telemetry, disable mapping
- sendMulti(moduleIdx, (uint8_t) (((g_model.moduleData[moduleIdx].getMultiProtocol()+3)&0xC0)
- | (g_model.header.modelId[moduleIdx] & 0x30)
- | (invert[moduleIdx] & 0x08)
- //| 0x04 // Future use
- | (g_model.moduleData[moduleIdx].multi.disableTelemetry << 1)
- | g_model.moduleData[moduleIdx].multi.disableMapping));
-
+ if (moduleState[moduleIdx].mode == MODULE_MODE_SPECTRUM_ANALYSER) {
+ sendMulti(moduleIdx, invert[moduleIdx] & 0x08);
+ }
+ else {
+ sendMulti(moduleIdx, (uint8_t) (((g_model.moduleData[moduleIdx].getMultiProtocol() + 3) & 0xC0)
+ | (g_model.header.modelId[moduleIdx] & 0x30)
+ | (invert[moduleIdx] & 0x08)
+ //| 0x04 // Future use
+ | (g_model.moduleData[moduleIdx].multi.disableTelemetry << 1)
+ | g_model.moduleData[moduleIdx].multi.disableMapping));
+ }
+
// Multi V1.3.X.X -> Send protocol additional data: max 9 bytes
if (getMultiModuleStatus(moduleIdx).isValid()) {
MultiModuleStatus &status = getMultiModuleStatus(moduleIdx);
@@ -189,6 +195,9 @@ void setupPulsesMulti(uint8_t moduleIdx)
else if (IS_HOTT_MULTI(moduleIdx)) {
sendHott(moduleIdx); //1 byte of additional data
}
+ else if (IS_DSM_MULTI(moduleIdx)) {
+ sendDSM(moduleIdx); //7 bytes of additional data
+ }
#endif
}
}
@@ -200,10 +209,8 @@ void setupPulsesMultiExternalModule()
extmodulePulsesData.dsm2.serialByte = 0 ;
extmodulePulsesData.dsm2.serialBitCount = 0 ;
#else
- extmodulePulsesData.dsm2.rest = getMultiSyncStatus(EXTERNAL_MODULE).getAdjustedRefreshRate();
extmodulePulsesData.dsm2.index = 0;
#endif
-
extmodulePulsesData.dsm2.ptr = extmodulePulsesData.dsm2.pulses;
setupPulsesMulti(EXTERNAL_MODULE);
@@ -396,4 +403,18 @@ void sendHott(uint8_t moduleIdx)
sendMulti(moduleIdx, Multi_Buffer[5]);
}
}
+
+void sendDSM(uint8_t moduleIdx)
+{
+ // Multi_Buffer[0..2]=="DSM" -> Lua script is running
+ // Multi_Buffer[3]==0x70 + len -> TX to RX data ready to be sent
+ // Multi_Buffer[4..9]=6 bytes of TX to RX data
+ // Multi_Buffer[10..25]=16 bytes of RX to TX data
+ if (Multi_Buffer && memcmp(Multi_Buffer, "DSM", 3) == 0 && (Multi_Buffer[3] & 0xF8) == 0x70) {
+ for(uint8_t i = 0; i < 7; i++) {
+ sendMulti(moduleIdx, Multi_Buffer[3+i]);
+ }
+ Multi_Buffer[3] = 0x00; // Data sent
+ }
+}
#endif
diff --git a/radio/src/pulses/pulses.cpp b/radio/src/pulses/pulses.cpp
index f669f5fdb..8ba672aa0 100755
--- a/radio/src/pulses/pulses.cpp
+++ b/radio/src/pulses/pulses.cpp
@@ -21,6 +21,7 @@
#include "opentx.h"
#include "io/frsky_pxx2.h"
#include "pulses/pxx2.h"
+#include "mixer_scheduler.h"
uint8_t s_pulses_paused = 0;
ModuleState moduleState[NUM_MODULES];
@@ -62,7 +63,7 @@ void getModuleSyncStatusString(uint8_t moduleIdx, char * statusText)
*statusText = 0;
#if defined(MULTIMODULE)
if (isModuleMultimodule(moduleIdx)) {
- getMultiSyncStatus(moduleIdx).getRefreshString(statusText);
+ getModuleSyncStatus(moduleIdx).getRefreshString(statusText);
}
#endif
#if defined(AFHDS3)
@@ -133,7 +134,6 @@ uint8_t getRequiredProtocol(uint8_t module)
#if defined(HARDWARE_EXTERNAL_MODULE_SIZE_SML)
case MODULE_TYPE_R9M_LITE_PXX1:
- case MODULE_TYPE_R9M_LITE_PRO_PXX1:
protocol = PROTOCOL_CHANNELS_PXX1_SERIAL;
break;
@@ -193,6 +193,12 @@ uint8_t getRequiredProtocol(uint8_t module)
break;
#endif
+#if defined(GHOST)
+ case MODULE_TYPE_GHOST:
+ protocol = PROTOCOL_CHANNELS_GHOST;
+ break;
+#endif
+
default:
protocol = PROTOCOL_CHANNELS_NONE;
break;
@@ -212,6 +218,7 @@ uint8_t getRequiredProtocol(uint8_t module)
return protocol;
}
+#if defined(HARDWARE_EXTERNAL_MODULE)
void enablePulsesExternalModule(uint8_t protocol)
{
// start new protocol hardware here
@@ -220,12 +227,14 @@ void enablePulsesExternalModule(uint8_t protocol)
#if defined(PXX1)
case PROTOCOL_CHANNELS_PXX1_PULSES:
extmodulePxx1PulsesStart();
+ mixerSchedulerSetPeriod(EXTERNAL_MODULE, PXX_PULSES_PERIOD);
break;
#endif
#if defined(PXX1) && defined(HARDWARE_EXTERNAL_MODULE_SIZE_SML)
case PROTOCOL_CHANNELS_PXX1_SERIAL:
extmodulePxx1SerialStart();
+ mixerSchedulerSetPeriod(EXTERNAL_MODULE, EXTMODULE_PXX1_SERIAL_PERIOD);
break;
#endif
@@ -233,53 +242,81 @@ void enablePulsesExternalModule(uint8_t protocol)
case PROTOCOL_CHANNELS_DSM2_LP45:
case PROTOCOL_CHANNELS_DSM2_DSM2:
case PROTOCOL_CHANNELS_DSM2_DSMX:
+#if defined(PCBSKY9X)
extmoduleSerialStart(DSM2_BAUDRATE, DSM2_PERIOD * 2000, false);
+#else
+ extmoduleSerialStart();
+ mixerSchedulerSetPeriod(EXTERNAL_MODULE, DSM2_PERIOD);
+#endif
break;
#endif
#if defined(CROSSFIRE)
case PROTOCOL_CHANNELS_CROSSFIRE:
EXTERNAL_MODULE_ON();
+ mixerSchedulerSetPeriod(EXTERNAL_MODULE, CROSSFIRE_PERIOD);
+ break;
+#endif
+
+#if defined(GHOST)
+ case PROTOCOL_CHANNELS_GHOST:
+ EXTERNAL_MODULE_ON();
+ mixerSchedulerSetPeriod(EXTERNAL_MODULE, GHOST_PERIOD);
break;
#endif
#if defined(PXX2) && defined(EXTMODULE_USART)
case PROTOCOL_CHANNELS_PXX2_HIGHSPEED:
extmoduleInvertedSerialStart(PXX2_HIGHSPEED_BAUDRATE);
+ mixerSchedulerSetPeriod(EXTERNAL_MODULE, PXX2_PERIOD);
break;
case PROTOCOL_CHANNELS_PXX2_LOWSPEED:
extmoduleInvertedSerialStart(PXX2_LOWSPEED_BAUDRATE);
+ mixerSchedulerSetPeriod(EXTERNAL_MODULE, PXX2_PERIOD);
break;
#endif
#if defined(MULTIMODULE)
case PROTOCOL_CHANNELS_MULTIMODULE:
+#if defined(PCBSKY9X)
extmoduleSerialStart(MULTIMODULE_BAUDRATE, MULTIMODULE_PERIOD * 2000, true);
+#else
+ extmoduleSerialStart();
+ mixerSchedulerSetPeriod(EXTERNAL_MODULE, MULTIMODULE_PERIOD);
+#endif
break;
#endif
#if defined(SBUS)
case PROTOCOL_CHANNELS_SBUS:
+#if defined(PCBSKY9X)
extmoduleSerialStart(SBUS_BAUDRATE, SBUS_PERIOD_HALF_US, false);
+#else
+ extmoduleSerialStart();
+ mixerSchedulerSetPeriod(EXTERNAL_MODULE, SBUS_PERIOD);
+#endif
break;
#endif
#if defined(PPM)
case PROTOCOL_CHANNELS_PPM:
extmodulePpmStart();
+ mixerSchedulerSetPeriod(EXTERNAL_MODULE, PPM_PERIOD(EXTERNAL_MODULE));
break;
#endif
#if defined(AFHDS3)
case PROTOCOL_CHANNELS_AFHDS3:
extmodulePulsesData.afhds3.init(EXTERNAL_MODULE);
- extmoduleSerialStart(AFHDS3_BAUDRATE, AFHDS3_COMMAND_TIMEOUT * 2000, false);
+ extmoduleSerialStart(/*AFHDS3_BAUDRATE, AFHDS3_COMMAND_TIMEOUT * 2000, false*/);
+ mixerSchedulerSetPeriod(EXTERNAL_MODULE, AFHDS3_COMMAND_TIMEOUT * 1000 /* us */);
break;
#endif
-
default:
+ // external module stopped, set period to 50ms (necessary for USB Joystick, for instance)
+ mixerSchedulerSetPeriod(EXTERNAL_MODULE, 50000/*us*/);
break;
}
}
@@ -290,14 +327,18 @@ bool setupPulsesExternalModule(uint8_t protocol)
#if defined(PXX1)
case PROTOCOL_CHANNELS_PXX1_PULSES:
extmodulePulsesData.pxx.setupFrame(EXTERNAL_MODULE);
+#if defined(PCBSKY9X)
scheduleNextMixerCalculation(EXTERNAL_MODULE, PXX_PULSES_PERIOD);
+#endif
return true;
#endif
#if defined(PXX1) && defined(HARDWARE_EXTERNAL_MODULE_SIZE_SML)
case PROTOCOL_CHANNELS_PXX1_SERIAL:
extmodulePulsesData.pxx_uart.setupFrame(EXTERNAL_MODULE);
+#if defined(PCBSKY9X)
scheduleNextMixerCalculation(EXTERNAL_MODULE, EXTMODULE_PXX1_SERIAL_PERIOD);
+#endif
return true;
#endif
@@ -305,59 +346,106 @@ bool setupPulsesExternalModule(uint8_t protocol)
case PROTOCOL_CHANNELS_PXX2_HIGHSPEED:
case PROTOCOL_CHANNELS_PXX2_LOWSPEED:
extmodulePulsesData.pxx2.setupFrame(EXTERNAL_MODULE);
- scheduleNextMixerCalculation(EXTERNAL_MODULE, PXX2_PERIOD);
+#if defined(PCBSKY9X)
+ sheduleNextMixerCalculation(EXTERNAL_MODULE, PXX2_PERIOD);
+#endif
return true;
#endif
#if defined(SBUS)
case PROTOCOL_CHANNELS_SBUS:
setupPulsesSbus();
+#if defined(PCBSKY9X)
scheduleNextMixerCalculation(EXTERNAL_MODULE, SBUS_PERIOD);
+#else
+ // SBUS_PERIOD is not a constant! It can be set from UI
+ mixerSchedulerSetPeriod(EXTERNAL_MODULE, SBUS_PERIOD);
return true;
#endif
+#endif
#if defined(DSM2)
case PROTOCOL_CHANNELS_DSM2_LP45:
case PROTOCOL_CHANNELS_DSM2_DSM2:
case PROTOCOL_CHANNELS_DSM2_DSMX:
setupPulsesDSM2();
+#if defined(PCBSKY9X)
scheduleNextMixerCalculation(EXTERNAL_MODULE, DSM2_PERIOD);
+#endif
return true;
#endif
#if defined(CROSSFIRE)
case PROTOCOL_CHANNELS_CROSSFIRE:
+ {
+ ModuleSyncStatus& status = getModuleSyncStatus(EXTERNAL_MODULE);
+ if (status.isValid())
+ mixerSchedulerSetPeriod(EXTERNAL_MODULE, status.getAdjustedRefreshRate());
+ else
+ mixerSchedulerSetPeriod(EXTERNAL_MODULE, CROSSFIRE_PERIOD);
setupPulsesCrossfire();
+#if defined(PCBSKY9X)
scheduleNextMixerCalculation(EXTERNAL_MODULE, CROSSFIRE_PERIOD);
+#endif
return true;
+ }
+#endif
+
+#if defined(GHOST)
+ case PROTOCOL_CHANNELS_GHOST:
+ {
+ ModuleSyncStatus& status = getModuleSyncStatus(EXTERNAL_MODULE);
+ if (status.isValid())
+ mixerSchedulerSetPeriod(EXTERNAL_MODULE, status.getAdjustedRefreshRate());
+ else
+ mixerSchedulerSetPeriod(EXTERNAL_MODULE, GHOST_PERIOD);
+ setupPulsesGhost();
+#if defined(PCBSKPCBSKY9X)
+ scheduleNextMixerCalculation(EXTERNAL_MODULE, GHOST_PERIOD);
+#endif
+ return true;
+ }
#endif
#if defined(MULTIMODULE)
case PROTOCOL_CHANNELS_MULTIMODULE:
+ {
+ ModuleSyncStatus& status = getModuleSyncStatus(EXTERNAL_MODULE);
+ if (status.isValid())
+ mixerSchedulerSetPeriod(EXTERNAL_MODULE, status.getAdjustedRefreshRate());
+ else
+ mixerSchedulerSetPeriod(EXTERNAL_MODULE, MULTIMODULE_PERIOD);
setupPulsesMultiExternalModule();
+#if defined(PCBSKY9X)
scheduleNextMixerCalculation(EXTERNAL_MODULE, MULTIMODULE_PERIOD);
+#endif
return true;
+ }
#endif
#if defined(PPM)
case PROTOCOL_CHANNELS_PPM:
setupPulsesPPMExternalModule();
+#if defined(PCBSKY9X)
scheduleNextMixerCalculation(EXTERNAL_MODULE, PPM_PERIOD(EXTERNAL_MODULE));
+#endif
return true;
#endif
#if defined(AFHDS3)
case PROTOCOL_CHANNELS_AFHDS3:
extmodulePulsesData.afhds3.setupFrame();
+#if defined(PCBSKY9X)
scheduleNextMixerCalculation(EXTERNAL_MODULE, AFHDS3_COMMAND_TIMEOUT);
+#endif
return true;
#endif
default:
- scheduleNextMixerCalculation(EXTERNAL_MODULE, 50/*ms*/);
return false;
}
}
+#endif
#if defined(HARDWARE_INTERNAL_MODULE)
static void enablePulsesInternalModule(uint8_t protocol)
@@ -368,12 +456,26 @@ static void enablePulsesInternalModule(uint8_t protocol)
#if defined(PXX1) && !defined(INTMODULE_USART)
case PROTOCOL_CHANNELS_PXX1_PULSES:
intmodulePxx1PulsesStart();
+#if defined(INTMODULE_HEARTBEAT)
+ // use backup trigger (1 ms later)
+ init_intmodule_heartbeat();
+ mixerSchedulerSetPeriod(INTERNAL_MODULE, INTMODULE_PXX1_SERIAL_PERIOD + 1000/*us*/);
+#else
+ mixerSchedulerSetPeriod(INTERNAL_MODULE, INTMODULE_PXX1_SERIAL_PERIOD);
+#endif
break;
#endif
#if defined(PXX1) && defined(INTMODULE_USART)
case PROTOCOL_CHANNELS_PXX1_SERIAL:
intmodulePxx1SerialStart();
+#if defined(INTMODULE_HEARTBEAT)
+ // use backup trigger (1 ms later)
+ init_intmodule_heartbeat();
+ mixerSchedulerSetPeriod(INTERNAL_MODULE, INTMODULE_PXX1_SERIAL_PERIOD + 1000/*us*/);
+#else
+ mixerSchedulerSetPeriod(INTERNAL_MODULE, INTMODULE_PXX1_SERIAL_PERIOD);
+#endif
break;
#endif
@@ -381,6 +483,14 @@ static void enablePulsesInternalModule(uint8_t protocol)
case PROTOCOL_CHANNELS_PXX2_HIGHSPEED:
intmoduleSerialStart(PXX2_HIGHSPEED_BAUDRATE, true, USART_Parity_No, USART_StopBits_1, USART_WordLength_8b);
resetAccessAuthenticationCount();
+
+#if defined(INTMODULE_HEARTBEAT)
+ // use backup trigger (1 ms later)
+ init_intmodule_heartbeat();
+ mixerSchedulerSetPeriod(INTERNAL_MODULE, PXX2_PERIOD + 1000/*us*/);
+#else
+ mixerSchedulerSetPeriod(INTERNAL_MODULE, PXX2_PERIOD);
+#endif
break;
#endif
@@ -388,17 +498,20 @@ static void enablePulsesInternalModule(uint8_t protocol)
case PROTOCOL_CHANNELS_MULTIMODULE:
intmodulePulsesData.multi.initFrame();
intmoduleSerialStart(MULTIMODULE_BAUDRATE, true, USART_Parity_Even, USART_StopBits_2, USART_WordLength_9b);
- intmoduleTimerStart(MULTIMODULE_PERIOD);
+ mixerSchedulerSetPeriod(INTERNAL_MODULE, MULTIMODULE_PERIOD);
break;
#endif
#if defined(INTERNAL_MODULE_PPM)
case PROTOCOL_CHANNELS_PPM:
intmodulePpmStart();
+ mixerSchedulerSetPeriod(INTERNAL_MODULE, PPM_PERIOD(INTERNAL_MODULE));
break;
#endif
default:
+ // internal module stopped, set internal period to 0 and start the scheduler
+ mixerSchedulerSetPeriod(INTERNAL_MODULE, 0);
break;
}
}
@@ -409,18 +522,18 @@ bool setupPulsesInternalModule(uint8_t protocol)
#if defined(HARDWARE_INTERNAL_MODULE) && defined(PXX1) && !defined(INTMODULE_USART)
case PROTOCOL_CHANNELS_PXX1_PULSES:
intmodulePulsesData.pxx.setupFrame(INTERNAL_MODULE);
- scheduleNextMixerCalculation(INTERNAL_MODULE, INTMODULE_PXX1_SERIAL_PERIOD);
+#if defined(INTMODULE_HEARTBEAT)
+ mixerSchedulerResetTimer();
+ mixerSchedulerSetPeriod(INTERNAL_MODULE, INTMODULE_PXX1_SERIAL_PERIOD + 1000 /* backup */);
+#else
+ mixerSchedulerSetPeriod(INTERNAL_MODULE, INTMODULE_PXX1_SERIAL_PERIOD);
+#endif
return true;
#endif
#if defined(PXX1) && defined(INTMODULE_USART)
case PROTOCOL_CHANNELS_PXX1_SERIAL:
intmodulePulsesData.pxx_uart.setupFrame(INTERNAL_MODULE);
-#if defined(INTMODULE_HEARTBEAT)
- scheduleNextMixerCalculation(INTERNAL_MODULE, INTMODULE_PXX1_SERIAL_PERIOD + 1 /* backup */);
-#else
- scheduleNextMixerCalculation(INTERNAL_MODULE, INTMODULE_PXX1_SERIAL_PERIOD);
-#endif
return true;
#endif
@@ -429,13 +542,14 @@ bool setupPulsesInternalModule(uint8_t protocol)
{
bool result = intmodulePulsesData.pxx2.setupFrame(INTERNAL_MODULE);
if (moduleState[INTERNAL_MODULE].mode == MODULE_MODE_SPECTRUM_ANALYSER || moduleState[INTERNAL_MODULE].mode == MODULE_MODE_POWER_METER) {
- scheduleNextMixerCalculation(INTERNAL_MODULE, PXX2_TOOLS_PERIOD);
+ mixerSchedulerSetPeriod(INTERNAL_MODULE, PXX2_TOOLS_PERIOD);
}
else {
#if defined(INTMODULE_HEARTBEAT)
- scheduleNextMixerCalculation(INTERNAL_MODULE, PXX2_PERIOD + 1 /* backup */);
+ mixerSchedulerResetTimer();
+ mixerSchedulerSetPeriod(INTERNAL_MODULE, PXX2_PERIOD + 2000 /* backup */);
#else
- scheduleNextMixerCalculation(INTERNAL_MODULE, PXX2_PERIOD);
+ mixerSchedulerSetPeriod(INTERNAL_MODULE, PXX2_PERIOD);
#endif
}
return result;
@@ -445,23 +559,32 @@ bool setupPulsesInternalModule(uint8_t protocol)
#if defined(PCBTARANIS) && defined(INTERNAL_MODULE_PPM)
case PROTOCOL_CHANNELS_PPM:
setupPulsesPPMInternalModule();
- scheduleNextMixerCalculation(INTERNAL_MODULE, PPM_PERIOD(INTERNAL_MODULE));
+ // probably useless, as the interval did not change since "enable" function
+ mixerSchedulerSetPeriod(INTERNAL_MODULE, PPM_PERIOD(INTERNAL_MODULE));
return true;
#endif
#if defined(INTERNAL_MODULE_MULTI)
case PROTOCOL_CHANNELS_MULTIMODULE:
setupPulsesMultiInternalModule();
- scheduleNextMixerCalculation(INTERNAL_MODULE, MULTIMODULE_PERIOD);
+ mixerSchedulerSetPeriod(INTERNAL_MODULE, MULTIMODULE_PERIOD);
return true;
#endif
default:
- scheduleNextMixerCalculation(INTERNAL_MODULE, 10 /*ms*/); // used for USB sim for example
+ //mixerSchedulerSetPeriod(INTERNAL_MODULE, 10000 /*us*/); // used for USB sim for example
return false;
}
}
+void stopPulsesInternalModule()
+{
+ if (moduleState[INTERNAL_MODULE].protocol != PROTOCOL_CHANNELS_UNINITIALIZED) {
+ intmoduleStop();
+ moduleState[INTERNAL_MODULE].protocol = PROTOCOL_CHANNELS_NONE;
+ }
+}
+
bool setupPulsesInternalModule()
{
uint8_t protocol = getRequiredProtocol(INTERNAL_MODULE);
@@ -480,6 +603,15 @@ bool setupPulsesInternalModule()
}
#endif
+#if defined(HARDWARE_EXTERNAL_MODULE)
+void stopPulsesExternalModule()
+{
+ if (moduleState[EXTERNAL_MODULE].protocol != PROTOCOL_CHANNELS_UNINITIALIZED) {
+ extmoduleStop();
+ moduleState[EXTERNAL_MODULE].protocol = PROTOCOL_CHANNELS_NONE;
+ }
+}
+
bool setupPulsesExternalModule()
{
uint8_t protocol = getRequiredProtocol(EXTERNAL_MODULE);
@@ -496,6 +628,7 @@ bool setupPulsesExternalModule()
return setupPulsesExternalModule(protocol);
}
}
+#endif
void setCustomFailsafe(uint8_t moduleIndex)
{
@@ -508,10 +641,11 @@ void setCustomFailsafe(uint8_t moduleIndex)
g_model.failsafeChannels[ch] = channelOutputs[ch];
}
}
+ storageDirty(EE_MODEL);
}
}
-int32_t getChannelValue(uint8_t channel) {
+int32_t getChannelValue(uint8_t channel)
+{
return channelOutputs[channel] + 2*PPM_CH_CENTER(channel) - 2*PPM_CENTER;
}
-
diff --git a/radio/src/pulses/pulses.h b/radio/src/pulses/pulses.h
index f92629f6e..e9f65a9d2 100644
--- a/radio/src/pulses/pulses.h
+++ b/radio/src/pulses/pulses.h
@@ -111,6 +111,7 @@ class ReceiverSettings {
uint8_t pwmRate;
uint8_t fport;
uint8_t enablePwmCh5Ch6;
+ uint8_t fport2;
uint8_t outputsCount;
uint8_t outputsMapping[24];
};
@@ -215,21 +216,20 @@ typedef Dsm2SerialPulsesData Dsm2PulsesData;
PACK(struct Dsm2TimerPulsesData {
pulse_duration_t pulses[MAX_PULSES_TRANSITIONS];
pulse_duration_t * ptr;
- uint16_t rest;
uint8_t index;
});
typedef Dsm2TimerPulsesData Dsm2PulsesData;
#endif
#define PPM_PERIOD_HALF_US(module) ((g_model.moduleData[module].ppm.frameLength * 5 + 225) * 200) /*half us*/
-#define PPM_PERIOD(module) (PPM_PERIOD_HALF_US(module) / 2000) /*ms*/
+#define PPM_PERIOD(module) (PPM_PERIOD_HALF_US(module) / 2) /*us*/
#define DSM2_BAUDRATE 125000
-#define DSM2_PERIOD 22 /*ms*/
+#define DSM2_PERIOD 22000 /*us*/
#define SBUS_BAUDRATE 100000
#define SBUS_PERIOD_HALF_US ((g_model.moduleData[EXTERNAL_MODULE].sbus.refreshRate * 5 + 225) * 200) /*half us*/
-#define SBUS_PERIOD (SBUS_PERIOD_HALF_US / 2000) /*ms*/
+#define SBUS_PERIOD (SBUS_PERIOD_HALF_US / 2) /*us*/
#define MULTIMODULE_BAUDRATE 100000
-#define MULTIMODULE_PERIOD 7 /*ms*/
+#define MULTIMODULE_PERIOD 7000 /*us*/
#define CROSSFIRE_FRAME_MAXLEN 64
PACK(struct CrossfirePulsesData {
@@ -237,6 +237,12 @@ PACK(struct CrossfirePulsesData {
uint8_t length;
});
+#define GHOST_FRAME_MAXLEN 16
+PACK(struct GhostPulsesData {
+ uint8_t pulses[GHOST_FRAME_MAXLEN];
+ uint8_t length;
+});
+
union InternalModulePulsesData {
#if defined(PXX1)
#if defined(INTMODULE_USART)
@@ -286,6 +292,8 @@ union ExternalModulePulsesData {
PpmPulsesData ppm;
CrossfirePulsesData crossfire;
+
+ GhostPulsesData ghost;
} __ALIGNED(4);
/* The __ALIGNED keyword is required to align the struct inside the modulePulsesData below,
@@ -306,10 +314,15 @@ extern TrainerPulsesData trainerPulsesData;
#if defined(HARDWARE_INTERNAL_MODULE)
bool setupPulsesInternalModule();
+void stopPulsesInternalModule();
#endif
+#if defined(HARDWARE_EXTERNAL_MODULE)
bool setupPulsesExternalModule();
+void stopPulsesExternalModule();
+#endif
void setupPulsesDSM2();
void setupPulsesCrossfire();
+void setupPulsesGhost();
void setupPulsesMultiExternalModule();
void setupPulsesMultiInternalModule();
void setupPulsesSbus();
@@ -343,7 +356,9 @@ inline void startPulses()
setupPulsesInternalModule();
#endif
+#if defined(HARDWARE_EXTERNAL_MODULE)
setupPulsesExternalModule();
+#endif
#if defined(HARDWARE_EXTRA_MODULE)
extramodulePpmStart();
@@ -364,7 +379,8 @@ enum ChannelsProtocols {
PROTOCOL_CHANNELS_SBUS,
PROTOCOL_CHANNELS_PXX2_LOWSPEED,
PROTOCOL_CHANNELS_PXX2_HIGHSPEED,
- PROTOCOL_CHANNELS_AFHDS3
+ PROTOCOL_CHANNELS_AFHDS3,
+ PROTOCOL_CHANNELS_GHOST
};
inline void stopPulses()
diff --git a/radio/src/pulses/pxx.h b/radio/src/pulses/pxx.h
index 5d0bfaf05..e852de180 100644
--- a/radio/src/pulses/pxx.h
+++ b/radio/src/pulses/pxx.h
@@ -29,20 +29,20 @@
#define PXX2_LOWSPEED_BAUDRATE 230400
#define PXX2_HIGHSPEED_BAUDRATE 450000
-#define PXX2_PERIOD 4 // 4ms
-#define PXX2_TOOLS_PERIOD 1 // 1ms
+#define PXX2_PERIOD 4000/*us*/
+#define PXX2_TOOLS_PERIOD 1000/*us*/
#define PXX2_FRAME_MAXLENGTH 64
-#define PXX_PULSES_PERIOD 9/*ms*/
-#define EXTMODULE_PXX1_SERIAL_PERIOD 4/*ms*/
+#define PXX_PULSES_PERIOD 9000/*us*/
+#define EXTMODULE_PXX1_SERIAL_PERIOD 4000/*us*/
#define EXTMODULE_PXX1_SERIAL_BAUDRATE 420000
#if defined(PXX_FREQUENCY_HIGH)
#define INTMODULE_PXX1_SERIAL_BAUDRATE 450000
- #define INTMODULE_PXX1_SERIAL_PERIOD 4/*ms*/
+ #define INTMODULE_PXX1_SERIAL_PERIOD 4000/*us*/
#else
#define INTMODULE_PXX1_SERIAL_BAUDRATE 115200
- #define INTMODULE_PXX1_SERIAL_PERIOD 9/*ms*/
+ #define INTMODULE_PXX1_SERIAL_PERIOD 9000/*us*/
#endif
// Used by the Sky9x family boards
@@ -108,7 +108,7 @@ class PwmPxxBitTransport: public PulsesBuffer {
void addTail()
{
// rest min value is 18000 - 200 * 48 = 8400 (4.2ms)
- *(ptr - 1) += rest;
+ *(ptr - 1) = 60000;
}
};
diff --git a/radio/src/pulses/pxx1.cpp b/radio/src/pulses/pxx1.cpp
index 4dfa3be95..ba05d026e 100644
--- a/radio/src/pulses/pxx1.cpp
+++ b/radio/src/pulses/pxx1.cpp
@@ -208,7 +208,7 @@ void Pxx1Pulses::setupFrame(uint8_t module)
add8ChannelsFrame(module, sendUpperChannels, sendFailsafe);
if (moduleState[module].counter-- == 0) {
- moduleState[module].counter = 1000;
+ moduleState[module].counter = 999;
}
}
diff --git a/radio/src/pulses/pxx2.cpp b/radio/src/pulses/pxx2.cpp
index 944be8a3a..a96adba3f 100644
--- a/radio/src/pulses/pxx2.cpp
+++ b/radio/src/pulses/pxx2.cpp
@@ -47,14 +47,20 @@ void Pxx2Pulses::addFlag1(uint8_t module)
else {
subType = g_model.moduleData[module].subType;
}
- Pxx2Transport::addByte(subType << 4);
+
+ uint8_t flag1 = subType << 4u;
+ if (isRacingModeEnabled() && isFunctionActive(FUNCTION_RACING_MODE)) {
+ flag1 |= PXX2_CHANNELS_FLAG1_RACING_MODE;
+ }
+
+ Pxx2Transport::addByte(flag1);
}
void Pxx2Pulses::addPulsesValues(uint16_t low, uint16_t high)
{
Pxx2Transport::addByte(low); // Low byte of channel
- Pxx2Transport::addByte(((low >> 8) & 0x0F) | (high << 4)); // 4 bits each from 2 channels
- Pxx2Transport::addByte(high >> 4); // High byte of channel
+ Pxx2Transport::addByte(((low >> 8u) & 0x0Fu) | (high << 4u)); // 4 bits each from 2 channels
+ Pxx2Transport::addByte(high >> 4u); // High byte of channel
}
void Pxx2Pulses::addChannels(uint8_t module)
@@ -227,6 +233,8 @@ void Pxx2Pulses::setupReceiverSettingsFrame(uint8_t module)
flag1 |= PXX2_RX_SETTINGS_FLAG1_TELEMETRY_25MW;
if (reusableBuffer.hardwareAndSettings.receiverSettings.enablePwmCh5Ch6)
flag1 |= PXX2_RX_SETTINGS_FLAG1_ENABLE_PWM_CH5_CH6;
+ if (reusableBuffer.hardwareAndSettings.receiverSettings.fport2)
+ flag1 |= PXX2_RX_SETTINGS_FLAG1_FPORT2;
Pxx2Transport::addByte(flag1);
uint8_t outputsCount = min(24, reusableBuffer.hardwareAndSettings.receiverSettings.outputsCount);
for (int i = 0; i < outputsCount; i++) {
diff --git a/radio/src/pulses/pxx2.h b/radio/src/pulses/pxx2.h
index 2fa64dcad..b752c06c8 100644
--- a/radio/src/pulses/pxx2.h
+++ b/radio/src/pulses/pxx2.h
@@ -46,6 +46,7 @@
#define PXX2_CHANNELS_FLAG0_FAILSAFE (1 << 6)
#define PXX2_CHANNELS_FLAG0_RANGECHECK (1 << 7)
+#define PXX2_CHANNELS_FLAG1_RACING_MODE (1 << 3)
#define PXX2_RX_SETTINGS_FLAG0_WRITE (1 << 6)
@@ -55,6 +56,7 @@
#define PXX2_RX_SETTINGS_FLAG1_FPORT (1 << 3)
#define PXX2_RX_SETTINGS_FLAG1_TELEMETRY_25MW (1 << 2)
#define PXX2_RX_SETTINGS_FLAG1_ENABLE_PWM_CH5_CH6 (1 << 1)
+#define PXX2_RX_SETTINGS_FLAG1_FPORT2 (1 << 0)
#define PXX2_TX_SETTINGS_FLAG0_WRITE (1 << 6)
#define PXX2_TX_SETTINGS_FLAG1_EXTERNAL_ANTENNA (1 << 3)
@@ -220,16 +222,16 @@ static const uint8_t PXX2ReceiverOptions[] = {
0b11111110, // X8R
0b11111110, // RX8R
0b11111110, // RX8R-PRO
- 0b11111110, // RX6R
- 0b11111110, // RX4R
- 0b11111110, // G-RX8
- 0b11111110, // G-RX6
+ 0b11111111, // RX6R
+ 0b11111111, // RX4R
+ 0b11111111, // G-RX8
+ 0b11111111, // G-RX6
0b11111110, // X6R
0b11111110, // X4R
0b11111110, // X4R-SB
0b11111110, // XSR
0b11111110, // XSR-M
- 0b11111110, // RXSR
+ 0b11111111, // RXSR
0b11111110, // S6R
0b11111110, // S8R
0b11111110, // XM
@@ -266,6 +268,8 @@ enum ReceiverCapabilities {
RECEIVER_CAPABILITY_FPORT,
RECEIVER_CAPABILITY_TELEMETRY_25MW,
RECEIVER_CAPABILITY_ENABLE_PWM_CH5_CH6,
+ RECEIVER_CAPABILITY_FPORT2,
+ RECEIVER_CAPABILITY_RACING_MODE,
RECEIVER_CAPABILITY_COUNT
};
diff --git a/radio/src/pulses/sbus.cpp b/radio/src/pulses/sbus.cpp
index a881730fc..e44abd642 100644
--- a/radio/src/pulses/sbus.cpp
+++ b/radio/src/pulses/sbus.cpp
@@ -55,7 +55,6 @@ static void _send_level(uint8_t v)
*extmodulePulsesData.dsm2.ptr++ = v - 1;
extmodulePulsesData.dsm2.index+=1;
- extmodulePulsesData.dsm2.rest -=v;
}
void sendByteSbus(uint8_t b) // max 11 changes 0 10 10 10 10 P 1
@@ -113,7 +112,6 @@ void setupPulsesSbus()
extmodulePulsesData.dsm2.serialByte = 0;
extmodulePulsesData.dsm2.serialBitCount = 0;
#else
- extmodulePulsesData.dsm2.rest = SBUS_PERIOD_HALF_US;
extmodulePulsesData.dsm2.index = 0;
#endif
diff --git a/radio/src/rtos.h b/radio/src/rtos.h
index 6e42ebf30..f9f112399 100644
--- a/radio/src/rtos.h
+++ b/radio/src/rtos.h
@@ -36,7 +36,9 @@ extern "C++" {
typedef pthread_t RTOS_TASK_HANDLE;
typedef pthread_mutex_t RTOS_MUTEX_HANDLE;
+
typedef uint32_t RTOS_FLAG_HANDLE;
+
typedef sem_t * RTOS_EVENT_HANDLE;
extern uint64_t simuTimerMicros(void);
@@ -76,16 +78,26 @@ extern "C++" {
pthread_mutex_unlock(&mutex);
}
- static inline void RTOS_CREATE_FLAG(uint32_t &flag)
+ static inline void RTOS_CREATE_FLAG(RTOS_FLAG_HANDLE flag)
{
- flag = 0; // TODO: real flags (use semaphores?)
}
- static inline void RTOS_SET_FLAG(uint32_t &flag)
+ static inline void RTOS_SET_FLAG(RTOS_FLAG_HANDLE flag)
{
- flag = 1;
}
+ static inline void RTOS_CLEAR_FLAG(RTOS_FLAG_HANDLE flag)
+ {
+ }
+
+ static inline bool RTOS_WAIT_FLAG(RTOS_FLAG_HANDLE flag, uint32_t timeout)
+ {
+ simuSleep(timeout);
+ return false;
+ }
+
+ #define RTOS_ISR_SET_FLAG RTOS_SET_FLAG
+
template
class FakeTaskStack
{
@@ -146,6 +158,7 @@ template
{
return (uint32_t)(simuTimerMicros() / 1000);
}
+
#elif defined(RTOS_COOS)
#ifdef __cplusplus
extern "C" {
@@ -155,7 +168,7 @@ template
}
#endif
- #define RTOS_MS_PER_TICK ((CFG_CPU_FREQ / CFG_SYSTICK_FREQ) / (CFG_CPU_FREQ / 1000)) // RTOS timer tick length in ms (currently 2)
+ #define RTOS_MS_PER_TICK (1000 / CFG_SYSTICK_FREQ) // RTOS timer tick length in ms (currently 1 for STM32, 2 for others)
typedef OS_TID RTOS_TASK_HANDLE;
typedef OS_MutexID RTOS_MUTEX_HANDLE;
@@ -230,7 +243,18 @@ template
#define RTOS_CREATE_FLAG(flag) flag = CoCreateFlag(false, false)
#define RTOS_SET_FLAG(flag) (void)CoSetFlag(flag)
+ #define RTOS_CLEAR_FLAG(flag) (void)CoClearFlag(flag)
+ #define RTOS_WAIT_FLAG(flag,timeout) (CoWaitForSingleFlag(flag,timeout) == E_TIMEOUT)
+ static inline void RTOS_ISR_SET_FLAG(RTOS_FLAG_HANDLE flag)
+ {
+ CoEnterISR();
+ CoSchedLock();
+ isr_SetFlag(flag);
+ CoSchedUnlock();
+ CoExitISR();
+ }
+
#ifdef __cplusplus
template
class TaskStack
diff --git a/radio/src/sdcard.h b/radio/src/sdcard.h
index c54e185a1..48e7e05e0 100644
--- a/radio/src/sdcard.h
+++ b/radio/src/sdcard.h
@@ -72,6 +72,7 @@ const char RADIO_SETTINGS_PATH[] = RADIO_PATH "/radio.bin";
#define SPORT_FIRMWARE_EXT ".frk"
#define FRSKY_FIRMWARE_EXT ".frsk"
#define MULTI_FIRMWARE_EXT ".bin"
+#define ELRS_FIRMWARE_EXT ".elrs"
#define LEN_FILE_EXTENSION_MAX 5 // longest used, including the dot, excluding null term.
@@ -142,6 +143,12 @@ const char * getBasename(const char * path);
#define OTX_FOURCC 0x3978746F // otx for Taranis X-Lite
#elif defined(RADIO_T12)
#define OTX_FOURCC 0x3D78746F // otx for Jumper T12
+#elif defined(RADIO_TLITE)
+ #define OTX_FOURCC 0x4278746F // otx for Jumper TLite
+#elif defined(RADIO_TX12)
+ #define OTX_FOURCC 0x4178746F // otx for Radiomaster TX12
+#elif defined(RADIO_T8)
+ #define OTX_FOURCC 0x4378746F // otx for Radiomaster T8
#elif defined(PCBX7)
#define OTX_FOURCC 0x3678746F // otx for Taranis X7 / X7S / X7 Express / X7S Express
#elif defined(PCBX9LITES)
diff --git a/radio/src/simu.cpp b/radio/src/simu.cpp
index 293170127..afbd95e96 100644
--- a/radio/src/simu.cpp
+++ b/radio/src/simu.cpp
@@ -255,7 +255,7 @@ void OpenTxSim::updateKeysAndSwitches(bool start)
KEY_Down, KEY_DOWN,
KEY_Right, KEY_RIGHT,
KEY_Left, KEY_LEFT,
-#elif defined(PCBXLITE) || defined(RADIO_T12)
+#elif defined(PCBXLITE) || defined(RADIO_FAMILY_JUMPER_T12)
#if defined(KEYS_GPIO_REG_SHIFT)
KEY_Shift_L, KEY_SHIFT,
#endif
@@ -265,6 +265,23 @@ void OpenTxSim::updateKeysAndSwitches(bool start)
KEY_Left, KEY_LEFT,
KEY_Up, KEY_UP,
KEY_Down, KEY_DOWN,
+#elif defined(RADIO_TX12)
+ KEY_Page_Up, KEY_PAGEUP,
+ KEY_Page_Down, KEY_PAGEDN,
+ KEY_Return, KEY_ENTER,
+ KEY_Up, KEY_MODEL,
+ KEY_Down, KEY_EXIT,
+ KEY_Right, KEY_TELE,
+ KEY_Left, KEY_SYS,
+#elif defined(RADIO_T8)
+ KEY_Page_Up, KEY_PAGEUP,
+ KEY_Page_Down, KEY_PAGEDN,
+ KEY_Return, KEY_ENTER,
+ KEY_Right, KEY_MODEL,
+ KEY_BackSpace, KEY_EXIT,
+ KEY_Left, KEY_SYS,
+ KEY_Up, KEY_PLUS,
+ KEY_Down, KEY_MINUS,
#elif defined(PCBTARANIS)
KEY_Page_Up, KEY_MENU,
#if defined(KEYS_GPIO_REG_PAGE)
diff --git a/radio/src/stamp.cpp b/radio/src/stamp.cpp
index ad28e4037..565df359a 100644
--- a/radio/src/stamp.cpp
+++ b/radio/src/stamp.cpp
@@ -37,21 +37,31 @@
#elif defined(JUMPER_RELEASE)
#define DISPLAY_VERSION "-jumper"
#elif defined(RADIOMASTER_RELEASE)
-#define DISPLAY_VERSION "-radiomaster"
+#define DISPLAY_VERSION "-RM"
#elif defined(TBS_RELEASE)
#define DISPLAY_VERSION "-tbs"
+#elif defined(IMRC_RELEASE)
+#define DISPLAY_VERSION "-imrc"
#else
#define DISPLAY_VERSION
#endif
#if defined(COLORLCD)
const char fw_stamp[] = "FW" TAB ": opentx-" FLAVOUR;
+#if defined(RADIOMASTER_RELEASE) || defined(JUMPER_RELEASE)
+ const char vers_stamp[] = "VERS" TAB ": Factory firmware (" GIT_STR ")";
+#else
const char vers_stamp[] = "VERS" TAB ": " VERSION DISPLAY_VERSION " (" GIT_STR ")";
+#endif
const char date_stamp[] = "DATE" TAB ": " DATE;
const char time_stamp[] = "TIME" TAB ": " TIME;
const char eeprom_stamp[] = "EEPR" TAB ": " EEPROM_STR;
#elif defined(BOARD_NAME)
const char vers_stamp[] = "FW" TAB ": opentx-" BOARD_NAME "\036VERS" TAB ": " VERSION DISPLAY_VERSION " (" GIT_STR ")" "\036DATE" TAB ": " DATE " " TIME "\036EEPR" TAB ": " EEPROM_STR;
+#elif defined(RADIOMASTER_RELEASE)
+ const char vers_stamp[] = "FW" TAB ": opentx-" FLAVOUR "\036VERS" TAB ": RM Factory (" GIT_STR ")" "\036BUILT BY : OpenTX" "\036DATE" TAB ": " DATE " " TIME "\036EEPR" TAB ": " EEPROM_STR;
+#elif defined(JUMPER_RELEASE)
+ const char vers_stamp[] = "FW" TAB ": opentx-" FLAVOUR "\036VERS" TAB ": Factory (" GIT_STR ")" "\036BUILT BY : OpenTX" "\036DATE" TAB ": " DATE " " TIME "\036EEPR" TAB ": " EEPROM_STR;
#else
const char vers_stamp[] = "FW" TAB ": opentx-" FLAVOUR "\036VERS" TAB ": " VERSION DISPLAY_VERSION " (" GIT_STR ")" "\036DATE" TAB ": " DATE " " TIME "\036EEPR" TAB ": " EEPROM_STR;
#endif
diff --git a/radio/src/storage/modelslist.cpp b/radio/src/storage/modelslist.cpp
index 972e24800..59bff7ce9 100644
--- a/radio/src/storage/modelslist.cpp
+++ b/radio/src/storage/modelslist.cpp
@@ -111,7 +111,7 @@ void ModelCell::loadBitmap()
getTimerString(timer, 0);
for (uint8_t i = 0; i < MAX_TIMERS; i++) {
if (partialmodel.timers[i].mode != 0 && partialmodel.timers[i].persistent) {
- getTimerString(timer, partialmodel.timers[i].value);
+ getTimerString(timer, partialmodel.timers[i].value, 1);
break;
}
}
diff --git a/radio/src/storage/storage_common.cpp b/radio/src/storage/storage_common.cpp
index 396ede0df..857cdd1a6 100644
--- a/radio/src/storage/storage_common.cpp
+++ b/radio/src/storage/storage_common.cpp
@@ -51,8 +51,16 @@ void preModelLoad()
if (pulsesStarted()) {
pausePulses();
}
-
pauseMixerCalculations();
+
+#if defined(HARDWARE_INTERNAL_MODULE)
+ stopPulsesInternalModule();
+#endif
+#if defined(HARDWARE_EXTERNAL_MODULE)
+ stopPulsesExternalModule();
+#endif
+
+ stopTrainer();
}
void postRadioSettingsLoad()
diff --git a/radio/src/strhelpers.cpp b/radio/src/strhelpers.cpp
index 07e6b4e8b..b88c26099 100644
--- a/radio/src/strhelpers.cpp
+++ b/radio/src/strhelpers.cpp
@@ -170,7 +170,11 @@ char * strAppendStringWithIndex(char * dest, const char * s, int idx)
return strAppendUnsigned(strAppend(dest, s), abs(idx));
}
-char * getTimerString(char * dest, int32_t tme, uint8_t hours)
+constexpr int secondsPerDay = 24 * 3600;
+constexpr int secondsPer99Hours = 99*3600 + 59*60 + 59;
+constexpr int secondsPerYear = 365 * secondsPerDay;
+
+char * getTimerString(char * dest, int tme, uint8_t hours)
{
char * s = dest;
div_t qr;
@@ -180,28 +184,63 @@ char * getTimerString(char * dest, int32_t tme, uint8_t hours)
*s++ = '-';
}
- qr = div((int)tme, 60);
+ if (tme < secondsPerDay) {
+ qr = div((int) tme, 60);
- if (hours) {
- div_t qr2 = div(qr.quot, 60);
+ if (hours) {
+ div_t qr2 = div(qr.quot, 60);
+ *s++ = '0' + (qr2.quot / 10);
+ *s++ = '0' + (qr2.quot % 10);
+ *s++ = ':';
+ qr.quot = qr2.rem;
+ }
+
+ if (!hours && qr.quot > 99) {
+ *s++ = '0' + (qr.quot / 100);
+ qr.quot = qr.quot % 100;
+ }
+
+ *s++ = '0' + (qr.quot / 10);
+ *s++ = '0' + (qr.quot % 10);
+ *s++ = ':';
+ *s++ = '0' + (qr.rem / 10);
+ *s++ = '0' + (qr.rem % 10);
+ *s = '\0';
+ }
+ else if (tme < secondsPer99Hours) {
+ qr = div(tme, 3600);
+ div_t qr2 = div(qr.rem, 60);
+ *s++ = '0' + (qr.quot / 10);
+ *s++ = '0' + (qr.quot % 10);
+ *s++ = 'H';
*s++ = '0' + (qr2.quot / 10);
*s++ = '0' + (qr2.quot % 10);
- *s++ = ':';
- qr.quot = qr2.rem;
+ *s = '\0';
}
-
- if (!hours && qr.quot > 99) {
+ else if (tme < secondsPerYear) {
+ qr = div(tme, secondsPerDay);
+ div_t qr2 = div(qr.rem, 60);
*s++ = '0' + (qr.quot / 100);
- qr.quot = qr.quot % 100;
+ *s++ = '0' + (qr.quot / 10);
+ *s++ = '0' + (qr.quot % 10);
+ *s++ = 'D';
+ *s++ = '0' + (qr2.quot / 10);
+ *s++ = '0' + (qr2.quot % 10);
+ *s++ = 'H';
+ *s = '\0';
+ }
+ else {
+ qr = div(tme, secondsPerYear);
+ div_t qr2 = div(qr.rem, secondsPerDay);
+ *s++ = '0' + (qr.quot / 10);
+ *s++ = '0' + (qr.quot % 10);
+ *s++ = 'Y';
+ *s++ = 'Y';
+ *s++ = '0' + (qr2.quot / 10);
+ *s++ = '0' + (qr2.quot % 10);
+ *s++ = 'D';
+ *s = '\0';
}
-
- *s++ = '0' + (qr.quot / 10);
- *s++ = '0' + (qr.quot % 10);
- *s++ = ':';
- *s++ = '0' + (qr.rem / 10);
- *s++ = '0' + (qr.rem % 10);
- *s = '\0';
-
return dest;
}
@@ -251,7 +290,7 @@ char * getSwitchName(char * dest, swsrc_t idx)
}
else {
*dest++ = 'S';
-#if defined(PCBX7)
+#if defined(PCBX7) && !defined(RADIO_TX12)
if (swinfo.quot >= 5)
*dest++ = 'H' + swinfo.quot - 5;
else if (swinfo.quot == 4)
@@ -312,16 +351,9 @@ char * getSwitchPositionName(char * dest, swsrc_t idx)
}
#endif
-#if defined(PCBSKY9X)
- else if (idx <= SWSRC_REa) {
- getStringAtIndex(s, STR_VSWITCHES, IDX_TRIMS_IN_STR_VSWITCHES+idx-SWSRC_FIRST_TRIM);
- }
-#else
else if (idx <= SWSRC_LAST_TRIM) {
getStringAtIndex(s, STR_VSWITCHES, IDX_TRIMS_IN_STR_VSWITCHES+idx-SWSRC_FIRST_TRIM);
}
-#endif
-
else if (idx <= SWSRC_LAST_LOGICAL_SWITCH) {
*s++ = 'L';
strAppendUnsigned(s, idx-SWSRC_FIRST_LOGICAL_SWITCH+1, 2);
diff --git a/radio/src/strhelpers.h b/radio/src/strhelpers.h
index 114d7a009..4217433c2 100644
--- a/radio/src/strhelpers.h
+++ b/radio/src/strhelpers.h
@@ -32,7 +32,7 @@ char * strAppendFilename(char * dest, const char * filename, const int size);
char * getStringAtIndex(char * dest, const char * s, int idx);
char * strAppendStringWithIndex(char * dest, const char * s, int idx);
#define LEN_TIMER_STRING 10 // "-00:00:00"
-char * getTimerString(char * dest, int32_t tme, uint8_t hours=0);
+char * getTimerString(char * dest, int tme, uint8_t hours=0);
char * getCurveString(char * dest, int idx);
char * getGVarString(char * dest, int idx);
char * getSwitchPositionName(char * dest, swsrc_t idx);
diff --git a/radio/src/switches.cpp b/radio/src/switches.cpp
index d3497dda7..9a7fbb2f8 100644
--- a/radio/src/switches.cpp
+++ b/radio/src/switches.cpp
@@ -126,9 +126,15 @@ uint64_t check3PosSwitchPosition(uint8_t idx, uint8_t sw, bool startup)
void getSwitchesPosition(bool startup)
{
uint64_t newPos = 0;
+#if defined(RADIO_TX12)
+ CHECK_2POS(SW_SA);
+ CHECK_3POS(0, SW_SB);
+ CHECK_3POS(1, SW_SC);
+#else
CHECK_3POS(0, SW_SA);
CHECK_3POS(1, SW_SB);
CHECK_3POS(2, SW_SC);
+#endif
#if defined(PCBX9LITES)
CHECK_2POS(SW_SD);
@@ -146,6 +152,10 @@ void getSwitchesPosition(bool startup)
#elif defined(PCBXLITE)
CHECK_3POS(3, SW_SD);
// no SWE, SWF, SWG and SWH on XLITE
+#elif defined(RADIO_TX12)
+ CHECK_2POS(SW_SD);
+ CHECK_3POS(2, SW_SE);
+ CHECK_3POS(3, SW_SF);
#elif defined(PCBX7)
CHECK_3POS(3, SW_SD);
CHECK_2POS(SW_SF);
@@ -510,14 +520,28 @@ swsrc_t getMovedSwitch()
swsrc_t result = 0;
#if defined(PCBTARANIS) || defined(PCBHORUS)
- for (int i=0; i> (i*2);
- uint8_t next = (1024+getValue(MIXSRC_SA+i)) / 1024;
+ swarnstate_t mask = ((swarnstate_t) 0x03 << (i * 2));
+ uint8_t prev = (switches_states & mask) >> (i * 2);
+ uint8_t next = (1024 + getValue(MIXSRC_SA + i)) / 1024;
if (prev != next) {
- switches_states = (switches_states & (~mask)) | ((swarnstate_t)next << (i*2));
- result = 1+(3*i)+next;
+ switches_states = (switches_states & (~mask)) | ((swarnstate_t) next << (i * 2));
+ result = 1 + (3 * i) + next;
+ }
+ }
+ }
+ // Multipos
+ for (int i = 0; i < NUM_XPOTS; i++) {
+ if (IS_POT_MULTIPOS(POT1 + i)) {
+ StepsCalibData * calib = (StepsCalibData *) &g_eeGeneral.calib[POT1 + i];
+ if (IS_MULTIPOS_CALIBRATED(calib)) {
+ uint8_t prev = potsPos[i] & 0x0F;
+ uint8_t next = anaIn(POT1 + i) / (2 * RESX / calib->count);
+ if (prev != next) {
+ result = SWSRC_LAST_SWITCH + i * XPOTS_MULTIPOS_COUNT + next + 1;
+ }
}
}
}
@@ -653,6 +677,9 @@ void checkSwitches()
}
int x = SWITCH_WARNING_LIST_X;
int y = SWITCH_WARNING_LIST_Y;
+#if defined(COLORLCD)
+ lcdNextPos = SWITCH_WARNING_LIST_X;
+#endif
int numWarnings = 0;
for (int i=0; iSQR2 = (ADC_CHANNEL_BATT << 0) + (ADC_Channel_Vbat << 5);
ADC_MAIN->SQR3 = (ADC_CHANNEL_STICK_LH << 0) + (ADC_CHANNEL_STICK_LV << 5) + (ADC_CHANNEL_STICK_RV << 10) + (ADC_CHANNEL_STICK_RH << 15) + (ADC_CHANNEL_POT1 << 20) + (ADC_CHANNEL_POT2 << 25);
}
+#elif defined(RADIO_T8) || defined(RADIO_TLITE)
+ ADC_MAIN->SQR2 = (ADC_CHANNEL_BATT << 0) + (ADC_Channel_Vbat << 5);
+ ADC_MAIN->SQR3 = (ADC_CHANNEL_STICK_LH << 0) + (ADC_CHANNEL_STICK_LV << 5) + (ADC_CHANNEL_STICK_RV << 10) + (ADC_CHANNEL_STICK_RH << 15);
#elif defined(PCBX7)
ADC_MAIN->SQR2 = (ADC_CHANNEL_BATT << 0) + (ADC_Channel_Vbat << 5);
ADC_MAIN->SQR3 = (ADC_CHANNEL_STICK_LH << 0) + (ADC_CHANNEL_STICK_LV << 5) + (ADC_CHANNEL_STICK_RV << 10) + (ADC_CHANNEL_STICK_RH << 15) + (ADC_CHANNEL_POT1 << 20) + (ADC_CHANNEL_POT2 << 25);
@@ -134,8 +139,8 @@ void adcInit()
ADC_MAIN->SQR3 = (ADC_CHANNEL_STICK_LH << 0) + (ADC_CHANNEL_STICK_LV << 5) + (ADC_CHANNEL_STICK_RV << 10) + (ADC_CHANNEL_STICK_RH << 15) + (ADC_CHANNEL_POT1 << 20) + (ADC_CHANNEL_POT2 << 25);
#endif
- ADC_MAIN->SMPR1 = (ADC_SAMPTIME << 0) + (ADC_SAMPTIME << 3) + (ADC_SAMPTIME << 6) + (ADC_SAMPTIME << 9) + (ADC_SAMPTIME << 12) + (ADC_SAMPTIME << 15) + (ADC_SAMPTIME << 18) + (ADC_SAMPTIME << 21) + (ADC_SAMPTIME << 24);
- ADC_MAIN->SMPR2 = (ADC_SAMPTIME << 0) + (ADC_SAMPTIME << 3) + (ADC_SAMPTIME << 6) + (ADC_SAMPTIME << 9) + (ADC_SAMPTIME << 12) + (ADC_SAMPTIME << 15) + (ADC_SAMPTIME << 18) + (ADC_SAMPTIME << 21) + (ADC_SAMPTIME << 24) + (ADC_SAMPTIME << 27);
+ ADC_MAIN->SMPR1 = ADC_MAIN_SMPR1;
+ ADC_MAIN->SMPR2 = ADC_MAIN_SMPR2;
ADC->CCR = ADC_CCR_VBATE; // Enable vbat sensor
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 e646c30d9..86082f7f8 100644
--- a/radio/src/targets/common/arm/stm32/aux_serial_driver.cpp
+++ b/radio/src/targets/common/arm/stm32/aux_serial_driver.cpp
@@ -21,16 +21,12 @@
#include "opentx.h"
#include "targets/horus/board.h"
-#if defined(SBUS)
-extern Fifo trainerSbusFifo;
-#endif
-
#if defined(AUX_SERIAL)
-uint8_t auxSerialMode = 0;
+uint8_t auxSerialMode = UART_MODE_COUNT; // Prevent debug output before port is setup
Fifo auxSerialTxFifo;
AuxSerialRxFifo auxSerialRxFifo __DMA (AUX_SERIAL_DMA_Stream_RX);
-void auxSerialSetup(unsigned int baudrate, bool dma, uint16_t lenght = USART_WordLength_8b, uint16_t parity = USART_Parity_No, uint16_t stop = USART_StopBits_1)
+void auxSerialSetup(unsigned int baudrate, bool dma, uint16_t length, uint16_t parity, uint16_t stop)
{
USART_InitTypeDef USART_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
@@ -53,7 +49,7 @@ void auxSerialSetup(unsigned int baudrate, bool dma, uint16_t lenght = USART_Wor
#endif
USART_InitStructure.USART_BaudRate = baudrate;
- USART_InitStructure.USART_WordLength = lenght;
+ USART_InitStructure.USART_WordLength = length;
USART_InitStructure.USART_StopBits = stop;
USART_InitStructure.USART_Parity = parity;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
@@ -128,12 +124,12 @@ void auxSerialInit(unsigned int mode, unsigned int protocol)
break;
case UART_MODE_SBUS_TRAINER:
- auxSerialSetup(SBUS_BAUDRATE, false, USART_WordLength_9b, USART_Parity_Even, USART_StopBits_2); // 2 stop bits requires USART_WordLength_9b
+ auxSerialSetup(SBUS_BAUDRATE, true, USART_WordLength_9b, USART_Parity_Even, USART_StopBits_2); // USART_WordLength_9b due to parity bit
AUX_SERIAL_POWER_ON();
break;
case UART_MODE_LUA:
- auxSerialSetup(DEBUG_BAUDRATE, false);
+ auxSerialSetup(LUA_DEFAULT_BAUDRATE, false);
AUX_SERIAL_POWER_ON();
}
}
@@ -213,24 +209,20 @@ extern "C" void AUX_SERIAL_USART_IRQHandler(void)
#if defined(LUA) & !defined(CLI)
if (luaRxFifo && auxSerialMode == UART_MODE_LUA)
luaRxFifo->push(data);
-#endif
-#if !defined(BOOT)
- if (auxSerialMode == UART_MODE_SBUS_TRAINER)
- trainerSbusFifo.push(data);
#endif
}
status = AUX_SERIAL_USART->SR;
}
-#endif
}
-#endif
+#endif // SIMU
+#endif // AUX_SERIAL
#if defined(AUX2_SERIAL)
-uint8_t aux2SerialMode = 0;
+uint8_t aux2SerialMode = UART_MODE_COUNT; // Prevent debug output before port is setup
Fifo aux2SerialTxFifo;
AuxSerialRxFifo aux2SerialRxFifo __DMA (AUX2_SERIAL_DMA_Stream_RX);
-void aux2SerialSetup(unsigned int baudrate, bool dma, uint16_t lenght = USART_WordLength_8b, uint16_t parity = USART_Parity_No, uint16_t stop = USART_StopBits_1)
+void aux2SerialSetup(unsigned int baudrate, bool dma, uint16_t length, uint16_t parity, uint16_t stop)
{
USART_InitTypeDef USART_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
@@ -253,7 +245,7 @@ void aux2SerialSetup(unsigned int baudrate, bool dma, uint16_t lenght = USART_Wo
#endif
USART_InitStructure.USART_BaudRate = baudrate;
- USART_InitStructure.USART_WordLength = lenght;
+ USART_InitStructure.USART_WordLength = length;
USART_InitStructure.USART_StopBits = stop;
USART_InitStructure.USART_Parity = parity;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
@@ -328,12 +320,12 @@ void aux2SerialInit(unsigned int mode, unsigned int protocol)
break;
case UART_MODE_SBUS_TRAINER:
- aux2SerialSetup(SBUS_BAUDRATE, false, USART_WordLength_9b, USART_Parity_Even, USART_StopBits_2); // 2 stop bits requires USART_WordLength_9b
+ aux2SerialSetup(SBUS_BAUDRATE, true, USART_WordLength_9b, USART_Parity_Even, USART_StopBits_2); // 2 stop bits requires USART_WordLength_9b
AUX2_SERIAL_POWER_ON();
break;
case UART_MODE_LUA:
- aux2SerialSetup(DEBUG_BAUDRATE, false);
+ aux2SerialSetup(LUA_DEFAULT_BAUDRATE, false);
AUX2_SERIAL_POWER_ON();
}
}
@@ -404,7 +396,6 @@ extern "C" void AUX2_SERIAL_USART_IRQHandler(void)
}
}
#endif
-#if defined(AUX2_SERIAL)
// Receive
uint32_t status = AUX2_SERIAL_USART->SR;
while (status & (USART_FLAG_RXNE | USART_FLAG_ERRORS)) {
@@ -415,17 +406,10 @@ extern "C" void AUX2_SERIAL_USART_IRQHandler(void)
if (luaRxFifo && aux2SerialMode == UART_MODE_LUA) {
luaRxFifo->push(data);
}
-#endif
-#if !defined(BOOT)
- if (aux2SerialMode == UART_MODE_SBUS_TRAINER) {
- trainerSbusFifo.push(data);
- }
#endif
}
status = AUX2_SERIAL_USART->SR;
}
}
-#endif
-
-#endif
-#endif // AUX_SERIAL
\ No newline at end of file
+#endif // SIMU
+#endif // AUX2_SERIAL
diff --git a/radio/src/targets/common/arm/stm32/bootloader/CMakeLists.txt b/radio/src/targets/common/arm/stm32/bootloader/CMakeLists.txt
index b94180761..3f57a743a 100644
--- a/radio/src/targets/common/arm/stm32/bootloader/CMakeLists.txt
+++ b/radio/src/targets/common/arm/stm32/bootloader/CMakeLists.txt
@@ -89,14 +89,14 @@ set(BOOTLOADER_SRC
bin_files.cpp
)
-if(PCB STREQUAL X12S OR PCB STREQUAL X10 OR PCB STREQUAL X9E OR (PCB STREQUAL X9D+ AND PCBREV STREQUAL 2019) OR (PCB STREQUAL X7 AND NOT (PCBREV STREQUAL T12)) OR PCB STREQUAL X9LITE OR PCB STREQUAL X9LITES)
+if(ROTARY_ENCODER)
set(BOOTLOADER_SRC
${BOOTLOADER_SRC}
../../../../../targets/common/arm/stm32/rotary_encoder_driver.cpp
)
endif()
-if(PCB STREQUAL X7 OR PCB STREQUAL XLITE OR PCB STREQUAL XLITES)
+if(BLUETOOTH)
set(BOOTLOADER_SRC
${BOOTLOADER_SRC}
../../../../../targets/common/arm/stm32/bluetooth_driver.cpp
diff --git a/radio/src/targets/common/arm/stm32/bootloader/boot.cpp b/radio/src/targets/common/arm/stm32/bootloader/boot.cpp
index cd337fb7f..e94ae4756 100644
--- a/radio/src/targets/common/arm/stm32/bootloader/boot.cpp
+++ b/radio/src/targets/common/arm/stm32/bootloader/boot.cpp
@@ -218,8 +218,13 @@ int main()
}
}
+#if defined(RADIO_T8) && !defined(RADIOMASTER_RELEASE)
+ // Bind button not pressed
+ if ((~KEYS_GPIO_REG_BIND & KEYS_GPIO_PIN_BIND) == false) {
+#else
// LHR & RHL trims not pressed simultanously
if (readTrims() != BOOTLOADER_KEYS) {
+#endif
// Start main application
jumpTo(APP_START_ADDRESS);
}
@@ -247,7 +252,7 @@ int main()
backlightInit();
backlightEnable();
-#if defined(PCBX7) || defined(PCBXLITE)
+#if defined(BLUETOOTH)
// we shutdown the bluetooth module now to be sure it will be detected on firmware start
bluetoothInit(BLUETOOTH_DEFAULT_BAUDRATE, false);
#endif
diff --git a/radio/src/targets/common/arm/stm32/heartbeat_driver.cpp b/radio/src/targets/common/arm/stm32/heartbeat_driver.cpp
index 25544c33a..269b40854 100644
--- a/radio/src/targets/common/arm/stm32/heartbeat_driver.cpp
+++ b/radio/src/targets/common/arm/stm32/heartbeat_driver.cpp
@@ -19,6 +19,7 @@
*/
#include "opentx.h"
+#include "mixer_scheduler.h"
#if defined(INTMODULE_HEARTBEAT_GPIO)
volatile HeartbeatCapture heartbeatCapture;
@@ -77,6 +78,8 @@ void check_intmodule_heartbeat()
heartbeatCapture.count++;
#endif
EXTI_ClearITPendingBit(INTMODULE_HEARTBEAT_EXTI_LINE);
+
+ mixerSchedulerISRTrigger();
}
}
#endif
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 56b71d97c..e918f174a 100755
--- a/radio/src/targets/common/arm/stm32/intmodule_serial_driver.cpp
+++ b/radio/src/targets/common/arm/stm32/intmodule_serial_driver.cpp
@@ -45,12 +45,6 @@ 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()
@@ -103,28 +97,6 @@ void intmoduleSerialStart(uint32_t baudrate, uint8_t rxEnable, uint16_t parity,
}
}
-#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)
{
@@ -197,7 +169,7 @@ void intmoduleSendBuffer(const uint8_t * data, uint8_t size)
void intmoduleSendNextFrame()
{
- switch(moduleState[INTERNAL_MODULE].protocol) {
+ switch (moduleState[INTERNAL_MODULE].protocol) {
#if defined(PXX2)
case PROTOCOL_CHANNELS_PXX2_HIGHSPEED:
intmoduleSendBuffer(intmodulePulsesData.pxx2.getData(), intmodulePulsesData.pxx2.getSize());
@@ -217,12 +189,3 @@ void intmoduleSendNextFrame()
#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/mixer_scheduler_driver.cpp b/radio/src/targets/common/arm/stm32/mixer_scheduler_driver.cpp
new file mode 100644
index 000000000..7f7b23a1c
--- /dev/null
+++ b/radio/src/targets/common/arm/stm32/mixer_scheduler_driver.cpp
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ */
+
+#include "opentx.h"
+#include "mixer_scheduler.h"
+
+#if !defined(SIMU)
+
+// Start scheduler with default period
+void mixerSchedulerStart()
+{
+ MIXER_SCHEDULER_TIMER->CR1 &= ~TIM_CR1_CEN;
+
+ MIXER_SCHEDULER_TIMER->CR1 = TIM_CR1_URS; // do not generate interrupt on soft update
+ MIXER_SCHEDULER_TIMER->PSC = MIXER_SCHEDULER_TIMER_FREQ / 2000000 - 1; // 0.5uS (2Mhz)
+ MIXER_SCHEDULER_TIMER->CCER = 0;
+ MIXER_SCHEDULER_TIMER->CCMR1 = 0;
+ MIXER_SCHEDULER_TIMER->ARR = 2 * getMixerSchedulerPeriod() - 1;
+ MIXER_SCHEDULER_TIMER->EGR = TIM_EGR_UG; // reset timer
+
+ NVIC_EnableIRQ(MIXER_SCHEDULER_TIMER_IRQn);
+ NVIC_SetPriority(MIXER_SCHEDULER_TIMER_IRQn, 8);
+
+ MIXER_SCHEDULER_TIMER->SR &= TIM_SR_UIF; // clear interrupt flag
+ MIXER_SCHEDULER_TIMER->DIER |= TIM_DIER_UIE; // enable interrupt
+ MIXER_SCHEDULER_TIMER->CR1 |= TIM_CR1_CEN;
+}
+
+void mixerSchedulerStop()
+{
+ MIXER_SCHEDULER_TIMER->CR1 &= ~TIM_CR1_CEN;
+ NVIC_DisableIRQ(MIXER_SCHEDULER_TIMER_IRQn);
+}
+
+void mixerSchedulerResetTimer()
+{
+ mixerSchedulerDisableTrigger();
+ MIXER_SCHEDULER_TIMER->CNT = 0;
+ mixerSchedulerEnableTrigger();
+}
+
+void mixerSchedulerEnableTrigger()
+{
+ MIXER_SCHEDULER_TIMER->DIER |= TIM_DIER_UIE; // enable interrupt
+}
+
+void mixerSchedulerDisableTrigger()
+{
+ MIXER_SCHEDULER_TIMER->DIER &= ~TIM_DIER_UIE; // disable interrupt
+}
+
+extern "C" void MIXER_SCHEDULER_TIMER_IRQHandler(void)
+{
+ MIXER_SCHEDULER_TIMER->SR &= ~TIM_SR_UIF; // clear flag
+ mixerSchedulerDisableTrigger();
+
+ // set next period
+ MIXER_SCHEDULER_TIMER->ARR = 2 * getMixerSchedulerPeriod() - 1;
+
+ // trigger mixer start
+ mixerSchedulerISRTrigger();
+}
+
+#endif
diff --git a/radio/src/targets/common/arm/stm32/pwr_driver.cpp b/radio/src/targets/common/arm/stm32/pwr_driver.cpp
index 220b5fdfd..32ff59195 100644
--- a/radio/src/targets/common/arm/stm32/pwr_driver.cpp
+++ b/radio/src/targets/common/arm/stm32/pwr_driver.cpp
@@ -80,7 +80,7 @@ void pwrInit()
GPIO_Init(SD_PRESENT_GPIO, &GPIO_InitStructure);
#endif
-#if defined(INTMODULE_USART) && defined(TRAINER_MODULE_CPPM_GPIO_PIN)
+#if defined(INTMODULE_USART) && defined(TRAINER_MODULE_CPPM)
GPIO_SetBits(TRAINER_MODULE_CPPM_GPIO, TRAINER_MODULE_CPPM_GPIO_PIN);
GPIO_InitStructure.GPIO_Pin = TRAINER_MODULE_CPPM_GPIO_PIN;
GPIO_Init(TRAINER_MODULE_CPPM_GPIO, &GPIO_InitStructure);
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 00b3c76f8..570e134b1 100644
--- a/radio/src/targets/common/arm/stm32/rotary_encoder_driver.cpp
+++ b/radio/src/targets/common/arm/stm32/rotary_encoder_driver.cpp
@@ -71,7 +71,7 @@ void rotaryEncoderInit()
void rotaryEncoderCheck()
{
-#if defined(RADIO_FAMILY_T16) && !defined(RADIO_T18)
+#if (defined(RADIO_FAMILY_T16) && !defined(RADIO_T18)) || defined(RADIO_TX12)
static uint8_t state = 0;
uint8_t pins = ROTARY_ENCODER_POSITION();
diff --git a/radio/src/targets/common/arm/stm32/sdio_sd.c b/radio/src/targets/common/arm/stm32/sdio_sd.c
index f02916b44..f0f97b97f 100644
--- a/radio/src/targets/common/arm/stm32/sdio_sd.c
+++ b/radio/src/targets/common/arm/stm32/sdio_sd.c
@@ -1107,7 +1107,9 @@ OPTIMIZE("O0") SD_Error SD_WaitReadOperation(uint32_t timeout)
delay_ms(1);
timeout--;
}
+#if !defined(BOOT)
TRACE_SD_CARD_EVENT((timeout == 0), sd_wait_read, (TransferError << 8) + (DMAEndOfTransfer << 1) + TransferEnd);
+#endif
DMAEndOfTransfer = 0;
@@ -1117,7 +1119,9 @@ OPTIMIZE("O0") SD_Error SD_WaitReadOperation(uint32_t timeout)
delay_ms(1);
timeout--;
}
+#if !defined(BOOT)
TRACE_SD_CARD_EVENT((timeout == 0), sd_wait_read, -1);
+#endif
if (StopCondition == 1) {
errorstatus = SD_StopTransfer();
@@ -1332,8 +1336,10 @@ OPTIMIZE("O0") SD_Error SD_WaitWriteOperation(uint32_t timeout)
delay_ms(1);
timeout--;
}
+#if !defined(BOOT)
TRACE_SD_CARD_EVENT((timeout == 0), sd_wait_write, (TransferError << 8) + (DMAEndOfTransfer << 1) + TransferEnd);
-
+#endif
+
DMAEndOfTransfer = 0;
timeout = 100;
@@ -1342,7 +1348,9 @@ OPTIMIZE("O0") SD_Error SD_WaitWriteOperation(uint32_t timeout)
delay_ms(1);
timeout--;
}
+#if !defined(BOOT)
TRACE_SD_CARD_EVENT((timeout == 0), sd_wait_write, -1);
+#endif
if (StopCondition == 1) {
errorstatus = SD_StopTransfer();
@@ -1474,7 +1482,9 @@ OPTIMIZE("O0") void SD_ProcessIRQ(void)
SDIO_IT_TXFIFOHE | SDIO_IT_RXFIFOHF | SDIO_IT_TXUNDERR |
SDIO_IT_RXOVERR | SDIO_IT_STBITERR, DISABLE);
+#if !defined(BOOT)
TRACE_SD_CARD_EVENT((TransferError != SD_OK), sd_irq, TransferError);
+#endif
}
/**
diff --git a/radio/src/targets/common/arm/stm32/usb_driver.h b/radio/src/targets/common/arm/stm32/usb_driver.h
index 90e1ccd84..350ceace0 100644
--- a/radio/src/targets/common/arm/stm32/usb_driver.h
+++ b/radio/src/targets/common/arm/stm32/usb_driver.h
@@ -21,6 +21,8 @@
#ifndef OPENTX_USB_DRIVER_H
#define OPENTX_USB_DRIVER_H
+#include
+
// USB driver
enum usbMode {
USB_UNSELECTED_MODE,
diff --git a/radio/src/targets/common/arm/stm32/usbd_desc.c b/radio/src/targets/common/arm/stm32/usbd_desc.c
index 527a6c0f5..c43359c8a 100644
--- a/radio/src/targets/common/arm/stm32/usbd_desc.c
+++ b/radio/src/targets/common/arm/stm32/usbd_desc.c
@@ -54,29 +54,32 @@
* @{
*/
-#define USBD_VID 0x0483
+#define USBD_VID_STM 0x0483 // STM Vendor ID
+#define USBD_VID_PID_CODES 0x1209 // https://pid.codes
#define USBD_LANGID_STRING 0x409
-#define USBD_MANUFACTURER_STRING "FrSky"
+#define USBD_MANUFACTURER_STRING "OpenTX"
#define USBD_SERIALNUMBER_FS_STRING "00000000001B"
-
#if defined(BOOT)
#define USBD_MSC_PRODUCT_FS_STRING USB_NAME " Bootloader"
#else
#define USBD_MSC_PRODUCT_FS_STRING USB_NAME " Mass Storage"
#endif
+#define USBD_MSC_VID USBD_VID_STM
#define USBD_MSC_PID 0x5720
#define USBD_MSC_CONFIGURATION_FS_STRING "MSC Config"
#define USBD_MSC_INTERFACE_FS_STRING "MSC Interface"
-#define USBD_HID_PID 0x5710
+#define USBD_HID_VID USBD_VID_PID_CODES
+#define USBD_HID_PID 0x4F54 // OpenTX assigned PID
#define USBD_HID_PRODUCT_FS_STRING USB_NAME " Joystick"
#define USBD_HID_CONFIGURATION_FS_STRING "HID Config"
#define USBD_HID_INTERFACE_FS_STRING "HID Interface"
-#define USBD_CDC_PID 0x5740 // do not change, this ID is used by the ST USB driver for Windows
+#define USBD_CDC_VID USBD_VID_STM
+#define USBD_CDC_PID 0x5740 // do not change, this ID is used by the ST USB driver for Windows
#define USBD_CDC_PRODUCT_FS_STRING USB_NAME " Serial Port"
#define USBD_CDC_CONFIGURATION_FS_STRING "VSP Config"
#define USBD_CDC_INTERFACE_FS_STRING "VSP Interface"
@@ -126,20 +129,29 @@ __ALIGN_BEGIN uint8_t USBD_StrDesc[USB_MAX_STR_DESC_SIZ] __ALIGN_END ; // modifi
* @param length : pointer to data length variable
* @retval pointer to descriptor buffer
*/
-uint8_t * USBD_USR_DeviceDescriptor( uint8_t speed , uint16_t *length)
+uint8_t * USBD_USR_DeviceDescriptor( uint8_t speed , uint16_t *length)
{
- int pid=0;
+ int vid, pid;
switch (getSelectedUsbMode()) {
case USB_JOYSTICK_MODE:
+ vid = USBD_HID_VID;
pid = USBD_HID_PID;
break;
+
case USB_SERIAL_MODE:
+ vid = USBD_CDC_VID;
pid = USBD_CDC_PID;
break;
+
case USB_MASS_STORAGE_MODE:
+ vid = USBD_MSC_VID;
pid = USBD_MSC_PID;
break;
+
+ default:
+ vid = 0;
+ pid = 0;
}
/* USB Standard Device Descriptor */
@@ -153,10 +165,10 @@ uint8_t * USBD_USR_DeviceDescriptor( uint8_t speed , uint16_t *length)
0x00, /*bDeviceSubClass*/
0x00, /*bDeviceProtocol*/
USB_OTG_MAX_EP0_SIZE, /*bMaxPacketSize*/
- LOBYTE(USBD_VID), /*idVendor*/
- HIBYTE(USBD_VID), /*idVendor*/
- LOBYTE(pid), /*idVendor*/
- HIBYTE(pid), /*idVendor*/
+ LOBYTE(vid), /*idVendor*/
+ HIBYTE(vid), /*idVendor*/
+ LOBYTE(pid), /*idVendor*/
+ HIBYTE(pid), /*idVendor*/
0x00, /*bcdDevice rel. 2.00*/
0x02,
USBD_IDX_MFC_STR, /*Index of manufacturer string*/
diff --git a/radio/src/targets/horus/CMakeLists.txt b/radio/src/targets/horus/CMakeLists.txt
index 525c8a4ad..40454fde3 100644
--- a/radio/src/targets/horus/CMakeLists.txt
+++ b/radio/src/targets/horus/CMakeLists.txt
@@ -4,6 +4,8 @@ option(PXX1 "PXX1 protocol support" ON)
option(PXX2 "PXX2 protocol support" OFF)
option(AFHDS3 "AFHDS3 TX Module" ON)
option(MULTIMODULE "DIY Multiprotocol TX Module (https://github.com/pascallanger/DIY-Multiprotocol-TX-Module)" ON)
+option(GHOST "Ghost TX Module" ON)
+option(HARDWARE_EXTERNAL_ACCESS_MOD "Support for R9M 2019 hardware mod" OFF)
set(PWR_BUTTON "PRESS" CACHE STRING "Pwr button type (PRESS/SWITCH)")
set(CPU_TYPE STM32F4)
@@ -18,6 +20,8 @@ set(LINKER_SCRIPT targets/horus/stm32f4_flash.ld)
set(RTC_BACKUP_RAM YES)
set(PPM_LIMITS_SYMETRICAL YES)
set(USB_SERIAL ON CACHE BOOL "Enable USB serial (CDC)")
+set(ROTARY_ENCODER YES)
+set(EXTERNAL_MODULE YES)
# for size report script
set(CPU_TYPE_FULL STM32F429xI)
@@ -48,6 +52,8 @@ if (PCB STREQUAL X10)
option(INTERNAL_MODULE_PXX2 "Support for PXX2 internal module" ON)
set(BLUETOOTH ON)
add_definitions(-DHARDWARE_POWER_MANAGEMENT_UNIT)
+ add_definitions(-DRADIO_X10E)
+ add_definitions(-DMANUFACTURER_FRSKY)
elseif (PCBREV STREQUAL T16)
set(FLAVOUR t16)
set(LUA_EXPORT lua_export_t16)
@@ -55,6 +61,7 @@ if (PCB STREQUAL X10)
add_definitions(-DRADIO_FAMILY_T16)
option(INTERNAL_MODULE_MULTI "Support for MULTI internal module" OFF)
option(BLUETOOTH "Support for bluetooth module" OFF)
+ add_definitions(-DMANUFACTURER_JUMPER)
elseif (PCBREV STREQUAL TX16S)
set(FLAVOUR tx16s)
set(LUA_EXPORT lua_export_t16)
@@ -68,6 +75,7 @@ if (PCB STREQUAL X10)
set(DEFAULT_THEME "DARKBLUE")
set(SBUS_TRAINER ON)
set(AUX_SERIAL ON)
+ add_definitions(-DMANUFACTURER_RADIOMASTER)
if (NOT BLUETOOTH AND NOT INTERNAL_GPS)
set(AUX2_SERIAL ON)
endif()
@@ -79,11 +87,13 @@ if (PCB STREQUAL X10)
add_definitions(-DRADIO_FAMILY_T16)
option(INTERNAL_MODULE_MULTI "Support for MULTI internal module" ON)
option(BLUETOOTH "Support for bluetooth module" OFF)
+ add_definitions(-DMANUFACTURER_JUMPER)
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)
+ add_definitions(-DMANUFACTURER_FRSKY)
endif()
elseif (PCB STREQUAL X12S)
option(INTERNAL_MODULE_PXX1 "Support for PXX1 internal module" ON)
@@ -110,6 +120,7 @@ elseif (PCB STREQUAL X12S)
set(FONTS_TARGET x12s_fonts)
set(LCD_DRIVER lcd_driver.cpp)
set(LUA_EXPORT lua_export_x12s)
+ add_definitions(-DMANUFACTURER_FRSKY)
endif()
add_definitions(-DPCBREV=${PCBREV})
@@ -137,6 +148,12 @@ if(NOT UNEXPECTED_SHUTDOWN)
add_definitions(-DNO_UNEXPECTED_SHUTDOWN)
endif()
+if(HARDWARE_EXTERNAL_ACCESS_MOD)
+ set(PXX2 ON)
+ set(AUX_SERIAL OFF)
+ add_definitions(-DHARDWARE_EXTERNAL_ACCESS_MOD)
+endif()
+
if(INTERNAL_MODULE_PXX1)
add_definitions(-DHARDWARE_INTERNAL_MODULE)
add_definitions(-DINTERNAL_MODULE_PXX1)
@@ -157,6 +174,10 @@ if(INTERNAL_MODULE_MULTI)
add_definitions(-DINTERNAL_MODULE_MULTI)
endif()
+if(EXTERNAL_MODULE)
+ add_definitions(-DHARDWARE_EXTERNAL_MODULE)
+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)
@@ -202,6 +223,10 @@ if(PXX2)
set(GUI_SRC ${GUI_SRC} radio_power_meter.cpp)
endif()
+if(GHOST)
+ set(GUI_SRC ${GUI_SRC} radio_ghost_menu.cpp)
+endif()
+
if(DISK_CACHE)
set(SRC ${SRC} disk_cache.cpp)
add_definitions(-DDISK_CACHE)
@@ -221,6 +246,7 @@ set(TARGET_SRC
led_driver.cpp
extmodule_driver.cpp
trainer_driver.cpp
+ ../common/arm/stm32/mixer_scheduler_driver.cpp
../common/arm/stm32/heartbeat_driver.cpp
../common/arm/stm32/timers_driver.cpp
../common/arm/stm32/intmodule_serial_driver.cpp
diff --git a/radio/src/targets/horus/board.cpp b/radio/src/targets/horus/board.cpp
index cb379e6fe..0f3f9df4a 100644
--- a/radio/src/targets/horus/board.cpp
+++ b/radio/src/targets/horus/board.cpp
@@ -137,6 +137,7 @@ void boardInit()
INTMODULE_RCC_APB1Periph |
EXTMODULE_RCC_APB1Periph |
I2C_RCC_APB1Periph |
+ MIXER_SCHEDULER_TIMER_RCC_APB1Periph |
GPS_RCC_APB1Periph |
BACKLIGHT_RCC_APB1Periph,
ENABLE);
diff --git a/radio/src/targets/horus/board.h b/radio/src/targets/horus/board.h
index e4e99d40f..2b71dab39 100644
--- a/radio/src/targets/horus/board.h
+++ b/radio/src/targets/horus/board.h
@@ -89,6 +89,8 @@ enum {
#elif defined(PCBX10)
#if defined(PCBREV_EXPRESS)
#define IS_FIRMWARE_COMPATIBLE_WITH_BOARD() (hardwareOptions.pcbrev == PCBREV_X10_EXPRESS)
+ #elif defined(RADIO_FAMILY_T16)
+ #define IS_FIRMWARE_COMPATIBLE_WITH_BOARD() (true)
#else
#define IS_FIRMWARE_COMPATIBLE_WITH_BOARD() (hardwareOptions.pcbrev == PCBREV_X10_STD)
#endif
@@ -178,14 +180,11 @@ void init_intmodule_heartbeat();
void check_intmodule_heartbeat();
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();
-void extmoduleSerialStart(uint32_t baudrate, uint32_t period_half_us, bool inverted);
+void extmoduleSerialStart();
void extmoduleInvertedSerialStart(uint32_t baudrate);
void extmoduleSendBuffer(const uint8_t * data, uint8_t size);
void extmoduleSendNextFrame();
@@ -379,7 +378,7 @@ enum Analogs {
SLIDER_LAST = SLIDER_FIRST + NUM_SLIDERS - 1,
TX_VOLTAGE,
#if defined(PCBX12S)
- MOUSE1, // TODO why after voltage?
+ MOUSE1, // after voltage because previous ones come from SPI on X12S
MOUSE2,
#endif
NUM_ANALOGS
@@ -544,7 +543,8 @@ void backlightInit();
#else
void backlightEnable(uint8_t dutyCycle = 0);
#endif
-#define BACKLIGHT_LEVEL_MAX 100
+#define BACKLIGHT_LEVEL_MAX 100
+#define BACKLIGHT_FORCED_ON BACKLIGHT_LEVEL_MAX + 1
#if defined(PCBX12S)
#define BACKLIGHT_LEVEL_MIN 5
#elif defined(RADIO_FAMILY_T16)
@@ -552,7 +552,7 @@ void backlightEnable(uint8_t dutyCycle = 0);
#else
#define BACKLIGHT_LEVEL_MIN 46
#endif
-#define BACKLIGHT_ENABLE() backlightEnable(globalData.unexpectedShutdown ? BACKLIGHT_LEVEL_MAX : BACKLIGHT_LEVEL_MAX - g_eeGeneral.backlightBright)
+#define BACKLIGHT_ENABLE() backlightEnable(globalData.unexpectedShutdown ? BACKLIGHT_LEVEL_MAX : BACKLIGHT_LEVEL_MAX - currentBacklightBright)
#define BACKLIGHT_DISABLE() backlightEnable(globalData.unexpectedShutdown ? BACKLIGHT_LEVEL_MAX : ((g_eeGeneral.blOffBright == BACKLIGHT_LEVEL_MIN) && (g_eeGeneral.backlightMode != e_backlight_mode_off)) ? 0 : g_eeGeneral.blOffBright)
#define isBacklightEnabled() true
@@ -572,9 +572,9 @@ void usbJoystickUpdate();
#define USB_MANUFACTURER 'J', 'u', 'm', 'p', 'e', 'r', ' ', ' ' /* 8 bytes */
#define USB_PRODUCT 'T', '1', '8', ' ', ' ', ' ', ' ', ' ' /* 8 Bytes */
#elif defined(RADIO_TX16S)
- #define USB_NAME "RadioMas TX16S"
- #define USB_MANUFACTURER 'R', 'a', 'd', 'i', 'o', 'M', 'a', 's' /* 8 bytes */
- #define USB_PRODUCT 'T', 'X', '1', '6', 'S', ' ', ' ', ' ' /* 8 Bytes */
+ #define USB_NAME "RM TX16S"
+ #define USB_MANUFACTURER 'R', 'M', '_', 'T', 'X', ' ', ' ', ' ' /* 8 bytes */
+ #define USB_PRODUCT 'R', 'M', ' ', 'T', 'X', '1', '6', 'S' /* 8 Bytes */
#elif defined(PCBX10)
#define USB_NAME "FrSky X10"
#define USB_MANUFACTURER 'F', 'r', 'S', 'k', 'y', ' ', ' ', ' ' /* 8 bytes */
@@ -632,9 +632,18 @@ void sportUpdatePowerInit();
#endif
// Aux serial port driver
+#if defined(RADIO_TX16S)
+ #define DEBUG_BAUDRATE 400000
+ #define LUA_DEFAULT_BAUDRATE 115200
+#else
+ #define DEBUG_BAUDRATE 115200
+ #define LUA_DEFAULT_BAUDRATE 115200
+#endif
#if defined(AUX_SERIAL_GPIO)
-#define DEBUG_BAUDRATE 115200
extern uint8_t auxSerialMode;
+#if defined __cplusplus
+void auxSerialSetup(unsigned int baudrate, bool dma, uint16_t length = USART_WordLength_8b, uint16_t parity = USART_Parity_No, uint16_t stop = USART_StopBits_1);
+#endif
void auxSerialInit(unsigned int mode, unsigned int protocol);
void auxSerialPutc(char c);
#define auxSerialTelemetryInit(protocol) auxSerialInit(UART_MODE_TELEMETRY, protocol)
@@ -654,6 +663,9 @@ void auxSerialPowerOff();
// Aux2 serial port driver
#if defined(AUX2_SERIAL)
extern uint8_t aux2SerialMode;
+#if defined __cplusplus
+void aux2SerialSetup(unsigned int baudrate, bool dma, uint16_t length = USART_WordLength_8b, uint16_t parity = USART_Parity_No, uint16_t stop = USART_StopBits_1);
+#endif
void aux2SerialInit(unsigned int mode, unsigned int protocol);
void aux2SerialPutc(char c);
#define aux2SerialTelemetryInit(protocol) aux2SerialInit(UART_MODE_TELEMETRY, protocol)
@@ -706,6 +718,7 @@ void bluetoothDisable();
extern DMAFifo<512> telemetryFifo;
typedef DMAFifo<32> AuxSerialRxFifo;
extern AuxSerialRxFifo auxSerialRxFifo;
+extern AuxSerialRxFifo aux2SerialRxFifo;
extern volatile uint32_t externalModulePort;
#endif
diff --git a/radio/src/targets/horus/extmodule_driver.cpp b/radio/src/targets/horus/extmodule_driver.cpp
index 9c04aeb21..e73d5c3d3 100644
--- a/radio/src/targets/horus/extmodule_driver.cpp
+++ b/radio/src/targets/horus/extmodule_driver.cpp
@@ -143,7 +143,7 @@ void extmodulePxx1PulsesStart()
}
#endif
-void extmoduleSerialStart(uint32_t /*baudrate*/, uint32_t period_half_us, bool inverted)
+void extmoduleSerialStart()
{
EXTERNAL_MODULE_ON();
@@ -176,10 +176,9 @@ void extmoduleSerialStart(uint32_t /*baudrate*/, uint32_t period_half_us, bool i
EXTMODULE_TIMER->CCMR1 = TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_0;
#endif
- EXTMODULE_TIMER->ARR = period_half_us;
- EXTMODULE_TIMER->CCR2 = period_half_us - 4000;
+ EXTMODULE_TIMER->ARR = 40000; // dummy value until the DMA request kicks in
EXTMODULE_TIMER->SR &= ~TIM_SR_CC2IF; // Clear flag
- EXTMODULE_TIMER->DIER |= TIM_DIER_UDE | TIM_DIER_CC2IE;
+ EXTMODULE_TIMER->DIER |= TIM_DIER_UDE;
EXTMODULE_TIMER->CR1 |= TIM_CR1_CEN;
NVIC_EnableIRQ(EXTMODULE_TIMER_DMA_STREAM_IRQn);
@@ -342,23 +341,36 @@ void extmoduleSendNextFrame()
#if defined(DSM2)
case PROTOCOL_CHANNELS_SBUS:
-#if defined(PCBX10) || PCBREV >= 13
- EXTMODULE_TIMER->CCER = TIM_CCER_CC3E | (GET_SBUS_POLARITY(EXTERNAL_MODULE) ? TIM_CCER_CC3P : 0); // reverse polarity for Sbus if needed
-#else
- EXTMODULE_TIMER->CCER = TIM_CCER_CC1E | (GET_SBUS_POLARITY(EXTERNAL_MODULE) ? TIM_CCER_CC1P : 0); // reverse polarity for Sbus if needed
-#endif
- // no break
case PROTOCOL_CHANNELS_DSM2_LP45:
case PROTOCOL_CHANNELS_DSM2_DSM2:
case PROTOCOL_CHANNELS_DSM2_DSMX:
case PROTOCOL_CHANNELS_MULTIMODULE:
- EXTMODULE_TIMER->CCR2 = *(extmodulePulsesData.dsm2.ptr - 1) - 4000; // 2mS in advance
+
+ if (EXTMODULE_TIMER_DMA_STREAM->CR & DMA_SxCR_EN)
+ return;
+
+ if (PROTOCOL_CHANNELS_SBUS == moduleState[EXTERNAL_MODULE].protocol) {
+#if defined(PCBX10) || PCBREV >= 13
+ EXTMODULE_TIMER->CCER = TIM_CCER_CC3E | (GET_SBUS_POLARITY(EXTERNAL_MODULE) ? TIM_CCER_CC3P : 0); // reverse polarity for Sbus if needed
+#else
+ EXTMODULE_TIMER->CCER = TIM_CCER_CC1E | (GET_SBUS_POLARITY(EXTERNAL_MODULE) ? TIM_CCER_CC1P : 0); // reverse polarity for Sbus if needed
+#endif
+ }
+
+ // disable timer
+ EXTMODULE_TIMER->CR1 &= ~TIM_CR1_CEN;
+
+ // send DMA request
EXTMODULE_TIMER_DMA_STREAM->CR &= ~DMA_SxCR_EN; // Disable DMA
EXTMODULE_TIMER_DMA_STREAM->CR |= EXTMODULE_TIMER_DMA_CHANNEL | DMA_SxCR_DIR_0 | DMA_SxCR_MINC | EXTMODULE_TIMER_DMA_SIZE | DMA_SxCR_PL_0 | DMA_SxCR_PL_1;
EXTMODULE_TIMER_DMA_STREAM->PAR = CONVERT_PTR_UINT(&EXTMODULE_TIMER->ARR);
EXTMODULE_TIMER_DMA_STREAM->M0AR = CONVERT_PTR_UINT(extmodulePulsesData.dsm2.pulses);
EXTMODULE_TIMER_DMA_STREAM->NDTR = extmodulePulsesData.dsm2.ptr - extmodulePulsesData.dsm2.pulses;
EXTMODULE_TIMER_DMA_STREAM->CR |= DMA_SxCR_EN | DMA_SxCR_TCIE; // Enable DMA
+
+ // re-init timer
+ EXTMODULE_TIMER->EGR = 1;
+ EXTMODULE_TIMER->CR1 |= TIM_CR1_CEN;
break;
#endif
@@ -368,6 +380,12 @@ void extmoduleSendNextFrame()
break;
#endif
+#if defined(GHOST)
+ case PROTOCOL_CHANNELS_GHOST:
+ sportSendBuffer(extmodulePulsesData.ghost.pulses, extmodulePulsesData.ghost.length);
+ break;
+#endif
+
default:
EXTMODULE_TIMER->DIER |= TIM_DIER_CC2IE;
break;
@@ -413,14 +431,20 @@ extern "C" void EXTMODULE_TIMER_DMA_IRQHandler()
DMA_ClearITPendingBit(EXTMODULE_TIMER_DMA_STREAM, EXTMODULE_TIMER_DMA_FLAG_TC);
- EXTMODULE_TIMER->SR &= ~TIM_SR_CC2IF; // Clear flag
- EXTMODULE_TIMER->DIER |= TIM_DIER_CC2IE; // Enable this interrupt
+ switch (moduleState[EXTERNAL_MODULE].protocol) {
+ case PROTOCOL_CHANNELS_PXX1_PULSES:
+ case PROTOCOL_CHANNELS_PPM:
+ EXTMODULE_TIMER->SR &= ~TIM_SR_CC2IF; // Clear flag
+ EXTMODULE_TIMER->DIER |= TIM_DIER_CC2IE; // Enable this interrupt
+ break;
+ }
}
extern "C" void EXTMODULE_TIMER_IRQHandler()
{
EXTMODULE_TIMER->DIER &= ~TIM_DIER_CC2IE; // Stop this interrupt
EXTMODULE_TIMER->SR &= ~TIM_SR_CC2IF;
+
if (setupPulsesExternalModule())
extmoduleSendNextFrame();
}
diff --git a/radio/src/targets/horus/hal.h b/radio/src/targets/horus/hal.h
index dd8f6ec70..22a646a2d 100644
--- a/radio/src/targets/horus/hal.h
+++ b/radio/src/targets/horus/hal.h
@@ -329,6 +329,9 @@
#endif
#endif
+#define ADC_MAIN_SMPR1 (ADC_SAMPTIME << 0) + (ADC_SAMPTIME << 3) + (ADC_SAMPTIME << 6) + (ADC_SAMPTIME << 9) + (ADC_SAMPTIME << 12) + (ADC_SAMPTIME << 15) + (ADC_SAMPTIME << 18) + (ADC_SAMPTIME << 21) + (ADC_SAMPTIME << 24);
+#define ADC_MAIN_SMPR2 (ADC_SAMPTIME << 0) + (ADC_SAMPTIME << 3) + (ADC_SAMPTIME << 6) + (ADC_SAMPTIME << 9) + (ADC_SAMPTIME << 12) + (ADC_SAMPTIME << 15) + (ADC_SAMPTIME << 18) + (ADC_SAMPTIME << 21) + (ADC_SAMPTIME << 24) + (ADC_SAMPTIME << 27);
+
// Power
#if defined(RADIO_T18)
#define PWR_RCC_AHB1Periph RCC_AHB1Periph_GPIOJ | RCC_AHB1Periph_GPIOB
@@ -402,7 +405,7 @@
#endif
// Serial Port (DEBUG)
-#if defined(PCBX12S) || defined(RADIO_TX16S)
+#if (defined(PCBX12S) || (defined(RADIO_TX16S)) && !defined(HARDWARE_EXTERNAL_ACCESS_MOD))
#define AUX_SERIAL_RCC_AHB1Periph (RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_DMA1)
#define AUX_SERIAL_RCC_APB1Periph RCC_APB1Periph_USART3
#define AUX_SERIAL_RCC_APB2Periph 0
@@ -417,9 +420,9 @@
#define AUX_SERIAL_USART_IRQn USART3_IRQn
#define AUX_SERIAL_DMA_Stream_RX DMA1_Stream1
#define AUX_SERIAL_DMA_Channel_RX DMA_Channel_4
- #define AUX_SERIAL_PWR_GPIO GPIOA
- #define AUX_SERIAL_PWR_GPIO_PIN GPIO_Pin_15 // PB.00
#if defined(RADIO_TX16S)
+ #define AUX_SERIAL_PWR_GPIO GPIOA
+ #define AUX_SERIAL_PWR_GPIO_PIN GPIO_Pin_15 // PA.15
#define TRAINER_BATTERY_COMPARTMENT // allows serial port TTL trainer
#endif
#else
@@ -445,6 +448,9 @@
#define AUX2_SERIAL_DMA_Channel_RX DMA_Channel_5
#define AUX2_SERIAL_PWR_GPIO GPIOB
#define AUX2_SERIAL_PWR_GPIO_PIN GPIO_Pin_0 // PB.00
+#if defined(RADIO_TX16S)
+ #define TRAINER_BATTERY_COMPARTMENT // allows serial port TTL trainer
+#endif
#elif defined(RADIO_TX16S) && defined(INTERNAL_GPS)
#define GPS_RCC_AHB1Periph (RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOG)
#define GPS_RCC_APB1Periph 0
@@ -762,7 +768,7 @@
#define INTMODULE_BOOTCMD_GPIO_PIN GPIO_Pin_9 // PI.09
#endif
#define INIT_INTMODULE_BOOTCMD_PIN() GPIO_ResetBits(INTMODULE_BOOTCMD_GPIO, INTMODULE_BOOTCMD_GPIO_PIN);
-#if defined(PCBX10) || PCBREV >= 13
+#if (defined(PCBX10) || PCBREV >= 13) && !defined(HARDWARE_EXTERNAL_ACCESS_MOD) //TIM2 used by ext mod
#define INTMODULE_RCC_APB1Periph RCC_APB1Periph_TIM2
#define INTMODULE_RCC_APB2Periph RCC_APB2Periph_USART1
#define INTMODULE_TIMER TIM2
@@ -782,7 +788,7 @@
#define EXTMODULE_PWR_GPIO GPIOB
#define EXTMODULE_PWR_GPIO_PIN GPIO_Pin_3 // PB.03
#define EXTERNAL_MODULE_PWR_OFF() GPIO_ResetBits(EXTMODULE_PWR_GPIO, EXTMODULE_PWR_GPIO_PIN)
-#if defined(PCBX10) && defined(PCBREV_EXPRESS)
+#if (defined(PCBX10) && defined(PCBREV_EXPRESS)) || defined(HARDWARE_EXTERNAL_ACCESS_MOD)
#define EXTMODULE_RCC_AHB1Periph (RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_DMA1)
#define EXTMODULE_RCC_APB1Periph (RCC_APB1Periph_TIM2 | RCC_APB1Periph_USART3)
#define EXTMODULE_RCC_APB2Periph 0
@@ -861,7 +867,7 @@
#define INTMODULE_HEARTBEAT_EXTI_LINE EXTI_Line12
#define INTMODULE_HEARTBEAT_EXTI_IRQn EXTI15_10_IRQn
#define INTMODULE_HEARTBEAT_REUSE_INTERRUPT_ROTARY_ENCODER
-#if defined(PXX2)
+#if defined(INTERNAL_MODULE_PXX2)
#define INTMODULE_HEARTBEAT_TRIGGER EXTI_Trigger_Falling
#else
#define INTMODULE_HEARTBEAT_TRIGGER EXTI_Trigger_Rising
@@ -899,6 +905,13 @@
#define TIMER_2MHz_RCC_APB1Periph RCC_APB1Periph_TIM7
#define TIMER_2MHz_TIMER TIM7
+// Mixer scheduler timer
+#define MIXER_SCHEDULER_TIMER_RCC_APB1Periph RCC_APB1Periph_TIM13
+#define MIXER_SCHEDULER_TIMER TIM13
+#define MIXER_SCHEDULER_TIMER_FREQ (PERI1_FREQUENCY * TIMER_MULT_APB1)
+#define MIXER_SCHEDULER_TIMER_IRQn TIM8_UP_TIM13_IRQn
+#define MIXER_SCHEDULER_TIMER_IRQHandler TIM8_UP_TIM13_IRQHandler
+
// Bluetooth
#define STORAGE_BLUETOOTH
#if defined(BLUETOOTH)
diff --git a/radio/src/targets/horus/lcd_driver.cpp b/radio/src/targets/horus/lcd_driver.cpp
index 751aa88cd..97ecc5a61 100644
--- a/radio/src/targets/horus/lcd_driver.cpp
+++ b/radio/src/targets/horus/lcd_driver.cpp
@@ -141,29 +141,19 @@ static void LCD_NRSTConfig(void)
GPIO_Init(LCD_GPIO_NRST, &GPIO_InitStructure);
}
-// TODO delay function
-static void delay3(uint32_t nCount)
-{
- uint32_t index = 0;
- for(index = (1000 * 100 * nCount); index != 0; --index)
- {
- __asm("nop\n");
- }
-}
-
static void lcd_reset(void)
{
#if defined(RADIO_T18) // T18 screen has issues if NRST is ever brought low
NRST_HIGH();
#else
NRST_HIGH();
- delay3(1);
+ delay_ms(1);
NRST_LOW(); // RESET();
- delay3(20);
+ delay_ms(20);
NRST_HIGH();
- delay3(30);
+ delay_ms(30);
#endif
}
diff --git a/radio/src/targets/horus/startup_stm32f42_43xxx.s b/radio/src/targets/horus/startup_stm32f42_43xxx.s
index e87226bf2..ad8a89264 100644
--- a/radio/src/targets/horus/startup_stm32f42_43xxx.s
+++ b/radio/src/targets/horus/startup_stm32f42_43xxx.s
@@ -1,16 +1,16 @@
/**
******************************************************************************
- * @file startup_stm32f40_41xxx.s
+ * @file startup_stm32f42_43xx.s
* @author MCD Application Team
* @version V1.3.0
* @date 08-November-2013
- * @brief STM32F40xxx/41xxx Devices vector table for RIDE7 toolchain.
+ * @brief STM32F42xxx/43xxx Devices vector table for RIDE7 toolchain.
* This module performs:
* - Set the initial SP
* - Set the initial PC == Reset_Handler,
* - Set the vector table entries with the exceptions ISR address
* - Configure the clock system and the external SRAM mounted on
- * STM324xG-EVAL board to be used as data memory (optional,
+ * STM32F4xG-EVAL board to be used as data memory (optional,
* to be enabled by user)
* - Branches to main in the C library (which eventually
* calls main()).
@@ -37,7 +37,7 @@
*/
.syntax unified
- .cpu cortex-m3
+ .cpu cortex-m4
.fpu softvfp
.thumb
@@ -69,9 +69,9 @@ defined in linker script */
.section .text.Reset_Handler
.weak Reset_Handler
.type Reset_Handler, %function
-Reset_Handler:
-
- bl pwrResetHandler /*jump to WDT reset handler where soft power control pin is turned on as soon as possible */
+Reset_Handler:
+ ldr sp, =_estack /* set stack pointer */
+ bl pwrResetHandler /* jump to WDT reset handler where soft power control pin is turned on as soon as possible */
/* Copy the data segment initializers from flash to SRAM */
movs r1, #0
@@ -113,7 +113,7 @@ LoopPaintMainStack:
/* Call the clock system intitialization function.*/
bl SystemInit
-/* Call C++ constructors for static objects */
+/* Call static constructors */
bl __libc_init_array
/* Call the application's entry point.*/
bl main
diff --git a/radio/src/targets/horus/telemetry_driver.cpp b/radio/src/targets/horus/telemetry_driver.cpp
index 23318dd7e..165e65933 100644
--- a/radio/src/targets/horus/telemetry_driver.cpp
+++ b/radio/src/targets/horus/telemetry_driver.cpp
@@ -34,6 +34,7 @@ static void telemetryInitDirPin()
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
+ GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Pin = TELEMETRY_DIR_GPIO_PIN;
GPIO_Init(TELEMETRY_DIR_GPIO, &GPIO_InitStructure);
GPIO_ResetBits(TELEMETRY_DIR_GPIO, TELEMETRY_DIR_GPIO_PIN);
@@ -240,6 +241,11 @@ void telemetryPortInvertedRxBit()
void telemetryPortSetDirectionOutput()
{
+#if defined(GHOST) && SPORT_MAX_BAUDRATE < 400000
+ if (isModuleGhost(EXTERNAL_MODULE)) {
+ TELEMETRY_USART->BRR = BRR_400K;
+ }
+#endif
TELEMETRY_DIR_GPIO->BSRRL = TELEMETRY_DIR_GPIO_PIN; // output enable
TELEMETRY_USART->CR1 &= ~USART_CR1_RE; // turn off receiver
}
@@ -252,6 +258,11 @@ void sportWaitTransmissionComplete()
void telemetryPortSetDirectionInput()
{
sportWaitTransmissionComplete();
+#if defined(GHOST) && SPORT_MAX_BAUDRATE < 400000
+ if (isModuleGhost(EXTERNAL_MODULE) && g_eeGeneral.telemetryBaudrate == GHST_TELEMETRY_RATE_115K) {
+ TELEMETRY_USART->BRR = BRR_115K;
+ }
+#endif
TELEMETRY_DIR_GPIO->BSRRH = TELEMETRY_DIR_GPIO_PIN; // output disable
TELEMETRY_USART->CR1 |= USART_CR1_RE; // turn on receiver
}
diff --git a/radio/src/targets/horus/tp_gt911.cpp b/radio/src/targets/horus/tp_gt911.cpp
index 5c4929e95..3bb3ec21d 100644
--- a/radio/src/targets/horus/tp_gt911.cpp
+++ b/radio/src/targets/horus/tp_gt911.cpp
@@ -18,54 +18,204 @@
* GNU General Public License for more details.
*/
+#include "opentx.h"
#include "tp_gt911.h"
+#include "touch.h"
+
+//GT911 param table
+const uint8_t TOUCH_GT911_Cfg[] =
+ {
+ GT911_CFG_NUMER, // 0x8047 Config version
+ 0xE0, // 0x8048 X output map : x 480
+ 0x01,
+ 0x10, // 0x804A Y ouptut max : y 272
+ 0x01,
+ GT911_MAX_TP, // 0x804C Touch number
+ 0x3C, // 0x804D Module switch 1 : bit4= xy change Int mode
+ 0x20, // 0x804E Module switch 2
+ 0x22, // 0x804F Shake_Count
+ 0x0A, // 0x8050 Filter
+ 0x28, // 0x8051 Larger touch
+ 0x0F, // 0x8052 Noise reduction
+ 0x5A, // 0x8053 Screen touch level
+ 0x3C, // 0x8054 Screen touch leave
+ 0x03, // 0x8055 Low power control
+ 0x05, // 0x8056 Refresh rate
+ 0x00, // 0x8057 X threshold
+ 0x00, // 0x8058 Y threshold
+ 0x00, // 0x8059 Reserved
+ 0x00, // 0x805A Reserved
+ 0x11, // 0x805B Space (top, bottom)
+ 0x11, // 0x805C Space (left, right)
+ 0x08, // 0x805D Mini filter
+ 0x18, // 0x805E Strech R0
+ 0x1A, // 0x805F Strech R1
+ 0x1E, // 0x8060 Strech R2
+ 0x14, // 0x8061 Strech RM
+ 0x87, // 0x8062 Drv groupA num
+ 0x29, // 0x8063 Drv groupB num
+ 0x0A, // 0x8064 Sensor num
+ 0xCF, // 0x8065 FreqA factor
+ 0xD1, // 0x8066 FreqB factor
+ 0xB2, // 0x8067 Panel bit freq
+ 0x04,
+ 0x00, // 0x8069 Reserved
+ 0x00,
+ 0x00, // 0x806B Panel tx gain
+ 0xD8, // 0x806C Panel rx gain
+ 0x02, // 0x806D Panel dump shift
+ 0x1D, // 0x806E Drv frame control
+ 0x00, // 0x806F Charging level up
+ 0x01, // 0x8070 Module switch 3
+ 0x00, // 0x8071 Gesture distance
+ 0x00, // 0x8072 Gesture long press time
+ 0x00, // 0x8073 X/Y slope adjust
+ 0x00, // 0x8074 Gesture control
+ 0x00, // 0x8075 Gesture switch 1
+ 0x00, // 0x8076 Gesture switch 2
+ 0x00, // 0x8077 Gesture refresh rate
+ 0x00, // 0x8078 Gesture touch level
+ 0x00, // 0x8079 New green wake up level
+ 0xB4, // 0x807A Freq hopping start
+ 0xEF, // 0x807B Freq hopping end
+ 0x94, // 0x807C Noise detect time
+ 0xD5, // 0x807D Hopping flag
+ 0x02, // 0x807E Hopping flag
+ 0x07, // 0x807F Noise threshold
+ 0x00, // 0x8080 Nois min threshold old
+ 0x00, // 0x8081 Reserved
+ 0x04, // 0x8082 Hopping sensor group
+ 0x6E, // 0x8083 Hopping Seg1 normalize
+ 0xB9, // 0x8084 Hopping Seg1 factor
+ 0x00, // 0x8085 Main clock adjust
+ 0x6A, // 0x8086 Hopping Seg2 normalize
+ 0xC4, // 0x8087 Hopping Seg2 factor
+ 0x00, // 0x8088 Reserved
+ 0x66, // 0x8089 Hopping Seg3 normalize
+ 0xCF, // 0x808A Hopping Seg3 factor
+ 0x00, // 0x808B Reserved
+ 0x62, // 0x808C Hopping Seg4 normalize
+ 0xDB, // 0x808D Hopping Seg4 factor
+ 0x00, // 0x808E Reserved
+ 0x5E, // 0x808F Hopping Seg5 normalize
+ 0xE8, // 0x8090 Hopping Seg5 factor
+ 0x00, // 0x8091 Reserved
+ 0x5E, // 0x8092 Hopping Seg6 normalize
+ 0x00, // 0x8093 Key1
+ 0x00, // 0x8094 Key2
+ 0x00, // 0x8095 Key3
+ 0x00, // 0x8096 Key4
+ 0x00, // 0x8097 Key area
+ 0x00, // 0x8098 Key touch level
+ 0x00, // 0x8099 Key leave level
+ 0x00, // 0x809A Key sens
+ 0x00, // 0x809B Key sens
+ 0x00, // 0x809C Key restrain
+ 0x00, // 0x809D Key restrain time
+ 0x00, // 0x809E Large gesture touch
+ 0x00, // 0x809F Reserved
+ 0x00, // 0x80A0 Reserved
+ 0x00, // 0x80A1 Hotknot noise map
+ 0x00, // 0x80A2 Link threshold
+ 0x00, // 0x80A3 Pxy threshold
+ 0x00, // 0x80A4 GHot dump shift
+ 0x00, // 0x80A5 GHot rx gain
+ 0x00, // 0x80A6 Freg gain
+ 0x00, // 0x80A7 Freg gain 1
+ 0x00, // 0x80A8 Freg gain 2
+ 0x00, // 0x80A9 Freg gain 3
+ 0x00, // 0x80AA Reserved
+ 0x00, // 0x80AB Reserved
+ 0x00, // 0x80AC Reserved
+ 0x00, // 0x80AD Reserved
+ 0x00, // 0x80AE Reserved
+ 0x00, // 0x80AF Reserved
+ 0x00, // 0x80B0 Reserved
+ 0x00, // 0x80B1 Reserved
+ 0x00, // 0x80B2 Reserved
+ 0x00, // 0x80B3 Combine dis
+ 0x00, // 0x80B4 Split set
+ 0x00, // 0x80B5 Reserved
+ 0x00, // 0x80B6 Reserved
+ 0x14, // 0x80B7 Sensor CH0
+ 0x12, // 0x80B8 Sensor CH1
+ 0x10, // 0x80B9 Sensor CH2
+ 0x0E, // 0x80BA Sensor CH3
+ 0x0C, // 0x80BB Sensor CH4
+ 0x0A, // 0x80BC Sensor CH5
+ 0x08, // 0x80BD Sensor CH6
+ 0x06, // 0x80BE Sensor CH7
+ 0x04, // 0x80BF Sensor CH8
+ 0x02, // 0x80C0 Sensor CH9
+ 0xFF, // 0x80C1 Sensor CH10
+ 0xFF, // 0x80C2 Sensor CH11
+ 0xFF, // 0x80C3 Sensor CH12
+ 0xFF, // 0x80C4 Sensor CH13
+ 0x00, // 0x80C5 Reserved
+ 0x00, // 0x80C6 Reserved
+ 0x00, // 0x80C7 Reserved
+ 0x00, // 0x80C8 Reserved
+ 0x00, // 0x80C9 Reserved
+ 0x00, // 0x80CA Reserved
+ 0x00, // 0x80CB Reserved
+ 0x00, // 0x80CC Reserved
+ 0x00, // 0x80CD Reserved
+ 0x00, // 0x80CE Reserved
+ 0x00, // 0x80CF Reserved
+ 0x00, // 0x80D0 Reserved
+ 0x00, // 0x80D1 Reserved
+ 0x00, // 0x80D2 Reserved
+ 0x00, // 0x80D3 Reserved
+ 0x00, // 0x80D4 Reserved
+ 0x28, // 0x80D5 Driver CH0
+ 0x26, // 0x80D6 Driver CH1
+ 0x24, // 0x80D7 Driver CH2
+ 0x22, // 0x80D8 Driver CH3
+ 0x21, // 0x80D9 Driver CH4
+ 0x20, // 0x80DA Driver CH5
+ 0x1F, // 0x80DB Driver CH6
+ 0x1E, // 0x80DC Driver CH7
+ 0x1D, // 0x80DD Driver CH8
+ 0x0C, // 0x80DE Driver CH9
+ 0x0A, // 0x80DF Driver CH10
+ 0x08, // 0x80E0 Driver CH11
+ 0x06, // 0x80E1 Driver CH12
+ 0x04, // 0x80E2 Driver CH13
+ 0x02, // 0x80E3 Driver CH14
+ 0x00, // 0x80E4 Driver CH15
+ 0xFF, // 0x80E5 Driver CH16
+ 0xFF, // 0x80E6 Driver CH17
+ 0xFF, // 0x80E7 Driver CH18
+ 0xFF, // 0x80E8 Driver CH19
+ 0xFF, // 0x80E9 Driver CH20
+ 0xFF, // 0x80EA Driver CH21
+ 0xFF, // 0x80EB Driver CH22
+ 0xFF, // 0x80EC Driver CH23
+ 0xFF, // 0x80ED Driver CH24
+ 0xFF, // 0x80EE Driver CH25
+ 0x00, // 0x80EF Reserved
+ 0x00, // 0x80F0 Reserved
+ 0x00, // 0x80F1 Reserved
+ 0x00, // 0x80F2 Reserved
+ 0x00, // 0x80F3 Reserved
+ 0x00, // 0x80F4 Reserved
+ 0x00, // 0x80F5 Reserved
+ 0x00, // 0x80F6 Reserved
+ 0x00, // 0x80F7 Reserved
+ 0x00, // 0x80F8 Reserved
+ 0x00, // 0x80F9 Reserved
+ 0x00, // 0x80FA Reserved
+ 0x00, // 0x80FB Reserved
+ 0x00, // 0x80FC Reserved
+ 0x00, // 0x80FD Reserved
+ 0x00 // 0x80FE Reserved
+ };
uint8_t touchGT911Flag = 0;
-uint8_t touchPanelEvent = 0;
+uint8_t touchEventOccured = 0;
struct TouchData touchData;
struct TouchState touchState;
-void GT911_INT_Change(void)
-{
- GPIO_InitTypeDef GPIO_InitStructure;
-
- GPIO_InitStructure.GPIO_Pin = TOUCH_INT_GPIO_PIN;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
- GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
- GPIO_Init(TOUCH_INT_GPIO, &GPIO_InitStructure);
-}
-
-uint8_t GT911_Send_Cfg(uint8_t mode)
-{
- uint8_t buf[2];
- uint8_t i = 0;
- buf[0] = 0;
- buf[1] = mode;
- for (i = 0; i < sizeof(GT911_Cfg); i++)
- buf[0] += GT911_Cfg[i];//check sum
-
- buf[0] = (~buf[0]) + 1;
- gt911WriteRegister(GT_CFGS_REG, (uint8_t *) GT911_Cfg, sizeof(GT911_Cfg));//
- gt911WriteRegister(GT_CHECK_REG, buf, 2);//write checksum
- return 0;
-}
-
-static void I2C_Config(void)
-{
- GPIO_InitTypeDef GPIO_InitStructure;
- RCC_AHB1PeriphClockCmd(I2C_RCC_AHB1Periph, ENABLE);
- GPIO_InitStructure.GPIO_Pin = I2C_SCL_GPIO_PIN | I2C_SDA_GPIO_PIN;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
- GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
- GPIO_Init(I2C_GPIO, &GPIO_InitStructure);
-
- GPIO_SetBits(I2C_GPIO, I2C_SCL_GPIO_PIN | I2C_SDA_GPIO_PIN);
-}
-
static void TOUCH_AF_ExtiStop(void)
{
SYSCFG_EXTILineConfig(TOUCH_INT_EXTI_PortSource, TOUCH_INT_EXTI_PinSource1);
@@ -99,7 +249,6 @@ static void TOUCH_AF_ExtiConfig(void)
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
-
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = TOUCH_INT_EXTI_IRQn1;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 9;
@@ -130,174 +279,158 @@ static void TOUCH_AF_GPIOConfig(void)
GPIO_ResetBits(TOUCH_INT_GPIO, TOUCH_INT_GPIO_PIN);
}
-void SDA_IN(void)
+void TOUCH_AF_INT_Change(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
- GPIO_InitStructure.GPIO_Pin = I2C_SDA_GPIO_PIN;
+
+ GPIO_InitStructure.GPIO_Pin = TOUCH_INT_GPIO_PIN;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+ GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
+ GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(I2C_GPIO, &GPIO_InitStructure);
+ GPIO_Init(TOUCH_INT_GPIO, &GPIO_InitStructure);
}
-void SDA_OUT(void)
+void I2C_Init()
{
+ I2C_DeInit(I2C);
+
GPIO_InitTypeDef GPIO_InitStructure;
- GPIO_InitStructure.GPIO_Pin = I2C_SDA_GPIO_PIN;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+ I2C_InitTypeDef I2C_InitStructure;
+ I2C_InitStructure.I2C_ClockSpeed = I2C_SPEED;
+ I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
+ I2C_InitStructure.I2C_OwnAddress1 = 0x00;
+ I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
+ I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
+ I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
+ I2C_Init(I2C, &I2C_InitStructure);
+ I2C_Cmd(I2C, ENABLE);
+
+ GPIO_PinAFConfig(I2C_GPIO, I2C_SCL_GPIO_PinSource, I2C_GPIO_AF);
+ GPIO_PinAFConfig(I2C_GPIO, I2C_SDA_GPIO_PinSource, I2C_GPIO_AF);
+
+ GPIO_InitStructure.GPIO_Pin = I2C_SCL_GPIO_PIN | I2C_SDA_GPIO_PIN;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
+ GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
+ GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(I2C_GPIO, &GPIO_InitStructure);
}
-void I2C_Start(void)
+bool I2C_WaitEvent(uint32_t event)
{
- SDA_OUT();
- I2C_SDA_H();
- I2C_SCL_H();
- delay_us(2);
- I2C_SDA_L();//START:when CLK is high,DATA change form high to low
- delay_us(2);
- I2C_SCL_L();//
- delay_us(2);
-}
-
-void I2C_Stop(void)
-{
- SDA_OUT();
- I2C_SCL_L();
- I2C_SDA_L();//STOP:when CLK is high DATA change form low to high
- delay_us(2);
- I2C_SCL_H();
- I2C_SDA_H();//
- delay_us(2);
-}
-
-uint8_t I2C_Wait_Ack(void)
-{
- uint8_t ucErrTime = 0;
- SDA_IN();
- I2C_SDA_H();
- delay_us(2);
- I2C_SCL_H();
- while (READ_SDA) {
- ucErrTime++;
- if (ucErrTime > 166) {
- I2C_Stop();
- return 1;
- }
- delay_us(1);
+ uint32_t timeout = I2C_TIMEOUT_MAX;
+ while (!I2C_CheckEvent(I2C, event)) {
+ if ((timeout--) == 0) return false;
}
- I2C_SDA_L();
- I2C_SCL_L();
+ return true;
+}
+
+bool I2C_WaitEventCleared(uint32_t event)
+{
+ uint32_t timeout = I2C_TIMEOUT_MAX;
+ while (I2C_CheckEvent(I2C, event)) {
+ if ((timeout--) == 0) return false;
+ }
+ return true;
+}
+
+uint8_t I2C_GT911_WriteRegister(uint16_t reg, uint8_t * buf, uint8_t len)
+{
+ if (!I2C_WaitEventCleared(I2C_FLAG_BUSY))
+ return false;
+
+ I2C_GenerateSTART(I2C, ENABLE);
+ if (!I2C_WaitEvent(I2C_EVENT_MASTER_MODE_SELECT))
+ return false;
+
+ I2C_Send7bitAddress(I2C, GT_CMD_WR, I2C_Direction_Transmitter);
+ if (!I2C_WaitEvent(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
+ return false;
+
+ I2C_SendData(I2C, (uint8_t)((reg & 0xFF00) >> 8));
+ if (!I2C_WaitEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTING))
+ return false;
+ I2C_SendData(I2C, (uint8_t)(reg & 0x00FF));
+ if (!I2C_WaitEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTING))
+ return false;
+
+ /* While there is data to be written */
+ while (len--) {
+ I2C_SendData(I2C, *buf);
+ if (!I2C_WaitEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTING))
+ return false;
+ buf++;
+ }
+
+ if (!I2C_WaitEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTED))
+ return false;
+
+ I2C_GenerateSTOP(I2C, ENABLE);
+ return true;
+}
+
+bool I2C_GT911_ReadRegister(u16 reg, uint8_t * buf, uint8_t len)
+{
+ if (!I2C_WaitEventCleared(I2C_FLAG_BUSY))
+ return false;
+
+ I2C_GenerateSTART(I2C, ENABLE);
+ if (!I2C_WaitEvent(I2C_EVENT_MASTER_MODE_SELECT))
+ return false;
+
+ I2C_Send7bitAddress(I2C, GT_CMD_WR, I2C_Direction_Transmitter);
+ if (!I2C_WaitEvent(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
+ return false;
+
+ I2C_SendData(I2C, (uint8_t)((reg & 0xFF00) >> 8));
+ if (!I2C_WaitEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTING))
+ return false;
+ I2C_SendData(I2C, (uint8_t)(reg & 0x00FF));
+ if (!I2C_WaitEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTED))
+ return false;
+
+ I2C_GenerateSTART(I2C, ENABLE);
+ if (!I2C_WaitEvent(I2C_EVENT_MASTER_MODE_SELECT))
+ return false;
+
+ I2C_Send7bitAddress(I2C, GT_CMD_RD, I2C_Direction_Receiver);
+ if (!I2C_WaitEvent(I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))
+ return false;
+
+ if (len > 1) {
+ I2C_AcknowledgeConfig(I2C, ENABLE);
+ }
+
+ while (len) {
+ if (len == 1) {
+ I2C_AcknowledgeConfig(I2C, DISABLE);
+ }
+ if (!I2C_WaitEvent(I2C_EVENT_MASTER_BYTE_RECEIVED))
+ return false;
+ *buf++ = I2C_ReceiveData(I2C);
+ len--;
+ }
+
+ I2C_GenerateSTOP(I2C, ENABLE);
+ return true;
+}
+
+uint8_t I2C_GT911_SendConfig(uint8_t mode)
+{
+ uint8_t buf[2];
+ uint8_t i = 0;
+ buf[0] = 0;
+ buf[1] = mode;
+ for (i = 0; i < sizeof(TOUCH_GT911_Cfg); i++)
+ buf[0] += TOUCH_GT911_Cfg[i];//check sum
+
+ buf[0] = (~buf[0]) + 1;
+ I2C_GT911_WriteRegister(GT_CFGS_REG, (uint8_t *) TOUCH_GT911_Cfg, sizeof(TOUCH_GT911_Cfg));//
+ I2C_GT911_WriteRegister(GT_CHECK_REG, buf, 2);//write checksum
return 0;
}
-void I2C_Ack(void)
-{
- I2C_SCL_L();
- SDA_OUT();
- I2C_SDA_L();
- delay_us(2);
- I2C_SCL_H();
- delay_us(2);
- I2C_SCL_L();
-}
-
-void I2C_NAck(void)
-{
- I2C_SCL_L();
- SDA_OUT();
- I2C_SDA_H();
- delay_us(2);
- I2C_SCL_H();
- delay_us(2);
- I2C_SCL_L();
-}
-
-void I2C_Send_Byte(uint8_t txd)
-{
- uint8_t t;
-
- SDA_OUT();
- I2C_SCL_L();
- for (t = 0; t < 8; t++) {
- if ((txd & 0x80) >> 7)
- I2C_SDA_H();
- else
- I2C_SDA_L();
- txd <<= 1;
- delay_us(1);
- I2C_SCL_H();
- delay_us(2);
- I2C_SCL_L();
- delay_us(1);
- }
-}
-
-uint8_t I2C_Read_Byte(unsigned char ack)
-{
- unsigned char i, receive = 0;
-
- SDA_IN();
- for (i = 0; i < 8; i++) {
- I2C_SCL_L();
- delay_us(2);
- I2C_SCL_H();
- receive <<= 1;
- if (READ_SDA)receive++;
- delay_us(1);
- }
- if (!ack)
- I2C_NAck();
- else
- I2C_Ack();
- return receive;
-}
-
-uint8_t gt911WriteRegister(uint16_t reg, uint8_t * buf, uint8_t len)
-{
- {
- uint8_t i;
- uint8_t ret = 0;
-
- I2C_Start();
- I2C_Send_Byte(GT_CMD_WR); //send cmd
- I2C_Wait_Ack();
- I2C_Send_Byte(reg >> 8); //send hi
- I2C_Wait_Ack();
- I2C_Send_Byte(reg & 0XFF); //send low
- I2C_Wait_Ack();
- for (i = 0; i < len; i++) {
- I2C_Send_Byte(buf[i]);
- ret = I2C_Wait_Ack();
- if (ret)break;
- }
- I2C_Stop();
-
- return ret;
- }
-}
-
-void gt911ReadRegister(u16 reg, uint8_t * buf, uint8_t len)
-{
- uint8_t i;
-
- I2C_Start();
- I2C_Send_Byte(GT_CMD_WR); //send addr
- I2C_Wait_Ack();
- I2C_Send_Byte(reg >> 8); //send hi
- I2C_Wait_Ack();
- I2C_Send_Byte(reg & 0XFF); //send low
- I2C_Wait_Ack();
- I2C_Start();
- I2C_Send_Byte(GT_CMD_RD); //send rd
- I2C_Wait_Ack();
-
- for (i = 0; i < len; i++) {
- buf[i] = I2C_Read_Byte(i == (len - 1) ? 0 : 1); //send data
- }
- I2C_Stop();
-}
-
void touchPanelDeInit(void)
{
TOUCH_AF_ExtiStop();
@@ -307,61 +440,70 @@ bool touchPanelInit(void)
{
uint8_t tmp[4] = {0};
- TRACE("Touchpanel init start ...");
-
- TOUCH_AF_GPIOConfig(); //SET RST=OUT INT=OUT INT=LOW
- I2C_Config();
-
- TPRST_LOW();
- TPINT_HIGH();
- delay_us(200);
-
- TPRST_HIGH();
- delay_ms(6);
-
- TPINT_LOW();
- delay_ms(55);
-
- GT911_INT_Change(); //Set INT INPUT INT=LOW
-
- delay_ms(50);
-
- TRACE("Reading Touch registry");
- gt911ReadRegister(GT_PID_REG, tmp, 4);
-
- if (strcmp((char *) tmp, "911") == 0) //ID==9147
- {
- TRACE("GT911 chip detected");
- tmp[0] = 0X02;
- gt911WriteRegister(GT_CTRL_REG, tmp, 1);
- gt911ReadRegister(GT_CFGS_REG, tmp, 1);
-
- TRACE("Chip config Ver:%x\r\n",tmp[0]);
- if (tmp[0] < GT911_CFG_NUMER) //Config ver
- {
- TRACE("Sending new config %d", GT911_CFG_NUMER);
- GT911_Send_Cfg(1);
- }
-
- delay_ms(10);
- tmp[0] = 0X00;
- gt911WriteRegister(GT_CTRL_REG, tmp, 1); //end reset
- touchGT911Flag = true;
-
+ if (touchGT911Flag) {
TOUCH_AF_ExtiConfig();
-
return true;
}
- TRACE("GT911 chip NOT FOUND");
- return false;
+ else {
+ TRACE("Touchpanel init start ...");
+
+ TOUCH_AF_GPIOConfig(); //SET RST=OUT INT=OUT INT=LOW
+ I2C_Init();
+
+ TPRST_LOW();
+ TPINT_HIGH();
+ delay_us(200);
+
+ TPRST_HIGH();
+ delay_ms(6);
+
+ TPINT_LOW();
+ delay_ms(55);
+
+ TOUCH_AF_INT_Change(); //Set INT INPUT INT=LOW
+
+ delay_ms(50);
+
+ TRACE("Reading Touch registry");
+ I2C_GT911_ReadRegister(GT_PID_REG, tmp, 4);
+
+ if (strcmp((char *) tmp, "911") == 0) //ID==9147
+ {
+ TRACE("GT911 chip detected");
+ tmp[0] = 0X02;
+ I2C_GT911_WriteRegister(GT_CTRL_REG, tmp, 1);
+ I2C_GT911_ReadRegister(GT_CFGS_REG, tmp, 1);
+
+ TRACE("Chip config Ver:%x\r\n", tmp[0]);
+ if (tmp[0] < GT911_CFG_NUMER) //Config ver
+ {
+ TRACE("Sending new config %d", GT911_CFG_NUMER);
+ I2C_GT911_SendConfig(1);
+ }
+
+ delay_ms(10);
+ tmp[0] = 0X00;
+ I2C_GT911_WriteRegister(GT_CTRL_REG, tmp, 1); //end reset
+ touchGT911Flag = true;
+
+ TOUCH_AF_ExtiConfig();
+
+ return true;
+ }
+ TRACE("GT911 chip NOT FOUND");
+ return false;
+ }
}
void touchPanelRead()
{
uint8_t state = 0;
- gt911ReadRegister(GT911_READ_XY_REG, &state, 1);
- touchPanelEvent = false;
+ if (!touchEventOccured)
+ return;
+
+ touchEventOccured = false;
+ I2C_GT911_ReadRegister(GT911_READ_XY_REG, &state, 1);
if ((state & 0x80u) == 0x00) {
// not ready
@@ -371,7 +513,7 @@ void touchPanelRead()
uint8_t pointsCount = (state & 0x0Fu);
if (pointsCount > 0 && pointsCount < GT911_MAX_TP) {
- gt911ReadRegister(GT911_READ_XY_REG + 1, touchData.data, pointsCount * sizeof(TouchPoint));
+ I2C_GT911_ReadRegister(GT911_READ_XY_REG + 1, touchData.data, pointsCount * sizeof(TouchPoint));
if (touchData.pointsCount == 0) {
touchState.event = TE_DOWN;
touchState.startX = touchState.x = touchData.points[0].x;
@@ -399,14 +541,22 @@ void touchPanelRead()
}
uint8_t zero = 0;
- gt911WriteRegister(GT911_READ_XY_REG, &zero, 1);
+ I2C_GT911_WriteRegister(GT911_READ_XY_REG, &zero, 1);
}
extern "C" void TOUCH_INT_EXTI_IRQHandler1(void)
{
if (EXTI_GetITStatus(TOUCH_INT_EXTI_LINE1) != RESET) {
- TRACE("TI");
- touchPanelEvent = 1;
+ if (g_eeGeneral.backlightMode & e_backlight_mode_keys) {
+ // on touch turn the light on
+ resetBacklightTimeout();
+ }
+ touchEventOccured = 1;
EXTI_ClearITPendingBit(TOUCH_INT_EXTI_LINE1);
}
}
+
+bool touchPanelEventOccured()
+{
+ return touchEventOccured;
+}
\ No newline at end of file
diff --git a/radio/src/targets/horus/tp_gt911.h b/radio/src/targets/horus/tp_gt911.h
index 2b5f7d32c..0f9aa98ed 100644
--- a/radio/src/targets/horus/tp_gt911.h
+++ b/radio/src/targets/horus/tp_gt911.h
@@ -21,218 +21,22 @@
#ifndef _FT5X06_H_
#define _FT5X06_H_
-#include "opentx.h"
-#include "touch.h"
-
#define HAS_TOUCH_PANEL() touchGT911Flag == true
-bool touchPanelInit();
-void touchPanelDeInit();
-
extern uint8_t touchGT911Flag;
-extern uint8_t touchPanelEvent;
+extern bool touchPanelInit(void);
+extern void touchPanelDeInit(void);
-uint8_t gt911WriteRegister(uint16_t reg, uint8_t * buf, uint8_t len);
-void gt911ReadRegister(uint16_t reg, uint8_t * buf, uint8_t len);
void touchPanelRead();
+bool touchPanelEventOccured();
-#define GT911_MAX_TP 5
-#define GT911_CFG_NUMER 0x6A
-
-//GT911 param table
-const uint8_t GT911_Cfg[] =
-{
- GT911_CFG_NUMER, // 0x8047 Config version
- 0xE0, // 0x8048 X output map : x 480
- 0x01,
- 0x10, // 0x804A Y ouptut max : y 272
- 0x01,
- GT911_MAX_TP, // 0x804C Touch number
- 0x3C, // 0x804D Module switch 1 : bit4= xy change Int mode
- 0x20, // 0x804E Module switch 2
- 0x22, // 0x804F Shake_Count
- 0x0A, // 0x8050 Filter
- 0x28, // 0x8051 Larger touch
- 0x0F, // 0x8052 Noise reduction
- 0x5A, // 0x8053 Screen touch level
- 0x3C, // 0x8054 Screen touch leave
- 0x03, // 0x8055 Low power control
- 0x05, // 0x8056 Refresh rate
- 0x00, // 0x8057 X threshold
- 0x00, // 0x8058 Y threshold
- 0x00, // 0x8059 Reserved
- 0x00, // 0x805A Reserved
- 0x11, // 0x805B Space (top, bottom)
- 0x11, // 0x805C Space (left, right)
- 0x08, // 0x805D Mini filter
- 0x18, // 0x805E Strech R0
- 0x1A, // 0x805F Strech R1
- 0x1E, // 0x8060 Strech R2
- 0x14, // 0x8061 Strech RM
- 0x87, // 0x8062 Drv groupA num
- 0x29, // 0x8063 Drv groupB num
- 0x0A, // 0x8064 Sensor num
- 0xCF, // 0x8065 FreqA factor
- 0xD1, // 0x8066 FreqB factor
- 0xB2, // 0x8067 Panel bit freq
- 0x04,
- 0x00, // 0x8069 Reserved
- 0x00,
- 0x00, // 0x806B Panel tx gain
- 0xD8, // 0x806C Panel rx gain
- 0x02, // 0x806D Panel dump shift
- 0x1D, // 0x806E Drv frame control
- 0x00, // 0x806F Charging level up
- 0x01, // 0x8070 Module switch 3
- 0x00, // 0x8071 Gesture distance
- 0x00, // 0x8072 Gesture long press time
- 0x00, // 0x8073 X/Y slope adjust
- 0x00, // 0x8074 Gesture control
- 0x00, // 0x8075 Gesture switch 1
- 0x00, // 0x8076 Gesture switch 2
- 0x00, // 0x8077 Gesture refresh rate
- 0x00, // 0x8078 Gesture touch level
- 0x00, // 0x8079 New green wake up level
- 0xB4, // 0x807A Freq hopping start
- 0xEF, // 0x807B Freq hopping end
- 0x94, // 0x807C Noise detect time
- 0xD5, // 0x807D Hopping flag
- 0x02, // 0x807E Hopping flag
- 0x07, // 0x807F Noise threshold
- 0x00, // 0x8080 Nois min threshold old
- 0x00, // 0x8081 Reserved
- 0x04, // 0x8082 Hopping sensor group
- 0x6E, // 0x8083 Hopping Seg1 normalize
- 0xB9, // 0x8084 Hopping Seg1 factor
- 0x00, // 0x8085 Main clock adjust
- 0x6A, // 0x8086 Hopping Seg2 normalize
- 0xC4, // 0x8087 Hopping Seg2 factor
- 0x00, // 0x8088 Reserved
- 0x66, // 0x8089 Hopping Seg3 normalize
- 0xCF, // 0x808A Hopping Seg3 factor
- 0x00, // 0x808B Reserved
- 0x62, // 0x808C Hopping Seg4 normalize
- 0xDB, // 0x808D Hopping Seg4 factor
- 0x00, // 0x808E Reserved
- 0x5E, // 0x808F Hopping Seg5 normalize
- 0xE8, // 0x8090 Hopping Seg5 factor
- 0x00, // 0x8091 Reserved
- 0x5E, // 0x8092 Hopping Seg6 normalize
- 0x00, // 0x8093 Key1
- 0x00, // 0x8094 Key2
- 0x00, // 0x8095 Key3
- 0x00, // 0x8096 Key4
- 0x00, // 0x8097 Key area
- 0x00, // 0x8098 Key touch level
- 0x00, // 0x8099 Key leave level
- 0x00, // 0x809A Key sens
- 0x00, // 0x809B Key sens
- 0x00, // 0x809C Key restrain
- 0x00, // 0x809D Key restrain time
- 0x00, // 0x809E Large gesture touch
- 0x00, // 0x809F Reserved
- 0x00, // 0x80A0 Reserved
- 0x00, // 0x80A1 Hotknot noise map
- 0x00, // 0x80A2 Link threshold
- 0x00, // 0x80A3 Pxy threshold
- 0x00, // 0x80A4 GHot dump shift
- 0x00, // 0x80A5 GHot rx gain
- 0x00, // 0x80A6 Freg gain
- 0x00, // 0x80A7 Freg gain 1
- 0x00, // 0x80A8 Freg gain 2
- 0x00, // 0x80A9 Freg gain 3
- 0x00, // 0x80AA Reserved
- 0x00, // 0x80AB Reserved
- 0x00, // 0x80AC Reserved
- 0x00, // 0x80AD Reserved
- 0x00, // 0x80AE Reserved
- 0x00, // 0x80AF Reserved
- 0x00, // 0x80B0 Reserved
- 0x00, // 0x80B1 Reserved
- 0x00, // 0x80B2 Reserved
- 0x00, // 0x80B3 Combine dis
- 0x00, // 0x80B4 Split set
- 0x00, // 0x80B5 Reserved
- 0x00, // 0x80B6 Reserved
- 0x14, // 0x80B7 Sensor CH0
- 0x12, // 0x80B8 Sensor CH1
- 0x10, // 0x80B9 Sensor CH2
- 0x0E, // 0x80BA Sensor CH3
- 0x0C, // 0x80BB Sensor CH4
- 0x0A, // 0x80BC Sensor CH5
- 0x08, // 0x80BD Sensor CH6
- 0x06, // 0x80BE Sensor CH7
- 0x04, // 0x80BF Sensor CH8
- 0x02, // 0x80C0 Sensor CH9
- 0xFF, // 0x80C1 Sensor CH10
- 0xFF, // 0x80C2 Sensor CH11
- 0xFF, // 0x80C3 Sensor CH12
- 0xFF, // 0x80C4 Sensor CH13
- 0x00, // 0x80C5 Reserved
- 0x00, // 0x80C6 Reserved
- 0x00, // 0x80C7 Reserved
- 0x00, // 0x80C8 Reserved
- 0x00, // 0x80C9 Reserved
- 0x00, // 0x80CA Reserved
- 0x00, // 0x80CB Reserved
- 0x00, // 0x80CC Reserved
- 0x00, // 0x80CD Reserved
- 0x00, // 0x80CE Reserved
- 0x00, // 0x80CF Reserved
- 0x00, // 0x80D0 Reserved
- 0x00, // 0x80D1 Reserved
- 0x00, // 0x80D2 Reserved
- 0x00, // 0x80D3 Reserved
- 0x00, // 0x80D4 Reserved
- 0x28, // 0x80D5 Driver CH0
- 0x26, // 0x80D6 Driver CH1
- 0x24, // 0x80D7 Driver CH2
- 0x22, // 0x80D8 Driver CH3
- 0x21, // 0x80D9 Driver CH4
- 0x20, // 0x80DA Driver CH5
- 0x1F, // 0x80DB Driver CH6
- 0x1E, // 0x80DC Driver CH7
- 0x1D, // 0x80DD Driver CH8
- 0x0C, // 0x80DE Driver CH9
- 0x0A, // 0x80DF Driver CH10
- 0x08, // 0x80E0 Driver CH11
- 0x06, // 0x80E1 Driver CH12
- 0x04, // 0x80E2 Driver CH13
- 0x02, // 0x80E3 Driver CH14
- 0x00, // 0x80E4 Driver CH15
- 0xFF, // 0x80E5 Driver CH16
- 0xFF, // 0x80E6 Driver CH17
- 0xFF, // 0x80E7 Driver CH18
- 0xFF, // 0x80E8 Driver CH19
- 0xFF, // 0x80E9 Driver CH20
- 0xFF, // 0x80EA Driver CH21
- 0xFF, // 0x80EB Driver CH22
- 0xFF, // 0x80EC Driver CH23
- 0xFF, // 0x80ED Driver CH24
- 0xFF, // 0x80EE Driver CH25
- 0x00, // 0x80EF Reserved
- 0x00, // 0x80F0 Reserved
- 0x00, // 0x80F1 Reserved
- 0x00, // 0x80F2 Reserved
- 0x00, // 0x80F3 Reserved
- 0x00, // 0x80F4 Reserved
- 0x00, // 0x80F5 Reserved
- 0x00, // 0x80F6 Reserved
- 0x00, // 0x80F7 Reserved
- 0x00, // 0x80F8 Reserved
- 0x00, // 0x80F9 Reserved
- 0x00, // 0x80FA Reserved
- 0x00, // 0x80FB Reserved
- 0x00, // 0x80FC Reserved
- 0x00, // 0x80FD Reserved
- 0x00 // 0x80FE Reserved
-};
+#define GT911_MAX_TP 5
+#define GT911_CFG_NUMER 0x6A
//I2C
#define GT_CMD_WR 0X28
#define GT_CMD_RD 0X29
-
-#define SLAVE_Write_Address 0X28
+#define I2C_TIMEOUT_MAX 1000
//GT9147
#define GT_CTRL_REG 0X8040
@@ -257,8 +61,7 @@ const uint8_t GT911_Cfg[] =
#define GT911_CONFIG_CHECKSUM_REG 0x80FF
#define GT911_FIRMWARE_VERSION_REG 0x8144
-PACK(typedef struct
-{
+PACK(typedef struct {
uint8_t track;
uint16_t x;
uint16_t y;
@@ -266,8 +69,7 @@ PACK(typedef struct
uint8_t reserved;
}) TouchPoint;
-PACK(struct TouchData
-{
+PACK(struct TouchData {
uint8_t pointsCount;
union
{
@@ -276,21 +78,10 @@ PACK(struct TouchData
};
});
-extern struct TouchData touchData;
-
#define TPRST_LOW() do { TOUCH_RST_GPIO->BSRRH = TOUCH_RST_GPIO_PIN; } while(0)
#define TPRST_HIGH() do { TOUCH_RST_GPIO->BSRRL = TOUCH_RST_GPIO_PIN; } while(0)
#define TPINT_LOW() do { TOUCH_INT_GPIO->BSRRH = TOUCH_INT_GPIO_PIN; } while(0)
#define TPINT_HIGH() do { TOUCH_INT_GPIO->BSRRL = TOUCH_INT_GPIO_PIN; } while(0)
-
-#define I2C_SCL_L() do { I2C_GPIO->BSRRH = I2C_SCL_GPIO_PIN; } while(0)
-#define I2C_SCL_H() do { I2C_GPIO->BSRRL = I2C_SCL_GPIO_PIN; } while(0)
-
-#define I2C_SDA_L() do { I2C_GPIO->BSRRH = I2C_SDA_GPIO_PIN; } while(0)
-#define I2C_SDA_H() do { I2C_GPIO->BSRRL = I2C_SDA_GPIO_PIN; } while(0)
-
-#define READ_SDA GPIO_ReadInputDataBit(I2C_GPIO, I2C_SDA_GPIO_PIN)
-
-#endif // _FT5X06_H_
+#endif // _FT5X06_H_
\ No newline at end of file
diff --git a/radio/src/targets/horus/trainer_driver.cpp b/radio/src/targets/horus/trainer_driver.cpp
index 83ec7a542..38d25cb45 100644
--- a/radio/src/targets/horus/trainer_driver.cpp
+++ b/radio/src/targets/horus/trainer_driver.cpp
@@ -20,10 +20,6 @@
#include "opentx.h"
-#if defined(SBUS_TRAINER)
-Fifo trainerSbusFifo;
-#endif
-
void trainerSendNextFrame();
void init_trainer_ppm()
@@ -106,7 +102,7 @@ void trainerSendNextFrame()
{
TRAINER_TIMER->CCR2 = GET_TRAINER_PPM_DELAY() * 2;
TRAINER_TIMER->CCER = TIM_CCER_CC2E | (GET_TRAINER_PPM_POLARITY() ? 0 : TIM_CCER_CC2P);
- TRAINER_TIMER->CCR1 = *(trainerPulsesData.ppm.ptr - 1) - 4000; // 2mS in advance
+ TRAINER_TIMER->CCR3 = *(trainerPulsesData.ppm.ptr - 1) - 4000; // 2mS in advance
TRAINER_DMA_STREAM->CR &= ~DMA_SxCR_EN; // Disable DMA
TRAINER_DMA_STREAM->CR |= TRAINER_DMA_CHANNEL | DMA_SxCR_DIR_0 | DMA_SxCR_MINC | DMA_SxCR_PSIZE_0 | DMA_SxCR_MSIZE_0 | DMA_SxCR_PL_0 | DMA_SxCR_PL_1;
@@ -123,8 +119,8 @@ extern "C" void TRAINER_DMA_IRQHandler()
DMA_ClearITPendingBit(TRAINER_DMA_STREAM, TRAINER_DMA_FLAG_TC);
- TRAINER_TIMER->SR &= ~TIM_SR_CC1IF; // Clear flag
- TRAINER_TIMER->DIER |= TIM_DIER_CC1IE; // Enable this interrupt
+ TRAINER_TIMER->SR &= ~TIM_SR_CC3IF; // Clear flag
+ TRAINER_TIMER->DIER |= TIM_DIER_CC3IE; // Enable this interrupt
}
extern "C" void TRAINER_TIMER_IRQHandler()
@@ -148,10 +144,10 @@ extern "C" void TRAINER_TIMER_IRQHandler()
}
// PPM out compare interrupt
- if ((TRAINER_TIMER->DIER & TIM_DIER_CC1IE) && (TRAINER_TIMER->SR & TIM_SR_CC1IF)) {
+ if ((TRAINER_TIMER->DIER & TIM_DIER_CC3IE) && (TRAINER_TIMER->SR & TIM_SR_CC3IF)) {
// compare interrupt
- TRAINER_TIMER->DIER &= ~TIM_DIER_CC1IE; // stop this interrupt
- TRAINER_TIMER->SR &= ~TIM_SR_CC1IF; // Clear flag
+ TRAINER_TIMER->DIER &= ~TIM_DIER_CC3IE; // stop this interrupt
+ TRAINER_TIMER->SR &= ~TIM_SR_CC3IF; // Clear flag
setupPulsesPPMTrainer();
trainerSendNextFrame();
}
@@ -160,11 +156,18 @@ extern "C" void TRAINER_TIMER_IRQHandler()
int sbusGetByte(uint8_t * byte)
{
switch (currentTrainerMode) {
-#if defined(AUX_SERIAL)
+#if defined(AUX_SERIAL) || defined(AUX2_SERIAL)
case TRAINER_MODE_MASTER_BATTERY_COMPARTMENT:
- return trainerSbusFifo.pop(*byte);
+#if defined(AUX_SERIAL)
+ if (auxSerialMode == UART_MODE_SBUS_TRAINER)
+ return auxSerialRxFifo.pop(*byte);
+#endif
+#if defined(AUX2_SERIAL)
+ if (aux2SerialMode == UART_MODE_SBUS_TRAINER)
+ return aux2SerialRxFifo.pop(*byte);
+#endif
#endif
default:
return false;
}
-}
\ No newline at end of file
+}
diff --git a/radio/src/targets/simu/opentxsimulator.cpp b/radio/src/targets/simu/opentxsimulator.cpp
index f7e4f80e9..df763c8fa 100644
--- a/radio/src/targets/simu/opentxsimulator.cpp
+++ b/radio/src/targets/simu/opentxsimulator.cpp
@@ -213,17 +213,7 @@ void OpenTxSimulator::setTrim(unsigned int idx, int value)
if (i < 4) // swap axes
i = modn12x3[4 * getStickMode() + idx];
uint8_t phase = getTrimFlightMode(getFlightMode(), i);
-
- if (!setTrimValue(phase, i, value)) {
- QTimer *timer = new QTimer(this);
- timer->setSingleShot(true);
- connect(timer, &QTimer::timeout, [=]() {
- emit trimValueChange(idx, 0);
- emit outputValueChange(OUTPUT_SRC_TRIM_VALUE, idx, 0);
- timer->deleteLater();
- });
- timer->start(350);
- }
+ setTrimValue(phase, i, value);
}
void OpenTxSimulator::setTrainerInput(unsigned int inputNumber, int16_t value)
diff --git a/radio/src/targets/simu/simpgmspace.cpp b/radio/src/targets/simu/simpgmspace.cpp
index fa0122175..8402cf4fd 100644
--- a/radio/src/targets/simu/simpgmspace.cpp
+++ b/radio/src/targets/simu/simpgmspace.cpp
@@ -42,6 +42,8 @@ char * main_thread_error = nullptr;
bool simu_shutdown = false;
bool simu_running = false;
+uint32_t telemetryErrors = 0;
+
#if defined(STM32)
GPIO_TypeDef gpioa, gpiob, gpioc, gpiod, gpioe, gpiof, gpiog, gpioh, gpioi, gpioj;
TIM_TypeDef tim1, tim2, tim3, tim4, tim5, tim6, tim7, tim8, tim9, tim10;
@@ -441,6 +443,47 @@ void sportUpdatePowerInit()
{
}
+void telemetryPortSetDirectionInput()
+{
+}
+
+void telemetryPortSetDirectionOutput()
+{
+}
+
+void rxPdcUsart( void (*pChProcess)(uint8_t x) )
+{
+}
+
+void telemetryPortInit(uint32_t baudrate, uint8_t mode)
+{
+}
+
+bool telemetryGetByte(uint8_t * byte)
+{
+ return false;
+}
+
+void telemetryClearFifo()
+{
+}
+
+void telemetryPortInvertedInit(uint32_t baudrate)
+{
+}
+
+void sportSendByte(uint8_t byte)
+{
+}
+
+void sportSendBuffer(const uint8_t * buffer, uint32_t count)
+{
+}
+
+void check_telemetry_exti()
+{
+}
+
void boardInit()
{
}
@@ -768,9 +811,20 @@ void rtcSetTime(const struct gtm * t)
{
}
+#if defined(USB_SERIAL)
+void usbSerialPutc(uint8_t c)
+{
+}
+#endif
+
#if defined(AUX_SERIAL)
AuxSerialRxFifo auxSerialRxFifo(nullptr);
uint8_t auxSerialMode;
+
+void auxSerialSetup(unsigned int baudrate, bool dma, uint16_t length, uint16_t parity, uint16_t stop)
+{
+}
+
void auxSerialInit(unsigned int mode, unsigned int protocol)
{
}
@@ -791,6 +845,11 @@ void auxSerialStop()
#if defined(AUX2_SERIAL)
AuxSerialRxFifo aux2SerialRxFifo(nullptr);
uint8_t aux2SerialMode;
+
+void aux2SerialSetup(unsigned int baudrate, bool dma, uint16_t length, uint16_t parity, uint16_t stop)
+{
+}
+
void aux2SerialInit(unsigned int mode, unsigned int protocol)
{
}
diff --git a/radio/src/targets/sky9x/CMakeLists.txt b/radio/src/targets/sky9x/CMakeLists.txt
index 4188444fe..d09906965 100644
--- a/radio/src/targets/sky9x/CMakeLists.txt
+++ b/radio/src/targets/sky9x/CMakeLists.txt
@@ -11,6 +11,8 @@ set(RADIO_DEPENDENCIES ${RADIO_DEPENDENCIES} 9x_bitmaps)
set(PPM_LIMITS_SYMETRICAL YES)
set(PXX1 YES)
set(AFHDS3 NO)
+set(GHOST NO)
+add_definitions(-DHARDWARE_EXTERNAL_MODULE)
add_definitions(-DDISABLE_MULTI_UPDATE)
if(PCB STREQUAL 9XRPRO)
@@ -121,9 +123,13 @@ set(FIRMWARE_TARGET_SRC
MEDSdcard.c
)
+set(FIRMWARE_TARGET_SRC
+ ${FIRMWARE_TARGET_SRC}
+ telemetry_driver.cpp
+ )
+
set(TARGET_SRC
${TARGET_SRC}
- telemetry_driver.cpp
adc_driver.cpp
pulses_driver.cpp
audio_driver.cpp
diff --git a/radio/src/targets/sky9x/audio_driver.h b/radio/src/targets/sky9x/audio_driver.h
index dc2e14008..9c69d161f 100644
--- a/radio/src/targets/sky9x/audio_driver.h
+++ b/radio/src/targets/sky9x/audio_driver.h
@@ -21,6 +21,8 @@
#ifndef _AUDIO_DRIVER_H_
#define _AUDIO_DRIVER_H_
+#include
+
void audioInit( void ) ;
void audioEnd( void ) ;
void audioConsumeCurrentBuffer();
diff --git a/radio/src/targets/sky9x/board.h b/radio/src/targets/sky9x/board.h
index 8b1c7275c..ca7e23acd 100644
--- a/radio/src/targets/sky9x/board.h
+++ b/radio/src/targets/sky9x/board.h
@@ -269,11 +269,12 @@ extern "C" {
#endif
// Backlight driver
-#define backlightEnable() (PWM->PWM_CH_NUM[0].PWM_CDTY = g_eeGeneral.backlightBright)
+#define backlightEnable() (PWM->PWM_CH_NUM[0].PWM_CDTY = currentBacklightBright)
#define backlightDisable() (PWM->PWM_CH_NUM[0].PWM_CDTY = 100)
#define isBacklightEnabled() (PWM->PWM_CH_NUM[0].PWM_CDTY != 100)
#define BACKLIGHT_ENABLE() backlightEnable()
#define BACKLIGHT_DISABLE() backlightDisable()
+#define BACKLIGHT_FORCED_ON 101
// ADC driver
#define NUM_POTS 3
@@ -394,10 +395,8 @@ void debugPutc(const char c);
// Telemetry driver
void telemetryPortInit(uint32_t baudrate, uint8_t mode);
-inline void telemetryPortSetDirectionOutput()
-{
-}
-uint32_t telemetryTransmitPending();
+void telemetryPortSetDirectionOutput();
+void telemetryPortSetDirectionInput();
void telemetryTransmitBuffer(const uint8_t * buffer, uint32_t size);
void rxPdcUsart( void (*pChProcess)(uint8_t x) );
void sportSendBuffer(const uint8_t * buffer, uint32_t size);
diff --git a/radio/src/targets/sky9x/telemetry_driver.cpp b/radio/src/targets/sky9x/telemetry_driver.cpp
index 4875c5d35..8efa83951 100644
--- a/radio/src/targets/sky9x/telemetry_driver.cpp
+++ b/radio/src/targets/sky9x/telemetry_driver.cpp
@@ -93,10 +93,8 @@ void startPdcUsartReceive()
{
Usart *pUsart = SECOND_USART;
TelemetryInBuffer.outPtr = TelemetryInBuffer.fifo ;
-#ifndef SIMU
pUsart->US_RPR = (uint32_t)TelemetryInBuffer.fifo ;
pUsart->US_RNPR = (uint32_t)TelemetryInBuffer.fifo ;
-#endif
pUsart->US_RCR = RX_UART_BUFFER_SIZE ;
pUsart->US_RNCR = RX_UART_BUFFER_SIZE ;
pUsart->US_PTCR = US_PTCR_RXTEN ;
@@ -104,7 +102,6 @@ void startPdcUsartReceive()
void rxPdcUsart( void (*pChProcess)(uint8_t x) )
{
-#if !defined(SIMU)
Usart *pUsart = SECOND_USART;
uint8_t *ptr ;
uint8_t *endPtr ;
@@ -132,7 +129,6 @@ void rxPdcUsart( void (*pChProcess)(uint8_t x) )
pUsart->US_RNPR = (uint32_t)TelemetryInBuffer.fifo ;
pUsart->US_RNCR = RX_UART_BUFFER_SIZE ;
}
-#endif
}
uint32_t txPdcUsart(const uint8_t * buffer, uint32_t size)
@@ -140,9 +136,7 @@ uint32_t txPdcUsart(const uint8_t * buffer, uint32_t size)
Usart * pUsart = SECOND_USART;
if (pUsart->US_TNCR == 0) {
-#ifndef SIMU
pUsart->US_TNPR = (uint32_t)buffer ;
-#endif
pUsart->US_TNCR = size ;
pUsart->US_PTCR = US_PTCR_TXTEN ;
return 1 ;
@@ -150,6 +144,7 @@ uint32_t txPdcUsart(const uint8_t * buffer, uint32_t size)
return 0 ;
}
+/*
uint32_t telemetryTransmitPending()
{
Usart *pUsart = SECOND_USART;
@@ -164,13 +159,20 @@ uint32_t telemetryTransmitPending()
return x ;
}
+*/
+
+void telemetryPortSetDirectionOutput()
+{
+}
+
+void telemetryPortSetDirectionInput()
+{
+}
void telemetryPortInit(uint32_t baudrate, uint8_t mode)
{
-#if !defined(SIMU)
UART2_Configure(baudrate, Master_frequency, mode);
startPdcUsartReceive();
-#endif
}
void sportSendBuffer(const uint8_t * buffer, uint32_t size)
diff --git a/radio/src/targets/taranis/CMakeLists.txt b/radio/src/targets/taranis/CMakeLists.txt
index b00c7dfba..c292250e1 100644
--- a/radio/src/targets/taranis/CMakeLists.txt
+++ b/radio/src/targets/taranis/CMakeLists.txt
@@ -2,9 +2,13 @@ option(SHUTDOWN_CONFIRMATION "Shutdown confirmation" OFF)
option(LCD_DUAL_BUFFER "Dual LCD Buffer" OFF)
option(PXX1 "PXX1 protocol support" ON)
option(PXX2 "PXX2 protocol support" OFF)
-option(AFHDS3 "AFHDS3 TX Module" OFF)
+option(AFHDS3 "AFHDS3 TX Module" ON)
+option(GHOST "Ghost TX Module" ON)
option(INTERNAL_MODULE_PPM "Support for PPM internal module" OFF)
option(AUTOUPDATE "Auto update internal chips from SD" OFF)
+option(BIND_KEY "Enable bind button" OFF)
+
+set(EXTERNAL_MODULE YES)
if(PCB STREQUAL X9E)
option(INTERNAL_MODULE_PXX1 "Support for PXX1 internal module" ON)
@@ -39,6 +43,7 @@ if(PCB STREQUAL X9E)
set(STATUS_LEDS NO)
set(BLUETOOTH YES)
set(ROTARY_ENCODER YES)
+ add_definitions(-DMANUFACTURER_FRSKY)
elseif(PCB STREQUAL X9D+)
set(HAPTIC YES)
set(LUA_EXPORT lua_export_x9d)
@@ -51,11 +56,14 @@ elseif(PCB STREQUAL X9D+)
set(LCD_DRIVER lcd_driver_spi.cpp)
set(GVAR_SCREEN model_gvars.cpp)
set(PCBREV 2014 CACHE STRING "PCB Revision")
+ set(AFHDS3 NO)
add_definitions(-DPCBREV=${PCBREV})
+ add_definitions(-DMANUFACTURER_FRSKY)
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(FLAVOUR x9d+2019)
+ set(LUA_EXPORT lua_export_x9d+2019)
set(CPU_TYPE STM32F4)
set(CPU_TYPE_FULL STM32F407xE) # for size report
set(LINKER_SCRIPT targets/taranis/stm32f4_flash.ld)
@@ -102,6 +110,8 @@ elseif(PCB STREQUAL X9D)
set(AUX_SERIAL_DRIVER ../common/arm/stm32/aux_serial_driver.cpp)
set(GVAR_SCREEN model_gvars.cpp)
set(STATUS_LEDS NO)
+ add_definitions(-DMANUFACTURER_FRSKY)
+ set(AFHDS3 NO)
elseif(PCB STREQUAL X7)
set(PWR_BUTTON "PRESS" CACHE STRING "Pwr button type (PRESS/SWITCH)")
set(HAPTIC YES)
@@ -122,7 +132,53 @@ elseif(PCB STREQUAL X7)
set(LINKER_SCRIPT targets/taranis/stm32f2_flash.ld)
set(LUA_EXPORT lua_export_t12)
add_definitions(-DRADIO_T12)
+ add_definitions(-DRADIO_FAMILY_JUMPER_T12)
add_definitions(-DEEPROM_VARIANT=0x4001)
+ add_definitions(-DMANUFACTURER_JUMPER)
+ elseif(PCBREV STREQUAL TLITE)
+ option(INTERNAL_MODULE_MULTI "Support for MULTI internal module" ON)
+ set(FLAVOUR tlite)
+ set(NAVIGATION_TYPE 9x)
+ set(CPU_TYPE STM32F2)
+ set(CPU_TYPE_FULL STM32F205xE) # for size report
+ set(LINKER_SCRIPT targets/taranis/stm32f2_flash.ld)
+ set(LUA_EXPORT lua_export_tlite)
+ add_definitions(-DRADIO_TLITE)
+ add_definitions(-DRADIO_FAMILY_JUMPER_T12)
+ add_definitions(-DEEPROM_VARIANT=0x4003)
+ add_definitions(-DMANUFACTURER_JUMPER)
+ elseif(PCBREV STREQUAL TX12)
+ option(INTERNAL_MODULE_MULTI "Support for MULTI internal module" ON)
+ set(FLAVOUR tx12)
+ set(NAVIGATION_TYPE x7)
+ set(CPU_TYPE STM32F2)
+ set(CPU_TYPE_FULL STM32F205xE) # for size report
+ set(LINKER_SCRIPT targets/taranis/stm32f2_flash.ld)
+ set(ROTARY_ENCODER YES)
+ set(LUA_EXPORT lua_export_tx12)
+ set(BLUETOOTH NO)
+ set(USB_CHARGER YES)
+ add_definitions(-DRADIO_TX12)
+ add_definitions(-DEEPROM_VARIANT=0x4002)
+ add_definitions(-DMANUFACTURER_RADIOMASTER)
+ elseif(PCBREV STREQUAL T8)
+ option(INTERNAL_MODULE_MULTI "Support for MULTI internal module" ON)
+ set(EXTERNAL_MODULE NO)
+ set(AFHDS3 NO)
+ set(FLAVOUR t8)
+ set(NAVIGATION_TYPE x7)
+ set(CPU_TYPE STM32F2)
+ set(CPU_TYPE_FULL STM32F205xE) # for size report
+ set(LINKER_SCRIPT targets/taranis/stm32f2_flash.ld)
+ set(ROTARY_ENCODER NO)
+ set(LUA_EXPORT lua_export_t8)
+ set(BLUETOOTH NO)
+ if(RADIOMASTER_RELEASE)
+ set(BIND_KEY YES)
+ endif()
+ add_definitions(-DRADIO_T8)
+ add_definitions(-DEEPROM_VARIANT=0x4004)
+ add_definitions(-DMANUFACTURER_RADIOMASTER)
elseif(PCBREV STREQUAL ACCESS)
option(INTERNAL_MODULE_PXX1 "Support for PXX1 internal module" OFF)
option(INTERNAL_MODULE_PXX2 "Support for PXX2 internal module" ON)
@@ -147,6 +203,7 @@ elseif(PCB STREQUAL X7)
set(BLUETOOTH YES)
set(ROTARY_ENCODER YES)
set(INTERNAL_MODULE_SERIAL YES)
+ add_definitions(-DMANUFACTURER_FRSKY)
else()
option(INTERNAL_MODULE_PXX1 "Support for PXX1 internal module" ON)
option(INTERNAL_MODULE_PXX2 "Support for PXX2 internal module" OFF)
@@ -161,6 +218,7 @@ elseif(PCB STREQUAL X7)
set(BLUETOOTH YES)
add_definitions(-DBLUETOOTH_PROBE)
set(ROTARY_ENCODER YES)
+ add_definitions(-DMANUFACTURER_FRSKY)
if(DEFINED PCBREV_HARDCODED)
# This *can* be used to prevent messing with PA14 (SWCLK), so stlink can be used
# without interruptions.
@@ -195,6 +253,7 @@ elseif(PCB STREQUAL X9LITE)
set(STATUS_LEDS YES)
set(ROTARY_ENCODER YES)
set(INTERNAL_MODULE_SERIAL YES)
+ add_definitions(-DMANUFACTURER_FRSKY)
elseif(PCB STREQUAL X9LITES)
option(INTERNAL_MODULE_PXX1 "Support for PXX1 internal module" OFF)
option(INTERNAL_MODULE_PXX2 "Support for PXX2 internal module" ON)
@@ -221,6 +280,7 @@ elseif(PCB STREQUAL X9LITES)
set(BLUETOOTH YES)
set(ROTARY_ENCODER YES)
set(INTERNAL_MODULE_SERIAL YES)
+ add_definitions(-DMANUFACTURER_FRSKY)
elseif(PCB STREQUAL XLITE)
option(INTERNAL_MODULE_PXX1 "Support for PXX1 internal module" ON)
option(INTERNAL_MODULE_PXX2 "Support for PXX2 internal module" OFF)
@@ -245,6 +305,7 @@ elseif(PCB STREQUAL XLITE)
set(STATUS_LEDS YES)
set(BLUETOOTH YES)
set(INTERNAL_MODULE_SERIAL YES)
+ add_definitions(-DMANUFACTURER_FRSKY)
elseif(PCB STREQUAL XLITES)
option(INTERNAL_MODULE_PXX1 "Support for PXX1 internal module" OFF)
option(INTERNAL_MODULE_PXX2 "Support for PXX2 internal module" ON)
@@ -270,6 +331,7 @@ elseif(PCB STREQUAL XLITES)
set(BLUETOOTH YES)
set(GYRO YES)
set(INTERNAL_MODULE_SERIAL YES)
+ add_definitions(-DMANUFACTURER_FRSKY)
endif()
if(GYRO)
@@ -293,7 +355,7 @@ if(INTERNAL_MODULE_SERIAL)
${TARGET_SRC}
../common/arm/stm32/intmodule_serial_driver.cpp
)
-elseif(NOT (PCB STREQUAL X7 AND PCBREV STREQUAL T12))
+elseif(INTERNAL_MODULE_PXX1 OR INTERNAL_MODULE_PXX2)
set(TARGET_SRC
${TARGET_SRC}
intmodule_pulses_driver.cpp
@@ -307,6 +369,19 @@ if(ROTARY_ENCODER)
)
endif()
+if(BIND_KEY)
+ set(TARGET_SRC
+ ${TARGET_SRC}
+ bind_button_driver.cpp
+ )
+ add_definitions(-DBIND_KEY)
+endif()
+
+if(USB_CHARGER)
+ set(TARGET_SRC ${TARGET_SRC} usb_charger_driver.cpp)
+ add_definitions(-DUSB_CHARGER)
+endif()
+
if(BLUETOOTH)
add_definitions(-DBLUETOOTH)
set(TARGET_SRC
@@ -369,12 +444,12 @@ set(TARGET_SRC
${TARGET_SRC}
${LED_DRIVER}
backlight_driver.cpp
- extmodule_driver.cpp
trainer_driver.cpp
../common/arm/stm32/timers_driver.cpp
../common/arm/stm32/audio_dac_driver.cpp
../common/arm/stm32/adc_driver.cpp
../common/arm/stm32/heartbeat_driver.cpp
+ ../common/arm/stm32/mixer_scheduler_driver.cpp
)
if(PCB STREQUAL XLITE OR PCB STREQUAL XLITES)
@@ -422,4 +497,12 @@ if(INTERNAL_MODULE_PPM)
add_definitions(-DINTERNAL_MODULE_PPM)
endif()
+if(EXTERNAL_MODULE)
+ set(TARGET_SRC
+ ${TARGET_SRC}
+ extmodule_driver.cpp
+ )
+ add_definitions(-DHARDWARE_EXTERNAL_MODULE)
+endif()
+
set(RADIO_DEPENDENCIES ${RADIO_DEPENDENCIES} ${BITMAPS_TARGET})
diff --git a/radio/src/targets/taranis/backlight_driver.cpp b/radio/src/targets/taranis/backlight_driver.cpp
index 63a5bfd1a..7c758f818 100644
--- a/radio/src/targets/taranis/backlight_driver.cpp
+++ b/radio/src/targets/taranis/backlight_driver.cpp
@@ -20,7 +20,13 @@
#include "opentx.h"
-#if defined(PCBX9E)
+#if !defined(BACKLIGHT_GPIO)
+ // no backlight
+ void backlightInit() {}
+ void backlightEnable(uint8_t level) {}
+ void backlightDisable() {}
+ uint8_t isBacklightEnabled() {return false;}
+#elif defined(PCBX9E)
void backlightInit()
{
GPIO_InitTypeDef GPIO_InitStructure;
diff --git a/radio/src/targets/taranis/bind_button_driver.cpp b/radio/src/targets/taranis/bind_button_driver.cpp
new file mode 100644
index 000000000..2d3ca63fc
--- /dev/null
+++ b/radio/src/targets/taranis/bind_button_driver.cpp
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+
+#include "opentx.h"
+
+
+bool setBindProtocolSelection()
+{
+ int16_t xPos = calibratedAnalogs[CONVERT_MODE(0)];
+ int16_t yPos = calibratedAnalogs[CONVERT_MODE(1)];
+
+ // Center: D8
+ if (abs(xPos < 50 && abs(yPos) < 50)) {
+ g_model.moduleData[INTERNAL_MODULE].setMultiProtocol(MODULE_SUBTYPE_MULTI_FRSKY);
+ g_model.moduleData[INTERNAL_MODULE].subType = MM_RF_FRSKY_SUBTYPE_D8;
+ storageDirty(EE_MODEL);
+ return true;
+ }
+
+ // Top left: D16 FCC
+ if (xPos < -512 && yPos > 512) {
+ g_model.moduleData[INTERNAL_MODULE].setMultiProtocol(MODULE_SUBTYPE_MULTI_FRSKY);
+ g_model.moduleData[INTERNAL_MODULE].subType = MM_RF_FRSKY_SUBTYPE_D16;
+ g_model.moduleData[INTERNAL_MODULE].failsafeMode = FAILSAFE_NOPULSES;
+ storageDirty(EE_MODEL);
+ return true;
+ }
+
+ // Top right: D16 LBT
+ if (xPos > 512 && yPos > 512) {
+ g_model.moduleData[INTERNAL_MODULE].setMultiProtocol(MODULE_SUBTYPE_MULTI_FRSKY);
+ g_model.moduleData[INTERNAL_MODULE].subType = MM_RF_FRSKY_SUBTYPE_D16_LBT;
+ g_model.moduleData[INTERNAL_MODULE].failsafeMode = FAILSAFE_NOPULSES;
+ storageDirty(EE_MODEL);
+ return true;
+ }
+
+ // Bottom left: V2.1 D16 FCC
+ if (xPos < -512 && yPos < -512) {
+ g_model.moduleData[INTERNAL_MODULE].setMultiProtocol(MODULE_SUBTYPE_MULTI_FRSKYX2);
+ g_model.moduleData[INTERNAL_MODULE].subType = MM_RF_FRSKYX2_SUBTYPE_D16;
+ g_model.moduleData[INTERNAL_MODULE].failsafeMode = FAILSAFE_NOPULSES;
+ storageDirty(EE_MODEL);
+ return true;
+ }
+
+ // Bottom right: V2.1 D16 LBT
+ if (xPos > 512 && yPos < -512) {
+ g_model.moduleData[INTERNAL_MODULE].setMultiProtocol(MODULE_SUBTYPE_MULTI_FRSKYX2);
+ g_model.moduleData[INTERNAL_MODULE].subType = MM_RF_FRSKYX2_SUBTYPE_D16_LBT;
+ g_model.moduleData[INTERNAL_MODULE].failsafeMode = FAILSAFE_NOPULSES;
+ storageDirty(EE_MODEL);
+ return true;
+ }
+
+ return false;
+}
+
+void bindButtonHandler(event_t event)
+{
+ if( !isModuleMultimodule(INTERNAL_MODULE))
+ return;
+
+ if (event == EVT_KEY_LONG(KEY_BIND) && getMultiBindStatus(INTERNAL_MODULE) == MULTI_NORMAL_OPERATION) {
+ if (setBindProtocolSelection()) {
+ setMultiBindStatus(INTERNAL_MODULE, MULTI_BIND_INITIATED);
+ moduleState[INTERNAL_MODULE].mode = MODULE_MODE_BIND;
+ }
+ }
+
+ if (getMultiBindStatus(INTERNAL_MODULE) == MULTI_BIND_INITIATED) {
+ if (FAST_BLINK_ON_PHASE)
+ LED_BIND();
+ else
+ ledOff();
+ }
+
+ if (getMultiBindStatus(INTERNAL_MODULE) == MULTI_BIND_FINISHED) {
+ setMultiBindStatus(INTERNAL_MODULE, MULTI_NORMAL_OPERATION);
+ moduleState[INTERNAL_MODULE].mode = MODULE_MODE_NORMAL;
+ LED_ERROR_END();
+ }
+}
diff --git a/radio/src/targets/taranis/board.cpp b/radio/src/targets/taranis/board.cpp
index 521ab1d9b..69e36d5e8 100644
--- a/radio/src/targets/taranis/board.cpp
+++ b/radio/src/targets/taranis/board.cpp
@@ -92,7 +92,8 @@ void boardInit()
TRAINER_RCC_AHB1Periph |
TRAINER_MODULE_RCC_AHB1Periph |
BT_RCC_AHB1Periph |
- GYRO_RCC_AHB1Periph,
+ GYRO_RCC_AHB1Periph |
+ USB_CHARGER_RCC_AHB1Periph,
ENABLE);
RCC_APB1PeriphClockCmd(ROTARY_ENCODER_RCC_APB1Periph |
@@ -110,6 +111,7 @@ void boardInit()
AUX_SERIAL_RCC_APB1Periph |
INTMODULE_RCC_APB1Periph |
TRAINER_MODULE_RCC_APB1Periph |
+ MIXER_SCHEDULER_TIMER_RCC_APB1Periph |
BT_RCC_APB1Periph |
GYRO_RCC_APB1Periph,
ENABLE);
@@ -193,6 +195,10 @@ void boardInit()
toplcdInit();
#endif
+#if defined(USB_CHARGER)
+ usbChargerInit();
+#endif
+
if (HAS_SPORT_UPDATE_CONNECTOR()) {
sportUpdateInit();
}
@@ -265,10 +271,18 @@ void boardOff()
// this function must not return!
}
+#if defined (RADIO_TX12)
+ #define BATTERY_DIVIDER 22830
+#elif defined (RADIO_T8)
+ #define BATTERY_DIVIDER 50000
+#else
+ #define BATTERY_DIVIDER 26214
+#endif
+
uint16_t getBatteryVoltage()
{
int32_t instant_vbat = anaIn(TX_VOLTAGE); // using filtered ADC value on purpose
- instant_vbat = (instant_vbat * BATT_SCALE * (128 + g_eeGeneral.txVoltageCalibration) ) / 26214;
+ instant_vbat = (instant_vbat * BATT_SCALE * (128 + g_eeGeneral.txVoltageCalibration) ) / BATTERY_DIVIDER;
instant_vbat += 20; // add 0.2V because of the diode TODO check if this is needed, but removal will break existing calibrations!
return (uint16_t)instant_vbat;
}
@@ -333,4 +347,4 @@ void initJackDetect(void)
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(JACK_DETECT_GPIO, &GPIO_InitStructure);
}
-#endif
\ No newline at end of file
+#endif
diff --git a/radio/src/targets/taranis/board.h b/radio/src/targets/taranis/board.h
index 62ad32a5f..8e583be73 100644
--- a/radio/src/targets/taranis/board.h
+++ b/radio/src/targets/taranis/board.h
@@ -27,6 +27,9 @@
#include "board_common.h"
#include "hal.h"
+#if defined(RADIO_TX12) || defined(RADIO_TX12)
+ #define NAVIGATION_X7_TX12
+#endif
#if defined(ROTARY_ENCODER_NAVIGATION)
// Rotary Encoder driver
@@ -114,7 +117,7 @@ uint32_t isBootloaderStart(const uint8_t * buffer);
#define INTERNAL_MODULE_OFF() GPIO_ResetBits(INTMODULE_PWR_GPIO, INTMODULE_PWR_GPIO_PIN)
#endif
-#if !defined(PCBX9LITE) || defined(PCBX9LITES)
+#if (defined(INTERNAL_MODULE_PXX1) || defined(INTERNAL_MODULE_PXX2)) && (!defined(PCBX9LITE) || defined(PCBX9LITES))
#define HARDWARE_INTERNAL_RAS
#endif
@@ -140,7 +143,7 @@ void intmoduleSendByte(uint8_t byte);
void intmoduleSendBuffer(const uint8_t * data, uint8_t size);
void intmoduleSendNextFrame();
-void extmoduleSerialStart(uint32_t baudrate, uint32_t period_half_us, bool inverted);
+void extmoduleSerialStart();
void extmoduleInvertedSerialStart(uint32_t baudrate);
void extmoduleSendBuffer(const uint8_t * data, uint8_t size);
void extmoduleSendNextFrame();
@@ -149,7 +152,7 @@ void extmoduleSendInvertedByte(uint8_t byte);
// Trainer driver
#define SLAVE_MODE() (g_model.trainerData.mode == TRAINER_MODE_SLAVE)
-#if defined(PCBX9D) || (defined(PCBX9DP) && PCBREV < 2019)
+#if defined(TRAINER_DETECT_GPIO)
// Trainer detect is a switch on the jack
#define TRAINER_CONNECTED() (GPIO_ReadInputDataBit(TRAINER_DETECT_GPIO, TRAINER_DETECT_GPIO_PIN) == Bit_RESET)
#elif defined(PCBXLITES)
@@ -239,6 +242,26 @@ enum EnumKeys
KEY_PAGE,
#endif
+#if defined(KEYS_GPIO_REG_PAGEUP)
+ KEY_PAGEUP,
+#endif
+
+#if defined(KEYS_GPIO_REG_PAGEDN)
+ KEY_PAGEDN,
+#endif
+
+#if defined(KEYS_GPIO_REG_SYS)
+ KEY_SYS,
+#endif
+
+#if defined(KEYS_GPIO_REG_MDL)
+ KEY_MODEL,
+#endif
+
+#if defined(KEYS_GPIO_REG_TELE)
+ KEY_TELE,
+#endif
+
#if defined(KEYS_GPIO_REG_PLUS)
KEY_PLUS,
KEY_MINUS,
@@ -247,6 +270,10 @@ enum EnumKeys
KEY_COUNT,
KEY_MAX = KEY_COUNT - 1,
+#if defined(KEYS_GPIO_REG_BIND)
+ KEY_BIND,
+#endif
+
#if defined(ROTARY_ENCODER_NAVIGATION)
KEY_PLUS,
KEY_MINUS,
@@ -308,8 +335,11 @@ enum EnumSwitches
SW_SG,
SW_SH
};
-#define IS_3POS(x) ((x) != SW_SF && (x) != SW_SH)
-
+#if defined(RADIO_TX12)
+ #define IS_3POS(x) ((x) != SW_SA && (x) != SW_SD)
+#else
+ #define IS_3POS(x) ((x) != SW_SF && (x) != SW_SH)
+#endif
enum EnumSwitchesPositions
{
SW_SA0,
@@ -324,12 +354,12 @@ enum EnumSwitchesPositions
SW_SD0,
SW_SD1,
SW_SD2,
-#if defined(PCBX9) || defined(PCBXLITES) || defined(PCBX9LITES)
+#if defined(PCBX9) || defined(PCBXLITES) || defined(PCBX9LITES) || defined(RADIO_TX12)
SW_SE0,
SW_SE1,
SW_SE2,
#endif
-#if defined(PCBX9D) || defined(PCBX9DP) || defined(PCBX9E) || defined(PCBX7) || defined(PCBXLITES) || defined(PCBX9LITES)
+#if defined(PCBX9D) || defined(PCBX9DP) || defined(PCBX9E) || defined(PCBX7) || defined(PCBXLITES) || defined(PCBX9LITES) || defined(RADIO_T8)
SW_SF0,
SW_SF1,
SW_SF2,
@@ -339,7 +369,7 @@ enum EnumSwitchesPositions
SW_SG1,
SW_SG2,
#endif
-#if defined(PCBX9D) || defined(PCBX9DP) || defined(PCBX9E) || defined(PCBX7)
+#if defined(PCBX9D) || defined(PCBX9DP) || defined(PCBX9E) || (defined(PCBX7) && !defined(RADIO_TX12)) || defined(RADIO_T8)
SW_SH0,
SW_SH1,
SW_SH2,
@@ -406,11 +436,26 @@ enum EnumSwitchesPositions
#define STORAGE_NUM_SWITCHES 6
#define DEFAULT_SWITCH_CONFIG (SWITCH_2POS << 6) + (SWITCH_2POS << 4) + (SWITCH_3POS << 2) + (SWITCH_3POS << 0);
#define DEFAULT_POTS_CONFIG (POT_WITHOUT_DETENT << 2) + (POT_WITHOUT_DETENT << 0)
-#elif defined(RADIO_T12)
+#elif defined(RADIO_TLITE)
+ #define NUM_SWITCHES 4
+ #define STORAGE_NUM_SWITCHES 8
+ #define DEFAULT_SWITCH_CONFIG (SWITCH_2POS << 6) + (SWITCH_2POS << 4) + (SWITCH_3POS << 2) + (SWITCH_3POS << 0);
+ #define DEFAULT_POTS_CONFIG (0)
+#elif defined(RADIO_FAMILY_JUMPER_T12)
#define NUM_SWITCHES 8
#define STORAGE_NUM_SWITCHES NUM_SWITCHES
#define DEFAULT_SWITCH_CONFIG (SWITCH_2POS << 10) + (SWITCH_2POS << 8) + (SWITCH_3POS << 6) + (SWITCH_3POS << 4) + (SWITCH_3POS << 2) + (SWITCH_3POS << 0)
#define DEFAULT_POTS_CONFIG (POT_WITHOUT_DETENT << 0) + (POT_WITHOUT_DETENT << 2); // S1 = pot without detent, S2 = pot with detent
+#elif defined(RADIO_TX12)
+ #define NUM_SWITCHES 8
+ #define STORAGE_NUM_SWITCHES NUM_SWITCHES
+ #define DEFAULT_SWITCH_CONFIG (SWITCH_3POS << 10) + (SWITCH_3POS << 8) + (SWITCH_TOGGLE << 6) + (SWITCH_3POS << 4) + (SWITCH_3POS << 2) + (SWITCH_TOGGLE << 0)
+ #define DEFAULT_POTS_CONFIG (POT_WITH_DETENT << 0) + (POT_WITH_DETENT << 2);
+#elif defined(RADIO_T8)
+ #define NUM_SWITCHES 4
+ #define STORAGE_NUM_SWITCHES 8
+ #define DEFAULT_SWITCH_CONFIG (SWITCH_2POS << 6) + (SWITCH_3POS << 4) + (SWITCH_3POS << 2) + (SWITCH_2POS << 0);
+ #define DEFAULT_POTS_CONFIG (0)
#elif defined(PCBX7ACCESS)
#define NUM_SWITCHES 7
#define STORAGE_NUM_SWITCHES 8
@@ -513,6 +558,11 @@ enum Analogs {
#define NUM_SLIDERS 0
#define STORAGE_NUM_POTS 1
#define STORAGE_NUM_SLIDERS 0
+#elif defined(RADIO_T8) || defined(RADIO_TLITE)
+ #define NUM_POTS 0
+ #define NUM_SLIDERS 0
+ #define STORAGE_NUM_POTS 2
+ #define STORAGE_NUM_SLIDERS 0
#elif defined(PCBXLITE) || defined(PCBX7)
#define NUM_POTS 2
#define NUM_SLIDERS 0
@@ -613,6 +663,11 @@ extern uint16_t adcValues[NUM_ANALOGS];
#define BATTERY_WARN 66 // 6.6V
#define BATTERY_MIN 67 // 6.7V
#define BATTERY_MAX 83 // 8.3V
+#elif defined(RADIO_T8) || defined(RADIO_TLITE)
+ // 1S Li-ion / Lipo, LDO for 3.3V
+ #define BATTERY_WARN 35 // 3.5V
+ #define BATTERY_MIN 34 // 3.4V
+ #define BATTERY_MAX 42 // 4.2V
#else
// NI-MH 7.2V
#define BATTERY_WARN 65 // 6.5V
@@ -660,23 +715,38 @@ void pwrResetHandler();
void backlightInit();
void backlightDisable();
#define BACKLIGHT_DISABLE() backlightDisable()
+#define BACKLIGHT_FORCED_ON 101
uint8_t isBacklightEnabled();
#if !defined(__cplusplus)
#define backlightEnable(...)
#elif defined(PCBX9E) || defined(PCBX9DP)
void backlightEnable(uint8_t level = 0, uint8_t color = 0);
- #define BACKLIGHT_ENABLE() backlightEnable(g_eeGeneral.backlightBright, g_eeGeneral.backlightColor)
+ #define BACKLIGHT_ENABLE() backlightEnable(currentBacklightBright, g_eeGeneral.backlightColor)
#else
void backlightEnable(uint8_t level = 0);
- #define BACKLIGHT_ENABLE() backlightEnable(g_eeGeneral.backlightBright)
+ #define BACKLIGHT_ENABLE() backlightEnable(currentBacklightBright)
#endif
#if !defined(SIMU)
void usbJoystickUpdate();
#endif
-#define USB_NAME "FrSky Taranis"
-#define USB_MANUFACTURER 'F', 'r', 'S', 'k', 'y', ' ', ' ', ' ' /* 8 bytes */
-#define USB_PRODUCT 'T', 'a', 'r', 'a', 'n', 'i', 's', ' ' /* 8 Bytes */
+#if defined(RADIO_TX12)
+ #define USB_NAME "Radiomaster TX12"
+ #define USB_MANUFACTURER 'R', 'M', '_', 'T', 'X', ' ', ' ', ' ' /* 8 bytes */
+ #define USB_PRODUCT 'R', 'M', ' ', 'T', 'X', '1', '2', ' ' /* 8 Bytes */
+#elif defined(RADIO_T8)
+ #define USB_NAME "Radiomaster T8"
+ #define USB_MANUFACTURER 'R', 'M', '_', 'T', 'X', ' ', ' ', ' ' /* 8 bytes */
+ #define USB_PRODUCT 'R', 'M', ' ', 'T', '8', ' ', ' ', ' ' /* 8 Bytes */
+#elif defined(RADIO_TLITE)
+ #define USB_NAME "Jumper TLite"
+ #define USB_MANUFACTURER 'J', 'U', 'M', 'P', 'E', 'R', ' ', ' ' /* 8 bytes */
+ #define USB_PRODUCT 'T', '-', 'L', 'I', 'T', 'E', ' ', ' ' /* 8 Bytes */
+#else
+ #define USB_NAME "FrSky Taranis"
+ #define USB_MANUFACTURER 'F', 'r', 'S', 'k', 'y', ' ', ' ', ' ' /* 8 bytes */
+ #define USB_PRODUCT 'T', 'a', 'r', 'a', 'n', 'i', 's', ' ' /* 8 Bytes */
+#endif
#if defined(__cplusplus) && !defined(SIMU)
}
@@ -789,8 +859,12 @@ void hapticOff();
// Aux serial port driver
#if defined(AUX_SERIAL_GPIO)
#define DEBUG_BAUDRATE 115200
+#define LUA_DEFAULT_BAUDRATE 115200
#define AUX_SERIAL
extern uint8_t auxSerialMode;
+#if defined __cplusplus
+void auxSerialSetup(unsigned int baudrate, bool dma, uint16_t length = USART_WordLength_8b, uint16_t parity = USART_Parity_No, uint16_t stop = USART_StopBits_1);
+#endif
void auxSerialInit(unsigned int mode, unsigned int protocol);
void auxSerialPutc(char c);
#define auxSerialTelemetryInit(protocol) auxSerialInit(UART_MODE_TELEMETRY, protocol)
@@ -825,6 +899,12 @@ void bluetoothDisable();
#define IS_BLUETOOTH_CHIP_PRESENT() (true)
#endif
+// USB Charger
+#if defined(USB_CHARGER)
+void usbChargerInit();
+bool usbChargerLed();
+#endif
+
// LED driver
void ledInit();
void ledOff();
@@ -847,7 +927,11 @@ void ledBlue();
#define IS_LCD_RESET_NEEDED() true
#define LCD_CONTRAST_MIN 10
#define LCD_CONTRAST_MAX 30
-#define LCD_CONTRAST_DEFAULT 20
+#if defined(RADIO_TX12) || defined(RADIO_FAMILY_JUMPER_T12)
+ #define LCD_CONTRAST_DEFAULT 25
+#else
+ #define LCD_CONTRAST_DEFAULT 15
+#endif
#endif
#if defined(PCBX9D) || defined(PCBX9E) || (defined(PCBX9DP) && PCBREV < 2019)
diff --git a/radio/src/targets/taranis/extmodule_driver.cpp b/radio/src/targets/taranis/extmodule_driver.cpp
index 0910f156e..512f16c5d 100644
--- a/radio/src/targets/taranis/extmodule_driver.cpp
+++ b/radio/src/targets/taranis/extmodule_driver.cpp
@@ -37,7 +37,8 @@ void extmoduleStop()
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(EXTMODULE_USART_GPIO, &GPIO_InitStructure);
- GPIO_ResetBits(EXTMODULE_USART_GPIO, EXTMODULE_TX_GPIO_PIN | EXTMODULE_RX_GPIO_PIN);
+ // TX and RX are inverted, we set it to HIGH
+ GPIO_SetBits(EXTMODULE_USART_GPIO, EXTMODULE_TX_GPIO_PIN | EXTMODULE_RX_GPIO_PIN);
#endif
EXTMODULE_TIMER->DIER &= ~(TIM_DIER_CC2IE | TIM_DIER_UDE);
@@ -82,7 +83,7 @@ void extmodulePpmStart()
NVIC_SetPriority(EXTMODULE_TIMER_CC_IRQn, 7);
}
-void extmoduleSerialStart(uint32_t /*baudrate*/, uint32_t period_half_us, bool inverted)
+void extmoduleSerialStart()
{
EXTERNAL_MODULE_ON();
@@ -97,17 +98,18 @@ void extmoduleSerialStart(uint32_t /*baudrate*/, uint32_t period_half_us, bool i
GPIO_Init(EXTMODULE_TX_GPIO, &GPIO_InitStructure);
EXTMODULE_TIMER->CR1 &= ~TIM_CR1_CEN;
- EXTMODULE_TIMER->PSC = EXTMODULE_TIMER_FREQ / 2000000 - 1; // 0.5uS from 30MHz
- EXTMODULE_TIMER->CCER = EXTMODULE_TIMER_OUTPUT_ENABLE | (inverted ? 0 : EXTMODULE_TIMER_OUTPUT_POLARITY);
+ EXTMODULE_TIMER->PSC = EXTMODULE_TIMER_FREQ / 2000000 - 1; // 0.5uS (2 MHz)
+
+ EXTMODULE_TIMER->CCR3 = 0;
+ EXTMODULE_TIMER->CCER = EXTMODULE_TIMER_OUTPUT_ENABLE | EXTMODULE_TIMER_OUTPUT_POLARITY;
EXTMODULE_TIMER->BDTR = TIM_BDTR_MOE; // Enable outputs
EXTMODULE_TIMER->CCR1 = 0;
EXTMODULE_TIMER->CCMR1 = TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_0; // Force O/P high
EXTMODULE_TIMER->EGR = 1; // Restart
EXTMODULE_TIMER->CCMR1 = TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_0;
- EXTMODULE_TIMER->ARR = period_half_us;
- EXTMODULE_TIMER->CCR2 = 40000; // The first frame will be sent in 20ms
+ EXTMODULE_TIMER->ARR = 40000; // dummy value until the DMA request kicks in
EXTMODULE_TIMER->SR &= ~TIM_SR_CC2IF; // Clear flag
- EXTMODULE_TIMER->DIER |= TIM_DIER_UDE | TIM_DIER_CC2IE;
+ EXTMODULE_TIMER->DIER |= TIM_DIER_UDE;
EXTMODULE_TIMER->CR1 |= TIM_CR1_CEN;
NVIC_EnableIRQ(EXTMODULE_TIMER_DMA_STREAM_IRQn);
@@ -213,16 +215,17 @@ void extmodulePxx1PulsesStart()
EXTMODULE_TIMER->CR1 &= ~TIM_CR1_CEN;
EXTMODULE_TIMER->PSC = EXTMODULE_TIMER_FREQ / 2000000 - 1; // 0.5uS (2Mhz)
+
+ EXTMODULE_TIMER->CCR3 = 0;
EXTMODULE_TIMER->CCER = EXTMODULE_TIMER_OUTPUT_ENABLE | EXTMODULE_TIMER_OUTPUT_POLARITY; // polarity, default low
EXTMODULE_TIMER->BDTR = TIM_BDTR_MOE; // Enable outputs
EXTMODULE_TIMER->CCR1 = 18;
EXTMODULE_TIMER->CCMR1 = TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_0; // Force O/P high
EXTMODULE_TIMER->EGR = 1; // Restart
- EXTMODULE_TIMER->CCMR1 = TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2;
- EXTMODULE_TIMER->ARR = 45000;
- EXTMODULE_TIMER->CCR2 = 40000; // The first frame will be sent in 20ms
+ EXTMODULE_TIMER->CCMR1 = TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2; // 0 TOGGLE / 2 PWM1
+ EXTMODULE_TIMER->ARR = 40000;
EXTMODULE_TIMER->SR &= ~TIM_SR_CC2IF; // Clear flag
- EXTMODULE_TIMER->DIER |= TIM_DIER_UDE | TIM_DIER_CC2IE;
+ EXTMODULE_TIMER->DIER |= TIM_DIER_UDE;
EXTMODULE_TIMER->CR1 |= TIM_CR1_CEN;
NVIC_EnableIRQ(EXTMODULE_TIMER_DMA_STREAM_IRQn);
@@ -256,13 +259,23 @@ void extmoduleSendNextFrame()
#if defined(PXX1)
case PROTOCOL_CHANNELS_PXX1_PULSES:
- EXTMODULE_TIMER->CCR2 = extmodulePulsesData.pxx.getLast() - 4000; // 2mS in advance
+
+ if (EXTMODULE_TIMER_DMA_STREAM->CR & DMA_SxCR_EN)
+ return;
+
+ // disable timer
+ EXTMODULE_TIMER->CR1 &= ~TIM_CR1_CEN;
+
EXTMODULE_TIMER_DMA_STREAM->CR &= ~DMA_SxCR_EN; // Disable DMA
EXTMODULE_TIMER_DMA_STREAM->CR |= EXTMODULE_TIMER_DMA_CHANNEL | DMA_SxCR_DIR_0 | DMA_SxCR_MINC | DMA_SxCR_PSIZE_0 | DMA_SxCR_MSIZE_0 | DMA_SxCR_PL_0 | DMA_SxCR_PL_1;
EXTMODULE_TIMER_DMA_STREAM->PAR = CONVERT_PTR_UINT(&EXTMODULE_TIMER->ARR);
EXTMODULE_TIMER_DMA_STREAM->M0AR = CONVERT_PTR_UINT(extmodulePulsesData.pxx.getData());
EXTMODULE_TIMER_DMA_STREAM->NDTR = extmodulePulsesData.pxx.getSize();
EXTMODULE_TIMER_DMA_STREAM->CR |= DMA_SxCR_EN | DMA_SxCR_TCIE; // Enable DMA
+
+ // re-init timer
+ EXTMODULE_TIMER->EGR = 1;
+ EXTMODULE_TIMER->CR1 |= TIM_CR1_CEN;
break;
#endif
@@ -284,34 +297,54 @@ void extmoduleSendNextFrame()
#if defined(EXTMODULE_USART) && defined(EXTMODULE_TX_INVERT_GPIO)
extmoduleSendBuffer(extmodulePulsesData.afhds3.getData(), extmodulePulsesData.afhds3.getSize());
#else
+ if (EXTMODULE_TIMER_DMA_STREAM->CR & DMA_SxCR_EN)
+ return;
+
const uint16_t* dataPtr = extmodulePulsesData.afhds3.getData();
uint32_t dataSize = extmodulePulsesData.afhds3.getSize();
- EXTMODULE_TIMER->CCR2 = dataPtr[dataSize -1] - 4000; // 2mS in advance
EXTMODULE_TIMER_DMA_STREAM->CR &= ~DMA_SxCR_EN; // Disable DMA
EXTMODULE_TIMER_DMA_STREAM->CR |= EXTMODULE_TIMER_DMA_CHANNEL | DMA_SxCR_DIR_0 | DMA_SxCR_MINC | DMA_SxCR_PSIZE_0 | DMA_SxCR_MSIZE_0 | DMA_SxCR_PL_0 | DMA_SxCR_PL_1;
EXTMODULE_TIMER_DMA_STREAM->PAR = CONVERT_PTR_UINT(&EXTMODULE_TIMER->ARR);
EXTMODULE_TIMER_DMA_STREAM->M0AR = CONVERT_PTR_UINT(dataPtr);
EXTMODULE_TIMER_DMA_STREAM->NDTR = dataSize;
EXTMODULE_TIMER_DMA_STREAM->CR |= DMA_SxCR_EN | DMA_SxCR_TCIE; // Enable DMA
+
+ // re-init timer
+ EXTMODULE_TIMER->EGR = TIM_PSCReloadMode_Immediate;
+ EXTMODULE_TIMER->CR1 |= TIM_CR1_CEN;
#endif
}
break;
#endif
#if defined(SBUS) || defined(DSM2) || defined(MULTIMODULE)
case PROTOCOL_CHANNELS_SBUS:
- EXTMODULE_TIMER->CCER = EXTMODULE_TIMER_OUTPUT_ENABLE | (GET_SBUS_POLARITY(EXTERNAL_MODULE) ? 0 : EXTMODULE_TIMER_OUTPUT_POLARITY); // reverse polarity for Sbus if needed
// no break
case PROTOCOL_CHANNELS_DSM2_LP45:
case PROTOCOL_CHANNELS_DSM2_DSM2:
case PROTOCOL_CHANNELS_DSM2_DSMX:
case PROTOCOL_CHANNELS_MULTIMODULE:
- EXTMODULE_TIMER->CCR2 = *(extmodulePulsesData.dsm2.ptr - 1) - 4000; // 2mS in advance
+
+ if (EXTMODULE_TIMER_DMA_STREAM->CR & DMA_SxCR_EN)
+ return;
+
+ // disable timer
+ EXTMODULE_TIMER->CR1 &= ~TIM_CR1_CEN;
+
+ if (PROTOCOL_CHANNELS_SBUS == moduleState[EXTERNAL_MODULE].protocol) {
+ EXTMODULE_TIMER->CCER = EXTMODULE_TIMER_OUTPUT_ENABLE | (GET_SBUS_POLARITY(EXTERNAL_MODULE) ? EXTMODULE_TIMER_OUTPUT_POLARITY : 0); // reverse polarity for Sbus if needed
+ }
+
+ // send DMA request
EXTMODULE_TIMER_DMA_STREAM->CR &= ~DMA_SxCR_EN; // Disable DMA
EXTMODULE_TIMER_DMA_STREAM->CR |= EXTMODULE_TIMER_DMA_CHANNEL | DMA_SxCR_DIR_0 | DMA_SxCR_MINC | DMA_SxCR_PSIZE_0 | DMA_SxCR_MSIZE_0 | DMA_SxCR_PL_0 | DMA_SxCR_PL_1;
EXTMODULE_TIMER_DMA_STREAM->PAR = CONVERT_PTR_UINT(&EXTMODULE_TIMER->ARR);
EXTMODULE_TIMER_DMA_STREAM->M0AR = CONVERT_PTR_UINT(extmodulePulsesData.dsm2.pulses);
EXTMODULE_TIMER_DMA_STREAM->NDTR = extmodulePulsesData.dsm2.ptr - extmodulePulsesData.dsm2.pulses;
EXTMODULE_TIMER_DMA_STREAM->CR |= DMA_SxCR_EN | DMA_SxCR_TCIE; // Enable DMA
+
+ // re-init timer
+ EXTMODULE_TIMER->EGR = 1;
+ EXTMODULE_TIMER->CR1 |= TIM_CR1_CEN;
break;
#endif
@@ -321,6 +354,12 @@ void extmoduleSendNextFrame()
break;
#endif
+#if defined(GHOST)
+ case PROTOCOL_CHANNELS_GHOST:
+ sportSendBuffer(extmodulePulsesData.ghost.pulses, extmodulePulsesData.ghost.length);
+ break;
+#endif
+
default:
EXTMODULE_TIMER->DIER |= TIM_DIER_CC2IE;
break;
@@ -366,14 +405,19 @@ extern "C" void EXTMODULE_TIMER_DMA_STREAM_IRQHandler()
DMA_ClearITPendingBit(EXTMODULE_TIMER_DMA_STREAM, EXTMODULE_TIMER_DMA_FLAG_TC);
- EXTMODULE_TIMER->SR &= ~TIM_SR_CC2IF; // Clear flag
- EXTMODULE_TIMER->DIER |= TIM_DIER_CC2IE; // Enable this interrupt
+ switch (moduleState[EXTERNAL_MODULE].protocol) {
+ case PROTOCOL_CHANNELS_PPM:
+ EXTMODULE_TIMER->SR &= ~TIM_SR_CC2IF; // Clear flag
+ EXTMODULE_TIMER->DIER |= TIM_DIER_CC2IE; // Enable this interrupt
+ break;
+ }
}
extern "C" void EXTMODULE_TIMER_CC_IRQHandler()
{
EXTMODULE_TIMER->DIER &= ~TIM_DIER_CC2IE; // Stop this interrupt
EXTMODULE_TIMER->SR &= ~TIM_SR_CC2IF;
+
if (setupPulsesExternalModule()) {
extmoduleSendNextFrame();
}
diff --git a/radio/src/targets/taranis/hal.h b/radio/src/targets/taranis/hal.h
index 65462c576..5c00b3052 100644
--- a/radio/src/targets/taranis/hal.h
+++ b/radio/src/targets/taranis/hal.h
@@ -46,7 +46,7 @@
#define KEYS_GPIO_PIN_LEFT GPIO_Pin_12 // PE.12
#define KEYS_GPIO_REG_RIGHT GPIOE->IDR
#define KEYS_GPIO_PIN_RIGHT GPIO_Pin_13 // PE.13
-#elif defined(RADIO_T12)
+#elif defined(RADIO_FAMILY_JUMPER_T12)
#define KEYS_GPIO_REG_EXIT GPIOD->IDR
#define KEYS_GPIO_PIN_EXIT GPIO_Pin_2 // PD.02
#define KEYS_GPIO_REG_ENTER GPIOE->IDR
@@ -59,6 +59,40 @@
#define KEYS_GPIO_PIN_LEFT GPIO_Pin_7 // PD.07
#define KEYS_GPIO_REG_RIGHT GPIOD->IDR
#define KEYS_GPIO_PIN_RIGHT GPIO_Pin_3 // PD.03
+#elif defined(RADIO_TX12)
+ #define KEYS_GPIO_REG_PAGEUP GPIOD->IDR
+ #define KEYS_GPIO_PIN_PAGEUP GPIO_Pin_3 // PD.03
+ #define KEYS_GPIO_REG_PAGEDN GPIOD->IDR
+ #define KEYS_GPIO_PIN_PAGEDN GPIO_Pin_7 // PD.07
+ #define KEYS_GPIO_REG_EXIT GPIOB->IDR
+ #define KEYS_GPIO_PIN_EXIT GPIO_Pin_3 // PB.03
+ #define KEYS_GPIO_REG_ENTER GPIOA->IDR
+ #define KEYS_GPIO_PIN_ENTER GPIO_Pin_13 // PA.13
+ #define KEYS_GPIO_REG_SYS GPIOB->IDR
+ #define KEYS_GPIO_PIN_SYS GPIO_Pin_4 // PB.04
+ #define KEYS_GPIO_REG_MDL GPIOE->IDR
+ #define KEYS_GPIO_PIN_MDL GPIO_Pin_11 // PE.11
+ #define KEYS_GPIO_REG_TELE GPIOD->IDR
+ #define KEYS_GPIO_PIN_TELE GPIO_Pin_2 // PD.02
+#elif defined(RADIO_T8)
+ #define KEYS_GPIO_REG_PAGEUP GPIOD->IDR
+ #define KEYS_GPIO_PIN_PAGEUP GPIO_Pin_3 // PD.03
+ #define KEYS_GPIO_REG_PAGEDN GPIOD->IDR
+ #define KEYS_GPIO_PIN_PAGEDN GPIO_Pin_7 // PD.07
+ #define KEYS_GPIO_REG_EXIT GPIOB->IDR
+ #define KEYS_GPIO_PIN_EXIT GPIO_Pin_3 // PB.03
+ #define KEYS_GPIO_REG_ENTER GPIOA->IDR
+ #define KEYS_GPIO_PIN_ENTER GPIO_Pin_13 // PA.13
+ #define KEYS_GPIO_REG_SYS GPIOB->IDR
+ #define KEYS_GPIO_PIN_SYS GPIO_Pin_4 // PB.04
+ #define KEYS_GPIO_REG_MDL GPIOE->IDR
+ #define KEYS_GPIO_PIN_MDL GPIO_Pin_11 // PE.11
+ #define KEYS_GPIO_REG_PLUS GPIOE->IDR
+ #define KEYS_GPIO_PIN_PLUS GPIO_Pin_9 // PE.09
+ #define KEYS_GPIO_REG_MINUS GPIOE->IDR
+ #define KEYS_GPIO_PIN_MINUS GPIO_Pin_10 // PE.10
+ #define KEYS_GPIO_REG_BIND GPIOA->IDR
+ #define KEYS_GPIO_PIN_BIND GPIO_Pin_10 // PA.10
#elif defined(PCBX7)
#define KEYS_GPIO_REG_PAGE GPIOD->IDR
#define KEYS_GPIO_PIN_PAGE GPIO_Pin_3 // PD.03
@@ -156,7 +190,23 @@
#define ROTARY_ENCODER_EXTI_PortSource EXTI_PortSourceGPIOE
#define ROTARY_ENCODER_EXTI_PinSource1 EXTI_PinSource10
#define ROTARY_ENCODER_EXTI_PinSource2 EXTI_PinSource12
+#elif defined(RADIO_TX12)
+ #define ROTARY_ENCODER_NAVIGATION
+ #define ROTARY_ENCODER_GPIO GPIOE
+ #define ROTARY_ENCODER_GPIO_PIN_A GPIO_Pin_9 // PE.9
+ #define ROTARY_ENCODER_GPIO_PIN_B GPIO_Pin_10 // PE.10
+ #define ROTARY_ENCODER_POSITION() ((ROTARY_ENCODER_GPIO->IDR >> 9) & 0x03)
+ #define ROTARY_ENCODER_EXTI_LINE1 EXTI_Line9
+ #define ROTARY_ENCODER_EXTI_LINE2 EXTI_Line10
+ #define ROTARY_ENCODER_EXTI_IRQn1 EXTI9_5_IRQn
+ #define ROTARY_ENCODER_EXTI_IRQHandler1 EXTI9_5_IRQHandler
+ #define ROTARY_ENCODER_EXTI_IRQn2 EXTI15_10_IRQn
+ #define ROTARY_ENCODER_EXTI_IRQHandler2 EXTI15_10_IRQHandler
+ #define ROTARY_ENCODER_EXTI_PortSource EXTI_PortSourceGPIOE
+ #define ROTARY_ENCODER_EXTI_PinSource1 EXTI_PinSource9
+ #define ROTARY_ENCODER_EXTI_PinSource2 EXTI_PinSource10
#endif
+
#if defined(ROTARY_ENCODER_NAVIGATION)
#define ROTARY_ENCODER_RCC_APB1Periph RCC_APB1Periph_TIM5
#define ROTARY_ENCODER_TIMER TIM5
@@ -296,6 +346,16 @@
#define SWITCHES_GPIO_PIN_A_H GPIO_Pin_1 // PE.01
#define SWITCHES_GPIO_REG_A_L GPIOE->IDR
#define SWITCHES_GPIO_PIN_A_L GPIO_Pin_0 // PE.00
+#elif defined(RADIO_TX12)
+ #define STORAGE_SWITCH_A
+ #define HARDWARE_SWITCH_A
+ #define SWITCHES_GPIO_REG_A GPIOC->IDR
+ #define SWITCHES_GPIO_PIN_A GPIO_Pin_13 // PC.13
+#elif defined(RADIO_T8)
+ #define STORAGE_SWITCH_A
+ #define HARDWARE_SWITCH_A
+ #define SWITCHES_GPIO_REG_A GPIOE->IDR
+ #define SWITCHES_GPIO_PIN_A GPIO_Pin_14 // PE.14
#elif defined(PCBX7)
#define STORAGE_SWITCH_A
#define HARDWARE_SWITCH_A
@@ -326,6 +386,20 @@
#define SWITCHES_GPIO_PIN_B_L GPIO_Pin_6 // PA.06
#define SWITCHES_GPIO_REG_B_H GPIOA->IDR
#define SWITCHES_GPIO_PIN_B_H GPIO_Pin_5 // PA.05
+#elif defined(RADIO_T8)
+ #define STORAGE_SWITCH_B
+ #define HARDWARE_SWITCH_B
+ #define SWITCHES_GPIO_REG_B_L GPIOE->IDR
+ #define SWITCHES_GPIO_PIN_B_L GPIO_Pin_7 // PE.07
+ #define SWITCHES_GPIO_REG_B_H GPIOE->IDR
+ #define SWITCHES_GPIO_PIN_B_H GPIO_Pin_13 // PE.13
+#elif defined(RADIO_TLITE)
+ #define STORAGE_SWITCH_B
+ #define HARDWARE_SWITCH_B
+ #define SWITCHES_GPIO_REG_B_L GPIOE->IDR
+ #define SWITCHES_GPIO_PIN_B_L GPIO_Pin_1 // PE.01
+ #define SWITCHES_GPIO_REG_B_H GPIOE->IDR
+ #define SWITCHES_GPIO_PIN_B_H GPIO_Pin_2 // PE.02
#elif defined(PCBX7)
#define STORAGE_SWITCH_B
#define HARDWARE_SWITCH_B
@@ -363,6 +437,25 @@
#define SWITCHES_GPIO_PIN_C_L GPIO_Pin_2 // PE.02
#define SWITCHES_GPIO_REG_C_H GPIOE->IDR
#define SWITCHES_GPIO_PIN_C_H GPIO_Pin_3 // PE.03
+#elif defined(RADIO_TX12)
+ #define STORAGE_SWITCH_C
+ #define HARDWARE_SWITCH_C
+ #define SWITCHES_GPIO_REG_C_L GPIOD->IDR
+ #define SWITCHES_GPIO_PIN_C_L GPIO_Pin_11 // PD.11
+ #define SWITCHES_GPIO_REG_C_H GPIOE->IDR
+ #define SWITCHES_GPIO_PIN_C_H GPIO_Pin_0 // PE.00
+#elif defined(RADIO_T8)
+ #define STORAGE_SWITCH_C
+ #define HARDWARE_SWITCH_C
+ #define SWITCHES_GPIO_REG_C_L GPIOE->IDR
+ #define SWITCHES_GPIO_PIN_C_L GPIO_Pin_2 // PE.02
+ #define SWITCHES_GPIO_REG_C_H GPIOE->IDR
+ #define SWITCHES_GPIO_PIN_C_H GPIO_Pin_1 // PE.01
+#elif defined(RADIO_TLITE)
+ #define STORAGE_SWITCH_C
+ #define HARDWARE_SWITCH_C
+ #define SWITCHES_GPIO_REG_C GPIOE->IDR
+ #define SWITCHES_GPIO_PIN_C GPIO_Pin_14 // PE.14
#elif defined(PCBX7)
#define STORAGE_SWITCH_C
#define HARDWARE_SWITCH_C
@@ -405,6 +498,21 @@
#define SWITCHES_GPIO_PIN_D_L GPIO_Pin_4 // PB.04
#define SWITCHES_GPIO_REG_D_H GPIOB->IDR
#define SWITCHES_GPIO_PIN_D_H GPIO_Pin_5 // PB.05
+#elif defined(RADIO_T8)
+ #define STORAGE_SWITCH_D
+ #define HARDWARE_SWITCH_D
+ #define SWITCHES_GPIO_REG_D GPIOD->IDR
+ #define SWITCHES_GPIO_PIN_D GPIO_Pin_14 // PD.14
+#elif defined(RADIO_TX12)
+ #define STORAGE_SWITCH_D
+ #define HARDWARE_SWITCH_D
+ #define SWITCHES_GPIO_REG_D GPIOE->IDR
+ #define SWITCHES_GPIO_PIN_D GPIO_Pin_8 // PE.08
+#elif defined(RADIO_TLITE)
+ #define STORAGE_SWITCH_D
+ #define HARDWARE_SWITCH_D
+ #define SWITCHES_GPIO_REG_D GPIOD->IDR
+ #define SWITCHES_GPIO_PIN_D GPIO_Pin_14 // PD.14
#elif defined(PCBX7)
#define STORAGE_SWITCH_D
#define HARDWARE_SWITCH_D
@@ -446,6 +554,13 @@
#define HARDWARE_SWITCH_E
#define SWITCHES_GPIO_REG_E GPIOA->IDR
#define SWITCHES_GPIO_PIN_E GPIO_Pin_5 // PA.05
+#elif defined(RADIO_TX12)
+ #define STORAGE_SWITCH_E
+ #define HARDWARE_SWITCH_E
+ #define SWITCHES_GPIO_REG_E_H GPIOE->IDR
+ #define SWITCHES_GPIO_PIN_E_H GPIO_Pin_13 // PE.13
+ #define SWITCHES_GPIO_REG_E_L GPIOE->IDR
+ #define SWITCHES_GPIO_PIN_E_L GPIO_Pin_7 // PE.07
#elif defined(PCBX7)
// no SWE
#else
@@ -477,6 +592,16 @@
#define SWITCHES_GPIO_PIN_F GPIO_Pin_3 // PC.03
#elif defined(PCBX9LITE)
// no SWF
+#elif defined(RADIO_TX12)
+ #define STORAGE_SWITCH_F
+ #define HARDWARE_SWITCH_F
+ #define SWITCHES_GPIO_REG_F_L GPIOE->IDR
+ #define SWITCHES_GPIO_PIN_F_L GPIO_Pin_1 // PE.01
+ #define SWITCHES_GPIO_REG_F_H GPIOE->IDR
+ #define SWITCHES_GPIO_PIN_F_H GPIO_Pin_2 // PE.02
+#elif defined(RADIO_T8) || defined(RADIO_TLITE)
+ // no SWF
+ #define STORAGE_SWITCH_F
#elif defined(PCBX7)
#define STORAGE_SWITCH_F
#define HARDWARE_SWITCH_F
@@ -501,7 +626,7 @@
#define HARDWARE_SWITCH_G
#define SWITCHES_GPIO_REG_G GPIOC->IDR
#define SWITCHES_GPIO_PIN_G GPIO_Pin_2 // PC.02
-#elif defined(PCBX7) || defined(PCBXLITE) || defined(PCBX9LITE)
+#elif defined(PCBX7) || defined(PCBXLITE) || defined(PCBX9LITE) || defined(RADIO_T8)
// no SWG
#else
#define STORAGE_SWITCH_G
@@ -524,6 +649,13 @@
#define SWITCHES_GPIO_PIN_H GPIO_Pin_14 // PD.14
#elif defined(PCBXLITE) || defined(PCBX9LITE)
// no SWH
+#elif defined(RADIO_T8)
+ #define STORAGE_SWITCH_H
+ // no SWH
+#elif defined(RADIO_TX12)
+#elif defined(RADIO_TLITE)
+ // no SWH
+ #define STORAGE_SWITCH_H
#elif defined(PCBX7)
#define STORAGE_SWITCH_H
#define HARDWARE_SWITCH_H
@@ -552,7 +684,25 @@
#define SWITCHES_GPIO_REG_I GPIOC->IDR
#define SWITCHES_GPIO_PIN_I GPIO_Pin_13 // PC.13
#define STORAGE_SWITCH_J
-#elif defined(PCBX7)
+#elif defined(RADIO_T8)
+ #define STORAGE_SWITCH_I
+ #define STORAGE_SWITCH_J
+ // no SWI/J
+#elif defined(RADIO_TX12)
+ #define STORAGE_SWITCH_I
+ #define HARDWARE_SWITCH_I
+ #define SWITCHES_GPIO_REG_I GPIOE->IDR
+ #define SWITCHES_GPIO_PIN_I GPIO_Pin_14 // PE.14
+ #define STORAGE_SWITCH_J
+ #define HARDWARE_SWITCH_J
+ #define SWITCHES_GPIO_REG_J GPIOD->IDR
+ #define SWITCHES_GPIO_PIN_J GPIO_Pin_14 // PD.14
+#elif defined(RADIO_TLITE)
+ // no SWI
+ #define STORAGE_SWITCH_I
+ // no SWJ
+ #define STORAGE_SWITCH_J
+#elif defined(PCBX7)
#define STORAGE_SWITCH_I
#define HARDWARE_SWITCH_I
#define SWITCHES_GPIO_REG_I GPIOC->IDR
@@ -661,12 +811,26 @@
#define KEYS_GPIOB_PINS (GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_4 | GPIO_Pin_5)
#define KEYS_GPIOC_PINS (GPIO_Pin_4 | GPIO_Pin_5)
#define KEYS_GPIOE_PINS (GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14)
-#elif defined(RADIO_T12)
- #define KEYS_RCC_AHB1Periph (RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_GPIOE)
+#elif defined(RADIO_FAMILY_JUMPER_T12)
+ #define KEYS_RCC_AHB1Periph (RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_GPIOE)
#define KEYS_GPIOA_PINS GPIO_Pin_5
#define KEYS_GPIOC_PINS (GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3)
#define KEYS_GPIOD_PINS (GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_7 | GPIO_Pin_11 | GPIO_Pin_14 | GPIO_Pin_15)
#define KEYS_GPIOE_PINS (GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15)
+#elif defined(RADIO_TX12)
+ #define KEYS_RCC_AHB1Periph (RCC_AHB1Periph_GPIOA|RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_GPIOE)
+ #define KEYS_GPIOA_PINS (GPIO_Pin_13 | GPIO_Pin_5)
+ #define KEYS_GPIOB_PINS (GPIO_Pin_3 | GPIO_Pin_4)
+ #define KEYS_GPIOC_PINS (GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3|GPIO_Pin_13)
+ #define KEYS_GPIOD_PINS (GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_7 | GPIO_Pin_11 | GPIO_Pin_14 | GPIO_Pin_15)
+ #define KEYS_GPIOE_PINS (GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7 |GPIO_Pin_8| GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15)
+#elif defined(RADIO_T8)
+ #define KEYS_RCC_AHB1Periph (RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_GPIOE)
+ #define KEYS_GPIOA_PINS (KEYS_GPIO_PIN_ENTER | KEYS_GPIO_PIN_BIND)
+ #define KEYS_GPIOB_PINS (KEYS_GPIO_PIN_EXIT | KEYS_GPIO_PIN_SYS)
+ #define KEYS_GPIOC_PINS (TRIMS_GPIO_PIN_LHR | TRIMS_GPIO_PIN_RVU | TRIMS_GPIO_PIN_RVD)
+ #define KEYS_GPIOD_PINS (KEYS_GPIO_PIN_PAGEUP | KEYS_GPIO_PIN_PAGEDN | SWITCHES_GPIO_PIN_D | TRIMS_GPIO_PIN_LHL)
+ #define KEYS_GPIOE_PINS (SWITCHES_GPIO_PIN_C_H | SWITCHES_GPIO_PIN_C_L | TRIMS_GPIO_PIN_RHL | TRIMS_GPIO_PIN_RHR | TRIMS_GPIO_PIN_LVU | TRIMS_GPIO_PIN_LVD | SWITCHES_GPIO_PIN_B_L | KEYS_GPIO_PIN_PLUS | KEYS_GPIO_PIN_MINUS | KEYS_GPIO_PIN_MDL | SWITCHES_GPIO_PIN_B_H | SWITCHES_GPIO_PIN_A)
#elif defined(RADIO_X7ACCESS)
#define KEYS_RCC_AHB1Periph (RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_GPIOE)
#define KEYS_GPIOA_PINS GPIO_Pin_5
@@ -710,6 +874,13 @@
#define ADC_SET_DMA_FLAGS() ADC_DMA->HIFCR = (DMA_HIFCR_CTCIF4 | DMA_HIFCR_CHTIF4 | DMA_HIFCR_CTEIF4 | DMA_HIFCR_CDMEIF4 | DMA_HIFCR_CFEIF4)
#define ADC_TRANSFER_COMPLETE() (ADC_DMA->HISR & DMA_HISR_TCIF4)
#define ADC_SAMPTIME 2 // sample time = 28 cycles
+#if defined(RADIO_TLITE)
+ #define ADC_MAIN_SMPR1 (ADC_SAMPTIME << 0) + (ADC_SAMPTIME << 3) + (ADC_SAMPTIME << 6) + (ADC_SAMPTIME << 9) + (ADC_SAMPTIME << 12) + (ADC_SAMPTIME << 15) + (ADC_SAMPTIME << 18) + (ADC_SAMPTIME << 21) + ((ADC_SAMPTIME + 1) << 24); // TLite needs +1 for proper RTC Bat measurement.
+ #define ADC_MAIN_SMPR2 (ADC_SAMPTIME << 0) + (ADC_SAMPTIME << 3) + (ADC_SAMPTIME << 6) + (ADC_SAMPTIME << 9) + (ADC_SAMPTIME << 12) + (ADC_SAMPTIME << 15) + (ADC_SAMPTIME << 18) + (ADC_SAMPTIME << 21) + (ADC_SAMPTIME << 24) + (ADC_SAMPTIME << 27);
+#else
+ #define ADC_MAIN_SMPR1 (ADC_SAMPTIME << 0) + (ADC_SAMPTIME << 3) + (ADC_SAMPTIME << 6) + (ADC_SAMPTIME << 9) + (ADC_SAMPTIME << 12) + (ADC_SAMPTIME << 15) + (ADC_SAMPTIME << 18) + (ADC_SAMPTIME << 21) + (ADC_SAMPTIME << 24);
+ #define ADC_MAIN_SMPR2 (ADC_SAMPTIME << 0) + (ADC_SAMPTIME << 3) + (ADC_SAMPTIME << 6) + (ADC_SAMPTIME << 9) + (ADC_SAMPTIME << 12) + (ADC_SAMPTIME << 15) + (ADC_SAMPTIME << 18) + (ADC_SAMPTIME << 21) + (ADC_SAMPTIME << 24) + (ADC_SAMPTIME << 27);
+#endif
#if defined(PCBX9E)
#define HARDWARE_POT1
#define HARDWARE_POT2
@@ -821,6 +992,43 @@
#define ADC_CHANNEL_POT2 ADC_Channel_12 // ADC1_IN12
#define ADC_CHANNEL_BATT ADC_Channel_10 // ADC1_IN10
#define ADC_VREF_PREC2 330
+#elif defined(RADIO_T8)
+ // No pots
+ #define ADC_RCC_AHB1Periph (RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_DMA2)
+ #define ADC_RCC_APB1Periph 0
+ #define ADC_RCC_APB2Periph RCC_APB2Periph_ADC1
+ #define ADC_GPIO_PIN_STICK_RV GPIO_Pin_0 // PA.00
+ #define ADC_GPIO_PIN_STICK_RH GPIO_Pin_1 // PA.01
+ #define ADC_GPIO_PIN_STICK_LV GPIO_Pin_2 // PA.02
+ #define ADC_GPIO_PIN_STICK_LH GPIO_Pin_3 // PA.03
+ #define ADC_CHANNEL_STICK_RV ADC_Channel_0 // ADC1_IN0
+ #define ADC_CHANNEL_STICK_RH ADC_Channel_1 // ADC1_IN1
+ #define ADC_CHANNEL_STICK_LV ADC_Channel_2 // ADC1_IN2
+ #define ADC_CHANNEL_STICK_LH ADC_Channel_3 // ADC1_IN3
+ #define ADC_GPIO_PIN_BATT GPIO_Pin_0 // PC.00
+ #define ADC_GPIOA_PINS (ADC_GPIO_PIN_STICK_RV | ADC_GPIO_PIN_STICK_RH | ADC_GPIO_PIN_STICK_LH | ADC_GPIO_PIN_STICK_LV)
+ #define ADC_GPIOB_PINS 0
+ #define ADC_GPIOC_PINS ADC_GPIO_PIN_BATT
+ #define ADC_CHANNEL_BATT ADC_Channel_10
+ #define ADC_VREF_PREC2 300
+#elif defined(RADIO_TLITE)
+ #define ADC_RCC_AHB1Periph (RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_DMA2)
+ #define ADC_RCC_APB1Periph 0
+ #define ADC_RCC_APB2Periph RCC_APB2Periph_ADC1
+ #define ADC_GPIO_PIN_STICK_RV GPIO_Pin_0 // PA.00
+ #define ADC_GPIO_PIN_STICK_RH GPIO_Pin_1 // PA.01
+ #define ADC_GPIO_PIN_STICK_LV GPIO_Pin_2 // PA.02
+ #define ADC_GPIO_PIN_STICK_LH GPIO_Pin_3 // PA.03
+ #define ADC_CHANNEL_STICK_RV ADC_Channel_0 // ADC1_IN0
+ #define ADC_CHANNEL_STICK_RH ADC_Channel_1 // ADC1_IN1
+ #define ADC_CHANNEL_STICK_LV ADC_Channel_2 // ADC1_IN2
+ #define ADC_CHANNEL_STICK_LH ADC_Channel_3 // ADC1_IN3
+ #define ADC_GPIO_PIN_BATT GPIO_Pin_0 // PC.00
+ #define ADC_GPIOA_PINS (ADC_GPIO_PIN_STICK_RV | ADC_GPIO_PIN_STICK_RH | ADC_GPIO_PIN_STICK_LH | ADC_GPIO_PIN_STICK_LV)
+ #define ADC_GPIOB_PINS 0
+ #define ADC_GPIOC_PINS ADC_GPIO_PIN_BATT
+ #define ADC_CHANNEL_BATT ADC_Channel_10
+ #define ADC_VREF_PREC2 330
#elif defined(PCBX7)
#define HARDWARE_POT1
#define HARDWARE_POT2
@@ -922,6 +1130,14 @@
#define GPIO_LED_GPIO_OFF GPIO_SetBits
#define LED_RED_GPIO GPIOA
#define LED_RED_GPIO_PIN GPIO_Pin_13 // PA.13
+#elif defined(PCBXLITES)
+ #define STATUS_LEDS
+ #define GPIO_LED_GPIO_ON GPIO_ResetBits
+ #define GPIO_LED_GPIO_OFF GPIO_SetBits
+ #define LED_BLUE_GPIO GPIOE
+ #define LED_BLUE_GPIO_PIN GPIO_Pin_6 // PE.06
+ #define LED_RED_GPIO GPIOE
+ #define LED_RED_GPIO_PIN GPIO_Pin_4 // PE.04
#elif defined(PCBXLITE)
#define STATUS_LEDS
#define GPIO_LED_GPIO_ON GPIO_ResetBits
@@ -940,6 +1156,16 @@
#define LED_BLUE_GPIO_PIN GPIO_Pin_1 // PB.01
#define LED_RED_GPIO GPIOC
#define LED_RED_GPIO_PIN GPIO_Pin_4 // PC.04
+#elif defined(RADIO_T8)
+ #define STATUS_LEDS
+ #define GPIO_LED_GPIO_ON GPIO_SetBits
+ #define GPIO_LED_GPIO_OFF GPIO_ResetBits
+ #define LED_RED_GPIO GPIOC
+ #define LED_RED_GPIO_PIN GPIO_Pin_4 // PC.04
+ #define LED_BLUE_GPIO GPIOC
+ #define LED_BLUE_GPIO_PIN GPIO_Pin_5 // PC.05
+ #define LED_GREEN_GPIO GPIOB
+ #define LED_GREEN_GPIO_PIN GPIO_Pin_1 // PB.01
#elif defined(PCBX7)
#define STATUS_LEDS
#define GPIO_LED_GPIO_ON GPIO_SetBits
@@ -1065,8 +1291,10 @@
#define INTMODULE_DMA_STREAM_IRQHandler DMA2_Stream5_IRQHandler
#define INTMODULE_DMA_FLAG_TC DMA_IT_TCIF5
#define INTMODULE_TIMER_FREQ (PERI2_FREQUENCY * TIMER_MULT_APB2)
-#elif defined(RADIO_T12)
+#elif (defined(RADIO_FAMILY_JUMPER_T12) && defined(HARDWARE_INTERNAL_MODULE))|| defined(RADIO_TX12) || defined(RADIO_T8)
#define INTMODULE_RCC_AHB1Periph (RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_DMA1)
+ #define INTMODULE_RCC_APB1Periph (RCC_APB1Periph_USART3 | RCC_APB1Periph_TIM2)
+ #define INTMODULE_RCC_APB2Periph 0
#define INTMODULE_PWR_GPIO GPIOC
#define INTMODULE_PWR_GPIO_PIN GPIO_Pin_6 // PC.06
#define INTMODULE_GPIO GPIOB
@@ -1078,8 +1306,6 @@
#define INTMODULE_GPIO_AF GPIO_AF_USART3
#define INTMODULE_USART_IRQn USART3_IRQn
#define INTMODULE_USART_IRQHandler USART3_IRQHandler
- #define INTMODULE_RCC_APB1Periph RCC_APB1Periph_TIM2
- #define INTMODULE_RCC_APB2Periph RCC_APB1Periph_USART3
#define INTMODULE_TIMER TIM2
#define INTMODULE_TIMER_IRQn TIM2_IRQn
#define INTMODULE_TIMER_IRQHandler TIM2_IRQHandler
@@ -1155,70 +1381,23 @@
#define EXTMODULE_USART_TX_DMA_STREAM DMA2_Stream6
#define EXTMODULE_USART_RX_DMA_CHANNEL DMA_Channel_5
#define EXTMODULE_USART_RX_DMA_STREAM DMA2_Stream1
-#elif defined(RADIO_T12)
- //Jumper T12v2 external module configured
- #define EXTMODULE_RCC_AHB1Periph (RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_DMA2)
- #define EXTMODULE_RCC_APB2Periph RCC_APB2Periph_TIM8
- #define EXTMODULE_PWR_GPIO GPIOD
- #define EXTMODULE_PWR_GPIO_PIN GPIO_Pin_8 // JUMPER EXT PD.08 // X7 EXT is PD.08
- #define EXTERNAL_MODULE_PWR_ON() GPIO_SetBits(EXTMODULE_PWR_GPIO, EXTMODULE_PWR_GPIO_PIN)
- #define EXTERNAL_MODULE_PWR_OFF() GPIO_ResetBits(EXTMODULE_PWR_GPIO, EXTMODULE_PWR_GPIO_PIN)
- #define IS_EXTERNAL_MODULE_ON() (GPIO_ReadInputDataBit(EXTMODULE_PWR_GPIO, EXTMODULE_PWR_GPIO_PIN) == Bit_SET)
- #define EXTMODULE_TX_GPIO GPIOA
- #define EXTMODULE_TX_GPIO_PIN GPIO_Pin_7 // JUMPER EXT PA.07 // X7 EXT is PA.07
- #define EXTMODULE_TX_GPIO_PinSource GPIO_PinSource7
- #define EXTMODULE_TIMER TIM8
- #define EXTMODULE_TIMER_TX_GPIO_AF GPIO_AF_TIM8 // TIM8_CH1N
- #define EXTMODULE_TIMER_CC_IRQn TIM8_CC_IRQn
- #define EXTMODULE_TIMER_CC_IRQHandler TIM8_CC_IRQHandler
- #define EXTMODULE_TIMER_DMA_CHANNEL DMA_Channel_7
- #define EXTMODULE_TIMER_DMA_STREAM DMA2_Stream1
- #define EXTMODULE_TIMER_DMA_STREAM_IRQn DMA2_Stream1_IRQn
- #define EXTMODULE_TIMER_DMA_STREAM_IRQHandler DMA2_Stream1_IRQHandler
- #define EXTMODULE_TIMER_DMA_FLAG_TC DMA_IT_TCIF1
- #define EXTMODULE_TIMER_OUTPUT_ENABLE TIM_CCER_CC1NE
- #define EXTMODULE_TIMER_OUTPUT_POLARITY TIM_CCER_CC1NP
- #define EXTMODULE_TIMER_FREQ (PERI2_FREQUENCY * TIMER_MULT_APB2)
-#elif defined(RADIO_X9DP2019)
- #define EXTMODULE_RCC_AHB1Periph (RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_DMA2)
- #define EXTMODULE_RCC_APB2Periph (RCC_APB2Periph_TIM8 | RCC_APB2Periph_USART6)
- #define EXTMODULE_PWR_GPIO GPIOD
- #define EXTMODULE_PWR_GPIO_PIN GPIO_Pin_8 // PD.08
- #define EXTERNAL_MODULE_PWR_ON() GPIO_SetBits(EXTMODULE_PWR_GPIO, EXTMODULE_PWR_GPIO_PIN)
- #define EXTERNAL_MODULE_PWR_OFF() GPIO_ResetBits(EXTMODULE_PWR_GPIO, EXTMODULE_PWR_GPIO_PIN)
- #define IS_EXTERNAL_MODULE_ON() (GPIO_ReadInputDataBit(EXTMODULE_PWR_GPIO, EXTMODULE_PWR_GPIO_PIN) == Bit_SET)
- #define EXTMODULE_TX_GPIO GPIOC
- #define EXTMODULE_TX_GPIO_PIN GPIO_Pin_7 // PC.07
- #define EXTMODULE_TX_GPIO_PinSource GPIO_PinSource7
- #define EXTMODULE_TIMER TIM8
- #define EXTMODULE_TIMER_TX_GPIO_AF GPIO_AF_TIM8 // TIM8_CH2
- #define EXTMODULE_TIMER_CC_IRQn TIM8_CC_IRQn
- #define EXTMODULE_TIMER_CC_IRQHandler TIM8_CC_IRQHandler
- #define EXTMODULE_TIMER_DMA_CHANNEL DMA_Channel_7 // TIM8_UP
- #define EXTMODULE_TIMER_DMA_STREAM DMA2_Stream1 // TIM8_UP
- #define EXTMODULE_TIMER_DMA_STREAM_IRQn DMA2_Stream1_IRQn
- #define EXTMODULE_TIMER_DMA_STREAM_IRQHandler DMA2_Stream1_IRQHandler
- #define EXTMODULE_TIMER_DMA_FLAG_TC DMA_IT_TCIF1
- #define EXTMODULE_TIMER_OUTPUT_ENABLE TIM_CCER_CC2E
- #define EXTMODULE_TIMER_OUTPUT_POLARITY TIM_CCER_CC2NP
- #define EXTMODULE_TIMER_FREQ (PERI2_FREQUENCY * TIMER_MULT_APB2)
#else
- #define EXTMODULE_RCC_AHB1Periph (RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_DMA2)
- #define EXTMODULE_RCC_APB2Periph RCC_APB2Periph_TIM8
- #define EXTMODULE_PWR_GPIO GPIOD
- #define EXTMODULE_PWR_GPIO_PIN GPIO_Pin_8 // PD.08
- #define EXTERNAL_MODULE_PWR_ON() GPIO_SetBits(EXTMODULE_PWR_GPIO, EXTMODULE_PWR_GPIO_PIN)
- #define EXTERNAL_MODULE_PWR_OFF() GPIO_ResetBits(EXTMODULE_PWR_GPIO, EXTMODULE_PWR_GPIO_PIN)
- #define IS_EXTERNAL_MODULE_ON() (GPIO_ReadInputDataBit(EXTMODULE_PWR_GPIO, EXTMODULE_PWR_GPIO_PIN) == Bit_SET)
- #define EXTMODULE_TX_GPIO GPIOA
- #define EXTMODULE_TX_GPIO_PIN GPIO_Pin_7 // PA.07
- #define EXTMODULE_TX_GPIO_PinSource GPIO_PinSource7
- #define EXTMODULE_TIMER TIM8
- #define EXTMODULE_TIMER_TX_GPIO_AF GPIO_AF_TIM8 // TIM8_CH1N
- #define EXTMODULE_TIMER_CC_IRQn TIM8_CC_IRQn
- #define EXTMODULE_TIMER_CC_IRQHandler TIM8_CC_IRQHandler
- #define EXTMODULE_TIMER_DMA_CHANNEL DMA_Channel_7 // TIM8_UP
- #define EXTMODULE_TIMER_DMA_STREAM DMA2_Stream1 // TIM8_UP
+ #define EXTMODULE_RCC_AHB1Periph (RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_DMA2)
+ #define EXTMODULE_RCC_APB2Periph RCC_APB2Periph_TIM8
+ #define EXTMODULE_PWR_GPIO GPIOD
+ #define EXTMODULE_PWR_GPIO_PIN GPIO_Pin_8 // PD.08
+ #define EXTERNAL_MODULE_PWR_ON() GPIO_SetBits(EXTMODULE_PWR_GPIO, EXTMODULE_PWR_GPIO_PIN)
+ #define EXTERNAL_MODULE_PWR_OFF() GPIO_ResetBits(EXTMODULE_PWR_GPIO, EXTMODULE_PWR_GPIO_PIN)
+ #define IS_EXTERNAL_MODULE_ON() (GPIO_ReadInputDataBit(EXTMODULE_PWR_GPIO, EXTMODULE_PWR_GPIO_PIN) == Bit_SET)
+ #define EXTMODULE_TX_GPIO GPIOA
+ #define EXTMODULE_TX_GPIO_PIN GPIO_Pin_7
+ #define EXTMODULE_TX_GPIO_PinSource GPIO_PinSource7 // PA.07
+ #define EXTMODULE_TIMER TIM8
+ #define EXTMODULE_TIMER_TX_GPIO_AF GPIO_AF_TIM8 // TIM8_CH1N
+ #define EXTMODULE_TIMER_CC_IRQn TIM8_CC_IRQn
+ #define EXTMODULE_TIMER_CC_IRQHandler TIM8_CC_IRQHandler
+ #define EXTMODULE_TIMER_DMA_CHANNEL DMA_Channel_7
+ #define EXTMODULE_TIMER_DMA_STREAM DMA2_Stream1
#define EXTMODULE_TIMER_DMA_STREAM_IRQn DMA2_Stream1_IRQn
#define EXTMODULE_TIMER_DMA_STREAM_IRQHandler DMA2_Stream1_IRQHandler
#define EXTMODULE_TIMER_DMA_FLAG_TC DMA_IT_TCIF1
@@ -1361,7 +1540,7 @@
#define TELEMETRY_EXTI_IRQn EXTI9_5_IRQn
#define TELEMETRY_EXTI_TRIGGER EXTI_Trigger_Rising
-#if defined(RADIO_X7) || defined(RADIO_X7ACCESS)
+#if defined(RADIO_X7) || defined(RADIO_X7ACCESS) || defined(RADIO_TX12) || defined(RADIO_T8)
#define TELEMETRY_EXTI_REUSE_INTERRUPT_ROTARY_ENCODER
#elif defined(PCBXLITE) || defined(PCBX9LITE) || defined(RADIO_X9DP2019)
#define TELEMETRY_EXTI_IRQHandler EXTI9_5_IRQHandler
@@ -1374,7 +1553,7 @@
#define TELEMETRY_TIMER_IRQHandler TIM1_TRG_COM_TIM11_IRQHandler
// PCBREV
-#if defined(PCBX7)
+#if defined(RADIO_X7)
#define PCBREV_RCC_AHB1Periph RCC_AHB1Periph_GPIOA
#define PCBREV_GPIO GPIOA
#define PCBREV_GPIO_PIN GPIO_Pin_14 // PA.14
@@ -1384,6 +1563,16 @@
#define PCBREV_RCC_AHB1Periph 0
#endif
+
+// USB Charger
+#if defined(USB_CHARGER)
+ #define USB_CHARGER_RCC_AHB1Periph RCC_AHB1Periph_GPIOB
+ #define USB_CHARGER_GPIO GPIOB
+ #define USB_CHARGER_GPIO_PIN GPIO_Pin_5 // PB.05
+#else
+ #define USB_CHARGER_RCC_AHB1Periph 0
+#endif
+
// S.Port update connector
#if defined(PCBXLITE)
#define SPORT_MAX_BAUDRATE 250000 // not tested
@@ -1399,7 +1588,7 @@
#define SPORT_UPDATE_PWR_GPIO_PIN GPIO_Pin_3 // PB.03
#define GPIO_SPORT_UPDATE_PWR_GPIO_ON GPIO_SetBits
#define GPIO_SPORT_UPDATE_PWR_GPIO_OFF GPIO_ResetBits
-#elif defined(PCBX7)
+#elif defined(RADIO_X7)
#define SPORT_MAX_BAUDRATE 250000 // < 400000
#define SPORT_UPDATE_RCC_AHB1Periph RCC_AHB1Periph_GPIOB
#define SPORT_UPDATE_PWR_GPIO GPIOB
@@ -1427,7 +1616,9 @@
// Heartbeat for iXJT / ISRM synchro
#define INTMODULE_HEARTBEAT_TRIGGER EXTI_Trigger_Falling
-#if defined(PCBXLITE)
+#if !defined(HARDWARE_EXTERNAL_MODULE)
+ // No heartbeat
+#elif defined(PCBXLITE)
#define INTMODULE_HEARTBEAT
#define INTMODULE_HEARTBEAT_RCC_AHB1Periph RCC_AHB1Periph_GPIOD
#define INTMODULE_HEARTBEAT_GPIO GPIOD
@@ -1457,7 +1648,7 @@
#define INTMODULE_HEARTBEAT_EXTI_PinSource GPIO_PinSource7
#define INTMODULE_HEARTBEAT_EXTI_LINE EXTI_Line7
#define INTMODULE_HEARTBEAT_EXTI_IRQn EXTI9_5_IRQn
-#elif defined(RADIO_X7)
+#elif defined(RADIO_X7) || defined(RADIO_TX12)
#define INTMODULE_HEARTBEAT
#define INTMODULE_HEARTBEAT_REUSE_INTERRUPT_ROTARY_ENCODER
#define INTMODULE_HEARTBEAT_RCC_AHB1Periph RCC_AHB1Periph_GPIOC
@@ -1527,29 +1718,31 @@
#define TRAINER_MODULE_SBUS_DMA_STREAM EXTMODULE_USART_RX_DMA_STREAM
#define TRAINER_MODULE_SBUS_DMA_CHANNEL EXTMODULE_USART_RX_DMA_CHANNEL
#else
+#if defined(HARDWARE_EXTERNAL_MODULE)
#define TRAINER_MODULE_CPPM
#define TRAINER_MODULE_SBUS
- #define TRAINER_MODULE_RCC_AHB1Periph RCC_AHB1Periph_GPIOC
- #define TRAINER_MODULE_RCC_APB2Periph RCC_APB2Periph_USART6
- #define TRAINER_MODULE_RCC_APB1Periph RCC_APB1Periph_TIM3
- #define TRAINER_MODULE_CPPM_TIMER TRAINER_TIMER
- #define TRAINER_MODULE_CPPM_GPIO INTMODULE_HEARTBEAT_GPIO
- #define TRAINER_MODULE_CPPM_GPIO_PIN INTMODULE_HEARTBEAT_GPIO_PIN
- #define TRAINER_MODULE_CPPM_GPIO_PinSource INTMODULE_HEARTBEAT_EXTI_PinSource
- #define TRAINER_MODULE_CPPM_INTERRUPT_ENABLE TIM_DIER_CC2IE
- #define TRAINER_MODULE_CPPM_INTERRUPT_FLAG TIM_SR_CC2IF
- #define TRAINER_MODULE_CPPM_CCMR1 (TIM_CCMR1_IC2F_0 | TIM_CCMR1_IC2F_1 | TIM_CCMR1_CC2S_0)
- #define TRAINER_MODULE_CPPM_CCER TIM_CCER_CC2E
- #define TRAINER_MODULE_CPPM_COUNTER_REGISTER TRAINER_TIMER->CCR2
- #define TRAINER_MODULE_CPPM_TIMER_IRQn TRAINER_TIMER_IRQn
- #define TRAINER_MODULE_CPPM_GPIO_AF GPIO_AF_TIM3
- #define TRAINER_MODULE_SBUS_GPIO_AF GPIO_AF_USART6
- #define TRAINER_MODULE_SBUS_USART USART6
- #define TRAINER_MODULE_SBUS_GPIO INTMODULE_HEARTBEAT_GPIO
- #define TRAINER_MODULE_SBUS_GPIO_PIN INTMODULE_HEARTBEAT_GPIO_PIN
- #define TRAINER_MODULE_SBUS_GPIO_PinSource INTMODULE_HEARTBEAT_EXTI_PinSource
- #define TRAINER_MODULE_SBUS_DMA_STREAM DMA2_Stream1
- #define TRAINER_MODULE_SBUS_DMA_CHANNEL DMA_Channel_5
+#endif
+ #define TRAINER_MODULE_RCC_AHB1Periph RCC_AHB1Periph_GPIOC
+ #define TRAINER_MODULE_RCC_APB2Periph RCC_APB2Periph_USART6
+ #define TRAINER_MODULE_RCC_APB1Periph RCC_APB1Periph_TIM3
+ #define TRAINER_MODULE_CPPM_TIMER TRAINER_TIMER
+ #define TRAINER_MODULE_CPPM_GPIO INTMODULE_HEARTBEAT_GPIO
+ #define TRAINER_MODULE_CPPM_GPIO_PIN INTMODULE_HEARTBEAT_GPIO_PIN
+ #define TRAINER_MODULE_CPPM_GPIO_PinSource INTMODULE_HEARTBEAT_EXTI_PinSource
+ #define TRAINER_MODULE_CPPM_INTERRUPT_ENABLE TIM_DIER_CC2IE
+ #define TRAINER_MODULE_CPPM_INTERRUPT_FLAG TIM_SR_CC2IF
+ #define TRAINER_MODULE_CPPM_CCMR1 (TIM_CCMR1_IC2F_0 | TIM_CCMR1_IC2F_1 | TIM_CCMR1_CC2S_0)
+ #define TRAINER_MODULE_CPPM_CCER TIM_CCER_CC2E
+ #define TRAINER_MODULE_CPPM_COUNTER_REGISTER TRAINER_TIMER->CCR2
+ #define TRAINER_MODULE_CPPM_TIMER_IRQn TRAINER_TIMER_IRQn
+ #define TRAINER_MODULE_CPPM_GPIO_AF GPIO_AF_TIM3
+ #define TRAINER_MODULE_SBUS_GPIO_AF GPIO_AF_USART6
+ #define TRAINER_MODULE_SBUS_USART USART6
+ #define TRAINER_MODULE_SBUS_GPIO INTMODULE_HEARTBEAT_GPIO
+ #define TRAINER_MODULE_SBUS_GPIO_PIN INTMODULE_HEARTBEAT_GPIO_PIN
+ #define TRAINER_MODULE_SBUS_GPIO_PinSource INTMODULE_HEARTBEAT_EXTI_PinSource
+ #define TRAINER_MODULE_SBUS_DMA_STREAM DMA2_Stream1
+ #define TRAINER_MODULE_SBUS_DMA_CHANNEL DMA_Channel_5
#endif
// USB
@@ -1615,6 +1808,10 @@
#define BACKLIGHT_CCMR1 TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2 // Channel 1, PWM
#define BACKLIGHT_CCER TIM_CCER_CC1E
#define BACKLIGHT_COUNTER_REGISTER BACKLIGHT_TIMER->CCR1
+#elif defined(RADIO_T8)
+ #define BACKLIGHT_RCC_AHB1Periph 0
+ #define BACKLIGHT_RCC_APB1Periph 0
+ #define BACKLIGHT_RCC_APB2Periph 0
#elif defined(PCBX7)
#define BACKLIGHT_RCC_AHB1Periph RCC_AHB1Periph_GPIOD
#define BACKLIGHT_RCC_APB1Periph RCC_APB1Periph_TIM4
@@ -1642,6 +1839,9 @@
#define KEYS_BACKLIGHT_RCC_AHB1Periph 0
// LCD driver
+#if defined(RADIO_TX12) || defined(RADIO_FAMILY_JUMPER_T12) || defined(RADIO_T8)
+ #define LCD_VERTICAL_INVERT
+#endif
#if defined(PCBX9E)
#define LCD_RCC_AHB1Periph (RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_DMA1)
#define LCD_RCC_APB1Periph RCC_APB1Periph_SPI3
@@ -1834,6 +2034,16 @@
#define AUDIO_SPEAKER_ENABLE_GPIO_PIN GPIO_Pin_14 // PD.14
#define HEADPHONE_TRAINER_SWITCH_GPIO GPIOD
#define HEADPHONE_TRAINER_SWITCH_GPIO_PIN GPIO_Pin_9 // PD.09
+#elif defined(AUDIO_MUTE_GPIO)
+ #define AUDIO_RCC_AHB1Periph (RCC_AHB1Periph_GPIOE | RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_DMA1)
+ #define AUDIO_MUTE_GPIO GPIOE
+ #define AUDIO_MUTE_GPIO_PIN GPIO_Pin_12 // PE.12
+ #define AUDIO_MUTE_DELAY 500 // ms
+#if defined(RADIO_TLITE)
+ #define AUDIO_UNMUTE_DELAY 250 // ms
+#else
+ #define AUDIO_UNMUTE_DELAY 150 // ms
+#endif
#else
#define AUDIO_RCC_AHB1Periph (RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_DMA1)
#endif
@@ -1922,7 +2132,7 @@
#define BT_TX_GPIO_PinSource GPIO_PinSource14
#define BT_RX_GPIO_PinSource GPIO_PinSource9
#define BT_USART_IRQHandler USART6_IRQHandler
-#elif defined(PCBX7) || defined(PCBXLITE) || defined(PCBX9LITES) || defined(RADIO_X9DP2019)
+#elif defined(RADIO_X7) || defined(RADIO_X7ACCESS) || defined(PCBXLITE) || defined(PCBX9LITES) || defined(RADIO_X9DP2019)
#define STORAGE_BLUETOOTH
#define BT_RCC_APB1Periph RCC_APB1Periph_USART3
#define BT_RCC_APB2Periph 0
@@ -1954,7 +2164,7 @@
#define BT_USART_IRQn USART3_IRQn
// #define BT_DMA_Stream_RX DMA1_Stream1
// #define BT_DMA_Channel_RX DMA_Channel_4
-#elif defined(PCBX9D) || defined(PCBX9DP)
+#elif defined(PCBX9D) || defined(PCBX9DP) || defined(RADIO_FAMILY_JUMPER_T12) || defined(RADIO_TX12) || defined(RADIO_T8)
#define STORAGE_BLUETOOTH
#define BT_RCC_AHB1Periph 0
#define BT_RCC_APB1Periph 0
@@ -1975,4 +2185,11 @@
#define TIMER_2MHz_RCC_APB1Periph RCC_APB1Periph_TIM7
#define TIMER_2MHz_TIMER TIM7
+// Mixer scheduler timer
+#define MIXER_SCHEDULER_TIMER_RCC_APB1Periph RCC_APB1Periph_TIM13
+#define MIXER_SCHEDULER_TIMER TIM13
+#define MIXER_SCHEDULER_TIMER_FREQ (PERI1_FREQUENCY * TIMER_MULT_APB1)
+#define MIXER_SCHEDULER_TIMER_IRQn TIM8_UP_TIM13_IRQn
+#define MIXER_SCHEDULER_TIMER_IRQHandler TIM8_UP_TIM13_IRQHandler
+
#endif // _HAL_H_
diff --git a/radio/src/targets/taranis/intmodule_pulses_driver.cpp b/radio/src/targets/taranis/intmodule_pulses_driver.cpp
index e71768eac..9afacfda8 100644
--- a/radio/src/targets/taranis/intmodule_pulses_driver.cpp
+++ b/radio/src/targets/taranis/intmodule_pulses_driver.cpp
@@ -42,21 +42,23 @@ void intmoduleSendNextFrame()
#if defined(PXX1)
case PROTOCOL_CHANNELS_PXX1_PULSES:
{
- uint32_t last = intmodulePulsesData.pxx.getLast();
- if (heartbeatCapture.valid) {
- if (getTmr2MHz() - heartbeatCapture.timestamp > HEARBEAT_OFFSET)
- last -= 21;
- else
- last += 19;
- intmodulePulsesData.pxx.setLast(last);
- }
- INTMODULE_TIMER->CCR2 = last - 4000; // 2mS in advance
+ if (INTMODULE_DMA_STREAM->CR & DMA_SxCR_EN)
+ return;
+
+ //disable timer
+ INTMODULE_TIMER->CR1 &= ~TIM_CR1_CEN;
+
+ //INTMODULE_TIMER->CCR2 = last - 4000; // 2mS in advance
INTMODULE_DMA_STREAM->CR &= ~DMA_SxCR_EN; // Disable DMA
INTMODULE_DMA_STREAM->CR |= INTMODULE_DMA_CHANNEL | DMA_SxCR_DIR_0 | DMA_SxCR_MINC | DMA_SxCR_PSIZE_0 | DMA_SxCR_MSIZE_0 | DMA_SxCR_PL_0 | DMA_SxCR_PL_1;
INTMODULE_DMA_STREAM->PAR = CONVERT_PTR_UINT(&INTMODULE_TIMER->ARR);
INTMODULE_DMA_STREAM->M0AR = CONVERT_PTR_UINT(intmodulePulsesData.pxx.getData());
INTMODULE_DMA_STREAM->NDTR = intmodulePulsesData.pxx.getSize();
INTMODULE_DMA_STREAM->CR |= DMA_SxCR_EN | DMA_SxCR_TCIE; // Enable DMA
+
+ // re-init timer
+ INTMODULE_TIMER->EGR = 1;
+ INTMODULE_TIMER->CR1 |= TIM_CR1_CEN;
break;
}
#endif
@@ -97,17 +99,16 @@ void intmodulePxx1PulsesStart()
INTMODULE_TIMER->CR1 &= ~TIM_CR1_CEN;
INTMODULE_TIMER->PSC = INTMODULE_TIMER_FREQ / 2000000 - 1; // 0.5uS (2Mhz)
- INTMODULE_TIMER->ARR = 18000;
+
INTMODULE_TIMER->CCER = TIM_CCER_CC3E | TIM_CCER_CC3NE;
INTMODULE_TIMER->BDTR = TIM_BDTR_MOE; // Enable outputs
INTMODULE_TIMER->CCR3 = 16;
INTMODULE_TIMER->CCMR2 = TIM_CCMR2_OC3M_2 | TIM_CCMR2_OC3M_0; // Force O/P high
INTMODULE_TIMER->EGR = 1; // Restart
- INTMODULE_TIMER->DIER |= TIM_DIER_UDE; // Enable DMA on update
- INTMODULE_TIMER->CCMR2 = TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3M_2;
+ INTMODULE_TIMER->CCMR2 = TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3M_2 | TIM_CCMR2_OC3PE;
+ INTMODULE_TIMER->ARR = 40000;
INTMODULE_TIMER->SR &= ~TIM_SR_CC2IF; // Clear flag
- INTMODULE_TIMER->CCR2 = 16000; // The first frame will be sent in 20ms
- INTMODULE_TIMER->DIER |= TIM_DIER_CC2IE; // Enable this interrupt
+ INTMODULE_TIMER->DIER |= TIM_DIER_UDE; // Enable DMA on update
INTMODULE_TIMER->CR1 |= TIM_CR1_CEN;
NVIC_EnableIRQ(INTMODULE_DMA_STREAM_IRQn);
@@ -157,8 +158,12 @@ extern "C" void INTMODULE_DMA_STREAM_IRQHandler()
DMA_ClearITPendingBit(INTMODULE_DMA_STREAM, INTMODULE_DMA_FLAG_TC);
- INTMODULE_TIMER->SR &= ~TIM_SR_CC2IF; // Clear flag
- INTMODULE_TIMER->DIER |= TIM_DIER_CC2IE; // Enable this interrupt
+ switch (moduleState[INTERNAL_MODULE].protocol) {
+ case PROTOCOL_CHANNELS_PPM:
+ INTMODULE_TIMER->SR &= ~TIM_SR_CC2IF; // Clear flag
+ INTMODULE_TIMER->DIER |= TIM_DIER_CC2IE; // Enable this interrupt
+ break;
+ }
}
extern "C" void INTMODULE_TIMER_CC_IRQHandler()
diff --git a/radio/src/targets/taranis/keys_driver.cpp b/radio/src/targets/taranis/keys_driver.cpp
index 0699a1c50..bca5e3e97 100644
--- a/radio/src/targets/taranis/keys_driver.cpp
+++ b/radio/src/targets/taranis/keys_driver.cpp
@@ -37,6 +37,31 @@ uint32_t readKeys()
result |= 1 << KEY_PAGE;
#endif
+#if defined(KEYS_GPIO_PIN_PAGEUP)
+ if (~KEYS_GPIO_REG_PAGEUP & KEYS_GPIO_PIN_PAGEUP)
+ result |= 1 << KEY_PAGEUP;
+#endif
+
+#if defined(KEYS_GPIO_PIN_PAGEDN)
+ if (~KEYS_GPIO_REG_PAGEDN & KEYS_GPIO_PIN_PAGEDN)
+ result |= 1 << KEY_PAGEDN;
+#endif
+
+#if defined(KEYS_GPIO_PIN_SYS)
+ if (~KEYS_GPIO_REG_SYS & KEYS_GPIO_PIN_SYS)
+ result |= 1 << KEY_SYS;
+#endif
+
+#if defined(KEYS_GPIO_PIN_MDL)
+ if (~KEYS_GPIO_REG_MDL & KEYS_GPIO_PIN_MDL)
+ result |= 1 << KEY_MODEL;
+#endif
+
+#if defined(KEYS_GPIO_PIN_TELE)
+ if (~KEYS_GPIO_REG_TELE & KEYS_GPIO_PIN_TELE)
+ result |= 1 << KEY_TELE;
+#endif
+
if (~KEYS_GPIO_REG_EXIT & KEYS_GPIO_PIN_EXIT)
result |= 1 << KEY_EXIT;
@@ -63,6 +88,10 @@ uint32_t readKeys()
result |= 1 << KEY_SHIFT;
#endif
+#if defined(KEYS_GPIO_PIN_BIND)
+ if (~KEYS_GPIO_REG_BIND & KEYS_GPIO_PIN_BIND)
+ result |= 1 << KEY_BIND;
+#endif
// if (result != 0) TRACE("readKeys(): result=0x%02x", result);
return result;
@@ -115,7 +144,7 @@ void readKeysAndTrims()
{
uint8_t index = 0;
uint32_t keys_input = readKeys();
- for (uint8_t i = 1; i != uint8_t(1 << TRM_BASE); i <<= 1) {
+ for (unsigned i = 1; i != unsigned(1 << TRM_BASE); i <<= 1) {
keys[index++].input(keys_input & i);
}
@@ -175,10 +204,21 @@ uint32_t switchState(uint8_t index)
uint32_t xxx = 0;
switch (index) {
+
+#if defined(RADIO_TX12) || defined(RADIO_T8)
+ ADD_2POS_CASE(A);
+ ADD_3POS_CASE(B, 1);
+ ADD_3POS_CASE(C, 2);
+#elif defined(RADIO_TLITE)
+ ADD_3POS_CASE(A, 0);
+ ADD_3POS_CASE(B, 1);
+ ADD_2POS_CASE(C);
+ ADD_2POS_CASE(D);
+#else
ADD_3POS_CASE(A, 0);
ADD_3POS_CASE(B, 1);
ADD_3POS_CASE(C, 2);
-
+#endif
#if defined(PCBX9LITES)
ADD_2POS_CASE(D);
ADD_2POS_CASE(E);
@@ -201,6 +241,14 @@ uint32_t switchState(uint8_t index)
ADD_2POS_CASE(H);
ADD_2POS_CASE(I);
// no SWJ on XLITE
+#elif defined(RADIO_TX12)
+ ADD_2POS_CASE(D);
+ ADD_3POS_CASE(E, 4);
+ ADD_3POS_CASE(F, 5);
+#elif defined(RADIO_T8)
+ ADD_2POS_CASE(D);
+#elif defined(RADIO_TLITE)
+ // Only 4 switches
#elif defined(PCBX7)
ADD_3POS_CASE(D, 3);
ADD_2POS_CASE(F);
diff --git a/radio/src/targets/taranis/lcd_driver_spi.cpp b/radio/src/targets/taranis/lcd_driver_spi.cpp
index ca66dc1a7..07924671c 100644
--- a/radio/src/targets/taranis/lcd_driver_spi.cpp
+++ b/radio/src/targets/taranis/lcd_driver_spi.cpp
@@ -20,7 +20,7 @@
#include "opentx.h"
-#if defined(RADIO_T12)
+#if defined(RADIO_FAMILY_JUMPER_T12) || defined(RADIO_TX12) || defined(RADIO_T8)
#define LCD_CONTRAST_OFFSET -10
#else
#define LCD_CONTRAST_OFFSET 160
@@ -107,8 +107,8 @@ void lcdHardwareInit()
#if LCD_W == 128
void lcdStart()
{
-#if defined(RADIO_T12)
- // Jumper has the screen inverted.
+#if defined(LCD_VERTICAL_INVERT)
+ // T12 and TX12 have the screen inverted.
lcdWriteCommand(0xe2); // (14) Soft reset
lcdWriteCommand(0xa0); // Set seg
lcdWriteCommand(0xc8); // Set com
@@ -144,9 +144,9 @@ void lcdStart()
lcdWriteCommand(0xE9); // Set bias=1/10
lcdWriteCommand(0x81); // Set Vop
#if defined(BOOT)
- lcdWriteCommand(LCD_CONTRAST_OFFSET+LCD_CONTRAST_DEFAULT);
+ lcdWriteCommand(LCD_CONTRAST_OFFSET + LCD_CONTRAST_DEFAULT);
#else
- lcdWriteCommand(LCD_CONTRAST_OFFSET+g_eeGeneral.contrast);
+ lcdWriteCommand(LCD_CONTRAST_OFFSET + g_eeGeneral.contrast);
#endif
lcdWriteCommand(0xA2); // Set line rate: 28KLPS
lcdWriteCommand(0x28); // Set panel loading
@@ -173,11 +173,11 @@ void lcdStart()
void lcdWriteAddress(uint8_t x, uint8_t y)
{
- lcdWriteCommand(x & 0x0F); // Set Column Address LSB CA[3:0]
- lcdWriteCommand((x>>4) | 0x10); // Set Column Address MSB CA[7:4]
+ lcdWriteCommand(x & 0x0Fu); // Set Column Address LSB CA[3:0]
+ lcdWriteCommand((x >> 4u) | 0x10u); // Set Column Address MSB CA[7:4]
- lcdWriteCommand((y&0x0F) | 0x60); // Set Row Address LSB RA [3:0]
- lcdWriteCommand(((y>>4) & 0x0F) | 0x70); // Set Row Address MSB RA [7:4]
+ lcdWriteCommand((y & 0x0Fu) | 0x60u); // Set Row Address LSB RA [3:0]
+ lcdWriteCommand(((y >> 4u) & 0x0Fu) | 0x70u); // Set Row Address MSB RA [7:4]
}
#endif
@@ -201,7 +201,7 @@ void lcdRefresh(bool wait)
for (uint8_t y=0; y < 8; y++, p+=LCD_W) {
lcdWriteCommand(0x10); // Column addr 0
lcdWriteCommand(0xB0 | y); // Page addr y
-#if !defined(RADIO_T12)
+#if !defined(LCD_VERTICAL_INVERT)
lcdWriteCommand(0x04);
#endif
diff --git a/radio/src/targets/taranis/telemetry_driver.cpp b/radio/src/targets/taranis/telemetry_driver.cpp
index b46eca541..c16d6feca 100644
--- a/radio/src/targets/taranis/telemetry_driver.cpp
+++ b/radio/src/targets/taranis/telemetry_driver.cpp
@@ -122,8 +122,8 @@ void telemetryPortInvertedInit(uint32_t baudrate)
probeTimeFromStartBit = 25;
break;
case 57600:
- bitLength = 35; //34 was used before - I prefer to use use 35 because of lower error
- probeTimeFromStartBit = 52; //round down - 48 used in original implementation
+ bitLength = 35;
+ probeTimeFromStartBit = 48;
break;
default:
bitLength = 2000000/baudrate; //because of 0,5 us tick
@@ -203,6 +203,11 @@ void telemetryPortInvertedRxBit()
void telemetryPortSetDirectionOutput()
{
+#if defined(GHOST) && SPORT_MAX_BAUDRATE < 400000
+ if (isModuleGhost(EXTERNAL_MODULE)) {
+ TELEMETRY_USART->BRR = BRR_400K;
+ }
+#endif
TELEMETRY_DIR_OUTPUT();
TELEMETRY_USART->CR1 &= ~USART_CR1_RE; // turn off receiver
}
@@ -215,6 +220,11 @@ void sportWaitTransmissionComplete()
void telemetryPortSetDirectionInput()
{
sportWaitTransmissionComplete();
+#if defined(GHOST) && SPORT_MAX_BAUDRATE < 400000
+ if (isModuleGhost(EXTERNAL_MODULE) && g_eeGeneral.telemetryBaudrate == GHST_TELEMETRY_RATE_115K) {
+ TELEMETRY_USART->BRR = BRR_115K;
+ }
+#endif
TELEMETRY_DIR_INPUT();
TELEMETRY_USART->CR1 |= USART_CR1_RE; // turn on receiver
}
diff --git a/radio/src/targets/taranis/usb_charger_driver.cpp b/radio/src/targets/taranis/usb_charger_driver.cpp
new file mode 100644
index 000000000..78cc3d6a6
--- /dev/null
+++ b/radio/src/targets/taranis/usb_charger_driver.cpp
@@ -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.
+ */
+
+#include "opentx.h"
+
+void usbChargerInit()
+{
+ GPIO_InitTypeDef GPIO_InitStructure;
+ GPIO_InitStructure.GPIO_Pin = USB_CHARGER_GPIO_PIN;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
+ GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
+ GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
+ GPIO_Init(USB_CHARGER_GPIO, &GPIO_InitStructure);
+}
+
+bool usbChargerLed()
+{
+#if defined(SIMU)
+ return true;
+#else
+ return (GPIO_ReadInputDataBit(USB_CHARGER_GPIO, USB_CHARGER_GPIO_PIN) == Bit_RESET && usbPlugged());
+#endif
+}
diff --git a/radio/src/tasks.cpp b/radio/src/tasks.cpp
index e9dcfac45..f44e1cb16 100644
--- a/radio/src/tasks.cpp
+++ b/radio/src/tasks.cpp
@@ -19,6 +19,7 @@
*/
#include "opentx.h"
+#include "mixer_scheduler.h"
RTOS_TASK_HANDLE menusTaskId;
RTOS_DEFINE_STACK(menusStack, MENUS_STACK_SIZE);
@@ -32,16 +33,6 @@ RTOS_DEFINE_STACK(audioStack, AUDIO_STACK_SIZE);
RTOS_MUTEX_HANDLE audioMutex;
RTOS_MUTEX_HANDLE mixerMutex;
-enum TaskIndex {
- MENU_TASK_INDEX,
- MIXER_TASK_INDEX,
- AUDIO_TASK_INDEX,
- CLI_TASK_INDEX,
- BLUETOOTH_TASK_INDEX,
- TASK_INDEX_COUNT,
- MAIN_TASK_INDEX = 255
-};
-
void stackPaint()
{
menusStack.paint();
@@ -75,13 +66,30 @@ bool isForcePowerOffRequested()
bool isModuleSynchronous(uint8_t moduleIdx)
{
- uint8_t protocol = moduleState[moduleIdx].protocol;
- if (protocol == PROTOCOL_CHANNELS_PXX2_HIGHSPEED || protocol == PROTOCOL_CHANNELS_PXX2_LOWSPEED || protocol == PROTOCOL_CHANNELS_CROSSFIRE || protocol == PROTOCOL_CHANNELS_NONE)
- return true;
-#if defined(INTMODULE_USART) || defined(EXTMODULE_USART)
- if (protocol == PROTOCOL_CHANNELS_PXX1_SERIAL)
- return true;
+ switch(moduleState[moduleIdx].protocol) {
+ case PROTOCOL_CHANNELS_PXX2_HIGHSPEED:
+ case PROTOCOL_CHANNELS_PXX2_LOWSPEED:
+ case PROTOCOL_CHANNELS_CROSSFIRE:
+ case PROTOCOL_CHANNELS_GHOST:
+ case PROTOCOL_CHANNELS_AFHDS3:
+ case PROTOCOL_CHANNELS_NONE:
+
+#if defined(MULTIMODULE)
+ case PROTOCOL_CHANNELS_MULTIMODULE:
#endif
+#if defined(INTMODULE_USART) || defined(EXTMODULE_USART)
+ case PROTOCOL_CHANNELS_PXX1_SERIAL:
+#endif
+ // case PROTOCOL_CHANNELS_PPM:
+ case PROTOCOL_CHANNELS_PXX1_PULSES:
+#if defined(DSM2)
+ case PROTOCOL_CHANNELS_SBUS:
+ case PROTOCOL_CHANNELS_DSM2_LP45:
+ case PROTOCOL_CHANNELS_DSM2_DSM2:
+ case PROTOCOL_CHANNELS_DSM2_DSMX:
+#endif
+ return true;
+ }
return false;
}
@@ -94,10 +102,12 @@ void sendSynchronousPulses(uint8_t runMask)
}
#endif
+#if defined(HARDWARE_EXTERNAL_MODULE)
if ((runMask & (1 << EXTERNAL_MODULE)) && isModuleSynchronous(EXTERNAL_MODULE)) {
if (setupPulsesExternalModule())
extmoduleSendNextFrame();
}
+#endif
}
uint32_t nextMixerTime[NUM_MODULES];
@@ -106,6 +116,11 @@ TASK_FUNCTION(mixerTask)
{
s_pulses_paused = true;
+ mixerSchedulerInit();
+#if !defined(PCBSKY9X)
+ mixerSchedulerStart();
+#endif
+
while (true) {
#if defined(SBUS_TRAINER)
// SBUS trainer
@@ -120,7 +135,18 @@ TASK_FUNCTION(mixerTask)
bluetooth.wakeup();
#endif
- RTOS_WAIT_TICKS(1);
+ // run mixer at least every 30ms
+ bool timeout = mixerSchedulerWaitForTrigger(30);
+
+#if defined(DEBUG_MIXER_SCHEDULER)
+ GPIO_SetBits(EXTMODULE_TX_GPIO, EXTMODULE_TX_GPIO_PIN);
+ GPIO_ResetBits(EXTMODULE_TX_GPIO, EXTMODULE_TX_GPIO_PIN);
+#endif
+
+#if !defined(PCBSKY9X)
+ // re-enable trigger
+ mixerSchedulerEnableTrigger();
+#endif
#if defined(SIMU)
if (pwrCheck() == e_power_off) {
@@ -132,29 +158,22 @@ TASK_FUNCTION(mixerTask)
}
#endif
- uint32_t now = RTOS_GET_MS();
- uint8_t runMask = 0;
-
- if (now >= nextMixerTime[0]) {
- runMask |= (1 << 0);
- }
-
-#if NUM_MODULES >= 2
- if (now >= nextMixerTime[1]) {
- runMask |= (1 << 1);
- }
-#endif
-
- if (!runMask) {
- continue; // go back to sleep
- }
-
if (!s_pulses_paused) {
uint16_t t0 = getTmr2MHz();
DEBUG_TIMER_START(debugTimerMixer);
RTOS_LOCK_MUTEX(mixerMutex);
+
doMixerCalculations();
+
+#if defined(PCBSKY9X)
+ sendSynchronousPulses(1 << EXTERNAL_MODULE);
+#else
+ sendSynchronousPulses((1 << INTERNAL_MODULE) | (1 << EXTERNAL_MODULE));
+#endif
+
+ doMixerPeriodicUpdates();
+
DEBUG_TIMER_START(debugTimerMixerCalcToUsage);
DEBUG_TIMER_SAMPLE(debugTimerMixerIterval);
RTOS_UNLOCK_MUTEX(mixerMutex);
@@ -183,7 +202,13 @@ TASK_FUNCTION(mixerTask)
if (t0 > maxMixerDuration)
maxMixerDuration = t0;
- sendSynchronousPulses(runMask);
+ // TODO:
+ // - check the cause of timeouts when switching
+ // between protocols with multi-proto RF
+#if defined(DEBUG)
+ if (timeout)
+ serialPrint("mix sched timeout!");
+#endif
}
}
}
diff --git a/radio/src/tasks.h b/radio/src/tasks.h
index 921958363..856aaf038 100644
--- a/radio/src/tasks.h
+++ b/radio/src/tasks.h
@@ -24,7 +24,11 @@
#include "rtos.h"
// stack sizes should be in multiples of 8 for better alignment
-#define MENUS_STACK_SIZE 2000
+#if defined (COLORLCD)
+ #define MENUS_STACK_SIZE 4000
+#else
+ #define MENUS_STACK_SIZE 2000
+#endif
#define MIXER_STACK_SIZE 400
#define AUDIO_STACK_SIZE 400
#define CLI_STACK_SIZE 1000 // only consumed with CLI build option
diff --git a/radio/src/telemetry/crossfire.cpp b/radio/src/telemetry/crossfire.cpp
index c71f6ce54..64dba983d 100644
--- a/radio/src/telemetry/crossfire.cpp
+++ b/radio/src/telemetry/crossfire.cpp
@@ -106,6 +106,10 @@ void processCrossfireTelemetryFrame()
return;
}
+ if (telemetryState == TELEMETRY_INIT && moduleState[EXTERNAL_MODULE].counter != CRSF_FRAME_MODELID_SENT) {
+ moduleState[EXTERNAL_MODULE].counter = CRSF_FRAME_MODELID;
+ }
+
uint8_t id = telemetryRxBuffer[2];
int32_t value;
switch(id) {
@@ -174,13 +178,31 @@ void processCrossfireTelemetryFrame()
case FLIGHT_MODE_ID:
{
const CrossfireSensor & sensor = crossfireSensors[FLIGHT_MODE_INDEX];
- for (int i=0; i(16, telemetryRxBuffer[1]-2); i+=4) {
- uint32_t value = *((uint32_t *)&telemetryRxBuffer[3+i]);
- setTelemetryValue(PROTOCOL_TELEMETRY_CROSSFIRE, sensor.id, 0, sensor.subId, value, sensor.unit, i);
- }
+ auto textLength = min(16, telemetryRxBuffer[1]);
+ telemetryRxBuffer[textLength] = '\0';
+ setTelemetryText(PROTOCOL_TELEMETRY_CROSSFIRE, sensor.id, 0, sensor.subId, (const char *)telemetryRxBuffer + 3);
break;
}
+ case RADIO_ID:
+ if (telemetryRxBuffer[3] == 0xEA // radio address
+ && telemetryRxBuffer[5] == 0x10 // timing correction frame
+ ) {
+
+ uint32_t update_interval;
+ int32_t offset;
+ if (getCrossfireTelemetryValue<4>(6, (int32_t&)update_interval) && getCrossfireTelemetryValue<4>(10, offset)) {
+
+ // values are in 10th of micro-seconds
+ update_interval /= 10;
+ offset /= 10;
+
+ TRACE("[XF] Rate: %d, Lag: %d", update_interval, offset);
+ getModuleSyncStatus(EXTERNAL_MODULE).update(update_interval, offset);
+ }
+ }
+ break;
+
#if defined(LUA)
default:
if (luaInputTelemetryFifo && luaInputTelemetryFifo->hasSpace(telemetryRxBufferCount-2) ) {
diff --git a/radio/src/telemetry/crossfire.h b/radio/src/telemetry/crossfire.h
index 79cc5f025..23d39947e 100644
--- a/radio/src/telemetry/crossfire.h
+++ b/radio/src/telemetry/crossfire.h
@@ -40,7 +40,12 @@
#define PING_DEVICES_ID 0x28
#define DEVICE_INFO_ID 0x29
#define REQUEST_SETTINGS_ID 0x2A
+#define COMMAND_ID 0x32
+#define RADIO_ID 0x3A
+#define UART_SYNC 0xC8
+#define SUBCOMMAND_CRSF 0x10
+#define COMMAND_MODEL_SELECT_ID 0x05
struct CrossfireSensor {
const uint8_t id;
@@ -79,23 +84,30 @@ enum CrossfireSensorIndexes {
UNKNOWN_INDEX,
};
+enum CrossfireFrames{
+ CRSF_FRAME_CHANNEL,
+ CRSF_FRAME_MODELID,
+ CRSF_FRAME_MODELID_SENT
+};
+
void processCrossfireTelemetryData(uint8_t data);
void crossfireSetDefault(int index, uint8_t id, uint8_t subId);
+uint8_t createCrossfireModelIDFrame(uint8_t * frame);
const uint32_t CROSSFIRE_BAUDRATES[] = {
400000,
115200,
};
const uint8_t CROSSFIRE_PERIODS[] = {
- 4,
+ 4,
16,
};
-#if SPORT_MAX_BAUDRATE < 400000
+#if SPORT_MAX_BAUDRATE < 400000 || defined(DEBUG)
#define CROSSFIRE_BAUDRATE CROSSFIRE_BAUDRATES[g_eeGeneral.telemetryBaudrate]
-#define CROSSFIRE_PERIOD CROSSFIRE_PERIODS[g_eeGeneral.telemetryBaudrate]
+#define CROSSFIRE_PERIOD (CROSSFIRE_PERIODS[g_eeGeneral.telemetryBaudrate] * 1000)
#else
#define CROSSFIRE_BAUDRATE 400000
-#define CROSSFIRE_PERIOD 4 // 4ms
+#define CROSSFIRE_PERIOD 4000 /* us; 250 Hz */
#endif
#define CROSSFIRE_TELEM_MIRROR_BAUDRATE 115200
diff --git a/radio/src/telemetry/frsky.h b/radio/src/telemetry/frsky.h
index 751196d1c..8621869c6 100644
--- a/radio/src/telemetry/frsky.h
+++ b/radio/src/telemetry/frsky.h
@@ -139,6 +139,8 @@ enum FrSkyDataState {
#define A4_LAST_ID 0x091F
#define AIR_SPEED_FIRST_ID 0x0A00
#define AIR_SPEED_LAST_ID 0x0A0F
+#define FUEL_QTY_FIRST_ID 0x0A10
+#define FUEL_QTY_LAST_ID 0x0A1F
#define RBOX_BATT1_FIRST_ID 0x0B00
#define RBOX_BATT1_LAST_ID 0x0B0F
#define RBOX_BATT2_FIRST_ID 0x0B10
@@ -152,9 +154,9 @@ enum FrSkyDataState {
#define ESC_POWER_FIRST_ID 0x0B50
#define ESC_POWER_LAST_ID 0x0B5F
#define ESC_RPM_CONS_FIRST_ID 0x0B60
-#define ESC_RPM_CONS_LAST_ID 0x0B6f
+#define ESC_RPM_CONS_LAST_ID 0x0B6F
#define ESC_TEMPERATURE_FIRST_ID 0x0B70
-#define ESC_TEMPERATURE_LAST_ID 0x0B7f
+#define ESC_TEMPERATURE_LAST_ID 0x0B7F
#define RB3040_OUTPUT_FIRST_ID 0x0B80
#define RB3040_OUTPUT_LAST_ID 0x0B8F
#define RB3040_CH1_2_FIRST_ID 0x0B90
@@ -165,10 +167,10 @@ enum FrSkyDataState {
#define RB3040_CH5_6_LAST_ID 0x0BBF
#define RB3040_CH7_8_FIRST_ID 0x0BC0
#define RB3040_CH7_8_LAST_ID 0x0BCF
-#define X8R_FIRST_ID 0x0c20
-#define X8R_LAST_ID 0x0c2F
-#define S6R_FIRST_ID 0x0c30
-#define S6R_LAST_ID 0x0c3F
+#define X8R_FIRST_ID 0x0C20
+#define X8R_LAST_ID 0x0C2F
+#define S6R_FIRST_ID 0x0C30
+#define S6R_LAST_ID 0x0C3F
#define GASSUIT_TEMP1_FIRST_ID 0x0D00
#define GASSUIT_TEMP1_LAST_ID 0x0D0F
#define GASSUIT_TEMP2_FIRST_ID 0x0D10
@@ -182,15 +184,17 @@ enum FrSkyDataState {
#define GASSUIT_FLOW_FIRST_ID 0x0D50
#define GASSUIT_FLOW_LAST_ID 0x0D5F
#define GASSUIT_MAX_FLOW_FIRST_ID 0x0D60
-#define GASSUIT_MAX_FLOW_LAST_ID 0x0D6f
+#define GASSUIT_MAX_FLOW_LAST_ID 0x0D6F
#define GASSUIT_AVG_FLOW_FIRST_ID 0x0D70
-#define GASSUIT_AVG_FLOW_LAST_ID 0x0D7f
+#define GASSUIT_AVG_FLOW_LAST_ID 0x0D7F
#define SBEC_POWER_FIRST_ID 0x0E50
#define SBEC_POWER_LAST_ID 0x0E5F
#define DIY_FIRST_ID 0x5100
#define DIY_LAST_ID 0x52FF
#define DIY_STREAM_FIRST_ID 0x5000
#define DIY_STREAM_LAST_ID 0x50FF
+#define SERVO_FIRST_ID 0x6800
+#define SERVO_LAST_ID 0x680F
#define FACT_TEST_ID 0xF000
#define VALID_FRAME_RATE_ID 0xF010
#define RSSI_ID 0xF101
@@ -202,8 +206,6 @@ enum FrSkyDataState {
#define R9_PWR_ID 0xF107
#define SP2UART_A_ID 0xFD00
#define SP2UART_B_ID 0xFD01
-#define FUEL_QTY_FIRST_ID 0x0A10
-#define FUEL_QTY_LAST_ID 0x0A1F
#if defined(MULTIMODULE)
// Virtual IDs, value can be changed to anything only used for display
diff --git a/radio/src/telemetry/frsky_pxx2.cpp b/radio/src/telemetry/frsky_pxx2.cpp
index 8ed11be1c..dd8d63106 100644
--- a/radio/src/telemetry/frsky_pxx2.cpp
+++ b/radio/src/telemetry/frsky_pxx2.cpp
@@ -92,6 +92,9 @@ void processReceiverSettingsFrame(uint8_t module, const uint8_t * frame)
if (frame[4] & PXX2_RX_SETTINGS_FLAG1_ENABLE_PWM_CH5_CH6)
destination->enablePwmCh5Ch6 = 1;
+ if (frame[4] & PXX2_RX_SETTINGS_FLAG1_FPORT2)
+ destination->fport2 = 1;
+
uint8_t outputsCount = min(16, frame[0] - 4);
destination->outputsCount = outputsCount;
for (uint8_t pin = 0; pin < outputsCount; pin++) {
diff --git a/radio/src/telemetry/frsky_sport.cpp b/radio/src/telemetry/frsky_sport.cpp
index d26946534..3790736fd 100644
--- a/radio/src/telemetry/frsky_sport.cpp
+++ b/radio/src/telemetry/frsky_sport.cpp
@@ -48,9 +48,9 @@ const FrSkySportSensor sportSensors[] = {
{ FUEL_FIRST_ID, FUEL_LAST_ID, 0, ZSTR_FUEL, UNIT_PERCENT, 0 },
{ ALT_FIRST_ID, ALT_LAST_ID, 0, ZSTR_ALT, UNIT_METERS, 2 },
{ VARIO_FIRST_ID, VARIO_LAST_ID, 0, ZSTR_VSPD, UNIT_METERS_PER_SECOND, 2 },
- { ACCX_FIRST_ID, ACCX_LAST_ID, 0, ZSTR_ACCX, UNIT_G, 2 },
- { ACCY_FIRST_ID, ACCY_LAST_ID, 0, ZSTR_ACCY, UNIT_G, 2 },
- { ACCZ_FIRST_ID, ACCZ_LAST_ID, 0, ZSTR_ACCZ, UNIT_G, 2 },
+ { ACCX_FIRST_ID, ACCX_LAST_ID, 0, ZSTR_ACCX, UNIT_G, 3 },
+ { ACCY_FIRST_ID, ACCY_LAST_ID, 0, ZSTR_ACCY, UNIT_G, 3 },
+ { ACCZ_FIRST_ID, ACCZ_LAST_ID, 0, ZSTR_ACCZ, UNIT_G, 3 },
{ CURR_FIRST_ID, CURR_LAST_ID, 0, ZSTR_CURR, UNIT_AMPS, 1 },
{ VFAS_FIRST_ID, VFAS_LAST_ID, 0, ZSTR_VFAS, UNIT_VOLTS, 2 },
{ AIR_SPEED_FIRST_ID, AIR_SPEED_LAST_ID, 0, ZSTR_ASPD, UNIT_KTS, 1 },
@@ -94,7 +94,11 @@ const FrSkySportSensor sportSensors[] = {
{ RB3040_CH5_6_FIRST_ID, RB3040_CH5_6_LAST_ID, 1, ZSTR_RB3040_CHANNEL6, UNIT_AMPS, 2 },
{ RB3040_CH7_8_FIRST_ID, RB3040_CH7_8_LAST_ID, 0, ZSTR_RB3040_CHANNEL7, UNIT_AMPS, 2 },
{ RB3040_CH7_8_FIRST_ID, RB3040_CH7_8_LAST_ID, 1, ZSTR_RB3040_CHANNEL8, UNIT_AMPS, 2 },
- { 0, 0, 0, NULL, UNIT_RAW, 0 } // sentinel
+ { SERVO_FIRST_ID, SERVO_LAST_ID, 0, ZSTR_SERVO_CURRENT, UNIT_AMPS, 1 },
+ { SERVO_FIRST_ID, SERVO_LAST_ID, 1, ZSTR_SERVO_VOLTAGE, UNIT_VOLTS, 1 },
+ { SERVO_FIRST_ID, SERVO_LAST_ID, 2, ZSTR_SERVO_TEMPERATURE, UNIT_CELSIUS, 0 },
+ { SERVO_FIRST_ID, SERVO_LAST_ID, 3, ZSTR_SERVO_STATUS, UNIT_TEXT, 0 },
+ { 0, 0, 0, nullptr, UNIT_RAW, 0 } // sentinel
};
const FrSkySportSensor * getFrSkySportSensor(uint16_t id, uint8_t subId=0)
@@ -110,13 +114,13 @@ const FrSkySportSensor * getFrSkySportSensor(uint16_t id, uint8_t subId=0)
bool checkSportPacket(const uint8_t * packet)
{
short crc = 0;
- for (int i=1; i> 8; // 0-1FF
- crc &= 0x00ff; // 0-FF
+ crc += crc >> 8u; // 0-1FF
+ crc &= 0x00FFu; // 0-FF
}
// TRACE("crc: 0x%02x", crc);
- return (crc == 0x00ff);
+ return crc == 0x00FF;
}
#define SPORT_DATA_U8(packet) (packet[4])
@@ -137,15 +141,15 @@ void sportProcessTelemetryPacket(uint16_t id, uint8_t subId, uint8_t instance, u
precision = sensor->prec;
}
if (unit == UNIT_CELLS) {
- uint8_t cellsCount = (data & 0xF0) >> 4;
- uint8_t cellIndex = (data & 0x0F);
+ uint8_t cellsCount = (data & 0xF0u) >> 4u;
+ uint8_t cellIndex = (data & 0x0Fu);
if (cellIndex >= MAX_CELLS)
return;
- uint32_t mask = (cellsCount << 24) + (cellIndex << 16);
- setTelemetryValue(PROTOCOL_TELEMETRY_FRSKY_SPORT, id, subId, instance, mask + (((data & 0x000FFF00) >> 8) / 5), unit, precision);
- if (cellIndex+1 < cellsCount) {
- mask += (1 << 16);
- setTelemetryValue(PROTOCOL_TELEMETRY_FRSKY_SPORT, id, subId, instance, mask + (((data & 0xFFF00000) >> 20) / 5), unit, precision);
+ uint32_t mask = (cellsCount << 24u) + (cellIndex << 16u);
+ setTelemetryValue(PROTOCOL_TELEMETRY_FRSKY_SPORT, id, subId, instance, mask + (((data & 0x000FFF00u) >> 8u) / 5), unit, precision);
+ if (cellIndex + 1 < cellsCount) {
+ mask += (1 << 16u);
+ setTelemetryValue(PROTOCOL_TELEMETRY_FRSKY_SPORT, id, subId, instance, mask + (((data & 0xFFF00000u) >> 20u) / 5), unit, precision);
}
}
else {
@@ -219,7 +223,7 @@ void sportProcessTelemetryPacketWithoutCrc(uint8_t origin, const uint8_t * packe
}
#if defined(MULTIMODULE)
if (telemetryProtocol == PROTOCOL_TELEMETRY_MULTIMODULE) {
- sportProcessTelemetryPacket(TX_RSSI_ID, 0, instance, packet[5] >> 1, UNIT_DB);
+ sportProcessTelemetryPacket(TX_RSSI_ID, 0, instance, packet[5] >> 1u, UNIT_DB);
sportProcessTelemetryPacket(TX_LQI_ID, 0, instance, packet[7], UNIT_RAW);
}
#endif
@@ -263,40 +267,40 @@ void sportProcessTelemetryPacketWithoutCrc(uint8_t origin, const uint8_t * packe
if (dataId >= GPS_LONG_LATI_FIRST_ID && dataId <= GPS_LONG_LATI_LAST_ID) {
int32_t value = (data & 0x3fffffff);
- if (data & (1 << 30))
+ if (data & (1 << 30u))
value = -value;
value = (value * 5) / 3; // min/10000 => deg/1000000
- if (data & (1 << 31))
+ if (data & (1 << 31u))
sportProcessTelemetryPacket(dataId, 0, instance, value, UNIT_GPS_LONGITUDE);
else
sportProcessTelemetryPacket(dataId, 0, instance, value, UNIT_GPS_LATITUDE);
}
else if (dataId >= RBOX_BATT1_FIRST_ID && dataId <= RBOX_BATT2_LAST_ID) {
- sportProcessTelemetryPacket(dataId, 0, instance, data & 0xffff);
- sportProcessTelemetryPacket(dataId, 1, instance, data >> 16);
+ sportProcessTelemetryPacket(dataId, 0, instance, data & 0xFFFFu);
+ sportProcessTelemetryPacket(dataId, 1, instance, data >> 16u);
}
else if (dataId >= RBOX_CNSP_FIRST_ID && dataId <= RBOX_CNSP_LAST_ID) {
- sportProcessTelemetryPacket(dataId, 0, instance, data & 0xffff);
- sportProcessTelemetryPacket(dataId, 1, instance, data >> 16);
+ sportProcessTelemetryPacket(dataId, 0, instance, data & 0xFFFFu);
+ sportProcessTelemetryPacket(dataId, 1, instance, data >> 16u);
}
else if (dataId >= RBOX_STATE_FIRST_ID && dataId <= RBOX_STATE_LAST_ID) {
bool static isRB10 = false;
uint16_t newServosState;
- if (servosState == 0 && (data & 0xff00) == 0xff00) {
+ if (servosState == 0 && (data & 0xFF00u) == 0xFF00u) {
isRB10 = true;
}
if (isRB10) {
- newServosState = data & 0x00ff; // 8ch only RB10
+ newServosState = data & 0x00FFu; // 8ch only RB10
}
else {
- newServosState = data & 0xffff;
+ newServosState = data & 0xFFFFu;
}
if (newServosState != 0 && servosState == 0) {
audioEvent(AU_SERVO_KO);
}
- uint16_t newRboxState = data >> 16;
- if ((newRboxState & 0x07) && (rboxState & 0x07) == 0) {
+ uint16_t newRboxState = data >> 16u;
+ if ((newRboxState & 0x07u) && (rboxState & 0x07u) == 0) {
audioEvent(AU_RX_OVERLOAD);
}
servosState = newServosState;
@@ -305,19 +309,19 @@ void sportProcessTelemetryPacketWithoutCrc(uint8_t origin, const uint8_t * packe
sportProcessTelemetryPacket(dataId, 1, instance, rboxState);
}
else if (dataId >= ESC_POWER_FIRST_ID && dataId <= ESC_POWER_LAST_ID) {
- sportProcessTelemetryPacket(dataId, 0, instance, data & 0xffff);
- sportProcessTelemetryPacket(dataId, 1, instance, data >> 16);
+ sportProcessTelemetryPacket(dataId, 0, instance, data & 0xFFFFu);
+ sportProcessTelemetryPacket(dataId, 1, instance, data >> 16u);
}
else if (dataId >= ESC_RPM_CONS_FIRST_ID && dataId <= ESC_RPM_CONS_LAST_ID) {
- sportProcessTelemetryPacket(dataId, 0, instance, 100 * (data & 0xffff));
- sportProcessTelemetryPacket(dataId, 1, instance, data >> 16);
+ sportProcessTelemetryPacket(dataId, 0, instance, 100 * (data & 0xFFFFu));
+ sportProcessTelemetryPacket(dataId, 1, instance, data >> 16u);
}
else if (dataId >= ESC_TEMPERATURE_FIRST_ID && dataId <= ESC_TEMPERATURE_LAST_ID) {
- sportProcessTelemetryPacket(dataId, 0, instance, data & 0x00ff);
+ sportProcessTelemetryPacket(dataId, 0, instance, data & 0x00FFu);
}
else if (dataId >= SBEC_POWER_FIRST_ID && dataId <= SBEC_POWER_LAST_ID) {
- sportProcessTelemetryPacket(dataId, 0, instance, (data & 0xffff) / 10);
- sportProcessTelemetryPacket(dataId, 1, instance, (data >> 16) / 10);
+ sportProcessTelemetryPacket(dataId, 0, instance, (data & 0xFFFFu) / 10);
+ sportProcessTelemetryPacket(dataId, 1, instance, (data >> 16u) / 10);
}
else if (dataId >= DIY_STREAM_FIRST_ID && dataId <= DIY_STREAM_LAST_ID) {
#if defined(LUA)
@@ -334,8 +338,19 @@ void sportProcessTelemetryPacketWithoutCrc(uint8_t origin, const uint8_t * packe
#endif
}
else if (dataId >= RB3040_CH1_2_FIRST_ID && dataId <= RB3040_CH7_8_LAST_ID) {
- sportProcessTelemetryPacket(dataId, 0, instance, data & 0xffff);
- sportProcessTelemetryPacket(dataId, 1, instance, (data >> 16u) & 0xffff);
+ sportProcessTelemetryPacket(dataId, 0, instance, data & 0xFFFFu);
+ sportProcessTelemetryPacket(dataId, 1, instance, (data >> 16u) & 0xFFFFu);
+ }
+ else if (dataId >= SERVO_FIRST_ID && dataId <= SERVO_LAST_ID) {
+ sportProcessTelemetryPacket(dataId, 0, instance, data & 0xFFu);
+ sportProcessTelemetryPacket(dataId, 1, instance, (data >> 8u) & 0xFFu);
+ sportProcessTelemetryPacket(dataId, 2, instance, (data >> 16u) & 0xFFu);
+ uint8_t newServosState = data >> 24u;
+ setTelemetryText(PROTOCOL_TELEMETRY_FRSKY_SPORT, dataId, 3, instance, newServosState ? "STALL" : "OK");
+ if (newServosState != 0 && servosState == 0) {
+ audioEvent(AU_SERVO_KO);
+ servosState = newServosState;
+ }
}
else {
sportProcessTelemetryPacket(dataId, 0, instance, data);
diff --git a/radio/src/telemetry/ghost.cpp b/radio/src/telemetry/ghost.cpp
new file mode 100755
index 000000000..8b949b69a
--- /dev/null
+++ b/radio/src/telemetry/ghost.cpp
@@ -0,0 +1,353 @@
+/*
+ * 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.
+ */
+
+#include "opentx.h"
+
+const char *ghstRfProfileValue[GHST_RF_PROFILE_COUNT] = { "Auto", "Norm", "Race", "Pure", "Long", "Unused", "Race2", "Pure2" };
+const char *ghstVtxBandName[GHST_VTX_BAND_COUNT] = { "- - -" , "IRC", "Race", "BandE", "BandB", "BandA" };
+
+struct GhostSensor
+{
+ const uint16_t id;
+ const char * name;
+ const TelemetryUnit unit;
+ const uint8_t precision;
+};
+
+// telemetry sensors ID
+enum
+{
+ GHOST_ID_RX_RSSI = 0x0001, // Rx-side RSSI
+ GHOST_ID_RX_LQ = 0x0002, // Rx-side link quality
+ GHOST_ID_RX_SNR = 0x0003, // Rx-side signal to noise
+ GHOST_ID_FRAME_RATE = 0x0004, // Tx-side frame rate
+ GHOST_ID_TX_POWER = 0x0005, // Tx-side power output
+ GHOST_ID_RF_MODE = 0x0006, // Tx-side frame rate
+ GHOST_ID_TOTAL_LATENCY = 0x0007, // Tx-side total latency
+ GHOST_ID_VTX_FREQ = 0x0008, // Vtx Frequency (in MHz)
+ GHOST_ID_VTX_POWER = 0x0009, // Vtx Power (in mW)
+ GHOST_ID_VTX_CHAN = 0x000A, // Vtx Channel
+ GHOST_ID_VTX_BAND = 0x000B, // Vtx Band
+
+ GHOST_ID_PACK_VOLTS = 0x000C, // Battery Pack Voltage
+ GHOST_ID_PACK_AMPS = 0x000D, // Battery Pack Current
+ GHOST_ID_PACK_MAH = 0x000E, // Battery Pack mAh consumed
+
+ GHOST_ID_GPS_LAT = 0x000F, // GPS Latitude
+ GHOST_ID_GPS_LONG = 0x0010, // GPS Longitude
+ GHOST_ID_GPS_ALT = 0x0011, // GPS Altitude
+ GHOST_ID_GPS_HDG = 0x0012, // GPS Heading
+ GHOST_ID_GPS_GSPD = 0x0013, // GPS Ground Speed
+ GHOST_ID_GPS_SATS = 0x0014 // GPS Satellite Count
+};
+
+const GhostSensor ghostSensors[] = {
+ {GHOST_ID_RX_RSSI, ZSTR_RSSI, UNIT_DB, 0},
+ {GHOST_ID_RX_LQ, ZSTR_RX_QUALITY, UNIT_PERCENT, 0},
+ {GHOST_ID_RX_SNR, ZSTR_RX_SNR, UNIT_DB, 0},
+
+ {GHOST_ID_FRAME_RATE, ZSTR_FRAME_RATE, UNIT_RAW, 0},
+ {GHOST_ID_TX_POWER, ZSTR_TX_POWER, UNIT_MILLIWATTS, 0},
+ {GHOST_ID_RF_MODE, ZSTR_RF_MODE, UNIT_TEXT, 0},
+ {GHOST_ID_TOTAL_LATENCY, ZSTR_TOTAL_LATENCY, UNIT_RAW, 0},
+
+ {GHOST_ID_VTX_FREQ, ZSTR_VTX_FREQ, UNIT_RAW, 0},
+ {GHOST_ID_VTX_POWER, ZSTR_VTX_PWR, UNIT_RAW, 0},
+ {GHOST_ID_VTX_CHAN, ZSTR_VTX_CHAN, UNIT_RAW, 0},
+ {GHOST_ID_VTX_BAND, ZSTR_VTX_BAND, UNIT_TEXT, 0},
+
+ {GHOST_ID_PACK_VOLTS, ZSTR_BATT, UNIT_VOLTS, 2},
+ {GHOST_ID_PACK_AMPS, ZSTR_CURR, UNIT_AMPS, 2},
+ {GHOST_ID_PACK_MAH, ZSTR_CAPACITY, UNIT_MAH, 0},
+
+ {GHOST_ID_GPS_LAT, ZSTR_GPS, UNIT_GPS_LATITUDE, 0},
+ {GHOST_ID_GPS_LONG, ZSTR_GPS, UNIT_GPS_LONGITUDE, 0},
+ {GHOST_ID_GPS_GSPD, ZSTR_GSPD, UNIT_KMH, 1},
+ {GHOST_ID_GPS_HDG, ZSTR_HDG, UNIT_DEGREE, 3},
+ {GHOST_ID_GPS_ALT, ZSTR_ALT, UNIT_METERS, 0},
+ {GHOST_ID_GPS_SATS, ZSTR_SATELLITES, UNIT_RAW, 0},
+
+ {0x00, NULL, UNIT_RAW, 0},
+};
+
+const GhostSensor *getGhostSensor(uint8_t id)
+{
+ for (const GhostSensor * sensor = ghostSensors; sensor->id; sensor++) {
+ if (id == sensor->id)
+ return sensor;
+ }
+ return nullptr;
+}
+
+void processGhostTelemetryValue(uint8_t index, int32_t value)
+{
+ if (!TELEMETRY_STREAMING())
+ return;
+
+ const GhostSensor * sensor = getGhostSensor(index);
+ uint16_t id = sensor->id;
+ if (id == GHOST_ID_GPS_LONG) {
+ id = GHOST_ID_GPS_LAT;
+ }
+ setTelemetryValue(PROTOCOL_TELEMETRY_GHOST, id, 0, 0, value, sensor->unit, sensor->precision);
+}
+
+void processGhostTelemetryValueString(const GhostSensor * sensor, const char * str)
+{
+ if (TELEMETRY_STREAMING()) {
+ setTelemetryText(PROTOCOL_TELEMETRY_GHOST, sensor->id, 0, 0, str);
+ }
+}
+
+bool checkGhostTelemetryFrameCRC()
+{
+ uint8_t len = telemetryRxBuffer[1];
+ uint8_t crc = crc8(&telemetryRxBuffer[2], len - 1);
+ return (crc == telemetryRxBuffer[len + 1]);
+}
+
+// hifirst
+uint16_t getTelemetryValue_u16(uint8_t index)
+{
+ return (telemetryRxBuffer[index] << 8) | telemetryRxBuffer[index + 1];
+}
+
+// lofirst
+uint16_t getTelemetryValue_u16le(uint8_t index)
+{
+ return (telemetryRxBuffer[index + 1] << 8) | telemetryRxBuffer[index];
+}
+
+// hifirst
+uint32_t getTelemetryValue_s32(uint8_t index)
+{
+ uint32_t val = 0;
+ for (int i = 0; i < 4; ++i)
+ val <<= 8, val |= telemetryRxBuffer[index + i];
+ return val;
+}
+
+// lofirst
+uint32_t getTelemetryValue_s32le(uint8_t index)
+{
+ uint32_t val = 0;
+ for (int i = 0; i < 4; ++i)
+ val <<= 8, val |= telemetryRxBuffer[index + 3 - i];
+ return val;
+}
+
+void processGhostTelemetryFrame()
+{
+ if (!checkGhostTelemetryFrameCRC()) {
+ TRACE("[GS] CRC error");
+ return;
+ }
+
+ uint8_t id = telemetryRxBuffer[2];
+ switch(id) {
+ case GHST_DL_OPENTX_SYNC:
+ {
+ uint32_t update_interval = getTelemetryValue_s32(3);
+ int32_t offset = getTelemetryValue_s32(7);
+
+ // values are in units of 100ns
+ update_interval /= 10;
+ offset /= 10;
+
+ getModuleSyncStatus(EXTERNAL_MODULE).update(update_interval, offset);
+ }
+ break;
+
+ case GHST_DL_LINK_STAT:
+ {
+#if defined(BLUETOOTH)
+ if (g_eeGeneral.bluetoothMode == BLUETOOTH_TELEMETRY && bluetooth.state == BLUETOOTH_STATE_CONNECTED) {
+ bluetooth.write(telemetryRxBuffer, telemetryRxBufferCount);
+ }
+#endif
+ uint8_t rssiVal = min(telemetryRxBuffer[3], 120); // RSSI is a negative value, but sent as a positive integer.
+ uint8_t lqVal = min(telemetryRxBuffer[4], 100);
+ uint8_t snrVal = min(telemetryRxBuffer[5], 100);
+
+ processGhostTelemetryValue(GHOST_ID_RX_RSSI, - rssiVal);
+ processGhostTelemetryValue(GHOST_ID_RX_LQ, lqVal);
+ processGhostTelemetryValue(GHOST_ID_RX_SNR, snrVal);
+
+ // give OpenTx the LQ value, not RSSI
+ if (lqVal) {
+ telemetryData.rssi.set(lqVal);
+ telemetryStreaming = TELEMETRY_TIMEOUT10ms;
+ }
+ else {
+ telemetryData.rssi.reset();
+ telemetryStreaming = 0;
+ }
+
+ processGhostTelemetryValue(GHOST_ID_TX_POWER, getTelemetryValue_u16(6));
+ processGhostTelemetryValue(GHOST_ID_FRAME_RATE, getTelemetryValue_u16(8));
+ processGhostTelemetryValue(GHOST_ID_TOTAL_LATENCY, getTelemetryValue_u16(10));
+ uint8_t rfModeEnum = min(telemetryRxBuffer[12], GHST_RF_PROFILE_MAX);
+
+ // RF mode string, one char at a time
+ const GhostSensor * sensor = getGhostSensor(GHOST_ID_RF_MODE);
+ const char * rfModeString = ghstRfProfileValue[rfModeEnum];
+ processGhostTelemetryValueString(sensor, rfModeString);
+ break;
+ }
+
+ case GHST_DL_VTX_STAT:
+ {
+#if defined(BLUETOOTH)
+ if (g_eeGeneral.bluetoothMode == BLUETOOTH_TELEMETRY && bluetooth.state == BLUETOOTH_STATE_CONNECTED) {
+ bluetooth.write(telemetryRxBuffer, telemetryRxBufferCount);
+ }
+#endif
+ uint8_t vtxBandEnum = min(telemetryRxBuffer[8], GHST_VTX_BAND_MAX);
+
+ const GhostSensor * sensor = getGhostSensor(GHOST_ID_VTX_BAND);
+ const char * vtxBandString = ghstVtxBandName[vtxBandEnum];
+
+ processGhostTelemetryValue(GHOST_ID_VTX_FREQ, getTelemetryValue_u16(4));
+ processGhostTelemetryValue(GHOST_ID_VTX_POWER, getTelemetryValue_u16(6));
+ processGhostTelemetryValue(GHOST_ID_VTX_CHAN, min(telemetryRxBuffer[9], 8));
+ processGhostTelemetryValueString(sensor, vtxBandString);
+ break;
+ }
+
+ case GHST_DL_MENU_DESC:
+ {
+ GhostMenuFrame * packet;
+ GhostMenuData * lineData;
+ packet = (GhostMenuFrame * ) telemetryRxBuffer;
+ lineData = (GhostMenuData *) &reusableBuffer.ghostMenu.line[packet->lineIndex];
+ lineData->splitLine = 0;
+ reusableBuffer.ghostMenu.menuStatus = packet->menuStatus;
+ lineData->lineFlags = packet->lineFlags;
+ for (uint8_t i = 0; i < GHST_MENU_CHARS; i++) {
+ if (packet->menuText[i] == 0x7C) {
+ lineData->menuText[i] = '\0';
+ lineData->splitLine = i + 1;
+ }
+ else {
+ lineData->menuText[i] = packet->menuText[i];
+ }
+ }
+ lineData->menuText[GHST_MENU_CHARS] = '\0';
+ break;
+ }
+
+ case GHST_DL_PACK_STAT: {
+#if defined(BLUETOOTH)
+ if (g_eeGeneral.bluetoothMode == BLUETOOTH_TELEMETRY && bluetooth.state == BLUETOOTH_STATE_CONNECTED) {
+ bluetooth.write(telemetryRxBuffer, telemetryRxBufferCount);
+ }
+#endif
+ processGhostTelemetryValue(GHOST_ID_PACK_VOLTS, getTelemetryValue_u16le(3));
+ processGhostTelemetryValue(GHOST_ID_PACK_AMPS, getTelemetryValue_u16le(5));
+ processGhostTelemetryValue(GHOST_ID_PACK_MAH, getTelemetryValue_u16le(7) * 10);
+ break;
+ }
+
+ case GHST_DL_GPS_PRIMARY: {
+#if defined(BLUETOOTH)
+ if (g_eeGeneral.bluetoothMode == BLUETOOTH_TELEMETRY && bluetooth.state == BLUETOOTH_STATE_CONNECTED) {
+ bluetooth.write(telemetryRxBuffer, telemetryRxBufferCount);
+ }
+#endif
+ processGhostTelemetryValue(GHOST_ID_GPS_LAT, getTelemetryValue_s32le(3) / 10);
+ processGhostTelemetryValue(GHOST_ID_GPS_LONG, getTelemetryValue_s32le(7) / 10);
+ processGhostTelemetryValue(GHOST_ID_GPS_ALT, (int16_t) getTelemetryValue_u16le(11));
+ break;
+ }
+
+ case GHST_DL_GPS_SECONDARY: {
+#if defined(BLUETOOTH)
+ if (g_eeGeneral.bluetoothMode == BLUETOOTH_TELEMETRY && bluetooth.state == BLUETOOTH_STATE_CONNECTED) {
+ bluetooth.write(telemetryRxBuffer, telemetryRxBufferCount);
+ }
+#endif
+ processGhostTelemetryValue(GHOST_ID_GPS_HDG, getTelemetryValue_u16le(5) / 10);
+
+ // ground speed is passed via GHST as cm/s, converted to km/h for OpenTx
+ processGhostTelemetryValue(GHOST_ID_GPS_GSPD, (getTelemetryValue_u16le(3) * 36 + 50) / 100);
+ processGhostTelemetryValue(GHOST_ID_GPS_SATS, telemetryRxBuffer[7]);
+ break;
+ }
+ }
+}
+
+void processGhostTelemetryData(uint8_t data)
+{
+#if defined(AUX_SERIAL)
+ if (g_eeGeneral.auxSerialMode == UART_MODE_TELEMETRY_MIRROR) {
+ auxSerialPutc(data);
+ }
+#endif
+
+#if defined(AUX2_SERIAL)
+ if (g_eeGeneral.aux2SerialMode == UART_MODE_TELEMETRY_MIRROR) {
+ aux2SerialPutc(data);
+ }
+#endif
+
+ if (telemetryRxBufferCount == 0 && data != GHST_ADDR_RADIO) {
+ TRACE("[GH] address 0x%02X error", data);
+ return;
+ }
+
+ if (telemetryRxBufferCount < TELEMETRY_RX_PACKET_SIZE) {
+ telemetryRxBuffer[telemetryRxBufferCount++] = data;
+ }
+ else {
+ TRACE("[GH] array size %d error", telemetryRxBufferCount);
+ telemetryRxBufferCount = 0;
+ }
+
+ if (telemetryRxBufferCount > 4) {
+ uint8_t length = telemetryRxBuffer[1];
+ if (length + 2 == telemetryRxBufferCount) {
+ processGhostTelemetryFrame();
+ telemetryRxBufferCount = 0;
+ }
+ }
+}
+
+
+void ghostSetDefault(int index, uint8_t id, uint8_t subId)
+{
+ TelemetrySensor &telemetrySensor = g_model.telemetrySensors[index];
+
+ telemetrySensor.id = id;
+ telemetrySensor.instance = subId;
+
+ const GhostSensor * sensor = getGhostSensor(id);
+ if (sensor) {
+ TelemetryUnit unit = sensor->unit;
+ if (unit == UNIT_GPS_LATITUDE || unit == UNIT_GPS_LONGITUDE) {
+ unit = UNIT_GPS;
+ }
+ uint8_t prec = min(2, sensor->precision);
+ telemetrySensor.init(sensor->name, unit, prec);
+ }
+ else
+ telemetrySensor.init(id);
+
+ storageDirty(EE_MODEL);
+}
diff --git a/radio/src/telemetry/ghost.h b/radio/src/telemetry/ghost.h
new file mode 100755
index 000000000..36f493b9f
--- /dev/null
+++ b/radio/src/telemetry/ghost.h
@@ -0,0 +1,183 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include
+#include "dataconstants.h"
+
+// Device (destination) address
+#define GHST_ADDR_RADIO 0x80 // phase 1
+#define GHST_ADDR_MODULE_SYM 0x81 // symmetrical, 400k pulses, 400k telemetry
+#define GHST_ADDR_MODULE_ASYM 0x88 // asymmetrical, 400k pulses, 115k telemetry
+#define GHST_ADDR_FC 0x82
+#define GHST_ADDR_GOGGLES 0x83 // phase 2
+#define GHST_ADDR_5G_TXCTRL 0x84 // phase 3
+#define GHST_ADDR_5G_TWRSCAN 0x85
+#define GHST_ADDR_5G_RLY 0x86
+
+#define GHST_UL_RC_CHANS_HS4_5TO8 0x10 // High Speed 4 channel (12 bits), plus CH5-8 (8 bits)
+#define GHST_UL_RC_CHANS_HS4_9TO12 0x11 // High Speed 4 channel (12 bits), plus CH9-12 (8 bits)
+#define GHST_UL_RC_CHANS_HS4_13TO16 0x12 // High Speed 4 channel (12 bits), plus CH13-16 (8 bits)
+#define GHST_UL_RC_CHANS_SIZE 12 // 1 (type) + 10 (data) + 1 (crc)
+#define GHST_UL_MENU_CTRL 0x13
+
+#define GHST_DL_OPENTX_SYNC 0x20
+#define GHST_DL_LINK_STAT 0x21
+#define GHST_DL_VTX_STAT 0x22
+#define GHST_DL_PACK_STAT 0x23
+#define GHST_DL_MENU_DESC 0x24
+#define GHST_DL_GPS_PRIMARY 0x25
+#define GHST_DL_GPS_SECONDARY 0x26
+
+#define GHST_RC_CTR_VAL_12BIT 0x7C0 // 0x3e0 << 1
+#define GHST_RC_CTR_VAL_8BIT 0x7C
+
+#define GHST_CH_BITS_12 12
+#define GHST_CH_BITS_8 8
+
+enum GhstPowerMode
+{
+ GHST_PWR_16UW = 0,
+ GHST_PWR_100UW = 1,
+ GHST_PWR_1MW = 2,
+ GHST_PWR_25MW = 3,
+ GHST_PWR_100MW = 4,
+ GHST_PWR_200MW = 5,
+ GHST_PWR_350MW = 6,
+ GHST_PWR_500MW = 7,
+ GHST_PWR_600MW = 8,
+ GHST_PWR_1W = 9,
+ GHST_PWR_1_5W = 10,
+ GHST_PWR_2W = 11,
+ GHST_PWR_3W = 12,
+ GHST_PWR_4W = 13,
+ GHST_PWR_COUNT
+};
+
+enum GhstRFProfile
+{
+ GHST_RF_PROFILE_Auto = 0,
+ GHST_RF_PROFILE_Normal = 1,
+ GHST_RF_PROFILE_Race = 2,
+ GHST_RF_PROFILE_PureRace = 3,
+ GHST_RF_PROFILE_LongRange = 4,
+ GHST_RF_PROFILE_Reserved = 5,
+ GHST_RF_PROFILE_Race2 = 6,
+ GHST_RF_PROFILE_PureRace2 = 7,
+ GHST_RF_PROFILE_MAX = GHST_RF_PROFILE_PureRace2,
+ GHST_RF_PROFILE_COUNT
+};
+
+enum GhstVtxBand
+{
+ GHST_VTX_BAND_Unknown = 0,
+ GHST_VTX_BAND_Irc = 1,
+ GHST_VTX_BAND_Race = 2,
+ GHST_VTX_BAND_BandE = 3,
+ GHST_VTX_BAND_BandB = 4,
+ GHST_VTX_BAND_BandA = 5,
+ GHST_VTX_BAND_MAX = GHST_VTX_BAND_BandA,
+ GHST_VTX_BAND_COUNT
+};
+
+void processGhostTelemetryData(uint8_t data);
+void ghostSetDefault(int index, uint8_t id, uint8_t subId);
+
+#if SPORT_MAX_BAUDRATE < 400000
+// For radios which can't support telemetry at high rates, offer baud rate choices
+// (modified vs. unmodified radios)
+
+constexpr uint16_t BRR_400K = PERI1_FREQUENCY / 400000;
+constexpr uint16_t BRR_115K = PERI1_FREQUENCY / 115200;
+
+enum GhostTelemetryBaudrates
+{
+ GHST_TELEMETRY_RATE_400K,
+ GHST_TELEMETRY_RATE_115K
+};
+#endif
+#define GHOST_BAUDRATE 400000
+#define GHOST_PERIOD 4000 /* us */
+
+enum GhostLineFlags
+{
+ GHST_LINE_FLAGS_NONE = 0x00,
+ GHST_LINE_FLAGS_LABEL_SELECT = 0x01,
+ GHST_LINE_FLAGS_VALUE_SELECT = 0x02,
+ GHST_LINE_FLAGS_VALUE_EDIT = 0x04,
+};
+
+enum GhostButtons
+{
+ GHST_BTN_NONE = 0x00,
+ GHST_BTN_JOYPRESS = 0X01,
+ GHST_BTN_JOYUP = 0X02,
+ GHST_BTN_JOYDOWN = 0X04,
+ GHST_BTN_JOYLEFT = 0X08,
+ GHST_BTN_JOYRIGHT = 0X10,
+ GHST_BTN_BIND = 0X20 // future, for no-UI Ghost
+};
+
+enum GhostMenuControl
+{
+ GHST_MENU_CTRL_NONE = 0X00,
+ GHST_MENU_CTRL_OPEN = 0X01,
+ GHST_MENU_CTRL_CLOSE = 0X02,
+ GHST_MENU_CTRL_REDRAW = 0X04,
+};
+
+enum GhostMenuStatus
+{
+ GHST_MENU_STATUS_UNOPENED = 0x00,
+ GHST_MENU_STATUS_OPENED = 0x01,
+ GHST_MENU_STATUS_CLOSING = 0x02,
+};
+
+enum GhostFrames
+{
+ GHST_FRAME_CHANNEL,
+ GHST_MENU_CONTROL
+};
+
+constexpr uint8_t GHST_MENU_LINES = 6;
+constexpr uint8_t GHST_MENU_CHARS = 20;
+
+// GHST_DL_MENU_DESC (27 bytes)
+struct GhostMenuFrame
+{
+ uint8_t address;
+ uint8_t length ;
+ uint8_t packetId;
+ uint8_t menuStatus; // GhostMenuStatus
+ uint8_t lineFlags; // GhostLineFlags
+ uint8_t lineIndex; // 0 = first line
+ unsigned char menuText[GHST_MENU_CHARS];
+ uint8_t crc;
+};
+
+struct GhostMenuData
+{
+ uint8_t menuStatus; // Update Line, Clear Menu, etc.
+ uint8_t lineFlags; // Carat states, Inverse, Bold for each of Menu Label, and Value
+ uint8_t splitLine; // Store beginning of Value substring
+ char menuText[GHST_MENU_CHARS + 1];
+};
+
diff --git a/radio/src/telemetry/hott.cpp b/radio/src/telemetry/hott.cpp
index f35b1544d..9dc9e723e 100644
--- a/radio/src/telemetry/hott.cpp
+++ b/radio/src/telemetry/hott.cpp
@@ -411,22 +411,22 @@ void processHottPacket(const uint8_t * packet)
sensor = getHottSensor(HOTT_ID_CELS);
// packet[7 ] uint8_t cell1_L; //#07 cell 1 voltage lower value. 0.02V steps, 124=2.48V
value = packet[7] << 1;
- if (value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS, 0, HOTT_TELEM_EAM, 0 << 16 | value, sensor->unit, sensor->precision);
+ if (value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS, 0, HOTT_TELEM_GAM, 0 << 16 | value, sensor->unit, sensor->precision);
// packet[8 ] uint8_t cell2_L; //#08
value = packet[8] << 1;
- if (value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS, 0, HOTT_TELEM_EAM, 1 << 16 | value, sensor->unit, sensor->precision);
+ if (value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS, 0, HOTT_TELEM_GAM, 1 << 16 | value, sensor->unit, sensor->precision);
// packet[9 ] uint8_t cell3_L; //#09
value = packet[9] << 1;
- if (value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS, 0, HOTT_TELEM_EAM, 2 << 16 | value, sensor->unit, sensor->precision);
+ if (value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS, 0, HOTT_TELEM_GAM, 2 << 16 | value, sensor->unit, sensor->precision);
// packet[10] uint8_t cell4_L; //#10
value = packet[10] << 1;
- if (value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS, 0, HOTT_TELEM_EAM, 3 << 16 | value, sensor->unit, sensor->precision);
+ if (value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS, 0, HOTT_TELEM_GAM, 3 << 16 | value, sensor->unit, sensor->precision);
// packet[11] uint8_t cell5_L; //#11
value = packet[11] << 1;
- if (value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS, 0, HOTT_TELEM_EAM, 4 << 16 | value, sensor->unit, sensor->precision);
+ if (value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS, 0, HOTT_TELEM_GAM, 4 << 16 | value, sensor->unit, sensor->precision);
// packet[12] uint8_t cell6_L; //#12
value = packet[12] << 1;
- if (value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS, 0, HOTT_TELEM_EAM, 5 << 16 | value, sensor->unit, sensor->precision);
+ if (value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS, 0, HOTT_TELEM_GAM, 5 << 16 | value, sensor->unit, sensor->precision);
// packet[13] uint8_t batt1_L; //#13 battery 1 voltage LSB value. 0.1V steps. 50 = 5.5V
break;
diff --git a/radio/src/telemetry/mlink.cpp b/radio/src/telemetry/mlink.cpp
new file mode 100644
index 000000000..a7cdccb92
--- /dev/null
+++ b/radio/src/telemetry/mlink.cpp
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) OpenTX
+ *
+ * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "opentx.h"
+
+struct MLinkSensor
+{
+ const uint16_t id;
+ const char * name;
+ const TelemetryUnit unit;
+ const uint8_t precision;
+};
+
+const MLinkSensor mlinkSensors[] = {
+ {MLINK_RX_VOLTAGE, ZSTR_BATT, UNIT_VOLTS, 1},
+ {MLINK_VOLTAGE, ZSTR_VFAS, UNIT_VOLTS, 1},
+ {MLINK_CURRENT, ZSTR_CURR, UNIT_AMPS, 1},
+ {MLINK_VARIO, ZSTR_VSPD, UNIT_METERS_PER_SECOND, 1},
+ {MLINK_SPEED, ZSTR_SPEED, UNIT_KMH, 1},
+ {MLINK_RPM, ZSTR_RPM, UNIT_RPMS, 0},
+ {MLINK_TEMP, ZSTR_TEMP1, UNIT_CELSIUS, 1},
+ {MLINK_HEADING, ZSTR_HDG, UNIT_DEGREE, 1},
+ {MLINK_ALT, ZSTR_ALT , UNIT_METERS, 0},
+ {MLINK_FUEL, ZSTR_FUEL, UNIT_PERCENT, 0},
+ {MLINK_CAPACITY, ZSTR_CAPACITY, UNIT_MAH, 0},
+ {MLINK_FLOW, ZSTR_FLOW, UNIT_MILLILITERS, 0},
+ {MLINK_DISTANCE, ZSTR_DIST, UNIT_KM, 1},
+ {MLINK_LQI, ZSTR_RSSI, UNIT_RAW, 0},
+ {MLINK_LOSS, ZSTR_LOSS, UNIT_RAW, 0},
+ {MLINK_TX_RSSI, ZSTR_TX_RSSI, UNIT_RAW, 0},
+ {MLINK_TX_LQI, ZSTR_TX_QUALITY, UNIT_RAW, 0},
+};
+
+const MLinkSensor * getMLinkSensor(uint16_t id)
+{
+ for (const MLinkSensor * sensor = mlinkSensors; sensor->id; sensor++) {
+ if (id == sensor->id)
+ return sensor;
+ }
+ return nullptr;
+}
+
+void processMLinkPacket(const uint8_t * packet)
+{
+ const uint8_t * data = packet + 2;
+
+ // Multi telem
+ setTelemetryValue(PROTOCOL_TELEMETRY_MLINK, MLINK_TX_RSSI, 0, 0, (packet[0] * 100) / 31, UNIT_RAW, 0);
+ setTelemetryValue(PROTOCOL_TELEMETRY_MLINK, MLINK_TX_LQI, 0, 0, packet[1], UNIT_RAW, 0);
+
+ // M-Link telem
+ if (data[0] == 0x13) { // Telemetry type RX-9
+ for (uint8_t i = 1; i < 5; i += 3) { //2 sensors per packet
+ int32_t val = (int16_t )(data[i + 2] << 8 | data[i + 1]);
+ val = val >> 1; // remove alarm flag
+ uint8_t adress = (data[i] & 0xF0) >> 4;
+ switch (data[i] & 0x0F) {
+ case MLINK_VOLTAGE:
+ if ((data[i] & 0xF0) == 0x00){
+ setTelemetryValue(PROTOCOL_TELEMETRY_MLINK, MLINK_RX_VOLTAGE, 0, adress, val, UNIT_VOLTS, 1);
+ }
+ else {
+ setTelemetryValue(PROTOCOL_TELEMETRY_MLINK, MLINK_VOLTAGE, 0, adress, val, UNIT_VOLTS, 1);
+ }
+ break;
+ case MLINK_CURRENT:
+ setTelemetryValue(PROTOCOL_TELEMETRY_MLINK, MLINK_CURRENT, 0, adress, val, UNIT_AMPS, 1);
+ break;
+ case MLINK_VARIO:
+ setTelemetryValue(PROTOCOL_TELEMETRY_MLINK, MLINK_VARIO, 0, adress, val, UNIT_METERS_PER_SECOND, 1);
+ break;
+ case MLINK_SPEED:
+ setTelemetryValue(PROTOCOL_TELEMETRY_MLINK, MLINK_SPEED, 0, adress, val, UNIT_KMH, 1);
+ break;
+ case MLINK_RPM:
+ if (val < 0) {
+ val = -val * 10;
+ }
+ else {
+ val = val * 100;
+ }
+ setTelemetryValue(PROTOCOL_TELEMETRY_MLINK, MLINK_RPM, 0, adress, val, UNIT_RPMS, 0);
+ break;
+ case MLINK_TEMP:
+ setTelemetryValue(PROTOCOL_TELEMETRY_MLINK, MLINK_TEMP, 0, adress, val, UNIT_CELSIUS, 1);
+ break;
+ case MLINK_HEADING:
+ setTelemetryValue(PROTOCOL_TELEMETRY_MLINK, MLINK_HEADING, 0, adress, val, UNIT_DEGREE, 1);
+ break;
+ case MLINK_ALT:
+ setTelemetryValue(PROTOCOL_TELEMETRY_MLINK, MLINK_ALT, 0, adress, val, UNIT_METERS, 0);
+ break;
+ case MLINK_FUEL:
+ setTelemetryValue(PROTOCOL_TELEMETRY_MLINK, MLINK_FUEL, 0, adress, val, UNIT_PERCENT, 0);
+ break;
+ case MLINK_CAPACITY:
+ setTelemetryValue(PROTOCOL_TELEMETRY_MLINK, MLINK_CAPACITY, 0, adress, val, UNIT_MAH, 0);
+ break;
+ case MLINK_FLOW:
+ setTelemetryValue(PROTOCOL_TELEMETRY_MLINK, MLINK_FLOW, 0, adress, val, UNIT_MILLILITERS, 0);
+ break;
+ case MLINK_DISTANCE:
+ setTelemetryValue(PROTOCOL_TELEMETRY_MLINK, MLINK_DISTANCE, 0, adress, val, UNIT_KM, 1);
+ break;
+ case MLINK_LQI:
+ uint8_t mlinkRssi = data[i + 1] >> 1;
+ setTelemetryValue(PROTOCOL_TELEMETRY_MLINK, MLINK_LQI, 0, 0, mlinkRssi, UNIT_RAW, 0);
+ telemetryData.rssi.set(mlinkRssi);
+ if (mlinkRssi > 0) {
+ telemetryStreaming = TELEMETRY_TIMEOUT10ms;
+ }
+ break;
+ }
+ }
+ }
+ else if (packet[2] == 0x03) { // Telemetry type RX-5
+ uint16_t mlinkRssi = (packet[4] * 100) / 35;
+ setTelemetryValue(PROTOCOL_TELEMETRY_MLINK, MLINK_LQI, 0, 0, mlinkRssi, UNIT_RAW, 0);
+ telemetryData.rssi.set(mlinkRssi);
+ if (mlinkRssi > 0) {
+ telemetryStreaming = TELEMETRY_TIMEOUT10ms;
+ }
+ setTelemetryValue(PROTOCOL_TELEMETRY_MLINK, MLINK_LOSS, 0, 0, packet[7], UNIT_RAW, 0);
+ }
+}
+
+void mlinkSetDefault(int index, uint16_t id, uint8_t subId, uint8_t instance)
+{
+ TelemetrySensor &telemetrySensor = g_model.telemetrySensors[index];
+ telemetrySensor.id = id;
+ telemetrySensor.subId = subId;
+ telemetrySensor.instance = instance;
+
+ const MLinkSensor * sensor = getMLinkSensor(id);
+ if (sensor) {
+ TelemetryUnit unit = sensor->unit;
+ uint8_t prec = min(2, sensor->precision);
+ telemetrySensor.init(sensor->name, unit, prec);
+ if (unit == UNIT_RPMS) {
+ telemetrySensor.custom.ratio = 1;
+ telemetrySensor.custom.offset = 1;
+ }
+ }
+ else {
+ telemetrySensor.init(id);
+ }
+
+ storageDirty(EE_MODEL);
+}
diff --git a/radio/src/telemetry/mlink.h b/radio/src/telemetry/mlink.h
new file mode 100644
index 000000000..eb5da955e
--- /dev/null
+++ b/radio/src/telemetry/mlink.h
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+enum {
+ MLINK_VOLTAGE = 1,
+ MLINK_CURRENT = 2,
+ MLINK_VARIO = 3,
+ MLINK_SPEED = 4,
+ MLINK_RPM = 5,
+ MLINK_TEMP = 6,
+ MLINK_HEADING = 7,
+ MLINK_ALT = 8,
+ MLINK_FUEL = 9,
+ MLINK_LQI = 10,
+ MLINK_CAPACITY = 11,
+ MLINK_FLOW = 12,
+ MLINK_DISTANCE = 13,
+ MLINK_RX_VOLTAGE = 16, // out of range ID for specific RxBt treatment
+ MLINK_LOSS = 17, // out of range ID for handling number of loss
+ MLINK_TX_RSSI = 18, // out of range ID for handling Telemetry RSSi reported by multi
+ MLINK_TX_LQI = 19, // out of range ID for handling Telemetry LQI reported by multi
+};
+
+void processMLinkTelemetryData(uint8_t data, uint8_t* rxBuffer, uint8_t& rxBufferCount);
+void mlinkSetDefault(int index, uint16_t id, uint8_t subId, uint8_t instance);
+
+// Used by multi protocol
+void processMLinkPacket(const uint8_t *packet);
diff --git a/radio/src/telemetry/multi.cpp b/radio/src/telemetry/multi.cpp
index 42f612d57..d71cdad34 100644
--- a/radio/src/telemetry/multi.cpp
+++ b/radio/src/telemetry/multi.cpp
@@ -21,7 +21,7 @@
#include "telemetry.h"
#include "multi.h"
-constexpr int32_t MULTI_DESIRED_VERSION = (1 << 24) | (3 << 16) | (1 << 8) | 1;
+constexpr int32_t MULTI_DESIRED_VERSION = (1 << 24) | (3 << 16) | (1 << 8) | 69;
#define MULTI_CHAN_BITS 11
extern uint8_t g_moduleIdx;
@@ -42,6 +42,7 @@ enum MultiPacketTypes : uint8_t
FlyskyIBusTelemetryAC,
MultiRxChannels,
HottTelemetry,
+ MLinkTelemetry
};
enum MultiBufferState : uint8_t
@@ -63,7 +64,6 @@ enum MultiBufferState : uint8_t
#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];
@@ -74,11 +74,6 @@ MultiModuleStatus &getMultiModuleStatus(uint8_t module)
return multiModuleStatus[module];
}
-MultiModuleSyncStatus &getMultiSyncStatus(uint8_t module)
-{
- return multiSyncStatus[module];
-}
-
uint8_t getMultiBindStatus(uint8_t module)
{
return multiBindStatus[module];
@@ -111,7 +106,6 @@ uint8_t intTelemetryRxBufferCount;
#else // !INTERNAL_MODULE_MULTI
static MultiModuleStatus multiModuleStatus;
-static MultiModuleSyncStatus multiSyncStatus;
static uint8_t multiBindStatus = MULTI_NORMAL_OPERATION;
static MultiBufferState multiTelemetryBufferState;
@@ -122,11 +116,6 @@ MultiModuleStatus& getMultiModuleStatus(uint8_t)
return multiModuleStatus;
}
-MultiModuleSyncStatus& getMultiSyncStatus(uint8_t)
-{
- return multiSyncStatus;
-}
-
uint8_t getMultiBindStatus(uint8_t)
{
return multiBindStatus;
@@ -254,23 +243,14 @@ static void processMultiStatusPacket(const uint8_t * data, uint8_t module, uint8
static void processMultiSyncPacket(const uint8_t * data, uint8_t module)
{
- MultiModuleSyncStatus &status = getMultiSyncStatus(module);
+ ModuleSyncStatus &status = getModuleSyncStatus(module);
- status.lastUpdate = get_tmr10ms();
- status.interval = data[4];
- status.target = data[5];
-#if !defined(PPM_PIN_SERIAL)
- auto oldlag = status.inputLag;
- (void) oldlag;
-#endif
+ uint16_t refreshRate = data[0] << 8 | data[1];
+ int16_t inputLag = 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",
- module == EXTERNAL_MODULE ? extmodulePulsesData.dsm2.rest : 0,
- status.inputLag, oldlag - status.inputLag, status.target, status.interval, status.refreshRate, status.adjustedRefreshRate / 50,
- status.getAdjustedRefreshRate());
+ status.update(refreshRate, inputLag);
+#if defined(DEBUG)
+ serialPrint("MP ADJ: R %d, L %04d", refreshRate, inputLag);
#endif
}
@@ -319,13 +299,13 @@ static void processMultiTelemetryPaket(const uint8_t * packet, uint8_t module)
#if defined(AUX_SERIAL)
if (g_eeGeneral.auxSerialMode == UART_MODE_TELEMETRY_MIRROR) {
- for (uint8_t c=0; c < len; c++)
+ for (uint8_t c = 0; c < len + 2; c++)
auxSerialPutc(packet[c]);
}
#endif
#if defined(AUX2_SERIAL)
if (g_eeGeneral.aux2SerialMode == UART_MODE_TELEMETRY_MIRROR) {
- for (uint8_t c=0; c < len; c++)
+ for (uint8_t c = 0; c < len + 2; c++)
aux2SerialPutc(packet[c]);
}
#endif
@@ -379,6 +359,13 @@ static void processMultiTelemetryPaket(const uint8_t * packet, uint8_t module)
TRACE("[MP] Received HoTT telemetry len %d < 14", len);
break;
+ case MLinkTelemetry:
+ if (len > 6)
+ processMLinkPacket(data);
+ else
+ TRACE("[MP] Received M-Link telemetry len %d < 6", len);
+ break;
+
case FrSkyHubTelemetry:
if (len >= 4)
frskyDProcessPacket(data);
@@ -434,104 +421,6 @@ static void processMultiTelemetryPaket(const uint8_t * packet, uint8_t module)
}
}
-#define MIN_REFRESH_RATE 5500
-
-void MultiModuleSyncStatus::calcAdjustedRefreshRate(uint16_t newRefreshRate, uint16_t newInputLag)
-{
- // Check how far off we are from our target, positive means we are too slow, negative we are too fast
- int lagDifference = newInputLag - inputLag;
-
- // The refresh rate that we target
- // Below is least common multiple of MIN_REFRESH_RATE and requested rate
- uint16_t targetRefreshRate = (uint16_t) (newRefreshRate * ((MIN_REFRESH_RATE / (newRefreshRate - 1)) + 1));
-
- // Overflow, reverse sample
- if (lagDifference < -targetRefreshRate / 2)
- lagDifference = -lagDifference;
-
-
- // Reset adjusted refresh if rate has changed
- if (newRefreshRate != refreshRate) {
- refreshRate = newRefreshRate;
- adjustedRefreshRate = targetRefreshRate;
- if (adjustedRefreshRate >= 30000)
- adjustedRefreshRate /= 2;
-
- // Our refresh rate in ps
- adjustedRefreshRate *= 1000;
- return;
- }
-
- // Caluclate how many samples went into the reported input Lag (*10)
- int numsamples = interval * 10000 / targetRefreshRate;
-
- // Convert lagDifference to ps
- lagDifference = lagDifference * 1000;
-
- // Calculate the time we intentionally were late/early
- if (inputLag > target * 10 + 30)
- lagDifference += numsamples * 500;
- else if (inputLag < target * 10 - 30)
- lagDifference -= numsamples * 500;
-
- // Caculate the time in ps each frame is to slow (positive), fast(negative)
- int perframeps = lagDifference * 10 / numsamples;
-
- if (perframeps > 20000)
- perframeps = 20000;
-
- if (perframeps < -20000)
- perframeps = -20000;
-
- adjustedRefreshRate = (adjustedRefreshRate + perframeps);
-
- // Safeguards
- if (adjustedRefreshRate < MIN_REFRESH_RATE * 1000)
- adjustedRefreshRate = MIN_REFRESH_RATE * 1000;
- if (adjustedRefreshRate > 30 * 1000 * 1000)
- adjustedRefreshRate = 30 * 1000 * 1000;
-
- inputLag = newInputLag;
-}
-
-static uint8_t counter;
-
-const uint16_t MultiModuleSyncStatus::getAdjustedRefreshRate()
-{
- if (!isValid() || refreshRate == 0)
- return 18000;
-
- counter = (uint8_t) (counter + 1 % 10);
- uint16_t rate = (uint16_t) ((adjustedRefreshRate + counter * 50) / 500);
- // Check how far off we are from our target, positive means we are too slow, negative we are too fast
- if (inputLag > target * 10 + 30)
- return (uint16_t) (rate - 1);
- else if (inputLag < target * 10 - 30)
- return (uint16_t) (rate + 1);
- else
- return rate;
-}
-
-void MultiModuleSyncStatus::getRefreshString(char * statusText)
-{
- if (!isValid()) {
- return;
- }
-
- char * tmp = statusText;
-#if defined(DEBUG)
- *tmp++ = 'L';
- tmp = strAppendUnsigned(tmp, inputLag, 5);
- tmp = strAppend(tmp, "us R ");
- tmp = strAppendUnsigned(tmp, (uint32_t) (adjustedRefreshRate / 1000), 5);
- tmp = strAppend(tmp, "us");
-#else
- tmp = strAppend(tmp, "Sync at ");
- tmp = strAppendUnsigned(tmp, (uint32_t) (adjustedRefreshRate / 1000000));
- tmp = strAppend(tmp, " ms");
-#endif
-}
-
void MultiModuleStatus::getStatusString(char * statusText) const
{
if (!isValid()) {
diff --git a/radio/src/telemetry/multi.h b/radio/src/telemetry/multi.h
index e9b9ada15..ca9d3fc79 100644
--- a/radio/src/telemetry/multi.h
+++ b/radio/src/telemetry/multi.h
@@ -94,28 +94,6 @@ void processMultiTelemetryData(uint8_t data, uint8_t module);
#define MULTI_SCANNER_MAX_CHANNEL 249
-// This should be put into the Module definition if other modules gain this functionality
-struct MultiModuleSyncStatus {
- uint32_t adjustedRefreshRate = 9000 * 1000; // in ps
- tmr10ms_t lastUpdate;
- uint16_t refreshRate;
- uint16_t inputLag;
- uint8_t interval;
- uint8_t target;
-
- inline bool isValid() const
- {
- return (get_tmr10ms() - lastUpdate < 100);
- }
-
- void getRefreshString(char * refreshText);
- const uint16_t getAdjustedRefreshRate();
- void calcAdjustedRefreshRate(uint16_t newRefreshRate, uint16_t newInputLag);
-};
-
-MultiModuleSyncStatus& getMultiSyncStatus(uint8_t module);
-
-
struct MultiModuleStatus {
uint8_t major;
diff --git a/radio/src/telemetry/spektrum.cpp b/radio/src/telemetry/spektrum.cpp
index aab694db0..1bd1829d5 100644
--- a/radio/src/telemetry/spektrum.cpp
+++ b/radio/src/telemetry/spektrum.cpp
@@ -47,6 +47,7 @@
#define DSM_BIND_PACKET_LENGTH 12
#define I2C_HIGH_CURRENT 0x03
+#define I2C_FWD_PGM 0x09
#define I2C_TEXTGEN 0x0c
#define I2C_GPS 0x17
#define I2C_GPS2 0x17
@@ -349,6 +350,20 @@ void processSpektrumPacket(const uint8_t *packet)
// highest bit indicates that TM1100 is in use, ignore it
uint8_t i2cAddress = (packet[2] & 0x7f);
+ if (i2cAddress == I2C_FWD_PGM) {
+#if defined(LUA)
+ // Forward Programming
+ if (Multi_Buffer && memcmp(Multi_Buffer, "DSM", 3) == 0) {
+ // Multi_Buffer[0..2]=="DSM" -> Lua script is running
+ // Multi_Buffer[3]==0x70 -> TX to RX data ready to be sent
+ // Multi_Buffer[4..9]=6 bytes of TX to RX data
+ // Multi_Buffer[10..25]=16 bytes of RX to TX data
+ Multi_Buffer[10] = i2cAddress;
+ memcpy(&Multi_Buffer[11], &packet[3], 15); // Store the received RX answer in the buffer
+ }
+#endif
+ return; // Not a sensor
+ }
//SmartBat Hack
if (i2cAddress == I2C_SMART_BAT_BASE_ADDRESS) {
i2cAddress = i2cAddress + (packet[4] >> 4); // use type to create virtual I2CAddresses
diff --git a/radio/src/telemetry/telemetry.cpp b/radio/src/telemetry/telemetry.cpp
index a5f1af94f..700bf535a 100644
--- a/radio/src/telemetry/telemetry.cpp
+++ b/radio/src/telemetry/telemetry.cpp
@@ -21,6 +21,7 @@
#include "opentx.h"
#include "multi.h"
#include "pulses/afhds3.h"
+#include "mixer_scheduler.h"
uint8_t telemetryStreaming = 0;
uint8_t telemetryRxBuffer[TELEMETRY_RX_PACKET_SIZE]; // Receive buffer. 9 bytes (full packet), worst case 18 bytes with byte-stuffing (+1)
@@ -45,6 +46,13 @@ void processTelemetryData(uint8_t data)
}
#endif
+#if defined(GHOST)
+ if (telemetryProtocol == PROTOCOL_TELEMETRY_GHOST) {
+ processGhostTelemetryData(data);
+ return;
+ }
+#endif
+
#if defined(MULTIMODULE)
if (telemetryProtocol == PROTOCOL_TELEMETRY_SPEKTRUM) {
processSpektrumTelemetryData(EXTERNAL_MODULE, data, telemetryRxBuffer, telemetryRxBufferCount);
@@ -111,7 +119,7 @@ void telemetryWakeup()
#endif
#if defined(EXTMODULE_USART)
- while (isModulePxx2(EXTERNAL_MODULE) && extmoduleFifo.getFrame(frame)) {
+ while (isModulePXX2(EXTERNAL_MODULE) && extmoduleFifo.getFrame(frame)) {
processPXX2Frame(EXTERNAL_MODULE, frame);
}
#endif
@@ -209,6 +217,11 @@ void telemetryWakeup()
if (TELEMETRY_STREAMING()) {
if (telemetryState == TELEMETRY_KO) {
AUDIO_TELEMETRY_BACK();
+#if defined(CROSSFIRE)
+ if (isModuleCrossfire(EXTERNAL_MODULE)) {
+ moduleState[EXTERNAL_MODULE].counter = CRSF_FRAME_MODELID;
+ }
+#endif
}
telemetryState = TELEMETRY_OK;
}
@@ -278,6 +291,7 @@ void telemetryInit(uint8_t protocol)
#if defined(LUA)
outputTelemetryBuffer.reset();
#endif
+ telemetryPortSetDirectionInput();
}
else if (protocol == PROTOCOL_TELEMETRY_SPEKTRUM) {
// Spektrum's own small race RX (SPM4648) uses 125000 8N1, use the same since there is no real standard
@@ -295,6 +309,16 @@ void telemetryInit(uint8_t protocol)
}
#endif
+#if defined(GHOST)
+ else if (protocol == PROTOCOL_TELEMETRY_GHOST) {
+ telemetryPortInit(GHOST_BAUDRATE, TELEMETRY_SERIAL_DEFAULT);
+#if defined(LUA)
+ outputTelemetryBuffer.reset();
+#endif
+ telemetryPortSetDirectionOutput();
+ }
+#endif
+
#if defined(AUX_SERIAL) || defined(PCBSKY9X)
else if (protocol == PROTOCOL_TELEMETRY_FRSKY_D_SECONDARY) {
telemetryPortInit(0, TELEMETRY_SERIAL_DEFAULT);
@@ -302,7 +326,7 @@ void telemetryInit(uint8_t protocol)
}
#endif
-#if defined(AFHDS3) && !defined(SIMU)
+#if defined(AFHDS3)
else if (protocol == PROTOCOL_TELEMETRY_AFHDS3) {
telemetryPortInvertedInit(AFHDS3_BAUDRATE);
telemetryPortSetDirectionInput();
@@ -352,3 +376,86 @@ OutputTelemetryBuffer outputTelemetryBuffer __DMA;
#if defined(LUA)
Fifo * luaInputTelemetryFifo = NULL;
#endif
+
+#if defined(HARDWARE_INTERNAL_MODULE)
+static ModuleSyncStatus moduleSyncStatus[NUM_MODULES];
+
+ModuleSyncStatus &getModuleSyncStatus(uint8_t moduleIdx)
+{
+ return moduleSyncStatus[moduleIdx];
+}
+#else
+static ModuleSyncStatus moduleSyncStatus;
+
+ModuleSyncStatus &getModuleSyncStatus(uint8_t moduleIdx)
+{
+ return moduleSyncStatus;
+}
+#endif
+
+ModuleSyncStatus::ModuleSyncStatus()
+{
+ memset(this, 0, sizeof(ModuleSyncStatus));
+}
+
+void ModuleSyncStatus::update(uint16_t newRefreshRate, uint16_t newInputLag)
+{
+ if (!newRefreshRate)
+ return;
+
+ if (newRefreshRate < MIN_REFRESH_RATE)
+ newRefreshRate = newRefreshRate * (MIN_REFRESH_RATE / (newRefreshRate + 1));
+ else if (newRefreshRate > MAX_REFRESH_RATE)
+ newRefreshRate = MAX_REFRESH_RATE;
+
+ refreshRate = newRefreshRate;
+ inputLag = newInputLag;
+ currentLag = newInputLag;
+ lastUpdate = get_tmr10ms();
+
+ TRACE("[SYNC] update rate = %dus; lag = %dus",refreshRate,currentLag);
+}
+
+uint16_t ModuleSyncStatus::getAdjustedRefreshRate()
+{
+ int16_t lag = currentLag;
+ int32_t newRefreshRate = refreshRate;
+
+ if (lag == 0) {
+ return refreshRate;
+ }
+
+ newRefreshRate += lag;
+
+ if (newRefreshRate < MIN_REFRESH_RATE) {
+ newRefreshRate = MIN_REFRESH_RATE;
+ }
+ else if (newRefreshRate > MAX_REFRESH_RATE) {
+ newRefreshRate = MAX_REFRESH_RATE;
+ }
+
+ currentLag -= newRefreshRate - refreshRate;
+ TRACE("[SYNC] mod rate = %dus; lag = %dus",newRefreshRate,currentLag);
+
+ return (uint16_t)newRefreshRate;
+}
+
+void ModuleSyncStatus::getRefreshString(char * statusText)
+{
+ if (!isValid()) {
+ return;
+ }
+
+ char * tmp = statusText;
+#if defined(DEBUG)
+ *tmp++ = 'L';
+ tmp = strAppendUnsigned(tmp, inputLag, 5);
+ tmp = strAppend(tmp, "us R ");
+ tmp = strAppendUnsigned(tmp, (uint32_t) (refreshRate / 1000), 5);
+ tmp = strAppend(tmp, "us");
+#else
+ tmp = strAppend(tmp, "Sync at ");
+ tmp = strAppendUnsigned(tmp, (uint32_t) (refreshRate / 1000000));
+ tmp = strAppend(tmp, " ms");
+#endif
+}
diff --git a/radio/src/telemetry/telemetry.h b/radio/src/telemetry/telemetry.h
index d35198cdc..c70cc5fb9 100644
--- a/radio/src/telemetry/telemetry.h
+++ b/radio/src/telemetry/telemetry.h
@@ -25,12 +25,15 @@
#include "crossfire.h"
#include "myeeprom.h"
#include "io/frsky_sport.h"
-
+#if defined(GHOST)
+ #include "ghost.h"
+#endif
#if defined(MULTIMODULE)
#include "spektrum.h"
#include "hitec.h"
#include "hott.h"
#include "multi.h"
+ #include "mlink.h"
#endif
#if defined(MULTIMODULE) || defined(AFHDS3)
#include "flysky_ibus.h"
@@ -95,6 +98,7 @@ PACK(struct CellValue
});
int setTelemetryValue(TelemetryProtocol protocol, uint16_t id, uint8_t subId, uint8_t instance, int32_t value, uint32_t unit, uint32_t prec);
+int setTelemetryText(TelemetryProtocol protocol, uint16_t id, uint8_t subId, uint8_t instance, const char * text);
void delTelemetryIndex(uint8_t index);
int availableTelemetryIndex();
int lastUsedTelemetryIndex();
@@ -114,6 +118,7 @@ extern uint8_t telemetryProtocol;
|| (g_model.moduleData[module].getMultiProtocol() == MODULE_SUBTYPE_MULTI_FRSKYX2))
#define IS_R9_MULTI(module) (g_model.moduleData[module].getMultiProtocol() == MODULE_SUBTYPE_MULTI_FRSKY_R9)
#define IS_HOTT_MULTI(module) (g_model.moduleData[module].getMultiProtocol() == MODULE_SUBTYPE_MULTI_HOTT)
+ #define IS_DSM_MULTI(module) (g_model.moduleData[module].getMultiProtocol() == MODULE_SUBTYPE_MULTI_DSM2)
#define IS_RX_MULTI(module) ((g_model.moduleData[module].getMultiProtocol() == MODULE_SUBTYPE_MULTI_AFHDS2A_RX) || (g_model.moduleData[module].getMultiProtocol() == MODULE_SUBTYPE_MULTI_FRSKYX_RX) \
|| (g_model.moduleData[module].getMultiProtocol() == MODULE_SUBTYPE_MULTI_BAYANG_RX) || (g_model.moduleData[module].getMultiProtocol() == MODULE_SUBTYPE_MULTI_DSM_RX))
#if defined(HARDWARE_INTERNAL_MODULE)
@@ -125,6 +130,7 @@ extern uint8_t telemetryProtocol;
#define IS_D16_MULTI(module) false
#define IS_R9_MULTI(module) false
#define IS_HOTT_MULTI(module) false
+ #define IS_DSM_MULTI(module) false
#define IS_FRSKY_SPORT_PROTOCOL() (telemetryProtocol == PROTOCOL_TELEMETRY_FRSKY_SPORT)
#define IS_RX_MULTI(module) false
#endif
@@ -153,6 +159,12 @@ inline uint8_t modelTelemetryProtocol()
}
#endif
+#if defined(GHOST)
+ if (g_model.moduleData[EXTERNAL_MODULE].type == MODULE_TYPE_GHOST) {
+ return PROTOCOL_TELEMETRY_GHOST;
+ }
+#endif
+
if (!sportUsed && g_model.moduleData[EXTERNAL_MODULE].type == MODULE_TYPE_PPM) {
return g_model.telemetryProtocol;
}
@@ -278,4 +290,33 @@ extern Fifo * luaInputTelemetryFifo;
void processPXX2Frame(uint8_t module, const uint8_t *frame);
+// Module pulse synchronization
+struct ModuleSyncStatus
+{
+ // feedback input: last received values
+ uint16_t refreshRate; // in us
+ int16_t inputLag; // in us
+
+ tmr10ms_t lastUpdate; // in 10ms
+ int16_t currentLag; // in us
+
+ inline bool isValid() {
+ // 2 seconds
+ return (get_tmr10ms() - lastUpdate < 200);
+ }
+
+ // Set feedback from RF module
+ void update(uint16_t newRefreshRate, uint16_t newInputLag);
+
+ // Get computed settings for scheduler
+ uint16_t getAdjustedRefreshRate();
+
+ // Status string for the UI
+ void getRefreshString(char* refreshText);
+
+ ModuleSyncStatus();
+};
+
+ModuleSyncStatus& getModuleSyncStatus(uint8_t moduleIdx);
+
#endif // _TELEMETRY_H_
diff --git a/radio/src/telemetry/telemetry_sensors.cpp b/radio/src/telemetry/telemetry_sensors.cpp
index d94a8471a..b439bd678 100644
--- a/radio/src/telemetry/telemetry_sensors.cpp
+++ b/radio/src/telemetry/telemetry_sensors.cpp
@@ -78,21 +78,27 @@ uint32_t getDistFromEarthAxis(int32_t latitude)
return 139*(((uint32_t)10000000 - ((angle2*(uint32_t)123370)/81) + (angle4/25))/12500);
}
+void TelemetryItem::setValue(const TelemetrySensor & sensor, const char * val, uint32_t, uint32_t)
+{
+ strncpy(text, val, sizeof(text));
+ setFresh();
+}
+
void TelemetryItem::setValue(const TelemetrySensor & sensor, int32_t val, uint32_t unit, uint32_t prec)
{
int32_t newVal = val;
- if(prec == 255) {
+ if (prec == 255) {
prec = sensor.prec;
}
if (unit == UNIT_CELLS) {
- uint32_t data = uint32_t(newVal);
- uint8_t cellsCount = (data >> 24);
- uint8_t cellIndex = ((data >> 16) & 0x0F);
+ auto data = uint32_t(newVal);
+ uint8_t cellsCount = (data >> 24u);
+ uint8_t cellIndex = ((data >> 16u) & 0x0Fu);
if (cellIndex >= MAX_CELLS)
return;
- uint16_t cellValue = (data & 0xFFFF);
+ uint16_t cellValue = (data & 0xFFFFu);
if (cellsCount == 0) {
cellsCount = (cellIndex >= cells.count ? cellIndex + 1 : cells.count);
if (cellsCount != cells.count) {
@@ -178,18 +184,18 @@ void TelemetryItem::setValue(const TelemetrySensor & sensor, int32_t val, uint32
}
else if (unit == UNIT_DATETIME_DAY_MONTH) {
auto data = uint32_t(newVal);
- datetime.month = data >> 8;
- datetime.day = data & 0xFF;
+ datetime.month = data >> 8u;
+ datetime.day = data & 0xFFu;
return;
}
else if (unit == UNIT_DATETIME_HOUR_MIN) {
auto data = uint32_t(newVal);
- datetime.hour = (data & 0xFF);
- datetime.min = data >> 8;
+ datetime.hour = (data & 0xFFu);
+ datetime.min = data >> 8u;
return;
}
else if (unit == UNIT_DATETIME_SEC) {
- datetime.sec = newVal & 0xFF;
+ datetime.sec = newVal & 0xFFu;
newVal = 0;
}
else if (unit == UNIT_RPMS) {
@@ -198,8 +204,7 @@ void TelemetryItem::setValue(const TelemetrySensor & sensor, int32_t val, uint32
}
}
else if (unit == UNIT_TEXT) {
- *((uint32_t*)&text[prec]) = newVal;
- setFresh();
+ // Should be handled at telemetry protocol level
return;
}
else {
@@ -380,7 +385,7 @@ void TelemetryItem::eval(const TelemetrySensor & sensor)
result = isqrt32(result);
if (altItem) {
- dist = abs(altItem->value) / g_model.telemetrySensors[sensor.dist.alt-1].getPrecDivisor();
+ dist = convertTelemetryValue(abs(altItem->value), g_model.telemetrySensors[sensor.dist.alt-1].unit, g_model.telemetrySensors[sensor.dist.alt-1].prec, UNIT_METERS, 0);
result = (dist * dist) + (result * result);
result = isqrt32(result);
}
@@ -495,7 +500,8 @@ int lastUsedTelemetryIndex()
return -1;
}
-int setTelemetryValue(TelemetryProtocol protocol, uint16_t id, uint8_t subId, uint8_t instance, int32_t value, uint32_t unit, uint32_t prec)
+template
+int setTelemetryValue(TelemetryProtocol protocol, uint16_t id, uint8_t subId, uint8_t instance, T value, uint32_t unit = 0, uint32_t prec = 0)
{
bool sensorFound = false;
@@ -518,36 +524,54 @@ int setTelemetryValue(TelemetryProtocol protocol, uint16_t id, uint8_t subId, ui
case PROTOCOL_TELEMETRY_FRSKY_SPORT:
frskySportSetDefault(index, id, subId, instance);
break;
+
case PROTOCOL_TELEMETRY_FRSKY_D:
frskyDSetDefault(index, id);
break;
+
#if defined(CROSSFIRE)
case PROTOCOL_TELEMETRY_CROSSFIRE:
crossfireSetDefault(index, id, instance);
break;
#endif
+
+#if defined(GHOST)
+ case PROTOCOL_TELEMETRY_GHOST:
+ ghostSetDefault(index, id, instance);
+ break;
+#endif
+
#if defined(MULTIMODULE) || defined(AFHDS3)
case PROTOCOL_TELEMETRY_FLYSKY_IBUS:
flySkySetDefault(index,id, subId, instance);
break;
#endif
+
#if defined(MULTIMODULE)
case PROTOCOL_TELEMETRY_SPEKTRUM:
spektrumSetDefault(index, id, subId, instance);
break;
+
case PROTOCOL_TELEMETRY_HITEC:
hitecSetDefault(index, id, subId, instance);
break;
+
case PROTOCOL_TELEMETRY_HOTT:
hottSetDefault(index, id, subId, instance);
break;
+
+ case PROTOCOL_TELEMETRY_MLINK:
+ mlinkSetDefault(index, id, subId, instance);
+ break;
#endif
+
#if defined(LUA)
case PROTOCOL_TELEMETRY_LUA:
// Sensor will be initialized by calling function
// This drops the first value
return index;
#endif
+
default:
return index;
}
@@ -558,7 +582,16 @@ int setTelemetryValue(TelemetryProtocol protocol, uint16_t id, uint8_t subId, ui
POPUP_WARNING(STR_TELEMETRYFULL);
return -1;
}
+}
+int setTelemetryValue(TelemetryProtocol protocol, uint16_t id, uint8_t subId, uint8_t instance, int32_t value, uint32_t unit, uint32_t prec)
+{
+ return setTelemetryValue(protocol, id, subId, instance, value, unit, prec);
+}
+
+int setTelemetryText(TelemetryProtocol protocol, uint16_t id, uint8_t subId, uint8_t instance, const char * text)
+{
+ return setTelemetryValue(protocol, id, subId, instance, text);
}
void TelemetrySensor::init(const char * label, uint8_t unit, uint8_t prec)
@@ -600,6 +633,7 @@ PACK(typedef struct {
const UnitConversionRule unitConversionTable[] = {
/* unitFrom unitTo multiplier divisor */
{ UNIT_METERS, UNIT_FEET, 105, 32},
+ { UNIT_FEET, UNIT_METERS, 32, 105},
{ UNIT_METERS_PER_SECOND, UNIT_FEET_PER_SECOND, 105, 32},
{ UNIT_KTS, UNIT_KMH, 1852, 1000}, // 1 knot = 1.85200 kilometers per hour
@@ -734,9 +768,9 @@ bool TelemetrySensor::isSameInstance(TelemetryProtocol protocol, uint8_t instanc
return true;
#else
if (((this->instance ^ instance) & 0x9F) == 0 && (this->instance >> 5) != TELEMETRY_ENDPOINT_SPORT && (instance >> 5) != TELEMETRY_ENDPOINT_SPORT) {
- this->instance = instance; // update the instance in case we had telemetry switching
- return true;
- }
+ this->instance = instance; // update the instance in case we had telemetry switching
+ return true;
+ }
#endif
}
diff --git a/radio/src/telemetry/telemetry_sensors.h b/radio/src/telemetry/telemetry_sensors.h
index 6ca1c0c97..8a44ae547 100644
--- a/radio/src/telemetry/telemetry_sensors.h
+++ b/radio/src/telemetry/telemetry_sensors.h
@@ -26,6 +26,7 @@
constexpr int8_t TELEMETRY_SENSOR_TIMEOUT_UNAVAILABLE = -2;
constexpr int8_t TELEMETRY_SENSOR_TIMEOUT_OLD = -1;
constexpr int8_t TELEMETRY_SENSOR_TIMEOUT_START = 125; // * 160ms = 20s
+constexpr uint8_t TELEMETRY_SENSOR_TEXT_LENGTH = 16;
class TelemetryItem
{
@@ -74,7 +75,7 @@ class TelemetryItem
// pilot latitude is stored in max
// distFromEarthAxis is stored in value
} gps;
- char text[16];
+ char text[TELEMETRY_SENSOR_TEXT_LENGTH];
};
TelemetryItem()
@@ -91,6 +92,8 @@ class TelemetryItem
void eval(const TelemetrySensor & sensor);
void per10ms(const TelemetrySensor & sensor);
+ void setValue(const TelemetrySensor & sensor, const char * newVal, uint32_t unit=UNIT_TEXT, uint32_t prec=0);
+
void setValue(const TelemetrySensor & sensor, int32_t newVal, uint32_t unit, uint32_t prec=0);
inline bool isAvailable()
diff --git a/radio/src/tests/fonts_480x272.png b/radio/src/tests/fonts_480x272.png
index abd3e1f72..94d4237b5 100644
Binary files a/radio/src/tests/fonts_480x272.png and b/radio/src/tests/fonts_480x272.png differ
diff --git a/radio/src/tests/mixer.cpp b/radio/src/tests/mixer.cpp
index 074f7f6ca..fa630a265 100644
--- a/radio/src/tests/mixer.cpp
+++ b/radio/src/tests/mixer.cpp
@@ -339,6 +339,106 @@ TEST_F(TrimsTest, CopySticksToOffset)
EXPECT_EQ(g_model.limitData[1].offset, -97);
}
+TEST_F(TrimsTest, MoveTrimsToOffsets)
+{
+ // No trim idle only
+ g_model.thrTrim = 0;
+ anaInValues[THR_STICK] = 0;
+ setTrimValue(0, MIXSRC_TrimThr - MIXSRC_FIRST_TRIM, 100);
+ setTrimValue(0, MIXSRC_TrimEle - MIXSRC_FIRST_TRIM, -100);
+ evalMixes(1);
+ EXPECT_EQ(channelOutputs[2], 200); // THR output value is reflecting 100 trim
+ moveTrimsToOffsets();
+ EXPECT_EQ(getTrimValue(0, MIXSRC_TrimThr - MIXSRC_FIRST_TRIM), 0); // back to neutral
+ EXPECT_EQ(g_model.limitData[2].offset, 195); // value transferred
+ EXPECT_EQ(getTrimValue(0, MIXSRC_TrimEle - MIXSRC_FIRST_TRIM), 0); // back to neutral
+ EXPECT_EQ(g_model.limitData[1].offset, -195); // value transferred
+ evalMixes(1);
+ EXPECT_EQ(channelOutputs[2], 200); // THR output value is still reflecting 100 trim
+}
+
+TEST_F(TrimsTest, MoveTrimsToOffsetsWithTrimIdle)
+{
+ // Trim idle only
+ g_model.thrTrim = 1;
+ anaInValues[THR_STICK] = -1024; // Min stick
+ g_model.limitData[2].offset = 0;
+ g_model.limitData[1].offset = 0;
+ setTrimValue(0, MIXSRC_TrimThr - MIXSRC_FIRST_TRIM, 100);
+ setTrimValue(0, MIXSRC_TrimEle - MIXSRC_FIRST_TRIM, -100);
+ evalMixes(1);
+ EXPECT_EQ(channelOutputs[2], -574); // THR output value is reflecting 100 trim idle
+ moveTrimsToOffsets();
+
+ // Trim affecting Throttle should not be affected
+ EXPECT_EQ(getTrimValue(0, MIXSRC_TrimThr - MIXSRC_FIRST_TRIM), 100); // unchanged
+ EXPECT_EQ(g_model.limitData[2].offset, 0); // unchanged
+
+ // Other trims should
+ EXPECT_EQ(getTrimValue(0, MIXSRC_TrimEle - MIXSRC_FIRST_TRIM), 0); // back to neutral
+ EXPECT_EQ(g_model.limitData[1].offset, -195); // value transferred
+ evalMixes(1);
+ EXPECT_EQ(channelOutputs[2], -574); // THR output value is still reflecting 100 trim idle
+}
+
+TEST_F(TrimsTest, MoveTrimsToOffsetsWithCrossTrims)
+{
+ // No trim idle only
+ // Cross trims
+ g_model.thrTrim = 0;
+ g_model.limitData[2].offset = 0;
+ g_model.limitData[1].offset = 0;
+ g_model.thrTrimSw = MIXSRC_TrimEle - MIXSRC_FIRST_TRIM;
+ ExpoData *expo = expoAddress(THR_STICK);
+ expo->carryTrim = TRIM_ELE;
+ expo = expoAddress(ELE_STICK);
+ expo->carryTrim = TRIM_THR;
+
+ anaInValues[THR_STICK] = 0;
+ setTrimValue(0, MIXSRC_TrimEle - MIXSRC_FIRST_TRIM, 100);
+ setTrimValue(0, MIXSRC_TrimThr - MIXSRC_FIRST_TRIM, -100);
+ evalMixes(1);
+ EXPECT_EQ(channelOutputs[2], 200); // THR output value is reflecting 100 Ele trim
+ moveTrimsToOffsets();
+ evalMixes(1);
+ EXPECT_EQ(channelOutputs[2], 200); // THR output value remains unchanged
+ EXPECT_EQ(getTrimValue(0, MIXSRC_TrimThr - MIXSRC_FIRST_TRIM), 0); // back to neutral
+ EXPECT_EQ(g_model.limitData[2].offset, 195); // value transferred
+ EXPECT_EQ(getTrimValue(0, MIXSRC_TrimEle - MIXSRC_FIRST_TRIM), 0); // back to neutral
+ EXPECT_EQ(g_model.limitData[1].offset, -195); // value transferred
+}
+
+TEST_F(TrimsTest, MoveTrimsToOffsetsWithCrosstrimsAndTrimIdle)
+{
+ // Trim idle only
+ // Cross trims
+ g_model.limitData[2].offset = 0;
+ g_model.limitData[1].offset = 0;
+ g_model.thrTrim = 1;
+ g_model.thrTrimSw = MIXSRC_TrimEle - MIXSRC_FIRST_TRIM;
+ ExpoData *expo = expoAddress(THR_STICK);
+ expo->carryTrim = TRIM_ELE;
+ expo = expoAddress(ELE_STICK);
+ expo->carryTrim = TRIM_THR;
+
+ anaInValues[THR_STICK] = -1024; // Min stick
+ setTrimValue(0, MIXSRC_TrimEle - MIXSRC_FIRST_TRIM, 100);
+ setTrimValue(0, MIXSRC_TrimThr - MIXSRC_FIRST_TRIM, -100);
+ evalMixes(1);
+ EXPECT_EQ(channelOutputs[2], -574); // THR output value is reflecting 100 ele trim idle
+ moveTrimsToOffsets();
+
+ // Trim affecting Throttle (now Ele because of crosstrims) should not be affected
+ EXPECT_EQ(getTrimValue(0, MIXSRC_TrimEle - MIXSRC_FIRST_TRIM), 100); // unchanged
+ EXPECT_EQ(g_model.limitData[2].offset, 0); // THR chan offset unchanged
+
+ // Other trims should
+ EXPECT_EQ(getTrimValue(0, MIXSRC_TrimThr - MIXSRC_FIRST_TRIM), 0); // back to neutral
+ EXPECT_EQ(g_model.limitData[1].offset, -195); // Ele chan offset transfered
+ evalMixes(1);
+ EXPECT_EQ(channelOutputs[2], -574); // THR output value is still reflecting 100 trim idle
+}
+
TEST_F(TrimsTest, InstantTrim)
{
anaInValues[AIL_STICK] = 50;
@@ -720,3 +820,152 @@ TEST_F(MixerTest, flightModeOverflow)
simuSetSwitch(0, 1);
CHECK_FLIGHT_MODE_TRANSITION(0, 1000, 1024, 1024);
}
+
+TEST_F(TrimsTest, throttleTrimWithCrossTrims)
+{
+ g_model.thrTrim = 1;
+ g_model.thrTrimSw = MIXSRC_TrimEle - MIXSRC_FIRST_TRIM;
+ ExpoData *expo = expoAddress(THR_STICK);
+ expo->carryTrim = TRIM_ELE;
+ expo = expoAddress(ELE_STICK);
+ expo->carryTrim = TRIM_THR;
+
+ // stick max + trim max
+ anaInValues[THR_STICK] = +1024;
+ setTrimValue(0, MIXSRC_TrimEle - MIXSRC_FIRST_TRIM, TRIM_MAX);
+ evalMixes(1);
+ EXPECT_EQ(channelOutputs[2], 1024);
+ EXPECT_EQ(channelOutputs[1], 0);
+ // stick max + trim min
+ anaInValues[THR_STICK] = +1024;
+ setTrimValue(0, MIXSRC_TrimEle - MIXSRC_FIRST_TRIM, TRIM_MIN);
+ evalMixes(1);
+ EXPECT_EQ(channelOutputs[2], 1024);
+ EXPECT_EQ(channelOutputs[1], 0);
+ // stick min + trim max
+ anaInValues[THR_STICK] = -1024;
+ setTrimValue(0, MIXSRC_TrimEle - MIXSRC_FIRST_TRIM, TRIM_MAX);
+ evalMixes(1);
+ EXPECT_EQ(channelOutputs[2], -1024 + 500);
+ EXPECT_EQ(channelOutputs[1], 0);
+ // stick min + trim mid
+ anaInValues[THR_STICK] = -1024;
+ setTrimValue(0, MIXSRC_TrimEle - MIXSRC_FIRST_TRIM, 0);
+ evalMixes(1);
+ EXPECT_EQ(channelOutputs[2], -1024 + 250);
+ EXPECT_EQ(channelOutputs[1], 0);
+ // stick min + trim min
+ anaInValues[THR_STICK] = -1024;
+ setTrimValue(0, MIXSRC_TrimEle - MIXSRC_FIRST_TRIM, TRIM_MIN);
+ evalMixes(1);
+ EXPECT_EQ(channelOutputs[2], -1024);
+ EXPECT_EQ(channelOutputs[1], 0);
+
+ // now the same tests with extended Trims
+ g_model.extendedTrims = 1;
+ // stick max + trim max
+ anaInValues[THR_STICK] = +1024;
+ setTrimValue(0, MIXSRC_TrimEle - MIXSRC_FIRST_TRIM, TRIM_EXTENDED_MAX);
+ evalMixes(1);
+ EXPECT_EQ(channelOutputs[2], 1024);
+ EXPECT_EQ(channelOutputs[1], 0);
+ // stick max + trim min
+ anaInValues[THR_STICK] = +1024;
+ setTrimValue(0, MIXSRC_TrimEle - MIXSRC_FIRST_TRIM, TRIM_EXTENDED_MIN);
+ evalMixes(1);
+ EXPECT_EQ(channelOutputs[2], 1024);
+ EXPECT_EQ(channelOutputs[1], 0);
+ // stick min + trim max
+ anaInValues[THR_STICK] = -1024;
+ setTrimValue(0, MIXSRC_TrimEle - MIXSRC_FIRST_TRIM, TRIM_EXTENDED_MAX);
+ evalMixes(1);
+ EXPECT_EQ(channelOutputs[2], -1024+2000);
+ EXPECT_EQ(channelOutputs[1], 0);
+ // stick min + trim mid
+ anaInValues[THR_STICK] = -1024;
+ setTrimValue(0, MIXSRC_TrimEle - MIXSRC_FIRST_TRIM, 0);
+ evalMixes(1);
+ EXPECT_EQ(channelOutputs[2], -1024+1000);
+ EXPECT_EQ(channelOutputs[1], 0);
+ // stick min + trim min
+ anaInValues[THR_STICK] = -1024;
+ setTrimValue(0, MIXSRC_TrimEle - MIXSRC_FIRST_TRIM, TRIM_EXTENDED_MIN);
+ evalMixes(1);
+ EXPECT_EQ(channelOutputs[2], -1024);
+ EXPECT_EQ(channelOutputs[1], 0);
+}
+
+TEST_F(TrimsTest, invertedThrottlePlusThrottleTrimWithCrossTrims)
+{
+ g_model.throttleReversed = 1;
+ g_model.thrTrim = 1;
+ g_model.thrTrimSw = MIXSRC_TrimEle - MIXSRC_FIRST_TRIM;
+ ExpoData *expo = expoAddress(THR_STICK);
+ expo->carryTrim = TRIM_ELE;
+ expo = expoAddress(ELE_STICK);
+ expo->carryTrim = TRIM_THR;
+
+ // stick max + trim max
+ anaInValues[THR_STICK] = +1024;
+ setTrimValue(0, MIXSRC_TrimEle - MIXSRC_FIRST_TRIM, TRIM_MAX);
+ evalMixes(1);
+ EXPECT_EQ(channelOutputs[2], -1024);
+ EXPECT_EQ(channelOutputs[1], 0);
+ // stick max + trim mid
+ anaInValues[THR_STICK] = +1024;
+ setTrimValue(0, MIXSRC_TrimEle - MIXSRC_FIRST_TRIM, 0);
+ evalMixes(1);
+ EXPECT_EQ(channelOutputs[2], -1024+250);
+ EXPECT_EQ(channelOutputs[1], 0);
+ // stick max + trim min
+ anaInValues[THR_STICK] = +1024;
+ setTrimValue(0, MIXSRC_TrimEle - MIXSRC_FIRST_TRIM, TRIM_MIN);
+ evalMixes(1);
+ EXPECT_EQ(channelOutputs[2], -1024+500);
+ EXPECT_EQ(channelOutputs[1], 0);
+ // stick min + trim max
+ anaInValues[THR_STICK] = -1024;
+ setTrimValue(0, MIXSRC_TrimEle - MIXSRC_FIRST_TRIM, TRIM_MAX);
+ evalMixes(1);
+ EXPECT_EQ(channelOutputs[2], +1024);
+ EXPECT_EQ(channelOutputs[1], 0);
+ // stick min + trim min
+ anaInValues[THR_STICK] = -1024;
+ setTrimValue(0, MIXSRC_TrimEle - MIXSRC_FIRST_TRIM, TRIM_MIN);
+ evalMixes(1);
+ EXPECT_EQ(channelOutputs[2], +1024);
+ EXPECT_EQ(channelOutputs[1], 0);
+
+ // now the same tests with extended Trims
+ g_model.extendedTrims = 1;
+ // stick max + trim max
+ anaInValues[THR_STICK] = +1024;
+ setTrimValue(0, MIXSRC_TrimEle - MIXSRC_FIRST_TRIM, TRIM_EXTENDED_MAX);
+ evalMixes(1);
+ EXPECT_EQ(channelOutputs[2], -1024);
+ EXPECT_EQ(channelOutputs[1], 0);
+ // stick max + trim mid
+ anaInValues[THR_STICK] = +1024;
+ setTrimValue(0, MIXSRC_TrimEle - MIXSRC_FIRST_TRIM, 0);
+ evalMixes(1);
+ EXPECT_EQ(channelOutputs[2], -1024+1000);
+ EXPECT_EQ(channelOutputs[1], 0);
+ // stick max + trim min
+ anaInValues[THR_STICK] = +1024;
+ setTrimValue(0, MIXSRC_TrimEle - MIXSRC_FIRST_TRIM, TRIM_EXTENDED_MIN);
+ evalMixes(1);
+ EXPECT_EQ(channelOutputs[2], -1024+2000);
+ EXPECT_EQ(channelOutputs[1], 0);
+ // stick min + trim max
+ anaInValues[THR_STICK] = -1024;
+ setTrimValue(0, MIXSRC_TrimEle - MIXSRC_FIRST_TRIM, TRIM_EXTENDED_MAX);
+ evalMixes(1);
+ EXPECT_EQ(channelOutputs[2], +1024);
+ EXPECT_EQ(channelOutputs[1], 0);
+ // stick min + trim min
+ anaInValues[THR_STICK] = -1024;
+ setTrimValue(0, MIXSRC_TrimEle - MIXSRC_FIRST_TRIM, TRIM_EXTENDED_MIN);
+ evalMixes(1);
+ EXPECT_EQ(channelOutputs[2], +1024);
+ EXPECT_EQ(channelOutputs[1], 0);
+}
diff --git a/radio/src/tests/switches.cpp b/radio/src/tests/switches.cpp
index 4eae3ba5c..504fae354 100644
--- a/radio/src/tests/switches.cpp
+++ b/radio/src/tests/switches.cpp
@@ -106,7 +106,7 @@ TEST(evalLogicalSwitches, playFile)
char filename[AUDIO_FILENAME_MAXLEN+1];
#if defined(EEPROM)
-#define MODELNAME "MODEL01"
+#define MODELNAME TR_MODEL "01"
#else
#define MODELNAME "Model00"
#endif
diff --git a/radio/src/trainer.cpp b/radio/src/trainer.cpp
index 27a237b54..c4c3c0c4f 100644
--- a/radio/src/trainer.cpp
+++ b/radio/src/trainer.cpp
@@ -26,8 +26,8 @@ uint8_t currentTrainerMode = 0xff;
void checkTrainerSignalWarning()
{
- enum PpmInValidState_t {
- PPM_IN_IS_NOT_USED=0,
+ enum {
+ PPM_IN_IS_NOT_USED = 0,
PPM_IN_IS_VALID,
PPM_IN_INVALID
};
@@ -48,6 +48,11 @@ void checkTrainerSignalWarning()
}
#if defined(PCBSKY9X)
+void stopTrainer()
+{
+ stop_trainer_capture();
+}
+
void checkTrainerSettings()
{
uint8_t requiredTrainerMode = SLAVE_MODE();
@@ -55,43 +60,59 @@ void checkTrainerSettings()
if (requiredTrainerMode != currentTrainerMode) {
currentTrainerMode = requiredTrainerMode;
if (requiredTrainerMode)
- stop_trainer_capture();
+ stopTrainer();
else
init_trainer_capture();
}
}
#else
+void stopTrainer()
+{
+ switch (currentTrainerMode) {
+ case TRAINER_MODE_MASTER_TRAINER_JACK:
+ stop_trainer_capture();
+ break;
+
+ case TRAINER_MODE_SLAVE:
+ stop_trainer_ppm();
+ break;
+
+#if defined(TRAINER_MODULE_CPPM)
+ case TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE:
+ stop_trainer_module_cppm();
+ break;
+#endif
+
+#if defined(TRAINER_MODULE_SBUS)
+ case TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE:
+ stop_trainer_module_sbus();
+ break;
+#endif
+
+#if defined(TRAINER_BATTERY_COMPARTMENT)
+ case TRAINER_MODE_MASTER_BATTERY_COMPARTMENT:
+#if defined(AUX_SERIAL)
+ if (g_eeGeneral.auxSerialMode == UART_MODE_SBUS_TRAINER)
+ auxSerialStop();
+#endif
+#if defined(AUX2_SERIAL)
+ if (g_eeGeneral.aux2SerialMode == UART_MODE_SBUS_TRAINER)
+ aux2SerialStop();
+#endif
+ break;
+#endif
+ }
+
+ currentTrainerMode = 0xFF;
+}
+
void checkTrainerSettings()
{
uint8_t requiredTrainerMode = g_model.trainerData.mode;
if (requiredTrainerMode != currentTrainerMode) {
- switch (currentTrainerMode) {
- case TRAINER_MODE_MASTER_TRAINER_JACK:
- stop_trainer_capture();
- break;
-
- case TRAINER_MODE_SLAVE:
- stop_trainer_ppm();
- break;
-
-#if defined(TRAINER_MODULE_CPPM)
- case TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE:
- stop_trainer_module_cppm();
- break;
-#endif
-
-#if defined(TRAINER_MODULE_SBUS)
- case TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE:
- stop_trainer_module_sbus();
- break;
-#endif
-
-#if defined(TRAINER_BATTERY_COMPARTMENT)
- case TRAINER_MODE_MASTER_BATTERY_COMPARTMENT:
- auxSerialStop();
- break;
-#endif
+ if (currentTrainerMode != 0xFF) {
+ stopTrainer();
}
currentTrainerMode = requiredTrainerMode;
@@ -116,17 +137,20 @@ void checkTrainerSettings()
#if defined(TRAINER_BATTERY_COMPARTMENT)
case TRAINER_MODE_MASTER_BATTERY_COMPARTMENT:
#if defined(AUX_SERIAL)
- if (g_eeGeneral.auxSerialMode == UART_MODE_SBUS_TRAINER)
+ if (g_eeGeneral.auxSerialMode == UART_MODE_SBUS_TRAINER) {
auxSerialSbusInit();
- else
+ break;
+ }
#endif
+
#if defined(AUX2_SERIAL)
- if (g_eeGeneral.aux2SerialMode == UART_MODE_SBUS_TRAINER)
+ if (g_eeGeneral.aux2SerialMode == UART_MODE_SBUS_TRAINER) {
aux2SerialSbusInit();
- else
+ break;
+ }
#endif
- init_trainer_capture();
- break;
+
+ // no break
#endif
case TRAINER_MODE_MASTER_TRAINER_JACK:
@@ -139,8 +163,13 @@ void checkTrainerSettings()
stop_intmodule_heartbeat();
else
init_intmodule_heartbeat();
+#else
+#if defined(HARDWARE_EXTERNAL_ACCESS_MOD)
+ if (g_model.moduleData[EXTERNAL_MODULE].type != MODULE_TYPE_R9M_PXX2) // externalaccessmod 'bridges' HB and Ext module RX pins
+ init_intmodule_heartbeat();
#else
init_intmodule_heartbeat();
+#endif
#endif
}
}
diff --git a/radio/src/trainer.h b/radio/src/trainer.h
index e3c67acac..1222d4f55 100644
--- a/radio/src/trainer.h
+++ b/radio/src/trainer.h
@@ -35,6 +35,7 @@ extern uint8_t currentTrainerMode;
void checkTrainerSignalWarning();
void checkTrainerSettings();
+void stopTrainer();
void forceResetTrainerSettings();
// Needs to be inlined to avoid slow function calls in ISR routines
diff --git a/radio/src/translations.cpp b/radio/src/translations.cpp
index 4d65e6840..7cc5977d7 100644
--- a/radio/src/translations.cpp
+++ b/radio/src/translations.cpp
@@ -81,6 +81,7 @@ ISTR(POTTYPES);
ISTR(SLIDERTYPES);
ISTR(ANTENNA_MODES);
ISTR(SPORT_UPDATE_POWER_MODES);
+ISTR(SPORT_MODES);
#if defined(PCBSKY9X) && defined(REVX)
ISTR(VOUTPUT_TYPE);
@@ -97,6 +98,8 @@ ISTR(INPUTNAMES);
#if defined(MULTIMODULE)
ISTR(MULTI_PROTOCOLS);
ISTR(MULTI_POWER);
+ISTR(MULTI_TELEMETRY_MODE);
+ISTR(MULTI_WBUS_MODE);
#endif
#if defined(BLUETOOTH)
@@ -123,6 +126,7 @@ const char STR_TRIMINC[] = TR_TRIMINC;
const char STR_DISPLAY_TRIMS[] = TR_DISPLAY_TRIMS;
const char STR_TTRACE[] = TR_TTRACE;
const char STR_TTRIM[] = TR_TTRIM;
+const char STR_TTRIM_SW[] = TR_TTRIM_SW;
const char STR_BEEPCTR[] = TR_BEEPCTR;
const char STR_USE_GLOBAL_FUNCS[] = TR_USE_GLOBAL_FUNCS;
const char STR_PPMFRAME[] = TR_PPMFRAME;
@@ -130,6 +134,7 @@ const char STR_REFRESHRATE[] = TR_REFRESHRATE;
const char STR_MS[] = TR_MS;
const char STR_SWITCH[] = TR_SWITCH;
const char STR_TRIMS[] = TR_TRIMS;
+const char STR_MIRROR[] = TR_MIRROR;
const char STR_FADEIN[] = TR_FADEIN;
const char STR_FADEOUT[] = TR_FADEOUT;
const char STR_DEFAULT[] = TR_DEFAULT;
@@ -181,6 +186,7 @@ const char STR_MINUTEBEEP[] = TR_MINUTEBEEP;
const char STR_BEEPCOUNTDOWN[] = TR_BEEPCOUNTDOWN;
const char STR_PERSISTENT[] = TR_PERSISTENT;
const char STR_BACKLIGHT_LABEL[] = TR_BACKLIGHT_LABEL;
+const char STR_GHOST_MENU_LABEL[] = TR_GHOST_MENU_LABEL;
const char STR_BLDELAY[] = TR_BLDELAY;
const char STR_RXCHANNELORD[] = TR_RXCHANNELORD;
const char STR_STICKS[] = TR_STICKS;
@@ -357,6 +363,7 @@ const char STR_SPECTRUM_ANALYSER_EXT[] = TR_SPECTRUM_ANALYSER_EXT;
const char STR_SPECTRUM_ANALYSER_INT[] = TR_SPECTRUM_ANALYSER_INT;
const char STR_WAITING_FOR_RX[] = TR_WAITING_FOR_RX;
const char STR_WAITING_FOR_TX[] = TR_WAITING_FOR_TX;
+const char STR_WAITING_FOR_MODULE[] = TR_WAITING_FOR_MODULE;
const char STR_WARN_5VOLTS[] = TR_WARN_5VOLTS;
const char STR_CAT_NOT_EMPTY[] = TR_CAT_NOT_EMPTY;
const char STR_WARNING[] = TR_WARNING;
@@ -434,13 +441,16 @@ const char STR_FLASH_INTERNAL_MODULE[] = TR_FLASH_INTERNAL_MODULE;
const char STR_FLASH_INTERNAL_MULTI[] = TR_FLASH_INTERNAL_MULTI;
const char STR_FLASH_EXTERNAL_MODULE[] = TR_FLASH_EXTERNAL_MODULE;
const char STR_FLASH_EXTERNAL_MULTI[] = TR_FLASH_EXTERNAL_MULTI;
+const char STR_FLASH_EXTERNAL_ELRS[] = TR_FLASH_EXTERNAL_ELRS;
const char STR_FIRMWARE_UPDATE_ERROR[] = TR_FIRMWARE_UPDATE_ERROR;
const char STR_FIRMWARE_UPDATE_SUCCESS[] = TR_FIRMWARE_UPDATE_SUCCESS;
const char STR_WRITING[] = TR_WRITING;
const char STR_FLASH_EXTERNAL_DEVICE[] = TR_FLASH_EXTERNAL_DEVICE;
const char STR_FLASH_RECEIVER_OTA[] = TR_FLASH_RECEIVER_OTA;
-const char STR_FLASH_RECEIVER_OTA_BY_EXTERNAL[] = TR_FLASH_RECEIVER_OTA_BY_EXTERNAL;
-const char STR_FLASH_RECEIVER_OTA_BY_INTERNAL[] = TR_FLASH_RECEIVER_OTA_BY_INTERNAL;
+const char STR_FLASH_RECEIVER_BY_EXTERNAL_MODULE_OTA[] = TR_FLASH_RECEIVER_BY_EXTERNAL_MODULE_OTA;
+const char STR_FLASH_RECEIVER_BY_INTERNAL_MODULE_OTA[] = TR_FLASH_RECEIVER_BY_INTERNAL_MODULE_OTA;
+const char STR_FLASH_FLIGHT_CONTROLLER_BY_EXTERNAL_MODULE_OTA[] = TR_FLASH_FLIGHT_CONTROLLER_BY_EXTERNAL_MODULE_OTA;
+const char STR_FLASH_FLIGHT_CONTROLLER_BY_INTERNAL_MODULE_OTA[] = TR_FLASH_FLIGHT_CONTROLLER_BY_INTERNAL_MODULE_OTA;
const char STR_FLASH_BLUETOOTH_MODULE[] = TR_FLASH_BLUETOOTH_MODULE;
const char STR_FLASH_POWER_MANAGEMENT_UNIT[] = TR_FLASH_POWER_MANAGEMENT_UNIT;
const char STR_CONFIRM_FORMAT[] = TR_CONFIRM_FORMAT;
@@ -531,6 +541,9 @@ const char STR_LAYOUT[] = TR_LAYOUT;
const char STR_ADDMAINVIEW[] = TR_ADDMAINVIEW;
const char STR_BACKGROUND_COLOR[] = TR_BACKGROUND_COLOR;
const char STR_MAIN_COLOR[] = TR_MAIN_COLOR;
+const char STR_BAR2_COLOR[] = TR_BAR2_COLOR;
+const char STR_BAR1_COLOR[] = TR_BAR1_COLOR;
+const char STR_TEXT_COLOR[] = TR_TEXT_COLOR;
const char STR_TEXT_VIEWER[] = TR_TEXT_VIEWER;
const char STR_RFPOWER[] = TR_RFPOWER;
const char STR_BYTES[] = TR_BYTES;
@@ -542,7 +555,6 @@ const char STR_MIN[] = TR_MIN;
const char STR_MAX[] = TR_MAX;
const char STR_CURVE_PRESET[] = TR_CURVE_PRESET;
const char STR_PRESET[] = TR_PRESET;
-const char STR_MIRROR[] = TR_MIRROR;
const char STR_CLEAR[] = TR_CLEAR;
const char STR_RESET[] = TR_RESET;
const char STR_COUNT[] = TR_COUNT;
@@ -697,6 +709,7 @@ const char STR_BIND_OK[] = TR_BIND_OK;
const char STR_MULTI_CUSTOM[] = TR_MULTI_CUSTOM;
const char STR_MULTI_RFTUNE[] = TR_MULTI_RFTUNE;
const char STR_MULTI_RFPOWER[] = TR_MULTI_RFPOWER;
+const char STR_MULTI_WBUS[] = TR_MULTI_WBUS;
const char STR_MULTI_TELEMETRY[] = TR_MULTI_TELEMETRY;
const char STR_MULTI_VIDFREQ[] = TR_MULTI_VIDFREQ;
const char STR_MULTI_OPTION[] = TR_MULTI_OPTION;
@@ -820,3 +833,5 @@ const char STR_ABOUT_PARENTS_3[] = TR_ABOUT_PARENTS_3;
const char STR_ABOUT_PARENTS_4[] = TR_ABOUT_PARENTS_4;
const char STR_AUTH_FAILURE[] = TR_AUTH_FAILURE;
+const char STR_PROTOCOL[] = TR_PROTOCOL;
+const char STR_RACING_MODE[] = TR_RACING_MODE;
diff --git a/radio/src/translations.h b/radio/src/translations.h
index f99520cd7..0ec58fe8e 100644
--- a/radio/src/translations.h
+++ b/radio/src/translations.h
@@ -161,6 +161,9 @@ extern const char STR_R9M_PXX2_RF_PROTOCOLS[];
extern const char STR_DSM_PROTOCOLS[];
extern const char STR_MULTI_PROTOCOLS[];
extern const char STR_MULTI_POWER[];
+extern const char STR_MULTI_TELEMETRY_MODE[];
+extern const char STR_MULTI_WBUS_MODE[];
+extern const char STR_SPORT_MODES[];
#if defined(AFHDS3)
extern const char STR_AFHDS3_ONE_TO_ONE_TELEMETRY[];
@@ -215,6 +218,7 @@ extern const char STR_TRIMINC[];
extern const char STR_DISPLAY_TRIMS[];
extern const char STR_TTRACE[];
extern const char STR_TTRIM[];
+extern const char STR_TTRIM_SW[];
extern const char STR_BEEPCTR[];
extern const char STR_USE_GLOBAL_FUNCS[];
@@ -227,6 +231,7 @@ extern const char STR_REFRESHRATE[];
extern const char STR_MS[];
extern const char STR_SWITCH[];
extern const char STR_TRIMS[];
+extern const char STR_MIRROR[];
extern const char STR_FADEIN[];
extern const char STR_FADEOUT[];
extern const char STR_DEFAULT[];
@@ -298,6 +303,7 @@ extern const char STR_MINUTEBEEP[];
extern const char STR_BEEPCOUNTDOWN[];
extern const char STR_PERSISTENT[];
extern const char STR_BACKLIGHT_LABEL[];
+extern const char STR_GHOST_MENU_LABEL[];
extern const char STR_BLDELAY[];
#if defined(PWM_BACKLIGHT) || defined(COLORLCD)
@@ -399,6 +405,7 @@ extern const char STR_MULTI_OPTION[];
extern const char STR_MULTI_VIDFREQ[];
extern const char STR_MULTI_RFTUNE[];
extern const char STR_MULTI_RFPOWER[];
+extern const char STR_MULTI_WBUS[];
extern const char STR_MULTI_TELEMETRY[];
extern const char STR_MULTI_AUTOBIND[];
extern const char STR_DISABLE_CH_MAP[];
@@ -541,6 +548,7 @@ extern const char STR_SPECTRUM_ANALYSER_EXT[];
extern const char STR_SPECTRUM_ANALYSER_INT[];
extern const char STR_WAITING_FOR_RX[];
extern const char STR_WAITING_FOR_TX[];
+extern const char STR_WAITING_FOR_MODULE[];
extern const char STR_WARN_5VOLTS[];
#if defined(SDCARD)
@@ -659,8 +667,10 @@ extern const char STR_VIEW_TEXT[];
extern const char STR_FLASH_BOOTLOADER[];
extern const char STR_FLASH_EXTERNAL_DEVICE[];
extern const char STR_FLASH_RECEIVER_OTA[];
-extern const char STR_FLASH_RECEIVER_OTA_BY_EXTERNAL[];
-extern const char STR_FLASH_RECEIVER_OTA_BY_INTERNAL[];
+extern const char STR_FLASH_RECEIVER_BY_EXTERNAL_MODULE_OTA[];
+extern const char STR_FLASH_RECEIVER_BY_INTERNAL_MODULE_OTA[];
+extern const char STR_FLASH_FLIGHT_CONTROLLER_BY_EXTERNAL_MODULE_OTA[];
+extern const char STR_FLASH_FLIGHT_CONTROLLER_BY_INTERNAL_MODULE_OTA[];
extern const char STR_FLASH_BLUETOOTH_MODULE[];
extern const char STR_FLASH_POWER_MANAGEMENT_UNIT[];
extern const char STR_CURRENT_VERSION[];
@@ -668,6 +678,7 @@ extern const char STR_FLASH_INTERNAL_MODULE[];
extern const char STR_FLASH_INTERNAL_MULTI[];
extern const char STR_FLASH_EXTERNAL_MODULE[];
extern const char STR_FLASH_EXTERNAL_MULTI[];
+extern const char STR_FLASH_EXTERNAL_ELRS[];
extern const char STR_FIRMWARE_UPDATE_ERROR[];
extern const char STR_FIRMWARE_UPDATE_SUCCESS[];
extern const char STR_WRITING[];
@@ -836,6 +847,9 @@ extern const char STR_LAYOUT[];
extern const char STR_ADDMAINVIEW[];
extern const char STR_BACKGROUND_COLOR[];
extern const char STR_MAIN_COLOR[];
+extern const char STR_BAR2_COLOR[];
+extern const char STR_BAR1_COLOR[];
+extern const char STR_TEXT_COLOR[];
extern const char STR_TEXT_VIEWER[];
extern const char STR_RFPOWER[];
@@ -848,7 +862,6 @@ extern const char STR_MIN[];
extern const char STR_MAX[];
extern const char STR_CURVE_PRESET[];
extern const char STR_PRESET[];
-extern const char STR_MIRROR[];
extern const char STR_CLEAR[];
extern const char STR_RESET[];
extern const char STR_COUNT[];
@@ -955,6 +968,8 @@ extern const char STR_ABOUT_PARENTS_3[];
extern const char STR_ABOUT_PARENTS_4[];
extern const char STR_AUTH_FAILURE[];
+extern const char STR_PROTOCOL[];
+extern const char STR_RACING_MODE[];
#define CHR_HOUR TR_CHR_HOUR
#define CHR_INPUT TR_CHR_INPUT
diff --git a/radio/src/translations/cz.h.txt b/radio/src/translations/cz.h.txt
index adaa7d30e..f042c994e 100644
--- a/radio/src/translations/cz.h.txt
+++ b/radio/src/translations/cz.h.txt
@@ -231,9 +231,10 @@
#endif
#define TR_SF_SCREENSHOT "Snímek LCD\0"
+#define TR_SF_RACING_MODE "RacingMode\0"
#define TR_SF_RESERVE "[rezerva]\0 "
-#define TR_VFSWFUNC TR_SF_SAFETY "Trenér \0 ""Insta-Trim\0""Reset\0 ""Změna \0 " TR_ADJUST_GVAR "Hlasitost\0 " "SetFailsafe" "RangeCheck\0" "ModuleBind\0" TR_SOUND TR_PLAY_TRACK TR_PLAY_VALUE TR_SF_RESERVE TR_SF_PLAY_SCRIPT TR_SF_RESERVE TR_SF_BG_MUSIC TR_VVARIO TR_HAPTIC TR_SDCLOGS "Podsvětlení" TR_SF_SCREENSHOT TR_SF_TEST
+#define TR_VFSWFUNC TR_SF_SAFETY "Trenér \0 ""Insta-Trim\0""Reset\0 ""Změna \0 " TR_ADJUST_GVAR "Hlasitost\0 " "SetFailsafe" "RangeCheck\0" "ModuleBind\0" TR_SOUND TR_PLAY_TRACK TR_PLAY_VALUE TR_SF_RESERVE TR_SF_PLAY_SCRIPT TR_SF_RESERVE TR_SF_BG_MUSIC TR_VVARIO TR_HAPTIC TR_SDCLOGS "Podsvětlení" TR_SF_SCREENSHOT TR_SF_RACING_MODE TR_SF_TEST
#define LEN_VFSWRESET TR("\004", "\012")
@@ -260,7 +261,7 @@
#define LEN_VUNITSSYSTEM TR("\006", "\010")
#define TR_VUNITSSYSTEM TR("Metr.\0""Imper.", "Metrické""Imperial")
#define LEN_VTELEMUNIT "\003"
-#define TR_VTELEMUNIT "-\0 ""V\0 ""A\0 ""mA\0""kts""m/s""f/s""kmh""mph""m\0 ""ft\0""@C\0""@F\0""%\0 ""mAh""W\0 ""mW\0""dB\0""rpm""g\0 ""@\0 ""rad""ml\0""fOz"
+#define TR_VTELEMUNIT "-\0 ""V\0 ""A\0 ""mA\0""kts""m/s""f/s""kmh""mph""m\0 ""ft\0""@C\0""@F\0""%\0 ""mAh""W\0 ""mW\0""dB\0""rpm""g\0 ""@\0 ""rad""ml\0""fOz""mlm""Hz\0""mS\0""uS\0""km\0"
#define STR_V (STR_VTELEMUNIT+1)
#define STR_A (STR_VTELEMUNIT+4)
@@ -288,9 +289,15 @@
#if defined(PCBHORUS)
#define LEN_VKEYS "\005"
#define TR_VKEYS "PGUP\0""PGDN\0""ENTER""MDL\0 ""RTN\0 ""TELE\0""SYS\0 "
-#elif defined(RADIO_T12)
+#elif defined(RADIO_FAMILY_JUMPER_T12)
#define LEN_VKEYS "\005"
#define TR_VKEYS "Exit\0""Enter""Dolů\0""Nhoru""Vprvo""Vlevo"
+#elif defined(RADIO_TX12)
+ #define LEN_VKEYS "\005"
+ #define TR_VKEYS "Exit\0""Enter""Up\0 ""Down\0""SYS\0 ""MDL\0 ""TELE\0"
+#elif defined(RADIO_T8)
+ #define LEN_VKEYS "\005"
+ #define TR_VKEYS "RTN\0 ""ENTER""PGUP\0""PGDN\0""SYS\0 ""MDL\0 ""UP\0 ""DOWN\0"
#elif defined(PCBTARANIS)
#define LEN_VKEYS "\005"
#define TR_VKEYS "Menu\0""Exit\0""Enter""Page\0""Plus\0""Mínus"
@@ -432,12 +439,13 @@
#define TR_DISPLAY_TRIMS TR3("Číslo v Trm", "Zobr.hodnotu trimu", "Číslo v liště trimu")
#define TR_TTRACE TR("StopaPlynu", INDENT "Stopa plynu")
#define TR_TTRIM TR3("TrimVolnob.", INDENT "Trim jen volnoběh", "Trim jen pro volnoběh")
+#define TR_TTRIM_SW TR("T-Trim-Sw", INDENT "Trim switch")
#define TR_BEEPCTR TR3("Středy \221\222", "Pípat středy \221\222", "Pípat středy")
#define TR_USE_GLOBAL_FUNCS TR("Glob.Funkce", "Použít Glob.Funkce")
#if defined(PCBSKY9X) && defined(REVX)
#define TR_OUTPUT_TYPE INDENT "Výstup"
#endif
-#define TR_PROTO INDENT "Protokol"
+#define TR_PROTOCOL "Protokol"
#define TR_PPMFRAME INDENT "PPM modulace"
#define TR_REFRESHRATE TR(INDENT "Obnovit", INDENT "Obn. frekv.")
#define STR_WARN_BATTVOLTAGE TR(INDENT "Výstup VBAT: ", INDENT "Varování: výstupní hodnota VBAT: ")
@@ -520,6 +528,7 @@
#define TR_BEEPCOUNTDOWN INDENT"Odpočet"
#define TR_PERSISTENT INDENT"Trvalé"
#define TR_BACKLIGHT_LABEL "Podsvětlení"
+#define TR_GHOST_MENU_LABEL "GHOST MENU"
#define TR_BLDELAY INDENT"Zhasnout po"
#define TR_BLONBRIGHTNESS TR3(INDENT"Jas Zap.", INDENT"Jas Zap.", INDENT"Jas zapnutého LCD")
#define TR_BLOFFBRIGHTNESS TR3(INDENT"Jas Vyp.", INDENT"Jas Vyp.", INDENT"Jas vypnutého LCD")
@@ -631,6 +640,7 @@
#define TR_RECEIVER "Přijímač"
#define TR_MULTI_RFTUNE TR(INDENT "Ladění frek", INDENT "Jemné ladění frek. RF")
#define TR_MULTI_RFPOWER "RF power"
+#define TR_MULTI_WBUS "Output"
#define TR_MULTI_TELEMETRY "Telemetrie"
#define TR_MULTI_VIDFREQ TR(INDENT "Freq. videa", INDENT "Frekvence videa")
#define TR_RFPOWER "Výkon RF"
@@ -699,6 +709,7 @@
#define TR_NO_SDCARD "Není SD karta"
#define TR_WAITING_FOR_RX "Čekám na RX..."
#define TR_WAITING_FOR_TX "Čekám na TX..."
+#define TR_WAITING_FOR_MODULE TR("Waiting module", "Waiting for module...")
#define TR_NO_TOOLS TR("Nejsou k dispozici", "Žádné nástroje k dispozici")
#define TR_NORMAL "Normální"
#define TR_NOT_INVERTED "Neinvert"
@@ -774,7 +785,7 @@
#define TR_NO_MODELS_ON_SD "žádný model" BREAKSPACE "na SD"
#define TR_NO_BITMAPS_ON_SD "žádné obrázky" BREAKSPACE "na SD"
#define TR_NO_SCRIPTS_ON_SD "žádný skript" BREAKSPACE "na SD"
-#define TR_SCRIPT_SYNTAX_ERROR "Syntaktická chyba skriptu"
+#define TR_SCRIPT_SYNTAX_ERROR TR("Syntaktická chyba", "Syntaktická chyba skriptu")
#define TR_SCRIPT_PANIC "Script zmaten"
#define TR_SCRIPT_KILLED "Script ukončen"
#define TR_SCRIPT_ERROR "Neznámá chyba"
@@ -820,7 +831,7 @@
#define TR_MENUGLOBALVARS "GLOBÁLNÍ PROMĚNNÉ"
#define TR_OWN " \043 "
#define TR_DATE "Datum"
-#define TR_MONTHS { "Led", "Úno", "Bře", "Dub", "Kvě", "Čer", "Čec", "Srp", "Zář", "Říj", "Lis", "Pro" }
+#define TR_MONTHS { "Led", "Úno", "Bře", "Dub", "Kvě", "Čvn", "Čvc", "Srp", "Zář", "Říj", "Lis", "Pro" }
#define TR_ROTARY_ENCODER "R.Enko"
#define TR_CHANNELS_MONITOR "MONITOR KANÁLU"
#define TR_MIXERS_MONITOR "MONITOR MIXU"
@@ -829,8 +840,10 @@
#define TR_FLASH_BOOTLOADER "Flash bootloaderu"
#define TR_FLASH_EXTERNAL_DEVICE TR("Flash S.Portem", "Flash S.Portem")
#define TR_FLASH_RECEIVER_OTA "Flash příjímače OTA"
-#define TR_FLASH_RECEIVER_OTA_BY_EXTERNAL "Flash RX by ext. OTA"
-#define TR_FLASH_RECEIVER_OTA_BY_INTERNAL "Flash RX by int. OTA"
+#define TR_FLASH_RECEIVER_BY_EXTERNAL_MODULE_OTA "Flash RX by ext. OTA"
+#define TR_FLASH_RECEIVER_BY_INTERNAL_MODULE_OTA "Flash RX by int. OTA"
+#define TR_FLASH_FLIGHT_CONTROLLER_BY_EXTERNAL_MODULE_OTA "Flash FC by ext. OTA"
+#define TR_FLASH_FLIGHT_CONTROLLER_BY_INTERNAL_MODULE_OTA "Flash FC by int. OTA"
#define TR_FLASH_BLUETOOTH_MODULE TR("Flash modulu BT", "Flash modulu Bluetooth")
#define TR_FLASH_POWER_MANAGEMENT_UNIT TR("Flash řízení spotř.", "Flash jednotky řízení spotřeby")
#define TR_CURRENT_VERSION TR("Současná ver. ", "Současná verze: ")
@@ -838,6 +851,7 @@
#define TR_FLASH_INTERNAL_MULTI TR("Flash Int. Multi", "Flash Internal Multi")
#define TR_FLASH_EXTERNAL_MODULE TR("Flash ext. modulu", "Flash externího zařízení")
#define TR_FLASH_EXTERNAL_MULTI TR("Flash Ext. Multi", "Flash External Multi")
+#define TR_FLASH_EXTERNAL_ELRS TR("Flash Ext. ELRS", "Flash External ELRS")
#define TR_FIRMWARE_UPDATE_ERROR TR("Chyba zápisu FW", "Chyba zápisu firmware")
#define TR_FIRMWARE_UPDATE_SUCCESS "Úspěšný zápis FW"
#define TR_WRITING "Zapisuji.."
@@ -1100,10 +1114,18 @@
#define TR_ABOUT_MARTIN_1 "Martin Hotař"
#define TR_ABOUT_MARTIN_2 "Design, Čeština"
-#if defined(PCBTARANIS)
+#if defined(MANUFACTURER_FRSKY)
#define TR_ABOUT_HARDWARE_1 "FrSky"
#define TR_ABOUT_HARDWARE_2 "Vývoj a výroba Hardware"
#define TR_ABOUT_HARDWARE_3 "Přispěvatel firmware"
+#elif defined(MANUFACTURER_RADIOMASTER)
+ #define TR_ABOUT_HARDWARE_1 "Radiomaster"
+ #define TR_ABOUT_HARDWARE_2 "Vývoj a výroba Hardware"
+ #define TR_ABOUT_HARDWARE_3 "Přispěvatel firmware"
+#elif defined(MANUFACTURER_JUMPER)
+ #define TR_ABOUT_HARDWARE_1 "JumperRC"
+ #define TR_ABOUT_HARDWARE_2 "Vývoj a výroba Hardware"
+ #define TR_ABOUT_HARDWARE_3 "Přispěvatel firmware"
#else
#define TR_ABOUT_HARDWARE_1 "Brent Nelson"
#define TR_ABOUT_HARDWARE_2 "Sky9x designer/výrobce"
@@ -1180,6 +1202,9 @@
#define TR_ADDMAINVIEW "Přidat hlavní panel"
#define TR_BACKGROUND_COLOR "Barva pozadí"
#define TR_MAIN_COLOR "Hlavní barva"
+#define TR_BAR2_COLOR "Secondary bar color"
+#define TR_BAR1_COLOR "Main bar color"
+#define TR_TEXT_COLOR "Text color"
#define TR_TEXT_VIEWER "Prohlížeč textu"
#define TR_MENU_INPUTS "\314Vstupy"
@@ -1201,6 +1226,7 @@
#define TR_JITTER_FILTER "ADC Filtr"
#define TR_RTC_CHECK TR("Check RTC", "Check RTC voltage")
#define TR_AUTH_FAILURE "Auth-failure"
+#define TR_RACING_MODE "Racing mode"
#define ZSTR_VFR "VFR"
#define ZSTR_RSSI "RSSI"
@@ -1347,3 +1373,16 @@
#define ZSTR_CL16 "Cl16"
#define ZSTR_CL17 "Cl17"
#define ZSTR_CL18 "Cl18"
+#define ZSTR_FRAME_RATE "FRat"
+#define ZSTR_TOTAL_LATENCY "TLat"
+#define ZSTR_VTX_FREQ "VFrq"
+#define ZSTR_VTX_PWR "VPwr"
+#define ZSTR_VTX_CHAN "VChn"
+#define ZSTR_VTX_BAND "VBan"
+#define ZSTR_SERVO_CURRENT "SrvA"
+#define ZSTR_SERVO_VOLTAGE "SrvV"
+#define ZSTR_SERVO_TEMPERATURE "SrvT"
+#define ZSTR_SERVO_STATUS "SrvS"
+#define ZSTR_LOSS "Loss"
+#define ZSTR_SPEED "Spd "
+#define ZSTR_FLOW "Flow"
diff --git a/radio/src/translations/de.h.txt b/radio/src/translations/de.h.txt
index e6c6eb431..05b377a40 100644
--- a/radio/src/translations/de.h.txt
+++ b/radio/src/translations/de.h.txt
@@ -234,9 +234,10 @@
#endif
#define TR_SF_SCREENSHOT "Screenshot"
+#define TR_SF_RACING_MODE "RacingMode"
#define TR_SF_RESERVE "[Reserve]\0"
-#define TR_VFSWFUNC TR_SF_SAFETY "Lehrer \0 ""Inst. Trim""Rücksetz.\0""Setze \0 " TR_ADJUST_GVAR "Lautstr.\0 " "SetFailsfe" "RangeCheck" "ModuleBind" TR_SOUND TR_PLAY_TRACK TR_PLAY_VALUE TR_SF_RESERVE TR_SF_PLAY_SCRIPT TR_SF_RESERVE TR_SF_BG_MUSIC TR_VVARIO TR_HAPTIC TR_SDCLOGS "LCD Licht\0" TR_SF_SCREENSHOT TR_SF_TEST
+#define TR_VFSWFUNC TR_SF_SAFETY "Lehrer \0 ""Inst. Trim""Rücksetz.\0""Setze \0 " TR_ADJUST_GVAR "Lautstr.\0 " "SetFailsfe" "RangeCheck" "ModuleBind" TR_SOUND TR_PLAY_TRACK TR_PLAY_VALUE TR_SF_RESERVE TR_SF_PLAY_SCRIPT TR_SF_RESERVE TR_SF_BG_MUSIC TR_VVARIO TR_HAPTIC TR_SDCLOGS "LCD Licht\0" TR_SF_SCREENSHOT TR_SF_RACING_MODE TR_SF_TEST
#define LEN_VFSWRESET TR("\004", "\011")
@@ -263,7 +264,7 @@
#define LEN_VUNITSSYSTEM TR("\006", "\012")
#define TR_VUNITSSYSTEM TR("Metrik""Imper.", "Metrisch\0 ""Imperial\0 ")
#define LEN_VTELEMUNIT "\003"
- #define TR_VTELEMUNIT "-\0 ""V\0 ""A\0 ""mA\0""kts""m/s""f/s""kmh""mph""m\0 ""ft\0""@C\0""@F\0""%\0 ""mAh""W\0 ""mW\0""dB\0""rpm""g\0 ""@\0 ""rad""ml\0""fOz"
+ #define TR_VTELEMUNIT "-\0 ""V\0 ""A\0 ""mA\0""kts""m/s""f/s""kmh""mph""m\0 ""ft\0""@C\0""@F\0""%\0 ""mAh""W\0 ""mW\0""dB\0""rpm""g\0 ""@\0 ""rad""ml\0""fOz""mlm""Hz\0""mS\0""uS\0""km\0"
#define STR_V (STR_VTELEMUNIT+1)
#define STR_A (STR_VTELEMUNIT+4)
@@ -294,9 +295,15 @@
#elif defined(PCBXLITE)
#define LEN_VKEYS "\005"
#define TR_VKEYS "Shift""Exit\0""Enter""Down\0""Up\0 ""Right""Left\0"
-#elif defined(RADIO_T12)
+#elif defined(RADIO_FAMILY_JUMPER_T12)
#define LEN_VKEYS "\005"
#define TR_VKEYS "Exit\0""Enter""Down\0""Up\0 ""Right""Left\0"
+#elif defined(RADIO_TX12)
+ #define LEN_VKEYS "\005"
+ #define TR_VKEYS "Exit\0""Enter""Up\0 ""Down\0""SYS\0 ""MDL\0 ""TELE\0"
+#elif defined(RADIO_T8)
+ #define LEN_VKEYS "\005"
+ #define TR_VKEYS "RTN\0 ""ENTER""PGUP\0""PGDN\0""SYS\0 ""MDL\0 ""UP\0 ""DOWN\0"
#elif defined(PCBTARANIS)
#define LEN_VKEYS "\005"
#define TR_VKEYS "Menu\0""Exit\0""Enter""Page\0""Plus\0""Minus"
@@ -434,13 +441,14 @@
#define TR_DISPLAY_TRIMS TR("Trimanzeige", "Trimwerte anzeigen")
#define TR_TTRACE TR("Gasquelle", INDENT "Gas-Timerquelle")
#define TR_TTRIM TR("Gastrim", INDENT "Gas-Leerlauftrim")
+#define TR_TTRIM_SW TR("T-Trim-Sw", INDENT "Trim switch")
#define TR_BEEPCTR TR("MittePieps", "Mittelstell. -Pieps")
#define TR_USE_GLOBAL_FUNCS TR("Glob. Funkt.", "Globale Funkt verw.")
#if defined(PCBSKY9X) && defined(REVX)
#define TR_OUTPUT_TYPE INDENT "Output"
#endif
-#define TR_PROTO TR(INDENT "Protok.", INDENT "Protokoll")
- #define TR_PPMFRAME INDENT "PPM-Frame"
+#define TR_PROTOCOL TR("Protok.", "Protokoll")
+#define TR_PPMFRAME INDENT "PPM-Frame"
#define TR_REFRESHRATE TR(INDENT "Refresh", INDENT "Refresh rate")
#define STR_WARN_BATTVOLTAGE TR(INDENT "Output is VBAT: ", INDENT "Warning: output level is VBAT: ")
#define TR_WARN_5VOLTS "Warning: output level is 5 volts"
@@ -522,6 +530,7 @@
#define TR_BEEPCOUNTDOWN INDENT "Countdown"
#define TR_PERSISTENT TR(INDENT "Permanent", INDENT "Permanent")
#define TR_BACKLIGHT_LABEL "LCD-Beleuchtung"
+#define TR_GHOST_MENU_LABEL "GHOST MENU"
#define TR_BLDELAY INDENT "Dauer"
#define TR_BLONBRIGHTNESS INDENT "An-Helligkeit"
#define TR_BLOFFBRIGHTNESS INDENT "Aus-Helligkeit"
@@ -633,6 +642,7 @@
#define TR_RECEIVER "Empfänger"
#define TR_MULTI_RFTUNE TR(INDENT "RF Freq.", INDENT "RF Freq. Feintuning")
#define TR_MULTI_RFPOWER "RF power"
+#define TR_MULTI_WBUS "Output"
#define TR_MULTI_TELEMETRY "Telemetry"
#define TR_MULTI_VIDFREQ TR(INDENT "Vid. Freq.", INDENT "Video Frequenz")
#define TR_RFPOWER "RF Power"
@@ -701,6 +711,7 @@
#define TR_NO_SDCARD "Keine SD-Karte"
#define TR_WAITING_FOR_RX "Waiting for RX..."
#define TR_WAITING_FOR_TX "Waiting for TX..."
+#define TR_WAITING_FOR_MODULE TR("Waiting module", "Waiting for module...")
#define TR_NO_TOOLS "No tools available"
#define TR_NORMAL "Normal"
#define TR_NOT_INVERTED "Not inv"
@@ -776,7 +787,7 @@
#define TR_NO_MODELS_ON_SD "Kein Modelle" BREAKSPACE "auf SD"
#define TR_NO_BITMAPS_ON_SD "Keine Bitmaps" BREAKSPACE "auf SD"
#define TR_NO_SCRIPTS_ON_SD "Keine Skripte" BREAKSPACE "auf SD"
-#define TR_SCRIPT_SYNTAX_ERROR "Skript Syntaxfehler"
+#define TR_SCRIPT_SYNTAX_ERROR TR("Syntaxfehler", "Skript Syntaxfehler")
#define TR_SCRIPT_PANIC "Skript Panik"
#define TR_SCRIPT_KILLED "Skript beendet"
#define TR_SCRIPT_ERROR "Unbekannter Fehler"
@@ -831,8 +842,10 @@
#define TR_FLASH_BOOTLOADER TR("Flash bootloader","Flash bootloader") //
#define TR_FLASH_EXTERNAL_DEVICE TR("Flash ext. Gerät","Flash externes Gerät")
#define TR_FLASH_RECEIVER_OTA "Flash receiver OTA"
-#define TR_FLASH_RECEIVER_OTA_BY_EXTERNAL "Flash RX by ext. OTA"
-#define TR_FLASH_RECEIVER_OTA_BY_INTERNAL "Flash RX by int. OTA"
+#define TR_FLASH_RECEIVER_BY_EXTERNAL_MODULE_OTA "Flash RX by ext. OTA"
+#define TR_FLASH_RECEIVER_BY_INTERNAL_MODULE_OTA "Flash RX by int. OTA"
+#define TR_FLASH_FLIGHT_CONTROLLER_BY_EXTERNAL_MODULE_OTA "Flash FC by ext. OTA"
+#define TR_FLASH_FLIGHT_CONTROLLER_BY_INTERNAL_MODULE_OTA "Flash FC by int. OTA"
#define TR_FLASH_BLUETOOTH_MODULE TR("Flash BT module", "Flash Bluetoothmodul")
#define TR_FLASH_POWER_MANAGEMENT_UNIT TR("Flash pwr mngt unit", "Flash power management unit")
#define TR_CURRENT_VERSION TR("Current vers. ", "Current version: ")
@@ -840,6 +853,7 @@
#define TR_FLASH_INTERNAL_MULTI TR("Flash Int. Multi", "Flash int. Multimodul")
#define TR_FLASH_EXTERNAL_MODULE TR("Flash ext. mod","Flash ext. Modul")
#define TR_FLASH_EXTERNAL_MULTI TR("Flash Ext. Multi", "Flash ext. Multimodul")
+#define TR_FLASH_EXTERNAL_ELRS TR("Flash Ext. ELRS", "Flash External ELRS")
#define TR_FIRMWARE_UPDATE_ERROR TR("FW update Error","Firmware Updatefehler")
#define TR_FIRMWARE_UPDATE_SUCCESS TR3("Flash successful","Flash successful","Update erfolgreich")
#define TR_WRITING "Schreibe..."
@@ -1053,7 +1067,7 @@
#define TR_LSW_HEADERS_V1 "V1"
#define TR_LSW_HEADERS_V2 "V2"
#define TR_LSW_HEADERS_ANDSW "UND Schalter"
-#define TR_LSW_HEADERS_DURATION "Min Dauer"
+#define TR_LSW_HEADERS_DURATION "Dauer"
#define TR_LSW_HEADERS_DELAY "Verzögerung"
#define TR_GVAR_HEADERS_NAME "Name"
@@ -1107,10 +1121,18 @@
#define TR_ABOUT_MARTIN_1 "Martin Hotar"
#define TR_ABOUT_MARTIN_2 "Grafikdesigner"
-#if defined(PCBTARANIS) || defined(PCBHORUS)
- #define TR_ABOUT_HARDWARE_1 "FrSky"
- #define TR_ABOUT_HARDWARE_2 "Hardware designer/producer"
- #define TR_ABOUT_HARDWARE_3 "Firmware contributor"
+#if defined(MANUFACTURER_FRSKY)
+ #define TR_ABOUT_HARDWARE_1 "FrSky"
+ #define TR_ABOUT_HARDWARE_2 TR("Hardware design/producer", "Hardware designer/producer")
+ #define TR_ABOUT_HARDWARE_3 "Firmware contributor"
+#elif defined(MANUFACTURER_RADIOMASTER)
+ #define TR_ABOUT_HARDWARE_1 "Radiomaster"
+ #define TR_ABOUT_HARDWARE_2 TR("Hardware design/producer", "Hardware designer/producer")
+ #define TR_ABOUT_HARDWARE_3 "Firmware contributor"
+#elif defined(MANUFACTURER_JUMPER)
+ #define TR_ABOUT_HARDWARE_1 "JumperRC"
+ #define TR_ABOUT_HARDWARE_2 TR("Hardware design/producer", "Hardware designer/producer")
+ #define TR_ABOUT_HARDWARE_3 "Firmware contributor"
#else
#define TR_ABOUT_HARDWARE_1 "Brent Nelson"
#define TR_ABOUT_HARDWARE_2 "Sky9x designer/producer"
@@ -1186,6 +1208,9 @@
#define TR_ADDMAINVIEW "Ansicht hinzufügen"
#define TR_BACKGROUND_COLOR "Hintergrundfarbe"
#define TR_MAIN_COLOR "Hauptfarbe"
+#define TR_BAR2_COLOR "Secondary bar color"
+#define TR_BAR1_COLOR "Main bar color"
+#define TR_TEXT_COLOR "Text color"
#define TR_TEXT_VIEWER "Text Viewer"
// ----------------------------- Symbole für Auswahlliste----------
#define TR_MENU_INPUTS "\314Inputs"
@@ -1207,6 +1232,7 @@
#define TR_JITTER_FILTER "ADC Filter"
#define TR_RTC_CHECK TR("Check RTC", "Check RTC voltage")
#define TR_AUTH_FAILURE "Auth-failure"
+#define TR_RACING_MODE "Racing mode"
// ----------------------------------------------------------------
#define ZSTR_VFR "VFR"
@@ -1354,3 +1380,16 @@
#define ZSTR_CL16 "Cl16"
#define ZSTR_CL17 "Cl17"
#define ZSTR_CL18 "Cl18"
+#define ZSTR_FRAME_RATE "FRat"
+#define ZSTR_TOTAL_LATENCY "TLat"
+#define ZSTR_VTX_FREQ "VFrq"
+#define ZSTR_VTX_PWR "VPwr"
+#define ZSTR_VTX_CHAN "VChn"
+#define ZSTR_VTX_BAND "VBan"
+#define ZSTR_SERVO_CURRENT "SrvA"
+#define ZSTR_SERVO_VOLTAGE "SrvV"
+#define ZSTR_SERVO_TEMPERATURE "SrvT"
+#define ZSTR_SERVO_STATUS "SrvS"
+#define ZSTR_LOSS "Loss"
+#define ZSTR_SPEED "Spd "
+#define ZSTR_FLOW "Flow"
diff --git a/radio/src/translations/en.h.txt b/radio/src/translations/en.h.txt
index 706197f33..7abf4a509 100644
--- a/radio/src/translations/en.h.txt
+++ b/radio/src/translations/en.h.txt
@@ -234,9 +234,10 @@
#endif
#define TR_SF_SCREENSHOT "Screenshot"
+#define TR_SF_RACING_MODE "RacingMode"
#define TR_SF_RESERVE "[reserve]\0"
-#define TR_VFSWFUNC TR_SF_SAFETY "Trainer\0 ""Inst. Trim""Reset\0 ""Set \0 " TR_ADJUST_GVAR "Volume\0 " "SetFailsfe" "RangeCheck" "ModuleBind" TR_SOUND TR_PLAY_TRACK TR_PLAY_VALUE TR_SF_RESERVE TR_SF_PLAY_SCRIPT TR_SF_RESERVE TR_SF_BG_MUSIC TR_VVARIO TR_HAPTIC TR_SDCLOGS "Backlight\0" TR_SF_SCREENSHOT TR_SF_TEST
+#define TR_VFSWFUNC TR_SF_SAFETY "Trainer\0 ""Inst. Trim""Reset\0 ""Set \0 " TR_ADJUST_GVAR "Volume\0 " "SetFailsfe" "RangeCheck" "ModuleBind" TR_SOUND TR_PLAY_TRACK TR_PLAY_VALUE TR_SF_RESERVE TR_SF_PLAY_SCRIPT TR_SF_RESERVE TR_SF_BG_MUSIC TR_VVARIO TR_HAPTIC TR_SDCLOGS "Backlight\0" TR_SF_SCREENSHOT TR_SF_RACING_MODE TR_SF_TEST
#define LEN_VFSWRESET TR("\004", "\011")
@@ -263,7 +264,7 @@
#define LEN_VUNITSSYSTEM TR("\006", "\010")
#define TR_VUNITSSYSTEM TR("Metric""Imper.", "Metric\0 ""Imperial")
#define LEN_VTELEMUNIT "\003"
-#define TR_VTELEMUNIT "-\0 ""V\0 ""A\0 ""mA\0""kts""m/s""f/s""kmh""mph""m\0 ""ft\0""@C\0""@F\0""%\0 ""mAh""W\0 ""mW\0""dB\0""rpm""g\0 ""@\0 ""rad""ml\0""fOz""mlm"
+#define TR_VTELEMUNIT "-\0 ""V\0 ""A\0 ""mA\0""kts""m/s""f/s""kmh""mph""m\0 ""ft\0""@C\0""@F\0""%\0 ""mAh""W\0 ""mW\0""dB\0""rpm""g\0 ""@\0 ""rad""ml\0""fOz""mlm""Hz\0""mS\0""uS\0""km\0"
#define STR_V (STR_VTELEMUNIT+1)
#define STR_A (STR_VTELEMUNIT+4)
@@ -294,9 +295,15 @@
#elif defined(PCBXLITE)
#define LEN_VKEYS "\005"
#define TR_VKEYS "Shift""Exit\0""Enter""Down\0""Up\0 ""Right""Left\0"
-#elif defined(RADIO_T12)
+#elif defined(RADIO_FAMILY_JUMPER_T12)
#define LEN_VKEYS "\005"
#define TR_VKEYS "Exit\0""Enter""Down\0""Up\0 ""Right""Left\0"
+#elif defined(RADIO_TX12)
+ #define LEN_VKEYS "\005"
+ #define TR_VKEYS "Exit\0""Enter""Up\0 ""Down\0""SYS\0 ""MDL\0 ""TELE\0"
+#elif defined(RADIO_T8)
+ #define LEN_VKEYS "\005"
+ #define TR_VKEYS "RTN\0 ""ENTER""PGUP\0""PGDN\0""SYS\0 ""MDL\0 ""UP\0 ""DOWN\0"
#elif defined(PCBTARANIS)
#define LEN_VKEYS "\005"
#define TR_VKEYS "Menu\0""Exit\0""Enter""Page\0""Plus\0""Minus"
@@ -432,13 +439,14 @@
#define TR_TRIMINC "Trim Step"
#define TR_DISPLAY_TRIMS TR("Show Trims", "Display trims")
#define TR_TTRACE TR("T-Source", INDENT "Source")
-#define TR_TTRIM TR("T-Trim", INDENT "Trim idle only")
+#define TR_TTRIM TR("T-Trim-Idle", INDENT "Trim idle only")
+#define TR_TTRIM_SW TR("T-Trim-Sw", INDENT "Trim switch")
#define TR_BEEPCTR TR("Ctr Beep", "Center Beep")
#define TR_USE_GLOBAL_FUNCS TR("Glob.Funcs", "Use global funcs")
#if defined(PCBSKY9X) && defined(REVX)
#define TR_OUTPUT_TYPE INDENT "Output"
#endif
-#define TR_PROTO TR(INDENT "Proto", INDENT "Protocol")
+#define TR_PROTOCOL TR("Proto", "Protocol")
#define TR_PPMFRAME INDENT "PPM frame"
#define TR_REFRESHRATE TR(INDENT "Refresh", INDENT "Refresh rate")
#define STR_WARN_BATTVOLTAGE TR(INDENT "Output is VBAT: ", INDENT "Warning: output level is VBAT: ")
@@ -521,6 +529,7 @@
#define TR_BEEPCOUNTDOWN INDENT "Countdown"
#define TR_PERSISTENT TR(INDENT "Persist.", INDENT "Persistent")
#define TR_BACKLIGHT_LABEL "Backlight"
+#define TR_GHOST_MENU_LABEL "GHOST MENU"
#define TR_BLDELAY INDENT "Duration"
#define TR_BLONBRIGHTNESS INDENT "ON brightness"
#define TR_BLOFFBRIGHTNESS INDENT "OFF brightness"
@@ -632,6 +641,7 @@
#define TR_RECEIVER "Receiver"
#define TR_MULTI_RFTUNE TR("Freq tune", "RF Freq. fine tune")
#define TR_MULTI_RFPOWER "RF power"
+#define TR_MULTI_WBUS "Output"
#define TR_MULTI_TELEMETRY "Telemetry"
#define TR_MULTI_VIDFREQ TR("Vid. freq.", "Video frequency")
#define TR_RFPOWER "RF Power"
@@ -705,6 +715,7 @@
#define TR_NO_SDCARD "No SD card"
#define TR_WAITING_FOR_RX "Waiting for RX..."
#define TR_WAITING_FOR_TX "Waiting for TX..."
+#define TR_WAITING_FOR_MODULE TR("Waiting module", "Waiting for module...")
#define TR_NO_TOOLS "No tools available"
#define TR_NORMAL "Normal"
#define TR_NOT_INVERTED "Not inv"
@@ -780,7 +791,7 @@
#define TR_NO_MODELS_ON_SD "No models" BREAKSPACE "on SD"
#define TR_NO_BITMAPS_ON_SD "No bitmaps" BREAKSPACE "on SD"
#define TR_NO_SCRIPTS_ON_SD "No scripts" BREAKSPACE "on SD"
-#define TR_SCRIPT_SYNTAX_ERROR "Script syntax error"
+#define TR_SCRIPT_SYNTAX_ERROR TR("Syntax error", "Script syntax error")
#define TR_SCRIPT_PANIC "Script panic"
#define TR_SCRIPT_KILLED "Script killed"
#define TR_SCRIPT_ERROR "Unknown error"
@@ -835,8 +846,10 @@
#define TR_FLASH_BOOTLOADER "Flash bootloader"
#define TR_FLASH_EXTERNAL_DEVICE TR("Flash S.Port", "Flash S.Port device")
#define TR_FLASH_RECEIVER_OTA "Flash receiver OTA"
-#define TR_FLASH_RECEIVER_OTA_BY_EXTERNAL "Flash RX by ext. OTA"
-#define TR_FLASH_RECEIVER_OTA_BY_INTERNAL "Flash RX by int. OTA"
+#define TR_FLASH_RECEIVER_BY_EXTERNAL_MODULE_OTA "Flash RX by ext. OTA"
+#define TR_FLASH_RECEIVER_BY_INTERNAL_MODULE_OTA "Flash RX by int. OTA"
+#define TR_FLASH_FLIGHT_CONTROLLER_BY_EXTERNAL_MODULE_OTA "Flash FC by ext. OTA"
+#define TR_FLASH_FLIGHT_CONTROLLER_BY_INTERNAL_MODULE_OTA "Flash FC by int. OTA"
#define TR_FLASH_BLUETOOTH_MODULE TR("Flash BT module", "Flash Bluetooth module")
#define TR_FLASH_POWER_MANAGEMENT_UNIT "Flash pwr mngt unit"
#define TR_CURRENT_VERSION TR("Curr Vers: ", "Current version: ")
@@ -844,6 +857,7 @@
#define TR_FLASH_INTERNAL_MULTI TR("Flash Int. Multi", "Flash Internal Multi")
#define TR_FLASH_EXTERNAL_MODULE TR("Flash ext. module", "Flash external module")
#define TR_FLASH_EXTERNAL_MULTI TR("Flash Ext. Multi", "Flash External Multi")
+#define TR_FLASH_EXTERNAL_ELRS TR("Flash Ext. ELRS", "Flash External ELRS")
#define TR_FIRMWARE_UPDATE_ERROR TR("FW update error", "Firmware update error")
#define TR_FIRMWARE_UPDATE_SUCCESS "Flash successful"
#define TR_WRITING "Writing..."
@@ -925,7 +939,7 @@
#define TR_DEL_BUTTON BUTTON(TR("Del", "Delete"))
#define TR_RESET_BTN BUTTON("Reset")
#define TR_DEBUG "Debug"
-#define TR_KEYS_BTN BUTTON(TR("Keys", "Switches"))
+#define TR_KEYS_BTN BUTTON("Keys")
#define TR_ANALOGS_BTN BUTTON(TR("Anas", "Analogs"))
#define TR_TOUCH_NOTFOUND "Touch hardware not found"
#define TR_TOUCH_EXIT "Touch screen to exit"
@@ -1034,7 +1048,7 @@
#define TR_LSW_HEADERS_V1 "V1"
#define TR_LSW_HEADERS_V2 "V2"
#define TR_LSW_HEADERS_ANDSW "AND Switch"
-#define TR_LSW_HEADERS_DURATION "Min Duration"
+#define TR_LSW_HEADERS_DURATION "Duration"
#define TR_LSW_HEADERS_DELAY "Delay"
#define TR_GVAR_HEADERS_NAME "Name"
@@ -1105,10 +1119,18 @@
#define TR_ABOUT_MARTIN_1 "Martin Hotar"
#define TR_ABOUT_MARTIN_2 "Graphics designer"
-#if defined(PCBTARANIS) || defined(PCBHORUS)
+#if defined(MANUFACTURER_FRSKY)
#define TR_ABOUT_HARDWARE_1 "FrSky"
#define TR_ABOUT_HARDWARE_2 TR("Hardware design/producer", "Hardware designer/producer")
#define TR_ABOUT_HARDWARE_3 "Firmware contributor"
+#elif defined(MANUFACTURER_RADIOMASTER)
+ #define TR_ABOUT_HARDWARE_1 "Radiomaster"
+ #define TR_ABOUT_HARDWARE_2 TR("Hardware design/producer", "Hardware designer/producer")
+ #define TR_ABOUT_HARDWARE_3 "Firmware contributor"
+#elif defined(MANUFACTURER_JUMPER)
+ #define TR_ABOUT_HARDWARE_1 "JumperRC"
+ #define TR_ABOUT_HARDWARE_2 TR("Hardware design/producer", "Hardware designer/producer")
+ #define TR_ABOUT_HARDWARE_3 "Firmware contributor"
#else
#define TR_ABOUT_HARDWARE_1 "Brent Nelson"
#define TR_ABOUT_HARDWARE_2 "Sky9x designer/producer"
@@ -1184,6 +1206,9 @@
#define TR_ADDMAINVIEW "Add main view"
#define TR_BACKGROUND_COLOR "Background color"
#define TR_MAIN_COLOR "Main color"
+#define TR_BAR2_COLOR "Secondary bar color"
+#define TR_BAR1_COLOR "Main bar color"
+#define TR_TEXT_COLOR "Text color"
#define TR_TEXT_VIEWER "Text Viewer"
#define TR_MENU_INPUTS "\314Inputs"
@@ -1205,6 +1230,7 @@
#define TR_JITTER_FILTER "ADC filter"
#define TR_RTC_CHECK TR("Check RTC", "Check RTC voltage")
#define TR_AUTH_FAILURE "Auth-failure"
+#define TR_RACING_MODE "Racing mode"
#define ZSTR_VFR "VFR"
#define ZSTR_RSSI "RSSI"
@@ -1351,3 +1377,16 @@
#define ZSTR_CL16 "Cl16"
#define ZSTR_CL17 "Cl17"
#define ZSTR_CL18 "Cl18"
+#define ZSTR_FRAME_RATE "FRat"
+#define ZSTR_TOTAL_LATENCY "TLat"
+#define ZSTR_VTX_FREQ "VFrq"
+#define ZSTR_VTX_PWR "VPwr"
+#define ZSTR_VTX_CHAN "VChn"
+#define ZSTR_VTX_BAND "VBan"
+#define ZSTR_SERVO_CURRENT "SrvA"
+#define ZSTR_SERVO_VOLTAGE "SrvV"
+#define ZSTR_SERVO_TEMPERATURE "SrvT"
+#define ZSTR_SERVO_STATUS "SrvS"
+#define ZSTR_LOSS "Loss"
+#define ZSTR_SPEED "Spd "
+#define ZSTR_FLOW "Flow"
diff --git a/radio/src/translations/es.h.txt b/radio/src/translations/es.h.txt
index 714fcc217..6d19f41df 100644
--- a/radio/src/translations/es.h.txt
+++ b/radio/src/translations/es.h.txt
@@ -231,10 +231,11 @@
#define TR_SF_SAFETY "---\0 "
#endif
-#define TR_SF_SCREENSHOT "Captura"
+#define TR_SF_SCREENSHOT "Captura\0 "
+#define TR_SF_RACING_MODE "RacingMode"
#define TR_SF_RESERVE "[reserv.]\0"
-#define TR_VFSWFUNC TR_SF_SAFETY "Entrenador""Inst. Trim""Reset\0 ""Ajuste \0 " TR_ADJUST_GVAR "Volumen\0 " "Failsafe\0 " "CheckRango" "Enl.módulo" TR_SOUND TR_PLAY_TRACK TR_PLAY_VALUE TR_SF_RESERVE TR_SF_PLAY_SCRIPT TR_SF_RESERVE TR_SF_BG_MUSIC TR_VVARIO TR_HAPTIC TR_SDCLOGS "Luz Fondo\0" TR_SF_SCREENSHOT TR_SF_TEST
+#define TR_VFSWFUNC TR_SF_SAFETY "Entrenador""Inst. Trim""Reset\0 ""Ajuste \0 " TR_ADJUST_GVAR "Volumen\0 " "Failsafe\0 " "CheckRango" "Enl.módulo" TR_SOUND TR_PLAY_TRACK TR_PLAY_VALUE TR_SF_RESERVE TR_SF_PLAY_SCRIPT TR_SF_RESERVE TR_SF_BG_MUSIC TR_VVARIO TR_HAPTIC TR_SDCLOGS "Luz Fondo\0" TR_SF_SCREENSHOT TR_SF_RACING_MODE TR_SF_TEST
#define LEN_VFSWRESET TR("\004", "\012")
#define TR_FSW_RESET_TELEM TR("Telm", "Telemetría")
@@ -260,7 +261,7 @@
#define LEN_VUNITSSYSTEM "\010"
#define TR_VUNITSSYSTEM "Métrico\0""Imperial"
#define LEN_VTELEMUNIT "\003"
-#define TR_VTELEMUNIT "-\0 ""V\0 ""A\0 ""mA\0""kts""m/s""f/s""kmh""mph""m\0 ""ft\0""@C\0""@F\0""%\0 ""mAh""W\0 ""mW\0""dB\0""rpm""g\0 ""@\0 ""rad""ml\0""fOz"
+#define TR_VTELEMUNIT "-\0 ""V\0 ""A\0 ""mA\0""kts""m/s""f/s""kmh""mph""m\0 ""ft\0""@C\0""@F\0""%\0 ""mAh""W\0 ""mW\0""dB\0""rpm""g\0 ""@\0 ""rad""ml\0""fOz""mlm""Hz\0""mS\0""uS\0""km\0"
#define STR_V (STR_VTELEMUNIT+1)
#define STR_A (STR_VTELEMUNIT+4)
@@ -291,9 +292,15 @@
#elif defined(PCBXLITE)
#define LEN_VKEYS "\005"
#define TR_VKEYS "Shift""Exit\0""Enter""Down\0""Up\0 ""Right""Left\0"
-#elif defined(RADIO_T12)
+#elif defined(RADIO_FAMILY_JUMPER_T12)
#define LEN_VKEYS "\005"
#define TR_VKEYS "Exit\0""Enter""Down\0""Up\0 ""Right""Left\0"
+#elif defined(RADIO_TX12)
+ #define LEN_VKEYS "\005"
+ #define TR_VKEYS "Exit\0""Enter""Up\0 ""Down\0""SYS\0 ""MDL\0 ""TELE\0"
+#elif defined(RADIO_T8)
+ #define LEN_VKEYS "\005"
+ #define TR_VKEYS "RTN\0 ""ENTER""PGUP\0""PGDN\0""SYS\0 ""MDL\0 ""UP\0 ""DOWN\0"
#elif defined(PCBTARANIS)
#define LEN_VKEYS "\005"
#define TR_VKEYS "Menu\0""Exit\0""Enter""Page\0""Plus\0""Minus"
@@ -432,16 +439,17 @@
#define TR_DISPLAY_TRIMS "Ver trims"
#define TR_TTRACE TR("Fuente-A", INDENT "Fuente acelerador")
#define TR_TTRIM TR("Trim-A", INDENT "Trim acelerador")
+#define TR_TTRIM_SW TR("T-Trim-Sw", INDENT "Trim switch")
#define TR_BEEPCTR TR("Beep ctr", "Beep centro")
#define TR_USE_GLOBAL_FUNCS TR("Funcs. glob.", "Usar func. globales")
#if defined(PCBSKY9X) && defined(REVX)
#define TR_OUTPUT_TYPE INDENT "Output"
#endif
-#define TR_PROTO TR(INDENT"Proto",INDENT"Protocolo")
-#define TR_PPMFRAME "Trama PPM"
+#define TR_PROTOCOL TR("Proto", "Protocolo")
+#define TR_PPMFRAME INDENT "Trama PPM"
#define TR_REFRESHRATE TR(INDENT "Refresco", INDENT "Velocidad refresco")
#define STR_WARN_BATTVOLTAGE TR(INDENT "Salida es VBAT: ", INDENT "Aviso: señal salida es VBAT: ")
-#define TR_WARN_5VOLTS "Warning: output level is 5 volts"
+#define TR_WARN_5VOLTS "Aviso: nivel de salida 5 voltios"
#define TR_MS "ms"
#define TR_FREQUENCY INDENT "Frequencia"
#define TR_SWITCH TR("Interr.", "Interruptor")
@@ -520,6 +528,7 @@
#define TR_BEEPCOUNTDOWN TR(INDENT"Cta. atrás", INDENT"Cuenta atrás")
#define TR_PERSISTENT TR(INDENT"Persisten.", INDENT"Persistente")
#define TR_BACKLIGHT_LABEL "Luz fondo"
+#define TR_GHOST_MENU_LABEL "GHOST MENU"
#define TR_BLDELAY INDENT"Duración"
#define TR_BLONBRIGHTNESS INDENT"MAS brillo"
#define TR_BLOFFBRIGHTNESS INDENT"MENOS brillo"
@@ -634,6 +643,7 @@
#define TR_RECEIVER "Receptor"
#define TR_MULTI_RFTUNE TR("Sint.freq.", "RF Freq. sint.fina")
#define TR_MULTI_RFPOWER "RF power"
+#define TR_MULTI_WBUS "Output"
#define TR_MULTI_TELEMETRY "Telemetría"
#define TR_MULTI_VIDFREQ TR("Freq.vídeo", "Frecuencia vídeo")
#define TR_RFPOWER "RF Power"
@@ -702,6 +712,7 @@
#define TR_NO_SDCARD "No SDCARD"
#define TR_WAITING_FOR_RX "Esperando a RX..."
#define TR_WAITING_FOR_TX "Esperando a TX..."
+#define TR_WAITING_FOR_MODULE TR("Waiting module", "Waiting for module...")
#define TR_NO_TOOLS "No hay utils"
#define TR_NORMAL "Normal"
#define TR_NOT_INVERTED "No inv"
@@ -777,7 +788,7 @@
#define TR_NO_MODELS_ON_SD "Sin modelos en SD"
#define TR_NO_BITMAPS_ON_SD "Sin imágenes en SD"
#define TR_NO_SCRIPTS_ON_SD "No scripts en SD"
-#define TR_SCRIPT_SYNTAX_ERROR "Script syntax error"
+#define TR_SCRIPT_SYNTAX_ERROR TR("Syntax error", "Script syntax error")
#define TR_SCRIPT_PANIC "Script panic"
#define TR_SCRIPT_KILLED "Script killed"
#define TR_SCRIPT_ERROR "Error desconocido"
@@ -832,8 +843,10 @@
#define TR_FLASH_BOOTLOADER "Flash bootloader"
#define TR_FLASH_EXTERNAL_DEVICE "Flash disp. externo"
#define TR_FLASH_RECEIVER_OTA "Flash RX OTA"
-#define TR_FLASH_RECEIVER_OTA_BY_EXTERNAL "Flash RX por ext. OTA"
-#define TR_FLASH_RECEIVER_OTA_BY_INTERNAL "Flash RX por int. OTA"
+#define TR_FLASH_RECEIVER_BY_EXTERNAL_MODULE_OTA "Flash RX por ext. OTA"
+#define TR_FLASH_RECEIVER_BY_INTERNAL_MODULE_OTA "Flash RX por int. OTA"
+#define TR_FLASH_FLIGHT_CONTROLLER_BY_EXTERNAL_MODULE_OTA "Flash FC by ext. OTA"
+#define TR_FLASH_FLIGHT_CONTROLLER_BY_INTERNAL_MODULE_OTA "Flash FC by int. OTA"
#define TR_FLASH_BLUETOOTH_MODULE TR("Flash módulo BT", "Flash módulo bluetooth")
#define TR_FLASH_POWER_MANAGEMENT_UNIT "Flash unid. pwr mngt"
#define TR_CURRENT_VERSION TR("Vers. actual", "Versión actual: ")
@@ -841,6 +854,7 @@
#define TR_FLASH_INTERNAL_MULTI TR("Flash Multi int", "Flash Multi interno")
#define TR_FLASH_EXTERNAL_MODULE TR("Flash módulo ext", "Flash módulo externo")
#define TR_FLASH_EXTERNAL_MULTI TR("Flash Multi ext", "Flash Multi externo")
+#define TR_FLASH_EXTERNAL_ELRS TR("Flash Ext. ELRS", "Flash External ELRS")
#define TR_FIRMWARE_UPDATE_ERROR TR("Error act FW", "Error actualiz. firmware")
#define TR_FIRMWARE_UPDATE_SUCCESS "Flash ok"
#define TR_WRITING "Escribiendo..."
@@ -924,8 +938,8 @@
#define TR_DEBUG "Debug"
#define TR_KEYS_BTN BUTTON(TR("SW","Switches"))
#define TR_ANALOGS_BTN BUTTON(TR("Analog","Analogs"))
-#define TR_TOUCH_NOTFOUND "Touch hardware not found"
-#define TR_TOUCH_EXIT "Touch screen to exit"
+#define TR_TOUCH_NOTFOUND "Hardware táctil no encontrado"
+#define TR_TOUCH_EXIT "Tocar pantalla para salir"
#define TR_CALIBRATION "Calibración"
#define TR_SET "[Ajuste]"
#define TR_TRAINER "Entrenador"
@@ -941,8 +955,8 @@
#define TR_UNIT "Unidad"
#define TR_TELEMETRY_NEWSENSOR INDENT "Añadir sensor..."
#define TR_CHANNELRANGE INDENT "Canales"
-#define TR_AFHDS3_RX_FREQ TR("RX freq.", "RX frequency")
-#define TR_AFHDS3_ONE_TO_ONE_TELEMETRY TR("Unicast/Tel.", "Unicast/Telemetry")
+#define TR_AFHDS3_RX_FREQ TR("RX freq.", "RX frequencia")
+#define TR_AFHDS3_ONE_TO_ONE_TELEMETRY TR("Unicast/Tel.", "Unicast/Telemetría")
#define TR_AFHDS3_ONE_TO_MANY "Multicast"
#define TR_AFHDS3_ACTUAL_POWER TR("Act. pow", "Actual power")
#define TR_AFHDS3_POWER_SOURCE TR("Power src.", "Power source")
@@ -1006,7 +1020,7 @@
#define LEN_SPORT_UPDATE_POWER_MODES "\004"
#define TR_SPORT_UPDATE_POWER_MODES "AUTO""ON\0 "
#define TR_NO_TELEMETRY_SCREENS TR("No hay pant. telemetría", "No hay pantallas de telemetría")
-#define TR_TOUCH_PANEL "Touch panel:"
+#define TR_TOUCH_PANEL "Pantalla táctil:"
// Horus and Taranis column headers
#define TR_PHASES_HEADERS_NAME "Nombre"
@@ -1104,10 +1118,18 @@
#define TR_ABOUT_MARTIN_1 "Martin Hotar"
#define TR_ABOUT_MARTIN_2 "Dise\201o gráfico"
-#if defined(PCBTARANIS)
+#if defined(MANUFACTURER_FRSKY)
#define TR_ABOUT_HARDWARE_1 "FrSky"
#define TR_ABOUT_HARDWARE_2 "Productor dise\201o de hardware"
#define TR_ABOUT_HARDWARE_3 "Colaborador firmware"
+#elif defined(MANUFACTURER_RADIOMASTER)
+ #define TR_ABOUT_HARDWARE_1 "Radiomaster"
+ #define TR_ABOUT_HARDWARE_2 "Productor dise\201o de hardware"
+ #define TR_ABOUT_HARDWARE_3 "Colaborador firmware"
+#elif defined(MANUFACTURER_JUMPER)
+ #define TR_ABOUT_HARDWARE_1 "JumperRC"
+ #define TR_ABOUT_HARDWARE_2 "Productor dise\201o de hardware"
+ #define TR_ABOUT_HARDWARE_3 "Colaborador firmware"
#else
#define TR_ABOUT_HARDWARE_1 "Brent Nelson"
#define TR_ABOUT_HARDWARE_2 "Sky9x dise\201ador/productor"
@@ -1183,6 +1205,9 @@
#define TR_ADDMAINVIEW "Añadir vista pral."
#define TR_BACKGROUND_COLOR "Color de fondo"
#define TR_MAIN_COLOR "Color principal"
+#define TR_BAR2_COLOR "Color barra secundaria"
+#define TR_BAR1_COLOR "Color barra principal"
+#define TR_TEXT_COLOR "Color texto"
#define TR_TEXT_VIEWER "Visor de texto"
#define TR_MENU_INPUTS "\314Entradas"
@@ -1204,6 +1229,7 @@
#define TR_JITTER_FILTER "Filtro ADC"
#define TR_RTC_CHECK TR("Check RTC", "Check RTC voltaje")
#define TR_AUTH_FAILURE "Fallo " LCDW_128_480_LINEBREAK "autentificación"
+#define TR_RACING_MODE "Racing mode"
#define ZSTR_VFR "VFR"
#define ZSTR_RSSI "RSSI"
@@ -1349,4 +1375,17 @@
#define ZSTR_CL15 "Cl15"
#define ZSTR_CL16 "Cl16"
#define ZSTR_CL17 "Cl17"
-#define ZSTR_CL18 "Cl18"
\ No newline at end of file
+#define ZSTR_CL18 "Cl18"
+#define ZSTR_FRAME_RATE "FRat"
+#define ZSTR_TOTAL_LATENCY "TLat"
+#define ZSTR_VTX_FREQ "VFrq"
+#define ZSTR_VTX_PWR "VPwr"
+#define ZSTR_VTX_CHAN "VChn"
+#define ZSTR_VTX_BAND "VBan"
+#define ZSTR_SERVO_CURRENT "SrvA"
+#define ZSTR_SERVO_VOLTAGE "SrvV"
+#define ZSTR_SERVO_TEMPERATURE "SrvT"
+#define ZSTR_SERVO_STATUS "SrvS"
+#define ZSTR_LOSS "Loss"
+#define ZSTR_SPEED "Spd "
+#define ZSTR_FLOW "Flow"
diff --git a/radio/src/translations/fi.h.txt b/radio/src/translations/fi.h.txt
index 90ce833cb..1e31139b1 100644
--- a/radio/src/translations/fi.h.txt
+++ b/radio/src/translations/fi.h.txt
@@ -235,9 +235,10 @@
#endif
#define TR_SF_SCREENSHOT "Screenshot"
+#define TR_SF_RACING_MODE "RacingMode"
#define TR_SF_RESERVE "[reserve]\0"
-#define TR_VFSWFUNC TR_SF_SAFETY "Trainer\0 ""Inst. Trim""Reset\0 ""Set \0 " TR_ADJUST_GVAR "Volume\0 " "SetFailsfe" "RangeCheck" "ModuleBind" TR_SOUND TR_PLAY_TRACK TR_PLAY_VALUE TR_SF_RESERVE TR_SF_PLAY_SCRIPT TR_SF_RESERVE TR_SF_BG_MUSIC TR_VVARIO TR_HAPTIC TR_SDCLOGS "Backlight\0" TR_SF_SCREENSHOT TR_SF_TEST
+#define TR_VFSWFUNC TR_SF_SAFETY "Trainer\0 ""Inst. Trim""Reset\0 ""Set \0 " TR_ADJUST_GVAR "Volume\0 " "SetFailsfe" "RangeCheck" "ModuleBind" TR_SOUND TR_PLAY_TRACK TR_PLAY_VALUE TR_SF_RESERVE TR_SF_PLAY_SCRIPT TR_SF_RESERVE TR_SF_BG_MUSIC TR_VVARIO TR_HAPTIC TR_SDCLOGS "Backlight\0" TR_SF_SCREENSHOT TR_SF_RACING_MODE TR_SF_TEST
#define LEN_VFSWRESET TR("\004", "\011")
@@ -281,7 +282,7 @@
#define LEN_VUNITSSYSTEM TR("\006", "\010")
#define TR_VUNITSSYSTEM TR("Metric""Imper.", "Metric\0 ""Imperial")
#define LEN_VTELEMUNIT "\003"
-#define TR_VTELEMUNIT "-\0 ""V\0 ""A\0 ""mA\0""kts""m/s""f/s""kmh""mph""m\0 ""ft\0""@C\0""@F\0""%\0 ""mAh""W\0 ""mW\0""dB\0""rpm""g\0 ""@\0 ""rad""ml\0""fOz"
+#define TR_VTELEMUNIT "-\0 ""V\0 ""A\0 ""mA\0""kts""m/s""f/s""kmh""mph""m\0 ""ft\0""@C\0""@F\0""%\0 ""mAh""W\0 ""mW\0""dB\0""rpm""g\0 ""@\0 ""rad""ml\0""fOz""mlm""Hz\0""mS\0""uS\0""km\0"
#define STR_V (STR_VTELEMUNIT+1)
#define STR_A (STR_VTELEMUNIT+4)
@@ -312,9 +313,15 @@
#elif defined(PCBXLITE)
#define LEN_VKEYS "\005"
#define TR_VKEYS "Shift""Exit\0""Enter""Down\0""Up\0 ""Right""Left\0"
-#elif defined(RADIO_T12)
+#elif defined(RADIO_FAMILY_JUMPER_T12)
#define LEN_VKEYS "\005"
#define TR_VKEYS "Exit\0""Enter""Down\0""Up\0 ""Right""Left\0"
+#elif defined(RADIO_TX12)
+ #define LEN_VKEYS "\005"
+ #define TR_VKEYS "Exit\0""Enter""Up\0 ""Down\0""SYS\0 ""MDL\0 ""TELE\0"
+#elif defined(RADIO_T8)
+ #define LEN_VKEYS "\005"
+ #define TR_VKEYS "RTN\0 ""ENTER""PGUP\0""PGDN\0""SYS\0 ""MDL\0 ""UP\0 ""DOWN\0"
#elif defined(PCBTARANIS)
#define LEN_VKEYS "\005"
#define TR_VKEYS "Menu\0""Exit\0""Enter""Page\0""Plus\0""Minus"
@@ -446,12 +453,13 @@
#define TR_DISPLAY_TRIMS "Display Trims"
#define TR_TTRACE TR("T-Source", INDENT "Throttle Source")
#define TR_TTRIM TR("T-Trim", INDENT "Throttle Trim")
+#define TR_TTRIM_SW TR("T-Trim-Sw", INDENT "Trim switch")
#define TR_BEEPCTR TR("Ctr Beep", "Center Beep")
#define TR_USE_GLOBAL_FUNCS "Use Global Funcs"
#if defined(PCBSKY9X) && defined(REVX)
#define TR_OUTPUT_TYPE INDENT "Output"
#endif
-#define TR_PROTO TR(INDENT "Proto", INDENT "Protocol")
+#define TR_PROTOCOL TR("Proto", "Protocol")
#define TR_PPMFRAME TR("PPM frame", INDENT "PPM frame")
#define TR_REFRESHRATE TR(INDENT "Refresh", INDENT "Refresh rate")
#define STR_WARN_BATTVOLTAGE TR(INDENT "Output is VBAT: ", INDENT "Warning: output level is VBAT: ")
@@ -534,6 +542,7 @@
#define TR_BEEPCOUNTDOWN INDENT"Countdown"
#define TR_PERSISTENT TR(INDENT"Persist.", INDENT"Persistent")
#define TR_BACKLIGHT_LABEL "Backlight"
+#define TR_GHOST_MENU_LABEL "GHOST MENU"
#define TR_BLDELAY INDENT"Duration"
#define TR_BLONBRIGHTNESS INDENT"ON Brightness"
#define TR_BLOFFBRIGHTNESS INDENT"OFF Brightness"
@@ -650,6 +659,7 @@
#define TR_RECEIVER "Receiver"
#define TR_MULTI_RFTUNE TR("Freq tune", "RF Freq. fine tune")
#define TR_MULTI_RFPOWER "RF power"
+#define TR_MULTI_WBUS "Output"
#define TR_MULTI_TELEMETRY "Telemetry"
#define TR_MULTI_VIDFREQ TR("Vid. freq.", "Video frequency")
#define TR_RFPOWER "RF Power"
@@ -718,6 +728,7 @@
#define TR_NO_SDCARD "No SDCARD"
#define TR_WAITING_FOR_RX "Waiting for RX..."
#define TR_WAITING_FOR_TX "Waiting for TX..."
+#define TR_WAITING_FOR_MODULE TR("Waiting module", "Waiting for module...")
#define TR_NO_TOOLS "No tools available"
#define TR_NORMAL "Normal"
#define TR_NOT_INVERTED "Not inv"
@@ -793,7 +804,7 @@
#define TR_NO_MODELS_ON_SD "No Models on SD"
#define TR_NO_BITMAPS_ON_SD "No Bitmaps on SD"
#define TR_NO_SCRIPTS_ON_SD "No Scripts on SD"
-#define TR_SCRIPT_SYNTAX_ERROR "Script syntax error"
+#define TR_SCRIPT_SYNTAX_ERROR TR("Syntax error", "Script syntax error")
#define TR_SCRIPT_PANIC "Script panic"
#define TR_SCRIPT_KILLED "Script killed"
#define TR_SCRIPT_ERROR "Unknown error"
@@ -848,8 +859,10 @@
#define TR_FLASH_BOOTLOADER "Flash bootloader"
#define TR_FLASH_EXTERNAL_DEVICE "Flash External Device"
#define TR_FLASH_RECEIVER_OTA "Flash receiver OTA"
-#define TR_FLASH_RECEIVER_OTA_BY_EXTERNAL "Flash RX by ext. OTA"
-#define TR_FLASH_RECEIVER_OTA_BY_INTERNAL "Flash RX by int. OTA"
+#define TR_FLASH_RECEIVER_BY_EXTERNAL_MODULE_OTA "Flash RX by ext. OTA"
+#define TR_FLASH_RECEIVER_BY_INTERNAL_MODULE_OTA "Flash RX by int. OTA"
+#define TR_FLASH_FLIGHT_CONTROLLER_BY_EXTERNAL_MODULE_OTA "Flash FC by ext. OTA"
+#define TR_FLASH_FLIGHT_CONTROLLER_BY_INTERNAL_MODULE_OTA "Flash FC by int. OTA"
#define TR_FLASH_BLUETOOTH_MODULE TR("Flash BT module", "Flash Bluetooth module")
#define TR_FLASH_POWER_MANAGEMENT_UNIT "Flash pwr mngt unit"
#define TR_CURRENT_VERSION TR("Current vers. ", "Current version: ")
@@ -857,6 +870,7 @@
#define TR_FLASH_INTERNAL_MULTI TR("Flash Int. Multi", "Flash Internal Multi")
#define TR_FLASH_EXTERNAL_MODULE "Flash external module"
#define TR_FLASH_EXTERNAL_MULTI TR("Flash Ext. Multi", "Flash External Multi")
+#define TR_FLASH_EXTERNAL_ELRS TR("Flash Ext. ELRS", "Flash External ELRS")
#define TR_FIRMWARE_UPDATE_ERROR TR("FW update Error","Firmware update error")
#define TR_FIRMWARE_UPDATE_SUCCESS "Flash successful"
#define TR_WRITING "Writing..."
@@ -1048,7 +1062,7 @@
#define TR_LSW_HEADERS_V1 "V1"
#define TR_LSW_HEADERS_V2 "V2"
#define TR_LSW_HEADERS_ANDSW "AND Switch"
-#define TR_LSW_HEADERS_DURATION "Min Duration"
+#define TR_LSW_HEADERS_DURATION "Duration"
#define TR_LSW_HEADERS_DELAY "Delay"
#define TR_GVAR_HEADERS_NAME "Name"
@@ -1119,10 +1133,18 @@
#define TR_ABOUT_MARTIN_1 "Martin Hotar"
#define TR_ABOUT_MARTIN_2 "Graphics designer"
-#if defined(PCBTARANIS)
- #define TR_ABOUT_HARDWARE_1 "FrSky"
- #define TR_ABOUT_HARDWARE_2 "Hardware designer/producer"
- #define TR_ABOUT_HARDWARE_3 "Firmware contributor"
+#if defined(MANUFACTURER_FRSKY)
+ #define TR_ABOUT_HARDWARE_1 "FrSky"
+ #define TR_ABOUT_HARDWARE_2 TR("Hardware design/producer", "Hardware designer/producer")
+ #define TR_ABOUT_HARDWARE_3 "Firmware contributor"
+#elif defined(MANUFACTURER_RADIOMASTER)
+ #define TR_ABOUT_HARDWARE_1 "Radiomaster"
+ #define TR_ABOUT_HARDWARE_2 TR("Hardware design/producer", "Hardware designer/producer")
+ #define TR_ABOUT_HARDWARE_3 "Firmware contributor"
+#elif defined(MANUFACTURER_JUMPER)
+ #define TR_ABOUT_HARDWARE_1 "JumperRC"
+ #define TR_ABOUT_HARDWARE_2 TR("Hardware design/producer", "Hardware designer/producer")
+ #define TR_ABOUT_HARDWARE_3 "Firmware contributor"
#else
#define TR_ABOUT_HARDWARE_1 "Brent Nelson"
#define TR_ABOUT_HARDWARE_2 "Sky9x designer/producer"
@@ -1192,6 +1214,9 @@
#define TR_SETUP_WIDGETS "Setup widgets"
#define TR_BACKGROUND_COLOR "Background color"
#define TR_MAIN_COLOR "Main color"
+#define TR_BAR2_COLOR "Secondary bar color"
+#define TR_BAR1_COLOR "Main bar color"
+#define TR_TEXT_COLOR "Text color"
#define TR_TEXT_VIEWER "Text Viewer"
#define TR_MENU_INPUTS "\314Inputs"
@@ -1213,6 +1238,7 @@
#define TR_JITTER_FILTER "ADC Filter"
#define TR_RTC_CHECK TR("Check RTC", "Check RTC voltage")
#define TR_AUTH_FAILURE "Auth-failure"
+#define TR_RACING_MODE "Racing mode"
#define ZSTR_VFR "VFR"
#define ZSTR_RSSI "RSSI"
@@ -1357,4 +1383,17 @@
#define ZSTR_CL15 "Cl15"
#define ZSTR_CL16 "Cl16"
#define ZSTR_CL17 "Cl17"
-#define ZSTR_CL18 "Cl18"
\ No newline at end of file
+#define ZSTR_CL18 "Cl18"
+#define ZSTR_FRAME_RATE "FRat"
+#define ZSTR_TOTAL_LATENCY "TLat"
+#define ZSTR_VTX_FREQ "VFrq"
+#define ZSTR_VTX_PWR "VPwr"
+#define ZSTR_VTX_CHAN "VChn"
+#define ZSTR_VTX_BAND "VBan"
+#define ZSTR_SERVO_CURRENT "SrvA"
+#define ZSTR_SERVO_VOLTAGE "SrvV"
+#define ZSTR_SERVO_TEMPERATURE "SrvT"
+#define ZSTR_SERVO_STATUS "SrvS"
+#define ZSTR_LOSS "Loss"
+#define ZSTR_SPEED "Spd "
+#define ZSTR_FLOW "Flow"
diff --git a/radio/src/translations/fr.h.txt b/radio/src/translations/fr.h.txt
index d4a1f5f29..06f7159a0 100644
--- a/radio/src/translations/fr.h.txt
+++ b/radio/src/translations/fr.h.txt
@@ -237,9 +237,10 @@
#endif
#define TR_SF_SCREENSHOT "Photo Ecran\0 "
+#define TR_SF_RACING_MODE "Racing Mode\0 "
#define TR_SF_RESERVE "[reserve]\0 "
- #define TR_VFSWFUNC TR_SF_SAFETY "Ecolage\0 ""Trim instant.""Remise à 0\0 ""Déf.\0 " TR_ADJUST_GVAR "Volume\0 " "DéfFailsafe\0 " "Test Port.\0 " "Bind\0 " TR_SOUND TR_PLAY_TRACK TR_PLAY_VALUE TR_SF_RESERVE TR_SF_PLAY_SCRIPT TR_SF_RESERVE TR_SF_BG_MUSIC TR_VVARIO TR_HAPTIC TR_SDCLOGS "Rétroécl.\0 " TR_SF_SCREENSHOT TR_SF_TEST
+ #define TR_VFSWFUNC TR_SF_SAFETY "Ecolage\0 ""Trim instant.""Remise à 0\0 ""Déf.\0 " TR_ADJUST_GVAR "Volume\0 " "DéfFailsafe\0 " "Test Port.\0 " "Bind\0 " TR_SOUND TR_PLAY_TRACK TR_PLAY_VALUE TR_SF_RESERVE TR_SF_PLAY_SCRIPT TR_SF_RESERVE TR_SF_BG_MUSIC TR_VVARIO TR_HAPTIC TR_SDCLOGS "Rétroécl.\0 " TR_SF_SCREENSHOT TR_SF_RACING_MODE TR_SF_TEST
#define LEN_VFSWRESET TR("\004", "\012")
@@ -283,7 +284,7 @@
#define LEN_VUNITSSYSTEM TR("\006", "\012")
#define TR_VUNITSSYSTEM TR("Métr.\0""Impér.", "Métriques\0""Impériales")
#define LEN_VTELEMUNIT "\003"
-#define TR_VTELEMUNIT "-\0 ""V\0 ""A\0 ""mA\0""kts""m/s""f/s""kmh""mph""m\0 ""ft\0""@C\0""@F\0""%\0 ""mAh""W\0 ""mW\0""dB\0""rpm""g\0 ""@\0 ""rad""ml\0""fOz"
+#define TR_VTELEMUNIT "-\0 ""V\0 ""A\0 ""mA\0""kts""m/s""f/s""kmh""mph""m\0 ""ft\0""@C\0""@F\0""%\0 ""mAh""W\0 ""mW\0""dB\0""rpm""g\0 ""@\0 ""rad""ml\0""fOz""mlm""Hz\0""mS\0""uS\0""km\0"
#define STR_V (STR_VTELEMUNIT+1)
#define STR_A (STR_VTELEMUNIT+4)
@@ -314,9 +315,15 @@
#elif defined(PCBXLITE)
#define LEN_VKEYS "\005"
#define TR_VKEYS "Shift""Exit\0""Enter""Bas\0 ""Haut\0""Droit""Gauch"
-#elif defined(RADIO_T12)
+#elif defined(RADIO_FAMILY_JUMPER_T12)
#define LEN_VKEYS "\005"
#define TR_VKEYS "Exit\0""Enter""Down\0""Up\0 ""Right""Left\0"
+#elif defined(RADIO_TX12)
+ #define LEN_VKEYS "\005"
+ #define TR_VKEYS "Exit\0""Enter""Up\0 ""Down\0""SYS\0 ""MDL\0 ""TELE\0"
+#elif defined(RADIO_T8)
+ #define LEN_VKEYS "\005"
+ #define TR_VKEYS "RTN\0 ""ENTER""PGUP\0""PGDN\0""SYS\0 ""MDL\0 ""UP\0 ""DOWN\0"
#elif defined(PCBTARANIS)
#define LEN_VKEYS "\005"
#define TR_VKEYS "Menu\0""Exit\0""Enter""Page\0""Plus\0""Moins"
@@ -452,13 +459,14 @@
#define TR_DISPLAY_TRIMS TR("Aff. trims", "Affichage trims")
#define TR_TTRACE TR("Source gaz", INDENT "Source")
#define TR_TTRIM TR("Trim gaz", INDENT "Trim ralenti uniq.")
+#define TR_TTRIM_SW TR("T-Trim-Sw", INDENT "Trim switch")
#define TR_BEEPCTR TR("Bips centr", "Bips centrage")
#define TR_USE_GLOBAL_FUNCS TR("Fonc. glob.", "Fonctions globales")
#if defined(PCBSKY9X) && defined(REVX)
#define TR_OUTPUT_TYPE INDENT "Sortie"
#endif
-#define TR_PROTO TR(INDENT "Proto.", INDENT "Protocole")
- #define TR_PPMFRAME INDENT "Trame PPM"
+#define TR_PROTOCOL TR("Proto.", "Protocole")
+#define TR_PPMFRAME INDENT "Trame PPM"
#define TR_REFRESHRATE INDENT "Période"
#define STR_WARN_BATTVOLTAGE TR(INDENT "Signal est VBAT: ", INDENT "ATTENTION: signal est à VBAT: ")
#define TR_WARN_5VOLTS "Warning: output level is 5 volts"
@@ -540,6 +548,7 @@
#define TR_BEEPCOUNTDOWN TR(INDENT "Bip fin", INDENT "Compte à rebours")
#define TR_PERSISTENT TR(INDENT "Persist.", INDENT "Persistant")
#define TR_BACKLIGHT_LABEL "Rétroéclairage"
+#define TR_GHOST_MENU_LABEL "GHOST MENU"
#define TR_BLDELAY INDENT "Durée"
#define TR_BLONBRIGHTNESS INDENT "Luminosité ON"
#define TR_BLOFFBRIGHTNESS INDENT "Luminosité OFF"
@@ -653,6 +662,7 @@
#define TR_RECEIVER "Récept."
#define TR_MULTI_RFTUNE TR(INDENT "Ajust.fréq", INDENT "Ajustement fréq.")
#define TR_MULTI_RFPOWER "RF power"
+#define TR_MULTI_WBUS "Output"
#define TR_MULTI_TELEMETRY "Télémétrie"
#define TR_MULTI_VIDFREQ TR(INDENT "Fréq. vidéo", INDENT "Fréquence vidéo")
#define TR_RFPOWER TR("Puiss. RF", "Puissance RF")
@@ -721,6 +731,7 @@
#define TR_NO_SDCARD "Carte SD indisponible"
#define TR_WAITING_FOR_RX "Attente du RX..."
#define TR_WAITING_FOR_TX "Attente du TX..."
+#define TR_WAITING_FOR_MODULE TR("Waiting module", "Waiting for module...")
#define TR_NO_TOOLS "Pas d'outils dispo"
#define TR_NORMAL "Normal"
#define TR_NOT_INVERTED "Non inv"
@@ -731,7 +742,7 @@
#define TR_16CH_WITHOUT_TELEMETRY TR("16CH sans télém.", "16CH sans télémétrie")
#define TR_16CH_WITH_TELEMETRY TR("16CH avec télém.", "16CH avec télémétrie")
#define TR_8CH_WITH_TELEMETRY TR("8CH avec télém.", "8CH avec télémétrie")
-#define TR_EXT_ANTENNA "Antenne externe"
+#define TR_EXT_ANTENNA "Antenne Ext."
#define TR_PIN "Pin"
#define TR_UPDATE_RX_OPTIONS "Sauver options RX?"
#define TR_UPDATE_TX_OPTIONS "Sauver options TX?"
@@ -796,7 +807,7 @@
#define TR_NO_MODELS_ON_SD "Aucun modèle SD"
#define TR_NO_BITMAPS_ON_SD "Aucun Bitmap SD"
#define TR_NO_SCRIPTS_ON_SD "Aucun Script SD"
-#define TR_SCRIPT_SYNTAX_ERROR "Erreur syntaxe script"
+#define TR_SCRIPT_SYNTAX_ERROR TR("Erreur syntaxe", "Erreur syntaxe script")
#define TR_SCRIPT_PANIC "Script bloqué"
#define TR_SCRIPT_KILLED "Script interrompu"
#define TR_SCRIPT_ERROR "Erreur inconnue"
@@ -850,8 +861,10 @@
#define TR_FLASH_BOOTLOADER "Flasher BootLoader"
#define TR_FLASH_EXTERNAL_DEVICE TR("Flasher S.Port", "Flasher S.Port externe")
#define TR_FLASH_RECEIVER_OTA "Flasher RX OTA"
-#define TR_FLASH_RECEIVER_OTA_BY_EXTERNAL "Flash RX by ext. OTA"
-#define TR_FLASH_RECEIVER_OTA_BY_INTERNAL "Flash RX by int. OTA"
+#define TR_FLASH_RECEIVER_BY_EXTERNAL_MODULE_OTA "Flash RX by ext. OTA"
+#define TR_FLASH_RECEIVER_BY_INTERNAL_MODULE_OTA "Flash RX by int. OTA"
+#define TR_FLASH_FLIGHT_CONTROLLER_BY_EXTERNAL_MODULE_OTA "Flash FC by ext. OTA"
+#define TR_FLASH_FLIGHT_CONTROLLER_BY_INTERNAL_MODULE_OTA "Flash FC by int. OTA"
#define TR_FLASH_BLUETOOTH_MODULE TR("Flash module BT", "Flash module Bluetooth")
#define TR_FLASH_POWER_MANAGEMENT_UNIT "Flasher pwr mngt unit"
#define TR_CURRENT_VERSION "Version courante :"
@@ -859,6 +872,7 @@
#define TR_FLASH_INTERNAL_MULTI TR("Flash Int. Multi", "Flash Internal Multi")
#define TR_FLASH_EXTERNAL_MODULE TR("Flasher module ext.", "Flasher module externe")
#define TR_FLASH_EXTERNAL_MULTI TR("Flash Ext. Multi", "Flash External Multi")
+#define TR_FLASH_EXTERNAL_ELRS TR("Flash Ext. ELRS", "Flash External ELRS")
#define TR_FIRMWARE_UPDATE_ERROR TR("Erreur màj FW","Erreur de mise à jour")
#define TR_FIRMWARE_UPDATE_SUCCESS "Flash ok"
#define TR_WRITING "Ecriture..."
@@ -1058,7 +1072,7 @@
#define TR_LSW_HEADERS_V1 "V1"
#define TR_LSW_HEADERS_V2 "V2"
#define TR_LSW_HEADERS_ANDSW "ET suppl."
-#define TR_LSW_HEADERS_DURATION "Durée min."
+#define TR_LSW_HEADERS_DURATION "Durée"
#define TR_LSW_HEADERS_DELAY "Délai"
#define TR_GVAR_HEADERS_NAME "Nom"
@@ -1129,10 +1143,18 @@
#define TR_ABOUT_MARTIN_1 "Martin Hotar"
#define TR_ABOUT_MARTIN_2 "Design graphique"
-#if defined(PCBTARANIS)
+#if defined(MANUFACTURER_FRSKY)
#define TR_ABOUT_HARDWARE_1 "FrSky"
#define TR_ABOUT_HARDWARE_2 "Développeur/fabricant"
#define TR_ABOUT_HARDWARE_3 "du matériel"
+#elif defined(MANUFACTURER_RADIOMASTER)
+ #define TR_ABOUT_HARDWARE_1 "Radiomaster"
+ #define TR_ABOUT_HARDWARE_2 "Développeur/fabricant"
+ #define TR_ABOUT_HARDWARE_3 "du matériel"
+#elif defined(MANUFACTURER_JUMPER)
+ #define TR_ABOUT_HARDWARE_1 "JumperRC"
+ #define TR_ABOUT_HARDWARE_2 "Développeur/fabricant"
+ #define TR_ABOUT_HARDWARE_3 "du matériel"
#else
#define TR_ABOUT_HARDWARE_1 "Brent Nelson"
#define TR_ABOUT_HARDWARE_2 "Développeur/fabricant"
@@ -1208,6 +1230,9 @@
#define TR_ADDMAINVIEW "Ajouter vue principale"
#define TR_BACKGROUND_COLOR "Couleur de fond"
#define TR_MAIN_COLOR "Couleur principale"
+#define TR_BAR2_COLOR "Secondary bar color"
+#define TR_BAR1_COLOR "Main bar color"
+#define TR_TEXT_COLOR "Text color"
#define TR_TEXT_VIEWER "Visualisateur de texte"
#define TR_MENU_INPUTS "\314Entrées"
@@ -1229,6 +1254,7 @@
#define TR_JITTER_FILTER "Filtre ADC"
#define TR_RTC_CHECK TR("Vérif. RTC", "Vérif. pile RTC")
#define TR_AUTH_FAILURE "Auth-failure"
+#define TR_RACING_MODE "Racing mode"
#define ZSTR_VFR "VFR"
#define ZSTR_RSSI "RSSI"
@@ -1374,4 +1400,17 @@
#define ZSTR_CL15 "Cl15"
#define ZSTR_CL16 "Cl16"
#define ZSTR_CL17 "Cl17"
-#define ZSTR_CL18 "Cl18"
\ No newline at end of file
+#define ZSTR_CL18 "Cl18"
+#define ZSTR_FRAME_RATE "FRat"
+#define ZSTR_TOTAL_LATENCY "TLat"
+#define ZSTR_VTX_FREQ "VFrq"
+#define ZSTR_VTX_PWR "VPwr"
+#define ZSTR_VTX_CHAN "VChn"
+#define ZSTR_VTX_BAND "VBan"
+#define ZSTR_SERVO_CURRENT "SrvA"
+#define ZSTR_SERVO_VOLTAGE "SrvV"
+#define ZSTR_SERVO_TEMPERATURE "SrvT"
+#define ZSTR_SERVO_STATUS "SrvS"
+#define ZSTR_LOSS "Loss"
+#define ZSTR_SPEED "Spd "
+#define ZSTR_FLOW "Flow"
diff --git a/radio/src/translations/it.h.txt b/radio/src/translations/it.h.txt
index 034bcd7db..cdd3dfc94 100644
--- a/radio/src/translations/it.h.txt
+++ b/radio/src/translations/it.h.txt
@@ -238,9 +238,10 @@
#endif
#define TR_SF_SCREENSHOT "Screenshot\0 "
+#define TR_SF_RACING_MODE "Racing Mode\0 "
#define TR_SF_RESERVE "[riserva] \0"
-#define TR_VFSWFUNC TR_SF_SAFETY "Maestro \0 ""Trim Instant.""Azzera\0 ""Set \0 " TR_ADJUST_GVAR "Volume\0 " "SetFailsafe\0 " "RangeCheck\0 " "ModuleBind\0 " TR_SOUND TR_PLAY_TRACK TR_PLAY_VALUE TR_SF_RESERVE TR_SF_PLAY_SCRIPT TR_SF_RESERVE TR_SF_BG_MUSIC TR_VVARIO TR_HAPTIC TR_SDCLOGS "Retroillum.\0 " TR_SF_SCREENSHOT TR_SF_TEST
+#define TR_VFSWFUNC TR_SF_SAFETY "Maestro \0 ""Trim Instant.""Azzera\0 ""Set \0 " TR_ADJUST_GVAR "Volume\0 " "SetFailsafe\0 " "RangeCheck\0 " "ModuleBind\0 " TR_SOUND TR_PLAY_TRACK TR_PLAY_VALUE TR_SF_RESERVE TR_SF_PLAY_SCRIPT TR_SF_RESERVE TR_SF_BG_MUSIC TR_VVARIO TR_HAPTIC TR_SDCLOGS "Retroillum.\0 " TR_SF_SCREENSHOT TR_SF_RACING_MODE TR_SF_TEST
#define LEN_VFSWRESET TR("\004", "\011")
@@ -284,7 +285,7 @@
#define LEN_VUNITSSYSTEM TR("\006", "\011")
#define TR_VUNITSSYSTEM TR("Metric""Imper.", "Metriche\0""Imperiali")
#define LEN_VTELEMUNIT "\003"
-#define TR_VTELEMUNIT "-\0 ""V\0 ""A\0 ""mA\0""kts""m/s""f/s""kmh""mph""m\0 ""ft\0""@C\0""@F\0""%\0 ""mAh""W\0 ""mW\0""dB\0""rpm""g\0 ""@\0 ""rad""ml\0""fOz"
+#define TR_VTELEMUNIT "-\0 ""V\0 ""A\0 ""mA\0""kts""m/s""f/s""kmh""mph""m\0 ""ft\0""@C\0""@F\0""%\0 ""mAh""W\0 ""mW\0""dB\0""rpm""g\0 ""@\0 ""rad""ml\0""fOz""mlm""Hz\0""mS\0""uS\0""km\0"
#define STR_V (STR_VTELEMUNIT+1)
#define STR_A (STR_VTELEMUNIT+4)
@@ -315,9 +316,15 @@
#elif defined(PCBXLITE)
#define LEN_VKEYS "\005"
#define TR_VKEYS "Shift""Exit\0""Enter""Down\0""Up\0 ""Right""Left\0"
-#elif defined(RADIO_T12)
+#elif defined(RADIO_FAMILY_JUMPER_T12)
#define LEN_VKEYS "\005"
#define TR_VKEYS "Exit\0""Enter""Down\0""Up\0 ""Right""Left\0"
+#elif defined(RADIO_TX12)
+ #define LEN_VKEYS "\005"
+ #define TR_VKEYS "Exit\0""Enter""Up\0 ""Down\0""SYS\0 ""MDL\0 ""TELE\0"
+#elif defined(RADIO_T8)
+ #define LEN_VKEYS "\005"
+ #define TR_VKEYS "RTN\0 ""ENTER""PGUP\0""PGDN\0""SYS\0 ""MDL\0 ""UP\0 ""DOWN\0"
#elif defined(PCBTARANIS)
#define LEN_VKEYS "\005"
#define TR_VKEYS "Menu\0""Exit\0""Enter""Page\0""Plus\0""Minus"
@@ -454,13 +461,14 @@
#define TR_DISPLAY_TRIMS TR("Mos. Trims", "Mostra Trims")
#define TR_TTRACE TR("So. motore", INDENT "Sorgente Motore")
#define TR_TTRIM TR("Trim Mot.", INDENT "Trim Motore")
+#define TR_TTRIM_SW TR("T-Trim-Sw", INDENT "Trim switch")
#define TR_BEEPCTR TR("Beep al c.", "Beep al centro")
-#define TR_USE_GLOBAL_FUNCS "Usa Funz. Globali"
+#define TR_USE_GLOBAL_FUNCS TR("Funz. Glob.", "Usa Funz. Globali")
#if defined(PCBSKY9X) && defined(REVX)
#define TR_OUTPUT_TYPE INDENT "Uscita"
#endif
-#define TR_PROTO TR(INDENT "Protoc.", INDENT "Protocollo")
- #define TR_PPMFRAME INDENT "Frame PPM"
+#define TR_PROTOCOL TR("Protoc.", "Protocollo")
+#define TR_PPMFRAME INDENT "Frame PPM"
#define TR_REFRESHRATE TR(INDENT "Refresh", INDENT "Refresh rate")
#define STR_WARN_BATTVOLTAGE TR(INDENT "Uscita VBAT: ", INDENT "Att.: livel. uscita VBAT: ")
#define TR_WARN_5VOLTS "Attenzione: il livello d'uscita è 5 Volts"
@@ -542,6 +550,7 @@
#define TR_BEEPCOUNTDOWN TR(INDENT "Conto rov", INDENT "Conto rovescia")
#define TR_PERSISTENT TR(INDENT "Persist.", INDENT "Persistente")
#define TR_BACKLIGHT_LABEL TR("Retroillu.", "Retroilluminazione")
+#define TR_GHOST_MENU_LABEL "GHOST MENU"
#define TR_BLDELAY INDENT "Durata"
#define TR_BLONBRIGHTNESS TR(INDENT "Lumin. ON", INDENT "Luminosità ON")
#define TR_BLOFFBRIGHTNESS TR(INDENT "Lumin. OFF", INDENT "Luminosità OFF")
@@ -652,6 +661,7 @@
#define TR_RECEIVER "Ricevente"
#define TR_MULTI_RFTUNE TR("Tune RF", "Tune fine Freq. RF")
#define TR_MULTI_RFPOWER "RF power"
+#define TR_MULTI_WBUS "Output"
#define TR_MULTI_TELEMETRY "Telemetria"
#define TR_MULTI_VIDFREQ TR("Freq. video", "Frequenza video")
#define TR_RFPOWER "Potenza RF"
@@ -720,6 +730,7 @@
#define TR_NO_SDCARD "No SDCard"
#define TR_WAITING_FOR_RX "Attendo la RX..."
#define TR_WAITING_FOR_TX "Attendo la TX..."
+#define TR_WAITING_FOR_MODULE TR("Waiting module", "Waiting for module...")
#define TR_NO_TOOLS "Tools non disp."
#define TR_NORMAL "Normale"
#define TR_NOT_INVERTED "No inv."
@@ -795,7 +806,7 @@
#define TR_NO_MODELS_ON_SD "No Model." BREAKSPACE "su SD"
#define TR_NO_BITMAPS_ON_SD "No Immag." BREAKSPACE "su SD"
#define TR_NO_SCRIPTS_ON_SD "No Scripts" BREAKSPACE "su SD"
-#define TR_SCRIPT_SYNTAX_ERROR "Script errore sintassi"
+#define TR_SCRIPT_SYNTAX_ERROR TR("Errore sintassi", "Script errore sintassi")
#define TR_SCRIPT_PANIC "Script panic"
#define TR_SCRIPT_KILLED "Script fermato"
#define TR_SCRIPT_ERROR "Errore sconosciuto"
@@ -841,47 +852,50 @@
#define TR_MENUGLOBALVARS "VARIABILI GLOBALI"
#define TR_OWN "Fase"
#define TR_DATE "Data"
-#define TR_MONTHS { "Gen", "Feb", "Mar", "Apr", "Mag", "Giu", "Lug", "Auo", "Set", "Ott", "Nov", "Dic" }
+#define TR_MONTHS { "Gen", "Feb", "Mar", "Apr", "Mag", "Giu", "Lug", "Ago", "Set", "Ott", "Nov", "Dic" }
#define TR_ROTARY_ENCODER "R.E."
#define TR_CHANNELS_MONITOR "MONITOR CANALI"
#define TR_MIXERS_MONITOR "MONITOR MIXER"
#define TR_PATH_TOO_LONG "Path troppo lungo"
#define TR_VIEW_TEXT "Vedi testo"
-#define TR_FLASH_BOOTLOADER "Prog. bootloader"
-#define TR_FLASH_EXTERNAL_DEVICE "Progr. dispositivo Esterno"
-#define TR_FLASH_RECEIVER_OTA TR("Prog. RX OTA", INDENT "Prog. ricevente OTA")
-#define TR_FLASH_RECEIVER_OTA_BY_EXTERNAL "Flash RX by ext. OTA"
-#define TR_FLASH_RECEIVER_OTA_BY_INTERNAL "Flash RX by int. OTA"
+#define TR_FLASH_BOOTLOADER TR("Prog. bootloader", "Programma bootloader")
+#define TR_FLASH_EXTERNAL_DEVICE TR("Prog. disp. est.", "Programma dispositivo esterno")
+#define TR_FLASH_RECEIVER_OTA TR("Prog. RX OTA", INDENT "Programma RX OTA")
+#define TR_FLASH_RECEIVER_BY_EXTERNAL_MODULE_OTA TR("Prog. RX da OTA est.", INDENT "Prog. RX da OTA esterno")
+#define TR_FLASH_RECEIVER_BY_INTERNAL_MODULE_OTA TR("Prog. RX da OTA int.", INDENT "Prog. RX da OTA interno")
+#define TR_FLASH_FLIGHT_CONTROLLER_BY_EXTERNAL_MODULE_OTA TR("Prog. FC da OTA est.", INDENT "Prog. FC da OTA esterno")
+#define TR_FLASH_FLIGHT_CONTROLLER_BY_INTERNAL_MODULE_OTA TR("Prog. FC da OTA int.", INDENT "Prog. FC da OTA interno")
#define TR_FLASH_BLUETOOTH_MODULE TR("Prog. mod. BT", INDENT "Prog. modulo Bluetooth")
-#define TR_FLASH_POWER_MANAGEMENT_UNIT TR("Prog. PMU", "Program. PMU")
+#define TR_FLASH_POWER_MANAGEMENT_UNIT TR("Prog. PMU", "Programma PMU")
#define TR_CURRENT_VERSION TR("Vers. currente ", "Versione corrente: ")
-#define TR_FLASH_INTERNAL_MODULE "Progr. modulo int."
-#define TR_FLASH_EXTERNAL_MODULE "Progr. modulo est."
-#define TR_FLASH_INTERNAL_MULTI "Prog. Multi int."
-#define TR_FLASH_EXTERNAL_MULTI "Prog. Multi est."
-#define TR_FIRMWARE_UPDATE_ERROR TR(INDENT "Errore agg. FW",INDENT "Errore aggiornamento firmware")
+#define TR_FLASH_EXTERNAL_ELRS TR("Flash Ext. ELRS", "Flash External ELRS")
+#define TR_FLASH_INTERNAL_MODULE TR("Prog. modulo int.", "Programma modulo interno")
+#define TR_FLASH_EXTERNAL_MODULE TR("Prog. modulo est.", "Programma modulo esterno")
+#define TR_FLASH_INTERNAL_MULTI TR("Prog. MULTI int.", "Programma MULTI interno")
+#define TR_FLASH_EXTERNAL_MULTI TR("Prog. MULTI est.", "Programma MULTI esterno")
+#define TR_FIRMWARE_UPDATE_ERROR TR(INDENT "Errore agg. FW",INDENT "Errore aggiornamento firmware")
#define TR_FIRMWARE_UPDATE_SUCCESS "Aggiornamento" BREAKSPACE "riuscito"
-#define TR_WRITING "Scrittura..."
-#define TR_CONFIRM_FORMAT "Confermi Formattazione?"
-#define TR_INTERNALRF "Modulo Interno"
+#define TR_WRITING "Scrittura..."
+#define TR_CONFIRM_FORMAT "Confermi formattazione?"
+#define TR_INTERNALRF "Modulo interno"
#define TR_INTERNAL_MODULE TR("Modulo int.", "Modulo interno")
#define TR_EXTERNAL_MODULE TR("Modulo est.", "Modulo esterno")
#define TR_OPENTX_UPGRADE_REQUIRED "OpenTX richiede aggiornamento"
#define TR_TELEMETRY_DISABLED TR("Telem. off", "Telem. disabilitata")
#define TR_MORE_OPTIONS_AVAILABLE "Altre opzioni assenti"
#define TR_NO_MODULE_INFORMATION "Nessuna info del modulo"
-#define TR_EXTERNALRF "Modulo esterno"
-#define TR_FAILSAFE "Modo failsafe"
-#define TR_FAILSAFESET TR(INDENT "FAILSAFE", INDENT "IMPOSTAZIONI FAILSAFE")
+#define TR_EXTERNALRF "Modulo esterno"
+#define TR_FAILSAFE TR(INDENT "Failsafe", INDENT "Modo failsafe")
+#define TR_FAILSAFESET TR(INDENT "FAILSAFE", INDENT "IMPOSTAZIONI FAILSAFE")
#define TR_REG_ID "Reg. ID"
#define TR_OWNER_ID "Owner ID"
#define TR_PINMAPSET "PINMAP"
-#define TR_HOLD "Hold"
+#define TR_HOLD "Hold"
#define TR_HOLD_UPPERCASE "HOLD"
-#define TR_NONE "None"
+#define TR_NONE "None"
#define TR_NONE_UPPERCASE "NONE"
-#define TR_MENUSENSOR "SENSOR"
-#define TR_POWERMETER_PEAK "Peak"
+#define TR_MENUSENSOR "SENSORE"
+#define TR_POWERMETER_PEAK "Picco"
#define TR_POWERMETER_POWER "Potenza"
#define TR_POWERMETER_ATTN "Att."
#define TR_POWERMETER_FREQ "Freq."
@@ -894,7 +908,7 @@
#define TR_COUNTRYCODE TR("Cod. Paese", "Codice del Paese")
#define TR_USBMODE "Modo USB"
#define TR_JACKMODE "Modo JACK"
-#define TR_VOICELANG "Lingua Voce"
+#define TR_VOICELANG "Lingua vocale"
#define TR_UNITSSYSTEM "Unità"
#define TR_EDIT "Modifica"
#define TR_INSERT_BEFORE "Inserisci prima"
@@ -922,7 +936,7 @@
#define TR_SPEAKER INDENT "Speaker"
#define TR_BUZZER INDENT "Buzzer"
#define TR_BYTES "Bytes"
-#define TR_MODULE_BIND "[Bind]"
+#define TR_MODULE_BIND TR("[Bnd]","[Bind]")
#define TR_POWERMETER_ATTN_NEEDED "Attenuatore necessario"
#define TR_PXX2_SELECT_RX "Seleziona RX..."
#define TR_PXX2_DEFAULT ""
@@ -934,17 +948,17 @@
#define TR_RECEIVER_RESET "Resetto RX?"
#define TR_SHARE "Condividere"
#define TR_BIND "Bind"
-#define TR_REGISTER TR("Reg", "Registrare")
-#define TR_MODULE_RANGE "[Range]"
+#define TR_REGISTER TR("Reg", "Registrare")
+#define TR_MODULE_RANGE TR("[Rng]","[Range]")
#define TR_RECEIVER_OPTIONS TR("OPZIONI RX", "OPZIONI RICEVENTE")
#define TR_DEL_BUTTON BUTTON(TR("Canc.", "Cancella"))
#define TR_RESET_BTN "[Reset]"
#define TR_DEBUG "Debug"
-#define TR_KEYS_BTN BUTTON(TR("SW","Interruttori"))
-#define TR_ANALOGS_BTN BUTTON(TR("Analogico","Analogici"))
-#define TR_TOUCH_NOTFOUND "Schermo touch non trovato"
-#define TR_TOUCH_EXIT "Tocca lo schermo per uscire"
-#define TR_CALIBRATION TR("Calibraz.", "Calibrazione")
+#define TR_KEYS_BTN BUTTON(TR("SW", "Tasti"))
+#define TR_ANALOGS_BTN BUTTON("Analogici")
+#define TR_TOUCH_NOTFOUND "Schermo touch non trovato"
+#define TR_TOUCH_EXIT "Tocca lo schermo per uscire"
+#define TR_CALIBRATION TR("Calibraz.", "Calibrazione")
#define TR_SET "[Set]"
#define TR_TRAINER TR("Trainer", "Maestro/Allievo")
#define TR_CHANS "Canali"
@@ -958,7 +972,7 @@
#define TR_TOPLCDTIMER "Timer LCD Sup."
#define TR_UNIT "Unita"
#define TR_TELEMETRY_NEWSENSOR INDENT "Aggiungi nuovo sensore"
-#define TR_CHANNELRANGE INDENT "Numero Canali"
+#define TR_CHANNELRANGE TR(INDENT "Num Canali", INDENT "Numero Canali")
#define TR_AFHDS3_RX_FREQ TR("Freq. RX", "Frequenza RX")
#define TR_AFHDS3_ONE_TO_ONE_TELEMETRY TR("Unicast/Tel.", "Unicast/Telemetria")
#define TR_AFHDS3_ONE_TO_MANY "Multicast"
@@ -1121,10 +1135,18 @@
#define TR_ABOUT_MARTIN_1 "Martin Hotar"
#define TR_ABOUT_MARTIN_2 "Graphic Designer"
-#if defined(PCBTARANIS)
+#if defined(MANUFACTURER_FRSKY)
#define TR_ABOUT_HARDWARE_1 "FrSky"
#define TR_ABOUT_HARDWARE_2 "Disegno/produzione Hardware"
#define TR_ABOUT_HARDWARE_3 "Contributi al Firmware"
+#elif defined(MANUFACTURER_RADIOMASTER)
+ #define TR_ABOUT_HARDWARE_1 "Radiomaster"
+ #define TR_ABOUT_HARDWARE_2 "Disegno/produzione Hardware"
+ #define TR_ABOUT_HARDWARE_3 "Contributi al Firmware"
+#elif defined(MANUFACTURER_JUMPER)
+ #define TR_ABOUT_HARDWARE_1 "JumperRC"
+ #define TR_ABOUT_HARDWARE_2 "Disegno/produzione Hardware"
+ #define TR_ABOUT_HARDWARE_3 "Contributi al Firmware"
#else
#define TR_ABOUT_HARDWARE_1 "Brent Nelson"
#define TR_ABOUT_HARDWARE_2 "Designer/Produttore SKY9X"
@@ -1201,6 +1223,9 @@
#define TR_ADDMAINVIEW "Aggiungi vista princ."
#define TR_BACKGROUND_COLOR "Colore background"
#define TR_MAIN_COLOR "Colore principale"
+#define TR_BAR2_COLOR "Secondary bar color"
+#define TR_BAR1_COLOR "Main bar color"
+#define TR_TEXT_COLOR "Text color"
#define TR_TEXT_VIEWER "Visualizzatore testi"
#define TR_MENU_INPUTS "\314Ingressi"
@@ -1220,12 +1245,13 @@
#define TR_MENU_OTHER "Altro"
#define TR_MENU_INVERT "Inverti"
#define TR_JITTER_FILTER "Filtro ADC"
-#define TR_RTC_CHECK TR("Controllo RTC", "Controllo voltaggio RTC")
-#define TR_AUTH_FAILURE "Auth-failure"
+#define TR_RTC_CHECK TR("Controllo RTC", "Controllo volt. RTC")
+#define TR_AUTH_FAILURE "Auth-failure"
+#define TR_RACING_MODE "Racing mode"
#define ZSTR_VFR "VFR"
#define ZSTR_RSSI "RSSI"
-#define ZSTR_R9PW "R9PW"
+#define ZSTR_R9PW "R9PW"
#define ZSTR_RAS "SWR"
#define ZSTR_A1 "A1"
#define ZSTR_A2 "A2"
@@ -1368,3 +1394,16 @@
#define ZSTR_CL16 "Cl16"
#define ZSTR_CL17 "Cl17"
#define ZSTR_CL18 "Cl18"
+#define ZSTR_FRAME_RATE "FRat"
+#define ZSTR_TOTAL_LATENCY "TLat"
+#define ZSTR_VTX_FREQ "VFrq"
+#define ZSTR_VTX_PWR "VPwr"
+#define ZSTR_VTX_CHAN "VChn"
+#define ZSTR_VTX_BAND "VBan"
+#define ZSTR_SERVO_CURRENT "SrvA"
+#define ZSTR_SERVO_VOLTAGE "SrvV"
+#define ZSTR_SERVO_TEMPERATURE "SrvT"
+#define ZSTR_SERVO_STATUS "SrvS"
+#define ZSTR_LOSS "Loss"
+#define ZSTR_SPEED "Spd "
+#define ZSTR_FLOW "Flow"
diff --git a/radio/src/translations/nl.h.txt b/radio/src/translations/nl.h.txt
index 64af03eea..4aad255b2 100644
--- a/radio/src/translations/nl.h.txt
+++ b/radio/src/translations/nl.h.txt
@@ -234,10 +234,11 @@
#define TR_SF_SAFETY "---\0 "
#endif
-#define TR_SF_SCREENSHOT "Schermafdruk"
+#define TR_SF_SCREENSHOT "Schermafdr"
+#define TR_SF_RACING_MODE "RacingMode"
#define TR_SF_RESERVE "[reserve]\0"
-#define TR_VFSWFUNC TR_SF_SAFETY "Trainer\0 ""Inst. Trim""Reset\0 ""Set \0 " TR_ADJUST_GVAR "Volume\0 " "SetFailsfe" "RangeCheck" "ModuleBind" TR_SOUND TR_PLAY_TRACK TR_PLAY_VALUE TR_SF_RESERVE TR_SF_PLAY_SCRIPT TR_SF_RESERVE TR_SF_BG_MUSIC TR_VVARIO TR_HAPTIC TR_SDCLOGS "Backlight\0" TR_SF_SCREENSHOT TR_SF_TEST
+#define TR_VFSWFUNC TR_SF_SAFETY "Trainer\0 ""Inst. Trim""Reset\0 ""Set \0 " TR_ADJUST_GVAR "Volume\0 " "SetFailsfe" "RangeCheck" "ModuleBind" TR_SOUND TR_PLAY_TRACK TR_PLAY_VALUE TR_SF_RESERVE TR_SF_PLAY_SCRIPT TR_SF_RESERVE TR_SF_BG_MUSIC TR_VVARIO TR_HAPTIC TR_SDCLOGS "Backlight\0" TR_SF_SCREENSHOT TR_SF_RACING_MODE TR_SF_TEST
#define LEN_VFSWRESET TR("\004", "\012")
@@ -264,7 +265,7 @@
#define LEN_VUNITSSYSTEM TR("\006", "\010")
#define TR_VUNITSSYSTEM TR("Mtrsch""Engels", "Metrisch\0 ""Engels\0 ")
#define LEN_VTELEMUNIT "\003"
-#define TR_VTELEMUNIT "-\0 ""V\0 ""A\0 ""mA\0""kts""m/s""f/s""kmh""mph""m\0 ""ft\0""@C\0""@F\0""%\0 ""mAh""W\0 ""mW\0""dB\0""rpm""g\0 ""@\0 ""rad""ml\0""fOz"
+#define TR_VTELEMUNIT "-\0 ""V\0 ""A\0 ""mA\0""kts""m/s""f/s""kmh""mph""m\0 ""ft\0""@C\0""@F\0""%\0 ""mAh""W\0 ""mW\0""dB\0""rpm""g\0 ""@\0 ""rad""ml\0""fOz""mlm""Hz\0""mS\0""uS\0""km\0"
#define STR_V (STR_VTELEMUNIT+1)
#define STR_A (STR_VTELEMUNIT+4)
@@ -292,9 +293,15 @@
#if defined(PCBHORUS)
#define LEN_VKEYS "\005"
#define TR_VKEYS "PGUP\0""PGDN\0""ENTER""MDL\0 ""RTN\0 ""TELE\0""SYS\0 "
-#elif defined(RADIO_T12)
+#elif defined(RADIO_FAMILY_JUMPER_T12)
#define LEN_VKEYS "\005"
#define TR_VKEYS "Exit\0""Enter""Down\0""Up\0 ""Right""Left\0"
+#elif defined(RADIO_TX12)
+ #define LEN_VKEYS "\005"
+ #define TR_VKEYS "Exit\0""Enter""Up\0 ""Down\0""SYS\0 ""MDL\0 ""TELE\0"
+#elif defined(RADIO_T8)
+ #define LEN_VKEYS "\005"
+ #define TR_VKEYS "RTN\0 ""ENTER""PGUP\0""PGDN\0""SYS\0 ""MDL\0 ""UP\0 ""DOWN\0"
#elif defined(PCBTARANIS)
#define LEN_VKEYS "\005"
#define TR_VKEYS "Menu\0""Exit\0""Enter""Page\0""Plus\0""Minus"
@@ -433,13 +440,14 @@
#define TR_DISPLAY_TRIMS "Toon Trims"
#define TR_TTRACE TR("T-Source", INDENT "Source")
#define TR_TTRIM TR("T-Trim", INDENT "Trim Idle Only")
+#define TR_TTRIM_SW TR("T-Trim-Sw", INDENT "Trim switch")
#define TR_BEEPCTR TR("Ctr Beep", "Center Beep")
#define TR_USE_GLOBAL_FUNCS TR("Glob.Funcs", "Globale Functies")
#if defined(PCBSKY9X) && defined(REVX)
#define TR_OUTPUT_TYPE INDENT "Output"
#endif
-#define TR_PROTO TR(INDENT "Proto", INDENT "Protocol")
- #define TR_PPMFRAME INDENT "PPM frame"
+#define TR_PROTOCOL TR("Proto", "Protocol")
+#define TR_PPMFRAME INDENT "PPM frame"
#define TR_REFRESHRATE TR(INDENT "Refresh", INDENT "Refresh rate")
#define STR_WARN_BATTVOLTAGE TR(INDENT "Output is VBAT: ", INDENT "Warning: output level is VBAT: ")
#define TR_WARN_5VOLTS "Warning: output level is 5 volts"
@@ -523,6 +531,7 @@
#define TR_BEEPCOUNTDOWN INDENT "Countdown"
#define TR_PERSISTENT TR(INDENT "Vasth.", INDENT "Vasthouden")
#define TR_BACKLIGHT_LABEL "LCD-Verlichting"
+#define TR_GHOST_MENU_LABEL "GHOST MENU"
#define TR_BLDELAY INDENT "Duur"
#define TR_BLONBRIGHTNESS INDENT "Aan-Helderheid"
#define TR_BLOFFBRIGHTNESS INDENT "Uit-Helderheid"
@@ -638,6 +647,7 @@
#define TR_RECEIVER "Receiver"
#define TR_MULTI_RFTUNE TR("Freq tune", "RF Freq. fine tune")
#define TR_MULTI_RFPOWER "RF power"
+#define TR_MULTI_WBUS "Output"
#define TR_MULTI_TELEMETRY "Telemetry"
#define TR_MULTI_VIDFREQ TR("Vid. freq.", "Video frequency")
#define TR_RFPOWER "RF Power"
@@ -706,6 +716,7 @@
#define TR_NO_SDCARD "Geen SD-Kaart"
#define TR_WAITING_FOR_RX "Waiting for RX..."
#define TR_WAITING_FOR_TX "Waiting for TX..."
+#define TR_WAITING_FOR_MODULE TR("Waiting module", "Waiting for module...")
#define TR_NO_TOOLS "No tools available"
#define TR_NORMAL "Normal"
#define TR_NOT_INVERTED "Not inv"
@@ -781,7 +792,7 @@
#define TR_NO_MODELS_ON_SD "Geen Modellen" BREAKSPACE "op SD"
#define TR_NO_BITMAPS_ON_SD "Geen Bitmaps" BREAKSPACE "op SD"
#define TR_NO_SCRIPTS_ON_SD "Geen Scripts" BREAKSPACE "op SD"
-#define TR_SCRIPT_SYNTAX_ERROR "Script syntax error"
+#define TR_SCRIPT_SYNTAX_ERROR TR("Syntax error", "Script syntax error")
#define TR_SCRIPT_PANIC "Script panic"
#define TR_SCRIPT_KILLED "Script killed"
#define TR_SCRIPT_ERROR "Unknown error"
@@ -836,8 +847,10 @@
#define TR_FLASH_BOOTLOADER "Flash bootloader"
#define TR_FLASH_EXTERNAL_DEVICE "Flash extern Apparaat"
#define TR_FLASH_RECEIVER_OTA "Flash receiver OTA"
-#define TR_FLASH_RECEIVER_OTA_BY_EXTERNAL "Flash RX by ext. OTA"
-#define TR_FLASH_RECEIVER_OTA_BY_INTERNAL "Flash RX by int. OTA"
+#define TR_FLASH_RECEIVER_BY_EXTERNAL_MODULE_OTA "Flash RX by ext. OTA"
+#define TR_FLASH_RECEIVER_BY_INTERNAL_MODULE_OTA "Flash RX by int. OTA"
+#define TR_FLASH_FLIGHT_CONTROLLER_BY_EXTERNAL_MODULE_OTA "Flash FC by ext. OTA"
+#define TR_FLASH_FLIGHT_CONTROLLER_BY_INTERNAL_MODULE_OTA "Flash FC by int. OTA"
#define TR_FLASH_BLUETOOTH_MODULE TR("Flash BT module", "Flash Bluetooth module")
#define TR_FLASH_POWER_MANAGEMENT_UNIT "Flash pwr mngt unit"
#define TR_CURRENT_VERSION TR("Current vers. ", "Current version: ")
@@ -845,6 +858,7 @@
#define TR_FLASH_INTERNAL_MULTI TR("Flash Int. Multi", "Flash Internal Multi")
#define TR_FLASH_EXTERNAL_MODULE "Flash external module"
#define TR_FLASH_EXTERNAL_MULTI TR("Flash Ext. Multi", "Flash External Multi")
+#define TR_FLASH_EXTERNAL_ELRS TR("Flash Ext. ELRS", "Flash External ELRS")
#define TR_FIRMWARE_UPDATE_ERROR TR("FW update Error","Firmware update error")
#define TR_FIRMWARE_UPDATE_SUCCESS "Flash successful"
#define TR_WRITING "Schrijven..."
@@ -1042,7 +1056,7 @@
#define TR_LSW_HEADERS_V1 "Var1"
#define TR_LSW_HEADERS_V2 "Var2"
#define TR_LSW_HEADERS_ANDSW "EN-Schakelaar"
-#define TR_LSW_HEADERS_DURATION "Min. Duur"
+#define TR_LSW_HEADERS_DURATION "Duur"
#define TR_LSW_HEADERS_DELAY "Vertraging"
#define TR_GVAR_HEADERS_NAME "Name"
@@ -1113,10 +1127,18 @@
#define TR_ABOUT_MARTIN_1 "Martin Hotar"
#define TR_ABOUT_MARTIN_2 "Graphics designer"
-#if defined(PCBTARANIS) || defined(PCBHORUS)
- #define TR_ABOUT_HARDWARE_1 "FrSky"
- #define TR_ABOUT_HARDWARE_2 "Hardware designer/producer"
- #define TR_ABOUT_HARDWARE_3 "Firmware contributor"
+#if defined(MANUFACTURER_FRSKY)
+ #define TR_ABOUT_HARDWARE_1 "FrSky"
+ #define TR_ABOUT_HARDWARE_2 TR("Hardware design/producer", "Hardware designer/producer")
+ #define TR_ABOUT_HARDWARE_3 "Firmware contributor"
+#elif defined(MANUFACTURER_RADIOMASTER)
+ #define TR_ABOUT_HARDWARE_1 "Radiomaster"
+ #define TR_ABOUT_HARDWARE_2 TR("Hardware design/producer", "Hardware designer/producer")
+ #define TR_ABOUT_HARDWARE_3 "Firmware contributor"
+#elif defined(MANUFACTURER_JUMPER)
+ #define TR_ABOUT_HARDWARE_1 "JumperRC"
+ #define TR_ABOUT_HARDWARE_2 TR("Hardware design/producer", "Hardware designer/producer")
+ #define TR_ABOUT_HARDWARE_3 "Firmware contributor"
#else
#define TR_ABOUT_HARDWARE_1 "Brent Nelson"
#define TR_ABOUT_HARDWARE_2 "Sky9x designer/producer"
@@ -1192,6 +1214,9 @@
#define TR_ADDMAINVIEW "Add main view"
#define TR_BACKGROUND_COLOR "Background color"
#define TR_MAIN_COLOR "Main color"
+#define TR_BAR2_COLOR "Secondary bar color"
+#define TR_BAR1_COLOR "Main bar color"
+#define TR_TEXT_COLOR "Text color"
#define TR_TEXT_VIEWER "Text Viewer"
@@ -1214,6 +1239,7 @@
#define TR_JITTER_FILTER "ADC Filter"
#define TR_RTC_CHECK TR("Check RTC", "Check RTC voltage")
#define TR_AUTH_FAILURE "Auth-failure"
+#define TR_RACING_MODE "Racing mode"
#define ZSTR_VFR "VFR"
#define ZSTR_RSSI "RSSI"
@@ -1359,4 +1385,17 @@
#define ZSTR_CL15 "Cl15"
#define ZSTR_CL16 "Cl16"
#define ZSTR_CL17 "Cl17"
-#define ZSTR_CL18 "Cl18"
\ No newline at end of file
+#define ZSTR_CL18 "Cl18"
+#define ZSTR_FRAME_RATE "FRat"
+#define ZSTR_TOTAL_LATENCY "TLat"
+#define ZSTR_VTX_FREQ "VFrq"
+#define ZSTR_VTX_PWR "VPwr"
+#define ZSTR_VTX_CHAN "VChn"
+#define ZSTR_VTX_BAND "VBan"
+#define ZSTR_SERVO_CURRENT "SrvA"
+#define ZSTR_SERVO_VOLTAGE "SrvV"
+#define ZSTR_SERVO_TEMPERATURE "SrvT"
+#define ZSTR_SERVO_STATUS "SrvS"
+#define ZSTR_LOSS "Loss"
+#define ZSTR_SPEED "Spd "
+#define ZSTR_FLOW "Flow"
diff --git a/radio/src/translations/pl.h.txt b/radio/src/translations/pl.h.txt
index 5ba5bd258..8923a5bd0 100644
--- a/radio/src/translations/pl.h.txt
+++ b/radio/src/translations/pl.h.txt
@@ -235,9 +235,10 @@
#endif
#define TR_SF_SCREENSHOT "Zrzut Ekra"
+#define TR_SF_RACING_MODE "RacingMode"
#define TR_SF_RESERVE "[rezerwa]\0"
-#define TR_VFSWFUNC TR_SF_SAFETY "Trener \0 ""Inst-Trim ""Resetuj\0 ""Ustaw\0 " TR_ADJUST_GVAR "Głośność\0 " "SetFailsfe" "RangeCheck" "ModuleBind" TR_SOUND TR_PLAY_TRACK TR_PLAY_VALUE TR_SF_RESERVE TR_SF_PLAY_SCRIPT TR_SF_RESERVE TR_SF_BG_MUSIC TR_VVARIO TR_HAPTIC TR_SDCLOGS "Podświetl\0" TR_SF_SCREENSHOT TR_SF_TEST
+#define TR_VFSWFUNC TR_SF_SAFETY "Trener \0 ""Inst-Trim ""Resetuj\0 ""Ustaw\0 " TR_ADJUST_GVAR "Głośność\0 " "SetFailsfe" "RangeCheck" "ModuleBind" TR_SOUND TR_PLAY_TRACK TR_PLAY_VALUE TR_SF_RESERVE TR_SF_PLAY_SCRIPT TR_SF_RESERVE TR_SF_BG_MUSIC TR_VVARIO TR_HAPTIC TR_SDCLOGS "Podświetl\0" TR_SF_SCREENSHOT TR_SF_RACING_MODE TR_SF_TEST
#define LEN_VFSWRESET TR("\004", "\011") /*9 decimal*/
@@ -281,7 +282,7 @@
#define LEN_VUNITSSYSTEM TR("\006", "\010") /*8 decimal*/
#define TR_VUNITSSYSTEM TR("Metr. ""Imper.", "Metryczn""Imperial")
#define LEN_VTELEMUNIT "\003"
-#define TR_VTELEMUNIT "-\0 ""V\0 ""A\0 ""mA\0""kts""m/s""f/s""kmh""mph""m\0 ""ft\0""@C\0""@F\0""%\0 ""mAh""W\0 ""mW\0""dB\0""rpm""g\0 ""@\0 ""rad""ml\0""fOz"
+#define TR_VTELEMUNIT "-\0 ""V\0 ""A\0 ""mA\0""kts""m/s""f/s""kmh""mph""m\0 ""ft\0""@C\0""@F\0""%\0 ""mAh""W\0 ""mW\0""dB\0""rpm""g\0 ""@\0 ""rad""ml\0""fOz""mlm""Hz\0""mS\0""uS\0""km\0"
#define STR_V (STR_VTELEMUNIT+1)
#define STR_A (STR_VTELEMUNIT+4)
@@ -312,9 +313,15 @@
#elif defined(PCBXLITE)
#define LEN_VKEYS "\005"
#define TR_VKEYS "Shift""Exit\0""Enter""Down\0""Up\0 ""Right""Left\0"
-#elif defined(RADIO_T12)
+#elif defined(RADIO_FAMILY_JUMPER_T12)
#define LEN_VKEYS "\005"
#define TR_VKEYS "Exit\0""Enter""Down\0""Up\0 ""Right""Left\0"
+#elif defined(RADIO_TX12)
+ #define LEN_VKEYS "\005"
+ #define TR_VKEYS "Exit\0""Enter""Up\0 ""Down\0""SYS\0 ""MDL\0 ""TELE\0"
+#elif defined(RADIO_T8)
+ #define LEN_VKEYS "\005"
+ #define TR_VKEYS "RTN\0 ""ENTER""PGUP\0""PGDN\0""SYS\0 ""MDL\0 ""UP\0 ""DOWN\0"
#elif defined(PCBTARANIS)
#define LEN_VKEYS "\005"
#define TR_VKEYS "Menu\0""Exit\0""Enter""Page\0""Plus\0""Minus"
@@ -453,13 +460,14 @@
#define TR_DISPLAY_TRIMS TR("Pok.Trym.","Pokaż Trymery")
#define TR_TTRACE TR("Źród gaz", INDENT "Źródło gazu ")
#define TR_TTRIM TR("TryGaz", INDENT "TrymWolnObrotó")
+#define TR_TTRIM_SW TR("T-Trim-Sw", INDENT "Trim switch")
#define TR_BEEPCTR TR("ŚrodBeep", "Pikn.Środka")
#define TR_USE_GLOBAL_FUNCS TR("Funk.Glb.","Użyj Funkcji Glb")
#if defined(PCBSKY9X) && defined(REVX)
#define TR_OUTPUT_TYPE INDENT "Wyjście"
#endif
-#define TR_PROTO TR(INDENT "Proto", INDENT "Protokół")
- #define TR_PPMFRAME INDENT "Ramka PPM"
+#define TR_PROTOCOL TR("Proto", "Protokół")
+#define TR_PPMFRAME INDENT "Ramka PPM"
#define TR_REFRESHRATE TR(INDENT "Refresh", INDENT "Refresh rate")
#define STR_WARN_BATTVOLTAGE TR(INDENT "Output is VBAT: ", INDENT "Warning: output level is VBAT: ")
#define TR_WARN_5VOLTS "Warning: output level is 5 volts"
@@ -541,6 +549,7 @@
#define TR_BEEPCOUNTDOWN INDENT "Odliczanie"
#define TR_PERSISTENT TR(INDENT "Dokł.", INDENT "Dokładny")
#define TR_BACKLIGHT_LABEL "Podświetl"
+#define TR_GHOST_MENU_LABEL "GHOST MENU"
#define TR_BLDELAY INDENT"Czas trwania"
#define TR_BLONBRIGHTNESS INDENT"Jasnośc wł."
#define TR_BLOFFBRIGHTNESS INDENT"Jasność wył."
@@ -651,6 +660,7 @@
#define TR_RECEIVER INDENT "Receiver"
#define TR_MULTI_RFTUNE TR("Freq tune", "RF Freq. fine tune")
#define TR_MULTI_RFPOWER "RF power"
+#define TR_MULTI_WBUS "Output"
#define TR_MULTI_TELEMETRY "Telemetry"
#define TR_MULTI_VIDFREQ TR("Vid. freq.", "Video frequency")
#define TR_RFPOWER "RF Power"
@@ -719,6 +729,7 @@
#define TR_NO_SDCARD "Brak karty SD"
#define TR_WAITING_FOR_RX "Waiting for RX..."
#define TR_WAITING_FOR_TX "Waiting for TX..."
+#define TR_WAITING_FOR_MODULE TR("Waiting module", "Waiting for module...")
#define TR_NO_TOOLS "No tools available"
#define TR_NORMAL "Normal"
#define TR_NOT_INVERTED "Not inv"
@@ -794,7 +805,7 @@
#define TR_NO_MODELS_ON_SD "Brak modelu na SD"
#define TR_NO_BITMAPS_ON_SD "Brak obrazków na SD"
#define TR_NO_SCRIPTS_ON_SD "Brak skryptów na SD"
-#define TR_SCRIPT_SYNTAX_ERROR "Skrypt:syntax error"
+#define TR_SCRIPT_SYNTAX_ERROR TR("Syntax error", "Skrypt:syntax error")
#define TR_SCRIPT_PANIC "Skrypt:panic"
#define TR_SCRIPT_KILLED "Skrypt:killed"
#define TR_SCRIPT_ERROR "Nieznany błąd"
@@ -849,8 +860,10 @@
#define TR_FLASH_BOOTLOADER "Flash bootloader"
#define TR_FLASH_EXTERNAL_DEVICE "Sflashuj Moduł Zewnętrzny"
#define TR_FLASH_RECEIVER_OTA "Flash receiver OTA"
-#define TR_FLASH_RECEIVER_OTA_BY_EXTERNAL "Flash RX by ext. OTA"
-#define TR_FLASH_RECEIVER_OTA_BY_INTERNAL "Flash RX by int. OTA"
+#define TR_FLASH_RECEIVER_BY_EXTERNAL_MODULE_OTA "Flash RX by ext. OTA"
+#define TR_FLASH_RECEIVER_BY_INTERNAL_MODULE_OTA "Flash RX by int. OTA"
+#define TR_FLASH_FLIGHT_CONTROLLER_BY_EXTERNAL_MODULE_OTA "Flash FC by ext. OTA"
+#define TR_FLASH_FLIGHT_CONTROLLER_BY_INTERNAL_MODULE_OTA "Flash FC by int. OTA"
#define TR_FLASH_BLUETOOTH_MODULE TR("Flash BT module", "Flash Bluetooth module")
#define TR_FLASH_POWER_MANAGEMENT_UNIT "Flash pwr mngt unit"
#define TR_CURRENT_VERSION TR("Current vers. ", "Current version: ")
@@ -858,6 +871,7 @@
#define TR_FLASH_INTERNAL_MULTI TR("Flash Int. Multi", "Flash Internal Multi")
#define TR_FLASH_EXTERNAL_MODULE "Flash external module"
#define TR_FLASH_EXTERNAL_MULTI TR("Flash Ext. Multi", "Flash External Multi")
+#define TR_FLASH_EXTERNAL_ELRS TR("Flash Ext. ELRS", "Flash External ELRS")
#define TR_FIRMWARE_UPDATE_ERROR TR("FW update Error","Firmware update error")
#define TR_FIRMWARE_UPDATE_SUCCESS "Flash successful"
#define TR_WRITING "Zapis... "
@@ -1120,14 +1134,22 @@
#define TR_ABOUT_MARTIN_1 "Martin Hotar"
#define TR_ABOUT_MARTIN_2 "Projekty graficzne"
-#if defined(PCBTARANIS)
- #define TR_ABOUT_HARDWARE_1 "FrSky"
- #define TR_ABOUT_HARDWARE_2 "Proucent/projektant Hardware"
- #define TR_ABOUT_HARDWARE_3 "Współautor firmware"
+#if defined(MANUFACTURER_FRSKY)
+ #define TR_ABOUT_HARDWARE_1 "FrSky"
+ #define TR_ABOUT_HARDWARE_2 "Proucent/projektant Hardware"
+ #define TR_ABOUT_HARDWARE_3 "Współautor firmware"
+#elif defined(MANUFACTURER_RADIOMASTER)
+ #define TR_ABOUT_HARDWARE_1 "Radiomaster"
+ #define TR_ABOUT_HARDWARE_2 "Proucent/projektant Hardware"
+ #define TR_ABOUT_HARDWARE_3 "Współautor firmware"
+#elif defined(MANUFACTURER_JUMPER)
+ #define TR_ABOUT_HARDWARE_1 "JumperRC"
+ #define TR_ABOUT_HARDWARE_2 "Proucent/projektant Hardware"
+ #define TR_ABOUT_HARDWARE_3 "Współautor firmware"
#else
- #define TR_ABOUT_HARDWARE_1 "Brent Nelson"
- #define TR_ABOUT_HARDWARE_2 "Sky9x twórca/producent"
- #define TR_ABOUT_HARDWARE_3 ""
+ #define TR_ABOUT_HARDWARE_1 "Brent Nelson"
+ #define TR_ABOUT_HARDWARE_2 "Sky9x designer/výrobce"
+ #define TR_ABOUT_HARDWARE_3 ""
#endif
#define TR_ABOUT_PARENTS_1 "Projekty macierzyste"
@@ -1200,6 +1222,9 @@
#define TR_ADDMAINVIEW "Add main view"
#define TR_BACKGROUND_COLOR "Background color"
#define TR_MAIN_COLOR "Main color"
+#define TR_BAR2_COLOR "Secondary bar color"
+#define TR_BAR1_COLOR "Main bar color"
+#define TR_TEXT_COLOR "Text color"
#define TR_TEXT_VIEWER "Text Viewer"
#define TR_MENU_INPUTS "\314Wejści"
@@ -1221,6 +1246,7 @@
#define TR_JITTER_FILTER "ADC Filter"
#define TR_RTC_CHECK TR("Check RTC", "Check RTC voltage")
#define TR_AUTH_FAILURE "Auth-failure"
+#define TR_RACING_MODE "Racing mode"
#define ZSTR_VFR "VFR"
#define ZSTR_RSSI "RSSI"
@@ -1366,4 +1392,17 @@
#define ZSTR_CL15 "Cl15"
#define ZSTR_CL16 "Cl16"
#define ZSTR_CL17 "Cl17"
-#define ZSTR_CL18 "Cl18"
\ No newline at end of file
+#define ZSTR_CL18 "Cl18"
+#define ZSTR_FRAME_RATE "FRat"
+#define ZSTR_TOTAL_LATENCY "TLat"
+#define ZSTR_VTX_FREQ "VFrq"
+#define ZSTR_VTX_PWR "VPwr"
+#define ZSTR_VTX_CHAN "VChn"
+#define ZSTR_VTX_BAND "VBan"
+#define ZSTR_SERVO_CURRENT "SrvA"
+#define ZSTR_SERVO_VOLTAGE "SrvV"
+#define ZSTR_SERVO_TEMPERATURE "SrvT"
+#define ZSTR_SERVO_STATUS "SrvS"
+#define ZSTR_LOSS "Loss"
+#define ZSTR_SPEED "Spd "
+#define ZSTR_FLOW "Flow"
diff --git a/radio/src/translations/pt.h.txt b/radio/src/translations/pt.h.txt
index e07e3ca78..9b82bfdfa 100644
--- a/radio/src/translations/pt.h.txt
+++ b/radio/src/translations/pt.h.txt
@@ -231,9 +231,10 @@
#endif
#define TR_SF_SCREENSHOT "Screenshot"
+#define TR_SF_RACING_MODE "RacingMode"
#define TR_SF_RESERVE "[reserve]\0 "
-#define TR_VFSWFUNC TR_SF_SAFETY "Aprendiz\0 ""Ajuste Rapido""Reset\0 ""Set \0 " TR_ADJUST_GVAR "Volume\0 " "SetFailsafe\0 " "RangeCheck\0 " "ModuleBind\0 " TR_SOUND TR_PLAY_TRACK TR_PLAY_VALUE TR_SF_RESERVE TR_SF_PLAY_SCRIPT TR_SF_RESERVE TR_SF_BG_MUSIC TR_VVARIO TR_HAPTIC TR_SDCLOGS "Backlight\0 " TR_SF_SCREENSHOT TR_SF_TEST
+#define TR_VFSWFUNC TR_SF_SAFETY "Aprendiz\0 ""Ajuste Rapido""Reset\0 ""Set \0 " TR_ADJUST_GVAR "Volume\0 " "SetFailsafe\0 " "RangeCheck\0 " "ModuleBind\0 " TR_SOUND TR_PLAY_TRACK TR_PLAY_VALUE TR_SF_RESERVE TR_SF_PLAY_SCRIPT TR_SF_RESERVE TR_SF_BG_MUSIC TR_VVARIO TR_HAPTIC TR_SDCLOGS "Backlight\0 " TR_SF_SCREENSHOT TR_SF_RACING_MODE TR_SF_TEST
#define LEN_VFSWRESET TR("\004", "\011")
@@ -277,7 +278,7 @@
#define LEN_VUNITSSYSTEM TR("\006", "\010")
#define TR_VUNITSSYSTEM TR("Metric""Imper.", "Metric\0 ""Imperial")
#define LEN_VTELEMUNIT "\003"
- #define TR_VTELEMUNIT "-\0 ""V\0 ""A\0 ""mA\0""kts""m/s""f/s""kmh""mph""m\0 ""ft\0""@C\0""@F\0""%\0 ""mAh""W\0 ""mW\0""dB\0""rpm""g\0 ""@\0 ""rad""ml\0""fOz"
+ #define TR_VTELEMUNIT "-\0 ""V\0 ""A\0 ""mA\0""kts""m/s""f/s""kmh""mph""m\0 ""ft\0""@C\0""@F\0""%\0 ""mAh""W\0 ""mW\0""dB\0""rpm""g\0 ""@\0 ""rad""ml\0""fOz""mlm""Hz\0""mS\0""uS\0""km\0"
#define STR_V (STR_VTELEMUNIT+1)
#define STR_A (STR_VTELEMUNIT+4)
@@ -302,8 +303,25 @@
#define LEN_VSWASHTYPE "\004"
#define TR_VSWASHTYPE "--- ""120 ""120X""140 ""90\0"
-#define LEN_VKEYS "\005"
-#define TR_VKEYS TR("Menu\0""Sair\0""Desce""Sobe\0""Direi""Esqda", "Menu\0""Exit\0""Enter""Page\0""Plus\0""Minus")
+#if defined(PCBHORUS)
+ #define LEN_VKEYS "\005"
+ #define TR_VKEYS "PGUP\0""PGDN\0""ENTER""MDL\0 ""RTN\0 ""TELE\0""SYS\0 "
+#elif defined(RADIO_FAMILY_JUMPER_T12)
+ #define LEN_VKEYS "\005"
+ #define TR_VKEYS "Exit\0""Enter""Down\0""Up\0 ""Right""Left\0"
+#elif defined(RADIO_TX12)
+ #define LEN_VKEYS "\005"
+ #define TR_VKEYS "Exit\0""Enter""Up\0 ""Down\0""SYS\0 ""MDL\0 ""TELE\0"
+#elif defined(RADIO_T8)
+ #define LEN_VKEYS "\005"
+ #define TR_VKEYS "RTN\0 ""ENTER""PGUP\0""PGDN\0""SYS\0 ""MDL\0 ""UP\0 ""DOWN\0"
+#elif defined(PCBTARANIS)
+ #define LEN_VKEYS "\005"
+ #define TR_VKEYS "Menu\0""Exit\0""Enter""Page\0""Plus\0""Minus"
+#else
+ #define LEN_VKEYS "\005"
+ #define TR_VKEYS "Menu\0""Exit\0""Ned\0 ""Upp\0 ""Höger""Vänst"
+#endif
#define LEN_VSWITCHES "\003"
#define LEN_VSRCRAW "\004"
@@ -439,12 +457,13 @@
#define TR_DISPLAY_TRIMS "Display Trims"
#define TR_TTRACE TR("T-Trace", INDENT "T-Trace")
#define TR_TTRIM TR("T-Trim", INDENT "T-Trim")
+#define TR_TTRIM_SW TR("T-Trim-Sw", INDENT "Trim switch")
#define TR_BEEPCTR "Ctr Beep"
#define TR_USE_GLOBAL_FUNCS "Use Global Funcs"
#if defined(PCBSKY9X) && defined(REVX)
#define TR_OUTPUT_TYPE INDENT "Output"
#endif
-#define TR_PROTO INDENT"Proto"
+#define TR_PROTOCOL "Proto"
#define TR_PPMFRAME "PPM frame"
#define TR_REFRESHRATE TR(INDENT "Refresh", INDENT "Refresh rate")
#define STR_WARN_BATTVOLTAGE TR(INDENT "Output is VBAT: ", INDENT "Warning: output level is VBAT: ")
@@ -527,6 +546,7 @@
#define TR_BEEPCOUNTDOWN INDENT "Beep Regressivo"
#define TR_PERSISTENT INDENT "Persist."
#define TR_BACKLIGHT_LABEL "Backlight"
+#define TR_GHOST_MENU_LABEL "GHOST MENU"
#define TR_BLDELAY INDENT "Tempo Backlight"
#define TR_BLONBRIGHTNESS INDENT "ON Brightness"
#define TR_BLOFFBRIGHTNESS INDENT "OFF Brightness"
@@ -642,6 +662,7 @@
#define TR_SYNCMENU "Sync [MENU]"
#define TR_MULTI_RFTUNE TR("Freq tune", "RF Freq. fine tune")
#define TR_MULTI_RFPOWER "RF power"
+#define TR_MULTI_WBUS "Output"
#define TR_MULTI_TELEMETRY "Telemetry"
#define TR_MULTI_VIDFREQ TR("Vid. freq.", "Video frequency")
#define TR_RFPOWER "RF Power"
@@ -709,6 +730,7 @@
#define TR_NO_SDCARD "Sem SDCARD"
#define TR_WAITING_FOR_RX "Waiting for RX..."
#define TR_WAITING_FOR_TX "Waiting for TX..."
+#define TR_WAITING_FOR_MODULE TR("Waiting module", "Waiting for module...")
#define TR_NO_TOOLS "No tools available"
#define TR_NORMAL "Normal"
#define TR_NOT_INVERTED "Not inv"
@@ -784,7 +806,7 @@
#define TR_NO_MODELS_ON_SD "Sem Modelo no SD"
#define TR_NO_BITMAPS_ON_SD "No Bitmaps on SD"
#define TR_NO_SCRIPTS_ON_SD "No Scripts on SD"
-#define TR_SCRIPT_SYNTAX_ERROR "Script syntax error"
+#define TR_SCRIPT_SYNTAX_ERROR TR("Syntax error", "Script syntax error")
#define TR_SCRIPT_PANIC "Script panic"
#define TR_SCRIPT_KILLED "Script killed"
#define TR_SCRIPT_ERROR "Unknown error"
@@ -839,8 +861,10 @@
#define TR_FLASH_BOOTLOADER "Flash bootloader"
#define TR_FLASH_EXTERNAL_DEVICE "Flash External Device"
#define TR_FLASH_RECEIVER_OTA "Flash receiver OTA"
-#define TR_FLASH_RECEIVER_OTA_BY_EXTERNAL "Flash RX by ext. OTA"
-#define TR_FLASH_RECEIVER_OTA_BY_INTERNAL "Flash RX by int. OTA"
+#define TR_FLASH_RECEIVER_BY_EXTERNAL_MODULE_OTA "Flash RX by ext. OTA"
+#define TR_FLASH_RECEIVER_BY_INTERNAL_MODULE_OTA "Flash RX by int. OTA"
+#define TR_FLASH_FLIGHT_CONTROLLER_BY_EXTERNAL_MODULE_OTA "Flash FC by ext. OTA"
+#define TR_FLASH_FLIGHT_CONTROLLER_BY_INTERNAL_MODULE_OTA "Flash FC by int. OTA"
#define TR_FLASH_BLUETOOTH_MODULE TR("Flash BT module", "Flash Bluetooth module")
#define TR_FLASH_POWER_MANAGEMENT_UNIT "Flash pwr mngt unit"
#define TR_CURRENT_VERSION TR("Current vers. ", "Current version: ")
@@ -848,6 +872,7 @@
#define TR_FLASH_INTERNAL_MULTI TR("Flash Int. Multi", "Flash Internal Multi")
#define TR_FLASH_EXTERNAL_MODULE "Flash external module"
#define TR_FLASH_EXTERNAL_MULTI TR("Flash Ext. Multi", "Flash External Multi")
+#define TR_FLASH_EXTERNAL_ELRS TR("Flash Ext. ELRS", "Flash External ELRS")
#define TR_FIRMWARE_UPDATE_ERROR TR("FW update Error","Firmware update error")
#define TR_FIRMWARE_UPDATE_SUCCESS "Flash successful"
#define TR_WRITING "Writing..."
@@ -1039,7 +1064,7 @@
#define TR_LSW_HEADERS_V1 "V1"
#define TR_LSW_HEADERS_V2 "V2"
#define TR_LSW_HEADERS_ANDSW "AND Switch"
-#define TR_LSW_HEADERS_DURATION "Min Duration"
+#define TR_LSW_HEADERS_DURATION "Duration"
#define TR_LSW_HEADERS_DELAY "Delay"
#define TR_GVAR_HEADERS_NAME "Name"
@@ -1110,10 +1135,18 @@
#define TR_ABOUT_MARTIN_1 "Martin Hotar"
#define TR_ABOUT_MARTIN_2 "Graphics designer"
-#if defined(PCBTARANIS)
- #define TR_ABOUT_HARDWARE_1 "FrSky"
- #define TR_ABOUT_HARDWARE_2 "Hardware designer/producer"
- #define TR_ABOUT_HARDWARE_3 "Firmware contributor"
+#if defined(MANUFACTURER_FRSKY)
+ #define TR_ABOUT_HARDWARE_1 "FrSky"
+ #define TR_ABOUT_HARDWARE_2 TR("Hardware design/producer", "Hardware designer/producer")
+ #define TR_ABOUT_HARDWARE_3 "Firmware contributor"
+#elif defined(MANUFACTURER_RADIOMASTER)
+ #define TR_ABOUT_HARDWARE_1 "Radiomaster"
+ #define TR_ABOUT_HARDWARE_2 TR("Hardware design/producer", "Hardware designer/producer")
+ #define TR_ABOUT_HARDWARE_3 "Firmware contributor"
+#elif defined(MANUFACTURER_JUMPER)
+ #define TR_ABOUT_HARDWARE_1 "JumperRC"
+ #define TR_ABOUT_HARDWARE_2 TR("Hardware design/producer", "Hardware designer/producer")
+ #define TR_ABOUT_HARDWARE_3 "Firmware contributor"
#else
#define TR_ABOUT_HARDWARE_1 "Brent Nelson"
#define TR_ABOUT_HARDWARE_2 "Sky9x designer/producer"
@@ -1189,6 +1222,9 @@
#define TR_ADDMAINVIEW "Add main view"
#define TR_BACKGROUND_COLOR "Background color"
#define TR_MAIN_COLOR "Main color"
+#define TR_BAR2_COLOR "Secondary bar color"
+#define TR_BAR1_COLOR "Main bar color"
+#define TR_TEXT_COLOR "Text color"
#define TR_TEXT_VIEWER "Text Viewer"
#define TR_MENU_INPUTS "\314Inputs"
@@ -1209,8 +1245,8 @@
#define TR_MENU_INVERT "Invert"
#define TR_JITTER_FILTER "ADC Filter"
#define TR_RTC_CHECK TR("Check RTC", "Check RTC voltage")
-#define TR_AUTH_FAILURE "Auth-failure"
-
+#define TR_AUTH_FAILURE "Auth-failure"
+#define TR_RACING_MODE "Racing mode"
#define ZSTR_VFR "VFR"
#define ZSTR_RSSI "RSSI"
#define ZSTR_R9PW "R9PW"
@@ -1355,4 +1391,17 @@
#define ZSTR_CL15 "Cl15"
#define ZSTR_CL16 "Cl16"
#define ZSTR_CL17 "Cl17"
-#define ZSTR_CL18 "Cl18"
\ No newline at end of file
+#define ZSTR_CL18 "Cl18"
+#define ZSTR_FRAME_RATE "FRat"
+#define ZSTR_TOTAL_LATENCY "TLat"
+#define ZSTR_VTX_FREQ "VFrq"
+#define ZSTR_VTX_PWR "VPwr"
+#define ZSTR_VTX_CHAN "VChn"
+#define ZSTR_VTX_BAND "VBan"
+#define ZSTR_SERVO_CURRENT "SrvA"
+#define ZSTR_SERVO_VOLTAGE "SrvV"
+#define ZSTR_SERVO_TEMPERATURE "SrvT"
+#define ZSTR_SERVO_STATUS "SrvS"
+#define ZSTR_LOSS "Loss"
+#define ZSTR_SPEED "Spd "
+#define ZSTR_FLOW "Flow"
diff --git a/radio/src/translations/se.h.txt b/radio/src/translations/se.h.txt
index c55d64650..1b13ffb8f 100644
--- a/radio/src/translations/se.h.txt
+++ b/radio/src/translations/se.h.txt
@@ -231,10 +231,11 @@
#define TR_SF_SAFETY "---\0 "
#endif
-#define TR_SF_SCREENSHOT "Skärmbild"
+#define TR_SF_SCREENSHOT "Skärmbild\0"
+#define TR_SF_RACING_MODE "RacingMode"
#define TR_SF_RESERVE "[reserve]\0"
-#define TR_VFSWFUNC TR_SF_SAFETY "Trainer\0 ""Sätt Trim\0""Nollställ\0""Sätt\0 " TR_ADJUST_GVAR "Volym\0 " "SetFailsfe" "RangeCheck" "ModuleBind" TR_SOUND TR_PLAY_TRACK TR_PLAY_VALUE TR_SF_RESERVE TR_SF_PLAY_SCRIPT TR_SF_RESERVE TR_SF_BG_MUSIC TR_VVARIO TR_HAPTIC TR_SDCLOGS "Belysning\0" TR_SF_SCREENSHOT TR_SF_TEST
+#define TR_VFSWFUNC TR_SF_SAFETY "Trainer\0 ""Sätt Trim\0""Nollställ\0""Sätt\0 " TR_ADJUST_GVAR "Volym\0 " "SetFailsfe" "RangeCheck" "ModuleBind" TR_SOUND TR_PLAY_TRACK TR_PLAY_VALUE TR_SF_RESERVE TR_SF_PLAY_SCRIPT TR_SF_RESERVE TR_SF_BG_MUSIC TR_VVARIO TR_HAPTIC TR_SDCLOGS "Belysning\0" TR_SF_SCREENSHOT TR_SF_RACING_MODE TR_SF_TEST
#define LEN_VFSWRESET TR("\004", "\011")
@@ -278,7 +279,7 @@
#define LEN_VUNITSSYSTEM TR("\006", "\010")
#define TR_VUNITSSYSTEM TR("Metri.""Imper.", "Metriska""Imperial")
#define LEN_VTELEMUNIT "\003"
-#define TR_VTELEMUNIT "-\0 ""V\0 ""A\0 ""mA\0""kts""m/s""f/s""kmh""mph""m\0 ""ft\0""@C\0""@F\0""%\0 ""mAh""W\0 ""mW\0""dB\0""rpm""g\0 ""@\0 ""rad""ml\0""fOz"
+#define TR_VTELEMUNIT "-\0 ""V\0 ""A\0 ""mA\0""kts""m/s""f/s""kmh""mph""m\0 ""ft\0""@C\0""@F\0""%\0 ""mAh""W\0 ""mW\0""dB\0""rpm""g\0 ""@\0 ""rad""ml\0""fOz""mlm""Hz\0""mS\0""uS\0""km\0"
#define STR_V (STR_VTELEMUNIT+1)
#define STR_A (STR_VTELEMUNIT+4)
@@ -304,11 +305,17 @@
#define TR_VSWASHTYPE "--- ""120 ""120X""140 ""90\0 "
#if defined(PCBHORUS)
- #define LEN_VKEYS "\005"
- #define TR_VKEYS "PGUP\0""PGDN\0""ENTER""MDL\0 ""RTN\0 ""TELE\0""SYS\0 "
-#elif defined(RADIO_T12)
+ #define LEN_VKEYS "\005"
+ #define TR_VKEYS "PGUP\0""PGDN\0""ENTER""MDL\0 ""RTN\0 ""TELE\0""SYS\0 "
+#elif defined(RADIO_FAMILY_JUMPER_T12)
#define LEN_VKEYS "\005"
#define TR_VKEYS "Exit\0""Enter""Down\0""Up\0 ""Right""Left\0"
+#elif defined(RADIO_TX12)
+ #define LEN_VKEYS "\005"
+ #define TR_VKEYS "Exit\0""Enter""Up\0 ""Down\0""SYS\0 ""MDL\0 ""TELE\0"
+#elif defined(RADIO_T8)
+ #define LEN_VKEYS "\005"
+ #define TR_VKEYS "RTN\0 ""ENTER""PGUP\0""PGDN\0""SYS\0 ""MDL\0 ""UP\0 ""DOWN\0"
#elif defined(PCBTARANIS)
#define LEN_VKEYS "\005"
#define TR_VKEYS "Menu\0""Exit\0""Enter""Page\0""Plus\0""Minus"
@@ -452,13 +459,14 @@
#define TR_DISPLAY_TRIMS "Display Trims"
#define TR_TTRACE TR("Följ Gas", INDENT "Följ Gas")
#define TR_TTRIM TR("Gastrim", INDENT "Gastrim")
+#define TR_TTRIM_SW TR("T-Trim-Sw", INDENT "Trim switch")
#define TR_BEEPCTR TR("Cent.pip", "Centerpip")
#define TR_USE_GLOBAL_FUNCS TR("Glob.Funkt", "Använd Global Funk.")
#if defined(PCBSKY9X) && defined(REVX)
#define TR_OUTPUT_TYPE INDENT "Output"
#endif
-#define TR_PROTO TR(INDENT "Proto", INDENT "Protokoll")
- #define TR_PPMFRAME INDENT "PPM-paket"
+#define TR_PROTOCOL TR("Proto", "Protokoll")
+#define TR_PPMFRAME INDENT "PPM-paket"
#define TR_REFRESHRATE TR(INDENT "Refresh", INDENT "Refresh rate")
#define STR_WARN_BATTVOLTAGE TR(INDENT "Output is VBAT: ", INDENT "Warning: output level is VBAT: ")
#define TR_WARN_5VOLTS "Warning: output level is 5 volts"
@@ -540,6 +548,7 @@
#define TR_BEEPCOUNTDOWN INDENT "Nedräkning"
#define TR_PERSISTENT TR("Jämt på ", INDENT"Alltid På")
#define TR_BACKLIGHT_LABEL "Belysning"
+#define TR_GHOST_MENU_LABEL "GHOST MENU"
#define TR_BLDELAY INDENT "Av efter"
#define TR_BLONBRIGHTNESS INDENT "På Ljusstyrka"
#define TR_BLOFFBRIGHTNESS INDENT "Av Ljusstyrka"
@@ -651,6 +660,7 @@
#define TR_SYNCMENU "Synk [MENU]"
#define TR_MULTI_RFTUNE TR("Freq tune", "RF Freq. fine tune")
#define TR_MULTI_RFPOWER "RF power"
+#define TR_MULTI_WBUS "Output"
#define TR_MULTI_TELEMETRY "Telemetry"
#define TR_MULTI_VIDFREQ TR("Vid. freq.", "Video frequency")
#define TR_RFPOWER "RF Power"
@@ -718,6 +728,7 @@
#define TR_NO_SDCARD "SDCARD saknas"
#define TR_WAITING_FOR_RX "Waiting for RX..."
#define TR_WAITING_FOR_TX "Waiting for TX..."
+#define TR_WAITING_FOR_MODULE TR("Waiting module", "Waiting for module...")
#define TR_NO_TOOLS "No tools available"
#define TR_NORMAL "Normal"
#define TR_NOT_INVERTED "Not inv"
@@ -794,7 +805,7 @@
#define TR_NO_MODELS_ON_SD "Ingen modell i SD"
#define TR_NO_BITMAPS_ON_SD "Ikoner saknas på SD"
#define TR_NO_SCRIPTS_ON_SD "Programkod saknas på SD"
-#define TR_SCRIPT_SYNTAX_ERROR "Script syntax error"
+#define TR_SCRIPT_SYNTAX_ERROR TR("Syntax error", "Script syntax error")
#define TR_SCRIPT_PANIC "Script panic"
#define TR_SCRIPT_KILLED "Script killed"
#define TR_SCRIPT_ERROR "Unknown error"
@@ -849,8 +860,10 @@
#define TR_FLASH_BOOTLOADER "Skriv BootLoader"
#define TR_FLASH_EXTERNAL_DEVICE "Flash External Device"
#define TR_FLASH_RECEIVER_OTA "Flash receiver OTA"
-#define TR_FLASH_RECEIVER_OTA_BY_EXTERNAL "Flash RX by ext. OTA"
-#define TR_FLASH_RECEIVER_OTA_BY_INTERNAL "Flash RX by int. OTA"
+#define TR_FLASH_RECEIVER_BY_EXTERNAL_MODULE_OTA "Flash RX by ext. OTA"
+#define TR_FLASH_RECEIVER_BY_INTERNAL_MODULE_OTA "Flash RX by int. OTA"
+#define TR_FLASH_FLIGHT_CONTROLLER_BY_EXTERNAL_MODULE_OTA "Flash FC by ext. OTA"
+#define TR_FLASH_FLIGHT_CONTROLLER_BY_INTERNAL_MODULE_OTA "Flash FC by int. OTA"
#define TR_FLASH_BLUETOOTH_MODULE TR("Flash BT module", "Flash Bluetooth module")
#define TR_FLASH_POWER_MANAGEMENT_UNIT "Flash pwr mngt unit"
#define TR_CURRENT_VERSION TR("Current vers. ", "Current version: ")
@@ -858,6 +871,7 @@
#define TR_FLASH_INTERNAL_MULTI TR("Flash Int. Multi", "Flash Internal Multi")
#define TR_FLASH_EXTERNAL_MODULE "Flash external module"
#define TR_FLASH_EXTERNAL_MULTI TR("Flash Ext. Multi", "Flash External Multi")
+#define TR_FLASH_EXTERNAL_ELRS TR("Flash Ext. ELRS", "Flash External ELRS")
#define TR_FIRMWARE_UPDATE_ERROR TR("FW update Error","Firmware update error")
#define TR_FIRMWARE_UPDATE_SUCCESS "Flash successful"
#define TR_WRITING "Skriver..."
@@ -1120,10 +1134,18 @@
#define TR_ABOUT_MARTIN_1 "Martin Hotar"
#define TR_ABOUT_MARTIN_2 "Grafikdesigner"
-#if defined(PCBTARANIS) || defined(PCBHORUS)
+#if defined(MANUFACTURER_FRSKY)
#define TR_ABOUT_HARDWARE_1 "FrSky"
#define TR_ABOUT_HARDWARE_2 "Hårdvarudesign/producent"
#define TR_ABOUT_HARDWARE_3 ""
+#elif defined(MANUFACTURER_RADIOMASTER)
+ #define TR_ABOUT_HARDWARE_1 "Radiomaster"
+ #define TR_ABOUT_HARDWARE_2 "Hårdvarudesign/producent"
+ #define TR_ABOUT_HARDWARE_3 ""
+#elif defined(MANUFACTURER_JUMPER)
+ #define TR_ABOUT_HARDWARE_1 "JumperRC"
+ #define TR_ABOUT_HARDWARE_2 "Hårdvarudesign/producent"
+ #define TR_ABOUT_HARDWARE_3 ""
#else
#define TR_ABOUT_HARDWARE_1 "Brent Nelson"
#define TR_ABOUT_HARDWARE_2 "Sky9x design/producent"
@@ -1200,6 +1222,9 @@
#define TR_ADDMAINVIEW "Add main view"
#define TR_BACKGROUND_COLOR "Background color"
#define TR_MAIN_COLOR "Main color"
+#define TR_BAR2_COLOR "Secondary bar color"
+#define TR_BAR1_COLOR "Main bar color"
+#define TR_TEXT_COLOR "Text color"
#define TR_TEXT_VIEWER "Text Viewer"
#define TR_MENU_INPUTS "\314Inputs"
@@ -1221,6 +1246,7 @@
#define TR_JITTER_FILTER "ADC Filter"
#define TR_RTC_CHECK TR("Check RTC", "Check RTC voltage")
#define TR_AUTH_FAILURE "Auth-failure"
+#define TR_RACING_MODE "Racing mode"
#define ZSTR_VFR "VFR"
#define ZSTR_RSSI "RSSI"
@@ -1366,4 +1392,17 @@
#define ZSTR_CL15 "Cl15"
#define ZSTR_CL16 "Cl16"
#define ZSTR_CL17 "Cl17"
-#define ZSTR_CL18 "Cl18"
\ No newline at end of file
+#define ZSTR_CL18 "Cl18"
+#define ZSTR_FRAME_RATE "FRat"
+#define ZSTR_TOTAL_LATENCY "TLat"
+#define ZSTR_VTX_FREQ "VFrq"
+#define ZSTR_VTX_PWR "VPwr"
+#define ZSTR_VTX_CHAN "VChn"
+#define ZSTR_VTX_BAND "VBan"
+#define ZSTR_SERVO_CURRENT "SrvA"
+#define ZSTR_SERVO_VOLTAGE "SrvV"
+#define ZSTR_SERVO_TEMPERATURE "SrvT"
+#define ZSTR_SERVO_STATUS "SrvS"
+#define ZSTR_LOSS "Loss"
+#define ZSTR_SPEED "Spd "
+#define ZSTR_FLOW "Flow"
diff --git a/radio/src/translations/untranslated.h b/radio/src/translations/untranslated.h
index 32acdcb84..a758b1a31 100644
--- a/radio/src/translations/untranslated.h
+++ b/radio/src/translations/untranslated.h
@@ -41,9 +41,12 @@
#elif defined(PCBXLITE)
#define TR_POTS_VSRCRAW "\310S1\0""\310S2\0"
#define TR_SW_VSRCRAW "\312SA\0""\312SB\0""\312SC\0""\312SD\0""\312SE\0""\312SF\0"
-#elif defined(RADIO_T12)
+#elif defined(RADIO_FAMILY_JUMPER_T12)
#define TR_POTS_VSRCRAW "\310S1\0""\310S2\0"
#define TR_SW_VSRCRAW "\312SA\0""\312SB\0""\312SC\0""\312SD\0""\312SG\0""\312SH\0""\312SI\0""\312SJ\0"
+#elif defined(RADIO_TX12)
+ #define TR_POTS_VSRCRAW "\310S1\0""\310S2\0"
+ #define TR_SW_VSRCRAW "\312SA\0""\312SB\0""\312SC\0""\312SD\0""\312SE\0""\312SF\0""\312SI\0""\312SJ\0"
#elif defined(PCBX7)
#define TR_POTS_VSRCRAW "\310S1\0""\310S2\0"
#define TR_SW_VSRCRAW "\312SA\0""\312SB\0""\312SC\0""\312SD\0""\312SF\0""\312SH\0""\312SI\0""\312SJ\0"
@@ -87,7 +90,7 @@
#endif
#define LEN_EXTERNAL_MODULE_PROTOCOLS "\014"
-#define TR_EXTERNAL_MODULE_PROTOCOLS "OFF\0 ""PPM\0 ""XJT\0 ""ISRM\0 ""DSM2\0 ""CRSF\0 ""MULTI\0 ""R9M\0 ""R9M ACCESS\0 " TR_MODULE_R9M_LITE "R9ML ACCESS\0""R9MLP\0 ""R9MLP ACCESS""SBUS\0 ""XJT Lite\0 ""AFHDS3"
+#define TR_EXTERNAL_MODULE_PROTOCOLS "OFF\0 ""PPM\0 ""XJT\0 ""ISRM\0 ""DSM2\0 ""CRSF\0 ""MULTI\0 ""R9M\0 ""R9M ACCESS\0 " TR_MODULE_R9M_LITE "R9ML ACCESS\0""GHST\0 ""R9MLP ACCESS""SBUS\0 ""XJT Lite\0 ""AFHDS3\0 "
#define LEN_INTERNAL_MODULE_PROTOCOLS LEN_EXTERNAL_MODULE_PROTOCOLS
#define TR_INTERNAL_MODULE_PROTOCOLS TR_EXTERNAL_MODULE_PROTOCOLS
@@ -106,6 +109,9 @@
#define LEN_R9M_PXX2_RF_PROTOCOLS "\006"
#define TR_R9M_PXX2_RF_PROTOCOLS "ACCESS""FCC\0 ""EU\0 ""Flex"
+#define LEN_SPORT_MODES "\014"
+#define TR_SPORT_MODES "S.PORT\0 ""F.PORT\0 ""FBUS(FPORT2)"
+
#define LEN_R9M_REGION "\006"
#define TR_R9M_REGION "FCC\0 ""EU\0 ""868MHz""915MHz"
@@ -125,10 +131,16 @@
#define TR_DSM_PROTOCOLS "LP45""DSM2""DSMX"
#define LEN_MULTI_PROTOCOLS "\007"
-#define TR_MULTI_PROTOCOLS "FlySky\0""Hubsan\0""FrSky\0 ""Hisky\0 ""V2x2\0 ""DSM\0 ""Devo\0 ""YD717\0 ""KN\0 ""SymaX\0 ""SLT\0 ""CX10\0 ""CG023\0 ""Bayang\0""ESky\0 ""MT99XX\0""MJXq\0 ""Shenqi\0""FY326\0 ""SFHSS\0 ""J6 Pro\0""FQ777\0 ""Assan\0 ""Hontai\0""OpenLrs""FlSky2A""Q2x2\0 ""Walkera""Q303\0 ""GW008\0 ""DM002\0 ""Cabell\0""Esky150""H8 3D\0 ""Corona\0""CFlie\0 ""Hitec\0 ""WFly\0 ""Bugs\0 ""BugMini""Traxxas""NCC1701""E01X\0 ""V911S\0 ""GD00X\0 ""V761\0 ""KF606\0 ""Redpine""Potensi""ZSX\0 ""FlyZone""Scanner""FrSkyRX""FS2A_RX""HoTT\0 ""FX816\0 ""BayanRX""Pelikan""Tiger\0 ""XK\0 ""XN297DU""FrSkyX2""FrSkyR9""Propel\0""FrSkyL\0""Skyarte""ESky-v2""DSM RX\0""JJRC345""Q90C\0 "
+#define TR_MULTI_PROTOCOLS "FlySky\0""Hubsan\0""FrSky\0 ""Hisky\0 ""V2x2\0 ""DSM\0 ""Devo\0 ""YD717\0 ""KN\0 ""SymaX\0 ""SLT\0 ""CX10\0 ""CG023\0 ""Bayang\0""ESky\0 ""MT99XX\0""MJXq\0 ""Shenqi\0""FY326\0 ""Futaba\0""J6 Pro\0""FQ777\0 ""Assan\0 ""Hontai\0""OpenLrs""FlSky2A""Q2x2\0 ""Walkera""Q303\0 ""GW008\0 ""DM002\0 ""Cabell\0""Esky150""H8 3D\0 ""Corona\0""CFlie\0 ""Hitec\0 ""WFly\0 ""Bugs\0 ""BugMini""Traxxas""NCC1701""E01X\0 ""V911S\0 ""GD00X\0 ""V761\0 ""KF606\0 ""Redpine""Potensi""ZSX\0 ""Height\0""Scanner""FrSkyRX""FS2A_RX""HoTT\0 ""FX816\0 ""BayanRX""Pelikan""Tiger\0 ""XK\0 ""XN297DU""FrSkyX2""FrSkyR9""Propel\0""FrSkyL\0""Skyartc""ESky-v2""DSM RX\0""JJRC345""Q90C\0 ""Kyosho\0""RadLink""ExpLRS\0""Realacc""OMP\0 ""M-Link\0""Wfly 2\0""E016Hv2"
#define LEN_MULTI_POWER "\005"
-#define TR_MULTI_POWER "10mW\0""25mW\0""50mW\0""100mW""200mW""300mW""500mW""1W\0 ""2W\0 "
+#define TR_MULTI_POWER "1.6mW""2.0mW""2.5mW""3.2mW""4.0mW""5.0mW""6.3mW""7.9mW""10mW\0""13mW\0""16mW\0""20mW\0""25mW\0""32mW\0""40mW\0""50mW\0"
+
+#define LEN_MULTI_WBUS_MODE "\004"
+#define TR_MULTI_WBUS_MODE "WBUS""PPM\0"
+
+#define LEN_MULTI_TELEMETRY_MODE "\007"
+#define TR_MULTI_TELEMETRY_MODE "Off\0 ""On\0 ""Off+Aux""On+Aux\0"
#define LEN_AFHDS3_PROTOCOLS "\x008"
#define TR_AFHDS3_PROTOCOLS "PWM/IBUS""PWM/SBUS""PPM/IBUS""PPM/SBUS"
diff --git a/radio/util/build-firmware.py b/radio/util/build-firmware.py
index c27e6b58a..5d577092c 100755
--- a/radio/util/build-firmware.py
+++ b/radio/util/build-firmware.py
@@ -93,13 +93,11 @@ def main():
maxsize = 65536 * 8
elif options[optcount] == "x7":
cmake_options["PCB"] = "X7"
- cmake_options["AFHDS3"] = "YES"
firmware_options = options_taranis_x7
maxsize = 65536 * 8
elif options[optcount] == "x7access":
cmake_options["PCB"] = "X7"
cmake_options["PCBREV"] = "ACCESS"
- cmake_options["AFHDS3"] = "YES"
firmware_options = options_taranis_x7
maxsize = 65536 * 8
elif board_name == "xlite":
@@ -121,7 +119,6 @@ def main():
elif board_name == "x9d+2019":
cmake_options["PCB"] = "X9D+"
cmake_options["PCBREV"] = "2019"
- cmake_options["AFHDS3"] = "YES"
firmware_options = options_taranis_x9dp
maxsize = 65536 * 8
elif board_name == "x9e":
@@ -141,11 +138,26 @@ def main():
cmake_options["PCB"] = "X12S"
firmware_options = options_horus_x12s
maxsize = 2 * 1024 * 1024
+ elif board_name == "tlite":
+ cmake_options["PCB"] = "X7"
+ cmake_options["PCBREV"] = "TLITE"
+ firmware_options = options_jumper_tlite
+ maxsize = 65536 * 8
elif board_name == "t12":
cmake_options["PCB"] = "X7"
cmake_options["PCBREV"] = "T12"
firmware_options = options_jumper_t12
maxsize = 65536 * 8
+ elif board_name == "tx12":
+ cmake_options["PCB"] = "X7"
+ cmake_options["PCBREV"] = "TX12"
+ firmware_options = options_radiomaster_tx12
+ maxsize = 65536 * 8
+ elif board_name == "t8":
+ cmake_options["PCB"] = "X7"
+ cmake_options["PCBREV"] = "T8"
+ firmware_options = options_radiomaster_t8
+ maxsize = 65536 * 8
elif board_name == "t16":
cmake_options["PCB"] = "X10"
cmake_options["PCBREV"] = "T16"
diff --git a/radio/util/font2png.py b/radio/util/font2png.py
index 169b6b63f..b83505a0c 100755
--- a/radio/util/font2png.py
+++ b/radio/util/font2png.py
@@ -77,6 +77,12 @@ def createFontBitmap(filename, fontname, fontsize, fontoffset, foreground, backg
image.paste(extraImage.copy(),(width,1))
elif c == " ":
pass
+ elif c == "j" and fontsize == 32:
+ w, h = font.getsize(c)
+ draw.text((width + 2, fontoffset), c, fill=foreground, font=font)
+ elif c == "j" and fontsize == 64:
+ aw, h = font.getsize(c)
+ draw.text((width + 3, fontoffset), c, fill=foreground, font=font)
else:
w, h = font.getsize(c)
draw.text((width + 1, fontoffset), c, fill=foreground, font=font)
diff --git a/radio/util/fwoptions.py b/radio/util/fwoptions.py
index 140cf4b47..2349bdd18 100755
--- a/radio/util/fwoptions.py
+++ b/radio/util/fwoptions.py
@@ -177,6 +177,7 @@ options_horus_x12s = {
"pcbdev": ("PCBREV", "10", None),
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None),
"internalaccess": [("INTERNAL_MODULE_PXX1", "NO", None), ("INTERNAL_MODULE_PXX2", "YES", None)],
+ "externalaccessmod": ("HARDWARE_EXTERNAL_ACCESS_MOD", "YES", "NO"),
}
options_horus_x10 = {
@@ -190,6 +191,7 @@ options_horus_x10 = {
"eu": ("MODULE_PROTOCOL_D8", "NO", "YES"),
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None),
"internalaccess": [("INTERNAL_MODULE_PXX1", "NO", None), ("INTERNAL_MODULE_PXX2", "YES", None)],
+ "externalaccessmod": ("HARDWARE_EXTERNAL_ACCESS_MOD", "YES", "NO"),
}
options_horus_x10express = {
@@ -205,6 +207,18 @@ options_horus_x10express = {
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None),
}
+options_jumper_tlite = {
+ "noheli": ("HELI", "NO", "YES"),
+ "ppmus": ("PPM_UNIT", "US", "PERCENT_PREC1"),
+ "lua": ("LUA", "YES", "NO_MODEL_SCRIPTS"),
+ "nogvars": ("GVARS", "NO", "YES"),
+ "faimode": ("FAI", "YES", None),
+ "faichoice": ("FAI", "CHOICE", None),
+ "nooverridech": ("OVERRIDE_CHANNEL_FUNCTION", "NO", "YES"),
+ "flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None),
+}
+
+
options_jumper_t12 = {
"noheli": ("HELI", "NO", "YES"),
"ppmus": ("PPM_UNIT", "US", "PERCENT_PREC1"),
@@ -229,6 +243,7 @@ options_jumper_t16 = {
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None),
"internalmulti": ("INTERNAL_MODULE_MULTI", "YES", "NO"),
"bluetooth": ("BLUETOOTH", "YES", "NO"),
+ "externalaccessmod": ("HARDWARE_EXTERNAL_ACCESS_MOD", "YES", "NO"),
}
options_jumper_t18 = {
@@ -241,6 +256,30 @@ options_jumper_t18 = {
"nooverridech": ("OVERRIDE_CHANNEL_FUNCTION", "NO", "YES"),
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None),
"bluetooth": ("BLUETOOTH", "YES", "NO"),
+ "externalaccessmod": ("HARDWARE_EXTERNAL_ACCESS_MOD", "YES", "NO"),
+}
+
+options_radiomaster_tx12 = {
+ "noheli": ("HELI", "NO", "YES"),
+ "ppmus": ("PPM_UNIT", "US", "PERCENT_PREC1"),
+ "lua": ("LUA", "YES", "NO_MODEL_SCRIPTS"),
+ "nogvars": ("GVARS", "NO", "YES"),
+ "faimode": ("FAI", "YES", None),
+ "faichoice": ("FAI", "CHOICE", None),
+ "nooverridech": ("OVERRIDE_CHANNEL_FUNCTION", "NO", "YES"),
+ "flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None),
+ "afhds3": ("AFHDS3", "YES", "NO")
+}
+
+options_radiomaster_t8 = {
+ "noheli": ("HELI", "NO", "YES"),
+ "ppmus": ("PPM_UNIT", "US", "PERCENT_PREC1"),
+ "lua": ("LUA", "YES", "NO_MODEL_SCRIPTS"),
+ "nogvars": ("GVARS", "NO", "YES"),
+ "faimode": ("FAI", "YES", None),
+ "faichoice": ("FAI", "CHOICE", None),
+ "nooverridech": ("OVERRIDE_CHANNEL_FUNCTION", "NO", "YES"),
+ "bindkey": ("BIND_KEY", "NO", "YES"),
}
options_radiomaster_tx16s = {
@@ -254,4 +293,5 @@ options_radiomaster_tx16s = {
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None),
"bluetooth": ("BLUETOOTH", "YES", "NO"),
"internalgps": ("INTERNAL_GPS", "YES", "NO"),
+ "externalaccessmod": ("HARDWARE_EXTERNAL_ACCESS_MOD", "YES", "NO"),
}
\ No newline at end of file
diff --git a/radio/util/tts_cz.py b/radio/util/tts_cz.py
index 8f5b77730..409ebb46a 100755
--- a/radio/util/tts_cz.py
+++ b/radio/util/tts_cz.py
@@ -58,16 +58,6 @@ for s, f in [("střed trimu", "midtrim"),
("neplatná eeprom", "eebad"),
("Žádám o povolení ke startu.", "hello"),
("Tak zase příště!", "bye"),
- ("dvacet sekund", "timer20"),
- ("třicet sekund", "timer30"),
- ("A1,nízká", "a1_org"),
- ("A1,kritická", "a1_red"),
- ("A2,nízká", "a2_org"),
- ("A2,kritická", "a2_red"),
- ("A3,nízká", "a3_org"),
- ("A3,kritická", "a3_red"),
- ("A4,nízká", "a4_org"),
- ("A4,kritická", "a4_red"),
("nízký RF signál", "rssi_org"),
("kritický RF signál", "rssi_red"),
("problém s anténou rádia", "swr_red"),
diff --git a/radio/util/tts_de.py b/radio/util/tts_de.py
index 793d3fb85..2ebf26680 100755
--- a/radio/util/tts_de.py
+++ b/radio/util/tts_de.py
@@ -4,7 +4,6 @@
from tts_common import filename
-
systemSounds = []
sounds = []
@@ -14,82 +13,78 @@ systemSounds.append(("ein", filename(100)))
systemSounds.append(("eine", filename(101)))
systemSounds.append(("hundert", filename(102)))
systemSounds.append(("tausend", filename(103)))
+
for i, s in enumerate(["komma", "und", "minus", "uhr", "minute", "minuten", "sekunde", "sekunden", "stunde", "stunden"]):
- systemSounds.append((s, filename(104 + i)))
+ systemSounds.append((s, filename(104 + i)))
+
for i, (s, f) in enumerate([("Wolt", "volt0"),
("Ampär", "amp0"),
("MilliAmpär", "mamp0"),
("Knoten", "knot0"),
("Meter pro sekunde", "mps0"),
- ("Fuss pro sekunde", "fps0"),
+ ("Fuß pro sekunde", "fps0"),
("Kilometer pro stunde", "kph0"),
("Meilen pro Stunde", "mph0"),
("Meter", "meter0"),
- ("Fuesse", "foot0"),
+ ("Fuß", "foot0"),
("Grad Celsius", "celsius0"),
("Grad Fahrenheit", "fahr0"),
("Prozent", "percent0"),
- ("Milliampär pro stunde", "mamph0"),
+ ("Milliampärstunde", "mamph0"), ("Milliampärstunden", "mamph1"),
("Watt", "watt0"),
("Milli Watt", "mwatt0"),
("D B", "db0"),
- ("Drehzahl", "rpm0"),
+ ("Umdrehungen pro Minute", "rpm0"),
("g", "g0"),
("Grad", "degree0"),
- ("radians", "rad0"),
+ ("radiant", "rad0"), ("radianten", "rad1"),
("Milliliter", "ml0"),
- ("Unze", "founce0"),
- ("Milliliter pro minute", "mlpm0"), ("Milliliter pro minuten", "mlpm1"),
+ ("Unze", "founce0"),("Unzen", "founce1"),
+ ("Milliliter pro minute", "mlpm0"),
+ ("Hertz", "hertz0"),
+ ("Millisekunde", "ms0"), ("Millisekunden", "ms1"),
+ ("Mikrosekunde", "us0"), ("Mikrosekunden", "us1"),
("Stunde", "hour0"), ("Stunden", "hour1"),
("Minute", "minute0"), ("Minuten", "minute1"),
("Sekunde", "second0"), ("Sekunden", "second1"),
]):
systemSounds.append((s, filename(f)))
-for s, f in [("Inaktivitätsalarm", "inactiv"),
+
+for s, f in [("Trimmung zentriert", "midtrim"),
+ ("Obere Trimmungsgrenze erreicht", "maxtrim"),
+ ("Untere Trimmungsgrenze erreicht", "mintrim"),
+ ("timer eins abgelaufen", "timovr1"),
+ ("timer zwei abgelaufen", "timovr2"),
+ ("timer drei abgelaufen", "timovr3"),
("Senderspannung schwach", "lowbatt"),
+ ("Inaktivitätsalarm", "inactiv"),
("Gaskanal nicht Null, bitte prüfen", "thralert"),
("Schalter fehlpositioniert, bitte prüfen", "swalert"),
("EEPROM fehlerhaft", "eebad"),
- ("EEPROM formatiert", "eeformat"),
- ("Fehler", "error"),
- ("Trim zentriert", "midtrim"),
- ("Poti zentriert", "midpot"),
- ("Obere Trimmungsgrenze erreicht", "maxtrim"),
- ("Untere Trimmungsgrenze erreicht", "mintrim"),
- ("20 Sekunden", "timer20"),
- ("30 Sekunden", "timer30"),
- ("Senderstrom zu hoch!", "highmah"),
- ("Sendertemperatur zu hoch!", "hightemp"),
- ("A1 schwach!", "a1_org"),
- ("A1 kritisch!", "a1_red"),
- ("A2 schwach!", "a2_org"),
- ("A2 kritisch!", "a2_red"),
- ("A3 schwach!", "a3_org"),
- ("A3 kritisch!", "a3_red"),
- ("A4 schwach!", "a4_org"),
- ("A4 kritisch!", "a4_red"),
+ ("Willkommen bei open t x", "hello"),
("Funksignal schwach!", "rssi_org"),
("Funksignal kritisch!", "rssi_red"),
- ("Problem mit der Sender Antenne", "swr_red"),
+ ("Senderantenne fehlerhaft", "swr_red"),
("Telemetrie verloren", "telemko"),
("Telemetrie wiederhergestellt", "telemok"),
("Schülersignal verloren", "trainko"),
("Schülersignal wiederhergestellt", "trainok"),
- ("servo overload", "servoko"),
- ("power overload", "rxko"),
- ("Empfänger noch verbunden", "modelpwr"),
- ("timer eins abgelaufen", "timovr1"),
- ("timer zwei abgelaufen", "timovr2"),
- ("timer drei abgelaufen", "timovr3"),
("Sensor verloren", "sensorko"),
- ("Willkommen bei open te ix", "hello"),
+ ("servo Überlast", "servoko"),
+ ("power Überlast", "rxko"),
+ ("Empfänger noch verbunden", "modelpwr"),
+ ("Fehler", "error"), # Not shure if this is needed
+ ("Senderstrom zu hoch!", "highmah"), # Not shure if this is needed. Only used in PCBX9E
+ ("Sendertemperatur zu hoch!", "hightemp"), # Not shure if this is needed. Only used in PCBX9E
]:
systemSounds.append((s, filename(f)))
+
for i, s in enumerate(["Uhr", "Uhr", "Sender", "Empfang", "A1", "A2", "Hoehe", "Motor",
"Treibstoff", "Temperatur", "Temperatur", "Geschwindigkeit", "Entfernung", "Höhe", "Lipo-Zelle",
"Zellen gesamt", "Spannung", "Strom", "Verbrauch", "Power", "Beschleunigung X", "Beschleunigung Y", "Beschleunigung Z",
"Richtung", "Variometer", "Minimum", "Maximum"]):
systemSounds.append((s, filename(134 + i)))
+
for i, (s, f) in enumerate([("Fahrwerk eingezogen", "gearup"),
("Fahrwerk ausgefahren", "geardn"),
("Klappen eingefahren", "flapup"),
diff --git a/radio/util/tts_en.py b/radio/util/tts_en.py
index dff2e29dd..6230aafe9 100755
--- a/radio/util/tts_en.py
+++ b/radio/util/tts_en.py
@@ -38,6 +38,10 @@ for i, (s, f) in enumerate([("volt", "volt0"), ("volts", "volt1"),
("milliliter", "ml0"), ("milliliters", "ml1"),
("fluid ounce", "founce0"), ("fluid ounces", "founce1"),
("milliliter per minute", "mlpm0"), ("milliliters per minute", "mlpm1"),
+ ("hertz", "hertz0"), ("hertz", "hertz1"),
+ ("milisecond", "ms0"), ("miliseconds", "ms1"),
+ ("microsecond", "us0"), ("microseconds", "us1"),
+ ("kilometer", "km0"), ("kilometers", "km1"),
("hour", "hour0"), ("hours", "hour1"),
("minute", "minute0"), ("minutes", "minute1"),
("second", "second0"), ("seconds", "second1"),
@@ -74,6 +78,8 @@ for s, f in [("trim center", "midtrim"),
systemSounds.append((s, filename(f)))
for i, (s, f) in enumerate([("armed", "armed"),
("disarmed", "disarm"),
+ ("throttle cut", "thrcut"),
+ ("throttle active", "thract"),
("gear!, up!", "gearup"),
("gear!, down!", "geardn"),
("flaps!, up!", "flapup"),
@@ -90,6 +96,8 @@ for i, (s, f) in enumerate([("armed", "armed"),
("crow!, off!", "crowof"),
("rf. signal!, low!", "siglow"),
("rf. signal!, critical!", "sigcrt"),
+ ("LQ", "lq"),
+ ("RF mode", "rfmode"),
("high. speed. mode!, active", "spdmod"),
("thermal. mode!, on", "thmmod"),
("normal. mode!, on", "nrmmod"),
@@ -119,5 +127,13 @@ for i, (s, f) in enumerate([("armed", "armed"),
("flight mode thermal", "fm-thm"),
("flight mode thermal left", "fm-thl"),
("flight mode thermal right", "fm-thr"),
+ ("flight mode stabilize", "fm-stb"),
+ ("flight mode horizon", "fm-hor"),
+ ("flight mode angle", "fm-ang"),
+ ("flight mode idle up 1", "fm-id1"),
+ ("flight mode idle up 2", "fm-id2"),
+ ("low rate", "ratlow"),
+ ("medium rate", "ratmed"),
+ ("high rate", "rathi"),
]):
sounds.append((s, filename(f)))
diff --git a/radio/util/tts_es.py b/radio/util/tts_es.py
index 897b6b9e4..701272a08 100755
--- a/radio/util/tts_es.py
+++ b/radio/util/tts_es.py
@@ -56,20 +56,12 @@ for s, f in [("me tienes abandonada", "inactiv"),
("El acelerador está activado, por favor, corrijalo", "thralert"),
("Los interruptores no están en la posición correcta, por favor corrijalo", "swalert"),
("eeprom corrompida", "eebad"),
- ("Formateo de eeprom en curso", "eeformat"),
("error", "error"),
("trim centrado", "midtrim"),
- ("potenciómetro centrado", "midpot"),
("trim al máximo", "maxtrim"),
("trim al mínimo", "mintrim"),
- ("20 segundos", "timer20"),
- ("30 segundos", "timer30"),
("consumo alto", "highmah"),
("temperatura alta", "hightemp"),
- ("Alarma A1", "a1_org"),
- ("A1 crítica", "a1_red"),
- ("Alarma A2", "a2_org"),
- ("A2 crítica", "a2_red"),
("Bienvenido a open t equis", "hello"),
("señal baja", "rssi_org"),
("señal crítica", "rssi_red"),
diff --git a/radio/util/tts_fr.py b/radio/util/tts_fr.py
index 9dc046fa5..eba461d72 100755
--- a/radio/util/tts_fr.py
+++ b/radio/util/tts_fr.py
@@ -39,6 +39,10 @@ for i, (s, f) in enumerate([("volts", "volt0"),
("millilitres", "ml0"),
("onces", "founce0"),
("millilitre minute", "mlpm0"),
+ ("microsecond", "us0"),
+ ("milisecond", "ms0"),
+ ("hertz", "hertz0"),
+ ("kilometre", "km0"),
("heure", "hour0"),
("minute", "minute0"),
("seconde", "second0"),
diff --git a/radio/util/tts_it.py b/radio/util/tts_it.py
index 2b87dd911..b9abd23f5 100755
--- a/radio/util/tts_it.py
+++ b/radio/util/tts_it.py
@@ -48,24 +48,12 @@ for s, f in [("radio inattiva controllare", "inactiv"),
("controllo motore non in posizione, verificare", "thralert"),
("interruttori non in posizione, verificare", "swalert"),
("eeprom corrotta", "eebad"),
- ("formattazione eeprom in corso", "eeformat"),
("errore", "error"),
("trim centrato", "midtrim"),
- ("potenziometro centrato", "midpot"),
("massimo trim raggiunto", "maxtrim"),
("minimo trim raggiunto", "mintrim"),
- ("venti secondi", "timer20"),
- ("trenta secondi", "timer30"),
("assorbimento elevato", "highmah"),
("temperatura elevata", "hightemp"),
- ("A1 in allarme", "a1_org"),
- ("A1 critico", "a1_red"),
- ("A2 in allarme", "a2_org"),
- ("A2 critico", "a2_red"),
- ("A3 in allarme", "a3_org"),
- ("A3 critico", "a3_red"),
- ("A4 in allarme", "a4_org"),
- ("A4 critico", "a4_red"),
("Segnale radio basso", "rssi_org"),
("Segnale radio critico", "rssi_red"),
("Problema all'antenna della radio", "swr_red"),
diff --git a/radio/util/tts_pt.py b/radio/util/tts_pt.py
index b2e71c8e8..cf7ba9cf0 100755
--- a/radio/util/tts_pt.py
+++ b/radio/util/tts_pt.py
@@ -56,20 +56,12 @@ for s, f in [("atenção, o rádio foi esquecido ligado, por favor desligue-o",
("atenção,acelerador não está no mínimo", "thralert"),
("atenção, certifique-se que os interruptores estão na posição certa", "swalert"),
("eeprom corrompida", "eebad"),
- ("formatação da eeprom em curso", "eeformat"),
("erro", "error"),
("trim centrado", "midtrim"),
- ("potenciómetro centrado", "midpot"),
("trim no máximo", "maxtrim"),
("trim no mínimo", "mintrim"),
- ("20 segundos", "timer20"),
- ("30 segundos", "timer30"),
("assorbimento elevato", "highmah"),
("temperatura elevata", "hightemp"),
- ("Alarme A1", "a1_org"),
- ("A1 critica", "a1_red"),
- ("Alarme A2", "a2_org"),
- ("A2 critica", "a2_red"),
("recepção de sinal muito baixa", "rssi_org"),
("recepção de sinal crítica", "rssi_red"),
("Problema com a antena do transmissor", "swr_red"),
diff --git a/tools/boards.py b/tools/boards.py
new file mode 100755
index 000000000..72e367cb3
--- /dev/null
+++ b/tools/boards.py
@@ -0,0 +1,69 @@
+#!/usr/bin/python3
+
+boards = {
+ "XLITE": {
+ "PCB": "XLITE",
+ },
+ "XLITES": {
+ "PCB": "XLITES",
+ },
+ "X9LITE": {
+ "PCB": "X9LITE",
+ },
+ "X9LITES": {
+ "PCB": "X9LITES",
+ },
+ "X9D": {
+ "PCB": "X9D",
+ },
+ "X9D+": {
+ "PCB": "X9D+",
+ },
+ "X9D+2019": {
+ "PCB": "X9D+",
+ "PCBREV": "2019",
+ },
+ "X9E": {
+ "PCB": "X9E",
+ },
+ "X7": {
+ "PCB": "X7",
+ },
+ "X7ACCESS": {
+ "PCB": "X7",
+ "PCBREV": "ACCESS",
+ },
+ "X10": {
+ "PCB": "X10",
+ },
+ "X10EXPRESS": {
+ "PCB": "X10",
+ "PCBREV": "EXPRESS",
+ },
+ "X12S": {
+ "PCB": "X12S",
+ },
+ "T16": {
+ "PCB": "X10",
+ "PCBREV": "T16",
+ "INTERNAL_MODULE_MULTI": "YES"
+ },
+ "T18": {
+ "PCB": "X10",
+ "PCBREV": "T18",
+ "INTERNAL_MODULE_MULTI": "YES"
+ },
+ "TX16S": {
+ "PCB": "X10",
+ "PCBREV": "TX16S",
+ "INTERNAL_MODULE_MULTI": "YES"
+ },
+ "T12": {
+ "PCB": "X7",
+ "PCBREV": "T12",
+ },
+ "TX12": {
+ "PCB": "X7",
+ "PCBREV": "TX12",
+ },
+}
diff --git a/tools/build-companion-nightly.sh b/tools/build-companion-nightly.sh
index fbf8f7166..a0406f691 100755
--- a/tools/build-companion-nightly.sh
+++ b/tools/build-companion-nightly.sh
@@ -70,6 +70,10 @@ cmake ${COMMON_OPTIONS} -DPCB=X7 -DPCBREV=T12 ${SRCDIR}
make -j${JOBS} libsimulator
rm CMakeCache.txt
+cmake ${COMMON_OPTIONS} -DPCB=X7 -DPCBREV=TX12 ${SRCDIR}
+make -j${JOBS} libsimulator
+rm CMakeCache.txt
+
cmake ${COMMON_OPTIONS} -DPCB=X9D ${SRCDIR}
make -j${JOBS} libsimulator
rm CMakeCache.txt
diff --git a/tools/build-companion-release.sh b/tools/build-companion-release.sh
index b73ce8ed2..463645dc2 100755
--- a/tools/build-companion-release.sh
+++ b/tools/build-companion-release.sh
@@ -70,6 +70,10 @@ cmake ${COMMON_OPTIONS} -DPCB=X7 -DPCBREV=T12 ${SRCDIR}
make -j${JOBS} libsimulator
rm CMakeCache.txt
+cmake ${COMMON_OPTIONS} -DPCB=X7 -DPCBREV=TX12 ${SRCDIR}
+make -j${JOBS} libsimulator
+rm CMakeCache.txt
+
cmake ${COMMON_OPTIONS} -DPCB=X9D ${SRCDIR}
make -j${JOBS} libsimulator
rm CMakeCache.txt
diff --git a/tools/build-imrc.py b/tools/build-imrc.py
new file mode 100755
index 000000000..e0c8cf061
--- /dev/null
+++ b/tools/build-imrc.py
@@ -0,0 +1,65 @@
+#!/usr/bin/python3
+
+import argparse
+import datetime
+import os
+from builtins import NotADirectoryError
+import shutil
+import tempfile
+
+from boards import *
+
+translations = [
+ "EN"
+]
+
+
+def timestamp():
+ return datetime.datetime.now().strftime("%Y%m%d")
+
+
+def build(board, translation, srcdir):
+ cmake_options = " ".join(["-D%s=%s" % (key, value) for key, value in boards[board].items()])
+ cwd = os.getcwd()
+ if not os.path.exists("output"):
+ os.mkdir("output")
+ path = tempfile.mkdtemp()
+ os.chdir(path)
+ command = "cmake %s -DTRANSLATIONS=%s -DIMRC_RELEASE=YES -DGHOST=YES %s" % (cmake_options, translation, srcdir)
+ print(command)
+ os.system(command)
+ os.system("make firmware -j16")
+ os.chdir(cwd)
+ index = 0
+ while 1:
+ suffix = "" if index == 0 else "_%d" % index
+ filename = "output/ghost_firm_%s_%s_%s%s.bin" % (board.lower(), translation.lower(), timestamp(), suffix)
+ if not os.path.exists(filename):
+ shutil.copy("%s/firmware.bin" % path, filename)
+ break
+ index += 1
+ shutil.rmtree(path)
+
+
+def dir_path(string):
+ if os.path.isdir(string):
+ return string
+ else:
+ raise NotADirectoryError(string)
+
+
+def main():
+ parser = argparse.ArgumentParser(description="Build Ghost firmware")
+ parser.add_argument("-b", "--boards", action="append", help="Destination boards", required=True)
+ parser.add_argument("-t", "--translations", action="append", help="Translations", required=True)
+ parser.add_argument("srcdir", type=dir_path)
+
+ args = parser.parse_args()
+
+ for board in (boards.keys() if "ALL" in args.boards else args.boards):
+ for translation in (translations if "ALL" in args.translations else args.translations):
+ build(board, translation, args.srcdir)
+
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file
diff --git a/tools/build-jumper.py b/tools/build-jumper.py
index 6e7f3d733..2df2aa46d 100755
--- a/tools/build-jumper.py
+++ b/tools/build-jumper.py
@@ -9,6 +9,11 @@ import tempfile
boards = {
+ "TLITE": {
+ "PCB": "X7",
+ "PCBREV": "TLITE",
+ "DEFAULT_MODE": "2",
+ },
"T12": {
"PCB": "X7",
"PCBREV": "T12",
@@ -53,7 +58,7 @@ def build(board, translation, srcdir):
command = "cmake %s -DTRANSLATIONS=%s -DJUMPER_RELEASE=YES %s" % (cmake_options, translation, srcdir)
print(command)
os.system(command)
- os.system("make firmware -j6")
+ os.system("make firmware -j16")
os.chdir(cwd)
index = 0
while 1:
diff --git a/tools/build-radiomaster.py b/tools/build-radiomaster.py
index 83faa31bb..564463537 100755
--- a/tools/build-radiomaster.py
+++ b/tools/build-radiomaster.py
@@ -18,6 +18,28 @@ boards = {
"PCB": "X10",
"PCBREV": "TX16S",
"DEFAULT_MODE": "2",
+ },
+ "TX12_1": {
+ "PCB": "X7",
+ "PCBREV": "TX12",
+ "DEFAULT_MODE": "1",
+ },
+ "TX12_2": {
+ "PCB": "X7",
+ "PCBREV": "TX12",
+ "DEFAULT_MODE": "2",
+ },
+ "T8_1": {
+ "PCB": "X7",
+ "PCBREV": "T8",
+ "DEFAULT_MODE": "1",
+ "RADIOMASTER_RTF_RELEASE": "YES",
+ },
+ "T8_2": {
+ "PCB": "X7",
+ "PCBREV": "T8",
+ "DEFAULT_MODE": "2",
+ "RADIOMASTER_RTF_RELEASE": "YES",
}
}
diff --git a/tools/build-tbs.py b/tools/build-tbs.py
index 3c5cb2d1c..4d469c608 100755
--- a/tools/build-tbs.py
+++ b/tools/build-tbs.py
@@ -7,60 +7,7 @@ from builtins import NotADirectoryError
import shutil
import tempfile
-
-boards = {
- "XLITE": {
- "PCB": "XLITE",
- },
- "XLITES": {
- "PCB": "XLITES",
- },
- "X9LITE": {
- "PCB": "X9LITE",
- },
- "X9LITES": {
- "PCB": "X9LITES",
- },
- "X9D": {
- "PCB": "X9D+",
- },
- "X9D+": {
- "PCB": "X9D+",
- },
- "X9D+2019": {
- "PCB": "X9D+",
- "PCBREV": "2019",
- },
- "X9E": {
- "PCB": "X9E",
- },
- "X7": {
- "PCB": "X7",
- },
- "X7ACCESS": {
- "PCB": "X7",
- "PCBREV": "ACCESS",
- },
- "X10": {
- "PCB": "X10",
- },
- "X10EXPRESS": {
- "PCB": "X10",
- "PCBREV": "EXPRESS",
- },
- "X12S": {
- "PCB": "X12S",
- },
- "T16": {
- "PCB": "X10",
- "PCBREV": "T16",
- "INTERNAL_MODULE_MULTI": "YES"
- },
- "T12": {
- "PCB": "X7",
- "PCBREV": "T12",
- },
-}
+from boards import *
translations = [
"EN"
@@ -78,15 +25,15 @@ def build(board, translation, srcdir):
os.mkdir("output")
path = tempfile.mkdtemp()
os.chdir(path)
- command = "cmake %s -DTRANSLATIONS=%s -DTBS_RELEASE=YES -DTEST_BUILD_WARNING=YES %s" % (cmake_options, translation, srcdir)
+ command = "cmake %s -DTRANSLATIONS=%s -DTBS_RELEASE=YES %s" % (cmake_options, translation, srcdir)
print(command)
os.system(command)
- os.system("make firmware -j6")
+ os.system("make firmware -j16")
os.chdir(cwd)
index = 0
while 1:
suffix = "" if index == 0 else "_%d" % index
- filename = "output/firmware_%s_%s_%s%s.bin" % (board.lower(), translation.lower(), timestamp(), suffix)
+ filename = "output/tbs_firm_%s_%s_%s%s.bin" % (board.lower(), translation.lower(), timestamp(), suffix)
if not os.path.exists(filename):
shutil.copy("%s/firmware.bin" % path, filename)
break
diff --git a/tools/clang-format.sh b/tools/clang-format.sh
new file mode 100755
index 000000000..9a6111beb
--- /dev/null
+++ b/tools/clang-format.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+# Automatic indentation of all .c, .cpp and .h-files using clang-format
+# based on https://github.com/opentx/opentx/wiki/OpenTX-Code-Style-Guide
+
+# clang-format version 10.0.0
+
+for i in $(find ./ -name "*.c" -or -name "*.cpp" -or -name "*.h")
+do
+ echo $i
+ clang-format -i -style="{BasedOnStyle: LLVM,
+ IndentWidth: 2,
+ UseTab: Never,
+
+ AllowShortBlocksOnASingleLine: false,
+ AllowShortIfStatementsOnASingleLine: false,
+ AllowShortFunctionsOnASingleLine: false,
+
+ BreakBeforeBraces: Custom,
+ BraceWrapping: { AfterFunction: true,
+ BeforeElse: true },
+
+ IndentCaseLabels: true,
+ PenaltyReturnTypeOnItsOwnLine: 0,
+ ColumnLimit: 120}" $i
+done
diff --git a/tools/commit-tests.sh b/tools/commit-tests.sh
index c1c97237e..8ef5e85fb 100755
--- a/tools/commit-tests.sh
+++ b/tools/commit-tests.sh
@@ -88,7 +88,7 @@ fi
if [[ " X9LITE ALL " =~ \ ${FLAVOR}\ ]] ; then
# OpenTX on X9LITE
rm -rf ./*
- cmake "${COMMON_OPTIONS}" -DPCB=X9LITE -DHELI=YES -DGVARS=YES "${SRCDIR}"
+ cmake "${COMMON_OPTIONS}" -DPCB=X9LITE -DHELI=YES -DGVARS=YES -DTRANSLATIONS=CZ "${SRCDIR}"
make -j"${CORES}" ${FIRMARE_TARGET}
make -j"${CORES}" libsimulator
make -j"${CORES}" tests-radio
@@ -97,7 +97,7 @@ fi
if [[ " X9LITES X9LITE ALL " =~ \ ${FLAVOR}\ ]] ; then
# OpenTX on X9LITES
rm -rf ./*
- cmake "${COMMON_OPTIONS}" -DPCB=X9LITES -DHELI=YES -DGVARS=YES -DMULTIMODULE=NO "${SRCDIR}"
+ cmake "${COMMON_OPTIONS}" -DPCB=X9LITES -DHELI=YES -DGVARS=YES -DMULTIMODULE=NO -DTRANSLATIONS=DE "${SRCDIR}"
make -j"${CORES}" ${FIRMARE_TARGET}
make -j"${CORES}" libsimulator
make -j"${CORES}" tests-radio
@@ -106,7 +106,16 @@ fi
if [[ " X7 ALL " =~ \ ${FLAVOR}\ ]] ; then
# OpenTX on X7
rm -rf ./*
- cmake "${COMMON_OPTIONS}" -DPCB=X7 -DHELI=YES -DGVARS=YES "${SRCDIR}"
+ cmake "${COMMON_OPTIONS}" -DPCB=X7 -DHELI=YES -DGVARS=YES -DTRANSLATIONS=ES "${SRCDIR}"
+ make -j"${CORES}" ${FIRMARE_TARGET}
+ make -j"${CORES}" libsimulator
+ make -j"${CORES}" tests-radio
+fi
+
+if [[ " X7ACCESS X7 ALL " =~ \ ${FLAVOR}\ ]] ; then
+ # OpenTX on X7 ACCESS
+ rm -rf ./*
+ cmake "${COMMON_OPTIONS}" -DPCB=X7 -DPCBREV=ACCESS -DHELI=YES -DGVARS=YES -DTRANSLATIONS=FR "${SRCDIR}"
make -j"${CORES}" ${FIRMARE_TARGET}
make -j"${CORES}" libsimulator
make -j"${CORES}" tests-radio
@@ -115,7 +124,43 @@ fi
if [[ " T12 X7 ALL " =~ \ ${FLAVOR}\ ]] ; then
# OpenTX on T12
rm -rf ./*
- cmake "${COMMON_OPTIONS}" -DPCB=X7 -DPCBREV=T12 -DHELI=YES -DGVARS=YES "${SRCDIR}"
+ cmake "${COMMON_OPTIONS}" -DPCB=X7 -DPCBREV=T12 -DHELI=YES -DGVARS=YES -DTRANSLATIONS=IT "${SRCDIR}"
+ make -j"${CORES}" ${FIRMARE_TARGET}
+ make -j"${CORES}" libsimulator
+ make -j"${CORES}" tests-radio
+fi
+
+if [[ " TX12 X7 ALL " =~ \ ${FLAVOR}\ ]] ; then
+ # OpenTX on TX12
+ rm -rf ./*
+ cmake "${COMMON_OPTIONS}" -DPCB=X7 -DPCBREV=TX12 -DHELI=YES -DGVARS=YES -DTRANSLATIONS=PT "${SRCDIR}"
+ make -j"${CORES}" ${FIRMARE_TARGET}
+ make -j"${CORES}" libsimulator
+ make -j"${CORES}" tests-radio
+fi
+
+if [[ " T8 X7 ALL " =~ \ ${FLAVOR}\ ]] ; then
+ # OpenTX on T8
+ rm -rf ./*
+ cmake "${COMMON_OPTIONS}" -DPCB=X7 -DPCBREV=T8 -DHELI=YES -DGVARS=YES "${SRCDIR}"
+ make -j"${CORES}" ${FIRMARE_TARGET}
+ make -j"${CORES}" libsimulator
+ make -j"${CORES}" tests-radio
+fi
+
+if [[ " TLITE X7 ALL " =~ \ ${FLAVOR}\ ]] ; then
+ # OpenTX on TLITE
+ rm -rf ./*
+ cmake "${COMMON_OPTIONS}" -DPCB=X7 -DPCBREV=TLITE -DHELI=YES -DGVARS=YES "${SRCDIR}"
+ make -j"${CORES}" ${FIRMARE_TARGET}
+ make -j"${CORES}" libsimulator
+ make -j"${CORES}" tests-radio
+fi
+
+if [[ " TX12 X7 ALL " =~ \ ${FLAVOR}\ ]] ; then
+ # OpenTX on TX12
+ rm -rf ./*
+ cmake "${COMMON_OPTIONS}" -DPCB=X7 -DPCBREV=TX12 -DHELI=YES -DGVARS=YES "${SRCDIR}"
make -j"${CORES}" ${FIRMARE_TARGET}
make -j"${CORES}" libsimulator
make -j"${CORES}" tests-radio
@@ -124,7 +169,7 @@ fi
if [[ " XLITE ALL " =~ \ ${FLAVOR}\ ]] ; then
# OpenTX on X-Lite
rm -rf ./*
- cmake "${COMMON_OPTIONS}" -DPCB=XLITE -DHELI=YES -DGVARS=YES "${SRCDIR}"
+ cmake "${COMMON_OPTIONS}" -DPCB=XLITE -DHELI=YES -DGVARS=YES -DTRANSLATIONS=SK "${SRCDIR}"
make -j"${CORES}" ${FIRMARE_TARGET}
make -j"${CORES}" libsimulator
make -j"${CORES}" tests-radio
@@ -133,7 +178,7 @@ fi
if [[ " XLITES XLITE ALL " =~ \ ${FLAVOR}\ ]] ; then
# OpenTX on X-Lites
rm -rf ./*
- cmake "${COMMON_OPTIONS}" -DPCB=XLITES -DHELI=YES -DGVARS=YES "${SRCDIR}"
+ cmake "${COMMON_OPTIONS}" -DPCB=XLITES -DHELI=YES -DGVARS=YES -DTRANSLATIONS=SE "${SRCDIR}"
make -j"${CORES}" ${FIRMARE_TARGET}
make -j"${CORES}" libsimulator
make -j"${CORES}" tests-radio
@@ -142,7 +187,7 @@ fi
if [[ " X9D X9 ALL " =~ \ ${FLAVOR}\ ]] ; then
# OpenTX on X9D
rm -rf ./*
- cmake "${COMMON_OPTIONS}" -DPCB=X9D -DHELI=YES -DLUA=YES -DGVARS=YES "${SRCDIR}"
+ cmake "${COMMON_OPTIONS}" -DPCB=X9D -DHELI=YES -DLUA=YES -DGVARS=YES -DTRANSLATIONS=PL "${SRCDIR}"
make -j"${CORES}" ${FIRMARE_TARGET}
make -j"${CORES}" libsimulator
make -j"${CORES}" tests-radio
@@ -151,7 +196,7 @@ fi
if [[ " X9D+ X9 ALL " =~ \ ${FLAVOR}\ ]] ; then
# OpenTX on X9D+
rm -rf ./*
- cmake "${COMMON_OPTIONS}" -DPCB=X9D+ -DHELI=YES -DLUA=YES -DGVARS=YES "${SRCDIR}"
+ cmake "${COMMON_OPTIONS}" -DPCB=X9D+ -DHELI=YES -DLUA=YES -DGVARS=YES -DTRANSLATIONS=HU "${SRCDIR}"
make -j"${CORES}" ${FIRMARE_TARGET}
make -j"${CORES}" libsimulator
make -j"${CORES}" tests-radio
@@ -160,7 +205,7 @@ fi
if [[ " X9D+2019 X9 ALL " =~ \ ${FLAVOR}\ ]] ; then
# OpenTX on X9D+ 2019
rm -rf ./*
- cmake "${COMMON_OPTIONS}" -DPCB=X9D+ -DPCBREV=2019 -DHELI=YES -DLUA=YES -DGVARS=YES "${SRCDIR}"
+ cmake "${COMMON_OPTIONS}" -DPCB=X9D+ -DPCBREV=2019 -DHELI=YES -DLUA=YES -DGVARS=YES -DTRANSLATIONS=NL "${SRCDIR}"
make -j"${CORES}" ${FIRMARE_TARGET}
make -j"${CORES}" libsimulator
make -j"${CORES}" tests-radio