From 8646ced5c2d913e42720624bd6507c9a44f0903f Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Mon, 10 Jun 2019 22:27:28 +0200 Subject: [PATCH 001/350] Typo --- CREDITS.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CREDITS.txt b/CREDITS.txt index 40bca616c..2a61c5e0e 100644 --- a/CREDITS.txt +++ b/CREDITS.txt @@ -40,8 +40,7 @@ Michael Byrne Craft & Theory (monthly) OpenTX Manuals by Lothar Thole Team BlackSheep -Team BlackSheep -www.3dxr.co.uk +3DXR [People who have donated to OpenTX] Mario Sette From e3ec3fa45edd61ab547be74826374e1a87cd7bf4 Mon Sep 17 00:00:00 2001 From: 3djc Date: Tue, 11 Jun 2019 08:56:34 +0200 Subject: [PATCH 002/350] Fix compilation options --- radio/util/fwoptions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/radio/util/fwoptions.py b/radio/util/fwoptions.py index 2a2d739d2..a32399004 100755 --- a/radio/util/fwoptions.py +++ b/radio/util/fwoptions.py @@ -116,7 +116,7 @@ options_taranis_x9lite = { "shutdownconfirm": ("SHUTDOWN_CONFIRMATION", "YES", "NO"), "eu": ("SUPPORT_D16_EU_ONLY", "YES", "NO"), "multimodule": ("MULTIMODULE", "YES", "NO"), - "internalpxx1": ("INTERNAL_MODULE_PXX1", "NO", "YES"), + "internalpxx1": ("INTERNAL_MODULE_PXX1", "YES", "NO"), "crossfire": ("CROSSFIRE", "YES", "NO") } @@ -149,7 +149,7 @@ options_taranis_xlites = { "shutdownconfirm": ("SHUTDOWN_CONFIRMATION", "YES", "NO"), "eu": ("SUPPORT_D16_EU_ONLY", "YES", "NO"), "multimodule": ("MULTIMODULE", "YES", "NO"), - "internalpxx1": ("INTERNAL_MODULE_PXX1", "NO", "YES"), + "internalpxx1": ("INTERNAL_MODULE_PXX1", "YES", "NO"), "crossfire": ("CROSSFIRE", "YES", "NO") } From 02302bdc1436ad97c4473edb8fbca2e161ef0f96 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Tue, 11 Jun 2019 12:53:45 +0200 Subject: [PATCH 003/350] Latency optimization using hearbeat bugfix --- .../src/targets/common/arm/stm32/heartbeat_driver.cpp | 10 +++++++--- .../targets/common/arm/stm32/rotary_encoder_driver.cpp | 2 +- radio/src/targets/taranis/board.h | 4 ++-- radio/src/targets/taranis/intmodule_pulses_driver.cpp | 2 +- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/radio/src/targets/common/arm/stm32/heartbeat_driver.cpp b/radio/src/targets/common/arm/stm32/heartbeat_driver.cpp index 2281fa866..46ddfd1b6 100644 --- a/radio/src/targets/common/arm/stm32/heartbeat_driver.cpp +++ b/radio/src/targets/common/arm/stm32/heartbeat_driver.cpp @@ -65,10 +65,14 @@ void stop_intmodule_heartbeat() EXTI_Init(&EXTI_InitStructure); } -void check_xjt_heartbeat() +void check_intmodule_heartbeat() { if (EXTI_GetITStatus(INTMODULE_HEARTBEAT_EXTI_LINE) != RESET) { - heartbeatCapture.timestamp = TIMER_2MHz_TIMER->CNT; +#if defined(PXX2) + heartbeatCapture.timestamp = RTOS_GET_MS(); +#else + heartbeatCapture.timestamp = getTmr2MHz(); +#endif heartbeatCapture.count++; EXTI_ClearITPendingBit(INTMODULE_HEARTBEAT_EXTI_LINE); } @@ -78,6 +82,6 @@ void check_xjt_heartbeat() #if defined(INTMODULE_HEARTBEAT) && !defined(INTMODULE_HEARTBEAT_REUSE_INTERRUPT_ROTARY_ENCODER) extern "C" void INTMODULE_HEARTBEAT_EXTI_IRQHandler() { - check_xjt_heartbeat(); + check_intmodule_heartbeat(); } #endif diff --git a/radio/src/targets/common/arm/stm32/rotary_encoder_driver.cpp b/radio/src/targets/common/arm/stm32/rotary_encoder_driver.cpp index 6e763f058..ea94cdaaf 100644 --- a/radio/src/targets/common/arm/stm32/rotary_encoder_driver.cpp +++ b/radio/src/targets/common/arm/stm32/rotary_encoder_driver.cpp @@ -92,7 +92,7 @@ extern "C" void ROTARY_ENCODER_EXTI_IRQHandler1(void) #endif #if !defined(BOOT) && defined(INTMODULE_HEARTBEAT_REUSE_INTERRUPT_ROTARY_ENCODER) - check_xjt_heartbeat(); + check_intmodule_heartbeat(); #endif } diff --git a/radio/src/targets/taranis/board.h b/radio/src/targets/taranis/board.h index 671677dfc..aca1b8f67 100644 --- a/radio/src/targets/taranis/board.h +++ b/radio/src/targets/taranis/board.h @@ -273,11 +273,11 @@ void extmoduleSendNextFrame(); #if defined(INTMODULE_HEARTBEAT_GPIO) void init_intmodule_heartbeat(); void stop_intmodule_heartbeat(); -void check_xjt_heartbeat(); +void check_intmodule_heartbeat(); #else #define init_intmodule_heartbeat() #define stop_intmodule_heartbeat() -#define check_xjt_heartbeat() +#define check_intmodule_heartbeat() #endif // SBUS diff --git a/radio/src/targets/taranis/intmodule_pulses_driver.cpp b/radio/src/targets/taranis/intmodule_pulses_driver.cpp index 044883034..822bb0b36 100644 --- a/radio/src/targets/taranis/intmodule_pulses_driver.cpp +++ b/radio/src/targets/taranis/intmodule_pulses_driver.cpp @@ -46,7 +46,7 @@ void intmoduleSendNextFrame() { uint32_t last = intmodulePulsesData.pxx.getLast(); if (heartbeatCapture.valid) { - if (TIMER_2MHz_TIMER->CNT - heartbeatCapture.timestamp > HEARBEAT_OFFSET) + if (getTmr2MHz() - heartbeatCapture.timestamp > HEARBEAT_OFFSET) last -= 21; else last += 19; From 3aab7b8a37d74ffaf3164f804c7efa13220762c3 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Tue, 11 Jun 2019 17:06:09 +0200 Subject: [PATCH 004/350] [ACCESS] Automatic detection of the module for accessPushTelemetry if module < 0 --- .../src/gui/common/stdlcd/radio_sdmanager.cpp | 2 +- radio/src/gui/common/stdlcd/radio_tools.cpp | 2 ++ radio/src/logs.cpp | 1 - radio/src/lua/api_general.cpp | 31 +++++++++++++++++-- 4 files changed, 32 insertions(+), 4 deletions(-) diff --git a/radio/src/gui/common/stdlcd/radio_sdmanager.cpp b/radio/src/gui/common/stdlcd/radio_sdmanager.cpp index 6554e12c3..be9522fcc 100644 --- a/radio/src/gui/common/stdlcd/radio_sdmanager.cpp +++ b/radio/src/gui/common/stdlcd/radio_sdmanager.cpp @@ -79,7 +79,7 @@ void onSdFormatConfirm(const char * result) #endif audioQueue.stopSD(); if (sdCardFormat()) { - f_chdir("/"); + f_chdir(ROOT_PATH); REFRESH_FILES(); } } diff --git a/radio/src/gui/common/stdlcd/radio_tools.cpp b/radio/src/gui/common/stdlcd/radio_tools.cpp index d7baa272d..4e21add61 100644 --- a/radio/src/gui/common/stdlcd/radio_tools.cpp +++ b/radio/src/gui/common/stdlcd/radio_tools.cpp @@ -32,6 +32,7 @@ bool addRadioTool(uint8_t index, const char * label) lcdDrawText(3*FW, y, label, (sub == index ? INVERS : 0)); if (attr && s_editMode > 0) { s_editMode = 0; + killAllEvents(); return true; } return false; @@ -101,6 +102,7 @@ void addRadioScriptTool(uint8_t index, const char * filename) } if (addRadioTool(index, label)) { + f_chdir("/SCRIPTS/TOOLS/"); luaExec(path); } } diff --git a/radio/src/logs.cpp b/radio/src/logs.cpp index cc5de96bb..1094d6af7 100644 --- a/radio/src/logs.cpp +++ b/radio/src/logs.cpp @@ -229,7 +229,6 @@ void logsWrite() #endif #if defined(TELEMETRY_FRSKY) - for (int i=0; i Date: Wed, 12 Jun 2019 08:22:04 +0200 Subject: [PATCH 005/350] Fixes #6846 --- radio/src/telemetry/telemetry.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radio/src/telemetry/telemetry.h b/radio/src/telemetry/telemetry.h index 372219fad..5998527b8 100644 --- a/radio/src/telemetry/telemetry.h +++ b/radio/src/telemetry/telemetry.h @@ -217,7 +217,7 @@ class OutputTelemetryBuffer { crc += crc >> 8; // 0-100 crc &= 0x00ff; } - pushByte(0xFF - crc); + pushByteWithBytestuffing(0xFF - crc); } public: From 74cd67fa35625cd6789f788bae925abcc4e371bf Mon Sep 17 00:00:00 2001 From: 3djc Date: Wed, 12 Jun 2019 10:31:32 +0200 Subject: [PATCH 006/350] Improve wording arround Aux Serial --- radio/src/translations/cz.h.txt | 4 ++-- radio/src/translations/de.h.txt | 4 ++-- radio/src/translations/en.h.txt | 4 ++-- radio/src/translations/es.h.txt | 4 ++-- radio/src/translations/fi.h.txt | 4 ++-- radio/src/translations/fr.h.txt | 4 ++-- radio/src/translations/nl.h.txt | 4 ++-- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/radio/src/translations/cz.h.txt b/radio/src/translations/cz.h.txt index 1f19fff1f..7426e5a7f 100644 --- a/radio/src/translations/cz.h.txt +++ b/radio/src/translations/cz.h.txt @@ -71,9 +71,9 @@ #define LEN_UART3MODES "\015" #if defined(CLI) || defined(DEBUG) -#define TR_UART3MODES "Debug\0 ""S-Port Mirror""Telemetrie\0 ""SBUS Trenér\0 ""LUA\0 " +#define TR_UART3MODES "Debug\0 ""Telem Mirror\0""Telemetry In\0""SBUS Trenér\0 ""LUA\0 " #else -#define TR_UART3MODES "VYP\0 ""S-Port Mirror""Telemetrie\0 ""SBUS Trenér\0 ""LUA\0 " +#define TR_UART3MODES "VYP\0 ""Telem Mirror\0""Telemetry In\0""SBUS Trenér\0 ""LUA\0 " #endif #define LEN_SWTYPES "\013" diff --git a/radio/src/translations/de.h.txt b/radio/src/translations/de.h.txt index b471bdd1a..78278b7de 100644 --- a/radio/src/translations/de.h.txt +++ b/radio/src/translations/de.h.txt @@ -72,9 +72,9 @@ #define LEN_UART3MODES "\015" #if defined(CLI) || defined(DEBUG) -#define TR_UART3MODES "Debug\0 ""S-Port Mirror""Telemetrie\0 ""SBUS Eingang\0""LUA\0 " +#define TR_UART3MODES "Debug\0 ""Telem Mirror\0""Telemetry In\0""SBUS Eingang\0""LUA\0 " #else -#define TR_UART3MODES "AUS\0 ""S-Port Mirror""Telemetrie\0 ""SBUS Eingang\0""LUA\0 " +#define TR_UART3MODES "AUS\0 ""Telem Mirror\0""Telemetry In\0""SBUS Eingang\0""LUA\0 " #endif #define LEN_SWTYPES "\006" diff --git a/radio/src/translations/en.h.txt b/radio/src/translations/en.h.txt index fae6870a8..3cd4c2ccc 100644 --- a/radio/src/translations/en.h.txt +++ b/radio/src/translations/en.h.txt @@ -72,9 +72,9 @@ #define LEN_UART3MODES "\015" #if defined(CLI) || defined(DEBUG) -#define TR_UART3MODES "Debug\0 ""S-Port Mirror""Telemetry\0 ""SBUS Trainer\0""LUA\0 " +#define TR_UART3MODES "Debug\0 ""Telem Mirror\0""Telemetry In\0""SBUS Trainer\0""LUA\0 " #else -#define TR_UART3MODES "OFF\0 ""S-Port Mirror""Telemetry\0 ""SBUS Trainer\0""LUA\0 " +#define TR_UART3MODES "OFF\0 ""Telem Mirror\0""Telemetry In\0""SBUS Trainer\0""LUA\0 " #endif #define LEN_SWTYPES "\006" diff --git a/radio/src/translations/es.h.txt b/radio/src/translations/es.h.txt index 86d0d786c..fa2817189 100644 --- a/radio/src/translations/es.h.txt +++ b/radio/src/translations/es.h.txt @@ -72,9 +72,9 @@ #define LEN_UART3MODES "\015" #if defined(CLI) || defined(DEBUG) -#define TR_UART3MODES "Debug\0 ""S-Port Mirror""Telemetry\0 ""SBUS Trainer\0""LUA\0 " +#define TR_UART3MODES "Debug\0 ""Telem Mirror\0""Telemetry In\0""SBUS Trainer\0""LUA\0 " #else -#define TR_UART3MODES "OFF\0 ""S-Port Mirror""Telemetry\0 ""SBUS Trainer\0""LUA\0 " +#define TR_UART3MODES "OFF\0 ""Telem Mirror\0""Telemetry In\0""SBUS Trainer\0""LUA\0 " #endif #define LEN_SWTYPES "\006" diff --git a/radio/src/translations/fi.h.txt b/radio/src/translations/fi.h.txt index cbf41d2b4..8d294401b 100644 --- a/radio/src/translations/fi.h.txt +++ b/radio/src/translations/fi.h.txt @@ -72,9 +72,9 @@ #define LEN_UART3MODES "\015" #if defined(CLI) || defined(DEBUG) -#define TR_UART3MODES "Debug\0 ""S-Port Pelik\0""Telemetry\0 ""SBUS Trainer\0""LUA\0 " +#define TR_UART3MODES "Debug\0 ""S-Port Pelik\0""Telemetry In\0""SBUS Trainer\0""LUA\0 " #else -#define TR_UART3MODES "POIS\0 ""S-Port Pelik\0""Telemetry\0 ""SBUS Trainer\0""LUA\0 " +#define TR_UART3MODES "POIS\0 ""S-Port Pelik\0""Telemetry In\0""SBUS Trainer\0""LUA\0 " #endif #define LEN_SWTYPES "\006" diff --git a/radio/src/translations/fr.h.txt b/radio/src/translations/fr.h.txt index 3a1784f20..05c968aee 100644 --- a/radio/src/translations/fr.h.txt +++ b/radio/src/translations/fr.h.txt @@ -72,9 +72,9 @@ #define LEN_UART3MODES "\016" #if defined(CLI) || defined(DEBUG) -#define TR_UART3MODES "Debug\0 ""Recopie S-Port""Télémétrie\0 ""Ecolage SBUS\0 ""LUA\0 " +#define TR_UART3MODES "Debug\0 ""Recopie Telem\0""Télémétrie In\0""Ecolage SBUS\0 ""LUA\0 " #else -#define TR_UART3MODES "OFF\0 ""Recopie S-Port""Télémétrie\0 ""Ecolage SBUS\0 ""LUA\0 " +#define TR_UART3MODES "OFF\0 ""Recopie Telem\0""Télémétrie In\0""Ecolage SBUS\0 ""LUA\0 " #endif #define LEN_SWTYPES "\006" diff --git a/radio/src/translations/nl.h.txt b/radio/src/translations/nl.h.txt index f1738dffb..f944e9d34 100644 --- a/radio/src/translations/nl.h.txt +++ b/radio/src/translations/nl.h.txt @@ -72,9 +72,9 @@ #define LEN_UART3MODES "\015" #if defined(CLI) || defined(DEBUG) -#define TR_UART3MODES "Debug\0 ""S-Port Mirror""Telemetrie\0 ""SBUS Leerling""LUA\0 " +#define TR_UART3MODES "Debug\0 ""Telem Mirror\0""Telemetry In\0""SBUS Leerling""LUA\0 " #else -#define TR_UART3MODES "UIT\0 ""S-Port Mirror""Telemetrie\0 ""SBUS Leerling""LUA\0 " +#define TR_UART3MODES "UIT\0 ""Telem Mirror\0""Telemetry In\0""SBUS Leerling""LUA\0 " #endif #define LEN_SWTYPES "\006" From f888b83add8bdb364ffb7b0da0e69bbcde698f0d Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Wed, 12 Jun 2019 14:06:11 +0200 Subject: [PATCH 007/350] R9M Access Fixes --- radio/src/gui/128x64/model_setup.cpp | 4 ++-- radio/src/gui/212x64/model_setup.cpp | 2 +- radio/src/gui/common/stdlcd/model_receiver_options.cpp | 2 +- radio/src/gui/common/stdlcd/model_setup_pxx2.cpp | 10 +++++----- .../src/gui/common/stdlcd/radio_spectrum_analyser.cpp | 2 +- radio/src/gui/gui_common.h | 2 +- radio/src/pulses/modules_helpers.h | 6 +++--- radio/src/pulses/pxx2.cpp | 7 ++++++- 8 files changed, 20 insertions(+), 15 deletions(-) diff --git a/radio/src/gui/128x64/model_setup.cpp b/radio/src/gui/128x64/model_setup.cpp index ff9a5378f..e70fc4773 100644 --- a/radio/src/gui/128x64/model_setup.cpp +++ b/radio/src/gui/128x64/model_setup.cpp @@ -1194,7 +1194,7 @@ void menuModelSetup(event_t event) drawReceiverName(MODEL_SETUP_2ND_COLUMN, y, moduleIdx, receiverIdx, attr); - if (s_editMode && isModuleR9M2(moduleIdx) && moduleState[moduleIdx].mode == MODULE_MODE_NORMAL && moduleInformation.information.modelID) { + if (s_editMode && isModuleR9MAccess(moduleIdx) && moduleState[moduleIdx].mode == MODULE_MODE_NORMAL && moduleInformation.information.modelID) { moduleInformation.information.modelID = 0; moduleState[moduleIdx].startBind(&reusableBuffer.moduleSetup.bindInformation); } @@ -1338,7 +1338,7 @@ void menuModelSetup(event_t event) if (attr && l_posHorz > 0) { if (s_editMode > 0) { if (l_posHorz == 1) { - if (isModuleR9M(moduleIdx) || (isModuleXJT(moduleIdx) && g_model.moduleData[moduleIdx].rfProtocol == MODULE_SUBTYPE_PXX1_ACCST_D16) || (isModuleXJT2(moduleIdx) && g_model.moduleData[moduleIdx].subType == MODULE_SUBTYPE_ISRM_PXX2_ACCST_D16) || (isModuleR9M2(moduleIdx) && g_model.moduleData[moduleIdx].subType != MODULE_SUBTYPE_R9M_PXX2_ACCESS)) { + if (isModuleR9M(moduleIdx) || (isModuleXJT(moduleIdx) && g_model.moduleData[moduleIdx].rfProtocol == MODULE_SUBTYPE_PXX1_ACCST_D16) || (isModuleXJT2(moduleIdx) && g_model.moduleData[moduleIdx].subType == MODULE_SUBTYPE_ISRM_PXX2_ACCST_D16) || (isModuleR9MAccess(moduleIdx) && g_model.moduleData[moduleIdx].subType != MODULE_SUBTYPE_R9M_PXX2_ACCESS)) { #if defined(PCBXLITE) if (EVT_KEY_MASK(event) == KEY_ENTER) { #elif defined(PCBSKY9X) || defined(PCBAR9X) diff --git a/radio/src/gui/212x64/model_setup.cpp b/radio/src/gui/212x64/model_setup.cpp index 38b7cf864..2650579a7 100644 --- a/radio/src/gui/212x64/model_setup.cpp +++ b/radio/src/gui/212x64/model_setup.cpp @@ -1414,7 +1414,7 @@ void menuModelSetup(event_t event) drawReceiverName(MODEL_SETUP_2ND_COLUMN, y, moduleIdx, receiverIdx, attr); - if (s_editMode && isModuleR9M2(moduleIdx) && moduleState[moduleIdx].mode == MODULE_MODE_NORMAL && moduleInformation.information.modelID) { + if (s_editMode && isModuleR9MAccess(moduleIdx) && moduleState[moduleIdx].mode == MODULE_MODE_NORMAL && moduleInformation.information.modelID) { moduleInformation.information.modelID = 0; moduleState[moduleIdx].startBind(&reusableBuffer.moduleSetup.bindInformation); } diff --git a/radio/src/gui/common/stdlcd/model_receiver_options.cpp b/radio/src/gui/common/stdlcd/model_receiver_options.cpp index f5c799095..7d1be30bd 100644 --- a/radio/src/gui/common/stdlcd/model_receiver_options.cpp +++ b/radio/src/gui/common/stdlcd/model_receiver_options.cpp @@ -111,7 +111,7 @@ void menuModelReceiverOptions(event_t event) break; case ITEM_RECEIVER_PWM_RATE: - reusableBuffer.hardwareAndSettings.receiverSettings.pwmRate = editCheckBox(reusableBuffer.hardwareAndSettings.receiverSettings.pwmRate, RECEIVER_OPTIONS_2ND_COLUMN, y, isModuleR9M2(g_moduleIdx) ? "6.67ms PWM": "9ms PWM", attr, event); + reusableBuffer.hardwareAndSettings.receiverSettings.pwmRate = editCheckBox(reusableBuffer.hardwareAndSettings.receiverSettings.pwmRate, RECEIVER_OPTIONS_2ND_COLUMN, y, isModuleR9MAccess(g_moduleIdx) ? "6.67ms PWM": "9ms PWM", attr, event); if (attr && checkIncDec_Ret) { reusableBuffer.hardwareAndSettings.receiverSettings.dirty = true; } diff --git a/radio/src/gui/common/stdlcd/model_setup_pxx2.cpp b/radio/src/gui/common/stdlcd/model_setup_pxx2.cpp index 36f82ba6a..d865d1aec 100644 --- a/radio/src/gui/common/stdlcd/model_setup_pxx2.cpp +++ b/radio/src/gui/common/stdlcd/model_setup_pxx2.cpp @@ -50,10 +50,10 @@ void onPXX2R9MBindModeMenu(const char * result) else if (result == STR_16CH_WITHOUT_TELEMETRY) { reusableBuffer.moduleSetup.bindInformation.lbtMode = 2; } - else if (result == STR_FLEX_868) { + else if (result == STR_FLEX_915) { reusableBuffer.moduleSetup.bindInformation.flexMode = 0; } - else if (result == STR_FLEX_915) { + else if (result == STR_FLEX_868) { reusableBuffer.moduleSetup.bindInformation.flexMode = 1; } else { @@ -83,14 +83,14 @@ void onPXX2BindMenu(const char * result) if (result != STR_EXIT) { uint8_t moduleIdx = CURRENT_MODULE_EDITED(menuVerticalPosition - HEADER_LINE); reusableBuffer.moduleSetup.bindInformation.selectedReceiverIndex = (result - reusableBuffer.moduleSetup.bindInformation.candidateReceiversNames[0]) / sizeof(reusableBuffer.moduleSetup.bindInformation.candidateReceiversNames[0]); - if (isModuleR9M2(moduleIdx) && reusableBuffer.moduleSetup.pxx2.moduleInformation.information.variant == PXX2_VARIANT_EU) { + if (isModuleR9MAccess(moduleIdx) && reusableBuffer.moduleSetup.pxx2.moduleInformation.information.variant == PXX2_VARIANT_EU) { reusableBuffer.moduleSetup.bindInformation.step = BIND_RX_NAME_SELECTED; POPUP_MENU_ADD_ITEM(STR_8CH_WITH_TELEMETRY); POPUP_MENU_ADD_ITEM(STR_16CH_WITH_TELEMETRY); POPUP_MENU_ADD_ITEM(STR_16CH_WITHOUT_TELEMETRY); POPUP_MENU_START(onPXX2R9MBindModeMenu); } - else if (isModuleR9M2(moduleIdx) && reusableBuffer.moduleSetup.pxx2.moduleInformation.information.variant == PXX2_VARIANT_FLEX) { + else if (isModuleR9MAccess(moduleIdx) && reusableBuffer.moduleSetup.pxx2.moduleInformation.information.variant == PXX2_VARIANT_FLEX) { reusableBuffer.moduleSetup.bindInformation.step = BIND_RX_NAME_SELECTED; POPUP_MENU_ADD_ITEM(STR_FLEX_868); POPUP_MENU_ADD_ITEM(STR_FLEX_915); @@ -142,7 +142,7 @@ void onPXX2ReceiverMenu(const char * result) else if (result == STR_BIND) { memclear(&reusableBuffer.moduleSetup.bindInformation, sizeof(BindInformation)); reusableBuffer.moduleSetup.bindInformation.rxUid = receiverIdx; - if (isModuleR9M2(moduleIdx)) { + if (isModuleR9MAccess(moduleIdx)) { #if defined(SIMU) reusableBuffer.moduleSetup.pxx2.moduleInformation.information.modelID = 1; reusableBuffer.moduleSetup.pxx2.moduleInformation.information.variant = 2; diff --git a/radio/src/gui/common/stdlcd/radio_spectrum_analyser.cpp b/radio/src/gui/common/stdlcd/radio_spectrum_analyser.cpp index 48349d8e8..693032325 100644 --- a/radio/src/gui/common/stdlcd/radio_spectrum_analyser.cpp +++ b/radio/src/gui/common/stdlcd/radio_spectrum_analyser.cpp @@ -51,7 +51,7 @@ void menuRadioSpectrumAnalyser(event_t event) return; } - if (isModuleR9M2(g_moduleIdx)) { + if (isModuleR9MAccess(g_moduleIdx)) { reusableBuffer.spectrumAnalyser.spanDefault = 20; reusableBuffer.spectrumAnalyser.spanMax = 40; reusableBuffer.spectrumAnalyser.freqDefault = 890; diff --git a/radio/src/gui/gui_common.h b/radio/src/gui/gui_common.h index a14d0f329..ef5923cc3 100644 --- a/radio/src/gui/gui_common.h +++ b/radio/src/gui/gui_common.h @@ -156,7 +156,7 @@ const mm_protocol_definition *getMultiProtocolDefinition (uint8_t protocol); #define IS_D8_RX(x) (g_model.moduleData[x].rfProtocol == MODULE_SUBTYPE_PXX1_ACCST_D8) #define IS_R9M_OR_XJTD16(x) ((isModuleXJT(x) && g_model.moduleData[x].rfProtocol== MODULE_SUBTYPE_PXX1_ACCST_D16) || isModuleR9M(x)) -#define FAILSAFE_ROWS(x) ((isModuleXJTVariant(x) && HAS_RF_PROTOCOL_FAILSAFE(g_model.moduleData[x].rfProtocol)) || MULTIMODULE_HASFAILSAFE(x) || isModuleR9M(x) || isModuleR9M2(x)) ? (g_model.moduleData[x].failsafeMode==FAILSAFE_CUSTOM ? (uint8_t)1 : (uint8_t)0) : HIDDEN_ROW +#define FAILSAFE_ROWS(x) ((isModuleXJTVariant(x) && HAS_RF_PROTOCOL_FAILSAFE(g_model.moduleData[x].rfProtocol)) || MULTIMODULE_HASFAILSAFE(x) || isModuleR9M(x) || isModuleR9MAccess(x)) ? (g_model.moduleData[x].failsafeMode==FAILSAFE_CUSTOM ? (uint8_t)1 : (uint8_t)0) : HIDDEN_ROW #define EXTERNAL_MODULE_OPTION_ROW (isModuleR9M(EXTERNAL_MODULE) || isModuleSBUS(EXTERNAL_MODULE) ? TITLE_ROW : MULTIMODULE_OPTIONS_ROW) diff --git a/radio/src/pulses/modules_helpers.h b/radio/src/pulses/modules_helpers.h index 2ae4280bf..1d2325078 100644 --- a/radio/src/pulses/modules_helpers.h +++ b/radio/src/pulses/modules_helpers.h @@ -108,7 +108,7 @@ inline bool isModuleR9M(uint8_t idx) return g_model.moduleData[idx].type == MODULE_TYPE_R9M_PXX1 || g_model.moduleData[idx].type == MODULE_TYPE_R9M_LITE_PXX1; } -inline bool isModuleR9M2(uint8_t idx) +inline bool isModuleR9MAccess(uint8_t idx) { return g_model.moduleData[idx].type == MODULE_TYPE_R9M_PXX2 || g_model.moduleData[idx].type == MODULE_TYPE_R9M_LITE_PXX2 || g_model.moduleData[idx].type == MODULE_TYPE_R9M_LITE_PRO_PXX2; } @@ -146,7 +146,7 @@ inline bool isModulePXX(uint8_t idx) inline bool isModulePXX2(uint8_t idx) { - return isModuleXJT2(idx) || isModuleR9M2(idx); + return isModuleXJT2(idx) || isModuleR9MAccess(idx); } inline bool isModuleRFAccess(uint8_t idx) @@ -154,7 +154,7 @@ inline bool isModuleRFAccess(uint8_t idx) if (isModuleXJT2(idx)) { return g_model.moduleData[idx].subType == MODULE_SUBTYPE_ISRM_PXX2_ACCESS; } - else if (isModuleR9M2(idx)) { + else if (isModuleR9MAccess(idx)) { return true; } else { diff --git a/radio/src/pulses/pxx2.cpp b/radio/src/pulses/pxx2.cpp index ada03129f..3280d1fd0 100644 --- a/radio/src/pulses/pxx2.cpp +++ b/radio/src/pulses/pxx2.cpp @@ -263,7 +263,12 @@ void Pxx2Pulses::setupAccessBindFrame(uint8_t module) for (uint8_t i=0; icandidateReceiversNames[destination->selectedReceiverIndex][i]); } - Pxx2Transport::addByte((destination->lbtMode << 6) + (destination->flexMode << 4) + destination->rxUid); // RX_UID is the slot index (which is unique and never moved) + if (isModuleR9MAccess(module)) { + Pxx2Transport::addByte((destination->lbtMode << 6) + (destination->flexMode << 4) + destination->rxUid); // RX_UID is the slot index (which is unique and never moved) + } + else { + Pxx2Transport::addByte(0x00); + } Pxx2Transport::addByte(g_model.header.modelId[module]); } else { From 32c461042ed3889acb421600530e478cbd36c9a4 Mon Sep 17 00:00:00 2001 From: 3djc Date: Wed, 12 Jun 2019 16:07:25 +0200 Subject: [PATCH 008/350] Standardize AUX_SERIAL --- radio/src/gui/212x64/radio_hardware.cpp | 6 +++--- radio/src/gui/480x272/radio_hardware.cpp | 8 ++++---- radio/src/translations.cpp | 4 ++-- radio/src/translations.h | 4 ++-- radio/src/translations/cz.h.txt | 8 ++++---- radio/src/translations/de.h.txt | 8 ++++---- radio/src/translations/en.h.txt | 8 ++++---- radio/src/translations/es.h.txt | 8 ++++---- radio/src/translations/fi.h.txt | 8 ++++---- radio/src/translations/fr.h.txt | 8 ++++---- radio/src/translations/it.h.txt | 8 ++++---- radio/src/translations/nl.h.txt | 8 ++++---- radio/src/translations/pl.h.txt | 8 ++++---- radio/src/translations/pt.h.txt | 8 ++++---- radio/src/translations/se.h.txt | 8 ++++---- 15 files changed, 55 insertions(+), 55 deletions(-) diff --git a/radio/src/gui/212x64/radio_hardware.cpp b/radio/src/gui/212x64/radio_hardware.cpp index 16868612d..1f2209574 100644 --- a/radio/src/gui/212x64/radio_hardware.cpp +++ b/radio/src/gui/212x64/radio_hardware.cpp @@ -59,7 +59,7 @@ enum menuRadioHwItems { CASE_BLUETOOTH(ITEM_RADIO_HARDWARE_BLUETOOTH_NAME) #endif #if defined(AUX_SERIAL) - ITEM_RADIO_HARDWARE_UART3_MODE, + ITEM_RADIO_HARDWARE_AUX_SERIAL_MODE, #endif ITEM_RADIO_HARDWARE_JITTER_FILTER, ITEM_RADIO_HARDWARE_DEBUG, @@ -234,8 +234,8 @@ void menuRadioHardware(event_t event) #endif #if defined(AUX_SERIAL) - case ITEM_RADIO_HARDWARE_UART3_MODE: - g_eeGeneral.auxSerialMode = editChoice(HW_SETTINGS_COLUMN, y, STR_UART3MODE, STR_UART3MODES, g_eeGeneral.auxSerialMode, 0, UART_MODE_MAX, attr, event); + case ITEM_RADIO_HARDWARE_AUX_SERIAL_MODE: + g_eeGeneral.auxSerialMode = editChoice(HW_SETTINGS_COLUMN, y, STR_AUX_SERIALMODE, STR_AUX_SERIALMODES, g_eeGeneral.auxSerialMode, 0, UART_MODE_MAX, attr, event); if (attr && checkIncDec_Ret) { auxSerialInit(g_eeGeneral.auxSerialMode, modelTelemetryProtocol()); } diff --git a/radio/src/gui/480x272/radio_hardware.cpp b/radio/src/gui/480x272/radio_hardware.cpp index 86c2ad01c..cec17ba80 100644 --- a/radio/src/gui/480x272/radio_hardware.cpp +++ b/radio/src/gui/480x272/radio_hardware.cpp @@ -57,7 +57,7 @@ enum MenuRadioHardwareItems { ITEM_RADIO_HARDWARE_BLUETOOTH_PAIRING_CODE, ITEM_RADIO_HARDWARE_BLUETOOTH_NAME, #if defined(AUX_SERIAL) - ITEM_RADIO_HARDWARE_UART3_MODE, + ITEM_RADIO_HARDWARE_AUX_SERIAL_MODE, #endif ITEM_RADIO_HARDWARE_JITTER_FILTER, ITEM_RADIO_HARDWARE_BAT_CAL, @@ -216,9 +216,9 @@ bool menuRadioHardware(event_t event) break; #if defined(AUX_SERIAL) - case ITEM_RADIO_HARDWARE_UART3_MODE: - lcdDrawText(MENUS_MARGIN_LEFT, y, STR_UART3MODE); - g_eeGeneral.auxSerialMode = editChoice(HW_SETTINGS_COLUMN+50, y, STR_UART3MODES, g_eeGeneral.auxSerialMode, 0, UART_MODE_MAX, attr, event); + case ITEM_RADIO_HARDWARE_AUX_SERIAL_MODE: + lcdDrawText(MENUS_MARGIN_LEFT, y, STR_AUX_SERIALMODE); + g_eeGeneral.auxSerialMode = editChoice(HW_SETTINGS_COLUMN+50, y, STR_AUX_SERIALMODES, g_eeGeneral.auxSerialMode, 0, UART_MODE_MAX, attr, event); if (attr && checkIncDec_Ret) { auxSerialInit(g_eeGeneral.auxSerialMode, modelTelemetryProtocol()); } diff --git a/radio/src/translations.cpp b/radio/src/translations.cpp index 7b4395a4c..3fc24883e 100644 --- a/radio/src/translations.cpp +++ b/radio/src/translations.cpp @@ -94,7 +94,7 @@ ISTR(VRENCODERS); #endif #if defined(PCBTARANIS) || defined(PCBHORUS) -ISTR(UART3MODES); +ISTR(AUX_SERIALMODES); ISTR(SWTYPES); ISTR(POTTYPES); ISTR(SLIDERTYPES); @@ -552,7 +552,7 @@ const char STR_DEVICE_RESET[] = TR_DEVICE_RESET; const char STR_ALTITUDE[] = TR_ALTITUDE; const char STR_SCALE[] = TR_SCALE; const char STR_VIEW_CHANNELS[] = TR_VIEW_CHANNELS; -const char STR_UART3MODE[] = TR_UART3MODE; +const char STR_AUX_SERIALMODE[] = TR_AUX_SERIALMODE; const char STR_THROTTLE_LABEL[] = TR_THROTTLE_LABEL; const char STR_SCRIPT[] = TR_SCRIPT; const char STR_INPUTS[] = TR_INPUTS; diff --git a/radio/src/translations.h b/radio/src/translations.h index 94ed6eb6e..76b9efabd 100644 --- a/radio/src/translations.h +++ b/radio/src/translations.h @@ -96,7 +96,7 @@ extern const char STR_MMMINV[]; extern const char STR_VBEEPMODE[]; extern const char STR_TRNMODE[]; extern const char STR_TRNCHN[]; -extern const char STR_UART3MODES[]; +extern const char STR_AUX_SERIALMODES[]; extern const char STR_SWTYPES[]; extern const char STR_POTTYPES[]; extern const char STR_SLIDERTYPES[]; @@ -812,7 +812,7 @@ extern const char STR_ALTITUDE[]; extern const char STR_SCALE[]; extern const char STR_VIEW_CHANNELS[]; extern const char STR_POTWARNING[]; -extern const char STR_UART3MODE[]; +extern const char STR_AUX_SERIALMODE[]; extern const char STR_THROTTLE_LABEL[]; extern const char STR_SCRIPT[]; extern const char STR_INPUTS[]; diff --git a/radio/src/translations/cz.h.txt b/radio/src/translations/cz.h.txt index 7426e5a7f..b998c2323 100644 --- a/radio/src/translations/cz.h.txt +++ b/radio/src/translations/cz.h.txt @@ -69,11 +69,11 @@ #define LEN_TRNCHN "\003" #define TR_TRNCHN "CH1CH2CH3CH4" -#define LEN_UART3MODES "\015" +#define LEN_AUX_SERIALMODES "\015" #if defined(CLI) || defined(DEBUG) -#define TR_UART3MODES "Debug\0 ""Telem Mirror\0""Telemetry In\0""SBUS Trenér\0 ""LUA\0 " +#define TR_AUX_SERIALMODES "Debug\0 ""Telem Mirror\0""Telemetry In\0""SBUS Trenér\0 ""LUA\0 " #else -#define TR_UART3MODES "VYP\0 ""Telem Mirror\0""Telemetry In\0""SBUS Trenér\0 ""LUA\0 " +#define TR_AUX_SERIALMODES "VYP\0 ""Telem Mirror\0""Telemetry In\0""SBUS Trenér\0 ""LUA\0 " #endif #define LEN_SWTYPES "\013" @@ -1018,7 +1018,7 @@ #define TR_PREFLIGHT "Předletová kontrola" #define TR_CHECKLIST TR(INDENT "Poznámky", INDENT "Zobrazit poznámky") #define TR_FAS_OFFSET TR(INDENT "FAS Ofs", INDENT "FAS Ofset") -#define TR_UART3MODE "Seriový port" +#define TR_AUX_SERIALMODE "Seriový port" #define TR_SCRIPT "Skript" #define TR_INPUTS "Vstupy" #define TR_OUTPUTS "Výstupy" diff --git a/radio/src/translations/de.h.txt b/radio/src/translations/de.h.txt index 78278b7de..0d53c08cd 100644 --- a/radio/src/translations/de.h.txt +++ b/radio/src/translations/de.h.txt @@ -70,11 +70,11 @@ #define LEN_TRNCHN "\003" #define TR_TRNCHN "CH1CH2CH3CH4" -#define LEN_UART3MODES "\015" +#define LEN_AUX_SERIALMODES "\015" #if defined(CLI) || defined(DEBUG) -#define TR_UART3MODES "Debug\0 ""Telem Mirror\0""Telemetry In\0""SBUS Eingang\0""LUA\0 " +#define TR_AUX_SERIALMODES "Debug\0 ""Telem Mirror\0""Telemetry In\0""SBUS Eingang\0""LUA\0 " #else -#define TR_UART3MODES "AUS\0 ""Telem Mirror\0""Telemetry In\0""SBUS Eingang\0""LUA\0 " +#define TR_AUX_SERIALMODES "AUS\0 ""Telem Mirror\0""Telemetry In\0""SBUS Eingang\0""LUA\0 " #endif #define LEN_SWTYPES "\006" @@ -1025,7 +1025,7 @@ #define TR_PREFLIGHT "Vorflug-Checkliste" #define TR_CHECKLIST TR(INDENT "Checkliste", INDENT "Checkliste anzeigen") //9XR-Pro #define TR_FAS_OFFSET TR(INDENT "FAS-Ofs", INDENT "FAS-Offset") -#define TR_UART3MODE "Serieller Port" +#define TR_AUX_SERIALMODE "Serieller Port" #define TR_SCRIPT "Lua-Skript" #define TR_INPUTS "Eingaben" #define TR_OUTPUTS "Ausgaben" diff --git a/radio/src/translations/en.h.txt b/radio/src/translations/en.h.txt index 3cd4c2ccc..ae04e077e 100644 --- a/radio/src/translations/en.h.txt +++ b/radio/src/translations/en.h.txt @@ -70,11 +70,11 @@ #define LEN_TRNCHN "\003" #define TR_TRNCHN "CH1CH2CH3CH4" -#define LEN_UART3MODES "\015" +#define LEN_AUX_SERIALMODES "\015" #if defined(CLI) || defined(DEBUG) -#define TR_UART3MODES "Debug\0 ""Telem Mirror\0""Telemetry In\0""SBUS Trainer\0""LUA\0 " +#define TR_AUX_SERIALMODES "Debug\0 ""Telem Mirror\0""Telemetry In\0""SBUS Trainer\0""LUA\0 " #else -#define TR_UART3MODES "OFF\0 ""Telem Mirror\0""Telemetry In\0""SBUS Trainer\0""LUA\0 " +#define TR_AUX_SERIALMODES "OFF\0 ""Telem Mirror\0""Telemetry In\0""SBUS Trainer\0""LUA\0 " #endif #define LEN_SWTYPES "\006" @@ -1024,7 +1024,7 @@ #define TR_PREFLIGHT "Preflight Checks" #define TR_CHECKLIST TR(INDENT "Checklist", INDENT "Display checklist") #define TR_FAS_OFFSET TR(INDENT "FAS Ofs", INDENT "FAS offset") -#define TR_UART3MODE "Serial port" +#define TR_AUX_SERIALMODE "Serial port" #define TR_SCRIPT "Script" #define TR_INPUTS "Inputs" #define TR_OUTPUTS "Outputs" diff --git a/radio/src/translations/es.h.txt b/radio/src/translations/es.h.txt index fa2817189..6968ad6d4 100644 --- a/radio/src/translations/es.h.txt +++ b/radio/src/translations/es.h.txt @@ -70,11 +70,11 @@ #define LEN_TRNCHN "\003" #define TR_TRNCHN "CH1CH2CH3CH4" -#define LEN_UART3MODES "\015" +#define LEN_AUX_SERIALMODES "\015" #if defined(CLI) || defined(DEBUG) -#define TR_UART3MODES "Debug\0 ""Telem Mirror\0""Telemetry In\0""SBUS Trainer\0""LUA\0 " +#define TR_AUX_SERIALMODES "Debug\0 ""Telem Mirror\0""Telemetry In\0""SBUS Trainer\0""LUA\0 " #else -#define TR_UART3MODES "OFF\0 ""Telem Mirror\0""Telemetry In\0""SBUS Trainer\0""LUA\0 " +#define TR_AUX_SERIALMODES "OFF\0 ""Telem Mirror\0""Telemetry In\0""SBUS Trainer\0""LUA\0 " #endif #define LEN_SWTYPES "\006" @@ -1040,7 +1040,7 @@ #define TR_PREFLIGHT "Preflight Checks" #define TR_CHECKLIST INDENT "Display Checklist" #define TR_FAS_OFFSET TR(INDENT "FAS Ofs", INDENT "FAS Offset") -#define TR_UART3MODE "Serial port" +#define TR_AUX_SERIALMODE "Serial port" #define TR_SCRIPT "Script" #define TR_INPUTS "Inputs" #define TR_OUTPUTS "Outputs" diff --git a/radio/src/translations/fi.h.txt b/radio/src/translations/fi.h.txt index 8d294401b..0e49e4998 100644 --- a/radio/src/translations/fi.h.txt +++ b/radio/src/translations/fi.h.txt @@ -70,11 +70,11 @@ #define LEN_TRNCHN "\003" #define TR_TRNCHN "CH1CH2CH3CH4" -#define LEN_UART3MODES "\015" +#define LEN_AUX_SERIALMODES "\015" #if defined(CLI) || defined(DEBUG) -#define TR_UART3MODES "Debug\0 ""S-Port Pelik\0""Telemetry In\0""SBUS Trainer\0""LUA\0 " +#define TR_AUX_SERIALMODES "Debug\0 ""S-Port Pelik\0""Telemetry In\0""SBUS Trainer\0""LUA\0 " #else -#define TR_UART3MODES "POIS\0 ""S-Port Pelik\0""Telemetry In\0""SBUS Trainer\0""LUA\0 " +#define TR_AUX_SERIALMODES "POIS\0 ""S-Port Pelik\0""Telemetry In\0""SBUS Trainer\0""LUA\0 " #endif #define LEN_SWTYPES "\006" @@ -1033,7 +1033,7 @@ #define TR_PREFLIGHT "Preflight Checks" #define TR_CHECKLIST INDENT "Display Checklist" #define TR_FAS_OFFSET TR(INDENT "FAS Ofs", INDENT "FAS Offset") -#define TR_UART3MODE "Serial port" +#define TR_AUX_SERIALMODE "Serial port" #define TR_SCRIPT "Script" #define TR_INPUTS "Inputs" #define TR_OUTPUTS "Outputs" diff --git a/radio/src/translations/fr.h.txt b/radio/src/translations/fr.h.txt index 05c968aee..7e9a91f47 100644 --- a/radio/src/translations/fr.h.txt +++ b/radio/src/translations/fr.h.txt @@ -70,11 +70,11 @@ #define LEN_TRNCHN "\003" #define TR_TRNCHN "CH1CH2CH3CH4" -#define LEN_UART3MODES "\016" +#define LEN_AUX_SERIALMODES "\016" #if defined(CLI) || defined(DEBUG) -#define TR_UART3MODES "Debug\0 ""Recopie Telem\0""Télémétrie In\0""Ecolage SBUS\0 ""LUA\0 " +#define TR_AUX_SERIALMODES "Debug\0 ""Recopie Telem\0""Télémétrie In\0""Ecolage SBUS\0 ""LUA\0 " #else -#define TR_UART3MODES "OFF\0 ""Recopie Telem\0""Télémétrie In\0""Ecolage SBUS\0 ""LUA\0 " +#define TR_AUX_SERIALMODES "OFF\0 ""Recopie Telem\0""Télémétrie In\0""Ecolage SBUS\0 ""LUA\0 " #endif #define LEN_SWTYPES "\006" @@ -1035,7 +1035,7 @@ #define TR_PREFLIGHT "Vérifications avant vol" #define TR_CHECKLIST TR(INDENT "Notes", INDENT "Afficher notes") #define TR_FAS_OFFSET TR(INDENT "Corr FAS", INDENT "Correction FAS") -#define TR_UART3MODE "Port série" +#define TR_AUX_SERIALMODE "Port série" #define TR_SCRIPT "Script" #define TR_INPUTS "Entrées" #define TR_OUTPUTS "Sorties" diff --git a/radio/src/translations/it.h.txt b/radio/src/translations/it.h.txt index 7ef942227..fd065953e 100644 --- a/radio/src/translations/it.h.txt +++ b/radio/src/translations/it.h.txt @@ -70,11 +70,11 @@ #define LEN_TRNCHN "\003" #define TR_TRNCHN "ch1ch2ch3ch4" -#define LEN_UART3MODES "\016" +#define LEN_AUX_SERIALMODES "\016" #if defined(CLI) || defined(DEBUG) -#define TR_UART3MODES "Debug\0 ""Replica S-Port""Telemetria\0 ""SBUS Trainer\0 ""LUA\0 " +#define TR_AUX_SERIALMODES "Debug\0 ""Replica S-Port""Telemetria\0 ""SBUS Trainer\0 ""LUA\0 " #else -#define TR_UART3MODES "OFF\0 ""Replica S-Port""Telemetria\0 ""SBUS Trainer\0 ""LUA\0 " +#define TR_AUX_SERIALMODES "OFF\0 ""Replica S-Port""Telemetria\0 ""SBUS Trainer\0 ""LUA\0 " #endif #define LEN_SWTYPES "\006" @@ -1034,7 +1034,7 @@ #define TR_PREFLIGHT "Controlli Prevolo" #define TR_CHECKLIST INDENT "Mostra Checklist" #define TR_FAS_OFFSET TR(INDENT "FAS Ofs", INDENT "FAS Offset") -#define TR_UART3MODE "Porta Seriale" +#define TR_AUX_SERIALMODE "Porta Seriale" #define TR_SCRIPT "Script" #define TR_INPUTS "Ingresso" #define TR_OUTPUTS "Uscita" diff --git a/radio/src/translations/nl.h.txt b/radio/src/translations/nl.h.txt index f944e9d34..98120a193 100644 --- a/radio/src/translations/nl.h.txt +++ b/radio/src/translations/nl.h.txt @@ -70,11 +70,11 @@ #define LEN_TRNCHN "\003" #define TR_TRNCHN "CH1CH2CH3CH4" -#define LEN_UART3MODES "\015" +#define LEN_AUX_SERIALMODES "\015" #if defined(CLI) || defined(DEBUG) -#define TR_UART3MODES "Debug\0 ""Telem Mirror\0""Telemetry In\0""SBUS Leerling""LUA\0 " +#define TR_AUX_SERIALMODES "Debug\0 ""Telem Mirror\0""Telemetry In\0""SBUS Leerling""LUA\0 " #else -#define TR_UART3MODES "UIT\0 ""Telem Mirror\0""Telemetry In\0""SBUS Leerling""LUA\0 " +#define TR_AUX_SERIALMODES "UIT\0 ""Telem Mirror\0""Telemetry In\0""SBUS Leerling""LUA\0 " #endif #define LEN_SWTYPES "\006" @@ -1023,7 +1023,7 @@ TR_GYR_VSRCRAW #define TR_PREFLIGHT "Preflight Checks" #define TR_CHECKLIST TR(INDENT "Checklist", INDENT "Toon Checklist") #define TR_FAS_OFFSET TR(INDENT "FAS Ofs", INDENT "FAS Offset") -#define TR_UART3MODE "Seriele poort" +#define TR_AUX_SERIALMODE "Seriele poort" #define TR_SCRIPT "Script" #define TR_INPUTS "Inputs" #define TR_OUTPUTS "Outputs" diff --git a/radio/src/translations/pl.h.txt b/radio/src/translations/pl.h.txt index f6e706992..eb5f76210 100644 --- a/radio/src/translations/pl.h.txt +++ b/radio/src/translations/pl.h.txt @@ -70,11 +70,11 @@ #define LEN_TRNCHN "\003" #define TR_TRNCHN "KN1KN2KN3KN4" -#define LEN_UART3MODES "\015" /*13 decimal*/ +#define LEN_AUX_SERIALMODES "\015" /*13 decimal*/ #if defined(CLI) || defined(DEBUG) -#define TR_UART3MODES "Debug\0 ""S-Port Kopia ""Telemetria\0 ""Trener SBUS\0 ""LUA\0 " +#define TR_AUX_SERIALMODES "Debug\0 ""S-Port Kopia ""Telemetria\0 ""Trener SBUS\0 ""LUA\0 " #else -#define TR_UART3MODES "Wyłącz\0 ""S-Port Kopia ""Telemetria\0 ""Trener SBUS\0 ""LUA\0 " +#define TR_AUX_SERIALMODES "Wyłącz\0 ""S-Port Kopia ""Telemetria\0 ""Trener SBUS\0 ""LUA\0 " #endif #define LEN_SWTYPES "\006" @@ -1034,7 +1034,7 @@ #define TR_PREFLIGHT "Lista Ostrzeżeń" #define TR_CHECKLIST TR(INDENT "Czeklista",INDENT "Pokaż Listę Ostrzeżeń") #define TR_FAS_OFFSET TR(INDENT "FAS Ofs", INDENT "FAS Offset") -#define TR_UART3MODE "Port szreg." +#define TR_AUX_SERIALMODE "Port szreg." #define TR_SCRIPT "Skrypt" #define TR_INPUTS "Wejścia" #define TR_OUTPUTS "Wyjścia" diff --git a/radio/src/translations/pt.h.txt b/radio/src/translations/pt.h.txt index 334105849..3c9dafbee 100644 --- a/radio/src/translations/pt.h.txt +++ b/radio/src/translations/pt.h.txt @@ -70,11 +70,11 @@ #define LEN_TRNCHN "\003" #define TR_TRNCHN "CH1CH2CH3CH4" -#define LEN_UART3MODES "\017" +#define LEN_AUX_SERIALMODES "\017" #if defined(CLI) || defined(DEBUG) -#define TR_UART3MODES "Debug\0 ""S-Port Mirror\0 ""Telemetry\0 ""SBUS Trainer\0 ""LUA\0 " +#define TR_AUX_SERIALMODES "Debug\0 ""S-Port Mirror\0 ""Telemetry\0 ""SBUS Trainer\0 ""LUA\0 " #else -#define TR_UART3MODES "OFF\0 ""S-Port Mirror\0 ""Telemetry\0 ""SBUS Trainer\0 ""LUA\0 " +#define TR_AUX_SERIALMODES "OFF\0 ""S-Port Mirror\0 ""Telemetry\0 ""SBUS Trainer\0 ""LUA\0 " #endif #define LEN_SWTYPES "\006" @@ -1024,7 +1024,7 @@ #define TR_PREFLIGHT "Preflight Checks" #define TR_CHECKLIST INDENT "Display Checklist" #define TR_FAS_OFFSET TR(INDENT "FAS Ofs", INDENT "FAS Offset") -#define TR_UART3MODE "Serial port" +#define TR_AUX_SERIALMODE "Serial port" #define TR_SCRIPT "Script" #define TR_INPUTS "Inputs" #define TR_OUTPUTS "Outputs" diff --git a/radio/src/translations/se.h.txt b/radio/src/translations/se.h.txt index f049c5326..0d0ee51ef 100644 --- a/radio/src/translations/se.h.txt +++ b/radio/src/translations/se.h.txt @@ -70,11 +70,11 @@ #define LEN_TRNCHN "\003" #define TR_TRNCHN "KN1KN2KN3KN4" -#define LEN_UART3MODES "\022" +#define LEN_AUX_SERIALMODES "\022" #if defined(CLI) || defined(DEBUG) -#define TR_UART3MODES "Debug\0 ""Spegling av S-Port""Telemetri\0 ""SBUS Trainer\0 ""LUA\0 " +#define TR_AUX_SERIALMODES "Debug\0 ""Spegling av S-Port""Telemetri\0 ""SBUS Trainer\0 ""LUA\0 " #else -#define TR_UART3MODES "Av\0 ""Spegling av S-Port""Telemetri\0 ""SBUS Trainer\0 ""LUA\0 " +#define TR_AUX_SERIALMODES "Av\0 ""Spegling av S-Port""Telemetri\0 ""SBUS Trainer\0 ""LUA\0 " #endif #define LEN_SWTYPES "\006" @@ -1034,7 +1034,7 @@ #define TR_PREFLIGHT "Startkontroller" #define TR_CHECKLIST TR(INDENT "Checklista", INDENT "Visa Checklista") #define TR_FAS_OFFSET TR(INDENT "FAS Ofs", INDENT "FAS Offset") -#define TR_UART3MODE "Serieporten" +#define TR_AUX_SERIALMODE "Serieporten" #define TR_SCRIPT "Programkod" #define TR_INPUTS "Input" #define TR_OUTPUTS "Outputs" From 344e53e3e289ce341c397fb32fcc6f29c17064f5 Mon Sep 17 00:00:00 2001 From: 3djc Date: Wed, 12 Jun 2019 16:41:25 +0200 Subject: [PATCH 009/350] Cosmetics --- radio/src/gui/212x64/radio_hardware.cpp | 2 +- radio/src/gui/480x272/radio_hardware.cpp | 4 ++-- radio/src/translations.cpp | 4 ++-- radio/src/translations.h | 4 ++-- radio/src/translations/cz.h.txt | 8 ++++---- radio/src/translations/de.h.txt | 8 ++++---- radio/src/translations/en.h.txt | 8 ++++---- radio/src/translations/es.h.txt | 8 ++++---- radio/src/translations/fi.h.txt | 8 ++++---- radio/src/translations/fr.h.txt | 8 ++++---- radio/src/translations/it.h.txt | 8 ++++---- radio/src/translations/nl.h.txt | 8 ++++---- radio/src/translations/pl.h.txt | 8 ++++---- radio/src/translations/pt.h.txt | 8 ++++---- radio/src/translations/se.h.txt | 8 ++++---- 15 files changed, 51 insertions(+), 51 deletions(-) diff --git a/radio/src/gui/212x64/radio_hardware.cpp b/radio/src/gui/212x64/radio_hardware.cpp index 1f2209574..3f59fd1e7 100644 --- a/radio/src/gui/212x64/radio_hardware.cpp +++ b/radio/src/gui/212x64/radio_hardware.cpp @@ -235,7 +235,7 @@ void menuRadioHardware(event_t event) #if defined(AUX_SERIAL) case ITEM_RADIO_HARDWARE_AUX_SERIAL_MODE: - g_eeGeneral.auxSerialMode = editChoice(HW_SETTINGS_COLUMN, y, STR_AUX_SERIALMODE, STR_AUX_SERIALMODES, g_eeGeneral.auxSerialMode, 0, UART_MODE_MAX, attr, event); + g_eeGeneral.auxSerialMode = editChoice(HW_SETTINGS_COLUMN, y, STR_AUX_SERIAL_MODE, STR_AUX_SERIAL_MODES, g_eeGeneral.auxSerialMode, 0, UART_MODE_MAX, attr, event); if (attr && checkIncDec_Ret) { auxSerialInit(g_eeGeneral.auxSerialMode, modelTelemetryProtocol()); } diff --git a/radio/src/gui/480x272/radio_hardware.cpp b/radio/src/gui/480x272/radio_hardware.cpp index cec17ba80..b11b500f2 100644 --- a/radio/src/gui/480x272/radio_hardware.cpp +++ b/radio/src/gui/480x272/radio_hardware.cpp @@ -217,8 +217,8 @@ bool menuRadioHardware(event_t event) #if defined(AUX_SERIAL) case ITEM_RADIO_HARDWARE_AUX_SERIAL_MODE: - lcdDrawText(MENUS_MARGIN_LEFT, y, STR_AUX_SERIALMODE); - g_eeGeneral.auxSerialMode = editChoice(HW_SETTINGS_COLUMN+50, y, STR_AUX_SERIALMODES, g_eeGeneral.auxSerialMode, 0, UART_MODE_MAX, attr, event); + lcdDrawText(MENUS_MARGIN_LEFT, y, STR_AUX_SERIAL_MODE); + g_eeGeneral.auxSerialMode = editChoice(HW_SETTINGS_COLUMN+50, y, STR_AUX_SERIAL_MODES, g_eeGeneral.auxSerialMode, 0, UART_MODE_MAX, attr, event); if (attr && checkIncDec_Ret) { auxSerialInit(g_eeGeneral.auxSerialMode, modelTelemetryProtocol()); } diff --git a/radio/src/translations.cpp b/radio/src/translations.cpp index 3fc24883e..e639e4e9b 100644 --- a/radio/src/translations.cpp +++ b/radio/src/translations.cpp @@ -94,7 +94,7 @@ ISTR(VRENCODERS); #endif #if defined(PCBTARANIS) || defined(PCBHORUS) -ISTR(AUX_SERIALMODES); +ISTR(AUX_SERIAL_MODES); ISTR(SWTYPES); ISTR(POTTYPES); ISTR(SLIDERTYPES); @@ -552,7 +552,7 @@ const char STR_DEVICE_RESET[] = TR_DEVICE_RESET; const char STR_ALTITUDE[] = TR_ALTITUDE; const char STR_SCALE[] = TR_SCALE; const char STR_VIEW_CHANNELS[] = TR_VIEW_CHANNELS; -const char STR_AUX_SERIALMODE[] = TR_AUX_SERIALMODE; +const char STR_AUX_SERIAL_MODE[] = TR_AUX_SERIAL_MODE; const char STR_THROTTLE_LABEL[] = TR_THROTTLE_LABEL; const char STR_SCRIPT[] = TR_SCRIPT; const char STR_INPUTS[] = TR_INPUTS; diff --git a/radio/src/translations.h b/radio/src/translations.h index 76b9efabd..e66a70a03 100644 --- a/radio/src/translations.h +++ b/radio/src/translations.h @@ -96,7 +96,7 @@ extern const char STR_MMMINV[]; extern const char STR_VBEEPMODE[]; extern const char STR_TRNMODE[]; extern const char STR_TRNCHN[]; -extern const char STR_AUX_SERIALMODES[]; +extern const char STR_AUX_SERIAL_MODES[]; extern const char STR_SWTYPES[]; extern const char STR_POTTYPES[]; extern const char STR_SLIDERTYPES[]; @@ -812,7 +812,7 @@ extern const char STR_ALTITUDE[]; extern const char STR_SCALE[]; extern const char STR_VIEW_CHANNELS[]; extern const char STR_POTWARNING[]; -extern const char STR_AUX_SERIALMODE[]; +extern const char STR_AUX_SERIAL_MODE[]; extern const char STR_THROTTLE_LABEL[]; extern const char STR_SCRIPT[]; extern const char STR_INPUTS[]; diff --git a/radio/src/translations/cz.h.txt b/radio/src/translations/cz.h.txt index b998c2323..06287bcc3 100644 --- a/radio/src/translations/cz.h.txt +++ b/radio/src/translations/cz.h.txt @@ -69,11 +69,11 @@ #define LEN_TRNCHN "\003" #define TR_TRNCHN "CH1CH2CH3CH4" -#define LEN_AUX_SERIALMODES "\015" +#define LEN_AUX_SERIAL_MODES "\015" #if defined(CLI) || defined(DEBUG) -#define TR_AUX_SERIALMODES "Debug\0 ""Telem Mirror\0""Telemetry In\0""SBUS Trenér\0 ""LUA\0 " +#define TR_AUX_SERIAL_MODES "Debug\0 ""Telem Mirror\0""Telemetry In\0""SBUS Trenér\0 ""LUA\0 " #else -#define TR_AUX_SERIALMODES "VYP\0 ""Telem Mirror\0""Telemetry In\0""SBUS Trenér\0 ""LUA\0 " +#define TR_AUX_SERIAL_MODES "VYP\0 ""Telem Mirror\0""Telemetry In\0""SBUS Trenér\0 ""LUA\0 " #endif #define LEN_SWTYPES "\013" @@ -1018,7 +1018,7 @@ #define TR_PREFLIGHT "Předletová kontrola" #define TR_CHECKLIST TR(INDENT "Poznámky", INDENT "Zobrazit poznámky") #define TR_FAS_OFFSET TR(INDENT "FAS Ofs", INDENT "FAS Ofset") -#define TR_AUX_SERIALMODE "Seriový port" +#define TR_AUX_SERIAL_MODE "Seriový port" #define TR_SCRIPT "Skript" #define TR_INPUTS "Vstupy" #define TR_OUTPUTS "Výstupy" diff --git a/radio/src/translations/de.h.txt b/radio/src/translations/de.h.txt index 0d53c08cd..0f2338f2e 100644 --- a/radio/src/translations/de.h.txt +++ b/radio/src/translations/de.h.txt @@ -70,11 +70,11 @@ #define LEN_TRNCHN "\003" #define TR_TRNCHN "CH1CH2CH3CH4" -#define LEN_AUX_SERIALMODES "\015" +#define LEN_AUX_SERIAL_MODES "\015" #if defined(CLI) || defined(DEBUG) -#define TR_AUX_SERIALMODES "Debug\0 ""Telem Mirror\0""Telemetry In\0""SBUS Eingang\0""LUA\0 " +#define TR_AUX_SERIAL_MODES "Debug\0 ""Telem Mirror\0""Telemetry In\0""SBUS Eingang\0""LUA\0 " #else -#define TR_AUX_SERIALMODES "AUS\0 ""Telem Mirror\0""Telemetry In\0""SBUS Eingang\0""LUA\0 " +#define TR_AUX_SERIAL_MODES "AUS\0 ""Telem Mirror\0""Telemetry In\0""SBUS Eingang\0""LUA\0 " #endif #define LEN_SWTYPES "\006" @@ -1025,7 +1025,7 @@ #define TR_PREFLIGHT "Vorflug-Checkliste" #define TR_CHECKLIST TR(INDENT "Checkliste", INDENT "Checkliste anzeigen") //9XR-Pro #define TR_FAS_OFFSET TR(INDENT "FAS-Ofs", INDENT "FAS-Offset") -#define TR_AUX_SERIALMODE "Serieller Port" +#define TR_AUX_SERIAL_MODE "Serieller Port" #define TR_SCRIPT "Lua-Skript" #define TR_INPUTS "Eingaben" #define TR_OUTPUTS "Ausgaben" diff --git a/radio/src/translations/en.h.txt b/radio/src/translations/en.h.txt index ae04e077e..e0602bd6c 100644 --- a/radio/src/translations/en.h.txt +++ b/radio/src/translations/en.h.txt @@ -70,11 +70,11 @@ #define LEN_TRNCHN "\003" #define TR_TRNCHN "CH1CH2CH3CH4" -#define LEN_AUX_SERIALMODES "\015" +#define LEN_AUX_SERIAL_MODES "\015" #if defined(CLI) || defined(DEBUG) -#define TR_AUX_SERIALMODES "Debug\0 ""Telem Mirror\0""Telemetry In\0""SBUS Trainer\0""LUA\0 " +#define TR_AUX_SERIAL_MODES "Debug\0 ""Telem Mirror\0""Telemetry In\0""SBUS Trainer\0""LUA\0 " #else -#define TR_AUX_SERIALMODES "OFF\0 ""Telem Mirror\0""Telemetry In\0""SBUS Trainer\0""LUA\0 " +#define TR_AUX_SERIAL_MODES "OFF\0 ""Telem Mirror\0""Telemetry In\0""SBUS Trainer\0""LUA\0 " #endif #define LEN_SWTYPES "\006" @@ -1024,7 +1024,7 @@ #define TR_PREFLIGHT "Preflight Checks" #define TR_CHECKLIST TR(INDENT "Checklist", INDENT "Display checklist") #define TR_FAS_OFFSET TR(INDENT "FAS Ofs", INDENT "FAS offset") -#define TR_AUX_SERIALMODE "Serial port" +#define TR_AUX_SERIAL_MODE "Serial port" #define TR_SCRIPT "Script" #define TR_INPUTS "Inputs" #define TR_OUTPUTS "Outputs" diff --git a/radio/src/translations/es.h.txt b/radio/src/translations/es.h.txt index 6968ad6d4..4bc971393 100644 --- a/radio/src/translations/es.h.txt +++ b/radio/src/translations/es.h.txt @@ -70,11 +70,11 @@ #define LEN_TRNCHN "\003" #define TR_TRNCHN "CH1CH2CH3CH4" -#define LEN_AUX_SERIALMODES "\015" +#define LEN_AUX_SERIAL_MODES "\015" #if defined(CLI) || defined(DEBUG) -#define TR_AUX_SERIALMODES "Debug\0 ""Telem Mirror\0""Telemetry In\0""SBUS Trainer\0""LUA\0 " +#define TR_AUX_SERIAL_MODES "Debug\0 ""Telem Mirror\0""Telemetry In\0""SBUS Trainer\0""LUA\0 " #else -#define TR_AUX_SERIALMODES "OFF\0 ""Telem Mirror\0""Telemetry In\0""SBUS Trainer\0""LUA\0 " +#define TR_AUX_SERIAL_MODES "OFF\0 ""Telem Mirror\0""Telemetry In\0""SBUS Trainer\0""LUA\0 " #endif #define LEN_SWTYPES "\006" @@ -1040,7 +1040,7 @@ #define TR_PREFLIGHT "Preflight Checks" #define TR_CHECKLIST INDENT "Display Checklist" #define TR_FAS_OFFSET TR(INDENT "FAS Ofs", INDENT "FAS Offset") -#define TR_AUX_SERIALMODE "Serial port" +#define TR_AUX_SERIAL_MODE "Serial port" #define TR_SCRIPT "Script" #define TR_INPUTS "Inputs" #define TR_OUTPUTS "Outputs" diff --git a/radio/src/translations/fi.h.txt b/radio/src/translations/fi.h.txt index 0e49e4998..903e1956e 100644 --- a/radio/src/translations/fi.h.txt +++ b/radio/src/translations/fi.h.txt @@ -70,11 +70,11 @@ #define LEN_TRNCHN "\003" #define TR_TRNCHN "CH1CH2CH3CH4" -#define LEN_AUX_SERIALMODES "\015" +#define LEN_AUX_SERIAL_MODES "\015" #if defined(CLI) || defined(DEBUG) -#define TR_AUX_SERIALMODES "Debug\0 ""S-Port Pelik\0""Telemetry In\0""SBUS Trainer\0""LUA\0 " +#define TR_AUX_SERIAL_MODES "Debug\0 ""S-Port Pelik\0""Telemetry In\0""SBUS Trainer\0""LUA\0 " #else -#define TR_AUX_SERIALMODES "POIS\0 ""S-Port Pelik\0""Telemetry In\0""SBUS Trainer\0""LUA\0 " +#define TR_AUX_SERIAL_MODES "POIS\0 ""S-Port Pelik\0""Telemetry In\0""SBUS Trainer\0""LUA\0 " #endif #define LEN_SWTYPES "\006" @@ -1033,7 +1033,7 @@ #define TR_PREFLIGHT "Preflight Checks" #define TR_CHECKLIST INDENT "Display Checklist" #define TR_FAS_OFFSET TR(INDENT "FAS Ofs", INDENT "FAS Offset") -#define TR_AUX_SERIALMODE "Serial port" +#define TR_AUX_SERIAL_MODE "Serial port" #define TR_SCRIPT "Script" #define TR_INPUTS "Inputs" #define TR_OUTPUTS "Outputs" diff --git a/radio/src/translations/fr.h.txt b/radio/src/translations/fr.h.txt index 7e9a91f47..cac789c72 100644 --- a/radio/src/translations/fr.h.txt +++ b/radio/src/translations/fr.h.txt @@ -70,11 +70,11 @@ #define LEN_TRNCHN "\003" #define TR_TRNCHN "CH1CH2CH3CH4" -#define LEN_AUX_SERIALMODES "\016" +#define LEN_AUX_SERIAL_MODES "\016" #if defined(CLI) || defined(DEBUG) -#define TR_AUX_SERIALMODES "Debug\0 ""Recopie Telem\0""Télémétrie In\0""Ecolage SBUS\0 ""LUA\0 " +#define TR_AUX_SERIAL_MODES "Debug\0 ""Recopie Telem\0""Télémétrie In\0""Ecolage SBUS\0 ""LUA\0 " #else -#define TR_AUX_SERIALMODES "OFF\0 ""Recopie Telem\0""Télémétrie In\0""Ecolage SBUS\0 ""LUA\0 " +#define TR_AUX_SERIAL_MODES "OFF\0 ""Recopie Telem\0""Télémétrie In\0""Ecolage SBUS\0 ""LUA\0 " #endif #define LEN_SWTYPES "\006" @@ -1035,7 +1035,7 @@ #define TR_PREFLIGHT "Vérifications avant vol" #define TR_CHECKLIST TR(INDENT "Notes", INDENT "Afficher notes") #define TR_FAS_OFFSET TR(INDENT "Corr FAS", INDENT "Correction FAS") -#define TR_AUX_SERIALMODE "Port série" +#define TR_AUX_SERIAL_MODE "Port série" #define TR_SCRIPT "Script" #define TR_INPUTS "Entrées" #define TR_OUTPUTS "Sorties" diff --git a/radio/src/translations/it.h.txt b/radio/src/translations/it.h.txt index fd065953e..2db0d6d15 100644 --- a/radio/src/translations/it.h.txt +++ b/radio/src/translations/it.h.txt @@ -70,11 +70,11 @@ #define LEN_TRNCHN "\003" #define TR_TRNCHN "ch1ch2ch3ch4" -#define LEN_AUX_SERIALMODES "\016" +#define LEN_AUX_SERIAL_MODES "\016" #if defined(CLI) || defined(DEBUG) -#define TR_AUX_SERIALMODES "Debug\0 ""Replica S-Port""Telemetria\0 ""SBUS Trainer\0 ""LUA\0 " +#define TR_AUX_SERIAL_MODES "Debug\0 ""Replica S-Port""Telemetria\0 ""SBUS Trainer\0 ""LUA\0 " #else -#define TR_AUX_SERIALMODES "OFF\0 ""Replica S-Port""Telemetria\0 ""SBUS Trainer\0 ""LUA\0 " +#define TR_AUX_SERIAL_MODES "OFF\0 ""Replica S-Port""Telemetria\0 ""SBUS Trainer\0 ""LUA\0 " #endif #define LEN_SWTYPES "\006" @@ -1034,7 +1034,7 @@ #define TR_PREFLIGHT "Controlli Prevolo" #define TR_CHECKLIST INDENT "Mostra Checklist" #define TR_FAS_OFFSET TR(INDENT "FAS Ofs", INDENT "FAS Offset") -#define TR_AUX_SERIALMODE "Porta Seriale" +#define TR_AUX_SERIAL_MODE "Porta Seriale" #define TR_SCRIPT "Script" #define TR_INPUTS "Ingresso" #define TR_OUTPUTS "Uscita" diff --git a/radio/src/translations/nl.h.txt b/radio/src/translations/nl.h.txt index 98120a193..67c9f529c 100644 --- a/radio/src/translations/nl.h.txt +++ b/radio/src/translations/nl.h.txt @@ -70,11 +70,11 @@ #define LEN_TRNCHN "\003" #define TR_TRNCHN "CH1CH2CH3CH4" -#define LEN_AUX_SERIALMODES "\015" +#define LEN_AUX_SERIAL_MODES "\015" #if defined(CLI) || defined(DEBUG) -#define TR_AUX_SERIALMODES "Debug\0 ""Telem Mirror\0""Telemetry In\0""SBUS Leerling""LUA\0 " +#define TR_AUX_SERIAL_MODES "Debug\0 ""Telem Mirror\0""Telemetry In\0""SBUS Leerling""LUA\0 " #else -#define TR_AUX_SERIALMODES "UIT\0 ""Telem Mirror\0""Telemetry In\0""SBUS Leerling""LUA\0 " +#define TR_AUX_SERIAL_MODES "UIT\0 ""Telem Mirror\0""Telemetry In\0""SBUS Leerling""LUA\0 " #endif #define LEN_SWTYPES "\006" @@ -1023,7 +1023,7 @@ TR_GYR_VSRCRAW #define TR_PREFLIGHT "Preflight Checks" #define TR_CHECKLIST TR(INDENT "Checklist", INDENT "Toon Checklist") #define TR_FAS_OFFSET TR(INDENT "FAS Ofs", INDENT "FAS Offset") -#define TR_AUX_SERIALMODE "Seriele poort" +#define TR_AUX_SERIAL_MODE "Seriele poort" #define TR_SCRIPT "Script" #define TR_INPUTS "Inputs" #define TR_OUTPUTS "Outputs" diff --git a/radio/src/translations/pl.h.txt b/radio/src/translations/pl.h.txt index eb5f76210..2753c4ed3 100644 --- a/radio/src/translations/pl.h.txt +++ b/radio/src/translations/pl.h.txt @@ -70,11 +70,11 @@ #define LEN_TRNCHN "\003" #define TR_TRNCHN "KN1KN2KN3KN4" -#define LEN_AUX_SERIALMODES "\015" /*13 decimal*/ +#define LEN_AUX_SERIAL_MODES "\015" /*13 decimal*/ #if defined(CLI) || defined(DEBUG) -#define TR_AUX_SERIALMODES "Debug\0 ""S-Port Kopia ""Telemetria\0 ""Trener SBUS\0 ""LUA\0 " +#define TR_AUX_SERIAL_MODES "Debug\0 ""S-Port Kopia ""Telemetria\0 ""Trener SBUS\0 ""LUA\0 " #else -#define TR_AUX_SERIALMODES "Wyłącz\0 ""S-Port Kopia ""Telemetria\0 ""Trener SBUS\0 ""LUA\0 " +#define TR_AUX_SERIAL_MODES "Wyłącz\0 ""S-Port Kopia ""Telemetria\0 ""Trener SBUS\0 ""LUA\0 " #endif #define LEN_SWTYPES "\006" @@ -1034,7 +1034,7 @@ #define TR_PREFLIGHT "Lista Ostrzeżeń" #define TR_CHECKLIST TR(INDENT "Czeklista",INDENT "Pokaż Listę Ostrzeżeń") #define TR_FAS_OFFSET TR(INDENT "FAS Ofs", INDENT "FAS Offset") -#define TR_AUX_SERIALMODE "Port szreg." +#define TR_AUX_SERIAL_MODE "Port szreg." #define TR_SCRIPT "Skrypt" #define TR_INPUTS "Wejścia" #define TR_OUTPUTS "Wyjścia" diff --git a/radio/src/translations/pt.h.txt b/radio/src/translations/pt.h.txt index 3c9dafbee..f175ea14b 100644 --- a/radio/src/translations/pt.h.txt +++ b/radio/src/translations/pt.h.txt @@ -70,11 +70,11 @@ #define LEN_TRNCHN "\003" #define TR_TRNCHN "CH1CH2CH3CH4" -#define LEN_AUX_SERIALMODES "\017" +#define LEN_AUX_SERIAL_MODES "\017" #if defined(CLI) || defined(DEBUG) -#define TR_AUX_SERIALMODES "Debug\0 ""S-Port Mirror\0 ""Telemetry\0 ""SBUS Trainer\0 ""LUA\0 " +#define TR_AUX_SERIAL_MODES "Debug\0 ""S-Port Mirror\0 ""Telemetry\0 ""SBUS Trainer\0 ""LUA\0 " #else -#define TR_AUX_SERIALMODES "OFF\0 ""S-Port Mirror\0 ""Telemetry\0 ""SBUS Trainer\0 ""LUA\0 " +#define TR_AUX_SERIAL_MODES "OFF\0 ""S-Port Mirror\0 ""Telemetry\0 ""SBUS Trainer\0 ""LUA\0 " #endif #define LEN_SWTYPES "\006" @@ -1024,7 +1024,7 @@ #define TR_PREFLIGHT "Preflight Checks" #define TR_CHECKLIST INDENT "Display Checklist" #define TR_FAS_OFFSET TR(INDENT "FAS Ofs", INDENT "FAS Offset") -#define TR_AUX_SERIALMODE "Serial port" +#define TR_AUX_SERIAL_MODE "Serial port" #define TR_SCRIPT "Script" #define TR_INPUTS "Inputs" #define TR_OUTPUTS "Outputs" diff --git a/radio/src/translations/se.h.txt b/radio/src/translations/se.h.txt index 0d0ee51ef..6f0a51c61 100644 --- a/radio/src/translations/se.h.txt +++ b/radio/src/translations/se.h.txt @@ -70,11 +70,11 @@ #define LEN_TRNCHN "\003" #define TR_TRNCHN "KN1KN2KN3KN4" -#define LEN_AUX_SERIALMODES "\022" +#define LEN_AUX_SERIAL_MODES "\022" #if defined(CLI) || defined(DEBUG) -#define TR_AUX_SERIALMODES "Debug\0 ""Spegling av S-Port""Telemetri\0 ""SBUS Trainer\0 ""LUA\0 " +#define TR_AUX_SERIAL_MODES "Debug\0 ""Spegling av S-Port""Telemetri\0 ""SBUS Trainer\0 ""LUA\0 " #else -#define TR_AUX_SERIALMODES "Av\0 ""Spegling av S-Port""Telemetri\0 ""SBUS Trainer\0 ""LUA\0 " +#define TR_AUX_SERIAL_MODES "Av\0 ""Spegling av S-Port""Telemetri\0 ""SBUS Trainer\0 ""LUA\0 " #endif #define LEN_SWTYPES "\006" @@ -1034,7 +1034,7 @@ #define TR_PREFLIGHT "Startkontroller" #define TR_CHECKLIST TR(INDENT "Checklista", INDENT "Visa Checklista") #define TR_FAS_OFFSET TR(INDENT "FAS Ofs", INDENT "FAS Offset") -#define TR_AUX_SERIALMODE "Serieporten" +#define TR_AUX_SERIAL_MODE "Serieporten" #define TR_SCRIPT "Programkod" #define TR_INPUTS "Input" #define TR_OUTPUTS "Outputs" From 18c6f6878db1790006a58a9b7ab3421ddb225a02 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Thu, 13 Jun 2019 17:06:25 +0200 Subject: [PATCH 010/350] Bsongis/receivers ota update (#6494) OTA update fixes --- radio/src/gui/128x64/model_setup.cpp | 12 ++--- radio/src/gui/212x64/model_setup.cpp | 12 ++--- .../src/gui/common/stdlcd/radio_sdmanager.cpp | 31 ++++++++---- radio/src/io/frsky_firmware_update.cpp | 2 +- radio/src/opentx.h | 15 ++---- radio/src/pulses/modules_helpers.h | 48 ++++++++++++++++++- radio/src/pulses/pxx2.h | 2 + radio/src/translations.cpp | 11 +++-- radio/src/translations.h | 11 +++-- radio/src/translations/cz.h.txt | 11 +++-- radio/src/translations/de.h.txt | 11 +++-- radio/src/translations/en.h.txt | 11 +++-- radio/src/translations/es.h.txt | 11 +++-- radio/src/translations/fi.h.txt | 11 +++-- radio/src/translations/fr.h.txt | 11 +++-- radio/src/translations/it.h.txt | 11 +++-- radio/src/translations/nl.h.txt | 11 +++-- radio/src/translations/pl.h.txt | 11 +++-- radio/src/translations/pt.h.txt | 11 +++-- radio/src/translations/se.h.txt | 11 +++-- 20 files changed, 179 insertions(+), 86 deletions(-) diff --git a/radio/src/gui/128x64/model_setup.cpp b/radio/src/gui/128x64/model_setup.cpp index e70fc4773..b163789b7 100644 --- a/radio/src/gui/128x64/model_setup.cpp +++ b/radio/src/gui/128x64/model_setup.cpp @@ -908,16 +908,16 @@ void menuModelSetup(event_t event) else if (old_editMode > 0) { if (isModuleR9M(EXTERNAL_MODULE)) { if (g_model.moduleData[EXTERNAL_MODULE].subType > MODULE_SUBTYPE_R9M_EU) { - POPUP_WARNING(STR_R9M_PROTO_FLEX_WARN1); - SET_WARNING_INFO(STR_R9M_PROTO_WARN2, sizeof(TR_R9M_PROTO_WARN2), 0); + POPUP_WARNING(STR_R9M_PROTO_FLEX_WARN_LINE1); + SET_WARNING_INFO(STR_R9M_PROTO_WARN_LINE2, sizeof(TR_R9M_PROTO_WARN_LINE2) - 1, 0); } else if (g_model.moduleData[EXTERNAL_MODULE].subType == MODULE_SUBTYPE_R9M_EU) { - POPUP_WARNING(STR_R9M_PROTO_EU_WARN1); - SET_WARNING_INFO(STR_R9M_PROTO_WARN2, sizeof(TR_R9M_PROTO_WARN2), 0); + POPUP_WARNING(STR_R9M_PROTO_EU_WARN_LINE1); + SET_WARNING_INFO(STR_R9M_PROTO_WARN_LINE2, sizeof(TR_R9M_PROTO_WARN_LINE2) - 1, 0); } else { - POPUP_WARNING(STR_R9M_PROTO_FCC_WARN1); - SET_WARNING_INFO(STR_R9M_PROTO_WARN2, sizeof(TR_R9M_PROTO_WARN2), 0); + POPUP_WARNING(STR_R9M_PROTO_FCC_WARN_LINE1); + SET_WARNING_INFO(STR_R9M_PROTO_WARN_LINE2, sizeof(TR_R9M_PROTO_WARN_LINE2) - 1, 0); } } } diff --git a/radio/src/gui/212x64/model_setup.cpp b/radio/src/gui/212x64/model_setup.cpp index 2650579a7..c04d064f7 100644 --- a/radio/src/gui/212x64/model_setup.cpp +++ b/radio/src/gui/212x64/model_setup.cpp @@ -898,16 +898,16 @@ void menuModelSetup(event_t event) else if (old_editMode > 0) { if (isModuleR9M(EXTERNAL_MODULE)) { if (g_model.moduleData[EXTERNAL_MODULE].subType > MODULE_SUBTYPE_R9M_EU) { - POPUP_WARNING(STR_R9M_PROTO_FLEX_WARN1); - SET_WARNING_INFO(STR_R9M_PROTO_WARN2, sizeof(TR_R9M_PROTO_WARN2), 0); + POPUP_WARNING(STR_R9M_PROTO_FLEX_WARN_LINE1); + SET_WARNING_INFO(STR_R9M_PROTO_WARN_LINE2, sizeof(TR_R9M_PROTO_WARN_LINE2) - 1, 0); } else if (g_model.moduleData[EXTERNAL_MODULE].subType == MODULE_SUBTYPE_R9M_EU) { - POPUP_WARNING(STR_R9M_PROTO_EU_WARN1); - SET_WARNING_INFO(STR_R9M_PROTO_WARN2, sizeof(TR_R9M_PROTO_WARN2), 0); + POPUP_WARNING(STR_R9M_PROTO_EU_WARN_LINE1); + SET_WARNING_INFO(STR_R9M_PROTO_WARN_LINE2, sizeof(TR_R9M_PROTO_WARN_LINE2) - 1, 0); } else { - POPUP_WARNING(STR_R9M_PROTO_FCC_WARN1); - SET_WARNING_INFO(STR_R9M_PROTO_WARN2, sizeof(TR_R9M_PROTO_WARN2), 0); + POPUP_WARNING(STR_R9M_PROTO_FCC_WARN_LINE1); + SET_WARNING_INFO(STR_R9M_PROTO_WARN_LINE2, sizeof(TR_R9M_PROTO_WARN_LINE2) - 1, 0); } } } diff --git a/radio/src/gui/common/stdlcd/radio_sdmanager.cpp b/radio/src/gui/common/stdlcd/radio_sdmanager.cpp index be9522fcc..4ec9bb196 100644 --- a/radio/src/gui/common/stdlcd/radio_sdmanager.cpp +++ b/radio/src/gui/common/stdlcd/radio_sdmanager.cpp @@ -101,14 +101,29 @@ void onUpdateConfirmation(const char * result) void onUpdateStateChanged() { if (reusableBuffer.sdManager.otaUpdateInformation.step == BIND_INFO_REQUEST) { - POPUP_CONFIRMATION(PXX2receiversModels[reusableBuffer.sdManager.otaUpdateInformation.receiverInformation.modelID], onUpdateConfirmation); - char * tmp = strAppend(reusableBuffer.sdManager.otaReceiverVersion, TR_CURRENT_VERSION); - tmp = strAppendUnsigned(tmp, 1 + reusableBuffer.sdManager.otaUpdateInformation.receiverInformation.swVersion.major); - *tmp++ = '.'; - tmp = strAppendUnsigned(tmp, reusableBuffer.sdManager.otaUpdateInformation.receiverInformation.swVersion.minor); - *tmp++ = '.'; - tmp = strAppendUnsigned(tmp, reusableBuffer.sdManager.otaUpdateInformation.receiverInformation.swVersion.revision); - SET_WARNING_INFO(reusableBuffer.sdManager.otaReceiverVersion, tmp - reusableBuffer.sdManager.otaReceiverVersion, 0); + uint8_t modelId = reusableBuffer.sdManager.otaUpdateInformation.receiverInformation.modelID; + if (modelId > 0 && modelId < DIM(PXX2receiversModels)) { + if (isReceiverOptionAvailable(modelId, RECEIVER_OPTION_OTA)) { + POPUP_CONFIRMATION(PXX2receiversModels[modelId], onUpdateConfirmation); + char *tmp = strAppend(reusableBuffer.sdManager.otaReceiverVersion, TR_CURRENT_VERSION); + tmp = strAppendUnsigned(tmp, 1 + reusableBuffer.sdManager.otaUpdateInformation.receiverInformation.swVersion.major); + *tmp++ = '.'; + tmp = strAppendUnsigned(tmp, reusableBuffer.sdManager.otaUpdateInformation.receiverInformation.swVersion.minor); + *tmp++ = '.'; + tmp = strAppendUnsigned(tmp, reusableBuffer.sdManager.otaUpdateInformation.receiverInformation.swVersion.revision); + SET_WARNING_INFO(reusableBuffer.sdManager.otaReceiverVersion, tmp - reusableBuffer.sdManager.otaReceiverVersion, 0); + } + else { + POPUP_WARNING(STR_OTA_UPDATE_ERROR); + SET_WARNING_INFO(STR_UNSUPPORTED_RX, sizeof(TR_UNSUPPORTED_RX) - 1, 0); + moduleState[EXTERNAL_MODULE].mode = MODULE_MODE_NORMAL; + } + } + else { + POPUP_WARNING(STR_OTA_UPDATE_ERROR); + SET_WARNING_INFO(STR_UNKNOWN_RX, sizeof(TR_UNKNOWN_RX) - 1, 0); + moduleState[EXTERNAL_MODULE].mode = MODULE_MODE_NORMAL; + } } } #endif diff --git a/radio/src/io/frsky_firmware_update.cpp b/radio/src/io/frsky_firmware_update.cpp index 7fcedbd86..6f1d49749 100644 --- a/radio/src/io/frsky_firmware_update.cpp +++ b/radio/src/io/frsky_firmware_update.cpp @@ -635,7 +635,7 @@ void FrskyChipFirmwareUpdate::flashFirmware(const char * filename) const char * result = doFlashFirmware(filename); - AUDIO_PLAY(AU_SPECIAL_SOUND_BEEP1 ); + AUDIO_PLAY(AU_SPECIAL_SOUND_BEEP1); BACKLIGHT_ENABLE(); if (result) { diff --git a/radio/src/opentx.h b/radio/src/opentx.h index 5ec52dca5..5bf6981de 100644 --- a/radio/src/opentx.h +++ b/radio/src/opentx.h @@ -1103,9 +1103,7 @@ void opentxResume(); union ReusableBuffer { - // ARM 334 bytes - struct - { + struct { #if defined(EEPROM_RLC) && LCD_W < 212 uint16_t eepromfree; #endif @@ -1146,7 +1144,6 @@ union ReusableBuffer #endif } moduleSetup; - // 103 bytes struct { int16_t midVals[NUM_STICKS+NUM_POTS+NUM_SLIDERS+NUM_MOUSE_ANALOGS]; int16_t loVals[NUM_STICKS+NUM_POTS+NUM_SLIDERS+NUM_MOUSE_ANALOGS]; @@ -1163,7 +1160,6 @@ union ReusableBuffer } calib; #if defined(SDCARD) - // 274 bytes struct { char lines[NUM_BODY_LINES][SD_SCREEN_FILE_LENGTH+1+1]; // the last char is used to store the flags (directory) of the line uint32_t available; @@ -1197,8 +1193,7 @@ union ReusableBuffer uint8_t stickMode; } generalSettings; - struct - { + struct { uint8_t bars[LCD_W]; uint32_t freq; uint32_t span; @@ -1211,8 +1206,7 @@ union ReusableBuffer uint8_t dirty; } spectrumAnalyser; - struct - { + struct { uint32_t freq; int16_t power; int16_t peak; @@ -1220,8 +1214,7 @@ union ReusableBuffer uint8_t dirty; } powerMeter; - struct - { + struct { int8_t preset; } curveEdit; diff --git a/radio/src/pulses/modules_helpers.h b/radio/src/pulses/modules_helpers.h index 1d2325078..6b9affe8c 100644 --- a/radio/src/pulses/modules_helpers.h +++ b/radio/src/pulses/modules_helpers.h @@ -23,8 +23,6 @@ #include "bitfield.h" - - #define CROSSFIRE_CHANNELS_COUNT 16 #if defined(MULTIMODULE) @@ -261,6 +259,52 @@ inline bool isModuleOptionAvailable(uint8_t modelId, uint8_t option) return moduleOptions[modelId] & (1 << option); } +enum { + RECEIVER_OPTION_OTA, +}; + +/* Options order: + * - OTA (0x01) + */ +static const uint8_t receiverOptions[] = { +#if defined(SIMU) + 0b11111111, // None = display all options on SIMU +#else + 0b00000000, // None = display all options on SIMU +#endif + 0b11111110, // X8R + 0b11111110, // RX8R + 0b11111110, // RX8R-PRO + 0b11111110, // RX6R + 0b11111110, // RX4R + 0b11111110, // G-RX8 + 0b11111110, // G-RX6 + 0b11111110, // X6R + 0b11111110, // X4R + 0b11111110, // X4R-SB + 0b11111110, // XSR + 0b11111110, // XSR-M + 0b11111110, // RXSR + 0b11111110, // S6R + 0b11111110, // S8R + 0b11111110, // XM + 0b11111110, // XM+ + 0b11111110, // XMR + 0b11111110, // R9 + 0b11111110, // R9-SLIM + 0b11111110, // R9-SLIM+ + 0b11111110, // R9-MINI + 0b11111110, // R9-MM + 0b11111110, // R9-STAB + 0b11111111, // R9-MINI+OTA + 0b11111111, // R9-MM+OTA +}; + +inline bool isReceiverOptionAvailable(uint8_t modelId, uint8_t option) +{ + return receiverOptions[modelId] & (1 << option); +} + inline bool isDefaultModelRegistrationID() { return memcmp(g_model.modelRegistrationID, g_eeGeneral.ownerRegistrationID, PXX2_LEN_REGISTRATION_ID) == 0; diff --git a/radio/src/pulses/pxx2.h b/radio/src/pulses/pxx2.h index 98186d5d3..41d53cce0 100644 --- a/radio/src/pulses/pxx2.h +++ b/radio/src/pulses/pxx2.h @@ -95,6 +95,8 @@ static const char * const PXX2receiversModels[] = { "R9-MINI", "R9-MM", "R9-STAB", + "R9-MINI-OTA", // this one has OTA (different bootloader) + "R9-MM-OTA", // this one has OTA (different bootloader) }; enum PXX2ModuleModelID { diff --git a/radio/src/translations.cpp b/radio/src/translations.cpp index e639e4e9b..caf79251e 100644 --- a/radio/src/translations.cpp +++ b/radio/src/translations.cpp @@ -465,10 +465,10 @@ const char STR_CHANNELRANGE[] = TR_CHANNELRANGE; const char STR_ANTENNASELECTION[] = TR_ANTENNASELECTION; const char STR_ANTENNACONFIRM1[] = TR_ANTENNACONFIRM1; const char STR_ANTENNACONFIRM2[] = TR_ANTENNACONFIRM2; -const char STR_R9M_PROTO_FLEX_WARN1[] = TR_R9M_PROTO_FLEX_WARN1; -const char STR_R9M_PROTO_FCC_WARN1[] = TR_R9M_PROTO_FCC_WARN1; -const char STR_R9M_PROTO_EU_WARN1[] = TR_R9M_PROTO_EU_WARN1; -const char STR_R9M_PROTO_WARN2[] = TR_R9M_PROTO_WARN2; +const char STR_R9M_PROTO_FLEX_WARN_LINE1[] = TR_R9M_PROTO_FLEX_WARN_LINE1; +const char STR_R9M_PROTO_FCC_WARN_LINE1[] = TR_R9M_PROTO_FCC_WARN_LINE1; +const char STR_R9M_PROTO_EU_WARN_LINE1[] = TR_R9M_PROTO_EU_WARN_LINE1; +const char STR_R9M_PROTO_WARN_LINE2[] = TR_R9M_PROTO_WARN_LINE2; const char STR_SET[] = TR_SET; const char STR_PREFLIGHT[] = TR_PREFLIGHT; const char STR_CHECKLIST[] = TR_CHECKLIST; @@ -548,6 +548,9 @@ const char STR_FLASH_ERASE[] = TR_FLASH_ERASE; const char STR_FLASH_WRITE[] = TR_FLASH_WRITE; const char STR_OTA_UPDATE[] = TR_OTA_UPDATE; const char STR_MODULE_RESET[] = TR_MODULE_RESET; +const char STR_UNKNOWN_RX[] = TR_UNKNOWN_RX; +const char STR_UNSUPPORTED_RX[] = TR_UNSUPPORTED_RX; +const char STR_OTA_UPDATE_ERROR[] = TR_OTA_UPDATE_ERROR; const char STR_DEVICE_RESET[] = TR_DEVICE_RESET; const char STR_ALTITUDE[] = TR_ALTITUDE; const char STR_SCALE[] = TR_SCALE; diff --git a/radio/src/translations.h b/radio/src/translations.h index e66a70a03..2d07b31e0 100644 --- a/radio/src/translations.h +++ b/radio/src/translations.h @@ -723,10 +723,10 @@ extern const char STR_CHANNELRANGE[]; extern const char STR_ANTENNASELECTION[]; extern const char STR_ANTENNACONFIRM1[]; extern const char STR_ANTENNACONFIRM2[]; -extern const char STR_R9M_PROTO_FLEX_WARN1[]; -extern const char STR_R9M_PROTO_FCC_WARN1[]; -extern const char STR_R9M_PROTO_EU_WARN1[]; -extern const char STR_R9M_PROTO_WARN2[]; +extern const char STR_R9M_PROTO_FLEX_WARN_LINE1[]; +extern const char STR_R9M_PROTO_FCC_WARN_LINE1[]; +extern const char STR_R9M_PROTO_EU_WARN_LINE1[]; +extern const char STR_R9M_PROTO_WARN_LINE2[]; extern const char STR_SET[]; extern const char STR_PREFLIGHT[]; extern const char STR_CHECKLIST[]; @@ -807,6 +807,9 @@ extern const char STR_FLASH_ERASE[]; extern const char STR_FLASH_WRITE[]; extern const char STR_OTA_UPDATE[]; extern const char STR_MODULE_RESET[]; +extern const char STR_UNKNOWN_RX[]; +extern const char STR_UNSUPPORTED_RX[]; +extern const char STR_OTA_UPDATE_ERROR[]; extern const char STR_DEVICE_RESET[]; extern const char STR_ALTITUDE[]; extern const char STR_SCALE[]; diff --git a/radio/src/translations/cz.h.txt b/radio/src/translations/cz.h.txt index 06287bcc3..a7834f583 100644 --- a/radio/src/translations/cz.h.txt +++ b/radio/src/translations/cz.h.txt @@ -984,10 +984,10 @@ #define TR_ANTENNASELECTION TR(INDENT "Antenna", INDENT "Volba antény") #define TR_ANTENNACONFIRM1 "Opravdu přepnout?" #define TR_ANTENNACONFIRM2 TR("Zkont. anténu", "Ujisti se že je anténa připojena!") -#define TR_R9M_PROTO_FLEX_WARN1 "Potřebuje" -#define TR_R9M_PROTO_FCC_WARN1 "Potřebuje FCC" -#define TR_R9M_PROTO_EU_WARN1 "Potřebuje EU" -#define TR_R9M_PROTO_WARN2 "necertifikovaný R9M firm." +#define TR_R9M_PROTO_FLEX_WARN_LINE1 "Potřebuje" +#define TR_R9M_PROTO_FCC_WARN_LINE1 "Potřebuje FCC" +#define TR_R9M_PROTO_EU_WARN_LINE1 "Potřebuje EU" +#define TR_R9M_PROTO_WARN_LINE2 "necertifikovaný R9M firm." #define TR_LOWALARM INDENT "Nízký Alarm" #define TR_CRITICALALARM INDENT "Kritický Alarm" #define TR_RSSIALARM_WARN TR("RSSI","RSSI TELEMETRIE") @@ -1141,6 +1141,9 @@ #define TR_FLASH_WRITE "Zápis flash..." #define TR_OTA_UPDATE "Aktualizace OTA..." #define TR_MODULE_RESET "Reset modulu..." +#define TR_UNKNOWN_RX "Unknown RX" +#define TR_UNSUPPORTED_RX "Unsupported RX" +#define TR_OTA_UPDATE_ERROR "OTA update error" #define TR_DEVICE_RESET "Reset zařízení..." #define TR_ALTITUDE INDENT "Výška" #define TR_SCALE "Měřítko" diff --git a/radio/src/translations/de.h.txt b/radio/src/translations/de.h.txt index 0f2338f2e..170e41596 100644 --- a/radio/src/translations/de.h.txt +++ b/radio/src/translations/de.h.txt @@ -991,10 +991,10 @@ #define TR_ANTENNASELECTION TR(INDENT "Antenna", INDENT "Antenne auswählen") #define TR_ANTENNACONFIRM1 "Ant. umschalten" #define TR_ANTENNACONFIRM2 TR("Check antenna", "Ist eine externe Antenne installiert?") -#define TR_R9M_PROTO_FLEX_WARN1 "Requires non" -#define TR_R9M_PROTO_FCC_WARN1 "Requires FCC" -#define TR_R9M_PROTO_EU_WARN1 "Requires EU" -#define TR_R9M_PROTO_WARN2 "certified firmware" +#define TR_R9M_PROTO_FLEX_WARN_LINE1 "Requires non" +#define TR_R9M_PROTO_FCC_WARN_LINE1 "Requires FCC" +#define TR_R9M_PROTO_EU_WARN_LINE1 "Requires EU" +#define TR_R9M_PROTO_WARN_LINE2 "certified firmware" #define TR_LOWALARM INDENT "Warnungsschwelle" #define TR_CRITICALALARM INDENT "Kritischer Alarm" #define TR_RSSIALARM_WARN "Telemetry" @@ -1144,6 +1144,9 @@ #define TR_FLASH_WRITE "Flash write..." #define TR_OTA_UPDATE "OTA update..." #define TR_MODULE_RESET "Module reset..." +#define TR_UNKNOWN_RX "Unknown RX" +#define TR_UNSUPPORTED_RX "Unsupported RX" +#define TR_OTA_UPDATE_ERROR "OTA update error" #define TR_DEVICE_RESET "Device reset..." #define TR_ALTITUDE INDENT "Höhenanzeige" #define TR_SCALE "Skalieren" diff --git a/radio/src/translations/en.h.txt b/radio/src/translations/en.h.txt index e0602bd6c..2e8b2f8a6 100644 --- a/radio/src/translations/en.h.txt +++ b/radio/src/translations/en.h.txt @@ -990,10 +990,10 @@ #define TR_ANTENNASELECTION TR(INDENT "Antenna", TR(INDENT "Antenna", INDENT "Antenna selection")) #define TR_ANTENNACONFIRM1 "Really switch?" #define TR_ANTENNACONFIRM2 TR("Check antenna", "Make sure antenna is installed!") -#define TR_R9M_PROTO_FLEX_WARN1 "Requires FLEX non" -#define TR_R9M_PROTO_FCC_WARN1 "Requires FCC" -#define TR_R9M_PROTO_EU_WARN1 "Requires EU" -#define TR_R9M_PROTO_WARN2 "certified firmware" +#define TR_R9M_PROTO_FLEX_WARN_LINE1 "Requires FLEX non" +#define TR_R9M_PROTO_FCC_WARN_LINE1 "Requires FCC" +#define TR_R9M_PROTO_EU_WARN_LINE1 "Requires EU" +#define TR_R9M_PROTO_WARN_LINE2 "certified firmware" #define TR_LOWALARM INDENT "Low alarm" #define TR_CRITICALALARM INDENT "Critical alarm" #define TR_RSSIALARM_WARN "RSSI" @@ -1142,6 +1142,9 @@ #define TR_FLASH_WRITE "Flash write..." #define TR_OTA_UPDATE "OTA update..." #define TR_MODULE_RESET "Module reset..." +#define TR_UNKNOWN_RX "Unknown RX" +#define TR_UNSUPPORTED_RX "Unsupported RX" +#define TR_OTA_UPDATE_ERROR "OTA update error" #define TR_DEVICE_RESET "Device reset..." #define TR_ALTITUDE INDENT "Altitude" #define TR_SCALE "Scale" diff --git a/radio/src/translations/es.h.txt b/radio/src/translations/es.h.txt index 4bc971393..0f3812097 100644 --- a/radio/src/translations/es.h.txt +++ b/radio/src/translations/es.h.txt @@ -1006,10 +1006,10 @@ #define TR_ANTENNASELECTION TR(INDENT "Antenna", TR(INDENT "Antenna", INDENT "Antenna selection")) #define TR_ANTENNACONFIRM1 "Really switch?" #define TR_ANTENNACONFIRM2 TR("Check antenna", "Make sure antenna is installed!") -#define TR_R9M_PROTO_FLEX_WARN1 "Requires non" -#define TR_R9M_PROTO_FCC_WARN1 "Requires FCC" -#define TR_R9M_PROTO_EU_WARN1 "Requires EU" -#define TR_R9M_PROTO_WARN2 "certified firmware" +#define TR_R9M_PROTO_FLEX_WARN_LINE1 "Requires non" +#define TR_R9M_PROTO_FCC_WARN_LINE1 "Requires FCC" +#define TR_R9M_PROTO_EU_WARN_LINE1 "Requires EU" +#define TR_R9M_PROTO_WARN_LINE2 "certified firmware" #define TR_LOWALARM INDENT "Alarma baja" #define TR_CRITICALALARM INDENT "Alarma Critica" #define TR_RSSIALARM_WARN TR("RSSI","TELEMETRY RSSI") @@ -1159,6 +1159,9 @@ #define TR_FLASH_WRITE "Flash write..." #define TR_OTA_UPDATE "OTA update..." #define TR_MODULE_RESET "Module reset..." +#define TR_UNKNOWN_RX "Unknown RX" +#define TR_UNSUPPORTED_RX "Unsupported RX" +#define TR_OTA_UPDATE_ERROR "OTA update error" #define TR_DEVICE_RESET "Device reset..." #define TR_ALTITUDE INDENT "Altitude" #define TR_SCALE "Scale" diff --git a/radio/src/translations/fi.h.txt b/radio/src/translations/fi.h.txt index 903e1956e..ed4770796 100644 --- a/radio/src/translations/fi.h.txt +++ b/radio/src/translations/fi.h.txt @@ -999,10 +999,10 @@ #define TR_ANTENNASELECTION TR(INDENT "Antenna", TR(INDENT "Antenna", INDENT "Antenna selection")) #define TR_ANTENNACONFIRM1 "Really switch?" #define TR_ANTENNACONFIRM2 TR("Check antenna", "Make sure antenna is installed!") -#define TR_R9M_PROTO_FLEX_WARN1 "Requires non" -#define TR_R9M_PROTO_FCC_WARN1 "Requires FCC" -#define TR_R9M_PROTO_EU_WARN1 "Requires EU" -#define TR_R9M_PROTO_WARN2 "certified firmware" +#define TR_R9M_PROTO_FLEX_WARN_LINE1 "Requires non" +#define TR_R9M_PROTO_FCC_WARN_LINE1 "Requires FCC" +#define TR_R9M_PROTO_EU_WARN_LINE1 "Requires EU" +#define TR_R9M_PROTO_WARN_LINE2 "certified firmware" #define TR_LOWALARM INDENT "Low Alarm" #define TR_CRITICALALARM INDENT "Critical Alarm" #define TR_RSSIALARM_WARN TR("RSSI","TELEMETRY RSSI") @@ -1152,6 +1152,9 @@ #define TR_FLASH_WRITE "Flash write..." #define TR_OTA_UPDATE "OTA update..." #define TR_MODULE_RESET "Module reset..." +#define TR_UNKNOWN_RX "Unknown RX" +#define TR_UNSUPPORTED_RX "Unsupported RX" +#define TR_OTA_UPDATE_ERROR "OTA update error" #define TR_DEVICE_RESET "Device reset..." #define TR_ALTITUDE INDENT "Korkeus" #define TR_SCALE "Scale" diff --git a/radio/src/translations/fr.h.txt b/radio/src/translations/fr.h.txt index cac789c72..32720e0c3 100644 --- a/radio/src/translations/fr.h.txt +++ b/radio/src/translations/fr.h.txt @@ -1001,10 +1001,10 @@ #define TR_ANTENNASELECTION TR(INDENT "Antenne", INDENT "Choix antenne") #define TR_ANTENNACONFIRM1 "Vraiment changer?" #define TR_ANTENNACONFIRM2 TR("Vérif antenne", "Installer l'antenne d'abord!") -#define TR_R9M_PROTO_FLEX_WARN1 "Nécessite firm." -#define TR_R9M_PROTO_FCC_WARN1 "Requires FCC" -#define TR_R9M_PROTO_EU_WARN1 "Requires EU" -#define TR_R9M_PROTO_WARN2 "R9M non certifié" +#define TR_R9M_PROTO_FLEX_WARN_LINE1 "Nécessite firm." +#define TR_R9M_PROTO_FCC_WARN_LINE1 "Requires FCC" +#define TR_R9M_PROTO_EU_WARN_LINE1 "Requires EU" +#define TR_R9M_PROTO_WARN_LINE2 "R9M non certifié" #define TR_LOWALARM INDENT "Alarme basse" #define TR_CRITICALALARM INDENT "Alarme critique" #define TR_RSSIALARM_WARN TR("RSSI", "TELEMETRIE") @@ -1161,6 +1161,9 @@ #define TR_FLASH_WRITE "Flash write..." #define TR_OTA_UPDATE "OTA update..." #define TR_MODULE_RESET "Module reset..." +#define TR_UNKNOWN_RX "Unknown RX" +#define TR_UNSUPPORTED_RX "Unsupported RX" +#define TR_OTA_UPDATE_ERROR "OTA update error" #define TR_DEVICE_RESET "Device reset..." #define TR_ALTITUDE INDENT "Altitude" #define TR_SCALE "Echelle" diff --git a/radio/src/translations/it.h.txt b/radio/src/translations/it.h.txt index 2db0d6d15..3093eceec 100644 --- a/radio/src/translations/it.h.txt +++ b/radio/src/translations/it.h.txt @@ -1000,10 +1000,10 @@ #define TR_ANTENNASELECTION TR(INDENT "Antenna", INDENT "Antenna selection") #define TR_ANTENNACONFIRM1 "Really switch?" #define TR_ANTENNACONFIRM2 TR("Check antenna", "Make sure antenna is installed!") -#define TR_R9M_PROTO_FLEX_WARN1 "Requires non" -#define TR_R9M_PROTO_FCC_WARN1 "Requires FCC" -#define TR_R9M_PROTO_EU_WARN1 "Requires EU" -#define TR_R9M_PROTO_WARN2 "certified firmware" +#define TR_R9M_PROTO_FLEX_WARN_LINE1 "Requires non" +#define TR_R9M_PROTO_FCC_WARN_LINE1 "Requires FCC" +#define TR_R9M_PROTO_EU_WARN_LINE1 "Requires EU" +#define TR_R9M_PROTO_WARN_LINE2 "certified firmware" #define TR_LOWALARM INDENT "Allarme Basso" #define TR_CRITICALALARM INDENT "Allarme Critico" #define TR_RSSIALARM_WARN TR("RSSI","TELEMETRY RSSI") @@ -1153,6 +1153,9 @@ #define TR_FLASH_WRITE "Flash write..." #define TR_OTA_UPDATE "OTA update..." #define TR_MODULE_RESET "Module reset..." +#define TR_UNKNOWN_RX "Unknown RX" +#define TR_UNSUPPORTED_RX "Unsupported RX" +#define TR_OTA_UPDATE_ERROR "OTA update error" #define TR_DEVICE_RESET "Device reset..." #define TR_ALTITUDE INDENT "Altitudine" #define TR_SCALE "Scala" diff --git a/radio/src/translations/nl.h.txt b/radio/src/translations/nl.h.txt index 67c9f529c..a83e8aeef 100644 --- a/radio/src/translations/nl.h.txt +++ b/radio/src/translations/nl.h.txt @@ -989,10 +989,10 @@ TR_GYR_VSRCRAW #define TR_ANTENNASELECTION TR(INDENT "Antenna", INDENT "Antenna selection") #define TR_ANTENNACONFIRM1 "Antennes wisselen?" #define TR_ANTENNACONFIRM2 TR("Check antenna", "Is er zeker een antenne geplaatst!") -#define TR_R9M_PROTO_FLEX_WARN1 "Requires non" -#define TR_R9M_PROTO_FCC_WARN1 "Requires FCC" -#define TR_R9M_PROTO_EU_WARN1 "Requires EU" -#define TR_R9M_PROTO_WARN2 "certified firmware" +#define TR_R9M_PROTO_FLEX_WARN_LINE1 "Requires non" +#define TR_R9M_PROTO_FCC_WARN_LINE1 "Requires FCC" +#define TR_R9M_PROTO_EU_WARN_LINE1 "Requires EU" +#define TR_R9M_PROTO_WARN_LINE2 "certified firmware" #define TR_LOWALARM INDENT "Waarschuwing" #define TR_CRITICALALARM INDENT "Kritiek Alarm" #define TR_RSSIALARM_WARN TR("RSSI","TELEMETRY RSSI") @@ -1147,6 +1147,9 @@ TR_GYR_VSRCRAW #define TR_FLASH_WRITE "Flash write..." #define TR_OTA_UPDATE "OTA update..." #define TR_MODULE_RESET "Module reset..." +#define TR_UNKNOWN_RX "Unknown RX" +#define TR_UNSUPPORTED_RX "Unsupported RX" +#define TR_OTA_UPDATE_ERROR "OTA update error" #define TR_DEVICE_RESET "Device reset..." #define TR_ALTITUDE INDENT "Hoogte" #define TR_SCALE "Schaal" diff --git a/radio/src/translations/pl.h.txt b/radio/src/translations/pl.h.txt index 2753c4ed3..65f183bff 100644 --- a/radio/src/translations/pl.h.txt +++ b/radio/src/translations/pl.h.txt @@ -1000,10 +1000,10 @@ #define TR_ANTENNASELECTION TR(INDENT "Antenna", INDENT "Antenna selection") #define TR_ANTENNACONFIRM1 "Really switch?" #define TR_ANTENNACONFIRM2 TR("Check antenna", "Make sure antenna is installed!") -#define TR_R9M_PROTO_FLEX_WARN1 "Requires non" -#define TR_R9M_PROTO_FCC_WARN1 "Requires FCC" -#define TR_R9M_PROTO_EU_WARN1 "Requires EU" -#define TR_R9M_PROTO_WARN2 "certified firmware" +#define TR_R9M_PROTO_FLEX_WARN_LINE1 "Requires non" +#define TR_R9M_PROTO_FCC_WARN_LINE1 "Requires FCC" +#define TR_R9M_PROTO_EU_WARN_LINE1 "Requires EU" +#define TR_R9M_PROTO_WARN_LINE2 "certified firmware" #define TR_LOWALARM INDENT "Alarm niski" #define TR_CRITICALALARM INDENT "Alarm krytyczny" #define TR_RSSIALARM_WARN TR("RSSI","TELEMETRY RSSI") @@ -1153,6 +1153,9 @@ #define TR_FLASH_WRITE "Flash write..." #define TR_OTA_UPDATE "OTA update..." #define TR_MODULE_RESET "Module reset..." +#define TR_UNKNOWN_RX "Unknown RX" +#define TR_UNSUPPORTED_RX "Unsupported RX" +#define TR_OTA_UPDATE_ERROR "OTA update error" #define TR_DEVICE_RESET "Device reset..." #define TR_ALTITUDE INDENT "Wysokość" #define TR_SCALE "Skala" diff --git a/radio/src/translations/pt.h.txt b/radio/src/translations/pt.h.txt index f175ea14b..0c9064ce3 100644 --- a/radio/src/translations/pt.h.txt +++ b/radio/src/translations/pt.h.txt @@ -990,10 +990,10 @@ #define TR_ANTENNASELECTION TR(INDENT "Antenna", INDENT "Antenna selection") #define TR_ANTENNACONFIRM1 "Really switch?" #define TR_ANTENNACONFIRM2 TR("Check antenna", "Make sure antenna is installed!") -#define TR_R9M_PROTO_FLEX_WARN1 "Requires non" -#define TR_R9M_PROTO_FCC_WARN1 "Requires FCC" -#define TR_R9M_PROTO_EU_WARN1 "Requires EU" -#define TR_R9M_PROTO_WARN2 "certified firmware" +#define TR_R9M_PROTO_FLEX_WARN_LINE1 "Requires non" +#define TR_R9M_PROTO_FCC_WARN_LINE1 "Requires FCC" +#define TR_R9M_PROTO_EU_WARN_LINE1 "Requires EU" +#define TR_R9M_PROTO_WARN_LINE2 "certified firmware" #define TR_LOWALARM INDENT "Low Alarm" #define TR_CRITICALALARM INDENT "Critical Alarm" #define TR_RSSIALARM_WARN TR("RSSI","TELEMETRY RSSI") @@ -1143,6 +1143,9 @@ #define TR_FLASH_WRITE "Flash write..." #define TR_OTA_UPDATE "OTA update..." #define TR_MODULE_RESET "Module reset..." +#define TR_UNKNOWN_RX "Unknown RX" +#define TR_UNSUPPORTED_RX "Unsupported RX" +#define TR_OTA_UPDATE_ERROR "OTA update error" #define TR_DEVICE_RESET "Device reset..." #define TR_ALTITUDE INDENT "Altitude" #define TR_SCALE "Scale" diff --git a/radio/src/translations/se.h.txt b/radio/src/translations/se.h.txt index 6f0a51c61..4d6096338 100644 --- a/radio/src/translations/se.h.txt +++ b/radio/src/translations/se.h.txt @@ -1000,10 +1000,10 @@ #define TR_ANTENNASELECTION TR(INDENT "Antenna", INDENT "Antenna selection") #define TR_ANTENNACONFIRM1 "Really switch?" #define TR_ANTENNACONFIRM2 TR("Check antenna", "Make sure antenna is installed!") -#define TR_R9M_PROTO_FLEX_WARN1 "Requires non" -#define TR_R9M_PROTO_FCC_WARN1 "Requires FCC" -#define TR_R9M_PROTO_EU_WARN1 "Requires EU" -#define TR_R9M_PROTO_WARN2 "certified firmware" +#define TR_R9M_PROTO_FLEX_WARN_LINE1 "Requires non" +#define TR_R9M_PROTO_FCC_WARN_LINE1 "Requires FCC" +#define TR_R9M_PROTO_EU_WARN_LINE1 "Requires EU" +#define TR_R9M_PROTO_WARN_LINE2 "certified firmware" #define TR_LOWALARM INDENT "Låg-alarm" #define TR_CRITICALALARM INDENT "Kritiskt alarm" #define TR_RSSIALARM_WARN TR("RSSI","TELEMETRY RSSI") @@ -1153,6 +1153,9 @@ #define TR_FLASH_WRITE "Flash write..." #define TR_OTA_UPDATE "OTA update..." #define TR_MODULE_RESET "Module reset..." +#define TR_UNKNOWN_RX "Unknown RX" +#define TR_UNSUPPORTED_RX "Unsupported RX" +#define TR_OTA_UPDATE_ERROR "OTA update error" #define TR_DEVICE_RESET "Device reset..." #define TR_ALTITUDE INDENT "Höjd" #define TR_SCALE "Skala" From 747e6131bc10bab7cd2300fbc228f8f490ffb9e8 Mon Sep 17 00:00:00 2001 From: lshems Date: Thu, 13 Jun 2019 17:07:07 +0200 Subject: [PATCH 011/350] Update api_model.cpp (#6492) Added carryTrim to input API's --- radio/src/lua/api_model.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/radio/src/lua/api_model.cpp b/radio/src/lua/api_model.cpp index 481bbf4b8..344b13101 100644 --- a/radio/src/lua/api_model.cpp +++ b/radio/src/lua/api_model.cpp @@ -335,8 +335,9 @@ Return input data for given input and line number * `switch` (number) input switch index * `curveType` (number) curve type (function, expo, custom curve) * `curveValue` (number) curve index + * `carryTrim` (boolean) input trims applied -@status current Introduced in 2.0.0, curveType/curveValue added in 2.3 +@status current Introduced in 2.0.0, curveType/curveValue/carryTrim added in 2.3 */ static int luaModelGetInput(lua_State *L) { @@ -354,6 +355,7 @@ static int luaModelGetInput(lua_State *L) lua_pushtableinteger(L, "switch", expo->swtch); lua_pushtableinteger(L, "curveType", expo->curve.type); lua_pushtableinteger(L, "curveValue", expo->curve.value); + lua_pushtableinteger(L, "carryTrim", expo->carryTrim); } else { lua_pushnil(L); @@ -372,7 +374,7 @@ Insert an Input at specified line @param value (table) input data, see model.getInput() -@status current Introduced in 2.0.0, curveType/curveValue added in 2.3 +@status current Introduced in 2.0.0, curveType/curveValue/carryTrim added in 2.3 */ static int luaModelInsertInput(lua_State *L) { @@ -413,6 +415,9 @@ static int luaModelInsertInput(lua_State *L) else if (!strcmp(key, "curveValue")) { expo->curve.value = luaL_checkinteger(L, -1); } + else if (!strcmp(key, "carryTrim")) { + expo->carryTrim= lua_toboolean(L, -1); + } } } From 1efd3cbefa22f3cf74879ee5c86f32bebe91880d Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Thu, 13 Jun 2019 17:14:59 +0200 Subject: [PATCH 012/350] Cosmetics --- radio/src/lua/api_model.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radio/src/lua/api_model.cpp b/radio/src/lua/api_model.cpp index 344b13101..31ad730d1 100644 --- a/radio/src/lua/api_model.cpp +++ b/radio/src/lua/api_model.cpp @@ -416,7 +416,7 @@ static int luaModelInsertInput(lua_State *L) expo->curve.value = luaL_checkinteger(L, -1); } else if (!strcmp(key, "carryTrim")) { - expo->carryTrim= lua_toboolean(L, -1); + expo->carryTrim = lua_toboolean(L, -1); } } } From 821865f70eef0fe1635b25fc96b10edf366911bb Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Thu, 13 Jun 2019 19:25:20 +0200 Subject: [PATCH 013/350] Bsongis/x9 lite pwr fix (#6495) Board init sequence changed --- .../common/arm/stm32/bootloader/boot.cpp | 1 + radio/src/targets/horus/hal.h | 5 ++-- radio/src/targets/horus/pwr_driver.cpp | 23 +++++++++++-------- radio/src/targets/taranis/board.cpp | 19 ++++++++------- radio/src/targets/taranis/board_preinit.cpp | 6 ++++- radio/src/targets/taranis/pwr_driver.cpp | 14 +---------- 6 files changed, 32 insertions(+), 36 deletions(-) diff --git a/radio/src/targets/common/arm/stm32/bootloader/boot.cpp b/radio/src/targets/common/arm/stm32/bootloader/boot.cpp index 9555001f6..0663ef223 100644 --- a/radio/src/targets/common/arm/stm32/bootloader/boot.cpp +++ b/radio/src/targets/common/arm/stm32/bootloader/boot.cpp @@ -228,6 +228,7 @@ int main() #endif pwrInit(); + pwrOn(); delaysInit(); // needed for lcdInit() #if defined(DEBUG) diff --git a/radio/src/targets/horus/hal.h b/radio/src/targets/horus/hal.h index 11361676a..b94470799 100644 --- a/radio/src/targets/horus/hal.h +++ b/radio/src/targets/horus/hal.h @@ -279,9 +279,10 @@ // Power #define PWR_RCC_AHB1Periph RCC_AHB1Periph_GPIOJ -#define PWR_GPIO GPIOJ -#define PWR_SWITCH_GPIO_PIN GPIO_Pin_0 // PJ.00 +#define PWR_ON_GPIO GPIOJ #define PWR_ON_GPIO_PIN GPIO_Pin_1 // PJ.01 +#define PWR_SWITCH_GPIO GPIOJ +#define PWR_SWITCH_GPIO_PIN GPIO_Pin_0 // PJ.00 // S.Port update connector #define SPORT_MAX_BAUDRATE 250000 // < 400000 diff --git a/radio/src/targets/horus/pwr_driver.cpp b/radio/src/targets/horus/pwr_driver.cpp index 7c7dab489..71ee994e4 100644 --- a/radio/src/targets/horus/pwr_driver.cpp +++ b/radio/src/targets/horus/pwr_driver.cpp @@ -28,37 +28,40 @@ uint32_t powerupReason __NOINIT; // Stores power up reason beyond initializati void pwrInit() { GPIO_InitTypeDef GPIO_InitStructure; - // Init Module PWR + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; + + // Internal module PWR GPIO_ResetBits(INTMODULE_PWR_GPIO, INTMODULE_PWR_GPIO_PIN); GPIO_InitStructure.GPIO_Pin = INTMODULE_PWR_GPIO_PIN; GPIO_Init(INTMODULE_PWR_GPIO, &GPIO_InitStructure); + // External module PWR GPIO_ResetBits(EXTMODULE_PWR_GPIO, EXTMODULE_PWR_GPIO_PIN); GPIO_InitStructure.GPIO_Pin = EXTMODULE_PWR_GPIO_PIN; GPIO_Init(EXTMODULE_PWR_GPIO, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; - // Init PWR SWITCH PIN + // PWR SWITCH GPIO_InitStructure.GPIO_Pin = PWR_SWITCH_GPIO_PIN; - GPIO_Init(PWR_GPIO, &GPIO_InitStructure); + GPIO_Init(PWR_SWITCH_GPIO, &GPIO_InitStructure); - // Init PCBREV PIN + // PCBREV // TODO to be removed on X10? GPIO_ResetBits(PCBREV_GPIO, PCBREV_GPIO_PIN); GPIO_InitStructure.GPIO_Pin = PCBREV_GPIO_PIN; GPIO_Init(PCBREV_GPIO, &GPIO_InitStructure); - // Init SD-DETECT PIN + // SD-DETECT PIN GPIO_ResetBits(SD_PRESENT_GPIO, SD_PRESENT_GPIO_PIN); GPIO_InitStructure.GPIO_Pin = SD_PRESENT_GPIO_PIN; GPIO_Init(SD_PRESENT_GPIO, &GPIO_InitStructure); - // Init TRAINER DETECT PIN + // TRAINER DETECT PIN GPIO_InitStructure.GPIO_Pin = TRAINER_DETECT_GPIO_PIN; GPIO_Init(TRAINER_DETECT_GPIO, &GPIO_InitStructure); @@ -73,9 +76,9 @@ void pwrOn() GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; - GPIO_Init(PWR_GPIO, &GPIO_InitStructure); + GPIO_Init(PWR_ON_GPIO, &GPIO_InitStructure); - GPIO_SetBits(PWR_GPIO, PWR_ON_GPIO_PIN); + GPIO_SetBits(PWR_ON_GPIO, PWR_ON_GPIO_PIN); shutdownRequest = NO_SHUTDOWN_REQUEST; shutdownReason = DIRTY_SHUTDOWN; @@ -100,12 +103,12 @@ void pwrOff() shutdownRequest = SHUTDOWN_REQUEST; shutdownReason = NORMAL_POWER_OFF; - GPIO_ResetBits(PWR_GPIO, PWR_ON_GPIO_PIN); + GPIO_ResetBits(PWR_ON_GPIO, PWR_ON_GPIO_PIN); } uint32_t pwrPressed() { - return GPIO_ReadInputDataBit(PWR_GPIO, PWR_SWITCH_GPIO_PIN) == Bit_RESET; + return GPIO_ReadInputDataBit(PWR_ON_GPIO, PWR_SWITCH_GPIO_PIN) == Bit_RESET; } void pwrResetHandler() diff --git a/radio/src/targets/taranis/board.cpp b/radio/src/targets/taranis/board.cpp index b8f408b3c..f5704f08b 100644 --- a/radio/src/targets/taranis/board.cpp +++ b/radio/src/targets/taranis/board.cpp @@ -192,10 +192,7 @@ void boardInit() bluetoothInit(BLUETOOTH_DEFAULT_BAUDRATE, true); #endif -#if !defined(PCBX9E) - // some X9E boards need that the pwrInit() is moved a little bit later pwrInit(); -#endif #if defined(STATUS_LEDS) ledInit(); @@ -247,7 +244,7 @@ void boardInit() #if defined(PWR_BUTTON_PRESS) if (!WAS_RESET_BY_WATCHDOG_OR_SOFTWARE()) { lcdClear(); -#if defined(PCBX9E) +#if LCD_DEPTH > 1 lcdDrawBitmap(76, 2, bmp_lock, 0, 60); #else lcdDrawFilledRect(LCD_W / 2 - 18, LCD_H / 2 - 3, 6, 6, SOLID, 0); @@ -263,7 +260,7 @@ void boardInit() if (duration < PWR_PRESS_DURATION_MIN) { unsigned index = duration / (PWR_PRESS_DURATION_MIN / 4); lcdClear(); -#if defined(PCBX9E) +#if LCD_DEPTH > 1 lcdDrawBitmap(76, 2, bmp_startup, index*60, 60); #else for(uint8_t i= 0; i < 4; i++) { @@ -280,7 +277,7 @@ void boardInit() else { if (pwr_on != 1) { pwr_on = 1; - pwrInit(); + pwrOn(); backlightInit(); haptic.play(15, 3, PLAY_NOW); } @@ -293,15 +290,17 @@ void boardInit() } } else { - pwrInit(); + pwrOn(); backlightInit(); } +#else // defined(PWR_BUTTON_PRESS) + pwrOn(); + backlightInit(); +#endif + #if defined(TOPLCD_GPIO) toplcdInit(); #endif -#else // defined(PWR_BUTTON_PRESS) - backlightInit(); -#endif if (HAS_SPORT_UPDATE_CONNECTOR()) { sportUpdateInit(); diff --git a/radio/src/targets/taranis/board_preinit.cpp b/radio/src/targets/taranis/board_preinit.cpp index 743dff65f..116c2577d 100644 --- a/radio/src/targets/taranis/board_preinit.cpp +++ b/radio/src/targets/taranis/board_preinit.cpp @@ -22,14 +22,18 @@ void boardPreInit() { -#if defined(INTMODULE_BOOTCMD_GPIO) GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; + // Board PWR kept OFF + GPIO_ResetBits(PWR_ON_GPIO, PWR_ON_GPIO_PIN); + GPIO_InitStructure.GPIO_Pin = PWR_ON_GPIO_PIN; + GPIO_Init(PWR_ON_GPIO, &GPIO_InitStructure); +#if defined(INTMODULE_BOOTCMD_GPIO) GPIO_SetBits(INTMODULE_BOOTCMD_GPIO, INTMODULE_BOOTCMD_GPIO_PIN); GPIO_InitStructure.GPIO_Pin = INTMODULE_BOOTCMD_GPIO_PIN; GPIO_Init(INTMODULE_BOOTCMD_GPIO, &GPIO_InitStructure); diff --git a/radio/src/targets/taranis/pwr_driver.cpp b/radio/src/targets/taranis/pwr_driver.cpp index ec4e5d3ac..f0e9855be 100644 --- a/radio/src/targets/taranis/pwr_driver.cpp +++ b/radio/src/targets/taranis/pwr_driver.cpp @@ -23,12 +23,11 @@ void pwrInit() { GPIO_InitTypeDef GPIO_InitStructure; - - GPIO_InitStructure.GPIO_Pin = PWR_ON_GPIO_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; + GPIO_ResetBits(INTMODULE_PWR_GPIO, INTMODULE_PWR_GPIO_PIN); GPIO_InitStructure.GPIO_Pin = INTMODULE_PWR_GPIO_PIN; GPIO_Init(INTMODULE_PWR_GPIO, &GPIO_InitStructure); @@ -58,21 +57,10 @@ void pwrInit() GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; GPIO_Init(PCBREV_GPIO, &GPIO_InitStructure); #endif - - pwrOn(); } void pwrOn() { - GPIO_InitTypeDef GPIO_InitStructure; - - GPIO_InitStructure.GPIO_Pin = PWR_ON_GPIO_PIN; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; - GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; - GPIO_Init(PWR_ON_GPIO, &GPIO_InitStructure); - GPIO_SetBits(PWR_ON_GPIO, PWR_ON_GPIO_PIN); } From a1e146bd63ce917afd3afcd9b0f9e123661e65b6 Mon Sep 17 00:00:00 2001 From: 3djc Date: Thu, 13 Jun 2019 19:26:40 +0200 Subject: [PATCH 014/350] Improve LUA system timers handling (#6368) * Add resetGlobalTimer option * Add getGlobalTimer function --- radio/src/lua/api_general.cpp | 108 ++++++++++++++++++++++++++++++++-- 1 file changed, 103 insertions(+), 5 deletions(-) diff --git a/radio/src/lua/api_general.cpp b/radio/src/lua/api_general.cpp index 65b0d12e0..d60b2a5bd 100644 --- a/radio/src/lua/api_general.cpp +++ b/radio/src/lua/api_general.cpp @@ -801,7 +801,7 @@ Return the internal GPS position or nil if no valid hardware found * 'speed' (number) internal GPSspeed in 0.1m/s * 'heading' (number) internal GPS ground course estimation in degrees * 10 -@status current Introduced in 2.3.0 +@status current Introduced in 2.2.2 */ static int luaGetTxGPS(lua_State * L) { @@ -1044,7 +1044,7 @@ Returns (some of) the general radio settings * `gtimer` (number) radio global timer in seconds (does not include current session) @status current Introduced in 2.0.6, `imperial` added in TODO, -`language` and `voice` added in 2.2.0, gtimer added in 2.3.0. +`language` and `voice` added in 2.2.0, gtimer added in 2.2.2. */ static int luaGetGeneralSettings(lua_State * L) @@ -1060,6 +1060,82 @@ static int luaGetGeneralSettings(lua_State * L) return 1; } +/*luadoc +@function getGlobalTimer() + +Returns radio timers + +@retval table with elements: +* `gtimer` (number) radio global timer in seconds +* `session` (number) radio session in seconds +* `ttimer` (number) radio throttle timer in seconds +* `tptimer` (number) radio throttle percent timer in seconds + +@status current Introduced added in 2.3.0. + +*/ +static int luaGetGlobalTimer(lua_State * L) +{ + lua_newtable(L); + lua_pushtableinteger(L, "gtimer", g_eeGeneral.globalTimer + sessionTimer); + lua_pushtableinteger(L, "session", sessionTimer); + lua_pushtableinteger(L, "ttimer", s_timeCumThr); + lua_pushtableinteger(L, "tptimer", s_timeCum16ThrP/16); + return 1; +} + +/*luadoc +@function popupInput(title, event, input, min, max) + +Raises a pop-up on screen that allows uses input + +@param title (string) text to display + +@param event (number) the event variable that is passed in from the +Run function (key pressed) + +@param input (number) value that can be adjusted by the +/­- keys + +@param min (number) min value that input can reach (by pressing the -­ key) + +@param max (number) max value that input can reach + +@retval number result of the input adjustment + +@retval "OK" user pushed ENT key + +@retval "CANCEL" user pushed EXIT key + +@notice Use only from stand-alone and telemetry scripts. + +@status current Introduced in 2.0.0 +*/ + +/* TODO : fix, broken by popups rewrite +static int luaPopupInput(lua_State * L) +{ + event_t event = luaL_checkinteger(L, 2); + warningInputValue = luaL_checkinteger(L, 3); + warningInputValueMin = luaL_checkinteger(L, 4); + warningInputValueMax = luaL_checkinteger(L, 5); + warningText = luaL_checkstring(L, 1); + warningType = WARNING_TYPE_INPUT; + runPopupWarning(event); + if (warningResult) { + warningResult = 0; + lua_pushstring(L, "OK"); + } + else if (!warningText) { + lua_pushstring(L, "CANCEL"); + } + else { + lua_pushinteger(L, warningInputValue); + } + warningText = NULL; + return 1; +} +*/ + /*luadoc @function popupWarning(title, event) @@ -1352,15 +1428,36 @@ static int luaGetUsage(lua_State * L) } /*luadoc -@function resetGlobalTimer() +@function resetGlobalTimer([type]) -Resets the radio global timer to 0. + Resets the radio global timer to 0. -@status current Introduced in 2.3.0 +@param (optional) : if set to 'all', throttle ,throttle percent and session timers are reset too + if set to 'session', radio session timer is reset too + if set to 'ttimer', radio throttle timer is reset too + if set to 'tptimer', radio throttle percent timer is reset too + +@status current Introduced in 2.2.2, param added in 2.3 */ static int luaResetGlobalTimer(lua_State * L) { g_eeGeneral.globalTimer = 0; + size_t length; + const char *option = luaL_optlstring(L, 1, "", &length); + if (!strcmp(option, "all")) { + sessionTimer = 0; + s_timeCumThr = 0; + s_timeCum16ThrP = 0; + } + else if (!strcmp(option, "session")) { + sessionTimer = 0; + } + else if (!strcmp(option, "ttimer")) { + s_timeCumThr = 0; + } + else if (!strcmp(option, "tptimer")) { + s_timeCum16ThrP = 0; + } storageDirty(EE_GENERAL); return 0; } @@ -1411,6 +1508,7 @@ const luaL_Reg opentxLib[] = { #endif { "getVersion", luaGetVersion }, { "getGeneralSettings", luaGetGeneralSettings }, + { "getGlobalTimer", luaGetGlobalTimer }, { "getValue", luaGetValue }, { "getRAS", luaGetRAS }, { "getTxGPS", luaGetTxGPS }, From 8773c56dadef9f42bd03ed1374706b9276e1c0bd Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Fri, 14 Jun 2019 08:21:45 +0200 Subject: [PATCH 015/350] Modifications according to #6368 comments --- radio/src/lua/api_general.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/radio/src/lua/api_general.cpp b/radio/src/lua/api_general.cpp index d60b2a5bd..e4902b528 100644 --- a/radio/src/lua/api_general.cpp +++ b/radio/src/lua/api_general.cpp @@ -1077,10 +1077,10 @@ Returns radio timers static int luaGetGlobalTimer(lua_State * L) { lua_newtable(L); - lua_pushtableinteger(L, "gtimer", g_eeGeneral.globalTimer + sessionTimer); + lua_pushtableinteger(L, "total", g_eeGeneral.globalTimer + sessionTimer); lua_pushtableinteger(L, "session", sessionTimer); - lua_pushtableinteger(L, "ttimer", s_timeCumThr); - lua_pushtableinteger(L, "tptimer", s_timeCum16ThrP/16); + lua_pushtableinteger(L, "throttle", s_timeCumThr); + lua_pushtableinteger(L, "throttlepct", s_timeCum16ThrP/16); return 1; } @@ -1441,21 +1441,25 @@ static int luaGetUsage(lua_State * L) */ static int luaResetGlobalTimer(lua_State * L) { - g_eeGeneral.globalTimer = 0; size_t length; - const char *option = luaL_optlstring(L, 1, "", &length); + const char * option = luaL_optlstring(L, 1, "all", &length); if (!strcmp(option, "all")) { + g_eeGeneral.globalTimer = 0; sessionTimer = 0; s_timeCumThr = 0; s_timeCum16ThrP = 0; } + else if (!strcmp(option, "total")) { + g_eeGeneral.globalTimer = 0; + sessionTimer = 0; + } else if (!strcmp(option, "session")) { sessionTimer = 0; } - else if (!strcmp(option, "ttimer")) { + else if (!strcmp(option, "throttle")) { s_timeCumThr = 0; } - else if (!strcmp(option, "tptimer")) { + else if (!strcmp(option, "throttlepct")) { s_timeCum16ThrP = 0; } storageDirty(EE_GENERAL); From 7132d4ec49a0ab5c57ad932a658376d28744d97c Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Fri, 14 Jun 2019 08:24:15 +0200 Subject: [PATCH 016/350] Cosmetics --- radio/src/lua/api_general.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radio/src/lua/api_general.cpp b/radio/src/lua/api_general.cpp index e4902b528..c107615f0 100644 --- a/radio/src/lua/api_general.cpp +++ b/radio/src/lua/api_general.cpp @@ -1472,7 +1472,7 @@ static int luaResetGlobalTimer(lua_State * L) Writes a string to the serial port. The string is allowed to contain any character, including 0. -@status current Introducted in TODO +@status current Introduced in TODO */ static int luaSerialWrite(lua_State * L) { From 998e8b6d3dadc67e57e1c46fdd3afa4ad68d2033 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Fri, 14 Jun 2019 08:40:35 +0200 Subject: [PATCH 017/350] Another change related to #6368 (avoids breaking compatibility) --- radio/src/lua/api_general.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radio/src/lua/api_general.cpp b/radio/src/lua/api_general.cpp index c107615f0..e52aafd59 100644 --- a/radio/src/lua/api_general.cpp +++ b/radio/src/lua/api_general.cpp @@ -1442,7 +1442,7 @@ static int luaGetUsage(lua_State * L) static int luaResetGlobalTimer(lua_State * L) { size_t length; - const char * option = luaL_optlstring(L, 1, "all", &length); + const char * option = luaL_optlstring(L, 1, "total", &length); if (!strcmp(option, "all")) { g_eeGeneral.globalTimer = 0; sessionTimer = 0; From ce6bf053b83dcbe3b9611c3b617a216207da1b09 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Fri, 14 Jun 2019 09:18:27 +0200 Subject: [PATCH 018/350] Throttle warning screen reworking --- radio/src/gui/128x64/radio_setup.cpp | 2 +- radio/src/gui/212x64/radio_setup.cpp | 2 +- radio/src/gui/480x272/radio_setup.cpp | 2 +- radio/src/opentx.cpp | 54 +++++++++++++-------------- radio/src/opentx.h | 2 +- 5 files changed, 31 insertions(+), 31 deletions(-) diff --git a/radio/src/gui/128x64/radio_setup.cpp b/radio/src/gui/128x64/radio_setup.cpp index a9fc6f4e5..34e8bfe76 100644 --- a/radio/src/gui/128x64/radio_setup.cpp +++ b/radio/src/gui/128x64/radio_setup.cpp @@ -632,7 +632,7 @@ void menuRadioSetup(event_t event) else if (reusableBuffer.generalSettings.stickMode != g_eeGeneral.stickMode) { pausePulses(); g_eeGeneral.stickMode = reusableBuffer.generalSettings.stickMode; - checkTHR(); + checkThrottleStick(); resumePulses(); waitKeysReleased(); } diff --git a/radio/src/gui/212x64/radio_setup.cpp b/radio/src/gui/212x64/radio_setup.cpp index ca81fb18b..17d376cc8 100644 --- a/radio/src/gui/212x64/radio_setup.cpp +++ b/radio/src/gui/212x64/radio_setup.cpp @@ -500,7 +500,7 @@ void menuRadioSetup(event_t event) else if (reusableBuffer.generalSettings.stickMode != g_eeGeneral.stickMode) { pausePulses(); g_eeGeneral.stickMode = reusableBuffer.generalSettings.stickMode; - checkTHR(); + checkThrottleStick(); resumePulses(); waitKeysReleased(); } diff --git a/radio/src/gui/480x272/radio_setup.cpp b/radio/src/gui/480x272/radio_setup.cpp index 2e7dc655b..f7c5c4248 100644 --- a/radio/src/gui/480x272/radio_setup.cpp +++ b/radio/src/gui/480x272/radio_setup.cpp @@ -480,7 +480,7 @@ bool menuRadioSetup(event_t event) else if (reusableBuffer.generalSettings.stickMode != g_eeGeneral.stickMode) { pausePulses(); g_eeGeneral.stickMode = reusableBuffer.generalSettings.stickMode; - checkTHR(); + checkThrottleStick(); resumePulses(); waitKeysReleased(); } diff --git a/radio/src/opentx.cpp b/radio/src/opentx.cpp index 598a531bf..43abbc78f 100644 --- a/radio/src/opentx.cpp +++ b/radio/src/opentx.cpp @@ -57,9 +57,14 @@ const uint8_t bchout_ar[] = { 0x87, 0x8D, 0x93, 0x9C, 0xB1, 0xB4, 0xC6, 0xC9, 0xD2, 0xD8, 0xE1, 0xE4 }; +uint8_t channel_order(uint8_t setup, uint8_t x) +{ + return ((*(bchout_ar + setup) >> (6 - (x - 1) * 2)) & 3) + 1; +} + uint8_t channel_order(uint8_t x) { - return ( ((*(bchout_ar + g_eeGeneral.templateSetup) >> (6-(x-1) * 2)) & 3 ) + 1 ); + return channel_order(g_eeGeneral.templateSetup, x); } /* @@ -867,9 +872,10 @@ void checkAll() checkLowEEPROM(); #endif - if (g_eeGeneral.chkSum == evalChkSum()) { - checkTHR(); - } + // we don't check the throttle stick if the radio is not calibrated + if (g_eeGeneral.chkSum == evalChkSum()) + checkThrottleStick(); + checkSwitches(); checkFailsafe(); checkRSSIAlarmsDisabled(); @@ -906,28 +912,32 @@ void checkLowEEPROM() } #endif -void checkTHR() +bool isThrottleWarningAlertNeeded() { - uint8_t thrchn = ((g_model.thrTraceSrc==0) || (g_model.thrTraceSrc>NUM_POTS+NUM_SLIDERS)) ? THR_STICK : g_model.thrTraceSrc+NUM_STICKS-1; + if (g_model.disableThrottleWarning) { + return false; + } + // throttle channel is either the stick according stick mode (already handled in evalInputs) // or P1 to P3; // in case an output channel is choosen as throttle source (thrTraceSrc>NUM_POTS+NUM_SLIDERS) we assume the throttle stick is the input // no other information available at the moment, and good enough to my option (otherwise too much exceptions...) - - if (g_model.disableThrottleWarning) { - return; - } + uint8_t thrchn = ((g_model.thrTraceSrc==0) || (g_model.thrTraceSrc>NUM_POTS+NUM_SLIDERS)) ? THR_STICK : g_model.thrTraceSrc+NUM_STICKS-1; GET_ADC_IF_MIXER_NOT_RUNNING(); - evalInputs(e_perout_mode_notrainer); // let do evalInputs do the job int16_t v = calibratedAnalogs[thrchn]; - if (g_model.thrTraceSrc && g_model.throttleReversed) { //TODO : proper review of THR source definition and handling + if (g_model.thrTraceSrc && g_model.throttleReversed) { // TODO : proper review of THR source definition and handling v = -v; } - if (v <= THRCHK_DEADBAND-1024) { - return; // prevent warning if throttle input OK + return v > THRCHK_DEADBAND - 1024; +} + +void checkThrottleStick() +{ + if (!isThrottleWarningAlertNeeded()) { + return; } // first - display warning; also deletes inputs if any have been before @@ -938,15 +948,9 @@ void checkTHR() bool refresh = false; #endif - while (1) { - - GET_ADC_IF_MIXER_NOT_RUNNING(); - - evalInputs(e_perout_mode_notrainer); // let do evalInputs do the job - - v = calibratedAnalogs[thrchn]; - if (g_model.thrTraceSrc && g_model.throttleReversed) { //TODO : proper review of THR source definition and handling - v = -v; + while (!getEvent()) { + if (!isThrottleWarningAlertNeeded()) { + return; } #if defined(PWR_BUTTON_PRESS) @@ -967,10 +971,6 @@ void checkTHR() } #endif - if (keyDown() || v <= THRCHK_DEADBAND-1024) { - break; - } - doLoopCommonActions(); wdt_reset(); diff --git a/radio/src/opentx.h b/radio/src/opentx.h index 5bf6981de..6ca4173cc 100644 --- a/radio/src/opentx.h +++ b/radio/src/opentx.h @@ -616,7 +616,7 @@ extern uint16_t maxMixerDuration; #endif void checkLowEEPROM(); -void checkTHR(); +void checkThrottleStick(); void checkSwitches(); void checkAlarm(); void checkAll(); From c28501fe462a05fbb3000fa15277fa04d682352b Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Fri, 14 Jun 2019 09:50:48 +0200 Subject: [PATCH 019/350] OTA update fix --- radio/src/io/frsky_firmware_update.cpp | 2 +- radio/src/pulses/pxx2.cpp | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/radio/src/io/frsky_firmware_update.cpp b/radio/src/io/frsky_firmware_update.cpp index 6f1d49749..ee3276864 100644 --- a/radio/src/io/frsky_firmware_update.cpp +++ b/radio/src/io/frsky_firmware_update.cpp @@ -299,7 +299,7 @@ const char * FrskyDeviceFirmwareUpdate::uploadFile(const char * filename) const char * ext = getFileExtension(filename); if (ext && !strcasecmp(ext, UPDATE_FIRMWARE_EXT)) { - // FrSkyFirmwareInformation *information = (FrSkyFirmwareInformation *) buffer; + // FrSkyFirmwareInformation * information = (FrSkyFirmwareInformation *) buffer; if (f_read(&file, buffer, sizeof(FrSkyFirmwareInformation), &count) != FR_OK || count != sizeof(FrSkyFirmwareInformation)) { f_close(&file); return "Format error"; diff --git a/radio/src/pulses/pxx2.cpp b/radio/src/pulses/pxx2.cpp index 3280d1fd0..984f7c0b4 100644 --- a/radio/src/pulses/pxx2.cpp +++ b/radio/src/pulses/pxx2.cpp @@ -20,6 +20,7 @@ #include "opentx.h" #include "pulses/pxx2.h" +#include "io/frsky_firmware_update.h" uint8_t Pxx2Pulses::addFlag0(uint8_t module) { @@ -452,7 +453,20 @@ const char * Pxx2OtaUpdate::doFlashFirmware(const char * filename) return "Open file failed"; } - uint32_t size = f_size(&file); + uint32_t size; + const char * ext = getFileExtension(filename); + if (ext && !strcasecmp(ext, UPDATE_FIRMWARE_EXT)) { + FrSkyFirmwareInformation * information = (FrSkyFirmwareInformation *) buffer; + if (f_read(&file, buffer, sizeof(FrSkyFirmwareInformation), &count) != FR_OK || count != sizeof(FrSkyFirmwareInformation)) { + f_close(&file); + return "Format error"; + } + size = information->size; + } + else { + size = f_size(&file); + } + uint32_t done = 0; while (1) { drawProgressScreen(getBasename(filename), STR_OTA_UPDATE, done, size); From 00d2d01dfe8c1727ed3c765feb65532abaec140b Mon Sep 17 00:00:00 2001 From: 3djc Date: Fri, 14 Jun 2019 14:35:07 +0200 Subject: [PATCH 020/350] LUA virtual navigation keys (#6500) LUA virtual navigation events --- radio/sdcard/FrSky-utilities/SxR-config.lua | 18 ++++---- radio/src/lua/api_general.cpp | 51 +++++++++++++++++++++ 2 files changed, 60 insertions(+), 9 deletions(-) diff --git a/radio/sdcard/FrSky-utilities/SxR-config.lua b/radio/sdcard/FrSky-utilities/SxR-config.lua index bfced2ef3..c49b78f52 100755 --- a/radio/sdcard/FrSky-utilities/SxR-config.lua +++ b/radio/sdcard/FrSky-utilities/SxR-config.lua @@ -258,9 +258,9 @@ end -- Main local function runFieldsPage(event) - if event == EVT_EXIT_BREAK then -- exit script + if event == EVT_VIRTUAL_EXIT then -- exit script return 2 - elseif event == EVT_ENTER_BREAK or event == EVT_ROT_BREAK then -- toggle editing/selecting current field + elseif event == EVT_VIRTUAL_ENTER then -- toggle editing/selecting current field if fields[current][4] ~= nil then edit = not edit if edit == false then @@ -268,15 +268,15 @@ local function runFieldsPage(event) end end elseif edit then - if event == EVT_PLUS_FIRST or event == EVT_ROT_RIGHT or event == EVT_PLUS_REPT then + if event == EVT_VIRTUAL_NEXT or event == EVT_VIRTUAL_NEXT_REPT then addField(1) - elseif event == EVT_MINUS_FIRST or event == EVT_ROT_LEFT or event == EVT_MINUS_REPT then + elseif event == EVT_VIRTUAL_PREVIOUS or event == EVT_VIRTUAL_PREVIOUS_REPT then addField(-1) end else - if event == EVT_MINUS_FIRST or event == EVT_ROT_RIGHT then + if event == EVT_VIRTUAL_NEXT then selectField(1) - elseif event == EVT_PLUS_FIRST or event == EVT_ROT_LEFT then + elseif event == EVT_VIRTUAL_PREVIOUS then selectField(-1) end end @@ -302,7 +302,7 @@ local function runConfigPage(event) if wingBitmaps[1 + fields[1][4]] == nil then wingBitmaps[1 + fields[1][4]] = Bitmap.open(wingBitmapsFile[1 + fields[1][4]]) end - lcd.drawBitmap(wingBitmapsFile[1 + fields[1][4]], 10, 90) + lcd.drawBitmap(wingBitmaps[1 + fields[1][4]], 10, 90) else lcd.drawPixmap(20, 28, wingBitmapsFile[1 + fields[1][4]]) end @@ -346,9 +346,9 @@ local function run(event) if event == nil then error("Cannot be run as a model script!") return 2 - elseif event == EVT_PAGE_BREAK or event == EVT_PAGEDN_FIRST then + elseif event == EVT_VIRTUAL_NEXT_PAGE then selectPage(1) - elseif event == EVT_PAGE_LONG or event == EVT_PAGEUP_FIRST then + elseif event == EVT_VIRTUAL_PREVIOUS_PAGE then killEvents(event); selectPage(-1) end diff --git a/radio/src/lua/api_general.cpp b/radio/src/lua/api_general.cpp index e52aafd59..5689e5dea 100644 --- a/radio/src/lua/api_general.cpp +++ b/radio/src/lua/api_general.cpp @@ -1630,9 +1630,60 @@ const luaR_value_entry opentxConstants[] = { #else { "FIXEDWIDTH", FIXEDWIDTH }, #endif + +// Virtual Page Next/Previous +#if defined(KEYS_GPIO_REG_PGUP) && defined(KEYS_GPIO_REG_PGDN) + { "EVT_VIRTUAL_PREVIOUS_PAGE", EVT_KEY_FIRST(KEY_PGUP) }, + { "EVT_VIRTUAL_NEXT_PAGE", EVT_KEY_FIRST(KEY_PGDN) }, +#elif defined(KEYS_GPIO_REG_PGDN) + { "EVT_VIRTUAL_PREVIOUS_PAGE", EVT_KEY_LONG(KEY_PGDN) }, + { "EVT_VIRTUAL_NEXT_PAGE", EVT_KEY_BREAK(KEY_PGDN) }, +#elif defined(KEYS_GPIO_REG_UP) && defined(KEYS_GPIO_REG_DOWN) + { "EVT_VIRTUAL_PREVIOUS_PAGE", EVT_KEY_LONG(KEY_UP) }, + { "EVT_VIRTUAL_NEXT_PAGE", EVT_KEY_LONG(KEY_DOWN) }, +#endif + +// Virtual exit + { "EVT_VIRTUAL_EXIT", EVT_KEY_BREAK(KEY_EXIT) }, + +// Virtual enter +#if defined(KEYS_GPIO_REG_ENTER) + { "EVT_VIRTUAL_ENTER", EVT_KEY_BREAK(KEY_ENTER) }, + { "EVT_VIRTUAL_ENTER_LONG", EVT_KEY_LONG(KEY_ENTER) }, +#endif + +// Virtual menu +#if defined(KEYS_GPIO_REG_MENU) + { "EVT_VIRTUAL_MENU", EVT_KEY_BREAK(KEY_MENU) }, + { "EVT_VIRTUAL_MENU_LONG", EVT_KEY_LONG(KEY_MENU) }, +#elif defined(KEYS_GPIO_REG_SHIFT) + { "EVT_VIRTUAL_MENU", EVT_KEY_BREAK(KEY_SHIFT) }, + { "EVT_VIRTUAL_MENU_LONG", EVT_KEY_LONG(KEY_SHIFT) }, +#endif + +// Virtual generic plus-next-right minus-previous-left +#if defined(ROTARY_ENCODER_NAVIGATION) + { "EVT_VIRTUAL_NEXT", EVT_ROTARY_RIGHT}, + { "EVT_VIRTUAL_PREVIOUS", EVT_ROTARY_LEFT }, +#elif defined(KEYS_GPIO_REG_RIGHT) && defined(KEYS_GPIO_REG_LEFT) + { "EVT_VIRTUAL_NEXT", EVT_KEY_FIRST(KEY_RIGHT) }, + { "EVT_VIRTUAL_NEXT_REPT", EVT_KEY_REPT(KEY_RIGHT) }, + { "EVT_VIRTUAL_PREVIOUS", EVT_KEY_FIRST(KEY_LEFT) }, + { "EVT_VIRTUAL_PREVIOUS_REPT", EVT_KEY_REPT(KEY_LEFT) }, +#elif defined(KEYS_GPIO_REG_PLUS) && defined(KEYS_GPIO_REG_MINUS) + { "EVT_VIRTUAL_NEXT", EVT_KEY_FIRST(KEY_PLUS) }, + { "EVT_VIRTUAL_NEXT_REPT", EVT_KEY_REPT(KEY_PLUS) }, + { "EVT_VIRTUAL_PREVIOUS", EVT_KEY_FIRST(KEY_MINUS) }, + { "EVT_VIRTUAL_PREVIOUS_REPT", EVT_KEY_REPT(KEY_MINUS) }, +#endif + #if defined(PCBHORUS) +#if defined(KEYS_GPIO_REG_PGUP) { "EVT_PAGEUP_FIRST", EVT_KEY_FIRST(KEY_PGUP) }, +#endif { "EVT_PAGEDN_FIRST", EVT_KEY_FIRST(KEY_PGDN) }, + { "EVT_PAGEDN_BREAK", EVT_KEY_BREAK(KEY_PGDN) }, + { "EVT_PAGEDN_LONG", EVT_KEY_LONG(KEY_PGDN) }, { "EVT_TELEM_FIRST", EVT_KEY_FIRST(KEY_TELEM) }, { "EVT_MODEL_FIRST", EVT_KEY_FIRST(KEY_MODEL) }, { "EVT_SYS_FIRST", EVT_KEY_FIRST(KEY_RADIO) }, From efdeb6bbd8d569962f6683fb0ac5e7326e041043 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Fri, 14 Jun 2019 15:34:34 +0200 Subject: [PATCH 021/350] Fixes #6498 --- radio/src/gui/128x64/radio_hardware.cpp | 2 +- radio/src/gui/480x272/radio_hardware.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/radio/src/gui/128x64/radio_hardware.cpp b/radio/src/gui/128x64/radio_hardware.cpp index 61ea3414b..b76ef736e 100644 --- a/radio/src/gui/128x64/radio_hardware.cpp +++ b/radio/src/gui/128x64/radio_hardware.cpp @@ -382,7 +382,7 @@ void menuRadioHardware(event_t event) lcdDrawNumber(HW_SETTINGS_COLUMN2, y, CROSSFIRE_BAUDRATES[g_eeGeneral.telemetryBaudrate], attr|LEFT); if (attr) { g_eeGeneral.telemetryBaudrate = DIM(CROSSFIRE_BAUDRATES) - 1 - checkIncDecModel(event, DIM(CROSSFIRE_BAUDRATES) - 1 - g_eeGeneral.telemetryBaudrate, 0, DIM(CROSSFIRE_BAUDRATES) - 1); - if (checkIncDec_Ret) { + if (checkIncDec_Ret && IS_EXTERNAL_MODULE_ON()) { pauseMixerCalculations(); pausePulses(); EXTERNAL_MODULE_OFF(); diff --git a/radio/src/gui/480x272/radio_hardware.cpp b/radio/src/gui/480x272/radio_hardware.cpp index b11b500f2..dad87c588 100644 --- a/radio/src/gui/480x272/radio_hardware.cpp +++ b/radio/src/gui/480x272/radio_hardware.cpp @@ -187,7 +187,7 @@ bool menuRadioHardware(event_t event) lcdDrawNumber(HW_SETTINGS_COLUMN+50, y, CROSSFIRE_BAUDRATES[g_eeGeneral.telemetryBaudrate], attr|LEFT); if (attr) { g_eeGeneral.telemetryBaudrate = DIM(CROSSFIRE_BAUDRATES) - 1 - checkIncDecModel(event, DIM(CROSSFIRE_BAUDRATES) - 1 - g_eeGeneral.telemetryBaudrate, 0, DIM(CROSSFIRE_BAUDRATES) - 1); - if (checkIncDec_Ret) { + if (checkIncDec_Ret && IS_EXTERNAL_MODULE_ON()) { pauseMixerCalculations(); pausePulses(); EXTERNAL_MODULE_OFF(); From 80960fb63e876a69ea15730fdead2679fc6313e7 Mon Sep 17 00:00:00 2001 From: 3djc Date: Fri, 14 Jun 2019 17:27:26 +0200 Subject: [PATCH 022/350] Fix missing virtual on world best radio (and a few others) --- radio/src/lua/api_general.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/radio/src/lua/api_general.cpp b/radio/src/lua/api_general.cpp index 5689e5dea..8aefc3068 100644 --- a/radio/src/lua/api_general.cpp +++ b/radio/src/lua/api_general.cpp @@ -1641,6 +1641,9 @@ const luaR_value_entry opentxConstants[] = { #elif defined(KEYS_GPIO_REG_UP) && defined(KEYS_GPIO_REG_DOWN) { "EVT_VIRTUAL_PREVIOUS_PAGE", EVT_KEY_LONG(KEY_UP) }, { "EVT_VIRTUAL_NEXT_PAGE", EVT_KEY_LONG(KEY_DOWN) }, +#elif defined(KEYS_GPIO_REG_PAGE) + { "EVT_VIRTUAL_PREVIOUS_PAGE", EVT_KEY_LONG(KEY_PAGE) }, + { "EVT_VIRTUAL_NEXT_PAGE", EVT_KEY_BREAK(KEY_PAGE) }, #endif // Virtual exit From 599b759e59f84c2cbb7a813dde04ff9d34352a70 Mon Sep 17 00:00:00 2001 From: 3djc Date: Fri, 14 Jun 2019 17:39:02 +0200 Subject: [PATCH 023/350] Ressources for multi radio SxR --- radio/sdcard/FrSky-utilities/bmp/back.bmp | Bin 0 -> 1144 bytes radio/sdcard/FrSky-utilities/bmp/delta.bmp | Bin 0 -> 1144 bytes radio/sdcard/FrSky-utilities/bmp/done.bmp | Bin 0 -> 1142 bytes radio/sdcard/FrSky-utilities/bmp/down.bmp | Bin 0 -> 1144 bytes radio/sdcard/FrSky-utilities/bmp/forward.bmp | Bin 0 -> 1144 bytes radio/sdcard/FrSky-utilities/bmp/horz-r.bmp | Bin 0 -> 1144 bytes radio/sdcard/FrSky-utilities/bmp/horz.bmp | Bin 0 -> 1144 bytes radio/sdcard/FrSky-utilities/bmp/left.bmp | Bin 0 -> 1144 bytes radio/sdcard/FrSky-utilities/bmp/plane.bmp | Bin 0 -> 1144 bytes radio/sdcard/FrSky-utilities/bmp/right.bmp | Bin 0 -> 1144 bytes radio/sdcard/FrSky-utilities/bmp/up.bmp | Bin 0 -> 1144 bytes radio/sdcard/FrSky-utilities/bmp/vert-r.bmp | Bin 0 -> 1144 bytes radio/sdcard/FrSky-utilities/bmp/vert.bmp | Bin 0 -> 1144 bytes radio/sdcard/FrSky-utilities/bmp/vtail.bmp | Bin 0 -> 1144 bytes radio/sdcard/FrSky-utilities/img/back.png | Bin 0 -> 9229 bytes radio/sdcard/FrSky-utilities/img/delta_b.png | Bin 0 -> 9102 bytes radio/sdcard/FrSky-utilities/img/done.bmp | Bin 0 -> 1142 bytes radio/sdcard/FrSky-utilities/img/down.png | Bin 0 -> 7866 bytes radio/sdcard/FrSky-utilities/img/forward.png | Bin 0 -> 10493 bytes radio/sdcard/FrSky-utilities/img/left.png | Bin 0 -> 11410 bytes radio/sdcard/FrSky-utilities/img/plane_b.png | Bin 0 -> 12743 bytes radio/sdcard/FrSky-utilities/img/planev_b.png | Bin 0 -> 13467 bytes radio/sdcard/FrSky-utilities/img/planev_s.png | Bin 0 -> 4393 bytes radio/sdcard/FrSky-utilities/img/right.png | Bin 0 -> 10388 bytes radio/sdcard/FrSky-utilities/img/up.png | Bin 0 -> 10799 bytes radio/sdcard/FrSky-utilities/img/vert-r.png | Bin 0 -> 6813 bytes radio/sdcard/FrSky-utilities/img/vert.png | Bin 0 -> 10493 bytes 27 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 radio/sdcard/FrSky-utilities/bmp/back.bmp create mode 100644 radio/sdcard/FrSky-utilities/bmp/delta.bmp create mode 100644 radio/sdcard/FrSky-utilities/bmp/done.bmp create mode 100644 radio/sdcard/FrSky-utilities/bmp/down.bmp create mode 100644 radio/sdcard/FrSky-utilities/bmp/forward.bmp create mode 100644 radio/sdcard/FrSky-utilities/bmp/horz-r.bmp create mode 100644 radio/sdcard/FrSky-utilities/bmp/horz.bmp create mode 100644 radio/sdcard/FrSky-utilities/bmp/left.bmp create mode 100644 radio/sdcard/FrSky-utilities/bmp/plane.bmp create mode 100644 radio/sdcard/FrSky-utilities/bmp/right.bmp create mode 100644 radio/sdcard/FrSky-utilities/bmp/up.bmp create mode 100644 radio/sdcard/FrSky-utilities/bmp/vert-r.bmp create mode 100644 radio/sdcard/FrSky-utilities/bmp/vert.bmp create mode 100644 radio/sdcard/FrSky-utilities/bmp/vtail.bmp create mode 100755 radio/sdcard/FrSky-utilities/img/back.png create mode 100755 radio/sdcard/FrSky-utilities/img/delta_b.png create mode 100755 radio/sdcard/FrSky-utilities/img/done.bmp create mode 100755 radio/sdcard/FrSky-utilities/img/down.png create mode 100755 radio/sdcard/FrSky-utilities/img/forward.png create mode 100755 radio/sdcard/FrSky-utilities/img/left.png create mode 100755 radio/sdcard/FrSky-utilities/img/plane_b.png create mode 100755 radio/sdcard/FrSky-utilities/img/planev_b.png create mode 100755 radio/sdcard/FrSky-utilities/img/planev_s.png create mode 100755 radio/sdcard/FrSky-utilities/img/right.png create mode 100755 radio/sdcard/FrSky-utilities/img/up.png create mode 100755 radio/sdcard/FrSky-utilities/img/vert-r.png create mode 100755 radio/sdcard/FrSky-utilities/img/vert.png diff --git a/radio/sdcard/FrSky-utilities/bmp/back.bmp b/radio/sdcard/FrSky-utilities/bmp/back.bmp new file mode 100644 index 0000000000000000000000000000000000000000..a8996262cc5c08c72c6480256d291629f3df247c GIT binary patch literal 1144 zcmb7@&ubG=5XZms2ntr|&Wi+3vb*shC|I+4c3V^Mq9xMoQ4585Qv_{_iu9lo`XA&U zD3X(c_L57*i-+KkKOm^>QAs1H6br`LecL44-5wm6eY^9S@9fOJeKS{=bBJt7uBXL) zaa){VfRaT|7?<$Sm>I6?!t*?o%VkunRn%%V)a!LL8Vxj?O|)7qwA*cTIvsSoUG#cA z3)C7ml*zOpdorruSJ!PEdgXwD z+gq}sl_dWHAymTg?G@TQm#)8|Xa?wRPSRK8zo+?&Fmx7gL0i=G(|m<+8ONNBqo04} z-aO9W8V(Ns{Wysqbn|Bh59hn2K23ak89|y(_P?ODgOe(3BVQz$Z{PerU`do%(xB7z zea=lmg}*VluqJ%Jo~5X<=U3*_^=(oXRM9zQW9`vml$iMbmKJ?(DY&tKc11c7OL8a) z1zO%O4MvvaTrjE_5<5vA$HRrSE9cO2$M-+R%x=U=a#$|}4@dup1rk;abtPG5Z>_!` hLAm=qA0kiG<>0}G1d1Pa@0Gk@^?);%CD@Ar{{Ua2F!TTb literal 0 HcmV?d00001 diff --git a/radio/sdcard/FrSky-utilities/bmp/delta.bmp b/radio/sdcard/FrSky-utilities/bmp/delta.bmp new file mode 100644 index 0000000000000000000000000000000000000000..ab94279c1eb7e803df6d341783f27763b4ab816e GIT binary patch literal 1144 zcmdr~J8Hu~5PdQRfl{pOCXmL9t8^}W0bvZOf-7IawW>IsTVKJQ0=295hw@9z-VXoz4>Wp@%}l4lMng6iYB63G(ZCksSnZfbICX}op<;M@a0&-AZ+lESc ztmJjP27$Mr2#*eAf)_CgZvdz|GEq}6McB|P>9`SLrXe#mAiv;u-NLc`TiO6Z>53$8 zO4Sj|dv1>dRY|uZDN>nv=0VnkDzKBYvTbSAT{>Y=gZRZJ!Nh7r|@$z*{Ba~I=&UXb5e7|cO8rwmym@w|e9FYAP J{&%dPz&Ex;fJy)W literal 0 HcmV?d00001 diff --git a/radio/sdcard/FrSky-utilities/bmp/done.bmp b/radio/sdcard/FrSky-utilities/bmp/done.bmp new file mode 100644 index 0000000000000000000000000000000000000000..9ac50139804db9e8f54d93f80c363d2a8b9f92dd GIT binary patch literal 1142 zcmZvaPe>a<6vn@G{gWD#YHtPvZ}Ct;3?au#@X!VVHue%ESdf}t1W%HSkV7SU5EO+V zlv3J5a}eq+m-e1Zz}iO5+K0Wgg-}5~3U>Quva2&w2j0xi_xs+PH@llmFLgqWC7wq( zCOC#UEO>yIqfk5gSr@~yER;$m)M_=PQYlm_6|`C{M59sU^La!f5tPeiG@DIivsqND zRk*H;L?VGgp#U;Q=1DSVNXpjv%SU!!DvI~m*aFtb*^@nC{6E8E0Y*347`QeJjs%lF zhMm(52MAsaY(Kr>SkU|P*3RHSo$;e&M%)oA8b3zh<@|j7 zIbPAj2Qck zxb8a%z3EKlO(`xE6~ns985C)U2RYRv*^@u1(2XbRyYz}_ta@fpF>dj1A1{)ip&X!aQIm*@xjriAQ| z9zC6Zu#UGr6Kj{wxg|Y+Nax>xUU@CAhOJ}b`s*Z{Ya3n|ocmiQc`wPsIg`)+W~tw+ fZoVAf?06^q@da}|C~$?qCsS7TyPK~^l`Z`PirX(` literal 0 HcmV?d00001 diff --git a/radio/sdcard/FrSky-utilities/bmp/down.bmp b/radio/sdcard/FrSky-utilities/bmp/down.bmp new file mode 100644 index 0000000000000000000000000000000000000000..97f9105ac5c1222e7eea179b0d412fa416b07671 GIT binary patch literal 1144 zcmb7?JxIeq6vy9H1;HhE5nP)~1;NGK1sq&T4O9ogq8%N&ba8XA4ld$SP!OR@M+cYA zbt+gK+=@;r9ZCoH?taG0S96!Pq7Pmk?|%RPyLXV>*3mThaVWk^BC{gXA`t{2B?_4f zQXCHhV+@p1;GBcwI8ZDWpom9U6@Wv|26bbUM)M^L*fzdg$QH9Db+Ai26QcNu^@<@GYq85{3T*uCA&5=ESWcDjFG*=xlUvM ztAeSP%B*wQeIo30X6(O=xM%jm0wV1nauQKd zEtrq}C%!+N9g2)p%u9m%i%A3cg2GiZXLPe4^X;UWX3k>jx(PEk^KBWsPx8H-n#T$i z&3!CjboC*LB>^+fN2xfu@h334aXS{f?zIrGMP+SOSu@T2qk5!vwSBe!QwQ(^fYqPC literal 0 HcmV?d00001 diff --git a/radio/sdcard/FrSky-utilities/bmp/forward.bmp b/radio/sdcard/FrSky-utilities/bmp/forward.bmp new file mode 100644 index 0000000000000000000000000000000000000000..df769aef2dec6178a757f0bddd9017e1de3779b3 GIT binary patch literal 1144 zcmb7@PiqrF7{;I34Xyv6GaGt{m+nq_5HD`B0ig(P>e`%yKuj+lOwmM&mx44atzZwK zrWHgAfh2n9No)K9%2vNX`w4`I2Tva2QAEr7Zc@#pD&ot|&hGr?edgKsWoNJ4jiDb^ zx}Txp(lBW-41h+HadI$d`Bw-bAf<%kIPg3V#bObaN(H{}qh7D0)oP*B=^zLK?CmdxoX#8g!)MRG$uQ>+|lYFuG?LY4Lc85oV2#%>E{L{@o z)w5}u>AE<=50!!O1ryNbZn!G{T8MJB@^YjN#>ZZk^XHWOC0Z}yLGz)FxRvH2=8o#q zYiMW8%cSs;la!IBU1)3~Hxl%|gUYFg4!>+u;z- zbRIKqiu&z07p4?{Heef>Y}%yebE;ipr);Y{X~U2lx>h3pmpEq}ntDDl1IIs}9p8p; zX6gIa{gRq*Vk{_aZeCc-N0nt_vgnyACx4l(S1(RKeT=vyG3uYC>XX0K(%bEc#0Tc{ z6nNr!J+J1Q&>OraPVKFMI?MQE!D1>;@>s)t^ySzVm^4z6g-lA-mz-^^=}`gos^yaZ z=288KO~+?SOi(h{so<(URm3S|f|YAjpBy>Ru6iT-oNLeSrI#%_Iajd+bl)HGPoAHU z@L{lM79;xf{XZ$4PmheNJX#p?!P7)Ij3E=kkd90XX0K_)&-)wg-QD*+ Vg@)m4`o$^Q!JF>q5%A9!;0MPpL6ZOg literal 0 HcmV?d00001 diff --git a/radio/sdcard/FrSky-utilities/bmp/horz-r.bmp b/radio/sdcard/FrSky-utilities/bmp/horz-r.bmp new file mode 100644 index 0000000000000000000000000000000000000000..93ffdb0fc51acc1dbeb78a52066a3a1f4e2cf7f5 GIT binary patch literal 1144 zcmaiyyNeT16vod)!NS6vyTw{8Z03dqaSL^BP^@;15o|cx9yRA|! z=vFE0vH&wXU>%o6dyxsUVvzH{$9>Ng%A2NREYJj1!k zS>X)8f)Y>Sq)jeofrucb1f>)-8VzVRo6u^tpxtgmr_+IMw+p>q5BmK+3QM#23XH6=s$+O_Ju$B3d*s$Nx5Y0jtgr+`&d zURtZO-v)oYB*!KHDJ-Z(!t>u57gfeAfUr9Evn=DnP$Ll1`FV<+U-xzq!Ms27L-X*i zw-a0lyx;Jww-c;+{)_$gV)OP&-5q-VGbr{}QSGUxMBk3|me+G;7AALmUtZN-x_ffxhHj{lrJyBuyh;q302@Be4cC7hk#q)5dzo@ERNqljTq2oiW5X2OAV9JySM zN~IE2t5vGiYE-Y+snKXqtJR`zw@bZVkNW*S4F&@m4u>=vjmYynVrCit#{?4JH+2sQ zW7a1d93zf<|HO(j_H;~x888Pg9pBJAMaW_awf`#O&6DK`ZBlJV0) z;JM8CLd4r*Rv{gpvBLoC|2WmWts!2PN};gJi(ElX0%wVJ2jt%r!($Z_U8rN3`O{Fa zj&Uw>Y(dsmJgAt(L^JFs48#8&`Psj4G*3S1_2V@aoqqYdc_1ks@5WkZZvrK-Z0ok^gt-B4Z1@^dHq||r|W{$SF aSzF6P!M563FvGgH*Vcmf{MOF9lSIGNK!Ys+ literal 0 HcmV?d00001 diff --git a/radio/sdcard/FrSky-utilities/bmp/left.bmp b/radio/sdcard/FrSky-utilities/bmp/left.bmp new file mode 100644 index 0000000000000000000000000000000000000000..8cc811fd1ea6133c8ed563542cc7d476145762f8 GIT binary patch literal 1144 zcma*mze~eF6bJC{*^0l-B^4Z#Ml0e{Y_8BvsV8(1ry{xtTDleyS~u5j9VLVRK%jqs z6r3FUC)m-^E?QdzIbU0F@k1KqE63k%6&?YQeX-*^m3M_Ny|TB z+ctdPM-T+iTBBSpqgt(^(P*IAY$6OpL{WrJr-N>{i(apXe!mZ6%sBrYU;aruuK101 zlsbK6ORlAG=woV3!Kacmz=p;6P>&sO86W-OLoF&vDY44*4|U?jHP#jHsASLGC*Ebr za?QgEJ74DEiS{z@$QonEc>eg-0_P(o&-Pj-v&hX?at%Th7I@Dja_RLL-=zI*&GY>` z*_tTL@t(8>CeQiDh~P~x(<8;qWoCT literal 0 HcmV?d00001 diff --git a/radio/sdcard/FrSky-utilities/bmp/plane.bmp b/radio/sdcard/FrSky-utilities/bmp/plane.bmp new file mode 100644 index 0000000000000000000000000000000000000000..b3e61bf5f9e5ac0120d7c96d50f99d7b1a266919 GIT binary patch literal 1144 zcmah|yKWOv5IxsU8ccH6G$f+%$`yjbmiz&UkXs}-t|JV6yeb$^> zKGmA+C4Wkel0>y)-uyv}>D;cmtNF&1n_fIjbzl}#klL=>RF*Vy4Z$AW=m8oIUpt&L zymx?n4}W`*d7XDQMJ@6fjm-0Dpw2xe<_dKesG8$LoD{6_zF@}~%nd(4#{^Y*fdl41 z4*S_S+hl+zAPwJde~?OI7lgf5<{C=6{ z@Y9hDjuAiUx9{b%E|m1RRq)xJciQYTX91qN`qX;9v}Cd_>O^0GqY_wk--7B<6{XVu-;qH+wNI zGd&+tN;r-Kr4&5RL!;3^5CjOr5Z!JUyX;9z$zAtNEDL+7I)W zgojTdn0qlwka+4)lxzuWlUVSrMA5cOGE4Y}68mLG<|&^jA>EBiIYZ=)gXL-}&CO<( ztd#t0Pg6X{r0GECn}sj!u=nHz=KBJh`x_XM-r`#4@It%A9G7yle=U|rImHjS=DT=I z?r-wool7^>wYG6b=FgkMs|^FCNhb7FXBaH?>}+2fV`s$j>P;CH=#6KZEO7#6r1JsB=1wb2^+@K zceihSrTOUq7xsfVe$h9@f>+R9ygk}=jul9;7DIaYxkzKTSLU4dqm8U}rhwc|5(htM zE~S+J^88x+&CL_Q#r+W+cx8p=K0g0!c}c85Ss$hJ_NSaB!Kv$a=5*vfj^R*1{K)sU phd6hTf`g#13m{|gaqpqLuXA7~&3h>L%_eyd1>YW|cAmZn`~@N!+Gzj) literal 0 HcmV?d00001 diff --git a/radio/sdcard/FrSky-utilities/bmp/vert-r.bmp b/radio/sdcard/FrSky-utilities/bmp/vert-r.bmp new file mode 100644 index 0000000000000000000000000000000000000000..763409ec4d18814b643b8cc9b48e2a093ec9b389 GIT binary patch literal 1144 zcmaizJ4*vW5XUDXSXg+QMhii2V?B|kEmH_5R%z7JO00~20P$L}kV|h9 zEVL4d_z5CL5QIn`f{!BJID40P#~LmJv%BnX=RdQrh2`CTaBYX$N%A@JaqP<3KmL@xfvcYtS@BskGEbya^Ga46%V+bW3*Sg_=5a?I>%xJl zRDVOU%(u?sR|B~{@=(1qe*OxgxX*G<;bkYxr7wN)yFZ~GDLiIt?|CaU#^nio; z|8enur~Um)JjxW}f%E+)J+dhMbgt>EhPiiS7wUezV_T<(=AKn3l=^i71U+;(r A;{X5v literal 0 HcmV?d00001 diff --git a/radio/sdcard/FrSky-utilities/bmp/vert.bmp b/radio/sdcard/FrSky-utilities/bmp/vert.bmp new file mode 100644 index 0000000000000000000000000000000000000000..5f1b91f05e2f270239956b286839851b3f3994a9 GIT binary patch literal 1144 zcmaizO=uHA6vzM5R6U3|vnm!WWV4%sU)Z%955+@6x={qb2#sEg#ai@W>7i*o*@BwZ zOZ_M`dJ(B26%hob5D!-HAVfWTh!{ceAnB&4cxW=d*<^L&L0|S|cIW@zZ|1$(O&l3( zg=eGmznwfzu9Gv=g%%pL^>wG|-zJ2BVHmJ&8;;{3olawLa1fbH2H9*Dxm*ql3k%5S z^C%PwC>Dz-m&=e+D*wN&P>AaW;%cu``^Mk;6L}sceWU*tu)m#_K)KVU#$=ya?}2a`)1s)>qAomG4%VfZ?2 zPtE{)=fgd=1VX83MB)F|d)!W`QU1_?8Mw zE_G~5L{*hW6Mw|Q`4twYb#Z9Kr2J%z`uoR*m4X&)%TpMtKP)1e_`@8VosOfk*;hbx zmiU_4#J|XK?(CE96e*#ho78{J^xhAD1p{q4KQzzWa2lh~nzR?z#Xz`P2><3zD zve^Rq@qj{PopZ+41oXJ4GocxV9ZP1WZa*v(y^o?1^L}n>j=uI=`R8vwlmmJHz6E{( D3imG- literal 0 HcmV?d00001 diff --git a/radio/sdcard/FrSky-utilities/bmp/vtail.bmp b/radio/sdcard/FrSky-utilities/bmp/vtail.bmp new file mode 100644 index 0000000000000000000000000000000000000000..6c7ec0b569b33a300a6d8f7efa5b591fa9b05d21 GIT binary patch literal 1144 zcmb_aJA@uy>?^oV}H|34c0t5bi{Lo&yZ)ZFnBg-;O zCKJqNGb|PhESF2H*K2IITkLi_?Du;dk4KzNC!Eh`TrL-gh`-%2uCx2B|A`mKeTuiy zU8100rEG0fzIdc4fPpgkAU^e7f0lY9?%;7p=QN=&beZzImls^o_!;kQ5r>If^Htm}02%A{7q7()wE4qHC+d;7SPnm7PbC zKL}#*>!=ZRiXn2<>Je`emfmv;eBw5fs-0>NK@#Lhbl-NagV_aaz-Te;UyP_gXQ!2)P~`WA9FR7 uG=GN0eb-R$XZYQ>6PVz7ix8F^>URPqr*oZ3{eHqM?QW{R-hZAANAee;+B%#7 literal 0 HcmV?d00001 diff --git a/radio/sdcard/FrSky-utilities/img/back.png b/radio/sdcard/FrSky-utilities/img/back.png new file mode 100755 index 0000000000000000000000000000000000000000..2cf3cd699030fd58a55cabcece2ae28eb23644d6 GIT binary patch literal 9229 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 literal 0 HcmV?d00001 diff --git a/radio/sdcard/FrSky-utilities/img/down.png b/radio/sdcard/FrSky-utilities/img/down.png new file mode 100755 index 0000000000000000000000000000000000000000..8eac8039afe27f1fa89c9020fd63dd013c6f66ed GIT binary patch literal 7866 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 Dg)Soz literal 0 HcmV?d00001 diff --git a/radio/sdcard/FrSky-utilities/img/forward.png b/radio/sdcard/FrSky-utilities/img/forward.png new file mode 100755 index 0000000000000000000000000000000000000000..de09680b7b01e4a2eef81bc3ae3a87a72d37bf39 GIT binary patch literal 10493 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 MO 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 literal 0 HcmV?d00001 diff --git a/radio/sdcard/FrSky-utilities/img/plane_b.png b/radio/sdcard/FrSky-utilities/img/plane_b.png new file mode 100755 index 0000000000000000000000000000000000000000..37abedc3ab047a26097ab9d80680f6188917e997 GIT binary patch literal 12743 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 KRVb4;4gOz9EewSK literal 0 HcmV?d00001 diff --git a/radio/sdcard/FrSky-utilities/img/planev_b.png b/radio/sdcard/FrSky-utilities/img/planev_b.png new file mode 100755 index 0000000000000000000000000000000000000000..4e33f660bee8f51b7a95275e27aba3d22697b474 GIT binary patch literal 13467 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 Y7FS@_-R&vhAQ4DeUL9G9un75o00R|QvH$=8 literal 0 HcmV?d00001 diff --git a/radio/sdcard/FrSky-utilities/img/planev_s.png b/radio/sdcard/FrSky-utilities/img/planev_s.png new file mode 100755 index 0000000000000000000000000000000000000000..48283a2903fe901c880ecef52d8994c35a13587e GIT binary patch literal 4393 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 literal 0 HcmV?d00001 diff --git a/radio/sdcard/FrSky-utilities/img/right.png b/radio/sdcard/FrSky-utilities/img/right.png new file mode 100755 index 0000000000000000000000000000000000000000..01d555394a4d145dda3222a0a8afef08ced25b75 GIT binary patch literal 10388 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 AcmMzZ literal 0 HcmV?d00001 diff --git a/radio/sdcard/FrSky-utilities/img/up.png b/radio/sdcard/FrSky-utilities/img/up.png new file mode 100755 index 0000000000000000000000000000000000000000..f033aba553f80ce27f76ba5c1dcb6d8783367820 GIT binary patch literal 10799 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 iEB}4L|9|H%ckJBCPo|)(nS9t$53Y6Cf53D1 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 MO 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 Date: Fri, 14 Jun 2019 18:06:54 +0200 Subject: [PATCH 024/350] More scripts converted to virtuals --- radio/sdcard/FrSky-utilities/FrSky SBEC.lua | 12 ++++++------ radio/sdcard/FrSky-utilities/GasSuit-config.lua | 16 ++++++++-------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/radio/sdcard/FrSky-utilities/FrSky SBEC.lua b/radio/sdcard/FrSky-utilities/FrSky SBEC.lua index e09e97e69..7bf997f48 100644 --- a/radio/sdcard/FrSky-utilities/FrSky SBEC.lua +++ b/radio/sdcard/FrSky-utilities/FrSky SBEC.lua @@ -211,10 +211,10 @@ end -- Main1 local function runFieldsPage(event) - if event == EVT_EXIT_BREAK then + if event == EVT_VIRTUAL_EXIT then telemetryUnIdle(0x80) return 2 - elseif event == EVT_ENTER_BREAK or event == EVT_ROT_BREAK then + elseif event == EVT_VIRTUAL_ENTER then if fields[current][4] ~= nil then edit = not edit if edit == false then @@ -222,15 +222,15 @@ local function runFieldsPage(event) end end elseif edit then - if event == EVT_PLUS_FIRST or event == EVT_ROT_RIGHT or event == EVT_PLUS_REPT or event == EVT_RIGHT_FIRST then + if event == EVT_VIRTUAL_NEXT or event == EVT_VIRTUAL_NEXT_REPT then addField(1) - elseif event == EVT_MINUS_FIRST or event == EVT_ROT_LEFT or event == EVT_MINUS_REPT or event == EVT_LEFT_FIRST then + elseif event == EVT_VIRTUAL_PREVIOUS or event == EVT_VIRTUAL_PREVIOUS_REPT then addField(-1) end else - if event == EVT_MINUS_FIRST or event == EVT_ROT_RIGHT or event == EVT_DOWN_FIRST then + if event == EVT_VIRTUAL_NEXT then selectField(1) - elseif event == EVT_PLUS_FIRST or event == EVT_ROT_LEFT or event == EVT_UP_FIRST then + elseif event == EVT_VIRTUAL_PREVIOUS then selectField(-1) end end diff --git a/radio/sdcard/FrSky-utilities/GasSuit-config.lua b/radio/sdcard/FrSky-utilities/GasSuit-config.lua index 9fb219667..df7fce8ce 100755 --- a/radio/sdcard/FrSky-utilities/GasSuit-config.lua +++ b/radio/sdcard/FrSky-utilities/GasSuit-config.lua @@ -322,9 +322,9 @@ end -- Main1 local function runFieldsPage(event) - if event == EVT_EXIT_BREAK then + if event == EVT_VIRTUAL_EXIT then return 2 - elseif event == EVT_ENTER_BREAK or event == EVT_ROT_BREAK then + elseif event == EVT_VIRTUAL_ENTER then if fields[current][4] ~= nil then edit = not edit if edit == false then @@ -332,15 +332,15 @@ local function runFieldsPage(event) end end elseif edit then - if event == EVT_PLUS_FIRST or event == EVT_ROT_RIGHT or event == EVT_PLUS_REPT or event == EVT_RIGHT_FIRST then + if event == EVT_VIRTUAL_NEXT or event == EVT_VIRTUAL_NEXT_REPT then addField(1) - elseif event == EVT_MINUS_FIRST or event == EVT_ROT_LEFT or event == EVT_MINUS_REPT or event == EVT_LEFT_FIRST then + elseif event == EVT_VIRTUAL_PREVIOUS or event == EVT_VIRTUAL_PREVIOUS_REPT then addField(-1) end else - if event == EVT_MINUS_FIRST or event == EVT_ROT_RIGHT or event == EVT_DOWN_FIRST then + if event == EVT_VIRTUAL_NEXT then selectField(1) - elseif event == EVT_PLUS_FIRST or event == EVT_ROT_LEFT or event == EVT_UP_FIRST then + elseif event == EVT_VIRTUAL_PREVIOUS then selectField(-1) end end @@ -498,9 +498,9 @@ local function run(event) if event == nil then error("Cannot be run as a sensor script!") return 2 - elseif event == EVT_PAGE_BREAK or event == EVT_PAGEDN_FIRST or event == EVT_SHIFT_BREAK then + elseif event == EVT_VIRTUAL_NEXT_PAGE then selectPage(1) - elseif event == EVT_PAGE_LONG or event == EVT_PAGEUP_FIRST or event == EVT_SHIFT_LONG then + elseif event == EVT_VIRTUAL_PREVIOUS_PAGE then killEvents(event); selectPage(-1) end From 618bcfe72fdfc5196e6b822bf21d028fe15aaa56 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Fri, 14 Jun 2019 18:25:49 +0200 Subject: [PATCH 025/350] Compilation fix --- radio/src/gui/common/stdlcd/radio_tools.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/radio/src/gui/common/stdlcd/radio_tools.cpp b/radio/src/gui/common/stdlcd/radio_tools.cpp index 4e21add61..5f54b4d93 100644 --- a/radio/src/gui/common/stdlcd/radio_tools.cpp +++ b/radio/src/gui/common/stdlcd/radio_tools.cpp @@ -48,6 +48,7 @@ void addRadioModuleTool(uint8_t index, const char * label, void (* tool)(event_t #define TOOL_NAME_MAXLEN 16 +#if defined(LUA) bool readToolName(const char * filename, char * name) { FIL file; @@ -112,6 +113,7 @@ bool isRadioScriptTool(const char * filename) const char * ext = getFileExtension(filename); return ext && !strcasecmp(ext, SCRIPT_EXT); } +#endif void menuRadioTools(event_t event) { @@ -144,6 +146,7 @@ void menuRadioTools(event_t event) addRadioModuleTool(index++, STR_POWER_METER_EXT, menuRadioPowerMeter, EXTERNAL_MODULE); #endif +#if defined(LUA) FILINFO fno; DIR dir; @@ -160,6 +163,7 @@ void menuRadioTools(event_t event) addRadioScriptTool(index++, fno.fname); } } +#endif if (index == 0) { lcdDrawCenteredText(LCD_H/2, STR_NO_TOOLS); From 55ec942610b3e6caffae87e72fa9aad78a3909a4 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Fri, 14 Jun 2019 19:19:52 +0200 Subject: [PATCH 026/350] Bsongis/rotary encoder delay (#6503) Rotary encoder fixed on X10 / X12S --- radio/src/audio.h | 2 - radio/src/debounce.h | 55 +++++++++++++ radio/src/opentx.h | 3 +- .../common/arm/stm32/bootloader/boot.cpp | 2 +- .../arm/stm32/rotary_encoder_driver.cpp | 38 +++++++-- .../common/arm/stm32/timers_driver.cpp | 79 +++++++++++++++++++ .../targets/common/arm/stm32/usb_driver.cpp | 19 +---- radio/src/targets/horus/CMakeLists.txt | 1 + radio/src/targets/horus/board.cpp | 59 +------------- radio/src/targets/horus/board.h | 4 + radio/src/targets/horus/hal.h | 4 + radio/src/targets/sky9x/board.cpp | 1 - radio/src/targets/taranis/CMakeLists.txt | 1 + radio/src/targets/taranis/board.cpp | 61 +------------- radio/src/targets/taranis/board.h | 4 + radio/src/targets/taranis/hal.h | 8 ++ 16 files changed, 195 insertions(+), 146 deletions(-) create mode 100644 radio/src/debounce.h create mode 100644 radio/src/targets/common/arm/stm32/timers_driver.cpp diff --git a/radio/src/audio.h b/radio/src/audio.h index 3dbfc5911..ac356863a 100644 --- a/radio/src/audio.h +++ b/radio/src/audio.h @@ -588,8 +588,6 @@ void audioTimerCountdown(uint8_t timer, int value); #define AUDIO_TRAINER_LOST() audioEvent(AU_TRAINER_LOST) #define AUDIO_TRAINER_BACK() audioEvent(AU_TRAINER_BACK) -#define AUDIO_HEARTBEAT() - enum AutomaticPromptsCategories { SYSTEM_AUDIO_CATEGORY, MODEL_AUDIO_CATEGORY, diff --git a/radio/src/debounce.h b/radio/src/debounce.h new file mode 100644 index 000000000..f7b1559bc --- /dev/null +++ b/radio/src/debounce.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) OpenTX + * + * Based on code named + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _DEBOUNCE_H_ +#define _DEBOUNCE_H_ + +#include "board.h" + +template +class Debounce +{ + public: + T debounce(T state) + { + if (state == lastState) + debouncedState = state; + else + lastState = state; + return debouncedState; + } + + private: + T lastState; + T debouncedState; +}; + +#if defined(STM32) +class PinDebounce: public Debounce +{ + public: + uint8_t debounce(GPIO_TypeDef * GPIOx, uint16_t GPIO_Pin) + { + return Debounce::debounce(GPIO_ReadInputDataBit(GPIOx, GPIO_Pin)); + } +}; +#endif + +#endif // _DEBOUNCE_H_ diff --git a/radio/src/opentx.h b/radio/src/opentx.h index 6ca4173cc..918cb6822 100644 --- a/radio/src/opentx.h +++ b/radio/src/opentx.h @@ -28,6 +28,7 @@ #include #include "definitions.h" #include "opentx_types.h" +#include "debounce.h" #if defined(STM32) #include "usbd_conf.h" @@ -542,8 +543,6 @@ bool setTrimValue(uint8_t phase, uint8_t idx, int trim); #if defined(PCBSKY9X) #define ROTARY_ENCODER_GRANULARITY (2 << g_eeGeneral.rotarySteps) -#elif defined(PCBHORUS) - #define ROTARY_ENCODER_GRANULARITY (1) #else #define ROTARY_ENCODER_GRANULARITY (2) #endif diff --git a/radio/src/targets/common/arm/stm32/bootloader/boot.cpp b/radio/src/targets/common/arm/stm32/bootloader/boot.cpp index 0663ef223..f1421abef 100644 --- a/radio/src/targets/common/arm/stm32/bootloader/boot.cpp +++ b/radio/src/targets/common/arm/stm32/bootloader/boot.cpp @@ -201,7 +201,7 @@ int main() AUX_SERIAL_RCC_AHB1Periph | I2C_RCC_AHB1Periph | SD_RCC_AHB1Periph, ENABLE); - RCC_APB1PeriphClockCmd(LCD_RCC_APB1Periph | BACKLIGHT_RCC_APB1Periph | + RCC_APB1PeriphClockCmd(ROTARY_ENCODER_RCC_APB1Periph | LCD_RCC_APB1Periph | BACKLIGHT_RCC_APB1Periph | INTERRUPT_xMS_RCC_APB1Periph | I2C_RCC_APB1Periph | AUX_SERIAL_RCC_APB1Periph | SD_RCC_APB1Periph, ENABLE); diff --git a/radio/src/targets/common/arm/stm32/rotary_encoder_driver.cpp b/radio/src/targets/common/arm/stm32/rotary_encoder_driver.cpp index ea94cdaaf..b8d06a03a 100644 --- a/radio/src/targets/common/arm/stm32/rotary_encoder_driver.cpp +++ b/radio/src/targets/common/arm/stm32/rotary_encoder_driver.cpp @@ -20,7 +20,7 @@ #include "opentx.h" -uint32_t rotencPosition; +uint8_t rotencPosition; void rotaryEncoderInit() { @@ -56,19 +56,29 @@ void rotaryEncoderInit() #endif rotencPosition = ROTARY_ENCODER_POSITION(); + + ROTARY_ENCODER_TIMER->ARR = 99; // 100uS + ROTARY_ENCODER_TIMER->PSC = (PERI1_FREQUENCY * TIMER_MULT_APB1) / 1000000 - 1; // 1uS + ROTARY_ENCODER_TIMER->CCER = 0; + ROTARY_ENCODER_TIMER->CCMR1 = 0; + ROTARY_ENCODER_TIMER->EGR = 0; + ROTARY_ENCODER_TIMER->CR1 = 0; + ROTARY_ENCODER_TIMER->DIER |= TIM_DIER_UIE; + NVIC_EnableIRQ(ROTARY_ENCODER_TIMER_IRQn); + NVIC_SetPriority(ROTARY_ENCODER_TIMER_IRQn, 7); } void rotaryEncoderCheck() { - uint32_t newpos = ROTARY_ENCODER_POSITION(); - if (newpos != rotencPosition && !keyState(KEY_ENTER)) { - if ((rotencPosition & 0x01) ^ ((newpos & 0x02) >> 1)) { + uint8_t newPosition = ROTARY_ENCODER_POSITION(); + if (newPosition != rotencPosition && !keyState(KEY_ENTER)) { + if ((rotencPosition & 0x01) ^ ((newPosition & 0x02) >> 1)) { --rotencValue; } else { ++rotencValue; } - rotencPosition = newpos; + rotencPosition = newPosition; #if !defined(BOOT) if (g_eeGeneral.backlightMode & e_backlight_mode_keys) { backlightOn(); @@ -77,16 +87,21 @@ void rotaryEncoderCheck() } } +void rotaryEncoderStartDelay() +{ + ROTARY_ENCODER_TIMER->CR1 = TIM_CR1_CEN | TIM_CR1_URS; +} + extern "C" void ROTARY_ENCODER_EXTI_IRQHandler1(void) { if (EXTI_GetITStatus(ROTARY_ENCODER_EXTI_LINE1) != RESET) { - rotaryEncoderCheck(); + rotaryEncoderStartDelay(); EXTI_ClearITPendingBit(ROTARY_ENCODER_EXTI_LINE1); } #if !defined(ROTARY_ENCODER_EXTI_IRQn2) if (EXTI_GetITStatus(ROTARY_ENCODER_EXTI_LINE2) != RESET) { - rotaryEncoderCheck(); + rotaryEncoderStartDelay(); EXTI_ClearITPendingBit(ROTARY_ENCODER_EXTI_LINE2); } #endif @@ -100,8 +115,15 @@ extern "C" void ROTARY_ENCODER_EXTI_IRQHandler1(void) extern "C" void ROTARY_ENCODER_EXTI_IRQHandler2(void) { if (EXTI_GetITStatus(ROTARY_ENCODER_EXTI_LINE2) != RESET) { - rotaryEncoderCheck(); + rotaryEncoderStartDelay(); EXTI_ClearITPendingBit(ROTARY_ENCODER_EXTI_LINE2); } } #endif + +extern "C" void ROTARY_ENCODER_TIMER_IRQHandler(void) +{ + ROTARY_ENCODER_TIMER->SR &= ~TIM_SR_UIF; + ROTARY_ENCODER_TIMER->CR1 = 0; + rotaryEncoderCheck(); +} \ No newline at end of file diff --git a/radio/src/targets/common/arm/stm32/timers_driver.cpp b/radio/src/targets/common/arm/stm32/timers_driver.cpp new file mode 100644 index 000000000..f25cf483b --- /dev/null +++ b/radio/src/targets/common/arm/stm32/timers_driver.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (C) OpenTX + * + * Based on code named + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "opentx.h" + +// Start TIMER at 2000000Hz +void init2MhzTimer() +{ + TIMER_2MHz_TIMER->PSC = (PERI1_FREQUENCY * TIMER_MULT_APB1) / 2000000 - 1; // 0.5 uS, 2 MHz + TIMER_2MHz_TIMER->ARR = 65535; + TIMER_2MHz_TIMER->CR2 = 0; + TIMER_2MHz_TIMER->CR1 = TIM_CR1_CEN; +} + +// Start TIMER at 200Hz +void init5msTimer() +{ + INTERRUPT_xMS_TIMER->ARR = 4999; // 5mS in uS + INTERRUPT_xMS_TIMER->PSC = (PERI1_FREQUENCY * TIMER_MULT_APB1) / 1000000 - 1; // 1uS + INTERRUPT_xMS_TIMER->CCER = 0; + INTERRUPT_xMS_TIMER->CCMR1 = 0; + INTERRUPT_xMS_TIMER->EGR = 0; + INTERRUPT_xMS_TIMER->CR1 = TIM_CR1_CEN | TIM_CR1_URS; + INTERRUPT_xMS_TIMER->DIER |= TIM_DIER_UIE; + NVIC_EnableIRQ(INTERRUPT_xMS_IRQn); + NVIC_SetPriority(INTERRUPT_xMS_IRQn, 7); +} + +void stop5msTimer() +{ + INTERRUPT_xMS_TIMER->CR1 = 0 ; // stop timer + NVIC_DisableIRQ(INTERRUPT_xMS_IRQn) ; +} + +// TODO use the same than board_sky9x.cpp +void interrupt5ms() +{ + static uint8_t pre_scale; // Used to get 10 Hz counter + + ++pre_scale; + +#if defined(HAPTIC) + DEBUG_TIMER_START(debugTimerHaptic); + HAPTIC_HEARTBEAT(); + DEBUG_TIMER_STOP(debugTimerHaptic); +#endif + + if (pre_scale == 2) { + pre_scale = 0; + DEBUG_TIMER_START(debugTimerPer10ms); + DEBUG_TIMER_SAMPLE(debugTimerPer10msPeriod); + per10ms(); + DEBUG_TIMER_STOP(debugTimerPer10ms); + } +} + +extern "C" void INTERRUPT_xMS_IRQHandler() +{ + INTERRUPT_xMS_TIMER->SR &= ~TIM_SR_UIF; + interrupt5ms(); + DEBUG_INTERRUPT(INT_1MS); +} diff --git a/radio/src/targets/common/arm/stm32/usb_driver.cpp b/radio/src/targets/common/arm/stm32/usb_driver.cpp index e47774623..7e2c5abf1 100644 --- a/radio/src/targets/common/arm/stm32/usb_driver.cpp +++ b/radio/src/targets/common/arm/stm32/usb_driver.cpp @@ -49,23 +49,8 @@ void setSelectedUsbMode(int mode) int usbPlugged() { - // debounce - static uint8_t debounced_state = 0; - static uint8_t last_state = 0; - - if (GPIO_ReadInputDataBit(USB_GPIO, USB_GPIO_PIN_VBUS)) { - if (last_state) { - debounced_state = 1; - } - last_state = 1; - } - else { - if (!last_state) { - debounced_state = 0; - } - last_state = 0; - } - return debounced_state; + static PinDebounce debounce; + return debounce.debounce(USB_GPIO, USB_GPIO_PIN_VBUS); } USB_OTG_CORE_HANDLE USB_OTG_dev; diff --git a/radio/src/targets/horus/CMakeLists.txt b/radio/src/targets/horus/CMakeLists.txt index 14fd9c4e9..e94df176b 100644 --- a/radio/src/targets/horus/CMakeLists.txt +++ b/radio/src/targets/horus/CMakeLists.txt @@ -128,6 +128,7 @@ set(TARGET_SRC led_driver.cpp extmodule_driver.cpp trainer_driver.cpp + ../common/arm/stm32/timers_driver.cpp ../common/arm/stm32/intmodule_serial_driver.cpp ../common/arm/stm32/bluetooth_driver.cpp ../common/arm/stm32/rotary_encoder_driver.cpp diff --git a/radio/src/targets/horus/board.cpp b/radio/src/targets/horus/board.cpp index c30c9b8ff..51b22889a 100644 --- a/radio/src/targets/horus/board.cpp +++ b/radio/src/targets/horus/board.cpp @@ -41,60 +41,6 @@ void watchdogInit(unsigned int duration) IWDG->KR = 0xCCCC; // start } -// Start TIMER7 at 2000000Hz -void init2MhzTimer() -{ - TIMER_2MHz_TIMER->PSC = (PERI1_FREQUENCY * TIMER_MULT_APB1) / 2000000 - 1; // 0.5 uS, 2 MHz - TIMER_2MHz_TIMER->ARR = 65535; - TIMER_2MHz_TIMER->CR2 = 0; - TIMER_2MHz_TIMER->CR1 = TIM_CR1_CEN; -} - -// Starts TIMER at 1000Hz -void init1msTimer() -{ - INTERRUPT_xMS_TIMER->ARR = 999; // 1mS in uS - INTERRUPT_xMS_TIMER->PSC = (PERI1_FREQUENCY * TIMER_MULT_APB1) / 1000000 - 1; // 1uS - INTERRUPT_xMS_TIMER->CCER = 0; - INTERRUPT_xMS_TIMER->CCMR1 = 0; - INTERRUPT_xMS_TIMER->EGR = 0; - INTERRUPT_xMS_TIMER->CR1 = 5; - INTERRUPT_xMS_TIMER->DIER |= 1; - NVIC_EnableIRQ(INTERRUPT_xMS_IRQn); - NVIC_SetPriority(INTERRUPT_xMS_IRQn, 7); -} - -// TODO use the same than board_sky9x.cpp -void interrupt1ms() -{ - static uint8_t pre_scale; // Used to get 10 Hz counter - - ++pre_scale; - -#if defined(HAPTIC) - if (pre_scale == 5 || pre_scale == 10) { - DEBUG_TIMER_START(debugTimerHaptic); - HAPTIC_HEARTBEAT(); - DEBUG_TIMER_STOP(debugTimerHaptic); - } -#endif - - if (pre_scale == 10) { - pre_scale = 0; - DEBUG_TIMER_START(debugTimerPer10ms); - DEBUG_TIMER_SAMPLE(debugTimerPer10msPeriod); - per10ms(); - DEBUG_TIMER_STOP(debugTimerPer10ms); - } -} - -extern "C" void INTERRUPT_xMS_IRQHandler() -{ - INTERRUPT_xMS_TIMER->SR &= ~TIM_SR_UIF; - interrupt1ms(); - DEBUG_INTERRUPT(INT_1MS); -} - #if defined(SEMIHOSTING) extern "C" void initialise_monitor_handles(); #endif @@ -150,7 +96,8 @@ void boardInit() SPORT_UPDATE_RCC_AHB1Periph, ENABLE); - RCC_APB1PeriphClockCmd(INTERRUPT_xMS_RCC_APB1Periph | + RCC_APB1PeriphClockCmd(ROTARY_ENCODER_RCC_APB1Periph | + INTERRUPT_xMS_RCC_APB1Periph | ADC_RCC_APB1Periph | TIMER_2MHz_RCC_APB1Periph | AUDIO_RCC_APB1Periph | @@ -208,7 +155,7 @@ void boardInit() backlightInit(); init2MhzTimer(); - init1msTimer(); + init5msTimer(); usbInit(); hapticInit(); diff --git a/radio/src/targets/horus/board.h b/radio/src/targets/horus/board.h index ea4d2604e..8eceb5587 100644 --- a/radio/src/targets/horus/board.h +++ b/radio/src/targets/horus/board.h @@ -112,6 +112,10 @@ void boardPreInit(void); void boardInit(void); void boardOff(void); +// Timers driver +void init2MhzTimer(); +void init5msTimer(); + // Delays driver #ifdef __cplusplus extern "C" { diff --git a/radio/src/targets/horus/hal.h b/radio/src/targets/horus/hal.h index b94470799..007fefec7 100644 --- a/radio/src/targets/horus/hal.h +++ b/radio/src/targets/horus/hal.h @@ -54,6 +54,7 @@ #endif // Rotary Encoder +#define ROTARY_ENCODER_RCC_APB1Periph RCC_APB1Periph_TIM4 #define ROTARY_ENCODER_GPIO GPIOH #define ROTARY_ENCODER_GPIO_PIN_A GPIO_Pin_11 // PH.11 #define ROTARY_ENCODER_GPIO_PIN_B GPIO_Pin_10 // PH.10 @@ -65,6 +66,9 @@ #define ROTARY_ENCODER_EXTI_PortSource EXTI_PortSourceGPIOH #define ROTARY_ENCODER_EXTI_PinSource1 EXTI_PinSource11 #define ROTARY_ENCODER_EXTI_PinSource2 EXTI_PinSource10 +#define ROTARY_ENCODER_TIMER TIM4 +#define ROTARY_ENCODER_TIMER_IRQn TIM4_IRQn +#define ROTARY_ENCODER_TIMER_IRQHandler TIM4_IRQHandler // Switches #define STORAGE_SWITCH_A diff --git a/radio/src/targets/sky9x/board.cpp b/radio/src/targets/sky9x/board.cpp index 515dc7708..93f96e491 100644 --- a/radio/src/targets/sky9x/board.cpp +++ b/radio/src/targets/sky9x/board.cpp @@ -148,7 +148,6 @@ void interrupt5ms() static uint32_t pre_scale ; // Used to get 10 Hz counter HAPTIC_HEARTBEAT(); - AUDIO_HEARTBEAT(); if ( ++pre_scale >= 2 ) { BUZZER_HEARTBEAT(); diff --git a/radio/src/targets/taranis/CMakeLists.txt b/radio/src/targets/taranis/CMakeLists.txt index aca21c142..1d2ccc7c5 100644 --- a/radio/src/targets/taranis/CMakeLists.txt +++ b/radio/src/targets/taranis/CMakeLists.txt @@ -253,6 +253,7 @@ set(TARGET_SRC backlight_driver.cpp extmodule_driver.cpp trainer_driver.cpp + ../common/arm/stm32/timers_driver.cpp ../common/arm/stm32/audio_dac_driver.cpp ../common/arm/stm32/adc_driver.cpp ../common/arm/stm32/heartbeat_driver.cpp diff --git a/radio/src/targets/taranis/board.cpp b/radio/src/targets/taranis/board.cpp index f5704f08b..5bc5def1d 100644 --- a/radio/src/targets/taranis/board.cpp +++ b/radio/src/targets/taranis/board.cpp @@ -41,64 +41,6 @@ void watchdogInit(unsigned int duration) IWDG->KR = 0xCCCC; // start } -// Starts TIMER at 2MHz -void init2MhzTimer() -{ - TIMER_2MHz_TIMER->PSC = (PERI1_FREQUENCY * TIMER_MULT_APB1) / 2000000 - 1 ; // 0.5 uS, 2 MHz - TIMER_2MHz_TIMER->ARR = 65535; - TIMER_2MHz_TIMER->CR2 = 0; - TIMER_2MHz_TIMER->CR1 = TIM_CR1_CEN; -} - -// Starts TIMER at 200Hz (5ms) -void init5msTimer() -{ - INTERRUPT_xMS_TIMER->ARR = 4999 ; // 5mS in uS - INTERRUPT_xMS_TIMER->PSC = (PERI1_FREQUENCY * TIMER_MULT_APB1) / 1000000 - 1 ; // 1uS - INTERRUPT_xMS_TIMER->CCER = 0 ; - INTERRUPT_xMS_TIMER->CCMR1 = 0 ; - INTERRUPT_xMS_TIMER->EGR = 0 ; - INTERRUPT_xMS_TIMER->CR1 = 5 ; - INTERRUPT_xMS_TIMER->DIER |= 1 ; - NVIC_EnableIRQ(INTERRUPT_xMS_IRQn) ; - NVIC_SetPriority(INTERRUPT_xMS_IRQn, 7); -} - -void stop5msTimer( void ) -{ - INTERRUPT_xMS_TIMER->CR1 = 0 ; // stop timer - NVIC_DisableIRQ(INTERRUPT_xMS_IRQn) ; -} - -// TODO use the same than board_sky9x.cpp -void interrupt5ms() -{ - static uint32_t pre_scale ; // Used to get 10 Hz counter - - AUDIO_HEARTBEAT(); - -#if defined(HAPTIC) - HAPTIC_HEARTBEAT(); -#endif - - if (++pre_scale >= 2) { - pre_scale = 0 ; - DEBUG_TIMER_START(debugTimerPer10ms); - DEBUG_TIMER_SAMPLE(debugTimerPer10msPeriod); - per10ms(); - DEBUG_TIMER_STOP(debugTimerPer10ms); - } -} - -#if !defined(SIMU) -extern "C" void INTERRUPT_xMS_IRQHandler() -{ - INTERRUPT_xMS_TIMER->SR &= ~TIM_SR_UIF ; - interrupt5ms() ; - DEBUG_INTERRUPT(INT_5MS); -} -#endif - #if defined(PWR_BUTTON_PRESS) #define PWR_PRESS_DURATION_MIN 100 // 1s #define PWR_PRESS_DURATION_MAX 500 // 5s @@ -160,7 +102,8 @@ void boardInit() GYRO_RCC_AHB1Periph, ENABLE); - RCC_APB1PeriphClockCmd(LCD_RCC_APB1Periph | + RCC_APB1PeriphClockCmd(ROTARY_ENCODER_RCC_APB1Periph | + LCD_RCC_APB1Periph | AUDIO_RCC_APB1Periph | ADC_RCC_APB1Periph | BACKLIGHT_RCC_APB1Periph | diff --git a/radio/src/targets/taranis/board.h b/radio/src/targets/taranis/board.h index aca1b8f67..f1a152e2b 100644 --- a/radio/src/targets/taranis/board.h +++ b/radio/src/targets/taranis/board.h @@ -124,6 +124,10 @@ void boardPreInit(void); void boardInit(void); void boardOff(void); +// Timers driver +void init2MhzTimer(); +void init5msTimer(); + // Delays driver #ifdef __cplusplus extern "C" { diff --git a/radio/src/targets/taranis/hal.h b/radio/src/targets/taranis/hal.h index 8c0175408..c9d8c15ef 100644 --- a/radio/src/targets/taranis/hal.h +++ b/radio/src/targets/taranis/hal.h @@ -135,6 +135,14 @@ #define ROTARY_ENCODER_EXTI_PinSource1 EXTI_PinSource10 #define ROTARY_ENCODER_EXTI_PinSource2 EXTI_PinSource12 #endif +#if defined(ROTARY_ENCODER_NAVIGATION) + #define ROTARY_ENCODER_RCC_APB1Periph RCC_APB1Periph_TIM5 + #define ROTARY_ENCODER_TIMER TIM5 + #define ROTARY_ENCODER_TIMER_IRQn TIM5_IRQn + #define ROTARY_ENCODER_TIMER_IRQHandler TIM5_IRQHandler +#else + #define ROTARY_ENCODER_RCC_APB1Periph 0 +#endif // Trims #if defined(PCBX9E) From 7c3ad50e7dcf3ac1236fe6df07c2707500dffa1a Mon Sep 17 00:00:00 2001 From: 3djc Date: Fri, 14 Jun 2019 21:08:39 +0200 Subject: [PATCH 027/350] FlexR9M looks like a missing option in 2.3 --- radio/util/fwoptions.py | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/radio/util/fwoptions.py b/radio/util/fwoptions.py index a32399004..07bc66734 100755 --- a/radio/util/fwoptions.py +++ b/radio/util/fwoptions.py @@ -81,7 +81,8 @@ options_taranis_x9d = { "shutdownconfirm": ("SHUTDOWN_CONFIRMATION", "YES", "NO"), "eu": ("SUPPORT_D16_EU_ONLY", "YES", "NO"), "multimodule": ("MULTIMODULE", "YES", "NO"), - "crossfire": ("CROSSFIRE", "YES", "NO") + "crossfire": ("CROSSFIRE", "YES", "NO"), + "flexr9m": ("R9M_PROTO_FLEX", "YES", None) } options_taranis_x9dp = { @@ -99,7 +100,8 @@ options_taranis_x9dp = { "shutdownconfirm": ("SHUTDOWN_CONFIRMATION", "YES", "NO"), "eu": ("SUPPORT_D16_EU_ONLY", "YES", "NO"), "multimodule": ("MULTIMODULE", "YES", "NO"), - "crossfire": ("CROSSFIRE", "YES", "NO") + "crossfire": ("CROSSFIRE", "YES", "NO"), + "flexr9m": ("R9M_PROTO_FLEX", "YES", None) } options_taranis_x9lite = { @@ -117,7 +119,8 @@ options_taranis_x9lite = { "eu": ("SUPPORT_D16_EU_ONLY", "YES", "NO"), "multimodule": ("MULTIMODULE", "YES", "NO"), "internalpxx1": ("INTERNAL_MODULE_PXX1", "YES", "NO"), - "crossfire": ("CROSSFIRE", "YES", "NO") + "crossfire": ("CROSSFIRE", "YES", "NO"), + "flexr9m": ("R9M_PROTO_FLEX", "YES", None) } options_taranis_xlite = { @@ -133,7 +136,8 @@ options_taranis_xlite = { "shutdownconfirm": ("SHUTDOWN_CONFIRMATION", "YES", "NO"), "eu": ("SUPPORT_D16_EU_ONLY", "YES", "NO"), "multimodule": ("MULTIMODULE", "YES", "NO"), - "crossfire": ("CROSSFIRE", "YES", "NO") + "crossfire": ("CROSSFIRE", "YES", "NO"), + "flexr9m": ("R9M_PROTO_FLEX", "YES", None) } options_taranis_xlites = { @@ -150,7 +154,8 @@ options_taranis_xlites = { "eu": ("SUPPORT_D16_EU_ONLY", "YES", "NO"), "multimodule": ("MULTIMODULE", "YES", "NO"), "internalpxx1": ("INTERNAL_MODULE_PXX1", "YES", "NO"), - "crossfire": ("CROSSFIRE", "YES", "NO") + "crossfire": ("CROSSFIRE", "YES", "NO"), + "flexr9m": ("R9M_PROTO_FLEX", "YES", None) } options_taranis_x9e = { @@ -168,7 +173,8 @@ options_taranis_x9e = { "eu": ("SUPPORT_D16_EU_ONLY", "YES", "NO"), "horussticks": ("STICKS", "HORUS", "STANDARD"), "multimodule": ("MULTIMODULE", "YES", "NO"), - "crossfire": ("CROSSFIRE", "YES", "NO") + "crossfire": ("CROSSFIRE", "YES", "NO"), + "flexr9m": ("R9M_PROTO_FLEX", "YES", None) } options_horus_x12s = { @@ -183,7 +189,8 @@ options_horus_x12s = { "eu": ("SUPPORT_D16_EU_ONLY", "YES", "NO"), "multimodule": ("MULTIMODULE", "YES", "NO"), "pcbdev": ("PCBREV", "10", None), - "crossfire": ("CROSSFIRE", "YES", "NO") + "crossfire": ("CROSSFIRE", "YES", "NO"), + "flexr9m": ("R9M_PROTO_FLEX", "YES", None) } options_horus_x10 = { @@ -197,5 +204,6 @@ options_horus_x10 = { "nooverridech": ("OVERRIDE_CHANNEL_FUNCTION", "NO", "YES"), "eu": ("SUPPORT_D16_EU_ONLY", "YES", "NO"), "multimodule": ("MULTIMODULE", "YES", "NO"), - "crossfire": ("CROSSFIRE", "YES", "NO") + "crossfire": ("CROSSFIRE", "YES", "NO"), + "flexr9m": ("R9M_PROTO_FLEX", "YES", None) } From c3388dc65e1ab400375c1dcd0af43aa82ec9317f Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Fri, 14 Jun 2019 21:19:26 +0200 Subject: [PATCH 028/350] Bsongis/x9lite pwr fix (#6501) X9 Pwr fix --- radio/src/CMakeLists.txt | 2 +- radio/src/opentx.cpp | 12 +- radio/src/opentx.h | 2 +- radio/src/switches.cpp | 92 +++++++----- .../arm/stm32/bootloader/CMakeLists.txt | 2 +- .../common/arm/stm32/bootloader/boot.cpp | 12 +- radio/src/targets/horus/CMakeLists.txt | 3 + radio/src/targets/horus/board.cpp | 62 ++++---- radio/src/targets/horus/board.h | 9 +- radio/src/targets/horus/board_preinit.cpp | 25 ---- radio/src/targets/horus/hal.h | 14 +- radio/src/targets/horus/pwr_driver.cpp | 21 --- radio/src/targets/sky9x/board.cpp | 10 -- radio/src/targets/sky9x/board.h | 3 +- radio/src/targets/sky9x/trainer_driver.cpp | 4 +- radio/src/targets/taranis/board.cpp | 79 +++------- radio/src/targets/taranis/board.h | 20 +-- radio/src/targets/taranis/board_preinit.cpp | 41 ----- radio/src/targets/taranis/pwr_driver.cpp | 40 ++--- radio/src/tasks.cpp | 2 +- radio/src/tests/CMakeLists.txt | 2 +- radio/src/trainer.cpp | 141 ++++++++++++++++++ radio/src/{trainer_input.h => trainer.h} | 10 +- radio/src/trainer_input.cpp | 51 ------- 24 files changed, 306 insertions(+), 353 deletions(-) delete mode 100644 radio/src/targets/horus/board_preinit.cpp delete mode 100644 radio/src/targets/taranis/board_preinit.cpp create mode 100644 radio/src/trainer.cpp rename radio/src/{trainer_input.h => trainer.h} (92%) delete mode 100644 radio/src/trainer_input.cpp diff --git a/radio/src/CMakeLists.txt b/radio/src/CMakeLists.txt index e3b89c9d7..4098c966b 100644 --- a/radio/src/CMakeLists.txt +++ b/radio/src/CMakeLists.txt @@ -325,7 +325,7 @@ set(SRC mixer.cpp stamp.cpp timers.cpp - trainer_input.cpp + trainer.cpp ) if(GUI) diff --git a/radio/src/opentx.cpp b/radio/src/opentx.cpp index 43abbc78f..ccdf1ab7f 100644 --- a/radio/src/opentx.cpp +++ b/radio/src/opentx.cpp @@ -954,14 +954,14 @@ void checkThrottleStick() } #if defined(PWR_BUTTON_PRESS) - uint32_t pwr_check = pwrCheck(); - if (pwr_check == e_power_off) { + uint32_t power = pwrCheck(); + if (power == e_power_off) { break; } - else if (pwr_check == e_power_press) { + else if (power == e_power_press) { refresh = true; } - else if (pwr_check == e_power_on && refresh) { + else if (power == e_power_on && refresh) { RAISE_ALERT(STR_THROTTLEWARN, STR_THROTTLENOTIDLE, STR_PRESSANYKEYTOSKIP, AU_NONE); refresh = false; } @@ -1886,10 +1886,6 @@ void opentxInit() #endif backlightOn(); -#if defined(PCBSKY9X) && !defined(SIMU) - init_trainer_capture(); -#endif - startPulses(); wdt_enable(WDTO_500MS); diff --git a/radio/src/opentx.h b/radio/src/opentx.h index 918cb6822..10f7c872b 100644 --- a/radio/src/opentx.h +++ b/radio/src/opentx.h @@ -741,7 +741,7 @@ extern uint8_t g_vbat100mV; #define g_blinkTmr10ms (*(uint8_t*)&g_tmr10ms) extern uint8_t g_beepCnt; -#include "trainer_input.h" +#include "trainer.h" extern int32_t chans[MAX_OUTPUT_CHANNELS]; extern int16_t ex_chans[MAX_OUTPUT_CHANNELS]; // Outputs (before LIMITS) of the last perMain diff --git a/radio/src/switches.cpp b/radio/src/switches.cpp index 38ae149b0..de552d87f 100644 --- a/radio/src/switches.cpp +++ b/radio/src/switches.cpp @@ -25,10 +25,9 @@ #if defined(PCBHORUS) #define SWITCH_WARNING_LIST_X WARNING_LINE_X #define SWITCH_WARNING_LIST_Y WARNING_LINE_Y+3*FH - #define SWITCH_WARNING_LIST_INTERVAL 35 #elif LCD_W >= 212 #define SWITCH_WARNING_LIST_X 60 - #define SWITCH_WARNING_LIST_Y 4*FH+3 + #define SWITCH_WARNING_LIST_Y 4*FH+4 #else #define SWITCH_WARNING_LIST_X 4 #define SWITCH_WARNING_LIST_Y 4*FH+4 @@ -558,6 +557,10 @@ void checkSwitches() uint8_t bad_pots = 0, last_bad_pots = 0xff; #endif +#if defined(PWR_BUTTON_PRESS) + bool refresh = false; +#endif + while (1) { #if defined(PCBTARANIS) || defined(PCBHORUS) @@ -642,12 +645,13 @@ void checkSwitches() // first - display warning #if defined(PCBTARANIS) || defined(PCBHORUS) - if ((last_bad_switches != switches_states) || (last_bad_pots != bad_pots)) { - drawAlertBox(STR_SWITCHWARN, NULL, STR_PRESSANYKEYTOSKIP); + if (last_bad_switches != switches_states || last_bad_pots != bad_pots) { + drawAlertBox(STR_SWITCHWARN, nullptr, STR_PRESSANYKEYTOSKIP); if (last_bad_switches == 0xff || last_bad_pots == 0xff) { AUDIO_ERROR_MESSAGE(AU_SWITCH_ALERT); } - int x = SWITCH_WARNING_LIST_X, y = SWITCH_WARNING_LIST_Y; + int x = SWITCH_WARNING_LIST_X; + int y = SWITCH_WARNING_LIST_Y; int numWarnings = 0; for (int i=0; i> (i*2)]; drawSource(x, y, MIXSRC_FIRST_SWITCH+i, attr); lcdDrawChar(lcdNextPos, y, c, attr); x = lcdNextPos + 3; } - else if (numWarnings == 7) { - lcdDrawText(x, y, "...", 0); - } } } #endif } if (g_model.potsWarnMode) { - if (y == 4*FH+3) { - y = 6*FH-2; - x = 60; - } for (int i=0; i 1) { -#if defined(COLORLCD) - char s[8]; - // TODO add an helper - strncpy(s, &STR_VSRCRAW[1+(NUM_STICKS+1+i)*STR_VSRCRAW[0]], STR_VSRCRAW[0]); - s[int(STR_VSRCRAW[0])] = '\0'; -#else - lcdDrawTextAtIndex(x, y, STR_VSRCRAW, NUM_STICKS+1+i, INVERS); - if (IS_POT(POT1+i)) - lcdDrawChar(lcdNextPos, y, g_model.potsWarnPosition[i] > GET_LOWRES_POT_POSITION(i) ? 126 : 127, INVERS); - else - lcdDrawChar(lcdNextPos, y, g_model.potsWarnPosition[i] > GET_LOWRES_POT_POSITION(i) ? '\300' : '\301', INVERS); -#endif -#if defined(COLORLCD) if (++numWarnings < 6) { +#if defined(COLORLCD) + char s[8]; + // TODO add an helper + strncpy(s, &STR_VSRCRAW[1+(NUM_STICKS+1+i)*STR_VSRCRAW[0]], STR_VSRCRAW[0]); + s[int(STR_VSRCRAW[0])] = '\0'; lcdDrawText(x, y, s, ALARM_COLOR); - } - else if (numWarnings == 6) { - lcdDrawText(x, y, "...", ALARM_COLOR); - } - x += 40; + x += 40; #else - x = lcdNextPos + 3; + lcdDrawTextAtIndex(x, y, STR_VSRCRAW, NUM_STICKS + 1 + i, INVERS); + if (IS_POT(POT1 + i)) + lcdDrawChar(lcdNextPos, y, g_model.potsWarnPosition[i] > GET_LOWRES_POT_POSITION(i) ? 126 : 127, INVERS); + else + lcdDrawChar(lcdNextPos, y, g_model.potsWarnPosition[i] > GET_LOWRES_POT_POSITION(i) ? '\300' : '\301', INVERS); + x = lcdNextPos + 3; #endif + } } - } } } + + if (numWarnings >= 6) { +#if defined(COLORLCD) + lcdDrawText(x, y, "...", ALARM_COLOR); +#else + lcdDrawText(x, y, "...", 0); +#endif + } + last_bad_pots = bad_pots; #else if (last_bad_switches != switches_states) { @@ -747,7 +743,27 @@ void checkSwitches() last_bad_switches = switches_states; } - if (pwrCheck() == e_power_off || keyDown()) break; + if (keyDown()) + break; + +#if defined(PWR_BUTTON_PRESS) + uint32_t power = pwrCheck(); + if (power == e_power_off) { + break; + } + else if (power == e_power_press) { + refresh = true; + } + else if (power == e_power_on && refresh) { + last_bad_switches = 0xff; + last_bad_pots = 0xff; + refresh = false; + } +#else + if (pwrCheck() == e_power_off) { + break; + } +#endif doLoopCommonActions(); diff --git a/radio/src/targets/common/arm/stm32/bootloader/CMakeLists.txt b/radio/src/targets/common/arm/stm32/bootloader/CMakeLists.txt index fec7b825f..68002e0d0 100644 --- a/radio/src/targets/common/arm/stm32/bootloader/CMakeLists.txt +++ b/radio/src/targets/common/arm/stm32/bootloader/CMakeLists.txt @@ -70,7 +70,7 @@ set(BOOTLOADER_SRC ../../../../../targets/${TARGET_DIR}/backlight_driver.cpp ../../../../../targets/${TARGET_DIR}/keys_driver.cpp ../../../../../targets/${TARGET_DIR}/diskio.cpp - ../../../../../targets/${TARGET_DIR}/board_preinit.cpp + ../../../../../targets/${TARGET_DIR}/board.cpp ../../../../../targets/${TARGET_DIR}/pwr_driver.cpp ../../../../../targets/${TARGET_DIR}/bootloader/boot_menu.cpp ../usbd_usr.cpp diff --git a/radio/src/targets/common/arm/stm32/bootloader/boot.cpp b/radio/src/targets/common/arm/stm32/bootloader/boot.cpp index f1421abef..679317779 100644 --- a/radio/src/targets/common/arm/stm32/bootloader/boot.cpp +++ b/radio/src/targets/common/arm/stm32/bootloader/boot.cpp @@ -209,8 +209,8 @@ int main() RCC_APB2PeriphClockCmd(LCD_RCC_APB2Periph | BACKLIGHT_RCC_APB2Periph | RCC_APB2Periph_SYSCFG, ENABLE); keysInit(); - - boardPreInit(); + pwrInit(); + pwrOff(); // wait for inputs to stabilize for (uint32_t i = 0; i < 50000; i += 1) { @@ -227,7 +227,6 @@ int main() rotaryEncoderInit(); #endif - pwrInit(); pwrOn(); delaysInit(); // needed for lcdInit() @@ -489,12 +488,7 @@ int main() if (state != ST_FLASHING && state != ST_USB) { if (pwrOffPressed()) { - lcdClear(); - lcdOff(); // this drains LCD caps - pwrOff(); - for (;;) { - // Wait for power to go off - } + boardOff(); } } diff --git a/radio/src/targets/horus/CMakeLists.txt b/radio/src/targets/horus/CMakeLists.txt index e94df176b..7525f6d25 100644 --- a/radio/src/targets/horus/CMakeLists.txt +++ b/radio/src/targets/horus/CMakeLists.txt @@ -108,10 +108,12 @@ set(GUI_SRC ${WIDGETS_SRC} rle.cpp ) + if(DISK_CACHE) set(SRC ${SRC} disk_cache.cpp) add_definitions(-DDISK_CACHE) endif() + if(INTERNAL_GPS) set(SRC ${SRC} gps.cpp) add_definitions(-DINTERNAL_GPS) @@ -128,6 +130,7 @@ set(TARGET_SRC led_driver.cpp extmodule_driver.cpp trainer_driver.cpp + ../common/arm/stm32/heartbeat_driver.cpp ../common/arm/stm32/timers_driver.cpp ../common/arm/stm32/intmodule_serial_driver.cpp ../common/arm/stm32/bluetooth_driver.cpp diff --git a/radio/src/targets/horus/board.cpp b/radio/src/targets/horus/board.cpp index 51b22889a..8ba0c5278 100644 --- a/radio/src/targets/horus/board.cpp +++ b/radio/src/targets/horus/board.cpp @@ -29,6 +29,10 @@ extern "C" { } #endif +uint32_t shutdownRequest; // Stores intentional shutdown to avoid reboot loop +uint32_t shutdownReason; // Used for detecting unexpected reboots regardless of reason +uint32_t powerupReason __NOINIT; // Stores power up reason beyond initialization for emergency mode activation + HardwareOptions hardwareOptions; void watchdogInit(unsigned int duration) @@ -122,6 +126,7 @@ void boardInit() ENABLE); pwrInit(); + pwrOn(); delaysInit(); #if defined(DEBUG) @@ -184,52 +189,35 @@ void boardInit() void boardOff() { - BACKLIGHT_DISABLE(); + backlightEnable(0); while (pwrPressed()) { wdt_reset(); } SysTick->CTRL = 0; // turn off systick + +#if defined(PCBX12S) + // Shutdown the Audio amp + GPIO_InitTypeDef GPIO_InitStructure; + GPIO_InitStructure.GPIO_Pin = AUDIO_SHUTDOWN_GPIO_PIN; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; + GPIO_Init(AUDIO_SHUTDOWN_GPIO, &GPIO_InitStructure); + GPIO_ResetBits(AUDIO_SHUTDOWN_GPIO, AUDIO_SHUTDOWN_GPIO_PIN); +#endif + + // Shutdown the Haptic + hapticDone(); + + shutdownRequest = SHUTDOWN_REQUEST; + shutdownReason = NORMAL_POWER_OFF; + pwrOff(); } -uint8_t currentTrainerMode = 0xff; - -void checkTrainerSettings() -{ - uint8_t requiredTrainerMode = g_model.trainerData.mode; - if (requiredTrainerMode != currentTrainerMode) { - switch (currentTrainerMode) { - case TRAINER_MODE_MASTER_TRAINER_JACK: - stop_trainer_capture(); - break; - case TRAINER_MODE_SLAVE: - stop_trainer_ppm(); - break; - case TRAINER_MODE_MASTER_BATTERY_COMPARTMENT: - auxSerialStop(); - } - - currentTrainerMode = requiredTrainerMode; - switch (requiredTrainerMode) { - case TRAINER_MODE_SLAVE: - init_trainer_ppm(); - break; - case TRAINER_MODE_MASTER_BATTERY_COMPARTMENT: - if (g_eeGeneral.auxSerialMode == UART_MODE_SBUS_TRAINER) { - auxSerialSbusInit(); - break; - } - // no break - default: - // master is default - init_trainer_capture(); - break; - } - } -} - uint16_t getBatteryVoltage() { int32_t instant_vbat = anaIn(TX_VOLTAGE); // using filtered ADC value on purpose diff --git a/radio/src/targets/horus/board.h b/radio/src/targets/horus/board.h index 8eceb5587..a3acfc140 100644 --- a/radio/src/targets/horus/board.h +++ b/radio/src/targets/horus/board.h @@ -108,7 +108,6 @@ extern uint16_t sessionTimer; #endif // Board driver -void boardPreInit(void); void boardInit(void); void boardOff(void); @@ -219,6 +218,9 @@ void init_pxx2(uint8_t module); void disable_pxx2(uint8_t module); void disable_serial(uint8_t module); +void init_intmodule_heartbeat(); +void check_intmodule_heartbeat(); + void intmoduleStop(); void intmoduleSerialStart(uint32_t baudrate, uint8_t rxEnable); void intmodulePxxStart(); @@ -507,6 +509,8 @@ extern "C" { // Power driver #define SOFT_PWR_CTRL +extern uint32_t shutdownRequest; // Stores intentional shutdown to avoid reboot loop +extern uint32_t shutdownReason; // Used for detecting unexpected reboots regardless of reason void pwrInit(void); uint32_t pwrCheck(void); void pwrOn(void); @@ -655,9 +659,6 @@ void bluetoothWriteWakeup(void); uint8_t bluetoothIsWriting(void); void bluetoothDisable(void); -extern uint8_t currentTrainerMode; -void checkTrainerSettings(void); - #if defined(__cplusplus) #include "fifo.h" #include "dmafifo.h" diff --git a/radio/src/targets/horus/board_preinit.cpp b/radio/src/targets/horus/board_preinit.cpp deleted file mode 100644 index 54a24cb21..000000000 --- a/radio/src/targets/horus/board_preinit.cpp +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) OpenTX - * - * Based on code named - * th9x - http://code.google.com/p/th9x - * er9x - http://code.google.com/p/er9x - * gruvin9x - http://code.google.com/p/gruvin9x - * - * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "board.h" - -void boardPreInit() -{ -} diff --git a/radio/src/targets/horus/hal.h b/radio/src/targets/horus/hal.h index 007fefec7..75d8a5c81 100644 --- a/radio/src/targets/horus/hal.h +++ b/radio/src/targets/horus/hal.h @@ -630,10 +630,16 @@ #endif // Heartbeat (not used) -#define TRAINER_MODULE_RCC_AHB1Periph RCC_AHB1Periph_GPIOD -#define INTMODULE_HEARTBEAT_GPIO GPIOD -#define INTMODULE_HEARTBEAT_GPIO_PIN GPIO_Pin_12 // PD.12 -#define INTMODULE_HEARTBEAT_TRIGGER EXTI_Trigger_Falling +#define INTMODULE_HEARTBEAT +#define INTMODULE_HEARTBEAT_RCC_AHB1Periph RCC_AHB1Periph_GPIOD +#define INTMODULE_HEARTBEAT_GPIO GPIOD +#define INTMODULE_HEARTBEAT_GPIO_PIN GPIO_Pin_12 +#define INTMODULE_HEARTBEAT_EXTI_PortSource EXTI_PortSourceGPIOD +#define INTMODULE_HEARTBEAT_EXTI_PinSource GPIO_PinSource12 +#define INTMODULE_HEARTBEAT_EXTI_LINE EXTI_Line12 +#define INTMODULE_HEARTBEAT_EXTI_IRQn EXTI15_10_IRQn +#define INTMODULE_HEARTBEAT_REUSE_INTERRUPT_ROTARY_ENCODER +#define INTMODULE_HEARTBEAT_TRIGGER EXTI_Trigger_Falling // Trainer Port #define TRAINER_RCC_AHB1Periph (RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_DMA1) diff --git a/radio/src/targets/horus/pwr_driver.cpp b/radio/src/targets/horus/pwr_driver.cpp index 71ee994e4..b6bc505f7 100644 --- a/radio/src/targets/horus/pwr_driver.cpp +++ b/radio/src/targets/horus/pwr_driver.cpp @@ -21,10 +21,6 @@ #include "pwr.h" #include "board.h" -uint32_t shutdownRequest; // Stores intentional shutdown to avoid reboot loop -uint32_t shutdownReason; // Used for detecting unexpected reboots regardless of reason -uint32_t powerupReason __NOINIT; // Stores power up reason beyond initialization for emergency mode activation - void pwrInit() { GPIO_InitTypeDef GPIO_InitStructure; @@ -86,23 +82,6 @@ void pwrOn() void pwrOff() { -#if defined(PCBX12S) - // Shutdown the Audio amp - GPIO_InitTypeDef GPIO_InitStructure; - GPIO_InitStructure.GPIO_Pin = AUDIO_SHUTDOWN_GPIO_PIN; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz; - GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; - GPIO_Init(AUDIO_SHUTDOWN_GPIO, &GPIO_InitStructure); - GPIO_ResetBits(AUDIO_SHUTDOWN_GPIO, AUDIO_SHUTDOWN_GPIO_PIN); -#endif - - // Shutdown the Haptic - hapticDone(); - - shutdownRequest = SHUTDOWN_REQUEST; - shutdownReason = NORMAL_POWER_OFF; GPIO_ResetBits(PWR_ON_GPIO, PWR_ON_GPIO_PIN); } diff --git a/radio/src/targets/sky9x/board.cpp b/radio/src/targets/sky9x/board.cpp index 93f96e491..d25f83fda 100644 --- a/radio/src/targets/sky9x/board.cpp +++ b/radio/src/targets/sky9x/board.cpp @@ -498,16 +498,6 @@ void calcConsumption() } } -void checkTrainerSettings() -{ - if (SLAVE_MODE()) { - PIOC->PIO_PDR = PIO_PC22; - } - else { - PIOC->PIO_PER = PIO_PC22; - } -} - uint16_t getBatteryVoltage() { int32_t instant_vbat = anaIn(TX_VOLTAGE); // using filtered ADC value on purpose diff --git a/radio/src/targets/sky9x/board.h b/radio/src/targets/sky9x/board.h index e46da5850..37aa4d47d 100644 --- a/radio/src/targets/sky9x/board.h +++ b/radio/src/targets/sky9x/board.h @@ -34,7 +34,6 @@ extern uint16_t ResetReason; #define FIRMWARE_ADDRESS 0x00400000 // Board driver -void boardPreInit(void); void boardInit(void); #define boardOff() pwrOff() @@ -212,8 +211,8 @@ void calcConsumption(); // Trainer driver #define SLAVE_MODE() (pwrCheck() == e_power_trainer) #define TRAINER_CONNECTED() (PIOA->PIO_PDSR & PIO_PA8) -void checkTrainerSettings(); void init_trainer_capture(); +void stop_trainer_capture(); // Write Flash driver #define FLASH_PAGESIZE 256 diff --git a/radio/src/targets/sky9x/trainer_driver.cpp b/radio/src/targets/sky9x/trainer_driver.cpp index 151be4b30..e47a9e549 100644 --- a/radio/src/targets/sky9x/trainer_driver.cpp +++ b/radio/src/targets/sky9x/trainer_driver.cpp @@ -82,14 +82,14 @@ extern "C" void TC3_IRQHandler() //capture ppm in at 2MHz void init_trainer_capture() { + PIOC->PIO_PER = PIO_PC22; start_timer4() ; start_timer3() ; } -#if 0 void stop_trainer_capture() { + PIOC->PIO_PDR = PIO_PC22; TC1->TC_CHANNEL[0].TC_IDR = TC_IDR0_LDRAS ; NVIC_DisableIRQ(TC3_IRQn) ; } -#endif diff --git a/radio/src/targets/taranis/board.cpp b/radio/src/targets/taranis/board.cpp index 5bc5def1d..585241221 100644 --- a/radio/src/targets/taranis/board.cpp +++ b/radio/src/targets/taranis/board.cpp @@ -269,13 +269,13 @@ void boardInit() void boardOff() { -#if defined(STATUS_LEDS) +#if defined(STATUS_LEDS) && !defined(BOOT) ledOff(); #endif BACKLIGHT_DISABLE(); -#if defined(TOPLCD_GPIO) +#if defined(TOPLCD_GPIO) && !defined(BOOT) toplcdOff(); #endif @@ -288,64 +288,33 @@ void boardOff() lcdOff(); SysTick->CTRL = 0; // turn off systick pwrOff(); -} -uint8_t currentTrainerMode = 0xff; + // disable interrupts + __disable_irq(); -void checkTrainerSettings() -{ - uint8_t requiredTrainerMode = g_model.trainerData.mode; - if (requiredTrainerMode != currentTrainerMode) { - switch (currentTrainerMode) { - case TRAINER_MODE_MASTER_TRAINER_JACK: - stop_trainer_capture(); - break; - case TRAINER_MODE_SLAVE: - stop_trainer_ppm(); - break; - case TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE: - stop_trainer_module_cppm(); - break; - case TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE: - stop_trainer_module_sbus(); - break; -#if defined(TRAINER_BATTERY_COMPARTMENT) - case TRAINER_MODE_MASTER_BATTERY_COMPARTMENT: - auxSerialStop(); - break; -#endif + while (1) { + wdt_reset(); +#if defined(SIMU) + return; +#elif defined(PWR_BUTTON_PRESS) + // X9E/X7 needs watchdog reset because CPU is still running while + // the power key is held pressed by the user. + // The power key should be released by now, but we must make sure + if (!pwrPressed()) { + // Put the CPU into sleep to reduce the consumption, + // it might help with the RTC reset issue + PWR->CR |= PWR_CR_CWUF; + /* Select STANDBY mode */ + PWR->CR |= PWR_CR_PDDS; + /* Set SLEEPDEEP bit of Cortex System Control Register */ + SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; + /* Request Wait For Event */ + __WFE(); } - - currentTrainerMode = requiredTrainerMode; - switch (requiredTrainerMode) { - case TRAINER_MODE_SLAVE: - init_trainer_ppm(); - break; - case TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE: - init_trainer_module_cppm(); - break; - case TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE: - init_trainer_module_sbus(); - break; -#if defined(TRAINER_BATTERY_COMPARTMENT) - case TRAINER_MODE_MASTER_BATTERY_COMPARTMENT: - if (g_eeGeneral.auxSerialMode == UART_MODE_SBUS_TRAINER) { - auxSerialSbusInit(); - break; - } - // no break #endif - default: - // master is default - init_trainer_capture(); - break; - } - - if (requiredTrainerMode == TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE || requiredTrainerMode == TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE) - stop_intmodule_heartbeat(); - else - init_intmodule_heartbeat(); } + + // this function must not return! } uint16_t getBatteryVoltage() diff --git a/radio/src/targets/taranis/board.h b/radio/src/targets/taranis/board.h index f1a152e2b..6e8148b08 100644 --- a/radio/src/targets/taranis/board.h +++ b/radio/src/targets/taranis/board.h @@ -120,7 +120,6 @@ void rotaryEncoderCheck(void); extern uint16_t sessionTimer; // Board driver -void boardPreInit(void); void boardInit(void); void boardOff(void); @@ -249,10 +248,10 @@ void extmoduleSendNextFrame(); #define TRAINER_CONNECTED() (GPIO_ReadInputDataBit(TRAINER_DETECT_GPIO, TRAINER_DETECT_GPIO_PIN) == Bit_RESET) #endif #if defined(TRAINER_GPIO) - void init_trainer_ppm(void); - void stop_trainer_ppm(void); - void init_trainer_capture(void); - void stop_trainer_capture(void); + void init_trainer_ppm(); + void stop_trainer_ppm(); + void init_trainer_capture(); + void stop_trainer_capture(); #else #define init_trainer_ppm() #define stop_trainer_ppm() @@ -260,15 +259,15 @@ void extmoduleSendNextFrame(); #define stop_trainer_capture() #endif #if defined(TRAINER_MODULE_CPPM) - void init_trainer_module_cppm(void); - void stop_trainer_module_cppm(void); + void init_trainer_module_cppm(); + void stop_trainer_module_cppm(); #else #define init_trainer_module_cppm() #define stop_trainer_module_cppm() #endif #if defined(TRAINER_MODULE_SBUS) - void init_trainer_module_sbus(void); - void stop_trainer_module_sbus(void); + void init_trainer_module_sbus(); + void stop_trainer_module_sbus(); #else #define init_trainer_module_sbus() #define stop_trainer_module_sbus() @@ -877,9 +876,6 @@ void setTopBatteryValue(uint32_t volts); #define USART_FLAG_ERRORS (USART_FLAG_ORE | USART_FLAG_NE | USART_FLAG_FE | USART_FLAG_PE) -extern uint8_t currentTrainerMode; -void checkTrainerSettings(void); - #if defined(__cplusplus) #include "fifo.h" #include "dmafifo.h" diff --git a/radio/src/targets/taranis/board_preinit.cpp b/radio/src/targets/taranis/board_preinit.cpp deleted file mode 100644 index 116c2577d..000000000 --- a/radio/src/targets/taranis/board_preinit.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) OpenTX - * - * Based on code named - * th9x - http://code.google.com/p/th9x - * er9x - http://code.google.com/p/er9x - * gruvin9x - http://code.google.com/p/gruvin9x - * - * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "board.h" - -void boardPreInit() -{ - GPIO_InitTypeDef GPIO_InitStructure; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; - GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; - - // Board PWR kept OFF - GPIO_ResetBits(PWR_ON_GPIO, PWR_ON_GPIO_PIN); - GPIO_InitStructure.GPIO_Pin = PWR_ON_GPIO_PIN; - GPIO_Init(PWR_ON_GPIO, &GPIO_InitStructure); - -#if defined(INTMODULE_BOOTCMD_GPIO) - GPIO_SetBits(INTMODULE_BOOTCMD_GPIO, INTMODULE_BOOTCMD_GPIO_PIN); - GPIO_InitStructure.GPIO_Pin = INTMODULE_BOOTCMD_GPIO_PIN; - GPIO_Init(INTMODULE_BOOTCMD_GPIO, &GPIO_InitStructure); -#endif -} diff --git a/radio/src/targets/taranis/pwr_driver.cpp b/radio/src/targets/taranis/pwr_driver.cpp index f0e9855be..b74e0d430 100644 --- a/radio/src/targets/taranis/pwr_driver.cpp +++ b/radio/src/targets/taranis/pwr_driver.cpp @@ -28,16 +28,30 @@ void pwrInit() GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; + // Board PWR + GPIO_InitStructure.GPIO_Pin = PWR_ON_GPIO_PIN; + GPIO_Init(PWR_ON_GPIO, &GPIO_InitStructure); + +#if defined(INTMODULE_BOOTCMD_GPIO) + GPIO_SetBits(INTMODULE_BOOTCMD_GPIO, INTMODULE_BOOTCMD_GPIO_PIN); + GPIO_InitStructure.GPIO_Pin = INTMODULE_BOOTCMD_GPIO_PIN; + GPIO_Init(INTMODULE_BOOTCMD_GPIO, &GPIO_InitStructure); +#endif + + // Internal module power GPIO_ResetBits(INTMODULE_PWR_GPIO, INTMODULE_PWR_GPIO_PIN); GPIO_InitStructure.GPIO_Pin = INTMODULE_PWR_GPIO_PIN; GPIO_Init(INTMODULE_PWR_GPIO, &GPIO_InitStructure); + // External module power EXTERNAL_MODULE_PWR_OFF(); GPIO_InitStructure.GPIO_Pin = EXTMODULE_PWR_GPIO_PIN; GPIO_Init(EXTMODULE_PWR_GPIO, &GPIO_InitStructure); - GPIO_InitStructure.GPIO_Pin = PWR_SWITCH_GPIO_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; + + // PWR switch + GPIO_InitStructure.GPIO_Pin = PWR_SWITCH_GPIO_PIN; GPIO_Init(PWR_SWITCH_GPIO, &GPIO_InitStructure); #if defined(TRAINER_DETECT_GPIO_PIN) @@ -67,30 +81,6 @@ void pwrOn() void pwrOff() { GPIO_ResetBits(PWR_ON_GPIO, PWR_ON_GPIO_PIN); - - // disable interrupts - __disable_irq(); - - while (1) { - wdt_reset(); -#if defined(PWR_BUTTON_PRESS) - // X9E/X7 needs watchdog reset because CPU is still running while - // the power key is held pressed by the user. - // The power key should be released by now, but we must make sure - if (!pwrPressed()) { - // Put the CPU into sleep to reduce the consumption, - // it might help with the RTC reset issue - PWR->CR |= PWR_CR_CWUF; - /* Select STANDBY mode */ - PWR->CR |= PWR_CR_PDDS; - /* Set SLEEPDEEP bit of Cortex System Control Register */ - SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; - /* Request Wait For Event */ - __WFE(); - } -#endif - } - // this function must not return! } uint32_t pwrPressed() diff --git a/radio/src/tasks.cpp b/radio/src/tasks.cpp index d0d02b9fe..140e4676c 100644 --- a/radio/src/tasks.cpp +++ b/radio/src/tasks.cpp @@ -128,7 +128,7 @@ TASK_FUNCTION(mixerTask) } #else if (isForcePowerOffRequested()) { - pwrOff(); + boardOff(); } #endif diff --git a/radio/src/tests/CMakeLists.txt b/radio/src/tests/CMakeLists.txt index 20a253d1a..d2062a0f3 100644 --- a/radio/src/tests/CMakeLists.txt +++ b/radio/src/tests/CMakeLists.txt @@ -1,4 +1,4 @@ -set(GTEST_ROOT /usr CACHE string "Base path to Google Test headers and source.") +set(GTEST_ROOT /usr CACHE STRING "Base path to Google Test headers and source.") find_path(GTEST_INCDIR gtest/gtest.h HINTS "${GTEST_ROOT}/include" DOC "Path to Google Test header files folder ('gtest/gtest.h').") find_path(GTEST_SRCDIR src/gtest-all.cc HINTS "${GTEST_ROOT}" "${GTEST_ROOT}/src/gtest" DOC "Path of Google Test 'src' folder.") diff --git a/radio/src/trainer.cpp b/radio/src/trainer.cpp new file mode 100644 index 000000000..7761645ba --- /dev/null +++ b/radio/src/trainer.cpp @@ -0,0 +1,141 @@ +/* + * Copyright (C) OpenTX + * + * Based on code named + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "opentx.h" + +int16_t ppmInput[MAX_TRAINER_CHANNELS]; +uint8_t ppmInputValidityTimer; +uint8_t currentTrainerMode = 0xff; + +void checkTrainerSignalWarning() +{ + enum PpmInValidState_t { + PPM_IN_IS_NOT_USED=0, + PPM_IN_IS_VALID, + PPM_IN_INVALID + }; + + static uint8_t ppmInputValidState = PPM_IN_IS_NOT_USED; + + if (ppmInputValidityTimer && (ppmInputValidState == PPM_IN_IS_NOT_USED)) { + ppmInputValidState = PPM_IN_IS_VALID; + } + else if (!ppmInputValidityTimer && (ppmInputValidState == PPM_IN_IS_VALID)) { + ppmInputValidState = PPM_IN_INVALID; + AUDIO_TRAINER_LOST(); + } + else if (ppmInputValidityTimer && (ppmInputValidState == PPM_IN_INVALID)) { + ppmInputValidState = PPM_IN_IS_VALID; + AUDIO_TRAINER_BACK(); + } +} + +#if defined(PCBSKY9X) +void checkTrainerSettings() +{ + uint8_t requiredTrainerMode = SLAVE_MODE(); + + if (requiredTrainerMode != currentTrainerMode) { + currentTrainerMode = requiredTrainerMode; + if (requiredTrainerMode) + stop_trainer_capture(); + else + init_trainer_capture(); + } +} +#else +void checkTrainerSettings() +{ + uint8_t requiredTrainerMode = g_model.trainerData.mode; + + if (requiredTrainerMode != currentTrainerMode) { + switch (currentTrainerMode) { + case TRAINER_MODE_MASTER_TRAINER_JACK: + stop_trainer_capture(); + break; + + case TRAINER_MODE_SLAVE: + stop_trainer_ppm(); + break; + +#if defined(TRAINER_MODULE_CPPM) + case TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE: + stop_trainer_module_cppm(); + break; +#endif + +#if defined(TRAINER_MODULE_SBUS) + case TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE: + stop_trainer_module_sbus(); + break; +#endif + +#if defined(TRAINER_BATTERY_COMPARTMENT) + case TRAINER_MODE_MASTER_BATTERY_COMPARTMENT: + auxSerialStop(); + break; +#endif + } + + currentTrainerMode = requiredTrainerMode; + + switch (requiredTrainerMode) { + case TRAINER_MODE_SLAVE: + init_trainer_ppm(); + break; + +#if defined(TRAINER_MODULE_CPPM) + case TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE: + init_trainer_module_cppm(); + break; +#endif + +#if defined(TRAINER_MODULE_SBUS) + case TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE: + init_trainer_module_sbus(); + break; +#endif + +#if defined(TRAINER_BATTERY_COMPARTMENT) + case TRAINER_MODE_MASTER_BATTERY_COMPARTMENT: + if (g_eeGeneral.auxSerialMode == UART_MODE_SBUS_TRAINER) { + auxSerialSbusInit(); + break; + } + // no break +#endif + + default: + // master is default + init_trainer_capture(); + break; + } + +#if defined(TRAINER_MODULE_CPPM) || defined(TRAINER_MODULE_SBUS) + if (requiredTrainerMode == TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE || requiredTrainerMode == TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE) + stop_intmodule_heartbeat(); + else + init_intmodule_heartbeat(); +#else + init_intmodule_heartbeat(); +#endif + } +} +#endif diff --git a/radio/src/trainer_input.h b/radio/src/trainer.h similarity index 92% rename from radio/src/trainer_input.h rename to radio/src/trainer.h index 8f96ec605..6f5549cc7 100644 --- a/radio/src/trainer_input.h +++ b/radio/src/trainer.h @@ -18,10 +18,10 @@ * GNU General Public License for more details. */ -#ifndef _TRAINER_INPUT_H_ -#define _TRAINER_INPUT_H_ +#ifndef _TRAINER_H_ +#define _TRAINER_H_ -#include "opentx.h" +#include "dataconstants.h" // Trainer input channels extern int16_t ppmInput[MAX_TRAINER_CHANNELS]; @@ -30,9 +30,11 @@ extern int16_t ppmInput[MAX_TRAINER_CHANNELS]; #define PPM_IN_VALID_TIMEOUT 100 // 1s extern uint8_t ppmInputValidityTimer; +extern uint8_t currentTrainerMode; #define IS_TRAINER_INPUT_VALID() (ppmInputValidityTimer != 0) void checkTrainerSignalWarning(); +void checkTrainerSettings(); // Needs to be inlined to avoid slow function calls in ISR routines inline void captureTrainerPulses(uint16_t capture) @@ -66,4 +68,4 @@ inline void captureTrainerPulses(uint16_t capture) } } -#endif // _TRAINER_INPUT_H_ +#endif // _TRAINER_H_ diff --git a/radio/src/trainer_input.cpp b/radio/src/trainer_input.cpp deleted file mode 100644 index a84ed0d6e..000000000 --- a/radio/src/trainer_input.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) OpenTX - * - * Based on code named - * th9x - http://code.google.com/p/th9x - * er9x - http://code.google.com/p/er9x - * gruvin9x - http://code.google.com/p/gruvin9x - * - * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "trainer_input.h" - -int16_t ppmInput[MAX_TRAINER_CHANNELS]; -uint8_t ppmInputValidityTimer; - - -#include "audio.h" - -void checkTrainerSignalWarning() -{ - enum PpmInValidState_t { - PPM_IN_IS_NOT_USED=0, - PPM_IN_IS_VALID, - PPM_IN_INVALID - }; - - static uint8_t ppmInputValidState = PPM_IN_IS_NOT_USED; - - if (ppmInputValidityTimer && (ppmInputValidState == PPM_IN_IS_NOT_USED)) { - ppmInputValidState = PPM_IN_IS_VALID; - } - else if (!ppmInputValidityTimer && (ppmInputValidState == PPM_IN_IS_VALID)) { - ppmInputValidState = PPM_IN_INVALID; - AUDIO_TRAINER_LOST(); - } - else if (ppmInputValidityTimer && (ppmInputValidState == PPM_IN_INVALID)) { - ppmInputValidState = PPM_IN_IS_VALID; - AUDIO_TRAINER_BACK(); - } -} - From 383e723b964c89df38e886e9a327b6de266f0085 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Fri, 14 Jun 2019 21:20:22 +0200 Subject: [PATCH 029/350] Bsongis/xlite trainer modes (#6497) More trainer modes added on XLite(S) and X9Lite --- radio/src/bluetooth.cpp | 7 +- radio/src/bluetooth.h | 2 +- radio/src/gui/212x64/model_setup.cpp | 59 +------------ radio/src/gui/212x64/radio_hardware.cpp | 19 +--- radio/src/gui/gui_common.cpp | 79 +++++------------ radio/src/opentx.h | 2 +- radio/src/targets/taranis/CMakeLists.txt | 14 ++- radio/src/targets/taranis/board.h | 2 +- .../src/targets/taranis/extmodule_driver.cpp | 25 ++---- radio/src/targets/taranis/hal.h | 74 +++++++++------- radio/src/targets/taranis/trainer_driver.cpp | 86 ++++++++++++------- radio/src/tasks.cpp | 4 +- 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 +- 23 files changed, 157 insertions(+), 238 deletions(-) diff --git a/radio/src/bluetooth.cpp b/radio/src/bluetooth.cpp index d65dad9ba..f268b180a 100644 --- a/radio/src/bluetooth.cpp +++ b/radio/src/bluetooth.cpp @@ -21,7 +21,7 @@ #include "opentx.h" #include "io/frsky_firmware_update.h" -#if defined(PCBHORUS) || defined(PCBX7) || defined(PCBXLITE) || defined(USEHORUSBT) +#if defined(PCBHORUS) || defined(PCBX7) || defined(PCBXLITE) #define BLUETOOTH_COMMAND_NAME "AT+NAME" #define BLUETOOTH_ANSWER_NAME "OK+" #define BLUETOOTH_COMMAND_BAUD_115200 "AT+BAUD115200" @@ -75,7 +75,8 @@ char * Bluetooth::readline(bool error_reset) while (1) { if (!btRxFifo.pop(byte)) { -#if defined(PCBX9E) && !defined(USEHORUSBT) // X9E BT module can get unresponsive +#if defined(PCBX9E) + // X9E BT module can get unresponsive TRACE("NO RESPONSE FROM BT MODULE"); #endif return nullptr; @@ -290,7 +291,7 @@ void Bluetooth::receiveTrainer() } } -#if defined(PCBX9E) && !defined(USEHORUSBT) +#if defined(PCBX9E) void Bluetooth::wakeup(void) { #if !defined(SIMU) diff --git a/radio/src/bluetooth.h b/radio/src/bluetooth.h index e8e86e056..84ae04507 100644 --- a/radio/src/bluetooth.h +++ b/radio/src/bluetooth.h @@ -19,7 +19,7 @@ */ enum BluetoothStates { -#if defined(PCBX9E) && !defined(USEHORUSBT) +#if defined(PCBX9E) BLUETOOTH_INIT, BLUETOOTH_WAIT_TTM, BLUETOOTH_WAIT_BAUDRATE_CHANGE, diff --git a/radio/src/gui/212x64/model_setup.cpp b/radio/src/gui/212x64/model_setup.cpp index c04d064f7..c6135cbb4 100644 --- a/radio/src/gui/212x64/model_setup.cpp +++ b/radio/src/gui/212x64/model_setup.cpp @@ -229,14 +229,8 @@ void editTimerCountdown(int timerIdx, coord_t y, LcdFlags attr, event_t event) #define PORT_CHANNELS_ROWS(x) (x==INTERNAL_MODULE ? INTERNAL_MODULE_CHANNELS_ROWS : (x==EXTERNAL_MODULE ? EXTERNAL_MODULE_CHANNELS_ROWS : 1)) -#if defined(BLUETOOTH) && defined(USEHORUSBT) - #define TRAINER_LINE1_BLUETOOTH_M_ROWS ((bluetooth.distantAddr[0] == 0 || bluetooth.state == BLUETOOTH_STATE_CONNECTED) ? (uint8_t)0 : (uint8_t)1) - #define TRAINER_LINE1_ROWS (g_model.trainerData.mode == TRAINER_MODE_SLAVE ? (uint8_t)1 : (g_model.trainerData.mode == TRAINER_MODE_MASTER_BLUETOOTH ? TRAINER_LINE1_BLUETOOTH_M_ROWS : (g_model.trainerData.mode == TRAINER_MODE_SLAVE_BLUETOOTH ? (uint8_t)1 : HIDDEN_ROW))) - #define TRAINER_LINE2_ROWS (g_model.trainerData.mode == TRAINER_MODE_SLAVE ? (uint8_t)2 : HIDDEN_ROW) -#else - #define TRAINER_LINE1_ROWS (g_model.trainerData.mode == TRAINER_MODE_SLAVE ? (uint8_t)1 : HIDDEN_ROW) - #define TRAINER_LINE2_ROWS (g_model.trainerData.mode == TRAINER_MODE_SLAVE ? (uint8_t)2 : HIDDEN_ROW) -#endif +#define TRAINER_LINE1_ROWS (g_model.trainerData.mode == TRAINER_MODE_SLAVE ? (uint8_t)1 : HIDDEN_ROW) +#define TRAINER_LINE2_ROWS (g_model.trainerData.mode == TRAINER_MODE_SLAVE ? (uint8_t)2 : HIDDEN_ROW) #define TIMER_ROWS(x) 2|NAVIGATION_LINE_BY_LINE, 0, 0, 0, g_model.timers[x].countdownBeep != COUNTDOWN_SILENT ? (uint8_t) 1 : (uint8_t)0 @@ -779,12 +773,6 @@ void menuModelSetup(event_t event) if (attr) { g_model.trainerData.mode = checkIncDec(event, g_model.trainerData.mode, 0, TRAINER_MODE_MAX(), EE_MODEL, isTrainerModeAvailable); } -#if defined(BLUETOOTH) && defined(USEHORUSBT) - if (attr && checkIncDec_Ret) { - bluetooth.state = BLUETOOTH_STATE_OFF; - bluetooth.distantAddr[0] = 0; - } -#endif break; case ITEM_MODEL_SETUP_EXTERNAL_MODULE_LABEL: @@ -918,48 +906,6 @@ void menuModelSetup(event_t event) lcdDrawTextAlignedLeft(y, STR_TRAINER); break; -#if defined(BLUETOOTH) && defined(USEHORUSBT) - case ITEM_MODEL_SETUP_TRAINER_LINE1: - if (g_model.trainerData.mode == TRAINER_MODE_MASTER_BLUETOOTH) { - if (attr) { - s_editMode = 0; - } - if (bluetooth.distantAddr[0]) { - lcdDrawText(INDENT_WIDTH, y+1, bluetooth.distantAddr, TINSIZE); - if (bluetooth.state != BLUETOOTH_STATE_CONNECTED) { - lcdDrawText(MODEL_SETUP_2ND_COLUMN, y, BUTTON("Bind"), menuHorizontalPosition == 0 ? attr : 0); - lcdDrawText(MODEL_SETUP_2ND_COLUMN+5*FW, y, BUTTON("Clear"), menuHorizontalPosition == 1 ? attr : 0); - } - else { - lcdDrawText(MODEL_SETUP_2ND_COLUMN, y, BUTTON("Clear"), attr); - } - if (attr && event == EVT_KEY_FIRST(KEY_ENTER)) { - if (bluetooth.state == BLUETOOTH_STATE_CONNECTED || menuHorizontalPosition == 1) { - bluetooth.state = BLUETOOTH_STATE_OFF; - bluetooth.distantAddr[0] = 0; - } - else { - bluetooth.state = BLUETOOTH_STATE_BIND_REQUESTED; - } - } - } - else { - lcdDrawText(INDENT_WIDTH, y, "---"); - if (bluetooth.state < BLUETOOTH_STATE_IDLE) - lcdDrawText(MODEL_SETUP_2ND_COLUMN, y, BUTTON("Init"), attr); - else - lcdDrawText(MODEL_SETUP_2ND_COLUMN, y, BUTTON("Discover"), attr); - if (attr && event == EVT_KEY_FIRST(KEY_ENTER)) { - if (bluetooth.state < BLUETOOTH_STATE_IDLE) - bluetooth.state = BLUETOOTH_STATE_OFF; - else - bluetooth.state = BLUETOOTH_STATE_DISCOVER_REQUESTED; - } - } - break; - } - // no break -#else case ITEM_MODEL_SETUP_TRAINER_LINE1: lcdDrawTextAlignedLeft(y, STR_CHANNELRANGE); lcdDrawText(MODEL_SETUP_2ND_COLUMN, y, STR_CH, menuHorizontalPosition==0 ? attr : 0); @@ -977,7 +923,6 @@ void menuModelSetup(event_t event) } } break; -#endif case ITEM_MODEL_SETUP_INTERNAL_MODULE_CHANNELS: case ITEM_MODEL_SETUP_EXTERNAL_MODULE_CHANNELS: diff --git a/radio/src/gui/212x64/radio_hardware.cpp b/radio/src/gui/212x64/radio_hardware.cpp index 3f59fd1e7..a24c7df9c 100644 --- a/radio/src/gui/212x64/radio_hardware.cpp +++ b/radio/src/gui/212x64/radio_hardware.cpp @@ -55,9 +55,6 @@ enum menuRadioHwItems { CASE_PCBX9E(ITEM_RADIO_HARDWARE_SQ) CASE_PCBX9E(ITEM_RADIO_HARDWARE_SR) CASE_BLUETOOTH(ITEM_RADIO_HARDWARE_BLUETOOTH_MODE) -#if defined(USEHORUSBT) - CASE_BLUETOOTH(ITEM_RADIO_HARDWARE_BLUETOOTH_NAME) -#endif #if defined(AUX_SERIAL) ITEM_RADIO_HARDWARE_AUX_SERIAL_MODE, #endif @@ -88,10 +85,10 @@ enum menuRadioHwItems { #define SWITCHES_ROWS NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1 #endif -#if defined(BLUETOOTH) && defined(USEHORUSBT) - #define BLUETOOTH_ROWS 0, uint8_t(g_eeGeneral.bluetoothMode == BLUETOOTH_OFF ? -1 : 0), +#if defined(BLUETOOTH) +#define BLUETOOTH_ROWS (uint8_t)0, #else - #define BLUETOOTH_ROWS (uint8_t)0, +#define BLUETOOTH_ROWS #endif #define SWITCH_TYPE_MAX(sw) ((MIXSRC_SF-MIXSRC_FIRST_SWITCH == sw || MIXSRC_SH-MIXSRC_FIRST_SWITCH == sw) ? SWITCH_2POS : SWITCH_3POS) @@ -218,19 +215,9 @@ void menuRadioHardware(event_t event) lcdDrawText(INDENT_WIDTH, y, STR_BLUETOOTH); lcdDrawTextAtIndex(HW_SETTINGS_COLUMN, y, STR_BLUETOOTH_MODES, g_eeGeneral.bluetoothMode, attr); if (attr) { -#if defined(USEHORUSBT) - g_eeGeneral.bluetoothMode = checkIncDecGen(event, g_eeGeneral.bluetoothMode, BLUETOOTH_OFF, BLUETOOTH_TRAINER); -#else g_eeGeneral.bluetoothMode = checkIncDecGen(event, g_eeGeneral.bluetoothMode, BLUETOOTH_OFF, BLUETOOTH_TELEMETRY); -#endif } break; -#if defined(USEHORUSBT) - case ITEM_RADIO_HARDWARE_BLUETOOTH_NAME: - lcdDrawText(INDENT_WIDTH, y, STR_NAME); - editName(HW_SETTINGS_COLUMN, y, g_eeGeneral.bluetoothName, LEN_BLUETOOTH_NAME, event, attr); - break; -#endif #endif #if defined(AUX_SERIAL) diff --git a/radio/src/gui/gui_common.cpp b/radio/src/gui/gui_common.cpp index 538a4ae93..818f083fe 100644 --- a/radio/src/gui/gui_common.cpp +++ b/radio/src/gui/gui_common.cpp @@ -698,66 +698,33 @@ bool isTelemetryProtocolAvailable(int protocol) return true; } -#if defined(PCBHORUS) bool isTrainerModeAvailable(int mode) { +#if defined(PCBTARANIS) + if (IS_EXTERNAL_MODULE_ENABLED() && (mode == TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE || mode == TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE)) + return false; +#endif + +#if !defined(PCBSKY9X) && !defined(TRAINER_BATTERY_COMPARTMENT) + if (mode == TRAINER_MODE_MASTER_BATTERY_COMPARTMENT) + return false; +#endif + +#if defined(PCBX9E) + if (mode == TRAINER_MODE_MASTER_BLUETOOTH || mode == TRAINER_MODE_SLAVE_BLUETOOTH) + return false; +#elif defined(BLUETOOTH) + if (g_eeGeneral.bluetoothMode != BLUETOOTH_TRAINER && (mode == TRAINER_MODE_MASTER_BLUETOOTH || mode == TRAINER_MODE_SLAVE_BLUETOOTH)) + return false; +#endif + +#if defined(PCBXLITE) + if (mode == TRAINER_MODE_MASTER_TRAINER_JACK || mode == TRAINER_MODE_SLAVE) + return false; +#endif + return true; } -#elif defined(PCBX9E) -bool isTrainerModeAvailable(int mode) -{ - if (IS_EXTERNAL_MODULE_ENABLED() && (mode == TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE || mode == TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE)) - return false; -#if defined(USEHORUSBT) - else if (mode == TRAINER_MODE_MASTER_BATTERY_COMPARTMENT) -#else - else if (mode == TRAINER_MODE_MASTER_BLUETOOTH || mode == TRAINER_MODE_MASTER_BATTERY_COMPARTMENT || mode == TRAINER_MODE_SLAVE_BLUETOOTH) -#endif - return false; - else - return true; -} -#elif defined(PCBX9D) || defined(PCBX9DP) || defined(PCBX9E) -bool isTrainerModeAvailable(int mode) -{ - if (IS_EXTERNAL_MODULE_ENABLED() && (mode == TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE || mode == TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE)) - return false; - else - return true; -} -#elif defined(PCBX7) || defined(PCBXLITES) || defined(PCBX9LITE) -bool isTrainerModeAvailable(int mode) -{ - if (IS_EXTERNAL_MODULE_ENABLED() && (mode == TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE || mode == TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE)) - return false; - else if (mode == TRAINER_MODE_MASTER_BATTERY_COMPARTMENT) - return false; -#if defined(BLUETOOTH) - else if (g_eeGeneral.bluetoothMode != BLUETOOTH_TRAINER && (mode == TRAINER_MODE_MASTER_BLUETOOTH || mode == TRAINER_MODE_SLAVE_BLUETOOTH)) - return false; -#endif - else - return true; -} -#elif defined(PCBXLITES) -bool isTrainerModeAvailable(int mode) -{ - if (mode == TRAINER_MODE_MASTER_TRAINER_JACK || mode == TRAINER_MODE_SLAVE) - return true; - else if (g_eeGeneral.bluetoothMode == BLUETOOTH_TRAINER && (mode == TRAINER_MODE_MASTER_BLUETOOTH || mode == TRAINER_MODE_SLAVE_BLUETOOTH)) - return true; - else - return false; -} -#elif defined(PCBXLITE) -bool isTrainerModeAvailable(int mode) -{ - if (g_eeGeneral.bluetoothMode == BLUETOOTH_TRAINER && (mode == TRAINER_MODE_MASTER_BLUETOOTH || mode == TRAINER_MODE_SLAVE_BLUETOOTH)) - return true; - else - return false; -} -#endif bool modelHasNotes() { diff --git a/radio/src/opentx.h b/radio/src/opentx.h index 10f7c872b..da3487f9c 100644 --- a/radio/src/opentx.h +++ b/radio/src/opentx.h @@ -201,7 +201,7 @@ #define IS_FAI_FORBIDDEN(idx) (IS_FAI_ENABLED() && isFaiForbidden(idx)) #if defined(BLUETOOTH) - #if defined(X9E) && !defined(USEHORUSBT) + #if defined(X9E) #define IS_BLUETOOTH_TRAINER() (g_model.trainerData.mode == TRAINER_MODE_SLAVE_BLUETOOTH) #define IS_SLAVE_TRAINER() (g_model.trainerData.mode == TRAINER_MODE_SLAVE) #else diff --git a/radio/src/targets/taranis/CMakeLists.txt b/radio/src/targets/taranis/CMakeLists.txt index 1d2ccc7c5..a180e0658 100644 --- a/radio/src/targets/taranis/CMakeLists.txt +++ b/radio/src/targets/taranis/CMakeLists.txt @@ -2,7 +2,6 @@ option(SHUTDOWN_CONFIRMATION "Shutdown confirmation" OFF) option(LCD_DUAL_BUFFER "Dual LCD Buffer" OFF) option(INTERNAL_MODULE_PPM "Support for PPM internal module hack" OFF) option(INTERNAL_MODULE_PXX1 "Support for PXX1 internal module replacement" OFF) -option(USEHORUSBT "X9E BT module replaced by Horus BT module" OFF) option(PXX1 "PXX1 protocol support" ON) option(PXX2 "PXX2 protocol support" OFF) @@ -184,10 +183,6 @@ else() ${TARGET_SRC} intmodule_pulses_driver.cpp ) - set(PULSES_SRC - ${PULSES_SRC} - ../sbus.cpp - ) endif() if(PCB STREQUAL X9E OR (PCB STREQUAL X7 AND NOT (PCBREV STREQUAL T12)) OR PCB STREQUAL X9LITE) @@ -246,6 +241,11 @@ if(STATUS_LEDS) set(LED_DRIVER led_driver.cpp) endif() +set(SRC + ${SRC} + sbus.cpp + ) + set(TARGET_SRC ${TARGET_SRC} board.cpp @@ -286,8 +286,4 @@ if(INTERNAL_MODULE_PXX1) add_definitions(-DINTERNAL_MODULE_PXX1) endif() -if(USEHORUSBT) - add_definitions(-DUSEHORUSBT) -endif(USEHORUSBT) - set(FIRMWARE_DEPENDENCIES ${FIRMWARE_DEPENDENCIES} ${BITMAPS_TARGET}) diff --git a/radio/src/targets/taranis/board.h b/radio/src/targets/taranis/board.h index 6e8148b08..360726507 100644 --- a/radio/src/targets/taranis/board.h +++ b/radio/src/targets/taranis/board.h @@ -798,7 +798,7 @@ void auxSerialStop(void); // BT driver #define BLUETOOTH_BOOTLOADER_BAUDRATE 230400 #define BLUETOOTH_DEFAULT_BAUDRATE 115200 -#if defined(PCBX9E) && !defined(USEHORUSBT) +#if defined(PCBX9E) #define BLUETOOTH_FACTORY_BAUDRATE 9600 #else #define BLUETOOTH_FACTORY_BAUDRATE 57600 diff --git a/radio/src/targets/taranis/extmodule_driver.cpp b/radio/src/targets/taranis/extmodule_driver.cpp index 6ac0b65d2..689f0caca 100644 --- a/radio/src/targets/taranis/extmodule_driver.cpp +++ b/radio/src/targets/taranis/extmodule_driver.cpp @@ -27,8 +27,7 @@ void extmoduleStop() EXTMODULE_TIMER_DMA_STREAM->CR &= ~DMA_SxCR_EN; // Disable DMA #if defined(EXTMODULE_USART) - NVIC_DisableIRQ(EXTMODULE_USART_DMA_STREAM_IRQn); - EXTMODULE_USART_DMA_STREAM->CR &= ~DMA_SxCR_EN; // Disable DMA + EXTMODULE_USART_TX_DMA_STREAM->CR &= ~DMA_SxCR_EN; // Disable DMA GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = EXTMODULE_TX_GPIO_PIN | EXTMODULE_RX_GPIO_PIN; @@ -126,13 +125,6 @@ void extmoduleInvertedSerialStart(uint32_t baudrate) { EXTERNAL_MODULE_ON(); - NVIC_InitTypeDef NVIC_InitStructure; - NVIC_InitStructure.NVIC_IRQChannel = EXTMODULE_USART_DMA_STREAM_IRQn; - NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; - NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; /* Not used as 4 bits are used for the pre-emption priority. */; - NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; - NVIC_Init(&NVIC_InitStructure); - // TX + RX Pins GPIO_PinAFConfig(EXTMODULE_USART_GPIO, EXTMODULE_TX_GPIO_PinSource, EXTMODULE_USART_GPIO_AF); GPIO_PinAFConfig(EXTMODULE_USART_GPIO, EXTMODULE_RX_GPIO_PinSource, EXTMODULE_USART_GPIO_AF); @@ -167,8 +159,8 @@ void extmoduleInvertedSerialStart(uint32_t baudrate) void extmoduleSendBuffer(const uint8_t * data, uint8_t size) { DMA_InitTypeDef DMA_InitStructure; - DMA_DeInit(EXTMODULE_USART_DMA_STREAM); - DMA_InitStructure.DMA_Channel = EXTMODULE_USART_DMA_CHANNEL; + DMA_DeInit(EXTMODULE_USART_TX_DMA_STREAM); + DMA_InitStructure.DMA_Channel = EXTMODULE_USART_TX_DMA_CHANNEL; DMA_InitStructure.DMA_PeripheralBaseAddr = CONVERT_PTR_UINT(&EXTMODULE_USART->DR); DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; DMA_InitStructure.DMA_Memory0BaseAddr = CONVERT_PTR_UINT(data); @@ -183,15 +175,11 @@ void extmoduleSendBuffer(const uint8_t * data, uint8_t size) DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; - DMA_Init(EXTMODULE_USART_DMA_STREAM, &DMA_InitStructure); - DMA_Cmd(EXTMODULE_USART_DMA_STREAM, ENABLE); + DMA_Init(EXTMODULE_USART_TX_DMA_STREAM, &DMA_InitStructure); + DMA_Cmd(EXTMODULE_USART_TX_DMA_STREAM, ENABLE); USART_DMACmd(EXTMODULE_USART, USART_DMAReq_Tx, ENABLE); } -// TODO remove this when we have adaptative speed -//uint8_t counter = 0; -//#include - #define USART_FLAG_ERRORS (USART_FLAG_ORE | USART_FLAG_NE | USART_FLAG_FE | USART_FLAG_PE) extern "C" void EXTMODULE_USART_IRQHandler(void) { @@ -201,9 +189,6 @@ extern "C" void EXTMODULE_USART_IRQHandler(void) uint8_t data = EXTMODULE_USART->DR; if (status & USART_FLAG_ERRORS) { extmoduleFifo.errors++; -// if (!counter++) { -// TRACE_NOCRLF("%02X ", (uint8_t)status); -// } } else { extmoduleFifo.push(data); diff --git a/radio/src/targets/taranis/hal.h b/radio/src/targets/taranis/hal.h index c9d8c15ef..e90a70866 100644 --- a/radio/src/targets/taranis/hal.h +++ b/radio/src/targets/taranis/hal.h @@ -826,7 +826,7 @@ #define INTERNAL_MODULE_PXX1 #endif #if defined(PCBXLITE) || defined(PCBX9LITE) - #define INTMODULE_RCC_APB1Periph RCC_APB1Periph_TIM3 + #define INTMODULE_RCC_APB1Periph 0 #define INTMODULE_RCC_APB2Periph RCC_APB2Periph_USART1 #if defined(PCBXLITES) || defined(PCBX9LITE) #define INTMODULE_RCC_AHB1Periph (RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_DMA2) @@ -855,10 +855,6 @@ #define INTMODULE_BOOTCMD_GPIO GPIOC #define INTMODULE_BOOTCMD_GPIO_PIN GPIO_Pin_8 // PC.08 #endif - // #define INTMODULE_TIMER TIM3 - // #define INTMODULE_TIMER_IRQn TIM3_IRQn - // #define INTMODULE_TIMER_IRQHandler TIM3_IRQHandler - // #define INTMODULE_TIMER_FREQ (PERI1_FREQUENCY * TIMER_MULT_APB1) #elif defined(PCBX9E) || defined(PCBX9DP) || defined(RADIO_X7) #define INTMODULE_PULSES #define INTMODULE_RCC_AHB1Periph (RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_DMA2) @@ -962,9 +958,10 @@ #define EXTMODULE_USART USART6 #define EXTMODULE_USART_IRQn USART6_IRQn #define EXTMODULE_USART_IRQHandler USART6_IRQHandler - #define EXTMODULE_USART_DMA_CHANNEL DMA_Channel_5 - #define EXTMODULE_USART_DMA_STREAM DMA2_Stream6 - #define EXTMODULE_USART_DMA_STREAM_IRQn DMA2_Stream6_IRQn + #define EXTMODULE_USART_TX_DMA_CHANNEL DMA_Channel_5 + #define EXTMODULE_USART_TX_DMA_STREAM DMA2_Stream6 + #define EXTMODULE_USART_RX_DMA_CHANNEL DMA_Channel_5 + #define EXTMODULE_USART_RX_DMA_STREAM DMA2_Stream1 #elif defined(RADIO_T12) //Jumper T12v2 external module configured #define EXTMODULE_RCC_AHB1Periph (RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_DMA2) @@ -1233,40 +1230,55 @@ #endif // Trainer / Trainee from the module bay -#if defined(PCBX9LITE) +#if defined(PCBX9LITE) || defined(PCBXLITE) #define TRAINER_MODULE_CPPM - #define TRAINER_MODULE_RCC_AHB1Periph EXTMODULE_HEARTBEAT_RCC_AHB1Periph - #define TRAINER_MODULE_RCC_APB1Periph RCC_APB1Periph_TIM4 + #define TRAINER_MODULE_SBUS + #define TRAINER_MODULE_RCC_AHB1Periph 0 + #define TRAINER_MODULE_RCC_APB1Periph RCC_APB1Periph_TIM3 #define TRAINER_MODULE_RCC_APB2Periph 0 - #define TRAINER_MODULE_CPPM_GPIO EXTMODULE_HEARTBEAT_GPIO - #define TRAINER_MODULE_CPPM_GPIO_PIN EXTMODULE_HEARTBEAT_GPIO_PIN - #define TRAINER_MODULE_CPPM_GPIO_PinSource EXTMODULE_HEARTBEAT_EXTI_PinSource - #define TRAINER_MODULE_CPPM_GPIO_AF GPIO_AF_TIM4 -#elif defined(PCBXLITE) - #define TRAINER_MODULE_CPPM - #define TRAINER_MODULE_RCC_AHB1Periph INTMODULE_HEARTBEAT_RCC_AHB1Periph - #define TRAINER_MODULE_RCC_APB1Periph RCC_APB1Periph_TIM4 - #define TRAINER_MODULE_RCC_APB2Periph 0 - #define TRAINER_MODULE_CPPM_GPIO INTMODULE_HEARTBEAT_GPIO - #define TRAINER_MODULE_CPPM_GPIO_PIN INTMODULE_HEARTBEAT_GPIO_PIN - #define TRAINER_MODULE_CPPM_GPIO_PinSource INTMODULE_HEARTBEAT_EXTI_PinSource - #define TRAINER_MODULE_CPPM_GPIO_AF GPIO_AF_TIM4 + #define TRAINER_MODULE_CPPM_GPIO EXTMODULE_USART_GPIO + #define TRAINER_MODULE_CPPM_GPIO_PIN EXTMODULE_RX_GPIO_PIN + #define TRAINER_MODULE_CPPM_GPIO_PinSource EXTMODULE_RX_GPIO_PinSource + #define TRAINER_MODULE_CPPM_GPIO_AF GPIO_AF_TIM3 + #define TRAINER_MODULE_CPPM_TIMER TIM3 + #define TRAINER_MODULE_CPPM_COUNTER_REGISTER TRAINER_MODULE_CPPM_TIMER->CCR2 + #define TRAINER_MODULE_CPPM_INTERRUPT_ENABLE TIM_DIER_CC2IE + #define TRAINER_MODULE_CPPM_INTERRUPT_FLAG TIM_SR_CC2IF + #define TRAINER_MODULE_CPPM_CCMR1 (TIM_CCMR1_IC2F_0 | TIM_CCMR1_IC2F_1 | TIM_CCMR1_CC2S_0) + #define TRAINER_MODULE_CPPM_CCER TIM_CCER_CC2E + #define TRAINER_MODULE_CPPM_TIMER_IRQn TIM3_IRQn + #define TRAINER_MODULE_CPPM_TIMER_IRQHandler TIM3_IRQHandler + #define TRAINER_MODULE_SBUS_GPIO EXTMODULE_USART_GPIO + #define TRAINER_MODULE_SBUS_GPIO_PIN EXTMODULE_RX_GPIO_PIN + #define TRAINER_MODULE_SBUS_GPIO_AF EXTMODULE_USART_GPIO_AF + #define TRAINER_MODULE_SBUS_USART EXTMODULE_USART + #define TRAINER_MODULE_SBUS_GPIO_PinSource EXTMODULE_RX_GPIO_PinSource + #define TRAINER_MODULE_SBUS_DMA_STREAM EXTMODULE_USART_RX_DMA_STREAM + #define TRAINER_MODULE_SBUS_DMA_CHANNEL EXTMODULE_USART_RX_DMA_CHANNEL #else #define TRAINER_MODULE_CPPM #define TRAINER_MODULE_SBUS #define TRAINER_MODULE_RCC_AHB1Periph RCC_AHB1Periph_GPIOC #define TRAINER_MODULE_RCC_APB2Periph RCC_APB2Periph_USART6 #define TRAINER_MODULE_RCC_APB1Periph RCC_APB1Periph_TIM3 + #define TRAINER_MODULE_CPPM_TIMER TRAINER_TIMER #define TRAINER_MODULE_CPPM_GPIO INTMODULE_HEARTBEAT_GPIO #define TRAINER_MODULE_CPPM_GPIO_PIN INTMODULE_HEARTBEAT_GPIO_PIN #define TRAINER_MODULE_CPPM_GPIO_PinSource INTMODULE_HEARTBEAT_EXTI_PinSource - #define TRAINER_MODULE_SBUS_GPIO_AF GPIO_AF_USART6 - #define TRAINER_MODULE_CPPM_GPIO_AF GPIO_AF_TIM3 - #define TRAINER_MODULE_SBUS_USART USART6 - #define TRAINER_MODULE_SBUS_USART_IRQHandler USART6_IRQHandler - #define TRAINER_MODULE_SBUS_USART_IRQn USART6_IRQn - #define TRAINER_MODULE_SBUS_DMA_Stream DMA2_Stream1 - #define TRAINER_MODULE_SBUS_DMA_Channel DMA_Channel_5 + #define TRAINER_MODULE_CPPM_INTERRUPT_ENABLE TIM_DIER_CC2IE + #define TRAINER_MODULE_CPPM_INTERRUPT_FLAG TIM_SR_CC2IF + #define TRAINER_MODULE_CPPM_CCMR1 (TIM_CCMR1_IC2F_0 | TIM_CCMR1_IC2F_1 | TIM_CCMR1_CC2S_0) + #define TRAINER_MODULE_CPPM_CCER TIM_CCER_CC2E + #define TRAINER_MODULE_CPPM_COUNTER_REGISTER TRAINER_TIMER->CCR2 + #define TRAINER_MODULE_CPPM_TIMER_IRQn TRAINER_TIMER_IRQn + #define TRAINER_MODULE_CPPM_GPIO_AF GPIO_AF_TIM3 + #define TRAINER_MODULE_SBUS_GPIO_AF GPIO_AF_USART6 + #define TRAINER_MODULE_SBUS_USART USART6 + #define TRAINER_MODULE_SBUS_GPIO INTMODULE_HEARTBEAT_GPIO + #define TRAINER_MODULE_SBUS_GPIO_PIN INTMODULE_HEARTBEAT_GPIO_PIN + #define TRAINER_MODULE_SBUS_GPIO_PinSource INTMODULE_HEARTBEAT_EXTI_PinSource + #define TRAINER_MODULE_SBUS_DMA_STREAM DMA2_Stream1 + #define TRAINER_MODULE_SBUS_DMA_CHANNEL DMA_Channel_5 #endif // USB diff --git a/radio/src/targets/taranis/trainer_driver.cpp b/radio/src/targets/taranis/trainer_driver.cpp index 92977c059..0e95f2a59 100644 --- a/radio/src/targets/taranis/trainer_driver.cpp +++ b/radio/src/targets/taranis/trainer_driver.cpp @@ -21,7 +21,7 @@ #include "opentx.h" #if defined(TRAINER_MODULE_SBUS_USART) -DMAFifo<32> heartbeatFifo __DMA (TRAINER_MODULE_SBUS_DMA_Stream); +DMAFifo<32> trainerSbusFifo __DMA (TRAINER_MODULE_SBUS_DMA_STREAM); #endif void trainerSendNextFrame(); @@ -165,10 +165,10 @@ extern "C" void TRAINER_TIMER_IRQHandler() } #endif -#if defined(TRAINER_MODULE_CPPM) - if ((TRAINER_TIMER->DIER & TIM_DIER_CC2IE) && (TRAINER_TIMER->SR & TIM_SR_CC2IF)) { +#if defined(TRAINER_MODULE_CPPM) && !defined(TRAINER_MODULE_CPPM_TIMER_IRQHandler) + if ((TRAINER_TIMER->DIER & TRAINER_MODULE_CPPM_INTERRUPT_ENABLE) && (TRAINER_TIMER->SR & TRAINER_MODULE_CPPM_INTERRUPT_FLAG)) { // capture mode on heartbeat pin (external module) - capture = TRAINER_TIMER->CCR2; + capture = TRAINER_MODULE_CPPM_COUNTER_REGISTER; if (currentTrainerMode == TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE) { doCapture = true; } @@ -202,6 +202,26 @@ extern "C" void TRAINER_TIMER_IRQHandler() #endif } +#if defined(TRAINER_MODULE_CPPM_TIMER_IRQHandler) +extern "C" void TRAINER_MODULE_CPPM_TIMER_IRQHandler() +{ + uint16_t capture = 0; + bool doCapture = false; + + if ((TRAINER_MODULE_CPPM_TIMER->DIER & TRAINER_MODULE_CPPM_INTERRUPT_ENABLE) && (TRAINER_MODULE_CPPM_TIMER->SR & TRAINER_MODULE_CPPM_INTERRUPT_FLAG)) { + // capture mode on external module + capture = TRAINER_MODULE_CPPM_COUNTER_REGISTER; + if (currentTrainerMode == TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE) { + doCapture = true; + } + } + + if (doCapture) { + captureTrainerPulses(capture); + } +} +#endif + #if defined(TRAINER_MODULE_CPPM) void init_trainer_module_cppm() { @@ -217,24 +237,28 @@ void init_trainer_module_cppm() GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(TRAINER_MODULE_CPPM_GPIO, &GPIO_InitStructure); - TRAINER_TIMER->ARR = 0xFFFF; - TRAINER_TIMER->PSC = (PERI1_FREQUENCY * TIMER_MULT_APB1) / 2000000 - 1; // 0.5uS - TRAINER_TIMER->CR2 = 0; - TRAINER_TIMER->CCMR1 = TIM_CCMR1_IC2F_0 | TIM_CCMR1_IC2F_1 | TIM_CCMR1_CC2S_0; - TRAINER_TIMER->CCER = TIM_CCER_CC2E; - TRAINER_TIMER->SR &= ~TIM_SR_CC2IF; // Clear flag - TRAINER_TIMER->DIER |= TIM_DIER_CC2IE; - TRAINER_TIMER->CR1 = TIM_CR1_CEN; + TRAINER_MODULE_CPPM_TIMER->ARR = 0xFFFF; + TRAINER_MODULE_CPPM_TIMER->PSC = (PERI1_FREQUENCY * TIMER_MULT_APB1) / 2000000 - 1; // 0.5uS + TRAINER_MODULE_CPPM_TIMER->CR2 = 0; +#if defined(TRAINER_MODULE_CPPM_CCMR1) + TRAINER_MODULE_CPPM_TIMER->CCMR1 = TRAINER_MODULE_CPPM_CCMR1; +#elif defined(TRAINER_MODULE_CPPM_CCMR2) + TRAINER_MODULE_CPPM_TIMER->CCMR2 = TRAINER_MODULE_CPPM_CCMR2; +#endif + TRAINER_MODULE_CPPM_TIMER->CCER = TRAINER_MODULE_CPPM_CCER; + TRAINER_MODULE_CPPM_TIMER->SR &= ~TRAINER_MODULE_CPPM_INTERRUPT_FLAG; // Clear flag + TRAINER_MODULE_CPPM_TIMER->DIER |= TRAINER_MODULE_CPPM_INTERRUPT_ENABLE; + TRAINER_MODULE_CPPM_TIMER->CR1 = TIM_CR1_CEN; - NVIC_SetPriority(TRAINER_TIMER_IRQn, 7); - NVIC_EnableIRQ(TRAINER_TIMER_IRQn); + NVIC_SetPriority(TRAINER_MODULE_CPPM_TIMER_IRQn, 7); + NVIC_EnableIRQ(TRAINER_MODULE_CPPM_TIMER_IRQn); } void stop_trainer_module_cppm() { - TRAINER_TIMER->DIER = 0; - TRAINER_TIMER->CR1 &= ~TIM_CR1_CEN; // Stop counter - NVIC_DisableIRQ(TRAINER_TIMER_IRQn); // Stop Interrupt + TRAINER_MODULE_CPPM_TIMER->DIER = 0; + TRAINER_MODULE_CPPM_TIMER->CR1 &= ~TIM_CR1_CEN; // Stop counter + NVIC_DisableIRQ(TRAINER_MODULE_CPPM_TIMER_IRQn); // Stop Interrupt if (!IS_EXTERNAL_MODULE_ENABLED()) { EXTERNAL_MODULE_OFF(); @@ -250,14 +274,14 @@ void init_trainer_module_sbus() USART_InitTypeDef USART_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; - GPIO_PinAFConfig(GPIOC, TRAINER_MODULE_CPPM_GPIO_PinSource, TRAINER_MODULE_SBUS_GPIO_AF); + GPIO_PinAFConfig(TRAINER_MODULE_SBUS_GPIO, TRAINER_MODULE_SBUS_GPIO_PinSource, TRAINER_MODULE_SBUS_GPIO_AF); - GPIO_InitStructure.GPIO_Pin = TRAINER_MODULE_CPPM_GPIO_PIN; + GPIO_InitStructure.GPIO_Pin = TRAINER_MODULE_SBUS_GPIO_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; - GPIO_Init(TRAINER_MODULE_CPPM_GPIO, &GPIO_InitStructure); + GPIO_Init(TRAINER_MODULE_SBUS_GPIO, &GPIO_InitStructure); USART_InitStructure.USART_BaudRate = 100000; USART_InitStructure.USART_WordLength = USART_WordLength_9b; @@ -268,14 +292,14 @@ void init_trainer_module_sbus() USART_Init(TRAINER_MODULE_SBUS_USART, &USART_InitStructure); DMA_InitTypeDef DMA_InitStructure; - heartbeatFifo.clear(); + trainerSbusFifo.clear(); USART_ITConfig(TRAINER_MODULE_SBUS_USART, USART_IT_RXNE, DISABLE); USART_ITConfig(TRAINER_MODULE_SBUS_USART, USART_IT_TXE, DISABLE); - DMA_InitStructure.DMA_Channel = TRAINER_MODULE_SBUS_DMA_Channel; + DMA_InitStructure.DMA_Channel = TRAINER_MODULE_SBUS_DMA_CHANNEL; DMA_InitStructure.DMA_PeripheralBaseAddr = CONVERT_PTR_UINT(&TRAINER_MODULE_SBUS_USART->DR); - DMA_InitStructure.DMA_Memory0BaseAddr = CONVERT_PTR_UINT(heartbeatFifo.buffer()); + DMA_InitStructure.DMA_Memory0BaseAddr = CONVERT_PTR_UINT(trainerSbusFifo.buffer()); DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; - DMA_InitStructure.DMA_BufferSize = heartbeatFifo.size(); + DMA_InitStructure.DMA_BufferSize = trainerSbusFifo.size(); DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; @@ -286,19 +310,18 @@ void init_trainer_module_sbus() DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; - DMA_Init(TRAINER_MODULE_SBUS_DMA_Stream, &DMA_InitStructure); + DMA_Init(TRAINER_MODULE_SBUS_DMA_STREAM, &DMA_InitStructure); USART_DMACmd(TRAINER_MODULE_SBUS_USART, USART_DMAReq_Rx, ENABLE); USART_Cmd(TRAINER_MODULE_SBUS_USART, ENABLE); - DMA_Cmd(TRAINER_MODULE_SBUS_DMA_Stream, ENABLE); + DMA_Cmd(TRAINER_MODULE_SBUS_DMA_STREAM, ENABLE); } void stop_trainer_module_sbus() { - DMA_Cmd(TRAINER_MODULE_SBUS_DMA_Stream, DISABLE); + DMA_Cmd(TRAINER_MODULE_SBUS_DMA_STREAM, DISABLE); USART_Cmd(TRAINER_MODULE_SBUS_USART, DISABLE); USART_DMACmd(TRAINER_MODULE_SBUS_USART, USART_DMAReq_Rx, DISABLE); - DMA_DeInit(TRAINER_MODULE_SBUS_DMA_Stream); - NVIC_DisableIRQ(TRAINER_MODULE_SBUS_USART_IRQn); + DMA_DeInit(TRAINER_MODULE_SBUS_DMA_STREAM); if (!IS_EXTERNAL_MODULE_ENABLED()) { EXTERNAL_MODULE_OFF(); @@ -306,13 +329,16 @@ void stop_trainer_module_sbus() } #endif +uint32_t ccount = 0; + #if defined(SBUS) int sbusGetByte(uint8_t * byte) { switch (currentTrainerMode) { #if defined(TRAINER_MODULE_SBUS_USART) case TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE: - return heartbeatFifo.pop(*byte); + ccount++; + return trainerSbusFifo.pop(*byte); #endif #if defined(AUX_SERIAL_USART) case TRAINER_MODE_MASTER_BATTERY_COMPARTMENT: diff --git a/radio/src/tasks.cpp b/radio/src/tasks.cpp index 140e4676c..12685157c 100644 --- a/radio/src/tasks.cpp +++ b/radio/src/tasks.cpp @@ -107,8 +107,8 @@ TASK_FUNCTION(mixerTask) s_pulses_paused = true; while (1) { -#if defined(PCBX9D) || defined(PCBX7) - // SBUS on Hearbeat PIN (which is a serial RX) +#if defined(PCBTARANIS) && defined(SBUS) + // SBUS trainer processSbusInput(); #endif diff --git a/radio/src/translations/cz.h.txt b/radio/src/translations/cz.h.txt index a7834f583..178fa87d9 100644 --- a/radio/src/translations/cz.h.txt +++ b/radio/src/translations/cz.h.txt @@ -859,7 +859,7 @@ #define TR_BLUETOOTH_PIN_CODE TR(INDENT "PIN kód", "PIN kód") #define TR_BAUDRATE "Baudrate BT" #define LEN_BLUETOOTH_MODES "\012" -#if defined(PCBX9E) && !defined(USEHORUSBT) +#if defined(PCBX9E) #define TR_BLUETOOTH_MODES "---\0 ""Povoleno\0 " #else #define TR_BLUETOOTH_MODES "---\0 ""Telemetrie""Trenér\0 " diff --git a/radio/src/translations/de.h.txt b/radio/src/translations/de.h.txt index 170e41596..fc8e65ce4 100644 --- a/radio/src/translations/de.h.txt +++ b/radio/src/translations/de.h.txt @@ -866,7 +866,7 @@ #define TR_BLUETOOTH_PIN_CODE TR(INDENT "PIN code", "PIN code") #define TR_BAUDRATE "BT Baudrate" #define LEN_BLUETOOTH_MODES "\011" -#if defined(PCBX9E) && !defined(USEHORUSBT) +#if defined(PCBX9E) #define TR_BLUETOOTH_MODES "---\0 ""Enabled\0 " #else #define TR_BLUETOOTH_MODES "---\0 ""Telemetry""Trainer\0" diff --git a/radio/src/translations/en.h.txt b/radio/src/translations/en.h.txt index 2e8b2f8a6..4c85f0adb 100644 --- a/radio/src/translations/en.h.txt +++ b/radio/src/translations/en.h.txt @@ -861,7 +861,7 @@ #define TR_BLUETOOTH_PIN_CODE TR(INDENT "PIN code", "PIN code") #define TR_BAUDRATE "BT Baudrate" #define LEN_BLUETOOTH_MODES "\011" -#if defined(PCBX9E) && !defined(USEHORUSBT) +#if defined(PCBX9E) #define TR_BLUETOOTH_MODES "---\0 ""Enabled\0 " #else #define TR_BLUETOOTH_MODES "---\0 ""Telemetry""Trainer\0" diff --git a/radio/src/translations/es.h.txt b/radio/src/translations/es.h.txt index 0f3812097..fca430329 100644 --- a/radio/src/translations/es.h.txt +++ b/radio/src/translations/es.h.txt @@ -881,7 +881,7 @@ #define TR_BLUETOOTH_PIN_CODE TR(INDENT "PIN code", "PIN code") #define TR_BAUDRATE "BT Baudrate" #define LEN_BLUETOOTH_MODES "\011" -#if defined(PCBX9E) && !defined(USEHORUSBT) +#if defined(PCBX9E) #define TR_BLUETOOTH_MODES "---\0 ""Enabled\0 " #else #define TR_BLUETOOTH_MODES "---\0 ""Telemetry""Trainer\0" diff --git a/radio/src/translations/fi.h.txt b/radio/src/translations/fi.h.txt index ed4770796..f158f3b9d 100644 --- a/radio/src/translations/fi.h.txt +++ b/radio/src/translations/fi.h.txt @@ -874,7 +874,7 @@ #define TR_BLUETOOTH_PIN_CODE TR(INDENT "PIN code", "PIN code") #define TR_BAUDRATE "BT Baudrate" #define LEN_BLUETOOTH_MODES "\011" -#if defined(PCBX9E) && !defined(USEHORUSBT) +#if defined(PCBX9E) #define TR_BLUETOOTH_MODES "---\0 ""Enabled\0 " #else #define TR_BLUETOOTH_MODES "---\0 ""Telemetry""Trainer\0" diff --git a/radio/src/translations/fr.h.txt b/radio/src/translations/fr.h.txt index 32720e0c3..ae8addb78 100644 --- a/radio/src/translations/fr.h.txt +++ b/radio/src/translations/fr.h.txt @@ -876,7 +876,7 @@ #define TR_BLUETOOTH_PIN_CODE TR(INDENT "PIN code", "PIN code") #define TR_BAUDRATE "Baudrate BT" #define LEN_BLUETOOTH_MODES "\012" -#if defined(PCBX9E) && !defined(USEHORUSBT) +#if defined(PCBX9E) #define TR_BLUETOOTH_MODES "---\0 ""Activé\0 " #else #define TR_BLUETOOTH_MODES "---\0 ""Télémétrie""Ecolage\0" diff --git a/radio/src/translations/it.h.txt b/radio/src/translations/it.h.txt index 3093eceec..2679823b0 100644 --- a/radio/src/translations/it.h.txt +++ b/radio/src/translations/it.h.txt @@ -875,7 +875,7 @@ #define TR_BLUETOOTH_PIN_CODE TR(INDENT "PIN code", "PIN code") #define TR_BAUDRATE "BT Baudrate" #define LEN_BLUETOOTH_MODES "\011" -#if defined(PCBX9E) && !defined(USEHORUSBT) +#if defined(PCBX9E) #define TR_BLUETOOTH_MODES "---\0 ""Enabled\0 " #else #define TR_BLUETOOTH_MODES "---\0 ""Telemetry""Trainer\0" diff --git a/radio/src/translations/nl.h.txt b/radio/src/translations/nl.h.txt index a83e8aeef..6aa47e53a 100644 --- a/radio/src/translations/nl.h.txt +++ b/radio/src/translations/nl.h.txt @@ -864,7 +864,7 @@ TR_GYR_VSRCRAW #define TR_BLUETOOTH_PIN_CODE TR(INDENT "PIN code", "PIN code") #define TR_BAUDRATE "BT Baudrate" #define LEN_BLUETOOTH_MODES "\011" -#if defined(PCBX9E) && !defined(USEHORUSBT) +#if defined(PCBX9E) #define TR_BLUETOOTH_MODES "---\0 ""Enabled\0 " #else #define TR_BLUETOOTH_MODES "---\0 ""Telemetry""Trainer\0" diff --git a/radio/src/translations/pl.h.txt b/radio/src/translations/pl.h.txt index 65f183bff..18c10b70e 100644 --- a/radio/src/translations/pl.h.txt +++ b/radio/src/translations/pl.h.txt @@ -875,7 +875,7 @@ #define TR_BLUETOOTH_PIN_CODE TR(INDENT "PIN code", "PIN code") #define TR_BAUDRATE "Prędkość BT" #define LEN_BLUETOOTH_MODES "\011" -#if defined(PCBX9E) && !defined(USEHORUSBT) +#if defined(PCBX9E) #define TR_BLUETOOTH_MODES "---\0 ""Enabled\0 " #else #define TR_BLUETOOTH_MODES "---\0 ""Telemetry""Trainer\0" diff --git a/radio/src/translations/pt.h.txt b/radio/src/translations/pt.h.txt index 0c9064ce3..0b96c237a 100644 --- a/radio/src/translations/pt.h.txt +++ b/radio/src/translations/pt.h.txt @@ -865,7 +865,7 @@ #define TR_BLUETOOTH_PIN_CODE TR(INDENT "PIN code", "PIN code") #define TR_BAUDRATE "BT Baudrate" #define LEN_BLUETOOTH_MODES "\011" -#if defined(PCBX9E) && !defined(USEHORUSBT) +#if defined(PCBX9E) #define TR_BLUETOOTH_MODES "---\0 ""Enabled\0 " #else #define TR_BLUETOOTH_MODES "---\0 ""Telemetry""Trainer\0" diff --git a/radio/src/translations/se.h.txt b/radio/src/translations/se.h.txt index 4d6096338..7ffad8438 100644 --- a/radio/src/translations/se.h.txt +++ b/radio/src/translations/se.h.txt @@ -875,7 +875,7 @@ #define TR_BLUETOOTH_PIN_CODE TR(INDENT "PIN code", "PIN code") #define TR_BAUDRATE "BT Baudrate" #define LEN_BLUETOOTH_MODES "\011" -#if defined(PCBX9E) && !defined(USEHORUSBT) +#if defined(PCBX9E) #define TR_BLUETOOTH_MODES "---\0 ""Enabled\0 " #else #define TR_BLUETOOTH_MODES "---\0 ""Telemetry""Trainer\0" From e6dce52ff9d8724b4a223cf4f93e2ae770ea8c79 Mon Sep 17 00:00:00 2001 From: 3djc Date: Fri, 14 Jun 2019 21:21:16 +0200 Subject: [PATCH 030/350] Rework LUA key handling, should auto adapt to new radios (#6502) --- radio/src/lua/api_general.cpp | 134 +++++++++++++++++----------------- 1 file changed, 68 insertions(+), 66 deletions(-) diff --git a/radio/src/lua/api_general.cpp b/radio/src/lua/api_general.cpp index 8aefc3068..a256856e6 100644 --- a/radio/src/lua/api_general.cpp +++ b/radio/src/lua/api_general.cpp @@ -53,6 +53,12 @@ #define FIND_FIELD_DESC 0x01 +#define ADD_KEY_EVT(xxx, yyy) \ + { "EVT_"#xxx"_FIRST", EVT_KEY_FIRST(yyy) }, \ + { "EVT_"#xxx"_BREAK", EVT_KEY_BREAK(yyy) }, \ + { "EVT_"#xxx"_LONG", EVT_KEY_LONG(yyy) }, \ + { "EVT_"#xxx"_REPT", EVT_KEY_REPT(yyy) } + /*luadoc @function getVersion() @@ -1691,77 +1697,73 @@ const luaR_value_entry opentxConstants[] = { { "EVT_MODEL_FIRST", EVT_KEY_FIRST(KEY_MODEL) }, { "EVT_SYS_FIRST", EVT_KEY_FIRST(KEY_RADIO) }, { "EVT_RTN_FIRST", EVT_KEY_FIRST(KEY_EXIT) }, -#elif defined(PCBXLITE) - { "EVT_DOWN_FIRST", EVT_KEY_FIRST(KEY_DOWN) }, - { "EVT_UP_FIRST", EVT_KEY_FIRST(KEY_UP) }, - { "EVT_LEFT_FIRST", EVT_KEY_FIRST(KEY_LEFT) }, - { "EVT_RIGHT_FIRST", EVT_KEY_FIRST(KEY_RIGHT) }, - { "EVT_SHIFT_FIRST", EVT_KEY_FIRST(KEY_SHIFT) }, - { "EVT_DOWN_BREAK", EVT_KEY_BREAK(KEY_DOWN) }, - { "EVT_UP_BREAK", EVT_KEY_BREAK(KEY_UP) }, - { "EVT_LEFT_BREAK", EVT_KEY_BREAK(KEY_LEFT) }, - { "EVT_RIGHT_BREAK", EVT_KEY_BREAK(KEY_RIGHT) }, - { "EVT_SHIFT_BREAK", EVT_KEY_BREAK(KEY_SHIFT) }, - { "EVT_DOWN_LONG", EVT_KEY_LONG(KEY_DOWN) }, - { "EVT_UP_LONG", EVT_KEY_LONG(KEY_UP) }, - { "EVT_LEFT_LONG", EVT_KEY_LONG(KEY_LEFT) }, - { "EVT_RIGHT_LONG", EVT_KEY_LONG(KEY_RIGHT) }, - { "EVT_SHIFT_LONG", EVT_KEY_LONG(KEY_SHIFT) }, - { "EVT_DOWN_REPT", EVT_KEY_REPT(KEY_DOWN) }, - { "EVT_UP_REPT", EVT_KEY_REPT(KEY_UP) }, - { "EVT_LEFT_REPT", EVT_KEY_REPT(KEY_LEFT) }, - { "EVT_RIGHT_REPT", EVT_KEY_REPT(KEY_RIGHT) }, - { "FORCE", FORCE }, - { "ERASE", ERASE }, - { "ROUND", ROUND }, -#elif defined(RADIO_T12) - { "EVT_DOWN_FIRST", EVT_KEY_FIRST(KEY_DOWN) }, - { "EVT_UP_FIRST", EVT_KEY_FIRST(KEY_UP) }, - { "EVT_LEFT_FIRST", EVT_KEY_FIRST(KEY_LEFT) }, - { "EVT_RIGHT_FIRST", EVT_KEY_FIRST(KEY_RIGHT) }, - { "EVT_DOWN_BREAK", EVT_KEY_BREAK(KEY_DOWN) }, - { "EVT_UP_BREAK", EVT_KEY_BREAK(KEY_UP) }, - { "EVT_LEFT_BREAK", EVT_KEY_BREAK(KEY_LEFT) }, - { "EVT_RIGHT_BREAK", EVT_KEY_BREAK(KEY_RIGHT) }, - { "EVT_DOWN_LONG", EVT_KEY_LONG(KEY_DOWN) }, - { "EVT_UP_LONG", EVT_KEY_LONG(KEY_UP) }, - { "EVT_LEFT_LONG", EVT_KEY_LONG(KEY_LEFT) }, - { "EVT_RIGHT_LONG", EVT_KEY_LONG(KEY_RIGHT) }, - { "EVT_DOWN_REPT", EVT_KEY_REPT(KEY_DOWN) }, - { "EVT_UP_REPT", EVT_KEY_REPT(KEY_UP) }, - { "EVT_LEFT_REPT", EVT_KEY_REPT(KEY_LEFT) }, - { "EVT_RIGHT_REPT", EVT_KEY_REPT(KEY_RIGHT) }, - { "FORCE", FORCE }, - { "ERASE", ERASE }, - { "ROUND", ROUND }, -#elif defined(PCBTARANIS) - { "EVT_MENU_BREAK", EVT_KEY_BREAK(KEY_MENU) }, - { "EVT_MENU_LONG", EVT_KEY_LONG(KEY_MENU) }, - { "EVT_PAGE_BREAK", EVT_KEY_BREAK(KEY_PAGE) }, - { "EVT_PAGE_LONG", EVT_KEY_LONG(KEY_PAGE) }, - { "EVT_PLUS_BREAK", EVT_KEY_BREAK(KEY_PLUS) }, - { "EVT_MINUS_BREAK", EVT_KEY_BREAK(KEY_MINUS) }, - { "EVT_PLUS_FIRST", EVT_KEY_FIRST(KEY_PLUS) }, - { "EVT_MINUS_FIRST", EVT_KEY_FIRST(KEY_MINUS) }, - { "EVT_PLUS_REPT", EVT_KEY_REPT(KEY_PLUS) }, - { "EVT_MINUS_REPT", EVT_KEY_REPT(KEY_MINUS) }, -#if LCD_DEPTH > 1 - { "FILL_WHITE", FILL_WHITE }, - { "GREY_DEFAULT", GREY_DEFAULT }, -#endif - { "FORCE", FORCE }, - { "ERASE", ERASE }, - { "ROUND", ROUND }, -#endif - { "EVT_ENTER_BREAK", EVT_KEY_BREAK(KEY_ENTER) }, - { "EVT_ENTER_LONG", EVT_KEY_LONG(KEY_ENTER) }, +#elif defined(KEYS_GPIO_REG_EXIT) { "EVT_EXIT_BREAK", EVT_KEY_BREAK(KEY_EXIT) }, +#endif + +#if defined(KEYS_GPIO_REG_ENTER) + ADD_KEY_EVT(ENTER, KEY_ENTER), +#endif + +#if defined(KEYS_GPIO_REG_RIGHT) && defined(NAVIGATION_HORUS) + ADD_KEY_EVT(TELEM, KEY_TELEM), +#elif defined(KEYS_GPIO_REG_RIGHT) + ADD_KEY_EVT(RIGHT, KEY_RIGHT), +#endif + +#if defined(KEYS_GPIO_REG_UP) && defined(NAVIGATION_HORUS) + ADD_KEY_EVT(MODEL, KEY_MODEL), +#elif defined(KEYS_GPIO_REG_UP) + ADD_KEY_EVT(UP, KEY_UP), +#endif + +#if defined(KEYS_GPIO_REG_LEFT) && defined(NAVIGATION_HORUS) + ADD_KEY_EVT(SYS, KEY_RADIO), +#elif defined(KEYS_GPIO_REG_LEFT) + ADD_KEY_EVT(LEFT, KEY_LEFT), +#endif + +#if defined(KEYS_GPIO_REG_PGUP) + ADD_KEY_EVT(PAGEUP, KEY_PGUP), +#endif + +#if defined(KEYS_GPIO_REG_PGDN) + ADD_KEY_EVT(PAGEDN, KEY_PGDN), +#endif + +#if defined(KEYS_GPIO_REG_PAGE) + ADD_KEY_EVT(PAGE, KEY_PAGE), +#endif + +#if defined(KEYS_GPIO_REG_SHIFT) + ADD_KEY_EVT(SHIFT, KEY_SHIFT), +#endif + +#if defined(KEYS_GPIO_REG_PLUS) + ADD_KEY_EVT(PLUS, KEY_PLUS), +#endif + +#if defined(KEYS_GPIO_REG_MINUS) + ADD_KEY_EVT(MINUS, KEY_MINUS), +#endif + #if defined(ROTARY_ENCODER_NAVIGATION) - { "EVT_ROT_BREAK", EVT_KEY_BREAK(KEY_ENTER) }, - { "EVT_ROT_LONG", EVT_KEY_LONG(KEY_ENTER) }, + ADD_KEY_EVT(ROT, KEY_ENTER), { "EVT_ROT_LEFT", EVT_ROTARY_LEFT }, { "EVT_ROT_RIGHT", EVT_ROTARY_RIGHT }, #endif + +#if LCD_DEPTH > 1 && !defined(COLORLCD) + { "FILL_WHITE", FILL_WHITE }, + { "GREY_DEFAULT", GREY_DEFAULT }, +#endif + +#if LCD_W <= 212 + { "FORCE", FORCE }, + { "ERASE", ERASE }, + { "ROUND", ROUND }, +#endif + { "SOLID", SOLID }, { "DOTTED", DOTTED }, { "LCD_W", LCD_W }, From c155830430d266aa8471eaeef88900210b07d34c Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Fri, 14 Jun 2019 21:23:40 +0200 Subject: [PATCH 031/350] Cosmetics --- radio/src/lua/api_general.cpp | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/radio/src/lua/api_general.cpp b/radio/src/lua/api_general.cpp index a256856e6..84270b66a 100644 --- a/radio/src/lua/api_general.cpp +++ b/radio/src/lua/api_general.cpp @@ -53,7 +53,7 @@ #define FIND_FIELD_DESC 0x01 -#define ADD_KEY_EVT(xxx, yyy) \ +#define KEY_EVENTS(xxx, yyy) \ { "EVT_"#xxx"_FIRST", EVT_KEY_FIRST(yyy) }, \ { "EVT_"#xxx"_BREAK", EVT_KEY_BREAK(yyy) }, \ { "EVT_"#xxx"_LONG", EVT_KEY_LONG(yyy) }, \ @@ -1702,53 +1702,53 @@ const luaR_value_entry opentxConstants[] = { #endif #if defined(KEYS_GPIO_REG_ENTER) - ADD_KEY_EVT(ENTER, KEY_ENTER), + KEY_EVENTS(ENTER, KEY_ENTER), #endif #if defined(KEYS_GPIO_REG_RIGHT) && defined(NAVIGATION_HORUS) - ADD_KEY_EVT(TELEM, KEY_TELEM), + KEY_EVENTS(TELEM, KEY_TELEM), #elif defined(KEYS_GPIO_REG_RIGHT) - ADD_KEY_EVT(RIGHT, KEY_RIGHT), + KEY_EVENTS(RIGHT, KEY_RIGHT), #endif #if defined(KEYS_GPIO_REG_UP) && defined(NAVIGATION_HORUS) - ADD_KEY_EVT(MODEL, KEY_MODEL), + KEY_EVENTS(MODEL, KEY_MODEL), #elif defined(KEYS_GPIO_REG_UP) - ADD_KEY_EVT(UP, KEY_UP), + KEY_EVENTS(UP, KEY_UP), #endif #if defined(KEYS_GPIO_REG_LEFT) && defined(NAVIGATION_HORUS) - ADD_KEY_EVT(SYS, KEY_RADIO), + KEY_EVENTS(SYS, KEY_RADIO), #elif defined(KEYS_GPIO_REG_LEFT) - ADD_KEY_EVT(LEFT, KEY_LEFT), + KEY_EVENTS(LEFT, KEY_LEFT), #endif #if defined(KEYS_GPIO_REG_PGUP) - ADD_KEY_EVT(PAGEUP, KEY_PGUP), + KEY_EVENTS(PAGEUP, KEY_PGUP), #endif #if defined(KEYS_GPIO_REG_PGDN) - ADD_KEY_EVT(PAGEDN, KEY_PGDN), + KEY_EVENTS(PAGEDN, KEY_PGDN), #endif #if defined(KEYS_GPIO_REG_PAGE) - ADD_KEY_EVT(PAGE, KEY_PAGE), + KEY_EVENTS(PAGE, KEY_PAGE), #endif #if defined(KEYS_GPIO_REG_SHIFT) - ADD_KEY_EVT(SHIFT, KEY_SHIFT), + KEY_EVENTS(SHIFT, KEY_SHIFT), #endif #if defined(KEYS_GPIO_REG_PLUS) - ADD_KEY_EVT(PLUS, KEY_PLUS), + KEY_EVENTS(PLUS, KEY_PLUS), #endif #if defined(KEYS_GPIO_REG_MINUS) - ADD_KEY_EVT(MINUS, KEY_MINUS), + KEY_EVENTS(MINUS, KEY_MINUS), #endif #if defined(ROTARY_ENCODER_NAVIGATION) - ADD_KEY_EVT(ROT, KEY_ENTER), + KEY_EVENTS(ROT, KEY_ENTER), { "EVT_ROT_LEFT", EVT_ROTARY_LEFT }, { "EVT_ROT_RIGHT", EVT_ROTARY_RIGHT }, #endif From 8c56a131ede013104bc89f6cf2a82063faeb5061 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Fri, 14 Jun 2019 21:52:27 +0200 Subject: [PATCH 032/350] Warning fix --- radio/src/targets/taranis/intmodule_pulses_driver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radio/src/targets/taranis/intmodule_pulses_driver.cpp b/radio/src/targets/taranis/intmodule_pulses_driver.cpp index 822bb0b36..29a85674f 100644 --- a/radio/src/targets/taranis/intmodule_pulses_driver.cpp +++ b/radio/src/targets/taranis/intmodule_pulses_driver.cpp @@ -35,7 +35,7 @@ void intmoduleStop() #if defined(DEBUG_LATENCY) #define HEARBEAT_OFFSET unsigned(5500 + g_model.flightModeData[0].gvars[0] * 100) #else -constexpr int HEARBEAT_OFFSET = 5500; +constexpr unsigned HEARBEAT_OFFSET = 5500; #endif void intmoduleSendNextFrame() From 43bb79f3e9e17cf1978bacb02abf86e3f9fb46cd Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Sun, 16 Jun 2019 18:56:45 +0200 Subject: [PATCH 033/350] Update CREDITS.txt --- CREDITS.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CREDITS.txt b/CREDITS.txt index 2a61c5e0e..81d4f33e8 100644 --- a/CREDITS.txt +++ b/CREDITS.txt @@ -1517,3 +1517,4 @@ Jean Gaillard Michel Garbarino For Our Better World Lothar Herrl +James Rhodes From 76a21f91602a0ed774f53a13b6fca9f933ef83a6 Mon Sep 17 00:00:00 2001 From: 3djc Date: Mon, 17 Jun 2019 10:41:36 +0200 Subject: [PATCH 034/350] Menu key was missing --- radio/src/lua/api_general.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/radio/src/lua/api_general.cpp b/radio/src/lua/api_general.cpp index 84270b66a..111d17c6c 100644 --- a/radio/src/lua/api_general.cpp +++ b/radio/src/lua/api_general.cpp @@ -1705,6 +1705,10 @@ const luaR_value_entry opentxConstants[] = { KEY_EVENTS(ENTER, KEY_ENTER), #endif +#if defined(KEYS_GPIO_REG_MENU) + KEY_EVENTS(MENU, KEY_MENU), +#endif + #if defined(KEYS_GPIO_REG_RIGHT) && defined(NAVIGATION_HORUS) KEY_EVENTS(TELEM, KEY_TELEM), #elif defined(KEYS_GPIO_REG_RIGHT) From 196da35c6ea3281f4c60161832087a9bde994212 Mon Sep 17 00:00:00 2001 From: WismyYao Date: Mon, 17 Jun 2019 04:58:13 -0500 Subject: [PATCH 035/350] Wismy/bt name fix (#6511) Change bluetooth name to lowercase --- radio/src/bluetooth.cpp | 12 ++++-------- radio/src/opentx.h | 1 + radio/src/strhelpers.cpp | 9 +++++++++ 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/radio/src/bluetooth.cpp b/radio/src/bluetooth.cpp index f268b180a..ebcd4fa4c 100644 --- a/radio/src/bluetooth.cpp +++ b/radio/src/bluetooth.cpp @@ -311,12 +311,12 @@ void Bluetooth::wakeup(void) uint8_t len = ZLEN(g_eeGeneral.bluetoothName); if (len > 0) { for (int i = 0; i < len; i++) { - *cur++ = zchar2char(g_eeGeneral.bluetoothName[i]); + *cur++ = char2lower(zchar2char(g_eeGeneral.bluetoothName[i])); } *cur = '\0'; } else { - cur = strAppend(cur, "Taranis-X9E"); + cur = strAppend(cur, FLAVOUR); } writeString(command); state = BLUETOOTH_WAIT_TTM; @@ -414,16 +414,12 @@ void Bluetooth::wakeup() uint8_t len = ZLEN(g_eeGeneral.bluetoothName); if (len > 0) { for (int i = 0; i < len; i++) { - *cur++ = zchar2char(g_eeGeneral.bluetoothName[i]); + *cur++ = char2lower(zchar2char(g_eeGeneral.bluetoothName[i])); } *cur = '\0'; } else { -#if defined(PCBHORUS) - cur = strAppend(cur, "Horus"); -#else - cur = strAppend(cur, "Taranis"); -#endif + cur = strAppend(cur, FLAVOUR); } writeString(command); state = BLUETOOTH_STATE_NAME_SENT; diff --git a/radio/src/opentx.h b/radio/src/opentx.h index da3487f9c..f45e254a6 100644 --- a/radio/src/opentx.h +++ b/radio/src/opentx.h @@ -433,6 +433,7 @@ extern struct t_inactivity inactivity; char hex2zchar(uint8_t hex); char zchar2char(int8_t idx); +char char2lower(char c); int8_t char2zchar(char c); void str2zchar(char *dest, const char *src, int size); int zchar2str(char *dest, const char *src, int size); diff --git a/radio/src/strhelpers.cpp b/radio/src/strhelpers.cpp index c9a595248..453cb7f91 100644 --- a/radio/src/strhelpers.cpp +++ b/radio/src/strhelpers.cpp @@ -44,6 +44,15 @@ char zchar2char(int8_t idx) return ' '; } +char char2lower(char c) +{ + if(c >= 'A' && c <= 'Z'){ + return c+32; + } + else + return c; +} + int8_t char2zchar(char c) { if (c == '_') return 37; From 1f1ccf277cbc3afe279be95bf21bd911f7fdf06e Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Mon, 17 Jun 2019 11:59:33 +0200 Subject: [PATCH 036/350] Cosmetics --- radio/src/strhelpers.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/radio/src/strhelpers.cpp b/radio/src/strhelpers.cpp index 453cb7f91..ee42b8fe6 100644 --- a/radio/src/strhelpers.cpp +++ b/radio/src/strhelpers.cpp @@ -46,11 +46,7 @@ char zchar2char(int8_t idx) char char2lower(char c) { - if(c >= 'A' && c <= 'Z'){ - return c+32; - } - else - return c; + return (c >= 'A' && c <= 'Z') ? c + 32 : c; } int8_t char2zchar(char c) From b20e4a6be40f85898d8cb309dc91142136089fd0 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Mon, 17 Jun 2019 12:02:42 +0200 Subject: [PATCH 037/350] Pulses refactoring (another one!) (#6510) Pulses refactoring (another one!) --- radio/src/io/frsky_firmware_update.cpp | 35 ++- radio/src/pulses/pulses.cpp | 229 ++++++++---------- radio/src/pulses/pulses.h | 29 ++- radio/src/targets/common/arm/CMakeLists.txt | 1 - .../arm/stm32/intmodule_serial_driver.cpp | 2 +- radio/src/targets/horus/board.h | 16 -- radio/src/targets/horus/extmodule_driver.cpp | 9 +- radio/src/targets/horus/pulses_driver.cpp | 93 ------- radio/src/targets/simu/simpgmspace.cpp | 1 + radio/src/targets/simu/simpgmspace.h | 6 + radio/src/targets/sky9x/board.h | 8 - radio/src/targets/sky9x/pulses_driver.cpp | 81 ++----- radio/src/targets/taranis/CMakeLists.txt | 2 +- radio/src/targets/taranis/board.h | 19 -- .../src/targets/taranis/extmodule_driver.cpp | 16 +- .../taranis/intmodule_pulses_driver.cpp | 9 +- radio/src/targets/taranis/pulses_driver.cpp | 106 -------- radio/src/tasks.cpp | 15 +- 18 files changed, 183 insertions(+), 494 deletions(-) delete mode 100644 radio/src/targets/horus/pulses_driver.cpp delete mode 100644 radio/src/targets/taranis/pulses_driver.cpp diff --git a/radio/src/io/frsky_firmware_update.cpp b/radio/src/io/frsky_firmware_update.cpp index ee3276864..fd3f7fe3c 100644 --- a/radio/src/io/frsky_firmware_update.cpp +++ b/radio/src/io/frsky_firmware_update.cpp @@ -359,15 +359,18 @@ void FrskyDeviceFirmwareUpdate::flashFirmware(const char * filename) { pausePulses(); +#if defined(HARDWARE_INTERNAL_MODULE) uint8_t intPwr = IS_INTERNAL_MODULE_ON(); + INTERNAL_MODULE_OFF(); +#endif + uint8_t extPwr = IS_EXTERNAL_MODULE_ON(); + EXTERNAL_MODULE_OFF(); + + SPORT_UPDATE_POWER_OFF(); drawProgressScreen(getBasename(filename), STR_DEVICE_RESET, 0, 0); - INTERNAL_MODULE_OFF(); - EXTERNAL_MODULE_OFF(); - SPORT_UPDATE_POWER_OFF(); - /* wait 2s off */ watchdogSuspend(2000); RTOS_WAIT_MS(2000); @@ -399,13 +402,16 @@ void FrskyDeviceFirmwareUpdate::flashFirmware(const char * filename) RTOS_WAIT_MS(2000); telemetryClearFifo(); +#if defined(HARDWARE_INTERNAL_MODULE) if (intPwr) { INTERNAL_MODULE_ON(); - setupPulses(INTERNAL_MODULE); + setupPulsesInternalModule(); } +#endif + if (extPwr) { EXTERNAL_MODULE_ON(); - setupPulses(EXTERNAL_MODULE); + setupPulsesExternalModule(); } state = SPORT_IDLE; @@ -620,11 +626,14 @@ void FrskyChipFirmwareUpdate::flashFirmware(const char * filename) pausePulses(); +#if defined(HARDWARE_INTERNAL_MODULE) uint8_t intPwr = IS_INTERNAL_MODULE_ON(); - uint8_t extPwr = IS_EXTERNAL_MODULE_ON(); - INTERNAL_MODULE_OFF(); +#endif + + uint8_t extPwr = IS_EXTERNAL_MODULE_ON(); EXTERNAL_MODULE_OFF(); + SPORT_UPDATE_POWER_OFF(); /* wait 2s off */ @@ -646,7 +655,10 @@ void FrskyChipFirmwareUpdate::flashFirmware(const char * filename) POPUP_INFORMATION(STR_FIRMWARE_UPDATE_SUCCESS); } +#if defined(HARDWARE_INTERNAL_MODULE) INTERNAL_MODULE_OFF(); +#endif + EXTERNAL_MODULE_OFF(); SPORT_UPDATE_POWER_OFF(); @@ -654,13 +666,16 @@ void FrskyChipFirmwareUpdate::flashFirmware(const char * filename) watchdogSuspend(2000); RTOS_WAIT_MS(2000); +#if defined(HARDWARE_INTERNAL_MODULE) if (intPwr) { INTERNAL_MODULE_ON(); - setupPulses(INTERNAL_MODULE); + setupPulsesInternalModule(); } +#endif + if (extPwr) { EXTERNAL_MODULE_ON(); - setupPulses(EXTERNAL_MODULE); + setupPulsesExternalModule(); } resumePulses(); diff --git a/radio/src/pulses/pulses.cpp b/radio/src/pulses/pulses.cpp index 23aaa1072..d5f2589fc 100755 --- a/radio/src/pulses/pulses.cpp +++ b/radio/src/pulses/pulses.cpp @@ -133,76 +133,21 @@ uint8_t getRequiredProtocol(uint8_t module) return protocol; } -void disablePulses(uint8_t module, uint8_t protocol) -{ - // stop existing protocol hardware - - switch (protocol) { -#if defined(PXX1) - case PROTOCOL_CHANNELS_PXX1_PULSES: - disable_pxx1_pulses(module); - break; - -#if defined(INTMODULE_USART) || defined(EXTMODULE_USART) - case PROTOCOL_CHANNELS_PXX1_SERIAL: - disable_pxx1_serial(module); - break; -#endif -#endif - -#if defined(DSM2) - case PROTOCOL_CHANNELS_DSM2_LP45: - case PROTOCOL_CHANNELS_DSM2_DSM2: - case PROTOCOL_CHANNELS_DSM2_DSMX: - disable_serial(module); - break; -#endif - -#if defined(CROSSFIRE) - case PROTOCOL_CHANNELS_CROSSFIRE: - // TODO disable_module_timer(module); - break; -#endif - -#if defined(PXX2) - case PROTOCOL_CHANNELS_PXX2: - disable_pxx2(module); - break; -#endif - -#if defined(MULTIMODULE) - case PROTOCOL_CHANNELS_MULTIMODULE: -#endif - -#if defined(SBUS) - case PROTOCOL_CHANNELS_SBUS: - disable_serial(module); - break; -#endif - -#if defined(PPM) - case PROTOCOL_CHANNELS_PPM: - disable_ppm(module); - break; -#endif - } -} - -void enablePulses(uint8_t module, uint8_t protocol) +void enablePulsesExternalModule(uint8_t protocol) { // start new protocol hardware here switch (protocol) { #if defined(PXX1) case PROTOCOL_CHANNELS_PXX1_PULSES: - init_pxx1_pulses(module); - break; - -#if defined(INTMODULE_USART) || defined(EXTMODULE_USART) - case PROTOCOL_CHANNELS_PXX1_SERIAL: - init_pxx1_serial(module); + extmodulePxx1PulsesStart(); break; #endif + +#if defined(PXX1) && defined(EXTMODULE_USART) + case PROTOCOL_CHANNELS_PXX1_SERIAL: + extmodulePxx1SerialStart(); + break; #endif #if defined(DSM2) @@ -215,13 +160,13 @@ void enablePulses(uint8_t module, uint8_t protocol) #if defined(CROSSFIRE) case PROTOCOL_CHANNELS_CROSSFIRE: - // TODO init_module_timer(module, CROSSFIRE_PERIOD, true); + EXTERNAL_MODULE_ON(); break; #endif #if defined(PXX2) case PROTOCOL_CHANNELS_PXX2: - init_pxx2(module); + extmoduleInvertedSerialStart(PXX2_EXTERNAL_MODULE_BAUDRATE); break; #endif @@ -239,54 +184,7 @@ void enablePulses(uint8_t module, uint8_t protocol) #if defined(PPM) case PROTOCOL_CHANNELS_PPM: - init_ppm(module); - break; -#endif - - default: - // TODO some reworking needed here ... -#if defined(PXX2) - disable_pxx2(module); -#endif - break; - } -} - -void setupPulsesInternalModule(uint8_t protocol) -{ - switch (protocol) { -#if defined(HARDWARE_INTERNAL_MODULE) && defined(PXX1) && !defined(INTMODULE_USART) - case PROTOCOL_CHANNELS_PXX1_PULSES: - intmodulePulsesData.pxx.setupFrame(INTERNAL_MODULE); - scheduleNextMixerCalculation(INTERNAL_MODULE, INTMODULE_PXX_PERIOD); - break; -#endif - -#if defined(PXX1) && defined(INTMODULE_USART) - case PROTOCOL_CHANNELS_PXX1_SERIAL: - intmodulePulsesData.pxx_uart.setupFrame(INTERNAL_MODULE); - scheduleNextMixerCalculation(INTERNAL_MODULE, INTMODULE_PXX_PERIOD); - break; -#endif - -#if defined(PXX2) - case PROTOCOL_CHANNELS_PXX2: - intmodulePulsesData.pxx2.setupFrame(INTERNAL_MODULE); - if (moduleState[INTERNAL_MODULE].mode == MODULE_MODE_SPECTRUM_ANALYSER || moduleState[INTERNAL_MODULE].mode == MODULE_MODE_POWER_METER) { - scheduleNextMixerCalculation(INTERNAL_MODULE, PXX2_TOOLS_PERIOD); - } -#if !defined(INTMODULE_HEARTBEAT) - else { - scheduleNextMixerCalculation(INTERNAL_MODULE, PXX2_PERIOD); - } -#endif - break; -#endif - -#if defined(PCBTARANIS) && defined(INTERNAL_MODULE_PPM) - case PROTOCOL_CHANNELS_PPM: - setupPulsesPPM(&extmodulePulsesData.ppm, g_model.moduleData[INTERNAL_MODULE].channelsStart, g_model.moduleData[INTERNAL_MODULE].channelsCount, g_model.moduleData[INTERNAL_MODULE].ppm.frameLength); - scheduleNextMixerCalculation(INTERNAL_MODULE, PPM_PERIOD(INTERNAL_MODULE)); + extmodulePpmStart(); break; #endif @@ -361,35 +259,112 @@ void setupPulsesExternalModule(uint8_t protocol) } } -void setupPulses(uint8_t module, uint8_t protocol) -{ - switch (module) { #if defined(HARDWARE_INTERNAL_MODULE) - case INTERNAL_MODULE: - setupPulsesInternalModule(protocol); + +void enablePulsesInternalModule(uint8_t protocol) +{ + // start new protocol hardware here + + switch (protocol) { +#if defined(PXX1) && !defined(INTMODULE_USART) + case PROTOCOL_CHANNELS_PXX1_PULSES: + intmodulePxx1PulsesStart(); break; #endif - case EXTERNAL_MODULE: - setupPulsesExternalModule(protocol); +#if defined(PXX1) && defined(INTMODULE_USART) + case PROTOCOL_CHANNELS_PXX1_SERIAL: + intmodulePxx1SerialStart(); + break; +#endif + +#if defined(PXX2) + case PROTOCOL_CHANNELS_PXX2: + intmoduleSerialStart(INTMODULE_PXX_BAUDRATE, true); + break; +#endif + + default: break; } } -bool setupPulses(uint8_t module) +void setupPulsesInternalModule(uint8_t protocol) { - uint8_t protocol = getRequiredProtocol(module); + switch (protocol) { +#if defined(HARDWARE_INTERNAL_MODULE) && defined(PXX1) && !defined(INTMODULE_USART) + case PROTOCOL_CHANNELS_PXX1_PULSES: + intmodulePulsesData.pxx.setupFrame(INTERNAL_MODULE); + scheduleNextMixerCalculation(INTERNAL_MODULE, INTMODULE_PXX_PERIOD); + break; +#endif - heartbeat |= (HEART_TIMER_PULSES << module); +#if defined(PXX1) && defined(INTMODULE_USART) + case PROTOCOL_CHANNELS_PXX1_SERIAL: + intmodulePulsesData.pxx_uart.setupFrame(INTERNAL_MODULE); + scheduleNextMixerCalculation(INTERNAL_MODULE, INTMODULE_PXX_PERIOD); + break; +#endif - if (moduleState[module].protocol != protocol) { - disablePulses(module, moduleState[module].protocol); - moduleState[module].protocol = protocol; - enablePulses(module, protocol); +#if defined(PXX2) + case PROTOCOL_CHANNELS_PXX2: + intmodulePulsesData.pxx2.setupFrame(INTERNAL_MODULE); + if (moduleState[INTERNAL_MODULE].mode == MODULE_MODE_SPECTRUM_ANALYSER || moduleState[INTERNAL_MODULE].mode == MODULE_MODE_POWER_METER) { + scheduleNextMixerCalculation(INTERNAL_MODULE, PXX2_TOOLS_PERIOD); + } +#if !defined(INTMODULE_HEARTBEAT) + else { + scheduleNextMixerCalculation(INTERNAL_MODULE, PXX2_PERIOD); + } +#endif + break; +#endif + +#if defined(PCBTARANIS) && defined(INTERNAL_MODULE_PPM) + case PROTOCOL_CHANNELS_PPM: + setupPulsesPPM(&extmodulePulsesData.ppm, g_model.moduleData[INTERNAL_MODULE].channelsStart, g_model.moduleData[INTERNAL_MODULE].channelsCount, g_model.moduleData[INTERNAL_MODULE].ppm.frameLength); + scheduleNextMixerCalculation(INTERNAL_MODULE, PPM_PERIOD(INTERNAL_MODULE)); + break; +#endif + + default: + break; + } +} + +bool setupPulsesInternalModule() +{ + uint8_t protocol = getRequiredProtocol(INTERNAL_MODULE); + + heartbeat |= (HEART_TIMER_PULSES << INTERNAL_MODULE); + + if (moduleState[INTERNAL_MODULE].protocol != protocol) { + intmoduleStop(); + moduleState[INTERNAL_MODULE].protocol = protocol; + enablePulsesInternalModule(protocol); return false; } else { - setupPulses(module, protocol); + setupPulsesInternalModule(protocol); + return true; + } +} +#endif + +bool setupPulsesExternalModule() +{ + uint8_t protocol = getRequiredProtocol(EXTERNAL_MODULE); + + heartbeat |= (HEART_TIMER_PULSES << EXTERNAL_MODULE); + + if (moduleState[EXTERNAL_MODULE].protocol != protocol) { + extmoduleStop(); + moduleState[EXTERNAL_MODULE].protocol = protocol; + enablePulsesExternalModule(protocol); + return false; + } + else { + setupPulsesExternalModule(protocol); return true; } } diff --git a/radio/src/pulses/pulses.h b/radio/src/pulses/pulses.h index 35c9a6cf1..a6a65ce36 100644 --- a/radio/src/pulses/pulses.h +++ b/radio/src/pulses/pulses.h @@ -302,7 +302,8 @@ union TrainerPulsesData { extern TrainerPulsesData trainerPulsesData; -bool setupPulses(uint8_t module); +bool setupPulsesInternalModule(); +bool setupPulsesExternalModule(); void setupPulsesDSM2(); void setupPulsesCrossfire(); void setupPulsesMultimodule(); @@ -314,28 +315,26 @@ void sendByteDsm2(uint8_t b); void putDsm2Flush(); void putDsm2SerialBit(uint8_t bit); void sendByteSbus(uint8_t b); - -#if defined(HUBSAN) -void Hubsan_Init(); -#endif +void intmodulePxx1PulsesStart(); +void intmodulePxx1SerialStart(); +void extmodulePxx1PulsesStart(); +void extmodulePxx1SerialStart(); +void extmodulePpmStart(); +void intmoduleStop(); +void extmoduleStop(); inline void startPulses() { s_pulses_paused = false; -#if defined(PCBTARANIS) || defined(PCBHORUS) - setupPulses(INTERNAL_MODULE); - setupPulses(EXTERNAL_MODULE); -#else - setupPulses(EXTERNAL_MODULE); +#if defined(HARDWARE_INTERNAL_MODULE) + setupPulsesInternalModule(); #endif -#if defined(PCBSKY9X) - init_ppm(EXTRA_MODULE); -#endif + setupPulsesExternalModule(); -#if defined(HUBSAN) - Hubsan_Init(); +#if defined(HARDWARE_EXTRA_MODULE) + extramodulePpmStart(); #endif } diff --git a/radio/src/targets/common/arm/CMakeLists.txt b/radio/src/targets/common/arm/CMakeLists.txt index da45e0309..90d196f41 100644 --- a/radio/src/targets/common/arm/CMakeLists.txt +++ b/radio/src/targets/common/arm/CMakeLists.txt @@ -197,7 +197,6 @@ set(FIRMWARE_TARGET_SRC set(TARGET_SRC ${TARGET_SRC} - pulses_driver.cpp keys_driver.cpp telemetry_driver.cpp ) diff --git a/radio/src/targets/common/arm/stm32/intmodule_serial_driver.cpp b/radio/src/targets/common/arm/stm32/intmodule_serial_driver.cpp index 8d254a7b4..2ddd7c74d 100755 --- a/radio/src/targets/common/arm/stm32/intmodule_serial_driver.cpp +++ b/radio/src/targets/common/arm/stm32/intmodule_serial_driver.cpp @@ -41,7 +41,7 @@ void intmoduleStop() GPIO_ResetBits(INTMODULE_GPIO, INTMODULE_TX_GPIO_PIN | INTMODULE_RX_GPIO_PIN); } -void intmodulePxxStart() +void intmodulePxx1SerialStart() { intmoduleSerialStart(INTMODULE_PXX_BAUDRATE, false); } diff --git a/radio/src/targets/horus/board.h b/radio/src/targets/horus/board.h index a3acfc140..4afdd36ea 100644 --- a/radio/src/targets/horus/board.h +++ b/radio/src/targets/horus/board.h @@ -208,31 +208,15 @@ void SDRAM_Init(void); #define IS_PXX1_INTERNAL_ENABLED() (true) #endif -void init_ppm(uint8_t module); -void disable_ppm(uint8_t module); -void init_pxx1_pulses(uint8_t module); -void init_pxx1_serial(uint8_t module); -void disable_pxx1_pulses(uint8_t module); -void disable_pxx1_serial(uint8_t module); -void init_pxx2(uint8_t module); -void disable_pxx2(uint8_t module); -void disable_serial(uint8_t module); - void init_intmodule_heartbeat(); void check_intmodule_heartbeat(); -void intmoduleStop(); void intmoduleSerialStart(uint32_t baudrate, uint8_t rxEnable); -void intmodulePxxStart(); void intmoduleSendBuffer(const uint8_t * data, uint8_t size); void intmoduleSendNextFrame(); void extmoduleSerialStart(uint32_t baudrate, uint32_t period_half_us, bool inverted); void extmoduleSendNextFrame(); -void extmoduleStop(); -void extmodulePpmStart(); -void extmodulePxxStart(); -void extmodulePxx2Start(); // Trainer driver void init_trainer_ppm(void); diff --git a/radio/src/targets/horus/extmodule_driver.cpp b/radio/src/targets/horus/extmodule_driver.cpp index 32490c7c1..89e403cbd 100644 --- a/radio/src/targets/horus/extmodule_driver.cpp +++ b/radio/src/targets/horus/extmodule_driver.cpp @@ -83,7 +83,7 @@ void extmodulePpmStart() NVIC_SetPriority(EXTMODULE_TIMER_IRQn, 7); } -void extmodulePxxStart() +void extmodulePxx1PulsesStart() { EXTERNAL_MODULE_ON(); @@ -127,11 +127,6 @@ void extmodulePxxStart() NVIC_SetPriority(EXTMODULE_TIMER_IRQn, 7); } -void extmodulePxx2Start() -{ - // TODO just enable the S.PORT line (or let telemetry init do it) -} - #if defined(DSM2) void extmoduleSerialStart(uint32_t /*baudrate*/, uint32_t period_half_us, bool inverted) { @@ -284,6 +279,6 @@ extern "C" void EXTMODULE_TIMER_IRQHandler() { EXTMODULE_TIMER->DIER &= ~TIM_DIER_CC2IE; // Stop this interrupt EXTMODULE_TIMER->SR &= ~TIM_SR_CC2IF; - if (setupPulses(EXTERNAL_MODULE)) + if (setupPulsesExternalModule()) extmoduleSendNextFrame(); } diff --git a/radio/src/targets/horus/pulses_driver.cpp b/radio/src/targets/horus/pulses_driver.cpp deleted file mode 100644 index 6a14b4046..000000000 --- a/radio/src/targets/horus/pulses_driver.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (C) OpenTX - * - * Based on code named - * th9x - http://code.google.com/p/th9x - * er9x - http://code.google.com/p/er9x - * gruvin9x - http://code.google.com/p/gruvin9x - * - * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "opentx.h" - -void init_ppm(uint8_t module) -{ - if (module == EXTERNAL_MODULE) { - extmodulePpmStart(); - } -} - -void disable_ppm(uint8_t module) -{ - if (module == EXTERNAL_MODULE) { - extmoduleStop(); - } -} - -void init_pxx2(uint8_t module) -{ - if (module == INTERNAL_MODULE) - intmoduleSerialStart(INTMODULE_PXX_BAUDRATE, true); - else - extmodulePxx2Start(); -} - -void disable_pxx2(uint8_t module) -{ - if (module == INTERNAL_MODULE) - intmoduleStop(); - else - extmoduleStop(); -} - -void init_pxx1_pulses(uint8_t module) -{ - if (module == INTERNAL_MODULE) - intmodulePxxStart(); - else - extmodulePxxStart(); -} - -void init_pxx1_serial(uint8_t module) -{ - if (module == INTERNAL_MODULE) - intmodulePxxStart(); - else - extmodulePxxStart(); -} - -void disable_pxx1_pulses(uint8_t module) -{ - if (module == INTERNAL_MODULE) - intmoduleStop(); - else - extmoduleStop(); -} - -void disable_pxx1_serial(uint8_t module) -{ - if (module == INTERNAL_MODULE) - intmoduleStop(); - else - extmoduleStop(); -} - -#if defined(DSM2) -void disable_serial(uint8_t module) -{ - if (module == EXTERNAL_MODULE) { - extmoduleStop(); - } -} -#endif - diff --git a/radio/src/targets/simu/simpgmspace.cpp b/radio/src/targets/simu/simpgmspace.cpp index 5d3fc51c0..e1436ab05 100644 --- a/radio/src/targets/simu/simpgmspace.cpp +++ b/radio/src/targets/simu/simpgmspace.cpp @@ -60,6 +60,7 @@ Pio Pioa, Piob, Pioc; Pmc pmc; Ssc ssc; Pwm pwm; +Tc tc1; Twi Twio; Usart Usart0; Dacc dacc; diff --git a/radio/src/targets/simu/simpgmspace.h b/radio/src/targets/simu/simpgmspace.h index b40864f24..16f99c089 100644 --- a/radio/src/targets/simu/simpgmspace.h +++ b/radio/src/targets/simu/simpgmspace.h @@ -172,6 +172,12 @@ extern Pmc pmc; extern Ssc ssc; #undef SSC #define SSC (&ssc) +extern Pmc pmc; +#undef PMC +#define PMC (&pmc) +extern Tc tc1; +#undef TC1 +#define TC1 (&tc1) extern Pio Pioa, Piob, Pioc; extern Twi Twio; extern Dacc dacc; diff --git a/radio/src/targets/sky9x/board.h b/radio/src/targets/sky9x/board.h index 37aa4d47d..2683e942b 100644 --- a/radio/src/targets/sky9x/board.h +++ b/radio/src/targets/sky9x/board.h @@ -229,14 +229,6 @@ uint32_t readTrims(void); #define KEYS_PRESSED() readKeys() // Pulses driver -void init_no_pulses(uint32_t port); -void init_ppm(uint32_t port); -void disable_ppm(uint32_t port); -void init_pxx1_pulses(uint32_t port); -void disable_pxx1_pulses(uint32_t port); -void disable_serial(uint32_t port); -void init_module_timer( uint32_t module_index, uint32_t period, uint8_t state); -void disable_module_timer( uint32_t module_index); void extmoduleSerialStart(uint32_t baudrate, uint32_t period_half_us, bool inverted); void extmoduleSendNextFrame(); diff --git a/radio/src/targets/sky9x/pulses_driver.cpp b/radio/src/targets/sky9x/pulses_driver.cpp index b25a4741a..8cc751b21 100644 --- a/radio/src/targets/sky9x/pulses_driver.cpp +++ b/radio/src/targets/sky9x/pulses_driver.cpp @@ -108,6 +108,8 @@ void init_second_ppm(uint32_t period) setExtraModulePolarity(); } +/* +// TODO re-add it later void disable_second_ppm() { Pio * pioptr = PIOC; @@ -115,16 +117,6 @@ void disable_second_ppm() PWM->PWM_IDR1 = PWM_IDR1_CHID1; } -void init_no_pulses(uint32_t port) -{ - if (port == EXTERNAL_MODULE) { - init_main_ppm(3000, 0); - } - else { - // TODO - } -} - void init_module_timer(uint32_t port, uint32_t period, uint8_t state) { if (port == EXTERNAL_MODULE) { @@ -132,32 +124,16 @@ void init_module_timer(uint32_t port, uint32_t period, uint8_t state) init_main_ppm(3000, 0); } } +*/ -void disable_module_timer(uint32_t port) +void extmodulePpmStart() { - if (port == EXTERNAL_MODULE) { - disable_ppm(EXTERNAL_MODULE); - } + init_main_ppm(3000, 1); } -void init_ppm(uint32_t port) +void extramodulePpmStart() { - if (port == EXTERNAL_MODULE) { - init_main_ppm(3000, 1); - } - else { - init_second_ppm(3000); - } -} - -void disable_ppm(uint32_t port) -{ - if (port == EXTERNAL_MODULE) { - disable_main_ppm(); - } - else { - disable_second_ppm(); - } + init_second_ppm(3000); } // Initialise the SSC to allow PXX output. @@ -201,26 +177,16 @@ void disable_ssc() sscptr->SSC_CR = SSC_CR_TXDIS; } -void init_pxx1_pulses(uint32_t port) +void extmodulePxx1PulsesStart() { - if (port == EXTERNAL_MODULE) { - init_main_ppm(2500 * 2, 0); - init_ssc(125); // 8us per bit - } - else { - // TODO - } + init_main_ppm(2500 * 2, 0); + init_ssc(125); // 8us per bit } -void disable_pxx1_pulses(uint32_t port) +void extmoduleStop() { - if (port == EXTERNAL_MODULE) { - disable_ssc(); - disable_ppm(EXTERNAL_MODULE); - } - else { - // TODO - } + disable_ssc(); + disable_main_ppm(); } void extmoduleSerialStart(uint32_t baudrate, uint32_t period_half_us, bool inverted) @@ -236,21 +202,10 @@ void extmoduleSerialStart(uint32_t baudrate, uint32_t period_half_us, bool inver } } -void disable_serial(uint32_t port) -{ - if (port == EXTERNAL_MODULE) { - disable_ssc(); - disable_ppm(EXTERNAL_MODULE); - } - else { - // TODO - } -} - void extmoduleSendNextFrame() { - } + #if !defined(SIMU) extern "C" void PWM_IRQHandler(void) { @@ -272,7 +227,7 @@ extern "C" void PWM_IRQHandler(void) } pwmptr->PWM_CH_NUM[3].PWM_CPDRUPD = period; // Period in half uS if (period != 2500 * 2) { - setupPulses(EXTERNAL_MODULE); + setupPulsesExternalModule(); setExternalModulePolarity(); } else { @@ -297,7 +252,7 @@ extern "C" void PWM_IRQHandler(void) } pwmptr->PWM_CH_NUM[3].PWM_CPDRUPD = period; // Period in half uS if (period != 2500 * 2) { - setupPulses(EXTERNAL_MODULE); + setupPulsesExternalModule(); } else { // Kick off serial output here @@ -323,7 +278,7 @@ extern "C" void PWM_IRQHandler(void) } pwmptr->PWM_CH_NUM[3].PWM_CPDRUPD = period; // Period in half uS if (period != 3500 * 2) { - setupPulses(EXTERNAL_MODULE); + setupPulsesExternalModule(); } else { // Kick off serial output here @@ -338,7 +293,7 @@ extern "C" void PWM_IRQHandler(void) pwmptr->PWM_CH_NUM[3].PWM_CPDRUPD = *extmodulePulsesData.ppm.ptr++; if (*extmodulePulsesData.ppm.ptr == 0) { setExternalModulePolarity(); - setupPulses(EXTERNAL_MODULE); + setupPulsesExternalModule(); } break; diff --git a/radio/src/targets/taranis/CMakeLists.txt b/radio/src/targets/taranis/CMakeLists.txt index a180e0658..aabd04a3c 100644 --- a/radio/src/targets/taranis/CMakeLists.txt +++ b/radio/src/targets/taranis/CMakeLists.txt @@ -178,7 +178,7 @@ if(PCB STREQUAL XLITE OR PCB STREQUAL XLITES OR PCB STREQUAL X9LITE) ${TARGET_SRC} ../common/arm/stm32/intmodule_serial_driver.cpp ) -else() +elseif(NOT (PCB STREQUAL X7 AND PCBREV STREQUAL T12)) set(TARGET_SRC ${TARGET_SRC} intmodule_pulses_driver.cpp diff --git a/radio/src/targets/taranis/board.h b/radio/src/targets/taranis/board.h index 360726507..cc0e67118 100644 --- a/radio/src/targets/taranis/board.h +++ b/radio/src/targets/taranis/board.h @@ -199,29 +199,10 @@ uint32_t isBootloaderStart(const uint8_t * buffer); #define IS_INTERNAL_MODULE_ON() (GPIO_ReadInputDataBit(INTMODULE_PWR_GPIO, INTMODULE_PWR_GPIO_PIN) == Bit_SET) #endif -void init_ppm(uint8_t module); -void disable_ppm(uint8_t module); -void init_pxx2(uint8_t module); -void disable_pxx2(uint8_t module); -void init_pxx1_pulses(uint8_t module); -void init_pxx1_serial(uint8_t module); -void disable_pxx1_pulses(uint8_t module); -void disable_pxx1_serial(uint8_t module); -void disable_serial(uint8_t module); -void intmoduleStop(); -void intmodulePxxStart(); void intmoduleSerialStart(uint32_t baudrate, uint8_t rxEnable); -#if defined(INTERNAL_MODULE_PPM) -void intmodulePpmStart(void); -#endif void intmoduleSendBuffer(const uint8_t * data, uint8_t size); void intmoduleSendNextFrame(); -void extmoduleStop(); -void extmodulePpmStart(); -void extmodulePxxPulsesStart(); -void extmodulePxxSerialStart(); -void extmodulePxx2Start(); void extmoduleSerialStart(uint32_t baudrate, uint32_t period_half_us, bool inverted); void extmoduleInvertedSerialStart(uint32_t baudrate); void extmoduleSendBuffer(const uint8_t * data, uint8_t size); diff --git a/radio/src/targets/taranis/extmodule_driver.cpp b/radio/src/targets/taranis/extmodule_driver.cpp index 689f0caca..98aa85a89 100644 --- a/radio/src/targets/taranis/extmodule_driver.cpp +++ b/radio/src/targets/taranis/extmodule_driver.cpp @@ -196,20 +196,10 @@ extern "C" void EXTMODULE_USART_IRQHandler(void) status = EXTMODULE_USART->SR; } } - -void extmodulePxx2Start() -{ - extmoduleInvertedSerialStart(PXX2_EXTERNAL_MODULE_BAUDRATE); -} -#else -void extmodulePxx2Start() -{ - // TODO just enable the S.PORT line (or let telemetry init do it) -} #endif #if defined(PXX1) -void extmodulePxxPulsesStart() +void extmodulePxx1PulsesStart() { EXTERNAL_MODULE_ON(); @@ -246,7 +236,7 @@ void extmodulePxxPulsesStart() #endif #if defined(PXX1) && defined(EXTMODULE_USART) -void extmodulePxxSerialStart() +void extmodulePxx1SerialStart() { extmoduleInvertedSerialStart(EXTMODULE_PXX_SERIAL_BAUDRATE); } @@ -340,7 +330,7 @@ extern "C" void EXTMODULE_TIMER_CC_IRQHandler() { EXTMODULE_TIMER->DIER &= ~TIM_DIER_CC2IE; // Stop this interrupt EXTMODULE_TIMER->SR &= ~TIM_SR_CC2IF; - if (setupPulses(EXTERNAL_MODULE)) { + if (setupPulsesExternalModule()) { extmoduleSendNextFrame(); } } diff --git a/radio/src/targets/taranis/intmodule_pulses_driver.cpp b/radio/src/targets/taranis/intmodule_pulses_driver.cpp index 29a85674f..6addfd85f 100644 --- a/radio/src/targets/taranis/intmodule_pulses_driver.cpp +++ b/radio/src/targets/taranis/intmodule_pulses_driver.cpp @@ -83,12 +83,7 @@ void intmoduleSendNextFrame() } } -void intmoduleSerialStart(uint32_t baudrate, uint8_t rxEnable) -{ - // nothing, the pulses will be sent through telemetry port -} - -void intmodulePxxStart() +void intmodulePxx1PulsesStart() { INTERNAL_MODULE_ON(); @@ -172,7 +167,7 @@ extern "C" void INTMODULE_TIMER_CC_IRQHandler() { INTMODULE_TIMER->DIER &= ~TIM_DIER_CC2IE; // Stop this interrupt INTMODULE_TIMER->SR &= ~TIM_SR_CC2IF; - if (setupPulses(INTERNAL_MODULE)) { + if (setupPulsesInternalModule()) { intmoduleSendNextFrame(); } } diff --git a/radio/src/targets/taranis/pulses_driver.cpp b/radio/src/targets/taranis/pulses_driver.cpp deleted file mode 100644 index e2cbf8392..000000000 --- a/radio/src/targets/taranis/pulses_driver.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (C) OpenTX - * - * Based on code named - * th9x - http://code.google.com/p/th9x - * er9x - http://code.google.com/p/er9x - * gruvin9x - http://code.google.com/p/gruvin9x - * - * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "opentx.h" - -#if defined(PXX1) -void init_pxx1_pulses(uint8_t module) -{ - if (module == INTERNAL_MODULE) - intmodulePxxStart(); - else - extmodulePxxPulsesStart(); -} - -void init_pxx1_serial(uint8_t module) -{ - if (module == INTERNAL_MODULE) - intmodulePxxStart(); -#if defined(EXTMODULE_USART) - else - extmodulePxxSerialStart(); -#endif -} - -void disable_pxx1_pulses(uint8_t module) -{ - if (module == INTERNAL_MODULE) - intmoduleStop(); - else - extmoduleStop(); -} - -void disable_pxx1_serial(uint8_t module) -{ - if (module == INTERNAL_MODULE) - intmoduleStop(); - else - extmoduleStop(); -} -#endif - -void init_pxx2(uint8_t module) -{ - if (module == INTERNAL_MODULE) - intmoduleSerialStart(INTMODULE_PXX_BAUDRATE, true); - else - extmodulePxx2Start(); -} - -void disable_pxx2(uint8_t module) -{ - if (module == INTERNAL_MODULE) - intmoduleStop(); - else - extmoduleStop(); -} - -#if defined(DSM2) -void disable_serial(uint8_t module) -{ - if (module == EXTERNAL_MODULE) { - extmoduleStop(); - } -} -#endif - -void init_ppm(uint8_t module) -{ - if (module == EXTERNAL_MODULE) { - extmodulePpmStart(); - } -#if defined(INTERNAL_MODULE_PPM) - else { - intmodulePpmStart(); - } -#endif -} - -void disable_ppm(uint8_t module) -{ - if (module == EXTERNAL_MODULE) { - extmoduleStop(); - } -#if defined(INTERNAL_MODULE_PPM) - else { - intmoduleStop(); - } -#endif -} diff --git a/radio/src/tasks.cpp b/radio/src/tasks.cpp index 12685157c..1063b9574 100644 --- a/radio/src/tasks.cpp +++ b/radio/src/tasks.cpp @@ -87,15 +87,16 @@ bool isModuleSynchronous(uint8_t module) void sendSynchronousPulses() { - for (uint8_t module = 0; module < NUM_MODULES; module++) { - if (isModuleSynchronous(module) && setupPulses(module)) { #if defined(HARDWARE_INTERNAL_MODULE) - if (module == INTERNAL_MODULE) - intmoduleSendNextFrame(); + if (isModuleSynchronous(INTERNAL_MODULE)) { + if (setupPulsesInternalModule()) + intmoduleSendNextFrame(); + } #endif - if (module == EXTERNAL_MODULE) - extmoduleSendNextFrame(); - } + + if (isModuleSynchronous(EXTERNAL_MODULE)) { + if (setupPulsesExternalModule()) + extmoduleSendNextFrame(); } } From ecf0ce87e38b34c959725d9963b18de3cf01128f Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Mon, 17 Jun 2019 12:48:52 +0200 Subject: [PATCH 038/350] Simplification --- radio/src/lua/CMakeLists.txt | 38 ++++++++----------------------- radio/src/pulses/pulses.cpp | 1 - radio/src/targets/taranis/board.h | 5 +++- 3 files changed, 14 insertions(+), 30 deletions(-) diff --git a/radio/src/lua/CMakeLists.txt b/radio/src/lua/CMakeLists.txt index 488531123..9b5d760c8 100644 --- a/radio/src/lua/CMakeLists.txt +++ b/radio/src/lua/CMakeLists.txt @@ -9,38 +9,20 @@ macro(add_lua_export_target target) endmacro(add_lua_export_target) set(LUA_INCLUDES - -DCPUARM -DLUA -DLUA_INPUTS + -DCPUARM -DLUA -DLUA_INPUTS -DLUA_EXPORT_GENERATION -DSIMU -I${RADIO_SRC_DIRECTORY}/targets/${TARGET_DIR} -I${RADIO_SRC_DIRECTORY}/thirdparty -I${RADIO_SRC_DIRECTORY}/targets/common/arm/stm32 - -I${RADIO_SRC_DIRECTORY}/${STM32LIB_DIR}/CMSIS/include - -I${RADIO_SRC_DIRECTORY}/${STM32USB_DIR}/STM32_USB_OTG_Driver/inc - -I${RADIO_SRC_DIRECTORY}/${STM32USB_DIR}/STM32_USB_Device_Library/Core/inc - -I${RADIO_SRC_DIRECTORY}/${STM32USB_DIR}/STM32_USB_Device_Library/Class/cdc/inc - -I${RADIO_SRC_DIRECTORY}/${STM32USB_DIR}/STM32_USB_Device_Library/Class/msc/inc - -I${RADIO_SRC_DIRECTORY}/${STM32USB_DIR}/STM32_USB_Device_Library/Class/hid/inc - ) - -set(LUA_INCLUDES_STM32F2 - ${LUA_INCLUDES} - -DSTM32F2 - -I${RADIO_SRC_DIRECTORY}/${STM32LIB_DIR}/CMSIS/Device/ST/STM32F2xx/Include - ) - -set(LUA_INCLUDES_STM32F4 - ${LUA_INCLUDES} - -DSTM32F4 - -I${RADIO_SRC_DIRECTORY}/${STM32LIB_DIR}/CMSIS/Device/ST/STM32F4xx/Include ) if(PYTHONINTERP_FOUND) - add_lua_export_target(x9lite ${LUA_INCLUDES_STM32F2} -DPCBTARANIS -DPCBX9LITE -DPCBX9) - add_lua_export_target(x7 ${LUA_INCLUDES_STM32F2} -DPCBTARANIS -DPCBX7 -DRADIO_X7) - add_lua_export_target(xlite ${LUA_INCLUDES_STM32F2} -DPCBTARANIS -DPCBXLITE) - add_lua_export_target(xlites ${LUA_INCLUDES_STM32F2} -DPCBTARANIS -DPCBXLITES -DPCBXLITE -DGYRO) - add_lua_export_target(x9d ${LUA_INCLUDES_STM32F2} -DPCBTARANIS -DPCBX9D -DPCBX9) - add_lua_export_target(x9e ${LUA_INCLUDES_STM32F4} -DPCBTARANIS -DPCBX9E -DPCBX9 -DSTM32F40_41xxx) - add_lua_export_target(x10 ${LUA_INCLUDES_STM32F4} -DPCBHORUS -DPCBX10 -DSTM32F40_41xxx) - add_lua_export_target(x12s ${LUA_INCLUDES_STM32F4} -DPCBHORUS -DPCBX12S -DSTM32F40_41xxx) - add_lua_export_target(t12 ${LUA_INCLUDES_STM32F2} -DPCBTARANIS -DPCBX7 -DRADIO_T12) + add_lua_export_target(x9lite ${LUA_INCLUDES} -DPCBTARANIS -DPCBX9LITE -DPCBX9) + add_lua_export_target(x7 ${LUA_INCLUDES} -DPCBTARANIS -DPCBX7 -DRADIO_X7) + add_lua_export_target(xlite ${LUA_INCLUDES} -DPCBTARANIS -DPCBXLITE) + add_lua_export_target(xlites ${LUA_INCLUDES} -DPCBTARANIS -DPCBXLITES -DPCBXLITE -DGYRO) + add_lua_export_target(x9d ${LUA_INCLUDES} -DPCBTARANIS -DPCBX9D -DPCBX9) + add_lua_export_target(x9e ${LUA_INCLUDES} -DPCBTARANIS -DPCBX9E -DPCBX9 -DSTM32F40_41xxx) + add_lua_export_target(x10 ${LUA_INCLUDES} -DPCBHORUS -DPCBX10 -DSTM32F40_41xxx) + add_lua_export_target(x12s ${LUA_INCLUDES} -DPCBHORUS -DPCBX12S -DSTM32F40_41xxx) + add_lua_export_target(t12 ${LUA_INCLUDES} -DPCBTARANIS -DPCBX7 -DRADIO_T12) endif() diff --git a/radio/src/pulses/pulses.cpp b/radio/src/pulses/pulses.cpp index d5f2589fc..1b93d3700 100755 --- a/radio/src/pulses/pulses.cpp +++ b/radio/src/pulses/pulses.cpp @@ -260,7 +260,6 @@ void setupPulsesExternalModule(uint8_t protocol) } #if defined(HARDWARE_INTERNAL_MODULE) - void enablePulsesInternalModule(uint8_t protocol) { // start new protocol hardware here diff --git a/radio/src/targets/taranis/board.h b/radio/src/targets/taranis/board.h index cc0e67118..ef9f8a8a0 100644 --- a/radio/src/targets/taranis/board.h +++ b/radio/src/targets/taranis/board.h @@ -36,7 +36,9 @@ extern "C" { #pragma clang diagnostic ignored "-Wdeprecated-register" #endif -#if defined(STM32F4) +#if defined(LUA_EXPORT_GENERATION) + // no includes +#elif defined(STM32F4) #include "STM32F4xx_DSP_StdPeriph_Lib_V1.4.0/Libraries/CMSIS/Device/ST/STM32F4xx/Include/stm32f4xx.h" #include "STM32F4xx_DSP_StdPeriph_Lib_V1.4.0/Libraries/STM32F4xx_StdPeriph_Driver/inc/stm32f4xx_rcc.h" #include "STM32F4xx_DSP_StdPeriph_Lib_V1.4.0/Libraries/STM32F4xx_StdPeriph_Driver/inc/stm32f4xx_syscfg.h" @@ -78,6 +80,7 @@ extern "C" { #endif #include "usb_driver.h" + #if !defined(SIMU) #include "usbd_cdc_core.h" #include "usbd_msc_core.h" From 018b23cc7d3494edaa07466f7f5d983e08bb2ef6 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Mon, 17 Jun 2019 14:03:26 +0200 Subject: [PATCH 039/350] Simplification --- radio/src/lua/CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/radio/src/lua/CMakeLists.txt b/radio/src/lua/CMakeLists.txt index 9b5d760c8..0c61847c5 100644 --- a/radio/src/lua/CMakeLists.txt +++ b/radio/src/lua/CMakeLists.txt @@ -21,8 +21,8 @@ if(PYTHONINTERP_FOUND) add_lua_export_target(xlite ${LUA_INCLUDES} -DPCBTARANIS -DPCBXLITE) add_lua_export_target(xlites ${LUA_INCLUDES} -DPCBTARANIS -DPCBXLITES -DPCBXLITE -DGYRO) add_lua_export_target(x9d ${LUA_INCLUDES} -DPCBTARANIS -DPCBX9D -DPCBX9) - add_lua_export_target(x9e ${LUA_INCLUDES} -DPCBTARANIS -DPCBX9E -DPCBX9 -DSTM32F40_41xxx) - add_lua_export_target(x10 ${LUA_INCLUDES} -DPCBHORUS -DPCBX10 -DSTM32F40_41xxx) - add_lua_export_target(x12s ${LUA_INCLUDES} -DPCBHORUS -DPCBX12S -DSTM32F40_41xxx) + add_lua_export_target(x9e ${LUA_INCLUDES} -DPCBTARANIS -DPCBX9E -DPCBX9) + add_lua_export_target(x10 ${LUA_INCLUDES} -DPCBHORUS -DPCBX10) + add_lua_export_target(x12s ${LUA_INCLUDES} -DPCBHORUS -DPCBX12S) add_lua_export_target(t12 ${LUA_INCLUDES} -DPCBTARANIS -DPCBX7 -DRADIO_T12) endif() From 170a8ff9960fa0ebc7ddfda701038f56302779bd Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Mon, 17 Jun 2019 15:38:20 +0200 Subject: [PATCH 040/350] Compilation fix --- radio/src/targets/horus/board.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/radio/src/targets/horus/board.h b/radio/src/targets/horus/board.h index 4afdd36ea..6ddd4d16f 100644 --- a/radio/src/targets/horus/board.h +++ b/radio/src/targets/horus/board.h @@ -35,6 +35,7 @@ extern "C" { #pragma clang diagnostic ignored "-Wdeprecated-register" #endif +#if !defined(LUA_EXPORT_GENERATION) #include "STM32F4xx_DSP_StdPeriph_Lib_V1.4.0/Libraries/CMSIS/Device/ST/STM32F4xx/Include/stm32f4xx.h" #include "STM32F4xx_DSP_StdPeriph_Lib_V1.4.0/Libraries/STM32F4xx_StdPeriph_Driver/inc/stm32f4xx_rcc.h" #include "STM32F4xx_DSP_StdPeriph_Lib_V1.4.0/Libraries/STM32F4xx_StdPeriph_Driver/inc/stm32f4xx_syscfg.h" @@ -53,12 +54,9 @@ extern "C" { #include "STM32F4xx_DSP_StdPeriph_Lib_V1.4.0/Libraries/STM32F4xx_StdPeriph_Driver/inc/stm32f4xx_fmc.h" #include "STM32F4xx_DSP_StdPeriph_Lib_V1.4.0/Libraries/STM32F4xx_StdPeriph_Driver/inc/stm32f4xx_tim.h" #include "STM32F4xx_DSP_StdPeriph_Lib_V1.4.0/Libraries/STM32F4xx_StdPeriph_Driver/inc/stm32f4xx_dma2d.h" - -#if defined(PCBX10) #include "STM32F4xx_DSP_StdPeriph_Lib_V1.4.0/Libraries/STM32F4xx_StdPeriph_Driver/inc/stm32f4xx_adc.h" -#endif - #include "STM32F4xx_DSP_StdPeriph_Lib_V1.4.0/Libraries/STM32F4xx_StdPeriph_Driver/inc/misc.h" +#endif #if __clang__ // Restore warnings about registers From 6516029fd177d77bd4dacaf2bbae1ee0fb5ed206 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Mon, 17 Jun 2019 16:09:09 +0200 Subject: [PATCH 041/350] Cosmetics (#6512) Cosmetics --- radio/src/gui/128x64/lcd.cpp | 16 ++++----- radio/src/gui/128x64/lcd.h | 43 ++++++++++------------- radio/src/gui/128x64/model_setup.cpp | 6 ++-- radio/src/gui/128x64/radio_setup.cpp | 6 ++-- radio/src/gui/212x64/lcd.cpp | 12 +++---- radio/src/gui/212x64/lcd.h | 25 ++++++------- radio/src/gui/212x64/model_setup.cpp | 6 ++-- radio/src/gui/212x64/radio_setup.cpp | 6 ++-- radio/src/gui/212x64/view_statistics.cpp | 2 +- radio/src/gui/480x272/lcd.cpp | 2 +- radio/src/gui/480x272/lcd.h | 2 -- radio/src/gui/480x272/view_statistics.cpp | 2 +- radio/src/gui/common/colorlcd/widgets.cpp | 2 +- radio/src/gui/gui_common.h | 2 +- radio/src/strhelpers.cpp | 2 +- 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 +- 26 files changed, 72 insertions(+), 84 deletions(-) diff --git a/radio/src/gui/128x64/lcd.cpp b/radio/src/gui/128x64/lcd.cpp index 6cb5a16b5..aa783306c 100644 --- a/radio/src/gui/128x64/lcd.cpp +++ b/radio/src/gui/128x64/lcd.cpp @@ -452,12 +452,12 @@ void lcdDraw8bitsNumber(coord_t x, coord_t y, int8_t val) lcdDrawNumber(x, y, val); } -void lcdDrawNumber(coord_t x, coord_t y, lcdint_t val, LcdFlags flags) +void lcdDrawNumber(coord_t x, coord_t y, int val, LcdFlags flags) { lcdDrawNumber(x, y, val, flags, 0); } -void lcdDrawNumber(coord_t x, coord_t y, lcdint_t val, LcdFlags flags, uint8_t len) +void lcdDrawNumber(coord_t x, coord_t y, int val, LcdFlags flags, uint8_t len) { char str[16+1]; char *s = str+16; @@ -540,7 +540,7 @@ void lcdDrawLine(coord_t x1, coord_t y1, coord_t x2, coord_t y2, uint8_t pat, Lc #endif -void lcdDrawVerticalLine(coord_t x, scoord_t y, scoord_t h, uint8_t pat, LcdFlags att) +void lcdDrawVerticalLine(coord_t x, coord_t y, coord_t h, uint8_t pat, LcdFlags att) { if (x >= LCD_W) return; // should never happen on 9X @@ -576,7 +576,7 @@ void lcdDrawVerticalLine(coord_t x, scoord_t y, scoord_t h, uint8_t pat, LcdFlag } } -void lcdDrawSolidVerticalLine(coord_t x, scoord_t y, scoord_t h, LcdFlags att) +void lcdDrawSolidVerticalLine(coord_t x, coord_t y, coord_t h, LcdFlags att) { lcdDrawVerticalLine(x, y, h, SOLID, att); } @@ -591,9 +591,9 @@ void lcdDrawRect(coord_t x, coord_t y, coord_t w, coord_t h, uint8_t pat, LcdFla } #if !defined(BOOT) -void lcdDrawFilledRect(coord_t x, scoord_t y, coord_t w, coord_t h, uint8_t pat, LcdFlags att) +void lcdDrawFilledRect(coord_t x, coord_t y, coord_t w, coord_t h, uint8_t pat, LcdFlags att) { - for (scoord_t i=y; i<(scoord_t)(y+h); i++) { // cast to scoord_t needed otherwise (y+h) is promoted to int (see #5055) + for (coord_t i=y; i +typedef int coord_t; +typedef uint32_t LcdFlags; +typedef uint8_t display_t; + #define BOX_WIDTH 23 -#define coord_t uint8_t -#define scoord_t int8_t #define CENTER #define CENTER_OFS 0 - typedef int32_t lcdint_t; - typedef uint32_t lcduint_t; - #define FW 6 #define FWNUM 5 #define FH 8 @@ -89,9 +88,6 @@ #define TIMEHOUR 0x2000 #define STREXPANDED 0x4000 -typedef uint32_t LcdFlags; - -#define display_t uint8_t #define DISPLAY_BUFFER_SIZE (LCD_W*((LCD_H+7)/8)) extern display_t displayBuf[DISPLAY_BUFFER_SIZE]; @@ -122,8 +118,8 @@ void lcdDrawTextAlignedLeft(coord_t y, const char * s); void lcdDrawHexNumber(coord_t x, coord_t y, uint32_t val, LcdFlags mode=0); void lcdDrawHexChar(coord_t x, coord_t y, uint8_t val, LcdFlags flags=0); -void lcdDrawNumber(coord_t x, coord_t y, lcdint_t val, LcdFlags mode, uint8_t len); -void lcdDrawNumber(coord_t x, coord_t y, lcdint_t val, LcdFlags mode=0); +void lcdDrawNumber(coord_t x, coord_t y, int val, LcdFlags mode, uint8_t len); +void lcdDrawNumber(coord_t x, coord_t y, int val, LcdFlags mode=0); void lcdDraw8bitsNumber(coord_t x, coord_t y, int8_t val); void drawStringWithIndex(coord_t x, coord_t y, const char * str, uint8_t idx, LcdFlags att=0); @@ -145,14 +141,12 @@ void putsChnLetter(coord_t x, coord_t y, uint8_t idx, LcdFlags attr); void putsVolts(coord_t x, coord_t y, uint16_t volts, LcdFlags att); void putsVBat(coord_t x, coord_t y, LcdFlags att); - - #define putstime_t int32_t - #define FlightModesType uint16_t +#define FlightModesType uint16_t void drawRtcTime(coord_t x, coord_t y, LcdFlags att); -void drawTimer(coord_t x, coord_t y, putstime_t tme, LcdFlags att, LcdFlags att2); +void drawTimer(coord_t x, coord_t y, int32_t tme, LcdFlags att, LcdFlags att2); void drawReceiverName(coord_t x, coord_t y, uint8_t moduleIdx, uint8_t receiverIdx, LcdFlags flags=0); -inline void drawTimer(coord_t x, coord_t y, putstime_t tme, LcdFlags att) +inline void drawTimer(coord_t x, coord_t y, int32_t tme, LcdFlags att) { drawTimer(x, y, tme, att, att); } @@ -164,13 +158,11 @@ void lcdDrawPoint(coord_t x, coord_t y, LcdFlags att=0); void lcdMaskPoint(uint8_t *p, uint8_t mask, LcdFlags att=0); void lcdDrawSolidHorizontalLine(coord_t x, coord_t y, coord_t w, LcdFlags att=0); void lcdDrawHorizontalLine(coord_t x, coord_t y, coord_t w, uint8_t pat, LcdFlags att=0); - void lcdDrawSolidVerticalLine(coord_t x, scoord_t y, scoord_t h, LcdFlags att=0); - void lcdDrawVerticalLine(coord_t x, scoord_t y, scoord_t h, uint8_t pat, LcdFlags att=0); - - void lcdDrawLine(coord_t x1, coord_t y1, coord_t x2, coord_t y2, uint8_t pat=SOLID, LcdFlags att=0); - -void lcdDrawFilledRect(coord_t x, scoord_t y, coord_t w, coord_t h, uint8_t pat=SOLID, LcdFlags att=0); -inline void lcdDrawSolidFilledRect(coord_t x, scoord_t y, coord_t w, coord_t h, LcdFlags att=0) +void lcdDrawSolidVerticalLine(coord_t x, coord_t y, coord_t h, LcdFlags att=0); +void lcdDrawVerticalLine(coord_t x, coord_t y, coord_t h, uint8_t pat, LcdFlags att=0); +void lcdDrawLine(coord_t x1, coord_t y1, coord_t x2, coord_t y2, uint8_t pat=SOLID, LcdFlags att=0); +void lcdDrawFilledRect(coord_t x, coord_t y, coord_t w, coord_t h, uint8_t pat=SOLID, LcdFlags att=0); +inline void lcdDrawSolidFilledRect(coord_t x, coord_t y, coord_t w, coord_t h, LcdFlags att=0) { lcdDrawFilledRect(x, y, w, h, SOLID, att); } @@ -178,7 +170,10 @@ void lcdDrawRect(coord_t x, coord_t y, coord_t w, coord_t h, uint8_t pat=SOLID, void lcdInvertLine(int8_t line); #define lcdInvertLastLine() lcdInvertLine(LCD_LINES-1) -inline void lcdDrawSquare(coord_t x, coord_t y, coord_t w, LcdFlags att=0) { lcdDrawRect(x, y, w, w, SOLID, att); } +inline void lcdDrawSquare(coord_t x, coord_t y, coord_t w, LcdFlags att=0) +{ + lcdDrawRect(x, y, w, w, SOLID, att); +} void drawTelemetryTopBar(); @@ -188,7 +183,7 @@ void drawTelemetryTopBar(); lcdDrawSolidVerticalLine(xx+1,yy-ll,ll) -void lcdClear(void); +void lcdClear(); void lcdDraw1bitBitmap(coord_t x, coord_t y, const unsigned char * img, uint8_t idx, LcdFlags att=0); inline void lcdDrawBitmap(coord_t x, coord_t y, const uint8_t * bitmap) { diff --git a/radio/src/gui/128x64/model_setup.cpp b/radio/src/gui/128x64/model_setup.cpp index b163789b7..6e1ffc8a4 100644 --- a/radio/src/gui/128x64/model_setup.cpp +++ b/radio/src/gui/128x64/model_setup.cpp @@ -759,7 +759,7 @@ void menuModelSetup(event_t event) case ITEM_MODEL_SETUP_INTERNAL_MODULE_TYPE: { - lcdDrawTextAlignedLeft(y, STR_MODE); + lcdDrawTextAlignedLeft(y, INDENT TR_MODE); #if defined(INTERNAL_MODULE_PXX1) lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_INTERNAL_MODULE_PROTOCOLS, g_model.moduleData[INTERNAL_MODULE].type, menuHorizontalPosition==0 ? attr : 0); if (isModuleXJT(INTERNAL_MODULE)) @@ -821,7 +821,7 @@ void menuModelSetup(event_t event) break; case ITEM_MODEL_SETUP_EXTERNAL_MODULE_TYPE: - lcdDrawTextAlignedLeft(y, STR_MODE); + lcdDrawTextAlignedLeft(y, INDENT TR_MODE); lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_EXTERNAL_MODULE_PROTOCOLS, g_model.moduleData[EXTERNAL_MODULE].type, menuHorizontalPosition==0 ? attr : 0); if (isModuleXJT(EXTERNAL_MODULE)) lcdDrawTextAtIndex(lcdNextPos + 3, y, STR_ACCST_RF_PROTOCOLS, 1+g_model.moduleData[EXTERNAL_MODULE].rfProtocol, menuHorizontalPosition==1 ? attr : 0); @@ -963,7 +963,7 @@ void menuModelSetup(event_t event) break; case ITEM_MODEL_SETUP_TRAINER_MODE: - lcdDrawTextAlignedLeft(y, STR_MODE); + lcdDrawTextAlignedLeft(y, INDENT TR_MODE); lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_VTRAINERMODES, g_model.trainerData.mode, attr); if (attr) { g_model.trainerData.mode = checkIncDec(event, g_model.trainerData.mode, 0, TRAINER_MODE_MAX(), EE_MODEL, isTrainerModeAvailable); diff --git a/radio/src/gui/128x64/radio_setup.cpp b/radio/src/gui/128x64/radio_setup.cpp index 34e8bfe76..b46925906 100644 --- a/radio/src/gui/128x64/radio_setup.cpp +++ b/radio/src/gui/128x64/radio_setup.cpp @@ -354,7 +354,7 @@ void menuRadioSetup(event_t event) break; case ITEM_SETUP_HAPTIC_MODE: - g_eeGeneral.hapticMode = editChoice(RADIO_SETUP_2ND_COLUMN, y, STR_MODE, STR_VBEEPMODE, g_eeGeneral.hapticMode, -2, 1, attr, event); + g_eeGeneral.hapticMode = editChoice(RADIO_SETUP_2ND_COLUMN, y, INDENT TR_MODE, STR_VBEEPMODE, g_eeGeneral.hapticMode, -2, 1, attr, event); break; case ITEM_SETUP_HAPTIC_LENGTH: @@ -464,7 +464,7 @@ void menuRadioSetup(event_t event) break; case ITEM_SETUP_BACKLIGHT_MODE: - g_eeGeneral.backlightMode = editChoice(RADIO_SETUP_2ND_COLUMN, y, STR_MODE, STR_VBLMODE, g_eeGeneral.backlightMode, e_backlight_mode_off, e_backlight_mode_on, attr, event); + g_eeGeneral.backlightMode = editChoice(RADIO_SETUP_2ND_COLUMN, y, INDENT TR_MODE, STR_VBLMODE, g_eeGeneral.backlightMode, e_backlight_mode_off, e_backlight_mode_on, attr, event); break; case ITEM_SETUP_FLASH_BEEP: @@ -603,7 +603,7 @@ void menuRadioSetup(event_t event) break; case ITEM_SETUP_STICK_MODE_LABELS: - lcdDrawTextAlignedLeft(y, NO_INDENT(STR_MODE)); + lcdDrawTextAlignedLeft(y, STR_MODE); for (uint8_t i=0; i<4; i++) { lcdDraw1bitBitmap(5*FW+i*(4*FW+2), y, sticks, i, 0); #if defined(FRSKY_STICKS) && !defined(PCBTARANIS) diff --git a/radio/src/gui/212x64/lcd.cpp b/radio/src/gui/212x64/lcd.cpp index 9aa14fe35..67e473a76 100644 --- a/radio/src/gui/212x64/lcd.cpp +++ b/radio/src/gui/212x64/lcd.cpp @@ -477,7 +477,7 @@ void lcdDrawLine(coord_t x1, coord_t y1, coord_t x2, coord_t y2, uint8_t pat, Lc } #endif -void lcdDrawSolidVerticalLine(coord_t x, scoord_t y, scoord_t h, LcdFlags att) +void lcdDrawSolidVerticalLine(coord_t x, coord_t y, coord_t h, LcdFlags att) { lcdDrawVerticalLine(x, y, h, SOLID, att); } @@ -492,9 +492,9 @@ void lcdDrawRect(coord_t x, coord_t y, coord_t w, coord_t h, uint8_t pat, LcdFla } #if !defined(BOOT) -void lcdDrawFilledRect(coord_t x, scoord_t y, coord_t w, coord_t h, uint8_t pat, LcdFlags att) +void lcdDrawFilledRect(coord_t x, coord_t y, coord_t w, coord_t h, uint8_t pat, LcdFlags att) { - for (scoord_t i=y; i<(scoord_t)(y+h); i++) { + for (coord_t i=y; i= LCD_W) return; if (y >= LCD_H) return; diff --git a/radio/src/gui/212x64/lcd.h b/radio/src/gui/212x64/lcd.h index cb8ce9476..5cf199b76 100644 --- a/radio/src/gui/212x64/lcd.h +++ b/radio/src/gui/212x64/lcd.h @@ -21,14 +21,14 @@ #ifndef _LCD_H_ #define _LCD_H_ +typedef int coord_t; +typedef uint32_t LcdFlags; +typedef uint8_t display_t; + #define BOX_WIDTH 31 -#define coord_t int -#define scoord_t int #define CENTER "\015" #define CENTER_OFS (7*FW-FW/2) -#define lcdint_t int32_t - #define FW 6 #define FWNUM 5 #define FH 8 @@ -84,9 +84,6 @@ #define GREY_DEFAULT GREY(11) #define COLOUR_MASK(x) ((x) & 0x0F0000) -#define LcdFlags uint32_t - -#define display_t uint8_t #define DISPLAY_BUFFER_SIZE (LCD_W*LCD_H*4/8) #if (defined(PCBX9E) || defined(PCBX9DP)) && defined(LCD_DUAL_BUFFER) @@ -135,11 +132,9 @@ void putsChnLetter(coord_t x, coord_t y, uint8_t idx, LcdFlags attr); void putsVolts(coord_t x, coord_t y, uint16_t volts, LcdFlags att); void putsVBat(coord_t x, coord_t y, LcdFlags att); -#define putstime_t int32_t - void drawRtcTime(coord_t x, coord_t y, LcdFlags att); -void drawTimer(coord_t x, coord_t y, putstime_t tme, LcdFlags att, LcdFlags att2); -inline void drawTimer(coord_t x, coord_t y, putstime_t tme, LcdFlags att) +void drawTimer(coord_t x, coord_t y, int32_t tme, LcdFlags att, LcdFlags att2); +inline void drawTimer(coord_t x, coord_t y, int32_t tme, LcdFlags att) { drawTimer(x, y, tme, att, att); } @@ -151,11 +146,11 @@ void lcdDrawPoint(coord_t x, coord_t y, LcdFlags att=0); void lcdMaskPoint(uint8_t *p, uint8_t mask, LcdFlags att=0); void lcdDrawSolidHorizontalLine(coord_t x, coord_t y, coord_t w, LcdFlags att=0); void lcdDrawHorizontalLine(coord_t x, coord_t y, coord_t w, uint8_t pat, LcdFlags att=0); -void lcdDrawSolidVerticalLine(coord_t x, scoord_t y, scoord_t h, LcdFlags att=0); -void lcdDrawVerticalLine(coord_t x, scoord_t y, scoord_t h, uint8_t pat, LcdFlags att=0); +void lcdDrawSolidVerticalLine(coord_t x, coord_t y, coord_t h, LcdFlags att=0); +void lcdDrawVerticalLine(coord_t x, coord_t y, coord_t h, uint8_t pat, LcdFlags att=0); void lcdDrawLine(coord_t x1, coord_t y1, coord_t x2, coord_t y2, uint8_t pat=SOLID, LcdFlags att=0); -void lcdDrawFilledRect(coord_t x, scoord_t y, coord_t w, coord_t h, uint8_t pat=SOLID, LcdFlags att=0); -inline void lcdDrawSolidFilledRect(coord_t x, scoord_t y, coord_t w, coord_t h, LcdFlags att=0) +void lcdDrawFilledRect(coord_t x, coord_t y, coord_t w, coord_t h, uint8_t pat=SOLID, LcdFlags att=0); +inline void lcdDrawSolidFilledRect(coord_t x, coord_t y, coord_t w, coord_t h, LcdFlags att=0) { lcdDrawFilledRect(x, y, w, h, SOLID, att); } diff --git a/radio/src/gui/212x64/model_setup.cpp b/radio/src/gui/212x64/model_setup.cpp index c6135cbb4..94122139b 100644 --- a/radio/src/gui/212x64/model_setup.cpp +++ b/radio/src/gui/212x64/model_setup.cpp @@ -717,7 +717,7 @@ void menuModelSetup(event_t event) case ITEM_MODEL_SETUP_INTERNAL_MODULE_TYPE: { - lcdDrawTextAlignedLeft(y, STR_MODE); + lcdDrawTextAlignedLeft(y, INDENT TR_MODE); #if defined(INTERNAL_MODULE_PXX1) lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_INTERNAL_MODULE_PROTOCOLS, g_model.moduleData[INTERNAL_MODULE].type, menuHorizontalPosition==0 ? attr : 0); if (isModuleXJT(INTERNAL_MODULE)) @@ -768,7 +768,7 @@ void menuModelSetup(event_t event) } case ITEM_MODEL_SETUP_TRAINER_MODE: - lcdDrawTextAlignedLeft(y, STR_MODE); + lcdDrawTextAlignedLeft(y, INDENT TR_MODE); lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_VTRAINERMODES, g_model.trainerData.mode, attr); if (attr) { g_model.trainerData.mode = checkIncDec(event, g_model.trainerData.mode, 0, TRAINER_MODE_MAX(), EE_MODEL, isTrainerModeAvailable); @@ -780,7 +780,7 @@ void menuModelSetup(event_t event) break; case ITEM_MODEL_SETUP_EXTERNAL_MODULE_TYPE: - lcdDrawTextAlignedLeft(y, STR_MODE); + lcdDrawTextAlignedLeft(y, INDENT TR_MODE); lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_EXTERNAL_MODULE_PROTOCOLS, g_model.moduleData[EXTERNAL_MODULE].type, menuHorizontalPosition==0 ? attr : 0); if (isModuleXJT(EXTERNAL_MODULE)) lcdDrawTextAtIndex(lcdNextPos + 3, y, STR_ACCST_RF_PROTOCOLS, 1+g_model.moduleData[EXTERNAL_MODULE].rfProtocol, menuHorizontalPosition==1 ? attr : 0); diff --git a/radio/src/gui/212x64/radio_setup.cpp b/radio/src/gui/212x64/radio_setup.cpp index 17d376cc8..4d9e31185 100644 --- a/radio/src/gui/212x64/radio_setup.cpp +++ b/radio/src/gui/212x64/radio_setup.cpp @@ -296,7 +296,7 @@ void menuRadioSetup(event_t event) break; case ITEM_SETUP_HAPTIC_MODE: - g_eeGeneral.hapticMode = editChoice(RADIO_SETUP_2ND_COLUMN, y, STR_MODE, STR_VBEEPMODE, g_eeGeneral.hapticMode, -2, 1, attr, event); + g_eeGeneral.hapticMode = editChoice(RADIO_SETUP_2ND_COLUMN, y, INDENT TR_MODE, STR_VBEEPMODE, g_eeGeneral.hapticMode, -2, 1, attr, event); break; case ITEM_SETUP_HAPTIC_LENGTH: @@ -360,7 +360,7 @@ void menuRadioSetup(event_t event) break; case ITEM_SETUP_BACKLIGHT_MODE: - g_eeGeneral.backlightMode = editChoice(RADIO_SETUP_2ND_COLUMN, y, STR_MODE, STR_VBLMODE, g_eeGeneral.backlightMode, e_backlight_mode_off, e_backlight_mode_on, attr, event); + g_eeGeneral.backlightMode = editChoice(RADIO_SETUP_2ND_COLUMN, y, INDENT TR_MODE, STR_VBLMODE, g_eeGeneral.backlightMode, e_backlight_mode_off, e_backlight_mode_on, attr, event); break; case ITEM_SETUP_FLASH_BEEP: @@ -483,7 +483,7 @@ void menuRadioSetup(event_t event) break; case ITEM_SETUP_STICK_MODE_LABELS: - lcdDrawTextAlignedLeft(y, NO_INDENT(STR_MODE)); + lcdDrawTextAlignedLeft(y, STR_MODE); for (uint8_t i=0; i<4; i++) { lcdDraw1bitBitmap((6+4*i)*FW, y, sticks, i, 0); } diff --git a/radio/src/gui/212x64/view_statistics.cpp b/radio/src/gui/212x64/view_statistics.cpp index 3b7f04a49..bfb6781dd 100644 --- a/radio/src/gui/212x64/view_statistics.cpp +++ b/radio/src/gui/212x64/view_statistics.cpp @@ -286,7 +286,7 @@ void menuTraceBuffer(event_t event) const struct TraceElement * te = getTraceElement(k); if (te) { //time - putstime_t tme = te->time % SECS_PER_DAY; + int32_t tme = te->time % SECS_PER_DAY; drawTimer(4*FW, y, tme, TIMEHOUR|LEFT, TIMEHOUR|LEFT); //event lcdDrawNumber(14*FW, y, te->event, LEADING0|LEFT, 3); diff --git a/radio/src/gui/480x272/lcd.cpp b/radio/src/gui/480x272/lcd.cpp index a9f9075ab..930b24aa8 100644 --- a/radio/src/gui/480x272/lcd.cpp +++ b/radio/src/gui/480x272/lcd.cpp @@ -250,7 +250,7 @@ void drawRtcTime(coord_t x, coord_t y, LcdFlags flags) drawTimer(x, y, getValue(MIXSRC_TX_TIME), flags); } -void drawTimer(coord_t x, coord_t y, putstime_t tme, LcdFlags flags) +void drawTimer(coord_t x, coord_t y, int32_t tme, LcdFlags flags) { char str[LEN_TIMER_STRING]; getTimerString(str, tme, (flags & TIMEHOUR) != 0); diff --git a/radio/src/gui/480x272/lcd.h b/radio/src/gui/480x272/lcd.h index e5529ac3c..5d1e9899d 100644 --- a/radio/src/gui/480x272/lcd.h +++ b/radio/src/gui/480x272/lcd.h @@ -32,8 +32,6 @@ #define CENTER -#define lcdint_t int32_t - /* lcd common flags */ #define BLINK 0x01 diff --git a/radio/src/gui/480x272/view_statistics.cpp b/radio/src/gui/480x272/view_statistics.cpp index 583c609fe..46391a7e8 100644 --- a/radio/src/gui/480x272/view_statistics.cpp +++ b/radio/src/gui/480x272/view_statistics.cpp @@ -231,7 +231,7 @@ bool menuStatsTraces(event_t event) const struct TraceElement * te = getTraceElement(k); if (te) { // time - putstime_t tme = te->time % SECS_PER_DAY; + int32_t tme = te->time % SECS_PER_DAY; drawTimer(STATS_TRACES_TIME_POS, y, tme, TIMEHOUR|LEFT); // event lcdDrawNumber(STATS_TRACES_EVENT_POS, y, te->event, LEADING0|LEFT, 3); diff --git a/radio/src/gui/common/colorlcd/widgets.cpp b/radio/src/gui/common/colorlcd/widgets.cpp index 1c0f801cb..373f0dafb 100644 --- a/radio/src/gui/common/colorlcd/widgets.cpp +++ b/radio/src/gui/common/colorlcd/widgets.cpp @@ -31,7 +31,7 @@ void drawStringWithIndex(coord_t x, coord_t y, const char * str, int idx, LcdFla lcdDrawText(x, y, s, flags); } -void drawValueWithUnit(coord_t x, coord_t y, int32_t val, uint8_t unit, LcdFlags att) +void drawValueWithUnit(coord_t x, coord_t y, int val, uint8_t unit, LcdFlags att) { // convertUnit(val, unit); if (!(att & NO_UNIT) && unit != UNIT_RAW) { diff --git a/radio/src/gui/gui_common.h b/radio/src/gui/gui_common.h index ef5923cc3..e21b67ac0 100644 --- a/radio/src/gui/gui_common.h +++ b/radio/src/gui/gui_common.h @@ -91,7 +91,7 @@ void drawFlightMode(coord_t x, coord_t y, int8_t idx, LcdFlags att=0); swsrc_t checkIncDecMovedSwitch(swsrc_t val); #include "telemetry/telemetry_sensors.h" -void drawValueWithUnit(coord_t x, coord_t y, int32_t val, uint8_t unit, LcdFlags flags); +void drawValueWithUnit(coord_t x, coord_t y, int val, uint8_t unit, LcdFlags flags); void drawCurveRef(coord_t x, coord_t y, CurveRef & curve, LcdFlags flags=0); void drawDate(coord_t x, coord_t y, TelemetryItem & telemetryItem, LcdFlags flags=0); void drawTelemScreenDate(coord_t x, coord_t y, source_t sensor, LcdFlags flags=0); diff --git a/radio/src/strhelpers.cpp b/radio/src/strhelpers.cpp index ee42b8fe6..591723571 100644 --- a/radio/src/strhelpers.cpp +++ b/radio/src/strhelpers.cpp @@ -170,7 +170,7 @@ char * strAppendStringWithIndex(char * dest, const char * s, int idx) return strAppendUnsigned(strAppend(dest, s), abs(idx)); } -char * getTimerString(char * dest, putstime_t tme, uint8_t hours) +char * getTimerString(char * dest, int32_t tme, uint8_t hours) { char * s = dest; div_t qr; diff --git a/radio/src/translations/cz.h.txt b/radio/src/translations/cz.h.txt index 178fa87d9..7b6f0d15b 100644 --- a/radio/src/translations/cz.h.txt +++ b/radio/src/translations/cz.h.txt @@ -532,7 +532,7 @@ #define TR_ELEDIRECTION "Směr:Výškovka" #define TR_AILDIRECTION "\012Křidélka" #define TR_COLDIRECTION "\012Kolektiv" -#define TR_MODE INDENT"Mód" +#define TR_MODE "Mód" #define TR_SUBTYPE INDENT "Subtyp" #define TR_NOFREEEXPO "Není volné expo!" #define TR_NOFREEMIXER "Není volný mix!" diff --git a/radio/src/translations/de.h.txt b/radio/src/translations/de.h.txt index fc8e65ce4..8807d478e 100644 --- a/radio/src/translations/de.h.txt +++ b/radio/src/translations/de.h.txt @@ -539,7 +539,7 @@ #define TR_ELEDIRECTION TR("Nick Richtung", "Nick Servo Richtung") #define TR_AILDIRECTION TR("Roll Richtung", "Roll Servo Richtung") #define TR_COLDIRECTION TR("Pitch Richtung", "Pitch Servo Richtung") -#define TR_MODE INDENT "Modus" +#define TR_MODE "Modus" #define TR_SUBTYPE INDENT "Subtype" #define TR_NOFREEEXPO "Expos voll!" #define TR_NOFREEMIXER "Mischer voll!" diff --git a/radio/src/translations/en.h.txt b/radio/src/translations/en.h.txt index 4c85f0adb..605c5cb9e 100644 --- a/radio/src/translations/en.h.txt +++ b/radio/src/translations/en.h.txt @@ -534,7 +534,7 @@ #define TR_ELEDIRECTION "ELE Direction" #define TR_AILDIRECTION "AIL Direction" #define TR_COLDIRECTION "PIT Direction" -#define TR_MODE INDENT "Mode" +#define TR_MODE "Mode" #define TR_SUBTYPE INDENT "Subtype" #define TR_NOFREEEXPO "No free expo!" #define TR_NOFREEMIXER "No free mixer!" diff --git a/radio/src/translations/es.h.txt b/radio/src/translations/es.h.txt index fca430329..8e7f46a0f 100644 --- a/radio/src/translations/es.h.txt +++ b/radio/src/translations/es.h.txt @@ -550,7 +550,7 @@ #define TR_ELEDIRECTION TR("ELE Direccion","Largo cyc. direccion") #define TR_AILDIRECTION TR("AIL Direccion","Lateral cyc. direccion") #define TR_COLDIRECTION TR("PIT Direccion","Coll. pitch direccion") -#define TR_MODE INDENT"Modo" +#define TR_MODE "Modo" #define TR_SUBTYPE INDENT "Subtype" #define TR_NOFREEEXPO "No expo libre!" #define TR_NOFREEMIXER "No mezcla lib!" diff --git a/radio/src/translations/fi.h.txt b/radio/src/translations/fi.h.txt index f158f3b9d..51b8a081a 100644 --- a/radio/src/translations/fi.h.txt +++ b/radio/src/translations/fi.h.txt @@ -542,7 +542,7 @@ #define TR_ELEDIRECTION TR("ELE Direction","Long. cyc. direction") #define TR_AILDIRECTION TR("AIL Direction","Lateral cyc. direction") #define TR_COLDIRECTION TR("PIT Direction","Coll. pitch direction") -#define TR_MODE INDENT"Mode" +#define TR_MODE "Mode" #define TR_SUBTYPE INDENT "Subtype" #define TR_NOFREEEXPO "No free expo!" #define TR_NOFREEMIXER "No free mixer!" diff --git a/radio/src/translations/fr.h.txt b/radio/src/translations/fr.h.txt index ae8addb78..108318792 100644 --- a/radio/src/translations/fr.h.txt +++ b/radio/src/translations/fr.h.txt @@ -548,7 +548,7 @@ #define TR_ELEDIRECTION TR("Inv. longitud.", "Inversion longitudinal") #define TR_AILDIRECTION TR("Inv. latéral", "Inversion latéral") #define TR_COLDIRECTION TR("Inv. collectif", "Inversion collectif") -#define TR_MODE INDENT "Mode" +#define TR_MODE "Mode" #define TR_SUBTYPE INDENT "Sous-type" #define TR_NOFREEEXPO "Max expos atteint!" #define TR_NOFREEMIXER "Max mixages atteint!" diff --git a/radio/src/translations/it.h.txt b/radio/src/translations/it.h.txt index 2679823b0..977c94cc1 100644 --- a/radio/src/translations/it.h.txt +++ b/radio/src/translations/it.h.txt @@ -549,7 +549,7 @@ #define TR_ELEDIRECTION TR("Direzione ELE","Direzione Long. cyc.") #define TR_AILDIRECTION TR("Direzione AIL","Direzione Lateral cyc.") #define TR_COLDIRECTION TR("Direzione PIT","Direzione Coll. Passo") -#define TR_MODE INDENT"Modo" +#define TR_MODE "Modo" #define TR_SUBTYPE INDENT "Subtype" #define TR_NOFREEEXPO "Expo pieni!" #define TR_NOFREEMIXER "Mixer pieni!" diff --git a/radio/src/translations/nl.h.txt b/radio/src/translations/nl.h.txt index 6aa47e53a..e8d5f18b8 100644 --- a/radio/src/translations/nl.h.txt +++ b/radio/src/translations/nl.h.txt @@ -531,7 +531,7 @@ TR_GYR_VSRCRAW #define TR_ELEDIRECTION "ELE Direction" #define TR_AILDIRECTION "AIL Direction" #define TR_COLDIRECTION "PIT Direction" -#define TR_MODE INDENT "Mode" +#define TR_MODE "Mode" #define TR_SUBTYPE INDENT "Subtype" #define TR_NOFREEEXPO "Geen vrije expo!" #define TR_NOFREEMIXER "Geen vrije mixer!" diff --git a/radio/src/translations/pl.h.txt b/radio/src/translations/pl.h.txt index 18c10b70e..2c52d7057 100644 --- a/radio/src/translations/pl.h.txt +++ b/radio/src/translations/pl.h.txt @@ -549,7 +549,7 @@ #define TR_ELEDIRECTION TR("Ster Wysokośc","Dług. Kierunku cyklu") #define TR_AILDIRECTION TR("Kierunek Lotk","Lateral cyc. direction") #define TR_COLDIRECTION TR("PIT Direction","Coll. pitch direction") -#define TR_MODE INDENT "Tryb" +#define TR_MODE "Tryb" #define TR_SUBTYPE INDENT "Subtype" #define TR_NOFREEEXPO "BrakWoln.Expo!" #define TR_NOFREEMIXER "BrakWoln.Mixów!" diff --git a/radio/src/translations/pt.h.txt b/radio/src/translations/pt.h.txt index 0b96c237a..6c35d5e9a 100644 --- a/radio/src/translations/pt.h.txt +++ b/radio/src/translations/pt.h.txt @@ -535,7 +535,7 @@ #define TR_ELEDIRECTION "PFD Sentido" #define TR_AILDIRECTION "AIL Sentido" #define TR_COLDIRECTION "COL Sentido" -#define TR_MODE INDENT"Modo" +#define TR_MODE "Modo" #define TR_SUBTYPE INDENT "Subtype" #define TR_NOFREEEXPO "No free expo!" #define TR_NOFREEMIXER "No free mixer!" diff --git a/radio/src/translations/se.h.txt b/radio/src/translations/se.h.txt index 7ffad8438..a72ef145f 100644 --- a/radio/src/translations/se.h.txt +++ b/radio/src/translations/se.h.txt @@ -548,7 +548,7 @@ #define TR_ELEDIRECTION "HöJD Riktning" #define TR_AILDIRECTION "SKEV Riktning" #define TR_COLDIRECTION "PITCH Riktn. " -#define TR_MODE INDENT"Läge" +#define TR_MODE "Läge" #define TR_SUBTYPE INDENT "Subtype" #define TR_NOFREEEXPO "Expo saknas!" #define TR_NOFREEMIXER "Mixer saknas!" From 35c5ee64766f397218305e0217177efd2f57b462 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Mon, 17 Jun 2019 16:23:00 +0200 Subject: [PATCH 042/350] Cosmetics --- radio/src/gui/128x64/lcd.h | 2 -- radio/src/gui/212x64/gui.h | 2 -- radio/src/gui/480x272/menus.h | 2 -- radio/src/opentx_types.h | 1 + 4 files changed, 1 insertion(+), 6 deletions(-) diff --git a/radio/src/gui/128x64/lcd.h b/radio/src/gui/128x64/lcd.h index 331145572..e41091fb6 100644 --- a/radio/src/gui/128x64/lcd.h +++ b/radio/src/gui/128x64/lcd.h @@ -141,8 +141,6 @@ void putsChnLetter(coord_t x, coord_t y, uint8_t idx, LcdFlags attr); void putsVolts(coord_t x, coord_t y, uint16_t volts, LcdFlags att); void putsVBat(coord_t x, coord_t y, LcdFlags att); -#define FlightModesType uint16_t - void drawRtcTime(coord_t x, coord_t y, LcdFlags att); void drawTimer(coord_t x, coord_t y, int32_t tme, LcdFlags att, LcdFlags att2); void drawReceiverName(coord_t x, coord_t y, uint8_t moduleIdx, uint8_t receiverIdx, LcdFlags flags=0); diff --git a/radio/src/gui/212x64/gui.h b/radio/src/gui/212x64/gui.h index 2d131eff0..79481c56d 100644 --- a/radio/src/gui/212x64/gui.h +++ b/radio/src/gui/212x64/gui.h @@ -74,8 +74,6 @@ void showAlertBox(const char * title, const char * text, const char * action, ui void doMainScreenGraphics(); -typedef uint16_t FlightModesType; - extern int8_t checkIncDec_Ret; // global helper vars #define EDIT_SELECT_FIELD 0 diff --git a/radio/src/gui/480x272/menus.h b/radio/src/gui/480x272/menus.h index 67e309ae9..13bbf3b1c 100644 --- a/radio/src/gui/480x272/menus.h +++ b/radio/src/gui/480x272/menus.h @@ -266,8 +266,6 @@ bool menuScreensTheme(event_t event); bool menuRadioSpectrumAnalyser(event_t event); bool menuRadioPowerMeter(event_t event); -typedef uint16_t FlightModesType; - extern int8_t checkIncDec_Ret; // global helper vars #define EDIT_SELECT_FIELD 0 diff --git a/radio/src/opentx_types.h b/radio/src/opentx_types.h index 8d6f86977..9851f5a5e 100644 --- a/radio/src/opentx_types.h +++ b/radio/src/opentx_types.h @@ -31,5 +31,6 @@ typedef int32_t swsrc_t; typedef int16_t safetych_t; typedef uint32_t bitfield_channels_t; typedef uint16_t event_t; +typedef uint16_t FlightModesType; #endif // _OPENTX_TYPES_H_ From a83ce6a4d530272af3b58e687de6467522d76d17 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Mon, 17 Jun 2019 17:16:06 +0200 Subject: [PATCH 043/350] Cosmetics --- radio/src/gui/128x64/model_setup.cpp | 2 +- radio/src/gui/212x64/model_setup.cpp | 6 +++--- radio/src/gui/480x272/model_setup.cpp | 6 +++--- radio/src/translations.cpp | 1 - radio/src/translations.h | 1 - radio/src/translations/cz.h.txt | 1 - radio/src/translations/de.h.txt | 1 - radio/src/translations/en.h.txt | 1 - radio/src/translations/es.h.txt | 1 - radio/src/translations/fi.h.txt | 1 - radio/src/translations/fr.h.txt | 1 - radio/src/translations/it.h.txt | 1 - radio/src/translations/nl.h.txt | 1 - radio/src/translations/pl.h.txt | 1 - radio/src/translations/pt.h.txt | 1 - radio/src/translations/se.h.txt | 1 - 16 files changed, 7 insertions(+), 20 deletions(-) diff --git a/radio/src/gui/128x64/model_setup.cpp b/radio/src/gui/128x64/model_setup.cpp index 6e1ffc8a4..cfb95e554 100644 --- a/radio/src/gui/128x64/model_setup.cpp +++ b/radio/src/gui/128x64/model_setup.cpp @@ -449,7 +449,7 @@ void menuModelSetup(event_t event) case ITEM_MODEL_SETUP_TIMER3_NAME: { TimerData * timer = &g_model.timers[k>=ITEM_MODEL_SETUP_TIMER3 ? 2 : (k>=ITEM_MODEL_SETUP_TIMER2 ? 1 : 0)]; - editSingleName(MODEL_SETUP_2ND_COLUMN, y, STR_TIMER_NAME, timer->name, sizeof(timer->name), event, attr); + editSingleName(MODEL_SETUP_2ND_COLUMN, y, INDENT TR_NAME, timer->name, sizeof(timer->name), event, attr); break; } diff --git a/radio/src/gui/212x64/model_setup.cpp b/radio/src/gui/212x64/model_setup.cpp index 94122139b..cc6aefead 100644 --- a/radio/src/gui/212x64/model_setup.cpp +++ b/radio/src/gui/212x64/model_setup.cpp @@ -401,7 +401,7 @@ void menuModelSetup(event_t event) break; case ITEM_MODEL_SETUP_TIMER1_NAME: - editSingleName(MODEL_SETUP_2ND_COLUMN, y, STR_TIMER_NAME, g_model.timers[0].name, LEN_TIMER_NAME, event, attr); + editSingleName(MODEL_SETUP_2ND_COLUMN, y, INDENT TR_NAME, g_model.timers[0].name, LEN_TIMER_NAME, event, attr); break; case ITEM_MODEL_SETUP_TIMER1_MINUTE_BEEP: @@ -422,7 +422,7 @@ void menuModelSetup(event_t event) break; case ITEM_MODEL_SETUP_TIMER2_NAME: - editSingleName(MODEL_SETUP_2ND_COLUMN, y, STR_TIMER_NAME, g_model.timers[1].name, LEN_TIMER_NAME, event, attr); + editSingleName(MODEL_SETUP_2ND_COLUMN, y, INDENT TR_NAME, g_model.timers[1].name, LEN_TIMER_NAME, event, attr); break; case ITEM_MODEL_SETUP_TIMER2_MINUTE_BEEP: @@ -444,7 +444,7 @@ void menuModelSetup(event_t event) break; case ITEM_MODEL_SETUP_TIMER3_NAME: - editSingleName(MODEL_SETUP_2ND_COLUMN, y, STR_TIMER_NAME, g_model.timers[2].name, LEN_TIMER_NAME, event, attr); + editSingleName(MODEL_SETUP_2ND_COLUMN, y, INDENT TR_NAME, g_model.timers[2].name, LEN_TIMER_NAME, event, attr); break; case ITEM_MODEL_SETUP_TIMER3_MINUTE_BEEP: diff --git a/radio/src/gui/480x272/model_setup.cpp b/radio/src/gui/480x272/model_setup.cpp index f512a6859..0364e935f 100644 --- a/radio/src/gui/480x272/model_setup.cpp +++ b/radio/src/gui/480x272/model_setup.cpp @@ -342,7 +342,7 @@ bool menuModelSetup(event_t event) break; case ITEM_MODEL_TIMER1_NAME: - lcdDrawText(MENUS_MARGIN_LEFT, y, STR_TIMER_NAME); + lcdDrawText(MENUS_MARGIN_LEFT, y, INDENT TR_NAME); editName(MODEL_SETUP_2ND_COLUMN, y, g_model.timers[0].name, LEN_TIMER_NAME, event, attr); break; @@ -366,7 +366,7 @@ bool menuModelSetup(event_t event) break; case ITEM_MODEL_TIMER2_NAME: - lcdDrawText(MENUS_MARGIN_LEFT, y, STR_TIMER_NAME); + lcdDrawText(MENUS_MARGIN_LEFT, y, INDENT TR_NAME); editName(MODEL_SETUP_2ND_COLUMN, y, g_model.timers[1].name, LEN_TIMER_NAME, event, attr); break; @@ -391,7 +391,7 @@ bool menuModelSetup(event_t event) break; case ITEM_MODEL_TIMER3_NAME: - lcdDrawText(MENUS_MARGIN_LEFT, y, STR_TIMER_NAME); + lcdDrawText(MENUS_MARGIN_LEFT, y, INDENT TR_NAME); editName(MODEL_SETUP_2ND_COLUMN, y, g_model.timers[2].name, LEN_TIMER_NAME, event, attr); break; diff --git a/radio/src/translations.cpp b/radio/src/translations.cpp index caf79251e..6a6a34901 100644 --- a/radio/src/translations.cpp +++ b/radio/src/translations.cpp @@ -187,7 +187,6 @@ const char STR_MODEL_STILL_POWERED[] = TR_MODEL_STILL_POWERED; const char STR_MODEL_SHUTDOWN[] = TR_MODEL_SHUTDOWN; const char STR_PRESS_ENTER_TO_CONFIRM[] = TR_PRESS_ENTER_TO_CONFIRM; const char STR_THROTTLEREVERSE[] = TR_THROTTLEREVERSE; -const char STR_TIMER_NAME[] = TR_TIMER_NAME; const char STR_MINUTEBEEP[] = TR_MINUTEBEEP; const char STR_BEEPCOUNTDOWN[] = TR_BEEPCOUNTDOWN; const char STR_PERSISTENT[] = TR_PERSISTENT; diff --git a/radio/src/translations.h b/radio/src/translations.h index 2d07b31e0..c91be1df9 100644 --- a/radio/src/translations.h +++ b/radio/src/translations.h @@ -288,7 +288,6 @@ extern const char STR_MODEL_STILL_POWERED[]; extern const char STR_MODEL_SHUTDOWN[]; extern const char STR_PRESS_ENTER_TO_CONFIRM[]; extern const char STR_THROTTLEREVERSE[]; -extern const char STR_TIMER_NAME[]; extern const char STR_MINUTEBEEP[]; extern const char STR_BEEPCOUNTDOWN[]; extern const char STR_PERSISTENT[]; diff --git a/radio/src/translations/cz.h.txt b/radio/src/translations/cz.h.txt index 7b6f0d15b..eaeb9c3e8 100644 --- a/radio/src/translations/cz.h.txt +++ b/radio/src/translations/cz.h.txt @@ -588,7 +588,6 @@ #define TR_RENAVIG "Navig. RotEnc" #define TR_THROTTLE_LABEL "Plyn" #define TR_THROTTLEREVERSE TR("ReversPlyn", INDENT"Revers plynu") -#define TR_TIMER_NAME INDENT "Název" #define TR_MINUTEBEEP TR(INDENT"Minuta", INDENT"Oznamovat minuty") #define TR_BEEPCOUNTDOWN INDENT"Odpočet" #define TR_PERSISTENT INDENT"Trvalé" diff --git a/radio/src/translations/de.h.txt b/radio/src/translations/de.h.txt index 8807d478e..534644682 100644 --- a/radio/src/translations/de.h.txt +++ b/radio/src/translations/de.h.txt @@ -595,7 +595,6 @@ #define TR_RENAVIG "Drehgeb. Navig." #define TR_THROTTLE_LABEL "Gas-Kontrolle" #define TR_THROTTLEREVERSE TR("Gas invers", INDENT "Vollgas hinten?") //Änderung wg TH9x, Taranis -#define TR_TIMER_NAME INDENT "Name" #define TR_MINUTEBEEP TR(INDENT "Min-Alarm", INDENT "Minuten-Alarm") #define TR_BEEPCOUNTDOWN INDENT "Countdown" #define TR_PERSISTENT TR(INDENT "Permanent", INDENT "Permanent") diff --git a/radio/src/translations/en.h.txt b/radio/src/translations/en.h.txt index 605c5cb9e..006561031 100644 --- a/radio/src/translations/en.h.txt +++ b/radio/src/translations/en.h.txt @@ -590,7 +590,6 @@ #define TR_RENAVIG "RotEnc Navig" #define TR_THROTTLE_LABEL "Throttle" #define TR_THROTTLEREVERSE TR("T-Reverse", INDENT "Reverse") -#define TR_TIMER_NAME INDENT "Name" #define TR_MINUTEBEEP TR(INDENT "Minute", INDENT "Minute call") #define TR_BEEPCOUNTDOWN INDENT "Countdown" #define TR_PERSISTENT TR(INDENT "Persist.", INDENT "Persistent") diff --git a/radio/src/translations/es.h.txt b/radio/src/translations/es.h.txt index 8e7f46a0f..e247bb789 100644 --- a/radio/src/translations/es.h.txt +++ b/radio/src/translations/es.h.txt @@ -606,7 +606,6 @@ #define TR_RENAVIG "RotEnc Navig" #define TR_THROTTLE_LABEL "Throttle" #define TR_THROTTLEREVERSE TR("Invert_Acel", INDENT "Invertir Acel.") -#define TR_TIMER_NAME INDENT "Name" #define TR_MINUTEBEEP TR(INDENT"Minuto", INDENT"Cada Minuto") #define TR_BEEPCOUNTDOWN INDENT"Cuentaatras" #define TR_PERSISTENT TR(INDENT"Persist.", INDENT"Persistente") diff --git a/radio/src/translations/fi.h.txt b/radio/src/translations/fi.h.txt index 51b8a081a..62eeda86a 100644 --- a/radio/src/translations/fi.h.txt +++ b/radio/src/translations/fi.h.txt @@ -598,7 +598,6 @@ #define TR_RENAVIG "RotEnc Navig" #define TR_THROTTLE_LABEL "Throttle" #define TR_THROTTLEREVERSE TR("T-Reverse", INDENT "Throttle reverse") -#define TR_TIMER_NAME INDENT "Name" #define TR_MINUTEBEEP TR(INDENT"Minute", INDENT"Minute call") #define TR_BEEPCOUNTDOWN INDENT"Countdown" #define TR_PERSISTENT TR(INDENT"Persist.", INDENT"Persistent") diff --git a/radio/src/translations/fr.h.txt b/radio/src/translations/fr.h.txt index 108318792..eaa4cb9a9 100644 --- a/radio/src/translations/fr.h.txt +++ b/radio/src/translations/fr.h.txt @@ -604,7 +604,6 @@ #define TR_RENAVIG "Navig EncRot" #define TR_THROTTLE_LABEL "Gaz" #define TR_THROTTLEREVERSE TR("Inv. gaz", INDENT "Inversion gaz") -#define TR_TIMER_NAME INDENT "Nom" #define TR_MINUTEBEEP TR(INDENT "Bip min.", INDENT "Annonces minutes") #define TR_BEEPCOUNTDOWN TR(INDENT "Bip fin", INDENT "Compte à rebours") #define TR_PERSISTENT TR(INDENT "Persist.", INDENT "Persistant") diff --git a/radio/src/translations/it.h.txt b/radio/src/translations/it.h.txt index 977c94cc1..bdcc05350 100644 --- a/radio/src/translations/it.h.txt +++ b/radio/src/translations/it.h.txt @@ -605,7 +605,6 @@ #define TR_RENAVIG "Navig EncRot " #define TR_THROTTLE_LABEL "Motore" #define TR_THROTTLEREVERSE TR("Mot inv.", INDENT "Motore Inverso") -#define TR_TIMER_NAME INDENT "Nome" #define TR_MINUTEBEEP INDENT"Minuto" #define TR_BEEPCOUNTDOWN TR(INDENT"Conto rov", INDENT"Conto rovescia") #define TR_PERSISTENT TR(INDENT"Persist.", INDENT"Persistente") diff --git a/radio/src/translations/nl.h.txt b/radio/src/translations/nl.h.txt index e8d5f18b8..f085e70a5 100644 --- a/radio/src/translations/nl.h.txt +++ b/radio/src/translations/nl.h.txt @@ -589,7 +589,6 @@ TR_GYR_VSRCRAW #define TR_RENAVIG "Stappenschakelaar" #define TR_THROTTLE_LABEL "Gas" #define TR_THROTTLEREVERSE TR("Reverse", INDENT "Omgekeerd") -#define TR_TIMER_NAME INDENT "Naam" #define TR_MINUTEBEEP TR(INDENT "Min-Alarm", INDENT "Minuten-Alarm") #define TR_BEEPCOUNTDOWN INDENT "Countdown" #define TR_PERSISTENT TR(INDENT "Vasth.", INDENT "Vasthouden") diff --git a/radio/src/translations/pl.h.txt b/radio/src/translations/pl.h.txt index 2c52d7057..210abc63a 100644 --- a/radio/src/translations/pl.h.txt +++ b/radio/src/translations/pl.h.txt @@ -605,7 +605,6 @@ #define TR_RENAVIG "Nawigacja potencjometrem" #define TR_THROTTLE_LABEL "Gaz " #define TR_THROTTLEREVERSE TR("OdwrGaz", INDENT "OdwrGaz") -#define TR_TIMER_NAME INDENT "Nazwa" #define TR_MINUTEBEEP TR(INDENT "Minuta", INDENT "PikCoMinutę") #define TR_BEEPCOUNTDOWN INDENT "Odliczanie" #define TR_PERSISTENT TR(INDENT "Dokł.", INDENT "Dokładny") diff --git a/radio/src/translations/pt.h.txt b/radio/src/translations/pt.h.txt index 6c35d5e9a..192e59226 100644 --- a/radio/src/translations/pt.h.txt +++ b/radio/src/translations/pt.h.txt @@ -591,7 +591,6 @@ #define TR_RENAVIG "RotEnc Navig" #define TR_THROTTLE_LABEL "Throttle" #define TR_THROTTLEREVERSE TR("Inverte Acel.", INDENT "Inverte Acel.") -#define TR_TIMER_NAME INDENT "Name" #define TR_MINUTEBEEP INDENT "Beep Minuto" #define TR_BEEPCOUNTDOWN INDENT "Beep Regressivo" #define TR_PERSISTENT INDENT "Persist." diff --git a/radio/src/translations/se.h.txt b/radio/src/translations/se.h.txt index a72ef145f..328cdbfc5 100644 --- a/radio/src/translations/se.h.txt +++ b/radio/src/translations/se.h.txt @@ -604,7 +604,6 @@ #define TR_RENAVIG "RotEnk Navig" #define TR_THROTTLE_LABEL "Gas" #define TR_THROTTLEREVERSE TR("Inv.Gas", INDENT "Inverterad Gas") -#define TR_TIMER_NAME INDENT "Namn" #define TR_MINUTEBEEP INDENT "Minutpip" #define TR_BEEPCOUNTDOWN INDENT "Nedräkning" #define TR_PERSISTENT TR("Jämt på ", INDENT"Alltid På") From ad215a2e95bfaaa36e93c504124aab1d4fbfaf23 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Mon, 17 Jun 2019 17:22:09 +0200 Subject: [PATCH 044/350] Cosmetics --- radio/src/gui/128x64/model_setup.cpp | 2 +- radio/src/gui/212x64/model_setup.cpp | 6 +++--- radio/src/gui/480x272/model_setup.cpp | 6 +++--- 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 +- 14 files changed, 18 insertions(+), 18 deletions(-) diff --git a/radio/src/gui/128x64/model_setup.cpp b/radio/src/gui/128x64/model_setup.cpp index cfb95e554..67b045780 100644 --- a/radio/src/gui/128x64/model_setup.cpp +++ b/radio/src/gui/128x64/model_setup.cpp @@ -458,7 +458,7 @@ void menuModelSetup(event_t event) case ITEM_MODEL_SETUP_TIMER3_MINUTE_BEEP: { TimerData * timer = &g_model.timers[k>=ITEM_MODEL_SETUP_TIMER3 ? 2 : (k>=ITEM_MODEL_SETUP_TIMER2 ? 1 : 0)]; - timer->minuteBeep = editCheckBox(timer->minuteBeep, MODEL_SETUP_2ND_COLUMN, y, STR_MINUTEBEEP, attr, event); + timer->minuteBeep = editCheckBox(timer->minuteBeep, MODEL_SETUP_2ND_COLUMN, y, INDENT TR_MINUTEBEEP, attr, event); break; } diff --git a/radio/src/gui/212x64/model_setup.cpp b/radio/src/gui/212x64/model_setup.cpp index cc6aefead..3b2885d4b 100644 --- a/radio/src/gui/212x64/model_setup.cpp +++ b/radio/src/gui/212x64/model_setup.cpp @@ -405,7 +405,7 @@ void menuModelSetup(event_t event) break; case ITEM_MODEL_SETUP_TIMER1_MINUTE_BEEP: - g_model.timers[0].minuteBeep = editCheckBox(g_model.timers[0].minuteBeep, MODEL_SETUP_2ND_COLUMN, y, STR_MINUTEBEEP, attr, event); + g_model.timers[0].minuteBeep = editCheckBox(g_model.timers[0].minuteBeep, MODEL_SETUP_2ND_COLUMN, y, INDENT TR_MINUTEBEEP, attr, event); break; case ITEM_MODEL_SETUP_TIMER1_COUNTDOWN_BEEP: @@ -426,7 +426,7 @@ void menuModelSetup(event_t event) break; case ITEM_MODEL_SETUP_TIMER2_MINUTE_BEEP: - g_model.timers[1].minuteBeep = editCheckBox(g_model.timers[1].minuteBeep, MODEL_SETUP_2ND_COLUMN, y, STR_MINUTEBEEP, attr, event); + g_model.timers[1].minuteBeep = editCheckBox(g_model.timers[1].minuteBeep, MODEL_SETUP_2ND_COLUMN, y, INDENT TR_MINUTEBEEP, attr, event); break; case ITEM_MODEL_SETUP_TIMER2_COUNTDOWN_BEEP: @@ -448,7 +448,7 @@ void menuModelSetup(event_t event) break; case ITEM_MODEL_SETUP_TIMER3_MINUTE_BEEP: - g_model.timers[2].minuteBeep = editCheckBox(g_model.timers[2].minuteBeep, MODEL_SETUP_2ND_COLUMN, y, STR_MINUTEBEEP, attr, event); + g_model.timers[2].minuteBeep = editCheckBox(g_model.timers[2].minuteBeep, MODEL_SETUP_2ND_COLUMN, y, INDENT TR_MINUTEBEEP, attr, event); break; case ITEM_MODEL_SETUP_TIMER3_COUNTDOWN_BEEP: diff --git a/radio/src/gui/480x272/model_setup.cpp b/radio/src/gui/480x272/model_setup.cpp index 0364e935f..630d9971d 100644 --- a/radio/src/gui/480x272/model_setup.cpp +++ b/radio/src/gui/480x272/model_setup.cpp @@ -347,7 +347,7 @@ bool menuModelSetup(event_t event) break; case ITEM_MODEL_TIMER1_MINUTE_BEEP: - lcdDrawText(MENUS_MARGIN_LEFT, y, STR_MINUTEBEEP); + lcdDrawText(MENUS_MARGIN_LEFT, y, INDENT TR_MINUTEBEEP); g_model.timers[0].minuteBeep = editCheckBox(g_model.timers[0].minuteBeep, MODEL_SETUP_2ND_COLUMN, y, attr, event); break; @@ -371,7 +371,7 @@ bool menuModelSetup(event_t event) break; case ITEM_MODEL_TIMER2_MINUTE_BEEP: - lcdDrawText(MENUS_MARGIN_LEFT, y, STR_MINUTEBEEP); + lcdDrawText(MENUS_MARGIN_LEFT, y, INDENT TR_MINUTEBEEP); g_model.timers[1].minuteBeep = editCheckBox(g_model.timers[1].minuteBeep, MODEL_SETUP_2ND_COLUMN, y, attr, event); break; @@ -396,7 +396,7 @@ bool menuModelSetup(event_t event) break; case ITEM_MODEL_TIMER3_MINUTE_BEEP: - lcdDrawText(MENUS_MARGIN_LEFT, y, STR_MINUTEBEEP); + lcdDrawText(MENUS_MARGIN_LEFT, y, INDENT TR_MINUTEBEEP); g_model.timers[2].minuteBeep = editCheckBox(g_model.timers[2].minuteBeep, MODEL_SETUP_2ND_COLUMN, y, attr, event); break; diff --git a/radio/src/translations/cz.h.txt b/radio/src/translations/cz.h.txt index eaeb9c3e8..9ae720a08 100644 --- a/radio/src/translations/cz.h.txt +++ b/radio/src/translations/cz.h.txt @@ -588,7 +588,7 @@ #define TR_RENAVIG "Navig. RotEnc" #define TR_THROTTLE_LABEL "Plyn" #define TR_THROTTLEREVERSE TR("ReversPlyn", INDENT"Revers plynu") -#define TR_MINUTEBEEP TR(INDENT"Minuta", INDENT"Oznamovat minuty") +#define TR_MINUTEBEEP TR("Minuta", "Oznamovat minuty") #define TR_BEEPCOUNTDOWN INDENT"Odpočet" #define TR_PERSISTENT INDENT"Trvalé" #define TR_BACKLIGHT_LABEL "Podsvětlení" diff --git a/radio/src/translations/de.h.txt b/radio/src/translations/de.h.txt index 534644682..22dcaae24 100644 --- a/radio/src/translations/de.h.txt +++ b/radio/src/translations/de.h.txt @@ -595,7 +595,7 @@ #define TR_RENAVIG "Drehgeb. Navig." #define TR_THROTTLE_LABEL "Gas-Kontrolle" #define TR_THROTTLEREVERSE TR("Gas invers", INDENT "Vollgas hinten?") //Änderung wg TH9x, Taranis -#define TR_MINUTEBEEP TR(INDENT "Min-Alarm", INDENT "Minuten-Alarm") +#define TR_MINUTEBEEP TR("Min-Alarm", "Minuten-Alarm") #define TR_BEEPCOUNTDOWN INDENT "Countdown" #define TR_PERSISTENT TR(INDENT "Permanent", INDENT "Permanent") #define TR_BACKLIGHT_LABEL "LCD-Beleuchtung" diff --git a/radio/src/translations/en.h.txt b/radio/src/translations/en.h.txt index 006561031..522df75a9 100644 --- a/radio/src/translations/en.h.txt +++ b/radio/src/translations/en.h.txt @@ -590,7 +590,7 @@ #define TR_RENAVIG "RotEnc Navig" #define TR_THROTTLE_LABEL "Throttle" #define TR_THROTTLEREVERSE TR("T-Reverse", INDENT "Reverse") -#define TR_MINUTEBEEP TR(INDENT "Minute", INDENT "Minute call") +#define TR_MINUTEBEEP TR("Minute", "Minute call") #define TR_BEEPCOUNTDOWN INDENT "Countdown" #define TR_PERSISTENT TR(INDENT "Persist.", INDENT "Persistent") #define TR_BACKLIGHT_LABEL "Backlight" diff --git a/radio/src/translations/es.h.txt b/radio/src/translations/es.h.txt index e247bb789..b4ea0f867 100644 --- a/radio/src/translations/es.h.txt +++ b/radio/src/translations/es.h.txt @@ -606,7 +606,7 @@ #define TR_RENAVIG "RotEnc Navig" #define TR_THROTTLE_LABEL "Throttle" #define TR_THROTTLEREVERSE TR("Invert_Acel", INDENT "Invertir Acel.") -#define TR_MINUTEBEEP TR(INDENT"Minuto", INDENT"Cada Minuto") +#define TR_MINUTEBEEP TR("Minuto", "Cada Minuto") #define TR_BEEPCOUNTDOWN INDENT"Cuentaatras" #define TR_PERSISTENT TR(INDENT"Persist.", INDENT"Persistente") #define TR_BACKLIGHT_LABEL "Luz Fondo" diff --git a/radio/src/translations/fi.h.txt b/radio/src/translations/fi.h.txt index 62eeda86a..fa03cff4b 100644 --- a/radio/src/translations/fi.h.txt +++ b/radio/src/translations/fi.h.txt @@ -598,7 +598,7 @@ #define TR_RENAVIG "RotEnc Navig" #define TR_THROTTLE_LABEL "Throttle" #define TR_THROTTLEREVERSE TR("T-Reverse", INDENT "Throttle reverse") -#define TR_MINUTEBEEP TR(INDENT"Minute", INDENT"Minute call") +#define TR_MINUTEBEEP TR("Minute", "Minute call") #define TR_BEEPCOUNTDOWN INDENT"Countdown" #define TR_PERSISTENT TR(INDENT"Persist.", INDENT"Persistent") #define TR_BACKLIGHT_LABEL "Backlight" diff --git a/radio/src/translations/fr.h.txt b/radio/src/translations/fr.h.txt index eaa4cb9a9..fd5ca33e8 100644 --- a/radio/src/translations/fr.h.txt +++ b/radio/src/translations/fr.h.txt @@ -604,7 +604,7 @@ #define TR_RENAVIG "Navig EncRot" #define TR_THROTTLE_LABEL "Gaz" #define TR_THROTTLEREVERSE TR("Inv. gaz", INDENT "Inversion gaz") -#define TR_MINUTEBEEP TR(INDENT "Bip min.", INDENT "Annonces minutes") +#define TR_MINUTEBEEP TR("Bip min.", "Annonces minutes") #define TR_BEEPCOUNTDOWN TR(INDENT "Bip fin", INDENT "Compte à rebours") #define TR_PERSISTENT TR(INDENT "Persist.", INDENT "Persistant") #define TR_BACKLIGHT_LABEL "Rétroéclairage" diff --git a/radio/src/translations/it.h.txt b/radio/src/translations/it.h.txt index bdcc05350..d6b21ae07 100644 --- a/radio/src/translations/it.h.txt +++ b/radio/src/translations/it.h.txt @@ -605,7 +605,7 @@ #define TR_RENAVIG "Navig EncRot " #define TR_THROTTLE_LABEL "Motore" #define TR_THROTTLEREVERSE TR("Mot inv.", INDENT "Motore Inverso") -#define TR_MINUTEBEEP INDENT"Minuto" +#define TR_MINUTEBEEP "Minuto" #define TR_BEEPCOUNTDOWN TR(INDENT"Conto rov", INDENT"Conto rovescia") #define TR_PERSISTENT TR(INDENT"Persist.", INDENT"Persistente") #define TR_BACKLIGHT_LABEL TR("Retroillum.", "Retroilluminazione") diff --git a/radio/src/translations/nl.h.txt b/radio/src/translations/nl.h.txt index f085e70a5..aea5b781a 100644 --- a/radio/src/translations/nl.h.txt +++ b/radio/src/translations/nl.h.txt @@ -589,7 +589,7 @@ TR_GYR_VSRCRAW #define TR_RENAVIG "Stappenschakelaar" #define TR_THROTTLE_LABEL "Gas" #define TR_THROTTLEREVERSE TR("Reverse", INDENT "Omgekeerd") -#define TR_MINUTEBEEP TR(INDENT "Min-Alarm", INDENT "Minuten-Alarm") +#define TR_MINUTEBEEP TR("Min-Alarm", "Minuten-Alarm") #define TR_BEEPCOUNTDOWN INDENT "Countdown" #define TR_PERSISTENT TR(INDENT "Vasth.", INDENT "Vasthouden") #define TR_BACKLIGHT_LABEL "LCD-Verlichting" diff --git a/radio/src/translations/pl.h.txt b/radio/src/translations/pl.h.txt index 210abc63a..5eabd8fbd 100644 --- a/radio/src/translations/pl.h.txt +++ b/radio/src/translations/pl.h.txt @@ -605,7 +605,7 @@ #define TR_RENAVIG "Nawigacja potencjometrem" #define TR_THROTTLE_LABEL "Gaz " #define TR_THROTTLEREVERSE TR("OdwrGaz", INDENT "OdwrGaz") -#define TR_MINUTEBEEP TR(INDENT "Minuta", INDENT "PikCoMinutę") +#define TR_MINUTEBEEP TR("Minuta", "PikCoMinutę") #define TR_BEEPCOUNTDOWN INDENT "Odliczanie" #define TR_PERSISTENT TR(INDENT "Dokł.", INDENT "Dokładny") #define TR_BACKLIGHT_LABEL "Podświetl" diff --git a/radio/src/translations/pt.h.txt b/radio/src/translations/pt.h.txt index 192e59226..34db69a29 100644 --- a/radio/src/translations/pt.h.txt +++ b/radio/src/translations/pt.h.txt @@ -591,7 +591,7 @@ #define TR_RENAVIG "RotEnc Navig" #define TR_THROTTLE_LABEL "Throttle" #define TR_THROTTLEREVERSE TR("Inverte Acel.", INDENT "Inverte Acel.") -#define TR_MINUTEBEEP INDENT "Beep Minuto" +#define TR_MINUTEBEEP "Beep Minuto" #define TR_BEEPCOUNTDOWN INDENT "Beep Regressivo" #define TR_PERSISTENT INDENT "Persist." #define TR_BACKLIGHT_LABEL "Backlight" diff --git a/radio/src/translations/se.h.txt b/radio/src/translations/se.h.txt index 328cdbfc5..7c3bd6351 100644 --- a/radio/src/translations/se.h.txt +++ b/radio/src/translations/se.h.txt @@ -604,7 +604,7 @@ #define TR_RENAVIG "RotEnk Navig" #define TR_THROTTLE_LABEL "Gas" #define TR_THROTTLEREVERSE TR("Inv.Gas", INDENT "Inverterad Gas") -#define TR_MINUTEBEEP INDENT "Minutpip" +#define TR_MINUTEBEEP "Minutpip" #define TR_BEEPCOUNTDOWN INDENT "Nedräkning" #define TR_PERSISTENT TR("Jämt på ", INDENT"Alltid På") #define TR_BACKLIGHT_LABEL "Belysning" From 2cc02a84e1fe285f72eee44490a0a582d0abbc95 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Mon, 17 Jun 2019 17:46:51 +0200 Subject: [PATCH 045/350] Cosmetics --- radio/src/gui/128x64/CMakeLists.txt | 47 +++++++++++++++++ radio/src/gui/212x64/CMakeLists.txt | 47 +++++++++++++++++ radio/src/gui/480x272/CMakeLists.txt | 47 +++++++++++++++++ radio/src/gui/CMakeLists.txt | 55 ++------------------ radio/src/gui/common/colorlcd/CMakeLists.txt | 9 ++++ 5 files changed, 153 insertions(+), 52 deletions(-) create mode 100644 radio/src/gui/128x64/CMakeLists.txt create mode 100644 radio/src/gui/212x64/CMakeLists.txt create mode 100644 radio/src/gui/480x272/CMakeLists.txt create mode 100644 radio/src/gui/common/colorlcd/CMakeLists.txt diff --git a/radio/src/gui/128x64/CMakeLists.txt b/radio/src/gui/128x64/CMakeLists.txt new file mode 100644 index 000000000..da222492c --- /dev/null +++ b/radio/src/gui/128x64/CMakeLists.txt @@ -0,0 +1,47 @@ +set(GUI_SRC + ${GUI_SRC} + lcd.cpp + splash.cpp + fonts.cpp + popups.cpp + widgets.cpp + menu_model.cpp + model_select.cpp + model_setup.cpp + model_failsafe.cpp + model_logical_switches.cpp + special_functions.cpp + model_outputs.cpp + model_telemetry.cpp + model_telemetry_sensor.cpp + menu_radio.cpp + radio_setup.cpp + radio_trainer.cpp + radio_version.cpp + radio_hardware.cpp + radio_calibration.cpp + view_main.cpp + view_statistics.cpp + ) + +set(SRC + ${SRC} + gui/common/widgets.cpp + gui/common/arm/widgets.cpp + ) + +if(FLIGHT_MODES) + set(GUI_SRC + ${GUI_SRC} + model_flightmodes.cpp + ) +endif() + +if(LUA STREQUAL YES) + set(GUI_SRC + ${GUI_SRC} + model_custom_scripts.cpp + ) +endif() + +include(gui/common/stdlcd/CMakeLists.txt) diff --git a/radio/src/gui/212x64/CMakeLists.txt b/radio/src/gui/212x64/CMakeLists.txt new file mode 100644 index 000000000..da222492c --- /dev/null +++ b/radio/src/gui/212x64/CMakeLists.txt @@ -0,0 +1,47 @@ +set(GUI_SRC + ${GUI_SRC} + lcd.cpp + splash.cpp + fonts.cpp + popups.cpp + widgets.cpp + menu_model.cpp + model_select.cpp + model_setup.cpp + model_failsafe.cpp + model_logical_switches.cpp + special_functions.cpp + model_outputs.cpp + model_telemetry.cpp + model_telemetry_sensor.cpp + menu_radio.cpp + radio_setup.cpp + radio_trainer.cpp + radio_version.cpp + radio_hardware.cpp + radio_calibration.cpp + view_main.cpp + view_statistics.cpp + ) + +set(SRC + ${SRC} + gui/common/widgets.cpp + gui/common/arm/widgets.cpp + ) + +if(FLIGHT_MODES) + set(GUI_SRC + ${GUI_SRC} + model_flightmodes.cpp + ) +endif() + +if(LUA STREQUAL YES) + set(GUI_SRC + ${GUI_SRC} + model_custom_scripts.cpp + ) +endif() + +include(gui/common/stdlcd/CMakeLists.txt) diff --git a/radio/src/gui/480x272/CMakeLists.txt b/radio/src/gui/480x272/CMakeLists.txt new file mode 100644 index 000000000..1a722278f --- /dev/null +++ b/radio/src/gui/480x272/CMakeLists.txt @@ -0,0 +1,47 @@ +set(GUI_SRC + ${GUI_SRC} + lcd.cpp + splash.cpp + fonts.cpp + popups.cpp + widgets.cpp + menu_model.cpp + model_select.cpp + model_setup.cpp + model_failsafe.cpp + model_logical_switches.cpp + model_special_functions.cpp + model_outputs.cpp + model_telemetry.cpp + model_telemetry_sensor.cpp + menu_radio.cpp + radio_setup.cpp + radio_trainer.cpp + radio_version.cpp + radio_hardware.cpp + radio_calibration.cpp + view_main.cpp + view_statistics.cpp + ) + +set(SRC + ${SRC} + gui/common/widgets.cpp + gui/common/arm/widgets.cpp + ) + +if(FLIGHT_MODES) + set(GUI_SRC + ${GUI_SRC} + model_flightmodes.cpp + ) +endif() + +if(LUA STREQUAL YES) + set(GUI_SRC + ${GUI_SRC} + model_custom_scripts.cpp + ) +endif() + +include(gui/common/colorlcd/CMakeLists.txt) diff --git a/radio/src/gui/CMakeLists.txt b/radio/src/gui/CMakeLists.txt index 5c13c957c..0e42d74ec 100644 --- a/radio/src/gui/CMakeLists.txt +++ b/radio/src/gui/CMakeLists.txt @@ -1,60 +1,11 @@ -set(GUI_SRC - ${GUI_SRC} - lcd.cpp - splash.cpp - fonts.cpp - popups.cpp - widgets.cpp - menu_model.cpp - model_select.cpp - model_setup.cpp - model_outputs.cpp - model_failsafe.cpp - model_logical_switches.cpp - model_special_functions.cpp - model_telemetry.cpp - model_telemetry_sensor.cpp - menu_radio.cpp - radio_setup.cpp - radio_trainer.cpp - radio_version.cpp - radio_calibration.cpp - view_main.cpp - view_statistics.cpp - ) +include(gui/${GUI_DIR}/CMakeLists.txt) +include_directories(gui gui/${GUI_DIR}) set(SRC ${SRC} - gui/common/widgets.cpp - gui/navigation/navigation_${NAVIGATION_TYPE}.cpp gui/navigation/common.cpp + gui/navigation/navigation_${NAVIGATION_TYPE}.cpp ) - string(TOUPPER ${NAVIGATION_TYPE} NAVIGATION_TYPE) add_definitions(-DNAVIGATION_${NAVIGATION_TYPE}) - -include_directories(gui gui/${GUI_DIR}) - -if(GUI_DIR STREQUAL 128x64 OR GUI_DIR STREQUAL 212x64) - include(gui/common/stdlcd/CMakeLists.txt) -endif() - -if(ARCH STREQUAL ARM) - set(SRC - ${SRC} - gui/common/arm/widgets.cpp - ) -endif() - -if(PCB STREQUAL X12S OR PCB STREQUAL X10) - if(HELI) - set(HELI_SRC gui/common/colorlcd/model_heli.cpp) - endif() - - set(SRC - ${SRC} - gui/common/colorlcd/widgets.cpp - ${HELI_SRC} - ) -endif() diff --git a/radio/src/gui/common/colorlcd/CMakeLists.txt b/radio/src/gui/common/colorlcd/CMakeLists.txt new file mode 100644 index 000000000..81271fe23 --- /dev/null +++ b/radio/src/gui/common/colorlcd/CMakeLists.txt @@ -0,0 +1,9 @@ +set(GUI_SRC + ${GUI_SRC} + ../common/colorlcd/widgets.cpp + ) + +if(HELI) + set(GUI_SRC ${GUI_SRC} ../common/colorlcd/model_heli.cpp) +endif() + From ad13301389eed498cf519dead289fdafac50f44c Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Mon, 17 Jun 2019 18:57:38 +0200 Subject: [PATCH 046/350] Compilation fix --- radio/src/gui/128x64/CMakeLists.txt | 2 +- radio/src/gui/212x64/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/radio/src/gui/128x64/CMakeLists.txt b/radio/src/gui/128x64/CMakeLists.txt index da222492c..ba48b93f6 100644 --- a/radio/src/gui/128x64/CMakeLists.txt +++ b/radio/src/gui/128x64/CMakeLists.txt @@ -10,7 +10,7 @@ set(GUI_SRC model_setup.cpp model_failsafe.cpp model_logical_switches.cpp - special_functions.cpp + model_special_functions.cpp model_outputs.cpp model_telemetry.cpp model_telemetry_sensor.cpp diff --git a/radio/src/gui/212x64/CMakeLists.txt b/radio/src/gui/212x64/CMakeLists.txt index da222492c..ba48b93f6 100644 --- a/radio/src/gui/212x64/CMakeLists.txt +++ b/radio/src/gui/212x64/CMakeLists.txt @@ -10,7 +10,7 @@ set(GUI_SRC model_setup.cpp model_failsafe.cpp model_logical_switches.cpp - special_functions.cpp + model_special_functions.cpp model_outputs.cpp model_telemetry.cpp model_telemetry_sensor.cpp From afa69cb0c5897a3bc18eedf4eaebcbd7e373bc3b Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Tue, 18 Jun 2019 12:13:11 +0200 Subject: [PATCH 047/350] Thread names and cosmetics --- radio/src/rtos.h | 3 +- radio/src/simu.cpp | 145 +++++++++++++------------ radio/src/targets/simu/simpgmspace.cpp | 3 +- radio/src/targets/simu/simueeprom.cpp | 17 +-- radio/src/tasks.cpp | 6 +- 5 files changed, 92 insertions(+), 82 deletions(-) diff --git a/radio/src/rtos.h b/radio/src/rtos.h index a67ee9887..b439ecea6 100644 --- a/radio/src/rtos.h +++ b/radio/src/rtos.h @@ -114,9 +114,10 @@ extern "C++" { #define TASK_FUNCTION(task) void * task(void * pdata) template - inline void RTOS_CREATE_TASK(pthread_t &taskId, void * task(void *), const char *, FakeTaskStack &, unsigned, unsigned) + inline void RTOS_CREATE_TASK(pthread_t &taskId, void * task(void *), const char * name, FakeTaskStack &, unsigned, unsigned) { pthread_create(&taskId, nullptr, task, nullptr); + pthread_setname_np(taskId, name); } #define TASK_RETURN() return nullptr diff --git a/radio/src/simu.cpp b/radio/src/simu.cpp index 8bbf98260..3c16325f9 100644 --- a/radio/src/simu.cpp +++ b/radio/src/simu.cpp @@ -42,14 +42,14 @@ #define W2 LCD_W*LCD_ZOOM #define H2 LCD_H*LCD_ZOOM -class Open9xSim: public FXMainWindow +class OpenTxSim: public FXMainWindow { - FXDECLARE(Open9xSim) + FXDECLARE(OpenTxSim) public: - Open9xSim(){}; - Open9xSim(FXApp* a); - ~Open9xSim(); + OpenTxSim(){}; + OpenTxSim(FXApp* a); + ~OpenTxSim(); void updateKeysAndSwitches(bool start=false); long onKeypress(FXObject*,FXSelector,void*); long onTimeout(FXObject*,FXSelector,void*); @@ -60,28 +60,26 @@ class Open9xSim: public FXMainWindow void setPixel(int x, int y, FXColor color); private: - FXImage *bmp; - FXImageFrame *bmf; - bool firstTime; + FXImage * bmp; + FXImageFrame * bmf; public: - FXSlider *sliders[NUM_STICKS]; - FXKnob *knobs[NUM_POTS+NUM_SLIDERS]; + FXSlider * sliders[NUM_STICKS]; + FXKnob * knobs[NUM_POTS+NUM_SLIDERS]; }; // Message Map -FXDEFMAP(Open9xSim) Open9xSimMap[] = { -//Message_Type _________ ID____Message_Handler_______ - FXMAPFUNC(SEL_TIMEOUT, 2, Open9xSim::onTimeout), - FXMAPFUNC(SEL_KEYPRESS, 0, Open9xSim::onKeypress), +FXDEFMAP(OpenTxSim) OpenTxSimMap[] = { + // Message_Type _______ID____Message_Handler_______ + FXMAPFUNC(SEL_TIMEOUT, 2, OpenTxSim::onTimeout), + FXMAPFUNC(SEL_KEYPRESS, 0, OpenTxSim::onKeypress), }; -FXIMPLEMENT(Open9xSim,FXMainWindow,Open9xSimMap,ARRAYNUMBER(Open9xSimMap)) +FXIMPLEMENT(OpenTxSim,FXMainWindow,OpenTxSimMap,ARRAYNUMBER(OpenTxSimMap)) -Open9xSim::Open9xSim(FXApp* a): +OpenTxSim::OpenTxSim(FXApp* a): FXMainWindow(a, "OpenTX Simu", NULL, NULL, DECOR_ALL, 20, 90, 0, 0) { - firstTime = true; memset(displayBuf, 0, DISPLAY_BUFFER_SIZE * sizeof(display_t)); bmp = new FXPPMImage(getApp(),NULL,IMAGE_OWNED|IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP, W2, H2); @@ -89,8 +87,8 @@ Open9xSim::Open9xSim(FXApp* a): SDL_Init(SDL_INIT_AUDIO); #endif - FXHorizontalFrame *hf11=new FXHorizontalFrame(this,LAYOUT_CENTER_X); - FXHorizontalFrame *hf1=new FXHorizontalFrame(this,LAYOUT_FILL_X); + FXHorizontalFrame * hf11 = new FXHorizontalFrame(this,LAYOUT_CENTER_X); + FXHorizontalFrame * hf1 = new FXHorizontalFrame(this,LAYOUT_FILL_X); //rh lv rv lh for (int i=0; i<4; i++) { @@ -131,16 +129,19 @@ Open9xSim::Open9xSim(FXApp* a): } bmf = new FXImageFrame(this,bmp); + bmf->enable(); + bmf->setTarget(this); updateKeysAndSwitches(true); getApp()->addTimeout(this, 2, 100); } -Open9xSim::~Open9xSim() +OpenTxSim::~OpenTxSim() { StopSimu(); StopAudioThread(); + #if defined(EEPROM) StopEepromThread(); #endif @@ -162,7 +163,7 @@ Open9xSim::~Open9xSim() #endif } -void Open9xSim::createBitmap(int index, uint16_t *data, int x, int y, int w, int h) +void OpenTxSim::createBitmap(int index, uint16_t *data, int x, int y, int w, int h) { FXPNGImage snapshot(getApp(), NULL, IMAGE_OWNED, w, h); @@ -187,59 +188,62 @@ void Open9xSim::createBitmap(int index, uint16_t *data, int x, int y, int w, int } } -void Open9xSim::makeSnapshot(const FXDrawable* drawable) +void OpenTxSim::makeSnapshot(const FXDrawable* drawable) { - // Construct and create an FXImage object - FXPNGImage snapshot(getApp(), NULL, 0, drawable->getWidth(), drawable->getHeight()); - snapshot.create(); + // Construct and create an FXImage object + FXPNGImage snapshot(getApp(), NULL, 0, drawable->getWidth(), drawable->getHeight()); + snapshot.create(); - // Create a window device context and lock it onto the image - FXDCWindow dc(&snapshot); + // Create a window device context and lock it onto the image + FXDCWindow dc(&snapshot); - // Draw from the widget to this - dc.drawArea(drawable, 0, 0, drawable->getWidth(), drawable->getHeight(), 0, 0); + // Draw from the widget to this + dc.drawArea(drawable, 0, 0, drawable->getWidth(), drawable->getHeight(), 0, 0); - // Release lock - dc.end(); + // Release lock + dc.end(); - // Grab pixels from server side back to client side - snapshot.restore(); + // Grab pixels from server side back to client side + snapshot.restore(); - // Save recovered pixels to a file - FXFileStream stream; - char buf[100]; + // Save recovered pixels to a file + FXFileStream stream; + char buf[100]; - do { - stream.close(); - sprintf(buf,"snapshot_%02d.png", ++g_snapshot_idx); - } while (stream.open(buf, FXStreamLoad)); + do { + stream.close(); + sprintf(buf, "snapshot_%02d.png", ++g_snapshot_idx); + } while (stream.open(buf, FXStreamLoad)); - if (stream.open(buf, FXStreamSave)) { - snapshot.savePixels(stream); - stream.close(); - printf("Snapshot written: %s\n", buf); - } - else { - printf("Cannot create snapshot %s\n", buf); - } + if (stream.open(buf, FXStreamSave)) { + snapshot.savePixels(stream); + stream.close(); + printf("Snapshot written: %s\n", buf); + } + else { + printf("Cannot create snapshot %s\n", buf); + } } -void Open9xSim::doEvents() +void OpenTxSim::doEvents() { getApp()->runOneEvent(false); } -long Open9xSim::onKeypress(FXObject*,FXSelector,void*v) +long OpenTxSim::onKeypress(FXObject *, FXSelector, void * v) { - FXEvent *evt=(FXEvent*)v; - // printf("keypress %x\n", evt->code); - if (evt->code=='s') { + FXEvent *evt = (FXEvent *)v; + + // TRACE("keypress %x", evt->code); + + if (evt->code == 's') { makeSnapshot(bmf); } + return 0; } -void Open9xSim::updateKeysAndSwitches(bool start) +void OpenTxSim::updateKeysAndSwitches(bool start) { static int keys1[] = { #if defined(PCBHORUS) @@ -352,7 +356,7 @@ void Open9xSim::updateKeysAndSwitches(bool start) #endif } -long Open9xSim::onTimeout(FXObject*, FXSelector, void*) +long OpenTxSim::onTimeout(FXObject*, FXSelector, void*) { if (hasFocus()) { #if defined(COPROCESSOR) @@ -442,7 +446,7 @@ long Open9xSim::onTimeout(FXObject*, FXSelector, void*) #define BL_COLOR FXRGB(150, 200, 152) #endif -void Open9xSim::setPixel(int x, int y, FXColor color) +void OpenTxSim::setPixel(int x, int y, FXColor color) { #if LCD_ZOOM > 1 for (int i=0; i= 212 +#elif LCD_DEPTH == 4 display_t * p = &simuLcdBuf[y / 2 * LCD_W + x]; uint8_t z = (y & 1) ? (*p >> 4) : (*p & 0x0F); if (z) { @@ -506,15 +510,16 @@ void Open9xSim::refreshDisplay() } } -Open9xSim *th9xSim; +OpenTxSim * opentxSim; + void doFxEvents() { //puts("doFxEvents"); - th9xSim->getApp()->runOneEvent(false); - th9xSim->refreshDisplay(); + opentxSim->getApp()->runOneEvent(false); + opentxSim->refreshDisplay(); } -int main(int argc,char **argv) +int main(int argc, char ** argv) { // Each FOX GUI program needs one, and only one, application object. // The application objects coordinates some common stuff shared between @@ -537,15 +542,15 @@ int main(int argc,char **argv) // drag handles, and so on the Window Manager is supposed to give this // window. //FXMainWindow *main=new FXMainWindow(&application,"Hello",NULL,NULL,DECOR_ALL); - th9xSim = new Open9xSim(&application); + opentxSim = new OpenTxSim(&application); application.create(); // Pretty self-explanatory:- this shows the window, and places it in the // middle of the screen. #ifndef __APPLE__ - th9xSim->show(PLACEMENT_SCREEN); + opentxSim->show(PLACEMENT_SCREEN); #else - th9xSim->show(); // Otherwise the main window gets centred across my two monitors, split down the middle. + opentxSim->show(); // Otherwise the main window gets centred across my two monitors, split down the middle. #endif #if defined(TELEMETRY_FRSKY) && !defined(TELEMETRY_FRSKY_SPORT) @@ -568,9 +573,9 @@ int main(int argc,char **argv) uint16_t anaIn(uint8_t chan) { if (chansliders[chan]->getValue(); + return opentxSim->sliders[chan]->getValue(); else if (chanknobs[chan-NUM_STICKS]->getValue(); + return opentxSim->knobs[chan-NUM_STICKS]->getValue(); #if defined(PCBHORUS) else if (chan == TX_VOLTAGE) return 1737; //~10.6V @@ -603,5 +608,5 @@ uint16_t getAnalogValue(uint8_t index) void createBitmap(int index, uint16_t *data, int x, int y, int w, int h) { - th9xSim->createBitmap(index, data, x, y, w, h); + opentxSim->createBitmap(index, data, x, y, w, h); } diff --git a/radio/src/targets/simu/simpgmspace.cpp b/radio/src/targets/simu/simpgmspace.cpp index e1436ab05..6a061eaca 100644 --- a/radio/src/targets/simu/simpgmspace.cpp +++ b/radio/src/targets/simu/simpgmspace.cpp @@ -554,7 +554,8 @@ void StartAudioThread(int volumeGain) struct sched_param sp; sp.sched_priority = SCHED_RR; pthread_attr_setschedparam(&attr, &sp); - pthread_create(&simuAudio.threadPid, &attr, &audioThread, NULL); + pthread_create(&simuAudio.threadPid, &attr, &audioThread, nullptr); + pthread_setname_np(simuAudio.threadPid, "audio"); return; } diff --git a/radio/src/targets/simu/simueeprom.cpp b/radio/src/targets/simu/simueeprom.cpp index 5aaaa4a7a..d2368c7c0 100644 --- a/radio/src/targets/simu/simueeprom.cpp +++ b/radio/src/targets/simu/simueeprom.cpp @@ -20,8 +20,8 @@ #include "opentx.h" -const char * eepromFile = NULL; -FILE * fp = NULL; +const char * eepromFile = nullptr; +FILE * fp = nullptr; uint32_t eeprom_pointer; uint8_t * eeprom_buffer_data; @@ -33,7 +33,7 @@ bool eeprom_thread_running = false; #if defined(EEPROM_SIZE) uint8_t eeprom[EEPROM_SIZE]; #else -uint8_t * eeprom = NULL; +uint8_t * eeprom = nullptr; #endif sem_t * eeprom_write_sem; @@ -75,7 +75,7 @@ void * eeprom_thread_function(void *) { while (!sem_wait(eeprom_write_sem)) { if (!eeprom_thread_running) - return NULL; + return nullptr; assert(eeprom_buffer_size); if (eeprom_read_operation) { eepromReadBlock(eeprom_buffer_data, eeprom_pointer, eeprom_buffer_size); @@ -162,17 +162,20 @@ void StartEepromThread(const char * filename) sem_init(eeprom_write_sem, 0, 0); #endif - if (!pthread_create(&eeprom_thread_pid, NULL, &eeprom_thread_function, NULL)) + if (!pthread_create(&eeprom_thread_pid, nullptr, &eeprom_thread_function, nullptr)) { + pthread_setname_np(eeprom_thread_pid, "eeprom"); eeprom_thread_running = true; - else + } + else { perror("Could not create eeprom thread."); + } } void StopEepromThread() { eeprom_thread_running = false; sem_post(eeprom_write_sem); - pthread_join(eeprom_thread_pid, NULL); + pthread_join(eeprom_thread_pid, nullptr); #ifdef __APPLE__ sem_close(eeprom_write_sem); diff --git a/radio/src/tasks.cpp b/radio/src/tasks.cpp index 1063b9574..dfbcb24f7 100644 --- a/radio/src/tasks.cpp +++ b/radio/src/tasks.cpp @@ -285,11 +285,11 @@ void tasksStart() cliStart(); #endif - RTOS_CREATE_TASK(mixerTaskId, mixerTask, "Mixer", mixerStack, MIXER_STACK_SIZE, MIXER_TASK_PRIO); - RTOS_CREATE_TASK(menusTaskId, menusTask, "Menus", menusStack, MENUS_STACK_SIZE, MENUS_TASK_PRIO); + RTOS_CREATE_TASK(mixerTaskId, mixerTask, "mixer", mixerStack, MIXER_STACK_SIZE, MIXER_TASK_PRIO); + RTOS_CREATE_TASK(menusTaskId, menusTask, "menus", menusStack, MENUS_STACK_SIZE, MENUS_TASK_PRIO); #if !defined(SIMU) - RTOS_CREATE_TASK(audioTaskId, audioTask, "Audio", audioStack, AUDIO_STACK_SIZE, AUDIO_TASK_PRIO); + RTOS_CREATE_TASK(audioTaskId, audioTask, "audio", audioStack, AUDIO_STACK_SIZE, AUDIO_TASK_PRIO); #endif RTOS_CREATE_MUTEX(audioMutex); From 65860da98648f43bb705d9eb99d35717411931d2 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Tue, 18 Jun 2019 12:41:29 +0200 Subject: [PATCH 048/350] Cosmetics --- radio/src/simu.cpp | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/radio/src/simu.cpp b/radio/src/simu.cpp index 3c16325f9..f775e7b14 100644 --- a/radio/src/simu.cpp +++ b/radio/src/simu.cpp @@ -51,8 +51,8 @@ class OpenTxSim: public FXMainWindow OpenTxSim(FXApp* a); ~OpenTxSim(); void updateKeysAndSwitches(bool start=false); - long onKeypress(FXObject*,FXSelector,void*); - long onTimeout(FXObject*,FXSelector,void*); + long onKeypress(FXObject*, FXSelector, void*); + long onTimeout(FXObject*, FXSelector, void*); void createBitmap(int index, uint16_t *data, int x, int y, int w, int h); void makeSnapshot(const FXDrawable* drawable); void doEvents(); @@ -75,36 +75,36 @@ FXDEFMAP(OpenTxSim) OpenTxSimMap[] = { FXMAPFUNC(SEL_KEYPRESS, 0, OpenTxSim::onKeypress), }; -FXIMPLEMENT(OpenTxSim,FXMainWindow,OpenTxSimMap,ARRAYNUMBER(OpenTxSimMap)) +FXIMPLEMENT(OpenTxSim, FXMainWindow, OpenTxSimMap, ARRAYNUMBER(OpenTxSimMap)) OpenTxSim::OpenTxSim(FXApp* a): - FXMainWindow(a, "OpenTX Simu", NULL, NULL, DECOR_ALL, 20, 90, 0, 0) + FXMainWindow(a, "OpenTX Simu", nullptr, nullptr, DECOR_ALL, 20, 90, 0, 0) { memset(displayBuf, 0, DISPLAY_BUFFER_SIZE * sizeof(display_t)); - bmp = new FXPPMImage(getApp(),NULL,IMAGE_OWNED|IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP, W2, H2); + bmp = new FXPPMImage(getApp(), nullptr, IMAGE_OWNED|IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP, W2, H2); #if defined(SIMU_AUDIO) SDL_Init(SDL_INIT_AUDIO); #endif - FXHorizontalFrame * hf11 = new FXHorizontalFrame(this,LAYOUT_CENTER_X); - FXHorizontalFrame * hf1 = new FXHorizontalFrame(this,LAYOUT_FILL_X); + FXHorizontalFrame * hf11 = new FXHorizontalFrame(this, LAYOUT_CENTER_X); + FXHorizontalFrame * hf1 = new FXHorizontalFrame(this, LAYOUT_FILL_X); //rh lv rv lh for (int i=0; i<4; i++) { switch (i) { #define L LAYOUT_FIX_WIDTH|LAYOUT_FIX_HEIGHT|LAYOUT_FIX_X|LAYOUT_FIX_Y case 0: - sliders[i]=new FXSlider(hf1,NULL,0,L|SLIDER_HORIZONTAL,10,110,100,20); + sliders[i]=new FXSlider(hf1, nullptr, 0, L|SLIDER_HORIZONTAL, 10, 110, 100, 20); break; case 1: - sliders[i]=new FXSlider(hf1,NULL,0,L|SLIDER_VERTICAL,110,10,20,100); + sliders[i]=new FXSlider(hf1, nullptr, 0, L|SLIDER_VERTICAL, 110, 10, 20, 100); break; case 2: - sliders[i]=new FXSlider(hf1,NULL,0,L|SLIDER_VERTICAL,130,10,20,100); + sliders[i]=new FXSlider(hf1, nullptr, 0, L|SLIDER_VERTICAL, 130, 10, 20, 100); break; case 3: - sliders[i]=new FXSlider(hf1,NULL,0,L|SLIDER_HORIZONTAL,150,110,100,20); + sliders[i]=new FXSlider(hf1, nullptr, 0, L|SLIDER_HORIZONTAL, 150, 110, 100, 20); break; default:; } @@ -114,7 +114,7 @@ OpenTxSim::OpenTxSim(FXApp* a): } for(int i=0; isetValue(0); #if defined(PCBHORUS) @@ -128,7 +128,7 @@ OpenTxSim::OpenTxSim(FXApp* a): knobs[i]->setRange(-1024, 1024); } - bmf = new FXImageFrame(this,bmp); + bmf = new FXImageFrame(this, bmp); bmf->enable(); bmf->setTarget(this); @@ -165,7 +165,7 @@ OpenTxSim::~OpenTxSim() void OpenTxSim::createBitmap(int index, uint16_t *data, int x, int y, int w, int h) { - FXPNGImage snapshot(getApp(), NULL, IMAGE_OWNED, w, h); + FXPNGImage snapshot(getApp(), nullptr, IMAGE_OWNED, w, h); for (int i=0; igetWidth(), drawable->getHeight()); + FXPNGImage snapshot(getApp(), nullptr, 0, drawable->getWidth(), drawable->getHeight()); snapshot.create(); // Create a window device context and lock it onto the image @@ -473,10 +473,10 @@ void OpenTxSim::refreshDisplay() display_t z = simuLcdBuf[y * LCD_W + x]; if (1) { if (z == 0) { - setPixel(x, y, FXRGB(0,0,0)); + setPixel(x, y, FXRGB(0, 0, 0)); } else if (z == 0xFFFF) { - setPixel(x, y, FXRGB(255,255,255)); + setPixel(x, y, FXRGB(255, 255, 255)); } else { FXColor color = FXRGB(255*((z&0xF800)>>11)/0x1f, 255*((z&0x07E0)>>5)/0x3F, 255*(z&0x001F)/0x01F); @@ -534,14 +534,14 @@ int main(int argc, char ** argv) // because FOX may sometimes need to filter out some of the arguments. // This opens up the display as well, and reads the registry database // so that persistent settings are now available. - application.init(argc,argv); + application.init(argc, argv); // This creates the main window. We pass in the title to be displayed // above the window, and possibly some icons for when its iconified. // The decorations determine stuff like the borders, close buttons, // drag handles, and so on the Window Manager is supposed to give this // window. - //FXMainWindow *main=new FXMainWindow(&application,"Hello",NULL,NULL,DECOR_ALL); + //FXMainWindow *main=new FXMainWindow(&application, "Hello", nullptr, nullptr, DECOR_ALL); opentxSim = new OpenTxSim(&application); application.create(); From 8a48cdb46136a0b70e521dd633b6ea06a8318965 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Tue, 18 Jun 2019 12:43:31 +0200 Subject: [PATCH 049/350] Cosmetics --- radio/util/font2png.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/radio/util/font2png.py b/radio/util/font2png.py index 86d0f9c40..caadfac11 100755 --- a/radio/util/font2png.py +++ b/radio/util/font2png.py @@ -29,7 +29,7 @@ def createFontBitmap(filename, fontname, fontsize, fontoffset, foreground, backg coords = [] font_filename = 'fonts/' + fontname + '.ttf' - print 'Font filename: %s' % font_filename + print("Font filename: %s" % font_filename) font = ImageFont.truetype(font_filename, fontsize) extraImage = None @@ -40,7 +40,7 @@ def createFontBitmap(filename, fontname, fontsize, fontoffset, foreground, backg extraImage = extraImage.convert('RGB'); except IOError: - print 'Missing extra symbol filename %s' % extraFilename + print("Missing extra symbol filename %s" % extraFilename) def getCharWidth(c): if c in chars_extra: @@ -67,7 +67,7 @@ def createFontBitmap(filename, fontname, fontsize, fontoffset, foreground, backg width = getFontWidth() image = Image.new('RGB', (width, fontsize + 4), background) - draw = ImageDraw.Draw(image) + draw = ImageDraw.Draw(image) width = 0 for c in chars: @@ -80,7 +80,7 @@ def createFontBitmap(filename, fontname, fontsize, fontoffset, foreground, backg pass else: w, h = font.getsize(c) - draw.text( (width + 1, fontoffset) , c, fill=foreground, font=font) + draw.text((width + 1, fontoffset), c, fill=foreground, font=font) width += getCharWidth(c) From 6ab73f3ece8a17b2156ff454fec3b32ed4178be1 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Tue, 18 Jun 2019 12:44:22 +0200 Subject: [PATCH 050/350] Dead code removed --- radio/src/targets/horus/board.h | 1 - 1 file changed, 1 deletion(-) diff --git a/radio/src/targets/horus/board.h b/radio/src/targets/horus/board.h index 6ddd4d16f..b2116afb5 100644 --- a/radio/src/targets/horus/board.h +++ b/radio/src/targets/horus/board.h @@ -608,7 +608,6 @@ void sportUpdatePowerOff(void); void hapticInit(void); void hapticDone(void); void hapticOff(void); -#define HAPTIC_OFF() hapticOff() void hapticOn(uint32_t pwmPercent); // GPS driver From 0ec02f096c9922c1f351eca991fff417f6d1c6ac Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Tue, 18 Jun 2019 15:47:38 +0200 Subject: [PATCH 051/350] Default switchs / pots / sliders configuration moved to the HAL (#6514) Default switchs / pots / sliders configuration moved to the HAL --- radio/src/gui/128x64/radio_calibration.cpp | 8 --- radio/src/gui/212x64/radio_calibration.cpp | 8 --- radio/src/gui/480x272/radio_calibration.cpp | 9 ---- radio/src/myeeprom.h | 16 ------ radio/src/opentx.cpp | 55 +++++++-------------- radio/src/opentx_constants.h | 51 +++++++++++++++++++ radio/src/targets/horus/board.h | 6 +++ radio/src/targets/sky9x/board.h | 1 + radio/src/targets/taranis/board.h | 18 ++++++- 9 files changed, 93 insertions(+), 79 deletions(-) create mode 100644 radio/src/opentx_constants.h diff --git a/radio/src/gui/128x64/radio_calibration.cpp b/radio/src/gui/128x64/radio_calibration.cpp index 5cf0159d8..a8004c7a2 100644 --- a/radio/src/gui/128x64/radio_calibration.cpp +++ b/radio/src/gui/128x64/radio_calibration.cpp @@ -23,14 +23,6 @@ #define XPOT_DELTA 10 #define XPOT_DELAY 10 /* cycles */ -enum CalibrationState { - CALIB_START = 0, - CALIB_SET_MIDPOINT, - CALIB_MOVE_STICKS, - CALIB_STORE, - CALIB_FINISHED -}; - void menuCommonCalib(event_t event) { for (uint8_t i=0; i(g_eeGeneral.switchConfig, 2*(x), 2)) #define SWITCH_EXISTS(x) (SWITCH_CONFIG(x) != SWITCH_NONE) #define IS_CONFIG_3POS(x) (SWITCH_CONFIG(x) == SWITCH_3POS) diff --git a/radio/src/opentx.cpp b/radio/src/opentx.cpp index ccdf1ab7f..6d3fb20a4 100644 --- a/radio/src/opentx.cpp +++ b/radio/src/opentx.cpp @@ -235,41 +235,22 @@ void generalDefault() g_eeGeneral.version = EEPROM_VER; g_eeGeneral.variant = EEPROM_VARIANT; -#if !defined(PCBHORUS) +#if defined(PCBHORUS) + g_eeGeneral.blOffBright = 20; +#else g_eeGeneral.contrast = LCD_CONTRAST_DEFAULT; #endif -#if defined(PCBHORUS) - #if PCBREV >= 13 - g_eeGeneral.potsConfig = 0x1B; // S1 = pot, 6P = multipos, S2 = pot with detent - #else - g_eeGeneral.potsConfig = 0x19; // S1 = pot without detent, 6P = multipos, S2 = pot with detent - #endif - g_eeGeneral.slidersConfig = 0x0f; // 4 sliders - g_eeGeneral.blOffBright = 20; -#elif defined(PCBXLITE) - g_eeGeneral.potsConfig = 0x0F; // S1 and S2 = pot without detent -#elif defined(PCBX7) - g_eeGeneral.potsConfig = (POT_WITHOUT_DETENT << 0) + (POT_WITH_DETENT << 2); // S1 = pot without detent, S2 = pot with detent -#elif defined(PCBX9LITE) - g_eeGeneral.potsConfig = (POT_WITH_DETENT << 0); // S1 = pot with detent -#elif defined(PCBTARANIS) - g_eeGeneral.potsConfig = 0x05; // S1 and S2 = pots with detent - g_eeGeneral.slidersConfig = 0x03; // LS and RS = sliders with detent +#if defined(DEFAULT_POTS_CONFIG) + g_eeGeneral.potsConfig = DEFAULT_POTS_CONFIG; #endif -#if defined(PCBXLITES) - g_eeGeneral.switchConfig = (SWITCH_TOGGLE << 10) + (SWITCH_TOGGLE << 8) + (SWITCH_2POS << 6) + (SWITCH_2POS << 4) + (SWITCH_3POS << 2) + (SWITCH_3POS << 0); -#elif defined(PCBXLITE) - g_eeGeneral.switchConfig = (SWITCH_2POS << 6) + (SWITCH_2POS << 4) + (SWITCH_3POS << 2) + (SWITCH_3POS << 0); -#elif defined(RADIO_X7) - g_eeGeneral.switchConfig = 0x000006ff; // 4x3POS, 1x2POS, 1xTOGGLE -#elif defined(RADIO_T12) - g_eeGeneral.switchConfig = (SWITCH_2POS << 10) + (SWITCH_2POS << 8) + (SWITCH_3POS << 6) + (SWITCH_3POS << 4) + (SWITCH_3POS << 2) + (SWITCH_3POS << 0); -#elif defined(PCBX9LITE) - g_eeGeneral.switchConfig = (SWITCH_TOGGLE << 8) + (SWITCH_2POS << 6) + (SWITCH_3POS << 4) + (SWITCH_3POS << 2) + (SWITCH_3POS << 0); -#elif defined(PCBTARANIS) || defined(PCBHORUS) - g_eeGeneral.switchConfig = 0x00007bff; // 6x3POS, 1x2POS, 1xTOGGLE +#if defined(DEFAULT_SWITCH_CONFIG) + g_eeGeneral.switchConfig = DEFAULT_SWITCH_CONFIG; +#endif + +#if defined(DEFAULT_SLIDERS_CONFIG) + g_eeGeneral.slidersConfig = DEFAULT_SLIDERS_CONFIG; #endif // vBatWarn is voltage in 100mV, vBatMin is in 100mV but with -9V offset, vBatMax has a -12V offset @@ -311,7 +292,7 @@ void generalDefault() strcpy(g_eeGeneral.currModelFilename, DEFAULT_MODEL_FILENAME); #endif -#if defined(PCBHORUS) +#if defined(COLORLCD) strcpy(g_eeGeneral.themeName, theme->getName()); theme->init(); #endif @@ -1563,7 +1544,7 @@ void opentxClose(uint8_t shutdown) #endif #if defined(LUA) luaClose(&lsScripts); -#if defined(PCBHORUS) +#if defined(COLORLCD) luaClose(&lsWidgets); #endif #endif @@ -1614,7 +1595,8 @@ void opentxResume() sdMount(); storageReadAll(); -#if defined(PCBHORUS) + +#if defined(COLORLCD) loadTheme(); loadFontCache(); #endif @@ -1790,7 +1772,7 @@ void opentxInit() storageReadCurrentModel(); #endif -#if defined(PCBHORUS) +#if defined(COLORLCD) if (!unexpectedShutdown) { // g_model.topbarData is still zero here (because it was not yet read from SDCARD), // but we only remember the pointer to in in constructor. @@ -1861,7 +1843,7 @@ void opentxInit() btInit(); #endif -#if defined(PCBHORUS) +#if defined(COLORLCD) loadTheme(); loadFontCache(); #endif @@ -1919,11 +1901,10 @@ int main() boardInit(); -#if defined(PCBHORUS) +#if defined(COLORLCD) loadFonts(); #endif - #if defined(GUI) && !defined(PCBTARANIS) && !defined(PCBHORUS) // TODO remove this lcdInit(); diff --git a/radio/src/opentx_constants.h b/radio/src/opentx_constants.h new file mode 100644 index 000000000..7267d6d33 --- /dev/null +++ b/radio/src/opentx_constants.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) OpenTX + * + * Based on code named + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _OPENTX_CONSTANTS_H_ +#define _OPENTX_CONSTANTS_H_ + +enum SwitchConfig { + SWITCH_NONE, + SWITCH_TOGGLE, + SWITCH_2POS, + SWITCH_3POS, +}; + +enum PotConfig { + POT_NONE, + POT_WITH_DETENT, + POT_MULTIPOS_SWITCH, + POT_WITHOUT_DETENT +}; + +enum SliderConfig { + SLIDER_NONE, + SLIDER_WITH_DETENT, +}; + +enum CalibrationState { + CALIB_START, + CALIB_SET_MIDPOINT, + CALIB_MOVE_STICKS, + CALIB_STORE, + CALIB_FINISHED +}; + +#endif // _OPENTX_CONSTANTS_H_ diff --git a/radio/src/targets/horus/board.h b/radio/src/targets/horus/board.h index b2116afb5..26e01fe54 100644 --- a/radio/src/targets/horus/board.h +++ b/radio/src/targets/horus/board.h @@ -22,6 +22,7 @@ #define _BOARD_HORUS_H_ #include "../definitions.h" +#include "../opentx_constants.h" #include "cpu_id.h" #if defined(__cplusplus) && !defined(SIMU) @@ -425,6 +426,10 @@ enum Analogs { #define POT_LAST (SLIDER_FIRST - 1) +#define DEFAULT_SWITCH_CONFIG (SWITCH_TOGGLE << 14) + (SWITCH_3POS << 12) + (SWITCH_2POS << 10) + (SWITCH_3POS << 8) + (SWITCH_3POS << 6) + (SWITCH_3POS << 4) + (SWITCH_3POS << 2) + (SWITCH_3POS << 0) +#define DEFAULT_POTS_CONFIG (POT_WITH_DETENT << 4) + (POT_MULTIPOS_SWITCH << 2) + (POT_WITHOUT_DETENT << 0) +#define DEFAULT_SLIDERS_CONFIG (SLIDER_WITH_DETENT << 3) + (SLIDER_WITH_DETENT << 2) + (SLIDER_WITH_DETENT << 1) + (SLIDER_WITH_DETENT << 0) + enum CalibratedAnalogs { CALIBRATED_STICK1, CALIBRATED_STICK2, @@ -521,6 +526,7 @@ void ledBlue(void); #define LCD_DEPTH 16 void lcdInit(void); void lcdRefresh(void); +void lcdCopy(void * dest, void * src); void DMAFillRect(uint16_t * dest, uint16_t destw, uint16_t desth, uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t color); void DMACopyBitmap(uint16_t * dest, uint16_t destw, uint16_t desth, uint16_t x, uint16_t y, const uint16_t * src, uint16_t srcw, uint16_t srch, uint16_t srcx, uint16_t srcy, uint16_t w, uint16_t h); void DMACopyAlphaBitmap(uint16_t * dest, uint16_t destw, uint16_t desth, uint16_t x, uint16_t y, const uint16_t * src, uint16_t srcw, uint16_t srch, uint16_t srcx, uint16_t srcy, uint16_t w, uint16_t h); diff --git a/radio/src/targets/sky9x/board.h b/radio/src/targets/sky9x/board.h index 2683e942b..9648b92e9 100644 --- a/radio/src/targets/sky9x/board.h +++ b/radio/src/targets/sky9x/board.h @@ -26,6 +26,7 @@ #include #include "board_lowlevel.h" #include "audio_driver.h" +#include "../opentx_constants.h" extern uint16_t ResetReason; diff --git a/radio/src/targets/taranis/board.h b/radio/src/targets/taranis/board.h index ef9f8a8a0..11cd6c90d 100644 --- a/radio/src/targets/taranis/board.h +++ b/radio/src/targets/taranis/board.h @@ -23,6 +23,7 @@ #include #include "../definitions.h" +#include "../opentx_constants.h" #include "cpu_id.h" #if defined(__cplusplus) && !defined(SIMU) @@ -448,28 +449,43 @@ enum EnumSwitchesPositions #if defined(PCBXLITES) #define NUM_SWITCHES 6 #define STORAGE_NUM_SWITCHES NUM_SWITCHES + #define DEFAULT_SWITCH_CONFIG (SWITCH_TOGGLE << 10) + (SWITCH_TOGGLE << 8) + (SWITCH_2POS << 6) + (SWITCH_2POS << 4) + (SWITCH_3POS << 2) + (SWITCH_3POS << 0) + #define DEFAULT_POTS_CONFIG (POT_WITHOUT_DETENT << 2) + (POT_WITHOUT_DETENT << 0) #elif defined(PCBXLITE) #define NUM_SWITCHES 4 #define STORAGE_NUM_SWITCHES 6 + #define DEFAULT_SWITCH_CONFIG (SWITCH_2POS << 6) + (SWITCH_2POS << 4) + (SWITCH_3POS << 2) + (SWITCH_3POS << 0); + #define DEFAULT_POTS_CONFIG (POT_WITHOUT_DETENT << 2) + (POT_WITHOUT_DETENT << 0) #elif defined(PCBT12) #define NUM_SWITCHES 6 #define STORAGE_NUM_SWITCHES 8 + #define DEFAULT_SWITCH_CONFIG (SWITCH_2POS << 10) + (SWITCH_2POS << 8) + (SWITCH_3POS << 6) + (SWITCH_3POS << 4) + (SWITCH_3POS << 2) + (SWITCH_3POS << 0) + #define DEFAULT_POTS_CONFIG (POT_WITHOUT_DETENT << 0) + (POT_WITH_DETENT << 2); // S1 = pot without detent, S2 = pot with detent #elif defined(PCBX7) #define NUM_SWITCHES 8 #define STORAGE_NUM_SWITCHES NUM_SWITCHES + #define DEFAULT_SWITCH_CONFIG (SWITCH_TOGGLE << 10) + (SWITCH_2POS << 8) + (SWITCH_3POS << 6) + (SWITCH_3POS << 4) + (SWITCH_3POS << 2) + (SWITCH_3POS << 0) + #define DEFAULT_POTS_CONFIG (POT_WITHOUT_DETENT << 0) + (POT_WITH_DETENT << 2); // S1 = pot without detent, S2 = pot with detent #elif defined(PCBX9LITE) #define NUM_SWITCHES 5 #define STORAGE_NUM_SWITCHES NUM_SWITCHES + #define DEFAULT_SWITCH_CONFIG (SWITCH_TOGGLE << 8) + (SWITCH_2POS << 6) + (SWITCH_3POS << 4) + (SWITCH_3POS << 2) + (SWITCH_3POS << 0); + #define DEFAULT_POTS_CONFIG (POT_WITH_DETENT << 0); // S1 = pot with detent #elif defined(PCBX9E) #define NUM_SWITCHES 18 // yes, it's perfect like that ! #define STORAGE_NUM_SWITCHES NUM_SWITCHES + #define DEFAULT_SWITCH_CONFIG (SWITCH_TOGGLE << 14) + (SWITCH_3POS << 12) + (SWITCH_2POS << 10) + (SWITCH_3POS << 8) + (SWITCH_3POS << 6) + (SWITCH_3POS << 4) + (SWITCH_3POS << 2) + (SWITCH_3POS << 0) + #define DEFAULT_POTS_CONFIG (POT_WITH_DETENT << 0) + (POT_WITH_DETENT << 2); // S1 = pot without detent, S2 = pot with detent + #define DEFAULT_SLIDERS_CONFIG (SLIDER_WITH_DETENT << 1) + (SLIDER_WITH_DETENT << 0) #else #define NUM_SWITCHES 8 #define STORAGE_NUM_SWITCHES NUM_SWITCHES + #define DEFAULT_SWITCH_CONFIG (SWITCH_TOGGLE << 14) + (SWITCH_3POS << 12) + (SWITCH_2POS << 10) + (SWITCH_3POS << 8) + (SWITCH_3POS << 6) + (SWITCH_3POS << 4) + (SWITCH_3POS << 2) + (SWITCH_3POS << 0) + #define DEFAULT_POTS_CONFIG (POT_WITH_DETENT << 0) + (POT_WITH_DETENT << 2); // S1 = pot without detent, S2 = pot with detent + #define DEFAULT_SLIDERS_CONFIG (SLIDER_WITH_DETENT << 1) + (SLIDER_WITH_DETENT << 0) #endif #define STORAGE_NUM_SWITCHES_POSITIONS (STORAGE_NUM_SWITCHES * 3) -#define NUM_SWITCHES_POSITIONS (NUM_SWITCHES * 3) void keysInit(void); uint8_t keyState(uint8_t index); From 499819191021085f48b17766eec8fb9da2a5680b Mon Sep 17 00:00:00 2001 From: 3djc Date: Tue, 18 Jun 2019 16:58:06 +0200 Subject: [PATCH 052/350] Fix X9E switches ((some cannot be configured or read) --- radio/src/gui/212x64/radio_hardware.cpp | 3 +-- radio/src/myeeprom.h | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/radio/src/gui/212x64/radio_hardware.cpp b/radio/src/gui/212x64/radio_hardware.cpp index a24c7df9c..6a92a126b 100644 --- a/radio/src/gui/212x64/radio_hardware.cpp +++ b/radio/src/gui/212x64/radio_hardware.cpp @@ -204,8 +204,7 @@ void menuRadioHardware(event_t event) lcdDrawMMM(HW_SETTINGS_COLUMN, y, menuHorizontalPosition == 0 ? attr : 0); config = editChoice(HW_SETTINGS_COLUMN+5*FW, y, "", STR_SWTYPES, config, SWITCH_NONE, SWITCH_TYPE_MAX(index), menuHorizontalPosition == 1 ? attr : 0, event); if (attr && checkIncDec_Ret) { - swconfig_t mask = (swconfig_t)0x03 << (2*index); - g_eeGeneral.switchConfig = (g_eeGeneral.switchConfig & ~mask) | ((swconfig_t(config) & 0x03) << (2*index)); + g_eeGeneral.switchConfig = bfSet(g_eeGeneral.switchConfig, config, 2*index, 2); } break; } diff --git a/radio/src/myeeprom.h b/radio/src/myeeprom.h index 200e66e63..977cc58c9 100644 --- a/radio/src/myeeprom.h +++ b/radio/src/myeeprom.h @@ -80,7 +80,7 @@ #define MODEL_GVAR_MAX(idx) (CFN_GVAR_CST_MAX - g_model.gvars[idx].max) #if defined(PCBTARANIS) || defined(PCBHORUS) - #define SWITCH_CONFIG(x) (bfGet(g_eeGeneral.switchConfig, 2*(x), 2)) + #define SWITCH_CONFIG(x) (bfGet(g_eeGeneral.switchConfig, 2*(x), 2)) #define SWITCH_EXISTS(x) (SWITCH_CONFIG(x) != SWITCH_NONE) #define IS_CONFIG_3POS(x) (SWITCH_CONFIG(x) == SWITCH_3POS) #define IS_CONFIG_TOGGLE(x) (SWITCH_CONFIG(x) == SWITCH_TOGGLE) From eaf595bd7614bbcf1e9cfacc5a2c4fd1ba5c15f5 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Tue, 18 Jun 2019 20:07:15 +0200 Subject: [PATCH 053/350] Refactoring keys/switches/trims in simu (#6515) Refactoring keys/switches/trims in simu --- radio/src/cli.cpp | 4 +- radio/src/gui/128x64/radio_diagkeys.cpp | 2 +- radio/src/gui/212x64/radio_diagkeys.cpp | 2 +- radio/src/opentx.h | 8 +- radio/src/simu.cpp | 107 +++---- radio/src/switches.cpp | 4 +- radio/src/targets/common/arm/CMakeLists.txt | 2 +- .../arm/stm32/rotary_encoder_driver.cpp | 2 +- radio/src/targets/horus/board.h | 8 +- radio/src/targets/horus/keys_driver.cpp | 9 +- radio/src/targets/simu/simpgmspace.cpp | 269 ++++++------------ radio/src/targets/sky9x/CMakeLists.txt | 2 +- radio/src/targets/sky9x/board.h | 2 +- radio/src/targets/sky9x/keys_driver.cpp | 7 +- radio/src/targets/taranis/board.h | 1 - radio/src/targets/taranis/keys_driver.cpp | 7 +- radio/src/tests/mixer.cpp | 15 +- 17 files changed, 147 insertions(+), 304 deletions(-) diff --git a/radio/src/cli.cpp b/radio/src/cli.cpp index 56f1abc37..6bb489b96 100644 --- a/radio/src/cli.cpp +++ b/radio/src/cli.cpp @@ -960,13 +960,13 @@ int cliDisplay(const char ** argv) uint8_t len = STR_VKEYS[0]; strncpy(name, STR_VKEYS+1+len*i, len); name[len] = '\0'; - serialPrint("[%s] = %s", name, keyState(i) ? "on" : "off"); + serialPrint("[%s] = %s", name, keys[i].state() ? "on" : "off"); } #if defined(ROTARY_ENCODER_NAVIGATION) serialPrint("[Enc.] = %d", rotencValue / ROTARY_ENCODER_GRANULARITY); #endif for (int i=TRM_BASE; i<=TRM_LAST; i++) { - serialPrint("[Trim%d] = %s", i-TRM_BASE, keyState(i) ? "on" : "off"); + serialPrint("[Trim%d] = %s", i-TRM_BASE, keys[i].state() ? "on" : "off"); } for (int i=MIXSRC_FIRST_SWITCH; i<=MIXSRC_LAST_SWITCH; i++) { mixsrc_t sw = i - MIXSRC_FIRST_SWITCH; diff --git a/radio/src/gui/128x64/radio_diagkeys.cpp b/radio/src/gui/128x64/radio_diagkeys.cpp index 813459aa5..bd8668c82 100644 --- a/radio/src/gui/128x64/radio_diagkeys.cpp +++ b/radio/src/gui/128x64/radio_diagkeys.cpp @@ -22,7 +22,7 @@ void displayKeyState(uint8_t x, uint8_t y, uint8_t key) { - uint8_t t = keyState(key); + uint8_t t = keys[key].state(); lcdDrawChar(x, y, t+'0', t ? INVERS : 0); } diff --git a/radio/src/gui/212x64/radio_diagkeys.cpp b/radio/src/gui/212x64/radio_diagkeys.cpp index c6e48b57e..a221e6260 100644 --- a/radio/src/gui/212x64/radio_diagkeys.cpp +++ b/radio/src/gui/212x64/radio_diagkeys.cpp @@ -22,7 +22,7 @@ void displayKeyState(uint8_t x, uint8_t y, uint8_t key) { - uint8_t t = keyState(key); + uint8_t t = keys[key].state(); lcdDrawChar(x, y, t+'0', t ? INVERS : 0); } diff --git a/radio/src/opentx.h b/radio/src/opentx.h index f45e254a6..352bdf86c 100644 --- a/radio/src/opentx.h +++ b/radio/src/opentx.h @@ -249,8 +249,6 @@ #define SW_DSM2_BIND SW_TRN #endif -#define NUM_PSWITCH (SWSRC_LAST_SWITCH-SWSRC_FIRST_SWITCH+1) - #include "myeeprom.h" inline void memclear(void * p, size_t size) @@ -447,11 +445,7 @@ div_t switchInfo(int switchPosition); extern uint8_t potsPos[NUM_XPOTS]; #endif -#if defined(PCBHORUS) - uint16_t trimDown(uint16_t idx); // TODO why? -#else - uint8_t trimDown(uint8_t idx); -#endif +bool trimDown(uint8_t idx); void readKeysAndTrims(); uint16_t evalChkSum(); diff --git a/radio/src/simu.cpp b/radio/src/simu.cpp index f775e7b14..3583a54a8 100644 --- a/radio/src/simu.cpp +++ b/radio/src/simu.cpp @@ -315,44 +315,44 @@ void OpenTxSim::updateKeysAndSwitches(bool start) else { \ state##key = false; \ } \ - simuSetSwitch(swtch, state_##swtch-states); + simuSetSwitch(swtch, state_##swtch-states) -#if defined(PCBX9E) - SWITCH_KEY(A, 0, 3); - SWITCH_KEY(B, 1, 3); - SWITCH_KEY(C, 2, 3); - SWITCH_KEY(D, 3, 3); - SWITCH_KEY(E, 4, 3); - SWITCH_KEY(F, 5, 3); - SWITCH_KEY(G, 6, 3); - SWITCH_KEY(H, 7, 3); - SWITCH_KEY(I, 8, 3); - SWITCH_KEY(J, 9, 3); - SWITCH_KEY(K, 10, 3); - SWITCH_KEY(L, 11, 3); - SWITCH_KEY(M, 12, 3); - SWITCH_KEY(N, 13, 3); - SWITCH_KEY(O, 14, 3); - SWITCH_KEY(P, 15, 3); - SWITCH_KEY(Q, 16, 3); - SWITCH_KEY(R, 17, 3); -#elif defined(PCBTARANIS) || defined(PCBHORUS) - SWITCH_KEY(A, 0, 3); - SWITCH_KEY(B, 1, 3); - SWITCH_KEY(C, 2, 3); - SWITCH_KEY(D, 3, 3); - SWITCH_KEY(E, 4, 3); - SWITCH_KEY(F, 5, 2); - SWITCH_KEY(G, 6, 3); - SWITCH_KEY(H, 7, 2); -#else - SWITCH_KEY(1, 0, 2); +#if defined(PCBSKY9X) + SWITCH_KEY(1, 0, 3); SWITCH_KEY(2, 1, 2); SWITCH_KEY(3, 2, 2); - SWITCH_KEY(4, 3, 3); + SWITCH_KEY(4, 3, 2); SWITCH_KEY(5, 4, 2); SWITCH_KEY(6, 5, 2); SWITCH_KEY(7, 6, 2); +#else + SWITCH_KEY(A, 0, 3); + SWITCH_KEY(B, 1, 3); + SWITCH_KEY(C, 2, 3); + SWITCH_KEY(D, 3, 3); + + #if defined(PCBX7) || defined(PCBXLITE) + SWITCH_KEY(F, 4, 2); + SWITCH_KEY(H, 5, 2); + #else + SWITCH_KEY(E, 4, 3); + SWITCH_KEY(F, 5, 2); + SWITCH_KEY(G, 6, 3); + SWITCH_KEY(H, 7, 2); + #endif + + #if defined(PCBX9E) + SWITCH_KEY(I, 8, 3); + SWITCH_KEY(J, 9, 3); + SWITCH_KEY(K, 10, 3); + SWITCH_KEY(L, 11, 3); + SWITCH_KEY(M, 12, 3); + SWITCH_KEY(N, 13, 3); + SWITCH_KEY(O, 14, 3); + SWITCH_KEY(P, 15, 3); + SWITCH_KEY(Q, 16, 3); + SWITCH_KEY(R, 17, 3); + #endif #endif } @@ -385,49 +385,6 @@ long OpenTxSim::onTimeout(FXObject*, FXSelector, void*) rotencAction = false; } #endif - -#if defined(PCBX9E) - SWITCH_KEY(A, 0, 3); - SWITCH_KEY(B, 1, 3); - SWITCH_KEY(C, 2, 3); - SWITCH_KEY(D, 3, 3); - SWITCH_KEY(E, 4, 3); - SWITCH_KEY(F, 5, 2); - SWITCH_KEY(G, 6, 3); - SWITCH_KEY(H, 7, 2); - SWITCH_KEY(I, 8, 3); - SWITCH_KEY(J, 9, 3); - SWITCH_KEY(K, 10, 3); - SWITCH_KEY(L, 11, 3); - SWITCH_KEY(M, 12, 3); - SWITCH_KEY(N, 13, 3); - SWITCH_KEY(O, 14, 3); - SWITCH_KEY(P, 15, 3); - SWITCH_KEY(Q, 16, 3); - SWITCH_KEY(R, 17, 3); -#elif defined(PCBTARANIS) || defined(PCBHORUS) - SWITCH_KEY(A, 0, 3); - SWITCH_KEY(B, 1, 3); - SWITCH_KEY(C, 2, 3); - SWITCH_KEY(D, 3, 3); -#if defined(PCBX7) - SWITCH_KEY(F, 4, 2); - SWITCH_KEY(H, 5, 2); -#else - SWITCH_KEY(E, 4, 3); - SWITCH_KEY(F, 5, 2); - SWITCH_KEY(G, 6, 3); - SWITCH_KEY(H, 7, 2); -#endif -#else - SWITCH_KEY(1, 0, 2); - SWITCH_KEY(2, 1, 2); - SWITCH_KEY(3, 2, 2); - SWITCH_KEY(4, 3, 3); - SWITCH_KEY(5, 4, 2); - SWITCH_KEY(6, 5, 2); - SWITCH_KEY(7, 6, 2); -#endif } per10ms(); diff --git a/radio/src/switches.cpp b/radio/src/switches.cpp index de552d87f..6b2199a0d 100644 --- a/radio/src/switches.cpp +++ b/radio/src/switches.cpp @@ -525,13 +525,13 @@ swsrc_t getMovedSwitch() // -4..-8 for all other switches if changed to false // 9 for Trainer switch if changed to true; Change to false is ignored swarnstate_t mask = 0x80; - for (uint8_t i=NUM_PSWITCH; i>1; i--) { + for (uint8_t i=NUM_SWITCHES_POSITIONS; i>1; i--) { bool prev; prev = (switches_states & mask); // don't use getSwitch here to always get the proper value, even getSwitch manipulates bool next = switchState(i-1); if (prev != next) { - if (((i3)) || next==true) + if (((i3)) || next==true) result = next ? i : -i; if (i<=3 && result==0) result = 1; switches_states ^= mask; diff --git a/radio/src/targets/common/arm/CMakeLists.txt b/radio/src/targets/common/arm/CMakeLists.txt index 90d196f41..533a28ab5 100644 --- a/radio/src/targets/common/arm/CMakeLists.txt +++ b/radio/src/targets/common/arm/CMakeLists.txt @@ -192,12 +192,12 @@ set(SRC set(FIRMWARE_TARGET_SRC ${FIRMWARE_TARGET_SRC} + keys_driver.cpp diskio.cpp ) set(TARGET_SRC ${TARGET_SRC} - keys_driver.cpp telemetry_driver.cpp ) diff --git a/radio/src/targets/common/arm/stm32/rotary_encoder_driver.cpp b/radio/src/targets/common/arm/stm32/rotary_encoder_driver.cpp index b8d06a03a..6a2445c44 100644 --- a/radio/src/targets/common/arm/stm32/rotary_encoder_driver.cpp +++ b/radio/src/targets/common/arm/stm32/rotary_encoder_driver.cpp @@ -71,7 +71,7 @@ void rotaryEncoderInit() void rotaryEncoderCheck() { uint8_t newPosition = ROTARY_ENCODER_POSITION(); - if (newPosition != rotencPosition && !keyState(KEY_ENTER)) { + if (newPosition != rotencPosition && !(readKeys() & (1 << KEY_ENTER))) { if ((rotencPosition & 0x01) ^ ((newPosition & 0x02) >> 1)) { --rotencValue; } diff --git a/radio/src/targets/horus/board.h b/radio/src/targets/horus/board.h index 26e01fe54..60c98b9fd 100644 --- a/radio/src/targets/horus/board.h +++ b/radio/src/targets/horus/board.h @@ -309,16 +309,12 @@ enum EnumSwitchesPositions SW_SGMBR0, SW_SGMBR1, SW_SGMBR2, - STORAGE_NUM_SWITCHES_POSITIONS + NUM_SWITCHES_POSITIONS }; - -#if defined(__cplusplus) -static_assert(STORAGE_NUM_SWITCHES_POSITIONS == NUM_SWITCHES * 3, "Wrong switches positions count"); -#endif +#define STORAGE_NUM_SWITCHES_POSITIONS (STORAGE_NUM_SWITCHES * 3) void keysInit(void); -uint8_t keyState(uint8_t index); uint32_t switchState(uint8_t index); uint32_t readKeys(void); #define KEYS_PRESSED() (readKeys()) diff --git a/radio/src/targets/horus/keys_driver.cpp b/radio/src/targets/horus/keys_driver.cpp index 0f0b5f7ac..090376b42 100644 --- a/radio/src/targets/horus/keys_driver.cpp +++ b/radio/src/targets/horus/keys_driver.cpp @@ -79,9 +79,9 @@ uint32_t readTrims() return result; } -uint16_t trimDown(uint16_t idx) +bool trimDown(uint8_t idx) { - return readTrims() & (1 << idx); + return readTrims() & ((uint32_t)1 << idx); } bool keyDown() @@ -158,11 +158,6 @@ void readKeysAndTrims() } \ break -uint8_t keyState(uint8_t index) -{ - return keys[index].state(); -} - #if !defined(BOOT) uint32_t switchState(uint8_t index) { diff --git a/radio/src/targets/simu/simpgmspace.cpp b/radio/src/targets/simu/simpgmspace.cpp index 6a061eaca..d5edb9d7d 100644 --- a/radio/src/targets/simu/simpgmspace.cpp +++ b/radio/src/targets/simu/simpgmspace.cpp @@ -144,197 +144,28 @@ void simuInit() PIOC->PIO_PDSR &= ~PIO_PC17; #endif - for (int i = 0; i <= 17; i++) { - simuSetSwitch(i, 0); - simuSetKey(i, false); // a little dirty, but setting keys that don't exist is perfectly OK here - } - for (int i = 0; i < 2*NUM_TRIMS; i++) - simuSetTrim(i, false); - #if defined(ROTARY_ENCODER_NAVIGATION) rotencValue = 0; #endif } -#define NEG_CASE(sw_or_key, pin, mask) \ - case sw_or_key: \ - if ((int)state > 0) pin &= ~(mask); else pin |= (mask); \ - break; -#define POS_CASE(sw_or_key, pin, mask) \ - case sw_or_key: \ - if ((int)state > 0) pin |= (mask); else pin &= ~(mask); \ - break; - - #if defined(PCBHORUS) || (defined(PCBTARANIS) && !defined(PCBX9E)) - #define SWITCH_CASE NEG_CASE - #define SWITCH_INV POS_CASE - #else - #define SWITCH_CASE POS_CASE - #endif - #define KEY_CASE NEG_CASE - #define SWITCH_3_CASE(swtch, pin1, pin2, mask1, mask2) \ - case swtch: \ - if ((int)state < 0) pin1 &= ~(mask1); else pin1 |= (mask1); \ - if ((int)state > 0) pin2 &= ~(mask2); else pin2 |= (mask2); \ - break; - #define SWITCH_3_INV(swtch, pin1, pin2, mask1, mask2) SWITCH_3_CASE(swtch, pin2, pin1, mask2, mask1) - -#define TRIM_CASE KEY_CASE - +bool keysStates[NUM_KEYS] = { false }; void simuSetKey(uint8_t key, bool state) { - // if (state) TRACE_SIMPGMSPACE("simuSetKey(%d, %d)", key, state); - - switch (key) { -#if defined(PCBX12S) - KEY_CASE(KEY_PGUP, KEYS_GPIO_REG_PGUP, KEYS_GPIO_PIN_PGUP) - KEY_CASE(KEY_PGDN, KEYS_GPIO_REG_PGDN, KEYS_GPIO_PIN_PGDN) - KEY_CASE(KEY_ENTER, KEYS_GPIO_REG_ENTER, KEYS_GPIO_PIN_ENTER) - KEY_CASE(KEY_TELEM, KEYS_GPIO_REG_RIGHT, KEYS_GPIO_PIN_RIGHT) - KEY_CASE(KEY_RADIO, KEYS_GPIO_REG_LEFT, KEYS_GPIO_PIN_LEFT) - KEY_CASE(KEY_MODEL, KEYS_GPIO_REG_UP, KEYS_GPIO_PIN_UP) - KEY_CASE(KEY_EXIT, KEYS_GPIO_REG_DOWN, KEYS_GPIO_PIN_DOWN) -#elif defined(PCBX10) - KEY_CASE(KEY_PGDN, KEYS_GPIO_REG_PGDN, KEYS_GPIO_PIN_PGDN) - KEY_CASE(KEY_ENTER, KEYS_GPIO_REG_ENTER, KEYS_GPIO_PIN_ENTER) - KEY_CASE(KEY_TELEM, KEYS_GPIO_REG_RIGHT, KEYS_GPIO_PIN_RIGHT) - KEY_CASE(KEY_RADIO, KEYS_GPIO_REG_LEFT, KEYS_GPIO_PIN_LEFT) - KEY_CASE(KEY_MODEL, KEYS_GPIO_REG_UP, KEYS_GPIO_PIN_UP) - KEY_CASE(KEY_EXIT, KEYS_GPIO_REG_DOWN, KEYS_GPIO_PIN_DOWN) -#elif defined(PCBXLITE) - KEY_CASE(KEY_SHIFT, KEYS_GPIO_REG_SHIFT, KEYS_GPIO_PIN_SHIFT) - KEY_CASE(KEY_EXIT, KEYS_GPIO_REG_EXIT, KEYS_GPIO_PIN_EXIT) - KEY_CASE(KEY_ENTER, KEYS_GPIO_REG_ENTER, KEYS_GPIO_PIN_ENTER) - KEY_CASE(KEY_RIGHT, KEYS_GPIO_REG_RIGHT, KEYS_GPIO_PIN_RIGHT) - KEY_CASE(KEY_LEFT, KEYS_GPIO_REG_LEFT, KEYS_GPIO_PIN_LEFT) - KEY_CASE(KEY_UP, KEYS_GPIO_REG_UP, KEYS_GPIO_PIN_UP) - KEY_CASE(KEY_DOWN, KEYS_GPIO_REG_DOWN, KEYS_GPIO_PIN_DOWN) -#elif defined(RADIO_T12) - KEY_CASE(KEY_EXIT, KEYS_GPIO_REG_EXIT, KEYS_GPIO_PIN_EXIT) - KEY_CASE(KEY_ENTER, KEYS_GPIO_REG_ENTER, KEYS_GPIO_PIN_ENTER) - KEY_CASE(KEY_RIGHT, KEYS_GPIO_REG_RIGHT, KEYS_GPIO_PIN_RIGHT) - KEY_CASE(KEY_LEFT, KEYS_GPIO_REG_LEFT, KEYS_GPIO_PIN_LEFT) - KEY_CASE(KEY_UP, KEYS_GPIO_REG_UP, KEYS_GPIO_PIN_UP) - KEY_CASE(KEY_DOWN, KEYS_GPIO_REG_DOWN, KEYS_GPIO_PIN_DOWN) -#elif defined(PCBTARANIS) - KEY_CASE(KEY_MENU, KEYS_GPIO_REG_MENU, KEYS_GPIO_PIN_MENU) - KEY_CASE(KEY_EXIT, KEYS_GPIO_REG_EXIT, KEYS_GPIO_PIN_EXIT) - KEY_CASE(KEY_ENTER, KEYS_GPIO_REG_ENTER, KEYS_GPIO_PIN_ENTER) - KEY_CASE(KEY_PAGE, KEYS_GPIO_REG_PAGE, KEYS_GPIO_PIN_PAGE) - #if defined(KEYS_GPIO_REG_MINUS) - KEY_CASE(KEY_MINUS, KEYS_GPIO_REG_MINUS, KEYS_GPIO_PIN_MINUS) - KEY_CASE(KEY_PLUS, KEYS_GPIO_REG_PLUS, KEYS_GPIO_PIN_PLUS) - #endif -#else - KEY_CASE(KEY_MENU, KEYS_GPIO_REG_MENU, KEYS_GPIO_PIN_MENU) - KEY_CASE(KEY_EXIT, KEYS_GPIO_REG_EXIT, KEYS_GPIO_PIN_EXIT) - KEY_CASE(KEY_RIGHT, KEYS_GPIO_REG_RIGHT, KEYS_GPIO_PIN_RIGHT) - KEY_CASE(KEY_LEFT, KEYS_GPIO_REG_LEFT, KEYS_GPIO_PIN_LEFT) - KEY_CASE(KEY_UP, KEYS_GPIO_REG_UP, KEYS_GPIO_PIN_UP) - KEY_CASE(KEY_DOWN, KEYS_GPIO_REG_DOWN, KEYS_GPIO_PIN_DOWN) -#endif - } + keysStates[key] = state; } +bool trimsStates[NUM_TRIMS*2] = { false }; void simuSetTrim(uint8_t trim, bool state) { - // TRACE_SIMPGMSPACE("trim=%d state=%d", trim, state); - - switch (trim) { - TRIM_CASE(0, TRIMS_GPIO_REG_LHL, TRIMS_GPIO_PIN_LHL) - TRIM_CASE(1, TRIMS_GPIO_REG_LHR, TRIMS_GPIO_PIN_LHR) - TRIM_CASE(2, TRIMS_GPIO_REG_LVD, TRIMS_GPIO_PIN_LVD) - TRIM_CASE(3, TRIMS_GPIO_REG_LVU, TRIMS_GPIO_PIN_LVU) - #if defined(TRIMS_GPIO_REG_RVD) - TRIM_CASE(4, TRIMS_GPIO_REG_RVD, TRIMS_GPIO_PIN_RVD) - TRIM_CASE(5, TRIMS_GPIO_REG_RVU, TRIMS_GPIO_PIN_RVU) - TRIM_CASE(6, TRIMS_GPIO_REG_RHL, TRIMS_GPIO_PIN_RHL) - TRIM_CASE(7, TRIMS_GPIO_REG_RHR, TRIMS_GPIO_PIN_RHR) - #endif -#if defined(PCBHORUS) - TRIM_CASE(8, TRIMS_GPIO_REG_LSD, TRIMS_GPIO_PIN_LSD) - TRIM_CASE(9, TRIMS_GPIO_REG_LSU, TRIMS_GPIO_PIN_LSU) - TRIM_CASE(10, TRIMS_GPIO_REG_RSD, TRIMS_GPIO_PIN_RSD) - TRIM_CASE(11, TRIMS_GPIO_REG_RSU, TRIMS_GPIO_PIN_RSU) -#endif - } + trimsStates[trim] = state; } -// TODO use a better numbering to allow google tests to work on Taranis +int8_t switchesStates[NUM_SWITCHES] = { -1 }; void simuSetSwitch(uint8_t swtch, int8_t state) { - // TRACE_SIMPGMSPACE("simuSetSwitch(%d, %d)", swtch, state); - - switch (swtch) { -#if defined(PCBTARANIS) - #if defined(SWITCHES_GPIO_REG_A_L) - SWITCH_3_CASE(0, SWITCHES_GPIO_REG_A_L, SWITCHES_GPIO_REG_A_H, SWITCHES_GPIO_PIN_A_L, SWITCHES_GPIO_PIN_A_H) - SWITCH_3_CASE(1, SWITCHES_GPIO_REG_B_L, SWITCHES_GPIO_REG_B_H, SWITCHES_GPIO_PIN_B_L, SWITCHES_GPIO_PIN_B_H) - #endif - #if defined(SWITCHES_GPIO_REG_C_L) - SWITCH_3_CASE(2, SWITCHES_GPIO_REG_C_L, SWITCHES_GPIO_REG_C_H, SWITCHES_GPIO_PIN_C_L, SWITCHES_GPIO_PIN_C_H) - #endif - #if defined(SWITCHES_GPIO_REG_D_L) - SWITCH_3_CASE(3, SWITCHES_GPIO_REG_D_L, SWITCHES_GPIO_REG_D_H, SWITCHES_GPIO_PIN_D_L, SWITCHES_GPIO_PIN_D_H) - #elif defined(SWITCHES_GPIO_REG_D) - SWITCH_CASE (3, SWITCHES_GPIO_REG_D, SWITCHES_GPIO_PIN_D) - #endif - #if defined(PCBX7) - SWITCH_CASE (4, SWITCHES_GPIO_REG_F, SWITCHES_GPIO_PIN_F) - SWITCH_CASE (5, SWITCHES_GPIO_REG_H, SWITCHES_GPIO_PIN_H) - SWITCH_CASE (6, SWITCHES_GPIO_REG_I, SWITCHES_GPIO_PIN_I) - SWITCH_CASE (7, SWITCHES_GPIO_REG_J, SWITCHES_GPIO_PIN_J) - #elif defined(PCBXLITES) - SWITCH_CASE (4, SWITCHES_GPIO_REG_E, SWITCHES_GPIO_PIN_E) - SWITCH_CASE (5, SWITCHES_GPIO_REG_F, SWITCHES_GPIO_PIN_F) - #elif !defined(PCBXLITE) && !defined(PCBX9LITE) - SWITCH_3_CASE(4, SWITCHES_GPIO_REG_E_L, SWITCHES_GPIO_REG_E_H, SWITCHES_GPIO_PIN_E_L, SWITCHES_GPIO_PIN_E_H) - SWITCH_CASE (5, SWITCHES_GPIO_REG_F, SWITCHES_GPIO_PIN_F) - SWITCH_3_CASE(6, SWITCHES_GPIO_REG_G_L, SWITCHES_GPIO_REG_G_H, SWITCHES_GPIO_PIN_G_L, SWITCHES_GPIO_PIN_G_H) - SWITCH_CASE (7, SWITCHES_GPIO_REG_H, SWITCHES_GPIO_PIN_H) - #endif - #if defined(SWITCHES_GPIO_REG_I_L) - SWITCH_3_CASE(8, SWITCHES_GPIO_REG_I_L, SWITCHES_GPIO_REG_I_H, SWITCHES_GPIO_PIN_I_L, SWITCHES_GPIO_PIN_I_H) - SWITCH_3_CASE(9, SWITCHES_GPIO_REG_J_L, SWITCHES_GPIO_REG_J_H, SWITCHES_GPIO_PIN_J_L, SWITCHES_GPIO_PIN_J_H) - SWITCH_3_CASE(10, SWITCHES_GPIO_REG_K_L, SWITCHES_GPIO_REG_K_H, SWITCHES_GPIO_PIN_K_L, SWITCHES_GPIO_PIN_K_H) - SWITCH_3_CASE(11, SWITCHES_GPIO_REG_L_L, SWITCHES_GPIO_REG_L_H, SWITCHES_GPIO_PIN_L_L, SWITCHES_GPIO_PIN_L_H) - SWITCH_3_CASE(12, SWITCHES_GPIO_REG_M_L, SWITCHES_GPIO_REG_M_H, SWITCHES_GPIO_PIN_M_L, SWITCHES_GPIO_PIN_M_H) - SWITCH_3_CASE(13, SWITCHES_GPIO_REG_N_L, SWITCHES_GPIO_REG_N_H, SWITCHES_GPIO_PIN_N_L, SWITCHES_GPIO_PIN_N_H) - SWITCH_3_CASE(14, SWITCHES_GPIO_REG_O_L, SWITCHES_GPIO_REG_O_H, SWITCHES_GPIO_PIN_O_L, SWITCHES_GPIO_PIN_O_H) - SWITCH_3_CASE(15, SWITCHES_GPIO_REG_P_L, SWITCHES_GPIO_REG_P_H, SWITCHES_GPIO_PIN_P_L, SWITCHES_GPIO_PIN_P_H) - SWITCH_3_CASE(16, SWITCHES_GPIO_REG_Q_L, SWITCHES_GPIO_REG_Q_H, SWITCHES_GPIO_PIN_Q_L, SWITCHES_GPIO_PIN_Q_H) - SWITCH_3_CASE(17, SWITCHES_GPIO_REG_R_L, SWITCHES_GPIO_REG_R_H, SWITCHES_GPIO_PIN_R_L, SWITCHES_GPIO_PIN_R_H) - #endif -#elif defined(PCBHORUS) - SWITCH_3_CASE(0, SWITCHES_GPIO_REG_A_L, SWITCHES_GPIO_REG_A_H, SWITCHES_GPIO_PIN_A_L, SWITCHES_GPIO_PIN_A_H) - #if defined(PCBX10) - SWITCH_3_INV (1, SWITCHES_GPIO_REG_B_L, SWITCHES_GPIO_REG_B_H, SWITCHES_GPIO_PIN_B_L, SWITCHES_GPIO_PIN_B_H) - SWITCH_3_CASE(2, SWITCHES_GPIO_REG_C_L, SWITCHES_GPIO_REG_C_H, SWITCHES_GPIO_PIN_C_L, SWITCHES_GPIO_PIN_C_H) - SWITCH_3_INV (3, SWITCHES_GPIO_REG_D_L, SWITCHES_GPIO_REG_D_H, SWITCHES_GPIO_PIN_D_L, SWITCHES_GPIO_PIN_D_H) - SWITCH_3_INV (4, SWITCHES_GPIO_REG_E_L, SWITCHES_GPIO_REG_E_H, SWITCHES_GPIO_PIN_E_L, SWITCHES_GPIO_PIN_E_H) - SWITCH_CASE (5, SWITCHES_GPIO_REG_F, SWITCHES_GPIO_PIN_F) - #else // X12 - SWITCH_3_CASE(1, SWITCHES_GPIO_REG_B_L, SWITCHES_GPIO_REG_B_H, SWITCHES_GPIO_PIN_B_L, SWITCHES_GPIO_PIN_B_H) - SWITCH_3_CASE(2, SWITCHES_GPIO_REG_C_L, SWITCHES_GPIO_REG_C_H, SWITCHES_GPIO_PIN_C_L, SWITCHES_GPIO_PIN_C_H) - SWITCH_3_CASE(3, SWITCHES_GPIO_REG_D_L, SWITCHES_GPIO_REG_D_H, SWITCHES_GPIO_PIN_D_L, SWITCHES_GPIO_PIN_D_H) - SWITCH_3_CASE(4, SWITCHES_GPIO_REG_E_L, SWITCHES_GPIO_REG_E_H, SWITCHES_GPIO_PIN_E_L, SWITCHES_GPIO_PIN_E_H) - SWITCH_INV (5, SWITCHES_GPIO_REG_F, SWITCHES_GPIO_PIN_F) - #endif - SWITCH_3_CASE(6, SWITCHES_GPIO_REG_G_L, SWITCHES_GPIO_REG_G_H, SWITCHES_GPIO_PIN_G_L, SWITCHES_GPIO_PIN_G_H) - SWITCH_CASE (7, SWITCHES_GPIO_REG_H, SWITCHES_GPIO_PIN_H) -#elif defined(PCBSKY9X) - SWITCH_3_CASE(0, PIOC->PIO_PDSR, PIOC->PIO_PDSR, 0x00004000, 0x00000800) - SWITCH_CASE(1, PIOC->PIO_PDSR, 1<<20) - SWITCH_CASE(2, PIOA->PIO_PDSR, 1<<15) - SWITCH_CASE(3, PIOC->PIO_PDSR, 1<<31) - SWITCH_CASE(4, PIOA->PIO_PDSR, 1<<2) - SWITCH_CASE(5, PIOC->PIO_PDSR, 1<<16) - SWITCH_CASE(6, PIOC->PIO_PDSR, 1<<8) -#endif - - default: - break; - } + // TRACE("simuSetSwitch(%d, %d)", swtch, state); + switchesStates[swtch] = state; } void StartSimu(bool tests, const char * sdPath, const char * settingsPath) @@ -569,7 +400,7 @@ void StopAudioThread() bool simuLcdRefresh = true; display_t simuLcdBuf[DISPLAY_BUFFER_SIZE]; -#if !defined(PCBHORUS) +#if !defined(COLORLCD) void lcdSetRefVolt(uint8_t val) { } @@ -638,8 +469,90 @@ uint32_t pwrPressed() #endif } +void pwrInit() +{ +} + +void readKeysAndTrims() +{ + uint8_t index = 0; + uint32_t in = readKeys(); + for (uint8_t i = 1; i != uint8_t(1 << TRM_BASE); i <<= 1) { + keys[index++].input(in & i); + } + + in = readTrims(); + for (uint8_t i = 1; i != uint8_t(1 << 8); i <<= 1) { + keys[index++].input(in & i); + } +} + +bool keyDown() +{ + return readKeys(); +} + +bool trimDown(uint8_t idx) +{ + return readTrims() & (1 << idx); +} + +uint32_t readKeys() +{ + uint32_t result = 0; + + for (int i=0; i 0; + default: + return switchesStates[index - 2] > 0; + } +#else + div_t qr = div(index, 3); + int state = switchesStates[qr.quot]; + switch (qr.rem) { + case 0: + return state < 0; + case 2: + return state > 0; + default: + return state == 0; + } +#endif +} + #if defined(STM32) -void pwrInit() { } int usbPlugged() { return false; } int getSelectedUsbMode() { return USB_JOYSTICK_MODE; } void setSelectedUsbMode(int mode) {} diff --git a/radio/src/targets/sky9x/CMakeLists.txt b/radio/src/targets/sky9x/CMakeLists.txt index 944910749..9add10595 100644 --- a/radio/src/targets/sky9x/CMakeLists.txt +++ b/radio/src/targets/sky9x/CMakeLists.txt @@ -90,6 +90,7 @@ set(FIRMWARE_TARGET_SRC eeprom_driver.cpp lcd_driver.cpp pwr_driver.cpp + keys_driver.cpp usb/device/core/USBD_UDP.c usb/device/core/USBDDriver.c usb/device/massstorage/MSDDriver.c @@ -115,7 +116,6 @@ set(TARGET_SRC telemetry_driver.cpp adc_driver.cpp pulses_driver.cpp - keys_driver.cpp audio_driver.cpp buzzer_driver.cpp haptic_driver.cpp diff --git a/radio/src/targets/sky9x/board.h b/radio/src/targets/sky9x/board.h index 9648b92e9..8846d63ff 100644 --- a/radio/src/targets/sky9x/board.h +++ b/radio/src/targets/sky9x/board.h @@ -52,6 +52,7 @@ void rotaryEncoderEnd(); // Keys driver #define NUM_SWITCHES 7 #define STORAGE_NUM_SWITCHES NUM_SWITCHES +#define NUM_SWITCHES_POSITIONS 9 enum EnumKeys { @@ -220,7 +221,6 @@ void stop_trainer_capture(); void flashWrite(uint32_t * address, uint32_t * buffer); // Keys driver -uint8_t keyState(uint8_t index); uint32_t switchState(uint8_t index); uint32_t readKeys(void); uint32_t readTrims(void); diff --git a/radio/src/targets/sky9x/keys_driver.cpp b/radio/src/targets/sky9x/keys_driver.cpp index dd959d8fc..9f7dac244 100644 --- a/radio/src/targets/sky9x/keys_driver.cpp +++ b/radio/src/targets/sky9x/keys_driver.cpp @@ -80,7 +80,7 @@ uint32_t readTrims() return result; } -uint8_t trimDown(uint8_t idx) +bool trimDown(uint8_t idx) { return readTrims() & (1 << idx); } @@ -113,11 +113,6 @@ void readKeysAndTrims() } } -uint8_t keyState(uint8_t index) -{ - return keys[index].state(); -} - uint32_t switchState(uint8_t index) { uint32_t a = PIOA->PIO_PDSR; diff --git a/radio/src/targets/taranis/board.h b/radio/src/targets/taranis/board.h index 11cd6c90d..983515c5e 100644 --- a/radio/src/targets/taranis/board.h +++ b/radio/src/targets/taranis/board.h @@ -488,7 +488,6 @@ enum EnumSwitchesPositions #define STORAGE_NUM_SWITCHES_POSITIONS (STORAGE_NUM_SWITCHES * 3) void keysInit(void); -uint8_t keyState(uint8_t index); uint32_t switchState(uint8_t index); uint32_t readKeys(void); uint32_t readTrims(void); diff --git a/radio/src/targets/taranis/keys_driver.cpp b/radio/src/targets/taranis/keys_driver.cpp index 09d92434c..9ae7c98d9 100644 --- a/radio/src/targets/taranis/keys_driver.cpp +++ b/radio/src/targets/taranis/keys_driver.cpp @@ -100,7 +100,7 @@ uint32_t readTrims() return result; } -uint8_t trimDown(uint8_t idx) +bool trimDown(uint8_t idx) { return readTrims() & (1 << idx); } @@ -168,11 +168,6 @@ void readKeysAndTrims() } \ break -uint8_t keyState(uint8_t index) -{ - return keys[index].state(); -} - #if !defined(BOOT) uint32_t switchState(uint8_t index) { diff --git a/radio/src/tests/mixer.cpp b/radio/src/tests/mixer.cpp index 41ed52b45..4c84a8944 100644 --- a/radio/src/tests/mixer.cpp +++ b/radio/src/tests/mixer.cpp @@ -455,18 +455,17 @@ TEST_F(MixerTest, SlowOnPhase) CHECK_SLOW_MOVEMENT(0, -1, 250); } - TEST_F(MixerTest, SlowOnSwitchSource) { g_model.mixData[0].destCh = 0; g_model.mixData[0].mltpx = MLTPX_ADD; -#if defined(PCBTARANIS) || defined(PCBHORUS) +#if defined(PCBSKY9X) + g_model.mixData[0].srcRaw = MIXSRC_THR; + int switchIndex = 1; +#else g_eeGeneral.switchConfig = 0x03; g_model.mixData[0].srcRaw = MIXSRC_SA; - int switch_index = 0; -#else - g_model.mixData[0].srcRaw = MIXSRC_THR; - int switch_index = 1; + int switchIndex = 0; #endif g_model.mixData[0].weight = 100; g_model.mixData[0].speedUp = SLOW_STEP*5; @@ -474,11 +473,11 @@ TEST_F(MixerTest, SlowOnSwitchSource) s_mixer_first_run_done = true; - simuSetSwitch(switch_index, -1); + simuSetSwitch(switchIndex, -1); CHECK_SLOW_MOVEMENT(0, -1, 250); EXPECT_EQ(chans[0], -CHANNEL_MAX); - simuSetSwitch(switch_index, 1); + simuSetSwitch(switchIndex, 1); CHECK_SLOW_MOVEMENT(0, +1, 500); } From ffe8d821cdaca0b74bbd601f96f319595555114f Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Tue, 18 Jun 2019 23:28:59 +0200 Subject: [PATCH 054/350] Double warnings on USB disconnect --- radio/src/opentx.cpp | 21 ++++++----------- radio/src/opentx.h | 4 ++++ radio/src/pulses/pulses.h | 31 +++++++++++++++++++++----- radio/src/targets/simu/simpgmspace.cpp | 4 ++-- 4 files changed, 38 insertions(+), 22 deletions(-) diff --git a/radio/src/opentx.cpp b/radio/src/opentx.cpp index 6d3fb20a4..62af6d9e6 100644 --- a/radio/src/opentx.cpp +++ b/radio/src/opentx.cpp @@ -1481,26 +1481,18 @@ void doMixerCalculations() s_mixer_first_run_done = true; } - -#define OPENTX_START_NO_SPLASH 0x01 -#define OPENTX_START_NO_CHECKS 0x02 - #if !defined(OPENTX_START_DEFAULT_ARGS) #define OPENTX_START_DEFAULT_ARGS 0 #endif -void opentxStart(const uint8_t startType = OPENTX_START_DEFAULT_ARGS) +void opentxStart(const uint8_t startOptions = OPENTX_START_DEFAULT_ARGS) { - TRACE("opentxStart(%u)", startType); + TRACE("opentxStart(%u)", startOptions); - if (startType & OPENTX_START_NO_CHECKS) { - return; - } - - uint8_t calibration_needed = (g_eeGeneral.chkSum != evalChkSum()); + uint8_t calibration_needed = !(startOptions & OPENTX_START_NO_CALIBRATION) && (g_eeGeneral.chkSum != evalChkSum()); #if defined(GUI) - if (!calibration_needed && !(startType & OPENTX_START_NO_SPLASH)) { + if (!calibration_needed && !(startOptions & OPENTX_START_NO_SPLASH)) { doSplash(); } #endif @@ -1523,7 +1515,7 @@ void opentxStart(const uint8_t startType = OPENTX_START_DEFAULT_ARGS) if (calibration_needed) { chainMenu(menuFirstCalib); } - else { + else if (!(startOptions & OPENTX_START_NO_CHECKS)) { checkAlarm(); checkAll(); PLAY_MODEL_NAME(); @@ -1601,7 +1593,8 @@ void opentxResume() loadFontCache(); #endif - opentxStart(OPENTX_START_NO_SPLASH); + // removed to avoid the double warnings (throttle, switch, etc.) + // opentxStart(OPENTX_START_NO_SPLASH | OPENTX_START_NO_CALIBRATION | OPENTX_START_NO_CHECKS); referenceSystemAudioFiles(); diff --git a/radio/src/opentx.h b/radio/src/opentx.h index 352bdf86c..e74139609 100644 --- a/radio/src/opentx.h +++ b/radio/src/opentx.h @@ -1076,6 +1076,10 @@ void opentxClose(uint8_t shutdown=true); void opentxInit(); void opentxResume(); +constexpr uint8_t OPENTX_START_NO_SPLASH = 0x01; +constexpr uint8_t OPENTX_START_NO_CALIBRATION = 0x02; +constexpr uint8_t OPENTX_START_NO_CHECKS = 0x04; + #if defined(STATUS_LEDS) #define LED_ERROR_BEGIN() ledRed() #define LED_ERROR_END() ledBlue() diff --git a/radio/src/pulses/pulses.h b/radio/src/pulses/pulses.h index a6a65ce36..d6612b48c 100644 --- a/radio/src/pulses/pulses.h +++ b/radio/src/pulses/pulses.h @@ -353,15 +353,35 @@ enum ChannelsProtocols { PROTOCOL_CHANNELS_PXX2 }; -inline bool pulsesStarted() { return moduleState[0].protocol != PROTOCOL_CHANNELS_UNINITIALIZED; } -inline void pausePulses() { s_pulses_paused = true; } -inline void resumePulses() { s_pulses_paused = false; } +inline void stopPulses() +{ + s_pulses_paused = true; + moduleState[0].protocol = PROTOCOL_CHANNELS_UNINITIALIZED; +} -#define SEND_FAILSAFE_NOW(idx) moduleState[idx].counter = 1 +inline bool pulsesStarted() +{ + return moduleState[0].protocol != PROTOCOL_CHANNELS_UNINITIALIZED; +} + +inline void pausePulses() +{ + s_pulses_paused = true; +} + +inline void resumePulses() +{ + s_pulses_paused = false; +} + +inline void SEND_FAILSAFE_NOW(uint8_t idx) +{ + moduleState[idx].counter = 1; +} inline void SEND_FAILSAFE_1S() { - for (int i=0; i Date: Wed, 19 Jun 2019 08:49:07 +0200 Subject: [PATCH 055/350] Cosmetics --- companion/src/firmwares/opentx/opentxeeprom.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/companion/src/firmwares/opentx/opentxeeprom.cpp b/companion/src/firmwares/opentx/opentxeeprom.cpp index 5968af129..f2c109e49 100644 --- a/companion/src/firmwares/opentx/opentxeeprom.cpp +++ b/companion/src/firmwares/opentx/opentxeeprom.cpp @@ -2662,7 +2662,7 @@ OpenTxGeneralData::OpenTxGeneralData(GeneralSettings & generalData, Board::Type } if (version >= 219) { - internalField.Append(new ZCharField<8>(this, generalData.registrationId, "PXX2 Registration ID")); + internalField.Append(new ZCharField<8>(this, generalData.registrationId, "ACCESS Registration ID")); } if (version >= 219 && (IS_TARANIS_XLITES(board) || IS_HORUS(board))) { From 510a1cf2766a9a0b358802afd1bf9c29bb42d522 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Wed, 19 Jun 2019 09:05:27 +0200 Subject: [PATCH 056/350] EEPROM conversion fix (sensors physID) --- radio/src/storage/conversions/conversions_218_219.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/radio/src/storage/conversions/conversions_218_219.cpp b/radio/src/storage/conversions/conversions_218_219.cpp index a832861bf..beb485726 100644 --- a/radio/src/storage/conversions/conversions_218_219.cpp +++ b/radio/src/storage/conversions/conversions_218_219.cpp @@ -215,7 +215,9 @@ void convertModelData_218_to_219(ModelData &model) #endif for (uint8_t i=0; i Date: Wed, 19 Jun 2019 09:32:22 +0200 Subject: [PATCH 057/350] EEPROM conversion fix (sensors physID) --- radio/src/datastructs.h | 5 +++-- radio/src/storage/conversions/conversions_218_219.cpp | 5 ++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/radio/src/datastructs.h b/radio/src/datastructs.h index 833abd52c..da984a14d 100644 --- a/radio/src/datastructs.h +++ b/radio/src/datastructs.h @@ -334,7 +334,8 @@ PACK(struct TelemetrySensor { }; char label[TELEM_LABEL_LEN]; // user defined label uint8_t subId; - uint8_t type:2; // 0=custom / 1=calculated// user can choose what unit to display each value in + uint8_t type:1; // 0=custom / 1=calculated // user can choose what unit to display each value in + uint8_t spare1:1; uint8_t unit:6; uint8_t prec:2; uint8_t autoOffset:1; @@ -342,7 +343,7 @@ PACK(struct TelemetrySensor { uint8_t logs:1; uint8_t persistent:1; uint8_t onlyPositive:1; - uint8_t spare:1; + uint8_t spare2:1; union { NOBACKUP(PACK(struct { uint16_t ratio; diff --git a/radio/src/storage/conversions/conversions_218_219.cpp b/radio/src/storage/conversions/conversions_218_219.cpp index beb485726..578b87e82 100644 --- a/radio/src/storage/conversions/conversions_218_219.cpp +++ b/radio/src/storage/conversions/conversions_218_219.cpp @@ -216,7 +216,10 @@ void convertModelData_218_to_219(ModelData &model) for (uint8_t i=0; i Date: Wed, 19 Jun 2019 16:25:11 +0200 Subject: [PATCH 058/350] Issue in non regression tests --- radio/src/tests/conversions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radio/src/tests/conversions.cpp b/radio/src/tests/conversions.cpp index 50d94c531..1421fa175 100644 --- a/radio/src/tests/conversions.cpp +++ b/radio/src/tests/conversions.cpp @@ -77,7 +77,7 @@ TEST(Conversions, ConversionX7From22) EXPECT_ZSTREQ("Tes", g_model.telemetrySensors[0].label); EXPECT_EQ(10, g_model.telemetrySensors[0].id); - EXPECT_EQ(10, g_model.telemetrySensors[0].frskyInstance.physID); + EXPECT_EQ(9, g_model.telemetrySensors[0].frskyInstance.physID); EXPECT_EQ(-100, g_model.limitData[0].max); EXPECT_EQ(10, g_model.flightModeData[0].gvars[0]); From 3dc91719a09d3d1450b6707db8d2b7ee5b933e4f Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Wed, 19 Jun 2019 17:09:19 +0200 Subject: [PATCH 059/350] Bootloader [Exit] works now on all boards --- radio/src/targets/common/arm/stm32/bootloader/boot.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/radio/src/targets/common/arm/stm32/bootloader/boot.cpp b/radio/src/targets/common/arm/stm32/bootloader/boot.cpp index 679317779..dc3d6f86e 100644 --- a/radio/src/targets/common/arm/stm32/bootloader/boot.cpp +++ b/radio/src/targets/common/arm/stm32/bootloader/boot.cpp @@ -212,22 +212,18 @@ int main() pwrInit(); pwrOff(); - // wait for inputs to stabilize - for (uint32_t i = 0; i < 50000; i += 1) { - wdt_reset(); - } - // LHR & RHL trims not pressed simultanously if (readTrims() != BOOTLOADER_KEYS) { // Start main application jumpTo(APP_START_ADDRESS); } + pwrOn(); + #if defined(ROTARY_ENCODER_NAVIGATION) rotaryEncoderInit(); #endif - pwrOn(); delaysInit(); // needed for lcdInit() #if defined(DEBUG) From 62bf275c341343935386697fd93acaca0ea598b5 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Wed, 19 Jun 2019 17:21:36 +0200 Subject: [PATCH 060/350] Issue in non regression tests --- radio/src/tests/conversions.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/radio/src/tests/conversions.cpp b/radio/src/tests/conversions.cpp index 1421fa175..a413feaa8 100644 --- a/radio/src/tests/conversions.cpp +++ b/radio/src/tests/conversions.cpp @@ -52,7 +52,7 @@ TEST(Conversions, ConversionX9DPFrom22) EXPECT_ZSTREQ("Thr", g_model.inputNames[0]); EXPECT_ZSTREQ("Tes", g_model.telemetrySensors[0].label); EXPECT_EQ(10, g_model.telemetrySensors[0].id); - EXPECT_EQ(10, g_model.telemetrySensors[0].frskyInstance.physID); + EXPECT_EQ(9, g_model.telemetrySensors[0].frskyInstance.physID); } #endif @@ -116,7 +116,7 @@ TEST(Conversions, ConversionHorusFrom22) EXPECT_ZSTREQ("Rud", g_model.inputNames[0]); EXPECT_ZSTREQ("Tes", g_model.telemetrySensors[0].label); EXPECT_EQ(10, g_model.telemetrySensors[0].id); - EXPECT_EQ(10, g_model.telemetrySensors[0].frskyInstance.physID); + EXPECT_EQ(9, g_model.telemetrySensors[0].frskyInstance.physID); } #endif From 8a185ddd28fd4793208b3410a8f495e708fea93c Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Wed, 19 Jun 2019 17:26:47 +0200 Subject: [PATCH 061/350] Cosmetics --- radio/src/targets/common/arm/stm32/bootloader/boot.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/radio/src/targets/common/arm/stm32/bootloader/boot.cpp b/radio/src/targets/common/arm/stm32/bootloader/boot.cpp index dc3d6f86e..c4f3a3b53 100644 --- a/radio/src/targets/common/arm/stm32/bootloader/boot.cpp +++ b/radio/src/targets/common/arm/stm32/bootloader/boot.cpp @@ -63,9 +63,7 @@ uint32_t eepromWritten = 0; #endif volatile uint8_t tenms = 1; - FlashCheckRes valid; - MemoryType memoryType; uint32_t unlocked = 0; From 6ce9f8644db8e5ad353c1e9c2e3bdbfeb5475474 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Wed, 19 Jun 2019 17:27:31 +0200 Subject: [PATCH 062/350] Cosmetics --- radio/src/targets/common/arm/stm32/bootloader/boot.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/radio/src/targets/common/arm/stm32/bootloader/boot.cpp b/radio/src/targets/common/arm/stm32/bootloader/boot.cpp index c4f3a3b53..7fda614ab 100644 --- a/radio/src/targets/common/arm/stm32/bootloader/boot.cpp +++ b/radio/src/targets/common/arm/stm32/bootloader/boot.cpp @@ -81,6 +81,7 @@ void interrupt10ms(void) #if defined(ROTARY_ENCODER_NAVIGATION) static rotenc_t rePreviousValue; + rotenc_t reNewValue = (rotencValue / ROTARY_ENCODER_GRANULARITY); int8_t scrollRE = reNewValue - rePreviousValue; if (scrollRE) { From aa1fa2aa09b2e4db9c839e0eec5e8759227b54e3 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Wed, 19 Jun 2019 18:01:22 +0200 Subject: [PATCH 063/350] Cosmetics --- radio/src/targets/common/arm/stm32/bootloader/boot.cpp | 10 ++++++---- radio/src/targets/taranis/board.h | 1 - 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/radio/src/targets/common/arm/stm32/bootloader/boot.cpp b/radio/src/targets/common/arm/stm32/bootloader/boot.cpp index 7fda614ab..4d3d7cc91 100644 --- a/radio/src/targets/common/arm/stm32/bootloader/boot.cpp +++ b/radio/src/targets/common/arm/stm32/bootloader/boot.cpp @@ -17,21 +17,23 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ + #include "opentx.h" #include "boot.h" #include "bin_files.h" #if defined(PCBXLITE) -#define BOOTLOADER_KEYS 0x0F + #define BOOTLOADER_KEYS 0x0F #else -#define BOOTLOADER_KEYS 0x42 + #define BOOTLOADER_KEYS 0x42 #endif + #define APP_START_ADDRESS (uint32_t)(FIRMWARE_ADDRESS + BOOTLOADER_SIZE) #if defined(EEPROM) -#define MAIN_MENU_LEN 3 + #define MAIN_MENU_LEN 3 #else -#define MAIN_MENU_LEN 2 + #define MAIN_MENU_LEN 2 #endif typedef void (*voidFunction)(void); diff --git a/radio/src/targets/taranis/board.h b/radio/src/targets/taranis/board.h index 983515c5e..9bb5b94a8 100644 --- a/radio/src/targets/taranis/board.h +++ b/radio/src/targets/taranis/board.h @@ -312,7 +312,6 @@ enum EnumKeys KEY_MINUS, #endif - TRM_BASE, TRM_LH_DWN = TRM_BASE, TRM_LH_UP, From 60ad2473156c5432accab1ec4ee5512382216f66 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Wed, 19 Jun 2019 18:22:15 +0200 Subject: [PATCH 064/350] Cosmetics --- radio/src/opentx.cpp | 24 +++--------------------- radio/src/sdcard.cpp | 2 +- radio/src/targets/horus/board.h | 1 - radio/src/targets/sky9x/board.cpp | 2 ++ radio/src/targets/sky9x/board.h | 2 -- radio/src/targets/taranis/board.cpp | 2 +- radio/src/targets/taranis/board.h | 1 - 7 files changed, 7 insertions(+), 27 deletions(-) diff --git a/radio/src/opentx.cpp b/radio/src/opentx.cpp index 62af6d9e6..d43959145 100644 --- a/radio/src/opentx.cpp +++ b/radio/src/opentx.cpp @@ -1819,9 +1819,9 @@ void opentxInit() #endif currentSpeakerVolume = requiredSpeakerVolume = g_eeGeneral.speakerVolume + VOLUME_LEVEL_DEF; - #if !defined(SOFTWARE_VOLUME) - setScaledVolume(currentSpeakerVolume); - #endif +#if !defined(SOFTWARE_VOLUME) + setScaledVolume(currentSpeakerVolume); +#endif referenceSystemAudioFiles(); audioQueue.start(); @@ -1890,7 +1890,6 @@ int main() #if defined(PCBTARANIS) g_eeGeneral.contrast = LCD_CONTRAST_DEFAULT; #endif - wdt_disable(); boardInit(); @@ -1898,31 +1897,14 @@ int main() loadFonts(); #endif -#if defined(GUI) && !defined(PCBTARANIS) && !defined(PCBHORUS) - // TODO remove this - lcdInit(); -#endif - #if !defined(SIMU) stackPaint(); #endif -#if defined(GUI) && !defined(PCBTARANIS) - // lcdSetRefVolt(25); -#endif - #if defined(SPLASH) && (defined(PCBTARANIS) || defined(PCBHORUS)) drawSplash(); #endif -#if defined(DSM2_SERIAL) && !defined(TELEMETRY_FRSKY) - DSM2_Init(); -#endif - -#if defined(MENU_ROTARY_SW) - init_rotary_sw(); -#endif - #if defined(PCBHORUS) if (!IS_FIRMWARE_COMPATIBLE_WITH_BOARD()) { runFatalErrorScreen(STR_WRONG_PCBREV); diff --git a/radio/src/sdcard.cpp b/radio/src/sdcard.cpp index 59a2f239b..60948c913 100644 --- a/radio/src/sdcard.cpp +++ b/radio/src/sdcard.cpp @@ -77,7 +77,7 @@ bool isFileAvailable(const char * path, bool exclDir) FILINFO fno; return (f_stat(path, &fno) == FR_OK && !(fno.fattrib & AM_DIR)); } - return f_stat(path, 0) == FR_OK; + return f_stat(path, nullptr) == FR_OK; } /** diff --git a/radio/src/targets/horus/board.h b/radio/src/targets/horus/board.h index 60c98b9fd..48ef15a92 100644 --- a/radio/src/targets/horus/board.h +++ b/radio/src/targets/horus/board.h @@ -343,7 +343,6 @@ extern uint32_t powerupReason; #define DIRTY_SHUTDOWN 0xCAFEDEAD #define NORMAL_POWER_OFF ~DIRTY_SHUTDOWN -#define wdt_disable() void watchdogInit(unsigned int duration); #if defined(SIMU) #define WAS_RESET_BY_WATCHDOG() (false) diff --git a/radio/src/targets/sky9x/board.cpp b/radio/src/targets/sky9x/board.cpp index d25f83fda..776d050a4 100644 --- a/radio/src/targets/sky9x/board.cpp +++ b/radio/src/targets/sky9x/board.cpp @@ -401,6 +401,8 @@ void boardInit() rotaryEncoderInit(); #endif + lcdInit(); + init_SDcard(); } #else diff --git a/radio/src/targets/sky9x/board.h b/radio/src/targets/sky9x/board.h index 8846d63ff..58815c2a8 100644 --- a/radio/src/targets/sky9x/board.h +++ b/radio/src/targets/sky9x/board.h @@ -254,11 +254,9 @@ extern "C" { // WDT driver #if defined(WATCHDOG_DISABLED) || defined(SIMU) - #define wdt_disable() #define wdt_enable(x) #define wdt_reset() #else - #define wdt_disable() #define wdt_enable(x) WDT->WDT_MR = 0x3FFF207F #define wdt_reset() WDT->WDT_CR = 0xA5000001 #endif diff --git a/radio/src/targets/taranis/board.cpp b/radio/src/targets/taranis/board.cpp index 585241221..cd7cfec62 100644 --- a/radio/src/targets/taranis/board.cpp +++ b/radio/src/targets/taranis/board.cpp @@ -206,7 +206,7 @@ void boardInit() #if LCD_DEPTH > 1 lcdDrawBitmap(76, 2, bmp_startup, index*60, 60); #else - for(uint8_t i= 0; i < 4; i++) { + for(uint8_t i = 0; i < 4; i++) { if (index >= i) { lcdDrawFilledRect(LCD_W / 2 - 18 + 10 * i, LCD_H / 2 - 3, 6, 6, SOLID, 0); } diff --git a/radio/src/targets/taranis/board.h b/radio/src/targets/taranis/board.h index 9bb5b94a8..c84d460aa 100644 --- a/radio/src/targets/taranis/board.h +++ b/radio/src/targets/taranis/board.h @@ -502,7 +502,6 @@ uint32_t readTrims(void); #define wdt_enable(x) watchdogInit(x) #define wdt_reset() IWDG->KR = 0xAAAA #endif -#define wdt_disable() void watchdogInit(unsigned int duration); #define WAS_RESET_BY_SOFTWARE() (RCC->CSR & RCC_CSR_SFTRSTF) #define WAS_RESET_BY_WATCHDOG() (RCC->CSR & (RCC_CSR_WDGRSTF | RCC_CSR_WWDGRSTF)) From 02d2c671780c62476f93269272a5467742b97151 Mon Sep 17 00:00:00 2001 From: 3djc Date: Thu, 20 Jun 2019 08:11:33 +0200 Subject: [PATCH 065/350] Fix T12 default switch and pots config --- radio/src/targets/taranis/board.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radio/src/targets/taranis/board.h b/radio/src/targets/taranis/board.h index c84d460aa..0737cbf32 100644 --- a/radio/src/targets/taranis/board.h +++ b/radio/src/targets/taranis/board.h @@ -455,7 +455,7 @@ enum EnumSwitchesPositions #define STORAGE_NUM_SWITCHES 6 #define DEFAULT_SWITCH_CONFIG (SWITCH_2POS << 6) + (SWITCH_2POS << 4) + (SWITCH_3POS << 2) + (SWITCH_3POS << 0); #define DEFAULT_POTS_CONFIG (POT_WITHOUT_DETENT << 2) + (POT_WITHOUT_DETENT << 0) -#elif defined(PCBT12) +#elif defined(RADIO_T12) #define NUM_SWITCHES 6 #define STORAGE_NUM_SWITCHES 8 #define DEFAULT_SWITCH_CONFIG (SWITCH_2POS << 10) + (SWITCH_2POS << 8) + (SWITCH_3POS << 6) + (SWITCH_3POS << 4) + (SWITCH_3POS << 2) + (SWITCH_3POS << 0) From ab3f033c94b1c7320516e8bbcf806b8f3f52ae21 Mon Sep 17 00:00:00 2001 From: 3djc Date: Thu, 20 Jun 2019 09:26:50 +0200 Subject: [PATCH 066/350] Fix ghost trainer row on xlite --- radio/src/gui/128x64/model_setup.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/radio/src/gui/128x64/model_setup.cpp b/radio/src/gui/128x64/model_setup.cpp index 67b045780..cfdb074ab 100644 --- a/radio/src/gui/128x64/model_setup.cpp +++ b/radio/src/gui/128x64/model_setup.cpp @@ -138,11 +138,11 @@ enum MenuModelSetupItems { ITEM_MODEL_SETUP_TRAINER_BLUETOOTH, #endif ITEM_MODEL_SETUP_TRAINER_CHANNELS, - ITEM_MODEL_SETUP_TRAINER_PARAMS, + ITEM_MODEL_SETUP_TRAINER_PPM_PARAMS, #elif defined(PCBXLITE) ITEM_MODEL_SETUP_TRAINER_BLUETOOTH, ITEM_MODEL_SETUP_TRAINER_CHANNELS, - ITEM_MODEL_SETUP_TRAINER_PARAMS, + ITEM_MODEL_SETUP_TRAINER_PPM_PARAMS, #endif ITEM_MODEL_SETUP_LINES_COUNT }; @@ -219,8 +219,8 @@ enum MenuModelSetupItems { #define TRAINER_BLUETOOTH_ROW #endif #define TRAINER_CHANNELS_ROW (IS_SLAVE_TRAINER() ? (uint8_t)1 : HIDDEN_ROW) - #define TRAINER_PARAMS_ROW (IS_SLAVE_TRAINER() ? (uint8_t)2 : HIDDEN_ROW) - #define TRAINER_ROWS LABEL(Trainer), 0, TRAINER_BLUETOOTH_ROW TRAINER_CHANNELS_ROW, TRAINER_PARAMS_ROW + #define TRAINER_PPM_PARAMS_ROW (IS_SLAVE_TRAINER() ? (uint8_t)2 : HIDDEN_ROW) + #define TRAINER_ROWS LABEL(Trainer), 0, TRAINER_BLUETOOTH_ROW TRAINER_CHANNELS_ROW, TRAINER_PPM_PARAMS_ROW #elif defined(PCBXLITES) #define ANTENNA_ROW IF_NOT_PXX2_MODULE(INTERNAL_MODULE, IF_INTERNAL_MODULE_ON(0)), #define IF_BT_TRAINER_ON(x) (g_eeGeneral.bluetoothMode == BLUETOOTH_TRAINER ? (uint8_t)(x) : HIDDEN_ROW) @@ -228,8 +228,8 @@ enum MenuModelSetupItems { #define TRAINER_BLUETOOTH_S_ROW (bluetooth.distantAddr[0] == '\0' ? HIDDEN_ROW : LABEL()) #define TRAINER_BLUETOOTH_ROW (g_model.trainerData.mode == TRAINER_MODE_MASTER_BLUETOOTH ? TRAINER_BLUETOOTH_M_ROW : (g_model.trainerData.mode == TRAINER_MODE_SLAVE_BLUETOOTH ? TRAINER_BLUETOOTH_S_ROW : HIDDEN_ROW)) #define TRAINER_CHANNELS_ROW (IS_SLAVE_TRAINER() ? (uint8_t)1 : HIDDEN_ROW) - #define TRAINER_PARAMS_ROW (IS_SLAVE_TRAINER() ? (uint8_t)2 : HIDDEN_ROW) - #define TRAINER_ROWS LABEL(Trainer), 0, IF_BT_TRAINER_ON(TRAINER_BLUETOOTH_ROW), TRAINER_CHANNELS_ROW, TRAINER_PARAMS_ROW + #define TRAINER_PPM_PARAMS_ROW (IS_SLAVE_TRAINER() ? (uint8_t)2 : HIDDEN_ROW) + #define TRAINER_ROWS LABEL(Trainer), 0, IF_BT_TRAINER_ON(TRAINER_BLUETOOTH_ROW), TRAINER_CHANNELS_ROW, TRAINER_PPM_PARAMS_ROW #elif defined(PCBXLITE) #define ANTENNA_ROW IF_NOT_PXX2_MODULE(INTERNAL_MODULE, IF_INTERNAL_MODULE_ON(0)), #define IF_BT_TRAINER_ON(x) (g_eeGeneral.bluetoothMode == BLUETOOTH_TRAINER ? (uint8_t)(x) : HIDDEN_ROW) @@ -237,7 +237,8 @@ enum MenuModelSetupItems { #define TRAINER_BLUETOOTH_S_ROW (bluetooth.distantAddr[0] == '\0' ? HIDDEN_ROW : LABEL()) #define TRAINER_BLUETOOTH_ROW (g_model.trainerData.mode == TRAINER_MODE_MASTER_BLUETOOTH ? TRAINER_BLUETOOTH_M_ROW : (g_model.trainerData.mode == TRAINER_MODE_SLAVE_BLUETOOTH ? TRAINER_BLUETOOTH_S_ROW : HIDDEN_ROW)) #define TRAINER_CHANNELS_ROW (IS_SLAVE_TRAINER() ? (uint8_t)1 : HIDDEN_ROW) - #define TRAINER_ROWS IF_BT_TRAINER_ON(LABEL(Trainer)), IF_BT_TRAINER_ON(0), IF_BT_TRAINER_ON(TRAINER_BLUETOOTH_ROW), IF_BT_TRAINER_ON(TRAINER_CHANNELS_ROW) + #define TRAINER_PPM_PARAMS_ROW (HIDDEN_ROW) // xlite has only BT trainer, so never PPM + #define TRAINER_ROWS IF_BT_TRAINER_ON(LABEL(Trainer)), IF_BT_TRAINER_ON(0), IF_BT_TRAINER_ON(TRAINER_BLUETOOTH_ROW), IF_BT_TRAINER_ON(TRAINER_CHANNELS_ROW), TRAINER_PPM_PARAMS_ROW #else #define TRAINER_ROWS #endif @@ -1081,7 +1082,7 @@ void menuModelSetup(event_t event) } #if defined(PCBX7) || defined(PCBX9LITE) || defined(PCBXLITE) - case ITEM_MODEL_SETUP_TRAINER_PARAMS: + case ITEM_MODEL_SETUP_TRAINER_PPM_PARAMS: lcdDrawTextAlignedLeft(y, STR_PPMFRAME); lcdDrawText(MODEL_SETUP_2ND_COLUMN+3*FW, y, STR_MS); lcdDrawNumber(MODEL_SETUP_2ND_COLUMN, y, (int16_t)g_model.trainerData.frameLength*5 + 225, (menuHorizontalPosition<=0 ? attr : 0) | PREC1|LEFT); From b262808aa16612869a6703c7d12be7f91b2e2dc7 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Thu, 20 Jun 2019 09:27:06 +0200 Subject: [PATCH 067/350] Black screen on simu --- radio/src/simu.cpp | 8 ++++---- radio/src/targets/simu/simulcd.h | 2 ++ radio/src/targets/taranis/hal.h | 6 +++--- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/radio/src/simu.cpp b/radio/src/simu.cpp index 3583a54a8..df566bbea 100644 --- a/radio/src/simu.cpp +++ b/radio/src/simu.cpp @@ -331,14 +331,14 @@ void OpenTxSim::updateKeysAndSwitches(bool start) SWITCH_KEY(C, 2, 3); SWITCH_KEY(D, 3, 3); - #if defined(PCBX7) || defined(PCBXLITE) - SWITCH_KEY(F, 4, 2); - SWITCH_KEY(H, 5, 2); - #else + #if defined(HARDWARE_SWITCH_G) SWITCH_KEY(E, 4, 3); SWITCH_KEY(F, 5, 2); SWITCH_KEY(G, 6, 3); SWITCH_KEY(H, 7, 2); + #elif defined(HARDWARE_SWITCH_F) && defined(HARDWARE_SWITCH_H) + SWITCH_KEY(F, 4, 2); + SWITCH_KEY(H, 5, 2); #endif #if defined(PCBX9E) diff --git a/radio/src/targets/simu/simulcd.h b/radio/src/targets/simu/simulcd.h index ecfc473fb..c968efc26 100644 --- a/radio/src/targets/simu/simulcd.h +++ b/radio/src/targets/simu/simulcd.h @@ -21,6 +21,8 @@ #ifndef _SIMULCD_H_ #define _SIMULCD_H_ +#include "lcd.h" + extern int g_snapshot_idx; extern bool simuLcdRefresh; extern display_t simuLcdBuf[DISPLAY_BUFFER_SIZE]; diff --git a/radio/src/targets/taranis/hal.h b/radio/src/targets/taranis/hal.h index e90a70866..1a7b10bd5 100644 --- a/radio/src/targets/taranis/hal.h +++ b/radio/src/targets/taranis/hal.h @@ -236,7 +236,7 @@ #elif defined(PCBXLITE) || defined(PCBX9LITE) #define STORAGE_SWITCH_A #define HARDWARE_SWITCH_A - #define SWITCHES_GPIO_REG_A_H GPIOE->IDR + #define SWITCHES_GPIO_REG_A_H GPIOE->IDR #define SWITCHES_GPIO_PIN_A_H GPIO_Pin_1 // PE.01 #define SWITCHES_GPIO_REG_A_L GPIOE->IDR #define SWITCHES_GPIO_PIN_A_L GPIO_Pin_0 // PE.00 @@ -245,12 +245,12 @@ #define HARDWARE_SWITCH_A #define SWITCHES_GPIO_REG_A_L GPIOE->IDR #define SWITCHES_GPIO_PIN_A_L GPIO_Pin_7 // PE.07 - #define SWITCHES_GPIO_REG_A_H GPIOE->IDR + #define SWITCHES_GPIO_REG_A_H GPIOE->IDR #define SWITCHES_GPIO_PIN_A_H GPIO_Pin_13 // PE.13 #else #define STORAGE_SWITCH_A #define HARDWARE_SWITCH_A - #define SWITCHES_GPIO_REG_A_H GPIOB->IDR + #define SWITCHES_GPIO_REG_A_H GPIOB->IDR #define SWITCHES_GPIO_PIN_A_H GPIO_Pin_5 // PB.05 #define SWITCHES_GPIO_REG_A_L GPIOE->IDR #define SWITCHES_GPIO_PIN_A_L GPIO_Pin_0 // PE.00 From 999e55f09f0369d7aef2138ed61d68a3095df249 Mon Sep 17 00:00:00 2001 From: 3djc Date: Thu, 20 Jun 2019 11:21:17 +0200 Subject: [PATCH 068/350] Please Travis --- radio/src/targets/taranis/board.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/radio/src/targets/taranis/board.h b/radio/src/targets/taranis/board.h index 0737cbf32..97dfe397e 100644 --- a/radio/src/targets/taranis/board.h +++ b/radio/src/targets/taranis/board.h @@ -456,8 +456,8 @@ enum EnumSwitchesPositions #define DEFAULT_SWITCH_CONFIG (SWITCH_2POS << 6) + (SWITCH_2POS << 4) + (SWITCH_3POS << 2) + (SWITCH_3POS << 0); #define DEFAULT_POTS_CONFIG (POT_WITHOUT_DETENT << 2) + (POT_WITHOUT_DETENT << 0) #elif defined(RADIO_T12) - #define NUM_SWITCHES 6 - #define STORAGE_NUM_SWITCHES 8 + #define NUM_SWITCHES 8 + #define STORAGE_NUM_SWITCHES NUM_SWITCHES #define DEFAULT_SWITCH_CONFIG (SWITCH_2POS << 10) + (SWITCH_2POS << 8) + (SWITCH_3POS << 6) + (SWITCH_3POS << 4) + (SWITCH_3POS << 2) + (SWITCH_3POS << 0) #define DEFAULT_POTS_CONFIG (POT_WITHOUT_DETENT << 0) + (POT_WITH_DETENT << 2); // S1 = pot without detent, S2 = pot with detent #elif defined(PCBX7) From ca22ba0494ed734ddbdbd0dd374587c56022f43e Mon Sep 17 00:00:00 2001 From: 3djc Date: Thu, 20 Jun 2019 17:57:21 +0200 Subject: [PATCH 069/350] Fix reboot on radio with only one module --- radio/src/opentx.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/radio/src/opentx.h b/radio/src/opentx.h index e74139609..44c5e3ca0 100644 --- a/radio/src/opentx.h +++ b/radio/src/opentx.h @@ -397,10 +397,10 @@ extern uint8_t channel_order(uint8_t x); constexpr uint8_t HEART_TIMER_10MS = 0x01; constexpr uint8_t HEART_TIMER_PULSES = 0x02; // when multiple modules this is the first one -#if defined(PCBTARANIS) || defined(PCBHORUS) -constexpr uint8_t HEART_WDT_CHECK = (HEART_TIMER_10MS + (HEART_TIMER_PULSES << 0) + (HEART_TIMER_PULSES << 1)); +#if defined(HARDWARE_INTERNAL_MODULE) +constexpr uint8_t HEART_WDT_CHECK = HEART_TIMER_10MS + (HEART_TIMER_PULSES << INTERNAL_MODULE) + (HEART_TIMER_PULSES << EXTERNAL_MODOULE); #else -constexpr uint8_t HEART_WDT_CHECK = (HEART_TIMER_10MS + HEART_TIMER_PULSES); +constexpr uint8_t HEART_WDT_CHECK = HEART_TIMER_10MS + (HEART_TIMER_PULSES << EXTERNAL_MODULE); #endif extern uint8_t heartbeat; From 8cdcf565c21ff234dcff0729653547bb43e48d69 Mon Sep 17 00:00:00 2001 From: 3djc Date: Thu, 20 Jun 2019 18:51:01 +0200 Subject: [PATCH 070/350] Typo --- radio/src/opentx.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radio/src/opentx.h b/radio/src/opentx.h index 44c5e3ca0..e36d5f6a0 100644 --- a/radio/src/opentx.h +++ b/radio/src/opentx.h @@ -398,7 +398,7 @@ extern uint8_t channel_order(uint8_t x); constexpr uint8_t HEART_TIMER_10MS = 0x01; constexpr uint8_t HEART_TIMER_PULSES = 0x02; // when multiple modules this is the first one #if defined(HARDWARE_INTERNAL_MODULE) -constexpr uint8_t HEART_WDT_CHECK = HEART_TIMER_10MS + (HEART_TIMER_PULSES << INTERNAL_MODULE) + (HEART_TIMER_PULSES << EXTERNAL_MODOULE); +constexpr uint8_t HEART_WDT_CHECK = HEART_TIMER_10MS + (HEART_TIMER_PULSES << INTERNAL_MODULE) + (HEART_TIMER_PULSES << EXTERNAL_MODULE); #else constexpr uint8_t HEART_WDT_CHECK = HEART_TIMER_10MS + (HEART_TIMER_PULSES << EXTERNAL_MODULE); #endif From 42f48680e1a12fab67ec1c9e6aaab8851fc36223 Mon Sep 17 00:00:00 2001 From: MRC3742 Date: Thu, 20 Jun 2019 22:04:16 -0400 Subject: [PATCH 071/350] Multi protocol updates to MPM version 1.2.1.63 --- companion/src/firmwares/moduledata.h | 5 ++++- companion/src/firmwares/multiprotocols.cpp | 9 ++++++++- radio/src/gui/gui_common.cpp | 6 +++++- radio/src/pulses/modules_constants.h | 4 +++- radio/src/translations/untranslated.h | 2 +- 5 files changed, 21 insertions(+), 5 deletions(-) diff --git a/companion/src/firmwares/moduledata.h b/companion/src/firmwares/moduledata.h index c5148cde5..d96322eab 100644 --- a/companion/src/firmwares/moduledata.h +++ b/companion/src/firmwares/moduledata.h @@ -104,7 +104,10 @@ enum MultiModuleRFProtocols { MODULE_SUBTYPE_MULTI_V911S, MODULE_SUBTYPE_MULTI_GD00X, MODULE_SUBTYPE_MULTI_V761, - MODULE_SUBTYPE_MULTI_LAST = MODULE_SUBTYPE_MULTI_V761 + MODULE_SUBTYPE_MULTI_KF606, + MODULE_SUBTYPE_MULTI_REDPINE, + MODULE_SUBTYPE_MULTI_POTENSIC, + MODULE_SUBTYPE_MULTI_LAST = MODULE_SUBTYPE_MULTI_POTENSIC }; enum TrainerProtocol { diff --git a/companion/src/firmwares/multiprotocols.cpp b/companion/src/firmwares/multiprotocols.cpp index 87104eaee..7378cacb2 100644 --- a/companion/src/firmwares/multiprotocols.cpp +++ b/companion/src/firmwares/multiprotocols.cpp @@ -64,6 +64,8 @@ static const QStringList STR_SUBTYPE_HITEC {"Optima", "Optima Hub Telem", "M static const QStringList STR_SUBTYPE_BUGS_MINI {"Standard", "Bugs 3H"}; static const QStringList STR_SUBTYPE_E01X {"E012", "E015", "E016H"}; static const QStringList STR_SUBTYPE_GD00X {"GD V1", "GD V2"}; +static const QStringList STR_SUBTYPE_REDPINE {"Fast", "Slow"}; +static const QStringList STR_SUBTYPE_POTENSIC {"A20 Firefly", " - "}; static const QStringList NO_SUBTYPE {STR_MULTI_DEFAULT}; @@ -100,7 +102,11 @@ const Multiprotocols multiProtocols { {MODULE_SUBTYPE_MULTI_HITEC, 2, false, STR_SUBTYPE_HITEC, STR_MULTI_RFTUNE}, {MODULE_SUBTYPE_MULTI_BUGS_MINI, 1, false, STR_SUBTYPE_BUGS_MINI, nullptr}, {MODULE_SUBTYPE_MULTI_E01X, 2, false, STR_SUBTYPE_E01X, nullptr}, + {MODULE_SUBTYPE_MULTI_V911S, 0, false, NO_SUBTYPE, STR_MULTI_RFTUNE}, {MODULE_SUBTYPE_MULTI_GD00X, 1, false, STR_SUBTYPE_GD00X, nullptr}, + {MODULE_SUBTYPE_MULTI_KF606, 0, false, NO_SUBTYPE, STR_MULTI_RFTUNE}, + {MODULE_SUBTYPE_MULTI_REDPINE, 1, false, STR_SUBTYPE_REDPINE, STR_MULTI_RFTUNE}, + {MODULE_SUBTYPE_MULTI_POTENSIC, 1, false, STR_SUBTYPE_POTENSIC, nullptr}, {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) @@ -142,7 +148,8 @@ QString Multiprotocols::protocolToString(int protocol, bool custom) "FlySky", "Hubsan", "FrSky", "Hisky", "V2x2", "DSM", "Devo", "YD717", "KN", "SymaX", "SLT", "CX10", "CG023", "Bayang", "ESky", "MT99XX", "MJXQ", "Shenqi", "FY326", "SFHSS", "J6 PRO","FQ777","Assan","Hontai","Open LRS", "FlySky AFHDS2A", "Q2x2", "Walkera", "Q303", "GW008", "DM002", "Cabell", "ESky 150", "H8 3D", "Corona", "CFlie", - "Hitec", "Wfly", "Bugs", "Bugs Mini", "Traxxas", "NCC-1701-A", "E01X", "V911S", "GD00X", "V761" + "Hitec", "Wfly", "Bugs", "Bugs Mini", "Traxxas", "NCC-1701-A", "E01X", "WL Heli V911S", "GD00X", "Volantex V761", + "KFPlan KF606", "Redpine", "Potensic" }); if (protocol == MM_RF_CUSTOM_SELECTED || custom) diff --git a/radio/src/gui/gui_common.cpp b/radio/src/gui/gui_common.cpp index 818f083fe..b7851341e 100644 --- a/radio/src/gui/gui_common.cpp +++ b/radio/src/gui/gui_common.cpp @@ -797,6 +797,8 @@ const char STR_SUBTYPE_HITEC[] = "\007""Optima\0""Opt Hub""Minima\0"; const char STR_SUBTYPE_BUGS_MINI[] = "\006"" Std\0 ""Bugs3H"; const char STR_SUBTYPE_E01X[] = "\005""E012\0""E015\0""E016H"; const char STR_SUBTYPE_GD00X[] = "\005""GD_V1""GD_V2"; +const char STR_SUBTYPE_REDPINE[] = "\005"" Fast"" Slow"; +const char STR_SUBTYPE_POTENSIC[] = "\004"" A20"" -\0"; const mm_protocol_definition multi_protocols[] = { @@ -829,9 +831,11 @@ const mm_protocol_definition multi_protocols[] = { {MODULE_SUBTYPE_MULTI_HITEC, 2, false, STR_SUBTYPE_HITEC, STR_MULTI_RFTUNE}, {MODULE_SUBTYPE_MULTI_BUGS_MINI, 1, false, STR_SUBTYPE_BUGS_MINI, nullptr}, {MODULE_SUBTYPE_MULTI_E01X, 2, false, STR_SUBTYPE_E01X, nullptr}, + {MODULE_SUBTYPE_MULTI_V911S, 0, false, NO_SUBTYPE, STR_MULTI_RFTUNE}, {MODULE_SUBTYPE_MULTI_GD00X, 1, false, STR_SUBTYPE_GD00X, STR_MULTI_RFTUNE}, {MODULE_SUBTYPE_MULTI_KF606, 0, false, NO_SUBTYPE, STR_MULTI_RFTUNE}, - {MODULE_SUBTYPE_MULTI_V911S, 0, false, NO_SUBTYPE, STR_MULTI_RFTUNE}, + {MODULE_SUBTYPE_MULTI_REDPINE, 1, false, STR_SUBTYPE_REDPINE, STR_MULTI_RFTUNE}, + {MODULE_SUBTYPE_MULTI_POTENSIC, 1, false, STR_SUBTYPE_POTENSIC, nullptr}, {MM_RF_CUSTOM_SELECTED, 7, 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 194dc3f4f..b2a9c3138 100644 --- a/radio/src/pulses/modules_constants.h +++ b/radio/src/pulses/modules_constants.h @@ -114,7 +114,9 @@ enum ModuleSubtypeMulti { MODULE_SUBTYPE_MULTI_GD00X, MODULE_SUBTYPE_MULTI_V761, MODULE_SUBTYPE_MULTI_KF606, - MODULE_SUBTYPE_MULTI_LAST = MODULE_SUBTYPE_MULTI_KF606 + MODULE_SUBTYPE_MULTI_REDPINE, + MODULE_SUBTYPE_MULTI_POTENSIC, + MODULE_SUBTYPE_MULTI_LAST = MODULE_SUBTYPE_MULTI_POTENSIC }; enum MMDSM2Subtypes { diff --git a/radio/src/translations/untranslated.h b/radio/src/translations/untranslated.h index 64bb5b3be..10a0209d3 100644 --- a/radio/src/translations/untranslated.h +++ b/radio/src/translations/untranslated.h @@ -127,4 +127,4 @@ #define TR_DSM_PROTOCOLS "LP45""DSM2""DSMX" #define LEN_MULTI_PROTOCOLS "\006" -#define TR_MULTI_PROTOCOLS "FlySky""Hubsan""FrSky\0""Hisky\0""V2x2\0 ""DSM\0 ""Devo\0 ""YD717\0""KN\0 ""SymaX\0""SLT\0 ""CX10\0 ""CG023\0""Bayang""ESky\0 ""MT99XX""MJXq\0 ""Shenqi""FY326\0""SFHSS\0""J6 PRO""FQ777\0""Assan\0""Hontai""OpnLrs""FS 2A\0""Q2x2\0 ""Walk.\0""Q303\0 ""GW008\0""DM002\0""Cabell""Esy150""H8 3D\0""Corona""CFlie\0""Hitec\0""WFly\0 ""Bugs\0 ""BugMin""Traxas""NC1701""E01X\0 ""V911S\0""GD00X\0""V761\0 ""KF606\0" +#define TR_MULTI_PROTOCOLS "FlySky""Hubsan""FrSky\0""Hisky\0""V2x2\0 ""DSM\0 ""Devo\0 ""YD717\0""KN\0 ""SymaX\0""SLT\0 ""CX10\0 ""CG023\0""Bayang""ESky\0 ""MT99XX""MJXq\0 ""Shenqi""FY326\0""SFHSS\0""J6 PRO""FQ777\0""Assan\0""Hontai""OpnLrs""FS 2A\0""Q2x2\0 ""Walk.\0""Q303\0 ""GW008\0""DM002\0""Cabell""Esy150""H8 3D\0""Corona""CFlie\0""Hitec\0""WFly\0 ""Bugs\0 ""BugMin""Traxas""NC1701""E01X\0 ""V911S\0""GD00X\0""V761\0 ""KF606\0""Redpin""Potens" From dbec79e10f7d2e3a7b8fbfc00cd81122e31d4d83 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Fri, 21 Jun 2019 08:52:48 +0200 Subject: [PATCH 072/350] Bsongis/autoupdate (#6521) Auto update internal chips at boot if /FIRMWARE/autoupdate.frsk is present on SD --- radio/src/io/frsky_firmware_update.cpp | 29 +++++++----------- radio/src/io/frsky_firmware_update.h | 5 ++-- radio/src/opentx.cpp | 12 +++++++- radio/src/sdcard.h | 1 + radio/src/targets/horus/telemetry_driver.cpp | 30 +++++++++++++++++++ radio/src/targets/taranis/CMakeLists.txt | 5 ++++ radio/src/targets/taranis/board.cpp | 5 ++++ radio/src/targets/taranis/board.h | 1 + .../src/targets/taranis/telemetry_driver.cpp | 30 +++++++++++++++++++ tools/build-frsky.py | 2 ++ 10 files changed, 99 insertions(+), 21 deletions(-) diff --git a/radio/src/io/frsky_firmware_update.cpp b/radio/src/io/frsky_firmware_update.cpp index fd3f7fe3c..c3012b862 100644 --- a/radio/src/io/frsky_firmware_update.cpp +++ b/radio/src/io/frsky_firmware_update.cpp @@ -355,7 +355,7 @@ const char * FrskyDeviceFirmwareUpdate::endTransfer() return nullptr; } -void FrskyDeviceFirmwareUpdate::flashFirmware(const char * filename) +const char * FrskyDeviceFirmwareUpdate::flashFirmware(const char * filename) { pausePulses(); @@ -416,6 +416,8 @@ void FrskyDeviceFirmwareUpdate::flashFirmware(const char * filename) state = SPORT_IDLE; resumePulses(); + + return result; } #define CHIP_FIRMWARE_UPDATE_TIMEOUT 20000 /* 20s */ @@ -452,8 +454,6 @@ const char * FrskyChipFirmwareUpdate::waitAnswer(uint8_t & status) const char * FrskyChipFirmwareUpdate::startBootloader() { - telemetryPortSetDirectionOutput(); - sportSendByte(0x01); for (uint8_t i = 0; i < 30; i++) @@ -489,8 +489,6 @@ void FrskyChipFirmwareUpdate::sendByte(uint8_t byte, bool crcFlag) const char * FrskyChipFirmwareUpdate::sendUpgradeCommand(char command, uint32_t packetsCount) { - telemetryPortSetDirectionOutput(); - crc = 0; // Head @@ -532,8 +530,6 @@ const char * FrskyChipFirmwareUpdate::sendUpgradeCommand(char command, uint32_t const char * FrskyChipFirmwareUpdate::sendUpgradeData(uint32_t index, uint8_t * data) { - telemetryPortSetDirectionOutput(); - crc = 0; // Head @@ -620,7 +616,7 @@ const char * FrskyChipFirmwareUpdate::doFlashFirmware(const char * filename) return sendUpgradeCommand('E', packetsCount); } -void FrskyChipFirmwareUpdate::flashFirmware(const char * filename) +const char * FrskyChipFirmwareUpdate::flashFirmware(const char * filename, bool wait) { drawProgressScreen(getBasename(filename), STR_DEVICE_RESET, 0, 0); @@ -636,9 +632,11 @@ void FrskyChipFirmwareUpdate::flashFirmware(const char * filename) SPORT_UPDATE_POWER_OFF(); - /* wait 2s off */ - watchdogSuspend(2000); - RTOS_WAIT_MS(2000); + if (wait) { + /* wait 2s off */ + watchdogSuspend(2000); + RTOS_WAIT_MS(2000); + } telemetryInit(PROTOCOL_TELEMETRY_FRSKY_SPORT); @@ -655,13 +653,6 @@ void FrskyChipFirmwareUpdate::flashFirmware(const char * filename) POPUP_INFORMATION(STR_FIRMWARE_UPDATE_SUCCESS); } -#if defined(HARDWARE_INTERNAL_MODULE) - INTERNAL_MODULE_OFF(); -#endif - - EXTERNAL_MODULE_OFF(); - SPORT_UPDATE_POWER_OFF(); - /* wait 2s off */ watchdogSuspend(2000); RTOS_WAIT_MS(2000); @@ -679,4 +670,6 @@ void FrskyChipFirmwareUpdate::flashFirmware(const char * filename) } resumePulses(); + + return result; } diff --git a/radio/src/io/frsky_firmware_update.h b/radio/src/io/frsky_firmware_update.h index f0724a6db..dea3adb33 100644 --- a/radio/src/io/frsky_firmware_update.h +++ b/radio/src/io/frsky_firmware_update.h @@ -22,6 +22,7 @@ #define _FRSKY_FIRMWARE_UPDATE_H_ #include "dataconstants.h" +#include "definitions.h" #include "frsky_pxx2.h" enum FrskyFirmwareProductFamily { @@ -65,7 +66,7 @@ class FrskyDeviceFirmwareUpdate { module(module) { } - void flashFirmware(const char * filename); + const char * flashFirmware(const char * filename); protected: uint8_t state = SPORT_IDLE; @@ -96,7 +97,7 @@ class FrskyChipFirmwareUpdate { { } - void flashFirmware(const char * filename); + const char * flashFirmware(const char * filename, bool wait = true); protected: uint8_t crc; diff --git a/radio/src/opentx.cpp b/radio/src/opentx.cpp index d43959145..c635c147e 100644 --- a/radio/src/opentx.cpp +++ b/radio/src/opentx.cpp @@ -18,6 +18,7 @@ * GNU General Public License for more details. */ +#include #include "opentx.h" RadioData g_eeGeneral; @@ -1753,10 +1754,19 @@ void opentxInit() unexpectedShutdown = 1; } -#if defined(SDCARD) && !defined(PCBMEGA2560) +#if defined(SDCARD) // SDCARD related stuff, only done if not unexpectedShutdown if (!unexpectedShutdown) { sdInit(); + +#if defined(AUTOUPDATE) + if (f_stat(AUTOUPDATE_FILENAME, nullptr) == FR_OK) { + FrskyChipFirmwareUpdate device; + if (device.flashFirmware(AUTOUPDATE_FILENAME, false) == nullptr) + f_unlink(AUTOUPDATE_FILENAME); + } +#endif + logsInit(); } #endif diff --git a/radio/src/sdcard.h b/radio/src/sdcard.h index 5f39d936a..2b86198a4 100644 --- a/radio/src/sdcard.h +++ b/radio/src/sdcard.h @@ -37,6 +37,7 @@ #define SYSTEM_SUBDIR "SYSTEM" #define BITMAPS_PATH ROOT_PATH "IMAGES" #define FIRMWARES_PATH ROOT_PATH "FIRMWARE" +#define AUTOUPDATE_FILENAME FIRMWARES_PATH "/autoupdate.frsk" #define EEPROMS_PATH ROOT_PATH "EEPROM" #define SCRIPTS_PATH ROOT_PATH "SCRIPTS" #define WIZARD_PATH SCRIPTS_PATH "/WIZARD" diff --git a/radio/src/targets/horus/telemetry_driver.cpp b/radio/src/targets/horus/telemetry_driver.cpp index 6d9276ef1..8b782f759 100644 --- a/radio/src/targets/horus/telemetry_driver.cpp +++ b/radio/src/targets/horus/telemetry_driver.cpp @@ -140,10 +140,40 @@ void telemetryPortSetDirectionInput() void sportSendByte(uint8_t byte) { + telemetryPortSetDirectionOutput(); + while (!(TELEMETRY_USART->SR & USART_SR_TXE)); USART_SendData(TELEMETRY_USART, byte); } +void sportSendByteLoop(uint8_t byte) +{ + telemetryPortSetDirectionOutput(); + + outputTelemetryBuffer.data[0] = byte; + + DMA_InitTypeDef DMA_InitStructure; + DMA_DeInit(TELEMETRY_DMA_Stream_TX); + DMA_InitStructure.DMA_Channel = TELEMETRY_DMA_Channel_TX; + DMA_InitStructure.DMA_PeripheralBaseAddr = CONVERT_PTR_UINT(&TELEMETRY_USART->DR); + DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; + DMA_InitStructure.DMA_Memory0BaseAddr = CONVERT_PTR_UINT(outputTelemetryBuffer.data); + DMA_InitStructure.DMA_BufferSize = 1; + DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; + DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable; + DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; + DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; + DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; + DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; + DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; + DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; + DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; + DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; + DMA_Init(TELEMETRY_DMA_Stream_TX, &DMA_InitStructure); + DMA_Cmd(TELEMETRY_DMA_Stream_TX, ENABLE); + USART_DMACmd(TELEMETRY_USART, USART_DMAReq_Tx, ENABLE); +} + void sportSendBuffer(const uint8_t * buffer, uint32_t count) { telemetryPortSetDirectionOutput(); diff --git a/radio/src/targets/taranis/CMakeLists.txt b/radio/src/targets/taranis/CMakeLists.txt index aabd04a3c..2be5745fb 100644 --- a/radio/src/targets/taranis/CMakeLists.txt +++ b/radio/src/targets/taranis/CMakeLists.txt @@ -4,6 +4,7 @@ option(INTERNAL_MODULE_PPM "Support for PPM internal module hack" OFF) option(INTERNAL_MODULE_PXX1 "Support for PXX1 internal module replacement" OFF) option(PXX1 "PXX1 protocol support" ON) option(PXX2 "PXX2 protocol support" OFF) +option(AUTOUPDATE "Auto update internal chips from SD" OFF) if(PCB STREQUAL X9E) set(PWR_BUTTON "PRESS" CACHE STRING "Pwr button type (PRESS/SWITCH)") @@ -204,6 +205,10 @@ if(PCB STREQUAL X9E OR PCB STREQUAL X7 OR PCB STREQUAL XLITE OR PCB STREQUAL XLI ) endif() +if(AUTOUPDATE) + add_definitions(-DAUTOUPDATE) +endif() + set(HSE_VALUE 12000000) set(SDCARD YES) set(EEPROM EEPROM_RLC) diff --git a/radio/src/targets/taranis/board.cpp b/radio/src/targets/taranis/board.cpp index cd7cfec62..d6f949a50 100644 --- a/radio/src/targets/taranis/board.cpp +++ b/radio/src/targets/taranis/board.cpp @@ -137,6 +137,11 @@ void boardInit() pwrInit(); +#if defined(AUTOUPDATE) + telemetryPortInit(FRSKY_SPORT_BAUDRATE, TELEMETRY_SERIAL_WITHOUT_DMA); + sportSendByteLoop(0x7E); +#endif + #if defined(STATUS_LEDS) ledInit(); ledGreen(); diff --git a/radio/src/targets/taranis/board.h b/radio/src/targets/taranis/board.h index 97dfe397e..e5ea488be 100644 --- a/radio/src/targets/taranis/board.h +++ b/radio/src/targets/taranis/board.h @@ -704,6 +704,7 @@ void telemetryPortInit(uint32_t baudrate, uint8_t mode); void telemetryPortSetDirectionInput(void); void telemetryPortSetDirectionOutput(void); void sportSendByte(uint8_t byte); +void sportSendByteLoop(uint8_t byte); void sportSendBuffer(const uint8_t * buffer, uint32_t count); uint8_t telemetryGetByte(uint8_t * byte); void telemetryClearFifo(); diff --git a/radio/src/targets/taranis/telemetry_driver.cpp b/radio/src/targets/taranis/telemetry_driver.cpp index dc82fcd81..f46331bc0 100644 --- a/radio/src/targets/taranis/telemetry_driver.cpp +++ b/radio/src/targets/taranis/telemetry_driver.cpp @@ -97,10 +97,40 @@ void telemetryPortSetDirectionInput() void sportSendByte(uint8_t byte) { + telemetryPortSetDirectionOutput(); + while (!(TELEMETRY_USART->SR & USART_SR_TXE)); USART_SendData(TELEMETRY_USART, byte); } +void sportSendByteLoop(uint8_t byte) +{ + telemetryPortSetDirectionOutput(); + + outputTelemetryBuffer.data[0] = byte; + + DMA_InitTypeDef DMA_InitStructure; + DMA_DeInit(TELEMETRY_DMA_Stream_TX); + DMA_InitStructure.DMA_Channel = TELEMETRY_DMA_Channel_TX; + DMA_InitStructure.DMA_PeripheralBaseAddr = CONVERT_PTR_UINT(&TELEMETRY_USART->DR); + DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; + DMA_InitStructure.DMA_Memory0BaseAddr = CONVERT_PTR_UINT(outputTelemetryBuffer.data); + DMA_InitStructure.DMA_BufferSize = 1; + DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; + DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable; + DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; + DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; + DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; + DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; + DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; + DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; + DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; + DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; + DMA_Init(TELEMETRY_DMA_Stream_TX, &DMA_InitStructure); + DMA_Cmd(TELEMETRY_DMA_Stream_TX, ENABLE); + USART_DMACmd(TELEMETRY_USART, USART_DMAReq_Tx, ENABLE); +} + void sportSendBuffer(const uint8_t * buffer, uint32_t count) { telemetryPortSetDirectionOutput(); diff --git a/tools/build-frsky.py b/tools/build-frsky.py index 8a6078adf..7d1efd68f 100755 --- a/tools/build-frsky.py +++ b/tools/build-frsky.py @@ -12,6 +12,7 @@ options = { "XLITES": { "LUA": "NO_MODEL_SCRIPTS", "GVARS": "YES", + "AUTOUPDATE": "YES", "PXX1": "YES", "XJT": "NO", "R9M_SIZE_STD": "NO", @@ -23,6 +24,7 @@ options = { "X9LITE": { "LUA": "NO_MODEL_SCRIPTS", "GVARS": "YES", + "AUTOUPDATE": "YES", "PXX1": "YES", "XJT": "NO", "R9M_SIZE_STD": "NO", From 856a5e08533a1574e04b4c63fe464e4ac3b89372 Mon Sep 17 00:00:00 2001 From: 3djc Date: Fri, 21 Jun 2019 09:15:46 +0200 Subject: [PATCH 073/350] Minor T12 fix --- radio/src/targets/taranis/board.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radio/src/targets/taranis/board.h b/radio/src/targets/taranis/board.h index e5ea488be..31641c30a 100644 --- a/radio/src/targets/taranis/board.h +++ b/radio/src/targets/taranis/board.h @@ -459,7 +459,7 @@ enum EnumSwitchesPositions #define NUM_SWITCHES 8 #define STORAGE_NUM_SWITCHES NUM_SWITCHES #define DEFAULT_SWITCH_CONFIG (SWITCH_2POS << 10) + (SWITCH_2POS << 8) + (SWITCH_3POS << 6) + (SWITCH_3POS << 4) + (SWITCH_3POS << 2) + (SWITCH_3POS << 0) - #define DEFAULT_POTS_CONFIG (POT_WITHOUT_DETENT << 0) + (POT_WITH_DETENT << 2); // S1 = pot without detent, S2 = pot with detent + #define DEFAULT_POTS_CONFIG (POT_WITHOUT_DETENT << 0) + (POT_WITHOUT_DETENT << 2); // S1 = pot without detent, S2 = pot with detent #elif defined(PCBX7) #define NUM_SWITCHES 8 #define STORAGE_NUM_SWITCHES NUM_SWITCHES From e00a40885f3625b48c97f7dda7574ff6023c1f54 Mon Sep 17 00:00:00 2001 From: 3djc Date: Fri, 21 Jun 2019 09:48:03 +0200 Subject: [PATCH 074/350] T12 default contrast fix --- radio/src/targets/taranis/lcd_driver_spi.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/radio/src/targets/taranis/lcd_driver_spi.cpp b/radio/src/targets/taranis/lcd_driver_spi.cpp index d04a6e1e0..d4ad857cd 100644 --- a/radio/src/targets/taranis/lcd_driver_spi.cpp +++ b/radio/src/targets/taranis/lcd_driver_spi.cpp @@ -117,8 +117,9 @@ void lcdStart() lcdWriteCommand(0xa3); // Set bias=1/6 lcdWriteCommand(0x22); // Set internal rb/ra=5.0 lcdWriteCommand(0x2f); // All built-in power circuits on - lcdWriteCommand(0x24); // Set contrast - lcdWriteCommand(0x36); // Set Vop + lcdWriteCommand(0x24); // Power control set + lcdWriteCommand(0x81); // Set contrast + lcdWriteCommand(0x0A); // Set Vop lcdWriteCommand(0xa6); // Set display mode #else lcdWriteCommand(0xe2); // (14) Soft reset From a0d6fd12cfddd92077d355c5dc3990ad2cbdc658 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Fri, 21 Jun 2019 10:25:38 +0200 Subject: [PATCH 075/350] autoupdate options added into Companion --- companion/src/firmwares/opentx/opentxinterface.cpp | 2 ++ radio/util/fwoptions.py | 2 ++ 2 files changed, 4 insertions(+) diff --git a/companion/src/firmwares/opentx/opentxinterface.cpp b/companion/src/firmwares/opentx/opentxinterface.cpp index 9cab7fde4..1dff0cccf 100644 --- a/companion/src/firmwares/opentx/opentxinterface.cpp +++ b/companion/src/firmwares/opentx/opentxinterface.cpp @@ -1229,6 +1229,7 @@ void registerOpenTxFirmwares() /* FrSky X9-Lite board */ firmware = new OpenTxFirmware("opentx-x9lite", Firmware::tr("FrSky Taranis X9-Lite"), BOARD_TARANIS_X9LITE); addOpenTxTaranisOptions(firmware); + firmware->addOption("autoupdate", Firmware::tr("Support for auto update on boot")); registerOpenTxFirmware(firmware); /* FrSky X7 board */ @@ -1240,6 +1241,7 @@ void registerOpenTxFirmwares() firmware = new OpenTxFirmware("opentx-xlites", Firmware::tr("FrSky Taranis X-Lite S/PRO"), BOARD_TARANIS_XLITES); addOpenTxTaranisOptions(firmware); firmware->addOption("internalpxx1", Firmware::tr("Support for PXX1 internal module replacement")); + firmware->addOption("autoupdate", Firmware::tr("Support for auto update on boot")); registerOpenTxFirmware(firmware); /* FrSky X-Lite board */ diff --git a/radio/util/fwoptions.py b/radio/util/fwoptions.py index 07bc66734..75ae7dcf7 100755 --- a/radio/util/fwoptions.py +++ b/radio/util/fwoptions.py @@ -110,6 +110,7 @@ options_taranis_x9lite = { "lua": ("LUA", "YES", "NO_MODEL_SCRIPTS"), "luac": ("LUA_COMPILER", "YES", "NO"), "nogvars": ("GVARS", "NO", "YES"), + "autoupdate": ("AUTOUPDATE", "YES", None), "sqt5font": ("FONT", "SQT5", None), "noras": ("RAS", "NO", "YES"), "faimode": ("FAI", "YES", None), @@ -146,6 +147,7 @@ options_taranis_xlites = { "lua": ("LUA", "YES", "NO_MODEL_SCRIPTS"), "luac": ("LUA_COMPILER", "YES", "NO"), "nogvars": ("GVARS", "NO", "YES"), + "autoupdate": ("AUTOUPDATE", "YES", None), "sqt5font": ("FONT", "SQT5", None), "faimode": ("FAI", "YES", None), "faichoice": ("FAI", "CHOICE", None), From 2ac0ed307d8d905532b816e802963e99f07f5205 Mon Sep 17 00:00:00 2001 From: 3djc Date: Fri, 21 Jun 2019 12:47:37 +0200 Subject: [PATCH 076/350] Fix T12 special functions navigation --- radio/src/gui/128x64/model_special_functions.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/radio/src/gui/128x64/model_special_functions.cpp b/radio/src/gui/128x64/model_special_functions.cpp index a6b18ddf3..51313dd8d 100644 --- a/radio/src/gui/128x64/model_special_functions.cpp +++ b/radio/src/gui/128x64/model_special_functions.cpp @@ -446,7 +446,7 @@ void menuSpecialFunctions(event_t event, CustomFunctionData * functions, CustomF void menuModelSpecialFunctions(event_t event) { -#if defined(PCBX7) || defined(PCBX9LITE) +#if defined(NAVIGATION_X7) const CustomFunctionData * cfn = &g_model.customFn[menuVerticalPosition]; if (!CFN_SWITCH(cfn) && menuHorizontalPosition < 0 && event==EVT_KEY_BREAK(KEY_ENTER)) { menuHorizontalPosition = 0; @@ -456,7 +456,7 @@ void menuModelSpecialFunctions(event_t event) menuSpecialFunctions(event, g_model.customFn, &modelFunctionsContext); -#if defined(PCBX7) || defined(PCBX9LITE) +#if defined(NAVIGATION_X7) if (!CFN_SWITCH(cfn) && menuHorizontalPosition == 0 && s_editMode <= 0) { menuHorizontalPosition = -1; } From ba445c6c0d97f61bfe2447cebf48b3d26fe28b58 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Fri, 21 Jun 2019 12:51:27 +0200 Subject: [PATCH 077/350] Compilation fix on OSX / Windows --- companion/src/storage/mountlist.cpp | 2 +- radio/src/rtos.h | 16 +++++++++++----- radio/src/targets/simu/simpgmspace.cpp | 2 ++ radio/src/targets/simu/simueeprom.cpp | 13 +++++-------- 4 files changed, 19 insertions(+), 14 deletions(-) diff --git a/companion/src/storage/mountlist.cpp b/companion/src/storage/mountlist.cpp index aa52c1afc..d40339c1c 100644 --- a/companion/src/storage/mountlist.cpp +++ b/companion/src/storage/mountlist.cpp @@ -363,7 +363,7 @@ dev_from_mount_options (char const *mount_options) /* GNU/Linux allows file system implementations to define their own meaning for "dev=" mount options, so don't trust the meaning here. */ -# ifndef __linux__ +#ifndef __linux__ static char const dev_pattern[] = ",dev="; char const *devopt = strstr (mount_options, dev_pattern); diff --git a/radio/src/rtos.h b/radio/src/rtos.h index b439ecea6..6e42ebf30 100644 --- a/radio/src/rtos.h +++ b/radio/src/rtos.h @@ -28,7 +28,6 @@ extern "C++" { #endif #if defined(SIMU) - #include #include @@ -113,11 +112,20 @@ extern "C++" { #define TASK_FUNCTION(task) void * task(void * pdata) - template - inline void RTOS_CREATE_TASK(pthread_t &taskId, void * task(void *), const char * name, FakeTaskStack &, unsigned, unsigned) + inline void RTOS_CREATE_TASK(pthread_t &taskId, void * task(void *), const char * name) { pthread_create(&taskId, nullptr, task, nullptr); +#ifdef __linux__ pthread_setname_np(taskId, name); +#endif + } + +template + inline void RTOS_CREATE_TASK(pthread_t &taskId, void * task(void *), const char * name, FakeTaskStack &, unsigned size = 0, unsigned priority = 0) + { + UNUSED(size); + UNUSED(priority); + RTOS_CREATE_TASK(taskId, task, name); } #define TASK_RETURN() return nullptr @@ -138,9 +146,7 @@ extern "C++" { { return (uint32_t)(simuTimerMicros() / 1000); } - #elif defined(RTOS_COOS) - #ifdef __cplusplus extern "C" { #endif diff --git a/radio/src/targets/simu/simpgmspace.cpp b/radio/src/targets/simu/simpgmspace.cpp index d93ee21c6..9a6fa552b 100644 --- a/radio/src/targets/simu/simpgmspace.cpp +++ b/radio/src/targets/simu/simpgmspace.cpp @@ -386,7 +386,9 @@ void StartAudioThread(int volumeGain) sp.sched_priority = SCHED_RR; pthread_attr_setschedparam(&attr, &sp); pthread_create(&simuAudio.threadPid, &attr, &audioThread, nullptr); +#ifdef __linux__ pthread_setname_np(simuAudio.threadPid, "audio"); +#endif return; } diff --git a/radio/src/targets/simu/simueeprom.cpp b/radio/src/targets/simu/simueeprom.cpp index d2368c7c0..414b73270 100644 --- a/radio/src/targets/simu/simueeprom.cpp +++ b/radio/src/targets/simu/simueeprom.cpp @@ -73,6 +73,8 @@ void eepromSimuWriteBlock(uint8_t * buffer, size_t address, size_t size) volatile uint8_t eepromTransferComplete = 1; void * eeprom_thread_function(void *) { + eeprom_thread_running = true; + while (!sem_wait(eeprom_write_sem)) { if (!eeprom_thread_running) return nullptr; @@ -85,7 +87,8 @@ void * eeprom_thread_function(void *) } eepromTransferComplete = 1; } - return 0; + + return nullptr; } uint8_t eepromReadStatus() @@ -162,13 +165,7 @@ void StartEepromThread(const char * filename) sem_init(eeprom_write_sem, 0, 0); #endif - if (!pthread_create(&eeprom_thread_pid, nullptr, &eeprom_thread_function, nullptr)) { - pthread_setname_np(eeprom_thread_pid, "eeprom"); - eeprom_thread_running = true; - } - else { - perror("Could not create eeprom thread."); - } + RTOS_CREATE_TASK(eeprom_thread_pid, eeprom_thread_function, "eeprom"); } void StopEepromThread() From 3d436f9d5cf8f256bb0c1250729b966673b59b6a Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Fri, 21 Jun 2019 12:54:53 +0200 Subject: [PATCH 078/350] Dead code removed --- radio/src/targets/simu/simpgmspace.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/radio/src/targets/simu/simpgmspace.cpp b/radio/src/targets/simu/simpgmspace.cpp index 9a6fa552b..8307499ef 100644 --- a/radio/src/targets/simu/simpgmspace.cpp +++ b/radio/src/targets/simu/simpgmspace.cpp @@ -408,10 +408,6 @@ void lcdSetRefVolt(uint8_t val) } #endif -void adcPrepareBandgap() -{ -} - #if defined(PCBTARANIS) void lcdOff() { From d6c6b0e6531af31da99d0d8e688c488f67b571b0 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Fri, 21 Jun 2019 12:57:33 +0200 Subject: [PATCH 079/350] Dead code removed --- radio/src/targets/simu/simpgmspace.cpp | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/radio/src/targets/simu/simpgmspace.cpp b/radio/src/targets/simu/simpgmspace.cpp index 8307499ef..db52fb40d 100644 --- a/radio/src/targets/simu/simpgmspace.cpp +++ b/radio/src/targets/simu/simpgmspace.cpp @@ -34,20 +34,15 @@ #include #endif -uint8_t MCUCSR, MCUSR, MCUCR; -volatile uint8_t pina=0xff, pinb=0xff, pinc=0xff, pind, pine=0xff, pinf=0xff, ping=0xff, pinh=0xff, pinj=0, pinl=0; -uint8_t portb, portc, porth=0, dummyport; -uint16_t dummyport16; int g_snapshot_idx = 0; uint8_t simu_start_mode = 0; -char * main_thread_error = NULL; +char * main_thread_error = nullptr; bool simu_shutdown = false; bool simu_running = false; #if defined(STM32) -uint32_t Peri1_frequency, Peri2_frequency; GPIO_TypeDef gpioa, gpiob, gpioc, gpiod, gpioe, gpiof, gpiog, gpioh, gpioi, gpioj; TIM_TypeDef tim1, tim2, tim3, tim4, tim5, tim6, tim7, tim8, tim9, tim10; RCC_TypeDef rcc; @@ -80,14 +75,12 @@ void toplcdOff() uint64_t simuTimerMicros(void) { #if SIMPGMSPC_USE_QT - static QElapsedTimer ticker; if (!ticker.isValid()) ticker.start(); return ticker.nsecsElapsed() / 1000; #elif defined(_MSC_VER) - static double freqScale = 0.0; static LARGE_INTEGER firstTick; LARGE_INTEGER newTick; @@ -106,12 +99,9 @@ uint64_t simuTimerMicros(void) QueryPerformanceCounter(&newTick); // compute the elapsed time return (newTick.QuadPart - firstTick.QuadPart) * freqScale; - #else // GNUC - auto now = std::chrono::steady_clock::now(); return (uint64_t) std::chrono::duration_cast(now.time_since_epoch()).count(); - #endif } @@ -389,7 +379,6 @@ void StartAudioThread(int volumeGain) #ifdef __linux__ pthread_setname_np(simuAudio.threadPid, "audio"); #endif - return; } void StopAudioThread() From 01a5e56b927415282398ab750203d7e3d15215e5 Mon Sep 17 00:00:00 2001 From: 3djc Date: Fri, 21 Jun 2019 17:52:08 +0200 Subject: [PATCH 080/350] Multimodule back as an option for T12 (less confusing for users) --- companion/src/firmwares/opentx/opentxinterface.cpp | 1 + radio/src/targets/taranis/CMakeLists.txt | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/companion/src/firmwares/opentx/opentxinterface.cpp b/companion/src/firmwares/opentx/opentxinterface.cpp index 1dff0cccf..4dc622ccb 100644 --- a/companion/src/firmwares/opentx/opentxinterface.cpp +++ b/companion/src/firmwares/opentx/opentxinterface.cpp @@ -1264,6 +1264,7 @@ void registerOpenTxFirmwares() /* Jumper T12 board */ firmware = new OpenTxFirmware("opentx-t12", QCoreApplication::translate("Firmware", "Jumper T12"), BOARD_JUMPER_T12); addOpenTxCommonOptions(firmware); + firmware->addOption("multimodule", Firmware::tr("Support for the DIY-Multiprotocol-TX-Module")); firmware->addOption("noheli", Firmware::tr("Disable HELI menu and cyclic mix support")); firmware->addOption("nogvars", Firmware::tr("Disable Global variables")); firmware->addOption("lua", Firmware::tr("Enable Lua custom scripts screen")); diff --git a/radio/src/targets/taranis/CMakeLists.txt b/radio/src/targets/taranis/CMakeLists.txt index 2be5745fb..7bcd07a48 100644 --- a/radio/src/targets/taranis/CMakeLists.txt +++ b/radio/src/targets/taranis/CMakeLists.txt @@ -78,7 +78,6 @@ elseif(PCB STREQUAL X7) set(LUA_EXPORT lua_export_t12) set(FLAVOUR t12) set(NAVIGATION_TYPE 9x) - set(MULTIMODULE ON) add_definitions(-DRADIO_T12) add_definitions(-DEEPROM_VARIANT=0x4001) else() From df489557a65dd17fd5ba3b19b1d2f5ba7325cd64 Mon Sep 17 00:00:00 2001 From: 3djc Date: Sat, 22 Jun 2019 13:13:04 +0200 Subject: [PATCH 081/350] Fix some wrong data when migrating to OpenTX --- radio/src/storage/conversions/conversions_218_219.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/radio/src/storage/conversions/conversions_218_219.cpp b/radio/src/storage/conversions/conversions_218_219.cpp index 578b87e82..0059c0b15 100644 --- a/radio/src/storage/conversions/conversions_218_219.cpp +++ b/radio/src/storage/conversions/conversions_218_219.cpp @@ -186,6 +186,10 @@ void convertModelData_218_to_219(ModelData &model) newModel.moduleData[i].type += 4; } +#if defined(RADIO_T12) + newModel.moduleData[INTERNAL_MODULE].type = MODULE_TYPE_NONE; // Early t12 firmware had unused INT settings that need to be cleared +#endif + for (uint8_t module=0; module<2; module++) { if (oldModel.moduleData[module].failsafeMode == FAILSAFE_CUSTOM) { memcpy(newModel.failsafeChannels, oldModel.moduleData[module].failsafeChannels, sizeof(newModel.failsafeChannels)); @@ -297,4 +301,8 @@ void convertRadioData_218_to_219(RadioData & settings) memcpy(&settings.currModelFilename[0], &settings_v218.currModelFilename[0], sizeof(RadioData_v218) - offsetof(RadioData_v218, currModelFilename[0])); #endif + +#if defined(RADIO_T12) + g_eeGeneral.potsConfig = bfSet(g_eeGeneral.potsConfig, POT_WITHOUT_DETENT, 2, 2); // T12 comes with wrongly defined pot2 +#endif } From 74086231fbcd14953067b0a3002d11f4bedc784a Mon Sep 17 00:00:00 2001 From: 3djc Date: Sat, 22 Jun 2019 17:42:10 +0200 Subject: [PATCH 082/350] Fix #6523 (at least the OTX part) --- radio/src/lua/api_general.cpp | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/radio/src/lua/api_general.cpp b/radio/src/lua/api_general.cpp index 111d17c6c..e19bea366 100644 --- a/radio/src/lua/api_general.cpp +++ b/radio/src/lua/api_general.cpp @@ -1686,18 +1686,7 @@ const luaR_value_entry opentxConstants[] = { { "EVT_VIRTUAL_PREVIOUS_REPT", EVT_KEY_REPT(KEY_MINUS) }, #endif -#if defined(PCBHORUS) -#if defined(KEYS_GPIO_REG_PGUP) - { "EVT_PAGEUP_FIRST", EVT_KEY_FIRST(KEY_PGUP) }, -#endif - { "EVT_PAGEDN_FIRST", EVT_KEY_FIRST(KEY_PGDN) }, - { "EVT_PAGEDN_BREAK", EVT_KEY_BREAK(KEY_PGDN) }, - { "EVT_PAGEDN_LONG", EVT_KEY_LONG(KEY_PGDN) }, - { "EVT_TELEM_FIRST", EVT_KEY_FIRST(KEY_TELEM) }, - { "EVT_MODEL_FIRST", EVT_KEY_FIRST(KEY_MODEL) }, - { "EVT_SYS_FIRST", EVT_KEY_FIRST(KEY_RADIO) }, - { "EVT_RTN_FIRST", EVT_KEY_FIRST(KEY_EXIT) }, -#elif defined(KEYS_GPIO_REG_EXIT) +#if defined(KEYS_GPIO_REG_EXIT) { "EVT_EXIT_BREAK", EVT_KEY_BREAK(KEY_EXIT) }, #endif @@ -1727,6 +1716,12 @@ const luaR_value_entry opentxConstants[] = { KEY_EVENTS(LEFT, KEY_LEFT), #endif +#if defined(KEYS_GPIO_REG_DOWN) && defined(NAVIGATION_HORUS) + { "EVT_RTN_FIRST", EVT_KEY_BREAK(KEY_EXIT) }, +#else + KEY_EVENTS(DOWN, KEY_DOWN), +#endif + #if defined(KEYS_GPIO_REG_PGUP) KEY_EVENTS(PAGEUP, KEY_PGUP), #endif From a89898f36b34d2e1c9e2a28c011427c0b2f6bdf2 Mon Sep 17 00:00:00 2001 From: 3djc Date: Mon, 24 Jun 2019 08:53:42 +0200 Subject: [PATCH 083/350] Fix key diag screen for256x128 range (was completely broken) --- radio/src/gui/212x64/radio_diagkeys.cpp | 41 +++++++++++++------------ 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/radio/src/gui/212x64/radio_diagkeys.cpp b/radio/src/gui/212x64/radio_diagkeys.cpp index a221e6260..3ea5eb862 100644 --- a/radio/src/gui/212x64/radio_diagkeys.cpp +++ b/radio/src/gui/212x64/radio_diagkeys.cpp @@ -30,30 +30,33 @@ void menuRadioDiagKeys(event_t event) { SIMPLE_SUBMENU(STR_MENU_RADIO_SWITCHES, 1); - lcdDrawText(14*FW, MENU_HEADER_HEIGHT + 1, STR_VTRIM); + lcdDrawText(24*FW, MENU_HEADER_HEIGHT + 1, STR_VTRIM); - for (uint8_t i=0; i<9; i++) { + for (uint8_t i=0; i Date: Mon, 24 Jun 2019 12:48:37 +0200 Subject: [PATCH 084/350] CZ translations update --- radio/src/translations/cz.h.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/radio/src/translations/cz.h.txt b/radio/src/translations/cz.h.txt index 9ae720a08..38d3206e7 100644 --- a/radio/src/translations/cz.h.txt +++ b/radio/src/translations/cz.h.txt @@ -778,17 +778,17 @@ #define TR_MODULES_RX_VERSION "Verze modulu a RX" #define TR_MENU_MODULES_RX_VERSION "VERZE MODULU A RX" #define TR_GYRO "Gyro" -#define TR_STICKS_POTS_SLIDERS "Páky/Poty/Slidery" -#define TR_PWM_STICKS_POTS_SLIDERS "PWM Páky/Poty/Slidery" +#define TR_STICKS_POTS_SLIDERS "páky/pot./slidery" +#define TR_PWM_STICKS_POTS_SLIDERS "PWM páky/Pot./slidery" #define TR_RF_PROTOCOL "RF Protokol" #define TR_MODULE_OPTIONS "Možnosti modulu" #define TR_POWER "Výkon" #define TR_NO_TX_OPTIONS "žádné možnosti" #define TR_RTC_BATT "RTC Bat" -#define TR_POWER_METER_EXT "Měřák výkonu (EXT)" -#define TR_POWER_METER_INT "Měřák výkonu (INT)" -#define TR_SPECTRUM_ANALYSER_EXT "Spekt. an. (EXT)" -#define TR_SPECTRUM_ANALYSER_INT "Spekt. an. (INT)" +#define TR_POWER_METER_EXT "Měřič výkonu (EXT)" +#define TR_POWER_METER_INT "Měřič výkonu (INT)" +#define TR_SPECTRUM_ANALYSER_EXT "Spektální. an. (EXT)" +#define TR_SPECTRUM_ANALYSER_INT "Spektální. an. (INT)" #define TR_SDCARD_FULL "Plná SD karta" #define TR_INCOMPATIBLE "Nekompatibilní" #define TR_WARNING "KONTROLA" From 29b7d3b08527bb7b3353c1c094398798658df5db Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Mon, 24 Jun 2019 12:50:39 +0200 Subject: [PATCH 085/350] Dead code removal, model registration ID was cleared on EEPROM transfer --- companion/src/firmwares/modeldata.h | 2 + .../src/firmwares/opentx/opentxeeprom.cpp | 183 ++---------------- 2 files changed, 19 insertions(+), 166 deletions(-) diff --git a/companion/src/firmwares/modeldata.h b/companion/src/firmwares/modeldata.h index a5e53432c..c4c0b0854 100644 --- a/companion/src/firmwares/modeldata.h +++ b/companion/src/firmwares/modeldata.h @@ -203,6 +203,8 @@ class ModelData { TopbarData topbarData; + char registrationId[8+1]; + void clear(); bool isEmpty() const; void setDefaultInputs(const GeneralSettings & settings); diff --git a/companion/src/firmwares/opentx/opentxeeprom.cpp b/companion/src/firmwares/opentx/opentxeeprom.cpp index f2c109e49..04d6dde18 100644 --- a/companion/src/firmwares/opentx/opentxeeprom.cpp +++ b/companion/src/firmwares/opentx/opentxeeprom.cpp @@ -757,7 +757,7 @@ class MixField: public TransformedField { } } - virtual void beforeExport() + virtual void beforeExport() override { if (mix.destCh && mix.srcRaw.type != SOURCE_TYPE_NONE) { _destCh = mix.destCh - 1; @@ -793,7 +793,7 @@ class MixField: public TransformedField { splitGvarParam(mix.sOffset, _offset, _offsetMode, board, version); } - virtual void afterImport() + void afterImport() override { if (mix.srcRaw.type != SOURCE_TYPE_NONE) { mix.destCh = _destCh + 1; @@ -1049,7 +1049,7 @@ class CurvesField: public TransformedField { } } - virtual void beforeExport() + void beforeExport() override { memset(_points, 0, sizeof(_points)); @@ -1084,7 +1084,7 @@ class CurvesField: public TransformedField { } } - virtual void afterImport() + void afterImport() override { int * cur = &_points[0]; @@ -1170,61 +1170,6 @@ class LogicalSwitchesFunctionsTable: public ConversionTable { } }; -class AndSwitchesConversionTable: public ConversionTable { - - public: - AndSwitchesConversionTable(Board::Type board, unsigned int version) - { - int val=0; - addConversion(RawSwitch(SWITCH_TYPE_NONE), val++); - - if (IS_STM32(board)) { - for (int i=1; i<=MAX_SWITCHES_POSITION(board, version); i++) { - int s = switchIndex(i, board, version); - addConversion(RawSwitch(SWITCH_TYPE_SWITCH, -s), -val); - addConversion(RawSwitch(SWITCH_TYPE_SWITCH, s), val++); - } - for (int i=1; i<=MAX_LOGICAL_SWITCHES(board, version); i++) { - addConversion(RawSwitch(SWITCH_TYPE_VIRTUAL, -i), -val); - addConversion(RawSwitch(SWITCH_TYPE_VIRTUAL, i), val++); - } - } - else if (IS_SKY9X(board)) { - for (int i=1; i<=8; i++) { - int s = switchIndex(i, board, version); - addConversion(RawSwitch(SWITCH_TYPE_SWITCH, -s), -val); - addConversion(RawSwitch(SWITCH_TYPE_SWITCH, s), val++); - } - for (int i=1; i<=MAX_LOGICAL_SWITCHES(board, version); i++) { - addConversion(RawSwitch(SWITCH_TYPE_VIRTUAL, -i), -val); - addConversion(RawSwitch(SWITCH_TYPE_VIRTUAL, i), val++); - } - } - else { - for (int i=1; i<=9; i++) { - int s = switchIndex(i, board, version); - addConversion(RawSwitch(SWITCH_TYPE_SWITCH, s), val++); - } - for (int i=1; i<=7; i++) { - addConversion(RawSwitch(SWITCH_TYPE_VIRTUAL, i), val++); - } - } - } - - static ConversionTable * getInstance(Board::Type board, unsigned int version) - { - return new SwitchesConversionTable(board, version); - } - - - protected: - - void addConversion(const RawSwitch & sw, const int b) - { - ConversionTable::addConversion(sw.toValue(), b); - } -}; - class LogicalSwitchField: public TransformedField { public: LogicalSwitchField(DataField * parent, LogicalSwitchData & csw, Board::Type board, unsigned int version, unsigned int variant, ModelData * model=nullptr): @@ -1238,7 +1183,6 @@ class LogicalSwitchField: public TransformedField { functionsConversionTable(board, version), sourcesConversionTable(SourcesConversionTable::getInstance(board, version, variant, 0)), switchesConversionTable(SwitchesConversionTable::getInstance(board, version)), - andswitchesConversionTable(AndSwitchesConversionTable::getInstance(board, version)), v1(0), v2(0), v3(0) @@ -1247,7 +1191,7 @@ class LogicalSwitchField: public TransformedField { internalField.Append(new ConversionField< UnsignedField<8> >(this, csw.func, &functionsConversionTable, "Function")); internalField.Append(new SignedField<10>(this, v1)); internalField.Append(new SignedField<10>(this, v3)); - internalField.Append(new ConversionField< SignedField<9> >(this, (int &)csw.andsw, andswitchesConversionTable, "AND switch")); + internalField.Append(new ConversionField< SignedField<9> >(this, (int &)csw.andsw, switchesConversionTable, "AND switch")); internalField.Append(new SpareBitsField<1>(this)); // TODO extra switch mode internalField.Append(new SpareBitsField<2>(this)); internalField.Append(new SignedField<16>(this, v2)); @@ -1263,16 +1207,15 @@ class LogicalSwitchField: public TransformedField { internalField.Append(new ConversionField< UnsignedField<8> >(this, csw.delay, 0, scale)); internalField.Append(new ConversionField< UnsignedField<8> >(this, csw.duration, 0, scale)); if (version == 217) { - internalField.Append(new ConversionField< SignedField<8> >(this, (int &)csw.andsw, andswitchesConversionTable, "AND switch")); + internalField.Append(new ConversionField< SignedField<8> >(this, (int &)csw.andsw, switchesConversionTable, "AND switch")); } } ~LogicalSwitchField() { - delete andswitchesConversionTable; } - virtual void beforeExport() + void beforeExport() override { if (csw.func == LS_FN_TIMER) { v1 = csw.val1; @@ -1297,7 +1240,7 @@ class LogicalSwitchField: public TransformedField { } } - virtual void afterImport() + void afterImport() override { if (csw.func == LS_FN_TIMER) { csw.val1 = v1; @@ -1334,7 +1277,6 @@ class LogicalSwitchField: public TransformedField { LogicalSwitchesFunctionsTable functionsConversionTable; SourcesConversionTable * sourcesConversionTable; SwitchesConversionTable * switchesConversionTable; - ConversionTable * andswitchesConversionTable; int v1; int v2; int v3; @@ -1408,12 +1350,12 @@ class SwitchesWarningField: public TransformedField { { } - virtual void beforeExport() + void beforeExport() override { _sw = sw; } - virtual void afterImport() + void afterImport() override { sw = _sw; qCDebug(eepromImport) << QString("imported %1").arg(internalField.getName()); @@ -1593,101 +1535,6 @@ class ArmCustomFunctionField: public TransformedField { unsigned int _mode; }; -class AvrCustomFunctionField: public TransformedField { - public: - AvrCustomFunctionField(DataField * parent, CustomFunctionData & fn, Board::Type board, unsigned int version, unsigned int variant): - TransformedField(parent, internalField), - internalField(this, "CustomFunction"), - fn(fn), - board(board), - version(version), - variant(variant), - functionsConversionTable(board, version), - sourcesConversionTable(SourcesConversionTable::getInstance(board, version, variant, 0)), - _param(0), - _mode(0), - _union_param(0), - _active(0) - { - internalField.Append(new SwitchField<6>(this, fn.swtch, board, version)); - internalField.Append(new ConversionField< UnsignedField<4> >(this, (unsigned int &)fn.func, &functionsConversionTable, "Function", DataField::tr("OpenTX on this board doesn't accept this function"))); - internalField.Append(new UnsignedField<5>(this, _union_param)); - internalField.Append(new UnsignedField<1>(this, _active)); - internalField.Append(new UnsignedField<8>(this, _param)); - } - - virtual void beforeExport() - { - _param = fn.param; - _active = (fn.enabled ? 1 : 0); - - if (fn.func >= FuncOverrideCH1 && fn.func <= FuncOverrideCH32) { - _union_param = fn.func - FuncOverrideCH1; - } - else if (fn.func >= FuncTrainer && fn.func <= FuncTrainerAIL) { - _union_param = fn.func - FuncTrainer; - } - else if (fn.func >= FuncAdjustGV1 && fn.func <= FuncAdjustGVLast) { - _union_param = fn.adjustMode; - _union_param += (fn.func - FuncAdjustGV1) << 2; - if (fn.adjustMode == 1) - sourcesConversionTable->exportValue(fn.param, (int &)_param); - else if (fn.adjustMode == 2) - _param = RawSource(fn.param).index; - } - else if (fn.func == FuncPlayValue) { - _union_param = fn.repeatParam / 10; - sourcesConversionTable->exportValue(fn.param, (int &)_param); - } - else if (fn.func == FuncPlaySound || fn.func == FuncPlayPrompt || fn.func == FuncPlayBoth) { - _union_param = fn.repeatParam / 10; - } - } - - virtual void afterImport() - { - fn.param = _param; - fn.enabled = (_active & 0x01); - - if (fn.func >= FuncOverrideCH1 && fn.func <= FuncOverrideCH32) { - fn.func = AssignFunc(fn.func + _union_param); - fn.param = (int8_t)fn.param; - } - else if (fn.func >= FuncTrainer && fn.func <= FuncTrainerAIL) { - fn.func = AssignFunc(fn.func + _union_param); - } - else if (fn.func >= FuncAdjustGV1 && fn.func <= FuncAdjustGVLast) { - fn.func = AssignFunc(fn.func + (_union_param >> 2)); - fn.adjustMode = (_union_param & 0x03); - if (fn.adjustMode == 1) - sourcesConversionTable->importValue(_param, (int &)fn.param); - else if (fn.adjustMode == 2) - fn.param = RawSource(SOURCE_TYPE_GVAR, _param).toValue(); - } - else if (fn.func == FuncPlayValue) { - fn.repeatParam = _union_param * 10; - sourcesConversionTable->importValue(_param, (int &)fn.param); - } - else if (fn.func == FuncPlaySound || fn.func == FuncPlayPrompt || fn.func == FuncPlayBoth) { - fn.repeatParam = _union_param * 10; - } - qCDebug(eepromImport) << QString("imported %1").arg(internalField.getName()); - } - - protected: - StructField internalField; - CustomFunctionData & fn; - Board::Type board; - unsigned int version; - unsigned int variant; - CustomFunctionsConversionTable functionsConversionTable; - SourcesConversionTable * sourcesConversionTable; - unsigned int _param; - unsigned int _mode; - unsigned int _union_param; - unsigned int _active; -}; - class FrskyScreenField: public DataField { public: FrskyScreenField(DataField * parent, FrSkyScreenData & screen, Board::Type board, unsigned int version, unsigned int variant): @@ -2304,6 +2151,10 @@ OpenTxModelData::OpenTxModelData(ModelData & modelData, Board::Type board, unsig internalField.Append(new FrskyScreenField(this, modelData.frsky.screens[i], board, version, variant)); } } + + if (version >= 219) { + internalField.Append(new ZCharField<8>(this, modelData.registrationId, "ACCESS Registration ID")); + } } void OpenTxModelData::beforeExport() @@ -2371,7 +2222,7 @@ void OpenTxModelData::afterImport() } else if (modelData.moduleData[module].protocol == PULSES_MULTIMODULE) { // Copy data from ppm struct to multi struct - unsigned int multiByte = (unsigned int)((modelData.moduleData[module].ppm.delay - 300) / 50); + auto multiByte = (unsigned int)((modelData.moduleData[module].ppm.delay - 300) / 50); modelData.moduleData[module].multi.rfProtocol = (subprotocols[module] & 0x0f) | ((multiByte & 0x3) << 4); modelData.moduleData[module].multi.customProto = (multiByte & 0x80) == 0x80; modelData.moduleData[module].multi.optionValue = modelData.moduleData[module].ppm.frameLength; @@ -2382,7 +2233,7 @@ void OpenTxModelData::afterImport() if ((modelData.moduleData[module].protocol >= PULSES_PXX_XJT_X16 && modelData.moduleData[module].protocol <= PULSES_PXX_XJT_LR12) || modelData.moduleData[module].protocol == PULSES_PXX_R9M) { // Do the same for pxx - unsigned int pxxByte = (unsigned int)((modelData.moduleData[module].ppm.delay - 300) / 50); + auto pxxByte = (unsigned int)((modelData.moduleData[module].ppm.delay - 300) / 50); modelData.moduleData[module].pxx.power = pxxByte & 0x03; modelData.moduleData[module].pxx.receiver_telem_off = static_cast(pxxByte & (1 << 4)); modelData.moduleData[module].pxx.receiver_channel_9_16 = static_cast(pxxByte & (1 << 5)); @@ -2405,7 +2256,7 @@ void OpenTxModelData::afterImport() } OpenTxGeneralData::OpenTxGeneralData(GeneralSettings & generalData, Board::Type board, unsigned int version, unsigned int variant): - TransformedField(NULL, internalField), + TransformedField(nullptr, internalField), internalField(this, "General Settings"), generalData(generalData), board(board), From d598533faf7047f4194f3716acba803607b63e4f Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Mon, 24 Jun 2019 13:16:16 +0200 Subject: [PATCH 086/350] Cosmetics --- radio/src/gui/212x64/radio_diagkeys.cpp | 32 +++++++++++-------------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/radio/src/gui/212x64/radio_diagkeys.cpp b/radio/src/gui/212x64/radio_diagkeys.cpp index 3ea5eb862..7a9f42499 100644 --- a/radio/src/gui/212x64/radio_diagkeys.cpp +++ b/radio/src/gui/212x64/radio_diagkeys.cpp @@ -32,31 +32,27 @@ void menuRadioDiagKeys(event_t event) lcdDrawText(24*FW, MENU_HEADER_HEIGHT + 1, STR_VTRIM); - for (uint8_t i=0; i Date: Mon, 24 Jun 2019 16:01:51 +0200 Subject: [PATCH 087/350] Add 'auto' to R9M 1W setting --- radio/src/translations/untranslated.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/radio/src/translations/untranslated.h b/radio/src/translations/untranslated.h index 10a0209d3..f3fe8c19a 100644 --- a/radio/src/translations/untranslated.h +++ b/radio/src/translations/untranslated.h @@ -117,8 +117,8 @@ #define LEN_R9M_LITE_LBT_POWER_VALUES "\015" #define TR_R9M_LITE_LBT_POWER_VALUES "25 mW 8ch\0 ""25 mW 16ch\0 ""100mW no tele" -#define LEN_R9M_FCC_POWER_VALUES "\006" -#define TR_R9M_FCC_POWER_VALUES "10 mW\0" "100 mW" "500 mW" "1 W\0" +#define LEN_R9M_FCC_POWER_VALUES "\012" +#define TR_R9M_FCC_POWER_VALUES "10 mW \0" "100 mW \0" "500 mW \0" "1 W (auto)" #define LEN_R9M_LBT_POWER_VALUES "\013" #define TR_R9M_LBT_POWER_VALUES "25 mW 8ch\0 ""25 mW 16ch\0" "200 mW 16ch" "500 mW 16ch" From 6f9ece1034798804f81cf19ed630d7dd031bdb2a Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Mon, 24 Jun 2019 21:44:17 +0200 Subject: [PATCH 088/350] Update CREDITS.txt --- CREDITS.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CREDITS.txt b/CREDITS.txt index 81d4f33e8..ed1e6446f 100644 --- a/CREDITS.txt +++ b/CREDITS.txt @@ -1518,3 +1518,6 @@ Michel Garbarino For Our Better World Lothar Herrl James Rhodes +Edward Glover +James Snodgrass +Dwayne Carden From b5cfa0b5be7d9a04ecabafac123404ea67cbcd69 Mon Sep 17 00:00:00 2001 From: 3djc Date: Tue, 25 Jun 2019 08:25:45 +0200 Subject: [PATCH 089/350] Cosmetics --- radio/src/translations/untranslated.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radio/src/translations/untranslated.h b/radio/src/translations/untranslated.h index f3fe8c19a..623f6b9c4 100644 --- a/radio/src/translations/untranslated.h +++ b/radio/src/translations/untranslated.h @@ -118,7 +118,7 @@ #define TR_R9M_LITE_LBT_POWER_VALUES "25 mW 8ch\0 ""25 mW 16ch\0 ""100mW no tele" #define LEN_R9M_FCC_POWER_VALUES "\012" -#define TR_R9M_FCC_POWER_VALUES "10 mW \0" "100 mW \0" "500 mW \0" "1 W (auto)" +#define TR_R9M_FCC_POWER_VALUES "10 mW\0 " "100 mW\0 " "500 mW\0 " "1 W (auto)" #define LEN_R9M_LBT_POWER_VALUES "\013" #define TR_R9M_LBT_POWER_VALUES "25 mW 8ch\0 ""25 mW 16ch\0" "200 mW 16ch" "500 mW 16ch" From f9ab0ee9addf8f92bddea28304e4107ce5458166 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Tue, 25 Jun 2019 11:26:08 +0200 Subject: [PATCH 090/350] Hardening --- .../common/stdlcd/model_module_options.cpp | 2 +- radio/src/pulses/modules_helpers.h | 20 +++++++++++++++++-- radio/src/pulses/pxx2.h | 7 ++++--- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/radio/src/gui/common/stdlcd/model_module_options.cpp b/radio/src/gui/common/stdlcd/model_module_options.cpp index a33a29b98..ad3701618 100644 --- a/radio/src/gui/common/stdlcd/model_module_options.cpp +++ b/radio/src/gui/common/stdlcd/model_module_options.cpp @@ -87,7 +87,7 @@ void menuModelModuleOptions(event_t event) uint8_t modelId = reusableBuffer.hardwareAndSettings.modules[g_moduleIdx].information.modelID; // uint8_t variant = reusableBuffer.hardwareAndSettings.modules[g_moduleIdx].information.variant; - uint8_t optionsAvailable = moduleOptions[modelId] & ((1 << MODULE_OPTION_EXTERNAL_ANTENNA) | (1 << MODULE_OPTION_POWER)); + uint8_t optionsAvailable = getModuleOptions(modelId) & ((1 << MODULE_OPTION_EXTERNAL_ANTENNA) | (1 << MODULE_OPTION_POWER)); SUBMENU_NOTITLE(ITEM_MODULE_SETTINGS_COUNT, { !optionsAvailable ? (uint8_t)0 : IF_MODULE_OPTIONS(MODULE_OPTION_EXTERNAL_ANTENNA, 0), diff --git a/radio/src/pulses/modules_helpers.h b/radio/src/pulses/modules_helpers.h index 6b9affe8c..efda11518 100644 --- a/radio/src/pulses/modules_helpers.h +++ b/radio/src/pulses/modules_helpers.h @@ -242,7 +242,7 @@ static const uint8_t moduleOptions[] = { #if defined(SIMU) 0b11111111, // None = display all options on SIMU #else - 0b00000000, // None = display all options on SIMU + 0b00000000, // None = no option available on unknown modules #endif 0b11110001, // XJT 0b11110001, // ISRM @@ -254,9 +254,17 @@ static const uint8_t moduleOptions[] = { 0b11110100, // ISRM-N }; +inline uint8_t getModuleOptions(uint8_t modelId) +{ + if (modelId < DIM(moduleOptions)) + return moduleOptions[modelId]; + else + return moduleOptions[0]; +} + inline bool isModuleOptionAvailable(uint8_t modelId, uint8_t option) { - return moduleOptions[modelId] & (1 << option); + return getModuleOptions(modelId) & (1 << option); } enum { @@ -300,6 +308,14 @@ static const uint8_t receiverOptions[] = { 0b11111111, // R9-MM+OTA }; +inline uint8_t getReceiverOptions(uint8_t modelId) +{ + if (modelId < DIM(receiverOptions)) + return receiverOptions[modelId]; + else + return receiverOptions[0]; +} + inline bool isReceiverOptionAvailable(uint8_t modelId, uint8_t option) { return receiverOptions[modelId] & (1 << option); diff --git a/radio/src/pulses/pxx2.h b/radio/src/pulses/pxx2.h index 41d53cce0..fccb6096f 100644 --- a/radio/src/pulses/pxx2.h +++ b/radio/src/pulses/pxx2.h @@ -102,12 +102,13 @@ static const char * const PXX2receiversModels[] = { enum PXX2ModuleModelID { PXX2_MODULE_NONE, PXX2_MODULE_XJT, - PXX2_MODULE_IXJT, - PXX2_MODULE_IXJT_PRO, - PXX2_MODULE_IXJT_S, + PXX2_MODULE_ISRM, + PXX2_MODULE_ISRM_PRO, + PXX2_MODULE_ISRM_S, PXX2_MODULE_R9M, PXX2_MODULE_R9M_LITE, PXX2_MODULE_R9M_LITE_PRO, + PXX2_MODULE_ISRM_N }; enum PXX2Variant { From 4560d8de42fe19992b04b62fce166d4898994bc4 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Tue, 25 Jun 2019 11:30:52 +0200 Subject: [PATCH 091/350] Compilation fix --- radio/src/definitions.h | 3 +++ radio/src/opentx.h | 3 --- radio/src/pulses/modules_helpers.h | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/radio/src/definitions.h b/radio/src/definitions.h index 8b5f5391e..8399656a6 100644 --- a/radio/src/definitions.h +++ b/radio/src/definitions.h @@ -67,4 +67,7 @@ #define CONVERT_UINT_PTR(x) ((uint32_t *)(x)) #endif +// returns the number of elements of an array +#define DIM(arr) (sizeof((arr)) / sizeof((arr)[0])) + #endif // _DEFINITIONS_H_ diff --git a/radio/src/opentx.h b/radio/src/opentx.h index e36d5f6a0..99243c1d8 100644 --- a/radio/src/opentx.h +++ b/radio/src/opentx.h @@ -634,9 +634,6 @@ void doLoopCommonActions(); #define BITMASK(bit) (1<<(bit)) -/// returns the number of elements of an array -#define DIM(arr) (sizeof((arr))/sizeof((arr)[0])) - template inline t min(t a, t b) { return a inline t max(t a, t b) { return a>b?a:b; } template inline t sgn(t a) { return a>0 ? 1 : (a < 0 ? -1 : 0); } diff --git a/radio/src/pulses/modules_helpers.h b/radio/src/pulses/modules_helpers.h index efda11518..b6c346203 100644 --- a/radio/src/pulses/modules_helpers.h +++ b/radio/src/pulses/modules_helpers.h @@ -22,6 +22,7 @@ #define _MODULES_H_ #include "bitfield.h" +#include "definitions.h" #define CROSSFIRE_CHANNELS_COUNT 16 From da226278dfaca0c5993b2ca467f01a5cdc64797e Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Tue, 25 Jun 2019 14:01:17 +0200 Subject: [PATCH 092/350] Compilation fix --- radio/src/definitions.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/radio/src/definitions.h b/radio/src/definitions.h index 8399656a6..4a7244faa 100644 --- a/radio/src/definitions.h +++ b/radio/src/definitions.h @@ -67,7 +67,8 @@ #define CONVERT_UINT_PTR(x) ((uint32_t *)(x)) #endif -// returns the number of elements of an array -#define DIM(arr) (sizeof((arr)) / sizeof((arr)[0])) +#if !defined(DIM) + #define DIM(__arr) (sizeof((__arr)) / sizeof((__arr)[0])) +#endif #endif // _DEFINITIONS_H_ From 2b61d609ba397948a2a6250e095ac5086c2b6433 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Tue, 25 Jun 2019 14:11:12 +0200 Subject: [PATCH 093/350] Backlight didn't work with simu --- radio/src/targets/simu/simpgmspace.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/radio/src/targets/simu/simpgmspace.cpp b/radio/src/targets/simu/simpgmspace.cpp index db52fb40d..0c1160df5 100644 --- a/radio/src/targets/simu/simpgmspace.cpp +++ b/radio/src/targets/simu/simpgmspace.cpp @@ -463,14 +463,18 @@ void pwrInit() void readKeysAndTrims() { uint8_t index = 0; - uint32_t in = readKeys(); + uint32_t keys_input = readKeys(); for (uint8_t i = 1; i != uint8_t(1 << TRM_BASE); i <<= 1) { - keys[index++].input(in & i); + keys[index++].input(keys_input & i); } - in = readTrims(); + uint32_t trims_input = readTrims(); for (uint8_t i = 1; i != uint8_t(1 << 8); i <<= 1) { - keys[index++].input(in & i); + keys[index++].input(trims_input & i); + } + + if (keys_input || trims_input) { + backlightOn(); } } From 03a0ebd9f7fe353e65ec2b660ffc8c43fd369f4d Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Tue, 25 Jun 2019 15:18:12 +0200 Subject: [PATCH 094/350] Some more assert to break the simu a little bit more in case of array overflow --- radio/src/simu.cpp | 8 ++++---- radio/src/targets/simu/simpgmspace.cpp | 7 ++++++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/radio/src/simu.cpp b/radio/src/simu.cpp index df566bbea..eb8681e39 100644 --- a/radio/src/simu.cpp +++ b/radio/src/simu.cpp @@ -232,7 +232,7 @@ void OpenTxSim::doEvents() long OpenTxSim::onKeypress(FXObject *, FXSelector, void * v) { - FXEvent *evt = (FXEvent *)v; + auto * evt = (FXEvent *)v; // TRACE("keypress %x", evt->code); @@ -245,7 +245,7 @@ long OpenTxSim::onKeypress(FXObject *, FXSelector, void * v) void OpenTxSim::updateKeysAndSwitches(bool start) { - static int keys1[] = { + static int keys[] = { #if defined(PCBHORUS) KEY_Page_Up, KEY_PGUP, KEY_Page_Down, KEY_PGDN, @@ -283,8 +283,8 @@ void OpenTxSim::updateKeysAndSwitches(bool start) #endif }; - for (unsigned int i=0; igetKeyState(keys1[i])); + for (unsigned int i=0; igetKeyState(keys[i])); } #ifdef __APPLE__ diff --git a/radio/src/targets/simu/simpgmspace.cpp b/radio/src/targets/simu/simpgmspace.cpp index 0c1160df5..c0d344bd7 100644 --- a/radio/src/targets/simu/simpgmspace.cpp +++ b/radio/src/targets/simu/simpgmspace.cpp @@ -142,12 +142,16 @@ void simuInit() bool keysStates[NUM_KEYS] = { false }; void simuSetKey(uint8_t key, bool state) { + // TRACE("simuSetKey(%d, %d)", key, state); + assert(key < DIM(keysStates)); keysStates[key] = state; } -bool trimsStates[NUM_TRIMS*2] = { false }; +bool trimsStates[NUM_TRIMS * 2] = { false }; void simuSetTrim(uint8_t trim, bool state) { + // TRACE("simuSetTrim(%d, %d)", trim, state); + assert(trim < DIM(trimsStates)); trimsStates[trim] = state; } @@ -155,6 +159,7 @@ int8_t switchesStates[NUM_SWITCHES] = { -1 }; void simuSetSwitch(uint8_t swtch, int8_t state) { // TRACE("simuSetSwitch(%d, %d)", swtch, state); + assert(swtch < DIM(switchesStates)); switchesStates[swtch] = state; } From efde2af17b660d28e59acda7ea3e3a9cf3581853 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Tue, 25 Jun 2019 15:20:00 +0200 Subject: [PATCH 095/350] Array overflow fix --- radio/src/simu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radio/src/simu.cpp b/radio/src/simu.cpp index eb8681e39..19b822b26 100644 --- a/radio/src/simu.cpp +++ b/radio/src/simu.cpp @@ -296,7 +296,7 @@ void OpenTxSim::updateKeysAndSwitches(bool start) static FXuint trimKeys[] = { KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12 }; #endif - for (unsigned i=0; igetKeyState(trimKeys[i])); } From e41fe19a3d0f64f1bdd2f2cf7b3ada48ffca6a95 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Wed, 26 Jun 2019 08:47:11 +0200 Subject: [PATCH 096/350] ACCESS Bind with RX > 0 was broken --- radio/src/pulses/pxx2.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radio/src/pulses/pxx2.cpp b/radio/src/pulses/pxx2.cpp index 984f7c0b4..0fc7a137d 100644 --- a/radio/src/pulses/pxx2.cpp +++ b/radio/src/pulses/pxx2.cpp @@ -268,7 +268,7 @@ void Pxx2Pulses::setupAccessBindFrame(uint8_t module) Pxx2Transport::addByte((destination->lbtMode << 6) + (destination->flexMode << 4) + destination->rxUid); // RX_UID is the slot index (which is unique and never moved) } else { - Pxx2Transport::addByte(0x00); + Pxx2Transport::addByte(destination->rxUid); // RX_UID is the slot index (which is unique and never moved) } Pxx2Transport::addByte(g_model.header.modelId[module]); } From 27f4f1bba6a1900a0e8dedc7024d07dda84b421e Mon Sep 17 00:00:00 2001 From: Kilrah Date: Wed, 26 Jun 2019 19:22:20 +0200 Subject: [PATCH 097/350] Memory allocated for conversions was not freed on all radios using it --- radio/src/storage/conversions/conversions_218_219.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radio/src/storage/conversions/conversions_218_219.cpp b/radio/src/storage/conversions/conversions_218_219.cpp index 0059c0b15..7376ee0cc 100644 --- a/radio/src/storage/conversions/conversions_218_219.cpp +++ b/radio/src/storage/conversions/conversions_218_219.cpp @@ -270,7 +270,7 @@ void convertModelData_218_to_219(ModelData &model) } #endif -#if defined(PCBHORUS) +#if defined(STM32) free(oldModelAllocated); #endif } From cfaea439dac728bc679f1e22919012fc30315472 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Wed, 26 Jun 2019 23:38:40 +0200 Subject: [PATCH 098/350] EEPROM shift which prevented the Model registration ID from being imported / exported with Companion --- companion/src/firmwares/opentx/opentxeeprom.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/companion/src/firmwares/opentx/opentxeeprom.cpp b/companion/src/firmwares/opentx/opentxeeprom.cpp index 04d6dde18..eeea646a1 100644 --- a/companion/src/firmwares/opentx/opentxeeprom.cpp +++ b/companion/src/firmwares/opentx/opentxeeprom.cpp @@ -2150,6 +2150,7 @@ OpenTxModelData::OpenTxModelData(ModelData & modelData, Board::Type board, unsig for (int i = 0; i < 4; i++) { internalField.Append(new FrskyScreenField(this, modelData.frsky.screens[i], board, version, variant)); } + internalField.Append(new SpareBitsField<8>(this)); // current view } if (version >= 219) { From d1c5217d243d14beba9840f678947b1dda952dfc Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Thu, 27 Jun 2019 10:57:30 +0200 Subject: [PATCH 099/350] Unused file removed --- radio/src/gui/212x64/model_module_options.cpp | 21 ------------------- 1 file changed, 21 deletions(-) delete mode 100644 radio/src/gui/212x64/model_module_options.cpp diff --git a/radio/src/gui/212x64/model_module_options.cpp b/radio/src/gui/212x64/model_module_options.cpp deleted file mode 100644 index f72d3594f..000000000 --- a/radio/src/gui/212x64/model_module_options.cpp +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (C) OpenTX - * - * Based on code named - * th9x - http://code.google.com/p/th9x - * er9x - http://code.google.com/p/er9x - * gruvin9x - http://code.google.com/p/gruvin9x - * - * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include From f106414bd8891e6dac9615c7b5f243b2193a3660 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Thu, 27 Jun 2019 10:57:46 +0200 Subject: [PATCH 100/350] Unused file removed --- .../src/gui/212x64/model_receiver_options.cpp | 21 ------------------- 1 file changed, 21 deletions(-) delete mode 100644 radio/src/gui/212x64/model_receiver_options.cpp diff --git a/radio/src/gui/212x64/model_receiver_options.cpp b/radio/src/gui/212x64/model_receiver_options.cpp deleted file mode 100644 index f72d3594f..000000000 --- a/radio/src/gui/212x64/model_receiver_options.cpp +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (C) OpenTX - * - * Based on code named - * th9x - http://code.google.com/p/th9x - * er9x - http://code.google.com/p/er9x - * gruvin9x - http://code.google.com/p/gruvin9x - * - * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include From 2f394d1b6ea6134edb8552936e2eeffe4bb185db Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Thu, 27 Jun 2019 13:22:11 +0200 Subject: [PATCH 101/350] Small switches refactoring --- radio/src/dataconstants.h | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/radio/src/dataconstants.h b/radio/src/dataconstants.h index 012fcc799..936aa399c 100644 --- a/radio/src/dataconstants.h +++ b/radio/src/dataconstants.h @@ -680,34 +680,43 @@ enum MixSources { MIXSRC_FIRST_SWITCH, -#if defined(PCBHORUS) || defined(PCBTARANIS) +#if defined(HARDWARE_SWITCH_A) MIXSRC_SA = MIXSRC_FIRST_SWITCH, LUA_EXPORT("sa", "Switch A") MIXSRC_SB, LUA_EXPORT("sb", "Switch B") MIXSRC_SC, LUA_EXPORT("sc", "Switch C") MIXSRC_SD, LUA_EXPORT("sd", "Switch D") #endif -#if defined(PCBHORUS) || defined(PCBX9) || defined(PCBXLITES) +#if defined(HARDWARE_SWITCH_E) MIXSRC_SE, LUA_EXPORT("se", "Switch E") +#elif defined(STORAGE_SWITCH_E) + MIXSRC_SE, #endif -#if defined(PCBHORUS) || defined(PCBX9D) || defined(PCBX9DP) || defined(PCBX9E) || defined(PCBX7) || defined(PCBXLITES) +#if defined(HARDWARE_SWITCH_F) MIXSRC_SF, LUA_EXPORT("sf", "Switch F") +#elif defined(STORAGE_SWITCH_F) + MIXSRC_SF, #endif -#if defined(PCBHORUS) || defined(PCBX9D) || defined(PCBX9DP) || defined(PCBX9E) +#if defined(HARDWARE_SWITCH_G) MIXSRC_SG, LUA_EXPORT("sg", "Switch G") +#elif defined(STORAGE_SWITCH_G) + MIXSRC_SG, #endif -#if defined(PCBHORUS) || defined(PCBX9D) || defined(PCBX9DP) || defined(PCBX9E) || defined(PCBX7) +#if defined(HARDWARE_SWITCH_H) MIXSRC_SH, LUA_EXPORT("sh", "Switch H") +#elif defined(STORAGE_SWITCH_H) + MIXSRC_SH, #endif -#if defined(RADIO_X7) +#if defined(HARDWARE_SWITCH_I) MIXSRC_SI, LUA_EXPORT("si", "Switch I") - MIXSRC_SJ, LUA_EXPORT("sj", "Switch J") -#elif defined(RADIO_T12) // keep switches for eeprom compatibity, but hide them +#elif defined(STORAGE_SWITCH_I) MIXSRC_SI, +#endif +#if defined(HARDWARE_SWITCH_J) + MIXSRC_SJ, LUA_EXPORT("sj", "Switch J") +#elif defined(STORAGE_SWITCH_J) MIXSRC_SJ, #endif -#if defined(PCBX9E) - MIXSRC_SI, LUA_EXPORT("si", "Switch I") - MIXSRC_SJ, LUA_EXPORT("sj", "Switch J") +#if defined(HARDWARE_SWITCH_K) MIXSRC_SK, LUA_EXPORT("sk", "Switch K") MIXSRC_SL, LUA_EXPORT("sl", "Switch L") MIXSRC_SM, LUA_EXPORT("sm", "Switch M") From 7b7ae1a494d34cb97a00634d216c4a0ca5fa8bc3 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Thu, 27 Jun 2019 14:10:05 +0200 Subject: [PATCH 102/350] X9Lite switches fix --- radio/src/dataconstants.h | 6 +++++- radio/src/targets/taranis/hal.h | 16 +++++++--------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/radio/src/dataconstants.h b/radio/src/dataconstants.h index 936aa399c..4f8013582 100644 --- a/radio/src/dataconstants.h +++ b/radio/src/dataconstants.h @@ -684,7 +684,11 @@ enum MixSources { MIXSRC_SA = MIXSRC_FIRST_SWITCH, LUA_EXPORT("sa", "Switch A") MIXSRC_SB, LUA_EXPORT("sb", "Switch B") MIXSRC_SC, LUA_EXPORT("sc", "Switch C") +#endif +#if defined(HARDWARE_SWITCH_D) MIXSRC_SD, LUA_EXPORT("sd", "Switch D") +#elif defined(STORAGE_SWITCH_D) + MIXSRC_SD, #endif #if defined(HARDWARE_SWITCH_E) MIXSRC_SE, LUA_EXPORT("se", "Switch E") @@ -792,7 +796,7 @@ enum MixSources { }; #if defined(__cplusplus) -static_assert(MIXSRC_FIRST_LOGICAL_SWITCH == MIXSRC_FIRST_SWITCH + NUM_SWITCHES, "Wrong switches definition in MIXSRC list"); +static_assert(MIXSRC_FIRST_LOGICAL_SWITCH == MIXSRC_FIRST_SWITCH + STORAGE_NUM_SWITCHES, "Wrong switches definition in MIXSRC list"); #endif #define MIXSRC_FIRST (MIXSRC_NONE + 1) diff --git a/radio/src/targets/taranis/hal.h b/radio/src/targets/taranis/hal.h index 1a7b10bd5..95e9015f6 100644 --- a/radio/src/targets/taranis/hal.h +++ b/radio/src/targets/taranis/hal.h @@ -352,7 +352,10 @@ #define SWITCHES_GPIO_REG_D_H GPIOE->IDR #define SWITCHES_GPIO_PIN_D_H GPIO_Pin_2 // PE.02 #elif defined(PCBX9LITE) - // no SWD + #define STORAGE_SWITCH_D + #define HARDWARE_SWITCH_D + #define SWITCHES_GPIO_REG_D GPIOC->IDR + #define SWITCHES_GPIO_PIN_D GPIO_Pin_13 // PC.13 #else #define STORAGE_SWITCH_D #define HARDWARE_SWITCH_D @@ -377,8 +380,8 @@ #elif defined(PCBX9LITE) #define STORAGE_SWITCH_E #define HARDWARE_SWITCH_E - #define SWITCHES_GPIO_REG_E GPIOC->IDR - #define SWITCHES_GPIO_PIN_E GPIO_Pin_13 // PC.13 + #define SWITCHES_GPIO_REG_E GPIOA->IDR + #define SWITCHES_GPIO_PIN_E GPIO_Pin_5 // PA.05 #elif defined(PCBX7) || defined(PCBXLITE) // no SWE #else @@ -400,18 +403,13 @@ #define HARDWARE_SWITCH_F #define SWITCHES_GPIO_REG_F GPIOC->IDR #define SWITCHES_GPIO_PIN_F GPIO_Pin_3 // PC.03 -#elif defined(PCBXLITE) +#elif defined(PCBXLITE) || defined(PCBX9LITE) // no SWF #elif defined(PCBX7) #define STORAGE_SWITCH_F #define HARDWARE_SWITCH_F #define SWITCHES_GPIO_REG_F GPIOE->IDR #define SWITCHES_GPIO_PIN_F GPIO_Pin_14 // PE.14 -#elif defined(PCBX9LITE) - #define STORAGE_SWITCH_F - #define HARDWARE_SWITCH_F - #define SWITCHES_GPIO_REG_F GPIOA->IDR - #define SWITCHES_GPIO_PIN_F GPIO_Pin_5 // PA.05 #else #define STORAGE_SWITCH_F #define HARDWARE_SWITCH_F From df95e316662648aceefa4c8adccf2771d1073a11 Mon Sep 17 00:00:00 2001 From: 3djc Date: Thu, 27 Jun 2019 14:34:31 +0200 Subject: [PATCH 103/350] Fix T12 switches --- radio/src/storage/conversions/conversions_218_219.cpp | 1 + radio/src/targets/taranis/hal.h | 7 +------ 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/radio/src/storage/conversions/conversions_218_219.cpp b/radio/src/storage/conversions/conversions_218_219.cpp index 7376ee0cc..528938038 100644 --- a/radio/src/storage/conversions/conversions_218_219.cpp +++ b/radio/src/storage/conversions/conversions_218_219.cpp @@ -303,6 +303,7 @@ void convertRadioData_218_to_219(RadioData & settings) #endif #if defined(RADIO_T12) + g_eeGeneral.switchConfig = bfSet(g_eeGeneral.switchConfig, SWITCH_2POS, 10, 2); // T12 comes with wrongly defined pot2 g_eeGeneral.potsConfig = bfSet(g_eeGeneral.potsConfig, POT_WITHOUT_DETENT, 2, 2); // T12 comes with wrongly defined pot2 #endif } diff --git a/radio/src/targets/taranis/hal.h b/radio/src/targets/taranis/hal.h index 95e9015f6..a4d98ec2c 100644 --- a/radio/src/targets/taranis/hal.h +++ b/radio/src/targets/taranis/hal.h @@ -426,12 +426,7 @@ #define SWITCHES_GPIO_PIN_G_L GPIO_Pin_4 // PF.04 #elif defined(RADIO_X7) || defined(PCBXLITE) || defined(PCBX9LITE) // no SWG -#elif defined(RADIO_T12) - #define STORAGE_SWITCH_G - #define HARDWARE_SWITCH_G - #define SWITCHES_GPIO_REG_G GPIOE->IDR - #define SWITCHES_GPIO_PIN_G GPIO_Pin_14 // PE.14 -#else +#elif !defined(RADIO_T12) #define STORAGE_SWITCH_G #define HARDWARE_SWITCH_G #define SWITCHES_GPIO_REG_G_H GPIOE->IDR From 9841b1ed2ce0ff64b6e47b5e4815ed35eae11f8b Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Thu, 27 Jun 2019 14:47:23 +0200 Subject: [PATCH 104/350] Cosmetics --- radio/src/targets/taranis/hal.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/radio/src/targets/taranis/hal.h b/radio/src/targets/taranis/hal.h index a4d98ec2c..c53db54f9 100644 --- a/radio/src/targets/taranis/hal.h +++ b/radio/src/targets/taranis/hal.h @@ -424,9 +424,9 @@ #define SWITCHES_GPIO_PIN_G_H GPIO_Pin_3 // PF.03 #define SWITCHES_GPIO_REG_G_L GPIOF->IDR #define SWITCHES_GPIO_PIN_G_L GPIO_Pin_4 // PF.04 -#elif defined(RADIO_X7) || defined(PCBXLITE) || defined(PCBX9LITE) +#elif defined(PCBX7) || defined(PCBXLITE) || defined(PCBX9LITE) // no SWG -#elif !defined(RADIO_T12) +#else #define STORAGE_SWITCH_G #define HARDWARE_SWITCH_G #define SWITCHES_GPIO_REG_G_H GPIOE->IDR From 87a1afb748faf8a1bae8aa8e3e298913c815799d Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Thu, 27 Jun 2019 22:30:25 +0200 Subject: [PATCH 105/350] Add radio tools to all radio (#6525) Add radio tools to all radio --- .../TOOLS}/CROSSFIRE/crossfire.lua | 1 + .../{ => SCRIPTS/TOOLS}/CROSSFIRE/device.lua | 0 .../SCRIPTS/TOOLS/FrSky GaSuite.lua} | 0 .../SCRIPTS/TOOLS}/FrSky SBEC.lua | 1 - .../SCRIPTS/TOOLS/FrSky SxR.lua} | 0 .../SCRIPTS/TOOLS}/bmp/back.bmp | Bin .../SCRIPTS/TOOLS}/bmp/delta.bmp | Bin .../SCRIPTS/TOOLS}/bmp/done.bmp | Bin .../SCRIPTS/TOOLS}/bmp/down.bmp | Bin .../SCRIPTS/TOOLS}/bmp/forward.bmp | Bin .../SCRIPTS/TOOLS}/bmp/horz-r.bmp | Bin .../SCRIPTS/TOOLS}/bmp/horz.bmp | Bin .../SCRIPTS/TOOLS}/bmp/left.bmp | Bin .../SCRIPTS/TOOLS}/bmp/plane.bmp | Bin .../SCRIPTS/TOOLS}/bmp/right.bmp | Bin .../SCRIPTS/TOOLS}/bmp/up.bmp | Bin .../SCRIPTS/TOOLS}/bmp/vert-r.bmp | Bin .../SCRIPTS/TOOLS}/bmp/vert.bmp | Bin .../SCRIPTS/TOOLS}/bmp/vtail.bmp | Bin .../SCRIPTS/TOOLS}/img/back.png | Bin .../SCRIPTS/TOOLS}/img/delta_b.png | Bin .../SCRIPTS/TOOLS}/img/done.bmp | Bin .../SCRIPTS/TOOLS}/img/down.png | Bin .../SCRIPTS/TOOLS}/img/forward.png | Bin .../SCRIPTS/TOOLS}/img/left.png | Bin .../SCRIPTS/TOOLS}/img/plane_b.png | Bin .../SCRIPTS/TOOLS}/img/planev_b.png | Bin .../SCRIPTS/TOOLS}/img/planev_s.png | Bin .../SCRIPTS/TOOLS}/img/right.png | Bin .../SCRIPTS/TOOLS}/img/up.png | Bin .../SCRIPTS/TOOLS}/img/vert-r.png | Bin .../SCRIPTS/TOOLS}/img/vert.png | Bin .../taranis-x7/SCRIPTS/TOOLS/readme.txt | 1 + .../TOOLS}/CROSSFIRE/crossfire.lua | 1 + .../{ => SCRIPTS/TOOLS}/CROSSFIRE/device.lua | 0 .../SCRIPTS/TOOLS/FrSky GaSuite.lua | 515 ++++++++++++++++++ .../taranis-x9/SCRIPTS/TOOLS/FrSky SBEC.lua | 289 ++++++++++ .../taranis-x9/SCRIPTS/TOOLS/FrSky SxR.lua | 363 ++++++++++++ .../taranis-x9/SCRIPTS/TOOLS/bmp/back.bmp | Bin 0 -> 1144 bytes .../taranis-x9/SCRIPTS/TOOLS/bmp/delta.bmp | Bin 0 -> 1144 bytes .../taranis-x9/SCRIPTS/TOOLS/bmp/done.bmp | Bin 0 -> 1142 bytes .../taranis-x9/SCRIPTS/TOOLS/bmp/down.bmp | Bin 0 -> 1144 bytes .../taranis-x9/SCRIPTS/TOOLS/bmp/forward.bmp | Bin 0 -> 1144 bytes .../taranis-x9/SCRIPTS/TOOLS/bmp/horz-r.bmp | Bin 0 -> 1144 bytes .../taranis-x9/SCRIPTS/TOOLS/bmp/horz.bmp | Bin 0 -> 1144 bytes .../taranis-x9/SCRIPTS/TOOLS/bmp/left.bmp | Bin 0 -> 1144 bytes .../taranis-x9/SCRIPTS/TOOLS/bmp/plane.bmp | Bin 0 -> 1144 bytes .../taranis-x9/SCRIPTS/TOOLS/bmp/right.bmp | Bin 0 -> 1144 bytes .../taranis-x9/SCRIPTS/TOOLS/bmp/up.bmp | Bin 0 -> 1144 bytes .../taranis-x9/SCRIPTS/TOOLS/bmp/vert-r.bmp | Bin 0 -> 1144 bytes .../taranis-x9/SCRIPTS/TOOLS/bmp/vert.bmp | Bin 0 -> 1144 bytes .../taranis-x9/SCRIPTS/TOOLS/bmp/vtail.bmp | Bin 0 -> 1144 bytes .../taranis-x9/SCRIPTS/TOOLS/img/back.png | Bin 0 -> 9229 bytes .../taranis-x9/SCRIPTS/TOOLS/img/delta_b.png | Bin 0 -> 9102 bytes .../taranis-x9/SCRIPTS/TOOLS/img/done.bmp | Bin 0 -> 1142 bytes .../taranis-x9/SCRIPTS/TOOLS/img/down.png | Bin 0 -> 7866 bytes .../taranis-x9/SCRIPTS/TOOLS/img/forward.png | Bin 0 -> 10493 bytes .../taranis-x9/SCRIPTS/TOOLS/img/left.png | Bin 0 -> 11410 bytes .../taranis-x9/SCRIPTS/TOOLS/img/plane_b.png | Bin 0 -> 12743 bytes .../taranis-x9/SCRIPTS/TOOLS/img/planev_b.png | Bin 0 -> 13467 bytes .../taranis-x9/SCRIPTS/TOOLS/img/planev_s.png | Bin 0 -> 4393 bytes .../taranis-x9/SCRIPTS/TOOLS/img/right.png | Bin 0 -> 10388 bytes .../taranis-x9/SCRIPTS/TOOLS/img/up.png | Bin 0 -> 10799 bytes .../taranis-x9/SCRIPTS/TOOLS/img/vert-r.png | Bin 0 -> 6813 bytes .../taranis-x9/SCRIPTS/TOOLS/img/vert.png | Bin 0 -> 10493 bytes .../taranis-x9/SCRIPTS/TOOLS/readme.txt | 1 + radio/src/gui/128x64/menus.h | 4 - radio/src/gui/212x64/menu_radio.cpp | 2 - radio/src/gui/212x64/menus.h | 2 - radio/src/gui/common/stdlcd/CMakeLists.txt | 2 +- radio/src/gui/common/stdlcd/radio_tools.cpp | 18 +- 71 files changed, 1183 insertions(+), 17 deletions(-) rename radio/sdcard/taranis-x7/{ => SCRIPTS/TOOLS}/CROSSFIRE/crossfire.lua (98%) rename radio/sdcard/taranis-x7/{ => SCRIPTS/TOOLS}/CROSSFIRE/device.lua (100%) rename radio/sdcard/{FrSky-utilities/GasSuit-config.lua => taranis-x7/SCRIPTS/TOOLS/FrSky GaSuite.lua} (100%) rename radio/sdcard/{FrSky-utilities => taranis-x7/SCRIPTS/TOOLS}/FrSky SBEC.lua (99%) rename radio/sdcard/{FrSky-utilities/SxR-config.lua => taranis-x7/SCRIPTS/TOOLS/FrSky SxR.lua} (100%) rename radio/sdcard/{FrSky-utilities => taranis-x7/SCRIPTS/TOOLS}/bmp/back.bmp (100%) rename radio/sdcard/{FrSky-utilities => taranis-x7/SCRIPTS/TOOLS}/bmp/delta.bmp (100%) rename radio/sdcard/{FrSky-utilities => taranis-x7/SCRIPTS/TOOLS}/bmp/done.bmp (100%) rename radio/sdcard/{FrSky-utilities => taranis-x7/SCRIPTS/TOOLS}/bmp/down.bmp (100%) rename radio/sdcard/{FrSky-utilities => taranis-x7/SCRIPTS/TOOLS}/bmp/forward.bmp (100%) rename radio/sdcard/{FrSky-utilities => taranis-x7/SCRIPTS/TOOLS}/bmp/horz-r.bmp (100%) rename radio/sdcard/{FrSky-utilities => taranis-x7/SCRIPTS/TOOLS}/bmp/horz.bmp (100%) rename radio/sdcard/{FrSky-utilities => taranis-x7/SCRIPTS/TOOLS}/bmp/left.bmp (100%) rename radio/sdcard/{FrSky-utilities => taranis-x7/SCRIPTS/TOOLS}/bmp/plane.bmp (100%) rename radio/sdcard/{FrSky-utilities => taranis-x7/SCRIPTS/TOOLS}/bmp/right.bmp (100%) rename radio/sdcard/{FrSky-utilities => taranis-x7/SCRIPTS/TOOLS}/bmp/up.bmp (100%) rename radio/sdcard/{FrSky-utilities => taranis-x7/SCRIPTS/TOOLS}/bmp/vert-r.bmp (100%) rename radio/sdcard/{FrSky-utilities => taranis-x7/SCRIPTS/TOOLS}/bmp/vert.bmp (100%) rename radio/sdcard/{FrSky-utilities => taranis-x7/SCRIPTS/TOOLS}/bmp/vtail.bmp (100%) rename radio/sdcard/{FrSky-utilities => taranis-x7/SCRIPTS/TOOLS}/img/back.png (100%) rename radio/sdcard/{FrSky-utilities => taranis-x7/SCRIPTS/TOOLS}/img/delta_b.png (100%) rename radio/sdcard/{FrSky-utilities => taranis-x7/SCRIPTS/TOOLS}/img/done.bmp (100%) rename radio/sdcard/{FrSky-utilities => taranis-x7/SCRIPTS/TOOLS}/img/down.png (100%) rename radio/sdcard/{FrSky-utilities => taranis-x7/SCRIPTS/TOOLS}/img/forward.png (100%) rename radio/sdcard/{FrSky-utilities => taranis-x7/SCRIPTS/TOOLS}/img/left.png (100%) rename radio/sdcard/{FrSky-utilities => taranis-x7/SCRIPTS/TOOLS}/img/plane_b.png (100%) rename radio/sdcard/{FrSky-utilities => taranis-x7/SCRIPTS/TOOLS}/img/planev_b.png (100%) rename radio/sdcard/{FrSky-utilities => taranis-x7/SCRIPTS/TOOLS}/img/planev_s.png (100%) rename radio/sdcard/{FrSky-utilities => taranis-x7/SCRIPTS/TOOLS}/img/right.png (100%) rename radio/sdcard/{FrSky-utilities => taranis-x7/SCRIPTS/TOOLS}/img/up.png (100%) rename radio/sdcard/{FrSky-utilities => taranis-x7/SCRIPTS/TOOLS}/img/vert-r.png (100%) rename radio/sdcard/{FrSky-utilities => taranis-x7/SCRIPTS/TOOLS}/img/vert.png (100%) create mode 100644 radio/sdcard/taranis-x7/SCRIPTS/TOOLS/readme.txt rename radio/sdcard/taranis-x9/{ => SCRIPTS/TOOLS}/CROSSFIRE/crossfire.lua (98%) rename radio/sdcard/taranis-x9/{ => SCRIPTS/TOOLS}/CROSSFIRE/device.lua (100%) create mode 100755 radio/sdcard/taranis-x9/SCRIPTS/TOOLS/FrSky GaSuite.lua create mode 100644 radio/sdcard/taranis-x9/SCRIPTS/TOOLS/FrSky SBEC.lua create mode 100755 radio/sdcard/taranis-x9/SCRIPTS/TOOLS/FrSky SxR.lua create mode 100644 radio/sdcard/taranis-x9/SCRIPTS/TOOLS/bmp/back.bmp create mode 100644 radio/sdcard/taranis-x9/SCRIPTS/TOOLS/bmp/delta.bmp create mode 100644 radio/sdcard/taranis-x9/SCRIPTS/TOOLS/bmp/done.bmp create mode 100644 radio/sdcard/taranis-x9/SCRIPTS/TOOLS/bmp/down.bmp create mode 100644 radio/sdcard/taranis-x9/SCRIPTS/TOOLS/bmp/forward.bmp create mode 100644 radio/sdcard/taranis-x9/SCRIPTS/TOOLS/bmp/horz-r.bmp create mode 100644 radio/sdcard/taranis-x9/SCRIPTS/TOOLS/bmp/horz.bmp create mode 100644 radio/sdcard/taranis-x9/SCRIPTS/TOOLS/bmp/left.bmp create mode 100644 radio/sdcard/taranis-x9/SCRIPTS/TOOLS/bmp/plane.bmp create mode 100644 radio/sdcard/taranis-x9/SCRIPTS/TOOLS/bmp/right.bmp create mode 100644 radio/sdcard/taranis-x9/SCRIPTS/TOOLS/bmp/up.bmp create mode 100644 radio/sdcard/taranis-x9/SCRIPTS/TOOLS/bmp/vert-r.bmp create mode 100644 radio/sdcard/taranis-x9/SCRIPTS/TOOLS/bmp/vert.bmp create mode 100644 radio/sdcard/taranis-x9/SCRIPTS/TOOLS/bmp/vtail.bmp create mode 100755 radio/sdcard/taranis-x9/SCRIPTS/TOOLS/img/back.png create mode 100755 radio/sdcard/taranis-x9/SCRIPTS/TOOLS/img/delta_b.png create mode 100755 radio/sdcard/taranis-x9/SCRIPTS/TOOLS/img/done.bmp create mode 100755 radio/sdcard/taranis-x9/SCRIPTS/TOOLS/img/down.png create mode 100755 radio/sdcard/taranis-x9/SCRIPTS/TOOLS/img/forward.png create mode 100755 radio/sdcard/taranis-x9/SCRIPTS/TOOLS/img/left.png create mode 100755 radio/sdcard/taranis-x9/SCRIPTS/TOOLS/img/plane_b.png create mode 100755 radio/sdcard/taranis-x9/SCRIPTS/TOOLS/img/planev_b.png create mode 100755 radio/sdcard/taranis-x9/SCRIPTS/TOOLS/img/planev_s.png create mode 100755 radio/sdcard/taranis-x9/SCRIPTS/TOOLS/img/right.png create mode 100755 radio/sdcard/taranis-x9/SCRIPTS/TOOLS/img/up.png create mode 100755 radio/sdcard/taranis-x9/SCRIPTS/TOOLS/img/vert-r.png create mode 100755 radio/sdcard/taranis-x9/SCRIPTS/TOOLS/img/vert.png create mode 100644 radio/sdcard/taranis-x9/SCRIPTS/TOOLS/readme.txt diff --git a/radio/sdcard/taranis-x7/CROSSFIRE/crossfire.lua b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/CROSSFIRE/crossfire.lua similarity index 98% rename from radio/sdcard/taranis-x7/CROSSFIRE/crossfire.lua rename to radio/sdcard/taranis-x7/SCRIPTS/TOOLS/CROSSFIRE/crossfire.lua index 8d409ccad..600ff56d8 100644 --- a/radio/sdcard/taranis-x7/CROSSFIRE/crossfire.lua +++ b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/CROSSFIRE/crossfire.lua @@ -1,3 +1,4 @@ +local toolName = "TNS|Crossfire setup|TNE" ---- ######################################################################### ---- # # ---- # Copyright (C) OpenTX # diff --git a/radio/sdcard/taranis-x7/CROSSFIRE/device.lua b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/CROSSFIRE/device.lua similarity index 100% rename from radio/sdcard/taranis-x7/CROSSFIRE/device.lua rename to radio/sdcard/taranis-x7/SCRIPTS/TOOLS/CROSSFIRE/device.lua diff --git a/radio/sdcard/FrSky-utilities/GasSuit-config.lua b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/FrSky GaSuite.lua similarity index 100% rename from radio/sdcard/FrSky-utilities/GasSuit-config.lua rename to radio/sdcard/taranis-x7/SCRIPTS/TOOLS/FrSky GaSuite.lua diff --git a/radio/sdcard/FrSky-utilities/FrSky SBEC.lua b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/FrSky SBEC.lua similarity index 99% rename from radio/sdcard/FrSky-utilities/FrSky SBEC.lua rename to radio/sdcard/taranis-x7/SCRIPTS/TOOLS/FrSky SBEC.lua index 7bf997f48..1b82bc47f 100644 --- a/radio/sdcard/FrSky-utilities/FrSky SBEC.lua +++ b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/FrSky SBEC.lua @@ -1,4 +1,3 @@ - ---- ######################################################################### ---- # # ---- # Copyright (C) OpenTX # diff --git a/radio/sdcard/FrSky-utilities/SxR-config.lua b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/FrSky SxR.lua similarity index 100% rename from radio/sdcard/FrSky-utilities/SxR-config.lua rename to radio/sdcard/taranis-x7/SCRIPTS/TOOLS/FrSky SxR.lua diff --git a/radio/sdcard/FrSky-utilities/bmp/back.bmp b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/bmp/back.bmp similarity index 100% rename from radio/sdcard/FrSky-utilities/bmp/back.bmp rename to radio/sdcard/taranis-x7/SCRIPTS/TOOLS/bmp/back.bmp diff --git a/radio/sdcard/FrSky-utilities/bmp/delta.bmp b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/bmp/delta.bmp similarity index 100% rename from radio/sdcard/FrSky-utilities/bmp/delta.bmp rename to radio/sdcard/taranis-x7/SCRIPTS/TOOLS/bmp/delta.bmp diff --git a/radio/sdcard/FrSky-utilities/bmp/done.bmp b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/bmp/done.bmp similarity index 100% rename from radio/sdcard/FrSky-utilities/bmp/done.bmp rename to radio/sdcard/taranis-x7/SCRIPTS/TOOLS/bmp/done.bmp diff --git a/radio/sdcard/FrSky-utilities/bmp/down.bmp b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/bmp/down.bmp similarity index 100% rename from radio/sdcard/FrSky-utilities/bmp/down.bmp rename to radio/sdcard/taranis-x7/SCRIPTS/TOOLS/bmp/down.bmp diff --git a/radio/sdcard/FrSky-utilities/bmp/forward.bmp b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/bmp/forward.bmp similarity index 100% rename from radio/sdcard/FrSky-utilities/bmp/forward.bmp rename to radio/sdcard/taranis-x7/SCRIPTS/TOOLS/bmp/forward.bmp diff --git a/radio/sdcard/FrSky-utilities/bmp/horz-r.bmp b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/bmp/horz-r.bmp similarity index 100% rename from radio/sdcard/FrSky-utilities/bmp/horz-r.bmp rename to radio/sdcard/taranis-x7/SCRIPTS/TOOLS/bmp/horz-r.bmp diff --git a/radio/sdcard/FrSky-utilities/bmp/horz.bmp b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/bmp/horz.bmp similarity index 100% rename from radio/sdcard/FrSky-utilities/bmp/horz.bmp rename to radio/sdcard/taranis-x7/SCRIPTS/TOOLS/bmp/horz.bmp diff --git a/radio/sdcard/FrSky-utilities/bmp/left.bmp b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/bmp/left.bmp similarity index 100% rename from radio/sdcard/FrSky-utilities/bmp/left.bmp rename to radio/sdcard/taranis-x7/SCRIPTS/TOOLS/bmp/left.bmp diff --git a/radio/sdcard/FrSky-utilities/bmp/plane.bmp b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/bmp/plane.bmp similarity index 100% rename from radio/sdcard/FrSky-utilities/bmp/plane.bmp rename to radio/sdcard/taranis-x7/SCRIPTS/TOOLS/bmp/plane.bmp diff --git a/radio/sdcard/FrSky-utilities/bmp/right.bmp b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/bmp/right.bmp similarity index 100% rename from radio/sdcard/FrSky-utilities/bmp/right.bmp rename to radio/sdcard/taranis-x7/SCRIPTS/TOOLS/bmp/right.bmp diff --git a/radio/sdcard/FrSky-utilities/bmp/up.bmp b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/bmp/up.bmp similarity index 100% rename from radio/sdcard/FrSky-utilities/bmp/up.bmp rename to radio/sdcard/taranis-x7/SCRIPTS/TOOLS/bmp/up.bmp diff --git a/radio/sdcard/FrSky-utilities/bmp/vert-r.bmp b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/bmp/vert-r.bmp similarity index 100% rename from radio/sdcard/FrSky-utilities/bmp/vert-r.bmp rename to radio/sdcard/taranis-x7/SCRIPTS/TOOLS/bmp/vert-r.bmp diff --git a/radio/sdcard/FrSky-utilities/bmp/vert.bmp b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/bmp/vert.bmp similarity index 100% rename from radio/sdcard/FrSky-utilities/bmp/vert.bmp rename to radio/sdcard/taranis-x7/SCRIPTS/TOOLS/bmp/vert.bmp diff --git a/radio/sdcard/FrSky-utilities/bmp/vtail.bmp b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/bmp/vtail.bmp similarity index 100% rename from radio/sdcard/FrSky-utilities/bmp/vtail.bmp rename to radio/sdcard/taranis-x7/SCRIPTS/TOOLS/bmp/vtail.bmp diff --git a/radio/sdcard/FrSky-utilities/img/back.png b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/img/back.png similarity index 100% rename from radio/sdcard/FrSky-utilities/img/back.png rename to radio/sdcard/taranis-x7/SCRIPTS/TOOLS/img/back.png diff --git a/radio/sdcard/FrSky-utilities/img/delta_b.png b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/img/delta_b.png similarity index 100% rename from radio/sdcard/FrSky-utilities/img/delta_b.png rename to radio/sdcard/taranis-x7/SCRIPTS/TOOLS/img/delta_b.png diff --git a/radio/sdcard/FrSky-utilities/img/done.bmp b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/img/done.bmp similarity index 100% rename from radio/sdcard/FrSky-utilities/img/done.bmp rename to radio/sdcard/taranis-x7/SCRIPTS/TOOLS/img/done.bmp diff --git a/radio/sdcard/FrSky-utilities/img/down.png b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/img/down.png similarity index 100% rename from radio/sdcard/FrSky-utilities/img/down.png rename to radio/sdcard/taranis-x7/SCRIPTS/TOOLS/img/down.png diff --git a/radio/sdcard/FrSky-utilities/img/forward.png b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/img/forward.png similarity index 100% rename from radio/sdcard/FrSky-utilities/img/forward.png rename to radio/sdcard/taranis-x7/SCRIPTS/TOOLS/img/forward.png diff --git a/radio/sdcard/FrSky-utilities/img/left.png b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/img/left.png similarity index 100% rename from radio/sdcard/FrSky-utilities/img/left.png rename to radio/sdcard/taranis-x7/SCRIPTS/TOOLS/img/left.png diff --git a/radio/sdcard/FrSky-utilities/img/plane_b.png b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/img/plane_b.png similarity index 100% rename from radio/sdcard/FrSky-utilities/img/plane_b.png rename to radio/sdcard/taranis-x7/SCRIPTS/TOOLS/img/plane_b.png diff --git a/radio/sdcard/FrSky-utilities/img/planev_b.png b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/img/planev_b.png similarity index 100% rename from radio/sdcard/FrSky-utilities/img/planev_b.png rename to radio/sdcard/taranis-x7/SCRIPTS/TOOLS/img/planev_b.png diff --git a/radio/sdcard/FrSky-utilities/img/planev_s.png b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/img/planev_s.png similarity index 100% rename from radio/sdcard/FrSky-utilities/img/planev_s.png rename to radio/sdcard/taranis-x7/SCRIPTS/TOOLS/img/planev_s.png diff --git a/radio/sdcard/FrSky-utilities/img/right.png b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/img/right.png similarity index 100% rename from radio/sdcard/FrSky-utilities/img/right.png rename to radio/sdcard/taranis-x7/SCRIPTS/TOOLS/img/right.png diff --git a/radio/sdcard/FrSky-utilities/img/up.png b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/img/up.png similarity index 100% rename from radio/sdcard/FrSky-utilities/img/up.png rename to radio/sdcard/taranis-x7/SCRIPTS/TOOLS/img/up.png diff --git a/radio/sdcard/FrSky-utilities/img/vert-r.png b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/img/vert-r.png similarity index 100% rename from radio/sdcard/FrSky-utilities/img/vert-r.png rename to radio/sdcard/taranis-x7/SCRIPTS/TOOLS/img/vert-r.png diff --git a/radio/sdcard/FrSky-utilities/img/vert.png b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/img/vert.png similarity index 100% rename from radio/sdcard/FrSky-utilities/img/vert.png rename to radio/sdcard/taranis-x7/SCRIPTS/TOOLS/img/vert.png diff --git a/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/readme.txt b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/readme.txt new file mode 100644 index 000000000..20b95c415 --- /dev/null +++ b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/readme.txt @@ -0,0 +1 @@ +Scripts that need to be available in TOOLS menu should be in this directory diff --git a/radio/sdcard/taranis-x9/CROSSFIRE/crossfire.lua b/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/CROSSFIRE/crossfire.lua similarity index 98% rename from radio/sdcard/taranis-x9/CROSSFIRE/crossfire.lua rename to radio/sdcard/taranis-x9/SCRIPTS/TOOLS/CROSSFIRE/crossfire.lua index 452512621..47bb8d31c 100644 --- a/radio/sdcard/taranis-x9/CROSSFIRE/crossfire.lua +++ b/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/CROSSFIRE/crossfire.lua @@ -1,3 +1,4 @@ +local toolName = "TNS|Crossfire setup|TNE" ---- ######################################################################### ---- # # ---- # Copyright (C) OpenTX # diff --git a/radio/sdcard/taranis-x9/CROSSFIRE/device.lua b/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/CROSSFIRE/device.lua similarity index 100% rename from radio/sdcard/taranis-x9/CROSSFIRE/device.lua rename to radio/sdcard/taranis-x9/SCRIPTS/TOOLS/CROSSFIRE/device.lua diff --git a/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/FrSky GaSuite.lua b/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/FrSky GaSuite.lua new file mode 100755 index 000000000..df7fce8ce --- /dev/null +++ b/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/FrSky GaSuite.lua @@ -0,0 +1,515 @@ + +---- ######################################################################### +---- # # +---- # Copyright (C) OpenTX # +-----# # +---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html # +---- # # +---- # This program is free software; you can redistribute it and/or modify # +---- # it under the terms of the GNU General Public License version 2 as # +---- # published by the Free Software Foundation. # +---- # # +---- # This program is distributed in the hope that it will be useful # +---- # but WITHOUT ANY WARRANTY; without even the implied warranty of # +---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +---- # GNU General Public License for more details. # +---- # # +---- ######################################################################### + +local version = "v1.1" + +local VALUE = 0 +local COMBO = 1 +local FLPOI = 2 + + +local edit = false +local page = 1 +local current = 1 --row +local refreshState = 0 +local refreshIndex = 0 +local refreshIndex3 = 0 +local pageOffset = 0 +local pages = {} +local fields = {} +local modifications = {} +local thistime = getTime() +local lastTime = thistime +local margin = 1 +local spacing = 8 +local configFields = {} +local counter = 0 +local appId = 0 + +local function drawScreenTitle(title,page, pages) + if math.fmod(math.floor(getTime()/100),10) == 0 then + title = version + end + if LCD_W == 480 then + lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR) + lcd.drawText(1, 5, title, MENU_TITLE_COLOR) + lcd.drawText(LCD_W-40, 5, page.."/"..pages, MENU_TITLE_COLOR) + else + lcd.drawScreenTitle(title, page, pages) + end +end + +local interfaceconfig = { + {"Sensor group select", VALUE, appId, nil, 0, 15}, +} + +local settingsFields = { + {"Software version", FLPOT, 0x0c, nil, 1, 100 }, + {"Physical ID", VALUE, 0x01, nil, 0, 26 }, + {"Application IDgroup", VALUE, 0x0D, nil, 0, 15 }, + {"Data rate(*100ms)", VALUE, 0x22, nil, 1, 255 }, +} + +local telemetryFields = { + {"TEMP1(C/F)", VALUE, 0x90, nil, -30, 600}, + {"TEMP2(C/F)", VALUE, 0x91, nil, -30, 600}, + {"SPEED(r/min)", VALUE, 0x92, nil, 0, 100000}, + {"Residual Volume(mL)", VALUE, 0x93, nil, 0, 60000}, + {"Residual Percent(%)", VALUE, 0x94, nil, 0, 100}, + {"FLOW(mL/min)", VALUE, 0x95, nil, 0, 2000}, + {"Max Flow(mL/min)", VALUE, 0x96, nil, 0, 2000}, + {"Avg Flow(mL/min)", VALUE, 0x97, nil, 0, 2000}, +} + +-- Change display attribute to current field +local function addField(step) + local field = fields[current] + local min, max + if field[2] == VALUE then + min = field[5] + max = field[6] + elseif field[2] == COMBO then + min = 0 + max = #(field[5]) - 1 + end + if field[2] ~= FLPOT then --only read ? + if field[2] == VALUE and field[6] > 256 then + if field[4] > 1000 then + step = step * 50 + field[4] = math.floor(field[4]/50) + field[4] = field[4] *50 + elseif field[4] > 500 then + step = step * 20 + field[4] = math.floor(field[4]/20) + field[4] = field[4] *20 + elseif field[4] > 200 then + step = step * 10 + field[4] = math.floor(field[4]/10) + field[4] = field[4] *10 + else + step = step * 1 + field[4] = math.floor(field[4]/1) + field[4] = field[4] *1 + end + end + if (step < 0 and field[4] > min) or (step > 0 and field[4] < max) then + field[4] = field[4] + step + end + else + field[4] = field[4] + end +end + +-- Select the next or previous page +local function selectPage(step) + page = 1 + ((page + step - 1 + #pages) % #pages) + refreshIndex = 0 + pageOffset = 0 +end + +-- Select the next or previous editable field +local function selectField(step) + current = current + step + if current > #fields then + current = #fields + elseif current < 1 then + current = 1 + end + if current > 7 + pageOffset then + pageOffset = current - 7 + elseif current <= pageOffset then + pageOffset = current - 1 + end +end + +local function drawProgressBar() + if LCD_W == 480 then + local width = (300 * refreshIndex) / #fields + lcd.drawRectangle(100, 10, 300, 6) + lcd.drawFilledRectangle(102, 13, width, 2); + else + local width = (60 * refreshIndex) / #fields + lcd.drawRectangle(45, 1, 60, 6) + lcd.drawFilledRectangle(47, 3, width, 2); + end +end + +-- Redraw the current page +local function redrawFieldsPage() + lcd.clear() + drawScreenTitle("GasSuit", page, #pages) + if refreshIndex < #fields then + drawProgressBar() + end + for index = 1, 7, 1 do + local field = fields[pageOffset+index] + if field == nil then + break + end + local attr = current == (pageOffset+index) and ((edit == true and BLINK or 0) + INVERS) or 0 + lcd.drawText(1, margin+ spacing * index, field[1]) + if field[4] == nil then + lcd.drawText(LCD_W, margin+ spacing * index, "---", attr + RIGHT) + else + if field[2] == VALUE then + if (field[3] == 0x90 or field[3] == 0x91) and field[4] == 500 then + lcd.drawText(LCD_W, margin+ spacing * index, "---", attr + RIGHT) + else + + lcd.drawNumber(LCD_W, margin+ spacing * index, field[4] , attr + RIGHT) + end + elseif field[2] == COMBO then + if field[4] >= 0 and field[4] < #(field[5]) then + lcd.drawText(LCD_W, margin+ spacing * index, field[5][1+field[4]], attr + RIGHT) + end + elseif field[2] == FLPOT then + lcd.drawText(LCD_W, margin+ spacing * index, field[4], attr + RIGHT) + end + end + end +end + +local function telemetryRead(fieldx) + return sportTelemetryPush(0x1b, 0x30, appId, fieldx) +end + +local function telemetryListen(fieldx) + return sportTelemetryPush(0x1b, 0, 0, 0) +end + +local function telemetryWrite(fieldx, valuex) + return sportTelemetryPush(0x1b, 0x31, appId, fieldx + valuex*256) +end + +local telemetryPopTimeout = 0 +local function refreshNext() + if refreshState == 0 and page ~= 3 then -- + if #modifications > 0 then -- + if modifications[1][1] ~= 0x0c then + if modifications[1][1] == 0x22 then + modifications[1][2] = modifications[1][2] + 0xf00 + end + local modificationstmp = modifications[1][2] + if modifications[1][1] == 0x8a or modifications[1][1] == 0x8b then + if configFields[11][4]== 1 then + modificationstmp = (modifications[1][2] - 32)*10 + modificationstmp = math.floor(modificationstmp/18) + end + end + telemetryWrite(modifications[1][1], modificationstmp) + refreshIndex = 0 + end + modifications[1] = nil + elseif refreshIndex < #fields then + local field = fields[refreshIndex + 1] + if telemetryRead(field[3]) == true then + refreshState = 1 + telemetryPopTimeout = getTime() + 80 + end + end + elseif refreshState == 0 and page == 3 then + if #modifications > 0 then + if modifications[1][1] == 0x96 or modifications[1][1] == 0x97 or modifications[1][1] == 0x93 then + telemetryWrite(modifications[1][1], 0) + end + modifications[1] = nil + elseif refreshIndex < #fields then + local field = fields[refreshIndex + 1] + if telemetryRead(field[3]) == true then + refreshState = 1 + telemetryPopTimeout = getTime() + 20 + end + elseif refreshIndex >= #fields then + refreshIndex = 0 + refreshState = 0 + end + elseif refreshState == 1 and page ~= 3 then + local physicalId, primId, dataId, value = sportTelemetryPop() + if primId == 0x32 and dataId >= 0x0d00 and dataId <= 0x0d7f then + local fieldId = value % 256 + local field = fields[refreshIndex + 1] + if fieldId == field[3] then + local value = math.floor(value / 256) + if field[2] == COMBO then + for index = 1, #(field[6]), 1 do + if value == field[6][index] then + value = index - 1 + break + end + end + elseif field[2] == VALUE then + value = value -- - field[8] + field[5] + end + if field[1] == "Software version" then + local flo_string = string.char(value/16%16 + 48).."."..string.char(value%16 + 48) + fields[refreshIndex + 1][4] = flo_string + else + fields[refreshIndex + 1][4] = value + end + refreshIndex = refreshIndex + 1 + refreshState = 0 + end + elseif getTime() > telemetryPopTimeout then + refreshState = 0 + end + elseif refreshState == 1 and page == 3 then + local pageID3 = 0 + local physicalId3, primId3, dataId3, value3 = sportTelemetryPop() + if value3 ~= nil then + pageID3 = value3 % 256 + value3 = math.floor(value3 / 0x100) + end + if primId3 == 0x32 and value3 ~= nil then + if pageID3 == fields[refreshIndex + 1][3] then + local field = fields[refreshIndex + 1] + if field[2] == COMBO and #field == 6 then + for index = 1, #(field[6]), 1 do + if value3 == field[6][index] then + value3 = index - 1 + break + end + end + elseif field[2] == VALUE then + if field[3] == 0x90 or field[3] == 0x91 then + value3 = math.floor(value3 % 0x10000) + if value3 > 0xf000 then + value3 = value3 - 0x10000 + end + if configFields[11][4]== 1 and (field[3] == 0x90 or field[3] == 0x91) then + value3 =(value3*18) + value3 = math.floor(value3/10)+32 + end + else + value3 = value3 + end + end + fields[refreshIndex + 1][4] = value3 + refreshIndex = refreshIndex + 1 + refreshState = 0 + end + elseif getTime() > telemetryPopTimeout then + refreshState = 0 + end + end +end + +local function updateField(field) + local value = field[4] + if field[2] == COMBO and #field == 6 then + value = field[6][1+value] + elseif field[2] == VALUE and #field == 6 then + value = value -- + field[8] - field[5] + elseif field[2] == FLPOT then + value = 0 + end + modifications[#modifications+1] = {field[3], value} +end + +-- Main1 +local function runFieldsPage(event) + if event == EVT_VIRTUAL_EXIT then + return 2 + elseif event == EVT_VIRTUAL_ENTER then + if fields[current][4] ~= nil then + edit = not edit + if edit == false then + updateField(fields[current]) + end + end + elseif edit then + if event == EVT_VIRTUAL_NEXT or event == EVT_VIRTUAL_NEXT_REPT then + addField(1) + elseif event == EVT_VIRTUAL_PREVIOUS or event == EVT_VIRTUAL_PREVIOUS_REPT then + addField(-1) + end + else + if event == EVT_VIRTUAL_NEXT then + selectField(1) + elseif event == EVT_VIRTUAL_PREVIOUS then + selectField(-1) + end + end + redrawFieldsPage() + return 0 +end + +local function runConfigPage(event) + fields = configFields + local result = runFieldsPage(event) + return result +end + +local function runSettingsPage(event) + fields = settingsFields + return runFieldsPage(event) +end + +local function runTelemetryPage(event) + fields = telemetryFields + return runFieldsPage(event) +end + +-- Init +local function init() + current, edit, refreshState, refreshIndex = 1, false, 0, 0 + if LCD_W == 480 then + margin = 10 + spacing = 20 + end + if LCD_W == 128 then + configFields = { + {"CDI off speed limit", VALUE, 0x81, nil, 10,10000}, -- 1 + {"Milliliter per pulse", VALUE, 0x80, nil, 1, 2000}, -- 2 + {"Volume", VALUE, 0x83, nil, 10,60000}, -- 3 + -- {"Flow trigger", VALUE, 0x84, nil, 5, 50 }, + -- {"Flow Reset", COMBO, 0x85, nil, { "ON", "OFF" }, {1 , 0}}, + {"Auto Reset", COMBO, 0x8d, nil, { "ON", "OFF" }, {0 , 1}}, -- 4 + {"Reset settings", COMBO, 0x86, nil,{ "YES", "NO" }, {1 , 0} }, -- 5 + {"Volume alarm(%)", VALUE, 0x87, nil, 0, 90 }, -- 6 + {"Max.Flow alarm", VALUE, 0x88, nil, 0, 2000 }, -- 7 + {"Over speed alarm", VALUE, 0x89, nil, 0, 10000 }, -- 8 + {"Over temp1 alarm", VALUE, 0x8a, nil, 0, 600 }, -- 9 + {"Over temp2 alarm", VALUE, 0x8b, nil, 0, 600 }, -- 10 + {"Temperature C/F", COMBO, 0x8c, nil,{ "C", "F" }, {0 , 1} }, -- 11 + } + else + configFields = { + {"CDI off speed limit(*100RPM)", VALUE, 0x81, nil, 10,10000}, + {"Milliliter per pulse(*0.001mL/pul)", VALUE, 0x80, nil, 1, 2000}, + {"Volume(mL)", VALUE, 0x83, nil, 10,60000}, + -- {"Flow trigger(mL/min)", VALUE, 0x84, nil, 5, 50 }, + -- {"Flow Reset", COMBO, 0x85, nil, { "ON", "OFF" }, {1 , 0}}, + {"Auto Reset", COMBO, 0x8d, nil, { "ON", "OFF" }, {0 , 1}}, + {"Reset to factory settings", COMBO, 0x86, nil,{ "YES", "NO" }, {1 , 0} }, + {"Volume alarm(%)", VALUE, 0x87, nil, 0, 90 }, + {"Max.Flow alarm(mL/min)", VALUE, 0x88, nil, 0, 2000 }, + {"Over speed alarm(*100RPM)", VALUE, 0x89, nil, 0, 10000 }, + {"Over temperature1 alarm(C/F)", VALUE, 0x8a, nil, 0, 600 }, + {"Over temperature2 alarm(C/F)", VALUE, 0x8b, nil, 0, 600 }, + {"Temperature Celsius/Fahrenheit", COMBO, 0x8c, nil,{ "C", "F" }, {0 , 1} }, + } + end + + pages = { + runConfigPage, + runSettingsPage, + runTelemetryPage, + } + + -- Warning : GaSuite tool requires Temp2 to be connected and discovered for script to work + for index = 1, 40, 1 do + local sensor = model.getSensor(index) + if sensor ~= nil and sensor.id >= 0x0d10 and sensor.id <= 0x0d1f then + appId = sensor.id + break + end + end + + if appId == 0 then + error("No GasSuit sensor in this model!") + end +end + +local function background() + local tonefrq,tonelength,tonepause + thistime = getTime() + lastTime = thistime + refreshNext() + if page == 3 then --alarm + local alarmnum = 0 + if fields[3][4] ~= nil and configFields[9][4] ~= nil then + local speedtest = fields[3][4] + local speedover = configFields[9][4]*100 + if speedtest >= speedover then + tonefrq = 800 + math.max(0,math.floor((speedtest - speedover)/10)) + tonelength = 50 + math.max(0,(150 - math.floor((speedtest - speedover)/10))) + tonepause = tonelength + playTone(tonefrq, tonelength, tonepause, PLAY_BACKGROUND,10) + alarmnum = alarmnum + 1 + end + end + if fields[5][4] ~= nil and configFields[7][4] ~= nil then + local Residualtest = fields[5][4] + local Residualline = configFields[6][4] + if Residualtest < Residualline then + tonefrq = 400 + tonelength = 100 + tonepause = 1000 + math.floor( Residualline - Residualtest )*30 + playTone(tonefrq, tonelength, tonepause, PLAY_BACKGROUND,10) + alarmnum = alarmnum + 1 + end + end + if fields[6][4] ~= nil and configFields[8][4] ~= nil then + local Flowtest = fields[6][4] + local Flowover = configFields[7][4] + if Flowtest > Flowover then + tonefrq = 400 + tonelength = 100 + tonepause = 200 + playTone(tonefrq, tonelength, tonepause, PLAY_BACKGROUND,10) + alarmnum = alarmnum + 1 + end + end + if fields[1][4] ~= nil and configFields[10][4] ~= nil then + local temp1test = fields[1][4] -- + local temp1over = configFields[9][4] + if temp1test > temp1over and (temp1test ~= 500 and temp1test ~= 932) then + tonefrq = 2000 + tonelength = 100 + tonepause = 900 + playTone(tonefrq, tonelength, tonepause, PLAY_BACKGROUND,10) + alarmnum = alarmnum + 1 + end + end + if fields[2][4] ~= nil and configFields[11][4] ~= nil then + local temp2test = fields[2][4] + local temp2over = configFields[10][4] + if temp2test > temp2over and (temp2test ~= 500 and temp2test ~= 932) then + tonefrq = 2000 + tonelength = 300 + tonepause = 700 + playTone(tonefrq, tonelength, tonepause, PLAY_BACKGROUND,10) + alarmnum = alarmnum + 1 + end + end + if alarmnum > 1 then + playTone(2000, 100, 100, PLAY_BACKGROUND,10) + end + alarmnum = 0 + end +end + +local function run(event) + if event == nil then + error("Cannot be run as a sensor script!") + return 2 + elseif event == EVT_VIRTUAL_NEXT_PAGE then + selectPage(1) + elseif event == EVT_VIRTUAL_PREVIOUS_PAGE then + killEvents(event); + selectPage(-1) + end + local result = pages[page](event) + if page ~= 3 then + refreshNext() + end + background() + return result +end + +return { init=init, background=background, run=run } diff --git a/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/FrSky SBEC.lua b/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/FrSky SBEC.lua new file mode 100644 index 000000000..1b82bc47f --- /dev/null +++ b/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/FrSky SBEC.lua @@ -0,0 +1,289 @@ +---- ######################################################################### +---- # # +---- # Copyright (C) OpenTX # +-----# # +---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html # +---- # # +---- # This program is free software; you can redistribute it and/or modify # +---- # it under the terms of the GNU General Public License version 2 as # +---- # published by the Free Software Foundation. # +---- # # +---- # This program is distributed in the hope that it will be useful # +---- # but WITHOUT ANY WARRANTY; without even the implied warranty of # +---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +---- # GNU General Public License for more details. # +---- # # +---- ######################################################################### + +local version = "v1.2" + +local VALUE = 0 +local COMBO = 1 + +local edit = false +local page = 1 +local current = 1 --row +local refreshState = 0 +local refreshIndex = 0 +local pageOffset = 0 +local pages = {} +local fields = {} +local modifications = {} +local margin = 1 +local spacing = 8 +local appId = 0 + +local function drawScreenTitle(title,page, pages) + if math.fmod(math.floor(getTime()/100),10) == 0 then + title = version + end + if LCD_W == 480 then + lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR) + lcd.drawText(1, 5, title, MENU_TITLE_COLOR) + lcd.drawText(LCD_W-40, 5, page.."/"..pages, MENU_TITLE_COLOR) + else + lcd.drawScreenTitle(title, page, pages) + end +end + +local settingsFields = { + {"SBEC OUTPUT (V)", VALUE, 0x80, nil, 50, 84 }, + {"Physical ID", VALUE, 0x01, nil, 0, 26 }, + {"Application IDgroup", VALUE, 0x0D, nil, 0, 15 }, + {"Data rate(*100ms)", VALUE, 0x22, nil, 1, 255 }, +} + +-- Change display attribute to current field +local function addField(step) + local field = fields[current] + local min, max + if field[2] == VALUE then + min = field[5] + max = field[6] + elseif field[2] == COMBO then + min = 0 + max = #(field[5]) - 1 + end + if field[2] ~= FLPOT then --only read ? + if field[2] == VALUE and field[6] > 256 then + if field[4] > 1000 then + step = step * 50 + field[4] = math.floor(field[4]/50) + field[4] = field[4] *50 + elseif field[4] > 500 then + step = step * 20 + field[4] = math.floor(field[4]/20) + field[4] = field[4] *20 + elseif field[4] > 200 then + step = step * 10 + field[4] = math.floor(field[4]/10) + field[4] = field[4] *10 + else + step = step * 1 + field[4] = math.floor(field[4]/1) + field[4] = field[4] *1 + end + end + if (step < 0 and field[4] > min) or (step > 0 and field[4] < max) then + field[4] = field[4] + step + end + else + field[4] = field[4] + end +end + + +-- Select the next or previous editable field +local function selectField(step) + current = current + step + if current > #fields then + current = #fields + elseif current < 1 then + current = 1 + end + if current > 7 + pageOffset then + pageOffset = current - 7 + elseif current <= pageOffset then + pageOffset = current - 1 + end +end + +local function drawProgressBar() + if LCD_W == 480 then + local width = (300 * refreshIndex) / #fields + lcd.drawRectangle(100, 10, 300, 6) + lcd.drawFilledRectangle(102, 13, width, 2); + else + local width = (60 * refreshIndex) / #fields + lcd.drawRectangle(45, 1, 60, 6) + lcd.drawFilledRectangle(47, 3, width, 2); + end +end + +-- Redraw the current page +local function redrawFieldsPage() + lcd.clear() + drawScreenTitle("SBEC", page, #pages) + if refreshIndex < #fields then + drawProgressBar() + end + for index = 1, 7, 1 do + local field = fields[pageOffset+index] + if field == nil then + break + end + local attr = current == (pageOffset+index) and ((edit == true and BLINK or 0) + INVERS) or 0 + lcd.drawText(1, margin+ spacing * index, field[1]) + if field[4] == nil then + lcd.drawText(LCD_W, margin+ spacing * index, "---", attr + RIGHT) + else + if field[2] == VALUE then + if field[3] == 0x80 then + lcd.drawNumber(LCD_W, margin+ spacing * index, field[4] , attr + RIGHT + PREC1) + else + lcd.drawNumber(LCD_W, margin+ spacing * index, field[4] , attr + RIGHT) + end + end + end + end +end + +local function telemetryRead(fieldx) + return sportTelemetryPush(0x17, 0x30, appId, fieldx) +end + +local function telemetryIdle(field) + return sportTelemetryPush(0x17, 0x21, appId, field) +end + +local function telemetryUnIdle(field) + return sportTelemetryPush(0x17, 0x20, appId, field) +end + +local function telemetryWrite(fieldx, valuex) + return sportTelemetryPush(0x17, 0x31, appId, fieldx + valuex*256) +end + +local telemetryPopTimeout = 0 +local function refreshNext() + if refreshState == 0 then + if #modifications > 0 then + local modificationstmp = modifications[1][2] + telemetryWrite(modifications[1][1], modificationstmp) + refreshIndex = 0 + modifications[1] = nil + elseif refreshIndex < #fields then + local field = fields[refreshIndex + 1] + if telemetryRead(field[3]) == true then + refreshState = 1 + telemetryPopTimeout = getTime() + 80 + end + end + elseif refreshState == 1 then + local physicalId, primId, dataId, value = sportTelemetryPop() + if primId == 0x32 and dataId == appId then + local fieldId = value % 256 + local field = fields[refreshIndex + 1] + if fieldId == field[3] then + local value = math.floor(value / 256) + if field[2] == VALUE then + value = value + end + + fields[refreshIndex + 1][4] = value + refreshIndex = refreshIndex + 1 + refreshState = 0 + end + elseif getTime() > telemetryPopTimeout then + refreshState = 0 + end + end +end + +local function updateField(field) + local value = field[4] + if field[2] == VALUE and #field == 6 then + value = value + end + modifications[#modifications+1] = {field[3], value} +end + +-- Main1 +local function runFieldsPage(event) + if event == EVT_VIRTUAL_EXIT then + telemetryUnIdle(0x80) + return 2 + elseif event == EVT_VIRTUAL_ENTER then + if fields[current][4] ~= nil then + edit = not edit + if edit == false then + updateField(fields[current]) + end + end + elseif edit then + if event == EVT_VIRTUAL_NEXT or event == EVT_VIRTUAL_NEXT_REPT then + addField(1) + elseif event == EVT_VIRTUAL_PREVIOUS or event == EVT_VIRTUAL_PREVIOUS_REPT then + addField(-1) + end + else + if event == EVT_VIRTUAL_NEXT then + selectField(1) + elseif event == EVT_VIRTUAL_PREVIOUS then + selectField(-1) + end + end + redrawFieldsPage() + return 0 +end + +local function runSettingsPage(event) + fields = settingsFields + return runFieldsPage(event) +end + +-- Init +local function init() + current, edit, refreshState, refreshIndex = 1, false, 0, 0 + if LCD_W == 480 then + margin = 10 + spacing = 20 + end + + pages = { + runSettingsPage, + } + + for index = 1, 40, 1 do + local sensor = model.getSensor(index) + if sensor ~= nil and sensor.id >= 0x0e50 and sensor.id <= 0x0e5f then + appId = sensor.id + break + end + end + + if appId == 0 then + error("No SBEC sensor in this model!") + end + + telemetryIdle(0x80) +end + +local function run(event) + if event == nil then + error("Cannot run as a model script!") + return 2 + elseif event == EVT_PAGE_BREAK or event == EVT_PAGEDN_FIRST or event == EVT_SHIFT_BREAK then + --selectPage(1) + elseif event == EVT_PAGE_LONG or event == EVT_PAGEUP_FIRST or event == EVT_SHIFT_LONG then + --killEvents(event); + --selectPage(-1) + end + local result = pages[page](event) + + refreshNext() + + return result +end + +return { init=init, background=background, run=run } diff --git a/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/FrSky SxR.lua b/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/FrSky SxR.lua new file mode 100755 index 000000000..c49b78f52 --- /dev/null +++ b/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/FrSky SxR.lua @@ -0,0 +1,363 @@ +--- - ######################################################################### +---- # # +---- # Copyright (C) OpenTX # +----- # # +---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html # +---- # # +---- # This program is free software; you can redistribute it and/or modify # +---- # it under the terms of the GNU General Public License version 2 as # +---- # published by the Free Software Foundation. # +---- # # +---- # This program is distributed in the hope that it will be useful # +---- # but WITHOUT ANY WARRANTY; without even the implied warranty of # +---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +---- # GNU General Public License for more details. # +---- # # +---- ######################################################################### + +local version = "v2.00" + +local VALUE = 0 +local COMBO = 1 + +local COLUMN_2 = 300 + +local edit = false +local page = 1 +local current = 1 +local refreshState = 0 +local refreshIndex = 0 +local calibrationState = 0 +local pageOffset = 0 +local calibrationStep = 0 +local pages = {} +local fields = {} +local modifications = {} +local wingBitmaps = {} +local mountBitmaps = {} +local margin = 1 +local spacing = 8 +local counter = 0 + +local configFields = { + { "Wing type", COMBO, 0x80, nil, { "Normal", "Delta", "VTail" } }, + { "Mounting type", COMBO, 0x81, nil, { "Horz", "Horz rev.", "Vert", "Vert rev." } }, +} + +local wingBitmapsFile = { "bmp/plane.bmp", "bmp/delta.bmp", "bmp/vtail.bmp" } +local mountBitmapsFile = { "bmp/horz.bmp", "bmp/horz-r.bmp", "bmp/vert.bmp", "bmp/vert-r.bmp" } + +local settingsFields = { + {"SxR functions", COMBO, 0x9C, nil, { "Disable", "Enable" } }, + {"Quick Mode:", COMBO, 0xAA, nil, { "Disable", "Enable" } }, + {"CH5 mode", COMBO, 0xA8, nil, { "AIL2", "AUX1" } }, + {"CH6 mode", COMBO, 0xA9, nil, { "ELE2", "AUX2" } }, + {"AIL direction", COMBO, 0x82, nil, { "Normal", "Invers" }, { 255, 0 } }, + {"ELE direction", COMBO, 0x83, nil, { "Normal", "Invers" }, { 255, 0 } }, + {"RUD direction", COMBO, 0x84, nil, { "Normal", "Invers" }, { 255, 0 } }, + {"AIL2 direction", COMBO, 0x9A, nil, { "Normal", "Invers" }, { 255, 0 } }, + {"ELE2 direction", COMBO, 0x9B, nil, { "Normal", "Invers" }, { 255, 0 } }, + {"AIL stab gain", VALUE, 0x85, nil, 0, 200, "%"}, + {"ELE stab gain", VALUE, 0x86, nil, 0, 200, "%"}, + {"RUD stab gain", VALUE, 0x87, nil, 0, 200, "%"}, + {"AIL autolvl gain", VALUE, 0x88, nil, 0, 200, "%"}, + {"ELE autolvl gain", VALUE, 0x89, nil, 0, 200, "%"}, + {"ELE hover gain", VALUE, 0x8C, nil, 0, 200, "%"}, + {"RUD hover gain", VALUE, 0x8D, nil, 0, 200, "%"}, + {"AIL knife gain", VALUE, 0x8E, nil, 0, 200, "%"}, + {"RUD knife gain", VALUE, 0x90, nil, 0, 200, "%"}, + {"AIL autolvl offset", VALUE, 0x91, nil, -20, 20, "%", 0x6C}, + {"ELE autolvl offset", VALUE, 0x92, nil, -20, 20, "%", 0x6C}, + {"ELE hover offset", VALUE, 0x95, nil, -20, 20, "%", 0x6C}, + {"RUD hover offset", VALUE, 0x96, nil, -20, 20, "%", 0x6C}, + {"AIL knife offset", VALUE, 0x97, nil, -20, 20, "%", 0x6C}, + {"RUD knife offset", VALUE, 0x99, nil, -20, 20, "%", 0x6C}, +} + +local calibrationFields = { + { "X:", VALUE, 0x9E, 0, -100, 100, "%" }, + { "Y:", VALUE, 0x9F, 0, -100, 100, "%" }, + { "Z:", VALUE, 0xA0, 0, -100, 100, "%" } +} + +local function drawScreenTitle(title, page, pages) + if math.fmod(math.floor(getTime() / 100), 10) == 0 then + title = version + end + if LCD_W == 480 then + lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR) + lcd.drawText(1, 5, title, MENU_TITLE_COLOR) + lcd.drawText(LCD_W - 40, 5, page .. "/" .. pages, MENU_TITLE_COLOR) + else + lcd.drawScreenTitle(title, page, pages) + end +end + +-- Change display attribute to current field +local function addField(step) + local field = fields[current] + local min, max + if field[2] == VALUE then + min = field[5] + max = field[6] + elseif field[2] == COMBO then + min = 0 + max = #(field[5]) - 1 + end + if (step < 0 and field[4] > min) or (step > 0 and field[4] < max) then + field[4] = field[4] + step + end +end + +-- Select the next or previous page +local function selectPage(step) + page = 1 + ((page + step - 1 + #pages) % #pages) + refreshIndex = 0 + calibrationStep = 0 + pageOffset = 0 +end + +-- Select the next or previous editable field +local function selectField(step) + current = 1 + ((current + step - 1 + #fields) % #fields) + if current > 7 + pageOffset then + pageOffset = current - 7 + elseif current <= pageOffset then + pageOffset = current - 1 + end +end + +local function drawProgressBar() + if LCD_W == 480 then + local width = (300 * refreshIndex) / #fields + lcd.drawRectangle(100, 10, 300, 6) + lcd.drawFilledRectangle(102, 13, width, 2); + else + local width = (60 * refreshIndex) / #fields + lcd.drawRectangle(45, 1, 60, 6) + lcd.drawFilledRectangle(47, 3, width, 2); + end +end + +-- Redraw the current page +local function redrawFieldsPage(event) + lcd.clear() + drawScreenTitle("SxR", page, #pages) + + if refreshIndex < #fields then + drawProgressBar() + end + + for index = 1, 10, 1 do + local field = fields[pageOffset + index] + if field == nil then + break + end + + local attr = current == (pageOffset + index) and ((edit == true and BLINK or 0) + INVERS) or 0 + + lcd.drawText(1, margin + spacing * index, field[1], attr) + + if field[4] == nil then + lcd.drawText(LCD_W, margin + spacing * index, "---", RIGHT + attr) + else + if field[2] == VALUE then + lcd.drawNumber(LCD_W, margin + spacing * index, field[4], RIGHT + attr) + elseif field[2] == COMBO then + if field[4] >= 0 and field[4] < #(field[5]) then + lcd.drawText(LCD_W, margin + spacing * index, field[5][1 + field[4]], RIGHT + attr) + end + end + end + end +end + +local function telemetryRead(field) + return sportTelemetryPush(0x17, 0x30, 0x0C30, field) +end + +local function telemetryWrite(field, value) + return sportTelemetryPush(0x17, 0x31, 0x0C30, field + value * 256) +end + +local telemetryPopTimeout = 0 +local function refreshNext() + if refreshState == 0 then + if calibrationState == 1 then + if telemetryWrite(0x9D, calibrationStep) == true then + refreshState = 1 + calibrationState = 2 + telemetryPopTimeout = getTime() + 120 -- normal delay is 500ms + end + elseif #modifications > 0 then + telemetryWrite(modifications[1][1], modifications[1][2]) + modifications[1] = nil + elseif refreshIndex < #fields then + local field = fields[refreshIndex + 1] + if telemetryRead(field[3]) == true then + refreshState = 1 + telemetryPopTimeout = getTime() + 80 -- normal delay is 500ms + end + end + elseif refreshState == 1 then + local physicalId, primId, dataId, value = sportTelemetryPop() + if physicalId == 0x1A and primId == 0x32 and dataId == 0x0C30 then + local fieldId = value % 256 + if calibrationState == 2 then + if fieldId == 0x9D then + refreshState = 0 + calibrationState = 0 + calibrationStep = (calibrationStep + 1) % 7 + end + else + local field = fields[refreshIndex + 1] + if fieldId == field[3] then + local value = math.floor(value / 256) + if field[3] == 0xAA then + value = bit32.band(value, 0x0001) + end + if field[3] >= 0x9E and field[3] <= 0xA0 then + local b1 = value % 256 + local b2 = math.floor(value / 256) + value = b1 * 256 + b2 + value = value - bit32.band(value, 0x8000) * 2 + end + if field[2] == COMBO and #field == 6 then + for index = 1, #(field[6]), 1 do + if value == field[6][index] then + value = index - 1 + break + end + end + elseif field[2] == VALUE and #field == 8 then + value = value - field[8] + field[5] + end + fields[refreshIndex + 1][4] = value + refreshIndex = refreshIndex + 1 + refreshState = 0 + end + end + elseif getTime() > telemetryPopTimeout then + fields[refreshIndex + 1][4] = nil + refreshIndex = refreshIndex + 1 + refreshState = 0 + calibrationState = 0 + end + end +end + +local function updateField(field) + local value = field[4] + if field[2] == COMBO and #field == 6 then + value = field[6][1 + value] + elseif field[2] == VALUE and #field == 8 then + value = value + field[8] - field[5] + end + modifications[#modifications + 1] = { field[3], value } +end + +-- Main +local function runFieldsPage(event) + if event == EVT_VIRTUAL_EXIT then -- exit script + return 2 + elseif event == EVT_VIRTUAL_ENTER then -- toggle editing/selecting current field + if fields[current][4] ~= nil then + edit = not edit + if edit == false then + updateField(fields[current]) + end + end + elseif edit then + if event == EVT_VIRTUAL_NEXT or event == EVT_VIRTUAL_NEXT_REPT then + addField(1) + elseif event == EVT_VIRTUAL_PREVIOUS or event == EVT_VIRTUAL_PREVIOUS_REPT then + addField(-1) + end + else + if event == EVT_VIRTUAL_NEXT then + selectField(1) + elseif event == EVT_VIRTUAL_PREVIOUS then + selectField(-1) + end + end + redrawFieldsPage(event) + return 0 +end + +local function runConfigPage(event) + fields = configFields + local result = runFieldsPage(event) + if LCD_W == 128 then + local mountText = { "Label is facing the sky", "Label is facing ground", "Label is left when", "Label is right when" } + if fields[2][4] ~= nil then + lcd.drawText(1, 30, "Pins toward tail") + lcd.drawText(1, 40, mountText[1 + fields[2][4]]) + if fields[2][4] > 1 then + lcd.drawText(1, 50, "looking from the tail") + end + end + else + if fields[1][4] ~= nil then + if LCD_W == 480 then + if wingBitmaps[1 + fields[1][4]] == nil then + wingBitmaps[1 + fields[1][4]] = Bitmap.open(wingBitmapsFile[1 + fields[1][4]]) + end + lcd.drawBitmap(wingBitmaps[1 + fields[1][4]], 10, 90) + else + lcd.drawPixmap(20, 28, wingBitmapsFile[1 + fields[1][4]]) + end + end + if fields[2][4] ~= nil then + if LCD_W == 480 then + if mountBitmaps[1 + fields[2][4]] == nil then + mountBitmaps[1 + fields[2][4]] = Bitmap.open(mountBitmapsFile[1 + fields[2][4]]) + end + lcd.drawBitmap(mountBitmaps[1 + fields[2][4]], 190, 110) + else + lcd.drawPixmap(128, 28, mountBitmapsFile[1 + fields[2][4]]) + end + end + end + return result +end + +local function runSettingsPage(event) + fields = settingsFields + return runFieldsPage(event) +end + +-- Init +local function init() + current, edit, refreshState, refreshIndex = 1, false, 0, 0 + if LCD_W == 480 then + margin = 10 + spacing = 20 + wingBitmapsFile = { "img/plane_b.png", "img/delta_b.png", "img/planev_b.png" } + mountBitmapsFile = { "img/up.png", "img/down.png", "img/vert.png", "img/vert-r.png" } + end + pages = { + runConfigPage, + runSettingsPage, + } +end + +-- Main +local function run(event) + if event == nil then + error("Cannot be run as a model script!") + return 2 + elseif event == EVT_VIRTUAL_NEXT_PAGE then + selectPage(1) + elseif event == EVT_VIRTUAL_PREVIOUS_PAGE then + killEvents(event); + selectPage(-1) + end + + local result = pages[page](event) + refreshNext() + + return result +end + +return { init = init, run = run } + diff --git a/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/bmp/back.bmp b/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/bmp/back.bmp new file mode 100644 index 0000000000000000000000000000000000000000..a8996262cc5c08c72c6480256d291629f3df247c GIT binary patch literal 1144 zcmb7@&ubG=5XZms2ntr|&Wi+3vb*shC|I+4c3V^Mq9xMoQ4585Qv_{_iu9lo`XA&U zD3X(c_L57*i-+KkKOm^>QAs1H6br`LecL44-5wm6eY^9S@9fOJeKS{=bBJt7uBXL) zaa){VfRaT|7?<$Sm>I6?!t*?o%VkunRn%%V)a!LL8Vxj?O|)7qwA*cTIvsSoUG#cA z3)C7ml*zOpdorruSJ!PEdgXwD z+gq}sl_dWHAymTg?G@TQm#)8|Xa?wRPSRK8zo+?&Fmx7gL0i=G(|m<+8ONNBqo04} z-aO9W8V(Ns{Wysqbn|Bh59hn2K23ak89|y(_P?ODgOe(3BVQz$Z{PerU`do%(xB7z zea=lmg}*VluqJ%Jo~5X<=U3*_^=(oXRM9zQW9`vml$iMbmKJ?(DY&tKc11c7OL8a) z1zO%O4MvvaTrjE_5<5vA$HRrSE9cO2$M-+R%x=U=a#$|}4@dup1rk;abtPG5Z>_!` hLAm=qA0kiG<>0}G1d1Pa@0Gk@^?);%CD@Ar{{Ua2F!TTb literal 0 HcmV?d00001 diff --git a/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/bmp/delta.bmp b/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/bmp/delta.bmp new file mode 100644 index 0000000000000000000000000000000000000000..ab94279c1eb7e803df6d341783f27763b4ab816e GIT binary patch literal 1144 zcmdr~J8Hu~5PdQRfl{pOCXmL9t8^}W0bvZOf-7IawW>IsTVKJQ0=295hw@9z-VXoz4>Wp@%}l4lMng6iYB63G(ZCksSnZfbICX}op<;M@a0&-AZ+lESc ztmJjP27$Mr2#*eAf)_CgZvdz|GEq}6McB|P>9`SLrXe#mAiv;u-NLc`TiO6Z>53$8 zO4Sj|dv1>dRY|uZDN>nv=0VnkDzKBYvTbSAT{>Y=gZRZJ!Nh7r|@$z*{Ba~I=&UXb5e7|cO8rwmym@w|e9FYAP J{&%dPz&Ex;fJy)W literal 0 HcmV?d00001 diff --git a/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/bmp/done.bmp b/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/bmp/done.bmp new file mode 100644 index 0000000000000000000000000000000000000000..9ac50139804db9e8f54d93f80c363d2a8b9f92dd GIT binary patch literal 1142 zcmZvaPe>a<6vn@G{gWD#YHtPvZ}Ct;3?au#@X!VVHue%ESdf}t1W%HSkV7SU5EO+V zlv3J5a}eq+m-e1Zz}iO5+K0Wgg-}5~3U>Quva2&w2j0xi_xs+PH@llmFLgqWC7wq( zCOC#UEO>yIqfk5gSr@~yER;$m)M_=PQYlm_6|`C{M59sU^La!f5tPeiG@DIivsqND zRk*H;L?VGgp#U;Q=1DSVNXpjv%SU!!DvI~m*aFtb*^@nC{6E8E0Y*347`QeJjs%lF zhMm(52MAsaY(Kr>SkU|P*3RHSo$;e&M%)oA8b3zh<@|j7 zIbPAj2Qck zxb8a%z3EKlO(`xE6~ns985C)U2RYRv*^@u1(2XbRyYz}_ta@fpF>dj1A1{)ip&X!aQIm*@xjriAQ| z9zC6Zu#UGr6Kj{wxg|Y+Nax>xUU@CAhOJ}b`s*Z{Ya3n|ocmiQc`wPsIg`)+W~tw+ fZoVAf?06^q@da}|C~$?qCsS7TyPK~^l`Z`PirX(` literal 0 HcmV?d00001 diff --git a/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/bmp/down.bmp b/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/bmp/down.bmp new file mode 100644 index 0000000000000000000000000000000000000000..97f9105ac5c1222e7eea179b0d412fa416b07671 GIT binary patch literal 1144 zcmb7?JxIeq6vy9H1;HhE5nP)~1;NGK1sq&T4O9ogq8%N&ba8XA4ld$SP!OR@M+cYA zbt+gK+=@;r9ZCoH?taG0S96!Pq7Pmk?|%RPyLXV>*3mThaVWk^BC{gXA`t{2B?_4f zQXCHhV+@p1;GBcwI8ZDWpom9U6@Wv|26bbUM)M^L*fzdg$QH9Db+Ai26QcNu^@<@GYq85{3T*uCA&5=ESWcDjFG*=xlUvM ztAeSP%B*wQeIo30X6(O=xM%jm0wV1nauQKd zEtrq}C%!+N9g2)p%u9m%i%A3cg2GiZXLPe4^X;UWX3k>jx(PEk^KBWsPx8H-n#T$i z&3!CjboC*LB>^+fN2xfu@h334aXS{f?zIrGMP+SOSu@T2qk5!vwSBe!QwQ(^fYqPC literal 0 HcmV?d00001 diff --git a/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/bmp/forward.bmp b/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/bmp/forward.bmp new file mode 100644 index 0000000000000000000000000000000000000000..df769aef2dec6178a757f0bddd9017e1de3779b3 GIT binary patch literal 1144 zcmb7@PiqrF7{;I34Xyv6GaGt{m+nq_5HD`B0ig(P>e`%yKuj+lOwmM&mx44atzZwK zrWHgAfh2n9No)K9%2vNX`w4`I2Tva2QAEr7Zc@#pD&ot|&hGr?edgKsWoNJ4jiDb^ zx}Txp(lBW-41h+HadI$d`Bw-bAf<%kIPg3V#bObaN(H{}qh7D0)oP*B=^zLK?CmdxoX#8g!)MRG$uQ>+|lYFuG?LY4Lc85oV2#%>E{L{@o z)w5}u>AE<=50!!O1ryNbZn!G{T8MJB@^YjN#>ZZk^XHWOC0Z}yLGz)FxRvH2=8o#q zYiMW8%cSs;la!IBU1)3~Hxl%|gUYFg4!>+u;z- zbRIKqiu&z07p4?{Heef>Y}%yebE;ipr);Y{X~U2lx>h3pmpEq}ntDDl1IIs}9p8p; zX6gIa{gRq*Vk{_aZeCc-N0nt_vgnyACx4l(S1(RKeT=vyG3uYC>XX0K(%bEc#0Tc{ z6nNr!J+J1Q&>OraPVKFMI?MQE!D1>;@>s)t^ySzVm^4z6g-lA-mz-^^=}`gos^yaZ z=288KO~+?SOi(h{so<(URm3S|f|YAjpBy>Ru6iT-oNLeSrI#%_Iajd+bl)HGPoAHU z@L{lM79;xf{XZ$4PmheNJX#p?!P7)Ij3E=kkd90XX0K_)&-)wg-QD*+ Vg@)m4`o$^Q!JF>q5%A9!;0MPpL6ZOg literal 0 HcmV?d00001 diff --git a/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/bmp/horz-r.bmp b/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/bmp/horz-r.bmp new file mode 100644 index 0000000000000000000000000000000000000000..93ffdb0fc51acc1dbeb78a52066a3a1f4e2cf7f5 GIT binary patch literal 1144 zcmaiyyNeT16vod)!NS6vyTw{8Z03dqaSL^BP^@;15o|cx9yRA|! z=vFE0vH&wXU>%o6dyxsUVvzH{$9>Ng%A2NREYJj1!k zS>X)8f)Y>Sq)jeofrucb1f>)-8VzVRo6u^tpxtgmr_+IMw+p>q5BmK+3QM#23XH6=s$+O_Ju$B3d*s$Nx5Y0jtgr+`&d zURtZO-v)oYB*!KHDJ-Z(!t>u57gfeAfUr9Evn=DnP$Ll1`FV<+U-xzq!Ms27L-X*i zw-a0lyx;Jww-c;+{)_$gV)OP&-5q-VGbr{}QSGUxMBk3|me+G;7AALmUtZN-x_ffxhHj{lrJyBuyh;q302@Be4cC7hk#q)5dzo@ERNqljTq2oiW5X2OAV9JySM zN~IE2t5vGiYE-Y+snKXqtJR`zw@bZVkNW*S4F&@m4u>=vjmYynVrCit#{?4JH+2sQ zW7a1d93zf<|HO(j_H;~x888Pg9pBJAMaW_awf`#O&6DK`ZBlJV0) z;JM8CLd4r*Rv{gpvBLoC|2WmWts!2PN};gJi(ElX0%wVJ2jt%r!($Z_U8rN3`O{Fa zj&Uw>Y(dsmJgAt(L^JFs48#8&`Psj4G*3S1_2V@aoqqYdc_1ks@5WkZZvrK-Z0ok^gt-B4Z1@^dHq||r|W{$SF aSzF6P!M563FvGgH*Vcmf{MOF9lSIGNK!Ys+ literal 0 HcmV?d00001 diff --git a/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/bmp/left.bmp b/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/bmp/left.bmp new file mode 100644 index 0000000000000000000000000000000000000000..8cc811fd1ea6133c8ed563542cc7d476145762f8 GIT binary patch literal 1144 zcma*mze~eF6bJC{*^0l-B^4Z#Ml0e{Y_8BvsV8(1ry{xtTDleyS~u5j9VLVRK%jqs z6r3FUC)m-^E?QdzIbU0F@k1KqE63k%6&?YQeX-*^m3M_Ny|TB z+ctdPM-T+iTBBSpqgt(^(P*IAY$6OpL{WrJr-N>{i(apXe!mZ6%sBrYU;aruuK101 zlsbK6ORlAG=woV3!Kacmz=p;6P>&sO86W-OLoF&vDY44*4|U?jHP#jHsASLGC*Ebr za?QgEJ74DEiS{z@$QonEc>eg-0_P(o&-Pj-v&hX?at%Th7I@Dja_RLL-=zI*&GY>` z*_tTL@t(8>CeQiDh~P~x(<8;qWoCT literal 0 HcmV?d00001 diff --git a/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/bmp/plane.bmp b/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/bmp/plane.bmp new file mode 100644 index 0000000000000000000000000000000000000000..b3e61bf5f9e5ac0120d7c96d50f99d7b1a266919 GIT binary patch literal 1144 zcmah|yKWOv5IxsU8ccH6G$f+%$`yjbmiz&UkXs}-t|JV6yeb$^> zKGmA+C4Wkel0>y)-uyv}>D;cmtNF&1n_fIjbzl}#klL=>RF*Vy4Z$AW=m8oIUpt&L zymx?n4}W`*d7XDQMJ@6fjm-0Dpw2xe<_dKesG8$LoD{6_zF@}~%nd(4#{^Y*fdl41 z4*S_S+hl+zAPwJde~?OI7lgf5<{C=6{ z@Y9hDjuAiUx9{b%E|m1RRq)xJciQYTX91qN`qX;9v}Cd_>O^0GqY_wk--7B<6{XVu-;qH+wNI zGd&+tN;r-Kr4&5RL!;3^5CjOr5Z!JUyX;9z$zAtNEDL+7I)W zgojTdn0qlwka+4)lxzuWlUVSrMA5cOGE4Y}68mLG<|&^jA>EBiIYZ=)gXL-}&CO<( ztd#t0Pg6X{r0GECn}sj!u=nHz=KBJh`x_XM-r`#4@It%A9G7yle=U|rImHjS=DT=I z?r-wool7^>wYG6b=FgkMs|^FCNhb7FXBaH?>}+2fV`s$j>P;CH=#6KZEO7#6r1JsB=1wb2^+@K zceihSrTOUq7xsfVe$h9@f>+R9ygk}=jul9;7DIaYxkzKTSLU4dqm8U}rhwc|5(htM zE~S+J^88x+&CL_Q#r+W+cx8p=K0g0!c}c85Ss$hJ_NSaB!Kv$a=5*vfj^R*1{K)sU phd6hTf`g#13m{|gaqpqLuXA7~&3h>L%_eyd1>YW|cAmZn`~@N!+Gzj) literal 0 HcmV?d00001 diff --git a/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/bmp/vert-r.bmp b/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/bmp/vert-r.bmp new file mode 100644 index 0000000000000000000000000000000000000000..763409ec4d18814b643b8cc9b48e2a093ec9b389 GIT binary patch literal 1144 zcmaizJ4*vW5XUDXSXg+QMhii2V?B|kEmH_5R%z7JO00~20P$L}kV|h9 zEVL4d_z5CL5QIn`f{!BJID40P#~LmJv%BnX=RdQrh2`CTaBYX$N%A@JaqP<3KmL@xfvcYtS@BskGEbya^Ga46%V+bW3*Sg_=5a?I>%xJl zRDVOU%(u?sR|B~{@=(1qe*OxgxX*G<;bkYxr7wN)yFZ~GDLiIt?|CaU#^nio; z|8enur~Um)JjxW}f%E+)J+dhMbgt>EhPiiS7wUezV_T<(=AKn3l=^i71U+;(r A;{X5v literal 0 HcmV?d00001 diff --git a/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/bmp/vert.bmp b/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/bmp/vert.bmp new file mode 100644 index 0000000000000000000000000000000000000000..5f1b91f05e2f270239956b286839851b3f3994a9 GIT binary patch literal 1144 zcmaizO=uHA6vzM5R6U3|vnm!WWV4%sU)Z%955+@6x={qb2#sEg#ai@W>7i*o*@BwZ zOZ_M`dJ(B26%hob5D!-HAVfWTh!{ceAnB&4cxW=d*<^L&L0|S|cIW@zZ|1$(O&l3( zg=eGmznwfzu9Gv=g%%pL^>wG|-zJ2BVHmJ&8;;{3olawLa1fbH2H9*Dxm*ql3k%5S z^C%PwC>Dz-m&=e+D*wN&P>AaW;%cu``^Mk;6L}sceWU*tu)m#_K)KVU#$=ya?}2a`)1s)>qAomG4%VfZ?2 zPtE{)=fgd=1VX83MB)F|d)!W`QU1_?8Mw zE_G~5L{*hW6Mw|Q`4twYb#Z9Kr2J%z`uoR*m4X&)%TpMtKP)1e_`@8VosOfk*;hbx zmiU_4#J|XK?(CE96e*#ho78{J^xhAD1p{q4KQzzWa2lh~nzR?z#Xz`P2><3zD zve^Rq@qj{PopZ+41oXJ4GocxV9ZP1WZa*v(y^o?1^L}n>j=uI=`R8vwlmmJHz6E{( D3imG- literal 0 HcmV?d00001 diff --git a/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/bmp/vtail.bmp b/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/bmp/vtail.bmp new file mode 100644 index 0000000000000000000000000000000000000000..6c7ec0b569b33a300a6d8f7efa5b591fa9b05d21 GIT binary patch literal 1144 zcmb_aJA@uy>?^oV}H|34c0t5bi{Lo&yZ)ZFnBg-;O zCKJqNGb|PhESF2H*K2IITkLi_?Du;dk4KzNC!Eh`TrL-gh`-%2uCx2B|A`mKeTuiy zU8100rEG0fzIdc4fPpgkAU^e7f0lY9?%;7p=QN=&beZzImls^o_!;kQ5r>If^Htm}02%A{7q7()wE4qHC+d;7SPnm7PbC zKL}#*>!=ZRiXn2<>Je`emfmv;eBw5fs-0>NK@#Lhbl-NagV_aaz-Te;UyP_gXQ!2)P~`WA9FR7 uG=GN0eb-R$XZYQ>6PVz7ix8F^>URPqr*oZ3{eHqM?QW{R-hZAANAee;+B%#7 literal 0 HcmV?d00001 diff --git a/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/img/back.png b/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/img/back.png new file mode 100755 index 0000000000000000000000000000000000000000..2cf3cd699030fd58a55cabcece2ae28eb23644d6 GIT binary patch literal 9229 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 literal 0 HcmV?d00001 diff --git a/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/img/down.png b/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/img/down.png new file mode 100755 index 0000000000000000000000000000000000000000..8eac8039afe27f1fa89c9020fd63dd013c6f66ed GIT binary patch literal 7866 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 Dg)Soz literal 0 HcmV?d00001 diff --git a/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/img/forward.png b/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/img/forward.png new file mode 100755 index 0000000000000000000000000000000000000000..de09680b7b01e4a2eef81bc3ae3a87a72d37bf39 GIT binary patch literal 10493 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 MO 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 literal 0 HcmV?d00001 diff --git a/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/img/plane_b.png b/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/img/plane_b.png new file mode 100755 index 0000000000000000000000000000000000000000..37abedc3ab047a26097ab9d80680f6188917e997 GIT binary patch literal 12743 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 KRVb4;4gOz9EewSK literal 0 HcmV?d00001 diff --git a/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/img/planev_b.png b/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/img/planev_b.png new file mode 100755 index 0000000000000000000000000000000000000000..4e33f660bee8f51b7a95275e27aba3d22697b474 GIT binary patch literal 13467 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 Y7FS@_-R&vhAQ4DeUL9G9un75o00R|QvH$=8 literal 0 HcmV?d00001 diff --git a/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/img/planev_s.png b/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/img/planev_s.png new file mode 100755 index 0000000000000000000000000000000000000000..48283a2903fe901c880ecef52d8994c35a13587e GIT binary patch literal 4393 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 literal 0 HcmV?d00001 diff --git a/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/img/right.png b/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/img/right.png new file mode 100755 index 0000000000000000000000000000000000000000..01d555394a4d145dda3222a0a8afef08ced25b75 GIT binary patch literal 10388 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 AcmMzZ literal 0 HcmV?d00001 diff --git a/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/img/up.png b/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/img/up.png new file mode 100755 index 0000000000000000000000000000000000000000..f033aba553f80ce27f76ba5c1dcb6d8783367820 GIT binary patch literal 10799 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 iEB}4L|9|H%ckJBCPo|)(nS9t$53Y6Cf53D1 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 MO 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