diff --git a/Dev_Docs/Pending_Features/2026-06-08_1435_esp32_lvgl_touch_debug_test.md b/Dev_Docs/Pending_Features/2026-06-08_1435_esp32_lvgl_touch_debug_test.md new file mode 100644 index 0000000..a1c0488 --- /dev/null +++ b/Dev_Docs/Pending_Features/2026-06-08_1435_esp32_lvgl_touch_debug_test.md @@ -0,0 +1,14 @@ +# ESP32 LVGL touch debug test + +- краткое описание фичи: + добавлен отдельный диагностический скетч `lvgl_touch_debug_test`, который одновременно показывает сырые координаты touch, маркер точки касания и одну большую кнопку `LVGL`. Он нужен, чтобы отделить проблему raw-touch от проблемы доставки событий в `LVGL`. +- что именно проверять: + 1. Прошить режим `lvgl-touch-debug-test`. + 2. Коснуться экрана в разных местах. + 3. Проверить, меняется ли текст `RAW pressed` и координаты `x/y`. + 4. Проверить, появляется ли розовый маркер точки касания. + 5. Проверить, срабатывает ли большая кнопка `Tap Here` и меняется ли строка `LVGL button clicked`. +- ожидаемый результат: + становится ясно, работает ли сам touch-драйвер, правильно ли приходят координаты и доходит ли нажатие до кнопки `LVGL`. +- статус: + pending diff --git a/Dev_Docs/Pending_Features/2026-06-08_1510_esp32_lvgl_official_based_test.md b/Dev_Docs/Pending_Features/2026-06-08_1510_esp32_lvgl_official_based_test.md new file mode 100644 index 0000000..d08f49e --- /dev/null +++ b/Dev_Docs/Pending_Features/2026-06-08_1510_esp32_lvgl_official_based_test.md @@ -0,0 +1,13 @@ +# ESP32 LVGL official based test + +- краткое описание фичи: + добавлен отдельный скетч `lvgl_official_based_test`, который строится на максимально близкой к официальному `05_LVGL_Widgets` инициализации `display + touch + LVGL`, но вместо официального demo рисует наш компактный экран с кнопками и статусом нажатия. +- что именно проверять: + 1. Прошить режим `lvgl-official-based-test`. + 2. Убедиться, что экран отображается без артефактов по краям. + 3. Нажать разные кнопки и проверить, меняется ли нижняя строка `Pressed: ...`. + 4. Проверить, идут ли координаты touch в `Serial`. +- ожидаемый результат: + если официальный каркас инициализации действительно является рабочей базой, то на этом тесте должны заработать и touch, и кнопки, и исчезнуть визуальные артефакты, которые были в наших самодельных `LVGL`-тестах. +- статус: + pending diff --git a/ESP32/esp32/ESP32-S3-Touch-AMOLED-2.16/test-device/README.md b/ESP32/esp32/ESP32-S3-Touch-AMOLED-2.16/test-device/README.md index 47388ec..df8c438 100644 --- a/ESP32/esp32/ESP32-S3-Touch-AMOLED-2.16/test-device/README.md +++ b/ESP32/esp32/ESP32-S3-Touch-AMOLED-2.16/test-device/README.md @@ -16,6 +16,9 @@ - `gfx-layout-test` — тест геометрии и нижних рядов кнопок - `lvgl-basic-test` — минимальный экран на `LVGL` с текстом и кнопками - `lvgl-interaction-test` — экран на `LVGL` с большим числом кнопок и сообщением о нажатой кнопке +- `lvgl-touch-debug-test` — точечная диагностика touch: сырые координаты, маркер точки и большая тест-кнопка `LVGL` +- `lvgl-official-based-test` — наш минимальный экран, но на максимально близкой к официальному `LVGL_Widgets` инициализации +- `lvgl-subserver-touch-test` — гибрид: `LVGL`-интерфейс, но display/touch init и raw touch-read взяты из `shine_subserver_ui`; подтверждено на устройстве, touch работает, зелёных линий по краям нет Запуск: @@ -29,4 +32,7 @@ - `./burn.sh gfx-layout-test` - `./burn.sh lvgl-basic-test` - `./burn.sh lvgl-interaction-test` +- `./burn.sh lvgl-touch-debug-test` +- `./burn.sh lvgl-official-based-test` +- `./burn.sh lvgl-subserver-touch-test` - `./flash_shine_subserver_ui.sh` - автоматически находит USB-порт и заливает `shine_subserver_ui` diff --git a/ESP32/esp32/ESP32-S3-Touch-AMOLED-2.16/test-device/burn.sh b/ESP32/esp32/ESP32-S3-Touch-AMOLED-2.16/test-device/burn.sh index 75c329b..bba895b 100755 --- a/ESP32/esp32/ESP32-S3-Touch-AMOLED-2.16/test-device/burn.sh +++ b/ESP32/esp32/ESP32-S3-Touch-AMOLED-2.16/test-device/burn.sh @@ -22,9 +22,12 @@ case "${MODE}" in gfx-layout-test) SKETCH_DIR="${ROOT_DIR}/test_sketches/gfx_button_layout_test" ;; lvgl-basic-test) SKETCH_DIR="${ROOT_DIR}/test_sketches/lvgl_basic_test" ;; lvgl-interaction-test) SKETCH_DIR="${ROOT_DIR}/test_sketches/lvgl_interaction_test" ;; + lvgl-touch-debug-test) SKETCH_DIR="${ROOT_DIR}/test_sketches/lvgl_touch_debug_test" ;; + lvgl-official-based-test) SKETCH_DIR="${ROOT_DIR}/test_sketches/lvgl_official_based_test" ;; + lvgl-subserver-touch-test) SKETCH_DIR="${ROOT_DIR}/test_sketches/lvgl_subserver_touch_test" ;; *) echo "Unknown mode: ${MODE}" >&2 - echo "Use one of: hello, widgets, audio, simple, argon2, subserver-ui, text-test, gfx-text-test, gfx-layout-test, lvgl-basic-test, lvgl-interaction-test" >&2 + echo "Use one of: hello, widgets, audio, simple, argon2, subserver-ui, text-test, gfx-text-test, gfx-layout-test, lvgl-basic-test, lvgl-interaction-test, lvgl-touch-debug-test, lvgl-official-based-test, lvgl-subserver-touch-test" >&2 exit 2 ;; esac diff --git a/ESP32/esp32/ESP32-S3-Touch-AMOLED-2.16/test-device/test_sketches/README.md b/ESP32/esp32/ESP32-S3-Touch-AMOLED-2.16/test-device/test_sketches/README.md index 6a818f9..06f8e0c 100644 --- a/ESP32/esp32/ESP32-S3-Touch-AMOLED-2.16/test-device/test_sketches/README.md +++ b/ESP32/esp32/ESP32-S3-Touch-AMOLED-2.16/test-device/test_sketches/README.md @@ -10,6 +10,9 @@ - `gfx_button_layout_test/` - проверка геометрии кнопок, особенно нижних рядов и широких кнопок - `lvgl_basic_test/` - минимальный тест `LVGL` с заголовком, текстом и кнопками - `lvgl_interaction_test/` - расширенный тест `LVGL` с 9 кнопками, touch-вводом и статусом нажатия +- `lvgl_touch_debug_test/` - диагностика touch: сырые координаты, точка касания и одна большая кнопка `LVGL` +- `lvgl_official_based_test/` - минимальный наш экран поверх максимально близкой к официальному `05_LVGL_Widgets` инициализации +- `lvgl_subserver_touch_test/` - гибридный тест: `LVGL`-экран с инициализацией дисплея и чтением touch из `shine_subserver_ui`; подтверждён на реальном устройстве ## Запуск @@ -19,3 +22,6 @@ - `./burn.sh gfx-layout-test` - `./burn.sh lvgl-basic-test` - `./burn.sh lvgl-interaction-test` +- `./burn.sh lvgl-touch-debug-test` +- `./burn.sh lvgl-official-based-test` +- `./burn.sh lvgl-subserver-touch-test` diff --git a/ESP32/esp32/ESP32-S3-Touch-AMOLED-2.16/test-device/test_sketches/lvgl_official_based_test/lvgl_official_based_test.ino b/ESP32/esp32/ESP32-S3-Touch-AMOLED-2.16/test-device/test_sketches/lvgl_official_based_test/lvgl_official_based_test.ino new file mode 100644 index 0000000..3d7a3d1 --- /dev/null +++ b/ESP32/esp32/ESP32-S3-Touch-AMOLED-2.16/test-device/test_sketches/lvgl_official_based_test/lvgl_official_based_test.ino @@ -0,0 +1,252 @@ +#include +#include "Arduino_GFX_Library.h" +#include "pin_config.h" +#include "TouchDrvCSTXXX.hpp" +#include "lv_conf.h" +#include "HWCDC.h" +#include + +HWCDC USBSerial; + +#define EXAMPLE_LVGL_TICK_PERIOD_MS 2 + +static lv_disp_draw_buf_t draw_buf; +static lv_color_t *buf1 = nullptr; +static lv_color_t *buf2 = nullptr; +static lv_obj_t *status_label = nullptr; +static uint32_t click_count = 0; + +Arduino_DataBus *bus = new Arduino_ESP32QSPI( + LCD_CS, LCD_SCLK, LCD_SDIO0, LCD_SDIO1, LCD_SDIO2, LCD_SDIO3); + +Arduino_CO5300 *gfx = new Arduino_CO5300( + bus, LCD_RESET, 0, LCD_WIDTH, LCD_HEIGHT, 0, 0, 0, 0); + +TouchDrvCST92xx touch; +int16_t touch_x[5], touch_y[5]; +bool isPressed = false; +uint32_t screenWidth = 0; +uint32_t screenHeight = 0; + +#if LV_USE_LOG != 0 +void my_print(const char *buf) { + USBSerial.printf(buf); + USBSerial.flush(); +} +#endif + +static void example_lvgl_rounder_cb(struct _lv_disp_drv_t *disp_drv, lv_area_t *area) { + LV_UNUSED(disp_drv); + if (area->x1 % 2 != 0) area->x1--; + if (area->y1 % 2 != 0) area->y1--; + if (area->x2 % 2 == 0) area->x2++; + if (area->y2 % 2 == 0) area->y2++; +} + +static void my_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p) { + uint32_t w = (area->x2 - area->x1 + 1); + uint32_t h = (area->y2 - area->y1 + 1); + +#if (LV_COLOR_16_SWAP != 0) + gfx->draw16bitBeRGBBitmap(area->x1, area->y1, (uint16_t *)&color_p->full, w, h); +#else + gfx->draw16bitRGBBitmap(area->x1, area->y1, (uint16_t *)&color_p->full, w, h); +#endif + + lv_disp_flush_ready(disp); +} + +static void example_increase_lvgl_tick(void *arg) { + LV_UNUSED(arg); + lv_tick_inc(EXAMPLE_LVGL_TICK_PERIOD_MS); +} + +static void my_touchpad_read(lv_indev_drv_t *indev_driver, lv_indev_data_t *data) { + LV_UNUSED(indev_driver); + if (isPressed) { + uint8_t touched = touch.getPoint(touch_x, touch_y, touch.getSupportTouchPoint()); + if (touched) { + isPressed = false; + data->state = LV_INDEV_STATE_PR; + data->point.x = touch_x[0]; + data->point.y = touch_y[0]; + USBSerial.print("Touch x="); + USBSerial.print(touch_x[0]); + USBSerial.print(" y="); + USBSerial.println(touch_y[0]); + } else { + data->state = LV_INDEV_STATE_REL; + } + } else { + data->state = LV_INDEV_STATE_REL; + } +} + +static void button_event_cb(lv_event_t *event) { + if (lv_event_get_code(event) != LV_EVENT_CLICKED) { + return; + } + + const char *name = (const char *)lv_event_get_user_data(event); + click_count++; + String text = "Pressed: "; + text += name; + text += " (#"; + text += String(click_count); + text += ")"; + lv_label_set_text(status_label, text.c_str()); + USBSerial.println(text); +} + +static lv_obj_t *make_button(lv_obj_t *parent, const char *label_text, lv_coord_t x, lv_coord_t y, lv_coord_t w, lv_coord_t h, lv_color_t bg) { + lv_obj_t *btn = lv_btn_create(parent); + lv_obj_set_size(btn, w, h); + lv_obj_set_pos(btn, x, y); + lv_obj_set_style_radius(btn, 16, 0); + lv_obj_set_style_bg_color(btn, bg, 0); + lv_obj_set_style_border_width(btn, 2, 0); + lv_obj_set_style_border_color(btn, lv_color_hex(0x8AA4BF), 0); + lv_obj_set_style_shadow_width(btn, 0, 0); + lv_obj_add_event_cb(btn, button_event_cb, LV_EVENT_CLICKED, (void *)label_text); + + lv_obj_t *label = lv_label_create(btn); + lv_label_set_text(label, label_text); + lv_obj_set_style_text_font(label, &lv_font_montserrat_18, 0); + lv_obj_set_style_text_color(label, lv_color_hex(0xFFFFFF), 0); + lv_obj_center(label); + return btn; +} + +static void create_ui() { + lv_obj_t *screen = lv_scr_act(); + lv_obj_set_style_bg_color(screen, lv_color_hex(0x0B1320), 0); + lv_obj_set_style_bg_opa(screen, LV_OPA_COVER, 0); + + lv_obj_t *title = lv_label_create(screen); + lv_label_set_text(title, "LVGL OFFICIAL BASED TEST"); + lv_obj_set_style_text_font(title, &lv_font_montserrat_20, 0); + lv_obj_set_style_text_color(title, lv_color_hex(0xFFFFFF), 0); + lv_obj_align(title, LV_ALIGN_TOP_MID, 0, 14); + + lv_obj_t *hint = lv_label_create(screen); + lv_label_set_text(hint, "Based on official LVGL_Widgets init. Tap buttons and watch the status."); + lv_obj_set_width(hint, 430); + lv_label_set_long_mode(hint, LV_LABEL_LONG_WRAP); + lv_obj_set_style_text_font(hint, &lv_font_montserrat_14, 0); + lv_obj_set_style_text_color(hint, lv_color_hex(0xD4DDE7), 0); + lv_obj_align(hint, LV_ALIGN_TOP_MID, 0, 44); + + make_button(screen, "Status", 22, 120, 136, 60, lv_color_hex(0x355C7D)); + make_button(screen, "Connect", 174, 120, 136, 60, lv_color_hex(0x2A9D8F)); + make_button(screen, "Wallet", 326, 120, 132, 60, lv_color_hex(0x457B9D)); + + make_button(screen, "Requests", 22, 196, 136, 60, lv_color_hex(0xE76F51)); + make_button(screen, "Settings",174, 196, 136, 60, lv_color_hex(0x8D5A97)); + make_button(screen, "Register",326, 196, 132, 60, lv_color_hex(0x6A994E)); + + make_button(screen, "Approve", 22, 272, 136, 60, lv_color_hex(0xBC6C25)); + make_button(screen, "Reject", 174, 272, 136, 60, lv_color_hex(0xB56576)); + make_button(screen, "Back", 326, 272, 132, 60, lv_color_hex(0x6C757D)); + + lv_obj_t *bottom_btn = make_button(screen, "Bottom Action", 22, 350, 436, 64, lv_color_hex(0x1D6F42)); + lv_obj_set_style_text_font(lv_obj_get_child(bottom_btn, 0), &lv_font_montserrat_20, 0); + + lv_obj_t *status_panel = lv_obj_create(screen); + lv_obj_set_size(status_panel, 436, 42); + lv_obj_set_pos(status_panel, 22, 426); + lv_obj_set_style_radius(status_panel, 12, 0); + lv_obj_set_style_bg_color(status_panel, lv_color_hex(0x17263A), 0); + lv_obj_set_style_border_width(status_panel, 2, 0); + lv_obj_set_style_border_color(status_panel, lv_color_hex(0x496582), 0); + lv_obj_set_style_pad_all(status_panel, 6, 0); + + status_label = lv_label_create(status_panel); + lv_label_set_text(status_label, "Pressed: none"); + lv_obj_set_style_text_font(status_label, &lv_font_montserrat_16, 0); + lv_obj_set_style_text_color(status_label, lv_color_hex(0xFFFFFF), 0); + lv_obj_center(status_label); +} + +void setup() { + USBSerial.begin(115200); + + Wire.begin(IIC_SDA, IIC_SCL); + + digitalWrite(TP_RST, LOW); + delay(30); + digitalWrite(TP_RST, HIGH); + delay(50); + delay(1000); + + Wire.begin(IIC_SDA, IIC_SCL); + + touch.setPins(TP_RST, TP_INT); + bool result = touch.begin(Wire, 0x5A, IIC_SDA, IIC_SCL); + if (result == false) { + USBSerial.println("touch is not online..."); + while (1) delay(1000); + } + USBSerial.print("Touch model: "); + USBSerial.println(touch.getModelName()); + touch.sleep(); + touch.reset(); + touch.setMaxCoordinates(480, 480); + touch.setSwapXY(true); + touch.setMirrorXY(true, false); + attachInterrupt( + TP_INT, []() { + isPressed = true; + }, + FALLING); + + gfx->begin(); + gfx->setBrightness(200); + bus->writeC8D8(0x36, 0xA0); + + screenWidth = gfx->width(); + screenHeight = gfx->height(); + + lv_init(); + + buf1 = (lv_color_t *)heap_caps_malloc(screenWidth * screenHeight / 4 * sizeof(lv_color_t), MALLOC_CAP_DMA); + buf2 = (lv_color_t *)heap_caps_malloc(screenWidth * screenHeight / 4 * sizeof(lv_color_t), MALLOC_CAP_DMA); + +#if LV_USE_LOG != 0 + lv_log_register_print_cb(my_print); +#endif + + lv_disp_draw_buf_init(&draw_buf, buf1, buf2, screenWidth * screenHeight / 4); + + static lv_disp_drv_t disp_drv; + lv_disp_drv_init(&disp_drv); + disp_drv.hor_res = screenWidth; + disp_drv.ver_res = screenHeight; + disp_drv.flush_cb = my_disp_flush; + disp_drv.rounder_cb = example_lvgl_rounder_cb; + disp_drv.draw_buf = &draw_buf; + disp_drv.sw_rotate = 1; + lv_disp_drv_register(&disp_drv); + + static lv_indev_drv_t indev_drv; + lv_indev_drv_init(&indev_drv); + indev_drv.type = LV_INDEV_TYPE_POINTER; + indev_drv.read_cb = my_touchpad_read; + lv_indev_drv_register(&indev_drv); + + const esp_timer_create_args_t lvgl_tick_timer_args = { + .callback = &example_increase_lvgl_tick, + .name = "lvgl_tick" + }; + + esp_timer_handle_t lvgl_tick_timer = NULL; + esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer); + esp_timer_start_periodic(lvgl_tick_timer, EXAMPLE_LVGL_TICK_PERIOD_MS * 1000); + + create_ui(); + USBSerial.println("LVGL official based test ready"); +} + +void loop() { + lv_timer_handler(); + delay(5); +} diff --git a/ESP32/esp32/ESP32-S3-Touch-AMOLED-2.16/test-device/test_sketches/lvgl_subserver_touch_test/lvgl_subserver_touch_test.ino b/ESP32/esp32/ESP32-S3-Touch-AMOLED-2.16/test-device/test_sketches/lvgl_subserver_touch_test/lvgl_subserver_touch_test.ino new file mode 100644 index 0000000..d76b1e9 --- /dev/null +++ b/ESP32/esp32/ESP32-S3-Touch-AMOLED-2.16/test-device/test_sketches/lvgl_subserver_touch_test/lvgl_subserver_touch_test.ino @@ -0,0 +1,256 @@ +#include +#include +#include +#include +#include + +// Подтверждено на устройстве: LVGL-рендер работает вместе с touch-путём из shine_subserver_ui. + +#define PIN_LCD_CS 12 +#define PIN_LCD_SCLK 38 +#define PIN_LCD_D0 4 +#define PIN_LCD_D1 5 +#define PIN_LCD_D2 6 +#define PIN_LCD_D3 7 +#define PIN_LCD_RST 2 +#define PIN_I2C_SDA 15 +#define PIN_I2C_SCL 14 +#define PIN_TP_INT 11 + +#define DISP_W 480 +#define DISP_H 480 +#define LVGL_TICK_MS 2 +#define TEST_VERSION "v1-subtouch" + +static lv_disp_draw_buf_t gDrawBuf; +static lv_color_t *gBuf1 = nullptr; +static lv_color_t *gBuf2 = nullptr; +static lv_obj_t *gStatusLabel = nullptr; +static lv_obj_t *gTouchLabel = nullptr; +static lv_obj_t *gVersionLabel = nullptr; +static uint32_t gClickCount = 0; +static bool gTouchActive = false; +static int16_t gLastX = -1; +static int16_t gLastY = -1; + +Arduino_DataBus *gBus = new Arduino_ESP32QSPI( + PIN_LCD_CS, PIN_LCD_SCLK, PIN_LCD_D0, PIN_LCD_D1, PIN_LCD_D2, PIN_LCD_D3); +Arduino_CO5300 *gfx = new Arduino_CO5300( + gBus, PIN_LCD_RST, 0, DISP_W, DISP_H, 0, 0, 0, 0); +TouchDrvCST92xx gTouch; + +static void lvglFlushCb(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *colorP) { + uint32_t w = area->x2 - area->x1 + 1; + uint32_t h = area->y2 - area->y1 + 1; +#if (LV_COLOR_16_SWAP != 0) + gfx->draw16bitBeRGBBitmap(area->x1, area->y1, (uint16_t *)&colorP->full, w, h); +#else + gfx->draw16bitRGBBitmap(area->x1, area->y1, (uint16_t *)&colorP->full, w, h); +#endif + lv_disp_flush_ready(disp); +} + +static void lvglTick(void *arg) { + LV_UNUSED(arg); + lv_tick_inc(LVGL_TICK_MS); +} + +static void updateTouchLabel() { + if (!gTouchLabel) { + return; + } + + char text[96]; + if (gTouchActive) { + snprintf(text, sizeof(text), "Touch: pressed x=%d y=%d", gLastX, gLastY); + } else { + snprintf(text, sizeof(text), "Touch: released x=%d y=%d", gLastX, gLastY); + } + lv_label_set_text(gTouchLabel, text); +} + +static void lvglTouchRead(lv_indev_drv_t *indevDrv, lv_indev_data_t *data) { + LV_UNUSED(indevDrv); + int16_t x = 0; + int16_t y = 0; + bool touching = gTouch.getPoint(&x, &y, 1) > 0; + + if (touching) { + gTouchActive = true; + gLastX = x; + gLastY = y; + data->state = LV_INDEV_STATE_PR; + data->point.x = x; + data->point.y = y; + } else { + gTouchActive = false; + data->state = LV_INDEV_STATE_REL; + data->point.x = gLastX >= 0 ? gLastX : 0; + data->point.y = gLastY >= 0 ? gLastY : 0; + } + + updateTouchLabel(); +} + +static void buttonEventCb(lv_event_t *event) { + if (lv_event_get_code(event) != LV_EVENT_CLICKED) { + return; + } + + const char *name = (const char *)lv_event_get_user_data(event); + gClickCount++; + + char text[96]; + snprintf(text, sizeof(text), "Pressed: %s (#%lu)", name, (unsigned long)gClickCount); + lv_label_set_text(gStatusLabel, text); + Serial.println(text); +} + +static lv_obj_t *makeButton(lv_obj_t *parent, + const char *labelText, + lv_coord_t x, + lv_coord_t y, + lv_coord_t w, + lv_coord_t h, + uint32_t bgColor) { + lv_obj_t *btn = lv_btn_create(parent); + lv_obj_set_size(btn, w, h); + lv_obj_set_pos(btn, x, y); + lv_obj_set_style_radius(btn, 16, 0); + lv_obj_set_style_bg_color(btn, lv_color_hex(bgColor), 0); + lv_obj_set_style_bg_opa(btn, LV_OPA_COVER, 0); + lv_obj_set_style_border_width(btn, 2, 0); + lv_obj_set_style_border_color(btn, lv_color_hex(0x6F8BA4), 0); + lv_obj_set_style_shadow_width(btn, 0, 0); + lv_obj_add_event_cb(btn, buttonEventCb, LV_EVENT_CLICKED, (void *)labelText); + + lv_obj_t *label = lv_label_create(btn); + lv_label_set_text(label, labelText); + lv_obj_set_style_text_color(label, lv_color_hex(0xFFFFFF), 0); + lv_obj_set_style_text_font(label, &lv_font_montserrat_18, 0); + lv_obj_center(label); + return btn; +} + +static void createUi() { + lv_obj_t *screen = lv_scr_act(); + lv_obj_set_style_bg_color(screen, lv_color_hex(0x07111C), 0); + lv_obj_set_style_bg_opa(screen, LV_OPA_COVER, 0); + lv_obj_set_style_pad_all(screen, 0, 0); + lv_obj_set_scrollbar_mode(screen, LV_SCROLLBAR_MODE_OFF); + + gVersionLabel = lv_label_create(screen); + lv_label_set_text(gVersionLabel, "LVGL + subserver touch " TEST_VERSION); + lv_obj_set_style_text_font(gVersionLabel, &lv_font_montserrat_18, 0); + lv_obj_set_style_text_color(gVersionLabel, lv_color_hex(0xFFFFFF), 0); + lv_obj_align(gVersionLabel, LV_ALIGN_TOP_MID, 0, 12); + + lv_obj_t *subtitle = lv_label_create(screen); + lv_label_set_text(subtitle, "Touch path comes from shine_subserver_ui. Tap buttons and watch status."); + lv_obj_set_width(subtitle, 436); + lv_label_set_long_mode(subtitle, LV_LABEL_LONG_WRAP); + lv_obj_set_style_text_font(subtitle, &lv_font_montserrat_14, 0); + lv_obj_set_style_text_color(subtitle, lv_color_hex(0xD6DEE7), 0); + lv_obj_align(subtitle, LV_ALIGN_TOP_MID, 0, 42); + + makeButton(screen, "Status", 22, 110, 136, 62, 0x355C7D); + makeButton(screen, "Connect", 172, 110, 136, 62, 0x2A9D8F); + makeButton(screen, "Wallet", 322, 110, 136, 62, 0x457B9D); + + makeButton(screen, "Requests", 22, 188, 136, 62, 0xE76F51); + makeButton(screen, "Settings", 172, 188, 136, 62, 0x8D5A97); + makeButton(screen, "Register", 322, 188, 136, 62, 0x6A994E); + + makeButton(screen, "Approve", 22, 266, 136, 62, 0xBC6C25); + makeButton(screen, "Reject", 172, 266, 136, 62, 0xB56576); + makeButton(screen, "Back", 322, 266, 136, 62, 0x6C757D); + + makeButton(screen, "Bottom Action", 22, 346, 436, 68, 0x1D6F42); + + lv_obj_t *statusPanel = lv_obj_create(screen); + lv_obj_set_size(statusPanel, 436, 26); + lv_obj_set_pos(statusPanel, 22, 420); + lv_obj_set_style_radius(statusPanel, 10, 0); + lv_obj_set_style_bg_color(statusPanel, lv_color_hex(0x162435), 0); + lv_obj_set_style_bg_opa(statusPanel, LV_OPA_COVER, 0); + lv_obj_set_style_border_width(statusPanel, 1, 0); + lv_obj_set_style_border_color(statusPanel, lv_color_hex(0x4D6986), 0); + lv_obj_set_style_pad_all(statusPanel, 2, 0); + + gStatusLabel = lv_label_create(statusPanel); + lv_label_set_text(gStatusLabel, "Pressed: none"); + lv_obj_set_style_text_font(gStatusLabel, &lv_font_montserrat_14, 0); + lv_obj_set_style_text_color(gStatusLabel, lv_color_hex(0xFFFFFF), 0); + lv_obj_center(gStatusLabel); + + lv_obj_t *touchPanel = lv_obj_create(screen); + lv_obj_set_size(touchPanel, 436, 26); + lv_obj_set_pos(touchPanel, 22, 450); + lv_obj_set_style_radius(touchPanel, 10, 0); + lv_obj_set_style_bg_color(touchPanel, lv_color_hex(0x162435), 0); + lv_obj_set_style_bg_opa(touchPanel, LV_OPA_COVER, 0); + lv_obj_set_style_border_width(touchPanel, 1, 0); + lv_obj_set_style_border_color(touchPanel, lv_color_hex(0x4D6986), 0); + lv_obj_set_style_pad_all(touchPanel, 2, 0); + + gTouchLabel = lv_label_create(touchPanel); + lv_label_set_text(gTouchLabel, "Touch: released x=-1 y=-1"); + lv_obj_set_style_text_font(gTouchLabel, &lv_font_montserrat_14, 0); + lv_obj_set_style_text_color(gTouchLabel, lv_color_hex(0xD6DEE7), 0); + lv_obj_center(gTouchLabel); +} + +void setup() { + Serial.begin(115200); + Wire.begin(PIN_I2C_SDA, PIN_I2C_SCL); + + gfx->begin(); + gBus->writeC8D8(0x36, 0xA0); + gfx->setBrightness(220); + gfx->fillScreen(0x0000); + + gTouch.setPins(PIN_TP_INT, -1); + gTouch.begin(Wire, CST92XX_SLAVE_ADDRESS, PIN_I2C_SDA, PIN_I2C_SCL); + gTouch.setMaxCoordinates(DISP_W, DISP_H); + gTouch.setSwapXY(true); + gTouch.setMirrorXY(true, false); + + lv_init(); + + uint32_t screenWidth = gfx->width(); + uint32_t screenHeight = gfx->height(); + uint32_t bufPixels = screenWidth * 40; + gBuf1 = (lv_color_t *)heap_caps_malloc(bufPixels * sizeof(lv_color_t), MALLOC_CAP_DMA); + gBuf2 = (lv_color_t *)heap_caps_malloc(bufPixels * sizeof(lv_color_t), MALLOC_CAP_DMA); + + lv_disp_draw_buf_init(&gDrawBuf, gBuf1, gBuf2, bufPixels); + + static lv_disp_drv_t dispDrv; + lv_disp_drv_init(&dispDrv); + dispDrv.hor_res = screenWidth; + dispDrv.ver_res = screenHeight; + dispDrv.flush_cb = lvglFlushCb; + dispDrv.draw_buf = &gDrawBuf; + lv_disp_drv_register(&dispDrv); + + static lv_indev_drv_t indevDrv; + lv_indev_drv_init(&indevDrv); + indevDrv.type = LV_INDEV_TYPE_POINTER; + indevDrv.read_cb = lvglTouchRead; + lv_indev_drv_register(&indevDrv); + + const esp_timer_create_args_t tickArgs = { + .callback = &lvglTick, + .name = "lvgl_tick"}; + esp_timer_handle_t tickTimer = nullptr; + esp_timer_create(&tickArgs, &tickTimer); + esp_timer_start_periodic(tickTimer, LVGL_TICK_MS * 1000); + + createUi(); + Serial.println("LVGL + subserver touch test ready: " TEST_VERSION); +} + +void loop() { + lv_timer_handler(); + delay(5); +} diff --git a/ESP32/esp32/ESP32-S3-Touch-AMOLED-2.16/test-device/test_sketches/lvgl_touch_debug_test/lvgl_touch_debug_test.ino b/ESP32/esp32/ESP32-S3-Touch-AMOLED-2.16/test-device/test_sketches/lvgl_touch_debug_test/lvgl_touch_debug_test.ino new file mode 100644 index 0000000..0f0c97c --- /dev/null +++ b/ESP32/esp32/ESP32-S3-Touch-AMOLED-2.16/test-device/test_sketches/lvgl_touch_debug_test/lvgl_touch_debug_test.ino @@ -0,0 +1,218 @@ +#include +#include +#include +#include +#include "pin_config.h" +#include "TouchDrvCSTXXX.hpp" + +#define EXAMPLE_LVGL_TICK_PERIOD_MS 2 + +static lv_disp_draw_buf_t gDrawBuf; +static lv_color_t *gBuf1 = nullptr; +static lv_color_t *gBuf2 = nullptr; +static lv_obj_t *gRawLabel = nullptr; +static lv_obj_t *gEventLabel = nullptr; +static lv_obj_t *gMarker = nullptr; + +static TouchDrvCST92xx gTouch; +static int16_t gTouchX[5]; +static int16_t gTouchY[5]; +static bool gTouchPressed = false; +static uint32_t gRawTouchCount = 0; +static uint32_t gLvglButtonCount = 0; + +Arduino_DataBus *gBus = new Arduino_ESP32QSPI( + LCD_CS, LCD_SCLK, LCD_SDIO0, LCD_SDIO1, LCD_SDIO2, LCD_SDIO3); +Arduino_CO5300 *gfx = new Arduino_CO5300( + gBus, LCD_RESET, 0, LCD_WIDTH, LCD_HEIGHT, 0, 0, 0, 0); + +static void lvglFlushCb(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *colorP) { + uint32_t w = area->x2 - area->x1 + 1; + uint32_t h = area->y2 - area->y1 + 1; +#if (LV_COLOR_16_SWAP != 0) + gfx->draw16bitBeRGBBitmap(area->x1, area->y1, (uint16_t *)&colorP->full, w, h); +#else + gfx->draw16bitRGBBitmap(area->x1, area->y1, (uint16_t *)&colorP->full, w, h); +#endif + lv_disp_flush_ready(disp); +} + +static void lvglTick(void *arg) { + LV_UNUSED(arg); + lv_tick_inc(EXAMPLE_LVGL_TICK_PERIOD_MS); +} + +static void lvglTouchRead(lv_indev_drv_t *indevDrv, lv_indev_data_t *data) { + LV_UNUSED(indevDrv); + uint8_t touched = gTouch.getPoint(gTouchX, gTouchY, gTouch.getSupportTouchPoint()); + if (touched > 0) { + data->state = LV_INDEV_STATE_PR; + data->point.x = gTouchX[0]; + data->point.y = gTouchY[0]; + return; + } + data->state = LV_INDEV_STATE_REL; +} + +static void bigButtonEventCb(lv_event_t *event) { + if (lv_event_get_code(event) != LV_EVENT_CLICKED) { + return; + } + gLvglButtonCount++; + String status = "LVGL button clicked: "; + status += String(gLvglButtonCount); + lv_label_set_text(gEventLabel, status.c_str()); + Serial.println(status); +} + +static void updateRawTouchState() { + uint8_t touched = gTouch.getPoint(gTouchX, gTouchY, gTouch.getSupportTouchPoint()); + if (touched > 0) { + gTouchPressed = true; + gRawTouchCount++; + + String line1 = "RAW pressed"; + String line2 = "x=" + String(gTouchX[0]) + " y=" + String(gTouchY[0]) + " n=" + String(gRawTouchCount); + String text = line1 + "\n" + line2; + lv_label_set_text(gRawLabel, text.c_str()); + + int markerX = gTouchX[0] - 8; + int markerY = gTouchY[0] - 8; + if (markerX < 0) markerX = 0; + if (markerY < 0) markerY = 0; + lv_obj_set_pos(gMarker, markerX, markerY); + lv_obj_clear_flag(gMarker, LV_OBJ_FLAG_HIDDEN); + return; + } + + if (gTouchPressed) { + gTouchPressed = false; + lv_label_set_text(gRawLabel, "RAW released\nTouch ended"); + lv_obj_add_flag(gMarker, LV_OBJ_FLAG_HIDDEN); + } +} + +static void createUi() { + lv_obj_t *screen = lv_scr_act(); + lv_obj_set_style_bg_color(screen, lv_color_hex(0x000000), 0); + lv_obj_set_style_bg_opa(screen, LV_OPA_COVER, 0); + + lv_obj_t *title = lv_label_create(screen); + lv_label_set_text(title, "LVGL TOUCH DEBUG"); + lv_obj_set_style_text_font(title, &lv_font_montserrat_22, 0); + lv_obj_set_style_text_color(title, lv_color_hex(0xFFFFFF), 0); + lv_obj_align(title, LV_ALIGN_TOP_MID, 0, 12); + + gRawLabel = lv_label_create(screen); + lv_label_set_text(gRawLabel, "RAW released\nTouch not seen yet"); + lv_obj_set_style_text_font(gRawLabel, &lv_font_montserrat_18, 0); + lv_obj_set_style_text_color(gRawLabel, lv_color_hex(0x9EE493), 0); + lv_obj_align(gRawLabel, LV_ALIGN_TOP_LEFT, 16, 56); + + gEventLabel = lv_label_create(screen); + lv_label_set_text(gEventLabel, "LVGL button clicked: 0"); + lv_obj_set_style_text_font(gEventLabel, &lv_font_montserrat_18, 0); + lv_obj_set_style_text_color(gEventLabel, lv_color_hex(0xFFD166), 0); + lv_obj_align(gEventLabel, LV_ALIGN_TOP_LEFT, 16, 118); + + lv_obj_t *btn = lv_btn_create(screen); + lv_obj_set_size(btn, 360, 110); + lv_obj_align(btn, LV_ALIGN_CENTER, 0, 36); + lv_obj_set_style_radius(btn, 18, 0); + lv_obj_set_style_bg_color(btn, lv_color_hex(0x2A9D8F), 0); + lv_obj_set_style_border_width(btn, 3, 0); + lv_obj_set_style_border_color(btn, lv_color_hex(0xBDE0FE), 0); + lv_obj_add_event_cb(btn, bigButtonEventCb, LV_EVENT_CLICKED, nullptr); + + lv_obj_t *btnLabel = lv_label_create(btn); + lv_label_set_text(btnLabel, "Tap Here"); + lv_obj_set_style_text_font(btnLabel, &lv_font_montserrat_24, 0); + lv_obj_set_style_text_color(btnLabel, lv_color_hex(0xFFFFFF), 0); + lv_obj_center(btnLabel); + + lv_obj_t *hint = lv_label_create(screen); + lv_label_set_text(hint, "Need both: RAW coords change and LVGL button click."); + lv_obj_set_width(hint, 430); + lv_label_set_long_mode(hint, LV_LABEL_LONG_WRAP); + lv_obj_set_style_text_font(hint, &lv_font_montserrat_16, 0); + lv_obj_set_style_text_color(hint, lv_color_hex(0xD9D9D9), 0); + lv_obj_align(hint, LV_ALIGN_BOTTOM_MID, 0, -34); + + gMarker = lv_obj_create(screen); + lv_obj_set_size(gMarker, 16, 16); + lv_obj_set_style_radius(gMarker, LV_RADIUS_CIRCLE, 0); + lv_obj_set_style_bg_color(gMarker, lv_color_hex(0xFF4D6D), 0); + lv_obj_set_style_border_width(gMarker, 2, 0); + lv_obj_set_style_border_color(gMarker, lv_color_hex(0xFFFFFF), 0); + lv_obj_add_flag(gMarker, LV_OBJ_FLAG_HIDDEN); +} + +void setup() { + Serial.begin(115200); + Wire.begin(IIC_SDA, IIC_SCL); + + pinMode(TP_RST, OUTPUT); + pinMode(TP_INT, INPUT); + digitalWrite(TP_RST, LOW); + delay(30); + digitalWrite(TP_RST, HIGH); + delay(50); + delay(1000); + + gTouch.setPins(TP_RST, TP_INT); + bool touchOk = gTouch.begin(Wire, 0x5A, IIC_SDA, IIC_SCL); + if (!touchOk) { + Serial.println("Touch init failed"); + } else { + Serial.print("Touch model: "); + Serial.println(gTouch.getModelName()); + gTouch.sleep(); + gTouch.reset(); + gTouch.setMaxCoordinates(480, 480); + gTouch.setSwapXY(true); + gTouch.setMirrorXY(true, false); + } + + gfx->begin(); + gBus->writeC8D8(0x36, 0xA0); + gfx->setBrightness(220); + gfx->fillScreen(0x0000); + + lv_init(); + + uint32_t screenWidth = gfx->width(); + uint32_t screenHeight = gfx->height(); + gBuf1 = (lv_color_t *)heap_caps_malloc(screenWidth * screenHeight / 4 * sizeof(lv_color_t), MALLOC_CAP_DMA); + gBuf2 = (lv_color_t *)heap_caps_malloc(screenWidth * screenHeight / 4 * sizeof(lv_color_t), MALLOC_CAP_DMA); + lv_disp_draw_buf_init(&gDrawBuf, gBuf1, gBuf2, screenWidth * screenHeight / 4); + + static lv_disp_drv_t dispDrv; + lv_disp_drv_init(&dispDrv); + dispDrv.hor_res = screenWidth; + dispDrv.ver_res = screenHeight; + dispDrv.flush_cb = lvglFlushCb; + dispDrv.draw_buf = &gDrawBuf; + lv_disp_drv_register(&dispDrv); + + static lv_indev_drv_t indevDrv; + lv_indev_drv_init(&indevDrv); + indevDrv.type = LV_INDEV_TYPE_POINTER; + indevDrv.read_cb = lvglTouchRead; + lv_indev_drv_register(&indevDrv); + + const esp_timer_create_args_t lvglTickTimerArgs = { + .callback = &lvglTick, + .name = "lvgl_tick"}; + esp_timer_handle_t lvglTickTimer = nullptr; + esp_timer_create(&lvglTickTimerArgs, &lvglTickTimer); + esp_timer_start_periodic(lvglTickTimer, EXAMPLE_LVGL_TICK_PERIOD_MS * 1000); + + createUi(); + Serial.println("LVGL touch debug test ready"); +} + +void loop() { + updateRawTouchState(); + lv_timer_handler(); + delay(5); +} diff --git a/VERSION.properties b/VERSION.properties index 9f4353c..1cf22bb 100644 --- a/VERSION.properties +++ b/VERSION.properties @@ -1,2 +1,2 @@ -client.version=1.2.140 -server.version=1.2.132 +client.version=1.2.141 +server.version=1.2.133