Touch and display driver subsystems reworked (and more) (#302)

- Refactored `TouchDevice`: it can now start/stop LVGL separately, and it has an optional `TouchDriver` interface
- Refactored `DisplayDevice`: it can now start/stop LVGL separately, and it has an optional `DisplayDriver` interface
- Updated all boards and drivers for above changes
- LVGL can now be stopped and (re)started on the fly
- Fixed issues with restarting Gui and Statusbar services
- Refactored `Gui` service to be class and renamed `Gui` to `GuiService`
- Fixed `Statusbar` service: forgot to deregister one of the icons
- Updated `esp_lcd_st7701` to v1.1.3
- `lv_textarea_create()` now automatically registers the hardware keyboard hooks (by wrapping the function)
- Fixed and updated `tactility.py`
- Cleanup of a lot of code
- `BootInitLvglBegin` and `BootInitLvglEnd` are replaced by `LvglStarted` and `LvglStopped`.
- Introduced `tt::service::State` which is accessible via `tt::service::getState()` (and internally via `ServiceInstance`)
- Started replacing `#define TAG` with `constexpr auto TAG = "..";`
This commit is contained in:
Ken Van Hoeylandt 2025-08-16 20:22:49 +02:00 committed by GitHub
parent 15f4fbfdc6
commit d875ade8cb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
127 changed files with 1907 additions and 1605 deletions

View File

@ -5,7 +5,7 @@
#include "tt_init.h"
#endif
// extern const tt::app::AppManifest hello_world_app;
extern const tt::app::AppManifest hello_world_app;
extern "C" {

View File

@ -9,7 +9,7 @@ dependencies:
espressif/esp_io_expander: "1.0.1"
espressif/esp_io_expander_tca95xx_16bit: "1.0.1"
espressif/esp_lcd_st7701:
version: "1.1.1"
version: "1.1.3"
rules:
- if: "target in [esp32s3, esp32p4]"
espressif/esp_lcd_st7796:

View File

@ -32,5 +32,6 @@ std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay() {
configuration->mirrorX = true;
configuration->backlightDutyFunction = driver::pwmbacklight::setBacklightDuty;
return std::make_shared<Ili934xDisplay>(std::move(configuration));
auto display = std::make_shared<Ili934xDisplay>(std::move(configuration));
return std::reinterpret_pointer_cast<tt::hal::display::DisplayDevice>(display);
}

View File

@ -14,7 +14,7 @@ bool initBoot() {
// This display has a weird glitch with gamma during boot, which results in uneven dark gray colours.
// Setting gamma curve index to 0 doesn't work at boot for an unknown reason, so we set the curve index to 1:
tt::kernel::subscribeSystemEvent(tt::kernel::SystemEvent::BootInitLvglEnd, [](auto event) {
tt::kernel::subscribeSystemEvent(tt::kernel::SystemEvent::BootSplash, [](auto) {
auto display = tt::hal::findFirstDevice<tt::hal::display::DisplayDevice>(tt::hal::Device::Type::Display);
assert(display != nullptr);
tt::lvgl::lock(portMAX_DELAY);

View File

@ -35,5 +35,6 @@ std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay() {
configuration->backlightDutyFunction = driver::pwmbacklight::setBacklightDuty;
return std::make_shared<Ili934xDisplay>(std::move(configuration));
auto display = std::make_shared<Ili934xDisplay>(std::move(configuration));
return std::reinterpret_pointer_cast<tt::hal::display::DisplayDevice>(display);
}

View File

@ -3,5 +3,5 @@ file(GLOB_RECURSE SOURCE_FILES Source/*.c*)
idf_component_register(
SRCS ${SOURCE_FILES}
INCLUDE_DIRS "Source"
REQUIRES Tactility esp_lvgl_port esp_lcd esp_lcd_st7701 esp_lcd_panel_io_additions GT911 PwmBacklight driver vfs fatfs
REQUIRES Tactility EspLcdCompat esp_lcd_st7701 esp_lcd_panel_io_additions GT911 PwmBacklight driver vfs fatfs
)

View File

@ -1,19 +1,17 @@
#include "CydDisplay.h"
#include "PwmBacklight.h"
#include <Gt911Touch.h>
#include <PwmBacklight.h>
#include <Tactility/Log.h>
#include <driver/gpio.h>
#include <esp_err.h>
#include <esp_lcd_panel_rgb.h>
#include <esp_lcd_panel_ops.h>
#include <esp_lcd_panel_io.h>
#include <esp_lcd_panel_io_additions.h>
#include <esp_lcd_st7701.h>
#include <esp_lvgl_port.h>
#define TAG "cyd_display"
constexpr auto TAG = "ST7701";
static const st7701_lcd_init_cmd_t st7701_lcd_init_cmds[] = {
// {cmd, { data }, data_size, delay_ms}
@ -58,9 +56,7 @@ static const st7701_lcd_init_cmd_t st7701_lcd_init_cmds[] = {
{0x29, (uint8_t[]) {0x00}, 0, 0}, //Display On
};
bool CydDisplay::start() {
TT_LOG_I(TAG, "Starting");
bool CydDisplay::createIoHandle(esp_lcd_panel_io_handle_t& outHandle) {
spi_line_config_t line_config = {
.cs_io_type = IO_TYPE_GPIO,
.cs_gpio_num = GPIO_NUM_39,
@ -68,11 +64,13 @@ bool CydDisplay::start() {
.scl_gpio_num = GPIO_NUM_48,
.sda_io_type = IO_TYPE_GPIO,
.sda_gpio_num = GPIO_NUM_47,
.io_expander = NULL,
.io_expander = nullptr,
};
esp_lcd_panel_io_3wire_spi_config_t panel_io_config = ST7701_PANEL_IO_3WIRE_SPI_CONFIG(line_config, 0);
ESP_ERROR_CHECK(esp_lcd_new_panel_io_3wire_spi(&panel_io_config, &ioHandle));
return esp_lcd_new_panel_io_3wire_spi(&panel_io_config, &outHandle) == ESP_OK;
}
bool CydDisplay::createPanelHandle(esp_lcd_panel_io_handle_t ioHandle, esp_lcd_panel_handle_t& panelHandle) {
const esp_lcd_rgb_panel_config_t rgb_config = {
.clk_src = LCD_CLK_SRC_DEFAULT,
.timings = {
@ -179,7 +177,11 @@ bool CydDisplay::start() {
TT_LOG_E(TAG, "Failed to turn display on");
}
const lvgl_port_display_cfg_t disp_cfg = {
return true;
}
lvgl_port_display_cfg_t CydDisplay::getLvglPortDisplayConfig(esp_lcd_panel_io_handle_t ioHandle, esp_lcd_panel_handle_t panelHandle) {
return {
.io_handle = ioHandle,
.panel_handle = panelHandle,
.control_handle = nullptr,
@ -204,44 +206,29 @@ bool CydDisplay::start() {
.direct_mode = false
}
};
}
const lvgl_port_display_rgb_cfg_t rgb_cfg = {
lvgl_port_display_rgb_cfg_t CydDisplay::getLvglPortDisplayRgbConfig(esp_lcd_panel_io_handle_t ioHandle, esp_lcd_panel_handle_t panelHandle) {
return {
.flags = {
.bb_mode = true,
.avoid_tearing = false
}
};
displayHandle = lvgl_port_add_disp_rgb(&disp_cfg, &rgb_cfg);
TT_LOG_I(TAG, "Finished");
return displayHandle != nullptr;
}
bool CydDisplay::stop() {
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;
}
std::shared_ptr<tt::hal::touch::TouchDevice> _Nullable CydDisplay::createTouch() {
std::shared_ptr<tt::hal::touch::TouchDevice> _Nullable CydDisplay::getTouchDevice() {
if (touchDevice == nullptr) {
auto configuration = std::make_unique<Gt911Touch::Configuration>(
I2C_NUM_0,
480,
480
);
return std::make_shared<Gt911Touch>(std::move(configuration));
touchDevice = std::make_shared<Gt911Touch>(std::move(configuration));
}
return touchDevice;
}
void CydDisplay::setBacklightDuty(uint8_t backlightDuty) {
@ -249,5 +236,6 @@ void CydDisplay::setBacklightDuty(uint8_t backlightDuty) {
}
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay() {
return std::make_shared<CydDisplay>();
auto display = std::make_shared<CydDisplay>();
return std::reinterpret_pointer_cast<tt::hal::display::DisplayDevice>(display);
}

View File

@ -1,32 +1,33 @@
#pragma once
#include "Tactility/hal/display/DisplayDevice.h"
#include <esp_lcd_types.h>
#include <EspLcdDisplay.h>
#include<lvgl.h>
class CydDisplay : public tt::hal::display::DisplayDevice {
class CydDisplay final : public EspLcdDisplay {
private:
std::shared_ptr<tt::hal::touch::TouchDevice> _Nullable touchDevice;
esp_lcd_panel_io_handle_t ioHandle = nullptr;
esp_lcd_panel_handle_t panelHandle = nullptr;
lv_display_t* displayHandle = nullptr;
bool createIoHandle(esp_lcd_panel_io_handle_t& outHandle) override;
bool createPanelHandle(esp_lcd_panel_io_handle_t ioHandle, esp_lcd_panel_handle_t& panelHandle) override;
lvgl_port_display_cfg_t getLvglPortDisplayConfig(esp_lcd_panel_io_handle_t ioHandle, esp_lcd_panel_handle_t panelHandle) override;
bool isRgbPanel() const override { return true; }
lvgl_port_display_rgb_cfg_t getLvglPortDisplayRgbConfig(esp_lcd_panel_io_handle_t ioHandle, esp_lcd_panel_handle_t panelHandle) override;
public:
std::string getName() const final { return "ST7701S"; }
std::string getDescription() const final { return "RGB Display"; }
std::string getName() const override { return "ST7701S"; }
bool start() override;
std::string getDescription() const override { return "ST7701S RGB display"; }
bool stop() override;
std::shared_ptr<tt::hal::touch::TouchDevice> _Nullable createTouch() override;
std::shared_ptr<tt::hal::touch::TouchDevice> _Nullable getTouchDevice() override;
void setBacklightDuty(uint8_t backlightDuty) override;
bool supportsBacklightDuty() const override { return true; }
lv_display_t* _Nullable getLvglDisplay() const override { return displayHandle; }
bool supportsBacklightDuty() const override { return true; }
};
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay();

View File

@ -34,5 +34,6 @@ std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay() {
configuration->backlightDutyFunction = driver::pwmbacklight::setBacklightDuty;
return std::make_shared<St7789Display>(std::move(configuration));
auto display = std::make_shared<St7789Display>(std::move(configuration));
return std::reinterpret_pointer_cast<tt::hal::display::DisplayDevice>(display);
}

View File

@ -3,5 +3,5 @@ file(GLOB_RECURSE SOURCE_FILES Source/*.c*)
idf_component_register(
SRCS ${SOURCE_FILES}
INCLUDE_DIRS "Source"
REQUIRES Tactility esp_lvgl_port FT5x06 ST7789 PwmBacklight driver
REQUIRES Tactility FT5x06 ST7789 PwmBacklight driver
)

View File

@ -5,8 +5,6 @@
#include <PwmBacklight.h>
#include <St7789Display.h>
#define TAG "crowpanel_display"
static std::shared_ptr<tt::hal::touch::TouchDevice> createTouch() {
// Note for future changes: Reset pin is 48 and interrupt pin is 47
auto configuration = std::make_unique<Ft5x06Touch::Configuration>(
@ -39,5 +37,6 @@ std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay() {
configuration->backlightDutyFunction = driver::pwmbacklight::setBacklightDuty;
return std::make_shared<St7789Display>(std::move(configuration));
auto display = std::make_shared<St7789Display>(std::move(configuration));
return std::reinterpret_pointer_cast<tt::hal::display::DisplayDevice>(display);
}

View File

@ -1,40 +1,5 @@
#pragma once
#include "Tactility/hal/display/DisplayDevice.h"
#include <esp_lcd_types.h>
#include <lvgl.h>
class CrowPanelDisplay : public tt::hal::display::DisplayDevice {
private:
esp_lcd_panel_io_handle_t ioHandle = nullptr;
esp_lcd_panel_handle_t panelHandle = nullptr;
lv_display_t* displayHandle = nullptr;
bool poweredOn = false;
public:
std::string getName() const final { return "ST7789"; }
std::string getDescription() const final { return "SPI display"; }
bool start() override;
bool stop() override;
void setPowerOn(bool turnOn) override;
bool isPoweredOn() const override { return poweredOn; };
bool supportsPowerControl() const override { return true; }
std::shared_ptr<tt::hal::touch::TouchDevice> _Nullable createTouch() override;
void setBacklightDuty(uint8_t backlightDuty) override;
bool supportsBacklightDuty() const override { return true; }
void setGammaCurve(uint8_t index) override;
uint8_t getGammaCurveCount() const override { return 4; };
lv_display_t* _Nullable getLvglDisplay() const override { return displayHandle; }
};
#include <Tactility/hal/display/DisplayDevice.h>
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay();

View File

@ -36,5 +36,6 @@ std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay() {
configuration->backlightDutyFunction = driver::pwmbacklight::setBacklightDuty;
return std::make_shared<Ili9488Display>(std::move(configuration));
auto display = std::make_shared<Ili9488Display>(std::move(configuration));
return std::reinterpret_pointer_cast<tt::hal::display::DisplayDevice>(display);
}

View File

@ -1,40 +1,5 @@
#pragma once
#include "Tactility/hal/display/DisplayDevice.h"
#include <esp_lcd_types.h>
#include <lvgl.h>
class CrowPanelDisplay : public tt::hal::display::DisplayDevice {
private:
esp_lcd_panel_io_handle_t ioHandle = nullptr;
esp_lcd_panel_handle_t panelHandle = nullptr;
lv_display_t* displayHandle = nullptr;
bool poweredOn = false;
public:
std::string getName() const final { return "ST7789"; }
std::string getDescription() const final { return "SPI display"; }
bool start() override;
bool stop() override;
void setPowerOn(bool turnOn) override;
bool isPoweredOn() const override { return poweredOn; };
bool supportsPowerControl() const override { return true; }
std::shared_ptr<tt::hal::touch::TouchDevice> _Nullable createTouch() override;
void setBacklightDuty(uint8_t backlightDuty) override;
bool supportsBacklightDuty() const override { return true; }
void setGammaCurve(uint8_t index) override;
uint8_t getGammaCurveCount() const override { return 4; };
lv_display_t* _Nullable getLvglDisplay() const override { return displayHandle; }
};
#include <Tactility/hal/display/DisplayDevice.h>
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay();

View File

@ -1,5 +1,5 @@
#pragma once
#include "Tactility/hal/display/DisplayDevice.h"
#include <Tactility/hal/display/DisplayDevice.h>
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay();

View File

@ -35,5 +35,6 @@ std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay() {
configuration->mirrorX = true;
configuration->backlightDutyFunction = driver::pwmbacklight::setBacklightDuty;
return std::make_shared<Ili934xDisplay>(std::move(configuration));
auto display = std::make_shared<Ili934xDisplay>(std::move(configuration));
return std::reinterpret_pointer_cast<tt::hal::display::DisplayDevice>(display);
}

View File

@ -1,40 +1,5 @@
#pragma once
#include "Tactility/hal/display/DisplayDevice.h"
#include <esp_lcd_types.h>
#include <lvgl.h>
class CrowPanelDisplay : public tt::hal::display::DisplayDevice {
private:
esp_lcd_panel_io_handle_t ioHandle = nullptr;
esp_lcd_panel_handle_t panelHandle = nullptr;
lv_display_t* displayHandle = nullptr;
bool poweredOn = false;
public:
std::string getName() const final { return "ST7789"; }
std::string getDescription() const final { return "SPI display"; }
bool start() override;
bool stop() override;
void setPowerOn(bool turnOn) override;
bool isPoweredOn() const override { return poweredOn; };
bool supportsPowerControl() const override { return true; }
std::shared_ptr<tt::hal::touch::TouchDevice> _Nullable createTouch() override;
void setBacklightDuty(uint8_t backlightDuty) override;
bool supportsBacklightDuty() const override { return true; }
void setGammaCurve(uint8_t index) override;
uint8_t getGammaCurveCount() const override { return 4; };
lv_display_t* _Nullable getLvglDisplay() const override { return displayHandle; }
};
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay();

View File

@ -42,5 +42,6 @@ std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay() {
configuration->mirrorX = true;
configuration->backlightDutyFunction = driver::pwmbacklight::setBacklightDuty;
return std::make_shared<Ili9488Display>(std::move(configuration));
auto display = std::make_shared<Ili9488Display>(std::move(configuration));
return std::reinterpret_pointer_cast<tt::hal::display::DisplayDevice>(display);
}

View File

@ -1,40 +1,5 @@
#pragma once
#include "Tactility/hal/display/DisplayDevice.h"
#include <esp_lcd_types.h>
#include <lvgl.h>
class CrowPanelDisplay : public tt::hal::display::DisplayDevice {
private:
esp_lcd_panel_io_handle_t ioHandle = nullptr;
esp_lcd_panel_handle_t panelHandle = nullptr;
lv_display_t* displayHandle = nullptr;
bool poweredOn = false;
public:
std::string getName() const final { return "ST7789"; }
std::string getDescription() const final { return "SPI display"; }
bool start() override;
bool stop() override;
void setPowerOn(bool turnOn) override;
bool isPoweredOn() const override { return poweredOn; };
bool supportsPowerControl() const override { return true; }
std::shared_ptr<tt::hal::touch::TouchDevice> _Nullable createTouch() override;
void setBacklightDuty(uint8_t backlightDuty) override;
bool supportsBacklightDuty() const override { return true; }
void setGammaCurve(uint8_t index) override;
uint8_t getGammaCurveCount() const override { return 4; };
lv_display_t* _Nullable getLvglDisplay() const override { return displayHandle; }
};
#include <Tactility/hal/display/DisplayDevice.h>
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay();

View File

@ -3,8 +3,6 @@
#include <Tactility/lvgl/LvglSync.h>
#include <Tactility/hal/sdcard/SpiSdCardDevice.h>
#include <esp_vfs_fat.h>
using tt::hal::sdcard::SpiSdCardDevice;
std::shared_ptr<SdCardDevice> createSdCard() {

View File

@ -101,5 +101,6 @@ std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay() {
driver::pwmbacklight::setBacklightDuty
);
return std::make_shared<RgbDisplay>(std::move(configuration));
auto display = std::make_shared<RgbDisplay>(std::move(configuration));
return std::reinterpret_pointer_cast<tt::hal::display::DisplayDevice>(display);
}

View File

@ -1,5 +1,5 @@
#pragma once
#include "Tactility/hal/display/DisplayDevice.h"
#include <Tactility/hal/display/DisplayDevice.h>
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay();

View File

@ -3,5 +3,5 @@ file(GLOB_RECURSE SOURCE_FILES Source/*.c*)
idf_component_register(
SRCS ${SOURCE_FILES}
INCLUDE_DIRS "Source"
REQUIRES Tactility esp_lvgl_port esp_lcd ST7796 BQ27220 TCA8418 PwmBacklight driver esp_adc
REQUIRES Tactility esp_lcd ST7796 BQ27220 TCA8418 PwmBacklight driver esp_adc
)

View File

@ -6,8 +6,6 @@
#include <driver/spi_master.h>
#define TAG "TPAGER_display"
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay() {
auto configuration = std::make_unique<St7796Display::Configuration>(
TPAGER_LCD_SPI_HOST,
@ -26,5 +24,6 @@ std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay() {
configuration->backlightDutyFunction = driver::pwmbacklight::setBacklightDuty;
return std::make_shared<St7796Display>(std::move(configuration));
auto display = std::make_shared<St7796Display>(std::move(configuration));
return std::reinterpret_pointer_cast<tt::hal::display::DisplayDevice>(display);
}

View File

@ -1,40 +1,5 @@
#pragma once
#include "Tactility/hal/display/DisplayDevice.h"
#include <esp_lcd_types.h>
#include <lvgl.h>
class TpagerDisplay : public tt::hal::display::DisplayDevice {
private:
esp_lcd_panel_io_handle_t ioHandle = nullptr;
esp_lcd_panel_handle_t panelHandle = nullptr;
lv_display_t* displayHandle = nullptr;
bool poweredOn = false;
public:
std::string getName() const final { return "ST7796"; }
std::string getDescription() const final { return "SPI display"; }
bool start() override;
bool stop() override;
void setPowerOn(bool turnOn) override;
bool isPoweredOn() const override { return poweredOn; };
bool supportsPowerControl() const override { return true; }
std::shared_ptr<tt::hal::touch::TouchDevice> _Nullable createTouch() override;
void setBacklightDuty(uint8_t backlightDuty) override;
bool supportsBacklightDuty() const override { return true; }
void setGammaCurve(uint8_t index) override;
uint8_t getGammaCurveCount() const override { return 4; };
lv_display_t* _Nullable getLvglDisplay() const override { return displayHandle; }
};
#include <Tactility/hal/display/DisplayDevice.h>
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay();

View File

@ -161,7 +161,7 @@ void TpagerKeyboard::processKeyboard() {
}
}
bool TpagerKeyboard::start(lv_display_t* display) {
bool TpagerKeyboard::startLvgl(lv_display_t* display) {
backlightOkay = initBacklight(BACKLIGHT, 30000, LEDC_TIMER_0, LEDC_CHANNEL_1);
initEncoder();
keypad->init(KB_ROWS, KB_COLS);
@ -195,7 +195,7 @@ bool TpagerKeyboard::start(lv_display_t* display) {
return true;
}
bool TpagerKeyboard::stop() {
bool TpagerKeyboard::stopLvgl() {
assert(inputTimer);
inputTimer->stop();
inputTimer = nullptr;

View File

@ -1,6 +1,5 @@
#pragma once
#include <Tactility/TactilityCore.h>
#include <Tactility/hal/keyboard/KeyboardDevice.h>
#include <Tca8418.h>
@ -10,10 +9,7 @@
#include <Tactility/Timer.h>
class TpagerKeyboard : public tt::hal::keyboard::KeyboardDevice {
private:
class TpagerKeyboard final : public tt::hal::keyboard::KeyboardDevice {
lv_indev_t* _Nullable kbHandle = nullptr;
lv_indev_t* _Nullable encHandle = nullptr;
@ -36,13 +32,13 @@ private:
public:
TpagerKeyboard(std::shared_ptr<Tca8418> tca) : keypad(std::move(tca)) {}
~TpagerKeyboard() {}
std::string getName() const final { return "T-Lora Pager Keyboard"; }
std::string getDescription() const final { return "I2C keyboard with encoder"; }
std::string getName() const override { return "T-Lora Pager Keyboard"; }
std::string getDescription() const override { return "T-Lora Pager I2C keyboard with encoder"; }
bool startLvgl(lv_display_t* display) override;
bool stopLvgl() override;
bool start(lv_display_t* display) override;
bool stop() override;
bool isAttached() const override;
lv_indev_t* _Nullable getLvglIndev() override { return kbHandle; }

View File

@ -3,5 +3,5 @@ file(GLOB_RECURSE SOURCE_FILES Source/*.c*)
idf_component_register(
SRCS ${SOURCE_FILES}
INCLUDE_DIRS "Source"
REQUIRES Tactility esp_lvgl_port esp_lcd ST7789 GT911 PwmBacklight driver esp_adc
REQUIRES Tactility EspLcdCompat ST7789 GT911 PwmBacklight driver esp_adc
)

View File

@ -41,5 +41,6 @@ std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay() {
configuration->backlightDutyFunction = driver::pwmbacklight::setBacklightDuty;
return std::make_shared<St7789Display>(std::move(configuration));
auto display = std::make_shared<St7789Display>(std::move(configuration));
return std::reinterpret_pointer_cast<tt::hal::display::DisplayDevice>(display);
}

View File

@ -1,40 +1,5 @@
#pragma once
#include "Tactility/hal/display/DisplayDevice.h"
#include <esp_lcd_types.h>
#include <lvgl.h>
class TdeckDisplay : public tt::hal::display::DisplayDevice {
private:
esp_lcd_panel_io_handle_t ioHandle = nullptr;
esp_lcd_panel_handle_t panelHandle = nullptr;
lv_display_t* displayHandle = nullptr;
bool poweredOn = false;
public:
std::string getName() const final { return "ST7789"; }
std::string getDescription() const final { return "SPI display"; }
bool start() override;
bool stop() override;
void setPowerOn(bool turnOn) override;
bool isPoweredOn() const override { return poweredOn; };
bool supportsPowerControl() const override { return true; }
std::shared_ptr<tt::hal::touch::TouchDevice> _Nullable createTouch() override;
void setBacklightDuty(uint8_t backlightDuty) override;
bool supportsBacklightDuty() const override { return true; }
void setGammaCurve(uint8_t index) override;
uint8_t getGammaCurveCount() const override { return 4; };
lv_display_t* _Nullable getLvglDisplay() const override { return displayHandle; }
};
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay();

View File

@ -7,7 +7,7 @@
#define TDECK_KEYBOARD_I2C_BUS_HANDLE I2C_NUM_0
#define TDECK_KEYBOARD_SLAVE_ADDRESS 0x55
static inline bool keyboard_i2c_read(uint8_t* output) {
static bool keyboard_i2c_read(uint8_t* output) {
return tt::hal::i2c::masterRead(TDECK_KEYBOARD_I2C_BUS_HANDLE, TDECK_KEYBOARD_SLAVE_ADDRESS, output, 1, 100 / portTICK_PERIOD_MS);
}
@ -43,7 +43,7 @@ static void keyboard_read_callback(TT_UNUSED lv_indev_t* indev, lv_indev_data_t*
last_buffer = read_buffer;
}
bool TdeckKeyboard::start(lv_display_t* display) {
bool TdeckKeyboard::startLvgl(lv_display_t* display) {
deviceHandle = lv_indev_create();
lv_indev_set_type(deviceHandle, LV_INDEV_TYPE_KEYPAD);
lv_indev_set_read_cb(deviceHandle, &keyboard_read_callback);
@ -52,7 +52,7 @@ bool TdeckKeyboard::start(lv_display_t* display) {
return true;
}
bool TdeckKeyboard::stop() {
bool TdeckKeyboard::stopLvgl() {
lv_indev_delete(deviceHandle);
deviceHandle = nullptr;
return true;

View File

@ -5,19 +5,17 @@
#include <esp_lcd_panel_io_interface.h>
#include <esp_lcd_touch.h>
class TdeckKeyboard : public tt::hal::keyboard::KeyboardDevice {
private:
class TdeckKeyboard final : public tt::hal::keyboard::KeyboardDevice {
lv_indev_t* _Nullable deviceHandle = nullptr;
public:
std::string getName() const final { return "T-Deck Keyboard"; }
std::string getDescription() const final { return "I2C keyboard"; }
std::string getName() const override { return "T-Deck Keyboard"; }
std::string getDescription() const override { return "I2C keyboard"; }
bool start(lv_display_t* display) override;
bool stop() override;
bool startLvgl(lv_display_t* display) override;
bool stopLvgl() override;
bool isAttached() const override;
lv_indev_t* _Nullable getLvglIndev() override { return deviceHandle; }
};

View File

@ -6,10 +6,13 @@
std::shared_ptr<tt::hal::touch::TouchDevice> createTouch() {
auto configuration = std::make_unique<Ft6x36Touch::Configuration>(
I2C_NUM_0,
GPIO_NUM_39
GPIO_NUM_39,
CORE2_LCD_HORIZONTAL_RESOLUTION,
CORE2_LCD_VERTICAL_RESOLUTION
);
return std::make_shared<Ft6x36Touch>(std::move(configuration));
auto touch = std::make_shared<Ft6x36Touch>(std::move(configuration));
return std::reinterpret_pointer_cast<tt::hal::touch::TouchDevice>(touch);
}
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay() {
@ -28,5 +31,6 @@ std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay() {
true
);
return std::make_shared<Ili934xDisplay>(std::move(configuration));
auto display = std::make_shared<Ili934xDisplay>(std::move(configuration));
return std::reinterpret_pointer_cast<tt::hal::display::DisplayDevice>(display);
}

View File

@ -2,7 +2,7 @@
#include <Tactility/TactilityCore.h>
#include "axp192/axp192.h"
#define TAG "core2_power"
constexpr auto TAG = "Core2Power";
extern axp192_t axpDevice;

View File

@ -1,5 +1,4 @@
#include "CoreS3Display.h"
#include "CoreS3Constants.h"
#include <Ft5x06Touch.h>
@ -7,7 +6,7 @@
#include <Tactility/Log.h>
#include <Tactility/hal/i2c/I2c.h>
#define TAG "cores3"
constexpr auto TAG = "CoreS3Display";
static void setBacklightDuty(uint8_t backlightDuty) {
const uint8_t voltage = 20 + ((8 * backlightDuty) / 255); // [0b00000, 0b11100] - under 20 is too dark
@ -25,7 +24,8 @@ static std::shared_ptr<tt::hal::touch::TouchDevice> createTouch() {
240
);
return std::make_shared<Ft5x06Touch>(std::move(configuration));
auto touch = std::make_shared<Ft5x06Touch>(std::move(configuration));
return std::reinterpret_pointer_cast<tt::hal::touch::TouchDevice>(touch);
}
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay() {
@ -46,5 +46,6 @@ std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay() {
configuration->backlightDutyFunction = ::setBacklightDuty;
return std::make_shared<Ili934xDisplay>(std::move(configuration));
auto display = std::make_shared<Ili934xDisplay>(std::move(configuration));
return std::reinterpret_pointer_cast<tt::hal::display::DisplayDevice>(display);
}

View File

@ -1,5 +1,5 @@
#pragma once
#include "Tactility/hal/display/DisplayDevice.h"
#include <Tactility/hal/display/DisplayDevice.h>
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay();

View File

@ -1,8 +1,7 @@
#pragma once
#include "SdlTouch.h"
#include "Tactility/hal/display/DisplayDevice.h"
#include <memory>
#include <Tactility/hal/display/DisplayDevice.h>
/** Hack: variable comes from LvglTask.cpp */
extern lv_disp_t* displayHandle;
@ -11,8 +10,8 @@ class SdlDisplay final : public tt::hal::display::DisplayDevice {
public:
std::string getName() const final { return "SDL Display"; }
std::string getDescription() const final { return ""; }
std::string getName() const override { return "SDL Display"; }
std::string getDescription() const override { return ""; }
bool start() override {
return displayHandle != nullptr;
@ -20,7 +19,11 @@ public:
bool stop() override { tt_crash("Not supported"); }
std::shared_ptr<tt::hal::touch::TouchDevice> _Nullable createTouch() override { return std::make_shared<SdlTouch>(); }
bool supportsLvgl() const override { return true; }
bool startLvgl() override { return true; }
bool stopLvgl() override { tt_crash("Not supported"); }
std::shared_ptr<tt::hal::touch::TouchDevice> _Nullable getTouchDevice() override { return std::make_shared<SdlTouch>(); }
lv_display_t* _Nullable getLvglDisplay() const override { return displayHandle; }
};

View File

@ -4,20 +4,20 @@
#include <Tactility/TactilityCore.h>
class SdlKeyboard final : public tt::hal::keyboard::KeyboardDevice {
private:
lv_indev_t* _Nullable handle = nullptr;
public:
std::string getName() const final { return "SDL Keyboard"; }
std::string getDescription() const final { return "SDL keyboard device"; }
std::string getName() const override { return "SDL Keyboard"; }
std::string getDescription() const override { return "SDL keyboard device"; }
bool start(lv_display_t* display) override {
bool startLvgl(lv_display_t* display) override {
handle = lv_sdl_keyboard_create();
return handle != nullptr;
}
bool stop() override { tt_crash("Not supported"); }
bool stopLvgl() override { tt_crash("Not supported"); }
bool isAttached() const override { return true; }

View File

@ -4,21 +4,32 @@
#include <Tactility/TactilityCore.h>
class SdlTouch final : public tt::hal::touch::TouchDevice {
private:
lv_indev_t* _Nullable handle = nullptr;
public:
std::string getName() const final { return "SDL Pointer"; }
std::string getDescription() const final { return "SDL mouse/touch pointer device"; }
std::string getName() const override { return "SDL Mouse"; }
bool start(lv_display_t* display) override {
std::string getDescription() const override { return "SDL mouse/touch pointer device"; }
bool start() override { return true; }
bool stop() override { tt_crash("Not supported"); }
bool supportsLvgl() const override { return true; }
bool startLvgl(lv_display_t* display) override {
handle = lv_sdl_mouse_create();
return handle != nullptr;
}
bool stop() override { tt_crash("Not supported"); }
bool stopLvgl() override { tt_crash("Not supported"); }
lv_indev_t* _Nullable getLvglIndev() override { return handle; }
bool supportsTouchDriver() override { return false; }
std::shared_ptr<tt::hal::touch::TouchDriver> _Nullable getTouchDriver() override { return nullptr; };
};

View File

@ -9,13 +9,13 @@
#include <hx8357/disp_spi.h>
#include <hx8357/hx8357.h>
#define TAG "unphone_display"
#define BUFFER_SIZE (UNPHONE_LCD_HORIZONTAL_RESOLUTION * UNPHONE_LCD_DRAW_BUFFER_HEIGHT * LV_COLOR_DEPTH / 8)
constexpr auto TAG = "UnPhoneDisplay";
constexpr auto BUFFER_SIZE = (UNPHONE_LCD_HORIZONTAL_RESOLUTION * UNPHONE_LCD_DRAW_BUFFER_HEIGHT * LV_COLOR_DEPTH / 8);
extern std::shared_ptr<UnPhoneFeatures> unPhoneFeatures;
bool UnPhoneDisplay::start() {
TT_LOG_I(TAG, "Starting");
TT_LOG_I(TAG, "start");
disp_spi_add_device(SPI2_HOST);
@ -24,39 +24,75 @@ bool UnPhoneDisplay::start() {
uint8_t madctl = (1U << MADCTL_BIT_INDEX_COLUMN_ADDRESS_ORDER);
hx8357_set_madctl(madctl);
displayHandle = lv_display_create(UNPHONE_LCD_HORIZONTAL_RESOLUTION, UNPHONE_LCD_VERTICAL_RESOLUTION);
lv_display_set_physical_resolution(displayHandle, UNPHONE_LCD_HORIZONTAL_RESOLUTION, UNPHONE_LCD_VERTICAL_RESOLUTION);
lv_display_set_color_format(displayHandle, LV_COLOR_FORMAT_NATIVE);
return true;
}
bool UnPhoneDisplay::stop() {
TT_LOG_I(TAG, "stop");
disp_spi_remove_device();
return true;
}
bool UnPhoneDisplay::startLvgl() {
TT_LOG_I(TAG, "startLvgl");
if (lvglDisplay != nullptr) {
TT_LOG_W(TAG, "LVGL was already started");
return false;
}
lvglDisplay = lv_display_create(UNPHONE_LCD_HORIZONTAL_RESOLUTION, UNPHONE_LCD_VERTICAL_RESOLUTION);
lv_display_set_physical_resolution(lvglDisplay, UNPHONE_LCD_HORIZONTAL_RESOLUTION, UNPHONE_LCD_VERTICAL_RESOLUTION);
lv_display_set_color_format(lvglDisplay, LV_COLOR_FORMAT_NATIVE);
// TODO malloc to use SPIRAM
buffer = (uint8_t*)heap_caps_malloc(BUFFER_SIZE, MALLOC_CAP_DMA);
buffer = static_cast<uint8_t*>(heap_caps_malloc(BUFFER_SIZE, MALLOC_CAP_DMA));
assert(buffer != nullptr);
lv_display_set_buffers(
displayHandle,
lvglDisplay,
buffer,
nullptr,
BUFFER_SIZE,
LV_DISPLAY_RENDER_MODE_PARTIAL
);
lv_display_set_flush_cb(displayHandle, hx8357_flush);
lv_display_set_flush_cb(lvglDisplay, hx8357_flush);
if (displayHandle != nullptr) {
TT_LOG_I(TAG, "Finished");
unPhoneFeatures->setBacklightPower(true);
return true;
} else {
if (lvglDisplay == nullptr) {
TT_LOG_I(TAG, "Failed");
return false;
}
unPhoneFeatures->setBacklightPower(true);
auto touch_device = getTouchDevice();
if (touch_device != nullptr) {
touch_device->startLvgl(lvglDisplay);
}
bool UnPhoneDisplay::stop() {
assert(displayHandle != nullptr);
return true;
}
lv_display_delete(displayHandle);
displayHandle = nullptr;
bool UnPhoneDisplay::stopLvgl() {
TT_LOG_I(TAG, "stopLvgl");
if (lvglDisplay == nullptr) {
TT_LOG_W(TAG, "LVGL was already stopped");
return false;
}
// Just in case
disp_wait_for_pending_transactions();
auto touch_device = getTouchDevice();
if (touch_device != nullptr && touch_device->getLvglIndev() != nullptr) {
TT_LOG_I(TAG, "Stopping touch device");
touch_device->stopLvgl();
}
lv_display_delete(lvglDisplay);
lvglDisplay = nullptr;
heap_caps_free(buffer);
buffer = nullptr;
@ -64,10 +100,21 @@ bool UnPhoneDisplay::stop() {
return true;
}
std::shared_ptr<tt::hal::touch::TouchDevice> _Nullable UnPhoneDisplay::createTouch() {
return ::createTouch();
std::shared_ptr<tt::hal::touch::TouchDevice> _Nullable UnPhoneDisplay::getTouchDevice() {
if (touchDevice == nullptr) {
touchDevice = std::reinterpret_pointer_cast<tt::hal::touch::TouchDevice>(createTouch());
TT_LOG_I(TAG, "Created touch device");
}
return touchDevice;
}
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay() {
return std::make_shared<UnPhoneDisplay>();
}
bool UnPhoneDisplay::UnPhoneDisplayDriver::drawBitmap(int xStart, int yStart, int xEnd, int yEnd, const void* pixelData) {
lv_area_t area = { xStart, yStart, xEnd, yEnd };
hx8357_flush(nullptr, &area, (uint8_t*)pixelData);
return true;
}

View File

@ -3,13 +3,24 @@
#include "Tactility/hal/display/DisplayDevice.h"
#include <esp_lcd_types.h>
#include <lvgl.h>
#include <Tactility/hal/display/DisplayDriver.h>
#include "UnPhoneDisplayConstants.h"
class UnPhoneDisplay : public tt::hal::display::DisplayDevice {
private:
uint8_t* _Nullable buffer = nullptr;
lv_display_t* _Nullable lvglDisplay = nullptr;
std::shared_ptr<tt::hal::touch::TouchDevice> _Nullable touchDevice;
std::shared_ptr<tt::hal::display::DisplayDriver> _Nullable nativeDisplay;
lv_display_t* displayHandle = nullptr;
uint8_t* buffer = nullptr;
class UnPhoneDisplayDriver : public tt::hal::display::DisplayDriver {
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;
};
public:
@ -20,9 +31,26 @@ public:
bool stop() override;
std::shared_ptr<tt::hal::touch::TouchDevice> _Nullable createTouch() override;
bool supportsLvgl() const override { return true; }
lv_display_t* _Nullable getLvglDisplay() const override { return displayHandle; }
bool startLvgl() override;
bool stopLvgl() override;
std::shared_ptr<tt::hal::touch::TouchDevice> _Nullable getTouchDevice() override;
lv_display_t* _Nullable getLvglDisplay() const override { return lvglDisplay; }
// TODO: Set to true after fixing UnPhoneDisplayDriver
bool supportsDisplayDriver() const override { return false; }
std::shared_ptr<tt::hal::display::DisplayDriver> _Nullable getDisplayDriver() override {
if (nativeDisplay == nullptr) {
nativeDisplay = std::make_shared<UnPhoneDisplayDriver>();
}
assert(nativeDisplay != nullptr);
return nativeDisplay;
}
};
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay();

View File

@ -55,6 +55,7 @@ if (DEFINED ENV{ESP_IDF_VERSION})
add_compile_definitions(LV_CONF_PATH="${LVGL_CONFIG_FULL_PATH}/lv_conf_kconfig.h")
idf_build_set_property(LINK_OPTIONS "-Wl,--wrap=esp_panic_handler" APPEND)
idf_build_set_property(LINK_OPTIONS "-Wl,--wrap=esp_log_write" APPEND)
idf_build_set_property(LINK_OPTIONS "-Wl,--wrap=lv_textarea_create" APPEND)
else ()
message("Building for sim target")
add_compile_definitions(CONFIG_TT_BOARD_ID="simulator")

View File

@ -1,22 +1,22 @@
# TODOs
- 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 user wants soft keyboard)
- 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)
- HAL for display touch calibration
- Start using non_null (either via MS GSL, or custom)
- `hal/Configuration.h` defines C function types: Use C++ std::function instead
- Fix system time to not be 1980 (use build year as minimum)
- Fix system time to not be 1980 (use build year as a minimum). Consider keeping track of the last known time.
- Use std::span or string_view in StringUtils https://youtu.be/FRkJCvHWdwQ?t=2754
- Fix bug in T-Deck/etc: esp_lvgl_port settings has a large stack size (~9kB) to fix an issue where the T-Deck would get a stackoverflow. This sometimes happens when WiFi is auto-enabled and you open the app while it is still connecting.
- Mutex: Implement give/take from ISR support (works only for non-recursive ones)
- Extend unPhone power driver: add charging status, usb connection status, etc.
- Expose app::Paths to TactilityC
- Experiment with what happens when using C++ code in an external app (without using standard library!)
- Make a ledger for setting CPU affinity of various services and tasks
- CrashHandler: use "corrupted" flag
- CrashHandler: process other types of crashes (WDT?)
- Call tt::lvgl::isSyncSet after HAL init and show error (and crash?) when it is not set.
- Create different partitions files for different ESP flash size targets (N4, N8, N16, N32)
- Call tt::lvgl::isSyncSet after HAL init and show an error (and crash?) when it is not set.
- Create different partition files for different ESP flash size targets (N4, N8, N16, N32)
- T-Deck: Clear screen before turning on blacklight
- T-Deck: Use knob for UI selection?
- Crash monitoring: Keep track of which system phase the app crashed in (e.g. which app in which state)
@ -26,28 +26,27 @@
- Show a warning screen when a user plugs in the SD card on a device that only supports mounting at boot.
- Localisation of texts (load in boot app from sd?)
- Explore LVGL9's FreeRTOS functionality
- External app loading: Check version of Tactility and check ESP target hardware, to check for compatibility.
- External app loading: Check version of Tactility and check ESP target hardware to check for compatibility.
- Scanning SD card for external apps and auto-register them (in a temporary register?)
- Support hot-plugging SD card
- All drivers (e.g. display, touch, etc.) should call stop() in their destructor, or at least assert that they should not be running.
- Use GPS time to set/update the current time
- Investigate EEZ Studio
- Remove flex_flow from app_container in Gui.cpp
# Nice-to-haves
- Give external app a different icon. Allow an external app update their id, icon, type and name once they are running(and persist that info?). Loader will need to be able to find app by (external) location.
- Give external app a different icon. Allow an external app to update their id, icon, type and name once they are running (and persist that info?). Loader will need to be able to find app by (external) location.
- Audio player app
- Audio recording app
- OTA updates
- T-Deck Plus: Create separate board config?
- Support for displays with different DPI. Consider the layer-based system like on Android.
- If present, use LED to show boot/wifi status
- Capacity based on voltage: estimation for various devices uses linear voltage curve, but it should use some sort of battery discharge curve.
- Capacity based on voltage: estimation for various devices uses a linear voltage curve, but it should use some sort of battery discharge curve.
- Statusbar widget to show how much memory is in use?
- Wrapper for Slider that shows "+" and "-" buttons, and also the value in a label.
- Wrapper for lvgl slider widget that shows "+" and "-" buttons, and also the value in a label.
- Files app: copy/paste actions
- On crash, try to save current log to flash or SD card? (this is risky, though, so ask in Discord first)
- On crash, try to save the current log to flash or SD card? (this is risky, though, so ask in Discord first)
- Support more than 1 hardware keyboard (see lvgl::hardware_keyboard_set_indev()). LVGL init currently calls keyboard init, but that part should probably be done from the KeyboardDevice base class.
# App Ideas

View File

@ -1,5 +1,5 @@
idf_component_register(
SRC_DIRS "Source"
INCLUDE_DIRS "Source"
REQUIRES Tactility esp_lvgl_port esp_lcd_touch esp_lcd_touch_cst816s driver
REQUIRES Tactility EspLcdCompat esp_lcd_touch_cst816s driver
)

View File

@ -1,9 +1,8 @@
#pragma once
#include <Tactility/hal/touch/TouchDevice.h>
#include <esp_lcd_touch.h>
#include <EspLcdTouch.h>
class Cst816sTouch final : public tt::hal::touch::TouchDevice {
class Cst816sTouch final : public EspLcdTouch {
public:
@ -54,16 +53,18 @@ private:
void cleanup();
bool createIoHandle(esp_lcd_panel_io_handle_t& ioHandle) override;
bool createTouchHandle(esp_lcd_panel_io_handle_t ioHandle, const esp_lcd_touch_config_t& configuration, esp_lcd_touch_handle_t& touchHandle) override;
esp_lcd_touch_config_t createEspLcdTouchConfig() override;
public:
explicit Cst816sTouch(std::unique_ptr<Configuration> inConfiguration) : configuration(std::move(inConfiguration)) {
assert(configuration != nullptr);
}
std::string getName() const final { return "CST816S"; }
std::string getDescription() const final { return "I2C touch driver"; }
bool start(lv_display_t* display) override;
bool stop() override;
lv_indev_t* _Nullable getLvglIndev() override { return deviceHandle; }
std::string getName() const override { return "CST816S"; }
std::string getDescription() const override { return "CST816S I2C touch driver"; }
};

View File

@ -1,25 +1,18 @@
#include "Cst816Touch.h"
#include <Tactility/Log.h>
#include <driver/i2c.h>
#include <esp_err.h>
#include <esp_lcd_touch.h>
#include <esp_lcd_touch_cst816s.h>
#include <esp_lvgl_port.h>
#define TAG "cst816s"
bool Cst816sTouch::start(lv_display_t* display) {
TT_LOG_I(TAG, "Starting");
const esp_lcd_panel_io_i2c_config_t touch_io_config = ESP_LCD_TOUCH_IO_I2C_CST816S_CONFIG();
if (esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t)configuration->port, &touch_io_config, &ioHandle) != ESP_OK) {
TT_LOG_E(TAG, "Touch I2C IO init failed");
return false;
bool Cst816sTouch::createIoHandle(esp_lcd_panel_io_handle_t& ioHandle) {
constexpr esp_lcd_panel_io_i2c_config_t touch_io_config = ESP_LCD_TOUCH_IO_I2C_CST816S_CONFIG();
return esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t)configuration->port, &touch_io_config, &ioHandle) == ESP_OK;
}
esp_lcd_touch_config_t config = {
bool Cst816sTouch::createTouchHandle(esp_lcd_panel_io_handle_t ioHandle, const esp_lcd_touch_config_t& touchConfiguration, esp_lcd_touch_handle_t& touchHandle) {
return esp_lcd_touch_new_i2c_cst816s(ioHandle, &touchConfiguration, &touchHandle) == ESP_OK;
}
esp_lcd_touch_config_t Cst816sTouch::createEspLcdTouchConfig() {
return {
.x_max = configuration->xMax,
.y_max = configuration->yMax,
.rst_gpio_num = configuration->pinReset,
@ -38,47 +31,4 @@ bool Cst816sTouch::start(lv_display_t* display) {
.user_data = nullptr,
.driver_data = nullptr
};
if (esp_lcd_touch_new_i2c_cst816s(ioHandle, &config, &touchHandle) != ESP_OK) {
TT_LOG_E(TAG, "Driver init failed");
cleanup();
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");
cleanup();
return false;
}
TT_LOG_I(TAG, "Finished");
return true;
}
bool Cst816sTouch::stop() {
cleanup();
return true;
}
void Cst816sTouch::cleanup() {
if (deviceHandle != nullptr) {
lv_indev_delete(deviceHandle);
deviceHandle = nullptr;
}
if (touchHandle != nullptr) {
esp_lcd_touch_del(touchHandle);
touchHandle = nullptr;
}
if (ioHandle != nullptr) {
esp_lcd_panel_io_del(ioHandle);
ioHandle = nullptr;
}
}

View File

@ -0,0 +1,5 @@
idf_component_register(
SRC_DIRS "Source"
INCLUDE_DIRS "Source"
REQUIRES Tactility esp_lcd esp_lcd_touch esp_lvgl_port
)

View File

@ -0,0 +1,3 @@
# EspLcdCompat
A set of helper classes to implement `esp_lcd` drivers in Tactility.

View File

@ -0,0 +1,102 @@
#include "EspLcdDisplay.h"
#include "EspLcdDisplayDriver.h"
#include <assert.h>
#include <esp_lvgl_port_disp.h>
#include <Tactility/Check.h>
#include <Tactility/LogEsp.h>
#include <Tactility/hal/touch/TouchDevice.h>
constexpr const char* TAG = "EspLcdDispDrv";
EspLcdDisplay::~EspLcdDisplay() {
if (displayDriver != nullptr && displayDriver.use_count() > 1) {
tt_crash("DisplayDriver is still in use. This will cause memory access violations.");
}
}
bool EspLcdDisplay::start() {
if (!createIoHandle(ioHandle)) {
TT_LOG_E(TAG, "Failed to create IO handle");
return false;
}
if (!createPanelHandle(ioHandle, panelHandle)) {
TT_LOG_E(TAG, "Failed to create panel handle");
esp_lcd_panel_io_del(ioHandle);
return false;
}
return true;
}
bool EspLcdDisplay::stop() {
if (lvglDisplay != nullptr) {
stopLvgl();
lvglDisplay = nullptr;
}
if (panelHandle != nullptr && esp_lcd_panel_del(panelHandle) != ESP_OK) {
return false;
}
if (ioHandle != nullptr && esp_lcd_panel_io_del(ioHandle) != ESP_OK) {
return false;
}
if (displayDriver != nullptr && displayDriver.use_count() > 1) {
TT_LOG_W(TAG, "DisplayDriver is still in use.");
}
return true;
}
bool EspLcdDisplay::startLvgl() {
assert(lvglDisplay == nullptr);
if (displayDriver != nullptr && displayDriver.use_count() > 1) {
TT_LOG_W(TAG, "DisplayDriver is still in use.");
}
lvglPortDisplayConfig = getLvglPortDisplayConfig(ioHandle, panelHandle);
if (isRgbPanel()) {
auto rgb_config = getLvglPortDisplayRgbConfig(ioHandle, panelHandle);
lvglDisplay = lvgl_port_add_disp_rgb(&lvglPortDisplayConfig, &rgb_config);
} else {
lvglDisplay = lvgl_port_add_disp(&lvglPortDisplayConfig);
}
auto touch_device = getTouchDevice();
if (touch_device != nullptr) {
touch_device->startLvgl(lvglDisplay);
}
return lvglDisplay != nullptr;
}
bool EspLcdDisplay::stopLvgl() {
if (lvglDisplay == nullptr) {
return false;
}
auto touch_device = getTouchDevice();
if (touch_device != nullptr) {
touch_device->stopLvgl();
}
lvgl_port_remove_disp(lvglDisplay);
lvglDisplay = nullptr;
return true;
}
std::shared_ptr<display::DisplayDriver> EspLcdDisplay::getDisplayDriver() {
assert(lvglDisplay == nullptr); // Still attached to LVGL context. Call stopLvgl() first.
if (displayDriver == nullptr) {
displayDriver = std::make_shared<EspLcdDisplayDriver>(
panelHandle,
lvglPortDisplayConfig
);
}
return displayDriver;
}

View File

@ -0,0 +1,60 @@
#pragma once
#include <Tactility/hal/display/DisplayDevice.h>
#include <esp_lcd_types.h>
#include <esp_lvgl_port_disp.h>
#include <Tactility/Check.h>
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<tt::hal::display::DisplayDriver> _Nullable displayDriver;
protected:
// Used for sending commands such as setting curves
esp_lcd_panel_io_handle_t getIoHandle() const { return ioHandle; }
virtual bool createIoHandle(esp_lcd_panel_io_handle_t& outHandle) = 0;
virtual bool createPanelHandle(esp_lcd_panel_io_handle_t ioHandle, esp_lcd_panel_handle_t& panelHandle) = 0;
virtual lvgl_port_display_cfg_t getLvglPortDisplayConfig(esp_lcd_panel_io_handle_t ioHandle, esp_lcd_panel_handle_t panelHandle) = 0;
virtual bool isRgbPanel() const { return false; }
virtual lvgl_port_display_rgb_cfg_t getLvglPortDisplayRgbConfig(esp_lcd_panel_io_handle_t ioHandle, esp_lcd_panel_handle_t panelHandle) { tt_crash("Not supported"); }
public:
~EspLcdDisplay() override;
bool start() final;
bool stop() final;
// region LVGL
bool supportsLvgl() const final { return true; }
bool startLvgl() final;
bool stopLvgl() final;
lv_display_t* _Nullable getLvglDisplay() const final { return lvglDisplay; }
// endregion
// region NativeDisplay
bool supportsDisplayDriver() const override { return true; }
/** @return a NativeDisplay instance if this device supports it */
std::shared_ptr<tt::hal::display::DisplayDriver> _Nullable getDisplayDriver() final;
// endregion
};

View File

@ -0,0 +1,44 @@
#pragma once
#include <Tactility/hal/display/DisplayDriver.h>
#include <esp_lcd_panel_ops.h>
#include <esp_lvgl_port_disp.h>
using namespace tt::hal;
class EspLcdDisplayDriver : public display::DisplayDriver {
esp_lcd_panel_handle_t panelHandle;
const lvgl_port_display_cfg_t& lvglPortDisplayConfig;
public:
EspLcdDisplayDriver(
esp_lcd_panel_handle_t panelHandle,
const lvgl_port_display_cfg_t& lvglPortDisplayConfig
) : panelHandle(panelHandle), lvglPortDisplayConfig(lvglPortDisplayConfig) {}
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;
}
}
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;
}
uint16_t getPixelWidth() const override { return lvglPortDisplayConfig.hres; }
uint16_t getPixelHeight() const override { return lvglPortDisplayConfig.vres; }
};

View File

@ -0,0 +1,92 @@
#include "EspLcdTouch.h"
#include <EspLcdTouchDriver.h>
#include <esp_lvgl_port_touch.h>
#include <Tactility/LogEsp.h>
constexpr const char* TAG = "EspLcdTouch";
bool EspLcdTouch::start() {
if (!createIoHandle(ioHandle) != ESP_OK) {
TT_LOG_E(TAG, "Touch IO failed");
return false;
}
config = createEspLcdTouchConfig();
if (!createTouchHandle(ioHandle, config, touchHandle)) {
TT_LOG_E(TAG, "Driver init failed");
esp_lcd_panel_io_del(ioHandle);
ioHandle = nullptr;
return false;
}
return true;
}
bool EspLcdTouch::stop() {
if (lvglDevice != nullptr) {
stopLvgl();
}
if (ioHandle != nullptr) {
esp_lcd_panel_io_del(ioHandle);
ioHandle = nullptr;
}
if (touchHandle != nullptr) {
esp_lcd_touch_del(touchHandle);
touchHandle = nullptr;
}
return true;
}
bool EspLcdTouch::startLvgl(lv_disp_t* display) {
if (lvglDevice != nullptr) {
return false;
}
if (touchDriver != nullptr && touchDriver.use_count() > 1) {
TT_LOG_W(TAG, "TouchDriver is still in use.");
}
const lvgl_port_touch_cfg_t touch_cfg = {
.disp = display,
.handle = touchHandle,
};
TT_LOG_I(TAG, "Adding touch to LVGL");
lvglDevice = lvgl_port_add_touch(&touch_cfg);
if (lvglDevice == nullptr) {
TT_LOG_E(TAG, "Adding touch failed");
return false;
}
return true;
}
bool EspLcdTouch::stopLvgl() {
if (lvglDevice == nullptr) {
return false;
}
lvgl_port_remove_touch(lvglDevice);
lvglDevice = nullptr;
return true;
}
std::shared_ptr<tt::hal::touch::TouchDriver> _Nullable EspLcdTouch::getTouchDriver() {
assert(lvglDevice == nullptr); // Still attached to LVGL context. Call stopLvgl() first.
if (touchHandle == nullptr) {
return nullptr;
}
if (touchDriver == nullptr) {
touchDriver = std::make_shared<EspLcdTouchDriver>(touchHandle);
}
return touchDriver;
}

View File

@ -0,0 +1,44 @@
#pragma once
#include <esp_lcd_touch.h>
#include <esp_lcd_types.h>
#include <lvgl.h>
#include <Tactility/hal/touch/TouchDevice.h>
#include <Tactility/hal/touch/TouchDriver.h>
class EspLcdTouch : public tt::hal::touch::TouchDevice {
esp_lcd_touch_config_t config;
esp_lcd_panel_io_handle_t _Nullable ioHandle = nullptr;
esp_lcd_touch_handle_t _Nullable touchHandle = nullptr;
lv_indev_t* _Nullable lvglDevice = nullptr;
std::shared_ptr<tt::hal::touch::TouchDriver> touchDriver;
protected:
esp_lcd_touch_handle_t _Nullable getTouchHandle() const { return touchHandle; }
virtual bool createIoHandle(esp_lcd_panel_io_handle_t& ioHandle) = 0;
virtual bool createTouchHandle(esp_lcd_panel_io_handle_t ioHandle, const esp_lcd_touch_config_t& configuration, esp_lcd_touch_handle_t& touchHandle) = 0;
virtual esp_lcd_touch_config_t createEspLcdTouchConfig() = 0;
public:
bool start() final;
bool stop() final;
bool supportsLvgl() const final { return true; }
bool startLvgl(lv_display_t* display) final;
bool stopLvgl() final;
lv_indev_t* _Nullable getLvglIndev() final { return lvglDevice; }
bool supportsTouchDriver() override { return true; }
std::shared_ptr<tt::hal::touch::TouchDriver> _Nullable getTouchDriver() final;
};

View File

@ -0,0 +1,13 @@
#include "EspLcdTouchDriver.h"
#include <Tactility/LogEsp.h>
constexpr const char* TAG = "EspLcdTouchDriver";
bool EspLcdTouchDriver::getTouchedPoints(uint16_t* x, uint16_t* y, uint16_t* _Nullable strength, uint8_t* pointCount, uint8_t maxPointCount) {
if (esp_lcd_touch_read_data(handle) != ESP_OK) {
TT_LOG_E(TAG, "Read data failed");
return false;
}
return esp_lcd_touch_get_coordinates(handle, x, y, strength, pointCount, maxPointCount) == ESP_OK;
}

View File

@ -0,0 +1,15 @@
#pragma once
#include <esp_lcd_touch.h>
#include <Tactility/hal/touch/TouchDriver.h>
class EspLcdTouchDriver final : public tt::hal::touch::TouchDriver {
esp_lcd_touch_handle_t handle;
public:
EspLcdTouchDriver(esp_lcd_touch_handle_t handle) : handle(handle) {}
bool getTouchedPoints(uint16_t* x, uint16_t* y, uint16_t* strength, uint8_t* pointCount, uint8_t maxPointCount) override;
};

View File

@ -1,5 +1,5 @@
idf_component_register(
SRC_DIRS "Source"
INCLUDE_DIRS "Source"
REQUIRES Tactility esp_lvgl_port esp_lcd_touch esp_lcd_touch_ft5x06 driver
REQUIRES Tactility EspLcdCompat esp_lcd_touch_ft5x06 driver
)

View File

@ -8,15 +8,17 @@
#define TAG "ft5x06"
bool Ft5x06Touch::start(lv_display_t* display) {
bool Ft5x06Touch::createIoHandle(esp_lcd_panel_io_handle_t& outHandle) {
esp_lcd_panel_io_i2c_config_t io_config = ESP_LCD_TOUCH_IO_I2C_FT5x06_CONFIG();
if (esp_lcd_new_panel_io_i2c(configuration->port, &io_config, &ioHandle) != ESP_OK) {
TT_LOG_E(TAG, "Touch IO I2C creation failed");
return false;
return esp_lcd_new_panel_io_i2c(configuration->port, &io_config, &outHandle) == ESP_OK;
}
esp_lcd_touch_config_t config = {
bool Ft5x06Touch::createTouchHandle(esp_lcd_panel_io_handle_t ioHandle, const esp_lcd_touch_config_t& configuration, esp_lcd_touch_handle_t& panelHandle) {
return esp_lcd_touch_new_i2c_ft5x06(ioHandle, &configuration, &panelHandle) == ESP_OK;
}
esp_lcd_touch_config_t Ft5x06Touch::createEspLcdTouchConfig() {
return {
.x_max = configuration->xMax,
.y_max = configuration->yMax,
.rst_gpio_num = configuration->pinReset,
@ -35,47 +37,4 @@ bool Ft5x06Touch::start(lv_display_t* display) {
.user_data = nullptr,
.driver_data = nullptr
};
if (esp_lcd_touch_new_i2c_ft5x06(ioHandle, &config, &touchHandle) != ESP_OK) {
TT_LOG_E(TAG, "Driver init failed");
cleanup();
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");
cleanup();
return false;
}
return true;
}
bool Ft5x06Touch::stop() {
cleanup();
return true;
}
void Ft5x06Touch::cleanup() {
if (deviceHandle != nullptr) {
lv_indev_delete(deviceHandle);
deviceHandle = nullptr;
}
if (touchHandle != nullptr) {
esp_lcd_touch_del(touchHandle);
touchHandle = nullptr;
}
if (ioHandle != nullptr) {
esp_lcd_panel_io_del(ioHandle);
ioHandle = nullptr;
}
}

View File

@ -4,10 +4,9 @@
#include <Tactility/TactilityCore.h>
#include <driver/i2c.h>
#include <esp_lcd_panel_io_interface.h>
#include <esp_lcd_touch.h>
#include <EspLcdTouch.h>
class Ft5x06Touch final : public tt::hal::touch::TouchDevice {
class Ft5x06Touch final : public EspLcdTouch {
public:
@ -52,11 +51,12 @@ public:
private:
std::unique_ptr<Configuration> configuration;
esp_lcd_panel_io_handle_t _Nullable ioHandle = nullptr;
esp_lcd_touch_handle_t _Nullable touchHandle = nullptr;
lv_indev_t* _Nullable deviceHandle = nullptr;
void cleanup();
bool createIoHandle(esp_lcd_panel_io_handle_t& outHandle) override;
bool createTouchHandle(esp_lcd_panel_io_handle_t ioHandle, const esp_lcd_touch_config_t& configuration, esp_lcd_touch_handle_t& panelHandle) override;
esp_lcd_touch_config_t createEspLcdTouchConfig() override;
public:
@ -64,10 +64,7 @@ public:
assert(configuration != nullptr);
}
bool start(lv_display_t* display) override;
bool stop() override;
lv_indev_t* _Nullable getLvglIndev() override { return deviceHandle; }
std::string getName() const override { return "FT5x06"; }
std::string getName() const final { return "FT5x06"; }
std::string getDescription() const final { return "I2C Touch Driver"; }
std::string getDescription() const override { return "FT5x06 I2C touch driver"; }
};

View File

@ -1,5 +1,6 @@
#include "Ft6x36Touch.h"
#include <Ft6x36Touch.h>
#include <Tactility/Log.h>
#include <esp_err.h>
@ -7,22 +8,23 @@
#define TAG "ft6x36"
static void touchReadCallback(lv_indev_t* indev, lv_indev_data_t* data) {
void Ft6x36Touch::touchReadCallback(lv_indev_t* indev, lv_indev_data_t* data) {
auto* touch = (Ft6x36Touch*)lv_indev_get_driver_data(indev);
touch->readLast(data);
touch->mutex.lock();
data->point = touch->lastPoint;
data->state = touch->lastState;
touch->mutex.unlock();
}
Ft6x36Touch::Ft6x36Touch(std::unique_ptr<Configuration> inConfiguration) :
configuration(std::move(inConfiguration)),
driverThread(tt::Thread("ft6x36", 4096, [this]() {
driverThreadMain();
return 0;
}))
{}
configuration(std::move(inConfiguration)) {
nativeTouch = std::make_shared<Ft6TouchDriver>(*this);
}
Ft6x36Touch::~Ft6x36Touch() {
if (driverThread.getState() != tt::Thread::State::Stopped) {
stop();
if (driverThread != nullptr && driverThread->getState() != tt::Thread::State::Stopped) {
interruptDriverThread = true;
driverThread->join();
}
}
@ -59,7 +61,7 @@ void Ft6x36Touch::driverThreadMain() {
}
}
bool Ft6x36Touch::shouldInterruptDriverThread() {
bool Ft6x36Touch::shouldInterruptDriverThread() const {
bool interrupt = false;
if (mutex.lock(50 / portTICK_PERIOD_MS)) {
interrupt = interruptDriverThread;
@ -68,35 +70,65 @@ bool Ft6x36Touch::shouldInterruptDriverThread() {
return interrupt;
}
bool Ft6x36Touch::start(lv_display_t* display) {
TT_LOG_I(TAG, "start");
bool Ft6x36Touch::start() {
TT_LOG_I(TAG, "Start");
driverThread.start();
uint16_t width = lv_display_get_horizontal_resolution(display);
uint16_t height = lv_display_get_vertical_resolution(display);
if (!driver.begin(FT6X36_DEFAULT_THRESHOLD, width, height)) {
if (!driver.begin(FT6X36_DEFAULT_THRESHOLD, configuration->width, configuration->height)) {
TT_LOG_E(TAG, "driver.begin() failed");
return false;
}
mutex.lock();
interruptDriverThread = false;
driverThread = std::make_shared<tt::Thread>("ft6x36", 4096, [this] {
driverThreadMain();
return 0;
});
driverThread->start();
mutex.unlock();
return true;
}
bool Ft6x36Touch::stop() {
TT_LOG_I(TAG, "Stop");
mutex.lock();
interruptDriverThread = true;
mutex.unlock();
driverThread->join();
mutex.lock();
driverThread = nullptr;
mutex.unlock();
return false;
}
bool Ft6x36Touch::startLvgl(lv_display_t* display) {
if (deviceHandle != nullptr) {
return false;
}
deviceHandle = lv_indev_create();
lv_indev_set_type(deviceHandle, LV_INDEV_TYPE_POINTER);
lv_indev_set_driver_data(deviceHandle, this);
lv_indev_set_read_cb(deviceHandle, touchReadCallback);
TT_LOG_I(TAG, "start success");
return true;
}
bool Ft6x36Touch::stop() {
bool Ft6x36Touch::stopLvgl() {
if (deviceHandle == nullptr) {
return false;
}
lv_indev_delete(deviceHandle);
interruptDriverThread = true;
driverThread.join();
deviceHandle = nullptr;
return true;
}
void Ft6x36Touch::readLast(lv_indev_data_t* data) {
data->point = lastPoint;
data->state = lastState;
}

View File

@ -15,13 +15,19 @@ public:
Configuration(
i2c_port_t port,
gpio_num_t pinInterrupt
gpio_num_t pinInterrupt,
uint16_t width,
uint16_t height
) : port(port),
pinInterrupt(pinInterrupt)
pinInterrupt(pinInterrupt),
width(width),
height(height)
{}
i2c_port_t port;
gpio_num_t pinInterrupt;
uint16_t width;
uint16_t height;
};
private:
@ -29,27 +35,58 @@ private:
std::unique_ptr<Configuration> configuration;
lv_indev_t* _Nullable deviceHandle = nullptr;
FT6X36 driver = FT6X36(configuration->port, configuration->pinInterrupt);
tt::Thread driverThread;
std::shared_ptr<tt::Thread> driverThread;
bool interruptDriverThread = false;
tt::Mutex mutex;
std::shared_ptr<tt::hal::touch::TouchDriver> nativeTouch;
lv_point_t lastPoint = { .x = 0, .y = 0 };
lv_indev_state_t lastState = LV_INDEV_STATE_RELEASED;
bool shouldInterruptDriverThread();
bool shouldInterruptDriverThread() const;
void driverThreadMain();
static void touchReadCallback(lv_indev_t* indev, lv_indev_data_t* data);
public:
explicit Ft6x36Touch(std::unique_ptr<Configuration> inConfiguration);
~Ft6x36Touch() final;
~Ft6x36Touch() override;
std::string getName() const final { return "FT6x36"; }
std::string getDescription() const final { return "I2C touch driver"; }
std::string getName() const override { return "FT6x36"; }
std::string getDescription() const override { return "FT6x36 I2C touch driver"; }
bool start(lv_display_t* display) override;
bool start() override;
bool stop() override;
void readLast(lv_indev_data_t* data);
bool supportsLvgl() const override { return true; }
bool startLvgl(lv_display_t* display) override;
bool stopLvgl() override;
lv_indev_t* _Nullable getLvglIndev() override { return deviceHandle; }
void driverThreadMain();
class Ft6TouchDriver : public tt::hal::touch::TouchDriver {
public:
const Ft6x36Touch& parent;
Ft6TouchDriver(const Ft6x36Touch& parent) : parent(parent) {}
bool getTouchedPoints(uint16_t* x, uint16_t* y, uint16_t* _Nullable strength, uint8_t* pointCount, uint8_t maxPointCount) {
auto lock = parent.mutex.asScopedLock();
lock.lock();
if (parent.lastState == LV_INDEV_STATE_PRESSED) {
*x = parent.lastPoint.x;
*y = parent.lastPoint.y;
*pointCount = 1;
return true;
} else {
*pointCount = 0;
return false;
}
}
};
bool supportsTouchDriver() override { return true; }
std::shared_ptr<tt::hal::touch::TouchDriver> _Nullable getTouchDriver() override { return nativeTouch; }
};

View File

@ -1,5 +1,5 @@
idf_component_register(
SRC_DIRS "Source"
INCLUDE_DIRS "Source"
REQUIRES Tactility esp_lvgl_port esp_lcd_touch esp_lcd_touch_gt911 driver
REQUIRES Tactility EspLcdCompat esp_lcd_touch_gt911 driver
)

View File

@ -5,11 +5,10 @@
#include <esp_lcd_touch_gt911.h>
#include <esp_err.h>
#include <esp_lvgl_port.h>
#define TAG "GT911"
bool Gt911Touch::start(lv_display_t* display) {
bool Gt911Touch::createIoHandle(esp_lcd_panel_io_handle_t& outHandle) {
esp_lcd_panel_io_i2c_config_t io_config = ESP_LCD_TOUCH_IO_I2C_GT911_CONFIG();
/**
@ -26,12 +25,15 @@ bool Gt911Touch::start(lv_display_t* display) {
return false;
}
if (esp_lcd_new_panel_io_i2c(configuration->port, &io_config, &ioHandle) != ESP_OK) {
TT_LOG_E(TAG, "Touch IO I2C creation failed");
return false;
return esp_lcd_new_panel_io_i2c(configuration->port, &io_config, &outHandle) == ESP_OK;
}
esp_lcd_touch_config_t config = {
bool Gt911Touch::createTouchHandle(esp_lcd_panel_io_handle_t ioHandle, const esp_lcd_touch_config_t& configuration, esp_lcd_touch_handle_t& panelHandle) {
return esp_lcd_touch_new_i2c_gt911(ioHandle, &configuration, &panelHandle) == ESP_OK;
}
esp_lcd_touch_config_t Gt911Touch::createEspLcdTouchConfig() {
return {
.x_max = configuration->xMax,
.y_max = configuration->yMax,
.rst_gpio_num = configuration->pinReset,
@ -50,43 +52,4 @@ bool Gt911Touch::start(lv_display_t* display) {
.user_data = nullptr,
.driver_data = nullptr
};
if (esp_lcd_touch_new_i2c_gt911(ioHandle, &config, &touchHandle) != ESP_OK) {
TT_LOG_E(TAG, "Driver init failed");
cleanup();
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");
cleanup();
return false;
}
return true;
}
bool Gt911Touch::stop() {
cleanup();
return true;
}
void Gt911Touch::cleanup() {
if (deviceHandle != nullptr) {
lv_indev_delete(deviceHandle);
deviceHandle = nullptr;
touchHandle = nullptr;
}
if (ioHandle != nullptr) {
esp_lcd_panel_io_del(ioHandle);
ioHandle = nullptr;
}
}

View File

@ -4,10 +4,9 @@
#include <Tactility/TactilityCore.h>
#include <driver/i2c.h>
#include <esp_lcd_panel_io_interface.h>
#include <esp_lcd_touch.h>
#include <EspLcdTouch.h>
class Gt911Touch final : public tt::hal::touch::TouchDevice {
class Gt911Touch final : public EspLcdTouch {
public:
@ -52,11 +51,12 @@ public:
private:
std::unique_ptr<Configuration> configuration;
esp_lcd_panel_io_handle_t _Nullable ioHandle = nullptr;
esp_lcd_touch_handle_t _Nullable touchHandle = nullptr;
lv_indev_t* _Nullable deviceHandle = nullptr;
void cleanup();
bool createIoHandle(esp_lcd_panel_io_handle_t& outHandle) override;
bool createTouchHandle(esp_lcd_panel_io_handle_t ioHandle, const esp_lcd_touch_config_t& configuration, esp_lcd_touch_handle_t& panelHandle) override;
esp_lcd_touch_config_t createEspLcdTouchConfig() override;
public:
@ -64,10 +64,7 @@ public:
assert(configuration != nullptr);
}
bool start(lv_display_t* display) override;
bool stop() override;
lv_indev_t* _Nullable getLvglIndev() override { return deviceHandle; }
std::string getName() const override { return "GT911"; }
std::string getName() const final { return "GT911"; }
std::string getDescription() const final { return "I2C Touch Driver"; }
std::string getDescription() const override { return "GT911 I2C touch driver"; }
};

View File

@ -1,5 +1,5 @@
idf_component_register(
SRC_DIRS "Source"
INCLUDE_DIRS "Source"
REQUIRES Tactility esp_lvgl_port esp_lcd esp_lcd_ili9341 driver
REQUIRES Tactility EspLcdCompat esp_lcd_ili9341 driver
)

View File

@ -6,11 +6,9 @@
#include <esp_lcd_panel_commands.h>
#include <esp_lvgl_port.h>
#define TAG "ili934x"
bool Ili934xDisplay::start() {
TT_LOG_I(TAG, "Starting");
constexpr const char* TAG = "ILI934x";
bool Ili934xDisplay::createIoHandle(esp_lcd_panel_io_handle_t& outHandle) {
const esp_lcd_panel_io_spi_config_t panel_io_config = {
.cs_gpio_num = configuration->csPin,
.dc_gpio_num = configuration->dcPin,
@ -35,11 +33,10 @@ bool Ili934xDisplay::start() {
}
};
if (esp_lcd_new_panel_io_spi(configuration->spiBusHandle, &panel_io_config, &ioHandle) != ESP_OK) {
TT_LOG_E(TAG, "Failed to create panel");
return false;
return esp_lcd_new_panel_io_spi(configuration->spiBusHandle, &panel_io_config, &outHandle) == ESP_OK;
}
bool Ili934xDisplay::createPanelHandle(esp_lcd_panel_io_handle_t ioHandle, esp_lcd_panel_handle_t& panelHandle) {
const esp_lcd_panel_dev_config_t panel_config = {
.reset_gpio_num = configuration->resetPin,
.rgb_ele_order = configuration->rgbElementOrder,
@ -86,18 +83,15 @@ bool Ili934xDisplay::start() {
return false;
}
uint32_t buffer_size;
if (configuration->bufferSize == 0) {
buffer_size = configuration->horizontalResolution * configuration->verticalResolution / 10;
} else {
buffer_size = configuration->bufferSize;
return true;
}
const lvgl_port_display_cfg_t disp_cfg = {
lvgl_port_display_cfg_t Ili934xDisplay::getLvglPortDisplayConfig(esp_lcd_panel_io_handle_t ioHandle, esp_lcd_panel_handle_t panelHandle) {
return {
.io_handle = ioHandle,
.panel_handle = panelHandle,
.control_handle = nullptr,
.buffer_size = buffer_size,
.buffer_size = configuration->bufferSize,
.double_buffer = false,
.trans_size = 0,
.hres = configuration->horizontalResolution,
@ -118,28 +112,6 @@ bool Ili934xDisplay::start() {
.direct_mode = false
}
};
displayHandle = lvgl_port_add_disp(&disp_cfg);
TT_LOG_I(TAG, "Finished");
return displayHandle != nullptr;
}
bool Ili934xDisplay::stop() {
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;
}
/**
@ -174,7 +146,7 @@ void Ili934xDisplay::setGammaCurve(uint8_t index) {
gamma_curve
};
if (esp_lcd_panel_io_tx_param(ioHandle , LCD_CMD_GAMSET, param, 1) != ESP_OK) {
if (esp_lcd_panel_io_tx_param(getIoHandle() , LCD_CMD_GAMSET, param, 1) != ESP_OK) {
TT_LOG_E(TAG, "Failed to set gamma");
}
}

View File

@ -9,7 +9,9 @@
#include <functional>
#include <lvgl.h>
class Ili934xDisplay final : public tt::hal::display::DisplayDevice {
#include <EspLcdDisplay.h>
class Ili934xDisplay final : public EspLcdDisplay {
public:
@ -41,8 +43,12 @@ public:
invertColor(invertColor),
bufferSize(bufferSize),
rgbElementOrder(rgbElementOrder),
touch(std::move(touch))
{}
touch(std::move(touch)
) {
if (this->bufferSize == 0) {
this->bufferSize = horizontalResolution * verticalResolution / 10;
}
}
esp_lcd_spi_bus_handle_t spiBusHandle;
gpio_num_t csPin;
@ -65,9 +71,12 @@ public:
private:
std::unique_ptr<Configuration> configuration;
esp_lcd_panel_io_handle_t ioHandle = nullptr;
esp_lcd_panel_handle_t panelHandle = nullptr;
lv_display_t* displayHandle = nullptr;
bool createIoHandle(esp_lcd_panel_io_handle_t& outHandle) override;
bool createPanelHandle(esp_lcd_panel_io_handle_t ioHandle, esp_lcd_panel_handle_t& panelHandle) override;
lvgl_port_display_cfg_t getLvglPortDisplayConfig(esp_lcd_panel_io_handle_t ioHandle, esp_lcd_panel_handle_t panelHandle) override;
public:
@ -75,25 +84,21 @@ public:
assert(configuration != nullptr);
}
std::string getName() const final { return "ILI934x"; }
std::string getDescription() const final { return "ILI934x display"; }
std::string getName() const override { return "ILI934x"; }
bool start() final;
std::string getDescription() const override { return "ILI934x display"; }
bool stop() final;
std::shared_ptr<tt::hal::touch::TouchDevice> _Nullable getTouchDevice() override { return configuration->touch; }
std::shared_ptr<tt::hal::touch::TouchDevice> _Nullable createTouch() final { return configuration->touch; }
void setBacklightDuty(uint8_t backlightDuty) final {
void setBacklightDuty(uint8_t backlightDuty) override {
if (configuration->backlightDutyFunction != nullptr) {
configuration->backlightDutyFunction(backlightDuty);
}
}
bool supportsBacklightDuty() const final { return configuration->backlightDutyFunction != nullptr; }
bool supportsBacklightDuty() const override { return configuration->backlightDutyFunction != nullptr; }
void setGammaCurve(uint8_t index) final;
uint8_t getGammaCurveCount() const final { return 4; };
void setGammaCurve(uint8_t index) override;
lv_display_t* _Nullable getLvglDisplay() const final { return displayHandle; }
uint8_t getGammaCurveCount() const override { return 4; };
};

View File

@ -1,5 +1,5 @@
idf_component_register(
SRC_DIRS "Source"
INCLUDE_DIRS "Source"
REQUIRES Tactility esp_lvgl_port esp_lcd esp_lcd_ili9488 driver
REQUIRES Tactility EspLcdCompat esp_lcd_ili9488 driver
)

View File

@ -6,11 +6,9 @@
#include <esp_lcd_panel_commands.h>
#include <esp_lvgl_port.h>
#define TAG "ili9488"
bool Ili9488Display::start() {
TT_LOG_I(TAG, "Starting");
#define TAG "ILI9488"
bool Ili9488Display::createIoHandle(esp_lcd_panel_io_handle_t& outHandle) {
const esp_lcd_panel_io_spi_config_t panel_io_config = {
.cs_gpio_num = configuration->csPin,
.dc_gpio_num = configuration->dcPin,
@ -35,11 +33,11 @@ bool Ili9488Display::start() {
}
};
if (esp_lcd_new_panel_io_spi(configuration->spiBusHandle, &panel_io_config, &ioHandle) != ESP_OK) {
TT_LOG_E(TAG, "Failed to create panel");
return false;
return esp_lcd_new_panel_io_spi(configuration->spiBusHandle, &panel_io_config, &outHandle) == ESP_OK;
}
bool Ili9488Display::createPanelHandle(esp_lcd_panel_io_handle_t ioHandle, esp_lcd_panel_handle_t& panelHandle) {
const esp_lcd_panel_dev_config_t panel_config = {
.reset_gpio_num = configuration->resetPin,
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_BGR,
@ -51,14 +49,7 @@ bool Ili9488Display::start() {
.vendor_config = nullptr
};
uint32_t buffer_size;
if (configuration->bufferSize == 0) {
buffer_size = configuration->horizontalResolution * configuration->verticalResolution / 20;
} else {
buffer_size = configuration->bufferSize;
}
if (esp_lcd_new_panel_ili9488(ioHandle, &panel_config, buffer_size, &panelHandle) != ESP_OK) {
if (esp_lcd_new_panel_ili9488(ioHandle, &panel_config, configuration->bufferSize, &panelHandle) != ESP_OK) {
TT_LOG_E(TAG, "Failed to create panel");
return false;
}
@ -93,11 +84,16 @@ bool Ili9488Display::start() {
return false;
}
const lvgl_port_display_cfg_t disp_cfg = {
return true;
}
lvgl_port_display_cfg_t Ili9488Display::getLvglPortDisplayConfig(esp_lcd_panel_io_handle_t ioHandle, esp_lcd_panel_handle_t panelHandle) {
return {
.io_handle = ioHandle,
.panel_handle = panelHandle,
.control_handle = nullptr,
.buffer_size = buffer_size,
.buffer_size = configuration->bufferSize,
.double_buffer = false,
.trans_size = 0,
.hres = configuration->horizontalResolution,
@ -118,26 +114,4 @@ bool Ili9488Display::start() {
.direct_mode = false
}
};
displayHandle = lvgl_port_add_disp(&disp_cfg);
TT_LOG_I(TAG, "Finished");
return displayHandle != nullptr;
}
bool Ili9488Display::stop() {
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;
}

View File

@ -2,14 +2,13 @@
#include "Tactility/hal/display/DisplayDevice.h"
#include <driver/spi_common.h>
#include <EspLcdDisplay.h>
#include <driver/gpio.h>
#include <esp_lcd_panel_io.h>
#include <esp_lcd_types.h>
#include <functional>
#include <lvgl.h>
class Ili9488Display final : public tt::hal::display::DisplayDevice {
class Ili9488Display final : public EspLcdDisplay {
public:
@ -39,8 +38,11 @@ public:
mirrorY(mirrorY),
invertColor(invertColor),
bufferSize(bufferSize),
touch(std::move(touch))
{}
touch(std::move(touch)) {
if (this->bufferSize == 0) {
this->bufferSize = horizontalResolution * verticalResolution / 10;
}
}
esp_lcd_spi_bus_handle_t spiBusHandle;
gpio_num_t csPin;
@ -62,9 +64,12 @@ public:
private:
std::unique_ptr<Configuration> configuration;
esp_lcd_panel_io_handle_t ioHandle = nullptr;
esp_lcd_panel_handle_t panelHandle = nullptr;
lv_display_t* displayHandle = nullptr;
bool createIoHandle(esp_lcd_panel_io_handle_t& outHandle) override;
bool createPanelHandle(esp_lcd_panel_io_handle_t ioHandle, esp_lcd_panel_handle_t& panelHandle) override;
lvgl_port_display_cfg_t getLvglPortDisplayConfig(esp_lcd_panel_io_handle_t ioHandle, esp_lcd_panel_handle_t panelHandle) override;
public:
@ -72,24 +77,19 @@ public:
assert(configuration != nullptr);
}
std::string getName() const final { return "ILI9488"; }
std::string getDescription() const final { return "ILI9488 display"; }
std::string getName() const override { return "ILI9488"; }
bool start() final;
std::string getDescription() const override { return "ILI9488 display"; }
bool stop() final;
std::shared_ptr<tt::hal::touch::TouchDevice> _Nullable getTouchDevice() override { return configuration->touch; }
std::shared_ptr<tt::hal::touch::TouchDevice> _Nullable createTouch() final { return configuration->touch; }
void setBacklightDuty(uint8_t backlightDuty) final {
void setBacklightDuty(uint8_t backlightDuty) override {
if (configuration->backlightDutyFunction != nullptr) {
configuration->backlightDutyFunction(backlightDuty);
}
}
bool supportsBacklightDuty() const final { return configuration->backlightDutyFunction != nullptr; }
lv_display_t* _Nullable getLvglDisplay() const final { return displayHandle; }
bool supportsBacklightDuty() const override { return configuration->backlightDutyFunction != nullptr; }
};
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay();

View File

@ -1,5 +1,5 @@
idf_component_register(
SRC_DIRS "Source"
INCLUDE_DIRS "Source"
REQUIRES Tactility esp_lvgl_port esp_lcd
REQUIRES Tactility EspLcdCompat
)

View File

@ -6,8 +6,16 @@
#include <esp_lcd_panel_rgb.h>
#include <esp_lcd_panel_ops.h>
#include <esp_lvgl_port.h>
#include <Tactility/Check.h>
#include <Tactility/hal/touch/TouchDevice.h>
#define TAG "RgbDisplay"
constexpr auto TAG = "RgbDisplay";
RgbDisplay::~RgbDisplay() {
if (displayDriver != nullptr && displayDriver.use_count() > 1) {
tt_crash("DisplayDriver is still in use. This will cause memory access violations.");
}
}
bool RgbDisplay::start() {
TT_LOG_I(TAG, "Starting");
@ -42,25 +50,85 @@ bool RgbDisplay::start() {
return false;
}
auto horizontal_resolution = configuration->panelConfig.timings.h_res;
auto vertical_resolution = configuration->panelConfig.timings.v_res;
uint32_t buffer_size;
if (configuration->bufferConfiguration.size == 0) {
buffer_size = horizontal_resolution * vertical_resolution / 15;
} else {
buffer_size = configuration->bufferConfiguration.size;
return true;
}
const lvgl_port_display_cfg_t display_config = {
.io_handle = ioHandle,
bool RgbDisplay::stop() {
if (lvglDisplay != nullptr) {
stopLvgl();
lvglDisplay = nullptr;
}
if (panelHandle != nullptr && esp_lcd_panel_del(panelHandle) != ESP_OK) {
return false;
}
if (displayDriver != nullptr && displayDriver.use_count() > 1) {
TT_LOG_W(TAG, "DisplayDriver is still in use.");
}
auto touch_device = getTouchDevice();
if (touch_device != nullptr) {
touch_device->startLvgl(lvglDisplay);
}
return true;
}
bool RgbDisplay::startLvgl() {
assert(lvglDisplay == nullptr);
if (displayDriver != nullptr && displayDriver.use_count() > 1) {
TT_LOG_W(TAG, "DisplayDriver is still in use.");
}
auto display_config = getLvglPortDisplayConfig();
const lvgl_port_display_rgb_cfg_t rgb_config = {
.flags = {
.bb_mode = configuration->bufferConfiguration.bounceBufferMode,
.avoid_tearing = configuration->bufferConfiguration.avoidTearing
}
};
lvglDisplay = lvgl_port_add_disp_rgb(&display_config, &rgb_config);
TT_LOG_I(TAG, "Finished");
auto touch_device = getTouchDevice();
if (touch_device != nullptr) {
touch_device->startLvgl(lvglDisplay);
}
return lvglDisplay != nullptr;
}
bool RgbDisplay::stopLvgl() {
if (lvglDisplay == nullptr) {
return false;
}
auto touch_device = getTouchDevice();
if (touch_device != nullptr) {
touch_device->stopLvgl();
}
lvgl_port_remove_disp(lvglDisplay);
lvglDisplay = nullptr;
return true;
}
lvgl_port_display_cfg_t RgbDisplay::getLvglPortDisplayConfig() const {
return {
.io_handle = nullptr,
.panel_handle = panelHandle,
.control_handle = nullptr,
.buffer_size = buffer_size,
.buffer_size = configuration->bufferConfiguration.size,
.double_buffer = configuration->bufferConfiguration.doubleBuffer,
.trans_size = 0,
.hres = horizontal_resolution,
.vres = vertical_resolution,
.hres = configuration->panelConfig.timings.h_res,
.vres = configuration->panelConfig.timings.v_res,
.monochrome = false,
.rotation = {
.swap_xy = configuration->swapXY,
@ -77,33 +145,5 @@ bool RgbDisplay::start() {
.direct_mode = false
}
};
const lvgl_port_display_rgb_cfg_t rgb_config = {
.flags = {
.bb_mode = configuration->bufferConfiguration.bounceBufferMode,
.avoid_tearing = configuration->bufferConfiguration.avoidTearing
}
};
displayHandle = lvgl_port_add_disp_rgb(&display_config, &rgb_config);
TT_LOG_I(TAG, "Finished");
return displayHandle != nullptr;
}
bool RgbDisplay::stop() {
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;
}

View File

@ -1,14 +1,10 @@
#pragma once
#include "Tactility/hal/display/DisplayDevice.h"
#include <Tactility/hal/display/DisplayDevice.h>
#include <EspLcdDisplayDriver.h>
#include <esp_lcd_panel_rgb.h>
#include <esp_lcd_types.h>
#include <lvgl.h>
#include <utility>
class RgbDisplay : public tt::hal::display::DisplayDevice {
class RgbDisplay final : public display::DisplayDevice {
public:
@ -25,7 +21,7 @@ public:
esp_lcd_rgb_panel_config_t panelConfig;
BufferConfiguration bufferConfiguration;
std::shared_ptr<tt::hal::touch::TouchDevice> touch;
std::shared_ptr<touch::TouchDevice> touch;
lv_color_format_t colorFormat;
bool swapXY;
bool mirrorX;
@ -36,7 +32,7 @@ public:
Configuration(
esp_lcd_rgb_panel_config_t panelConfig,
BufferConfiguration bufferConfiguration,
std::shared_ptr<tt::hal::touch::TouchDevice> touch,
std::shared_ptr<touch::TouchDevice> touch,
lv_color_format_t colorFormat,
bool swapXY = false,
bool mirrorX = false,
@ -51,16 +47,23 @@ public:
mirrorX(mirrorX),
mirrorY(mirrorY),
invertColor(invertColor),
backlightDutyFunction(std::move(backlightDutyFunction))
{}
backlightDutyFunction(std::move(backlightDutyFunction)) {
if (this->bufferConfiguration.size == 0) {
auto horizontal_resolution = panelConfig.timings.h_res;
auto vertical_resolution = panelConfig.timings.v_res;
this->bufferConfiguration.size = horizontal_resolution * vertical_resolution / 15;
}
}
};
private:
std::unique_ptr<Configuration> configuration = nullptr;
esp_lcd_panel_io_handle_t ioHandle = nullptr;
esp_lcd_panel_handle_t panelHandle = nullptr;
lv_display_t* displayHandle = nullptr;
std::unique_ptr<Configuration> _Nullable configuration = nullptr;
esp_lcd_panel_handle_t _Nullable panelHandle = nullptr;
lv_display_t* _Nullable lvglDisplay = nullptr;
std::shared_ptr<display::DisplayDriver> _Nullable displayDriver;
lvgl_port_display_cfg_t getLvglPortDisplayConfig() const;
public:
@ -68,24 +71,41 @@ public:
assert(configuration != nullptr);
}
std::string getName() const final { return "RGB Display"; }
std::string getDescription() const final { return "RGB Display"; }
~RgbDisplay();
std::string getName() const override { return "RGB Display"; }
std::string getDescription() const override { return "RGB Display"; }
bool start() override;
bool stop() override;
std::shared_ptr<tt::hal::touch::TouchDevice> _Nullable createTouch() final { return configuration->touch; }
bool supportsLvgl() const override { return true; }
void setBacklightDuty(uint8_t backlightDuty) final {
bool startLvgl() override;
bool stopLvgl() override;
std::shared_ptr<touch::TouchDevice> _Nullable getTouchDevice() override { return configuration->touch; }
void setBacklightDuty(uint8_t backlightDuty) override {
if (configuration->backlightDutyFunction != nullptr) {
configuration->backlightDutyFunction(backlightDuty);
}
}
bool supportsBacklightDuty() const final { return configuration->backlightDutyFunction != nullptr; }
bool supportsBacklightDuty() const override { return configuration->backlightDutyFunction != nullptr; }
lv_display_t* _Nullable getLvglDisplay() const override { return displayHandle; }
lv_display_t* _Nullable getLvglDisplay() const override { return lvglDisplay; }
bool supportsDisplayDriver() const override { return true; }
std::shared_ptr<display::DisplayDriver> _Nullable getDisplayDriver() override {
if (displayDriver == nullptr) {
displayDriver = std::make_shared<EspLcdDisplayDriver>(panelHandle, getLvglPortDisplayConfig());
}
return displayDriver;
}
};
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay();

View File

@ -1,5 +1,5 @@
idf_component_register(
SRC_DIRS "Source"
INCLUDE_DIRS "Source"
REQUIRES Tactility esp_lvgl_port esp_lcd driver
REQUIRES Tactility driver EspLcdCompat
)

View File

@ -7,9 +7,9 @@
#include <esp_lcd_panel_st7789.h>
#include <esp_lvgl_port.h>
#define TAG "st7789"
constexpr auto TAG = "ST7789";
bool St7789Display::start() {
bool St7789Display::createIoHandle(esp_lcd_panel_io_handle_t& outHandle) {
TT_LOG_I(TAG, "Starting");
const esp_lcd_panel_io_spi_config_t panel_io_config = {
@ -36,11 +36,16 @@ bool St7789Display::start() {
}
};
if (esp_lcd_new_panel_io_spi(configuration->spiBusHandle, &panel_io_config, &ioHandle) != ESP_OK) {
if (esp_lcd_new_panel_io_spi(configuration->spiBusHandle, &panel_io_config, &outHandle) != ESP_OK) {
TT_LOG_E(TAG, "Failed to create panel");
return false;
}
return true;
}
bool St7789Display::createPanelHandle(esp_lcd_panel_io_handle_t ioHandle, esp_lcd_panel_handle_t& panelHandle) {
const esp_lcd_panel_dev_config_t panel_config = {
.reset_gpio_num = configuration->resetPin,
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
@ -86,18 +91,16 @@ bool St7789Display::start() {
TT_LOG_E(TAG, "Failed to turn display on");
return false;
}
uint32_t buffer_size;
if (configuration->bufferSize == 0) {
buffer_size = configuration->horizontalResolution * configuration->verticalResolution / 10;
} else {
buffer_size = configuration->bufferSize;
return true;
}
const lvgl_port_display_cfg_t disp_cfg = {
lvgl_port_display_cfg_t St7789Display::getLvglPortDisplayConfig(esp_lcd_panel_io_handle_t ioHandle, esp_lcd_panel_handle_t panelHandle) {
return lvgl_port_display_cfg_t {
.io_handle = ioHandle,
.panel_handle = panelHandle,
.control_handle = nullptr,
.buffer_size = buffer_size,
.buffer_size = configuration->bufferSize,
.double_buffer = false,
.trans_size = 0,
.hres = configuration->horizontalResolution,
@ -118,30 +121,7 @@ bool St7789Display::start() {
.direct_mode = false
}
};
displayHandle = lvgl_port_add_disp(&disp_cfg);
TT_LOG_I(TAG, "Finished");
return displayHandle != nullptr;
}
bool St7789Display::stop() {
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;
}
/**
* Note:
* The datasheet implies this should work, but it doesn't:
@ -174,7 +154,9 @@ void St7789Display::setGammaCurve(uint8_t index) {
gamma_curve
};
if (esp_lcd_panel_io_tx_param(ioHandle , LCD_CMD_GAMSET, param, 1) != ESP_OK) {
auto io_handle = getIoHandle();
assert(io_handle != nullptr);
if (esp_lcd_panel_io_tx_param(io_handle, LCD_CMD_GAMSET, param, 1) != ESP_OK) {
TT_LOG_E(TAG, "Failed to set gamma");
}
}

View File

@ -1,15 +1,15 @@
#pragma once
#include "Tactility/hal/display/DisplayDevice.h"
#include <EspLcdDisplay.h>
#include <Tactility/hal/display/DisplayDevice.h>
#include <driver/spi_common.h>
#include <driver/gpio.h>
#include <esp_lcd_panel_io.h>
#include <esp_lcd_types.h>
#include <functional>
#include <lvgl.h>
class St7789Display final : public tt::hal::display::DisplayDevice {
class St7789Display final : public EspLcdDisplay {
public:
@ -40,7 +40,11 @@ public:
invertColor(invertColor),
bufferSize(bufferSize),
touch(std::move(touch))
{}
{
if (this->bufferSize == 0) {
this->bufferSize = horizontalResolution * verticalResolution / 10;
}
}
esp_lcd_spi_bus_handle_t spiBusHandle;
gpio_num_t csPin;
@ -62,9 +66,12 @@ public:
private:
std::unique_ptr<Configuration> configuration;
esp_lcd_panel_io_handle_t ioHandle = nullptr;
esp_lcd_panel_handle_t panelHandle = nullptr;
lv_display_t* displayHandle = nullptr;
bool createIoHandle(esp_lcd_panel_io_handle_t& ioHandle) override;
bool createPanelHandle(esp_lcd_panel_io_handle_t ioHandle, esp_lcd_panel_handle_t& panelHandle) override;
lvgl_port_display_cfg_t getLvglPortDisplayConfig(esp_lcd_panel_io_handle_t ioHandle, esp_lcd_panel_handle_t panelHandle) override;
public:
@ -72,27 +79,22 @@ public:
assert(configuration != nullptr);
}
std::string getName() const final { return "ST7789"; }
std::string getDescription() const final { return "ST7789 display"; }
std::string getName() const override { return "ST7789"; }
bool start() final;
std::string getDescription() const override { return "ST7789 display"; }
bool stop() final;
std::shared_ptr<tt::hal::touch::TouchDevice> _Nullable getTouchDevice() override { return configuration->touch; }
std::shared_ptr<tt::hal::touch::TouchDevice> _Nullable createTouch() final { return configuration->touch; }
void setBacklightDuty(uint8_t backlightDuty) final {
void setBacklightDuty(uint8_t backlightDuty) override {
if (configuration->backlightDutyFunction != nullptr) {
configuration->backlightDutyFunction(backlightDuty);
}
}
bool supportsBacklightDuty() const final { return configuration->backlightDutyFunction != nullptr; }
bool supportsBacklightDuty() const override { return configuration->backlightDutyFunction != nullptr; }
void setGammaCurve(uint8_t index) final;
uint8_t getGammaCurveCount() const final { return 4; };
lv_display_t* _Nullable getLvglDisplay() const final { return displayHandle; }
void setGammaCurve(uint8_t index) override;
uint8_t getGammaCurveCount() const override { return 4; };
};
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay();

View File

@ -1,5 +1,5 @@
idf_component_register(
SRC_DIRS "Source"
INCLUDE_DIRS "Source"
REQUIRES Tactility esp_lvgl_port esp_lcd_st7796 driver
REQUIRES Tactility EspLcdCompat esp_lcd_st7796 driver
)

View File

@ -2,16 +2,13 @@
#include <Tactility/Log.h>
#include <esp_lcd_panel_commands.h>
#include <esp_lcd_panel_dev.h>
#include <esp_lcd_st7796.h>
#include <esp_lvgl_port.h>
#define TAG "st7796"
bool St7796Display::start() {
TT_LOG_I(TAG, "Starting");
constexpr auto TAG = "ST7796";
bool St7796Display::createIoHandle(esp_lcd_panel_io_handle_t& ioHandle) {
const esp_lcd_panel_io_spi_config_t panel_io_config = {
.cs_gpio_num = configuration->csPin,
.dc_gpio_num = configuration->dcPin,
@ -36,11 +33,10 @@ bool St7796Display::start() {
}
};
if (esp_lcd_new_panel_io_spi(configuration->spiBusHandle, &panel_io_config, &ioHandle) != ESP_OK) {
TT_LOG_E(TAG, "Failed to create panel");
return false;
return esp_lcd_new_panel_io_spi(configuration->spiBusHandle, &panel_io_config, &ioHandle) == ESP_OK;
}
bool St7796Display::createPanelHandle(esp_lcd_panel_io_handle_t ioHandle, esp_lcd_panel_handle_t& panelHandle) {
static const st7796_lcd_init_cmd_t lcd_init_cmds[] = {
{0x01, (uint8_t[]) {0x00}, 0, 120},
{0x11, (uint8_t[]) {0x00}, 0, 120},
@ -69,7 +65,6 @@ bool St7796Display::start() {
.init_cmds_size = sizeof(lcd_init_cmds) / sizeof(st7796_lcd_init_cmd_t),
};
const esp_lcd_panel_dev_config_t panel_config = {
.reset_gpio_num = configuration->resetPin, // Set to -1 if not use
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
@ -133,18 +128,15 @@ bool St7796Display::start() {
return false;
}
uint32_t buffer_size;
if (configuration->bufferSize == 0) {
buffer_size = configuration->horizontalResolution * configuration->verticalResolution / 10;
} else {
buffer_size = configuration->bufferSize;
return true;
}
const lvgl_port_display_cfg_t disp_cfg = {
lvgl_port_display_cfg_t St7796Display::getLvglPortDisplayConfig(esp_lcd_panel_io_handle_t ioHandle, esp_lcd_panel_handle_t panelHandle) {
return {
.io_handle = ioHandle,
.panel_handle = panelHandle,
.control_handle = nullptr,
.buffer_size = buffer_size,
.buffer_size = configuration->bufferSize,
.double_buffer = false,
.trans_size = 0,
.hres = configuration->horizontalResolution,
@ -158,28 +150,6 @@ bool St7796Display::start() {
.color_format = LV_COLOR_FORMAT_NATIVE,
.flags = {.buff_dma = true, .buff_spiram = false, .sw_rotate = false, .swap_bytes = true, .full_refresh = false, .direct_mode = false}
};
displayHandle = lvgl_port_add_disp(&disp_cfg);
TT_LOG_I(TAG, "Finished");
return displayHandle != nullptr;
}
bool St7796Display::stop() {
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 St7796Display::setGammaCurve(uint8_t index) {
@ -200,6 +170,7 @@ void St7796Display::setGammaCurve(uint8_t index) {
default:
return;
}
const uint8_t param[] = {
gamma_curve
};

View File

@ -1,15 +1,10 @@
#pragma once
#include "Tactility/hal/display/DisplayDevice.h"
#include <EspLcdDisplay.h>
#include <driver/gpio.h>
#include <driver/spi_common.h>
#include <esp_lcd_panel_io.h>
#include <esp_lcd_types.h>
#include <functional>
#include <lvgl.h>
class St7796Display final : public tt::hal::display::DisplayDevice {
class St7796Display final : public EspLcdDisplay {
public:
@ -43,7 +38,11 @@ public:
gapX(gapX),
gapY(gapY),
bufferSize(bufferSize),
touch(std::move(touch)) {}
touch(std::move(touch)) {
if (this->bufferSize == 0) {
this->bufferSize = horizontalResolution * verticalResolution / 10;
}
}
esp_lcd_spi_bus_handle_t spiBusHandle;
gpio_num_t csPin;
@ -67,9 +66,12 @@ public:
private:
std::unique_ptr<Configuration> configuration;
esp_lcd_panel_io_handle_t ioHandle = nullptr;
esp_lcd_panel_handle_t panelHandle = nullptr;
lv_display_t* displayHandle = nullptr;
bool createIoHandle(esp_lcd_panel_io_handle_t& ioHandle) override;
bool createPanelHandle(esp_lcd_panel_io_handle_t ioHandle, esp_lcd_panel_handle_t& panelHandle) override;
lvgl_port_display_cfg_t getLvglPortDisplayConfig(esp_lcd_panel_io_handle_t ioHandle, esp_lcd_panel_handle_t panelHandle) override;
public:
@ -77,27 +79,23 @@ public:
assert(configuration != nullptr);
}
std::string getName() const final { return "ST7796"; }
std::string getDescription() const final { return "ST7796 display"; }
std::string getName() const override { return "ST7796"; }
bool start() final;
std::string getDescription() const override { return "ST7796 display"; }
bool stop() final;
std::shared_ptr<tt::hal::touch::TouchDevice> _Nullable getTouchDevice() override { return configuration->touch; }
std::shared_ptr<tt::hal::touch::TouchDevice> _Nullable createTouch() final { return configuration->touch; }
void setBacklightDuty(uint8_t backlightDuty) final {
void setBacklightDuty(uint8_t backlightDuty) override {
if (configuration->backlightDutyFunction != nullptr) {
configuration->backlightDutyFunction(backlightDuty);
}
}
void setGammaCurve(uint8_t index) final;
uint8_t getGammaCurveCount() const final { return 4; };
void setGammaCurve(uint8_t index) override;
bool supportsBacklightDuty() const final { return configuration->backlightDutyFunction != nullptr; }
uint8_t getGammaCurveCount() const override { return 4; };
lv_display_t* _Nullable getLvglDisplay() const final { return displayHandle; }
bool supportsBacklightDuty() const override { return configuration->backlightDutyFunction != nullptr; }
};
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay();

View File

@ -1,5 +1,5 @@
idf_component_register(
SRC_DIRS "Source"
INCLUDE_DIRS "Source"
REQUIRES Tactility esp_lcd_touch esp_lcd_touch_xpt2046
REQUIRES Tactility EspLcdCompat esp_lcd_touch_xpt2046
)

View File

@ -2,11 +2,28 @@
#include "Xpt2046Touch.h"
#include <Tactility/Log.h>
#include <Tactility/hal/Device.h>
#define TAG "xpt2046_power"
constexpr auto TAG = "Xpt2046Power";
constexpr auto BATTERY_VOLTAGE_MIN = 3.2f;
constexpr auto BATTERY_VOLTAGE_MAX = 4.2f;
constexpr auto MAX_VOLTAGE_SAMPLES = 15;
#define BATTERY_VOLTAGE_MIN 3.2f
#define BATTERY_VOLTAGE_MAX 4.2f
static std::shared_ptr<Xpt2046Touch> findXp2046TouchDevice() {
// Make a safe copy
auto touch = tt::hal::findFirstDevice<tt::hal::touch::TouchDevice>(tt::hal::Device::Type::Touch);
if (touch == nullptr) {
TT_LOG_E(TAG, "Touch device not found");
return nullptr;
}
if (touch->getName() != "XPT2046") {
TT_LOG_E(TAG, "Touch device name mismatch");
return nullptr;
}
return std::reinterpret_pointer_cast<Xpt2046Touch>(touch);
}
static uint8_t estimateChargeLevelFromVoltage(uint32_t milliVolt) {
float volts = std::min((float)milliVolt / 1000.f, BATTERY_VOLTAGE_MAX);
@ -47,25 +64,26 @@ bool Xpt2046Power::getMetric(MetricType type, MetricData& data) {
}
}
bool Xpt2046Power::readBatteryVoltageOnce(uint32_t& output) const {
// Make a safe copy
auto touch = Xpt2046Touch::getInstance();
if (touch != nullptr) {
bool Xpt2046Power::readBatteryVoltageOnce(uint32_t& output) {
if (xptTouch == nullptr) {
xptTouch = findXp2046TouchDevice();
if (xptTouch == nullptr) {
TT_LOG_E(TAG, "XPT2046 touch device not found");
return false;
}
}
float vbat;
if (touch->getVBat(vbat)) {
if (!xptTouch->getVBat(vbat)) {
return false;
}
// Convert to mV
output = (uint32_t)(vbat * 1000.f);
return true;
}
}
return false;
}
#define MAX_VOLTAGE_SAMPLES 15
bool Xpt2046Power::readBatteryVoltageSampled(uint32_t& output) const {
bool Xpt2046Power::readBatteryVoltageSampled(uint32_t& output) {
size_t samples_read = 0;
uint32_t sample_accumulator = 0;
uint32_t sample_read_buffer;

View File

@ -1,8 +1,8 @@
#pragma once
#include <Tactility/hal/power/PowerDevice.h>
#include <memory>
class Xpt2046Touch;
using tt::hal::power::PowerDevice;
/**
@ -11,9 +11,13 @@ using tt::hal::power::PowerDevice;
*/
class Xpt2046Power : public PowerDevice {
std::shared_ptr<Xpt2046Touch> xptTouch;
bool readBatteryVoltageOnce(uint32_t& output);
bool readBatteryVoltageSampled(uint32_t& output);
public:
Xpt2046Power() = default;
~Xpt2046Power() = default;
std::string getName() const final { return "XPT2046 Power Measurement"; }
@ -22,10 +26,6 @@ public:
bool supportsMetric(MetricType type) const override;
bool getMetric(MetricType type, MetricData& data) override;
private:
bool readBatteryVoltageOnce(uint32_t& output) const;
bool readBatteryVoltageSampled(uint32_t& output) const;
};
std::shared_ptr<PowerDevice> getOrCreatePower();

View File

@ -7,19 +7,19 @@
#include <esp_lcd_touch_xpt2046.h>
#include <esp_lvgl_port.h>
#define TAG "xpt2046_touch"
Xpt2046Touch* Xpt2046Touch::instance = nullptr;
bool Xpt2046Touch::start(lv_display_t* display) {
bool Xpt2046Touch::createIoHandle(esp_lcd_panel_io_handle_t& outHandle) {
const esp_lcd_panel_io_spi_config_t io_config = ESP_LCD_TOUCH_IO_SPI_XPT2046_CONFIG(configuration->spiPinCs);
if (esp_lcd_new_panel_io_spi(SPI2_HOST, &io_config, &ioHandle) != ESP_OK) {
TT_LOG_E(TAG, "Touch IO SPI creation failed");
return false;
return esp_lcd_new_panel_io_spi(SPI2_HOST, &io_config, &outHandle) == ESP_OK;
}
esp_lcd_touch_config_t config = {
bool Xpt2046Touch::createTouchHandle(esp_lcd_panel_io_handle_t ioHandle, const esp_lcd_touch_config_t& config, esp_lcd_touch_handle_t& panelHandle) {
return esp_lcd_touch_new_spi_xpt2046(ioHandle, &config, &panelHandle) == ESP_OK;
}
esp_lcd_touch_config_t Xpt2046Touch::createEspLcdTouchConfig() {
return {
.x_max = configuration->xMax,
.y_max = configuration->yMax,
.rst_gpio_num = GPIO_NUM_NC,
@ -38,61 +38,20 @@ bool Xpt2046Touch::start(lv_display_t* display) {
.user_data = nullptr,
.driver_data = nullptr
};
if (esp_lcd_touch_new_spi_xpt2046(ioHandle, &config, &touchHandle) != ESP_OK) {
TT_LOG_E(TAG, "XPT2046 driver init failed");
cleanup();
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");
cleanup();
return false;
}
instance = this;
return true;
}
bool Xpt2046Touch::stop() {
instance = nullptr;
cleanup();
return true;
}
void Xpt2046Touch::cleanup() {
if (deviceHandle != nullptr) {
lv_indev_delete(deviceHandle);
deviceHandle = nullptr;
}
if (touchHandle != nullptr) {
esp_lcd_touch_del(touchHandle);
touchHandle = nullptr;
}
if (ioHandle != nullptr) {
esp_lcd_panel_io_del(ioHandle);
ioHandle = nullptr;
}
}
bool Xpt2046Touch::getVBat(float& outputVbat) {
if (touchHandle != nullptr) {
auto touch_handle = getTouchHandle();
if (touch_handle == nullptr) {
return false;
}
// Shares the SPI bus with the display, so we have to sync/lock as this method might be called from anywhere
if (tt::lvgl::lock(50 / portTICK_PERIOD_MS)) {
esp_lcd_touch_xpt2046_read_battery_level(touchHandle, &outputVbat);
if (!tt::lvgl::lock(50 / portTICK_PERIOD_MS)) {
return false;
}
esp_lcd_touch_xpt2046_read_battery_level(touch_handle, &outputVbat);
tt::lvgl::unlock();
return true;
}
}
return false;
}

View File

@ -1,13 +1,10 @@
#pragma once
#include "Tactility/hal/touch/TouchDevice.h"
#include <Tactility/hal/touch/TouchDevice.h>
#include <Tactility/TactilityCore.h>
#include <EspLcdTouch.h>
#include <esp_lcd_panel_io_interface.h>
#include <esp_lcd_touch.h>
class Xpt2046Touch : public tt::hal::touch::TouchDevice {
class Xpt2046Touch : public EspLcdTouch {
public:
@ -45,11 +42,12 @@ private:
static Xpt2046Touch* instance;
std::unique_ptr<Configuration> configuration;
esp_lcd_panel_io_handle_t _Nullable ioHandle = nullptr;
esp_lcd_touch_handle_t _Nullable touchHandle = nullptr;
lv_indev_t* _Nullable deviceHandle = nullptr;
void cleanup();
bool createIoHandle(esp_lcd_panel_io_handle_t& outHandle) override;
bool createTouchHandle(esp_lcd_panel_io_handle_t ioHandle, const esp_lcd_touch_config_t& configuration, esp_lcd_touch_handle_t& panelHandle) override;
esp_lcd_touch_config_t createEspLcdTouchConfig() override;
public:
@ -58,14 +56,8 @@ public:
}
std::string getName() const final { return "XPT2046"; }
std::string getDescription() const final { return "I2C touch driver"; }
bool start(lv_display_t* display) override;
bool stop() override;
lv_indev_t* _Nullable getLvglIndev() override { return deviceHandle; }
std::string getDescription() const final { return "XPT2046 I2C touch driver"; }
bool getVBat(float& outputVbat);
/** Used for accessing getVBat() in Power driver */
static Xpt2046Touch* getInstance() { return instance; }
};

View File

@ -17,7 +17,7 @@ platform_targets = ["esp32", "esp32s3"]
platform_arguments = platform_targets.copy()
platform_arguments.append("all")
ttbuild_path = ".tactility"
ttbuild_version = "1.2.0"
ttbuild_version = "1.2.1"
ttbuild_properties_file = "tactility.properties"
ttbuild_cdn = "https://cdn.tactility.one"
ttbuild_sdk_json_validity = 3600 # seconds
@ -339,8 +339,6 @@ def read_sdk_json():
def build_action(platform_arg):
# Environment validation
validate_environment()
# Environment setup
setup_environment()
platforms_to_build = platform_targets if platform_arg == "all" else [platform_arg]
if not is_valid_platform_name(platform_arg):
print_help()
@ -448,6 +446,8 @@ if __name__ == "__main__":
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")

View File

@ -17,7 +17,7 @@ platform_targets = ["esp32", "esp32s3"]
platform_arguments = platform_targets.copy()
platform_arguments.append("all")
ttbuild_path = ".tactility"
ttbuild_version = "1.2.0"
ttbuild_version = "1.2.1"
ttbuild_properties_file = "tactility.properties"
ttbuild_cdn = "https://cdn.tactility.one"
ttbuild_sdk_json_validity = 3600 # seconds
@ -339,8 +339,6 @@ def read_sdk_json():
def build_action(platform_arg):
# Environment validation
validate_environment()
# Environment setup
setup_environment()
platforms_to_build = platform_targets if platform_arg == "all" else [platform_arg]
if not is_valid_platform_name(platform_arg):
print_help()
@ -448,6 +446,8 @@ if __name__ == "__main__":
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")

View File

@ -8,10 +8,8 @@
#include "Tactility/hal/uart/Uart.h"
#include "Tactility/lvgl/LvglSync.h"
#include "Tactility/lvgl/Style.h"
#include "Tactility/service/gui/Gui.h"
#include <Tactility/StringUtils.h>
#include <array>
#include <string>
namespace tt::app::serialconsole {
@ -117,7 +115,6 @@ public:
lv_textarea_set_one_line(speedTextarea, true);
lv_obj_set_width(speedTextarea, LV_PCT(50));
lv_obj_align(speedTextarea, LV_ALIGN_TOP_RIGHT, 0, 40);
service::gui::keyboardAddTextArea(speedTextarea);
auto* baud_rate_label = lv_label_create(wrapper);
lv_obj_align(baud_rate_label, LV_ALIGN_TOP_LEFT, 0, 50);
@ -130,7 +127,7 @@ public:
lv_obj_add_event_cb(connect_button, onConnectCallback, LV_EVENT_SHORT_CLICKED, this);
}
void onStop() final {
void onStop() {
int speed = getSpeedInput();
if (speed > 0) {
preferences.putInt32("speed", speed);

View File

@ -186,7 +186,6 @@ public:
lv_obj_set_width(logTextarea, LV_PCT(100));
lv_obj_add_state(logTextarea, LV_STATE_DISABLED);
lv_obj_set_style_margin_ver(logTextarea, 0, 0);
service::gui::keyboardAddTextArea(logTextarea);
auto* input_wrapper = lv_obj_create(parent);
lv_obj_set_size(input_wrapper, LV_PCT(100), LV_SIZE_CONTENT);
@ -200,7 +199,6 @@ public:
lv_textarea_set_placeholder_text(inputTextarea, "Text to send");
lv_obj_set_width(inputTextarea, LV_PCT(100));
lv_obj_set_flex_grow(inputTextarea, 1);
service::gui::keyboardAddTextArea(inputTextarea);
auto* terminator_dropdown = lv_dropdown_create(input_wrapper);
lv_dropdown_set_options(terminator_dropdown, "\\n\n\\r\\n");

View File

@ -36,7 +36,7 @@ public:
virtual ~Device() = default;
/** Unique identifier */
inline Id getId() const { return id; }
Id getId() const { return id; }
/** The type of device */
virtual Type getType() const = 0;

View File

@ -10,12 +10,15 @@ class TouchDevice;
namespace tt::hal::display {
class DisplayDriver;
class DisplayDevice : public Device {
public:
Type getType() const override { return Type::Display; }
/** Starts the internal driver */
virtual bool start() = 0;
virtual bool stop() = 0;
@ -23,7 +26,7 @@ public:
virtual bool isPoweredOn() const { return true; }
virtual bool supportsPowerControl() const { return false; }
virtual std::shared_ptr<touch::TouchDevice> _Nullable createTouch() = 0;
virtual std::shared_ptr<touch::TouchDevice> _Nullable getTouchDevice() = 0;
/** Set a value in the range [0, 255] */
virtual void setBacklightDuty(uint8_t backlightDuty) { /* NO-OP */ }
@ -33,8 +36,14 @@ public:
virtual void setGammaCurve(uint8_t index) { /* NO-OP */ }
virtual uint8_t getGammaCurveCount() const { return 0; };
/** After start() returns true, this should return a valid pointer until stop() is called and returns true */
virtual bool supportsLvgl() const { return false; }
virtual bool startLvgl() { return false; }
virtual bool stopLvgl() { return false; }
virtual lv_display_t* _Nullable getLvglDisplay() const = 0;
virtual bool supportsDisplayDriver() const { return false; }
virtual std::shared_ptr<DisplayDriver> _Nullable getDisplayDriver() { return nullptr; }
};
} // namespace tt::hal::display

View File

@ -0,0 +1,26 @@
#pragma once
#include <cstdint>
namespace tt::hal::display {
enum class ColorFormat {
Monochrome, // 1 bpp
BGR565,
RGB565,
RGB888
};
class DisplayDriver {
public:
virtual ~DisplayDriver() = default;
virtual ColorFormat getColorFormat() const = 0;
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;
};
}

View File

@ -14,8 +14,8 @@ public:
Type getType() const override { return Type::Keyboard; }
virtual bool start(lv_display_t* display) = 0;
virtual bool stop() = 0;
virtual bool startLvgl(lv_display_t* display) = 0;
virtual bool stopLvgl() = 0;
virtual bool isAttached() const = 0;
virtual lv_indev_t* _Nullable getLvglIndev() = 0;

View File

@ -1,6 +1,7 @@
#pragma once
#include "../Device.h"
#include "TouchDriver.h"
#include <lvgl.h>
@ -14,10 +15,18 @@ public:
Type getType() const override { return Type::Touch; }
virtual bool start(lv_display_t* display) = 0;
virtual bool start() = 0;
virtual bool stop() = 0;
virtual bool supportsLvgl() const = 0;
virtual bool startLvgl(lv_display_t* display) = 0;
virtual bool stopLvgl() = 0;
virtual lv_indev_t* _Nullable getLvglIndev() = 0;
virtual bool supportsTouchDriver() = 0;
virtual std::shared_ptr<TouchDriver> _Nullable getTouchDriver() = 0;
};
}

View File

@ -0,0 +1,23 @@
#pragma once
namespace tt::hal::touch {
class TouchDriver {
public:
/**
* Get the coordinates for the currently touched points on the screen.
*
* @param[in] x array of X coordinates
* @param[in] y array of Y coordinates
* @param[in] strength optional array of strengths
* @param[in] pointCount the number of points currently touched on the screen
* @param[in] maxPointCount the maximum number of points that can be touched at once
*
* @return true when touched and coordinates are available
*/
virtual bool getTouchedPoints(uint16_t* x, uint16_t* y, uint16_t* _Nullable strength, uint8_t* pointCount, uint8_t maxPointCount) = 0;
};
}

View File

@ -14,12 +14,14 @@ enum class SystemEvent {
BootInitSpiEnd,
BootInitUartBegin,
BootInitUartEnd,
BootInitLvglBegin,
BootInitLvglEnd,
BootSplash,
/** Gained IP address */
NetworkConnected,
NetworkDisconnected,
/** LVGL devices are initialized and usable */
LvglStarted,
/** LVGL devices were removed and not usable anymore */
LvglStopped,
/** An important system time-related event, such as NTP update or time-zone change */
Time,
};

View File

@ -48,12 +48,4 @@ bool hardware_keyboard_is_available();
*/
void hardware_keyboard_set_indev(lv_indev_t* device);
/**
* Glue code for the on-screen keyboard and the hardware keyboard:
* - Attach automatic hide/show parameters for the on-screen keyboard.
* - Registers the textarea to the default lv_group_t for hardware keyboards.
* @param[in] textarea
*/
void keyboard_add_textarea(lv_obj_t* textarea);
}

View File

@ -1,5 +1,11 @@
#pragma once
#include <lvgl.h>
namespace tt::lvgl {
#include "./Colors.h"
bool isStarted();
void start();
void stop();
}

View File

@ -4,6 +4,13 @@
namespace tt::service {
enum class State {
Starting,
Started,
Stopping,
Stopped
};
// Forward declaration
class ServiceContext;

View File

@ -22,8 +22,8 @@ protected:
public:
/** @return a reference ot the service's manifest */
virtual const service::ServiceManifest& getManifest() const = 0;
/** @return a reference to the service's manifest */
virtual const ServiceManifest& getManifest() const = 0;
/** Retrieve the paths that are relevant to this service */
virtual std::unique_ptr<Paths> getPaths() const = 0;

View File

@ -29,6 +29,13 @@ bool startService(const std::string& id);
*/
bool stopService(const std::string& id);
/** Get the state of a service.
* @warning If the service is not found, the returned result will be "Stopped" - even if the service id does not exist
* @param[in] the service id as defined in its manifest
* @return the service state
*/
State getState(const std::string& id);
/** Find a service manifest by its id.
* @param[in] id the id as defined in the manifest
* @return the matching manifest or nullptr when it wasn't found

Some files were not shown because too many files have changed in this diff Show More