From 33bb742dfbf279f2ea97caa6d7902fb04921a47e Mon Sep 17 00:00:00 2001 From: Ken Van Hoeylandt Date: Mon, 2 Dec 2024 00:32:39 +0100 Subject: [PATCH] Hal refactored (#99) --- .github/workflows/esp.yml | 15 -- App/CMakeLists.txt | 2 - App/Kconfig | 2 - App/Source/Boards.h | 22 +- App/Source/Main.cpp | 2 +- Boards/LilygoTdeck/CMakeLists.txt | 4 +- .../LilygoTdeck/{ => Source}/InitHardware.cpp | 31 +-- .../LilygoTdeck.cpp} | 15 +- .../{lilygo_tdeck.h => Source/LilygoTdeck.h} | 2 +- Boards/LilygoTdeck/Source/Lvgl.cpp | 33 +++ .../{InitPower.cpp => Source/PowerOn.cpp} | 17 +- .../{sdcard.cpp => Source/Sdcard.cpp} | 35 ++- .../hal/TdeckDisplay.cpp} | 130 +++++++---- Boards/LilygoTdeck/Source/hal/TdeckDisplay.h | 42 ++++ .../Source/hal/TdeckDisplayConstants.h | 20 ++ .../hal/TdeckKeyboard.cpp} | 58 ++--- Boards/LilygoTdeck/Source/hal/TdeckKeyboard.h | 18 ++ Boards/LilygoTdeck/Source/hal/TdeckTouch.cpp | 97 +++++++++ Boards/LilygoTdeck/Source/hal/TdeckTouch.h | 17 ++ Boards/LilygoTdeck/config.h | 64 ------ Boards/LilygoTdeck/display.h | 9 - Boards/LilygoTdeck/keyboard.h | 10 - Boards/LilygoTdeck/lvgl.cpp | 67 ------ Boards/LilygoTdeck/touch.cpp | 58 ----- Boards/M5stackCore2/Source/M5stackCore2.cpp | 3 +- Boards/M5stackCoreS3/Source/M5stackCoreS3.cpp | 5 +- Boards/M5stackShared/CMakeLists.txt | 2 +- Boards/M5stackShared/Source/Lvgl.cpp | 19 +- Boards/M5stackShared/Source/LvglTouch.cpp | 29 --- Boards/M5stackShared/Source/M5stackShared.h | 2 + .../M5stackDisplay.cpp} | 34 ++- .../M5stackShared/Source/hal/M5stackDisplay.h | 33 +++ .../M5stackShared/Source/hal/M5stackTouch.cpp | 48 ++++ .../M5stackShared/Source/hal/M5stackTouch.h | 13 ++ .../Source/{lvgl_task.cpp => LvglTask.cpp} | 19 +- .../Source/{lvgl_task.h => LvglTask.h} | 0 .../Source/{freertos.cpp => Main.cpp} | 23 +- Boards/Simulator/Source/Main.h | 3 + Boards/Simulator/Source/Simulator.cpp | 12 - Boards/Simulator/Source/Simulator.h | 22 +- .../Configuration.cpp} | 17 +- Boards/Simulator/Source/hal/Power.cpp | 31 +++ Boards/Simulator/Source/hal/SdlDisplay.h | 32 +++ Boards/Simulator/Source/hal/SdlKeyboard.h | 26 +++ Boards/Simulator/Source/hal/SdlTouch.h | 21 ++ Boards/Simulator/Source/lvgl_hal.cpp | 15 -- Boards/Simulator/Source/lvgl_hal.h | 5 - Boards/Simulator/Source/power.cpp | 31 --- Boards/WaveshareS3Touch/CMakeLists.txt | 5 - Boards/WaveshareS3Touch/bootstrap.cpp | 39 ---- Boards/WaveshareS3Touch/bootstrap_i.h | 3 - Boards/WaveshareS3Touch/config.h | 38 ---- Boards/WaveshareS3Touch/display.cpp | 206 ------------------ Boards/WaveshareS3Touch/display_i.h | 10 - Boards/WaveshareS3Touch/lvgl.cpp | 18 -- Boards/WaveshareS3Touch/lvgl_i.h | 3 - Boards/WaveshareS3Touch/touch.cpp | 72 ------ Boards/WaveshareS3Touch/touch_i.h | 5 - .../WaveshareS3Touch/waveshare_s3_touch.cpp | 51 ----- Boards/WaveshareS3Touch/waveshare_s3_touch.h | 6 - Boards/YellowBoard/CMakeLists.txt | 4 +- .../{bootstrap.cpp => Source/Boot.cpp} | 13 +- .../YellowBoard/{config.h => Source/Config.h} | 15 +- Boards/YellowBoard/Source/Lvgl.cpp | 26 +++ .../{sdcard.cpp => Source/Sdcard.cpp} | 2 +- .../YellowBoard.cpp} | 12 +- .../{yellow_board.h => Source/YellowBoard.h} | 0 .../hal/YellowDisplay.cpp} | 115 +++++++--- Boards/YellowBoard/Source/hal/YellowDisplay.h | 37 ++++ .../Source/hal/YellowDisplayConstants.h | 21 ++ .../{touch.cpp => Source/hal/YellowTouch.cpp} | 39 +++- Boards/YellowBoard/Source/hal/YellowTouch.h | 13 ++ .../Source/hal/YellowTouchConstants.h | 5 + Boards/YellowBoard/display_i.h | 6 - Boards/YellowBoard/lvgl.cpp | 56 ----- CMakeLists.txt | 12 +- Documentation/ideas.md | 6 +- .../src/lvgl9/esp_lvgl_port_button.c | 6 +- .../src/lvgl9/esp_lvgl_port_disp.c | 6 +- .../src/lvgl9/esp_lvgl_port_knob.c | 6 +- .../src/lvgl9/esp_lvgl_port_touch.c | 6 +- .../src/lvgl9/esp_lvgl_port_usbhid.c | 10 +- README.md | 16 +- Tactility/Private/lvgl/Init_i.h | 2 +- Tactility/Source/Tactility.cpp | 21 +- Tactility/Source/Tactility.h | 2 +- Tactility/Source/app/boot/Boot.cpp | 14 +- Tactility/Source/app/display/Display.cpp | 20 +- Tactility/Source/app/files/FileUtils.cpp | 1 + Tactility/Source/lvgl/Init.cpp | 93 +++++++- Tactility/Source/lvgl/Lvgl.cpp | 14 ++ Tactility/Source/lvgl/Lvgl.h | 7 + Tactility/Source/lvgl/LvglSync.cpp | 19 +- Tactility/Source/lvgl/LvglSync.h | 1 + .../Source/service/screenshot/Screenshot.cpp | 2 +- TactilityCore/Source/Log.cpp | 5 - TactilityHeadless/Source/hal/Configuration.h | 32 +-- TactilityHeadless/Source/hal/Display.h | 29 +++ TactilityHeadless/Source/hal/Hal.cpp | 9 +- TactilityHeadless/Source/hal/Keyboard.h | 18 ++ TactilityHeadless/Source/hal/Touch.h | 18 ++ sdkconfig.board.waveshare_s3_touch | 35 --- sdkconfig.developer | 5 +- 103 files changed, 1222 insertions(+), 1228 deletions(-) rename Boards/LilygoTdeck/{ => Source}/InitHardware.cpp (52%) rename Boards/LilygoTdeck/{lilygo_tdeck.cpp => Source/LilygoTdeck.cpp} (85%) rename Boards/LilygoTdeck/{lilygo_tdeck.h => Source/LilygoTdeck.h} (67%) create mode 100644 Boards/LilygoTdeck/Source/Lvgl.cpp rename Boards/LilygoTdeck/{InitPower.cpp => Source/PowerOn.cpp} (53%) rename Boards/LilygoTdeck/{sdcard.cpp => Source/Sdcard.cpp} (84%) rename Boards/LilygoTdeck/{display.cpp => Source/hal/TdeckDisplay.cpp} (53%) create mode 100644 Boards/LilygoTdeck/Source/hal/TdeckDisplay.h create mode 100644 Boards/LilygoTdeck/Source/hal/TdeckDisplayConstants.h rename Boards/LilygoTdeck/{keyboard.cpp => Source/hal/TdeckKeyboard.cpp} (55%) create mode 100644 Boards/LilygoTdeck/Source/hal/TdeckKeyboard.h create mode 100644 Boards/LilygoTdeck/Source/hal/TdeckTouch.cpp create mode 100644 Boards/LilygoTdeck/Source/hal/TdeckTouch.h delete mode 100644 Boards/LilygoTdeck/config.h delete mode 100644 Boards/LilygoTdeck/display.h delete mode 100644 Boards/LilygoTdeck/keyboard.h delete mode 100644 Boards/LilygoTdeck/lvgl.cpp delete mode 100644 Boards/LilygoTdeck/touch.cpp delete mode 100644 Boards/M5stackShared/Source/LvglTouch.cpp rename Boards/M5stackShared/Source/{LvglDisplay.cpp => hal/M5stackDisplay.cpp} (70%) create mode 100644 Boards/M5stackShared/Source/hal/M5stackDisplay.h create mode 100644 Boards/M5stackShared/Source/hal/M5stackTouch.cpp create mode 100644 Boards/M5stackShared/Source/hal/M5stackTouch.h rename Boards/Simulator/Source/{lvgl_task.cpp => LvglTask.cpp} (83%) rename Boards/Simulator/Source/{lvgl_task.h => LvglTask.h} (100%) rename Boards/Simulator/Source/{freertos.cpp => Main.cpp} (74%) create mode 100644 Boards/Simulator/Source/Main.h delete mode 100644 Boards/Simulator/Source/Simulator.cpp rename Boards/Simulator/Source/{hardware_config.cpp => hal/Configuration.cpp} (84%) create mode 100644 Boards/Simulator/Source/hal/Power.cpp create mode 100644 Boards/Simulator/Source/hal/SdlDisplay.h create mode 100644 Boards/Simulator/Source/hal/SdlKeyboard.h create mode 100644 Boards/Simulator/Source/hal/SdlTouch.h delete mode 100644 Boards/Simulator/Source/lvgl_hal.cpp delete mode 100644 Boards/Simulator/Source/lvgl_hal.h delete mode 100644 Boards/Simulator/Source/power.cpp delete mode 100644 Boards/WaveshareS3Touch/CMakeLists.txt delete mode 100644 Boards/WaveshareS3Touch/bootstrap.cpp delete mode 100644 Boards/WaveshareS3Touch/bootstrap_i.h delete mode 100644 Boards/WaveshareS3Touch/config.h delete mode 100644 Boards/WaveshareS3Touch/display.cpp delete mode 100644 Boards/WaveshareS3Touch/display_i.h delete mode 100644 Boards/WaveshareS3Touch/lvgl.cpp delete mode 100644 Boards/WaveshareS3Touch/lvgl_i.h delete mode 100644 Boards/WaveshareS3Touch/touch.cpp delete mode 100644 Boards/WaveshareS3Touch/touch_i.h delete mode 100644 Boards/WaveshareS3Touch/waveshare_s3_touch.cpp delete mode 100644 Boards/WaveshareS3Touch/waveshare_s3_touch.h rename Boards/YellowBoard/{bootstrap.cpp => Source/Boot.cpp} (87%) rename Boards/YellowBoard/{config.h => Source/Config.h} (58%) create mode 100644 Boards/YellowBoard/Source/Lvgl.cpp rename Boards/YellowBoard/{sdcard.cpp => Source/Sdcard.cpp} (99%) rename Boards/YellowBoard/{yellow_board.cpp => Source/YellowBoard.cpp} (88%) rename Boards/YellowBoard/{yellow_board.h => Source/YellowBoard.h} (100%) rename Boards/YellowBoard/{display.cpp => Source/hal/YellowDisplay.cpp} (52%) create mode 100644 Boards/YellowBoard/Source/hal/YellowDisplay.h create mode 100644 Boards/YellowBoard/Source/hal/YellowDisplayConstants.h rename Boards/YellowBoard/{touch.cpp => Source/hal/YellowTouch.cpp} (55%) create mode 100644 Boards/YellowBoard/Source/hal/YellowTouch.h create mode 100644 Boards/YellowBoard/Source/hal/YellowTouchConstants.h delete mode 100644 Boards/YellowBoard/display_i.h delete mode 100644 Boards/YellowBoard/lvgl.cpp create mode 100644 Tactility/Source/lvgl/Lvgl.cpp create mode 100644 Tactility/Source/lvgl/Lvgl.h create mode 100644 TactilityHeadless/Source/hal/Display.h create mode 100644 TactilityHeadless/Source/hal/Keyboard.h create mode 100644 TactilityHeadless/Source/hal/Touch.h delete mode 100644 sdkconfig.board.waveshare_s3_touch diff --git a/.github/workflows/esp.yml b/.github/workflows/esp.yml index caf6c96c..9962d65d 100644 --- a/.github/workflows/esp.yml +++ b/.github/workflows/esp.yml @@ -31,21 +31,6 @@ jobs: esp_idf_version: v5.3.1 target: esp32s3 path: './' - build-waveshare-s3-touch: - runs-on: ubuntu-latest - steps: - - name: checkout repo - uses: actions/checkout@v2 - with: - submodules: recursive - - name: board select - run: cp sdkconfig.board.waveshare_s3_touch sdkconfig - - name: build - uses: espressif/esp-idf-ci-action@main - with: - esp_idf_version: v5.3.1 - target: esp32s3 - path: './' build-m5stack-core2: runs-on: ubuntu-latest steps: diff --git a/App/CMakeLists.txt b/App/CMakeLists.txt index 7a032b65..650859b3 100644 --- a/App/CMakeLists.txt +++ b/App/CMakeLists.txt @@ -10,12 +10,10 @@ if (DEFINED ENV{ESP_IDF_VERSION}) ) endif() - # T-Deck is an S3 platform if("${IDF_TARGET}" STREQUAL "esp32s3") list(APPEND BOARD_COMPONENTS LilygoTdeck M5stackCoreS3 - WaveshareS3Touch ) endif() diff --git a/App/Kconfig b/App/Kconfig index c486418d..fef9ec43 100644 --- a/App/Kconfig +++ b/App/Kconfig @@ -14,8 +14,6 @@ menu "Tactility App" bool "M5Stack Core2" config TT_BOARD_M5STACK_CORES3 bool "M5Stack CoreS3" - config TT_BOARD_WAVESHARE_S3_TOUCH - bool "Waveshare S3 Touch LCD 4.3\"" help Select a board/hardware configuration. Use TT_BOARD_CUSTOM if you will manually configure the board in your project. diff --git a/App/Source/Boards.h b/App/Source/Boards.h index 2040505b..49f3b331 100644 --- a/App/Source/Boards.h +++ b/App/Source/Boards.h @@ -5,10 +5,10 @@ // Supported hardware: #if defined(CONFIG_TT_BOARD_LILYGO_TDECK) -#include "lilygo_tdeck.h" +#include "LilygoTdeck.h" #define TT_BOARD_HARDWARE &lilygo_tdeck #elif defined(CONFIG_TT_BOARD_YELLOW_BOARD_24_CAP) -#include "yellow_board.h" +#include "YellowBoard.h" #define TT_BOARD_HARDWARE &yellow_board_24inch_cap #elif defined(CONFIG_TT_BOARD_M5STACK_CORE2) #include "M5stackCore2.h" @@ -16,9 +16,6 @@ #elif defined(CONFIG_TT_BOARD_M5STACK_CORES3) #include "M5stackCoreS3.h" #define TT_BOARD_HARDWARE &m5stack_cores3 -#elif defined(CONFIG_TT_BOARD_WAVESHARE_S3_TOUCH) -#include "waveshare_s3_touch.h" -#define TT_BOARD_HARDWARE &waveshare_s3_touch #else #define TT_BOARD_HARDWARE NULL #error Replace TT_BOARD_HARDWARE in main.c with your own. Or copy one of the ./sdkconfig.board.* files into ./sdkconfig. @@ -28,18 +25,7 @@ #include "Simulator.h" -#define TT_BOARD_HARDWARE &sim_hardware - -extern "C" { -void app_main(); -} - -int main_stub(); // Main function logic from Simulator board project - -// Actual main that passes on app_main (to be executed in a FreeRTOS task) and bootstraps FreeRTOS -int main() { - setMainForSim(app_main); - return main_stub(); -} +extern tt::hal::Configuration hardware; +#define TT_BOARD_HARDWARE &hardware #endif // ESP_PLATFORM \ No newline at end of file diff --git a/App/Source/Main.cpp b/App/Source/Main.cpp index 3a69f482..014bf2a5 100644 --- a/App/Source/Main.cpp +++ b/App/Source/Main.cpp @@ -25,7 +25,7 @@ void app_main() { .auto_start_app_id = nullptr }; - tt::init(&config); + tt::init(config); tt::service::wifi::wifi_main(nullptr); } diff --git a/Boards/LilygoTdeck/CMakeLists.txt b/Boards/LilygoTdeck/CMakeLists.txt index 6269fd9b..087beb3a 100644 --- a/Boards/LilygoTdeck/CMakeLists.txt +++ b/Boards/LilygoTdeck/CMakeLists.txt @@ -1,5 +1,5 @@ idf_component_register( - SRC_DIRS "." - INCLUDE_DIRS "." + SRC_DIRS "Source" "Source/hal" + INCLUDE_DIRS "Source" REQUIRES Tactility esp_lvgl_port esp_lcd esp_lcd_touch_gt911 driver vfs fatfs ) diff --git a/Boards/LilygoTdeck/InitHardware.cpp b/Boards/LilygoTdeck/Source/InitHardware.cpp similarity index 52% rename from Boards/LilygoTdeck/InitHardware.cpp rename to Boards/LilygoTdeck/Source/InitHardware.cpp index e87a7784..76be2798 100644 --- a/Boards/LilygoTdeck/InitHardware.cpp +++ b/Boards/LilygoTdeck/Source/InitHardware.cpp @@ -1,11 +1,25 @@ #include "TactilityCore.h" -#include "config.h" -#include "display.h" -#include "keyboard.h" +#include "hal/TdeckDisplayConstants.h" #include +#include +#include #define TAG "tdeck" +// SPI +#define TDECK_SPI_HOST SPI2_HOST +#define TDECK_SPI_PIN_SCLK GPIO_NUM_40 +#define TDECK_SPI_PIN_MOSI GPIO_NUM_41 +#define TDECK_SPI_PIN_MISO GPIO_NUM_38 +#define TDECK_SPI_TRANSFER_SIZE_LIMIT (TDECK_LCD_HORIZONTAL_RESOLUTION * TDECK_LCD_SPI_TRANSFER_HEIGHT * (TDECK_LCD_BITS_PER_PIXEL / 8)) + +#define TDECK_LCD_BACKLIGHT_LEDC_TIMER LEDC_TIMER_0 +#define TDECK_LCD_BACKLIGHT_LEDC_MODE LEDC_LOW_SPEED_MODE +#define TDECK_LCD_BACKLIGHT_LEDC_CHANNEL LEDC_CHANNEL_0 +#define TDECK_LCD_BACKLIGHT_LEDC_DUTY_RES LEDC_TIMER_8_BIT +#define TDECK_LCD_BACKLIGHT_LEDC_FREQUENCY (4000) + + static bool init_spi() { spi_bus_config_t bus_config = { .mosi_io_num = TDECK_SPI_PIN_MOSI, @@ -21,20 +35,11 @@ static bool init_spi() { bool tdeck_init_hardware() { TT_LOG_I(TAG, "Init SPI"); + if (!init_spi()) { TT_LOG_E(TAG, "Init SPI failed"); return false; } - // Don't turn the backlight on yet - Tactility init will take care of it - TT_LOG_I(TAG, "Init backlight"); - if (!tdeck_backlight_init()) { - TT_LOG_E(TAG, "Init backlight failed"); - return false; - } - - // We wait for the keyboard peripheral to be booted up - keyboard_wait_for_response(); - return true; } \ No newline at end of file diff --git a/Boards/LilygoTdeck/lilygo_tdeck.cpp b/Boards/LilygoTdeck/Source/LilygoTdeck.cpp similarity index 85% rename from Boards/LilygoTdeck/lilygo_tdeck.cpp rename to Boards/LilygoTdeck/Source/LilygoTdeck.cpp index 04b734cb..3a2a710f 100644 --- a/Boards/LilygoTdeck/lilygo_tdeck.cpp +++ b/Boards/LilygoTdeck/Source/LilygoTdeck.cpp @@ -1,5 +1,7 @@ -#include "lilygo_tdeck.h" -#include "display.h" +#include "hal/Configuration.h" +#include "hal/TdeckDisplay.h" +#include "hal/TdeckKeyboard.h" +#include "hal/sdcard/Sdcard.h" bool tdeck_init_power(); bool tdeck_init_hardware(); @@ -8,12 +10,11 @@ bool tdeck_init_lvgl(); extern const tt::hal::sdcard::SdCard tdeck_sdcard; extern const tt::hal::Configuration lilygo_tdeck = { - .initPower = tdeck_init_power, + .initBoot = tdeck_init_power, .initHardware = tdeck_init_hardware, - .initLvgl = &tdeck_init_lvgl, - .display = { - .setBacklightDuty = &tdeck_backlight_set - }, + .initLvgl = tdeck_init_lvgl, + .createDisplay = createDisplay, + .createKeyboard = createKeyboard, .sdcard = &tdeck_sdcard, .power = nullptr, .i2c = { diff --git a/Boards/LilygoTdeck/lilygo_tdeck.h b/Boards/LilygoTdeck/Source/LilygoTdeck.h similarity index 67% rename from Boards/LilygoTdeck/lilygo_tdeck.h rename to Boards/LilygoTdeck/Source/LilygoTdeck.h index 1c9a111b..0039120f 100644 --- a/Boards/LilygoTdeck/lilygo_tdeck.h +++ b/Boards/LilygoTdeck/Source/LilygoTdeck.h @@ -1,5 +1,5 @@ #pragma once -#include "hal/Configuration.h" +#include extern const tt::hal::Configuration lilygo_tdeck; diff --git a/Boards/LilygoTdeck/Source/Lvgl.cpp b/Boards/LilygoTdeck/Source/Lvgl.cpp new file mode 100644 index 00000000..cef35f25 --- /dev/null +++ b/Boards/LilygoTdeck/Source/Lvgl.cpp @@ -0,0 +1,33 @@ +#include "Log.h" +#include "Thread.h" +#include "lvgl/LvglSync.h" +#include "esp_lvgl_port.h" +#include "hal/TdeckDisplay.h" + +#define TAG "tdeck_lvgl" + +// LVGL +// The minimum task stack seems to be about 3500, but that crashes the wifi app in some scenarios +// At 4000, it crashes when the fps renderer is available +#define TDECK_LVGL_TASK_STACK_DEPTH 8192 + +bool tdeck_init_lvgl() { + static lv_disp_t* display = nullptr; + const lvgl_port_cfg_t lvgl_cfg = { + .task_priority = tt::THREAD_PRIORITY_RENDER, + .task_stack = TDECK_LVGL_TASK_STACK_DEPTH, + .task_affinity = -1, // core pinning + .task_max_sleep_ms = 500, + .timer_period_ms = 5 + }; + + TT_LOG_D(TAG, "LVGL port init"); + if (lvgl_port_init(&lvgl_cfg) != ESP_OK) { + TT_LOG_E(TAG, "LVGL port init failed"); + return false; + } + + tt::lvgl::syncSet(&lvgl_port_lock, &lvgl_port_unlock); + + return true; +} diff --git a/Boards/LilygoTdeck/InitPower.cpp b/Boards/LilygoTdeck/Source/PowerOn.cpp similarity index 53% rename from Boards/LilygoTdeck/InitPower.cpp rename to Boards/LilygoTdeck/Source/PowerOn.cpp index ee5bbd65..990cd230 100644 --- a/Boards/LilygoTdeck/InitPower.cpp +++ b/Boards/LilygoTdeck/Source/PowerOn.cpp @@ -1,8 +1,11 @@ -#include "config.h" +#include #include "TactilityCore.h" #define TAG "tdeck" +// Power on +#define TDECK_POWERON_GPIO GPIO_NUM_10 + static bool tdeck_power_on() { gpio_config_t device_power_signal_config = { .pin_bit_mask = BIT64(TDECK_POWERON_GPIO), @@ -30,17 +33,5 @@ bool tdeck_init_power() { return false; } - /** - * Without this delay, the touch driver randomly fails when the device is USB-powered: - * > lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed - * > GT911: touch_gt911_read_cfg(352): GT911 read error! - * This might not be a problem with a lipo, but I haven't been able to test that. - * I tried to solve it just like I did with the keyboard: - * By reading from I2C until it succeeds and to then init the driver. - * It doesn't work, because it never recovers from the error. - */ - TT_LOG_I(TAG, "Waiting after power-on"); - tt::delay_ms(TDECK_POWERON_DELAY); - return true; } diff --git a/Boards/LilygoTdeck/sdcard.cpp b/Boards/LilygoTdeck/Source/Sdcard.cpp similarity index 84% rename from Boards/LilygoTdeck/sdcard.cpp rename to Boards/LilygoTdeck/Source/Sdcard.cpp index 45578baa..b0f975fa 100644 --- a/Boards/LilygoTdeck/sdcard.cpp +++ b/Boards/LilygoTdeck/Source/Sdcard.cpp @@ -1,7 +1,6 @@ #include "hal/sdcard/Sdcard.h" #include "Check.h" #include "Log.h" -#include "config.h" #include "esp_vfs_fat.h" #include "sdmmc_cmd.h" @@ -9,6 +8,18 @@ #define TAG "tdeck_sdcard" +#define TDECK_SDCARD_SPI_HOST SPI2_HOST +#define TDECK_SDCARD_PIN_CS GPIO_NUM_39 +#define TDECK_SDCARD_SPI_FREQUENCY 800000U +#define TDECK_SDCARD_FORMAT_ON_MOUNT_FAILED false +#define TDECK_SDCARD_MAX_OPEN_FILES 4 +#define TDECK_SDCARD_ALLOC_UNIT_SIZE (16 * 1024) +#define TDECK_SDCARD_STATUS_CHECK_ENABLED false + +// Other +#define TDECK_LCD_PIN_CS GPIO_NUM_12 +#define TDECK_RADIO_PIN_CS GPIO_NUM_9 + typedef struct { const char* mount_point; sdmmc_card_t* card; @@ -85,7 +96,7 @@ static void* _Nullable sdcard_mount(const char* mount_point) { } else { TT_LOG_E(TAG, "Mounting failed (%s)", esp_err_to_name(ret)); } - return NULL; + return nullptr; } auto* data = static_cast(malloc(sizeof(MountData))); @@ -100,7 +111,7 @@ static void* _Nullable sdcard_mount(const char* mount_point) { static void* sdcard_init_and_mount(const char* mount_point) { if (!sdcard_init()) { TT_LOG_E(TAG, "Failed to set SPI CS pins high. This is a pre-requisite for mounting."); - return NULL; + return nullptr; } auto* data = static_cast(sdcard_mount(mount_point)); if (data == nullptr) { @@ -125,6 +136,7 @@ static void sdcard_unmount(void* context) { free(data); } +// TODO: Refactor to "bool getStatus(Status* status)" method so that it can fail when the lvgl lock fails static bool sdcard_is_mounted(void* context) { auto* data = static_cast(context); /** @@ -132,13 +144,18 @@ static bool sdcard_is_mounted(void* context) { * Writing and reading to the bus from 2 devices at the same time causes crashes. * This work-around ensures that this check is only happening when LVGL isn't rendering. */ - if (tt::lvgl::lock(100)) { - bool result = (data != nullptr) && (sdmmc_get_status(data->card) == ESP_OK); - tt::lvgl::unlock(); - return result; - } else { - return false; + bool locked = tt::lvgl::lock(100); // TODO: Refactor to a more reliable locking mechanism + if (!locked) { + TT_LOG_W(TAG, "Failed to get LVGL lock"); } + + bool result = (data != nullptr) && (sdmmc_get_status(data->card) == ESP_OK); + + if (locked) { + tt::lvgl::unlock(); + } + + return result; } extern const tt::hal::sdcard::SdCard tdeck_sdcard = { diff --git a/Boards/LilygoTdeck/display.cpp b/Boards/LilygoTdeck/Source/hal/TdeckDisplay.cpp similarity index 53% rename from Boards/LilygoTdeck/display.cpp rename to Boards/LilygoTdeck/Source/hal/TdeckDisplay.cpp index 8141ac05..246b62f9 100644 --- a/Boards/LilygoTdeck/display.cpp +++ b/Boards/LilygoTdeck/Source/hal/TdeckDisplay.cpp @@ -1,15 +1,23 @@ -#include "config.h" +#include "TdeckDisplay.h" +#include "TdeckDisplayConstants.h" +#include "TdeckTouch.h" +#include "Log.h" + +#include + #include "driver/ledc.h" #include "driver/spi_master.h" #include "esp_err.h" #include "esp_lcd_panel_ops.h" #include "esp_lcd_panel_vendor.h" #include "esp_lvgl_port.h" -#include "Log.h" #define TAG "tdeck_display" -bool tdeck_backlight_init() { +static bool isBacklightInitialized = false; + +static bool initBacklight() { + TT_LOG_I(TAG, "Init backlight"); ledc_timer_config_t ledc_timer = { .speed_mode = TDECK_LCD_BACKLIGHT_LEDC_MODE, .duty_resolution = TDECK_LCD_BACKLIGHT_LEDC_DUTY_RES, @@ -27,7 +35,7 @@ bool tdeck_backlight_init() { return true; } -void tdeck_backlight_set(uint8_t duty) { +static bool setBacklight(uint8_t duty) { ledc_channel_config_t ledc_channel = { .gpio_num = TDECK_LCD_PIN_BACKLIGHT, .speed_mode = TDECK_LCD_BACKLIGHT_LEDC_MODE, @@ -43,12 +51,12 @@ void tdeck_backlight_set(uint8_t duty) { // Setting the config in the timer init and then calling ledc_set_duty() doesn't work when // the app is running. For an unknown reason we have to call this config method every time: - if (ledc_channel_config(&ledc_channel) != ESP_OK) { - TT_LOG_E(TAG, "Failed to configure display backlight"); - } + return ledc_channel_config(&ledc_channel) == ESP_OK; } -lv_display_t* tdeck_display_init() { +bool TdeckDisplay::start() { + TT_LOG_I(TAG, "Starting"); + const esp_lcd_panel_io_spi_config_t panel_io_config = { .cs_gpio_num = TDECK_LCD_PIN_CS, .dc_gpio_num = TDECK_LCD_PIN_DC, @@ -71,10 +79,9 @@ lv_display_t* tdeck_display_init() { } }; - esp_lcd_panel_io_handle_t io_handle; - if (esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)TDECK_LCD_SPI_HOST, &panel_io_config, &io_handle) != ESP_OK) { - TT_LOG_E(TAG, "failed to create panel IO"); - return nullptr; + if (esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)TDECK_LCD_SPI_HOST, &panel_io_config, &ioHandle) != ESP_OK) { + TT_LOG_E(TAG, "Failed to create panel IO"); + return false; } const esp_lcd_panel_dev_config_t panel_config = { @@ -88,45 +95,44 @@ lv_display_t* tdeck_display_init() { .vendor_config = nullptr }; - esp_lcd_panel_handle_t panel_handle; - if (esp_lcd_new_panel_st7789(io_handle, &panel_config, &panel_handle) != ESP_OK) { - TT_LOG_E(TAG, "failed to create panel"); - return nullptr; + if (esp_lcd_new_panel_st7789(ioHandle, &panel_config, &panelHandle) != ESP_OK) { + TT_LOG_E(TAG, "Failed to create panel"); + return false; } - if (esp_lcd_panel_reset(panel_handle) != ESP_OK) { - TT_LOG_E(TAG, "failed to reset panel"); - return nullptr; + if (esp_lcd_panel_reset(panelHandle) != ESP_OK) { + TT_LOG_E(TAG, "Failed to reset panel"); + return false; } - if (esp_lcd_panel_init(panel_handle) != ESP_OK) { - TT_LOG_E(TAG, "failed to init panel"); - return nullptr; + if (esp_lcd_panel_init(panelHandle) != ESP_OK) { + TT_LOG_E(TAG, "Failed to init panel"); + return false; } - if (esp_lcd_panel_invert_color(panel_handle, true) != ESP_OK) { - TT_LOG_E(TAG, "failed to init panel"); - return nullptr; + if (esp_lcd_panel_invert_color(panelHandle, true) != ESP_OK) { + TT_LOG_E(TAG, "Failed to init panel"); + return false; } - if (esp_lcd_panel_swap_xy(panel_handle, true) != ESP_OK) { - TT_LOG_E(TAG, "failed to init panel"); - return nullptr; + if (esp_lcd_panel_swap_xy(panelHandle, true) != ESP_OK) { + TT_LOG_E(TAG, "Failed to init panel"); + return false; } - if (esp_lcd_panel_mirror(panel_handle, true, false) != ESP_OK) { - TT_LOG_E(TAG, "failed to init panel"); - return nullptr; + if (esp_lcd_panel_mirror(panelHandle, true, false) != ESP_OK) { + TT_LOG_E(TAG, "Failed to init panel"); + return false; } - if (esp_lcd_panel_disp_on_off(panel_handle, true) != ESP_OK) { - TT_LOG_E(TAG, "failed to turn display on"); - return nullptr; + if (esp_lcd_panel_disp_on_off(panelHandle, true) != ESP_OK) { + TT_LOG_E(TAG, "Failed to turn display on"); + return false; } const lvgl_port_display_cfg_t disp_cfg = { - .io_handle = io_handle, - .panel_handle = panel_handle, + .io_handle = ioHandle, + .panel_handle = panelHandle, .buffer_size = TDECK_LCD_HORIZONTAL_RESOLUTION * TDECK_LCD_DRAW_BUFFER_HEIGHT * (TDECK_LCD_BITS_PER_PIXEL / 8), .double_buffer = true, // Disable to free up SPIRAM .trans_size = 0, @@ -146,5 +152,55 @@ lv_display_t* tdeck_display_init() { }, }; - return lvgl_port_add_disp(&disp_cfg); + displayHandle = lvgl_port_add_disp(&disp_cfg); + TT_LOG_I(TAG, "Finished"); + return displayHandle != nullptr; +} + +bool TdeckDisplay::stop() { + tt_assert(displayHandle != nullptr); + + lvgl_port_remove_disp(displayHandle); + + if (esp_lcd_panel_del(panelHandle) != ESP_OK) { + return false; + } + + if (esp_lcd_panel_io_del(ioHandle) != ESP_OK) { + return false; + } + + displayHandle = nullptr; + return true; + +} + +void TdeckDisplay::setPowerOn(bool turnOn) { + if (esp_lcd_panel_disp_on_off(panelHandle, turnOn) != ESP_OK) { + TT_LOG_E(TAG, "Failed to turn display on/off"); + } else { + poweredOn = turnOn; + } +} + +tt::hal::Touch* _Nullable TdeckDisplay::createTouch() { + return static_cast(new TdeckTouch()); +} + +void TdeckDisplay::setBacklightDuty(uint8_t backlightDuty) { + if (!isBacklightInitialized) { + tt_check(initBacklight()); + isBacklightInitialized = true; + } + + if (setBacklight(backlightDuty)) { + TT_LOG_I(TAG, "Backlight set: %d", backlightDuty); + lastBacklightDuty = backlightDuty; + } else { + TT_LOG_E(TAG, "Failed to configure display backlight"); + } +} + +tt::hal::Display* createDisplay() { + return static_cast(new TdeckDisplay()); } diff --git a/Boards/LilygoTdeck/Source/hal/TdeckDisplay.h b/Boards/LilygoTdeck/Source/hal/TdeckDisplay.h new file mode 100644 index 00000000..feb71a50 --- /dev/null +++ b/Boards/LilygoTdeck/Source/hal/TdeckDisplay.h @@ -0,0 +1,42 @@ +#pragma once + +#include +#include "lvgl.h" +#include "hal/Display.h" + +extern lv_disp_t* displayHandle; + +class TdeckDisplay : public tt::hal::Display { + +private: + + esp_lcd_panel_io_handle_t ioHandle = nullptr; + esp_lcd_panel_handle_t panelHandle = nullptr; + lv_display_t* displayHandle = nullptr; + uint8_t lastBacklightDuty = 255; + bool poweredOn = false; + +public: + + bool start() override; + + bool stop() override; + + void setPowerOn(bool turnOn) override; + bool isPoweredOn() const override { return poweredOn; }; + bool supportsPowerControl() const override { return true; } + + tt::hal::Touch* _Nullable createTouch() override; + + void setBacklightDuty(uint8_t backlightDuty) override; + uint8_t getBacklightDuty() const override { return lastBacklightDuty; } + bool supportsBacklightDuty() const override { return true; } + + lv_display_t* _Nullable getLvglDisplay() const override { return displayHandle; } + +private: + + static bool startBacklight(); +}; + +tt::hal::Display* createDisplay(); diff --git a/Boards/LilygoTdeck/Source/hal/TdeckDisplayConstants.h b/Boards/LilygoTdeck/Source/hal/TdeckDisplayConstants.h new file mode 100644 index 00000000..80644dff --- /dev/null +++ b/Boards/LilygoTdeck/Source/hal/TdeckDisplayConstants.h @@ -0,0 +1,20 @@ +#pragma once + +#define TDECK_LCD_SPI_HOST SPI2_HOST +#define TDECK_LCD_PIN_CS GPIO_NUM_12 +#define TDECK_LCD_PIN_DC GPIO_NUM_11 // RS +#define TDECK_LCD_PIN_BACKLIGHT GPIO_NUM_42 +#define TDECK_LCD_SPI_FREQUENCY 40000000 +#define TDECK_LCD_HORIZONTAL_RESOLUTION 320 +#define TDECK_LCD_VERTICAL_RESOLUTION 240 +#define TDECK_LCD_BITS_PER_PIXEL 16 +#define TDECK_LCD_DRAW_BUFFER_HEIGHT (TDECK_LCD_VERTICAL_RESOLUTION / 10) +#define TDECK_LCD_SPI_TRANSFER_HEIGHT (TDECK_LCD_VERTICAL_RESOLUTION / 10) + +// Backlight (PWM) +#define TDECK_LCD_BACKLIGHT_LEDC_TIMER LEDC_TIMER_0 +#define TDECK_LCD_BACKLIGHT_LEDC_MODE LEDC_LOW_SPEED_MODE +#define TDECK_LCD_BACKLIGHT_LEDC_CHANNEL LEDC_CHANNEL_0 +#define TDECK_LCD_BACKLIGHT_LEDC_DUTY_RES LEDC_TIMER_8_BIT +#define TDECK_LCD_BACKLIGHT_LEDC_FREQUENCY (4000) + diff --git a/Boards/LilygoTdeck/keyboard.cpp b/Boards/LilygoTdeck/Source/hal/TdeckKeyboard.cpp similarity index 55% rename from Boards/LilygoTdeck/keyboard.cpp rename to Boards/LilygoTdeck/Source/hal/TdeckKeyboard.cpp index 45688980..b1fe6ea3 100644 --- a/Boards/LilygoTdeck/keyboard.cpp +++ b/Boards/LilygoTdeck/Source/hal/TdeckKeyboard.cpp @@ -1,34 +1,16 @@ -#include "keyboard.h" -#include "config.h" -#include "lvgl.h" -#include "TactilityCore.h" -#include "lvgl/LvglKeypad.h" +#include "TdeckKeyboard.h" #include "hal/i2c/I2c.h" #include #define TAG "tdeck_keyboard" -typedef struct { - lv_indev_t* device; -} KeyboardData; +#define TDECK_KEYBOARD_I2C_BUS_HANDLE I2C_NUM_0 +#define TDECK_KEYBOARD_SLAVE_ADDRESS 0x55 static inline 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); } -void keyboard_wait_for_response() { - TT_LOG_I(TAG, "Waiting for keyboard response..."); - bool awake = false; - uint8_t read_buffer = 0x00; - do { - awake = keyboard_i2c_read(&read_buffer); - if (!awake) { - tt::delay_ms(100); - } - } while (!awake); - TT_LOG_I(TAG, "Keyboard responded"); -} - /** * The callback simulates press and release events, because the T-Deck * keyboard only publishes press events on I2C. @@ -61,21 +43,25 @@ static void keyboard_read_callback(TT_UNUSED lv_indev_t* indev, lv_indev_data_t* last_buffer = read_buffer; } -Keyboard keyboard_alloc(_Nullable lv_disp_t* display) { - auto* data = static_cast(malloc(sizeof(KeyboardData))); - - data->device = lv_indev_create(); - lv_indev_set_type(data->device, LV_INDEV_TYPE_KEYPAD); - lv_indev_set_read_cb(data->device, &keyboard_read_callback); - lv_indev_set_display(data->device, display); - - tt::lvgl::keypad_set_indev(data->device); - - return data; +bool TdeckKeyboard::start(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); + lv_indev_set_display(deviceHandle, display); + lv_indev_set_user_data(deviceHandle, this); + return true; } -void keyboard_free(Keyboard keyboard) { - auto* data = static_cast(keyboard); - lv_indev_delete(data->device); - free(data); +bool TdeckKeyboard::stop() { + lv_indev_delete(deviceHandle); + deviceHandle = nullptr; + return true; +} + +bool TdeckKeyboard::isAttached() const { + return tt::hal::i2c::masterCheckAddressForDevice(TDECK_KEYBOARD_I2C_BUS_HANDLE, TDECK_KEYBOARD_SLAVE_ADDRESS, 100); +} + +tt::hal::Keyboard* createKeyboard() { + return dynamic_cast(new TdeckKeyboard()); } diff --git a/Boards/LilygoTdeck/Source/hal/TdeckKeyboard.h b/Boards/LilygoTdeck/Source/hal/TdeckKeyboard.h new file mode 100644 index 00000000..33a65717 --- /dev/null +++ b/Boards/LilygoTdeck/Source/hal/TdeckKeyboard.h @@ -0,0 +1,18 @@ +#pragma once + +#include "hal/Keyboard.h" +#include +#include "esp_lcd_panel_io_interface.h" +#include "esp_lcd_touch.h" + +class TdeckKeyboard : public tt::hal::Keyboard { +private: + lv_indev_t* _Nullable deviceHandle = nullptr; +public: + bool start(lv_display_t* display) override; + bool stop() override; + bool isAttached() const override; + lv_indev_t* _Nullable getLvglIndev() override { return deviceHandle; } +}; + +tt::hal::Keyboard* createKeyboard(); diff --git a/Boards/LilygoTdeck/Source/hal/TdeckTouch.cpp b/Boards/LilygoTdeck/Source/hal/TdeckTouch.cpp new file mode 100644 index 00000000..22906f73 --- /dev/null +++ b/Boards/LilygoTdeck/Source/hal/TdeckTouch.cpp @@ -0,0 +1,97 @@ +#include "TdeckTouch.h" + +#include "esp_err.h" +#include "esp_lcd_touch_gt911.h" +#include "Log.h" +#include "Kernel.h" +#include "esp_lvgl_port.h" + +#define TAG "tdeck_touch" + +// Touch (GT911) +#define TDECK_TOUCH_I2C_BUS_HANDLE I2C_NUM_0 +#define TDECK_TOUCH_X_MAX 240 +#define TDECK_TOUCH_Y_MAX 320 +#define TDECK_TOUCH_PIN_INT GPIO_NUM_16 + +bool TdeckTouch::start(lv_display_t* display) { + const esp_lcd_panel_io_i2c_config_t io_config = ESP_LCD_TOUCH_IO_I2C_GT911_CONFIG(); + + // TODO: Revert on new ESP-IDF version + static_assert(ESP_IDF_VERSION == ESP_IDF_VERSION_VAL(5, 3, 1)); + esp_lcd_new_panel_io_i2c( + (esp_lcd_i2c_bus_handle_t)TDECK_TOUCH_I2C_BUS_HANDLE, + &io_config, + &ioHandle + ); + /* + if ( + esp_lcd_new_panel_io_i2c( + (esp_lcd_i2c_bus_handle_t)TDECK_TOUCH_I2C_BUS_HANDLE, + &touch_io_config, + &ioHandle + ) != ESP_OK + ) { + TT_LOG_E(TAG, "touch io i2c creation failed"); + return false; + } + */ + + esp_lcd_touch_config_t config = { + .x_max = TDECK_TOUCH_X_MAX, + .y_max = TDECK_TOUCH_Y_MAX, + .rst_gpio_num = GPIO_NUM_NC, + .int_gpio_num = TDECK_TOUCH_PIN_INT, + .levels = { + .reset = 0, + .interrupt = 0, + }, + .flags = { + .swap_xy = 1, + .mirror_x = 1, + .mirror_y = 0, + }, + .process_coordinates = nullptr, + .interrupt_callback = nullptr, + .user_data = nullptr, + .driver_data = nullptr + }; + + if (esp_lcd_touch_new_i2c_gt911(ioHandle, &config, &touchHandle) != ESP_OK) { + TT_LOG_E(TAG, "GT199 driver init failed"); + // TODO: De-init IO + return false; + } + + const lvgl_port_touch_cfg_t touch_cfg = { + .disp = display, + .handle = touchHandle, + }; + + TT_LOG_I(TAG, "Adding touch to LVGL"); + deviceHandle = lvgl_port_add_touch(&touch_cfg); + if (deviceHandle == nullptr) { + TT_LOG_E(TAG, "Adding touch failed"); + return false; + } + + return true; +} + +bool TdeckTouch::stop() { + if (esp_lcd_touch_del(touchHandle) == ESP_OK) { + touchHandle = nullptr; + } else { + TT_LOG_E(TAG, "Deleting driver failed"); + return false; + } + + if (esp_lcd_panel_io_del(ioHandle) == ESP_OK) { + ioHandle = nullptr; + } else { + TT_LOG_E(TAG, "Deleting IO handle failed"); + return false; + } + + return true; +} diff --git a/Boards/LilygoTdeck/Source/hal/TdeckTouch.h b/Boards/LilygoTdeck/Source/hal/TdeckTouch.h new file mode 100644 index 00000000..e35f9b7f --- /dev/null +++ b/Boards/LilygoTdeck/Source/hal/TdeckTouch.h @@ -0,0 +1,17 @@ +#pragma once + +#include "hal/Touch.h" +#include "TactilityCore.h" +#include "esp_lcd_panel_io_interface.h" +#include "esp_lcd_touch.h" + +class TdeckTouch : public tt::hal::Touch { +private: + esp_lcd_panel_io_handle_t _Nullable ioHandle = nullptr; + esp_lcd_touch_handle_t _Nullable touchHandle = nullptr; + lv_indev_t* _Nullable deviceHandle = nullptr; +public: + bool start(lv_display_t* display) override; + bool stop() override; + lv_indev_t* _Nullable getLvglIndev() override { return deviceHandle; } +}; diff --git a/Boards/LilygoTdeck/config.h b/Boards/LilygoTdeck/config.h deleted file mode 100644 index 2b3d5292..00000000 --- a/Boards/LilygoTdeck/config.h +++ /dev/null @@ -1,64 +0,0 @@ -#pragma once - -#include "driver/i2c.h" -#include "driver/gpio.h" - -// Main bus, used by GT911 touch hardware and keyboard -#define TDECK_I2C_BUS_HANDLE I2C_NUM_0 - -// SPI -#define TDECK_SPI_HOST SPI2_HOST -#define TDECK_SPI_PIN_SCLK GPIO_NUM_40 -#define TDECK_SPI_PIN_MOSI GPIO_NUM_41 -#define TDECK_SPI_PIN_MISO GPIO_NUM_38 -#define TDECK_SPI_TRANSFER_SIZE_LIMIT (TDECK_LCD_HORIZONTAL_RESOLUTION * TDECK_LCD_SPI_TRANSFER_HEIGHT * (TDECK_LCD_BITS_PER_PIXEL / 8)) - -// Power on -#define TDECK_POWERON_GPIO GPIO_NUM_10 -#define TDECK_POWERON_DELAY 2000 // milliseconds - see bootstrap.c for explanation - -// Display -#define TDECK_LCD_SPI_HOST SPI2_HOST -#define TDECK_LCD_PIN_CS GPIO_NUM_12 -#define TDECK_LCD_PIN_DC GPIO_NUM_11 // RS -#define TDECK_LCD_PIN_BACKLIGHT GPIO_NUM_42 -#define TDECK_LCD_SPI_FREQUENCY 40000000 -#define TDECK_LCD_HORIZONTAL_RESOLUTION 320 -#define TDECK_LCD_VERTICAL_RESOLUTION 240 -#define TDECK_LCD_BITS_PER_PIXEL 16 -#define TDECK_LCD_DRAW_BUFFER_HEIGHT (TDECK_LCD_VERTICAL_RESOLUTION / 10) -#define TDECK_LCD_SPI_TRANSFER_HEIGHT (TDECK_LCD_VERTICAL_RESOLUTION / 10) - -// LVGL -// The minimum task stack seems to be about 3500, but that crashes the wifi app in some scenarios -// At 4000, it crashes when the fps renderer is available -#define TDECK_LVGL_TASK_STACK_DEPTH 8192 - -// Dipslay backlight (PWM) -#define TDECK_LCD_BACKLIGHT_LEDC_TIMER LEDC_TIMER_0 -#define TDECK_LCD_BACKLIGHT_LEDC_MODE LEDC_LOW_SPEED_MODE -#define TDECK_LCD_BACKLIGHT_LEDC_CHANNEL LEDC_CHANNEL_0 -#define TDECK_LCD_BACKLIGHT_LEDC_DUTY_RES LEDC_TIMER_8_BIT -#define TDECK_LCD_BACKLIGHT_LEDC_FREQUENCY (4000) - -// Touch (GT911) -#define TDECK_TOUCH_I2C_BUS_HANDLE TDECK_I2C_BUS_HANDLE -#define TDECK_TOUCH_X_MAX 240 -#define TDECK_TOUCH_Y_MAX 320 -#define TDECK_TOUCH_PIN_INT GPIO_NUM_16 - -// SD Card -#define TDECK_SDCARD_SPI_HOST SPI2_HOST -#define TDECK_SDCARD_PIN_CS GPIO_NUM_39 -#define TDECK_SDCARD_SPI_FREQUENCY 800000U -#define TDECK_SDCARD_FORMAT_ON_MOUNT_FAILED false -#define TDECK_SDCARD_MAX_OPEN_FILES 4 -#define TDECK_SDCARD_ALLOC_UNIT_SIZE (16 * 1024) -#define TDECK_SDCARD_STATUS_CHECK_ENABLED false - -// Keyboard -#define TDECK_KEYBOARD_I2C_BUS_HANDLE TDECK_I2C_BUS_HANDLE -#define TDECK_KEYBOARD_SLAVE_ADDRESS 0x55 - -// Lora (optional) -#define TDECK_RADIO_PIN_CS GPIO_NUM_9 diff --git a/Boards/LilygoTdeck/display.h b/Boards/LilygoTdeck/display.h deleted file mode 100644 index 17bcf4ec..00000000 --- a/Boards/LilygoTdeck/display.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include "lvgl.h" - -lv_display_t* tdeck_display_init(); - -bool tdeck_backlight_init(); - -void tdeck_backlight_set(uint8_t duty); \ No newline at end of file diff --git a/Boards/LilygoTdeck/keyboard.h b/Boards/LilygoTdeck/keyboard.h deleted file mode 100644 index 26a3784a..00000000 --- a/Boards/LilygoTdeck/keyboard.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include "lvgl.h" - -void keyboard_wait_for_response(); - -typedef void* Keyboard; - -Keyboard keyboard_alloc(_Nullable lv_disp_t* display); -void keyboard_free(Keyboard keyboard); \ No newline at end of file diff --git a/Boards/LilygoTdeck/lvgl.cpp b/Boards/LilygoTdeck/lvgl.cpp deleted file mode 100644 index 80a9bfd2..00000000 --- a/Boards/LilygoTdeck/lvgl.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include "Log.h" -#include "Thread.h" -#include "lvgl/LvglSync.h" -#include "config.h" -#include "display.h" -#include "esp_lvgl_port.h" -#include "keyboard.h" - -#define TAG "tdeck_lvgl" - -bool tdeck_init_touch(esp_lcd_panel_io_handle_t* io_handle, esp_lcd_touch_handle_t* touch_handle); - -bool tdeck_init_lvgl() { - static lv_disp_t* display = nullptr; - static esp_lcd_panel_io_handle_t touch_io_handle; - static esp_lcd_touch_handle_t touch_handle; - - const lvgl_port_cfg_t lvgl_cfg = { - .task_priority = tt::THREAD_PRIORITY_RENDER, - .task_stack = TDECK_LVGL_TASK_STACK_DEPTH, - .task_affinity = -1, // core pinning - .task_max_sleep_ms = 500, - .timer_period_ms = 5 - }; - - TT_LOG_D(TAG, "LVGL port init"); - if (lvgl_port_init(&lvgl_cfg) != ESP_OK) { - TT_LOG_E(TAG, "LVGL port init failed"); - return false; - } - - // Add display - - TT_LOG_D(TAG, "Creating display"); - display = tdeck_display_init(); - if (display == nullptr) { - TT_LOG_E(TAG, "Creating display failed"); - return false; - } - - // Add touch - - TT_LOG_D(TAG, "Creating touch"); - if (!tdeck_init_touch(&touch_io_handle, &touch_handle)) { - TT_LOG_E(TAG, "Creating touch failed"); - return false; - } - - const lvgl_port_touch_cfg_t touch_cfg = { - .disp = display, - .handle = touch_handle, - }; - - TT_LOG_D(TAG, "Adding touch"); - lv_indev_t _Nullable* touch_indev = lvgl_port_add_touch(&touch_cfg); - if (touch_indev == nullptr) { - TT_LOG_E(TAG, "Adding touch failed"); - return false; - } - - // Set syncing functions - tt::lvgl::syncSet(&lvgl_port_lock, &lvgl_port_unlock); - - keyboard_alloc(display); - - return true; -} diff --git a/Boards/LilygoTdeck/touch.cpp b/Boards/LilygoTdeck/touch.cpp deleted file mode 100644 index 8d37565f..00000000 --- a/Boards/LilygoTdeck/touch.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include "config.h" -#include "esp_err.h" -#include "esp_lcd_panel_io_interface.h" -#include "esp_lcd_touch_gt911.h" -#include "Log.h" -#include "Kernel.h" - -#define TAG "tdeck_touch" - -bool tdeck_init_touch(esp_lcd_panel_io_handle_t* io_handle, esp_lcd_touch_handle_t* touch_handle) { - const esp_lcd_panel_io_i2c_config_t touch_io_config = ESP_LCD_TOUCH_IO_I2C_GT911_CONFIG(); - - // TODO: Revert on new ESP-IDF version - static_assert(ESP_IDF_VERSION == ESP_IDF_VERSION_VAL(5, 3, 1)); - esp_lcd_new_panel_io_i2c( - (esp_lcd_i2c_bus_handle_t)TDECK_TOUCH_I2C_BUS_HANDLE, - &touch_io_config, - io_handle - ); - /* - if ( - esp_lcd_new_panel_io_i2c( - (esp_lcd_i2c_bus_handle_t)TDECK_TOUCH_I2C_BUS_HANDLE, - &touch_io_config, - io_handle - ) != ESP_OK - ) { - TT_LOG_E(TAG, "touch io i2c creation failed"); - return false; - } - */ - - esp_lcd_touch_config_t config = { - .x_max = TDECK_TOUCH_X_MAX, - .y_max = TDECK_TOUCH_Y_MAX, - .rst_gpio_num = GPIO_NUM_NC, - .int_gpio_num = TDECK_TOUCH_PIN_INT, - .levels = { - .reset = 0, - .interrupt = 0, - }, - .flags = { - .swap_xy = 1, - .mirror_x = 1, - .mirror_y = 0, - }, - .process_coordinates = nullptr, - .interrupt_callback = nullptr, - .user_data = nullptr - }; - - if (esp_lcd_touch_new_i2c_gt911(*io_handle, &config, touch_handle) != ESP_OK) { - TT_LOG_E(TAG, "gt911 driver creation failed"); - return false; - } - - return true; -} \ No newline at end of file diff --git a/Boards/M5stackCore2/Source/M5stackCore2.cpp b/Boards/M5stackCore2/Source/M5stackCore2.cpp index 23c1cbfa..2bf3b1b4 100644 --- a/Boards/M5stackCore2/Source/M5stackCore2.cpp +++ b/Boards/M5stackCore2/Source/M5stackCore2.cpp @@ -2,8 +2,9 @@ #include "M5stackShared.h" extern const tt::hal::Configuration m5stack_core2 = { - .initPower = &m5stack_bootstrap, + .initBoot = &m5stack_bootstrap, .initLvgl = &m5stack_lvgl_init, + .createDisplay = createDisplay, .sdcard = &m5stack_sdcard, .power = &m5stack_power, .i2c = { diff --git a/Boards/M5stackCoreS3/Source/M5stackCoreS3.cpp b/Boards/M5stackCoreS3/Source/M5stackCoreS3.cpp index 8a0a4767..7a7cf0ff 100644 --- a/Boards/M5stackCoreS3/Source/M5stackCoreS3.cpp +++ b/Boards/M5stackCoreS3/Source/M5stackCoreS3.cpp @@ -1,11 +1,10 @@ #include "M5stackCoreS3.h" #include "M5stackShared.h" -extern const tt::hal::sdcard::SdCard m5stack_cores3_sdcard; - const tt::hal::Configuration m5stack_cores3 = { - .initPower = &m5stack_bootstrap, + .initBoot = &m5stack_bootstrap, .initLvgl = &m5stack_lvgl_init, + .createDisplay = createDisplay, .sdcard = &m5stack_sdcard, .power = &m5stack_power, .i2c = { diff --git a/Boards/M5stackShared/CMakeLists.txt b/Boards/M5stackShared/CMakeLists.txt index 95b47957..bf3c2afd 100644 --- a/Boards/M5stackShared/CMakeLists.txt +++ b/Boards/M5stackShared/CMakeLists.txt @@ -1,5 +1,5 @@ idf_component_register( - SRC_DIRS "Source" + SRC_DIRS "Source" "Source/hal" INCLUDE_DIRS "Source" REQUIRES Tactility esp_lvgl_port M5Unified vfs fatfs ) diff --git a/Boards/M5stackShared/Source/Lvgl.cpp b/Boards/M5stackShared/Source/Lvgl.cpp index 38fe798d..2c70e450 100644 --- a/Boards/M5stackShared/Source/Lvgl.cpp +++ b/Boards/M5stackShared/Source/Lvgl.cpp @@ -5,8 +5,8 @@ #define TAG "cores3_lvgl" -_Nullable lv_disp_t* m5stack_lvgl_display(bool usePsram); -_Nullable lv_indev_t* m5stack_lvgl_touch(); +_Nullable lv_disp_t* createDisplay(bool usePsram); +_Nullable lv_indev_t* createTouch(); bool m5stack_lvgl_init() { static lv_display_t* display = nullptr; @@ -24,21 +24,6 @@ bool m5stack_lvgl_init() { return false; } - // Add display - display = m5stack_lvgl_display(true); - if (display == nullptr) { - TT_LOG_E(TAG, "failed to add display"); - return false; - } - - // Add touch - lv_indev_t* touch_indev = m5stack_lvgl_touch(); - if (touch_indev == nullptr) { - TT_LOG_E(TAG, "failed to add touch"); - return false; - } - lv_indev_set_display(touch_indev, display); - // Set syncing functions tt::lvgl::syncSet(&lvgl_port_lock, &lvgl_port_unlock); diff --git a/Boards/M5stackShared/Source/LvglTouch.cpp b/Boards/M5stackShared/Source/LvglTouch.cpp deleted file mode 100644 index c0c3d24e..00000000 --- a/Boards/M5stackShared/Source/LvglTouch.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "M5Unified.hpp" -#include "lvgl.h" -#include "TactilityCore.h" - -#define TAG "cores3_touch" - -static void read_callback(TT_UNUSED lv_indev_t* indev, lv_indev_data_t* data) { - lgfx::touch_point_t point; // Making it static makes it unreliable - bool touched = M5.Lcd.getTouch(&point) > 0; - if (!touched) { - data->state = LV_INDEV_STATE_REL; - } else { - data->state = LV_INDEV_STATE_PR; - data->point.x = point.x; - data->point.y = point.y; - } -} - -_Nullable lv_indev_t* m5stack_lvgl_touch() { - static lv_indev_t* indev = lv_indev_create(); - LV_ASSERT_MALLOC(indev) - if (indev == nullptr) { - return nullptr; - } - - lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER); - lv_indev_set_read_cb(indev, read_callback); - return indev; -} diff --git a/Boards/M5stackShared/Source/M5stackShared.h b/Boards/M5stackShared/Source/M5stackShared.h index aefe3ef2..63ff27f8 100644 --- a/Boards/M5stackShared/Source/M5stackShared.h +++ b/Boards/M5stackShared/Source/M5stackShared.h @@ -1,6 +1,8 @@ #pragma once #include "hal/Power.h" +#include "hal/M5stackTouch.h" +#include "hal/M5stackDisplay.h" #include "hal/sdcard/Sdcard.h" extern bool m5stack_bootstrap(); diff --git a/Boards/M5stackShared/Source/LvglDisplay.cpp b/Boards/M5stackShared/Source/hal/M5stackDisplay.cpp similarity index 70% rename from Boards/M5stackShared/Source/LvglDisplay.cpp rename to Boards/M5stackShared/Source/hal/M5stackDisplay.cpp index 98da1dc2..a42446ba 100644 --- a/Boards/M5stackShared/Source/LvglDisplay.cpp +++ b/Boards/M5stackShared/Source/hal/M5stackDisplay.cpp @@ -1,4 +1,11 @@ -#include "TactilityCore.h" +#include "M5stackDisplay.h" +#include "M5stackTouch.h" +#include "Log.h" + +#include + +#define TAG "m5shared_display" + #include "M5Unified.hpp" #include "esp_err.h" @@ -18,8 +25,7 @@ static void flush_callback(lv_display_t* display, const lv_area_t* area, uint8_t lv_display_flush_ready(display); } - -_Nullable lv_disp_t* m5stack_lvgl_display(bool usePsram) { +_Nullable lv_disp_t* createDisplay(bool usePsram) { M5GFX& gfx = M5.Display; static lv_display_t* display = lv_display_create(gfx.width(), gfx.height()); @@ -59,3 +65,25 @@ _Nullable lv_disp_t* m5stack_lvgl_display(bool usePsram) { return display; } + +bool M5stackDisplay::start() { + TT_LOG_I(TAG, "Starting"); + displayHandle = createDisplay(true); + TT_LOG_I(TAG, "Finished"); + return displayHandle != nullptr; +} + +bool M5stackDisplay::stop() { + tt_assert(displayHandle != nullptr); + lv_display_delete(displayHandle); + displayHandle = nullptr; + return true; +} + +tt::hal::Touch* _Nullable M5stackDisplay::createTouch() { + return static_cast(new M5stackTouch()); +} + +tt::hal::Display* createDisplay() { + return static_cast(new M5stackDisplay()); +} diff --git a/Boards/M5stackShared/Source/hal/M5stackDisplay.h b/Boards/M5stackShared/Source/hal/M5stackDisplay.h new file mode 100644 index 00000000..961b7e61 --- /dev/null +++ b/Boards/M5stackShared/Source/hal/M5stackDisplay.h @@ -0,0 +1,33 @@ +#pragma once + +#include "lvgl.h" +#include "hal/Display.h" + +extern lv_disp_t* displayHandle; + +class M5stackDisplay : public tt::hal::Display { + +private: + + lv_display_t* displayHandle = nullptr; + +public: + + bool start() override; + + bool stop() override; + + void setPowerOn(bool turnOn) override {} + bool isPoweredOn() const override { return true; }; + bool supportsPowerControl() const override { return false; } + + tt::hal::Touch* _Nullable createTouch() override; + + void setBacklightDuty(uint8_t backlightDuty) override {} + uint8_t getBacklightDuty() const override { return 255; } + bool supportsBacklightDuty() const override { return false; } + + lv_display_t* _Nullable getLvglDisplay() const override { return displayHandle; } +}; + +tt::hal::Display* createDisplay(); diff --git a/Boards/M5stackShared/Source/hal/M5stackTouch.cpp b/Boards/M5stackShared/Source/hal/M5stackTouch.cpp new file mode 100644 index 00000000..4c38618f --- /dev/null +++ b/Boards/M5stackShared/Source/hal/M5stackTouch.cpp @@ -0,0 +1,48 @@ +#include "M5stackTouch.h" +#include "M5Unified.hpp" +#include "esp_err.h" +#include "Log.h" + +#define TAG "m5stack_touch" + +static void touchReadCallback(TT_UNUSED lv_indev_t* indev, lv_indev_data_t* data) { + lgfx::touch_point_t point; // Making it static makes it unreliable + bool touched = M5.Lcd.getTouch(&point) > 0; + if (!touched) { + data->state = LV_INDEV_STATE_REL; + } else { + data->state = LV_INDEV_STATE_PR; + data->point.x = point.x; + data->point.y = point.y; + } +} + +_Nullable lv_indev_t* createTouch() { + static lv_indev_t* indev = lv_indev_create(); + LV_ASSERT_MALLOC(indev) + if (indev == nullptr) { + return nullptr; + } + + lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER); + lv_indev_set_read_cb(indev, touchReadCallback); + return indev; +} +bool M5stackTouch::start(lv_display_t* display) { + + TT_LOG_I(TAG, "Adding touch to LVGL"); + deviceHandle = createTouch(); + if (deviceHandle == nullptr) { + TT_LOG_E(TAG, "Adding touch failed"); + return false; + } + + return true; +} + +bool M5stackTouch::stop() { + tt_assert(deviceHandle != nullptr); + lv_indev_delete(deviceHandle); + deviceHandle = nullptr; + return true; +} diff --git a/Boards/M5stackShared/Source/hal/M5stackTouch.h b/Boards/M5stackShared/Source/hal/M5stackTouch.h new file mode 100644 index 00000000..f26b6904 --- /dev/null +++ b/Boards/M5stackShared/Source/hal/M5stackTouch.h @@ -0,0 +1,13 @@ +#pragma once + +#include "hal/Touch.h" +#include "TactilityCore.h" + +class M5stackTouch : public tt::hal::Touch { +private: + lv_indev_t* _Nullable deviceHandle = nullptr; +public: + bool start(lv_display_t* display) override; + bool stop() override; + lv_indev_t* _Nullable getLvglIndev() override { return deviceHandle; } +}; diff --git a/Boards/Simulator/Source/lvgl_task.cpp b/Boards/Simulator/Source/LvglTask.cpp similarity index 83% rename from Boards/Simulator/Source/lvgl_task.cpp rename to Boards/Simulator/Source/LvglTask.cpp index 2a301085..17f33327 100644 --- a/Boards/Simulator/Source/lvgl_task.cpp +++ b/Boards/Simulator/Source/LvglTask.cpp @@ -1,8 +1,7 @@ -#include "lvgl_task.h" +#include "LvglTask.h" #include "lvgl.h" #include "Log.h" -#include "lvgl_hal.h" #include "TactilityCore.h" #include "Thread.h" #include "lvgl/LvglSync.h" @@ -66,18 +65,23 @@ void lvgl_task_start() { lvgl_task, "lvgl", 8192, - NULL, + nullptr, tt::Thread::PriorityHigh, // Should be higher than main app task - NULL + nullptr ); tt_assert(task_result == pdTRUE); } +lv_disp_t* displayHandle = nullptr; + static void lvgl_task(TT_UNUSED void* arg) { TT_LOG_I(TAG, "lvgl task started"); - lv_disp_t* display = lvgl_hal_init(); + /** Ideally. the display handle would be created during Simulator.start(), + * but somehow that doesn't work. Waiting here from a ThreadFlag when that happens + * also doesn't work. It seems that it must be called from this task. */ + displayHandle = lv_sdl_window_create(320, 240); uint32_t task_delay_ms = task_max_sleep_ms; @@ -96,8 +100,7 @@ static void lvgl_task(TT_UNUSED void* arg) { vTaskDelay(pdMS_TO_TICKS(task_delay_ms)); } - lv_disp_remove(display); - - vTaskDelete(NULL); + lv_disp_remove(displayHandle); + displayHandle = nullptr; } diff --git a/Boards/Simulator/Source/lvgl_task.h b/Boards/Simulator/Source/LvglTask.h similarity index 100% rename from Boards/Simulator/Source/lvgl_task.h rename to Boards/Simulator/Source/LvglTask.h diff --git a/Boards/Simulator/Source/freertos.cpp b/Boards/Simulator/Source/Main.cpp similarity index 74% rename from Boards/Simulator/Source/freertos.cpp rename to Boards/Simulator/Source/Main.cpp index 48e782ac..bd559e39 100644 --- a/Boards/Simulator/Source/freertos.cpp +++ b/Boards/Simulator/Source/Main.cpp @@ -1,21 +1,31 @@ +#include "Main.h" +#include "TactilityCore.h" #include "Thread.h" #include "FreeRTOS.h" #include "task.h" -#include "Simulator.h" #define TAG "freertos" -static void main_task(TT_UNUSED void* parameter) { +namespace simulator { + +MainFunction mainFunction = nullptr; + +void setMain(MainFunction newMainFunction) { + mainFunction = newMainFunction; +} + +static void freertosMainTask(TT_UNUSED void* parameter) { TT_LOG_I(TAG, "starting app_main()"); - executeMainFunction(); + assert(simulator::mainFunction); + mainFunction(); TT_LOG_I(TAG, "returned from app_main()"); vTaskDelete(nullptr); } -int main_stub() { +void freertosMain() { BaseType_t task_result = xTaskCreate( - main_task, + freertosMainTask, "main", 8192, nullptr, @@ -29,6 +39,8 @@ int main_stub() { vTaskStartScheduler(); } +} // namespace + /** * Assert implementation as defined in the FreeRTOSConfig.h * It allows you to set breakpoints and debug asserts. @@ -47,3 +59,4 @@ void vAssertCalled(unsigned long line, const char* const file) { } taskEXIT_CRITICAL(); } + diff --git a/Boards/Simulator/Source/Main.h b/Boards/Simulator/Source/Main.h new file mode 100644 index 00000000..30fcb48f --- /dev/null +++ b/Boards/Simulator/Source/Main.h @@ -0,0 +1,3 @@ +#pragma once + +typedef void (*MainFunction)(); diff --git a/Boards/Simulator/Source/Simulator.cpp b/Boards/Simulator/Source/Simulator.cpp deleted file mode 100644 index e84fd244..00000000 --- a/Boards/Simulator/Source/Simulator.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include "Simulator.h" - -MainFunction mainFunction = nullptr; - -void setMainForSim(MainFunction newMainFunction) { - mainFunction = newMainFunction; -} - -void executeMainFunction() { - assert(mainFunction); - mainFunction(); -} diff --git a/Boards/Simulator/Source/Simulator.h b/Boards/Simulator/Source/Simulator.h index 818d45bd..c0198327 100644 --- a/Boards/Simulator/Source/Simulator.h +++ b/Boards/Simulator/Source/Simulator.h @@ -1,10 +1,22 @@ #pragma once #include "hal/Configuration.h" +#include "Main.h" -extern const tt::hal::Configuration sim_hardware; +namespace simulator { + /** Set the function pointer of the real app_main() */ + void setMain(MainFunction mainFunction); + /** The actual main task */ + void freertosMain(); +} -typedef void (*MainFunction)(); -void setMainForSim(MainFunction mainFunction); -void executeMainFunction(); -int main_stub(); +extern "C" { +void app_main(); // ESP-IDF's main function, implemented in the application +} + +int main() { + // Actual main function that passes on app_main() (to be executed in a FreeRTOS task) and bootstraps FreeRTOS + simulator::setMain(app_main); + simulator::freertosMain(); + return 0; +} diff --git a/Boards/Simulator/Source/hardware_config.cpp b/Boards/Simulator/Source/hal/Configuration.cpp similarity index 84% rename from Boards/Simulator/Source/hardware_config.cpp rename to Boards/Simulator/Source/hal/Configuration.cpp index f95f0e1a..6a69c1a4 100644 --- a/Boards/Simulator/Source/hardware_config.cpp +++ b/Boards/Simulator/Source/hal/Configuration.cpp @@ -1,18 +1,20 @@ #include "hal/Configuration.h" -#include "lvgl_task.h" +#include "LvglTask.h" #include "src/lv_init.h" +#include "SdlDisplay.h" +#include "SdlKeyboard.h" #define TAG "hardware" extern const tt::hal::Power power; -static bool lvgl_init() { +static bool initBoot() { lv_init(); lvgl_task_start(); return true; } -TT_UNUSED static void lvgl_deinit() { +TT_UNUSED static void deinitPower() { lvgl_task_interrupt(); while (lvgl_task_is_running()) { tt::delay_ms(10); @@ -23,11 +25,10 @@ TT_UNUSED static void lvgl_deinit() { #endif } -extern const tt::hal::Configuration sim_hardware = { - .initLvgl = &lvgl_init, - .display = { - .setBacklightDuty = nullptr, - }, +extern const tt::hal::Configuration hardware = { + .initBoot = initBoot, + .createDisplay = createDisplay, + .createKeyboard = createKeyboard, .sdcard = nullptr, .power = &power, .i2c = { diff --git a/Boards/Simulator/Source/hal/Power.cpp b/Boards/Simulator/Source/hal/Power.cpp new file mode 100644 index 00000000..ce7012cf --- /dev/null +++ b/Boards/Simulator/Source/hal/Power.cpp @@ -0,0 +1,31 @@ +#include "hal/Power.h" + +static bool is_charging_enabled = false; + +static bool isCharging() { + return is_charging_enabled; +} + +static bool isChargingEnabled() { + return is_charging_enabled; +} + +static void setChargingEnabled(bool enabled) { + is_charging_enabled = enabled; +} + +static uint8_t getChargeLevel() { + return 204; +} + +static int32_t getCurrent() { + return is_charging_enabled ? 100 : -50; +} + +extern const tt::hal::Power power = { + .isCharging = isCharging, + .isChargingEnabled = isChargingEnabled, + .setChargingEnabled = setChargingEnabled, + .getChargeLevel = getChargeLevel, + .getCurrent = getCurrent +}; diff --git a/Boards/Simulator/Source/hal/SdlDisplay.h b/Boards/Simulator/Source/hal/SdlDisplay.h new file mode 100644 index 00000000..d4489415 --- /dev/null +++ b/Boards/Simulator/Source/hal/SdlDisplay.h @@ -0,0 +1,32 @@ +#pragma once + +#include "SdlTouch.h" +#include "hal/Display.h" + +extern lv_disp_t* displayHandle; + +class SdlDisplay : public tt::hal::Display { +public: + bool start() override { + return displayHandle != nullptr; + } + + bool stop() override { tt_crash("Not supported"); } + + void setPowerOn(bool turnOn) override {} + bool isPoweredOn() const override { return displayHandle != nullptr; } + bool supportsPowerControl() const override { return false; } + + tt::hal::Touch* _Nullable createTouch() override { return dynamic_cast(new SdlTouch()); } + + void setBacklightDuty(uint8_t backlightDuty) override {} + uint8_t getBacklightDuty() const override { return 255; } + bool supportsBacklightDuty() const override { return false; } + + lv_display_t* _Nullable getLvglDisplay() const override { return displayHandle; } +}; + +tt::hal::Display* createDisplay() { + return static_cast(new SdlDisplay()); +} + diff --git a/Boards/Simulator/Source/hal/SdlKeyboard.h b/Boards/Simulator/Source/hal/SdlKeyboard.h new file mode 100644 index 00000000..dc49e92d --- /dev/null +++ b/Boards/Simulator/Source/hal/SdlKeyboard.h @@ -0,0 +1,26 @@ +#pragma once + +#include "hal/Keyboard.h" + +#include + +class SdlKeyboard : public tt::hal::Keyboard { +private: + lv_indev_t* _Nullable handle = nullptr; + +public: + bool start(lv_display_t* display) override { + handle = lv_sdl_keyboard_create(); + return handle != nullptr; + } + + bool stop() override { tt_crash("Not supported"); } + + bool isAttached() const override { return true; } + + lv_indev_t* _Nullable getLvglIndev() override { return handle; } +}; + +tt::hal::Keyboard* createKeyboard() { + return static_cast(new SdlKeyboard()); +} diff --git a/Boards/Simulator/Source/hal/SdlTouch.h b/Boards/Simulator/Source/hal/SdlTouch.h new file mode 100644 index 00000000..df1dfbcc --- /dev/null +++ b/Boards/Simulator/Source/hal/SdlTouch.h @@ -0,0 +1,21 @@ +#pragma once + +#include "hal/Touch.h" + +#include + +class SdlTouch : public tt::hal::Touch { +private: + lv_indev_t* _Nullable handle = nullptr; + +public: + bool start(lv_display_t* display) override { + handle = lv_sdl_mouse_create(); + return handle != nullptr; + } + + bool stop() override { tt_crash("Not supported"); } + + lv_indev_t* _Nullable getLvglIndev() override { return handle; } +}; + diff --git a/Boards/Simulator/Source/lvgl_hal.cpp b/Boards/Simulator/Source/lvgl_hal.cpp deleted file mode 100644 index 1bc28a7a..00000000 --- a/Boards/Simulator/Source/lvgl_hal.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "lvgl.h" -#include "lvgl/LvglKeypad.h" - -lv_display_t* lvgl_hal_init() { - static lv_display_t* display = NULL; - static lv_indev_t* mouse = NULL; - static lv_indev_t* keyboard = NULL; - - display = lv_sdl_window_create(320, 240); - mouse = lv_sdl_mouse_create(); - keyboard = lv_sdl_keyboard_create(); - tt::lvgl::keypad_set_indev(keyboard); - - return display; -} diff --git a/Boards/Simulator/Source/lvgl_hal.h b/Boards/Simulator/Source/lvgl_hal.h deleted file mode 100644 index 6eef2636..00000000 --- a/Boards/Simulator/Source/lvgl_hal.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -#include - -lv_display_t* lvgl_hal_init(); diff --git a/Boards/Simulator/Source/power.cpp b/Boards/Simulator/Source/power.cpp deleted file mode 100644 index a97df182..00000000 --- a/Boards/Simulator/Source/power.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include "hal/Power.h" - -static bool is_charging_enabled = false; - -static bool power_is_charging() { - return is_charging_enabled; -} - -static bool power_is_charging_enabled() { - return is_charging_enabled; -} - -static void power_set_charging_enabled(bool enabled) { - is_charging_enabled = enabled; -} - -static uint8_t power_get_charge_level() { - return 204; -} - -static int32_t power_get_current() { - return is_charging_enabled ? 100 : -50; -} - -extern const tt::hal::Power power = { - .isCharging = &power_is_charging, - .isChargingEnabled = &power_is_charging_enabled, - .setChargingEnabled = &power_set_charging_enabled, - .getChargeLevel = &power_get_charge_level, - .getCurrent = &power_get_current -}; diff --git a/Boards/WaveshareS3Touch/CMakeLists.txt b/Boards/WaveshareS3Touch/CMakeLists.txt deleted file mode 100644 index ebb9df4a..00000000 --- a/Boards/WaveshareS3Touch/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -idf_component_register( - SRC_DIRS "." - INCLUDE_DIRS "." - REQUIRES Tactility lvgl esp_lcd esp_lcd_touch_gt911 -) diff --git a/Boards/WaveshareS3Touch/bootstrap.cpp b/Boards/WaveshareS3Touch/bootstrap.cpp deleted file mode 100644 index f8837be1..00000000 --- a/Boards/WaveshareS3Touch/bootstrap.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include "config.h" -#include "TactilityCore.h" -#include - -#define TAG "waveshare_bootstrap" - -#define WAVESHARE_I2C_MASTER_TX_BUF_DISABLE 0 -#define WAVESHARE_I2C_MASTER_RX_BUF_DISABLE 0 - -static esp_err_t i2c_init() { - const i2c_config_t i2c_conf = { - .mode = I2C_MODE_MASTER, - .sda_io_num = GPIO_NUM_8, - .scl_io_num = GPIO_NUM_9, - .sda_pullup_en = false, - .scl_pullup_en = false, - .master = { - .clk_speed = 400000 - } - }; - - i2c_param_config(WAVESHARE_TOUCH_I2C_PORT, &i2c_conf); - - return i2c_driver_install( - WAVESHARE_TOUCH_I2C_PORT, - i2c_conf.mode, - WAVESHARE_I2C_MASTER_RX_BUF_DISABLE, - WAVESHARE_I2C_MASTER_TX_BUF_DISABLE, - 0 - ) == ESP_OK; -} - -bool ws3t_bootstrap() { - if (!i2c_init()) { - TT_LOG_E(TAG, "I2C init failed"); - return false; - } - return true; -} diff --git a/Boards/WaveshareS3Touch/bootstrap_i.h b/Boards/WaveshareS3Touch/bootstrap_i.h deleted file mode 100644 index ffb4c9d1..00000000 --- a/Boards/WaveshareS3Touch/bootstrap_i.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -bool ws3t_bootstrap(); diff --git a/Boards/WaveshareS3Touch/config.h b/Boards/WaveshareS3Touch/config.h deleted file mode 100644 index 21e21f15..00000000 --- a/Boards/WaveshareS3Touch/config.h +++ /dev/null @@ -1,38 +0,0 @@ -/** -* The WaveShare S3 Touch uses a panel with the ST7262 display driver. -*/ -#pragma once - -#define WAVESHARE_LCD_HOR_RES 800 -#define WAVESHARE_LCD_VER_RES 480 - -#define WAVESHARE_LCD_PIXEL_CLOCK_HZ (12 * 1000 * 1000) // NOTE: original was 14MHz, but we had to slow it down with PSRAM frame buffer -#define WAVESHARE_LCD_PIN_NUM_HSYNC 46 -#define WAVESHARE_LCD_PIN_NUM_VSYNC 3 -#define WAVESHARE_LCD_PIN_NUM_DE 5 -#define WAVESHARE_LCD_PIN_NUM_PCLK 7 -#define WAVESHARE_LCD_PIN_NUM_DATA0 14 // B3 -#define WAVESHARE_LCD_PIN_NUM_DATA1 38 // B4 -#define WAVESHARE_LCD_PIN_NUM_DATA2 18 // B5 -#define WAVESHARE_LCD_PIN_NUM_DATA3 17 // B6 -#define WAVESHARE_LCD_PIN_NUM_DATA4 10 // B7 -#define WAVESHARE_LCD_PIN_NUM_DATA5 39 // G2 -#define WAVESHARE_LCD_PIN_NUM_DATA6 0 // G3 -#define WAVESHARE_LCD_PIN_NUM_DATA7 45 // G4 -#define WAVESHARE_LCD_PIN_NUM_DATA8 48 // G5 -#define WAVESHARE_LCD_PIN_NUM_DATA9 47 // G6 -#define WAVESHARE_LCD_PIN_NUM_DATA10 21 // G7 -#define WAVESHARE_LCD_PIN_NUM_DATA11 1 // R3 -#define WAVESHARE_LCD_PIN_NUM_DATA12 2 // R4 -#define WAVESHARE_LCD_PIN_NUM_DATA13 42 // R5 -#define WAVESHARE_LCD_PIN_NUM_DATA14 41 // R6 -#define WAVESHARE_LCD_PIN_NUM_DATA15 40 // R7 -#define WAVESHARE_LCD_PIN_NUM_DISP_EN (-1) -#define WAVESHARE_LCD_BUFFER_HEIGHT (WAVESHARE_LCD_VER_RES / 3) // How many rows of pixels to buffer - 1/3rd is about 1MB - -#define WAVESHARE_LCD_USE_DOUBLE_FB true // Performance boost at the cost of about extra PSRAM(SPIRAM) - -#define WAVESHARE_LVGL_TICK_PERIOD_MS 2 // TODO: Setting it to 5 causes a crash - why? -#define LVGL_MAX_SLEEP 500 - -#define WAVESHARE_TOUCH_I2C_PORT I2C_NUM_0 diff --git a/Boards/WaveshareS3Touch/display.cpp b/Boards/WaveshareS3Touch/display.cpp deleted file mode 100644 index 91d84903..00000000 --- a/Boards/WaveshareS3Touch/display.cpp +++ /dev/null @@ -1,206 +0,0 @@ -#include "config.h" - -#include "lvgl.h" -#include "TactilityCore.h" -#include "Thread.h" - -#include "esp_err.h" -#include "esp_lcd_panel_ops.h" -#include -#include -#include -#include "RtosCompatSemaphore.h" - -#define TAG "waveshare_s3_touch_display" - -SemaphoreHandle_t sem_vsync_end = nullptr; -SemaphoreHandle_t sem_gui_ready = nullptr; -SemaphoreHandle_t lvgl_mux = nullptr; - -#if WAVESHARE_LCD_USE_DOUBLE_FB -#define WAVESHARE_LCD_NUM_FB 2 -#else -#define WAVESHARE_LCD_NUM_FB 1 -#endif - -static bool lvgl_is_running = false; - -bool ws3t_display_lock(uint32_t timeout_ms) { - assert(lvgl_mux && "lvgl_port_init must be called first"); - const TickType_t timeout_ticks = (timeout_ms == 0) ? tt::TtWaitForever : pdMS_TO_TICKS(timeout_ms); - return xSemaphoreTakeRecursive(lvgl_mux, timeout_ticks) == pdTRUE; -} - -void ws3t_display_unlock(void) { - assert(lvgl_mux && "lvgl_port_init must be called first"); - xSemaphoreGiveRecursive(lvgl_mux); -} - -// Display_task should have lower priority than lvgl_tick_task below -static int32_t display_task(TT_UNUSED void* parameter) { - uint32_t task_delay_ms = LVGL_MAX_SLEEP; - - ESP_LOGI(TAG, "Starting LVGL task"); - lvgl_is_running = true; - while (lvgl_is_running) { - if (ws3t_display_lock(0)) { - task_delay_ms = lv_timer_handler(); - ws3t_display_unlock(); - } - if ((task_delay_ms > LVGL_MAX_SLEEP) || (1 == task_delay_ms)) { - task_delay_ms = LVGL_MAX_SLEEP; - } else if (task_delay_ms < 1) { - task_delay_ms = 1; - } - vTaskDelay(pdMS_TO_TICKS(task_delay_ms)); - } - - vTaskDelete(nullptr); - return 0; -} - -static bool on_vsync_event( - TT_UNUSED esp_lcd_panel_handle_t panel, - TT_UNUSED const esp_lcd_rgb_panel_event_data_t* event_data, - TT_UNUSED void* user_data -) { - BaseType_t high_task_awoken = pdFALSE; - - if (xSemaphoreTakeFromISR(sem_gui_ready, &high_task_awoken) == pdTRUE) { - xSemaphoreGiveFromISR(sem_vsync_end, &high_task_awoken); - } - - return high_task_awoken == pdTRUE; -} - -static void lvgl_tick_task(TT_UNUSED void* arg) { - // Tell how much time has passed - lv_tick_inc(WAVESHARE_LVGL_TICK_PERIOD_MS); -} - -static void display_flush_callback(lv_display_t* disp, const lv_area_t* area, uint8_t* px_map) { - auto panel_handle = static_cast(lv_display_get_user_data(disp)); - int offsetx1 = area->x1; - int offsetx2 = area->x2; - int offsety1 = area->y1; - int offsety2 = area->y2; - xSemaphoreGive(sem_gui_ready); - xSemaphoreTake(sem_vsync_end, portMAX_DELAY); - // pass the draw buffer to the driver - esp_lcd_panel_draw_bitmap(panel_handle, offsetx1, offsety1, offsetx2 + 1, offsety2 + 1, px_map); - lv_disp_flush_ready(disp); -} - -lv_disp_t* ws3t_display_create() { - TT_LOG_I(TAG, "display init"); - - sem_vsync_end = xSemaphoreCreateBinary(); - tt_assert(sem_vsync_end); - sem_gui_ready = xSemaphoreCreateBinary(); - tt_assert(sem_gui_ready); - - lvgl_mux = xSemaphoreCreateRecursiveMutex(); - tt_assert(lvgl_mux); - - tt::Thread* thread = new tt::Thread("display_task", 8192, &display_task, nullptr); - thread->setPriority(tt::Thread::PriorityHigh); // TODO: try out THREAD_PRIORITY_RENDER - thread->start(); - - esp_lcd_panel_handle_t panel_handle = NULL; - esp_lcd_rgb_panel_config_t panel_config = { - .clk_src = LCD_CLK_SRC_DEFAULT, - .timings = { - .pclk_hz = WAVESHARE_LCD_PIXEL_CLOCK_HZ, - .h_res = WAVESHARE_LCD_HOR_RES, - .v_res = WAVESHARE_LCD_VER_RES, - .hsync_pulse_width = 10, - // The following parameters should refer to LCD spec - .hsync_back_porch = 10, - .hsync_front_porch = 20, - .vsync_pulse_width = 10, - .vsync_back_porch = 10, - .vsync_front_porch = 10, - }, - .data_width = 16, // RGB565 in parallel mode, thus 16bit in width - .bits_per_pixel = 16, - .num_fbs = WAVESHARE_LCD_NUM_FB, - .bounce_buffer_size_px = 0, - .sram_trans_align = 0, - .psram_trans_align = 64, - .hsync_gpio_num = WAVESHARE_LCD_PIN_NUM_HSYNC, - .vsync_gpio_num = WAVESHARE_LCD_PIN_NUM_VSYNC, - .de_gpio_num = WAVESHARE_LCD_PIN_NUM_DE, - .pclk_gpio_num = WAVESHARE_LCD_PIN_NUM_PCLK, - .disp_gpio_num = WAVESHARE_LCD_PIN_NUM_DISP_EN, - .data_gpio_nums = {WAVESHARE_LCD_PIN_NUM_DATA0, WAVESHARE_LCD_PIN_NUM_DATA1, WAVESHARE_LCD_PIN_NUM_DATA2, WAVESHARE_LCD_PIN_NUM_DATA3, WAVESHARE_LCD_PIN_NUM_DATA4, WAVESHARE_LCD_PIN_NUM_DATA5, WAVESHARE_LCD_PIN_NUM_DATA6, WAVESHARE_LCD_PIN_NUM_DATA7, WAVESHARE_LCD_PIN_NUM_DATA8, WAVESHARE_LCD_PIN_NUM_DATA9, WAVESHARE_LCD_PIN_NUM_DATA10, WAVESHARE_LCD_PIN_NUM_DATA11, WAVESHARE_LCD_PIN_NUM_DATA12, WAVESHARE_LCD_PIN_NUM_DATA13, WAVESHARE_LCD_PIN_NUM_DATA14, WAVESHARE_LCD_PIN_NUM_DATA15}, - .flags = {.disp_active_low = false, .refresh_on_demand = false, .fb_in_psram = true, .double_fb = WAVESHARE_LCD_USE_DOUBLE_FB, .no_fb = false, .bb_invalidate_cache = false} - }; - - if (esp_lcd_new_rgb_panel(&panel_config, &panel_handle) != ESP_OK) { - TT_LOG_E(TAG, "Failed to create RGB panel"); - return nullptr; - } - - esp_lcd_rgb_panel_event_callbacks_t cbs = { - .on_vsync = on_vsync_event, - .on_bounce_empty = nullptr, - .on_bounce_frame_finish = nullptr - }; - if (esp_lcd_rgb_panel_register_event_callbacks(panel_handle, &cbs, nullptr) != ESP_OK) { - TT_LOG_E(TAG, "Failed to register callbacks"); - return nullptr; - } - - if (esp_lcd_panel_reset(panel_handle) != ESP_OK) { - TT_LOG_E(TAG, "Failed to reset panel"); - return nullptr; - } - - if (esp_lcd_panel_init(panel_handle) != ESP_OK) { - TT_LOG_E(TAG, "Failed to init panel"); - return nullptr; - } - - lv_init(); - -#if WAVESHARE_LCD_USE_DOUBLE_FB - // initialize LVGL draw buffers - lv_draw_buf_t* buffer1 = lv_draw_buf_create(WAVESHARE_LCD_HOR_RES, WAVESHARE_LCD_BUFFER_HEIGHT, LV_COLOR_FORMAT_RGB565, 0); - lv_draw_buf_t* buffer2 = lv_draw_buf_create(WAVESHARE_LCD_HOR_RES, WAVESHARE_LCD_BUFFER_HEIGHT, LV_COLOR_FORMAT_RGB565, 0); - tt_assert(buffer1); - tt_assert(buffer2); -#else - lv_draw_buf_t* buffer1 = lv_draw_buf_create(WAVESHARE_LCD_HOR_RES, WAVESHARE_LCD_VER_RES, LV_COLOR_FORMAT_RGB565, 0); - lv_draw_buf_t* buffer2 = NULL; - tt_assert(buffer1); -#endif // WAVESHARE_USE_DOUBLE_FB - - lv_display_t* display = lv_display_create(WAVESHARE_LCD_HOR_RES, WAVESHARE_LCD_VER_RES); - lv_display_set_draw_buffers(display, buffer1, buffer2); - lv_display_set_flush_cb(display, &display_flush_callback); - lv_display_set_user_data(display, panel_handle); - lv_display_set_antialiasing(display, false); - lv_display_set_render_mode(display, LV_DISPLAY_RENDER_MODE_PARTIAL); - - const esp_timer_create_args_t lvgl_tick_timer_args = { - .callback = &lvgl_tick_task, - .name = "lvgl_tick" - }; - esp_timer_handle_t lvgl_tick_timer = nullptr; - ESP_ERROR_CHECK(esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer)); - ESP_ERROR_CHECK(esp_timer_start_periodic(lvgl_tick_timer, WAVESHARE_LVGL_TICK_PERIOD_MS * 1000)); - - return display; -} - -void ws3t_display_destroy() { - // TODO: de-init display, its buffer and touch, stop display tasks, stop timer - // TODO: see esp_lvlg_port.c for more info - if (lvgl_mux) { - vSemaphoreDelete(lvgl_mux); - lvgl_mux = nullptr; - } -#if LV_ENABLE_GC || !LV_MEM_CUSTOM - lv_deinit(); -#endif -} diff --git a/Boards/WaveshareS3Touch/display_i.h b/Boards/WaveshareS3Touch/display_i.h deleted file mode 100644 index 595b0bad..00000000 --- a/Boards/WaveshareS3Touch/display_i.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include "lvgl.h" -#include - -bool ws3t_display_lock(uint32_t timeout_ms); -void ws3t_display_unlock(void); - -lv_display_t* ws3t_display_create(); -void ws3t_display_destroy(); \ No newline at end of file diff --git a/Boards/WaveshareS3Touch/lvgl.cpp b/Boards/WaveshareS3Touch/lvgl.cpp deleted file mode 100644 index 04d44673..00000000 --- a/Boards/WaveshareS3Touch/lvgl.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "lvgl_i.h" - -#include "display_i.h" -#include "touch_i.h" -#include "lvgl/LvglSync.h" - -bool ws3t_init_lvgl() { - tt::lvgl::syncSet(&ws3t_display_lock, &ws3t_display_unlock); - - lv_display_t* display = ws3t_display_create(); - if (display == nullptr) { - return false; - } - - ws3t_touch_init(display); - - return true; -} diff --git a/Boards/WaveshareS3Touch/lvgl_i.h b/Boards/WaveshareS3Touch/lvgl_i.h deleted file mode 100644 index 479ffe27..00000000 --- a/Boards/WaveshareS3Touch/lvgl_i.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -bool ws3t_init_lvgl(); \ No newline at end of file diff --git a/Boards/WaveshareS3Touch/touch.cpp b/Boards/WaveshareS3Touch/touch.cpp deleted file mode 100644 index 78e8a285..00000000 --- a/Boards/WaveshareS3Touch/touch.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include "config.h" - -#include "driver/i2c.h" -#include "esp_err.h" -#include "esp_lcd_touch_gt911.h" -#include "esp_log.h" -#include "lvgl.h" - -#define TAG "waveshare_s3_touch_i2c" - -static esp_lcd_touch_handle_t touch_init_internal() { - static esp_lcd_panel_io_handle_t tp_io_handle = nullptr; - static esp_lcd_panel_io_i2c_config_t tp_io_config = ESP_LCD_TOUCH_IO_I2C_GT911_CONFIG(); - ESP_LOGI(TAG, "Initialize touch IO"); - - // TODO: Revert on new ESP-IDF version - static_assert(ESP_IDF_VERSION == ESP_IDF_VERSION_VAL(5, 3, 1)); - // ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t)WAVESHARE_TOUCH_I2C_PORT, &tp_io_config, &tp_io_handle)); - esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t)WAVESHARE_TOUCH_I2C_PORT, &tp_io_config, &tp_io_handle); - - esp_lcd_touch_config_t tp_cfg = { - .x_max = WAVESHARE_LCD_VER_RES, - .y_max = WAVESHARE_LCD_HOR_RES, - .rst_gpio_num = GPIO_NUM_NC, - .int_gpio_num = GPIO_NUM_NC, - .flags = { - .swap_xy = 0, - .mirror_x = 0, - .mirror_y = 0, - }, - }; - /* Initialize touch */ - ESP_LOGI(TAG, "Initialize touch controller GT911"); - esp_lcd_touch_handle_t tp = nullptr; - ESP_ERROR_CHECK(esp_lcd_touch_new_i2c_gt911(tp_io_handle, &tp_cfg, &tp)); - - return tp; -} - -static void touch_callback(lv_indev_t* indev, lv_indev_data_t* data) { - uint16_t touchpad_x[1] = {0}; - uint16_t touchpad_y[1] = {0}; - uint8_t touchpad_cnt = 0; - - /* Read touch controller data */ - auto touch_handle = static_cast(lv_indev_get_user_data(indev)); - esp_lcd_touch_read_data(touch_handle); - - /* Get coordinates */ - bool touchpad_pressed = esp_lcd_touch_get_coordinates(touch_handle, touchpad_x, touchpad_y, nullptr, &touchpad_cnt, 1); - - if (touchpad_pressed && touchpad_cnt > 0) { - data->point.x = touchpad_x[0]; - data->point.y = touchpad_y[0]; - data->state = LV_INDEV_STATE_PR; - } else { - data->state = LV_INDEV_STATE_REL; - } -} - -void ws3t_touch_init(lv_display_t* display) { - esp_lcd_touch_handle_t touch_handle = touch_init_internal(); - - ESP_LOGI(TAG, "Register display indev to LVGL"); - - static lv_indev_t* device = nullptr; - device = lv_indev_create(); - lv_indev_set_type(device, LV_INDEV_TYPE_POINTER); - lv_indev_set_read_cb(device, &touch_callback); - lv_indev_set_display(device, display); - lv_indev_set_user_data(device, touch_handle); -} diff --git a/Boards/WaveshareS3Touch/touch_i.h b/Boards/WaveshareS3Touch/touch_i.h deleted file mode 100644 index b51cb935..00000000 --- a/Boards/WaveshareS3Touch/touch_i.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -#include "lvgl.h" - -void ws3t_touch_init(lv_display_t* display); \ No newline at end of file diff --git a/Boards/WaveshareS3Touch/waveshare_s3_touch.cpp b/Boards/WaveshareS3Touch/waveshare_s3_touch.cpp deleted file mode 100644 index e51a9bd9..00000000 --- a/Boards/WaveshareS3Touch/waveshare_s3_touch.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "waveshare_s3_touch.h" - -#include "lvgl_i.h" - -bool ws3t_bootstrap(); - -extern const tt::hal::Configuration waveshare_s3_touch = { - .initPower = &ws3t_bootstrap, - .initLvgl = &ws3t_init_lvgl, - .display = { .setBacklightDuty = nullptr }, - .sdcard = nullptr, - .power = nullptr, - .i2c = { - tt::hal::i2c::Configuration { - .name = "First", - .port = I2C_NUM_0, - .initMode = tt::hal::i2c::InitDisabled, - .canReinit = true, - .hasMutableConfiguration = true, - .config = (i2c_config_t) { - .mode = I2C_MODE_MASTER, - .sda_io_num = GPIO_NUM_NC, - .scl_io_num = GPIO_NUM_NC, - .sda_pullup_en = true, - .scl_pullup_en = true, - .master = { - .clk_speed = 400000 - }, - .clk_flags = 0 - } - }, - tt::hal::i2c::Configuration { - .name = "Second", - .port = I2C_NUM_1, - .initMode = tt::hal::i2c::InitDisabled, - .canReinit = true, - .hasMutableConfiguration = true, - .config = (i2c_config_t) { - .mode = I2C_MODE_MASTER, - .sda_io_num = GPIO_NUM_NC, - .scl_io_num = GPIO_NUM_NC, - .sda_pullup_en = true, - .scl_pullup_en = true, - .master = { - .clk_speed = 400000 - }, - .clk_flags = 0 - } - } - } -}; diff --git a/Boards/WaveshareS3Touch/waveshare_s3_touch.h b/Boards/WaveshareS3Touch/waveshare_s3_touch.h deleted file mode 100644 index 068ce656..00000000 --- a/Boards/WaveshareS3Touch/waveshare_s3_touch.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -#include "hal/Configuration.h" - -// Waveshare S3 Touch LCD 4.3 -extern const tt::hal::Configuration waveshare_s3_touch; diff --git a/Boards/YellowBoard/CMakeLists.txt b/Boards/YellowBoard/CMakeLists.txt index 45cb70d8..20e8d511 100644 --- a/Boards/YellowBoard/CMakeLists.txt +++ b/Boards/YellowBoard/CMakeLists.txt @@ -1,5 +1,5 @@ idf_component_register( - SRC_DIRS "." - INCLUDE_DIRS "." + SRC_DIRS "Source" "Source/hal" + INCLUDE_DIRS "Source" REQUIRES Tactility esp_lvgl_port esp_lcd_touch_cst816s esp_lcd_ili9341 driver vfs fatfs ) diff --git a/Boards/YellowBoard/bootstrap.cpp b/Boards/YellowBoard/Source/Boot.cpp similarity index 87% rename from Boards/YellowBoard/bootstrap.cpp rename to Boards/YellowBoard/Source/Boot.cpp index edf34b8e..64907cf9 100644 --- a/Boards/YellowBoard/bootstrap.cpp +++ b/Boards/YellowBoard/Source/Boot.cpp @@ -1,6 +1,6 @@ -#include "config.h" +#include "Config.h" #include "TactilityCore.h" -#include "display_i.h" +#include "hal/YellowTouchConstants.h" #include #define TAG "twodotfour_bootstrap" @@ -66,7 +66,7 @@ static bool init_spi3() { return true; } -bool twodotfour_bootstrap() { +bool twodotfour_boot() { TT_LOG_I(TAG, "Init I2C"); if (!init_i2c()) { TT_LOG_E(TAG, "Init I2C failed"); @@ -85,12 +85,5 @@ bool twodotfour_bootstrap() { return false; } - // Don't turn the backlight on yet - Tactility init will take care of it - TT_LOG_I(TAG, "Init backlight"); - if (!twodotfour_backlight_init()) { - TT_LOG_E(TAG, "Init backlight failed"); - return false; - } - return true; } diff --git a/Boards/YellowBoard/config.h b/Boards/YellowBoard/Source/Config.h similarity index 58% rename from Boards/YellowBoard/config.h rename to Boards/YellowBoard/Source/Config.h index 098f7488..247d3f2f 100644 --- a/Boards/YellowBoard/config.h +++ b/Boards/YellowBoard/Source/Config.h @@ -3,6 +3,7 @@ #include "driver/spi_common.h" #include "driver/i2c.h" #include "driver/gpio.h" +#include "hal/YellowDisplayConstants.h" // SPI 2 - display #define TWODOTFOUR_SPI2_PIN_SCLK GPIO_NUM_14 @@ -15,20 +16,6 @@ #define TWODOTFOUR_SPI3_PIN_MISO GPIO_NUM_19 #define TWODOTFOUR_SPI3_TRANSACTION_LIMIT 8192 // TODO: Determine proper limit -// Display -#define TWODOTFOUR_LCD_SPI_HOST SPI2_HOST -#define TWODOTFOUR_LCD_HORIZONTAL_RESOLUTION 240 -#define TWODOTFOUR_LCD_VERTICAL_RESOLUTION 320 -#define TWODOTFOUR_LCD_BITS_PER_PIXEL 16 -#define TWODOTFOUR_LCD_DRAW_BUFFER_HEIGHT (TWODOTFOUR_LCD_VERTICAL_RESOLUTION / 10) -#define TWODOTFOUR_LCD_DRAW_BUFFER_SIZE (TWODOTFOUR_LCD_HORIZONTAL_RESOLUTION * TWODOTFOUR_LCD_DRAW_BUFFER_HEIGHT * (TWODOTFOUR_LCD_BITS_PER_PIXEL / 8)) -#define TWODOTFOUR_LCD_PIN_CS GPIO_NUM_15 -#define TWODOTFOUR_LCD_PIN_DC GPIO_NUM_2 -#define TWODOTFOUR_LCD_PIN_BACKLIGHT GPIO_NUM_27 - -// Touch -#define TWODOTFOUR_TOUCH_I2C_PORT I2C_NUM_0 - // SD Card #define TWODOTFOUR_SDCARD_SPI_HOST SPI3_HOST #define TWODOTFOUR_SDCARD_PIN_CS GPIO_NUM_5 diff --git a/Boards/YellowBoard/Source/Lvgl.cpp b/Boards/YellowBoard/Source/Lvgl.cpp new file mode 100644 index 00000000..1f3ff115 --- /dev/null +++ b/Boards/YellowBoard/Source/Lvgl.cpp @@ -0,0 +1,26 @@ +#include "esp_lvgl_port.h" +#include "Log.h" +#include "lvgl/LvglSync.h" +#include "Thread.h" + +#define TAG "twodotfour_lvgl" + +bool twodotfour_lvgl_init() { + const lvgl_port_cfg_t lvgl_cfg = { + .task_priority = tt::Thread::PriorityHigh, + .task_stack = 8096, + .task_affinity = -1, // core pinning + .task_max_sleep_ms = 500, + .timer_period_ms = 5 + }; + + if (lvgl_port_init(&lvgl_cfg) != ESP_OK) { + TT_LOG_E(TAG, "lvgl port init failed"); + return false; + } + + // Set syncing functions + tt::lvgl::syncSet(&lvgl_port_lock, &lvgl_port_unlock); + + return true; +} diff --git a/Boards/YellowBoard/sdcard.cpp b/Boards/YellowBoard/Source/Sdcard.cpp similarity index 99% rename from Boards/YellowBoard/sdcard.cpp rename to Boards/YellowBoard/Source/Sdcard.cpp index c529beb1..0208117c 100644 --- a/Boards/YellowBoard/sdcard.cpp +++ b/Boards/YellowBoard/Source/Sdcard.cpp @@ -1,7 +1,7 @@ #include "hal/sdcard/Sdcard.h" #include "Check.h" #include "Log.h" -#include "config.h" +#include "Config.h" #include "esp_vfs_fat.h" #include "sdmmc_cmd.h" diff --git a/Boards/YellowBoard/yellow_board.cpp b/Boards/YellowBoard/Source/YellowBoard.cpp similarity index 88% rename from Boards/YellowBoard/yellow_board.cpp rename to Boards/YellowBoard/Source/YellowBoard.cpp index fe4863df..d8775894 100644 --- a/Boards/YellowBoard/yellow_board.cpp +++ b/Boards/YellowBoard/Source/YellowBoard.cpp @@ -1,17 +1,15 @@ -#include "yellow_board.h" -#include "display_i.h" +#include "YellowBoard.h" +#include "hal/YellowDisplay.h" bool twodotfour_lvgl_init(); -bool twodotfour_bootstrap(); +bool twodotfour_boot(); extern const tt::hal::sdcard::SdCard twodotfour_sdcard; const tt::hal::Configuration yellow_board_24inch_cap = { - .initPower = &twodotfour_bootstrap, + .initBoot = &twodotfour_boot, .initLvgl = &twodotfour_lvgl_init, - .display = { - .setBacklightDuty = &twodotfour_backlight_set - }, + .createDisplay = createDisplay, .sdcard = &twodotfour_sdcard, .power = nullptr, .i2c = { diff --git a/Boards/YellowBoard/yellow_board.h b/Boards/YellowBoard/Source/YellowBoard.h similarity index 100% rename from Boards/YellowBoard/yellow_board.h rename to Boards/YellowBoard/Source/YellowBoard.h diff --git a/Boards/YellowBoard/display.cpp b/Boards/YellowBoard/Source/hal/YellowDisplay.cpp similarity index 52% rename from Boards/YellowBoard/display.cpp rename to Boards/YellowBoard/Source/hal/YellowDisplay.cpp index 24ab262b..a93d97f3 100644 --- a/Boards/YellowBoard/display.cpp +++ b/Boards/YellowBoard/Source/hal/YellowDisplay.cpp @@ -1,24 +1,22 @@ -#include "config.h" -#include "TactilityCore.h" +#include "YellowDisplay.h" +#include "YellowDisplayConstants.h" +#include "YellowTouch.h" +#include "Log.h" + +#include #include "driver/gpio.h" #include "driver/ledc.h" #include "esp_err.h" #include "esp_lcd_ili9341.h" -#include "esp_lcd_panel_io.h" #include "esp_lcd_panel_ops.h" #include "esp_lvgl_port.h" -#define TAG "twodotfour_ili9341" +#define TAG "yellow_display" -// Dipslay backlight (PWM) -#define TWODOTFOUR_LCD_BACKLIGHT_LEDC_TIMER LEDC_TIMER_0 -#define TWODOTFOUR_LCD_BACKLIGHT_LEDC_MODE LEDC_LOW_SPEED_MODE -#define TWODOTFOUR_LCD_BACKLIGHT_LEDC_CHANNEL LEDC_CHANNEL_0 -#define TWODOTFOUR_LCD_BACKLIGHT_LEDC_DUTY_RES LEDC_TIMER_8_BIT -#define TWODOTFOUR_LCD_BACKLIGHT_LEDC_FREQUENCY (1000) +static bool isBacklightInitialized = false; -bool twodotfour_backlight_init() { +static bool initBacklight() { ledc_timer_config_t ledc_timer = { .speed_mode = TWODOTFOUR_LCD_BACKLIGHT_LEDC_MODE, .duty_resolution = TWODOTFOUR_LCD_BACKLIGHT_LEDC_DUTY_RES, @@ -35,7 +33,7 @@ bool twodotfour_backlight_init() { return true; } -void twodotfour_backlight_set(uint8_t duty) { +static bool setBacklight(uint8_t duty) { ledc_channel_config_t ledc_channel = { .gpio_num = TWODOTFOUR_LCD_PIN_BACKLIGHT, .speed_mode = TWODOTFOUR_LCD_BACKLIGHT_LEDC_MODE, @@ -43,18 +41,22 @@ void twodotfour_backlight_set(uint8_t duty) { .intr_type = LEDC_INTR_DISABLE, .timer_sel = TWODOTFOUR_LCD_BACKLIGHT_LEDC_TIMER, .duty = duty, - .hpoint = 0 + .hpoint = 0, + .flags = { + .output_invert = false + } }; - // Setting the config in the timer init and then calling ledc_set_duty() doesn't work when - // the app is running. For an unknown reason we have to call this config method every time: if (ledc_channel_config(&ledc_channel) != ESP_OK) { - TT_LOG_E(TAG, "Failed to configure display backlight"); + TT_LOG_E(TAG, "Backlight init failed"); + return false; } + + return true; } -lv_disp_t* twodotfour_display_init() { - TT_LOG_I(TAG, "Display init"); +bool YellowDisplay::start() { + TT_LOG_I(TAG, "Starting"); const esp_lcd_panel_io_spi_config_t panel_io_config = ILI9341_PANEL_IO_SPI_CONFIG( TWODOTFOUR_LCD_PIN_CS, @@ -63,47 +65,50 @@ lv_disp_t* twodotfour_display_init() { nullptr ); - esp_lcd_panel_io_handle_t io_handle; - if (esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)TWODOTFOUR_LCD_SPI_HOST, &panel_io_config, &io_handle) != ESP_OK) { + if (esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)TWODOTFOUR_LCD_SPI_HOST, &panel_io_config, &ioHandle) != ESP_OK) { TT_LOG_E(TAG, "Failed to create panel"); - return nullptr; + return false; } const esp_lcd_panel_dev_config_t panel_config = { .reset_gpio_num = GPIO_NUM_NC, .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_BGR, + .data_endian = LCD_RGB_DATA_ENDIAN_BIG, .bits_per_pixel = TWODOTFOUR_LCD_BITS_PER_PIXEL, + .flags = { + .reset_active_high = false + }, + .vendor_config = nullptr }; - esp_lcd_panel_handle_t panel_handle; - if (esp_lcd_new_panel_ili9341(io_handle, &panel_config, &panel_handle) != ESP_OK) { + if (esp_lcd_new_panel_ili9341(ioHandle, &panel_config, &panelHandle) != ESP_OK) { TT_LOG_E(TAG, "Failed to create ili9341"); - return nullptr; + return false; } - if (esp_lcd_panel_reset(panel_handle) != ESP_OK) { + if (esp_lcd_panel_reset(panelHandle) != ESP_OK) { TT_LOG_E(TAG, "Failed to reset panel"); - return nullptr; + return false; } - if (esp_lcd_panel_init(panel_handle) != ESP_OK) { + if (esp_lcd_panel_init(panelHandle) != ESP_OK) { TT_LOG_E(TAG, "Failed to init panel"); - return nullptr; + return false; } - if (esp_lcd_panel_mirror(panel_handle, true, false) != ESP_OK) { + if (esp_lcd_panel_mirror(panelHandle, true, false) != ESP_OK) { TT_LOG_E(TAG, "Failed to set panel to mirror"); - return nullptr; + return false; } - if (esp_lcd_panel_disp_on_off(panel_handle, true) != ESP_OK) { + if (esp_lcd_panel_disp_on_off(panelHandle, true) != ESP_OK) { TT_LOG_E(TAG, "Failed to turn display on"); - return nullptr; + return false; } const lvgl_port_display_cfg_t disp_cfg = { - .io_handle = io_handle, - .panel_handle = panel_handle, + .io_handle = ioHandle, + .panel_handle = panelHandle, .buffer_size = TWODOTFOUR_LCD_DRAW_BUFFER_SIZE, .double_buffer = false, .hres = TWODOTFOUR_LCD_HORIZONTAL_RESOLUTION, @@ -122,5 +127,45 @@ lv_disp_t* twodotfour_display_init() { } }; - return lvgl_port_add_disp(&disp_cfg); + displayHandle = lvgl_port_add_disp(&disp_cfg); + TT_LOG_I(TAG, "Finished"); + return displayHandle != nullptr; +} + +bool YellowDisplay::stop() { + tt_assert(displayHandle != nullptr); + + lvgl_port_remove_disp(displayHandle); + + if (esp_lcd_panel_del(panelHandle) != ESP_OK) { + return false; + } + + if (esp_lcd_panel_io_del(ioHandle) != ESP_OK) { + return false; + } + + displayHandle = nullptr; + return true; +} + +void YellowDisplay::setBacklightDuty(uint8_t backlightDuty) { + if (!isBacklightInitialized) { + tt_check(initBacklight()); + isBacklightInitialized = true; + } + + if (setBacklight(backlightDuty)) { + TT_LOG_I(TAG, "Backlight set: %d", backlightDuty); + lastBacklightDuty = backlightDuty; + } else { + TT_LOG_E(TAG, "Failed to configure display backlight"); + } +} +tt::hal::Touch* _Nullable YellowDisplay::createTouch() { + return static_cast(new YellowTouch()); +} + +tt::hal::Display* createDisplay() { + return static_cast(new YellowDisplay()); } diff --git a/Boards/YellowBoard/Source/hal/YellowDisplay.h b/Boards/YellowBoard/Source/hal/YellowDisplay.h new file mode 100644 index 00000000..2a9fa147 --- /dev/null +++ b/Boards/YellowBoard/Source/hal/YellowDisplay.h @@ -0,0 +1,37 @@ +#pragma once + +#include "lvgl.h" +#include "hal/Display.h" +#include "esp_lcd_panel_io.h" + +extern lv_disp_t* displayHandle; + +class YellowDisplay : public tt::hal::Display { + +private: + + esp_lcd_panel_io_handle_t ioHandle = nullptr; + esp_lcd_panel_handle_t panelHandle = nullptr; + lv_display_t* displayHandle = nullptr; + uint8_t lastBacklightDuty = 255; + +public: + + bool start() override; + + bool stop() override; + + void setPowerOn(bool turnOn) override {} + bool isPoweredOn() const override { return true; }; + bool supportsPowerControl() const override { return false; } + + tt::hal::Touch* _Nullable createTouch() override; + + void setBacklightDuty(uint8_t backlightDuty) override; + uint8_t getBacklightDuty() const override { return lastBacklightDuty; } + bool supportsBacklightDuty() const override { return true; } + + lv_display_t* _Nullable getLvglDisplay() const override { return displayHandle; } +}; + +tt::hal::Display* createDisplay(); diff --git a/Boards/YellowBoard/Source/hal/YellowDisplayConstants.h b/Boards/YellowBoard/Source/hal/YellowDisplayConstants.h new file mode 100644 index 00000000..30ab803d --- /dev/null +++ b/Boards/YellowBoard/Source/hal/YellowDisplayConstants.h @@ -0,0 +1,21 @@ +#pragma once + +// Dipslay backlight (PWM) +#define TWODOTFOUR_LCD_BACKLIGHT_LEDC_TIMER LEDC_TIMER_0 +#define TWODOTFOUR_LCD_BACKLIGHT_LEDC_MODE LEDC_LOW_SPEED_MODE +#define TWODOTFOUR_LCD_BACKLIGHT_LEDC_CHANNEL LEDC_CHANNEL_0 +#define TWODOTFOUR_LCD_BACKLIGHT_LEDC_DUTY_RES LEDC_TIMER_8_BIT +#define TWODOTFOUR_LCD_BACKLIGHT_LEDC_FREQUENCY (1000) + +#define TWODOTFOUR_LCD_PIN_BACKLIGHT GPIO_NUM_27 + +// Display +#define TWODOTFOUR_LCD_SPI_HOST SPI2_HOST +#define TWODOTFOUR_LCD_HORIZONTAL_RESOLUTION 240 +#define TWODOTFOUR_LCD_VERTICAL_RESOLUTION 320 +#define TWODOTFOUR_LCD_BITS_PER_PIXEL 16 +#define TWODOTFOUR_LCD_DRAW_BUFFER_HEIGHT (TWODOTFOUR_LCD_VERTICAL_RESOLUTION / 10) +#define TWODOTFOUR_LCD_DRAW_BUFFER_SIZE (TWODOTFOUR_LCD_HORIZONTAL_RESOLUTION * TWODOTFOUR_LCD_DRAW_BUFFER_HEIGHT * (TWODOTFOUR_LCD_BITS_PER_PIXEL / 8)) +#define TWODOTFOUR_LCD_PIN_CS GPIO_NUM_15 +#define TWODOTFOUR_LCD_PIN_DC GPIO_NUM_2 + diff --git a/Boards/YellowBoard/touch.cpp b/Boards/YellowBoard/Source/hal/YellowTouch.cpp similarity index 55% rename from Boards/YellowBoard/touch.cpp rename to Boards/YellowBoard/Source/hal/YellowTouch.cpp index 811880f2..dbedf25f 100644 --- a/Boards/YellowBoard/touch.cpp +++ b/Boards/YellowBoard/Source/hal/YellowTouch.cpp @@ -1,22 +1,26 @@ -#include "config.h" +#include "YellowTouch.h" +#include "YellowTouchConstants.h" +#include "Log.h" #include "driver/i2c.h" #include "esp_err.h" #include "esp_lcd_touch_cst816s.h" #include "esp_lcd_touch.h" -#include "Log.h" +#include "esp_lvgl_port.h" -#define TAG "twodotfour_cst816" +#define TAG "m5stack_touch" -bool twodotfour_touch_init(esp_lcd_panel_io_handle_t* io_handle, esp_lcd_touch_handle_t* touch_handle) { - TT_LOG_I(TAG, "Touch init"); +bool YellowTouch::start(lv_display_t* display) { + TT_LOG_I(TAG, "Starting"); + esp_lcd_panel_io_handle_t ioHandle; + esp_lcd_touch_handle_t touchHandle; const esp_lcd_panel_io_i2c_config_t touch_io_config = ESP_LCD_TOUCH_IO_I2C_CST816S_CONFIG(); // TODO: Check when ESP-IDF publishes fix (5.3.2 or 5.4.x) static_assert(ESP_IDF_VERSION == ESP_IDF_VERSION_VAL(5, 3, 1)); - esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t)TWODOTFOUR_TOUCH_I2C_PORT, &touch_io_config, io_handle); + esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t)TWODOTFOUR_TOUCH_I2C_PORT, &touch_io_config, &ioHandle); /* - if (esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t)TWODOTFOUR_TOUCH_I2C_PORT, &touch_io_config, io_handle) != ESP_OK) { + if (esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t)TWODOTFOUR_TOUCH_I2C_PORT, &touch_io_config, &ioHandle) != ESP_OK) { TT_LOG_E(TAG, "Touch I2C IO init failed"); return false; } @@ -41,10 +45,29 @@ bool twodotfour_touch_init(esp_lcd_panel_io_handle_t* io_handle, esp_lcd_touch_h .user_data = nullptr }; - if (esp_lcd_touch_new_i2c_cst816s(*io_handle, &config, touch_handle) != ESP_OK) { + if (esp_lcd_touch_new_i2c_cst816s(ioHandle, &config, &touchHandle) != ESP_OK) { TT_LOG_E(TAG, "Driver init failed"); return false; } + const lvgl_port_touch_cfg_t touch_cfg = { + .disp = display, + .handle = touchHandle, + }; + + deviceHandle = lvgl_port_add_touch(&touch_cfg); + if (deviceHandle == nullptr) { + TT_LOG_E(TAG, "Adding touch failed"); + return false; + } + + TT_LOG_I(TAG, "Finished"); + return true; +} + +bool YellowTouch::stop() { + tt_assert(deviceHandle != nullptr); + lv_indev_delete(deviceHandle); + deviceHandle = nullptr; return true; } diff --git a/Boards/YellowBoard/Source/hal/YellowTouch.h b/Boards/YellowBoard/Source/hal/YellowTouch.h new file mode 100644 index 00000000..9323caf5 --- /dev/null +++ b/Boards/YellowBoard/Source/hal/YellowTouch.h @@ -0,0 +1,13 @@ +#pragma once + +#include "hal/Touch.h" +#include "TactilityCore.h" + +class YellowTouch : public tt::hal::Touch { +private: + lv_indev_t* _Nullable deviceHandle = nullptr; +public: + bool start(lv_display_t* display) override; + bool stop() override; + lv_indev_t* _Nullable getLvglIndev() override { return deviceHandle; } +}; diff --git a/Boards/YellowBoard/Source/hal/YellowTouchConstants.h b/Boards/YellowBoard/Source/hal/YellowTouchConstants.h new file mode 100644 index 00000000..c2d9c540 --- /dev/null +++ b/Boards/YellowBoard/Source/hal/YellowTouchConstants.h @@ -0,0 +1,5 @@ +#pragma once + +// Touch +#define TWODOTFOUR_TOUCH_I2C_PORT I2C_NUM_0 + diff --git a/Boards/YellowBoard/display_i.h b/Boards/YellowBoard/display_i.h deleted file mode 100644 index 4c9bedfa..00000000 --- a/Boards/YellowBoard/display_i.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -#include - -bool twodotfour_backlight_init(); -void twodotfour_backlight_set(uint8_t duty); \ No newline at end of file diff --git a/Boards/YellowBoard/lvgl.cpp b/Boards/YellowBoard/lvgl.cpp deleted file mode 100644 index 6608cf58..00000000 --- a/Boards/YellowBoard/lvgl.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#include "esp_lvgl_port.h" -#include "Log.h" -#include "lvgl/LvglSync.h" -#include "Thread.h" - -#define TAG "twodotfour_lvgl" - -lv_display_t* twodotfour_display_init(); -bool twodotfour_touch_init(esp_lcd_panel_io_handle_t* io_handle, esp_lcd_touch_handle_t* touch_handle); - -bool twodotfour_lvgl_init() { - static lv_display_t* display = nullptr; - static esp_lcd_panel_io_handle_t touch_io_handle; - static esp_lcd_touch_handle_t touch_handle; - - const lvgl_port_cfg_t lvgl_cfg = { - .task_priority = tt::Thread::PriorityHigh, - .task_stack = 8096, - .task_affinity = -1, // core pinning - .task_max_sleep_ms = 500, - .timer_period_ms = 5 - }; - - if (lvgl_port_init(&lvgl_cfg) != ESP_OK) { - TT_LOG_E(TAG, "lvgl port init failed"); - return false; - } - - // Add display - display = twodotfour_display_init(); - if (display == nullptr) { - TT_LOG_E(TAG, "failed to add display"); - return false; - } - - // Add touch - if (!twodotfour_touch_init(&touch_io_handle, &touch_handle)) { - return false; - } - - const lvgl_port_touch_cfg_t touch_cfg = { - .disp = display, - .handle = touch_handle, - }; - - auto* touch_indev= lvgl_port_add_touch(&touch_cfg); - if (touch_indev == nullptr) { - TT_LOG_E(TAG, "failed to add touch to lvgl"); - return false; - } - - // Set syncing functions - tt::lvgl::syncSet(&lvgl_port_lock, &lvgl_port_unlock); - - return true; -} diff --git a/CMakeLists.txt b/CMakeLists.txt index 3bc95b58..6dac2e46 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,22 +28,22 @@ if (DEFINED ENV{ESP_IDF_VERSION}) "Libraries/M5GFX" ) + set(EXCLUDE_COMPONENTS "Simulator") + # ESP32 boards if(NOT "${IDF_TARGET}" STREQUAL "esp32") set(EXCLUDE_COMPONENTS "YellowBoard") set(EXCLUDE_COMPONENTS "M5stackCore2") - set(EXCLUDE_COMPONENTS "M5stackCoreS3") - endif() - - if(NOT "${IDF_TARGET}" STREQUAL "Simulator") - set(EXCLUDE_COMPONENTS "Simulator") endif() # ESP32-S3 boards if(NOT "${IDF_TARGET}" STREQUAL "esp32s3") set(EXCLUDE_COMPONENTS "LilygoTdeck") - set(EXCLUDE_COMPONENTS "WaveshareS3Touch") + set(EXCLUDE_COMPONENTS "M5stackCoreS3") endif() + + # TEMP - DO NOT COMMIT + set(EXCLUDE_COMPONENTS "YellowBoard" "M5stackCore2" "WaveshareS3Touch") else() message("Building for sim target") endif() diff --git a/Documentation/ideas.md b/Documentation/ideas.md index 2f8df48e..26595479 100644 --- a/Documentation/ideas.md +++ b/Documentation/ideas.md @@ -1,6 +1,8 @@ # TODOs +- Publish firmwares with upload tool +- Bug: When closing a top level app, there's often an error "can't stop root app" +- Bug: I2C Scanner is on M5Stack devices is broken - Create more unit tests for `tactility-core` and `tactility` (PC-only for now) -- Have a way to deinit LVGL drivers that are created from `HardwareConfig` - Show a warning screen if firmware encryption or secure boot are off when saving WiFi credentials. - Show a warning screen when a user plugs in the SD card on a device that only supports mounting at boot. - Try out Waveshare S3 120MHz mode for PSRAM (see "enabling 120M PSRAM is necessary" in [docs](https://www.waveshare.com/wiki/ESP32-S3-Touch-LCD-4.3#Other_Notes)) @@ -13,9 +15,9 @@ - Explore LVGL9's FreeRTOS functionality - Explore LVGL9's ILI93414 driver for 2.4" Yellow Board - Bug: in LVGL9 with M5Core2, crash when bottom item is clicked without scrolling first -- Publish firmwares with upload tool - De-duplicate WiFi SSIDs. - Replace M5Unified and M5GFX with custom drivers (so we can fix the Core2 SD card mounting bug, and so we regain some firmware space) +- Commit fix to esp_lvgl_port to have esp_lvgl_port_disp.c user driver_data instead of user_data # Core Ideas - Support for displays with different DPI. Consider the layer-based system like on Android. diff --git a/Libraries/esp_lvgl_port/src/lvgl9/esp_lvgl_port_button.c b/Libraries/esp_lvgl_port/src/lvgl9/esp_lvgl_port_button.c index 4527eff7..79b0ac01 100644 --- a/Libraries/esp_lvgl_port/src/lvgl9/esp_lvgl_port_button.c +++ b/Libraries/esp_lvgl_port/src/lvgl9/esp_lvgl_port_button.c @@ -90,7 +90,7 @@ lv_indev_t *lvgl_port_add_navigation_buttons(const lvgl_port_nav_btns_cfg_t *but lv_indev_set_type(indev, LV_INDEV_TYPE_ENCODER); lv_indev_set_read_cb(indev, lvgl_port_navigation_buttons_read); lv_indev_set_disp(indev, buttons_cfg->disp); - lv_indev_set_user_data(indev, buttons_ctx); + lv_indev_set_driver_data(indev, buttons_ctx); //buttons_ctx->indev->long_press_repeat_time = 300; buttons_ctx->indev = indev; lvgl_port_unlock(); @@ -116,7 +116,7 @@ err: esp_err_t lvgl_port_remove_navigation_buttons(lv_indev_t *buttons) { assert(buttons); - lvgl_port_nav_btns_ctx_t *buttons_ctx = (lvgl_port_nav_btns_ctx_t *)lv_indev_get_user_data(buttons); + lvgl_port_nav_btns_ctx_t *buttons_ctx = (lvgl_port_nav_btns_ctx_t *)lv_indev_get_driver_data(buttons); lvgl_port_lock(0); /* Remove input device driver */ @@ -140,7 +140,7 @@ static void lvgl_port_navigation_buttons_read(lv_indev_t *indev_drv, lv_indev_da static uint32_t last_key = 0; assert(indev_drv); - lvgl_port_nav_btns_ctx_t *ctx = (lvgl_port_nav_btns_ctx_t *)lv_indev_get_user_data(indev_drv); + lvgl_port_nav_btns_ctx_t *ctx = (lvgl_port_nav_btns_ctx_t *)lv_indev_get_driver_data(indev_drv); assert(ctx); /* Buttons */ diff --git a/Libraries/esp_lvgl_port/src/lvgl9/esp_lvgl_port_disp.c b/Libraries/esp_lvgl_port/src/lvgl9/esp_lvgl_port_disp.c index 4a51d864..c80a5554 100644 --- a/Libraries/esp_lvgl_port/src/lvgl9/esp_lvgl_port_disp.c +++ b/Libraries/esp_lvgl_port/src/lvgl9/esp_lvgl_port_disp.c @@ -114,7 +114,7 @@ lv_display_t *lvgl_port_add_disp(const lvgl_port_display_cfg_t *disp_cfg) lv_display_set_flush_cb(disp, lvgl_port_flush_callback); lv_display_add_event_cb(disp, lvgl_port_disp_size_update_callback, LV_EVENT_RESOLUTION_CHANGED, disp_ctx); - lv_display_set_user_data(disp, disp_ctx); + lv_display_set_driver_data(disp, disp_ctx); disp_ctx->disp_drv = disp; #if LVGL_PORT_HANDLE_FLUSH_READY @@ -146,7 +146,7 @@ err: esp_err_t lvgl_port_remove_disp(lv_display_t *disp) { assert(disp); - lvgl_port_display_ctx_t *disp_ctx = (lvgl_port_display_ctx_t *)lv_display_get_user_data(disp); + lvgl_port_display_ctx_t *disp_ctx = (lvgl_port_display_ctx_t *)lv_display_get_driver_data(disp); lvgl_port_lock(0); lv_disp_remove(disp); @@ -229,7 +229,7 @@ static void _lvgl_port_transform_monochrome(lv_display_t *display, const lv_area static void lvgl_port_flush_callback(lv_display_t *drv, const lv_area_t *area, uint8_t *color_map) { assert(drv != NULL); - lvgl_port_display_ctx_t *disp_ctx = (lvgl_port_display_ctx_t *)lv_display_get_user_data(drv); + lvgl_port_display_ctx_t *disp_ctx = (lvgl_port_display_ctx_t *)lv_display_get_driver_data(drv); assert(disp_ctx != NULL); //TODO: try to use SPI_SWAP_DATA_RX from https://docs.espressif.com/projects/esp-idf/en/v5.1/esp32s3/api-reference/peripherals/spi_master.html#c.SPI_SWAP_DATA_TX diff --git a/Libraries/esp_lvgl_port/src/lvgl9/esp_lvgl_port_knob.c b/Libraries/esp_lvgl_port/src/lvgl9/esp_lvgl_port_knob.c index 03efe4c1..782d0a6f 100644 --- a/Libraries/esp_lvgl_port/src/lvgl9/esp_lvgl_port_knob.c +++ b/Libraries/esp_lvgl_port/src/lvgl9/esp_lvgl_port_knob.c @@ -71,7 +71,7 @@ lv_indev_t *lvgl_port_add_encoder(const lvgl_port_encoder_cfg_t *encoder_cfg) lv_indev_set_type(indev, LV_INDEV_TYPE_ENCODER); lv_indev_set_read_cb(indev, lvgl_port_encoder_read); lv_indev_set_disp(indev, encoder_cfg->disp); - lv_indev_set_user_data(indev, encoder_ctx); + lv_indev_set_driver_data(indev, encoder_ctx); encoder_ctx->indev = indev; lvgl_port_unlock(); @@ -95,7 +95,7 @@ err: esp_err_t lvgl_port_remove_encoder(lv_indev_t *encoder) { assert(encoder); - lvgl_port_encoder_ctx_t *encoder_ctx = (lvgl_port_encoder_ctx_t *)lv_indev_get_user_data(encoder); + lvgl_port_encoder_ctx_t *encoder_ctx = (lvgl_port_encoder_ctx_t *)lv_indev_get_driver_data(encoder); if (encoder_ctx->knob_handle != NULL) { iot_knob_delete(encoder_ctx->knob_handle); @@ -125,7 +125,7 @@ static void lvgl_port_encoder_read(lv_indev_t *indev_drv, lv_indev_data_t *data) { static int32_t last_v = 0; assert(indev_drv); - lvgl_port_encoder_ctx_t *ctx = (lvgl_port_encoder_ctx_t *)lv_indev_get_user_data(indev_drv); + lvgl_port_encoder_ctx_t *ctx = (lvgl_port_encoder_ctx_t *)lv_indev_get_driver_data(indev_drv); assert(ctx); int32_t invd = iot_knob_get_count_value(ctx->knob_handle); diff --git a/Libraries/esp_lvgl_port/src/lvgl9/esp_lvgl_port_touch.c b/Libraries/esp_lvgl_port/src/lvgl9/esp_lvgl_port_touch.c index 6aac2fb6..2e8684a2 100644 --- a/Libraries/esp_lvgl_port/src/lvgl9/esp_lvgl_port_touch.c +++ b/Libraries/esp_lvgl_port/src/lvgl9/esp_lvgl_port_touch.c @@ -52,7 +52,7 @@ lv_indev_t *lvgl_port_add_touch(const lvgl_port_touch_cfg_t *touch_cfg) lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER); lv_indev_set_read_cb(indev, lvgl_port_touchpad_read); lv_indev_set_disp(indev, touch_cfg->disp); - lv_indev_set_user_data(indev, touch_ctx); + lv_indev_set_driver_data(indev, touch_ctx); touch_ctx->indev = indev; lvgl_port_unlock(); @@ -62,7 +62,7 @@ lv_indev_t *lvgl_port_add_touch(const lvgl_port_touch_cfg_t *touch_cfg) esp_err_t lvgl_port_remove_touch(lv_indev_t *touch) { assert(touch); - lvgl_port_touch_ctx_t *touch_ctx = (lvgl_port_touch_ctx_t *)lv_indev_get_user_data(touch); + lvgl_port_touch_ctx_t *touch_ctx = (lvgl_port_touch_ctx_t *)lv_indev_get_driver_data(touch); lvgl_port_lock(0); /* Remove input device driver */ @@ -83,7 +83,7 @@ esp_err_t lvgl_port_remove_touch(lv_indev_t *touch) static void lvgl_port_touchpad_read(lv_indev_t *indev_drv, lv_indev_data_t *data) { assert(indev_drv); - lvgl_port_touch_ctx_t *touch_ctx = (lvgl_port_touch_ctx_t *)lv_indev_get_user_data(indev_drv); + lvgl_port_touch_ctx_t *touch_ctx = (lvgl_port_touch_ctx_t *)lv_indev_get_driver_data(indev_drv); assert(touch_ctx); assert(touch_ctx->handle); diff --git a/Libraries/esp_lvgl_port/src/lvgl9/esp_lvgl_port_usbhid.c b/Libraries/esp_lvgl_port/src/lvgl9/esp_lvgl_port_usbhid.c index 947142f1..1a1acc62 100644 --- a/Libraries/esp_lvgl_port/src/lvgl9/esp_lvgl_port_usbhid.c +++ b/Libraries/esp_lvgl_port/src/lvgl9/esp_lvgl_port_usbhid.c @@ -93,7 +93,7 @@ lv_indev_t *lvgl_port_add_usb_hid_mouse_input(const lvgl_port_hid_mouse_cfg_t *m lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER); lv_indev_set_read_cb(indev, lvgl_port_usb_hid_read_mouse); lv_indev_set_disp(indev, mouse_cfg->disp); - lv_indev_set_user_data(indev, hid_ctx); + lv_indev_set_driver_data(indev, hid_ctx); hid_ctx->mouse.indev = indev; lvgl_port_unlock(); @@ -126,7 +126,7 @@ lv_indev_t *lvgl_port_add_usb_hid_keyboard_input(const lvgl_port_hid_keyboard_cf lv_indev_set_type(indev, LV_INDEV_TYPE_KEYPAD); lv_indev_set_read_cb(indev, lvgl_port_usb_hid_read_kb); lv_indev_set_disp(indev, keyboard_cfg->disp); - lv_indev_set_user_data(indev, hid_ctx); + lv_indev_set_driver_data(indev, hid_ctx); hid_ctx->kb.indev = indev; lvgl_port_unlock(); @@ -136,7 +136,7 @@ lv_indev_t *lvgl_port_add_usb_hid_keyboard_input(const lvgl_port_hid_keyboard_cf esp_err_t lvgl_port_remove_usb_hid_input(lv_indev_t *hid) { assert(hid); - lvgl_port_usb_hid_ctx_t *hid_ctx = (lvgl_port_usb_hid_ctx_t *)lv_indev_get_user_data(hid); + lvgl_port_usb_hid_ctx_t *hid_ctx = (lvgl_port_usb_hid_ctx_t *)lv_indev_get_driver_data(hid); lvgl_port_lock(0); /* Remove input device driver */ @@ -397,7 +397,7 @@ static void lvgl_port_usb_hid_read_mouse(lv_indev_t *indev_drv, lv_indev_data_t int16_t width = 0; int16_t height = 0; assert(indev_drv); - lvgl_port_usb_hid_ctx_t *ctx = (lvgl_port_usb_hid_ctx_t *)lv_indev_get_user_data(indev_drv); + lvgl_port_usb_hid_ctx_t *ctx = (lvgl_port_usb_hid_ctx_t *)lv_indev_get_driver_data(indev_drv); assert(ctx); lv_display_t *disp = lv_indev_get_display(indev_drv); @@ -452,7 +452,7 @@ static void lvgl_port_usb_hid_read_mouse(lv_indev_t *indev_drv, lv_indev_data_t static void lvgl_port_usb_hid_read_kb(lv_indev_t *indev_drv, lv_indev_data_t *data) { assert(indev_drv); - lvgl_port_usb_hid_ctx_t *ctx = (lvgl_port_usb_hid_ctx_t *)lv_indev_get_user_data(indev_drv); + lvgl_port_usb_hid_ctx_t *ctx = (lvgl_port_usb_hid_ctx_t *)lv_indev_get_driver_data(indev_drv); assert(ctx); data->key = ctx->kb.last_key; diff --git a/README.md b/README.md index 2192b196..652a334c 100644 --- a/README.md +++ b/README.md @@ -71,13 +71,13 @@ Implementing drivers can take some effort, so Tactility provides support for sev Predefined configurations are available for: -| Device | Screen&Touch | SD card | Power | Other | -|------------------------------------------|--------------|---------|-------|----------| -| [M5Stack Core2][m5stack] | ✅ | ✅ | ✅ | | -| [M5Stack CoreS3][m5stack] | ✅ | ✅ | ✅ | | -| [LilyGo T-Deck][tdeck] | ✅ | ✅ | | Keyboard | -| [Waveshare S3 Touch][waveshare_s3_touch] | ✅ | ⏳ | | | -| Yellow Board 2432S024C (\*) | ✅ | ✅ | | | +| Device | Screen&Touch | SD card | Power | Other | +|---------------------------------|--------------|---------|-------|----------| +| [LilyGo T-Deck Plus][tdeckplus] | ✅ | ✅ | ⏳ | Keyboard | +| [LilyGo T-Deck][tdeck] | ✅ | ✅ | | Keyboard | +| [M5Stack Core2][m5stack] | ✅ | ✅ | ✅ | | +| [M5Stack CoreS3][m5stack] | ✅ | ✅ | ✅ | | +| Yellow Board 2432S024C (\*) | ✅ | ✅ | | | - ✅: Capable and implemented - ⏳: Capable but not yet implemented @@ -86,7 +86,7 @@ Predefined configurations are available for: (*) Note: Only the capacitive version is supported. See AliExpress [here][2432s024c_1] and [here][2432s024c_2]. [tdeck]: https://www.lilygo.cc/products/t-deck -[waveshare_s3_touch]: https://www.waveshare.com/wiki/ESP32-S3-Touch-LCD-4.3 +[tdeckplus]: https://lilygo.cc/products/t-deck-plus [2432s024c_1]: https://www.aliexpress.com/item/1005005902429049.html [2432s024c_2]: https://www.aliexpress.com/item/1005005865107357.html [m5stack]: https://m5stack.com/ diff --git a/Tactility/Private/lvgl/Init_i.h b/Tactility/Private/lvgl/Init_i.h index bd412b5c..2fe1be24 100644 --- a/Tactility/Private/lvgl/Init_i.h +++ b/Tactility/Private/lvgl/Init_i.h @@ -4,6 +4,6 @@ namespace tt::lvgl { -void init(const hal::Configuration* config); +void init(const hal::Configuration& config); } // namespace diff --git a/Tactility/Source/Tactility.cpp b/Tactility/Source/Tactility.cpp index 58fcd095..3ca91f4d 100644 --- a/Tactility/Source/Tactility.cpp +++ b/Tactility/Source/Tactility.cpp @@ -125,15 +125,18 @@ static void register_and_start_user_services(const service::Manifest* const serv } } -void init(const Configuration* config) { +void init(const Configuration& config) { TT_LOG_I(TAG, "init started"); + tt_assert(config.hardware); + const hal::Configuration& hardware = *config.hardware; + // Assign early so starting services can use it - config_instance = config; + config_instance = &config; - initHeadless(*config->hardware); + initHeadless(hardware); - lvgl::init(config->hardware); + lvgl::init(hardware); // Note: the order of starting apps and services is critical! // System services are registered first so the apps below can find them if needed @@ -142,16 +145,16 @@ void init(const Configuration* config) { register_system_apps(); // Then we register and start user services. They are started after system app // registration just in case they want to figure out which system apps are installed. - register_and_start_user_services(config->services); + register_and_start_user_services(config.services); // Now we register the user apps, as they might rely on the user services. - register_user_apps(config->apps); + register_user_apps(config.apps); TT_LOG_I(TAG, "init starting desktop app"); service::loader::startApp(app::boot::manifest.id, true, Bundle()); - if (config->auto_start_app_id) { - TT_LOG_I(TAG, "init auto-starting %s", config->auto_start_app_id); - service::loader::startApp(config->auto_start_app_id, true, Bundle()); + if (config.auto_start_app_id) { + TT_LOG_I(TAG, "init auto-starting %s", config.auto_start_app_id); + service::loader::startApp(config.auto_start_app_id, true, Bundle()); } TT_LOG_I(TAG, "init complete"); diff --git a/Tactility/Source/Tactility.h b/Tactility/Source/Tactility.h index 4f0a71a5..067b7b6a 100644 --- a/Tactility/Source/Tactility.h +++ b/Tactility/Source/Tactility.h @@ -19,7 +19,7 @@ typedef struct { * Attempts to initialize Tactility and all configured hardware. * @param config */ -void init(const Configuration* config); +void init(const Configuration& config); /** * While technically nullable, this instance is always set if tt_init() succeeds. diff --git a/Tactility/Source/app/boot/Boot.cpp b/Tactility/Source/app/boot/Boot.cpp index 1fc8fa3f..78c1a176 100644 --- a/Tactility/Source/app/boot/Boot.cpp +++ b/Tactility/Source/app/boot/Boot.cpp @@ -1,12 +1,13 @@ -#include #include #include #include #include "Assets.h" #include "app/App.h" #include "lvgl.h" +#include "hal/Display.h" #include "service/loader/Loader.h" #include "lvgl/Style.h" +#include "app/display/DisplayPreferences.h" #ifdef ESP_PLATFORM #include "sdkconfig.h" @@ -26,7 +27,16 @@ struct Data { static int32_t threadCallback(TT_UNUSED void* context) { TickType_t start_time = tt::get_ticks(); - // Do stuff + + auto* lvgl_display = lv_display_get_default(); + tt_assert(lvgl_display != nullptr); + auto* hal_display = (tt::hal::Display*)lv_display_get_user_data(lvgl_display); + tt_assert(hal_display != nullptr); + if (hal_display->supportsBacklightDuty()) { + int32_t backlight_duty = app::display::preferences_get_backlight_duty(); + hal_display->setBacklightDuty(backlight_duty); + } + TickType_t end_time = tt::get_ticks(); TickType_t ticks_passed = end_time - start_time; TickType_t minimum_ticks = (CONFIG_TT_SPLASH_DURATION / portTICK_PERIOD_MS); diff --git a/Tactility/Source/app/display/Display.cpp b/Tactility/Source/app/display/Display.cpp index b5ed4f14..e265cb21 100644 --- a/Tactility/Source/app/display/Display.cpp +++ b/Tactility/Source/app/display/Display.cpp @@ -4,6 +4,7 @@ #include "Tactility.h" #include "lvgl/Toolbar.h" #include "lvgl.h" +#include "hal/Display.h" namespace tt::app::display { @@ -14,16 +15,18 @@ static uint8_t backlight_duty = 255; static void slider_event_cb(lv_event_t* event) { auto* slider = static_cast(lv_event_get_target(event)); - const Configuration* config = getConfiguration(); - hal::SetBacklightDuty set_backlight_duty = config->hardware->display.setBacklightDuty; + auto* lvgl_display = lv_display_get_default(); + tt_assert(lvgl_display != nullptr); + auto* hal_display = (tt::hal::Display*)lv_display_get_user_data(lvgl_display); + tt_assert(hal_display != nullptr); - if (set_backlight_duty != nullptr) { + if (hal_display->supportsBacklightDuty()) { int32_t slider_value = lv_slider_get_value(slider); backlight_duty = (uint8_t)slider_value; backlight_duty_set = true; - set_backlight_duty(backlight_duty); + hal_display->setBacklightDuty(backlight_duty); } } @@ -91,9 +94,12 @@ static void app_show(App& app, lv_obj_t* parent) { lv_slider_set_range(brightness_slider, 0, 255); lv_obj_add_event_cb(brightness_slider, slider_event_cb, LV_EVENT_VALUE_CHANGED, nullptr); - const Configuration* config = getConfiguration(); - hal::SetBacklightDuty set_backlight_duty = config->hardware->display.setBacklightDuty; - if (set_backlight_duty == nullptr) { + auto* lvgl_display = lv_display_get_default(); + tt_assert(lvgl_display != nullptr); + auto* hal_display = (tt::hal::Display*)lv_display_get_user_data(lvgl_display); + tt_assert(hal_display != nullptr); + + if (!hal_display->supportsBacklightDuty()) { lv_slider_set_value(brightness_slider, 255, LV_ANIM_OFF); lv_obj_add_state(brightness_slider, LV_STATE_DISABLED); } else { diff --git a/Tactility/Source/app/files/FileUtils.cpp b/Tactility/Source/app/files/FileUtils.cpp index b30ffee6..63deb35e 100644 --- a/Tactility/Source/app/files/FileUtils.cpp +++ b/Tactility/Source/app/files/FileUtils.cpp @@ -35,6 +35,7 @@ int scandir( ) { DIR* dir = opendir(path); if (dir == nullptr) { + TT_LOG_E(TAG, "Failed to open dir %s", path); return -1; } diff --git a/Tactility/Source/lvgl/Init.cpp b/Tactility/Source/lvgl/Init.cpp index 6ce5bd25..329c128d 100644 --- a/Tactility/Source/lvgl/Init.cpp +++ b/Tactility/Source/lvgl/Init.cpp @@ -1,20 +1,103 @@ #include "app/display/DisplayPreferences.h" #include "lvgl.h" #include "hal/Configuration.h" +#include "hal/Display.h" +#include "hal/Touch.h" +#include "hal/Keyboard.h" +#include "lvgl/LvglKeypad.h" +#include "lvgl/Lvgl.h" namespace tt::lvgl { -void init(const hal::Configuration* config) { - hal::SetBacklightDuty set_backlight_duty = config->display.setBacklightDuty; - if (set_backlight_duty != nullptr) { - int32_t backlight_duty = app::display::preferences_get_backlight_duty(); - set_backlight_duty(backlight_duty); +#define TAG "lvglinit" + +bool initDisplay(const hal::Configuration& config) { + assert(config.createDisplay); + auto* display = config.createDisplay(); + if (!display->start()) { + TT_LOG_E(TAG, "Display start failed"); + return false; } + lv_display_t* lvgl_display = display->getLvglDisplay(); + tt_assert(lvgl_display); + + if (display->supportsBacklightDuty()) { + display->setBacklightDuty(0); + } + + void* existing_display_user_data = lv_display_get_user_data(lvgl_display); + // esp_lvgl_port users user_data by default, so we have to modify the source + // this is a check for when we upgrade esp_lvgl_port and forget to modify it again + tt_assert(existing_display_user_data == nullptr); + lv_display_set_user_data(lvgl_display, display); + lv_display_rotation_t rotation = app::display::preferences_get_rotation(); if (rotation != lv_disp_get_rotation(lv_disp_get_default())) { lv_disp_set_rotation(lv_disp_get_default(), static_cast(rotation)); } + + return true; +} + +bool initTouch(hal::Display* display, hal::Touch* touch) { + TT_LOG_I(TAG, "Touch init"); + tt_assert(display); + tt_assert(touch); + if (touch->start(display->getLvglDisplay())) { + return true; + } else { + TT_LOG_E(TAG, "Touch init failed"); + return false; + } +} + +bool initKeyboard(hal::Display* display, hal::Keyboard* keyboard) { + TT_LOG_I(TAG, "Keyboard init"); + tt_assert(display); + tt_assert(keyboard); + if (keyboard->isAttached()) { + if (keyboard->start(display->getLvglDisplay())) { + lv_indev_t* keyboard_indev = keyboard->getLvglIndev(); + lv_indev_set_user_data(keyboard_indev, keyboard); + tt::lvgl::keypad_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, "Starting"); + + if (config.initLvgl != nullptr && !config.initLvgl()) { + TT_LOG_E(TAG, "LVGL init failed"); + return; + } + + if (!initDisplay(config)) { + return; + } + + hal::Display* display = getDisplay(); + + hal::Touch* touch = display->createTouch(); + if (touch != nullptr) { + initTouch(display, touch); + } + + if (config.createKeyboard) { + hal::Keyboard* keyboard = config.createKeyboard(); + initKeyboard(display, keyboard); + } + + TT_LOG_I(TAG, "Finished"); } } // namespace diff --git a/Tactility/Source/lvgl/Lvgl.cpp b/Tactility/Source/lvgl/Lvgl.cpp new file mode 100644 index 00000000..ed7fd746 --- /dev/null +++ b/Tactility/Source/lvgl/Lvgl.cpp @@ -0,0 +1,14 @@ +#include "lvgl/Lvgl.h" +#include "Check.h" + +namespace tt::lvgl { + +hal::Display* getDisplay() { + auto* lvgl_display = lv_display_get_default(); + tt_assert(lvgl_display != nullptr); + auto* hal_display = (tt::hal::Display*)lv_display_get_user_data(lvgl_display); + tt_assert(hal_display != nullptr); + return hal_display; +} + +} diff --git a/Tactility/Source/lvgl/Lvgl.h b/Tactility/Source/lvgl/Lvgl.h new file mode 100644 index 00000000..72d5e843 --- /dev/null +++ b/Tactility/Source/lvgl/Lvgl.h @@ -0,0 +1,7 @@ +#pragma once + +#include "hal/Display.h" + +namespace tt::lvgl { + hal::Display* getDisplay(); +} diff --git a/Tactility/Source/lvgl/LvglSync.cpp b/Tactility/Source/lvgl/LvglSync.cpp index 39efeaf7..32a1f08d 100644 --- a/Tactility/Source/lvgl/LvglSync.cpp +++ b/Tactility/Source/lvgl/LvglSync.cpp @@ -1,11 +1,20 @@ +#include #include "LvglSync.h" -#include "Check.h" - namespace tt::lvgl { -static LvglLock lock_singleton = nullptr; -static LvglUnlock unlock_singleton = nullptr; +Mutex lockMutex; + +static bool defaultLock(uint32_t timeoutTicks) { + return lockMutex.acquire(timeoutTicks) == TtStatusOk; +} + +static void defaultUnlock() { + lockMutex.release(); +} + +static LvglLock lock_singleton = defaultLock; +static LvglUnlock unlock_singleton = defaultUnlock; void syncSet(LvglLock lock, LvglUnlock unlock) { lock_singleton = lock; @@ -13,12 +22,10 @@ void syncSet(LvglLock lock, LvglUnlock unlock) { } bool lock(uint32_t timeout_ticks) { - tt_check(lock_singleton); return lock_singleton(timeout_ticks); } void unlock() { - tt_check(unlock_singleton); unlock_singleton(); } diff --git a/Tactility/Source/lvgl/LvglSync.h b/Tactility/Source/lvgl/LvglSync.h index bdce15d0..66e8d746 100644 --- a/Tactility/Source/lvgl/LvglSync.h +++ b/Tactility/Source/lvgl/LvglSync.h @@ -8,6 +8,7 @@ typedef bool (*LvglLock)(uint32_t timeout_ticks); typedef void (*LvglUnlock)(); void syncSet(LvglLock lock, LvglUnlock unlock); +bool isSyncSet(); bool lock(uint32_t timeout_ticks); void unlock(); diff --git a/Tactility/Source/service/screenshot/Screenshot.cpp b/Tactility/Source/service/screenshot/Screenshot.cpp index c88b7ac5..4b4e5bde 100644 --- a/Tactility/Source/service/screenshot/Screenshot.cpp +++ b/Tactility/Source/service/screenshot/Screenshot.cpp @@ -9,7 +9,7 @@ namespace tt::service::screenshot { -#define TAG "sdcard_service" +#define TAG "screenshot_service" extern const Manifest manifest; diff --git a/TactilityCore/Source/Log.cpp b/TactilityCore/Source/Log.cpp index 6321d370..0b463985 100644 --- a/TactilityCore/Source/Log.cpp +++ b/TactilityCore/Source/Log.cpp @@ -2,13 +2,8 @@ #include "Log.h" -#ifdef ESP_PLATFORM -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#else #include #include -#endif namespace tt { diff --git a/TactilityHeadless/Source/hal/Configuration.h b/TactilityHeadless/Source/hal/Configuration.h index e347c828..c2fce663 100644 --- a/TactilityHeadless/Source/hal/Configuration.h +++ b/TactilityHeadless/Source/hal/Configuration.h @@ -6,22 +6,23 @@ namespace tt::hal { -typedef bool (*InitPower)(); +typedef bool (*InitBoot)(); typedef bool (*InitHardware)(); typedef bool (*InitLvgl)(); typedef void (*SetBacklightDuty)(uint8_t); -typedef struct { - /** Set backlight duty */ - _Nullable SetBacklightDuty setBacklightDuty; -} Display; -typedef struct { +class Display; +class Keyboard; +typedef Display* (*CreateDisplay)(); +typedef Keyboard* (*CreateKeyboard)(); + +struct Configuration { /** * Called before I2C/SPI/etc is initialized. * Used for powering on the peripherals manually. */ - const InitPower _Nullable initPower = nullptr; + const InitBoot _Nullable initBoot = nullptr; /** * Called after I2C/SPI/etc is initialized. @@ -32,27 +33,32 @@ typedef struct { /** * Create and initialize all LVGL devices. (e.g. display, touch, keyboard) */ - const InitLvgl _Nullable initLvgl; + const InitLvgl _Nullable initLvgl = nullptr; /** * Display HAL functionality. */ - const Display display; + const CreateDisplay _Nullable createDisplay = nullptr; + + /** + * Display HAL functionality. + */ + const CreateKeyboard _Nullable createKeyboard = nullptr; /** * An optional SD card interface. */ - const sdcard::SdCard* _Nullable sdcard; + const sdcard::SdCard* _Nullable sdcard = nullptr; /** * An optional power interface for battery or other power delivery. */ - const Power* _Nullable power; + const Power* _Nullable power = nullptr; /** * A list of i2c devices (can be empty, but preferably accurately represents the device capabilities) */ - const std::vector i2c; -} Configuration; + const std::vector i2c = {}; +}; } // namespace diff --git a/TactilityHeadless/Source/hal/Display.h b/TactilityHeadless/Source/hal/Display.h new file mode 100644 index 00000000..b7b0af2d --- /dev/null +++ b/TactilityHeadless/Source/hal/Display.h @@ -0,0 +1,29 @@ +#pragma once + +#include "lvgl.h" + +namespace tt::hal { + +class Touch; + +class Display { +public: + [[nodiscard]] virtual bool start() = 0; + [[nodiscard]] virtual bool stop() = 0; + + [[nodiscard]] virtual void setPowerOn(bool turnOn) = 0; + [[nodiscard]] virtual bool isPoweredOn() const = 0; + [[nodiscard]] virtual bool supportsPowerControl() const = 0; + + [[nodiscard]] virtual Touch* _Nullable createTouch() = 0; + + /** Set a value in the range [0, 255] */ + virtual void setBacklightDuty(uint8_t backlightDuty) = 0; + [[nodiscard]] virtual uint8_t getBacklightDuty() const = 0; + [[nodiscard]] virtual bool supportsBacklightDuty() const = 0; + + /** After start() returns true, this should return a valid pointer until stop() is called and returns true */ + [[nodiscard]] virtual lv_display_t* _Nullable getLvglDisplay() const = 0; +}; + +} diff --git a/TactilityHeadless/Source/hal/Hal.cpp b/TactilityHeadless/Source/hal/Hal.cpp index b37a6c7a..93a59fc6 100644 --- a/TactilityHeadless/Source/hal/Hal.cpp +++ b/TactilityHeadless/Source/hal/Hal.cpp @@ -6,9 +6,9 @@ namespace tt::hal { void init(const Configuration& configuration) { - if (configuration.initPower != nullptr) { + if (configuration.initBoot != nullptr) { TT_LOG_I(TAG, "Init power"); - tt_check(configuration.initPower(), "Init power failed"); + tt_check(configuration.initBoot(), "Init power failed"); } tt_check(i2c::init(configuration.i2c), "I2C init failed"); @@ -23,11 +23,6 @@ void init(const Configuration& configuration) { TT_LOG_W(TAG, "SD card mount failed (init can continue)"); } } - - if (configuration.initLvgl != nullptr) { - TT_LOG_I(TAG, "Init LVGL"); - tt_check(configuration.initLvgl(), "LVGL init failed"); - } } } // namespace diff --git a/TactilityHeadless/Source/hal/Keyboard.h b/TactilityHeadless/Source/hal/Keyboard.h new file mode 100644 index 00000000..c4462d9d --- /dev/null +++ b/TactilityHeadless/Source/hal/Keyboard.h @@ -0,0 +1,18 @@ +#pragma once + +#include "lvgl.h" + +namespace tt::hal { + +class Display; + +class Keyboard { +public: + [[nodiscard]] virtual bool start(lv_display_t* display) = 0; + [[nodiscard]] virtual bool stop() = 0; + [[nodiscard]] virtual bool isAttached() const = 0; + + [[nodiscard]] virtual lv_indev_t* _Nullable getLvglIndev() = 0; +}; + +} diff --git a/TactilityHeadless/Source/hal/Touch.h b/TactilityHeadless/Source/hal/Touch.h new file mode 100644 index 00000000..76598fb9 --- /dev/null +++ b/TactilityHeadless/Source/hal/Touch.h @@ -0,0 +1,18 @@ +#pragma once + +#include "lvgl.h" + +namespace tt::hal { + +class Display; + +class Touch { + +public: + [[nodiscard]] virtual bool start(lv_display_t* display) = 0; + [[nodiscard]] virtual bool stop() = 0; + + [[nodiscard]] virtual lv_indev_t* _Nullable getLvglIndev() = 0; +}; + +} diff --git a/sdkconfig.board.waveshare_s3_touch b/sdkconfig.board.waveshare_s3_touch deleted file mode 100644 index 5bb4cc7f..00000000 --- a/sdkconfig.board.waveshare_s3_touch +++ /dev/null @@ -1,35 +0,0 @@ -# Software defaults -CONFIG_LV_FONT_MONTSERRAT_14=y -CONFIG_LV_FONT_MONTSERRAT_18=y -CONFIG_LV_USE_USER_DATA=y -CONFIG_LV_USE_FS_STDIO=y -CONFIG_LV_FS_STDIO_LETTER=65 -CONFIG_LV_FS_STDIO_PATH="" -CONFIG_LV_FS_STDIO_CACHE_SIZE=4096 -CONFIG_LV_USE_LODEPNG=y -CONFIG_LV_USE_BUILTIN_MALLOC=n -CONFIG_LV_USE_CLIB_MALLOC=y -CONFIG_FREERTOS_HZ=1000 -CONFIG_FREERTOS_TASK_NOTIFICATION_ARRAY_ENTRIES=2 -CONFIG_FREERTOS_SMP=n -CONFIG_FREERTOS_UNICORE=n -CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=4096 -CONFIG_PARTITION_TABLE_CUSTOM=y -CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" -CONFIG_PARTITION_TABLE_FILENAME="partitions.csv" - -# Hardware: Main -CONFIG_TT_BOARD_WAVESHARE_S3_TOUCH=y -CONFIG_IDF_TARGET="esp32s3" -CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y -CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y -CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y -CONFIG_FLASHMODE_QIO=y -# Hardware: SPI RAM -CONFIG_ESP32S3_SPIRAM_SUPPORT=y -CONFIG_SPIRAM_MODE_OCT=y -CONFIG_SPIRAM_SPEED_80M=y -# LVGL -CONFIG_LV_DISP_DEF_REFR_PERIOD=17 -CONFIG_LV_INDEV_DEF_READ_PERIOD=17 -CONFIG_LV_DPI_DEF=216 diff --git a/sdkconfig.developer b/sdkconfig.developer index efbb6257..dfe09d6e 100644 --- a/sdkconfig.developer +++ b/sdkconfig.developer @@ -1,4 +1,7 @@ CONFIG_STACK_CHECK_STRONG=y + LV_USE_SYSMON=y CONFIG_LV_USE_OBSERVER=y -CONFIG_LV_USE_PERF_MONITOR=y \ No newline at end of file +CONFIG_LV_USE_PERF_MONITOR=y + +CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT=y