From 4509e693dae07279af418d5446039b3789798732 Mon Sep 17 00:00:00 2001 From: Ken Van Hoeylandt Date: Fri, 15 Aug 2025 18:33:06 +0200 Subject: [PATCH] Native touch driver --- .../Source/hal/TpagerKeyboard.cpp | 4 +- .../Source/hal/TpagerKeyboard.h | 4 +- .../LilygoTdeck/Source/hal/TdeckKeyboard.cpp | 6 +- Boards/LilygoTdeck/Source/hal/TdeckKeyboard.h | 12 ++-- Boards/Simulator/Source/hal/SdlKeyboard.h | 10 +-- Drivers/EspLcdCompat/Source/EspLcdDisplay.cpp | 8 +-- Drivers/EspLcdCompat/Source/EspLcdDisplay.h | 2 +- .../EspLcdCompat/Source/EspLcdNativeDisplay.h | 9 ++- .../EspLcdCompat/Source/EspLcdNativeTouch.cpp | 5 ++ .../EspLcdCompat/Source/EspLcdNativeTouch.h | 15 +++++ Drivers/EspLcdCompat/Source/EspLcdTouch.cpp | 63 ++++++++++++++----- Drivers/EspLcdCompat/Source/EspLcdTouch.h | 15 +++-- Drivers/GT911/Source/Gt911Touch.h | 3 +- .../Tactility/hal/keyboard/KeyboardDevice.h | 4 +- .../Include/Tactility/hal/touch/NativeTouch.h | 24 +++++++ .../Include/Tactility/hal/touch/TouchDevice.h | 9 ++- Tactility/Source/lvgl/Lvgl.cpp | 53 +++++++++------- 17 files changed, 170 insertions(+), 76 deletions(-) create mode 100644 Drivers/EspLcdCompat/Source/EspLcdNativeTouch.cpp create mode 100644 Drivers/EspLcdCompat/Source/EspLcdNativeTouch.h create mode 100644 Tactility/Include/Tactility/hal/touch/NativeTouch.h diff --git a/Boards/LilygoTLoraPager/Source/hal/TpagerKeyboard.cpp b/Boards/LilygoTLoraPager/Source/hal/TpagerKeyboard.cpp index 93b31d4f..092073de 100644 --- a/Boards/LilygoTLoraPager/Source/hal/TpagerKeyboard.cpp +++ b/Boards/LilygoTLoraPager/Source/hal/TpagerKeyboard.cpp @@ -161,7 +161,7 @@ void TpagerKeyboard::processKeyboard() { } } -bool TpagerKeyboard::start(lv_display_t* display) { +bool TpagerKeyboard::startLvgl(lv_display_t* display) { backlightOkay = initBacklight(BACKLIGHT, 30000, LEDC_TIMER_0, LEDC_CHANNEL_1); initEncoder(); keypad->init(KB_ROWS, KB_COLS); @@ -195,7 +195,7 @@ bool TpagerKeyboard::start(lv_display_t* display) { return true; } -bool TpagerKeyboard::stop() { +bool TpagerKeyboard::stopLvgl() { assert(inputTimer); inputTimer->stop(); inputTimer = nullptr; diff --git a/Boards/LilygoTLoraPager/Source/hal/TpagerKeyboard.h b/Boards/LilygoTLoraPager/Source/hal/TpagerKeyboard.h index 1aba8c08..6922ba61 100644 --- a/Boards/LilygoTLoraPager/Source/hal/TpagerKeyboard.h +++ b/Boards/LilygoTLoraPager/Source/hal/TpagerKeyboard.h @@ -41,8 +41,8 @@ public: std::string getName() const final { return "T-Lora Pager Keyboard"; } std::string getDescription() const final { return "I2C keyboard with encoder"; } - bool start(lv_display_t* display) override; - bool stop() override; + bool startLvgl(lv_display_t* display) override; + bool stopLvgl() override; bool isAttached() const override; lv_indev_t* _Nullable getLvglIndev() override { return kbHandle; } diff --git a/Boards/LilygoTdeck/Source/hal/TdeckKeyboard.cpp b/Boards/LilygoTdeck/Source/hal/TdeckKeyboard.cpp index 47c8590d..0c357d82 100644 --- a/Boards/LilygoTdeck/Source/hal/TdeckKeyboard.cpp +++ b/Boards/LilygoTdeck/Source/hal/TdeckKeyboard.cpp @@ -7,7 +7,7 @@ #define TDECK_KEYBOARD_I2C_BUS_HANDLE I2C_NUM_0 #define TDECK_KEYBOARD_SLAVE_ADDRESS 0x55 -static inline bool keyboard_i2c_read(uint8_t* output) { +static bool keyboard_i2c_read(uint8_t* output) { return tt::hal::i2c::masterRead(TDECK_KEYBOARD_I2C_BUS_HANDLE, TDECK_KEYBOARD_SLAVE_ADDRESS, output, 1, 100 / portTICK_PERIOD_MS); } @@ -43,7 +43,7 @@ static void keyboard_read_callback(TT_UNUSED lv_indev_t* indev, lv_indev_data_t* last_buffer = read_buffer; } -bool TdeckKeyboard::start(lv_display_t* display) { +bool TdeckKeyboard::startLvgl(lv_display_t* display) { deviceHandle = lv_indev_create(); lv_indev_set_type(deviceHandle, LV_INDEV_TYPE_KEYPAD); lv_indev_set_read_cb(deviceHandle, &keyboard_read_callback); @@ -52,7 +52,7 @@ bool TdeckKeyboard::start(lv_display_t* display) { return true; } -bool TdeckKeyboard::stop() { +bool TdeckKeyboard::stopLvgl() { lv_indev_delete(deviceHandle); deviceHandle = nullptr; return true; diff --git a/Boards/LilygoTdeck/Source/hal/TdeckKeyboard.h b/Boards/LilygoTdeck/Source/hal/TdeckKeyboard.h index 26eea592..e526d2dc 100644 --- a/Boards/LilygoTdeck/Source/hal/TdeckKeyboard.h +++ b/Boards/LilygoTdeck/Source/hal/TdeckKeyboard.h @@ -5,19 +5,17 @@ #include #include -class TdeckKeyboard : public tt::hal::keyboard::KeyboardDevice { - -private: +class TdeckKeyboard final : public tt::hal::keyboard::KeyboardDevice { lv_indev_t* _Nullable deviceHandle = nullptr; public: - std::string getName() const final { return "T-Deck Keyboard"; } - std::string getDescription() const final { return "I2C keyboard"; } + std::string getName() const override { return "T-Deck Keyboard"; } + std::string getDescription() const override { return "I2C keyboard"; } - bool start(lv_display_t* display) override; - bool stop() override; + bool startLvgl(lv_display_t* display) override; + bool stopLvgl() override; bool isAttached() const override; lv_indev_t* _Nullable getLvglIndev() override { return deviceHandle; } }; diff --git a/Boards/Simulator/Source/hal/SdlKeyboard.h b/Boards/Simulator/Source/hal/SdlKeyboard.h index f9730286..9bf3dc50 100644 --- a/Boards/Simulator/Source/hal/SdlKeyboard.h +++ b/Boards/Simulator/Source/hal/SdlKeyboard.h @@ -4,20 +4,20 @@ #include class SdlKeyboard final : public tt::hal::keyboard::KeyboardDevice { -private: + lv_indev_t* _Nullable handle = nullptr; public: - std::string getName() const final { return "SDL Keyboard"; } - std::string getDescription() const final { return "SDL keyboard device"; } + std::string getName() const override { return "SDL Keyboard"; } + std::string getDescription() const override { return "SDL keyboard device"; } - bool start(lv_display_t* display) override { + bool startLvgl(lv_display_t* display) override { handle = lv_sdl_keyboard_create(); return handle != nullptr; } - bool stop() override { tt_crash("Not supported"); } + bool stopLvgl() override { tt_crash("Not supported"); } bool isAttached() const override { return true; } diff --git a/Drivers/EspLcdCompat/Source/EspLcdDisplay.cpp b/Drivers/EspLcdCompat/Source/EspLcdDisplay.cpp index 3f9689f1..52600c17 100644 --- a/Drivers/EspLcdCompat/Source/EspLcdDisplay.cpp +++ b/Drivers/EspLcdCompat/Source/EspLcdDisplay.cpp @@ -63,7 +63,7 @@ bool EspLcdDisplay::startLvgl() { auto touch_device = getTouchDevice(); if (touch_device != nullptr) { - touch_device->start(lvglDisplay); + touch_device->startLvgl(lvglDisplay); } return lvglDisplay != nullptr; @@ -76,7 +76,7 @@ bool EspLcdDisplay::stopLvgl() { auto touch_device = getTouchDevice(); if (touch_device != nullptr) { - touch_device->stop(); + touch_device->stopLvgl(); } lvgl_port_remove_disp(lvglDisplay); @@ -84,10 +84,10 @@ bool EspLcdDisplay::stopLvgl() { return true; } -std::shared_ptr EspLcdDisplay::getNativeDisplay() { +std::shared_ptr EspLcdDisplay::getNativeDisplay() { assert(lvglDisplay == nullptr); // Still attached to LVGL context. Call stopLvgl() first. if (nativeDisplay == nullptr) { - nativeDisplay = std::make_shared( + nativeDisplay = std::make_shared( panelHandle, lvglPortDisplayConfig ); diff --git a/Drivers/EspLcdCompat/Source/EspLcdDisplay.h b/Drivers/EspLcdCompat/Source/EspLcdDisplay.h index 693bcc03..8ef2d55c 100644 --- a/Drivers/EspLcdCompat/Source/EspLcdDisplay.h +++ b/Drivers/EspLcdCompat/Source/EspLcdDisplay.h @@ -47,7 +47,7 @@ public: // region NativedDisplay - /** @return a NativeDisplay if this device supports it */ + /** @return a NativeDisplay instance if this device supports it */ std::shared_ptr _Nullable getNativeDisplay() final; // endregion diff --git a/Drivers/EspLcdCompat/Source/EspLcdNativeDisplay.h b/Drivers/EspLcdCompat/Source/EspLcdNativeDisplay.h index 2954c996..97790398 100644 --- a/Drivers/EspLcdCompat/Source/EspLcdNativeDisplay.h +++ b/Drivers/EspLcdCompat/Source/EspLcdNativeDisplay.h @@ -4,9 +4,9 @@ #include #include -namespace tt::hal::display { +using namespace tt::hal; -class EspLcdNativeDisplay final : public NativeDisplay { +class EspLcdNativeDisplay final : public display::NativeDisplay { esp_lcd_panel_handle_t panelHandle; const lvgl_port_display_cfg_t& lvglPortDisplayConfig; @@ -17,7 +17,8 @@ public: const lvgl_port_display_cfg_t& lvglPortDisplayConfig ) : panelHandle(panelHandle), lvglPortDisplayConfig(lvglPortDisplayConfig) {} - ColorFormat getColorFormat() const override { + display::ColorFormat getColorFormat() const override { + using display::ColorFormat; switch (lvglPortDisplayConfig.color_format) { case LV_COLOR_FORMAT_I1: return ColorFormat::Monochrome; @@ -39,5 +40,3 @@ public: uint16_t getPixelWidth() const override { return lvglPortDisplayConfig.hres; } uint16_t getPixelHeight() const override { return lvglPortDisplayConfig.vres; } }; - -} diff --git a/Drivers/EspLcdCompat/Source/EspLcdNativeTouch.cpp b/Drivers/EspLcdCompat/Source/EspLcdNativeTouch.cpp new file mode 100644 index 00000000..d0d52be6 --- /dev/null +++ b/Drivers/EspLcdCompat/Source/EspLcdNativeTouch.cpp @@ -0,0 +1,5 @@ +#include "EspLcdNativeTouch.h" + +bool EspLcdNativeTouch::getTouchedPoints(uint16_t* x, uint16_t* y, uint16_t* strength, uint8_t* pointCount, uint8_t maxPointCount) { + return esp_lcd_touch_get_coordinates(handle, x, y, strength, pointCount, maxPointCount) == ESP_OK; +} diff --git a/Drivers/EspLcdCompat/Source/EspLcdNativeTouch.h b/Drivers/EspLcdCompat/Source/EspLcdNativeTouch.h new file mode 100644 index 00000000..d2ccac34 --- /dev/null +++ b/Drivers/EspLcdCompat/Source/EspLcdNativeTouch.h @@ -0,0 +1,15 @@ +#pragma once + +#include +#include + +class EspLcdNativeTouch final : public tt::hal::touch::NativeTouch { + + esp_lcd_touch_handle_t handle; + +public: + + EspLcdNativeTouch(esp_lcd_touch_handle_t handle) : handle(handle) {} + + bool getTouchedPoints(uint16_t* x, uint16_t* y, uint16_t* strength, uint8_t* pointCount, uint8_t maxPointCount) override; +}; diff --git a/Drivers/EspLcdCompat/Source/EspLcdTouch.cpp b/Drivers/EspLcdCompat/Source/EspLcdTouch.cpp index c1eda766..8f1db3a6 100644 --- a/Drivers/EspLcdCompat/Source/EspLcdTouch.cpp +++ b/Drivers/EspLcdCompat/Source/EspLcdTouch.cpp @@ -1,11 +1,12 @@ #include "EspLcdTouch.h" +#include #include #include constexpr char* TAG = "EspLcdTouch"; -bool EspLcdTouch::start(lv_display_t* display) { +bool EspLcdTouch::start() { if (!createIoHandle(ioHandle) != ESP_OK) { TT_LOG_E(TAG, "Touch IO failed"); return false; @@ -15,10 +16,41 @@ bool EspLcdTouch::start(lv_display_t* display) { if (!createTouchHandle(ioHandle, config, touchHandle)) { TT_LOG_E(TAG, "Driver init failed"); - cleanup(); + esp_lcd_panel_io_del(ioHandle); + ioHandle = nullptr; return false; } + return true; +} + +bool EspLcdTouch::stop() { + if (lvglDevice != nullptr) { + stopLvgl(); + } + + if (ioHandle != nullptr) { + esp_lcd_panel_io_del(ioHandle); + ioHandle = nullptr; + } + + if (touchHandle != nullptr) { + esp_lcd_touch_del(touchHandle); + touchHandle = nullptr; + } + + return true; +} + +bool EspLcdTouch::startLvgl(lv_disp_t* display) { + if (lvglDevice != nullptr) { + return false; + } + + if (nativeTouch != nullptr && nativeTouch.use_count() > 1) { + TT_LOG_W(TAG, "NativeTouch is still in use."); + } + const lvgl_port_touch_cfg_t touch_cfg = { .disp = display, .handle = touchHandle, @@ -28,28 +60,27 @@ bool EspLcdTouch::start(lv_display_t* display) { lvglDevice = lvgl_port_add_touch(&touch_cfg); if (lvglDevice == nullptr) { TT_LOG_E(TAG, "Adding touch failed"); - cleanup(); return false; } return true; } -bool EspLcdTouch::stop() { - cleanup(); +bool EspLcdTouch::stopLvgl() { + if (lvglDevice == nullptr) { + return false; + } + + lvgl_port_remove_touch(lvglDevice); + lvglDevice = nullptr; + return true; } -void EspLcdTouch::cleanup() { - if (lvglDevice != nullptr) { - lv_indev_delete(lvglDevice); - lvglDevice = nullptr; - // TODO: is this correct? We don't have to delete it manually? - touchHandle = nullptr; - } - - if (ioHandle != nullptr) { - esp_lcd_panel_io_del(ioHandle); - ioHandle = nullptr; +std::shared_ptr _Nullable EspLcdTouch::getNativeTouch() { + assert(lvglDevice == nullptr); // Still attached to LVGL context. Call stopLvgl() first. + if (nativeTouch == nullptr) { + nativeTouch = std::make_shared(touchHandle); } + return nativeTouch; } diff --git a/Drivers/EspLcdCompat/Source/EspLcdTouch.h b/Drivers/EspLcdCompat/Source/EspLcdTouch.h index c8f80756..5f4c6a19 100644 --- a/Drivers/EspLcdCompat/Source/EspLcdTouch.h +++ b/Drivers/EspLcdCompat/Source/EspLcdTouch.h @@ -11,8 +11,7 @@ class EspLcdTouch : public tt::hal::touch::TouchDevice { esp_lcd_panel_io_handle_t _Nullable ioHandle = nullptr; esp_lcd_touch_handle_t _Nullable touchHandle = nullptr; lv_indev_t* _Nullable lvglDevice = nullptr; - - void cleanup(); + std::shared_ptr nativeTouch; protected: @@ -24,11 +23,17 @@ protected: public: + bool start() final; - bool start(lv_display_t* display) override; + bool stop() final; - bool stop() override; + bool supportsLvgl() const final { return true; } + bool startLvgl(lv_display_t* display) final; - lv_indev_t* _Nullable getLvglIndev() override { return lvglDevice; } + bool stopLvgl() final; + + lv_indev_t* _Nullable getLvglIndev() final { return lvglDevice; } + + std::shared_ptr _Nullable getNativeTouch() final; }; diff --git a/Drivers/GT911/Source/Gt911Touch.h b/Drivers/GT911/Source/Gt911Touch.h index 65c34597..df9a0806 100644 --- a/Drivers/GT911/Source/Gt911Touch.h +++ b/Drivers/GT911/Source/Gt911Touch.h @@ -67,5 +67,6 @@ public: } std::string getName() const override { return "GT911"; } - std::string getDescription() const override { return "I2C Touch Driver"; } + + std::string getDescription() const override { return "GT911 I2C touch driver"; } }; diff --git a/Tactility/Include/Tactility/hal/keyboard/KeyboardDevice.h b/Tactility/Include/Tactility/hal/keyboard/KeyboardDevice.h index 1aa618c8..599288f3 100644 --- a/Tactility/Include/Tactility/hal/keyboard/KeyboardDevice.h +++ b/Tactility/Include/Tactility/hal/keyboard/KeyboardDevice.h @@ -14,8 +14,8 @@ public: Type getType() const override { return Type::Keyboard; } - virtual bool start(lv_display_t* display) = 0; - virtual bool stop() = 0; + virtual bool startLvgl(lv_display_t* display) = 0; + virtual bool stopLvgl() = 0; virtual bool isAttached() const = 0; virtual lv_indev_t* _Nullable getLvglIndev() = 0; diff --git a/Tactility/Include/Tactility/hal/touch/NativeTouch.h b/Tactility/Include/Tactility/hal/touch/NativeTouch.h new file mode 100644 index 00000000..63bfa1f4 --- /dev/null +++ b/Tactility/Include/Tactility/hal/touch/NativeTouch.h @@ -0,0 +1,24 @@ +#pragma once + +namespace tt::hal::touch { + +class NativeTouch { + +public: + + /** + * Get the coordinates for the currently touched points on the screen. + * + * @param[in] x array of X coordinates + * @param[in] y array of Y coordinates + * @param[in] strength Array of strengths + * @param[in] pointCount the number of points currently touched on the screen + * @param[in] maxPointCount the maximum number of points that can be touched at once + * + * @return + * - Returns true, when touched and coordinates readed. Otherwise returns false. + */ + virtual bool getTouchedPoints(uint16_t* x, uint16_t* y, uint16_t* strength, uint8_t* pointCount, uint8_t maxPointCount) = 0; +}; + +} diff --git a/Tactility/Include/Tactility/hal/touch/TouchDevice.h b/Tactility/Include/Tactility/hal/touch/TouchDevice.h index a6da2fa8..74aefb09 100644 --- a/Tactility/Include/Tactility/hal/touch/TouchDevice.h +++ b/Tactility/Include/Tactility/hal/touch/TouchDevice.h @@ -1,6 +1,7 @@ #pragma once #include "../Device.h" +#include "NativeTouch.h" #include @@ -14,10 +15,16 @@ public: Type getType() const override { return Type::Touch; } - virtual bool start(lv_display_t* display) = 0; + virtual bool start() = 0; virtual bool stop() = 0; + virtual bool supportsLvgl() const { return false; } + virtual bool startLvgl(lv_display_t* display) = 0; + virtual bool stopLvgl() = 0; + virtual lv_indev_t* _Nullable getLvglIndev() = 0; + + virtual std::shared_ptr _Nullable getNativeTouch() = 0; }; } diff --git a/Tactility/Source/lvgl/Lvgl.cpp b/Tactility/Source/lvgl/Lvgl.cpp index 885d3528..06deab3b 100644 --- a/Tactility/Source/lvgl/Lvgl.cpp +++ b/Tactility/Source/lvgl/Lvgl.cpp @@ -40,26 +40,6 @@ static std::shared_ptr createDisplay(const hal::Con return display; } -static bool startKeyboard(const std::shared_ptr& display, const std::shared_ptr& keyboard) { - TT_LOG_I(TAG, "Keyboard init"); - assert(display); - assert(keyboard); - if (keyboard->isAttached()) { - if (keyboard->start(display->getLvglDisplay())) { - lv_indev_t* keyboard_indev = keyboard->getLvglIndev(); - hardware_keyboard_set_indev(keyboard_indev); - TT_LOG_I(TAG, "Keyboard started"); - return true; - } else { - TT_LOG_E(TAG, "Keyboard start failed"); - return false; - } - } else { - TT_LOG_E(TAG, "Keyboard attach failed"); - return false; - } -} - void init(const hal::Configuration& config) { TT_LOG_I(TAG, "Init started"); @@ -77,6 +57,7 @@ void init(const hal::Configuration& config) { auto touch = display->getTouchDevice(); if (touch != nullptr) { + touch->start(); hal::registerDevice(touch); } @@ -119,6 +100,19 @@ void start() { } } + // Start touch + + auto touch_devices = hal::findDevices(hal::Device::Type::Touch); + for (auto touch_device : touch_devices) { + if (displays.size() > 0) { + // TODO: Consider implementing support for multiple displays + auto display = displays[0]; + if (touch_device->supportsLvgl()) { + touch_device->startLvgl(display->getLvglDisplay()); + } + } + } + // Start keyboards auto keyboards = hal::findDevices(hal::Device::Type::Keyboard); @@ -126,7 +120,15 @@ void start() { if (displays.size() > 0) { // TODO: Consider implementing support for multiple displays auto display = displays[0]; - startKeyboard(display, keyboard); + if (keyboard->isAttached()) { + if (keyboard->startLvgl(display->getLvglDisplay())) { + lv_indev_t* keyboard_indev = keyboard->getLvglIndev(); + hardware_keyboard_set_indev(keyboard_indev); + TT_LOG_I(TAG, "Keyboard started"); + } else { + TT_LOG_E(TAG, "Keyboard start failed"); + } + } } } @@ -168,7 +170,14 @@ void stop() { auto keyboards = hal::findDevices(hal::Device::Type::Keyboard); for (auto keyboard : keyboards) { - keyboard->stop(); + keyboard->stopLvgl(); + } + + // Stop touch + + auto touch_devices = hal::findDevices(hal::Device::Type::Touch); + for (auto touch_device : touch_devices) { + touch_device->stopLvgl(); } // Stop displays (and their touch devices)