diff --git a/Boards/CYD-4848S040C/Source/hal/CydDisplay.h b/Boards/CYD-4848S040C/Source/hal/CydDisplay.h index 61a3c1ef..960d00fd 100644 --- a/Boards/CYD-4848S040C/Source/hal/CydDisplay.h +++ b/Boards/CYD-4848S040C/Source/hal/CydDisplay.h @@ -1,7 +1,9 @@ #pragma once +#include + #include -#include +#include class CydDisplay final : public EspLcdDisplay { @@ -19,6 +21,8 @@ class CydDisplay final : public EspLcdDisplay { public: + CydDisplay() : EspLcdDisplay(std::make_shared(tt::Mutex::Type::Recursive)) {} + std::string getName() const override { return "ST7701S"; } std::string getDescription() const override { return "ST7701S RGB display"; } diff --git a/Boards/UnPhone/Source/hal/UnPhoneDisplay.h b/Boards/UnPhone/Source/hal/UnPhoneDisplay.h index 2c25a42b..3d489783 100644 --- a/Boards/UnPhone/Source/hal/UnPhoneDisplay.h +++ b/Boards/UnPhone/Source/hal/UnPhoneDisplay.h @@ -1,12 +1,16 @@ #pragma once -#include "Tactility/hal/display/DisplayDevice.h" +#include +#include +#include + #include #include -#include #include "UnPhoneDisplayConstants.h" +#include + class UnPhoneDisplay : public tt::hal::display::DisplayDevice { uint8_t* _Nullable buffer = nullptr; @@ -14,12 +18,14 @@ class UnPhoneDisplay : public tt::hal::display::DisplayDevice { std::shared_ptr _Nullable touchDevice; std::shared_ptr _Nullable nativeDisplay; - class UnPhoneDisplayDriver : public tt::hal::display::DisplayDriver { + std::shared_ptr lock = tt::hal::spi::getLock(SPI2_HOST); + public: tt::hal::display::ColorFormat getColorFormat() const override { return tt::hal::display::ColorFormat::RGB888; } uint16_t getPixelWidth() const override { return UNPHONE_LCD_HORIZONTAL_RESOLUTION; } uint16_t getPixelHeight() const override { return UNPHONE_LCD_VERTICAL_RESOLUTION; } bool drawBitmap(int xStart, int yStart, int xEnd, int yEnd, const void* pixelData) override; + std::shared_ptr getLock() const override { return lock; } }; public: diff --git a/Documentation/ideas.md b/Documentation/ideas.md index e0b2f32d..899531c5 100644 --- a/Documentation/ideas.md +++ b/Documentation/ideas.md @@ -1,5 +1,6 @@ # TODOs +- When an external app fails to load (e.g. due to mapping error) then show an error dialog. - Revisit TinyUSB mouse idea: the bugs related to cleanup seem to be fixed in the library. - Bug: When a Wi-Fi SSID is too long, then it fails to save the credentials - Add a Keyboard setting app to override the behaviour of soft keyboard hiding (e.g. keyboard hardware is present, but the user wants to use a soft keyboard) diff --git a/Drivers/EspLcdCompat/Source/EspLcdDisplay.cpp b/Drivers/EspLcdCompat/Source/EspLcdDisplay.cpp index adef57f0..bcc3e6e1 100644 --- a/Drivers/EspLcdCompat/Source/EspLcdDisplay.cpp +++ b/Drivers/EspLcdCompat/Source/EspLcdDisplay.cpp @@ -58,13 +58,13 @@ bool EspLcdDisplay::startLvgl() { TT_LOG_W(TAG, "DisplayDriver is still in use."); } - lvglPortDisplayConfig = getLvglPortDisplayConfig(ioHandle, panelHandle); + auto lvgl_port_config = getLvglPortDisplayConfig(ioHandle, panelHandle); if (isRgbPanel()) { auto rgb_config = getLvglPortDisplayRgbConfig(ioHandle, panelHandle); - lvglDisplay = lvgl_port_add_disp_rgb(&lvglPortDisplayConfig, &rgb_config); + lvglDisplay = lvgl_port_add_disp_rgb(&lvgl_port_config , &rgb_config); } else { - lvglDisplay = lvgl_port_add_disp(&lvglPortDisplayConfig); + lvglDisplay = lvgl_port_add_disp(&lvgl_port_config ); } auto touch_device = getTouchDevice(); @@ -90,12 +90,40 @@ bool EspLcdDisplay::stopLvgl() { return true; } -std::shared_ptr EspLcdDisplay::getDisplayDriver() { +std::shared_ptr EspLcdDisplay::getDisplayDriver() { assert(lvglDisplay == nullptr); // Still attached to LVGL context. Call stopLvgl() first. if (displayDriver == nullptr) { + auto lvgl_port_config = getLvglPortDisplayConfig(ioHandle, panelHandle); + + tt::hal::display::ColorFormat color_format; + if (lvgl_port_config.color_format == LV_COLOR_FORMAT_I1) { + color_format = tt::hal::display::ColorFormat::Monochrome; + } else if (lvgl_port_config.color_format == LV_COLOR_FORMAT_RGB565) { + if (rgbElementOrder == LCD_RGB_ELEMENT_ORDER_RGB) { + if (lvgl_port_config.flags.swap_bytes) { + color_format = tt::hal::display::ColorFormat::RGB565Swapped; + } else { + color_format = tt::hal::display::ColorFormat::RGB565; + } + } else { + if (lvgl_port_config.flags.swap_bytes) { + color_format = tt::hal::display::ColorFormat::BGR565Swapped; + } else { + color_format = tt::hal::display::ColorFormat::BGR565; + } + } + } else if (lvgl_port_config.color_format == LV_COLOR_FORMAT_RGB888) { + color_format = tt::hal::display::ColorFormat::RGB888; + } else { + tt_crash("unsupported driver"); + } + displayDriver = std::make_shared( panelHandle, - lvglPortDisplayConfig + lock, + lvgl_port_config.hres, + lvgl_port_config.vres, + color_format ); } return displayDriver; diff --git a/Drivers/EspLcdCompat/Source/EspLcdDisplay.h b/Drivers/EspLcdCompat/Source/EspLcdDisplay.h index 3fe40c70..7fecff1b 100644 --- a/Drivers/EspLcdCompat/Source/EspLcdDisplay.h +++ b/Drivers/EspLcdCompat/Source/EspLcdDisplay.h @@ -1,5 +1,7 @@ #pragma once +#include "Tactility/Lock.h" + #include #include @@ -11,8 +13,9 @@ class EspLcdDisplay : tt::hal::display::DisplayDevice { esp_lcd_panel_io_handle_t _Nullable ioHandle = nullptr; esp_lcd_panel_handle_t _Nullable panelHandle = nullptr; lv_display_t* _Nullable lvglDisplay = nullptr; - lvgl_port_display_cfg_t _Nullable lvglPortDisplayConfig; std::shared_ptr _Nullable displayDriver; + std::shared_ptr lock; + lcd_rgb_element_order_t rgbElementOrder; protected: @@ -31,8 +34,12 @@ protected: public: + EspLcdDisplay(std::shared_ptr lock) : lock(lock) {} + ~EspLcdDisplay() override; + std::shared_ptr getLock() const { return lock; } + bool start() final; bool stop() final; diff --git a/Drivers/EspLcdCompat/Source/EspLcdDisplayDriver.h b/Drivers/EspLcdCompat/Source/EspLcdDisplayDriver.h index ceae9f5f..4192f1de 100644 --- a/Drivers/EspLcdCompat/Source/EspLcdDisplayDriver.h +++ b/Drivers/EspLcdCompat/Source/EspLcdDisplayDriver.h @@ -1,44 +1,40 @@ #pragma once +#include #include + #include -#include -using namespace tt::hal; - -class EspLcdDisplayDriver : public display::DisplayDriver { +class EspLcdDisplayDriver : public tt::hal::display::DisplayDriver { esp_lcd_panel_handle_t panelHandle; - const lvgl_port_display_cfg_t& lvglPortDisplayConfig; + std::shared_ptr lock; + uint16_t hRes; + uint16_t vRes; + tt::hal::display::ColorFormat colorFormat; public: EspLcdDisplayDriver( esp_lcd_panel_handle_t panelHandle, - const lvgl_port_display_cfg_t& lvglPortDisplayConfig - ) : panelHandle(panelHandle), lvglPortDisplayConfig(lvglPortDisplayConfig) {} + std::shared_ptr lock, + uint16_t hRes, + uint16_t vRes, + tt::hal::display::ColorFormat colorFormat + ) : panelHandle(panelHandle), lock(lock), hRes(hRes), vRes(vRes), colorFormat(colorFormat) {} - display::ColorFormat getColorFormat() const override { - using display::ColorFormat; - switch (lvglPortDisplayConfig.color_format) { - case LV_COLOR_FORMAT_I1: - return ColorFormat::Monochrome; - case LV_COLOR_FORMAT_RGB565: - // swap_bytes is only used for the 565 color format - // see lvgl_port_flush_callback() in esp_lvgl_port_disp.c - return lvglPortDisplayConfig.flags.swap_bytes ? ColorFormat::BGR565 : ColorFormat::RGB565; - case LV_COLOR_FORMAT_RGB888: - return ColorFormat::RGB888; - default: - return ColorFormat::RGB565; - } + tt::hal::display::ColorFormat getColorFormat() const override { + return colorFormat; } bool drawBitmap(int xStart, int yStart, int xEnd, int yEnd, const void* pixelData) override { - return esp_lcd_panel_draw_bitmap(panelHandle, xStart, yStart, xEnd, yEnd, pixelData) == ESP_OK; + bool result = esp_lcd_panel_draw_bitmap(panelHandle, xStart, yStart, xEnd, yEnd, pixelData) == ESP_OK; + return result; } - uint16_t getPixelWidth() const override { return lvglPortDisplayConfig.hres; } + uint16_t getPixelWidth() const override { return hRes; } - uint16_t getPixelHeight() const override { return lvglPortDisplayConfig.vres; } + uint16_t getPixelHeight() const override { return vRes; } + + std::shared_ptr getLock() const override { return lock; } }; diff --git a/Drivers/EspLcdCompat/Source/EspLcdTouchDriver.cpp b/Drivers/EspLcdCompat/Source/EspLcdTouchDriver.cpp index 7d186ac0..56b0c526 100644 --- a/Drivers/EspLcdCompat/Source/EspLcdTouchDriver.cpp +++ b/Drivers/EspLcdCompat/Source/EspLcdTouchDriver.cpp @@ -9,5 +9,5 @@ bool EspLcdTouchDriver::getTouchedPoints(uint16_t* x, uint16_t* y, uint16_t* _Nu TT_LOG_E(TAG, "Read data failed"); return false; } - return esp_lcd_touch_get_coordinates(handle, x, y, strength, pointCount, maxPointCount) == ESP_OK; + return esp_lcd_touch_get_coordinates(handle, x, y, strength, pointCount, maxPointCount); } diff --git a/Drivers/ILI934x/Source/Ili934xDisplay.cpp b/Drivers/ILI934x/Source/Ili934xDisplay.cpp index 71f7aa0a..0f767e06 100644 --- a/Drivers/ILI934x/Source/Ili934xDisplay.cpp +++ b/Drivers/ILI934x/Source/Ili934xDisplay.cpp @@ -33,7 +33,7 @@ bool Ili934xDisplay::createIoHandle(esp_lcd_panel_io_handle_t& outHandle) { } }; - return esp_lcd_new_panel_io_spi(configuration->spiBusHandle, &panel_io_config, &outHandle) == ESP_OK; + return esp_lcd_new_panel_io_spi(configuration->spiHostDevice, &panel_io_config, &outHandle) == ESP_OK; } bool Ili934xDisplay::createPanelHandle(esp_lcd_panel_io_handle_t ioHandle, esp_lcd_panel_handle_t& panelHandle) { diff --git a/Drivers/ILI934x/Source/Ili934xDisplay.h b/Drivers/ILI934x/Source/Ili934xDisplay.h index ff37dedf..77a234ea 100644 --- a/Drivers/ILI934x/Source/Ili934xDisplay.h +++ b/Drivers/ILI934x/Source/Ili934xDisplay.h @@ -1,16 +1,16 @@ #pragma once -#include "Tactility/hal/display/DisplayDevice.h" +#include +#include + +#include -#include #include #include #include #include #include -#include - class Ili934xDisplay final : public EspLcdDisplay { public: @@ -20,7 +20,7 @@ public: public: Configuration( - esp_lcd_spi_bus_handle_t spi_bus_handle, + spi_host_device_t spiHostDevice, gpio_num_t csPin, gpio_num_t dcPin, unsigned int horizontalResolution, @@ -32,7 +32,7 @@ public: bool invertColor = false, uint32_t bufferSize = 0, // Size in pixel count. 0 means default, which is 1/10 of the screen size, lcd_rgb_element_order_t rgbElementOrder = LCD_RGB_ELEMENT_ORDER_BGR - ) : spiBusHandle(spi_bus_handle), + ) : spiHostDevice(spiHostDevice), csPin(csPin), dcPin(dcPin), horizontalResolution(horizontalResolution), @@ -50,7 +50,7 @@ public: } } - esp_lcd_spi_bus_handle_t spiBusHandle; + spi_host_device_t spiHostDevice; gpio_num_t csPin; gpio_num_t dcPin; gpio_num_t resetPin = GPIO_NUM_NC; @@ -80,7 +80,10 @@ private: public: - explicit Ili934xDisplay(std::unique_ptr inConfiguration) : configuration(std::move(inConfiguration)) { + explicit Ili934xDisplay(std::unique_ptr inConfiguration) : + EspLcdDisplay(tt::hal::spi::getLock(inConfiguration->spiHostDevice)), + configuration(std::move(inConfiguration) + ) { assert(configuration != nullptr); } diff --git a/Drivers/ILI9488/Source/Ili9488Display.cpp b/Drivers/ILI9488/Source/Ili9488Display.cpp index 96e11f18..6773c832 100644 --- a/Drivers/ILI9488/Source/Ili9488Display.cpp +++ b/Drivers/ILI9488/Source/Ili9488Display.cpp @@ -33,7 +33,7 @@ bool Ili9488Display::createIoHandle(esp_lcd_panel_io_handle_t& outHandle) { } }; - return esp_lcd_new_panel_io_spi(configuration->spiBusHandle, &panel_io_config, &outHandle) == ESP_OK; + return esp_lcd_new_panel_io_spi(configuration->spiHostDevice, &panel_io_config, &outHandle) == ESP_OK; } bool Ili9488Display::createPanelHandle(esp_lcd_panel_io_handle_t ioHandle, esp_lcd_panel_handle_t& panelHandle) { diff --git a/Drivers/ILI9488/Source/Ili9488Display.h b/Drivers/ILI9488/Source/Ili9488Display.h index 5455e300..06c71fa1 100644 --- a/Drivers/ILI9488/Source/Ili9488Display.h +++ b/Drivers/ILI9488/Source/Ili9488Display.h @@ -1,6 +1,7 @@ #pragma once -#include "Tactility/hal/display/DisplayDevice.h" +#include +#include #include @@ -17,7 +18,7 @@ public: public: Configuration( - esp_lcd_spi_bus_handle_t spi_bus_handle, + spi_host_device_t spiHostDevice, gpio_num_t csPin, gpio_num_t dcPin, unsigned int horizontalResolution, @@ -28,7 +29,7 @@ public: bool mirrorY = false, bool invertColor = false, uint32_t bufferSize = 0 // Size in pixel count. 0 means default, which is 1/20 of the screen size - ) : spiBusHandle(spi_bus_handle), + ) : spiHostDevice(spiHostDevice), csPin(csPin), dcPin(dcPin), horizontalResolution(horizontalResolution), @@ -44,7 +45,7 @@ public: } } - esp_lcd_spi_bus_handle_t spiBusHandle; + spi_host_device_t spiHostDevice; gpio_num_t csPin; gpio_num_t dcPin; gpio_num_t resetPin = GPIO_NUM_NC; @@ -73,7 +74,10 @@ private: public: - explicit Ili9488Display(std::unique_ptr inConfiguration) : configuration(std::move(inConfiguration)) { + explicit Ili9488Display(std::unique_ptr inConfiguration) : + EspLcdDisplay(tt::hal::spi::getLock(inConfiguration->spiHostDevice)), + configuration(std::move(inConfiguration) + ) { assert(configuration != nullptr); } diff --git a/Drivers/RgbDisplay/Source/RgbDisplay.h b/Drivers/RgbDisplay/Source/RgbDisplay.h index 84cc6469..7c6ebc1f 100644 --- a/Drivers/RgbDisplay/Source/RgbDisplay.h +++ b/Drivers/RgbDisplay/Source/RgbDisplay.h @@ -3,8 +3,11 @@ #include #include #include +#include -class RgbDisplay final : public display::DisplayDevice { +class RgbDisplay final : public tt::hal::display::DisplayDevice { + + std::shared_ptr lock = std::make_shared(tt::Mutex::Type::Recursive); public: @@ -21,7 +24,7 @@ public: esp_lcd_rgb_panel_config_t panelConfig; BufferConfiguration bufferConfiguration; - std::shared_ptr touch; + std::shared_ptr touch; lv_color_format_t colorFormat; bool swapXY; bool mirrorX; @@ -32,7 +35,7 @@ public: Configuration( esp_lcd_rgb_panel_config_t panelConfig, BufferConfiguration bufferConfiguration, - std::shared_ptr touch, + std::shared_ptr touch, lv_color_format_t colorFormat, bool swapXY = false, bool mirrorX = false, @@ -61,7 +64,7 @@ private: std::unique_ptr _Nullable configuration = nullptr; esp_lcd_panel_handle_t _Nullable panelHandle = nullptr; lv_display_t* _Nullable lvglDisplay = nullptr; - std::shared_ptr _Nullable displayDriver; + std::shared_ptr _Nullable displayDriver; lvgl_port_display_cfg_t getLvglPortDisplayConfig() const; @@ -86,7 +89,7 @@ public: bool stopLvgl() override; - std::shared_ptr _Nullable getTouchDevice() override { return configuration->touch; } + std::shared_ptr _Nullable getTouchDevice() override { return configuration->touch; } void setBacklightDuty(uint8_t backlightDuty) override { if (configuration->backlightDutyFunction != nullptr) { @@ -98,11 +101,13 @@ public: lv_display_t* _Nullable getLvglDisplay() const override { return lvglDisplay; } - bool supportsDisplayDriver() const override { return true; } + // TODO: Fix driver and re-enable + bool supportsDisplayDriver() const override { return false; } - std::shared_ptr _Nullable getDisplayDriver() override { + std::shared_ptr _Nullable getDisplayDriver() override { if (displayDriver == nullptr) { - displayDriver = std::make_shared(panelHandle, getLvglPortDisplayConfig()); + auto config = getLvglPortDisplayConfig(); + displayDriver = std::make_shared(panelHandle, lock, config.hres, config.vres, tt::hal::display::ColorFormat::RGB888); } return displayDriver; } diff --git a/Drivers/ST7789/Source/St7789Display.cpp b/Drivers/ST7789/Source/St7789Display.cpp index 99a00ac2..976ca589 100644 --- a/Drivers/ST7789/Source/St7789Display.cpp +++ b/Drivers/ST7789/Source/St7789Display.cpp @@ -36,7 +36,7 @@ bool St7789Display::createIoHandle(esp_lcd_panel_io_handle_t& outHandle) { } }; - if (esp_lcd_new_panel_io_spi(configuration->spiBusHandle, &panel_io_config, &outHandle) != ESP_OK) { + if (esp_lcd_new_panel_io_spi(configuration->spiHostDevice, &panel_io_config, &outHandle) != ESP_OK) { TT_LOG_E(TAG, "Failed to create panel"); return false; } diff --git a/Drivers/ST7789/Source/St7789Display.h b/Drivers/ST7789/Source/St7789Display.h index b4bdd941..79292b94 100644 --- a/Drivers/ST7789/Source/St7789Display.h +++ b/Drivers/ST7789/Source/St7789Display.h @@ -1,5 +1,7 @@ #pragma once +#include "Tactility/hal/spi/Spi.h" + #include #include @@ -11,6 +13,8 @@ class St7789Display final : public EspLcdDisplay { + std::shared_ptr lock; + public: class Configuration { @@ -18,7 +22,7 @@ public: public: Configuration( - esp_lcd_spi_bus_handle_t spi_bus_handle, + spi_host_device_t spiHostDevice, gpio_num_t csPin, gpio_num_t dcPin, unsigned int horizontalResolution, @@ -29,7 +33,7 @@ public: bool mirrorY = false, bool invertColor = false, uint32_t bufferSize = 0 // Size in pixel count. 0 means default, which is 1/10 of the screen size - ) : spiBusHandle(spi_bus_handle), + ) : spiHostDevice(spiHostDevice), csPin(csPin), dcPin(dcPin), horizontalResolution(horizontalResolution), @@ -46,7 +50,7 @@ public: } } - esp_lcd_spi_bus_handle_t spiBusHandle; + spi_host_device_t spiHostDevice; gpio_num_t csPin; gpio_num_t dcPin; gpio_num_t resetPin = GPIO_NUM_NC; @@ -75,8 +79,12 @@ private: public: - explicit St7789Display(std::unique_ptr inConfiguration) : configuration(std::move(inConfiguration)) { + explicit St7789Display(std::unique_ptr inConfiguration) : + EspLcdDisplay(tt::hal::spi::getLock(inConfiguration->spiHostDevice)), + configuration(std::move(inConfiguration) + ) { assert(configuration != nullptr); + assert(getLock() != nullptr); } std::string getName() const override { return "ST7789"; } diff --git a/Drivers/ST7796/Source/St7796Display.cpp b/Drivers/ST7796/Source/St7796Display.cpp index 0cf1c4ec..04cfd9b1 100644 --- a/Drivers/ST7796/Source/St7796Display.cpp +++ b/Drivers/ST7796/Source/St7796Display.cpp @@ -33,7 +33,7 @@ bool St7796Display::createIoHandle(esp_lcd_panel_io_handle_t& ioHandle) { } }; - return esp_lcd_new_panel_io_spi(configuration->spiBusHandle, &panel_io_config, &ioHandle) == ESP_OK; + return esp_lcd_new_panel_io_spi(configuration->spiHostDevice, &panel_io_config, &ioHandle) == ESP_OK; } bool St7796Display::createPanelHandle(esp_lcd_panel_io_handle_t ioHandle, esp_lcd_panel_handle_t& panelHandle) { diff --git a/Drivers/ST7796/Source/St7796Display.h b/Drivers/ST7796/Source/St7796Display.h index 8ded6d59..a5ee3ef9 100644 --- a/Drivers/ST7796/Source/St7796Display.h +++ b/Drivers/ST7796/Source/St7796Display.h @@ -1,5 +1,8 @@ #pragma once +#include +#include + #include #include #include @@ -13,7 +16,7 @@ public: public: Configuration( - esp_lcd_spi_bus_handle_t spi_bus_handle, + spi_host_device_t spiHostDevice, gpio_num_t csPin, gpio_num_t dcPin, unsigned int horizontalResolution, @@ -26,7 +29,7 @@ public: unsigned int gapX = 0, unsigned int gapY = 0, uint32_t bufferSize = 0 // Size in pixel count. 0 means default, which is 1/10 of the screen size - ) : spiBusHandle(spi_bus_handle), + ) : spiHostDevice(spiHostDevice), csPin(csPin), dcPin(dcPin), horizontalResolution(horizontalResolution), @@ -44,7 +47,7 @@ public: } } - esp_lcd_spi_bus_handle_t spiBusHandle; + spi_host_device_t spiHostDevice; gpio_num_t csPin; gpio_num_t dcPin; gpio_num_t resetPin = GPIO_NUM_NC; @@ -75,7 +78,10 @@ private: public: - explicit St7796Display(std::unique_ptr inConfiguration) : configuration(std::move(inConfiguration)) { + explicit St7796Display(std::unique_ptr inConfiguration) : + EspLcdDisplay(tt::hal::spi::getLock(inConfiguration->spiHostDevice)), + configuration(std::move(inConfiguration) + ) { assert(configuration != nullptr); } diff --git a/ExternalApps/GraphicsDemo/.gitignore b/ExternalApps/GraphicsDemo/.gitignore new file mode 100644 index 00000000..89baa26e --- /dev/null +++ b/ExternalApps/GraphicsDemo/.gitignore @@ -0,0 +1,2 @@ +build*/ +.tactility/ diff --git a/ExternalApps/GraphicsDemo/CMakeLists.txt b/ExternalApps/GraphicsDemo/CMakeLists.txt new file mode 100644 index 00000000..c9cfd749 --- /dev/null +++ b/ExternalApps/GraphicsDemo/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.20) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) + +if (DEFINED ENV{TACTILITY_SDK_PATH}) + set(TACTILITY_SDK_PATH $ENV{TACTILITY_SDK_PATH}) +else() + set(TACTILITY_SDK_PATH "../../release/TactilitySDK") + message(WARNING "⚠️ TACTILITY_SDK_PATH environment variable is not set, defaulting to ${TACTILITY_SDK_PATH}") +endif() + +include("${TACTILITY_SDK_PATH}/TactilitySDK.cmake") +set(EXTRA_COMPONENT_DIRS ${TACTILITY_SDK_PATH}) + +project(GraphicsDemo) +tactility_project(GraphicsDemo) diff --git a/ExternalApps/GraphicsDemo/main/CMakeLists.txt b/ExternalApps/GraphicsDemo/main/CMakeLists.txt new file mode 100644 index 00000000..759aed70 --- /dev/null +++ b/ExternalApps/GraphicsDemo/main/CMakeLists.txt @@ -0,0 +1,7 @@ +file(GLOB_RECURSE SOURCE_FILES Source/*.c*) + +idf_component_register( + SRC_DIRS "Source" + INCLUDE_DIRS "Include" + REQUIRES TactilitySDK +) diff --git a/ExternalApps/GraphicsDemo/main/Include/Application.h b/ExternalApps/GraphicsDemo/main/Include/Application.h new file mode 100644 index 00000000..90bcf712 --- /dev/null +++ b/ExternalApps/GraphicsDemo/main/Include/Application.h @@ -0,0 +1,6 @@ +#pragma once + +#include "drivers/DisplayDriver.h" +#include "drivers/TouchDriver.h" + +void runApplication(DisplayDriver* display, TouchDriver* touch); diff --git a/ExternalApps/GraphicsDemo/main/Include/PixelBuffer.h b/ExternalApps/GraphicsDemo/main/Include/PixelBuffer.h new file mode 100644 index 00000000..c13b47fb --- /dev/null +++ b/ExternalApps/GraphicsDemo/main/Include/PixelBuffer.h @@ -0,0 +1,125 @@ +#pragma once + +#include +#include "drivers/Colors.h" + +#include +#include + +class PixelBuffer { + uint16_t pixelWidth; + uint16_t pixelHeight; + ColorFormat colorFormat; + uint8_t* data; + +public: + + PixelBuffer(uint16_t pixelWidth, uint16_t pixelHeight, ColorFormat colorFormat) : + pixelWidth(pixelWidth), + pixelHeight(pixelHeight), + colorFormat(colorFormat) + { + data = static_cast(malloc(pixelWidth * pixelHeight * getPixelSize())); + assert(data != nullptr); + } + + ~PixelBuffer() { + free(data); + } + + uint16_t getPixelWidth() const { + return pixelWidth; + } + + uint16_t getPixelHeight() const { + return pixelHeight; + } + + ColorFormat getColorFormat() const { + return colorFormat; + } + + void* getData() const { + return data; + } + + uint32_t getDataSize() const { + return pixelWidth * pixelHeight * getPixelSize(); + } + + void* getDataAtRow(uint16_t row) const { + auto address = reinterpret_cast(data) + (row * getRowDataSize()); + return reinterpret_cast(address); + } + + uint16_t getRowDataSize() const { + return pixelWidth * getPixelSize(); + } + + uint8_t getPixelSize() const { + switch (colorFormat) { + case COLOR_FORMAT_MONOCHROME: + return 1; + case COLOR_FORMAT_BGR565: + case COLOR_FORMAT_BGR565_SWAPPED: + case COLOR_FORMAT_RGB565: + case COLOR_FORMAT_RGB565_SWAPPED: + return 2; + case COLOR_FORMAT_RGB888: + return 3; + default: + // TODO: Crash with error + return 0; + } + } + + uint8_t* getPixelAddress(uint16_t x, uint16_t y) const { + uint32_t offset = ((y * getPixelWidth()) + x) * getPixelSize(); + uint32_t address = reinterpret_cast(data) + offset; + return reinterpret_cast(address); + } + + void setPixel(uint16_t x, uint16_t y, uint8_t r, uint8_t g, uint8_t b) const { + auto address = getPixelAddress(x, y); + switch (colorFormat) { + case COLOR_FORMAT_MONOCHROME: + *address = (uint8_t)((uint16_t)r + (uint16_t)g + (uint16_t)b / 3); + break; + case COLOR_FORMAT_BGR565: + Colors::rgb888ToBgr565(r, g, b, reinterpret_cast(address)); + break; + case COLOR_FORMAT_BGR565_SWAPPED: { + // TODO: Make proper conversion function + Colors::rgb888ToBgr565(r, g, b, reinterpret_cast(address)); + uint8_t temp = *address; + *address = *(address + 1); + *(address + 1) = temp; + break; + } + case COLOR_FORMAT_RGB565: { + Colors::rgb888ToRgb565(r, g, b, reinterpret_cast(address)); + break; + } + case COLOR_FORMAT_RGB565_SWAPPED: { + // TODO: Make proper conversion function + Colors::rgb888ToRgb565(r, g, b, reinterpret_cast(address)); + uint8_t temp = *address; + *address = *(address + 1); + *(address + 1) = temp; + break; + } + case COLOR_FORMAT_RGB888: { + uint8_t pixel[3] = { r, g, b }; + memcpy(address, pixel, 3); + break; + } + default: + // NO-OP + break; + } + } + + void clear(int value = 0) const { + memset(data, value, getDataSize()); + } +}; \ No newline at end of file diff --git a/ExternalApps/GraphicsDemo/main/Include/drivers/Colors.h b/ExternalApps/GraphicsDemo/main/Include/drivers/Colors.h new file mode 100644 index 00000000..d068574c --- /dev/null +++ b/ExternalApps/GraphicsDemo/main/Include/drivers/Colors.h @@ -0,0 +1,35 @@ +#pragma once + +class Colors { + +public: + + static void rgb888ToRgb565(uint8_t red, uint8_t green, uint8_t blue, uint16_t* rgb565) { + uint16_t _rgb565 = (red >> 3); + _rgb565 = (_rgb565 << 6) | (green >> 2); + _rgb565 = (_rgb565 << 5) | (blue >> 3); + *rgb565 = _rgb565; + } + + static void rgb888ToBgr565(uint8_t red, uint8_t green, uint8_t blue, uint16_t* bgr565) { + uint16_t _bgr565 = (blue >> 3); + _bgr565 = (_bgr565 << 6) | (green >> 2); + _bgr565 = (_bgr565 << 5) | (red >> 3); + *bgr565 = _bgr565; + } + + static void rgb565ToRgb888(uint16_t rgb565, uint32_t* rgb888) { + uint32_t _rgb565 = rgb565; + uint8_t b = (_rgb565 >> 8) & 0xF8; + uint8_t g = (_rgb565 >> 3) & 0xFC; + uint8_t r = (_rgb565 << 3) & 0xF8; + + uint8_t* r8p = reinterpret_cast(rgb888); + uint8_t* g8p = r8p + 1; + uint8_t* b8p = r8p + 2; + + *r8p = r | ((r >> 3) & 0x7); + *g8p = g | ((g >> 2) & 0x3); + *b8p = b | ((b >> 3) & 0x7); + } +}; \ No newline at end of file diff --git a/ExternalApps/GraphicsDemo/main/Include/drivers/DisplayDriver.h b/ExternalApps/GraphicsDemo/main/Include/drivers/DisplayDriver.h new file mode 100644 index 00000000..d699093f --- /dev/null +++ b/ExternalApps/GraphicsDemo/main/Include/drivers/DisplayDriver.h @@ -0,0 +1,48 @@ +#pragma once + +#include +#include + +/** + * Wrapper for tt_hal_display_driver_* + */ +class DisplayDriver { + + DisplayDriverHandle handle = nullptr; + +public: + + explicit DisplayDriver(DeviceId id) { + assert(tt_hal_display_driver_supported(id)); + handle = tt_hal_display_driver_alloc(id); + assert(handle != nullptr); + } + + ~DisplayDriver() { + tt_hal_display_driver_free(handle); + } + + bool lock(TickType timeout = MAX_TICKS) const { + return tt_hal_display_driver_lock(handle, timeout); + } + + void unlock() const { + tt_hal_display_driver_unlock(handle); + } + + uint16_t getWidth() const { + return tt_hal_display_driver_get_pixel_width(handle); + } + + uint16_t getHeight() const { + return tt_hal_display_driver_get_pixel_height(handle); + } + + ColorFormat getColorFormat() const { + return tt_hal_display_driver_get_colorformat(handle); + } + + void drawBitmap(int xStart, int yStart, int xEnd, int yEnd, const void* pixelData) const { + tt_hal_display_driver_draw_bitmap(handle, xStart, yStart, xEnd, yEnd, pixelData); + } +}; diff --git a/ExternalApps/GraphicsDemo/main/Include/drivers/TouchDriver.h b/ExternalApps/GraphicsDemo/main/Include/drivers/TouchDriver.h new file mode 100644 index 00000000..622f1260 --- /dev/null +++ b/ExternalApps/GraphicsDemo/main/Include/drivers/TouchDriver.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include + +/** + * Wrapper for tt_hal_touch_driver_* + */ +class TouchDriver { + + TouchDriverHandle handle = nullptr; + +public: + + explicit TouchDriver(DeviceId id) { + assert(tt_hal_touch_driver_supported(id)); + handle = tt_hal_touch_driver_alloc(id); + assert(handle != nullptr); + } + + ~TouchDriver() { + tt_hal_touch_driver_free(handle); + } + + bool getTouchedPoints(uint16_t* x, uint16_t* y, uint16_t* strength, uint8_t* count, uint8_t maxCount) const { + return tt_hal_touch_driver_get_touched_points(handle, x, y, strength, count, maxCount); + } +}; diff --git a/ExternalApps/GraphicsDemo/main/Source/Application.cpp b/ExternalApps/GraphicsDemo/main/Source/Application.cpp new file mode 100644 index 00000000..6594cf03 --- /dev/null +++ b/ExternalApps/GraphicsDemo/main/Source/Application.cpp @@ -0,0 +1,72 @@ +#include "Application.h" +#include "PixelBuffer.h" +#include "esp_log.h" + +#include + +constexpr auto TAG = "Application"; + +static bool isTouched(TouchDriver* touch) { + uint16_t x, y, strength; + uint8_t pointCount = 0; + return touch->getTouchedPoints(&x, &y, &strength, &pointCount, 1); +} + +void createRgbRow(PixelBuffer& buffer) { + uint8_t offset = buffer.getPixelWidth() / 3; + for (int i = 0; i < buffer.getPixelWidth(); ++i) { + if (i < offset) { + buffer.setPixel(i, 0, 255, 0, 0); + } else if (i < offset * 2) { + buffer.setPixel(i, 0, 0, 255, 0); + } else { + buffer.setPixel(i, 0, 0, 0, 255); + } + } +} + +void createRgbFadingRow(PixelBuffer& buffer) { + uint8_t stroke = buffer.getPixelWidth() / 3; + for (int i = 0; i < buffer.getPixelWidth(); ++i) { + if (i < stroke) { + auto color = i * 255 / stroke; + buffer.setPixel(i, 0, color, 0, 0); + } else if (i < stroke * 2) { + auto color = (i - stroke) * 255 / stroke; + buffer.setPixel(i, 0, 0, color, 0); + } else { + auto color = (i - (2*stroke)) * 255 / stroke; + buffer.setPixel(i, 0, 0, 0, color); + } + } +} + +void runApplication(DisplayDriver* display, TouchDriver* touch) { + // Single row buffers + PixelBuffer line_clear_buffer(display->getWidth(), 1, display->getColorFormat()); + line_clear_buffer.clear(); + PixelBuffer line_buffer(display->getWidth(), 1, display->getColorFormat()); + line_buffer.clear(); + + do { + // Draw row by row + // This is placed in a loop to test the SPI locking mechanismss + for (int i = 0; i < display->getHeight(); i++) { + + if (i == 0) { + createRgbRow(line_buffer); + } else if (i == display->getHeight() / 2) { + createRgbFadingRow(line_buffer); + } + + display->lock(); + display->drawBitmap(0, i, display->getWidth(), i + 1, line_buffer.getData()); + display->unlock(); + } + + // Give other tasks space to breathe + // SPI displays would otherwise time out SPI SD card access + tt_kernel_delay_ticks(1); + } while (!isTouched(touch)); +} + diff --git a/ExternalApps/GraphicsDemo/main/Source/Main.cpp b/ExternalApps/GraphicsDemo/main/Source/Main.cpp new file mode 100644 index 00000000..d25007ca --- /dev/null +++ b/ExternalApps/GraphicsDemo/main/Source/Main.cpp @@ -0,0 +1,71 @@ +#include "Application.h" +#include "drivers/DisplayDriver.h" +#include "drivers/TouchDriver.h" + +#include + +#include +#include + +constexpr auto TAG = "Main"; + +static void onCreate(AppHandle appHandle, void* data) { + uint16_t display_count = 0; + DeviceId display_id; + if (!tt_hal_device_find(DEVICE_TYPE_DISPLAY, &display_id, &display_count, 1)) { + ESP_LOGI(TAG, "No display device found"); + return; + } + + uint16_t touch_count = 0; + DeviceId touch_id; + if (!tt_hal_device_find(DEVICE_TYPE_TOUCH, &touch_id, &touch_count, 1)) { + ESP_LOGI(TAG, "No touch device found"); + return; + } + + // Stop LVGL first (because it's currently using the drivers we want to use) + tt_lvgl_stop(); + + ESP_LOGI(TAG, "Creating display driver"); + auto display = new DisplayDriver(display_id); + + ESP_LOGI(TAG, "Creating touch driver"); + auto touch = new TouchDriver(touch_id); + + // Run the main logic + ESP_LOGI(TAG, "Running application"); + runApplication(display, touch); + + ESP_LOGI(TAG, "Cleanup display driver"); + delete display; + + ESP_LOGI(TAG, "Cleanup touch driver"); + delete touch; + + ESP_LOGI(TAG, "Stopping application"); + tt_app_stop(); +} + +static void onDestroy(AppHandle appHandle, void* data) { + // Restart LVGL to resume rendering of regular apps + if (!tt_lvgl_is_started()) { + ESP_LOGI(TAG, "Restarting LVGL"); + tt_lvgl_start(); + } +} + +ExternalAppManifest manifest = { + .name = "Hello World", + .onCreate = onCreate, + .onDestroy = onDestroy +}; + +extern "C" { + +int main(int argc, char* argv[]) { + tt_app_register(&manifest); + return 0; +} + +} diff --git a/ExternalApps/GraphicsDemo/tactility.properties b/ExternalApps/GraphicsDemo/tactility.properties new file mode 100644 index 00000000..aa5aa4a2 --- /dev/null +++ b/ExternalApps/GraphicsDemo/tactility.properties @@ -0,0 +1,2 @@ +[sdk] +version = 0.4.0 diff --git a/ExternalApps/GraphicsDemo/tactility.py b/ExternalApps/GraphicsDemo/tactility.py new file mode 100644 index 00000000..a1ede4ea --- /dev/null +++ b/ExternalApps/GraphicsDemo/tactility.py @@ -0,0 +1,478 @@ +import configparser +import json +import os +import re +import shutil +import sys +import subprocess +import time +import urllib.request +import zipfile + +import requests + +# Targetable platforms that represent a specific hardware target +platform_targets = ["esp32", "esp32s3"] +# All valid platform commandline arguments +platform_arguments = platform_targets.copy() +platform_arguments.append("all") +ttbuild_path = ".tactility" +ttbuild_version = "1.2.1" +ttbuild_properties_file = "tactility.properties" +ttbuild_cdn = "https://cdn.tactility.one" +ttbuild_sdk_json_validity = 3600 # seconds +ttport = 6666 +verbose = False +use_local_sdk = False + +spinner_pattern = [ + "⠋", + "⠙", + "⠹", + "⠸", + "⠼", + "⠴", + "⠦", + "⠧", + "⠇", + "⠏" +] + +if sys.platform == "win32": + shell_color_red = "" + shell_color_orange = "" + shell_color_green = "" + shell_color_purple = "" + shell_color_cyan = "" + shell_color_reset = "" +else: + shell_color_red = "\033[91m" + shell_color_orange = "\033[93m" + shell_color_green = "\033[32m" + shell_color_purple = "\033[35m" + shell_color_cyan = "\033[36m" + shell_color_reset = "\033[m" + +def print_help(): + print("Usage: python tactility.py [action] [options]") + print("") + print("Actions:") + print(" build [esp32,esp32s3,all,local] Build the app for the specified platform") + print(" esp32: ESP32") + print(" esp32s3: ESP32 S3") + print(" all: all supported ESP platforms") + print(" clean Clean the build folders") + print(" clearcache Clear the SDK cache") + print(" updateself Update this tool") + print(" run [ip] [app id] Run an application") + print(" install [ip] [esp32,esp32s3] Install an application") + print("") + print("Options:") + print(" --help Show this commandline info") + print(" --local-sdk Use SDK specified by environment variable TACTILITY_SDK_PATH") + print(" --skip-build Run everything except the idf.py/CMake commands") + print(" --verbose Show extra console output") + +def download_file(url, filepath): + global verbose + if verbose: + print(f"Downloading from {url} to {filepath}") + request = urllib.request.Request( + url, + data=None, + headers={ + "User-Agent": f"Tactility Build Tool {ttbuild_version}" + } + ) + try: + response = urllib.request.urlopen(request) + file = open(filepath, mode="wb") + file.write(response.read()) + file.close() + return True + except OSError as error: + if verbose: + print_error(f"Failed to fetch URL {url}\n{error}") + return False + +def print_warning(message): + print(f"{shell_color_orange}WARNING: {message}{shell_color_reset}") + +def print_error(message): + print(f"{shell_color_red}ERROR: {message}{shell_color_reset}") + +def exit_with_error(message): + print_error(message) + sys.exit(1) + +def get_url(ip, path): + return f"http://{ip}:{ttport}{path}" + +def is_valid_platform_name(name): + global platform_arguments + return name in platform_arguments + +def validate_environment(): + global ttbuild_properties_file, use_local_sdk + if os.environ.get("IDF_PATH") is None: + exit_with_error("Cannot find the Espressif IDF SDK. Ensure it is installed and that it is activated via $PATH_TO_IDF_SDK/export.sh") + if not os.path.exists(ttbuild_properties_file): + exit_with_error(f"{ttbuild_properties_file} file not found") + if use_local_sdk == False and os.environ.get("TACTILITY_SDK_PATH") is not None: + print_warning("TACTILITY_SDK_PATH is set, but will be ignored by this command.") + print_warning("If you want to use it, use the 'build local' parameters.") + elif use_local_sdk == True and os.environ.get("TACTILITY_SDK_PATH") is None: + exit_with_error("local build was requested, but TACTILITY_SDK_PATH environment variable is not set.") + +def setup_environment(): + global ttbuild_path + os.makedirs(ttbuild_path, exist_ok=True) + +def get_sdk_dir(version, platform): + global use_local_sdk + if use_local_sdk: + return os.environ.get("TACTILITY_SDK_PATH") + else: + global ttbuild_cdn + return os.path.join(ttbuild_path, f"{version}-{platform}", "TactilitySDK") + +def get_sdk_version(): + global ttbuild_properties_file + parser = configparser.RawConfigParser() + parser.read(ttbuild_properties_file) + sdk_dict = dict(parser.items("sdk")) + if not "version" in sdk_dict: + exit_with_error(f"Could not find 'version' in [sdk] section in {ttbuild_properties_file}") + return sdk_dict["version"] + +def get_sdk_root_dir(version, platform): + global ttbuild_cdn + return os.path.join(ttbuild_path, f"{version}-{platform}") + +def get_sdk_url(version, platform): + global ttbuild_cdn + return f"{ttbuild_cdn}/TactilitySDK-{version}-{platform}.zip" + +def sdk_exists(version, platform): + sdk_dir = get_sdk_dir(version, platform) + return os.path.isdir(sdk_dir) + +def should_update_sdk_json(): + global ttbuild_cdn + json_filepath = os.path.join(ttbuild_path, "sdk.json") + if os.path.exists(json_filepath): + json_modification_time = os.path.getmtime(json_filepath) + now = time.time() + global ttbuild_sdk_json_validity + minimum_seconds_difference = ttbuild_sdk_json_validity + return (now - json_modification_time) > minimum_seconds_difference + else: + return True + +def update_sdk_json(): + global ttbuild_cdn, ttbuild_path + json_url = f"{ttbuild_cdn}/sdk.json" + json_filepath = os.path.join(ttbuild_path, "sdk.json") + return download_file(json_url, json_filepath) + +def should_fetch_sdkconfig_files(): + for platform in platform_targets: + sdkconfig_filename = f"sdkconfig.app.{platform}" + if not os.path.exists(os.path.join(ttbuild_path, sdkconfig_filename)): + return True + return False + +def fetch_sdkconfig_files(): + for platform in platform_targets: + sdkconfig_filename = f"sdkconfig.app.{platform}" + target_path = os.path.join(ttbuild_path, sdkconfig_filename) + if not download_file(f"{ttbuild_cdn}/{sdkconfig_filename}", target_path): + exit_with_error(f"Failed to download sdkconfig file for {platform}") + + +def validate_version_and_platforms(sdk_json, sdk_version, platforms_to_build): + version_map = sdk_json["versions"] + if not sdk_version in version_map: + exit_with_error(f"Version not found: {sdk_version}") + version_data = version_map[sdk_version] + available_platforms = version_data["platforms"] + for desired_platform in platforms_to_build: + if not desired_platform in available_platforms: + exit_with_error(f"Platform {desired_platform} is not available. Available ones: {available_platforms}") + +def validate_self(sdk_json): + if not "toolVersion" in sdk_json: + exit_with_error("Server returned invalid SDK data format (toolVersion not found)") + if not "toolCompatibility" in sdk_json: + exit_with_error("Server returned invalid SDK data format (toolCompatibility not found)") + if not "toolDownloadUrl" in sdk_json: + exit_with_error("Server returned invalid SDK data format (toolDownloadUrl not found)") + tool_version = sdk_json["toolVersion"] + tool_compatibility = sdk_json["toolCompatibility"] + if tool_version != ttbuild_version: + print_warning(f"New version available: {tool_version} (currently using {ttbuild_version})") + print_warning(f"Run 'tactility.py updateself' to update.") + if re.search(tool_compatibility, ttbuild_version) is None: + print_error("The tool is not compatible anymore.") + print_error("Run 'tactility.py updateself' to update.") + sys.exit(1) + +def sdk_download(version, platform): + sdk_root_dir = get_sdk_root_dir(version, platform) + os.makedirs(sdk_root_dir, exist_ok=True) + sdk_url = get_sdk_url(version, platform) + filepath = os.path.join(sdk_root_dir, f"{version}-{platform}.zip") + print(f"Downloading SDK version {version} for {platform}") + if download_file(sdk_url, filepath): + with zipfile.ZipFile(filepath, "r") as zip_ref: + zip_ref.extractall(os.path.join(sdk_root_dir, "TactilitySDK")) + return True + else: + return False + +def sdk_download_all(version, platforms): + for platform in platforms: + if not sdk_exists(version, platform): + if not sdk_download(version, platform): + return False + else: + if verbose: + print(f"Using cached download for SDK version {version} and platform {platform}") + return True + +def find_elf_file(platform): + build_dir = f"build-{platform}" + if os.path.exists(build_dir): + for file in os.listdir(build_dir): + if file.endswith(".app.elf"): + return os.path.join(build_dir, file) + return None + +def build_all(version, platforms, skip_build): + for platform in platforms: + # First build command must be "idf.py build", otherwise it fails to execute "idf.py elf" + # We check if the ELF file exists and run the correct command + # This can lead to code caching issues, so sometimes a clean build is required + if find_elf_file(platform) is None: + if not build_first(version, platform, skip_build): + break + else: + if not build_consecutively(version, platform, skip_build): + break + +def wait_for_build(process, platform): + buffer = [] + os.set_blocking(process.stdout.fileno(), False) + while process.poll() is None: + for i in spinner_pattern: + time.sleep(0.1) + progress_text = f"Building for {platform} {shell_color_cyan}" + str(i) + shell_color_reset + sys.stdout.write(progress_text + "\r") + while True: + line = process.stdout.readline() + decoded_line = line.decode("UTF-8") + if decoded_line != "": + buffer.append(decoded_line) + else: + break + return buffer + +# The first build must call "idf.py build" and consecutive builds must call "idf.py elf" as it finishes faster. +# The problem is that the "idf.py build" always results in an error, even though the elf file is created. +# The solution is to suppress the error if we find that the elf file was created. +def build_first(version, platform, skip_build): + sdk_dir = get_sdk_dir(version, platform) + if verbose: + print(f"Using SDK at {sdk_dir}") + os.environ["TACTILITY_SDK_PATH"] = sdk_dir + sdkconfig_path = os.path.join(ttbuild_path, f"sdkconfig.app.{platform}") + os.system(f"cp {sdkconfig_path} sdkconfig") + elf_path = find_elf_file(platform) + # Remove previous elf file: re-creation of the file is used to measure if the build succeeded, + # as the actual build job will always fail due to technical issues with the elf cmake script + if elf_path is not None: + os.remove(elf_path) + if skip_build: + return True + print("Building first build") + with subprocess.Popen(["idf.py", "-B", f"build-{platform}", "build"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) as process: + build_output = wait_for_build(process, platform) + # The return code is never expected to be 0 due to a bug in the elf cmake script, but we keep it just in case + if process.returncode == 0: + print(f"{shell_color_green}Building for {platform} ✅{shell_color_reset}") + return True + else: + if find_elf_file(platform) is None: + for line in build_output: + print(line, end="") + print(f"{shell_color_red}Building for {platform} failed ❌{shell_color_reset}") + return False + else: + print(f"{shell_color_green}Building for {platform} ✅{shell_color_reset}") + return True + +def build_consecutively(version, platform, skip_build): + sdk_dir = get_sdk_dir(version, platform) + if verbose: + print(f"Using SDK at {sdk_dir}") + os.environ["TACTILITY_SDK_PATH"] = sdk_dir + sdkconfig_path = os.path.join(ttbuild_path, f"sdkconfig.app.{platform}") + os.system(f"cp {sdkconfig_path} sdkconfig") + if skip_build: + return True + with subprocess.Popen(["idf.py", "-B", f"build-{platform}", "elf"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) as process: + build_output = wait_for_build(process, platform) + if process.returncode == 0: + print(f"{shell_color_green}Building for {platform} ✅{shell_color_reset}") + return True + else: + for line in build_output: + print(line, end="") + print(f"{shell_color_red}Building for {platform} failed ❌{shell_color_reset}") + return False + +def read_sdk_json(): + json_file_path = os.path.join(ttbuild_path, "sdk.json") + json_file = open(json_file_path) + return json.load(json_file) + +def build_action(platform_arg): + # Environment validation + validate_environment() + platforms_to_build = platform_targets if platform_arg == "all" else [platform_arg] + if not is_valid_platform_name(platform_arg): + print_help() + exit_with_error("Invalid platform name") + if not use_local_sdk: + if should_fetch_sdkconfig_files(): + fetch_sdkconfig_files() + sdk_json = read_sdk_json() + validate_self(sdk_json) + if not "versions" in sdk_json: + exit_with_error("Version data not found in sdk.json") + # Build + sdk_version = get_sdk_version() + if not use_local_sdk: + validate_version_and_platforms(sdk_json, sdk_version, platforms_to_build) + if not sdk_download_all(sdk_version, platforms_to_build): + exit_with_error("Failed to download one or more SDKs") + build_all(sdk_version, platforms_to_build, skip_build) # Environment validation + +def clean_action(): + count = 0 + for path in os.listdir("."): + if path.startswith("build-"): + print(f"Removing {path}/") + shutil.rmtree(path) + count = count + 1 + if count == 0: + print("Nothing to clean") + +def clear_cache_action(): + if os.path.exists(ttbuild_path): + print(f"Removing {ttbuild_path}/") + shutil.rmtree(ttbuild_path) + else: + print("Nothing to clear") + +def update_self_action(): + sdk_json = read_sdk_json() + tool_download_url = sdk_json["toolDownloadUrl"] + if download_file(tool_download_url, "tactility.py"): + print("Updated") + else: + exit_with_error("Update failed") + +def get_device_info(ip): + print(f"Getting device info from {ip}") + url = get_url(ip, "/info") + try: + response = requests.get(url) + if response.status_code != 200: + print_error("Run failed") + else: + print(response.json()) + print(f"{shell_color_green}Run successful ✅{shell_color_reset}") + except requests.RequestException as e: + print(f"Request failed: {e}") + +def run_action(ip, app_id): + print(f"Running {app_id} on {ip}") + url = get_url(ip, "/app/run") + params = {'id': app_id} + try: + response = requests.post(url, params=params) + if response.status_code != 200: + print_error("Run failed") + else: + print(f"{shell_color_green}Run successful ✅{shell_color_reset}") + except requests.RequestException as e: + print(f"Request failed: {e}") + +def install_action(ip, platform): + file_path = find_elf_file(platform) + if file_path is None: + print_error(f"File not found: {file_path}") + return + print(f"Installing {file_path} to {ip}") + url = get_url(ip, "/app/install") + try: + # Prepare multipart form data + with open(file_path, 'rb') as file: + files = { + 'elf': file + } + response = requests.put(url, files=files) + if response.status_code != 200: + print_error("Install failed") + else: + print(f"{shell_color_green}Installation successful ✅{shell_color_reset}") + except requests.RequestException as e: + print_error(f"Installation failed: {e}") + except IOError as e: + print_error(f"File error: {e}") + + +if __name__ == "__main__": + print(f"Tactility Build System v{ttbuild_version}") + if "--help" in sys.argv: + print_help() + sys.exit() + # Argument validation + if len(sys.argv) == 1: + print_help() + sys.exit() + action_arg = sys.argv[1] + verbose = "--verbose" in sys.argv + skip_build = "--skip-build" in sys.argv + use_local_sdk = "--local-sdk" in sys.argv + # Environment setup + setup_environment() + # Update SDK cache (sdk.json) + if should_update_sdk_json() and not update_sdk_json(): + exit_with_error("Failed to retrieve SDK info") + # Actions + if action_arg == "build": + if len(sys.argv) < 3: + print_help() + exit_with_error("Commandline parameter missing") + build_action(sys.argv[2]) + elif action_arg == "clean": + clean_action() + elif action_arg == "clearcache": + clear_cache_action() + elif action_arg == "updateself": + update_self_action() + elif action_arg == "run": + if len(sys.argv) < 4: + print_help() + exit_with_error("Commandline parameter missing") + run_action(sys.argv[2], sys.argv[3]) + elif action_arg == "install": + if len(sys.argv) < 4: + print_help() + exit_with_error("Commandline parameter missing") + install_action(sys.argv[2], sys.argv[3]) + else: + print_help() + exit_with_error("Unknown commandline parameter") diff --git a/Tactility/Include/Tactility/hal/Device.h b/Tactility/Include/Tactility/hal/Device.h index 864550ca..abccbb09 100644 --- a/Tactility/Include/Tactility/hal/Device.h +++ b/Tactility/Include/Tactility/hal/Device.h @@ -95,6 +95,8 @@ std::vector> findDevices(Device::Type type) { } } +void findDevices(Device::Type type, std::function&)> onDeviceFound); + /** Find the first device of the specified type and cast it to the specified class */ template std::shared_ptr findFirstDevice(Device::Type type) { diff --git a/Tactility/Include/Tactility/hal/display/DisplayDriver.h b/Tactility/Include/Tactility/hal/display/DisplayDriver.h index a8cd4bed..a11328cb 100644 --- a/Tactility/Include/Tactility/hal/display/DisplayDriver.h +++ b/Tactility/Include/Tactility/hal/display/DisplayDriver.h @@ -1,5 +1,6 @@ #pragma once +#include #include namespace tt::hal::display { @@ -7,7 +8,9 @@ namespace tt::hal::display { enum class ColorFormat { Monochrome, // 1 bpp BGR565, + BGR565Swapped, RGB565, + RGB565Swapped, RGB888 }; @@ -21,6 +24,7 @@ public: virtual uint16_t getPixelWidth() const = 0; virtual uint16_t getPixelHeight() const = 0; virtual bool drawBitmap(int xStart, int yStart, int xEnd, int yEnd, const void* pixelData) = 0; + virtual std::shared_ptr getLock() const = 0; }; } \ No newline at end of file diff --git a/Tactility/Source/hal/Device.cpp b/Tactility/Source/hal/Device.cpp index 21d8a548..c9dc4002 100644 --- a/Tactility/Source/hal/Device.cpp +++ b/Tactility/Source/hal/Device.cpp @@ -88,6 +88,15 @@ std::vector> findDevices(Device::Type type) { }); } +void findDevices(Device::Type type, std::function&)> onDeviceFound) { + auto devices_view = findDevices(type); + for (auto& device : devices_view) { + if (!onDeviceFound(device)) { + break; + } + } +} + std::vector> getDevices() { return devices; } diff --git a/Tactility/Source/lvgl/Statusbar.cpp b/Tactility/Source/lvgl/Statusbar.cpp index 8bf8d8c2..7e9e39b1 100644 --- a/Tactility/Source/lvgl/Statusbar.cpp +++ b/Tactility/Source/lvgl/Statusbar.cpp @@ -64,7 +64,7 @@ static void update_main(Statusbar* statusbar); static TickType_t getNextUpdateTime() { time_t now = ::time(nullptr); - struct tm* tm_struct = localtime(&now); + tm* tm_struct = localtime(&now); uint32_t seconds_to_wait = 60U - tm_struct->tm_sec; TT_LOG_D(TAG, "Update in %lu s", seconds_to_wait); return pdMS_TO_TICKS(seconds_to_wait * 1000U); @@ -72,7 +72,7 @@ static TickType_t getNextUpdateTime() { static void onUpdateTime() { time_t now = ::time(nullptr); - struct tm* tm_struct = localtime(&now); + tm* tm_struct = localtime(&now); if (statusbar_data.mutex.lock(100 / portTICK_PERIOD_MS)) { if (tm_struct->tm_year >= (2025 - 1900)) { diff --git a/TactilityC/Include/tt_hal_device.h b/TactilityC/Include/tt_hal_device.h new file mode 100644 index 00000000..e08c167c --- /dev/null +++ b/TactilityC/Include/tt_hal_device.h @@ -0,0 +1,33 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +enum DeviceType { + DEVICE_TYPE_I2C, + DEVICE_TYPE_DISPLAY, + DEVICE_TYPE_TOUCH, + DEVICE_TYPE_SDCARD, + DEVICE_TYPE_KEYBOARD, + DEVICE_TYPE_POWER, + DEVICE_TYPE_GPS +}; + +typedef uint32_t DeviceId; + +/** + * Find one or more devices of a certain type. + * @param[in] type the type to look for + * @param[inout] deviceIds the output ids, which should fit at least maxCount amount of devices + * @param[out] count the resulting number of device ids that were returned + * @param[in] maxCount the maximum number of items that the "deviceIds" output can contain (minimum value is 1) + * @return true if one or more devices were found + */ +bool tt_hal_device_find(DeviceType type, DeviceId* deviceIds, uint16_t* count, uint16_t maxCount); + +#ifdef __cplusplus +} +#endif diff --git a/TactilityC/Include/tt_hal_display.h b/TactilityC/Include/tt_hal_display.h new file mode 100644 index 00000000..36dd90d7 --- /dev/null +++ b/TactilityC/Include/tt_hal_display.h @@ -0,0 +1,91 @@ +#pragma once + +#include + +#include "tt_hal_device.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void* DisplayDriverHandle; + +enum ColorFormat { + COLOR_FORMAT_MONOCHROME, // 1 bpp + COLOR_FORMAT_BGR565, + COLOR_FORMAT_BGR565_SWAPPED, + COLOR_FORMAT_RGB565, + COLOR_FORMAT_RGB565_SWAPPED, + COLOR_FORMAT_RGB888 +}; + +/** + * Check if the display driver interface is supported for this device. + * @param[in] displayId the identifier of the display device + * @return true if the driver is supported. + */ +bool tt_hal_display_driver_supported(DeviceId displayId); + +/** + * Allocate a driver object for the specified displayId. + * @warning check whether the driver is supported by calling tt_hal_display_driver_supported() first + * @param[in] displayId the identifier of the display device + * @return the driver handle + */ +DisplayDriverHandle tt_hal_display_driver_alloc(DeviceId displayId); + +/** + * Free the memory for the display driver. + * @param[in] handle the display driver handle + */ +void tt_hal_display_driver_free(DisplayDriverHandle handle); + +/** + * Lock the display device. Call this function before doing any draw calls. + * Certain display devices are on a shared bus (e.g. SPI) so they must run + * mutually exclusive with other devices on the same bus (e.g. SD card) + * @param[in] handle the display driver handle + * @param[in] timeout the maximum amount of ticks to wait for getting a lock + * @return true if the lock was acquired + */ +bool tt_hal_display_driver_lock(DisplayDriverHandle handle, TickType timeout); + +/** + * Unlock the display device. Must be called exactly once after locking. + * @param[in] handle the display driver handle + */ +void tt_hal_display_driver_unlock(DisplayDriverHandle handle); + +/** + * @param[in] handle the display driver handle + * @return the native color format for this display + */ +ColorFormat tt_hal_display_driver_get_colorformat(DisplayDriverHandle handle); + +/** + * @param[in] handle the display driver handle + * @return the horizontal resolution of the display + */ +uint16_t tt_hal_display_driver_get_pixel_width(DisplayDriverHandle handle); + +/** + * @param[in] handle the display driver handle + * @return the vertical resolution of the display + */ +uint16_t tt_hal_display_driver_get_pixel_height(DisplayDriverHandle handle); + +/** + * Draw pixels on the screen. Make sure to call the lock function first and unlock afterwards. + * Many draw calls can be done inbetween a single lock and unlock. + * @param[in] handle the display driver handle + * @param[in] xStart the starting x coordinate for rendering the pixel data + * @param[in] yStart the starting y coordinate for rendering the pixel data + * @param[in] xEnd the last x coordinate for rendering the pixel data (absolute pixel value, not relative to xStart!) + * @param[in] yEnd the last y coordinate for rendering the pixel data (absolute pixel value, not relative to yStart!) + * @param[in] pixelData a buffer of pixels. the data is placed as "RowRowRowRow". The size depends on the ColorFormat + */ +void tt_hal_display_driver_draw_bitmap(DisplayDriverHandle handle, int xStart, int yStart, int xEnd, int yEnd, const void* pixelData); + +#ifdef __cplusplus +} +#endif diff --git a/TactilityC/Include/tt_hal_touch.h b/TactilityC/Include/tt_hal_touch.h new file mode 100644 index 00000000..904aa387 --- /dev/null +++ b/TactilityC/Include/tt_hal_touch.h @@ -0,0 +1,47 @@ +#pragma once + +#include "tt_hal_device.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void* TouchDriverHandle; +/** + * Check if the touch driver interface is supported for this device. + * @param[in] touchDeviceId the identifier of the touch device + * @return true if the driver is supported. + */ +bool tt_hal_touch_driver_supported(DeviceId touchDeviceId); + +/** + * Allocate a driver object for the specified touchDeviceId. + * @warning check whether the driver is supported by calling tt_hal_touch_driver_supported() first + * @param[in] touchDeviceId the identifier of the touch device + * @return the driver handle + */ +TouchDriverHandle tt_hal_touch_driver_alloc(DeviceId touchDeviceId); + +/** + * Free the memory for the touch driver. + * @param[in] handle the touch driver handle + */ +void tt_hal_touch_driver_free(TouchDriverHandle handle); + +/** + * Get the coordinates for the currently touched points on the screen. + * + * @param[in] handle the touch driver handle + * @param[in] x array of X coordinates + * @param[in] y array of Y coordinates + * @param[in] strength array of strengths (with the minimum size of maxPointCount) or NULL + * @param[in] pointCount the number of points currently touched on the screen + * @param[in] maxPointCount the maximum number of points that can be touched at once + * + * @return true when touched and coordinates are available + */ +bool tt_hal_touch_driver_get_touched_points(TouchDriverHandle handle, uint16_t* x, uint16_t* y, uint16_t* strength, uint8_t* pointCount, uint8_t maxPointCount); + +#ifdef __cplusplus +} +#endif diff --git a/TactilityC/Include/tt_kernel.h b/TactilityC/Include/tt_kernel.h new file mode 100644 index 00000000..c399b200 --- /dev/null +++ b/TactilityC/Include/tt_kernel.h @@ -0,0 +1,50 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned long TickType; + +/** + * Stall the current task for the specified amount of time. + * @param milliseconds the time in milliseconds to stall. + */ +void tt_kernel_delay_millis(uint32_t milliseconds); + +/** + * Stall the current task for the specified amount of time. + * @param milliseconds the time in microsends to stall. + */ +void tt_kernel_delay_micros(uint32_t microSeconds); + +/** + * Stall the current task for the specified amount of time. + * @param milliseconds the time in ticks to stall. + */ +void tt_kernel_delay_ticks(TickType ticks); + +/** @return the number of ticks since the device was started */ +TickType tt_kernel_get_ticks(); + +/** Convert milliseconds to ticks */ +TickType tt_kernel_millis_to_ticks(uint32_t milliSeconds); + +/** Stall the current task until the specified timestamp + * @return false if for some reason the delay was broken off + */ +bool tt_kernel_delay_until_tick(TickType tick); + +/** @return the tick frequency of the kernel (commonly 1000 Hz when running FreeRTOS) */ +uint32_t tt_kernel_get_tick_frequency(); + +/** @return the number of milliseconds that have passed since the device was started */ +uint32_t tt_kernel_get_millis(); + +unsigned long tt_kernel_get_micros(); + +#ifdef __cplusplus +} +#endif diff --git a/TactilityC/Include/tt_lvgl.h b/TactilityC/Include/tt_lvgl.h new file mode 100644 index 00000000..89572141 --- /dev/null +++ b/TactilityC/Include/tt_lvgl.h @@ -0,0 +1,18 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +/** @return true if LVGL is started and active */ +bool tt_lvgl_is_started(); + +/** Start LVGL and related background services */ +void tt_lvgl_start(); + +/** Stop LVGL and related background services */ +void tt_lvgl_stop(); + +#ifdef __cplusplus +} +#endif diff --git a/TactilityC/Source/tt_hal_device.cpp b/TactilityC/Source/tt_hal_device.cpp new file mode 100644 index 00000000..1ba090dc --- /dev/null +++ b/TactilityC/Source/tt_hal_device.cpp @@ -0,0 +1,48 @@ +#include "tt_hal_device.h" + +#include "Tactility/Check.h" + +#include + +static tt::hal::Device::Type toTactilityDeviceType(DeviceType type) { + switch (type) { + case DEVICE_TYPE_I2C: + return tt::hal::Device::Type::I2c; + case DEVICE_TYPE_DISPLAY: + return tt::hal::Device::Type::Display; + case DEVICE_TYPE_TOUCH: + return tt::hal::Device::Type::Touch; + case DEVICE_TYPE_SDCARD: + return tt::hal::Device::Type::SdCard; + case DEVICE_TYPE_KEYBOARD: + return tt::hal::Device::Type::Keyboard; + case DEVICE_TYPE_POWER: + return tt::hal::Device::Type::Power; + case DEVICE_TYPE_GPS: + return tt::hal::Device::Type::Gps; + default: + tt_crash("Device::Type not supported"); + } +} + +extern "C" { + +bool tt_hal_device_find(DeviceType type, DeviceId* deviceIds, uint16_t* count, uint16_t maxCount) { + assert(maxCount > 0); + + int16_t currentIndex = -1; + uint16_t maxIndex = maxCount - 1; + + findDevices(toTactilityDeviceType(type), [&](const std::shared_ptr& device) { + currentIndex++; + deviceIds[currentIndex] = device->getId(); + // Continue if there is storage capacity left + return currentIndex < maxIndex; + }); + + *count = currentIndex + 1; + + return currentIndex >= 0; +} + +} diff --git a/TactilityC/Source/tt_hal_display.cpp b/TactilityC/Source/tt_hal_display.cpp new file mode 100644 index 00000000..008f7479 --- /dev/null +++ b/TactilityC/Source/tt_hal_display.cpp @@ -0,0 +1,88 @@ +#include "tt_hal_display.h" + +#include "Tactility/Check.h" +#include "Tactility/hal/Device.h" +#include "Tactility/hal/display/DisplayDevice.h" +#include "Tactility/hal/display/DisplayDriver.h" + +static ColorFormat toColorFormat(tt::hal::display::ColorFormat format) { + switch (format) { + case tt::hal::display::ColorFormat::Monochrome: + return COLOR_FORMAT_MONOCHROME; + case tt::hal::display::ColorFormat::BGR565: + return COLOR_FORMAT_BGR565; + case tt::hal::display::ColorFormat::BGR565Swapped: + return COLOR_FORMAT_BGR565_SWAPPED; + case tt::hal::display::ColorFormat::RGB565: + return COLOR_FORMAT_RGB565; + case tt::hal::display::ColorFormat::RGB565Swapped: + return COLOR_FORMAT_RGB565_SWAPPED; + case tt::hal::display::ColorFormat::RGB888: + return COLOR_FORMAT_RGB888; + default: + tt_crash("ColorFormat not supported"); + } +} + +struct DriverWrapper { + std::shared_ptr driver; + DriverWrapper(std::shared_ptr driver) : driver(driver) {} +}; + +static std::shared_ptr findValidDisplayDevice(tt::hal::Device::Id id) { + auto device = tt::hal::findDevice(id); + if (device == nullptr || device->getType() != tt::hal::Device::Type::Display) { + return nullptr; + } + return std::reinterpret_pointer_cast(device); +} + +extern "C" { + +bool tt_hal_display_driver_supported(DeviceId id) { + auto display = findValidDisplayDevice(id); + return display != nullptr && display->supportsDisplayDriver(); +} + +DisplayDriverHandle tt_hal_display_driver_alloc(DeviceId id) { + auto display = findValidDisplayDevice(id); + assert(display->supportsDisplayDriver()); + return new DriverWrapper(display->getDisplayDriver()); +} + +void tt_hal_display_driver_free(DisplayDriverHandle handle) { + auto wrapper = static_cast(handle); + delete wrapper; +} + +bool tt_hal_display_driver_lock(DisplayDriverHandle handle, TickType timeout) { + auto wrapper = static_cast(handle); + return wrapper->driver->getLock()->lock(timeout); +} + +void tt_hal_display_driver_unlock(DisplayDriverHandle handle) { + auto wrapper = static_cast(handle); + wrapper->driver->getLock()->unlock(); +} + +ColorFormat tt_hal_display_driver_get_colorformat(DisplayDriverHandle handle) { + auto wrapper = static_cast(handle); + return toColorFormat(wrapper->driver->getColorFormat()); +} + +uint16_t tt_hal_display_driver_get_pixel_width(DisplayDriverHandle handle) { + auto wrapper = static_cast(handle); + return wrapper->driver->getPixelWidth(); +} + +uint16_t tt_hal_display_driver_get_pixel_height(DisplayDriverHandle handle) { + auto wrapper = static_cast(handle); + return wrapper->driver->getPixelHeight(); +} + +void tt_hal_display_driver_draw_bitmap(DisplayDriverHandle handle, int xStart, int yStart, int xEnd, int yEnd, const void* pixelData) { + auto wrapper = static_cast(handle); + wrapper->driver->drawBitmap(xStart, yStart, xEnd, yEnd, pixelData); +} + +} \ No newline at end of file diff --git a/TactilityC/Source/tt_hal_touch.cpp b/TactilityC/Source/tt_hal_touch.cpp new file mode 100644 index 00000000..d28089f8 --- /dev/null +++ b/TactilityC/Source/tt_hal_touch.cpp @@ -0,0 +1,43 @@ +#include "tt_hal_touch.h" + +#include "Tactility/hal/Device.h" +#include "Tactility/hal/touch/TouchDevice.h" +#include "Tactility/hal/touch/TouchDriver.h" + +struct DriverWrapper { + std::shared_ptr driver; + DriverWrapper(std::shared_ptr driver) : driver(driver) {} +}; + +static std::shared_ptr findValidTouchDevice(tt::hal::Device::Id id) { + auto device = tt::hal::findDevice(id); + if (device == nullptr || device->getType() != tt::hal::Device::Type::Touch) { + return nullptr; + } + return std::reinterpret_pointer_cast(device); +} + +extern "C" { + +bool tt_hal_touch_driver_supported(DeviceId id) { + auto touch = findValidTouchDevice(id); + return touch != nullptr && touch->supportsTouchDriver(); +} + +TouchDriverHandle tt_hal_touch_driver_alloc(DeviceId id) { + auto touch = findValidTouchDevice(id); + assert(touch->supportsTouchDriver()); + return new DriverWrapper(touch->getTouchDriver()); +} + +void tt_hal_touch_driver_free(TouchDriverHandle handle) { + DriverWrapper* wrapper = static_cast(handle); + delete wrapper; +} + +bool tt_hal_touch_driver_get_touched_points(TouchDriverHandle handle, uint16_t* x, uint16_t* y, uint16_t* _Nullable strength, uint8_t* pointCount, uint8_t maxPointCount) { + DriverWrapper* wrapper = static_cast(handle); + return wrapper->driver->getTouchedPoints(x, y, strength, pointCount, maxPointCount); +} + +} diff --git a/TactilityC/Source/tt_init.cpp b/TactilityC/Source/tt_init.cpp index 55139462..8a2142d5 100644 --- a/TactilityC/Source/tt_init.cpp +++ b/TactilityC/Source/tt_init.cpp @@ -6,7 +6,12 @@ #include "tt_app_selectiondialog.h" #include "tt_bundle.h" #include "tt_gps.h" +#include "tt_hal_device.h" +#include "tt_hal_display.h" #include "tt_hal_i2c.h" +#include "tt_hal_touch.h" +#include "tt_kernel.h" +#include "tt_lvgl.h" #include "tt_lvgl_keyboard.h" #include "tt_lvgl_spinner.h" #include "tt_lvgl_toolbar.h" @@ -103,6 +108,9 @@ const esp_elfsym elf_symbols[] { ESP_ELFSYM_EXPORT(esp_log_write), ESP_ELFSYM_EXPORT(esp_log_timestamp), // Tactility + ESP_ELFSYM_EXPORT(tt_app_start), + ESP_ELFSYM_EXPORT(tt_app_start_with_bundle), + ESP_ELFSYM_EXPORT(tt_app_stop), ESP_ELFSYM_EXPORT(tt_app_register), ESP_ELFSYM_EXPORT(tt_app_get_parameters), ESP_ELFSYM_EXPORT(tt_app_set_result), @@ -121,6 +129,16 @@ const esp_elfsym elf_symbols[] { ESP_ELFSYM_EXPORT(tt_bundle_put_string), ESP_ELFSYM_EXPORT(tt_gps_has_coordinates), ESP_ELFSYM_EXPORT(tt_gps_get_coordinates), + ESP_ELFSYM_EXPORT(tt_hal_device_find), + ESP_ELFSYM_EXPORT(tt_hal_display_driver_alloc), + ESP_ELFSYM_EXPORT(tt_hal_display_driver_draw_bitmap), + ESP_ELFSYM_EXPORT(tt_hal_display_driver_free), + ESP_ELFSYM_EXPORT(tt_hal_display_driver_get_colorformat), + ESP_ELFSYM_EXPORT(tt_hal_display_driver_get_pixel_height), + ESP_ELFSYM_EXPORT(tt_hal_display_driver_get_pixel_width), + ESP_ELFSYM_EXPORT(tt_hal_display_driver_lock), + ESP_ELFSYM_EXPORT(tt_hal_display_driver_unlock), + ESP_ELFSYM_EXPORT(tt_hal_display_driver_supported), ESP_ELFSYM_EXPORT(tt_hal_i2c_start), ESP_ELFSYM_EXPORT(tt_hal_i2c_stop), ESP_ELFSYM_EXPORT(tt_hal_i2c_is_started), @@ -132,6 +150,22 @@ const esp_elfsym elf_symbols[] { ESP_ELFSYM_EXPORT(tt_hal_i2c_master_has_device_at_address), ESP_ELFSYM_EXPORT(tt_hal_i2c_lock), ESP_ELFSYM_EXPORT(tt_hal_i2c_unlock), + ESP_ELFSYM_EXPORT(tt_hal_touch_driver_supported), + ESP_ELFSYM_EXPORT(tt_hal_touch_driver_alloc), + ESP_ELFSYM_EXPORT(tt_hal_touch_driver_free), + ESP_ELFSYM_EXPORT(tt_hal_touch_driver_get_touched_points), + ESP_ELFSYM_EXPORT(tt_kernel_delay_millis), + ESP_ELFSYM_EXPORT(tt_kernel_delay_micros), + ESP_ELFSYM_EXPORT(tt_kernel_delay_ticks), + ESP_ELFSYM_EXPORT(tt_kernel_get_ticks), + ESP_ELFSYM_EXPORT(tt_kernel_millis_to_ticks), + ESP_ELFSYM_EXPORT(tt_kernel_delay_until_tick), + ESP_ELFSYM_EXPORT(tt_kernel_get_tick_frequency), + ESP_ELFSYM_EXPORT(tt_kernel_get_millis), + ESP_ELFSYM_EXPORT(tt_kernel_get_micros), + ESP_ELFSYM_EXPORT(tt_lvgl_is_started), + ESP_ELFSYM_EXPORT(tt_lvgl_start), + ESP_ELFSYM_EXPORT(tt_lvgl_stop), ESP_ELFSYM_EXPORT(tt_lvgl_software_keyboard_show), ESP_ELFSYM_EXPORT(tt_lvgl_software_keyboard_hide), ESP_ELFSYM_EXPORT(tt_lvgl_software_keyboard_is_enabled), diff --git a/TactilityC/Source/tt_kernel.cpp b/TactilityC/Source/tt_kernel.cpp new file mode 100644 index 00000000..46c1b632 --- /dev/null +++ b/TactilityC/Source/tt_kernel.cpp @@ -0,0 +1,42 @@ +#include "tt_kernel.h" +#include + +extern "C" { + +void tt_kernel_delay_millis(uint32_t milliseconds) { + tt::kernel::delayMillis(milliseconds); +} + +void tt_kernel_delay_micros(uint32_t microSeconds) { + tt::kernel::delayMicros(microSeconds); +} + +void tt_kernel_delay_ticks(TickType ticks) { + tt::kernel::delayTicks((TickType_t)ticks); +} + +TickType tt_kernel_get_ticks() { + return tt::kernel::getTicks(); +} + +TickType tt_kernel_millis_to_ticks(uint32_t milliSeconds) { + return tt::kernel::millisToTicks(milliSeconds); +} + +bool tt_kernel_delay_until_tick(TickType tick) { + return tt::kernel::delayUntilTick(tick); +} + +uint32_t tt_kernel_get_tick_frequency() { + return tt::kernel::getTickFrequency(); +} + +uint32_t tt_kernel_get_millis() { + return tt::kernel::getMillis(); +} + +unsigned long tt_kernel_get_micros() { + return tt::kernel::getMicros(); +} + +} \ No newline at end of file diff --git a/TactilityC/Source/tt_lvgl.cpp b/TactilityC/Source/tt_lvgl.cpp new file mode 100644 index 00000000..f7bf8a6c --- /dev/null +++ b/TactilityC/Source/tt_lvgl.cpp @@ -0,0 +1,17 @@ +#include + +extern "C" { + +bool tt_lvgl_is_started() { + return tt::lvgl::isStarted(); +} + +void tt_lvgl_start() { + tt::lvgl::start(); +} + +void tt_lvgl_stop() { + tt::lvgl::stop(); +} + +}