From 92396f4767d7cb7598935a8c8b1af092df0234a8 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Fri, 29 May 2020 14:40:50 +0200 Subject: [PATCH 01/93] Update CREDITS.txt --- CREDITS.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CREDITS.txt b/CREDITS.txt index b7ce3cb68..c8e43f756 100644 --- a/CREDITS.txt +++ b/CREDITS.txt @@ -1733,3 +1733,4 @@ MeCodeGoodSomeday Timothy Fry John Beech Wojciech Winiarski +Armin Kuepfer From 8ebc4fa8917a7bf698ee74dbb372919638645624 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Charpentier?= Date: Fri, 29 May 2020 18:06:16 +0200 Subject: [PATCH 02/93] Updated French translation (#7640) * Initial state. * Updated French Translation. --- companion/src/translations/companion_fr.ts | 708 ++++++++++++++------- 1 file changed, 492 insertions(+), 216 deletions(-) diff --git a/companion/src/translations/companion_fr.ts b/companion/src/translations/companion_fr.ts index c8d06c20f..fff65e6d9 100644 --- a/companion/src/translations/companion_fr.ts +++ b/companion/src/translations/companion_fr.ts @@ -903,50 +903,65 @@ Manche Droit: Profondeur, Direction - + + Delete Channel. Are you sure? + Supprimer la Voie. Êtes-vous sûr? + + + Copy Copier - + Cut Couper - + Paste Coller - + Clear Effacer - + Insert Insérer - + Delete Supprimer - + Move Up Monter - + Move Down Descendre - + Clear All Effacer Tout + + + Clear Channel. Are you sure? + Effacer la Voie. Êtes-vous sûr? + + + + Clear all Channels. Are you sure? + Effacer toutes les Voies. Êtes-vous sûr? + ChecklistDialog @@ -1361,7 +1376,7 @@ Si vous avez un fichier de sauvegarde des paramètres, vous pouvez l'import CurveData - + CV CB @@ -1501,77 +1516,107 @@ Si vous avez un fichier de sauvegarde des paramètres, vous pouvez l'import Nom de la courbe - + Curve %1 Courbe %1 - + Popup menu available Menu contextuel disponible - + %1 points - + Linear Linéaire - + Single Expo Expo simple - + Symmetrical f(x)=-f(-x) Symétrique f(x)=-f(-x) - + Symmetrical f(x)=f(-x) Symétrique f(x)=f(-x) - + Copy Copier - + + Cut + Couper + + + Paste Coller - + Clear Effacer - - Clear all curves - Effacer toutes les courbes + + Insert + Insérer - - Are you sure you want to reset curve %1? - Etes-vous sûr de vouloir effacer la courbe %1 ? + + Delete + Supprimer - - Are you sure you want to reset all curves? - Etes-vous sûr de vouloir effacer toutes les courbes ? + + Move Up + Monter - + + Move Down + Descendre + + + + Clear All + Effacer Tout + + + + Clear Curve. Are you sure? + Effacer la Courbe. Êtes-vous sûr? + + + + Clear all Curves. Are you sure? + Effacer toutes les Courbes. Êtes-vous sûr? + + + + Delete Curve. Are you sure? + Supprimer la Courbe. Êtes-vous sûr? + + + Editing curve %1 Édition de la courbe %1 - + Not enough free points in EEPROM to store the curve. Pas assez de points disponibles en mémoire pour enregistrer la courbe. @@ -1871,70 +1916,85 @@ Si vous avez un fichier de sauvegarde des paramètres, vous pouvez l'import %1 - + + Delete Special Function. Are you sure? + Supprimer la Fonction Spéciale. Êtes-vous sûr? + + + Copy Copier - + Cut Couper - + Paste Coller - + Clear Effacer - + Insert Insérer - + Delete Supprimer - + Move Up Monter - + Move Down Descendre - + Clear All Effacer Tout - + Value Valeur - + Source Source - + GVAR VG - + Increment Incrément + + + Clear Special Function. Are you sure? + Effacer la Fonction Spéciale. Êtes-vous sûr? + + + + Clear all Special Functions. Are you sure? + Supprimer toutes les Fonctions Spéciales. Êtes-vous sûr? + CustomizeSplashDialog @@ -2877,274 +2937,279 @@ Blanc signifie "inclure tous".Les métacaractères ?, * et [...] sont Firmware - + Channel values displayed in us Positions de voies affichées en µs - + No OverrideCH functions available Désactive la fonction spéciale "Remplacer VOIExx" - + Possibility to enable FAI MODE (no telemetry) at field Possibilité d'activer le mode FAI (télémétrie désactivée) sur le terrain - + FAI MODE (no telemetry) always enabled Mode FAI (télémétrie toujours désactivée) - + Removes D8 FrSky protocol support which is not legal for use in the EU on radios sold after Jan 1st, 2015 Masque le protocole D8. Légalement obligatoire sur les radios Européennes importées après le 1er janvier 2015 - - + + Disable HELI menu and cyclic mix support Supprimer le menu HELICO et les mixages cycliques - - + + Disable Global variables Supprimer le support des variables globales - - + + Enable Lua custom scripts screen Activer l'écran des scripts Lua personnalisés - + Support for PPM internal module hack Support du remplacement du module interne par un module PPM - + Use alternative SQT5 font Utiliser la police alternative SQT5 - - + + Disable RAS (SWR) Désactiver le RAS (SWR). Utile uniquement pour les X9D+ avec un RAS/SWR non fonctionnel - + Pots use in menus navigation Support de la navigation dans les menus avec les POTS - + FrSky Taranis X9D+ - + FrSky Taranis X9D+ 2019 - + FrSky Taranis X9D - + Haptic module installed Module vibreur installé - + FrSky Taranis X9E - + Confirmation before radio shutdown Confirmation avant l'arrêt de la radio - + Horus gimbals installed (Hall sensors) Manches Horus à effet HALL installés - + FrSky Taranis X9-Lite - + FrSky Taranis X9-Lite S - + FrSky Taranis X7 / X7S - + FrSky Taranis X7 / X7S Access - + FrSky Taranis X-Lite S/PRO - + FrSky Taranis X-Lite - + FrSky Horus X10 / X10S - - + + Support for ACCESS internal module replacement Prise en charge du module de remplacement interne ACCESS - + FrSky Horus X10 Express / X10S Express - + FrSky Horus X12S - + Use ONLY with first DEV pcb version Exclusivement pour les Horus DEV - - + + Support for MULTI internal module Prise en charge du module MULTI interne - - + + Support for bluetooth module Prise en charge du module Bluetooth - + Radiomaster TX16s / TX16s Hall / TX16s Masterfire - + + Support internal GPS + Prise en charge du GPS interne + + + Turnigy 9XR-PRO - + Enable HELI menu and cyclic mix support Activer le menu hélico et les mixages CCPM - + Global variables Variables globales - + Enable non certified firmwares Activer les firmwares non certifiés - + In model setup menus automatically set source by moving the control Sélectionner les sources des mixeurs en bougeant le contrôle désiré - + In model setup menus automatically set switch by moving the control Sélectionner les interrupteurs en bougeant le contrôle désiré - + No graphical check boxes and sliders Pas de cases à cocher et de curseurs graphiques - + Battery graph Graphique de la batterie - + Don't use bold font for highlighting active items Ne pas mettre les lignes actives en gras - + Turnigy 9XR with m128 chip Turnigy 9XR avec une puce m128 - + Turnigy 9XR - + 9X with stock board 9X avec carte mère d'origine - + Enable resetting values by pressing up and down at the same time Permet la remise à zéro des valeurs en pressant haut-bas en même temps, valeur min avec gauche/bas, valeur max avec haut/droite, inversion avec gauche/droite - + 9X with stock board and m128 chip Carte 9x avec un chip m128 - + 9X with AR9X board 9X avec carte AR9X - + Jumper T12 / T12 Pro - + Jumper T16 / T16+ / T16 Pro - + 9X with Sky9x board 9X avec carte Sky9x - + 9X with Gruvin9x board 9X avec carte Gruvin9x - + DIY MEGA2560 radio Radio DIY à base de MEGA2560 @@ -3633,7 +3698,7 @@ Vous utilisez actuellement: FlightModeData - + FM PV @@ -3641,122 +3706,200 @@ 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 - + + Warning: Global variable links back to itself. Flight Mode 0 value used. + Avertissement: la Variable Globale boucle sur elle-même. La Phase de Vol 0 est utilisée. + + + + Warning: Rotary encoder links back to itself. Flight Mode 0 value used. + Avertissement: le Sélecteur Rotatif boucle sur lui-même. La Phase de Vol 0 est utilisée. + + + + + Copy + Copier + + + + + Cut + Couper + + + + + Paste + Coller + + + + + Insert + Insérer + + + + + Delete + Supprimer + + + + + Move Up + Monter + + + + + Move Down + Descendre + + + + + Clear All + Effacer Tout + + + + Clear Flight Mode. Are you sure? + Effacer la Phase de Vol. Êtes-vous sûr? + + + + Clear all Flight Modes. Are you sure? + Effacer toutes les Phases de Vol. Êtes-vous sûr? + + + + Delete Flight Mode. Are you sure? + Supprimer la Phase de Vol. Êtes-vous sûr? + + + + Clear selected Global Variable across all Flight Modes. Are you sure? + Effacer les Variables Globales selectionnées à travers toutes les Phases de Vol. Êtes-vous sûr? + + + + Clear all Global Variables for all Flight Modes. Are you sure? + Effacer toutes les Variables Globales pour toutes les Phases de Vol. Êtes-vous sûr? + + + + Clear all Global Variables for this Flight Mode. Are you sure? + Effacer toutes les Variables Globales pour cette Phase de Vol. Êtes-vous sûr? + + + Popup enabled Indication activée - + + Popup menu available Menu contextuel disponible - + Trim disabled Trim désactivé - + Own Trim Valeur indépendante - + Use Trim from Flight mode %1 Utiliser le trim de la phase de vol %1 - + Use Trim from Flight mode %1 + Own Trim as an offset Utiliser le trim de la phase de vol %1 + une valeur indépendante additionnée - + 0._ - + 0.0 - - - &Clear - &Effacer - - - - + + Clear Effacer - - - Clear all current Flight Mode properties? - Effacer tout les modes de vols ? - FlightModesPanel - + Flight Mode %1 Phase de vol %1 - + (%1) - + (default) (par défaut) @@ -5582,25 +5725,27 @@ Cette fonction ne peut pas être désactivée sur la radio. InputsPanel - + + Move Up Monter - + Ctrl+Up Ctrl+Haut - + + Move Down Descendre - + Ctrl+Down Ctrl+Bas @@ -5610,110 +5755,141 @@ Cette fonction ne peut pas être désactivée sur la radio. Effacer toutes les entrées - - Not enough available inputs! - Pas assez d'entrées disponibles ! + + Not enough available Inputs! + Pas assez d'Entrées disponibles! - - Delete Selected Inputs? - Supprimer les entrées sélectionnées ? + + Delete selected Inputs. Are you sure? + Supprimer les Entrées selectionnés. Êtes-vous sûr? - + + Lines + Linéaire + + + &Add &Ajouter - + Ctrl+A Ctrl+A - + &Edit &Édition - + Enter Entrée - + &Delete &Supprimer - + + Delete Supprimer - + &Copy &Copier - + Ctrl+C - + &Cut &Couper - + Ctrl+X - + &Paste &Coller - + Ctrl+V - + Du&plicate Du&pliquer - + Ctrl+U - - Clear Inputs? - Effacer toutes les entrées ? + + Input + Entrée - - Really clear all the inputs? - Voulez-vous vraiment effacer toutes les entrées ? + + Insert + Insérer + + + + Clear + Effacer + + + + Clear All + Effacer Tout + + + + Clear all Inputs. Are you sure? + Effacer toutes les Entrées. Êtes-vous sûr? + + + + Clear Input. Are you sure? + Effacer l'Entrée. Êtes-vous sûr? + + + + Delete Input. Are you sure? + Supprimer l'Entrée. Êtes-vous sûr? LimitData - + INV - + NOR - + CH VOIE @@ -5852,69 +6028,104 @@ Cette fonction ne peut pas être désactivée sur la radio. LogicalSwitchesPanel - + V1 - + V2 - + Duration Durée - + Delay Délai - + Function Fonction - + AND Switch ET supplémentaire - + Popup menu available Menu contextuel disponible - + (instant) - + (infinite) (infini) - - &Delete - &Supprimer - - - - &Copy - &Copier - - - - &Cut - &Couper + + Delete Logical Switch. Are you sure? + Supprimer l'Interrupteur Logique. Êtes-vous sûr? - &Paste - &Coller + Copy + Copier + + + + Cut + Couper + + + + Paste + Coller + + + + Clear + Effacer + + + + Insert + Insérer + + + + Delete + Supprimer + + + + Move Up + Monter + + + + Move Down + Descendre + + + + Clear All + Effacer Tout + + + + Clear all Logical Switches. Are you sure? + Effacer tous les Interrupteurs Logiques. Êtes-vous sûr? @@ -7457,12 +7668,12 @@ Enregistrer les changements ? MixData - + MIX - + (@%1) @@ -7857,12 +8068,12 @@ Mixage actif par défaut si non-renseigné. ModelData - + Model: Modèle: - + Throttle Source Source des gaz @@ -8998,12 +9209,12 @@ Mixage actif par défaut si non-renseigné. ModuleData - + Positive - + Negative Négative @@ -9084,47 +9295,47 @@ Mixage actif par défaut si non-renseigné. ModulePanel - + Value Valeur - + Hold Maintien - + No Pulse Pas d'impulsion - + Ask Demander - + Internal Interne - + Internal + External Interne + Externe - + External Externe - + Autodetect Format Format Détection auto - + Bind on channel Bind avec VOIE @@ -11075,25 +11286,90 @@ Si cette option est cochée, la voie des gaz est inversée: le ralenti est &apo SetupPanel - + + Popup menu available + Menu contextuel disponible + + + Timer %1 Chrono %1 - + THR GAZ - + Profile Settings Paramètres du profil - + SD structure path not specified or invalid Chemin de la structure SD non spécifié ou invalide + + + Copy + Copier + + + + Cut + Couper + + + + Paste + Coller + + + + Clear + Effacer + + + + Insert + Insérer + + + + Delete + Supprimer + + + + Move Up + Monter + + + + Move Down + Descendre + + + + Clear All + Effacer Tout + + + + Clear Timer. Are you sure? + Effacer le Chrono. Êtes-vous sûr? + + + + Clear all Timers. Are you sure? + Effacer tous les Chronos. Êtes-vous sûr? + + + + Delete Timer. Are you sure? + Supprimer le Chrono. Êtes-vous sûr? + SimpleTailPage @@ -13410,12 +13686,12 @@ hh:mm:ss TimerData - + TMR - + Timer %1 Chrono %1 From 3504a4bb40811bf10cc16bb29213f73447d8027f Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Sat, 30 May 2020 10:51:26 +0200 Subject: [PATCH 03/93] Update CREDITS.txt --- CREDITS.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CREDITS.txt b/CREDITS.txt index c8e43f756..1f743164c 100644 --- a/CREDITS.txt +++ b/CREDITS.txt @@ -1734,3 +1734,4 @@ Timothy Fry John Beech Wojciech Winiarski Armin Kuepfer +Alain Bregand From e3c97723cd7267ddeec80ff2387b1aaefa88eba4 Mon Sep 17 00:00:00 2001 From: DanielGeA Date: Sat, 30 May 2020 11:00:46 +0100 Subject: [PATCH 04/93] Fix 7641 (#7642) --- radio/src/gui/128x64/model_logical_switches.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radio/src/gui/128x64/model_logical_switches.cpp b/radio/src/gui/128x64/model_logical_switches.cpp index 0ce6bb44b..c07be3c72 100644 --- a/radio/src/gui/128x64/model_logical_switches.cpp +++ b/radio/src/gui/128x64/model_logical_switches.cpp @@ -259,7 +259,7 @@ void menuModelLogicalSwitches(event_t event) LogicalSwitchData * cs = lswAddress(sub); if (cs->func) s_currIdx = sub; - POPUP_MENU_ADD_ITEM(STR_EDIT); + if (sub >=0) POPUP_MENU_ADD_ITEM(STR_EDIT); if (cs->func || cs->v1 || cs->v2 || cs->delay || cs->duration || cs->andsw) POPUP_MENU_ADD_ITEM(STR_COPY); if (clipboard.type == CLIPBOARD_TYPE_CUSTOM_SWITCH) From 100a405a835d9836844418aba25e9d6d26fb4244 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Sat, 30 May 2020 12:02:22 +0200 Subject: [PATCH 05/93] Cosmetics --- radio/src/gui/128x64/model_logical_switches.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/radio/src/gui/128x64/model_logical_switches.cpp b/radio/src/gui/128x64/model_logical_switches.cpp index c07be3c72..b0acc2ae4 100644 --- a/radio/src/gui/128x64/model_logical_switches.cpp +++ b/radio/src/gui/128x64/model_logical_switches.cpp @@ -254,12 +254,13 @@ void menuModelLogicalSwitches(event_t event) uint8_t k = 0; int8_t sub = menuVerticalPosition - HEADER_LINE; - if (event==EVT_KEY_FIRST(KEY_ENTER)) { + if (event == EVT_KEY_FIRST(KEY_ENTER)) { killEvents(event); LogicalSwitchData * cs = lswAddress(sub); if (cs->func) s_currIdx = sub; - if (sub >=0) POPUP_MENU_ADD_ITEM(STR_EDIT); + if (sub >= 0) + POPUP_MENU_ADD_ITEM(STR_EDIT); if (cs->func || cs->v1 || cs->v2 || cs->delay || cs->duration || cs->andsw) POPUP_MENU_ADD_ITEM(STR_COPY); if (clipboard.type == CLIPBOARD_TYPE_CUSTOM_SWITCH) From d6c0ae4645b8ffb77bf21b777f185cbc4e7bb880 Mon Sep 17 00:00:00 2001 From: DanielGeA Date: Sat, 30 May 2020 11:06:37 +0100 Subject: [PATCH 06/93] Fix 6853 (#7643) --- radio/src/gui/128x64/model_curve_edit.cpp | 3 +++ radio/src/gui/212x64/model_curve_edit.cpp | 3 +++ radio/src/gui/480x272/model_curves.cpp | 3 +++ 3 files changed, 9 insertions(+) diff --git a/radio/src/gui/128x64/model_curve_edit.cpp b/radio/src/gui/128x64/model_curve_edit.cpp index 8f606072c..2dfdaf567 100644 --- a/radio/src/gui/128x64/model_curve_edit.cpp +++ b/radio/src/gui/128x64/model_curve_edit.cpp @@ -125,6 +125,9 @@ void menuModelCurveOne(event_t event) lcdDrawNumber(INDENT_WIDTH, 6*FH+1, 5+crv.points, LEFT|attr); lcdDrawText(lcdLastRightPos, 6*FH+1, STR_PTS, attr); if (attr) { +#if defined(ROTARY_ENCODER_NAVIGATION) + rotencSpeed = ROTENC_LOWSPEED; +#endif int8_t count = checkIncDecModel(event, crv.points, -3, 12); // 2pts - 17pts if (checkIncDec_Ret) { int8_t newPoints[MAX_POINTS_PER_CURVE]; diff --git a/radio/src/gui/212x64/model_curve_edit.cpp b/radio/src/gui/212x64/model_curve_edit.cpp index 681480602..5cc622903 100644 --- a/radio/src/gui/212x64/model_curve_edit.cpp +++ b/radio/src/gui/212x64/model_curve_edit.cpp @@ -131,6 +131,9 @@ void menuModelCurveOne(event_t event) lcdDrawNumber(INDENT_WIDTH, 6*FH+1, 5+crv.points, LEFT|attr); lcdDrawText(lcdLastRightPos, 6*FH+1, STR_PTS, attr); if (attr) { +#if defined(ROTARY_ENCODER_NAVIGATION) + rotencSpeed = ROTENC_LOWSPEED; +#endif int8_t count = checkIncDecModel(event, crv.points, -3, 12); // 2pts - 17pts if (checkIncDec_Ret) { int8_t newPoints[MAX_POINTS_PER_CURVE]; diff --git a/radio/src/gui/480x272/model_curves.cpp b/radio/src/gui/480x272/model_curves.cpp index a7f8adf29..e53f9aad4 100644 --- a/radio/src/gui/480x272/model_curves.cpp +++ b/radio/src/gui/480x272/model_curves.cpp @@ -155,6 +155,9 @@ bool menuModelCurveOne(event_t event) lcdDrawText(MENUS_MARGIN_LEFT, MENU_CONTENT_TOP + FH, STR_COUNT); lcdDrawNumber(MODEL_CURVE_ONE_2ND_COLUMN, MENU_CONTENT_TOP + FH, 5+crv.points, LEFT|attr, 0, NULL, STR_PTS); if (attr) { +#if defined(ROTARY_ENCODER_NAVIGATION) + rotencSpeed = ROTENC_LOWSPEED; +#endif int count = checkIncDecModel(event, crv.points, -3, 12); // 2pts - 17pts if (checkIncDec_Ret) { int newPoints[MAX_POINTS_PER_CURVE]; From fe9750fc0ce2b0b961e5827558a1dd80e7ee75eb Mon Sep 17 00:00:00 2001 From: DanielGeA Date: Sat, 30 May 2020 11:08:19 +0100 Subject: [PATCH 07/93] Fix 9x rotary encoder source (#7639) Fix rotary encoder source --- companion/src/firmwares/opentx/opentxeeprom.cpp | 2 +- radio/src/translations/untranslated.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/companion/src/firmwares/opentx/opentxeeprom.cpp b/companion/src/firmwares/opentx/opentxeeprom.cpp index f2275fe61..e39d04180 100644 --- a/companion/src/firmwares/opentx/opentxeeprom.cpp +++ b/companion/src/firmwares/opentx/opentxeeprom.cpp @@ -128,7 +128,7 @@ inline int SWITCHES_CONFIG_SIZE(Board::Type board, int version) return 16; } -#define MAX_ROTARY_ENCODERS(board) (IS_SKY9X(board) ? 1 : 0) +#define MAX_ROTARY_ENCODERS(board) 0 #define MAX_FLIGHT_MODES(board, version) 9 #define MAX_TIMERS(board, version) 3 #define MAX_MIXERS(board, version) 64 diff --git a/radio/src/translations/untranslated.h b/radio/src/translations/untranslated.h index d737b7c5e..88289ed22 100644 --- a/radio/src/translations/untranslated.h +++ b/radio/src/translations/untranslated.h @@ -78,7 +78,7 @@ #define TR_VTRAINERMODES TR_VTRAINER_MASTER_JACK TR_VTRAINER_SLAVE_JACK TR_VTRAINER_MASTER_CPPM_MODULE TR_VTRAINER_MASTER_BATTERY TR_VTRAINER_BLUETOOTH TR_VTRAINER_MULTI #endif -#define TR_VSRCRAW "---\0" TR_STICKS_VSRCRAW TR_POTS_VSRCRAW TR_ROTARY_ENCODERS TR_GYR_VSRCRAW "MAX\0" TR_CYC_VSRCRAW TR_TRIMS_VSRCRAW TR_SW_VSRCRAW TR_EXTRA_VSRCRAW +#define TR_VSRCRAW "---\0" TR_STICKS_VSRCRAW TR_POTS_VSRCRAW TR_GYR_VSRCRAW "MAX\0" TR_CYC_VSRCRAW TR_TRIMS_VSRCRAW TR_SW_VSRCRAW TR_EXTRA_VSRCRAW #if defined(MODULE_PROTOCOL_FLEX) #define TR_MODULE_R9M_LITE "R9ML\0 " From fa1e6f087cddcd634f28fcc0a00d44ab40f933ed Mon Sep 17 00:00:00 2001 From: pascallanger Date: Sat, 30 May 2020 12:11:36 +0200 Subject: [PATCH 08/93] Graupner HoTT: full telemetry (#7627) --- .../horus/SCRIPTS/TOOLS/Graupner HoTT.lua | 87 ++- .../SCRIPTS/TOOLS/Graupner HoTT.lua | 87 ++- .../SCRIPTS/TOOLS/Graupner HoTT.lua | 87 ++- radio/src/pulses/multi.cpp | 2 +- radio/src/telemetry/frsky_d.cpp | 6 +- radio/src/telemetry/frsky_sport.cpp | 2 + radio/src/telemetry/hott.cpp | 596 ++++++++++++++++-- radio/src/telemetry/multi.cpp | 3 +- radio/src/telemetry/telemetry_holders.h | 1 + radio/src/telemetry/telemetry_sensors.cpp | 2 + radio/src/telemetry/telemetry_sensors.h | 2 +- 11 files changed, 742 insertions(+), 133 deletions(-) diff --git a/radio/sdcard/horus/SCRIPTS/TOOLS/Graupner HoTT.lua b/radio/sdcard/horus/SCRIPTS/TOOLS/Graupner HoTT.lua index ff6a3254c..d0a7d4af8 100644 --- a/radio/sdcard/horus/SCRIPTS/TOOLS/Graupner HoTT.lua +++ b/radio/sdcard/horus/SCRIPTS/TOOLS/Graupner HoTT.lua @@ -21,19 +21,41 @@ -- To start operation: -- Write "HoTT" at address 0..3 -- Write 0xFF at address 4 will request the buffer to be cleared --- Write 0xDF at address 5 +-- Write 0x0F at address 5 -- Read buffer from address 6 access the RX text for 168 bytes, 21 caracters -- by 8 lines --- Write at address 5 sends an order to the RX: 0xDF=start, 0xD7=prev page, --- 0xDE=next page, 0xD9=enter, 0xDD=next or 0xDB=prev +-- Write at address 5 sends an order to the RX: 0xXF=start, 0xX7=prev page, +-- 0xXE=next page, 0xX9=enter, 0xXD=next or 0xXB=prev with X being the sensor +-- to request data from 8=RX only, 9=Vario, A=GPS, B=Cust, C=ESC, D=GAM, E=EAM -- Write at address 4 the value 0xFF will request the buffer to be cleared -- !! Before exiting the script must write 0 at address 0 for normal operation !! --############################################################################### +HoTT_Sensor = 0 +Timer_128 = 100 + local function HoTT_Release() multiBuffer( 0, 0 ) end +local function HoTT_Send(button) + multiBuffer( 5, 0x80+(HoTT_Sensor*16) + button) +end + +local function HoTT_Sensor_Inc() + local detected_sensors=multiBuffer( 4 ) + local a + if detected_sensors ~= 0xFF then + repeat + HoTT_Sensor=(HoTT_Sensor+1)%7 -- Switch to next sensor + if HoTT_Sensor ~= 0 then + a = math.floor(detected_sensors/ (2^(HoTT_Sensor-1))) -- shift right + end + until HoTT_Sensor==0 or a % 2 == 1 + HoTT_Send( 0x0F ) + end +end + local function HoTT_Draw_LCD() local i local value @@ -41,12 +63,14 @@ local function HoTT_Draw_LCD() local result local offset=0 + local sensor_name = { "", "+Vario", "+GPS", "+Cust", "+ESC", "+GAM", "+EAM" } + lcd.clear() if LCD_W == 480 then --Draw title lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR) - lcd.drawText(1, 5, "Graupner HoTT RX configuration", MENU_TITLE_COLOR) + lcd.drawText(1, 5, "Graupner HoTT: config RX" .. sensor_name[HoTT_Sensor+1] .. " - Menu cycle Sensors", MENU_TITLE_COLOR) --Draw RX Menu if multiBuffer( 4 ) == 0xFF then lcd.drawText(10,50,"No HoTT telemetry...", BLINK) @@ -56,9 +80,9 @@ local function HoTT_Draw_LCD() value=multiBuffer( line*21+6+i ) if value > 0x80 then value = value - 0x80 - lcd.drawText(10+i*16,32+16*line,string.char(value).." ",INVERS) + lcd.drawText(10+i*16,32+20*line,string.char(value).." ",INVERS) else - lcd.drawText(10+i*16,32+16*line,string.char(value)) + lcd.drawText(10+i*16,32+20*line,string.char(value)) end end end @@ -68,14 +92,23 @@ local function HoTT_Draw_LCD() if multiBuffer( 4 ) == 0xFF then lcd.drawText(2,17,"No HoTT telemetry...",SMLSIZE) else - for line = 0, 7, 1 do - for i = 0, 21-1, 1 do - value=multiBuffer( line*21+6+i ) - if value > 0x80 then - value = value - 0x80 - lcd.drawText(2+i*6,1+8*line,string.char(value).." ",SMLSIZE+INVERS) - else - lcd.drawText(2+i*6,1+8*line,string.char(value),SMLSIZE) + if Timer_128 ~= 0 then + --Intro page + Timer_128 = Timer_128 - 1 + lcd.drawScreenTitle("Graupner Hott",0,0) + lcd.drawText(2,17,"Configuration of RX" .. sensor_name[HoTT_Sensor+1] ,SMLSIZE) + lcd.drawText(2,37,"Press menu to cycle Sensors" ,SMLSIZE) + else + --Menu page + for line = 0, 7, 1 do + for i = 0, 21-1, 1 do + value=multiBuffer( line*21+6+i ) + if value > 0x80 then + value = value - 0x80 + lcd.drawText(2+i*6,1+8*line,string.char(value).." ",SMLSIZE+INVERS) + else + lcd.drawText(2+i*6,1+8*line,string.char(value),SMLSIZE) + end end end end @@ -98,7 +131,10 @@ local function HoTT_Init() --Request init of the RX buffer multiBuffer( 4, 0xFF ) --Request RX to send the config menu - multiBuffer( 5, 0xDF ) + HoTT_Send( 0x0F ) + HoTT_Sensor = 0; + HoTT_Detected_Sensors=0; + Timer_128 = 100 end -- Main @@ -111,18 +147,21 @@ local function HoTT_Run(event) return 2 else if event == EVT_VIRTUAL_PREV_PAGE then - killEvents(event); - multiBuffer( 5, 0xD7 ) - elseif event == EVT_VIRTUAL_NEXT_PAGE then - multiBuffer( 5, 0xDE ) + killEvents(event) + HoTT_Send( 0x07 ) elseif event == EVT_VIRTUAL_ENTER then - multiBuffer( 5, 0xD9 ) - elseif event == EVT_VIRTUAL_NEXT then - multiBuffer( 5, 0xDD ) + HoTT_Send( 0x09 ) elseif event == EVT_VIRTUAL_PREV then - multiBuffer( 5, 0xDB ) + HoTT_Send( 0x0B ) + elseif event == EVT_VIRTUAL_NEXT then + HoTT_Send( 0x0D ) + elseif event == EVT_VIRTUAL_NEXT_PAGE then + HoTT_Send( 0x0E ) + elseif event == EVT_VIRTUAL_MENU then + Timer_128 = 100 + HoTT_Sensor_Inc() else - multiBuffer( 5, 0xDF ) + HoTT_Send( 0x0F ) end HoTT_Draw_LCD() return 0 diff --git a/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/Graupner HoTT.lua b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/Graupner HoTT.lua index ff6a3254c..d0a7d4af8 100644 --- a/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/Graupner HoTT.lua +++ b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/Graupner HoTT.lua @@ -21,19 +21,41 @@ -- To start operation: -- Write "HoTT" at address 0..3 -- Write 0xFF at address 4 will request the buffer to be cleared --- Write 0xDF at address 5 +-- Write 0x0F at address 5 -- Read buffer from address 6 access the RX text for 168 bytes, 21 caracters -- by 8 lines --- Write at address 5 sends an order to the RX: 0xDF=start, 0xD7=prev page, --- 0xDE=next page, 0xD9=enter, 0xDD=next or 0xDB=prev +-- Write at address 5 sends an order to the RX: 0xXF=start, 0xX7=prev page, +-- 0xXE=next page, 0xX9=enter, 0xXD=next or 0xXB=prev with X being the sensor +-- to request data from 8=RX only, 9=Vario, A=GPS, B=Cust, C=ESC, D=GAM, E=EAM -- Write at address 4 the value 0xFF will request the buffer to be cleared -- !! Before exiting the script must write 0 at address 0 for normal operation !! --############################################################################### +HoTT_Sensor = 0 +Timer_128 = 100 + local function HoTT_Release() multiBuffer( 0, 0 ) end +local function HoTT_Send(button) + multiBuffer( 5, 0x80+(HoTT_Sensor*16) + button) +end + +local function HoTT_Sensor_Inc() + local detected_sensors=multiBuffer( 4 ) + local a + if detected_sensors ~= 0xFF then + repeat + HoTT_Sensor=(HoTT_Sensor+1)%7 -- Switch to next sensor + if HoTT_Sensor ~= 0 then + a = math.floor(detected_sensors/ (2^(HoTT_Sensor-1))) -- shift right + end + until HoTT_Sensor==0 or a % 2 == 1 + HoTT_Send( 0x0F ) + end +end + local function HoTT_Draw_LCD() local i local value @@ -41,12 +63,14 @@ local function HoTT_Draw_LCD() local result local offset=0 + local sensor_name = { "", "+Vario", "+GPS", "+Cust", "+ESC", "+GAM", "+EAM" } + lcd.clear() if LCD_W == 480 then --Draw title lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR) - lcd.drawText(1, 5, "Graupner HoTT RX configuration", MENU_TITLE_COLOR) + lcd.drawText(1, 5, "Graupner HoTT: config RX" .. sensor_name[HoTT_Sensor+1] .. " - Menu cycle Sensors", MENU_TITLE_COLOR) --Draw RX Menu if multiBuffer( 4 ) == 0xFF then lcd.drawText(10,50,"No HoTT telemetry...", BLINK) @@ -56,9 +80,9 @@ local function HoTT_Draw_LCD() value=multiBuffer( line*21+6+i ) if value > 0x80 then value = value - 0x80 - lcd.drawText(10+i*16,32+16*line,string.char(value).." ",INVERS) + lcd.drawText(10+i*16,32+20*line,string.char(value).." ",INVERS) else - lcd.drawText(10+i*16,32+16*line,string.char(value)) + lcd.drawText(10+i*16,32+20*line,string.char(value)) end end end @@ -68,14 +92,23 @@ local function HoTT_Draw_LCD() if multiBuffer( 4 ) == 0xFF then lcd.drawText(2,17,"No HoTT telemetry...",SMLSIZE) else - for line = 0, 7, 1 do - for i = 0, 21-1, 1 do - value=multiBuffer( line*21+6+i ) - if value > 0x80 then - value = value - 0x80 - lcd.drawText(2+i*6,1+8*line,string.char(value).." ",SMLSIZE+INVERS) - else - lcd.drawText(2+i*6,1+8*line,string.char(value),SMLSIZE) + if Timer_128 ~= 0 then + --Intro page + Timer_128 = Timer_128 - 1 + lcd.drawScreenTitle("Graupner Hott",0,0) + lcd.drawText(2,17,"Configuration of RX" .. sensor_name[HoTT_Sensor+1] ,SMLSIZE) + lcd.drawText(2,37,"Press menu to cycle Sensors" ,SMLSIZE) + else + --Menu page + for line = 0, 7, 1 do + for i = 0, 21-1, 1 do + value=multiBuffer( line*21+6+i ) + if value > 0x80 then + value = value - 0x80 + lcd.drawText(2+i*6,1+8*line,string.char(value).." ",SMLSIZE+INVERS) + else + lcd.drawText(2+i*6,1+8*line,string.char(value),SMLSIZE) + end end end end @@ -98,7 +131,10 @@ local function HoTT_Init() --Request init of the RX buffer multiBuffer( 4, 0xFF ) --Request RX to send the config menu - multiBuffer( 5, 0xDF ) + HoTT_Send( 0x0F ) + HoTT_Sensor = 0; + HoTT_Detected_Sensors=0; + Timer_128 = 100 end -- Main @@ -111,18 +147,21 @@ local function HoTT_Run(event) return 2 else if event == EVT_VIRTUAL_PREV_PAGE then - killEvents(event); - multiBuffer( 5, 0xD7 ) - elseif event == EVT_VIRTUAL_NEXT_PAGE then - multiBuffer( 5, 0xDE ) + killEvents(event) + HoTT_Send( 0x07 ) elseif event == EVT_VIRTUAL_ENTER then - multiBuffer( 5, 0xD9 ) - elseif event == EVT_VIRTUAL_NEXT then - multiBuffer( 5, 0xDD ) + HoTT_Send( 0x09 ) elseif event == EVT_VIRTUAL_PREV then - multiBuffer( 5, 0xDB ) + HoTT_Send( 0x0B ) + elseif event == EVT_VIRTUAL_NEXT then + HoTT_Send( 0x0D ) + elseif event == EVT_VIRTUAL_NEXT_PAGE then + HoTT_Send( 0x0E ) + elseif event == EVT_VIRTUAL_MENU then + Timer_128 = 100 + HoTT_Sensor_Inc() else - multiBuffer( 5, 0xDF ) + HoTT_Send( 0x0F ) end HoTT_Draw_LCD() return 0 diff --git a/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/Graupner HoTT.lua b/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/Graupner HoTT.lua index ff6a3254c..d0a7d4af8 100644 --- a/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/Graupner HoTT.lua +++ b/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/Graupner HoTT.lua @@ -21,19 +21,41 @@ -- To start operation: -- Write "HoTT" at address 0..3 -- Write 0xFF at address 4 will request the buffer to be cleared --- Write 0xDF at address 5 +-- Write 0x0F at address 5 -- Read buffer from address 6 access the RX text for 168 bytes, 21 caracters -- by 8 lines --- Write at address 5 sends an order to the RX: 0xDF=start, 0xD7=prev page, --- 0xDE=next page, 0xD9=enter, 0xDD=next or 0xDB=prev +-- Write at address 5 sends an order to the RX: 0xXF=start, 0xX7=prev page, +-- 0xXE=next page, 0xX9=enter, 0xXD=next or 0xXB=prev with X being the sensor +-- to request data from 8=RX only, 9=Vario, A=GPS, B=Cust, C=ESC, D=GAM, E=EAM -- Write at address 4 the value 0xFF will request the buffer to be cleared -- !! Before exiting the script must write 0 at address 0 for normal operation !! --############################################################################### +HoTT_Sensor = 0 +Timer_128 = 100 + local function HoTT_Release() multiBuffer( 0, 0 ) end +local function HoTT_Send(button) + multiBuffer( 5, 0x80+(HoTT_Sensor*16) + button) +end + +local function HoTT_Sensor_Inc() + local detected_sensors=multiBuffer( 4 ) + local a + if detected_sensors ~= 0xFF then + repeat + HoTT_Sensor=(HoTT_Sensor+1)%7 -- Switch to next sensor + if HoTT_Sensor ~= 0 then + a = math.floor(detected_sensors/ (2^(HoTT_Sensor-1))) -- shift right + end + until HoTT_Sensor==0 or a % 2 == 1 + HoTT_Send( 0x0F ) + end +end + local function HoTT_Draw_LCD() local i local value @@ -41,12 +63,14 @@ local function HoTT_Draw_LCD() local result local offset=0 + local sensor_name = { "", "+Vario", "+GPS", "+Cust", "+ESC", "+GAM", "+EAM" } + lcd.clear() if LCD_W == 480 then --Draw title lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR) - lcd.drawText(1, 5, "Graupner HoTT RX configuration", MENU_TITLE_COLOR) + lcd.drawText(1, 5, "Graupner HoTT: config RX" .. sensor_name[HoTT_Sensor+1] .. " - Menu cycle Sensors", MENU_TITLE_COLOR) --Draw RX Menu if multiBuffer( 4 ) == 0xFF then lcd.drawText(10,50,"No HoTT telemetry...", BLINK) @@ -56,9 +80,9 @@ local function HoTT_Draw_LCD() value=multiBuffer( line*21+6+i ) if value > 0x80 then value = value - 0x80 - lcd.drawText(10+i*16,32+16*line,string.char(value).." ",INVERS) + lcd.drawText(10+i*16,32+20*line,string.char(value).." ",INVERS) else - lcd.drawText(10+i*16,32+16*line,string.char(value)) + lcd.drawText(10+i*16,32+20*line,string.char(value)) end end end @@ -68,14 +92,23 @@ local function HoTT_Draw_LCD() if multiBuffer( 4 ) == 0xFF then lcd.drawText(2,17,"No HoTT telemetry...",SMLSIZE) else - for line = 0, 7, 1 do - for i = 0, 21-1, 1 do - value=multiBuffer( line*21+6+i ) - if value > 0x80 then - value = value - 0x80 - lcd.drawText(2+i*6,1+8*line,string.char(value).." ",SMLSIZE+INVERS) - else - lcd.drawText(2+i*6,1+8*line,string.char(value),SMLSIZE) + if Timer_128 ~= 0 then + --Intro page + Timer_128 = Timer_128 - 1 + lcd.drawScreenTitle("Graupner Hott",0,0) + lcd.drawText(2,17,"Configuration of RX" .. sensor_name[HoTT_Sensor+1] ,SMLSIZE) + lcd.drawText(2,37,"Press menu to cycle Sensors" ,SMLSIZE) + else + --Menu page + for line = 0, 7, 1 do + for i = 0, 21-1, 1 do + value=multiBuffer( line*21+6+i ) + if value > 0x80 then + value = value - 0x80 + lcd.drawText(2+i*6,1+8*line,string.char(value).." ",SMLSIZE+INVERS) + else + lcd.drawText(2+i*6,1+8*line,string.char(value),SMLSIZE) + end end end end @@ -98,7 +131,10 @@ local function HoTT_Init() --Request init of the RX buffer multiBuffer( 4, 0xFF ) --Request RX to send the config menu - multiBuffer( 5, 0xDF ) + HoTT_Send( 0x0F ) + HoTT_Sensor = 0; + HoTT_Detected_Sensors=0; + Timer_128 = 100 end -- Main @@ -111,18 +147,21 @@ local function HoTT_Run(event) return 2 else if event == EVT_VIRTUAL_PREV_PAGE then - killEvents(event); - multiBuffer( 5, 0xD7 ) - elseif event == EVT_VIRTUAL_NEXT_PAGE then - multiBuffer( 5, 0xDE ) + killEvents(event) + HoTT_Send( 0x07 ) elseif event == EVT_VIRTUAL_ENTER then - multiBuffer( 5, 0xD9 ) - elseif event == EVT_VIRTUAL_NEXT then - multiBuffer( 5, 0xDD ) + HoTT_Send( 0x09 ) elseif event == EVT_VIRTUAL_PREV then - multiBuffer( 5, 0xDB ) + HoTT_Send( 0x0B ) + elseif event == EVT_VIRTUAL_NEXT then + HoTT_Send( 0x0D ) + elseif event == EVT_VIRTUAL_NEXT_PAGE then + HoTT_Send( 0x0E ) + elseif event == EVT_VIRTUAL_MENU then + Timer_128 = 100 + HoTT_Sensor_Inc() else - multiBuffer( 5, 0xDF ) + HoTT_Send( 0x0F ) end HoTT_Draw_LCD() return 0 diff --git a/radio/src/pulses/multi.cpp b/radio/src/pulses/multi.cpp index 9fe10113c..cfcff15d0 100644 --- a/radio/src/pulses/multi.cpp +++ b/radio/src/pulses/multi.cpp @@ -393,7 +393,7 @@ void sendSport(uint8_t moduleIdx) void sendHott(uint8_t moduleIdx) { - if (Multi_Buffer && memcmp(Multi_Buffer, "HoTT", 4) == 0 && Multi_Buffer[5] >= 0xD7 && Multi_Buffer[5] <= 0xDF) { + if (Multi_Buffer && memcmp(Multi_Buffer, "HoTT", 4) == 0 && (Multi_Buffer[5] & 0x80) && (Multi_Buffer[5] & 0x0F) >= 0x07) { // HoTT Lua script is running sendMulti(moduleIdx, Multi_Buffer[5]); } diff --git a/radio/src/telemetry/frsky_d.cpp b/radio/src/telemetry/frsky_d.cpp index 67445c193..c1ad3f9d5 100644 --- a/radio/src/telemetry/frsky_d.cpp +++ b/radio/src/telemetry/frsky_d.cpp @@ -227,6 +227,8 @@ void processHubPacket(uint8_t id, int16_t value) else if (id == VOLTS_ID) { unit = UNIT_CELLS; uint32_t cellData = (uint32_t)data; + if (((cellData & 0x00F0) >> 4) >= MAX_CELLS) + return; data = ((cellData & 0x00F0) << 12) + (((((cellData & 0xFF00) >> 8) + ((cellData & 0x000F) << 8))) / 5); } else if (id == GPS_DAY_MONTH_ID) { @@ -264,7 +266,7 @@ void processHubPacket(uint8_t id, int16_t value) data *= 10; } } - + setTelemetryValue(PROTOCOL_TELEMETRY_FRSKY_D, id, 0, 0, data, unit, precision); } @@ -326,4 +328,4 @@ void frskyDSetDefault(int index, uint16_t id) } storageDirty(EE_MODEL); -} +} \ No newline at end of file diff --git a/radio/src/telemetry/frsky_sport.cpp b/radio/src/telemetry/frsky_sport.cpp index 0e4f3920c..d5215e300 100644 --- a/radio/src/telemetry/frsky_sport.cpp +++ b/radio/src/telemetry/frsky_sport.cpp @@ -139,6 +139,8 @@ void sportProcessTelemetryPacket(uint16_t id, uint8_t subId, uint8_t instance, u if (unit == UNIT_CELLS) { uint8_t cellsCount = (data & 0xF0) >> 4; uint8_t cellIndex = (data & 0x0F); + if (cellIndex >= MAX_CELLS) + return; uint32_t mask = (cellsCount << 24) + (cellIndex << 16); setTelemetryValue(PROTOCOL_TELEMETRY_FRSKY_SPORT, id, subId, instance, mask + (((data & 0x000FFF00) >> 8) / 5), unit, precision); if (cellIndex+1 < cellsCount) { diff --git a/radio/src/telemetry/hott.cpp b/radio/src/telemetry/hott.cpp index f36236add..98b3c54cc 100644 --- a/radio/src/telemetry/hott.cpp +++ b/radio/src/telemetry/hott.cpp @@ -16,26 +16,27 @@ #include "opentx.h" /* Telemetry -packet[0] = TX RSSI value -packet[1] = TX LQI value -packet[2] = frame number -packet[3-12] telemetry data +packet[0] = TX RSSI value +packet[1] = TX LQI value +packet[2] = Telemetry type +packet[3] = Telemetry page +packet[4-13] = Telemetry data -The frame number takes the following values: 0x00, 0x01, 0x02, 0x03 and 0x04. The frames can be present or not, they also do not have to follow each others. -Here is a description of the telemetry data for each frame number: -- frame 0x00 -[3] = [12] = ?? -[4] = RX_Voltage*10 in V -[5] = Temperature-20 in °C -[6] = RX_RSSI -[7] = RX_LQI ?? -[8] = RX_STR ?? -[9,10] = [10]*256+[9]=max lost packet time in ms, max value seems 2s=0x7D0 -[11] = 0x00 ?? -- frame 0x01 Unknown -- frame 0x02 Unknown -- frame 0x03 Unknown -- frame 0x04 Unknown +Telemetry type: 0x00 RX, 0x09 Vario, 0x0A GPS, 0x0B not seen, 0x0C ESC, 0x0D GAM, 0x0E EAM, 0x80 Text config mode +Telemetry page: 0x00..0x04 for all telemetry except Text config mode which is 0x00..0x12. The pages can be present or not, they also do not have to follow each others. + +Here is a description of the RX telemetry: + [2] = 0x00 -> Telemetry type RX + [3] = 0x00 -> Telemetry page 0 + [4] = ?? looks to be a copy of [7] + [5] = RX_Voltage*10 in V + [6] = Temperature-20 in °C + [7] = RX_RSSI CC2500 formated (a<128:a/2-71dBm, a>=128:(a-256)/2-71dBm) + [8] = RX_LQI in % + [9] = RX_MIN_Voltage*10 in V + [10,11] = [11]*256+[10]=max lost packet time in ms, max value seems 2s=0x7D0 + [12] = 0x00 ?? + [13] = ?? looks to be a copy of [7] */ struct HottSensor @@ -49,22 +50,54 @@ struct HottSensor // telemetry frames enum { - HOTT_FRAME_00 = 0x00, - HOTT_FRAME_01 = 0x01, - HOTT_FRAME_02 = 0x02, - HOTT_FRAME_03 = 0x03, - HOTT_FRAME_04 = 0x04, + HOTT_PAGE_00 = 0x00, + HOTT_PAGE_01 = 0x01, + HOTT_PAGE_02 = 0x02, + HOTT_PAGE_03 = 0x03, + HOTT_PAGE_04 = 0x04, }; -#define HOTT_TELEM_NORMAL 0x00 -#define HOTT_TELEM_BIND 0x40 -#define HOTT_TELEM_MENU 0x80 +enum +{ + HOTT_TELEM_RX = 0x00, + HOTT_TELEM_VARIO = 0x09, + HOTT_TELEM_GPS = 0x0A, + HOTT_TELEM_ESC = 0x0C, + HOTT_TELEM_GAM = 0x0D, + HOTT_TELEM_EAM = 0x0E, + HOTT_TELEM_TEXT = 0x80, +}; // telemetry sensors ID enum { HOTT_ID_RX_VOLTAGE = 0x0004, // RX_Batt Voltage HOTT_ID_TEMP1 = 0x0005, // RX Temperature sensor + HOTT_ID_VARIO = 0x0006, // Vario sensor + HOTT_ID_ALT = 0x0007, // Alt sensor + HOTT_ID_HDG = 0x0008, // Heading sensor + HOTT_ID_GSPD = 0x0008, // Ground speed sensor + HOTT_ID_GPS_LAT_LONG = 0x0009, // GPS sensor + HOTT_ID_GPS_COUNT = 0x000A, // GPS sat count + HOTT_ID_CELS = 0x000B, // Cels L sensor + HOTT_ID_CELS_H = 0x000C, // Cels H sensor + HOTT_ID_VOLT1 = 0x000D, // Voltage sensor + HOTT_ID_VOLT2 = 0x000E, // Voltage sensor + HOTT_ID_AMP1 = 0x000F, // Amp sensor + HOTT_ID_AMP2 = 0x0010, // Amp sensor + HOTT_ID_RPM1 = 0x0011, // RPM sensor + HOTT_ID_RPM2 = 0x0012, // RPM sensor + HOTT_ID_ESC_VIN = 0x0013, // ESC Volt + HOTT_ID_ESC_CUR = 0x0014, // ESC Amp + HOTT_ID_ESC_TBEC = 0x0015, // BEC Temp + HOTT_ID_ESC_BCUR = 0x0016, // BEC Cur + HOTT_ID_ESC_VBEC = 0x0017, // BEC Volt + HOTT_ID_BCAPA = 0x0018, // Batt capacity + HOTT_ID_TEMP2 = 0x0019, // Temperature sensor 2 + HOTT_ID_AIR_SPEED = 0x001A, + HOTT_ID_VOLT3 = 0x001B, // Voltage sensor + HOTT_ID_FUEL = 0x001C, // Fuel percentage + HOTT_TX_RSSI_ID = 0xFF00, // Pseudo id outside 1 byte range of Hott sensors HOTT_TX_LQI_ID = 0xFF01, // Pseudo id outside 1 byte range of Hott sensors HOTT_RX_RSSI_ID = 0xFF02, // Pseudo id outside 1 byte range of Hott sensors @@ -72,18 +105,39 @@ enum }; const HottSensor hottSensors[] = { - //frame 00 - {HOTT_ID_RX_VOLTAGE, ZSTR_BATT, UNIT_VOLTS, 1}, // RX_Batt Voltage - {HOTT_ID_TEMP1, ZSTR_TEMP1, UNIT_CELSIUS, 0}, // RX Temperature sensor - //frame 01 - //frame 02 - //frame 03 - //frame 04 - {HOTT_TX_RSSI_ID, ZSTR_TX_RSSI, UNIT_RAW, 0}, // Pseudo id outside 1 byte range of Hott sensors - {HOTT_TX_LQI_ID, ZSTR_TX_QUALITY, UNIT_RAW, 0}, // Pseudo id outside 1 byte range of Hott sensors - {HOTT_RX_RSSI_ID, ZSTR_RSSI, UNIT_DB, 0}, // RX RSSI - {HOTT_RX_LQI_ID, ZSTR_RX_QUALITY, UNIT_RAW, 0}, // RX LQI - {0x00, NULL, UNIT_RAW, 0}, // sentinel + //HOTT_TELEM_RX + {HOTT_ID_RX_VOLTAGE, ZSTR_BATT, UNIT_VOLTS, 1}, // RX_Batt Voltage + {HOTT_ID_TEMP1, ZSTR_TEMP1, UNIT_CELSIUS, 0}, // Temperature sensor 1 + {HOTT_ID_TEMP2, ZSTR_TEMP2, UNIT_CELSIUS, 0}, // Temperature sensor 2 + {HOTT_ID_VARIO, ZSTR_VSPD, UNIT_METERS_PER_SECOND, 2}, // Vario sensor + {HOTT_ID_ALT, ZSTR_ALT, UNIT_METERS, 0}, // Alt sensor + {HOTT_ID_HDG, ZSTR_HDG, UNIT_DEGREE, 0}, // Heading sensor + {HOTT_ID_GSPD, ZSTR_GSPD, UNIT_KMH, 0}, // Ground speed sensor + {HOTT_ID_GPS_LAT_LONG, ZSTR_GPS, UNIT_GPS, 0}, // GPS position + {HOTT_ID_GPS_COUNT, ZSTR_SATELLITES, UNIT_RAW, 0}, // GPS sat count + {HOTT_ID_VOLT1, ZSTR_A1, UNIT_VOLTS, 1}, // Voltage sensor 1 + {HOTT_ID_VOLT2, ZSTR_A2, UNIT_VOLTS, 1}, // Voltage sensor 2 + {HOTT_ID_VOLT3, ZSTR_A3, UNIT_VOLTS, 1}, // Voltage sensor 3 + {HOTT_ID_AMP1, ZSTR_CURR, UNIT_AMPS, 1}, // Amp sensor 1 + {HOTT_ID_AMP2, ZSTR_CURR, UNIT_AMPS, 1}, // Amp sensor 2 + {HOTT_ID_RPM1, ZSTR_RPM, UNIT_RPMS, 0}, // RPM1 + {HOTT_ID_RPM2, ZSTR_RPM2, UNIT_RPMS, 0}, // RPM2 + {HOTT_ID_ESC_VIN, ZSTR_ESC_VIN, UNIT_VOLTS, 1}, // ESC VIN + {HOTT_ID_BCAPA, ZSTR_SMART_BAT_CAPACITY, UNIT_MAH, 2}, // Batt Capa + {HOTT_ID_ESC_CUR, ZSTR_ESC_CUR, UNIT_AMPS, 1}, // ESC Amp + {HOTT_ID_ESC_TBEC, ZSTR_ESC_TBEC, UNIT_CELSIUS, 0}, // ESC BEC Temp + {HOTT_ID_ESC_BCUR, ZSTR_ESC_BCUR, UNIT_AMPS, 1}, // ESC BEC Amp + {HOTT_ID_ESC_VBEC, ZSTR_ESC_VBEC, UNIT_VOLTS, 1}, // ESC BEC Volt + {HOTT_ID_CELS, ZSTR_CELLS, UNIT_CELLS, 2}, // Batt cells + {HOTT_ID_CELS_H, ZSTR_CELLS, UNIT_CELLS, 2}, // Batt H cells + {HOTT_ID_AIR_SPEED, ZSTR_ASPD, UNIT_KMH, 0}, // Air speed + {HOTT_ID_FUEL, ZSTR_FUEL, UNIT_PERCENT, 0}, // Fuel + + {HOTT_TX_RSSI_ID, ZSTR_TX_RSSI, UNIT_DB, 0}, // Pseudo id outside 1 byte range of Hott sensors + {HOTT_TX_LQI_ID, ZSTR_TX_QUALITY, UNIT_RAW, 0}, // Pseudo id outside 1 byte range of Hott sensors + {HOTT_RX_RSSI_ID, ZSTR_RSSI, UNIT_DB, 0}, // RX RSSI + {HOTT_RX_LQI_ID, ZSTR_RX_QUALITY, UNIT_RAW, 0}, // RX LQI + {0x00, NULL, UNIT_RAW, 0}, // sentinel }; const HottSensor * getHottSensor(uint16_t id) @@ -95,22 +149,30 @@ const HottSensor * getHottSensor(uint16_t id) return nullptr; } +int16_t processHoTTdBm(uint8_t value) +{ + if (value >= 128) { + value = 256 - value; + } + return value / 2 -71; +} + void processHottPacket(const uint8_t * packet) { // Set TX RSSI Value - setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_TX_RSSI_ID, 0, 0, packet[0]>>1, UNIT_RAW, 0); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_TX_RSSI_ID, 0, 0, processHoTTdBm(packet[0]), UNIT_RAW, 0); // Set TX LQI Value setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_TX_LQI_ID, 0, 0, packet[1], UNIT_RAW, 0); #if defined(LUA) - #define HOTT_MENU_NBR_PAGE 0x13 +#define HOTT_MENU_NBR_PAGE 0x13 // Config menu consists of the different telem pages put all together // [3] = config mennu page 0x00 to 0x12. // Page X [4] = seems like all the telem pages with the same value are going together to make the full config menu text. Seen so far 'a', 'b', 'c', 'd' // Page X [5..13] = 9 ascii chars to be displayed, char is highlighted when ascii|0x80 // Screen display is 21 characters large which means that once the first 21 chars are filled go to the begining of the next line // Menu commands are sent through TX packets: - // packet[28]= 0xXF=>no key press, 0xXD=>down, 0xXB=>up, 0xX9=>enter, 0xXE=>right, 0xX7=>left with X=0 or D + // packet[28]= 0xXF=>no key press, 0xXD=>down, 0xXB=>up, 0xX9=>enter, 0xXE=>right, 0xX7=>left with X=0, 9=Vario, A=GPS, B=Unknown, C=ESC, D=GAM, or E=EAM // packet[29]= 0xX1/0xX9 with X=0 or X counting 0,1,1,2,2,..,9,9 if (Multi_Buffer && memcmp(Multi_Buffer, "HoTT", 4) == 0) { // HoTT Lua script is running @@ -118,21 +180,31 @@ void processHottPacket(const uint8_t * packet) // Init memset(&Multi_Buffer[6], ' ', HOTT_MENU_NBR_PAGE * 9); // Clear text buffer } - - if (packet[3] < HOTT_MENU_NBR_PAGE && Multi_Buffer[5] >= 0xD7 && Multi_Buffer[5] <= 0xDF) { - Multi_Buffer[4] = packet[4]; // Store current menu being received + + if (packet[2] == HOTT_TELEM_TEXT && packet[3] < HOTT_MENU_NBR_PAGE && (Multi_Buffer[5] & 0x80) && (Multi_Buffer[5] & 0x0F) >= 0x07) { + Multi_Buffer[4] = packet[4]; // Store detected sensors memcpy(&Multi_Buffer[6 + packet[3] * 9], &packet[5], 9); // Store the received page in the buffer } return; } #endif + struct HottGPSMinutes + { + uint16_t value: 14; + uint16_t isNegative: 1; + uint16_t spare: 1; + }; + const HottSensor * sensor; int32_t value; + static uint8_t prev_page = 0, prev_value = 0; + static HottGPSMinutes min = {}; + int16_t deg = 0, sec = 0; - if (packet[2] == HOTT_TELEM_NORMAL) { - switch (packet[3]) { - case HOTT_FRAME_00: + switch (packet[2]) { // Telemetry type + case HOTT_TELEM_RX: + if (packet[3] == 0) { // Telemetry page: only page 0 is for RX // RX_VOLT value = packet[5]; sensor = getHottSensor(HOTT_ID_RX_VOLTAGE); @@ -142,21 +214,433 @@ void processHottPacket(const uint8_t * packet) sensor = getHottSensor(HOTT_ID_TEMP1); setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_TEMP1, 0, 0, value, sensor->unit, sensor->precision); // RX_RSSI - setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_RX_RSSI_ID, 0, 0, packet[7], UNIT_DB, 0); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_RX_RSSI_ID, 0, 0, processHoTTdBm(packet[7]), UNIT_DB, 0); // RX_LQI telemetryData.rssi.set(packet[8]); if (packet[8] > 0) telemetryStreaming = TELEMETRY_TIMEOUT10ms; setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_RX_LQI_ID, 0, 0, packet[8], UNIT_RAW, 0); - break; + } + break; - default: - // unknown - value = (packet[7] << 24) | (packet[6] << 16) | (packet[5] << 8) | packet[4]; - setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, 0xFE00 | packet[3], 0, 0, value, UNIT_RAW, 0); - break; - } + case HOTT_TELEM_VARIO: + // https://github.com/betaflight/betaflight/blob/1d8a0e9fd61cf01df7b34805e84365df72d9d68d/src/main/telemetry/hott.h#L240 + switch (packet[3]) { // Telemetry page 1,2,3,4 + case HOTT_PAGE_01: + // packet[6 ] uint8_t altitude_L; //#06 Altitude low uint8_t. In meters. A value of 500 means 0m + // packet[7 ] uint8_t altitude_H; //#07 Altitude high uint8_t + value = packet[6] + (packet[7] << 8) - 500; + sensor = getHottSensor(HOTT_ID_ALT); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_ALT, 0, HOTT_TELEM_VARIO, value, sensor->unit, sensor->precision); + + // packet[12] uint8_t climbrate_L; //#12 Climb rate in m/s. Steps of 0.01m/s. Value of 30000 = 0.00 m/s + // packet[13] uint8_t climbrate_H; //#13 Climb rate in m/s + value = packet[12] + (packet[13] << 8) - 30000; + sensor = getHottSensor(HOTT_ID_VARIO); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_VARIO, 0, HOTT_TELEM_VARIO, value, sensor->unit, sensor->precision); + break; + case HOTT_PAGE_02: + // packet[12] uint8_t compass_direction; //#42 Compass heading in 2� steps. 1 = 2� + value = packet[12] * 2; + sensor = getHottSensor(HOTT_ID_HDG); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_HDG, 0, HOTT_TELEM_VARIO, value, sensor->unit, sensor->precision); + break; + case HOTT_PAGE_03: + break; + case HOTT_PAGE_04: + break; + } + break; + + case HOTT_TELEM_GPS: + // https://github.com/betaflight/betaflight/blob/1d8a0e9fd61cf01df7b34805e84365df72d9d68d/src/main/telemetry/hott.h#L378 + switch (packet[3]) { // Telemetry page 1,2,3,4 + case HOTT_PAGE_01: + // packet[7 ] uint8_t flight_direction; //#07 flight direction in 2 degreees/step (1 = 2degrees); + value = packet[7] * 2; + sensor = getHottSensor(HOTT_ID_HDG); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_HDG, 0, HOTT_TELEM_GPS, value, sensor->unit, sensor->precision); + + // packet[8 ] uint8_t gps_speed_L; //08 km/h + // packet[9 ] uint8_t gps_speed_H; //#09 + value = packet[8] + (packet[9] << 8); + sensor = getHottSensor(HOTT_ID_GSPD); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_GSPD, 0, HOTT_TELEM_GPS, value, sensor->unit, sensor->precision); + + // packet[10] uint8_t pos_NS; //#10 north = 0, south = 1 + // packet[11] uint8_t pos_NS_dm_L; //#11 degree minutes ie N48�39�988 + // packet[12] uint8_t pos_NS_dm_H; //#12 + // packet[13] uint8_t pos_NS_sec_L; //#13 position seconds + min.value = (int16_t) (packet[11] + (packet[12] << 8)); + if (packet[10] == 1) { + min.isNegative = true; + } + break; + + case HOTT_PAGE_02: + if (prev_page == ((HOTT_TELEM_GPS << 4) | HOTT_PAGE_01)) { + // packet[4 ] uint8_t pos_NS_sec_H; //#14 + deg = min.value / 100; + min.value = min.value - deg * 100; + sec = prev_value + (packet[4] << 8); + value = deg * 1000000 + (min.value * 1000000 + sec * 100) / 60; + if (min.isNegative) { + value = -value; + } + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_GPS_LAT_LONG, 0, HOTT_TELEM_GPS, value, UNIT_GPS_LATITUDE, 0); + } + + // packet[5 ] uint8_t pos_EW; //#15 east = 0, west = 1 + // packet[6 ] uint8_t pos_EW_dm_L; //#16 degree minutes ie. E9�25�9360 + // packet[7 ] uint8_t pos_EW_dm_H; //#17 + // packet[8 ] uint8_t pos_EW_sec_L; //#18 position seconds + // packet[9 ] uint8_t pos_EW_sec_H; //#19 + min.value = (int16_t) (packet[6] + (packet[7] << 8)); + sec = (int16_t) (packet[8] + (packet[9] << 8)); + deg = min.value / 100; + min.value = min.value - deg * 100; + value = deg * 1000000 + (min.value * 1000000 + sec * 100) / 60; + if (packet[5] == 1) { + value = -value; + } + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_GPS_LAT_LONG, 0, HOTT_TELEM_GPS, value, UNIT_GPS_LONGITUDE, 0); + // packet[10] uint8_t home_distance_L; //#20 meters + // packet[11] uint8_t home_distance_H; //#21 + + // packet[12] uint8_t altitude_L; //#22 meters. Value of 500 = 0m + // packet[13] uint8_t altitude_H; //#23 + value = packet[12] + (packet[13] << 8) - 500; + sensor = getHottSensor(HOTT_ID_ALT); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_ALT, 0, HOTT_TELEM_GPS, value, sensor->unit, sensor->precision); + break; + + case HOTT_PAGE_03: + // packet[4 ] uint8_t climbrate_L; //#24 m/s 0.01m/s resolution. Value of 30000 = 0.00 m/s + // packet[5 ] uint8_t climbrate_H; //#25 + value = packet[4] + (packet[5] << 8) - 30000; + sensor = getHottSensor(HOTT_ID_VARIO); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_VARIO, 0, HOTT_TELEM_GPS, value, sensor->unit, sensor->precision); + + // packet[6 ] uint8_t climbrate3s; //#26 climbrate in m/3s resolution, value of 120 = 0 m/3s + // packet[7 ] uint8_t gps_satelites; //#27 sat count + sensor = getHottSensor(HOTT_ID_GPS_COUNT); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_GPS_COUNT, 0, HOTT_TELEM_GPS, packet[7], sensor->unit, sensor->precision); + // packet[8 ] uint8_t gps_fix_char; //#28 GPS fix character. display, 'D' = DGPS, '2' = 2D, '3' = 3D, '-' = no fix. Where appears this char??? + // packet[9 ] uint8_t home_direction;//#29 direction from starting point to Model position (2 degree steps) + // packet[10] uint8_t angle_roll; //#30 angle roll in 2 degree steps + // packet[11] uint8_t angle_nick; //#31 angle in 2degree steps + // packet[12] uint8_t angle_compass; //#32 angle in 2degree steps. 1 = 2�, 255 = - 2� (1 uint8_t) North = 0� + // packet[13] uint8_t gps_time_h; //#33 UTC time hours + break; + + case HOTT_PAGE_04: + // packet[4 ] uint8_t gps_time_m; //#34 UTC time minutes + // packet[5 ] uint8_t gps_time_s; //#35 UTC time seconds + // packet[6 ] uint8_t gps_time_sss; //#36 UTC time milliseconds + // packet[7 ] uint8_t msl_altitude_L;//#37 mean sea level altitude + // packet[8 ] uint8_t msl_altitude_H;//#38 + // packet[9 ] uint8_t vibration; //#39 vibrations level in % + // packet[10] uint8_t free_char1; //#40 appears right to home distance + // packet[11] uint8_t free_char2; //#41 appears right to home direction + // packet[12] uint8_t free_char3; //#42 GPS ASCII D=DGPS 2=2D 3=3D -=No Fix + break; + } + break; + + case HOTT_TELEM_ESC: + // https://github.com/betaflight/betaflight/blob/1d8a0e9fd61cf01df7b34805e84365df72d9d68d/src/main/telemetry/hott.h#L454 + switch (packet[3]) { // Telemetry page 1,2,3,4 + case HOTT_PAGE_01: + // packet[7 ] uint8_t input_v_L; //#07 Input voltage low byte + // packet[8 ] uint8_t input_v_H; //#08 + value = packet[7] + (packet[8] << 8); + sensor = getHottSensor(HOTT_ID_ESC_VIN); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_ESC_VIN, 0, HOTT_TELEM_ESC, value, sensor->unit, sensor->precision); + // packet[11] uint8_t batt_cap_L; //#11 battery capacity in 10mAh steps + // packet[12] uint8_t batt_cap_H; //#12 + value = packet[11] + (packet[12] << 8); + sensor = getHottSensor(HOTT_ID_BCAPA); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_BCAPA, 0, HOTT_TELEM_ESC, value, sensor->unit, sensor->precision); + // packet[13] uint8_t esc_temp; //#13 ESC temperature + value = packet[13] - 20; + sensor = getHottSensor(HOTT_ID_TEMP1); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_TEMP1, 0, HOTT_TELEM_ESC, value, sensor->unit, sensor->precision); + break; + + case HOTT_PAGE_02: + // packet[5 ] uint8_t current_L; //#15 Current in 0.1 steps + // packet[6 ] uint8_t current_H; //#16 + value = packet[5] + (packet[6] << 8); + sensor = getHottSensor(HOTT_ID_ESC_CUR); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_ESC_CUR, 0, HOTT_TELEM_ESC, value, sensor->unit, sensor->precision); + // packet[9 ] uint8_t rpm_L; //#19 RPM in 10U/min steps + // packet[10] uint8_t rpm_H; //#20 + value = (packet[9] + (packet[10] << 8)) * 10; + sensor = getHottSensor(HOTT_ID_RPM1); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_RPM1, 0, HOTT_TELEM_ESC, value, sensor->unit, sensor->precision); + break; + + case HOTT_PAGE_03: + // packet[8 ] uint8_t bec_v; //#28 BEC voltage + value = packet[8]; + sensor = getHottSensor(HOTT_ID_ESC_VBEC); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_ESC_VBEC, 0, HOTT_TELEM_ESC, value, sensor->unit, sensor->precision); + // packet[10] uint8_t bec_current; //#30 BEC current + value = packet[10]; + sensor = getHottSensor(HOTT_ID_ESC_BCUR); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_ESC_BCUR, 0, HOTT_TELEM_ESC, value, sensor->unit, sensor->precision); + break; + + case HOTT_PAGE_04: + // packet[4 ] uint8_t bec_temp; //#34 BEC temperature + value = packet[4] - 20; + sensor = getHottSensor(HOTT_ID_ESC_TBEC); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_ESC_TBEC, 0, HOTT_TELEM_ESC, value, sensor->unit, sensor->precision); + // packet[6 ] uint8_t motor_temp; //#36 Motor or external sensor temperature + value = packet[6] - 20; + sensor = getHottSensor(HOTT_ID_TEMP2); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_TEMP2, 0, HOTT_TELEM_ESC, value, sensor->unit, sensor->precision); + break; + } + break; + + case HOTT_TELEM_GAM: + // https://github.com/betaflight/betaflight/blob/1d8a0e9fd61cf01df7b34805e84365df72d9d68d/src/main/telemetry/hott.h#L151 + switch (packet[3]) { // Telemetry page 1,2,3,4 + case HOTT_PAGE_01: + sensor = getHottSensor(HOTT_ID_CELS); + // packet[7 ] uint8_t cell1_L; //#07 cell 1 voltage lower value. 0.02V steps, 124=2.48V + value = packet[7] << 1; + if (value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS, 0, HOTT_TELEM_EAM, 0 << 16 | value, sensor->unit, sensor->precision); + // packet[8 ] uint8_t cell2_L; //#08 + value = packet[8] << 1; + if (value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS, 0, HOTT_TELEM_EAM, 1 << 16 | value, sensor->unit, sensor->precision); + // packet[9 ] uint8_t cell3_L; //#09 + value = packet[9] << 1; + if (value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS, 0, HOTT_TELEM_EAM, 2 << 16 | value, sensor->unit, sensor->precision); + // packet[10] uint8_t cell4_L; //#10 + value = packet[10] << 1; + if (value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS, 0, HOTT_TELEM_EAM, 3 << 16 | value, sensor->unit, sensor->precision); + // packet[11] uint8_t cell5_L; //#11 + value = packet[11] << 1; + if (value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS, 0, HOTT_TELEM_EAM, 4 << 16 | value, sensor->unit, sensor->precision); + // packet[12] uint8_t cell6_L; //#12 + value = packet[12] << 1; + if (value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS, 0, HOTT_TELEM_EAM, 5 << 16 | value, sensor->unit, sensor->precision); + // packet[13] uint8_t batt1_L; //#13 battery 1 voltage LSB value. 0.1V steps. 50 = 5.5V + break; + + case HOTT_PAGE_02: + if (prev_page == ((HOTT_TELEM_GAM << 4) | HOTT_PAGE_01)) { + // packet[4 ] uint8_t batt1_H; //#14 + value = prev_value + (packet[4] << 8); + sensor = getHottSensor(HOTT_ID_VOLT2); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_VOLT2, 0, HOTT_TELEM_GAM, value, sensor->unit, sensor->precision); + } + // packet[5 ] uint8_t batt2_L; //#15 battery 2 voltage LSB value. 0.1V steps. 50 = 5.5V + // packet[6 ] uint8_t batt2_H; //#16 + value = packet[5] + (packet[6] << 8); + sensor = getHottSensor(HOTT_ID_VOLT3); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_VOLT3, 0, HOTT_TELEM_GAM, value, sensor->unit, sensor->precision); + // packet[7 ] uint8_t temperature1; //#17 temperature 1. offset of 20. a value of 20 = 0�C + value = packet[7] - 20; + sensor = getHottSensor(HOTT_ID_TEMP1); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_TEMP1, 0, HOTT_TELEM_GAM, value, sensor->unit, sensor->precision); + // packet[8 ] uint8_t temperature2; //#18 temperature 2. offset of 20. a value of 20 = 0�C + value = packet[8] - 20; + sensor = getHottSensor(HOTT_ID_TEMP2); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_TEMP2, 0, HOTT_TELEM_GAM, value, sensor->unit, sensor->precision); + // packet[9 ] uint8_t fuel_procent; //#19 Fuel capacity in %. Values 0--100, graphical display ranges: 0-25% 50% 75% 100% + value = packet[9]; + sensor = getHottSensor(HOTT_ID_FUEL); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_FUEL, 0, HOTT_TELEM_GAM, value, sensor->unit, sensor->precision); + // packet[10] uint8_t fuel_ml_L; //#20 Fuel in ml scale. Full = 65535! + // packet[11] uint8_t fuel_ml_H; //#21 + // packet[12] uint8_t rpm_L; //#22 RPM in 10 RPM steps. 300 = 3000rpm + // packet[13] uint8_t rpm_H; //#23 + value = (packet[12] + (packet[13] << 8)) * 10; + sensor = getHottSensor(HOTT_ID_RPM1); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_RPM1, 0, HOTT_TELEM_GAM, value, sensor->unit, sensor->precision); + break; + + case HOTT_PAGE_03: + // packet[4 ] uint8_t altitude_L; //#24 altitude in meters. offset of 500, 500 = 0m + // packet[5 ] uint8_t altitude_H; //#25 + value = packet[4] + (packet[5] << 8) - 500; + sensor = getHottSensor(HOTT_ID_ALT); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_ALT, 0, HOTT_TELEM_GAM, value, sensor->unit, sensor->precision); + // packet[6 ] uint8_t climbrate_L; //#26 climb rate in 0.01m/s. Value of 30000 = 0.00 m/s + // packet[7 ] uint8_t climbrate_H; //#27 + value = packet[6] + (packet[7] << 8) - 30000; + sensor = getHottSensor(HOTT_ID_VARIO); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_VARIO, 0, HOTT_TELEM_GAM, value, sensor->unit, sensor->precision); + // packet[8 ] uint8_t climbrate3s; //#28 climb rate in m/3sec. Value of 120 = 0m/3sec + // packet[9 ] uint8_t current_L; //#29 current in 0.1A steps + // packet[10] uint8_t current_H; //#30 + value = packet[9] + (packet[10] << 8); + sensor = getHottSensor(HOTT_ID_AMP1); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_AMP1, 0, HOTT_TELEM_GAM, value, sensor->unit, sensor->precision); + // packet[11] uint8_t main_voltage_L; //#31 Main power voltage using 0.1V steps + // packet[12] uint8_t main_voltage_H; //#32 + value = packet[11] + (packet[12] << 8); + sensor = getHottSensor(HOTT_ID_VOLT1); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_VOLT1, 0, HOTT_TELEM_GAM, value, sensor->unit, sensor->precision); + // packet[13] uint8_t batt_cap_L; //#33 used battery capacity in 10mAh steps + break; + + case HOTT_PAGE_04: + // packet[4 ] uint8_t batt_cap_H; //#34 + if (prev_page == ((HOTT_TELEM_GAM << 4) | HOTT_PAGE_03)) { + value = prev_value + (packet[4] << 8); + sensor = getHottSensor(HOTT_ID_BCAPA); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_BCAPA, 0, HOTT_TELEM_GAM, value, sensor->unit, sensor->precision); + } + // packet[5 ] uint8_t speed_L; //#35 (air?) speed in km/h(?) we are using ground speed here per default + // packet[6 ] uint8_t speed_H; //#36 + value = packet[5] + (packet[6] << 8); + sensor = getHottSensor(HOTT_ID_AIR_SPEED); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_AIR_SPEED, 0, HOTT_TELEM_GAM, value, sensor->unit, sensor->precision); + // packet[7 ] uint8_t min_cell_volt; //#37 minimum cell voltage in 2mV steps. 124 = 2,48V + // packet[8 ] uint8_t min_cell_volt_num; //#38 number of the cell with the lowest voltage + // packet[9 ] uint8_t rpm2_L; //#39 RPM in 10 RPM steps. 300 = 3000rpm + // packet[10] uint8_t rpm2_H; //#40 + value = (packet[9] + (packet[10] << 8)) * 10; + sensor = getHottSensor(HOTT_ID_RPM2); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_RPM2, 0, HOTT_TELEM_GAM, value, sensor->unit, sensor->precision); + // packet[11] uint8_t general_error_number;//#41 Voice error == 12. TODO: more docu + // packet[12] uint8_t pressure; //#42 Pressure up to 16bar. 0,1bar scale. 20 = 2bar + break; + } + break; + + case HOTT_TELEM_EAM: + // https://github.com/betaflight/betaflight/blob/1d8a0e9fd61cf01df7b34805e84365df72d9d68d/src/main/telemetry/hott.h#L288 + switch (packet[3]) { // Telemetry page 1,2,3,4 + case HOTT_PAGE_01: + sensor = getHottSensor(HOTT_ID_CELS); + // packet[7 ] uint8_t cell1_L; //#07 cell 1 voltage lower value. 0.02V steps, 124=2.48V + value = packet[7] << 1; + if (value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS, 0, HOTT_TELEM_EAM, 0 << 16 | value, sensor->unit, sensor->precision); + // packet[8 ] uint8_t cell2_L; //#08 + value = packet[8] << 1; + if (value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS, 0, HOTT_TELEM_EAM, 1 << 16 | value, sensor->unit, sensor->precision); + // packet[9 ] uint8_t cell3_L; //#09 + value = packet[9] << 1; + if (value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS, 0, HOTT_TELEM_EAM, 2 << 16 | value, sensor->unit, sensor->precision); + // packet[10] uint8_t cell4_L; //#10 + value = packet[10] << 1; + if (value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS, 0, HOTT_TELEM_EAM, 3 << 16 | value, sensor->unit, sensor->precision); + // packet[11] uint8_t cell5_L; //#11 + value = packet[11] << 1; + if (value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS, 0, HOTT_TELEM_EAM, 4 << 16 | value, sensor->unit, sensor->precision); + // packet[12] uint8_t cell6_L; //#12 + value = packet[12] << 1; + if (value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS, 0, HOTT_TELEM_EAM, 5 << 16 | value, sensor->unit, sensor->precision); + // packet[13] uint8_t cell7_L; //#13 + // value = packet[13] << 1; + // if(value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS, 0, HOTT_TELEM_EAM, 6 << 16 | value, sensor->unit, sensor->precision); + break; + + case HOTT_PAGE_02: + sensor = getHottSensor(HOTT_ID_CELS); + // packet[4 ] uint8_t cell1_H; //#14 cell 1 voltage high value. 0.02V steps, 124=2.48V + value = packet[4] << 1; + if (value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS_H, 0, HOTT_TELEM_EAM, 0 << 16 | value, sensor->unit, sensor->precision); + // packet[5 ] uint8_t cell2_H; //#15 + value = packet[5] << 1; + if (value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS_H, 0, HOTT_TELEM_EAM, 1 << 16 | value, sensor->unit, sensor->precision); + // packet[6 ] uint8_t cell3_H; //#16 + value = packet[6] << 1; + if (value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS_H, 0, HOTT_TELEM_EAM, 2 << 16 | value, sensor->unit, sensor->precision); + // packet[7 ] uint8_t cell4_H; //#17 + value = packet[7] << 1; + if (value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS_H, 0, HOTT_TELEM_EAM, 3 << 16 | value, sensor->unit, sensor->precision); + // packet[8 ] uint8_t cell5_H; //#18 + value = packet[8] << 1; + if (value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS_H, 0, HOTT_TELEM_EAM, 4 << 16 | value, sensor->unit, sensor->precision); + // packet[9 ] uint8_t cell6_H; //#19 + value = packet[9] << 1; + if (value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS_H, 0, HOTT_TELEM_EAM, 5 << 16 | value, sensor->unit, sensor->precision); + // packet[10] uint8_t cell7_H; //#20 + //value = packet[10] << 1; + //if(value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS, 0, HOTT_TELEM_EAM, 13 << 16 | value, sensor->unit, sensor->precision); + // packet[11] uint8_t batt1_voltage_L; //#21 battery 1 voltage lower value in 100mv steps, 50=5V. optionally cell8_L value 0.02V steps + // packet[12] uint8_t batt1_voltage_H; //#22 + value = packet[11] + (packet[12] << 8); + sensor = getHottSensor(HOTT_ID_VOLT2); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_VOLT2, 0, HOTT_TELEM_EAM, value, sensor->unit, sensor->precision); + + // packet[13] uint8_t batt2_voltage_L; //#23 battery 2 voltage lower value in 100mv steps, 50=5V. optionally cell8_H value. 0.02V steps + break; + + case HOTT_PAGE_03: + if (prev_page == ((HOTT_TELEM_EAM << 4) | HOTT_PAGE_02)) { + // packet[4 ] uint8_t batt2_voltage_H; //#24 + value = prev_value + (packet[4] << 8); + sensor = getHottSensor(HOTT_ID_VOLT3); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_VOLT3, 0, HOTT_TELEM_EAM, value, sensor->unit, sensor->precision); + } + // packet[5 ] uint8_t temp1; //#25 Temperature sensor 1. 20=0�, 46=26� - offset of 20. + value = packet[5] - 20; + sensor = getHottSensor(HOTT_ID_TEMP1); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_TEMP1, 0, HOTT_TELEM_EAM, value, sensor->unit, sensor->precision); + // packet[6 ] uint8_t temp2; //#26 temperature sensor 2 + value = packet[6] - 20; + sensor = getHottSensor(HOTT_ID_TEMP2); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_TEMP2, 0, HOTT_TELEM_EAM, value, sensor->unit, sensor->precision); + + // packet[7 ] uint8_t altitude_L; //#27 Attitude lower value. unit: meters. Value of 500 = 0m + // packet[8 ] uint8_t altitude_H; //#28 + value = packet[7] + (packet[8] << 8) - 500; + sensor = getHottSensor(HOTT_ID_ALT); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_ALT, 0, HOTT_TELEM_EAM, value, sensor->unit, sensor->precision); + + // packet[9 ] uint8_t current_L; //#29 Current in 0.1 steps + // packet[10] uint8_t current_H; //#30 + value = packet[9] + (packet[10] << 8); + sensor = getHottSensor(HOTT_ID_AMP1); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_AMP1, 0, HOTT_TELEM_EAM, value, sensor->unit, sensor->precision); + // packet[11] uint8_t main_voltage_L; //#31 Main power voltage (drive) in 0.1V steps + // packet[12] uint8_t main_voltage_H; //#32 + value = packet[11] + (packet[12] << 8); + sensor = getHottSensor(HOTT_ID_VOLT1); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_VOLT1, 0, HOTT_TELEM_EAM, value, sensor->unit, sensor->precision); + // packet[13] uint8_t batt_cap_L; //#33 used battery capacity in 10mAh steps + break; + + case HOTT_PAGE_04: + // packet[4 ] uint8_t batt_cap_H; //#34 + if (prev_page == ((HOTT_TELEM_EAM << 4) | HOTT_PAGE_03)) { + value = prev_value + (packet[4] << 8); + sensor = getHottSensor(HOTT_ID_BCAPA); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_BCAPA, 0, HOTT_TELEM_EAM, value, sensor->unit, sensor->precision); + } + + // packet[5 ] uint8_t climbrate_L; //#35 climb rate in 0.01m/s. Value of 30000 = 0.00 m/s + // packet[6 ] uint8_t climbrate_H; //#36 + value = packet[5] + (packet[6] << 8) - 30000; + sensor = getHottSensor(HOTT_ID_VARIO); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_VARIO, 0, HOTT_TELEM_EAM, value, sensor->unit, sensor->precision); + + // packet[7 ] uint8_t climbrate3s; //#37 climbrate in m/3sec. Value of 120 = 0m/3sec + // packet[8 ] uint8_t rpm_L; //#38 RPM. Steps: 10 U/min + // packet[9 ] uint8_t rpm_H; //#39 + value = (packet[8] + (packet[9] << 8)) * 10; + sensor = getHottSensor(HOTT_ID_RPM1); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_RPM1, 0, HOTT_TELEM_EAM, value, sensor->unit, sensor->precision); + // packet[10] uint8_t electric_min; //#40 Electric minutes. Time does start, when motor current is > 3 A + // packet[11] uint8_t electric_sec; //#41 + // packet[12] uint8_t speed_L; //#42 (air?) speed in km/h. Steps 1km/h + // packet[13] uint8_t speed_H; //#43 + value = packet[12] + (packet[13] << 8); + sensor = getHottSensor(HOTT_ID_AIR_SPEED); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_AIR_SPEED, 0, HOTT_TELEM_EAM, value, sensor->unit, sensor->precision); + break; + } + break; } + prev_page = (packet[2] << 4) | packet[3]; // concatenate telemetry type and page + prev_value = packet[13]; // page overflow } void hottSetDefault(int index, uint16_t id, uint8_t subId, uint8_t instance) diff --git a/radio/src/telemetry/multi.cpp b/radio/src/telemetry/multi.cpp index 55f09eed3..42f612d57 100644 --- a/radio/src/telemetry/multi.cpp +++ b/radio/src/telemetry/multi.cpp @@ -21,6 +21,7 @@ #include "telemetry.h" #include "multi.h" +constexpr int32_t MULTI_DESIRED_VERSION = (1 << 24) | (3 << 16) | (1 << 8) | 1; #define MULTI_CHAN_BITS 11 extern uint8_t g_moduleIdx; @@ -561,7 +562,7 @@ void MultiModuleStatus::getStatusString(char * statusText) const return; } - if (major <= 1 && minor <= 3 && revision <= 0 && patch < 91 && SLOW_BLINK_ON_PHASE) { + if ((((major << 24) | (minor << 16) | (revision << 8) | patch) < MULTI_DESIRED_VERSION) && SLOW_BLINK_ON_PHASE) { strcpy(statusText, STR_MODULE_UPGRADE); } else { diff --git a/radio/src/telemetry/telemetry_holders.h b/radio/src/telemetry/telemetry_holders.h index 9db8d629f..3e99b27f4 100644 --- a/radio/src/telemetry/telemetry_holders.h +++ b/radio/src/telemetry/telemetry_holders.h @@ -27,6 +27,7 @@ #define TELEMETRY_AVERAGE_COUNT 3 // we actually average one more reading! #define RAW_FRSKY_MINMAX(v) v.values[TELEMETRY_AVERAGE_COUNT-1] +#define MAX_CELLS 6 class TelemetryValue { public: diff --git a/radio/src/telemetry/telemetry_sensors.cpp b/radio/src/telemetry/telemetry_sensors.cpp index 66b0e2255..1d0eb89b6 100644 --- a/radio/src/telemetry/telemetry_sensors.cpp +++ b/radio/src/telemetry/telemetry_sensors.cpp @@ -90,6 +90,8 @@ void TelemetryItem::setValue(const TelemetrySensor & sensor, int32_t val, uint32 uint32_t data = uint32_t(newVal); uint8_t cellsCount = (data >> 24); uint8_t cellIndex = ((data >> 16) & 0x0F); + if (cellIndex >= MAX_CELLS) + return; uint16_t cellValue = (data & 0xFFFF); if (cellsCount == 0) { cellsCount = (cellIndex >= cells.count ? cellIndex + 1 : cells.count); diff --git a/radio/src/telemetry/telemetry_sensors.h b/radio/src/telemetry/telemetry_sensors.h index def941861..6ca1c0c97 100644 --- a/radio/src/telemetry/telemetry_sensors.h +++ b/radio/src/telemetry/telemetry_sensors.h @@ -57,7 +57,7 @@ class TelemetryItem } consumption; struct { uint8_t count; - CellValue values[6]; + CellValue values[MAX_CELLS]; } cells; struct { uint16_t year; // full year (4 digits) From 7df6ec4c58304249c3be7694f0f17c20ace7b380 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Sat, 30 May 2020 15:33:10 +0200 Subject: [PATCH 09/93] Cosmetics in Trainer screen --- radio/src/gui/common/stdlcd/radio_trainer.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/radio/src/gui/common/stdlcd/radio_trainer.cpp b/radio/src/gui/common/stdlcd/radio_trainer.cpp index 58c338a8d..c14e27604 100644 --- a/radio/src/gui/common/stdlcd/radio_trainer.cpp +++ b/radio/src/gui/common/stdlcd/radio_trainer.cpp @@ -21,9 +21,9 @@ #include "opentx.h" #if LCD_W >= 212 - #define TRAINER_CALIB_COLUMN_WIDTH 12 + #define TRAINER_CALIB_COLUMN_WIDTH (6 * FW) #else - #define TRAINER_CALIB_COLUMN_WIDTH 8 + #define TRAINER_CALIB_COLUMN_WIDTH (4 * FW + 2) #endif void menuRadioTrainer(event_t event) @@ -86,8 +86,8 @@ void menuRadioTrainer(event_t event) if (attr) s_editMode = 0; lcdDrawText(0*FW, MENU_HEADER_HEIGHT+1+6*FH, STR_CAL, attr); - for (uint8_t i=0; i<4; i++) { - uint8_t x = (i*TRAINER_CALIB_COLUMN_WIDTH + 16) * FW/2; + for (uint8_t i = 0; i < 4; i++) { + uint8_t x = 8*FW + (i * TRAINER_CALIB_COLUMN_WIDTH); int32_t chVal = ppmInput[i] - g_eeGeneral.trainer.calib[i]; chVal *= g_eeGeneral.trainer.mix[i].studWeight * 10; chVal /= 512; From b6dfa477ef72db92ffe3cb1fe88433ca87e0f917 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Sat, 30 May 2020 15:35:32 +0200 Subject: [PATCH 10/93] Translations cosmetics --- radio/src/translations/cz.h.txt | 2 +- radio/src/translations/fr.h.txt | 2 +- radio/src/translations/nl.h.txt | 6 +++--- radio/src/translations/pl.h.txt | 6 +++--- radio/src/translations/se.h.txt | 6 +++--- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/radio/src/translations/cz.h.txt b/radio/src/translations/cz.h.txt index 4c04f2bf1..ac34feec2 100644 --- a/radio/src/translations/cz.h.txt +++ b/radio/src/translations/cz.h.txt @@ -836,7 +836,7 @@ #define TR_FLASH_EXTERNAL_MULTI TR("Flash Ext. Multi", "Flash External Multi") #define TR_FIRMWARE_UPDATE_ERROR TR("Chyba zápisu FW", "Chyba zápisu firmware") #define TR_FIRMWARE_UPDATE_SUCCESS "Úspěšný zápis FW" -#define TR_WRITING TR3("\14Zapisuji..", "\032Zapisuji..", "Zapisuji..") +#define TR_WRITING "Zapisuji.." #define TR_CONFIRM_FORMAT "Provést Formát?" #define TR_INTERNALRF "Interní RF modul" #define TR_INTERNAL_MODULE "Interní modul" diff --git a/radio/src/translations/fr.h.txt b/radio/src/translations/fr.h.txt index e9e87f731..80f462c09 100644 --- a/radio/src/translations/fr.h.txt +++ b/radio/src/translations/fr.h.txt @@ -857,7 +857,7 @@ #define TR_FLASH_EXTERNAL_MULTI TR("Flash Ext. Multi", "Flash External Multi") #define TR_FIRMWARE_UPDATE_ERROR TR("Erreur màj FW","Erreur de mise à jour") #define TR_FIRMWARE_UPDATE_SUCCESS "Flash ok" -#define TR_WRITING TR("\14Ecriture...", "\032Ecriture...") +#define TR_WRITING "Ecriture..." #define TR_CONFIRM_FORMAT "Confirmer Formatage?" #define TR_INTERNALRF "HF interne" #define TR_INTERNAL_MODULE TR("Module int.","Module interne") diff --git a/radio/src/translations/nl.h.txt b/radio/src/translations/nl.h.txt index 397cdd636..36377aca8 100644 --- a/radio/src/translations/nl.h.txt +++ b/radio/src/translations/nl.h.txt @@ -843,9 +843,9 @@ #define TR_FLASH_EXTERNAL_MULTI TR("Flash Ext. Multi", "Flash External Multi") #define TR_FIRMWARE_UPDATE_ERROR TR("FW update Error","Firmware update error") #define TR_FIRMWARE_UPDATE_SUCCESS "Flash successful" -#define TR_WRITING "\032Schrijven..." -#define TR_CONFIRM_FORMAT "Formatteren bevestigen?" -#define TR_INTERNALRF "Interne RF" +#define TR_WRITING "Schrijven..." +#define TR_CONFIRM_FORMAT "Formatteren bevestigen?" +#define TR_INTERNALRF "Interne RF" #define TR_INTERNAL_MODULE TR("Int. module","Internal module") #define TR_EXTERNAL_MODULE TR("Ext. module","External module") #define TR_OPENTX_UPGRADE_REQUIRED "OpenTX upgrade required" diff --git a/radio/src/translations/pl.h.txt b/radio/src/translations/pl.h.txt index 370d757f6..1753b3ec3 100644 --- a/radio/src/translations/pl.h.txt +++ b/radio/src/translations/pl.h.txt @@ -856,9 +856,9 @@ #define TR_FLASH_EXTERNAL_MULTI TR("Flash Ext. Multi", "Flash External Multi") #define TR_FIRMWARE_UPDATE_ERROR TR("FW update Error","Firmware update error") #define TR_FIRMWARE_UPDATE_SUCCESS "Flash successful" -#define TR_WRITING "\032Zapis... " -#define TR_CONFIRM_FORMAT "Zatwierdź Format?" -#define TR_INTERNALRF "Wewn.Moduł RF" +#define TR_WRITING "Zapis... " +#define TR_CONFIRM_FORMAT "Zatwierdź Format?" +#define TR_INTERNALRF "Wewn.Moduł RF" #define TR_INTERNAL_MODULE TR("Int. module","Internal module") #define TR_EXTERNAL_MODULE TR("Ext. module","External module") #define TR_OPENTX_UPGRADE_REQUIRED "OpenTX upgrade required" diff --git a/radio/src/translations/se.h.txt b/radio/src/translations/se.h.txt index 1578d86a1..8868d8106 100644 --- a/radio/src/translations/se.h.txt +++ b/radio/src/translations/se.h.txt @@ -856,9 +856,9 @@ #define TR_FLASH_EXTERNAL_MULTI TR("Flash Ext. Multi", "Flash External Multi") #define TR_FIRMWARE_UPDATE_ERROR TR("FW update Error","Firmware update error") #define TR_FIRMWARE_UPDATE_SUCCESS "Flash successful" -#define TR_WRITING "\032Skriver..." -#define TR_CONFIRM_FORMAT "Formatera Minnet?" -#define TR_INTERNALRF "Intern Radio" +#define TR_WRITING "Skriver..." +#define TR_CONFIRM_FORMAT "Formatera Minnet?" +#define TR_INTERNALRF "Intern Radio" #define TR_INTERNAL_MODULE TR("Int. module","Internal module") #define TR_EXTERNAL_MODULE TR("Ext. module","External module") #define TR_OPENTX_UPGRADE_REQUIRED "OpenTX upgrade required" From c3f0e2ea88e6b43baaba7d71d94aab7145aa1b65 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Sun, 31 May 2020 16:45:48 +0200 Subject: [PATCH 11/93] Avoid Bluetooth fifo full (and 1ms wait in the mixer task...) (#7652) Avoid Bluetooth fifo full (and 1ms wait in the mixer task...) --- radio/src/bluetooth.cpp | 19 ++++++++++--------- radio/src/fifo.h | 6 +++--- radio/src/telemetry/crossfire.cpp | 3 ++- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/radio/src/bluetooth.cpp b/radio/src/bluetooth.cpp index a977d8990..025237eb2 100644 --- a/radio/src/bluetooth.cpp +++ b/radio/src/bluetooth.cpp @@ -48,17 +48,18 @@ Bluetooth bluetooth; void Bluetooth::write(const uint8_t * data, uint8_t length) { - BLUETOOTH_TRACE("BT>"); - for (int i=0; i"); + for (int i = 0; i < length; i++) { + BLUETOOTH_TRACE(" %02X", data[i]); + btTxFifo.push(data[i]); } - btTxFifo.push(data[i]); + BLUETOOTH_TRACE(CRLF); } - BLUETOOTH_TRACE(CRLF); + else { + BLUETOOTH_TRACE("[BT] TX fifo full!" CRLF); + } + bluetoothWriteWakeup(); } diff --git a/radio/src/fifo.h b/radio/src/fifo.h index 9aff60f57..8ef67be66 100644 --- a/radio/src/fifo.h +++ b/radio/src/fifo.h @@ -71,7 +71,7 @@ class Fifo return (ridx == widx); } - bool isFull() + bool isFull() const { uint32_t next = nextIndex(widx); return (next == ridx); @@ -82,7 +82,7 @@ class Fifo return (N + widx - ridx) & (N - 1); } - uint32_t hasSpace(uint32_t n) const + bool hasSpace(uint32_t n) const { return (N > (size() + n)); } @@ -103,7 +103,7 @@ class Fifo volatile uint32_t widx; volatile uint32_t ridx; - inline uint32_t nextIndex(uint32_t idx) + static inline uint32_t nextIndex(uint32_t idx) { return (idx + 1) & (N - 1); } diff --git a/radio/src/telemetry/crossfire.cpp b/radio/src/telemetry/crossfire.cpp index 07f3577f4..c71f6ce54 100644 --- a/radio/src/telemetry/crossfire.cpp +++ b/radio/src/telemetry/crossfire.cpp @@ -69,7 +69,7 @@ const CrossfireSensor & getCrossfireSensor(uint8_t id, uint8_t subId) void processCrossfireTelemetryValue(uint8_t index, int32_t value) { - if(!TELEMETRY_STREAMING()) + if (!TELEMETRY_STREAMING()) return; const CrossfireSensor & sensor = crossfireSensors[index]; @@ -201,6 +201,7 @@ void processCrossfireTelemetryData(uint8_t data) auxSerialPutc(data); } #endif + #if defined(AUX2_SERIAL) if (g_eeGeneral.aux2SerialMode == UART_MODE_TELEMETRY_MIRROR) { aux2SerialPutc(data); From ad83a78901ab78eb4598de77bae605084020ee30 Mon Sep 17 00:00:00 2001 From: Neil Horne Date: Mon, 1 Jun 2020 00:46:56 +1000 Subject: [PATCH 12/93] Align companion telemetry sensor units to radio (#7653) * Align cpn sensor units to radio * Add cpn conversion for sensor unit --- .../src/firmwares/opentx/opentxeeprom.cpp | 6 ++++++ companion/src/firmwares/sensordata.h | 21 ++++++++++++++++--- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/companion/src/firmwares/opentx/opentxeeprom.cpp b/companion/src/firmwares/opentx/opentxeeprom.cpp index e39d04180..b49a4a7ab 100644 --- a/companion/src/firmwares/opentx/opentxeeprom.cpp +++ b/companion/src/firmwares/opentx/opentxeeprom.cpp @@ -1983,6 +1983,12 @@ class SensorField: public TransformedField { sensor.unit++; } + if (version < 219) { + if (sensor.unit > SensorData::UNIT_FLOZ) { + sensor.unit += 11; + } + } + qCDebug(eepromImport) << QString("imported %1").arg(internalField.getName()); } diff --git a/companion/src/firmwares/sensordata.h b/companion/src/firmwares/sensordata.h index 65a8a4957..3f995ea3e 100644 --- a/companion/src/firmwares/sensordata.h +++ b/companion/src/firmwares/sensordata.h @@ -74,10 +74,13 @@ class SensorData { UNIT_METERS_PER_SECOND, UNIT_FEET_PER_SECOND, UNIT_KMH, + UNIT_SPEED = UNIT_KMH, UNIT_MPH, UNIT_METERS, + UNIT_DIST = UNIT_METERS, UNIT_FEET, UNIT_CELSIUS, + UNIT_TEMPERATURE = UNIT_CELSIUS, UNIT_FAHRENHEIT, UNIT_PERCENT, UNIT_MAH, @@ -91,18 +94,30 @@ class SensorData { UNIT_MILLILITERS, UNIT_FLOZ, UNIT_MILLILITERS_PER_MINUTE, + UNIT_MAX = UNIT_MILLILITERS_PER_MINUTE, + UNIT_SPARE1, + UNIT_SPARE2, + UNIT_SPARE3, + UNIT_SPARE4, + UNIT_SPARE5, + UNIT_SPARE6, + UNIT_SPARE7, + UNIT_SPARE8, + UNIT_SPARE9, + UNIT_SPARE10, UNIT_HOURS, UNIT_MINUTES, UNIT_SECONDS, // FrSky format used for these fields, could be another format in the future - UNIT_FIRST_VIRTUAL, + UNIT_FIRST_VIRTUAL, UNIT_CELLS = UNIT_FIRST_VIRTUAL, UNIT_DATETIME, UNIT_GPS, + UNIT_BITFIELD, + UNIT_TEXT, + // Internal units (not stored in sensor unit) UNIT_GPS_LONGITUDE, UNIT_GPS_LATITUDE, - UNIT_GPS_LONGITUDE_EW, - UNIT_GPS_LATITUDE_NS, UNIT_DATETIME_YEAR, UNIT_DATETIME_DAY_MONTH, UNIT_DATETIME_HOUR_MIN, From 64def18735782cb126ca54925762f71b22f328da Mon Sep 17 00:00:00 2001 From: cheki <4509524+ku2works@users.noreply.github.com> Date: Mon, 1 Jun 2020 16:05:56 +0900 Subject: [PATCH 13/93] updated japanese translation. (#7656) Co-authored-by: ku2works --- companion/src/translations/companion_ja.ts | 2257 +++++++++++--------- 1 file changed, 1300 insertions(+), 957 deletions(-) diff --git a/companion/src/translations/companion_ja.ts b/companion/src/translations/companion_ja.ts index ddc8b2c37..da32c47fc 100644 --- a/companion/src/translations/companion_ja.ts +++ b/companion/src/translations/companion_ja.ts @@ -108,94 +108,94 @@ 送信機プロファイル - - - - - - + + + + + + Select Folder フォルダの選択 - - + + The profile specific folder, if set, will override general Backup folder プロファイル保存フォルダが指定される場合は、バックアップフォルダを上書き保存します - + Splash Screen 起動イメージ - + Select Image イメージの選択 - + Clear Image イメージの消去 - + Profile Name プロファイル名 - + Radio Type 送信機タイプ - + Menu Language メニュー言語 - + Build Options ビルドオプション - + SD Structure path SDカード保存先パス - + Backup folder バックアップフォルダ - + If set it will override the application general setting 設定されている場合はアプリケーション設定を上書き保存します - + if set, will override general backup enable 設定されている場合は有効なバックアップを上書き保存します - - + + Enable automatic backup before writing firmware 設定した場合は自動バックアップを有効にします - + General Settings 一般設定 - + Default Stick Mode 初期スティックモード - + Mode selection: Mode 1: @@ -218,464 +218,479 @@ Mode 4: - + Mode 1 (RUD ELE THR AIL) モード1 (左:エレベーター・ラダー 右:スロットル・エルロン) - + Mode 2 (RUD THR ELE AIL) モード2 (左:スロットル・ラダー 右:エレベーター・エルロン) - + Mode 3 (AIL ELE THR RUD) モード3 (左:エレベーター・エルロン 右:スロットル・ラダー) - + Mode 4 (AIL THR ELE RUD) モード4 (左:スロットル・エルロン 右:エレベーター・ラダー) - + Default Channel Order 初期チャンネルマップ - + <html><head/><body><p>Channel order</p><p><br/></p><p>Defines the order of the default mixes created on a new model.</p></body></html> <html><head/><body><p>チャンネルマップ</p><p><br/></p><p>モデル作成された際の初期チャンネルマップを定義します</p></body></html> - + R E T A ↔RUD ↕ELE ↕THR ↔AIL [R E T A] - + R E A T ↔RUD ↕ELE ↔AIL ↕THR [R E A T] - + R T E A ↔RUD ↕THR ↕ELE ↔AIL [R T E A] - + R T A E ↔RUD ↕THR ↔AIL ↕ELE [R T A E] - + R A E T ↔RUD ↔AIL ↕ELE ↕THR [R A E T] - + R A T E ↔RUD ↔AIL ↕THR ↕ELE [R A T E] - + E R T A ↕ELE ↔RUD ↕THR ↔AIL [E R T A] - + E R A T ↕ELE ↔RUD ↔AIL ↕THR [E R A T] - + E T R A ↕ELE ↕THR ↔RUD ↔AIL [E T R A] - + E T A R ↕ELE ↕THR ↔AIL ↔RUD [E T A R] - + E A R T ↕ELE ↔AIL ↔RUD ↕THR [E A R T] - + E A T R ↕ELE ↔AIL ↕THR ↔RUD [E A T R] - + T R E A ↕THR ↔RUD ↕ELE ↔AIL [T R E A] - + T R A E ↕THR ↔RUD ↔AIL ↕ELE [T R A E] - + T E R A ↕THR ↕ELE ↔RUD ↔AIL [T E R A] - + T E A R ↕THR ↕ELE ↔AIL ↔RUD [T E A R] - + T A R E ↕THR ↔AIL ↔RUD ↕ELE [T A R E] - + T A E R ↕THR ↔AIL ↕ELE ↔RUD [T A E R] - + A R E T ↔AIL ↔RUD ↕ELE ↕THR [A R E T] - + A R T E ↔AIL ↔RUD ↕THR ↕ELE [A R T E] - + A E R T ↔AIL ↕ELE ↔RUD ↕THR [A E R T] - + A E T R ↔AIL ↕ELE ↕THR ↔RUD [A E T R] - + A T R E ↔AIL ↕THR ↔RUD ↕ELE [A T R E] - + A T E R ↔AIL ↕THR ↕ELE ↔RUD [A T E R] - + Append version number to FW file name ファームウェア ファイル名にバージョン番号を追加 - + + Simulator controls + シミュレータ コントロール + + + + Save switch/pot positions on simulator exit + シミュレータ終了時にスイッチ/ポットのポジションを保存 + + + + Clear saved positions + 保存したポジションを消去 + + + Offer to write FW to Tx after download ダウンロード後、送信機にFWを適用可能な事を通知 - + Other Settings その他の設定 - + Application Settings アプリケーション設定 - + Automatic check for OpenTX firmware updates OpenTXファームアップデートの自動チェック - + Automatic check for Companion updates Companionアップデートの自動チェック - + most recently used files 最近使用したファイル - + Startup Settings スタートアップ設定 - + Google Earth Executable Google Earthの実行 - + Automatic Backup Folder 自動バックアップフォルダ - + Remember ファイル履歴 - - Show splash screen when Companion starts - Companion起動時に起動イメージを表示 - - - + Output Logs Folder ログ出力フォルダ - + <html><head/><body><p>This option maintains the behaviour from older OpenTx versions where empty model slots are preserved when a model is deleted or moved. </p><p>When this option is de-selected, the other models may be re-arranged to fill the gap left by the removed model.</p></body></html> <html><head/><body><p>このオプションは、機体モデルが削除または移動した際、そのモデルスロットが保持される旧版のOpenTxバージョンの挙動を維持します。</p><p>このオプションが選択されない場合は、他の機体モデルは削除により残された差異を埋めるために並べ替えるかもしれません。</p></body></html> - + Remove empty model slots when deleting models (only applies for radios w/out categories) モデルを削除するとき同時に空モデルスロットを削除 (カテゴリなしの機体モデルにのみ適用) - + Use model wizard 機体モデルウィザードを使用 - + Open model editor 機体モデルエディタを開く - + Just create the model 機体モデルの作成のみ - + Debug Output Logging 出力したログのデバッグ - + Only show user splash images オリジナルの起動イメージのみを表示 - + Show user and companion splash images オリジナルとCompanion標準イメージを表示 - + + Show splash screen + 起動イメージを表示 + + + Select Executable 実行ファイル選択 - + <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>デスクトップのCompanion / シミュレータ アプリケーションにより生成された、すべてのデバッグメッセージのログを保存します。OpenTX開発者は問題を診断・解析するため、ログを要求するかもしれません。</p></body></html> - + Application (Companion/Simulator) アプリケーション (Companion / シミュレータ) - + <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>シミュレータで実行しているときは、送信機ファームウェアによって生成されたすべてのメッセージのログを保存してください。これはシミュレータの<span style = "font-style:italic;">デバッグ出力</span>ウィンドウにも同じ情報が表示されます。</p></body></html> - + Radio Firmware (in Simulator) 送信機ファームウェア (シミュレータ内) - + Splash Screen Library 起動イメージライブラリ - + User Splash Screens オリジナル起動イメージ - + Action on New Model 機体モデル新規作成 - + Release channel リリース状態 選択 - + Releases (stable) リリース版 (Stable) - + Release candidates (testing) Release candidates RC版 (Testing) - + Nightly builds (unstable) ナイトリービルド版 (Unstable) - + + Prompt for radio profile + 送信機プロファイルの呼び出し + + + Simulator Settings シミュレータ設定 - + Calibrate キャリブレート - + Blue 青色 - + Green 緑色 - + Red 赤色 - + Orange オレンジ - + Yellow 黄色 - + Screenshot capture folder 画面キャプチャフォルダ - + Only capture to clipboard キャプチャをクリップボードのみにコピー - + Enable 有効 - + Joystick スティック - + Simulator BackLight バックライト - - Remember simulator switch values - シミュレータで設定した各スイッチの値を記憶 - - - + Simulator Volume Gain シミュレータ 音量幅 - + My Radio マイ送信機 - + <p><b>You cannot switch Radio Type or change Build Options while there are unsaved file changes. What do you wish to do?</b></p> <ul><li><i>Save All</i> - Save any open file(s) before saving Settings.<li><li><i>Reset</i> - Revert to the previous Radio Type and Build Options before saving Settings.</li><li><i>Cancel</i> - Return to the Settings editor dialog.</li></ul> <p><b>ファイル変更後で保存されていない間は、送信機タイプの切り替えやビルドオプションの変更はできません。保存しますか?</b></p> <ul><li><i>すべて保存</i> - 設定を保存する前に、開いているファイルをすべて保存します  <li><li><i>リセット</i> - 設定を保存する前に、以前の送信機タイプとビルドオプションに戻します </li><li><i>キャンセル</i> - 設定エディタダイアログに戻ります </li></ul> - + Select your snapshot folder 画面キャプチャフォルダ選択してください - + Note: Nightly builds are not available in this version, Release/RC update channel will be used. 注: このバージョンではナイトリービルドは使用できません。リリース/RC版のアップデートチャネルが使用されます。 - - + + No joysticks found スティックが認識できません - + EMPTY: No radio settings stored in profile 空: プロファイルに送信機設定が保存されていません - + AVAILABLE: Radio settings of unknown age 利用可能: 詳細不明の送信機設定 - + AVAILABLE: Radio settings stored %1 利用可能: 送信機設定は %1 に保存されています - + Select your library folder ライブラリフォルダを選択してください - - + + Select your Models and Settings backup folder 機体モデルの選択とバックアップフォルダの設定をしてください - + Select a folder for application logs アプリケーションログフォルダを選択してください - + Select Google Earth executable Google Earth実行有無を選択してください - + Select the folder replicating your SD structure SDカード保存先フォルダを選択してください - + Open Image to load イメージを開いてロードします - + Images (%1) イメージ (%1) @@ -715,58 +730,58 @@ Mode 4: Boards - + Left Horizontal 左・横 - + Left Vertical 左・縦 - + Right Vertical 右・縦 - + Right Horizontal 右・横 - + Aux. 1 AUX. 1 - + Aux. 2 AUX. 2 - - + + Unknown 不明 - + Rud ラダー - + Ele エレベーター - + Thr スロットル - + Ail エルロン @@ -815,84 +830,124 @@ Mode 4: Channels - + Name 名称 - + Subtrim サブトリム - + Min 最小 - + Max 最大 - + Direction 方向 - + Curve カーブ - + PPM Center PPM センター - + Linear Subtrim 線形サブトリム - + CH%1 CH%1 - + Popup menu available 利用可能なポップアップメニュー - + --- --- - + INV リバース - - &Copy - &コピー - - - - &Cut - &切り取り + + Delete Channel. Are you sure? + チャンネルを削除します。よろしいですか? - &Paste - &貼り付け + Copy + コピー - &Delete - &削除 + Cut + 切り取り + + + + Paste + 貼り付け + + + + Clear + 消去 + + + + Insert + 挿入 + + + + Delete + 削除 + + + + Move Up + 上へ移動 + + + + Move Down + 下へ移動 + + + + Clear All + すべて消去 + + + + Clear Channel. Are you sure? + チャンネルを消去します。よろしいですか? + + + + Clear all Channels. Are you sure? + チャンネルをすべて消去します。よろしいですか? @@ -1310,7 +1365,7 @@ If you have a settings backup file, you may import that instead. CurveData - + CV CV @@ -1450,79 +1505,109 @@ If you have a settings backup file, you may import that instead. 点のサイズ - + Curve %1 カーブ %1 - + Popup menu available 利用可能なポップアップメニュー - + %1 points %1 点 - + Linear 線形 - + Single Expo シングルエクスポ - + Symmetrical f(x)=-f(-x) 対称 f(x)=-f(-x) - + Symmetrical f(x)=f(-x) 対称 f(x)=f(-x) - + Editing curve %1 カーブ %1 編集 - + Not enough free points in EEPROM to store the curve. EEPROMにカーブを保存する十分な空き容量がありません。 - + Copy コピー - + + Cut + 切り取り + + + Paste 貼り付け - + Clear 消去 - - Clear all curves - すべてのカーブ消去 + + Insert + 挿入 - - Are you sure you want to reset curve %1? - カーブ %1をリセットしてもよいですか? + + Delete + 削除 - - Are you sure you want to reset all curves? - すべてのカーブをリセットしてもよいですか? + + Move Up + 上へ移動 + + + + Move Down + 下へ移動 + + + + Clear All + すべて消去 + + + + Clear Curve. Are you sure? + カーブを消去します。よろしいですか? + + + + Clear all Curves. Are you sure? + カーブをすべて消去します。よろしいですか? + + + + Delete Curve. Are you sure? + カーブを削除します。よろしいですか? @@ -1569,193 +1654,198 @@ If you have a settings backup file, you may import that instead. + Trainer Channels + トレーナー チャンネル + + + Instant Trim トリム - + Play Sound サウンド 再生 - + Haptic タッチパネル - + Reset リセット - + Set Timer %1 設定: タイマー %1 - + Vario バリオ - + Play Track トラック 再生 - + Play Both 両方 実行 - + Play Value 値 実行 - + Play Script スクリプト 実行 - + SD Logs SDログ - + Volume 音量 - + Backlight バックライト - + Screenshot 画面キャプチャ - + Background Music BGM - + Background Music Pause BGM一時停止 - + Adjust %1 アジャスト %1 - + SetFailsafe Int. Module 設定: フェイルセーフ 内部モジュール - + SetFailsafe Ext. Module 設定: フェイルセーフ 外部モジュール - + RangeCheck Int. Module レンジチェック 内部モジュール - + RangeCheck Ext. Module レンジチェック 外部モジュール - + Bind Int. Module バインド 内部モジュール - + Bind Ext. Module バインド 外部モジュール - + Timer1 タイマー1 - + Timer2 タイマー2 - + Timer3 タイマー3 - + Flight フライト - + Telemetry テレメトリー - + Rotary Encoder エンコーダ再生 - + REa エンコーダ再生a - + REb エンコーダ再生b - + s s - - - + + + <font color=red><b>Inconsistent parameter</b></font> <font color=red><b>矛盾しているパラメータ</b></font> - + Value 値 - + played once, not during startup 起動時以外 1回実行 - + repeat(%1s) リピート(%1s) - + DISABLED 無効 - + CFN CFN @@ -1815,42 +1905,82 @@ If you have a settings backup file, you may import that instead. %1 - - &Copy - &コピー + + Delete Special Function. Are you sure? + スペシャルファンクションを削除します。よろしいですか? - - &Cut - &切り取り + + Copy + コピー - - &Paste - &貼り付け + + Cut + 切り取り - - &Delete - &削除 + + Paste + 貼り付け - + + Clear + 消去 + + + + Insert + 挿入 + + + + Delete + 削除 + + + + Move Up + 上へ移動 + + + + Move Down + 下へ移動 + + + + Clear All + すべて消去 + + + + Clear Special Function. Are you sure? + スペシャルファンクションを消去します。よろしいですか? + + + + Clear all Special Functions. Are you sure? + スペシャルファンクションをすべて消去します。よろしいですか? + + + Value 値 - + Source 選択元 - + GVAR GVAR - + Increment 増加 @@ -2043,23 +2173,23 @@ If you have a settings backup file, you may import that instead. このボードでは選択元 %1 をエクスポートできません! - + OpenTX only accepts %1 points in all curves OpenTXはすべてのカーブで %1 点のみを許容します - + OpenTx only accepts %1 points in all curves OpenTxはすべてのカーブで %1 点のみを許容します - - + + OpenTX on this board doesn't accept this function このボード上のOpenTXはこの機能を受け付けません - + OpenTX doesn't accept this radio protocol OpenTXはこの送信機プロトコルを受け付けません @@ -2139,12 +2269,12 @@ To <b>remove a remembered entry</b> from the filter list, first cho フィルタをON / OFFします。 - + <html><head><style>kbd {background-color: palette(alternate-base); font-size: large; white-space: nowrap;}</style></head><body><p>The filter supports two syntax types: basic matching with common wildcards as well as full Perl-style (<code>pcre</code>) Regular Expressions.</p><p>By default a filter will only show lines which match (<b>inclusive</b>). To make an <b>exclusive</b> filter which removes matching lines, prefix the filter expression with a <kbd>!</kbd> (exclamation mark).</p><p>To use <b>Regular Expressions</b> (RegEx), prefix the filter text with a <kbd>/</kbd> (slash) or <kbd>^</kbd> (up caret). <ul><li>Put the <kbd>/</kbd> or <kbd>^</kbd> after the exclusive <kbd>!</kbd> indicator if you're using one.</li><li>By default the match is case-sensitive. To make it insensitive, add the typical <kbd>/i</kbd> (slash i) operator at the end of your RegEx.</li><li>If you use a caret (^) to denote a RegEx, it will become part of the Reg. Ex. (that is, matches from start of line).</li><li>If the RegEx is invalid, the filter edit field should show a red border and you will not be able to enable the filter.</li><li>A useful resource for testing REs (with a full reference) can be found at <a href="http://www.regexr.com/">http://www.regexr.com/</a></li></ul></p><p>To use <b>basic matching</b> just type any text.<ul><li>Wildcards: <kbd>*</kbd> (asterisk) matches zero or more of any character(s), and <kbd>?</kbd> (question mark) matches any single character.</li><li>The match is always case-insensitive.</li><li>The match always starts from the beginning of a log line. To ignore characters at the start, use a leading <kbd>*</kbd> wildcard.</li><li>A trailing <kbd>*</kbd> is always implied (that is, matches anything to the end of the log line). To avoid this, use a RegEx.</li><li>You can match literal wildcard characters by prefixing them with a <kbd>\</kbd> (backslash) character (eg. "foo\*bar" matches "foo*bar").</li></ul></p><p>After <b>editing text</b>, press ENTER or TAB key (or click anywhere outside the box) to update the filter.</p><p>To <b>remove an entry</b> from the filter selector list, first choose it, and while in the line editor press <kbd>Shift-Delete</kbd> (or <kbd>Shift-Backspace</kbd>) key combination. The default filters cannot be removed. Up to 50 filters are stored.</p></body></html> <html><head><style>kbd {background-color: palette(alternate-base); font-size: large; white-space: nowrap;}</style></head><body><p>フィルタは2つのシンタックスタイプをサポートしています: 一般的なワイルドカードを用いた完全一致、そして完全なPerlスタイル (<code>pcre</code>) 正規表現です。初期値ではフィルタは一致する (<b>包括的</b>) な行のみを表示します。一致する行を削除する<b>排他的</b>フィルタを作成するには、フィルタ式の先頭に<kbd>!</kbd>(Exclamationマーク)を付けます。</p><p>To use <b>Regular Expressions</b> (RegEx), prefix the filter text with a <kbd>/</kbd> (slash) or <kbd>^</kbd> (up caret). <b>正規表現</b> (RegEx)を使用するには、フィルタテキストの先頭に<kbd>/</kbd> (スラッシュ) または<kbd>^</kbd>(アップキャレット)を付けます。<ul><li>既に <kbd>/</kbd> または <kbd>^</kbd> を使用している場合は、 <kbd>!</kbd> の後ろに置きます。</li><li>初期値では大文字と小文字が区別されます。それを鈍感にするには、正規表現の最後に典型的な <kbd>/i</kbd> (スラッシュ+i)演算子を追加します。</li> <li> 正規表現を表すためにキャレット『^』を使用すると、それは正規表現の一部になります。例(つまり、行頭から一致します。)</li> <li> 正規表現が無効な場合、フィルタ編集フィールドには赤い枠が表示されフィルタを有効にすることはできません。</li> <li> 正規表現のテストに役立つリソース(参考文献)は、<a href="http://www.regexr.com/"> http://www.regexr.com/にあります。</a></li> </ul></p><p><b>標準一致 basic matching</b> を使用するには、テキストを入力するだけです。<ul><li>ワイルドカード: <kbd>*</kbd> (アスタリスク)は0個以上の任意の文字に一致し、 <kbd>?</kbd> (クエスチョンマーク) は任意の1文字に一致します。</li><li>この一致では常に大文字と小文字が区別されません。</li><li>一致は常にログの先頭行から始まります。 先頭の文字を無視するには、先頭に<kbd>*</kbd>ワイルドカードを使用します。</li><li>末尾の <kbd>*</kbd> は常に暗黙的に指定されます。(つまり、ログ末尾行までが対象) これを回避するには、正規表現を使用します。</li><li>リテラルワイルドカード文字の前に <kbd>\</kbd> (バックスラッシュ) 文字を付けることで一致させることができます。(例: "foo\*bar"は"foo*bar"と一致)</li></ul></p><p><b>テキスト編集</b>後、EnterまたはTabキーを押して (またはボックスの外側をクリックし) フィルタを更新します。</p><p>フィルタセレクタリストから<b>エントリー削除</b>をするには、まずエントリーを選択しエディタで<kbd>Shift+Delete</kbd> (または<kbd>Shift+Backspace</kbd>) を押します。デフォルトのフィルタは削除できません。また最大50個のフィルタが保存されています。</p></body></html> - + Debug Console Filter Help デバッグコンソールフィルタ ヘルプ @@ -2795,275 +2925,279 @@ Blank means include all. ?, *, and [...] wildcards accepted. Firmware - + Channel values displayed in us 表示されるチャンネル値 - + No OverrideCH functions available 使用可能な上書きチャンネル機能はありません - + Possibility to enable FAI MODE (no telemetry) at field フィールドでFAIモード (テレメトリーなし) を有効にする可能性 - + FAI MODE (no telemetry) always enabled FAIモード (テレメトリーなし) を常に有効 - + Removes D8 FrSky protocol support which is not legal for use in the EU on radios sold after Jan 1st, 2015 2015/01/01以降に販売された送信機に対し、EUでの使用に適さないD8 FrSkyプロトコルサポートを削除 - + Enable non certified firmwares 認定されていないファームウェアを有効にする - - + + Disable HELI menu and cyclic mix support HELIメニューとサイクリックミックスサポートを無効にする - - + + Disable Global variables グローバル変数を無効にする - - + + Enable Lua custom scripts screen Luaカスタムスクリプト画面を有効にする - + Use alternative SQT5 font SQT5 代替フォントを使用する - + Pots use in menus navigation メニューナビゲーションでダイヤルを使用 - + FrSky Taranis X9D+ FrSky Taranis X9D+ - + Support for PPM internal module hack PPM内部モジュールハックのサポート - + + Disable RAS (SWR) RAS (SWR)を無効にする - + FrSky Taranis X9D+ 2019 - + FrSky Taranis X9D FrSky Taranis X9D - + Haptic module installed タッチパネル対応モジュールをインストール - + FrSky Taranis X9E FrSky Taranis X9E - + Confirmation before radio shutdown 送信機シャットダウン前の確認 - + Horus gimbals installed (Hall sensors) Horusジンバル (ホールセンサー) をインストール - + FrSky Taranis X9-Lite FrSky Taranis X9-Lite - - - - - - Support for auto update on boot - 起動時の自動更新サポート - - - + FrSky Taranis X9-Lite S - + FrSky Taranis X7 / X7S FrSky Taranis X7 / X7S - + FrSky Taranis X-Lite S/PRO FrSky Taranis X-Lite S/PRO - + FrSky Taranis X-Lite FrSky Taranis X-Lite - + FrSky Horus X10 / X10S FrSky Horus X10 / X10S - - FrSky Horus X10 / X10S Express - - - - + FrSky Horus X12S FrSky Horus X12S - + Use ONLY with first DEV pcb version 初期DEV pcbバージョンでのみ使用 - - Jumper T16 / T16+ - - - - + + Support for MULTI internal module MULTI内部モジュールのサポート - + + Support for bluetooth module Bluetoothモジュールのサポート - + Turnigy 9XR-PRO Turnigy 9XR-PRO - + Enable HELI menu and cyclic mix support HELIメニューとサイクリックミックスのサポートを有効にする - + Global variables グローバル変数 - + In model setup menus automatically set source by moving the control モデル設定メニューでは、コントローラーを動かし自動的に選択元を設定します - + In model setup menus automatically set switch by moving the control モデル設定メニューでは、コントローラーを動かし自動的にスイッチを設定します - + No graphical check boxes and sliders グラフィカルなチェックボックスとスライダーはありません - + Battery graph バッテリーグラフ - + Don't use bold font for highlighting active items 有効なアイテムを強調表示するために太字フォントを使用しない - - + + FrSky Taranis X7 / X7S Access + FrSky Taranis X7 / X7S ACCESS + + + + Support for ACCESS internal module replacement ACCESS内部モジュール変更のサポート - - Jumper T12 - - - - - Enable non certified R9M firmwares - 非認定 R9Mファームウェアを有効 - - - + Turnigy 9XR with m128 chip Turnigy 9XR m128チップ搭載 - + Turnigy 9XR Turnigy 9XR - + 9X with stock board 9X ストックボード - + Enable resetting values by pressing up and down at the same time 上下に同時に押し、値のリセットを有効にする - + 9X with stock board and m128 chip 9X ストックボード+m128 chip - + 9X with AR9X board 9X AR9Xボード - + + FrSky Horus X10 Express / X10S Express + FrSky Horus X10 Express / X10S Express + + + + Jumper T12 / T12 Pro + Jumper T12 / T12 Pro + + + + Jumper T16 / T16+ / T16 Pro + Jumper T16 / T16+ / T16 Pro + + + + Radiomaster TX16s / TX16s Hall / TX16s Masterfire + Radiomaster TX16s / TX16s Hall / TX16s Masterfire + + + + Support internal GPS + 内蔵GPSサポート + + + 9X with Sky9x board 9X Sky9Xボード - + 9X with Gruvin9x board 9X Gruvin9X - + DIY MEGA2560 radio DIY MEGA2560 送信機 @@ -3538,11 +3672,21 @@ You are currently using: Switch スイッチ + + + trim6 + トリム6 + + + + trim5 + トリム5 + FlightModeData - + FM FM @@ -3550,122 +3694,200 @@ You are currently using: FlightModePanel - + + Popup menu available 利用可能なポップアップメニュー - + Trim disabled トリム 無効 - + Own Trim 独自トリム - + Use Trim from Flight mode %1 フライトモードからトリムを使用してください %1 - + Use Trim from Flight mode %1 + Own Trim as an offset フライトモードからトリムを使用してください %1+オフセット独自トリム - + Rotary Encoder %1 ロータリーエンコーダ %1 - + Name 名称 - + Value source 元値 - + Value 値 - + Unit ユニット - + Prec - + Min 最小 - + Max 最大 - + Popup enabled ポップアップ有効 - + GVAR%1 - + 0._ - + 0.0 0.0 - - - &Clear - &消去 + + Warning: Global variable links back to itself. Flight Mode 0 value used. + 警告: フライトモード0の値を使用するとグローバル変数としてリンクされます。 - - + + Warning: Rotary encoder links back to itself. Flight Mode 0 value used. + 警告: フライトモード0の値を使用するとロータリーエンコーダとしてリンクされます。 + + + + + Copy + コピー + + + + + Cut + 切り取り + + + + + Paste + 貼り付け + + + + + Insert + 挿入 + + + + + Delete + 削除 + + + + + Move Up + 上へ移動 + + + + + Move Down + 下へ移動 + + + + + Clear All + すべて消去 + + + + Clear Flight Mode. Are you sure? + フライトモードを消去します。よろしいですか? + + + + Clear all Flight Modes. Are you sure? + フライトモードをすべて消去します。よろしいですか? + + + + Delete Flight Mode. Are you sure? + フライトモードを削除します。よろしいですか? + + + + Clear selected Global Variable across all Flight Modes. Are you sure? + すべてのフライトモードの選択したグローバル変数を消去します。よろしいですか? + + + + Clear all Global Variables for all Flight Modes. Are you sure? + すべてのフライトモードのすべてのグローバル変数を消去します。よろしいですか? + + + + Clear all Global Variables for this Flight Mode. Are you sure? + このフライトモードのすべてのグローバル変数を消去します。よろしいですか? + + + + Clear 消去 - - - Clear all current Flight Mode properties? - 現在のフライトモードのプロパティをすべて消去しますか? - FlightModesPanel - + Flight Mode %1 フライトモード %1 - + (%1) (%1) - + (default) (初期値) @@ -3993,7 +4215,7 @@ These will be relevant for all models in the same EEPROM. GeneralSettings - + Radio Settings 送信機設定 @@ -4462,6 +4684,11 @@ p, li { white-space: pre-wrap; } Show splash screen on startup 起動時、起動イメージ表示 + + + nnnnnnNN + nnnnnnNN + Power On Delay @@ -4648,11 +4875,6 @@ Acceptable values are 5v..10v Owner Registration ID オーナー登録ID - - - aaaaaaAA - - R E T A @@ -5283,8 +5505,8 @@ Are you sure ? HardwarePanel - - + + None なし @@ -5304,67 +5526,67 @@ Are you sure ? 3 ポジション - + Pot with detent ダイヤル (ノッチあり) - + Multipos switch マルチPosスイッチ - + Pot without detent ダイヤル (ノッチなし) - + Slider with detent スライダー (ノッチあり) - + OFF OFF - + Enabled 有効 - + Telemetry テレメトリー - + Trainer トレーナー - + Internal 内部 - + Ask 確認 - + Per model Per モデル - + Internal + External 内部 + 外部 - + External 外部 @@ -5491,138 +5713,171 @@ Are you sure ? InputsPanel - + + Move Up 上へ移動 - + Ctrl+Up - + + Move Down 下へ移動 - + Ctrl+Down Clear All Inputs - すべての入力を消去 + すべての入力項目を消去 - - Not enough available inputs! - 入力項目が足りません! + + Not enough available Inputs! + 入力項目が不足しています! - - Delete Selected Inputs? - 選択した入力を削除しますか? + + Delete selected Inputs. Are you sure? + 選択した入力項目を削除します。よろしいですか? - + + Lines + 直線 + + + &Add &追加 - + Ctrl+A - + &Edit &編集 - + Enter Enter - + &Delete &削除 - + + Delete 削除 - + &Copy &コピー - + Ctrl+C - + &Cut &切り取り - + Ctrl+X - + &Paste &貼り付け - + Ctrl+V - + Du&plicate &複製 - + Ctrl+U - - Clear Inputs? - 入力を消去しますか? + + Input + 入力 - - Really clear all the inputs? - すべての入力を本当に消去しますか? + + Insert + 挿入 + + + + Clear + 消去 + + + + Clear All + すべて消去 + + + + Clear all Inputs. Are you sure? + すべての入力項目を消去します。よろしいですか? + + + + Clear Input. Are you sure? + 入力項目を消去します。よろしいですか? + + + + Delete Input. Are you sure? + 入力項目を削除します。よろしいですか? LimitData - + INV リバース - + NOR ノーマル - + CH CH @@ -5761,69 +6016,104 @@ Are you sure ? LogicalSwitchesPanel - + Function 機能 - + V1 - + V2 - + AND Switch & スイッチ - + Duration 期間 - + Delay 遅延 - + Popup menu available 利用可能なポップアップメニュー - + (instant) (瞬間) - + (infinite) (無制限) - - &Copy - &コピー - - - - &Cut - &切り取り + + Delete Logical Switch. Are you sure? + 論理スイッチを削除します。よろしいですか? - &Paste - &貼り付け + Copy + コピー - &Delete - &削除 + Cut + 切り取り + + + + Paste + 貼り付け + + + + Clear + 消去 + + + + Insert + 挿入 + + + + Delete + 削除 + + + + Move Up + 上へ移動 + + + + Move Down + 下へ移動 + + + + Clear All + すべて消去 + + + + Clear all Logical Switches. Are you sure? + 論理スイッチをすべて消去します。よろしいですか? @@ -5971,8 +6261,8 @@ The columns for altitude "GAlt" and for speed "GSpd" are opt - total duration - 合計期間 + time span + 期間 @@ -6003,123 +6293,123 @@ The columns for altitude "GAlt" and for speed "GSpd" are opt MainWindow - + Diskimage (*.dmg) ディスクイメージ (*.dmg) - + Would you like to open the disk image to install the new version? 新しいバージョンをインストールするためにディスクイメージを開きますか? - + Executable (*.exe) 実行ファイル (*.exe) - - + + Would you like to launch the installer? インストーラを起動しますか? - - + + File loaded ファイルがロードされました - + Checking for updates アップデートの確認 - + A new version of Companion is available (version %1)<br>Would you like to download it? Companionの新しいバージョンがあります。 (version %1)<br>ダウンロードしますか? - - + + Save As 名前を付けて保存 - + New release available 新リリースが利用可能 - + A new release of Companion is available, please check the <a href='%1'>OpenTX website!</a> Companionの新リリースが利用可能です。<a href='%1'>OpenTX Webサイト</a>をチェックしてください - - + + No updates available at this time. 現時点で利用可能なアップデートはありません。 - + Error opening file %1: %2. ファイル %1 を開くときにエラーが発生しました: %2. - + Not enough flash available on this board for all the selected options 選択されたすべてのオプションに対してこのボードでは十分な書き込みが行えません - + Compilation server temporary failure, try later コンパイルサーバが一時的に失敗しました。後程お試しください - + Compilation server too busy, try later コンパイルサーバがビジー状態です。後程お試しください - + Compilation error コンパイルエラー - + Invalid firmware 無効なファームウェア - + Invalid board 無効なボード - + Invalid language 無効な言語 - + Unknown server failure, try later 不明なサーバの障害です。後程お試しください - + Do you want to write the firmware to the radio now ? 今すぐファームウェアを送信機に書き込みますか? - + Firmware update check failed, new version information not found or invalid. ファームウェアアップデートの確認に失敗しました。新しいバージョン情報が見つからないか、または無効です。 - + Firmware %1 does not seem to have ever been downloaded. Version %2 is available. Do you want to download it now? @@ -6132,31 +6422,31 @@ We recommend you view the release notes using the button below to learn about an 重要な変更については、下のボタンをクリックしてリリースノートを参照することをお勧めします。 - - + + Yes はい - - + + No いいえ - - + + Release Notes リリースノート - - + + Do you want to download version %1 now ? 今すぐバージョン %1 をダウンロードしますか? - + A new version of %1 firmware is available: - current is %2 - newer is %3 @@ -6173,29 +6463,29 @@ We recommend you view the release notes using the button below to learn about an 重要な変更については、下のボタンをクリックしてリリースノートを参照することをお勧めします。 - + Ignore this version %1? このバージョン %1 を無視しますか? - + The new theme will be loaded the next time you start Companion. 次回Companionを起動したときに、新しいテーマがロードされます。 - - + + Open Models and Settings file 機体モデルと設定ファイルを開く - + File saved ファイル 保存 - + There are unsaved file changes which you may lose when switching radio types. Do you wish to continue? @@ -6204,780 +6494,780 @@ Do you wish to continue? そのまま続けますか? - - + + Synchronize SD SDカードを同期する - + No local SD structure path configured! SDカード保存先パスが設定されていません! - + No Companion release candidates are currently being served for this version, please switch release channel 現在このバージョンのCompanion RC版は提供されていません。リリース状態を切り替えてください - + No nightly Companion builds are currently being served for this version, please switch release channel 現在、このバージョンのCompanion ナイトリービルド版は提供されていません。リリース状態を切り替えてください - + No Companion release builds are currently being served for this version, please switch release channel このバージョンのCompanion リリース版は現在提供されていません。リリース状態を切り替えてください - + Companion update check failed, new version information not found. Companionアップデートの確認に失敗しました。新しいバージョン情報が見つかりません。 - + No firmware release candidates are currently being served for this version, please switch release channel 現在、このバージョンのファームウェア RC版は提供されていません。リリース状態を切り替えてください - + No firmware nightly builds are currently being served for this version, please switch release channel 現在、このバージョンのファームウェア ナイトリービルド版は提供されていません。リリース状態を切り替えてください - + No firmware release builds are currently being served for this version, please switch release channel 現在、このバージョンのファームウェア リリース版は提供されていません。リリース状態を切り替えてください - + Release candidate builds are now available for this version, would you like to switch to using them? RC版はこのバージョンで利用可能になりました。それらに切り替えますか? - + Channel changed to RC, please restart the download process リリース状態をRC版に変更しました。ダウンロードプロセスを再起動してください - + Official release builds are now available for this version, would you like to switch to using them? このバージョンの公式リリース版が利用可能になりました。それらに切り替えますか? - + Channel changed to Release, please restart the download process リリース状態をリリース版に変更しました。ダウンロードプロセスを再起動してください - + This radio (%1) is not currently available in this firmware release channel この送信機 (%1) は、現在このファームウェアリリース状態では利用できません - + No Radio or SD card detected! 送信機またはSDカードが検出されませんでした! - + Local Folder ローカルフォルダ - + Radio Folder 送信機フォルダ - - + + Read Firmware from Radio 送信機からファームウェアを読み込み - - + + Read Models and Settings from Radio 送信機から機体モデルや設定を読み込み - + Models and Settings read 機体モデルと設定の読み込み - - + + This function is not yet implemented この機能はまだ実装されていません - + Save Radio Backup to File 送信機のバックアップをファイルに保存 - + Read Radio Firmware to File 送信機ファームウェアからファイルへの読み込み - + OpenTX Home Page: <a href='%1'>%1</a> OpenTX ホームページ: <a href='%1'>%1</a> - + The OpenTX Companion project was originally forked from <a href='%1'>eePe</a> OpenTX Companionプロジェクトは元々<a href='%1'>eePe</a>から派生しました - + If you've found this program useful, please support by <a href='%1'>donating</a> このプログラムが役に立つと感じた場合は、<a href='%1'>寄付</a>でのサポートをお願いします - + Copyright OpenTX Team Copyright OpenTX Team - + About Companion Companionについて - + OpenTX Companion %1 - Radio: %2 - Profile: %3 OpenTX Companion %1 - 送信機: %2 - プロファイル: %3 - + New 新規 - + Create a new Models and Settings file 新規モデルと設定ファイルを作成します - + Open... 開く... - + Save 保存 - - + + Save Models and Settings file 機体モデルと設定ファイルを保存します - + Save As... 名前を付けて保存... - + Close 閉じる - + Close Models and Settings file 機体モデルと設定ファイルを閉じます - + Exit 終了 - + Exit the application アプリケーションを終了します - + About... バージョン情報... - + Show the application's About box アプリケーションのバージョン情報を表示します - + Recent Files 最近使用したファイル - + List of recently used files 最近使用したファイルを一覧表示 - + Radio Profiles 送信機プロファイル - + Create or Select Radio Profiles 送信機プロファイルを作成または選択します - + View Log File... ログファイルを表示... - + Open and view log file ログファイルを開いて表示します - + Settings... 設定... - + Edit Settings 設定を編集します - + Download... ダウンロード... - + Download firmware and voice files ファームウェアと音声ファイルをダウンロードします - + Check for Updates... アップデートのチェック... - + Check OpenTX and Companion updates OpenTXとCompanionのアップデートを確認します - + Release notes... リリースノート... - + Show release notes リリースノートを表示します - + Compare Models... 機体モデルを比較... - + Compare models 機体モデルを比較します - + Edit Radio Splash Image... 送信機の起動イメージを編集... - + Edit the splash image of your Radio 送信機の起動イメージを編集します - + List programmers... プログラムを一覧表示... - + List available programmers 利用可能なプログラムを一覧表示します - + Fuses... ヒューズ... - + Show fuses dialog ヒューズダイアログを表示します - + Read firmware from Radio 送信機からファームウェアを読み込み - + Write Firmware to Radio 送信機にファームウェアを書き込み - + Write firmware to Radio 送信機にファームウェアを書き込み - + SD card synchronization SDカードの同期 - + Manuals and other Documents マニュアルと他の文書 - + Open the OpenTX document page in a web browser WebブラウザでOpenTXドキュメントページを開く - + Write Models and Settings To Radio 機体モデルと設定を送信機に書き込み - + Write Models and Settings to Radio 機体モデルと設定を送信機に書き込み - + Read Models and Settings From Radio 送信機から機体モデルや設定を読み込み - + Configure Communications... 送信機疎通を設定... - + Configure software for communicating with the Radio 送信機と疎通するためのソフトウェアを設定します - + Write Backup to Radio 送信機からバックアップを書き出す - + Write Backup from file to Radio 送信機ファイルからバックアップを書き出します - + Backup Radio to File ファイルを送信機にバックアップ - + Save a complete backup file of all settings and model data in the Radio すべての設定とモデルデータの完全なバックアップファイルを送信機に保存します - + Contributors... 貢献者... - + A tribute to those who have contributed to OpenTX and Companion OpenTXとCompanionに貢献した人々への賛辞 - + Add Radio Profile 送信機プロファイルの追加 - + Create a new Radio Settings Profile 新しい送信機設定プロファイルを作成します - + Copy Current Radio Profile 現在の送信機プロファイルをコピー - + Duplicate current Radio Settings Profile 現在の送信機設定プロファイルを複製します - + Delete Current Radio Profile... 現在の送信機プロファイルを削除... - + Delete the current Radio Settings Profile 現在の送信機設定プロファイルを削除します - + Export Application Settings.. アプリケーション設定のエクスポート.. - + Save all the current %1 and Simulator settings (including radio profiles) to a file. 現在のすべての%1およびシミュレータ設定(送信機プロファイル含)をファイルに保存します。 - + Import Application Settings.. アプリケーション設定をインポート.. - + Load %1 and Simulator settings from a prevously exported settings file. 以前にエクスポートした設定ファイルから%1とシミュレーション設定を読み込みます。 - + Tabbed Windows タブ付きウィンドウ - + Use tabs to arrange open windows. 開いているウィンドウを並べ替えるのにタブを使用します。 - + Tile Windows ウィンドウのタイトル - + Arrange open windows across all the available space. 利用可能なすべてのスペースに開いているウィンドウを配置します。 - + Cascade Windows ウィンドウを重ねる - + Arrange all open windows in a stack. 開いているウィンドウをすべて重ねて配置します。 - + Close All Windows すべてのウィンドウを閉じる - + Closes all open files (prompts to save if necessary. 開いているファイルをすべて閉じます (必要に応じ保存を求められます)。 - - + + Edit 編集 - - + + File ファイル - + Settings 設定 - + Set Icon Theme アイコンテーマ設定 - + Set Icon Size アイコンサイズ設定 - + Read/Write 読み込み/書き込み - + Window ウィンドウ - - + + Help ヘルプ - + Write 書き込み - + Some text will not be translated until the next time you start Companion. Please note that some translations may not be complete. 次にCompanionを起動するまで一部のテキストは翻訳されません。いくつかの翻訳は完全ではないかもしれませんのでご注意ください。 - + Ctrl+Shift+S - + Ctrl+Alt+L - + Ctrl+Alt+D - + Ctrl+Alt+R - + Classical クラシック - + The classic companion9x icon theme クラシック Companion9x アイコンテーマ - + Yerico イェリコ - + Yellow round honey sweet icon theme Yellow round honey sweet アイコンテーマ - + Monochrome モノクローム - + A monochrome black icon theme A monochrome black アイコンテーマ - + MonoBlue モノブルー - + A monochrome blue icon theme A monochrome blue アイコンテーマ - + MonoWhite モノホワイト - + A monochrome white icon theme A monochrome white アイコンテーマ - + Small 小サイズ - + Use small toolbar icons 小サイズのツールバーアイコンを使用 - + Normal 標準サイズ - + Use normal size toolbar icons 標準サイズのツールバーアイコンを使用 - + Big 大サイズ - + Use big toolbar icons 大サイズのツールバーアイコンを使用 - + Huge 特大サイズ - + Use huge toolbar icons 特大サイズのツールバーアイコンを使用 - + Set Menu Language メニュー言語を設定 - + System language システム言語 - + Use default system language. デフォルトのシステム言語を使用します。 - + Use %1 language (some translations may not be complete). %1言語を使用します (一部の翻訳が不完全な場合あり)。 - + Ready 準備完了 - + %2 %2 - + Alt+%1 - + New Radio 新規 送信機 - + - Copy - コピー - + Companion :: Open files warning Companion :: ファイルを開くときの警告 - + Please save or close modified file(s) before deleting the active profile. 有効なプロファイルを削除する前に、変更したファイルを保存するか閉じてください。 - + Not possible to remove profile プロファイルを削除できません - + The default profile can not be removed. デフォルトプロファイルは削除できません。 - + Confirm Delete Profile プロファイル削除の確認 - + Are you sure you wish to delete the "%1" radio profile? There is no way to undo this action! 『%1』送信機プロファイルを削除してもよろしいですか?この操作を元に戻すことはできません! - + Please save or close all modified files before importing settings 設定をインポートする前に、変更したファイルをすべて保存するか閉じてください - + <html><p>%1 and Simulator settings can be imported (restored) from a previosly saved export (backup) file. This will replace current settings with any settings found in the file.</p><p>An automatic backup of the current settings will be attempted. But if the current settings are useful then it is recommended that you make a manual backup first.</p><p>For best results when importing settings, <b>close any other %1 windows you may have open, and make sure the standalone Simulator application is not running.</p><p>Do you wish to continue?</p></html> <html><p>%1とシミュレータの設定は、以前に保存したエクスポート(バックアップ)ファイルからインポート(復元)できます。これにより、現在の設定がファイル内の設定に置き換えられます。</p><p>現在の設定の自動バックアップが実行されます。ただし、現在の設定が便利な場合は、まず手動バックアップを作成することをお勧めします。</p><p>設定をインポートし最良の結果を得るには、<b>開いている%1ウィンドウをすべて閉じます。スタンドアロンのシミュレーターアプリケーションが実行されていません。</p><p>続行しますか?</p></html> - + Confirm Settings Import 設定のインポートの確認 - + Select %1: %1を選択: - + backup バックアップ - + Press the 'Ignore' button to continue anyway. とにかく続行するには『無視』ボタンを押してください。 - + The settings could not be imported. 設定をインポートできませんでした。 - + <html><p>New settings have been imported from:<br> %1.</p><p>%2 will now re-initialize.</p><p>Note that you may need to close and restart %2 before some settings like language and icon theme take effect.</p> <html><p>新しい設定は次の場所からインポートされました。<br>%1.</p><p>%2は再初期化されます。</p><p>場合によっては閉じて再起動する必要があります。言語やアイコンテーマなどの設定が有効になる前に%2が発生しました。</p> - + <p>The previous settings were backed up to:<br> %1</p> <p>以前の設定は次の場所にバックアップされました:<br> %1</p> @@ -7194,159 +7484,164 @@ Do you wish to continue? 空き容量 - + + read only + 読み取りのみ + + + New category Translators do NOT use accent for this, this is the default category name on Horus. 新規カテゴリ - + Category index out of range. カテゴリインデックスが範囲外です。 - + Cannot delete the last category. 最後のカテゴリは削除できません。 - + This category is not empty! このカテゴリは空ではありません! - + Cannot insert model, last model in list would be deleted. 機体モデルを挿入できません。リストの最後のモデルが削除されます。 - + Cannot add model, could not find an available model slot. 機体モデルを追加できません。利用可能なモデルスロットが見つかりません。 - + New model Translators: do NOT use accents here, this is a default model name. 新規モデル - + Cannot paste model, out of available model slots. 利用可能なモデルスロットから、機体モデルを貼り付けることができません。 - + You are replacing an existing model, are you sure? 既存の機体モデルを差し替えます。よろしいですか? - + Do you want to overwrite radio general settings? 送信機の一般設定を上書きしますか? - + Delete %n selected model(s)? 選択した機体モデルを %n つ削除しますか? - + Delete %n selected category(ies)? 選択したカテゴリ(ies)を %n つ削除しますか? - + Cannot duplicate model, could not find an available model slot. 機体モデルを複製できません。利用なモデルスロットが見つかりません。 - + Editing model %1: 機体モデル %1 を編集しています: - + Save As 名前を付けて保存 - + %1 has been modified. Do you want to save your changes? %1 は変更されました。 変更を保存しますか? - + <p><b>Currently selected radio type (%1) is not compatible with file %3 (from %2), models and settings need to be converted.</b></p> <p><b>現在選択されている送信機タイプ (%1) はファイル %3 (from %2) と互換性がありません。機体モデルと設定を変換する必要があります。</b></p> - + Do you wish to continue with the conversion? 変換を続けますか? - + Choose <i>Apply</i> to convert the file, or <i>Close</i> to close it without conversion. ファイルを変換するには<i>適用</i>を、変換せずに閉じるには<i>閉じる</i>を選択します。 - + <b>The conversion generated some important messages, please review them below.</b> <b>変換によっていくつかの重要なメッセージが出力されました。下記の内容を確認してください。</b> - + Companion :: Conversion Result for %1 Companion :: %1 の変換結果 - - Unable to find Horus radio SD card! - Horus送信機のSDカードが見つかりません! + + Unable to find radio SD card! + 送信機のSDカードが見つかりません! - + Models and Settings written 機体モデルと設定が書かれました - + Cannot write temporary file! 一時ファイルを書き込めません! - + Open backup Models and Settings file バックアップ機体モデルと設定ファイルを開く - + Unable to find file %1! ファイル %1 が見つかりません! - + Error opening file %1: %2. ファイル %1 を開くときにエラーが発生しました: %2. - + Error reading file %1: %2. ファイル %1 の読み取りエラーです: %2. - + Invalid binary backup File %1 無効なバイナリバックアップファイルです %1 @@ -7354,12 +7649,12 @@ Do you want to save your changes? MixData - + MIX ミックス - + (@%1) @@ -7754,12 +8049,12 @@ If blank then the mix is considered to be "ON" all the time. ModelData - + Model: 機体モデル: - + Throttle Source スロットル値 @@ -8700,12 +8995,7 @@ If blank then the mix is considered to be "ON" all the time. 受信機 3 - - Bind on startup - 起動時バインド - - - + Low Power 低パワー @@ -8715,158 +9005,183 @@ If blank then the mix is considered to be "ON" all the time. 警告: 送信出力を変更するには再バインドが必要です - + Channels チャンネル - + PPM delay PPM 遅延 - + us - + PPM Frame Length PPM フレーム長 - + ms ms - + Antenna アンテナ - + Output type 出力タイプ - + Open Drain オープン ドレン - + Push Pull プッシュ プル - + Option value オプション値 - + Protocol プロトコル - + Registration ID 登録ID - + Multi Radio Protocol マルチプロトコル - + Sub Type サブタイプ - + Failsafe Mode フェイルセーフモード - + Not set 設定なし - + Hold ホールド - + Custom カスタム - + No Pulses パルスなし - + Receiver 受信機 - + Trainer Mode トレーナーモード - + Master/Jack マスター/Jack - + Slave/Jack スレーブ/Jack - + Master/SBUS Module マスター/SBUSモジュール - + Master/CPPM Module マスター/CPPMモジュール - + Master/SBUS in battery compartment マスター/バッテリーカバー内SBUB - + WARNING: Requires non-certified firmware! 警告: 未認定のR9Mファームウェアが必要です! - + + Master/Bluetooth + マスター/Bluetooth + + + + Slave/Bluetooth + スレーブ/Bluetooth + + + + Master/Multi + マスター/Multi + + + + Disable Telemetry + テレメトリー無効 + + + + Disable Ch. Map + チャンネルマップ無効 + + + Failsafe Positions フェイルセーフポジション - + Show values in: 値の表示: - + % abbreviation for percent - + μs abbreviation for microseconds @@ -8948,12 +9263,12 @@ If blank then the mix is considered to be "ON" all the time. 100mW - 16CH (テレメトリーなし) - + Positive ノーマル - + Negative リバース @@ -8961,40 +9276,50 @@ If blank then the mix is considered to be "ON" all the time. ModulePanel - + Value 値 - + Hold ホールド - + No Pulse パルスなし - + Ask 確認 - + Internal 内部 - + Internal + External 内部 + 外部 - + External 外部 + + + Autodetect Format + フォーマット自動検出 + + + + Bind on channel + チャンネルへバインド + MultiModelPrinter @@ -9492,11 +9817,6 @@ If blank then the mix is considered to be "ON" all the time. DEFAULT 初期値 - - - Custom - proto %1) - カスタム - プロトコル%1) - MultirotorPage @@ -9524,22 +9844,22 @@ If blank then the mix is considered to be "ON" all the time. OpenTxEepromInterface - + Unknown error 不明のエラー - + ... plus %1 errors ...追加 %1 エラー - + Cannot write radio settings 送信機設定を書き込めません - + Cannot write model %1 機体モデル %1 を書き込めません @@ -9644,6 +9964,19 @@ If blank then the mix is considered to be "ON" all the time. ODFファイル (*.odt);;PDFファイル (*.pdf);;HTMLファイル (*.htm *.html);;すべてのファイル (*) + + ProfileChooserDialog + + + Select Profile + プロファイル選択 + + + + Profile + プロファイル + + ProgressDialog @@ -9812,8 +10145,8 @@ If blank then the mix is considered to be "ON" all the time. - Unable to find Horus radio SD card! - Horus送信機のSDカードが見つかりません! + Unable to find radio SD card! + 送信機のSDカードが見つかりません! @@ -10750,7 +11083,12 @@ X - + + ml/minute + + + + TELE @@ -10930,25 +11268,90 @@ If this is checked the throttle will be reversed. Idle will be forward, trim wi SetupPanel - + + Popup menu available + 利用可能なポップアップメニュー + + + Timer %1 タイマー %1 - + THR - + Profile Settings プロファイル設定 - + SD structure path not specified or invalid SDカード保存先パスが指定されていないか無効です + + + Copy + コピー + + + + Cut + 切り取り + + + + Paste + 貼り付け + + + + Clear + 消去 + + + + Insert + 挿入 + + + + Delete + 削除 + + + + Move Up + 上へ移動 + + + + Move Down + 下へ移動 + + + + Clear All + すべて消去 + + + + Clear Timer. Are you sure? + タイマーを消去します。よろしいですか? + + + + Clear all Timers. Are you sure? + タイマーをすべて消去します。よろしいですか? + + + + Delete Timer. Are you sure? + タイマーを削除します。よろしいですか? + SimpleTailPage @@ -11671,62 +12074,62 @@ The default is configured in the chosen Radio Profile. 送信機シミュレータ (%1) - + Could not determine startup data source. 起動データ元を特定できませんでした。 - + Could not load data, possibly wrong format. データをロードできません、フォーマットが間違っている可能性があります。 - + Data Load Error データロード エラー - + Invalid startup data provided. Plese specify a proper file/path. 無効なスタートアップデータが提供されました。正しいファイル/パスを指定してください。 - + Simulator Startup Error シミュレータ スタートアップ エラー - + Error saving data: could open file for writing: '%1' データ保存エラー: 書き込み用にファイルを開くことができました: 「%1」 - + Error saving data: could not get data from simulator interface. データ保存エラー: シミュレータのインターフェイスからデータを取得できませんでした。 - + An unexpected error occurred while attempting to save radio data to file '%1'. 送信機データをファイル「%1」に保存しようとしたときに予期せぬエラーが発生しました。 - + Data Save Error データ保存 エラー - + Cannot open joystick, joystick disabled スティックが接続不可、もしくはスティックが無効です - + Radio firmware error: %1 送信機 ファームウェア エラー: %1 - + - Flight Mode %1 (#%2) - フライトモード %1 (#%2) @@ -12427,104 +12830,104 @@ Too many errors, giving up. TelemetryPanel - + Telemetry screen %1 テレメトリースクリーン %1 - + FrSky S.PORT - + FrSky D - + FrSky D (cable) - + Source 信号元 - + Low Alarm 低アラーム - + Critical Alarm クリティカルアラーム - + Winged Shadow How High Winged Shadow How High - + Winged Shadow How High (not supported) Winged Shadow How High (サポートなし) - + Alti - + Alti+ - + VSpeed - - - + + + A1 - - - + + + A2 - - + + A3 - - + + A4 - - + + FAS - + Cells セル - + --- --- @@ -12537,274 +12940,284 @@ Too many errors, giving up. フォーム - + + TELE## + TELE## + + + Custom カスタム - + Calculated 計算値 - + Id ID - + Instance インスタンス - + Rx 受信 - + Add 追加 - + Average 平均 - + Min 最小 - + Max 最大 - + Multiply 乗算 - + Totalize 合計 - + Cell セル - + Consumption 消費 - + Dist 距離 - + Cells Sensor : セル センサー : - - - - - - - - + + + + + + + + --- --- - + GPS Sensor : GPS センサー : - + Alt. Sensor : 高度 センサー : - + Sensor : センサー : - + Raw (-) Raw (-) - + V V - + A - + mA - + kt - + m/s - + ft/s - + km/h - + mph - + m 分 - + ft - + °C - + °F - + % - + mAh - + W - + mW - + dBm - + RPM - + g - + ° - + Rad - + mL - + US fl.Oz. - + + ml/min + + + + Precision 精度 - + Ratio レシオ - + Blades ブレード - + Offset オフセット - + Multiplier 乗算 - + Auto Offset 自動オフセット - + Filter フィルタ - + Persistent 持続 - + Positive ノーマル - + Logs ログ @@ -12812,25 +13225,70 @@ Too many errors, giving up. TelemetrySensorPanel - + + TELE%1 + + + + + Popup menu available + 利用可能なポップアップメニュー + + + Lowest より低く - + Cell %1 セル %1 - + Highest より高く - + Delta 差分 + + + Copy + コピー + + + + Cut + 切り取り + + + + Paste + 貼り付け + + + + Clear + 消去 + + + + Clear All + すべて消去 + + + + Clear Telemetry Sensor. Are you sure? + テレメトリーセンサーを消去します。よろしいですか? + + + + Clear all Telemetry Sensors. Are you sure? + テレメトリーセンサーのすべてを消去します。よろしいですか? + TelemetrySimulator @@ -13209,12 +13667,12 @@ hh:mm:ss TimerData - + TMR - + Timer %1 タイマー %1 @@ -14192,119 +14650,4 @@ Press Cancel to abort joystick calibration without saving. キャリブレーションが完了していません。そのまま保存しますか? - - preferencesDialog - - - Preferences - 設定 - - - - Simu BackLight - シミュレータ バックライト - - - - Simulator capture folder - シミュレータ キャプチャフォルダ - - - - Joystick - スティック - - - - Remember simulator switches - シミュレータスイッチの記憶 - - - - Enable - 有効 - - - - Use clipboard only - クリップボードのみを使用 - - - - Calibrate - キャリブレート - - - - Blue - 青色 - - - - Green - 緑色 - - - - Red - 赤色 - - - - Orange - オレンジ - - - - Yellow - 黄色 - - - - - Open Folder - フォルダを開く - - - - Personal splash library - 個人イメージライブラリ - - - - Include companion splashes - 標準Companion起動イメージ - - - - Only user defined splashes - ユーザ設定の起動イメージのみ - - - - Splash library behaviour - 起動イメージライブラリの動作 - - - - Custom TX splash screen - カスタム起動イメージ - - - - Open Image - イメージを開く - - - - - ... - ... - - - - Invert Pixels - ピクセルを反転 - - From c6eedb1cbed3d8dacf2afa5c8f04676e0a1f1e6c Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Mon, 1 Jun 2020 12:49:06 +0200 Subject: [PATCH 14/93] Option INTERNAL_MODULE_PPM=YES was broken --- radio/src/pulses/pulses.cpp | 7 +++++++ radio/src/pulses/pulses.h | 1 + 2 files changed, 8 insertions(+) diff --git a/radio/src/pulses/pulses.cpp b/radio/src/pulses/pulses.cpp index afcbaa061..f0e48f4b6 100755 --- a/radio/src/pulses/pulses.cpp +++ b/radio/src/pulses/pulses.cpp @@ -319,6 +319,13 @@ static void enablePulsesInternalModule(uint8_t protocol) intmoduleTimerStart(MULTIMODULE_PERIOD); break; #endif + +#if defined(INTERNAL_MODULE_PPM) + case PROTOCOL_CHANNELS_PPM: + intmodulePpmStart(); + break; +#endif + default: break; } diff --git a/radio/src/pulses/pulses.h b/radio/src/pulses/pulses.h index e8c3ce8af..eba14a463 100644 --- a/radio/src/pulses/pulses.h +++ b/radio/src/pulses/pulses.h @@ -330,6 +330,7 @@ void sendByteDsm2(uint8_t b); void putDsm2Flush(); void putDsm2SerialBit(uint8_t bit); void sendByteSbus(uint8_t b); +void intmodulePpmStart(); void intmodulePxx1PulsesStart(); void intmodulePxx1SerialStart(); void extmodulePxx1PulsesStart(); From d2a4c79a7ab020cfe066bc8d69254fdca28d13a7 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Mon, 1 Jun 2020 12:50:30 +0200 Subject: [PATCH 15/93] Option "internalppm" removed from Companion. DIY people should be able to compile their firmware by themselves. --- companion/src/firmwares/opentx/opentxinterface.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/companion/src/firmwares/opentx/opentxinterface.cpp b/companion/src/firmwares/opentx/opentxinterface.cpp index 150352da8..2fed78ab4 100644 --- a/companion/src/firmwares/opentx/opentxinterface.cpp +++ b/companion/src/firmwares/opentx/opentxinterface.cpp @@ -1218,11 +1218,6 @@ void addOpenTxTaranisOptions(OpenTxFirmware * firmware) addOpenTxFontOptions(firmware); } -void addPPMInternalModuleHack(OpenTxFirmware * firmware) -{ - firmware->addOption("internalppm", Firmware::tr("Support for PPM internal module hack")); -} - void addOpenTxArm9xOptions(OpenTxFirmware * firmware, bool dblkeys = true) { addOpenTxCommonOptions(firmware); @@ -1249,7 +1244,6 @@ void registerOpenTxFirmwares() firmware = new OpenTxFirmware("opentx-x9d+", Firmware::tr("FrSky Taranis X9D+"), BOARD_TARANIS_X9DP); firmware->addOption("noras", Firmware::tr("Disable RAS (SWR)")); addOpenTxTaranisOptions(firmware); - addPPMInternalModuleHack(firmware); registerOpenTxFirmware(firmware); addOpenTxRfOptions(firmware, EU + FLEX); @@ -1264,7 +1258,6 @@ void registerOpenTxFirmwares() firmware->addOption("noras", Firmware::tr("Disable RAS (SWR)")); firmware->addOption("haptic", Firmware::tr("Haptic module installed")); addOpenTxTaranisOptions(firmware); - addPPMInternalModuleHack(firmware); registerOpenTxFirmware(firmware); addOpenTxRfOptions(firmware, EU + FLEX); @@ -1273,7 +1266,6 @@ void registerOpenTxFirmwares() firmware->addOption("shutdownconfirm", Firmware::tr("Confirmation before radio shutdown")); firmware->addOption("horussticks", Firmware::tr("Horus gimbals installed (Hall sensors)")); addOpenTxTaranisOptions(firmware); - addPPMInternalModuleHack(firmware); registerOpenTxFirmware(firmware); addOpenTxRfOptions(firmware, EU + FLEX); From f6ddfb759733f7120acfc77d355e0d8ec207e79d Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Mon, 1 Jun 2020 15:24:04 +0200 Subject: [PATCH 16/93] 9XR-PRO navigation fixes --- radio/src/gui/128x64/model_setup.cpp | 30 +++++++++++++--------------- radio/src/gui/212x64/lcd.h | 6 +++--- radio/src/gui/gui_common.h | 1 + 3 files changed, 18 insertions(+), 19 deletions(-) diff --git a/radio/src/gui/128x64/model_setup.cpp b/radio/src/gui/128x64/model_setup.cpp index 4c7e72e9d..5ced958d3 100644 --- a/radio/src/gui/128x64/model_setup.cpp +++ b/radio/src/gui/128x64/model_setup.cpp @@ -116,8 +116,6 @@ enum MenuModelSetupItems { #if defined(MULTIMODULE) ITEM_MODEL_SETUP_EXTERNAL_MODULE_PROTOCOL, ITEM_MODEL_SETUP_EXTERNAL_MODULE_SUBTYPE, -#endif -#if defined(MULTIMODULE) ITEM_MODEL_SETUP_EXTERNAL_MODULE_STATUS, ITEM_MODEL_SETUP_EXTERNAL_MODULE_SYNCSTATUS, #endif @@ -406,13 +404,14 @@ void menuModelSetup(event_t event) NUM_STICKS+NUM_POTS+NUM_SLIDERS-1, // Center beeps 0, // Global functions - LABEL(ExternalModule), + LABEL(ExternalModule), MODULE_TYPE_ROWS(EXTERNAL_MODULE), MULTIMODULE_SUBTYPE_ROWS(EXTERNAL_MODULE) MULTIMODULE_STATUS_ROWS(EXTERNAL_MODULE) MODULE_CHANNELS_ROWS(EXTERNAL_MODULE), IF_NOT_ACCESS_MODULE_RF(EXTERNAL_MODULE, MODULE_BIND_ROWS(EXTERNAL_MODULE)), // line reused for PPM: PPM settings IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 0), // RxNum + 0, // Output type (OpenDrain / PushPull) MODULE_POWER_ROW(EXTERNAL_MODULE), IF_NOT_PXX2_MODULE(EXTERNAL_MODULE, MODULE_OPTION_ROW(EXTERNAL_MODULE)), MULTIMODULE_MODULE_ROWS(EXTERNAL_MODULE) @@ -732,24 +731,24 @@ void menuModelSetup(event_t event) } } - for (uint8_t i=0; i>= 2; + c = '0' + (states & 0x03); + states >>= 2u; } else { if ((states & 0x01) && swactive) - attr = INVERS; + swattr = INVERS; c = *(STR_VSWITCHES - 2 + 9 + (3*(i+1))); - states >>= 1; + states >>= 1u; } if (attr && (menuHorizontalPosition == i)) { - attr = BLINK | INVERS; + swattr = BLINK | INVERS; } - lcdDrawChar(MODEL_SETUP_2ND_COLUMN+i*FW, y, (swactive) ? c : '-', attr); + lcdDrawChar(MODEL_SETUP_2ND_COLUMN+i*FW, y, swactive ? c : '-', swattr); lcdDrawText(MODEL_SETUP_2ND_COLUMN+(NUM_SWITCHES*FW), y, "<]", (menuHorizontalPosition == NUM_SWITCHES-1 && !NO_HIGHLIGHT()) ? attr : 0); } #endif @@ -807,10 +806,9 @@ void menuModelSetup(event_t event) case ITEM_MODEL_SETUP_BEEP_CENTER: lcdDrawTextAlignedLeft(y, STR_BEEPCTR); - for (uint8_t i=0; i Date: Mon, 1 Jun 2020 15:33:59 +0200 Subject: [PATCH 17/93] 9XR-PRO Extra module broken --- radio/src/pulses/pulses.h | 1 + radio/src/targets/sky9x/board.h | 3 +++ 2 files changed, 4 insertions(+) diff --git a/radio/src/pulses/pulses.h b/radio/src/pulses/pulses.h index eba14a463..3b3fffca5 100644 --- a/radio/src/pulses/pulses.h +++ b/radio/src/pulses/pulses.h @@ -338,6 +338,7 @@ void extmodulePxx1SerialStart(); void extmodulePpmStart(); void intmoduleStop(); void extmoduleStop(); +void extramodulePpmStart(); inline void startPulses() { diff --git a/radio/src/targets/sky9x/board.h b/radio/src/targets/sky9x/board.h index 952e48282..4a8587194 100644 --- a/radio/src/targets/sky9x/board.h +++ b/radio/src/targets/sky9x/board.h @@ -410,4 +410,7 @@ bool telemetrySecondPortReceive(uint8_t & data); extern const uint8_t BootCode[]; +// Pulses driver +#define HARDWARE_EXTRA_MODULE + #endif // _BOARD_SKY9X_H_ From 36839dd417c66a1db4fd37e0fbc76c17b6b0379b Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Mon, 1 Jun 2020 16:02:20 +0200 Subject: [PATCH 18/93] [Horus] Gauge percent was not vertically centered --- radio/src/gui/480x272/widgets/gauge.cpp | 6 +++--- radio/src/gui/480x272/widgets/modelbmp.cpp | 2 +- radio/src/gui/480x272/widgets/outputs.cpp | 2 +- radio/src/gui/480x272/widgets/text.cpp | 2 +- radio/src/gui/480x272/widgets/timer.cpp | 2 +- radio/src/gui/480x272/widgets/value.cpp | 2 +- radio/src/lua/widgets.cpp | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/radio/src/gui/480x272/widgets/gauge.cpp b/radio/src/gui/480x272/widgets/gauge.cpp index 099920abc..2558f8319 100644 --- a/radio/src/gui/480x272/widgets/gauge.cpp +++ b/radio/src/gui/480x272/widgets/gauge.cpp @@ -28,7 +28,7 @@ class GaugeWidget: public Widget { } - virtual void refresh(); + void refresh() override; static const ZoneOption options[]; }; @@ -38,7 +38,7 @@ const ZoneOption GaugeWidget::options[] = { { 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) }, - { NULL, ZoneOption::Bool } + { nullptr, ZoneOption::Bool } }; void GaugeWidget::refresh() @@ -64,7 +64,7 @@ void GaugeWidget::refresh() // Gauge lcdSetColor(color); lcdDrawSolidFilledRect(zone.x, zone.y + 16, zone.w, 16, TEXT_INVERTED_COLOR); - lcdDrawNumber(zone.x+zone.w/2, zone.y + 17, percent, SMLSIZE | CUSTOM_COLOR | CENTERED, 0, NULL, "%"); + lcdDrawNumber(zone.x + zone.w/2, zone.y + 16, percent, SMLSIZE | CUSTOM_COLOR | CENTERED, 0, nullptr, "%"); lcd->invertRect(zone.x + w, zone.y + 16, zone.w - w, 16, CUSTOM_COLOR); } diff --git a/radio/src/gui/480x272/widgets/modelbmp.cpp b/radio/src/gui/480x272/widgets/modelbmp.cpp index 131d59b2b..09e632ab3 100644 --- a/radio/src/gui/480x272/widgets/modelbmp.cpp +++ b/radio/src/gui/480x272/widgets/modelbmp.cpp @@ -63,7 +63,7 @@ class ModelBitmapWidget: public Widget } } - virtual void refresh() + void refresh() override { uint32_t new_hash = hash(g_model.header.bitmap, sizeof(g_model.header.bitmap)); new_hash ^= hash(g_model.header.name, sizeof(g_model.header.name)); diff --git a/radio/src/gui/480x272/widgets/outputs.cpp b/radio/src/gui/480x272/widgets/outputs.cpp index 0628b5faa..467657519 100644 --- a/radio/src/gui/480x272/widgets/outputs.cpp +++ b/radio/src/gui/480x272/widgets/outputs.cpp @@ -33,7 +33,7 @@ class OutputsWidget: public Widget { } - virtual void refresh(); + void refresh() override; uint8_t drawChannels(const uint16_t & x, const uint16_t & y, const uint16_t & w, const uint16_t & h, const uint8_t & firstChan, const bool & bg_shown, const uint16_t & bg_color) { diff --git a/radio/src/gui/480x272/widgets/text.cpp b/radio/src/gui/480x272/widgets/text.cpp index ce18b7b26..f297798eb 100644 --- a/radio/src/gui/480x272/widgets/text.cpp +++ b/radio/src/gui/480x272/widgets/text.cpp @@ -30,7 +30,7 @@ class TextWidget: public Widget { } - virtual void refresh(); + void refresh() override; static const ZoneOption options[]; }; diff --git a/radio/src/gui/480x272/widgets/timer.cpp b/radio/src/gui/480x272/widgets/timer.cpp index 424db91e7..58c53c4d4 100644 --- a/radio/src/gui/480x272/widgets/timer.cpp +++ b/radio/src/gui/480x272/widgets/timer.cpp @@ -28,7 +28,7 @@ class TimerWidget: public Widget { } - virtual void refresh(); + void refresh() override; static const ZoneOption options[]; }; diff --git a/radio/src/gui/480x272/widgets/value.cpp b/radio/src/gui/480x272/widgets/value.cpp index 96fc885db..c7fe6ce99 100644 --- a/radio/src/gui/480x272/widgets/value.cpp +++ b/radio/src/gui/480x272/widgets/value.cpp @@ -28,7 +28,7 @@ class ValueWidget: public Widget { } - virtual void refresh(); + void refresh() override; static const ZoneOption options[]; }; diff --git a/radio/src/lua/widgets.cpp b/radio/src/lua/widgets.cpp index 165d95eff..4ab6b967e 100644 --- a/radio/src/lua/widgets.cpp +++ b/radio/src/lua/widgets.cpp @@ -265,7 +265,7 @@ class LuaWidget: public Widget virtual void update(); - virtual void refresh(); + void refresh() override; virtual void background(); From d2345aa3fe813ead7e2554ea0c97ce3c34c314be Mon Sep 17 00:00:00 2001 From: 3djc Date: Mon, 1 Jun 2020 16:03:59 +0200 Subject: [PATCH 19/93] Fix std font 1px vertical shift --- radio/src/fonts/480x272/CMakeLists.txt | 2 +- radio/src/fonts/480x272/font_stdsize.png | Bin 22725 -> 22533 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/radio/src/fonts/480x272/CMakeLists.txt b/radio/src/fonts/480x272/CMakeLists.txt index 61ace50ce..a8b57384e 100644 --- a/radio/src/fonts/480x272/CMakeLists.txt +++ b/radio/src/fonts/480x272/CMakeLists.txt @@ -12,7 +12,7 @@ set(FONT_OFFSET 1) add_truetype_font_target(480x272 tinsize ${FONT} 9 0) add_truetype_font_target(480x272 smlsize ${FONT} 13 0) -add_truetype_font_target(480x272 stdsize ${FONT} 16 0) +add_truetype_font_target(480x272 stdsize ${FONT} 16 1) add_truetype_font_target(480x272 stdsizebold ${FONT_BOLD} 16 1) add_truetype_font_target(480x272 midsize ${FONT} 24 0) add_truetype_font_target(480x272 dblsize ${FONT_BOLD} 32 0) diff --git a/radio/src/fonts/480x272/font_stdsize.png b/radio/src/fonts/480x272/font_stdsize.png index 4baafebab04bba97e18003f589693dd4dcfe21b6..afd1e98b5230abd370ac2c4a23eb003abe54624c 100644 GIT binary patch literal 22533 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 K-z&=^e)tD~WSThu literal 22725 zcmYJb2RxQ-{|9_o*)y`rh={E0nOVrDq7tG|MnYt-G80i*S*avtM51h2MMyVBMMEGE==Jq<%n1alNBEkRiWL8p zJ|M+SAXwed*U>z7_1`HrF3-F73`42H$<3G#YqDw{Hk0BPA~!q8 zm#WzuO0z@f%pJMhaE@IR#|#BE4~p#|Kgg$-B)hr!*yZ2sY}V8T4d0-ZjDM8uy~od- zIrA;(*RjkeUWC0m(M+6%Wsb2l|+LtPP=1ZBdj7%B(6{bb?)}|=ND_5?}57pIO{&6HA z;9pD25!Z`mX19up=4t}|R=9t==;HFVyE{~+rm*nc(2%;K;%b-rwycztV!(=+L=$hw zMs9w-rI}f&_tb}50=gA1UW`Z&)&y8uTE2Yzc)yTPOM81kRaKgk+E7h^lbzl0$Vkt? zz}tD7`}glZc<{je+pFs;@5eozy0V@R8sYXaUp7#kZ4`nPh$ z*O!q;H8s_LbNz~%S`FU*dQ?<^zkl%dR%YtN%Iw!yuU?sCsm9#6;qB`?@kQs>ty_dp zT>dULHmqBws$bHB3c&@JbFqoCiY9tldrTgy(t7G;eXMK758*FYS#c4&xbUJo%}@$vQ+v#Cz)bc~9OWVu5wdNm+`jNthG z-pNy^o)i_?96RwfZi{9g3R-{p=n4%Djr&k- zW_EVS#QV&~#zsmkr2q2c$B(HLhGO}s2-^yesHmyGyu37|e%gY6oBa6kbpE=AQLCI)SYEKc)_x0r^1u3b?nVFfMDK<8?-3-DC3hbIpPEHdgB_%c= zHQToLCh)3%{`k?`$H)ER#l4Sqv9r5exS*u0yqG~b^XnH49o_BZsLR={bFLrEG&LF6^34miZV%+3bUoA3RewW?e6YQ%-6$Sj*N+E$FfE18>C3= zQE=aFqCykShfkDz=T7E9haK%Y7cDG$b2KA-=D&AJl7;i(^Tu8KRoHgm6Fi2?$smKYk}YT~t_jVs!Mw>kD#8M;=l6 zMeOAF^U)#hmA34Ub%)*Do+T$IM?`3AX_0o(u?8d_T4C1mH}dnV%FR7nO#g5Un=gS| zK|)pa-n;R|ciQ8<(Km1MsQJsrFv-iweJeRjrcWJo>jUZ3+}z62(&-XA&GY9U;&a7w zEBK#k3?riyGQPJu(iHXkN2`H>0k7)S682A%STicBRO$0H`YzkY{6)2x$wee2EUX5tDIsdQGNtL`wMh`SX*YH6~#8sl2 za(kR{@_ju$*ISEh%*+m+YhyZa;DAKR*G=}Jx{%_hPoEYQwX~n(n%!<;&CSi-{P#Co z#_49gfvVr)SVIIQc9CPL)#uNjwWAn5eg3?I@VKA=yGUL^!Rh>Y5<(=yo+rh{2`UQW z;_>gsS>Cx`x+HnvK=0?zC(O8Nl7LRXd={thl~+b4c2B~{^)4K~25SN<>qbPJz8d9t9OK!l&ar;jD(1mC4gmvE1l^Q)@^Po7MB`0)IR6T2kxqoOFS z->`FXa&mFS8Yu^@m#3w15;P7UKL6>-@&0|n`6k&|k-K;9oGEu^u2TDj3&qL2o0wSg z{CVT-`van)ENpDeJlJ16au;vEe5o+_eq&)o+s|*Uu~Eyu^wLl*1!3Xq%}uf@@2RBw z_w99cDgDp&6`k?-_cs)>u(b`D|6cRP;@7WVdj$kGH#aZ0)`e`>`pllv*4Cz`rna!K z7!+!#sHpfSH#g_v;zIXpO3y1k^ZL=lhYt%1+Iw|)Sy|uMNgWE=GBjNL{af>^&Z$%W z!}VcPQ&W|yZf%`;td%agGxgrRdj|#vmL|GFwzt&UkDJQ759%fP zuP&TjUXF~6+-Gpt*~KL;CT41SIw~sa$6Rx3Yimaboo~;ZH#&s+zGB;vu7w2;+!=dX z4aMCIClr}zt!o3TqNAyN{z-Mkjk^0ye}4An!Jp|qG6E?nX-Qg|;m_WDlhQBvxFvsd znI6>CsL9J$*wzJ)j*jBuT>6Td#r5ke9z1^RTo=4~SL|f?=^ulGgS*+-9u^iJkdSb9 zb*=VWavb!PbstnLXX4~c!;b!%yLs9<|)v z3{G1cYyG6}-o7OeJbnavc%U^XUjCg|Rpqz6waHAbZ*07S5V*QPVsxs+F08y<_OtGr z?p*CN*49kqA|fKp%*<&rP7D=~$KR#&I+t&31d?kycBD3(lg^!HyWQV!MIdZ^$1Zud zh_&G_?m=JGOhWcw|AeQVDx*ntLE7Gj~@M;o;C;) z;f!iJ`N~_QxkC_j-o?emqT^m#+68xa2?>c>$4)NMwe|y5xIq^A#<}VWZUg8Q5uG_j zMaG`5o;`bp{dDId)mn4fp&*J(DH}m6&A+58@H(q^uztPtqs&<8k_9NL-}ev zU-;yS|GFB|8M?4hK@2SG| z^z^!?ysh`d#>Udn(vqBI^%`lUP*G92aN&Yba=T+0Jsll3U$lWH<8H;A+*}euVq#*d zyc?IRO;~wF1>UnOQzd0INuQRM78sx>Pq)~*YH_g2>rG2k(5|CcBpaLWL|pdtY2d#V zx8P5_ykSnI!9y_+&c1xi0$J*K&jx%;xO?SP1xh=V7#ib#J zR?@$7-%h{w5tlfg({i0pFEDTeJC&Kd>dN%4C%sy2e|ES1`cz0uL&HSg{{H>$#|vfU*(l+@;3SV z(W6IbweDY@KP)LRJ$;(n?Ze%>yYN<5ra!9%Z&=|wpJ_A`fBm|+b7wMf$<+dgX9A$3 zQW<|rNl_6s#qPND?U@uCtEUS++qlZ|3fBC&3SU{yg)m5AjOSrc1kDwm11&kBR*LH(b1~|i` zVC+MNj&z>s1;0hrW9iYhbvt6>SUzH;00yc#@p|l22@zxoTb9yOK9~a= z01GaclP@MjZv^q>_U%139Mjp^85S0X%2IgZS>wfz+c#z&S~dQiADZaO?s6<^YHW=D z+D3l2e%w>{=5A^N6+OMUh=|#V6D`4tHFvjF4G-bvvCg2-mJ%JLlwta(>r1zqO^M@xh}AGf z?@4YStZ+N+<5LkA7gt{H4OU=s>Ti^prKPZ>CRmaQ^%_ z;Ldbk@%)!EU2W~Aw{K~tJ(ip@0*&t}k`VNc9&P+~TO&CEkY-LX<=u6I(91%+gwW*V zo$|uQ?UO(t2kprRxl(W4V&>*PATB;TIvPG}P$Hg|k&%&_x?fWAlABvRmp8!w?99yA z__%`m;Of8mI$+H7PDg-fhJbI_*16ZwWR(O3$@`MszE;o^n0R=y?%cU^>(_+q`#Jhl5^B?&?C@+i4Hne`!R-G5RttnZi{92^MsAj~6O z@828mihJSz=i;hY&;7&R%9|(~&Sr)}GW+*aZ3S+w%O$tJd0UTNNkKv3P1v6OsxbJj z%Ke)%p&m@L$71=+O{RtpFfAX3SqahVoewxv{nR&*35OUfH#c7nLN1!5hNN>4Cu_APc`nM)(B; zmd4t5?%Ve;HI?IP_3PKC&CGtIA6Iq|2=W=?`}XbQ=hw{Z@$~Y#e1HY0)Ya7$mjr_C z*qJWp+|9Qu?mUS3#DwlW$HP-IGslh}-}nBJl8Q>UiZ8>Kq=<-;&x{o>Z?=B25H8;+ zQ(12R{{4!Iiu?CFe|~xrpCB8EO>_tt&8Z`mL^#^Z%WHgWj6gtpLtFm#!le%tQ5bC7 z<+Ir1@cTl%jEszx?+N=PBpCM4-={o%>J+vh9X-8_j7${69{OGTBFRQLMz>-+ad-^A<$Ah~<@ z?uip8CU2;dZ+trkE+8Z%6v@}tnW2E4a5;@%PEHQrQTlM_2La~NOS`%D!8))IrE$IjMN;b=YeUs_gI zukPHrbLO$maP-TvG7A$E$%6-(H51#~^tidXU4H@(3MHrAyLT@m!^O#|^-`Am+Tu70 zrd1xp+s5m(XqM51mAEUB^xS}}*Ja!)%F8QXy+WJ+@n{Ro=aRcSi1GT$?CH_t_%#rj zx4r2f1_xao9JKG<81|)US1AMJmd~hh>65T$3Fkw5d{I&HbISZtUYq z)vnEjkqDeVA0uj$oGq{Itsny7*BuI<*WmqJ(&wn2oJ~sbZTsVNtuZyu`Y`+BVw#Uv z&Dzv?vxImT!@e_e{@h?nW?aj;^LBsa+gXh+^*?|9n3j*f!DR~x!3CMMk9~dE9g8vn$y8S4nphFEXtOi41{xam*Qj@1%>n^e zzPezSMN83^k-7eqwQF80r+p$STEtUH()6fBnorJ$6HLLR*X*fZ`_5Oqd|CYL*`I}l zVa{i<)z?tOu3Y&8vg_JkqG@g}4NZjoipFY)4(Sjji@&%QMHUAe8#p0$m;-?R@vbe- zF9xO8#7|c!s;KmR{;aH`g3b6We;@d#jx98{+TiiGM2M}(R@k?g9o632)y4Qa*7U@Q ziqg^^;PjU)zi_0*b`_SDmEnjUJxViuNK#Nx$Hatjb_Wh$y zn<{+u-@iP0{@W_Pa|FV0=md5!Ar$|TQvl2iNHy7Y^CkmBR78fN`-KY)hda{`Iz-;P zH+WmbVz|15*iC$?3yO=?edl&Jj|Y#*%F6@!IK1Sf=afFTJlQj8A}J{e$hw@5hVby= zI4TU7&}E_QSFe-_gq2P&4-buTM+1X6P?nYND7t|`L6`rmL7~E4j))+8KL!HGNT~Fl zV(EJQxTwgn>e`e+`wQO6cvIK-<-Ij-=bhd!@}?1rDbITy9~-tPfkypq{~uo zRzbNS5PUQiTX{nWgl?%jl`J4?>wo7HxL?zh-%Nbq{=J&hG7N}?D?W0TBlt=C1T+${ zU9`egj|W-3KZSp7O3BEeB@BBgDkd`ymfrmI(&K0g)D!}tKj>Pwb0%7_`NNJ5LjqyI z((TLh>qqi(wJpdsC2XprgVL!agPb9Ap}0+&pt7o~t1mn0>PFSpZb6!giRXjj=@opp zS{NPegoQ;@K@7LNYfg`IiT1c>6=2C^`ke3lcM<}$1k<$*=$!<@t9{deGPs{UK0c-c z0avfKwYLXttTKxSHiT2)XiT=gfHbR|X>;Plk*7-Ge1Kd~FTvwmRs!(>!uhl#=|+^A zLuJ;g1J{y_^Sd$>5-Rs^>HhA@2t?B-A$VNhb9miKKet`id2!9j+1YvF@81cf%4TV| zfpVUj?K&aBtyUmWx|ajC)mML`gQG(Bms&$>0zpxx*vZa5@$={BfdMX7R&w9XGOMRw z%A72Z9|yNZ|Ddh8S5~$JoCU;DU0sd)S!7%H9mMa%37^Ssen>dBwzgT*+0v-)^xTmu ztLVPiv!BD7?Qab-g!5hcUfuKY})yGes0FON>C?Fx=%~mB-z2$A8Sd)h82E9?E?fqscJN?i9CS@QcVHQLq|s&HtDK-2arZ=qr+ zXBw+%t)lssmzU!$$(1>w8bsrg?;no)@Zm#xMh4>^Wgtplrg785W;~ME>Ll- z=x6)FtpDwcifuW}@aOPN)dq%JsQ;9N(ARITZ5+_poWLEoN?1{SeP%H?Ok?xpaH>I0 z?9J=>wMWfl?;{6`rHY^gBt8yVGH{;}g;>zHTN_3PKWcd{M@ zBwYRd11eK==LZYp>_g8WTRAw8g?LsCLU4OsS((F$S~46(9)gB^_x5c7eI_!qaujOo zD$kFP%_f;Et0}g+?4%(3$b0=Xls#@}`1IjJ3QIj5oof&%G&BfvSB;G52?XUzK2Pj6 zB_*Yq@T0+lwLz~TlR(&*yj4*l|I|ePl;)O}6SK2w_;!E6a_mGrny;MOsvSd zij?ul;luDtNC}YDoMjBr(o$S(Y-9V<%F4=hT6R$&U=b1Y1mljxvK>I}hfB4wu~9OV z6B`Sw#}KTtE0%;1{BKqP1rs_(P*6}MDQ$qexA!v68GJo9R@S=`X9m7~i+|+f>kHUo z4Iu!;hgUrqT>`bY--}($O3HIg56pOR(evs8dJ2#k(Wba{3-9Q+FifIa^!PDsJ6A&J zy?fSnc6_S)4;*-X@sntIJzT9u@qR)mBujB|aoK|E>U&4>&O14g5$@;ZjqFyyB2lQ( z66!}h?9#9yWVz_)sCN+Fw6YoS$idAGg+3-ax;o&m@#)hlYHGke z^Fy^kP3sl4!JGcZ#_#bL{Em2Ys0UZ$^8)IV5Wra6+}&G5o8;x?p|}C)T!lf2VipHQ(5P zK;ealSVSHi-(H*_y5J&fpRc{QRDVo$@>B1auVm0vc>C#8)jRoHJ2^P6j`F zz!bLbWzuRLnseV_q@dXR_OJ+7AiN6fn6sl)d-Iq&=>xs;a2) z`CjeU(9i&V6*UQJ2flb5QHNVXM!4!8rMne74!uk!WNQOl9tvsjw6dD2YEGXkgu<+> zx29U!+I|w_Xo9i?!fO{IUIaF9`TP`;?Hjj*?sf+r$zn~l^C*G+&kRiK&u+45&EDm( zY-(?h$v4rzJvZkLwP5r+6}cv=(chUb0(_@cvAw;WgrL!P zQCeCWWVUsk?6RjPX!+9b-?z~HEUxP0UrVIkDKxBlY3AE&OGCq%#qoDIk7;RXXeEyw z6cotN^XJ{%W^r&?TzEJ+;ivtEUHa_wOCb2g z<;r-zHq@R;Z)Nwd`x;$Rx}e6T8VX%jBJ)XMT-GJ0xCvpQ{_j0r?1i(XRwy9VUK2O# z>eM3|>LvQeJQUF*k-o4jwmDPdFPCZD+S2#s)s+Jg4N%#--n~1GZ^j?dR{QDp?bV$l zd7y2?9}^XgHO_bNU4t^&<6J&DIf;IAvdl3iHdc%B321fqpy%RPI|yod0a_l$}9UTdzE(IOii_d z(gSF$qeD)phcW*3s|vac6i_Ikrxl}`!VVqwJ23+@XW&1&)EG(oi z9RPi?T0h>rfOC8Ka+dya*LrQ4+%*a*i0H2@V9 zRV1p3gn+n8qT&v#+Q7BD;-|r^+s8ezH()CuOA*&u@5LIKl$shHyhXKL6s8(e&Hkgx zBKg6R)_&)@G0O+{FH_&%9`k32iH^+IK51!dD=8qL{Zw7wVR2fdjXS=7DpAjsMM<*6 zEyg5y%x3)qMe<82KhdhKh=nO1W=(Cfu=TR~gDDzpd#-2K#+r6tr3gM$(?7nX9jT-q zn8MiT(jBYy{GIObY+~Ijz3lU>ei6xm7H^z%Hw3q@kmv=^j}?ruY40yry+brp{_8v} z`o@csF|PyH_u8#pkrmt%Rd1#-pS~xq{>&j*zj3?78~rXdWqtKMcsMBQn$A($j&5C& z#i9M0!~ZlEA1$h*2w!ctv2n0|u)yZ47N5R5)0QB; z1_8Eb%G*`;J;E6af4_M^|0E;WeL5Mfk=%82kBXJpXHeo8mG_QiBYJETNze20n&3R& zoRCPFRSEllni_NiYa4v~p*J9+!7|({Og-zyJBtAi>FA?Da#)!D(Sz#7eYr1`#_29u$U|zU^ zJBjWcNF*<1_*ddmoeRwm=7*QAq5-%aYTbrhWtSex|thngWZs! zJH|aB8~>gC+BYyDDkS9d=hty^O+a=JnGscC6{cqpP3|MXJ< zFoVMhE#r;;#rw>pnu%yS0e*fX4E9Ec*d?r)*x92JB-PZ;pgiYL@?_zZ<&?T15u$VW z@JrV(;g38OcRwv`0qD$KLK<)ufWa!o8P;CZO$j)~cW&P%cF70z^%~x9Bi@ZeFu{p$ z%KrB48wjEE)d%9$BrJ2 zd)MxK*G;doJA-tFtymdHOD zF*iAx2*~p@79e!bo;}cY6z2mMhBdL@%5xDpM2&{wqySL{H_H1ARiIbS=JUcr0~;G2 z_N&y-UB5_UOF-hYXQ5Wz^BQ;PnN_KlrDflnH{{%H=~NOv6mLNm$d%29s=V@1hVd^s zN=|cwRk+7G+lx%Ugt8&f6a5;sVE~@)2lU+XAa$lU-o`nAPyw=8r6Cr>(8;*qxiR=w z8?xlY^mG6sQO$AeJ1vMN0D}SU1j>D3VWH(ytK6cZU?e)g0ZyMjEkN~QVBpv2=>39% zn3~=4Cw!m~*3<-fd&|-({rK^t7jdEsy^k8Y1SKTiBgvxTh~x7N+x)ZC32SQz`vUv+ zQOMl~$47y{+tvC1p*ih@EYc+VG$5_XHp4ReDGQ6dCr@Z(@`QNXu;q5|-i?f1Nl~tu zX|jp4^ZpZDeAV`A2!q)hT_&Ov)bCP<){?)@&|jQB;K1XRt2*LYb>PI)oZcy^=X`fF zReXaXJ5n`vbUc0aD%~oCT+`gb0+xGGUS2PPJ@@YImPm=C?WNhD5vccS$D&O{HM_vg zSbb&5XpPyFvDjm>5~7RSQK^AB0XFw2QmPNG{b3!8Zz=25Y|wZ0R2s_5*AFK0iU7Ao z{=N{?RV5z*&iTaYu466Mq{qFfV*cL>uWEE?jI4%Nx?_z~i1(V5^I?94wZuV&y?W0M zuM6cdeb^zq{fOLHWs8P1apSwbImHRO-0nrvCDXt&?eq8h#5MM|xAO+UaDb4742^Qc zM|KheX+ceXvp;@9w-i*GPl^N&9S#gsU7ka(A~YjiyK9r*K6X@)Z7HpF?Ca- z&}Ka`^@3{i&iVObQ_>HVYm)t?-0Bd}bCc7c(XTRAT-zyZ3>uHpi1=we_T3S_dZO!w zoWzpX^f4{Ss+=kV7;Sz1&ouVe%pNjy*Z+L2 zaBF(SIkSfEoFNj^xyS0|K0xofVgq?CKio`|!}9v!ml@M_RyYM-T5`$A^FV>{ zIJv*nw8+-h7Wl;0)}{)94+7d)+bv`UoSy(ZA;}Bc0d-zIcta7Q4J_D8mqLED#3O5n zurmD~WmZc&)PZ~ZH`f0g`0a_`Gq@|JkF2G$vlS>rmniaP>Y%G~a(CL#nO9v$Ie}aQ zew$_+iGvRQt9ePBgoFgpPA4ku7~--zyopdsu$b=J%AcJ)Qfb8=nN3@0on> z(KpnU(`(2O5Dh^jX49{+DMGM#R#2dMhetUR6+3!~Ct@5wfH&>`V9NewjDrqLQ<+4#BJrQ!u!8BoBKZ zdKwR50c{m(^|Ay9T_mCe)@`0JR}VV0+~85;TKR~dLZri48^LKvRhI_Jrx5je?K2CQ z8{P^swz;t}{2>-Qdwt#iV}`_Ae6*b`ED&Pt&Ylh9amDpZoejs9M;Uo?{hY4d z@QK+G$Pv!RolRP;!XAHKTFM{%4J&oU+k5Qqr#vz1$_0>B=sOD&ke(KomU=!<%4NvA zt#7QAfjVXyQxbA+CJ_j@qnuK9p@oGmCT9*sUcWvIJs6QJt2DIADR1SB&RQfIV6U4A zm#Utu3l1_gyir_y3Bnp(Z!|H03o1Ah2idmXu?*o$#D5nccAagC{4+najf_4x$J>sM zbEQ^gj-8D*423&nIBwv-W~v43lBgGzkT`_kEEF=3xqFF;9@v~Xfc?@;pzTPpR2tF{ zJbsT7AZXrw}%)?4p!#3AI$%Qh8iwYCl1BP+EF%WhMB}FSa5P z4_6#f1W5V?dU|@W&M?!jsiT8z;YO~~T&@}f+<}D!{S;IM9p5NRmGiBevj-^w3ig9n zuee@uPW2TJwZwBnB`+DJ`q0ypo09`8b;qZC$fkI~1;sVw=j05-k%6IBga0E&1^`v^ zeHPX%WJyFpvHCy9#=P+{fX@5>K^eF;C_*iGhRm;+zl6O>^Mjuz`NcXx@Dwq#Tifd7 zAhANp)SKoxi3&n>Sz2~^%qn}R%5js){pnR|DyUe@XCFK%kL{XAd4+GbTlOheHAXp{aZA z4A9O-%%2yO$cfV_|E90eUKm49ftA$E6V{}v*hv!>nao4Kjdz`b&4G*=x(u@gw0KC9 zKC=Vkb92Om=hX#BTHw_~kX7WDnW?3AaLK1L%d5uV*dQGE{+Scl|HX^HupLT^=~Lbj zkq*Ab>6{xLF7X_Ho0!P-w7~A)$}B?TkTQUw;a$>GQSr?S@I zuN5WHadC`Xvd*AF=+%Xm#aYtlA@I`~CIQ_sGxKNv5;H*e0py)E))m4q~G$k@YU z0S5?z^FQnglywfz(20Hmq25jkHw-2GmD^YOnalf`N=}?@11d$#@pF^P00VNJg-C&b zD0zEd)0gt6@8N=ei0+rbHtx)iDmCg^<EZO`W25LR>) zI9dRdLGTuknaej!3pYAn_62zxyfI2^dTuU%`Dut|LzS1wB%~YD0xPYFM-`T`k)h!( zF{^s7P(&l`g_4!dzhyA4IZisFg56A-q?~I05Pf8ohyE_D!t}MWO3lj3Lab@# zkDj#lVcwr%b5o^f<6%df75+2QM7hxCNxs)ZZ+Ln-&PNuNMAhwrGrj)NAJlbImchFZ z1zMdvS%saMultWjGx&lm+jmwU3GVNF>gQQ2WL&NKL)9)a5$e%H&~t09OrO9?Kq2Gk zeeG+QE<1(!5yZ<-?vjv5lph#`STigX@${*f2{JyCl9Mrtzzj`IWT)GpYUV~9x)=8= zG&B?d51eBHHwBI>IAH%rZ<5DjevBn~YO%np(<4p>R9sRssF zh(#BG2%$>sFJd89@)bj^#Aib!q@NSgSuE6Pn3(SUC1KUg^|qzl{IFyGjVx0*=R*5# z*yB`c1%^3U@QL!S&##Xn<zpP=D*8?4=0zq-tUyz{VZ`>#mb;sSq zs7hhsG|alQJE23uB0-abDOgutzKrD&OzG|J#sJ7c1qB2Z{6SV;y!eCcAnGmL%FFOD zMirpDG5lqQGJtgQUr5ZvvxPVTej6T@HI6DoG9I3rDztKI3lYZoOLQws2+G;o4uQSE zGrL83{&q@=@TuoOM?D1|aI6r|fsBU4Gjaj-;)lT1Al4(yigiK43t}L8Z@6PFpd~KU z*1}>5y9oCS6Ad+}BydzCU!-B?fSi)Dcgh<Zy{NK{~kQqoePlxC>!~b zvKKGpq@}g854*b;m6l#MHBE#}{_4uK_mwM{-NA@ZeCE$NivJo%Po523qK{2z`ig<) zVNotilkt#ZR0xd5m>3(Qs!Bh3^`f8=zHt%Y}f9(VDg^#_xJLeYpt0bARdLNbTwq%aSzYJ2E<| zWtN1f@8LrxdrglfJ59bOtTEo^TL@x$yhIeVp8qFkNiIlb({amp^!6qXQDaM@eh{Zg zkZJ+{1HgmKVO>EsJpc}KwrPi~=<}EueQ$4X%*!mhMw(k&2V&RCxqOCtQwCiY92HYn znTV_#2H`)ziEL_WI;^7uvu>A!H3tjJa~Ncb;rl)xH8;ooj=#Fw-Ee1R&;umbpxfiM z(4rg9MG?ZH-GGk7wn?F$`J$v`fe6opjo-Y${E(v09%AwBca^{MOgs_N5CGpmON%2a zXa5iEAk5q}aV3k1i;o=jBGe=Gj-876K^pZ098FRp!@{-LMPh&1sb7Fg>pFrDX;nsZ z??%0N-SwM4ojTL6tF1z*g~4jyc^F}vBEVp>JBZg3Y4Y0QL)1CcZ)`q~I5s7~a~K5J zbw*eefB#p=Wy#B@U{lS`BiX$JnaL|~xYsM(z9Q&_;!c@2b-w__2<5a}J5D2~`vwer z%dq0?`ou*r02Iq^Yt8&#FcC1$%YHzp!&`^4>e)ueL@BQ9pywhNFd+~yJAqUdUeON6 z?k!yL@Zg)1B0}9t|39KDdKlG_xc3}K1O+2Hx($F7ebP*Z<4VqeEb^Qvy2uUiph6lL zyzA_wPkb+ejpPmDgC41vF^=iRTwPr;eEgP{r(~%PCo(x zUDmy+Ah8K=v}yj849z*7H2xdGZF4l$wPtf^82`gk~^yzL^?d-1Xa`mJ91 zzCdQEuP@R_5GeY6t-74I5ttdc4^;MNSN8T&Q8)!xSIOz{oGp!eE7$EhRTm`N8KkmG zzRZBI!q~ty(s4-Dx3)%|)1+TZ`b3OnOiu$LACi&r0+H#L`1I}DCLjy&*4oN!25L)G zR4cYBj6Ncn1?9A({qp=gZKiQ?VPR9+fk-;e`^ClC@aRDxM|Wi}EG$4BLK1Z3L<>?d z`$R=AB7^}Jz(`A*A$uX|>C+i>bAao2^AgChuMRIvP>NXk^O5_(;d2eqF8RA%s<3u@M zxWK#=vc60$+K)bjaXC0hVcRh0@)6ykpa35j|M_$DwjW|k&OOu&40ktGOx2+Dz6q{^ z-ShF|?WU2jpFffIOdg~lgtnhsl;t{$O<4spRC2ZnNB5Co8fhjsdM?qY1#<*)!W<16 zcZ9+D>0iGv6iFN#VP^+~z2x8k6LuE*hqvIP!oq;H#q*VSOf@w}5J?6#B<7>R#Sw!z zAR^LkU&=wZLzI5_;{sR@oJ=@fIDV}+I4x{!=ElZuBeD+{4Lqjy+C||huC{=9oT!NKMs(QuF3AQjB=-w?*6Ny+<^Lj& zt=HA~-Y8fAFNFEAy2WmH15qSny{=wI=21jc z6ar*=S{l9xUSHM+V!;dXG8=%^=9U)wK3k&Pa3pU;tQ@ivVvd-EDth`9Gp#9i@A4p@ z50`?PeX8l9kCfI90uh0u*(!x>1rpOPDrU!zk6(zrCZnkuRQrbk`*FH%c;YIo2scPd zmH!_0PQh2}w&9-ua&v@C4H^Eg`<4@^Qz z0N#vP_apkiMFN1w@&uwfx8?2S^{%5sr}F}~=EaMy{3mG+vzdLSjZeRAL z|C<&fzvzFecZQ)sp!XrQmTB)&VnrZ(JIwod;ZkPZ51y_+`a0sZU9yd#4*DaZUUUxna-8JL9KN-Ucks5V=FrY-MJ zvD&-3?q+9y2{gyiU!5%QXf7>2V8xLcQ7r?wf0?Q`0e}AaJPU65M z4zfu1H1pk@oE)IpN*ylHBt(~4KHi82GAlm)QbJvwH^>QQ4*V+c#)!@x4!Rb_Ef|-E zQCzw*4*&~>Jt}5m@yM{fqeJ!b=rs(FmTrK8*ZTkYg$_6QJ_43IpjwvVWzv_;`ItDt zNGbpzRs=K1nTnU~0|NsSS{%XT5yBd*3sG;+xg`vC7=)nGjezasRis{Ut*CsLTwG`; zwo2|^p}J^INx*=|Nz|zK4^LTHVL0Y&Cu-*{(>EBNyA01HGWHCO9mWGOpbb0KM;6|( z;Lg_`oaA(?hGMf(Ifx@5YM7Md3AO8^(u7I#;Gi{dt$+ZTnkT?Apa3N$sBP9H>Lks-nx*Kq0PYtRV_uZ9NEnh({fqHaFM0&vhpy1wV~xMfSpp`mFKU;gdL zP{0_INzSJU;29)MCf_?KXVzl-fGOl~B2aghPHz>RYze&*V|D#nhk`fyzki1>fXc|j z%^fiQmMvJtm5F?6auQ?L1<#)0_~PD070d44`rToB>J-h3xY1GjW1V_PYtqrF25($7 zHD!uuAdVr^lL8sq?aA56A_hQm-SW-xMW}RO&mI(XY>dIE(%qw4S{fP}=gvKV)q<#x zmR2L6Ab2Pc6qXeF1NscQ4zLfE+!C}Uv_3q7LP1qE5c_&^fc-XL&`|I{`c092`(PDO zu>FICgf5FAdrV5;(Fq<^))+Jgj7M?Dq1R&nD)k@@5u*6`&c|kXZ{ECt(+`#gw%d3~ z;JF6ek0e3S8V-h}_i?c+2Nq&U!2C zd*RlST2Q*$ap4l-Bz4loT|)Z%;DJPclTbRgJi!xR6)mbf8Bt3!^=G(LciBHxV4>{3 zVy(s+f5eHbm)ebtx6A~W*E6)%d@1irXR$#}E`O_DxPN*V->oso(;gq5 z_a$W68zeF6>nSq?>#Js{iHK155%a{qXlr&_92=|FfYwG#R@Ir2GA$ok)|v=gJ}kc0 z_n&MuKd!FDCnJ+=Yjx!|FkF2}0E~zJMCU|6=I2&VVT)p{2Z3K4y0!IndztFs%>fXP zBXS9GaokFt=Nue}#@kA|I z^lQ8xW8JkYHYNt1^YBeX-*LFphE7697=W#@!MncozN16XF``Ry@7_`PfgV##-k)zE zb=8hP?Atvwgsla&kK3g#?BFP7$}uYz8F>WbtPn|;pOQvs?Zk5`cnJh<<2BSInBl-W zh~=mRuEHHs<>I2%Ohn8Er9(mCCBz!E6k@}NxIlX?_`=mlw}hKFF}JVcGXrZ7Q@e0& zZOa_#<(p6jh`J94haP72E`7gYgg8YL>Rri86CRaU^Te@RU_3;HNxifR`!VoWLJ3I( zDU_01>nMAs>?BAkci(vB(8?g&1i=8V^y5d5d@zxWQ0?r%3j-ouZKjBqzi~G)BO?I5 zC|WNY+Z_ZuXRef5YHH4hJBb;IVUk*GmkWNL7&3u?2A$=C>;SBk((#=JFuuuCHPZW2 zFJPym;yr))5`AL>)7l-Korr{Wmjt{a#Z|$5{q*TmDX&OZhL%IBgF)ySW<-`QowT)8 z=i>`~u;sx*b9x)J8^~49zyOPLrqbgq)E{sj%y>xsl54(;hbg>7divNgOelUuG5cI> zE4go<91;!t$NBpEOQ^yS792}e}{|oTz9ytQpPf12*r*f2`k{+JuH-A4V0H}pOdU7D!U7Pd=Dq_9I=b36y9oUL4=@q_`)_^*3m-lBgvc8o2e zrx{Cwhv#6R+HprjSWvvuZia}4e(;LrZ#wzC@R)l(;=nenr9&C)U+n+ce1=^!5!pvf zs)4i7vP;0FN9t6XgHCo~3a%gt0W4ioR8;G0Sf^wDqeqC{YKqh6Q#6#O0fLyF3EL9J z0N04gq_r%jD>GVAecRd|=jG)gy45sdN5K`&hstU?(Zut#u+ZYzv2vIq7pYh=d9S?k z1$~rtb5AhIFa8C;v)PR}J+hchaC0kN%-)UX6o6wa8X{jXfcA$Zvt8B!%Ob-J`S^VK zXuh^^3R<9Ylg(H?7nee8*YI#Hw0FWV`m1viG+?+)^GEUcgO+{q@O*-<^C1HPq6r2_ z=6{Z;JWjmdC!#JUMwh;miChVm2eMTdS*VwBLI4I6z~$8ZRL_CciLLf_HTox8wQB@u zz_`kGuhc@Er;0(oUO-*4M|(#{#o@aK!DKke@;wfD_+(*awPJoO7dS; zLA67rz0CVd{obzGs2U~tK9W2mYo6+3HpR`Vw*O=*8k6{x(cxPh zk+1T}YQEF|Z}i=iv;6)7H*xko$?|Vh+y2EJ!fTJnBbju!+=zk|>FLM^M3yot%vTaa z{<*AAJT&p>BIa^Ocs3C)I%^J-9^<|%wf^FE`u`O!E(kHG z?zX4*@3ZXM6&bvwgM*GqwlA&~#92r|jD=LdWk7l#N&_CV1xcNql@(+3V1@Sl$hhrf zV{>zLeY1y=nwmI>R>vMzZ{)EM>^J)3hs?!~`^$xZF#Cn0_90ejVv^8chbgtZsLeH(j{Z2C!Qg+l9xIsd&61xl6huF4u z5D;AE;(|Db0W4U9?tr&gl^H>mQ{i~>6Tmz2<(EIu2e7doYiDwPjNvvs^C1djK6r8v zp6rmE+za95^7!AjG3;JE$pwuVE)FJgVVjr*5b8*QQkxyip!S#qTTI?yEFwps5)$)r zz6LRPC3S@T6yhcWU%&P}J5AjB5)wuE`7c3BFtrml8;YlqC`n73W1UyQ?y{wl^P|KWKt;EPC>l`vL%jF5J@{N@(pr&`2-9ZD-2Jkmn^+L1`y{_gmR zTux3-y@|P|u3x`^)SH8!D{0w9hG+CWZ1m7SAz)ZoT0Ly$zxiaDRXQ>ST|A>{sY& zUtE2>yku6a@vIB*=yQ&anD*F0gp;V|&AuE0=*#-w<6h9woZZ9HkO;|#to N8M7m zrLe&8B)t&$xO-H5a^3}*CNn~xEVWW~VUQBSB%?Ybhm;+jZ3Kd%GZc@=0I1L7!oob0 zUCMfXII=14_SrtG^PRUD9EWX&)`u<)xxnzLp|7ukw`ui-ULibQr!yV5nIc8GfkUrf zj^xey&W5x=rmZt%`Ye8uExlt1&sOihi1@9}ehjG>Z0M3tDUI#rTCsrGQC3j_4HqQ~ zvl5kIjCC!7QzEN!T#bdjxqC}vJZqQR$WbVtzK< z*u3pp?fv`b;VXS-m3idmQQY73^uSh`pP)|97-{no*vBXpBwlr5k49?W=;tF6oo&~q z>|hy0e%wmwW(PGZrU8`JjJWC1KlqfX44gUm;Iy6w0&jNtA4LY#TsiO?@9uWXwQj43 zAc}JmTd+TjQjy#rt*<3hL3OMCRMfSMtgsls05IR15&HOkMZTCCxw+rDlYTC7qkYY@ zqxt!po5N8iY8E(KkB*B_DD0AQv$K5_it%1v7UK+Y-9h&elTrpI*4YlpduU98VY4gg zcn`2DRc^OE3n0*685tX^m_B_&tl<9TLI?B&FjDg!vJbqn#EfSK!j{cY%l5V90z; zZouxJFtAityF=tO-FasJ5c(6YfX{tZ_mt7HBu6Lj-=%ZLe?vL!HJmw7-kM@Ct*uY+ z90Xxt(lxS&Hw?qwe0)|Q42?N1DB1)|q=7+4aSITGmD|kn7PX#A?r&b3NWa9PUH80Y zCy8%=Q7om-&Jr>zr)+d^&|sY42d~4WnnqWOTg+x7?tsJktY;ksOV+47?%vj!fVvgs z=g%rxSqv-71BJFow!C51#-R?uK-Not+YtXN9%_E!%V@%6!fA8v$vqXIdQ-fe-68ws zTe#i|mO9K0m6ecdn-=&Upd}0o4c%@%A~mU)((uK_4Hp$SUA9R%-{)G%W?RcGB4!KH za_f>777CpQv*q$9RudFV0+;b@ZgqYA&m<1Gy9d$o-~p#MAgmDreSkCwr=)6=gG3@J zS^9V@v7!L?`g(fo8K$`mrzD0%!wr3$jvYlUhT6+L^rYBkBh;NBZGgw2!qXHp1#`b% z4m1o409X)|=_OYvN^!{nDV_T!c*=*D7Hge=?^hPW^Rdi>2dxaKZ(R?^B zT5<9fL&*GlXCEC;i~8GQi6Me9^bwN+0`dqsRjcJ;VK#}&8-)zJ_3IN@VQexXr*1Ga zBNCw&5qN{o+deY)P}aAh*owd2PtYr|)hS_!PBFSiM?|1k>IBK6w~+h$Tg(Y#WeCnQ zD|8J5mKk&xc>=?78Rd+gcihQAwsTJCulx^S2H{_hrjU8&_ z1?wl5s}XJJi@;^6BLuF1py^(IZ~RZ1tZWl>UtxHuAT#3O6QUI=NDbe1Xn+Ev>Mks2 zFWnJ#zlnw7@^{%rQd$L$F1Ym`M5`^h}@Qy88=nvWVvU~q^sw( zo_^hXva6>D?D5ixVSZ-fZtdG-;ssEtcM{i>013qe0t_ Date: Mon, 1 Jun 2020 19:31:59 +0200 Subject: [PATCH 20/93] Please Travis after font fixes --- radio/src/tests/fonts_480x272.png | Bin 14756 -> 14769 bytes radio/src/tests/primitives_480x272.png | Bin 5713 -> 5713 bytes radio/src/tests/transparency_480x272.png | Bin 5773 -> 5773 bytes tools/commit-tests.sh | 2 +- 4 files changed, 1 insertion(+), 1 deletion(-) diff --git a/radio/src/tests/fonts_480x272.png b/radio/src/tests/fonts_480x272.png index c47657715dbc91385107bdf63a0efa40b0e99c1a..abd3e1f72f3bee0adaa26f9c32958dd41613f8d5 100644 GIT binary patch literal 14769 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 literal 14756 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 F{|orobhH2f diff --git a/radio/src/tests/primitives_480x272.png b/radio/src/tests/primitives_480x272.png index 38630592fe2024e967443a5375067a711d97f717..68bb2f88655e889c9e3530c9de29d6945d1bcbcf 100644 GIT binary patch delta 4633 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 delta 4628 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 Dh>Dwr diff --git a/radio/src/tests/transparency_480x272.png b/radio/src/tests/transparency_480x272.png index 05845c138402682c768e71045185ae4b96e02ce0..2b0588eb91099c84eb5331edfa06082056dd42b4 100644 GIT binary patch delta 4865 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 delta 4886 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 SJ@+KUpMyQbuIk*4KmG;FFcd@p diff --git a/tools/commit-tests.sh b/tools/commit-tests.sh index a15b698e7..92b5542f0 100755 --- a/tools/commit-tests.sh +++ b/tools/commit-tests.sh @@ -5,7 +5,7 @@ set -e set -x # Allow variable core usage, default uses all cpu cores, to set 8 cores for example : commit-tests.sh -j8 -num_cpus=$(grep 'physical id' /proc/cpuinfo | sort -u | wc -l) +num_cpus=$(nproc) : "${CORES:=$num_cpus}" # Default build treats warnings as errors, set -Wno-error to override, e.g.: commit-tests.sh -Wno-error : "${WERROR:=1}" From fb6145267162012d7b10fc604368272d4a9c9c60 Mon Sep 17 00:00:00 2001 From: 3djc Date: Tue, 2 Jun 2020 07:57:41 +0200 Subject: [PATCH 21/93] Fix wrong mix order in quad wizard --- CMakeLists.txt | 2 +- radio/sdcard/taranis-x7/SCRIPTS/WIZARD/multi.lua | 4 ++-- radio/sdcard/taranis-x9/SCRIPTS/WIZARD/multi.lua | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e9bca79b0..e0e9d6bad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ set(VERSION_REVISION "8") 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 "0028") +set(SDCARD_REVISION "0029") set(SDCARD_VERSION ${VERSION_MAJOR}.${VERSION_MINOR}V${SDCARD_REVISION}) cmake_minimum_required(VERSION 2.8) diff --git a/radio/sdcard/taranis-x7/SCRIPTS/WIZARD/multi.lua b/radio/sdcard/taranis-x7/SCRIPTS/WIZARD/multi.lua index f4677ed4e..321b7324f 100755 --- a/radio/sdcard/taranis-x7/SCRIPTS/WIZARD/multi.lua +++ b/radio/sdcard/taranis-x7/SCRIPTS/WIZARD/multi.lua @@ -165,8 +165,8 @@ end -- Init function local function init() thrCH1 = defaultChannel(2) - rollCH1 = defaultChannel(0) - yawCH1 = defaultChannel(3) + rollCH1 = defaultChannel(3) + yawCH1 = defaultChannel(0) pitchCH1 = defaultChannel(1) local ver, radio, maj, minor, rev = getVersion() if string.match(radio, "x7") then diff --git a/radio/sdcard/taranis-x9/SCRIPTS/WIZARD/multi.lua b/radio/sdcard/taranis-x9/SCRIPTS/WIZARD/multi.lua index 3296626ad..c78b982a9 100644 --- a/radio/sdcard/taranis-x9/SCRIPTS/WIZARD/multi.lua +++ b/radio/sdcard/taranis-x9/SCRIPTS/WIZARD/multi.lua @@ -164,8 +164,8 @@ end -- Init function local function init() thrCH1 = defaultChannel(2) - rollCH1 = defaultChannel(0) - yawCH1 = defaultChannel(3) + rollCH1 = defaultChannel(3) + yawCH1 = defaultChannel(0) pitchCH1 = defaultChannel(1) local ver, radio, maj, minor, rev = getVersion() -- if string.match(radio, "x7") then From c8b31fc904a79198f72e5715ea2e7fd6282b6338 Mon Sep 17 00:00:00 2001 From: 3djc Date: Tue, 2 Jun 2020 09:16:41 +0200 Subject: [PATCH 22/93] Secure screen DMA transfers (#7657) Secure DMA write to LCD buffer --- radio/src/targets/horus/lcd_driver.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/radio/src/targets/horus/lcd_driver.cpp b/radio/src/targets/horus/lcd_driver.cpp index 110db0007..691dd28ce 100644 --- a/radio/src/targets/horus/lcd_driver.cpp +++ b/radio/src/targets/horus/lcd_driver.cpp @@ -41,6 +41,14 @@ uint32_t CurrentLayer = LCD_FIRST_LAYER; #define NRST_LOW() do { LCD_GPIO_NRST->BSRRH = LCD_GPIO_PIN_NRST; } while(0) #define NRST_HIGH() do { LCD_GPIO_NRST->BSRRL = LCD_GPIO_PIN_NRST; } while(0) +static inline bool coordsWithinScreen(coord_t x, coord_t y, coord_t w, coord_t h) +{ + if (x < 0 || y < 0 || (x + w) > LCD_W || (y + h) > LCD_H) + return false; + else + return true; +} + static void LCD_AF_GPIOConfig(void) { GPIO_InitTypeDef GPIO_InitStructure; @@ -383,6 +391,9 @@ void DMAFillRect(uint16_t * dest, uint16_t destw, uint16_t desth, uint16_t x, ui y = desth - (y + h); #endif + if (dest == displayBuf && !coordsWithinScreen(x, y, w, h)) + return; + DMA2D_DeInit(); DMA2D_InitTypeDef DMA2D_InitStruct; @@ -414,6 +425,9 @@ void DMACopyBitmap(uint16_t * dest, uint16_t destw, uint16_t desth, uint16_t x, srcy = srch - (srcy + h); #endif + if (dest == displayBuf && !coordsWithinScreen(x, y, w, h)) + return; + DMA2D_DeInit(); DMA2D_InitTypeDef DMA2D_InitStruct; @@ -454,6 +468,9 @@ void DMACopyAlphaBitmap(uint16_t * dest, uint16_t destw, uint16_t desth, uint16_ srcy = srch - (srcy + h); #endif + if (dest == displayBuf && !coordsWithinScreen(x, y, w, h)) + return; + DMA2D_DeInit(); DMA2D_InitTypeDef DMA2D_InitStruct; From 515aa9bcdb137de7336742fd83cab3d27a65065f Mon Sep 17 00:00:00 2001 From: 3djc Date: Tue, 2 Jun 2020 09:17:08 +0200 Subject: [PATCH 23/93] Fix wizard in DarkBlue theme --- .../horus/SCRIPTS/WIZARD/glider/wizard.lua | 39 +++++++++--------- .../horus/SCRIPTS/WIZARD/plane/wizard.lua | 41 +++++++++---------- 2 files changed, 39 insertions(+), 41 deletions(-) diff --git a/radio/sdcard/horus/SCRIPTS/WIZARD/glider/wizard.lua b/radio/sdcard/horus/SCRIPTS/WIZARD/glider/wizard.lua index a07089513..86b08451e 100644 --- a/radio/sdcard/horus/SCRIPTS/WIZARD/glider/wizard.lua +++ b/radio/sdcard/horus/SCRIPTS/WIZARD/glider/wizard.lua @@ -149,14 +149,13 @@ local function runMotorConfig(event) lcd.drawBitmap(BackgroundImg, 0, 0) lcd.drawBitmap(ImgPageDn, 455, 95) lcd.drawBitmap(ImgEngine, 310, 50) - lcd.setColor(CUSTOM_COLOR, lcd.RGB(255, 255, 255)) fields = MotorFields lcd.drawText(40, 20, "Does your model have a motor ?", TEXT_COLOR) - lcd.drawFilledRectangle(40, 45, 200, 30, CUSTOM_COLOR) + lcd.drawFilledRectangle(40, 45, 200, 30, TEXT_BGCOLOR) fields[2][4]=0 if fields[1][5] == 1 then lcd.drawText(40, 100, "What channel is it on ?", TEXT_COLOR) - lcd.drawFilledRectangle(40, 122, 100, 30, CUSTOM_COLOR) + lcd.drawFilledRectangle(40, 122, 100, 30, TEXT_BGCOLOR) fields[2][4]=1 end local result = runFieldsPage(event) @@ -190,7 +189,7 @@ local function runAilConfig(event) lcd.drawBitmap(ImgAilL, 395, 235) drawMark(308, 115, "A") drawMark(422, 220, "A") - lcd.drawFilledRectangle(40, 122, 100, 30, CUSTOM_COLOR) + lcd.drawFilledRectangle(40, 122, 100, 30, TEXT_BGCOLOR) drawMark(152, 124, "A") setFieldsVisible(1, 0) elseif fields[1][5] == 2 then @@ -198,16 +197,16 @@ local function runAilConfig(event) lcd.drawBitmap(ImgAilL, 395, 235) drawMark(308, 115, "A") drawMark(422, 220, "B") - lcd.drawFilledRectangle(40, 122, 100, 30, CUSTOM_COLOR) + lcd.drawFilledRectangle(40, 122, 100, 30, TEXT_BGCOLOR) drawMark(152, 124, "A") - lcd.drawFilledRectangle(40, 162, 100, 30, CUSTOM_COLOR) + lcd.drawFilledRectangle(40, 162, 100, 30, TEXT_BGCOLOR) drawMark(152, 164, "B") setFieldsVisible(1, 1) else setFieldsVisible(0, 0) end lcd.drawText(40, 20, "Number of ailerons on your model ?", TEXT_COLOR) - lcd.drawFilledRectangle(40, 45, 400, 30, CUSTOM_COLOR) + lcd.drawFilledRectangle(40, 45, 400, 30, TEXT_BGCOLOR) local result = runFieldsPage(event) return result end @@ -235,7 +234,7 @@ local function runFlapsConfig(event) lcd.drawBitmap(ImgFlp, 358, 202) drawMark(332, 132, "A") drawMark(412, 215, "A") - lcd.drawFilledRectangle(40, 122, 100, 30, CUSTOM_COLOR) + lcd.drawFilledRectangle(40, 122, 100, 30, TEXT_BGCOLOR) drawMark(152, 124, "A") setFieldsVisible(1, 0) elseif fields[1][5] == 2 then @@ -243,16 +242,16 @@ local function runFlapsConfig(event) lcd.drawBitmap(ImgFlp, 358, 202) drawMark(332, 132, "A") drawMark(412, 215, "B") - lcd.drawFilledRectangle(40, 122, 100, 30, CUSTOM_COLOR) + lcd.drawFilledRectangle(40, 122, 100, 30, TEXT_BGCOLOR) drawMark(152, 124, "A") - lcd.drawFilledRectangle(40, 162, 100, 30, CUSTOM_COLOR) + lcd.drawFilledRectangle(40, 162, 100, 30, TEXT_BGCOLOR) drawMark(152, 164, "B") setFieldsVisible(1, 1) else setFieldsVisible(0, 0) end lcd.drawText(40, 20, "Does your model have flaps ?", TEXT_COLOR) - lcd.drawFilledRectangle(40, 45, 400, 30, CUSTOM_COLOR) + lcd.drawFilledRectangle(40, 45, 400, 30, TEXT_BGCOLOR) local result = runFieldsPage(event) return result end @@ -283,7 +282,7 @@ local function runTailConfig(event) lcd.drawBitmap(ImgTail, 252, 100) drawMark(360, 125, "A") drawMark(390, 155, "A") - lcd.drawFilledRectangle(40, 122, 100, 30, CUSTOM_COLOR) + lcd.drawFilledRectangle(40, 122, 100, 30, TEXT_BGCOLOR) drawMark(152, 124, "A") setFieldsVisible(1, 0, 0) end @@ -293,9 +292,9 @@ local function runTailConfig(event) drawMark(415, 150, "A") drawMark(380, 120, "A") drawMark(390, 185, "B") - lcd.drawFilledRectangle(40, 122, 100, 30, CUSTOM_COLOR) + lcd.drawFilledRectangle(40, 122, 100, 30, TEXT_BGCOLOR) drawMark(152, 124, "A") - lcd.drawFilledRectangle(40, 162, 100, 30, CUSTOM_COLOR) + lcd.drawFilledRectangle(40, 162, 100, 30, TEXT_BGCOLOR) drawMark(152, 164, "B") setFieldsVisible(1, 1, 0) end @@ -305,11 +304,11 @@ local function runTailConfig(event) drawMark(415, 150, "C") drawMark(380, 120, "A") drawMark(390, 185, "B") - lcd.drawFilledRectangle(40, 122, 100, 30, CUSTOM_COLOR) + lcd.drawFilledRectangle(40, 122, 100, 30, TEXT_BGCOLOR) drawMark(152, 124, "A") - lcd.drawFilledRectangle(40, 162, 100, 30, CUSTOM_COLOR) + lcd.drawFilledRectangle(40, 162, 100, 30, TEXT_BGCOLOR) drawMark(152, 164, "B") - lcd.drawFilledRectangle(40, 202, 100, 30, CUSTOM_COLOR) + lcd.drawFilledRectangle(40, 202, 100, 30, TEXT_BGCOLOR) drawMark(152, 204, "C") setFieldsVisible(1, 1, 1) end @@ -317,14 +316,14 @@ local function runTailConfig(event) lcd.drawBitmap(ImgVTail, 252, 100) drawMark(315, 110, "A") drawMark(382, 120, "B") - lcd.drawFilledRectangle(40, 122, 100, 30, CUSTOM_COLOR) + lcd.drawFilledRectangle(40, 122, 100, 30, TEXT_BGCOLOR) drawMark(152, 124, "A") - lcd.drawFilledRectangle(40, 162, 100, 30, CUSTOM_COLOR) + lcd.drawFilledRectangle(40, 162, 100, 30, TEXT_BGCOLOR) drawMark(152, 164, "B") setFieldsVisible(1, 1, 0) end lcd.drawText(40, 20, "Pick the tail config of your model", TEXT_COLOR) - lcd.drawFilledRectangle(40, 45, 400, 30, CUSTOM_COLOR) + lcd.drawFilledRectangle(40, 45, 400, 30, TEXT_BGCOLOR) local result = runFieldsPage(event) return result end diff --git a/radio/sdcard/horus/SCRIPTS/WIZARD/plane/wizard.lua b/radio/sdcard/horus/SCRIPTS/WIZARD/plane/wizard.lua index 3c44e5ad5..8a43ed159 100755 --- a/radio/sdcard/horus/SCRIPTS/WIZARD/plane/wizard.lua +++ b/radio/sdcard/horus/SCRIPTS/WIZARD/plane/wizard.lua @@ -144,19 +144,18 @@ local ImgEngine local function runMotorConfig(event) lcd.clear() if ImgEngine == nil then - ImgEngine = Bitmap.open("img/prop.png") + ImgEngine = Bitmap.open("img/prop.png") end lcd.drawBitmap(BackgroundImg, 0, 0) lcd.drawBitmap(ImgPageDn, 455, 95) lcd.drawBitmap(ImgEngine, 310, 50) - lcd.setColor(CUSTOM_COLOR, lcd.RGB(255, 255, 255)) fields = MotorFields lcd.drawText(40, 20, "Does your model have a motor ?", TEXT_COLOR) - lcd.drawFilledRectangle(40, 45, 200, 30, CUSTOM_COLOR) + lcd.drawFilledRectangle(40, 45, 200, 30, TEXT_BGCOLOR) fields[2][4]=0 if fields[1][5] == 1 then lcd.drawText(40, 100, "What channel is it on ?", TEXT_COLOR) - lcd.drawFilledRectangle(40, 122, 100, 30, CUSTOM_COLOR) + lcd.drawFilledRectangle(40, 122, 100, 30, TEXT_BGCOLOR) fields[2][4]=1 end local result = runFieldsPage(event) @@ -190,7 +189,7 @@ local function runAilConfig(event) lcd.drawBitmap(ImgAilL, 275, 210) drawMark(362, 132, "A") drawMark(302, 227, "A") - lcd.drawFilledRectangle(40, 122, 100, 30, CUSTOM_COLOR) + lcd.drawFilledRectangle(40, 122, 100, 30, TEXT_BGCOLOR) drawMark(152, 124, "A") setFieldsVisible(1, 0) elseif fields[1][5] == 2 then @@ -198,16 +197,16 @@ local function runAilConfig(event) lcd.drawBitmap(ImgAilL, 275, 210) drawMark(362, 132, "A") drawMark(302, 227, "B") - lcd.drawFilledRectangle(40, 122, 100, 30, CUSTOM_COLOR) + lcd.drawFilledRectangle(40, 122, 100, 30, TEXT_BGCOLOR) drawMark(152, 124, "A") - lcd.drawFilledRectangle(40, 162, 100, 30, CUSTOM_COLOR) + lcd.drawFilledRectangle(40, 162, 100, 30, TEXT_BGCOLOR) drawMark(152, 164, "B") setFieldsVisible(1, 1) else setFieldsVisible(0, 0) end lcd.drawText(40, 20, "Number of ailerons on your model ?", TEXT_COLOR) - lcd.drawFilledRectangle(40, 45, 400, 30, CUSTOM_COLOR) + lcd.drawFilledRectangle(40, 45, 400, 30, TEXT_BGCOLOR) local result = runFieldsPage(event) return result end @@ -235,7 +234,7 @@ local function runFlapsConfig(event) lcd.drawBitmap(ImgFlp, 285, 191) drawMark(362, 132, "A") drawMark(302, 227, "A") - lcd.drawFilledRectangle(40, 122, 100, 30, CUSTOM_COLOR) + lcd.drawFilledRectangle(40, 122, 100, 30, TEXT_BGCOLOR) drawMark(152, 124, "A") setFieldsVisible(1, 0) elseif fields[1][5] == 2 then @@ -243,16 +242,16 @@ local function runFlapsConfig(event) lcd.drawBitmap(ImgFlp, 285, 191) drawMark(362, 132, "A") drawMark(302, 227, "B") - lcd.drawFilledRectangle(40, 122, 100, 30, CUSTOM_COLOR) + lcd.drawFilledRectangle(40, 122, 100, 30, TEXT_BGCOLOR) drawMark(152, 124, "A") - lcd.drawFilledRectangle(40, 162, 100, 30, CUSTOM_COLOR) + lcd.drawFilledRectangle(40, 162, 100, 30, TEXT_BGCOLOR) drawMark(152, 164, "B") setFieldsVisible(1, 1) else setFieldsVisible(0, 0) end lcd.drawText(40, 20, "Does your model have flaps ?", TEXT_COLOR) - lcd.drawFilledRectangle(40, 45, 400, 30, CUSTOM_COLOR) + lcd.drawFilledRectangle(40, 45, 400, 30, TEXT_BGCOLOR) local result = runFieldsPage(event) return result end @@ -283,7 +282,7 @@ local function runTailConfig(event) lcd.drawBitmap(ImgTail, 252, 100) drawMark(275, 120, "A") drawMark(390, 155, "A") - lcd.drawFilledRectangle(40, 122, 100, 30, CUSTOM_COLOR) + lcd.drawFilledRectangle(40, 122, 100, 30, TEXT_BGCOLOR) drawMark(152, 124, "A") setFieldsVisible(1, 0, 0) end @@ -293,9 +292,9 @@ local function runTailConfig(event) drawMark(275, 120, "A") drawMark(390, 155, "A") drawMark(370, 112, "B") - lcd.drawFilledRectangle(40, 122, 100, 30, CUSTOM_COLOR) + lcd.drawFilledRectangle(40, 122, 100, 30, TEXT_BGCOLOR) drawMark(152, 124, "A") - lcd.drawFilledRectangle(40, 162, 100, 30, CUSTOM_COLOR) + lcd.drawFilledRectangle(40, 162, 100, 30, TEXT_BGCOLOR) drawMark(152, 164, "B") setFieldsVisible(1, 1, 0) end @@ -305,11 +304,11 @@ local function runTailConfig(event) drawMark(275, 120, "A") drawMark(390, 155, "C") drawMark(370, 112, "B") - lcd.drawFilledRectangle(40, 122, 100, 30, CUSTOM_COLOR) + lcd.drawFilledRectangle(40, 122, 100, 30, TEXT_BGCOLOR) drawMark(152, 124, "A") - lcd.drawFilledRectangle(40, 162, 100, 30, CUSTOM_COLOR) + lcd.drawFilledRectangle(40, 162, 100, 30, TEXT_BGCOLOR) drawMark(152, 164, "B") - lcd.drawFilledRectangle(40, 202, 100, 30, CUSTOM_COLOR) + lcd.drawFilledRectangle(40, 202, 100, 30, TEXT_BGCOLOR) drawMark(152, 204, "C") setFieldsVisible(1, 1, 1) end @@ -317,14 +316,14 @@ local function runTailConfig(event) lcd.drawBitmap(ImgVTail, 252, 100) drawMark(315, 110, "A") drawMark(382, 120, "B") - lcd.drawFilledRectangle(40, 122, 100, 30, CUSTOM_COLOR) + lcd.drawFilledRectangle(40, 122, 100, 30, TEXT_BGCOLOR) drawMark(152, 124, "A") - lcd.drawFilledRectangle(40, 162, 100, 30, CUSTOM_COLOR) + lcd.drawFilledRectangle(40, 162, 100, 30, TEXT_BGCOLOR) drawMark(152, 164, "B") setFieldsVisible(1, 1, 0) end lcd.drawText(40, 20, "Pick the tail config of your model", TEXT_COLOR) - lcd.drawFilledRectangle(40, 45, 400, 30, CUSTOM_COLOR) + lcd.drawFilledRectangle(40, 45, 400, 30, TEXT_BGCOLOR) local result = runFieldsPage(event) return result end From f7a3aeac74eccfede32f5b309ea44bae9a28e287 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Tue, 2 Jun 2020 09:18:06 +0200 Subject: [PATCH 24/93] Cosmetics --- radio/src/targets/horus/lcd_driver.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/radio/src/targets/horus/lcd_driver.cpp b/radio/src/targets/horus/lcd_driver.cpp index 691dd28ce..444994d02 100644 --- a/radio/src/targets/horus/lcd_driver.cpp +++ b/radio/src/targets/horus/lcd_driver.cpp @@ -41,15 +41,12 @@ uint32_t CurrentLayer = LCD_FIRST_LAYER; #define NRST_LOW() do { LCD_GPIO_NRST->BSRRH = LCD_GPIO_PIN_NRST; } while(0) #define NRST_HIGH() do { LCD_GPIO_NRST->BSRRL = LCD_GPIO_PIN_NRST; } while(0) -static inline bool coordsWithinScreen(coord_t x, coord_t y, coord_t w, coord_t h) +inline bool coordsWithinScreen(coord_t x, coord_t y, coord_t w, coord_t h) { - if (x < 0 || y < 0 || (x + w) > LCD_W || (y + h) > LCD_H) - return false; - else - return true; + return x >= 0 && y >= 0 && x + w <= LCD_W && y + h <= LCD_H; } -static void LCD_AF_GPIOConfig(void) +static void LCD_AF_GPIOConfig() { GPIO_InitTypeDef GPIO_InitStructure; From 837dffecdc54eb8271afb5d754f767690161ba98 Mon Sep 17 00:00:00 2001 From: WismyYao Date: Tue, 2 Jun 2020 16:38:57 +0800 Subject: [PATCH 25/93] Wismy/vfr (#7661) Change 'FLR' to 'VFR' Show R9M power in 'mW' --- radio/src/telemetry/frsky.h | 2 +- radio/src/telemetry/frsky_sport.cpp | 16 +++++++++++++--- radio/src/translations/cz.h.txt | 2 +- radio/src/translations/de.h.txt | 2 +- radio/src/translations/en.h.txt | 2 +- radio/src/translations/es.h.txt | 2 +- radio/src/translations/fi.h.txt | 2 +- radio/src/translations/fr.h.txt | 2 +- radio/src/translations/it.h.txt | 2 +- radio/src/translations/nl.h.txt | 2 +- radio/src/translations/pl.h.txt | 2 +- radio/src/translations/pt.h.txt | 2 +- radio/src/translations/se.h.txt | 2 +- 13 files changed, 25 insertions(+), 15 deletions(-) diff --git a/radio/src/telemetry/frsky.h b/radio/src/telemetry/frsky.h index 623ecb67d..751196d1c 100644 --- a/radio/src/telemetry/frsky.h +++ b/radio/src/telemetry/frsky.h @@ -192,7 +192,7 @@ enum FrSkyDataState { #define DIY_STREAM_FIRST_ID 0x5000 #define DIY_STREAM_LAST_ID 0x50FF #define FACT_TEST_ID 0xF000 -#define FRAME_LOSS_RATE_ID 0xF010 +#define VALID_FRAME_RATE_ID 0xF010 #define RSSI_ID 0xF101 #define ADC1_ID 0xF102 #define ADC2_ID 0xF103 diff --git a/radio/src/telemetry/frsky_sport.cpp b/radio/src/telemetry/frsky_sport.cpp index d5215e300..bf816cf04 100644 --- a/radio/src/telemetry/frsky_sport.cpp +++ b/radio/src/telemetry/frsky_sport.cpp @@ -30,7 +30,7 @@ struct FrSkySportSensor { }; const FrSkySportSensor sportSensors[] = { - { FRAME_LOSS_RATE_ID, FRAME_LOSS_RATE_ID, 0, ZSTR_FLR, UNIT_PERCENT, 0 }, + { VALID_FRAME_RATE_ID, VALID_FRAME_RATE_ID, 0, ZSTR_VFR, UNIT_PERCENT, 0 }, { RSSI_ID, RSSI_ID, 0, ZSTR_RSSI, UNIT_DB, 0 }, #if defined(MULTIMODULE) { TX_RSSI_ID, TX_RSSI_ID, 0, ZSTR_TX_RSSI , UNIT_DB , 0 }, @@ -224,9 +224,19 @@ void sportProcessTelemetryPacketWithoutCrc(uint8_t origin, const uint8_t * packe } #endif } + else if (dataId == VALID_FRAME_RATE_ID) { + data = 100 - SPORT_DATA_U8(packet); + } else if (dataId == R9_PWR_ID) { - uint32_t r9pwr[] = {100, 200, 500, 1000}; - data = r9pwr[SPORT_DATA_U8(packet) & 0x03]; + // receive 'dBm' and show by 'mw' + static const uint32_t r9pwrs[][2] = {{0, 1}, {5, 3}, {10, 10}, {13, 20}, {14, 25}, {20, 100}, {23, 200}, {27, 500}, {30, 1000}}; + uint32_t dBm = SPORT_DATA_U8(packet); + for (auto & r9pwr : r9pwrs) { + if (dBm == r9pwr[0]) { + data = r9pwr[1]; + break; + } + } } else if (dataId == XJT_VERSION_ID) { telemetryData.xjtVersion = HUB_DATA_U16(packet); diff --git a/radio/src/translations/cz.h.txt b/radio/src/translations/cz.h.txt index ac34feec2..115f2ab17 100644 --- a/radio/src/translations/cz.h.txt +++ b/radio/src/translations/cz.h.txt @@ -1193,7 +1193,7 @@ #define TR_RTC_CHECK TR("Check RTC", "Check RTC voltage") #define TR_AUTH_FAILURE "Auth-failure" -#define ZSTR_FLR "FLR" +#define ZSTR_VFR "VFR" #define ZSTR_RSSI "RSSI" #define ZSTR_R9PW "R9PW" #define ZSTR_RAS "SWR" diff --git a/radio/src/translations/de.h.txt b/radio/src/translations/de.h.txt index c9e91bd45..842050723 100644 --- a/radio/src/translations/de.h.txt +++ b/radio/src/translations/de.h.txt @@ -1200,7 +1200,7 @@ #define TR_AUTH_FAILURE "Auth-failure" // ---------------------------------------------------------------- -#define ZSTR_FLR "FLR" +#define ZSTR_VFR "VFR" #define ZSTR_RSSI "RSSI" #define ZSTR_R9PW "R9PW" #define ZSTR_RAS "SWR" diff --git a/radio/src/translations/en.h.txt b/radio/src/translations/en.h.txt index e7c30c01e..c17be6890 100644 --- a/radio/src/translations/en.h.txt +++ b/radio/src/translations/en.h.txt @@ -1197,7 +1197,7 @@ #define TR_RTC_CHECK TR("Check RTC", "Check RTC voltage") #define TR_AUTH_FAILURE "Auth-failure" -#define ZSTR_FLR "FLR" +#define ZSTR_VFR "VFR" #define ZSTR_RSSI "RSSI" #define ZSTR_R9PW "R9PW" #define ZSTR_RAS "SWR" diff --git a/radio/src/translations/es.h.txt b/radio/src/translations/es.h.txt index 428505c1c..699a47368 100644 --- a/radio/src/translations/es.h.txt +++ b/radio/src/translations/es.h.txt @@ -1196,7 +1196,7 @@ #define TR_RTC_CHECK TR("Check RTC", "Check RTC voltaje") #define TR_AUTH_FAILURE "Fallo " LCDW_128_480_LINEBREAK "autentificación" -#define ZSTR_FLR "FLR" +#define ZSTR_VFR "VFR" #define ZSTR_RSSI "RSSI" #define ZSTR_R9PW "R9PW" #define ZSTR_RAS "SWR" diff --git a/radio/src/translations/fi.h.txt b/radio/src/translations/fi.h.txt index 4ff379551..1396855a9 100644 --- a/radio/src/translations/fi.h.txt +++ b/radio/src/translations/fi.h.txt @@ -1205,7 +1205,7 @@ #define TR_RTC_CHECK TR("Check RTC", "Check RTC voltage") #define TR_AUTH_FAILURE "Auth-failure" -#define ZSTR_FLR "FLR" +#define ZSTR_VFR "VFR" #define ZSTR_RSSI "RSSI" #define ZSTR_R9PW "R9PW" #define ZSTR_RAS "SWR" diff --git a/radio/src/translations/fr.h.txt b/radio/src/translations/fr.h.txt index 80f462c09..bfd07bd25 100644 --- a/radio/src/translations/fr.h.txt +++ b/radio/src/translations/fr.h.txt @@ -1221,7 +1221,7 @@ #define TR_RTC_CHECK TR("Vérif. RTC", "Vérif. pile RTC") #define TR_AUTH_FAILURE "Auth-failure" -#define ZSTR_FLR "FLR" +#define ZSTR_VFR "VFR" #define ZSTR_RSSI "RSSI" #define ZSTR_R9PW "R9PW" #define ZSTR_RAS "SWR" diff --git a/radio/src/translations/it.h.txt b/radio/src/translations/it.h.txt index 37a494f8a..b9a9cf639 100644 --- a/radio/src/translations/it.h.txt +++ b/radio/src/translations/it.h.txt @@ -1214,7 +1214,7 @@ #define TR_RTC_CHECK TR("Controllo RTC", "Controllo voltaggio RTC") #define TR_AUTH_FAILURE "Auth-failure" -#define ZSTR_FLR "FLR" +#define ZSTR_VFR "VFR" #define ZSTR_RSSI "RSSI" #define ZSTR_R9PW "R9PW" #define ZSTR_RAS "SWR" diff --git a/radio/src/translations/nl.h.txt b/radio/src/translations/nl.h.txt index 36377aca8..c50884c73 100644 --- a/radio/src/translations/nl.h.txt +++ b/radio/src/translations/nl.h.txt @@ -1206,7 +1206,7 @@ #define TR_RTC_CHECK TR("Check RTC", "Check RTC voltage") #define TR_AUTH_FAILURE "Auth-failure" -#define ZSTR_FLR "FLR" +#define ZSTR_VFR "VFR" #define ZSTR_RSSI "RSSI" #define ZSTR_R9PW "R9PW" #define ZSTR_RAS "SWR" diff --git a/radio/src/translations/pl.h.txt b/radio/src/translations/pl.h.txt index 1753b3ec3..2e1389e2c 100644 --- a/radio/src/translations/pl.h.txt +++ b/radio/src/translations/pl.h.txt @@ -1213,7 +1213,7 @@ #define TR_RTC_CHECK TR("Check RTC", "Check RTC voltage") #define TR_AUTH_FAILURE "Auth-failure" -#define ZSTR_FLR "FLR" +#define ZSTR_VFR "VFR" #define ZSTR_RSSI "RSSI" #define ZSTR_R9PW "R9PW" #define ZSTR_RAS "SWR" diff --git a/radio/src/translations/pt.h.txt b/radio/src/translations/pt.h.txt index a9b5d0027..fb0e97e48 100644 --- a/radio/src/translations/pt.h.txt +++ b/radio/src/translations/pt.h.txt @@ -1202,7 +1202,7 @@ #define TR_RTC_CHECK TR("Check RTC", "Check RTC voltage") #define TR_AUTH_FAILURE "Auth-failure" -#define ZSTR_FLR "FLR" +#define ZSTR_VFR "VFR" #define ZSTR_RSSI "RSSI" #define ZSTR_R9PW "R9PW" #define ZSTR_RAS "SWR" diff --git a/radio/src/translations/se.h.txt b/radio/src/translations/se.h.txt index 8868d8106..deacd3518 100644 --- a/radio/src/translations/se.h.txt +++ b/radio/src/translations/se.h.txt @@ -1213,7 +1213,7 @@ #define TR_RTC_CHECK TR("Check RTC", "Check RTC voltage") #define TR_AUTH_FAILURE "Auth-failure" -#define ZSTR_FLR "FLR" +#define ZSTR_VFR "VFR" #define ZSTR_RSSI "RSSI" #define ZSTR_R9PW "R9PW" #define ZSTR_RAS "SWR" From 13b81841c4d38ad430a6314c478b19ff4c8685b2 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Tue, 2 Jun 2020 10:40:58 +0200 Subject: [PATCH 26/93] Cosmetics in a comment --- radio/src/telemetry/frsky_sport.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radio/src/telemetry/frsky_sport.cpp b/radio/src/telemetry/frsky_sport.cpp index bf816cf04..d26946534 100644 --- a/radio/src/telemetry/frsky_sport.cpp +++ b/radio/src/telemetry/frsky_sport.cpp @@ -228,7 +228,7 @@ void sportProcessTelemetryPacketWithoutCrc(uint8_t origin, const uint8_t * packe data = 100 - SPORT_DATA_U8(packet); } else if (dataId == R9_PWR_ID) { - // receive 'dBm' and show by 'mw' + // convert 'dBm' to 'mW' static const uint32_t r9pwrs[][2] = {{0, 1}, {5, 3}, {10, 10}, {13, 20}, {14, 25}, {20, 100}, {23, 200}, {27, 500}, {30, 1000}}; uint32_t dBm = SPORT_DATA_U8(packet); for (auto & r9pwr : r9pwrs) { From 0001c277ff204f347b42592190e25e3364e82a69 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Tue, 2 Jun 2020 22:48:39 +0200 Subject: [PATCH 27/93] Bluetooth RX fifo size is not big enough --- radio/src/targets/horus/board.h | 2 +- radio/src/targets/taranis/board.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/radio/src/targets/horus/board.h b/radio/src/targets/horus/board.h index 7de47b95b..44d8a5d10 100644 --- a/radio/src/targets/horus/board.h +++ b/radio/src/targets/horus/board.h @@ -675,7 +675,7 @@ void gpsSendByte(uint8_t byte); // BT driver #define BT_TX_FIFO_SIZE 64 -#define BT_RX_FIFO_SIZE 128 +#define BT_RX_FIFO_SIZE 256 #define BLUETOOTH_BOOTLOADER_BAUDRATE 230400 #define BLUETOOTH_FACTORY_BAUDRATE 57600 #define BLUETOOTH_DEFAULT_BAUDRATE 115200 diff --git a/radio/src/targets/taranis/board.h b/radio/src/targets/taranis/board.h index e62b71523..7dd0050a5 100644 --- a/radio/src/targets/taranis/board.h +++ b/radio/src/targets/taranis/board.h @@ -808,7 +808,7 @@ void auxSerialStop(); #define BLUETOOTH_FACTORY_BAUDRATE 57600 #endif #define BT_TX_FIFO_SIZE 64 -#define BT_RX_FIFO_SIZE 128 +#define BT_RX_FIFO_SIZE 256 void bluetoothInit(uint32_t baudrate, bool enable); void bluetoothWriteWakeup(); uint8_t bluetoothIsWriting(); From f34b5216a78d23c48ccacbe7b025916ba02190fe Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Wed, 3 Jun 2020 19:59:17 +0200 Subject: [PATCH 28/93] Update CREDITS.txt --- CREDITS.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CREDITS.txt b/CREDITS.txt index 1f743164c..e18ed5192 100644 --- a/CREDITS.txt +++ b/CREDITS.txt @@ -1735,3 +1735,4 @@ John Beech Wojciech Winiarski Armin Kuepfer Alain Bregand +James Thompson From a468005adade485263eaf7e11b687345b0a784d5 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Thu, 4 Jun 2020 15:13:32 +0200 Subject: [PATCH 29/93] 2nd attempt to fix #7613 (#7670) --- companion/src/firmwares/opentx/opentxeeprom.cpp | 15 ++++----------- radio/src/datastructs.h | 9 +++++++-- radio/src/telemetry/telemetry_sensors.cpp | 2 +- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/companion/src/firmwares/opentx/opentxeeprom.cpp b/companion/src/firmwares/opentx/opentxeeprom.cpp index b49a4a7ab..ec702514c 100644 --- a/companion/src/firmwares/opentx/opentxeeprom.cpp +++ b/companion/src/firmwares/opentx/opentxeeprom.cpp @@ -1880,7 +1880,7 @@ class CustomScreenField: public StructField { class SensorField: public TransformedField { public: - SensorField(DataField * parent, const ModelData& model, SensorData & sensor, Board::Type board, unsigned int version): + SensorField(DataField * parent, const ModelData & model, SensorData & sensor, Board::Type board, unsigned int version): TransformedField(parent, internalField), internalField(this, "Sensor"), sensor(sensor), @@ -1948,16 +1948,9 @@ class SensorField: public TransformedField { else { sensor.id = _id; sensor.subid = _subid; - if (model.moduleData[0].isPxx1Module() || model.moduleData[1].isPxx1Module()) { - sensor.instance = (_instance & 0x1F) + (version <= 218 ? 0 : 1); // 5 bits instance - sensor.rxIdx = 0x03; // 2 bits Rx idx - sensor.moduleIdx = 0x01; // 1 bit module idx - } - else { - sensor.instance = (_instance & 0x1F) + 1; - sensor.rxIdx = (_instance >> 5) & 0x03; // 2 bits Rx idx - sensor.moduleIdx = (_instance >> 7) & 0x1; // 1 bit module idx - } + sensor.instance = (_instance & 0x1F) + (version <= 218 ? 0 : 1); // 5 bits instance + sensor.rxIdx = (_instance >> 5) & 0x03; // 2 bits Rx idx + sensor.moduleIdx = (_instance >> 7) & 0x1; // 1 bit module idx sensor.ratio = _ratio; sensor.offset = _offset; } diff --git a/radio/src/datastructs.h b/radio/src/datastructs.h index 213d9cc4d..899190096 100644 --- a/radio/src/datastructs.h +++ b/radio/src/datastructs.h @@ -387,10 +387,15 @@ PACK(struct TelemetrySensor { return true; if (protocol == PROTOCOL_TELEMETRY_FRSKY_SPORT) { +#if defined(SIMU) + if (((this->instance ^ instance) & 0x1F) == 0) + return true; +#else if (((this->instance ^ instance) & 0x9F) == 0 && (this->instance >> 5) != TELEMETRY_ENDPOINT_SPORT && (instance >> 5) != TELEMETRY_ENDPOINT_SPORT) { this->instance = instance; // update the instance in case we had telemetry switching return true; } +#endif } return false; @@ -471,11 +476,11 @@ PACK(struct ModuleData { // Helper functions to set both of the rfProto protocol at the same time NOBACKUP(inline uint8_t getMultiProtocol() { - return ((uint8_t) (rfProtocol & 0x0f)) + (multi.rfProtocolExtra << 4); + return ((uint8_t) (rfProtocol & 0x0F)) + (multi.rfProtocolExtra << 4); }) NOBACKUP(inline void setMultiProtocol(uint8_t proto) { - rfProtocol = (uint8_t) (proto & 0x0f); + rfProtocol = (uint8_t) (proto & 0x0F); multi.rfProtocolExtra = (proto & 0x70) >> 4; }) }); diff --git a/radio/src/telemetry/telemetry_sensors.cpp b/radio/src/telemetry/telemetry_sensors.cpp index 1d0eb89b6..449879c5a 100644 --- a/radio/src/telemetry/telemetry_sensors.cpp +++ b/radio/src/telemetry/telemetry_sensors.cpp @@ -499,7 +499,7 @@ int setTelemetryValue(TelemetryProtocol protocol, uint16_t id, uint8_t subId, ui { bool sensorFound = false; - for (int index=0; index Date: Thu, 4 Jun 2020 20:52:41 +0200 Subject: [PATCH 30/93] Update CREDITS.txt --- CREDITS.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CREDITS.txt b/CREDITS.txt index e18ed5192..341241272 100644 --- a/CREDITS.txt +++ b/CREDITS.txt @@ -1736,3 +1736,5 @@ Wojciech Winiarski Armin Kuepfer Alain Bregand James Thompson +Dautremépuis Benoit +Adriano Emanuele Figliola From f0569b7a84b7ba29cbbed1840a4c7ec8e412b97e Mon Sep 17 00:00:00 2001 From: 3djc Date: Fri, 5 Jun 2020 10:23:34 +0200 Subject: [PATCH 31/93] Remove unnecessary code (handled by hardware) --- .../targets/common/arm/stm32/bootloader/boot.cpp | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/radio/src/targets/common/arm/stm32/bootloader/boot.cpp b/radio/src/targets/common/arm/stm32/bootloader/boot.cpp index c849f9e9a..59027be27 100644 --- a/radio/src/targets/common/arm/stm32/bootloader/boot.cpp +++ b/radio/src/targets/common/arm/stm32/bootloader/boot.cpp @@ -210,21 +210,6 @@ int main() pwrInit(); keysInit(); - // USB charger handling -#if defined(USB_CHARGER) - if (!WAS_RESET_BY_WATCHDOG_OR_SOFTWARE() && !pwrPressed()) { - ledInit(); - usbChargerInit(); - ledOff(); - while (!pwrPressed()) { - if(usbChargerLed()) - GPIO_SetBits(LED_GPIO, LED_GREEN_GPIO_PIN); - else - ledOff(); - } - } -#endif - // wait a bit for the inputs to stabilize... if (!WAS_RESET_BY_WATCHDOG_OR_SOFTWARE()) { for (uint32_t i = 0; i < 150000; i++) { From 0087c172ab068db1d3e152db23cfbee79eae72c7 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Fri, 5 Jun 2020 16:02:53 +0200 Subject: [PATCH 32/93] Fixes #7662 --- radio/src/gui/480x272/model_setup.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radio/src/gui/480x272/model_setup.cpp b/radio/src/gui/480x272/model_setup.cpp index 8108577d2..bc5185a2d 100644 --- a/radio/src/gui/480x272/model_setup.cpp +++ b/radio/src/gui/480x272/model_setup.cpp @@ -352,10 +352,10 @@ void runPopupRegister(event_t event) // loop index (will be removed in future) lcdDrawText(REGISTER_COLUMN_1, REGISTER_TOP + 8 + FH, "UID"); - lcdDrawNumber(REGISTER_COLUMN_2, REGISTER_TOP + 8 + FH, reusableBuffer.moduleSetup.pxx2.registerLoopIndex, menuVerticalPosition == ITEM_REGISTER_MODULE_INDEX ? (s_editMode ? INVERS + BLINK : INVERS) : 0); if (menuVerticalPosition == ITEM_REGISTER_MODULE_INDEX && s_editMode) { CHECK_INCDEC_MODELVAR_ZERO(event, reusableBuffer.moduleSetup.pxx2.registerLoopIndex, 2); } + lcdDrawNumber(REGISTER_COLUMN_2, REGISTER_TOP + 8 + FH, reusableBuffer.moduleSetup.pxx2.registerLoopIndex, menuVerticalPosition == ITEM_REGISTER_MODULE_INDEX ? (s_editMode ? INVERS : INVERS) : 0); // RX name if (reusableBuffer.moduleSetup.pxx2.registerStep < REGISTER_RX_NAME_RECEIVED) { From f6ce40e7c85dd94ba6413409c2c755e538d8dc2d Mon Sep 17 00:00:00 2001 From: Kilrah Date: Fri, 5 Jun 2020 18:08:45 +0200 Subject: [PATCH 33/93] Fix typo --- radio/src/gui/128x64/model_special_functions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radio/src/gui/128x64/model_special_functions.cpp b/radio/src/gui/128x64/model_special_functions.cpp index bfcee26c3..2eaad8f2b 100644 --- a/radio/src/gui/128x64/model_special_functions.cpp +++ b/radio/src/gui/128x64/model_special_functions.cpp @@ -147,7 +147,7 @@ void menuSpecialFunctions(event_t event, CustomFunctionData * functions, CustomF #if defined(PCBTARANIS) #if defined(PCBXLITE) - // ENT LONG on xlite brings up switch type menu, so this menu is activated with SHIT + ENT LONG + // ENT LONG on xlite brings up switch type menu, so this menu is activated with SHIFT + ENT LONG if (menuHorizontalPosition==0 && event==EVT_KEY_LONG(KEY_ENTER) && IS_SHIFT_PRESSED() && !READ_ONLY()) { #else if (menuHorizontalPosition<0 && event==EVT_KEY_LONG(KEY_ENTER) && !READ_ONLY()) { From d2a4635f36066d222bf583094918e8e59f8eb76b Mon Sep 17 00:00:00 2001 From: 3djc Date: Sat, 6 Jun 2020 13:33:40 +0200 Subject: [PATCH 34/93] Fix RxNun missing on 128x64 This fixes #7687 --- radio/src/gui/128x64/model_setup.cpp | 2 +- radio/src/gui/212x64/model_setup.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/radio/src/gui/128x64/model_setup.cpp b/radio/src/gui/128x64/model_setup.cpp index 5ced958d3..fb35dee26 100644 --- a/radio/src/gui/128x64/model_setup.cpp +++ b/radio/src/gui/128x64/model_setup.cpp @@ -416,7 +416,7 @@ void menuModelSetup(event_t event) IF_NOT_PXX2_MODULE(EXTERNAL_MODULE, MODULE_OPTION_ROW(EXTERNAL_MODULE)), MULTIMODULE_MODULE_ROWS(EXTERNAL_MODULE) FAILSAFE_ROWS(EXTERNAL_MODULE), - IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 1), // Range check and Register buttons + IF_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 diff --git a/radio/src/gui/212x64/model_setup.cpp b/radio/src/gui/212x64/model_setup.cpp index 808173efb..33833727e 100644 --- a/radio/src/gui/212x64/model_setup.cpp +++ b/radio/src/gui/212x64/model_setup.cpp @@ -1141,7 +1141,7 @@ void menuModelSetup(event_t event) lcdDrawText(INDENT_WIDTH, y, STR_RECEIVER_NUM); } if (isModuleBindRangeAvailable(moduleIdx)) { - if (!IS_RX_MULTI(moduleIdx)) { + if (isModuleRxNumAvailable(moduleIdx)) { lcdDrawNumber(MODEL_SETUP_2ND_COLUMN, y, g_model.header.modelId[moduleIdx], (l_posHorz == 0 ? attr : 0) | LEADING0 | LEFT, 2); bindButtonPos = lcdNextPos + FW; } From 9d8f00065c1c91d51d54e247c1ea8bc8f5e94500 Mon Sep 17 00:00:00 2001 From: 3djc Date: Sat, 6 Jun 2020 16:47:37 +0200 Subject: [PATCH 35/93] Sanitize AUDIO_FILENAME_MAXLEN (#7688) --- radio/src/audio.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/radio/src/audio.h b/radio/src/audio.h index 0f4821a82..4e312f71a 100644 --- a/radio/src/audio.h +++ b/radio/src/audio.h @@ -64,8 +64,7 @@ template class BitField { #define INDEX_LOGICAL_SWITCH_AUDIO_FILE(index, event) (2*(index)+(event)) #define INDEX_PHASE_AUDIO_FILE(index, event) (2*(index)+(event)) - -#define AUDIO_FILENAME_MAXLEN (42) // max length (example: /SOUNDS/fr/123456789012/1234567890-off.wav) +constexpr uint8_t AUDIO_FILENAME_MAXLEN = (sizeof("/SOUNDS/fr/") - 1) + LEN_MODEL_NAME + 1 + LEN_FLIGHT_MODE_NAME + (sizeof("-off.wav") - 1); // max length (example: /SOUNDS/fr/123456789012/1234567890-off.wav) #define AUDIO_QUEUE_LENGTH (16) // must be a power of 2! #define AUDIO_SAMPLE_RATE (32000) From 9aa9f36b5df3a3658490751fd008ed30be5d5c4b Mon Sep 17 00:00:00 2001 From: DanielGeA Date: Sun, 7 Jun 2020 21:59:05 +0100 Subject: [PATCH 36/93] Add dinamic bit shift for flight modes fading (#7690) --- radio/src/mixer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/radio/src/mixer.cpp b/radio/src/mixer.cpp index d361ac479..cda081576 100644 --- a/radio/src/mixer.cpp +++ b/radio/src/mixer.cpp @@ -947,7 +947,7 @@ void evalMixes(uint8_t tick10ms) mixerCurrentFlightMode = p; evalFlightModeMixes(p==fm ? e_perout_mode_normal : e_perout_mode_inactive_flight_mode, p==fm ? tick10ms : 0); for (uint8_t i=0; i> 4) * fp_act[p]; + sum_chans512[i] += (chans[i] >> (17-__builtin_clz(abs(chans[i])))) * fp_act[p]; weight += fp_act[p]; } } @@ -978,7 +978,7 @@ void evalMixes(uint8_t tick10ms) // at the end chans[i] = chans[i]/256 => -1024..1024 // interpolate value with min/max so we get smooth motion from center to stop // this limits based on v original values and min=-1024, max=1024 RESX=1024 - int32_t q = (flightModesFade ? (sum_chans512[i] / weight) << 4 : chans[i]); + int32_t q = (flightModesFade ? (sum_chans512[i] / weight) << (17-__builtin_clz(abs(chans[i]))) : chans[i]); ex_chans[i] = q / 256; From db8da58453b535e29bc123524170b3f519db29de Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Sun, 7 Jun 2020 23:00:28 +0200 Subject: [PATCH 37/93] Cosmetics --- radio/src/mixer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/radio/src/mixer.cpp b/radio/src/mixer.cpp index cda081576..373981044 100644 --- a/radio/src/mixer.cpp +++ b/radio/src/mixer.cpp @@ -947,7 +947,7 @@ void evalMixes(uint8_t tick10ms) mixerCurrentFlightMode = p; evalFlightModeMixes(p==fm ? e_perout_mode_normal : e_perout_mode_inactive_flight_mode, p==fm ? tick10ms : 0); for (uint8_t i=0; i> (17-__builtin_clz(abs(chans[i])))) * fp_act[p]; + sum_chans512[i] += (chans[i] >> (17 - __builtin_clz(abs(chans[i])))) * fp_act[p]; weight += fp_act[p]; } } @@ -978,7 +978,7 @@ void evalMixes(uint8_t tick10ms) // at the end chans[i] = chans[i]/256 => -1024..1024 // interpolate value with min/max so we get smooth motion from center to stop // this limits based on v original values and min=-1024, max=1024 RESX=1024 - int32_t q = (flightModesFade ? (sum_chans512[i] / weight) << (17-__builtin_clz(abs(chans[i]))) : chans[i]); + int32_t q = (flightModesFade ? (sum_chans512[i] / weight) << (17 - __builtin_clz(abs(chans[i]))) : chans[i]); ex_chans[i] = q / 256; From 3054d91da0bee38eda0e6a56b6b8cad76392fcd8 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Mon, 8 Jun 2020 08:35:40 +0200 Subject: [PATCH 38/93] Update CREDITS.txt --- CREDITS.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CREDITS.txt b/CREDITS.txt index 341241272..a7c69bff2 100644 --- a/CREDITS.txt +++ b/CREDITS.txt @@ -1738,3 +1738,4 @@ Alain Bregand James Thompson Dautremépuis Benoit Adriano Emanuele Figliola +Stefano Bortolotti From 9547e1c999aebfc89bf08577d89a11bedf376de7 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Mon, 8 Jun 2020 08:47:19 +0200 Subject: [PATCH 39/93] Typo --- companion/src/firmwares/adjustmentreference.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/companion/src/firmwares/adjustmentreference.cpp b/companion/src/firmwares/adjustmentreference.cpp index 37b284ecd..7181e15dd 100644 --- a/companion/src/firmwares/adjustmentreference.cpp +++ b/companion/src/firmwares/adjustmentreference.cpp @@ -45,15 +45,12 @@ AdjustmentReference::AdjustmentReference(AdjustRefType type, int value) bool AdjustmentReference::isValid(const int value) const { - switch(type) { + switch (type) { case ADJUST_REF_VALUE: - if (abs(value) < ADJUST_REF_GVAR_BASE) - return true; - break; + return abs(value) < ADJUST_REF_GVAR_BASE; + case ADJUST_REF_GVAR: - if (abs(value) > 0 && abs(value) <= CPN_MAX_GVARS); - return true; - break; + return abs(value) > 0 && abs(value) <= CPN_MAX_GVARS; } return false; } From 6609481c2306973e5258240a80a97822a8c02747 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Mon, 8 Jun 2020 10:08:20 +0200 Subject: [PATCH 40/93] Another attempt to fix #6063 (#7706) --- radio/src/gui/480x272/model_select.cpp | 11 +++++----- radio/src/storage/modelslist.cpp | 8 +++---- radio/src/storage/modelslist.h | 29 ++++++++++++++------------ 3 files changed, 26 insertions(+), 22 deletions(-) diff --git a/radio/src/gui/480x272/model_select.cpp b/radio/src/gui/480x272/model_select.cpp index 539191372..36dac8ba8 100644 --- a/radio/src/gui/480x272/model_select.cpp +++ b/radio/src/gui/480x272/model_select.cpp @@ -95,11 +95,10 @@ void setCurrentCategory(unsigned int index) if (currentCategory->size() > 0) setCurrentModel(0); else - currentModel = NULL; + currentModel = nullptr; } #if defined(LUA) - #define MAX_WIZARD_NAME_LEN (sizeof(WIZARD_PATH)+20) #define WIZARD_SPACING 40 #define WIZARD_LEFT_SPACING 30 @@ -248,6 +247,7 @@ void onModelSelectMenu(const char * result) storageCheck(true); memcpy(g_eeGeneral.currModelFilename, currentModel->modelFilename, LEN_MODEL_FILENAME); modelslist.setCurrentModel(currentModel); + modelslist.setCurrentCategory(currentCategory); loadModel(g_eeGeneral.currModelFilename, true); storageDirty(EE_GENERAL); storageCheck(true); @@ -264,6 +264,7 @@ void onModelSelectMenu(const char * result) selectMode = MODE_SELECT_MODEL; setCurrentModel(currentCategory->size() - 1); modelslist.setCurrentModel(currentModel); + modelslist.setCurrentCategory(currentCategory); modelslist.onNewModelCreated(currentModel, &g_model); #if defined(LUA) chainMenu(menuModelWizard); @@ -274,7 +275,7 @@ void onModelSelectMenu(const char * result) memcpy(duplicatedFilename, currentModel->modelFilename, sizeof(duplicatedFilename)); if (findNextFileIndex(duplicatedFilename, LEN_MODEL_FILENAME, MODELS_PATH)) { sdCopyFile(currentModel->modelFilename, MODELS_PATH, duplicatedFilename, MODELS_PATH); - ModelCell* dup_model = modelslist.addModel(currentCategory, duplicatedFilename); + ModelCell * dup_model = modelslist.addModel(currentCategory, duplicatedFilename); dup_model->fetchRfData(); setCurrentModel(currentCategory->size() - 1); } @@ -344,7 +345,7 @@ void initModelsList() bool menuModelSelect(event_t event) { const std::list& cats = modelslist.getCategories(); - switch(event) { + switch (event) { case 0: // no need to refresh the screen return false; @@ -387,7 +388,7 @@ bool menuModelSelect(event_t event) categoriesVerticalPosition -= 1; setCurrentCategory(categoriesVerticalPosition); modelslist.moveModel(model, previous_category, currentCategory); - setCurrentModel(currentCategory->size()-1); + setCurrentModel(currentCategory->size() - 1); } killEvents(event); break; diff --git a/radio/src/storage/modelslist.cpp b/radio/src/storage/modelslist.cpp index b706b9891..972e24800 100644 --- a/radio/src/storage/modelslist.cpp +++ b/radio/src/storage/modelslist.cpp @@ -288,8 +288,8 @@ ModelsList::~ModelsList() void ModelsList::init() { loaded = false; - currentCategory = NULL; - currentModel = NULL; + currentCategory = nullptr; + currentModel = nullptr; modelsCount = 0; } @@ -368,12 +368,12 @@ void ModelsList::save() f_close(&file); } -void ModelsList::setCurrentCategorie(ModelsCategory* cat) +void ModelsList::setCurrentCategory(ModelsCategory * cat) { currentCategory = cat; } -void ModelsList::setCurrentModel(ModelCell* cell) +void ModelsList::setCurrentModel(ModelCell * cell) { currentModel = cell; if (!currentModel->valid_rfData) diff --git a/radio/src/storage/modelslist.h b/radio/src/storage/modelslist.h index c5a157207..7da9d4b46 100644 --- a/radio/src/storage/modelslist.h +++ b/radio/src/storage/modelslist.h @@ -40,8 +40,8 @@ struct SimpleModuleData class ModelCell { public: - char modelFilename[LEN_MODEL_FILENAME+1]; - char modelName[LEN_MODEL_NAME+1]; + char modelFilename[LEN_MODEL_FILENAME + 1]; + char modelName[LEN_MODEL_NAME + 1]; BitmapBuffer * buffer; bool valid_rfData; @@ -51,10 +51,10 @@ public: ModelCell(const char * name); ~ModelCell(); - void save(FIL* file); + void save(FIL * file); - void setModelName(char* name); - void setRfData(ModelData* model); + void setModelName(char * name); + void setRfData(ModelData * model); void setModelId(uint8_t moduleIdx, uint8_t id); void setRfModuleData(uint8_t moduleIdx, ModuleData* modData); @@ -68,7 +68,7 @@ public: class ModelsCategory: public std::list { public: - char name[LEN_MODEL_FILENAME+1]; + char name[LEN_MODEL_FILENAME + 1]; ModelsCategory(const char * name); ~ModelsCategory(); @@ -98,21 +98,25 @@ public: void save(); void clear(); - const std::list& getCategories() const { + const std::list & getCategories() const + { return categories; } - void setCurrentCategorie(ModelsCategory* cat); - ModelsCategory* getCurrentCategory() const { + void setCurrentCategory(ModelsCategory * cat); + ModelsCategory * getCurrentCategory() const + { return currentCategory; } - void setCurrentModel(ModelCell* cell); - ModelCell* getCurrentModel() const { + void setCurrentModel(ModelCell * cell); + ModelCell * getCurrentModel() const + { return currentModel; } - unsigned int getModelsCount() const { + unsigned int getModelsCount() const + { return modelsCount; } @@ -133,7 +137,6 @@ public: protected: FIL file; - }; extern ModelsList modelslist; From 31d734d14a61d5f7268b36a6d6e39464afd41603 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Mon, 8 Jun 2020 10:46:16 +0200 Subject: [PATCH 41/93] Companion failsafe fix (#7705) Companion failsafe fix --- companion/src/firmwares/io_data.h | 3 +- companion/src/firmwares/modeldata.cpp | 26 +++++----- companion/src/firmwares/moduledata.h | 7 ++- .../src/firmwares/opentx/opentxeeprom.cpp | 10 ++-- companion/src/modeledit/setup.cpp | 50 ++++++++++++++----- companion/src/modeledit/setup.h | 7 ++- companion/src/modelprinter.cpp | 5 +- 7 files changed, 70 insertions(+), 38 deletions(-) diff --git a/companion/src/firmwares/io_data.h b/companion/src/firmwares/io_data.h index 05136f210..b70b174ea 100644 --- a/companion/src/firmwares/io_data.h +++ b/companion/src/firmwares/io_data.h @@ -109,7 +109,8 @@ class LimitData { int offset; int ppmCenter; bool symetrical; - char name[LIMITDATA_NAME_LEN+1]; + int failsafe; + char name[LIMITDATA_NAME_LEN + 1]; CurveReference curve; QString minToString() const; QString maxToString() const; diff --git a/companion/src/firmwares/modeldata.cpp b/companion/src/firmwares/modeldata.cpp index b72cc328a..3386ba41d 100644 --- a/companion/src/firmwares/modeldata.cpp +++ b/companion/src/firmwares/modeldata.cpp @@ -1174,8 +1174,7 @@ void ModelData::updateModuleFailsafes(ModuleData * md) bool updated = false; - switch (updRefInfo.action) - { + switch (updRefInfo.action) { case REF_UPD_ACT_CLEAR: break; case REF_UPD_ACT_SHIFT: @@ -1183,16 +1182,16 @@ void ModelData::updateModuleFailsafes(ModuleData * md) return; if (updRefInfo.shift > 0) { - for (int i = (CPN_MAX_CHNOUT - 1); i > updRefInfo.index1; i--) { - md->failsafeChannels[i] = md->failsafeChannels[i - 1]; + for (int i = CPN_MAX_CHNOUT - 1; i > updRefInfo.index1; i--) { + limitData[i].failsafe = limitData[i - 1].failsafe; } - md->failsafeChannels[updRefInfo.index1] = 0; + limitData[updRefInfo.index1].failsafe = 0; } else { - for (int i = (updRefInfo.index1 + 1); i < (CPN_MAX_CHNOUT - 1); i++) { - md->failsafeChannels[i - 1] = md->failsafeChannels[i]; + for (int i = updRefInfo.index1 + 1; i < CPN_MAX_CHNOUT - 1; i++) { + limitData[i - 1].failsafe = limitData[i].failsafe; } - md->failsafeChannels[CPN_MAX_CHNOUT - 1] = 0; + limitData[CPN_MAX_CHNOUT - 1].failsafe = 0; } updated = true; break; @@ -1200,17 +1199,18 @@ void ModelData::updateModuleFailsafes(ModuleData * md) int tmp; if (updRefInfo.index1 >= 0 && updRefInfo.index1 < CPN_MAX_CHNOUT) { updated = true; - tmp = md->failsafeChannels[updRefInfo.index1]; + tmp = limitData[updRefInfo.index1].failsafe; if (updRefInfo.index2 >= 0 && updRefInfo.index2 < CPN_MAX_CHNOUT) - md->failsafeChannels[updRefInfo.index1] = md->failsafeChannels[updRefInfo.index2]; + limitData[updRefInfo.index1].failsafe = limitData[updRefInfo.index2].failsafe; else - md->failsafeChannels[updRefInfo.index1] = 0; + limitData[updRefInfo.index1].failsafe = 0; } else tmp = 0; - if (updRefInfo.index2 >= 0 && updRefInfo.index2 < CPN_MAX_CHNOUT) + if (updRefInfo.index2 >= 0 && updRefInfo.index2 < CPN_MAX_CHNOUT) { updated = true; - md->failsafeChannels[updRefInfo.index2] = tmp; + limitData[updRefInfo.index2].failsafe = tmp; + } break; default: qDebug() << "Error - unhandled action:" << updRefInfo.action; diff --git a/companion/src/firmwares/moduledata.h b/companion/src/firmwares/moduledata.h index 1df7380a1..d356c3012 100644 --- a/companion/src/firmwares/moduledata.h +++ b/companion/src/firmwares/moduledata.h @@ -158,7 +158,11 @@ class ModuleData { Q_DECLARE_TR_FUNCTIONS(ModuleData) public: - ModuleData() { clear(); } + ModuleData() + { + clear(); + } + unsigned int modelId; unsigned int protocol; // type in datastructs.h int rfProtocol; // rfProtocol in datastructs.h @@ -168,7 +172,6 @@ class ModuleData { unsigned int channelsStart; int channelsCount; // 0=8 channels unsigned int failsafeMode; - int failsafeChannels[CPN_MAX_CHNOUT]; struct PPM { int delay; diff --git a/companion/src/firmwares/opentx/opentxeeprom.cpp b/companion/src/firmwares/opentx/opentxeeprom.cpp index ec702514c..17c5b03a5 100644 --- a/companion/src/firmwares/opentx/opentxeeprom.cpp +++ b/companion/src/firmwares/opentx/opentxeeprom.cpp @@ -2184,7 +2184,7 @@ class ModuleUnionField: public UnionField { class ModuleField: public TransformedField { public: - ModuleField(DataField * parent, ModuleData & module, Board::Type board, unsigned int version): + ModuleField(DataField * parent, ModuleData & module, ModelData & model, Board::Type board, unsigned int version): TransformedField(parent, internalField), internalField(this, "Module"), module(module), @@ -2198,8 +2198,8 @@ class ModuleField: public TransformedField { internalField.Append(new UnsignedField<3>(this, module.subType)); internalField.Append(new BoolField<1>(this, module.invertedSerial)); if (version <= 218) { - for (int i=0; i<32; i++) { - internalField.Append(new SignedField<16>(this, module.failsafeChannels[i])); + for (int i = 0; i < 32; i++) { + internalField.Append(new SignedField<16>(this, model.limitData[i].failsafe)); } } @@ -2393,12 +2393,12 @@ OpenTxModelData::OpenTxModelData(ModelData & modelData, Board::Type board, unsig int modulesCount = (version <= 218 ? 3 : 2); for (int module = 0; module < modulesCount; module++) { - internalField.Append(new ModuleField(this, modelData.moduleData[module], board, version)); + internalField.Append(new ModuleField(this, modelData.moduleData[module], modelData, board, version)); } if (version >= 219) { for (int i = 0; i < 32; i++) { - internalField.Append(new SignedField<16>(this, modelData.moduleData[0].failsafeChannels[i])); + internalField.Append(new SignedField<16>(this, modelData.limitData[i].failsafe)); } } diff --git a/companion/src/modeledit/setup.cpp b/companion/src/modeledit/setup.cpp index c813b0b9c..43eaf11fe 100644 --- a/companion/src/modeledit/setup.cpp +++ b/companion/src/modeledit/setup.cpp @@ -792,18 +792,22 @@ void ModulePanel::on_lowPower_stateChanged(int state) module.multi.lowPowerMode = (state == Qt::Checked); } -// updtSb (update spin box(es)): 0=none or bitmask of FailsafeValueDisplayTypes -void ModulePanel::setChannelFailsafeValue(const int channel, const int value, quint8 updtSb) +void ModulePanel::onFailsafeModified(unsigned channel) { - if (channel < 0 || channel >= CPN_MAX_CHNOUT) - return; + updateFailsafeUI(channel, FAILSAFE_DISPLAY_PERCENT | FAILSAFE_DISPLAY_USEC); +} - module.failsafeChannels[channel] = value; +void ModulePanel::updateFailsafeUI(unsigned channel, quint8 updtSb) +{ + int value = model->limitData[channel].failsafe; double pctVal = divRoundClosest(value * 1000, 1024) / 10.0; - // qDebug() << value << pctVal; if (failsafeGroupsMap.contains(channel)) { const ChannelFailsafeWidgetsGroup & grp = failsafeGroupsMap.value(channel); + bool disable = (value == FAILSAFE_CHANNEL_HOLD || value == FAILSAFE_CHANNEL_NOPULSE); + if (grp.combo) { + grp.combo->setCurrentIndex(grp.combo->findData(disable ? value : 0)); + } if ((updtSb & FAILSAFE_DISPLAY_PERCENT) && grp.sbPercent) { grp.sbPercent->blockSignals(true); grp.sbPercent->setValue(pctVal); @@ -815,8 +819,21 @@ void ModulePanel::setChannelFailsafeValue(const int channel, const int value, qu grp.sbUsec->blockSignals(false); } } - if (!lock) +} + +// updtSb (update spin box(es)): 0=none or bitmask of FailsafeValueDisplayTypes +void ModulePanel::setChannelFailsafeValue(const int channel, const int value, quint8 updtSb) +{ + if (channel < 0 || channel >= CPN_MAX_CHNOUT) + return; + + model->limitData[channel].failsafe = value; + updateFailsafeUI(channel, updtSb); + + if (!lock) { + emit failsafeModified(channel); emit modified(); + } } void ModulePanel::onFailsafeUsecChanged(int value) @@ -853,8 +870,9 @@ void ModulePanel::onFailsafeComboIndexChanged(int index) bool ok = false; int channel = sender()->property("index").toInt(&ok); if (ok) { - module.failsafeChannels[channel] = cb->itemData(index).toInt(); + model->limitData[channel].failsafe = cb->itemData(index).toInt(); updateFailsafe(channel); + emit failsafeModified(channel); emit modified(); } lock = false; @@ -886,12 +904,12 @@ void ModulePanel::onExtendedLimitsToggled() } } -void ModulePanel::updateFailsafe(int channel) +void ModulePanel::updateFailsafe(unsigned channel) { if (channel >= CPN_MAX_CHNOUT || !failsafeGroupsMap.contains(channel)) return; - const int failsafeValue = module.failsafeChannels[channel]; + const int failsafeValue = model->limitData[channel].failsafe; const ChannelFailsafeWidgetsGroup & grp = failsafeGroupsMap.value(channel); const bool valDisable = (failsafeValue == FAILSAFE_CHANNEL_HOLD || failsafeValue == FAILSAFE_CHANNEL_NOPULSE); @@ -903,7 +921,7 @@ void ModulePanel::updateFailsafe(int channel) grp.sbUsec->setDisabled(valDisable); if (!valDisable) - setChannelFailsafeValue(channel, failsafeValue, (FAILSAFE_DISPLAY_PERCENT | FAILSAFE_DISPLAY_USEC)); + setChannelFailsafeValue(channel, failsafeValue, FAILSAFE_DISPLAY_PERCENT | FAILSAFE_DISPLAY_USEC); } void ModulePanel::onClearAccessRxClicked() @@ -1166,13 +1184,21 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge ui->trimsDisplay->hide(); } - for (int i=firmware->getCapability(NumFirstUsableModule); igetCapability(NumModules); i++) { + for (int i = firmware->getCapability(NumFirstUsableModule); i < firmware->getCapability(NumModules); i++) { modules[i] = new ModulePanel(this, model, model.moduleData[i], generalSettings, firmware, i); ui->modulesLayout->addWidget(modules[i]); connect(modules[i], &ModulePanel::modified, this, &SetupPanel::modified); connect(this, &SetupPanel::extendedLimitsToggled, modules[i], &ModulePanel::onExtendedLimitsToggled); } + for (int i = firmware->getCapability(NumFirstUsableModule); i < firmware->getCapability(NumModules); i++) { + for (int j = firmware->getCapability(NumFirstUsableModule); j < firmware->getCapability(NumModules); j++) { + if (i != j) { + connect(modules[i], SIGNAL(failsafeModified(unsigned)), modules[j], SLOT(onFailsafeModified(unsigned))); + } + } + } + if (firmware->getCapability(ModelTrainerEnable)) { modules[CPN_MAX_MODULES] = new ModulePanel(this, model, model.moduleData[CPN_MAX_MODULES], generalSettings, firmware, -1); ui->modulesLayout->addWidget(modules[CPN_MAX_MODULES]); diff --git a/companion/src/modeledit/setup.h b/companion/src/modeledit/setup.h index fa9e4ad5b..1470e4e2f 100644 --- a/companion/src/modeledit/setup.h +++ b/companion/src/modeledit/setup.h @@ -61,15 +61,17 @@ class ModulePanel : public ModelPanel Q_OBJECT public: - ModulePanel(QWidget *parent, ModelData & model, ModuleData & module, GeneralSettings & generalSettings, Firmware * firmware, int moduleIdx); + ModulePanel(QWidget * parent, ModelData & model, ModuleData & module, GeneralSettings & generalSettings, Firmware * firmware, int moduleIdx); virtual ~ModulePanel(); virtual void update(); public slots: void onExtendedLimitsToggled(); + void onFailsafeModified(unsigned index); signals: void channelsRangeChanged(); + void failsafeModified(unsigned index); private slots: void setupFailsafes(); @@ -95,7 +97,7 @@ class ModulePanel : public ModelPanel void onFailsafeUsecChanged(int value); void onFailsafePercentChanged(double value); void onFailsafesDisplayValueTypeChanged(int type); - void updateFailsafe(int channel); + void updateFailsafe(unsigned channel); void on_optionValue_editingFinished(); void onClearAccessRxClicked(); @@ -114,6 +116,7 @@ class ModulePanel : public ModelPanel Ui::Module *ui; QMap failsafeGroupsMap; static quint8 failsafesValueDisplayType; // FailsafeValueDisplayTypes + void updateFailsafeUI(unsigned channel, quint8 updtSb); }; class SetupPanel : public ModelPanel diff --git a/companion/src/modelprinter.cpp b/companion/src/modelprinter.cpp index ac9f6f066..dde8517e0 100644 --- a/companion/src/modelprinter.cpp +++ b/companion/src/modelprinter.cpp @@ -897,9 +897,8 @@ QString ModelPrinter::printFailsafe(int idx) ModuleData module = model.moduleData[idx]; strl << printLabelValue(tr("Failsafe Mode"), printFailsafeMode(module.failsafeMode)); if (module.failsafeMode == FAILSAFE_CUSTOM) { - for (int i=0; i Date: Mon, 8 Jun 2020 14:40:53 +0200 Subject: [PATCH 42/93] Fixes #7694 --- radio/src/gui/480x272/menus.h | 9 +++++++++ radio/src/gui/480x272/radio_sdmanager.cpp | 4 ++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/radio/src/gui/480x272/menus.h b/radio/src/gui/480x272/menus.h index e9f4e7008..0177397f2 100644 --- a/radio/src/gui/480x272/menus.h +++ b/radio/src/gui/480x272/menus.h @@ -570,6 +570,15 @@ inline void POPUP_WAIT(const char * s) popupFunc = runPopupWarning; } +inline void DRAW_POPUP_WAIT(const char * s) +{ + warningText = s; + warningInfoText = nullptr; + warningType = WARNING_TYPE_WAIT; + runPopupWarning(0); + warningText = nullptr; +} + inline void POPUP_INFORMATION(const char * s) { warningText = s; diff --git a/radio/src/gui/480x272/radio_sdmanager.cpp b/radio/src/gui/480x272/radio_sdmanager.cpp index 96fb7c18d..fbf12764c 100644 --- a/radio/src/gui/480x272/radio_sdmanager.cpp +++ b/radio/src/gui/480x272/radio_sdmanager.cpp @@ -568,12 +568,12 @@ bool menuRadioSdManager(event_t _event) for (auto rx = 0; rx < popupMenuItemsCount; rx++) { popupMenuItems[rx] = reusableBuffer.sdManager.otaUpdateInformation.candidateReceiversNames[rx]; } - //popupMenuTitle = STR_PXX2_SELECT_RX; + // popupMenuTitle = STR_PXX2_SELECT_RX; POPUP_MENU_START(onUpdateReceiverSelection); } } else { - POPUP_WAIT(STR_WAITING_FOR_RX); + DRAW_POPUP_WAIT(STR_WAITING_FOR_RX); } } } From 48c227d5f5b095f0f6babcd1e11f629657a75809 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Mon, 8 Jun 2020 15:11:34 +0200 Subject: [PATCH 43/93] Add a title to the popups on Horus --- radio/src/gui/480x272/menus.h | 1 + radio/src/gui/480x272/model_setup.cpp | 2 +- radio/src/gui/480x272/popups.cpp | 9 +++++++-- radio/src/gui/480x272/radio_sdmanager.cpp | 2 +- radio/src/gui/common/stdlcd/popups.h | 1 + 5 files changed, 11 insertions(+), 4 deletions(-) diff --git a/radio/src/gui/480x272/menus.h b/radio/src/gui/480x272/menus.h index 0177397f2..5173bb04d 100644 --- a/radio/src/gui/480x272/menus.h +++ b/radio/src/gui/480x272/menus.h @@ -502,6 +502,7 @@ inline void DISPLAY_WARNING(event_t event) #define MENU_MAX_DISPLAY_LINES 9 #define MENU_LINE_LENGTH (LEN_MODEL_NAME+12) +extern const char * popupMenuTitle; extern const char * popupMenuItems[POPUP_MENU_MAX_LINES]; extern uint16_t popupMenuItemsCount; extern uint16_t popupMenuOffset; diff --git a/radio/src/gui/480x272/model_setup.cpp b/radio/src/gui/480x272/model_setup.cpp index bc5185a2d..5f9d680cf 100644 --- a/radio/src/gui/480x272/model_setup.cpp +++ b/radio/src/gui/480x272/model_setup.cpp @@ -1455,7 +1455,7 @@ bool menuModelSetup(event_t event) for (auto rx = 0; rx < popupMenuItemsCount; rx++) { popupMenuItems[rx] = reusableBuffer.moduleSetup.bindInformation.candidateReceiversNames[rx]; } - // popupMenuTitle = STR_PXX2_SELECT_RX; + popupMenuTitle = STR_PXX2_SELECT_RX; POPUP_MENU_START(onPXX2BindMenu); } } diff --git a/radio/src/gui/480x272/popups.cpp b/radio/src/gui/480x272/popups.cpp index 2d8caeca3..672922d33 100644 --- a/radio/src/gui/480x272/popups.cpp +++ b/radio/src/gui/480x272/popups.cpp @@ -27,6 +27,7 @@ uint8_t warningType; uint8_t warningResult = 0; uint8_t warningInfoFlags = ZCHAR; PopupFunc popupFunc = nullptr; +const char * popupMenuTitle = nullptr; const char *popupMenuItems[POPUP_MENU_MAX_LINES]; uint8_t popupMenuSelectedItem = 0; uint16_t popupMenuItemsCount = 0; @@ -61,6 +62,10 @@ void drawPopupBackgroundAndBorder(coord_t x, coord_t y, coord_t w, coord_t h) { lcdDrawSolidFilledRect(x + 1, y + 1, w - 2, h - 2, TEXT_BGCOLOR); lcdDrawSolidRect(x, y, w, h, 1, ALARM_COLOR); + if (popupMenuTitle) { + lcdDrawSolidFilledRect(x, y - FH, w, FH, TEXT_INVERTED_BGCOLOR); + lcdDrawText(x + w / 2, y - FH, popupMenuTitle, BOLD | CENTERED | TEXT_INVERTED_COLOR); + } } void runPopupWarning(event_t event) @@ -167,9 +172,9 @@ const char * runPopupMenu(event_t event) break; } - int y = (LCD_H - (display_count*(FH+1))) / 2; + int y = (LCD_H - (display_count*(FH + 1)) + (popupMenuTitle ? FH : 0) + FH) / 2; - drawPopupBackgroundAndBorder(MENU_X, y, MENU_W, display_count * (FH+1) + 2); + drawPopupBackgroundAndBorder(MENU_X, y, MENU_W, display_count * (FH + 1) + 2); for (uint8_t i=0; i Date: Mon, 8 Jun 2020 17:53:39 +0200 Subject: [PATCH 44/93] Cosmetics --- radio/src/gui/480x272/radio_sdmanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radio/src/gui/480x272/radio_sdmanager.cpp b/radio/src/gui/480x272/radio_sdmanager.cpp index b5134bb3e..24c9d2c7b 100644 --- a/radio/src/gui/480x272/radio_sdmanager.cpp +++ b/radio/src/gui/480x272/radio_sdmanager.cpp @@ -523,7 +523,7 @@ bool menuRadioSdManager(event_t _event) reusableBuffer.sdManager.offset = menuVerticalOffset; - for (uint8_t i=0; i Date: Mon, 8 Jun 2020 17:57:26 +0200 Subject: [PATCH 45/93] Cosmetics --- radio/src/gui/128x64/model_setup.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/radio/src/gui/128x64/model_setup.cpp b/radio/src/gui/128x64/model_setup.cpp index fb35dee26..cc625e367 100644 --- a/radio/src/gui/128x64/model_setup.cpp +++ b/radio/src/gui/128x64/model_setup.cpp @@ -1419,7 +1419,8 @@ void menuModelSetup(event_t event) #if defined(HARDWARE_INTERNAL_MODULE) case ITEM_MODEL_SETUP_INTERNAL_MODULE_FAILSAFE: #endif - case ITEM_MODEL_SETUP_EXTERNAL_MODULE_FAILSAFE: { + case ITEM_MODEL_SETUP_EXTERNAL_MODULE_FAILSAFE: + { ModuleData &moduleData = g_model.moduleData[moduleIdx]; lcdDrawTextAlignedLeft(y, STR_FAILSAFE); lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_VFAILSAFE, moduleData.failsafeMode, menuHorizontalPosition == 0 ? attr : 0); From 8f7d3c9786bf22d52da969a337e7c1d0f37947cc Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Mon, 8 Jun 2020 18:34:58 +0200 Subject: [PATCH 46/93] Cosmetics --- radio/src/bluetooth.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/radio/src/bluetooth.cpp b/radio/src/bluetooth.cpp index 025237eb2..22daa0c42 100644 --- a/radio/src/bluetooth.cpp +++ b/radio/src/bluetooth.cpp @@ -176,7 +176,7 @@ void Bluetooth::processTrainerByte(uint8_t data) switch (dataState) { case STATE_DATA_START: if (data == START_STOP) { - dataState = STATE_DATA_IN_FRAME ; + dataState = STATE_DATA_IN_FRAME; bufferIndex = 0; } else { @@ -189,7 +189,7 @@ void Bluetooth::processTrainerByte(uint8_t data) dataState = STATE_DATA_XOR; // XOR next byte } else if (data == START_STOP) { - dataState = STATE_DATA_IN_FRAME ; + dataState = STATE_DATA_IN_FRAME; bufferIndex = 0; } else { From 2edfa73dc1c1368ca6c817266b030ae3c7a57e57 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Mon, 8 Jun 2020 19:06:55 +0200 Subject: [PATCH 47/93] Cosmetics --- radio/src/targets/horus/extmodule_driver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radio/src/targets/horus/extmodule_driver.cpp b/radio/src/targets/horus/extmodule_driver.cpp index 0da9e46a5..e4b28244e 100644 --- a/radio/src/targets/horus/extmodule_driver.cpp +++ b/radio/src/targets/horus/extmodule_driver.cpp @@ -362,7 +362,7 @@ void extmoduleSendInvertedByte(uint8_t byte) // wait } time += 34; - for (i = 0 ; i < 8 ; i += 1) { + for (i = 0; i < 8; i++) { if (byte & 1) { GPIO_ResetBits(EXTMODULE_TX_GPIO, EXTMODULE_TX_GPIO_PIN); } From 9493b4500a7a1839f876d52f2581fb6a205dc011 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Mon, 8 Jun 2020 19:14:13 +0200 Subject: [PATCH 48/93] Cosmetics --- radio/src/gui/common/stdlcd/model_inputs.cpp | 2 +- radio/src/gui/common/stdlcd/model_mixes.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/radio/src/gui/common/stdlcd/model_inputs.cpp b/radio/src/gui/common/stdlcd/model_inputs.cpp index edf245654..c396db061 100644 --- a/radio/src/gui/common/stdlcd/model_inputs.cpp +++ b/radio/src/gui/common/stdlcd/model_inputs.cpp @@ -26,7 +26,7 @@ uint8_t getExposCount() { uint8_t count = 0; - uint8_t ch ; + uint8_t ch; for (int i=MAX_EXPOS-1 ; i>=0; i--) { ch = EXPO_VALID(expoAddress(i)); diff --git a/radio/src/gui/common/stdlcd/model_mixes.cpp b/radio/src/gui/common/stdlcd/model_mixes.cpp index c2714a3b0..d5324e509 100644 --- a/radio/src/gui/common/stdlcd/model_mixes.cpp +++ b/radio/src/gui/common/stdlcd/model_mixes.cpp @@ -26,7 +26,7 @@ uint8_t getMixesCount() { uint8_t count = 0; - uint8_t ch ; + uint8_t ch; for (int i=MAX_MIXERS-1; i>=0; i--) { ch = mixAddress(i)->srcRaw; From dee71500a8030d718999af0017c4378560835e9a Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Mon, 8 Jun 2020 19:59:43 +0200 Subject: [PATCH 49/93] Cosmetics --- radio/src/targets/horus/extmodule_driver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radio/src/targets/horus/extmodule_driver.cpp b/radio/src/targets/horus/extmodule_driver.cpp index e4b28244e..7e8b90937 100644 --- a/radio/src/targets/horus/extmodule_driver.cpp +++ b/radio/src/targets/horus/extmodule_driver.cpp @@ -376,7 +376,7 @@ void extmoduleSendInvertedByte(uint8_t byte) time += 35 ; } GPIO_ResetBits(EXTMODULE_TX_GPIO, EXTMODULE_TX_GPIO_PIN); - __enable_irq() ; // No need to wait for the stop bit to complete + __enable_irq(); // No need to wait for the stop bit to complete while ((uint16_t) (getTmr2MHz() - time) < 34) { // wait } From 5276a4d42a29485039d7c444f50ecf1f1c176904 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Mon, 8 Jun 2020 20:46:34 +0200 Subject: [PATCH 50/93] Cosmetics for another attempt --- radio/src/gui/212x64/model_setup.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radio/src/gui/212x64/model_setup.cpp b/radio/src/gui/212x64/model_setup.cpp index 33833727e..1b9d612ad 100644 --- a/radio/src/gui/212x64/model_setup.cpp +++ b/radio/src/gui/212x64/model_setup.cpp @@ -536,7 +536,7 @@ void menuModelSetup(event_t event) break; case ITEM_MODEL_SETUP_THROTTLE_REVERSED: - ON_OFF_MENU_ITEM(g_model.throttleReversed, MODEL_SETUP_2ND_COLUMN, y, STR_THROTTLEREVERSE, attr, event ) ; + ON_OFF_MENU_ITEM(g_model.throttleReversed, MODEL_SETUP_2ND_COLUMN, y, STR_THROTTLEREVERSE, attr, event ); break; case ITEM_MODEL_SETUP_THROTTLE_TRACE: From 62bcb1dbadd35c05ddf6418dce5377921abf41f2 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Mon, 8 Jun 2020 21:25:39 +0200 Subject: [PATCH 51/93] VC++ compilation fix --- radio/src/datastructs.h | 20 +------------------- radio/src/telemetry/telemetry_sensors.cpp | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/radio/src/datastructs.h b/radio/src/datastructs.h index 899190096..9ff05975a 100644 --- a/radio/src/datastructs.h +++ b/radio/src/datastructs.h @@ -381,25 +381,7 @@ PACK(struct TelemetrySensor { bool isPrecConfigurable() const; int32_t getPrecMultiplier() const; int32_t getPrecDivisor() const; - bool isSameInstance(TelemetryProtocol protocol, uint8_t instance) - { - if (this->instance == instance) - return true; - - if (protocol == PROTOCOL_TELEMETRY_FRSKY_SPORT) { -#if defined(SIMU) - if (((this->instance ^ instance) & 0x1F) == 0) - return true; -#else - if (((this->instance ^ instance) & 0x9F) == 0 && (this->instance >> 5) != TELEMETRY_ENDPOINT_SPORT && (instance >> 5) != TELEMETRY_ENDPOINT_SPORT) { - this->instance = instance; // update the instance in case we had telemetry switching - return true; - } -#endif - } - - return false; - } + bool isSameInstance(TelemetryProtocol protocol, uint8_t instance); ); }); diff --git a/radio/src/telemetry/telemetry_sensors.cpp b/radio/src/telemetry/telemetry_sensors.cpp index 449879c5a..0896e1424 100644 --- a/radio/src/telemetry/telemetry_sensors.cpp +++ b/radio/src/telemetry/telemetry_sensors.cpp @@ -720,3 +720,23 @@ int32_t TelemetrySensor::getPrecDivisor() const if (prec == 1) return 10; return 1; } + +bool TelemetrySensor::isSameInstance(TelemetryProtocol protocol, uint8_t instance) +{ + if (this->instance == instance) + return true; + + if (protocol == PROTOCOL_TELEMETRY_FRSKY_SPORT) { +#if defined(SIMU) + if (((this->instance ^ instance) & 0x1F) == 0) + return true; +#else + if (((this->instance ^ instance) & 0x9F) == 0 && (this->instance >> 5) != TELEMETRY_ENDPOINT_SPORT && (instance >> 5) != TELEMETRY_ENDPOINT_SPORT) { + this->instance = instance; // update the instance in case we had telemetry switching + return true; + } +#endif + } + + return false; +} From e7e8c95c4584ff14c068230fd8c7c2907d44c9ac Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Mon, 8 Jun 2020 21:51:51 +0200 Subject: [PATCH 52/93] VC++ compilation fix --- radio/src/targets/simu/simpgmspace.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/radio/src/targets/simu/simpgmspace.h b/radio/src/targets/simu/simpgmspace.h index 302355fd7..ed9d16b4b 100644 --- a/radio/src/targets/simu/simpgmspace.h +++ b/radio/src/targets/simu/simpgmspace.h @@ -23,11 +23,16 @@ #ifndef __GNUC__ #include +#include #define sleep(x) Sleep(x) #define strcasecmp _stricmp #define strncasecmp _tcsnicmp #define chdir _chdir #define getcwd _getcwd +inline int __builtin_clz(unsigned x) +{ + return (int)__lzcnt(x); +} #else #include #define sleep(x) usleep(1000*x) From dcd53bdf054609f0bbec81b8f09e26d555cfe779 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Tue, 9 Jun 2020 08:27:21 +0200 Subject: [PATCH 53/93] Cosmetics --- radio/src/gui/128x64/model_setup.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/radio/src/gui/128x64/model_setup.cpp b/radio/src/gui/128x64/model_setup.cpp index cc625e367..d5e9d1004 100644 --- a/radio/src/gui/128x64/model_setup.cpp +++ b/radio/src/gui/128x64/model_setup.cpp @@ -511,7 +511,7 @@ void menuModelSetup(event_t event) break; case 2: qr.rem -= checkIncDecModel(event, qr.rem+2, 1, 62)-2; - timer->start -= qr.rem ; + timer->start -= qr.rem; if ((int16_t)timer->start < 0) timer->start=0; if ((int16_t)timer->start > 5999) timer->start=32399; // 8:59:59 break; @@ -585,7 +585,7 @@ void menuModelSetup(event_t event) break; case ITEM_MODEL_SETUP_THROTTLE_REVERSED: - ON_OFF_MENU_ITEM(g_model.throttleReversed, MODEL_SETUP_2ND_COLUMN, y, STR_THROTTLEREVERSE, attr, event ) ; + ON_OFF_MENU_ITEM(g_model.throttleReversed, MODEL_SETUP_2ND_COLUMN, y, STR_THROTTLEREVERSE, attr, event ); break; case ITEM_MODEL_SETUP_THROTTLE_TRACE: From 563761c114fa18c73cdb0885277614fa76f636c7 Mon Sep 17 00:00:00 2001 From: 3djc Date: Tue, 9 Jun 2020 08:35:08 +0200 Subject: [PATCH 54/93] Silence warning --- companion/src/modeledit/inputs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/companion/src/modeledit/inputs.cpp b/companion/src/modeledit/inputs.cpp index a5220019e..806de54fc 100644 --- a/companion/src/modeledit/inputs.cpp +++ b/companion/src/modeledit/inputs.cpp @@ -643,7 +643,7 @@ void InputsPanel::cmInputSwapData(int idx1, int idx2) } // move expos up const int offset = i - expoidx; - int expocnt; + int expocnt = 0; for (int j = i; j < CPN_MAX_EXPOS; j++) { ExpoData *ed = &model->expoData[j]; if ((int)ed->chn == idx2) { From 38f6d5772fc9344e664801b4cb30c17a4db443da Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Tue, 9 Jun 2020 10:46:22 +0200 Subject: [PATCH 55/93] Change binaries version (origin added: otx / frsky / tbs / radiomaster) --- companion/src/helpers.cpp | 1 - companion/src/mainwindow.cpp | 1 - companion/src/storage/firmwareinterface.cpp | 2 -- companion/src/storage/firmwareinterface.h | 2 -- radio/src/CMakeLists.txt | 5 +++++ radio/src/stamp.cpp | 18 ++++++++++-------- 6 files changed, 15 insertions(+), 14 deletions(-) diff --git a/companion/src/helpers.cpp b/companion/src/helpers.cpp index eb594b9b6..63b374062 100644 --- a/companion/src/helpers.cpp +++ b/companion/src/helpers.cpp @@ -565,7 +565,6 @@ QPixmap makePixMap(const QImage & image) return QPixmap::fromImage(result); } - int version2index(const QString & version) { int result = 999; diff --git a/companion/src/mainwindow.cpp b/companion/src/mainwindow.cpp index 2c230000b..4753e0b71 100644 --- a/companion/src/mainwindow.cpp +++ b/companion/src/mainwindow.cpp @@ -360,7 +360,6 @@ void MainWindow::checkForCompanionUpdateFinished(QNetworkReply * reply) return onUpdatesError(tr("Companion update check failed, new version information not found.")); int webVersion = version2index(version); - int ownVersion = version2index(VERSION); if (ownVersion < webVersion) { diff --git a/companion/src/storage/firmwareinterface.cpp b/companion/src/storage/firmwareinterface.cpp index 369af6504..f480ae527 100644 --- a/companion/src/storage/firmwareinterface.cpp +++ b/companion/src/storage/firmwareinterface.cpp @@ -36,7 +36,6 @@ FirmwareInterface::FirmwareInterface(const QString & filename): flash(FSIZE_MAX, 0), flashSize(0), - versionId(0), eepromVersion(0), eepromVariant(0), splashOffset(0), @@ -80,7 +79,6 @@ FirmwareInterface::FirmwareInterface(const QString & filename): eepromVersion = eepromId.toInt(); } - versionId = version2index(version); seekSplash(); isValidFlag = !version.isEmpty(); } diff --git a/companion/src/storage/firmwareinterface.h b/companion/src/storage/firmwareinterface.h index ce9aa994a..2912ec6ff 100644 --- a/companion/src/storage/firmwareinterface.h +++ b/companion/src/storage/firmwareinterface.h @@ -46,7 +46,6 @@ class FirmwareInterface QString getFlavour() const; bool isHardwareCompatible(const FirmwareInterface &previousFirmware) const; inline QString getVersion() { return version; } - unsigned int getVersionId() { return versionId; } inline int getEEpromVersion() { return eepromVersion; } inline int getEEpromVariant() { return eepromVariant; } inline QString getEEpromId() { return eepromId; } @@ -72,7 +71,6 @@ class FirmwareInterface QString time; QString flavour; QString version; - int versionId; QString eepromId; int eepromVersion; int eepromVariant; diff --git a/radio/src/CMakeLists.txt b/radio/src/CMakeLists.txt index 989457f92..61db95377 100644 --- a/radio/src/CMakeLists.txt +++ b/radio/src/CMakeLists.txt @@ -52,6 +52,7 @@ option(MODULE_PROTOCOL_FCC "Add support for FCC modules" ON) option(MODULE_PROTOCOL_LBT "Add support for EU/LBT modules" ON) option(MODULE_PROTOCOL_FLEX "Add support for non certified FLEX modules" OFF) option(MODULE_PROTOCOL_D8 "Add support for D8 modules" ON) +option(OTX_RELEASE "Used to build OpenTX released firmware" OFF) option(FRSKY_RELEASE "Used to build FrSky released firmware" OFF) option(TBS_RELEASE "Used to build TBS released firmware" OFF) option(ALLOW_TRAINER_MULTI "Allow multi trainer" OFF) @@ -336,6 +337,10 @@ if(MODULE_PROTOCOL_D8) add_definitions(-DMODULE_PROTOCOL_D8) endif() +if(OTX_RELEASE) + add_definitions(-DOTX_RELEASE) +endif() + if(JUMPER_RELEASE) add_definitions(-DJUMPER_RELEASE) endif() diff --git a/radio/src/stamp.cpp b/radio/src/stamp.cpp index f4f8b836a..06b601b69 100644 --- a/radio/src/stamp.cpp +++ b/radio/src/stamp.cpp @@ -33,26 +33,28 @@ #endif #if defined(FRSKY_RELEASE) -#define DISPLAY_VERSION "FrSky" +#define DISPLAY_VERSION "-frsky" #elif defined(JUMPER_RELEASE) -#define DISPLAY_VERSION "JumperRC" +#define DISPLAY_VERSION "-jumper" #elif defined(RADIOMASTER_RELEASE) -#define DISPLAY_VERSION "Radiomaster" +#define DISPLAY_VERSION "-radiomaster" #elif defined(TBS_RELEASE) -#define DISPLAY_VERSION "TBS" +#define DISPLAY_VERSION "-tbs" +#elif defined(OTX_RELEASE) +#define DISPLAY_VERSION "-otx" #else -#define DISPLAY_VERSION VERSION +#define DISPLAY_VERSION #endif #if defined(COLORLCD) - const char vers_stamp[] = "VERS" TAB ": " "opentx-" FLAVOUR "-" DISPLAY_VERSION " (" GIT_STR ")"; + const char vers_stamp[] = "VERS" TAB ": " "opentx-" FLAVOUR "-" VERSION DISPLAY_VERSION " (" GIT_STR ")"; const char date_stamp[] = "DATE" TAB ": " DATE; const char time_stamp[] = "TIME" TAB ": " TIME; const char eeprom_stamp[] = "EEPR" TAB ": " EEPROM_STR; #elif defined(BOARD_NAME) - const char vers_stamp[] = "FW" TAB ": opentx-" BOARD_NAME "\036VERS" TAB ": " DISPLAY_VERSION " (" GIT_STR ")" "\036DATE" TAB ": " DATE " " TIME "\036EEPR" TAB ": " EEPROM_STR; + const char vers_stamp[] = "FW" TAB ": opentx-" BOARD_NAME "\036VERS" TAB ": " VERSION DISPLAY_VERSION " (" GIT_STR ")" "\036DATE" TAB ": " DATE " " TIME "\036EEPR" TAB ": " EEPROM_STR; #else - const char vers_stamp[] = "FW" TAB ": opentx-" FLAVOUR "\036VERS" TAB ": " DISPLAY_VERSION " (" GIT_STR ")" "\036DATE" TAB ": " DATE " " TIME "\036EEPR" TAB ": " EEPROM_STR; + const char vers_stamp[] = "FW" TAB ": opentx-" FLAVOUR "\036VERS" TAB ": " VERSION DISPLAY_VERSION " (" GIT_STR ")" "\036DATE" TAB ": " DATE " " TIME "\036EEPR" TAB ": " EEPROM_STR; #endif /** From 8967b8356d3767b13f8fa856038553f7a590a2f0 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Tue, 9 Jun 2020 11:02:10 +0200 Subject: [PATCH 56/93] Remove unneeded extension --- radio/src/CMakeLists.txt | 5 ----- radio/src/stamp.cpp | 2 -- 2 files changed, 7 deletions(-) diff --git a/radio/src/CMakeLists.txt b/radio/src/CMakeLists.txt index 61db95377..989457f92 100644 --- a/radio/src/CMakeLists.txt +++ b/radio/src/CMakeLists.txt @@ -52,7 +52,6 @@ option(MODULE_PROTOCOL_FCC "Add support for FCC modules" ON) option(MODULE_PROTOCOL_LBT "Add support for EU/LBT modules" ON) option(MODULE_PROTOCOL_FLEX "Add support for non certified FLEX modules" OFF) option(MODULE_PROTOCOL_D8 "Add support for D8 modules" ON) -option(OTX_RELEASE "Used to build OpenTX released firmware" OFF) option(FRSKY_RELEASE "Used to build FrSky released firmware" OFF) option(TBS_RELEASE "Used to build TBS released firmware" OFF) option(ALLOW_TRAINER_MULTI "Allow multi trainer" OFF) @@ -337,10 +336,6 @@ if(MODULE_PROTOCOL_D8) add_definitions(-DMODULE_PROTOCOL_D8) endif() -if(OTX_RELEASE) - add_definitions(-DOTX_RELEASE) -endif() - if(JUMPER_RELEASE) add_definitions(-DJUMPER_RELEASE) endif() diff --git a/radio/src/stamp.cpp b/radio/src/stamp.cpp index 06b601b69..0c90f5c71 100644 --- a/radio/src/stamp.cpp +++ b/radio/src/stamp.cpp @@ -40,8 +40,6 @@ #define DISPLAY_VERSION "-radiomaster" #elif defined(TBS_RELEASE) #define DISPLAY_VERSION "-tbs" -#elif defined(OTX_RELEASE) -#define DISPLAY_VERSION "-otx" #else #define DISPLAY_VERSION #endif From 9f41e81fc99b929c7f70892220119891a3ca20e1 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Tue, 9 Jun 2020 11:10:02 +0200 Subject: [PATCH 57/93] Compilation fix when no multimodule on X9D+ --- radio/src/gui/gui_common.h | 1 + 1 file changed, 1 insertion(+) diff --git a/radio/src/gui/gui_common.h b/radio/src/gui/gui_common.h index 3aeee3128..4fbd63194 100644 --- a/radio/src/gui/gui_common.h +++ b/radio/src/gui/gui_common.h @@ -264,6 +264,7 @@ inline uint8_t MULTIMODULE_HASOPTIONS(uint8_t moduleIdx) #else #define MULTIMODULE_STATUS_ROWS(moduleIdx) #define MULTIMODULE_MODULE_ROWS(moduleIdx) +#define MULTIMODULE_TYPE_ROW(moduleIdx) #define MULTIMODULE_SUBTYPE_ROWS(moduleIdx) #define MULTIMODULE_TYPE_ROWS(moduleIdx) #define MULTIMODULE_MODE_ROWS(moduleIdx) (uint8_t)0 From 2a8c1f914dfeb6200c338063e1197d78dd8907ed Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Wed, 10 Jun 2020 12:16:50 +0200 Subject: [PATCH 58/93] FrSky build script updated (new boards added) --- radio/src/opentx.cpp | 2 +- tools/build-frsky.py | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/radio/src/opentx.cpp b/radio/src/opentx.cpp index 9e5ced95e..3186e8975 100644 --- a/radio/src/opentx.cpp +++ b/radio/src/opentx.cpp @@ -765,7 +765,7 @@ void doSplash() } #endif -#if defined(FRSKY_RELEASE) +#if defined(FRSKY_RELEASE) && !defined(COLORLCD) static uint8_t secondSplash = false; if (!secondSplash && get_tmr10ms() >= tgtime-200) { secondSplash = true; diff --git a/tools/build-frsky.py b/tools/build-frsky.py index e4478a2a8..5a5cb26ac 100755 --- a/tools/build-frsky.py +++ b/tools/build-frsky.py @@ -87,6 +87,14 @@ boards = { "CROSSFIRE": "NO", "DEFAULT_MODE": "2", }, + "X9E": { + "PCB": "X9E", + "LUA": "NO_MODEL_SCRIPTS", + "GVARS": "YES", + "MULTIMODULE": "NO", + "CROSSFIRE": "NO", + "DEFAULT_MODE": "2", + }, "X7_FCC": { "PCB": "X7", "LUA": "NO_MODEL_SCRIPTS", @@ -114,7 +122,32 @@ boards = { "MULTIMODULE": "NO", "CROSSFIRE": "NO", "DEFAULT_MODE": "2", - } + }, + "X10S": { + "PCB": "X10", + "LUA": "NO_MODEL_SCRIPTS", + "GVARS": "YES", + "MULTIMODULE": "NO", + "CROSSFIRE": "NO", + "DEFAULT_MODE": "2", + }, + "X10SExpress": { + "PCB": "X10", + "PCBREV": "EXPRESS", + "LUA": "NO_MODEL_SCRIPTS", + "GVARS": "YES", + "MULTIMODULE": "NO", + "CROSSFIRE": "NO", + "DEFAULT_MODE": "2", + }, + "X12S": { + "PCB": "X12S", + "LUA": "NO_MODEL_SCRIPTS", + "GVARS": "YES", + "MULTIMODULE": "NO", + "CROSSFIRE": "NO", + "DEFAULT_MODE": "2", + }, } translations = [ From 4eed0ae7601cd146fded9b789a0a4d3f5e35caf1 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Thu, 11 Jun 2020 09:28:18 +0200 Subject: [PATCH 59/93] Update CREDITS.txt --- CREDITS.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CREDITS.txt b/CREDITS.txt index a7c69bff2..4394e66db 100644 --- a/CREDITS.txt +++ b/CREDITS.txt @@ -1739,3 +1739,4 @@ James Thompson Dautremépuis Benoit Adriano Emanuele Figliola Stefano Bortolotti +Gerald Zierer From 054117722497ffba0fb36a5f2a74cf1c63381ca4 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Sat, 13 Jun 2020 10:15:03 +0200 Subject: [PATCH 60/93] Update CREDITS.txt --- CREDITS.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CREDITS.txt b/CREDITS.txt index 4394e66db..2df7ffa7a 100644 --- a/CREDITS.txt +++ b/CREDITS.txt @@ -1740,3 +1740,4 @@ Dautremépuis Benoit Adriano Emanuele Figliola Stefano Bortolotti Gerald Zierer +Alessio Noto From 5198b9a8a7b632f850e78d2f85d8c6d8925665bc Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Fri, 12 Jun 2020 11:22:06 +0200 Subject: [PATCH 61/93] Attempt to fix the progress bar issue on Companion Read Firmware function (DFU mode) --- companion/src/downloaddialog.cpp | 2 +- companion/src/flashfirmwaredialog.cpp | 2 +- companion/src/process_flash.cpp | 17 ++++++++++++++--- companion/src/radiointerface.cpp | 3 +-- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/companion/src/downloaddialog.cpp b/companion/src/downloaddialog.cpp index 3f70e6529..d5c037645 100644 --- a/companion/src/downloaddialog.cpp +++ b/companion/src/downloaddialog.cpp @@ -54,7 +54,7 @@ DownloadDialog::DownloadDialog(QWidget *parent, QString src, QString tgt): reply = qnam.get(QNetworkRequest(QUrl(src))); connect(reply, SIGNAL(finished()), this, SLOT(httpFinished())); connect(reply, SIGNAL(readyRead()), this, SLOT(httpReadyRead())); - connect(reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(updateDataReadProgress(qint64,qint64))); + connect(reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(updateDataReadProgress(qint64, qint64))); } } diff --git a/companion/src/flashfirmwaredialog.cpp b/companion/src/flashfirmwaredialog.cpp index 9a2b688ab..fd6046f92 100644 --- a/companion/src/flashfirmwaredialog.cpp +++ b/companion/src/flashfirmwaredialog.cpp @@ -112,7 +112,7 @@ void FlashFirmwareDialog::updateUI() } QImage image; - switch(imageSource) { + switch (imageSource) { case FIRMWARE: ui->useFirmwareSplash->setChecked(true); image = firmware.getSplash(); diff --git a/companion/src/process_flash.cpp b/companion/src/process_flash.cpp index 599d7e653..22baa83c6 100644 --- a/companion/src/process_flash.cpp +++ b/companion/src/process_flash.cpp @@ -134,15 +134,18 @@ void FlashProcess::onKillTimerElapsed() #endif } -void FlashProcess::analyseStandardOutput(const QString &text) +void FlashProcess::analyseStandardOutput(const QString & text) { + +// qDebug() << text; + currStdoutLine.append(text); if (currStdoutLine.contains("size = ")) { int pos = currStdoutLine.lastIndexOf("size = "); QString temp = currStdoutLine.mid(pos+7); pos = temp.lastIndexOf("\n"); int size = temp.left(pos).toInt(); - progress->setMaximum(size/2048); + progress->setMaximum(size / 2048); } if (currStdoutLine.contains("\n")) { int nlPos = currStdoutLine.lastIndexOf("\n"); @@ -168,7 +171,15 @@ void FlashProcess::analyseStandardOutput(const QString &text) int end = text.indexOf("%"); if (start > 0) { start += 9; - int value = text.mid(start, end-start).toInt(); + int value = text.mid(start, end - start).toInt(); + progress->setValue(value); + } + } + + if (text.contains("Upload\t[")) { + int end = text.indexOf("%"); + if (end > 0) { + int value = text.mid(end - 3, 3).toInt(); progress->setValue(value); } } diff --git a/companion/src/radiointerface.cpp b/companion/src/radiointerface.cpp index c3214958a..fbc03186f 100644 --- a/companion/src/radiointerface.cpp +++ b/companion/src/radiointerface.cpp @@ -253,7 +253,6 @@ void resetAvrdudeFuses(bool eepromProtect, ProgressWidget * progress) } } - bool readFirmware(const QString & filename, ProgressWidget * progress) { bool result = false; @@ -274,7 +273,7 @@ bool readFirmware(const QString & filename, ProgressWidget * progress) } } - if (result == false) { + if (!result) { qDebug() << "readFirmware: reading" << filename << "with" << getRadioInterfaceCmd() << getReadFirmwareArgs(filename); FlashProcess flashProcess(getRadioInterfaceCmd(), getReadFirmwareArgs(filename), progress); result = flashProcess.run(); From 281daa7a671de8a692c3eb09a318bd1999c1bf8b Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Fri, 12 Jun 2020 14:47:52 +0200 Subject: [PATCH 62/93] Attempt to fix the progress bar issue on Companion Read Firmware function on Windows, dfu-util 0.7 (DFU mode) --- companion/src/process_flash.cpp | 12 ++++++++---- companion/src/process_flash.h | 4 ++-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/companion/src/process_flash.cpp b/companion/src/process_flash.cpp index 22baa83c6..77a77ea4d 100644 --- a/companion/src/process_flash.cpp +++ b/companion/src/process_flash.cpp @@ -136,10 +136,8 @@ void FlashProcess::onKillTimerElapsed() void FlashProcess::analyseStandardOutput(const QString & text) { - -// qDebug() << text; - currStdoutLine.append(text); + if (currStdoutLine.contains("size = ")) { int pos = currStdoutLine.lastIndexOf("size = "); QString temp = currStdoutLine.mid(pos+7); @@ -147,17 +145,23 @@ void FlashProcess::analyseStandardOutput(const QString & text) int size = temp.left(pos).toInt(); progress->setMaximum(size / 2048); } + if (currStdoutLine.contains("\n")) { int nlPos = currStdoutLine.lastIndexOf("\n"); currStdoutLine = currStdoutLine.mid(nlPos+1); } + if (!currStdoutLine.isEmpty()) { if (currStdoutLine.at(0) == QChar('.')) { int pos = currStdoutLine.lastIndexOf("."); progress->setValue(pos); } else if (currStdoutLine.startsWith("Starting upload: [")) { - int pos = (currStdoutLine.lastIndexOf("#")-19)*100/256; + int pos = (currStdoutLine.lastIndexOf("#") - 19) * 100 / 256; + progress->setValue(pos); + } + else if (currStdoutLine.startsWith("[") && progress->getText().contains("bytes_per_hash=2048")) { + int pos = (currStdoutLine.lastIndexOf("#") - 1) * 2048 / (2 * 1024 * 1024); // TODO depends on bin size progress->setValue(pos); } } diff --git a/companion/src/process_flash.h b/companion/src/process_flash.h index c39be2644..530938590 100644 --- a/companion/src/process_flash.h +++ b/companion/src/process_flash.h @@ -53,10 +53,10 @@ protected: void analyseStandardError(const QString &text); void errorWizard(); void addReadFuses(); - ProgressWidget *progress; + ProgressWidget * progress; const QString cmd; const QStringList args; - QProcess *process; + QProcess * process; bool hasErrors; QString currStdoutLine; QString currStderrLine; From e494f043cf3a483f0250f0dc0fda0c9a890aacde Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Fri, 12 Jun 2020 17:13:45 +0200 Subject: [PATCH 63/93] Attempt to fix the progress bar issue on Companion Read Firmware function on Windows, dfu-util 0.7 (DFU mode) --- companion/src/process_flash.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/companion/src/process_flash.cpp b/companion/src/process_flash.cpp index 77a77ea4d..50a07e522 100644 --- a/companion/src/process_flash.cpp +++ b/companion/src/process_flash.cpp @@ -161,7 +161,7 @@ void FlashProcess::analyseStandardOutput(const QString & text) progress->setValue(pos); } else if (currStdoutLine.startsWith("[") && progress->getText().contains("bytes_per_hash=2048")) { - int pos = (currStdoutLine.lastIndexOf("#") - 1) * 2048 / (2 * 1024 * 1024); // TODO depends on bin size + int pos = (currStdoutLine.lastIndexOf("#") - 1) * 2048 * 100 / (2 * 1024 * 1024); // TODO depends on bin size progress->setValue(pos); } } From b795a72ef43a046eaeae6f7d1abcf9325ae7951d Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Sat, 13 Jun 2020 12:46:38 +0200 Subject: [PATCH 64/93] Cosmetics (bootloader title bar) --- companion/src/process_flash.cpp | 2 +- companion/src/storage/firmwareinterface.cpp | 2 +- radio/src/targets/common/arm/stm32/bootloader/boot.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/companion/src/process_flash.cpp b/companion/src/process_flash.cpp index 50a07e522..ca8c3479e 100644 --- a/companion/src/process_flash.cpp +++ b/companion/src/process_flash.cpp @@ -292,7 +292,7 @@ void FlashProcess::errorWizard() DeviceStr = "Atmega 2561"; } } - if (fwexist==false) { + if (!fwexist) { QMessageBox::warning(nullptr, "Companion - Tip of the day", tr("Your radio uses a %1 CPU!!!\n\nPlease check advanced burn options to set the correct cpu type.").arg(DeviceStr)); } else { diff --git a/companion/src/storage/firmwareinterface.cpp b/companion/src/storage/firmwareinterface.cpp index f480ae527..a07ebbd67 100644 --- a/companion/src/storage/firmwareinterface.cpp +++ b/companion/src/storage/firmwareinterface.cpp @@ -64,7 +64,7 @@ FirmwareInterface::FirmwareInterface(const QString & filename): // old version format int index = version.lastIndexOf('-'); flavour = version.mid(0, index); - version = version.mid(index+1); + version = version.mid(index + 1); } date = seekLabel(DATE_MARK); time = seekLabel(TIME_MARK); diff --git a/radio/src/targets/common/arm/stm32/bootloader/boot.h b/radio/src/targets/common/arm/stm32/bootloader/boot.h index 4f8e7edc7..13e6e3036 100644 --- a/radio/src/targets/common/arm/stm32/bootloader/boot.h +++ b/radio/src/targets/common/arm/stm32/bootloader/boot.h @@ -24,7 +24,7 @@ #include "stamp.h" #if LCD_W < 212 - #define BOOTLOADER_TITLE " OTX Bootloader - " VERSION + #define BOOTLOADER_TITLE " Bootloader - " VERSION #else #define BOOTLOADER_TITLE " OpenTX Bootloader - " VERSION #endif From edf65f0b282a2b64ee5896a711f8971d8b9d1900 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Sat, 13 Jun 2020 12:50:44 +0200 Subject: [PATCH 65/93] Version parsing fix --- companion/src/helpers.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/companion/src/helpers.cpp b/companion/src/helpers.cpp index 63b374062..2b0f62503 100644 --- a/companion/src/helpers.cpp +++ b/companion/src/helpers.cpp @@ -580,6 +580,10 @@ int version2index(const QString & version) result = parts[1].toInt(); // nightly build up to 899 mainVersion = parts[0]; } + else if (version.contains("-")) { + parts = version.split("-"); + mainVersion = parts[0]; + } parts = mainVersion.split('.'); if (parts.size() > 2) result += 1000 * parts[2].toInt(); From e9728d263c619357c99e3c234f60e9fb10a5dc7d Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Sat, 13 Jun 2020 12:52:27 +0200 Subject: [PATCH 66/93] Revert last non working Progress bar for Windows fix --- companion/src/process_flash.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/companion/src/process_flash.cpp b/companion/src/process_flash.cpp index ca8c3479e..502b3c7ca 100644 --- a/companion/src/process_flash.cpp +++ b/companion/src/process_flash.cpp @@ -160,10 +160,6 @@ void FlashProcess::analyseStandardOutput(const QString & text) int pos = (currStdoutLine.lastIndexOf("#") - 19) * 100 / 256; progress->setValue(pos); } - else if (currStdoutLine.startsWith("[") && progress->getText().contains("bytes_per_hash=2048")) { - int pos = (currStdoutLine.lastIndexOf("#") - 1) * 2048 * 100 / (2 * 1024 * 1024); // TODO depends on bin size - progress->setValue(pos); - } } if (text.contains("Complete ")) { From 18461a3b28105ccd730699ab59decf92f762cda2 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Sat, 13 Jun 2020 14:26:25 +0200 Subject: [PATCH 67/93] Progressbar for "Download firmware" --- companion/src/process_flash.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/companion/src/process_flash.cpp b/companion/src/process_flash.cpp index 502b3c7ca..ee01e29d0 100644 --- a/companion/src/process_flash.cpp +++ b/companion/src/process_flash.cpp @@ -176,7 +176,7 @@ void FlashProcess::analyseStandardOutput(const QString & text) } } - if (text.contains("Upload\t[")) { + if (text.contains("Upload\t[") || text.contains("Download\t[")) { int end = text.indexOf("%"); if (end > 0) { int value = text.mid(end - 3, 3).toInt(); From 24cd7611cf62c39e1f9e6a61b49ecd5d827962ba Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Sat, 13 Jun 2020 14:59:13 +0200 Subject: [PATCH 68/93] Bootloader cosmetics --- radio/src/gui/128x64/lcd.cpp | 20 ++++++---- radio/src/gui/128x64/lcd.h | 4 +- radio/src/gui/212x64/lcd.cpp | 18 +++++---- radio/src/opentx.h | 2 +- radio/src/stamp.cpp | 28 ++++++-------- .../common/arm/stm32/bootloader/bin_files.cpp | 6 +-- .../common/arm/stm32/bootloader/boot.h | 4 +- .../common/arm/stm32/usbd_storage_msd.cpp | 10 ++--- .../targets/horus/bootloader/boot_menu.cpp | 2 +- .../targets/taranis/bootloader/boot_menu.cpp | 37 +++++++++---------- 10 files changed, 64 insertions(+), 67 deletions(-) diff --git a/radio/src/gui/128x64/lcd.cpp b/radio/src/gui/128x64/lcd.cpp index f3adae2ca..9118fef5d 100644 --- a/radio/src/gui/128x64/lcd.cpp +++ b/radio/src/gui/128x64/lcd.cpp @@ -116,7 +116,6 @@ void lcdPutPattern(coord_t x, coord_t y, const uint8_t * pattern, uint8_t width, } } -#if !defined(BOOT) struct PatternData { uint8_t width; @@ -143,10 +142,11 @@ uint8_t getPatternWidth(const PatternData * pattern) void getCharPattern(PatternData * pattern, unsigned char c, LcdFlags flags) { +#if !defined(BOOT) 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<=':') @@ -203,6 +203,11 @@ void getCharPattern(PatternData * pattern, unsigned char c, LcdFlags flags) pattern->height = 7; pattern->data = (c < 0xC0) ? &font_5x7[(c-0x20)*5] : &font_5x7_extra[(c-0xC0)*5]; } +#else + pattern->width = 5; + pattern->height = 7; + pattern->data = &font_5x7[(c-0x20)*5]; +#endif } uint8_t getCharWidth(char c, LcdFlags flags) @@ -211,7 +216,6 @@ uint8_t getCharWidth(char c, LcdFlags flags) getCharPattern(&pattern, c, flags); return getPatternWidth(&pattern); } -#endif void lcdDrawChar(coord_t x, coord_t y, const unsigned char c, LcdFlags flags) { @@ -288,12 +292,15 @@ void lcdDrawChar(coord_t x, coord_t y, const unsigned char c) lcdDrawChar(x, y, c, 0); } -#if !defined(BOOT) uint8_t getTextWidth(const char * s, uint8_t len, LcdFlags flags) { uint8_t width = 0; - for (int i=0; len==0 || iheight = 7; pattern->data = (c < 0xC0) ? &font_5x7[(c-0x20)*5] : &font_5x7_extra[(c-0xC0)*5]; } +#else + pattern->width = 5; + pattern->height = 7; + pattern->data = &font_5x7[(c-0x20) * 5]; +#endif } uint8_t getCharWidth(char c, LcdFlags flags) @@ -220,7 +225,6 @@ uint8_t getCharWidth(char c, LcdFlags flags) getCharPattern(&pattern, c, flags); return getPatternWidth(&pattern); } -#endif void lcdDrawChar(coord_t x, coord_t y, const unsigned char c, LcdFlags flags) { @@ -240,12 +244,15 @@ void lcdDrawChar(coord_t x, coord_t y, const unsigned char c) lcdDrawChar(x, y, c, 0); } -#if !defined(BOOT) uint8_t getTextWidth(const char * s, uint8_t len, LcdFlags flags) { uint8_t width = 0; - for (int i=0; len==0 || iflavour, "unknown", sizeof("unknown")); - tag->version = "unknown"; + memcpy(tag->flavour, "unknown", sizeof("unknown")); + tag->version = "unknown"; } // skip "opentx-" diff --git a/radio/src/targets/common/arm/stm32/bootloader/boot.h b/radio/src/targets/common/arm/stm32/bootloader/boot.h index 13e6e3036..c9e36269b 100644 --- a/radio/src/targets/common/arm/stm32/bootloader/boot.h +++ b/radio/src/targets/common/arm/stm32/bootloader/boot.h @@ -34,12 +34,12 @@ #if LCD_W >= 480 #define STR_INVALID_FIRMWARE "Not a valid firmware file" #elif LCD_W >= 212 - #define STR_OR_PLUGIN_USB_CABLE INDENT "Or plug in a USB cable for mass storage" + #define STR_OR_PLUGIN_USB_CABLE "Or plug in a USB cable for mass storage" #define STR_HOLD_ENTER_TO_START "\012Hold [ENT] to start writing" #define STR_INVALID_FIRMWARE "\011Not a valid firmware file! " #define STR_INVALID_EEPROM "\011Not a valid EEPROM file! " #else - #define STR_OR_PLUGIN_USB_CABLE INDENT "Or plug in a USB cable" + #define STR_OR_PLUGIN_USB_CABLE "Or plug in a USB cable" #define STR_HOLD_ENTER_TO_START "\006Hold [ENT] to start" #define STR_INVALID_FIRMWARE "\004Not a valid firmware! " #define STR_INVALID_EEPROM "\004Not a valid EEPROM! " diff --git a/radio/src/targets/common/arm/stm32/usbd_storage_msd.cpp b/radio/src/targets/common/arm/stm32/usbd_storage_msd.cpp index b60e5da8f..1fbfb970a 100644 --- a/radio/src/targets/common/arm/stm32/usbd_storage_msd.cpp +++ b/radio/src/targets/common/arm/stm32/usbd_storage_msd.cpp @@ -408,7 +408,7 @@ const FATDirEntry_t g_DIRroot[] = 0xA302, 0x3D55, 0x0002, - sizeof(firmware_txt) + strlen(getOtherVersion(nullptr)) + sizeof(firmware_txt) + strlen(getFirmwareVersion()) }, { { 'F', 'I', 'R', 'M', 'W', 'A', 'R', 'E'}, @@ -512,13 +512,11 @@ int32_t fat12Read(uint8_t * buffer, uint16_t sector, uint16_t count) else if (sector == 3) { memcpy(buffer, g_DIRroot, sizeof(g_DIRroot) ) ; } - else if (sector == 4) - { + else if (sector == 4) { memcpy(buffer, firmware_txt, sizeof(firmware_txt)); - memcpy(buffer + sizeof(firmware_txt), getOtherVersion(nullptr), strlen(getOtherVersion(nullptr))); + strcpy((char *)(buffer + sizeof(firmware_txt)), getFirmwareVersion()); } - else if (sector < RESERVED_SECTORS) - { + else if (sector < RESERVED_SECTORS) { // allocated to firmware.txt } else if (sector < RESERVED_SECTORS + (FLASHSIZE/BLOCK_SIZE )) { diff --git a/radio/src/targets/horus/bootloader/boot_menu.cpp b/radio/src/targets/horus/bootloader/boot_menu.cpp index d64f2c7f8..025b0d7ef 100644 --- a/radio/src/targets/horus/bootloader/boot_menu.cpp +++ b/radio/src/targets/horus/bootloader/boot_menu.cpp @@ -84,7 +84,7 @@ void bootloaderDrawScreen(BootloaderState st, int opt, const char* str) bootloaderDrawFooter(); lcdDrawText( 36, 242, "Current Firmware:"); - lcdDrawText(200, 242, getOtherVersion(nullptr)); + lcdDrawText(200, 242, getFirmwareVersion()); } else if (st == ST_USB) { diff --git a/radio/src/targets/taranis/bootloader/boot_menu.cpp b/radio/src/targets/taranis/bootloader/boot_menu.cpp index 4a2eb1497..d6f6a86ac 100644 --- a/radio/src/targets/taranis/bootloader/boot_menu.cpp +++ b/radio/src/targets/taranis/bootloader/boot_menu.cpp @@ -21,28 +21,25 @@ void bootloaderDrawFilename(const char *str, uint8_t line, bool selected) void bootloaderDrawScreen(BootloaderState st, int opt, const char *str) { lcdClear(); - lcdDrawText(0, 0, BOOTLOADER_TITLE, INVERS); + lcdDrawText(LCD_W / 2, 0, BOOTLOADER_TITLE, CENTERED); + lcdInvertLine(0); if (st == ST_START) { lcdDrawTextAlignedLeft(2*FH, "\010Write Firmware"); lcdDrawTextAlignedLeft(3*FH, "\010Restore EEPROM"); lcdDrawTextAlignedLeft(4*FH, "\010Exit"); - -#if LCD_W >= 212 - lcdDrawTextAlignedLeft(6*FH, "\001Curr FW:"); - lcdDrawText(50, 6*FH, getOtherVersion(nullptr)); -#else - lcdDrawTextAlignedLeft(6 * FH, "\001FW:"); - - // Remove opentx- from string - const char *other_ver = getOtherVersion(nullptr); - if (strstr(other_ver, "opentx-")) - other_ver = other_ver + 7; - lcdDrawText(20, 6 * FH, other_ver); -#endif - lcdInvertLine(2 + opt); - lcdDrawTextAlignedLeft(7 * FH, STR_OR_PLUGIN_USB_CABLE); + + lcdDrawText(LCD_W / 2, 5 * FH + FH / 2, STR_OR_PLUGIN_USB_CABLE, CENTERED); + + // Remove "opentx-" from string + const char * vers = getFirmwareVersion(); +#if LCD_W < 212 + if (strncmp(vers, "opentx-", 7) == 0) + vers += 7; +#endif + lcdDrawText(LCD_W / 2, 7 * FH, vers, CENTERED); + lcdInvertLine(7); } else if (st == ST_USB) { lcdDrawTextAlignedLeft(4 * FH, STR_USB_CONNECTED); @@ -65,11 +62,11 @@ void bootloaderDrawScreen(BootloaderState st, int opt, const char *str) } else if (opt == FC_OK) { if (memoryType == MEM_FLASH) { - const char * vers = getOtherVersion((char *) Block_buffer); + const char * vers = getFirmwareVersion((const char *)Block_buffer); #if LCD_W < 212 - // Remove opentx- from string - if (strstr(vers, "opentx-")) - vers = vers + 7; + // Remove "opentx-" from string + if (strncmp(vers, "opentx-", 7) == 0) + vers += 7; #endif bootloaderDrawMsg(INDENT_WIDTH, vers, 0, false); } From 977846d7091dd434d2e3d6449a0250fb1037b07f Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Sat, 13 Jun 2020 15:06:58 +0200 Subject: [PATCH 69/93] Bootloader cosmetics on Horus now --- .../targets/horus/bootloader/boot_menu.cpp | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/radio/src/targets/horus/bootloader/boot_menu.cpp b/radio/src/targets/horus/bootloader/boot_menu.cpp index 025b0d7ef..911d98b43 100644 --- a/radio/src/targets/horus/bootloader/boot_menu.cpp +++ b/radio/src/targets/horus/bootloader/boot_menu.cpp @@ -67,24 +67,22 @@ void bootloaderDrawScreen(BootloaderState st, int opt, const char* str) lcdDrawSolidFilledRect(0, 0, LCD_W, LCD_H, TEXT_BGCOLOR); if (st == ST_START) { + bootloaderDrawTitle(88, BOOTLOADER_TITLE); - bootloaderDrawTitle(88, BOOTLOADER_TITLE); - - lcdDrawBitmapPattern(90, 72, LBM_FLASH, TEXT_COLOR); - lcdDrawText(124, 75, "Write Firmware"); + lcdDrawBitmapPattern(90, 72, LBM_FLASH, TEXT_COLOR); + lcdDrawText(124, 75, "Write Firmware"); - lcdDrawBitmapPattern(90, 107, LBM_EXIT, TEXT_COLOR); - lcdDrawText(124, 110, "Exit"); + lcdDrawBitmapPattern(90, 107, LBM_EXIT, TEXT_COLOR); + lcdDrawText(124, 110, "Exit"); - lcdDrawSolidRect(119, (opt == 0) ? 72 : 107, 270, 26, 2, LINE_COLOR); - - lcd->drawBitmap(60, 166, &BMP_PLUG_USB); - lcdDrawText(195, 175, "Or plug in a USB cable"); - lcdDrawText(195, 200, "for mass storage"); + lcdDrawSolidRect(119, (opt == 0) ? 72 : 107, 270, 26, 2, LINE_COLOR); - bootloaderDrawFooter(); - lcdDrawText( 36, 242, "Current Firmware:"); - lcdDrawText(200, 242, getFirmwareVersion()); + lcd->drawBitmap(60, 166, &BMP_PLUG_USB); + lcdDrawText(195, 175, "Or plug in a USB cable"); + lcdDrawText(195, 200, "for mass storage"); + + bootloaderDrawFooter(); + lcdDrawText(LCD_W / 2, 242, getFirmwareVersion(), CENTERED); } else if (st == ST_USB) { From 51ab3b1939bd82ff3f1f03cfa255481eaccf2625 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Sat, 13 Jun 2020 15:14:44 +0200 Subject: [PATCH 70/93] Update CREDITS.txt --- CREDITS.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CREDITS.txt b/CREDITS.txt index 2df7ffa7a..0fd19015e 100644 --- a/CREDITS.txt +++ b/CREDITS.txt @@ -1741,3 +1741,4 @@ Adriano Emanuele Figliola Stefano Bortolotti Gerald Zierer Alessio Noto +Walter Fowler From 17db3dff101380ad8b210b254984683845fa675f Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Sat, 13 Jun 2020 15:19:34 +0200 Subject: [PATCH 71/93] Bootloader cosmetics again --- radio/src/targets/taranis/bootloader/boot_menu.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/radio/src/targets/taranis/bootloader/boot_menu.cpp b/radio/src/targets/taranis/bootloader/boot_menu.cpp index d6f6a86ac..b1d1a9a50 100644 --- a/radio/src/targets/taranis/bootloader/boot_menu.cpp +++ b/radio/src/targets/taranis/bootloader/boot_menu.cpp @@ -25,10 +25,9 @@ void bootloaderDrawScreen(BootloaderState st, int opt, const char *str) lcdInvertLine(0); if (st == ST_START) { - lcdDrawTextAlignedLeft(2*FH, "\010Write Firmware"); - lcdDrawTextAlignedLeft(3*FH, "\010Restore EEPROM"); - lcdDrawTextAlignedLeft(4*FH, "\010Exit"); - lcdInvertLine(2 + opt); + lcdDrawText(3*FW, 2*FH, "Write Firmware", opt == 0 ? INVERS : 0); + lcdDrawText(3*FW, 3*FH, "Restore EEPROM", opt == 1 ? INVERS : 0); + lcdDrawText(3*FW, 4*FH, "Exit", opt == 2 ? INVERS : 0); lcdDrawText(LCD_W / 2, 5 * FH + FH / 2, STR_OR_PLUGIN_USB_CABLE, CENTERED); From 89efdadba7fc88802b862a7c26669ed00ccc77fb Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Sun, 14 Jun 2020 18:16:31 +0200 Subject: [PATCH 72/93] Update CREDITS.txt --- CREDITS.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CREDITS.txt b/CREDITS.txt index 0fd19015e..52ec9a9a8 100644 --- a/CREDITS.txt +++ b/CREDITS.txt @@ -1742,3 +1742,8 @@ Stefano Bortolotti Gerald Zierer Alessio Noto Walter Fowler +Robert Black +Klaus Kernstock +Michael Wittich +AG-Software +Dietmar Drees From 23aaafbfa27fd306e2491702cf03b632d8ea89af Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Sun, 14 Jun 2020 18:41:37 +0200 Subject: [PATCH 73/93] Fixes #7731 --- companion/src/downloaddialog.cpp | 2 +- companion/src/flashfirmwaredialog.cpp | 3 +-- companion/src/storage/firmwareinterface.h | 2 +- radio/src/stamp.cpp | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/companion/src/downloaddialog.cpp b/companion/src/downloaddialog.cpp index d5c037645..5b9b2dfa0 100644 --- a/companion/src/downloaddialog.cpp +++ b/companion/src/downloaddialog.cpp @@ -114,7 +114,7 @@ void DownloadDialog::updateDataReadProgress(qint64 bytesRead, qint64 totalBytes) void DownloadDialog::fileError() { delete file; - file = NULL; + file = nullptr; reject(); } diff --git a/companion/src/flashfirmwaredialog.cpp b/companion/src/flashfirmwaredialog.cpp index fd6046f92..4650cd4c0 100644 --- a/companion/src/flashfirmwaredialog.cpp +++ b/companion/src/flashfirmwaredialog.cpp @@ -21,7 +21,6 @@ #include "flashfirmwaredialog.h" #include "ui_flashfirmwaredialog.h" #include "appdata.h" -#include "process_flash.h" #include "helpers.h" #include "progressdialog.h" #include "radiointerface.h" @@ -202,7 +201,7 @@ void FlashFirmwareDialog::on_useExternalSplash_clicked() void FlashFirmwareDialog::on_useLibrarySplash_clicked() { QString fileName; - SplashLibraryDialog *ld = new SplashLibraryDialog(this, &fileName); + auto ld = new SplashLibraryDialog(this, &fileName); ld->exec(); if (!fileName.isEmpty()) { QImage image(fileName); diff --git a/companion/src/storage/firmwareinterface.h b/companion/src/storage/firmwareinterface.h index 2912ec6ff..d6dee286b 100644 --- a/companion/src/storage/firmwareinterface.h +++ b/companion/src/storage/firmwareinterface.h @@ -39,7 +39,7 @@ class FirmwareInterface { public: - FirmwareInterface(const QString &filename); + FirmwareInterface(const QString & filename); inline QString getDate() { return date; } inline QString getTime() { return time; } int getSize() { return flashSize; } diff --git a/radio/src/stamp.cpp b/radio/src/stamp.cpp index 31deb5486..e8b67bdff 100644 --- a/radio/src/stamp.cpp +++ b/radio/src/stamp.cpp @@ -45,7 +45,7 @@ #endif #if defined(COLORLCD) - const char vers_stamp[] = "VERS" TAB ": " "opentx-" FLAVOUR "-" VERSION DISPLAY_VERSION " (" GIT_STR ")"; + const char vers_stamp[] = "VERS" TAB ": " VERSION DISPLAY_VERSION " (" GIT_STR ")"; const char date_stamp[] = "DATE" TAB ": " DATE; const char time_stamp[] = "TIME" TAB ": " TIME; const char eeprom_stamp[] = "EEPR" TAB ": " EEPROM_STR; From d4e11966cd21b4a5c142ab1e7dc7fb1e281d9468 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Sun, 14 Jun 2020 18:42:22 +0200 Subject: [PATCH 74/93] Bump to 2.3.9 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e0e9d6bad..23596aff6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ project(OpenTX) set(VERSION_MAJOR "2") set(VERSION_MINOR "3") -set(VERSION_REVISION "8") +set(VERSION_REVISION "9") set(VERSION_SUFFIX $ENV{OPENTX_VERSION_SUFFIX}) set(VERSION_FAMILY ${VERSION_MAJOR}.${VERSION_MINOR}) set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_REVISION}${VERSION_SUFFIX}) From 60e1edc15936aeda3be2294fc981261357c1849a Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Sun, 14 Jun 2020 18:46:28 +0200 Subject: [PATCH 75/93] Fixes #7734 --- radio/src/mixer.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/radio/src/mixer.cpp b/radio/src/mixer.cpp index 373981044..3f373ae6e 100644 --- a/radio/src/mixer.cpp +++ b/radio/src/mixer.cpp @@ -947,7 +947,7 @@ void evalMixes(uint8_t tick10ms) mixerCurrentFlightMode = p; evalFlightModeMixes(p==fm ? e_perout_mode_normal : e_perout_mode_inactive_flight_mode, p==fm ? tick10ms : 0); for (uint8_t i=0; i> (17 - __builtin_clz(abs(chans[i])))) * fp_act[p]; + sum_chans512[i] += (chans[i] >> 4) * fp_act[p]; weight += fp_act[p]; } } @@ -978,7 +978,7 @@ void evalMixes(uint8_t tick10ms) // at the end chans[i] = chans[i]/256 => -1024..1024 // interpolate value with min/max so we get smooth motion from center to stop // this limits based on v original values and min=-1024, max=1024 RESX=1024 - int32_t q = (flightModesFade ? (sum_chans512[i] / weight) << (17 - __builtin_clz(abs(chans[i]))) : chans[i]); + int32_t q = (flightModesFade ? (sum_chans512[i] / weight) << 4 : chans[i]); ex_chans[i] = q / 256; @@ -1011,5 +1011,4 @@ void evalMixes(uint8_t tick10ms) } } } - } From 72ebe902f4d940f8bcea2071e9fb50a5937486b7 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Sun, 14 Jun 2020 19:45:08 +0200 Subject: [PATCH 76/93] Update CREDITS.txt --- CREDITS.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CREDITS.txt b/CREDITS.txt index 52ec9a9a8..d7a0557ef 100644 --- a/CREDITS.txt +++ b/CREDITS.txt @@ -1747,3 +1747,4 @@ Klaus Kernstock Michael Wittich AG-Software Dietmar Drees +Winfried Goers From 5b126480d241b596248b4ef3ccb6a9c953479535 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Sun, 14 Jun 2020 19:53:22 +0200 Subject: [PATCH 77/93] Update CREDITS.txt --- CREDITS.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CREDITS.txt b/CREDITS.txt index d7a0557ef..35748e899 100644 --- a/CREDITS.txt +++ b/CREDITS.txt @@ -1748,3 +1748,4 @@ Michael Wittich AG-Software Dietmar Drees Winfried Goers +Steve Schoonover From ab8913052c4c89278cd88dea803f14581182768e Mon Sep 17 00:00:00 2001 From: 3djc Date: Mon, 15 Jun 2020 11:11:57 +0200 Subject: [PATCH 78/93] Colorlcd popup improve (#7740) Popups improvement --- radio/src/gui/128x64/model_setup.cpp | 2 +- radio/src/gui/212x64/model_setup.cpp | 2 +- radio/src/gui/480x272/menus.h | 5 +++++ radio/src/gui/480x272/model_setup.cpp | 2 +- radio/src/gui/480x272/popups.cpp | 3 +-- radio/src/gui/480x272/radio_sdmanager.cpp | 2 +- radio/src/gui/common/stdlcd/model_setup_pxx1.cpp | 1 + radio/src/gui/common/stdlcd/model_setup_pxx2.cpp | 2 +- radio/src/gui/common/stdlcd/popups.h | 5 +++++ radio/src/gui/common/stdlcd/radio_sdmanager.cpp | 2 +- radio/src/main.cpp | 1 + radio/src/translations.cpp | 1 + radio/src/translations.h | 1 + radio/src/translations/cz.h.txt | 3 ++- radio/src/translations/de.h.txt | 5 +++-- radio/src/translations/en.h.txt | 5 +++-- radio/src/translations/es.h.txt | 3 ++- radio/src/translations/fi.h.txt | 5 +++-- radio/src/translations/fr.h.txt | 3 ++- radio/src/translations/it.h.txt | 1 + radio/src/translations/nl.h.txt | 5 +++-- radio/src/translations/pl.h.txt | 5 +++-- radio/src/translations/pt.h.txt | 5 +++-- radio/src/translations/se.h.txt | 5 +++-- 24 files changed, 49 insertions(+), 25 deletions(-) diff --git a/radio/src/gui/128x64/model_setup.cpp b/radio/src/gui/128x64/model_setup.cpp index d5e9d1004..be8c15092 100644 --- a/radio/src/gui/128x64/model_setup.cpp +++ b/radio/src/gui/128x64/model_setup.cpp @@ -1104,7 +1104,7 @@ void menuModelSetup(event_t event) for (uint8_t i=0; i 0 ? (index < popupMenuItemsCount ? index : popupMenuItemsCount - 1) : 0); } +inline void POPUP_MENU_TITLE(const char * s) +{ + popupMenuTitle = s; +} + inline void POPUP_MENU_START(PopupMenuHandler handler) { if (handler != popupMenuHandler) { diff --git a/radio/src/gui/480x272/model_setup.cpp b/radio/src/gui/480x272/model_setup.cpp index 5f9d680cf..f2f207654 100644 --- a/radio/src/gui/480x272/model_setup.cpp +++ b/radio/src/gui/480x272/model_setup.cpp @@ -1455,7 +1455,7 @@ bool menuModelSetup(event_t event) for (auto rx = 0; rx < popupMenuItemsCount; rx++) { popupMenuItems[rx] = reusableBuffer.moduleSetup.bindInformation.candidateReceiversNames[rx]; } - popupMenuTitle = STR_PXX2_SELECT_RX; + POPUP_MENU_TITLE(STR_PXX2_SELECT_RX); POPUP_MENU_START(onPXX2BindMenu); } } diff --git a/radio/src/gui/480x272/popups.cpp b/radio/src/gui/480x272/popups.cpp index 672922d33..d95eea7cd 100644 --- a/radio/src/gui/480x272/popups.cpp +++ b/radio/src/gui/480x272/popups.cpp @@ -178,8 +178,7 @@ const char * runPopupMenu(event_t event) for (uint8_t i=0; i 0 ? (index < popupMenuItemsCount ? index : popupMenuItemsCount) : 0); } +inline void POPUP_MENU_TITLE(const char * s) +{ + popupMenuTitle = s; +} + inline void POPUP_MENU_START(PopupMenuHandler handler) { if (handler != popupMenuHandler) { diff --git a/radio/src/gui/common/stdlcd/radio_sdmanager.cpp b/radio/src/gui/common/stdlcd/radio_sdmanager.cpp index e719951b3..ffb4ff0bd 100644 --- a/radio/src/gui/common/stdlcd/radio_sdmanager.cpp +++ b/radio/src/gui/common/stdlcd/radio_sdmanager.cpp @@ -580,7 +580,7 @@ void menuRadioSdManager(event_t _event) for (auto rx = 0; rx < popupMenuItemsCount; rx++) { popupMenuItems[rx] = reusableBuffer.sdManager.otaUpdateInformation.candidateReceiversNames[rx]; } - popupMenuTitle = STR_PXX2_SELECT_RX; + POPUP_MENU_TITLE(STR_PXX2_SELECT_RX); POPUP_MENU_START(onUpdateReceiverSelection); } } diff --git a/radio/src/main.cpp b/radio/src/main.cpp index 6c2520e72..1490fb989 100644 --- a/radio/src/main.cpp +++ b/radio/src/main.cpp @@ -50,6 +50,7 @@ void handleUsbConnection() #if defined(DEBUG) POPUP_MENU_ADD_ITEM(STR_USB_SERIAL); #endif + POPUP_MENU_TITLE(STR_SELECT_MODE); POPUP_MENU_START(onUSBConnectMenu); } else { diff --git a/radio/src/translations.cpp b/radio/src/translations.cpp index 39a5bc556..906bf56c7 100644 --- a/radio/src/translations.cpp +++ b/radio/src/translations.cpp @@ -288,6 +288,7 @@ const char STR_BEEP_VOLUME[] = INDENT TR_BEEP_VOLUME; const char STR_WAV_VOLUME[] = INDENT TR_WAV_VOLUME; const char STR_BG_VOLUME[] = INDENT TR_BG_VOLUME; const char STR_SELECT_MODEL[] = TR_SELECT_MODEL; +const char STR_SELECT_MODE[] = TR_SELECT_MODE; const char STR_CREATE_CATEGORY[] = TR_CREATE_CATEGORY; const char STR_RENAME_CATEGORY[] = TR_RENAME_CATEGORY; const char STR_DELETE_CATEGORY[] = TR_DELETE_CATEGORY; diff --git a/radio/src/translations.h b/radio/src/translations.h index 3e7536295..c10c7ffde 100644 --- a/radio/src/translations.h +++ b/radio/src/translations.h @@ -465,6 +465,7 @@ extern const char STR_BEEP_VOLUME[]; extern const char STR_WAV_VOLUME[]; extern const char STR_BG_VOLUME[]; extern const char STR_SELECT_MODEL[]; +extern const char STR_SELECT_MODE[]; extern const char STR_CREATE_CATEGORY[]; extern const char STR_RENAME_CATEGORY[]; extern const char STR_DELETE_CATEGORY[]; diff --git a/radio/src/translations/cz.h.txt b/radio/src/translations/cz.h.txt index 115f2ab17..2086ff7a8 100644 --- a/radio/src/translations/cz.h.txt +++ b/radio/src/translations/cz.h.txt @@ -679,6 +679,7 @@ #define TR_VOLTAGE INDENT"Napětí" #define TR_CURRENT INDENT"Proud" #define TR_SELECT_MODEL "Vyber model" +#define TR_SELECT_MODE "Select mode" #define TR_CREATE_CATEGORY "Nová kategorie" #define TR_RENAME_CATEGORY "Přejmenovat kategorii" #define TR_DELETE_CATEGORY "Odstranit kategorii" @@ -901,7 +902,7 @@ #define TR_POWERMETER_ATTN_NEEDED "Útlumový člen nutný!" #define TR_PXX2_SELECT_RX "Vyber RX..." #define TR_PXX2_DEFAULT "" -#define TR_BT_SELECT_DEVICE "Vyberte zařízení..." +#define TR_BT_SELECT_DEVICE "Vyberte zařízení" #define TR_DISCOVER "Hledat" #define TR_BUTTON_INIT BUTTON("Init") #define TR_WAITING "Čekám..." diff --git a/radio/src/translations/de.h.txt b/radio/src/translations/de.h.txt index 842050723..fc900bcdf 100644 --- a/radio/src/translations/de.h.txt +++ b/radio/src/translations/de.h.txt @@ -681,6 +681,7 @@ #define TR_VOLTAGE TR(INDENT "Spg", INDENT "Spannungsquelle") //9XR-Pro #define TR_CURRENT TR(INDENT "Strom", INDENT "Stromquelle") #define TR_SELECT_MODEL "Modell auswählen" +#define TR_SELECT_MODE "Select mode" #define TR_CREATE_CATEGORY "Modelltyp erstellen" #define TR_RENAME_CATEGORY "Modelltyp umbenennen" #define TR_DELETE_CATEGORY "Modelltyp löschen" @@ -901,9 +902,9 @@ #define TR_BYTES "Bytes" #define TR_MODULE_BIND BUTTON(TR("Bnd","Bind")) //9XR-Pro #define TR_POWERMETER_ATTN_NEEDED "Attenuator needed" -#define TR_PXX2_SELECT_RX "Select RX..." +#define TR_PXX2_SELECT_RX "Select RX" #define TR_PXX2_DEFAULT "" -#define TR_BT_SELECT_DEVICE "Select device..." +#define TR_BT_SELECT_DEVICE "Select device" #define TR_DISCOVER "Discover" #define TR_BUTTON_INIT BUTTON("Init") #define TR_WAITING "Waiting..." diff --git a/radio/src/translations/en.h.txt b/radio/src/translations/en.h.txt index c17be6890..8bde18bf1 100644 --- a/radio/src/translations/en.h.txt +++ b/radio/src/translations/en.h.txt @@ -680,6 +680,7 @@ #define TR_VOLTAGE TR(INDENT "Voltage", INDENT "Voltage source") #define TR_CURRENT TR(INDENT "Current", INDENT "Current source") #define TR_SELECT_MODEL "Select model" +#define TR_SELECT_MODE "Select mode" #define TR_CREATE_CATEGORY "Create category" #define TR_RENAME_CATEGORY "Rename category" #define TR_DELETE_CATEGORY "Delete category" @@ -900,9 +901,9 @@ #define TR_BYTES "bytes" #define TR_MODULE_BIND BUTTON(TR("Bnd", "Bind")) #define TR_POWERMETER_ATTN_NEEDED "Attenuator needed" -#define TR_PXX2_SELECT_RX "Select RX..." +#define TR_PXX2_SELECT_RX "Select RX" #define TR_PXX2_DEFAULT "" -#define TR_BT_SELECT_DEVICE "Select device..." +#define TR_BT_SELECT_DEVICE "Select device" #define TR_DISCOVER "Discover" #define TR_BUTTON_INIT BUTTON("Init") #define TR_WAITING "Waiting..." diff --git a/radio/src/translations/es.h.txt b/radio/src/translations/es.h.txt index 699a47368..fcfade7a1 100644 --- a/radio/src/translations/es.h.txt +++ b/radio/src/translations/es.h.txt @@ -682,6 +682,7 @@ #define TR_VOLTAGE INDENT"Voltaje" #define TR_CURRENT INDENT"Actual" #define TR_SELECT_MODEL TR("Selec. modelo", "Seleccionar modelo") +#define TR_SELECT_MODE "Select mode" #define TR_CREATE_CATEGORY "Crear categoría" #define TR_RENAME_CATEGORY "Renombrar categoría" #define TR_DELETE_CATEGORY "Borrar categoría" @@ -904,7 +905,7 @@ #define TR_POWERMETER_ATTN_NEEDED "Necesita atenuador" #define TR_PXX2_SELECT_RX "Selecciona RX..." #define TR_PXX2_DEFAULT "" -#define TR_BT_SELECT_DEVICE "Selecciona dispositivo..." +#define TR_BT_SELECT_DEVICE "Selecciona dispositivo" #define TR_DISCOVER "Buscar" #define TR_BUTTON_INIT BUTTON("Init") #define TR_WAITING "Espera..." diff --git a/radio/src/translations/fi.h.txt b/radio/src/translations/fi.h.txt index 1396855a9..22b2ac966 100644 --- a/radio/src/translations/fi.h.txt +++ b/radio/src/translations/fi.h.txt @@ -698,6 +698,7 @@ #define TR_VOLTAGE INDENT"Voltage" #define TR_CURRENT INDENT"Current" #define TR_SELECT_MODEL "Select Model" +#define TR_SELECT_MODE "Select mode" #define TR_CREATE_CATEGORY "Create Category" #define TR_RENAME_CATEGORY "Rename Category" #define TR_DELETE_CATEGORY "Delete Category" @@ -918,9 +919,9 @@ #define TR_BYTES "bytes" #define TR_MODULE_BIND "[Bind]" #define TR_POWERMETER_ATTN_NEEDED "Attenuator needed" -#define TR_PXX2_SELECT_RX "Select RX..." +#define TR_PXX2_SELECT_RX "Select RX" #define TR_PXX2_DEFAULT "" -#define TR_BT_SELECT_DEVICE "Select device..." +#define TR_BT_SELECT_DEVICE "Select device" #define TR_DISCOVER "Discover" #define TR_BUTTON_INIT BUTTON("Init") #define TR_WAITING "Waiting..." diff --git a/radio/src/translations/fr.h.txt b/radio/src/translations/fr.h.txt index bfd07bd25..5ef45e312 100644 --- a/radio/src/translations/fr.h.txt +++ b/radio/src/translations/fr.h.txt @@ -701,6 +701,7 @@ #define TR_VOLTAGE TR(INDENT "Tension",INDENT "Source tension") #define TR_CURRENT TR(INDENT "Courant",INDENT "Source courant") #define TR_SELECT_MODEL "Sélect. modèle" +#define TR_SELECT_MODE "Select mode" #define TR_CREATE_CATEGORY "Créer une catégorie" #define TR_RENAME_CATEGORY "Renommer la catégorie" #define TR_DELETE_CATEGORY "Supprimer la catégorie" @@ -922,7 +923,7 @@ #define TR_POWERMETER_ATTN_NEEDED "Atténuateur requis" #define TR_PXX2_SELECT_RX "Sélect RX..." #define TR_PXX2_DEFAULT "" -#define TR_BT_SELECT_DEVICE "Sélect appareil..." +#define TR_BT_SELECT_DEVICE "Sélect appareil" #define TR_DISCOVER "Découvrir" #define TR_BUTTON_INIT BUTTON("Init") #define TR_WAITING "Attente..." diff --git a/radio/src/translations/it.h.txt b/radio/src/translations/it.h.txt index b9a9cf639..22416cdd2 100644 --- a/radio/src/translations/it.h.txt +++ b/radio/src/translations/it.h.txt @@ -700,6 +700,7 @@ #define TR_VOLTAGE TR(INDENT "Voltagg.",INDENT "Voltaggio") #define TR_CURRENT TR(INDENT "Corrente",INDENT "Corrente") #define TR_SELECT_MODEL TR("Scegli mod.", "Scegli Modello") +#define TR_SELECT_MODE "Select mode" #define TR_CREATE_CATEGORY "Crea Categoria" #define TR_RENAME_CATEGORY "Rinomina Categoria" #define TR_DELETE_CATEGORY "Cancella Categoria" diff --git a/radio/src/translations/nl.h.txt b/radio/src/translations/nl.h.txt index c50884c73..a3c642135 100644 --- a/radio/src/translations/nl.h.txt +++ b/radio/src/translations/nl.h.txt @@ -686,6 +686,7 @@ #define TR_VOLTAGE TR(INDENT "Spg", INDENT "Spanningsbron") //9XR-Pro #define TR_CURRENT TR(INDENT "Stroom", INDENT "Stroombron") #define TR_SELECT_MODEL "Kies Model" +#define TR_SELECT_MODE "Select mode" #define TR_CREATE_CATEGORY "Create Category" #define TR_RENAME_CATEGORY "Rename Category" #define TR_DELETE_CATEGORY "Delete Category" @@ -906,9 +907,9 @@ #define TR_BYTES "bytes" #define TR_MODULE_BIND TR("[Bnd]", "[Bind]") #define TR_POWERMETER_ATTN_NEEDED "Attenuator needed" -#define TR_PXX2_SELECT_RX "Select RX..." +#define TR_PXX2_SELECT_RX "Select RX" #define TR_PXX2_DEFAULT "" -#define TR_BT_SELECT_DEVICE "Select device..." +#define TR_BT_SELECT_DEVICE "Select device" #define TR_DISCOVER "Discover" #define TR_BUTTON_INIT BUTTON("Init") #define TR_WAITING "Waiting..." diff --git a/radio/src/translations/pl.h.txt b/radio/src/translations/pl.h.txt index 2e1389e2c..e64b4edff 100644 --- a/radio/src/translations/pl.h.txt +++ b/radio/src/translations/pl.h.txt @@ -699,6 +699,7 @@ #define TR_VOLTAGE TR (INDENT"Napięcie",INDENT"Źródło Napięcia") #define TR_CURRENT TR (INDENT"Prąd",INDENT"Źródło Prądu") #define TR_SELECT_MODEL "Wybór modelu" +#define TR_SELECT_MODE "Select mode" #define TR_CREATE_CATEGORY "Create Category" #define TR_RENAME_CATEGORY "Rename Category" #define TR_DELETE_CATEGORY "Delete Category" @@ -919,9 +920,9 @@ #define TR_BYTES "bajty" #define TR_MODULE_BIND TR("[BND]","[Bind]") #define TR_POWERMETER_ATTN_NEEDED "Attenuator needed" -#define TR_PXX2_SELECT_RX "Select RX..." +#define TR_PXX2_SELECT_RX "Select RX" #define TR_PXX2_DEFAULT "" -#define TR_BT_SELECT_DEVICE "Select device..." +#define TR_BT_SELECT_DEVICE "Select device" #define TR_DISCOVER "Discover" #define TR_BUTTON_INIT BUTTON("Init") #define TR_WAITING "Waiting..." diff --git a/radio/src/translations/pt.h.txt b/radio/src/translations/pt.h.txt index fb0e97e48..75830e538 100644 --- a/radio/src/translations/pt.h.txt +++ b/radio/src/translations/pt.h.txt @@ -689,6 +689,7 @@ #define TR_VOLTAGE INDENT"Volts" #define TR_CURRENT INDENT"Amperes" #define TR_SELECT_MODEL "Selec. Modelo" +#define TR_SELECT_MODE "Select mode" #define TR_CREATE_CATEGORY "Create Category" #define TR_RENAME_CATEGORY "Rename Category" #define TR_DELETE_CATEGORY "Delete Category" @@ -909,9 +910,9 @@ #define TR_BYTES "bytes" #define TR_MODULE_BIND "[Bind]" #define TR_POWERMETER_ATTN_NEEDED "Attenuator needed" -#define TR_PXX2_SELECT_RX "Select RX..." +#define TR_PXX2_SELECT_RX "Select RX" #define TR_PXX2_DEFAULT "" -#define TR_BT_SELECT_DEVICE "Select device..." +#define TR_BT_SELECT_DEVICE "Select device" #define TR_DISCOVER "Discover" #define TR_BUTTON_INIT BUTTON("Init") #define TR_WAITING "Waiting..." diff --git a/radio/src/translations/se.h.txt b/radio/src/translations/se.h.txt index deacd3518..368ad237b 100644 --- a/radio/src/translations/se.h.txt +++ b/radio/src/translations/se.h.txt @@ -698,6 +698,7 @@ #define TR_VOLTAGE INDENT"Volt" #define TR_CURRENT INDENT"Ampere" #define TR_SELECT_MODEL "Välj Modell" +#define TR_SELECT_MODE "Select mode" #define TR_CREATE_CATEGORY "Skapa Kategori" #define TR_RENAME_CATEGORY "Byt Kat.namn" #define TR_DELETE_CATEGORY "Ta Bort Kategori" @@ -919,9 +920,9 @@ #define TR_BYTES "byte" #define TR_MODULE_BIND TR("[Bnd]", "[Bind]") #define TR_POWERMETER_ATTN_NEEDED "Attenuator needed" -#define TR_PXX2_SELECT_RX "Select RX..." +#define TR_PXX2_SELECT_RX "Select RX" #define TR_PXX2_DEFAULT "" -#define TR_BT_SELECT_DEVICE "Select device..." +#define TR_BT_SELECT_DEVICE "Select device" #define TR_DISCOVER "Discover" #define TR_BUTTON_INIT BUTTON("Init") #define TR_WAITING "Waiting..." From 463910c9039001332b1cc80241ce701dde0023c6 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Mon, 15 Jun 2020 11:12:52 +0200 Subject: [PATCH 79/93] Bsongis/navigation issue internal module receiver row (#7726) Navigation issue (212x64, when internal module is XJT D8): invisible cursor on "Receiver" row --- radio/src/gui/128x64/model_setup.cpp | 32 +++++----- .../src/gui/128x64/model_telemetry_sensor.cpp | 2 +- radio/src/gui/212x64/model_setup.cpp | 60 +++++++++---------- radio/src/gui/480x272/model_setup.cpp | 44 +++++++------- radio/src/gui/gui_common.h | 35 ++++++++--- radio/src/pulses/modules_helpers.h | 5 ++ radio/src/translations/en.h.txt | 4 +- 7 files changed, 97 insertions(+), 85 deletions(-) diff --git a/radio/src/gui/128x64/model_setup.cpp b/radio/src/gui/128x64/model_setup.cpp index be8c15092..47b8e4958 100644 --- a/radio/src/gui/128x64/model_setup.cpp +++ b/radio/src/gui/128x64/model_setup.cpp @@ -158,8 +158,6 @@ enum MenuModelSetupItems { }; #define MODEL_SETUP_2ND_COLUMN (LCD_W-11*FW) -#define MODEL_SETUP_BIND_OFS 2*FW+1 -#define MODEL_SETUP_RANGE_OFS 4*FW+3 #define MODEL_SETUP_SET_FAILSAFE_OFS 7*FW-2 #define IF_PXX2_MODULE(module, xxx) (isModulePXX2(module) ? (uint8_t)(xxx) : HIDDEN_ROW) @@ -311,7 +309,7 @@ void onBluetoothConnectMenu(const char * result) MULTIMODULE_SUBTYPE_ROWS(INTERNAL_MODULE) /* ITEM_MODEL_SETUP_INTERNAL_MODULE_SUBTYPE */ \ MULTIMODULE_STATUS_ROWS(INTERNAL_MODULE) /* ITEM_MODEL_SETUP_INTERNAL_MODULE_STATUS, ITEM_MODEL_SETUP_INTERNAL_MODULE_SYNCSTATUS */ \ MODULE_CHANNELS_ROWS(INTERNAL_MODULE), /* ITEM_MODEL_SETUP_INTERNAL_MODULE_CHANNELS */ \ - IF_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_NOT_ACCESS_MODULE_RF(INTERNAL_MODULE, MODULE_BIND_ROWS(INTERNAL_MODULE)), /* *ITEM_MODEL_SETUP_INTERNAL_MODULE_NOT_ACCESS_RXNUM_BIND_RANGE */\ IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 0), /* ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_MODEL_NUM */ \ MODULE_OPTION_ROW(INTERNAL_MODULE), /* ITEM_MODEL_SETUP_INTERNAL_MODULE_OPTIONS */ \ MULTIMODULE_MODULE_ROWS(INTERNAL_MODULE) /* ITEM_MODEL_SETUP_INTERNAL_MODULE_AUTOBIND */ \ @@ -1300,8 +1298,7 @@ void menuModelSetup(event_t event) lcdDrawNumber(MODEL_SETUP_2ND_COLUMN, y, (int16_t)moduleData.ppm.frameLength*5 + 225, (menuHorizontalPosition<=0 ? attr : 0) | PREC1|LEFT); lcdDrawText(lcdLastRightPos, y, STR_MS); lcdDrawText(MODEL_SETUP_2ND_COLUMN+5*FW+2, y, moduleData.sbus.noninverted ? STR_NOT_INVERTED : STR_NORMAL, (CURSOR_ON_LINE() || menuHorizontalPosition==1) ? attr : 0); - - if (attr && s_editMode>0) { + if (attr && s_editMode > 0) { switch (menuHorizontalPosition) { case 0: CHECK_INCDEC_MODELVAR(event, moduleData.ppm.frameLength, -33, 35); @@ -1313,19 +1310,17 @@ void menuModelSetup(event_t event) } } else { + lcdDrawText(INDENT_WIDTH, y, STR_RECEIVER); horzpos_t l_posHorz = menuHorizontalPosition; - coord_t xOffsetBind = MODEL_SETUP_BIND_OFS; - if (!isModuleRxNumAvailable(moduleIdx)) { - xOffsetBind = 0; - lcdDrawText(INDENT_WIDTH, y, STR_RECEIVER); - if (attr) l_posHorz += 1; + coord_t bindButtonPos = MODEL_SETUP_2ND_COLUMN; + if (isModuleRxNumAvailable(moduleIdx)) { + lcdDrawNumber(MODEL_SETUP_2ND_COLUMN, y, g_model.header.modelId[moduleIdx], (l_posHorz==0 ? attr : 0) | LEADING0|LEFT, 2); + bindButtonPos = lcdNextPos + 2; } - else { - lcdDrawText(INDENT_WIDTH, y, STR_RECEIVER_NUM); + else if (attr) { + l_posHorz += 1; } if (isModuleBindRangeAvailable(moduleIdx)) { - if (xOffsetBind) - lcdDrawNumber(MODEL_SETUP_2ND_COLUMN, y, g_model.header.modelId[moduleIdx], (l_posHorz==0 ? attr : 0) | LEADING0|LEFT, 2); if (attr && l_posHorz == 0) { if (s_editMode > 0) { CHECK_INCDEC_MODELVAR_ZERO(event, g_model.header.modelId[moduleIdx], getMaxRxNum(moduleIdx)); @@ -1342,9 +1337,10 @@ void menuModelSetup(event_t event) } } } - lcdDrawText(MODEL_SETUP_2ND_COLUMN+xOffsetBind, y, STR_MODULE_BIND, l_posHorz==1 ? 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); + lcdDrawText(bindButtonPos, y, STR_MODULE_BIND, l_posHorz == 1 ? attr : 0); + if (isModuleRangeAvailable(moduleIdx)) { + lcdDrawText(lcdNextPos + 2, y, STR_MODULE_RANGE, l_posHorz == 2 ? attr : 0); + } uint8_t newFlag = 0; #if defined(MULTIMODULE) if (getMultiBindStatus(moduleIdx) == MULTI_BIND_FINISHED) { @@ -1387,7 +1383,7 @@ void menuModelSetup(event_t event) } } #else - if (attr && l_posHorz>0 && s_editMode>0) { + if (attr && l_posHorz > 0 && s_editMode > 0) { if (l_posHorz == 1) newFlag = MODULE_MODE_BIND; else if (l_posHorz == 2) diff --git a/radio/src/gui/128x64/model_telemetry_sensor.cpp b/radio/src/gui/128x64/model_telemetry_sensor.cpp index 301b956c1..33dcaf60c 100644 --- a/radio/src/gui/128x64/model_telemetry_sensor.cpp +++ b/radio/src/gui/128x64/model_telemetry_sensor.cpp @@ -24,7 +24,7 @@ enum SensorFields { SENSOR_FIELD_NAME, SENSOR_FIELD_TYPE, SENSOR_FIELD_ID, - SENSOR_FIELD_FORMULA=SENSOR_FIELD_ID, + SENSOR_FIELD_FORMULA = SENSOR_FIELD_ID, SENSOR_FILED_RECEIVER_NAME, SENSOR_FIELD_UNIT, SENSOR_FIELD_PRECISION, diff --git a/radio/src/gui/212x64/model_setup.cpp b/radio/src/gui/212x64/model_setup.cpp index c3d911012..f2933d5b7 100644 --- a/radio/src/gui/212x64/model_setup.cpp +++ b/radio/src/gui/212x64/model_setup.cpp @@ -86,7 +86,7 @@ enum MenuModelSetupItems { ITEM_MODEL_SETUP_INTERNAL_MODULE_LABEL, ITEM_MODEL_SETUP_INTERNAL_MODULE_TYPE, ITEM_MODEL_SETUP_INTERNAL_MODULE_CHANNELS, - ITEM_MODEL_SETUP_INTERNAL_MODULE_NOT_ACCESS_BIND, + ITEM_MODEL_SETUP_INTERNAL_MODULE_NOT_ACCESS_RXNUM_BIND_RANGE, ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_MODEL_NUM, ITEM_MODEL_SETUP_INTERNAL_MODULE_FAILSAFE, ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_REGISTER_RANGE, @@ -103,7 +103,7 @@ enum MenuModelSetupItems { ITEM_MODEL_SETUP_EXTERNAL_MODULE_SYNCSTATUS, #endif ITEM_MODEL_SETUP_EXTERNAL_MODULE_CHANNELS, - ITEM_MODEL_SETUP_EXTERNAL_MODULE_NOT_ACCESS_BIND, + ITEM_MODEL_SETUP_EXTERNAL_MODULE_NOT_ACCESS_RXNUM_BIND_RANGE, ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_MODEL_NUM, ITEM_MODEL_SETUP_EXTERNAL_MODULE_OPTIONS, #if defined(MULTIMODULE) @@ -347,10 +347,10 @@ void menuModelSetup(event_t event) LABEL(InternalModule), INTERNAL_MODULE_TYPE_ROWS, MODULE_CHANNELS_ROWS(INTERNAL_MODULE), - IF_NOT_ACCESS_MODULE_RF(INTERNAL_MODULE, IF_INTERNAL_MODULE_ON(isModuleBindRangeAvailable(INTERNAL_MODULE)? (uint8_t)2 : (uint8_t)1)), // RxNum, Range check and Register buttons + IF_NOT_ACCESS_MODULE_RF(INTERNAL_MODULE, MODULE_BIND_ROWS(INTERNAL_MODULE)), // RxNum, [Bind] and [Range] buttons IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 0), // RxNum for ACCESS IF_INTERNAL_MODULE_ON(FAILSAFE_ROWS(INTERNAL_MODULE)), // Failsafe - IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 1), // Range check and Register buttons + IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 1), // [Range] and [Register] buttons IF_PXX2_MODULE(INTERNAL_MODULE, 0), // Module options IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 0), // Receiver 1 IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 0), // Receiver 2 @@ -1086,8 +1086,8 @@ void menuModelSetup(event_t event) } break; - case ITEM_MODEL_SETUP_INTERNAL_MODULE_NOT_ACCESS_BIND: - case ITEM_MODEL_SETUP_EXTERNAL_MODULE_NOT_ACCESS_BIND: + case ITEM_MODEL_SETUP_INTERNAL_MODULE_NOT_ACCESS_RXNUM_BIND_RANGE: + case ITEM_MODEL_SETUP_EXTERNAL_MODULE_NOT_ACCESS_RXNUM_BIND_RANGE: { uint8_t moduleIdx = CURRENT_MODULE_EDITED(k); ModuleData & moduleData = g_model.moduleData[moduleIdx]; @@ -1098,8 +1098,7 @@ void menuModelSetup(event_t event) lcdDrawNumber(MODEL_SETUP_2ND_COLUMN+6*FW, y, (moduleData.ppm.delay*50)+300, (CURSOR_ON_LINE() || menuHorizontalPosition==1) ? attr : 0); lcdDrawChar(lcdLastRightPos, y, 'u'); lcdDrawChar(MODEL_SETUP_2ND_COLUMN+12*FW, y, moduleData.ppm.pulsePol ? '+' : '-', (CURSOR_ON_LINE() || menuHorizontalPosition==2) ? attr : 0); - - if (attr && s_editMode>0) { + if (attr && s_editMode > 0) { switch (menuHorizontalPosition) { case 0: CHECK_INCDEC_MODELVAR(event, moduleData.ppm.frameLength, -20, 35); @@ -1117,9 +1116,8 @@ void menuModelSetup(event_t event) lcdDrawTextAlignedLeft(y, STR_REFRESHRATE); lcdDrawNumber(MODEL_SETUP_2ND_COLUMN, y, (int16_t)moduleData.ppm.frameLength*5 + 225, (menuHorizontalPosition<=0 ? attr : 0) | PREC1|LEFT); lcdDrawText(lcdLastRightPos, y, STR_MS); - lcdDrawText(MODEL_SETUP_3RD_COLUMN, y, moduleData.sbus.noninverted ? "not inverted" : "normal", (CURSOR_ON_LINE() || menuHorizontalPosition==1) ? attr : 0); - - if (attr && s_editMode>0) { + lcdDrawText(MODEL_SETUP_3RD_COLUMN, y, moduleData.sbus.noninverted ? STR_NOT_INVERTED : STR_NORMAL, (CURSOR_ON_LINE() || menuHorizontalPosition==1) ? attr : 0); + if (attr && s_editMode > 0) { switch (menuHorizontalPosition) { case 0: CHECK_INCDEC_MODELVAR(event, moduleData.ppm.frameLength, -33, 35); @@ -1131,25 +1129,19 @@ void menuModelSetup(event_t event) } } else { + lcdDrawText(INDENT_WIDTH, y, STR_RECEIVER); horzpos_t l_posHorz = menuHorizontalPosition; coord_t bindButtonPos = MODEL_SETUP_2ND_COLUMN; - if (!isModuleRxNumAvailable(moduleIdx)) { - lcdDrawText(INDENT_WIDTH, y, STR_RECEIVER); - if (attr) l_posHorz += 1; + if (isModuleRxNumAvailable(moduleIdx)) { + lcdDrawNumber(MODEL_SETUP_2ND_COLUMN, y, g_model.header.modelId[moduleIdx], (l_posHorz == 0 ? attr : 0) | LEADING0 | LEFT, 2); + bindButtonPos = lcdNextPos + FW; } - else { - lcdDrawText(INDENT_WIDTH, y, STR_RECEIVER_NUM); + else if (attr) { + l_posHorz += 1; } if (isModuleBindRangeAvailable(moduleIdx)) { - if (isModuleRxNumAvailable(moduleIdx)) { - lcdDrawNumber(MODEL_SETUP_2ND_COLUMN, y, g_model.header.modelId[moduleIdx], (l_posHorz == 0 ? attr : 0) | LEADING0 | LEFT, 2); - bindButtonPos = lcdNextPos + FW; - } - else { - bindButtonPos = MODEL_SETUP_2ND_COLUMN; - } - if (attr && l_posHorz==0) { - if (s_editMode>0) { + if (attr && l_posHorz == 0) { + if (s_editMode > 0) { CHECK_INCDEC_MODELVAR_ZERO(event, g_model.header.modelId[moduleIdx], getMaxRxNum(moduleIdx)); if (checkIncDec_Ret) { modelHeaders[g_eeGeneral.currModel].modelId[moduleIdx] = g_model.header.modelId[moduleIdx]; @@ -1164,9 +1156,10 @@ void menuModelSetup(event_t event) } } } - lcdDrawText(bindButtonPos, y, STR_MODULE_BIND, l_posHorz==1 ? attr : 0); - if (!IS_RX_MULTI(moduleIdx)) - lcdDrawText(lcdNextPos + FW, y, STR_MODULE_RANGE, l_posHorz==2 ? attr : 0); + lcdDrawText(bindButtonPos, y, STR_MODULE_BIND, l_posHorz == 1 ? attr : 0); + if (isModuleRangeAvailable(moduleIdx)) { + lcdDrawText(lcdNextPos + FW, y, STR_MODULE_RANGE, l_posHorz == 2 ? attr : 0); + } uint8_t newFlag = 0; #if defined(MULTIMODULE) if (getMultiBindStatus(moduleIdx) == MULTI_BIND_FINISHED) { @@ -1174,8 +1167,8 @@ void menuModelSetup(event_t event) s_editMode = 0; } #endif - if (attr && l_posHorz>0) { - if (s_editMode>0) { + if (attr && l_posHorz > 0) { + if (s_editMode > 0) { if (l_posHorz == 1) { if (isModuleR9MNonAccess(moduleIdx) || isModuleD16(moduleIdx)) { if (event == EVT_KEY_BREAK(KEY_ENTER)) { @@ -1202,8 +1195,9 @@ void menuModelSetup(event_t event) } moduleState[moduleIdx].mode = newFlag; #if defined(MULTIMODULE) - if (newFlag == MODULE_MODE_BIND) + if (newFlag == MODULE_MODE_BIND) { setMultiBindStatus(moduleIdx, MULTI_BIND_INITIATED); + } #endif } } @@ -1454,12 +1448,12 @@ void menuModelSetup(event_t event) if (old_editMode > 0 && s_editMode == 0) { switch(menuVerticalPosition) { - case ITEM_MODEL_SETUP_INTERNAL_MODULE_NOT_ACCESS_BIND: + case ITEM_MODEL_SETUP_INTERNAL_MODULE_NOT_ACCESS_RXNUM_BIND_RANGE: if (menuHorizontalPosition == 0) checkModelIdUnique(g_eeGeneral.currModel, INTERNAL_MODULE); break; - case ITEM_MODEL_SETUP_EXTERNAL_MODULE_NOT_ACCESS_BIND: + case ITEM_MODEL_SETUP_EXTERNAL_MODULE_NOT_ACCESS_RXNUM_BIND_RANGE: if (menuHorizontalPosition == 0) checkModelIdUnique(g_eeGeneral.currModel, EXTERNAL_MODULE); break; diff --git a/radio/src/gui/480x272/model_setup.cpp b/radio/src/gui/480x272/model_setup.cpp index f2f207654..191813f38 100644 --- a/radio/src/gui/480x272/model_setup.cpp +++ b/radio/src/gui/480x272/model_setup.cpp @@ -100,7 +100,7 @@ enum MenuModelSetupItems { ITEM_MODEL_SETUP_EXTERNAL_MODULE_SYNCSTATUS, #endif ITEM_MODEL_SETUP_EXTERNAL_MODULE_CHANNELS, - ITEM_MODEL_SETUP_EXTERNAL_MODULE_NOT_ACCESS_BIND, + ITEM_MODEL_SETUP_EXTERNAL_MODULE_NOT_ACCESS_RXNUM_BIND_RANGE, ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_MODEL_NUM, ITEM_MODEL_SETUP_EXTERNAL_MODULE_OPTIONS, #if defined(MULTIMODULE) @@ -129,8 +129,6 @@ enum MenuModelSetupItems { #define MODEL_SETUP_2ND_COLUMN 200 #define MODEL_SETUP_3RD_COLUMN 270 #define MODEL_SETUP_4TH_COLUMN 350 -#define MODEL_SETUP_BIND_OFS 40 -#define MODEL_SETUP_RANGE_OFS 80 #define MODEL_SETUP_SET_FAILSAFE_OFS 100 #define MODEL_SETUP_SLIDPOT_SPACING 45 @@ -1348,6 +1346,7 @@ bool menuModelSetup(event_t event) } } break; + #if defined(HARDWARE_INTERNAL_MODULE) case ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_REGISTER_RANGE: #endif @@ -1355,7 +1354,7 @@ bool menuModelSetup(event_t event) { lcdDrawText(MENUS_MARGIN_LEFT + INDENT_WIDTH, y, STR_MODULE); drawButton(MODEL_SETUP_2ND_COLUMN, y, STR_REGISTER, (menuHorizontalPosition == 0 ? attr : 0)); - if (!IS_RX_MULTI(moduleIdx)) + if (isModuleRangeAvailable(moduleIdx)) drawButton(MODEL_SETUP_2ND_COLUMN + MODEL_SETUP_SET_FAILSAFE_OFS, y, STR_MODULE_RANGE, (menuHorizontalPosition == 1 ? attr : 0)); if (attr) { if (moduleState[moduleIdx].mode == MODULE_MODE_NORMAL && s_editMode > 0) { @@ -1374,8 +1373,9 @@ bool menuModelSetup(event_t event) s_editMode = 0; } } - } break; + } + #if defined(HARDWARE_INTERNAL_MODULE) case ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_OPTIONS: #endif @@ -1387,6 +1387,7 @@ bool menuModelSetup(event_t event) pushMenu(menuModelModuleOptions); } break; + #if defined(HARDWARE_INTERNAL_MODULE) case ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_RECEIVER_1: case ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_RECEIVER_2: @@ -1471,10 +1472,11 @@ bool menuModelSetup(event_t event) } } break; + #if defined(HARDWARE_INTERNAL_MODULE) case ITEM_MODEL_SETUP_INTERNAL_MODULE_NOT_ACCESS_RXNUM_BIND_RANGE: #endif - case ITEM_MODEL_SETUP_EXTERNAL_MODULE_NOT_ACCESS_BIND: + case ITEM_MODEL_SETUP_EXTERNAL_MODULE_NOT_ACCESS_RXNUM_BIND_RANGE: { ModuleData & moduleData = g_model.moduleData[moduleIdx]; if (isModulePPM(moduleIdx)) { @@ -1500,7 +1502,6 @@ bool menuModelSetup(event_t event) lcdDrawText(MENUS_MARGIN_LEFT, y, STR_REFRESHRATE); lcdDrawNumber(MODEL_SETUP_2ND_COLUMN, y, (int16_t)moduleData.ppm.frameLength*5 + 225, (menuHorizontalPosition<=0 ? attr : 0) | PREC1|LEFT, 0, NULL, STR_MS); lcdDrawText(MODEL_SETUP_3RD_COLUMN, y, moduleData.sbus.noninverted ? "not inverted" : "normal", (CURSOR_ON_LINE() || menuHorizontalPosition==1) ? attr : 0); - if (attr && s_editMode>0) { switch (menuHorizontalPosition) { case 0: @@ -1513,21 +1514,19 @@ bool menuModelSetup(event_t event) } } else { + lcdDrawText(MENUS_MARGIN_LEFT + INDENT_WIDTH, y, STR_RECEIVER); int l_posHorz = menuHorizontalPosition; - coord_t xOffsetBind = MODEL_SETUP_BIND_OFS; - if (!isModuleRxNumAvailable(moduleIdx)) { - xOffsetBind = 0; - lcdDrawText(MENUS_MARGIN_LEFT + INDENT_WIDTH, y, STR_RECEIVER); - if (attr) l_posHorz += 1; + coord_t bindButtonPos = MODEL_SETUP_2ND_COLUMN; + if (isModuleRxNumAvailable(moduleIdx)) { + lcdDrawNumber(MODEL_SETUP_2ND_COLUMN, y, g_model.header.modelId[moduleIdx], (l_posHorz==0 ? attr : 0) | LEADING0 | LEFT, 2); + bindButtonPos += 40; } - else { - lcdDrawText(MENUS_MARGIN_LEFT + INDENT_WIDTH, y, STR_RECEIVER_NUM); + else if (attr) { + l_posHorz += 1; } if (isModuleBindRangeAvailable(moduleIdx)) { - if (xOffsetBind) - lcdDrawNumber(MODEL_SETUP_2ND_COLUMN, y, g_model.header.modelId[moduleIdx], (l_posHorz==0 ? attr : 0) | LEADING0 | LEFT, 2); - if (attr && l_posHorz==0) { - if (s_editMode>0) { + if (attr && l_posHorz == 0) { + if (s_editMode > 0) { CHECK_INCDEC_MODELVAR_ZERO(event, g_model.header.modelId[moduleIdx], getMaxRxNum(moduleIdx)); if (event == EVT_KEY_LONG(KEY_ENTER)) { killEvents(event); @@ -1539,9 +1538,10 @@ bool menuModelSetup(event_t event) } } } - drawButton(MODEL_SETUP_2ND_COLUMN+xOffsetBind, y, STR_MODULE_BIND, (moduleState[moduleIdx].mode == MODULE_MODE_BIND ? BUTTON_ON : BUTTON_OFF) | (l_posHorz==1 ? attr : 0)); - if (!IS_RX_MULTI(moduleIdx)) - drawButton(MODEL_SETUP_2ND_COLUMN+MODEL_SETUP_RANGE_OFS+xOffsetBind, y, STR_MODULE_RANGE, (moduleState[moduleIdx].mode == MODULE_MODE_RANGECHECK ? BUTTON_ON : BUTTON_OFF) | (l_posHorz==2 ? attr : 0)); + drawButton(bindButtonPos, y, STR_MODULE_BIND, (moduleState[moduleIdx].mode == MODULE_MODE_BIND ? BUTTON_ON : BUTTON_OFF) | (l_posHorz==1 ? attr : 0)); + if (isModuleRangeAvailable(moduleIdx)) { + drawButton(bindButtonPos + 80, y, STR_MODULE_RANGE, (moduleState[moduleIdx].mode == MODULE_MODE_RANGECHECK ? BUTTON_ON : BUTTON_OFF) | (l_posHorz==2 ? attr : 0)); + } uint8_t newFlag = 0; #if defined(MULTIMODULE) if (getMultiBindStatus(moduleIdx) == MULTI_BIND_FINISHED) { @@ -1791,7 +1791,7 @@ bool menuModelSetup(event_t event) checkModelIdUnique(INTERNAL_MODULE); break; #endif - case ITEM_MODEL_SETUP_EXTERNAL_MODULE_NOT_ACCESS_BIND: + case ITEM_MODEL_SETUP_EXTERNAL_MODULE_NOT_ACCESS_RXNUM_BIND_RANGE: if (menuHorizontalPosition != 0) break; case ITEM_MODEL_SETUP_EXTERNAL_MODULE_TYPE: diff --git a/radio/src/gui/gui_common.h b/radio/src/gui/gui_common.h index 4fbd63194..8aa034226 100644 --- a/radio/src/gui/gui_common.h +++ b/radio/src/gui/gui_common.h @@ -141,27 +141,44 @@ void runFatalErrorScreen(const char * message); inline uint8_t MODULE_BIND_ROWS(int moduleIdx) { - if (isModuleXJTD8(moduleIdx) || isModuleSBUS(moduleIdx) || IS_RX_MULTI(moduleIdx)) + if (isModuleMultimodule(moduleIdx)) { + if (IS_RX_MULTI(moduleIdx)) + return 1; + else + return 2; + } + else if (isModuleXJTD8(moduleIdx) || isModuleSBUS(moduleIdx)) { return 1; - - if (isModulePPM(moduleIdx) || isModulePXX1(moduleIdx) || isModulePXX2(moduleIdx) || isModuleDSM2(moduleIdx) || isModuleMultimodule(moduleIdx)) + } + else if (isModulePPM(moduleIdx) || isModulePXX1(moduleIdx) || isModulePXX2(moduleIdx) || isModuleDSM2(moduleIdx)) { return 2; - else + } + else { return HIDDEN_ROW; + } } inline uint8_t MODULE_CHANNELS_ROWS(int moduleIdx) { - if (!IS_MODULE_ENABLED(moduleIdx) || IS_RX_MULTI(moduleIdx)) + if (!IS_MODULE_ENABLED(moduleIdx)) { return HIDDEN_ROW; - - if (isModuleDSM2(moduleIdx) || isModuleCrossfire(moduleIdx) || isModuleSBUS(moduleIdx) || (isModuleMultimodule(moduleIdx) && g_model.moduleData[moduleIdx].getMultiProtocol() != MODULE_SUBTYPE_MULTI_DSM2)) + } + else if (isModuleMultimodule(moduleIdx)) { + if (IS_RX_MULTI(moduleIdx)) + return HIDDEN_ROW; + else if (g_model.moduleData[moduleIdx].getMultiProtocol() == MODULE_SUBTYPE_MULTI_DSM2) + return 1; + else + return 0; + } + else if (isModuleDSM2(moduleIdx) || isModuleCrossfire(moduleIdx) || isModuleSBUS(moduleIdx)) { return 0; - else + } + else { return 1; + } } - #if defined(MULTIMODULE) inline uint8_t MULTI_DISABLE_CHAN_MAP_ROW(uint8_t moduleIdx) { diff --git a/radio/src/pulses/modules_helpers.h b/radio/src/pulses/modules_helpers.h index 244e58a79..cdaf58336 100644 --- a/radio/src/pulses/modules_helpers.h +++ b/radio/src/pulses/modules_helpers.h @@ -424,6 +424,11 @@ inline bool isModuleBindRangeAvailable(uint8_t moduleIdx) return isModulePXX2(moduleIdx) || isModulePXX1(moduleIdx) || isModuleDSM2(moduleIdx) || isModuleMultimodule(moduleIdx); } +inline bool isModuleRangeAvailable(uint8_t moduleIdx) +{ + return isModuleBindRangeAvailable(moduleIdx) && !IS_RX_MULTI(moduleIdx); +} + constexpr uint8_t MAX_RXNUM = 63; inline uint8_t getMaxRxNum(uint8_t idx) diff --git a/radio/src/translations/en.h.txt b/radio/src/translations/en.h.txt index 8bde18bf1..eae2ad25a 100644 --- a/radio/src/translations/en.h.txt +++ b/radio/src/translations/en.h.txt @@ -841,8 +841,8 @@ #define TR_WRITING "Writing..." #define TR_CONFIRM_FORMAT "Confirm Format?" #define TR_INTERNALRF "Internal RF" -#define TR_INTERNAL_MODULE TR("Int. module","Internal module") -#define TR_EXTERNAL_MODULE TR("Ext. module","External module") +#define TR_INTERNAL_MODULE TR("Int. module", "Internal module") +#define TR_EXTERNAL_MODULE TR("Ext. module", "External module") #define TR_OPENTX_UPGRADE_REQUIRED "OpenTX upgrade required" #define TR_TELEMETRY_DISABLED "Telem. disabled" #define TR_MORE_OPTIONS_AVAILABLE "More options available" From af58426261679328a9891cb9d8bc7cabbb772ff7 Mon Sep 17 00:00:00 2001 From: MRC3742 Date: Mon, 15 Jun 2020 05:38:55 -0400 Subject: [PATCH 80/93] Update MPM to 1.3.1.9 (#7682) --- companion/src/firmwares/moduledata.h | 3 ++- companion/src/firmwares/multiprotocols.cpp | 12 ++++++++---- radio/src/gui/gui_common.cpp | 10 +++++++--- radio/src/pulses/modules_constants.h | 5 +++-- radio/src/translations/untranslated.h | 2 +- 5 files changed, 21 insertions(+), 11 deletions(-) diff --git a/companion/src/firmwares/moduledata.h b/companion/src/firmwares/moduledata.h index d356c3012..86614b392 100644 --- a/companion/src/firmwares/moduledata.h +++ b/companion/src/firmwares/moduledata.h @@ -132,7 +132,8 @@ enum MultiModuleRFProtocols { MODULE_SUBTYPE_MULTI_ESKY150V2, MODULE_SUBTYPE_MULTI_DSM_RX, MODULE_SUBTYPE_MULTI_JJRC345, - MODULE_SUBTYPE_MULTI_LAST = MODULE_SUBTYPE_MULTI_JJRC345 + MODULE_SUBTYPE_MULTI_Q90C, + MODULE_SUBTYPE_MULTI_LAST = MODULE_SUBTYPE_MULTI_Q90C }; enum TrainerProtocol { diff --git a/companion/src/firmwares/multiprotocols.cpp b/companion/src/firmwares/multiprotocols.cpp index 4feeb997f..737bd36ed 100644 --- a/companion/src/firmwares/multiprotocols.cpp +++ b/companion/src/firmwares/multiprotocols.cpp @@ -50,7 +50,7 @@ static const QStringList STR_SUBTYPE_SYMAX {"Standard", "Syma X5C"}; static const QStringList STR_SUBTYPE_SLT {"V1 (6 Channel)", "V2 (8 Channel)", "Q100", "Q200", "MR100"}; 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_BAYANG {"Standard", "H8S3D", "X16 AH", "IRDRONE", "DHD D4", "QX100"}; 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"}; @@ -76,7 +76,9 @@ 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 {"RX", "Clone TX"}; +static const QStringList STR_SUBTYPE_HOTT {"Sync", "No_Sync"}; static const QStringList STR_SUBTYPE_FX816 {"P38"}; +static const QStringList STR_SUBTYPE_PELIKAN {"Pro", "Lite"}; static const QStringList STR_SUBTYPE_XK {"X450", "X420"}; static const QStringList STR_SUBTYPE_XN297DUMP {"250K", "1M", "2M", "AUTO"}; static const QStringList STR_SUBTYPE_FRSKYX2 {"D16", "D16 8ch", "D16 EU-LBT", "D16 EU-LBT 8ch", "D16 Cloned"}; @@ -104,7 +106,7 @@ const Multiprotocols multiProtocols { {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_BAYANG, 5, 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}, @@ -134,8 +136,9 @@ const Multiprotocols multiProtocols { {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_HOTT, 0, true, NO_SUBTYPE, STR_MULTI_RFTUNE}, + {MODULE_SUBTYPE_MULTI_HOTT, 1, true, STR_SUBTYPE_HOTT, STR_MULTI_RFTUNE}, {MODULE_SUBTYPE_MULTI_FX816, 0, false, STR_SUBTYPE_FX816, nullptr}, + {MODULE_SUBTYPE_MULTI_PELIKAN, 1, false, STR_SUBTYPE_PELIKAN, nullptr}, {MODULE_SUBTYPE_MULTI_XK, 1, false, STR_SUBTYPE_XK, STR_MULTI_RFTUNE}, {MODULE_SUBTYPE_MULTI_XN297DUMP, 3, false, STR_SUBTYPE_XN297DUMP, nullptr}, {MODULE_SUBTYPE_MULTI_FRSKYX2, 4, true, STR_SUBTYPE_FRSKYX2, STR_MULTI_RFTUNE}, @@ -144,6 +147,7 @@ const Multiprotocols multiProtocols { {MODULE_SUBTYPE_MULTI_FRSKYL, 1, false, STR_SUBTYPE_FRSKYL, STR_MULTI_RFTUNE}, {MODULE_SUBTYPE_MULTI_SKYARTEC, 0, false, NO_SUBTYPE, STR_MULTI_RFTUNE}, {MODULE_SUBTYPE_MULTI_ESKY150V2, 0, false, STR_SUBTYPE_ESKY150V2, STR_MULTI_RFTUNE}, + {MODULE_SUBTYPE_MULTI_Q90C, 0, false, NO_SUBTYPE, STR_MULTI_RFTUNE}, {MM_RF_CUSTOM_SELECTED, 7, true, STR_SUBTYPE_CUSTOM, STR_MULTI_OPTION}, // Sentinel and default for protocols not listed above (MM_RF_CUSTOM is 0xff) @@ -188,7 +192,7 @@ QString Multiprotocols::protocolToString(int protocol, bool custom) "Hitec", "Wfly", "Bugs", "Bugs Mini", "Traxxas", "NCC-1701-A", "E01X", "WL Heli V911S", "GD00X", "Volantex V761", "KFPlan KF606", "Redpine", "Potensic", "ZSX", "FlyZone", "Scanner", "FrSky RX", "FlySky AFHDS2A RX", "HoTT", "Fx816", "Bayang RX", "Pelikan", "Tiger", "XK", "XN297 Dump", "FrSky X 2.1", "FrSky R9", "Propel", "FrSky L", "Skyartec", - "ESky 150v2", "DSM RX", "JJRC345" + "ESky 150v2", "DSM RX", "JJRC345", "Q90C" }); return strings.value(protocol, CPN_STR_UNKNOWN_ITEM); diff --git a/radio/src/gui/gui_common.cpp b/radio/src/gui/gui_common.cpp index 1cbf5dcc2..29666fd26 100644 --- a/radio/src/gui/gui_common.cpp +++ b/radio/src/gui/gui_common.cpp @@ -863,7 +863,7 @@ const char STR_SUBTYPE_SYMAX[] = "\003""Std""X5C"; const char STR_SUBTYPE_SLT[] = "\006""V1_6ch""V2_8ch""Q100\0 ""Q200\0 ""MR100\0"; const char STR_SUBTYPE_CX10[] = "\007""Green\0 ""Blue\0 ""DM007\0 ""-\0 ""JC3015a""JC3015b""MK33041"; const char STR_SUBTYPE_CG023[] = "\005""Std\0 ""YD829"; -const char STR_SUBTYPE_BAYANG[] = "\007""Std\0 ""H8S3D\0 ""X16 AH\0""IRDrone""DHD D4"; +const char STR_SUBTYPE_BAYANG[] = "\007""Std\0 ""H8S3D\0 ""X16 AH\0""IRDrone""DHD D4\0""QX100\0 "; 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"; @@ -889,7 +889,9 @@ 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_HOTT[] = "\007""Sync\0 ""No_Sync"; const char STR_SUBTYPE_FX816[] = "\003""P38"; +const char STR_SUBTYPE_PELIKAN[] = "\004""Pro\0""Lite"; const char STR_SUBTYPE_XK[] = "\004""X450""X420"; const char STR_SUBTYPE_XN297DUMP[] = "\004""250K""1M\0 ""2M\0 ""AUTO"; const char STR_SUBTYPE_FRSKYX2[] = "\011""D16\0 ""D16 8ch\0 ""LBT(EU)\0 ""LBT 8ch\0 ""D16Cloned"; @@ -925,7 +927,7 @@ const mm_protocol_definition multi_protocols[] = { {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_BAYANG, 5, 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}, @@ -955,8 +957,9 @@ const mm_protocol_definition multi_protocols[] = { {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, 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_HOTT, 1, true, false, STR_SUBTYPE_HOTT, STR_MULTI_RFTUNE}, {MODULE_SUBTYPE_MULTI_FX816, 0, false, false, STR_SUBTYPE_FX816, nullptr}, + {MODULE_SUBTYPE_MULTI_PELIKAN, 1, false, false, STR_SUBTYPE_PELIKAN, nullptr}, {MODULE_SUBTYPE_MULTI_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}, @@ -965,6 +968,7 @@ const mm_protocol_definition multi_protocols[] = { {MODULE_SUBTYPE_MULTI_FRSKYL, 1, false, false, STR_SUBTYPE_FRSKYL, STR_MULTI_RFTUNE}, {MODULE_SUBTYPE_MULTI_SKYARTEC, 0, false, false, NO_SUBTYPE, STR_MULTI_RFTUNE}, {MODULE_SUBTYPE_MULTI_ESKY150V2, 0, false, true, STR_SUBTYPE_ESKY150V2, STR_MULTI_RFTUNE}, + {MODULE_SUBTYPE_MULTI_Q90C, 0, false, false, NO_SUBTYPE, STR_MULTI_RFTUNE}, {MM_RF_CUSTOM_SELECTED, 7, true, true, NO_SUBTYPE, STR_MULTI_OPTION}, // Sentinel and default for protocols not listed above (MM_RF_CUSTOM is 0xff) diff --git a/radio/src/pulses/modules_constants.h b/radio/src/pulses/modules_constants.h index 829d35c32..1e5879d92 100644 --- a/radio/src/pulses/modules_constants.h +++ b/radio/src/pulses/modules_constants.h @@ -166,11 +166,12 @@ enum ModuleSubtypeMulti { MODULE_SUBTYPE_MULTI_FRSKY_R9, MODULE_SUBTYPE_MULTI_PROPEL, MODULE_SUBTYPE_MULTI_FRSKYL, - MODULE_SUBTYPE_MULTI_SKYARTEC, + MODULE_SUBTYPE_MULTI_SKYARTEC, //65 MODULE_SUBTYPE_MULTI_ESKY150V2, MODULE_SUBTYPE_MULTI_DSM_RX, MODULE_SUBTYPE_MULTI_JJRC345, - MODULE_SUBTYPE_MULTI_LAST = MODULE_SUBTYPE_MULTI_JJRC345 + MODULE_SUBTYPE_MULTI_Q90C, + MODULE_SUBTYPE_MULTI_LAST = MODULE_SUBTYPE_MULTI_Q90C }; #define MODULE_SUBTYPE_MULTI_XN297DP 63-3 diff --git a/radio/src/translations/untranslated.h b/radio/src/translations/untranslated.h index 88289ed22..38631545a 100644 --- a/radio/src/translations/untranslated.h +++ b/radio/src/translations/untranslated.h @@ -125,4 +125,4 @@ #define TR_DSM_PROTOCOLS "LP45""DSM2""DSMX" #define LEN_MULTI_PROTOCOLS "\007" -#define TR_MULTI_PROTOCOLS "FlySky\0""Hubsan\0""FrSky\0 ""Hisky\0 ""V2x2\0 ""DSM\0 ""Devo\0 ""YD717\0 ""KN\0 ""SymaX\0 ""SLT\0 ""CX10\0 ""CG023\0 ""Bayang\0""ESky\0 ""MT99XX\0""MJXq\0 ""Shenqi\0""FY326\0 ""SFHSS\0 ""J6 Pro\0""FQ777\0 ""Assan\0 ""Hontai\0""OpenLrs""FlSky2A""Q2x2\0 ""Walkera""Q303\0 ""GW008\0 ""DM002\0 ""Cabell\0""Esky150""H8 3D\0 ""Corona\0""CFlie\0 ""Hitec\0 ""WFly\0 ""Bugs\0 ""BugMini""Traxxas""NCC1701""E01X\0 ""V911S\0 ""GD00X\0 ""V761\0 ""KF606\0 ""Redpine""Potensi""ZSX\0 ""FlyZone""Scanner""FrSkyRX""FS2A_RX""HoTT\0 ""FX816\0 ""BayanRX""Pelikan""Tiger\0 ""XK\0 ""XN297DU""FrSkyX2""FrSkyR9""Propel\0""FrSkyL\0""Skyarte""ESky-v2""DSM RX\0""JJRC345" +#define TR_MULTI_PROTOCOLS "FlySky\0""Hubsan\0""FrSky\0 ""Hisky\0 ""V2x2\0 ""DSM\0 ""Devo\0 ""YD717\0 ""KN\0 ""SymaX\0 ""SLT\0 ""CX10\0 ""CG023\0 ""Bayang\0""ESky\0 ""MT99XX\0""MJXq\0 ""Shenqi\0""FY326\0 ""SFHSS\0 ""J6 Pro\0""FQ777\0 ""Assan\0 ""Hontai\0""OpenLrs""FlSky2A""Q2x2\0 ""Walkera""Q303\0 ""GW008\0 ""DM002\0 ""Cabell\0""Esky150""H8 3D\0 ""Corona\0""CFlie\0 ""Hitec\0 ""WFly\0 ""Bugs\0 ""BugMini""Traxxas""NCC1701""E01X\0 ""V911S\0 ""GD00X\0 ""V761\0 ""KF606\0 ""Redpine""Potensi""ZSX\0 ""FlyZone""Scanner""FrSkyRX""FS2A_RX""HoTT\0 ""FX816\0 ""BayanRX""Pelikan""Tiger\0 ""XK\0 ""XN297DU""FrSkyX2""FrSkyR9""Propel\0""FrSkyL\0""Skyartc""ESky-v2""DSM RX\0""JJRC345""Q90C\0 " From 5b9d2167c1aa933225540a9997d64af9236474fa Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Mon, 15 Jun 2020 14:21:25 +0200 Subject: [PATCH 81/93] Update CREDITS.txt --- CREDITS.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CREDITS.txt b/CREDITS.txt index 35748e899..7fa64d9aa 100644 --- a/CREDITS.txt +++ b/CREDITS.txt @@ -1749,3 +1749,9 @@ AG-Software Dietmar Drees Winfried Goers Steve Schoonover +N. Haasnoot (monthly) +Wolfram Bahmann +Florian Reck +Gary Bancroft +Karl-Heinz Behn +Stuart Godsmark From 417f36b543a08154c676973b8251b1b626c15cd0 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Mon, 15 Jun 2020 15:07:07 +0200 Subject: [PATCH 82/93] Update CREDITS.txt --- CREDITS.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CREDITS.txt b/CREDITS.txt index 7fa64d9aa..0cd309253 100644 --- a/CREDITS.txt +++ b/CREDITS.txt @@ -1755,3 +1755,4 @@ Florian Reck Gary Bancroft Karl-Heinz Behn Stuart Godsmark +Josko Povse From 4cca618f1ec0b8a90f54fa4a2d544a97183f82f2 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Mon, 15 Jun 2020 16:03:20 +0200 Subject: [PATCH 83/93] Fixes #7739 --- radio/src/audio.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/radio/src/audio.h b/radio/src/audio.h index 4e312f71a..0db4bed45 100644 --- a/radio/src/audio.h +++ b/radio/src/audio.h @@ -18,8 +18,8 @@ * GNU General Public License for more details. */ -#ifndef _AUDIO_ARM_H_ -#define _AUDIO_ARM_H_ +#ifndef _AUDIO_H_ +#define _AUDIO_H_ #include #include "ff.h" @@ -64,7 +64,11 @@ template class BitField { #define INDEX_LOGICAL_SWITCH_AUDIO_FILE(index, event) (2*(index)+(event)) #define INDEX_PHASE_AUDIO_FILE(index, event) (2*(index)+(event)) -constexpr uint8_t AUDIO_FILENAME_MAXLEN = (sizeof("/SOUNDS/fr/") - 1) + LEN_MODEL_NAME + 1 + LEN_FLIGHT_MODE_NAME + (sizeof("-off.wav") - 1); // max length (example: /SOUNDS/fr/123456789012/1234567890-off.wav) +// max length (example: /SOUNDS/fr/123456789012/1234567890-off.wav) +constexpr uint8_t AUDIO_MODEL_FILENAME_MAXLEN = (sizeof("/SOUNDS/fr/") - 1) + LEN_MODEL_NAME + 1 + LEN_FLIGHT_MODE_NAME + (sizeof("-off.wav") - 1); +constexpr uint8_t AUDIO_LUA_FILENAME_MAXLEN = 42; +constexpr uint8_t AUDIO_FILENAME_MAXLEN = (AUDIO_LUA_FILENAME_MAXLEN > AUDIO_MODEL_FILENAME_MAXLEN ? AUDIO_LUA_FILENAME_MAXLEN : AUDIO_MODEL_FILENAME_MAXLEN); + #define AUDIO_QUEUE_LENGTH (16) // must be a power of 2! #define AUDIO_SAMPLE_RATE (32000) @@ -652,4 +656,4 @@ void referenceModelAudioFiles(); bool isAudioFileReferenced(uint32_t i, char * filename/*at least AUDIO_FILENAME_MAXLEN+1 long*/); -#endif // _AUDIO_ARM_H_ +#endif // _AUDIO_H_ From bbfdf1b209c113bf9c516f9d235cd2e0a61e7561 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Mon, 15 Jun 2020 16:07:05 +0200 Subject: [PATCH 84/93] Comment added --- radio/src/audio.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radio/src/audio.h b/radio/src/audio.h index 0db4bed45..35e3cb810 100644 --- a/radio/src/audio.h +++ b/radio/src/audio.h @@ -66,7 +66,7 @@ template class BitField { // max length (example: /SOUNDS/fr/123456789012/1234567890-off.wav) constexpr uint8_t AUDIO_MODEL_FILENAME_MAXLEN = (sizeof("/SOUNDS/fr/") - 1) + LEN_MODEL_NAME + 1 + LEN_FLIGHT_MODE_NAME + (sizeof("-off.wav") - 1); -constexpr uint8_t AUDIO_LUA_FILENAME_MAXLEN = 42; +constexpr uint8_t AUDIO_LUA_FILENAME_MAXLEN = 42; // Some scripts use long audio paths, even on 128x64 boards constexpr uint8_t AUDIO_FILENAME_MAXLEN = (AUDIO_LUA_FILENAME_MAXLEN > AUDIO_MODEL_FILENAME_MAXLEN ? AUDIO_LUA_FILENAME_MAXLEN : AUDIO_MODEL_FILENAME_MAXLEN); #define AUDIO_QUEUE_LENGTH (16) // must be a power of 2! From 702567504da46bb5581e83bfe6dd134047d52acd Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Mon, 15 Jun 2020 16:09:26 +0200 Subject: [PATCH 85/93] Update CREDITS.txt --- CREDITS.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CREDITS.txt b/CREDITS.txt index 0cd309253..52d2c6627 100644 --- a/CREDITS.txt +++ b/CREDITS.txt @@ -1756,3 +1756,4 @@ Gary Bancroft Karl-Heinz Behn Stuart Godsmark Josko Povse +David Reese From 8ea3464df7dbc53dab90a7302e4ff53c54f58515 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Mon, 15 Jun 2020 16:19:27 +0200 Subject: [PATCH 86/93] Cosmetics --- radio/src/audio.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/radio/src/audio.h b/radio/src/audio.h index 35e3cb810..ab6228616 100644 --- a/radio/src/audio.h +++ b/radio/src/audio.h @@ -86,8 +86,6 @@ constexpr uint8_t AUDIO_FILENAME_MAXLEN = (AUDIO_LUA_FILENAME_MAXLEN > AUDIO_MOD #define BEEP_MIN_FREQ (150) #define BEEP_MAX_FREQ (15000) #define BEEP_DEFAULT_FREQ (2250) -#define BEEP_KEY_UP_FREQ (BEEP_DEFAULT_FREQ+150) -#define BEEP_KEY_DOWN_FREQ (BEEP_DEFAULT_FREQ-150) #if defined(AUDIO_DUAL_BUFFER) enum AudioBufferState From 27b5d2ff36b7e64767bbc35081150a09b475e5c9 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Mon, 15 Jun 2020 21:15:30 +0200 Subject: [PATCH 87/93] Update CREDITS.txt --- CREDITS.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CREDITS.txt b/CREDITS.txt index 52d2c6627..181b9bb9a 100644 --- a/CREDITS.txt +++ b/CREDITS.txt @@ -1757,3 +1757,4 @@ Karl-Heinz Behn Stuart Godsmark Josko Povse David Reese +Paul Pearson From 9c70be755a85b0eec9c1e36b8fb22c4c5c026ca4 Mon Sep 17 00:00:00 2001 From: 3djc Date: Tue, 16 Jun 2020 07:20:21 +0200 Subject: [PATCH 88/93] HoTT BCpT scaling fix This fixes #7744 --- radio/src/telemetry/hott.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/radio/src/telemetry/hott.cpp b/radio/src/telemetry/hott.cpp index 98b3c54cc..0d97a274e 100644 --- a/radio/src/telemetry/hott.cpp +++ b/radio/src/telemetry/hott.cpp @@ -123,7 +123,7 @@ const HottSensor hottSensors[] = { {HOTT_ID_RPM1, ZSTR_RPM, UNIT_RPMS, 0}, // RPM1 {HOTT_ID_RPM2, ZSTR_RPM2, UNIT_RPMS, 0}, // RPM2 {HOTT_ID_ESC_VIN, ZSTR_ESC_VIN, UNIT_VOLTS, 1}, // ESC VIN - {HOTT_ID_BCAPA, ZSTR_SMART_BAT_CAPACITY, UNIT_MAH, 2}, // Batt Capa + {HOTT_ID_BCAPA, ZSTR_SMART_BAT_CAPACITY, UNIT_MAH, 0}, // Batt Capa {HOTT_ID_ESC_CUR, ZSTR_ESC_CUR, UNIT_AMPS, 1}, // ESC Amp {HOTT_ID_ESC_TBEC, ZSTR_ESC_TBEC, UNIT_CELSIUS, 0}, // ESC BEC Temp {HOTT_ID_ESC_BCUR, ZSTR_ESC_BCUR, UNIT_AMPS, 1}, // ESC BEC Amp @@ -358,7 +358,7 @@ void processHottPacket(const uint8_t * packet) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_ESC_VIN, 0, HOTT_TELEM_ESC, value, sensor->unit, sensor->precision); // packet[11] uint8_t batt_cap_L; //#11 battery capacity in 10mAh steps // packet[12] uint8_t batt_cap_H; //#12 - value = packet[11] + (packet[12] << 8); + value = (packet[11] + (packet[12] << 8)) * 10; sensor = getHottSensor(HOTT_ID_BCAPA); setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_BCAPA, 0, HOTT_TELEM_ESC, value, sensor->unit, sensor->precision); // packet[13] uint8_t esc_temp; //#13 ESC temperature @@ -491,7 +491,7 @@ void processHottPacket(const uint8_t * packet) case HOTT_PAGE_04: // packet[4 ] uint8_t batt_cap_H; //#34 if (prev_page == ((HOTT_TELEM_GAM << 4) | HOTT_PAGE_03)) { - value = prev_value + (packet[4] << 8); + value = (prev_value + (packet[4] << 8)) * 10; sensor = getHottSensor(HOTT_ID_BCAPA); setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_BCAPA, 0, HOTT_TELEM_GAM, value, sensor->unit, sensor->precision); } From bfc30af29878426e0b412052be6c9c9d4747d5f0 Mon Sep 17 00:00:00 2001 From: 3djc Date: Tue, 16 Jun 2020 08:00:05 +0200 Subject: [PATCH 89/93] HoTT BCpT scaling fix (missed one sensor) --- radio/src/telemetry/hott.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radio/src/telemetry/hott.cpp b/radio/src/telemetry/hott.cpp index 0d97a274e..f35b1544d 100644 --- a/radio/src/telemetry/hott.cpp +++ b/radio/src/telemetry/hott.cpp @@ -611,7 +611,7 @@ void processHottPacket(const uint8_t * packet) case HOTT_PAGE_04: // packet[4 ] uint8_t batt_cap_H; //#34 if (prev_page == ((HOTT_TELEM_EAM << 4) | HOTT_PAGE_03)) { - value = prev_value + (packet[4] << 8); + value = (prev_value + (packet[4] << 8)) * 10; sensor = getHottSensor(HOTT_ID_BCAPA); setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_BCAPA, 0, HOTT_TELEM_EAM, value, sensor->unit, sensor->precision); } From 798c98d506a8174d2ef14744ab4870a02f4d09d0 Mon Sep 17 00:00:00 2001 From: 3djc Date: Tue, 16 Jun 2020 08:39:17 +0200 Subject: [PATCH 90/93] Fix some spanish translation This fixes #7743 --- radio/src/translations/es.h.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/radio/src/translations/es.h.txt b/radio/src/translations/es.h.txt index fcfade7a1..16752d94f 100644 --- a/radio/src/translations/es.h.txt +++ b/radio/src/translations/es.h.txt @@ -240,12 +240,12 @@ #define TR_FSW_RESET_TELEM TR("Telm", "Telemetría") #if LCD_W >= 212 - #define TR_FSW_RESET_TIMERS "Timer 1\0 ""Timer 2\0 ""Timer 3\0 " + #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 "Todo" TR_FSW_RESET_TELEM, TR_FSW_RESET_TIMERS "Todo\0 " TR_FSW_RESET_TELEM) +#define TR_VFSWRESET TR(TR_FSW_RESET_TIMERS "Todo" TR_FSW_RESET_TELEM, TR_FSW_RESET_TIMERS "Vuelo\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") From edc57f70cc3ba5a9479e81d75035c0f836c522a0 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Tue, 16 Jun 2020 09:01:53 +0200 Subject: [PATCH 91/93] Update CREDITS.txt --- CREDITS.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CREDITS.txt b/CREDITS.txt index 181b9bb9a..f488b3c7a 100644 --- a/CREDITS.txt +++ b/CREDITS.txt @@ -1758,3 +1758,5 @@ Stuart Godsmark Josko Povse David Reese Paul Pearson +Stuart Olson +Pierre Connan From e4336857869a53e3fdc699c0ae333e46230995e8 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Tue, 16 Jun 2020 10:04:18 +0200 Subject: [PATCH 92/93] Update CREDITS.txt --- CREDITS.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CREDITS.txt b/CREDITS.txt index f488b3c7a..4fcf98a29 100644 --- a/CREDITS.txt +++ b/CREDITS.txt @@ -1760,3 +1760,4 @@ David Reese Paul Pearson Stuart Olson Pierre Connan +Henk Eeltink From fca11fc6b6df65939ced578e113f4bb1941bd88e Mon Sep 17 00:00:00 2001 From: DanielGeA Date: Wed, 17 Jun 2020 14:55:42 +0100 Subject: [PATCH 93/93] Fix mixer overflow (#7747) --- radio/src/mixer.cpp | 2 +- radio/src/tests/gtests.h | 1 + radio/src/tests/mixer.cpp | 61 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 1 deletion(-) diff --git a/radio/src/mixer.cpp b/radio/src/mixer.cpp index 3f373ae6e..0e75f94d7 100644 --- a/radio/src/mixer.cpp +++ b/radio/src/mixer.cpp @@ -947,7 +947,7 @@ void evalMixes(uint8_t tick10ms) mixerCurrentFlightMode = p; evalFlightModeMixes(p==fm ? e_perout_mode_normal : e_perout_mode_inactive_flight_mode, p==fm ? tick10ms : 0); for (uint8_t i=0; i> 4) * fp_act[p]; + sum_chans512[i] += limit(-0x6fff, chans[i] >> 4, 0x6fff) * fp_act[p]; weight += fp_act[p]; } } diff --git a/radio/src/tests/gtests.h b/radio/src/tests/gtests.h index ab5c35abd..a1f6f5d24 100644 --- a/radio/src/tests/gtests.h +++ b/radio/src/tests/gtests.h @@ -65,6 +65,7 @@ inline void MODEL_RESET() memset(&anaInValues, 0, sizeof(anaInValues)); extern uint8_t s_mixer_first_run_done; s_mixer_first_run_done = false; + evalMixes(1); // this is needed to reset fp_act lastFlightMode = 255; } diff --git a/radio/src/tests/mixer.cpp b/radio/src/tests/mixer.cpp index 8d8058d31..074f7f6ca 100644 --- a/radio/src/tests/mixer.cpp +++ b/radio/src/tests/mixer.cpp @@ -47,6 +47,22 @@ class MixerTest : public OpenTxTest {}; } \ } while (0) +#define CHECK_FLIGHT_MODE_TRANSITION(channel, duration, initValue, endValue) \ + do { \ + uint32_t delta = 0xffff / duration; \ + int32_t weightInit = 0xffff; \ + int32_t weightEnd = 0; \ + for (int i = 0; i <= (duration); i++) { \ + evalMixes(1); \ + GTEST_ASSERT_LE( abs(((initValue) * weightInit + (endValue) * weightEnd) / 0xffff - channelOutputs[(channel)]), 1); \ + weightInit = weightInit - delta; \ + weightEnd = weightEnd + delta; \ + } \ + for (int i = 0; i < 100; i++) { /* be sure the transition is finished*/ \ + evalMixes(1); \ + } \ + } while (0) + TEST_F(TrimsTest, throttleTrim) { g_model.thrTrim = 1; @@ -659,3 +675,48 @@ TEST(Trainer, UnpluggedTest) ppmInput[0] = 1024; CHECK_DELAY(0, 5000); } + +TEST_F(MixerTest, flightModeTransition) +{ + SYSTEM_RESET(); + MODEL_RESET(); + MIXER_RESET(); + modelDefault(0); + g_model.flightModeData[1].swtch = TR(SWSRC_ID2, SWSRC_SA2); + g_model.flightModeData[0].fadeIn = 100; + g_model.flightModeData[0].fadeOut = 100; + g_model.flightModeData[1].fadeIn = 100; + g_model.flightModeData[1].fadeOut = 100; + g_model.mixData[0].destCh = 0; + g_model.mixData[0].mltpx = MLTPX_REP; + g_model.mixData[0].srcRaw = MIXSRC_MAX; + g_model.mixData[0].flightModes = 0b11110; + g_model.mixData[0].weight = 100; + g_model.mixData[1].destCh = 0; + g_model.mixData[1].mltpx = MLTPX_REP; + g_model.mixData[1].srcRaw = MIXSRC_MAX; + g_model.mixData[1].flightModes = 0b11101; + g_model.mixData[1].weight = -10; + evalMixes(1); + simuSetSwitch(0, 1); + CHECK_FLIGHT_MODE_TRANSITION(0, 1000, 1024, -102); +} + +TEST_F(MixerTest, flightModeOverflow) +{ + SYSTEM_RESET(); + MODEL_RESET(); + MIXER_RESET(); + modelDefault(0); + g_model.flightModeData[1].swtch = TR(SWSRC_ID2, SWSRC_SA2); + g_model.flightModeData[0].fadeIn = 100; + g_model.flightModeData[0].fadeOut = 100; + g_model.mixData[0].destCh = 0; + g_model.mixData[0].mltpx = MLTPX_REP; + g_model.mixData[0].srcRaw = MIXSRC_MAX; + g_model.mixData[0].flightModes = 0; + g_model.mixData[0].weight = 250; + evalMixes(1); + simuSetSwitch(0, 1); + CHECK_FLIGHT_MODE_TRANSITION(0, 1000, 1024, 1024); +}