From 3cdf2f9b4de9eaeb53f76ab5523f149dd20bc063 Mon Sep 17 00:00:00 2001 From: Florent de Lamotte Date: Tue, 2 Sep 2025 11:43:48 +0200 Subject: [PATCH 01/13] techo: display backlight behavior --- examples/companion_radio/ui-new/UITask.cpp | 8 ++++++++ src/helpers/ui/GxEPDDisplay.cpp | 5 +++-- variants/techo/platformio.ini | 1 + 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/examples/companion_radio/ui-new/UITask.cpp b/examples/companion_radio/ui-new/UITask.cpp index c751eaf5..f0f9ed1d 100644 --- a/examples/companion_radio/ui-new/UITask.cpp +++ b/examples/companion_radio/ui-new/UITask.cpp @@ -519,6 +519,14 @@ void UITask::loop() { c = handleLongPress(KEY_ENTER); } #endif +#if defined(DISP_BACKLIGHT) && defined(BACKLIGHT_BTN) + static int next_btn_check = 0; + if (millis() > next_btn_check) { + bool touch_state = digitalRead(PIN_BUTTON2); + digitalWrite(DISP_BACKLIGHT, !touch_state); + next_btn_check = millis() + 300; + } +#endif if (c != 0 && curr) { curr->handleInput(c); diff --git a/src/helpers/ui/GxEPDDisplay.cpp b/src/helpers/ui/GxEPDDisplay.cpp index ace25460..9ba7d074 100644 --- a/src/helpers/ui/GxEPDDisplay.cpp +++ b/src/helpers/ui/GxEPDDisplay.cpp @@ -19,6 +19,7 @@ bool GxEPDDisplay::begin() { display.fillScreen(GxEPD_WHITE); display.display(true); #if DISP_BACKLIGHT + digitalWrite(DISP_BACKLIGHT, LOW); pinMode(DISP_BACKLIGHT, OUTPUT); #endif _init = true; @@ -27,14 +28,14 @@ bool GxEPDDisplay::begin() { void GxEPDDisplay::turnOn() { if (!_init) begin(); -#if DISP_BACKLIGHT +#if defined(DISP_BACKLIGHT) && !defined(BACLIGHT_BTN) digitalWrite(DISP_BACKLIGHT, HIGH); #endif _isOn = true; } void GxEPDDisplay::turnOff() { -#if DISP_BACKLIGHT +#if defined(DISP_BACKLIGHT) && !defined(BACKLIGHT_BTN) digitalWrite(DISP_BACKLIGHT, LOW); #endif _isOn = false; diff --git a/variants/techo/platformio.ini b/variants/techo/platformio.ini index e5cfacd4..260be35f 100644 --- a/variants/techo/platformio.ini +++ b/variants/techo/platformio.ini @@ -78,6 +78,7 @@ build_flags = -D DISPLAY_CLASS=GxEPDDisplay -D OFFLINE_QUEUE_SIZE=256 -D UI_RECENT_LIST_SIZE=9 + -D BACKLIGHT_BTN=PIN_BUTTON2 ; -D MESH_PACKET_LOGGING=1 ; -D MESH_DEBUG=1 build_src_filter = ${LilyGo_Techo.build_src_filter} From 90cb1e73f9c7709a244981d7c14291330878c53a Mon Sep 17 00:00:00 2001 From: Scott Powell Date: Tue, 2 Sep 2025 21:18:05 +1000 Subject: [PATCH 02/13] * HeltecV3: powerOff() fix --- src/helpers/HeltecV3Board.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/helpers/HeltecV3Board.h b/src/helpers/HeltecV3Board.h index b71514cc..c63ed2d8 100644 --- a/src/helpers/HeltecV3Board.h +++ b/src/helpers/HeltecV3Board.h @@ -85,8 +85,7 @@ public: } void powerOff() override { - // TODO: re-enable this when there is a definite wake-up source pin: - // enterDeepSleep(0); + enterDeepSleep(0); } uint16_t getBattMilliVolts() override { From 03358b33c22d909d2414fa4f53010f7aa6f98a2b Mon Sep 17 00:00:00 2001 From: taco Date: Tue, 2 Sep 2025 21:30:51 +1000 Subject: [PATCH 03/13] fix: promicro: add powerOff --- variants/promicro/PromicroBoard.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/variants/promicro/PromicroBoard.h b/variants/promicro/PromicroBoard.h index 89e71755..e4b67415 100644 --- a/variants/promicro/PromicroBoard.h +++ b/variants/promicro/PromicroBoard.h @@ -60,6 +60,10 @@ public: void reboot() override { NVIC_SystemReset(); } + + void powerOff() override { + sd_power_system_off(); + } bool startOTAUpdate(const char* id, char reply[]) override; }; From ddc900c8c8675c4ebc42edc8bfdf2b50fdb02c0d Mon Sep 17 00:00:00 2001 From: recrof Date: Tue, 2 Sep 2025 22:23:32 +0200 Subject: [PATCH 04/13] renamend and refactored vision master to play better with build system --- ...sion_master_e213.json => heltec_e213.json} | 0 ...sion_master_e290.json => heltec_e290.json} | 0 ...sion_master_t190.json => heltec_t190.json} | 0 .../HeltecE213Board.cpp | 6 +- .../HeltecE213Board.h | 10 --- .../pins_arduino.h | 0 .../platformio.ini | 69 +++++++++++++------ .../target.cpp | 0 .../target.h | 0 .../HeltecE290Board.cpp | 6 +- .../HeltecE290Board.h | 9 --- .../pins_arduino.h | 0 .../platformio.ini | 69 +++++++++++++------ .../target.cpp | 0 .../target.h | 0 .../HeltecT190Board.cpp | 6 +- .../HeltecT190Board.h | 9 --- .../pins_arduino.h | 0 .../platformio.ini | 61 +++++++++++----- .../target.cpp | 0 .../target.h | 0 21 files changed, 143 insertions(+), 102 deletions(-) rename boards/{heltec_vision_master_e213.json => heltec_e213.json} (100%) rename boards/{heltec_vision_master_e290.json => heltec_e290.json} (100%) rename boards/{heltec_vision_master_t190.json => heltec_t190.json} (100%) rename variants/{heltec_vision_master_e213 => heltec_e213}/HeltecE213Board.cpp (94%) rename variants/{heltec_vision_master_e213 => heltec_e213}/HeltecE213Board.h (66%) rename variants/{heltec_vision_master_e213 => heltec_e213}/pins_arduino.h (100%) rename variants/{heltec_vision_master_e213 => heltec_e213}/platformio.ini (56%) rename variants/{heltec_vision_master_e213 => heltec_e213}/target.cpp (100%) rename variants/{heltec_vision_master_e213 => heltec_e213}/target.h (100%) rename variants/{heltec_vision_master_e290 => heltec_e290}/HeltecE290Board.cpp (94%) rename variants/{heltec_vision_master_e290 => heltec_e290}/HeltecE290Board.h (66%) rename variants/{heltec_vision_master_e290 => heltec_e290}/pins_arduino.h (100%) rename variants/{heltec_vision_master_e290 => heltec_e290}/platformio.ini (53%) rename variants/{heltec_vision_master_e290 => heltec_e290}/target.cpp (100%) rename variants/{heltec_vision_master_e290 => heltec_e290}/target.h (100%) rename variants/{heltec_vision_master_t190 => heltec_t190}/HeltecT190Board.cpp (94%) rename variants/{heltec_vision_master_t190 => heltec_t190}/HeltecT190Board.h (67%) rename variants/{heltec_vision_master_t190 => heltec_t190}/pins_arduino.h (100%) rename variants/{heltec_vision_master_t190 => heltec_t190}/platformio.ini (57%) rename variants/{heltec_vision_master_t190 => heltec_t190}/target.cpp (100%) rename variants/{heltec_vision_master_t190 => heltec_t190}/target.h (100%) diff --git a/boards/heltec_vision_master_e213.json b/boards/heltec_e213.json similarity index 100% rename from boards/heltec_vision_master_e213.json rename to boards/heltec_e213.json diff --git a/boards/heltec_vision_master_e290.json b/boards/heltec_e290.json similarity index 100% rename from boards/heltec_vision_master_e290.json rename to boards/heltec_e290.json diff --git a/boards/heltec_vision_master_t190.json b/boards/heltec_t190.json similarity index 100% rename from boards/heltec_vision_master_t190.json rename to boards/heltec_t190.json diff --git a/variants/heltec_vision_master_e213/HeltecE213Board.cpp b/variants/heltec_e213/HeltecE213Board.cpp similarity index 94% rename from variants/heltec_vision_master_e213/HeltecE213Board.cpp rename to variants/heltec_e213/HeltecE213Board.cpp index d32d274e..af115318 100644 --- a/variants/heltec_vision_master_e213/HeltecE213Board.cpp +++ b/variants/heltec_e213/HeltecE213Board.cpp @@ -23,7 +23,7 @@ void HeltecE213Board::begin() { void HeltecE213Board::enterDeepSleep(uint32_t secs, int pin_wake_btn) { esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); - // Make sure the DIO1 and NSS GPIOs are hold on required levels during deep sleep + // Make sure the DIO1 and NSS GPIOs are hold on required levels during deep sleep rtc_gpio_set_direction((gpio_num_t)P_LORA_DIO_1, RTC_GPIO_MODE_INPUT_ONLY); rtc_gpio_pulldown_en((gpio_num_t)P_LORA_DIO_1); @@ -44,8 +44,7 @@ void HeltecE213Board::begin() { } void HeltecE213Board::powerOff() { - // TODO: re-enable this when there is a definite wake-up source pin: - // enterDeepSleep(0); + enterDeepSleep(0); } uint16_t HeltecE213Board::getBattMilliVolts() { @@ -66,4 +65,3 @@ void HeltecE213Board::begin() { const char* HeltecE213Board::getManufacturerName() const { return "Heltec E213"; } - diff --git a/variants/heltec_vision_master_e213/HeltecE213Board.h b/variants/heltec_e213/HeltecE213Board.h similarity index 66% rename from variants/heltec_vision_master_e213/HeltecE213Board.h rename to variants/heltec_e213/HeltecE213Board.h index dd622064..2192c141 100644 --- a/variants/heltec_vision_master_e213/HeltecE213Board.h +++ b/variants/heltec_e213/HeltecE213Board.h @@ -5,15 +5,6 @@ #include #include -// LoRa radio module pins for heltec_vision_master_e213 -#define P_LORA_DIO_1 14 -#define P_LORA_NSS 8 -#define P_LORA_RESET 12 -#define P_LORA_BUSY 13 -#define P_LORA_SCLK 9 -#define P_LORA_MISO 11 -#define P_LORA_MOSI 10 - class HeltecE213Board : public ESP32Board { public: @@ -26,5 +17,4 @@ public: void powerOff() override; uint16_t getBattMilliVolts() override; const char* getManufacturerName() const override ; - }; diff --git a/variants/heltec_vision_master_e213/pins_arduino.h b/variants/heltec_e213/pins_arduino.h similarity index 100% rename from variants/heltec_vision_master_e213/pins_arduino.h rename to variants/heltec_e213/pins_arduino.h diff --git a/variants/heltec_vision_master_e213/platformio.ini b/variants/heltec_e213/platformio.ini similarity index 56% rename from variants/heltec_vision_master_e213/platformio.ini rename to variants/heltec_e213/platformio.ini index c6b68724..c8efc819 100644 --- a/variants/heltec_vision_master_e213/platformio.ini +++ b/variants/heltec_e213/platformio.ini @@ -1,14 +1,22 @@ -[Heltec_Vision_Master_E213_base] +[Heltec_E213_base] extends = esp32_base -board = heltec_vision_master_e213 +board = heltec_e213 build_flags = ${esp32_base.build_flags} - -I variants/heltec_vision_master_e213 - -D HELTEC_VISION_MASTER_E213 + -I variants/heltec_e213 + -D Vision_Master_E213 + -D ARDUINO_USB_CDC_ON_BOOT=1 -D RADIO_CLASS=CustomSX1262 -D WRAPPER_CLASS=CustomSX1262Wrapper - -D LORA_TX_POWER=22 + -D P_LORA_DIO_1=14 + -D P_LORA_NSS=8 + -D P_LORA_RESET=12 + -D P_LORA_BUSY=13 + -D P_LORA_SCLK=9 + -D P_LORA_MISO=11 + -D P_LORA_MOSI=10 -D P_LORA_TX_LED=45 + -D LORA_TX_POWER=22 -D PIN_USER_BTN=0 -D PIN_VEXT_EN=18 -D PIN_VEXT_EN_ACTIVE=HIGH @@ -26,17 +34,16 @@ build_flags = -D DISP_RST=3 -D DISP_SCLK=4 -D DISP_MOSI=6 - -D Vision_Master_E213 build_src_filter = ${esp32_base.build_src_filter} - +<../variants/heltec_vision_master_e213> + +<../variants/heltec_e213> lib_deps = ${esp32_base.lib_deps} https://github.com/Quency-D/heltec-eink-modules/archive/563dd41fd850a1bc3039b8723da4f3a20fe1c800.zip -[env:Heltec_Vision_Master_E213_radio_ble] -extends = Heltec_Vision_Master_E213_base +[env:Heltec_E213_companion_radio_ble] +extends = Heltec_E213_base build_flags = - ${Heltec_Vision_Master_E213_base.build_flags} + ${Heltec_E213_base.build_flags} -I examples/companion_radio/ui-new -D MAX_CONTACTS=300 -D MAX_GROUP_CHANNELS=8 @@ -44,43 +51,61 @@ build_flags = -D BLE_PIN_CODE=123456 ; dynamic, random PIN -D BLE_DEBUG_LOGGING=1 -D OFFLINE_QUEUE_SIZE=256 -build_src_filter = ${Heltec_Vision_Master_E213_base.build_src_filter} +build_src_filter = ${Heltec_E213_base.build_src_filter} + + +<../examples/companion_radio/*.cpp> +<../examples/companion_radio/ui-new/*.cpp> lib_deps = - ${Heltec_Vision_Master_E213_base.lib_deps} + ${Heltec_E213_base.lib_deps} densaugeo/base64 @ ~1.4.0 -[env:Heltec_Vision_Master_E213_repeater] -extends = Heltec_Vision_Master_E213_base +[env:Heltec_E213_companion_radio_usb] +extends = Heltec_E213_base build_flags = - ${Heltec_Vision_Master_E213_base.build_flags} + ${Heltec_E213_base.build_flags} + -I examples/companion_radio/ui-new + -D MAX_CONTACTS=300 + -D MAX_GROUP_CHANNELS=8 + -D DISPLAY_CLASS=E213Display + -D OFFLINE_QUEUE_SIZE=256 +build_src_filter = ${Heltec_E213_base.build_src_filter} + + + + + +<../examples/companion_radio/*.cpp> + +<../examples/companion_radio/ui-new/*.cpp> +lib_deps = + ${Heltec_E213_base.lib_deps} + densaugeo/base64 @ ~1.4.0 + +[env:Heltec_E213_repeater] +extends = Heltec_E213_base +build_flags = + ${Heltec_E213_base.build_flags} -D DISPLAY_CLASS=E213Display -D ADVERT_NAME='"Heltec E213 Repeater"' -D ADVERT_LAT=0.0 -D ADVERT_LON=0.0 -build_src_filter = ${Heltec_Vision_Master_E213_base.build_src_filter} +build_src_filter = ${Heltec_E213_base.build_src_filter} + +<../examples/simple_repeater> lib_deps = - ${Heltec_Vision_Master_E213_base.lib_deps} + ${Heltec_E213_base.lib_deps} ${esp32_ota.lib_deps} -[env:Heltec_Vision_Master_E213_room_server] -extends = Heltec_Vision_Master_E213_base +[env:Heltec_E213_room_server] +extends = Heltec_E213_base build_flags = - ${Heltec_Vision_Master_E213_base.build_flags} + ${Heltec_E213_base.build_flags} -D DISPLAY_CLASS=E213Display -D ADVERT_NAME='"Heltec E213 Room"' -D ADVERT_LAT=0.0 -D ADVERT_LON=0.0 -D ADMIN_PASSWORD='"password"' -D ROOM_PASSWORD='"hello"' -build_src_filter = ${Heltec_Vision_Master_E213_base.build_src_filter} +build_src_filter = ${Heltec_E213_base.build_src_filter} + +<../examples/simple_room_server> lib_deps = - ${Heltec_Vision_Master_E213_base.lib_deps} + ${Heltec_E213_base.lib_deps} ${esp32_ota.lib_deps} diff --git a/variants/heltec_vision_master_e213/target.cpp b/variants/heltec_e213/target.cpp similarity index 100% rename from variants/heltec_vision_master_e213/target.cpp rename to variants/heltec_e213/target.cpp diff --git a/variants/heltec_vision_master_e213/target.h b/variants/heltec_e213/target.h similarity index 100% rename from variants/heltec_vision_master_e213/target.h rename to variants/heltec_e213/target.h diff --git a/variants/heltec_vision_master_e290/HeltecE290Board.cpp b/variants/heltec_e290/HeltecE290Board.cpp similarity index 94% rename from variants/heltec_vision_master_e290/HeltecE290Board.cpp rename to variants/heltec_e290/HeltecE290Board.cpp index 7d8c654d..3994a206 100644 --- a/variants/heltec_vision_master_e290/HeltecE290Board.cpp +++ b/variants/heltec_e290/HeltecE290Board.cpp @@ -23,7 +23,7 @@ void HeltecE290Board::begin() { void HeltecE290Board::enterDeepSleep(uint32_t secs, int pin_wake_btn) { esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); - // Make sure the DIO1 and NSS GPIOs are hold on required levels during deep sleep + // Make sure the DIO1 and NSS GPIOs are hold on required levels during deep sleep rtc_gpio_set_direction((gpio_num_t)P_LORA_DIO_1, RTC_GPIO_MODE_INPUT_ONLY); rtc_gpio_pulldown_en((gpio_num_t)P_LORA_DIO_1); @@ -44,8 +44,7 @@ void HeltecE290Board::begin() { } void HeltecE290Board::powerOff() { - // TODO: re-enable this when there is a definite wake-up source pin: - // enterDeepSleep(0); + enterDeepSleep(0); } uint16_t HeltecE290Board::getBattMilliVolts() { @@ -66,4 +65,3 @@ void HeltecE290Board::begin() { const char* HeltecE290Board::getManufacturerName() const { return "Heltec E290"; } - diff --git a/variants/heltec_vision_master_e290/HeltecE290Board.h b/variants/heltec_e290/HeltecE290Board.h similarity index 66% rename from variants/heltec_vision_master_e290/HeltecE290Board.h rename to variants/heltec_e290/HeltecE290Board.h index 95f8c03e..ff16e273 100644 --- a/variants/heltec_vision_master_e290/HeltecE290Board.h +++ b/variants/heltec_e290/HeltecE290Board.h @@ -5,15 +5,6 @@ #include #include -// LoRa radio module pins for heltec_vision_master_e290 -#define P_LORA_DIO_1 14 -#define P_LORA_NSS 8 -#define P_LORA_RESET 12 -#define P_LORA_BUSY 13 -#define P_LORA_SCLK 9 -#define P_LORA_MISO 11 -#define P_LORA_MOSI 10 - class HeltecE290Board : public ESP32Board { public: diff --git a/variants/heltec_vision_master_e290/pins_arduino.h b/variants/heltec_e290/pins_arduino.h similarity index 100% rename from variants/heltec_vision_master_e290/pins_arduino.h rename to variants/heltec_e290/pins_arduino.h diff --git a/variants/heltec_vision_master_e290/platformio.ini b/variants/heltec_e290/platformio.ini similarity index 53% rename from variants/heltec_vision_master_e290/platformio.ini rename to variants/heltec_e290/platformio.ini index 4150adc8..377162f4 100644 --- a/variants/heltec_vision_master_e290/platformio.ini +++ b/variants/heltec_e290/platformio.ini @@ -1,13 +1,21 @@ -[Heltec_Vision_Master_E290_base] +[Heltec_E290_base] extends = esp32_base -board = heltec_vision_master_e290 +board = heltec_e290 build_flags = ${esp32_base.build_flags} - -I variants/heltec_vision_master_e290 - -D HELTEC_VISION_MASTER_E290 + -I variants/heltec_e290 + -D Vision_Master_E290 + -D ARDUINO_USB_CDC_ON_BOOT=1 -D RADIO_CLASS=CustomSX1262 -D WRAPPER_CLASS=CustomSX1262Wrapper -D LORA_TX_POWER=22 + -D P_LORA_DIO_1=14 + -D P_LORA_NSS=8 + -D P_LORA_RESET=12 + -D P_LORA_BUSY=13 + -D P_LORA_SCLK=9 + -D P_LORA_MISO=11 + -D P_LORA_MOSI=10 -D P_LORA_TX_LED=45 -D PIN_USER_BTN=0 -D PIN_VEXT_EN=18 @@ -20,17 +28,16 @@ build_flags = -D SX126X_RX_BOOSTED_GAIN=1 -D PIN_BOARD_SDA=39 -D PIN_BOARD_SCL=38 - -D Vision_Master_E290 build_src_filter = ${esp32_base.build_src_filter} - +<../variants/heltec_vision_master_e290> + +<../variants/heltec_e290> lib_deps = ${esp32_base.lib_deps} https://github.com/Quency-D/heltec-eink-modules/archive/563dd41fd850a1bc3039b8723da4f3a20fe1c800.zip -[env:Heltec_Vision_Master_E290_radio_ble] -extends = Heltec_Vision_Master_E290_base +[env:Heltec_E290_companion_radio_ble] +extends = Heltec_E290_base build_flags = - ${Heltec_Vision_Master_E290_base.build_flags} + ${Heltec_E290_base.build_flags} -I examples/companion_radio/ui-new -D MAX_CONTACTS=300 -D MAX_GROUP_CHANNELS=8 @@ -38,43 +45,63 @@ build_flags = -D BLE_PIN_CODE=123456 ; dynamic, random PIN -D BLE_DEBUG_LOGGING=1 -D OFFLINE_QUEUE_SIZE=256 -build_src_filter = ${Heltec_Vision_Master_E290_base.build_src_filter} +build_src_filter = ${Heltec_E290_base.build_src_filter} + + +<../examples/companion_radio/*.cpp> +<../examples/companion_radio/ui-new/*.cpp> lib_deps = - ${Heltec_Vision_Master_E290_base.lib_deps} + ${Heltec_E290_base.lib_deps} densaugeo/base64 @ ~1.4.0 -[env:Heltec_Vision_Master_E290_repeater] -extends = Heltec_Vision_Master_E290_base +[env:Heltec_E290_companion_radio_usb] +extends = Heltec_E290_base build_flags = - ${Heltec_Vision_Master_E290_base.build_flags} + ${Heltec_E290_base.build_flags} + -I examples/companion_radio/ui-new + -D MAX_CONTACTS=300 + -D MAX_GROUP_CHANNELS=8 + -D DISPLAY_CLASS=E290Display + -D BLE_PIN_CODE=123456 ; dynamic, random PIN + -D BLE_DEBUG_LOGGING=1 + -D OFFLINE_QUEUE_SIZE=256 +build_src_filter = ${Heltec_E290_base.build_src_filter} + + + + + +<../examples/companion_radio/*.cpp> + +<../examples/companion_radio/ui-new/*.cpp> +lib_deps = + ${Heltec_E290_base.lib_deps} + densaugeo/base64 @ ~1.4.0 + +[env:Heltec_E290_repeater] +extends = Heltec_E290_base +build_flags = + ${Heltec_E290_base.build_flags} -D DISPLAY_CLASS=E290Display -D ADVERT_NAME='"Heltec E290 Repeater"' -D ADVERT_LAT=0.0 -D ADVERT_LON=0.0 -build_src_filter = ${Heltec_Vision_Master_E290_base.build_src_filter} +build_src_filter = ${Heltec_E290_base.build_src_filter} + +<../examples/simple_repeater> lib_deps = - ${Heltec_Vision_Master_E290_base.lib_deps} + ${Heltec_E290_base.lib_deps} ${esp32_ota.lib_deps} -[env:Heltec_Vision_Master_E290_room_server] -extends = Heltec_Vision_Master_E290_base +[env:Heltec_E290_room_server] +extends = Heltec_E290_base build_flags = - ${Heltec_Vision_Master_E290_base.build_flags} + ${Heltec_E290_base.build_flags} -D DISPLAY_CLASS=E290Display -D ADVERT_NAME='"Heltec E290 Room"' -D ADVERT_LAT=0.0 -D ADVERT_LON=0.0 -D ADMIN_PASSWORD='"password"' -D ROOM_PASSWORD='"hello"' -build_src_filter = ${Heltec_Vision_Master_E290_base.build_src_filter} +build_src_filter = ${Heltec_E290_base.build_src_filter} + +<../examples/simple_room_server> lib_deps = - ${Heltec_Vision_Master_E290_base.lib_deps} + ${Heltec_E290_base.lib_deps} ${esp32_ota.lib_deps} diff --git a/variants/heltec_vision_master_e290/target.cpp b/variants/heltec_e290/target.cpp similarity index 100% rename from variants/heltec_vision_master_e290/target.cpp rename to variants/heltec_e290/target.cpp diff --git a/variants/heltec_vision_master_e290/target.h b/variants/heltec_e290/target.h similarity index 100% rename from variants/heltec_vision_master_e290/target.h rename to variants/heltec_e290/target.h diff --git a/variants/heltec_vision_master_t190/HeltecT190Board.cpp b/variants/heltec_t190/HeltecT190Board.cpp similarity index 94% rename from variants/heltec_vision_master_t190/HeltecT190Board.cpp rename to variants/heltec_t190/HeltecT190Board.cpp index c5b03bc8..4f35be40 100644 --- a/variants/heltec_vision_master_t190/HeltecT190Board.cpp +++ b/variants/heltec_t190/HeltecT190Board.cpp @@ -23,7 +23,7 @@ void HeltecT190Board::begin() { void HeltecT190Board::enterDeepSleep(uint32_t secs, int pin_wake_btn) { esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); - // Make sure the DIO1 and NSS GPIOs are hold on required levels during deep sleep + // Make sure the DIO1 and NSS GPIOs are hold on required levels during deep sleep rtc_gpio_set_direction((gpio_num_t)P_LORA_DIO_1, RTC_GPIO_MODE_INPUT_ONLY); rtc_gpio_pulldown_en((gpio_num_t)P_LORA_DIO_1); @@ -44,8 +44,7 @@ void HeltecT190Board::begin() { } void HeltecT190Board::powerOff() { - // TODO: re-enable this when there is a definite wake-up source pin: - // enterDeepSleep(0); + enterDeepSleep(0); } uint16_t HeltecT190Board::getBattMilliVolts() { @@ -66,4 +65,3 @@ void HeltecT190Board::begin() { const char* HeltecT190Board::getManufacturerName() const { return "Heltec T190"; } - diff --git a/variants/heltec_vision_master_t190/HeltecT190Board.h b/variants/heltec_t190/HeltecT190Board.h similarity index 67% rename from variants/heltec_vision_master_t190/HeltecT190Board.h rename to variants/heltec_t190/HeltecT190Board.h index 96c09c1c..bc38c1e0 100644 --- a/variants/heltec_vision_master_t190/HeltecT190Board.h +++ b/variants/heltec_t190/HeltecT190Board.h @@ -5,15 +5,6 @@ #include #include -// LoRa radio module pins for heltec_vision_master_e290 -#define P_LORA_DIO_1 14 -#define P_LORA_NSS 8 -#define P_LORA_RESET 12 -#define P_LORA_BUSY 13 -#define P_LORA_SCLK 9 -#define P_LORA_MISO 11 -#define P_LORA_MOSI 10 - class HeltecT190Board : public ESP32Board { public: diff --git a/variants/heltec_vision_master_t190/pins_arduino.h b/variants/heltec_t190/pins_arduino.h similarity index 100% rename from variants/heltec_vision_master_t190/pins_arduino.h rename to variants/heltec_t190/pins_arduino.h diff --git a/variants/heltec_vision_master_t190/platformio.ini b/variants/heltec_t190/platformio.ini similarity index 57% rename from variants/heltec_vision_master_t190/platformio.ini rename to variants/heltec_t190/platformio.ini index e8492335..7debe178 100644 --- a/variants/heltec_vision_master_t190/platformio.ini +++ b/variants/heltec_t190/platformio.ini @@ -1,13 +1,20 @@ -[Heltec_Vision_Master_T190_base] +[Heltec_T190_base] extends = esp32_base -board = heltec_vision_master_t190 +board = heltec_t190 build_flags = ${esp32_base.build_flags} - -I variants/heltec_vision_master_t190 + -I variants/heltec_t190 -I src/helpers/ui -D HELTEC_VISION_MASTER_T190 -D RADIO_CLASS=CustomSX1262 -D WRAPPER_CLASS=CustomSX1262Wrapper + -D P_LORA_DIO_1=14 + -D P_LORA_NSS=8 + -D P_LORA_RESET=12 + -D P_LORA_BUSY=13 + -D P_LORA_SCLK=9 + -D P_LORA_MISO=11 + -D P_LORA_MOSI=10 -D LORA_TX_POWER=22 -D PIN_USER_BTN=0 -D PIN_VEXT_EN=5 @@ -31,7 +38,7 @@ build_flags = -D ST7789 -D DISPLAY_CLASS=ST7789Display build_src_filter = ${esp32_base.build_src_filter} - +<../variants/heltec_vision_master_t190> + +<../variants/heltec_t190> + + + @@ -40,48 +47,64 @@ lib_deps = ${esp32_base.lib_deps} adafruit/Adafruit GFX Library @ ^1.12.1 -[env:Heltec_Vision_Master_T190_radio_ble] -extends = Heltec_Vision_Master_T190_base +[env:Heltec_T190_companion_radio_ble] +extends = Heltec_T190_base build_flags = - ${Heltec_Vision_Master_T190_base.build_flags} + ${Heltec_T190_base.build_flags} -I examples/companion_radio/ui-new -D MAX_CONTACTS=300 -D MAX_GROUP_CHANNELS=8 -D BLE_PIN_CODE=123456 ; dynamic, random PIN -D BLE_DEBUG_LOGGING=1 -D OFFLINE_QUEUE_SIZE=256 -build_src_filter = ${Heltec_Vision_Master_T190_base.build_src_filter} +build_src_filter = ${Heltec_T190_base.build_src_filter} + +<../examples/companion_radio/*.cpp> +<../examples/companion_radio/ui-new/*.cpp> lib_deps = - ${Heltec_Vision_Master_T190_base.lib_deps} + ${Heltec_T190_base.lib_deps} densaugeo/base64 @ ~1.4.0 -[env:Heltec_Vision_Master_T190_repeater] -extends = Heltec_Vision_Master_T190_base +[env:Heltec_T190_companion_radio_usb] +extends = Heltec_T190_base build_flags = - ${Heltec_Vision_Master_T190_base.build_flags} + ${Heltec_T190_base.build_flags} + -I examples/companion_radio/ui-new + -D MAX_CONTACTS=300 + -D MAX_GROUP_CHANNELS=8 + -D OFFLINE_QUEUE_SIZE=256 +build_src_filter = ${Heltec_T190_base.build_src_filter} + + + +<../examples/companion_radio/*.cpp> + +<../examples/companion_radio/ui-new/*.cpp> +lib_deps = + ${Heltec_T190_base.lib_deps} + densaugeo/base64 @ ~1.4.0 + +[env:Heltec_T190_repeater] +extends = Heltec_T190_base +build_flags = + ${Heltec_T190_base.build_flags} -D ADVERT_NAME='"Heltec T190 Repeater"' -D ADVERT_LAT=0.0 -D ADVERT_LON=0.0 -build_src_filter = ${Heltec_Vision_Master_T190_base.build_src_filter} +build_src_filter = ${Heltec_T190_base.build_src_filter} +<../examples/simple_repeater> lib_deps = - ${Heltec_Vision_Master_T190_base.lib_deps} + ${Heltec_T190_base.lib_deps} ${esp32_ota.lib_deps} -[env:Heltec_Vision_Master_T190_room_server] -extends = Heltec_Vision_Master_T190_base +[env:Heltec_T190_room_server] +extends = Heltec_T190_base build_flags = - ${Heltec_Vision_Master_T190_base.build_flags} + ${Heltec_T190_base.build_flags} -D ADVERT_NAME='"Heltec T190 Room"' -D ADVERT_LAT=0.0 -D ADVERT_LON=0.0 -D ADMIN_PASSWORD='"password"' -D ROOM_PASSWORD='"hello"' -build_src_filter = ${Heltec_Vision_Master_T190_base.build_src_filter} +build_src_filter = ${Heltec_T190_base.build_src_filter} +<../examples/simple_room_server> lib_deps = - ${Heltec_Vision_Master_T190_base.lib_deps} + ${Heltec_T190_base.lib_deps} ${esp32_ota.lib_deps} diff --git a/variants/heltec_vision_master_t190/target.cpp b/variants/heltec_t190/target.cpp similarity index 100% rename from variants/heltec_vision_master_t190/target.cpp rename to variants/heltec_t190/target.cpp diff --git a/variants/heltec_vision_master_t190/target.h b/variants/heltec_t190/target.h similarity index 100% rename from variants/heltec_vision_master_t190/target.h rename to variants/heltec_t190/target.h From ce31fd7c572d025ca96fab9e2a87fa705fba570c Mon Sep 17 00:00:00 2001 From: taco Date: Wed, 3 Sep 2025 08:25:59 +1000 Subject: [PATCH 05/13] multi click support including buzzer toggle --- examples/companion_radio/ui-new/UITask.cpp | 46 +++++++++++++++++++--- examples/companion_radio/ui-new/UITask.h | 6 +++ src/helpers/ui/MomentaryButton.cpp | 38 +++++++++++++++++- src/helpers/ui/MomentaryButton.h | 6 +++ 4 files changed, 89 insertions(+), 7 deletions(-) diff --git a/examples/companion_radio/ui-new/UITask.cpp b/examples/companion_radio/ui-new/UITask.cpp index c751eaf5..d3fc5bad 100644 --- a/examples/companion_radio/ui-new/UITask.cpp +++ b/examples/companion_radio/ui-new/UITask.cpp @@ -495,6 +495,10 @@ void UITask::loop() { c = checkDisplayOn(KEY_SELECT); } else if (ev == BUTTON_EVENT_LONG_PRESS) { c = handleLongPress(KEY_ENTER); + } else if (ev == BUTTON_EVENT_DOUBLE_CLICK) { + c = handleDoubleClick(KEY_ENTER); + } else if (ev == BUTTON_EVENT_TRIPLE_CLICK) { + c = handleTripleClick(KEY_ENTER); } #endif #if defined(WIO_TRACKER_L1) @@ -604,10 +608,43 @@ char UITask::handleLongPress(char c) { return c; } -/* -void UITask::handleButtonTriplePress() { - MESH_DEBUG_PRINTLN("UITask: triple press triggered"); - // Toggle buzzer quiet mode +char UITask::handleDoubleClick(char c) { + MESH_DEBUG_PRINTLN("UITask: double click triggered"); + c = 0; + return c; +} + +char UITask::handleTripleClick(char c) { + MESH_DEBUG_PRINTLN("UITask: triple click triggered"); + toggleBuzzer(); + c = 0; + return c; +} + +void UITask::toggleGPS() { + if (_sensors != NULL) { + // toggle GPS on/off + int num = _sensors->getNumSettings(); + for (int i = 0; i < num; i++) { + if (strcmp(_sensors->getSettingName(i), "gps") == 0) { + if (strcmp(_sensors->getSettingValue(i), "1") == 0) { + _sensors->setSettingValue("gps", "0"); + soundBuzzer(UIEventType::ack); + showAlert("GPS: Disabled", 600); + } else { + _sensors->setSettingValue("gps", "1"); + soundBuzzer(UIEventType::ack); + showAlert("GPS: Enabled", 600); + } + _next_refresh = 0; + break; + } + } + } +} + +void UITask::toggleBuzzer() { + // Toggle buzzer quiet mode #ifdef PIN_BUZZER if (buzzer.isQuiet()) { buzzer.quiet(false); @@ -620,4 +657,3 @@ void UITask::handleButtonTriplePress() { _next_refresh = 0; // trigger refresh #endif } -*/ diff --git a/examples/companion_radio/ui-new/UITask.h b/examples/companion_radio/ui-new/UITask.h index f9e01550..a96abf89 100644 --- a/examples/companion_radio/ui-new/UITask.h +++ b/examples/companion_radio/ui-new/UITask.h @@ -37,6 +37,8 @@ class UITask : public AbstractUITask { // Button action handlers char checkDisplayOn(char c); char handleLongPress(char c); + char handleDoubleClick(char c); + char handleTripleClick(char c); void setCurrScreen(UIScreen* c); @@ -55,6 +57,10 @@ public: bool hasDisplay() const { return _display != NULL; } bool isButtonPressed() const; + void toggleBuzzer(); + void toggleGPS(); + + // from AbstractUITask void msgRead(int msgcount) override; void newMsg(uint8_t path_len, const char* from_name, const char* text, int msgcount) override; diff --git a/src/helpers/ui/MomentaryButton.cpp b/src/helpers/ui/MomentaryButton.cpp index 36309600..4b87705a 100644 --- a/src/helpers/ui/MomentaryButton.cpp +++ b/src/helpers/ui/MomentaryButton.cpp @@ -9,6 +9,10 @@ MomentaryButton::MomentaryButton(int8_t pin, int long_press_millis, bool reverse cancel = 0; _long_millis = long_press_millis; _threshold = 0; + _click_count = 0; + _last_click_time = 0; + _multi_click_window = 500; + _pending_click = false; } MomentaryButton::MomentaryButton(int8_t pin, int long_press_millis, int analog_threshold) { @@ -20,6 +24,10 @@ MomentaryButton::MomentaryButton(int8_t pin, int long_press_millis, int analog_t cancel = 0; _long_millis = long_press_millis; _threshold = analog_threshold; + _click_count = 0; + _last_click_time = 0; + _multi_click_window = 500; + _pending_click = false; } void MomentaryButton::begin() { @@ -35,6 +43,8 @@ bool MomentaryButton::isPressed() const { void MomentaryButton::cancelClick() { cancel = 1; + _click_count = 0; + _pending_click = false; } bool MomentaryButton::isPressed(int level) const { @@ -60,10 +70,14 @@ int MomentaryButton::check(bool repeat_click) { // button UP if (_long_millis > 0) { if (down_at > 0 && (unsigned long)(millis() - down_at) < _long_millis) { // only a CLICK if still within the long_press millis - event = BUTTON_EVENT_CLICK; + _click_count++; + _last_click_time = millis(); + _pending_click = true; } } else { - event = BUTTON_EVENT_CLICK; // any UP results in CLICK event when NOT using long_press feature + _click_count++; + _last_click_time = millis(); + _pending_click = true; } if (event == BUTTON_EVENT_CLICK && cancel) { event = BUTTON_EVENT_NONE; @@ -87,5 +101,25 @@ int MomentaryButton::check(bool repeat_click) { } } + if (_pending_click && (millis() - _last_click_time) >= _multi_click_window) { + switch (_click_count) { + case 1: + event = BUTTON_EVENT_CLICK; + break; + case 2: + event = BUTTON_EVENT_DOUBLE_CLICK; + break; + case 3: + event = BUTTON_EVENT_TRIPLE_CLICK; + break; + default: + // For 4+ clicks, treat as triple click? + event = BUTTON_EVENT_TRIPLE_CLICK; + break; + } + _click_count = 0; + _pending_click = false; + } + return event; } \ No newline at end of file diff --git a/src/helpers/ui/MomentaryButton.h b/src/helpers/ui/MomentaryButton.h index d002f652..1122e56a 100644 --- a/src/helpers/ui/MomentaryButton.h +++ b/src/helpers/ui/MomentaryButton.h @@ -5,6 +5,8 @@ #define BUTTON_EVENT_NONE 0 #define BUTTON_EVENT_CLICK 1 #define BUTTON_EVENT_LONG_PRESS 2 +#define BUTTON_EVENT_DOUBLE_CLICK 3 +#define BUTTON_EVENT_TRIPLE_CLICK 4 class MomentaryButton { int8_t _pin; @@ -13,6 +15,10 @@ class MomentaryButton { int _long_millis; int _threshold; // analog mode unsigned long down_at; + uint8_t _click_count; + unsigned long _last_click_time; + int _multi_click_window; + bool _pending_click; bool isPressed(int level) const; From 43c3105bf1d0fc8c0682960352bf0f3aedb64af1 Mon Sep 17 00:00:00 2001 From: taco Date: Wed, 3 Sep 2025 08:31:38 +1000 Subject: [PATCH 06/13] wake screen on double and triple clicks --- examples/companion_radio/ui-new/UITask.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/companion_radio/ui-new/UITask.cpp b/examples/companion_radio/ui-new/UITask.cpp index d3fc5bad..1c565a8a 100644 --- a/examples/companion_radio/ui-new/UITask.cpp +++ b/examples/companion_radio/ui-new/UITask.cpp @@ -610,12 +610,14 @@ char UITask::handleLongPress(char c) { char UITask::handleDoubleClick(char c) { MESH_DEBUG_PRINTLN("UITask: double click triggered"); + checkDisplayOn(c); c = 0; return c; } char UITask::handleTripleClick(char c) { MESH_DEBUG_PRINTLN("UITask: triple click triggered"); + checkDisplayOn(c); toggleBuzzer(); c = 0; return c; From 5de0dc1fd6152a7f3bb5a34f0f8e0679138093c8 Mon Sep 17 00:00:00 2001 From: taco Date: Wed, 3 Sep 2025 12:03:31 +1000 Subject: [PATCH 07/13] sliding multiclick window --- src/helpers/ui/MomentaryButton.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/helpers/ui/MomentaryButton.cpp b/src/helpers/ui/MomentaryButton.cpp index 4b87705a..0446c639 100644 --- a/src/helpers/ui/MomentaryButton.cpp +++ b/src/helpers/ui/MomentaryButton.cpp @@ -11,7 +11,7 @@ MomentaryButton::MomentaryButton(int8_t pin, int long_press_millis, bool reverse _threshold = 0; _click_count = 0; _last_click_time = 0; - _multi_click_window = 500; + _multi_click_window = 260; _pending_click = false; } @@ -26,7 +26,7 @@ MomentaryButton::MomentaryButton(int8_t pin, int long_press_millis, int analog_t _threshold = analog_threshold; _click_count = 0; _last_click_time = 0; - _multi_click_window = 500; + _multi_click_window = 260; _pending_click = false; } @@ -81,6 +81,9 @@ int MomentaryButton::check(bool repeat_click) { } if (event == BUTTON_EVENT_CLICK && cancel) { event = BUTTON_EVENT_NONE; + _click_count = 0; + _last_click_time = 0; + _pending_click = false; } down_at = 0; } @@ -93,6 +96,9 @@ int MomentaryButton::check(bool repeat_click) { if (_long_millis > 0 && down_at > 0 && (unsigned long)(millis() - down_at) >= _long_millis) { event = BUTTON_EVENT_LONG_PRESS; down_at = 0; + _click_count = 0; + _last_click_time = 0; + _pending_click = false; } if (down_at > 0 && repeat_click) { unsigned long diff = (unsigned long)(millis() - down_at); @@ -118,6 +124,7 @@ int MomentaryButton::check(bool repeat_click) { break; } _click_count = 0; + _last_click_time = 0; _pending_click = false; } From 9f185303b4448df72c2fa38d844a6d6b8ecdae72 Mon Sep 17 00:00:00 2001 From: taco Date: Wed, 3 Sep 2025 12:29:20 +1000 Subject: [PATCH 08/13] long press cancels multi click --- src/helpers/ui/MomentaryButton.cpp | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/helpers/ui/MomentaryButton.cpp b/src/helpers/ui/MomentaryButton.cpp index 0446c639..0ea4b027 100644 --- a/src/helpers/ui/MomentaryButton.cpp +++ b/src/helpers/ui/MomentaryButton.cpp @@ -1,5 +1,7 @@ #include "MomentaryButton.h" +#define MULTI_CLICK_WINDOW_MS 280 + MomentaryButton::MomentaryButton(int8_t pin, int long_press_millis, bool reverse, bool pulldownup) { _pin = pin; _reverse = reverse; @@ -11,7 +13,7 @@ MomentaryButton::MomentaryButton(int8_t pin, int long_press_millis, bool reverse _threshold = 0; _click_count = 0; _last_click_time = 0; - _multi_click_window = 260; + _multi_click_window = MULTI_CLICK_WINDOW_MS; _pending_click = false; } @@ -26,7 +28,7 @@ MomentaryButton::MomentaryButton(int8_t pin, int long_press_millis, int analog_t _threshold = analog_threshold; _click_count = 0; _last_click_time = 0; - _multi_click_window = 260; + _multi_click_window = MULTI_CLICK_WINDOW_MS; _pending_click = false; } @@ -43,7 +45,9 @@ bool MomentaryButton::isPressed() const { void MomentaryButton::cancelClick() { cancel = 1; + down_at = 0; _click_count = 0; + _last_click_time = 0; _pending_click = false; } @@ -94,11 +98,16 @@ int MomentaryButton::check(bool repeat_click) { } if (_long_millis > 0 && down_at > 0 && (unsigned long)(millis() - down_at) >= _long_millis) { - event = BUTTON_EVENT_LONG_PRESS; - down_at = 0; - _click_count = 0; - _last_click_time = 0; - _pending_click = false; + if (_pending_click) { + // long press during multi-click detection - cancel pending clicks + cancelClick(); + } else { + event = BUTTON_EVENT_LONG_PRESS; + down_at = 0; + _click_count = 0; + _last_click_time = 0; + _pending_click = false; + } } if (down_at > 0 && repeat_click) { unsigned long diff = (unsigned long)(millis() - down_at); @@ -108,6 +117,10 @@ int MomentaryButton::check(bool repeat_click) { } if (_pending_click && (millis() - _last_click_time) >= _multi_click_window) { + if (down_at > 0) { + // still pressed - wait for button release before processing clicks + return event; + } switch (_click_count) { case 1: event = BUTTON_EVENT_CLICK; From a9ab1f072a78e0eea51e7f469af00be9536b16f4 Mon Sep 17 00:00:00 2001 From: taco Date: Wed, 3 Sep 2025 14:02:35 +1000 Subject: [PATCH 09/13] increase gps/buzzer alert times 600 is a bit short for eink --- examples/companion_radio/ui-new/UITask.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/companion_radio/ui-new/UITask.cpp b/examples/companion_radio/ui-new/UITask.cpp index 1c565a8a..39eb26b3 100644 --- a/examples/companion_radio/ui-new/UITask.cpp +++ b/examples/companion_radio/ui-new/UITask.cpp @@ -632,11 +632,11 @@ void UITask::toggleGPS() { if (strcmp(_sensors->getSettingValue(i), "1") == 0) { _sensors->setSettingValue("gps", "0"); soundBuzzer(UIEventType::ack); - showAlert("GPS: Disabled", 600); + showAlert("GPS: Disabled", 800); } else { _sensors->setSettingValue("gps", "1"); soundBuzzer(UIEventType::ack); - showAlert("GPS: Enabled", 600); + showAlert("GPS: Enabled", 800); } _next_refresh = 0; break; @@ -651,10 +651,10 @@ void UITask::toggleBuzzer() { if (buzzer.isQuiet()) { buzzer.quiet(false); soundBuzzer(UIEventType::ack); - showAlert("Buzzer: ON", 600); + showAlert("Buzzer: ON", 800); } else { buzzer.quiet(true); - showAlert("Buzzer: OFF", 600); + showAlert("Buzzer: OFF", 800); } _next_refresh = 0; // trigger refresh #endif From afbfc6c6edd223a9f7bfd4eae0305394afa026b6 Mon Sep 17 00:00:00 2001 From: taco Date: Wed, 3 Sep 2025 15:48:50 +1000 Subject: [PATCH 10/13] add new keycodes --- src/helpers/ui/UIScreen.h | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/helpers/ui/UIScreen.h b/src/helpers/ui/UIScreen.h index 6faa591a..6aa1d69c 100644 --- a/src/helpers/ui/UIScreen.h +++ b/src/helpers/ui/UIScreen.h @@ -2,13 +2,17 @@ #include "DisplayDriver.h" -#define KEY_LEFT 0xB4 -#define KEY_UP 0xB5 -#define KEY_DOWN 0xB6 -#define KEY_RIGHT 0xB7 -#define KEY_SELECT 10 -#define KEY_ENTER 13 -#define KEY_BACK 27 // Esc +#define KEY_LEFT 0xB4 +#define KEY_UP 0xB5 +#define KEY_DOWN 0xB6 +#define KEY_RIGHT 0xB7 +#define KEY_SELECT 10 +#define KEY_ENTER 13 +#define KEY_CANCEL 27 // Esc +#define KEY_HOME 0xF0 +#define KEY_NEXT 0xF1 +#define KEY_PREV 0xF2 +#define KEY_CONTEXT_MENU 0xF3 class UIScreen { protected: From 96a71bb21b6f93fd8f7c22496ff4999ec406249a Mon Sep 17 00:00:00 2001 From: taco Date: Wed, 3 Sep 2025 16:28:58 +1000 Subject: [PATCH 11/13] alter keycode keycode handling --- examples/companion_radio/ui-new/UITask.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/examples/companion_radio/ui-new/UITask.cpp b/examples/companion_radio/ui-new/UITask.cpp index 39eb26b3..dfc545d0 100644 --- a/examples/companion_radio/ui-new/UITask.cpp +++ b/examples/companion_radio/ui-new/UITask.cpp @@ -223,11 +223,11 @@ public: } bool handleInput(char c) override { - if (c == KEY_LEFT) { + if (c == KEY_LEFT || c == KEY_PREV) { _page = (_page + HomePage::Count - 1) % HomePage::Count; return true; } - if (c == KEY_RIGHT || c == KEY_SELECT) { + if (c == KEY_NEXT || c == KEY_RIGHT) { _page = (_page + 1) % HomePage::Count; if (_page == HomePage::RECENT) { _task->showAlert("Recent adverts", 800); @@ -325,7 +325,7 @@ public: } bool handleInput(char c) override { - if (c == KEY_SELECT || c == KEY_RIGHT) { + if (c == KEY_NEXT || c == KEY_RIGHT) { num_unread--; if (num_unread == 0) { _task->gotoHomeScreen(); @@ -492,13 +492,13 @@ void UITask::loop() { #if defined(PIN_USER_BTN) int ev = user_btn.check(); if (ev == BUTTON_EVENT_CLICK) { - c = checkDisplayOn(KEY_SELECT); + c = checkDisplayOn(KEY_NEXT); } else if (ev == BUTTON_EVENT_LONG_PRESS) { c = handleLongPress(KEY_ENTER); } else if (ev == BUTTON_EVENT_DOUBLE_CLICK) { - c = handleDoubleClick(KEY_ENTER); + c = handleDoubleClick(KEY_PREV); } else if (ev == BUTTON_EVENT_TRIPLE_CLICK) { - c = handleTripleClick(KEY_ENTER); + c = handleTripleClick(KEY_SELECT); } #endif #if defined(WIO_TRACKER_L1) @@ -518,9 +518,13 @@ void UITask::loop() { #if defined(PIN_USER_BTN_ANA) ev = analog_btn.check(); if (ev == BUTTON_EVENT_CLICK) { - c = checkDisplayOn(KEY_SELECT); + c = checkDisplayOn(KEY_NEXT); } else if (ev == BUTTON_EVENT_LONG_PRESS) { c = handleLongPress(KEY_ENTER); + } else if (ev == BUTTON_EVENT_DOUBLE_CLICK) { + c = handleDoubleClick(KEY_PREV); + } else if (ev == BUTTON_EVENT_TRIPLE_CLICK) { + c = handleTripleClick(KEY_SELECT); } #endif @@ -611,7 +615,6 @@ char UITask::handleLongPress(char c) { char UITask::handleDoubleClick(char c) { MESH_DEBUG_PRINTLN("UITask: double click triggered"); checkDisplayOn(c); - c = 0; return c; } From cb3049e706201e300681981590feceeb5af02a91 Mon Sep 17 00:00:00 2001 From: Florent Date: Wed, 3 Sep 2025 17:22:11 +0200 Subject: [PATCH 12/13] cleanups (remove statics and typos) --- examples/companion_radio/ui-new/UITask.cpp | 33 +++++++++------------- examples/companion_radio/ui-new/UITask.h | 6 ++++ src/helpers/ui/GxEPDDisplay.cpp | 2 +- variants/techo/platformio.ini | 1 + 4 files changed, 22 insertions(+), 20 deletions(-) diff --git a/examples/companion_radio/ui-new/UITask.cpp b/examples/companion_radio/ui-new/UITask.cpp index f0f9ed1d..a02b0288 100644 --- a/examples/companion_radio/ui-new/UITask.cpp +++ b/examples/companion_radio/ui-new/UITask.cpp @@ -419,38 +419,34 @@ void UITask::newMsg(uint8_t path_len, const char* from_name, const char* text, i if (_display != NULL) { if (!_display->isOn()) _display->turnOn(); _auto_off = millis() + AUTO_OFF_MILLIS; // extend the auto-off timer - _next_refresh = 0; // trigger refresh + _next_refresh = 100; // trigger refresh } } void UITask::userLedHandler() { #ifdef PIN_STATUS_LED - static int state = 0; - static int next_change = 0; - static int last_increment = 0; - int cur_time = millis(); - if (cur_time > next_change) { - if (state == 0) { - state = 1; + if (cur_time > next_led_change) { + if (led_state == 0) { + led_state = 1; if (_msgcount > 0) { - last_increment = LED_ON_MSG_MILLIS; + last_led_increment = LED_ON_MSG_MILLIS; } else { - last_increment = LED_ON_MILLIS; + last_led_increment = LED_ON_MILLIS; } - next_change = cur_time + last_increment; + next_led_change = cur_time + last_led_increment; } else { - state = 0; - next_change = cur_time + LED_CYCLE_MILLIS - last_increment; + led_state = 0; + next_led_change = cur_time + LED_CYCLE_MILLIS - last_led_increment; } - digitalWrite(PIN_STATUS_LED, state); + digitalWrite(PIN_STATUS_LED, led_state); } #endif } void UITask::setCurrScreen(UIScreen* c) { curr = c; - _next_refresh = 0; + _next_refresh = 100; } /* @@ -520,18 +516,17 @@ void UITask::loop() { } #endif #if defined(DISP_BACKLIGHT) && defined(BACKLIGHT_BTN) - static int next_btn_check = 0; - if (millis() > next_btn_check) { + if (millis() > next_backlight_btn_check) { bool touch_state = digitalRead(PIN_BUTTON2); digitalWrite(DISP_BACKLIGHT, !touch_state); - next_btn_check = millis() + 300; + next_backlight_btn_check = millis() + 300; } #endif if (c != 0 && curr) { curr->handleInput(c); _auto_off = millis() + AUTO_OFF_MILLIS; // extend auto-off timer - _next_refresh = 0; // trigger refresh + _next_refresh = 100; // trigger refresh } userLedHandler(); diff --git a/examples/companion_radio/ui-new/UITask.h b/examples/companion_radio/ui-new/UITask.h index f9e01550..3a27e55f 100644 --- a/examples/companion_radio/ui-new/UITask.h +++ b/examples/companion_radio/ui-new/UITask.h @@ -26,6 +26,12 @@ class UITask : public AbstractUITask { unsigned long _alert_expiry; int _msgcount; unsigned long ui_started_at, next_batt_chck; + int next_backlight_btn_check = 0; +#ifdef PIN_STATUS_LED + int led_state = 0; + int next_led_change = 0; + int last_led_increment = 0; +#endif UIScreen* splash; UIScreen* home; diff --git a/src/helpers/ui/GxEPDDisplay.cpp b/src/helpers/ui/GxEPDDisplay.cpp index 9ba7d074..49022d74 100644 --- a/src/helpers/ui/GxEPDDisplay.cpp +++ b/src/helpers/ui/GxEPDDisplay.cpp @@ -28,7 +28,7 @@ bool GxEPDDisplay::begin() { void GxEPDDisplay::turnOn() { if (!_init) begin(); -#if defined(DISP_BACKLIGHT) && !defined(BACLIGHT_BTN) +#if defined(DISP_BACKLIGHT) && !defined(BACKLIGHT_BTN) digitalWrite(DISP_BACKLIGHT, HIGH); #endif _isOn = true; diff --git a/variants/techo/platformio.ini b/variants/techo/platformio.ini index 260be35f..f748fdfe 100644 --- a/variants/techo/platformio.ini +++ b/variants/techo/platformio.ini @@ -92,3 +92,4 @@ lib_deps = ${LilyGo_Techo.lib_deps} densaugeo/base64 @ ~1.4.0 zinggjm/GxEPD2 @ 1.6.2 + bakercp/CRC32 @ ^2.0.0 From 9f97edcb21f01fb126bd94f55a1215d965c41999 Mon Sep 17 00:00:00 2001 From: Florent Date: Wed, 3 Sep 2025 18:17:37 +0200 Subject: [PATCH 13/13] gxepd: use a crc to track damage ! --- examples/companion_radio/ui-new/UITask.cpp | 10 ++++++++- src/helpers/ui/GxEPDDisplay.cpp | 26 +++++++++++++++++++++- src/helpers/ui/GxEPDDisplay.h | 3 +++ variants/techo/platformio.ini | 3 ++- 4 files changed, 39 insertions(+), 3 deletions(-) diff --git a/examples/companion_radio/ui-new/UITask.cpp b/examples/companion_radio/ui-new/UITask.cpp index a02b0288..8ca5c950 100644 --- a/examples/companion_radio/ui-new/UITask.cpp +++ b/examples/companion_radio/ui-new/UITask.cpp @@ -3,7 +3,9 @@ #include "../MyMesh.h" #include "target.h" -#define AUTO_OFF_MILLIS 15000 // 15 seconds +#ifndef AUTO_OFF_MILLIS + #define AUTO_OFF_MILLIS 15000 // 15 seconds +#endif #define BOOT_SCREEN_MILLIS 3000 // 3 seconds #ifdef PIN_STATUS_LED @@ -321,7 +323,11 @@ public: display.setColor(DisplayDriver::LIGHT); display.printWordWrap(p->msg, display.width()); +#if AUTO_OFF_MILLIS==0 // probably e-ink + return 10000; // 10 s +#else return 1000; // next render after 1000 ms +#endif } bool handleInput(char c) override { @@ -556,9 +562,11 @@ void UITask::loop() { } _display->endFrame(); } +#if AUTO_OFF_MILLIS > 0 if (millis() > _auto_off) { _display->turnOff(); } +#endif } #ifdef AUTO_SHUTDOWN_MILLIVOLTS diff --git a/src/helpers/ui/GxEPDDisplay.cpp b/src/helpers/ui/GxEPDDisplay.cpp index 49022d74..98b34eaa 100644 --- a/src/helpers/ui/GxEPDDisplay.cpp +++ b/src/helpers/ui/GxEPDDisplay.cpp @@ -44,14 +44,17 @@ void GxEPDDisplay::turnOff() { void GxEPDDisplay::clear() { display.fillScreen(GxEPD_WHITE); display.setTextColor(GxEPD_BLACK); + display_crc.reset(); } void GxEPDDisplay::startFrame(Color bkg) { display.fillScreen(GxEPD_WHITE); display.setTextColor(_curr_color = GxEPD_BLACK); + display_crc.reset(); } void GxEPDDisplay::setTextSize(int sz) { + display_crc.update(sz); switch(sz) { case 1: // Small display.setFont(&FreeSans9pt7b); @@ -69,6 +72,7 @@ void GxEPDDisplay::setTextSize(int sz) { } void GxEPDDisplay::setColor(Color c) { + display_crc.update (c); // colours need to be inverted for epaper displays if (c == DARK) { display.setTextColor(_curr_color = GxEPD_WHITE); @@ -78,22 +82,38 @@ void GxEPDDisplay::setColor(Color c) { } void GxEPDDisplay::setCursor(int x, int y) { + display_crc.update(x); + display_crc.update(y); display.setCursor(x*SCALE_X, (y+10)*SCALE_Y); } void GxEPDDisplay::print(const char* str) { + display_crc.update(str, strlen(str)); display.print(str); } void GxEPDDisplay::fillRect(int x, int y, int w, int h) { + display_crc.update(x); + display_crc.update(y); + display_crc.update(w); + display_crc.update(h); display.fillRect(x*SCALE_X, y*SCALE_Y, w*SCALE_X, h*SCALE_Y, _curr_color); } void GxEPDDisplay::drawRect(int x, int y, int w, int h) { + display_crc.update(x); + display_crc.update(y); + display_crc.update(w); + display_crc.update(h); display.drawRect(x*SCALE_X, y*SCALE_Y, w*SCALE_X, h*SCALE_Y, _curr_color); } void GxEPDDisplay::drawXbm(int x, int y, const uint8_t* bits, int w, int h) { + display_crc.update(x); + display_crc.update(y); + display_crc.update(w); + display_crc.update(h); + display_crc.update(bits, w * h / 8); // Calculate the base position in display coordinates uint16_t startX = x * SCALE_X; uint16_t startY = y * SCALE_Y; @@ -137,5 +157,9 @@ uint16_t GxEPDDisplay::getTextWidth(const char* str) { } void GxEPDDisplay::endFrame() { - display.display(true); + uint32_t crc = display_crc.finalize(); + if (crc != last_display_crc_value) { + display.display(true); + last_display_crc_value = crc; + } } diff --git a/src/helpers/ui/GxEPDDisplay.h b/src/helpers/ui/GxEPDDisplay.h index 49746dee..9acf3ac2 100644 --- a/src/helpers/ui/GxEPDDisplay.h +++ b/src/helpers/ui/GxEPDDisplay.h @@ -17,6 +17,7 @@ #define GxEPD2_DRIVER_CLASS GxEPD2_150_BN // DEPG0150BN 200x200, SSD1681, (FPC8101), TTGO T5 V2.4.1 #include // 1.54" b/w +#include #include "DisplayDriver.h" @@ -29,6 +30,8 @@ class GxEPDDisplay : public DisplayDriver { bool _init = false; bool _isOn = false; uint16_t _curr_color; + CRC32 display_crc; + int last_display_crc_value = 0; public: // there is a margin in y... diff --git a/variants/techo/platformio.ini b/variants/techo/platformio.ini index f748fdfe..812baa78 100644 --- a/variants/techo/platformio.ini +++ b/variants/techo/platformio.ini @@ -74,11 +74,12 @@ build_flags = -D MAX_CONTACTS=100 -D MAX_GROUP_CHANNELS=8 -D BLE_PIN_CODE=123456 - -D BLE_DEBUG_LOGGING=1 +; -D BLE_DEBUG_LOGGING=1 -D DISPLAY_CLASS=GxEPDDisplay -D OFFLINE_QUEUE_SIZE=256 -D UI_RECENT_LIST_SIZE=9 -D BACKLIGHT_BTN=PIN_BUTTON2 + -D AUTO_OFF_MILLIS=0 ; -D MESH_PACKET_LOGGING=1 ; -D MESH_DEBUG=1 build_src_filter = ${LilyGo_Techo.build_src_filter}