From b990ec17a2249108d55b429dfc586a7edda6fada Mon Sep 17 00:00:00 2001 From: rotorman Date: Mon, 14 Jun 2021 20:42:52 +0200 Subject: [PATCH 01/24] The UARTs of radios are using 3.3V logic level, not TTL / 5V. --- radio/src/translations/cn.h.txt | 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 +- radio/src/translations/tw.h.txt | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/radio/src/translations/cn.h.txt b/radio/src/translations/cn.h.txt index 8f1b6f2ed..1f0e07dd3 100644 --- a/radio/src/translations/cn.h.txt +++ b/radio/src/translations/cn.h.txt @@ -718,7 +718,7 @@ #define TR_COPROC_TEMP "主板温度" #define TR_CAPAWARNING INDENT "电流过低" #define TR_TEMPWARNING INDENT "过热" -#define TR_TTL_WARNING "注意: 串口仅能使用TTL电平或5V" +#define TR_TTL_WARNING "注意:使用逻辑电平3.3V" #define TR_FUNC "功能" #define TR_V1 "V1" #define TR_V2 "V2" diff --git a/radio/src/translations/cz.h.txt b/radio/src/translations/cz.h.txt index f369d2b88..67ba25ac1 100644 --- a/radio/src/translations/cz.h.txt +++ b/radio/src/translations/cz.h.txt @@ -805,7 +805,7 @@ #define TR_COPROC_TEMP "Tepl. MB \016>" #define TR_CAPAWARNING INDENT "Nízká kapacita" #define TR_TEMPWARNING INDENT "Přehřátí" -#define TR_TTL_WARNING "Warning: use only TLL or 5v" +#define TR_TTL_WARNING "Warning: use 3.3V logic levels" #define TR_FUNC "Fce." #define TR_V1 "V1" #define TR_V2 "V2" diff --git a/radio/src/translations/de.h.txt b/radio/src/translations/de.h.txt index 071d63b46..7486afd00 100644 --- a/radio/src/translations/de.h.txt +++ b/radio/src/translations/de.h.txt @@ -810,7 +810,7 @@ #define TR_COPROC_TEMP "MB Temp. \016>" #define TR_CAPAWARNING INDENT "Kapaz. niedrig" // wg 9XR-Pro #define TR_TEMPWARNING INDENT "Temp. größer" //wg 9XR-Pro -#define TR_TTL_WARNING "Warning: use only TLL or 5v" +#define TR_TTL_WARNING "Warning: use 3.3V logic levels" #define TR_FUNC "Funktion" #define TR_V1 "V1" #define TR_V2 "V2" diff --git a/radio/src/translations/en.h.txt b/radio/src/translations/en.h.txt index 6ebdca2f9..b990e4484 100644 --- a/radio/src/translations/en.h.txt +++ b/radio/src/translations/en.h.txt @@ -814,7 +814,7 @@ #define TR_COPROC_TEMP "MB Temp." #define TR_CAPAWARNING INDENT "Capacity low" #define TR_TEMPWARNING INDENT "Overheat" -#define TR_TTL_WARNING "Warning: use only TLL or 5v" +#define TR_TTL_WARNING "Warning: use 3.3V logic levels" #define TR_FUNC "Func" #define TR_V1 "V1" #define TR_V2 "V2" diff --git a/radio/src/translations/es.h.txt b/radio/src/translations/es.h.txt index b88667292..cdfdc068f 100644 --- a/radio/src/translations/es.h.txt +++ b/radio/src/translations/es.h.txt @@ -812,7 +812,7 @@ #define TR_COPROC_TEMP "MB Temp. \016>" #define TR_CAPAWARNING INDENT "Capacidad baja" #define TR_TEMPWARNING INDENT "Sobrecalent" -#define TR_TTL_WARNING "Warning: use only TLL or 5v" +#define TR_TTL_WARNING "Warning: use 3.3V logic levels" #define TR_FUNC "Función" #define TR_V1 "V1" #define TR_V2 "V2" diff --git a/radio/src/translations/fi.h.txt b/radio/src/translations/fi.h.txt index 3d41e884a..17bd0b0c1 100644 --- a/radio/src/translations/fi.h.txt +++ b/radio/src/translations/fi.h.txt @@ -826,7 +826,7 @@ #define TR_COPROC_TEMP "MB Temp. \016>" #define TR_CAPAWARNING INDENT "Capacity Low" #define TR_TEMPWARNING INDENT "Overheat" -#define TR_TTL_WARNING "Warning: use only TLL or 5v" +#define TR_TTL_WARNING "Warning: use 3.3V logic levels" #define TR_FUNC "Func" #define TR_V1 "V1" #define TR_V2 "V2" diff --git a/radio/src/translations/fr.h.txt b/radio/src/translations/fr.h.txt index a730fda64..d2ac7ff04 100644 --- a/radio/src/translations/fr.h.txt +++ b/radio/src/translations/fr.h.txt @@ -831,7 +831,7 @@ #define TR_COPROC_TEMP "Temp. MB \016>" #define TR_CAPAWARNING INDENT "Capacité Basse" #define TR_TEMPWARNING INDENT "Surchauffe" -#define TR_TTL_WARNING "Warning: use only TLL or 5v" +#define TR_TTL_WARNING "Warning: use 3.3V logic levels" #define TR_FUNC "Fonction" #define TR_V1 "V1" #define TR_V2 "V2" diff --git a/radio/src/translations/it.h.txt b/radio/src/translations/it.h.txt index a1adc9151..db28fde80 100644 --- a/radio/src/translations/it.h.txt +++ b/radio/src/translations/it.h.txt @@ -832,7 +832,7 @@ #define TR_COPROC_TEMP "Temp. MB \016>" #define TR_CAPAWARNING INDENT "Capacità Bassa" #define TR_TEMPWARNING INDENT "Temp. Alta" -#define TR_TTL_WARNING "Warning: use only TLL or 5v" +#define TR_TTL_WARNING "Warning: use 3.3V logic levels" #define TR_FUNC "Funz" #define TR_V1 "V1" #define TR_V2 "V2" diff --git a/radio/src/translations/nl.h.txt b/radio/src/translations/nl.h.txt index b0bc956d9..4b4783a38 100644 --- a/radio/src/translations/nl.h.txt +++ b/radio/src/translations/nl.h.txt @@ -815,7 +815,7 @@ #define TR_COPROC_TEMP "MB Temp. \016>" #define TR_CAPAWARNING INDENT "Capaciteit laag" // wg 9XR-Pro #define TR_TEMPWARNING INDENT "Overhitting" //wg 9XR-Pro -#define TR_TTL_WARNING "Warning: use only TLL or 5v" +#define TR_TTL_WARNING "Warning: use 3.3V logic levels" #define TR_FUNC "Funktie" #define TR_V1 "V1" #define TR_V2 "V2" diff --git a/radio/src/translations/pl.h.txt b/radio/src/translations/pl.h.txt index 82ab7cb74..4b14f6f25 100644 --- a/radio/src/translations/pl.h.txt +++ b/radio/src/translations/pl.h.txt @@ -829,7 +829,7 @@ #define TR_COPROC_TEMP "Temp. MB" #define TR_CAPAWARNING INDENT "Mała pojemność" #define TR_TEMPWARNING INDENT "Przegrzanie" -#define TR_TTL_WARNING "Warning: use only TLL or 5v" +#define TR_TTL_WARNING "Warning: use 3.3V logic levels" #define TR_FUNC "Funkc" #define TR_V1 "V1" #define TR_V2 "V2" diff --git a/radio/src/translations/pt.h.txt b/radio/src/translations/pt.h.txt index fe29043b4..0669c02c4 100644 --- a/radio/src/translations/pt.h.txt +++ b/radio/src/translations/pt.h.txt @@ -830,7 +830,7 @@ #define TR_COPROC_TEMP "MB Temp. \016>" #define TR_CAPAWARNING INDENT "Aviso Capacidade" #define TR_TEMPWARNING INDENT "Temperat. ALTA" -#define TR_TTL_WARNING "Warning: use only TLL or 5v" +#define TR_TTL_WARNING "Warning: use 3.3V logic levels" #define TR_FUNC "Funcao" #define TR_V1 "V1" #define TR_V2 "V2" diff --git a/radio/src/translations/se.h.txt b/radio/src/translations/se.h.txt index 8a790710b..c39926ca7 100644 --- a/radio/src/translations/se.h.txt +++ b/radio/src/translations/se.h.txt @@ -832,7 +832,7 @@ #define TR_COPROC_TEMP "MB temp. \016>" #define TR_CAPAWARNING INDENT "Låg Kapacitet" #define TR_TEMPWARNING TR(INDENT "Hög Temp ", INDENT "Hög Temperatur") -#define TR_TTL_WARNING "Warning: use only TLL or 5v" +#define TR_TTL_WARNING "Warning: use 3.3V logic levels" #define TR_FUNC "Funk" #define TR_V1 "V1" #define TR_V2 "V2" diff --git a/radio/src/translations/tw.h.txt b/radio/src/translations/tw.h.txt index 7dba22e07..0913cd8f4 100644 --- a/radio/src/translations/tw.h.txt +++ b/radio/src/translations/tw.h.txt @@ -718,7 +718,7 @@ #define TR_COPROC_TEMP "主板溫度" #define TR_CAPAWARNING INDENT "電流過低" #define TR_TEMPWARNING INDENT "過熱" -#define TR_TTL_WARNING "注意: 端口僅能使用TTL電平或5V" +#define TR_TTL_WARNING "注意:使用逻辑电平3.3V" #define TR_FUNC "功能" #define TR_V1 "V1" #define TR_V2 "V2" From 962592b2f78f7cc7542af98f97e4eac3457bee42 Mon Sep 17 00:00:00 2001 From: olliw42 Date: Wed, 23 Jun 2021 16:23:20 +0200 Subject: [PATCH 02/24] Consistify icons for model setting, select, and category --- .../default_theme/mask_menu_model_select.png | Bin 0 -> 1287 bytes .../default_theme/mask_model_select_category.png | Bin 0 -> 803 bytes radio/src/gui/colorlcd/menus.h | 2 ++ radio/src/gui/colorlcd/model_select.cpp | 4 ++-- radio/src/gui/colorlcd/themes/480_bitmaps.h | 6 ++++++ radio/src/gui/colorlcd/themes/480_default.cpp | 2 ++ radio/src/gui/colorlcd/view_main_menu.cpp | 4 ++-- 7 files changed, 14 insertions(+), 4 deletions(-) create mode 100644 radio/src/bitmaps/480x272/default_theme/mask_menu_model_select.png create mode 100644 radio/src/bitmaps/480x272/default_theme/mask_model_select_category.png diff --git a/radio/src/bitmaps/480x272/default_theme/mask_menu_model_select.png b/radio/src/bitmaps/480x272/default_theme/mask_menu_model_select.png new file mode 100644 index 0000000000000000000000000000000000000000..e4d326ce304c18336da053dfde320d6a8eda262f GIT binary patch literal 1287 zcmV+i1^D`jP)0ZdHC=lckkXMolXN_Hk)y|T(q>b(9qBTz^6~2SYKZ!91fGsW&yBR zEO@q`~5{ZqS5H@iR1CO9^iC3C7DdhKSeT`)YYr1TB2Mh-re2R z%jl~d~Rc%-hbPC7a|Bo>SPk@7+nCnqP1 ziBqYRSS%I+4m{JEni~D3Sz20>#l=M#A0L-+I4obkem(Te0kK#tdaEHK;`90R5|_i~ z=BAuHc~U1{Sy_>b7cUARmo8nBjg1Y_G)=yI`69Vou56A%$$dVbh=>>g0)YSkw{PDD zK+`n*em~c)U8A+N6|2=sHk+lpyPMI`(W2gLZEa;`WrZ_m&d}M}NhXsi+qQ+=1ukN- zm;honnop-@QD>9jPsxaJgJmS68#Tx=JpW1K`=SXPh{3g8TRH z)6~?&<;$0O^X3h`y}i7C{hClHgsQ4MdGbV`c2A!^<^B8jY;A3kOeWdh-Ugt$x*C_u z1wbSc!BiObEiEl&OLXtvJv2=N;O*PD%*@O%J3GsrJ9pUH+A6v?m&@rTH5d%EwY72n z{CWEN`f$75I!7Xr_(5Ely@z39VuJns{i7@&mY0`VUS4K?ejc~mt#c$22~58ROixd< zx3>pCMMVXF3noQT^et03ivsrc_W1nyv;IGwPIL9@ReoJ)tE;Qb&CO9!QGv(fDIuw^ zuP@?I6y*o;`uciFz|V>;77K%egVfd4ar5R)o zMx(K;$^wU?D5dRm5PqIqu~Hk%E*-Ojsr?+6Bi z3=9kuJ*CIv;p4}TeEaqdx7$r)VJ`T@vl>?RtsB;jo-LcTNClXlRgyg@v--%WAb2`L1$H!USNoTJd_l zjE#*kJUmQKPY-9$o&}((sfm0(4?tyQWs!=is;aWivbMHXzuwr`V0d^K0I%1J)oLyF xT*qbvj?MZUtJ(W6?d|`|&>!n3%-{ZK`wrc^6OQP}xH$j-002ovPDHLkV1n~3Xm
6iG0Fe{0T0!CD(7Q4j)2;kug@14$O%bveAqT|Dow$%BEJ-I@8=_uKcIafpcU4dLXQq6uz- zzaPA^vVza&V`ylI$H&JngB^|5aaUItmSq8OcXx+nS)81lFgZEN$jAsDkLPn_X&`i6 z7mvpyfB=%oWMq7NTmYGxnvz1HAckRxX_`{0R2tb*K1{V?7#tlPv9`8GBoe{z_fsyH ziN#_h5(!#cTWfP8kqDVghTh&@hKGlFeSQ5qjT4Ck{r&yS&(Cvzf6wyrGMc8L>pIC~ zl5jZ8*47p`H#hY3^q{ILg+c+_wlPf;MNu$KlTxYlIdC?crBbN?aBy%ydwV-OJ39n} zLFVS>xW2w-Vq$`;t1C23BM=C%x3>pCxm+fhOmcgBi)C5l^LgIh-Wt<*c6PR=WiFQ! zRaM_(^+1Xip{!w!{91@L2WpQy)_V@SeH2yT$>2&@U_)!amLUmx}*9;sU z9#XAV0dToo|II+^z#SbOwSKi)<>lq2HZB&6tgf!|Yw2gRSuQRvaJgK>beX z*w~QM(^CP&>-CDR>kaLv{OL>M@i@6$j#8<_($W$G0|PjnP83C9Y;25BD1^h|_^F+u z{F_4}olc`^8n$h-zP?T%5MXzA7sD_(J3C`=aFFx!a{z4HCY4HYd3i~(Sp1q-N2AeN zic_hSjE;^9Abov(l1`^TEFZt$FVD}name, ICON_MODEL), category(category) + PageTab(category->name, ICON_MODEL_SELECT_CATEGORY), category(category) { } @@ -360,7 +360,7 @@ class ModelCategoryPage : public PageTab }; ModelSelectMenu::ModelSelectMenu(): - TabsGroup(ICON_MODEL) + TabsGroup(ICON_MODEL_SELECT) { modelslist.load(); diff --git a/radio/src/gui/colorlcd/themes/480_bitmaps.h b/radio/src/gui/colorlcd/themes/480_bitmaps.h index 2b1df160b..ea278241a 100644 --- a/radio/src/gui/colorlcd/themes/480_bitmaps.h +++ b/radio/src/gui/colorlcd/themes/480_bitmaps.h @@ -61,6 +61,12 @@ const uint8_t mask_model_special_functions[] = { const uint8_t mask_model_telemetry[] = { #include "mask_model_telemetry.lbm" }; +const uint8_t mask_menu_model_select[] = { +#include "mask_menu_model_select.lbm" //TODO: someone may want to make proper icon +}; +const uint8_t mask_model_select_category[] = { +#include "mask_model_select_category.lbm" //TODO: someone should make proper icon +}; const uint8_t mask_monitor[] = { #include "mask_monitor.lbm" }; diff --git a/radio/src/gui/colorlcd/themes/480_default.cpp b/radio/src/gui/colorlcd/themes/480_default.cpp index 5d5907536..c5159c6b4 100644 --- a/radio/src/gui/colorlcd/themes/480_default.cpp +++ b/radio/src/gui/colorlcd/themes/480_default.cpp @@ -150,6 +150,8 @@ class Theme480: public OpenTxTheme loadMenuIcon(ICON_MODEL_SPECIAL_FUNCTIONS, mask_model_special_functions); loadMenuIcon(ICON_MODEL_LUA_SCRIPTS, mask_model_lua_scripts); loadMenuIcon(ICON_MODEL_TELEMETRY, mask_model_telemetry); + loadMenuIcon(ICON_MODEL_SELECT, mask_menu_model_select); + loadMenuIcon(ICON_MODEL_SELECT_CATEGORY, mask_model_select_category); loadMenuIcon(ICON_STATS, mask_menu_stats); loadMenuIcon(ICON_STATS_THROTTLE_GRAPH, mask_stats_throttle_graph); loadMenuIcon(ICON_STATS_TIMERS, mask_stats_timers); diff --git a/radio/src/gui/colorlcd/view_main_menu.cpp b/radio/src/gui/colorlcd/view_main_menu.cpp index 569baa0a8..b82f9c1cf 100644 --- a/radio/src/gui/colorlcd/view_main_menu.cpp +++ b/radio/src/gui/colorlcd/view_main_menu.cpp @@ -51,7 +51,7 @@ ViewMainMenu::ViewMainMenu(Window* parent) : // "Tasks", 0, FOCUS_COLOR | FONT(XL) | CENTERED); // pos += title->height() + PAGE_LINE_SPACING; - carousel->addButton(ICON_MODEL, "Select\nModel", [=]() -> uint8_t { + carousel->addButton(ICON_MODEL_SELECT, "Select\nModel", [=]() -> uint8_t { deleteLater(); new ModelSelectMenu(); return 0; @@ -63,7 +63,7 @@ ViewMainMenu::ViewMainMenu(Window* parent) : return 0; }); - carousel->addButton(ICON_RADIO_TOOLS, "Model\nSettings", [=]() -> uint8_t { + carousel->addButton(ICON_MODEL, "Model\nSettings", [=]() -> uint8_t { deleteLater(); new ModelMenu(); return 0; From f604fed503b361ae7f60f86170756497cd1ef1ef Mon Sep 17 00:00:00 2001 From: Risto Date: Sat, 3 Jul 2021 13:48:02 +0200 Subject: [PATCH 03/24] Try fix X12S RTC battery sampling --- radio/src/targets/horus/x12s_adc_driver.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/radio/src/targets/horus/x12s_adc_driver.cpp b/radio/src/targets/horus/x12s_adc_driver.cpp index 2833c4620..b8127bddc 100644 --- a/radio/src/targets/horus/x12s_adc_driver.cpp +++ b/radio/src/targets/horus/x12s_adc_driver.cpp @@ -128,6 +128,8 @@ void adcInit() ADC_DMA_Stream->NDTR = 2; ADC_DMA_Stream->FCR = DMA_SxFCR_DMDIS | DMA_SxFCR_FTH_0; + ADC->CCR = ADC_CCR_VBATE; // Enable RTC coin cell sampling bridge + ADC1->CR1 = ADC_CR1_SCAN; ADC1->CR2 = ADC_CR2_ADON | ADC_CR2_DMA | ADC_CR2_DDS; ADC1->SQR1 = (1 - 1) << 20; From f1ba56232ae9edaa2edf96040597a25130b503f3 Mon Sep 17 00:00:00 2001 From: Peter Feerick Date: Sat, 3 Jul 2021 20:42:31 +1000 Subject: [PATCH 04/24] Use uint32_t values consistent with underlying data structures --- radio/src/gui/colorlcd/model_inputs.cpp | 4 ++-- radio/src/gui/colorlcd/model_mixes.cpp | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/radio/src/gui/colorlcd/model_inputs.cpp b/radio/src/gui/colorlcd/model_inputs.cpp index 62a24d2a8..a28b1e0dd 100644 --- a/radio/src/gui/colorlcd/model_inputs.cpp +++ b/radio/src/gui/colorlcd/model_inputs.cpp @@ -284,12 +284,12 @@ class InputEditWindow : public Page // Flight modes new StaticText(window, grid.getLabelSlot(), STR_FLMODE); - for (uint8_t i=0; i 0 && (i % 4) == 0) grid.nextLine(); new TextButton(window, grid.getFieldSlot(4, i % 4), fm, - [=]() -> uint8_t { + [=]() -> uint32_t { BFBIT_FLIP(line->flightModes, bfBit(i)); SET_DIRTY(); return !(bfSingleBitGet(line->flightModes, i)); diff --git a/radio/src/gui/colorlcd/model_mixes.cpp b/radio/src/gui/colorlcd/model_mixes.cpp index 3d534b32a..a6fae37a9 100644 --- a/radio/src/gui/colorlcd/model_mixes.cpp +++ b/radio/src/gui/colorlcd/model_mixes.cpp @@ -136,13 +136,13 @@ class MixEditWindow : public Page // Flight modes new StaticText(window, grid.getLabelSlot(), STR_FLMODE); - for (uint8_t i = 0; i < MAX_FLIGHT_MODES; i++) { + for (uint32_t i = 0; i < MAX_FLIGHT_MODES; i++) { char fm[2] = {char('0' + i), '\0'}; if (i > 0 && (i % 4) == 0) grid.nextLine(); new TextButton( window, grid.getFieldSlot(4, i % 4), fm, - [=]() -> uint8_t { - BFBIT_FLIP(mix->flightModes, bfBit(i)); + [=]() -> uint32_t { + BFBIT_FLIP(mix->flightModes, bfBit(i)); SET_DIRTY(); return !(bfSingleBitGet(mix->flightModes, i)); }, From 17ed43d0d0dcbda1d75e6b2080daf15c62705bed Mon Sep 17 00:00:00 2001 From: Richard Li Date: Wed, 7 Jul 2021 13:48:32 +0800 Subject: [PATCH 05/24] Fixed flysky hall stick mod problem in T16. --- radio/src/targets/horus/CMakeLists.txt | 1 + radio/src/targets/horus/hal.h | 5 ----- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/radio/src/targets/horus/CMakeLists.txt b/radio/src/targets/horus/CMakeLists.txt index bfbb3153e..c01057e9c 100644 --- a/radio/src/targets/horus/CMakeLists.txt +++ b/radio/src/targets/horus/CMakeLists.txt @@ -183,6 +183,7 @@ endif() if(FLYSKY_HALL_STICKS) add_definitions(-DFLYSKY_HALL_STICKS) + add_definitions(-DFLYSKY_HALL_STICKS_REVERSE) set(AUX_SERIAL OFF) set(FLYSKY_HALL_STICKS_DRIVER flyskyHallStick_driver.cpp) endif() diff --git a/radio/src/targets/horus/hal.h b/radio/src/targets/horus/hal.h index 752ed29d4..8d7be0da5 100644 --- a/radio/src/targets/horus/hal.h +++ b/radio/src/targets/horus/hal.h @@ -758,10 +758,6 @@ // Flysky Hall Stick #if defined(FLYSKY_HALL_STICKS) - #if defined (RADIO_TX16S) - #define FLYSKY_HALL_STICKS_REVERSE - #endif - #define FLYSKY_HALL_SERIAL_USART UART4 #define FLYSKY_HALL_SERIAL_GPIO GPIOA #define FLYSKY_HALL_DMA_Channel DMA_Channel_4 @@ -784,7 +780,6 @@ #define FLYSKY_HALL_RX_DMA_Stream_IRQHandler DMA1_Stream2_IRQHandler #define FLYSKY_HALL_TX_DMA_Stream_IRQHandler DMA1_Stream4_IRQHandler - #endif // Internal Module From 88ef710ecb12458b3ca28546733208794995cfc9 Mon Sep 17 00:00:00 2001 From: 3djc Date: Thu, 8 Jul 2021 16:07:43 +0200 Subject: [PATCH 06/24] Better solution to silence warning on GCC 10 Imported from opentx/opentx#8605 --- .../STM32_USB_OTG_Driver/src/usb_core.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.2.0/Libraries/STM32_USB_OTG_Driver/src/usb_core.c b/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.2.0/Libraries/STM32_USB_OTG_Driver/src/usb_core.c index 8c96a04fc..f76c587c6 100644 --- a/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.2.0/Libraries/STM32_USB_OTG_Driver/src/usb_core.c +++ b/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.2.0/Libraries/STM32_USB_OTG_Driver/src/usb_core.c @@ -29,6 +29,19 @@ #include "usb_core.h" #include "usb_bsp.h" +// taken from https://github.com/ARMmbed/mbed-os/blob/master/cmsis/TARGET_CORTEX_M/cmsis_compiler.h +#ifndef __PACKED_STRUCT +#define __PACKED_STRUCT struct __attribute__((packed)) +#endif +#ifndef __UNALIGNED_UINT32_WRITE +__PACKED_STRUCT T_UINT32_WRITE { uint32_t v; }; +#define __UNALIGNED_UINT32_WRITE(addr, val) (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val)) +#endif +#ifndef __UNALIGNED_UINT32_READ +__PACKED_STRUCT T_UINT32_READ { uint32_t v; }; +#define __UNALIGNED_UINT32_READ(addr) (((const struct T_UINT32_READ *)(const void *)(addr))->v) +#endif + /** @addtogroup USB_OTG_DRIVER * @{ @@ -180,7 +193,7 @@ USB_OTG_STS USB_OTG_WritePacket(USB_OTG_CORE_HANDLE *pdev, fifo = pdev->regs.DFIFO[ch_ep_num]; for (i = 0; i < count32b; i++) { - USB_OTG_WRITE_REG32( fifo, *((uint32_t *)src) ); + USB_OTG_WRITE_REG32( fifo, __UNALIGNED_UINT32_READ(src) ); src+=4; } } @@ -206,7 +219,7 @@ void *USB_OTG_ReadPacket(USB_OTG_CORE_HANDLE *pdev, for( i = 0; i < count32b; i++) { - *(uint32_t *)dest = USB_OTG_READ_REG32(fifo); + __UNALIGNED_UINT32_WRITE(dest, USB_OTG_READ_REG32(fifo)); dest += 4 ; } return ((void *)dest); From 9afd2e4fba1facd3074993304fe91a0944e05076 Mon Sep 17 00:00:00 2001 From: Peter Feerick Date: Fri, 9 Jul 2021 15:29:50 +1000 Subject: [PATCH 07/24] Reset MultiProtocol subType reset to zero on protocol change Resolves #410 by ensuring an out of range sub-protocol is not set when the protocol is changed. Stops the module from complaining about an invalid protocol, as well as stops simu from crashing. --- radio/src/gui/colorlcd/model_setup.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/radio/src/gui/colorlcd/model_setup.cpp b/radio/src/gui/colorlcd/model_setup.cpp index cbd353bf6..342199fb5 100644 --- a/radio/src/gui/colorlcd/model_setup.cpp +++ b/radio/src/gui/colorlcd/model_setup.cpp @@ -644,6 +644,7 @@ class ModuleWindow : public FormGroup { } #if defined(MULTIMODULE) else if (isModuleMultimodule(moduleIdx)) { + Choice * mmSubProtocol = nullptr; grid.nextLine(); new StaticText(this, grid.getLabelSlot(true), STR_RF_PROTOCOL); @@ -653,6 +654,8 @@ class ModuleWindow : public FormGroup { GET_DEFAULT(multiRfProto), [=](int32_t newValue) { g_model.moduleData[moduleIdx].setMultiProtocol(newValue); + g_model.moduleData[moduleIdx].subType = 0; + if (mmSubProtocol != nullptr) mmSubProtocol->invalidate(); resetMultiProtocolsOptions(moduleIdx); SET_DIRTY(); update(); @@ -662,7 +665,7 @@ class ModuleWindow : public FormGroup { // Subtype (D16, DSMX,...) const mm_protocol_definition * pdef = getMultiProtocolDefinition(g_model.moduleData[moduleIdx].getMultiProtocol()); if (pdef->maxSubtype > 0) - new Choice(this, grid.getFieldSlot(2, 1), pdef->subTypeString, 0, pdef->maxSubtype,GET_SET_DEFAULT(g_model.moduleData[moduleIdx].subType)); + mmSubProtocol = new Choice(this, grid.getFieldSlot(2, 1), pdef->subTypeString, 0, pdef->maxSubtype,GET_SET_DEFAULT(g_model.moduleData[moduleIdx].subType)); grid.nextLine(); // Multimodule status From 12946fe70c81298d3c31ebc786010d3ea07e334b Mon Sep 17 00:00:00 2001 From: Julio Cesar Matias Date: Fri, 9 Jul 2021 07:19:28 -0300 Subject: [PATCH 08/24] Dump Improvement (#423) --- radio/src/dump.cpp | 10 +++++----- radio/src/dump.h | 3 --- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/radio/src/dump.cpp b/radio/src/dump.cpp index 12a6b3459..c8964ce10 100644 --- a/radio/src/dump.cpp +++ b/radio/src/dump.cpp @@ -26,31 +26,31 @@ #define dumpPrintf(...) serialPrintf(__VA_ARGS__) #endif +#if defined(DEBUG) || defined(CLI) uint8_t dumpPosition; -void dumpStart(unsigned int size) +static void dumpStart(unsigned int size) { dumpPrintf("DUMP %d bytes ...\n\r", size); dumpPosition = 0; } -void dumpBody(const void *data, unsigned int size) +static void dumpBody(const void *data, unsigned int size) { for (unsigned int i=0; i Date: Wed, 7 Jul 2021 12:42:44 +0200 Subject: [PATCH 09/24] Use longer period for PXX2 modules triggered by heartbeat signal and reset timer early This allows to cope for the different frame rates used by ACCESS and ACCST modes. See opentx/opentx#8601 for details. --- radio/src/pulses/pxx.h | 2 +- radio/src/targets/common/arm/stm32/heartbeat_driver.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/radio/src/pulses/pxx.h b/radio/src/pulses/pxx.h index 90956fe35..a6f78cc54 100644 --- a/radio/src/pulses/pxx.h +++ b/radio/src/pulses/pxx.h @@ -30,7 +30,7 @@ #define PXX2_LOWSPEED_BAUDRATE 230400 #define PXX2_HIGHSPEED_BAUDRATE 450000 #define PXX2_NO_HEARTBEAT_PERIOD 4000/*us*/ -#define PXX2_MAX_HEARTBEAT_PERIOD (7000 + 1000)/*us 7ms frame rate + 1ms heartbeat backup*/ +#define PXX2_MAX_HEARTBEAT_PERIOD (9000 + 1000)/*us longest period (isrm/accst) + 1ms heartbeat backup*/ #define PXX2_TOOLS_PERIOD 1000/*us*/ #define PXX2_FRAME_MAXLENGTH 64 diff --git a/radio/src/targets/common/arm/stm32/heartbeat_driver.cpp b/radio/src/targets/common/arm/stm32/heartbeat_driver.cpp index 269b40854..ee00a6db3 100644 --- a/radio/src/targets/common/arm/stm32/heartbeat_driver.cpp +++ b/radio/src/targets/common/arm/stm32/heartbeat_driver.cpp @@ -79,6 +79,7 @@ void check_intmodule_heartbeat() #endif EXTI_ClearITPendingBit(INTMODULE_HEARTBEAT_EXTI_LINE); + mixerSchedulerResetTimer(); mixerSchedulerISRTrigger(); } } From e75bd64d547192bcdb57c172402b156ce218a6c2 Mon Sep 17 00:00:00 2001 From: Raphael Coeffic Date: Wed, 7 Jul 2021 12:44:16 +0200 Subject: [PATCH 10/24] Simplify pulses code with respect to period settings with PXX1 and PXX2 And a bit of clean-up. --- radio/src/pulses/pulses.cpp | 32 +++++--------------------------- radio/src/pulses/pxx.h | 19 +++++++++++++++++-- 2 files changed, 22 insertions(+), 29 deletions(-) diff --git a/radio/src/pulses/pulses.cpp b/radio/src/pulses/pulses.cpp index 7ac4a69e8..779771c04 100755 --- a/radio/src/pulses/pulses.cpp +++ b/radio/src/pulses/pulses.cpp @@ -347,7 +347,7 @@ bool setupPulsesExternalModule(uint8_t protocol) case PROTOCOL_CHANNELS_PXX2_LOWSPEED: extmodulePulsesData.pxx2.setupFrame(EXTERNAL_MODULE); #if defined(PCBSKY9X) - sheduleNextMixerCalculation(EXTERNAL_MODULE, PXX2_NO_HEARTBEAT_PERIOD); + scheduleNextMixerCalculation(EXTERNAL_MODULE, PXX2_NO_HEARTBEAT_PERIOD); #endif return true; #endif @@ -457,12 +457,9 @@ static void enablePulsesInternalModule(uint8_t protocol) case PROTOCOL_CHANNELS_PXX1_PULSES: intmodulePxx1PulsesStart(); #if defined(INTMODULE_HEARTBEAT) - // use backup trigger (1 ms later) init_intmodule_heartbeat(); - mixerSchedulerSetPeriod(INTERNAL_MODULE, INTMODULE_PXX1_SERIAL_PERIOD + 1000/*us*/); -#else - mixerSchedulerSetPeriod(INTERNAL_MODULE, INTMODULE_PXX1_SERIAL_PERIOD); #endif + mixerSchedulerSetPeriod(INTERNAL_MODULE, INTMODULE_PXX1_SERIAL_PERIOD); break; #endif @@ -470,12 +467,9 @@ static void enablePulsesInternalModule(uint8_t protocol) case PROTOCOL_CHANNELS_PXX1_SERIAL: intmodulePxx1SerialStart(); #if defined(INTMODULE_HEARTBEAT) - // use backup trigger (1 ms later) init_intmodule_heartbeat(); - mixerSchedulerSetPeriod(INTERNAL_MODULE, INTMODULE_PXX1_SERIAL_PERIOD + 1000/*us*/); -#else - mixerSchedulerSetPeriod(INTERNAL_MODULE, INTMODULE_PXX1_SERIAL_PERIOD); #endif + mixerSchedulerSetPeriod(INTERNAL_MODULE, INTMODULE_PXX1_SERIAL_PERIOD); break; #endif @@ -487,10 +481,8 @@ static void enablePulsesInternalModule(uint8_t protocol) #if defined(INTMODULE_HEARTBEAT) // use backup trigger (1 ms later) init_intmodule_heartbeat(); - mixerSchedulerSetPeriod(INTERNAL_MODULE, PXX2_MAX_HEARTBEAT_PERIOD); -#else - mixerSchedulerSetPeriod(INTERNAL_MODULE, PXX2_NO_HEARTBEAT_PERIOD); #endif + mixerSchedulerSetPeriod(INTERNAL_MODULE, PXX2_PERIOD); break; #endif @@ -522,12 +514,6 @@ bool setupPulsesInternalModule(uint8_t protocol) #if defined(HARDWARE_INTERNAL_MODULE) && defined(PXX1) && !defined(INTMODULE_USART) case PROTOCOL_CHANNELS_PXX1_PULSES: intmodulePulsesData.pxx.setupFrame(INTERNAL_MODULE); -#if defined(INTMODULE_HEARTBEAT) - mixerSchedulerResetTimer(); - mixerSchedulerSetPeriod(INTERNAL_MODULE, INTMODULE_PXX1_SERIAL_PERIOD + 1000 /* backup */); -#else - mixerSchedulerSetPeriod(INTERNAL_MODULE, INTMODULE_PXX1_SERIAL_PERIOD); -#endif return true; #endif @@ -545,12 +531,7 @@ bool setupPulsesInternalModule(uint8_t protocol) mixerSchedulerSetPeriod(INTERNAL_MODULE, PXX2_TOOLS_PERIOD); } else { -#if defined(INTMODULE_HEARTBEAT) - mixerSchedulerResetTimer(); - mixerSchedulerSetPeriod(INTERNAL_MODULE, PXX2_MAX_HEARTBEAT_PERIOD); -#else - mixerSchedulerSetPeriod(INTERNAL_MODULE, PXX2_NO_HEARTBEAT_PERIOD); -#endif + mixerSchedulerSetPeriod(INTERNAL_MODULE, PXX2_PERIOD); } return result; } @@ -559,8 +540,6 @@ bool setupPulsesInternalModule(uint8_t protocol) #if defined(PCBTARANIS) && defined(INTERNAL_MODULE_PPM) case PROTOCOL_CHANNELS_PPM: setupPulsesPPMInternalModule(); - // probably useless, as the interval did not change since "enable" function - mixerSchedulerSetPeriod(INTERNAL_MODULE, PPM_PERIOD(INTERNAL_MODULE)); return true; #endif @@ -572,7 +551,6 @@ bool setupPulsesInternalModule(uint8_t protocol) #endif default: - //mixerSchedulerSetPeriod(INTERNAL_MODULE, 10000 /*us*/); // used for USB sim for example return false; } } diff --git a/radio/src/pulses/pxx.h b/radio/src/pulses/pxx.h index a6f78cc54..42e7c6c28 100644 --- a/radio/src/pulses/pxx.h +++ b/radio/src/pulses/pxx.h @@ -31,6 +31,11 @@ #define PXX2_HIGHSPEED_BAUDRATE 450000 #define PXX2_NO_HEARTBEAT_PERIOD 4000/*us*/ #define PXX2_MAX_HEARTBEAT_PERIOD (9000 + 1000)/*us longest period (isrm/accst) + 1ms heartbeat backup*/ +#if defined(INTMODULE_HEARTBEAT) + #define PXX2_PERIOD PXX2_MAX_HEARTBEAT_PERIOD +#else + #define PXX2_PERIOD PXX2_NO_HEARTBEAT_PERIOD +#endif #define PXX2_TOOLS_PERIOD 1000/*us*/ #define PXX2_FRAME_MAXLENGTH 64 @@ -40,10 +45,20 @@ #if defined(PXX_FREQUENCY_HIGH) #define INTMODULE_PXX1_SERIAL_BAUDRATE 450000 - #define INTMODULE_PXX1_SERIAL_PERIOD 4000/*us*/ + #if defined(INTMODULE_HEARTBEAT) + // use backup trigger (1 ms later) + #define INTMODULE_PXX1_SERIAL_PERIOD (4000 + 1000)/*us*/ + #else + #define INTMODULE_PXX1_SERIAL_PERIOD 4000/*us*/ + #endif #else #define INTMODULE_PXX1_SERIAL_BAUDRATE 115200 - #define INTMODULE_PXX1_SERIAL_PERIOD 9000/*us*/ + #if defined(INTMODULE_HEARTBEAT) + // use backup trigger (1 ms later) + #define INTMODULE_PXX1_SERIAL_PERIOD (9000 + 1000)/*us*/ + #else + #define INTMODULE_PXX1_SERIAL_PERIOD 9000/*us*/ + #endif #endif // Used by the Sky9x family boards From 2eef807fbaa18ef99361a9e53e1c83b6cb390862 Mon Sep 17 00:00:00 2001 From: olliw42 Date: Wed, 23 Jun 2021 14:40:18 +0200 Subject: [PATCH 11/24] avoid compile warning --- radio/src/targets/horus/tp_gt911.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/radio/src/targets/horus/tp_gt911.cpp b/radio/src/targets/horus/tp_gt911.cpp index d176b5b71..12a8d8a7a 100644 --- a/radio/src/targets/horus/tp_gt911.cpp +++ b/radio/src/targets/horus/tp_gt911.cpp @@ -686,6 +686,7 @@ bool touchPanelInit(void) } } +#if defined(SIMU) || defined(SEMIHOSTING) || defined(DEBUG) static const char* event2str(uint8_t ev) { switch(ev){ @@ -703,6 +704,7 @@ static const char* event2str(uint8_t ev) return "UNKNOWN"; } } +#endif void touchPanelRead() { From 2c65b21355f697c6ad83842d37002b295e57007a Mon Sep 17 00:00:00 2001 From: rotorman Date: Sat, 10 Jul 2021 10:19:09 +0200 Subject: [PATCH 12/24] Based on PR #408 ff34616 that according to @rcvideoreviews on Discord works. Added: * @olliw42 PR #415 STOP condition fix. * @raphaelcoeffic EXTI_Trigger_Rising * fixed some uint8_t bool confusions * added volatile to touchEventOccured that is set from ISR and accessed from main code * changed to upload GT911 config also if config version is the same --- radio/src/targets/horus/hal.h | 2 +- radio/src/targets/horus/tp_gt911.cpp | 39 ++++++++++++++++++---------- radio/src/targets/horus/tp_gt911.h | 2 +- 3 files changed, 27 insertions(+), 16 deletions(-) diff --git a/radio/src/targets/horus/hal.h b/radio/src/targets/horus/hal.h index 8d7be0da5..cc12222fa 100644 --- a/radio/src/targets/horus/hal.h +++ b/radio/src/targets/horus/hal.h @@ -728,7 +728,7 @@ #define I2C_SCL_GPIO_PinSource GPIO_PinSource8 #define I2C_SDA_GPIO_PinSource GPIO_PinSource9 #endif -#define I2C_SPEED 400000 +#define I2C_SPEED 100000 // Haptic #define HAPTIC_PWM diff --git a/radio/src/targets/horus/tp_gt911.cpp b/radio/src/targets/horus/tp_gt911.cpp index 12a8d8a7a..6b9823dd9 100644 --- a/radio/src/targets/horus/tp_gt911.cpp +++ b/radio/src/targets/horus/tp_gt911.cpp @@ -230,9 +230,9 @@ const uint8_t TOUCH_GT911_Cfg[] = 0x5A, // 0x8053 Screen touch level 0x3C, // 0x8054 Screen touch leave 0x03, // 0x8055 Low power control - 0x05, // 0x8056 Refresh rate - 0x00, // 0x8057 X threshold - 0x00, // 0x8058 Y threshold + 0x0F, // 0x8056 Refresh rate + 0x0A, // 0x8057 X threshold + 0x0A, // 0x8058 Y threshold 0x00, // 0x8059 Reserved 0x00, // 0x805A Reserved 0x11, // 0x805B Space (top, bottom) @@ -403,8 +403,8 @@ const uint8_t TOUCH_GT911_Cfg[] = #endif -uint8_t touchGT911Flag = 0; -uint8_t touchEventOccured = 0; +bool touchGT911Flag = false; +volatile bool touchEventOccured = false; struct TouchData touchData; static void TOUCH_AF_ExtiStop(void) @@ -415,7 +415,7 @@ static void TOUCH_AF_ExtiStop(void) EXTI_StructInit(&EXTI_InitStructure); EXTI_InitStructure.EXTI_Line = TOUCH_INT_EXTI_LINE1; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; - EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling; + EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; EXTI_InitStructure.EXTI_LineCmd = DISABLE; EXTI_Init(&EXTI_InitStructure); @@ -436,7 +436,7 @@ static void TOUCH_AF_ExtiConfig(void) EXTI_StructInit(&EXTI_InitStructure); EXTI_InitStructure.EXTI_Line = TOUCH_INT_EXTI_LINE1; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; - EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling; + EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); @@ -581,6 +581,11 @@ bool I2C_GT911_ReadRegister(u16 reg, uint8_t * buf, uint8_t len) if (!I2C_WaitEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTED)) return false; + // see GP911 data sheet, chapter 6.1.c, page 12, diagram for reading data + I2C_GenerateSTOP(I2C, ENABLE); + if (!I2C_WaitEventCleared(I2C_FLAG_BUSY)) + return false; + I2C_GenerateSTART(I2C, ENABLE); if (!I2C_WaitEvent(I2C_EVENT_MASTER_MODE_SELECT)) return false; @@ -607,7 +612,7 @@ bool I2C_GT911_ReadRegister(u16 reg, uint8_t * buf, uint8_t len) return true; } -uint8_t I2C_GT911_SendConfig(uint8_t mode) +void I2C_GT911_SendConfig(uint8_t mode) { uint8_t buf[2]; uint8_t i = 0; @@ -619,12 +624,12 @@ uint8_t I2C_GT911_SendConfig(uint8_t mode) buf[0] = (~buf[0]) + 1; I2C_GT911_WriteRegister(GT_CFGS_REG, (uint8_t *) TOUCH_GT911_Cfg, sizeof(TOUCH_GT911_Cfg));// I2C_GT911_WriteRegister(GT_CHECK_REG, buf, 2);//write checksum - return 0; } void touchPanelDeInit(void) { TOUCH_AF_ExtiStop(); + touchGT911Flag = false; } bool touchPanelInit(void) @@ -666,7 +671,7 @@ bool touchPanelInit(void) I2C_GT911_ReadRegister(GT_CFGS_REG, tmp, 1); TRACE("Chip config Ver:%x\r\n", tmp[0]); - if (tmp[0] < GT911_CFG_NUMER) //Config ver + if (tmp[0] <= GT911_CFG_NUMER) //Config ver { TRACE("Sending new config %d", GT911_CFG_NUMER); I2C_GT911_SendConfig(1); @@ -713,12 +718,15 @@ void touchPanelRead() if (!touchEventOccured) return; - touchEventOccured = 0; + touchEventOccured = false; uint32_t startReadStatus = RTOS_GET_MS(); do { if (!I2C_GT911_ReadRegister(GT911_READ_XY_REG, &state, 1)) { - TRACE("GT911 I2C read error"); + ledRed(); + TRACE("GT911 I2C read XY error"); + touchPanelDeInit(); + touchPanelInit(); return; } @@ -736,7 +744,10 @@ void touchPanelRead() if (pointsCount > 0 && pointsCount <= GT911_MAX_TP) { if (!I2C_GT911_ReadRegister(GT911_READ_XY_REG + 1, touchData.data, pointsCount * sizeof(TouchPoint))) { - TRACE("GT911 I2C read error"); + ledRed(); + TRACE("GT911 I2C data read error"); + touchPanelDeInit(); + touchPanelInit(); return; } if (touchState.event == TE_NONE || touchState.event == TE_UP || @@ -779,7 +790,7 @@ extern "C" void TOUCH_INT_EXTI_IRQHandler1(void) // on touch turn the light on resetBacklightTimeout(); } - touchEventOccured = 1; + touchEventOccured = true; EXTI_ClearITPendingBit(TOUCH_INT_EXTI_LINE1); } } diff --git a/radio/src/targets/horus/tp_gt911.h b/radio/src/targets/horus/tp_gt911.h index 1a3371d31..b8f59677f 100644 --- a/radio/src/targets/horus/tp_gt911.h +++ b/radio/src/targets/horus/tp_gt911.h @@ -22,7 +22,7 @@ #define HAS_TOUCH_PANEL() touchGT911Flag == true -extern uint8_t touchGT911Flag; +extern bool touchGT911Flag; extern bool touchPanelInit(); void touchPanelRead(); From 8c7f3cecec21c5b541f462d87c18736bcaa7336c Mon Sep 17 00:00:00 2001 From: rotorman Date: Sat, 10 Jul 2021 19:05:23 +0200 Subject: [PATCH 13/24] * removed red LED * added GT911 fw version and hiccup cound output to analogs page * changed I2C to 400 kHz * changed X Y threshold to 1 * added trace output * fixed bool / uint8_t errors --- radio/src/gui/colorlcd/radio_diaganas.cpp | 10 +- radio/src/targets/horus/hal.h | 2 +- radio/src/targets/horus/tp_gt911.cpp | 140 ++++++++++++++++++---- radio/src/targets/horus/tp_gt911.h | 2 + radio/src/targets/nv14/touch_driver.cpp | 2 +- 5 files changed, 132 insertions(+), 24 deletions(-) diff --git a/radio/src/gui/colorlcd/radio_diaganas.cpp b/radio/src/gui/colorlcd/radio_diaganas.cpp index 3b24c3cd6..4de2b94d1 100644 --- a/radio/src/gui/colorlcd/radio_diaganas.cpp +++ b/radio/src/gui/colorlcd/radio_diaganas.cpp @@ -49,7 +49,7 @@ class RadioAnalogsDiagsWindow: public Window { } #if defined(HARDWARE_TOUCH) - constexpr coord_t y = MENU_CONTENT_TOP + 6 * FH; + constexpr coord_t y = MENU_CONTENT_TOP + 5 * FH; if (touchState.event != TE_NONE && touchState.event != TE_SLIDE_END) { coord_t x = dc->drawText(MENUS_MARGIN_LEFT, y, STR_TOUCH_PANEL); @@ -59,6 +59,14 @@ class RadioAnalogsDiagsWindow: public Window { dc->drawLine(touchState.x - 10, touchState.y - 8 - parent->top(), touchState.x + 10, touchState.y + 8 - parent->top(), SOLID, 0); dc->drawLine(touchState.x - 10, touchState.y + 8 - parent->top(), touchState.x + 10, touchState.y - 8- parent->top(), SOLID, 0); } +#if !defined(SIMU) + constexpr coord_t y1 = MENU_CONTENT_TOP + 6 * FH; + constexpr coord_t x1 = MENUS_MARGIN_LEFT; + dc->drawText(x1, y1, "Touch GT911 FW ver:"); + dc->drawNumber(x1 + 150, y1, touchGT911fwver, LEFT, 4); + dc->drawText(x1 + 200, y1, "Hiccups:"); + dc->drawNumber(x1 + 260, y1, touchGT911hiccups, LEFT, 5); +#endif #endif }; diff --git a/radio/src/targets/horus/hal.h b/radio/src/targets/horus/hal.h index cc12222fa..8d7be0da5 100644 --- a/radio/src/targets/horus/hal.h +++ b/radio/src/targets/horus/hal.h @@ -728,7 +728,7 @@ #define I2C_SCL_GPIO_PinSource GPIO_PinSource8 #define I2C_SDA_GPIO_PinSource GPIO_PinSource9 #endif -#define I2C_SPEED 100000 +#define I2C_SPEED 400000 // Haptic #define HAPTIC_PWM diff --git a/radio/src/targets/horus/tp_gt911.cpp b/radio/src/targets/horus/tp_gt911.cpp index 6b9823dd9..3bd973c24 100644 --- a/radio/src/targets/horus/tp_gt911.cpp +++ b/radio/src/targets/horus/tp_gt911.cpp @@ -39,9 +39,9 @@ const uint8_t TOUCH_GT911_Cfg[] = { 0x50, // 0x8053 Screen touch level 0x3C, // 0x8054 Screen touch leave 0x03, // 0x8055 Low power control - 0x05, // 0x8056 Refresh rate - 0x00, // 0x8057 X threshold - 0x00, // 0x8058 Y threshold + 0x0F, // 0x8056 Refresh rate + 0x01, // 0x8057 X threshold + 0x01, // 0x8058 Y threshold 0x00, // 0x8059 Reserved 0x00, // 0x805A Reserved 0x00, // 0x805B Space (top, bottom) @@ -231,8 +231,8 @@ const uint8_t TOUCH_GT911_Cfg[] = 0x3C, // 0x8054 Screen touch leave 0x03, // 0x8055 Low power control 0x0F, // 0x8056 Refresh rate - 0x0A, // 0x8057 X threshold - 0x0A, // 0x8058 Y threshold + 0x01, // 0x8057 X threshold + 0x01, // 0x8058 Y threshold 0x00, // 0x8059 Reserved 0x00, // 0x805A Reserved 0x11, // 0x805B Space (top, bottom) @@ -404,8 +404,10 @@ const uint8_t TOUCH_GT911_Cfg[] = #endif bool touchGT911Flag = false; -volatile bool touchEventOccured = false; +volatile static bool touchEventOccured = false; struct TouchData touchData; +uint16_t touchGT911fwver = 0; +uint16_t touchGT911hiccups = 0; static void TOUCH_AF_ExtiStop(void) { @@ -484,6 +486,8 @@ void TOUCH_AF_INT_Change(void) void I2C_Init() { + TRACE("I2C Init"); + I2C_DeInit(I2C); GPIO_InitTypeDef GPIO_InitStructure; @@ -529,33 +533,55 @@ bool I2C_WaitEventCleared(uint32_t event) uint8_t I2C_GT911_WriteRegister(uint16_t reg, uint8_t * buf, uint8_t len) { if (!I2C_WaitEventCleared(I2C_FLAG_BUSY)) + { + TRACE("I2C WRITE ERROR: busy timeout"); return false; + } I2C_GenerateSTART(I2C, ENABLE); if (!I2C_WaitEvent(I2C_EVENT_MASTER_MODE_SELECT)) + { + TRACE("I2C WRITE ERROR: could not issue start"); return false; + } I2C_Send7bitAddress(I2C, GT_CMD_WR, I2C_Direction_Transmitter); if (!I2C_WaitEvent(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) + { + TRACE("I2C WRITE ERROR: could not send device address"); return false; + } I2C_SendData(I2C, (uint8_t)((reg & 0xFF00) >> 8)); if (!I2C_WaitEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTING)) + { + TRACE("I2C WRITE ERROR: could not send register high address"); return false; + } + I2C_SendData(I2C, (uint8_t)(reg & 0x00FF)); if (!I2C_WaitEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTING)) + { + TRACE("I2C WRITE ERROR: could not send register low address"); return false; + } /* While there is data to be written */ while (len--) { I2C_SendData(I2C, *buf); if (!I2C_WaitEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTING)) + { + TRACE("I2C WRITE ERROR: could not send data with %u bytes remaining", len+1 ); return false; + } buf++; } if (!I2C_WaitEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTED)) + { + TRACE("I2C WRITE ERROR: waiting for BTF failed."); return false; + } I2C_GenerateSTOP(I2C, ENABLE); return true; @@ -564,35 +590,61 @@ uint8_t I2C_GT911_WriteRegister(uint16_t reg, uint8_t * buf, uint8_t len) bool I2C_GT911_ReadRegister(u16 reg, uint8_t * buf, uint8_t len) { if (!I2C_WaitEventCleared(I2C_FLAG_BUSY)) + { + TRACE("I2C READ ERROR: busy timeout"); return false; + } I2C_GenerateSTART(I2C, ENABLE); if (!I2C_WaitEvent(I2C_EVENT_MASTER_MODE_SELECT)) + { + TRACE("I2C READ ERROR: could not issue first step start"); return false; + } I2C_Send7bitAddress(I2C, GT_CMD_WR, I2C_Direction_Transmitter); if (!I2C_WaitEvent(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) + { + TRACE("I2C READ ERROR: could not send first step device address"); return false; + } I2C_SendData(I2C, (uint8_t)((reg & 0xFF00) >> 8)); if (!I2C_WaitEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTING)) + { + TRACE("I2C READ ERROR: could not send register high address"); return false; + } + I2C_SendData(I2C, (uint8_t)(reg & 0x00FF)); if (!I2C_WaitEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTED)) + { + TRACE("I2C READ ERROR: could not send register low address"); return false; + } - // see GP911 data sheet, chapter 6.1.c, page 12, diagram for reading data + // According to GP911 data sheet, repeated start is not listed, so we do full stop. + // See chapter 6.1.c, page 12, diagram for reading data I2C_GenerateSTOP(I2C, ENABLE); if (!I2C_WaitEventCleared(I2C_FLAG_BUSY)) + { + TRACE("I2C READ ERROR: timeout waiting for first stop"); return false; + } I2C_GenerateSTART(I2C, ENABLE); if (!I2C_WaitEvent(I2C_EVENT_MASTER_MODE_SELECT)) + { + TRACE("I2C READ ERROR: could not issue second step start"); return false; + } I2C_Send7bitAddress(I2C, GT_CMD_RD, I2C_Direction_Receiver); if (!I2C_WaitEvent(I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)) + { + TRACE("I2C READ ERROR: could not send second step device address"); return false; + } if (len > 1) { I2C_AcknowledgeConfig(I2C, ENABLE); @@ -600,10 +652,13 @@ bool I2C_GT911_ReadRegister(u16 reg, uint8_t * buf, uint8_t len) while (len) { if (len == 1) { - I2C_AcknowledgeConfig(I2C, DISABLE); + I2C_AcknowledgeConfig(I2C, DISABLE); // Send NACK on last byte } if (!I2C_WaitEvent(I2C_EVENT_MASTER_BYTE_RECEIVED)) + { + TRACE("I2C READ ERROR: could not read data with %u bytes remaining", len ); return false; + } *buf++ = I2C_ReceiveData(I2C); len--; } @@ -612,18 +667,30 @@ bool I2C_GT911_ReadRegister(u16 reg, uint8_t * buf, uint8_t len) return true; } -void I2C_GT911_SendConfig(uint8_t mode) +bool I2C_GT911_SendConfig(void) { uint8_t buf[2]; uint8_t i = 0; buf[0] = 0; - buf[1] = mode; + buf[1] = 1; + bool bResult = true; + for (i = 0; i < sizeof(TOUCH_GT911_Cfg); i++) buf[0] += TOUCH_GT911_Cfg[i];//check sum buf[0] = (~buf[0]) + 1; - I2C_GT911_WriteRegister(GT_CFGS_REG, (uint8_t *) TOUCH_GT911_Cfg, sizeof(TOUCH_GT911_Cfg));// - I2C_GT911_WriteRegister(GT_CHECK_REG, buf, 2);//write checksum + if (!I2C_GT911_WriteRegister(GT_CFGS_REG, (uint8_t *) TOUCH_GT911_Cfg, sizeof(TOUCH_GT911_Cfg))) + { + TRACE("GT911 ERROR: write config failed"); + bResult = false; + } + + if (!I2C_GT911_WriteRegister(GT_CHECK_REG, buf, 2)) //write checksum + { + TRACE("GT911 ERROR: write config checksum failed"); + bResult = false; + } + return bResult; } void touchPanelDeInit(void) @@ -661,29 +728,55 @@ bool touchPanelInit(void) delay_ms(50); TRACE("Reading Touch registry"); - I2C_GT911_ReadRegister(GT_PID_REG, tmp, 4); + if (!I2C_GT911_ReadRegister(GT_PID_REG, tmp, 4)) + { + TRACE("GT911 ERROR: Product ID read failed"); + } if (strcmp((char *) tmp, "911") == 0) //ID==9147 { TRACE("GT911 chip detected"); tmp[0] = 0X02; - I2C_GT911_WriteRegister(GT_CTRL_REG, tmp, 1); - I2C_GT911_ReadRegister(GT_CFGS_REG, tmp, 1); + if (!I2C_GT911_WriteRegister(GT_CTRL_REG, tmp, 1)) + { + TRACE("GT911 ERROR: write to control register failed"); + } + if (!I2C_GT911_ReadRegister(GT_CFGS_REG, tmp, 1)) + { + TRACE("GT911 ERROR: configration register read failed"); + } - TRACE("Chip config Ver:%x\r\n", tmp[0]); + TRACE("Chip config Ver:%x", tmp[0]); if (tmp[0] <= GT911_CFG_NUMER) //Config ver { TRACE("Sending new config %d", GT911_CFG_NUMER); - I2C_GT911_SendConfig(1); + if (!I2C_GT911_SendConfig()) + { + TRACE("GT911 ERROR: sending configration failed"); + } + } + + if (!I2C_GT911_ReadRegister(GT911_FIRMWARE_VERSION_REG, tmp, 2)) + { + TRACE("GT911 ERROR: reading firmware version failed"); + } + else + { + touchGT911fwver = (tmp[1] << 8) + tmp[0]; + TRACE("GT911 FW version: %u", touchGT911fwver); } delay_ms(10); tmp[0] = 0X00; - I2C_GT911_WriteRegister(GT_CTRL_REG, tmp, 1); //end reset + if (!I2C_GT911_WriteRegister(GT_CTRL_REG, tmp, 1)) //end reset + { + TRACE("GT911 ERROR: write to control register failed"); + } touchGT911Flag = true; TOUCH_AF_ExtiConfig(); + return true; } TRACE("GT911 chip NOT FOUND"); @@ -723,7 +816,8 @@ void touchPanelRead() uint32_t startReadStatus = RTOS_GET_MS(); do { if (!I2C_GT911_ReadRegister(GT911_READ_XY_REG, &state, 1)) { - ledRed(); + //ledRed(); + touchGT911hiccups++; TRACE("GT911 I2C read XY error"); touchPanelDeInit(); touchPanelInit(); @@ -744,7 +838,8 @@ void touchPanelRead() if (pointsCount > 0 && pointsCount <= GT911_MAX_TP) { if (!I2C_GT911_ReadRegister(GT911_READ_XY_REG + 1, touchData.data, pointsCount * sizeof(TouchPoint))) { - ledRed(); + //ledRed(); + touchGT911hiccups++; TRACE("GT911 I2C data read error"); touchPanelDeInit(); touchPanelInit(); @@ -778,7 +873,10 @@ void touchPanelRead() } uint8_t zero = 0; - I2C_GT911_WriteRegister(GT911_READ_XY_REG, &zero, 1); + if (!I2C_GT911_WriteRegister(GT911_READ_XY_REG, &zero, 1)) + { + TRACE("GT911 ERROR: clearing XY register failed"); + } TRACE("touch event = %s", event2str(touchState.event)); } diff --git a/radio/src/targets/horus/tp_gt911.h b/radio/src/targets/horus/tp_gt911.h index b8f59677f..cf0163712 100644 --- a/radio/src/targets/horus/tp_gt911.h +++ b/radio/src/targets/horus/tp_gt911.h @@ -23,6 +23,8 @@ #define HAS_TOUCH_PANEL() touchGT911Flag == true extern bool touchGT911Flag; +extern uint16_t touchGT911fwver; +extern uint16_t touchGT911hiccups; extern bool touchPanelInit(); void touchPanelRead(); diff --git a/radio/src/targets/nv14/touch_driver.cpp b/radio/src/targets/nv14/touch_driver.cpp index 72234dd0d..d93829674 100644 --- a/radio/src/targets/nv14/touch_driver.cpp +++ b/radio/src/targets/nv14/touch_driver.cpp @@ -21,7 +21,7 @@ #include "opentx.h" #include "touch_driver.h" -static bool touchEventOccured; +volatile static bool touchEventOccured; #define FT6x06_MAX_INSTANCE 1 From 49ae57d370e87155f47d57f591b3800d2a9444eb Mon Sep 17 00:00:00 2001 From: Raphael Coeffic Date: Sun, 11 Jul 2021 13:03:53 +0200 Subject: [PATCH 14/24] Take account of some corner cases in I2C multi-byte read See https://github.com/geoffreymbrown/STM32-Template/blob/master/Library/i2c.c#L39 and RM0090 p851-853. --- radio/src/targets/horus/tp_gt911.cpp | 106 +++++++++++++++++++++++---- 1 file changed, 93 insertions(+), 13 deletions(-) diff --git a/radio/src/targets/horus/tp_gt911.cpp b/radio/src/targets/horus/tp_gt911.cpp index 3bd973c24..ad7262924 100644 --- a/radio/src/targets/horus/tp_gt911.cpp +++ b/radio/src/targets/horus/tp_gt911.cpp @@ -512,6 +512,15 @@ void I2C_Init() GPIO_Init(I2C_GPIO, &GPIO_InitStructure); } +bool I2C_WaitFlag(uint32_t flag) +{ + uint32_t timeout = I2C_TIMEOUT_MAX; + while (!I2C_GetFlagStatus(I2C, flag)) { + if ((timeout--) == 0) return false; + } + return true; +} + bool I2C_WaitEvent(uint32_t event) { uint32_t timeout = I2C_TIMEOUT_MAX; @@ -632,6 +641,10 @@ bool I2C_GT911_ReadRegister(u16 reg, uint8_t * buf, uint8_t len) return false; } + // Enable Acknowledgement, clear POS flag + I2C_AcknowledgeConfig(I2C, ENABLE); + I2C_NACKPositionConfig(I2C, I2C_NACKPosition_Current); + I2C_GenerateSTART(I2C, ENABLE); if (!I2C_WaitEvent(I2C_EVENT_MASTER_MODE_SELECT)) { @@ -646,24 +659,91 @@ bool I2C_GT911_ReadRegister(u16 reg, uint8_t * buf, uint8_t len) return false; } - if (len > 1) { - I2C_AcknowledgeConfig(I2C, ENABLE); - } + if (len == 1) { + // Clear Ack bit + I2C_AcknowledgeConfig(I2C, DISABLE); - while (len) { - if (len == 1) { - I2C_AcknowledgeConfig(I2C, DISABLE); // Send NACK on last byte - } - if (!I2C_WaitEvent(I2C_EVENT_MASTER_BYTE_RECEIVED)) - { - TRACE("I2C READ ERROR: could not read data with %u bytes remaining", len ); + // EV6_1 -- must be atomic -- Clear ADDR, generate STOP + __disable_irq(); + (void) I2C->SR2; + I2C_GenerateSTOP(I2C,ENABLE); + __enable_irq(); + + // Receive data EV7 + if(!I2C_WaitFlag(I2C_FLAG_RXNE)) { + TRACE("I2C READ ERROR: timeout waiting for RxNE"); + I2C_Init(); return false; } + *buf++ = I2C_ReceiveData(I2C); - len--; + } + else if (len == 2) { + + // Set POS flag + I2C_NACKPositionConfig(I2C, I2C_NACKPosition_Next); + + // EV6_1 -- must be atomic and in this order + __disable_irq(); + (void) I2C->SR2; // Clear ADDR flag + I2C_AcknowledgeConfig(I2C, DISABLE); // Clear Ack bit + __enable_irq(); + + // EV7_3 -- Wait for BTF, program stop, read data twice + if (!I2C_WaitFlag(I2C_FLAG_BTF)) { + TRACE("I2C READ ERROR: timeout waiting for BTF"); + I2C_Init(); + return false; + } + + __disable_irq(); + I2C_GenerateSTOP(I2C,ENABLE); + *buf++ = I2C->DR; + __enable_irq(); + + *buf++ = I2C->DR; + } + else { + + (void) I2C->SR2; // Clear ADDR flag + while (len-- != 3) { + // EV7 -- cannot guarantee 1 transfer completion time, wait for BTF + // instead of RXNE + if (!I2C_WaitFlag(I2C_FLAG_BTF)) { + TRACE("I2C READ ERROR: timeout waiting for BTF"); + I2C_Init(); + return false; + } + + *buf++ = I2C_ReceiveData(I2C); + } + + // Data N-2 in DR, data N-1 in shift register, + // SCL stretched low until data N-2 is read + if (!I2C_WaitFlag(I2C_FLAG_BTF)) { + TRACE("I2C READ ERROR: timeout waiting for BTF"); + I2C_Init(); + return false; + } + + I2C_AcknowledgeConfig(I2C, DISABLE); // clear ack bit + *buf++ = I2C_ReceiveData(I2C); // receive byte N-2 + + // Wait for BTF, program stop, read data twice + if (!I2C_WaitFlag(I2C_FLAG_BTF)) { + TRACE("I2C READ ERROR: timeout waiting for BTF"); + I2C_Init(); + return false; + } + + __disable_irq(); + I2C_GenerateSTOP(I2C,ENABLE); + *buf++ = I2C->DR; + __enable_irq(); + + *buf++ = I2C->DR; } - I2C_GenerateSTOP(I2C, ENABLE); return true; } @@ -743,7 +823,7 @@ bool touchPanelInit(void) } if (!I2C_GT911_ReadRegister(GT_CFGS_REG, tmp, 1)) { - TRACE("GT911 ERROR: configration register read failed"); + TRACE("GT911 ERROR: configuration register read failed"); } TRACE("Chip config Ver:%x", tmp[0]); From 52acfcd20db157906b315449ce6bbc22ec5b2660 Mon Sep 17 00:00:00 2001 From: Raphael Coeffic Date: Sun, 11 Jul 2021 17:43:31 +0200 Subject: [PATCH 15/24] Quick & dirty polling mode (don't care about INT line) --- radio/src/targets/horus/tp_gt911.cpp | 6 +++--- radio/src/targets/horus/tp_gt911.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/radio/src/targets/horus/tp_gt911.cpp b/radio/src/targets/horus/tp_gt911.cpp index ad7262924..0802ba3f4 100644 --- a/radio/src/targets/horus/tp_gt911.cpp +++ b/radio/src/targets/horus/tp_gt911.cpp @@ -888,10 +888,10 @@ void touchPanelRead() { uint8_t state = 0; - if (!touchEventOccured) - return; + // if (!touchEventOccured) + // return; - touchEventOccured = false; + // touchEventOccured = false; uint32_t startReadStatus = RTOS_GET_MS(); do { diff --git a/radio/src/targets/horus/tp_gt911.h b/radio/src/targets/horus/tp_gt911.h index cf0163712..2a051e847 100644 --- a/radio/src/targets/horus/tp_gt911.h +++ b/radio/src/targets/horus/tp_gt911.h @@ -30,7 +30,7 @@ extern bool touchPanelInit(); void touchPanelRead(); bool touchPanelEventOccured(); -#define GT911_TIMEOUT 20 // 20ms +#define GT911_TIMEOUT 3 // 3ms #define GT911_MAX_TP 5 #define GT911_CFG_NUMER 0x6C From bdee14297e3e4adc8a3074151d56b2fa7c952bdd Mon Sep 17 00:00:00 2001 From: Raphael Coeffic Date: Fri, 9 Jul 2021 12:42:34 +0200 Subject: [PATCH 16/24] [color] Fix vario settings range --- radio/src/gui/colorlcd/model_telemetry.cpp | 31 ++++++++++++++++++---- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/radio/src/gui/colorlcd/model_telemetry.cpp b/radio/src/gui/colorlcd/model_telemetry.cpp index d945293bc..3ae56b644 100644 --- a/radio/src/gui/colorlcd/model_telemetry.cpp +++ b/radio/src/gui/colorlcd/model_telemetry.cpp @@ -552,13 +552,34 @@ void ModelTelemetryPage::build(FormWindow * window, int8_t focusSensorIndex) }); grid.nextLine(); new StaticText(window, grid.getLabelSlot(true), STR_RANGE); - new NumberEdit(window, grid.getFieldSlot(2, 0), -7, 7, GET_SET_WITH_OFFSET(g_model.varioData.min, -10)); - new NumberEdit(window, grid.getFieldSlot(2, 1), -7, 7, GET_SET_WITH_OFFSET(g_model.varioData.max, 10)); + + auto vMin = new NumberEdit(window, grid.getFieldSlot(2, 0), -17, 17, + GET_SET_WITH_OFFSET(g_model.varioData.min, -10)); + vMin->setAvailableHandler( + [](int val) { return val < g_model.varioData.max + 10; }); + + auto vMax = new NumberEdit(window, grid.getFieldSlot(2, 1), -17, 17, + GET_SET_WITH_OFFSET(g_model.varioData.max, 10)); + vMax->setAvailableHandler( + [](int val) { return g_model.varioData.min - 10 < val; }); + grid.nextLine(); new StaticText(window, grid.getLabelSlot(true), STR_CENTER); - new NumberEdit(window, grid.getFieldSlot(3, 0), -7, 7, GET_SET_WITH_OFFSET(g_model.varioData.min, -5), 0, PREC1); - new NumberEdit(window, grid.getFieldSlot(3, 1), -7, 7, GET_SET_WITH_OFFSET(g_model.varioData.max, 5), 0, PREC1); - new Choice(window, grid.getFieldSlot(3, 2), STR_VVARIOCENTER, 0, 1, GET_SET_DEFAULT(g_model.varioData.centerSilent)); + + auto cMin = new NumberEdit( + window, grid.getFieldSlot(3, 0), -15, 15, + GET_SET_WITH_OFFSET(g_model.varioData.centerMin, -5), 0, PREC1); + cMin->setAvailableHandler( + [](int val) { return val < g_model.varioData.centerMax + 5; }); + + auto cMax = new NumberEdit( + window, grid.getFieldSlot(3, 1), -15, 15, + GET_SET_WITH_OFFSET(g_model.varioData.centerMax, 5), 0, PREC1); + cMax->setAvailableHandler( + [](int val) { return g_model.varioData.centerMin - 5 < val; }); + + new Choice(window, grid.getFieldSlot(3, 2), STR_VVARIOCENTER, 0, 1, + GET_SET_DEFAULT(g_model.varioData.centerSilent)); grid.nextLine(); window->setInnerHeight(grid.getWindowHeight()); From 9cd44774957a793abcbe06457da7780f164d4564 Mon Sep 17 00:00:00 2001 From: Peter Feerick Date: Sat, 10 Jul 2021 13:28:02 +1000 Subject: [PATCH 17/24] Save current category when selecting model --- radio/src/gui/colorlcd/model_select.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/radio/src/gui/colorlcd/model_select.cpp b/radio/src/gui/colorlcd/model_select.cpp index 909b2cc5c..c91515b48 100644 --- a/radio/src/gui/colorlcd/model_select.cpp +++ b/radio/src/gui/colorlcd/model_select.cpp @@ -244,6 +244,7 @@ class ModelCategoryPageBody : public FormWindow storageCheck(true); modelslist.setCurrentModel(model); + modelslist.setCurrentCategory(category); update(); }); } From da661a6e031bde68e093ccc0bfb6e44368c19026 Mon Sep 17 00:00:00 2001 From: Peter Feerick Date: Sat, 10 Jul 2021 13:30:48 +1000 Subject: [PATCH 18/24] Clear signed/unsigned comparision compiler warning STL list is uint, vs int of index being compared --- radio/src/gui/colorlcd/model_select.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radio/src/gui/colorlcd/model_select.cpp b/radio/src/gui/colorlcd/model_select.cpp index c91515b48..3d4201ec9 100644 --- a/radio/src/gui/colorlcd/model_select.cpp +++ b/radio/src/gui/colorlcd/model_select.cpp @@ -272,7 +272,7 @@ class ModelCategoryPageBody : public FormWindow .c_str(), [=] { modelslist.removeModel(category, model); - update(index < category->size() - 1 ? index : index - 1); + update((unsigned)index < category->size() - 1 ? index : index - 1); }); }); } From 068c1a0f11be5fb74d34fb70009c0f56b650a054 Mon Sep 17 00:00:00 2001 From: Raphael Coeffic Date: Mon, 12 Jul 2021 08:58:54 +0200 Subject: [PATCH 19/24] Renamed "hiccups" to "TSI2CEvents" And use uint32_t for counting them. --- radio/src/gui/colorlcd/radio_diaganas.cpp | 10 +++++----- radio/src/targets/horus/tp_gt911.cpp | 2 +- radio/src/targets/horus/tp_gt911.h | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/radio/src/gui/colorlcd/radio_diaganas.cpp b/radio/src/gui/colorlcd/radio_diaganas.cpp index 4de2b94d1..939b113b2 100644 --- a/radio/src/gui/colorlcd/radio_diaganas.cpp +++ b/radio/src/gui/colorlcd/radio_diaganas.cpp @@ -61,11 +61,11 @@ class RadioAnalogsDiagsWindow: public Window { } #if !defined(SIMU) constexpr coord_t y1 = MENU_CONTENT_TOP + 6 * FH; - constexpr coord_t x1 = MENUS_MARGIN_LEFT; - dc->drawText(x1, y1, "Touch GT911 FW ver:"); - dc->drawNumber(x1 + 150, y1, touchGT911fwver, LEFT, 4); - dc->drawText(x1 + 200, y1, "Hiccups:"); - dc->drawNumber(x1 + 260, y1, touchGT911hiccups, LEFT, 5); + coord_t x1 = MENUS_MARGIN_LEFT; + x1 = dc->drawText(x1, y1, "Touch GT911 FW ver:") + 8; + x1 = dc->drawNumber(x1, y1, touchGT911fwver, LEFT, 4) + 16; + x1 = dc->drawText(x1, y1, "TSI2CEvents:") + 4; + dc->drawNumber(x1, y1, touchGT911hiccups, LEFT, 5); #endif #endif }; diff --git a/radio/src/targets/horus/tp_gt911.cpp b/radio/src/targets/horus/tp_gt911.cpp index 0802ba3f4..8dd01b49b 100644 --- a/radio/src/targets/horus/tp_gt911.cpp +++ b/radio/src/targets/horus/tp_gt911.cpp @@ -407,7 +407,7 @@ bool touchGT911Flag = false; volatile static bool touchEventOccured = false; struct TouchData touchData; uint16_t touchGT911fwver = 0; -uint16_t touchGT911hiccups = 0; +uint32_t touchGT911hiccups = 0; static void TOUCH_AF_ExtiStop(void) { diff --git a/radio/src/targets/horus/tp_gt911.h b/radio/src/targets/horus/tp_gt911.h index 2a051e847..0651dc1b6 100644 --- a/radio/src/targets/horus/tp_gt911.h +++ b/radio/src/targets/horus/tp_gt911.h @@ -24,7 +24,7 @@ extern bool touchGT911Flag; extern uint16_t touchGT911fwver; -extern uint16_t touchGT911hiccups; +extern uint32_t touchGT911hiccups; extern bool touchPanelInit(); void touchPanelRead(); From bb2ed31e5658f5301593398b3cbc214c636c15bd Mon Sep 17 00:00:00 2001 From: olliw42 Date: Mon, 12 Jul 2021 08:04:37 +0200 Subject: [PATCH 20/24] update submodule libopenui --- radio/src/thirdparty/libopenui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radio/src/thirdparty/libopenui b/radio/src/thirdparty/libopenui index 05067daa6..014e87b9f 160000 --- a/radio/src/thirdparty/libopenui +++ b/radio/src/thirdparty/libopenui @@ -1 +1 @@ -Subproject commit 05067daa62127ae1bfaa0a2f518d8249b606a4d3 +Subproject commit 014e87b9fc5dd345a3619f375b84c5e9747a398f From 621dddf1eefa27b40887d8b48cdf0e4beea4b3bb Mon Sep 17 00:00:00 2001 From: olliw42 Date: Mon, 12 Jul 2021 08:24:15 +0200 Subject: [PATCH 21/24] add extra_chars to model setup, model name text edit field --- radio/src/gui/colorlcd/model_setup.cpp | 3 ++- radio/src/gui/colorlcd/textedits.h | 10 +++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/radio/src/gui/colorlcd/model_setup.cpp b/radio/src/gui/colorlcd/model_setup.cpp index 342199fb5..846274763 100644 --- a/radio/src/gui/colorlcd/model_setup.cpp +++ b/radio/src/gui/colorlcd/model_setup.cpp @@ -1033,7 +1033,8 @@ void ModelSetupPage::build(FormWindow * window) // Model name new StaticText(window, grid.getLabelSlot(), STR_MODELNAME); - auto text = new RadioTextEdit(window, grid.getFieldSlot(), g_model.header.name, sizeof(g_model.header.name)); + auto text = new RadioTextEdit(window, grid.getFieldSlot(), g_model.header.name, sizeof(g_model.header.name), + 0, "_-.,:;<=>"); text->setChangeHandler([=] { modelslist.load(); auto model = modelslist.getCurrentModel(); diff --git a/radio/src/gui/colorlcd/textedits.h b/radio/src/gui/colorlcd/textedits.h index 15e3e2e79..b8dddc97e 100644 --- a/radio/src/gui/colorlcd/textedits.h +++ b/radio/src/gui/colorlcd/textedits.h @@ -27,8 +27,8 @@ class ModelTextEdit: public TextEdit { public: - ModelTextEdit(Window * parent, const rect_t & rect, char * value, uint8_t length, LcdFlags windowFlags = 0): - TextEdit(parent, rect, value, length, windowFlags) + ModelTextEdit(Window * parent, const rect_t & rect, char * value, uint8_t length, LcdFlags windowFlags = 0, const char * extra_chars = nullptr): + TextEdit(parent, rect, value, length, windowFlags, extra_chars) { setChangeHandler([](){ storageDirty(EE_MODEL); @@ -39,11 +39,11 @@ class ModelTextEdit: public TextEdit class RadioTextEdit: public TextEdit { public: - RadioTextEdit(Window * parent, const rect_t & rect, char * value, uint8_t length, LcdFlags windowFlags = 0): - TextEdit(parent, rect, value, length, windowFlags) + RadioTextEdit(Window * parent, const rect_t & rect, char * value, uint8_t length, LcdFlags windowFlags = 0, const char * extra_chars = nullptr): + TextEdit(parent, rect, value, length, windowFlags, extra_chars) { setChangeHandler([](){ storageDirty(EE_GENERAL); }); } -}; \ No newline at end of file +}; From 24f85545904ff97e6901ac23247489444ccb91cb Mon Sep 17 00:00:00 2001 From: olliw42 Date: Mon, 12 Jul 2021 09:01:12 +0200 Subject: [PATCH 22/24] adopt comment, use const char --- radio/src/gui/colorlcd/model_setup.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/radio/src/gui/colorlcd/model_setup.cpp b/radio/src/gui/colorlcd/model_setup.cpp index 846274763..a69df8222 100644 --- a/radio/src/gui/colorlcd/model_setup.cpp +++ b/radio/src/gui/colorlcd/model_setup.cpp @@ -1026,6 +1026,8 @@ void onBindMenu(const char * result) const char * STR_TIMER_MODES[] = {"OFF", "ON", "Start", "Throttle", "Throttle %", "Throttle Start"}; +const char MODEL_NAME_EXTRA_CHARS[] = "_-.,:;<=>"; + void ModelSetupPage::build(FormWindow * window) { FormGridLayout grid; @@ -1034,7 +1036,7 @@ void ModelSetupPage::build(FormWindow * window) // Model name new StaticText(window, grid.getLabelSlot(), STR_MODELNAME); auto text = new RadioTextEdit(window, grid.getFieldSlot(), g_model.header.name, sizeof(g_model.header.name), - 0, "_-.,:;<=>"); + 0, MODEL_NAME_EXTRA_CHARS); text->setChangeHandler([=] { modelslist.load(); auto model = modelslist.getCurrentModel(); From cf4b5b014e392e2857bd85e34dcc0b15a0328ae9 Mon Sep 17 00:00:00 2001 From: olliw42 Date: Tue, 13 Jul 2021 02:59:33 +0200 Subject: [PATCH 23/24] avoid compile warning --- radio/src/gui/colorlcd/model_select.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radio/src/gui/colorlcd/model_select.cpp b/radio/src/gui/colorlcd/model_select.cpp index 84158bd29..8ecb3ffa7 100644 --- a/radio/src/gui/colorlcd/model_select.cpp +++ b/radio/src/gui/colorlcd/model_select.cpp @@ -272,7 +272,7 @@ class ModelCategoryPageBody : public FormWindow .c_str(), [=] { modelslist.removeModel(category, model); - update((unsigned)index < category->size() - 1 ? index : index - 1); + update(index < (int)category->size() - 1 ? index : index - 1); }); }); } From 64f277152cd87d8c72e13583c092d3061a44fa8c Mon Sep 17 00:00:00 2001 From: eshifri <46511024+eshifri@users.noreply.github.com> Date: Tue, 13 Jul 2021 17:46:42 -0700 Subject: [PATCH 24/24] Implement View Text (#406) * View text and code cleanup * Typo fix * Fixed case generation * check list fixed * Horizontal clipping fixed * Lost letter fixed. * Cleanup * Unified implementation (Rotory button support) * Fixed USB menu issue and RTN button. * Rotary encoder acceleration implemented * Do not close file on every line read * Sliding window implemented. File size limitations practically removed. * scrollbar implemented * Cleanup & scroll bar adjustment * Cleanup * Smoother scrolling for long lines. * Minor cleanup --- radio/src/gui/colorlcd/CMakeLists.txt | 1 + radio/src/gui/colorlcd/message_dialog.cpp | 47 ++- radio/src/gui/colorlcd/message_dialog.h | 42 +- radio/src/gui/colorlcd/model_setup.cpp | 30 +- radio/src/gui/colorlcd/radio_sdmanager.cpp | 27 +- radio/src/gui/colorlcd/view_text.cpp | 435 +++++++++++++++++++++ radio/src/gui/colorlcd/view_text.h | 126 ++++++ radio/src/opentx.cpp | 5 +- 8 files changed, 659 insertions(+), 54 deletions(-) create mode 100644 radio/src/gui/colorlcd/view_text.cpp create mode 100644 radio/src/gui/colorlcd/view_text.h diff --git a/radio/src/gui/colorlcd/CMakeLists.txt b/radio/src/gui/colorlcd/CMakeLists.txt index de3a1d804..367430657 100644 --- a/radio/src/gui/colorlcd/CMakeLists.txt +++ b/radio/src/gui/colorlcd/CMakeLists.txt @@ -62,6 +62,7 @@ set(GUI_SRC view_channels.cpp view_logical_switches.cpp view_statistics.cpp + view_text.cpp menu_screen.cpp screen_setup.cpp switch_warn_dialog.cpp diff --git a/radio/src/gui/colorlcd/message_dialog.cpp b/radio/src/gui/colorlcd/message_dialog.cpp index 067d69500..4e5675f82 100644 --- a/radio/src/gui/colorlcd/message_dialog.cpp +++ b/radio/src/gui/colorlcd/message_dialog.cpp @@ -21,10 +21,38 @@ #include "static.h" MessageDialog::MessageDialog(Window* parent, const char* title, - const char* message, const char* info, - const int lineHeight, - const WindowFlags windowFlags, - const LcdFlags textFlags) : + const char* message, const char* info) : + Dialog(parent, title, {50, 73, LCD_W - 100, LCD_H - 146}) +{ + messageWidget = new StaticText( + this, + {0, coord_t(height() - PAGE_LINE_HEIGHT) / 2, width(), PAGE_LINE_HEIGHT}, + message, 0, CENTERED); + + infoWidget = new StaticText(this, + {0, 30 + coord_t(height() - PAGE_LINE_HEIGHT) / 2, + width(), PAGE_LINE_HEIGHT}, + info, 0, CENTERED); + setCloseWhenClickOutside(true); + setFocus(); +} + +#if defined(HARDWARE_KEYS) +void MessageDialog::onEvent(event_t event) +{ + TRACE_WINDOWS("%s received event 0x%X", getWindowDebugString().c_str(), + event); + + if (event == EVT_KEY_BREAK(KEY_EXIT) || event == EVT_KEY_BREAK(KEY_ENTER)) { + deleteLater(); + } +} +#endif + +DynamicMessageDialog::DynamicMessageDialog( + Window* parent, const char* title, std::function textHandler, + const char* message, const int lineHeight, + const LcdFlags textFlags) : Dialog(parent, title, {50, 73, LCD_W - 100, LCD_H - 146}) { setWindowFlags(windowFlags); @@ -34,21 +62,22 @@ MessageDialog::MessageDialog(Window* parent, const char* title, {0, coord_t(height() - PAGE_LINE_HEIGHT) / 2, width(), PAGE_LINE_HEIGHT}, message, 0, CENTERED); - infoWidget = new StaticText( + infoWidget = new DynamicText( this, {0, 30 + coord_t(height() - PAGE_LINE_HEIGHT) / 2, width(), lineHeight}, - info, 0, textFlags); + textHandler, textFlags); setCloseWhenClickOutside(true); setFocus(); } #if defined(HARDWARE_KEYS) -void MessageDialog::onEvent(event_t event) +void DynamicMessageDialog::onEvent(event_t event) { - TRACE_WINDOWS("%s received event 0x%X", getWindowDebugString().c_str(), event); + TRACE_WINDOWS("%s received event 0x%X", getWindowDebugString().c_str(), + event); if (event == EVT_KEY_BREAK(KEY_EXIT) || event == EVT_KEY_BREAK(KEY_ENTER)) { deleteLater(); } } -#endif +#endif \ No newline at end of file diff --git a/radio/src/gui/colorlcd/message_dialog.h b/radio/src/gui/colorlcd/message_dialog.h index bf0d570ba..a439568e1 100644 --- a/radio/src/gui/colorlcd/message_dialog.h +++ b/radio/src/gui/colorlcd/message_dialog.h @@ -23,23 +23,46 @@ #include "dialog.h" #include "static.h" -class MessageDialog : public Dialog +class MessageDialog: public Dialog { + public: + MessageDialog(Window * parent, const char * title, const char * message, const char * info = ""); + + void setInfoText(std::string text) + { + infoWidget->setText(std::move(text)); + } + + protected: + StaticText * messageWidget; + StaticText * infoWidget; + +#if defined(DEBUG_WINDOWS) + std::string getName() const override + { + return "MessageDialog"; + } +#endif + +#if defined(HARDWARE_KEYS) + void onEvent(event_t event) override; +#endif +}; + +class DynamicMessageDialog : public Dialog { public: - MessageDialog(Window* parent, const char* title, const char* message, - const char* info = "", const int lineHeight = PAGE_LINE_HEIGHT, - const WindowFlags windowFlags = 0, + DynamicMessageDialog(Window* parent, const char* title, + std::function textHandler, const char* message = "", const int lineHeight = PAGE_LINE_HEIGHT, const LcdFlags textFlags = CENTERED); - // Attn.: FONT(XXL) is not supported by MessageDialog + // Attn.: FONT(XXL) is not supported by DynamicMessageDialog - void setInfoText(std::string text) { infoWidget->setText(std::move(text)); } protected: StaticText* messageWidget; - StaticText* infoWidget; - LcdFlags textFlags; + DynamicText* infoWidget; + #if defined(DEBUG_WINDOWS) - std::string getName() const override { return "MessageDialog"; } + std::string getName() const override { return "DynamicMessageDialog"; } #endif #if defined(HARDWARE_KEYS) @@ -47,4 +70,5 @@ class MessageDialog : public Dialog #endif }; + #endif // _MESSAGE_DIALOG_H_ diff --git a/radio/src/gui/colorlcd/model_setup.cpp b/radio/src/gui/colorlcd/model_setup.cpp index a69df8222..75033cc05 100644 --- a/radio/src/gui/colorlcd/model_setup.cpp +++ b/radio/src/gui/colorlcd/model_setup.cpp @@ -41,26 +41,6 @@ std::string switchWarninglabel(swsrc_t index) 1); } -class RssiDialog : public MessageDialog -{ - public: - RssiDialog(Window* parent, const char* title, const char* message, - const char* info = "", const int lineHeight = PAGE_LINE_HEIGHT, - const WindowFlags windowFlags = 0, - const LcdFlags textFlags = CENTERED) : - MessageDialog(parent, title, message, info, lineHeight, windowFlags, - textFlags) - { - } - - virtual void checkEvents() - { - char buf[10]; - sprintf(buf, "%d", (int)TELEMETRY_RSSI()); - setInfoText(buf); - MessageDialog::checkEvents(); - } -}; class ChannelFailsafeBargraph: public Window { public: @@ -871,8 +851,14 @@ class ModuleWindow : public FormGroup { } else { moduleState[moduleIdx].mode = MODULE_MODE_RANGECHECK; - auto rssiDialog = new RssiDialog( - this, "Range Test", "RSSI:", "", 50, REFRESH_ALWAYS, + auto rssiDialog = new DynamicMessageDialog( + this, "Range Test", + [=]() { + char buf[16]; + sprintf(buf, "%d db", (int)TELEMETRY_RSSI()); + return std::string(buf); + }, + "RSSI:", 50, DEFAULT_COLOR | CENTERED | FONT(BOLD) | FONT(XL)); rssiDialog->setCloseHandler([this]() { rangeButton->check(false); diff --git a/radio/src/gui/colorlcd/radio_sdmanager.cpp b/radio/src/gui/colorlcd/radio_sdmanager.cpp index 2eef2e5fa..217d44612 100644 --- a/radio/src/gui/colorlcd/radio_sdmanager.cpp +++ b/radio/src/gui/colorlcd/radio_sdmanager.cpp @@ -26,6 +26,7 @@ #include "io/bootloader_flash.h" #include "standalone_lua.h" #include "sdcard.h" +#include "view_text.h" class FileNameEditWindow : public Page { @@ -232,15 +233,15 @@ void RadioSdManagerPage::build(FormWindow * window) if (res != FR_OK || fno.fname[0] == 0) break; // Break on error or end of dir - if (strlen(fno.fname) > SD_SCREEN_FILE_LENGTH) + if (strlen((const char*)fno.fname) > SD_SCREEN_FILE_LENGTH) continue; if (fno.fname[0] == '.' && fno.fname[1] != '.') continue; // Ignore hidden files under UNIX, but not .. if (fno.fattrib & AM_DIR) { - directories.push_back(fno.fname); + directories.push_back((char*)fno.fname); } else { - files.push_back(fno.fname); + files.push_back((char*)fno.fname); } } @@ -251,7 +252,7 @@ void RadioSdManagerPage::build(FormWindow * window) for (auto name: directories) { auto b = new TextButton(window, grid.getLabelSlot(), name, [=]() -> uint8_t { std::string fullpath = currentPath + "/" + name; - f_chdir(fullpath.c_str()); + f_chdir((TCHAR*)fullpath.c_str()); window->clear(); build(window); return 0; @@ -303,11 +304,18 @@ void RadioSdManagerPage::build(FormWindow * window) // else if (isExtensionMatching(ext, BITMAPS_EXT)) { // // TODO // } - // else if (!strcasecmp(ext, TEXT_EXT)) { - // menu->addLine(STR_VIEW_TEXT, [=]() { - // // TODO - // }); - // } + else if (!strcasecmp(ext, TEXT_EXT)) { + menu->addLine(STR_VIEW_TEXT, [=]() { + static char lfn[FF_MAX_LFN + 1]; // TODO optimize that! + f_getcwd((TCHAR *)lfn, FF_MAX_LFN); + + auto textView = new ViewTextWindow(lfn, name); + textView->setCloseHandler([=]() { + //window->clear(); + rebuild(window); + }); + }); + } if (!READ_ONLY() && !strcasecmp(ext, FIRMWARE_EXT)) { if (isBootloader(name.data())) { menu->addLine(STR_FLASH_BOOTLOADER, [=]() { @@ -378,7 +386,6 @@ void RadioSdManagerPage::build(FormWindow * window) //window->clear(); rebuild(window); }); - // rebuild(window); }); }); menu->addLine(STR_DELETE_FILE, [=]() { f_unlink((const TCHAR*)getFullPath(name)); diff --git a/radio/src/gui/colorlcd/view_text.cpp b/radio/src/gui/colorlcd/view_text.cpp new file mode 100644 index 000000000..c3381508d --- /dev/null +++ b/radio/src/gui/colorlcd/view_text.cpp @@ -0,0 +1,435 @@ +/* + * Copyright (C) EdgeTX + * + * 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 "view_text.h" + +#include "gridlayout.h" +#include "menu.h" +#include "opentx.h" +#include "sdcard.h" + +#define CASE_EVT_KEY_NEXT_LINE \ + case EVT_ROTARY_RIGHT: \ + case EVT_KEY_BREAK(KEY_PGDN) +// case EVT_KEY_BREAK(KEY_DOWN) + +#define CASE_EVT_KEY_PREVIOUS_LINE \ + case EVT_ROTARY_LEFT: \ + case EVT_KEY_BREAK(KEY_PGUP): \ + case EVT_KEY_BREAK(KEY_UP) + +#define CASE_EVT_START \ + case EVT_ENTRY: \ + case EVT_KEY_BREAK(KEY_ENTER): \ + case EVT_KEY_BREAK(KEY_TELEM) + +void ViewTextWindow::extractNameSansExt() +{ + uint8_t nameLength; + uint8_t extLength; + + const char *ext = + getFileExtension(name.data(), 0, 0, &nameLength, &extLength); + extension = std::string(ext); + if (nameLength > TEXT_FILENAME_MAXLEN) nameLength = TEXT_FILENAME_MAXLEN; + + nameLength -= extLength; + name.substr(nameLength); +} + +#if READ_FILE_BY_LINE +void ViewTextWindow::buildBody(Window *window) +{ + GridLayout grid(window); + grid.spacer(); + int i; + + // assume average characte is 10 pixels wide, round the string length to tens. + // Font is not fixed width, so this is for the worst case... + const int maxLineLength = int(floor(window->width() / 10 / 10)) * 10 - 2; + window->setFocus(); + + FIL file; + if (FR_OK != + f_open(&file, (TCHAR *)fullPath.c_str(), FA_OPEN_EXISTING | FA_READ)) { + return; + } + readCount = 0; + longestLine = 0; + lastLine = false; + for (i = 0; i < TEXT_FILE_MAXSIZE && !lastLine; i++) { + lastLine = + sdReadTextLine(&file, reusableBuffer.viewText.lines[0], maxLineLength); + + new StaticText(window, grid.getSlot(), reusableBuffer.viewText.lines[0]); + grid.nextLine(); + } + + f_close(&file); + + window->setInnerWidth((longestLine + 4) * 10); + window->setInnerHeight(grid.getWindowHeight()); +} + +void ViewTextWindow::checkEvents() +{ + if (&body == Window::focusWindow) { + const int step = PAGE_LINE_HEIGHT + PAGE_LINE_SPACING; + coord_t currentPos = body.getScrollPositionY(); + coord_t deltaY; + event_t event = getWindowEvent(); + + if (event == EVT_ROTARY_LEFT || event == EVT_ROTARY_RIGHT) { + deltaY = ROTARY_ENCODER_SPEED() * step; + } else { + deltaY = step; + } + + switch (event) { + CASE_EVT_KEY_NEXT_LINE: + currentPos += deltaY; + break; + + CASE_EVT_KEY_PREVIOUS_LINE: + currentPos -= deltaY; + break; + + default: + Page::onEvent(event); + return; + } + body.setScrollPositionY(currentPos); + } + Page::checkEvents(); +} + +bool ViewTextWindow::sdReadTextLine(FIL *file, char line[], + const uint8_t maxLineLength) +{ + char c; + unsigned int sz; + uint8_t line_length = 0; + uint8_t escape = 0; + char escape_chars[4] = {0}; + int current_line = 0; + + memclear(line, maxLineLength + 1); + line[line_length++] = 0x20; + + for (uint8_t i = 0; i < maxLineLength && readCount < (int)TEXT_FILE_MAXSIZE; + ++i) { + if ((f_read(file, &c, 1, &sz) != FR_OK || !sz) && + line_length < maxLineLength) { + return true; + } + readCount++; + + if (c == '\n') { + ++current_line; + escape = 0; + return false; + } else if (c != '\r') { + if (c == '\\' && escape == 0) { + escape = 1; + continue; + } else if (c != '\\' && escape > 0 && escape < sizeof(escape_chars)) { + escape_chars[escape - 1] = c; + if (escape == 2 && !strncmp(escape_chars, "up", 2)) { + c = CHAR_UP; + } else if (escape == 2 && !strncmp(escape_chars, "dn", 2)) { + c = CHAR_DOWN; + } else if (escape == 3) { + int val = atoi(escape_chars); + if (val >= 200 && val < 225) { + c = '\200' + val - 200; + } + } else { + escape++; + continue; + } + } else if (c == '~') { + c = 'z' + 1; + } else if (c == '\t') { + c = 0x1D; // tab + } + escape = 0; + line[line_length++] = c; + if (longestLine < line_length) longestLine = line_length; + } + } + if (c != '\n') { + current_line += 1; + return false; + } + + return false; +} +#else + +void ViewTextWindow::buildBody(Window *window) +{ + GridLayout grid(window); + grid.spacer(); + int i; + + // assume average characte is 10 pixels wide, round the string length to tens. + // Font is not fixed width, so this is for the worst case... + maxLineLength = int(floor(window->width() / 10 / 10)) * 10 - 2; + maxScreenLines = window->height() / (PAGE_LINE_HEIGHT + PAGE_LINE_SPACING); + window->setFocus(); + readLinesCount = 0; + lastLoadedLine = 0; + + lines = new char*[maxScreenLines]; + for(i = 0 ; i < maxScreenLines; i++) + { + lines[i] = new char[maxLineLength + 1]; + memclear(lines[i], maxLineLength + 1); + } + + longestLine = 0; + loadFirstScreen(); + + if(isInSetup == true) + { + textBottom = false; + while(!textBottom) + { + sdReadTextFileBlock(fullPath.c_str(), readLinesCount); + textVerticalOffset += 10; + } + maxPos = (maxLines - maxScreenLines) * (PAGE_LINE_HEIGHT + PAGE_LINE_SPACING); + if(maxPos < body.getRect().h) maxPos = body.getRect().h; + } + + isInSetup = false; + loadFirstScreen(); + + for (i = 0; i < maxScreenLines; i++) { + new DynamicText(window, grid.getSlot(), [=]() { + std::string str = (lines[i][0]) ? std::string(lines[i]) : std::string(" "); + return std::string(str); + }); + grid.nextLine(); + } +} + +#if defined(HARDWARE_TOUCH) +bool ViewTextWindow::onTouchSlide(coord_t x, coord_t y, coord_t startX, + coord_t startY, coord_t slideX, + coord_t slideY) +{ + if (&body == Window::focusWindow) { + const int step = PAGE_LINE_HEIGHT + PAGE_LINE_SPACING; + int deltaY = -slideY; + int lineStep = deltaY / step; + + textVerticalOffset += lineStep; + if (textVerticalOffset < 0) textVerticalOffset = 0; + + // if (textBottom && lineStep > 0) textVerticalOffset -= lineStep; + if(textVerticalOffset > maxLines) textVerticalOffset = maxLines; + sdReadTextFileBlock(fullPath.c_str(), readLinesCount); + } + return Page::onTouchSlide(x, y, startX, startY, slideX, slideY); +} +#endif + +void ViewTextWindow::checkEvents() +{ + if (&body == Window::focusWindow) { + const int step = PAGE_LINE_HEIGHT + PAGE_LINE_SPACING; + coord_t deltaY; + event_t event = getWindowEvent(); + + if (event == EVT_ROTARY_LEFT || event == EVT_ROTARY_RIGHT) { + deltaY = ROTARY_ENCODER_SPEED() * step; + } else { + deltaY = step; + } + + int lineStep = deltaY / step; + if(lineStep > (maxScreenLines >> 1)) lineStep = maxScreenLines >> 1; +/* + if(event) { + sprintf(lines[0], "Received event %d", event); + if(!readLinesCount) + readLinesCount = 1; + Page::onEvent(event); + return; + } +*/ + switch (event) { + CASE_EVT_START: + textVerticalOffset = 0; + readLinesCount = 0; + sdReadTextFileBlock(fullPath.c_str(), readLinesCount); + break; + + CASE_EVT_KEY_NEXT_LINE: + if(textBottom && textVerticalOffset) //(textVerticalOffset + maxScreenLines - 1 >= readLinesCount) + break; + else { + textVerticalOffset += lineStep; + if(textVerticalOffset > maxLines) textVerticalOffset = maxLines; + } + sdReadTextFileBlock(fullPath.c_str(), readLinesCount); + break; + + CASE_EVT_KEY_PREVIOUS_LINE: + if (textVerticalOffset == 0) + break; + else { + textVerticalOffset -= lineStep; + if(textVerticalOffset < 0) textVerticalOffset = 0; + } + + sdReadTextFileBlock(fullPath.c_str(), readLinesCount); + break; + + default: + Page::onEvent(event); + break; + } + } + Page::checkEvents(); +} + +void ViewTextWindow::loadFirstScreen() +{ + textVerticalOffset = 0; + readLinesCount = 0; + sdReadTextFileBlock(fullPath.c_str(), readLinesCount); +} + +void ViewTextWindow::sdReadTextFileBlock(const char *filename, int &lines_count) +{ + FIL file; + int result; + char c; + unsigned int sz = 0; + int line_length = 1; + uint8_t escape = 0; + char escape_chars[4] = {0}; + int current_line = 0; + textBottom = false; + + for(int i = 0; i < maxScreenLines; i++) { + memclear(lines[i], maxLineLength + 1); + lines[i][0] = ' '; + } + + result = f_open(&file, (TCHAR *)filename, FA_OPEN_EXISTING | FA_READ); + if (result == FR_OK) { + for (int i = 0; i < TEXT_FILE_MAXSIZE && + f_read(&file, &c, 1, &sz) == FR_OK && sz == 1 && + (lines_count == 0 || + current_line - textVerticalOffset < maxScreenLines); + i++) { + if (c == '\n' || line_length >= maxLineLength) { + ++current_line; + line_length = 1; + escape = 0; + } + if (c != '\r' && c != '\n' && current_line >= textVerticalOffset && + current_line - textVerticalOffset < maxScreenLines && + line_length < maxLineLength) { + if (c == '\\' && escape == 0) { + escape = 1; + continue; + } else if (c != '\\' && escape > 0 && escape < sizeof(escape_chars)) { + escape_chars[escape - 1] = c; + if (escape == 2 && !strncmp(escape_chars, "up", 2)) { + c = CHAR_UP; + } else if (escape == 2 && !strncmp(escape_chars, "dn", 2)) { + c = CHAR_DOWN; + } else if (escape == 3) { + int val = atoi(escape_chars); + if (val >= 200 && val < 225) { + c = '\200' + val - 200; + } + } else { + escape++; + continue; + } + } + else if (c == '~') { + c = 'z' + 1; + } else if (c == '\t') { + c = 0x1D; // tab + } + escape = 0; + + lines[current_line - textVerticalOffset][line_length++] = c; + if (longestLine < line_length) longestLine = line_length; + } else if(current_line < textVerticalOffset) { + ++line_length; + } + } + if (c != '\n') { + ++current_line; + } + + if (f_eof(&file)) { + textBottom = true; + if (isInSetup) maxLines = current_line; + } + + f_close(&file); + } + + if(lastLoadedLine < textVerticalOffset) + lastLoadedLine = textVerticalOffset; + + if (lines_count == 0) { + lines_count = current_line; + } +} + +void ViewTextWindow::drawVerticalScrollbar(BitmapBuffer *dc) +{ + int readPos = textVerticalOffset * (PAGE_LINE_HEIGHT + PAGE_LINE_SPACING); + + if(readPos < header.getRect().h << 1) readPos = header.getRect().h << 1; + + coord_t yofs = divRoundClosest(body.getRect().h * readPos, maxPos); + coord_t yhgt = divRoundClosest(body.getRect().h * body.getRect().h, maxPos); + if (yhgt < 15) yhgt = 15; + if (yhgt + yofs > maxPos) yhgt = maxPos - yofs; + dc->drawSolidFilledRect(body.getRect().w - SCROLLBAR_WIDTH, yofs, + SCROLLBAR_WIDTH, yhgt, SCROLLBAR_COLOR); +} + +#endif + +#include "datastructs.h" + +void readModelNotes() +{ + LED_ERROR_BEGIN(); + + std::string modelNotesName(g_model.header.name); + modelNotesName.append(TEXT_EXT); + const char buf[] = {MODELS_PATH}; + f_chdir((TCHAR*)buf); + new ViewTextWindow(std::string(buf), modelNotesName, ICON_MODEL); + + LED_ERROR_END(); +} \ No newline at end of file diff --git a/radio/src/gui/colorlcd/view_text.h b/radio/src/gui/colorlcd/view_text.h new file mode 100644 index 000000000..e73938ef1 --- /dev/null +++ b/radio/src/gui/colorlcd/view_text.h @@ -0,0 +1,126 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#pragma once + +#include "page.h" +#include "static.h" +#include "lcd.h" +#include "menus.h" +#include "ff.h" + +#define READ_FILE_BY_LINE 0 + +constexpr uint16_t TEXT_FILE_MAXSIZE = 20480; + +class ViewTextWindow : public Page +{ + public: + ViewTextWindow(const std::string iPath, const std::string iName, unsigned int icon = ICON_RADIO_SD_MANAGER) : + Page(icon), + path(std::move(iPath)), + name(std::move(iName)), + icon(icon) + { + fullPath = path + std::string("/") + name; + extractNameSansExt(); + lines = nullptr; + lastLoadedLine = 0; + maxPos = 0; + maxLines = 0; + isInSetup = true; + //body.setWindowFlags(FORWARD_SCROLL); + header.setWindowFlags(NO_SCROLLBAR); + + buildHeader(&header); + buildBody(&body); + }; + +#if READ_FILE_BY_LINE + bool sdReadTextLine(FIL* file, char lines[], + const uint8_t lineLength = LCD_COLS); +#else + void sdReadTextFileBlock(const char * filename, int& lines_count); + void loadFirstScreen(void); + #if defined(HARDWARE_TOUCH) + bool onTouchSlide(coord_t x, coord_t y, coord_t startX, coord_t startY, coord_t slideX, coord_t slideY) override; +#endif + void drawVerticalScrollbar(BitmapBuffer * dc); + + ~ViewTextWindow() + { + if(lines != nullptr) { + for(int i = 0; i < maxScreenLines; i++) + { + delete[] lines[i]; + } + delete[] lines; + } + } + + void paint(BitmapBuffer* dc) + { + Page::paint(dc); + drawVerticalScrollbar(dc); + } +#endif + virtual void checkEvents(); + +#if defined(DEBUG_WINDOWS) + std::string getName() const override { return "ViewTextWindow"; }; +#endif + + protected: + std::string path; + std::string name; + std::string fullPath; + std::string extension; + unsigned int icon; + + bool lastLine; + uint16_t readCount; + int longestLine; + +#if !READ_FILE_BY_LINE +char** lines = nullptr; +//char lines[15][80]; +int maxScreenLines; +int maxLineLength; +int textVerticalOffset; +int readLinesCount; +int lastLoadedLine; +int maxPos; +int maxLines; +bool textBottom; +bool isInSetup; +#endif + + void extractNameSansExt(void); + void buildBody(Window *window); + void buildHeader(Window *window) + { + new StaticText(window, + {PAGE_TITLE_LEFT, PAGE_TITLE_TOP + 10, + LCD_W - PAGE_TITLE_LEFT, PAGE_LINE_HEIGHT}, + name, 0, MENU_HIGHLIGHT_COLOR); + }; +}; + +void readModelNotes(); \ No newline at end of file diff --git a/radio/src/opentx.cpp b/radio/src/opentx.cpp index 6ea3dec47..dab39d0fc 100644 --- a/radio/src/opentx.cpp +++ b/radio/src/opentx.cpp @@ -26,6 +26,7 @@ // #include "shutdown_animation.h" #include "radio_calibration.h" #include "view_main.h" + #include "view_text.h" #endif #if defined(PCBSKY9X) @@ -745,13 +746,9 @@ void checkAll() disableVBatBridge(); #endif -#if defined(COLORLCD) -#warning "Model notes missing" -#else if (g_model.displayChecklist && modelHasNotes()) { readModelNotes(); } -#endif #if defined(MULTIMODULE) checkMultiLowPower();