diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 000000000..fdb7dc9f4 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,12 @@ +# These are supported funding model platforms + +github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +patreon: # Replace with a single Patreon username +open_collective: # Replace with a single Open Collective username +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: # Replace with a single Liberapay username +issuehunt: # Replace with a single IssueHunt username +otechie: # Replace with a single Otechie username +custom: ['PayPal.Me/opentx'] diff --git a/CMakeLists.txt b/CMakeLists.txt index 5fd4eaf54..c31e39426 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ set(VERSION_REVISION "0") 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 "0026") +set(SDCARD_REVISION "0028") 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 f8d4f14e6..b7ce3cb68 100644 --- a/CREDITS.txt +++ b/CREDITS.txt @@ -11,6 +11,7 @@ Arne Schwabe (schwabe) [Translators] [fr] Sebastien Charpentier (LapinFou) +[es] Daniel Gorbea (dgatf) [Other contributors] Rob Thomson @@ -422,7 +423,6 @@ Pablo Gomez Martinez Alan Thoren Jack Clodfelter William Simon -James Houck Peter Fithern Thomas Svedman TechFixPros @@ -687,7 +687,6 @@ Shaun Currier Danilo Schiara John Hennig RK Custom Homes -James Houck Piet Teekens Tommy Widenflycht Johan Petrus Theophilus @@ -1707,3 +1706,30 @@ Fabrice Debonnet James Laver Kevin Bowens David Frech +Udo Kastenholz +Julio Margarido +Uwe Muendelein +James Jewitt +Daniel Ferreira +Michael Charlston +Leopoldo Cicero +Tom Van Driel +Karl Vetter +Johannes Janssen +François Blondé +Precision Aero +Thomas Håkansson +Gordon Evans +Benny Simonsen +George Kennedy +Stefano Boggia +Maksym Arshynkin +Tomas Sodergren +Jörg Lemnitz +TMac FPV +Josef Schaeffler +Mike Frizell +MeCodeGoodSomeday +Timothy Fry +John Beech +Wojciech Winiarski diff --git a/README.md b/README.md index c966e7ed4..64e672a51 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ ## OpenTX 2.3 Branch [![Travis build Status](https://travis-ci.org/opentx/opentx.svg?branch=2.3)](https://travis-ci.org/opentx/opentx) -[![Join the Discord chat](https://img.shields.io/badge/discord-join_chat-yellow.svg)](https://discord.gg/pAmmCp2) +[![Join the Discord chat](https://img.shields.io/badge/discord-join_chat-yellow.svg)](https://discord.gg/CZCwVx2) [![Donate using Paypal](https://img.shields.io/badge/paypal-donate-yellow.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=DJ9MASSKVW8WN) The ongoing development on 2.3.x is done in this branch. diff --git a/companion/src/CMakeLists.txt b/companion/src/CMakeLists.txt index b867acb74..ca278494f 100644 --- a/companion/src/CMakeLists.txt +++ b/companion/src/CMakeLists.txt @@ -250,6 +250,7 @@ set(companion_SRCS wizarddialog.cpp styleeditdialog.cpp dialogs/filesyncdialog.cpp # TODO move to own lib with other dialogs + profilechooser.cpp ) set(companion_MOC_HDRS @@ -284,6 +285,7 @@ set(companion_MOC_HDRS styleeditdialog.h helpers_html.h dialogs/filesyncdialog.h + profilechooser.h ) set(companion_UIS @@ -305,6 +307,7 @@ set(companion_UIS flasheepromdialog.ui radionotfound.ui styleeditdialog.ui + profilechooser.ui ) if(WIN32) diff --git a/companion/src/apppreferencesdialog.cpp b/companion/src/apppreferencesdialog.cpp index 63c260176..c235788df 100644 --- a/companion/src/apppreferencesdialog.cpp +++ b/companion/src/apppreferencesdialog.cpp @@ -73,6 +73,7 @@ void AppPreferencesDialog::accept() g.OpenTxBranch(AppData::DownloadBranchType(ui->OpenTxBranch->currentIndex())); g.autoCheckFw(ui->autoCheckFirmware->isChecked()); g.showSplash(ui->showSplash->isChecked()); + g.promptProfile(ui->chkPromptProfile->isChecked()); g.simuSW(ui->simuSW->isChecked()); g.removeModelSlots(ui->opt_removeBlankSlots->isChecked()); g.newModelAction(ui->opt_newMdl_useWizard->isChecked() ? AppData::MODEL_ACT_WIZARD : ui->opt_newMdl_useEditor->isChecked() ? AppData::MODEL_ACT_EDITOR : AppData::MODEL_ACT_NONE); @@ -185,6 +186,7 @@ void AppPreferencesDialog::initSettings() ui->autoCheckCompanion->setChecked(g.autoCheckApp()); ui->autoCheckFirmware->setChecked(g.autoCheckFw()); ui->showSplash->setChecked(g.showSplash()); + ui->chkPromptProfile->setChecked(g.promptProfile()); ui->historySize->setValue(g.historySize()); ui->backLightColor->setCurrentIndex(g.backLight()); ui->volumeGain->setValue(profile.volumeGain() / 10.0); @@ -352,6 +354,13 @@ void AppPreferencesDialog::on_ge_pathButton_clicked() } } +void AppPreferencesDialog::on_btnClearPos_clicked() +{ + SimulatorOptions opts = g.profile[g.sessionId()].simulatorOptions(); + opts.controlsState.clear(); + g.profile[g.sessionId()].simulatorOptions(opts); +} + #if defined(JOYSTICKS) void AppPreferencesDialog::on_joystickChkB_clicked() { if (ui->joystickChkB->isChecked()) { diff --git a/companion/src/apppreferencesdialog.h b/companion/src/apppreferencesdialog.h index 8c796cf7f..7e3f6f234 100644 --- a/companion/src/apppreferencesdialog.h +++ b/companion/src/apppreferencesdialog.h @@ -66,6 +66,7 @@ class AppPreferencesDialog : public QDialog void on_SplashSelect_clicked(); void on_clearImageButton_clicked(); void on_btn_appLogsDir_clicked(); + void on_btnClearPos_clicked(); #if defined(JOYSTICKS) void on_joystickChkB_clicked(); diff --git a/companion/src/apppreferencesdialog.ui b/companion/src/apppreferencesdialog.ui index ca015d2dc..80301223d 100644 --- a/companion/src/apppreferencesdialog.ui +++ b/companion/src/apppreferencesdialog.ui @@ -6,7 +6,7 @@ 0 0 - 741 + 864 668 @@ -45,7 +45,7 @@ - 1 + 0 @@ -61,22 +61,40 @@ + + 0 + + + 0 + + + 0 + + + 0 + 5 4 - - 0 - - + + 0 + + + 0 + + + 0 + + 0 @@ -704,29 +722,90 @@ Mode 4: 6 - - + + + + + 0 + 0 + + + + Enable automatic backup before writing firmware + + + + + + + + 0 + 0 + + + + Google Earth Executable + + + + + + + + 0 + 0 + + - - - Automatic check for OpenTX firmware updates - - - true - - + + Releases (stable) + - - - Automatic check for Companion updates - - - true - - + + Release candidates (testing) + - + + + Nightly builds (unstable) + + + + + + + + + 0 + 0 + + + + + Only show user splash images + + + + + Show user and companion splash images + + + + + + + + Qt::Horizontal + + + + + + + Qt::Horizontal + + @@ -764,120 +843,27 @@ Mode 4: - - - - - 0 - 0 - - - - Startup Settings - - - - - - - - 0 - 0 - - - - Google Earth Executable - - - - - - - Qt::Horizontal - - - - Show splash screen when Companion starts + Show splash screen true - - - - - 0 - 0 - - - - Automatic Backup Folder - - - - - - - - 0 - 0 - - - - Remember - - - - - + + - + - false - - - - - - - - 0 - 0 - - - - Select Folder - - - - - - - - - Qt::Horizontal - - - - - - - - true - - false - - + 0 @@ -885,49 +871,13 @@ Mode 4: - Select Folder + Select Executable - - - <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) - - - - - - - - 0 - 0 - - - - Output Logs Folder - - - - - - - - 0 - 0 - - - - Debug Output Logging - - - - @@ -962,90 +912,22 @@ Mode 4: - - - - 0 - 0 - - - - Enable automatic backup before writing firmware - - - - - - - Qt::Horizontal - - - - - - - - 0 - 0 - - + - - Only show user splash images - - - - - Show user and companion splash images - - - - - - - - Qt::Horizontal - - - - - - - + - true + false - + 0 0 - - Select Executable - - - - - - - - - - - true - - - false - - - - - Select Folder @@ -1053,14 +935,56 @@ Mode 4: - - - - Qt::Horizontal + + + + + 0 + 0 + + + + Remember - + + + + + 0 + 0 + + + + Output Logs Folder + + + + + + + + 0 + 0 + + + + Startup Settings + + + + + + + <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) + + + + @@ -1073,33 +997,7 @@ Mode 4: - - - - - 0 - 0 - - - - Splash Screen Library - - - - - - - - 0 - 0 - - - - Action on New Model - - - - + @@ -1123,36 +1021,163 @@ Mode 4: - + + + + + + true + + + false + + + + + + + Select Folder + + + + + + + + + + 0 + 0 + + + + Action on New Model + + + + + + + + + true + + + false + + + + + + + + 0 + 0 + + + + Select Folder + + + + + + + + + + 0 + 0 + + + + Splash Screen Library + + + + Release channel - - + + + + Qt::Horizontal + + + + + - + 0 0 + + Debug Output Logging + + + + + + + Qt::Horizontal + + + + + + + + 0 + 0 + + + + Automatic Backup Folder + + + + + - - Releases (stable) - + + + Automatic check for OpenTX firmware updates + + + true + + - - Release candidates (testing) - - - - - Nightly builds (unstable) - + + + Automatic check for Companion updates + + + true + + + + + + + + Qt::Horizontal + + + + + + + Prompt for radio profile + @@ -1180,7 +1205,38 @@ Mode 4: 6 - + + + + + 0 + 0 + + + + + 50 + 16777215 + + + + 1 + + + 0.500000000000000 + + + 3.000000000000000 + + + 0.100000000000000 + + + 1.000000000000000 + + + + @@ -1193,14 +1249,20 @@ Mode 4: - - + + + + + 0 + 0 + + - Calibrate + Screenshot capture folder - + @@ -1235,31 +1297,22 @@ Mode 4: - - - - - 0 - 0 - - + + - Screenshot capture folder + Calibrate - - - - Qt::Vertical + + + + Select Folder - - - 20 - 5 - + + false - + @@ -1274,7 +1327,7 @@ Mode 4: - + @@ -1287,17 +1340,20 @@ Mode 4: - - - - Select Folder + + + + Qt::Vertical - - false + + + 20 + 5 + - + - + @@ -1310,7 +1366,20 @@ Mode 4: - + + + + + 0 + 0 + + + + Simulator Volume Gain + + + + @@ -1348,60 +1417,30 @@ Mode 4: - + + + + Simulator controls + + + + - + 0 0 - Remember simulator switch values + Save switch/pot positions on simulator exit - - - - - 0 - 0 - - + + - Simulator Volume Gain - - - - - - - - 0 - 0 - - - - - 50 - 16777215 - - - - 1 - - - 0.500000000000000 - - - 3.000000000000000 - - - 0.100000000000000 - - - 1.000000000000000 + Clear saved positions diff --git a/companion/src/firmwares/CMakeLists.txt b/companion/src/firmwares/CMakeLists.txt index b6b8fcaba..502a04961 100644 --- a/companion/src/firmwares/CMakeLists.txt +++ b/companion/src/firmwares/CMakeLists.txt @@ -1,5 +1,6 @@ set(firmwares_SRCS + adjustmentreference.cpp boards.cpp curvereference.cpp customfunctiondata.cpp diff --git a/companion/src/firmwares/adjustmentreference.cpp b/companion/src/firmwares/adjustmentreference.cpp new file mode 100644 index 000000000..37b284ecd --- /dev/null +++ b/companion/src/firmwares/adjustmentreference.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 "adjustmentreference.h" +#include "radiodata.h" // for ModelData + +AdjustmentReference::AdjustmentReference(int value) +{ + int val = value; + if (abs(val) > ADJUST_REF_GVAR_BASE && abs(val) <= ADJUST_REF_GVAR_BASE + CPN_MAX_GVARS) { + type = ADJUST_REF_GVAR; + val = val >= 0 ? val - ADJUST_REF_GVAR_BASE : val + ADJUST_REF_GVAR_BASE; + } + else + this->type = ADJUST_REF_VALUE; + + this->value = val; +} + +AdjustmentReference::AdjustmentReference(AdjustRefType type, int value) +{ + this->type = type; + if (isValid(value)) + this->value = value; + else + clear(); +} + +bool AdjustmentReference::isValid(const int value) const +{ + switch(type) { + case ADJUST_REF_VALUE: + if (abs(value) < ADJUST_REF_GVAR_BASE) + return true; + break; + case ADJUST_REF_GVAR: + if (abs(value) > 0 && abs(value) <= CPN_MAX_GVARS); + return true; + break; + } + return false; +} + +QString AdjustmentReference::toString(const ModelData * model, const bool sign) const +{ + QString ret; + + switch(type) { + case ADJUST_REF_GVAR: + ret = RawSource(SOURCE_TYPE_GVAR, abs(value) - 1).toString(model); + if (value < 0) + ret.prepend("-"); + else if (sign) + ret.prepend("+"); + break; + default: + ret = "%1%"; + if (sign && value > 0) + ret.prepend("+"); + ret = ret.arg(value); + break; + } + return ret; +} diff --git a/companion/src/firmwares/adjustmentreference.h b/companion/src/firmwares/adjustmentreference.h new file mode 100644 index 000000000..2a7b7e141 --- /dev/null +++ b/companion/src/firmwares/adjustmentreference.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. + */ + +#ifndef ADJUSTMENTREFERENCE_H +#define ADJUSTMENTREFERENCE_H + +#include + +class ModelData; + +constexpr int ADJUST_REF_GVAR_BASE { 10000 }; + +class AdjustmentReference { + Q_DECLARE_TR_FUNCTIONS(AdjustmentReference) + + public: + enum AdjustRefType { + ADJUST_REF_VALUE, + ADJUST_REF_GVAR, + }; + + AdjustmentReference() { clear(); } + explicit AdjustmentReference(int value); + AdjustmentReference(const AdjustRefType type, const int value); + + void clear() { memset(this, 0, sizeof(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; + + inline const int toValue() const + { + if (type == ADJUST_REF_GVAR) + return value >= 0 ? value + ADJUST_REF_GVAR_BASE : value - ADJUST_REF_GVAR_BASE; + else + return value; + } + + bool operator== ( const AdjustmentReference & other) const { + return (this->type == other.type) && (this->value == other.value); + } + + bool operator!= ( const AdjustmentReference & other) const { + return (this->type != other.type) || (this->value != other.value); + } + + AdjustRefType type; + int value; +}; + +#endif // ADJUSTMENTREFERENCE_H diff --git a/companion/src/firmwares/curvereference.h b/companion/src/firmwares/curvereference.h index ff5571bb5..cb5be4e73 100644 --- a/companion/src/firmwares/curvereference.h +++ b/companion/src/firmwares/curvereference.h @@ -50,6 +50,7 @@ class CurveReference { int value; QString toString(const ModelData * model = NULL, bool verbose = true) const; + bool isSet() const { return type != CURVE_REF_DIFF || value != 0; } }; #endif // CURVEREFERENCE_H diff --git a/companion/src/firmwares/eeprominterface.h b/companion/src/firmwares/eeprominterface.h index 9632af1ac..c2bf0dafa 100644 --- a/companion/src/firmwares/eeprominterface.h +++ b/companion/src/firmwares/eeprominterface.h @@ -100,6 +100,8 @@ enum Capability { GvarsName, NoTelemetryProtocol, TelemetryCustomScreens, + TelemetryCustomScreensBars, + TelemetryCustomScreensLines, TelemetryCustomScreensFieldsPerLine, TelemetryMaxMultiplier, HasVario, @@ -149,7 +151,8 @@ enum Capability { DangerousFunctions, HasModelCategories, HasSwitchableJack, - PwrButtonPress + PwrButtonPress, + Sensors }; class EEPROMInterface diff --git a/companion/src/firmwares/generalsettings.cpp b/companion/src/firmwares/generalsettings.cpp index 1676e913c..9c38391c7 100644 --- a/companion/src/firmwares/generalsettings.cpp +++ b/companion/src/firmwares/generalsettings.cpp @@ -123,6 +123,12 @@ GeneralSettings::GeneralSettings() strcpy(bluetoothName, "taranis"); } + for (uint8_t i = 0; i < 4; i++) { + trainer.mix[i].mode = 2; // replace (:=) + trainer.mix[i].src = i; + trainer.mix[i].weight = 100; + } + templateSetup = g.profile[g.sessionId()].channelOrder(); stickMode = g.profile[g.sessionId()].defaultMode(); diff --git a/companion/src/firmwares/gvardata.cpp b/companion/src/firmwares/gvardata.cpp index 23c90cd2a..6ee1712d0 100644 --- a/companion/src/firmwares/gvardata.cpp +++ b/companion/src/firmwares/gvardata.cpp @@ -90,3 +90,8 @@ float GVarData::getMaxPrec() const { return getMax() * multiplierGet(); } + +bool GVarData::isEmpty() const +{ + return (name[0] == '\0' && min == 0 && max == 0 && (!popup) && prec == 0 && unit == 0); +} diff --git a/companion/src/firmwares/gvardata.h b/companion/src/firmwares/gvardata.h index 7718c5b21..e0d2da882 100644 --- a/companion/src/firmwares/gvardata.h +++ b/companion/src/firmwares/gvardata.h @@ -43,7 +43,7 @@ class GVarData { GVAR_PREC_MUL1 }; - char name[GVAR_NAME_LEN+1]; + char name[GVAR_NAME_LEN + 1]; int min; int max; bool popup; @@ -62,6 +62,7 @@ class GVarData { int getMax() const; float getMinPrec() const; float getMaxPrec() const; + bool isEmpty() const; }; diff --git a/companion/src/firmwares/io_data.cpp b/companion/src/firmwares/io_data.cpp index b0201d3d5..a958750d8 100644 --- a/companion/src/firmwares/io_data.cpp +++ b/companion/src/firmwares/io_data.cpp @@ -35,6 +35,10 @@ void ExpoData::convert(RadioDataConversionState & cstate) swtch.convert(cstate); } +bool ExpoData::isEmpty() const +{ + return (chn == 0 && mode == INPUT_MODE_NONE); +} /* * MixData @@ -48,6 +52,10 @@ void MixData::convert(RadioDataConversionState & cstate) swtch.convert(cstate); } +bool MixData::isEmpty() const +{ + return (destCh == 0); +} /* * LimitData @@ -87,17 +95,16 @@ void LimitData::clear() bool LimitData::isEmpty() const { - return (min == -1000 && max == 1000 && !revert && !offset && !ppmCenter && !symetrical && name[0] == '\0'); + return (min == -1000 && max == 1000 && !revert && !offset && !ppmCenter && !symetrical && name[0] == '\0' && !curve.isSet()); } - /* * CurveData */ CurveData::CurveData() { - clear(5); + clear(); } void CurveData::clear(int count) @@ -126,22 +133,20 @@ QString CurveData::nameToString(const int idx) const * FlightModeData */ -void FlightModeData::clear(const int phase) +void FlightModeData::clear(const int phaseIdx) { memset(reinterpret_cast(this), 0, sizeof(FlightModeData)); - if (phase != 0) { - for (int idx=0; idx(this), 0, sizeof(ExpoData)); } void convert(RadioDataConversionState & cstate); + bool isEmpty() const; }; enum MltpxValue { @@ -90,8 +93,11 @@ class MixData { 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) @@ -103,7 +109,7 @@ class LimitData { int offset; int ppmCenter; bool symetrical; - char name[6+1]; + char name[LIMITDATA_NAME_LEN+1]; CurveReference curve; QString minToString() const; QString maxToString() const; @@ -120,6 +126,8 @@ class CurvePoint { int8_t y; }; +#define CURVEDATA_NAME_LEN 6 + class CurveData { Q_DECLARE_TR_FUNCTIONS(CurveData) @@ -131,7 +139,7 @@ class CurveData { }; CurveData(); - void clear(int count); + void clear(int count = 5); bool isEmpty() const; QString nameToString(const int idx) const; @@ -139,9 +147,13 @@ class CurveData { bool smooth; int count; CurvePoint points[CPN_MAX_POINTS]; - char name[6+1]; + 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) @@ -151,14 +163,20 @@ class FlightModeData { int trimRef[CPN_MAX_TRIMS]; int trim[CPN_MAX_TRIMS]; RawSwitch swtch; - char name[10+1]; + 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 phase); - QString nameToString(int index) const; + 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 { diff --git a/companion/src/firmwares/modeldata.cpp b/companion/src/firmwares/modeldata.cpp index a2fdb4981..b72cc328a 100644 --- a/companion/src/firmwares/modeldata.cpp +++ b/companion/src/firmwares/modeldata.cpp @@ -25,6 +25,7 @@ #include "macros.h" #include "radiodataconversionstate.h" #include "helpers.h" +#include "adjustmentreference.h" /* * TimerData @@ -37,6 +38,10 @@ void TimerData::convert(RadioDataConversionState & cstate) 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 @@ -60,16 +65,16 @@ ModelData & ModelData::operator = (const ModelData & src) ExpoData * ModelData::insertInput(const int idx) { - memmove(&expoData[idx+1], &expoData[idx], (CPN_MAX_EXPOS-(idx+1))*sizeof(ExpoData)); + memmove(&expoData[idx + 1], &expoData[idx], (CPN_MAX_EXPOS - (idx + 1)) * sizeof(ExpoData)); expoData[idx].clear(); return &expoData[idx]; } bool ModelData::isInputValid(const unsigned int idx) const { - for (int i=0; imode == 0) break; + if (expo->mode == INPUT_MODE_NONE) break; if (expo->chn == idx) return true; } @@ -78,9 +83,9 @@ bool ModelData::isInputValid(const unsigned int idx) const bool ModelData::hasExpos(uint8_t inputIdx) const { - for (int i=0; i ModelData::expos(int input) const { QVector result; - for (int i=0; ichn==input && ed->mode!=0) { + if ((int)ed->chn == input && ed->mode != INPUT_MODE_NONE) { result << ed; } } @@ -113,9 +118,9 @@ QVector ModelData::expos(int input) const QVector ModelData::mixes(int channel) const { QVector result; - for (int i=0; idestCh == channel+1) { + if ((int)md->destCh == channel + 1) { result << md; } } @@ -126,8 +131,8 @@ void ModelData::removeInput(const int idx, bool clearName) { unsigned int chn = expoData[idx].chn; - memmove(&expoData[idx], &expoData[idx+1], (CPN_MAX_EXPOS-(idx+1))*sizeof(ExpoData)); - expoData[CPN_MAX_EXPOS-1].clear(); + memmove(&expoData[idx], &expoData[idx + 1], (CPN_MAX_EXPOS - (idx + 1)) * sizeof(ExpoData)); + expoData[CPN_MAX_EXPOS - 1].clear(); //also remove input name if removing last line for this input if (clearName && !expos(chn).size()) @@ -136,12 +141,12 @@ void ModelData::removeInput(const int idx, bool clearName) void ModelData::clearInputs() { - for (int i=0; igetCapability(VirtualInputs)) { - for (int i=0; ichn = i; expo->mode = INPUT_MODE_BOTH; expo->srcRaw = settings.getDefaultSource(i); expo->weight = 100; - strncpy(inputNames[i], Helpers::removeAccents(expo->srcRaw.toString(this)).toLatin1().constData(), sizeof(inputNames[i])-1); + strncpy(inputNames[i], Helpers::removeAccents(expo->srcRaw.toString(this)).toLatin1().constData(), sizeof(inputNames[i]) - 1); } } } @@ -222,9 +227,9 @@ void ModelData::setDefaultMixes(const GeneralSettings & settings) setDefaultInputs(settings); } - for (int i=0; idestCh = i+1; + mix->destCh = i + 1; mix->weight = 100; if (IS_ARM(board)) { mix->srcRaw = RawSource(SOURCE_TYPE_VIRTUAL_INPUT, i); @@ -240,8 +245,8 @@ void ModelData::setDefaultValues(unsigned int id, const GeneralSettings & settin clear(); used = true; sprintf(name, "MODEL%02d", id+1); - for (int i=0; i 1024; + return flightModeData[phaseIdx].gvars[gvarIdx] > GVAR_MAX_VALUE; } -int ModelData::getGVarFieldValue(int phaseIdx, int gvarIdx) +bool ModelData::isGVarLinkedCircular(int phaseIdx, int gvarIdx) { - int idx = flightModeData[phaseIdx].gvars[gvarIdx]; - for (int i=0; idx>GVAR_MAX_VALUE && i= phaseIdx) nextPhase += 1; + for (int i = 0; i < CPN_MAX_FLIGHT_MODES; i++) { + int val = flightModeData[phaseIdx].gvars[gvarIdx]; + if (phaseIdx == 0 || val <= GVAR_MAX_VALUE) + return false; + int nextPhase = val - (GVAR_MAX_VALUE + 1); + if (nextPhase >= phaseIdx) + nextPhase += 1; phaseIdx = nextPhase; - idx = flightModeData[phaseIdx].gvars[gvarIdx]; } - return idx; + return true; +} + +int ModelData::getGVarValue(int phaseIdx, int gvarIdx) +{ + for (int i = 0; i < CPN_MAX_FLIGHT_MODES; i++) { + int val = flightModeData[phaseIdx].gvars[gvarIdx]; + if (phaseIdx == 0 || val <= GVAR_MAX_VALUE) + return val; + int nextPhase = val - (GVAR_MAX_VALUE + 1); + if (nextPhase >= phaseIdx) + nextPhase += 1; + phaseIdx = nextPhase; + } + return flightModeData[0].gvars[gvarIdx]; // circular linked so return FM0 value +} + +bool ModelData::isREncLinked(int phaseIdx, int reIdx) +{ + return flightModeData[phaseIdx].rotaryEncoders[reIdx] > RENC_MAX_VALUE; +} + +bool ModelData::isREncLinkedCircular(int phaseIdx, int reIdx) +{ + for (int i = 0; i < CPN_MAX_FLIGHT_MODES; i++) { + int val = flightModeData[phaseIdx].rotaryEncoders[reIdx]; + if (phaseIdx == 0 || val <= RENC_MAX_VALUE) + return false; + int nextPhase = val - (RENC_MAX_VALUE + 1); + if (nextPhase >= phaseIdx) + nextPhase += 1; + phaseIdx = nextPhase; + } + return true; +} + +int ModelData::getREncValue(int phaseIdx, int reIdx) +{ + for (int i = 0; i < CPN_MAX_FLIGHT_MODES; i++) { + int val = flightModeData[phaseIdx].rotaryEncoders[reIdx]; + if (phaseIdx == 0 || val <= RENC_MAX_VALUE) + return val; + int nextPhase = val - (RENC_MAX_VALUE + 1); + if (nextPhase >= phaseIdx) + nextPhase += 1; + phaseIdx = nextPhase; + } + return flightModeData[0].rotaryEncoders[reIdx]; // circular linked so return FM0 value } void ModelData::setTrimValue(int phaseIdx, int trimIdx, int value) { - for (uint8_t i=0; i= 126 && var <= 130) - var = flightModeData[0].gvars[var-126]; + var = flightModeData[0].gvars[var - 126]; else if (var <= -126 && var >= -130) - var = - flightModeData[0].gvars[-126-var]; + var = - flightModeData[0].gvars[-126 - var]; } ModelData ModelData::removeGlobalVars() { ModelData result = *this; - for (int i=0; isize() <= MAX_REF_UPDATES) + updRefList->append(UpdateReferenceParams(type, action, index1, index2, shift)); + else + qDebug() << "Warning: Update ignored as the list of updates exceeds " << MAX_REF_UPDATES; + } +} + +int ModelData::updateAllReferences(const ReferenceUpdateType type, const ReferenceUpdateAction action, const int index1, const int index2, const int shift) +{ + //Stopwatch s1("ModelData::updateAllReferences"); + //s1.report("Start"); + + int loopcnt = 0; + int updcnt = 0; + updRefList = nullptr; + QVector updRefParams; // declaring this variable in ModelData class crashes program on opening model file + updRefList = &updRefParams; // so declare pointer variable in ModelData class and pass it the address of the local array + + if (updRefList) { + appendUpdateReferenceParams(type, action, index1, index2, shift); + + while (!updRefList->isEmpty()) + { + if (++loopcnt > MAX_REF_UPDATES) { + qDebug() << "Warning: Update iterations terminated early as the list exceeded " << MAX_REF_UPDATES; + break; + } + //qDebug() << "Start of iteration:" << loopcnt; + updcnt += updateReference(); + updRefList->removeFirst(); + } + } + + qDebug() << "Iterations:" << loopcnt << " References updated:" << updcnt; + //s1.report("Finish"); + + return updcnt; +} + +int ModelData::updateReference() +{ + UpdateReferenceParams p = updRefList->first(); + + if (p.action < REF_UPD_ACT_CLEAR || p.action > REF_UPD_ACT_SWAP || p.type < REF_UPD_TYPE_CHANNEL || p.type > REF_UPD_TYPE_TIMER) { + qDebug() << "Error - invalid parameters" << " > type:" << p.type << " action:" << p.action << " index1:" << p.index1 << " index2:" << p.index2 << " shift:" << p.shift; + return 0; + } + + memset(&updRefInfo, 0, sizeof(updRefInfo)); + updRefInfo.type = p.type; + updRefInfo.action = p.action; + updRefInfo.index1 = abs(p.index1); + updRefInfo.index2 = abs(p.index2); + updRefInfo.shift = p.shift; + + if ((updRefInfo.action == REF_UPD_ACT_SWAP && updRefInfo.index1 == updRefInfo.index2) || (updRefInfo.action == REF_UPD_ACT_SHIFT && updRefInfo.shift == 0)) { + qDebug() << "Warning - nothing to do" << " > type:" << updRefInfo.type << " action:" << updRefInfo.action << " index1:" << updRefInfo.index1 << " index2:" << updRefInfo.index2 << " shift:" << updRefInfo.shift; + return 0; + } + + //Stopwatch s1("ModelData::updateReference"); + //s1.report("Start"); + + Firmware *fw = getCurrentFirmware(); + + switch (updRefInfo.type) + { + case REF_UPD_TYPE_CHANNEL: + updRefInfo.srcType = SOURCE_TYPE_CH; + updRefInfo.maxindex = fw->getCapability(Outputs); + break; + case REF_UPD_TYPE_CURVE: + updRefInfo.maxindex = fw->getCapability(NumCurves); + break; + case REF_UPD_TYPE_FLIGHT_MODE: + updRefInfo.swtchType = SWITCH_TYPE_FLIGHT_MODE; + updRefInfo.maxindex = fw->getCapability(FlightModes); + break; + case REF_UPD_TYPE_GLOBAL_VARIABLE: + updRefInfo.srcType = SOURCE_TYPE_GVAR; + updRefInfo.maxindex = fw->getCapability(Gvars); + break; + case REF_UPD_TYPE_INPUT: + updRefInfo.srcType = SOURCE_TYPE_VIRTUAL_INPUT; + updRefInfo.maxindex = fw->getCapability(VirtualInputs); + break; + case REF_UPD_TYPE_LOGICAL_SWITCH: + updRefInfo.srcType = SOURCE_TYPE_CUSTOM_SWITCH; + updRefInfo.swtchType = SWITCH_TYPE_VIRTUAL; + updRefInfo.maxindex = fw->getCapability(LogicalSwitches); + break; + case REF_UPD_TYPE_SCRIPT: + updRefInfo.srcType = SOURCE_TYPE_LUA_OUTPUT; + updRefInfo.maxindex = fw->getCapability(LuaScripts); + break; + case REF_UPD_TYPE_SENSOR: + updRefInfo.srcType = SOURCE_TYPE_TELEMETRY; + updRefInfo.swtchType = SWITCH_TYPE_SENSOR; + updRefInfo.maxindex = fw->getCapability(Sensors); + break; + case REF_UPD_TYPE_TIMER: + updRefInfo.srcType = SOURCE_TYPE_SPECIAL; + updRefInfo.maxindex = fw->getCapability(Timers); + // rawsource index offset TODO refactor timers so be own category + updRefInfo.index1 += 2; + updRefInfo.index2 += 2; + updRefInfo.maxindex += 2; + break; + default: + qDebug() << "Error - unhandled reference type:" << updRefInfo.type; + return 0; + } + + updRefInfo.maxindex--; // getCapabilities and constants are 1 based + + //qDebug() << "updRefInfo - type:" << updRefInfo.type << " action:" << updRefInfo.action << " index1:" << updRefInfo.index1 << " index2:" << updRefInfo.index2 << " shift:" << updRefInfo.shift; + //qDebug() << "maxindex:" << updRefInfo.maxindex << "updRefInfo - srcType:" << updRefInfo.srcType << " swtchType:" << updRefInfo.swtchType; + + //s1.report("Initialise"); + + for (int i = fw->getCapability(NumFirstUsableModule); i < fw->getCapability(NumModules); i++) { + ModuleData *md = &moduleData[i]; + if (md->protocol != PULSES_OFF && md->failsafeMode == FAILSAFE_CUSTOM && md->hasFailsafes(fw)) + updateModuleFailsafes(md); + } + //s1.report("Modules"); + + for (int i = 0; i < CPN_MAX_TIMERS; i++) { + TimerData *td = &timers[i]; + if (!td->isModeOff()) { + updateTimerMode(td->mode); + if (td->isModeOff()) + appendUpdateReferenceParams(REF_UPD_TYPE_TIMER, REF_UPD_ACT_CLEAR, i); + } + } + //s1.report("Timers"); + + for (int i = 1; i < CPN_MAX_FLIGHT_MODES; i++) { // skip FM0 as switch not used + FlightModeData *fmd = &flightModeData[i]; + if (fmd->swtch.isSet()) { + updateSwitchRef(fmd->swtch); + if(!fmd->swtch.isSet()) + appendUpdateReferenceParams(REF_UPD_TYPE_FLIGHT_MODE, REF_UPD_ACT_CLEAR, i); + } + } + //s1.report("Flight Modes"); + + for (int i = 0; i < CPN_MAX_EXPOS; i++) { + ExpoData *ed = &expoData[i]; + if (!ed->isEmpty()) { + updateSourceRef(ed->srcRaw); + if (ed->srcRaw.isSet()) { + updateSwitchRef(ed->swtch); + updateCurveRef(ed->curve); + updateAdjustRef(ed->weight); + updateAdjustRef(ed->offset); + updateFlightModeFlags(ed->flightModes); + } + else { + unsigned int chnsave = ed->chn; + removeInput(i); + i--; + if (!hasExpos(chnsave)) + appendUpdateReferenceParams(REF_UPD_TYPE_INPUT, REF_UPD_ACT_CLEAR, chnsave); + } + } + } + //s1.report("Inputs"); + + for (int i = 0; i < CPN_MAX_MIXERS; i++) { + MixData *md = &mixData[i]; + if (!md->isEmpty()) { + updateDestCh(md); + if (!md->isEmpty()) { + updateSourceRef(md->srcRaw); + if (md->srcRaw.isSet()) { + updateSwitchRef(md->swtch); + updateCurveRef(md->curve); + updateAdjustRef(md->weight); + updateAdjustRef(md->sOffset); + updateFlightModeFlags(md->flightModes); + } + else { + removeMix(i); + i--; + } + } + } + } + //s1.report("Mixes"); + + for (int i = 0; i < CPN_MAX_CHNOUT; i++) { + LimitData *ld = &limitData[i]; + if (!ld->isEmpty()) { + updateAdjustRef(ld->min); + updateAdjustRef(ld->max); + updateAdjustRef(ld->offset); + updateLimitCurveRef(ld->curve); + } + } + //s1.report("Outputs"); + + for (int i = 0; i < CPN_MAX_LOGICAL_SWITCHES; i++) { + LogicalSwitchData *lsd = &logicalSw[i]; + if (!lsd->isEmpty()) { + bool clearlsd = false; + CSFunctionFamily family = lsd->getFunctionFamily(); + switch(family) { + case LS_FAMILY_VOFS: + 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) + clearlsd = true; + break; + case LS_FAMILY_EDGE: + 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) + clearlsd = true; + break; + default: + break; + } + if (clearlsd) { + lsd->clear(); + appendUpdateReferenceParams(REF_UPD_TYPE_LOGICAL_SWITCH, REF_UPD_ACT_CLEAR, i); + } + else { + updateSwitchIntRef(lsd->andsw); + } + } + } + //s1.report("Logical Switches"); + + for (int i = 0; i < CPN_MAX_SPECIAL_FUNCTIONS; i++) { + CustomFunctionData *cfd = &customFn[i]; + if (!cfd->isEmpty()) { + 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))) { + updateSourceIntRef(cfd->param); + if (cfd->param == 0) + cfd->clear(); + } + } + } + } + //s1.report("Special Functions"); + + if (fw->getCapability(Heli)) { + updateSourceRef(swashRingData.aileronSource); + updateSourceRef(swashRingData.collectiveSource); + updateSourceRef(swashRingData.elevatorSource); + //s1.report("Heli"); + } + + if (fw->getCapability(Telemetry)) { + updateTelemetryRef(frsky.voltsSource); + updateTelemetryRef(frsky.altitudeSource); + updateTelemetryRef(frsky.currentSource); + updateTelemetryRef(frsky.varioSource); + for (int i = 0; i < fw->getCapability(TelemetryCustomScreens); i++) { + switch(frsky.screens[i].type) { + case TELEMETRY_SCREEN_BARS: + for (int j = 0; j < fw->getCapability(TelemetryCustomScreensBars); j++) { + FrSkyBarData *fbd = &frsky.screens[i].body.bars[j]; + updateSourceRef(fbd->source); + if (!fbd->source.isSet()) { + fbd->barMin = 0; + fbd->barMax = 0; + } + } + break; + case TELEMETRY_SCREEN_NUMBERS: + for (int j = 0; j < fw->getCapability(TelemetryCustomScreensLines); j++) { + FrSkyLineData *fld = &frsky.screens[i].body.lines[j]; + for (int k = 0; k < fw->getCapability(TelemetryCustomScreensFieldsPerLine); k++) { + updateSourceRef(fld->source[k]); + } + } + break; + default: + break; + } + } + //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) { + } + } + 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 + /* + for (int i=0; i < CPN_MAX_SCRIPTS; i++) { + ScriptData *sd = &scriptData[i]; + if (sd->filename[0] != '\0') { + for (int j = 0; j < CPN_MAX_SCRIPT_INPUTS; j++) { + // get input parameters and for each one where type is SOURCE + if(inputtype = "SOURCE") + updateSourceIntRef(sd->inputs[j]); + } + } + } + s1.report("Custom Scripts"); + */ + + // TODO Horus CustomScreenData and TopBarData will need checking for updates but Companion does not current handle ie just data blobs refer modeldata.h + + qDebug() << "References updated this iteration:" << updRefInfo.updcnt; + //s1.report("Finish"); + + return updRefInfo.updcnt; +} + +template +void ModelData::updateTypeIndexRef(R & curRef, const T type, const int idxAdj, const bool defClear, const int defType, const int defIndex) +{ + //qDebug() << "Raw value: " << curRef.toValue() << " String:" << curRef.toString() << " Type: " << curRef.type << " Index:" << curRef.index << " idxAdj:" << idxAdj << " defClear:" << defClear << " defType:" << defType << " defIndex:" << defIndex; + if (!curRef.isSet() || curRef.type != type) + return; + + R newRef; + newRef.type = curRef.type; + newRef.index = abs(curRef.index); + + switch (updRefInfo.action) + { + case REF_UPD_ACT_CLEAR: + if (newRef.index != (updRefInfo.index1 + idxAdj)) + return; + if (defClear) + newRef.clear(); + else { + newRef.type = (T)defType; + newRef.index = defIndex; + } + break; + case REF_UPD_ACT_SHIFT: + if (newRef.index < (updRefInfo.index1 + idxAdj)) + return; + + newRef.index += updRefInfo.shift; + + if (newRef.index < (updRefInfo.index1 + idxAdj) || newRef.index > (updRefInfo.maxindex + idxAdj)) { + if (defClear) + newRef.clear(); + else { + newRef.type = (T)defType; + newRef.index = defIndex; + } + } + 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; + break; + default: + qDebug() << "Error - unhandled action:" << updRefInfo.action; + return; + } + + if (curRef.type != newRef.type || abs(curRef.index) != newRef.index) { + newRef.index = curRef.index < 0 ? -newRef.index : newRef.index; + //qDebug() << "Updated reference: " << curRef.toString() << " -> " << newRef.toString(); + curRef = newRef; + updRefInfo.updcnt++; + } +} + +template +void ModelData::updateTypeValueRef(R & curRef, const T type, const int idxAdj, const bool defClear, const int defType, const int defValue) +{ + //qDebug() << " String:" << curRef.toString() << " Type: " << curRef.type << " Value:" << curRef.value; + if (!curRef.isSet() || curRef.type != type) + return; + + R newRef; + newRef.type = curRef.type; + newRef.value = abs(curRef.value); + + switch (updRefInfo.action) + { + case REF_UPD_ACT_CLEAR: + if (newRef.value != (updRefInfo.index1 + idxAdj)) + return; + if (defClear) + newRef.clear(); + else { + newRef.type = (T)defType; + newRef.value = defValue; + } + break; + case REF_UPD_ACT_SHIFT: + if (newRef.value < (updRefInfo.index1 + idxAdj)) + return; + + newRef.value += updRefInfo.shift; + + if (newRef.value < (updRefInfo.index1 + idxAdj) || newRef.value > (updRefInfo.maxindex + idxAdj)) { + if (defClear) + newRef.clear(); + else { + newRef.type = (T)defType; + newRef.value = defValue; + } + } + break; + case REF_UPD_ACT_SWAP: + if (newRef.value == updRefInfo.index1 + idxAdj) + newRef.value = updRefInfo.index2 + idxAdj; + else if (newRef.value == updRefInfo.index2 + idxAdj) + newRef.value = updRefInfo.index1 + idxAdj; + break; + default: + qDebug() << "Error - unhandled action:" << updRefInfo.action; + return; + } + + if (curRef.type != newRef.type || abs(curRef.value) != newRef.value) { + newRef.value = curRef.value < 0 ? -newRef.value : newRef.value; + //qDebug() << "Updated reference: " << curRef.toString() << " -> " << newRef.toString(); + curRef = newRef; + updRefInfo.updcnt++; + } +} + +void ModelData::updateCurveRef(CurveReference & crv) +{ + if (updRefInfo.type == REF_UPD_TYPE_GLOBAL_VARIABLE && (crv.type == CurveReference::CURVE_REF_DIFF || crv.type == CurveReference::CURVE_REF_EXPO)) + updateAdjustRef(crv.value); + else if (updRefInfo.type == REF_UPD_TYPE_CURVE && crv.type == CurveReference::CURVE_REF_CUSTOM) + updateTypeValueRef(crv, CurveReference::CURVE_REF_CUSTOM, 1); +} + +void ModelData::updateLimitCurveRef(CurveReference & crv) +{ + CurveReference src = CurveReference(CurveReference::CURVE_REF_CUSTOM, crv.value); + updateCurveRef(src); + if (crv.value != src.value) + crv.value = src.value; +} + +void ModelData::updateAdjustRef(int & value) +{ + if (updRefInfo.type != REF_UPD_TYPE_GLOBAL_VARIABLE) + return; + + AdjustmentReference adj = AdjustmentReference(value); + updateTypeValueRef(adj, AdjustmentReference::ADJUST_REF_GVAR, 1); + if (value != adj.toValue()) + value = adj.toValue(); +} + +void ModelData::updateAssignFunc(CustomFunctionData * cfd) +{ + const int invalidateRef = -1; + int newRef = (int)cfd->func; + int idxAdj; + + switch (updRefInfo.type) + { + case REF_UPD_TYPE_CHANNEL: + if(cfd->func < FuncOverrideCH1 || cfd->func > FuncOverrideCH32) // TODO refactor to FuncOverrideCHLast + return; + idxAdj = FuncOverrideCH1; + break; + case REF_UPD_TYPE_GLOBAL_VARIABLE: + if (cfd->func < FuncAdjustGV1 || cfd->func > FuncAdjustGVLast) + return; + idxAdj = FuncAdjustGV1; + break; + 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 + 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->func != (AssignFunc)newRef) { + //qDebug() << "Updated reference:" << cfd->func << " -> " << newRef; + cfd->func = (AssignFunc)newRef; + updRefInfo.updcnt++; + } +} + +void ModelData::updateDestCh(MixData * md) +{ + if (updRefInfo.type != REF_UPD_TYPE_CHANNEL) + return; + + const int invalidateRef = -1; + const int idxAdj = 1; + int newRef = md->destCh; + 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) { + md->clear(); + //qDebug() << "Mix cleared"; + updRefInfo.updcnt++; + } + else if (md->destCh != static_cast(newRef)) { + //qDebug() << "Updated reference:" << md->destCh << " -> " << newRef; + md->destCh = newRef; + updRefInfo.updcnt++; + } +} + +void ModelData::updateFlightModeFlags(unsigned int & curRef) +{ + if (updRefInfo.type != REF_UPD_TYPE_FLIGHT_MODE || curRef == 0 /*all selected*/ || curRef == 511 /*all deselected*/) + return; + + if (updRefInfo.index1 > CPN_MAX_FLIGHT_MODES || updRefInfo.index2 > CPN_MAX_FLIGHT_MODES) + return; + + unsigned int newRef = curRef; + bool flag[CPN_MAX_FLIGHT_MODES]; + bool f; + + int mask = 1; + for (int i = 0; i < CPN_MAX_FLIGHT_MODES; i++) { + flag[i] = curRef & mask; + mask <<= 1; + } + + switch (updRefInfo.action) + { + case REF_UPD_ACT_CLEAR: + flag[updRefInfo.index1] = false; + break; + case REF_UPD_ACT_SHIFT: + if(updRefInfo.shift < 0) { + for (int i = updRefInfo.index1; i < CPN_MAX_FLIGHT_MODES; i++) { + if (i - updRefInfo.shift <= updRefInfo.maxindex) + flag[i] = flag[i - updRefInfo.shift]; + else + flag[i] = false; + } + } + else { + for (int i = CPN_MAX_FLIGHT_MODES - 1; i >= updRefInfo.index1; i--) { + if (i - updRefInfo.shift >= updRefInfo.index1) + flag[i] = flag[i - updRefInfo.shift]; + else + flag[i] = false; + } + } + break; + case REF_UPD_ACT_SWAP: + f = flag[updRefInfo.index1]; + flag[updRefInfo.index1] = flag[updRefInfo.index2]; + flag[updRefInfo.index2] = f; + break; + default: + qDebug() << "Error - unhandled action:" << updRefInfo.action; + return; + } + + newRef = 0; + for (int i = CPN_MAX_FLIGHT_MODES - 1; i >= 0 ; i--) { + if (flag[i]) + newRef++; + newRef <<= 1; + } + newRef >>= 1; + + if (curRef != newRef) { + //qDebug() << "Updated reference:" << curRef << " -> " << newRef; + curRef = newRef; + updRefInfo.updcnt++; + } +} + +void ModelData::updateTelemetryRef(unsigned 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: + if (newRef != (updRefInfo.index1 + idxAdj)) + return; + newRef = 0; + 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 = 0; + 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 (curRef != static_cast(newRef)) { + //qDebug() << "Updated reference:" << curRef << " -> " << newRef; + curRef = newRef; + updRefInfo.updcnt++; + } +} + +void ModelData::updateModuleFailsafes(ModuleData * md) +{ + if (updRefInfo.type != REF_UPD_TYPE_CHANNEL) + return; + + bool updated = false; + + switch (updRefInfo.action) + { + case REF_UPD_ACT_CLEAR: + break; + case REF_UPD_ACT_SHIFT: + if (updRefInfo.shift == 0 || updRefInfo.index1 < 0 || updRefInfo.index1 > CPN_MAX_CHNOUT - 1) + return; + + if (updRefInfo.shift > 0) { + for (int i = (CPN_MAX_CHNOUT - 1); i > updRefInfo.index1; i--) { + md->failsafeChannels[i] = md->failsafeChannels[i - 1]; + } + md->failsafeChannels[updRefInfo.index1] = 0; + } + else { + for (int i = (updRefInfo.index1 + 1); i < (CPN_MAX_CHNOUT - 1); i++) { + md->failsafeChannels[i - 1] = md->failsafeChannels[i]; + } + md->failsafeChannels[CPN_MAX_CHNOUT - 1] = 0; + } + updated = true; + break; + case REF_UPD_ACT_SWAP: + int tmp; + if (updRefInfo.index1 >= 0 && updRefInfo.index1 < CPN_MAX_CHNOUT) { + updated = true; + tmp = md->failsafeChannels[updRefInfo.index1]; + if (updRefInfo.index2 >= 0 && updRefInfo.index2 < CPN_MAX_CHNOUT) + md->failsafeChannels[updRefInfo.index1] = md->failsafeChannels[updRefInfo.index2]; + else + md->failsafeChannels[updRefInfo.index1] = 0; + } + else + tmp = 0; + if (updRefInfo.index2 >= 0 && updRefInfo.index2 < CPN_MAX_CHNOUT) + updated = true; + md->failsafeChannels[updRefInfo.index2] = tmp; + break; + default: + qDebug() << "Error - unhandled action:" << updRefInfo.action; + return; + } + + if (updated) { + //qDebug() << "Updated module failsafes"; + updRefInfo.updcnt++; + } +} + +int ModelData::linkedFlightModeIndexToValue(const int phaseIdx, const int useFmIdx, const int maxOwnValue) +{ + int val; + + if (phaseIdx == useFmIdx || phaseIdx < 0 || phaseIdx > (CPN_MAX_FLIGHT_MODES - 1) || useFmIdx < 0 || useFmIdx > (CPN_MAX_FLIGHT_MODES - 1)) + val = flightModeData[phaseIdx].linkedFlightModeZero(phaseIdx, maxOwnValue); + else + val = maxOwnValue + useFmIdx + (useFmIdx >= phaseIdx ? 0 : 1); + + return val; +} + +int ModelData::linkedFlightModeValueToIndex(const int phaseIdx, const int val, const int maxOwnValue) +{ + int idx = val - maxOwnValue - 1; + if (idx >= phaseIdx) + idx += 1; + return idx; +} + +int ModelData::getGVarFlightModeIndex(const int phaseIdx, const int gvarIdx) +{ + if (!isGVarLinked(phaseIdx, gvarIdx)) + return -1; + return (linkedFlightModeValueToIndex(phaseIdx, flightModeData[phaseIdx].gvars[gvarIdx], GVAR_MAX_VALUE)); +} + +void ModelData::setGVarFlightModeIndexToValue(const int phaseIdx, const int gvarIdx, const int useFmIdx) +{ + flightModeData[phaseIdx].gvars[gvarIdx] = linkedFlightModeIndexToValue(phaseIdx, useFmIdx, GVAR_MAX_VALUE); +} + +int ModelData::getREncFlightModeIndex(const int phaseIdx, const int reIdx) +{ + if (!isREncLinked(phaseIdx, reIdx)) + return -1; + return (linkedFlightModeValueToIndex(phaseIdx, flightModeData[phaseIdx].rotaryEncoders[reIdx], RENC_MAX_VALUE)); +} + +void ModelData::setREncFlightModeIndexToValue(const int phaseIdx, const int reIdx, const int useFmIdx) +{ + flightModeData[phaseIdx].rotaryEncoders[reIdx] = linkedFlightModeIndexToValue(phaseIdx, useFmIdx, RENC_MAX_VALUE); +} + +bool ModelData::isExpoParent(const int index) +{ + const ExpoData &ed = expoData[index]; + const QVector chexpos = expos(ed.chn); + return chexpos.constFirst() == &ed; +} + +bool ModelData::isExpoChild(const int index) +{ + const ExpoData &ed = expoData[index]; + const QVector chexpos = expos(ed.chn); + return chexpos.constFirst() != &ed; +} + +bool ModelData::hasExpoChildren(const int index) +{ + const ExpoData &ed = expoData[index]; + const QVector chexpos = expos(ed.chn); + return chexpos.constFirst() == &ed && chexpos.constLast() != &ed; +} + +bool ModelData::hasExpoSiblings(const int index) +{ + const ExpoData &ed = expoData[index]; + const QVector chexpos = expos(ed.chn); + return !isExpoParent(index) && chexpos.size() > 2; +} + +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(); +} diff --git a/companion/src/firmwares/modeldata.h b/companion/src/firmwares/modeldata.h index c4959d456..93e98588e 100644 --- a/companion/src/firmwares/modeldata.h +++ b/companion/src/firmwares/modeldata.h @@ -76,6 +76,8 @@ class TimerData { 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 @@ -128,6 +130,8 @@ enum TrainerMode { TRAINER_MODE_MULTI }; +#define INPUT_NAME_LEN 4 + class ModelData { Q_DECLARE_TR_FUNCTIONS(ModelData) @@ -170,7 +174,7 @@ class ModelData { MixData mixData[CPN_MAX_MIXERS]; LimitData limitData[CPN_MAX_CHNOUT]; - char inputNames[CPN_MAX_INPUTS][4+1]; + char inputNames[CPN_MAX_INPUTS][INPUT_NAME_LEN+1]; ExpoData expoData[CPN_MAX_EXPOS]; CurveData curves[CPN_MAX_CURVES]; @@ -219,11 +223,23 @@ class ModelData { void setTrimValue(int phaseIdx, int trimIdx, int value); bool isGVarLinked(int phaseIdx, int gvarIdx); - int getGVarFieldValue(int phaseIdx, int gvarIdx); - float getGVarFieldValuePrec(int phaseIdx, int gvarIdx); + bool isGVarLinkedCircular(int phaseIdx, int gvarIdx); + int getGVarValue(int phaseIdx, int gvarIdx); + float getGVarValuePrec(int phaseIdx, int gvarIdx); + int getGVarFlightModeIndex(const int phaseIdx, const int gvarIdx); + void setGVarFlightModeIndexToValue(const int phaseIdx, const int gvarIdx, const int useFmIdx); + + bool isREncLinked(int phaseIdx, int reIdx); + bool isREncLinkedCircular(int phaseIdx, int reIdx); + int getREncValue(int phaseIdx, int reIdx); + int getREncFlightModeIndex(const int phaseIdx, const int reIdx); + void setREncFlightModeIndexToValue(const int phaseIdx, const int reIdx, const int useFmIdx); ModelData removeGlobalVars(); + int linkedFlightModeIndexToValue(const int phaseIdx, const int useFmIdx, const int maxOwnValue); + int linkedFlightModeValueToIndex(const int phaseIdx, const int val, const int maxOwnValue); + void clearMixes(); void clearInputs(); @@ -231,8 +247,95 @@ class ModelData { bool isAvailable(const RawSwitch & swtch) const; + enum ReferenceUpdateAction { + REF_UPD_ACT_CLEAR, + REF_UPD_ACT_SHIFT, + REF_UPD_ACT_SWAP, + }; + + enum ReferenceUpdateType { + REF_UPD_TYPE_CHANNEL, + REF_UPD_TYPE_CURVE, + REF_UPD_TYPE_FLIGHT_MODE, + REF_UPD_TYPE_GLOBAL_VARIABLE, + REF_UPD_TYPE_INPUT, + REF_UPD_TYPE_LOGICAL_SWITCH, + REF_UPD_TYPE_SCRIPT, + REF_UPD_TYPE_SENSOR, + REF_UPD_TYPE_TIMER, + }; + + struct UpdateReferenceParams + { + ReferenceUpdateType type; + ReferenceUpdateAction action; + int index1; + int index2; + int shift; + + UpdateReferenceParams() {} + UpdateReferenceParams(ReferenceUpdateType t, ReferenceUpdateAction a, int i1, int i2 = 0, int s = 0) : + type(t), action(a), index1(i1), index2(i2), shift(s) {} + }; + + int updateAllReferences(const ReferenceUpdateType type, const ReferenceUpdateAction action, const int index1, const int index2 = 0, const int shift = 0); + bool isExpoParent(const int index); + bool isExpoChild(const int index); + bool hasExpoChildren(const int index); + bool hasExpoSiblings(const int index); + void removeMix(const int idx); + protected: void removeGlobalVar(int & var); + + private: + QVector *updRefList = nullptr; + + struct UpdateReferenceInfo + { + ReferenceUpdateType type; + ReferenceUpdateAction action; + int index1; + int index2; + int shift; + int updcnt; + int maxindex; + RawSourceType srcType; + RawSwitchType swtchType; + }; + UpdateReferenceInfo updRefInfo; + + int updateReference(); + void appendUpdateReferenceParams(const ReferenceUpdateType type, const ReferenceUpdateAction action, const int index1, const int index2 = 0, const int shift = 0); + template + void updateTypeIndexRef(R & curref, const T type, const int idxAdj = 0, const bool defClear = true, const int defType = 0, const int defIndex = 0); + template + void updateTypeValueRef(R & curref, const T type, const int idxAdj = 0, const bool defClear = true, const int defType = 0, const int defValue = 0); + void updateAdjustRef(int & adj); + void updateAssignFunc(CustomFunctionData * cfd); + void updateCurveRef(CurveReference & crv); + void updateDestCh(MixData * md); + void updateLimitCurveRef(CurveReference & crv); + void updateFlightModeFlags(unsigned int & flags); + void updateTelemetryRef(unsigned int & idx); + void updateModuleFailsafes(ModuleData * md); + inline void updateSourceRef(RawSource & src) { updateTypeIndexRef(src, updRefInfo.srcType); } + inline void updateSwitchRef(RawSwitch & swtch) { updateTypeIndexRef(swtch, updRefInfo.swtchType, 1); } + inline void updateTimerMode(RawSwitch & swtch) { updateTypeIndexRef(swtch, updRefInfo.swtchType, 1, false, (int)SWITCH_TYPE_TIMER_MODE, 0); } + inline void updateSourceIntRef(int & value) + { + RawSource src = RawSource(value); + updateTypeIndexRef(src, updRefInfo.srcType); + if (value != src.toValue()) + value = src.toValue(); + } + inline void updateSwitchIntRef(int & value) + { + RawSwitch swtch = RawSwitch(value); + updateTypeIndexRef(swtch, updRefInfo.swtchType, 1); + if (value != swtch.toValue()) + value = swtch.toValue(); + } }; #endif // MODELDATA_H diff --git a/companion/src/firmwares/moduledata.cpp b/companion/src/firmwares/moduledata.cpp index a227dd5b8..370a6979b 100644 --- a/companion/src/firmwares/moduledata.cpp +++ b/companion/src/firmwares/moduledata.cpp @@ -181,3 +181,59 @@ QStringList ModuleData::powerValueStrings(int subType, Firmware * fw) strIdx += 2; return strings[strIdx]; } + +bool ModuleData::hasFailsafes(Firmware * fw) const +{ + return fw->getCapability(HasFailsafe) && ( + protocol == PULSES_ACCESS_ISRM || + protocol == PULSES_ACCST_ISRM_D16 || + protocol == PULSES_PXX_XJT_X16 || + protocol == PULSES_PXX_R9M || + protocol == PULSES_ACCESS_R9M || + protocol == PULSES_ACCESS_R9M_LITE || + protocol == PULSES_ACCESS_R9M_LITE_PRO || + protocol == PULSES_XJT_LITE_X16 || + protocol == PULSES_MULTIMODULE + ); +} + +int ModuleData::getMaxChannelCount() +{ + switch (protocol) { + case PULSES_ACCESS_ISRM: + return 24; + case PULSES_PXX_R9M: + case PULSES_ACCESS_R9M: + case PULSES_ACCESS_R9M_LITE: + case PULSES_ACCESS_R9M_LITE_PRO: + case PULSES_ACCST_ISRM_D16: + case PULSES_XJT_LITE_X16: + case PULSES_PXX_XJT_X16: + case PULSES_CROSSFIRE: + case PULSES_SBUS: + case PULSES_PPM: + return 16; + case PULSES_XJT_LITE_LR12: + case PULSES_PXX_XJT_LR12: + return 12; + case PULSES_PXX_DJT: + case PULSES_XJT_LITE_D8: + case PULSES_PXX_XJT_D8: + return 8; + case PULSES_LP45: + case PULSES_DSM2: + case PULSES_DSMX: + return 6; + case PULSES_MULTIMODULE: + if (multi.rfProtocol == MODULE_SUBTYPE_MULTI_DSM2) + return 12; + else + return 16; + break; + case PULSES_OFF: + break; + default: + break; + } + return 8; +} diff --git a/companion/src/firmwares/moduledata.h b/companion/src/firmwares/moduledata.h index caeaad833..1df7380a1 100644 --- a/companion/src/firmwares/moduledata.h +++ b/companion/src/firmwares/moduledata.h @@ -119,7 +119,20 @@ enum MultiModuleRFProtocols { MODULE_SUBTYPE_MULTI_AFHDS2A_RX, MODULE_SUBTYPE_MULTI_HOTT, MODULE_SUBTYPE_MULTI_FX816, - MODULE_SUBTYPE_MULTI_LAST = MODULE_SUBTYPE_MULTI_FX816 + MODULE_SUBTYPE_MULTI_BAYANG_RX, + MODULE_SUBTYPE_MULTI_PELIKAN, + MODULE_SUBTYPE_MULTI_TIGER, + MODULE_SUBTYPE_MULTI_XK, + MODULE_SUBTYPE_MULTI_XN297DUMP, + MODULE_SUBTYPE_MULTI_FRSKYX2, + MODULE_SUBTYPE_MULTI_FRSKY_R9, + MODULE_SUBTYPE_MULTI_PROPEL, + MODULE_SUBTYPE_MULTI_FRSKYL, + MODULE_SUBTYPE_MULTI_SKYARTEC, + MODULE_SUBTYPE_MULTI_ESKY150V2, + MODULE_SUBTYPE_MULTI_DSM_RX, + MODULE_SUBTYPE_MULTI_JJRC345, + MODULE_SUBTYPE_MULTI_LAST = MODULE_SUBTYPE_MULTI_JJRC345 }; enum TrainerProtocol { @@ -149,7 +162,7 @@ class ModuleData { unsigned int modelId; unsigned int protocol; // type in datastructs.h int rfProtocol; // rfProtocol in datastructs.h - + unsigned int subType; bool invertedSerial; unsigned int channelsStart; @@ -197,6 +210,8 @@ class ModuleData { static QString indexToString(int index, Firmware * fw); static QString protocolToString(unsigned protocol); static QStringList powerValueStrings(int subType, Firmware * fw); + bool hasFailsafes(Firmware * fw) const; + int getMaxChannelCount(); }; #endif // MODULEDATA_H diff --git a/companion/src/firmwares/multiprotocols.cpp b/companion/src/firmwares/multiprotocols.cpp index 18b7035a9..4feeb997f 100644 --- a/companion/src/firmwares/multiprotocols.cpp +++ b/companion/src/firmwares/multiprotocols.cpp @@ -39,7 +39,7 @@ static const QStringList STR_SUBTYPE_CUSTOM ({ }); static const QStringList STR_SUBTYPE_FLYSKY {"Standard", "V9x9", "V6x6", "V912", "CX20"}; static const QStringList STR_SUBTYPE_HUBSAN {"H107", "H301", "H501"}; -static const QStringList STR_SUBTYPE_FRSKY {"D16", "D8", "D16 8ch", "V8", "D16 EU-LBT", "D16 EU-LBT 8ch"}; +static const QStringList STR_SUBTYPE_FRSKY {"D16", "D8", "D16 8ch", "V8", "D16 EU-LBT", "D16 EU-LBT 8ch", "D8 Cloned", "D16 Cloned"}; static const QStringList STR_SUBTYPE_HISKY {"Standard", "HK310"}; static const QStringList STR_SUBTYPE_V2X2 {"Standard", "JXD506"}; static const QStringList STR_SUBTYPE_DSM {"DSM2 22ms", "DSM2 11ms", "DSMX 22ms", "DSMX 11ms"}; @@ -51,6 +51,7 @@ static const QStringList STR_SUBTYPE_SLT {"V1 (6 Channel)", "V2 (8 Channel static const QStringList STR_SUBTYPE_CX10 {"Green", "Blue", "DM007", "-", "JC3015a", "JC3015b", "MK33041"}; static const QStringList STR_SUBTYPE_CG023 {"Standard", "YD829"}; static const QStringList STR_SUBTYPE_BAYANG {"Standard", "H8S3D", "X16 AH", "IRDRONE", "DHD D4"}; +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"}; @@ -60,20 +61,29 @@ 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"}; static const QStringList STR_SUBTYPE_CABELL {"Cabell V3", "Cab V3 Telem", "-", "-", "-", "-", "Set FailSafe", "Unbind"}; +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_TRAXXAS {"6519 RX"}; +static const QStringList STR_SUBTYPE_WFLY {"WFR0xS"}; 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"}; +static const QStringList STR_SUBTYPE_V911S {"Standard", "E119"}; static const QStringList STR_SUBTYPE_GD00X {"GD V1", "GD V2"}; 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_FRSKYX_RX {"D16 FCC", "D16 LBT"}; +static const QStringList STR_SUBTYPE_FRSKYX_RX {"RX", "Clone TX"}; static const QStringList STR_SUBTYPE_FX816 {"P38"}; -static const QStringList STR_SUBTYPE_ESKY150 {"4CH", "7CH"}; +static const QStringList STR_SUBTYPE_XK {"X450", "X420"}; +static const QStringList STR_SUBTYPE_XN297DUMP {"250K", "1M", "2M", "AUTO"}; +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_PROPEL {"74-Z"}; +static const QStringList STR_SUBTYPE_FRSKYL {"LR12", "LR12 6-Channel"}; +static const QStringList STR_SUBTYPE_ESKY150V2 {"150 V2"}; static const QStringList NO_SUBTYPE {STR_MULTI_DEFAULT}; @@ -83,7 +93,7 @@ static const QStringList NO_SUBTYPE {STR_MULTI_DEFAULT}; const Multiprotocols multiProtocols { {MODULE_SUBTYPE_MULTI_FLYSKY, 4, false, STR_SUBTYPE_FLYSKY, nullptr}, {MODULE_SUBTYPE_MULTI_HUBSAN, 2, false, STR_SUBTYPE_HUBSAN, STR_MULTI_VIDFREQ}, - {MODULE_SUBTYPE_MULTI_FRSKY, 5, false, STR_SUBTYPE_FRSKY, STR_MULTI_RFTUNE}, + {MODULE_SUBTYPE_MULTI_FRSKY, 7, false, STR_SUBTYPE_FRSKY, STR_MULTI_RFTUNE}, {MODULE_SUBTYPE_MULTI_HISKY, 1, false, STR_SUBTYPE_HISKY, nullptr}, {MODULE_SUBTYPE_MULTI_V2X2, 1, false, STR_SUBTYPE_V2X2, nullptr}, {MODULE_SUBTYPE_MULTI_DSM2, 3, false, STR_SUBTYPE_DSM, nullptr}, @@ -91,14 +101,16 @@ const Multiprotocols multiProtocols { {MODULE_SUBTYPE_MULTI_YD717, 4, false, STR_SUBTYPE_YD717, nullptr}, {MODULE_SUBTYPE_MULTI_KN, 1, false, STR_SUBTYPE_KN, nullptr}, {MODULE_SUBTYPE_MULTI_SYMAX, 1, false, STR_SUBTYPE_SYMAX, nullptr}, - {MODULE_SUBTYPE_MULTI_SLT, 4, false, STR_SUBTYPE_SLT, nullptr}, + {MODULE_SUBTYPE_MULTI_SLT, 4, false, STR_SUBTYPE_SLT, STR_MULTI_RFTUNE}, {MODULE_SUBTYPE_MULTI_CX10, 6, false, STR_SUBTYPE_CX10, nullptr}, {MODULE_SUBTYPE_MULTI_CG023, 1, false, STR_SUBTYPE_CG023, nullptr}, {MODULE_SUBTYPE_MULTI_BAYANG, 4, false, STR_SUBTYPE_BAYANG, STR_MULTI_TELEMETRY}, + {MODULE_SUBTYPE_MULTI_ESky, 1, false, STR_SUBTYPE_ESky, nullptr}, {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_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}, @@ -106,25 +118,32 @@ const Multiprotocols multiProtocols { {MODULE_SUBTYPE_MULTI_WK_2X01, 5, false, STR_SUBTYPE_WK2x01, nullptr}, {MODULE_SUBTYPE_MULTI_Q303, 3, false, STR_SUBTYPE_Q303, nullptr}, {MODULE_SUBTYPE_MULTI_CABELL, 7, false, STR_SUBTYPE_CABELL, STR_MULTI_OPTION}, + {MODULE_SUBTYPE_MULTI_ESKY150, 1, false, STR_SUBTYPE_ESKY150, nullptr}, {MODULE_SUBTYPE_MULTI_H83D, 3, false, STR_SUBTYPE_H83D, nullptr}, {MODULE_SUBTYPE_MULTI_CORONA, 2, false, STR_SUBTYPE_CORONA, STR_MULTI_RFTUNE}, {MODULE_SUBTYPE_MULTI_HITEC, 2, false, STR_SUBTYPE_HITEC, STR_MULTI_RFTUNE}, + {MODULE_SUBTYPE_MULTI_WFLY, 0, false, STR_SUBTYPE_WFLY, nullptr}, {MODULE_SUBTYPE_MULTI_BUGS_MINI, 1, false, STR_SUBTYPE_BUGS_MINI, nullptr}, {MODULE_SUBTYPE_MULTI_TRAXXAS, 0, false, STR_SUBTYPE_TRAXXAS, nullptr}, {MODULE_SUBTYPE_MULTI_E01X, 2, false, STR_SUBTYPE_E01X, STR_MULTI_OPTION}, - {MODULE_SUBTYPE_MULTI_V911S, 0, false, NO_SUBTYPE, STR_MULTI_RFTUNE}, - {MODULE_SUBTYPE_MULTI_GD00X, 1, false, STR_SUBTYPE_GD00X, nullptr}, + {MODULE_SUBTYPE_MULTI_V911S, 1, false, STR_SUBTYPE_V911S, STR_MULTI_RFTUNE}, + {MODULE_SUBTYPE_MULTI_GD00X, 1, false, STR_SUBTYPE_GD00X, STR_MULTI_RFTUNE}, {MODULE_SUBTYPE_MULTI_KF606, 0, false, NO_SUBTYPE, STR_MULTI_RFTUNE}, {MODULE_SUBTYPE_MULTI_REDPINE, 1, false, STR_SUBTYPE_REDPINE, STR_MULTI_RFTUNE}, {MODULE_SUBTYPE_MULTI_POTENSIC, 0, false, STR_SUBTYPE_POTENSIC, nullptr}, {MODULE_SUBTYPE_MULTI_ZSX, 0, false, STR_SUBTYPE_ZSX, nullptr}, {MODULE_SUBTYPE_MULTI_FLYZONE, 0, false, STR_SUBTYPE_FLYZONE, nullptr}, {MODULE_SUBTYPE_MULTI_FRSKYX_RX, 1, false, STR_SUBTYPE_FRSKYX_RX, STR_MULTI_RFTUNE}, - {MODULE_SUBTYPE_MULTI_ESky, 0, false, NO_SUBTYPE, nullptr}, - {MODULE_SUBTYPE_MULTI_J6PRO, 0, false, NO_SUBTYPE, nullptr}, - {MODULE_SUBTYPE_MULTI_ESKY150, 1, false, STR_SUBTYPE_ESKY150, nullptr}, - {MODULE_SUBTYPE_MULTI_FX816, 0, false, STR_SUBTYPE_FX816, nullptr}, {MODULE_SUBTYPE_MULTI_HOTT, 0, true, NO_SUBTYPE, STR_MULTI_RFTUNE}, + {MODULE_SUBTYPE_MULTI_FX816, 0, false, STR_SUBTYPE_FX816, nullptr}, + {MODULE_SUBTYPE_MULTI_XK, 1, false, STR_SUBTYPE_XK, STR_MULTI_RFTUNE}, + {MODULE_SUBTYPE_MULTI_XN297DUMP, 3, 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_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}, {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) @@ -165,15 +184,14 @@ 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", - "FlySky AFHDS2A", "Q2x2", "Walkera", "Q303", "GW008", "DM002", "Cabell", "ESky 150", "H8 3D", "Corona", "CFlie", + "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", "ZXS", "FlyZone", "Scanner", "FrSky RX", "FlySky AFHDS2A RX", "HoTT", "Fx816" + "KFPlan KF606", "Redpine", "Potensic", "ZSX", "FlyZone", "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" }); - if (protocol == MM_RF_CUSTOM_SELECTED || custom) - return tr("Custom - proto %1)").arg(protocol); - else - return strings.value(protocol, CPN_STR_UNKNOWN_ITEM); + return strings.value(protocol, CPN_STR_UNKNOWN_ITEM); } // static diff --git a/companion/src/firmwares/opentx/opentxeeprom.cpp b/companion/src/firmwares/opentx/opentxeeprom.cpp index 3609713a5..f2275fe61 100644 --- a/companion/src/firmwares/opentx/opentxeeprom.cpp +++ b/companion/src/firmwares/opentx/opentxeeprom.cpp @@ -693,11 +693,13 @@ class FlightModeField: public TransformedField { internalField.Append(new UnsignedField<8>(this, phase.fadeIn)); internalField.Append(new UnsignedField<8>(this, phase.fadeOut)); - for (int i=0; i(this, phase.rotaryEncoders[i])); + if (version < 219) { + for (int i = 0; i < rotencCount; i++) { + internalField.Append(new SignedField<16>(this, phase.rotaryEncoders[i])); + } } - for (int i=0; i(this, phase.gvars[i])); } } @@ -1914,7 +1916,7 @@ class SensorField: public TransformedField { internalField.Append(new UnsignedField<32>(this, _param, "param")); } - virtual void beforeExport() + void beforeExport() override { if (sensor.type == SensorData::TELEM_TYPE_CUSTOM) { _id = sensor.id; @@ -2037,7 +2039,7 @@ class ModuleUnionField: public UnionField { module(module), rfProtExtra(0) { - ModuleData::Multi& multi = module.multi; + ModuleData::Multi & multi = module.multi; internalField.Append(new UnsignedField<3>(this, rfProtExtra)); internalField.Append(new BoolField<1>(this, multi.disableTelemetry)); internalField.Append(new BoolField<1>(this, multi.disableMapping)); @@ -2054,22 +2056,17 @@ class ModuleUnionField: public UnionField { void beforeExport() override { - if (module.multi.rfProtocol > MODULE_SUBTYPE_MULTI_LAST) - module.multi.rfProtocol += 3; rfProtExtra = (module.multi.rfProtocol & 0x70) >> 4; - module.multi.rfProtocol &= 0x0f; } void afterImport() override { module.multi.rfProtocol = (rfProtExtra << 4) + (module.rfProtocol & 0xf); - if (module.multi.rfProtocol > MODULE_SUBTYPE_MULTI_LAST) - module.multi.rfProtocol -= 3; } private: StructField internalField; - ModuleData& module; + ModuleData & module; unsigned int rfProtExtra; }; @@ -2133,7 +2130,8 @@ class ModuleUnionField: public UnionField { 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; } @@ -2141,7 +2139,6 @@ class ModuleUnionField: public UnionField { { for (int i=0; iaddOption("noras", Firmware::tr("Disable RAS (SWR)")); firmware->addOption("haptic", Firmware::tr("Haptic module installed")); addOpenTxTaranisOptions(firmware); addPPMInternalModuleHack(firmware); @@ -1331,7 +1341,6 @@ void registerOpenTxFirmwares() 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")); - firmware->addOption("flexr9m", Firmware::tr("Enable non certified R9M firmwares")); firmware->addOption("internalmulti", Firmware::tr("Support for MULTI internal module")); addOpenTxFontOptions(firmware); registerOpenTxFirmware(firmware); @@ -1342,15 +1351,17 @@ void registerOpenTxFirmwares() addOpenTxFrskyOptions(firmware); firmware->addOption("internalmulti", Firmware::tr("Support for MULTI internal module")); firmware->addOption("bluetooth", Firmware::tr("Support for bluetooth module")); - registerOpenTxFirmware(firmware); addOpenTxRfOptions(firmware, FLEX); + registerOpenTxFirmware(firmware); - // TX16S is unavailable until finalized - /* Radiomaster TX16S board + /* Radiomaster TX16S board */ firmware = new OpenTxFirmware("opentx-tx16s", Firmware::tr("Radiomaster TX16s / TX16s Hall / TX16s Masterfire"), BOARD_RADIOMASTER_TX16S); addOpenTxFrskyOptions(firmware); - firmware->addOption("bluetooth", Firmware::tr("Support for bluetooth module")); - registerOpenTxFirmware(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}); + registerOpenTxFirmware(firmware); /* 9XR-Pro */ firmware = new OpenTxFirmware("opentx-9xrpro", Firmware::tr("Turnigy 9XR-PRO"), BOARD_9XRPRO); diff --git a/companion/src/firmwares/rawsource.h b/companion/src/firmwares/rawsource.h index e9273d399..f59ab70f5 100644 --- a/companion/src/firmwares/rawsource.h +++ b/companion/src/firmwares/rawsource.h @@ -227,11 +227,7 @@ class RawSource { AllSourceGroups = InputSourceGroups | GVarsGroup | TelemGroup | ScriptsGroup }; - RawSource(): - type(SOURCE_TYPE_NONE), - index(0) - { - } + RawSource() { clear(); } explicit RawSource(int value): type(RawSourceType(abs(value)/65536)), @@ -258,6 +254,8 @@ class RawSource { bool isSlider(int * sliderIndex = NULL, Board::Type board = Board::BOARD_UNKNOWN) const; bool isTimeBased(Board::Type board = Board::BOARD_UNKNOWN) const; 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; } bool operator == ( const RawSource & other) const { return (this->type == other.type) && (this->index == other.index); diff --git a/companion/src/firmwares/rawswitch.h b/companion/src/firmwares/rawswitch.h index af49156c0..d79ac0aa6 100644 --- a/companion/src/firmwares/rawswitch.h +++ b/companion/src/firmwares/rawswitch.h @@ -65,11 +65,7 @@ class RawSwitch { AllSwitchContexts = AllModelContexts | GlobalFunctionsContext }; - RawSwitch(): - type(SWITCH_TYPE_NONE), - index(0) - { - } + RawSwitch() { clear(); } explicit RawSwitch(int value): type(RawSwitchType(abs(value)/256)), @@ -91,6 +87,8 @@ class RawSwitch { RawSwitch convert(RadioDataConversionState & cstate); QString toString(Board::Type board = Board::BOARD_UNKNOWN, const GeneralSettings * const generalSettings = NULL, const ModelData * const modelData = NULL) const; 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; } bool operator== ( const RawSwitch& other) const { return (this->type == other.type) && (this->index == other.index); @@ -100,7 +98,6 @@ class RawSwitch { return (this->type != other.type) || (this->index != other.index); } - RawSwitchType type; int index; }; diff --git a/companion/src/firmwares/sensordata.cpp b/companion/src/firmwares/sensordata.cpp index 8d677ed50..0a7e7eada 100644 --- a/companion/src/firmwares/sensordata.cpp +++ b/companion/src/firmwares/sensordata.cpp @@ -82,6 +82,8 @@ QString SensorData::unitString() const return tr("seconds"); case UNIT_CELLS: return tr("V"); + case UNIT_MILLILITERS_PER_MINUTE: + return tr("ml/minute"); default: return ""; } diff --git a/companion/src/firmwares/sensordata.h b/companion/src/firmwares/sensordata.h index a5cdb4957..65a8a4957 100644 --- a/companion/src/firmwares/sensordata.h +++ b/companion/src/firmwares/sensordata.h @@ -90,6 +90,7 @@ class SensorData { UNIT_RADIANS, UNIT_MILLILITERS, UNIT_FLOZ, + UNIT_MILLILITERS_PER_MINUTE, UNIT_HOURS, UNIT_MINUTES, UNIT_SECONDS, diff --git a/companion/src/generaledit/generalsetup.ui b/companion/src/generaledit/generalsetup.ui index d4e9bff01..98f9e76dd 100644 --- a/companion/src/generaledit/generalsetup.ui +++ b/companion/src/generaledit/generalsetup.ui @@ -1124,7 +1124,7 @@ p, li { white-space: pre-wrap; } - aaaaaaAA + nnnnnnNN 8 diff --git a/companion/src/images/simulator/TX16S/bottom.png b/companion/src/images/simulator/TX16S/bottom.png old mode 100755 new mode 100644 diff --git a/companion/src/images/simulator/TX16S/left.png b/companion/src/images/simulator/TX16S/left.png old mode 100755 new mode 100644 index ded33bf62..602017e44 Binary files a/companion/src/images/simulator/TX16S/left.png and b/companion/src/images/simulator/TX16S/left.png differ diff --git a/companion/src/images/simulator/TX16S/left_page.png b/companion/src/images/simulator/TX16S/left_page.png old mode 100755 new mode 100644 index 306d044f4..9ea20a59f Binary files a/companion/src/images/simulator/TX16S/left_page.png and b/companion/src/images/simulator/TX16S/left_page.png differ diff --git a/companion/src/images/simulator/TX16S/left_page2.png b/companion/src/images/simulator/TX16S/left_page2.png old mode 100755 new mode 100644 index c104c148b..6ef922970 Binary files a/companion/src/images/simulator/TX16S/left_page2.png and b/companion/src/images/simulator/TX16S/left_page2.png differ diff --git a/companion/src/images/simulator/TX16S/left_rtn.png b/companion/src/images/simulator/TX16S/left_rtn.png old mode 100755 new mode 100644 index 0080f271a..4fa7d04ff Binary files a/companion/src/images/simulator/TX16S/left_rtn.png and b/companion/src/images/simulator/TX16S/left_rtn.png differ diff --git a/companion/src/images/simulator/TX16S/left_sys.png b/companion/src/images/simulator/TX16S/left_sys.png old mode 100755 new mode 100644 index 31eeb409f..da6b6e939 Binary files a/companion/src/images/simulator/TX16S/left_sys.png and b/companion/src/images/simulator/TX16S/left_sys.png differ diff --git a/companion/src/images/simulator/TX16S/left_tele.png b/companion/src/images/simulator/TX16S/left_tele.png old mode 100755 new mode 100644 index 6b925f22c..a51f18bd1 Binary files a/companion/src/images/simulator/TX16S/left_tele.png and b/companion/src/images/simulator/TX16S/left_tele.png differ diff --git a/companion/src/images/simulator/TX16S/right.png b/companion/src/images/simulator/TX16S/right.png old mode 100755 new mode 100644 diff --git a/companion/src/images/simulator/TX16S/right_ent.png b/companion/src/images/simulator/TX16S/right_ent.png old mode 100755 new mode 100644 diff --git a/companion/src/images/simulator/TX16S/right_mdl.png b/companion/src/images/simulator/TX16S/right_mdl.png old mode 100755 new mode 100644 diff --git a/companion/src/images/simulator/TX16S/top.png b/companion/src/images/simulator/TX16S/top.png old mode 100755 new mode 100644 diff --git a/companion/src/imgpreferences.ui b/companion/src/imgpreferences.ui deleted file mode 100644 index 1ba680d4d..000000000 --- a/companion/src/imgpreferences.ui +++ /dev/null @@ -1,500 +0,0 @@ - - - preferencesDialog - - - - 0 - 0 - 685 - 432 - - - - - 0 - 0 - - - - - 685 - 0 - - - - Preferences - - - - QLayout::SetMinimumSize - - - 2 - - - 4 - - - - - 8 - - - - - - - true - - - true - - - - - - - - 0 - 0 - - - - Simu BackLight - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - Simulator capture folder - - - - - - - - 0 - 0 - - - - Joystick - - - - - - - Remember simulator switches - - - - - - - - - - - - - - - - - 0 - 0 - - - - - - - - Enable - - - - - - - - - Use clipboard only - - - - - - - Calibrate - - - - - - - - - - Blue - - - - - Green - - - - - Red - - - - - Orange - - - - - Yellow - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - Open Folder - - - false - - - - - - - - - Qt::Horizontal - - - - - - - - - - 0 - 0 - - - - Personal splash library - - - - - - - - - true - - - true - - - - - - - Open Folder - - - - - - - - - - - - 0 - 0 - - - - - Include companion splashes - - - - - Only user defined splashes - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - 0 - 0 - - - - Splash library behaviour - - - - - - - - - Qt::Horizontal - - - - - - - - - - 0 - 0 - - - - Custom TX splash screen - - - - - - - - - true - - - true - - - - - - - - 0 - 0 - - - - Open Image - - - - - - - - - - - - - ... - - - - - - - ... - - - - - - - false - - - Invert Pixels - - - - - - - - - - 0 - 0 - - - - - 128 - 64 - - - - - 128 - 64 - - - - QFrame::Panel - - - QFrame::Raised - - - - - - true - - - - - - - - - - - Qt::Horizontal - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - - - backLightColor - joystickCB - joystickChkB - joystickcalButton - simuSW - snapshotPath - snapshotPathButton - snapshotClipboardCKB - libraryPath - libraryPathButton - splashincludeCB - SplashFileName - SplashSelect - SplashLibraryDialogButton - clearImageButton - InvertPixels - buttonBox - - - - - - - buttonBox - accepted() - preferencesDialog - accept() - - - 370 - 49 - - - 157 - 274 - - - - - buttonBox - rejected() - preferencesDialog - reject() - - - 390 - 55 - - - 286 - 274 - - - - - diff --git a/companion/src/mainwindow.cpp b/companion/src/mainwindow.cpp index 35e15968b..2c230000b 100644 --- a/companion/src/mainwindow.cpp +++ b/companion/src/mainwindow.cpp @@ -49,6 +49,7 @@ #include "translations.h" #include "dialogs/filesyncdialog.h" +#include "profilechooser.h" #include #include @@ -130,10 +131,16 @@ MainWindow::MainWindow(): else { if (!g.previousVersion().isEmpty()) g.warningId(g.warningId() | AppMessages::MSG_UPGRADED); - if (checkProfileRadioExists(g.sessionId())) - QTimer::singleShot(updateDelay, this, SLOT(doAutoUpdates())); - else - g.warningId(g.warningId() | AppMessages::MSG_NO_RADIO_TYPE); + 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); + } } QTimer::singleShot(updateDelay, this, SLOT(displayWarnings())); @@ -468,7 +475,7 @@ void MainWindow::checkForFirmwareUpdateFinished(QNetworkReply * reply) const QString errorString = seekCodeString(qba, "ERROR"); const QString blockedRadios = seekCodeString(qba, "BLOCK"); long version; - + if (errorString == "NO_RC") return onUpdatesError(tr("No firmware release candidates are currently being served for this version, please switch release channel")); else if (errorString == "NO_NIGHTLY") @@ -481,7 +488,7 @@ void MainWindow::checkForFirmwareUpdateFinished(QNetworkReply * reply) msgbox.setText(tr("Release candidate builds are now available for this version, would you like to switch to using them?")); msgbox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); msgbox.setDefaultButton(QMessageBox::Yes); - + if(msgbox.exec() == QMessageBox::Yes) { g.OpenTxBranch(AppData::DownloadBranchType(AppData::BRANCH_RC_TESTING)); return onUpdatesError(tr("Channel changed to RC, please restart the download process")); @@ -493,7 +500,7 @@ void MainWindow::checkForFirmwareUpdateFinished(QNetworkReply * reply) msgbox.setText(tr("Official release builds are now available for this version, would you like to switch to using them?")); msgbox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); msgbox.setDefaultButton(QMessageBox::Yes); - + if(msgbox.exec() == QMessageBox::Yes) { g.OpenTxBranch(AppData::DownloadBranchType(AppData::BRANCH_RELEASE_STABLE)); return onUpdatesError(tr("Channel changed to Release, please restart the download process")); @@ -916,14 +923,15 @@ void MainWindow::changelog() void MainWindow::customizeSplash() { - CustomizeSplashDialog * dialog = new CustomizeSplashDialog(this); + auto * dialog = new CustomizeSplashDialog(this); dialog->exec(); dialog->deleteLater(); } void MainWindow::writeEeprom() { - if (activeMdiChild()) activeMdiChild()->writeEeprom(); + if (activeMdiChild()) + activeMdiChild()->writeEeprom(); } void MainWindow::readEeprom() @@ -1806,3 +1814,20 @@ void MainWindow::autoClose() { this->close(); } + +void MainWindow::chooseProfile() +{ + QMap active; + active = g.getActiveProfiles(); + if (active.size() > 1) { + ProfileChooserDialog *pcd = new ProfileChooserDialog(this); + 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 + g.warningId(g.warningId() | AppMessages::MSG_NO_RADIO_TYPE); + } +} diff --git a/companion/src/mainwindow.h b/companion/src/mainwindow.h index 222c047e0..9369dacac 100644 --- a/companion/src/mainwindow.h +++ b/companion/src/mainwindow.h @@ -128,6 +128,7 @@ class MainWindow : public QMainWindow void exportSettings(); void importSettings(); void autoClose(); + void chooseProfile(); void openUpdatesWaitDialog(); void closeUpdatesWaitDialog(); diff --git a/companion/src/mdichild.cpp b/companion/src/mdichild.cpp index 3c8c7c214..1a85aafb7 100644 --- a/companion/src/mdichild.cpp +++ b/companion/src/mdichild.cpp @@ -1490,18 +1490,18 @@ bool MdiChild::convertStorage(Board::Type from, Board::Type to, bool newFile) isUntitled = true; if (cstate.hasLogEntries(RadioDataConversionState::EVT_INF)) { - QDialog * msgBox = new QDialog(Q_NULLPTR, Qt::Dialog | Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint); + auto * msgBox = new QDialog(Q_NULLPTR, Qt::Dialog | Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint); - ExportableTableView * tv = new ExportableTableView(msgBox); + auto * tv = new ExportableTableView(msgBox); tv->setSortingEnabled(true); tv->verticalHeader()->hide(); tv->setModel(cstate.getLogModel(RadioDataConversionState::EVT_INF, tv)); tv->resizeColumnsToContents(); tv->resizeRowsToContents(); - QDialogButtonBox * btnBox = new QDialogButtonBox(QDialogButtonBox::Ok, this); + auto * btnBox = new QDialogButtonBox(QDialogButtonBox::Ok, this); - QVBoxLayout * lo = new QVBoxLayout(msgBox); + auto * lo = new QVBoxLayout(msgBox); lo->addWidget(new QLabel(tr("The conversion generated some important messages, please review them below."))); lo->addWidget(tv); lo->addWidget(btnBox); diff --git a/companion/src/modeledit/channels.cpp b/companion/src/modeledit/channels.cpp index 593121d83..450f785fd 100644 --- a/companion/src/modeledit/channels.cpp +++ b/companion/src/modeledit/channels.cpp @@ -120,7 +120,7 @@ Channels::Channels(QWidget * parent, ModelData & model, GeneralSettings & genera s1.report("header"); - for (int i=0; isetContextMenuPolicy(Qt::CustomContextMenu); label->setToolTip(tr("Popup menu available")); label->setMouseTracking(true); - connect(label, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(chn_customContextMenuRequested(QPoint))); + connect(label, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(onCustomContextMenuRequested(QPoint))); tableLayout->addWidget(i, col++, label); // Channel name @@ -204,7 +204,7 @@ Channels::Channels(QWidget * parent, ModelData & model, GeneralSettings & genera Channels::~Channels() { // compiler warning if delete[] - for (int i=0; igetChannelsMax(); - for (int i=0 ; iupdateMinMax(10 * channelMax); chnMin[i]->updateMinMax(10 * channelMax); chnMax[i]->updateMinMax(10 * channelMax); @@ -280,7 +280,7 @@ void Channels::ppmcenterEdited() void Channels::update() { - for (int i=0; igetBoard())) { int numcurves = firmware->getCapability(NumCurves); curveCB[i]->clear(); - for (int j=-numcurves; j<=numcurves; j++) { + 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); @@ -312,118 +312,140 @@ void Channels::updateLine(int i) lock = false; } -void Channels::chnPaste() +void Channels::cmPaste() { - const QClipboard *clipboard = QApplication::clipboard(); - const QMimeData *mimeData = clipboard->mimeData(); - if (mimeData->hasFormat(MIMETYPE_CHN)) { - QByteArray chnData = mimeData->data(MIMETYPE_CHN); - LimitData *chn = &model->limitData[selectedChannel]; - memcpy(chn, chnData.constData(), sizeof(LimitData)); - updateLine(selectedChannel); + QByteArray data; + if (hasClipboardData(&data)) { + memcpy(&model->limitData[selectedIndex], data.constData(), sizeof(LimitData)); + updateLine(selectedIndex); emit modified(); } } -void Channels::chnDelete() +void Channels::cmDelete() { - int maxidx = chnCapability - 1; - for (int i=selectedChannel; ilimitData[i].isEmpty() || !model->limitData[i+1].isEmpty()) { - LimitData *chn1 = &model->limitData[i]; - LimitData *chn2 = &model->limitData[i+1]; - memcpy(chn1, chn2, sizeof(LimitData)); - updateLine(i); - } + 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); + + for (int i = selectedIndex; i < chnCapability; i++) { + updateLine(i); } - model->limitData[maxidx].clear(); - updateLine(maxidx); + emit modified(); } -void Channels::chnCopy() +void Channels::cmCopy() { - QByteArray chnData; - chnData.append((char*)&model->limitData[selectedChannel],sizeof(LimitData)); + QByteArray data; + data.append((char*)&model->limitData[selectedIndex], sizeof(LimitData)); QMimeData *mimeData = new QMimeData; - mimeData->setData(MIMETYPE_CHN, chnData); + mimeData->setData(MIMETYPE_CHANNEL, data); QApplication::clipboard()->setMimeData(mimeData,QClipboard::Clipboard); } -void Channels::chnCut() +void Channels::cmCut() { - chnCopy(); - chnClear(); + cmCopy(); + cmClear(); } -void Channels::chn_customContextMenuRequested(QPoint pos) +void Channels::onCustomContextMenuRequested(QPoint pos) { QLabel *label = (QLabel *)sender(); - selectedChannel = label->property("index").toInt(); - + selectedIndex = label->property("index").toInt(); QPoint globalPos = label->mapToGlobal(pos); - const QClipboard *clipboard = QApplication::clipboard(); - const QMimeData *mimeData = clipboard->mimeData(); - bool hasData = mimeData->hasFormat(MIMETYPE_CHN); - bool moveUpAllowed = (selectedChannel > 0); - bool moveDownAllowed = (selectedChannel < (chnCapability - 1)); - bool insertAllowed = (selectedChannel < (chnCapability - 1)) && (model->limitData[chnCapability - 1].isEmpty()); - QMenu contextMenu; - contextMenu.addAction(CompanionIcon("copy.png"), tr("Copy"),this,SLOT(chnCopy())); - contextMenu.addAction(CompanionIcon("cut.png"), tr("Cut"),this,SLOT(chnCut())); - contextMenu.addAction(CompanionIcon("paste.png"), tr("Paste"),this,SLOT(chnPaste()))->setEnabled(hasData); - contextMenu.addAction(CompanionIcon("clear.png"), tr("Clear"),this,SLOT(chnClear())); + contextMenu.addAction(CompanionIcon("copy.png"), tr("Copy"),this,SLOT(cmCopy())); + contextMenu.addAction(CompanionIcon("cut.png"), tr("Cut"),this,SLOT(cmCut())); + 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(chnInsert()))->setEnabled(insertAllowed); - contextMenu.addAction(CompanionIcon("arrow-left.png"), tr("Delete"),this,SLOT(chnDelete())); - contextMenu.addAction(CompanionIcon("moveup.png"), tr("Move Up"),this,SLOT(chnMoveUp()))->setEnabled(moveUpAllowed); - contextMenu.addAction(CompanionIcon("movedown.png"), tr("Move Down"),this,SLOT(chnMoveDown()))->setEnabled(moveDownAllowed); + 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(chnClearAll())); + contextMenu.addAction(CompanionIcon("clear.png"), tr("Clear All"),this,SLOT(cmClearAll())); contextMenu.exec(globalPos); } -void Channels::chnMoveUp() +bool Channels::hasClipboardData(QByteArray * data) const { - swapChnData(selectedChannel, selectedChannel - 1); + const QClipboard * clipboard = QApplication::clipboard(); + const QMimeData * mimeData = clipboard->mimeData(); + if (mimeData->hasFormat(MIMETYPE_CHANNEL)) { + if (data) + data->append(mimeData->data(MIMETYPE_CHANNEL)); + return true; + } + return false; } -void Channels::chnMoveDown() +bool Channels::insertAllowed() const { - swapChnData(selectedChannel, selectedChannel + 1); + return ((selectedIndex < chnCapability - 1) && (model->limitData[chnCapability - 1].isEmpty())); } -void Channels::chnClear() +bool Channels::moveDownAllowed() const { - model->limitData[selectedChannel].clear(); - updateLine(selectedChannel); + return selectedIndex < chnCapability - 1; +} + +bool Channels::moveUpAllowed() const +{ + return selectedIndex > 0; +} + +void Channels::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); + updateLine(selectedIndex); emit modified(); } -void Channels::chnClearAll() +void Channels::cmClearAll() { - for (int i=0; ilimitData[i].clear(); + model->updateAllReferences(ModelData::REF_UPD_TYPE_CHANNEL, ModelData::REF_UPD_ACT_CLEAR, i); updateLine(i); } emit modified(); } -void Channels::chnInsert() +void Channels::cmInsert() { - for (int i=(chnCapability - 1); i>selectedChannel; i--) { - if (!model->limitData[i].isEmpty() || !model->limitData[i-1].isEmpty()) { - memcpy(&model->limitData[i], &model->limitData[i-1], sizeof(LimitData)); - updateLine(i); - } - } - chnClear(); + 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(); } -void Channels::swapChnData(int idx1, int idx2) +void Channels::swapData(int idx1, int idx2) { if ((idx1 != idx2) && (!model->limitData[idx1].isEmpty() || !model->limitData[idx2].isEmpty())) { LimitData chntmp = model->limitData[idx2]; @@ -431,6 +453,7 @@ void Channels::swapChnData(int idx1, int idx2) 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(); diff --git a/companion/src/modeledit/channels.h b/companion/src/modeledit/channels.h index f50c72b89..caa0fca38 100644 --- a/companion/src/modeledit/channels.h +++ b/companion/src/modeledit/channels.h @@ -26,7 +26,7 @@ #include -constexpr char MIMETYPE_CHN[] = "application/x-companion-chn"; +constexpr char MIMETYPE_CHANNEL[] = "application/x-companion-channel"; class GVarGroup; @@ -68,19 +68,23 @@ class Channels : public ModelPanel void ppmcenterEdited(); void update(); void updateLine(int index); - void chnDelete(); - void chnCopy(); - void chnPaste(); - void chnCut(); - void chnMoveUp(); - void chnMoveDown(); - void chnInsert(); - void chnClear(); - void chnClearAll(); - void chn_customContextMenuRequested(QPoint pos); + void cmDelete(); + void cmCopy(); + void cmPaste(); + void cmCut(); + void cmMoveUp(); + void cmMoveDown(); + void cmInsert(); + void cmClear(); + void cmClearAll(); + void onCustomContextMenuRequested(QPoint pos); private: - void swapChnData(int idx1, int idx2); + 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]; @@ -89,7 +93,7 @@ class Channels : public ModelPanel QComboBox *curveCB[CPN_MAX_CHNOUT]; QSpinBox *centerSB[CPN_MAX_CHNOUT]; QCheckBox *symlimitsChk[CPN_MAX_CHNOUT]; - int selectedChannel; + int selectedIndex; int chnCapability; }; diff --git a/companion/src/modeledit/curves.cpp b/companion/src/modeledit/curves.cpp index cf3eb9e71..5759e60e6 100644 --- a/companion/src/modeledit/curves.cpp +++ b/companion/src/modeledit/curves.cpp @@ -117,7 +117,12 @@ Curves::Curves(QWidget * parent, ModelData & model, GeneralSettings & generalSet lock = true; - if (!firmware->getCapability(HasCvNames)) { + maxCurves = firmware->getCapability(NumCurves); + hasNames = firmware->getCapability(HasCvNames); + hasEnhanced = firmware->getCapability(EnhancedCurves); + maxPoints = firmware->getCapability(NumCurvePoints); + + if (!hasNames) { ui->curveName->hide(); ui->curveNameLabel->hide(); } @@ -127,14 +132,14 @@ Curves::Curves(QWidget * parent, ModelData & model, GeneralSettings & generalSet connect(scene, SIGNAL(newPoint(int, int)), this, SLOT(onSceneNewPoint(int, int))); ui->curvePreview->setScene(scene); - int numcurves=firmware->getCapability(NumCurves); + int limit; - if (numcurves>16) { - limit=numcurves/2; + if (maxCurves > 16) { + limit = maxCurves / 2; } else { - limit=numcurves; + limit = maxCurves; } - for (int i=0; isetStyleSheet(QString("background-color: %1; color: white; padding: 2px 3px; border-style: outset; border-width: 1px; border-radius: 2px; border-color: inherit;").arg(colors[i].name())); #endif edit->setPalette(palette); - edit->setText(tr("Curve %1").arg(i+1)); + edit->setText(tr("Curve %1").arg(i + 1)); edit->setContextMenuPolicy(Qt::CustomContextMenu); edit->setToolTip(tr("Popup menu available")); - connect(edit, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(ShowContextMenu(const QPoint&))); + connect(edit, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(onCustomContextMenuRequested(const QPoint&))); connect(edit, SIGNAL(clicked()), this, SLOT(editCurve())); - if (icurvesLayout->addWidget(edit, i, 1, 1, 1); } else { - ui->curvesLayout2->addWidget(edit, i-limit, 2, 1, 1); + ui->curvesLayout2->addWidget(edit, i - limit, 2, 1, 1); } // The curve plot checkbox @@ -167,7 +172,7 @@ Curves::Curves(QWidget * parent, ModelData & model, GeneralSettings & generalSet plot->setProperty("index", i); plot->setPalette(palette); connect(plot, SIGNAL(toggled(bool)), this, SLOT(plotCurve(bool))); - if (icurvesLayout->addWidget(plot, i, 2, 1, 1); } else { ui->curvesLayout2->addWidget(plot, i-limit, 1, 1, 1); @@ -175,13 +180,13 @@ Curves::Curves(QWidget * parent, ModelData & model, GeneralSettings & generalSet } QSpacerItem * item = new QSpacerItem(1,1, QSizePolicy::Fixed, QSizePolicy::Expanding); - ui->curvesLayout->addItem(item,limit+1,1,1,1,0); - if (limit!=numcurves) { + ui->curvesLayout->addItem(item,limit + 1, 1, 1, 1, 0); + if (limit != maxCurves) { QSpacerItem * item2 = new QSpacerItem(1,1, QSizePolicy::Fixed, QSizePolicy::Expanding); - ui->curvesLayout2->addItem(item2,limit+1,1,1,1,0); + ui->curvesLayout2->addItem(item2,limit + 1, 1, 1, 1, 0); } - for (int i=0; isetProperty("index", i); spnx[i]->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); @@ -199,14 +204,14 @@ Curves::Curves(QWidget * parent, ModelData & model, GeneralSettings & generalSet ui->pointsLayout->addWidget(spny[i], i, 1, 1, 1); bool insert; - if (firmware->getCapability(EnhancedCurves)) { + if (hasEnhanced) { insert = (i >= 1); } else { - insert = (i==2 || i==4 || i==8 || i==16); + insert = (i == 2 || i == 4 || i ==8 || i == 16); } if (insert) { - ui->curvePoints->addItem(tr("%1 points").arg(i+1), i+1); + ui->curvePoints->addItem(tr("%1 points").arg(i + 1), i + 1); } } @@ -250,7 +255,7 @@ void Curves::update() { lock = true; - if (firmware->getCapability(HasCvNames)) { + if (hasNames) { ui->curveName->setText(model->curves[currentCurve].name); } @@ -272,7 +277,7 @@ void Curves::updateCurveType() int index = 0; - if (firmware->getCapability(EnhancedCurves)) { + if (hasEnhanced) { index = model->curves[currentCurve].count - 2; } else { @@ -305,35 +310,34 @@ void Curves::updateCurve() qreal width = scene->sceneRect().width(); qreal height = scene->sceneRect().height(); - qreal centerX = scene->sceneRect().left() + width/2; - qreal centerY = scene->sceneRect().top() + height/2; + qreal centerX = scene->sceneRect().left() + width / 2; + qreal centerY = scene->sceneRect().top() + height / 2; - QGraphicsSimpleTextItem *ti = scene->addSimpleText(tr("Editing curve %1").arg(currentCurve+1)); + QGraphicsSimpleTextItem *ti = scene->addSimpleText(tr("Editing curve %1").arg(currentCurve + 1)); ti->setPos(3, 3); - scene->addLine(centerX, GFX_MARGIN, centerX, height+GFX_MARGIN); - scene->addLine(GFX_MARGIN, centerY, width+GFX_MARGIN, centerY); + scene->addLine(centerX, GFX_MARGIN, centerX, height + GFX_MARGIN); + scene->addLine(GFX_MARGIN, centerY, width + GFX_MARGIN, centerY); QPen pen; pen.setWidth(1); pen.setStyle(Qt::SolidLine); - int numcurves = firmware->getCapability(NumCurves); - for (int k=0; kcurves[k].count; - for (int i=0; icurves[k].type == CurveData::CURVE_TYPE_CUSTOM) - scene->addLine(centerX + (qreal)model->curves[k].points[i].x*width/200,centerY - (qreal)model->curves[k].points[i].y*height/200,centerX + (qreal)model->curves[k].points[i+1].x*width/200,centerY - (qreal)model->curves[k].points[i+1].y*height/200, pen); + scene->addLine(centerX + (qreal)model->curves[k].points[i].x*width/200, centerY - (qreal)model->curves[k].points[i].y*height/200,centerX + (qreal)model->curves[k].points[i+1].x*width/200,centerY - (qreal)model->curves[k].points[i+1].y*height/200, pen); else - scene->addLine(GFX_MARGIN + i*width/(numpoints-1),centerY - (qreal)model->curves[k].points[i].y*height/200,GFX_MARGIN + (i+1)*width/(numpoints-1),centerY - (qreal)model->curves[k].points[i+1].y*height/200, pen); + scene->addLine(GFX_MARGIN + i*width/(numpoints-1), centerY - (qreal)model->curves[k].points[i].y*height/200,GFX_MARGIN + (i+1)*width/(numpoints-1),centerY - (qreal)model->curves[k].points[i+1].y*height/200, pen); } } } int numpoints = model->curves[currentCurve].count; - for (int i=0; isetProperty("index", i); @@ -341,26 +345,27 @@ void Curves::updateCurve() nodex->setBallSize(ui->pointSize->value()); nodex->setBallHeight(0); if (model->curves[currentCurve].type == CurveData::CURVE_TYPE_CUSTOM) { - if (i>0 && i 0 && i < numpoints - 1) { nodex->setFixedX(false); - nodex->setMinX(model->curves[currentCurve].points[i-1].x); - nodex->setMaxX(model->curves[currentCurve].points[i+1].x); + nodex->setMinX(model->curves[currentCurve].points[i - 1].x); + nodex->setMaxX(model->curves[currentCurve].points[i + 1].x); } else { nodex->setFixedX(true); } - nodex->setPos(centerX + (qreal)model->curves[currentCurve].points[i].x*width/200,centerY - (qreal)model->curves[currentCurve].points[i].y*height/200); + nodex->setPos(centerX + (qreal)model->curves[currentCurve].points[i].x * width / 200, centerY - (qreal)model->curves[currentCurve].points[i].y * height / 200); } else { nodex->setFixedX(true); - nodex->setPos(GFX_MARGIN + i*width/(numpoints-1), centerY - (qreal)model->curves[currentCurve].points[i].y*height/200); + nodex->setPos(GFX_MARGIN + i * width / (numpoints - 1), centerY - (qreal)model->curves[currentCurve].points[i].y * height / 200); } connect(nodex, SIGNAL(moved(int, int)), this, SLOT(onNodeMoved(int, int))); connect(nodex, SIGNAL(focus()), this, SLOT(onNodeFocus())); connect(nodex, SIGNAL(unfocus()), this, SLOT(onNodeUnfocus())); connect(nodex, SIGNAL(deleteMe()), this, SLOT(onNodeDelete())); scene->addItem(nodex); - if (i>0) scene->addItem(new Edge(nodel, nodex)); + if (i > 0) + scene->addItem(new Edge(nodel, nodex)); } lock = false; @@ -371,20 +376,20 @@ void Curves::updateCurvePoints() lock = true; int count = model->curves[currentCurve].count; - for (int i=0; ishow(); spny[i]->setValue(model->curves[currentCurve].points[i].y); if (model->curves[currentCurve].type == CurveData::CURVE_TYPE_CUSTOM) { spnx[i]->show(); - if (i==0 || i==model->curves[currentCurve].count-1) { + if (i == 0 || i == model->curves[currentCurve].count - 1) { spnx[i]->setDisabled(true); spnx[i]->setMaximum(+100); spnx[i]->setMinimum(-100); } else { spnx[i]->setDisabled(false); - spnx[i]->setMaximum(model->curves[currentCurve].points[i+1].x); - spnx[i]->setMinimum(model->curves[currentCurve].points[i-1].x); + spnx[i]->setMaximum(model->curves[currentCurve].points[i + 1].x); + spnx[i]->setMinimum(model->curves[currentCurve].points[i - 1].x); } spnx[i]->setValue(model->curves[currentCurve].points[i].x); } @@ -392,7 +397,7 @@ void Curves::updateCurvePoints() spnx[i]->hide(); } } - for (int i=count; ihide(); spnx[i]->hide(); } @@ -421,9 +426,9 @@ void Curves::onNodeMoved(int x, int y) spnx[index]->setValue(x); spny[index]->setValue(y); if (index > 0) - spnx[index-1]->setMaximum(x); - if (index < model->curves[currentCurve].count-1) - spnx[index+1]->setMinimum(x); + spnx[index - 1]->setMaximum(x); + if (index < model->curves[currentCurve].count - 1) + spnx[index + 1]->setMinimum(x); emit modified(); lock = false; } @@ -444,17 +449,14 @@ void Curves::onNodeUnfocus() bool Curves::allowCurveType(int points, CurveData::CurveType type) { - int numcurves = firmware->getCapability(NumCurves); - int totalpoints = 0; - for (int i=0; icurves[i].count); - CurveData::CurveType cvType = (i==currentCurve ? type : model->curves[i].type); - totalpoints += cvPoints + (cvType==CurveData::CURVE_TYPE_CUSTOM ? cvPoints-2 : 0); + for (int i = 0; i < maxCurves; i++) { + int cvPoints = (i == currentCurve ? points : model->curves[i].count); + CurveData::CurveType cvType = (i == currentCurve ? type : model->curves[i].type); + totalpoints += cvPoints + (cvType == CurveData::CURVE_TYPE_CUSTOM ? cvPoints - 2 : 0); } - int fwpoints = firmware->getCapability(NumCurvePoints); - if (totalpoints > fwpoints) { + if (totalpoints > maxPoints) { QMessageBox::warning(this, "companion", tr("Not enough free points in EEPROM to store the curve.")); return false; } @@ -472,8 +474,8 @@ void Curves::on_curvePoints_currentIndexChanged(int index) model->curves[currentCurve].count = numpoints; // TODO something better + reuse! - for (int i=0; icurves[currentCurve].points[i].x = (i >= numpoints-1 ? +100 : -100 + (200*i)/(numpoints-1)); + for (int i = 0; i < CPN_MAX_POINTS; i++) { + model->curves[currentCurve].points[i].x = (i >= numpoints - 1 ? +100 : -100 + (200 * i) / (numpoints - 1)); model->curves[currentCurve].points[i].y = 0; } @@ -491,12 +493,13 @@ void Curves::on_curveCustom_currentIndexChanged(int index) if (!lock) { CurveData::CurveType type = (CurveData::CurveType)index; int numpoints = ui->curvePoints->itemData(ui->curvePoints->currentIndex()).toInt(); + if (allowCurveType(model->curves[currentCurve].count, type)) { model->curves[currentCurve].type = type; // TODO something better + reuse! - for (int i=0; icurves[currentCurve].points[i].x = (i >= numpoints-1 ? +100 : -100 + (200*i)/(numpoints-1)); + for (int i = 0; i < CPN_MAX_POINTS; i++) { + model->curves[currentCurve].points[i].x = (i >= numpoints - 1 ? +100 : -100 + (200 * i) / (numpoints - 1)); model->curves[currentCurve].points[i].y = 0; } @@ -525,7 +528,7 @@ void Curves::on_curveName_editingFinished() void Curves::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); + ui->curvePreview->scene()->setSceneRect(GFX_MARGIN, GFX_MARGIN, qr.width() - GFX_MARGIN * 2, qr.height() - GFX_MARGIN * 2); updateCurve(); ModelPanel::resizeEvent(event); } @@ -559,12 +562,12 @@ void Curves::on_curveApply_clicked() int index = ui->curveType->currentIndex(); int numpoints = model->curves[currentCurve].count; - for (int i=0; icurves[currentCurve].type == CurveData::CURVE_TYPE_CUSTOM) x = model->curves[currentCurve].points[i].x; else - x = -100.0 + (200.0/(numpoints-1))*i; + x = -100.0 + (200.0 / (numpoints - 1)) * i; bool apply = false; switch (ui->curveSide->currentIndex()) { @@ -572,11 +575,11 @@ void Curves::on_curveApply_clicked() apply = true; break; case 1: - if (x>=0) + if (x >= 0) apply = true; break; case 2: - if (x<0) + if (x < 0) apply = true; break; } @@ -591,68 +594,6 @@ void Curves::on_curveApply_clicked() emit modified(); } -void Curves::ShowContextMenu(const QPoint& pos) // this is a slot -{ - QPushButton *button = (QPushButton *)sender(); - int index = button->property("index").toInt(); - const QClipboard *clipboard = QApplication::clipboard(); - const QMimeData *mimeData = clipboard->mimeData(); - QPoint globalPos = button->mapToGlobal(pos); - QMenu myMenu; - QAction *action; - action = myMenu.addAction(CompanionIcon("copy.png"),tr("Copy")); - action->setProperty("index", CURVE_COPY); - - action = myMenu.addAction(CompanionIcon("paste.png"),tr("Paste")); - if (!mimeData->hasFormat("application/x-companion-curve-item")) { - action->setEnabled(false); - } - action->setProperty("index", CURVE_PASTE); - - action = myMenu.addAction(CompanionIcon("clear.png"),tr("Clear")); - action->setProperty("index", CURVE_RESET); - action = myMenu.addAction(CompanionIcon("clear.png"),tr("Clear all curves")); - action->setProperty("index", CURVE_RESETALL); - - QAction* selectedItem = myMenu.exec(globalPos); - if (selectedItem) { - int action=selectedItem->property("index").toInt(); - if (action==CURVE_COPY) { - QByteArray curveData; - QMimeData *mimeData2 = new QMimeData; - curveData.append((char*)&model->curves[index], sizeof(CurveData)); - mimeData2->setData("application/x-companion-curve-item", curveData); - QApplication::clipboard()->setMimeData(mimeData2, QClipboard::Clipboard); - } - else if (action==CURVE_PASTE) { - QByteArray curveData = mimeData->data("application/x-companion-curve-item"); - CurveData *curve = &model->curves[index]; - memcpy(curve, curveData.constData(), sizeof(CurveData)); - update(); - emit modified(); - } - else if (action==CURVE_RESET) { - int res = QMessageBox::question(this, "companion", tr("Are you sure you want to reset curve %1?").arg(index+1), QMessageBox::Yes | QMessageBox::No); - if (res == QMessageBox::Yes) { - model->curves[index].clear(5); - update(); - emit modified(); - } - } - else if (action==CURVE_RESETALL) { - int res = QMessageBox::question(this, "companion", tr("Are you sure you want to reset all curves?"), QMessageBox::Yes | QMessageBox::No); - if (res == QMessageBox::Yes) { - int numcurves = firmware->getCapability(NumCurves); - for (int i=0; icurves[i].clear(5); - } - update(); - emit modified(); - } - } - } -} - void Curves::onPointSizeEdited() { if (!lock) { @@ -690,7 +631,7 @@ void Curves::onSceneNewPoint(int x, int y) newidx = numpoints; } else { - for (int i=0; icurves[currentCurve].points[i].x) { newidx = i; break; @@ -699,8 +640,8 @@ void Curves::onSceneNewPoint(int x, int y) } numpoints++; model->curves[currentCurve].count = numpoints; - for (int idx=(numpoints-1); idx>(newidx); idx--) { - model->curves[currentCurve].points[idx] = model->curves[currentCurve].points[idx-1]; + for (int idx = (numpoints - 1); idx > newidx; idx--) { + model->curves[currentCurve].points[idx] = model->curves[currentCurve].points[idx - 1]; } model->curves[currentCurve].points[newidx].x = x; model->curves[currentCurve].points[newidx].y = y; @@ -709,6 +650,150 @@ void Curves::onSceneNewPoint(int x, int y) } } +void Curves::onCustomContextMenuRequested(QPoint pos) +{ + QPushButton *button = (QPushButton *)sender(); + selectedIndex = button->property("index").toInt(); + QPoint globalPos = button->mapToGlobal(pos); + + QMenu contextMenu; + contextMenu.addAction(CompanionIcon("copy.png"), tr("Copy"), this, SLOT(cmCopy())); + contextMenu.addAction(CompanionIcon("cut.png"), tr("Cut"), this, SLOT(cmCut())); + 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); +} + +bool Curves::hasClipboardData(QByteArray * data) const +{ + const QClipboard * clipboard = QApplication::clipboard(); + const QMimeData * mimeData = clipboard->mimeData(); + if (mimeData->hasFormat(MIMETYPE_CURVE)) { + if (data) + data->append(mimeData->data(MIMETYPE_CURVE)); + return true; + } + return false; +} + +bool Curves::insertAllowed() const +{ + return ((selectedIndex < maxCurves - 1) && (model->curves[maxCurves - 1].isEmpty())); +} + +bool Curves::moveDownAllowed() const +{ + return selectedIndex < maxCurves - 1; +} + +bool Curves::moveUpAllowed() const +{ + return selectedIndex > 0; +} + +void Curves::cmClear() +{ + 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(); + emit modified(); +} + +void Curves::cmClearAll() +{ + if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear all Curves. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) + return; + + for (int i = 0; i < maxCurves; i++) { + model->curves[i].clear(); + model->updateAllReferences(ModelData::REF_UPD_TYPE_CURVE, ModelData::REF_UPD_ACT_CLEAR, i); + } + update(); + emit modified(); +} + +void Curves::cmCopy() +{ + QByteArray data; + data.append((char*)&model->curves[selectedIndex], sizeof(CurveData)); + QMimeData *mimeData = new QMimeData; + mimeData->setData(MIMETYPE_CURVE, data); + QApplication::clipboard()->setMimeData(mimeData,QClipboard::Clipboard); +} + +void Curves::cmCut() +{ + cmCopy(); + cmClear(); +} + +void Curves::cmDelete() +{ + if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Delete Curve. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) + return; + + memmove(&model->curves[selectedIndex], &model->curves[selectedIndex + 1], (CPN_MAX_CURVES - (selectedIndex + 1)) * sizeof(CurveData)); + model->curves[maxCurves - 1].clear(); + model->updateAllReferences(ModelData::REF_UPD_TYPE_CURVE, ModelData::REF_UPD_ACT_SHIFT, selectedIndex, 0, -1); + update(); + emit modified(); +} + +void Curves::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(); + emit modified(); +} + +void Curves::cmMoveDown() +{ + swapData(selectedIndex, selectedIndex + 1); +} + +void Curves::cmMoveUp() +{ + swapData(selectedIndex, selectedIndex - 1); +} + +void Curves::cmPaste() +{ + QByteArray data; + if (hasClipboardData(&data)) { + CurveData *cd = &model->curves[selectedIndex]; + memcpy(cd, data.constData(), sizeof(CurveData)); + update(); + emit modified(); + } +} + +void Curves::swapData(int idx1, int idx2) +{ + if ((idx1 != idx2) && (!model->curves[idx1].isEmpty() || !model->curves[idx2].isEmpty())) { + CurveData cdtmp = model->curves[idx2]; + CurveData *cd1 = &model->curves[idx1]; + CurveData *cd2 = &model->curves[idx2]; + memcpy(cd2, cd1, sizeof(CurveData)); + memcpy(cd1, &cdtmp, sizeof(CurveData)); + model->updateAllReferences(ModelData::REF_UPD_TYPE_CURVE, ModelData::REF_UPD_ACT_SWAP, idx1, idx2); + update(); + emit modified(); + } +} + CustomScene::CustomScene(QGraphicsView * view) : QGraphicsScene(view) { diff --git a/companion/src/modeledit/curves.h b/companion/src/modeledit/curves.h index a65ba8872..d9a5364a6 100644 --- a/companion/src/modeledit/curves.h +++ b/companion/src/modeledit/curves.h @@ -26,12 +26,7 @@ #include #include -enum CopyAction { - CURVE_COPY, - CURVE_PASTE, - CURVE_RESET, - CURVE_RESETALL -}; +constexpr char MIMETYPE_CURVE[] = "application/x-companion-curve"; namespace Ui { class Curves; @@ -71,7 +66,6 @@ class Curves : public ModelPanel private slots: void editCurve(); - void ShowContextMenu(const QPoint& pos); void plotCurve(bool checked); void on_curveName_editingFinished(); void on_curvePoints_currentIndexChanged(int index); @@ -86,6 +80,16 @@ class Curves : public ModelPanel void onSceneNewPoint(int x, int y); void onPointSizeEdited(); void onNodeDelete(); + void onCustomContextMenuRequested(QPoint pos); + void cmClear(); + void cmClearAll(); + void cmCopy(); + void cmCut(); + void cmDelete(); + void cmInsert(); + void cmPaste(); + void cmMoveDown(); + void cmMoveUp(); protected: virtual void resizeEvent(QResizeEvent *event); @@ -105,6 +109,16 @@ class Curves : public ModelPanel bool allowCurveType(int points, CurveData::CurveType type); void setPointY(int i, int x, int y); CustomScene * scene; + int maxCurves; + int hasNames; + int hasEnhanced; + int maxPoints; + int selectedIndex; + bool hasClipboardData(QByteArray * data = nullptr) const; + bool insertAllowed() const; + bool moveDownAllowed() const; + bool moveUpAllowed() const; + void swapData(int idx1, int idx2); }; #endif // _CURVES_H_ diff --git a/companion/src/modeledit/customfunctions.cpp b/companion/src/modeledit/customfunctions.cpp index fdba765d8..34f05a707 100644 --- a/companion/src/modeledit/customfunctions.cpp +++ b/companion/src/modeledit/customfunctions.cpp @@ -127,7 +127,7 @@ CustomFunctionsPanel::CustomFunctionsPanel(QWidget * parent, ModelData * model, else label->setText(tr("GF%1").arg(i+1)); label->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum); - connect(label, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(fsw_customContextMenuRequested(QPoint))); + connect(label, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(onCustomContextMenuRequested(QPoint))); tableLayout->addWidget(i, 0, label); // s1.report("label"); @@ -608,76 +608,63 @@ void CustomFunctionsPanel::update() lock = false; } -void CustomFunctionsPanel::fswPaste() +void CustomFunctionsPanel::cmPaste() { - const QClipboard *clipboard = QApplication::clipboard(); - const QMimeData *mimeData = clipboard->mimeData(); - if (mimeData->hasFormat(MIMETYPE_FSW)) { - QByteArray fswData = mimeData->data(MIMETYPE_FSW); - CustomFunctionData *fsw = &functions[selectedFunction]; - memcpy(fsw, fswData.constData(), sizeof(CustomFunctionData)); - resetCBsAndRefresh(selectedFunction); + QByteArray data; + if (hasClipboardData(&data)) { + memcpy(&functions[selectedIndex], data.constData(), sizeof(CustomFunctionData)); + resetCBsAndRefresh(selectedIndex); emit modified(); } } -void CustomFunctionsPanel::fswDelete() +void CustomFunctionsPanel::cmDelete() { - int maxidx = fswCapability - 1; - for (int i=selectedFunction; isetData(MIMETYPE_FSW, fswData); + mimeData->setData(MIMETYPE_CUSTOM_FUNCTION, data); QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard); } -void CustomFunctionsPanel::fswCut() +void CustomFunctionsPanel::cmCut() { - fswCopy(); - fswClear(); + cmCopy(); + cmClear(); } -void CustomFunctionsPanel::fsw_customContextMenuRequested(QPoint pos) +void CustomFunctionsPanel::onCustomContextMenuRequested(QPoint pos) { QLabel *label = (QLabel *)sender(); - selectedFunction = label->property("index").toInt(); - + selectedIndex = label->property("index").toInt(); QPoint globalPos = label->mapToGlobal(pos); - const QClipboard *clipboard = QApplication::clipboard(); - const QMimeData *mimeData = clipboard->mimeData(); - bool hasData = mimeData->hasFormat(MIMETYPE_FSW); - bool moveUpAllowed = (selectedFunction > 0); - bool moveDownAllowed = (selectedFunction < (fswCapability - 1)); - bool insertAllowed = (selectedFunction < (fswCapability - 1)) && (functions[fswCapability - 1].isEmpty()); - QMenu contextMenu; - contextMenu.addAction(CompanionIcon("copy.png"), tr("Copy"),this,SLOT(fswCopy())); - contextMenu.addAction(CompanionIcon("cut.png"), tr("Cut"),this,SLOT(fswCut())); - contextMenu.addAction(CompanionIcon("paste.png"), tr("Paste"),this,SLOT(fswPaste()))->setEnabled(hasData); - contextMenu.addAction(CompanionIcon("clear.png"), tr("Clear"),this,SLOT(fswClear())); + contextMenu.addAction(CompanionIcon("copy.png"), tr("Copy"),this,SLOT(cmCopy())); + contextMenu.addAction(CompanionIcon("cut.png"), tr("Cut"),this,SLOT(cmCut())); + 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(fswInsert()))->setEnabled(insertAllowed); - contextMenu.addAction(CompanionIcon("arrow-left.png"), tr("Delete"),this,SLOT(fswDelete())); - contextMenu.addAction(CompanionIcon("moveup.png"), tr("Move Up"),this,SLOT(fswMoveUp()))->setEnabled(moveUpAllowed); - contextMenu.addAction(CompanionIcon("movedown.png"), tr("Move Down"),this,SLOT(fswMoveDown()))->setEnabled(moveDownAllowed); + 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(fswClearAll())); + contextMenu.addAction(CompanionIcon("clear.png"), tr("Clear All"),this,SLOT(cmClearAll())); contextMenu.exec(globalPos); } @@ -762,25 +749,31 @@ void CustomFunctionsPanel::populateFuncParamCB(QComboBox *b, uint function, unsi } } -void CustomFunctionsPanel::fswMoveUp() +void CustomFunctionsPanel::cmMoveUp() { - swapFuncData(selectedFunction, selectedFunction - 1); + swapData(selectedIndex, selectedIndex - 1); } -void CustomFunctionsPanel::fswMoveDown() +void CustomFunctionsPanel::cmMoveDown() { - swapFuncData(selectedFunction, selectedFunction + 1); + swapData(selectedIndex, selectedIndex + 1); } -void CustomFunctionsPanel::fswClear() +void CustomFunctionsPanel::cmClear() { - functions[selectedFunction].clear(); - resetCBsAndRefresh(selectedFunction); + if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear Special Function. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) + return; + + functions[selectedIndex].clear(); + resetCBsAndRefresh(selectedIndex); emit modified(); } -void CustomFunctionsPanel::fswClearAll() +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) + return; + for (int i=0; iselectedFunction; i--) { - if (!functions[i].isEmpty() || !functions[i-1].isEmpty()) { - memcpy(&functions[i], &functions[i-1], sizeof(CustomFunctionData)); - resetCBsAndRefresh(i); - } + memmove(&functions[selectedIndex + 1], &functions[selectedIndex], (CPN_MAX_SPECIAL_FUNCTIONS - (selectedIndex + 1)) * sizeof(CustomFunctionData)); + functions[selectedIndex].clear(); + + for (int i = selectedIndex; i < (fswCapability - 1); i++) { + resetCBsAndRefresh(i); } - fswClear(); } -void CustomFunctionsPanel::swapFuncData(int idx1, int idx2) +void CustomFunctionsPanel::swapData(int idx1, int idx2) { if ((idx1 != idx2) && (!functions[idx1].isEmpty() || !functions[idx2].isEmpty())) { CustomFunctionData fswtmp = functions[idx2]; @@ -823,3 +815,30 @@ void CustomFunctionsPanel::resetCBsAndRefresh(int idx) refreshCustomFunction(idx); lock = false; } + +bool CustomFunctionsPanel::hasClipboardData(QByteArray * data) const +{ + const QClipboard * clipboard = QApplication::clipboard(); + const QMimeData * mimeData = clipboard->mimeData(); + if (mimeData->hasFormat(MIMETYPE_CUSTOM_FUNCTION)) { + if (data) + data->append(mimeData->data(MIMETYPE_CUSTOM_FUNCTION)); + return true; + } + return false; +} + +bool CustomFunctionsPanel::insertAllowed() const +{ + return ((selectedIndex < fswCapability - 1) && (model->curves[fswCapability - 1].isEmpty())); +} + +bool CustomFunctionsPanel::moveDownAllowed() const +{ + return selectedIndex < fswCapability - 1; +} + +bool CustomFunctionsPanel::moveUpAllowed() const +{ + return selectedIndex > 0; +} diff --git a/companion/src/modeledit/customfunctions.h b/companion/src/modeledit/customfunctions.h index fd257ce98..1c93f3e96 100644 --- a/companion/src/modeledit/customfunctions.h +++ b/companion/src/modeledit/customfunctions.h @@ -30,7 +30,7 @@ class RawSourceFilterItemModel; class RawSwitchFilterItemModel; class TimerEdit; -constexpr char MIMETYPE_FSW[] = "application/x-companion-fsw"; +constexpr char MIMETYPE_CUSTOM_FUNCTION[] = "application/x-companion-custom-function"; class RepeatComboBox: public QComboBox { @@ -67,7 +67,7 @@ class CustomFunctionsPanel : public GenericPanel void updateDataModels(); void customFunctionEdited(); void functionEdited(); - void fsw_customContextMenuRequested(QPoint pos); + void onCustomContextMenuRequested(QPoint pos); void refreshCustomFunction(int index, bool modified=false); void onChildModified(); bool playSound(int index); @@ -75,21 +75,25 @@ class CustomFunctionsPanel : public GenericPanel void toggleSound(bool play); void onMediaPlayerStateChanged(QMediaPlayer::State state); void onMediaPlayerError(QMediaPlayer::Error error); - void fswDelete(); - void fswCopy(); - void fswPaste(); - void fswCut(); - void fswMoveUp(); - void fswMoveDown(); - void fswInsert(); - void fswClear(); - void fswClearAll(); + void cmDelete(); + void cmCopy(); + void cmPaste(); + void cmCut(); + void cmMoveUp(); + void cmMoveDown(); + void cmInsert(); + void cmClear(); + void cmClearAll(); 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); - void swapFuncData(int idx1, int idx2); + bool hasClipboardData(QByteArray * data = nullptr) const; + bool insertAllowed() const; + bool moveDownAllowed() const; + bool moveUpAllowed() const; + void swapData(int idx1, int idx2); void resetCBsAndRefresh(int idx); RawSwitchFilterItemModel * rawSwitchItemModel; RawSourceFilterItemModel * rawSrcAllItemModel; @@ -113,7 +117,7 @@ class CustomFunctionsPanel : public GenericPanel QSlider * fswtchBLcolor[CPN_MAX_SPECIAL_FUNCTIONS]; QMediaPlayer * mediaPlayer; - int selectedFunction; + int selectedIndex; int fswCapability; }; diff --git a/companion/src/modeledit/flightmodes.cpp b/companion/src/modeledit/flightmodes.cpp index 53f5d7585..1634aed3a 100644 --- a/companion/src/modeledit/flightmodes.cpp +++ b/companion/src/modeledit/flightmodes.cpp @@ -29,21 +29,23 @@ FlightModePanel::FlightModePanel(QWidget * parent, ModelData & model, int phaseI ui(new Ui::FlightMode), phaseIdx(phaseIdx), phase(model.flightModeData[phaseIdx]), - reCount(firmware->getCapability(RotaryEncoders)), - gvCount(firmware->getCapability(Gvars)), rawSwitchItemModel(NULL) { ui->setupUi(this); ui->labelName->setContextMenuPolicy(Qt::CustomContextMenu); ui->labelName->setToolTip(tr("Popup menu available")); - connect(ui->labelName, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(name_customContextMenuRequested(const QPoint &))); + connect(ui->labelName, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onCustomContextMenuRequested(const QPoint &))); - int modesCount = firmware->getCapability(FlightModes); + board = getCurrentBoard(); + fmCount = firmware->getCapability(FlightModes); + gvCount = firmware->getCapability(Gvars); + reCount = firmware->getCapability(RotaryEncoders); + trimCount = Boards::getCapability(board, Board::NumTrims); // Flight mode name QRegExp rx(CHAR_FOR_NAMES_REGEX); - if (modesCount) { + if (fmCount) { ui->name->setValidator(new QRegExpValidator(rx, this)); ui->name->setMaxLength(firmware->getCapability(FlightModesName)); connect(ui->name, SIGNAL(editingFinished()), this, SLOT(phaseName_editingFinished())); @@ -65,13 +67,13 @@ FlightModePanel::FlightModePanel(QWidget * parent, ModelData & model, int phaseI if (firmware->getCapability(FlightModesHaveFades)) { int scale = firmware->getCapability(SlowScale); int range = firmware->getCapability(SlowRange); - ui->fadeIn->setMaximum(float(range)/scale); - ui->fadeIn->setSingleStep(1.0/scale); - ui->fadeIn->setDecimals((scale==1 ? 0 :1) ); + ui->fadeIn->setMaximum(float(range) / scale); + ui->fadeIn->setSingleStep(1.0 / scale); + ui->fadeIn->setDecimals((scale == 1 ? 0 :1) ); connect(ui->fadeIn, SIGNAL(editingFinished()), this, SLOT(phaseFadeIn_editingFinished())); - ui->fadeOut->setMaximum(float(range)/scale); - ui->fadeOut->setSingleStep(1.0/scale); - ui->fadeOut->setDecimals((scale==1 ? 0 :1)); + ui->fadeOut->setMaximum(float(range) / scale); + ui->fadeOut->setSingleStep(1.0 / scale); + ui->fadeOut->setDecimals((scale == 1 ? 0 :1)); connect(ui->fadeOut, SIGNAL(editingFinished()), this, SLOT(phaseFadeOut_editingFinished())); } else { @@ -81,78 +83,82 @@ FlightModePanel::FlightModePanel(QWidget * parent, ModelData & model, int phaseI // The trims QString labels[CPN_MAX_TRIMS]; - for(int i=0; i < CPN_MAX_STICKS; i++) { + for(int i = 0; i < CPN_MAX_STICKS; i++) { labels[i] = firmware->getAnalogInputName(i); } - labels[4] = "T5"; - labels[5] = "T6"; + labels[4] = "T5"; // TODO firmware function + labels[5] = "T6"; // TODO firmware function trimsLabel << ui->trim1Label << ui->trim2Label << ui->trim3Label << ui->trim4Label << ui->trim5Label << ui->trim6Label; trimsUse << ui->trim1Use << ui->trim2Use << ui->trim3Use << ui->trim4Use << ui->trim5Use << ui->trim6Use; trimsValue << ui->trim1Value << ui->trim2Value << ui->trim3Value << ui->trim4Value << ui->trim5Value << ui->trim6Value; trimsSlider << ui->trim1Slider << ui->trim2Slider << ui->trim3Slider << ui->trim4Slider << ui->trim5Slider << ui->trim6Slider; - Board::Type board = firmware->getBoard(); - - for (int i = getBoardCapability(board,Board::NumTrims); i < CPN_MAX_TRIMS; i++) { + for (int i = trimCount; i < CPN_MAX_TRIMS; i++) { trimsLabel[i]->hide(); trimsUse[i]->hide(); trimsValue[i]->hide(); trimsSlider[i]->hide(); } - for (int i = 0; i < getBoardCapability(board,Board::NumTrims); i++) { - trimsLabel[i]->setText(labels[CONVERT_MODE(i+1)-1]); - + for (int i = 0; i < trimCount; i++) { + trimsLabel[i]->setText(labels[CONVERT_MODE(i + 1) - 1]); QComboBox * cb = trimsUse[i]; cb->setProperty("index", i); if (IS_HORUS_OR_TARANIS(board)) { cb->addItem(tr("Trim disabled"), -1); } - for (int m=0; maddItem(tr("Own Trim"), m*2); + cb->addItem(tr("Own Trim"), m * 2); } else if (phaseIdx > 0) { - cb->addItem(tr("Use Trim from Flight mode %1").arg(m), m*2); + cb->addItem(tr("Use Trim from Flight mode %1").arg(m), m * 2); if (IS_HORUS_OR_TARANIS(board)) { - cb->addItem(tr("Use Trim from Flight mode %1 + Own Trim as an offset").arg(m), m*2+1); + cb->addItem(tr("Use Trim from Flight mode %1 + Own Trim as an offset").arg(m), m * 2 + 1); } } } connect(cb, SIGNAL(currentIndexChanged(int)), this, SLOT(phaseTrimUse_currentIndexChanged(int))); + int trimsMax = firmware->getCapability(ExtendedTrimsRange); + if (trimsMax == 0 || !model.extendedTrims) { + trimsMax = firmware->getCapability(TrimsRange); + } + trimsValue[i]->setProperty("index", i); + trimsValue[i]->setRange(-trimsMax, +trimsMax); connect(trimsValue[i], SIGNAL(valueChanged(int)), this, SLOT(phaseTrim_valueChanged())); trimsSlider[i]->setProperty("index", i); + trimsSlider[i]->setRange(-trimsMax, +trimsMax); + int chn = CONVERT_MODE(i + 1) - 1; + if (chn == 2/*TODO constant*/ && model.throttleReversed) + trimsSlider[i]->setInvertedAppearance(true); connect(trimsSlider[i], SIGNAL(valueChanged(int)), this, SLOT(phaseTrimSlider_valueChanged())); } // Rotary encoders if (reCount > 0) { QGridLayout *reLayout = new QGridLayout(ui->reGB); - for (int i=0; ireGB); - label->setText(tr("Rotary Encoder %1").arg(i+1)); + label->setText(tr("Rotary Encoder %1").arg(i + 1)); reLayout->addWidget(label, i, 0, 1, 1); if (phaseIdx > 0) { // RE link to another RE reUse[i] = new QComboBox(ui->reGB); reUse[i]->setProperty("index", i); Helpers::populateGvarUseCB(reUse[i], phaseIdx); - if (phase.rotaryEncoders[i] > 1024) { - reUse[i]->setCurrentIndex(phase.rotaryEncoders[i] - 1024); - } connect(reUse[i], SIGNAL(currentIndexChanged(int)), this, SLOT(phaseREUse_currentIndexChanged(int))); reLayout->addWidget(reUse[i], i, 1, 1, 1); } // RE value reValues[i] = new QSpinBox(ui->reGB); reValues[i]->setProperty("index", i); - reValues[i]->setMinimum(-1024); - reValues[i]->setMaximum(1024); + reValues[i]->setMinimum(RENC_MIN_VALUE); + reValues[i]->setMaximum(RENC_MAX_VALUE); connect(reValues[i], SIGNAL(editingFinished()), this, SLOT(phaseREValue_editingFinished())); reLayout->addWidget(reValues[i], i, 2, 1, 1); } @@ -206,15 +212,16 @@ FlightModePanel::FlightModePanel(QWidget * parent, ModelData & model, int phaseI gvLayout->addWidget(popupLabel, 0, headerCol++, 1, 1); } - for (int i=0; igvGB); - label->setText(tr("GVAR%1").arg(i+1)); + label->setText(tr("GVAR%1").arg(i + 1)); label->setProperty("index", i); label->setContextMenuPolicy(Qt::CustomContextMenu); - connect(label, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(gvLabel_customContextMenuRequested(const QPoint &))); - gvLayout->addWidget(label, i+1, col++, 1, 1); + label->setToolTip(tr("Popup menu available")); + connect(label, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(gvOnCustomContextMenuRequested(const QPoint &))); + gvLayout->addWidget(label, i + 1, col++, 1, 1); // GVar name int nameLen = firmware->getCapability(GvarsName); if (nameLen > 0) { @@ -222,24 +229,21 @@ FlightModePanel::FlightModePanel(QWidget * parent, ModelData & model, int phaseI gvNames[i]->setProperty("index", i); gvNames[i]->setMaxLength(nameLen); connect(gvNames[i], SIGNAL(editingFinished()), this, SLOT(GVName_editingFinished())); - gvLayout->addWidget(gvNames[i], i+1, col++, 1, 1); + gvLayout->addWidget(gvNames[i], i + 1, col++, 1, 1); } if (phaseIdx > 0) { // GVar link to another GVar gvUse[i] = new QComboBox(ui->gvGB); gvUse[i]->setProperty("index", i); Helpers::populateGvarUseCB(gvUse[i], phaseIdx); - if (phase.gvars[i] > GVAR_MAX_VALUE) { - gvUse[i]->setCurrentIndex(phase.gvars[i] - GVAR_MAX_VALUE); - } connect(gvUse[i], SIGNAL(currentIndexChanged(int)), this, SLOT(phaseGVUse_currentIndexChanged(int))); - gvLayout->addWidget(gvUse[i], i+1, col++, 1, 1); + gvLayout->addWidget(gvUse[i], i + 1, col++, 1, 1); } // GVar value gvValues[i] = new QDoubleSpinBox(ui->gvGB); gvValues[i]->setProperty("index", i); connect(gvValues[i], SIGNAL(editingFinished()), this, SLOT(phaseGVValue_editingFinished())); - gvLayout->addWidget(gvValues[i], i+1, col++, 1, 1); + gvLayout->addWidget(gvValues[i], i + 1, col++, 1, 1); if (IS_HORUS_OR_TARANIS(board) && phaseIdx == 0) { // GVar unit @@ -247,33 +251,33 @@ FlightModePanel::FlightModePanel(QWidget * parent, ModelData & model, int phaseI gvUnit[i]->setProperty("index", i); populateGvarUnitCB(gvUnit[i]); connect(gvUnit[i], SIGNAL(currentIndexChanged(int)), this, SLOT(phaseGVUnit_currentIndexChanged(int))); - gvLayout->addWidget(gvUnit[i], i+1, col++, 1, 1); + gvLayout->addWidget(gvUnit[i], i + 1, col++, 1, 1); // GVar precision gvPrec[i] = new QComboBox(ui->gvGB); gvPrec[i]->setProperty("index", i); populateGvarPrecCB(gvPrec[i]); connect(gvPrec[i], SIGNAL(currentIndexChanged(int)), this, SLOT(phaseGVPrec_currentIndexChanged(int))); - gvLayout->addWidget(gvPrec[i], i+1, col++, 1, 1); + gvLayout->addWidget(gvPrec[i], i + 1, col++, 1, 1); // GVar min gvMin[i] = new QDoubleSpinBox(ui->gvGB); gvMin[i]->setProperty("index", i); connect(gvMin[i], SIGNAL(editingFinished()), this, SLOT(phaseGVMin_editingFinished())); - gvLayout->addWidget(gvMin[i], i+1, col++, 1, 1); + gvLayout->addWidget(gvMin[i], i + 1, col++, 1, 1); // GVar max gvMax[i] = new QDoubleSpinBox(ui->gvGB); gvMax[i]->setProperty("index", i); connect(gvMax[i], SIGNAL(editingFinished()), this, SLOT(phaseGVMax_editingFinished())); - gvLayout->addWidget(gvMax[i], i+1, col++, 1, 1); + gvLayout->addWidget(gvMax[i], i + 1, col++, 1, 1); // Popups gvPopups[i] = new QCheckBox(ui->gvGB); gvPopups[i]->setProperty("index", i); //gvPopups[i]->setText(tr("Popup enabled")); connect(gvPopups[i], SIGNAL(toggled(bool)), this, SLOT(phaseGVPopupToggled(bool))); - gvLayout->addWidget(gvPopups[i], i+1, col++, 1, 1); + gvLayout->addWidget(gvPopups[i], i + 1, col++, 1, 1); } } } @@ -302,45 +306,35 @@ void FlightModePanel::update() ui->fadeOut->setValue(float(phase.fadeOut)/scale); for (int i = 0; i < getBoardCapability(firmware->getBoard(), Board::NumTrims); i++) { - int trimsMax = firmware->getCapability(ExtendedTrimsRange); - if (trimsMax == 0 || !model->extendedTrims) { - trimsMax = firmware->getCapability(TrimsRange); - } - trimsSlider[i]->setRange(-trimsMax, +trimsMax); - trimsValue[i]->setRange(-trimsMax, +trimsMax); - int chn = CONVERT_MODE(i+1)-1; - if (chn == 2/*TODO constant*/ && model->throttleReversed) - trimsSlider[i]->setInvertedAppearance(true); trimUpdate(i); } - for (int i=0; isetDisabled(false); - int idx = phase.rotaryEncoders[i]; - FlightModeData *phasere = &phase; - while (idx > 1024) { - int nextPhase = idx - 1025; - if (nextPhase >= phaseIdx) nextPhase += 1; - phasere = &model->flightModeData[nextPhase]; - idx = phasere->rotaryEncoders[i]; - reValues[i]->setDisabled(true); - } - reValues[i]->setValue(phasere->rotaryEncoders[i]); + for (int i = 0; i < reCount; i++) { + updateRotaryEncoder(i); } + + emit nameModified(); } + void FlightModePanel::updateGVar(int index) { lock = true; if (firmware->getCapability(GvarsName) > 0) { gvNames[index]->setText(model->gvarData[index].name); } + if (phaseIdx > 0) { + if (model->isGVarLinked(phaseIdx, index)) + gvUse[index]->setCurrentIndex(phase.gvars[index] - GVAR_MAX_VALUE); + else + gvUse[index]->setCurrentIndex(0); + } gvValues[index]->setDisabled(model->isGVarLinked(phaseIdx, index)); - setGVSB(gvValues[index], model->gvarData[index].getMin(), model->gvarData[index].getMax(), model->getGVarFieldValue(phaseIdx, index)); - if (IS_HORUS_OR_TARANIS(getCurrentBoard()) && phaseIdx == 0) { + setGVSB(gvValues[index], model->gvarData[index].getMin(), model->gvarData[index].getMax(), model->getGVarValue(phaseIdx, index)); + if (IS_HORUS_OR_TARANIS(board) && phaseIdx == 0) { gvUnit[index]->setCurrentIndex(model->gvarData[index].unit); gvPrec[index]->setCurrentIndex(model->gvarData[index].prec); setGVSB(gvMin[index], GVAR_MIN_VALUE, model->gvarData[index].getMax(), model->gvarData[index].getMin()); @@ -362,6 +356,20 @@ void FlightModePanel::setGVSB(QDoubleSpinBox * sb, int min, int max, int val) sb->setValue(val * mul); } +void FlightModePanel::updateRotaryEncoder(int index) +{ + lock = true; + if (phaseIdx > 0) { + if (model->isREncLinked(phaseIdx, index)) + reUse[index]->setCurrentIndex(phase.rotaryEncoders[index] - RENC_MAX_VALUE); + else + reUse[index]->setCurrentIndex(0); + } + reValues[index]->setDisabled(model->isREncLinked(phaseIdx, index)); + reValues[index]->setValue(model->getREncValue(phaseIdx, index)); + lock = false; +} + // TODO: pull units from GVarData void FlightModePanel::populateGvarUnitCB(QComboBox * cb) { @@ -380,45 +388,44 @@ void FlightModePanel::populateGvarPrecCB(QComboBox * cb) void FlightModePanel::phaseName_editingFinished() { - QLineEdit *lineEdit = qobject_cast(sender()); - strcpy(phase.name, lineEdit->text().toLatin1()); - emit modified(); - emit nameModified(); + QLineEdit *lineEdit = qobject_cast(sender()); + strcpy(phase.name, lineEdit->text().toLatin1()); + emit modified(); + emit nameModified(); } void FlightModePanel::phaseSwitchChanged(int index) { - if (lock) - return; - - bool ok; - const RawSwitch rs(ui->swtch->itemData(index).toInt(&ok)); - if (ok && phase.swtch.toValue() != rs.toValue()) { - phase.swtch = rs; - emit modified(); + if (!lock) { + bool ok; + const RawSwitch rs(ui->swtch->itemData(index).toInt(&ok)); + if (ok && phase.swtch.toValue() != rs.toValue()) { + phase.swtch = rs; + emit modified(); + } } } void FlightModePanel::phaseFadeIn_editingFinished() { - QDoubleSpinBox *spinBox = qobject_cast(sender()); - int scale = firmware->getCapability(SlowScale); - phase.fadeIn = round(spinBox->value()*scale); - emit modified(); + QDoubleSpinBox *spinBox = qobject_cast(sender()); + int scale = firmware->getCapability(SlowScale); + phase.fadeIn = round(spinBox->value()*scale); + emit modified(); } void FlightModePanel::phaseFadeOut_editingFinished() { - QDoubleSpinBox *spinBox = qobject_cast(sender()); - int scale = firmware->getCapability(SlowScale); - phase.fadeOut = round(spinBox->value()*scale); - emit modified(); + QDoubleSpinBox *spinBox = qobject_cast(sender()); + int scale = firmware->getCapability(SlowScale); + phase.fadeOut = round(spinBox->value()*scale); + emit modified(); } void FlightModePanel::trimUpdate(unsigned int trim) { lock = true; - int chn = CONVERT_MODE(trim+1)-1; + int chn = CONVERT_MODE(trim + 1) - 1; int value = model->getTrimValue(phaseIdx, chn); trimsSlider[trim]->setValue(value); trimsValue[trim]->setValue(value); @@ -428,9 +435,8 @@ void FlightModePanel::trimUpdate(unsigned int trim) trimsSlider[trim]->setEnabled(false); } else { - Board::Type board = firmware->getBoard(); if (IS_HORUS_OR_TARANIS(board)) - trimsUse[trim]->setCurrentIndex(1 + 2*phase.trimRef[chn] + phase.trimMode[chn] - (phase.trimRef[chn] > phaseIdx ? 1 : 0)); + trimsUse[trim]->setCurrentIndex(1 + 2 * phase.trimRef[chn] + phase.trimMode[chn] - (phase.trimRef[chn] > phaseIdx ? 1 : 0)); else trimsUse[trim]->setCurrentIndex(phase.trimRef[chn]); if (phaseIdx == 0 || phase.trimRef[chn] == phaseIdx || (IS_HORUS_OR_TARANIS(board) && phase.trimMode[chn] != 0)) { @@ -451,6 +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(); emit modified(); } } @@ -462,6 +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 modified(); } } @@ -478,7 +486,9 @@ void FlightModePanel::phaseGVUse_currentIndexChanged(int index) else { phase.gvars[gvar] = GVAR_MAX_VALUE + index; } - updateGVar(gvar); + if (model->isGVarLinkedCircular(phaseIdx, gvar)) + QMessageBox::warning(this, "Companion", tr("Warning: Global variable links back to itself. Flight Mode 0 value used.")); + emit datachanged(); emit modified(); lock = false; } @@ -490,8 +500,8 @@ void FlightModePanel::phaseGVUnit_currentIndexChanged(int index) QComboBox *comboBox = qobject_cast(sender()); int gvar = comboBox->property("index").toInt(); model->gvarData[gvar].unit = index; + emit datachanged(); emit modified(); - updateGVar(gvar); } } @@ -501,8 +511,8 @@ void FlightModePanel::phaseGVPrec_currentIndexChanged(int index) QComboBox *comboBox = qobject_cast(sender()); int gvar = comboBox->property("index").toInt(); model->gvarData[gvar].prec = index; + emit datachanged(); emit modified(); - updateGVar(gvar); } } @@ -513,19 +523,19 @@ void FlightModePanel::phaseGVMin_editingFinished() int gvar = spinBox->property("index").toInt(); model->gvarData[gvar].setMin(spinBox->value()); if (!model->isGVarLinked(phaseIdx, gvar)) { - if (model->getGVarFieldValuePrec(phaseIdx, gvar) < spinBox->value()) { + if (model->getGVarValuePrec(phaseIdx, gvar) < spinBox->value()) { phase.gvars[gvar] = model->gvarData[gvar].getMin(); } } - for (int x=1; xgetCapability(FlightModes); x++) { + for (int x = 1; x < fmCount; x++) { if (!model->isGVarLinked(x, gvar)) { if (model->flightModeData[x].gvars[gvar] < model->gvarData[gvar].getMin()) { model->flightModeData[x].gvars[gvar] = model->gvarData[gvar].getMin(); } } } + emit datachanged(); emit modified(); - updateGVar(gvar); } } @@ -536,19 +546,19 @@ void FlightModePanel::phaseGVMax_editingFinished() int gvar = spinBox->property("index").toInt(); model->gvarData[gvar].setMax(spinBox->value()); if (!model->isGVarLinked(phaseIdx, gvar)) { - if (model->getGVarFieldValuePrec(phaseIdx, gvar) > spinBox->value()) { + if (model->getGVarValuePrec(phaseIdx, gvar) > spinBox->value()) { phase.gvars[gvar] = model->gvarData[gvar].getMax(); } } - for (int x=1; xgetCapability(FlightModes); x++) { + for (int x = 1; x < fmCount; x++) { if (!model->isGVarLinked(x, gvar)) { if (model->flightModeData[x].gvars[gvar] > model->gvarData[gvar].getMax()) { model->flightModeData[x].gvars[gvar] = model->gvarData[gvar].getMax(); } } } + emit datachanged(); emit modified(); - updateGVar(gvar); } } @@ -582,11 +592,13 @@ void FlightModePanel::phaseREUse_currentIndexChanged(int index) phase.rotaryEncoders[re] = 0; } else { - phase.rotaryEncoders[re] = 1024 + index; ; + phase.rotaryEncoders[re] = RENC_MAX_VALUE + index; ; } update(); - lock = false; + if (model->isREncLinkedCircular(phaseIdx, re)) + QMessageBox::warning(this, "Companion", tr("Warning: Rotary encoder links back to itself. Flight Mode 0 value used.")); emit modified(); + lock = false; } } @@ -595,7 +607,7 @@ void FlightModePanel::phaseTrimUse_currentIndexChanged(int index) if (!lock) { QComboBox *comboBox = qobject_cast(sender()); int trim = comboBox->property("index").toInt(); - int chn = CONVERT_MODE(trim+1)-1; + int chn = CONVERT_MODE(trim + 1) - 1; int data = comboBox->itemData(index).toInt(); if (data < 0) { phase.trimMode[chn] = -1; @@ -603,7 +615,6 @@ void FlightModePanel::phaseTrimUse_currentIndexChanged(int index) phase.trim[chn] = 0; } else { - Board::Type board = firmware->getBoard(); if (IS_HORUS_OR_TARANIS(board)) { phase.trimMode[chn] = data % 2; phase.trimRef[chn] = data / 2; @@ -624,7 +635,7 @@ void FlightModePanel::phaseTrim_valueChanged() if (!lock) { QSpinBox *spinBox = qobject_cast(sender()); int trim = spinBox->property("index").toInt(); - int chn = CONVERT_MODE(trim+1)-1; + int chn = CONVERT_MODE(trim + 1) - 1; int value = spinBox->value(); model->setTrimValue(phaseIdx, chn, value); lock = true; @@ -639,7 +650,7 @@ void FlightModePanel::phaseTrimSlider_valueChanged() if (!lock) { QSlider *slider = qobject_cast(sender()); int trim = slider->property("index").toInt(); - int chn = CONVERT_MODE(trim+1)-1; + int chn = CONVERT_MODE(trim + 1) - 1; int value = slider->value(); model->setTrimValue(phaseIdx, chn, value); lock = true; @@ -649,78 +660,638 @@ void FlightModePanel::phaseTrimSlider_valueChanged() } } -void FlightModePanel::name_customContextMenuRequested(const QPoint & pos) +void FlightModePanel::onCustomContextMenuRequested(QPoint pos) { QLabel *label = (QLabel *)sender(); QPoint globalPos = label->mapToGlobal(pos); + QMenu contextMenu; - contextMenu.addAction(CompanionIcon("clear.png"), tr("&Clear"),this,SLOT(fmClear()),tr("Clear")); + contextMenu.addAction(CompanionIcon("copy.png"), tr("Copy"), this, SLOT(cmCopy())); + contextMenu.addAction(CompanionIcon("cut.png"), tr("Cut"), this, SLOT(cmCut())); + 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()))->setEnabled(phaseIdx == 0); + contextMenu.exec(globalPos); } -void FlightModePanel::fmClear() +bool FlightModePanel::hasClipboardData(QByteArray * data) const { - int res = QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear all current Flight Mode properties?"), QMessageBox::Yes | QMessageBox::No); - if (res == QMessageBox::Yes) { - phase.clear(phaseIdx); - if (phaseIdx == 0) { - if (IS_HORUS_OR_TARANIS(getCurrentBoard())) { - for (int i=0; i < gvCount; ++i) { - model->gvarData[i].clear(); + const QClipboard * clipboard = QApplication::clipboard(); + const QMimeData * mimeData = clipboard->mimeData(); + if (mimeData->hasFormat(MIMETYPE_FLIGHTMODE)) { + if (data) + data->append(mimeData->data(MIMETYPE_FLIGHTMODE)); + return true; + } + return false; +} + +bool FlightModePanel::insertAllowed() const +{ + return ((phaseIdx < fmCount - 1) && (model->flightModeData[fmCount - 1].isEmpty(fmCount - 1))); +} + +bool FlightModePanel::moveDownAllowed() const +{ + return phaseIdx < fmCount - 1; +} + +bool FlightModePanel::moveUpAllowed() const +{ + return phaseIdx > 0; +} + +void FlightModePanel::cmClear() +{ + 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); + + if (phaseIdx == 0) { + for (int i = 0; i < gvCount; i++) { + model->gvarData[i].clear(); + for (int j = 0; j < fmCount; j++) { + FlightModeData *fm = &model->flightModeData[j]; + fm->gvars[i] = fm->linkedGVarFlightModeZero(j); + } + model->updateAllReferences(ModelData::REF_UPD_TYPE_GLOBAL_VARIABLE, ModelData::REF_UPD_ACT_CLEAR, i); + } + } + else { + QComboBox * pswtch = ui->swtch; + RawSwitch item = RawSwitch(SWITCH_TYPE_NONE); + pswtch->setCurrentIndex(pswtch->findText(item.toString())); + for (int i = 0; i < gvCount; i++) { + phase.gvars[i] = phase.linkedGVarFlightModeZero(phaseIdx); + } + for (int i = 0; i < reCount; i++) { + phase.rotaryEncoders[i] = phase.linkedREncFlightModeZero(phaseIdx); + } + } + + model->updateAllReferences(ModelData::REF_UPD_TYPE_FLIGHT_MODE, ModelData::REF_UPD_ACT_CLEAR, phaseIdx); + + emit datachanged(); + emit modified(); +} + +void FlightModePanel::cmClearAll() +{ + if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear all Flight Modes. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) + return; + + for (int j = 0; j < fmCount; j++) { + FlightModeData *fm = &model->flightModeData[j]; + fm->clear(j); + for (int i = 0; i < gvCount; i++) { + fm->gvars[i] = fm->linkedGVarFlightModeZero(j); + } + for (int i = 0; i < reCount; i++) { + fm->rotaryEncoders[i] = fm->linkedREncFlightModeZero(j); + } + model->updateAllReferences(ModelData::REF_UPD_TYPE_FLIGHT_MODE, ModelData::REF_UPD_ACT_CLEAR, j); + } + + for (int i = 0; i < gvCount; i++) { + model->gvarData[i].clear(); + model->updateAllReferences(ModelData::REF_UPD_TYPE_GLOBAL_VARIABLE, ModelData::REF_UPD_ACT_CLEAR, i); + } + + emit datachanged(); + emit modified(); +} + +void FlightModePanel::cmCopy() +{ + QByteArray data; + data.append((char*)&model->flightModeData[phaseIdx], sizeof(FlightModeData)); + QMimeData *mimeData = new QMimeData; + mimeData->setData(MIMETYPE_FLIGHTMODE, data); + QApplication::clipboard()->setMimeData(mimeData,QClipboard::Clipboard); +} + +void FlightModePanel::cmCut() +{ + cmCopy(); + cmClear(); +} + +void FlightModePanel::cmDelete() +{ + if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Delete Flight Mode. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) + return; + + const int maxidx = fmCount - 1; + + memmove(&model->flightModeData[phaseIdx], &model->flightModeData[phaseIdx + 1], (CPN_MAX_FLIGHT_MODES - (phaseIdx + 1)) * sizeof(FlightModeData)); + model->flightModeData[maxidx].clear(maxidx); + + for (int j = 0; j < maxidx; j++) { + FlightModeData *fm = &model->flightModeData[j]; + + if (phaseIdx == 0 && j == 0) + fm->swtch = RawSwitch(0); + + for (int i = 0; i < trimCount; i++) { + if (phaseIdx == 0 && j == 0) { + fm->trimMode[i] = 0; + fm->trimRef[i] = 0; + } + else if (fm->trimRef[i] > phaseIdx && fm->trimMode[i] > -1) { + fm->trimRef[i]--; + } + else if (fm->trimRef[i] == phaseIdx) { + fm->trimMode[i] = 0; + fm->trimRef[i] = 0; + fm->trim[i] = 0; + } + } + + for (int i = 0; i < gvCount; i++) { + if (model->isGVarLinked(j, i)) { + int idx = model->getGVarFlightModeIndex(j, i); + if (phaseIdx == 0 && j == 0) + model->setGVarFlightModeIndexToValue(j, i, j); + else if (idx > phaseIdx) + model->setGVarFlightModeIndexToValue(j, i, idx - 1); + else if (idx == phaseIdx) + model->setGVarFlightModeIndexToValue(j, i, 0); + } + } + + for (int i = 0; i < reCount; i++) { + if (model->isREncLinked(j, i)) { + int idx = model->getREncFlightModeIndex(j, i); + if (phaseIdx == 0 && j == 0) + model->setREncFlightModeIndexToValue(j, i, j); + else if (idx > phaseIdx) + model->setREncFlightModeIndexToValue(j, i, idx - 1); + else if (idx == phaseIdx) + model->setREncFlightModeIndexToValue(j, i, 0); + } + } + } + + model->updateAllReferences(ModelData::REF_UPD_TYPE_FLIGHT_MODE, ModelData::REF_UPD_ACT_SHIFT, phaseIdx, 0, -1); + + emit datachanged(); + emit modified(); +} + +void FlightModePanel::cmInsert() +{ + const int maxidx = fmCount - 1; + + memmove(&model->flightModeData[phaseIdx + 1], &model->flightModeData[phaseIdx], (CPN_MAX_FLIGHT_MODES - (phaseIdx + 1)) * sizeof(FlightModeData)); + model->flightModeData[phaseIdx].clear(phaseIdx); + + for (int j = maxidx; j > 0; j--) { + FlightModeData *fm = &model->flightModeData[j]; + + for (int i = 0; i < trimCount; i++) { + if (phaseIdx == 0 && j == 1) + fm->trimRef[i] = j; + else if (fm->trimRef[i] >= phaseIdx) { + if (fm->trimRef[i] < maxidx) + fm->trimRef[i]++; + else { + fm->trimMode[i] = 0; + fm->trimRef[i] = 0; + fm->trim[i] = 0; } } } - else { - lock = true; - QComboBox * pswtch = ui->swtch; - RawSwitch item = RawSwitch(SWITCH_TYPE_NONE); - pswtch->setCurrentIndex(pswtch->findText(item.toString())); - if (gvCount > 0 && (firmware->getCapability(GvarsFlightModes))) { - for (int i=0; isetCurrentIndex((phase.gvars[i] > GVAR_MAX_VALUE ? (phase.gvars[i] - GVAR_MAX_VALUE) : 0)); - } + + for (int i = 0; i < gvCount; i++) { + if (model->isGVarLinked(j, i)) { + int idx = model->getGVarFlightModeIndex(j, i); + if (phaseIdx == 0 && j == 1) + model->setGVarFlightModeIndexToValue(j, i, j); + else if (idx >= phaseIdx) + model->setGVarFlightModeIndexToValue(j, i, idx + 1); } - for (int i=0; isetCurrentIndex((phase.rotaryEncoders[i] > GVAR_MAX_VALUE ? (phase.rotaryEncoders[i] - GVAR_MAX_VALUE) : 0)); - } - lock = false; } - update(); + + for (int i = 0; i < reCount; i++) { + if (model->isREncLinked(j, i)) { + int idx = model->getREncFlightModeIndex(j, i); + if (phaseIdx == 0 && j == 1) + model->setREncFlightModeIndexToValue(j, i, j); + else if (idx >= phaseIdx) + model->setREncFlightModeIndexToValue(j, i, idx + 1); + } + } + } + + model->updateAllReferences(ModelData::REF_UPD_TYPE_FLIGHT_MODE, ModelData::REF_UPD_ACT_SHIFT, phaseIdx, 0, 1); + + emit datachanged(); + emit modified(); +} + +void FlightModePanel::cmMoveDown() +{ + swapData(phaseIdx, phaseIdx + 1); +} + +void FlightModePanel::cmMoveUp() +{ + swapData(phaseIdx, phaseIdx - 1); +} + +void FlightModePanel::cmPaste() +{ + QByteArray data; + if (hasClipboardData(&data)) { + FlightModeData *fm = &model->flightModeData[phaseIdx]; + memcpy(fm, data.constData(), sizeof(FlightModeData)); + + if (phaseIdx == 0) + fm->swtch = RawSwitch(0); + + for (int i = 0; i < trimCount; i++) { + if (phaseIdx == 0) { + fm->trimMode[i] = 0; + fm->trimRef[i] = 0; + } + } + + // TODO fix up linked GVs but need to know source FM index to make adjustments + for (int i = 0; i < gvCount; i++) { + if (model->isGVarLinked(phaseIdx, i)) { + int linkedidx = model->getGVarFlightModeIndex(phaseIdx, i); + if (phaseIdx == 0 || linkedidx == phaseIdx) + model->setGVarFlightModeIndexToValue(phaseIdx, i, phaseIdx); + } + } + + // TODO fix up linked REs but need to know source FM index to make adjustments + for (int i = 0; i < reCount; i++) { + if (model->isREncLinked(phaseIdx, i)) { + int linkedidx = model->getREncFlightModeIndex(phaseIdx, i); + if (phaseIdx == 0 || linkedidx == phaseIdx) + model->setREncFlightModeIndexToValue(phaseIdx, i, phaseIdx); + } + } + + emit datachanged(); emit modified(); - emit nameModified(); } } -void FlightModePanel::gvLabel_customContextMenuRequested(const QPoint & pos) +void FlightModePanel::swapData(int idx1, int idx2) +{ + if (idx1 == idx2) + return; + + const int shift = idx2 - idx1; + + FlightModeData fmdtmp = model->flightModeData[idx2]; + FlightModeData *fmd1 = &model->flightModeData[idx1]; + FlightModeData *fmd2 = &model->flightModeData[idx2]; + memcpy(fmd2, fmd1, sizeof(FlightModeData)); + memcpy(fmd1, &fmdtmp, sizeof(FlightModeData)); + + if (idx1 == 0) + fmd1->swtch = RawSwitch(0); + else if (idx2 == 0) + fmd2->swtch = RawSwitch(0); + + for (int i = 0; i < trimCount; i++) { + if (fmd1->trimRef[i] == idx1) + fmd1->trimRef[i] = idx2; + else if (fmd1->trimRef[i] == idx2) + fmd1->trimRef[i] = idx1; + + if (fmd2->trimRef[i] == idx1) + fmd2->trimRef[i] = idx2; + else if (fmd2->trimRef[i] == idx2) + fmd2->trimRef[i] = idx1; + + if (idx1 == 0) { + fmd1->trimMode[i] = 0; + fmd1->trimRef[i] = 0; + } + else if (idx2 == 0) { + fmd2->trimMode[i] = 0; + fmd2->trimRef[i] = 0; + } + } + + for (int i = 0; i < gvCount; i++) { + if (model->isGVarLinked(idx1, i)) { + int linkedidx = model->getGVarFlightModeIndex(idx1, i); + if (linkedidx == idx1) + model->setGVarFlightModeIndexToValue(idx1, i, idx2 - shift); + else if (linkedidx == idx2) + model->setGVarFlightModeIndexToValue(idx1, i, idx1 + shift); + else + model->setGVarFlightModeIndexToValue(idx1, i, linkedidx); + } + + if (model->isGVarLinked(idx2, i)) { + int linkedidx = model->getGVarFlightModeIndex(idx2, i); + if (linkedidx == idx1) + model->setGVarFlightModeIndexToValue(idx2, i, idx2 - shift); + else if (linkedidx == idx2) + model->setGVarFlightModeIndexToValue(idx2, i, idx1 + shift); + else + model->setGVarFlightModeIndexToValue(idx2, i, linkedidx); + } + } + + for (int i = 0; i < reCount; i++) { + if (model->isREncLinked(idx1, i)) { + int linkedidx = model->getREncFlightModeIndex(idx1, i); + if (linkedidx == idx1) + model->setREncFlightModeIndexToValue(idx1, i, idx2 - shift); + else if (linkedidx == idx2) + model->setREncFlightModeIndexToValue(idx1, i, idx1 + shift); + else + model->setREncFlightModeIndexToValue(idx1, i, linkedidx); + } + + if (model->isREncLinked(idx2, i)) { + int linkedidx = model->getREncFlightModeIndex(idx2, i); + if (linkedidx == idx1) + model->setREncFlightModeIndexToValue(idx2, i, idx2 - shift); + else if (linkedidx == idx2) + model->setREncFlightModeIndexToValue(idx2, i, idx1 + shift); + else + model->setREncFlightModeIndexToValue(idx2, i, linkedidx); + } + } + + model->updateAllReferences(ModelData::REF_UPD_TYPE_FLIGHT_MODE, ModelData::REF_UPD_ACT_SWAP, idx1, idx2); + emit datachanged(); + emit modified(); +} + +void FlightModePanel::gvOnCustomContextMenuRequested(QPoint pos) { QLabel *label = (QLabel *)sender(); gvIdx = label->property("index").toInt(); QPoint globalPos = label->mapToGlobal(pos); + QMenu contextMenu; - contextMenu.addAction(CompanionIcon("clear.png"), tr("&Clear"),this,SLOT(gvClear()),tr("Clear")); + contextMenu.addAction(CompanionIcon("copy.png"), tr("Copy"), this, SLOT(gvCmCopy())); + contextMenu.addAction(CompanionIcon("cut.png"), tr("Cut"), this, SLOT(gvCmCut())); + contextMenu.addAction(CompanionIcon("paste.png"), tr("Paste"), this, SLOT(gvCmPaste()))->setEnabled(gvHasClipboardData()); + contextMenu.addAction(CompanionIcon("clear.png"), tr("Clear"), this, SLOT(gvCmClear())); + contextMenu.addSeparator(); + contextMenu.addAction(CompanionIcon("arrow-right.png"), tr("Insert"), this, SLOT(gvCmInsert()))->setEnabled(gvInsertAllowed()); + contextMenu.addAction(CompanionIcon("arrow-left.png"), tr("Delete"), this, SLOT(gvCmDelete()))->setEnabled(gvDeleteAllowed()); + contextMenu.addAction(CompanionIcon("moveup.png"), tr("Move Up"), this, SLOT(gvCmMoveUp()))->setEnabled(gvMoveUpAllowed()); + contextMenu.addAction(CompanionIcon("movedown.png"), tr("Move Down"), this, SLOT(gvCmMoveDown()))->setEnabled(gvMoveDownAllowed()); + contextMenu.addSeparator(); + contextMenu.addAction(CompanionIcon("clear.png"), tr("Clear All"), this, SLOT(gvCmClearAll())); + contextMenu.exec(globalPos); } -void FlightModePanel::gvClear() +bool FlightModePanel::gvHasClipboardData() const +{ + if (gvHasDefnClipboardData() || gvHasValueClipboardData()) + return true; + return false; +} + +bool FlightModePanel::gvHasDefnClipboardData(QByteArray * data) const +{ + const QClipboard * clipboard = QApplication::clipboard(); + const QMimeData * mimeData = clipboard->mimeData(); + if (phaseIdx == 0 && mimeData->hasFormat(MIMETYPE_GVAR_PARAMS)) { + if (data) { + data->clear(); + data->append(mimeData->data(MIMETYPE_GVAR_PARAMS)); + } + return true; + } + return false; +} + +bool FlightModePanel::gvHasValueClipboardData(QByteArray * data) const +{ + const QClipboard * clipboard = QApplication::clipboard(); + const QMimeData * mimeData = clipboard->mimeData(); + if (mimeData->hasFormat(MIMETYPE_GVAR_VALUE)) { + if (data) { + data->clear(); + data->append(mimeData->data(MIMETYPE_GVAR_VALUE)); + } + return true; + } + return false; +} + +bool FlightModePanel::gvDeleteAllowed() const +{ + return phaseIdx == 0; +} + +bool FlightModePanel::gvInsertAllowed() const +{ + bool ret = true; + if (phaseIdx == 0) { + if (!model->gvarData[gvCount - 1].isEmpty()) + ret = false; + for (int i = 0; i < fmCount; i++) { + if (model->flightModeData[i].gvars[gvCount - 1] != phase.linkedGVarFlightModeZero(i)) + ret = false; + } + } + else + ret = false; + + return ret; +} + +bool FlightModePanel::gvMoveDownAllowed() const +{ + return (phaseIdx == 0 && gvIdx < gvCount - 1); +} + +bool FlightModePanel::gvMoveUpAllowed() const +{ + return (phaseIdx == 0 && gvIdx > 0); +} + +void FlightModePanel::gvCmClear() { if (phaseIdx == 0) { - if (IS_HORUS_OR_TARANIS(getCurrentBoard())) { - model->gvarData[gvIdx].clear(); - phase.gvars[gvIdx] = 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; + model->gvarData[gvIdx].clear(); + for (int i = 0; i < fmCount; i++) { + model->flightModeData[i].gvars[gvIdx] = model->flightModeData[i].linkedGVarFlightModeZero(i); + } + model->updateAllReferences(ModelData::REF_UPD_TYPE_GLOBAL_VARIABLE, ModelData::REF_UPD_ACT_CLEAR, gvIdx); + } + else { + phase.gvars[gvIdx] = phase.linkedGVarFlightModeZero(phaseIdx); + } + emit datachanged(); + emit modified(); +} + +void FlightModePanel::gvCmClearAll() +{ + if (phaseIdx == 0) { + if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear all Global Variables for all Flight Modes. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) + return; + for (int i = 0; i < gvCount; i++) { + model->gvarData[i].clear(); + for (int j = 0; j < fmCount; j++) { + model->flightModeData[j].gvars[i] = model->flightModeData[j].linkedGVarFlightModeZero(j); + } + model->updateAllReferences(ModelData::REF_UPD_TYPE_GLOBAL_VARIABLE, ModelData::REF_UPD_ACT_CLEAR, i); } } else { - lock = true; - if (gvCount > 0 && (firmware->getCapability(GvarsFlightModes))) { - phase.gvars[gvIdx] = GVAR_MAX_VALUE + 1; - gvUse[gvIdx]->setCurrentIndex(1); + if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear all Global Variables for this Flight Mode. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) + return; + for (int i = 0; i < gvCount; i++) { + phase.gvars[i] = phase.linkedGVarFlightModeZero(phaseIdx); } - lock = false; } - update(); + emit datachanged(); emit modified(); } +void FlightModePanel::gvCmCopy() +{ + QMimeData *mimeData = new QMimeData; + QByteArray data; + if (phaseIdx == 0) { + data.append((char*)&model->gvarData[gvIdx], sizeof(GVarData)); + mimeData->setData(MIMETYPE_GVAR_PARAMS, data); + } + else { + mimeData->removeFormat(MIMETYPE_GVAR_PARAMS); + } + 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(); + } + 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(); + } +} + +void FlightModePanel::gvCmDelete() +{ + if (phaseIdx > 0) + return; + int maxidx = gvCount - 1; + for (int i = gvIdx; i < maxidx; i++) { + memcpy(&model->gvarData[i], &model->gvarData[i + 1], sizeof(GVarData)); + for (int j = 0; j < fmCount; j++) { + model->flightModeData[j].gvars[i] = model->flightModeData[j].gvars[i + 1]; + } + } + + model->gvarData[maxidx].clear(); + 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(); + emit modified(); +} + +void FlightModePanel::gvCmInsert() +{ + for (int i = (gvCount - 1); i > gvIdx; i--) { + memcpy(&model->gvarData[i], &model->gvarData[i - 1], sizeof(GVarData)); + for (int j = 0; j < fmCount; j++) { + model->flightModeData[j].gvars[i] = model->flightModeData[j].gvars[i - 1]; + } + } + model->gvarData[gvIdx].clear(); + for (int j = 0; j < fmCount; j++) { + 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(); + emit modified(); +} + +void FlightModePanel::gvCmMoveDown() +{ + if (phaseIdx == 0) + gvSwapData(gvIdx, gvIdx + 1); +} + +void FlightModePanel::gvCmMoveUp() +{ + if (phaseIdx == 0) + gvSwapData(gvIdx, gvIdx - 1); +} + +void FlightModePanel::gvCmPaste() +{ + QByteArray data; + if (phaseIdx == 0 && gvHasDefnClipboardData(&data)) { + GVarData *gvd = &model->gvarData[gvIdx]; + memcpy(gvd, data.constData(), sizeof(GVarData)); + } + if (gvHasValueClipboardData(&data)) { + int val = data.toInt(); + if (val > GVAR_MAX_VALUE) { + if (phaseIdx > 0) + model->setGVarFlightModeIndexToValue(phaseIdx, gvIdx, val - (GVAR_MAX_VALUE + 1)); // index stored in clipboard + else + phase.gvars[gvIdx] = 0; + } + else + phase.gvars[gvIdx] = val; + } + emit datachanged(); + emit modified(); +} + +void FlightModePanel::gvSwapData(int idx1, int idx2) +{ + if (phaseIdx == 0 && idx1 != idx2) { + GVarData datatmp = model->gvarData[idx2]; + GVarData *data1 = &model->gvarData[idx1]; + GVarData *data2 = &model->gvarData[idx2]; + memcpy(data2, data1, sizeof(GVarData)); + memcpy(data1, &datatmp, sizeof(GVarData)); + for (int j = 0; j < fmCount; j++) { + int valtmp = model->flightModeData[j].gvars[idx2]; + model->flightModeData[j].gvars[idx2] = model->flightModeData[j].gvars[idx1]; + model->flightModeData[j].gvars[idx1] = valtmp; + } + model->updateAllReferences(ModelData::REF_UPD_TYPE_GLOBAL_VARIABLE, ModelData::REF_UPD_ACT_SWAP, idx1, idx2); + emit datachanged(); + emit modified(); + } +} + /**********************************************************/ FlightModesPanel::FlightModesPanel(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware): @@ -733,16 +1304,16 @@ FlightModesPanel::FlightModesPanel(QWidget * parent, ModelData & model, GeneralS QGridLayout * gridLayout = new QGridLayout(this); tabWidget = new QTabWidget(this); - for (int i=0; isetProperty("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); tabWidget->addTab(tab, getTabName(i)); } gridLayout->addWidget(tabWidget, 0, 0, 1, 1); - connect(tabWidget, SIGNAL(currentChanged(int)), this, SLOT(on_tabWidget_currentChanged(int))); } FlightModesPanel::~FlightModesPanel() diff --git a/companion/src/modeledit/flightmodes.h b/companion/src/modeledit/flightmodes.h index c5aa434fb..1986f1e46 100644 --- a/companion/src/modeledit/flightmodes.h +++ b/companion/src/modeledit/flightmodes.h @@ -26,6 +26,10 @@ class RawSwitchFilterItemModel; +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"; + namespace Ui { class FlightMode; } @@ -42,6 +46,7 @@ class FlightModePanel : public ModelPanel signals: void nameModified(); + void datachanged(); private slots: void phaseName_editingFinished(); @@ -61,18 +66,36 @@ class FlightModePanel : public ModelPanel void phaseGVMax_editingFinished(); void phaseREValue_editingFinished(); void phaseREUse_currentIndexChanged(int index); - void name_customContextMenuRequested(const QPoint & pos); - void fmClear(); - void gvLabel_customContextMenuRequested(const QPoint & pos); - void gvClear(); + void onCustomContextMenuRequested(QPoint pos); + void cmClear(); + void cmClearAll(); + void cmCopy(); + void cmCut(); + void cmDelete(); + void cmInsert(); + void cmPaste(); + void cmMoveDown(); + void cmMoveUp(); + void gvOnCustomContextMenuRequested(QPoint pos); + void gvCmClear(); + void gvCmClearAll(); + void gvCmCopy(); + void gvCmCut(); + void gvCmDelete(); + void gvCmInsert(); + void gvCmPaste(); + void gvCmMoveDown(); + void gvCmMoveUp(); private: Ui::FlightMode *ui; int phaseIdx; FlightModeData & phase; + int fmCount; int reCount; int gvCount; int gvIdx; + int trimCount; QVector trimsLabel; QLineEdit * gvNames[CPN_MAX_GVARS]; QDoubleSpinBox * gvValues[CPN_MAX_GVARS]; @@ -88,12 +111,27 @@ class FlightModePanel : public ModelPanel QVector trimsValue; QVector trimsSlider; RawSwitchFilterItemModel * rawSwitchItemModel; + Board::Type board; void trimUpdate(unsigned int trim); void updateGVar(int index); + void updateRotaryEncoder(int index); void setGVSB(QDoubleSpinBox * spinBox, int min, int max, int val); void populateGvarUnitCB(QComboBox * cb); void populateGvarPrecCB(QComboBox * cb); + bool hasClipboardData(QByteArray * data = nullptr) const; + bool insertAllowed() const; + bool moveDownAllowed() const; + bool moveUpAllowed() const; + void swapData(int idx1, int idx2); + bool gvHasClipboardData() const; + bool gvHasDefnClipboardData(QByteArray * data = nullptr) const; + bool gvHasValueClipboardData(QByteArray * data = nullptr) const; + bool gvDeleteAllowed() const; + bool gvInsertAllowed() const; + bool gvMoveDownAllowed() const; + bool gvMoveUpAllowed() const; + void gvSwapData(int idx1, int idx2); }; class FlightModesPanel : public ModelPanel diff --git a/companion/src/modeledit/inputs.cpp b/companion/src/modeledit/inputs.cpp index 27ca4c42f..a5220019e 100644 --- a/companion/src/modeledit/inputs.cpp +++ b/companion/src/modeledit/inputs.cpp @@ -47,18 +47,18 @@ InputsPanel::InputsPanel(QWidget *parent, ModelData & model, GeneralSettings & g qbClear->setText(tr("Clear All Inputs")); qbClear->setIcon(CompanionIcon("clear.png")); - exposLayout->addWidget(ExposlistWidget,1,1,1,3); - exposLayout->addWidget(qbUp,2,1); - exposLayout->addWidget(qbClear,2,2); - exposLayout->addWidget(qbDown,2,3); + exposLayout->addWidget(ExposlistWidget, 1, 1, 1, 3); + exposLayout->addWidget(qbUp, 2, 1); + exposLayout->addWidget(qbClear, 2, 2); + exposLayout->addWidget(qbDown, 2, 3); connect(ExposlistWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(expolistWidget_customContextMenuRequested(QPoint))); connect(ExposlistWidget, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(expolistWidget_doubleClicked(QModelIndex))); - connect(ExposlistWidget, SIGNAL(mimeDropped(int,const QMimeData*,Qt::DropAction)), this, SLOT(mimeExpoDropped(int, const QMimeData*, Qt::DropAction))); + connect(ExposlistWidget, SIGNAL(mimeDropped(int, const QMimeData*,Qt::DropAction)), this, SLOT(mimeExpoDropped(int, const QMimeData*, Qt::DropAction))); - connect(qbUp, SIGNAL(pressed()),SLOT(moveExpoUp())); - connect(qbDown, SIGNAL(pressed()),SLOT(moveExpoDown())); - connect(qbClear, SIGNAL(pressed()),SLOT(clearExpos())); + connect(qbUp, SIGNAL(pressed()), SLOT(moveExpoUp())); + connect(qbDown, SIGNAL(pressed()), SLOT(moveExpoDown())); + connect(qbClear, SIGNAL(pressed()), SLOT(clearExpos())); connect(ExposlistWidget, SIGNAL(keyWasPressed(QKeyEvent*)), this, SLOT(expolistWidget_KeyPress(QKeyEvent*))); } @@ -71,9 +71,9 @@ void InputsPanel::update() { lock = true; ExposlistWidget->clear(); - for (int i=0; i < inputsCount; ++i) { + for (int i = 0; i < inputsCount; ++i) { bool filled = false; - for (uint j=0; j < CPN_MAX_EXPOS; ++j) { + for (uint j = 0; j < CPN_MAX_EXPOS; ++j) { const ExpoData & ed = model->expoData[j]; if ((int)ed.chn == i && ed.mode) { AddInputLine(j); @@ -81,7 +81,7 @@ void InputsPanel::update() } } if (!filled) { - AddInputLine(-i-1); + AddInputLine(-i - 1); } } lock = false; @@ -108,9 +108,8 @@ void InputsPanel::AddInputLine(int dest) const ExpoData &md = model->expoData[dest]; qba.append((const char*)&md, sizeof(ExpoData)); destId = md.chn + 1; - const QVector expos = model->expos(md.chn); - newChan = (expos.constFirst() == &md); - hasSibs = (expos.constLast() != &md); + newChan = model->isExpoParent(dest); + hasSibs = (model->hasExpoChildren(dest) || model->hasExpoSiblings(dest)); } QListWidgetItem *itm = new QListWidgetItem(getInputText(dest, newChan)); itm->setData(Qt::UserRole, qba); @@ -133,10 +132,10 @@ QString InputsPanel::getInputText(int dest, bool newChan) { QString str; if (dest < 0) { - str = modelPrinter.printInputName(-dest-1); + str = modelPrinter.printInputName(-dest - 1); } else { - const ExpoData & input = model->expoData[dest]; + const ExpoData &input = model->expoData[dest]; const int nameChars = (firmware->getCapability(VirtualInputs) ? 10 : 4); if (newChan) str = QString("%1").arg(modelPrinter.printInputName(input.chn), -nameChars, QChar(' ')); @@ -150,14 +149,14 @@ QString InputsPanel::getInputText(int dest, bool newChan) bool InputsPanel::gm_insertExpo(int idx) { - if (idx<0 || idx>=CPN_MAX_EXPOS || model->expoData[CPN_MAX_EXPOS-1].mode > 0) { - QMessageBox::information(this, CPN_STR_APP_NAME, tr("Not enough available inputs!")); + if (idx < 0 || idx >= CPN_MAX_EXPOS || model->expoData[CPN_MAX_EXPOS-1].mode > 0) { + QMessageBox::information(this, CPN_STR_APP_NAME, tr("Not enough available Inputs!")); return false; } int chn = model->expoData[idx].chn; - ExpoData * newExpo = model->insertInput(idx); + ExpoData *newExpo = model->insertInput(idx); newExpo->chn = chn; newExpo->weight = 100; newExpo->mode = INPUT_MODE_BOTH; @@ -172,107 +171,107 @@ void InputsPanel::gm_deleteExpo(int index, bool clearName) void InputsPanel::gm_openExpo(int index) { - if(index<0 || index>=CPN_MAX_EXPOS) return; + if (index < 0 || index >= CPN_MAX_EXPOS) + return; - ExpoData mixd(model->expoData[index]); + ExpoData ed(model->expoData[index]); - QString inputName; + QString inputName; + if (firmware->getCapability(VirtualInputs)) + inputName = model->inputNames[ed.chn]; + + ExpoDialog *g = new ExpoDialog(this, *model, &ed, generalSettings, firmware, inputName); + if (g->exec()) { + model->expoData[index] = ed; if (firmware->getCapability(VirtualInputs)) - inputName = model->inputNames[mixd.chn]; - - ExpoDialog *g = new ExpoDialog(this, *model, &mixd, generalSettings, firmware, inputName); - if (g->exec()) { - model->expoData[index] = mixd; - if (firmware->getCapability(VirtualInputs)) - strncpy(model->inputNames[mixd.chn], inputName.toLatin1().data(), 4); - emit modified(); - update(); - } - else { - if (expoInserted) { - gm_deleteExpo(index); - } - expoInserted=false; - update(); + strncpy(model->inputNames[ed.chn], inputName.toLatin1().data(), INPUT_NAME_LEN); + emit modified(); + update(); + } + else { + if (expoInserted) { + gm_deleteExpo(index); } + expoInserted=false; + update(); + } } int InputsPanel::getExpoIndex(unsigned int dch) { - unsigned int i = 0; - while (model->expoData[i].chn<=dch && model->expoData[i].mode && iexpoData[i].chn <= dch && model->expoData[i].mode && i < CPN_MAX_EXPOS) + i++; + if (i == CPN_MAX_EXPOS) + return -1; + return i; } - QList InputsPanel::createExpoListFromSelected() { - QList list; - foreach(QListWidgetItem *item, ExposlistWidget->selectedItems()) { - int idx= item->data(Qt::UserRole).toByteArray().at(0); - if(idx>=0 && idx list; + foreach (QListWidgetItem *item, ExposlistWidget->selectedItems()) { + int idx = item->data(Qt::UserRole).toByteArray().at(0); + if (idx >= 0 && idx < CPN_MAX_EXPOS) + list << idx; + } + return list; } - void InputsPanel::setSelectedByExpoList(QList list) { - for(int i=0; icount(); i++) { - int t = ExposlistWidget->item(i)->data(Qt::UserRole).toByteArray().at(0); - if(list.contains(t)) - ExposlistWidget->item(i)->setSelected(true); - } + for (int i = 0; i < ExposlistWidget->count(); i++) { + int t = ExposlistWidget->item(i)->data(Qt::UserRole).toByteArray().at(0); + if (list.contains(t)) + ExposlistWidget->item(i)->setSelected(true); + } } void InputsPanel::exposDelete(bool ask) { - QList list = createExpoListFromSelected(); - if(list.isEmpty()) return; + QList list = createExpoListFromSelected(); + if (list.isEmpty()) + return; - QMessageBox::StandardButton ret = QMessageBox::No; + QMessageBox::StandardButton ret = QMessageBox::No; - if(ask) - ret = QMessageBox::warning(this, "companion", - tr("Delete Selected Inputs?"), - QMessageBox::Yes | 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 ((ret == QMessageBox::Yes) || (!ask)) { + exposDeleteList(list, ask); + emit modified(); + update(); + } } void InputsPanel::exposCut() { - exposCopy(); - exposDelete(false); + exposCopy(); + exposDelete(false); } void InputsPanel::exposCopy() { - QList list = createExpoListFromSelected(); + QList list = createExpoListFromSelected(); - QByteArray mxData; - foreach(int idx, list) { - mxData.append((char*)&model->expoData[idx], sizeof(ExpoData)); - } + QByteArray exData; + foreach (int idx, list) { + exData.append((char*)&model->expoData[idx], sizeof(ExpoData)); + } - QMimeData *mimeData = new QMimeData; - mimeData->setData("application/x-companion-expo", mxData); - QApplication::clipboard()->setMimeData(mimeData,QClipboard::Clipboard); + QMimeData *mimeData = new QMimeData; + mimeData->setData(MIMETYPE_EXPO, exData); + QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard); } void InputsPanel::mimeExpoDropped(int index, const QMimeData *data, Qt::DropAction action) { int idx = ExposlistWidget->item(index)->data(Qt::UserRole).toByteArray().at(0); - if (action==Qt::CopyAction) { + if (action == Qt::CopyAction) { pasteExpoMimeData(data, idx); } - else if (action==Qt::MoveAction) { + else if (action == Qt::MoveAction) { QList list = createExpoListFromSelected(); exposDeleteList(list, false); foreach (const int del, list) { @@ -285,30 +284,31 @@ void InputsPanel::mimeExpoDropped(int index, const QMimeData *data, Qt::DropActi void InputsPanel::pasteExpoMimeData(const QMimeData * mimeData, int destIdx) { - if (mimeData->hasFormat("application/x-companion-expo")) { - int idx; // mixer index + if (mimeData->hasFormat(MIMETYPE_EXPO)) { + int idx; // expo index int dch; if (destIdx < 0) { dch = -destIdx - 1; idx = getExpoIndex(dch) - 1; //get expo index to insert - } else { + } + else { idx = destIdx; dch = model->expoData[idx].chn; } - QByteArray mxData = mimeData->data("application/x-companion-expo"); + QByteArray exData = mimeData->data(MIMETYPE_EXPO); int i = 0; - while (i < mxData.size()) { + while (i < exData.size()) { idx++; if (!gm_insertExpo(idx)) break; - ExpoData *md = &model->expoData[idx]; - memcpy(md, mxData.mid(i, sizeof(ExpoData)).constData(), sizeof(ExpoData)); - const int oldChan = md->chn; - md->chn = dch; - maybeCopyInputName(oldChan, md->chn); + ExpoData *ed = &model->expoData[idx]; + memcpy(ed, exData.mid(i, sizeof(ExpoData)).constData(), sizeof(ExpoData)); + const int oldChan = ed->chn; + ed->chn = dch; + maybeCopyInputName(oldChan, ed->chn); i += sizeof(ExpoData); } @@ -334,83 +334,104 @@ void InputsPanel::exposDuplicate() exposPaste(); } - void InputsPanel::expoOpen(QListWidgetItem *item) { - if (!item) - item = ExposlistWidget->currentItem(); + if (!item) + item = ExposlistWidget->currentItem(); - int idx = item->data(Qt::UserRole).toByteArray().at(0); - if (idx<0) { - int ch = -idx-1; - idx = getExpoIndex(ch); // get expo index to insert - if (!gm_insertExpo(idx)) - return; - model->expoData[idx].chn = ch; - expoInserted=true; - } else { - expoInserted=false; - } - gm_openExpo(idx); + int idx = item->data(Qt::UserRole).toByteArray().at(0); + if (idx < 0) { + int ch = -idx - 1; + idx = getExpoIndex(ch); // get expo index to insert + if (!gm_insertExpo(idx)) + return; + model->expoData[idx].chn = ch; + expoInserted = true; + } + else { + expoInserted = false; + } + gm_openExpo(idx); } void InputsPanel::expoAdd() { - int index = ExposlistWidget->currentItem()->data(Qt::UserRole).toByteArray().at(0); + int index = ExposlistWidget->currentItem()->data(Qt::UserRole).toByteArray().at(0); - if(index<0) { // if empty then return relevant index - expoOpen(); - } else { - index++; - if (!gm_insertExpo(index)) - return; - model->expoData[index].chn = model->expoData[index-1].chn; - expoInserted=true; - } - gm_openExpo(index); + if (index < 0) { // if empty then return relevant index + expoOpen(); + } + else { + index++; + if (!gm_insertExpo(index)) + return; + model->expoData[index].chn = model->expoData[index-1].chn; + expoInserted = true; + } + gm_openExpo(index); } void InputsPanel::expolistWidget_customContextMenuRequested(QPoint pos) { - QPoint globalPos = ExposlistWidget->mapToGlobal(pos); + QPoint globalPos = ExposlistWidget->mapToGlobal(pos); - const QClipboard *clipboard = QApplication::clipboard(); - const QMimeData *mimeData = clipboard->mimeData(); - bool hasData = mimeData->hasFormat("application/x-companion-expo"); + const QClipboard *clipboard = QApplication::clipboard(); + const QMimeData *mimeData = clipboard->mimeData(); + bool hasData = mimeData->hasFormat(MIMETYPE_EXPO); - QMenu contextMenu; - contextMenu.addAction(CompanionIcon("add.png"), tr("&Add"),this,SLOT(expoAdd()),tr("Ctrl+A")); - contextMenu.addAction(CompanionIcon("edit.png"), tr("&Edit"),this,SLOT(expoOpen()),tr("Enter")); - contextMenu.addSeparator(); - contextMenu.addAction(CompanionIcon("clear.png"), tr("&Delete"),this,SLOT(exposDelete()),tr("Delete")); - contextMenu.addAction(CompanionIcon("copy.png"), tr("&Copy"),this,SLOT(exposCopy()),tr("Ctrl+C")); - contextMenu.addAction(CompanionIcon("cut.png"), tr("&Cut"),this,SLOT(exposCut()),tr("Ctrl+X")); - contextMenu.addAction(CompanionIcon("paste.png"), tr("&Paste"),this,SLOT(exposPaste()),tr("Ctrl+V"))->setEnabled(hasData); - contextMenu.addAction(CompanionIcon("duplicate.png"), tr("Du&plicate"),this,SLOT(exposDuplicate()),tr("Ctrl+U")); - contextMenu.addSeparator(); - contextMenu.addAction(CompanionIcon("moveup.png"), tr("Move Up"),this,SLOT(moveExpoUp()),tr("Ctrl+Up")); - contextMenu.addAction(CompanionIcon("movedown.png"), tr("Move Down"),this,SLOT(moveExpoDown()),tr("Ctrl+Down")); - contextMenu.addSeparator(); - contextMenu.addActions(ExposlistWidget->actions()); + selectedIdx = getIndexFromSelected(); + inputIdx = getInputIndexFromSelected(); - contextMenu.exec(globalPos); + QMenu contextMenu; + QMenu *contextMenuLines = contextMenu.addMenu(tr("Lines")); + contextMenuLines->addAction(CompanionIcon("add.png"), tr("&Add"), this, SLOT(expoAdd()), tr("Ctrl+A")); + contextMenuLines->addAction(CompanionIcon("edit.png"), tr("&Edit"), this, SLOT(expoOpen()), tr("Enter")); + contextMenuLines->addSeparator(); + contextMenuLines->addAction(CompanionIcon("clear.png"), tr("&Delete"), this, SLOT(exposDelete()), tr("Delete")); + contextMenuLines->addAction(CompanionIcon("copy.png"), tr("&Copy"), this, SLOT(exposCopy()), tr("Ctrl+C")); + contextMenuLines->addAction(CompanionIcon("cut.png"), tr("&Cut"), this, SLOT(exposCut()), tr("Ctrl+X")); + contextMenuLines->addAction(CompanionIcon("paste.png"), tr("&Paste"), this, SLOT(exposPaste()), tr("Ctrl+V"))->setEnabled(hasData); + contextMenuLines->addAction(CompanionIcon("duplicate.png"), tr("Du&plicate"), this, SLOT(exposDuplicate()), tr("Ctrl+U")); + contextMenuLines->addSeparator(); + contextMenuLines->addAction(CompanionIcon("moveup.png"), tr("Move Up"), this, SLOT(moveExpoUp()), tr("Ctrl+Up")); + contextMenuLines->addAction(CompanionIcon("movedown.png"), tr("Move Down"), this, SLOT(moveExpoDown()), tr("Ctrl+Down")); + + QMenu *contextMenuInputs = contextMenu.addMenu(tr("Input")); + contextMenuInputs->addAction(CompanionIcon("arrow-right.png"), tr("Insert"), this, SLOT(cmInputInsert()))->setEnabled(cmInputInsertAllowed()); + contextMenuInputs->addAction(CompanionIcon("arrow-left.png"), tr("Delete"), this, SLOT(cmInputDelete())); + contextMenuInputs->addAction(CompanionIcon("moveup.png"), tr("Move Up"), this, SLOT(cmInputMoveUp()))->setEnabled(cmInputMoveUpAllowed()); + contextMenuInputs->addAction(CompanionIcon("movedown.png"), tr("Move Down"), this, SLOT(cmInputMoveDown()))->setEnabled(cmInputMoveDownAllowed()); + contextMenuInputs->addSeparator(); + contextMenuInputs->addAction(CompanionIcon("clear.png"), tr("Clear"), this, SLOT(cmInputClear()))->setEnabled(isExpoIndex(selectedIdx)); + + contextMenu.addSeparator(); + contextMenu.addAction(CompanionIcon("clear.png"), tr("Clear All"), this, SLOT(clearExpos())); + contextMenu.addSeparator(); + contextMenu.addActions(ExposlistWidget->actions()); + contextMenu.exec(globalPos); } - void InputsPanel::expolistWidget_KeyPress(QKeyEvent *event) { - if(event->matches(QKeySequence::SelectAll)) expoAdd(); //Ctrl A - if(event->matches(QKeySequence::Delete)) exposDelete(); - if(event->matches(QKeySequence::Copy)) exposCopy(); - if(event->matches(QKeySequence::Cut)) exposCut(); - if(event->matches(QKeySequence::Paste)) exposPaste(); - if(event->matches(QKeySequence::Underline)) exposDuplicate(); + if (event->matches(QKeySequence::SelectAll)) + expoAdd(); //Ctrl A + if (event->matches(QKeySequence::Delete)) + exposDelete(); + if (event->matches(QKeySequence::Copy)) + exposCopy(); + if (event->matches(QKeySequence::Cut)) + exposCut(); + if (event->matches(QKeySequence::Paste)) + exposPaste(); + if (event->matches(QKeySequence::Underline)) + exposDuplicate(); - if(event->key()==Qt::Key_Return || event->key()==Qt::Key_Enter) expoOpen(); - if(event->matches(QKeySequence::MoveToNextLine)) - ExposlistWidget->setCurrentRow(ExposlistWidget->currentRow()+1); - if(event->matches(QKeySequence::MoveToPreviousLine)) - ExposlistWidget->setCurrentRow(ExposlistWidget->currentRow()-1); + if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) + expoOpen(); + if (event->matches(QKeySequence::MoveToNextLine)) + ExposlistWidget->setCurrentRow(ExposlistWidget->currentRow() + 1); + if (event->matches(QKeySequence::MoveToPreviousLine)) + ExposlistWidget->setCurrentRow(ExposlistWidget->currentRow() - 1); } int InputsPanel::gm_moveExpo(int idx, bool dir) //true=inc=down false=dec=up @@ -418,7 +439,7 @@ int InputsPanel::gm_moveExpo(int idx, bool dir) //true=inc=down false=dec=up if (idx >= CPN_MAX_EXPOS || idx < 0 || (dir && idx >= CPN_MAX_EXPOS - 1) || (!dir && !idx)) return -1; - const int tdx = dir ? idx+1 : idx-1; + const int tdx = dir ? idx + 1 : idx-1; ExpoData temp; ExpoData &src = model->expoData[idx]; ExpoData &tgt = model->expoData[tdx]; @@ -432,7 +453,7 @@ int InputsPanel::gm_moveExpo(int idx, bool dir) //true=inc=down false=dec=up if (tgt.chn != src.chn || tgtempty) { const int oldChan = src.chn; - if (dir && src.chn < unsigned(inputsCount-1)) + if (dir && src.chn < unsigned(inputsCount - 1)) src.chn++; else if (!dir && src.chn > 0) src.chn--; @@ -452,7 +473,7 @@ void InputsPanel::moveExpoList(bool down) QList list = createExpoListFromSelected(); QList highlightList; bool mod = false; - foreach(int idx, list) { + foreach (int idx, list) { const int newIdx = gm_moveExpo(idx, down); if (newIdx > -1) { highlightList << newIdx; @@ -483,19 +504,22 @@ void InputsPanel::expolistWidget_doubleClicked(QModelIndex index) void InputsPanel::exposDeleteList(QList list, bool clearName) { - std::sort(list.begin(), list.end()); + std::sort(list.begin(), list.end()); - int iDec = 0; - foreach(int idx, list) { - gm_deleteExpo(idx-iDec, clearName); - iDec++; - } + int iDec = 0; + foreach (int idx, list) { + gm_deleteExpo(idx-iDec, clearName); + iDec++; + } } void InputsPanel::clearExpos() { - if (QMessageBox::question(this, tr("Clear Inputs?"), tr("Really clear all the inputs?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { + if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear all Inputs. 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(); } @@ -512,8 +536,172 @@ void InputsPanel::maybeCopyInputName(int srcChan, int destChan) if (srcEmpty) { // if destination input name is empty, copy it from source expo input if (!strlen(model->inputNames[destChan])) - strncpy(model->inputNames[destChan], model->inputNames[srcChan], 5); + strncpy(model->inputNames[destChan], model->inputNames[srcChan], INPUT_NAME_LEN); // clear the emptry source channel name model->inputNames[srcChan][0] = 0; } } + +bool InputsPanel::cmInputInsertAllowed() const +{ + return ((!model->hasExpos(inputsCount - 1)) && (inputIdx < inputsCount - 1)); +} + +bool InputsPanel::cmInputMoveDownAllowed() const +{ + return (inputIdx >= 0 && (inputIdx < inputsCount - 1)); +} + +bool InputsPanel::cmInputMoveUpAllowed() const +{ + return inputIdx > 0; +} + +void InputsPanel::cmInputClear() +{ + if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear 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); + } + model->updateAllReferences(ModelData::REF_UPD_TYPE_INPUT, ModelData::REF_UPD_ACT_CLEAR, inputIdx); + update(); + 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) + return; + + for (int i = 0; i < CPN_MAX_EXPOS; i++) { + ExpoData *ed = &model->expoData[i]; + if ((int)ed->chn == inputIdx) + model->removeInput(i); + else if ((int)ed->chn > inputIdx) + ed->chn--; + } + + for (int i = inputIdx; i < inputsCount; i++) { + strncpy(model->inputNames[i], model->inputNames[i + 1], sizeof(model->inputNames[i]) - 1); + } + model->inputNames[inputsCount - 1][0] = 0; + + model->updateAllReferences(ModelData::REF_UPD_TYPE_INPUT, ModelData::REF_UPD_ACT_SHIFT, inputIdx, 0, -1); + update(); + emit modified(); +} + +void InputsPanel::cmInputInsert() +{ + for (int i = 0; i < CPN_MAX_EXPOS; i++) { + ExpoData *ed = &model->expoData[i]; + if ((int)ed->chn >= inputIdx) + ed->chn++; + } + + for (int i = inputsCount - 1; i > inputIdx; i--) { + strncpy(model->inputNames[i], model->inputNames[i - 1], sizeof(model->inputNames[i]) - 1); + } + model->inputNames[inputIdx][0] = 0; + + model->updateAllReferences(ModelData::REF_UPD_TYPE_INPUT, ModelData::REF_UPD_ACT_SHIFT, inputIdx, 0, 1); + update(); + emit modified(); +} + +void InputsPanel::cmInputMoveDown() +{ + cmInputSwapData(inputIdx, inputIdx + 1); +} + +void InputsPanel::cmInputMoveUp() +{ + cmInputSwapData(inputIdx - 1, inputIdx); +} + +void InputsPanel::cmInputSwapData(int idx1, int idx2) +{ + if (idx1 >= idx2 || (!model->hasExpos(idx1) && !model->hasExpos(idx2))) + return; + // save expos + int expoidx = -1; + QVector edtmp; + int i; + for (i = 0; i < CPN_MAX_EXPOS; i++) { + ExpoData *ed = &model->expoData[i]; + if ((int)ed->chn == idx1) { + edtmp << model->expoData[i]; + if (expoidx < 0) + expoidx = i; + } + else if ((int)ed->chn > idx1) + break; + } + // move expos up + const int offset = i - expoidx; + int expocnt; + for (int j = i; j < CPN_MAX_EXPOS; j++) { + ExpoData *ed = &model->expoData[j]; + if ((int)ed->chn == idx2) { + ExpoData *dest = &model->expoData[j - offset]; + memcpy(dest, &model->expoData[j], sizeof(ExpoData)); + dest->chn = idx1; + expocnt++; + } + else if ((int)ed->chn > idx2) + break; + } + // copy back saved expos + int cnt = 0; + foreach (ExpoData ed, edtmp) { + ExpoData *dest = &model->expoData[expoidx + expocnt + cnt]; + memcpy(dest, &ed, sizeof(ExpoData)); + dest->chn = idx2; + cnt++; + } + + // swap names + QByteArray *tname = new QByteArray(model->inputNames[idx2]); + strncpy(model->inputNames[idx2], model->inputNames[idx1], sizeof(model->inputNames[idx2]) - 1); + strncpy(model->inputNames[idx1], tname->data(), sizeof(model->inputNames[idx1]) - 1); + + model->updateAllReferences(ModelData::REF_UPD_TYPE_INPUT, ModelData::REF_UPD_ACT_SWAP, idx1, idx2); + update(); + emit modified(); +} + +bool InputsPanel::isInputIndex(const int index) +{ + if (index < 0) + return true; + else + return false; +} + +bool InputsPanel::isExpoIndex(const int index) +{ + return !isInputIndex(index); +} + +int InputsPanel::getIndexFromSelected() +{ + return ExposlistWidget->currentItem()->data(Qt::UserRole).toByteArray().at(0); +} + +int InputsPanel::getInputIndexFromSelected() +{ + const int selidx = getIndexFromSelected(); + int idx; + + if (isInputIndex(selidx)) + idx = -selidx - 1; + else { + const ExpoData *ed = &model->expoData[selidx]; + idx = ed->chn; + } + return idx; +} diff --git a/companion/src/modeledit/inputs.h b/companion/src/modeledit/inputs.h index 939d0a647..884573fef 100644 --- a/companion/src/modeledit/inputs.h +++ b/companion/src/modeledit/inputs.h @@ -25,6 +25,8 @@ #include "mixerslistwidget.h" #include "modelprinter.h" +constexpr char MIMETYPE_EXPO[] = "application/x-companion-expo"; + class InputsPanel : public ModelPanel { Q_OBJECT @@ -52,12 +54,19 @@ class InputsPanel : public ModelPanel void expoOpen(QListWidgetItem *item = NULL); void expoAdd(); void maybeCopyInputName(int srcChan, int destChan); + void cmInputClear(); + void cmInputDelete(); + void cmInputInsert(); + void cmInputMoveDown(); + void cmInputMoveUp(); private: bool expoInserted; MixersListWidget *ExposlistWidget; int inputsCount; ModelPrinter modelPrinter; + int selectedIdx; + int inputIdx; int getExpoIndex(unsigned int dch); bool gm_insertExpo(int idx); @@ -70,7 +79,14 @@ class InputsPanel : public ModelPanel void pasteExpoMimeData(const QMimeData * mimeData, int destIdx); void AddInputLine(int dest); QString getInputText(int dest, bool newChan); - + bool cmInputInsertAllowed() const; + bool cmInputMoveDownAllowed() const; + bool cmInputMoveUpAllowed() const; + void cmInputSwapData(int idx1, int idx2); + bool isInputIndex(const int index); + bool isExpoIndex(const int index); + int getIndexFromSelected(); + int getInputIndexFromSelected(); }; #endif // _INPUTS_H_ diff --git a/companion/src/modeledit/logicalswitches.cpp b/companion/src/modeledit/logicalswitches.cpp index 81f2f52e7..13e20b8f6 100644 --- a/companion/src/modeledit/logicalswitches.cpp +++ b/companion/src/modeledit/logicalswitches.cpp @@ -26,7 +26,7 @@ LogicalSwitchesPanel::LogicalSwitchesPanel(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware): ModelPanel(parent, model, generalSettings, firmware), - selectedSwitch(0) + selectedIndex(0) { Stopwatch s1("LogicalSwitchesPanel"); @@ -35,19 +35,22 @@ LogicalSwitchesPanel::LogicalSwitchesPanel(QWidget * parent, ModelData & model, const int srcGroups = firmware->getCapability(GvarsInCS) ? 0 : (RawSource::AllSourceGroups & ~RawSource::GVarsGroup); rawSourceItemModel = new RawSourceFilterItemModel(&generalSettings, &model, srcGroups, this); + lsCapability = firmware->getCapability(LogicalSwitches); + lsCapabilityExt = firmware->getCapability(LogicalSwitchesExt); + QStringList headerLabels; headerLabels << "#" << tr("Function") << tr("V1") << tr("V2") << tr("AND Switch"); - if (firmware->getCapability(LogicalSwitchesExt)) { + if (lsCapabilityExt) { headerLabels << tr("Duration") << tr("Delay"); } - TableLayout * tableLayout = new TableLayout(this, firmware->getCapability(LogicalSwitches), headerLabels); + TableLayout * tableLayout = new TableLayout(this, lsCapability, headerLabels); s1.report("header"); const int channelsMax = model.getChannelsMax(true); lock = true; - for (int i=0; igetCapability(LogicalSwitches); i++) { + for (int i=0; isetProperty("index", i); @@ -56,96 +59,96 @@ LogicalSwitchesPanel::LogicalSwitchesPanel(QWidget * parent, ModelData & model, label->setToolTip(tr("Popup menu available")); label->setMouseTracking(true); label->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum); - connect(label, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(csw_customContextMenuRequested(QPoint))); + connect(label, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(onCustomContextMenuRequested(QPoint))); tableLayout->addWidget(i, 0, label); // The function - csw[i] = new QComboBox(this); - csw[i]->setProperty("index", i); - populateCSWCB(csw[i]); - connect(csw[i], SIGNAL(currentIndexChanged(int)), this, SLOT(functionChanged())); - tableLayout->addWidget(i, 1, csw[i]); + cbFunction[i] = new QComboBox(this); + cbFunction[i]->setProperty("index", i); + populateFunctionCB(cbFunction[i]); + connect(cbFunction[i], SIGNAL(currentIndexChanged(int)), this, SLOT(onFunctionChanged())); + tableLayout->addWidget(i, 1, cbFunction[i]); // V1 QHBoxLayout *v1Layout = new QHBoxLayout(); - cswitchSource1[i] = new QComboBox(this); - cswitchSource1[i]->setProperty("index",i); - connect(cswitchSource1[i], SIGNAL(currentIndexChanged(int)), this, SLOT(v1Edited(int))); - v1Layout->addWidget(cswitchSource1[i]); - cswitchSource1[i]->setVisible(false); - cswitchValue[i] = new QDoubleSpinBox(this); - cswitchValue[i]->setMaximum(channelsMax); - cswitchValue[i]->setMinimum(-channelsMax); - cswitchValue[i]->setAccelerated(true); - cswitchValue[i]->setDecimals(0); - cswitchValue[i]->setProperty("index", i); - connect(cswitchValue[i], SIGNAL(editingFinished()), this, SLOT(offsetEdited())); - v1Layout->addWidget(cswitchValue[i]); - cswitchValue[i]->setVisible(false); + cbSource1[i] = new QComboBox(this); + cbSource1[i]->setProperty("index",i); + connect(cbSource1[i], SIGNAL(currentIndexChanged(int)), this, SLOT(onV1Changed(int))); + v1Layout->addWidget(cbSource1[i]); + cbSource1[i]->setVisible(false); + dsbValue[i] = new QDoubleSpinBox(this); + dsbValue[i]->setMaximum(channelsMax); + dsbValue[i]->setMinimum(-channelsMax); + dsbValue[i]->setAccelerated(true); + dsbValue[i]->setDecimals(0); + dsbValue[i]->setProperty("index", i); + connect(dsbValue[i], SIGNAL(editingFinished()), this, SLOT(onOffsetChanged())); + v1Layout->addWidget(dsbValue[i]); + dsbValue[i]->setVisible(false); tableLayout->addLayout(i, 2, v1Layout); // V2 QHBoxLayout *v2Layout = new QHBoxLayout(); - cswitchSource2[i] = new QComboBox(this); - cswitchSource2[i]->setProperty("index", i); - connect(cswitchSource2[i], SIGNAL(currentIndexChanged(int)), this, SLOT(v2Edited(int))); - v2Layout->addWidget(cswitchSource2[i]); - cswitchSource2[i]->setVisible(false); - cswitchOffset[i] = new QDoubleSpinBox(this); - cswitchOffset[i]->setProperty("index",i); - cswitchOffset[i]->setMaximum(channelsMax); - cswitchOffset[i]->setMinimum(-channelsMax); - cswitchOffset[i]->setAccelerated(true); - cswitchOffset[i]->setDecimals(0); - connect(cswitchOffset[i], SIGNAL(editingFinished()), this, SLOT(offsetEdited())); - cswitchOffset[i]->setVisible(false); - v2Layout->addWidget(cswitchOffset[i]); - cswitchOffset2[i] = new QDoubleSpinBox(this); - cswitchOffset2[i]->setProperty("index",i); - cswitchOffset2[i]->setMaximum(channelsMax); - cswitchOffset2[i]->setMinimum(-channelsMax); - cswitchOffset2[i]->setAccelerated(true); - cswitchOffset2[i]->setDecimals(0); - cswitchOffset2[i]->setSpecialValueText(" " + tr("(instant)")); - connect(cswitchOffset2[i], SIGNAL(editingFinished()), this, SLOT(offsetEdited())); - cswitchOffset2[i]->setVisible(false); - v2Layout->addWidget(cswitchOffset2[i]); - cswitchTOffset[i] = new TimerEdit(this); - cswitchTOffset[i]->setProperty("index",i); - connect(cswitchTOffset[i],SIGNAL(editingFinished()),this,SLOT(offsetEdited())); - v2Layout->addWidget(cswitchTOffset[i]); - cswitchTOffset[i]->setVisible(false); + cbSource2[i] = new QComboBox(this); + cbSource2[i]->setProperty("index", i); + connect(cbSource2[i], SIGNAL(currentIndexChanged(int)), this, SLOT(onV2Changed(int))); + v2Layout->addWidget(cbSource2[i]); + cbSource2[i]->setVisible(false); + dsbOffset[i] = new QDoubleSpinBox(this); + dsbOffset[i]->setProperty("index",i); + dsbOffset[i]->setMaximum(channelsMax); + dsbOffset[i]->setMinimum(-channelsMax); + dsbOffset[i]->setAccelerated(true); + dsbOffset[i]->setDecimals(0); + connect(dsbOffset[i], SIGNAL(editingFinished()), this, SLOT(onOffsetChanged())); + dsbOffset[i]->setVisible(false); + v2Layout->addWidget(dsbOffset[i]); + dsbOffset2[i] = new QDoubleSpinBox(this); + dsbOffset2[i]->setProperty("index",i); + dsbOffset2[i]->setMaximum(channelsMax); + dsbOffset2[i]->setMinimum(-channelsMax); + dsbOffset2[i]->setAccelerated(true); + dsbOffset2[i]->setDecimals(0); + dsbOffset2[i]->setSpecialValueText(" " + tr("(instant)")); + connect(dsbOffset2[i], SIGNAL(editingFinished()), this, SLOT(onOffsetChanged())); + dsbOffset2[i]->setVisible(false); + v2Layout->addWidget(dsbOffset2[i]); + teOffset[i] = new TimerEdit(this); + teOffset[i]->setProperty("index",i); + connect(teOffset[i],SIGNAL(editingFinished()),this,SLOT(onOffsetChanged())); + v2Layout->addWidget(teOffset[i]); + teOffset[i]->setVisible(false); tableLayout->addLayout(i, 3, v2Layout); // AND - cswitchAnd[i] = new QComboBox(this); - cswitchAnd[i]->setProperty("index", i); - populateAndSwitchCB(cswitchAnd[i]); - connect(cswitchAnd[i], SIGNAL(currentIndexChanged(int)), this, SLOT(andEdited(int))); - tableLayout->addWidget(i, 4, cswitchAnd[i]); + cbAndSwitch[i] = new QComboBox(this); + cbAndSwitch[i]->setProperty("index", i); + populateAndSwitchCB(cbAndSwitch[i]); + connect(cbAndSwitch[i], SIGNAL(currentIndexChanged(int)), this, SLOT(onAndSwitchChanged(int))); + tableLayout->addWidget(i, 4, cbAndSwitch[i]); - if (firmware->getCapability(LogicalSwitchesExt)) { + if (lsCapabilityExt) { // Duration - cswitchDuration[i] = new QDoubleSpinBox(this); - cswitchDuration[i]->setProperty("index", i); - cswitchDuration[i]->setSingleStep(0.1); - cswitchDuration[i]->setMaximum(25); - cswitchDuration[i]->setMinimum(0); - cswitchDuration[i]->setAccelerated(true); - cswitchDuration[i]->setDecimals(1); - connect(cswitchDuration[i], SIGNAL(valueChanged(double)), this, SLOT(durationEdited(double))); - tableLayout->addWidget(i, 5, cswitchDuration[i]); + dsbDuration[i] = new QDoubleSpinBox(this); + dsbDuration[i]->setProperty("index", i); + dsbDuration[i]->setSingleStep(0.1); + dsbDuration[i]->setMaximum(25); + dsbDuration[i]->setMinimum(0); + dsbDuration[i]->setAccelerated(true); + dsbDuration[i]->setDecimals(1); + connect(dsbDuration[i], SIGNAL(valueChanged(double)), this, SLOT(onDurationChanged(double))); + tableLayout->addWidget(i, 5, dsbDuration[i]); // Delay - cswitchDelay[i] = new QDoubleSpinBox(this); - cswitchDelay[i]->setProperty("index", i); - cswitchDelay[i]->setSingleStep(0.1); - cswitchDelay[i]->setMaximum(25); - cswitchDelay[i]->setMinimum(0); - cswitchDelay[i]->setAccelerated(true); - cswitchDelay[i]->setDecimals(1); - connect(cswitchDelay[i], SIGNAL(valueChanged(double)), this, SLOT(delayEdited(double))); - tableLayout->addWidget(i, 6, cswitchDelay[i]); + dsbDelay[i] = new QDoubleSpinBox(this); + dsbDelay[i]->setProperty("index", i); + dsbDelay[i]->setSingleStep(0.1); + dsbDelay[i]->setMaximum(25); + dsbDelay[i]->setMinimum(0); + dsbDelay[i]->setAccelerated(true); + dsbDelay[i]->setDecimals(1); + connect(dsbDelay[i], SIGNAL(valueChanged(double)), this, SLOT(onDelayChanged(double))); + tableLayout->addWidget(i, 6, dsbDelay[i]); } } @@ -155,7 +158,7 @@ LogicalSwitchesPanel::LogicalSwitchesPanel(QWidget * parent, ModelData & model, lock = false; update(); tableLayout->resizeColumnsToContents(); - tableLayout->pushRowsUp(firmware->getCapability(LogicalSwitches)+1); + tableLayout->pushRowsUp(lsCapability+1); s1.report("end"); } @@ -172,10 +175,10 @@ void LogicalSwitchesPanel::updateDataModels() lock = oldLock; } -void LogicalSwitchesPanel::functionChanged() +void LogicalSwitchesPanel::onFunctionChanged() { int i = sender()->property("index").toInt(); - unsigned newFunc = csw[i]->currentData().toUInt(); + unsigned newFunc = cbFunction[i]->currentData().toUInt(); if (model->logicalSw[i].func == newFunc) return; @@ -204,13 +207,13 @@ void LogicalSwitchesPanel::functionChanged() emit modified(); } -void LogicalSwitchesPanel::v1Edited(int value) +void LogicalSwitchesPanel::onV1Changed(int value) { if (!lock) { int i = sender()->property("index").toInt(); - model->logicalSw[i].val1 = cswitchSource1[i]->itemData(value).toInt(); + model->logicalSw[i].val1 = cbSource1[i]->itemData(value).toInt(); if (model->logicalSw[i].getFunctionFamily() == LS_FAMILY_VOFS) { - if (!offsetEditedAt(i)) + if (!offsetChangedAt(i)) updateLine(i); } else { @@ -219,25 +222,25 @@ void LogicalSwitchesPanel::v1Edited(int value) } } -void LogicalSwitchesPanel::v2Edited(int value) +void LogicalSwitchesPanel::onV2Changed(int value) { if (!lock) { int i = sender()->property("index").toInt(); - model->logicalSw[i].val2 = cswitchSource2[i]->itemData(value).toInt(); + model->logicalSw[i].val2 = cbSource2[i]->itemData(value).toInt(); emit modified(); } } -void LogicalSwitchesPanel::andEdited(int value) +void LogicalSwitchesPanel::onAndSwitchChanged(int value) { if (!lock) { int index = sender()->property("index").toInt(); - model->logicalSw[index].andsw = cswitchAnd[index]->itemData(value).toInt(); + model->logicalSw[index].andsw = cbAndSwitch[index]->itemData(value).toInt(); emit modified(); } } -void LogicalSwitchesPanel::durationEdited(double duration) +void LogicalSwitchesPanel::onDurationChanged(double duration) { if (!lock) { int index = sender()->property("index").toInt(); @@ -246,7 +249,7 @@ void LogicalSwitchesPanel::durationEdited(double duration) } } -void LogicalSwitchesPanel::delayEdited(double delay) +void LogicalSwitchesPanel::onDelayChanged(double delay) { if (!lock) { int index = sender()->property("index").toInt(); @@ -255,12 +258,12 @@ void LogicalSwitchesPanel::delayEdited(double delay) } } -void LogicalSwitchesPanel::offsetEdited() +void LogicalSwitchesPanel::onOffsetChanged() { - offsetEditedAt(sender()->property("index").toInt()); + offsetChangedAt(sender()->property("index").toInt()); } -bool LogicalSwitchesPanel::offsetEditedAt(int index) +bool LogicalSwitchesPanel::offsetChangedAt(int index) { if (lock) return false; @@ -275,7 +278,7 @@ bool LogicalSwitchesPanel::offsetEditedAt(int index) { RawSource source = RawSource(model->logicalSw[index].val1); RawSourceRange range = source.getRange(model, generalSettings, model->logicalSw[index].getRangeFlags()); - double currVal = source.isTimeBased() ? cswitchTOffset[index]->timeInSeconds() : cswitchOffset[index]->value(); + double currVal = source.isTimeBased() ? teOffset[index]->timeInSeconds() : dsbOffset[index]->value(); value = round((currVal - range.offset) / range.step); mod = (mod || value != model->logicalSw[index].val2); model->logicalSw[index].val2 = value; @@ -283,22 +286,22 @@ bool LogicalSwitchesPanel::offsetEditedAt(int index) } case LS_FAMILY_TIMER: - value = TimToVal(cswitchValue[index]->value()); + value = TimToVal(dsbValue[index]->value()); mod = (mod || value != model->logicalSw[index].val1); model->logicalSw[index].val1 = value; - value = TimToVal(cswitchOffset[index]->value()); + value = TimToVal(dsbOffset[index]->value()); mod = (mod || value != model->logicalSw[index].val2); model->logicalSw[index].val2 = value; break; case LS_FAMILY_EDGE: - if (sender() == cswitchOffset[index]) { - value = TimToVal(cswitchOffset[index]->value()); + if (sender() == dsbOffset[index]) { + value = TimToVal(dsbOffset[index]->value()); mod = (mod || value != model->logicalSw[index].val2); model->logicalSw[index].val2 = value; } else { - value = TimToVal(cswitchOffset2[index]->value()) - model->logicalSw[index].val2; + value = TimToVal(dsbOffset2[index]->value()) - model->logicalSw[index].val2; mod = (mod || value != model->logicalSw[index].val3); model->logicalSw[index].val3 = value; } @@ -347,8 +350,8 @@ void LogicalSwitchesPanel::updateLine(int i) lock = true; unsigned int mask; - csw[i]->setCurrentIndex(csw[i]->findData(model->logicalSw[i].func)); - cswitchAnd[i]->setCurrentIndex(cswitchAnd[i]->findData(RawSwitch(model->logicalSw[i].andsw).toValue())); + 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; @@ -364,27 +367,27 @@ 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)*/ - cswitchSource1[i]->setModel(rawSourceItemModel); - cswitchSource1[i]->setCurrentIndex(cswitchSource1[i]->findData(source.toValue())); + cbSource1[i]->setModel(rawSourceItemModel); + cbSource1[i]->setCurrentIndex(cbSource1[i]->findData(source.toValue())); if (source.isTimeBased()) { mask |= VALUE_TO_VISIBLE; - cswitchTOffset[i]->setTimeRange(range.min, range.max); - cswitchTOffset[i]->setSingleStep(range.step); - cswitchTOffset[i]->setPageStep(range.step * 60); - cswitchTOffset[i]->setShowSeconds(range.step != 60); - cswitchTOffset[i]->setTime((int)value); + teOffset[i]->setTimeRange(range.min, range.max); + teOffset[i]->setSingleStep(range.step); + teOffset[i]->setPageStep(range.step * 60); + teOffset[i]->setShowSeconds(range.step != 60); + teOffset[i]->setTime((int)value); } else { mask |= VALUE2_VISIBLE; if (range.unit.isEmpty()) - cswitchOffset[i]->setSuffix(""); + dsbOffset[i]->setSuffix(""); else - cswitchOffset[i]->setSuffix(" " + range.unit); - cswitchOffset[i]->setDecimals(range.decimals); - cswitchOffset[i]->setMinimum(range.min); - cswitchOffset[i]->setMaximum(range.max); - cswitchOffset[i]->setSingleStep(range.step); - cswitchOffset[i]->setValue(value); + dsbOffset[i]->setSuffix(" " + range.unit); + dsbOffset[i]->setDecimals(range.decimals); + dsbOffset[i]->setMinimum(range.min); + dsbOffset[i]->setMaximum(range.max); + dsbOffset[i]->setSingleStep(range.step); + dsbOffset[i]->setValue(value); } break; @@ -393,58 +396,58 @@ void LogicalSwitchesPanel::updateLine(int i) case LS_FAMILY_STICKY: // no break case LS_FAMILY_VBOOL: mask |= SOURCE1_VISIBLE | SOURCE2_VISIBLE; - cswitchSource1[i]->setModel(rawSwitchItemModel); - cswitchSource1[i]->setCurrentIndex(cswitchSource1[i]->findData(model->logicalSw[i].val1)); - cswitchSource2[i]->setModel(rawSwitchItemModel); - cswitchSource2[i]->setCurrentIndex(cswitchSource2[i]->findData(model->logicalSw[i].val2)); + cbSource1[i]->setModel(rawSwitchItemModel); + cbSource1[i]->setCurrentIndex(cbSource1[i]->findData(model->logicalSw[i].val1)); + cbSource2[i]->setModel(rawSwitchItemModel); + 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; - cswitchSource1[i]->setModel(rawSwitchItemModel); - cswitchSource1[i]->setCurrentIndex(cswitchSource1[i]->findData(model->logicalSw[i].val1)); - updateTimerParam(cswitchOffset[i], model->logicalSw[i].val2, 0.0); - updateTimerParam(cswitchOffset2[i], model->logicalSw[i].val2+model->logicalSw[i].val3, ValToTim(TimToVal(cswitchOffset[i]->value())-1)); - cswitchOffset2[i]->setSuffix((model->logicalSw[i].val3) ? "" : tr(" (infinite)")); + cbSource1[i]->setModel(rawSwitchItemModel); + 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)); + dsbOffset2[i]->setSuffix((model->logicalSw[i].val3) ? "" : tr(" (infinite)")); break; case LS_FAMILY_VCOMP: mask |= SOURCE1_VISIBLE | SOURCE2_VISIBLE; - cswitchSource1[i]->setModel(rawSourceItemModel); - cswitchSource1[i]->setCurrentIndex(cswitchSource1[i]->findData(model->logicalSw[i].val1)); - cswitchSource2[i]->setModel(rawSourceItemModel); - cswitchSource2[i]->setCurrentIndex(cswitchSource2[i]->findData(model->logicalSw[i].val2)); + cbSource1[i]->setModel(rawSourceItemModel); + cbSource1[i]->setCurrentIndex(cbSource1[i]->findData(model->logicalSw[i].val1)); + cbSource2[i]->setModel(rawSourceItemModel); + cbSource2[i]->setCurrentIndex(cbSource2[i]->findData(model->logicalSw[i].val2)); break; case LS_FAMILY_TIMER: mask |= VALUE1_VISIBLE | VALUE2_VISIBLE; - updateTimerParam(cswitchValue[i], model->logicalSw[i].val1, 0.1); - updateTimerParam(cswitchOffset[i], model->logicalSw[i].val2, 0.1); + updateTimerParam(dsbValue[i], model->logicalSw[i].val1, 0.1); + updateTimerParam(dsbOffset[i], model->logicalSw[i].val2, 0.1); break; } } - cswitchSource1[i]->setVisible(mask & SOURCE1_VISIBLE); - cswitchSource2[i]->setVisible(mask & SOURCE2_VISIBLE); - cswitchValue[i]->setVisible(mask & VALUE1_VISIBLE); - cswitchOffset[i]->setVisible(mask & VALUE2_VISIBLE); - cswitchOffset2[i]->setVisible(mask & VALUE3_VISIBLE); - cswitchTOffset[i]->setVisible(mask & VALUE_TO_VISIBLE); - cswitchAnd[i]->setVisible(mask & LINE_ENABLED); - if (firmware->getCapability(LogicalSwitchesExt)) { - cswitchDuration[i]->setVisible(mask & DURATION_ENABLED); - cswitchDelay[i]->setVisible(mask & DELAY_ENABLED); + cbSource1[i]->setVisible(mask & SOURCE1_VISIBLE); + cbSource2[i]->setVisible(mask & SOURCE2_VISIBLE); + dsbValue[i]->setVisible(mask & VALUE1_VISIBLE); + dsbOffset[i]->setVisible(mask & VALUE2_VISIBLE); + dsbOffset2[i]->setVisible(mask & VALUE3_VISIBLE); + teOffset[i]->setVisible(mask & VALUE_TO_VISIBLE); + cbAndSwitch[i]->setVisible(mask & LINE_ENABLED); + if (lsCapabilityExt) { + dsbDuration[i]->setVisible(mask & DURATION_ENABLED); + dsbDelay[i]->setVisible(mask & DELAY_ENABLED); if (mask & DURATION_ENABLED) - cswitchDuration[i]->setValue(model->logicalSw[i].duration/10.0); + dsbDuration[i]->setValue(model->logicalSw[i].duration/10.0); if (mask & DELAY_ENABLED) - cswitchDelay[i]->setValue(model->logicalSw[i].delay/10.0); + dsbDelay[i]->setValue(model->logicalSw[i].delay/10.0); } lock = false; } -void LogicalSwitchesPanel::populateCSWCB(QComboBox *b) +void LogicalSwitchesPanel::populateFunctionCB(QComboBox *b) { int order[] = { LS_FN_OFF, @@ -514,63 +517,150 @@ void LogicalSwitchesPanel::populateAndSwitchCB(QComboBox *b) void LogicalSwitchesPanel::update() { updateDataModels(); - for (int i=0; igetCapability(LogicalSwitches); i++) { + for (int i=0; imimeData(); - if (mimeData->hasFormat("application/x-companion-csw")) { - QByteArray cswData = mimeData->data("application/x-companion-csw"); - LogicalSwitchData *csw = &model->logicalSw[selectedSwitch]; - memcpy(csw, cswData.constData(), sizeof(LogicalSwitchData)); - update(); + QByteArray data; + if (hasClipboardData(&data)) { + memcpy(&model->logicalSw[selectedIndex], data.constData(), sizeof(LogicalSwitchData)); + updateDataModels(); + updateLine(selectedIndex); emit modified(); } } -void LogicalSwitchesPanel::cswDelete() +void LogicalSwitchesPanel::cmDelete() { - model->logicalSw[selectedSwitch].clear(); + if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Delete Logical Switch. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) + return; + + memmove(&model->logicalSw[selectedIndex], &model->logicalSw[selectedIndex + 1], (CPN_MAX_LOGICAL_SWITCHES - (selectedIndex + 1)) * sizeof(LogicalSwitchData)); + model->logicalSw[lsCapability - 1].clear(); + + model->updateAllReferences(ModelData::REF_UPD_TYPE_LOGICAL_SWITCH, ModelData::REF_UPD_ACT_SHIFT, selectedIndex, 0, -1); + update(); emit modified(); - updateLine(selectedSwitch); } -void LogicalSwitchesPanel::cswCopy() +void LogicalSwitchesPanel::cmCopy() { - QByteArray cswData; - cswData.append((char*)&model->logicalSw[selectedSwitch],sizeof(LogicalSwitchData)); + QByteArray data; + data.append((char*)&model->logicalSw[selectedIndex], sizeof(LogicalSwitchData)); QMimeData *mimeData = new QMimeData; - mimeData->setData("application/x-companion-csw", cswData); + mimeData->setData(MIMETYPE_LOGICAL_SWITCH, data); QApplication::clipboard()->setMimeData(mimeData,QClipboard::Clipboard); } -void LogicalSwitchesPanel::cswCut() +void LogicalSwitchesPanel::cmCut() { - cswCopy(); - cswDelete(); + cmCopy(); + cmClear(); } // TODO make something generic here! -void LogicalSwitchesPanel::csw_customContextMenuRequested(QPoint pos) +void LogicalSwitchesPanel::onCustomContextMenuRequested(QPoint pos) { - QLabel *label = (QLabel *)sender(); - selectedSwitch = label->property("index").toInt(); + QLabel *label = (QLabel *)sender(); + selectedIndex = label->property("index").toInt(); + QPoint globalPos = label->mapToGlobal(pos); - QPoint globalPos = label->mapToGlobal(pos); + QMenu contextMenu; + contextMenu.addAction(CompanionIcon("copy.png"), tr("Copy"),this,SLOT(cmCopy())); + contextMenu.addAction(CompanionIcon("cut.png"), tr("Cut"),this,SLOT(cmCut())); + 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())); - const QClipboard * clipboard = QApplication::clipboard(); - const QMimeData * mimeData = clipboard->mimeData(); - bool hasData = mimeData->hasFormat("application/x-companion-csw"); + contextMenu.exec(globalPos); +} - QMenu contextMenu; - contextMenu.addAction(CompanionIcon("copy.png"), tr("&Copy"),this,SLOT(cswCopy())); - contextMenu.addAction(CompanionIcon("cut.png"), tr("&Cut"),this,SLOT(cswCut())); - contextMenu.addAction(CompanionIcon("paste.png"), tr("&Paste"),this,SLOT(cswPaste()))->setEnabled(hasData); - contextMenu.addAction(CompanionIcon("clear.png"), tr("&Delete"),this,SLOT(cswDelete())); +bool LogicalSwitchesPanel::hasClipboardData(QByteArray * data) const +{ + const QClipboard * clipboard = QApplication::clipboard(); + const QMimeData * mimeData = clipboard->mimeData(); + if (mimeData->hasFormat(MIMETYPE_LOGICAL_SWITCH)) { + if (data) + data->append(mimeData->data(MIMETYPE_LOGICAL_SWITCH)); + return true; + } + return false; +} - contextMenu.exec(globalPos); +bool LogicalSwitchesPanel::insertAllowed() const +{ + return ((selectedIndex < lsCapability - 1) && (model->logicalSw[lsCapability - 1].isEmpty())); +} + +bool LogicalSwitchesPanel::moveDownAllowed() const +{ + return selectedIndex < lsCapability - 1; +} + +bool LogicalSwitchesPanel::moveUpAllowed() const +{ + return selectedIndex > 0; +} + +void LogicalSwitchesPanel::cmMoveUp() +{ + swapData(selectedIndex, selectedIndex - 1); +} + +void LogicalSwitchesPanel::cmMoveDown() +{ + swapData(selectedIndex, selectedIndex + 1); +} + +void LogicalSwitchesPanel::cmClear() +{ + model->logicalSw[selectedIndex].clear(); + model->updateAllReferences(ModelData::REF_UPD_TYPE_LOGICAL_SWITCH, ModelData::REF_UPD_ACT_CLEAR, selectedIndex); + update(); + emit modified(); +} + +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(); + emit modified(); +} + +void LogicalSwitchesPanel::cmInsert() +{ + memmove(&model->logicalSw[selectedIndex + 1], &model->logicalSw[selectedIndex], (CPN_MAX_LOGICAL_SWITCHES - (selectedIndex + 1)) * sizeof(LogicalSwitchData)); + model->logicalSw[selectedIndex].clear(); + model->updateAllReferences(ModelData::REF_UPD_TYPE_LOGICAL_SWITCH, ModelData::REF_UPD_ACT_SHIFT, selectedIndex, 0, 1); + update(); + emit modified(); +} + +void LogicalSwitchesPanel::swapData(int idx1, int idx2) +{ + if ((idx1 != idx2) && (!model->logicalSw[idx1].isEmpty() || !model->logicalSw[idx2].isEmpty())) { + LogicalSwitchData lstmp = model->logicalSw[idx2]; + LogicalSwitchData *lsw1 = &model->logicalSw[idx1]; + LogicalSwitchData *lsw2 = &model->logicalSw[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(); + emit modified(); + } } diff --git a/companion/src/modeledit/logicalswitches.h b/companion/src/modeledit/logicalswitches.h index fde3df0f4..2aea300c5 100644 --- a/companion/src/modeledit/logicalswitches.h +++ b/companion/src/modeledit/logicalswitches.h @@ -28,6 +28,8 @@ class RawSwitchFilterItemModel; class RawSourceFilterItemModel; class TimerEdit; +constexpr char MIMETYPE_LOGICAL_SWITCH[] = "application/x-companion-logical-switch"; + class LogicalSwitchesPanel : public ModelPanel { Q_OBJECT @@ -40,40 +42,50 @@ class LogicalSwitchesPanel : public ModelPanel private slots: void updateDataModels(); - void functionChanged(); - void v1Edited(int value); - void v2Edited(int value); - void andEdited(int value); - void durationEdited(double duration); - void delayEdited(double delay); - void offsetEdited(); - bool offsetEditedAt(int index); + void onFunctionChanged(); + void onV1Changed(int value); + void onV2Changed(int value); + void onAndSwitchChanged(int value); + void onDurationChanged(double duration); + void onDelayChanged(double delay); + void onOffsetChanged(); + bool offsetChangedAt(int index); void updateLine(int index); - void csw_customContextMenuRequested(QPoint pos); - void cswDelete(); - void cswCopy(); - void cswPaste(); - void cswCut(); + void onCustomContextMenuRequested(QPoint pos); + void cmDelete(); + void cmCopy(); + void cmPaste(); + void cmCut(); + void cmMoveUp(); + void cmMoveDown(); + void cmInsert(); + void cmClear(); + void cmClearAll(); private: - QComboBox * csw[CPN_MAX_LOGICAL_SWITCHES]; - QDoubleSpinBox * cswitchValue[CPN_MAX_LOGICAL_SWITCHES]; - QDoubleSpinBox * cswitchOffset[CPN_MAX_LOGICAL_SWITCHES]; - QDoubleSpinBox * cswitchOffset2[CPN_MAX_LOGICAL_SWITCHES]; - TimerEdit * cswitchTOffset[CPN_MAX_LOGICAL_SWITCHES]; - QComboBox * cswitchAnd[CPN_MAX_LOGICAL_SWITCHES]; - QDoubleSpinBox * cswitchDuration[CPN_MAX_LOGICAL_SWITCHES]; - QDoubleSpinBox * cswitchDelay[CPN_MAX_LOGICAL_SWITCHES]; - QComboBox * cswitchSource1[CPN_MAX_LOGICAL_SWITCHES]; - QComboBox * cswitchSource2[CPN_MAX_LOGICAL_SWITCHES]; + QComboBox * cbFunction[CPN_MAX_LOGICAL_SWITCHES]; + QDoubleSpinBox * dsbValue[CPN_MAX_LOGICAL_SWITCHES]; + QDoubleSpinBox * dsbOffset[CPN_MAX_LOGICAL_SWITCHES]; + QDoubleSpinBox * dsbOffset2[CPN_MAX_LOGICAL_SWITCHES]; + TimerEdit * teOffset[CPN_MAX_LOGICAL_SWITCHES]; + QComboBox * cbAndSwitch[CPN_MAX_LOGICAL_SWITCHES]; + QDoubleSpinBox * dsbDuration[CPN_MAX_LOGICAL_SWITCHES]; + QDoubleSpinBox * dsbDelay[CPN_MAX_LOGICAL_SWITCHES]; + QComboBox * cbSource1[CPN_MAX_LOGICAL_SWITCHES]; + QComboBox * cbSource2[CPN_MAX_LOGICAL_SWITCHES]; RawSwitchFilterItemModel * rawSwitchItemModel; RawSourceFilterItemModel * rawSourceItemModel; - int selectedSwitch; - - void populateCSWCB(QComboBox *b); + int selectedIndex; + void populateFunctionCB(QComboBox *b); void populateAndSwitchCB(QComboBox *b); void updateTimerParam(QDoubleSpinBox *sb, int timer, double minimum=0); - + int lsCapability; + int lsCapabilityExt; + void swapData(int idx1, int idx2); + bool hasClipboardData(QByteArray * data = nullptr) const; + bool insertAllowed() const; + bool moveDownAllowed() const; + bool moveUpAllowed() const; }; #endif // _LOGICALSWITCHES_H_ diff --git a/companion/src/modeledit/setup.cpp b/companion/src/modeledit/setup.cpp index 5e193faec..c813b0b9c 100644 --- a/companion/src/modeledit/setup.cpp +++ b/companion/src/modeledit/setup.cpp @@ -49,7 +49,7 @@ TimerPanel::TimerPanel(QWidget *parent, ModelData & model, TimerData & timer, Ge } else { ui->name->setMaxLength(length); - ui->name->setText(timer.name); + //ui->name->setText(timer.name); } // Mode @@ -85,6 +85,7 @@ TimerPanel::TimerPanel(QWidget *parent, ModelData & model, TimerData & timer, Ge QWidget::setTabOrder(ui->countdownBeep, ui->minuteBeep); QWidget::setTabOrder(ui->minuteBeep, ui->persistent); + update(); lock = false; } @@ -95,6 +96,9 @@ 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; @@ -116,7 +120,10 @@ void TimerPanel::update() 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->countdownBeep->updateValue(); ui->minuteBeep->setChecked(timer.minuteBeep); + ui->persistent->updateValue(); + lock = false; } QWidget * TimerPanel::getLastFocus() @@ -126,38 +133,43 @@ QWidget * TimerPanel::getLastFocus() void TimerPanel::on_value_editingFinished() { - 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(); + 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(); + } } } void TimerPanel::onModeChanged(int index) { - if (lock) - return; - - bool ok; - const RawSwitch rs(ui->mode->itemData(index).toInt(&ok)); - if (ok && timer.mode.toValue() != rs.toValue()) { - timer.mode = rs; - emit modified(); + 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(); + } } } void TimerPanel::on_minuteBeep_toggled(bool checked) { - timer.minuteBeep = checked; - emit modified(); + if (!lock) { + timer.minuteBeep = checked; + emit modified(); + } } void TimerPanel::on_name_editingFinished() { - if (QString(timer.name) != ui->name->text()) { - int length = ui->name->maxLength(); - strncpy(timer.name, ui->name->text().toLatin1(), length); - emit modified(); + if (!lock) { + if (QString(timer.name) != ui->name->text()) { + int length = ui->name->maxLength(); + strncpy(timer.name, ui->name->text().toLatin1(), length); + emit modified(); + } } } @@ -273,27 +285,12 @@ ModulePanel::~ModulePanel() delete ui; } -bool ModulePanel::moduleHasFailsafes() -{ - return firmware->getCapability(HasFailsafe) && ( - (PulsesProtocol)module.protocol == PulsesProtocol::PULSES_ACCESS_ISRM || - (PulsesProtocol)module.protocol == PulsesProtocol::PULSES_ACCST_ISRM_D16 || - (PulsesProtocol)module.protocol == PulsesProtocol::PULSES_PXX_XJT_X16 || - (PulsesProtocol)module.protocol == PulsesProtocol::PULSES_PXX_R9M || - (PulsesProtocol)module.protocol == PulsesProtocol::PULSES_ACCESS_R9M || - (PulsesProtocol)module.protocol == PulsesProtocol::PULSES_ACCESS_R9M_LITE || - (PulsesProtocol)module.protocol == PulsesProtocol::PULSES_ACCESS_R9M_LITE_PRO || - (PulsesProtocol)module.protocol == PulsesProtocol::PULSES_XJT_LITE_X16 || - (PulsesProtocol)module.protocol == PulsesProtocol::PULSES_MULTIMODULE - ); -} - void ModulePanel::setupFailsafes() { ChannelFailsafeWidgetsGroup grp; const int start = module.channelsStart; const int end = start + module.channelsCount; - const bool hasFailsafe = moduleHasFailsafes(); + const bool hasFailsafe = module.hasFailsafes(firmware); lock = true; @@ -382,48 +379,6 @@ void ModulePanel::setupFailsafes() lock = false; } -int ModulePanel::getMaxChannelCount() -{ - const PulsesProtocol protocol = (PulsesProtocol)module.protocol; - switch (protocol) { - case PULSES_ACCESS_ISRM: - return 24; - case PULSES_PXX_R9M: - case PULSES_ACCESS_R9M: - case PULSES_ACCESS_R9M_LITE: - case PULSES_ACCESS_R9M_LITE_PRO: - case PULSES_ACCST_ISRM_D16: - case PULSES_XJT_LITE_X16: - case PULSES_PXX_XJT_X16: - case PULSES_CROSSFIRE: - case PULSES_SBUS: - case PULSES_PPM: - return 16; - case PULSES_XJT_LITE_LR12: - case PULSES_PXX_XJT_LR12: - return 12; - case PULSES_PXX_DJT: - case PULSES_XJT_LITE_D8: - case PULSES_PXX_XJT_D8: - return 8; - case PULSES_LP45: - case PULSES_DSM2: - case PULSES_DSMX: - return 6; - case PULSES_MULTIMODULE: - if (module.multi.rfProtocol == MODULE_SUBTYPE_MULTI_DSM2) - return 12; - else - return 16; - break; - case PULSES_OFF: - break; - default: - break; - } - return 8; -} - void ModulePanel::update() { const PulsesProtocol protocol = (PulsesProtocol)module.protocol; @@ -510,7 +465,7 @@ void ModulePanel::update() mask |= MASK_PPM_FIELDS | MASK_CHANNELS_RANGE | MASK_CHANNELS_COUNT; } - if (moduleHasFailsafes()) { + if (module.hasFailsafes(firmware)) { mask |= MASK_FAILSAFES; } @@ -527,7 +482,7 @@ void ModulePanel::update() ui->label_channelsCount->setVisible(mask & MASK_CHANNELS_RANGE); ui->channelsCount->setVisible(mask & MASK_CHANNELS_RANGE); ui->channelsCount->setEnabled(mask & MASK_CHANNELS_COUNT); - ui->channelsCount->setMaximum(getMaxChannelCount()); + ui->channelsCount->setMaximum(module.getMaxChannelCount()); ui->channelsCount->setValue(module.channelsCount); ui->channelsCount->setSingleStep(firmware->getCapability(HasPPMStart) ? 1 : 2); @@ -695,7 +650,7 @@ void ModulePanel::onProtocolChanged(int index) { if (!lock && module.protocol != ui->protocol->itemData(index).toUInt()) { module.protocol = ui->protocol->itemData(index).toInt(); - module.channelsCount = getMaxChannelCount(); + module.channelsCount = module.getMaxChannelCount(); update(); emit modified(); } @@ -790,7 +745,7 @@ void ModulePanel::onMultiProtocolChanged(int index) if (rfProtocol > MODULE_SUBTYPE_MULTI_LAST) maxSubTypes=8; module.subType = std::min(module.subType, maxSubTypes -1); - module.channelsCount = getMaxChannelCount(); + module.channelsCount = module.getMaxChannelCount(); update(); emit modified(); lock = false; @@ -1064,16 +1019,28 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge RawSwitchFilterItemModel * swModel = new RawSwitchFilterItemModel(&generalSettings, &model, RawSwitch::TimersContext, this); connect(this, &SetupPanel::updated, swModel, &RawSwitchFilterItemModel::update); - for (int i=0; igetCapability(Timers)) { + 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); ui->gridLayout->addWidget(timers[i], 1+i, 1); connect(timers[i], &TimerPanel::modified, this, &SetupPanel::modified); 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)); + if (label) { // to stop crashing if not found + label->setProperty("index", i); + label->setContextMenuPolicy(Qt::CustomContextMenu); + label->setToolTip(tr("Popup menu available")); + label->setMouseTracking(true); + connect(label, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(onTimerCustomContextMenuRequested(QPoint))); + } } else { - foreach(QLabel *label, findChildren(QRegularExpression(QString("label_timer%1").arg(i+1)))) { + foreach(QLabel *label, findChildren(QRegularExpression(QString("label_timer%1").arg(i + 1 )))) { //TODO more reliable method required label->hide(); } } @@ -1081,9 +1048,9 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge if (firmware->getCapability(HasTopLcd)) { ui->toplcdTimer->setField(model.toplcdTimer, this); - for (int i=0; igetCapability(Timers)) { - ui->toplcdTimer->addItem(tr("Timer %1").arg(i+1), i); + for (int i = 0; i < CPN_MAX_TIMERS; i++) { + if (itoplcdTimer->addItem(tr("Timer %1").arg(i + 1), i); } } } @@ -1528,3 +1495,155 @@ void SetupPanel::on_editText_clicked() } } +void SetupPanel::onTimerCustomContextMenuRequested(QPoint pos) +{ + QLabel *label = (QLabel *)sender(); + selectedTimerIndex = label->property("index").toInt(); + QPoint globalPos = label->mapToGlobal(pos); + + QMenu contextMenu; + contextMenu.addAction(CompanionIcon("copy.png"), tr("Copy"), this, SLOT(cmTimerCopy())); + contextMenu.addAction(CompanionIcon("cut.png"), tr("Cut"), this, SLOT(cmTimerCut())); + contextMenu.addAction(CompanionIcon("paste.png"), tr("Paste"), this, SLOT(cmTimerPaste()))->setEnabled(hasTimerClipboardData()); + contextMenu.addAction(CompanionIcon("clear.png"), tr("Clear"), this, SLOT(cmTimerClear())); + contextMenu.addSeparator(); + contextMenu.addAction(CompanionIcon("arrow-right.png"), tr("Insert"), this, SLOT(cmTimerInsert()))->setEnabled(insertTimerAllowed()); + contextMenu.addAction(CompanionIcon("arrow-left.png"), tr("Delete"), this, SLOT(cmTimerDelete())); + contextMenu.addAction(CompanionIcon("moveup.png"), tr("Move Up"), this, SLOT(cmTimerMoveUp()))->setEnabled(moveTimerUpAllowed()); + contextMenu.addAction(CompanionIcon("movedown.png"), tr("Move Down"), this, SLOT(cmTimerMoveDown()))->setEnabled(moveTimerDownAllowed()); + contextMenu.addSeparator(); + contextMenu.addAction(CompanionIcon("clear.png"), tr("Clear All"), this, SLOT(cmTimerClearAll())); + + contextMenu.exec(globalPos); +} + +bool SetupPanel::hasTimerClipboardData(QByteArray * data) const +{ + const QClipboard * clipboard = QApplication::clipboard(); + const QMimeData * mimeData = clipboard->mimeData(); + if (mimeData->hasFormat(MIMETYPE_TIMER)) { + if (data) + data->append(mimeData->data(MIMETYPE_TIMER)); + return true; + } + return false; +} + +bool SetupPanel::insertTimerAllowed() const +{ + return ((selectedTimerIndex < timersCount - 1) && (model->timers[timersCount - 1].isEmpty())); +} + +bool SetupPanel::moveTimerDownAllowed() const +{ + return selectedTimerIndex < timersCount - 1; +} + +bool SetupPanel::moveTimerUpAllowed() const +{ + return selectedTimerIndex > 0; +} + +void SetupPanel::cmTimerClear() +{ + 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(); + emit modified(); +} + +void SetupPanel::cmTimerClearAll() +{ + if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear all Timers. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) + return; + + for (int i = 0; i < timersCount; i++) { + model->timers[i].clear(); + model->updateAllReferences(ModelData::REF_UPD_TYPE_TIMER, ModelData::REF_UPD_ACT_CLEAR, i); + } + emit timerUpdated(); + emit modified(); +} + +void SetupPanel::cmTimerCopy() +{ + QByteArray data; + data.append((char*)&model->timers[selectedTimerIndex], sizeof(TimerData)); + QMimeData *mimeData = new QMimeData; + mimeData->setData(MIMETYPE_TIMER, data); + QApplication::clipboard()->setMimeData(mimeData,QClipboard::Clipboard); +} + +void SetupPanel::cmTimerCut() +{ + cmTimerCopy(); + cmTimerClear(); +} + +void SetupPanel::cmTimerDelete() +{ + if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Delete Timer. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) + return; + + int maxidx = timersCount - 1; + for (int i = selectedTimerIndex; i < maxidx; i++) { + if (!model->timers[i].isEmpty() || !model->timers[i + 1].isEmpty()) { + memcpy(&model->timers[i], &model->timers[i+1], sizeof(TimerData)); + } + } + model->timers[maxidx].clear(); + model->updateAllReferences(ModelData::REF_UPD_TYPE_TIMER, ModelData::REF_UPD_ACT_SHIFT, selectedTimerIndex, 0, -1); + emit timerUpdated(); + emit modified(); +} + +void SetupPanel::cmTimerInsert() +{ + for (int i = (timersCount - 1); i > selectedTimerIndex; i--) { + if (!model->timers[i].isEmpty() || !model->timers[i-1].isEmpty()) { + memcpy(&model->timers[i], &model->timers[i-1], sizeof(TimerData)); + } + } + model->timers[selectedTimerIndex].clear(); + model->updateAllReferences(ModelData::REF_UPD_TYPE_TIMER, ModelData::REF_UPD_ACT_SHIFT, selectedTimerIndex, 0, 1); + emit timerUpdated(); + emit modified(); +} + +void SetupPanel::cmTimerMoveDown() +{ + swapTimerData(selectedTimerIndex, selectedTimerIndex + 1); +} + +void SetupPanel::cmTimerMoveUp() +{ + swapTimerData(selectedTimerIndex, selectedTimerIndex - 1); +} + +void SetupPanel::cmTimerPaste() +{ + QByteArray data; + if (hasTimerClipboardData(&data)) { + TimerData *td = &model->timers[selectedTimerIndex]; + memcpy(td, data.constData(), sizeof(TimerData)); + emit timerUpdated(); + emit modified(); + } +} + +void SetupPanel::swapTimerData(int idx1, int idx2) +{ + if ((idx1 != idx2) && (!model->timers[idx1].isEmpty() || !model->timers[idx2].isEmpty())) { + TimerData tdtmp = model->timers[idx2]; + TimerData *td1 = &model->timers[idx1]; + TimerData *td2 = &model->timers[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(); + emit modified(); + } +} diff --git a/companion/src/modeledit/setup.h b/companion/src/modeledit/setup.h index 586cba07d..fa9e4ad5b 100644 --- a/companion/src/modeledit/setup.h +++ b/companion/src/modeledit/setup.h @@ -24,6 +24,8 @@ #include "modeledit.h" #include "eeprominterface.h" +constexpr char MIMETYPE_TIMER[] = "application/x-companion-timer"; + class RawSwitchFilterItemModel; namespace Ui { @@ -62,7 +64,6 @@ class ModulePanel : public ModelPanel ModulePanel(QWidget *parent, ModelData & model, ModuleData & module, GeneralSettings & generalSettings, Firmware * firmware, int moduleIdx); virtual ~ModulePanel(); virtual void update(); - bool moduleHasFailsafes(); public slots: void onExtendedLimitsToggled(); @@ -71,7 +72,6 @@ class ModulePanel : public ModelPanel void channelsRangeChanged(); private slots: - int getMaxChannelCount(); void setupFailsafes(); void on_trainerMode_currentIndexChanged(int index); void onProtocolChanged(int index); @@ -129,6 +129,7 @@ class SetupPanel : public ModelPanel signals: void extendedLimitsToggled(); void updated(); + void timerUpdated(); private slots: void on_name_editingFinished(); @@ -148,6 +149,16 @@ class SetupPanel : public ModelPanel void potWarningToggled(bool checked); void on_potWarningMode_currentIndexChanged(int index); void on_editText_clicked(); + void onTimerCustomContextMenuRequested(QPoint pos); + void cmTimerClear(); + void cmTimerClearAll(); + void cmTimerCopy(); + void cmTimerCut(); + void cmTimerDelete(); + void cmTimerInsert(); + void cmTimerPaste(); + void cmTimerMoveDown(); + void cmTimerMoveUp(); private: Ui::Setup *ui; @@ -161,6 +172,13 @@ class SetupPanel : public ModelPanel void updatePotWarnings(); void updateBeepCenter(); void populateThrottleSourceCB(); + int timersCount; + int selectedTimerIndex; + bool hasTimerClipboardData(QByteArray * data = nullptr) const; + bool insertTimerAllowed() const; + bool moveTimerDownAllowed() const; + bool moveTimerUpAllowed() const; + void swapTimerData(int idx1, int idx2); }; #endif // _SETUP_H_ diff --git a/companion/src/modeledit/setup.ui b/companion/src/modeledit/setup.ui index 9ad725ce1..fc499ad63 100644 --- a/companion/src/modeledit/setup.ui +++ b/companion/src/modeledit/setup.ui @@ -590,7 +590,7 @@ If this is checked the throttle will be reversed. Idle will be forward, trim wi - + 50 diff --git a/companion/src/modeledit/telemetry.cpp b/companion/src/modeledit/telemetry.cpp index 68be10638..83565c03e 100644 --- a/companion/src/modeledit/telemetry.cpp +++ b/companion/src/modeledit/telemetry.cpp @@ -592,13 +592,28 @@ void TelemetryCustomScreen::barTimeChanged() } } -TelemetrySensorPanel::TelemetrySensorPanel(QWidget *parent, SensorData & sensor, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware): +/******************************************************/ + +TelemetrySensorPanel::TelemetrySensorPanel(QWidget *parent, SensorData & sensor, int sensorIndex, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware): ModelPanel(parent, model, generalSettings, firmware), ui(new Ui::TelemetrySensor), sensor(sensor), - lock(false) + lock(false), + sensorIndex(sensorIndex), + selectedIndex(0) { ui->setupUi(this); + 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"); + 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->id->setField(sensor.id, this); ui->instance->setField(sensor.instance, this); ui->ratio->setField(sensor.ratio, this); @@ -613,7 +628,7 @@ TelemetrySensorPanel::TelemetrySensorPanel(QWidget *parent, SensorData & sensor, ui->ampsSensor->setField(sensor.amps, this); ui->cellsSensor->setField(sensor.source, this); ui->cellsIndex->addItem(tr("Lowest"), SensorData::TELEM_CELL_INDEX_LOWEST); - for (int i=1; i<=6; i++) + 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); @@ -622,6 +637,7 @@ TelemetrySensorPanel::TelemetrySensorPanel(QWidget *parent, SensorData & sensor, ui->source2->setField(sensor.sources[1], this); ui->source3->setField(sensor.sources[2], this); ui->source4->setField(sensor.sources[3], this); + ui->prec->setField(sensor.prec, 0, 2, false, "", this); update(); } @@ -645,7 +661,21 @@ void TelemetrySensorPanel::update() ui->name->setText(sensor.label); ui->type->setCurrentIndex(sensor.type); ui->unit->setCurrentIndex(sensor.unit); - ui->prec->setValue(sensor.prec); + ui->id->updateValue(); + ui->instance->updateValue(); + ui->ratio->updateValue(); + ui->offset->updateValue(); + ui->autoOffset->updateValue(); + ui->filter->updateValue(); + ui->logs->updateValue(); + ui->persistent->updateValue(); + ui->onlyPositive->updateValue(); + ui->gpsSensor->updateValue(); + ui->altSensor->updateValue(); + ui->ampsSensor->updateValue(); + ui->cellsSensor->updateValue(); + ui->cellsIndex->updateValue(); + ui->prec->updateValue(); if (sensor.type == SensorData::TELEM_TYPE_CALCULATED) { sensor.updateUnit(); @@ -825,15 +855,85 @@ void TelemetrySensorPanel::on_unit_currentIndexChanged(int index) } } -void TelemetrySensorPanel::on_prec_valueChanged(double value) +void TelemetrySensorPanel::on_prec_valueChanged() { if (!lock) { - sensor.prec = value; + update(); + } +} + +void TelemetrySensorPanel::on_customContextMenuRequested(QPoint pos) +{ + QLabel *label = (QLabel *)sender(); + selectedIndex = label->property("index").toInt(); + QPoint globalPos = label->mapToGlobal(pos); + + QMenu contextMenu; + contextMenu.addAction(CompanionIcon("copy.png"), tr("Copy"),this,SLOT(cmCopy())); + contextMenu.addAction(CompanionIcon("cut.png"), tr("Cut"),this,SLOT(cmCut())); + 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("clear.png"), tr("Clear All"),this,SLOT(cmClearAll())); + + contextMenu.exec(globalPos); +} + +bool TelemetrySensorPanel::hasClipboardData(QByteArray * data) const +{ + const QClipboard * clipboard = QApplication::clipboard(); + const QMimeData * mimeData = clipboard->mimeData(); + if (mimeData->hasFormat(MIMETYPE_TELE_SENSOR)) { + if (data) + data->append(mimeData->data(MIMETYPE_TELE_SENSOR)); + return true; + } + return false; +} + +void TelemetrySensorPanel::cmCopy() +{ + QByteArray data; + data.append((char*)&sensor, sizeof(SensorData)); + QMimeData *mimeData = new QMimeData; + mimeData->setData(MIMETYPE_TELE_SENSOR, data); + QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard); +} + +void TelemetrySensorPanel::cmCut() +{ + cmCopy(); + cmClear(); +} + +void TelemetrySensorPanel::cmPaste() +{ + QByteArray data; + if (hasClipboardData(&data)) { + memcpy(&sensor, data.constData(), sizeof(SensorData)); emit dataModified(); emit modified(); } } +void TelemetrySensorPanel::cmClear() +{ + if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear Telemetry Sensor. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) + return; + + sensor.clear(); + emit dataModified(); + emit modified(); +} + +void TelemetrySensorPanel::cmClearAll() +{ + if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear all Telemetry Sensors. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) + return; + + emit clearAllSensors(); +} + /******************************************************/ TelemetryPanel::TelemetryPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware): @@ -851,12 +951,13 @@ TelemetryPanel::TelemetryPanel(QWidget *parent, ModelData & model, GeneralSettin ui->varioCenterSilent->setField(model.frsky.varioCenterSilent, this); ui->A1GB->hide(); ui->A2GB->hide(); - for (unsigned i=0; isensorsLayout->addWidget(panel); sensorPanels[i] = panel; connect(panel, SIGNAL(dataModified()), this, SLOT(update())); connect(panel, SIGNAL(modified()), this, SLOT(onModified())); + connect(panel, SIGNAL(clearAllSensors()), this, SLOT(on_clearAllSensors())); } } else { @@ -869,7 +970,7 @@ TelemetryPanel::TelemetryPanel(QWidget *parent, ModelData & model, GeneralSettin ui->A2Layout->addWidget(analogs[1]); connect(analogs[1], SIGNAL(modified()), this, SLOT(onModified())); } - + if (IS_TARANIS_X9(firmware->getBoard())) { ui->voltsSource->setField(model.frsky.voltsSource, this); ui->altitudeSource->setField(model.frsky.altitudeSource, this); @@ -881,7 +982,7 @@ TelemetryPanel::TelemetryPanel(QWidget *parent, ModelData & model, GeneralSettin RawSourceFilterItemModel * srcModel = (new RawSourceFilterItemModel(&generalSettings, &model, this)); connect(this, &TelemetryPanel::updated, srcModel, &RawSourceFilterItemModel::update); - for (int i=0; igetCapability(TelemetryCustomScreens); i++) { + 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)); telemetryCustomScreens[i] = tab; @@ -963,7 +1064,7 @@ void TelemetryPanel::setup() 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")); @@ -1198,3 +1299,13 @@ void TelemetryPanel::on_mahCount_ChkB_toggled(bool 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(); + } + + update(); + emit modified(); +} diff --git a/companion/src/modeledit/telemetry.h b/companion/src/modeledit/telemetry.h index b23214927..39f3a42ad 100644 --- a/companion/src/modeledit/telemetry.h +++ b/companion/src/modeledit/telemetry.h @@ -24,6 +24,8 @@ #include "modeledit.h" #include "eeprominterface.h" +constexpr char MIMETYPE_TELE_SENSOR[] = "application/x-companion-tele-sensor"; + class AutoComboBox; class RawSourceFilterItemModel; class TimerEdit; @@ -103,19 +105,27 @@ class TelemetrySensorPanel: public ModelPanel Q_OBJECT public: - TelemetrySensorPanel(QWidget *parent, SensorData & sensor, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware); + TelemetrySensorPanel(QWidget *parent, SensorData & sensor, int sensorIndex, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware); ~TelemetrySensorPanel(); void update(); signals: void dataModified(); + void clearAllSensors(); 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(double value); + void on_prec_valueChanged(); + void on_customContextMenuRequested(QPoint pos); + bool hasClipboardData(QByteArray * data = nullptr) const; + void cmCopy(); + void cmCut(); + void cmPaste(); + void cmClear(); + void cmClearAll(); protected: void updateSourcesComboBox(AutoComboBox * cb, bool negative); @@ -123,7 +133,9 @@ class TelemetrySensorPanel: public ModelPanel private: Ui::TelemetrySensor * ui; SensorData & sensor; - bool lock; + bool lock = false; + int sensorIndex = 0; + int selectedIndex = 0; }; class TelemetryPanel : public ModelPanel @@ -154,6 +166,7 @@ class TelemetryPanel : public ModelPanel void on_fasOffset_DSB_editingFinished(); void on_mahCount_SB_editingFinished(); void on_mahCount_ChkB_toggled(bool checked); + void on_clearAllSensors(); private: Ui::Telemetry *ui; diff --git a/companion/src/modeledit/telemetry_sensor.ui b/companion/src/modeledit/telemetry_sensor.ui index 7d08243e0..12af2cf06 100644 --- a/companion/src/modeledit/telemetry_sensor.ui +++ b/companion/src/modeledit/telemetry_sensor.ui @@ -13,13 +13,32 @@ Form - + 0 0 + + + + + 0 + 0 + + + + + 0 + 0 + + + + TELE## + + + @@ -520,6 +539,11 @@ US fl.Oz. + + + ml/min + + @@ -536,23 +560,7 @@ - - - true - - - - 0 - 0 - - - - 0 - - - 2.000000000000000 - - + @@ -711,6 +719,11 @@ QSpinBox
autohexspinbox.h
+ + AutoPrecisionComboBox + QComboBox +
autoprecisioncombobox.h
+
diff --git a/companion/src/profilechooser.cpp b/companion/src/profilechooser.cpp new file mode 100644 index 000000000..17a9570e5 --- /dev/null +++ b/companion/src/profilechooser.cpp @@ -0,0 +1,62 @@ +/* + * 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 "profilechooser.h" +#include "ui_profilechooser.h" +#include "appdata.h" + +ProfileChooserDialog::ProfileChooserDialog(QWidget * parent): + QDialog(parent), + ui(new Ui::ProfileChooserDialog) +{ + ui->setupUi(this); + setWindowIcon(QIcon(":/icon.png")); + QComboBox *prof = ui->cboProfiles; + prof->clear(); + + QMap active; + active = g.getActiveProfiles(); + QMapIterator i(active); + while (i.hasNext()) { + i.next(); + prof->addItem(i.value(), i.key()); + } + + prof->setSizeAdjustPolicy(QComboBox::AdjustToContents); + prof->setCurrentIndex(prof->findData(g.id())); + connect(prof, SIGNAL(currentIndexChanged(int)), this, SLOT(on_cboProfilesCurrentIndexChanged(int))); +} + +ProfileChooserDialog::~ProfileChooserDialog() +{ + delete ui; +} + +void ProfileChooserDialog::on_cboProfilesCurrentIndexChanged(int index) +{ + QComboBox *prof = ui->cboProfiles; + + if ((prof->currentIndex() > -1)) { + int oldid = g.id(); + int newid = prof->currentData().toInt(); + if (oldid != newid) + emit profileChanged(newid); + } +} diff --git a/companion/src/profilechooser.h b/companion/src/profilechooser.h new file mode 100644 index 000000000..b40e6b359 --- /dev/null +++ b/companion/src/profilechooser.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. + */ + +#ifndef _PROFILECHOOSER_H_ +#define _PROFILECHOOSER_H_ + +#include + +namespace Ui { + class ProfileChooserDialog; +} + +class ProfileChooserDialog : public QDialog +{ + Q_OBJECT + + public: + ProfileChooserDialog(QWidget * parent = 0); + ~ProfileChooserDialog(); +signals: + void profileChanged(int newid); + + private slots: + void on_cboProfilesCurrentIndexChanged(int index); + + private: + Ui::ProfileChooserDialog *ui; +}; + +#endif // _PROFILECHOOSER_H_ diff --git a/companion/src/profilechooser.ui b/companion/src/profilechooser.ui new file mode 100644 index 000000000..10a6d6bbe --- /dev/null +++ b/companion/src/profilechooser.ui @@ -0,0 +1,110 @@ + + + ProfileChooserDialog + + + + 0 + 0 + 352 + 102 + + + + + 0 + 0 + + + + Select Profile + + + + + 20 + 20 + 311 + 66 + + + + + + + + + + 0 + 0 + + + + Profile + + + + + + + + 0 + 0 + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + false + + + + + + + + + + buttonBox + accepted() + ProfileChooserDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + ProfileChooserDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/companion/src/shared/CMakeLists.txt b/companion/src/shared/CMakeLists.txt index 81df9dd67..2fbbafbf9 100644 --- a/companion/src/shared/CMakeLists.txt +++ b/companion/src/shared/CMakeLists.txt @@ -15,6 +15,7 @@ set(shared_HDRS autolineedit.h genericpanel.h hexspinbox.h + autoprecisioncombobox.h ) qt5_wrap_cpp(shared_SRCS ${shared_HDRS}) diff --git a/companion/src/shared/autoprecisioncombobox.h b/companion/src/shared/autoprecisioncombobox.h new file mode 100644 index 000000000..4e143f286 --- /dev/null +++ b/companion/src/shared/autoprecisioncombobox.h @@ -0,0 +1,257 @@ +/* + * 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 _AUTOPRECISIONCOMBOBOX_H_ +#define _AUTOPRECISIONCOMBOBOX_H_ + +#include "genericpanel.h" + +#include +#include + +class AutoPrecisionComboBox: public QComboBox +{ + Q_OBJECT + //! \property minDecimals Determines the first list item + Q_PROPERTY(unsigned int minDecimals READ minDecimals WRITE setMinDecimals) + //! \property maxDecimals Determines the last list item + Q_PROPERTY(unsigned int maxDecimals READ maxDecimals WRITE setMaxDecimals) + //! \property padding If true, add trailing underscore placeholders to each list item + Q_PROPERTY(bool padding READ padding WRITE setPadding) + //! \property suffix Optional text suffix to each list value + Q_PROPERTY(QString suffix READ suffix WRITE setSuffix) + + public: + explicit AutoPrecisionComboBox(QWidget * parent = nullptr): + QComboBox(parent) + { + init(); + } + + explicit AutoPrecisionComboBox(unsigned int & field, unsigned int minDecimals = 0, unsigned int maxDecimals = 1, bool padding = false, QString suffix = "", QWidget * parent = nullptr, GenericPanel * panel = nullptr): + QComboBox(parent) + { + setField(field, minDecimals, maxDecimals, padding, suffix, panel); + init(); + } + + explicit AutoPrecisionComboBox(int & field, unsigned int minDecimals = 0, unsigned int maxDecimals = 1, bool padding = false, QString suffix = "", QWidget * parent = nullptr, GenericPanel * panel = nullptr): + QComboBox(parent) + { + setField(field, minDecimals, maxDecimals, padding, suffix, panel); + init(); + } + + inline int minDecimals() const { return m_minDecimals; } + inline int maxDecimals() const { return m_maxDecimals; } + inline bool padding() const { return m_padding; } + inline QString suffix() const { return m_suffix; } + + public slots: + void setField(int & field, unsigned int minDecimals = 0, unsigned int maxDecimals = 1, bool padding = false, QString suffix = "", GenericPanel * panel = nullptr) + { + m_field = reinterpret_cast(&field); + initField(minDecimals, maxDecimals, padding, suffix); + setPanel(panel); + } + + void setField(unsigned int & field, unsigned int minDecimals = 0, unsigned int maxDecimals = 1, bool padding = false, QString suffix = "", GenericPanel * panel = nullptr) + { + m_field = &field; + initField(minDecimals, maxDecimals, padding, suffix); + setPanel(panel); + } + + void setMinDecimals(unsigned int minDecimals) + { + m_minDecimals = rangecheckDecimals(minDecimals); + if (m_minDecimals > m_maxDecimals) + m_minDecimals = m_maxDecimals; + if (!m_lock) + updateList(); + } + + void setMaxDecimals(unsigned int maxDecimals) + { + m_maxDecimals = rangecheckDecimals(maxDecimals); + if (m_maxDecimals < m_minDecimals) + m_maxDecimals = m_minDecimals; + if (!m_lock) + updateList(); + } + + void setPadding(bool padding) + { + m_padding = padding; + if (!m_lock) + updateList(); + } + + void setSuffix(QString suffix) + { + m_suffix = suffix.trimmed(); + if (!m_lock) + updateList(); + } + + void setPanel(GenericPanel * panel) + { + m_panel = panel; + } + + void setValue(int value) + { + if (!m_field) + return; + const unsigned int val = (unsigned int)value; + if (*m_field != val) { + *m_field = rangecheckDecimals(val); + updateValue(); + emit valueChanged(); + } + } + + void setValue(unsigned int value) + { + if (!m_field) + return; + if (*m_field != value) { + *m_field = rangecheckDecimals(value); + updateValue(); + emit valueChanged(); + } + } + + void updateValue() + { + if (!m_field) + return; + if (!isValidDecimals(*m_field)) + return; + if (*m_field > m_maxDecimals) { + setMaxDecimals(*m_field); + } + const bool savedlock = setLocked(true); + setCurrentIndex(findData(*m_field)); + setLocked(savedlock); + } + + void setAutoIndexes() + { + for (int i = 0; i < count(); ++i) + setItemData(i, i); + updateValue(); + } + + signals: + void valueChanged(); + + protected slots: + void init() + { + connect(this, QOverload::of(&AutoPrecisionComboBox::currentIndexChanged), this, &AutoPrecisionComboBox::onCurrentIndexChanged); + } + + void initField(unsigned int minDecimals, unsigned int maxDecimals, bool padding, QString suffix) + { + const bool savedlock = setLocked(true); + setMinDecimals(minDecimals); + setMaxDecimals(maxDecimals); + setPadding(padding); + setSuffix(suffix); + setLocked(savedlock); + updateList(); + } + + void updateList() + { + const bool savedlock = setLocked(true); + unsigned int i; + int j; + clear(); + + for (i = APCB_DECIMALS_MIN, j = (int)m_maxDecimals; j >= 0; i++, j--) { + if (i >= m_minDecimals) { + QString str = QString("0.%1").arg(QString(i, '0')); + if (m_padding) + str.append(QString(j, '_')); + if (m_suffix != "") + str.append(QString(" %1").arg(m_suffix)); + addItem(str, i); + } + } + + setSizeAdjustPolicy(QComboBox::AdjustToContents); + setLocked(savedlock); + } + + void onCurrentIndexChanged(int index) + { + if (index < 0) + return; + if (m_field && !m_lock) { + *m_field = itemData(index).toUInt(); + if (m_panel) + emit m_panel->modified(); + emit valueChanged(); + } + } + + unsigned int rangecheckDecimals(unsigned int decimals) + { + unsigned int ret; + if (decimals < APCB_DECIMALS_MIN) + ret = APCB_DECIMALS_MIN; + else if (decimals > APCB_DECIMALS_MAX) + ret = APCB_DECIMALS_MAX; + else + ret = decimals; + return ret; + } + + bool isValidDecimals(unsigned int value) + { + if (value >= APCB_DECIMALS_MIN && value <= APCB_DECIMALS_MAX) + return true; + else + return false; + } + + bool setLocked(bool lock) + { + const bool ret = m_lock; + m_lock = lock; + return ret; + } + + protected: + constexpr static unsigned int APCB_DECIMALS_MIN = {0}; + constexpr static unsigned int APCB_DECIMALS_MAX = {6}; + + unsigned int * m_field = nullptr; + GenericPanel * m_panel = nullptr; + unsigned int m_minDecimals = 0; + unsigned int m_maxDecimals = 0; + bool m_padding = false; + QString m_suffix = ""; + bool m_lock = false; +}; + +#endif // _AUTOPRECISIONCOMBOBOX_H_ diff --git a/companion/src/shared/genericpanel.h b/companion/src/shared/genericpanel.h index 1ce8e906e..5351355b6 100644 --- a/companion/src/shared/genericpanel.h +++ b/companion/src/shared/genericpanel.h @@ -39,6 +39,7 @@ class GenericPanel : public QWidget friend class AutoHexSpinBox; friend class AutoLineEdit; friend class GVarGroup; + friend class AutoPrecisionComboBox; public: GenericPanel(QWidget *parent, ModelData * model, GeneralSettings & generalSettings, Firmware * firmware); diff --git a/companion/src/simulation/joystick.cpp b/companion/src/simulation/joystick.cpp index fdffd4bfb..fb6501a06 100644 --- a/companion/src/simulation/joystick.cpp +++ b/companion/src/simulation/joystick.cpp @@ -99,8 +99,9 @@ void Joystick::processEvents() axes[i] = moved; } } - else + else { axisRepeatTimers[i].restart(); + } } else { emit axisValueChanged(i, 0); diff --git a/companion/src/simulation/simulateduiwidgetTX16S.cpp b/companion/src/simulation/simulateduiwidgetTX16S.cpp index db1d5fa8b..76bfd1f33 100644 --- a/companion/src/simulation/simulateduiwidgetTX16S.cpp +++ b/companion/src/simulation/simulateduiwidgetTX16S.cpp @@ -34,7 +34,7 @@ SimulatedUIWidgetTX16S::SimulatedUIWidgetTX16S(SimulatorInterface *simulator, QW // add actions in order of appearance on the help menu act = new RadioUiAction(3, QList() << Qt::Key_Up, SIMU_STR_HLP_KEY_UP, SIMU_STR_HLP_ACT_MDL); - addRadioWidget(ui->rightbuttons->addArea(QRect(10, 0, 80, 35), "TX16S/right_mdl.png", act)); + addRadioWidget(ui->rightbuttons->addArea(QRect(40, 0, 110, 35), "TX16S/right_mdl.png", act)); m_mouseMidClickAction = new RadioUiAction(2, QList() << Qt::Key_Enter << Qt::Key_Return, SIMU_STR_HLP_KEYS_ACTIVATE, SIMU_STR_HLP_ACT_ROT_DN); addRadioWidget(ui->rightbuttons->addArea(QRect(45, 70, 100, 160), "TX16S/right_ent.png", m_mouseMidClickAction)); @@ -59,7 +59,7 @@ SimulatedUIWidgetTX16S::SimulatedUIWidgetTX16S(SimulatorInterface *simulator, QW m_scrollDnAction = new RadioUiAction(-1, QList() << Qt::Key_Plus << Qt::Key_Equal, SIMU_STR_HLP_KEY_PLS % "|" % SIMU_STR_HLP_MOUSE_DN, SIMU_STR_HLP_ACT_ROT_RGT); connectScrollActions(); - addRadioWidget(ui->leftbuttons->addArea(QRect(10, 252, 30, 30), "TX16S/left_scrnsht.png", m_screenshotAction)); + addRadioWidget(ui->leftbuttons->addArea(QRect(10, 245, 30, 30), "TX16S/left_scrnsht.png", m_screenshotAction)); m_backlightColors << QColor(47, 123, 227); diff --git a/companion/src/simulation/simulatorwidget.cpp b/companion/src/simulation/simulatorwidget.cpp index 798c8664b..d20e34cc7 100644 --- a/companion/src/simulation/simulatorwidget.cpp +++ b/companion/src/simulation/simulatorwidget.cpp @@ -699,9 +699,11 @@ void SimulatorWidget::restoreRadioWidgetsState() void SimulatorWidget::saveRadioWidgetsState(QList & state) { if (m_radioWidgets.size()) { - state.clear(); - foreach (RadioWidget * rw, m_radioWidgets) - state.append(rw->getStateData()); + if (g.simuSW()) { + state.clear(); + foreach (RadioWidget * rw, m_radioWidgets) + state.append(rw->getStateData()); + } } } diff --git a/companion/src/storage/appdata.h b/companion/src/storage/appdata.h index 3ffa7d688..a17b9c1ce 100644 --- a/companion/src/storage/appdata.h +++ b/companion/src/storage/appdata.h @@ -575,6 +575,7 @@ class AppData: public CompStoreObj PROPERTY4(bool, snapToClpbrd, "snapshot_to_clipboard", false) PROPERTY4(bool, autoCheckApp, "startup_check_companion", true) PROPERTY4(bool, autoCheckFw, "startup_check_fw", true) + PROPERTY4(bool, promptProfile, "startup_prompt_profile", false) PROPERTY(bool, enableBackup, false) PROPERTY(bool, backupOnFlash, true) diff --git a/companion/src/translations/companion_es.ts b/companion/src/translations/companion_es.ts index 61d6368a0..bdd44458d 100644 --- a/companion/src/translations/companion_es.ts +++ b/companion/src/translations/companion_es.ts @@ -11,22 +11,22 @@ Yes, controlled by a single channel - Si, controlado por un único canal + Sí, controlado por un único canal Yes, controlled by two channels - Si, controlado por dos canales + Sí, controlado por dos canales <br>First Aileron Channel: - <br>Canal Primer Alerón: + <br>Canal primer alerón: Second Aileron Channel: - Canal Segundo Alerón: + Canal segundo alerón: @@ -39,22 +39,22 @@ Yes, controlled by a single channel - Si, controlado por un único canal + Sí, controlado por un único canal Yes, controlled by two channels - Si, controlado por dos canales + Sí, controlado por dos canales <br>First Airbrake Channel: - <br>Primer Canal Aerofreno: + <br>Primer canal aerofreno: Second Airbrake Channel: - Segundo Canal Aerofreno: + Segundo canal aerofreno: @@ -63,22 +63,23 @@ Application Settings have been saved to %1 - + Los ajustes de la aplicación han sido grabados a +.%1 Could not save Application Settings to file "%1" - + No se han podido grabar los ajustes de la aplicación en el archivo "%1" because the file could not be saved (check access permissions). - + porque el archivo no se ha podido grabar (revisa los permisos). for unknown reasons. - + por causas desconocidas. @@ -86,104 +87,64 @@ Show this message again at next startup? - + ¿Mostrar este mensaje de nuevo en el siguiente inicio? AppPreferencesDialog - - - - - - - + + Edit Settings - Editar Ajustes + Editar ajustes - - - - - - - + + Radio Profile - Perfil de Radio + Perfil de radio - - - - - - - - + + + Default Channel Order - Orden Prederterminado Canales + Orden prederterminado canales - - - - - - - - + + + Build Options - Opciones Firmware + Opciones del firmware - - - - - - - - + + + Menu Language - Lenguaje Menú + Lenguaje de los menús - - - - - - - - + + + Default Stick Mode - Modo Prederterminado Sticks + Modo prederterminado sticks - - - - - - - - + + + Select Image - Seleccionar Imagen + Seleccionar imagen - - - - - - - - + + + Mode selection: Mode 1: @@ -203,1161 +164,712 @@ Mode 4: Right stick: Elevator, Rudder - Selección de Modo: + Selección de modo: Modo 1: - Stick Izquierdo: Elevador, Timón - Stick Derecho: Acelerador, Alerón + Stick izquierdo: Elevador, Timón + Stick derecho: Acelerador, Alerón Modo 2: - Stick Izquierdo: Acelerador, Timón - Stick Derecho: Elevador, Alerón + Stick izquierdo: Acelerador, Timón + Stick derecho: Elevador, Alerón Modo 3: - Stick Izquierdo: Elevador, Alerón - Stick Derecho: Acelerador, Timón + Stick izquierdo: Elevador, Alerón + Stick derecho: Acelerador, Timón Modo 4: - Stick Izquierdo: Acelerador, Alerón - Stick Derecho: Elevador, Timón + Stick izquierdo: Acelerador, Alerón + Stick derecho: Elevador, Timón - - - - - - - - + + + Mode 1 (RUD ELE THR AIL) Modo 1 (RUD ELE THR AIL) - - - - - - - - + + + Mode 2 (RUD THR ELE AIL) - Modo 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 + 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 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 + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + Select Folder - + Selecciona carpeta - - - - - - - - + + + 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 + Nombre de perfil - - - - - - - - + + + Clear Image - Limpiar Imagen + Limpiar imagen - - - - - - - - + + + Append version number to FW file name - Agregar el número de version al nombre de archivo de Firmware + 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 + Tipo de radio - - - - - - - - + + + Other Settings - Otros Ajustes + Otros ajustes - - - - - - - - + + + General Settings - Ajustes Generales + Ajustes generales - - - - - - - - + + + SD Structure path Estructura de archivos SD - - - - - - - - + + + Application Settings - Ajustes Aplicación + Ajustes de la aplicación - - - - - - - - + + + Show splash screen when Companion starts - Mostrar pantalla de inicion cuando Companion comience + 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 auromaticamente actualizaciones del firmware OpenTX + Comprobar automáticamente actualizaciones del firmware OpenTX - - - - - - - - + + + Splash Screen Library - Libreria de pantallas de inicio + Librería de pantallas de inicio - - - - - - - - + + + Google Earth Executable Ejecutable Google Earth - - - - - - - - + + + Only show user splash images - Mostrar solo pantallas de inicio del usuario + Mostrar sólo pantallas de inicio de usuario - - - - - - - - + + + Show user and companion splash images - Mostrar pantallas de inicio del usuario y companion + Mostrar pantallas de inicio de usuario y companion - - - - - - - - + + + User Splash Screens - Pantallas de Inicio del Usuario + Pantallas de inicio de usuario - - - - - - - - + + + Automatic Backup Folder - Carpeta copia de seguridad Automática + Carpeta copia de seguridad automática - - - - - - - - + + + Simulator Settings - Ajustes Simulador + 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 - - - - - - - - + + + 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 - Solo capturar a portapapeles - - - - - - - - - - - Remember simulator switch values - Recordar los valores de los switch en el simulador + Sólo capturar al portapapeles My Radio - Mi 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 tu carpeta de capturas + 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 encopntrado joysticks + No se han encontrado joysticks EMPTY: No radio settings stored in profile - VACIO: No se han guardado ajustes en el perfil de tu radio + VACÍO: No se han guardado ajustes en el perfil de tu radio AVAILABLE: Radio settings of unknown age - DISPONIBLE:Ajustes de radio de tiempo desconocido + DISPONIBLE:Ajustes de radio de antigüedad desconocida @@ -1367,7 +879,7 @@ Modo 4: Select your library folder - Selecciona tu carpeta de una carpeta + Selecciona tu carpeta de librerías @@ -1378,7 +890,7 @@ Modo 4: Select a folder for application logs - + Selecciona una carpeta para los reportes de la aplicación @@ -1386,44 +898,19 @@ Modo 4: Selecciona el ejecutable de Google Earth - + Select the folder replicating your SD structure - Selecciona la carpeta que replica la structura de tu tarjeta SD + Selecciona la carpeta que replica la estructura de tu tarjeta SD - + Open Image to load - Abrir imagen para cargar + Abre imagen para cargar - + Images (%1) - Imagenes (%1) - - - - - - Use releases (stable) - - - - - Use release candidates (testing) - - - - - - - Use nightly builds (unstable) - - - - - - Use releases and release candidates (testing) - + Imágenes (%1) @@ -1431,89 +918,90 @@ Modo 4: Error reading %1: %2 - + Error leyendo %1: %2 Cannot save EEPROM - + No se puede guardar la EEPROM Cannot open file %1: %2. - + No se puede abrir el archivo %1: +%2. Error writing file %1: %2. - Error escribiendo el archivo %1: + Error escribiendo el archivo %1: %2. Invalid binary EEPROM file %1 - + Archivo binario de la EEPROM no válido %1 Boards - + Left Horizontal - Izquierda Hrizontal + Izquierda horizontal - + Left Vertical - Izquierda Vertical + Izquierda vertical - + Right Vertical - Derecha Vertical - - - - Right Horizontal - Derecha Horizontal - - - - Aux. 1 - - - - - Aux. 2 - - - - - - Unknown - Desconocido + Derecha vertical - Rud - Rud + Right Horizontal + Derecha horizontal - Ele - Ele + Aux. 1 + - Thr - Thr + Aux. 2 + - + + + Unknown + Desconocido + + + + Rud + + + + + Ele + + + + + Thr + + + + Ail - Ail + @@ -1521,17 +1009,17 @@ Modo 4: Negative span - Amplitud negativa + Amp. negativa Mid value - Valor medio + Valor medio Positive span - Amplitud positiva + Amp. positiva @@ -1539,202 +1027,192 @@ Modo 4: Can't extract RADIO/radio.bin - + No se puede extraer RADIO/radio.bin Can't extract RADIO/models.txt - + No se puede extraer RADIO/models.txt Can't extract %1 - + No se puede extraer %1 Error loading models - + Error cargando modelos Channels - + Name Nombre - + Min - Min + Mín - + Max - Max + Máx - + Subtrim - Subtrim + - + Direction Dirección - + Curve Curva - + PPM Center Centro PPM - + Linear Subtrim Subtrim lineal - + CH%1 - + - + Popup menu available - + Menú emergente disponible - + --- - --- + - + INV - INV + - - &Copy - &Copiar + + Copy + Copiar - - &Cut - C&ortar + + Cut + Cortar - - &Paste - &Pegar + + Paste + Pegar - - &Delete - &Borrar + + Clear + Limpiar + + + + Insert + Insertar + + + + Delete + Borrar + + + + Move Up + Mover arriba + + + + Move Down + Mover abajo + + + + Clear All + Limpiar todo ChecklistDialog - - - - - - - + + Edit Checklist - + Editar lista de verificación - - - - - - - + + Line nn, Col nn - + Línea nn, Col nn - - - - - - - + + &Import... - + &Importar... - - - - - - - + + &Cancel - + &Cancelar - - - - - - - + + &OK - + - - - - - - - + + Please note, the maximum width displayable is radio model limited. Also, renaming the model will break the link to this checklist file. - + Ten en cuenta que el máximo ancho del display está limitado por el modelo de la radio. También renombrar el modelo rompe el link a este archivo de verificación. - - - - - - - + + File: unknown - + Archivo: desconocido Open Checklist - + Abrir lista de verificación Checklist Files (*.txt) - + Ficheros de verificación (*.txt) @@ -1743,43 +1221,47 @@ Modo 4: Model Checklist - + Lista de verificación del modelo Cannot open file for writing %1: %2. - + No se puede abrir el archivo para escritura %1: +%2. Cannot write to file %1: %2. - + No se puede escribir en el archivo %1: +%2. Cannot write file %1: %2. - No se puede escribir el archivo %1: + No se puede escribir el archivo %1: %2. Cannot open file %1: %2. - + No se puede abrir el archivo %1: +%2. Cannot read file %1: %2. - + No se puede leer el archivo %1: +%2. Line %1, Col %2 - + Línea %1, Col %2 @@ -1787,118 +1269,119 @@ Modo 4: OpenTX Companion - + Information - Información + Información Warning - Aviso + Aviso Error - Error + Error Application Settings - Ajustes Aplicación + Ajustes aplicación files - + archivos Radio and Models settings - + Ajustes de radio y modelos - + Select or create a file for exported Settings: - + Selecciona o crea un archivo para exportar los ajustes: - + Press the 'Retry' button to choose another file. - + Presiona el botón de 'Reintentar' para elegir otro archivo. - + Simulator for this firmware is not yet available - El simulador para este firmware ya no está disponible + El simulador para este firmware aún no está disponible - + Uknown error during Simulator startup. - + Error durante el arranque del simulador. - + Simulator Error - + Error del simulador - + Data Load Error - + Error de carga de datos - + Error occurred while starting simulator. - + Ha ocurrido un error al arrancar el simulador. <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 -&gt; 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>Bienvenido a OpenTX %1.</b></p><p>Como primer paso, por favor configura el perfil de radio inicial seleccionando el tipo de radio, el lenguaje y las opciones de firmware.</p><p>También puedes tomarte un tiempo para revisar las otras opciones disponibles en el cuadro de diálogo Ajustes que se muestra.</p><p>Después de guardar la configuración, te recomendamos que descargues el firmware más reciente para tu radio utilizando la opción de menú <i>Archivo -&gt; Descargar</i>.</p><p>Por favor visita <a href='http://www.open-tx.org'>open-tx.org</a> para últims noticies y documentación. Gracias pr elegir OpenTX!</p>- El equipo de OpenTX. <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><b>Gracias por actualizar a OpenTX %1.</b></p><p>Esta es una actualización mayor que añade y modifica muchas cosas, por favor asegúrate que lees cuidadosamente las notas de la version para entender los cambios y verificar que cada uno de tus modelos funciona correctamente.</p><p>Por favor visita <a href='http://www.open-tx.org'>open-tx.org</a> para las notas de la versión y otra documentación.</p>- El equipo de OpenTX. <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> - + <p>El tipo de radio en el perfil seleccionado no existe. Usando en su lugar el tipo predeterminado.</p> <p><b>¡Por favor, actualiza los ajustes del perfil!</b></p> The saved settings could not be imported, please try again or continue with current settings. - + Los ajustes guardados no pudieron ser importafos, por favor inténtalo de nuevo con los ajustes actuales. Import from File - + Importar desde archivo Import from v%1 - + Importar desde v%1 Do not import - + No importar We have found possible Companion settings backup file(s). Do you want to import settings from a file? - + Se ha encontrado archivo(s) de ajustes de Companion +¿Quieres importar los ajustes desde un archivo? Import settings from a file, or start with current values. - + Importar ajustes desde un archivo, o empezar con los valores actuales. @@ -1906,147 +1389,120 @@ Do you want to import settings from a file? Do you want to import them? If you have a settings backup file, you may import that instead. - + Se han encontrado ajutes de la versión de Companion: %1. +¿Quieres importarlos? + +Si tienes un archivo de backup, puedes importar en su lugar. Select %1: - + Selecciona %1: Save application settings to file... - + Guardar ajustes aplicación a archivo... Load application settings from file or previous version... - + Cargar ajustes de aplicación desde archivo o versión previa... Reset ALL application settings to default and remove radio profiles... - + Resetea TODOS los ajustes de la aplicación y eliminar los perfiles de radio... Exit before settings initialization and application startup. - + Salir antes de inicializar ajustes y arrancar aplicación. Print version number and exit. - + Muestra número de de versión y sale. Print this help text. - + Muestra este texto de ayuda. Reset ALL application settings to default values and remove radio profiles, are you sure? - + Resetea TODOS los ajustes a valores predeterminados y elimina los perfiles de radio, ¿estás seguro? Would you like to perform a backup first? - + ¿Quieres hacer una copia primero? Application settings were reset and saved. - + Los ajustes de la aplicación fueron reseteados y guadados. settings - + ajustes CompareDialog - - - - - - - + + Compare Models - + Comparar modelos - - - - - - - + + To compare models, drag and drop them anywhere in this window. - + Para comparar modelos, arrastra y suéltalos en esta ventana. - - - - - - - + + Close Cerrar - - - - - - - + + Style - + Estilo - - - - - - - + + Print Imprimir - - - - - - - + + Print to file Imprimir a archivo Unnamed Model %1 - + Modelo sin nombre %1 Click to remove this model. - + Presiona para eleminar este modelo. @@ -2056,7 +1512,7 @@ If you have a settings backup file, you may import that instead. Select PDF output file - Seleccionar archivo de salida PDF + Seleccionar archivo de salida PDF @@ -2064,7 +1520,7 @@ If you have a settings backup file, you may import that instead. OK, I understand. - OK, Entiendo. + OK, entiendo. @@ -2072,17 +1528,17 @@ If you have a settings backup file, you may import that instead. Write error - Error escritura + Error de escritura Cannot write %1 (reason: %2) - + No se puede escribir %1 (razón: %2) Cannot open %1 (reason: %2) - + No se puede abrir %1 (razón: %2) @@ -2090,55 +1546,55 @@ If you have a settings backup file, you may import that instead. OpenTX Contributors - + Colaboradores de OpenTX Honors go to Rafal Tomczak (RadioClone), Thomas Husterer (th9x) and Erez Raviv (er9x and eePe) - Los honores van a Rafal Tomczak (RadioClone), Thomas Husterer (th9x) y Erez Raviv (er9x y eePe) + Los honores son para Rafal Tomczak (RadioClone), Thomas Husterer (th9x) y Erez Raviv (er9x y eePe) OpenTX Blacklist - + Main developers - + Desarrolladores principales Translators - + Traductores Companies and projects who have donated to OpenTX - + Compañías y proyectos que han donado a OpenTX People who have donated to OpenTX - + Gente que ha donado a OpenTX Other contributors - + Otros colaboradores monthly - + mensualmente CurveData - + CV - + @@ -2146,17 +1602,17 @@ If you have a settings backup file, you may import that instead. Diff - Diff + Expo - Expo + Func - Func + @@ -2169,235 +1625,145 @@ If you have a settings backup file, you may import that instead. Diff(%1) - + Expo(%1) - + Function(%1) - Función(%1) + Función(%1) Curve(%1) - Curva(%1) + Curva(%1) Curves - - - - - - - + + Fixed X - X Fija + X fija - - - - - - - + + Custom X - X A medida + X personalizada - - - - - - - + + Lines - Lineas + Líneas - - - - - - - + + Smooth Suave - - - - - - - - - - - - - - + + + + Curve type - Tipo de Curva + Tipo de curva - - - - - - - + + Curve Creator - Creador de curva + Propiedades de la curva - - - - - - - + + Y at X=0 - Y a X=0 + Y en X=0 - - - - - - - + + Point size - + Tamaño punto - - - - - - - + + Y at X=100 - Y a X=100 + Y en X=100 - - - - - - - + + Both Ambos - - - - - - - + + x>0 - x>0 + - - - - - - - + + x<0 - x<0 + - - - - - - - + + Apply Aplicar - - - - - - - + + Side - Cara + Lado - - - - - - - + + Y at X=-100 - Y a X=-100 + Y en X=-100 - - - - - - - + + Coefficient Coeficiente - - - - - - - + + Curve name Nombre de la curva @@ -2409,7 +1775,7 @@ If you have a settings backup file, you may import that instead. Popup menu available - + Menú desplegable disponible @@ -2424,47 +1790,47 @@ If you have a settings backup file, you may import that instead. Single Expo - Expo Unico + Expo único Symmetrical f(x)=-f(-x) - Simetricas f(x)=-f(-x) + Simétricas f(x)=-f(-x) Symmetrical f(x)=f(-x) - Simetricas 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? @@ -2474,7 +1840,7 @@ If you have a settings backup file, you may import that instead. Not enough free points in EEPROM to store the curve. - No hay suficientes puntos en el EEPROM para guardar la curva. + No hay suficientes puntos libres en la EEPROM para guardar la curva. @@ -2482,234 +1848,239 @@ If you have a settings backup file, you may import that instead. GF - + SF - SF + Override %1 - Invalidar %1 + Invalidar %1 Trainer - Trainer + Entrenador Trainer RUD - Entrenador RUD + Entrenador RUD Trainer ELE - Entrenador ELE + Entrenador ELE Trainer THR - Entrenador THR + Entrenador THR Trainer AIL - Entrenador AIL + Entrenador AIL - Instant Trim - Trim Instantáneo + Trainer Channels + Canales entrenador - Play Sound - Reproducir Sonido + Instant Trim + Trim instantáneo - Haptic - Reproducir Haptic + Play Sound + Reproducir sonido - Reset - Resetear + Haptic + Reproducir haptic - Set Timer %1 - Ajustar temporizador %1 + Reset + Resetear - Vario - + Set Timer %1 + Ajustar temporizador %1 - Play Track - Reproducir Pista + Vario + Variómetro - Play Both - Reproducir Ambos + Play Track + Reproducir pista - Play Value - Reproducir Valor + Play Both + Reproducir ambos - Play Script - + Play Value + Reproducir valor - SD Logs - + Play Script + Reproducir script - Volume - Volumen + SD Logs + Reportes SD - Backlight - Luz de Fondo + Volume + Volumen - Screenshot - + Backlight + Luz de fondo - Background Music - Música de Fondo + Screenshot + Captura - Background Music Pause - Pausar Música de Fondo + Background Music + Música de fondo - Adjust %1 - + Background Music Pause + Pausar música de fondo - SetFailsafe Int. Module - + Adjust %1 + Ajustar %1 - SetFailsafe Ext. Module - + SetFailsafe Int. Module + Fijar failsafe módulo interno - RangeCheck Int. Module - + SetFailsafe Ext. Module + Fijar failsafe módulo externo - RangeCheck Ext. Module - + RangeCheck Int. Module + RangeCheck módulo interno - Bind Int. Module - + RangeCheck Ext. Module + RangeCheck módulo externo + Bind Int. Module + Bind módulo interno + + + Bind Ext. Module - + Bind módulo externo - + Timer1 - Temporizador1 - - - - Timer2 - Temporizador 2 + Temporizador 1 - Timer3 - Temporizador 3 + Timer2 + Temporizador 2 + Timer3 + Temporizador 3 + + + Flight - + Vuelo - + Telemetry - Telemetría + Telemetría - + Rotary Encoder - Codificador Rotativo + Codificador rotativo - + REa - + - + REb - + - + s - + - - - + + + <font color=red><b>Inconsistent parameter</b></font> - <font color=red><b>Parámetro Inconsistente</b></font> + <font color=red><b>Parámetro Inconsistente</b></font> - + Value - Valor + Valor - + played once, not during startup - + reproducido una vez, no durante el inicio - + repeat(%1s) - + repetir(%1s) - + DISABLED - + DESABILITADO - + CFN - + @@ -2717,7 +2088,7 @@ If you have a settings backup file, you may import that instead. Switch - Cambiar + Interruptor @@ -2737,269 +2108,210 @@ If you have a settings backup file, you may import that instead. Popup menu available - + Menú deplegable disponible SF%1 - SF%1 + GF%1 - + ON - 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 - - Value - Valor - - - - Source - - - - - GVAR - GVAR - - - - Increment - Incremento - - - - &Delete - &Borrar + + Copy + Copiar - &Copy - &Copiar + Cut + Cortar - &Cut - C&ortar + Paste + Pegar - &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 CustomizeSplashDialog - - - - - - - + + Transmitter Splash Screen Editor - Editor de la pantalla de inicio del transmisor + Editor de la pantalla de inicio de la radio - - - - - - - - - - - - - - + + + + Invert Invertir - - - - - - - - - - - - - - + + + + Load FW Cargar FW - - - - - - - - - - - - - - + + + + Load Pict - Cargar Imag + Cargar imag - - - - - - - - - - - - - - + + + + Load Profile - Cargar Perfil + Cargar perfil - - - - - - - - - - - - - - + + + + Save Guardar - - - - - - - - - - - - - - + + + + Open Splash Library - Abrir libreria de pantallas de inicio + Abrir librería de pantallas de inicio - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + ... FW: %1 - + Pict: %1 - + Profile image - Nombre de Perfil + Nombre de imagen Open Firmware File - Abrir archivo de Firmware + Abrir archivo de firmware Can not load embedded image from firmware file %1. - No se pueden cargar la imagen incrustada el archivo de firmware %1. + No se puede cargar la imagen incrustada en el archivo de firmware %1. @@ -3009,7 +2321,7 @@ If you have a settings backup file, you may import that instead. Images (%1) - Imagenes (%1) + Imágenes (%1) @@ -3029,7 +2341,7 @@ If you have a settings backup file, you may import that instead. File Saved - Archivo Guardado + Archivo guardado @@ -3049,7 +2361,7 @@ If you have a settings backup file, you may import that instead. File Save Error - Error Guardado de Archivo + Error en el guardado del archivo @@ -3062,22 +2374,22 @@ If you have a settings backup file, you may import that instead. 90 - 90 + 120 - 120 + 120x - 120x + 140 - 140 + @@ -3085,288 +2397,186 @@ If you have a settings backup file, you may import that instead. Conversion error on field %1 - + 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 solo aceta %1 puntos en todas las curvas + OpenTX sólo acepta %1 puntos en todas las curvas - + OpenTx only accepts %1 points in all curves - OpenTx solo aceta %1 puntos en todas las curvas + 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 en esta placa no acepta esa función - + OpenTX doesn't accept this radio protocol - OpenTX en esta placa no acepta este protocolo de radio + OpenTX no acepta este protocolo de radio DebugOutput - - - - - - - - - + + Debug Output - + Salida de depuración - - - - - - - - - + + <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> - - - - - - - - - + + Filter: - + Filtro: - - - - - - - - - + + <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> +Para <b>eliminar una entrada recordada</b> desde la lista de filtros, primero elígelo, y entonces presiona la combinación de teclas <code>Shift-Delete</code> (o <code>Shift-Backspace</code>) .</p></body></html> - - - - - - - - - + + Buffer: - + Buffer: - - - - - - - - - + + Number of lines to keep in display. - + Número de líneas a mantener en display. - - - - - - - - - + + Filter &Help - + &Ayuda filtros - - - - - - - - - + + Show information about using the filter. - + Muestra información acerca del uso de filtros. - - - - - - - - - + + Word &Wrap - + Ajuste de &línea - - - - - - - - - + + Toggle word wrapping on/off. - + Habilita/desabilita ajuste de línea. - - - - - - - - - + + &Clear - + &Limpiar - - - - - - - - - + + Clear the output window of all text. - + Limpia de texto la ventana de salida. - - - - - - - - - + + Enable &Filter - + Habilitar &filtro - - - - - - - - - + + Turn the filter on/off. - + Apaga/enciende el filtro. - + <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>El filtro admite dos tipos de sintaxis: coincidencia básica con comodines comunes y expresiones regulares Perl-style (<code>pcre</code>).</p><p>Por defecto, un filtro solo mostrará líneas que coinciden (<b>inclusivo</b>). Para hacer un filtro <b>exclusivo</b> que elimine la lineas con coincidencias, prefija la expresión del filtro con un <kbd>!</kbd> (símbolo de exclamación).</p><p>Para usar <b>expresiones regulares</b> (RegEx), prefija el filtro de texto con un <kbd>/</kbd> (barra oblicua) o <kbd>^</kbd> (et). <ul><li>Pon el <kbd>/</kbd> o <kbd>^</kbd> después del indicador exclusivo <kbd>!</kbd> si estás usando uno.</li><li> Por defecto, la coincidencia distingue entre mayúsculas y minúsculas. Para hacerlo insensible, agrega el operador típico<kbd>/i</kbd> (barra invertida) al final del RegEx.</li><li>Si usas un et (^) para indicar RegEx, se convertirá en parte del Reg. Ex. (esto es, coincidencia desde el incio de línea).</li><li>Si el RegEx no es válido, el campo de edición del filtro mostrará un borde rojo y no se podrá habilitar el filtro.</li><li>Encuentra un recurso útil para probar RE (con una referencia completa) en <a href="http://www.regexr.com/">http://www.regexr.com/</a></li></ul></p><p>Para usar <b>coincidencia básica</b> simplemente teclee cualquier texto.<ul><li>Comodines: <kbd>*</kbd> (asterisco) coincidencia de ningúno o más caracter(es), y <kbd>?</kbd> (símbolo de interrogación) coincidecia de caracteres individuales.</li><li>La coincidecia es insensible a mayús/minus.</li><li>La coincidencia siempre empieza desde el inicio de la línea de reporte. Para ignorar caracteres al inicio, usa un comodín de comienzo <kbd>*</kbd>.</li><li>De final <kbd>*</kbd> está siempre implícito (esto es, cualquier coincidecia hasta el final de la línea de reporte). Para evitar esto, use ub RegEx.</li><li>Puedes hacer coincidir con caracteres comodines prefijándolos con el carácter <kbd>\</kbd> (barra invertida) (ej. "foo\*bar" coincide "foo*bar").</li></ul></p><p>Después de <b>editar texto</b>, presiona la tecla ENTER o TAB (o haz click fuera del texto para actualizar el filtro.</p><p>Para <b>eliminar una entrada</b> de la lista de selección de filtro, primero selecciónala, y mientras estás en la linea del editor pulsa la combinación de teclas <kbd>Shift-Delete</kbd> (o <kbd>Shift-Backspace</kbd>). Los filtros predeterminados no se pueden eliminar. Se guardan hasta 50 filtros.</p></body></html> - + Debug Console Filter Help - + Ayuda del filtro de la consola de depuración DownloadDialog - - - - - - - + + Downloading: - Descargando: + Descargando: Unable to save the file %1: %2. - No se puede guardar el archivo %1: %2. + No se puede guardar el archivo %1: %2. Download failed: %1. - Descarga fallida: %1. + Descarga fallida: %1. @@ -3374,85 +2584,87 @@ To <b>remove a remembered entry</b> from the filter list, first cho Possible causes for this: - + Posibles causas de esto: - Eeprom is from a newer version of OpenTX - + - Eeprom es de una versión más nueva de OpenTX - Eeprom is not from OpenTX - + - Eeprom no es de OpenTX - 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! + Para mantener tu archivo original como un backup, por favor elige Archivo -> Guarda Como especificando un nombre diferente. @@ -3460,12 +2672,12 @@ To <b>remove a remembered entry</b> from the filter list, first cho Unable to open %1: %2 - + No se puede abrir %1: %2 Invalid EEPROM file %1 - + Fichero EEPROM %1 no válido @@ -3473,12 +2685,12 @@ To <b>remove a remembered entry</b> from the filter list, first cho <br>First Elevon Channel: - <br>Primer canal de Elevon: + <br>Primer canal de elevón: Second Elevon Channel: - Segundo canal de Elevon: + Segundo canal de elevón: @@ -3486,25 +2698,20 @@ To <b>remove a remembered entry</b> from the filter list, first cho INP - + (@%1) - + ExpoDialog - - - - - - - + + Weight Peso @@ -3512,257 +2719,147 @@ To <b>remove a remembered entry</b> from the filter list, first cho - - - - - - - - - - - - - - - - - - - - - + + + + + + GV - GV + - - - - - - - + + Input name Nombre entrada - - - - - - - + + Flight modes Modos de vuelo - - - - - - - + + Switch - Switch + Interruptor - - - - - - - + + Source - Origen + Fuente - - - - - - - + + Line name - Nombre de linea + Nombre de línea - - - - - - - + + Stick Side - Lado Stick + Lado stick - - - - - - - + + Scale Escala - - - - - - - + + Include Trim - Incluir Trim + Incluir trim - - - - - - - + + No - No + - - - - - - - + + Yes - Si + Sí - - - - - - - + + Curve Curva - - - - - - - + + Curve applied to the source. - Curva aplicada al origen. + Curva aplicada a la fuente. - - - - - - - + + Offset Offset - - - - - - - + + The source for the mixer - El origen de la mezcla + La fuente de la mezcla - - - - - - - + + NEG - NEG + - - - - - - - + + Source for the mixer. - Origen para la mezcla. + Fuente para la mezcla. - - - - - - - + + Switch used to enable the line. If blank then the input is considered to be "ON" all the time. - Switch usado para activar la linea. -Si está en blanco entonces las entradas son consideradas como ON todo el tiempo. + Interruptor usado para activar la linea. +Si está en blanco entonces las entradas son consideradas ON todo el tiempo. - - - - - - - + + POS - POS + - - - - - - - + + ALL TODO @@ -3774,22 +2871,22 @@ Si está en blanco entonces las entradas son consideradas como ON todo el tiempo Popup menu available - + Disponible menú desplegable Clear All - + Limpiar todo Set All - + Fijar todo Invert All - + Invertir todo @@ -3797,57 +2894,57 @@ Si está en blanco entonces las entradas son consideradas como ON todo el tiempo Select All - + Selecciona todo Copy selection as TAB-delimited text - + Copiar selección como texto delimitado por TAB Copy selection as cooma-delimited text (CSV) - + Copiar selección como texto delimitado por comas (CSV) Copy selection as pipe-delimited text - + Copiar selección como texto delimitado por barras verticales Copy selection as HTML - + Copiar selección como HTML Save selection to file - + Guardar seleccíon a archivo Tab-delimited text - + Texto delimitado por TAB Comma-delimited text - + Texto delimitado por comas Pipe-delimited text - + Texto delimitado por barras verticales HTML - + Save to file - + Guardar a archivo @@ -3855,22 +2952,22 @@ Si está en blanco entonces las entradas son consideradas como ON todo el tiempo Throttle Channel: - Canal de Acelerador: + Canal de acelerador: Yaw Channel: - Canal de Yaw: + Canal de viraje: Pitch Channel: - Canal de pitch: + Canal de inclinación: Roll Channel: - Canal de roll: + Canal de balanceo: @@ -3878,607 +2975,604 @@ Si está en blanco entonces las entradas son consideradas como ON todo el tiempo Synchronize Files - + Sincroniza ficheros Are you sure you wish to abort the sync? - + ¿Seguro que quieres abortar la sincronización? Source Folder: - + Carpeta de origen: Destination Folder: - + Carpeta de destino: %1%2 Both directions, to destination folder first - + %1%2 ambas direcciones, a la carpeta de destino primero %1%2 Both directions, to source folder first - + %1%2 ambas direcciones, a la carpeta de origen primero %1 Only from source folder to destination folder - + %1 Sólo de la carpeta de origen a la carpeta de destino %1 Only from destination folder to source folder - + %1 Sólo de la carpeta de destino a la carpeta de origen How to handle overwriting files which already exist in the destination folder. - + Como manejar sobreescritura de archivos que ya existen en la carpte de destino. Copy only if newer and different (compare contents) - + Sólo copiar si es más reciente y diferente (comparar contenido) Copy only if newer (do not compare contents) - + Sólo copiar si más reciente (no comparar contenido) Copy only if different (ignore file time stamps) - + Copiar si es diferente (ignora marcas de tiempo del archivo) Always copy (force overwite existing files) - + Siempre copia (fuerza sobreescritura de archivos existentes) Any size - + Cualquier tamaño Skip files larger than this size. Enter zero for unlimited. - + Omitir archivos mayores de este tamaño. Cero para ilimitado. Minimum reporting level. Events of this type and of higher importance are shown. WARNING: High log rates may make the user interface temporarily unresponsive. - + Mínimo nivel de reporte. Eventos de este tipo y de mayor importancia son mostrados. +ADVERTENCIA: Altos niveles de reporte pueden hace que la interfaz de usuario no responda temporalemente. Skipped - + Omitido Created - + Creado Updated - + Actualizado Errors Only - + Sólo errores Test-run only - + Sólo Test-run Run as normal but do not actually copy anything. Useful for verifying results before real sync. - + Ejecución normal pero no copia nada. Útil para verificar resultados antes de una sincronización real. Log Level: - + Nivel de reporte: Filters: - + Filtros: 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. - + El filtro "Incluye" sólo copiará archivos que coincidan con el patrón(es). +El filtro "Excluye" omitirá archivos que coincidan con el patrón(es). +El filtro Incluye es evaluado primero. One or more file pattern(s) to exclude, separated by commas. Blank means exclude none. ?, *, and [...] wildcards accepted. - + Uno o más patrones de archivos a excluir, separados por comas. +Vacío significa incluir todos. Comodines ?, *, y [...] aceptados. One or more file pattern(s) to include, separated by commas. Blank means include all. ?, *, and [...] wildcards accepted. - + Uno o más patrones de archivos a incluir, separados por comas. +Vacío significa incluir todos. Comodines ?, *, y [...] aceptados. Include: - + Incluye: Exclude: - + Excluye: Case sensitive - + Distingue mayús/minus Follow links - + Sigue links Include hidden - + Incluye ocultos Recursive - + Recursivo Skip empty - + Omitir vacíos Apply filters - + Aplica filtros Filter Options: - + Opciones de filtro: Folder Options: - + Opciones de carpeta: Options - + Opciones Show extra options - + Muestra opciones extra Reset to defaults - + Resetear a predeterminados Close - Cerrar + Cerrar Sync. Direction: - + Dirección de sinc: Existing Files: - + Archivos existentes: Max. File Size: - + Max. tamaño archivo: MB - + KB - + Abort - + Abortar Start - Comenzar + Iniciar 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>; Creados: <b>%2</b>; Actualizados: <b>%3</b>; Omitidos: <b>%4</b>; Errores: <font color=%6><b>%5</b></font>; Current: <b>%1</b> of - + Actual: <b>%1</b> de Source folder not found. - + Carpeta de origen no encontrada. Destination folder not found. - + Carpeta de destino no encontrada. Source and destination folders are the same. - + Carpetas de origen y destino son las mismas. Firmware - + Channel values displayed in us - Visualizar los valores de canal en us + Visualiza los valores de canal en us - + No OverrideCH functions available - No hay funciones OverrideCH disponibles + Sin funciones OverrideCH - + Possibility to enable FAI MODE (no telemetry) at field - - - - - FAI MODE (no telemetry) always enabled - - - - - Removes D8 FrSky protocol support which is not legal for use in the EU on radios sold after Jan 1st, 2015 - + 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 - Desactivar el menú de HELI y el soporte de mezcla de cíclico + Desactiva el menú de HELI y el soporte de mezcla de cíclico - - + + Disable Global variables - Desactivar las variables Globales + Desactiva las variables globales - - + + Enable Lua custom scripts screen - - - - - Use alternative SQT5 font - Usar fuente alternativa SQT5 - - - - Pots use in menus navigation - Usar potenciómetros en los menús de navegación - - - - FrSky Taranis X9D+ - - - - - Support for PPM internal module hack - - - - - Enable non certified firmwares - - - - - Disable RAS (SWR) - - - - - FrSky Taranis X9D+ 2019 - - - - - FrSky Taranis X9D - - - - - Haptic module installed - Módulo Haptic instalado - - - - FrSky Taranis X9E - - - - - Confirmation before radio shutdown - - - - - Horus gimbals installed (Hall sensors) - - - - - 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 - - - - - 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 moviendolo - - - - In model setup menus automatically set switch by moving the control - En el menú de ajuste de modelo se selecciona automáticamente el switch de control moviendolo - - - - No graphical check boxes and sliders - Sin casillas de verificación ni sliders gráficos - - - - Battery graph - Gráfico batería + Habilita la pantalla de Lua custom scripts - Don't use bold font for highlighting active items - No usar la fuente negrita para destacar elementos activos + Use alternative SQT5 font + Usa la fuente alternativa SQT5 - - - Support for ACCESS internal module replacement - + + 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 + + + + + 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 - FrSky Horus X10 Express - + Horus gimbals installed (Hall sensors) + Gimbals Horus instalados (sensores Hall) - - Jumper T12 - + + FrSky Taranis X9-Lite + - - Enable non certified R9M firmwares - + + FrSky Taranis X7 / X7S + - - Turnigy 9XR with m128 chip - + + FrSky Taranis X-Lite S/PRO + - - Turnigy 9XR - - - - - 9X with stock board - - - - - Enable resetting values by pressing up and down at the same time - Activar el reseteo de valores presionando up y down al mismo tiempo - - - - 9X with stock board and m128 chip - - - - - 9X with AR9X board - - - - - 9X with Sky9x board - - - - - 9X with Gruvin9x board - + + FrSky Taranis X-Lite + + FrSky Horus X10 / X10S + + + + + 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 + + + + + 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 - - - - - - - + + Downloads Descargas - - - - - - - + + Check for updates - Comprobar Actualizaciones + Comprobar actualizaciones - - - - - - - + + Firmware - Firmware + - - - - - - - + + Download firmware - + Descargar firmware - - - - - - - + + Download SD contents - + Descargar contenido SD - - - - - - - + + Latest Download - Última Descarga + Última descarga Unknown - Desconocido + Desconocido @@ -4486,508 +3580,373 @@ Blank means include all. ?, *, and [...] wildcards accepted. No - No + Yes, controlled by a single channel - Si, controlado por un único canal + Sí, controlado por un único canal Yes, controlled by two channels - Si, controlado por dos canales + Sí, controlado por dos canales <br>First Flap Channel: - <br>Canal del primer Flap: + <br>Canal del primer flap: Second Flap Channel: - Canal del segundo Flap: + Canal del segundo flap: FlashEEpromDialog - - - - - - - + + Write Models and Settings to Radio - Escribir Modelos y Ajustes a la Radio + Escribir modelos y ajustes a la radio - - - - - - - + + Load... - + Cargar... - - - - - - - + + Current Profile - Perfil Actual + Perfil actual - - - - - - - + + Allows Companion to write to older version of the firmware - Permitir a Companion escribir a las versiones viejas de firmware + Permite a Companion escribir en las versiones anteriores de firmware - - - - - - - + + Check Firmware compatibility - Comprobar la compatibilidad del firmware + Comprobar la compatibilidad del firmware - - - - - - - + + <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> - + <html><head/><body><p>Guarda una copia de la eeprom a la carpeta de backup especificada en los ajustes de Companion antes de escribir el modelo actual en la radio.</p></body></html> - - - - - - - + + Backup before Write - + Guadar antes de escribir - - - - - - - + + <html><head/><body><p>Modify calibration parameters using settings from current profile</p></body></html> - <html><head/><body><p>Modificar los parámetros de calibración utilizando la configuración de perfil actual</p></body></html> + <html><head/><body><p>Modifica los parámetros de calibración utilizando la configuración de perfil actual</p></body></html> - - - - - - - + + Patch calibration setting from profile - Arreglar los ajustes de calibración desde el perfil + Arreglar los ajustes de calibración desde el perfil - - - - - - - + + <html><head/><body><p>Modify HW parameters using settings from current profile</p></body></html> - <html><head/><body><p>Modificar los parámetros de HW usando los ajustes del perfil actual</p></body></html> + <html><head/><body><p>Modifica los parámetros de HW usando los ajustes del perfil actual</p></body></html> - - - - - - - + + Patch HW settings from profile - + Arreglar los ajustes de HW desde el perfil - - - - - - - + + Cancel - Cancelar + Cancelar - - - - - - - + + Write to TX - Escribir al TX + Escribir al TX Current profile: %1 - + Perfil actual: %1 Choose Radio Backup file - Elegir archivo de copia de seguridad de la radio + Elegir archivo de copia de seguridad de la radio Wrong radio calibration data in profile, Settings not patched - Datos de calibración de radio incorrectos en el perfil, ajustes no corregidos + Datos de calibración de radio incorrectos en el perfil, ajustes no corregidos Wrong radio setting data in profile, Settings not patched - Datos de ajustes de radio incorrectos en el perfil, ajustes no corregidos + Datos de ajustes de radio incorrectos en el perfil, ajustes no corregidos Cannot write file %1: %2. - No se puede escribir el archivo %1: + No se puede escribir el archivo %1: %2. Error writing file %1: %2. - Error escribiendo el archivo %1: + Error escribiendo el archivo %1: %2. The radio firmware belongs to another product family, check file and preferences! - El firmware de la radio pertenece a otro producto, ¡comprueba el archivo y las preferencias! + El firmware de la radio pertenece a otro producto, ¡comprueba el archivo y las preferencias! The radio firmware is outdated, please upgrade! - El firmware de la radio está obsoleto, ¡por favor actializalo! + El firmware de la radio está obsoleto, ¡por favor actualízalo! Cannot check Models and Settings compatibility! Continue anyway? - ¡No se pueden comprobar la compatibilidad de Modelos y Ajustes! ¿Continuar de todas maneras? + ¡No se puede comprobar la compatibilidad de modelos y ajustes! ¿Continuar de todas maneras? FlashFirmwareDialog - - - - - - - + + Flash Firmware - + Flash firmware - - - - - - - + + Load... - + Cargando... - - - - - - - + + Date & Time - Fecha & Hora + Fecha & Hora - - - - - - - + + Variant - Variante + Variante - - - - - - - + + Version - + Versión - - - - - - - + + Use profile start screen - Usar la pantala de inicio del perfil + Usar la pantalla de inicio del perfil - - - - - - - + + Use firmware start screen - Usar la pantalla de inicio del firmware + Usar la pantalla de inicio del firmware - - - - - - - + + Use library start screen - Usar la libreria de pantalla de inicio + Usar la librería de pantalla de inicio - - - - - - - + + Use another start screen - Usar otra pantalla de inicio + Usar otra pantalla de inicio - - - - - - - + + Allows Companion to write to older version of the firmware - Permitir a Companion escribir a las versiones viejas de firmware + Permitir a Companion escribir a las versiones anteriores de firmware - - - - - - - + + Check Hardware compatibility - + Verificar compatibilidad del hardware - - - - - - - + + Backup and restore Models and Settings - Copia de seguridad y restauración de Modelos y Ajustes + Copia de seguridad y restauración de modelos y ajustes - - - - - - - + + Cancel - Cancelar + Cancelar - - - - - - - + + Write to TX - Escribir al TX + Escribir al TX Open Firmware File - Abrir archivo de Firmware + Abrir archivo de firmware %1 may not be a valid firmware file - %1 puede no ser un archivo de firmware válido + %1 puede no ser un archivo de firmware válido The firmware file is not valid. - El archivo de firmware no es válido. + 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. + No hay imagen de pantalla de inicio en el archivo de firmware. Profile image %1 is invalid. - El perfil de imagen %1 es inválido. + El perfil de imagen %1 no es válido. Open image file to use as radio start screen - Abir archivo de imagen para usar de pantalla de inicio de la radio + Abrir archivo de imagen para usar de pantalla de inicio de la radio Images (%1) - Imagenes (%1) + Imágenes (%1) Image could not be loaded from %1 - La imagen no puede ser cargada desde %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 + 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 + No se puede guardar el firmware personalizado Write Firmware to Radio - Escribir Firmware a la Radio + Escribir firmware a la radio Firmware check failed - + Ha fallado la verificación del firmware Could not check firmware from radio - + No se puede verificar el firmware de la radio New firmware is not compatible with the one currently installed! - + ¡El nuevo firmware no es compatible con el instalado actualmente! Conversion failed - Coversion fallida + Coversión fallida Cannot convert Models and Settings for use with this firmware, original data will be used - No se pueden convertir los Modelos y Ajustes para usar con este firmware, se usarán los datos originales + No se puede convertir los modelos y ajustes para usar con este firmware, se usarán los datos originales Restore failed - Restauración fallida + 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 + 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 @@ -4995,58 +3954,58 @@ Blank means include all. ?, *, and [...] wildcards accepted. Executable %1 not found - + 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 + 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 + 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 + Esto es: OpenTX para placas Gruvin9x Your radio uses a %1 CPU!!! Please check advanced burn options to set the correct cpu type. - Tu radio usa un %1 CPU!!! + Tu radio usa un %1 CPU!!! -Por favor comprueba en las opciones avanzadas de gravado el tipo correcto de cpu. +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. - Tu radio usa un %1 CPU!!! + Tu radio usa un %1 CPU!!! Por favor elige el tipo de firmware apropiado para programarlo. @@ -5055,211 +4014,205 @@ Por favor elige el tipo de firmware apropiado para programarlo. You are currently using: %1 - + 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 FlightMode - - - - - - - + + Fade In - + Transición entrada - - - - - - - + + Fade Out - + Transición salida - - - - - - - + + Name Nombre - - - - - - - + + Switch - Switch + Interruptor + + + + + + trim6 + + + + + + + trim5 + FlightModeData - + FM - + FlightModePanel - + Rotary Encoder %1 - Codificador Rotativo %1 + Codificador rotativo %1 - + Name - Nombre + Nombre - + Value source - + Valor fuente - + Value - Valor + Valor + + + + GVAR%1 + - GVAR%1 - GVAR%1 - - - Popup enabled - Popup activado + Menú desplegable activado Popup menu available - + Menú desplegable disponible - + Trim disabled - Trim desactivado + Trim desactivado - + Own Trim - Trim propio + Trim propio - + Use Trim from Flight mode %1 - Usar Trim para el modo de vuelo %1 + Usar trim para modo de vuelo %1 - + Use Trim from Flight mode %1 + Own Trim as an offset - Usar Trim para el modo de vuelo %1 + Trim propio com un compensador - - - - Unit - Unidad - - - - Prec - + Usar trim para modo de vuelo %1 + trim propio con compensador - Min - + Unit + Unidad + Prec + + + + + Min + Mín + + + Max - + Máx - + 0._ - + - + 0.0 - 6P {0.0?} + - - + + &Clear - + &Limpiar - - + + 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 + Modo de vuelo %1 - + (%1) - (%1) + - + (default) - (Predeterminado) + (predeterminado) @@ -5267,17 +4220,17 @@ Actualmente estás usando: Has Flybar - Tiene Flybar + Tiene flybar Flybarless - Flybarless + Flybar: - Flybar: + @@ -5285,17 +4238,17 @@ Actualmente estás usando: Yellow - Amarillo + Amarillo Orange - Naranja + Naranja Red - Rojo + Rojo @@ -5304,37 +4257,27 @@ Actualmente estás usando: V - + --- - --- + 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; } @@ -5348,29 +4291,31 @@ 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-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;">Lee los fuses actuales en el controlador 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;">Estados apropiados para </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 borrar fuse no fijado: 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 borra fuse fijado: 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;">Estados apropiados para 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 borrar fuse no fijado: 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 borrar fuse fijado: D7, 19, FC</span></p></body></html> - - - - - - - + + Read Fuses - Leer 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; } @@ -5386,31 +4331,35 @@ p, li { white-space: pre-wrap; } <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 &quot;dealing with Fuse Bricks&quot;.</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;">Resetear fusibles</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;">Los fusibles en el AVR le dicen cómo comportarse. Al presionar este botón, los fusibles tienen los parámetros predeterminados necesarios en el FW. Estos parámetros son diferentes para el stock y 4,1 MB, verifique que haya seleccionado el tipo de procesador apropiado en las preferencias. </span> </p> +<p style = "- qt-parameter-type: empty; margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-block-indent: 0; text-indent : 0px; familia de fuentes: 'MS Shell Dlg 2'; tamaño de fuente: 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;"> Este botón también establece la "Protección EEPROM" Fusible. </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;"> Esto evita que se borre la EEPROM cuando se escribe la memoria flash. </span> </p> +<p style = "- qt-parameter-type: empty; margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-block-indent: 0; text-indent : 0px; familia de fuentes: 'MS Shell Dlg 2'; tamaño de fuente: 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 = "familia-fuente: 'MS Shell Dlg 2'; tamaño de fuente: 8pt; peso de fuente: 600; decoración de texto: subrayado;"> ADVERTENCIA </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;"> La configuración de los fusibles puede ocasionar problemas e incluso un bloqueo total de tu controlador. Haz esto solo si sabes lo que estás haciendo. </span> </p> +<p style = "- qt-parameter-type: empty; margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-block-indent: 0; text-indent : 0px; familia de fuentes: 'MS Shell Dlg 2'; tamaño de fuente: 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;"> En caso de duda, consulta la página del proyecto o el 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;"> Si quedas bloqueado, busca en google para & quot; tratar con Fuse Bricks & quot ;. </span> </p> </body> </html> - - - - - - - + + Reset Fuses EEPROM - PROTECT - Resetear Fuses + Resetear fusibles 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; } @@ -5426,30 +4375,35 @@ p, li { white-space: pre-wrap; } <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 &quot;dealing with Fuse Bricks&quot;.</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;">Resetear fusibles</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;">Los fusibles en el AVR te dicen cómo comportarse. Al presionar este botón, los fusibles tienen los parámetros predeterminados necesarios en </span> <span style = "font-family: 'MS Shell Dlg 2'; font-size: 8pt;"> FW. Estos parámetros son diferentes para el stock y 4,1 MB, verifique que haya seleccionado el tipo de procesador apropiado en las preferencias. </span> </p> +<p style = "- qt-parameter-type: empty; margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-block-indent: 0; text-indent : 0px; familia de fuentes: 'MS Shell Dlg 2'; tamaño de fuente: 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;"> Este botón también borra la "protección EEPROM" Fusible. </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;"> Esto causa el borrado de la EEPROM cuando se escribe la memoria flash. </span> </p> +<p style = "- qt-parameter-type: empty; margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-block-indent: 0; text-indent : 0px; familia de fuentes: 'MS Shell Dlg 2'; tamaño de fuente: 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 = "familia-fuente: 'MS Shell Dlg 2'; tamaño de fuente: 8pt; peso de fuente: 600; decoración de texto: subrayado;"> ADVERTENCIA </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;"> La configuración de los fusibles puede ocasionar problemas e incluso un bloqueo total de su controlador. Haz esto solo si sabes lo que estás haciendo. </span> </p> +<p style = "- qt-parameter-type: empty; margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-block-indent: 0; text-indent : 0px; familia de fuentes: 'MS Shell Dlg 2'; tamaño de fuente: 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;"> En caso de duda, consulta la página del proyecto o el 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;"> Si quedas bloqueado, busca en google para & quot; tratar con Fuse Bricks & quot ;. </span> </p> </body> </html> - - - - - - - + + Reset Fuses EEPROM - DELETE - + Resetear fusibles +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; } @@ -5458,18 +4412,24 @@ p, li { white-space: pre-wrap; } <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> - + <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;">AVISO</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;">Cambiar los fuses de la radio puede estropear la 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;">Continúa sólo si sabes lo que estás haciendo.</p></body></html> Reset Radio Fuses - + Resetear fusibles de la radio Read Fuses from Radio - + Leer fusibles de la radio @@ -5477,67 +4437,57 @@ p, li { white-space: pre-wrap; } % - + ? - + 0._ - + 0.0 - 6P {0.0?} + ?.? - + GV - GV + Own value - Valor propio + Valor propio Flight mode %1 value - Valor modo de vuelo%1 + Valor modo de vuelo %1 GeneralEdit - - - - - - - + + Radio settings - + Ajustes radio - - - - - - - + + General settings used throught the transmitter. These will be relevant for all models in the same EEPROM. Ajustes generales usados a través del transmisor. @@ -5551,46 +4501,36 @@ Estos puede ser relevantes para todos los modelos en el mismo EEPROM. Trainer - Trainer + Entrenador - - - - - - - + + Store calib. and hw settings in selected profile - Guardar calib. y los ajustes de hw en el perfil seleccionado + Guardar calib. y ajustes hw en el perfil seleccionado - - - - - - - + + Retrieve calib. and hw settings from profile - Recuperar calib. y los ajustes de hw de un perfil + Recuperar calib. y ajustes hw de un perfil Global Functions - + Funciones globales Hardware - + Hardware Calibration - + Calibración @@ -5600,12 +4540,12 @@ Estos puede ser relevantes para todos los modelos en el mismo EEPROM. 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 ha recuperado + Datos incorrectos en el perfil, los parámetros de hw no se han recuperado @@ -5621,559 +4561,330 @@ Estos puede ser relevantes para todos los modelos en el mismo EEPROM. GeneralSettings - + Radio Settings - + Ajustes de radio GeneralSetup - - - - - - - + + Form - + Form - - - - - - - + + Readonly Unlock - Desactivar solo lectura + Desactivar sólo lectura - - - - - - - + + SC - + - - - - - - - + + SE - + - - - - - - - + + SA - + - - - - - - - + + SF - SF + - - - - - - - + + SH - + - - - - - - - + + SD - + - - - - - - - + + SB - + - - - - - - - + + SG - + - - - - - - - + + Timeshift from UTC - Zona horaria UTC + Zona horaria UTC - - - - - - - + + Voice Language - Lenguaje de las Voces + Lenguaje de las voces - - - - - - - + + Country Code - Codigo País + Código país - - - - - - - + + Stick reverse - + Invertir stick - - - - - - - + + FAI Mode - Modo FAI + Modo FAI - - - - - - - + + Adjust RTC - + Ajustar RTC - - - - - - - + + Vario pitch at max - Tono de vario al max + Tono de vario al máx - - - - - - - - - - - - - - + + + + Hz - + - - - - - - - + + Speaker Volume - Volumen Altavoz + Volumen altavoz - - - - - - - + + Backlight Switch - Switch de pantalla + Interruptor de luz de fondo - - - - - - - + + Sound Mode - Modo sonido + Modo sonido - - - - - - - + + Color 1 - + - - - - - - - + + Color 2 - + - - - - - - - + + Speaker Pitch (spkr only) - Tono del altavoz (solo altavoz) + 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. + 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 + seg - - - - - - - + + Backlight color - Color de pantalla + Color de pantalla - - - - - - - + + Beeper - + Beeper - - - - - - - + + Speaker - Altavoz + Altavoz - - - - - - - + + BeeperVoice - BeeperVoz + VozBeeper - - - - - - - + + SpeakerVoice - VozAltavoz + VozAltavoz - - - - - - - + + Beep volume - Volumen Beep + Volumen beep - - - - - - - + + Wav volume - Volumen Wav + Volumen wav - - - - - - - + + Vario volume - Volumen Vario + Volumen vario - - - - - - - + + Background volume - Volumen de Fondo + Volumen de fondo - - - - - - - - - - - - - - + + + + ms - + - - - - - - - + + Backlight Auto OFF after - Apagado automático de pantalla después + Auto apagado de pantalla después de - - - - - - - + + Backlight flash on alarm - Pantalla parpadea con una alarma + Pantalla parpadea con alarma - - - - - - - + + Vario pitch at zero - Tono de vario a cero + Tono de vario en cero - - - - - - - + + Vario repeat at zero - Vario repite a cero + Vario repite en cero - - - - - - - + + This is the switch selectrion for turning on the backlight (if installed). - Este es el switch seleccionado para encender la pantalla (si está instalada). + Este es el interruptor seleccionado para encender la luz de fondo (si está instalada). - - - - - - - - - - - - - - + + + + <!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"> + <!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;"> @@ -6182,97 +4893,57 @@ p, li { white-space: pre-wrap; } - - - - - - - + + Backlight Brightness - Brillo pantalla + Brillo pantalla - - - - - - - + + RotEnc Navigation - Navegación RotEnc + 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 + Japón - - - - - - - + + Europe - Europa + Europa - - - - - - - + + Backlight OFF Brightness - + Brillo luz de fondo OFF - - - - - - - + + Mode selection: Mode 1: @@ -6292,7 +4963,7 @@ Mode 4: Right stick: Elevator, Rudder - Selección de Modo: + Selección de modo: Modo 1: Stick Izquierdo: Elevador, Timón @@ -6314,1139 +4985,661 @@ Modo 4: - - - - - - - + + Mode 1 (RUD ELE THR AIL) - Modo 1 (RUD ELE THR AIL) + Modo 1 (RUD ELE THR AIL) - - - - - - - + + Mode 2 (RUD THR ELE AIL) - Modo 2 (RUD THR ELE AIL) + Modo 2 (RUD THR ELE AIL) - - - - - - - + + Mode 3 (AIL ELE THR RUD) - Modo 3 (AIL ELE THR RUD) + Modo 3 (AIL ELE THR RUD) - - - - - - - + + Mode 4 (AIL THR ELE RUD) - Modo 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> + <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 - - - - - - - - - aaaaaaAA - + ID de propietario - - - - - - - + + 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 - + Retraso de encendido - - - - - - - + + Jack Mode - + Modo jack - - - - - - - + + Audio - + - - - - - - - + + Trainer - 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 Stick + Modo sticks - - - - - - - + + Metric - Métrico + Métrico - - - - - - - + + Imperial - + Imperial - - - - - - - + + Default Channel Order - Orden Prederterminado Canales + Orden prederterminado canales - - - - - - - + + GPS Coordinates - Coordenadas GPS + Coordenadas GPS - - - - - - - + + Min - + Mín - - - - - - - - - - - - - - + + + + v - + - - - - - - - + + Max - + Máx - - - - - - - + + Inactivity Timer - Tiempo de inactividad + Tiempo de inactividad - - - - - - - + + Show Splash Screen on Startup - Mostrar Pantalla de Inicio al Enceder + Mostrar pantalla de inicio al encender - - - - - - - + + Contrast - Contraste + Contraste - - - - - - - + + Battery Meter Range - + Medidor de rango de batería - - - - - - - + + Haptic Strength - Fuerza de Haptic + Fuerza de haptic - - - - - - - + + LCD Display Type - Tipo de Pantalla LCD + Tipo de pantalla LCD - - - - - - - + + "No Sound" Warning - Aviso "Sin Sonido" + Aviso "sin sonido" - - - - - - - + + Battery Warning - Aviso de Bateria + Aviso de batería - - - - - - - + + Haptic Length - Longitud Haptic + Duración haptic - - - - - - - + + MAVLink Baud Rate - Transferencia Baud MAVLink + Velocidad de transmisión MAVLink - - - - - - - - - - - - - - + + + + Quiet - Silencio + Silencio - - - - - - - + + Only Alarms - Solo Alarmas + Sólo alarmas - - - - - - - - - - - - - - + + + + No Keys - Sin teclas + No teclas - - - - - - - - - - - - - - + + + + All - Todo + Todo - - - - - - - + + Battery warning voltage. This is the threashhold where the battery warning sounds. Acceptable values are 5v..10v - Voltaje de aviso de la batería. + Voltaje de aviso de la batería. Este es el umbral cuando la batería emite sonidos de aviso. Los valores aceptables son 5v..10v - - - - - - - + + Standard - Estandar + 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 de deja sin pulsaciones surante el numero específico de minutos. + Si no es cero emitirá sonidos si el transmisor se deja sin pulsaciones durante el número específico de minutos. + + + + + + nnnnnnNN + - - - - - - - + + min - min + - - - - - - - - - - - - - - + + + + Show splash screen on startup - Mostrar pantalla de inicio al encender + Mostrar pantalla de inicio al encender - - - - - - - + + --- - --- + - - - - - - - + + 2s - 2s + - - - - - - - + + 3s - 3s + - - - - - - - + + 4s - 4s + - - - - - - - + + 6s - 6s + - - - - - - - + + 8s - 8s + - - - - - - - + + 10s - 10s + - - - - - - - + + 15s - 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; } @@ -7458,7 +5651,7 @@ 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;">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> - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> + <!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;"> @@ -7466,191 +5659,106 @@ p, li { white-space: pre-wrap; } <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;">Esto define los avisos al inicio.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Aviso de acelerador - te alertará sin el gas no esta en la posición inactiva</p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Aviso de Switch - tealertará si los switches no están en su posición prederterminada</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Aviso de interruptor - te alertará si los interruptores no están en su posición prederterminada</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Aviso de memoria - te alertará si no hay suficiente memoria libre</p> <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 + X-Corto - - - - - - - - - - - - - - + + + + Short - Corto + Corto - - - - - - - - - - - - - - + + + + Normal - + - - - - - - - - - - - - - - + + + + Long - Largo + Largo - - - - - - - - - - - - - - + + + + X-Long - X-Largo + X-Largo - - - - - - - + + NMEA - + - - - - - - - + + Play Delay (switch mid position) - Retardo de Play (switch en posición media) + Retardo de reproducción (interruptor en posición media) - - - - - - - + + Measurement Units - Unidades de Medida + Unidades de medida - - - - - - - + + Haptic Mode - Modo Haptic + Modo haptic - - - - - - - + + Beeper Length - Longitud del beeper + Duración del beeper - - - - - - - + + Beeper Mode - Modo Beeper + Modo beeper - - - - - - - + + Beeper volume 0 - Quiet. No beeps at all. @@ -7658,35 +5766,20 @@ p, li { white-space: pre-wrap; } 2 - Normal. 3 - Loud. 4 - Extra loud. - Volumen Beeper + Volumen beeper 0 - Silencio. Ningun tipo de beep. -1 - Sin teclas. Los beeps suenan normal pero las teclas de menu no sonarán. +1 - No teclas. Los beeps suenan normal pero las teclas de menu no sonarán. 2 - Normal. 3 - Alto. 4 - Extra Alto. - - - - - - - + + Alarms Only - Solo Alarmas - - - - Power On Speed - - - - - Power Off Speed - + Sólo alarmas @@ -7694,129 +5787,131 @@ p, li { white-space: pre-wrap; } OFF - + Keys - Teclas + Teclas Sticks - + Sticks Keys + Sticks - Teclas + Sticks + Teclas + Sticks ON - ON + English - Inglés + Inglés Dutch - + Holandés French - Francés + Francés Italian - Italiano + Italiano German - Alemán + Alemán Czech - Checo + Checo Slovak - Eslovaco + Eslovaco Spanish - Español + Español Polish - Polaco + Polaco Portuguese - Portugués + Portugués Russian - + Ruso Swedish - Sueco + Sueco Hungarian - + Húngaro No - 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 ? - + Si activas FAI, sólo sensores RSSI and RxBt seguirán funcionando. +Esta función no puede ser deshabilitada en la radio. +¿ Estás seguro ? @@ -7824,875 +5919,568 @@ Are you sure ? No - No + Yes, controled by a switch - Si, controlado por un switch + Sí, controlado por un interruptor Yes, controlled by a pot - Si, controlado por un potenciómetro + Sí, controlado por un potenciómetro Hardware - - - - - - - + + Form - - - - - - - - - - - - SQ - - - - - - - - - - - - SR - - - - - - - - - - - - LS2 - - - - - - - - - - - - SP - - - - - - - - - - - - SO - - - - - - - - - - - - S4 - - - - - - - - - - - - RS - - - - - - - - - - - - SB - - - - - - - - - - - - PPM 2 - PPM 2 - - - - - - - - - - - OFF - - - - - - - - - - - - S-Port Mirror - S-Port Espejo - - - - - - - - - - - Telemetry - Telemetría - - - - - - - - - - - SBUS Trainer - - - - - - - - - - - - Debug - Depurar - - - - - - - - - - - Rud - Rud - - - - - - - - - - - PPM 3 - PPM 3 - - - - - - - - - - - S1 - - - - - - - - - - - - S2 - - - - - - - - - - - - S3 - - - - - - - - - - - - PPM 1 - PPM 1 - - - - - - - - - - - Serial Port - Puerto Serie - - - - - - - - - - - v - - - - - - - - - - - - PPM Multiplier - Multiplicador PPM - - - - - - - - - - - Current Offset - - - - - - - - - - - - PPM 4 - PPM 4 - - - - - - - - - - - SA - - - - - - - - - - - - Ele - Ele - - - - - - - Antenna - - - - - - - - - - S5 - - - - - - - - - - - - Ail - Ail - - - - - - - - - - - Thr - Thr - - - - - - - - - - - SC - - - - - - - - - - - - LS - LS - - - - - - - - - - - SD - - - - - - - - - - - - Battery Offset - - - - - - - - - - - - SE - - - - - - - - - - - - SF - SF - - - - - - - - - - - SG - - - - - - - - - - - - SH - - - - - - - - - - - - SI - - - - - - - - - - - - SJ - - - - - - - - - - - - SK - + 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 + + + + + + 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: HardwarePanel - - + + None - Ninguno + Ninguno 2 Positions Toggle - + 2 posiciones palanca 2 Positions - + 2 posiciones 3 Positions - + 3 posiciones - + Pot with detent - + Pos con fijador - + Multipos switch - + Interruptor multipos - + Pot without detent - + Pot sin fijador - + Slider with detent - - - - - OFF - - - - - Enabled - - - - - Telemetry - Telemetría + Slider con fijador + OFF + + + + + Enabled + Activado + + + + Telemetry + Telemetría + + + Trainer - Trainer + Entrenador - + Internal - + Interno - + Ask - + Preguntar - + Per model - + Por modelo - + Internal + External - + Interno + Externo - + External - + Externo Heli - - - - - - - + + Invert Elevator - Invertir Elevador + Invertir elevador - - - - - - - + + Invert Aileron - Invertir Aleron + Invertir alerón - - - - - - - + + Invert Collective - Invertir Colectivo + Invertir colec. - - - - - - - + + Invert Invertir - - - - - - - + + Off - - - - - - - + + 120 - - - - - - - + + 120X - - - - - - - + + 140 - - - - - - - + + 90 - - - - - - - + + Long. cyc - + Cíclico longitudinal - - - - - - - + + Lateral cyc - + Cíclico lateral - - - - - - - + + Collective Colectivo - - - - - - - + + Swash Type - Tipo de Plato + Tipo de plato - - - - - - - + + Swash Ring - + Plato @@ -8700,22 +6488,22 @@ Are you sure ? Throttle Channel: - Canal de Acelerador: + Canal de acelerador: Yaw Channel: - Canal de Yaw: + Canal de viraje: Pitch Channel: - Canal de pitch: + Canal de inclinación: Roll Channel: - Canal de roll: + Canal de balanceo: @@ -8723,19 +6511,20 @@ Are you sure ? Invalid EEPROM File %1 - Archivo EEPROM inválido %1 + Archivo EEPROM no válido %1 Cannot open file %1: %2. - + No se puede abrir el archivo %1: +%2. Error writing file %1: %2. - Error escribiendo el archivo %1: + Error escribiendo el archivo %1: %2. @@ -8745,30 +6534,30 @@ Are you sure ? Move Up - Mover Arriba + Mover arriba Ctrl+Up - + Ctrl+Arriba Move Down - Mover Abajo + Mover abajo Ctrl+Down - + Ctrl+Abajo Clear All Inputs - Limpiar Todas las entradas + Limpiar todas las entradas @@ -8778,7 +6567,7 @@ Are you sure ? Delete Selected Inputs? - ¿Borrar las Entradas Seleccionadas? + ¿Borrar las entradas seleccionadas? @@ -8798,7 +6587,7 @@ Are you sure ? Enter - + Intro @@ -8818,7 +6607,7 @@ Are you sure ? Ctrl+C - Ctrl+C + @@ -8828,7 +6617,7 @@ Are you sure ? Ctrl+X - Ctrl+X + @@ -8866,17 +6655,17 @@ Are you sure ? INV - INV + NOR - NOR + CH - + @@ -8884,7 +6673,7 @@ Are you sure ? GV - GV + @@ -8892,122 +6681,122 @@ Are you sure ? --- - --- + a>x - + a<x - + |a|>x - + |a|<x - + AND - + OR - + XOR - + a=b - + a!=b - + a>b - + a<b - + a>=b - + a<=b - + d>=x - + |d|>=x - + a=x - + a~x - + Timer - Temporizador + Temporizador Sticky - + Pegajoso Edge - + Borde Unknown - Desconocido + Desconocido L - + LSW - + @@ -9040,22 +6829,22 @@ Are you sure ? AND Switch - + Interruptor AND Popup menu available - + Menú emergente disponible (instant) - + (instante) (infinite) - + (infinito) @@ -9082,235 +6871,192 @@ Are you sure ? LogsDialog - - - - - - - + + Companion Log Viewer - Visor de registros de Companion + Visor de registros de Companion - - - - - - - + + Filename - Nombre Archivo + Nombre archivo - - - - - - - + + Open LogFile - Abrir archivo Registros + Abrir archivo registros - - - - - - - + + Zoom - + Zoom - - - - - - - + + Save session CSV - + Guardar sesión CSV - - - - - - - + + X - + - - - - - - - + + Y - + - - - - - - - + + Reset - Resetear + Resetear - - - - - - - + + Fly sessions - Sesiones de vuelo + Sesiones de vuelo Telemetry logs - Registros de telemetría + Registros de telemetría Time (hh:mm:ss) - Hora (hh:mm:ss) + Hora (hh:mm:ss) Plot Title Change - + Cambia título de plot New plot title: - + Nuevo título de plot: Axis Label Change - + Cambia etiqueta de eje New axis label: - + Nueva etiqueta de eje: Graph Name Change - + Cambia nombre gráfico New graph name: - + Nuevo nombre gráfico: Error: no GPS data found - + Error: datos de GPS no encontrados The column containing GPS coordinates must be named "GPS". The columns for altitude "GAlt" and for speed "GSpd" are optional - + La columna conteniendo las coordenadas GPS debe llamarse "GPS". + +Las columnas para altitud "GAlt" y para velocidad "GSpd" son opcionales Cannot write file %1: %2. - No se puede escribir el archivo %1: + No se puede escribir el archivo %1: %2. Cursor A: %1 m - + Cursor A: %1 m Cursor B: %1 m - + Cursor B: %1 m Time delta: %1 - + Tiempo delta: %1 Climb rate: %1 m/s - + Velocidad de ascenso: %1 m/s Select your log file - Selecciona tu archivo de registros + Selecciona tu archivo de registros Available fields - Campos disponibles + Campos disponibles The selected logfile contains %1 invalid lines out of %2 total lines - El archivo de registros elegido contiene %1 lineas inválidas de un total de %2 lineas + El archivo de registros elegido contiene %1 líneas inválidas de un total de %2 líneas - total duration - + time span + lapso de tiempo duration - + duración (L1) - + (R1) - + (L2) - + (R2) - + @@ -9319,13 +7065,13 @@ The columns for altitude "GAlt" and for speed "GSpd" are opt File loaded - Archivo Cargado + Archivo cargado Save As - Guardar Como + Guardar como @@ -9356,24 +7102,24 @@ The columns for altitude "GAlt" and for speed "GSpd" are opt Archivo guardado - + Read Models and Settings From Radio - Leer los Modelos y Ajustes de la Radio + Leer los modelos y ajustes de la radio Save Radio Backup to File - Guardar Copia deSeguridad de la Radio a un Archivo + Guardar copia de seguridad de la radio a un archivo Read Radio Firmware to File - Leer el Firmware de la Radio a un Archivo + 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> @@ -9395,18 +7141,18 @@ The columns for altitude "GAlt" and for speed "GSpd" are opt Compilation server too busy, try later - Servidor de compilación demasiado ocupado, inténtalo mas tarde + Servidor de compilación demasiado ocupado, inténtalo más tarde Unknown server failure, try later - Fallo desconocido de servidor, inténtalo mas tarde + Fallo desconocido de servidor, inténtalo más tarde Yes - Si + Sí @@ -9418,83 +7164,83 @@ The columns for altitude "GAlt" and for speed "GSpd" are opt Release Notes - Notas de la Versión + Notas de la versión - + Open Models and Settings file - Abrir archivo de Modelos y Ajustes + Abre archivo de modelos y ajustes - + New Nuevo - + Open... Abrir... - + Save Guardar - + Save As... - Guardar Como... + Guardar como... - + Compare models Comparar modelos - + Exit the application - Salir de la aplicación + 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 - Mostrar la ventana de aplicación Acerca de + Muestra la ventana de aplicación Acerca de - + Set Menu Language - Menú Ajuste Lenguaje + Lenguaje - + Write Escribir - + %2 - %2 + - + Alt+%1 - + - + New Radio - Nueva Radio + Nueva radio @@ -9504,7 +7250,7 @@ The columns for altitude "GAlt" and for speed "GSpd" are opt Do you want to write the firmware to the radio now ? - ¿Te gustaría escribir el firmware a la radio ahora? + ¿Te gustaría escribir el firmware en la radio ahora? @@ -9517,421 +7263,423 @@ The columns for altitude "GAlt" and for speed "GSpd" are opt 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 Diskimage (*.dmg) - + Imagen de disco(*.dmg) Would you like to open the disk image to install the new version? - + ¿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? - + Hay cambios sin guardar en el archivo que se perderán al cambiar de tipo de radio. + +¿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 + 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 - - Tabbed Windows - - - - + 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 - - - - - Ctrl+Shift+S - - - - - Ctrl+Alt+L - + Ventana + Ctrl+Shift+S + + + + + Ctrl+Alt+L + + + + Ctrl+Alt+D - + - + Ctrl+Alt+R - + - + Small Pequeño - + Use small toolbar icons - Usar iconos pequeños en la barra de herramientas + Usa iconos pequeños en la barra de herramientas - + Use normal size toolbar icons - Usar iconos normales en la barra de herramientas + Usa iconos normales en la barra de herramientas - + Normal - + Normal - + Use big toolbar icons - Usar iconos grandes en la barra de herramientas + Usa iconos grandes en la barra de herramientas - + Big Grande - + Use huge toolbar icons - Usar iconos extra grandes en la barra de herramientas + 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 es posible eliminar el perfil + No se puede eliminar el perfil - + The default profile can not be removed. - El perfil prederterminado no se puede eliminar. + 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 - - - - - Select %1: - - - - - backup - + 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. - - - - - <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> - + 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. @@ -9940,34 +7688,38 @@ 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. - + El firmware %1 parece que no se ha descargado anteriormente: +La versión %2 está disponible. +¿Quieres descargarla ahora? + +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 @@ -9980,68 +7732,68 @@ We recommend you view the release notes using the button below to learn about an Derechos de autor del equipo OpenTX - + Create a new Models and Settings file - Crear un nuevo archivo de Modelos y Ajustes + Crea un nuevo archivo de modelos y ajustes - - + + Save Models and Settings file - Guardar el archivo de Modelos y Ajustes + 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 - Clasico + Clásico - + The classic companion9x icon theme - Tema de iconos clasicos de companion9x + 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 @@ -10054,231 +7806,237 @@ We recommend you view the release notes using the button below to learn about an 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. - + Una nueva versión del firmware %1 está disponible: + - actual es %2 + - nuevo es %3 + +¿Quieres descargar ahora? + +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... + Ver archivo de registro... - + Open and view log file - Abrir y ver el archivo de registro + Abre el archivo de registro - + Settings... Ajustes... - + Edit Settings - Editar Ajustes + Edita ajustes - + Download... Descargar... - + Download firmware and voice files - Descargar los archivos de firmware y voces + Descarga los archivos de firmware y voces - + Check for Updates... - Comprobar Actualizaciones... + Comprobar actualizaciones... - + Check OpenTX and Companion updates - Comprobar la actualizaciones de OpenTX y Companion + Comprueba las actualizaciones de OpenTX y Companion - + Compare Models... - Comparar Modelos... + Comparar modelos... - + Edit Radio Splash Image... - Editar Imagen de Inicio de la Radio... + 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 desde la Radio - - - - Read firmware from Radio - Leer firmware desde 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 - Abrir 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 + Read Firmware from Radio + Leer firmware de la radio + + + + Read firmware from Radio + Leer firmware de la radio - Configure Communications... - Configurar Comunicaciones... + Write Firmware to Radio + Escribir firmware a la radio - Configure software for communicating with the Radio - Configurar software para la comunicación con la Radio + Write firmware to Radio + Escribir firmware a 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 + + 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 + Archivos recientes - - Set Icon Theme - Selecciona el Tema de Iconos - - - - Set Icon Size - Selecciona el Tamaño de Iconos - - - + 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 @@ -10286,63 +8044,58 @@ We recommend you view the release notes using the button below to learn about an MdiChild - + Editing model %1: Editando modelo %1: Delete - Borrar + Borrar Move to Category - + Mover a categoría Alt+S - + - + Do you want to overwrite radio general settings? - ¿Quieres sobreescribir los ajustes generales de la radio? + ¿Quieres sobreescribir los ajustes generales de la radio? - + This category is not empty! - + ¡Esta categoría no está vacía! - + New model Translators: do NOT use accents here, this is a default model name. - + Nuevo modelo - + <p><b>Currently selected radio type (%1) is not compatible with file %3 (from %2), models and settings need to be converted.</b></p> - + ><p><b>El tipo actualmente seleccionado de radio (%1) no es compatible con el archivo %3 (de %2), los modelos y ajustes necesitan ser convertidos.</b></p> - - Unable to find Horus radio SD card! - - - - + Models and Settings written - + Modelos y ajustes escritos - + Unable to find file %1! - ¡No es posible encontrar el archivo %1! + ¡No se puede encontrar el archivo %1! - + Error reading file %1: %2. Error leyendo el archivo %1: @@ -10356,303 +8109,313 @@ We recommend you view the release notes using the button below to learn about an 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 modelo + %n modelos %n Model(s) As in "Paste 3 Models" or "Insert 1 Model." - - - + + %n modelo + %n modelos %n Category(ies) As in "Delete 3 Categories" or "Delete 1 Category." - - - + + %n categoría + %n categorías Nothing selected - + Nada seleccionado Rename Category - + Renombrar categoría Edit Model - + Editar modelo Cut - + Cortar Copy - + Copiar Paste - + Pegar Insert - + Insertar Edit Radio Settings - + Editar ajustes de radio Copy Radio Settings - + Copiar ajustes de radio Paste Radio Settings - + Pegar ajustes de radio Simulate Radio - + Simular radio Add Category - + Añadir categoría Category - + Categoría Add Model - + Añadir modelo Model - Modelo + Modelo Restore from Backup - + Restaurar desde copia de seguridad Model Wizard - Asistente Modelos + Asistente modelos Set as Default - + Fijar como predeterminado Print Model - + Imprimir modelo Simulate Model - + Simular modelo Duplicate Model - + Duplicar modelo Show Category Actions Toolbar - + Muestra barra de acciones de categoría Show Radio Actions Toolbar - + Muestra barra de acciones de radio Show Model Actions Toolbar - + Muestra barra de acciones de modelo - + + read only + solo lectura + + + New category Translators do NOT use accent for this, this is the default category name on Horus. - + Nueva categoria - + Category index out of range. - + Índice de categoría fuera de rango. - + Cannot delete the last category. - + No se puede eliminar la última categoría. - + Cannot insert model, last model in list would be deleted. - + No se puede insertar el modelo, no hay slots de modelo disponibles. - + Cannot add model, could not find an available model slot. - + No se puede añadir el modelo, no hay slots de modelo disponibles. - + Cannot paste model, out of available model slots. - + No se puede pegar el modelo, no hay slots de modelo disponibles. - + You are replacing an existing model, are you sure? - + Estás reemplazando un modelo existente, ¿estás seguro? - + Delete %n selected model(s)? - - - + + ¿Borrar %n modelo seleccionado? + ¿Borrar %n modelos seleccionados? - + Delete %n selected category(ies)? - - - + + ¿Borrar %n categoría seleccionada? + ¿Borrar %n categorías seleccionadas? - + Cannot duplicate model, could not find an available model slot. - + No se puede duplicar el modelo, no hay un slot de modelo disponibles. - + Do you wish to continue with the conversion? - + ¿Quieres continuar la conversión? - + Choose <i>Apply</i> to convert the file, or <i>Close</i> to close it without conversion. - + Elige <i>Aplicar</i> para convertir el archivo, o <i>Cerrar</i> para cerrar sin conversión. - + <b>The conversion generated some important messages, please review them below.</b> - + <b>La conversión ha generado mensajes importantes, por favor revísalos.</b> - + Companion :: Conversion Result for %1 - + Companion :: Resultado de la conversión para %1 - + + Unable to find radio SD card! + ¡No se puede encontrar la tarjeta SD de la radio! + + + Error opening file %1: %2. Error abriendo el archivo %1: %2. - + Save As - Guardar Como + Guardar como - + Open backup Models and Settings file - Abrir archivo de copia de seguridad de Modelos y Ajustes + Abre archivo de copia de seguridad de modelos y ajustes - + %1 has been modified. Do you want to save your changes? %1 ha sido modificado. ¿Quieres guardar los cambios? - + Invalid binary backup File %1 - Archivo binariode copia de seguridad inválido %1 + Archivo binariode copia de seguridad no válido %1 - + Cannot write temporary file! ¡No se puede escribir el archivo temporal! @@ -10662,35 +8425,27 @@ Do you want to save your changes? MIX - + (@%1) - + MixerDialog - - - - - + + Dialog Mezclas - - - - - - - + + Source Fuente @@ -10699,197 +8454,107 @@ Do you want to save your changes? - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + The source for the mixer - LA fuente de la mezcla + La fuente de la mezcla - - - - - - - + + Weight - Carga + Peso - - - - - - - - - - - - - - - - - - - - - + + + + + + GV - + GV - - - - - - - + + Switch used by the mix. If blank then the mix is considered to be "ON" all the time. The value of the mixer is multiplied by this value and divided by 100. - Switch usado por la mezcla. + Interruptor usado por la mezcla. Si está en blanco entonces la mezcla se considera que está activa todo el tiempo. - - - - - - - + + Offset - + Offset - - - - - - - + + Include Trim - Incluir Trim + Incluir trim - - - - - - - + + Curve Curva - - - - - - - + + The curve used by the mix La curva usada por la mezcla - - - - - - - + + Switch - + Interruptor - - - - - - - + + Yes - Si + Sí - - - - - - - + + No - No + - - - - - - - + + Warning Aviso - - - - - - - + + Name Nombre @@ -10898,34 +8563,14 @@ Si está en blanco entonces la mezcla se considera que está activa todo el tiem - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + <!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; } @@ -10937,93 +8582,57 @@ 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;">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 -&gt; the value states the number of seconds it takes to transit from -100 to 100.</p></body></html> - + - - - - - - - + + Mixer warning. Setting this value will cause a beep to be emmitted when this value is active. - Sellecionar este valor provocará un beep emitido cuando este activo. Aviso del mezclador. - +Selecionar este valor provocará un beep cuando el valor esté activo. - - - - - - - + + OFF APAGADO - - - - - - - + + 1 Beep - - - - - - - + + 2 Beep 2 Beeo - - - - - - - + + 3 Beep - - - - - - - + + Multiplex - Opciones + - - - - - - - + + Multiplexer This determines how mixer values are added. @@ -11031,9 +8640,9 @@ 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. - Opciones + Multiplexer -Esto determina como los valores de mezcla son añadidos. +Esto determina cómo los valores de mezcla son añadidos. "+" significa que el valor de la mezcla actual es añadido a la mezcla previa en el mismo canal. "*" significa que el valor de la mezcla actual es multiplicada por la mezcla previa en el mismo canal @@ -11041,142 +8650,91 @@ Esto determina como los valores de mezcla son añadidos. - - - - - - - + + ADD AÑADIR - - - - - - - + + MULTIPLY MULTIPLICAR - - - - - - - + + REPLACE REEMPLAZAR - - - - - - - + + Flight modes Modos de vuelo - - - - - - - + + Include DR/Expo - Incluye DR/Expo + IncluirDR/Expo - - - - - - - + + Delay Retardo - - - - - - - + + Slow Lento - - - - - - - + + Up Arriba - - - - - - - + + Down Abajo DEST -> %1 - + Click to access popup menu - + Pulsa para acceder el menú emergente Clear All - + Limpiar todo Set All - + Fijar todo Invert All - - - - - - FullScreenDialog - + Ivertir todo @@ -11184,22 +8742,22 @@ Esto determina como los valores de mezcla son añadidos. Increase font size - + Aumentar tamaño de fuente Decrease font size - + Reducir tamaño de fuente Default font size - + Tamaño de fuente predeterminado Ctrl+0 - + @@ -11208,7 +8766,7 @@ Esto determina como los valores de mezcla son añadidos. Move Up - Mover Arriba + Mover arriba @@ -11220,7 +8778,7 @@ Esto determina como los valores de mezcla son añadidos. Move Down - Mover Abajo + Mover abajo @@ -11261,12 +8819,12 @@ Esto determina como los valores de mezcla son añadidos. Enter - Enter + Intro &Toggle highlight - &Seleccionar Palanca + &Seleccionar palanca @@ -11339,23 +8897,20 @@ Esto determina como los valores de mezcla son añadidos. Model: - + Modelo: Throttle Source - Fuente del acelerador + Fuente del acelerador ModelEdit - - - - - + + Dialog Mensaje @@ -11367,7 +8922,7 @@ Esto determina como los valores de mezcla son añadidos. Heli - + Heli @@ -11377,7 +8932,7 @@ Esto determina como los valores de mezcla son añadidos. Logical Switches - Switches lógicos + Interruptor lógicos @@ -11387,7 +8942,7 @@ Esto determina como los valores de mezcla son añadidos. Outputs - Salidas + Salidas @@ -11411,124 +8966,113 @@ Esto determina como los valores de mezcla son añadidos. - - - - - - - + + Simulate Simular - - - - FullScreenDialog - - ModelPrinter Exponential - Exponencial + Exponencial Extra Fine - Extra Fino + Extra Fino Fine - Fino + Fino Medium - Medio + Medio Coarse - Duro + Duro Unknown - Desconocido + 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 - Si + Sí No - No + Y - + N - + ON - ON + @@ -11536,458 +9080,458 @@ Esto determina como los valores de mezcla son añadidos. OFF - + bytes - + Mode - Modo + Modo Channels - Canales + Canales Frame length - + Longitud frame PPM delay - Retardo PPM + Retardo PPM Polarity - Polaridad + Polaridad Protocol - Protocolo + Protocolo Delay - Retardo + Retardo Receiver - Receptor + Receptor Radio protocol - + Protocolo radio Subtype - + Subtipo Option value - + Valor opción Sub Type - + Sub tipo RF Output Power - + Potencia de salida RF 90 - 90 + 120 - 120 + 120X - 120X + 140 - 140 + MULT! - + Offset - Offset + Slow - Lento + Lento Warn - + Aviso Flight modes - Modos de vuelo + Modos de vuelo Flight mode - Modo de vuelo + Modo de vuelo All - Todo + Todo Edge - + Borde Sticky - + Pegajoso Timer - Temporizador + Temporizador missing - + falta Duration - Duración + Duración Extended Limits - Límites extendidos + Límites extendidos Display Checklist - Lista verificación pantalla + Mostrar lista de verificación Global Functions - + Funciones globales Manual - + Manual Auto - + Auto Failsafe Mode - Modo Failsafe + Modo failsafe Hold - Esperar + Mantener No Pulse - + Sin pulsos Not set - + No fijado No pulses - + Sin pulsos Silent - Silencio + Silencio Beeps - + Beeps Voice - Voz + Voz Haptic - Reproducir 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 + Aviso Reversed - + Invertido Tmr - + Temporiz. FrSky S.PORT - + FrSky D - + FrSky D (cable) - + Alti - + Alti+ - + VSpeed - + Veloc. vert. A1 - + A2 - + A3 - + 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 Id - + Instance - + Instancia @@ -11995,130 +9539,130 @@ Esto determina como los valores de mezcla son añadidos. Sensor - + Sources - + Fuentes GPS - + GPS Alt. - + Blades - Palas + Palas Multi. - + F - + Inst - + Alt - + Unit - Unidad + Unidad Prec - + Ratio - + Multi - + A/Offset - + Filter - + Filtro Persist - + Persist. Positive - Positivo + Positivo Log - + Reporte Numbers - + Números Bars - Barras + Barras Script - + Script Filename - Nombre Archivo + Nombre archivo Error: Unable to open or read file! - + Error: ¡No se puede abrir o leer el archivo! Persistent - + Persistente Off - Apagado + @@ -12128,89 +9672,89 @@ Esto determina como los valores de mezcla son añadidos. None - Ninguno + Ninguno Name - Nombre + Nombre Countdown - Cuenta Atrás + 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 - A medida + Personalizado Standard - Estandar + Estándar @@ -12233,692 +9777,500 @@ Esto determina como los valores de mezcla son añadidos. Model Name: - Nombre Modelo: + Nombre modelo: Model Type: - Tipo Modelo: + Tipo modelo: Module - - - - - - - - + + + Failsafe Mode - Modo Failsafe + Modo failsafe - - - - - - - + + Start Comenzar - - - - - - - - + + + PPM delay Retardo PPM - - - - - - - + + Negative Negativo - - - - - - - + + Positive Positivo - - - - - - - + + Polarity Polaridad - - - - - - - - + + + Trainer Mode - Modo Entrenador + Modo entrenador - - - - - - - - + + + PPM Frame Length - Longitud Trama PPM + Longitud trama PPM - - - - - - - + + CH - - - - - - - - + + + Antenna - + Antena - - - - - - - - + + + Option value - - - - - - - - - - - - Bind on startup - + 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 - - - - - + + + Registration ID - + Registro ID - - - - - - - - + + + WARNING: Requires non-certified firmware! - + AVISO: ¡Requiere firmware no certificado! - - - - - - - - + + + Not set - + No fijado - - - - - - - - + + + Hold - Esperar + Mantener - - - - - - - - + + + Custom - A medida + Personalizado - - - - - - - - + + + No Pulses Sin Pulsos - - - - - - - - + + + Receiver Receptor - - - - - - - - - Failsafe Positions - Posiciones Failsafe + + + + 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 - - - - - - - - Internal - - - - - - - - Ext. + Int. - + ModuleData - + Positive - Positivo + Positivo - + Negative - Negativo + Negativo - + Trainer Port - Puerto Entrenador + Puerto entrenador - + Internal Radio System - Sistema Interno de Radio + Sistema de radio interno - + External Radio Module - Modulo externo de Radio + Módulo externo de radio - + Extra Radio System - Extra Sistema de Radio + Sistema de radio extra - + Radio System - Sistema de Radio + 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) ModulePanel - + Value - Valor + Valor - + Hold - Esperar + 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 @@ -12926,448 +10278,448 @@ Esto determina como los valores de mezcla son añadidos. Input - Entrada + Entrada Weight - + Peso Long. cyc - + Cíc. long. Lateral cyc - + Cíc. lateral Collective - Colectivo + Colectivo Flight modes - Modos de vuelo + Modos de vuelo Flight mode - Modo de vuelo + Modo de vuelo Switch - + Interruptores General - + EEprom Size - + Tamaño EEprom Model Image - Imagen del modelo + Imagen del modelo Throttle - Acelerador + Acelerador Trims - + Center Beep - + Beep en centro Switch Warnings - Avisos palancas (Switch) + Avisos interruptores Pot Warnings - Avisos Potenciómetros + Avisos potenciómetros Other - + Otro Timers - + Temporizadores Time - Hora + Hora Countdown - Cuenta Atrás + Cuenta atrás Modules - + Módulos Trainer port - + Puerto entrenador Helicopter - Helicóptero + Helicóptero Swash - + Type - + Tipo Ring - + Protocol - Protocolo + Protocolo Low - + Bajo Critical - + Crítico Telemetry audio - + Audio telemetría Altimetry - Altímetro + Altímetro Vario source - Fuente Variómetro + 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 + Varios Serial protocol - + Protocolo serie FAS offset - + mAh count - Valor mAh + Valor mAh Persistent mAh - mAh Constantes + mAh persistente Current source - Fuente Actual + Fuente actual Blades - Palas + Palas Parameters - Parámetros + 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 + Nombre Prec - + Popup - + Emergente Outputs - Salidas + Salidas Subtrim - Subtrim + Direct - + Directo Curve - Curva + Curva PPM - + Linear - Lineal + Lineal Telemetry - Telemetría + Telemetría Offset - 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 + Variables globales Inputs - Entradas + Entradas Mixers - Mezclas + Mezclas Curves - Curvas + Curvas L%1 - + Logical Switches - Switches lógicos + Interruptores lógicos SF%1 - SF%1 + Special Functions - Funciones especiales + Funciones especiales Analogs - + Analógicos Unit - Unidad + Unidad Scale - Escala + Escala RSSI Alarms - + Alarmas RSSI @@ -13375,52 +10727,47 @@ Esto determina como los valores de mezcla son añadidos. Subtype - + Subtipo Video TX frequency - + Frecuencia vídeo TX CC2500 frequency fine tune - + CC2500 ajuste fino de frecuencia Telemetry - Telemetría + Telemetría Radio output power - + Potencia de salida radio Servo output frequency - + Frecuencia de salida servo Option value - + Valor opción Fixed ID value - + Valor ID fijo DEFAULT - - - - - Custom - proto %1) - + PREDETERMINADO @@ -13428,45 +10775,45 @@ Esto determina como los valores de mezcla son añadidos. Throttle Channel: - Canal Throttle: + Canal de acelerador: Yaw Channel: - Canal Yaw: + Canal de viraje: Pitch Channel: - Canal Pitch: + Canal de inclinación: Roll Channel: - Canal Roll: + Canal de balanceo: OpenTxEepromInterface - - - Unknown error - - + 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 @@ -13474,12 +10821,12 @@ Esto determina como los valores de mezcla son añadidos. Throttle Cut - Corte de Gas + Corte de gas Throttle Timer - Temporizador de Gas + Temporizador de gas @@ -13493,90 +10840,71 @@ Esto determina como los valores de mezcla son añadidos. Error opening file %1: %2. - Error abriendo el archivo %1: + Error abriendo el archivo %1: %2. Error opening OTX archive %1 - + Error abriendo archivo OTX %1 Error initializing OTX archive writer - + Error inicializando el escritor de archivo OTX Error writing file %1: %2. - Error escribiendo el archivo %1: + Error escribiendo el archivo %1: %2. Error creating OTX file %1: %2. - + Error creando el fichero OTX %1: +%2. Error creating OTX archive - + Error creando el archivo OTX Error adding %1 to OTX archive - + Error añadiendo %1 al archivo OTX PrintDialog - - - - - - - + + Close Cerrar - - - - - - - + + Style - + Estilo - - - - - - - + + Print Imprimir - - - - - - - + + Print to file Imprimir a archivo @@ -13588,7 +10916,7 @@ Esto determina como los valores de mezcla son añadidos. Select PDF output file - Seleccionar archivo de salida PDF + Seleccionar archivo de salida PDF @@ -13600,48 +10928,46 @@ Esto determina como los valores de mezcla son añadidos. ProgressDialog - - - - - - - + + Flash Firmware - + - - - - - - - + + Close - Cerrar + Cerrar Cancel - Cancelar + Cancelar ProgressWidget - - - - - - - + + Show Details - Mostrar detalles + Mostrar detalles + + + + QObject + + + WARNING + AVISO + + + + <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> Importar datos de JumperTX a OpenTX 2.3 <b> no es compatible y es peligroso. </b> </p> <p> Desafortunadamente, no es posible diferenciar los datos de JumperTX de los datos legítimos de FrSky X10, pero <b> Sólo debes continuar aquí si el archivo que se abrió proviene de un FrSky X10 real. </b> </p> <p> ¿Realmente deseas continuar? </p> @@ -13649,7 +10975,7 @@ Esto determina como los valores de mezcla son añadidos. Models - + Modelos @@ -13657,97 +10983,97 @@ Esto determina como los valores de mezcla son añadidos. is invalid - + es inválido converted to - + convertido a verify is - + verificar si [DBG] - + [NFO] - + [WRN] - + [CVT] - + [ERR] - + [INV] - + Event - + Evento Origin - + Fuente Comp - + Comp Sub-Component - + Sub-componente Field - + Campo Type - + Tipo Old - + Anterior Action - Acción + Acción New - Nuevo + Nuevo Seq - + @@ -13756,24 +11082,24 @@ Esto determina como los valores de mezcla son añadidos. Cannot write file %1: %2. - No se puede escribir el archivo %1: + 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 fuses de %1 a los ajustes de fábrica.<br>Escribir fuses puede estropear tu radio.<br>¡Haz esto sólo si estás seguro que están mal!<br>¿Estás seguro de continuar? + <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 Horus radio SD card! - + Unable to find radio SD card! + ¡No se puede encontrar la tarjeta SD de la radio! @@ -13781,49 +11107,34 @@ Esto determina como los valores de mezcla son añadidos. <p>Value (input): <b>%1</b></p> - + <p>Valor (entrada): <b>%1</b></p> Right-double-click to reset to center. - + Doble click derecho para reiniciar centro. RadioNotFoundDialog - - - - - - - + + No Radio Found - No se ha encontrado la Radio + No se ha encontrado radio - - - - - - - + + <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> ¡No se encontró radio! </p> <p> Asegúrate de mantener presionados los botones de ajuste inferiores hacia el centro mientras la enciendes. </p> <p> Luego, conecta el cable USB. </p> <p> <span style = "font-family: 'arial, sans-serif'; font-size: 13px; font-style: italic; color: # 222222; background-color : #ffffff; "> Nota: si tienes una Taranis que no tiene el firmware actualizado a 2.0, entonces esta versión de Companion no funcionará. </span> </p> </body> </html> - - - - - - - + + OK @@ -13832,136 +11143,78 @@ Esto determina como los valores de mezcla son añadidos. RadioOutputsWidget - - - - - - - - - + + Form - + - - - - - - - - - + + View: - + Vista: - - - - - - - - - + + Logical Switches - Switches lógicos + Interruptores lógicos - - - - - - - - - + + Global Variables - Variables globales + Variables globales - - - - - - - - - + + Channel Outputs - + Salidas canales - - - - - - - - - + + Mix Outputs - + Salidas mixes - - - - - - - - - + + L o g i c - + L +ó +g +i +c +o - - - - - - - - - + + G l o b a l - + - - - - - - - - - + + C h a @@ -13970,35 +11223,34 @@ n e l s - + C +a +n +a +l +e +s - - - - - - - - - + + M i x e s - + FM%1 - + GV%1 - + @@ -14006,7 +11258,7 @@ s Latch/unlatch the momentary switch. - + Activa/desactiva el interruptor momentáneo. @@ -14017,7 +11269,7 @@ s V - + @@ -14025,428 +11277,428 @@ s s - + ft - + m - + °C - + ° - + % - + mph - + km/h - + m/s - + A - + mAh - + W - + g - + TrmR - + TrmE - + TrmT - + TrmA - + Trm5 - + Trm6 - + TrmH - + TrmV - + Batt - Batería + Batería Time - Hora + Hora Timer1 - Temporizador1 + Temporizador1 Timer2 - Temporizador 2 + Temporizador 2 Timer3 - Temporizador 3 + Temporizador 3 RAS - + RSSI Tx - + RSSI Rx - + A1 - + A2 - + A3 - + A4 - + Alt - + Rpm - + Fuel - Combustible + Combustible T1 - + T2 - + Speed - Velocidad + 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+ + Velocidad+ Dist+ - + AirSpeed+ - + VelocAire+ Cell- - + Celda- Cells- - + Celdas- Vfas- - + Curr+ - + Powr+ - + ACC - + GPS Time - Hora GPS + Hora GPS REa - + REb - + ??? - ??? + ---- - + I as in Input - + LUA%1%2 - + MAX - + CYC%1 - + TR as in Trainer - + SRC - + @@ -14454,165 +11706,170 @@ s ↑ - + ↓ - + - - + ! - + RudTrim Left - RudTrim Izquierda + RudTrim izquierda RudTrim Right - RudTrim Derecha + RudTrim derecha EleTrim Down - EleTrim Abajo + EleTrim Abajo EleTrim Up - EleTrim Arriba + EleTrim Arriba ThrTrim Down - ThrTrim Abajo + ThrTrim abajo ThrTrim Up - ThrTrim Arriba + ThrTrim arriba AilTrim Left - AilTrim Izquierda + AilTrim Izquierda AilTrim Right - AilTrim Derecha + AilTrim Derecha Trim 5 Down - + Trim 5 abajo Trim 5 Up - + Trim 5 arriba Trim 6 Down - + Trim 6 abajo Trim 6 Up - + Trim 6 arriba TrmH Left - + TrmH izquierda TrmH Right - + TrmH derecha TrmV Down - + TrmV abajo TrmV Up - + TrmV arriba REa - + REb - + OFF - + ON - ON + THs - + TH% - + THt - + - + ??? - ??? + One - Uno + Uno - + + Act + + + + ---- - + - + Telemetry - Telemetría + Telemetría - + SW - + @@ -14620,7 +11877,7 @@ s Companion Release Notes - Notas de la versión Companion + Notas de la versión de Companion @@ -14628,7 +11885,7 @@ s OpenTX Release Notes - Notas de la versión OpenTX + Notas de la versión de OpenTX @@ -14636,17 +11893,17 @@ s Played once, not during startup - Reproducir una vez, no en el inicio + Reproducir una vez, no durante el inicio No repeat - No Repetir + No repetir %1s - %1s + @@ -14659,7 +11916,7 @@ s Yes - Si + Sí @@ -14673,14 +11930,15 @@ s Error opening file %1: %2. - Error abriendo el archivo %1: + Error abriendo el archivo %1: %2. Error opening file %1 in write mode: %2. - + Error abriendo archivo %1 en modo de escritura: +%2. @@ -14689,517 +11947,352 @@ s V - + A - + mA - + kts - + m/s - + km/h - + mph - + m - + f - + °C - + °F - + % - + mAh - + W - + mW - + dB - + rpms - + g - + ° - + Rad - + hours - + horas minutes - + minutos seconds - + segundos - + + ml/minute + ml/minuto + + + TELE - - - - - Internal - - - - - External - + Setup - - - - - - - + + Center beep Centro beep - - - - - - - + + OFF - OFF + - - - - - - - + + Model Image Imagen del modelo - - - - - - - + + Exponential Exponencial - - - - - - - + + Throttle Trim Idle Only - Trim de acelerador ajuste de ralentí + Trim acel. ralentí - - - - - - - + + Extra Fine Extra Fino - - - - - - - + + Fine Fino - - - - - - - + + Medium Medio - - - - - - - + + Coarse - Duro + Grueso - - - - - - - + + Display Checklist - Lista verificación pantalla + Lista de verific. - - - - - - - + + Timer 2 Temporizador 2 - - - - - - - + + Timer 1 - Temporizador1 + Temporizador 1 - - - - - - - + + Timer 3 - Temporizador3 + 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 del acelerador + Fuente acelerador - - - - - - - + + Trim Step - Pasos de Trim + Paso de trim - - - - - - - + + Trims Display - + Mostrar trims - - - - - - - + + Warnings Avisos - - - - - - - + + Switch Warnings - Avisos palancas (Switch) + Avisos interruptores - - - - - - - + + Pot Warnings Avisos Potenciómetros - - - - - - - + + Manual - + Manual - - - - - - - + + Auto - - - - - - - + + Model Modelo - - - - - - - + + 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. @@ -15211,38 +12304,33 @@ Si está marcado el acelerador será invertido. El ralentí será delante, el t - - - - - - - + + Reverse Throttle - Invertir acelerador (Throttle) + Invertir acelerador SetupPanel - + 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 @@ -15250,7 +12338,7 @@ Si está marcado el acelerador será invertido. El ralentí será delante, el t Elevator Channel: - Canal Profundidad (Elevator): + Canal de profundidad: @@ -15259,203 +12347,203 @@ Si está marcado el acelerador será invertido. El ralentí será delante, el t screenshot Simulator LCD screenshot file name prefix - + captura ENTER - + INTRO S - + PG-UP - + RE PÁG PG-DN - + AV PÁG DEL - + SUPR BKSP - + RETR ESC - + INS - + <font size=+3>+</font> - + <font size=+3>-</font> - + <font size=+3>&larr;</font> - + <font size=+3>&rarr;</font> - + <font size=+3>&uarr;</font> - + <font size=+3>&darr;</font> - + <font size=+3>&#x2686;</font> - + <font size=+3>&#x21b6;</font> - + <font size=+3>&#x21b7;</font> - + <font size=+3>&#x21c6;</font> - + <font size=+3>&#x21d3;</font> - + <font size=+3>&#x21d1;</font> - + <font size=+3>&#x21d5;</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>&#x2261;</font> - + @@ -15463,1041 +12551,673 @@ Si está marcado el acelerador será invertido. El ralentí será delante, el t OpenTx Simulator - + Simulador de OpenTx Available profiles: - + Perfiles disponibles: ID: - + Name: - + Nombre: Available radios: - + Radios disponibles: Radio profile ID or Name to use for simulator. - + Perfil ID de radio o nombre a usar para simulador. profile - + perfil Radio type to simulate (usually defined in profile). - + Tipo de radio a simular (normalmente definido en el perfil). radio - + radio Directory containing the SD card image to use. The default is configured in the chosen Radio Profile. - + Directorio conteniendo la imagen de la tarjeta SD a usar. El predeterminado es configurado en el perfil de radio seleccionado. path - + ruta Data source type to use (applicable to Horus only). One of: - + Origen de datos a usar (sólo aplicable a Horus). Uno de: type - + tipo data-source - + origen-datos 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! - + Imagen de datos de radio (.bin/.eeprom/.otx) o carpeta (para radios estilo Horus) a usar. +NOTA: cualquier dato EEPROM incompatible con la radio seleccionada puede ser sobreescrito! [data-source] - + [origen-datos] Error: Profile ID %1 was not found. - + Error: Perfil ID %1 no encontrado. Unrecognized startup data source type: %1 - + Tipo de origen de datos de arranque desconocido: %1 WARNING: couldn't initialize SDL: %1 - + WARNING: No se puede inicializar SDL: +%1 ERROR: No simulator libraries available. - + ERROR: No hay librerías de simulador disponibles. ERROR: Couldn't start simulator, missing radio/profile/data file/folder. Profile ID: [%1]; Radio ID: [%2]; Data File: [%3] - + ERROR: No se puede iniciar el simulador, falta radio/perfil/datos ficheo/carpeta. + Perfil ID: [%1]; Radio ID: [%2]; +Archivo datos: [%3] ERROR: Radio profile or simulator firmware not found. Profile ID: [%1]; Radio ID: [%2] - + ERROR: Perfil de radio o firmware del simulador no encontrado. +Perfil ID: [%1]; Radio ID: [%2] Uknown error during Simulator startup. - + Error desconocido al iniciar el simulador. SimulatorMainWindow - - - - - - - - - + + OpenTx Simulator - + Simulador de OpenTX - - - - - - - - - + + View - + Vista - - - - - - - - - + + Radio Window - + Ventana de radio - - - - - - - - - + + Reload... - + Recargar... - - - - - - - - - + + Tools - + Herramientas - - - - - - - - - + + Toolbar - + Barra de herramientas - - - - - - - - - + + Reload Lua Scripts - + Recarga scripts Lua - - - - - - - - - + + Reload the Lua environment on the simulated radio. - + Recarga el entorno Lua en la simulación de la radio. - - - - - - - - - + + F7 - + - - - - - - - - - + + Reload Radio Data - + Recarga datos de radio - - - - - - - - - + + Reload all radio data without restarting the simulator. - + Recarga todos los datos de la radio sin reiniciar el simulador. - - - - - - - - - + + F9 - + - - - - - - - - - + + Key Mapping - + Mapa de teclas - - - - - - - - - + + Show keyboard maping reference. - + Muestra el mapa de teclas. - - - - - - - - - + + F1 - + - - - - - - - - - + + Joystick Settings - + Ajustes joystick - - - - - - - - - + + Open joystick configuration settings dialog. - + Abre la configuracíon de ajustes del joystick. - - - - - - - - - + + F3 - + - - - - - - - - - + + LCD Screenshot - + Captura LCD - - - - - - - - - + + Save a screenshot of the current simulated LCD screen. - + Guarda una captura de la simulación de la pantalla LCD. - - - - - - - - - + + F8 - + - - - - - - - - - + + Dock In Main Window - + Anclar en la ventana principal - - - - - - - - - + + 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. - - - - - - - - - + + Menu Bar - + Barra superior - - - - - - - - - + + Show or hide the top menu bar. - + Muestra u oculta la barra superior. - - - - - - - - - + + Alt+M - + Alt+M - - - - - - - - - + + Constrain Width - + Restringir ancho - - - - - - - - - + + Set radio widget width to be a fixed size. - + Fija el ancho de widget de la radio a un tamaño fijo. - - - - - - - - - + + Constrain Height - + Restringir alto - - - - - - - - - + + Set radio widget height to be a fixed size. - + Fija el alto de widget de la radio a un tamaño fijo. ERROR: Failed to create simulator interface, possibly missing or bad library. - + ERROR: No se puede crear la interfaz de simulador, posiblemente falta o es erronea la librería. Alt+T - + Radio Outputs - + Salidas de radio F2 - + Telemetry Simulator - + Simulador de telemetría F4 - + Trainer Simulator - + Simulador de entrenador F5 - + Debug Output - + Salida de depuración F6 - + <b>Simulator Controls:</b> - + <b>Controles simulador:</b> <tr><th>Key/Mouse</th><th>Action</th></tr> note: must match html layout of each table row (keyTemplate). - + <tr><th>Tecla/Ratón</th><th>Acción</th></tr> <tr><td><kbd>%1</kbd></td><td>%2</td></tr> note: must match html layout of help text table header. - + <tr><td><kbd>%1</kbd></td><td>%2</td></tr> Simulator Help - + Ayuda simulador SimulatorStartupDialog - - - - - - - - - + + OpenTX Simulator - Startup Options - + Simulador de OpenTX - Opciones de arranque - - - - - - - - - + + Simulator Startup Options: - + Opciones de arranque del simulador: - - - - - - - - - + + Radio Profile: - + Perfil de radio: - - - - - - - - - + + Existing radio profiles are shown here.<br /> Create or edit profiles using the Companion application. - + Los perfiles de radio existentes se muestran aquí.<br /> +Crea o edita perfiles usando la aplicación de Companion. - - - - - - - - - + + Radio Type: - + Tipo de radio: - - - - - - - - - + + 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 /> +Por defecto se us el tipo de radio especificado en en perfil seleccionado. - - - - - - - - - + + Data Source: - + Origen de datos: - - - - - - - - - + + Data File: - + Archivo de datos: - - - - - - - - - + + Data Folder: - + Carpeta de datos: - - - - - - - - - + + SD Image Path: - + Ruta de la imagen SD: - - - - - - - - - + + 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 /> +<b>NOTE</b>: cualquier EEPROM incompatible con la radio selccionada se sobreescribirá! - - - - - - - - - + + Select data file... - + Selecciona archivo de datos... - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + ... - + - - - - - - - - - + + 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 /> +Nuevas carpeta(s) con radio/modelo predeterminado se crearán aquí si es necesario. - - - - - - - - - + + Select data folder... - + Selecciona carpeta de datos... - - - - - - - - - + + 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/> +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... - - - - - - - - - + + 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. - - - - - - - - - + + File - Archivo + Archivo - - - - - - - - - + + Folder - + Carpeta - - - - - - - - - + + SD Path - + Ruta SD All files (*.*) - + Todos los ficheros (*.*) Select a data file - + Selecciona un archivo de datos Select Data Directory - + Selecciona directorio de datos Select SD Card Image Folder - + Selecciona carpeta de imágenes de la tarjeta SD SimulatorWidget - - - - - - - - - + + Companion Simulator - Simulador Companion + Simulador Companion Radio Simulator (%1) - + 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 + No se puede abrir el joystick, joystick desactivado @@ -16505,12 +13225,12 @@ The default is configured in the chosen Radio Profile. Right-double-click to reset to center. - + Doble click derecho para reiniciar el centro. <p>Value (input): <b>%1</b></p> - + <p>Valor (entrada): <b>%1</b></p> @@ -16518,32 +13238,22 @@ The default is configured in the chosen Radio Profile. - - - - - - - - - - - - - - + + + + ... Splash Library - page %1 of %2 - LIbreria de pantallas de inicio - página %1 de %2 + LIbrería de pantallas de inicio - página %1 de %2 Invalid image in library %1 - Imagen inválida en la librería %1 + Imagen no válida en la librería %1 @@ -16564,91 +13274,69 @@ The default is configured in the chosen Radio Profile. Unable to find file %1! - ¡No es posible encontrar el archivo %1! + ¡No se puede encontrar el archivo %1! StyleEditDialog - - - - - - - + + Style Sheet Editor - + Editor de hoja de estilo - - - - - - - + + &Reset to default - + &Reiniciar a los predeterminados - - - - - - - + + &Cancel - + &Cancelar - - - - - - - + + &OK - + - - - - - - - + + This feature does not validate your changes and assumes you are familiar with CSS syntax for QT. - + Esta propiedad no valida tus cambios y asume que eres familiar con la sintaxis CSS para QT. Cannot retrieve style %1 Error: %2 - + No se puede obtener el estilo %1 +Error: %2 Cannot retrieve default style %1 Error: %2 - + No se puede obtener el estilo predeterminado %1 +Error: %2 Cannot update custom style %1 Error: %2 - + No se puede actualizar el estilo personalizado %1 +Error: %2 @@ -16656,47 +13344,47 @@ Error: %2 Style sheet data read from '%1' - + Hoja de estilo leída desde '%1' Style sheet data unable to be read from '%1' - + No se puede leer hoja de estilo desde '%1' Cannot create folder '%1' - + No se puede crear el directorio '%1' Cannot open file for writing '%1': Error: %2 - + No se puede abrir el archivo para escritura '%1': Error: %2 Cannot write to file '%1': Error: %2 - + No se puede escribir en el archivo '%1': Error: %2 Cannot flush buffer for file '%1': Error: %2 - + No se puede vaciar buffer para el archivo '%1': Error: %2 Style sheet written to '%1' - + Hoja de estilo escrita a '%1' Custom style sheet deleted: '%1' - + Hoja de estilo personalizada borrada: '%1' Unable to delete custom style sheet: '%1' - + No se puede borrar hoja de estilo personalizada: '%1' @@ -16704,141 +13392,145 @@ Error: %2 [TEST RUN] - + [TEST RUN] Synchronization failed, nothing found to copy. - + Sincronización fallida, no se ha encontrado nada para copiar. Skipping large file: %1 (%2KB) - + Omitiendo archivo largo: %1 (%2KB) Creating directory: %1 - + Creando directorio: %1 Could not create directory: %1 - + No se puede crear el directorio: %1 Gathering file information for %1... - + Reuniendo información del archivo para %1... No files found in %1 - + Ficheros no encontrados en %1 Synchronization aborted at %1 of %2 files. - + Sincronización abortada con %1 de %2 ficheros. Synchronization finished with %1 files in %2m %3s. - + Sincronización finalizada con %1 ficheros en %2m %3s. Synchronizing: %1 To: %2 - + Sincronizando: %1 + a: %2 Starting synchronization: %1 -> %2 - + Iniciando sincronización: + %1 -> %2 + Too many errors, giving up. - + +Demasiados errores, abortando. Skipping filtered file: %1 - + Omitiendo archivo filtrado: %1 Skipping linked file: %1 - + Omitiendo archivo linkado: %1 Aborted synchronization of: - + Sincronizacíon abortada de: Finished synchronizing: - + Sincronización finalizada: Created: %1; Updated: %2; Skipped: %3; Errors: %4; - + Creado: %1; Actualizado: %2; Omitido: %3; Errores: %4; Directory exists: %1 - + Existe el directorio: %1 At least one of the file modification dates is in the future, error on: %1 - + Al menos una de las fechas de modificación de los ficheros está en el futuro, error en: %1 Skipping older file: %1 - + Omitiendo fichero más antiguo: %1 Could not open source file '%1': %2 - + No se puede abrir el archivo de origen '%1': %2 Could not open destination file '%1': %2 - + No se puede abrir el archivo de destino '%1': %2 Skipping identical file: %1 - + Omitiendo archivo idéntico: %1 Replacing file: %1 - + Reemplazando archivo:; %1 Creating file: %1 - + Creando archivo: %1 Could not delete destination file '%1': %2 - + No se puede borrar el archivo de destino '%1': %2 Copy failed: '%1' to '%2': %3 - + Copia fallida: '%1' a '%2': %3 @@ -16851,12 +13543,12 @@ Too many errors, giving up. Elevator Channel: - Canal Profundidad (Elevator): + Canal de profundidad: Only one channel still available!<br>You probably should configure your model without using the wizard. - + ¡Sólo hay un canal disponible!<br>Deberías configurar el modelo sin el asistente. @@ -16869,7 +13561,7 @@ Too many errors, giving up. Only Elevator - Solo profundidad + Sólo profundidad @@ -16886,766 +13578,433 @@ Too many errors, giving up. Telemetry - - - - - - - + + A1 - - - - - - - + + A2 - - - - - - - + + RSSI - - - - - - - + + Alarm 1 Alarma 1 - - - - - - - - - - - - - - + + + + ---- - - - - - - - - - - - - - - + + + + Yellow Amarillo - - - - - - - - - - - - - - + + + + Orange Naranja - - - - - - - - - - - - - - + + + + Red Rojo - - - - - - - + + Alarm 2 Alarma 2 - - - - - - - + + Disable telemetry audio warnings - + Desactivar avisos de telemetría - - - - - + + Source - + Fuente - - - - - - - + + Center Silent - + Centro silencioso - - - - - - - + + Altitude source - + Fuente de altitud - - - - - - - + + Volts source - + Fuente de voltage - - - - - - - + + Top Bar - + Barra superior - - - - - - - + + Serial Protocol - Protocolo Serie + Protocolo serie - - - - - - - + + Sensors - + Sensores - - - - - - - + + Disable multi sensor handling - + Desactivar soporte sensor múltiple - - - - - - - + + Volt source Fuente Voltaje - - - - - - - + + Current source Fuente Actual - - - - - - - + + Protocol Protocolo - - - - - - - + + None Ninguno - - - - - - - + + FrSky Sensor Hub - + FrSky Sensor Hub - - - - - - - + + Blades Palas - - - - - - - + + Sink Max - Descenso Máximo + Máximo descenso - - - - - - - + + Climb Max - Máximo Ascenso + Máximo ascenso - - - - - - - + + Sink Min - Descenso Mínimo + Mínimo descenso - - - - - - - + + Climb Min - Mínimo Ascenso + Mínimo ascenso - - - - - - - + + Vario source - Fuente Variómetro + Fuente variómetro - - - - - - - + + Vario limits - Límites Variómetro + Límites variómetro - - - - - - - + + Altimetry Altímetro - - - - - - - + + mAh - - - - - - - + + A - - - - - - - + + Various Varios - - - - - - - + + mAh count Valor mAh - - - - - - - + + FAS Offset - - - - - - - + + Persistent mAh - mAh Constantes + mAh constantes TelemetryAnalog - - - - - - - + + Unit Unidad - - - - - - - + + Max Value - Valor Máximo + Valor máx - - - - - - - + + Alarm 1 Alarma 1 - - - - - - - - - - - - - - + + + + ---- - - - - - - - - - - - - - - + + + + Yellow Amarillo - - - - - - - - - - - - - - + + + + Orange Naranja - - - - - - - - - - - - - - + + + + Red Rojo - - - - - - - - - - - - - - + + + + < - - - - - - - - - - - - - - + + + + > - - - - - - - + + Alarm 2 Alarma 2 - - - - - - - + + Offset - 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 (°) - Temp (°) + - - - - - - - + + Fuel (%) Combustible (%) - - - - - - - + + mAmps (mA) miliAmperios (mA) @@ -17659,25 +14018,20 @@ Too many errors, giving up. TelemetryCustomScreen - - - - - - - + + Custom Screen Type Personalizar tipo pantalla None - Ninguno + Ninguno Numbers - + Números @@ -17687,53 +14041,33 @@ Too many errors, giving up. Script - + Script - - - - - - - + + Min Mínimo - - - - - - - + + Source Fuente - - - - - - - + + Gauge Medida - - - - - - - + + Max Máximo @@ -17741,104 +14075,104 @@ Too many errors, giving up. TelemetryPanel - + FrSky S.PORT - + FrSky D - + FrSky D (cable) - + Telemetry screen %1 Pantalla telemetría %1 - + Source - + Fuente - + Low Alarm - Alarma Baja + 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 - + --- @@ -17847,1068 +14181,649 @@ Too many errors, giving up. TelemetrySensor - - - - - - - + + Form - - - - - - - - - - - - Custom - A medida - - - - - - - - - - - Calculated - + Form - - - - - - - + + + Custom + Personalizado + + + + + + Calculated + Calculado + + + + + Id - + - - - - - - - - + + + Instance - + Instancia - - - - - + + + Rx - + - - - - - - Mod. - - - - - - - - - - - + + + Add - + Suma - - - - - - - - + + + Average - + Media - - - - - - - - + + + Min - + Mín - - - - - - - - + + + Max - + Máx - - - - - - - - + + + Multiply - + Multiplicar - - - - - - - - + + + Totalize - + Total - - - - - - - - + + + Cell - + Celda - - - - - - - - + + + Consumption - + Consumo - - - - - - - - + + + Dist - + Distancia - - - - - - - - + + + Cells Sensor : - + Sensor celdas : - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + --- - --- + - - - - - - - - + + + GPS Sensor : - + Sensor GPS: - - - - - - - - + + + Alt. Sensor : - + Sensor alt: - - - - - - - - + + + Sensor : - + - - - - - - - - + + + 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 (-) - + - - - - - - - - + + + + TELE## + + + + + + RPM - + - - - - - - - - + + + + ml/min + + + + + + Precision - + Precisión - - - - - - - - + + + Ratio - + Ratio - - - - - - - - + + + Blades - Palas + Palas - - - - - - - - + + + Offset - Offset + Offset - - - - - - - - + + + Multiplier - + - - - - - - - - + + + Auto Offset - + - - - - - - - - + + + Filter - + Filtro - - - - - - - - + + + Persistent - + Persistente - - - - - - - - + + + Positive - Positivo + Positivo - - - - - - - - + + + Logs - + 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 + + + + Clear All + Limpiar todo + + + + 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? TelemetrySimulator - - - - - - - - - + + Telemetry Simulator - + Simulador de telemetría - - - - - - - - - + + VFAS - + - - - - - - - - - + + RSSI - + - - - - - - - - - + + A1 - + - - - - - - - - - + + A2 - + - - - - - - - - - + + Simulate - Simular + Simular - - - - - - - - - + + Replay SD Log File - + Reproducir archivo SD de reporte - - - - - - - - - + + Replay rate - + Velocidad de reproducción - - - - - - - - - + + Load - + Cargar - - - - - - - - - + + |> - + - - - - - - - - - + + <| - + - - - - - - - - - + + > - + - - - - - - - - - + + <- - + - - - - - - - - - + + X - + - - - - - - - - - + + Row # Timestamp - + Col # +Tiempo - - - - - - - - - + + 1/5x - 1/5x + - - - - - - - - - + + 5x - 5x + - - - - - - - - - + + No Log File Currently Loaded - + Actualmente no hay cargado archivo de reporte - - - - - - - - - + + RAS - + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + V / ratio - + - - - - - - - - - + + Db - + - - - - - - - - - + + RxBt - + @@ -18924,730 +14839,331 @@ Timestamp - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + <html><head/><body><p><br/></p></body></html> - + - - - - - - - - - + + Tmp1 - + Temporizador 1 - - - - - - - - - + + A3 - + - - - - - - - - - + + A4 - + - - - - - - - - - + + Tmp2 - + Temporizador 2 - - - - - - - - - + + Fuel - Combustible + Combustible - - - - - - - - - - - - - - - - - - + + + + °C - + - - - - - - - - - + + ml - + - - - - - - - - - + + % - + - - - - - - - - - - - - - - - - - - + + + + Meters - + Metros - - - - - - - - - + + Alt - + - - - - - - - - - + + VSpd - + VelocVertical - - - - - - - - - + + m/s - + - - - - - - - - - + + Fuel Qty - + Cant. combust. - - - - - - - - - - - - - - - - - - + + + + km/h - + - - - - - - - - - + + Hdg - + - - - - - - - - - + + ASpd - + VelocAire - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + G - + - - - - - - - - - + + GPS - + - - - - - - - - - + + Lat,Lon (dec.deg.) - + - - - - - - - - - + + AccX - + - - - - - - - - - + + dd-MM-yyyy hh:mm:ss - + - - - - - - - - - + + Date - + Fecha - - - - - - - - - + + Amps - + - - - - - - - - - + + AccZ - + - - - - - - - - - + + GAlt - + - - - - - - - - - - - - - - - - - - + + + + Volts - + Voltios - - - - - - - - - + + Cels - + Celdas - - - - - - - - - + + Curr - + - - - - - - - - - + + AccY - + - - - - - - - - - + + GSpd - + VelocTierra - - - - - - - - - + + Degrees - + Grados - - - - - - - - - + + 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. - - - - - - - - - + + Set RSSI to zero when paused. - + Fijar RSSI a cero en pausa. - - - - - - - - - + + Stop sending telemetry data when the Telemetry Simulator window is hidden. - + Para de enviar datos de telemetría cuado el simulador esté oculto. - - - - - - - - - + + Pause simulation when hidden. - + Pausar simulación cuando se oculte. - - - - - - - - - - - - - - - - - - + + + + RPM - + - - - - - - - - - + + 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. Log File - + Archivo Log LOG Files (*.csv) - + Ficheros LOG (*.csv) ERROR - invalid file - + ERROR - archivo no válido @@ -19655,44 +15171,34 @@ hh:mm:ss Yes - Si + Sí No - No + <br>Throttle Channel: - <br>Canal de Acelerador: + <br>Canal de acelerador: Timer - - - - - - - + + Countdown - Cuenta Atrás + Cuenta atrás - - - - - - - + + Minute Call - Cada Minuto + Cada minuto @@ -19700,12 +15206,12 @@ hh:mm:ss TMR - + Timer %1 - + Temporizador %1 @@ -19714,22 +15220,23 @@ hh:mm:ss 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. - + Usar el scroll del ratón o teclas ARRIBA/ABAJO para cambiar el tiempo en pequeños pasos. +CTRL + scroll o AV/RE PÁG para cambiar el tiempo en pasos grandes. m - + h - + s - + @@ -19752,7 +15259,7 @@ CTRL + scroll or PAGE UP/DOWN keys to change time in larger steps. Haptic - Reproducir Haptic + @@ -19774,63 +15281,38 @@ CTRL + scroll or PAGE UP/DOWN keys to change time in larger steps. Trainer - - - - - - - + + Form - + - - - - - - - + + Mode - Modo + Modo - - - - - - - + + Input - Entrada + Entrada - - - - - - - + + Weight - + Peso - - - - - - - + + Rud - Rud + @@ -19841,62 +15323,22 @@ CTRL + scroll or PAGE UP/DOWN keys to change time in larger steps. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + Beeper volume 0 - Quiet. No beeps at all. @@ -19904,10 +15346,10 @@ CTRL + scroll or PAGE UP/DOWN keys to change time in larger steps. 2 - Normal. 3 - Loud. 4 - Extra loud. - Volumen Beeper + Volumen Beeper 0 - Silencio. Ningun tipo de beep. -1 - Sin 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. @@ -19917,305 +15359,143 @@ CTRL + scroll or PAGE UP/DOWN keys to change time in larger steps. - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + Off - Apagado + Apagado - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + += (Sum) - + += (Suma) - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + := (Replace) - := (Reemplazar) + := (Reemplazar) - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + chn1 - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + chn2 - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + chn3 - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + chn4 - + - - - - - - - + + Ele - Ele + - - - - - - - + + Thr - Thr + - - - - - - - + + Ail - Ail + TrainerSimulator - - - - - - - - - + + Trainer simulator - + Simulador de entrenador @@ -20223,34 +15503,34 @@ CTRL + scroll or PAGE UP/DOWN keys to change time in larger steps. Index - + Índice Name - Nombre + Nombre Size - + Tamaño RX # - + Models Translators do NOT use accent for this, this is the default category name on Horus. - + Modelos Model %1 Translators: do NOT use accents here, this is a default model name. - + Modelo %1 @@ -20258,12 +15538,12 @@ CTRL + scroll or PAGE UP/DOWN keys to change time in larger steps. First Tail Channel: - Primer Canal de cola: + Primer canal de cola: Second Tail Channel: - Segundo Canal de cola: + Segundo canal de cola: @@ -20271,42 +15551,42 @@ CTRL + scroll or PAGE UP/DOWN keys to change time in larger steps. Hld Y - + Hold Vertical stick position. - + Mantener la posición vertical del stick. Fix Y - Fijar Y + Fijar Y Prevent Vertical movement of stick. - + Evitar el movimiento vertical del stick. Fix X - Fijar X + Fijar X Prevent Horizontal movement of stick. - + Evitar el movimiento horizontal del stick. Hld X - + Hold Horizontal stick position. - + Mantener la posición horizontal del stick. @@ -20314,7 +15594,7 @@ CTRL + scroll or PAGE UP/DOWN keys to change time in larger steps. Standard Wing - Ala estandar + Ala estándar @@ -20372,7 +15652,7 @@ CTRL + scroll or PAGE UP/DOWN keys to change time in larger steps. Flaps - + Flaps @@ -20464,7 +15744,7 @@ CTRL + scroll or PAGE UP/DOWN keys to change time in larger steps. Rotor Type - Tipo Rotor + Tipo rotor @@ -20486,7 +15766,7 @@ CTRL + scroll or PAGE UP/DOWN keys to change time in larger steps. Multirotor - + Multirotor @@ -20511,7 +15791,7 @@ CTRL + scroll or PAGE UP/DOWN keys to change time in larger steps. 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! - Comprobar manualmente la dirección de cada control de superficie y los reversos de cualquier canal para que el control de movimiento no se erroneo. Saca la hélice/hélices antes de intentar controlar tu modelo por primera vez.<br> ¡Por favor tenga en cuenta eliminar los ajustes viejos! + Comprobar manualmente la dirección de cada control de superficie y los reversos de cualquier canal para que el control de movimiento no sea erróneo. Saca la hélice/hélices antes de intentar controlar tu modelo por primera vez.<br> ¡Por favor ten en cuenta que continuar eliminar los ajustes anteriores del modelo! @@ -20526,17 +15806,17 @@ CTRL + scroll or PAGE UP/DOWN keys to change time in larger steps. 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. - La mayoría de los aviones tienen un ala principal y una cola con controles de superficie. Volando alas y alas delta solo hay un ala simple. El control principal de superficie en un ala estandar controla el alabeo del avión. Esta superficie se llama alerón.<br> El control de superficie de un ala delta controla ambos alabeo y cabeceo. Esta superficie se llama elevon. + La mayoría de los aviones tienen un ala principal y una cola con controles de superficie. Volando alas y alas delta sólo hay un ala simple. El control principal de superficie en un ala estandar controla el alabeo del avión. Esta superficie se llama alerón.<br> El control de superficie de un ala delta controla ambos alabeo y cabeceo. Esta superficie se llama elevon. 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 - Los modelos usan 1 o 2 canales para controlar los alerones.<br>Un cable en Y se puede usar para conectar un solo canal del receptor a dos servos separados de los alerones. Si usas servos conectados por un cable Y debes seleccionar la opcion de servo único.<br><br> Alerón Spektrum: CH2, Futaba CH1 + Los modelos usan 1 o 2 canales para controlar los alerones.<br>Un cable en Y se puede usar para conectar un sólo canal del receptor a dos servos separados de los alerones. Si usas servos conectados por un cable Y debes seleccionar la opcion de servo único.<br><br> Alerón - Spektrum: CH2, Futaba CH1 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. - Este asistente asume que tus flaps estan controlados por un switch. Si tus flaps están controlados por un potenciómetro lo puedes cambiar manualmente mas tarde. + Este asistente asume que tus flaps estan controlados por un interruptor. Si tus flaps están controlados por un potenciómetro lo puedes cambiar manualmente más tarde. @@ -20616,12 +15896,12 @@ CTRL + scroll or PAGE UP/DOWN keys to change time in larger steps. Model Name: - Nombre Modelo: + Nombre modelo: Model Type: - Tipo Modelo: + Tipo Modelo: @@ -20638,38 +15918,23 @@ CTRL + scroll or PAGE UP/DOWN keys to change time in larger steps. burnConfigDialog - - - - - - - + + AVRDUDE Location - Localización AVRDUDE + Ubicación AVRDUDE - - - - - - - + + Location of AVRDUDE executable Locatioon of AVRDUDE executable - Localización del ejecutable AVRDUDE + Ubicación del ejecutable AVRDUDE - - - - - - - + + Programmer Configuration Configuration AVRDUDE / SAM-BA Configuración del programador @@ -20679,127 +15944,62 @@ CTRL + scroll or PAGE UP/DOWN keys to change time in larger steps. - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + The location of the AVRDUDE executable. The location of the AVRDUDE.EXE executable. - La localización del ejecutable AVRDUDE. + La ubicación del ejecutable AVRDUDE. - - - - - - - + + DFU-Util Location - Localización de la utilidad DFU + 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 mirar el archivo ejecutable de AVRDUDE. + 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. @@ -20807,65 +16007,35 @@ Por favor consulta la documentacion del programador y la documentación de AVRDU - - - - - - - + + List all available programmers. Lista todos los programadores disponibles. - - - - - - - + + List Available - Listado Disponibles + Listado disponibles - - - - - - - - - - - - - - + + + + Extra arguments that will be passed to AVRDUDE on every call - Argumentos extras que deben pasar a AVRDUDE en cada llamada + 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. @@ -20877,174 +16047,99 @@ Por favor solamente usa esto si sabes lo que estás haciendo. No hay control de - - - - - - - + + Extra Arguments Argumentos extra - - - - - - - + + Show AVRDUDE help Mostrar la ayuda de AVRDUDE - - - - - - - + + Show Help - Mostrar Ayuda + 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 - Localizacon SAM-BA + Ubicación SAM-BA - - - - - - - - - - - - - - + + + + Location of sam-ba executable - Localización del ejecutable sam-ba + Ubicación del ejecutable sam-ba - - - - - - - + + ARM MCU - - - - - - - + + sam-ba serial port Puerto serie sam-ba @@ -21068,60 +16163,40 @@ Por favor solamente usa esto si sabes lo que estás haciendo. No hay control de Select Location - Seleccionar localización + Seleccionar ubicación List available programmers - Lista de programadores disponibles + 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 ees automáticamente elegida para el tipo de firmware.<br>Si cambias el tipo de CPU el eeprom resultante podria ser inconsistente. + <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 a tu TX + CPU de tu TX - - - - - - - - - - - - - - + + + + CPU present on your 9x radio Should be m64 for stock radios m2560 for v4.1 boards @@ -21134,199 +16209,101 @@ m2560 para las placas v4.1 joystickDialog - - - - - - - - - + + Configure Joystick - Configurar Joystick + Configurar joystick - - - - - - - - - + + Ch2 - - - - - - - - - + + Ch1 - - - - - - - - - + + Ch4 - - - - - - - - - + + Ch6 - - - - - - - - - + + Ch3 - - - - - - - - - + + Ch5 - - - - - - - - - + + Ch7 - - - - - - - - - + + Ch8 - - - - - - - - - + + Instructions Instrucciones - - - - - - - - - + + Enable - + Activar - - - - - - - - - + + Cancel Cancelar - - - - - - - - - + + Back - + Atrás - - - - - - - - - + + Start - Comenzar + Inicio @@ -21335,37 +16312,30 @@ m2560 para las placas v4.1 - - - - - - - - - + + Ok Not Assigned - + No asignado Stick - + Knob/Slider %1 - + Knob/Slider %1 No joysticks found - No se han encopntrado joysticks + No se han encontrado joysticks @@ -21376,158 +16346,48 @@ m2560 para las placas v4.1 Press the Start button to start the stick range calibration procedure. You may change the channel assignments or inversion at any time. - + Presiona el botón Inicio para empezar el procedimiento de calibración de los stick +Puedes cambiar la asinación de canales o inversión en cualquier momento. Move sticks and pots in every direction making full movement Press Next when finished - + Mueve los sticks y pots hasta el final en todas las direcciones +Presiona Siguiente al finalizar Place sticks and pots in middle position. Press Next when done - + Mueve los sticks y pots a la posición central +Presiona Siguiente al finalizar Map joystick channels to controls using comboboxes. Press Next when done. - + Mapea los canales de joystick a los controles usando las listas deplegables +Presiona Siguiente al finalizar. Check inversion checkbox to if necessary to reverse direction. Press Next when done. - + Revisa la casilla de inversión si es necesario invertir la dirección. +Presiona Siguiente cuando finalices. Press OK to save configuration Press Cancel to abort joystick calibration without saving. - + Presiona OK oara guardar la configuración +Presiona Cancelar para abortar la calibración del joystick sin guardar. Calibration not complete, save anyway? - - - - - preferencesDialog - - - Preferences - Preferencias - - - - Simulator capture folder - Carpeta de captura de simulador - - - - Use clipboard only - Usar sólo portapapeles - - - - - ... - - - - - Splash library behaviour - Libreria de pantallas de inicio - - - - Remember simulator switches - Recordar los switch en el simulador - - - - Include companion splashes - Incluir pantallas de inicio de companion - - - - Only user defined splashes - Solo pantallas de inicio definidas por el usuario - - - - Custom TX splash screen - Pantalla de inicio personalizada del TX - - - - Personal splash library - Pantallas de inicio personales - - - - Joystick - - - - - - Open Folder - Abrir Carpeta - - - - Blue - Blu - Azul - - - - Simu BackLight - Luz de fondo del simulador - - - - Green - Verde - - - - Red - Rojo - - - - Orange - Naranja - - - - Yellow - Amarillo - - - - Enable - Activado - - - - Calibrate - Calibrar - - - - Open Image - Abrir Imagen - - - - Invert Pixels - Ivertir Pixeles + Calibración incompleta, ¿guardar? diff --git a/companion/src/translations/companion_fr.ts b/companion/src/translations/companion_fr.ts index 98fb5663a..c8d06c20f 100644 --- a/companion/src/translations/companion_fr.ts +++ b/companion/src/translations/companion_fr.ts @@ -103,32 +103,32 @@ Profil de radio - + Default Channel Order Ordre des voies par défaut - + Build Options Options de compilation - + Menu Language Langue des menus - + Default Stick Mode Mode par défaut - + Select Image Sélectionner une image - + Mode selection: Mode 1: @@ -169,526 +169,541 @@ Manche Droit: Profondeur, Direction - + Mode 1 (RUD ELE THR AIL) Mode 1 (DIR PROF GAZ AIL) - + Mode 2 (RUD THR ELE AIL) Mode 2 (DIR GAZ PROF AIL) - + Mode 3 (AIL ELE THR RUD) Mode 3 (AIL PROF GAZ DIR) - + Mode 4 (AIL THR ELE RUD) Mode 4 (AIL GAZ PROF DIR) - + Splash Screen Ecran d'accueil - - + + The profile specific folder, if set, will override general Backup folder Dossier de sauvegarde spécifique au profil courant, si défini remplace le paramètre de l'application - + Backup folder Dossier de sauvegarde - + If set it will override the application general setting Si défini, remplace le paramètre de l'application pour ce profil - + if set, will override general backup enable Si défini, remplace le paramètre de l'application pour ce profil - + <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> - + 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 - - - - - - + + + + + + Select Folder Sélectionner dossier - + + Show splash screen + Afficher l'écran de démarrage + + + Select Executable Sélectionner exécutable - + Release channel Canal de version - + Releases (stable) Officiel (stable) - + Release candidates (testing) Candidate (test) - + Nightly builds (unstable) Nighlty (instable) - + Simulator Volume Gain Gain de volume du simulateur - + + Simulator controls + Commandes du simulateur + + + + Save switch/pot positions on simulator exit + Enregistrer les positions des inters/pots à la sortie du simulateur + + + + Clear saved positions + Effacer les positions enregistrées + + + Profile Name Nom du profil - + Clear Image Effacer l'image - + Append version number to FW file name Ajouter le numéro de version au nom du fichier téléchargé - + Offer to write FW to Tx after download Proposer de transférer le firmware à la radio après téléchargement - + Radio Type Type de radio - + Other Settings Autres paramètres - + General Settings Paramètres généraux - + SD Structure path Chemin de la structure de la carte SD - + Application Settings Paramètres de l'application - - Show splash screen when Companion starts - Afficher l'écran d'accueil au lancement de Companion - - - + Automatic check for Companion updates Vérifier la présence de mises à jour de Companion automatiquement - - + + Enable automatic backup before writing firmware Sauvegarder les paramètres et modèles automatiquement lors des transferts - + Automatic check for OpenTX firmware updates Vérifier la présence de mises à jour de firmware automatiquement - + Splash Screen Library Bibliothèque d'écrans d'accueil - + Google Earth Executable Exécutable Google Earth - + Only show user splash images Ne montrer que les images de l'utilisateur - + Show user and companion splash images Montrer les images de Companion et de l'utilisateur - + User Splash Screens Ecrans d'accueil personnalisés - + Automatic Backup Folder Dossier de sauvegardes automatiques - + Simulator Settings Paramètres du simulateur - + Simulator BackLight Rétroéclairage du simulateur - + Enable Actif - + Action on New Model Action par défaut "Ajout Modèle" - + Use model wizard Assistant - + Open model editor Éditer modèle - + Just create the model Créer modèle - + <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><b><u>/!\</u> Uniquement pour les radios sans catégories <u>/!\</u></b></p><p>Cette option maintient le comportement des anciennes versions d’OpenTx où les emplacements des modèles vides sont conservés lorsqu'un modèle est supprimé ou déplacé.</p><p>Lorsque cette option est désélectionnée, les autres modèles peuvent être réarrangés pour combler l'écart laissé par le modèle supprimé.</p></body></html> - + most recently used files fichiers récemment utilisés - + Startup Settings Paramètres de démarrage - + Remember Mémoriser - + Output Logs Folder Dossier des logs sauvegardés - + Remove empty model slots when deleting models (only applies for radios w/out categories) Supprimer les emplacements vides lors de la suppression de modèles - + Debug Output Logging Log les messages de debug - + <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>Garder un log de tous les messages de débogage générés par les applications Companion/Simulateur. Un développeur OpenTX peut demander ce log afin d'aider à diagnostiquer un problème.</p></body></html> - + Application (Companion/Simulator) Application (Companion/Simulateur) - + <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>Conserver un log de tous les messages générés par le firmware radio lors de l'exécution du Simulateur. C'est la même information visible depuis le Simulateur dans la <span style=" font-style:italic;">Fenêtre de débogage</span>.</p></body></html> - + Radio Firmware (in Simulator) Firmware radio (Simulateur) - + + Prompt for radio profile + Afficher le choix "profil radio" au démarrage + + + Blue Bleu - + Green Vert - + Red Rouge - + Orange Orange - + Yellow Jaune - + Screenshot capture folder Dossier des captures d'écran - + Joystick - + Calibrate Calibrer - + Only capture to clipboard Capturer dans le presse-papiers uniquement - - Remember simulator switch values - Mémoriser les positions des inters du simulateur - - - + My Radio Ma 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>Vous ne pouvez pas changer de type de radio ou modifier les options de compilation tant que les changements ne sont pas sauvegardés. Que souhaitez-vous faire?</b></p> <ul><li><i>Sauvegarder tout</i> - Enregistrez le(s) fichier(s) ouvert(s) avant d'enregistrer les paramètres.<li><li><i>Réinitialiser</i> - Revenir aux précédentes options de type et de compilation de la radio avant d'enregistrer les paramètres</li><li><i>Annuler</i> - Retournez dans la boîte de dialogue de l'éditeur de paramètres.</li></ul> - + Select your snapshot folder Sélectionner le dossier où stocker les captures d'écran - + Note: Nightly builds are not available in this version, Release/RC update channel will be used. Remarque: la version " nightly" n'est pas disponible dans cette version. Le canal de mise à jour "officiel" sera utilisé. - - + + No joysticks found Aucun Joystick trouvé - + EMPTY: No radio settings stored in profile VIDE: Aucune donnée stockée dans le profil - + AVAILABLE: Radio settings of unknown age DISPONIBLE: Paramètres enregistrés à une date inconnue - + AVAILABLE: Radio settings stored %1 DISPONIBLE: Paramètres enregistrés le %1 - + Select your library folder Sélectionner le dossier de bibliothèque - - + + Select your Models and Settings backup folder Sélectionner le dossier dans lequel une sauvegarde des paramètres et modèles sera placée automatiquement lors de chaque opération - + Select a folder for application logs Sélectionner un dossier pour le log des applications - + Select Google Earth executable Sélectionner l'emplacement de l'exécutable Google Earth - + Select the folder replicating your SD structure Sélectionner un dossier contenant une copie des dossiers de la carte SD - + Open Image to load Ouvrir l'image à charger - + Images (%1) Images (%1) @@ -2109,23 +2124,23 @@ Si vous avez un fichier de sauvegarde des paramètres, vous pouvez l'import 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 @@ -2888,19 +2903,19 @@ Blanc signifie "inclure tous".Les métacaractères ?, * et [...] sont - + 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 @@ -2916,6 +2931,7 @@ Blanc signifie "inclure tous".Les métacaractères ?, * et [...] sont + Disable RAS (SWR) Désactiver le RAS (SWR). Utile uniquement pour les X9D+ avec un RAS/SWR non fonctionnel @@ -2940,86 +2956,81 @@ Blanc signifie "inclure tous".Les métacaractères ?, * et [...] sont - + 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 - + FrSky Horus X10 Express / X10S Express - + FrSky Horus X12S - + Use ONLY with first DEV pcb version Exclusivement pour les Horus DEV - - - Enable non certified R9M firmwares - Activer les firmwares R9M non certifiés - @@ -3034,11 +3045,11 @@ Blanc signifie "inclure tous".Les métacaractères ?, * et [...] sont - Radiomaster TX16S + Radiomaster TX16s / TX16s Hall / TX16s Masterfire - + Turnigy 9XR-PRO @@ -3083,17 +3094,17 @@ Blanc signifie "inclure tous".Les métacaractères ?, * et [...] sont 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 @@ -3103,17 +3114,17 @@ Blanc signifie "inclure tous".Les métacaractères ?, * et [...] sont 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 - + 9X with AR9X board 9X avec carte AR9X - + Jumper T12 / T12 Pro @@ -3123,17 +3134,17 @@ Blanc signifie "inclure tous".Les métacaractères ?, * et [...] sont - + 9X with Sky9x board 9X avec carte Sky9x - + 9X with Gruvin9x board 9X avec carte Gruvin9x - + DIY MEGA2560 radio Radio DIY à base de MEGA2560 @@ -3608,6 +3619,16 @@ Vous utilisez actuellement: Switch Interrupteur + + + trim6 + + + + + trim5 + + FlightModeData @@ -3620,52 +3641,52 @@ 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 - + Popup enabled Indication activée @@ -3675,49 +3696,49 @@ Vous utilisez actuellement: 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 - - + + Clear Effacer - + Clear all current Flight Mode properties? Effacer tout les modes de vols ? @@ -3725,17 +3746,17 @@ Vous utilisez actuellement: FlightModesPanel - + Flight Mode %1 Phase de vol %1 - + (%1) - + (default) (par défaut) @@ -4063,7 +4084,7 @@ Communs à tous les modèles d'une même EEPROM. GeneralSettings - + Radio Settings Paramètres de la radio @@ -4408,11 +4429,6 @@ Mode 4: Owner Registration ID Enregistrement ID du propriétaire - - - aaaaaaAA - - R E T A @@ -4730,6 +4746,11 @@ Plage de valeurs: 5v...10v 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 @@ -6073,79 +6094,79 @@ 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 @@ -6162,511 +6183,511 @@ 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? @@ -6679,18 +6700,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? @@ -6699,355 +6720,355 @@ 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 @@ -8170,7 +8191,7 @@ Mixage actif par défaut si non-renseigné. Extended Limits - Débattements étendus + Limites étendues @@ -8977,12 +8998,12 @@ Mixage actif par défaut si non-renseigné. ModuleData - + Positive - + Negative Négative @@ -9604,11 +9625,6 @@ Mixage actif par défaut si non-renseigné. DEFAULT DÉFAUT - - - Custom - proto %1) - Personnaliser - proto %1) - MultirotorPage @@ -9756,6 +9772,19 @@ Mixage actif par défaut si non-renseigné. Fichiers ODF (*.odt);; Fichiers PDF (*.pdf);;Fichiers HTML (*.htm *.html);;Tous les fichiers (*) + + ProfileChooserDialog + + + Select Profile + Choisir Profil + + + + Profile + Profil + + ProgressDialog @@ -10859,7 +10888,12 @@ E secondes - + + ml/minute + + + + TELE @@ -11009,7 +11043,7 @@ E Extended Limits - Débattements étendus + Limites étendues @@ -11830,12 +11864,12 @@ La valeur par défaut est configurée dans le profil radio sélectionné.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) @@ -12538,104 +12572,104 @@ 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 - + --- @@ -12648,274 +12682,284 @@ Trop d'erreurs, abandon. Formulaire - + + TELE## + + + + 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 @@ -12923,25 +12967,70 @@ 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 + + + + Clear All + Effacer Tout + + + + 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? + TelemetrySimulator @@ -14303,120 +14392,4 @@ Cliquer sur Annuler pour interrompre la calibration sans sauvegarder.Calibration incomplète, sauvegarder tout de même ? - - preferencesDialog - - - - ... - - - - - Enable - Actif - - - - Remember simulator switches - Mémoriser les positions des inters du simulateur - - - - Calibrate - Calibrer - - - - - Open Folder - Ouvrir le dossier - - - - Custom TX splash screen - Personnaliser l'écran d'accueil - - - - Simulator capture folder - Dossier des captures d'écran - - - - Use clipboard only - Utiliser le presse-papiers - - - - Simu BackLight - Rétroéclairage simu - - - - Blue - Blu - Bleu - - - - Green - Vert - - - - Red - Rouge - - - - Orange - - - - - Yellow - Jaune - - - - Personal splash library - Librairie d'écran d'accueil personnalisé - - - - Splash library behaviour - Utilisation de la librairie d'écran d'accueil - - - - Include companion splashes - Inclure les écrans d'accueil de Companion - - - - Only user defined splashes - Seulement les écrans d'accueil personnalisé - - - - Joystick - - - - - Open Image - Charger une image - - - - Invert Pixels - Inverser les couleurs - - - - Preferences - Préférences - - diff --git a/companion/src/translations/companion_it.ts b/companion/src/translations/companion_it.ts index cb4847378..587e208b2 100644 --- a/companion/src/translations/companion_it.ts +++ b/companion/src/translations/companion_it.ts @@ -10184,7 +10184,7 @@ We recommend you view the release notes using the button below to learn about an Set Menu Language - Inposta Menu Lingua + Menù Impostazione Lingua diff --git a/companion/targets/windows/companion.nsi.in b/companion/targets/windows/companion.nsi.in index 1a06fde23..9aa19f155 100644 --- a/companion/targets/windows/companion.nsi.in +++ b/companion/targets/windows/companion.nsi.in @@ -6,6 +6,7 @@ ;Include Modern UI !include "MUI2.nsh" + !include "nsDialogs.nsh" !include "@CMAKE_CURRENT_SOURCE_DIR@\..\targets\windows\FileAssociation.nsh" ;-------------------------------- @@ -32,6 +33,10 @@ ;Variables Var StartMenuFolder + Var StartMenuLocationDialog + Var StartMenuLocationRadioCurrent + Var StartMenuLocationRadioAll + Var StartMenuLocationValue ; "current_user" or "all_users" ;-------------------------------- ;Interface Settings @@ -68,9 +73,11 @@ !define MUI_STARTMENUPAGE_REGISTRY_ROOT "HKCU" !define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\OpenTX\Companion @VERSION_FAMILY@" !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder" - !insertmacro MUI_PAGE_STARTMENU Application $StartMenuFolder + ;Start Menu Folder for current user or all users? + Page custom StartMenuLocationCreator StartMenuLocationLeave + !insertmacro MUI_PAGE_INSTFILES # These indented statements modify settings for MUI_PAGE_FINISH @@ -117,6 +124,7 @@ Section "OpenTX Companion @VERSION_FAMILY@" SecDummy ;Registry information for add/remove programs WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenTX Companion @VERSION_FAMILY@" "DisplayName" "OpenTX Companion @VERSION_FAMILY@" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenTX Companion @VERSION_FAMILY@" "DisplayVersion" "@VERSION@" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenTX Companion @VERSION_FAMILY@" "UninstallString" "$\"$INSTDIR\Uninstall.exe$\"" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenTX Companion @VERSION_FAMILY@" "DisplayIcon" "$\"$INSTDIR\companion.exe$\"" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenTX Companion @VERSION_FAMILY@" "Publisher" "OpenTX" @@ -126,10 +134,14 @@ Section "OpenTX Companion @VERSION_FAMILY@" SecDummy !insertmacro MUI_STARTMENU_WRITE_BEGIN Application ;Create shortcuts + ${If} $StartMenuLocationValue == "all_users" + SetShellVarContext all + ${Endif} CreateDirectory "$SMPROGRAMS\$StartMenuFolder" CreateShortCut "$SMPROGRAMS\$StartMenuFolder\Companion @VERSION_FAMILY@.lnk" "$INSTDIR\companion.exe" CreateShortCut "$SMPROGRAMS\$StartMenuFolder\Firmware Simulator @VERSION_FAMILY@.lnk" "$INSTDIR\simulator.exe" CreateShortCut "$SMPROGRAMS\$StartMenuFolder\Uninstall Companion @VERSION_FAMILY@.lnk" "$INSTDIR\Uninstall.exe" + SetShellVarContext current !insertmacro MUI_STARTMENU_WRITE_END @@ -141,6 +153,14 @@ SectionEnd ;Language strings LangString DESC_SecDummy ${LANG_ENGLISH} "Models and settings editor for OpenTX" LangString DESC_SecDummy ${LANG_FRENCH} "Editeur de r�glages et mod�les pour OpenTX" + LangString SML_SubTitle ${LANG_ENGLISH} "Choose a location for the Start Menu shortcuts" + LangString SML_SubTitle ${LANG_FRENCH} "Choisissez un emplacement pour les raccourcis de l'application" + LangString SML_MainLabel ${LANG_ENGLISH} "Create start menu shortcuts for:" + LangString SML_MainLabel ${LANG_FRENCH} "Emplacement pour les raccourcis de l'application:" + LangString SML_RadioCurrent ${LANG_ENGLISH} "Current user only" + LangString SML_RadioCurrent ${LANG_FRENCH} "Utilisateur actuel" + LangString SML_RadioAll ${LANG_ENGLISH} "All users" + LangString SML_RadioAll ${LANG_FRENCH} "Tous les utilisateurs" ;Assign language strings to sections !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN @@ -203,6 +223,13 @@ Section "un.OpenTX Companion @VERSION_FAMILY@" !insertmacro MUI_STARTMENU_GETFOLDER Application $StartMenuFolder + ; Always remove start menu folder for both locations: current user and all users + SetShellVarContext all + Delete "$SMPROGRAMS\$StartMenuFolder\Companion @VERSION_FAMILY@.lnk" + Delete "$SMPROGRAMS\$StartMenuFolder\Firmware Simulator @VERSION_FAMILY@.lnk" + Delete "$SMPROGRAMS\$StartMenuFolder\Uninstall Companion @VERSION_FAMILY@.lnk" + RMDir "$SMPROGRAMS\$StartMenuFolder" + SetShellVarContext current Delete "$SMPROGRAMS\$StartMenuFolder\Companion @VERSION_FAMILY@.lnk" Delete "$SMPROGRAMS\$StartMenuFolder\Firmware Simulator @VERSION_FAMILY@.lnk" Delete "$SMPROGRAMS\$StartMenuFolder\Uninstall Companion @VERSION_FAMILY@.lnk" @@ -218,3 +245,58 @@ SectionEnd Function LaunchLink ExecShell "" "$INSTDIR\companion.exe" FunctionEnd + + +; Custom page with radio buttons, if the start menu entries shall be created +; for the current user or for all users. +Function StartMenuLocationCreator + ; Set default value if not already set. Do this before we might "abort" this page. + ${If} $StartMenuLocationValue == "" + StrCpy $StartMenuLocationValue "current_user" + ${EndIf} + + ; If the folder starts with >, the user has chosen not to create a shortcut (see NSIS/StartMenu.nsh) + StrCpy $R0 $StartMenuFolder 1 + ${If} $R0 == ">" + Abort + ${EndIf} + + !insertmacro MUI_HEADER_TEXT_PAGE $(MUI_TEXT_STARTMENU_TITLE) $(SML_SubTitle) + + nsDialogs::Create 1018 + Pop $StartMenuLocationDialog + + ${If} $StartMenuLocationDialog == error + Abort + ${EndIf} + + ${NSD_CreateLabel} 0u 0u 100% 12u $(SML_MainLabel) + Pop $R0 + + ${NSD_CreateRadioButton} 8u 20u 100% 12u $(SML_RadioCurrent) + Pop $StartMenuLocationRadioCurrent + ${NSD_AddStyle} $StartMenuLocationRadioCurrent ${WS_GROUP} + + ${NSD_CreateRadioButton} 8u 40u 100% 12u $(SML_RadioAll) + Pop $StartMenuLocationRadioAll + + ${If} $StartMenuLocationValue == "all_users" + ${NSD_SetState} $StartMenuLocationRadioAll ${BST_CHECKED} + ${Else} + ${NSD_SetState} $StartMenuLocationRadioCurrent ${BST_CHECKED} + ${EndIf} + + ${NSD_OnBack} StartMenuLocationLeave + + nsDialogs::Show +FunctionEnd + +; Converts the radio button state back into a value for "StartMenuLocationValue" +Function StartMenuLocationLeave + ${NSD_GetState} $StartMenuLocationRadioAll $R0 + ${If} $R0 == ${BST_CHECKED} + StrCpy $StartMenuLocationValue "all_users" + ${Else} + StrCpy $StartMenuLocationValue "current_user" + ${Endif} +FunctionEnd diff --git a/radio/sdcard/horus/SCRIPTS/TOOLS/CROSSFIRE/device.lua b/radio/sdcard/horus/SCRIPTS/TOOLS/CROSSFIRE/device.lua index 106ad939d..7ebc8ec43 100644 --- a/radio/sdcard/horus/SCRIPTS/TOOLS/CROSSFIRE/device.lua +++ b/radio/sdcard/horus/SCRIPTS/TOOLS/CROSSFIRE/device.lua @@ -489,7 +489,7 @@ end local function runPopupPage(event) local result if fieldPopup.status == 3 then - result = popupConfirmation(fieldPopup.info, event) + result = popupConfirmation("Confirmation", fieldPopup.info, event) else result = popupWarning(fieldPopup.info, event) end diff --git a/radio/sdcard/horus/SCRIPTS/TOOLS/MultiChan.txt b/radio/sdcard/horus/SCRIPTS/TOOLS/MultiChan.txt new file mode 100644 index 000000000..bf61d8ca6 --- /dev/null +++ b/radio/sdcard/horus/SCRIPTS/TOOLS/MultiChan.txt @@ -0,0 +1,157 @@ +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 +1,3,Flysky,V912,1,BtmBtn,TopBtn +1,4,Flysky,CX20,0,CH5,CH6,CH7 +28,0,Flysky_AFHDS2A,PWM_IBUS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14 +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 +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 +67,0,FrSkyL,LR12,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12 +67,1,FrSkyL,LR12_6CH,0,CH5,CH6 +15,0,FrSkyX,D16_FCC,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16 +15,1,FrSkyX,D16_8CH_FCC,0,CH5,CH6,CH7,CH8 +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 +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 +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 +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 +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 +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 +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 +18,3,MJXQ,H26D,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate +18,4,MJXQ,E010,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate +18,5,MJXQ,H26WH,1,Flip,Arm,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate +18,6,MJXQ,Phoenix,1,Flip,Arm,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate +17,0,MT99XX,Std,1,Flip,LED,Pict,Video,HLess +17,1,MT99XX,H7,1,Flip,LED,Pict,Video,HLess +17,2,MT99XX,YZ,1,Flip,LED,Pict,Video,HLess +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 +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 +29,1,Q2x2,Q242,1,Flip,LED,Pict,Video,HLess,RTH,XCal,YCal +29,2,Q2x2,Q282,1,Flip,LED,Pict,Video,HLess,RTH,XCal,YCal +31,0,Q303,Q303,1,AltHol,Flip,Pict,Video,HLess,RTH,Gimbal +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 +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 +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 +11,3,SLT,Q200,0,Rates,n-a,CH7,CH8,Mode,VidOn,VidOff,Calib +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 +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 +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 +8,1,YD717,SkyWlkr,1,Flip,Light,Pict,Video,HLess +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 new file mode 100644 index 000000000..42de75e4f --- /dev/null +++ b/radio/sdcard/horus/SCRIPTS/TOOLS/MultiChannelsUpdater.lua @@ -0,0 +1,302 @@ + +local toolName = "TNS|Multi chan namer|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. # +---- # # +---- ######################################################################### + +local protocol_name = "" +local sub_protocol_name = "" +local bind_ch = 0 +local module_conf = {} +local module_pos = "Internal" +local file_ok = 0 +local done = 0 +local protocol = 0 +local sub_protocol = 0 +local f_seek = 0 +local channel_names={} +local num_search = "Searching" + +local function drawScreenTitle(title) + if LCD_W == 480 then + lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR) + lcd.drawText(1, 5, title, MENU_TITLE_COLOR) + else + lcd.drawScreenTitle(title, 0, 0) + end +end + +function bitand(a, b) + local result = 0 + local bitval = 1 + while a > 0 and b > 0 do + if a % 2 == 1 and b % 2 == 1 then -- test the rightmost bits + result = result + bitval -- set the current bit + end + bitval = bitval * 2 -- shift left + a = math.floor(a/2) -- shift right + b = math.floor(b/2) + end + return result +end + +local function Multi_Draw_LCD(event) + local line = 0 + + lcd.clear() + drawScreenTitle("Multi channels namer") + + --Display settings + local lcd_opt = 0 + if LCD_W == 480 then + x_pos = 10 + y_pos = 32 + y_inc = 20 + else + x_pos = 0 + y_pos = 9 + y_inc = 8 + lcd_opt = SMLSIZE + end + + --Multi Module detection + if module_conf["Type"] ~= 6 then + if LCD_W == 480 then + lcd.drawText(10,50,"No Multi module configured...", BLINK) + else + --Draw on LCD_W=128 + lcd.drawText(2,17,"No Multi module configured...",SMLSIZE) + end + return + else + lcd.drawText(x_pos, y_pos+y_inc*line,module_pos .. " Multi detected.", lcd_opt) + line = line + 1 + end + + --Channel order + if (ch_order == -1) then + lcd.drawText(x_pos, y_pos+y_inc*line,"Channels order can't be read from Multi...", lcd_opt) + line = line + 1 + end + + --Can't open file MultiChan.txt + if file_ok == 0 then + lcd.drawText(x_pos, y_pos+y_inc*line,"Can't read MultiChan.txt file...", lcd_opt) + return + end + + if ( protocol_name == "" or sub_protocol_name == "" ) and f_seek ~=-1 then + local f = io.open("/SCRIPTS/TOOLS/MultiChan.txt", "r") + if f == nil then return end + lcd.drawText(x_pos, y_pos+y_inc*line,num_search, lcd_opt) + num_search = num_search .. "." + if #num_search > 15 then + num_search = string.sub(num_search,1,9) + end + local proto = 0 + local sub_proto = 0 + local proto_name = "" + local sub_proto_name = "" + local channels = "" + local nbr_try = 0 + local nbr_car = 0 + repeat + io.seek(f, f_seek) + local data = io.read(f, 100) -- read 100 characters + if #data ==0 then + f_seek = -1 -- end of file + break + end + proto, sub_proto, proto_name, sub_proto_name, bind_ch, channels = string.match(data,'(%d+),(%d),([%w-_ ]+),([%w-_ ]+),(%d)(.+)') + if proto ~= nil and sub_proto ~= nil and protocol_name ~= nil and sub_protocol_name ~= nil and bind_ch ~= nil then + if tonumber(proto) == protocol and tonumber(sub_proto) == sub_protocol then + protocol_name = proto_name + sub_protocol_name = sub_proto_name + bind_ch = tonumber(bind_ch) + if channels ~= nil then + --extract channel names + nbr_car = string.find(channels, "\r") + if nbr_car == nil then nbr_car = string.find(channels, "\n") end + if nbr_car ~= nil then + channels = string.sub(channels,1,nbr_car-1) + end + local i = 5 + for k in string.gmatch(channels, ",([%w-_ ]+)") do + channel_names[i] = k + i = i + 1 + end + end + f_seek = -1 -- protocol found + break + end + end + if f_seek ~= -1 then + nbr_car = string.find(data, "\n") + if nbr_car == nil then nbr_car = string.find(data, "\r") end + if nbr_car == nil then + f_seek = -1 -- end of file + break + end + f_seek = f_seek + nbr_car -- seek to next line + nbr_try = nbr_try + 1 + end + until nbr_try > 20 or f_seek == -1 + io.close(f) + end + + if f_seek ~= -1 then + return -- continue searching... + end + + --Protocol & Sub_protocol + if protocol_name == "" or sub_protocol_name == "" then + lcd.drawText(x_pos, y_pos+y_inc*line,"Unknown protocol "..tostring(protocol).."/"..tostring(sub_protocol).." ...", lcd_opt) + return + elseif LCD_W > 128 then + lcd.drawText(x_pos, y_pos+y_inc*line,"Protocol: " .. protocol_name .. " / SubProtocol: " .. sub_protocol_name, lcd_opt) + line = line + 1 + else + lcd.drawText(x_pos, y_pos+y_inc*line,"Protocol: " .. protocol_name, lcd_opt) + line = line + 1 + lcd.drawText(x_pos, y_pos+y_inc*line,"SubProtocol: " .. sub_protocol_name, lcd_opt) + line = line + 1 + end + + text1="" + text2="" + for i,v in ipairs(channel_names) do + if i<=8 then + if i==1 then + text1 = v + else + text1=text1 .. "," .. v + end + else + if i==9 then + text2 = v + else + text2=text2 .. "," .. v + end + end + end + if LCD_W > 128 then + lcd.drawText(x_pos, y_pos+y_inc*line,"Channels: " .. text1, lcd_opt) + line = line + 1 + if text2 ~= "" then + lcd.drawText(x_pos*9, y_pos+y_inc*line,text2, lcd_opt) + line = line + 1 + end + end + + if event ~= EVT_VIRTUAL_ENTER and done == 0 then + lcd.drawText(x_pos, y_pos+y_inc*line," Save", lcd_opt + INVERS + BLINK) + return + end + + lcd.drawText(x_pos, y_pos+y_inc*line,"Setting channel names.", lcd_opt) + line = line + 1 + local output, nbr + if done == 0 then + for i,v in ipairs(channel_names) do + output = model.getOutput(i-1) + output["name"] = v + model.setOutput(i-1,output) + nbr = i + end + for i = nbr, 15 do + output = model.getOutput(i) + output["name"] = "n-a" + model.setOutput(i,output) + end + if bind_ch == 1 then + output = model.getOutput(15) + output["name"] = "BindCH" + model.setOutput(15,output) + end + done = 1 + end + lcd.drawText(x_pos, y_pos+y_inc*line,"Done!", lcd_opt) + line = line + 1 +end + +-- Init +local function Multi_Init() + module_conf = model.getModule(0) + if module_conf["Type"] ~= 6 then + module_pos = "External" + module_conf = model.getModule(1) + if module_conf["Type"] ~= 6 then + return + end + end + + protocol = module_conf["protocol"] + sub_protocol = module_conf["subProtocol"] + + --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 + 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 + stick_names[4] = "n-a" + elseif protocol == 47 or protocol == 49 or protocol == 58 then -- GD00x, KF606, FX816 + stick_names[1] = "n-a" + stick_names[2] = "n-a" + end + + --Determine fist 4 channels order + local ch_order=module_conf["channelsOrder"] + if (ch_order == -1) then + channel_names[1] = stick_names[defaultChannel(0)+1] + channel_names[2] = stick_names[defaultChannel(1)+1] + channel_names[3] = stick_names[defaultChannel(2)+1] + channel_names[4] = stick_names[defaultChannel(3)+1] + else + channel_names[bitand(ch_order,3)+1] = stick_names[4] + ch_order = math.floor(ch_order/4) + channel_names[bitand(ch_order,3)+1] = stick_names[2] + ch_order = math.floor(ch_order/4) + channel_names[bitand(ch_order,3)+1] = stick_names[3] + ch_order = math.floor(ch_order/4) + channel_names[bitand(ch_order,3)+1] = stick_names[1] + end + --Check MultiChan.txt + local f = io.open("/SCRIPTS/TOOLS/MultiChan.txt", "r") + if f == nil then return end + file_ok = 1 + io.close(f) +end + +-- Main +local function Multi_Run(event) + if event == nil then + error("Cannot be run as a model script!") + return 2 + else + Multi_Draw_LCD(event) + if event == EVT_VIRTUAL_EXIT then + return 2 + end + end + return 0 +end + +return { init=Multi_Init, run=Multi_Run } diff --git a/radio/sdcard/horus/THEMES/Darkblue/tx16s.bmp b/radio/sdcard/horus/THEMES/Darkblue/tx16s.bmp old mode 100755 new mode 100644 index 826fc35f0..bb44eda41 Binary files a/radio/sdcard/horus/THEMES/Darkblue/tx16s.bmp and b/radio/sdcard/horus/THEMES/Darkblue/tx16s.bmp differ diff --git a/radio/sdcard/horus/THEMES/Default/tx16s.bmp b/radio/sdcard/horus/THEMES/Default/tx16s.bmp index 49a08c396..8f6e2872d 100644 Binary files a/radio/sdcard/horus/THEMES/Default/tx16s.bmp and b/radio/sdcard/horus/THEMES/Default/tx16s.bmp differ diff --git a/radio/sdcard/horus/WIDGETS/BattCheck/main.lua b/radio/sdcard/horus/WIDGETS/BattCheck/main.lua index 215d589ac..58790445a 100755 --- a/radio/sdcard/horus/WIDGETS/BattCheck/main.lua +++ b/radio/sdcard/horus/WIDGETS/BattCheck/main.lua @@ -19,15 +19,50 @@ -- Horus Widget to display the levels of lipo battery with per cell indication -- 3djc & Offer Shmuely -- Date: 2020 --- ver: 0.4 +-- ver: 0.5 +local version = "v0.5" local _options = { - { "Sensor", SOURCE, 0 }, -- default to 'Cels' - { "Color", COLOR, WHITE }, - { "Shadow", BOOL, 0 }, - { "LowestCell", BOOL, 1 } -- 0=main voltage display shows all-cell-voltage, 1=main voltage display shows lowest-cell + { "Sensor", SOURCE, 0 }, -- default to 'Cels' + { "Color", COLOR, WHITE }, + { "Shadow", BOOL, 0 }, + { "LowestCell", BOOL, 1 } -- 0=main voltage display shows all-cell-voltage, 1=main voltage display shows lowest-cell } +-- Data gathered from commercial lipo sensors + +local _lipoPercentListSplit = { + { { 3, 0 }, { 3.093, 1 }, { 3.196, 2 }, { 3.301, 3 }, { 3.401, 4 }, { 3.477, 5 }, { 3.544, 6 }, { 3.601, 7 }, { 3.637, 8 }, { 3.664, 9 }, { 3.679, 10 }, { 3.683, 11 }, { 3.689, 12 }, { 3.692, 13 } }, + { { 3.705, 14 }, { 3.71, 15 }, { 3.713, 16 }, { 3.715, 17 }, { 3.72, 18 }, { 3.731, 19 }, { 3.735, 20 }, { 3.744, 21 }, { 3.753, 22 }, { 3.756, 23 }, { 3.758, 24 }, { 3.762, 25 }, { 3.767, 26 } }, + { { 3.774, 27 }, { 3.78, 28 }, { 3.783, 29 }, { 3.786, 30 }, { 3.789, 31 }, { 3.794, 32 }, { 3.797, 33 }, { 3.8, 34 }, { 3.802, 35 }, { 3.805, 36 }, { 3.808, 37 }, { 3.811, 38 }, { 3.815, 39 } }, + { { 3.818, 40 }, { 3.822, 41 }, { 3.825, 42 }, { 3.829, 43 }, { 3.833, 44 }, { 3.836, 45 }, { 3.84, 46 }, { 3.843, 47 }, { 3.847, 48 }, { 3.85, 49 }, { 3.854, 50 }, { 3.857, 51 }, { 3.86, 52 } }, + { { 3.863, 53 }, { 3.866, 54 }, { 3.87, 55 }, { 3.874, 56 }, { 3.879, 57 }, { 3.888, 58 }, { 3.893, 59 }, { 3.897, 60 }, { 3.902, 61 }, { 3.906, 62 }, { 3.911, 63 }, { 3.918, 64 } }, + { { 3.923, 65 }, { 3.928, 66 }, { 3.939, 67 }, { 3.943, 68 }, { 3.949, 69 }, { 3.955, 70 }, { 3.961, 71 }, { 3.968, 72 }, { 3.974, 73 }, { 3.981, 74 }, { 3.987, 75 }, { 3.994, 76 } }, + { { 4.001, 77 }, { 4.007, 78 }, { 4.014, 79 }, { 4.021, 80 }, { 4.029, 81 }, { 4.036, 82 }, { 4.044, 83 }, { 4.052, 84 }, { 4.062, 85 }, { 4.074, 86 }, { 4.085, 87 }, { 4.095, 88 } }, + { { 4.105, 89 }, { 4.111, 90 }, { 4.116, 91 }, { 4.12, 92 }, { 4.125, 93 }, { 4.129, 94 }, { 4.135, 95 }, { 4.145, 96 }, { 4.176, 97 }, { 4.179, 98 }, { 4.193, 99 }, { 4.2, 100 } }, +} + +local function periodicInit(t, durationMili) + t.startTime = getTime(); + t.durationMili = durationMili; +end +local function periodicReset(t) + t.startTime = getTime(); +end +local function periodicHasPassed(t) + local elapsed = getTime() - t.startTime; + local elapsedMili = elapsed * 10; + if (elapsedMili < t.durationMili) then + return false; + end + return true; +end +local function periodicGetElapsedTime(t) + local elapsed = getTime() - t.startTime; + local elapsedMili = elapsed * 10; + return elapsedMili; +end + -- This function is run once at the creation of the widget local function create(zone, options) local wgt = { @@ -40,8 +75,8 @@ local function create(zone, options) telemResetLowestMinRSSI = 101, no_telem_blink = 0, isDataAvailable = 0, - cellDataLive = {0,0,0,0,0,0}, - cellDataHistoryLowest = {5,5,5,5,5,5}, + cellDataLive = { 0, 0, 0, 0, 0, 0 }, + cellDataHistoryLowest = { 5, 5, 5, 5, 5, 5 }, cellDataHistoryCellLowest = 5, cellMax = 0, cellMin = 0, @@ -50,7 +85,10 @@ local function create(zone, options) cellCount = 0, cellSum = 0, mainValue = 0, - secondaryValue = 0 + secondaryValue = 0, + periodic1 = { startTime = getTime(), durationMili = 1000 }, + periodicProfiler = { startTime = getTime(), durationMili = 5000 }, + profTimes = {}, } -- use default if user did not set, So widget is operational on "select widget" @@ -65,7 +103,9 @@ end -- This function allow updates when you change widgets settings local function update(wgt, options) - if (wgt == nil) then return end + if (wgt == nil) then + return + end wgt.options = options @@ -83,8 +123,8 @@ end local function onTelemetryResetEvent(wgt) wgt.telemResetCount = wgt.telemResetCount + 1 - wgt.cellDataLive = {0,0,0,0,0,0} - wgt.cellDataHistoryLowest = {5,5,5,5,5,5} + wgt.cellDataLive = { 0, 0, 0, 0, 0, 0 } + wgt.cellDataHistoryLowest = { 5, 5, 5, 5, 5, 5 } wgt.cellDataHistoryCellLowest = 5 end @@ -99,9 +139,12 @@ end local function detectResetEvent(wgt) local currMinRSSI = getValue('RSSI-') - if (currMinRSSI == nil) then return + if (currMinRSSI == nil) then + return + end + if (currMinRSSI == wgt.telemResetLowestMinRSSI) then + return end - if (currMinRSSI == wgt.telemResetLowestMinRSSI) then return end if (currMinRSSI < wgt.telemResetLowestMinRSSI) then -- rssi just got lower, record it @@ -118,28 +161,28 @@ local function detectResetEvent(wgt) end - --- This function return the percentage remaining in a single Lipo cel -local function getCellPercent(cellValue) +--- since running on long array found to be very intensive to hrous cpu, we are splitting the list to small lists +local function getCellPercent(wgt, cellValue) if cellValue == nil then return 0 end + local result = 0; - -- in case somehow voltage is higher, don't return nil - if (cellValue > 4.2) then - return 100 - end - - -- Data gathered from commercial lipo sensors - local myArrayPercentList = { {3,0},{3.093,1},{3.196,2},{3.301,3},{3.401,4},{3.477,5},{3.544,6},{3.601,7},{3.637,8},{3.664,9},{3.679,10},{3.683,11},{3.689,12},{3.692,13},{3.705,14},{3.71,15},{3.713,16},{3.715,17},{3.72,18},{3.731,19},{3.735,20},{3.744,21},{3.753,22},{3.756,23},{3.758,24},{3.762,25},{3.767,26},{3.774,27},{3.78,28},{3.783,29},{3.786,30},{3.789,31},{3.794,32},{3.797,33},{3.8,34},{3.802,35},{3.805,36},{3.808,37},{3.811,38},{3.815,39},{3.818,40},{3.822,41},{3.825,42},{3.829,43},{3.833,44},{3.836,45},{3.84,46},{3.843,47},{3.847,48},{3.85,49},{3.854,50},{3.857,51},{3.86,52},{3.863,53},{3.866,54},{3.87,55},{3.874,56},{3.879,57},{3.888,58},{3.893,59},{3.897,60},{3.902,61},{3.906,62},{3.911,63},{3.918,64},{3.923,65},{3.928,66},{3.939,67},{3.943,68},{3.949,69},{3.955,70},{3.961,71},{3.968,72},{3.974,73},{3.981,74},{3.987,75},{3.994,76},{4.001,77},{4.007,78},{4.014,79},{4.021,80},{4.029,81},{4.036,82},{4.044,83},{4.052,84},{4.062,85},{4.074,86},{4.085,87},{4.095,88},{4.105,89},{4.111,90},{4.116,91},{4.12,92},{4.125,93},{4.129,94},{4.135,95},{4.145,96},{4.176,97},{4.179,98},{4.193,99},{4.2,100} } - - for i, v in ipairs(myArrayPercentList) do - if v[1] >= cellValue then - result = v[2] - break + for i1, v1 in ipairs(_lipoPercentListSplit) do + --is the cellVal < last-value-on-sub-list? (first-val:v1[1], last-val:v1[#v1]) + if (cellValue <= v1[#v1][1]) then + -- cellVal is in this sub-list, find the exact value + for i2, v2 in ipairs(v1) do + if v2[1] >= cellValue then + result = v2[2] + return result + end + end end end - return result + -- in case somehow voltage is too high (>4.2), don't return nil + return 100 end --- This function returns a table with cels values @@ -152,20 +195,13 @@ local function calculateBatteryData(wgt) return end - -- this is necessary for simu where cell-count can change - if #wgt.cellDataHistoryLowest ~= #newCellData then - wgt.cellDataHistoryLowest = {} - for k, v in pairs(newCellData) do - wgt.cellDataHistoryLowest[k] = 5 -- invalid reading, set high value so the min() will update it soon - end - end - local cellMax = 0 local cellMin = 5 local cellSum = 0 for k, v in pairs(newCellData) do -- stores the lowest cell values in historical table - if v > 1 and v < wgt.cellDataHistoryLowest[k] then -- min 1v to consider a valid reading + if v > 1 and v < wgt.cellDataHistoryLowest[k] then + -- min 1v to consider a valid reading wgt.cellDataHistoryLowest[k] = v --- calc history lowest of all cells @@ -181,7 +217,8 @@ local function calculateBatteryData(wgt) end --- calc lowest of all cells - if v < cellMin and v > 1 then -- min 1v to consider a valid reading + if v < cellMin and v > 1 then + -- min 1v to consider a valid reading cellMin = v end --- sum of all cells @@ -197,7 +234,6 @@ local function calculateBatteryData(wgt) --- average of all cells wgt.cellAvg = wgt.cellSum / wgt.cellCount - wgt.cellPercent = getCellPercent(wgt.cellMin) wgt.cellDataLive = newCellData @@ -219,13 +255,19 @@ local function calculateBatteryData(wgt) wgt.secondaryValue = "-2" end - wgt.isDataAvailable = true + -- calculate intensive CPU data + if (periodicHasPassed(wgt.periodic1) or wgt.cellPercent == 0) then + + --wgt.cellPercent = getCellPercent(wgt, wgt.cellMin) -- use batt percentage by lowest cell voltage + wgt.cellPercent = getCellPercent(wgt, wgt.cellAvg) -- use batt percentage by average cell voltage + + periodicReset(wgt.periodic1) + end end - -- color for battery -- This function returns green at 100%, red bellow 30% and graduate in between local function getPercentColor(percent) @@ -242,34 +284,46 @@ end -- This function returns green at gvalue, red at rvalue and graduate in between local function getRangeColor(value, green_value, red_value) local range = math.abs(green_value - red_value) - if range==0 then return lcd.RGB(0, 0xdf, 0) end + if range == 0 then + return lcd.RGB(0, 0xdf, 0) + end + if value == nil then + return lcd.RGB(0, 0xdf, 0) + end if green_value > red_value then - if value > green_value then return lcd.RGB(0, 0xdf, 0) end - if value < red_value then return lcd.RGB(0xdf, 0, 0) end + if value > green_value then + return lcd.RGB(0, 0xdf, 0) + end + if value < red_value then + return lcd.RGB(0xdf, 0, 0) + end g = math.floor(0xdf * (value - red_value) / range) r = 0xdf - g return lcd.RGB(r, g, 0) else - if value > green_value then return lcd.RGB(0, 0xdf, 0) end - if value < red_value then return lcd.RGB(0xdf, 0, 0) end + if value > green_value then + return lcd.RGB(0, 0xdf, 0) + end + if value < red_value then + return lcd.RGB(0xdf, 0, 0) + end r = math.floor(0xdf * (value - green_value) / range) g = 0xdf - r return lcd.RGB(r, g, 0) end end - --- Zone size: 70x39 1/8th top bar local function refreshZoneTiny(wgt) local myString = string.format("%2.1fV", wgt.mainValue) - lcd.drawText(wgt.zone.x + wgt.zone.w -25, wgt.zone.y + 5, wgt.cellPercent .. "%", RIGHT + SMLSIZE + CUSTOM_COLOR + wgt.no_telem_blink) - lcd.drawText(wgt.zone.x + wgt.zone.w -25, wgt.zone.y + 20, myString, RIGHT + SMLSIZE + CUSTOM_COLOR + wgt.no_telem_blink) + lcd.drawText(wgt.zone.x + wgt.zone.w - 25, wgt.zone.y + 5, wgt.cellPercent .. "%", RIGHT + SMLSIZE + CUSTOM_COLOR + wgt.no_telem_blink) + lcd.drawText(wgt.zone.x + wgt.zone.w - 25, wgt.zone.y + 20, myString, RIGHT + SMLSIZE + CUSTOM_COLOR + wgt.no_telem_blink) -- draw batt lcd.drawRectangle(wgt.zone.x + 50, wgt.zone.y + 9, 16, 25, CUSTOM_COLOR, 2) - lcd.drawFilledRectangle(wgt.zone.x +50 + 4, wgt.zone.y + 7, 6, 3, CUSTOM_COLOR) + lcd.drawFilledRectangle(wgt.zone.x + 50 + 4, wgt.zone.y + 7, 6, 3, CUSTOM_COLOR) local rect_h = math.floor(25 * wgt.cellPercent / 100) - lcd.drawFilledRectangle(wgt.zone.x +50, wgt.zone.y + 9 + 25 - rect_h, 16, rect_h, CUSTOM_COLOR + wgt.no_telem_blink) + lcd.drawFilledRectangle(wgt.zone.x + 50, wgt.zone.y + 9 + 25 - rect_h, 16, rect_h, CUSTOM_COLOR + wgt.no_telem_blink) end --- Zone size: 160x32 1/8th @@ -307,13 +361,13 @@ local function refreshZoneMedium(wgt) end -- draw values - lcd.drawText(wgt.zone.x, wgt.zone.y + 35, string.format("%2.1fV", wgt.mainValue), DBLSIZE + CUSTOM_COLOR + wgt.shadowed + wgt.no_telem_blink) + lcd.drawText(wgt.zone.x + wgt.zone.w, wgt.zone.y, string.format("%2.1fV", wgt.mainValue), DBLSIZE + CUSTOM_COLOR + RIGHT + wgt.shadowed + wgt.no_telem_blink) -- more info if 1/4 is high enough (without trim & slider) if wgt.zone.h > 80 then - lcd.drawText(wgt.zone.x , wgt.zone.y + 70, string.format("%2.2fV" , wgt.secondaryValue), SMLSIZE + CUSTOM_COLOR + wgt.no_telem_blink) - lcd.drawText(wgt.zone.x + 50, wgt.zone.y + 70, string.format("dV %2.2fV", wgt.cellMax - wgt.cellMin), SMLSIZE + CUSTOM_COLOR + wgt.no_telem_blink) - lcd.drawText(wgt.zone.x , wgt.zone.y + 84, string.format("Min %2.2fV", wgt.cellDataHistoryCellLowest), SMLSIZE + CUSTOM_COLOR + wgt.no_telem_blink) + --lcd.drawText(wgt.zone.x + 50 , wgt.zone.y + 70, string.format("%2.2fV" , wgt.secondaryValue), SMLSIZE + CUSTOM_COLOR + wgt.no_telem_blink) + lcd.drawText(wgt.zone.x, wgt.zone.y + 70, string.format("dV %2.2fV", wgt.cellMax - wgt.cellMin), SMLSIZE + CUSTOM_COLOR + wgt.no_telem_blink) + lcd.drawText(wgt.zone.x, wgt.zone.y + 84, string.format("Min %2.2fV", wgt.cellDataHistoryCellLowest), SMLSIZE + CUSTOM_COLOR + wgt.no_telem_blink) end -- fill batt @@ -321,28 +375,21 @@ local function refreshZoneMedium(wgt) lcd.drawGauge(wgt.zone.x + myBatt.x, wgt.zone.y + myBatt.y, myBatt.w, myBatt.h, wgt.cellPercent, 100, CUSTOM_COLOR) -- draw cells - local cellH = wgt.zone.h / wgt.cellCount - if cellH > 20 then cellH =20 end + local cellH = 19 local cellX = 118 - local cellW = 58 + local cellW = wgt.zone.w / 3 + + local pos = { { x = 0, y = 38 }, { x = cellW, y = 38 }, { x = 2 * cellW, y = 38 }, { x = 0, y = 57 }, { x = cellW, y = 57 }, { x = 2 * cellW, y = 57 } } for i = 1, wgt.cellCount, 1 do - local cellY = wgt.zone.y + (i-1)* (cellH -1) + local cellY = wgt.zone.y + (i - 1) * (cellH - 1) -- fill current cell - lcd.setColor(CUSTOM_COLOR, getRangeColor(wgt.cellDataLive[i], wgt.cellMax, wgt.cellMax - 0.2)) --lcd.drawFilledRectangle(wgt.zone.x + cellX , cellY, 58, cellH, CUSTOM_COLOR) - local percentCurrent = getCellPercent(wgt.cellDataLive[i]) - local percentMin = getCellPercent(wgt.cellDataHistoryLowest[i]) - - lcd.drawFilledRectangle(wgt.zone.x + cellX , cellY, cellW * percentCurrent / 100, cellH, CUSTOM_COLOR) - - -- fill min - lcd.setColor(CUSTOM_COLOR, getRangeColor(wgt.cellDataHistoryLowest[i], wgt.cellMax, wgt.cellMax - 0.2)) - lcd.drawFilledRectangle(wgt.zone.x + cellX + ((percentCurrent - percentMin) / 100) , cellY, cellW - (cellW * (percentCurrent - percentMin) / 100), cellH, CUSTOM_COLOR) - + lcd.setColor(CUSTOM_COLOR, getRangeColor(wgt.cellDataLive[i], wgt.cellMax, wgt.cellMax - 0.2)) + lcd.drawFilledRectangle(wgt.zone.x + pos[i].x, wgt.zone.y + pos[i].y, cellW - 1, 20, CUSTOM_COLOR) lcd.setColor(CUSTOM_COLOR, WHITE) - lcd.drawText (wgt.zone.x + cellX + 10, cellY, string.format("%.2f", wgt.cellDataLive[i]), SMLSIZE + CUSTOM_COLOR + wgt.shadowed + wgt.no_telem_blink) - lcd.drawRectangle (wgt.zone.x + cellX , cellY, 59, cellH, CUSTOM_COLOR , 1) + lcd.drawText(wgt.zone.x + pos[i].x + 10, wgt.zone.y + pos[i].y, string.format("%.2f", wgt.cellDataLive[i]), CUSTOM_COLOR + wgt.shadowed) + lcd.drawRectangle(wgt.zone.x + pos[i].x, wgt.zone.y + pos[i].y, cellW, 20, CUSTOM_COLOR, 1) end -- draws bat @@ -447,7 +494,9 @@ end -- This function allow recording of lowest cells when widget is in background local function background(wgt) - if (wgt == nil) then return end + if (wgt == nil) then + return + end detectResetEvent(wgt) @@ -456,11 +505,21 @@ local function background(wgt) end local function refresh(wgt) - - if (wgt == nil) then return end - if (wgt.options == nil) then return end - if (wgt.zone == nil) then return end - if (wgt.options.LowestCell == nil) then return end + if (wgt == nil) then + return + end + if type(wgt) ~= "table" then + return + end + if (wgt.options == nil) then + return + end + if (wgt.zone == nil) then + return + end + if (wgt.options.LowestCell == nil) then + return + end if wgt.options.Shadow == 1 then wgt.shadowed = SHADOWED @@ -478,14 +537,17 @@ local function refresh(wgt) wgt.no_telem_blink = INVERS + BLINK end - - if wgt.zone.w > 380 and wgt.zone.h > 165 then refreshZoneXLarge(wgt) - elseif wgt.zone.w > 180 and wgt.zone.h > 145 then refreshZoneLarge(wgt) - elseif wgt.zone.w > 170 and wgt.zone.h > 65 then refreshZoneMedium(wgt) - elseif wgt.zone.w > 150 and wgt.zone.h > 28 then refreshZoneSmall(wgt) - elseif wgt.zone.w > 65 and wgt.zone.h > 35 then refreshZoneTiny(wgt) + if wgt.zone.w > 380 and wgt.zone.h > 165 then + refreshZoneXLarge(wgt) + elseif wgt.zone.w > 180 and wgt.zone.h > 145 then + refreshZoneLarge(wgt) + elseif wgt.zone.w > 170 and wgt.zone.h > 65 then + refreshZoneMedium(wgt) + elseif wgt.zone.w > 150 and wgt.zone.h > 28 then + refreshZoneSmall(wgt) + elseif wgt.zone.w > 65 and wgt.zone.h > 35 then + refreshZoneTiny(wgt) end - end -return { name="BattCheck", options=_options, create=create, update=update, background=background, refresh=refresh } +return { name = "BattCheck", options = _options, create = create, update = update, background = background, refresh = refresh } \ No newline at end of file diff --git a/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/MultiChan.txt b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/MultiChan.txt new file mode 100644 index 000000000..bf61d8ca6 --- /dev/null +++ b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/MultiChan.txt @@ -0,0 +1,157 @@ +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 +1,3,Flysky,V912,1,BtmBtn,TopBtn +1,4,Flysky,CX20,0,CH5,CH6,CH7 +28,0,Flysky_AFHDS2A,PWM_IBUS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14 +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 +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 +67,0,FrSkyL,LR12,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12 +67,1,FrSkyL,LR12_6CH,0,CH5,CH6 +15,0,FrSkyX,D16_FCC,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16 +15,1,FrSkyX,D16_8CH_FCC,0,CH5,CH6,CH7,CH8 +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 +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 +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 +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 +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 +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 +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 +18,3,MJXQ,H26D,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate +18,4,MJXQ,E010,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate +18,5,MJXQ,H26WH,1,Flip,Arm,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate +18,6,MJXQ,Phoenix,1,Flip,Arm,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate +17,0,MT99XX,Std,1,Flip,LED,Pict,Video,HLess +17,1,MT99XX,H7,1,Flip,LED,Pict,Video,HLess +17,2,MT99XX,YZ,1,Flip,LED,Pict,Video,HLess +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 +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 +29,1,Q2x2,Q242,1,Flip,LED,Pict,Video,HLess,RTH,XCal,YCal +29,2,Q2x2,Q282,1,Flip,LED,Pict,Video,HLess,RTH,XCal,YCal +31,0,Q303,Q303,1,AltHol,Flip,Pict,Video,HLess,RTH,Gimbal +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 +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 +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 +11,3,SLT,Q200,0,Rates,n-a,CH7,CH8,Mode,VidOn,VidOff,Calib +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 +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 +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 +8,1,YD717,SkyWlkr,1,Flip,Light,Pict,Video,HLess +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 new file mode 100644 index 000000000..42de75e4f --- /dev/null +++ b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/MultiChannelsUpdater.lua @@ -0,0 +1,302 @@ + +local toolName = "TNS|Multi chan namer|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. # +---- # # +---- ######################################################################### + +local protocol_name = "" +local sub_protocol_name = "" +local bind_ch = 0 +local module_conf = {} +local module_pos = "Internal" +local file_ok = 0 +local done = 0 +local protocol = 0 +local sub_protocol = 0 +local f_seek = 0 +local channel_names={} +local num_search = "Searching" + +local function drawScreenTitle(title) + if LCD_W == 480 then + lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR) + lcd.drawText(1, 5, title, MENU_TITLE_COLOR) + else + lcd.drawScreenTitle(title, 0, 0) + end +end + +function bitand(a, b) + local result = 0 + local bitval = 1 + while a > 0 and b > 0 do + if a % 2 == 1 and b % 2 == 1 then -- test the rightmost bits + result = result + bitval -- set the current bit + end + bitval = bitval * 2 -- shift left + a = math.floor(a/2) -- shift right + b = math.floor(b/2) + end + return result +end + +local function Multi_Draw_LCD(event) + local line = 0 + + lcd.clear() + drawScreenTitle("Multi channels namer") + + --Display settings + local lcd_opt = 0 + if LCD_W == 480 then + x_pos = 10 + y_pos = 32 + y_inc = 20 + else + x_pos = 0 + y_pos = 9 + y_inc = 8 + lcd_opt = SMLSIZE + end + + --Multi Module detection + if module_conf["Type"] ~= 6 then + if LCD_W == 480 then + lcd.drawText(10,50,"No Multi module configured...", BLINK) + else + --Draw on LCD_W=128 + lcd.drawText(2,17,"No Multi module configured...",SMLSIZE) + end + return + else + lcd.drawText(x_pos, y_pos+y_inc*line,module_pos .. " Multi detected.", lcd_opt) + line = line + 1 + end + + --Channel order + if (ch_order == -1) then + lcd.drawText(x_pos, y_pos+y_inc*line,"Channels order can't be read from Multi...", lcd_opt) + line = line + 1 + end + + --Can't open file MultiChan.txt + if file_ok == 0 then + lcd.drawText(x_pos, y_pos+y_inc*line,"Can't read MultiChan.txt file...", lcd_opt) + return + end + + if ( protocol_name == "" or sub_protocol_name == "" ) and f_seek ~=-1 then + local f = io.open("/SCRIPTS/TOOLS/MultiChan.txt", "r") + if f == nil then return end + lcd.drawText(x_pos, y_pos+y_inc*line,num_search, lcd_opt) + num_search = num_search .. "." + if #num_search > 15 then + num_search = string.sub(num_search,1,9) + end + local proto = 0 + local sub_proto = 0 + local proto_name = "" + local sub_proto_name = "" + local channels = "" + local nbr_try = 0 + local nbr_car = 0 + repeat + io.seek(f, f_seek) + local data = io.read(f, 100) -- read 100 characters + if #data ==0 then + f_seek = -1 -- end of file + break + end + proto, sub_proto, proto_name, sub_proto_name, bind_ch, channels = string.match(data,'(%d+),(%d),([%w-_ ]+),([%w-_ ]+),(%d)(.+)') + if proto ~= nil and sub_proto ~= nil and protocol_name ~= nil and sub_protocol_name ~= nil and bind_ch ~= nil then + if tonumber(proto) == protocol and tonumber(sub_proto) == sub_protocol then + protocol_name = proto_name + sub_protocol_name = sub_proto_name + bind_ch = tonumber(bind_ch) + if channels ~= nil then + --extract channel names + nbr_car = string.find(channels, "\r") + if nbr_car == nil then nbr_car = string.find(channels, "\n") end + if nbr_car ~= nil then + channels = string.sub(channels,1,nbr_car-1) + end + local i = 5 + for k in string.gmatch(channels, ",([%w-_ ]+)") do + channel_names[i] = k + i = i + 1 + end + end + f_seek = -1 -- protocol found + break + end + end + if f_seek ~= -1 then + nbr_car = string.find(data, "\n") + if nbr_car == nil then nbr_car = string.find(data, "\r") end + if nbr_car == nil then + f_seek = -1 -- end of file + break + end + f_seek = f_seek + nbr_car -- seek to next line + nbr_try = nbr_try + 1 + end + until nbr_try > 20 or f_seek == -1 + io.close(f) + end + + if f_seek ~= -1 then + return -- continue searching... + end + + --Protocol & Sub_protocol + if protocol_name == "" or sub_protocol_name == "" then + lcd.drawText(x_pos, y_pos+y_inc*line,"Unknown protocol "..tostring(protocol).."/"..tostring(sub_protocol).." ...", lcd_opt) + return + elseif LCD_W > 128 then + lcd.drawText(x_pos, y_pos+y_inc*line,"Protocol: " .. protocol_name .. " / SubProtocol: " .. sub_protocol_name, lcd_opt) + line = line + 1 + else + lcd.drawText(x_pos, y_pos+y_inc*line,"Protocol: " .. protocol_name, lcd_opt) + line = line + 1 + lcd.drawText(x_pos, y_pos+y_inc*line,"SubProtocol: " .. sub_protocol_name, lcd_opt) + line = line + 1 + end + + text1="" + text2="" + for i,v in ipairs(channel_names) do + if i<=8 then + if i==1 then + text1 = v + else + text1=text1 .. "," .. v + end + else + if i==9 then + text2 = v + else + text2=text2 .. "," .. v + end + end + end + if LCD_W > 128 then + lcd.drawText(x_pos, y_pos+y_inc*line,"Channels: " .. text1, lcd_opt) + line = line + 1 + if text2 ~= "" then + lcd.drawText(x_pos*9, y_pos+y_inc*line,text2, lcd_opt) + line = line + 1 + end + end + + if event ~= EVT_VIRTUAL_ENTER and done == 0 then + lcd.drawText(x_pos, y_pos+y_inc*line," Save", lcd_opt + INVERS + BLINK) + return + end + + lcd.drawText(x_pos, y_pos+y_inc*line,"Setting channel names.", lcd_opt) + line = line + 1 + local output, nbr + if done == 0 then + for i,v in ipairs(channel_names) do + output = model.getOutput(i-1) + output["name"] = v + model.setOutput(i-1,output) + nbr = i + end + for i = nbr, 15 do + output = model.getOutput(i) + output["name"] = "n-a" + model.setOutput(i,output) + end + if bind_ch == 1 then + output = model.getOutput(15) + output["name"] = "BindCH" + model.setOutput(15,output) + end + done = 1 + end + lcd.drawText(x_pos, y_pos+y_inc*line,"Done!", lcd_opt) + line = line + 1 +end + +-- Init +local function Multi_Init() + module_conf = model.getModule(0) + if module_conf["Type"] ~= 6 then + module_pos = "External" + module_conf = model.getModule(1) + if module_conf["Type"] ~= 6 then + return + end + end + + protocol = module_conf["protocol"] + sub_protocol = module_conf["subProtocol"] + + --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 + 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 + stick_names[4] = "n-a" + elseif protocol == 47 or protocol == 49 or protocol == 58 then -- GD00x, KF606, FX816 + stick_names[1] = "n-a" + stick_names[2] = "n-a" + end + + --Determine fist 4 channels order + local ch_order=module_conf["channelsOrder"] + if (ch_order == -1) then + channel_names[1] = stick_names[defaultChannel(0)+1] + channel_names[2] = stick_names[defaultChannel(1)+1] + channel_names[3] = stick_names[defaultChannel(2)+1] + channel_names[4] = stick_names[defaultChannel(3)+1] + else + channel_names[bitand(ch_order,3)+1] = stick_names[4] + ch_order = math.floor(ch_order/4) + channel_names[bitand(ch_order,3)+1] = stick_names[2] + ch_order = math.floor(ch_order/4) + channel_names[bitand(ch_order,3)+1] = stick_names[3] + ch_order = math.floor(ch_order/4) + channel_names[bitand(ch_order,3)+1] = stick_names[1] + end + --Check MultiChan.txt + local f = io.open("/SCRIPTS/TOOLS/MultiChan.txt", "r") + if f == nil then return end + file_ok = 1 + io.close(f) +end + +-- Main +local function Multi_Run(event) + if event == nil then + error("Cannot be run as a model script!") + return 2 + else + Multi_Draw_LCD(event) + if event == EVT_VIRTUAL_EXIT then + return 2 + end + end + return 0 +end + +return { init=Multi_Init, run=Multi_Run } diff --git a/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/MultiChan.txt b/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/MultiChan.txt new file mode 100644 index 000000000..bf61d8ca6 --- /dev/null +++ b/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/MultiChan.txt @@ -0,0 +1,157 @@ +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 +1,3,Flysky,V912,1,BtmBtn,TopBtn +1,4,Flysky,CX20,0,CH5,CH6,CH7 +28,0,Flysky_AFHDS2A,PWM_IBUS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14 +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 +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 +67,0,FrSkyL,LR12,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12 +67,1,FrSkyL,LR12_6CH,0,CH5,CH6 +15,0,FrSkyX,D16_FCC,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16 +15,1,FrSkyX,D16_8CH_FCC,0,CH5,CH6,CH7,CH8 +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 +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 +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 +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 +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 +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 +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 +18,3,MJXQ,H26D,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate +18,4,MJXQ,E010,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate +18,5,MJXQ,H26WH,1,Flip,Arm,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate +18,6,MJXQ,Phoenix,1,Flip,Arm,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate +17,0,MT99XX,Std,1,Flip,LED,Pict,Video,HLess +17,1,MT99XX,H7,1,Flip,LED,Pict,Video,HLess +17,2,MT99XX,YZ,1,Flip,LED,Pict,Video,HLess +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 +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 +29,1,Q2x2,Q242,1,Flip,LED,Pict,Video,HLess,RTH,XCal,YCal +29,2,Q2x2,Q282,1,Flip,LED,Pict,Video,HLess,RTH,XCal,YCal +31,0,Q303,Q303,1,AltHol,Flip,Pict,Video,HLess,RTH,Gimbal +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 +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 +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 +11,3,SLT,Q200,0,Rates,n-a,CH7,CH8,Mode,VidOn,VidOff,Calib +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 +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 +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 +8,1,YD717,SkyWlkr,1,Flip,Light,Pict,Video,HLess +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 new file mode 100644 index 000000000..42de75e4f --- /dev/null +++ b/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/MultiChannelsUpdater.lua @@ -0,0 +1,302 @@ + +local toolName = "TNS|Multi chan namer|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. # +---- # # +---- ######################################################################### + +local protocol_name = "" +local sub_protocol_name = "" +local bind_ch = 0 +local module_conf = {} +local module_pos = "Internal" +local file_ok = 0 +local done = 0 +local protocol = 0 +local sub_protocol = 0 +local f_seek = 0 +local channel_names={} +local num_search = "Searching" + +local function drawScreenTitle(title) + if LCD_W == 480 then + lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR) + lcd.drawText(1, 5, title, MENU_TITLE_COLOR) + else + lcd.drawScreenTitle(title, 0, 0) + end +end + +function bitand(a, b) + local result = 0 + local bitval = 1 + while a > 0 and b > 0 do + if a % 2 == 1 and b % 2 == 1 then -- test the rightmost bits + result = result + bitval -- set the current bit + end + bitval = bitval * 2 -- shift left + a = math.floor(a/2) -- shift right + b = math.floor(b/2) + end + return result +end + +local function Multi_Draw_LCD(event) + local line = 0 + + lcd.clear() + drawScreenTitle("Multi channels namer") + + --Display settings + local lcd_opt = 0 + if LCD_W == 480 then + x_pos = 10 + y_pos = 32 + y_inc = 20 + else + x_pos = 0 + y_pos = 9 + y_inc = 8 + lcd_opt = SMLSIZE + end + + --Multi Module detection + if module_conf["Type"] ~= 6 then + if LCD_W == 480 then + lcd.drawText(10,50,"No Multi module configured...", BLINK) + else + --Draw on LCD_W=128 + lcd.drawText(2,17,"No Multi module configured...",SMLSIZE) + end + return + else + lcd.drawText(x_pos, y_pos+y_inc*line,module_pos .. " Multi detected.", lcd_opt) + line = line + 1 + end + + --Channel order + if (ch_order == -1) then + lcd.drawText(x_pos, y_pos+y_inc*line,"Channels order can't be read from Multi...", lcd_opt) + line = line + 1 + end + + --Can't open file MultiChan.txt + if file_ok == 0 then + lcd.drawText(x_pos, y_pos+y_inc*line,"Can't read MultiChan.txt file...", lcd_opt) + return + end + + if ( protocol_name == "" or sub_protocol_name == "" ) and f_seek ~=-1 then + local f = io.open("/SCRIPTS/TOOLS/MultiChan.txt", "r") + if f == nil then return end + lcd.drawText(x_pos, y_pos+y_inc*line,num_search, lcd_opt) + num_search = num_search .. "." + if #num_search > 15 then + num_search = string.sub(num_search,1,9) + end + local proto = 0 + local sub_proto = 0 + local proto_name = "" + local sub_proto_name = "" + local channels = "" + local nbr_try = 0 + local nbr_car = 0 + repeat + io.seek(f, f_seek) + local data = io.read(f, 100) -- read 100 characters + if #data ==0 then + f_seek = -1 -- end of file + break + end + proto, sub_proto, proto_name, sub_proto_name, bind_ch, channels = string.match(data,'(%d+),(%d),([%w-_ ]+),([%w-_ ]+),(%d)(.+)') + if proto ~= nil and sub_proto ~= nil and protocol_name ~= nil and sub_protocol_name ~= nil and bind_ch ~= nil then + if tonumber(proto) == protocol and tonumber(sub_proto) == sub_protocol then + protocol_name = proto_name + sub_protocol_name = sub_proto_name + bind_ch = tonumber(bind_ch) + if channels ~= nil then + --extract channel names + nbr_car = string.find(channels, "\r") + if nbr_car == nil then nbr_car = string.find(channels, "\n") end + if nbr_car ~= nil then + channels = string.sub(channels,1,nbr_car-1) + end + local i = 5 + for k in string.gmatch(channels, ",([%w-_ ]+)") do + channel_names[i] = k + i = i + 1 + end + end + f_seek = -1 -- protocol found + break + end + end + if f_seek ~= -1 then + nbr_car = string.find(data, "\n") + if nbr_car == nil then nbr_car = string.find(data, "\r") end + if nbr_car == nil then + f_seek = -1 -- end of file + break + end + f_seek = f_seek + nbr_car -- seek to next line + nbr_try = nbr_try + 1 + end + until nbr_try > 20 or f_seek == -1 + io.close(f) + end + + if f_seek ~= -1 then + return -- continue searching... + end + + --Protocol & Sub_protocol + if protocol_name == "" or sub_protocol_name == "" then + lcd.drawText(x_pos, y_pos+y_inc*line,"Unknown protocol "..tostring(protocol).."/"..tostring(sub_protocol).." ...", lcd_opt) + return + elseif LCD_W > 128 then + lcd.drawText(x_pos, y_pos+y_inc*line,"Protocol: " .. protocol_name .. " / SubProtocol: " .. sub_protocol_name, lcd_opt) + line = line + 1 + else + lcd.drawText(x_pos, y_pos+y_inc*line,"Protocol: " .. protocol_name, lcd_opt) + line = line + 1 + lcd.drawText(x_pos, y_pos+y_inc*line,"SubProtocol: " .. sub_protocol_name, lcd_opt) + line = line + 1 + end + + text1="" + text2="" + for i,v in ipairs(channel_names) do + if i<=8 then + if i==1 then + text1 = v + else + text1=text1 .. "," .. v + end + else + if i==9 then + text2 = v + else + text2=text2 .. "," .. v + end + end + end + if LCD_W > 128 then + lcd.drawText(x_pos, y_pos+y_inc*line,"Channels: " .. text1, lcd_opt) + line = line + 1 + if text2 ~= "" then + lcd.drawText(x_pos*9, y_pos+y_inc*line,text2, lcd_opt) + line = line + 1 + end + end + + if event ~= EVT_VIRTUAL_ENTER and done == 0 then + lcd.drawText(x_pos, y_pos+y_inc*line," Save", lcd_opt + INVERS + BLINK) + return + end + + lcd.drawText(x_pos, y_pos+y_inc*line,"Setting channel names.", lcd_opt) + line = line + 1 + local output, nbr + if done == 0 then + for i,v in ipairs(channel_names) do + output = model.getOutput(i-1) + output["name"] = v + model.setOutput(i-1,output) + nbr = i + end + for i = nbr, 15 do + output = model.getOutput(i) + output["name"] = "n-a" + model.setOutput(i,output) + end + if bind_ch == 1 then + output = model.getOutput(15) + output["name"] = "BindCH" + model.setOutput(15,output) + end + done = 1 + end + lcd.drawText(x_pos, y_pos+y_inc*line,"Done!", lcd_opt) + line = line + 1 +end + +-- Init +local function Multi_Init() + module_conf = model.getModule(0) + if module_conf["Type"] ~= 6 then + module_pos = "External" + module_conf = model.getModule(1) + if module_conf["Type"] ~= 6 then + return + end + end + + protocol = module_conf["protocol"] + sub_protocol = module_conf["subProtocol"] + + --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 + 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 + stick_names[4] = "n-a" + elseif protocol == 47 or protocol == 49 or protocol == 58 then -- GD00x, KF606, FX816 + stick_names[1] = "n-a" + stick_names[2] = "n-a" + end + + --Determine fist 4 channels order + local ch_order=module_conf["channelsOrder"] + if (ch_order == -1) then + channel_names[1] = stick_names[defaultChannel(0)+1] + channel_names[2] = stick_names[defaultChannel(1)+1] + channel_names[3] = stick_names[defaultChannel(2)+1] + channel_names[4] = stick_names[defaultChannel(3)+1] + else + channel_names[bitand(ch_order,3)+1] = stick_names[4] + ch_order = math.floor(ch_order/4) + channel_names[bitand(ch_order,3)+1] = stick_names[2] + ch_order = math.floor(ch_order/4) + channel_names[bitand(ch_order,3)+1] = stick_names[3] + ch_order = math.floor(ch_order/4) + channel_names[bitand(ch_order,3)+1] = stick_names[1] + end + --Check MultiChan.txt + local f = io.open("/SCRIPTS/TOOLS/MultiChan.txt", "r") + if f == nil then return end + file_ok = 1 + io.close(f) +end + +-- Main +local function Multi_Run(event) + if event == nil then + error("Cannot be run as a model script!") + return 2 + else + Multi_Draw_LCD(event) + if event == EVT_VIRTUAL_EXIT then + return 2 + end + end + return 0 +end + +return { init=Multi_Init, run=Multi_Run } diff --git a/radio/src/CMakeLists.txt b/radio/src/CMakeLists.txt index 7376e96ad..972a805a1 100644 --- a/radio/src/CMakeLists.txt +++ b/radio/src/CMakeLists.txt @@ -381,9 +381,12 @@ endif() add_definitions(-DPOPUP_LEVEL=${POPUP_LEVEL}) -if(BOOTLOADER) - add_definitions(-DBOOTLOADER) -endif(BOOTLOADER) +if(INTERNAL_MODULE_MULTI) + set(DEFAULT_TEMPLATE_SETUP 21 CACHE STRING "") +else() + set(DEFAULT_TEMPLATE_SETUP 0 CACHE STRING "") +endif() +add_definitions(-DDEFAULT_TEMPLATE_SETUP=${DEFAULT_TEMPLATE_SETUP}) set(SRC ${SRC} @@ -444,7 +447,6 @@ endif() set(SRC ${SRC} ${FIRMWARE_SRC}) - ##### firmware target ##### option(FIRMWARE_TARGET "Configure Firmware target (can be turned of for compiling Companion only)" ON) diff --git a/radio/src/bitmaps/480x272/mask_txbat.png b/radio/src/bitmaps/480x272/mask_txbat.png index fd5939190..001d2751c 100644 Binary files a/radio/src/bitmaps/480x272/mask_txbat.png and b/radio/src/bitmaps/480x272/mask_txbat.png differ diff --git a/radio/src/bitmaps/480x272/mask_txbat_charging.png b/radio/src/bitmaps/480x272/mask_txbat_charging.png old mode 100755 new mode 100644 index 99a895151..fa8ab8154 Binary files a/radio/src/bitmaps/480x272/mask_txbat_charging.png and b/radio/src/bitmaps/480x272/mask_txbat_charging.png differ diff --git a/radio/src/bluetooth.cpp b/radio/src/bluetooth.cpp index b2c02f7d4..d9d24dff9 100644 --- a/radio/src/bluetooth.cpp +++ b/radio/src/bluetooth.cpp @@ -315,7 +315,7 @@ void Bluetooth::wakeup(void) uint8_t len = ZLEN(g_eeGeneral.bluetoothName); if (len > 0) { for (int i = 0; i < len; i++) { - *cur++ = char2lower(zchar2char(g_eeGeneral.bluetoothName[i])); + *cur++ = char2lower(g_eeGeneral.bluetoothName[i]); } *cur = '\0'; } @@ -418,7 +418,7 @@ void Bluetooth::wakeup() uint8_t len = ZLEN(g_eeGeneral.bluetoothName); if (len > 0) { for (int i = 0; i < len; i++) { - *cur++ = char2lower(zchar2char(g_eeGeneral.bluetoothName[i])); + *cur++ = char2lower(g_eeGeneral.bluetoothName[i]); } *cur = '\0'; } diff --git a/radio/src/buzzer.h b/radio/src/buzzer.h index aa13746f8..f0c545d5e 100644 --- a/radio/src/buzzer.h +++ b/radio/src/buzzer.h @@ -22,8 +22,6 @@ #define _BUZZER_H_ #if defined(BUZZER) -extern uint8_t g_beepCnt; -extern uint8_t beepAgain; extern uint8_t beepAgainOrig; extern uint8_t beepOn; extern bool warble; diff --git a/radio/src/curves.cpp b/radio/src/curves.cpp index 81b1fd987..a60c3a3a6 100644 --- a/radio/src/curves.cpp +++ b/radio/src/curves.cpp @@ -20,7 +20,6 @@ #include "opentx.h" -uint8_t s_curveChan; int8_t * curveEnd[MAX_CURVES]; void loadCurves() @@ -120,7 +119,7 @@ bool isCurveUsed(uint8_t index) } #define CUSTOM_POINT_X(points, count, idx) ((idx)==0 ? -100 : (((idx)==(count)-1) ? 100 : points[(count)+(idx)-1])) -int32_t compute_tangent(CurveHeader * crv, int8_t * points, int i) +int32_t compute_tangent(CurveHeader * crv, const int8_t * points, int i) { int32_t m=0; uint8_t num_points = crv->points + 5; @@ -240,7 +239,7 @@ int intpol(int x, uint8_t idx) // -100, -75, -50, -25, 0 ,25 ,50, 75, 100 int8_t * points = curveAddress(idx); uint8_t count = crv.points+5; bool custom = (crv.type == CURVE_TYPE_CUSTOM); - int16_t erg = 0; + int16_t erg; x += RESXu; @@ -339,11 +338,6 @@ int applyCustomCurve(int x, uint8_t idx) return intpol(x, idx); } -point_t getPoint(uint8_t index) -{ - return getPoint(s_curveChan, index); -} - point_t getPoint(uint8_t curveIndex, uint8_t index) { point_t result = {0, 0}; @@ -363,7 +357,14 @@ point_t getPoint(uint8_t curveIndex, uint8_t index) return result; } +#if !defined(COLORLCD) +point_t getPoint(uint8_t index) +{ + return getPoint(s_currIdxSubMenu, index); +} + int applyCurrentCurve(int x) { - return applyCustomCurve(x, s_curveChan); + return applyCustomCurve(x, s_currIdxSubMenu); } +#endif diff --git a/radio/src/dataconstants.h b/radio/src/dataconstants.h index d34be3eed..e584e226e 100644 --- a/radio/src/dataconstants.h +++ b/radio/src/dataconstants.h @@ -208,6 +208,16 @@ enum TrainerMode { }; #endif +#if defined(RADIO_FAMILY_T16) || (defined(RADIO_T12) && defined(INTERNAL_MODULE_MULTI)) || defined(ALLOW_TRAINER_MULTI) + #define TRAINER_MODE_MAX() TRAINER_MODE_MULTI +#elif defined(BLUETOOTH) + #define TRAINER_MODE_MAX() TRAINER_MODE_SLAVE_BLUETOOTH +#elif defined(PCBX7) || defined(PCBXLITE) + #define TRAINER_MODE_MAX() TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE +#else + #define TRAINER_MODE_MAX() HAS_WIRELESS_TRAINER_HARDWARE() ? TRAINER_MODE_MASTER_BATTERY_COMPARTMENT : TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE +#endif + #if defined(HARDWARE_INTERNAL_MODULE) #define IS_INTERNAL_MODULE_ENABLED() (g_model.moduleData[INTERNAL_MODULE].type != MODULE_TYPE_NONE) #else diff --git a/radio/src/datastructs.h b/radio/src/datastructs.h index 85abade3a..671b4797f 100644 --- a/radio/src/datastructs.h +++ b/radio/src/datastructs.h @@ -26,6 +26,7 @@ #include "dataconstants.h" #include "definitions.h" #include "opentx_types.h" +#include "globals.h" #if defined(PCBTARANIS) #define N_TARANIS_FIELD(x) @@ -331,10 +332,10 @@ PACK(struct TelemetrySensor { NOBACKUP(uint16_t persistentValue); } NAME(id1) FUNC(select_id1); union { - PACK(struct { + NOBACKUP(PACK(struct { uint8_t physID:5; uint8_t rxIndex:3; // 1 bit for module index, 2 bits for receiver index - }) frskyInstance; + }) frskyInstance); uint8_t instance; NOBACKUP(uint8_t formula); } NAME(id2) FUNC(select_id2); @@ -513,8 +514,6 @@ PACK(struct ModuleData { * Model structure */ -typedef uint16_t BeepANACenter; - #if LEN_BITMAP_NAME > 0 #define MODEL_HEADER_BITMAP_FIELD NOBACKUP(char bitmap[LEN_BITMAP_NAME]); #else @@ -697,7 +696,8 @@ PACK(struct TrainerData { #if defined(PCBHORUS) || defined(PCBNV14) #define EXTRA_GENERAL_FIELDS \ - NOBACKUP(uint8_t auxSerialMode); \ + NOBACKUP(uint8_t auxSerialMode:4); \ + NOBACKUP(uint8_t aux2SerialMode:4); \ swconfig_t switchConfig ARRAY(2,struct_switchConfig,nullptr); \ uint16_t potsConfig ARRAY(2,struct_potConfig,nullptr); /* two bits per pot */ \ uint8_t slidersConfig ARRAY(1,struct_sliderConfig,nullptr); /* 1 bit per slider */ \ diff --git a/radio/src/debug.h b/radio/src/debug.h index f5faa7933..04c54c335 100644 --- a/radio/src/debug.h +++ b/radio/src/debug.h @@ -37,6 +37,7 @@ extern volatile uint32_t g_tmr10ms; uint8_t auxSerialTracesEnabled(); +uint8_t aux2SerialTracesEnabled(); #if defined(SIMU) typedef void (*traceCallbackFunc)(const char * text); diff --git a/radio/src/fonts/CMakeLists.txt b/radio/src/fonts/CMakeLists.txt index 5d7e54740..819d9eb0b 100644 --- a/radio/src/fonts/CMakeLists.txt +++ b/radio/src/fonts/CMakeLists.txt @@ -19,10 +19,10 @@ add_truetype_font_target(9 9 ${subset} none) add_truetype_font_target(13 13 ${subset} none) add_truetype_font_target(15 15 ${subset} none) add_truetype_font_target(16 16 ${subset} none) -add_truetype_font_target(16en 16 en none) +add_truetype_font_target(16en 16 en none) add_truetype_font_target(bold16 16 ${subset} bold) add_truetype_font_target(17 17 ${subset} none) -add_truetype_font_target(17en 17 en none) +add_truetype_font_target(17en 17 en none) add_truetype_font_target(bold17 17 ${subset} bold) add_truetype_font_target(24 24 ${subset} none) add_truetype_font_target(32 32 ${subset} bold) diff --git a/radio/src/fonts/sqt5/font_es_04x06.png b/radio/src/fonts/sqt5/font_es_04x06.png index 23425282a..64c5040a8 100644 Binary files a/radio/src/fonts/sqt5/font_es_04x06.png and b/radio/src/fonts/sqt5/font_es_04x06.png differ diff --git a/radio/src/fonts/sqt5/font_es_05x07.png b/radio/src/fonts/sqt5/font_es_05x07.png index d23e8b850..55ec15e4f 100644 Binary files a/radio/src/fonts/sqt5/font_es_05x07.png and b/radio/src/fonts/sqt5/font_es_05x07.png differ diff --git a/radio/src/fonts/sqt5/font_es_08x10.png b/radio/src/fonts/sqt5/font_es_08x10.png index 6f520ee2a..c2c9b9465 100644 Binary files a/radio/src/fonts/sqt5/font_es_08x10.png and b/radio/src/fonts/sqt5/font_es_08x10.png differ diff --git a/radio/src/fonts/sqt5/font_es_10x14.png b/radio/src/fonts/sqt5/font_es_10x14.png index d66da4460..bfaa3b87e 100644 Binary files a/radio/src/fonts/sqt5/font_es_10x14.png and b/radio/src/fonts/sqt5/font_es_10x14.png differ diff --git a/radio/src/fonts/std/font_es_04x06.png b/radio/src/fonts/std/font_es_04x06.png index 876bc5b7a..b3cff8c78 100644 Binary files a/radio/src/fonts/std/font_es_04x06.png and b/radio/src/fonts/std/font_es_04x06.png differ diff --git a/radio/src/fonts/std/font_es_05x07.png b/radio/src/fonts/std/font_es_05x07.png index 50a64fe6c..066e7cab5 100644 Binary files a/radio/src/fonts/std/font_es_05x07.png and b/radio/src/fonts/std/font_es_05x07.png differ diff --git a/radio/src/fonts/std/font_es_08x10.png b/radio/src/fonts/std/font_es_08x10.png index d88578f1f..78a166085 100644 Binary files a/radio/src/fonts/std/font_es_08x10.png and b/radio/src/fonts/std/font_es_08x10.png differ diff --git a/radio/src/fonts/std/font_es_10x14.png b/radio/src/fonts/std/font_es_10x14.png index 72383b448..05411cc13 100644 Binary files a/radio/src/fonts/std/font_es_10x14.png and b/radio/src/fonts/std/font_es_10x14.png differ diff --git a/radio/src/globals.h b/radio/src/globals.h new file mode 100644 index 000000000..cf67dbc4a --- /dev/null +++ b/radio/src/globals.h @@ -0,0 +1,97 @@ +/* + * 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 _GLOBALS_H_ +#define _GLOBALS_H_ + +#include "definitions.h" +#include "dataconstants.h" + +PACK(struct GlobalData { + uint8_t unexpectedShutdown:1; + uint8_t externalAntennaEnabled:1; + uint8_t authenticationCount:2; + uint8_t upgradeModulePopup:1; + uint8_t internalModuleVersionChecked:1; + uint8_t spare:2; +}); + +extern GlobalData globalData; + +extern uint16_t sessionTimer; +extern uint16_t s_timeCumThr; +extern uint16_t s_timeCum16ThrP; + +#if defined(OVERRIDE_CHANNEL_FUNCTION) +#define OVERRIDE_CHANNEL_UNDEFINED -4096 +extern safetych_t safetyCh[MAX_OUTPUT_CHANNELS]; +#endif + +extern uint8_t trimsCheckTimer; +extern uint8_t trimsDisplayTimer; +extern uint8_t trimsDisplayMask; +extern uint16_t maxMixerDuration; + +extern uint8_t requiredSpeakerVolume; + +enum MainRequest { + REQUEST_SCREENSHOT, + REQUEST_FLIGHT_RESET, +}; + +extern uint8_t mainRequestFlags; + +#define DELAY_POS_MARGIN 3 +typedef int16_t delayval_t; +PACK(struct SwOn { + uint16_t delay:14; // max = 2550 + uint8_t activeMix:1; + uint8_t activeExpo:1; + int16_t now; // timer trigger source -> off, abs, stk, stk%, sw/!sw, !m_sw/!m_sw + int16_t prev; +}); + +extern SwOn swOn[MAX_MIXERS]; +extern int32_t act[MAX_MIXERS]; + +// static variables used in evalFlightModeMixes - moved here so they don't interfere with the stack +// It's also easier to initialize them here. +extern int8_t virtualInputsTrims[MAX_INPUTS]; + +extern int16_t anas [MAX_INPUTS]; +extern int16_t trims[NUM_TRIMS]; +extern int32_t chans[MAX_OUTPUT_CHANNELS]; +extern int16_t ex_chans[MAX_OUTPUT_CHANNELS]; // Outputs (before LIMITS) of the last perMain +extern int16_t channelOutputs[MAX_OUTPUT_CHANNELS]; + +typedef uint16_t BeepANACenter; +extern BeepANACenter bpanaCenter; + +extern uint8_t s_mixer_first_run_done; + +extern int16_t calibratedAnalogs[NUM_CALIBRATED_ANALOGS]; + +extern uint8_t g_beepCnt; +extern uint8_t beepAgain; +extern uint16_t lightOffCounter; +extern uint8_t flashCounter; +extern uint8_t mixWarning; + +#endif diff --git a/radio/src/gui/128x64/gui.h b/radio/src/gui/128x64/gui.h index bde61cd9f..e7367524f 100644 --- a/radio/src/gui/128x64/gui.h +++ b/radio/src/gui/128x64/gui.h @@ -40,6 +40,7 @@ #define drawFieldLabel(x, y, str) lcdDrawTextAlignedLeft(y, str) #define NUM_BODY_LINES (LCD_LINES-1) +#define TEXT_VIEWER_LINES NUM_BODY_LINES #define MENU_HEADER_HEIGHT FH #define CURVE_SIDE_WIDTH (LCD_H/2) @@ -213,7 +214,7 @@ extern uint8_t s_copyMode; extern int8_t s_copySrcRow; extern int8_t s_copyTgtOfs; extern uint8_t s_currIdx; -extern uint8_t s_curveChan; +extern uint8_t s_currIdxSubMenu; extern uint8_t s_copySrcIdx; extern uint8_t s_copySrcCh; extern int8_t s_currCh; diff --git a/radio/src/gui/128x64/lcd.cpp b/radio/src/gui/128x64/lcd.cpp index 4414cbc1e..d3e8d5e47 100644 --- a/radio/src/gui/128x64/lcd.cpp +++ b/radio/src/gui/128x64/lcd.cpp @@ -18,6 +18,7 @@ * GNU General Public License for more details. */ +#include #include "opentx.h" #include "gui/common/stdlcd/fonts.h" @@ -213,7 +214,7 @@ uint8_t getCharWidth(char c, LcdFlags flags) } #endif -void lcdDrawChar(coord_t x, coord_t y, const unsigned char c, LcdFlags flags) +void lcdDrawChar(coord_t x, coord_t y, char c, LcdFlags flags) { const unsigned char * q; @@ -281,7 +282,7 @@ void lcdDrawChar(coord_t x, coord_t y, const unsigned char c, LcdFlags flags) } } -void lcdDrawChar(coord_t x, coord_t y, const unsigned char c) +void lcdDrawChar(coord_t x, coord_t y, char c) { lcdDrawChar(x, y, c, 0); } @@ -441,12 +442,12 @@ void lcdDraw8bitsNumber(coord_t x, coord_t y, int8_t val) lcdDrawNumber(x, y, val); } -void lcdDrawNumber(coord_t x, coord_t y, int val, LcdFlags flags) +void lcdDrawNumber(coord_t x, coord_t y, int32_t val, LcdFlags flags) { lcdDrawNumber(x, y, val, flags, 0); } -void lcdDrawNumber(coord_t x, coord_t y, int val, LcdFlags flags, uint8_t len) +void lcdDrawNumber(coord_t x, coord_t y, int32_t val, LcdFlags flags, uint8_t len) { char str[16+1]; char *s = str+16; @@ -454,7 +455,19 @@ void lcdDrawNumber(coord_t x, coord_t y, int val, LcdFlags flags, uint8_t len) int idx = 0; int mode = MODE(flags); bool neg = false; + + if (val == INT_MAX) { + flags &= ~(LEADING0 | PREC1 | PREC2); + lcdDrawText(x, y, "INT_MAX", flags); + return; + } + if (val < 0) { + if (val == INT_MIN) { + flags &= ~(LEADING0 | PREC1 | PREC2); + lcdDrawText(x, y, "INT_MIN", flags); + return; + } val = -val; neg = true; } diff --git a/radio/src/gui/128x64/lcd.h b/radio/src/gui/128x64/lcd.h index d069490a1..d1a3383a2 100644 --- a/radio/src/gui/128x64/lcd.h +++ b/radio/src/gui/128x64/lcd.h @@ -98,8 +98,8 @@ extern coord_t lcdNextPos; extern volatile uint32_t lcdInputs ; #endif -void lcdDrawChar(coord_t x, coord_t y, const unsigned char c); -void lcdDrawChar(coord_t x, coord_t y, const unsigned char c, LcdFlags flags); +void lcdDrawChar(coord_t x, coord_t y, char c); +void lcdDrawChar(coord_t x, coord_t y, char c, LcdFlags flags); void lcdDrawCenteredText(coord_t y, const char * s, LcdFlags flags = 0); void lcdDrawText(coord_t x, coord_t y, const char * s, LcdFlags flags); void lcdDrawTextAtIndex(coord_t x, coord_t y, const char * s, uint8_t idx, LcdFlags flags); @@ -112,8 +112,8 @@ void drawTimerWithMode(coord_t x, coord_t y, uint8_t index, LcdFlags att); void lcdDrawHexNumber(coord_t x, coord_t y, uint32_t val, LcdFlags mode=0); void lcdDrawHexChar(coord_t x, coord_t y, uint8_t val, LcdFlags flags=0); -void lcdDrawNumber(coord_t x, coord_t y, int val, LcdFlags mode, uint8_t len); -void lcdDrawNumber(coord_t x, coord_t y, int val, LcdFlags mode=0); +void lcdDrawNumber(coord_t x, coord_t y, int32_t val, LcdFlags mode, uint8_t len); +void lcdDrawNumber(coord_t x, coord_t y, int32_t val, LcdFlags mode=0); void lcdDraw8bitsNumber(coord_t x, coord_t y, int8_t val); void drawModelName(coord_t x, coord_t y, char * name, uint8_t id, LcdFlags att); diff --git a/radio/src/gui/128x64/menu_model.cpp b/radio/src/gui/128x64/menu_model.cpp index 4a450d143..b6f5b3bb3 100644 --- a/radio/src/gui/128x64/menu_model.cpp +++ b/radio/src/gui/128x64/menu_model.cpp @@ -45,3 +45,4 @@ void editSingleName(coord_t x, coord_t y, const char * label, char * name, uint8 } uint8_t s_currIdx; +uint8_t s_currIdxSubMenu; diff --git a/radio/src/gui/128x64/model_curve_edit.cpp b/radio/src/gui/128x64/model_curve_edit.cpp index b225283d4..bc7d67b95 100644 --- a/radio/src/gui/128x64/model_curve_edit.cpp +++ b/radio/src/gui/128x64/model_curve_edit.cpp @@ -50,8 +50,8 @@ void runPopupCurvePreset(event_t event) if (warningResult) { warningResult = 0; - CurveHeader & crv = g_model.curves[s_curveChan]; - int8_t * points = curveAddress(s_curveChan); + CurveHeader & crv = g_model.curves[s_currIdxSubMenu]; + int8_t * points = curveAddress(s_currIdxSubMenu); int k = 25 * reusableBuffer.curveEdit.preset; int dx = 2000 / (5+crv.points-1); for (uint8_t i=0; i<5+crv.points; i++) { @@ -71,14 +71,14 @@ void onCurveOneMenu(const char * result) POPUP_INPUT(STR_PRESET, runPopupCurvePreset); } else if (result == STR_MIRROR) { - CurveHeader & crv = g_model.curves[s_curveChan]; - int8_t * points = curveAddress(s_curveChan); + CurveHeader & crv = g_model.curves[s_currIdxSubMenu]; + int8_t * points = curveAddress(s_currIdxSubMenu); for (int i=0; i<5+crv.points; i++) points[i] = -points[i]; } else if (result == STR_CLEAR) { - CurveHeader & crv = g_model.curves[s_curveChan]; - int8_t * points = curveAddress(s_curveChan); + CurveHeader & crv = g_model.curves[s_currIdxSubMenu]; + int8_t * points = curveAddress(s_currIdxSubMenu); for (int i=0; i<5+crv.points; i++) points[i] = 0; if (crv.type == CURVE_TYPE_CUSTOM) { @@ -89,10 +89,10 @@ void onCurveOneMenu(const char * result) void menuModelCurveOne(event_t event) { - CurveHeader & crv = g_model.curves[s_curveChan]; - int8_t * points = curveAddress(s_curveChan); + CurveHeader & crv = g_model.curves[s_currIdxSubMenu]; + int8_t * points = curveAddress(s_currIdxSubMenu); - drawStringWithIndex(PSIZE(TR_MENUCURVES)*FW+FW, 0, STR_CV, s_curveChan+1); + drawStringWithIndex(PSIZE(TR_MENUCURVES)*FW+FW, 0, STR_CV, s_currIdxSubMenu+1); SIMPLE_SUBMENU(STR_MENUCURVES, 4 + 5+crv.points + (crv.type==CURVE_TYPE_CUSTOM ? 5+crv.points-2 : 0)); @@ -108,9 +108,9 @@ void menuModelCurveOne(event_t event) uint8_t newType = checkIncDecModelZero(event, crv.type, CURVE_TYPE_LAST); if (newType != crv.type) { for (int i = 1; i < 4 + crv.points; i++) { - points[i] = calcRESXto100(applyCustomCurve(calc100toRESX(getCurveX(5 + crv.points, i)), s_curveChan)); + points[i] = calcRESXto100(applyCustomCurve(calc100toRESX(getCurveX(5 + crv.points, i)), s_currIdxSubMenu)); } - if (moveCurve(s_curveChan, checkIncDec_Ret > 0 ? 3 + crv.points : -3 - crv.points)) { + if (moveCurve(s_currIdxSubMenu, checkIncDec_Ret > 0 ? 3 + crv.points : -3 - crv.points)) { if (newType == CURVE_TYPE_CUSTOM) { resetCustomCurveX(points, 5 + crv.points); } @@ -131,8 +131,8 @@ void menuModelCurveOne(event_t event) newPoints[0] = points[0]; newPoints[4 + count] = points[4 + crv.points]; for (int i = 1; i < 4 + count; i++) - newPoints[i] = calcRESXto100(applyCustomCurve(calc100toRESX(getCurveX(5 + count, i)), s_curveChan)); - if (moveCurve(s_curveChan, checkIncDec_Ret * (crv.type == CURVE_TYPE_CUSTOM ? 2 : 1))) { + newPoints[i] = calcRESXto100(applyCustomCurve(calc100toRESX(getCurveX(5 + count, i)), s_currIdxSubMenu)); + if (moveCurve(s_currIdxSubMenu, checkIncDec_Ret * (crv.type == CURVE_TYPE_CUSTOM ? 2 : 1))) { for (int i = 0; i < 5 + count; i++) { points[i] = newPoints[i]; if (crv.type == CURVE_TYPE_CUSTOM && i != 0 && i != 4 + count) diff --git a/radio/src/gui/128x64/model_flightmodes.cpp b/radio/src/gui/128x64/model_flightmodes.cpp index ff469dca2..0002bf23b 100644 --- a/radio/src/gui/128x64/model_flightmodes.cpp +++ b/radio/src/gui/128x64/model_flightmodes.cpp @@ -87,7 +87,8 @@ void menuModelFlightModeOne(event_t event) int8_t editMode = s_editMode; #if defined(GVARS) - if (s_currIdx == 0 && sub>=ITEM_MODEL_FLIGHT_MODE_SWITCH) sub += VERTICAL_SHIFT; + if (s_currIdx == 0 && sub>=ITEM_MODEL_FLIGHT_MODE_SWITCH) + sub += VERTICAL_SHIFT; for (uint8_t k=0; k0 && posHorz==0) { - s_currIdx = sub - ITEM_MODEL_FLIGHT_MODE_GV1; + s_currIdxSubMenu = sub - ITEM_MODEL_FLIGHT_MODE_GV1; editMode = 0; pushMenu(menuModelGVarOne); } diff --git a/radio/src/gui/128x64/model_gvars.cpp b/radio/src/gui/128x64/model_gvars.cpp index 0631b3a20..d0e651fd2 100644 --- a/radio/src/gui/128x64/model_gvars.cpp +++ b/radio/src/gui/128x64/model_gvars.cpp @@ -64,10 +64,10 @@ enum GVarFields { void menuModelGVarOne(event_t event) { - GVarData * gvar = &g_model.gvars[s_currIdx]; + GVarData * gvar = &g_model.gvars[s_currIdxSubMenu]; - drawStringWithIndex(PSIZE(TR_GVARS)*FW+FW, 0, STR_GV, s_currIdx+1, 0); - drawGVarValue(32*FW, 0, s_currIdx, getGVarValue(s_currIdx, getFlightMode())); + drawStringWithIndex(PSIZE(TR_GVARS)*FW+FW, 0, STR_GV, s_currIdxSubMenu+1, 0); + drawGVarValue(32*FW, 0, s_currIdxSubMenu, getGVarValue(s_currIdxSubMenu, getFlightMode())); lcdDrawFilledRect(0, 0, LCD_W, FH, SOLID); SIMPLE_SUBMENU(STR_GVARS, GVAR_FIELD_LAST); @@ -92,13 +92,13 @@ void menuModelGVarOne(event_t event) case GVAR_FIELD_MIN: lcdDrawText(0, y, STR_MIN); - drawGVarValue(GVAR_2ND_COLUMN, y, s_currIdx, GVAR_MIN+gvar->min, LEFT|attr); + drawGVarValue(GVAR_2ND_COLUMN, y, s_currIdxSubMenu, GVAR_MIN+gvar->min, LEFT|attr); if (attr) gvar->min = checkIncDec(event, GVAR_MIN+gvar->min, GVAR_MIN, GVAR_MAX-gvar->max, EE_MODEL) - GVAR_MIN; break; case GVAR_FIELD_MAX: lcdDrawText(0, y, STR_MAX); - drawGVarValue(GVAR_2ND_COLUMN, y, s_currIdx, GVAR_MAX-gvar->max, LEFT|attr); + drawGVarValue(GVAR_2ND_COLUMN, y, s_currIdxSubMenu, GVAR_MAX-gvar->max, LEFT|attr); if (attr) gvar->max = GVAR_MAX - checkIncDec(event, GVAR_MAX-gvar->max, GVAR_MIN+gvar->min, GVAR_MAX, EE_MODEL); break; @@ -108,7 +108,7 @@ void menuModelGVarOne(event_t event) default: drawStringWithIndex(0, y, STR_FM, k-GVAR_FIELD_FM0); - editGVarValue(GVAR_2ND_COLUMN, y, event, s_currIdx, k-GVAR_FIELD_FM0, LEFT|attr); + editGVarValue(GVAR_2ND_COLUMN, y, event, s_currIdxSubMenu, k-GVAR_FIELD_FM0, LEFT|attr); break; } } diff --git a/radio/src/gui/128x64/model_inputs_mixes.cpp b/radio/src/gui/128x64/model_inputs_mixes.cpp index 2d791fa04..93342bf24 100644 --- a/radio/src/gui/128x64/model_inputs_mixes.cpp +++ b/radio/src/gui/128x64/model_inputs_mixes.cpp @@ -271,7 +271,7 @@ void menuModelExpoOne(event_t event) 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_curveChan = ed->curveParam - CURVE_BASE; + s_currIdxSubMenu = ed->curveParam - CURVE_BASE; pushMenu(menuModelCurveOne); } } @@ -442,7 +442,7 @@ void menuModelMixOne(event_t event) drawCurveName(COLUMN_X+MIXES_2ND_COLUMN, y, curveParam, attr); if (attr) { if (event==EVT_KEY_LONG(KEY_ENTER) && (curveParam<0 || curveParam>=CURVE_BASE)){ - s_curveChan = (curveParam<0 ? -curveParam-1 : curveParam-CURVE_BASE); + s_currIdxSubMenu = (curveParam<0 ? -curveParam-1 : curveParam-CURVE_BASE); pushMenu(menuModelCurveOne); } else { diff --git a/radio/src/gui/128x64/model_mix_edit.cpp b/radio/src/gui/128x64/model_mix_edit.cpp index 7f4b859e8..d21e76e6f 100644 --- a/radio/src/gui/128x64/model_mix_edit.cpp +++ b/radio/src/gui/128x64/model_mix_edit.cpp @@ -150,7 +150,7 @@ void menuModelMixOne(event_t event) case MIX_FIELD_CURVE: lcdDrawTextAlignedLeft(y, STR_CURVE); - editCurveRef(MIXES_2ND_COLUMN, y, md2->curve, event, attr); + editCurveRef(MIXES_2ND_COLUMN, y, md2->curve, s_editMode > 0 ? event : 0, attr); break; #if defined(FLIGHT_MODES) diff --git a/radio/src/gui/128x64/model_setup.cpp b/radio/src/gui/128x64/model_setup.cpp index 1b2a94e1e..4a06f741b 100644 --- a/radio/src/gui/128x64/model_setup.cpp +++ b/radio/src/gui/128x64/model_setup.cpp @@ -88,6 +88,7 @@ enum MenuModelSetupItems { ITEM_MODEL_SETUP_INTERNAL_MODULE_LABEL, ITEM_MODEL_SETUP_INTERNAL_MODULE_TYPE, #if defined(MULTIMODULE) + ITEM_MODEL_SETUP_INTERNAL_MODULE_PROTOCOL, ITEM_MODEL_SETUP_INTERNAL_MODULE_SUBTYPE, ITEM_MODEL_SETUP_INTERNAL_MODULE_STATUS, ITEM_MODEL_SETUP_INTERNAL_MODULE_SYNCSTATUS, @@ -116,6 +117,7 @@ enum MenuModelSetupItems { ITEM_MODEL_SETUP_EXTERNAL_MODULE_LABEL, ITEM_MODEL_SETUP_EXTERNAL_MODULE_TYPE, #if defined(MULTIMODULE) + ITEM_MODEL_SETUP_EXTERNAL_MODULE_PROTOCOL, ITEM_MODEL_SETUP_EXTERNAL_MODULE_SUBTYPE, #endif #if defined(MULTIMODULE) @@ -211,7 +213,7 @@ inline uint8_t MODULE_TYPE_ROWS(int moduleIdx) return 1; #if defined(MULTIMODULE) else if (isModuleMultimodule(moduleIdx)) { - return 1; + return 0; } #endif else @@ -309,19 +311,20 @@ void onBluetoothConnectMenu(const char * result) #if defined(HARDWARE_INTERNAL_MODULE) #define INTERNAL_MODULE_ROWS \ LABEL(InternalModule), \ - MODULE_TYPE_ROWS(INTERNAL_MODULE), /* ITEM_MODEL_SETUP_INTERNAL_MODULE_TYPE*/ \ - MULTIMODULE_SUBTYPE_ROWS(INTERNAL_MODULE) /* ITEM_MODEL_SETUP_INTERNAL_MODULE_SUBTYPE*/ \ + MODULE_TYPE_ROWS(INTERNAL_MODULE), /* ITEM_MODEL_SETUP_INTERNAL_MODULE_TYPE */ \ + MULTIMODULE_TYPE_ROWS(INTERNAL_MODULE) /* ITEM_MODEL_SETUP_INTERNAL_MODULE_PROTOCOL */ \ + 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_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_ACCESS_MODULE_RF(INTERNAL_MODULE, 0), /* ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_MODEL_NUM*/ \ + 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(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 */ \ EXTERNAL_ANTENNA_ROW /* ITEM_MODEL_SETUP_INTERNAL_MODULE_ANTENNA */ \ MODULE_POWER_ROW(INTERNAL_MODULE), /* ITEM_MODEL_SETUP_INTERNAL_MODULE_POWER */ \ IF_INTERNAL_MODULE_ON(FAILSAFE_ROWS(INTERNAL_MODULE)), /* ITEM_MODEL_SETUP_INTERNAL_MODULE_FAILSAFE */ \ IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 1), /* ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_REGISTER_RANGE */ \ - IF_PXX2_MODULE(INTERNAL_MODULE, 0), /* ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_OPTIONS*/ \ + IF_PXX2_MODULE(INTERNAL_MODULE, 0), /* ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_OPTIONS */ \ IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 0), /* ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_RECEIVER_1 */ \ IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 0), /* ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_RECEIVER_2 */ \ IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 0), /* ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_RECEIVER_3 */ @@ -365,7 +368,8 @@ void menuModelSetup(event_t event) LABEL(ExternalModule), MODULE_TYPE_ROWS(EXTERNAL_MODULE), - MULTIMODULE_SUBTYPE_ROWS(EXTERNAL_MODULE) + MULTIMODULE_TYPE_ROWS(EXTERNAL_MODULE) // PROTOCOL + MULTIMODULE_SUBTYPE_ROWS(EXTERNAL_MODULE) // SUBTYPE 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 @@ -373,8 +377,8 @@ void menuModelSetup(event_t event) 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 + 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 @@ -908,12 +912,6 @@ void menuModelSetup(event_t event) lcdDrawTextAtIndex(lcdNextPos + 3, y, STR_DSM_PROTOCOLS, g_model.moduleData[moduleIdx].rfProtocol, menuHorizontalPosition==1 ? attr : 0); else if (isModuleR9MNonAccess(moduleIdx)) lcdDrawTextAtIndex(lcdNextPos + 3, y, STR_R9M_REGION, g_model.moduleData[moduleIdx].subType, (menuHorizontalPosition==1 ? attr : 0)); -#if defined(MULTIMODULE) - else if (isModuleMultimodule(moduleIdx)) { - int multi_rfProto = g_model.moduleData[moduleIdx].getMultiProtocol(); - lcdDrawMultiProtocolString(lcdNextPos + 3, y, moduleIdx, multi_rfProto, menuHorizontalPosition == 1 ? attr : 0); - } -#endif if (attr && menuHorizontalPosition == 0 && moduleIdx == EXTERNAL_MODULE) { if (s_editMode > 0) { g_model.moduleData[moduleIdx].type = MODULE_TYPE_NONE; @@ -962,18 +960,6 @@ void menuModelSetup(event_t event) g_model.moduleData[moduleIdx].channelsCount = defaultModuleChannels_M8(moduleIdx); } } - -#if defined(MULTIMODULE) - else if (isModuleMultimodule(moduleIdx)) { - int multiRfProto = g_model.moduleData[moduleIdx].getMultiProtocol(); - CHECK_INCDEC_MODELVAR_CHECK(event, multiRfProto, MODULE_SUBTYPE_MULTI_FIRST, MULTI_MAX_PROTOCOLS, isMultiProtocolSelectable); - if (checkIncDec_Ret) { - g_model.moduleData[moduleIdx].setMultiProtocol(multiRfProto); - g_model.moduleData[moduleIdx].subType = 0; - resetMultiProtocolsOptions(moduleIdx); - } - } -#endif else { CHECK_INCDEC_MODELVAR(event, g_model.moduleData[moduleIdx].subType, 0, MODULE_SUBTYPE_PXX1_LAST); } @@ -1008,6 +994,45 @@ void menuModelSetup(event_t event) break; #if defined(MULTIMODULE) +#if defined(HARDWARE_INTERNAL_MODULE) + case ITEM_MODEL_SETUP_INTERNAL_MODULE_PROTOCOL: +#endif + case ITEM_MODEL_SETUP_EXTERNAL_MODULE_PROTOCOL: + { + lcdDrawTextAlignedLeft(y, TR_TYPE); + int multi_rfProto = g_model.moduleData[moduleIdx].getMultiProtocol(); + lcdDrawMultiProtocolString(MODEL_SETUP_2ND_COLUMN, y, moduleIdx, multi_rfProto, attr); + if (attr) { + int multiRfProto = g_model.moduleData[moduleIdx].getMultiProtocol(); + MultiModuleStatus &status = getMultiModuleStatus(moduleIdx); + if (status.isValid()) { + int8_t direction = checkIncDec(event, 0, -1, 1); + if (direction == -1) { + if (multiRfProto == MODULE_SUBTYPE_MULTI_FRSKY) + multiRfProto = MODULE_SUBTYPE_MULTI_FRSKYX_RX; + else + multiRfProto = convertMultiToOtx(status.protocolPrev); + } + if (direction == 1) { + if (multiRfProto == MODULE_SUBTYPE_MULTI_FRSKY) + multiRfProto = MODULE_SUBTYPE_MULTI_FRSKYX2; + else + multiRfProto = convertMultiToOtx(status.protocolNext); + } + } + else { + CHECK_INCDEC_MODELVAR_CHECK(event, multiRfProto, MODULE_SUBTYPE_MULTI_FIRST, MULTI_MAX_PROTOCOLS, isMultiProtocolSelectable); + } + if (checkIncDec_Ret) { + g_model.moduleData[moduleIdx].setMultiProtocol(multiRfProto); + g_model.moduleData[moduleIdx].subType = 0; + resetMultiProtocolsOptions(moduleIdx); + storageDirty(EE_MODEL); + } + } + } + break; + #if defined(HARDWARE_INTERNAL_MODULE) case ITEM_MODEL_SETUP_INTERNAL_MODULE_SUBTYPE: #endif @@ -1324,7 +1349,8 @@ void menuModelSetup(event_t event) } } lcdDrawText(MODEL_SETUP_2ND_COLUMN+xOffsetBind, y, STR_MODULE_BIND, l_posHorz==1 ? attr : 0); - lcdDrawText(MODEL_SETUP_2ND_COLUMN+MODEL_SETUP_RANGE_OFS+xOffsetBind, y, STR_MODULE_RANGE, l_posHorz==2 ? attr : 0); + if (!IS_RX_MULTI(moduleIdx)) + lcdDrawText(MODEL_SETUP_2ND_COLUMN+MODEL_SETUP_RANGE_OFS+xOffsetBind, y, STR_MODULE_RANGE, l_posHorz==2 ? attr : 0); uint8_t newFlag = 0; #if defined(MULTIMODULE) if (getMultiBindStatus(moduleIdx) == MULTI_BIND_FINISHED) { @@ -1584,7 +1610,7 @@ void menuModelSetup(event_t event) } #if defined(MULTIMODULE) else if (isModuleMultimodule(moduleIdx)) { - module.multi.lowPowerMode = editCheckBox(module.multi.lowPowerMode, MODEL_SETUP_2ND_COLUMN, y, STR_MULTI_LOWPOWER, attr, event); + module.multi.lowPowerMode = editCheckBox(module.multi.lowPowerMode, MODEL_SETUP_2ND_COLUMN, y, IS_RX_MULTI(moduleIdx) ? STR_MULTI_LNA_DISABLE : STR_MULTI_LOWPOWER, attr, event); } #endif diff --git a/radio/src/gui/128x64/view_channels.cpp b/radio/src/gui/128x64/view_channels.cpp index 2e3ed0a40..ccd8fc9b3 100644 --- a/radio/src/gui/128x64/view_channels.cpp +++ b/radio/src/gui/128x64/view_channels.cpp @@ -128,10 +128,6 @@ void menuChannelsView(event_t event) case EVT_KEY_PREVIOUS_PAGE: g_eeGeneral.view = (g_eeGeneral.view + (4 * ALTERNATE_VIEW) - ALTERNATE_VIEW) % (4 * ALTERNATE_VIEW); break; - - case EVT_KEY_FIRST(KEY_ENTER): - reusableBuffer.viewChannels.mixersView = !reusableBuffer.viewChannels.mixersView; - break; } menuChannelsViewCommon(event); diff --git a/radio/src/gui/212x64/gui.h b/radio/src/gui/212x64/gui.h index 70e6615bf..763c5f7c6 100644 --- a/radio/src/gui/212x64/gui.h +++ b/radio/src/gui/212x64/gui.h @@ -32,6 +32,7 @@ #define DEFAULT_SCROLLBAR_X (LCD_W-1) #define NUM_BODY_LINES (LCD_LINES-1) +#define TEXT_VIEWER_LINES NUM_BODY_LINES #define MENU_HEADER_HEIGHT FH #define MODEL_BITMAP_WIDTH 64 @@ -226,7 +227,6 @@ swsrc_t editSwitch(coord_t x, coord_t y, swsrc_t value, LcdFlags attr, event_t e void gvarWeightItem(coord_t x, coord_t y, MixData * md, LcdFlags attr, event_t event); -extern uint8_t s_curveChan; void editCurveRef(coord_t x, coord_t y, CurveRef & curve, event_t event, LcdFlags flags); extern uint8_t editNameCursorPos; @@ -244,6 +244,7 @@ extern uint8_t s_copyMode; extern int8_t s_copySrcRow; extern int8_t s_copyTgtOfs; extern uint8_t s_currIdx; +extern uint8_t s_currIdxSubMenu; extern uint8_t s_maxLines; extern uint8_t s_copySrcIdx; extern uint8_t s_copySrcCh; diff --git a/radio/src/gui/212x64/lcd.cpp b/radio/src/gui/212x64/lcd.cpp index 3b09fee9b..fdeca7cc9 100644 --- a/radio/src/gui/212x64/lcd.cpp +++ b/radio/src/gui/212x64/lcd.cpp @@ -18,6 +18,7 @@ * GNU General Public License for more details. */ +#include #include "opentx.h" #include "common/stdlcd/fonts.h" @@ -87,11 +88,11 @@ void lcdPutPattern(coord_t x, coord_t y, const uint8_t * pattern, uint8_t width, uint8_t lines = (height+7)/8; assert(lines <= 5); - for (int8_t i=0; i<(int8_t)(width+2); i++) { - if (x= 12) continue; - if (j<0 && !inv) continue; - if (y+j < 0) continue; + if (height >= 12) + continue; + if (j < 0 && !inv) + continue; + if (y + j < 0) + continue; } else { uint8_t line = (j / 8); uint8_t pixel = (j % 8); plot = b[line] & (1 << pixel); } - if (inv) plot = !plot; + if (inv) + plot = !plot; if (!blink) { if (flags & VERTICAL) lcdDrawPoint(y+j, LCD_H-x, plot ? FORCE : ERASE); @@ -154,10 +159,10 @@ void getCharPattern(PatternData * pattern, unsigned char c, LcdFlags flags) uint32_t fontsize = FONTSIZE(flags); unsigned char c_remapped = 0; - if (fontsize == DBLSIZE || (flags&BOLD)) { + if (fontsize == DBLSIZE || (flags & BOLD)) { // To save space only some DBLSIZE and BOLD chars are available // c has to be remapped. All non existing chars mapped to 0 (space) - if (c>=',' && c<=':') + if (c >= ',' && c <= ':') c_remapped = c - ',' + 1; else if (c>='A' && c<='Z') c_remapped = c - 'A' + 16; @@ -221,7 +226,7 @@ uint8_t getCharWidth(char c, LcdFlags flags) } #endif -void lcdDrawChar(coord_t x, coord_t y, const unsigned char c, LcdFlags flags) +void lcdDrawChar(coord_t x, coord_t y, char c, LcdFlags flags) { lcdNextPos = x-1; #if defined(BOOT) @@ -234,7 +239,7 @@ void lcdDrawChar(coord_t x, coord_t y, const unsigned char c, LcdFlags flags) #endif } -void lcdDrawChar(coord_t x, coord_t y, const unsigned char c) +void lcdDrawChar(coord_t x, coord_t y, char c) { lcdDrawChar(x, y, c, 0); } @@ -285,7 +290,7 @@ void lcdDrawSizedText(coord_t x, coord_t y, const char * s, uint8_t len, LcdFlag break; } else if (c >= 0x20) { - if ( ( c == 46) && ((FONTSIZE(flags) == TINSIZE))) { // '.' handling + if (c == 46 && FONTSIZE(flags) == TINSIZE) { // '.' handling if (((flags & BLINK) && BLINK_ON_PHASE) || ((!(flags & BLINK) && (flags & INVERS)))) { lcdDrawSolidVerticalLine(x, y-1, 5); lcdDrawPoint(x, y + 5); @@ -293,7 +298,7 @@ void lcdDrawSizedText(coord_t x, coord_t y, const char * s, uint8_t len, LcdFlag else { lcdDrawPoint(x, y + 5 -1 , flags); } - x+=2; + x += 2; } else { lcdDrawChar(x, y, c, flags); @@ -320,7 +325,7 @@ void lcdDrawSizedText(coord_t x, coord_t y, const char * s, uint8_t len, LcdFlag x += 1; } else { - x += (c*FW/2); // EXTENDED SPACE + x += (c * FW/2); // EXTENDED SPACE } s++; } @@ -398,7 +403,19 @@ void lcdDrawNumber(coord_t x, coord_t y, int32_t val, LcdFlags flags, uint8_t le int idx = 0; int mode = MODE(flags); bool neg = false; + + if (val == INT_MAX) { + flags &= ~(LEADING0 | PREC1 | PREC2); + lcdDrawText(x, y, "INT_MAX", flags); + return; + } + if (val < 0) { + if (val == INT_MIN) { + flags &= ~(LEADING0 | PREC1 | PREC2); + lcdDrawText(x, y, "INT_MIN", flags); + return; + } val = -val; neg = true; } diff --git a/radio/src/gui/212x64/lcd.h b/radio/src/gui/212x64/lcd.h index 73bd600f4..be9b89e95 100644 --- a/radio/src/gui/212x64/lcd.h +++ b/radio/src/gui/212x64/lcd.h @@ -100,12 +100,12 @@ extern coord_t lcdNextPos; #define DISPLAY_END (displayBuf + DISPLAY_BUFFER_SIZE) #define ASSERT_IN_DISPLAY(p) assert((p) >= displayBuf && (p) < DISPLAY_END) -void lcdDrawChar(coord_t x, coord_t y, const unsigned char c); -void lcdDrawChar(coord_t x, coord_t y, const unsigned char c, LcdFlags mode); +void lcdDrawChar(coord_t x, coord_t y, char c); +void lcdDrawChar(coord_t x, coord_t y, char c, LcdFlags mode); void lcdDrawCenteredText(coord_t y, const char * s, LcdFlags flags = 0); void lcdDrawText(coord_t x, coord_t y, const char * s, LcdFlags mode); void lcdDrawTextAtIndex(coord_t x, coord_t y, const char * s,uint8_t idx, LcdFlags mode); -void lcdDrawSizedText(coord_t x, coord_t y, const char * s,unsigned char len, LcdFlags mode); +void lcdDrawSizedText(coord_t x, coord_t y, const char * s, unsigned char len, LcdFlags mode); void lcdDrawText(coord_t x, coord_t y, const char * s); void lcdDrawSizedText(coord_t x, coord_t y, const char * s, unsigned char len); void lcdDrawTextAlignedLeft(coord_t y, const char * s); diff --git a/radio/src/gui/212x64/menu_model.cpp b/radio/src/gui/212x64/menu_model.cpp index 402189fb5..329220305 100644 --- a/radio/src/gui/212x64/menu_model.cpp +++ b/radio/src/gui/212x64/menu_model.cpp @@ -63,7 +63,9 @@ uint8_t editNameCursorPos = 0; void editSingleName(coord_t x, coord_t y, const char * label, char *name, uint8_t size, event_t event, uint8_t active) { lcdDrawTextAlignedLeft(y, label); + TRACE("EDIT SINGLE NAME %s", name); editName(x, y, name, size, event, active); } uint8_t s_currIdx; +uint8_t s_currIdxSubMenu; diff --git a/radio/src/gui/212x64/model_curve_edit.cpp b/radio/src/gui/212x64/model_curve_edit.cpp index 5e2145f4c..fd2ad6bc8 100644 --- a/radio/src/gui/212x64/model_curve_edit.cpp +++ b/radio/src/gui/212x64/model_curve_edit.cpp @@ -52,8 +52,8 @@ void runPopupCurvePreset(event_t event) if (warningResult) { warningResult = 0; - CurveHeader & crv = g_model.curves[s_curveChan]; - int8_t * points = curveAddress(s_curveChan); + CurveHeader & crv = g_model.curves[s_currIdxSubMenu]; + int8_t * points = curveAddress(s_currIdxSubMenu); int k = 25 * reusableBuffer.curveEdit.preset; int dx = 2000 / (5+crv.points-1); for (uint8_t i=0; i<5+crv.points; i++) { @@ -73,14 +73,14 @@ void onCurveOneMenu(const char * result) POPUP_INPUT(STR_PRESET, runPopupCurvePreset); } else if (result == STR_MIRROR) { - CurveHeader & crv = g_model.curves[s_curveChan]; - int8_t * points = curveAddress(s_curveChan); + CurveHeader & crv = g_model.curves[s_currIdxSubMenu]; + int8_t * points = curveAddress(s_currIdxSubMenu); for (int i=0; i<5+crv.points; i++) points[i] = -points[i]; } else if (result == STR_CLEAR) { - CurveHeader & crv = g_model.curves[s_curveChan]; - int8_t * points = curveAddress(s_curveChan); + CurveHeader & crv = g_model.curves[s_currIdxSubMenu]; + int8_t * points = curveAddress(s_currIdxSubMenu); for (int i=0; i<5+crv.points; i++) points[i] = 0; if (crv.type == CURVE_TYPE_CUSTOM) { @@ -92,10 +92,10 @@ void onCurveOneMenu(const char * result) void menuModelCurveOne(event_t event) { static uint8_t pointsOfs = 0; - CurveHeader & crv = g_model.curves[s_curveChan]; - int8_t * points = curveAddress(s_curveChan); + CurveHeader & crv = g_model.curves[s_currIdxSubMenu]; + int8_t * points = curveAddress(s_currIdxSubMenu); - drawStringWithIndex(PSIZE(TR_MENUCURVES)*FW+FW, 0, "CV", s_curveChan+1); + drawStringWithIndex(PSIZE(TR_MENUCURVES)*FW+FW, 0, "CV", s_currIdxSubMenu+1); lcdDrawText(11*FW+FW/2, 0, TR_PT "\002X\006Y"); lcdDrawFilledRect(0, 0, LCD_W, FH, SOLID, FILL_WHITE|GREY_DEFAULT); @@ -114,9 +114,9 @@ void menuModelCurveOne(event_t event) uint8_t newType = checkIncDecModelZero(event, crv.type, CURVE_TYPE_LAST); if (newType != crv.type) { for (int i = 1; i < 4 + crv.points; i++) { - points[i] = calcRESXto100(applyCustomCurve(calc100toRESX(getCurveX(5 + crv.points, i)), s_curveChan)); + points[i] = calcRESXto100(applyCustomCurve(calc100toRESX(getCurveX(5 + crv.points, i)), s_currIdxSubMenu)); } - if (moveCurve(s_curveChan, checkIncDec_Ret > 0 ? 3 + crv.points : -3 - crv.points)) { + if (moveCurve(s_currIdxSubMenu, checkIncDec_Ret > 0 ? 3 + crv.points : -3 - crv.points)) { if (newType == CURVE_TYPE_CUSTOM) { resetCustomCurveX(points, 5 + crv.points); } @@ -137,8 +137,8 @@ void menuModelCurveOne(event_t event) newPoints[0] = points[0]; newPoints[4 + count] = points[4 + crv.points]; for (int i = 1; i < 4 + count; i++) - newPoints[i] = calcRESXto100(applyCustomCurve(calc100toRESX(getCurveX(5 + count, i)), s_curveChan)); - if (moveCurve(s_curveChan, checkIncDec_Ret * (crv.type == CURVE_TYPE_CUSTOM ? 2 : 1))) { + newPoints[i] = calcRESXto100(applyCustomCurve(calc100toRESX(getCurveX(5 + count, i)), s_currIdxSubMenu)); + if (moveCurve(s_currIdxSubMenu, checkIncDec_Ret * (crv.type == CURVE_TYPE_CUSTOM ? 2 : 1))) { for (int i = 0; i < 5 + count; i++) { points[i] = newPoints[i]; if (crv.type == CURVE_TYPE_CUSTOM && i != 0 && i != 4 + count) diff --git a/radio/src/gui/212x64/model_outputs.cpp b/radio/src/gui/212x64/model_outputs.cpp index 54261d88b..404788aeb 100644 --- a/radio/src/gui/212x64/model_outputs.cpp +++ b/radio/src/gui/212x64/model_outputs.cpp @@ -212,7 +212,7 @@ void menuModelLimits(event_t event) case ITEM_LIMITS_CURVE: drawCurveName(LIMITS_CURVE_POS, y, ld->curve, attr); if (attr && event==EVT_KEY_LONG(KEY_ENTER) && ld->curve>0) { - s_curveChan = (ld->curve<0 ? -ld->curve-1 : ld->curve-1); + s_currIdxSubMenu = (ld->curve<0 ? -ld->curve-1 : ld->curve-1); pushMenu(menuModelCurveOne); } if (active) { diff --git a/radio/src/gui/212x64/model_select.cpp b/radio/src/gui/212x64/model_select.cpp index 2ddc1628f..6b5282c15 100644 --- a/radio/src/gui/212x64/model_select.cpp +++ b/radio/src/gui/212x64/model_select.cpp @@ -20,7 +20,6 @@ #include "opentx.h" -#define MODELSIZE_POS_X 170 #define MODELSEL_W 133 void onModelSelectMenu(const char * result) diff --git a/radio/src/gui/212x64/model_setup.cpp b/radio/src/gui/212x64/model_setup.cpp index e286261ee..92729de50 100644 --- a/radio/src/gui/212x64/model_setup.cpp +++ b/radio/src/gui/212x64/model_setup.cpp @@ -98,6 +98,7 @@ enum MenuModelSetupItems { ITEM_MODEL_SETUP_EXTERNAL_MODULE_LABEL, ITEM_MODEL_SETUP_EXTERNAL_MODULE_TYPE, #if defined (MULTIMODULE) + ITEM_MODEL_SETUP_EXTERNAL_MODULE_PROTOCOL, ITEM_MODEL_SETUP_EXTERNAL_MODULE_STATUS, ITEM_MODEL_SETUP_EXTERNAL_MODULE_SYNCSTATUS, #endif @@ -248,11 +249,6 @@ inline uint8_t EXTERNAL_MODULE_TYPE_ROW() { if (isModuleXJT(EXTERNAL_MODULE) || isModuleR9MNonAccess(EXTERNAL_MODULE) || isModuleDSM2(EXTERNAL_MODULE)) return 1; -#if defined(MULTIMODULE) - else if (isModuleMultimodule(EXTERNAL_MODULE)) { - return 1 + MULTIMODULE_RFPROTO_COLUMNS(EXTERNAL_MODULE); - } -#endif else return 0; } @@ -362,6 +358,7 @@ void menuModelSetup(event_t event) LABEL(ExternalModule), EXTERNAL_MODULE_TYPE_ROW(), + MULTIMODULE_TYPE_ROW(EXTERNAL_MODULE) MULTIMODULE_STATUS_ROWS(EXTERNAL_MODULE) MODULE_CHANNELS_ROWS(EXTERNAL_MODULE), IF_NOT_ACCESS_MODULE_RF(EXTERNAL_MODULE, MODULE_BIND_ROWS(EXTERNAL_MODULE)), @@ -813,15 +810,6 @@ void menuModelSetup(event_t event) lcdDrawTextAtIndex(lcdNextPos + 3, y, STR_DSM_PROTOCOLS, g_model.moduleData[EXTERNAL_MODULE].rfProtocol, menuHorizontalPosition==1 ? attr : 0); else if (isModuleR9MNonAccess(EXTERNAL_MODULE)) lcdDrawTextAtIndex(lcdNextPos + 3, y, STR_R9M_REGION, g_model.moduleData[EXTERNAL_MODULE].subType, (menuHorizontalPosition==1 ? attr : 0)); -#if defined(MULTIMODULE) - else if (isModuleMultimodule(EXTERNAL_MODULE)) { - uint8_t multi_rfProto = g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(); - // Do not use MODEL_SETUP_3RD_COLUMN here since some the protocol string are so long that we cannot afford the 2 spaces (+6) here - lcdDrawMultiProtocolString(lcdNextPos + 3, y, EXTERNAL_MODULE, multi_rfProto, menuHorizontalPosition == 1 ? attr : 0); - if (MULTIMODULE_HAS_SUBTYPE(EXTERNAL_MODULE)) - lcdDrawMultiSubProtocolString(lcdNextPos + 3, y, EXTERNAL_MODULE, g_model.moduleData[EXTERNAL_MODULE].subType, menuHorizontalPosition==2 ? attr : 0); - } -#endif if (attr && menuHorizontalPosition == 0) { if (s_editMode > 0) { g_model.moduleData[EXTERNAL_MODULE].type = MODULE_TYPE_NONE; @@ -906,6 +894,59 @@ void menuModelSetup(event_t event) } break; +#if defined(MULTIMODULE) + case ITEM_MODEL_SETUP_EXTERNAL_MODULE_PROTOCOL: + { + lcdDrawTextAlignedLeft(y, TR_TYPE); + uint8_t multi_rfProto = g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(); + lcdDrawMultiProtocolString(MODEL_SETUP_2ND_COLUMN, y, EXTERNAL_MODULE, multi_rfProto, menuHorizontalPosition == 0 ? attr : 0); + if (MULTIMODULE_HAS_SUBTYPE(EXTERNAL_MODULE)) + lcdDrawMultiSubProtocolString(MODEL_SETUP_3RD_COLUMN + 15, y, EXTERNAL_MODULE, g_model.moduleData[EXTERNAL_MODULE].subType, + menuHorizontalPosition == 1 ? attr : 0); + if (attr) { + switch (menuHorizontalPosition) { + case 0: { + int multiRfProto = g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(); + MultiModuleStatus &status = getMultiModuleStatus(EXTERNAL_MODULE); + if (status.isValid()) { + int8_t direction = checkIncDec(event, 0, -1, 1); + if (direction == -1) { + if (multiRfProto == MODULE_SUBTYPE_MULTI_FRSKY) + multiRfProto = MODULE_SUBTYPE_MULTI_FRSKYX_RX; + else + multiRfProto = convertMultiToOtx(status.protocolPrev); + } + if (direction == 1) { + if (multiRfProto == MODULE_SUBTYPE_MULTI_FRSKY) + multiRfProto = MODULE_SUBTYPE_MULTI_FRSKYX2; + else + multiRfProto = convertMultiToOtx(status.protocolNext); + } + } + else { + CHECK_INCDEC_MODELVAR_CHECK(event, multiRfProto, MODULE_SUBTYPE_MULTI_FIRST, MULTI_MAX_PROTOCOLS, isMultiProtocolSelectable); + } + if (checkIncDec_Ret) { + g_model.moduleData[EXTERNAL_MODULE].setMultiProtocol(multiRfProto); + g_model.moduleData[EXTERNAL_MODULE].subType = 0; + resetMultiProtocolsOptions(EXTERNAL_MODULE); + storageDirty(EE_MODEL); + } + } + break; + + case 1: + CHECK_INCDEC_MODELVAR(event, g_model.moduleData[EXTERNAL_MODULE].subType, 0, getMaxMultiSubtype(EXTERNAL_MODULE)); + if (checkIncDec_Ret) { + resetMultiProtocolsOptions(EXTERNAL_MODULE); + } + break; + } + } + } + break; +#endif + case ITEM_MODEL_SETUP_TRAINER_LABEL: lcdDrawTextAlignedLeft(y, STR_TRAINER); break; @@ -1100,8 +1141,13 @@ void menuModelSetup(event_t event) lcdDrawText(INDENT_WIDTH, y, STR_RECEIVER_NUM); } if (isModuleBindRangeAvailable(moduleIdx)) { - lcdDrawNumber(MODEL_SETUP_2ND_COLUMN, y, g_model.header.modelId[moduleIdx], (l_posHorz==0 ? attr : 0) | LEADING0|LEFT, 2); - bindButtonPos = lcdNextPos + FW; + if (!IS_RX_MULTI(moduleIdx)) { + lcdDrawNumber(MODEL_SETUP_2ND_COLUMN, y, g_model.header.modelId[moduleIdx], (l_posHorz == 0 ? attr : 0) | LEADING0 | LEFT, 2); + bindButtonPos = lcdNextPos + FW; + } + else { + bindButtonPos = MODEL_SETUP_2ND_COLUMN; + } if (attr && l_posHorz==0) { if (s_editMode>0) { CHECK_INCDEC_MODELVAR_ZERO(event, g_model.header.modelId[moduleIdx], getMaxRxNum(moduleIdx)); @@ -1119,7 +1165,8 @@ void menuModelSetup(event_t event) } } lcdDrawText(bindButtonPos, y, STR_MODULE_BIND, l_posHorz==1 ? attr : 0); - lcdDrawText(lcdNextPos + FW, y, STR_MODULE_RANGE, l_posHorz==2 ? attr : 0); + if (!IS_RX_MULTI(moduleIdx)) + lcdDrawText(lcdNextPos + FW, y, STR_MODULE_RANGE, l_posHorz==2 ? attr : 0); uint8_t newFlag = 0; #if defined(MULTIMODULE) if (getMultiBindStatus(moduleIdx) == MULTI_BIND_FINISHED) { @@ -1284,7 +1331,7 @@ void menuModelSetup(event_t event) } #if defined (MULTIMODULE) else if (isModuleMultimodule(moduleIdx)) { - g_model.moduleData[EXTERNAL_MODULE].multi.lowPowerMode = editCheckBox(g_model.moduleData[EXTERNAL_MODULE].multi.lowPowerMode, MODEL_SETUP_2ND_COLUMN, y, STR_MULTI_LOWPOWER, attr, event); + g_model.moduleData[EXTERNAL_MODULE].multi.lowPowerMode = editCheckBox(g_model.moduleData[EXTERNAL_MODULE].multi.lowPowerMode, MODEL_SETUP_2ND_COLUMN, y, IS_RX_MULTI(moduleIdx) ? STR_MULTI_LNA_DISABLE : STR_MULTI_LOWPOWER, attr, event); } #endif break; diff --git a/radio/src/gui/212x64/radio_diaganas.cpp b/radio/src/gui/212x64/radio_diaganas.cpp index bea4089a4..6e1f21ced 100644 --- a/radio/src/gui/212x64/radio_diaganas.cpp +++ b/radio/src/gui/212x64/radio_diaganas.cpp @@ -38,12 +38,4 @@ void menuRadioDiagAnalogs(event_t event) lcdDrawNumber(x+10*FW-1, y, (int16_t)calibratedAnalogs[CONVERT_MODE(i)]*25/256, RIGHT); #endif } - - // RAS - if ((isModuleXJT(INTERNAL_MODULE) && IS_INTERNAL_MODULE_ON()) || (isModulePXX1(EXTERNAL_MODULE) && !IS_INTERNAL_MODULE_ON())) { - lcdDrawTextAlignedLeft(MENU_HEADER_HEIGHT+6*FH, "RAS"); - lcdDrawNumber(10*FW-1, MENU_HEADER_HEIGHT+6*FH, telemetryData.swrInternal.value(), RIGHT); - lcdDrawText(LCD_W/2, MENU_HEADER_HEIGHT+6*FH, "XJTVER"); - lcdDrawNumber(LCD_W/2 + 10*FW-1, MENU_HEADER_HEIGHT+6*FH, telemetryData.xjtVersion, RIGHT); - } } diff --git a/radio/src/gui/colorlcd/layouts/layout1x1.cpp b/radio/src/gui/colorlcd/layouts/layout1x1.cpp index 2dcd44a7a..0ea3f10a4 100644 --- a/radio/src/gui/colorlcd/layouts/layout1x1.cpp +++ b/radio/src/gui/colorlcd/layouts/layout1x1.cpp @@ -25,8 +25,8 @@ const uint8_t LBM_LAYOUT_1x1[] = { }; const ZoneOption OPTIONS_LAYOUT_1x1[] = { - { "Top bar", ZoneOption::Bool }, - { "Sliders+Trims", ZoneOption::Bool }, + { STR_TOP_BAR, ZoneOption::Bool }, + { STR_SLIDERS_TRIMS, ZoneOption::Bool }, { nullptr, ZoneOption::Bool } }; diff --git a/radio/src/gui/colorlcd/layouts/layout2x1.cpp b/radio/src/gui/colorlcd/layouts/layout2x1.cpp index 6344ada45..b6345bd47 100644 --- a/radio/src/gui/colorlcd/layouts/layout2x1.cpp +++ b/radio/src/gui/colorlcd/layouts/layout2x1.cpp @@ -25,7 +25,7 @@ const uint8_t LBM_LAYOUT_2x1[] = { }; const ZoneOption OPTIONS_LAYOUT_2x1[] = { - { "Top bar", ZoneOption::Bool }, + { STR_TOP_BAR, ZoneOption::Bool }, { nullptr, ZoneOption::Bool } }; @@ -45,7 +45,7 @@ class Layout2x1: public Layout unsigned int getZonesCount() const override { - return 4; + return 2; } Zone getZone(unsigned int index) const override diff --git a/radio/src/gui/colorlcd/layouts/layout2x2.cpp b/radio/src/gui/colorlcd/layouts/layout2x2.cpp index 453bf9085..08ed50159 100644 --- a/radio/src/gui/colorlcd/layouts/layout2x2.cpp +++ b/radio/src/gui/colorlcd/layouts/layout2x2.cpp @@ -25,7 +25,7 @@ const uint8_t LBM_LAYOUT_2x2[] = { }; const ZoneOption OPTIONS_LAYOUT_2x2[] = { - { "Top bar", ZoneOption::Bool }, + { STR_TOP_BAR, ZoneOption::Bool }, { nullptr, ZoneOption::Bool } }; diff --git a/radio/src/gui/colorlcd/lcd.cpp b/radio/src/gui/colorlcd/lcd.cpp index 297193247..71e67cc27 100644 --- a/radio/src/gui/colorlcd/lcd.cpp +++ b/radio/src/gui/colorlcd/lcd.cpp @@ -28,50 +28,12 @@ uint8_t getMappedChar(uint8_t c) { uint8_t result; -#if defined(TRANSLATIONS_FR) - if (c >= 0x80 && c <= 0x84) { - result = 115 + c - 0x80; - } -#elif defined(TRANSLATIONS_DE) - if (c >= 0x80 && c <= 0x86) { - result = 120 + c - 0x80; - } -#elif defined(TRANSLATIONS_CZ) - if (c >= 0x80 && c <= 0x80+29) { - result = 127 + c - 0x80; - } -#elif defined(TRANSLATIONS_ES) - if (c >= 0x80 && c <= 0x81) { - result = 157 + c - 0x80; - } -#elif defined(TRANSLATIONS_FI) - if (c >= 0x80 && c <= 0x85) { - result = 159 + c - 0x80; - } -#elif defined(TRANSLATIONS_IT) - if (c >= 0x80 && c <= 0x81) { - result = 165 + c - 0x80; - } -#elif defined(TRANSLATIONS_PL) - if (c >= 0x80 && c <= 0x80+17) { - result = 167 + c - 0x80; - } -#elif defined(TRANSLATIONS_PT) - if (c >= 0x80 && c <= 0x80+21) { - result = 185 + c - 0x80; - } -#elif defined(TRANSLATIONS_SE) - if (c >= 0x80 && c <= 0x85) { - result = 207 + c - 0x80; - } -#endif - - if (c < 0xC0) + if (c < 0x80) result = c - 0x20; else - result = c - 0xC0 + 96; + result = c - 0x80 + 32 + 26 + 6 + 26 + 5; // 96; -// TRACE("getMappedChar '%c' (%x) = %d", c, c, result); +// TRACE("getMappedChar '%c' (0x%x) = %d", c, c, result); return result; } diff --git a/radio/src/gui/colorlcd/menus.h b/radio/src/gui/colorlcd/menus.h index 3739d052f..544fce039 100644 --- a/radio/src/gui/colorlcd/menus.h +++ b/radio/src/gui/colorlcd/menus.h @@ -278,7 +278,7 @@ extern int8_t s_editMode; // global editmode //#define NAVIGATION_LINE_BY_LINE 0x40 //#define CURSOR_ON_LINE() (menuHorizontalPosition<0) -extern uint8_t s_curveChan; +extern uint8_t s_currIdxSubMenu; extern const char * warningText; extern const char * warningInfoText; diff --git a/radio/src/gui/colorlcd/model_select_old.cpp b/radio/src/gui/colorlcd/model_select_old.cpp index a405bdc35..abb12ce68 100644 --- a/radio/src/gui/colorlcd/model_select_old.cpp +++ b/radio/src/gui/colorlcd/model_select_old.cpp @@ -62,7 +62,7 @@ void drawModel(coord_t x, coord_t y, ModelCell * model, bool current, bool selec if (selected) { lcdDrawSolidRect(x, y, MODELCELL_WIDTH+2, MODELCELL_HEIGHT+2, 1, TITLE_BGCOLOR); drawShadow(x, y, MODELCELL_WIDTH+2, MODELCELL_HEIGHT+2); - if (selectMode == MODE_MOVE_MODEL) { + if (selectMode == MODE_MOVE_MODEL && modelselModelMoveBackground) { lcd->drawMask(x+MODELCELL_WIDTH+2-modelselModelMoveBackground->width(), y, modelselModelMoveBackground, TITLE_BGCOLOR); lcd->drawMask(x+MODELCELL_WIDTH+2-modelselModelMoveBackground->width()+12, y+5, modelselModelMoveIcon, DEFAULT_BGCOLOR); } @@ -279,7 +279,7 @@ void onModelSelectMenu(const char * result) setCurrentModel(currentCategory->size() - 1); } else { - POPUP_WARNING("Invalid File"); + POPUP_WARNING(STR_INVALID_FILE); } } else if (result == STR_MOVE_MODEL) { diff --git a/radio/src/gui/colorlcd/screens_setup_old.cpp b/radio/src/gui/colorlcd/screens_setup_old.cpp index cf9671c8c..7015325cc 100644 --- a/radio/src/gui/colorlcd/screens_setup_old.cpp +++ b/radio/src/gui/colorlcd/screens_setup_old.cpp @@ -121,7 +121,7 @@ bool editZoneOption(coord_t y, const ZoneOption * option, ZoneOptionValue * valu } } else if (option->type == ZoneOption::TextSize) { - lcdDrawTextAtIndex(SCREENS_SETUP_2ND_COLUMN, y, "\010StandardTiny\0 Small\0 Mid\0 Double", value->unsignedValue, attr); + lcdDrawTextAtIndex(SCREENS_SETUP_2ND_COLUMN, y, STR_TEXT_SIZE, value->unsignedValue, attr); if (attr) { value->unsignedValue = checkIncDec(event, value->unsignedValue, 0, 4, i_flags); } @@ -346,7 +346,7 @@ bool menuWidgetsSetup(event_t event) currentScreen->refresh(); - for (int i=currentContainer->getZonesCount()-1; i>=0; i--) { + for (int i = currentContainer->getZonesCount() - 1; i >= 0; i--) { Zone zone = currentContainer->getZone(i); LcdFlags color; int padding, thickness; @@ -558,7 +558,7 @@ bool menuScreenSetup(int index, event_t event) currentContainer = currentScreen; bool needsOffsetCheck = (menuVerticalPosition != 0 || menuHorizontalPosition < 0); - char title[] = "Main view X"; + char title[] = TR_MAIN_VIEW_X; title[sizeof(title)-2] = '1' + index; menuPageCount = updateMainviewsMenu(); diff --git a/radio/src/gui/colorlcd/sourcechoice.cpp b/radio/src/gui/colorlcd/sourcechoice.cpp index c2f4a1060..5d2598e7d 100644 --- a/radio/src/gui/colorlcd/sourcechoice.cpp +++ b/radio/src/gui/colorlcd/sourcechoice.cpp @@ -26,30 +26,31 @@ #include "lcd.h" #include "strhelpers.h" #include "draw_functions.h" +#include "opentx.h" class SourceChoiceMenuToolbar : public MenuToolbar { public: SourceChoiceMenuToolbar(SourceChoice * choice, Menu * menu): MenuToolbar(choice, menu) { - addButton(char('\314'), MIXSRC_FIRST_INPUT, MIXSRC_LAST_INPUT); + addButton(CHAR_INPUT, MIXSRC_FIRST_INPUT, MIXSRC_LAST_INPUT); #if defined(LUA_MODEL_SCRIPTS) - addButton(char('\322'), MIXSRC_LAST_LUA, MIXSRC_FIRST_LUA); + addButton(CHAR_LUA, MIXSRC_LAST_LUA, MIXSRC_FIRST_LUA); #endif - addButton(char('\307'), MIXSRC_FIRST_STICK, MIXSRC_LAST_STICK); - addButton(char('\310'), MIXSRC_FIRST_POT, MIXSRC_LAST_POT); - addButton(char('\315'), MIXSRC_MAX, MIXSRC_MAX); + addButton(char(CHAR_STICK), MIXSRC_FIRST_STICK, MIXSRC_LAST_STICK); + addButton(CHAR_POT, MIXSRC_FIRST_POT, MIXSRC_LAST_POT); + addButton(CHAR_FUNCTION, MIXSRC_MAX, MIXSRC_MAX); #if defined(HELI) - addButton(char('\316'), MIXSRC_FIRST_HELI, MIXSRC_LAST_HELI); + addButton(CHAR_CYC, MIXSRC_FIRST_HELI, MIXSRC_LAST_HELI); #endif - addButton(char('\313'), MIXSRC_FIRST_TRIM, MIXSRC_LAST_TRIM); - addButton(char('\312'), MIXSRC_FIRST_SWITCH, MIXSRC_LAST_SWITCH); - addButton(char('\317'), MIXSRC_FIRST_TRAINER, MIXSRC_LAST_TRAINER); - addButton(char('\320'), MIXSRC_FIRST_CH, MIXSRC_LAST_CH); + addButton(CHAR_TRIM, MIXSRC_FIRST_TRIM, MIXSRC_LAST_TRIM); + addButton(CHAR_SWITCH, MIXSRC_FIRST_SWITCH, MIXSRC_LAST_SWITCH); + addButton(CHAR_TRAINER, MIXSRC_FIRST_TRAINER, MIXSRC_LAST_TRAINER); + addButton(CHAR_CHANNEL, MIXSRC_FIRST_CH, MIXSRC_LAST_CH); #if defined(GVARS) - addButton(char('\311'), MIXSRC_LAST_GVAR, MIXSRC_FIRST_GVAR); + addButton(CHAR_GVAR, MIXSRC_LAST_GVAR, MIXSRC_FIRST_GVAR); #endif - addButton(char('\321'), MIXSRC_FIRST_TELEM, MIXSRC_LAST_TELEM); + addButton(CHAR_TELEMETRY, MIXSRC_FIRST_TELEM, MIXSRC_LAST_TELEM); } }; diff --git a/radio/src/gui/colorlcd/tabsgroup.cpp b/radio/src/gui/colorlcd/tabsgroup.cpp index a53b9b37a..23a144ebe 100644 --- a/radio/src/gui/colorlcd/tabsgroup.cpp +++ b/radio/src/gui/colorlcd/tabsgroup.cpp @@ -83,7 +83,7 @@ bool TabsCarousel::onTouchEnd(coord_t x, coord_t y) TabsGroup::TabsGroup(uint8_t icon): Window(&mainWindow, { 0, 0, LCD_W, LCD_H }, OPAQUE), header(this, icon), - body(this, { 0, MENU_BODY_TOP, LCD_W, MENU_BODY_HEIGHT }) + body(this, { 0, MENU_BODY_TOP, LCD_W, MENU_BODY_HEIGHT }, FORM_FORWARD_FOCUS) { } diff --git a/radio/src/gui/colorlcd/topbar.cpp b/radio/src/gui/colorlcd/topbar.cpp index eab8ad57e..1bc9e1aef 100644 --- a/radio/src/gui/colorlcd/topbar.cpp +++ b/radio/src/gui/colorlcd/topbar.cpp @@ -76,11 +76,19 @@ void drawTopBar() /* Tx battery */ uint8_t bars = GET_TXBATT_BARS(5); - lcdDrawBitmapPattern(LCD_W-130, 24, LBM_TOPMENU_TXBATT, MENU_COLOR); +#if defined(USB_CHARGER) + if (usbChargerLed()) { + lcdDrawBitmapPattern(LCD_W - 130, 25, LBM_TOPMENU_TXBATT_CHARGING, MENU_TITLE_COLOR); + } + else { + lcdDrawBitmapPattern(LCD_W - 130, 25, LBM_TOPMENU_TXBATT, MENU_TITLE_COLOR); + } +#else + lcdDrawBitmapPattern(LCD_W - 130, 25, LBM_TOPMENU_TXBATT, MENU_TITLE_COLOR); +#endif for (unsigned int i = 0; i < 5; i++) { - lcdDrawSolidFilledRect(LCD_W-122+4*i, 30, 2, 8, i >= bars ? MENU_TITLE_DISABLE_COLOR : MENU_COLOR); + lcdDrawSolidFilledRect(LCD_W - 128 + 4 * i, 30, 2, 8, i >= bars ? MENU_TITLE_DISABLE_COLOR : MENU_COLOR); } - topbar->refresh(); #if 0 diff --git a/radio/src/gui/colorlcd/view_text.cpp b/radio/src/gui/colorlcd/view_text.cpp index 24a1779db..e09f62699 100644 --- a/radio/src/gui/colorlcd/view_text.cpp +++ b/radio/src/gui/colorlcd/view_text.cpp @@ -42,7 +42,7 @@ bool menuTextView(event_t event) break; case EVT_ROTARY_RIGHT: - if (menuVerticalOffset + NUM_BODY_LINES >= lines_count) + if (menuVerticalOffset + TEXT_VIEWER_LINES >= lines_count) break; else ++menuVerticalOffset; @@ -55,11 +55,11 @@ bool menuTextView(event_t event) break; } - for (int i=0; idrawTextMaxWidth(MENUS_MARGIN_LEFT, MENU_CONTENT_TOP + i * FH, reusableBuffer.viewText.lines[i], 0, LCD_W - 2 * MENUS_MARGIN_LEFT); + for (int i = 0; i < TEXT_VIEWER_LINES; i++) { + lcd->drawTextMaxWidth(MENUS_MARGIN_LEFT, MENU_HEADER_HEIGHT + i * FH, reusableBuffer.viewText.lines[i], 0, LCD_W - 2 * MENUS_MARGIN_LEFT); } - drawVerticalScrollbar(LCD_W-5, 50, 195, menuVerticalOffset, lines_count, NUM_BODY_LINES); + drawVerticalScrollbar(LCD_W-5, 50, 195, menuVerticalOffset, lines_count, TEXT_VIEWER_LINES); return true; } diff --git a/radio/src/gui/colorlcd/widgets/gauge.cpp b/radio/src/gui/colorlcd/widgets/gauge.cpp index 0e03a5438..6b3dfac5c 100644 --- a/radio/src/gui/colorlcd/widgets/gauge.cpp +++ b/radio/src/gui/colorlcd/widgets/gauge.cpp @@ -34,10 +34,10 @@ class GaugeWidget: public Widget }; const ZoneOption GaugeWidget::options[] = { - { "Source", ZoneOption::Source, OPTION_VALUE_UNSIGNED(1) }, - { "Min", ZoneOption::Integer, OPTION_VALUE_SIGNED(-RESX), OPTION_VALUE_SIGNED(-RESX), OPTION_VALUE_SIGNED(RESX) }, - { "Max", ZoneOption::Integer, OPTION_VALUE_SIGNED(RESX), OPTION_VALUE_SIGNED(-RESX), OPTION_VALUE_SIGNED(RESX) }, - { "Color", ZoneOption::Color, OPTION_VALUE_UNSIGNED(RED) }, + { STR_SOURCE, ZoneOption::Source, OPTION_VALUE_UNSIGNED(1) }, + { STR_MIN, ZoneOption::Integer, OPTION_VALUE_SIGNED(-RESX), OPTION_VALUE_SIGNED(-RESX), OPTION_VALUE_SIGNED(RESX) }, + { STR_MAX, ZoneOption::Integer, OPTION_VALUE_SIGNED(RESX), OPTION_VALUE_SIGNED(-RESX), OPTION_VALUE_SIGNED(RESX) }, + { STR_COLOR, ZoneOption::Color, OPTION_VALUE_UNSIGNED(RED) }, { nullptr, ZoneOption::Bool } }; diff --git a/radio/src/gui/colorlcd/widgets/outputs.cpp b/radio/src/gui/colorlcd/widgets/outputs.cpp index 1f51db61f..d950c4618 100644 --- a/radio/src/gui/colorlcd/widgets/outputs.cpp +++ b/radio/src/gui/colorlcd/widgets/outputs.cpp @@ -95,9 +95,9 @@ class OutputsWidget: public Widget }; const ZoneOption OutputsWidget::options[] = { - { "First channel", ZoneOption::Integer, OPTION_VALUE_UNSIGNED(1), OPTION_VALUE_UNSIGNED(1), OPTION_VALUE_UNSIGNED(32) }, - { "Fill Background?", ZoneOption::Bool, OPTION_VALUE_BOOL(false) }, - { "BG Color", ZoneOption::Color, OPTION_VALUE_UNSIGNED(LIGHTGREY) }, + { 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) }, { nullptr, ZoneOption::Bool } }; diff --git a/radio/src/gui/colorlcd/widgets/text.cpp b/radio/src/gui/colorlcd/widgets/text.cpp index 2c2b4d143..5376064ca 100644 --- a/radio/src/gui/colorlcd/widgets/text.cpp +++ b/radio/src/gui/colorlcd/widgets/text.cpp @@ -36,10 +36,10 @@ class TextWidget: public Widget }; const ZoneOption TextWidget::options[] = { - { "Text", ZoneOption::String, OPTION_VALUE_STRING(TEXT_WIDGET_DEFAULT_LABEL) }, - { "Color", ZoneOption::Color, OPTION_VALUE_UNSIGNED(RED) }, - { "Size", ZoneOption::TextSize, OPTION_VALUE_UNSIGNED(0) }, - { "Shadow", ZoneOption::Bool, OPTION_VALUE_BOOL(false) }, + { STR_TEXT, ZoneOption::String, OPTION_VALUE_STRING(TEXT_WIDGET_DEFAULT_LABEL) }, + { STR_COLOR, ZoneOption::Color, OPTION_VALUE_UNSIGNED(RED) }, + { STR_SIZE, ZoneOption::TextSize, OPTION_VALUE_UNSIGNED(0) }, + { STR_SHADOW, ZoneOption::Bool, OPTION_VALUE_BOOL(false) }, { nullptr, ZoneOption::Bool } }; diff --git a/radio/src/gui/colorlcd/widgets/timer.cpp b/radio/src/gui/colorlcd/widgets/timer.cpp index e1b3d840e..b603c9c18 100644 --- a/radio/src/gui/colorlcd/widgets/timer.cpp +++ b/radio/src/gui/colorlcd/widgets/timer.cpp @@ -34,7 +34,7 @@ class TimerWidget: public Widget }; const ZoneOption TimerWidget::options[] = { - { "Timer source", ZoneOption::Timer, OPTION_VALUE_UNSIGNED(0) }, + { STR_TIMER_SOURCE, ZoneOption::Timer, OPTION_VALUE_UNSIGNED(0) }, { nullptr, ZoneOption::Bool } }; diff --git a/radio/src/gui/colorlcd/widgets/value.cpp b/radio/src/gui/colorlcd/widgets/value.cpp index af1f9931b..b0c8c5b52 100644 --- a/radio/src/gui/colorlcd/widgets/value.cpp +++ b/radio/src/gui/colorlcd/widgets/value.cpp @@ -34,9 +34,9 @@ class ValueWidget: public Widget }; const ZoneOption ValueWidget::options[] = { - { "Source", ZoneOption::Source, OPTION_VALUE_UNSIGNED(MIXSRC_Rud) }, - { "Color", ZoneOption::Color, OPTION_VALUE_UNSIGNED(WHITE) }, - { "Shadow", ZoneOption::Bool, OPTION_VALUE_BOOL(false) }, + { STR_SOURCE, ZoneOption::Source, OPTION_VALUE_UNSIGNED(MIXSRC_Rud) }, + { STR_COLOR, ZoneOption::Color, OPTION_VALUE_UNSIGNED(WHITE) }, + { STR_SHADOW, ZoneOption::Bool, OPTION_VALUE_BOOL(false) }, { nullptr, ZoneOption::Bool } }; diff --git a/radio/src/gui/common/stdlcd/draw_functions.cpp b/radio/src/gui/common/stdlcd/draw_functions.cpp index c11cbd4ae..155450fc3 100644 --- a/radio/src/gui/common/stdlcd/draw_functions.cpp +++ b/radio/src/gui/common/stdlcd/draw_functions.cpp @@ -84,7 +84,7 @@ void drawTrimMode(coord_t x, coord_t y, uint8_t flightMode, uint8_t idx, LcdFlag } } -void drawValueWithUnit(coord_t x, coord_t y, int val, uint8_t unit, LcdFlags att) +void drawValueWithUnit(coord_t x, coord_t y, int32_t val, uint8_t unit, LcdFlags att) { // convertUnit(val, unit); lcdDrawNumber(x, y, val, att & (~NO_UNIT)); @@ -121,6 +121,40 @@ FlightModesType editFlightModes(coord_t x, coord_t y, event_t event, FlightModes return value; } +char getNextChar(char c, uint8_t position) +{ + if (c == ' ') + return (position == 0 ? 'A' : 'a'); + + if (c == 'Z' || c == 'z') + return '0'; + + static const char * specialChars = "9_-., "; + for (uint8_t i = 0; specialChars[i] != 0; i++) { + if (c == specialChars[i]) + return specialChars[i + 1]; + } + + return c + 1; +} + +char getPreviousChar(char c, uint8_t position) +{ + if (c == 'A' || c == 'a') + return ' '; + + if (c == '0') + return (position == 0 ? 'Z' : 'z'); + + static const char * specialChars = "9_-., "; + for (uint8_t i = 1; specialChars[i] != 0; i++) { + if (c == specialChars[i]) + return specialChars[i - 1]; + } + + return c - 1; +} + void editName(coord_t x, coord_t y, char * name, uint8_t size, event_t event, uint8_t active, LcdFlags attr) { uint8_t mode = 0; @@ -131,23 +165,24 @@ void editName(coord_t x, coord_t y, char * name, uint8_t size, event_t event, ui mode = FIXEDWIDTH; } - lcdDrawSizedText(x, y, name, size, attr | mode); + lcdDrawSizedText(x, y, name[0] == '\0' ? "---" : name, size, attr | mode); coord_t backupNextPos = lcdNextPos; if (active) { uint8_t cur = editNameCursorPos; if (s_editMode > 0) { int8_t c = name[cur]; - int8_t v = c; - - if (IS_NEXT_EVENT(event) || IS_PREVIOUS_EVENT(event)) { - if (attr == ZCHAR) { - v = checkIncDec(event, abs(v), 0, ZCHAR_MAX, 0); - if (c <= 0) v = -v; - } - else { - v = checkIncDec(event, abs(v), '0', 'z', 0); - } + if (c == '\0') + c = ' '; + char v; + if (IS_NEXT_EVENT(event)) { + v = getNextChar(c, cur); + } + else if (IS_PREVIOUS_EVENT(event)) { + v = getPreviousChar(c, cur); + } + else { + v = c; } switch (event) { @@ -164,11 +199,13 @@ void editName(coord_t x, coord_t y, char * name, uint8_t size, event_t event, ui #if defined(NAVIGATION_XLITE) || defined(NAVIGATION_9X) case EVT_KEY_BREAK(KEY_LEFT): - if (cur>0) cur--; + if (cur > 0) + cur--; break; case EVT_KEY_BREAK(KEY_RIGHT): - if (cur= -26 && v <= 26) { - v = -v; // toggle case - } - } - else { #if !defined(NAVIGATION_XLITE) - if (v == ' ') { - s_editMode = 0; - killEvents(event); - break; - } - else -#endif - if (v >= 'A' && v <= 'Z') { - v = 'a' + v - 'A'; // toggle case - } - else if (v >= 'a' && v <= 'z') { - v = 'A' + v - 'a'; // toggle case - } + if (v == ' ') { + s_editMode = 0; + killEvents(event); + break; } + else +#endif + if (v >= 'A' && v <= 'Z') { + v = 'a' + v - 'A'; // toggle case + } + else if (v >= 'a' && v <= 'z') { + v = 'A' + v - 'a'; // toggle case + } + #if defined(NAVIGATION_9X) if (event==EVT_KEY_LONG(KEY_LEFT)) killEvents(KEY_LEFT); @@ -220,12 +245,7 @@ void editName(coord_t x, coord_t y, char * name, uint8_t size, event_t event, ui storageDirty(isModelMenuDisplayed() ? EE_MODEL : EE_GENERAL); } - if (attr == ZCHAR) { - lcdDrawChar(x+editNameCursorPos*FW, y, zchar2char(v), ERASEBG|INVERS|FIXEDWIDTH); - } - else { - lcdDrawChar(x+editNameCursorPos*FW, y, v, ERASEBG|INVERS|FIXEDWIDTH); - } + lcdDrawChar(x+editNameCursorPos*FW, y, v, ERASEBG|INVERS|FIXEDWIDTH); } else { cur = 0; diff --git a/radio/src/gui/common/stdlcd/draw_functions.h b/radio/src/gui/common/stdlcd/draw_functions.h index a3b237126..5cbc9c271 100644 --- a/radio/src/gui/common/stdlcd/draw_functions.h +++ b/radio/src/gui/common/stdlcd/draw_functions.h @@ -25,7 +25,7 @@ void lcdDrawMultiProtocolString(coord_t x, coord_t y, uint8_t moduleIdx, uint8_t protocol, LcdFlags flags = 0); void lcdDrawMultiSubProtocolString(coord_t x, coord_t y, uint8_t moduleIdx, uint8_t subType, LcdFlags flags = 0); void drawStringWithIndex(coord_t x, coord_t y, const char * str, uint8_t idx, LcdFlags att=0); -void drawValueWithUnit(coord_t x, coord_t y, int val, uint8_t unit, LcdFlags att=0); +void drawValueWithUnit(coord_t x, coord_t y, int32_t val, uint8_t unit, LcdFlags att=0); void drawPower(coord_t x, coord_t y, int8_t dBm, LcdFlags att = 0); void drawGVarName(coord_t x, coord_t y, int8_t index, LcdFlags flags=0); diff --git a/radio/src/gui/common/stdlcd/model_curves.cpp b/radio/src/gui/common/stdlcd/model_curves.cpp index 70a7ef68a..659e8beae 100644 --- a/radio/src/gui/common/stdlcd/model_curves.cpp +++ b/radio/src/gui/common/stdlcd/model_curves.cpp @@ -61,7 +61,7 @@ void menuModelCurvesAll(event_t event) #endif case EVT_KEY_FIRST(KEY_ENTER): if (CURVE_SELECTED() && !READ_ONLY()) { - s_curveChan = sub; + s_currIdxSubMenu = sub; pushMenu(menuModelCurveOne); } break; @@ -94,7 +94,7 @@ void menuModelCurvesAll(event_t event) } if (CURVE_SELECTED()) { - s_curveChan = sub; + s_currIdxSubMenu = sub; #if LCD_W >= 212 drawCurve(23); #else @@ -143,7 +143,7 @@ void editCurveRef(coord_t x, coord_t y, CurveRef & curve, event_t event, LcdFlag drawCurveName(x, y, curve.value, flags); if (active && menuHorizontalPosition==1) { if (event==EVT_KEY_LONG(KEY_ENTER) && curve.value!=0) { - s_curveChan = (curve.value<0 ? -curve.value-1 : curve.value-1); + s_currIdxSubMenu = (curve.value<0 ? -curve.value-1 : curve.value-1); pushMenu(menuModelCurveOne); } else { diff --git a/radio/src/gui/common/stdlcd/popups.cpp b/radio/src/gui/common/stdlcd/popups.cpp index 37707b560..7a7fbe633 100644 --- a/radio/src/gui/common/stdlcd/popups.cpp +++ b/radio/src/gui/common/stdlcd/popups.cpp @@ -227,7 +227,7 @@ void showAlertBox(const char * title, const char * text, const char * action , u lcdRefresh(); lcdSetContrast(); waitKeysReleased(); - backlightOn(); + resetBacklightTimeout(); checkBacklight(); } diff --git a/radio/src/gui/common/stdlcd/popups.h b/radio/src/gui/common/stdlcd/popups.h index 2aea293d6..4b3b54823 100644 --- a/radio/src/gui/common/stdlcd/popups.h +++ b/radio/src/gui/common/stdlcd/popups.h @@ -107,7 +107,7 @@ enum { warningText = message; warningInfoText = info; - warningInfoLength = strlen(info); + warningInfoLength = info ? strlen(info) : 0; warningInfoFlags = 0; warningType = WARNING_TYPE_ASTERISK; popupFunc = runPopupWarning; diff --git a/radio/src/gui/common/stdlcd/radio_hardware.cpp b/radio/src/gui/common/stdlcd/radio_hardware.cpp index 5dd184322..ddeccb348 100644 --- a/radio/src/gui/common/stdlcd/radio_hardware.cpp +++ b/radio/src/gui/common/stdlcd/radio_hardware.cpp @@ -624,22 +624,23 @@ void menuRadioHardware(event_t event) break; case ITEM_RADIO_HARDWARE_RAS: -#if defined(PCBX9LITE) && !defined(PCBX9LITES) - lcdDrawTextAlignedLeft(y, "Ext. RAS"); - lcdNextPos = HW_SETTINGS_COLUMN2; -#else +#if defined(HARDWARE_INTERNAL_RAS) lcdDrawTextAlignedLeft(y, "RAS"); if (telemetryData.swrInternal.isFresh()) lcdDrawNumber(HW_SETTINGS_COLUMN2, y, telemetryData.swrInternal.value()); else lcdDrawText(HW_SETTINGS_COLUMN2, y, "---"); lcdDrawText(lcdNextPos, y, "/"); +#else + lcdDrawTextAlignedLeft(y, "Ext. RAS"); + lcdNextPos = HW_SETTINGS_COLUMN2; #endif if (telemetryData.swrExternal.isFresh()) lcdDrawNumber(lcdNextPos, y, telemetryData.swrExternal.value()); else lcdDrawText(lcdNextPos, y, "---"); break; + #if defined(SPORT_UPDATE_PWR_GPIO) case ITEM_RADIO_HARDWARE_SPORT_UPDATE_POWER: g_eeGeneral.sportUpdatePower = editChoice(HW_SETTINGS_COLUMN2, y, STR_SPORT_UPDATE_POWER_MODE, STR_SPORT_UPDATE_POWER_MODES, g_eeGeneral.sportUpdatePower, 0, 1, attr, event); diff --git a/radio/src/gui/common/stdlcd/radio_sdmanager.cpp b/radio/src/gui/common/stdlcd/radio_sdmanager.cpp index 637715d56..ffbede8e0 100644 --- a/radio/src/gui/common/stdlcd/radio_sdmanager.cpp +++ b/radio/src/gui/common/stdlcd/radio_sdmanager.cpp @@ -291,12 +291,14 @@ void menuRadioSdManager(event_t _event) int lastPos = menuVerticalPosition; #endif - if (moduleState[reusableBuffer.sdManager.otaUpdateInformation.module].mode == MODULE_MODE_BIND && EVT_KEY_MASK(_event) == KEY_EXIT) { +#if defined(PXX2) + if (EVT_KEY_MASK(_event) == KEY_EXIT && moduleState[reusableBuffer.sdManager.otaUpdateInformation.module].mode == MODULE_MODE_BIND) { moduleState[reusableBuffer.sdManager.otaUpdateInformation.module].mode = MODULE_MODE_NORMAL; CLEAR_POPUP(); killEvents(KEY_EXIT); _event = 0; } +#endif event_t event = (EVT_KEY_MASK(_event) == KEY_ENTER ? 0 : _event); SIMPLE_MENU(SD_IS_HC() ? STR_SDHC_CARD : STR_SD_CARD, menuTabGeneral, MENU_RADIO_SD_MANAGER, HEADER_LINE + reusableBuffer.sdManager.count); @@ -304,13 +306,13 @@ void menuRadioSdManager(event_t _event) switch (_event) { case EVT_ENTRY: f_chdir(ROOT_PATH); - REFRESH_FILES(); #if LCD_DEPTH > 1 lastPos = -1; #endif - break; + // no break case EVT_ENTRY_UP: + memclear(&reusableBuffer.sdManager, sizeof(reusableBuffer.sdManager)); REFRESH_FILES(); break; @@ -579,7 +581,7 @@ void menuRadioSdManager(event_t _event) if (reusableBuffer.sdManager.otaUpdateInformation.candidateReceiversCount > 0) { if (reusableBuffer.sdManager.otaUpdateInformation.candidateReceiversCount != popupMenuItemsCount) { CLEAR_POPUP(); - popupMenuItemsCount = min(reusableBuffer.sdManager.otaUpdateInformation.candidateReceiversCount,PXX2_MAX_RECEIVERS_PER_MODULE); + popupMenuItemsCount = min(reusableBuffer.sdManager.otaUpdateInformation.candidateReceiversCount, PXX2_MAX_RECEIVERS_PER_MODULE); for (auto rx = 0; rx < popupMenuItemsCount; rx++) { popupMenuItems[rx] = reusableBuffer.sdManager.otaUpdateInformation.candidateReceiversNames[rx]; } diff --git a/radio/src/gui/common/stdlcd/view_telemetry.cpp b/radio/src/gui/common/stdlcd/view_telemetry.cpp index e2bf39503..61b506269 100644 --- a/radio/src/gui/common/stdlcd/view_telemetry.cpp +++ b/radio/src/gui/common/stdlcd/view_telemetry.cpp @@ -92,7 +92,7 @@ void menuViewTelemetry(event_t event) } drawTelemetryTopBar(); - lcdDrawText(LCD_W / 2, 3 * FH, "No Telemetry Screens", CENTERED); + lcdDrawText(LCD_W / 2, 3 * FH, STR_NO_TELEMETRY_SCREENS, CENTERED); displayRssiLine(); } diff --git a/radio/src/gui/gui_common.cpp b/radio/src/gui/gui_common.cpp index 77b24eb3b..62bbd952d 100644 --- a/radio/src/gui/gui_common.cpp +++ b/radio/src/gui/gui_common.cpp @@ -752,16 +752,12 @@ bool isTrainerModeAvailable(int mode) return g_eeGeneral.auxSerialMode == UART_MODE_SBUS_TRAINER; #endif -#if defined(HARDWARE_TRAINER_BLUETOOTH) - case TRAINER_MODE_MASTER_BLUETOOTH: - case TRAINER_MODE_SLAVE_BLUETOOTH: - return g_eeGeneral.bluetoothMode == BLUETOOTH_TRAINER; -#endif - -#if defined(HARDWARE_TRAINER_JACK) - case TRAINER_MODE_MASTER_TRAINER_JACK: - case TRAINER_MODE_SLAVE: - return true; +#if defined(BLUETOOTH) && !defined(PCBX9E) + if (g_eeGeneral.bluetoothMode != BLUETOOTH_TRAINER && (mode == TRAINER_MODE_MASTER_BLUETOOTH || mode == TRAINER_MODE_SLAVE_BLUETOOTH)) + return false; +#elif !defined(PCBSKY9X) + if (mode == TRAINER_MODE_MASTER_BLUETOOTH || mode == TRAINER_MODE_SLAVE_BLUETOOTH) + return false; #endif #if defined(HARDWARE_TRAINER_MULTI) @@ -813,7 +809,7 @@ int getFirstAvailable(int min, int max, IsValueAvailable isValueAvailable) #if defined(MULTIMODULE) // This maps OpenTX multi type with Pascal's Multi type -uint8_t convertMultiProtocol(uint8_t moduleIdx, uint8_t type) +uint8_t multiConvertOtxToMulti(uint8_t moduleIdx, uint8_t type) { // 15 for Multimodule is FrskyX or D16 which we map as a subprotocol of 3 (FrSky) @@ -827,7 +823,7 @@ uint8_t convertMultiProtocol(uint8_t moduleIdx, uint8_t type) if (type == MODULE_SUBTYPE_MULTI_FRSKY) { int subtype = g_model.moduleData[moduleIdx].subType; - if (subtype == MM_RF_FRSKY_SUBTYPE_D8) { + if (subtype == MM_RF_FRSKY_SUBTYPE_D8 || subtype == MM_RF_FRSKY_SUBTYPE_D8_CLONED) { //D8 type = 3; } @@ -842,6 +838,27 @@ uint8_t convertMultiProtocol(uint8_t moduleIdx, uint8_t type) return type; } +// This maps multi type to OpenTX number, type ONLY (no subtype) +int convertMultiToOtx(int type) +{ + if (type == 3) //FrSkyD + return MODULE_SUBTYPE_MULTI_FRSKY; + + if (type == 15) //FrSkyX + return MODULE_SUBTYPE_MULTI_FRSKY; + + if (type == 25) //FrSkyV + return MODULE_SUBTYPE_MULTI_FRSKY; + + if (type > 25) + type = type - 1; + + if (type > 15) + type = type - 1; + + return type - 1; //Multi list starts at 1 +} + // Third row is number of subtypes -1 (max valid subtype) #define NO_SUBTYPE nullptr @@ -855,7 +872,7 @@ uint8_t convertMultiProtocol(uint8_t moduleIdx, uint8_t type) const char STR_SUBTYPE_FLYSKY[] = "\004""Std\0""V9x9""V6x6""V912""CX20"; const char STR_SUBTYPE_HUBSAN[] = "\004""H107""H301""H501"; -const char STR_SUBTYPE_FRSKY[] = "\007""D16\0 ""D8\0 ""D16 8ch""V8\0 ""LBT(EU)""LBT 8ch"; +const char STR_SUBTYPE_FRSKY[] = "\011""D16\0 ""D8\0 ""D16 8ch\0 ""V8\0 ""LBT(EU)\0 ""LBT 8ch\0 ""D8Cloned\0""D16Cloned"; const char STR_SUBTYPE_HISKY[] = "\005""Std\0 ""HK310"; const char STR_SUBTYPE_V2X2[] = "\006""Std\0 ""JXD506"; const char STR_SUBTYPE_DSM[] = "\006""2 22ms""2 11ms""X 22ms""X 11ms"; @@ -867,6 +884,7 @@ const char STR_SUBTYPE_SLT[] = "\006""V1_6ch""V2_8ch""Q100\0 ""Q200\0 ""M const char STR_SUBTYPE_CX10[] = "\007""Green\0 ""Blue\0 ""DM007\0 ""-\0 ""JC3015a""JC3015b""MK33041"; const char STR_SUBTYPE_CG023[] = "\005""Std\0 ""YD829"; const char STR_SUBTYPE_BAYANG[] = "\007""Std\0 ""H8S3D\0 ""X16 AH\0""IRDrone""DHD D4"; +const char STR_SUBTYPE_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"; @@ -876,19 +894,29 @@ 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"; const char STR_SUBTYPE_CABELL[] = "\007""V3\0 ""V3 Telm""-\0 ""-\0 ""-\0 ""-\0 ""F-Safe\0""Unbind\0"; +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_BUGS_MINI[] = "\006""Std\0 ""Bugs3H"; const char STR_SUBTYPE_TRAXXAS[] = "\004""6519"; const char STR_SUBTYPE_E01X[] = "\005""E012\0""E015\0""E016H"; +const char STR_SUBTYPE_V911S[] = "\004""Std\0""E119"; const char STR_SUBTYPE_GD00X[] = "\005""GD_V1""GD_V2"; const char STR_SUBTYPE_REDPINE[] = "\004""Fast""Slow"; const char STR_SUBTYPE_POTENSIC[] = "\003""A20"; const char STR_SUBTYPE_ZSX[] = "\007""280JJRC"; const char STR_SUBTYPE_FLYZONE[] = "\005""FZ410"; +const char STR_SUBTYPE_FRSKYX_RX[] = "\007""RX\0 ""CloneTX"; const char STR_SUBTYPE_FX816[] = "\003""P38"; -const char STR_SUBTYPE_ESKY150[] = "\003""4CH""7CH"; +const char STR_SUBTYPE_XK[] = "\004""X450""X420"; +const char STR_SUBTYPE_XN297DUMP[] = "\004""250K""1M\0 ""2M\0 ""AUTO"; +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_PROPEL[] = "\004""74-Z"; +const char STR_SUBTYPE_FRSKYL[] = "\010""LR12\0 ""LR12 6ch"; +const char STR_SUBTYPE_ESKY150V2[] = "\006""150 V2"; const char* mm_options_strings::options[] = { nullptr, @@ -906,7 +934,7 @@ 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}, {MODULE_SUBTYPE_MULTI_HUBSAN, 2, false, false, STR_SUBTYPE_HUBSAN, STR_MULTI_VIDFREQ}, - {MODULE_SUBTYPE_MULTI_FRSKY, 5, false, false, STR_SUBTYPE_FRSKY, STR_MULTI_RFTUNE}, + {MODULE_SUBTYPE_MULTI_FRSKY, 7, false, false, STR_SUBTYPE_FRSKY, STR_MULTI_RFTUNE}, {MODULE_SUBTYPE_MULTI_HISKY, 1, false, true, STR_SUBTYPE_HISKY, nullptr}, {MODULE_SUBTYPE_MULTI_V2X2, 1, false, false, STR_SUBTYPE_V2X2, nullptr}, {MODULE_SUBTYPE_MULTI_DSM2, 3, false, true, STR_SUBTYPE_DSM, STR_MULTI_MAX_THROW}, @@ -914,14 +942,16 @@ const mm_protocol_definition multi_protocols[] = { {MODULE_SUBTYPE_MULTI_YD717, 4, false, false, STR_SUBTYPE_YD717, nullptr}, {MODULE_SUBTYPE_MULTI_KN, 1, false, false, STR_SUBTYPE_KN, nullptr}, {MODULE_SUBTYPE_MULTI_SYMAX, 1, false, false, STR_SUBTYPE_SYMAX, nullptr}, - {MODULE_SUBTYPE_MULTI_SLT, 4, false, true, STR_SUBTYPE_SLT, nullptr}, + {MODULE_SUBTYPE_MULTI_SLT, 4, false, true, STR_SUBTYPE_SLT, STR_MULTI_RFTUNE}, {MODULE_SUBTYPE_MULTI_CX10, 6, false, false, STR_SUBTYPE_CX10, nullptr}, {MODULE_SUBTYPE_MULTI_CG023, 1, false, false, STR_SUBTYPE_CG023, nullptr}, {MODULE_SUBTYPE_MULTI_BAYANG, 4, false, false, STR_SUBTYPE_BAYANG, STR_MULTI_TELEMETRY}, + {MODULE_SUBTYPE_MULTI_ESky, 1, false, true, STR_SUBTYPE_ESky, nullptr}, {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_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_RF_POWER}, {MODULE_SUBTYPE_MULTI_FS_AFHDS2A, 3, true, true, STR_SUBTYPE_AFHDS2A, STR_MULTI_SERVOFREQ}, @@ -929,24 +959,32 @@ const mm_protocol_definition multi_protocols[] = { {MODULE_SUBTYPE_MULTI_WK_2X01, 5, false, true, STR_SUBTYPE_WK2x01, nullptr}, {MODULE_SUBTYPE_MULTI_Q303, 3, false, false, STR_SUBTYPE_Q303, nullptr}, {MODULE_SUBTYPE_MULTI_CABELL, 7, false, false, STR_SUBTYPE_CABELL, STR_MULTI_OPTION}, + {MODULE_SUBTYPE_MULTI_ESKY150, 1, false, false, STR_SUBTYPE_ESKY150, nullptr}, {MODULE_SUBTYPE_MULTI_H83D, 3, false, false, STR_SUBTYPE_H83D, nullptr}, {MODULE_SUBTYPE_MULTI_CORONA, 2, false, false, STR_SUBTYPE_CORONA, STR_MULTI_RFTUNE}, {MODULE_SUBTYPE_MULTI_HITEC, 2, false, false, STR_SUBTYPE_HITEC, STR_MULTI_RFTUNE}, + {MODULE_SUBTYPE_MULTI_WFLY, 0, false, false, STR_SUBTYPE_WFLY, nullptr}, {MODULE_SUBTYPE_MULTI_BUGS_MINI, 1, false, false, STR_SUBTYPE_BUGS_MINI, nullptr}, {MODULE_SUBTYPE_MULTI_TRAXXAS, 0, false, false, STR_SUBTYPE_TRAXXAS, nullptr}, {MODULE_SUBTYPE_MULTI_E01X, 2, false, false, STR_SUBTYPE_E01X, STR_MULTI_OPTION}, + {MODULE_SUBTYPE_MULTI_V911S, 1, false, false, STR_SUBTYPE_V911S, STR_MULTI_RFTUNE}, {MODULE_SUBTYPE_MULTI_GD00X, 1, false, false, STR_SUBTYPE_GD00X, STR_MULTI_RFTUNE}, {MODULE_SUBTYPE_MULTI_KF606, 0, false, false, NO_SUBTYPE, STR_MULTI_RFTUNE}, {MODULE_SUBTYPE_MULTI_REDPINE, 1, false, false, STR_SUBTYPE_REDPINE, STR_MULTI_RFTUNE}, {MODULE_SUBTYPE_MULTI_POTENSIC, 0, false, false, STR_SUBTYPE_POTENSIC, nullptr}, {MODULE_SUBTYPE_MULTI_ZSX, 0, false, false, STR_SUBTYPE_ZSX, nullptr}, {MODULE_SUBTYPE_MULTI_FLYZONE, 0, false, false, STR_SUBTYPE_FLYZONE, nullptr}, - {MODULE_SUBTYPE_MULTI_FRSKYX_RX, 0, false, false, NO_SUBTYPE, STR_MULTI_RFTUNE}, - {MODULE_SUBTYPE_MULTI_ESky, 0, false, true, NO_SUBTYPE, nullptr}, - {MODULE_SUBTYPE_MULTI_J6PRO, 0, false, true, NO_SUBTYPE, nullptr}, - {MODULE_SUBTYPE_MULTI_ESKY150, 1, false, false, STR_SUBTYPE_ESKY150, nullptr}, - {MODULE_SUBTYPE_MULTI_FX816, 0, false, false, STR_SUBTYPE_FX816, nullptr}, + {MODULE_SUBTYPE_MULTI_FRSKYX_RX, 1, false, false, STR_SUBTYPE_FRSKYX_RX, STR_MULTI_RFTUNE}, {MODULE_SUBTYPE_MULTI_HOTT, 0, true, false, NO_SUBTYPE, STR_MULTI_RFTUNE}, + {MODULE_SUBTYPE_MULTI_FX816, 0, false, false, STR_SUBTYPE_FX816, nullptr}, + {MODULE_SUBTYPE_MULTI_XK, 1, false, false, STR_SUBTYPE_XK, STR_MULTI_RFTUNE}, + {MODULE_SUBTYPE_MULTI_XN297DUMP, 3, 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_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}, {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) diff --git a/radio/src/gui/gui_common.h b/radio/src/gui/gui_common.h index 30662c056..597dd5ce7 100644 --- a/radio/src/gui/gui_common.h +++ b/radio/src/gui/gui_common.h @@ -137,6 +137,8 @@ void drawSensorCustomValue(coord_t x, coord_t y, uint8_t sensor, int32_t value, void drawSourceCustomValue(coord_t x, coord_t y, source_t channel, int32_t val, LcdFlags flags=0); void drawSourceValue(coord_t x, coord_t y, source_t channel, LcdFlags flags=0); +int convertMultiToOtx(int type); + void drawCurve(coord_t offset=0); // model_setup Defines that are used in all uis in the same way @@ -145,7 +147,7 @@ void drawCurve(coord_t offset=0); inline uint8_t MODULE_BIND_ROWS(int moduleIdx) { - if (isModuleXJTD8(moduleIdx) || isModuleSBUS(moduleIdx)) + if (isModuleXJTD8(moduleIdx) || isModuleSBUS(moduleIdx) || IS_RX_MULTI(moduleIdx)) return 1; if (isModulePPM(moduleIdx) || isModulePXX1(moduleIdx) || isModulePXX2(moduleIdx) || isModuleDSM2(moduleIdx) || isModuleMultimodule(moduleIdx)) @@ -156,7 +158,7 @@ inline uint8_t MODULE_BIND_ROWS(int moduleIdx) inline uint8_t MODULE_CHANNELS_ROWS(int moduleIdx) { - if (!IS_MODULE_ENABLED(moduleIdx)) + if (!IS_MODULE_ENABLED(moduleIdx) || IS_RX_MULTI(moduleIdx)) return HIDDEN_ROW; if (isModuleDSM2(moduleIdx) || isModuleCrossfire(moduleIdx) || isModuleSBUS(moduleIdx) || (isModuleMultimodule(moduleIdx) && g_model.moduleData[moduleIdx].getMultiProtocol() != MODULE_SUBTYPE_MULTI_DSM2)) @@ -256,12 +258,14 @@ inline uint8_t MULTIMODULE_HASOPTIONS(uint8_t moduleIdx) return false; } -#define MULTIMODULE_MODULE_ROWS(moduleIdx) MULTIMODULE_PROTOCOL_KNOWN(moduleIdx) ? (uint8_t) 0 : HIDDEN_ROW, MULTIMODULE_PROTOCOL_KNOWN(moduleIdx) ? (uint8_t) 0 : HIDDEN_ROW, MULTI_DISABLE_CHAN_MAP_ROW(moduleIdx), // AUTOBIND, DISABLE TELEM, DISABLE CN.MAP +#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_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, #define MULTIMODULE_OPTIONS_ROW(moduleIdx) (isModuleMultimodule(moduleIdx) && MULTIMODULE_HASOPTIONS(moduleIdx)) ? (uint8_t) 0: HIDDEN_ROW -#define MODULE_POWER_ROW(moduleIdx) (MULTIMODULE_PROTOCOL_KNOWN(moduleIdx) || isModuleR9MNonAccess(moduleIdx)) ? (isModuleR9MLiteNonPro(moduleIdx) ? (isModuleR9M_FCC_VARIANT(moduleIdx) ? READONLY_ROW : (uint8_t)0) : (uint8_t)0) : HIDDEN_ROW +#define MODULE_POWER_ROW(moduleIdx) (MULTIMODULE_PROTOCOL_KNOWN(moduleIdx) || isModuleR9MNonAccess(moduleIdx)) ? (isModuleR9MLiteNonPro(moduleIdx) ? (isModuleR9M_FCC_VARIANT(moduleIdx) ? READONLY_ROW : (uint8_t)0) : (uint8_t)0) : HIDDEN_ROW #else #define MULTIMODULE_STATUS_ROWS(moduleIdx) diff --git a/radio/src/gui/navigation/navigation_horus.cpp b/radio/src/gui/navigation/navigation_horus.cpp index b8729c8a3..d62d07810 100644 --- a/radio/src/gui/navigation/navigation_horus.cpp +++ b/radio/src/gui/navigation/navigation_horus.cpp @@ -316,9 +316,9 @@ bool check(event_t event, uint8_t curr, const MenuHandlerFunc * menuTab, uint8_t if (menuTab && !menuCalibrationState) { int cc = curr; switch (event) { -#if defined(PCBX12S) +#if defined(KEYS_GPIO_REG_PGUP) case EVT_KEY_FIRST(KEY_PGDN): -#elif defined(PCBX10) +#else case EVT_KEY_BREAK(KEY_PGDN): #endif if (s_editMode>0) @@ -328,8 +328,9 @@ bool check(event_t event, uint8_t curr, const MenuHandlerFunc * menuTab, uint8_t cc = 0; break; +#if defined(KEYS_GPIO_REG_PGUP) case EVT_KEY_FIRST(KEY_PGUP): -#if defined(PCBX10) +#else case EVT_KEY_LONG(KEY_PGDN): #endif if (s_editMode>0) diff --git a/radio/src/io/frsky_firmware_update.h b/radio/src/io/frsky_firmware_update.h index 42996d46f..16b99e224 100644 --- a/radio/src/io/frsky_firmware_update.h +++ b/radio/src/io/frsky_firmware_update.h @@ -45,30 +45,52 @@ enum FrskyFirmwareModuleProductId { enum FrskyFirmwareReceiverProductId { FIRMWARE_ID_RECEIVER_NONE, - FIRMWARE_ID_RECEIVER_ARCHER = 0xC0, // TODO use the right constant - FIRMWARE_ID_RECEIVER_R9MX = 0xF0, // TODO use the right constant - // TODO fill the table - + FIRMWARE_ID_RECEIVER_X8R = 0x01, + FIRMWARE_ID_RECEIVER_RX8R = 0x02, + FIRMWARE_ID_RECEIVER_RX8R_PRO = 0x03, + FIRMWARE_ID_RECEIVER_RX6R = 0x04, + FIRMWARE_ID_RECEIVER_RX4R = 0x05, + FIRMWARE_ID_RECEIVER_G_RX8 = 0x06, + FIRMWARE_ID_RECEIVER_G_RX6 = 0x07, + FIRMWARE_ID_RECEIVER_X6R = 0x08, + FIRMWARE_ID_RECEIVER_X4R = 0x09, + FIRMWARE_ID_RECEIVER_X4R_SB = 0x0A, + FIRMWARE_ID_RECEIVER_XSR = 0x0B, + FIRMWARE_ID_RECEIVER_XSR_M = 0x0C, + FIRMWARE_ID_RECEIVER_RXSR = 0x0D, + FIRMWARE_ID_RECEIVER_S6R = 0x0E, + FIRMWARE_ID_RECEIVER_S8R = 0x0F, + FIRMWARE_ID_RECEIVER_XM = 0x10, + FIRMWARE_ID_RECEIVER_XMP = 0x11, + FIRMWARE_ID_RECEIVER_XMR = 0x12, + FIRMWARE_ID_RECEIVER_R9 = 0x13, + FIRMWARE_ID_RECEIVER_R9_SLIM = 0x14, + FIRMWARE_ID_RECEIVER_R9_SLIMP = 0x15, + FIRMWARE_ID_RECEIVER_R9_MINI = 0x16, + FIRMWARE_ID_RECEIVER_R9_MM = 0x17, + FIRMWARE_ID_RECEIVER_R9_STAB = 0x18, // R9_STAB has OTA + FIRMWARE_ID_RECEIVER_R9_MINI_OTA = 0x19, // this one has OTA (different bootloader) + FIRMWARE_ID_RECEIVER_R9_MM_OTA = 0x1A, // this one has OTA (different bootloader) + FIRMWARE_ID_RECEIVER_R9_SLIMP_OTA = 0x1B, // this one has OTA (different bootloader) + FIRMWARE_ID_RECEIVER_ARCHER_X = 0x1C, // this one has OTA (internal module) + FIRMWARE_ID_RECEIVER_R9MX = 0x1D, // this one has OTA + FIRMWARE_ID_RECEIVER_R9SX = 0x1E, // this one has OTA }; inline bool isReceiverOTAEnabledFromModule(uint8_t moduleIdx, uint8_t productId) { switch (productId) { - case FIRMWARE_ID_RECEIVER_ARCHER: + case FIRMWARE_ID_RECEIVER_ARCHER_X: return isModuleISRM(moduleIdx); + case FIRMWARE_ID_RECEIVER_R9_STAB: + case FIRMWARE_ID_RECEIVER_R9_MINI_OTA: + case FIRMWARE_ID_RECEIVER_R9_MM_OTA: + case FIRMWARE_ID_RECEIVER_R9_SLIMP_OTA: case FIRMWARE_ID_RECEIVER_R9MX: + case FIRMWARE_ID_RECEIVER_R9SX: return isModuleR9M(moduleIdx); - // TODO add all those OTA receivers here - -/* - "R9-MINI-OTA", // this one has OTA (different bootloader) - "R9-MM-OTA", // this one has OTA (different bootloader) - "R9-SLIM+-OTA", // this one has OTA (different bootloader) - "R9SX", // this one has OTA - */ - default: return false; } diff --git a/radio/src/io/multi_firmware_update.h b/radio/src/io/multi_firmware_update.h index 5d467451d..100b9012d 100644 --- a/radio/src/io/multi_firmware_update.h +++ b/radio/src/io/multi_firmware_update.h @@ -71,7 +71,7 @@ class MultiFirmwareInformation { bool isMultiInternalFirmware() const { - return (boardType == FIRMWARE_MULTI_STM && telemetryInversion == false && optibootSupport == true && bootloaderCheck == true && telemetryType == FIRMWARE_MULTI_TELEM_MULTI_TELEMETRY); + return (boardType == FIRMWARE_MULTI_STM && optibootSupport == true && bootloaderCheck == true && telemetryType == FIRMWARE_MULTI_TELEM_MULTI_TELEMETRY); } bool isMultiExternalFirmware() const diff --git a/radio/src/logs.cpp b/radio/src/logs.cpp index 693ac7ef8..13f6f4a3a 100644 --- a/radio/src/logs.cpp +++ b/radio/src/logs.cpp @@ -71,9 +71,7 @@ const char * logsOpen() if (!len && filename[i]) len = i+1; if (len) { - if (filename[i]) - filename[i] = zchar2char(filename[i]); - else + if (!filename[i]) filename[i] = '_'; } i--; diff --git a/radio/src/lua/api_general.cpp b/radio/src/lua/api_general.cpp index 1439ec8cb..a2556453e 100644 --- a/radio/src/lua/api_general.cpp +++ b/radio/src/lua/api_general.cpp @@ -66,6 +66,10 @@ { "EVT_"#xxx"_LONG", EVT_KEY_LONG(yyy) }, \ { "EVT_"#xxx"_REPT", EVT_KEY_REPT(yyy) } +#if defined(LUA) && !defined(CLI) +Fifo * luaRxFifo = nullptr; +#endif + /*luadoc @function getVersion() @@ -694,7 +698,8 @@ The list of valid sources is available: |----------------|-------| | 2.0 | [all](http://downloads-20.open-tx.org/firmware/lua_fields.txt) | | 2.1 | [X9D and X9D+](http://downloads-21.open-tx.org/firmware/lua_fields_taranis.txt), [X9E](http://downloads-21.open-tx.org/firmware/lua_fields_taranis_x9e.txt) | -| 2.2 | [X9D and X9D+](http://downloads.open-tx.org/2.2/firmware/lua_fields_x9d.txt), [X9E](http://downloads.open-tx.org/2.2/firmware/lua_fields_x9e.txt), [Horus](http://downloads.open-tx.org/2.2/firmware/lua_fields_x12s.txt) | +| 2.2 | [X9D and X9D+](http://downloads.open-tx.org/2.2/release/firmware/lua_fields_x9d.txt), [X9E](http://downloads.open-tx.org/2.2/release/firmware/lua_fields_x9e.txt), [Horus](http://downloads.open-tx.org/2.2/release/firmware/lua_fields_x12s.txt) | +| 2.3 | [X9D and X9D+](http://downloads.open-tx.org/2.3/release/firmware/lua_fields_x9d.txt), [X9E](http://downloads.open-tx.org/2.3/release/firmware/lua_fields_x9e.txt), [X7](http://downloads.open-tx.org/2.3/release/firmware/lua_fields_x7.txt), [Horus](http://downloads.open-tx.org/2.3/release/firmware/lua_fields_x12s.txt) | @param name (string) name of the field @@ -741,8 +746,8 @@ The list of fixed sources: |----------------|-------| | 2.0 | [all](http://downloads-20.open-tx.org/firmware/lua_fields.txt) | | 2.1 | [X9D and X9D+](http://downloads-21.open-tx.org/firmware/lua_fields_taranis.txt), [X9E](http://downloads-21.open-tx.org/firmware/lua_fields_taranis_x9e.txt) | -| 2.2 | [X9D and X9D+](http://downloads.open-tx.org/2.2/firmware/lua_fields_x9d.txt), [X9E](http://downloads.open-tx.org/2.2/firmware/lua_fields_x9e.txt), [Horus](http://downloads.open-tx.org/2.2/firmware/lua_fields_x12s.txt) | - +| 2.2 | [X9D and X9D+](http://downloads.open-tx.org/2.2/release/firmware/lua_fields_x9d.txt), [X9E](http://downloads.open-tx.org/2.2/release/firmware/lua_fields_x9e.txt), [Horus](http://downloads.open-tx.org/2.2/release/firmware/lua_fields_x12s.txt) | +| 2.3 | [X9D and X9D+](http://downloads.open-tx.org/2.3/release/firmware/lua_fields_x9d.txt), [X9E](http://downloads.open-tx.org/2.3/release/firmware/lua_fields_x9e.txt), [X7](http://downloads.open-tx.org/2.3/release/firmware/lua_fields_x7.txt), [Horus](http://downloads.open-tx.org/2.3/release/firmware/lua_fields_x12s.txt) | In OpenTX 2.1.x the telemetry sources no longer have a predefined name. To get a telemetry value simply use it's sensor name. For example: @@ -1206,11 +1211,14 @@ static int luaPopupWarning(lua_State * L) } /*luadoc -@function popupConfirmation(title, event) +@function popupConfirmation(title, event) deprecated, please replace by +@function popupConfirmation(title, message, event) Raises a pop-up on screen that asks for confirmation -@param title (string) text to display +@param title (string) title to display + +@param message (string) text to display @param event (number) the event variable that is passed in from the Run function (key pressed) @@ -1219,13 +1227,24 @@ Run function (key pressed) @notice Use only from stand-alone and telemetry scripts. -@status current Introduced in 2.2.0 +@status current Introduced in 2.2.0, changed to (title, message, event) in 2.3.8 */ static int luaPopupConfirmation(lua_State * L) { - event_t event = luaL_checkinteger(L, 2); - warningText = luaL_checkstring(L, 1); warningType = WARNING_TYPE_CONFIRM; + event_t event; + + if (lua_isnone(L, 3)) { + // only two args: deprecated mode + warningText = luaL_checkstring(L, 1); + event = luaL_checkinteger(L, 2); + } + else { + warningText = luaL_checkstring(L, 1); + warningInfoText = luaL_checkstring(L, 2); + event = luaL_optinteger(L, 3, 0); + } + runPopupWarning(event); if (!warningText) { lua_pushstring(L, warningResult ? "OK" : "CANCEL"); @@ -1586,6 +1605,13 @@ static int luaSerialWrite(lua_State * L) while(wr_len--) auxSerialPutc(*p++); } #endif +#if defined(AUX2_SERIAL) + if (aux2SerialMode == UART_MODE_LUA) { + size_t wr_len = len; + const char* p = str; + while(wr_len--) aux2SerialPutc(*p++); + } +#endif #else debugPrintf("luaSerialWrite: %.*s",len,str); #endif @@ -1593,6 +1619,58 @@ static int luaSerialWrite(lua_State * L) return 0; } +/*luadoc +@function serialRead([num]) +@param num (optional): maximum number of bytes to read. + If non-zero, serialRead will read up to num characters from the buffer. + If 0 or left out, serialRead will read up to and including the first newline character or the end of the buffer. + Note that the returned string may not end in a newline if this character is not present in the buffer. + +@retval str string. Empty if no new characters were available. + +Reads characters from the serial port. The string is allowed to contain any character, including 0. + +@status current Introduced in 2.3.8 +*/ +static int luaSerialRead(lua_State * L) +{ +#if defined(LUA) && !defined(CLI) + int num = luaL_optunsigned(L, 1, 0); + + if (!luaRxFifo) { + luaRxFifo = new Fifo(); + if (!luaRxFifo) { + lua_pushlstring(L, "", 0); + return 1; + } + } + uint8_t str[LUA_FIFO_SIZE]; + uint8_t *p = str; + while (luaRxFifo->pop(*p)) { + p++; // increment only when pop was successful + if (p - str >= LUA_FIFO_SIZE) { + // buffer full + break; + } + if (num == 0) { + if (*(p - 1) == '\n' || *(p - 1) == '\r') { + // found newline + break; + } + } + else if (p - str >= num) { + // requested number of characters reached + break; + } + } + lua_pushlstring(L, (const char*)str, p - str); +#else + lua_pushlstring(L, "", 0); +#endif + + return 1; +} + const luaL_Reg opentxLib[] = { { "getTime", luaGetTime }, { "getDateTime", luaGetDateTime }, @@ -1640,6 +1718,7 @@ const luaL_Reg opentxLib[] = { { "multiBuffer", luaMultiBuffer }, #endif { "serialWrite", luaSerialWrite }, + { "serialRead", luaSerialRead }, { nullptr, nullptr } /* sentinel */ }; @@ -1649,6 +1728,9 @@ const luaR_value_entry opentxConstants[] = { { "DBLSIZE", DBLSIZE }, { "MIDSIZE", MIDSIZE }, { "SMLSIZE", SMLSIZE }, +#if defined(COLORLCD) + { "TINSIZE", TINSIZE }, +#endif { "INVERS", INVERS }, { "BOLD", BOLD }, { "BLINK", BLINK }, @@ -1790,9 +1872,7 @@ const luaR_value_entry opentxConstants[] = { { "EVT_VIRTUAL_EXIT", EVT_KEY_BREAK(KEY_EXIT) }, #endif -#if defined(KEYS_GPIO_REG_EXIT) { "EVT_EXIT_BREAK", EVT_KEY_BREAK(KEY_EXIT) }, -#endif #if defined(KEYS_GPIO_REG_ENTER) KEY_EVENTS(ENTER, KEY_ENTER), @@ -1875,8 +1955,6 @@ const luaR_value_entry opentxConstants[] = { { "PLAY_BACKGROUND", PLAY_BACKGROUND }, { "TIMEHOUR", TIMEHOUR }, -#if defined(PCBHORUS) - // Adding the unit consts for the set Telemetry function adds about 1k of flash usage {"UNIT_RAW", UNIT_RAW }, {"UNIT_VOLTS", UNIT_VOLTS }, {"UNIT_AMPS", UNIT_AMPS }, @@ -1910,6 +1988,6 @@ const luaR_value_entry opentxConstants[] = { {"UNIT_GPS", UNIT_GPS}, {"UNIT_BITFIELD", UNIT_BITFIELD}, {"UNIT_TEXT", UNIT_TEXT}, -#endif + { nullptr, 0 } /* sentinel */ }; diff --git a/radio/src/lua/api_lcd.cpp b/radio/src/lua/api_lcd.cpp index 020b41c7b..d9c1078ac 100644 --- a/radio/src/lua/api_lcd.cpp +++ b/radio/src/lua/api_lcd.cpp @@ -62,6 +62,20 @@ static int luaLcdClear(lua_State *L) return 0; } +/*luadoc +@function lcd.resetBacklightTimeout() + +Reset the backlight timeout + +@status current Introduced in 2.3.6 +*/ +static int luaLcdResetBacklightTimeout(lua_State * L) +{ + if (!luaLcdAllowed) return 0; + resetBacklightTimeout(); + return 0; +} + /*luadoc @function lcd.drawPoint(x, y) @@ -861,6 +875,7 @@ static int luaRGB(lua_State *L) const luaL_Reg lcdLib[] = { { "refresh", luaLcdRefresh }, { "clear", luaLcdClear }, + { "resetBacklightTimeout", luaLcdResetBacklightTimeout }, { "drawPoint", luaLcdDrawPoint }, { "drawLine", luaLcdDrawLine }, { "drawRectangle", luaLcdDrawRectangle }, diff --git a/radio/src/lua/api_model.cpp b/radio/src/lua/api_model.cpp index 3cc4ee98b..d2d5f767a 100644 --- a/radio/src/lua/api_model.cpp +++ b/radio/src/lua/api_model.cpp @@ -86,7 +86,24 @@ static int luaModelSetInfo(lua_State *L) Get RF module parameters -`subType` values: +`Type` values: + * 0 NONE + * 1 PPM + * 2 XJT_PXX1 + * 3 ISRM_PXX2 + * 4 DSM2 + * 5 CROSSFIRE + * 6 MULTIMODULE + * 7 R9M_PXX1 + * 8 R9M_PXX2 + * 9 R9M_LITE_PXX1 + * 10 R9M_LITE_PXX2 + * 11 R9M_LITE_PRO_PXX1 + * 12 R9M_LITE_PRO_PXX2 + * 13 SBUS + * 14 XJT_LITE_PXX2 + +`subType` values for XJT_PXX1: * -1 OFF * 0 D16 * 1 D8 @@ -101,6 +118,11 @@ Get RF module parameters * `modelId` (number) receiver number * `firstChannel` (number) start channel (0 is CH1) * `channelsCount` (number) number of channels sent to module + * `Type` (number) module type + * if the module type is Multi additional information are available + * `protocol` (number) protocol number + * `subProtocol` (number) sub-protocol number + * `channelsOrder` (number) first 4 channels expected order @status current Introduced in TODO */ @@ -114,6 +136,25 @@ static int luaModelGetModule(lua_State *L) 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, "Type", module.type); +#if defined(MULTIMODULE) + if (module.type == MODULE_TYPE_MULTIMODULE) { + int protocol = g_model.moduleData[idx].getMultiProtocol() + 1; + int subprotocol = g_model.moduleData[idx].subType; + convertOtxProtocolToMulti(&protocol, &subprotocol); // Special treatment for the FrSky entry... + lua_pushtableinteger(L, "protocol", protocol); + lua_pushtableinteger(L, "subProtocol", subprotocol); + if (getMultiModuleStatus(idx).isValid()) { + if (getMultiModuleStatus(idx).ch_order == 0xFF) + lua_pushtableinteger(L, "channelsOrder", -1); + else + lua_pushtableinteger(L, "channelsOrder", getMultiModuleStatus(idx).ch_order); + } + else { + lua_pushtableinteger(L, "channelsOrder", -1); + } + } +#endif } else { lua_pushnil(L); diff --git a/radio/src/lua/lua_api.h b/radio/src/lua/lua_api.h index 71a1cef01..53ef9df04 100644 --- a/radio/src/lua/lua_api.h +++ b/radio/src/lua/lua_api.h @@ -41,6 +41,11 @@ extern "C" { #endif #endif +#if !defined(CLI) || defined(AUX2_SERIAL) +#define LUA_FIFO_SIZE 256 +extern Fifo * luaRxFifo; +#endif + extern lua_State * lsScripts; extern lua_State * lsWidgets; extern bool luaLcdAllowed; diff --git a/radio/src/mixer.cpp b/radio/src/mixer.cpp index 2b72c57e8..85e9c4b96 100644 --- a/radio/src/mixer.cpp +++ b/radio/src/mixer.cpp @@ -457,7 +457,7 @@ void evalInputs(uint8_t mode) if (mode == e_perout_mode_normal) { if (tmp==0 || (tmp==1 && (bpanaCenter & mask))) { anaCenter |= mask; - if ((g_model.beepANACenter & mask) && !(bpanaCenter & mask) && !menuCalibrationState) { + if ((g_model.beepANACenter & mask) && !(bpanaCenter & mask) && s_mixer_first_run_done && !menuCalibrationState) { if (!IS_POT(i) || IS_POT_SLIDER_AVAILABLE(i)) { AUDIO_POT_MIDDLE(i); } @@ -893,9 +893,7 @@ void evalMixes(uint8_t tick10ms) static uint16_t fp_act[MAX_FLIGHT_MODES] = {0}; static uint16_t delta = 0; - static ACTIVE_PHASES_TYPE flightModesFade = 0; - - LS_RECURSIVE_EVALUATION_RESET(); + static uint16_t flightModesFade = 0; uint8_t fm = getFlightMode(); @@ -907,7 +905,7 @@ void evalMixes(uint8_t tick10ms) } else { uint8_t fadeTime = max(g_model.flightModeData[lastFlightMode].fadeOut, g_model.flightModeData[fm].fadeIn); - ACTIVE_PHASES_TYPE transitionMask = ((ACTIVE_PHASES_TYPE)1 << lastFlightMode) + ((ACTIVE_PHASES_TYPE)1 << fm); + uint16_t transitionMask = (0x01u << lastFlightMode) + (0x01u << fm); if (fadeTime) { flightModesFade |= transitionMask; delta = (MAX_ACT / 10) / fadeTime; @@ -937,15 +935,13 @@ void evalMixes(uint8_t tick10ms) if (flightModesFade) { memclear(sum_chans512, sizeof(sum_chans512)); for (uint8_t p=0; p> 4) * fp_act[p]; weight += fp_act[p]; } - LS_RECURSIVE_EVALUATION_RESET(); } assert(weight); mixerCurrentFlightMode = fm; @@ -986,7 +982,7 @@ void evalMixes(uint8_t tick10ms) if (tick10ms && flightModesFade) { uint16_t tick_delta = delta * tick10ms; for (uint8_t p=0; p tick_delta) diff --git a/radio/src/opentx.cpp b/radio/src/opentx.cpp index cfaa469b0..9f40813bc 100644 --- a/radio/src/opentx.cpp +++ b/radio/src/opentx.cpp @@ -303,9 +303,7 @@ void generalDefault() g_eeGeneral.stickMode = DEFAULT_MODE - 1; #endif -#if defined(FRSKY_RELEASE) - g_eeGeneral.templateSetup = 17; /* TAER */ -#endif + g_eeGeneral.templateSetup = DEFAULT_TEMPLATE_SETUP; g_eeGeneral.backlightMode = e_backlight_mode_all; g_eeGeneral.lightAutoOff = 2; @@ -510,11 +508,7 @@ void modelDefault(uint8_t id) } #endif -#if !defined(EEPROM) - strcpy(g_model.header.name, "Model"); - g_model.header.name[5] = '0' + id / 10; - g_model.header.name[6] = '0' + id % 10; -#endif + strAppendUnsigned(strAppend(g_model.header.name, STR_MODEL), id + 1, 2); #if defined(COLORLCD) extern const LayoutFactory * defaultLayout; @@ -696,7 +690,7 @@ void checkBacklight() if (inputsMoved()) { inactivity.counter = 0; if (g_eeGeneral.backlightMode & e_backlight_mode_sticks) { - backlightOn(); + resetBacklightTimeout(); } } @@ -709,7 +703,7 @@ void checkBacklight() } } -void backlightOn() +void resetBacklightTimeout() { lightOffCounter = ((uint16_t)g_eeGeneral.lightAutoOff*250) << 1; } @@ -736,7 +730,7 @@ void doSplash() #endif if (SPLASH_NEEDED()) { - backlightOn(); + resetBacklightTimeout(); drawSplash(); #if defined(PCBSKY9X) @@ -1999,6 +1993,10 @@ void opentxInit() auxSerialInit(g_eeGeneral.auxSerialMode, modelTelemetryProtocol()); #endif +#if defined(AUX2_SERIAL) + aux2SerialInit(g_eeGeneral.aux2SerialMode, modelTelemetryProtocol()); +#endif + #if MENUS_LOCK == 1 getMovedSwitch(); if (TRIMS_PRESSED() && g_eeGeneral.switchUnlockStates==switches_states) { @@ -2034,7 +2032,7 @@ void opentxInit() if (g_eeGeneral.backlightMode != e_backlight_mode_off) { // on Tx start turn the light on - backlightOn(); + resetBacklightTimeout(); } if (!globalData.unexpectedShutdown) { @@ -2052,7 +2050,7 @@ void opentxInit() lcdSetContrast(); #endif - backlightOn(); + resetBacklightTimeout(); startPulses(); diff --git a/radio/src/opentx.h b/radio/src/opentx.h index 1847e4a72..c328ac390 100644 --- a/radio/src/opentx.h +++ b/radio/src/opentx.h @@ -21,11 +21,7 @@ #ifndef _OPENTX_H_ #define _OPENTX_H_ -#include -#include -#include #include -#include #include "definitions.h" #include "opentx_types.h" #include "debounce.h" @@ -434,7 +430,6 @@ char char2lower(char c); int8_t char2zchar(char c); void str2zchar(char *dest, const char *src, int size); int zchar2str(char *dest, const char *src, int size); -bool cmpStrWithZchar(const char * charString, const char * zcharString, int size); #include "keys.h" #include "pwr.h" @@ -519,7 +514,6 @@ void logicalSwitchesReset(); void evalLogicalSwitches(bool isCurrentFlightmode=true); void logicalSwitchesCopyState(uint8_t src, uint8_t dst); -#define LS_RECURSIVE_EVALUATION_RESET() #if defined(PCBFRSKY) || defined(PCBFLYSKY) void getSwitchesPosition(bool startup); @@ -564,34 +558,8 @@ bool setTrimValue(uint8_t phase, uint8_t idx, int trim); #include "gvars.h" -extern uint16_t sessionTimer; -extern uint16_t s_timeCumThr; -extern uint16_t s_timeCum16ThrP; - -#if defined(OVERRIDE_CHANNEL_FUNCTION) -#define OVERRIDE_CHANNEL_UNDEFINED -4096 -extern safetych_t safetyCh[MAX_OUTPUT_CHANNELS]; -#endif - -extern uint8_t trimsCheckTimer; -extern uint8_t trimsDisplayTimer; -extern uint8_t trimsDisplayMask; - void flightReset(uint8_t check=true); -PACK(struct GlobalData { - uint8_t unexpectedShutdown:1; - uint8_t externalAntennaEnabled:1; - uint8_t authenticationCount:2; - uint8_t upgradeModulePopup:1; - uint8_t internalModuleVersionChecked:1; - uint8_t spare:2; -}); - -extern GlobalData globalData; - -extern uint16_t maxMixerDuration; - #define DURATION_MS_PREC2(x) ((x)/20) #if defined(THRTRACE) @@ -652,7 +620,7 @@ static inline void GET_ADC_IF_MIXER_NOT_RUNNING() #include "sbus.h" -void backlightOn(); +void resetBacklightTimeout(); void checkBacklight(); uint16_t isqrt32(uint32_t n); @@ -733,14 +701,9 @@ extern const char vers_stamp[]; const char * getOtherVersion(char * buffer); #define g_blinkTmr10ms (*(uint8_t*)&g_tmr10ms) -extern uint8_t g_beepCnt; #include "trainer.h" -extern int32_t chans[MAX_OUTPUT_CHANNELS]; -extern int16_t ex_chans[MAX_OUTPUT_CHANNELS]; // Outputs (before LIMITS) of the last perMain -extern int16_t channelOutputs[MAX_OUTPUT_CHANNELS]; - int expo(int x, int k); inline void getMixSrcRange(const int source, int16_t & valMin, int16_t & valMax, LcdFlags * flags = 0) @@ -813,33 +776,15 @@ int16_t applyLimits(uint8_t channel, int32_t value); void evalInputs(uint8_t mode); uint16_t anaIn(uint8_t chan); -extern int16_t calibratedAnalogs[NUM_CALIBRATED_ANALOGS]; - #define FLASH_DURATION 20 /*200ms*/ -extern uint8_t beepAgain; -extern uint16_t lightOffCounter; -extern uint8_t flashCounter; -extern uint8_t mixWarning; - FlightModeData * flightModeAddress(uint8_t idx); ExpoData * expoAddress(uint8_t idx); MixData * mixAddress(uint8_t idx); LimitData * limitAddress(uint8_t idx); LogicalSwitchData * lswAddress(uint8_t idx); -// static variables used in evalFlightModeMixes - moved here so they don't interfere with the stack -// It's also easier to initialize them here. -extern int8_t virtualInputsTrims[MAX_INPUTS]; - -extern int16_t anas [MAX_INPUTS]; -extern int16_t trims[NUM_TRIMS]; -extern BeepANACenter bpanaCenter; - -extern uint8_t s_mixer_first_run_done; - void applyDefaultTemplate(); - void instantTrim(); void evalTrims(); void copyTrimsToOffset(uint8_t ch); @@ -847,20 +792,6 @@ void copySticksToOffset(uint8_t ch); void copyMinMaxToOutputs(uint8_t ch); void moveTrimsToOffsets(); -typedef uint16_t ACTIVE_PHASES_TYPE; -#define DELAY_POS_MARGIN 3 -typedef int16_t delayval_t; -PACK(struct SwOn { - uint16_t delay:14; // max = 2550 - uint8_t activeMix:1; - uint8_t activeExpo:1; - int16_t now; // timer trigger source -> off, abs, stk, stk%, sw/!sw, !m_sw/!m_sw - int16_t prev; -}); - -extern SwOn swOn[MAX_MIXERS]; -extern int32_t act[MAX_MIXERS]; - inline bool isExpoActive(uint8_t expo) { return swOn[expo].activeExpo; @@ -1028,15 +959,6 @@ void setMFP(); void clearMFP(); #endif -extern uint8_t requiredSpeakerVolume; - -enum MainRequest { - REQUEST_SCREENSHOT, - REQUEST_FLIGHT_RESET, -}; - -extern uint8_t mainRequestFlags; - void checkBattery(); void opentxClose(uint8_t shutdown=true); void opentxInit(); diff --git a/radio/src/options.h b/radio/src/options.h index 2afb1596b..e8bf634c1 100644 --- a/radio/src/options.h +++ b/radio/src/options.h @@ -53,6 +53,9 @@ static const char * options[] = { #if defined(HORUS_STICKS) "horussticks", #endif +#if defined(INTERNAL_GPS) + "internalgps", +#endif #if defined(INTERNAL_MODULE_PPM) "internalppm", #endif diff --git a/radio/src/pulses/modules_constants.h b/radio/src/pulses/modules_constants.h index 3ac04aae7..32f7fe4cc 100644 --- a/radio/src/pulses/modules_constants.h +++ b/radio/src/pulses/modules_constants.h @@ -103,62 +103,75 @@ enum ModuleSubtypeR9M { enum ModuleSubtypeMulti { MODULE_SUBTYPE_MULTI_FIRST = 0, MODULE_SUBTYPE_MULTI_FLYSKY = MODULE_SUBTYPE_MULTI_FIRST, - MODULE_SUBTYPE_MULTI_HUBSAN, - MODULE_SUBTYPE_MULTI_FRSKY, - MODULE_SUBTYPE_MULTI_HISKY, - MODULE_SUBTYPE_MULTI_V2X2, - MODULE_SUBTYPE_MULTI_DSM2, + MODULE_SUBTYPE_MULTI_HUBSAN, //1 + MODULE_SUBTYPE_MULTI_FRSKY, //2 + MODULE_SUBTYPE_MULTI_HISKY, //3 + MODULE_SUBTYPE_MULTI_V2X2, //4 + MODULE_SUBTYPE_MULTI_DSM2, //5 MODULE_SUBTYPE_MULTI_DEVO, MODULE_SUBTYPE_MULTI_YD717, MODULE_SUBTYPE_MULTI_KN, MODULE_SUBTYPE_MULTI_SYMAX, - MODULE_SUBTYPE_MULTI_SLT, + MODULE_SUBTYPE_MULTI_SLT, //10 MODULE_SUBTYPE_MULTI_CX10, MODULE_SUBTYPE_MULTI_CG023, MODULE_SUBTYPE_MULTI_BAYANG, MODULE_SUBTYPE_MULTI_ESky, - MODULE_SUBTYPE_MULTI_MT99XX, + MODULE_SUBTYPE_MULTI_MT99XX, //15 MODULE_SUBTYPE_MULTI_MJXQ, MODULE_SUBTYPE_MULTI_SHENQI, MODULE_SUBTYPE_MULTI_FY326, MODULE_SUBTYPE_MULTI_SFHSS, - MODULE_SUBTYPE_MULTI_J6PRO, + MODULE_SUBTYPE_MULTI_J6PRO, //20 MODULE_SUBTYPE_MULTI_FQ777, MODULE_SUBTYPE_MULTI_ASSAN, MODULE_SUBTYPE_MULTI_HONTAI, MODULE_SUBTYPE_MULTI_OLRS, - MODULE_SUBTYPE_MULTI_FS_AFHDS2A, + MODULE_SUBTYPE_MULTI_FS_AFHDS2A, //25 MODULE_SUBTYPE_MULTI_Q2X2, MODULE_SUBTYPE_MULTI_WK_2X01, MODULE_SUBTYPE_MULTI_Q303, MODULE_SUBTYPE_MULTI_GW008, - MODULE_SUBTYPE_MULTI_DM002, + MODULE_SUBTYPE_MULTI_DM002, //30 MODULE_SUBTYPE_MULTI_CABELL, MODULE_SUBTYPE_MULTI_ESKY150, MODULE_SUBTYPE_MULTI_H83D, MODULE_SUBTYPE_MULTI_CORONA, - MODULE_SUBTYPE_MULTI_CFLIE, + MODULE_SUBTYPE_MULTI_CFLIE, //35 MODULE_SUBTYPE_MULTI_HITEC, MODULE_SUBTYPE_MULTI_WFLY, MODULE_SUBTYPE_MULTI_BUGS, MODULE_SUBTYPE_MULTI_BUGS_MINI, - MODULE_SUBTYPE_MULTI_TRAXXAS, + MODULE_SUBTYPE_MULTI_TRAXXAS, //40 MODULE_SUBTYPE_MULTI_NCC1701, MODULE_SUBTYPE_MULTI_E01X, MODULE_SUBTYPE_MULTI_V911S, MODULE_SUBTYPE_MULTI_GD00X, - MODULE_SUBTYPE_MULTI_V761, + MODULE_SUBTYPE_MULTI_V761, //45 MODULE_SUBTYPE_MULTI_KF606, MODULE_SUBTYPE_MULTI_REDPINE, MODULE_SUBTYPE_MULTI_POTENSIC, MODULE_SUBTYPE_MULTI_ZSX, - MODULE_SUBTYPE_MULTI_FLYZONE, + MODULE_SUBTYPE_MULTI_FLYZONE, //50 MODULE_SUBTYPE_MULTI_SCANNER, MODULE_SUBTYPE_MULTI_FRSKYX_RX, MODULE_SUBTYPE_MULTI_AFHDS2A_RX, MODULE_SUBTYPE_MULTI_HOTT, - MODULE_SUBTYPE_MULTI_FX816, - MODULE_SUBTYPE_MULTI_LAST = MODULE_SUBTYPE_MULTI_FX816 + MODULE_SUBTYPE_MULTI_FX816, //55 + MODULE_SUBTYPE_MULTI_BAYANG_RX, + MODULE_SUBTYPE_MULTI_PELIKAN, + MODULE_SUBTYPE_MULTI_TIGER, + MODULE_SUBTYPE_MULTI_XK, + MODULE_SUBTYPE_MULTI_XN297DUMP, //60 + MODULE_SUBTYPE_MULTI_FRSKYX2, + MODULE_SUBTYPE_MULTI_FRSKY_R9, + MODULE_SUBTYPE_MULTI_PROPEL, + MODULE_SUBTYPE_MULTI_FRSKYL, + MODULE_SUBTYPE_MULTI_SKYARTEC, + MODULE_SUBTYPE_MULTI_ESKY150V2, + MODULE_SUBTYPE_MULTI_DSM_RX, + MODULE_SUBTYPE_MULTI_JJRC345, + MODULE_SUBTYPE_MULTI_LAST = MODULE_SUBTYPE_MULTI_JJRC345 }; #define MODULE_SUBTYPE_MULTI_XN297DP 63-3 @@ -176,7 +189,9 @@ enum MMRFrskySubtypes { MM_RF_FRSKY_SUBTYPE_D16_8CH, MM_RF_FRSKY_SUBTYPE_V8, MM_RF_FRSKY_SUBTYPE_D16_LBT, - MM_RF_FRSKY_SUBTYPE_D16_LBT_8CH + MM_RF_FRSKY_SUBTYPE_D16_LBT_8CH, + MM_RF_FRSKY_SUBTYPE_D8_CLONED, + MM_RF_FRSKY_SUBTYPE_D16_CLONED }; enum ModuleSubtypeDSM2 { diff --git a/radio/src/pulses/modules_helpers.h b/radio/src/pulses/modules_helpers.h index 4038ab9a1..71d135078 100644 --- a/radio/src/pulses/modules_helpers.h +++ b/radio/src/pulses/modules_helpers.h @@ -26,6 +26,7 @@ #include "opentx_helpers.h" #include "telemetry/telemetry.h" #include "storage/storage.h" +#include "globals.h" #if defined(MULTIMODULE) #include "telemetry/multi.h" @@ -57,7 +58,7 @@ inline uint8_t getMaxMultiSubtype(uint8_t moduleIdx) const mm_protocol_definition *pdef = getMultiProtocolDefinition(g_model.moduleData[moduleIdx].getMultiProtocol()); if (g_model.moduleData[moduleIdx].getMultiProtocol() == MODULE_SUBTYPE_MULTI_FRSKY) { - return 5; + return 7; } if (g_model.moduleData[moduleIdx].getMultiProtocol() > MODULE_SUBTYPE_MULTI_LAST) { @@ -584,6 +585,14 @@ inline void setDefaultPpmFrameLength(uint8_t moduleIdx) g_model.moduleData[moduleIdx].ppm.frameLength = 4 * max(0, g_model.moduleData[moduleIdx].channelsCount); } +inline void resetAccessAuthenticationCount() +{ +#if defined(ACCESS_LIB) + // the module will reset on mode switch, we need to reset the authentication counter + globalData.authenticationCount = 0; +#endif +} + inline void setModuleType(uint8_t moduleIdx, uint8_t moduleType) { ModuleData & moduleData = g_model.moduleData[moduleIdx]; @@ -594,6 +603,8 @@ inline void setModuleType(uint8_t moduleIdx, uint8_t moduleType) moduleData.sbus.refreshRate = -31; else if (moduleData.type == MODULE_TYPE_PPM) setDefaultPpmFrameLength(moduleIdx); + else + resetAccessAuthenticationCount(); } extern bool isExternalAntennaEnabled(); diff --git a/radio/src/pulses/multi.cpp b/radio/src/pulses/multi.cpp index 936da0948..9fe10113c 100644 --- a/radio/src/pulses/multi.cpp +++ b/radio/src/pulses/multi.cpp @@ -244,6 +244,50 @@ void sendChannels(uint8_t moduleIdx) } } +void convertOtxProtocolToMulti(int *protocol, int *subprotocol) +{ + // Special treatment for the FrSky entry... + if (*protocol == MODULE_SUBTYPE_MULTI_FRSKY +1) { + if (*subprotocol == MM_RF_FRSKY_SUBTYPE_D8) { + //D8 + *protocol = 3; + *subprotocol = 0; + } + else if (*subprotocol == MM_RF_FRSKY_SUBTYPE_D8_CLONED) { + //D8 + *protocol = 3; + *subprotocol = 1; + } + else if (*subprotocol == MM_RF_FRSKY_SUBTYPE_V8) { + //V8 + *protocol = 25; + *subprotocol = 0; + } + else { + *protocol = 15; + if (*subprotocol == MM_RF_FRSKY_SUBTYPE_D16_8CH) + *subprotocol = 1; + else if (*subprotocol == MM_RF_FRSKY_SUBTYPE_D16) + *subprotocol = 0; // D16 + else if (*subprotocol == MM_RF_FRSKY_SUBTYPE_D16_LBT) + *subprotocol = 2; + else if (*subprotocol == MM_RF_FRSKY_SUBTYPE_D16_LBT_8CH) + *subprotocol = 3; + else + *subprotocol = 4; // D16_CLONED + } + } + else { + // 15 for Multimodule is FrskyX or D16 which we map as a protocol of 3 (FrSky) + // all protos > frskyx are therefore also off by one + if (*protocol >= 15) + *protocol = *protocol + 1; + // 25 is again a FrSky *protocol (FrskyV) so shift again + if (*protocol >= 25) + *protocol = *protocol + 1; + } +} + void sendFrameProtocolHeader(uint8_t moduleIdx, bool failsafe) {// byte 1+2, protocol information @@ -268,8 +312,7 @@ void sendFrameProtocolHeader(uint8_t moduleIdx, bool failsafe) protoByte |= MULTI_SEND_RANGECHECK; // rfProtocol - if (g_model.moduleData[moduleIdx].getMultiProtocol() == MODULE_SUBTYPE_MULTI_DSM2) { - + if (type == MODULE_SUBTYPE_MULTI_DSM2 +1 ) { // Autobinding should always be done in DSMX 11ms if (g_model.moduleData[moduleIdx].multi.autoBindMode && moduleState[moduleIdx].mode == MODULE_MODE_BIND) subtype = MM_RF_DSM2_SUBTYPE_AUTO; @@ -279,39 +322,11 @@ void sendFrameProtocolHeader(uint8_t moduleIdx, bool failsafe) optionValue = 0x80 | sentModuleChannels(moduleIdx); // Max throw else optionValue = sentModuleChannels(moduleIdx); -} - - // 15 for Multimodule is FrskyX or D16 which we map as a subprotocol of 3 (FrSky) - // all protos > frskyx are therefore also off by one - if (type >= 15) - type = type + 1; - - // 25 is again a FrSky protocol (FrskyV) so shift again - if (type >= 25) - type = type + 1; - - if (g_model.moduleData[moduleIdx].getMultiProtocol() == MODULE_SUBTYPE_MULTI_FRSKY) { - if (subtype == MM_RF_FRSKY_SUBTYPE_D8) { - //D8 - type = 3; - subtype = 0; - } else if (subtype == MM_RF_FRSKY_SUBTYPE_V8) { - //V8 - type = 25; - subtype = 0; - } else { - type = 15; - if (subtype == MM_RF_FRSKY_SUBTYPE_D16_8CH) // D16 8ch - subtype = 1; - else if (subtype == MM_RF_FRSKY_SUBTYPE_D16) - subtype = 0; // D16 - else if (subtype == MM_RF_FRSKY_SUBTYPE_D16_LBT) - subtype = 2; - else - subtype = 3; // MM_RF_FRSKY_SUBTYPE_D16_LBT_8CH - } } + // Special treatment for the FrSky entry... + convertOtxProtocolToMulti(&type, &subtype); + // Set the highest bit of option byte in AFHDS2A protocol to instruct MULTI to passthrough telemetry bytes instead // of sending Frsky D telemetry if (g_model.moduleData[moduleIdx].getMultiProtocol() == MODULE_SUBTYPE_MULTI_FS_AFHDS2A) diff --git a/radio/src/pulses/multi.h b/radio/src/pulses/multi.h index a19e526eb..29e335d3a 100644 --- a/radio/src/pulses/multi.h +++ b/radio/src/pulses/multi.h @@ -24,6 +24,7 @@ #include "pulses_common.h" void multiPatchCustom(uint8_t moduleIdx); +void convertOtxProtocolToMulti(int *protocol, int *subprotocol); class UartMultiPulses: public DataBuffer { diff --git a/radio/src/pulses/pulses.cpp b/radio/src/pulses/pulses.cpp index 42f04fb26..afcbaa061 100755 --- a/radio/src/pulses/pulses.cpp +++ b/radio/src/pulses/pulses.cpp @@ -308,9 +308,7 @@ static void enablePulsesInternalModule(uint8_t protocol) #if defined(PXX2) case PROTOCOL_CHANNELS_PXX2_HIGHSPEED: intmoduleSerialStart(PXX2_HIGHSPEED_BAUDRATE, true, USART_Parity_No, USART_StopBits_1, USART_WordLength_8b); -#if defined(HARDWARE_INTERNAL_MODULE) && defined(INTERNAL_MODULE_PXX2) && defined(ACCESS_LIB) - globalData.authenticationCount = 0; -#endif + resetAccessAuthenticationCount(); break; #endif diff --git a/radio/src/pulses/pxx2.cpp b/radio/src/pulses/pxx2.cpp index a709f6352..2724def67 100644 --- a/radio/src/pulses/pxx2.cpp +++ b/radio/src/pulses/pxx2.cpp @@ -172,10 +172,10 @@ void Pxx2Pulses::setupRegisterFrame(uint8_t module) if (reusableBuffer.moduleSetup.pxx2.registerStep == REGISTER_RX_NAME_SELECTED) { Pxx2Transport::addByte(0x01); for (uint8_t i=0; i= menuVerticalOffset && current_line - menuVerticalOffset < int(NUM_BODY_LINES) && line_length < LCD_COLS) { + else if (c != '\r' && current_line >= menuVerticalOffset && current_line - menuVerticalOffset < int(TEXT_VIEWER_LINES) && line_length < LCD_COLS) { if (c == '\\' && escape == 0) { escape = 1; continue; @@ -386,15 +386,15 @@ void sdReadTextFile(const char * filename, char lines[NUM_BODY_LINES][LCD_COLS + else if (c != '\\' && escape > 0 && escape < sizeof(escape_chars)) { escape_chars[escape - 1] = c; if (escape == 2 && !strncmp(escape_chars, "up", 2)) { - c = '\300'; + c = CHAR_UP; } else if (escape == 2 && !strncmp(escape_chars, "dn", 2)) { - c = '\301'; + c = CHAR_DOWN; } else if (escape == 3) { int val = atoi(escape_chars); if (val >= 200 && val < 225) { - c = '\200' + val-200; + c = '\200' + val - 200; } } else { diff --git a/radio/src/serial.cpp b/radio/src/serial.cpp index 351f58502..ff89bb52f 100644 --- a/radio/src/serial.cpp +++ b/radio/src/serial.cpp @@ -34,6 +34,10 @@ void serialPutc(char c) { if (auxSerialTracesEnabled()) auxSerialPutc(c); #endif +#if defined(AUX2_SERIAL) + if (aux2SerialTracesEnabled()) + aux2SerialPutc(c); +#endif } void serialPrintf(const char * format, ...) diff --git a/radio/src/storage/conversions/conversions_218_219.cpp b/radio/src/storage/conversions/conversions_218_219.cpp index fa5ec608a..c47f7b738 100644 --- a/radio/src/storage/conversions/conversions_218_219.cpp +++ b/radio/src/storage/conversions/conversions_218_219.cpp @@ -401,7 +401,7 @@ void convertRadioData_218_to_219(RadioData & settings) #if defined(PCBHORUS) // 2 new pots from X10: // - copy btw. 'chkSum' and 'auxSerialMode' (excl.) - memcpy(&settings.chkSum, &oldSettings.chkSum, offsetof(RadioData, auxSerialMode) - offsetof(RadioData, chkSum)); + memcpy(&settings.chkSum, &oldSettings.chkSum, offsetof(RadioData, switchConfig) - sizeof(uint8_t) - offsetof(RadioData, chkSum)); // - move calibration data memcpy(&settings.calib[NUM_STICKS + 5], &oldSettings.calib[NUM_STICKS + 3], sizeof(CalibData) * (STORAGE_NUM_SLIDERS + STORAGE_NUM_MOUSE_ANALOGS)); memclear(&settings.calib[NUM_STICKS + 3], sizeof(CalibData) * 2); diff --git a/radio/src/storage/eeprom_rlc.cpp b/radio/src/storage/eeprom_rlc.cpp index 6ede67fc2..ff68681d2 100644 --- a/radio/src/storage/eeprom_rlc.cpp +++ b/radio/src/storage/eeprom_rlc.cpp @@ -465,13 +465,11 @@ const char * eeBackupModel(uint8_t i_fileSrc) uint8_t i = sizeof(MODELS_PATH)+sizeof(g_model.header.name)-1; uint8_t len = 0; - while (i>sizeof(MODELS_PATH)-1) { + while (i > sizeof(MODELS_PATH)-1) { if (!len && buf[i]) len = i+1; if (len) { - if (buf[i]) - buf[i] = zchar2char(buf[i]); - else + if (!buf[i]) buf[i] = '_'; } i--; diff --git a/radio/src/strhelpers.cpp b/radio/src/strhelpers.cpp index a19103968..5e7c1e39f 100644 --- a/radio/src/strhelpers.cpp +++ b/radio/src/strhelpers.cpp @@ -84,20 +84,10 @@ int zchar2str(char * dest, const char * src, int size) return size+1; } -bool cmpStrWithZchar(const char * charString, const char * zcharString, int size) -{ - for (int i=0; i 0) { - if (str[size-1] != ' ') + if (str[size-1] != ' ' && str[size-1] != '\0') return size; size--; } @@ -137,9 +127,7 @@ char * strcat_zchar(char * dest, const char * name, uint8_t size, const char * d if (!len && dest[i]) len = i+1; if (len) { - if (dest[i]) - dest[i] = zchar2char(dest[i]); - else + if (!dest[i]) dest[i] = '_'; } i--; @@ -392,7 +380,7 @@ char * getSourceString(char * dest, mixsrc_t idx) } else if (idx <= MIXSRC_LAST_INPUT) { idx -= MIXSRC_FIRST_INPUT; - *dest = '\314'; + *dest = CHAR_INPUT; if (strlen(g_model.inputNames[idx])) { memset(dest + 1, 0, LEN_INPUT_NAME); strncpy(dest + 1, g_model.inputNames[idx], LEN_INPUT_NAME); @@ -406,7 +394,7 @@ char * getSourceString(char * dest, mixsrc_t idx) #if defined(LUA_MODEL_SCRIPTS) div_t qr = div(idx-MIXSRC_FIRST_LUA, MAX_SCRIPT_OUTPUTS); if (qr.quot < MAX_SCRIPTS && qr.rem < scriptInputsOutputs[qr.quot].outputsCount) { - *dest++ = '\322'; + *dest++ = CHAR_LUA; // *dest++ = '1'+qr.quot; strcpy(dest, scriptInputsOutputs[qr.quot].outputs[qr.rem].name); } diff --git a/radio/src/switches.cpp b/radio/src/switches.cpp index 9614cd7d6..8657b9b8c 100644 --- a/radio/src/switches.cpp +++ b/radio/src/switches.cpp @@ -648,7 +648,7 @@ void checkSwitches() } LED_ERROR_BEGIN(); - backlightOn(); + resetBacklightTimeout(); // first - display warning #if defined(PCBSKY9X) diff --git a/radio/src/targets/common/arm/stm32/adc_driver.cpp b/radio/src/targets/common/arm/stm32/adc_driver.cpp index 3972ab86c..6360b9676 100644 --- a/radio/src/targets/common/arm/stm32/adc_driver.cpp +++ b/radio/src/targets/common/arm/stm32/adc_driver.cpp @@ -25,7 +25,7 @@ #elif defined(RADIO_T16) const int8_t adcDirection[NUM_ANALOGS] = {1,-1,1,-1, 1,1,1, -1,1, -1,1}; #elif defined(RADIO_TX16S) - const int8_t adcDirection[NUM_ANALOGS] = {-1,1,-1,1, 1,1,1, -1,1, -1,1}; + const int8_t adcDirection[NUM_ANALOGS] = {1,-1,1,-1, 1,1,1, -1,1, -1,1}; #elif defined(PCBX10) const int8_t adcDirection[NUM_ANALOGS] = {1,-1,1,-1, -1,1,-1, 1,1, 1, -1}; #elif defined(PCBX9E) 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 e36f435a2..973ce688e 100644 --- a/radio/src/targets/common/arm/stm32/aux_serial_driver.cpp +++ b/radio/src/targets/common/arm/stm32/aux_serial_driver.cpp @@ -122,26 +122,30 @@ void auxSerialInit(unsigned int mode, unsigned int protocol) #if defined(CROSSFIRE) if (protocol == PROTOCOL_TELEMETRY_CROSSFIRE) { auxSerialSetup(CROSSFIRE_TELEM_MIRROR_BAUDRATE, false); + AUX_SERIAL_POWER_OFF(); break; } #endif - auxSerialSetup(FRSKY_SPORT_BAUDRATE, false); + auxSerialSetup(FRSKY_TELEM_MIRROR_BAUDRATE, false); break; #if defined(DEBUG) || defined(CLI) case UART_MODE_DEBUG: auxSerialSetup(DEBUG_BAUDRATE, false); + AUX_SERIAL_POWER_OFF(); break; #endif case UART_MODE_TELEMETRY: if (protocol == PROTOCOL_TELEMETRY_FRSKY_D_SECONDARY) { auxSerialSetup(FRSKY_D_BAUDRATE, true); + AUX_SERIAL_POWER_OFF(); } break; case UART_MODE_LUA: auxSerialSetup(DEBUG_BAUDRATE, false); + AUX_SERIAL_POWER_ON(); } } @@ -214,5 +218,214 @@ extern "C" void AUX_SERIAL_USART_IRQHandler(void) status = AUX_SERIAL_USART->SR; } } +#endif + // Receive + uint32_t status = AUX_SERIAL_USART->SR; + while (status & (USART_FLAG_RXNE | USART_FLAG_ERRORS)) { + uint8_t data = AUX_SERIAL_USART->DR; + if (!(status & USART_FLAG_ERRORS)) { +#if defined(LUA) & !defined(CLI) + if (luaRxFifo && auxSerialMode == UART_MODE_LUA) + luaRxFifo->push(data); +#endif + } + status = AUX_SERIAL_USART->SR; + } #endif } +#endif + +#if defined(AUX2_SERIAL) +uint8_t aux2SerialMode = 0; +Fifo aux2SerialTxFifo; +AuxSerialRxFifo aux2SerialRxFifo __DMA (AUX2_SERIAL_DMA_Stream_RX); + +void aux2SerialSetup(unsigned int baudrate, bool dma) +{ + USART_InitTypeDef USART_InitStructure; + GPIO_InitTypeDef GPIO_InitStructure; + + GPIO_PinAFConfig(AUX2_SERIAL_GPIO, AUX2_SERIAL_GPIO_PinSource_RX, AUX2_SERIAL_GPIO_AF); + GPIO_PinAFConfig(AUX2_SERIAL_GPIO, AUX2_SERIAL_GPIO_PinSource_TX, AUX2_SERIAL_GPIO_AF); + + GPIO_InitStructure.GPIO_Pin = AUX2_SERIAL_GPIO_PIN_TX | AUX2_SERIAL_GPIO_PIN_RX; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; + GPIO_Init(AUX2_SERIAL_GPIO, &GPIO_InitStructure); + +#if defined(AUX2_SERIAL_PWR_GPIO) + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; + GPIO_InitStructure.GPIO_Pin = AUX2_SERIAL_PWR_GPIO_PIN; + GPIO_Init(AUX2_SERIAL_PWR_GPIO, &GPIO_InitStructure); +#endif + + USART_InitStructure.USART_BaudRate = baudrate; + USART_InitStructure.USART_WordLength = USART_WordLength_8b; + USART_InitStructure.USART_StopBits = USART_StopBits_1; + USART_InitStructure.USART_Parity = USART_Parity_No; + USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; + USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; + USART_Init(AUX2_SERIAL_USART, &USART_InitStructure); + + if (dma) { + DMA_InitTypeDef DMA_InitStructure; + aux2SerialRxFifo.clear(); + USART_ITConfig(AUX2_SERIAL_USART, USART_IT_RXNE, DISABLE); + USART_ITConfig(AUX2_SERIAL_USART, USART_IT_TXE, DISABLE); + DMA_InitStructure.DMA_Channel = AUX2_SERIAL_DMA_Channel_RX; + DMA_InitStructure.DMA_PeripheralBaseAddr = CONVERT_PTR_UINT(&AUX2_SERIAL_USART->DR); + DMA_InitStructure.DMA_Memory0BaseAddr = CONVERT_PTR_UINT(aux2SerialRxFifo.buffer()); + DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; + DMA_InitStructure.DMA_BufferSize = aux2SerialRxFifo.size(); + DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; + DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; + DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; + DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; + DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; + DMA_InitStructure.DMA_Priority = DMA_Priority_Low; + DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; + DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; + DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; + DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; + DMA_Init(AUX2_SERIAL_DMA_Stream_RX, &DMA_InitStructure); + USART_DMACmd(AUX2_SERIAL_USART, USART_DMAReq_Rx, ENABLE); + USART_Cmd(AUX2_SERIAL_USART, ENABLE); + DMA_Cmd(AUX2_SERIAL_DMA_Stream_RX, ENABLE); + } + else { + USART_Cmd(AUX2_SERIAL_USART, ENABLE); + USART_ITConfig(AUX2_SERIAL_USART, USART_IT_RXNE, ENABLE); + USART_ITConfig(AUX2_SERIAL_USART, USART_IT_TXE, DISABLE); + NVIC_SetPriority(AUX2_SERIAL_USART_IRQn, 7); + NVIC_EnableIRQ(AUX2_SERIAL_USART_IRQn); + } +} + +void aux2SerialInit(unsigned int mode, unsigned int protocol) +{ + aux2SerialStop(); + + aux2SerialMode = mode; + + switch (mode) { + case UART_MODE_TELEMETRY_MIRROR: +#if defined(CROSSFIRE) + if (protocol == PROTOCOL_TELEMETRY_CROSSFIRE) { + aux2SerialSetup(CROSSFIRE_TELEM_MIRROR_BAUDRATE, false); + AUX2_SERIAL_POWER_OFF(); + break; + } +#endif + aux2SerialSetup(FRSKY_TELEM_MIRROR_BAUDRATE, false); + AUX2_SERIAL_POWER_OFF(); + break; + +#if defined(DEBUG) || defined(CLI) + case UART_MODE_DEBUG: + aux2SerialSetup(DEBUG_BAUDRATE, false); + AUX2_SERIAL_POWER_OFF(); + break; +#endif + + case UART_MODE_TELEMETRY: + if (protocol == PROTOCOL_TELEMETRY_FRSKY_D_SECONDARY) { + aux2SerialSetup(FRSKY_D_BAUDRATE, true); + AUX2_SERIAL_POWER_OFF(); + } + break; + + case UART_MODE_LUA: + aux2SerialSetup(DEBUG_BAUDRATE, false); + AUX2_SERIAL_POWER_ON(); + } +} + +void aux2SerialPutc(char c) +{ +#if !defined(SIMU) + int n = 0; + while (aux2SerialTxFifo.isFull()) { + delay_ms(1); + if (++n > 100) return; + } + aux2SerialTxFifo.push(c); + USART_ITConfig(AUX2_SERIAL_USART, USART_IT_TXE, ENABLE); +#endif +} + +void aux2SerialSbusInit() +{ + aux2SerialSetup(SBUS_BAUDRATE, true); + AUX2_SERIAL_USART->CR1 |= USART_CR1_M | USART_CR1_PCE ; + AUX2_SERIAL_POWER_ON(); +} + +void aux2SerialStop() +{ + DMA_DeInit(AUX2_SERIAL_DMA_Stream_RX); + USART_DeInit(AUX2_SERIAL_USART); +} + +uint8_t aux2SerialTracesEnabled() +{ +#if defined(DEBUG) + return (aux2SerialMode == UART_MODE_DEBUG); +#else + return false; +#endif +} + +#if !defined(SIMU) +extern "C" void AUX2_SERIAL_USART_IRQHandler(void) +{ + DEBUG_INTERRUPT(INT_SER2); + // Send + if (USART_GetITStatus(AUX2_SERIAL_USART, USART_IT_TXE) != RESET) { + uint8_t txchar; + if (aux2SerialTxFifo.pop(txchar)) { + /* Write one byte to the transmit data register */ + USART_SendData(AUX2_SERIAL_USART, txchar); + } + else { + USART_ITConfig(AUX2_SERIAL_USART, USART_IT_TXE, DISABLE); + } + } + +#if defined(CLI) + if (getSelectedUsbMode() != USB_SERIAL_MODE) { + // Receive + uint32_t status = AUX2_SERIAL_USART->SR; + while (status & (USART_FLAG_RXNE | USART_FLAG_ERRORS)) { + uint8_t data = AUX2_SERIAL_USART->DR; + if (!(status & USART_FLAG_ERRORS)) { + switch (aux2SerialMode) { + case UART_MODE_DEBUG: + cliRxFifo.push(data); + break; + } + } + status = AUX2_SERIAL_USART->SR; + } + } +#endif +#if defined(AUX2_SERIAL) + // Receive + uint32_t status = AUX2_SERIAL_USART->SR; + while (status & (USART_FLAG_RXNE | USART_FLAG_ERRORS)) { + uint8_t data = AUX2_SERIAL_USART->DR; + if (!(status & USART_FLAG_ERRORS)) { +#if defined(LUA) + if (luaRxFifo && aux2SerialMode == UART_MODE_LUA) + luaRxFifo->push(data); +#endif + } + status = AUX2_SERIAL_USART->SR; + } +} +#endif + +#endif +#endif // AUX_SERIAL \ No newline at end of file diff --git a/radio/src/targets/common/arm/stm32/bootloader/boot.cpp b/radio/src/targets/common/arm/stm32/bootloader/boot.cpp index a2e4a4a1a..4e74cda70 100644 --- a/radio/src/targets/common/arm/stm32/bootloader/boot.cpp +++ b/radio/src/targets/common/arm/stm32/bootloader/boot.cpp @@ -197,15 +197,15 @@ int main() RCC_AHB1PeriphClockCmd(PWR_RCC_AHB1Periph | KEYS_RCC_AHB1Periph | LCD_RCC_AHB1Periph | BACKLIGHT_RCC_AHB1Periph | - AUX_SERIAL_RCC_AHB1Periph | I2C_RCC_AHB1Periph | + AUX_SERIAL_RCC_AHB1Periph | AUX2_SERIAL_RCC_AHB1Periph | I2C_RCC_AHB1Periph | SD_RCC_AHB1Periph, ENABLE); RCC_APB1PeriphClockCmd(ROTARY_ENCODER_RCC_APB1Periph | LCD_RCC_APB1Periph | BACKLIGHT_RCC_APB1Periph | INTERRUPT_xMS_RCC_APB1Periph | I2C_RCC_APB1Periph | - AUX_SERIAL_RCC_APB1Periph | + AUX_SERIAL_RCC_APB1Periph | AUX2_SERIAL_RCC_APB1Periph | SD_RCC_APB1Periph, ENABLE); - RCC_APB2PeriphClockCmd(LCD_RCC_APB2Periph | BACKLIGHT_RCC_APB2Periph | RCC_APB2Periph_SYSCFG | AUX_SERIAL_RCC_APB2Periph, ENABLE); + RCC_APB2PeriphClockCmd(LCD_RCC_APB2Periph | BACKLIGHT_RCC_APB2Periph | RCC_APB2Periph_SYSCFG | AUX_SERIAL_RCC_APB2Periph | AUX2_SERIAL_RCC_APB2Periph, ENABLE); pwrInit(); keysInit(); @@ -249,6 +249,9 @@ int main() #if defined(DEBUG) && defined(AUX_SERIAL) auxSerialInit(UART_MODE_DEBUG, 0); // default serial mode (None if DEBUG not defined) #endif +#if defined(DEBUG) && defined(AUX2_SERIAL) + aux2SerialInit(UART_MODE_DEBUG, 0); // default serial mode (None if DEBUG not defined) +#endif __enable_irq(); 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 e2f01f586..56b71d97c 100755 --- a/radio/src/targets/common/arm/stm32/intmodule_serial_driver.cpp +++ b/radio/src/targets/common/arm/stm32/intmodule_serial_driver.cpp @@ -21,12 +21,18 @@ #include "opentx.h" ModuleFifo intmoduleFifo; +#if !defined(INTMODULE_DMA_STREAM) +uint8_t * intmoduleTxBufferData; +uint8_t intmoduleTxBufferRemaining; +#endif void intmoduleStop() { GPIO_ResetBits(INTMODULE_PWR_GPIO, INTMODULE_PWR_GPIO_PIN); +#if defined(INTMODULE_DMA_STREAM) INTMODULE_DMA_STREAM->CR &= ~DMA_SxCR_EN; // Disable DMA +#endif GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = INTMODULE_TX_GPIO_PIN | INTMODULE_RX_GPIO_PIN; @@ -57,7 +63,11 @@ void intmoduleSerialStart(uint32_t baudrate, uint8_t rxEnable, uint16_t parity, INTERNAL_MODULE_ON(); NVIC_InitTypeDef NVIC_InitStructure; +#if defined(INTMODULE_DMA_STREAM) NVIC_InitStructure.NVIC_IRQChannel = INTMODULE_DMA_STREAM_IRQ; +#else + NVIC_InitStructure.NVIC_IRQChannel = INTMODULE_USART_IRQn; +#endif NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; /* Not used as 4 bits are used for the pre-emption priority. */; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; @@ -118,8 +128,22 @@ void intmoduleTimerStart(uint32_t periodMs) #define USART_FLAG_ERRORS (USART_FLAG_ORE | USART_FLAG_NE | USART_FLAG_FE | USART_FLAG_PE) extern "C" void INTMODULE_USART_IRQHandler(void) { - uint32_t status = INTMODULE_USART->SR; +#if !defined(INTMODULE_DMA_STREAM) + // Send + if (USART_GetITStatus(INTMODULE_USART, USART_IT_TXE) != RESET) { + if (intmoduleTxBufferRemaining) { + USART_SendData(INTMODULE_USART, intmoduleTxBufferData[0]); + intmoduleTxBufferData++; + intmoduleTxBufferRemaining--; + } + else { + USART_ITConfig(INTMODULE_USART, USART_IT_TXE, DISABLE); + } + } +#endif + // Receive + uint32_t status = INTMODULE_USART->SR; while (status & (USART_FLAG_RXNE | USART_FLAG_ERRORS)) { uint8_t data = INTMODULE_USART->DR; if (status & USART_FLAG_ERRORS) { @@ -143,6 +167,7 @@ void intmoduleSendBuffer(const uint8_t * data, uint8_t size) if (size == 0) return; +#if defined(INTMODULE_DMA_STREAM) DMA_InitTypeDef DMA_InitStructure; DMA_DeInit(INTMODULE_DMA_STREAM); DMA_InitStructure.DMA_Channel = INTMODULE_DMA_CHANNEL; @@ -163,6 +188,11 @@ void intmoduleSendBuffer(const uint8_t * data, uint8_t size) DMA_Init(INTMODULE_DMA_STREAM, &DMA_InitStructure); DMA_Cmd(INTMODULE_DMA_STREAM, ENABLE); USART_DMACmd(INTMODULE_USART, USART_DMAReq_Tx, ENABLE); +#else + intmoduleTxBufferData = (uint8_t *)data; + intmoduleTxBufferRemaining = size; + USART_ITConfig(INTMODULE_USART, USART_IT_TXE, ENABLE); +#endif } void intmoduleSendNextFrame() 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 436cb0bd7..debe8793d 100644 --- a/radio/src/targets/common/arm/stm32/rotary_encoder_driver.cpp +++ b/radio/src/targets/common/arm/stm32/rotary_encoder_driver.cpp @@ -104,7 +104,7 @@ void rotaryEncoderCheck() #endif #if !defined(BOOT) if (g_eeGeneral.backlightMode & e_backlight_mode_keys) { - backlightOn(); + resetBacklightTimeout(); } inactivity.counter = 0; #endif diff --git a/radio/src/targets/common/arm/stm32/usbd_cdc.cpp b/radio/src/targets/common/arm/stm32/usbd_cdc.cpp index dd0233941..4d9409ec8 100644 --- a/radio/src/targets/common/arm/stm32/usbd_cdc.cpp +++ b/radio/src/targets/common/arm/stm32/usbd_cdc.cpp @@ -218,11 +218,18 @@ static uint16_t VCP_DataRx (uint8_t* Buf, uint32_t Len) #if defined(CLI) //copy data to the application FIFO - for (uint32_t i = 0; i < Len; i++) - { + for (uint32_t i = 0; i < Len; i++) { cliRxFifo.push(Buf[i]); } #endif +#if defined(LUA) && !defined(CLI) + // copy data to the LUA FIFO + if (luaRxFifo) { + for (uint32_t i = 0; i < Len; i++) { + luaRxFifo->push(Buf[i]); + } + } +#endif return USBD_OK; } diff --git a/radio/src/targets/horus/CMakeLists.txt b/radio/src/targets/horus/CMakeLists.txt index 17e72ea20..ac05a6302 100644 --- a/radio/src/targets/horus/CMakeLists.txt +++ b/radio/src/targets/horus/CMakeLists.txt @@ -76,10 +76,15 @@ 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) - if (NOT BLUETOOTH) - set(AUX_SERIAL ON) - endif() + option(INTERNAL_GPS "Support for internal ublox GPS" OFF) + set(HARDWARE_TOUCH YES) set(USB_CHARGER YES) + set(DEFAULT_THEME "DARKBLUE") + set(AUX_SERIAL ON) + if (NOT BLUETOOTH AND NOT INTERNAL_GPS) + set(AUX2_SERIAL ON) + endif() + set(INTERNAL_GPS_BAUDRATE "9600" CACHE STRING "Baud rate for internal GPS") else() set(FLAVOUR x10) option(INTERNAL_MODULE_PXX1 "Support for PXX1 internal module" ON) @@ -106,7 +111,6 @@ elseif (PCB STREQUAL X12S) ${TARGET_SRC} audio_spi_driver.cpp x12s_adc_driver.cpp - gps_driver.cpp ) set(BITMAPS_TARGET x12s_bitmaps) set(FONTS_TARGET x12s_fonts) @@ -131,6 +135,12 @@ add_definitions(-DGPS_USART_BAUDRATE=${INTERNAL_GPS_BAUDRATE}) add_definitions(-DPWR_BUTTON_${PWR_BUTTON}) add_definitions(-DHARDWARE_TRAINER_JACK) +if(DEFAULT_THEME) + add_definitions(-DDEFAULT_THEME_${DEFAULT_THEME}) +else() + add_definitions(-DDEFAULT_THEME_DEFAULT) +endif() + if(NOT UNEXPECTED_SHUTDOWN) add_definitions(-DNO_UNEXPECTED_SHUTDOWN) endif() @@ -162,6 +172,7 @@ endif() if(INTERNAL_GPS) set(SRC ${SRC} gps.cpp) + set(TARGET_SRC ${TARGET_SRC} gps_driver.cpp) add_definitions(-DINTERNAL_GPS) message("Horus: Internal GPS enabled") endif() @@ -178,6 +189,13 @@ set(TARGET_SRC ../common/arm/stm32/rotary_encoder_driver.cpp ) +if(HARDWARE_TOUCH) + set(TARGET_SRC ${TARGET_SRC} + tp_gt911.cpp + ) + add_definitions(-DHARDWARE_TOUCH) +endif() + if(USB_CHARGER) set(TARGET_SRC ${TARGET_SRC} usb_charger_driver.cpp) add_definitions(-DUSB_CHARGER) @@ -195,6 +213,11 @@ if (AUX_SERIAL) set(AUX_SERIAL_DRIVER ../common/arm/stm32/aux_serial_driver.cpp) endif() +if (AUX2_SERIAL) + add_definitions(-DAUX2_SERIAL) + set(AUX_SERIAL_DRIVER ../common/arm/stm32/aux_serial_driver.cpp) +endif() + set(FIRMWARE_TARGET_SRC ${FIRMWARE_TARGET_SRC} ${LCD_DRIVER} diff --git a/radio/src/targets/horus/board.cpp b/radio/src/targets/horus/board.cpp index 61a429a70..49a0f13f7 100644 --- a/radio/src/targets/horus/board.cpp +++ b/radio/src/targets/horus/board.cpp @@ -52,6 +52,18 @@ void auxSerialPowerOff() GPIO_ResetBits(AUX_SERIAL_PWR_GPIO, AUX_SERIAL_PWR_GPIO_PIN); } #endif +#if defined(AUX2_SERIAL_PWR_GPIO) +void aux2SerialPowerOn() +{ + GPIO_SetBits(AUX2_SERIAL_PWR_GPIO, AUX2_SERIAL_PWR_GPIO_PIN); +} + +void aux2SerialPowerOff() +{ + GPIO_ResetBits(AUX2_SERIAL_PWR_GPIO, AUX2_SERIAL_PWR_GPIO_PIN); +} +#endif + #if HAS_SPORT_UPDATE_CONNECTOR() void sportUpdateInit() @@ -96,6 +108,7 @@ void boardInit() KEYS_RCC_AHB1Periph | ADC_RCC_AHB1Periph | AUX_SERIAL_RCC_AHB1Periph | + AUX2_SERIAL_RCC_AHB1Periph | TELEMETRY_RCC_AHB1Periph | TRAINER_RCC_AHB1Periph | BT_RCC_AHB1Periph | @@ -103,9 +116,11 @@ void boardInit() HAPTIC_RCC_AHB1Periph | INTMODULE_RCC_AHB1Periph | EXTMODULE_RCC_AHB1Periph | - I2C_TOUCH_RCC_AHB1Periph | + I2C_RCC_AHB1Periph | GPS_RCC_AHB1Periph | - SPORT_UPDATE_RCC_AHB1Periph, + SPORT_UPDATE_RCC_AHB1Periph | + TOUCH_INT_RCC_AHB1Periph | + TOUCH_RST_RCC_AHB1Periph, ENABLE); RCC_APB1PeriphClockCmd(ROTARY_ENCODER_RCC_APB1Periph | @@ -114,12 +129,13 @@ void boardInit() TIMER_2MHz_RCC_APB1Periph | AUDIO_RCC_APB1Periph | AUX_SERIAL_RCC_APB1Periph | + AUX2_SERIAL_RCC_APB1Periph | TELEMETRY_RCC_APB1Periph | TRAINER_RCC_APB1Periph | AUDIO_RCC_APB1Periph | INTMODULE_RCC_APB1Periph | EXTMODULE_RCC_APB1Periph | - I2C_TOUCH_RCC_APB1Periph | + I2C_RCC_APB1Periph | GPS_RCC_APB1Periph | BACKLIGHT_RCC_APB1Periph, ENABLE); @@ -133,6 +149,8 @@ void boardInit() TELEMETRY_RCC_APB2Periph | BT_RCC_APB2Periph | AUX_SERIAL_RCC_APB2Periph | + AUX2_SERIAL_RCC_APB2Periph | + GPS_RCC_APB2Periph | BACKLIGHT_RCC_APB2Periph, ENABLE); @@ -145,6 +163,9 @@ void boardInit() #if defined(DEBUG) && defined(AUX_SERIAL) auxSerialInit(UART_MODE_DEBUG, 0); // default serial mode (None if DEBUG not defined) #endif +#if defined(DEBUG) && defined(AUX2_SERIAL) + aux2SerialInit(UART_MODE_DEBUG, 0); // default serial mode (None if DEBUG not defined) +#endif TRACE("\nHorus board started :)"); TRACE("RCC->CSR = %08x", RCC->CSR); @@ -189,6 +210,10 @@ void boardInit() ledInit(); +#if defined(USB_CHARGER) + usbChargerInit(); +#endif + #if HAS_SPORT_UPDATE_CONNECTOR() sportUpdateInit(); #endif @@ -235,8 +260,14 @@ void boardOff() pwrOff(); } +#if defined (RADIO_TX16S) + #define BATTERY_DIVIDER 1495 +#else + #define BATTERY_DIVIDER 1629 +#endif + uint16_t getBatteryVoltage() { int32_t instant_vbat = anaIn(TX_VOLTAGE); // using filtered ADC value on purpose - return (uint16_t)((instant_vbat * (1000 + g_eeGeneral.txVoltageCalibration)) / 1629); + return (uint16_t)((instant_vbat * (1000 + g_eeGeneral.txVoltageCalibration)) / BATTERY_DIVIDER); } diff --git a/radio/src/targets/horus/board.h b/radio/src/targets/horus/board.h index 8b88b674e..fd862e2f0 100644 --- a/radio/src/targets/horus/board.h +++ b/radio/src/targets/horus/board.h @@ -137,6 +137,10 @@ void SDRAM_Init(); // Pulses driver #define INTERNAL_MODULE_ON() GPIO_SetBits(INTMODULE_PWR_GPIO, INTMODULE_PWR_GPIO_PIN) +#if defined(INTERNAL_MODULE_PXX1) || defined(INTERNAL_MODULE_PXX2) + #define HARDWARE_INTERNAL_RAS +#endif + #if defined(INTMODULE_USART) #define INTERNAL_MODULE_OFF() intmoduleStop() #else @@ -604,7 +608,7 @@ void sportUpdatePowerInit(); #define IS_SPORT_UPDATE_POWER_ON() (false) #endif -// Second serial port driver +// Aux serial port driver #if defined(AUX_SERIAL_GPIO) #define DEBUG_BAUDRATE 115200 extern uint8_t auxSerialMode; @@ -616,11 +620,30 @@ void auxSerialStop(); void auxSerialPowerOn(); void auxSerialPowerOff(); #if defined(AUX_SERIAL_PWR_GPIO) -#define AUX_SERIAL_POWER_ON() auxSerialPowerOn() -#define AUX_SERIAL__POWER_OFF() auxSerialPowerOff() +#define AUX_SERIAL_POWER_ON() auxSerialPowerOn() +#define AUX_SERIAL_POWER_OFF() auxSerialPowerOff() #else #define AUX_SERIAL_POWER_ON() -#define AUX_SERIAL__POWER_OFF() +#define AUX_SERIAL_POWER_OFF() +#endif +#endif + +// Aux2 serial port driver +#if defined(AUX2_SERIAL) +extern uint8_t aux2SerialMode; +void aux2SerialInit(unsigned int mode, unsigned int protocol); +void aux2SerialPutc(char c); +#define aux2SerialTelemetryInit(protocol) aux2SerialInit(UART_MODE_TELEMETRY, protocol) +void aux2SerialSbusInit(); +void aux2SerialStop(); +void aux2SerialPowerOn(); +void aux2SerialPowerOff(); +#if defined(AUX2_SERIAL_PWR_GPIO) +#define AUX2_SERIAL_POWER_ON() aux2SerialPowerOn() +#define AUX2_SERIAL_POWER_OFF() aux2SerialPowerOff() +#else +#define AUX2_SERIAL_POWER_ON() +#define AUX2_SERIAL_POWER_OFF() #endif #endif diff --git a/radio/src/targets/horus/gps_driver.cpp b/radio/src/targets/horus/gps_driver.cpp index 7a5e464c4..0e165b978 100644 --- a/radio/src/targets/horus/gps_driver.cpp +++ b/radio/src/targets/horus/gps_driver.cpp @@ -33,8 +33,8 @@ void gpsInit(uint32_t baudrate) NVIC_InitTypeDef NVIC_InitStructure; // RX and TX pins - GPIO_PinAFConfig(GPIOA, GPS_TX_GPIO_PinSource, GPS_GPIO_AF); - GPIO_PinAFConfig(GPIOA, GPS_RX_GPIO_PinSource, GPS_GPIO_AF); + GPIO_PinAFConfig(GPS_UART_GPIO, GPS_TX_GPIO_PinSource, GPS_GPIO_AF); + GPIO_PinAFConfig(GPS_UART_GPIO, GPS_RX_GPIO_PinSource, GPS_GPIO_AF); GPIO_InitStructure.GPIO_Pin = (GPS_TX_GPIO_PIN | GPS_RX_GPIO_PIN); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; @@ -58,6 +58,14 @@ void gpsInit(uint32_t baudrate) NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); + +#if defined(GPS_PWR_GPIO) + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; + GPIO_InitStructure.GPIO_Pin = GPS_PWR_GPIO_PIN; + GPIO_Init(GPS_PWR_GPIO, &GPIO_InitStructure); + GPIO_SetBits(GPS_PWR_GPIO, GPS_PWR_GPIO_PIN); +#endif } #if defined(DEBUG) diff --git a/radio/src/targets/horus/hal.h b/radio/src/targets/horus/hal.h index b7573a7ab..f4b49f5ae 100644 --- a/radio/src/targets/horus/hal.h +++ b/radio/src/targets/horus/hal.h @@ -184,10 +184,17 @@ #define TRIMS_GPIO_REG_LSU GPIOB->IDR #define TRIMS_GPIO_PIN_LSU GPIO_Pin_13 // PB.13 #elif defined(PCBX10) - #define TRIMS_GPIO_REG_LHL GPIOB->IDR - #define TRIMS_GPIO_PIN_LHL GPIO_Pin_8 // PB.08 - #define TRIMS_GPIO_REG_LHR GPIOB->IDR - #define TRIMS_GPIO_PIN_LHR GPIO_Pin_9 // PB.09 + #if defined(RADIO_TX16S) + #define TRIMS_GPIO_REG_LHL GPIOA->IDR + #define TRIMS_GPIO_PIN_LHL GPIO_Pin_6 // PA.06 + #define TRIMS_GPIO_REG_LHR GPIOC->IDR + #define TRIMS_GPIO_PIN_LHR GPIO_Pin_4 // PC.04 + #else + #define TRIMS_GPIO_REG_LHL GPIOB->IDR + #define TRIMS_GPIO_PIN_LHL GPIO_Pin_8 // PB.08 + #define TRIMS_GPIO_REG_LHR GPIOB->IDR + #define TRIMS_GPIO_PIN_LHR GPIO_Pin_9 // PB.09 + #endif #define TRIMS_GPIO_REG_LVD GPIOG->IDR #define TRIMS_GPIO_PIN_LVD GPIO_Pin_12 // PG.12 #define TRIMS_GPIO_REG_LVU GPIOJ->IDR @@ -228,14 +235,21 @@ #define KEYS_GPIOI_PINS (KEYS_GPIO_PIN_PGDN | KEYS_GPIO_PIN_LEFT | KEYS_GPIO_PIN_DOWN | SWITCHES_GPIO_PIN_A_L | GPIO_Pin_4) #define KEYS_GPIOJ_PINS (SWITCHES_GPIO_PIN_D_H | TRIMS_GPIO_PIN_RVU | TRIMS_GPIO_PIN_LVD | TRIMS_GPIO_PIN_LVU | TRIMS_GPIO_PIN_RSD) #elif defined(PCBX10) - #define KEYS_GPIOB_PINS (GPIO_Pin_12 | GPIO_Pin_15 | GPIO_Pin_14 | GPIO_Pin_13 | GPIO_Pin_8 | GPIO_Pin_9) -#if defined(RADIO_TX16S) - #define KEYS_GPIOC_PINS (GPIO_Pin_13) -#endif + #if defined(RADIO_TX16S) + #define KEYS_GPIOB_PINS (GPIO_Pin_12 | GPIO_Pin_15 | GPIO_Pin_14 | GPIO_Pin_13) + #else + #define KEYS_GPIOB_PINS (GPIO_Pin_12 | GPIO_Pin_15 | GPIO_Pin_14 | GPIO_Pin_13 | GPIO_Pin_8 | GPIO_Pin_9) + #endif #define KEYS_GPIOD_PINS (GPIO_Pin_11 | GPIO_Pin_3 | GPIO_Pin_7 | GPIO_Pin_13) #define KEYS_GPIOE_PINS (GPIO_Pin_3) #define KEYS_GPIOG_PINS (SWITCHES_GPIO_PIN_D_L | SWITCHES_GPIO_PIN_G_H | SWITCHES_GPIO_PIN_G_L | SWITCHES_GPIO_PIN_H | TRIMS_GPIO_PIN_LVD) +#if defined(RADIO_TX16S) + #define KEYS_GPIOA_PINS (GPIO_Pin_6) + #define KEYS_GPIOC_PINS (GPIO_Pin_4 | GPIO_Pin_13) + #define KEYS_GPIOH_PINS (GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_14 | GPIO_Pin_15) +#else #define KEYS_GPIOH_PINS (GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_14 | GPIO_Pin_15) +#endif #define KEYS_GPIOI_PINS (GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_11 | GPIO_Pin_15) #define KEYS_GPIOJ_PINS (SWITCHES_GPIO_PIN_D_H | TRIMS_GPIO_PIN_LVU | TRIMS_GPIO_PIN_RVD | TRIMS_GPIO_PIN_RVU | GPIO_Pin_8) #endif @@ -308,7 +322,9 @@ #define ADC_DMA_Stream DMA2_Stream0 #define ADC_SET_DMA_FLAGS() ADC_DMA->LIFCR = (DMA_LIFCR_CTCIF0 | DMA_LIFCR_CHTIF0 | DMA_LIFCR_CTEIF0 | DMA_LIFCR_CDMEIF0 | DMA_LIFCR_CFEIF0) #define ADC_TRANSFER_COMPLETE() (ADC_DMA->LISR & DMA_LISR_TCIF0) - #if defined(RADIO_FAMILY_T16) + #if defined(RADIO_TX16S) + #define ADC_VREF_PREC2 330 + #elif defined(RADIO_T16) #define ADC_VREF_PREC2 300 #else #define ADC_VREF_PREC2 250 @@ -327,6 +343,7 @@ #define USB_CHARGER_RCC_AHB1Periph RCC_AHB1Periph_GPIOG #define USB_CHARGER_GPIO GPIOG #define USB_CHARGER_GPIO_PIN GPIO_Pin_11 // PG.11 +#define USB_USBDet_GPIO_PIN GPIO_Pin_13 // PG.13 #else #define USB_CHARGER_RCC_AHB1Periph 0 #endif @@ -377,8 +394,8 @@ #endif // Serial Port (DEBUG) -#if defined(PCBX12S) - #define AUX_SERIAL_RCC_AHB1Periph (RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_DMA1) +#if defined(PCBX12S) || defined(RADIO_TX16S) + #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 #define AUX_SERIAL_GPIO GPIOB @@ -392,47 +409,58 @@ #define AUX_SERIAL_USART_IRQn USART3_IRQn #define AUX_SERIAL_DMA_Stream_RX DMA1_Stream1 #define AUX_SERIAL_DMA_Channel_RX DMA_Channel_4 -#elif defined(RADIO_TX16S) && !defined(BLUETOOTH) - #define AUX_SERIAL_RCC_AHB1Periph (RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOG | RCC_AHB1Periph_DMA2) - #define AUX_SERIAL_RCC_APB1Periph 0 - #define AUX_SERIAL_RCC_APB2Periph RCC_APB2Periph_USART6 - #define AUX_SERIAL_USART USART6 - #define AUX_SERIAL_GPIO_AF GPIO_AF_USART6 - #define AUX_SERIAL_USART_IRQn USART6_IRQn - #define AUX_SERIAL_GPIO GPIOG - #define AUX_SERIAL_GPIO_PIN_TX GPIO_Pin_14 // PG.14 - #define AUX_SERIAL_GPIO_PIN_RX GPIO_Pin_9 // PG.09 - #define AUX_SERIAL_GPIO_PinSource_TX GPIO_PinSource14 - #define AUX_SERIAL_GPIO_PinSource_RX GPIO_PinSource9 - #define AUX_SERIAL_USART_IRQHandler USART6_IRQHandler - #define AUX_SERIAL_DMA_Stream_RX DMA2_Stream6 - #define AUX_SERIAL_DMA_Channel_RX DMA_Channel_5 - #define AUX_SERIAL_PWR_GPIO GPIOB - #define AUX_SERIAL_PWR_GPIO_PIN GPIO_Pin_0 // PB.00 - #define HARDWARE_TRAINER_AUX_SERIAL - - #define AUX2_SERIAL_RCC_AHB1Periph (RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_DMA1) - #define AUX2_SERIAL_PWR_GPIO GPIOA - #define AUX2_SERIAL_PWR_GPIO_PIN GPIO_Pin_15 // PA.15 - #define AUX2_SERIAL_RCC_APB1Periph RCC_APB1Periph_USART3 - #define AUX2_SERIAL_RCC_APB2Periph 0 - #define AUX2_SERIAL_GPIO GPIOB - #define AUX2_SERIAL_GPIO_PIN_TX GPIO_Pin_10 // PB.10 - #define AUX2_SERIAL_GPIO_PIN_RX GPIO_Pin_11 // PB.11 - #define AUX2_SERIAL_GPIO_PinSource_TX GPIO_PinSource10 - #define AUX2_SERIAL_GPIO_PinSource_RX GPIO_PinSource11 - #define AUX2_SERIAL_GPIO_AF GPIO_AF_USART3 - #define AUX2_SERIAL_USART USART3 - #define AUX2_SERIAL_USART_IRQHandler USART3_IRQHandler - #define AUX2_SERIAL_USART_IRQn USART3_IRQn - #define AUX2_SERIAL_DMA_Stream_RX DMA1_Stream1 - #define AUX2_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 TRAINER_BATTERY_COMPARTMENT // allows serial port TTL trainer +#endif #else #define AUX_SERIAL_RCC_AHB1Periph 0 #define AUX_SERIAL_RCC_APB1Periph 0 #define AUX_SERIAL_RCC_APB2Periph 0 #endif +#if defined(AUX2_SERIAL) + #define AUX2_SERIAL_RCC_AHB1Periph (RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOG | RCC_AHB1Periph_DMA2) + #define AUX2_SERIAL_RCC_APB1Periph 0 + #define AUX2_SERIAL_RCC_APB2Periph RCC_APB2Periph_USART6 + #define AUX2_SERIAL_USART USART6 + #define AUX2_SERIAL_GPIO_AF GPIO_AF_USART6 + #define AUX2_SERIAL_USART_IRQn USART6_IRQn + #define AUX2_SERIAL_GPIO GPIOG + #define AUX2_SERIAL_GPIO_PIN_TX GPIO_Pin_14 // PG.14 + #define AUX2_SERIAL_GPIO_PIN_RX GPIO_Pin_9 // PG.09 + #define AUX2_SERIAL_GPIO_PinSource_TX GPIO_PinSource14 + #define AUX2_SERIAL_GPIO_PinSource_RX GPIO_PinSource9 + #define AUX2_SERIAL_USART_IRQHandler USART6_IRQHandler + #define AUX2_SERIAL_DMA_Stream_RX DMA2_Stream6 + #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 +#elif defined(RADIO_TX16S) && defined(INTERNAL_GPS) + #define GPS_RCC_AHB1Periph (RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOG) + #define GPS_RCC_APB1Periph 0 + #define GPS_RCC_APB2Periph RCC_APB2Periph_USART6 + #define GPS_USART USART6 + #define GPS_GPIO_AF GPIO_AF_USART6 + #define GPS_USART_IRQn USART6_IRQn + #define GPS_USART_IRQHandler USART6_IRQHandler + #define GPS_UART_GPIO GPIOG + #define GPS_TX_GPIO_PIN GPIO_Pin_14 // PG.14 + #define GPS_RX_GPIO_PIN GPIO_Pin_9 // PG.09 + #define GPS_TX_GPIO_PinSource GPIO_PinSource14 + #define GPS_RX_GPIO_PinSource GPIO_PinSource9 + #define GPS_PWR_GPIO GPIOB + #define GPS_PWR_GPIO_PIN GPIO_Pin_0 // PB.00 + #define AUX2_SERIAL_RCC_AHB1Periph 0 + #define AUX2_SERIAL_RCC_APB1Periph 0 + #define AUX2_SERIAL_RCC_APB2Periph 0 +#else + #define AUX2_SERIAL_RCC_AHB1Periph 0 + #define AUX2_SERIAL_RCC_APB1Periph 0 + #define AUX2_SERIAL_RCC_APB2Periph 0 +#endif + // Telemetry #define TELEMETRY_RCC_AHB1Periph (RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_DMA1) #define TELEMETRY_RCC_APB1Periph RCC_APB1Periph_USART2 @@ -625,11 +653,34 @@ #define AUDIO_MUTE_DELAY 500 // ms #endif -// I2C Bus #if defined(RADIO_TX16S) -#define I2C_RCC_AHB1Periph 0 -#define I2C_RCC_APB1Periph 0 +// Only slight noise with 868MHz > 1W, if complaints later remove and set AUDIO_UNMUTE_DELAY to 150 + #undef AUDIO_MUTE_GPIO_PIN +#endif + +// Touch +#if defined(HARDWARE_TOUCH) + #define TOUCH_INT_RCC_AHB1Periph RCC_AHB1Periph_GPIOH + #define TOUCH_INT_GPIO GPIOH + #define TOUCH_INT_GPIO_PIN GPIO_Pin_2 // PH.02 + + #define TOUCH_RST_RCC_AHB1Periph RCC_AHB1Periph_GPIOF + #define TOUCH_RST_GPIO GPIOF + #define TOUCH_RST_GPIO_PIN GPIO_Pin_10 // PF.10 + + #define TOUCH_INT_EXTI_LINE1 EXTI_Line2 + #define TOUCH_INT_EXTI_IRQn1 EXTI2_IRQn + #define TOUCH_INT_EXTI_IRQHandler1 EXTI2_IRQHandler + #define TOUCH_INT_EXTI_PortSource EXTI_PortSourceGPIOH + #define TOUCH_INT_EXTI_PinSource1 EXTI_PinSource2 + + #define TOUCH_INT_STATUS() (GPIO_ReadInputDataBit(TOUCH_INT_GPIO, TOUCH_INT_GPIO_PIN)) #else + #define TOUCH_INT_RCC_AHB1Periph 0 + #define TOUCH_RST_RCC_AHB1Periph 0 +#endif + +// I2C Bus #define I2C_RCC_AHB1Periph RCC_AHB1Periph_GPIOB #define I2C_RCC_APB1Periph RCC_APB1Periph_I2C1 #define I2C I2C1 @@ -640,7 +691,6 @@ #define I2C_SCL_GPIO_PinSource GPIO_PinSource8 #define I2C_SDA_GPIO_PinSource GPIO_PinSource9 #define I2C_SPEED 400000 -#endif // Haptic #define HAPTIC_PWM @@ -834,24 +884,6 @@ #define TIMER_2MHz_RCC_APB1Periph RCC_APB1Periph_TIM7 #define TIMER_2MHz_TIMER TIM7 -// Touch -#if defined(HARDWARE_TOUCH) -#define I2C_TOUCH_RCC_AHB1Periph RCC_AHB1Periph_GPIOB -#define I2C_TOUCH_RCC_APB1Periph RCC_APB1Periph_I2C1 -#define I2C_TOUCH I2C1 -#define I2C_TOUCH_GPIO GPIOB -#define I2C_TOUCH_SCL_GPIO_PIN GPIO_Pin_8 // PB.08 -#define I2C_TOUCH_SDA_GPIO_PIN GPIO_Pin_7 // PB.07 - -#define I2C_TOUCH_RESET_GPIO GPIOF -#define I2C_TOUCH_RESET_GPIO_PIN GPIO_Pin_10 // PF.10 -#define I2C_TOUCH_INT_GPIO GPIOH -#define I2C_TOUCH_INT_GPIO_PIN GPIO_Pin_2 // PH.02 -#else -#define I2C_TOUCH_RCC_AHB1Periph 0 -#define I2C_TOUCH_RCC_APB1Periph 0 -#endif - // Bluetooth #define STORAGE_BLUETOOTH #if defined(BLUETOOTH) @@ -892,6 +924,7 @@ #if defined(PCBX12S) #define GPS_RCC_AHB1Periph RCC_AHB1Periph_GPIOA #define GPS_RCC_APB1Periph RCC_APB1Periph_UART4 + #define GPS_RCC_APB2Periph 0 #define GPS_USART UART4 #define GPS_GPIO_AF GPIO_AF_UART4 #define GPS_USART_IRQn UART4_IRQn @@ -901,9 +934,10 @@ #define GPS_RX_GPIO_PIN GPIO_Pin_1 // PA.01 #define GPS_TX_GPIO_PinSource GPIO_PinSource0 #define GPS_RX_GPIO_PinSource GPIO_PinSource1 -#else +#elif !defined(INTERNAL_GPS) #define GPS_RCC_AHB1Periph 0 #define GPS_RCC_APB1Periph 0 + #define GPS_RCC_APB2Periph 0 #endif #endif // _HAL_H_ diff --git a/radio/src/targets/horus/keys_driver.cpp b/radio/src/targets/horus/keys_driver.cpp old mode 100644 new mode 100755 index 888c4dabc..7433ee58f --- a/radio/src/targets/horus/keys_driver.cpp +++ b/radio/src/targets/horus/keys_driver.cpp @@ -107,7 +107,7 @@ void readKeysAndTrims() if ((keys_input || trims_input) && (g_eeGeneral.backlightMode & e_backlight_mode_keys)) { // on keypress turn the light on - backlightOn(); + resetBacklightTimeout(); } } @@ -204,16 +204,39 @@ void keysInit() GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; +#if defined(KEYS_GPIOA_PINS) + INIT_KEYS_PINS(GPIOA); +#endif + +#if defined(KEYS_GPIOB_PINS) INIT_KEYS_PINS(GPIOB); +#endif #if defined(KEYS_GPIOC_PINS) INIT_KEYS_PINS(GPIOC); #endif +#if defined(KEYS_GPIOD_PINS) INIT_KEYS_PINS(GPIOD); +#endif + +#if defined(KEYS_GPIOE_PINS) INIT_KEYS_PINS(GPIOE); +#endif + +#if defined(KEYS_GPIOG_PINS) INIT_KEYS_PINS(GPIOG); +#endif + +#if defined(KEYS_GPIOH_PINS) INIT_KEYS_PINS(GPIOH); +#endif + +#if defined(KEYS_GPIOI_PINS) INIT_KEYS_PINS(GPIOI); +#endif + +#if defined(KEYS_GPIOJ_PINS) INIT_KEYS_PINS(GPIOJ); +#endif } diff --git a/radio/src/targets/horus/libopenui_config.h b/radio/src/targets/horus/libopenui_config.h index bcc6a4216..2b7e576b8 100644 --- a/radio/src/targets/horus/libopenui_config.h +++ b/radio/src/targets/horus/libopenui_config.h @@ -46,13 +46,14 @@ constexpr uint32_t DEFAULT_SCROLLBAR_X = LCD_W - 10; constexpr uint32_t DEFAULT_SCROLLBAR_Y = MENU_CONTENT_TOP; constexpr uint32_t DEFAULT_SCROLLBAR_H = MENU_FOOTER_TOP - DEFAULT_SCROLLBAR_Y - 6; -constexpr coord_t PAGE_PADDING = 6; +constexpr coord_t PAGE_PADDING = 6; constexpr uint32_t PAGE_LINE_HEIGHT = 20; constexpr uint32_t PAGE_LINE_SPACING = 2; constexpr uint32_t PAGE_INDENT_WIDTH = 10; constexpr uint32_t PAGE_LABEL_WIDTH = 240; constexpr uint32_t FH = PAGE_LINE_HEIGHT; constexpr uint32_t NUM_BODY_LINES = MENU_BODY_HEIGHT / PAGE_LINE_HEIGHT; +constexpr uint32_t TEXT_VIEWER_LINES = (MENU_FOOTER_TOP - MENU_HEADER_HEIGHT) / FH; constexpr uint32_t FIELD_PADDING_LEFT = 3; constexpr uint32_t FIELD_PADDING_TOP = 2; @@ -168,6 +169,7 @@ constexpr LcdFlags MENU_FONT = FONT(STD); constexpr LcdFlags TABLE_HEADER_FONT = FONT(STD); constexpr LcdFlags TABLE_BODY_FONT = FONT(STD); -constexpr int CJK_FIRST_LETTER_INDEX = 187; +constexpr int CJK_FIRST_LETTER_INDEX = 168; +constexpr coord_t CHAR_SPACING = 0; #endif // _LIBOPENUI_CONFIG_H_ diff --git a/radio/src/targets/horus/tp_gt911.cpp b/radio/src/targets/horus/tp_gt911.cpp new file mode 100644 index 000000000..5c4929e95 --- /dev/null +++ b/radio/src/targets/horus/tp_gt911.cpp @@ -0,0 +1,412 @@ +/* + * 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 "tp_gt911.h" + +uint8_t touchGT911Flag = 0; +uint8_t touchPanelEvent = 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); + + EXTI_InitTypeDef EXTI_InitStructure; + EXTI_StructInit(&EXTI_InitStructure); + EXTI_InitStructure.EXTI_Line = TOUCH_INT_EXTI_LINE1; + EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; + EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling; + EXTI_InitStructure.EXTI_LineCmd = DISABLE; + EXTI_Init(&EXTI_InitStructure); + + + NVIC_InitTypeDef NVIC_InitStructure; + NVIC_InitStructure.NVIC_IRQChannel = TOUCH_INT_EXTI_IRQn1; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 9; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; /* Not used as 4 bits are used for the pre-emption priority. */; + NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE; + NVIC_Init(&NVIC_InitStructure); +} + +static void TOUCH_AF_ExtiConfig(void) +{ + SYSCFG_EXTILineConfig(TOUCH_INT_EXTI_PortSource, TOUCH_INT_EXTI_PinSource1); + + EXTI_InitTypeDef EXTI_InitStructure; + EXTI_StructInit(&EXTI_InitStructure); + EXTI_InitStructure.EXTI_Line = TOUCH_INT_EXTI_LINE1; + EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; + EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling; + 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; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; /* Not used as 4 bits are used for the pre-emption priority. */; + NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; + NVIC_Init(&NVIC_InitStructure); +} + +static void TOUCH_AF_GPIOConfig(void) +{ + GPIO_InitTypeDef GPIO_InitStructure; + GPIO_InitStructure.GPIO_Pin = TOUCH_RST_GPIO_PIN; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; + GPIO_Init(TOUCH_RST_GPIO, &GPIO_InitStructure); + + GPIO_ResetBits(TOUCH_RST_GPIO, TOUCH_RST_GPIO_PIN); + + GPIO_InitStructure.GPIO_Pin = TOUCH_INT_GPIO_PIN; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; + GPIO_Init(TOUCH_INT_GPIO, &GPIO_InitStructure); + + GPIO_ResetBits(TOUCH_INT_GPIO, TOUCH_INT_GPIO_PIN); +} + +void SDA_IN(void) +{ + GPIO_InitTypeDef GPIO_InitStructure; + GPIO_InitStructure.GPIO_Pin = I2C_SDA_GPIO_PIN; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_Init(I2C_GPIO, &GPIO_InitStructure); +} + +void SDA_OUT(void) +{ + 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; + GPIO_Init(I2C_GPIO, &GPIO_InitStructure); +} + +void I2C_Start(void) +{ + 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); + } + I2C_SDA_L(); + I2C_SCL_L(); + 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(); +} + +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; + + 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 ((state & 0x80u) == 0x00) { + // not ready + return; + } + + uint8_t pointsCount = (state & 0x0Fu); + + if (pointsCount > 0 && pointsCount < GT911_MAX_TP) { + gt911ReadRegister(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; + touchState.startY = touchState.y = touchData.points[0].y; + } + else { + touchState.deltaX = touchData.points[0].x - touchState.x; + touchState.deltaY = touchData.points[0].y - touchState.y; + if (touchState.event == TE_SLIDE || abs(touchState.deltaX) >= SLIDE_RANGE || abs(touchState.deltaY) >= SLIDE_RANGE) { + touchState.event = TE_SLIDE; + touchState.x = touchData.points[0].x; + touchState.y = touchData.points[0].y; + } + } + touchData.pointsCount = pointsCount; + } + else { + if (touchData.pointsCount > 0) { + touchData.pointsCount = 0; + if (touchState.event == TE_SLIDE) + touchState.event = TE_SLIDE_END; + else + touchState.event = TE_UP; + } + } + + uint8_t zero = 0; + gt911WriteRegister(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; + EXTI_ClearITPendingBit(TOUCH_INT_EXTI_LINE1); + } +} diff --git a/radio/src/targets/horus/tp_gt911.h b/radio/src/targets/horus/tp_gt911.h new file mode 100644 index 000000000..2b5f7d32c --- /dev/null +++ b/radio/src/targets/horus/tp_gt911.h @@ -0,0 +1,296 @@ +/* + * 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 _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; + +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(); + +#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 +}; + +//I2C +#define GT_CMD_WR 0X28 +#define GT_CMD_RD 0X29 + +#define SLAVE_Write_Address 0X28 + +//GT9147 +#define GT_CTRL_REG 0X8040 +#define GT_CFGS_REG 0X8047 +#define GT_CHECK_REG 0X80FF +#define GT_PID_REG 0X8140 + +#define GT_GSTID_REG 0X814E +#define GT_TP1_REG 0X8150 +#define GT_TP2_REG 0X8158 +#define GT_TP3_REG 0X8160 +#define GT_TP4_REG 0X8168 +#define GT_TP5_REG 0X8170 + +#define GT911_READ_XY_REG 0x814E +#define GT911_CLEARBUF_REG 0x814E +#define GT911_CONFIG_REG 0x8047 +#define GT911_COMMAND_REG 0x8040 +#define GT911_PRODUCT_ID_REG 0x8140 +#define GT911_VENDOR_ID_REG 0x814A +#define GT911_CONFIG_VERSION_REG 0x8047 +#define GT911_CONFIG_CHECKSUM_REG 0x80FF +#define GT911_FIRMWARE_VERSION_REG 0x8144 + +PACK(typedef struct +{ + uint8_t track; + uint16_t x; + uint16_t y; + uint16_t size; + uint8_t reserved; +}) TouchPoint; + +PACK(struct TouchData +{ + uint8_t pointsCount; + union + { + TouchPoint points[GT911_MAX_TP]; + uint8_t data[GT911_MAX_TP * sizeof(TouchPoint)]; + }; +}); + +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_ diff --git a/radio/src/targets/horus/usb_charger_driver.cpp b/radio/src/targets/horus/usb_charger_driver.cpp index 3ba915318..be27276f0 100644 --- a/radio/src/targets/horus/usb_charger_driver.cpp +++ b/radio/src/targets/horus/usb_charger_driver.cpp @@ -23,7 +23,7 @@ void usbChargerInit() { GPIO_InitTypeDef GPIO_InitStructure; - GPIO_InitStructure.GPIO_Pin = USB_CHARGER_RCC_AHB1Periph; + GPIO_InitStructure.GPIO_Pin = USB_CHARGER_GPIO_PIN | USB_USBDet_GPIO_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; @@ -33,6 +33,6 @@ void usbChargerInit() bool usbChargerLed() { - return GPIO_ReadInputDataBit(USB_CHARGER_GPIO, USB_CHARGER_GPIO_PIN) == Bit_RESET; + return GPIO_ReadInputDataBit(USB_CHARGER_GPIO, USB_USBDet_GPIO_PIN) == 0 ? 0 : GPIO_ReadInputDataBit(USB_CHARGER_GPIO, USB_CHARGER_GPIO_PIN) == Bit_RESET; } diff --git a/radio/src/targets/nv14/libopenui_config.h b/radio/src/targets/nv14/libopenui_config.h index 67cd91a1a..a19246e18 100644 --- a/radio/src/targets/nv14/libopenui_config.h +++ b/radio/src/targets/nv14/libopenui_config.h @@ -53,6 +53,7 @@ constexpr uint32_t PAGE_INDENT_WIDTH = 10; constexpr uint32_t PAGE_LABEL_WIDTH = 140; constexpr uint32_t FH = PAGE_LINE_HEIGHT; constexpr uint32_t NUM_BODY_LINES = MENU_BODY_HEIGHT / PAGE_LINE_HEIGHT; +constexpr uint32_t TEXT_VIEWER_LINES = (MENU_FOOTER_TOP - MENU_HEADER_HEIGHT) / FH; constexpr uint32_t FIELD_PADDING_LEFT = 3; constexpr uint32_t FIELD_PADDING_TOP = 4; @@ -172,6 +173,7 @@ constexpr LcdFlags MENU_FONT = FONT(STD); constexpr LcdFlags TABLE_HEADER_FONT = FONT(STD); constexpr LcdFlags TABLE_BODY_FONT = FONT(STD); -constexpr int CJK_FIRST_LETTER_INDEX = 187; +constexpr int CJK_FIRST_LETTER_INDEX = 168; +constexpr coord_t CHAR_SPACING = 0; #endif // _LIBOPENUI_CONFIG_H_ diff --git a/radio/src/targets/simu/simpgmspace.cpp b/radio/src/targets/simu/simpgmspace.cpp index 0ec31e6ba..e2238ba8a 100644 --- a/radio/src/targets/simu/simpgmspace.cpp +++ b/radio/src/targets/simu/simpgmspace.cpp @@ -530,7 +530,7 @@ void readKeysAndTrims() } if (keysInput || trimsInput) { - backlightOn(); + resetBacklightTimeout(); } } @@ -609,6 +609,7 @@ int usbPlugged() { return false; } int getSelectedUsbMode() { return USB_JOYSTICK_MODE; } void setSelectedUsbMode(int mode) {} void delay_ms(uint32_t ms) { } +void delay_us(uint16_t us) { } // GPIO fake functions void GPIO_PinAFConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_PinSource, uint8_t GPIO_AF) { } @@ -820,6 +821,26 @@ void auxSerialStop() } #endif +#if defined(AUX2_SERIAL) +AuxSerialRxFifo aux2SerialRxFifo(nullptr); +uint8_t aux2SerialMode; +void aux2SerialInit(unsigned int mode, unsigned int protocol) +{ +} + +void aux2SerialPutc(char c) +{ +} + +void aux2SerialSbusInit() +{ +} + +void aux2SerialStop() +{ +} +#endif + #if defined(INTMODULE_HEARTBEAT_GPIO) volatile HeartbeatCapture heartbeatCapture; diff --git a/radio/src/targets/sky9x/keys_driver.cpp b/radio/src/targets/sky9x/keys_driver.cpp index 9f7dac244..f37cb52b5 100644 --- a/radio/src/targets/sky9x/keys_driver.cpp +++ b/radio/src/targets/sky9x/keys_driver.cpp @@ -109,7 +109,7 @@ void readKeysAndTrims() if ((keys_input || trims_input) && (g_eeGeneral.backlightMode & e_backlight_mode_keys)) { // on keypress turn the light on - backlightOn(); + resetBacklightTimeout(); } } diff --git a/radio/src/targets/taranis/board.h b/radio/src/targets/taranis/board.h index 32078c5bf..4e07b6191 100644 --- a/radio/src/targets/taranis/board.h +++ b/radio/src/targets/taranis/board.h @@ -113,12 +113,16 @@ 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) + #define HARDWARE_INTERNAL_RAS +#endif + #define EXTERNAL_MODULE_ON() EXTERNAL_MODULE_PWR_ON() #if defined(EXTMODULE_USART) -#define EXTERNAL_MODULE_OFF() extmoduleStop() + #define EXTERNAL_MODULE_OFF() extmoduleStop() #else -#define EXTERNAL_MODULE_OFF() EXTERNAL_MODULE_PWR_OFF() + #define EXTERNAL_MODULE_OFF() EXTERNAL_MODULE_PWR_OFF() #endif #if defined(RADIO_T12) @@ -781,7 +785,7 @@ void hapticOff(); void hapticOn(); #endif -// Second serial port driver +// Aux serial port driver #if defined(AUX_SERIAL_GPIO) #define DEBUG_BAUDRATE 115200 #define AUX_SERIAL @@ -792,7 +796,7 @@ void auxSerialPutc(char c); void auxSerialSbusInit(); void auxSerialStop(); #define AUX_SERIAL_POWER_ON() -#define AUX_SERIAL__POWER_OFF() +#define AUX_SERIAL_POWER_OFF() #endif // BT driver diff --git a/radio/src/targets/taranis/hal.h b/radio/src/targets/taranis/hal.h index a83d230c1..6fc3b994f 100644 --- a/radio/src/targets/taranis/hal.h +++ b/radio/src/targets/taranis/hal.h @@ -1084,11 +1084,6 @@ #define INTMODULE_GPIO_AF GPIO_AF_USART3 #define INTMODULE_USART_IRQn USART3_IRQn #define INTMODULE_USART_IRQHandler USART3_IRQHandler - #define INTMODULE_DMA_STREAM DMA1_Stream3 - #define INTMODULE_DMA_STREAM_IRQ DMA1_Stream3_IRQn - #define INTMODULE_DMA_STREAM_IRQHandler DMA1_Stream3_IRQHandler - #define INTMODULE_DMA_FLAG_TC DMA_IT_TCIF3 - #define INTMODULE_DMA_CHANNEL DMA_Channel_4 #define INTMODULE_RCC_APB1Periph RCC_APB1Periph_TIM2 #define INTMODULE_RCC_APB2Periph RCC_APB1Periph_USART3 #define INTMODULE_TIMER TIM2 @@ -1335,6 +1330,11 @@ #define AUX_SERIAL_DMA_Channel_RX DMA_Channel_4 #endif +// No aux2 on taranis +#define AUX2_SERIAL_RCC_AHB1Periph 0 +#define AUX2_SERIAL_RCC_APB1Periph 0 +#define AUX2_SERIAL_RCC_APB2Periph 0 + // Telemetry #define TELEMETRY_RCC_AHB1Periph (RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_DMA1) #define TELEMETRY_RCC_APB1Periph RCC_APB1Periph_USART2 diff --git a/radio/src/targets/taranis/keys_driver.cpp b/radio/src/targets/taranis/keys_driver.cpp index ab0a6202d..0699a1c50 100644 --- a/radio/src/targets/taranis/keys_driver.cpp +++ b/radio/src/targets/taranis/keys_driver.cpp @@ -130,7 +130,7 @@ void readKeysAndTrims() if ((keys_input || trims_input) && (g_eeGeneral.backlightMode & e_backlight_mode_keys)) { #endif // on keypress turn the light on - backlightOn(); + resetBacklightTimeout(); } } diff --git a/radio/src/telemetry/crossfire.cpp b/radio/src/telemetry/crossfire.cpp index eb08dc9ed..e0f216615 100644 --- a/radio/src/telemetry/crossfire.cpp +++ b/radio/src/telemetry/crossfire.cpp @@ -201,6 +201,11 @@ void processCrossfireTelemetryData(uint8_t data) auxSerialPutc(data); } #endif +#if defined(AUX2_SERIAL) + if (g_eeGeneral.aux2SerialMode == UART_MODE_TELEMETRY_MIRROR) { + aux2SerialPutc(data); + } +#endif if (telemetryRxBufferCount == 0 && data != RADIO_ADDRESS) { TRACE("[XF] address 0x%02X error", data); diff --git a/radio/src/telemetry/frsky.cpp b/radio/src/telemetry/frsky.cpp index 0fe1a5bfd..611ece4ac 100644 --- a/radio/src/telemetry/frsky.cpp +++ b/radio/src/telemetry/frsky.cpp @@ -32,6 +32,11 @@ void processFrskyTelemetryData(uint8_t data) auxSerialPutc(data); } #endif +#if defined(AUX2_SERIAL) + if (g_eeGeneral.aux2SerialMode == UART_MODE_TELEMETRY_MIRROR) { + aux2SerialPutc(data); + } +#endif if (pushFrskyTelemetryData(data)) { if (IS_FRSKY_SPORT_PROTOCOL()) { diff --git a/radio/src/telemetry/frsky.h b/radio/src/telemetry/frsky.h index 8218447e4..623ecb67d 100644 --- a/radio/src/telemetry/frsky.h +++ b/radio/src/telemetry/frsky.h @@ -33,7 +33,12 @@ enum FrSkyDataState { STATE_DATA_XOR, }; -#define FRSKY_SPORT_BAUDRATE 57600 +#define FRSKY_SPORT_BAUDRATE 57600 +#if defined(RADIO_TX16S) +#define FRSKY_TELEM_MIRROR_BAUDRATE 115200 +#else +#define FRSKY_TELEM_MIRROR_BAUDRATE FRSKY_SPORT_BAUDRATE +#endif #define FRSKY_D_BAUDRATE 9600 @@ -293,10 +298,10 @@ inline bool isRasValueValid() { return true; } -#elif defined(PCBX9DP) || defined(PCBX9E) +#elif defined(PCBTARANIS) inline bool isRasValueValid() { - return telemetryData.xjtVersion != 0x0000 && telemetryData.xjtVersion != 0x00FF; + return telemetryData.xjtVersion != 0x00FF; } #elif defined(PCBHORUS) inline bool isRasValueValid() diff --git a/radio/src/telemetry/frsky_pxx2.cpp b/radio/src/telemetry/frsky_pxx2.cpp index df4c30c54..3557fe84b 100644 --- a/radio/src/telemetry/frsky_pxx2.cpp +++ b/radio/src/telemetry/frsky_pxx2.cpp @@ -125,8 +125,8 @@ void processRegisterFrame(uint8_t module, const uint8_t * frame) case 0x01: if (reusableBuffer.moduleSetup.pxx2.registerStep == REGISTER_RX_NAME_SELECTED) { // RX_NAME + PASSWORD follow, we check they are good - if (cmpStrWithZchar((char *)&frame[4], reusableBuffer.moduleSetup.pxx2.registerRxName, PXX2_LEN_RX_NAME) && - cmpStrWithZchar((char *)&frame[12], g_model.modelRegistrationID, PXX2_LEN_REGISTRATION_ID)) { + if (memcmp(&frame[4], reusableBuffer.moduleSetup.pxx2.registerRxName, PXX2_LEN_RX_NAME) == 0 && + memcmp(&frame[12], g_model.modelRegistrationID, PXX2_LEN_REGISTRATION_ID) == 0) { reusableBuffer.moduleSetup.pxx2.registerStep = REGISTER_OK; moduleState[module].mode = MODULE_MODE_NORMAL; #if !defined(COLORLCD) diff --git a/radio/src/telemetry/frsky_sport.cpp b/radio/src/telemetry/frsky_sport.cpp index f946f3c67..f1de5bd23 100644 --- a/radio/src/telemetry/frsky_sport.cpp +++ b/radio/src/telemetry/frsky_sport.cpp @@ -130,7 +130,7 @@ uint16_t rboxState; void sportProcessTelemetryPacket(uint16_t id, uint8_t subId, uint8_t instance, uint32_t data, TelemetryUnit unit=UNIT_RAW) { const FrSkySportSensor * sensor = getFrSkySportSensor(id, subId); - uint8_t precision = 0; + uint8_t precision = 255; if (sensor) { if (unit == UNIT_RAW) unit = sensor->unit; @@ -177,17 +177,20 @@ void sportProcessTelemetryPacketWithoutCrc(uint8_t origin, const uint8_t * packe if (primId == DATA_FRAME) { uint8_t originMask; + uint8_t moduleIndex; if (origin == TELEMETRY_ENDPOINT_SPORT) { #if defined(SIMU) && defined(INTERNAL_MODULE_PXX2) // When running simu on ACCESS radio, we set the origin as internal module + moduleIndex = 0; origin = 0; originMask = 0x01; #else + moduleIndex = isSportLineUsedByInternalModule() ? 0 : 1; originMask = 0x04; #endif } else { - uint8_t moduleIndex = (origin >> 2); + moduleIndex = (origin >> 2); originMask = 0x01 << moduleIndex; } uint8_t instance = physicalId + (origin << 5); @@ -226,12 +229,12 @@ void sportProcessTelemetryPacketWithoutCrc(uint8_t origin, const uint8_t * packe else if (dataId == XJT_VERSION_ID) { telemetryData.xjtVersion = HUB_DATA_U16(packet); if (!isRasValueValid()) { - telemetryData.setSwr(origin >> 2, 0); + telemetryData.setSwr(moduleIndex, 0); } } else if (dataId == RAS_ID) { if (isRasValueValid()) { - telemetryData.setSwr(origin >> 2, SPORT_DATA_U8(packet)); + telemetryData.setSwr(moduleIndex, SPORT_DATA_U8(packet)); } } diff --git a/radio/src/telemetry/multi.cpp b/radio/src/telemetry/multi.cpp index e720776a4..2b55eeadd 100644 --- a/radio/src/telemetry/multi.cpp +++ b/radio/src/telemetry/multi.cpp @@ -322,6 +322,12 @@ static void processMultiTelemetryPaket(const uint8_t * packet, uint8_t module) auxSerialPutc(packet[c]); } #endif +#if defined(AUX2_SERIAL) + if (g_eeGeneral.aux2SerialMode == UART_MODE_TELEMETRY_MIRROR) { + for (uint8_t c=0; c < len; c++) + aux2SerialPutc(packet[c]); + } +#endif // Switch type switch (type) { @@ -555,7 +561,7 @@ void MultiModuleStatus::getStatusString(char * statusText) const return; } - if (major <= 1 && minor <= 3 && revision <= 0 && patch <= 47 && SLOW_BLINK_ON_PHASE) { + if (major <= 1 && minor <= 3 && revision <= 0 && patch < 91 && SLOW_BLINK_ON_PHASE) { strcpy(statusText, STR_MODULE_UPGRADE); } else { diff --git a/radio/src/telemetry/spektrum.cpp b/radio/src/telemetry/spektrum.cpp index f241cc332..8e2791540 100644 --- a/radio/src/telemetry/spektrum.cpp +++ b/radio/src/telemetry/spektrum.cpp @@ -24,6 +24,7 @@ /* * Documentation of the Spektrum protocol is available under * https://www.spektrumrc.com/ProdInfo/Files/SPM_Telemetry_Developers_Specs.pdf + * https://github.com/SpektrumRC/SpektrumDocumentation/blob/master/Telemetry/spektrumTelemetrySensors.h * * Multi module adds two byte header of 0xAA [RSSI of telemetry packet] [16 byte message] */ @@ -49,7 +50,18 @@ #define I2C_TEXTGEN 0x0c #define I2C_GPS 0x17 #define I2C_GPS2 0x17 +#define I2C_ESC 0x20 #define I2C_CELLS 0x3a + +// SMART_BAT is using fake I2C adresses compared to official Spektrum address because of subtype used only for this I2C address +#define I2C_SMART_BAT_BASE_ADDRESS 0x42 +#define I2C_SMART_BAT_REALTIME 0x42 +#define I2C_SMART_BAT_CELLS_1_6 0x43 +#define I2C_SMART_BAT_CELLS_7_12 0x44 +#define I2C_SMART_BAT_CELLS_13_18 0x45 +#define I2C_SMART_BAT_ID 0x4A +#define I2C_SMART_BAT_LIMITS 0x4B + #define I2C_QOS 0x7f enum SpektrumDataType : uint8_t { @@ -62,6 +74,8 @@ enum SpektrumDataType : uint8_t { uint8bcd, uint16bcd, uint32bcd, + uint16le, + uint32le, custom }; @@ -151,7 +165,16 @@ const SpektrumSensor spektrumSensors[] = { {0x1b, 2, int16, STR_SENSOR_PITCH, UNIT_DEGREE, 1}, {0x1b, 4, int16, STR_SENSOR_YAW, UNIT_DEGREE, 1}, - // {0x20, esc}, does not exist in the wild? + // {0x20, esc}, Smart ESC telemetry + {I2C_ESC, 0, uint16, ZSTR_ESC_RPM, UNIT_RPMS, 0}, + {I2C_ESC, 2, uint16, ZSTR_ESC_VIN, UNIT_VOLTS, 2}, + {I2C_ESC, 4, uint16, ZSTR_ESC_TFET, UNIT_CELSIUS, 1}, + {I2C_ESC, 6, uint16, ZSTR_ESC_CUR, UNIT_MAH, 1}, + {I2C_ESC, 8, uint16, ZSTR_ESC_TBEC, UNIT_CELSIUS, 1}, + {I2C_ESC, 10, uint8, ZSTR_ESC_BCUR, UNIT_AMPS, 1}, + {I2C_ESC, 11, uint8, ZSTR_ESC_VBEC, UNIT_VOLTS, 2}, + {I2C_ESC, 12, uint8, ZSTR_ESC_THR, UNIT_PERCENT, 1}, + {I2C_ESC, 13, uint8, ZSTR_ESC_POUT, UNIT_PERCENT, 1}, // Dual Cell monitor (0x34) {0x34, 0, int16, STR_SENSOR_BATT1_CURRENT, UNIT_AMPS, 1}, @@ -178,6 +201,53 @@ const SpektrumSensor spektrumSensors[] = { {0x40, 0, int16, STR_SENSOR_ALT, UNIT_METERS, 1}, {0x40, 2, int16, STR_SENSOR_VSPD, UNIT_METERS_PER_SECOND, 1}, + // Smartbat + //{I2C_SMART_BAT_REALTIME, 1, int8, ZSTR_SMART_BAT_BTMP, UNIT_CELSIUS, 0}, // disabled because sensor is a duplicate of cells sensors ones + {I2C_SMART_BAT_REALTIME, 2, uint32le, ZSTR_SMART_BAT_BCUR, UNIT_MAH, 0}, + {I2C_SMART_BAT_REALTIME, 6, uint16le, ZSTR_SMART_BAT_BCAP, UNIT_MAH, 0}, + {I2C_SMART_BAT_REALTIME, 8, uint16le, ZSTR_SMART_BAT_MIN_CEL, UNIT_VOLTS, 2}, + {I2C_SMART_BAT_REALTIME, 10, uint16le, ZSTR_SMART_BAT_MAX_CEL, UNIT_VOLTS, 2}, + //{I2C_SMART_BAT_REALTIME, 12, uint16le, "RFU[2]", UNIT_RAW, 0}, // disabled to save sensors slots + + {I2C_SMART_BAT_CELLS_1_6, 1, int8, ZSTR_SMART_BAT_BTMP, UNIT_CELSIUS, 0}, + {I2C_SMART_BAT_CELLS_1_6, 2, uint16le, ZSTR_CL01, UNIT_VOLTS, 2}, + {I2C_SMART_BAT_CELLS_1_6, 4, uint16le, ZSTR_CL02, UNIT_VOLTS, 2}, + {I2C_SMART_BAT_CELLS_1_6, 6, uint16le, ZSTR_CL03, UNIT_VOLTS, 2}, + {I2C_SMART_BAT_CELLS_1_6, 8, uint16le, ZSTR_CL04, UNIT_VOLTS, 2}, + {I2C_SMART_BAT_CELLS_1_6, 10, uint16le, ZSTR_CL05, UNIT_VOLTS, 2}, + {I2C_SMART_BAT_CELLS_1_6, 12, uint16le, ZSTR_CL06, UNIT_VOLTS, 2}, + + {I2C_SMART_BAT_CELLS_7_12, 1, int8, ZSTR_SMART_BAT_BTMP, UNIT_CELSIUS, 0}, + {I2C_SMART_BAT_CELLS_7_12, 2, uint16le, ZSTR_CL07, UNIT_VOLTS, 2}, + {I2C_SMART_BAT_CELLS_7_12, 4, uint16le, ZSTR_CL08, UNIT_VOLTS, 2}, + {I2C_SMART_BAT_CELLS_7_12, 6, uint16le, ZSTR_CL09, UNIT_VOLTS, 2}, + {I2C_SMART_BAT_CELLS_7_12, 8, uint16le, ZSTR_CL10, UNIT_VOLTS, 2}, + {I2C_SMART_BAT_CELLS_7_12, 10, uint16le, ZSTR_CL11, UNIT_VOLTS, 2}, + {I2C_SMART_BAT_CELLS_7_12, 12, uint16le, ZSTR_CL12, UNIT_VOLTS, 2}, + + {I2C_SMART_BAT_CELLS_13_18, 1, int8, ZSTR_SMART_BAT_BTMP, UNIT_CELSIUS, 0}, + {I2C_SMART_BAT_CELLS_13_18, 2, uint16le, ZSTR_CL13, UNIT_VOLTS, 2}, + {I2C_SMART_BAT_CELLS_13_18, 4, uint16le, ZSTR_CL14, UNIT_VOLTS, 2}, + {I2C_SMART_BAT_CELLS_13_18, 6, uint16le, ZSTR_CL15, UNIT_VOLTS, 2}, + {I2C_SMART_BAT_CELLS_13_18, 8, uint16le, ZSTR_CL16, UNIT_VOLTS, 2}, + {I2C_SMART_BAT_CELLS_13_18, 10, uint16le, ZSTR_CL17, UNIT_VOLTS, 2}, + {I2C_SMART_BAT_CELLS_13_18, 12, uint16le, ZSTR_CL18, UNIT_VOLTS, 2}, + + //{I2C_SMART_BAT_ID, 1, uint8, "chemistery", UNIT_RAW, 0}, // disabled to save sensors slots + //{I2C_SMART_BAT_ID, 2, uint8, "number of cells", UNIT_RAW, 0}, // disabled to save sensors slots + //{I2C_SMART_BAT_ID, 3, uint8, "manufacturer code", UNIT_RAW, 0}, // disabled to save sensors slots + {I2C_SMART_BAT_ID, 4, uint16le, ZSTR_SMART_BAT_CYCLES, UNIT_RAW, 0}, + //{I2C_SMART_BAT_ID, 6, uint8, "uniqueID[8]", UNIT_RAW, 0}, // disabled to save sensors slots + + //{I2C_SMART_BAT_LIMITS, 1, uint8, "rfu", UNIT_RAW, 0}, // disabled to save sensors slots + {I2C_SMART_BAT_LIMITS, 2, uint16le, ZSTR_SMART_BAT_CAPACITY,UNIT_MAH, 0}, + //{I2C_SMART_BAT_LIMITS, 4, uint16le, "dischargeCurrentRating", UNIT_RAW, 0}, // disabled to save sensors slots + //{I2C_SMART_BAT_LIMITS, 6, uint16le, "overDischarge_mV", UNIT_RAW, 0}, // disabled to save sensors slots + //{I2C_SMART_BAT_LIMITS, 8, uint16le, "zeroCapacity_mV", UNIT_RAW, 0}, // disabled to save sensors slots + //{I2C_SMART_BAT_LIMITS, 10, uint16le, "fullyCharged_mV", UNIT_RAW, 0}, // disabled to save sensors slots + //{I2C_SMART_BAT_LIMITS, 12, uint8, "minWorkingTemp", UNIT_RAW, 0}, // disabled to save sensors slots + //{I2C_SMART_BAT_LIMITS, 13, uint8, "maxWorkingTemp", UNIT_RAW, 0}, // disabled to save sensors slots + // 0x50-0x56 custom 3rd party sensors //{0x50, 0, int16, STR_SENSOR_} @@ -248,6 +318,10 @@ static int32_t spektrumGetValue(const uint8_t *packet, int startByte, SpektrumDa return bcdToInt8(*(uint8_t *)data); case uint32bcd: return bcdToInt32(*(uint32_t *)data); + case uint16le: + return (int16_t) ((uint16_t) (data[0] + (data[1] << 8))); + case uint32le: + return ((uint32_t) (data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24))); default: return -1; } @@ -274,6 +348,12 @@ void processSpektrumPacket(const uint8_t *packet) setTelemetryValue(PROTOCOL_TELEMETRY_SPEKTRUM, (I2C_PSEUDO_TX << 8) + 0, 0, 0, packet[1], UNIT_RAW, 0); // highest bit indicates that TM1100 is in use, ignore it uint8_t i2cAddress = (packet[2] & 0x7f); + + //SmartBat Hack + if (i2cAddress == I2C_SMART_BAT_BASE_ADDRESS) { + i2cAddress = i2cAddress + (packet[4] >> 4); // use type to create virtual I2CAddresses + } + uint8_t instance = packet[3]; if (i2cAddress == I2C_TEXTGEN) { @@ -303,6 +383,41 @@ void processSpektrumPacket(const uint8_t *packet) if (!isSpektrumValidValue(value, sensor->dataType)) continue; + // mV to VOLT PREC2 for Smart Batteries + if ((i2cAddress >= I2C_SMART_BAT_REALTIME && i2cAddress <= I2C_SMART_BAT_LIMITS) && sensor->unit == UNIT_VOLTS) { + if (value == -1) { + continue; // discard unavailable sensors + } + else { + value = value / 10; + } + } + + // RPM, 10RPM (0-655340 RPM) + if (i2cAddress == I2C_ESC && sensor->unit == UNIT_RPMS) { + value = value / 10; + } + + // Current, 10mA (0-655.34A) + if (i2cAddress == I2C_ESC && sensor->startByte == 6) { + value = value / 10; + } + + // BEC Current, 100mA (0-25.4A) + if (i2cAddress == I2C_ESC && sensor->startByte == 10) { + value = value / 10; + } + + // Throttle 0.5% (0-127%) + if (i2cAddress == I2C_ESC && sensor->startByte == 12) { + value = value / 2; + } + + // Power 0.5% (0-127%) + if (i2cAddress == I2C_ESC && sensor->startByte == 13) { + value = value / 2; + } + if (i2cAddress == I2C_CELLS && sensor->unit == UNIT_VOLTS) { // Map to FrSky style cell values int cellIndex = (sensor->startByte / 2) << 16; diff --git a/radio/src/telemetry/telemetry.h b/radio/src/telemetry/telemetry.h index bdd90219d..1de358705 100644 --- a/radio/src/telemetry/telemetry.h +++ b/radio/src/telemetry/telemetry.h @@ -110,8 +110,11 @@ void frskyDSetDefault(int index, uint16_t id); extern uint8_t telemetryProtocol; #if defined (MULTIMODULE) - #define IS_D16_MULTI(module) ((g_model.moduleData[module].getMultiProtocol() == MODULE_SUBTYPE_MULTI_FRSKY) && (g_model.moduleData[module].subType == MM_RF_FRSKY_SUBTYPE_D16 || g_model.moduleData[module].subType == MM_RF_FRSKY_SUBTYPE_D16_8CH || g_model.moduleData[module].subType == MM_RF_FRSKY_SUBTYPE_D16_LBT || g_model.moduleData[module].subType == MM_RF_FRSKY_SUBTYPE_D16_LBT_8CH)) + #define IS_D16_MULTI(module) (((g_model.moduleData[module].getMultiProtocol() == MODULE_SUBTYPE_MULTI_FRSKY) && (g_model.moduleData[module].subType == MM_RF_FRSKY_SUBTYPE_D16 || g_model.moduleData[module].subType == MM_RF_FRSKY_SUBTYPE_D16_8CH || g_model.moduleData[module].subType == MM_RF_FRSKY_SUBTYPE_D16_LBT || g_model.moduleData[module].subType == MM_RF_FRSKY_SUBTYPE_D16_LBT_8CH || g_model.moduleData[module].subType == MM_RF_FRSKY_SUBTYPE_D16_CLONED)) \ + || (g_model.moduleData[module].getMultiProtocol() == MODULE_SUBTYPE_MULTI_FRSKYX2)) #define IS_HOTT_MULTI(module) (g_model.moduleData[module].getMultiProtocol() == MODULE_SUBTYPE_MULTI_HOTT) + #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) #define IS_FRSKY_SPORT_PROTOCOL() (telemetryProtocol == PROTOCOL_TELEMETRY_FRSKY_SPORT || (telemetryProtocol == PROTOCOL_TELEMETRY_MULTIMODULE && (IS_D16_MULTI(INTERNAL_MODULE)||IS_D16_MULTI(EXTERNAL_MODULE)))) #else @@ -121,6 +124,7 @@ extern uint8_t telemetryProtocol; #define IS_D16_MULTI(module) false #define IS_HOTT_MULTI(module) false #define IS_FRSKY_SPORT_PROTOCOL() (telemetryProtocol == PROTOCOL_TELEMETRY_FRSKY_SPORT) + #define IS_RX_MULTI(module) false #endif #define IS_SPEKTRUM_PROTOCOL() (telemetryProtocol == PROTOCOL_TELEMETRY_SPEKTRUM) diff --git a/radio/src/telemetry/telemetry_sensors.cpp b/radio/src/telemetry/telemetry_sensors.cpp index dc9742b55..66b0e2255 100644 --- a/radio/src/telemetry/telemetry_sensors.cpp +++ b/radio/src/telemetry/telemetry_sensors.cpp @@ -82,6 +82,10 @@ void TelemetryItem::setValue(const TelemetrySensor & sensor, int32_t val, uint32 { int32_t newVal = val; + if(prec == 255) { + prec = sensor.prec; + } + if (unit == UNIT_CELLS) { uint32_t data = uint32_t(newVal); uint8_t cellsCount = (data >> 24); diff --git a/radio/src/tests/fonts_480x272.png b/radio/src/tests/fonts_480x272.png index da2ac09d3..c47657715 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/lcd_480x272.cpp b/radio/src/tests/lcd_480x272.cpp index 08877d4e5..42d20fb8a 100644 --- a/radio/src/tests/lcd_480x272.cpp +++ b/radio/src/tests/lcd_480x272.cpp @@ -167,6 +167,12 @@ TEST(Lcd_colorlcd, fonts) lcdDrawText(30, 200, "The quick brown fox", DEFAULT_COLOR|VERTICAL); // lcdDrawText(50, 200, "The quick brown fox jumps over the lazy dog", DEFAULT_COLOR|VERTICAL); + lcdDrawText(50, 25, "The quick", TEXT_COLOR|TINSIZE); + lcdDrawText(50, 40, "The quick", TEXT_COLOR|SMLSIZE); + lcdDrawText(50, 55, "The quick", TEXT_COLOR|MIDSIZE); + lcdDrawText(50, 80, "The quick", TEXT_COLOR|DBLSIZE); + lcdDrawText(50, 120, "The quick", TEXT_COLOR|XXLSIZE); + lcdDrawText(8, 208, "The quick brown fox jumps over the lazy dog", TITLE_BGCOLOR|OPACITY(4)); lcdDrawText(5, 205, "The quick brown fox jumps over the lazy dog", TITLE_BGCOLOR|OPACITY(12)); diff --git a/radio/src/tests/primitives_480x272.png b/radio/src/tests/primitives_480x272.png index ae3f0b94f..38630592f 100644 Binary files a/radio/src/tests/primitives_480x272.png and b/radio/src/tests/primitives_480x272.png differ diff --git a/radio/src/tests/transparency_480x272.png b/radio/src/tests/transparency_480x272.png index b8fec6660..05845c138 100644 Binary files a/radio/src/tests/transparency_480x272.png and b/radio/src/tests/transparency_480x272.png differ diff --git a/radio/src/thirdparty/Lua/src/lauxlib.h b/radio/src/thirdparty/Lua/src/lauxlib.h index aab96bd1c..9cd4c02d3 100644 --- a/radio/src/thirdparty/Lua/src/lauxlib.h +++ b/radio/src/thirdparty/Lua/src/lauxlib.h @@ -29,6 +29,7 @@ extern const luaL_Reg mathlib[]; extern const luaL_Reg bitlib[]; extern const luaL_Reg iolib[]; extern const luaL_Reg strlib[]; +extern const luaL_Reg tab_funcs[]; extern const luaL_Reg opentxLib[]; extern const luaL_Reg lcdLib[]; diff --git a/radio/src/thirdparty/Lua/src/linit.c b/radio/src/thirdparty/Lua/src/linit.c index 940790e3d..4706a3ab7 100644 --- a/radio/src/thirdparty/Lua/src/linit.c +++ b/radio/src/thirdparty/Lua/src/linit.c @@ -28,7 +28,9 @@ */ static const luaL_Reg loadedlibs[] = { // {"_G", luaopen_base}, - // {LUA_LOADLIBNAME, luaopen_package}, +#if defined(PCBHORUS) + {LUA_LOADLIBNAME, luaopen_package}, +#endif // {LUA_COLIBNAME, luaopen_coroutine}, // {LUA_TABLIBNAME, luaopen_table}, {LUA_IOLIBNAME, luaopen_io}, @@ -51,6 +53,9 @@ const luaR_table lua_rotable[] = {LUA_STRLIBNAME, strlib, NULL}, {LUA_MATHLIBNAME, mathlib, mathlib_vals}, {LUA_BITLIBNAME, bitlib, NULL}, +#if defined(PCBHORUS) + {LUA_TABLIBNAME, tab_funcs, NULL}, +#endif {NULL, NULL, NULL} }; diff --git a/radio/src/thirdparty/Lua/src/ltablib.c b/radio/src/thirdparty/Lua/src/ltablib.c index c61903b08..d545a5325 100644 --- a/radio/src/thirdparty/Lua/src/ltablib.c +++ b/radio/src/thirdparty/Lua/src/ltablib.c @@ -256,7 +256,7 @@ static int sort (lua_State *L) { /* }====================================================== */ -static const luaL_Reg tab_funcs[] = { +const luaL_Reg tab_funcs[] = { {"concat", tconcat}, #if defined(LUA_COMPAT_MAXN) {"maxn", maxn}, diff --git a/radio/src/thirdparty/libopenui b/radio/src/thirdparty/libopenui index 0f1183d95..ec8dc7b3f 160000 --- a/radio/src/thirdparty/libopenui +++ b/radio/src/thirdparty/libopenui @@ -1 +1 @@ -Subproject commit 0f1183d95601b0782bc10be983b4f7f4ef11bbe3 +Subproject commit ec8dc7b3f152f547f7d65f20ed7cee85f71ab1c5 diff --git a/radio/src/touch.h b/radio/src/touch.h index 31bf94f58..e95f199cf 100644 --- a/radio/src/touch.h +++ b/radio/src/touch.h @@ -2,7 +2,7 @@ * Copyright (C) OpenTX * * Based on code named - * th9x - http://code.google.com/p/th9x + * th9x - http://code.google.com/p/th9x * er9x - http://code.google.com/p/er9x * gruvin9x - http://code.google.com/p/gruvin9x * diff --git a/radio/src/translations.cpp b/radio/src/translations.cpp index 05d94a29e..0a9a4b131 100644 --- a/radio/src/translations.cpp +++ b/radio/src/translations.cpp @@ -104,6 +104,10 @@ ISTR(MULTI_PROTOCOLS); ISTR(BLUETOOTH_MODES); #endif +#if defined(PCBHORUS) +ISTR(TEXT_SIZE); +#endif + const char STR_POPUPS_ENTER_EXIT[] = TR_POPUPS_ENTER_EXIT; const char STR_OK[] = TR_OK; const char STR_FREE[] = TR_FREE; @@ -326,6 +330,8 @@ const char STR_RESET_BTN[] = TR_RESET_BTN; const char STR_DEBUG[] = TR_DEBUG; const char STR_KEYS_BTN[] = TR_KEYS_BTN; const char STR_ANALOGS_BTN[] = TR_ANALOGS_BTN; +const char STR_TOUCH_NOTFOUND[] = TR_TOUCH_NOTFOUND; +const char STR_TOUCH_EXIT[] = TR_TOUCH_EXIT; const char STR_CALIBRATION[] = TR_CALIBRATION; const char STR_NO_TOOLS[] = TR_NO_TOOLS; const char STR_NORMAL[] = TR_NORMAL; @@ -671,6 +677,7 @@ const char STR_ALTITUDE[] = TR_ALTITUDE; const char STR_SCALE[] = TR_SCALE; const char STR_VIEW_CHANNELS[] = TR_VIEW_CHANNELS; const char STR_AUX_SERIAL_MODE[] = TR_AUX_SERIAL_MODE; +const char STR_AUX2_SERIAL_MODE[] = TR_AUX2_SERIAL_MODE; const char STR_THROTTLE_LABEL[] = TR_THROTTLE_LABEL; const char STR_SCRIPT[] = TR_SCRIPT; const char STR_INPUTS[] = TR_INPUTS; @@ -697,13 +704,30 @@ const char STR_EXIT[] = TR_EXIT; const char STR_MODULE_RANGE[] = TR_MODULE_RANGE; const char STR_RECEIVER_OPTIONS[] = TR_RECEIVER_OPTIONS; const char STR_SPORT_UPDATE_POWER_MODE[] = TR_SPORT_UPDATE_POWER_MODE; +const char STR_TOUCH_PANEL[] = TR_TOUCH_PANEL; -#if defined(PCBHORUS) +#if defined(COLORLCD) const char STR_ASSIGN_SPLASH[] = TR_ASSIGN_SPLASH; +const char STR_FIRST_CHANNEL[] = TR_FIRST_CHANNEL; +const char STR_FILL_BACKGROUND[] = TR_FILL_BACKGROUND; +const char STR_BG_COLOR[] = TR_BG_COLOR; +const char STR_SLIDERS_TRIMS[] = TR_SLIDERS_TRIMS; +const char STR_SLIDERS[] = TR_SLIDERS; +const char STR_FLIGHT_MODE[] = TR_FLIGHT_MODE; +const char STR_INVALID_FILE[] = TR_INVALID_FILE; +const char STR_TIMER_SOURCE[] = TR_TIMER_SOURCE; +const char STR_SIZE[] = TR_SIZE; +const char STR_SHADOW[] = TR_SHADOW; +const char STR_TEXT[] = TR_TEXT; +const char STR_COLOR[] = TR_COLOR; +const char STR_MAIN_VIEW_X[] = TR_MAIN_VIEW_X; +const char STR_PANEL1_BACKGROUND[] = TR_PANEL1_BACKGROUND; +const char STR_PANEL2_BACKGROUND[] = TR_PANEL2_BACKGROUND; #endif #if !defined(COLORLCD) const char STR_MENUWHENDONE[] = TR_MENUWHENDONE; +const char STR_NO_TELEMETRY_SCREENS[] = TR_NO_TELEMETRY_SCREENS; #endif #if defined(PCBSKY9X) && defined(REVX) @@ -789,6 +813,7 @@ const char STR_DISABLE_CH_MAP[] = TR_DISABLE_CH_MAP; const char STR_DISABLE_TELEM[] = TR_DISABLE_TELEM; const char STR_MULTI_DSM_AUTODTECT[] = TR_MULTI_DSM_AUTODTECT; const char STR_MULTI_LOWPOWER[] = TR_MULTI_LOWPOWER; +const char STR_MULTI_LNA_DISABLE[] = TR_MULTI_LNA_DISABLE; const char STR_MODULE_NO_SERIAL_MODE[] = TR_MODULE_NO_SERIAL_MODE; const char STR_MODULE_NO_INPUT[] = TR_MODULE_NO_INPUT; const char STR_MODULE_WAITFORBIND[] = TR_MODULE_WAITFORBIND; diff --git a/radio/src/translations.h b/radio/src/translations.h index 31ca7eb9d..55bf01d35 100644 --- a/radio/src/translations.h +++ b/radio/src/translations.h @@ -179,6 +179,7 @@ extern const char STR_VSENSORTYPES[]; extern const char STR_VFORMULAS[]; extern const char STR_VPREC[]; extern const char STR_VCELLINDEX[]; +extern const char STR_TOUCH_PANEL[]; #if defined(BLUETOOTH) extern const char STR_BLUETOOTH[]; @@ -198,6 +199,7 @@ extern const char STR_EXIT[]; #if !defined(PCBHORUS) extern const char STR_MENUWHENDONE[]; +extern const char STR_NO_TELEMETRY_SCREENS[]; #endif extern const char STR_FREE[]; @@ -409,6 +411,7 @@ extern const char STR_DISABLE_CH_MAP[]; extern const char STR_DISABLE_TELEM[]; extern const char STR_MULTI_DSM_AUTODTECT[]; extern const char STR_MULTI_LOWPOWER[]; +extern const char STR_MULTI_LNA_DISABLE[]; extern const char STR_MODULE_NO_SERIAL_MODE[]; extern const char STR_MODULE_NO_INPUT[]; extern const char STR_MODULE_WAITFORBIND[]; @@ -512,6 +515,8 @@ extern const char STR_RESET_BTN[]; extern const char STR_DEBUG[]; extern const char STR_KEYS_BTN[]; extern const char STR_ANALOGS_BTN[]; +extern const char STR_TOUCH_NOTFOUND[]; +extern const char STR_TOUCH_EXIT[]; extern const char STR_CALIBRATION[]; extern const char STR_NO_TOOLS[]; extern const char STR_NORMAL[]; @@ -610,8 +615,24 @@ extern const char STR_SCRIPT_KILLED[]; extern const char STR_SCRIPT_ERROR[]; extern const char STR_PLAY_FILE[]; extern const char STR_ASSIGN_BITMAP[]; -#if defined(PCBHORUS) +#if defined(COLORLCD) extern const char STR_ASSIGN_SPLASH[]; +extern const char STR_FIRST_CHANNEL[]; +extern const char STR_FILL_BACKGROUND[]; +extern const char STR_BG_COLOR[]; +extern const char STR_SLIDERS_TRIMS[]; +extern const char STR_SLIDERS[]; +extern const char STR_FLIGHT_MODE[]; +extern const char STR_INVALID_FILE[]; +extern const char STR_TIMER_SOURCE[]; +extern const char STR_TEXT_SIZE[]; +extern const char STR_SIZE[]; +extern const char STR_SHADOW[]; +extern const char STR_TEXT[]; +extern const char STR_COLOR[]; +extern const char STR_MAIN_VIEW_X[]; +extern const char STR_PANEL1_BACKGROUND[]; +extern const char STR_PANEL2_BACKGROUND[]; #endif extern const char STR_EXECUTE_FILE[]; extern const char STR_DELETE_FILE[]; @@ -967,6 +988,7 @@ extern const char STR_SCALE[]; extern const char STR_VIEW_CHANNELS[]; extern const char STR_POTWARNING[]; extern const char STR_AUX_SERIAL_MODE[]; +extern const char STR_AUX2_SERIAL_MODE[]; extern const char STR_THROTTLE_LABEL[]; extern const char STR_SCRIPT[]; extern const char STR_INPUTS[]; diff --git a/radio/src/translations/cn.h.txt b/radio/src/translations/cn.h.txt index b19f01607..a26644a28 100644 --- a/radio/src/translations/cn.h.txt +++ b/radio/src/translations/cn.h.txt @@ -71,6 +71,8 @@ #define TR_AUX_SERIAL_MODES "OFF\0 ""Telem Mirror\0""Telemetry In\0""SBUS Trainer\0""LUA\0 " #endif +#define TR_AUX2_SERIAL_MODE "Serial port 2" + #define LEN_SWTYPES "\006" #define TR_SWTYPES "None\0 ""Toggle""2POS\0 ""3POS\0" @@ -384,6 +386,9 @@ #define LEN_GYROS "\004" #define TR_GYROS "GyrX""GyrY" +#define LEN_TEXT_SIZE "\010" +#define TR_TEXT_SIZE "Standard""Tiny\0 ""Small\0 ""Mid\0 ""Double\0 " + // ZERO TERMINATED STRINGS #if defined(COLORLCD) #define INDENT @@ -556,6 +561,8 @@ #define TR_MODESRC "Mode\006% Source" #define TR_MULTIPLIER "乘数" #define TR_CAL "Cal" +#define TR_TOUCH_NOTFOUND "Touch hardware not found" +#define TR_TOUCH_EXIT "Touch screen to exit" #define TR_CALIBRATION "校准" #define TR_VTRIM "Trim- +" #define TR_BG "BG:" @@ -644,14 +651,15 @@ #define TR_MULTI_RFTUNE TR("Freq tune", "RF Freq. fine tune") #define TR_MULTI_TELEMETRY "Telemetry" #define TR_MULTI_VIDFREQ TR("Vid. freq.", "Video frequency") -#define TR_RF_POWER "RF Power" +#define TR_RF_POWER "RF Power" #define TR_MULTI_FIXEDID TR("FixedID", "Fixed ID") #define TR_MULTI_OPTION TR("Option", "Option value") -#define TR_MULTI_AUTOBIND TR(INDENT "Autobind",INDENT "Bind on channel") +#define TR_MULTI_AUTOBIND TR(INDENT "Bind Ch.", INDENT "Bind on channel") #define TR_DISABLE_CH_MAP TR("No Ch. map", "Disable Ch. map") #define TR_DISABLE_TELEM TR("No Telem", "Disable Telemetry") #define TR_MULTI_DSM_AUTODTECT TR(INDENT "Autodetect", INDENT "Autodetect format") #define TR_MULTI_LOWPOWER TR(INDENT "Low power", INDENT "Low power mode") +#define TR_MULTI_LNA_DISABLE INDENT "LNA disable" #define TR_MODULE_TELEMETRY TR(INDENT "S.Port", INDENT "S.Port link") #define TR_MODULE_TELEM_ON TR("ON", "Enabled") #define TR_DISABLE_INTERNAL TR("Disable int.", "Disable internal RF") @@ -671,7 +679,7 @@ #define TR_BINDING_CH9_16_TELEM_OFF "Ch9-16 Telem OFF" #define TR_PROTOCOL_INVALID TR("Prot. invalid", "Protocol invalid") #define TR_MODULE_STATUS TR(INDENT "Status", INDENT "Module Status") -#define TR_MODULE_SYNC TR(INDENT "Sync", INDENT "Module Sync") +#define TR_MODULE_SYNC TR(INDENT "Sync", INDENT "Proto Sync Status") #define TR_MULTI_SERVOFREQ TR("Servo rate", "Servo update rate") #define TR_MULTI_MAX_THROW TR("Max. Throw", "Enable max. throw") #define TR_MULTI_RFCHAN TR("RF Channel", "Select RF channel") @@ -843,6 +851,8 @@ #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_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: ") @@ -992,6 +1002,7 @@ #define TR_PTS "pts" #define TR_SMOOTH "Smooth" #define TR_COPY_STICKS_TO_OFS TR("Cpy stick->subtrim", "Copy sticks to subtrim") +#define TR_COPY_MIN_MAX_TO_OUTPUTS TR("Cpy min/max to all", "Copy min/max/center to all outputs") #define TR_COPY_TRIMS_TO_OFS TR("Cpy trim->subtrim", "Copy trims to subtrim") #define TR_INCDEC "Inc/Decrement" #define TR_GLOBALVAR "Global var" @@ -1009,6 +1020,12 @@ #define STR_FACTORYRESET "恢复出厂设置" #define TR_CONFIRMRESET TR("Erase ALL", "擦除所有模型和设置数据?") #define TR_TOO_MANY_LUA_SCRIPTS "Lua脚本数量超出!" +#define TR_SPORT_UPDATE_POWER_MODE "SP Power" +#define LEN_SPORT_UPDATE_POWER_MODES "\004" +#define TR_SPORT_UPDATE_POWER_MODES "AUTO""ON\0 " +#define TR_NO_TELEMETRY_SCREENS "No Telemetry Screens" +#define TR_TOUCH_PANEL "Touch panel:" + // Horus and Taranis column headers #define TR_PHASES_HEADERS_NAME "名称" @@ -1052,6 +1069,23 @@ // Horus footer descriptions #define TR_LSW_DESCRIPTIONS { "Comparison type or function", "First variable", "Second variable or constant", "Second variable or constant", "Additional condition for line to be enabled", "Minimum ON duration of the logical switch", "Minimum TRUE duration for the switch to become ON" } +// Horus layouts and widgets +#define TR_FIRST_CHANNEL "First channel" +#define TR_FILL_BACKGROUND "Fill background?" +#define TR_BG_COLOR "BG Color" +#define TR_SLIDERS_TRIMS "Sliders+Trims" +#define TR_SLIDERS "Sliders" +#define TR_FLIGHT_MODE "Flight mode" +#define TR_INVALID_FILE "Invalid File" +#define TR_TIMER_SOURCE "Timer source" +#define TR_SIZE "Size" +#define TR_SHADOW "Shadow" +#define TR_TEXT "Text" +#define TR_COLOR "Color" +#define TR_MAIN_VIEW_X "Main view X" +#define TR_PANEL1_BACKGROUND "Panel1 background" +#define TR_PANEL2_BACKGROUND "Panel2 background" + // About screen #define TR_ABOUTUS TR(" ABOUT ", "ABOUT") @@ -1165,7 +1199,7 @@ #define TR_SETUP "Setup" #define TR_MAINVIEWX "Main view X" #define TR_LAYOUT "Layout" -#define TR_ADD_MAIN_VIEW "Add main view" +#define TR_ADD_MAIN_VIEW "Add main view" #define TR_BACKGROUND_COLOR "Background color" #define TR_MAIN_COLOR "Main color" #define TR_TEXT_VIEWER "Text Viewer" @@ -1188,3 +1222,149 @@ #define TR_JITTER_FILTER "ADC filter" #define TR_RTC_CHECK TR("Check RTC", "Check RTC voltage") #define TR_AUTH_FAILURE "Auth-failure" + +#define ZSTR_FLR "FLR" +#define ZSTR_RSSI "RSSI" +#define ZSTR_R9PW "R9PW" +#define ZSTR_RAS "SWR" +#define ZSTR_A1 "A1" +#define ZSTR_A2 "A2" +#define ZSTR_A3 "A3" +#define ZSTR_A4 "A4" +#define ZSTR_BATT "RxBt" +#define ZSTR_ALT "Alt" +#define ZSTR_TEMP1 "Tmp1" +#define ZSTR_TEMP2 "Tmp2" +#define ZSTR_TEMP3 "Tmp3" +#define ZSTR_TEMP4 "Tmp4" +#define ZSTR_RPM2 "RPM2" +#define ZSTR_PRES "Pres" +#define ZSTR_ODO1 "Odo1" +#define ZSTR_ODO2 "Odo2" +#define ZSTR_TXV "TX_V" +#define ZSTR_CURR_SERVO1 "CSv1" +#define ZSTR_CURR_SERVO2 "CSv2" +#define ZSTR_CURR_SERVO3 "CSv3" +#define ZSTR_CURR_SERVO4 "CSv4" +#define ZSTR_DIST "Dist" +#define ZSTR_ARM "Arm" +#define ZSTR_C50 "C50" +#define ZSTR_C200 "C200" +#define ZSTR_RPM "RPM" +#define ZSTR_FUEL "Fuel" +#define ZSTR_VSPD "VSpd" +#define ZSTR_ACCX "AccX" +#define ZSTR_ACCY "AccY" +#define ZSTR_ACCZ "AccZ" +#define ZSTR_GYROX "GYRX" +#define ZSTR_GYROY "GYRY" +#define ZSTR_GYROZ "GYRZ" +#define ZSTR_CURR "Curr" +#define ZSTR_CAPACITY "Capa" +#define ZSTR_VFAS "VFAS" +#define ZSTR_BATT_PERCENT "Bat%" +#define ZSTR_ASPD "ASpd" +#define ZSTR_GSPD "GSpd" +#define ZSTR_HDG "Hdg" +#define ZSTR_SATELLITES "Sats" +#define ZSTR_CELLS "Cels" +#define ZSTR_GPSALT "GAlt" +#define ZSTR_GPSDATETIME "Date" +#define ZSTR_GPS "GPS" +#define ZSTR_BATT1_VOLTAGE "RB1V" +#define ZSTR_BATT2_VOLTAGE "RB2V" +#define ZSTR_BATT1_CURRENT "RB1A" +#define ZSTR_BATT2_CURRENT "RB2A" +#define ZSTR_BATT1_CONSUMPTION "RB1C" +#define ZSTR_BATT2_CONSUMPTION "RB2C" +#define ZSTR_BATT1_TEMP "RB1T" +#define ZSTR_BATT2_TEMP "RB2T" +#define ZSTR_RB_STATE "RBS" +#define ZSTR_CHANS_STATE "RBCS" +#define ZSTR_RX_RSSI1 "1RSS" +#define ZSTR_RX_RSSI2 "2RSS" +#define ZSTR_RX_QUALITY "RQly" +#define ZSTR_RX_SNR "RSNR" +#define ZSTR_RX_NOISE "RNse" +#define ZSTR_ANTENNA "ANT" +#define ZSTR_RF_MODE "RFMD" +#define ZSTR_TX_POWER "TPWR" +#define ZSTR_TX_RSSI "TRSS" +#define ZSTR_TX_QUALITY "TQly" +#define ZSTR_TX_SNR "TSNR" +#define ZSTR_TX_NOISE "TNse" +#define ZSTR_PITCH "Ptch" +#define ZSTR_ROLL "Roll" +#define ZSTR_YAW "Yaw" +#define ZSTR_FLIGHT_MODE "FM" +#define ZSTR_THROTTLE "Thr" +#define ZSTR_QOS_A "FdeA" +#define ZSTR_QOS_B "FdeB" +#define ZSTR_QOS_L "FdeL" +#define ZSTR_QOS_R "FdeR" +#define ZSTR_QOS_F "FLss" +#define ZSTR_QOS_H "Hold" +#define ZSTR_BIND "BIND" +#define ZSTR_LAP_NUMBER "Lap " +#define ZSTR_GATE_NUMBER "Gate" +#define ZSTR_LAP_TIME "LapT" +#define ZSTR_GATE_TIME "GteT" +#define ZSTR_ESC_VOLTAGE "EscV" +#define ZSTR_ESC_CURRENT "EscA" +#define ZSTR_ESC_RPM "Erpm" +#define ZSTR_ESC_CONSUMPTION "EscC" +#define ZSTR_ESC_TEMP "EscT" +#define ZSTR_SD1_CHANNEL "Chan" +#define ZSTR_GASSUIT_TEMP1 "GTp1" +#define ZSTR_GASSUIT_TEMP2 "GTp2" +#define ZSTR_GASSUIT_RPM "GRPM" +#define ZSTR_GASSUIT_FLOW "GFlo" +#define ZSTR_GASSUIT_CONS "GFue" +#define ZSTR_GASSUIT_RES_VOL "GRVl" +#define ZSTR_GASSUIT_RES_PERC "GRPc" +#define ZSTR_GASSUIT_MAX_FLOW "GMFl" +#define ZSTR_GASSUIT_AVG_FLOW "GAFl" +#define ZSTR_SBEC_VOLTAGE "BecV" +#define ZSTR_SBEC_CURRENT "BecA" +#define ZSTR_RB3040_EXTRA_STATE "RBES" +#define ZSTR_RB3040_CHANNEL1 "CH1A" +#define ZSTR_RB3040_CHANNEL2 "CH2A" +#define ZSTR_RB3040_CHANNEL3 "CH3A" +#define ZSTR_RB3040_CHANNEL4 "CH4A" +#define ZSTR_RB3040_CHANNEL5 "CH5A" +#define ZSTR_RB3040_CHANNEL6 "CH6A" +#define ZSTR_RB3040_CHANNEL7 "CH7A" +#define ZSTR_RB3040_CHANNEL8 "CH8A" +#define ZSTR_ESC_VIN "EVIN" +#define ZSTR_ESC_TFET "TFET" +#define ZSTR_ESC_CUR "ECUR" +#define ZSTR_ESC_TBEC "TBEC" +#define ZSTR_ESC_BCUR "CBEC" +#define ZSTR_ESC_VBEC "VBEC" +#define ZSTR_ESC_THR "ETHR" +#define ZSTR_ESC_POUT "EOUT" +#define ZSTR_SMART_BAT_BTMP "BTmp" +#define ZSTR_SMART_BAT_BCUR "BCur" +#define ZSTR_SMART_BAT_BCAP "BUse" +#define ZSTR_SMART_BAT_MIN_CEL "CLMi" +#define ZSTR_SMART_BAT_MAX_CEL "CLMa" +#define ZSTR_SMART_BAT_CYCLES "Cycl" +#define ZSTR_SMART_BAT_CAPACITY "BCpT" +#define ZSTR_CL01 "Cel1" +#define ZSTR_CL02 "Cel2" +#define ZSTR_CL03 "Cel3" +#define ZSTR_CL04 "Cel4" +#define ZSTR_CL05 "Cel5" +#define ZSTR_CL06 "Cel6" +#define ZSTR_CL07 "Cel7" +#define ZSTR_CL08 "Cel8" +#define ZSTR_CL09 "Cel9" +#define ZSTR_CL10 "Cl10" +#define ZSTR_CL11 "Cl11" +#define ZSTR_CL12 "Cl12" +#define ZSTR_CL13 "Cl13" +#define ZSTR_CL14 "Cl14" +#define ZSTR_CL15 "Cl15" +#define ZSTR_CL16 "Cl16" +#define ZSTR_CL17 "Cl17" +#define ZSTR_CL18 "Cl18" diff --git a/radio/src/translations/cz.h.txt b/radio/src/translations/cz.h.txt index cd75fd371..20595e331 100644 --- a/radio/src/translations/cz.h.txt +++ b/radio/src/translations/cz.h.txt @@ -376,6 +376,9 @@ #define LEN_GYROS "\004" #define TR_GYROS "GyrX""GyrY" +#define LEN_TEXT_SIZE "\010" +#define TR_TEXT_SIZE "Standard""Tiny\0 ""Small\0 ""Mid\0 ""Double\0 " + // ZERO TERMINATED STRINGS #if defined(COLORLCD) #define INDENT "\007" @@ -642,6 +645,7 @@ #define TR_DISABLE_TELEM TR("No Telem", "Disable Telemetry") #define TR_MULTI_DSM_AUTODTECT TR(INDENT "Autodetekce", INDENT "Formát autodetekce") #define TR_MULTI_LOWPOWER TR(INDENT "Nízký výkon", INDENT "Režim nízkého výkonu") +#define TR_MULTI_LNA_DISABLE INDENT "LNA disable" #define TR_MODULE_TELEMETRY TR(INDENT "S.Port", INDENT "S.Port link") #define TR_MODULE_TELEM_ON TR("Zap", "Zapnuto") #define TR_DISABLE_INTERNAL TR("Vypnout int.", "Vypnout interní RF") @@ -923,6 +927,8 @@ #define TR_DEBUG "Debug" #define TR_KEYS_BTN BUTTON(TR("SW","Přepínače")) #define TR_ANALOGS_BTN BUTTON(TR("Analog","Analogy")) +#define TR_TOUCH_NOTFOUND "Touch hardware not found" +#define TR_TOUCH_EXIT "Touch screen to exit" #define TR_CALIBRATION "Kalibrace" #define TR_SET BUTTON("Nast") #define TR_TRAINER "Trenér" @@ -985,6 +991,7 @@ #define TR_CHECKLIST TR(INDENT "Poznámky", INDENT "Zobrazit poznámky") #define TR_FAS_OFFSET TR(INDENT "FAS Ofs", INDENT "FAS Ofset") #define TR_AUX_SERIAL_MODE "Seriový port" +#define TR_AUX2_SERIAL_MODE "Seriový port 2" #define TR_SCRIPT "Skript" #define TR_INPUTS "Vstupy" #define TR_OUTPUTS "Výstupy" @@ -995,6 +1002,8 @@ #define TR_SPORT_UPDATE_POWER_MODE "SP Power" #define LEN_SPORT_UPDATE_POWER_MODES "\004" #define TR_SPORT_UPDATE_POWER_MODES "AUTO""ON\0 " +#define TR_NO_TELEMETRY_SCREENS "No Telemetry Screens" +#define TR_TOUCH_PANEL "Touch panel:" // Horus and Taranis column headers #define TR_PHASES_HEADERS_NAME "Název" @@ -1038,6 +1047,23 @@ // Horus footer descriptions #define TR_LSW_DESCRIPTIONS { "Typ porovnávací funkce", "První proměnná", "Druhá proměnná nebo konstanta", "Druhá proměnná nebo konstanta", "Další stav povolující tenko spínač", "Minimální doba trvání sepnutého stavu", "Minimální doba platné podmínky pro aktivaci" } +// Horus layouts and widgets +#define TR_FIRST_CHANNEL "First channel" +#define TR_FILL_BACKGROUND "Fill background?" +#define TR_BG_COLOR "BG Color" +#define TR_SLIDERS_TRIMS "Sliders+Trims" +#define TR_SLIDERS "Sliders" +#define TR_FLIGHT_MODE "Flight mode" +#define TR_INVALID_FILE "Invalid File" +#define TR_TIMER_SOURCE "Timer source" +#define TR_SIZE "Size" +#define TR_SHADOW "Shadow" +#define TR_TEXT "Text" +#define TR_COLOR "Color" +#define TR_MAIN_VIEW_X "Main view X" +#define TR_PANEL1_BACKGROUND "Panel1 background" +#define TR_PANEL2_BACKGROUND "Panel2 background" + // Taranis About screen #define TR_ABOUTUS TR(" O nás ", "O nás") @@ -1265,7 +1291,7 @@ #define ZSTR_GATE_TIME "GteT" #define ZSTR_ESC_VOLTAGE "EscV" #define ZSTR_ESC_CURRENT "EscA" -#define ZSTR_ESC_RPM "EscR" +#define ZSTR_ESC_RPM "Erpm" #define ZSTR_ESC_CONSUMPTION "EscC" #define ZSTR_ESC_TEMP "EscT" #define ZSTR_SD1_CHANNEL "Chan" @@ -1289,3 +1315,36 @@ #define ZSTR_RB3040_CHANNEL6 "CH6A" #define ZSTR_RB3040_CHANNEL7 "CH7A" #define ZSTR_RB3040_CHANNEL8 "CH8A" +#define ZSTR_ESC_VIN "EVIN" +#define ZSTR_ESC_TFET "TFET" +#define ZSTR_ESC_CUR "ECUR" +#define ZSTR_ESC_TBEC "TBEC" +#define ZSTR_ESC_BCUR "CBEC" +#define ZSTR_ESC_VBEC "VBEC" +#define ZSTR_ESC_THR "ETHR" +#define ZSTR_ESC_POUT "EOUT" +#define ZSTR_SMART_BAT_BTMP "BTmp" +#define ZSTR_SMART_BAT_BCUR "BCur" +#define ZSTR_SMART_BAT_BCAP "BUse" +#define ZSTR_SMART_BAT_MIN_CEL "CLMi" +#define ZSTR_SMART_BAT_MAX_CEL "CLMa" +#define ZSTR_SMART_BAT_CYCLES "Cycl" +#define ZSTR_SMART_BAT_CAPACITY "BCpT" +#define ZSTR_CL01 "Cel1" +#define ZSTR_CL02 "Cel2" +#define ZSTR_CL03 "Cel3" +#define ZSTR_CL04 "Cel4" +#define ZSTR_CL05 "Cel5" +#define ZSTR_CL06 "Cel6" +#define ZSTR_CL07 "Cel7" +#define ZSTR_CL08 "Cel8" +#define ZSTR_CL09 "Cel9" +#define ZSTR_CL10 "Cl10" +#define ZSTR_CL11 "Cl11" +#define ZSTR_CL12 "Cl12" +#define ZSTR_CL13 "Cl13" +#define ZSTR_CL14 "Cl14" +#define ZSTR_CL15 "Cl15" +#define ZSTR_CL16 "Cl16" +#define ZSTR_CL17 "Cl17" +#define ZSTR_CL18 "Cl18" diff --git a/radio/src/translations/de.h.txt b/radio/src/translations/de.h.txt index 46d715d97..fb6e32efc 100644 --- a/radio/src/translations/de.h.txt +++ b/radio/src/translations/de.h.txt @@ -382,6 +382,9 @@ #define LEN_GYROS "\004" #define TR_GYROS "GyrX""GyrY" +#define LEN_TEXT_SIZE "\010" +#define TR_TEXT_SIZE "Standard""Tiny\0 ""Small\0 ""Mid\0 ""Double\0 " + // ZERO TERMINATED STRINGS #if defined(COLORLCD) #define INDENT " " @@ -650,6 +653,7 @@ #define TR_DISABLE_TELEM TR("No Telem", "Disable Telemetry") #define TR_MULTI_DSM_AUTODTECT TR(INDENT "Autodetect", INDENT "Autodetect format") #define TR_MULTI_LOWPOWER TR(INDENT "Low power", INDENT "Low power mode") +#define TR_MULTI_LNA_DISABLE INDENT "LNA disable" #define TR_MODULE_TELEMETRY TR(INDENT "S.Port", INDENT "S.Port link") #define TR_MODULE_TELEM_ON TR("ON", "Enabled") #define TR_DISABLE_INTERNAL TR("Disable int. RF", "Disable internal RF") @@ -932,6 +936,8 @@ #define TR_DEBUG "Testen" #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_CALIBRATION "Kalibrieren" #define TR_SET BUTTON("Set") #define TR_TRAINER "DSC Buchse PPM In/Out" @@ -998,6 +1004,7 @@ #define TR_CHECKLIST TR(INDENT "Checkliste", INDENT "Checkliste anzeigen") //9XR-Pro #define TR_FAS_OFFSET TR(INDENT "FAS-Ofs", INDENT "FAS-Offset") #define TR_AUX_SERIAL_MODE "Serieller Port" +#define TR_AUX2_SERIAL_MODE "Serieller Port 2" #define TR_SCRIPT "Lua-Skript" #define TR_INPUTS "Eingaben" #define TR_OUTPUTS "Ausgaben" @@ -1008,6 +1015,8 @@ #define TR_SPORT_UPDATE_POWER_MODE "SP Power" #define LEN_SPORT_UPDATE_POWER_MODES "\004" #define TR_SPORT_UPDATE_POWER_MODES "AUTO""ON\0 " +#define TR_NO_TELEMETRY_SCREENS "No Telemetry Screens" +#define TR_TOUCH_PANEL "Touch panel:" // Horus and Taranis specific column headers #define TR_PHASES_HEADERS_NAME "Name " @@ -1020,6 +1029,24 @@ #define TR_PHASES_HEADERS_CH6_TRIM "Trim 6" #define TR_PHASES_HEADERS_FAD_IN "Langs Ein" #define TR_PHASES_HEADERS_FAD_OUT "Langs Aus" + +// Horus layouts and widgets +#define TR_FIRST_CHANNEL "First channel" +#define TR_FILL_BACKGROUND "Fill background?" +#define TR_BG_COLOR "BG Color" +#define TR_SLIDERS_TRIMS "Sliders+Trims" +#define TR_SLIDERS "Sliders" +#define TR_FLIGHT_MODE "Flight mode" +#define TR_INVALID_FILE "Invalid File" +#define TR_TIMER_SOURCE "Timer source" +#define TR_SIZE "Size" +#define TR_SHADOW "Shadow" +#define TR_TEXT "Text" +#define TR_COLOR "Color" +#define TR_MAIN_VIEW_X "Main view X" +#define TR_PANEL1_BACKGROUND "Panel1 background" +#define TR_PANEL2_BACKGROUND "Panel2 background" + // Taranis Info Zeile Anzeigen #define TR_LIMITS_HEADERS_NAME "Name" #define TR_LIMITS_HEADERS_SUBTRIM "Subtrim" @@ -1278,7 +1305,7 @@ #define ZSTR_GATE_TIME "GteT" #define ZSTR_ESC_VOLTAGE "EscV" #define ZSTR_ESC_CURRENT "EscA" -#define ZSTR_ESC_RPM "EscR" +#define ZSTR_ESC_RPM "Erpm" #define ZSTR_ESC_CONSUMPTION "EscC" #define ZSTR_ESC_TEMP "EscT" #define ZSTR_SD1_CHANNEL "Chan" @@ -1302,3 +1329,36 @@ #define ZSTR_RB3040_CHANNEL6 "CH6A" #define ZSTR_RB3040_CHANNEL7 "CH7A" #define ZSTR_RB3040_CHANNEL8 "CH8A" +#define ZSTR_ESC_VIN "EVIN" +#define ZSTR_ESC_TFET "TFET" +#define ZSTR_ESC_CUR "ECUR" +#define ZSTR_ESC_TBEC "TBEC" +#define ZSTR_ESC_BCUR "CBEC" +#define ZSTR_ESC_VBEC "VBEC" +#define ZSTR_ESC_THR "ETHR" +#define ZSTR_ESC_POUT "EOUT" +#define ZSTR_SMART_BAT_BTMP "BTmp" +#define ZSTR_SMART_BAT_BCUR "BCur" +#define ZSTR_SMART_BAT_BCAP "BUse" +#define ZSTR_SMART_BAT_MIN_CEL "CLMi" +#define ZSTR_SMART_BAT_MAX_CEL "CLMa" +#define ZSTR_SMART_BAT_CYCLES "Cycl" +#define ZSTR_SMART_BAT_CAPACITY "BCpT" +#define ZSTR_CL01 "Cel1" +#define ZSTR_CL02 "Cel2" +#define ZSTR_CL03 "Cel3" +#define ZSTR_CL04 "Cel4" +#define ZSTR_CL05 "Cel5" +#define ZSTR_CL06 "Cel6" +#define ZSTR_CL07 "Cel7" +#define ZSTR_CL08 "Cel8" +#define ZSTR_CL09 "Cel9" +#define ZSTR_CL10 "Cl10" +#define ZSTR_CL11 "Cl11" +#define ZSTR_CL12 "Cl12" +#define ZSTR_CL13 "Cl13" +#define ZSTR_CL14 "Cl14" +#define ZSTR_CL15 "Cl15" +#define ZSTR_CL16 "Cl16" +#define ZSTR_CL17 "Cl17" +#define ZSTR_CL18 "Cl18" diff --git a/radio/src/translations/en.h.txt b/radio/src/translations/en.h.txt index 9b13ef3bd..bd0c24665 100644 --- a/radio/src/translations/en.h.txt +++ b/radio/src/translations/en.h.txt @@ -381,6 +381,9 @@ #define LEN_GYROS "\004" #define TR_GYROS "GyrX""GyrY" +#define LEN_TEXT_SIZE "\010" +#define TR_TEXT_SIZE "Standard""Tiny\0 ""Small\0 ""Mid\0 ""Double\0 " + // ZERO TERMINATED STRINGS #if defined(COLORLCD) #define INDENT @@ -480,10 +483,10 @@ #define TR_ANTENNA "Antenna" #define TR_NO_INFORMATION TR("No info", "No information") #define TR_MULTPX "Multiplex" -#define TR_DELAYDOWN "Delay dn" +#define TR_DELAYDOWN TR("Delay dn", "Delay down") #define TR_DELAYUP "Delay up" -#define TR_SLOWDOWN "Slow dn" -#define TR_SLOWUP "Slow up" +#define TR_SLOWDOWN TR("Slow dn", "Slow down") +#define TR_SLOWUP "Slow up" #define TR_MIXES "MIXES" #define TR_CV "CV" #if defined(PCBNV14) @@ -641,11 +644,12 @@ #define TR_RF_POWER "RF Power" #define TR_MULTI_FIXEDID TR("FixedID", "Fixed ID") #define TR_MULTI_OPTION TR("Option", "Option value") -#define TR_MULTI_AUTOBIND TR(INDENT "Bind Ch.",INDENT "Bind on channel") +#define TR_MULTI_AUTOBIND TR(INDENT "Bind Ch.", INDENT "Bind on channel") #define TR_DISABLE_CH_MAP TR("No Ch. map", "Disable Ch. map") #define TR_DISABLE_TELEM TR("No Telem", "Disable Telemetry") #define TR_MULTI_DSM_AUTODTECT TR(INDENT "Autodetect", INDENT "Autodetect format") #define TR_MULTI_LOWPOWER TR(INDENT "Low power", INDENT "Low power mode") +#define TR_MULTI_LNA_DISABLE INDENT "LNA disable" #define TR_MODULE_TELEMETRY TR(INDENT "S.Port", INDENT "S.Port link") #define TR_MODULE_TELEM_ON TR("ON", "Enabled") #define TR_DISABLE_INTERNAL TR("Disable int.", "Disable internal RF") @@ -929,6 +933,9 @@ #define TR_DEBUG "Debug" #define TR_KEYS_BTN BUTTON(TR("Keys", "Switches")) #define TR_ANALOGS_BTN BUTTON(TR("Anas", "Analogs")) +#define TR_TOUCH_NOTFOUND "Touch hardware not found" +#define TR_TOUCH_EXIT "Touch screen to exit" +#define TR_CALIBRATION "Calibration" #define TR_SET BUTTON("Set") #define TR_TRAINER "Trainer" #define TR_CHANS "Chans" @@ -996,7 +1003,8 @@ #define TR_PREFLIGHT "Preflight Checks" #define TR_CHECKLIST TR(INDENT "Checklist", INDENT "Display checklist") #define TR_FAS_OFFSET TR(INDENT "FAS Ofs", INDENT "FAS offset") -#define TR_AUX_SERIAL_MODE "Serial port" +#define TR_AUX_SERIAL_MODE "Serial port" +#define TR_AUX2_SERIAL_MODE "Serial port 2" #define TR_SCRIPT "Script" #define TR_INPUTS "Inputs" #define TR_OUTPUTS "Outputs" @@ -1007,6 +1015,8 @@ #define TR_SPORT_UPDATE_POWER_MODE "SP Power" #define LEN_SPORT_UPDATE_POWER_MODES "\004" #define TR_SPORT_UPDATE_POWER_MODES "AUTO""ON\0 " +#define TR_NO_TELEMETRY_SCREENS "No Telemetry Screens" +#define TR_TOUCH_PANEL "Touch panel:" // Horus and Taranis column headers #define TR_PHASES_HEADERS_NAME "Name" @@ -1050,6 +1060,23 @@ // Horus footer descriptions #define TR_LSW_DESCRIPTIONS { "Comparison type or function", "First variable", "Second variable or constant", "Second variable or constant", "Additional condition for line to be enabled", "Minimum ON duration of the logical switch", "Minimum TRUE duration for the switch to become ON" } +// Horus layouts and widgets +#define TR_FIRST_CHANNEL "First channel" +#define TR_FILL_BACKGROUND "Fill background?" +#define TR_BG_COLOR "BG Color" +#define TR_SLIDERS_TRIMS "Sliders+Trims" +#define TR_SLIDERS "Sliders" +#define TR_FLIGHT_MODE "Flight mode" +#define TR_INVALID_FILE "Invalid File" +#define TR_TIMER_SOURCE "Timer source" +#define TR_SIZE "Size" +#define TR_SHADOW "Shadow" +#define TR_TEXT "Text" +#define TR_COLOR "Color" +#define TR_MAIN_VIEW_X "Main view X" +#define TR_PANEL1_BACKGROUND "Panel1 background" +#define TR_PANEL2_BACKGROUND "Panel2 background" + // About screen #define TR_ABOUTUS TR(" ABOUT ", "ABOUT") @@ -1275,7 +1302,7 @@ #define ZSTR_GATE_TIME "GteT" #define ZSTR_ESC_VOLTAGE "EscV" #define ZSTR_ESC_CURRENT "EscA" -#define ZSTR_ESC_RPM "EscR" +#define ZSTR_ESC_RPM "Erpm" #define ZSTR_ESC_CONSUMPTION "EscC" #define ZSTR_ESC_TEMP "EscT" #define ZSTR_SD1_CHANNEL "Chan" @@ -1299,3 +1326,36 @@ #define ZSTR_RB3040_CHANNEL6 "CH6A" #define ZSTR_RB3040_CHANNEL7 "CH7A" #define ZSTR_RB3040_CHANNEL8 "CH8A" +#define ZSTR_ESC_VIN "EVIN" +#define ZSTR_ESC_TFET "TFET" +#define ZSTR_ESC_CUR "ECUR" +#define ZSTR_ESC_TBEC "TBEC" +#define ZSTR_ESC_BCUR "CBEC" +#define ZSTR_ESC_VBEC "VBEC" +#define ZSTR_ESC_THR "ETHR" +#define ZSTR_ESC_POUT "EOUT" +#define ZSTR_SMART_BAT_BTMP "BTmp" +#define ZSTR_SMART_BAT_BCUR "BCur" +#define ZSTR_SMART_BAT_BCAP "BUse" +#define ZSTR_SMART_BAT_MIN_CEL "CLMi" +#define ZSTR_SMART_BAT_MAX_CEL "CLMa" +#define ZSTR_SMART_BAT_CYCLES "Cycl" +#define ZSTR_SMART_BAT_CAPACITY "BCpT" +#define ZSTR_CL01 "Cel1" +#define ZSTR_CL02 "Cel2" +#define ZSTR_CL03 "Cel3" +#define ZSTR_CL04 "Cel4" +#define ZSTR_CL05 "Cel5" +#define ZSTR_CL06 "Cel6" +#define ZSTR_CL07 "Cel7" +#define ZSTR_CL08 "Cel8" +#define ZSTR_CL09 "Cel9" +#define ZSTR_CL10 "Cl10" +#define ZSTR_CL11 "Cl11" +#define ZSTR_CL12 "Cl12" +#define ZSTR_CL13 "Cl13" +#define ZSTR_CL14 "Cl14" +#define ZSTR_CL15 "Cl15" +#define ZSTR_CL16 "Cl16" +#define ZSTR_CL17 "Cl17" +#define ZSTR_CL18 "Cl18" diff --git a/radio/src/translations/es.h.txt b/radio/src/translations/es.h.txt index 3eccbf397..d710e5b0f 100644 --- a/radio/src/translations/es.h.txt +++ b/radio/src/translations/es.h.txt @@ -19,7 +19,7 @@ * */ -// ES translations author: Jose Moreno +// ES translations authors: Jose Moreno , Daniel GeA /* * !!!!! DO NOT EDIT es.h - EDIT es.h.txt INSTEAD !!!!!!! @@ -49,11 +49,11 @@ #define LEN_MMMINV "\003" #define TR_MMMINV "---""INV" -#define LEN_VBEEPMODE "\005" -#define TR_VBEEPMODE "Mudo ""Alarm""NoKey""Todo " +#define LEN_VBEEPMODE "\010" +#define TR_VBEEPMODE "Silencio""Alarma\0 ""No tecla""Todo\0 " -#define LEN_VBLMODE "\005" -#define TR_VBLMODE "OFF\0 ""Keys\0""Stks\0""Ambos""ON\0" +#define LEN_VBLMODE "\006" +#define TR_VBLMODE "OFF\0 ""Teclas""Sticks""Ambos\0""ON\0 " #define LEN_TRNMODE "\003" #define TR_TRNMODE "OFF""+=\0"":=" @@ -63,13 +63,13 @@ #define LEN_AUX_SERIAL_MODES "\015" #if defined(CLI) || defined(DEBUG) -#define TR_AUX_SERIAL_MODES "Debug\0 ""Telem Mirror\0""Telemetria\0 ""Entrenador SBUS""LUA\0 " +#define TR_AUX_SERIAL_MODES "Debug\0 ""Telem Mirror\0""Telemetría\0 ""Entrenador SBUS""LUA\0 " #else -#define TR_AUX_SERIAL_MODES "OFF\0 ""Telem Mirror\0""Telemetria\0 ""Entrenador SBUS""LUA\0 " +#define TR_AUX_SERIAL_MODES "OFF\0 ""Telem Mirror\0""Telemetría\0 ""Entrenador SBUS""LUA\0 " #endif -#define LEN_SWTYPES "\006" -#define TR_SWTYPES "Nada\0 ""Palanc""2POS\0 ""3POS\0" +#define LEN_SWTYPES "\007" +#define TR_SWTYPES "Nada\0 ""Palanca""2POS\0 ""3POS\0 " #define LEN_POTTYPES TR("\013", "\017") #define TR_POTTYPES TR("Nada\0 ""Pot con fij""Multipos\0 ""Pot\0 ", "Nada\0 ""Pot con fijador""Switch multipos""Pot\0 ") @@ -84,13 +84,13 @@ #define TR_VPERSISTENT "OFF\0 ""Vuelo\0 ""Reset manual" #define LEN_COUNTRY_CODES TR("\002", "\007") -#define TR_COUNTRY_CODES TR("US""JP""EU", "America""Japon\0 ""Europa\0") +#define TR_COUNTRY_CODES TR("US""JP""EU", "América""Japón\0 ""Europa\0") -#define LEN_USBMODES TR("\006", "\008") -#define TR_USBMODES TR("Pregun""Joyst\0""SDCard""Serie\0", "Pregunta""Joystick""SDCard\0 ""Serie\0 ") +#define LEN_USBMODES "\010" +#define TR_USBMODES "Pregunta""Joystick""SDCard\0 ""Serie\0 " -#define LEN_JACK_MODES "\007" -#define TR_JACK_MODES "Pregunt""Audio\0 ""Entrena" +#define LEN_JACK_MODES "\010" +#define TR_JACK_MODES "Pregunta""Audio\0 ""Entrena." #define LEN_TELEMETRY_PROTOCOLS "\017" #define TR_TELEMETRY_PROTOCOLS "FrSky S.PORT\0 ""FrSky D\0 ""FrSky D (cable)""TBS Crossfire\0 ""Spektrum\0 ""AFHDS2A IBUS\0 ""Multi Telemetr." @@ -98,18 +98,18 @@ #define TR_MULTI_CUSTOM "Custom" #define LEN_VTRIMINC TR("\006", "\013") -#define TR_VTRIMINC TR("Expo ""ExFino""Fino ""Medio ""Grueso", "Exponencial""Extra Fino ""Fino ""Medio ""Grueso ") +#define TR_VTRIMINC TR("Expo\0 ""ExFino""Fino\0 ""Medio\0""Grueso", "Exponencial""Extra fino\0""Fino\0 ""Medio\0 ""Grueso\0 ") -#define LEN_VDISPLAYTRIMS "\006" -#define TR_VDISPLAYTRIMS "No\0 ""Cambiar""Si\0 " +#define LEN_VDISPLAYTRIMS "\007" +#define TR_VDISPLAYTRIMS "No\0 ""Cambiar""Si\0 " -#define LEN_VBEEPCOUNTDOWN "\006" -#define TR_VBEEPCOUNTDOWN "SilencBeeps\0Voz\0 Haptic" +#define LEN_VBEEPCOUNTDOWN "\010" +#define TR_VBEEPCOUNTDOWN "Silencio""Beeps\0 ""Voz\0 ""Haptic\0 " #define LEN_COUNTDOWNVALUES "\003" #define TR_COUNTDOWNVALUES "5s\0""10s""20s""30s" -#define LEN_VVARIOCENTER "\008" +#define LEN_VVARIOCENTER "\010" #define TR_VVARIOCENTER "Tono\0 ""Silencio" #define LEN_CURVE_TYPES "\006" @@ -146,21 +146,21 @@ #define LEN_VMIXTRIMS "\003" #if defined(PCBHORUS) - #define TR_VMIXTRIMS "OFF""ON\0""Dir""Ele""Ace""Ale""T5\0""T6\0" + #define TR_VMIXTRIMS "OFF""ON\0""Rud""Ele""Thr""Ail""T5\0""T6\0" #else - #define TR_VMIXTRIMS "OFF""ON\0""Dir""Ele""Ace""Ale" + #define TR_VMIXTRIMS "OFF""ON\0""Rud""Ele""Thr""Ail" #endif -#if defined(PCBTARANIS) +#if LCD_W >= 212 #define TR_CSWTIMER "Timer" - #define TR_CSWSTICKY "Stcky" - #define TR_CSWRANGE "Range" - #define TR_CSWSTAY "Edge\0" + #define TR_CSWSTICKY "Pega\0" + #define TR_CSWRANGE "Rango" + #define TR_CSWSTAY "Borde" #else #define TR_CSWTIMER "Tim\0 " - #define TR_CSWSTICKY "Glue\0" - #define TR_CSWRANGE "Rnge\0" - #define TR_CSWSTAY "Edge\0" + #define TR_CSWSTICKY "Pega\0" + #define TR_CSWRANGE "Rngo\0" + #define TR_CSWSTAY "Bord\0" #endif #define TR_CSWEQUAL "a=x\0 " @@ -177,7 +177,7 @@ #endif #if defined(AUDIO) - #define TR_SOUND "Oir Sonido" + #define TR_SOUND "Oir sonido" #else #define TR_SOUND "Beep\0 " #endif @@ -202,7 +202,7 @@ #define TR_PLAY_VALUE "[OirValor]" #endif -#define TR_SF_BG_MUSIC "BgMusica\0 ""BgMusica||" +#define TR_SF_BG_MUSIC "BgMúsica\0 ""BgMúsica||" #if defined(SDCARD) #define TR_SDCLOGS "SD Logs\0 " @@ -237,57 +237,39 @@ #define TR_SF_SCREENSHOT "Captura" #define TR_SF_RESERVE "[reserv.]\0" -#define TR_VFSWFUNC TR_SF_SAFETY "Entrena.\0 ""Inst. Trim""Reset\0 ""Set \0 " TR_ADJUST_GVAR "Volumen\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 "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_TEST -#define LEN_VFSWRESET TR("\004", "\011") +#define LEN_VFSWRESET TR("\004", "\012") +#define TR_FSW_RESET_TELEM TR("Telm", "Telemetría") -#define TR_FSW_RESET_TELEM TR("Telm", "Telemetria") - -#if defined(PCBTARANIS) +#if LCD_W >= 212 #define TR_FSW_RESET_TIMERS "Timer 1\0 ""Timer 2\0 ""Timer 3\0 " #else #define TR_FSW_RESET_TIMERS "Tmr1""Tmr2""Tmr3" #endif -#define TR_VFSWRESET TR(TR_FSW_RESET_TIMERS "All\0" TR_FSW_RESET_TELEM, TR_FSW_RESET_TIMERS "All\0 " TR_FSW_RESET_TELEM) +#define TR_VFSWRESET TR(TR_FSW_RESET_TIMERS "Todo" TR_FSW_RESET_TELEM, TR_FSW_RESET_TIMERS "Todo\0 " TR_FSW_RESET_TELEM) #define LEN_FUNCSOUNDS TR("\004", "\006") #define TR_FUNCSOUNDS TR("Bp1\0""Bp2\0""Bp3\0""Avs1""Avs2""Chee""Rata""Tick""Sirn""Ring""SciF""Robt""Chrp""Tada""Crck""Alrm", "Beep1 ""Beep2 ""Beep3 ""Aviso1""Aviso2""Cheep ""Ratata""Tick ""Sirena""Ring ""SciFi ""Robot ""Chirp ""Tada ""Crickt""AlmClk") #define LEN_VTELEMCHNS "\004" - #define TR_TELEM_RESERVE TR("[--]", "[---]") - #define TR_TELEM_TIME TR("Time", "Time\0") - #define TR_RAS TR("SWR\0", "SWR\0 ") - #define TR_RX_BATT TR("[NA]", "[NA]\0") - #define TR_A3_A4 TR("A3\0 ""A4\0 ", "A3\0 ""A4\0 ") - #define TR_A3_A4_MIN TR("A3-\0""A4-\0", "A3-\0 ""A4-\0 ") - -#define TR_ASPD_MAX TR("ASp+", "ASpd+") - -#if defined(PCBTARANIS) - #define TR_TELEM_RSSI_RX "RSSI\0" -#else - #define TR_TELEM_RSSI_RX TR("Rx\0 ", "Rx\0 ") -#endif - - #define TR_TELEM_TIMERS TR("Tmr1""Tmr2""Tmr3", "Tmr1\0""Tmr2\0""Tmr3\0") - #define LENGTH_UNIT_IMP "ft\0" #define SPEED_UNIT_IMP "mph" #define LENGTH_UNIT_METR "m\0 " #define SPEED_UNIT_METR "kmh" - #define LEN_VUNITSSYSTEM "\007" - #define TR_VUNITSSYSTEM "Metrico""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 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 STR_V (STR_VTELEMUNIT+1) #define STR_A (STR_VTELEMUNIT+4) -#define LEN_VTELEMSCREENTYPE "\004" -#define TR_VTELEMSCREENTYPE "Nums""Bars" +#define LEN_VTELEMSCREENTYPE "\007" +#define TR_VTELEMSCREENTYPE "Nada\0 ""Números""Barras\0""Script\0" #define LEN_GPSFORMAT "\004" #define TR_GPSFORMAT "HMS NMEA" @@ -326,12 +308,12 @@ #define LEN_VSWITCHES "\003" #define LEN_VSRCRAW "\004" -#define TR_STICKS_VSRCRAW "\307Dir""\307Ele""\307Thr""\307Ale" +#define TR_STICKS_VSRCRAW "\307Rud""\307Ele""\307Thr""\307Ail" #if defined(PCBHORUS) - #define TR_TRIMS_VSRCRAW "\313Dir""\313Ele""\313Thr""\313Ale""\313T5\0""\313T6\0" + #define TR_TRIMS_VSRCRAW "\313Rud""\313Ele""\313Thr""\313Ail""\313T5\0""\313T6\0" #else - #define TR_TRIMS_VSRCRAW TR("TrmD" "TrmE" "TrmT" "TrmA", "\313Dir""\313Ele""\313Thr""\313Ale") + #define TR_TRIMS_VSRCRAW TR("TrmR" "TrmE" "TrmT" "TrmA", "\313Rud""\313Ele""\313Thr""\313Ail") #endif #if defined(PCBHORUS) @@ -372,21 +354,21 @@ #define TR_VTRAINER_MASTER_OFF "Off\0 " #define TR_VTRAINER_MASTER_JACK "Master/Jack\0 " #define TR_VTRAINER_SLAVE_JACK "Esclav/Jack\0 " -#define TR_VTRAINER_MASTER_SBUS_MODULE "Master/Modulo SBUS" -#define TR_VTRAINER_MASTER_CPPM_MODULE "Master/Modulo CPPM" +#define TR_VTRAINER_MASTER_SBUS_MODULE "Master/Módulo SBUS" +#define TR_VTRAINER_MASTER_CPPM_MODULE "Master/Módulo CPPM" #define TR_VTRAINER_MASTER_BATTERY "Master/Serie\0 " #define TR_VTRAINER_BLUETOOTH TR("Master/BT\0 ""Esclavo/BT\0 ", "Master/Bluetooth\0 ""Esclavo/Bluetooth\0") #define TR_VTRAINER_MULTI "Master/Multi" #define LEN_VFAILSAFE "\011" -#define TR_VFAILSAFE "No\0 ""Guardar\0 ""Adaptar\0 ""Sin pulso""Receptor\0" +#define TR_VFAILSAFE "No\0 ""Hold\0 ""Custom\0 ""No pulsos""Receptor\0" #define LEN_VSENSORTYPES "\012" #define TR_VSENSORTYPES "Custom\0 ""Calculado" -#define LEN_VFORMULAS "\010" -#define TR_VFORMULAS "Suma\0 ""Media\0 ""Min\0 ""Max\0 ""Multipl.""Total\0 ""Cell\0 ""Consumo\0""Distanc." +#define LEN_VFORMULAS "\011" +#define TR_VFORMULAS "Suma\0 ""Media\0 ""Min\0 ""Máx\0 ""Multipl. ""Total\0 ""Cell\0 ""Consumo\0 ""Distancia" #define LEN_VPREC "\004" #define TR_VPREC "0.--""0.0 ""0.00" @@ -397,6 +379,9 @@ #define LEN_GYROS "\004" #define TR_GYROS "GyrX""GyrY" +#define LEN_TEXT_SIZE "\013" +#define TR_TEXT_SIZE "Normal\0 ""Muy pequeño""Pequeño\0 ""Medio\0 ""Doble\0 " + // ZERO TERMINATED STRINGS #if defined(COLORLCD) #define INDENT @@ -435,25 +420,25 @@ #define TR_FREE "libre" #define TR_DELETEMODEL "BORRAR MODELO" #define TR_COPYINGMODEL "Copiando modelo.." -#define TR_MOVINGMODEL "Mover modelo..." -#define TR_LOADINGMODEL "Cargar modelo..." +#define TR_MOVINGMODEL "Moviendo modelo..." +#define TR_LOADINGMODEL "Cargando modelo..." #define STR_NAME "Nombre" -#define TR_MODELNAME "Nom.Modelo" -#define TR_PHASENAME "Nom.Fase " -#define TR_MIXNAME "Nom.Mezcla" -#define TR_INPUTNAME TR("N.entr","Nombre entrada") -#define TR_EXPONAME TR("N.expo","Nombre expo") -#define TR_BITMAP "Imagen Modelo" -#define TR_TIMER TR("Reloj","Reloj ") +#define TR_MODELNAME TR("Nom. modelo", "Nombre modelo") +#define TR_PHASENAME "Nombre fase " +#define TR_MIXNAME TR("Nom. mezcla", "Nombre mezcla") +#define TR_INPUTNAME TR("Entrada", "Nom. entrada") +#define TR_EXPONAME TR("Nom.", "Nombre expo") +#define TR_BITMAP "Imagen modelo" +#define TR_TIMER TR("Timer", "Timer ") #define TR_START "Start" -#define TR_ELIMITS TR("E.Limite","Ampliar Limites") -#define TR_ETRIMS TR("E.Trims","Ampliar Trims") -#define TR_TRIMINC "Paso Trim" -#define TR_DISPLAY_TRIMS "Ver Trims" -#define TR_TTRACE TR("Fuente-A", INDENT "Fuente Acelerad") -#define TR_TTRIM TR("Trim-A", INDENT "Trim Acelerad") -#define TR_BEEPCTR TR("Beep ctr","Beep centro") -#define TR_USE_GLOBAL_FUNCS "Funcs glob." +#define TR_ELIMITS TR("E.Límite", "Ampliar límites") +#define TR_ETRIMS TR("E.Trims", "Ampliar trims") +#define TR_TRIMINC "Paso trim" +#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_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 @@ -463,46 +448,46 @@ #define STR_WARN_BATTVOLTAGE TR(INDENT "Salida es VBAT: ", INDENT "Aviso: señal salida es VBAT: ") #define TR_MS "ms" #define TR_FREQUENCY INDENT "Frequencia" -#define TR_SWITCH "Interr" +#define TR_SWITCH TR("Interr.", "Interruptor") #define TR_TRIMS "Trims" #define TR_FADEIN "Inicio" #define TR_FADEOUT "Final" #define TR_DEFAULT "(defecto)" #define TR_CHECKTRIMS CENTER "\006Check\012Trims" #define OFS_CHECKTRIMS CENTER_OFS+(9*FW) -#define TR_SWASHTYPE "Tipo ciclico" -#define TR_COLLECTIVE TR("Colectivo", "Fuente Colectivo") +#define TR_SWASHTYPE "Tipo cíclico" +#define TR_COLLECTIVE TR("Colectivo", "Fuente colectivo") #define TR_AILERON TR("Col. lateral", "Fuente col. lateral") #define TR_ELEVATOR TR("Col. long. ", "Fuente col. longitudinal") #define TR_SWASHRING "Ciclico" -#define TR_ELEDIRECTION TR("ELE Direccion","Largo cyc. direccion") -#define TR_AILDIRECTION TR("AIL Direccion","Lateral cyc. direccion") -#define TR_COLDIRECTION TR("PIT Direccion","Coll. pitch direccion") +#define TR_ELEDIRECTION TR("ELE Dirección", "Largo cyc. dirección") +#define TR_AILDIRECTION TR("AIL Dirección", "Lateral cyc. dirección") +#define TR_COLDIRECTION TR("PIT Dirección", "Coll. pitch dirección") #define TR_MODE "Modo" #define TR_SUBTYPE INDENT "Subtipo" #define TR_NOFREEEXPO "No expo libre!" #define TR_NOFREEMIXER "No mezcla lib!" #define TR_SOURCE "Fuente" #define TR_WEIGHT "Cantidad" -#define TR_EXPO TR("Expo","Exponencial") -#define TR_SIDE "Lado" +#define TR_EXPO TR("Expo", "Exponencial") +#define TR_SIDE "Zona" #define TR_DIFFERENTIAL "Diferenc" #define TR_OFFSET "Offset" #define TR_TRIM "Trim" #define TR_DREX "DRex" #define DREX_CHBOX_OFFSET 30 #define TR_CURVE "Curva" -#define TR_FLMODE TR("Modo","Modos") +#define TR_FLMODE TR("Modo", "Modos") #define TR_MIXWARNING "Aviso" #define TR_OFF "OFF" #define TR_ANTENNA "Antena" -#define TR_NO_INFORMATION TR("Sin info", "Sin informacion") +#define TR_NO_INFORMATION TR("Sin info", "Sin información") #define TR_MULTPX "Multipx" #define TR_DELAYDOWN "Atraso bajar" #define TR_DELAYUP "Atraso subir" #define TR_SLOWDOWN "Bajar lento " #define TR_SLOWUP "Subir lento" -#define TR_MIXES "MEZCLAS" +#define TR_MIXES "MIXES" #define TR_CV "CV" #if defined(PCBNV14) #define TR_GV "GV" @@ -519,52 +504,53 @@ #define TR_SCREEN "Pant. " #define TR_SOUND_LABEL "Sonido" #define TR_LENGTH "Longitud" -#define TR_BEEP_LENGTH "Duracion Beep" +#define TR_BEEP_LENGTH "Duración Beep" #define TR_BEEP_PITCH "Tono" -#define TR_HAPTIC_LABEL "Tactil" +#define TR_HAPTIC_LABEL "Haptic" #define TR_STRENGTH "Intensidad" #define TR_GYRO_LABEL "Gyro" #define TR_GYRO_OFFSET "Offset" -#define TR_GYRO_MAX "Max" +#define TR_GYRO_MAX "Máx" #define TR_CONTRAST "Contraste" #define TR_ALARMS_LABEL "Alarmas" -#define TR_BATTERY_RANGE TR("Rango bateria","Rango medidor Bater") +#define TR_BATTERY_RANGE TR("Rango batería", "Rango medidor batería") #define TR_BATTERYCHARGING "Charging..." #define TR_BATTERYFULL "Battery full" #define TR_BATTERYNONE "None!" -#define TR_BATTERYWARNING "Bateria Baja" +#define TR_BATTERYWARNING "Batería baja" #define TR_INACTIVITYALARM "Inactividad" -#define TR_MEMORYWARNING "Memoria Baja" -#define TR_ALARMWARNING "Sin Sonido" +#define TR_MEMORYWARNING "Memoria baja" +#define TR_ALARMWARNING "Sin sonido" #define TR_RSSI_SHUTDOWN_ALARM TR("Apagado Rssi", "Check Rssi al apagar") #define TR_MODEL_STILL_POWERED "Modelo aun encendido" #define TR_MODEL_SHUTDOWN "Apagar ?" #define TR_PRESS_ENTER_TO_CONFIRM "Enter para confirmar" #define TR_THROTTLE_LABEL "Potencia" -#define TR_THROTTLEREVERSE TR("Invert_Acel", INDENT "Invertir Acel.") -#define TR_MINUTEBEEP TR("Minuto", "Cada Minuto") -#define TR_BEEPCOUNTDOWN INDENT"Cta. atras" -#define TR_PERSISTENT TR(INDENT"Persist.", INDENT"Persistente") -#define TR_BACKLIGHT_LABEL "Luz Fondo" -#define TR_BLONBRIGHTNESS "MAS Brillo" -#define TR_BLOFFBRIGHTNESS "MENOS Brillo" -#define TR_BLCOLOR "Color" -#define TR_SPLASHSCREEN "Pant. inicio" -#define TR_PWR_ON_DELAY "Atraso On" -#define TR_PWR_OFF_DELAY "Atraso Off" -#define TR_THROTTLE_WARNING TR("Aviso-A", INDENT "Aviso Acelerador") -#define TR_SWITCHWARNING TR("Aviso-I", INDENT "Aviso Intrptor") +#define TR_THROTTLEREVERSE TR("Invert acel", INDENT "Invertir acel.") +#define TR_MINUTEBEEP TR("Minuto", "Cada minuto") +#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_BLDELAY INDENT"Duración" +#define TR_BLONBRIGHTNESS INDENT"MAS brillo" +#define TR_BLOFFBRIGHTNESS INDENT"MENOS brillo" +#define TR_BLCOLOR INDENT "Color" +#define TR_SPLASHSCREEN "Pantalla inicio" +#define TR_PWR_ON_DELAY TR("Atraso On", "Atraso encendido") +#define TR_PWR_OFF_DELAY TR("Atraso Off", "Atraso apagado") +#define TR_THROTTLEWARNING TR("Aviso-A", INDENT "Aviso acelerador") +#define TR_SWITCHWARNING TR("Aviso-I", INDENT "Aviso interruptor") #define TR_POTWARNINGSTATE TR(INDENT "Pot&Slid.", INDENT "Pots & sliders") #define TR_SLIDERWARNING TR(INDENT "Pos. slid.", INDENT "Posiciones slider") #define TR_POTWARNING TR("Aviso pot", INDENT "Aviso pot") -#define TR_TIMEZONE TR("Zona Hora", "GPS Zona Hora") +#define TR_TIMEZONE TR("Zona horaria", INDENT "Zona horaria") #define TR_ADJUST_RTC TR("Ajustar RTC", "Ajustar RTC") #define TR_GPS "GPS" #define TR_RXCHANNELORD TR("Rx Orden canal", "Orden habitual canales") #define TR_STICKS "Sticks" #define TR_POTS "Pots" #define TR_SWITCHES "Switches" -#define TR_SWITCHES_DELAY "Atraso switch." +#define TR_SWITCHES_DELAY TR("Atraso switch.", "Atraso switches") #define TR_SLAVE "Esclavo" #define TR_MODESRC "Modo\006% Fuente" #define TR_MULTIPLIER "Multiplicar" @@ -588,7 +574,7 @@ #define TR_ACCEL "Acc:" #define TR_NODATA CENTER "SIN DATOS" #define TR_US "us" -#define TR_TMIXMAXMS "Tmix max" +#define TR_TMIXMAXMS "Tmix máx" #define TR_FREE_STACK "Stack libre" #define TR_MENUTORESET TR_ENTER "Resetear" #define TR_PPM_TRAINER "TR" @@ -600,20 +586,20 @@ #define TR_PRESS_ANY_KEY_TO_SKIP "Pulsar tecla para omitir" #define TR_THROTTLE_NOT_IDLE "Aceler. Activado" #define TR_ALARMSDISABLED "Alarmas Desact." -#define TR_PRESSANYKEY TR("\010Pulsa una Tecla", "Pulsa una Tecla") -#define TR_BADEEPROMDATA "Error datos EEprom" +#define TR_PRESSANYKEY TR("\010Pulsa una tecla", "Pulsa una tecla") +#define TR_BADEEPROMDATA "Error datos EEPROM" #define TR_BAD_RADIO_DATA "Error datos radio" #define TR_EEPROMFORMATTING "Formateo EEPROM" -#define TR_STORAGE_FORMAT "Preparacion alamacenamiento" +#define TR_STORAGE_FORMAT "Preparación alamacenamiento" #define TR_EEPROMOVERFLOW "Desborde EEPROM" -#define TR_RADIO_SETUP "CONFIGURACION" +#define TR_RADIO_SETUP "CONFIGURACIÓN" #define TR_MENUDATEANDTIME "FECHA Y HORA" #define TR_MENUTRAINER "ENTRENADOR" #define TR_MENUSPECIALFUNCS "FUNCIONES GLOBALES" -#define TR_MENUVERSION "VERSION" -#define TR_MENU_RADIO_SWITCHES TR("INTERUPTS", "TEST INTERUP.") -#define TR_MENU_RADIO_ANALOGS TR("ANAS", "ENTRADAS ANALOG") -#define TR_MENUCALIBRATION "CALIBRACION" +#define TR_MENUVERSION "VERSIÓN" +#define TR_MENU_RADIO_SWITCHES TR("INTERUPTS", "TEST INTERRUPTORES") +#define TR_MENU_RADIO_ANALOGS TR("ANALÓGICOS", "TEST ANALÓGICOS") +#define TR_MENUCALIBRATION "CALIBRACIÓN" #if defined(COLORLCD) #define TR_TRIMS2OFFSETS "Trims => Offsets" #else @@ -621,11 +607,11 @@ #endif #define TR_CHANNELS2FAILSAFE "Canales=>Failsafe" #define TR_CHANNEL2FAILSAFE "Canal=>Failsafe" -#define TR_MENUMODELSEL TR("MODELOS", "SELECCION MODELO") -#define TR_MENU_MODEL_SETUP "CONFIG. MODELO" +#define TR_MENUMODELSEL TR("MODELOS", "SELECCIÓN MODELO") +#define TR_MENUSETUP TR("CONFIG. MODELO", "CONFIGURACIÓN MODELO") #define TR_MENUFLIGHTMODE "MODO DE VUELO" #define TR_MENUFLIGHTMODES "MODOS DE VUELO" -#define TR_MENUHELISETUP "CONFIGURACION HELI" +#define TR_MENUHELISETUP "CONFIGURACIÓN HELI" // Alignment @@ -635,49 +621,50 @@ #define TR_MENULIMITS "SERVOS" #else #define TR_MENUINPUTS "DR/EXPO" - #define TR_MENULIMITS "LIMITES" + #define TR_MENULIMITS "LÍMITES" #endif #define TR_MENUCURVES "CURVAS" #define TR_MENUCURVE "CURVA" -#define TR_MENULOGICALSWITCH "INTERRUP. LOGICO" -#define TR_MENULOGICALSWITCHES "INTERRUP. LOGICOS" -#define TR_MENUCUSTOMFUNC "FUNCIONES" +#define TR_MENULOGICALSWITCH "INTERRUP.LÓGICO" +#define TR_MENULOGICALSWITCHES TR3("INTERRUP. LÓGICOS", "INTERRUP. LÓGICOS", "INTERRUPTORES LÓGICOS") +#define TR_MENUCUSTOMFUNC TR("FUNCIONES", "FUNCIONES ESPECIALES") #define TR_MENUCUSTOMSCRIPTS "CUSTOM SCRIPTS" -#define TR_MENUTELEMETRY "TELEMETRIA" +#define TR_MENUTELEMETRY "TELEMETRÍA" #define TR_MENUTEMPLATES "PLANTILLAS" -#define TR_MENUSTAT "ESTADISTICAS" +#define TR_MENUSTAT TR("ESTAD.", "ESTADÍSTICAS") #define TR_MENUDEBUG "DEBUG" #define TR_MONITOR_CHANNELS1 "MONITOR CANALES 1/8" #define TR_MONITOR_CHANNELS2 "MONITOR CANALES 9/16" -#define TR_MONITOR_SWITCHES "MONITOR INTERRP LOGICOS" +#define TR_MONITOR_SWITCHES "MONITOR INTERRP LÓGICOS" #define TR_MONITOR_CHANNELS3 "MONITOR CANALES 17/24" #define TR_MONITOR_CHANNELS4 "MONITOR CANALES 25/32" #define TR_MONITOR_OUTPUT_DESC "SALIDAS" -#define TR_MONITOR_MIXER_DESC "MEZCLAS" -#define TR_RECEIVER_NUM TR("RxNum", "Receptor No.") +#define TR_MONITOR_MIXER_DESC "Mixers" +#define TR_RECEIVER_NUM TR("Num Rx", "Receptor No.") #define TR_RECEIVER "Receptor" #define TR_MULTI_RFTUNE TR("Sint.freq.", "RF Freq. sint.fina") -#define TR_MULTI_TELEMETRY "Telemetria" -#define TR_MULTI_VIDFREQ TR("Freq. Vid.", "Frecuancia Video") +#define TR_MULTI_TELEMETRY "Telemetría" +#define TR_MULTI_VIDFREQ TR("Freq.vídeo", "Frecuencia vídeo") #define TR_RF_POWER "RF Power" #define TR_MULTI_FIXEDID TR("ID Fijo", "ID Fijo") -#define TR_MULTI_OPTION TR("Opcion", "Valor opcion") +#define TR_MULTI_OPTION TR("Opción", "Valor opción") #define TR_MULTI_AUTOBIND TR(INDENT "Emp Cnl",INDENT "Emparejar en canal") #define TR_DISABLE_CH_MAP TR("No ch map", "Desactivar mapa cnl") -#define TR_DISABLE_TELEM TR("No Telem", "Desactivar Telemetria") +#define TR_DISABLE_TELEM TR("No telem", "Desactivar telem.") #define TR_MULTI_DSM_AUTODTECT TR(INDENT "Autodetect", INDENT "Autodetectar formato") -#define TR_MULTI_LOWPOWER TR(INDENT "Baja potencia", INDENT "Modo de baja potencia") +#define TR_MULTI_LOWPOWER TR(INDENT "Baja poten.", INDENT "Modo de baja poten.") +#define TR_MULTI_LNA_DISABLE INDENT "LNA desact." #define TR_MODULE_TELEMETRY TR(INDENT "S.Port", INDENT "S.Port link") #define TR_MODULE_TELEM_ON TR("ON", "Activado") -#define TR_DISABLE_INTERNAL TR("Desac.RF int", "Desactivar modulo interno RF") +#define TR_DISABLE_INTERNAL TR("Desac.RF int", "Desact. mód. int. RF") #define TR_MODULE_NO_SERIAL_MODE TR("No modo serie", "No en modo serie") -#define TR_MODULE_NO_INPUT TR("Sin señal", "Sin señal") -#define TR_MODULE_NO_TELEMETRY TR3( "No telemetria", "No MULTI_TELEMETRY", "No telemetria (activa MULTI_TELEMETRY)") +#define TR_MODULE_NO_INPUT "Sin señal" +#define TR_MODULE_NO_TELEMETRY TR3( "No telemetría", "No MULTI_TELEMETRY", "No telemetría (activa MULTI_TELEMETRY)") #define TR_MODULE_WAITFORBIND "Emparejar con protocolo" #define TR_MODULE_BINDING "Emparejando" -#define TR_MODULE_UPGRADE_ALERT TR3("Actualizar", "Actualizar modulo", "Actualizar\nmodulo") -#define TR_MODULE_UPGRADE TR("Act recom", "Actualizar modulo recomendado") +#define TR_MODULE_UPGRADE_ALERT TR3("Actualizar", "Actualizar módulo", "Actualizar\nmódulo") +#define TR_MODULE_UPGRADE TR("Act recom", "Actualizar módulo recomendado") #define TR_REBIND "Reemparejar " #define TR_REG_OK "Registro ok" #define TR_BIND_OK "Emparejado ok" @@ -685,42 +672,41 @@ #define TR_BINDING_CH1_8_TELEM_OFF "Ch1-8 Telem OFF" #define TR_BINDING_CH9_16_TELEM_ON "Ch9-16 Telem ON" #define TR_BINDING_CH9_16_TELEM_OFF "Ch9-16 Telem OFF" -#define TR_PROTOCOL_INVALID TR("Prot. invalido", "Protocolo invalido") -#define TR_MODULE_STATUS TR(INDENT "EStado", INDENT "Estado modulo") +#define TR_PROTOCOL_INVALID TR("Prot. inválido", "Protocolo inválido") +#define TR_MODULE_STATUS TR(INDENT "Estado", INDENT "Estado módulo") #define TR_MODULE_SYNC TR(INDENT "Sync", INDENT "Estado proto sync") #define TR_MULTI_SERVOFREQ TR("V ref serv", "Vel. refr. servo") -#define TR_MULTI_MAX_THROW TR("Max. Throw", "Activar max. throw") +#define TR_MULTI_MAX_THROW TR("Máx. Throw", "Activar máx. throw") #define TR_MULTI_RFCHAN TR("Canal RF", "Selecciona canal RF") #define TR_SYNCMENU "Sync " TR_ENTER -#define TR_LIMIT INDENT"Limite" +#define TR_LIMIT INDENT"Límite" #define TR_MINRSSI "Min Rssi" -#define TR_FLYSKY_TELEMETRY TR("FlySky RSSI #", "Use FlySky RSSI value without rescalling") -#define TR_LATITUDE "Latitud" -#define TR_LONGITUDE "Longitud" -#define TR_GPS_COORDS_FORMAT TR("Coords GPS", "GPS formato coordenadas") -#define TR_VARIO TR("Vario", "Variometro") -#define TR_PITCH_AT_ZERO "Pitch en cero" -#define TR_PITCH_AT_MAX "Pitch en max" -#define TR_REPEAT_AT_ZERO "Repet. en cero" +#define TR_LATITUDE "Latitud" +#define TR_LONGITUDE "Longitud" +#define TR_GPSCOORD TR("Coords GPS", INDENT "Formato coordenadas") +#define TR_VARIO TR("Vario", "Variómetro") +#define TR_PITCH_AT_ZERO INDENT "Pitch en cero" +#define TR_PITCH_AT_MAX INDENT "Pitch en máx" +#define TR_REPEAT_AT_ZERO TR(INDENT "Repet. en cero", INDENT "Repetir en cero") #define TR_SHUTDOWN "APAGANDO" #define TR_SAVE_MODEL "Grabando modelo" -#define TR_BATT_CALIB "Calib.bat." +#define TR_BATT_CALIB TR("Calib.bat.", "Calibración batería") #define TR_CURRENT_CALIB "Calib. actual" #define TR_VOLTAGE INDENT"Voltaje" #define TR_CURRENT INDENT"Actual" -#define TR_SELECT_MODEL "Selec Modelo" -#define TR_CREATE_CATEGORY "Crear categoria" -#define TR_RENAME_CATEGORY "Renombrar categoria" -#define TR_DELETE_CATEGORY "Borrar categoria" +#define TR_SELECT_MODEL TR("Selec. modelo", "Seleccionar modelo") +#define TR_CREATE_CATEGORY "Crear categoría" +#define TR_RENAME_CATEGORY "Renombrar categoría" +#define TR_DELETE_CATEGORY "Borrar categoría" #define TR_CREATE_MODEL "Crear modelo" #define TR_DUPLICATE_MODEL "Duplicar modelo" #define TR_COPY_MODEL "Copiar modelo" #define TR_MOVE_MODEL "Mover modelo" -#define TR_BACKUP_MODEL "Copia sgdad mod." +#define TR_BACKUP_MODEL TR("Copia sgdad. mod.", "Copia seguridad modelo") #define TR_DELETE_MODEL "Borrar modelo" #define TR_RESTORE_MODEL "Restaurar modelo" #define TR_DELETE_ERROR "Error de borrado" -#define TR_CAT_NOT_EMPTY "Categoria no esta vacia" +#define TR_CAT_NOT_EMPTY "Categoría no esta vacía" #define TR_SDCARD_ERROR "Error SDCARD" #define TR_SDCARD "SD Card" #define TR_NO_FILES_ON_SD "No files on SD!" @@ -734,28 +720,28 @@ #define TR_CONNECTED "Conectado" #define TR_FLEX_915 "Flex 915MHz" #define TR_FLEX_868 "Flex 868MHz" -#define TR_16CH_WITHOUT_TELEMETRY TR("16CH sin telem.", "16CH sin telemetria") -#define TR_16CH_WITH_TELEMETRY TR("16CH con telem.", "16CH con telemetria") -#define TR_8CH_WITH_TELEMETRY TR("8CH con telem.", "8CH con telemetria") +#define TR_16CH_WITHOUT_TELEMETRY TR("16CH sin telem.", "16CH sin telemetría") +#define TR_16CH_WITH_TELEMETRY TR("16CH con telem.", "16CH con telemetría") +#define TR_8CH_WITH_TELEMETRY TR("8CH con telem.", "8CH con telemetría") #define TR_EXT_ANTENNA "Antena ext." #define TR_PIN "Pin" #define TR_UPDATE_RX_OPTIONS "Actualizar opciones RX?" #define TR_UPDATE_TX_OPTIONS "Actualizar opciones TX?" -#define TR_MODULES_RX_VERSION "Modulos / version RX" -#define TR_MENU_MODULES_RX_VERSION "MODULOS / VERSION RX" +#define TR_MODULES_RX_VERSION "Módulos / versión RX" +#define TR_MENU_MODULES_RX_VERSION "MÓDULOS / VERSIÓN RX" #define TR_MENU_FIRM_OPTIONS "OPCIONES FIRMWARE" #define TR_GYRO "Gyro" #define TR_STICKS_POTS_SLIDERS "Sticks/Pots/Sliders" #define TR_PWM_STICKS_POTS_SLIDERS "PWM Sticks/Pots/Sliders" #define TR_RF_PROTOCOL "Protocolo RF" -#define TR_MODULE_OPTIONS "Opciones modulo" +#define TR_MODULE_OPTIONS "Opciones módulo" #define TR_POWER "Potencia" -#define TR_NO_TX_OPTIONS "Sin pciones TX" -#define TR_RTC_BATT "Bat. RTC" +#define TR_NO_TX_OPTIONS "Sin opciones TX" +#define TR_RTC_BATT TR("Bat. RTC", "Batería RTC") #define TR_POWER_METER_EXT "Medidor potencia(EXT)" #define TR_POWER_METER_INT "Medidor potencia(INT)" -#define TR_SPECTRUM_ANALYSER_EXT "Spectro (EXT)" -#define TR_SPECTRUM_ANALYSER_INT "Spectro (INT)" +#define TR_SPECTRUM_ANALYSER_EXT "Espectro (EXT)" +#define TR_SPECTRUM_ANALYSER_INT "Espectro (INT)" #define TR_SDCARD_FULL "SD Card llena" #define TR_NEEDS_FILE "NECESITA ARCHIVO" #define TR_EXT_MULTI_SPEC "opentx-inv" @@ -765,22 +751,22 @@ #define TR_EEPROMWARN "EEPROM" #define TR_STORAGE_WARNING "ALMAC." #define TR_EEPROM_CONVERTING "Convirtiendo EEPROM" -#define TR_THROTTLE_UPPERCASE "ACELERADOR" +#define TR_THROTTLEWARN TR("ACELERAD.", "ACELERADOR") #define TR_ALARMSWARN "ALARMAS" -#define TR_SWITCHWARN "INTERPTOR" +#define TR_SWITCHWARN TR("INTERRUP.", "INTERRUPTOR") #define TR_FAILSAFEWARN "FAILSAFE" #define TR_TEST_WARNING TR("TESTING", "TEST BUILD") #define TR_TEST_NOTSAFE "Usar solo para test" -#define TR_WRONG_SDCARDVERSION TR("Ver esperada: ","Version esperada: ") -#define TR_WARN_RTC_BATTERY_LOW "Bateria RTC baja" +#define TR_WRONG_SDCARDVERSION TR("Ver esperada: ", "Versión esperada: ") +#define TR_WARN_RTC_BATTERY_LOW "Batería RTC baja" #define TR_WARN_MULTI_LOWPOWER "Modo baja potencia" -#define TR_BATTERY "BATERiA" -#define TR_WRONG_PCBREV "Placa PCB erronea" +#define TR_BATTERY "BATERÍA" +#define TR_WRONG_PCBREV "Placa PCB errónea" #define TR_EMERGENCY_MODE "MODO EMERGENCIA" #define TR_PCBREV_ERROR "Error PCB" #define TR_NO_FAILSAFE "Failsafe no fijado" #define TR_KEYSTUCK "Tecla atascada" -#define TR_INVERT_THR TR("Invertir Acel?", "Invertir Acel.?") +#define TR_INVERT_THR TR("Invertir acel?", "Invertir acel.?") #define TR_VOLUME "Volumen" #define TR_LCD "LCD" #define TR_BRIGHTNESS "Brillo" @@ -789,18 +775,18 @@ #define TR_CPU_MAH "Consumo" #define TR_COPROC "CoProc." #define TR_COPROC_TEMP "MB Temp. \016>" -#define TR_CAPAWARNING INDENT "Capacidad Baja" +#define TR_CAPAWARNING INDENT "Capacidad baja" #define TR_TEMPWARNING INDENT "Sobrecalent" -#define TR_FUNC "Func" +#define TR_FUNC "Función" #define TR_V1 "V1" #define TR_V2 "V2" -#define TR_DURATION "Duracion" +#define TR_DURATION "Duración" #define TR_DELAY "Atraso" #define TR_SD_CARD "SD CARD" #define TR_SDHC_CARD "SD-HC CARD" #define TR_NO_SOUNDS_ON_SD "Sin sonidos en SD" #define TR_NO_MODELS_ON_SD "Sin modelos en SD" -#define TR_NO_BITMAPS_ON_SD "Sin imagenes 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_PANIC "Script panic" @@ -814,27 +800,27 @@ #define TR_ASSIGN_SPLASH "Pant. bienvenida" #define TR_EXECUTE_FILE "Ejecutar" #define TR_REMOVED "Borrado" -#define TR_SD_INFO "Informacion" +#define TR_SD_INFO "Información" #define TR_SD_FORMAT "Formatear" #define TR_NA "N/A" #define TR_HARDWARE "COMPONENTES" #define TR_FORMATTING "Formateando.." #define TR_TEMP_CALIB "Temp. Calib" #define TR_TIME "Hora" -#define TR_MAXBAUDRATE "Max bauds" +#define TR_MAXBAUDRATE "Máx bauds" #define TR_BLUETOOTH "Bluetooth" #define TR_BLUETOOTH_DISC "Buscar" #define TR_BLUETOOTH_INIT "Init" #define TR_BLUETOOTH_DIST_ADDR "Dir. remota" #define TR_BLUETOOTH_LOCAL_ADDR "Dir. local" -#define TR_BLUETOOTH_PIN_CODE "Codigo PIN" +#define TR_BLUETOOTH_PIN_CODE "Código PIN" #define TR_BAUDRATE "Velocidad BT" -#define LEN_BLUETOOTH_MODES "\011" +#define LEN_BLUETOOTH_MODES "\012" #if defined(PCBX9E) -#define TR_BLUETOOTH_MODES "---\0 ""Activo\0 " +#define TR_BLUETOOTH_MODES "---\0 ""Activo\0 " #else -#define TR_BLUETOOTH_MODES "---\0 ""Telemetria""Entrenador" +#define TR_BLUETOOTH_MODES "---\0 ""Telemetría""Entrenador" #endif #define TR_SD_INFO_TITLE "SD INFO" #define TR_SD_TYPE "Tipo:" @@ -857,29 +843,29 @@ #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 by ext. OTA" -#define TR_FLASH_RECEIVER_OTA_BY_INTERNAL "Flash RX by int. OTA" -#define TR_FLASH_BLUETOOTH_MODULE TR("Flash modulo BT", "Flash modulo bluetooth") +#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_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", "Version actual: ") -#define TR_FLASH_INTERNAL_MODULE TR("Flash modulo int", "Flash modulo interno") +#define TR_CURRENT_VERSION TR("Vers. actual", "Versión actual: ") +#define TR_FLASH_INTERNAL_MODULE TR("Flash módulo int", "Flash módulo interno") #define TR_FLASH_INTERNAL_MULTI TR("Flash Multi int", "Flash Multi interno") -#define TR_FLASH_EXTERNAL_MODULE TR("Flash modulo ext", "Flash modulo externo") +#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_FIRMWARE_UPDATE_ERROR TR("Error act FW","Error actualiz. firmware") +#define TR_FIRMWARE_UPDATE_ERROR TR("Error act FW", "Error actualiz. firmware") #define TR_FIRMWARE_UPDATE_SUCCESS "Flash ok" #define TR_WRITING "Escribiendo..." #define TR_CONFIRM_FORMAT "Confirmar formato?" #define TR_INTERNALRF "RF interna" -#define TR_INTERNAL_MODULE TR("Modulo int","Modulo interno") -#define TR_EXTERNAL_MODULE TR("Modulo ext","Modulo externo") +#define TR_INTERNAL_MODULE TR("Módulo int", "Módulo interno") +#define TR_EXTERNAL_MODULE TR("Módulo ext", "Módulo externo") #define TR_OPENTX_UPGRADE_REQUIRED "Actualiz. OpenTX requerida" #define TR_TELEMETRY_DISABLED "Telem. inactiva" -#define TR_MORE_OPTIONS_AVAILABLE "Mas opciones disp." -#define TR_NO_MODULE_INFORMATION "Sin informacion modulo" +#define TR_MORE_OPTIONS_AVAILABLE "Más opciones disp." +#define TR_NO_MODULE_INFORMATION "Sin información módulo" #define TR_EXTERNALRF "RF externa" -#define TR_FAILSAFE INDENT"Modo sgdad." -#define TR_FAILSAFESET "AJUSTES SGDAD." +#define TR_FAILSAFE INDENT"Failsafe" +#define TR_FAILSAFESET "AJUSTES FAILSAFE" #define TR_REG_ID "Reg. ID" #define TR_OWNER_ID "Pers. ID" #define TR_PINMAPSET "PINMAP" @@ -898,14 +884,14 @@ #define TR_MENU_SPECTRUM_ANALYSER "ANALIZADOR DE ESPECTRO" #define TR_MENU_POWER_METER "MEDIDOR POTENCIA" #define TR_SENSOR "SENSOR" -#define TR_COUNTRY_CODE "Codigo Pais" +#define TR_COUNTRY_CODE "Código país" #define TR_USBMODE "Modo USB" #define TR_JACK_MODE "Modo Jack" #define TR_VOICE_LANGUAGE "Idioma voces" #define TR_UNITS_SYSTEM "Unidades" #define TR_EDIT "Editar" #define TR_INSERT_BEFORE "Insertar antes" -#define TR_INSERT_AFTER "Insertar despues" +#define TR_INSERT_AFTER "Insertar después" #define TR_COPY "Copiar" #define TR_MOVE "Mover" #define TR_PASTE "Pegar" @@ -917,15 +903,15 @@ #define TR_RESET_TIMER1 "Reset Reloj 1" #define TR_RESET_TIMER2 "Reset Reloj 2" #define TR_RESET_TIMER3 "Reset Reloj 3" -#define TR_RESET_TELEMETRY "Reset Telemetria" -#define TR_STATISTICS "Estadisticas" +#define TR_RESET_TELEMETRY "Reset Telemetría" +#define TR_STATISTICS "Estadísticas" #define TR_ABOUT_US "Nosotros" #define TR_USB_JOYSTICK "Joystick USB (HID)" #define TR_USB_MASS_STORAGE "Almaz. USB (SD)" #define TR_USB_SERIAL "Serie USB (Debug)" #define TR_SETUP_SCREENS "Pantallas config" #define TR_MONITOR_SCREENS "Monitores" -#define TR_AND_SWITCH "AND Inter." +#define TR_AND_SWITCH TR("Inter. AND", "Interruptor AND") #define TR_SF "CF" #define TR_GF "GF" #define TR_SPEAKER INDENT"Altavoz" @@ -951,50 +937,52 @@ #define TR_DEBUG "Debug" #define TR_KEYS_BTN BUTTON(TR("SW","Switches")) #define TR_ANALOGS_BTN BUTTON(TR("Analog","Analogs")) -#define TR_CALIBRATION "Calibracion" +#define TR_TOUCH_NOTFOUND "Touch hardware not found" +#define TR_TOUCH_EXIT "Touch screen to exit" +#define TR_CALIBRATION "Calibración" #define TR_SET "[Ajuste]" -#define TR_TRAINER "Entrena." +#define TR_TRAINER "Entrenador" #define TR_CHANS "Chans" -#define TR_ANTENNAPROBLEM CENTER "¡Problema antena TX!" +#define TR_ANTENNAPROBLEM CENTER "Problema antena TX!" #define TR_MODELIDUSED TR("ID en uso", "ID modelo en uso") -#define TR_MODULE "Modulo" +#define TR_MODULE "Módulo" #define TR_RX_NAME "Nombre Rx" -#define TR_TELEMETRY_TYPE TR("Tipo", "Tipo telemetria") +#define TR_TELEMETRY_TYPE TR("Tipo", "Tipo telemetría") #define TR_TELEMETRY_SENSORS "Sensores" #define TR_VALUE "Valor" #define TR_REPEAT "Repeat" #define TR_ENABLE "Enable" #define TR_TOPLCDTIMER "Timer LCD superior" #define TR_UNIT "Unidad" -#define TR_TELEMETRY_NEWSENSOR INDENT "Añadir nuevo sensor..." +#define TR_TELEMETRY_NEWSENSOR INDENT "Añadir sensor..." #define TR_CHANNELRANGE INDENT "Canales" #define TR_RXFREQUENCY TR("Rx Freqency", "Rx Servo Frequency") #define TR_ANTENNACONFIRM1 "ANTENA EXT." #if defined(PCBX12S) -#define LEN_ANTENNA_MODES "\023" -#define TR_ANTENNA_MODES "Interna\0 ""Preguntar\0 ""Por modelo\0 ""Interno + Externo\0 " +#define LEN_ANTENNA_MODES "\020" +#define TR_ANTENNA_MODES "Interna\0 ""Preguntar\0 ""Por modelo\0 ""Interno + Externo\0" #else -#define LEN_ANTENNA_MODES "\011" -#define TR_ANTENNA_MODES "Interna\0 ""Preguntar\0""Por model""Externa\0 " +#define LEN_ANTENNA_MODES "\012" +#define TR_ANTENNA_MODES "Interna\0 ""Preguntar\0""Por modelo""Externa\0 " #endif #define TR_USE_INTERNAL_ANTENNA TR("Usa antena int.", "Usa antena interna") #define TR_USE_EXTERNAL_ANTENNA TR("Use antena ext.", "Usa antena externa") -#define TR_ANTENNACONFIRM2 TR("Revisa antena", "Revisa que la antena este instalada!") +#define TR_ANTENNACONFIRM2 TR("Revisa antena", "Revisa que la antena esté instalada!") #define TR_MODULE_PROTOCOL_FLEX_WARN_LINE1 "No requerido" #define TR_MODULE_PROTOCOL_FCC_WARN_LINE1 "Requiere FCC" #define TR_MODULE_PROTOCOL_EU_WARN_LINE1 "Requiere EU" #define TR_MODULE_PROTOCOL_WARN_LINE2 "firmware certificado" #define TR_LOWALARM INDENT "Alarma baja" -#define TR_CRITICALALARM INDENT "Alarma critica" -#define TR_RSSIALARM_WARN TR("RSSI","TELEMETRY RSSI") -#define TR_NO_RSSIALARM TR(INDENT "Alarmas desact.", INDENT "Alarmas telemetria desact.") +#define TR_CRITICALALARM INDENT "Alarma crítica" +#define TR_RSSIALARM_WARN TR("RSSI", "TELEMETRY RSSI") +#define TR_NO_RSSIALARM TR(INDENT "Alarmas desact.", INDENT "Alarmas telemetría desact.") #define TR_DISABLE_ALARM TR(INDENT "Desact. alarmas", INDENT "Desact. alarmas telem.") #define TR_ENABLE_POPUP "Activa Popup" #define TR_DISABLE_POPUP "Desactiva Popup" #define TR_POPUP "Popup" #define TR_MIN "Min" -#define TR_MAX "Max" +#define TR_MAX "Máx" #define TR_CURVE_PRESET "Preset..." #define TR_PRESET "Preset" #define TR_MIRROR "Mirror" @@ -1004,30 +992,32 @@ #define TR_COUNT "Puntos" #define TR_PT "pt" #define TR_PTS "pts" -#define TR_SMOOTH "Suaviz" +#define TR_SMOOTH TR3("Suaviz.", "Suaviz.", "Suavizado") #define TR_COPY_STICKS_TO_OFS TR("Copia stick->subtr", "Copia Sticks a Offset") -#define TR_COPY_MIN_MAX_TO_OUTPUTS TR("Copia min/max a sal", "Copia min/max/ctr a salidas") +#define TR_COPY_MIN_MAX_TO_OUTPUTS TR("Copia min/máx a sal", "Copia min/máx/ctr a salidas") #define TR_COPY_TRIMS_TO_OFS TR("Copia trim->subtr", "Copia trims a subtrim") #define TR_INCDEC "Inc/Decrement" #define TR_GLOBALVAR "Var global" #define TR_MIXSOURCE "Entrada mixer" #define TR_CONSTANT "Constante" #define TR_PERSISTENT_MAH INDENT "Valor mAh" -#define TR_PREFLIGHT "Chequeos Prevuelo" -#define TR_CHECKLIST INDENT "Lista verif" +#define TR_PREFLIGHT "Chequeos prevuelo" +#define TR_CHECKLIST TR(INDENT "Lista verif", INDENT "Lista verificación") #define TR_FAS_OFFSET TR(INDENT "FAS Ofs", INDENT "FAS Offset") #define TR_AUX_SERIAL_MODE "Puerto serie" +#define TR_AUX2_SERIAL_MODE "Puerto serie 2" #define TR_SCRIPT "Script" #define TR_INPUTS "Entradas" #define TR_OUTPUTS "Salidas" #define STR_EEBACKUP "Copia seg. EEPROM" #define STR_FACTORYRESET "Rest. fabrica" -#define TR_CONFIRMRESET "Borrar TODOS los modelos y configuracion?" +#define TR_CONFIRMRESET "Borrar TODOS los " LCDW_128_480_LINEBREAK "modelos y conf?" #define TR_TOO_MANY_LUA_SCRIPTS "Demasiados Lua scripts!" #define TR_SPORT_UPDATE_POWER_MODE "SP Power" #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:" // Horus and Taranis column headers #define TR_PHASES_HEADERS_NAME "Nombre" @@ -1035,26 +1025,26 @@ #define TR_PHASES_HEADERS_RUD_TRIM "Trim timon" #define TR_PHASES_HEADERS_ELE_TRIM "Trim elevador" #define TR_PHASES_HEADERS_THT_TRIM "Trim potencia" -#define TR_PHASES_HEADERS_AIL_TRIM "Trim aleron" +#define TR_PHASES_HEADERS_AIL_TRIM "Trim alerón" #define TR_PHASES_HEADERS_CH5_TRIM "Trim 5" #define TR_PHASES_HEADERS_CH6_TRIM "Trim 6" #define TR_PHASES_HEADERS_FAD_IN "Aparecer" #define TR_PHASES_HEADERS_FAD_OUT "Desparecer" #define TR_LIMITS_HEADERS_NAME "Nombre" -#define TR_LIMITS_HEADERS_SUBTRIM "Compensacion" +#define TR_LIMITS_HEADERS_SUBTRIM "Compensación" #define TR_LIMITS_HEADERS_MIN "Min" -#define TR_LIMITS_HEADERS_MAX "Max" -#define TR_LIMITS_HEADERS_DIRECTION "Direccion" +#define TR_LIMITS_HEADERS_MAX "Máx" +#define TR_LIMITS_HEADERS_DIRECTION "Dirección" #define TR_LIMITS_HEADERS_CURVE "Curva" #define TR_LIMITS_HEADERS_PPMCENTER "Centrado PPM" -#define TR_LIMITS_HEADERS_SUBTRIMMODE "Simetrica" +#define TR_LIMITS_HEADERS_SUBTRIMMODE "Simétrica" -#define TR_LSW_HEADERS_FUNCTION "Funcion" +#define TR_LSW_HEADERS_FUNCTION "Función" #define TR_LSW_HEADERS_V1 "V1" #define TR_LSW_HEADERS_V2 "V2" -#define TR_LSW_HEADERS_ANDSW "AND Interrup." -#define TR_LSW_HEADERS_DURATION "Duracion" +#define TR_LSW_HEADERS_ANDSW "Interrup. AND" +#define TR_LSW_HEADERS_DURATION "Duración" #define TR_LSW_HEADERS_DELAY "Retardo" #define TR_GVAR_HEADERS_NAME "Nombre" @@ -1069,7 +1059,24 @@ #define TR_GVAR_HEADERS_FM8 "Valor en FM8" // Horus footer descriptions -#define TR_LSW_DESCRIPTIONS { "Tipo de comparacion o funcion", "Primera variable", "Segunda variable o constante", "Segunda variable o constante", "Condicion adicional para activar linea", "Duracion minima de switch logico", "Duracion minima TRUE para activar switch logico" } +#define TR_LSW_DESCRIPTIONS { "Tipo de comparación o función", "Primera variable", "Segunda variable o constante", "Segunda variable o constante", "Condición adicional para activar línea", "Duración mínima de switch lógico", "Duración mínima TRUE para activar switch lógico" } + +// Horus layouts and widgets +#define TR_FIRST_CHANNEL "Primer canal" +#define TR_FILL_BACKGROUND "Rellenar fondo" +#define TR_BG_COLOR "Color BG" +#define TR_SLIDERS_TRIMS "Sliders+Trims" +#define TR_SLIDERS "Sliders" +#define TR_FLIGHT_MODE "Modo de vuelo" +#define TR_INVALID_FILE "Fichero no valido" +#define TR_TIMER_SOURCE "Entrada timer" +#define TR_SIZE "Tamaño" +#define TR_SHADOW "Sombra" +#define TR_TEXT "Texto" +#define TR_COLOR "Color" +#define TR_MAIN_VIEW_X "Vista principal X" +#define TR_PANEL1_BACKGROUND "Fondo panel1" +#define TR_PANEL2_BACKGROUND "Fondo panel2" // Taranis About screen #define TR_ABOUTUS "Nosotros" @@ -1077,7 +1084,7 @@ #define TR_ABOUT_OPENTX_1 "OpenTX es open source, no-" #define TR_ABOUT_OPENTX_2 "comercial y viene sin " #define TR_ABOUT_OPENTX_3 "garantias. Fue desarrollado" -#define TR_ABOUT_OPENTX_4 "libremente. Ayudas a traves" +#define TR_ABOUT_OPENTX_4 "libremente. Ayudas a través" #define TR_ABOUT_OPENTX_5 "de donaciones son bienvenidas!" #define TR_ABOUT_BERTRAND_1 "Bertrand Songis" @@ -1085,7 +1092,7 @@ #define TR_ABOUT_BERTRAND_3 "Companion codesarrollador" #define TR_ABOUT_MIKE_1 "Mike Blandford" -#define TR_ABOUT_MIKE_2 "Guru de codigo y drivers" +#define TR_ABOUT_MIKE_2 "Gurú de codigo y drivers" #define TR_ABOUT_MIKE_3 "Seguramente uno de los" #define TR_ABOUT_MIKE_4 "mejores inspiradores" @@ -1095,7 +1102,7 @@ #define TR_ABOUT_ANDRE_1 "Andre Bernet" #define TR_ABOUT_ANDRE_2 "Funcionalidad, usabilidad," -#define TR_ABOUT_ANDRE_3 "depurado, documentacion" +#define TR_ABOUT_ANDRE_3 "depurado, documentación" #define TR_ABOUT_ROB_1 "Rob Thomson" #define TR_ABOUT_ROB_2 "openrcforums webmaster" @@ -1106,7 +1113,7 @@ #define TR_ABOUT_KJELL_4 "Colaborador Companion" #define TR_ABOUT_MARTIN_1 "Martin Hotar" -#define TR_ABOUT_MARTIN_2 "Dise\201o grafico" +#define TR_ABOUT_MARTIN_2 "Dise\201o gráfico" #if defined(PCBTARANIS) #define TR_ABOUT_HARDWARE_1 "FrSky" @@ -1135,24 +1142,24 @@ #define TR_TOP_BAR "Panel superior" #define TR_FLASH_ERASE "Borrar flash..." -#define TR_FLASH_WRITE "Escrivir flash..." -#define TR_OTA_UPDATE "Actualizacion OTA..." -#define TR_MODULE_RESET "Reset modulo..." -#define TR_UNKNOWN_RX "RX deconocido" +#define TR_FLASH_WRITE "Escribir flash..." +#define TR_OTA_UPDATE "Actualización OTA..." +#define TR_MODULE_RESET "Reset módulo..." +#define TR_UNKNOWN_RX "RX desconocido" #define TR_UNSUPPORTED_RX "RX no soportado" -#define TR_OTA_UPDATE_ERROR "Error actualizacion OTA" +#define TR_OTA_UPDATE_ERROR "Error actualización OTA" #define TR_DEVICE_RESET "Reset dispositivo..." #define TR_ALTITUDE INDENT "Altitud" #define TR_SCALE "Escala" #define TR_VIEW_CHANNELS "Ver Canales" #define TR_VIEW_NOTES "Ver Notas" #define TR_MODEL_SELECT "Seleccionar modelo" -#define TR_MODS_FORBIDDEN "Modificacions prohibidas!" +#define TR_MODS_FORBIDDEN "Modificaciones prohibidas" #define TR_UNLOCKED "Desbloqueado" #define TR_ID "ID" -#define TR_PRECISION "Precision" +#define TR_PRECISION "Precisión" #define TR_RATIO "Ratio" -#define TR_FORMULA "Formula" +#define TR_FORMULA "Fórmula" #define TR_CELLINDEX "Cell index" #define TR_LOGS "Logs" #define TR_OPTIONS "Opciones" @@ -1162,26 +1169,26 @@ #define TR_CELLSENSOR "Cell sensor" #define TR_GPSSENSOR "GPS sensor" #define TR_CURRENTSENSOR "Sensor" -#define TR_AUTOOFFSET "Auto Offset" +#define TR_AUTOOFFSET "Auto offset" #define TR_ONLYPOSITIVE "Positivo" #define TR_FILTER "Filtro" -#define TR_TELEMETRYFULL TR("Telem. llena!", "Todas las entradas de telemetria llenas!") +#define TR_TELEMETRYFULL TR("Telem. llena!", "Todas las entradas de telemetría llenas!") #define TR_SERVOS_OK "Servos OK" #define TR_SERVOS_KO "Servos KO" #define TR_INVERTED_SERIAL INDENT "Invertir" -#define TR_IGNORE_INSTANCE INDENT "Ignorar instancia" -#define TR_DISCOVER_SENSORS "Buscar nuevos sensores" +#define TR_IGNORE_INSTANCE TR(INDENT "No inst.", INDENT "Ignora instancias") +#define TR_DISCOVER_SENSORS "Buscar sensores" #define TR_STOP_DISCOVER_SENSORS "Parar busqueda" #define TR_DELETE_ALL_SENSORS "Borrar sensores" #define TR_CONFIRMDELETE "Seguro " LCDW_128_480_LINEBREAK "borrar todo ?" #define TR_SELECT_WIDGET "Seleccionar widget" #define TR_REMOVE_WIDGET "Borrar widget" #define TR_WIDGET_SETTINGS "Config. widget" -#define TR_REMOVE_SCREEN "Borar pantalla" +#define TR_REMOVE_SCREEN "Borrar pantalla" #define TR_SETUP_WIDGETS "Config. widgets" #define TR_USER_INTERFACE "Interfaz" #define TR_THEME "Tema" -#define TR_SETUP "Configiracion" +#define TR_SETUP "Configuración" #define TR_MAINVIEWX "Vista pral. X" #define TR_LAYOUT "Diseño" #define TR_ADD_MAIN_VIEW "Añadir vista pral." @@ -1189,25 +1196,25 @@ #define TR_MAIN_COLOR "Color principal" #define TR_TEXT_VIEWER "Visor de texto" -#define TR_MENU_INPUTS "\314Inputs" +#define TR_MENU_INPUTS "\314Entradas" #define TR_MENU_LUA "\322Lua scripts" #define TR_MENU_STICKS "\307Sticks" #define TR_MENU_POTS "\310Pots" #define TR_MENU_MAX "\315MAX" -#define TR_MENU_HELI "\316Ciclico" +#define TR_MENU_HELI "\316Cíclico" #define TR_MENU_TRIMS "\313Trims" -#define TR_MENU_SWITCHES "\312Switches" -#define TR_MENU_LOGICAL_SWITCHES "\312Logical Switches" +#define TR_MENU_SWITCHES "\312Interruptores" +#define TR_MENU_LOGICAL_SWITCHES TR("\312Interr. lógicos", "\312Interruptores lógicos") #define TR_MENU_TRAINER "\317Entrenador" #define TR_MENU_CHANNELS "\320Canales" #define TR_MENU_GVARS "\311GVars" -#define TR_MENU_TELEMETRY "\321Telemetria" -#define TR_MENU_DISPLAY "Monitor" +#define TR_MENU_TELEMETRY "\321Telemetría" +#define TR_MENU_DISPLAY "MONITOR" #define TR_MENU_OTHER "Otros" #define TR_MENU_INVERT "Invertir" #define TR_JITTER_FILTER "Filtro ADC" #define TR_RTC_CHECK TR("Check RTC", "Check RTC voltaje") -#define TR_AUTH_FAILURE "Fallo auth." +#define TR_AUTH_FAILURE "Fallo " LCDW_128_480_LINEBREAK "autentificación" #define ZSTR_FLR "FLR" #define ZSTR_RSSI "RSSI" @@ -1297,7 +1304,7 @@ #define ZSTR_GATE_TIME "GteT" #define ZSTR_ESC_VOLTAGE "EscV" #define ZSTR_ESC_CURRENT "EscA" -#define ZSTR_ESC_RPM "EscR" +#define ZSTR_ESC_RPM "Erpm" #define ZSTR_ESC_CONSUMPTION "EscC" #define ZSTR_ESC_TEMP "EscT" #define ZSTR_SD1_CHANNEL "Chan" @@ -1321,3 +1328,36 @@ #define ZSTR_RB3040_CHANNEL6 "CH6A" #define ZSTR_RB3040_CHANNEL7 "CH7A" #define ZSTR_RB3040_CHANNEL8 "CH8A" +#define ZSTR_ESC_VIN "EVIN" +#define ZSTR_ESC_TFET "TFET" +#define ZSTR_ESC_CUR "ECUR" +#define ZSTR_ESC_TBEC "TBEC" +#define ZSTR_ESC_BCUR "CBEC" +#define ZSTR_ESC_VBEC "VBEC" +#define ZSTR_ESC_THR "ETHR" +#define ZSTR_ESC_POUT "EOUT" +#define ZSTR_SMART_BAT_BTMP "BTmp" +#define ZSTR_SMART_BAT_BCUR "BCur" +#define ZSTR_SMART_BAT_BCAP "BUse" +#define ZSTR_SMART_BAT_MIN_CEL "CLMi" +#define ZSTR_SMART_BAT_MAX_CEL "CLMa" +#define ZSTR_SMART_BAT_CYCLES "Cycl" +#define ZSTR_SMART_BAT_CAPACITY "BCpT" +#define ZSTR_CL01 "Cel1" +#define ZSTR_CL02 "Cel2" +#define ZSTR_CL03 "Cel3" +#define ZSTR_CL04 "Cel4" +#define ZSTR_CL05 "Cel5" +#define ZSTR_CL06 "Cel6" +#define ZSTR_CL07 "Cel7" +#define ZSTR_CL08 "Cel8" +#define ZSTR_CL09 "Cel9" +#define ZSTR_CL10 "Cl10" +#define ZSTR_CL11 "Cl11" +#define ZSTR_CL12 "Cl12" +#define ZSTR_CL13 "Cl13" +#define ZSTR_CL14 "Cl14" +#define ZSTR_CL15 "Cl15" +#define ZSTR_CL16 "Cl16" +#define ZSTR_CL17 "Cl17" +#define ZSTR_CL18 "Cl18" \ No newline at end of file diff --git a/radio/src/translations/fi.h.txt b/radio/src/translations/fi.h.txt index 20e27d5fb..e21621409 100644 --- a/radio/src/translations/fi.h.txt +++ b/radio/src/translations/fi.h.txt @@ -168,6 +168,9 @@ #define LEN_VCSWFUNC "\005" #define TR_VCSWFUNC "---\0 " TR_CSWEQUAL "a~x\0 ""a>x\0 ""ax""|a|b\0 ""ax\0 ""ax""|a|b\0 ""ax\0 ""ax""|a|b\0 ""a left: - if self.is_column_needed(px, right, image.height): + if self.is_column_needed(px, right, image.height, debug): break right -= 1 top = 0 @@ -74,19 +76,15 @@ class FontBitmap: bottom -= 1 return left, top, right, bottom - def draw_char(self, image, x, c, font): + def draw_char(self, image, x, c, font, offset_y=0): size = font.font.getsize(c) width = size[0][0] - offset = size[1][0] - char_image = Image.new("RGB", (width, image.height), self.background) + offset_x = size[1][0] + char_image = Image.new("RGB", (width + 10, image.height), self.background) draw = ImageDraw.Draw(char_image) - draw.text((-offset, 0), c, fill=self.foreground, font=font) - left, _, right, _ = self.get_real_size(char_image) - if right + offset + 1 < width: - # print("char %c: space reduced" % c) - width = right + offset + 1 + draw.text((-offset_x, offset_y), c, fill=self.foreground, font=font) if image: - image.paste(char_image.crop((-offset, 0, width, image.height)), (x, 0)) + image.paste(char_image.crop((0, 0, width, image.height)), (x, 0)) return width def generate(self, filename, generate_coords_file=True): @@ -98,11 +96,17 @@ class FontBitmap: if c == " ": w = 4 elif c in special_chars["cn"]: - w = self.draw_char(image, width, c, self.cjk_font) - elif c not in extra_chars: - w = self.draw_char(image, width, c, self.font) - else: + w = self.draw_char(image, width, c, self.cjk_font, -3) + elif c in extra_chars: + if self.extra_bitmap: + image.paste(self.extra_bitmap.copy(), (width, 0)) + for coord in [14, 14, 12, 12, 13, 13, 13, 13, 13] + [15] * 12: + width += coord + coords.append(width) + self.extra_bitmap = None continue + else: + w = self.draw_char(image, width, c, self.font) coords.append(width) width += w @@ -110,13 +114,9 @@ class FontBitmap: _, top, _, bottom = self.get_real_size(image) - if self.extra_bitmap: - image.paste(self.extra_bitmap.copy(), (width, top)) - for coord in [14, 14, 12, 12, 13, 13, 13, 13, 13] + [15] * 12: - width += coord - coords.append(width) - - image = image.crop((0, top, width, bottom + 1)) + top = 1 + # bottom = self.font_size + image = image.crop((0, top, width - 1, bottom)) coords.insert(0, bottom - top + 1) image.save(filename + ".png") diff --git a/tools/build-frsky.py b/tools/build-frsky.py index 3db1e97fb..e4478a2a8 100755 --- a/tools/build-frsky.py +++ b/tools/build-frsky.py @@ -134,7 +134,7 @@ def build(board, translation, srcdir): os.mkdir("output") path = tempfile.mkdtemp() os.chdir(path) - command = "cmake %s -DTRANSLATIONS=%s -DFRSKY_RELEASE=YES %s" % (cmake_options, translation, srcdir) + command = "cmake %s -DTRANSLATIONS=%s -DFRSKY_RELEASE=YES -DDEFAULT_TEMPLATE_SETUP=17 %s" % (cmake_options, translation, srcdir) print(command) os.system(command) os.system("make firmware -j6") diff --git a/tools/encode-font.py b/tools/encode-font.py index f5758bc43..aeed8a068 100755 --- a/tools/encode-font.py +++ b/tools/encode-font.py @@ -1,6 +1,5 @@ #!/usr/bin/env python - import sys import argparse from PIL import Image