C++ conversion (#80)

Converted project to C++
This commit is contained in:
Ken Van Hoeylandt
2024-11-22 20:26:08 +01:00
committed by GitHub
parent 6d80144e12
commit 85e26636a3
488 changed files with 6017 additions and 39466 deletions
+5
View File
@@ -0,0 +1,5 @@
idf_component_register(
SRC_DIRS "."
INCLUDE_DIRS "."
REQUIRES Tactility lvgl esp_lcd esp_lcd_touch_gt911
)
+39
View File
@@ -0,0 +1,39 @@
#include "config.h"
#include "TactilityCore.h"
#include <driver/i2c.h>
#define TAG "waveshare_bootstrap"
#define WAVESHARE_I2C_MASTER_TX_BUF_DISABLE 0
#define WAVESHARE_I2C_MASTER_RX_BUF_DISABLE 0
static esp_err_t i2c_init() {
const i2c_config_t i2c_conf = {
.mode = I2C_MODE_MASTER,
.sda_io_num = GPIO_NUM_8,
.scl_io_num = GPIO_NUM_9,
.sda_pullup_en = GPIO_PULLUP_DISABLE,
.scl_pullup_en = GPIO_PULLUP_DISABLE,
.master = {
.clk_speed = 400000
}
};
i2c_param_config(WAVESHARE_TOUCH_I2C_PORT, &i2c_conf);
return i2c_driver_install(
WAVESHARE_TOUCH_I2C_PORT,
i2c_conf.mode,
WAVESHARE_I2C_MASTER_RX_BUF_DISABLE,
WAVESHARE_I2C_MASTER_TX_BUF_DISABLE,
0
) == ESP_OK;
}
bool ws3t_bootstrap() {
if (!i2c_init()) {
TT_LOG_E(TAG, "I2C init failed");
return false;
}
return true;
}
+3
View File
@@ -0,0 +1,3 @@
#pragma once
bool ws3t_bootstrap();
+38
View File
@@ -0,0 +1,38 @@
/**
* The WaveShare S3 Touch uses a panel with the ST7262 display driver.
*/
#pragma once
#define WAVESHARE_LCD_HOR_RES 800
#define WAVESHARE_LCD_VER_RES 480
#define WAVESHARE_LCD_PIXEL_CLOCK_HZ (12 * 1000 * 1000) // NOTE: original was 14MHz, but we had to slow it down with PSRAM frame buffer
#define WAVESHARE_LCD_PIN_NUM_HSYNC 46
#define WAVESHARE_LCD_PIN_NUM_VSYNC 3
#define WAVESHARE_LCD_PIN_NUM_DE 5
#define WAVESHARE_LCD_PIN_NUM_PCLK 7
#define WAVESHARE_LCD_PIN_NUM_DATA0 14 // B3
#define WAVESHARE_LCD_PIN_NUM_DATA1 38 // B4
#define WAVESHARE_LCD_PIN_NUM_DATA2 18 // B5
#define WAVESHARE_LCD_PIN_NUM_DATA3 17 // B6
#define WAVESHARE_LCD_PIN_NUM_DATA4 10 // B7
#define WAVESHARE_LCD_PIN_NUM_DATA5 39 // G2
#define WAVESHARE_LCD_PIN_NUM_DATA6 0 // G3
#define WAVESHARE_LCD_PIN_NUM_DATA7 45 // G4
#define WAVESHARE_LCD_PIN_NUM_DATA8 48 // G5
#define WAVESHARE_LCD_PIN_NUM_DATA9 47 // G6
#define WAVESHARE_LCD_PIN_NUM_DATA10 21 // G7
#define WAVESHARE_LCD_PIN_NUM_DATA11 1 // R3
#define WAVESHARE_LCD_PIN_NUM_DATA12 2 // R4
#define WAVESHARE_LCD_PIN_NUM_DATA13 42 // R5
#define WAVESHARE_LCD_PIN_NUM_DATA14 41 // R6
#define WAVESHARE_LCD_PIN_NUM_DATA15 40 // R7
#define WAVESHARE_LCD_PIN_NUM_DISP_EN (-1)
#define WAVESHARE_LCD_BUFFER_HEIGHT (WAVESHARE_LCD_VER_RES / 3) // How many rows of pixels to buffer - 1/3rd is about 1MB
#define WAVESHARE_LCD_USE_DOUBLE_FB true // Performance boost at the cost of about extra PSRAM(SPIRAM)
#define WAVESHARE_LVGL_TICK_PERIOD_MS 2 // TODO: Setting it to 5 causes a crash - why?
#define LVGL_MAX_SLEEP 500
#define WAVESHARE_TOUCH_I2C_PORT I2C_NUM_0
+208
View File
@@ -0,0 +1,208 @@
#include "config.h"
#include "lvgl.h"
#include "TactilityCore.h"
#include "Thread.h"
#include "esp_err.h"
#include "esp_lcd_panel_ops.h"
#include <esp_lcd_panel_rgb.h>
#include <esp_timer.h>
#include <sys/cdefs.h>
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#define TAG "waveshare_s3_touch_display"
SemaphoreHandle_t sem_vsync_end = nullptr;
SemaphoreHandle_t sem_gui_ready = nullptr;
SemaphoreHandle_t lvgl_mux = nullptr;
#if WAVESHARE_LCD_USE_DOUBLE_FB
#define WAVESHARE_LCD_NUM_FB 2
#else
#define WAVESHARE_LCD_NUM_FB 1
#endif
static bool lvgl_is_running = false;
bool ws3t_display_lock(uint32_t timeout_ms) {
assert(lvgl_mux && "lvgl_port_init must be called first");
const TickType_t timeout_ticks = (timeout_ms == 0) ? tt::TtWaitForever : pdMS_TO_TICKS(timeout_ms);
return xSemaphoreTakeRecursive(lvgl_mux, timeout_ticks) == pdTRUE;
}
void ws3t_display_unlock(void) {
assert(lvgl_mux && "lvgl_port_init must be called first");
xSemaphoreGiveRecursive(lvgl_mux);
}
// Display_task should have lower priority than lvgl_tick_task below
static int32_t display_task(TT_UNUSED void* parameter) {
uint32_t task_delay_ms = LVGL_MAX_SLEEP;
ESP_LOGI(TAG, "Starting LVGL task");
lvgl_is_running = true;
while (lvgl_is_running) {
if (ws3t_display_lock(0)) {
task_delay_ms = lv_timer_handler();
ws3t_display_unlock();
}
if ((task_delay_ms > LVGL_MAX_SLEEP) || (1 == task_delay_ms)) {
task_delay_ms = LVGL_MAX_SLEEP;
} else if (task_delay_ms < 1) {
task_delay_ms = 1;
}
vTaskDelay(pdMS_TO_TICKS(task_delay_ms));
}
vTaskDelete(nullptr);
return 0;
}
static bool on_vsync_event(
TT_UNUSED esp_lcd_panel_handle_t panel,
TT_UNUSED const esp_lcd_rgb_panel_event_data_t* event_data,
TT_UNUSED void* user_data
) {
BaseType_t high_task_awoken = pdFALSE;
if (xSemaphoreTakeFromISR(sem_gui_ready, &high_task_awoken) == pdTRUE) {
xSemaphoreGiveFromISR(sem_vsync_end, &high_task_awoken);
}
return high_task_awoken == pdTRUE;
}
static void lvgl_tick_task(TT_UNUSED void* arg) {
// Tell how much time has passed
lv_tick_inc(WAVESHARE_LVGL_TICK_PERIOD_MS);
}
static void display_flush_callback(lv_display_t* disp, const lv_area_t* area, uint8_t* px_map) {
auto panel_handle = static_cast<esp_lcd_panel_handle_t>(lv_display_get_user_data(disp));
int offsetx1 = area->x1;
int offsetx2 = area->x2;
int offsety1 = area->y1;
int offsety2 = area->y2;
xSemaphoreGive(sem_gui_ready);
xSemaphoreTake(sem_vsync_end, portMAX_DELAY);
// pass the draw buffer to the driver
esp_lcd_panel_draw_bitmap(panel_handle, offsetx1, offsety1, offsetx2 + 1, offsety2 + 1, px_map);
lv_disp_flush_ready(disp);
}
lv_disp_t* ws3t_display_create() {
TT_LOG_I(TAG, "display init");
sem_vsync_end = xSemaphoreCreateBinary();
tt_assert(sem_vsync_end);
sem_gui_ready = xSemaphoreCreateBinary();
tt_assert(sem_gui_ready);
lvgl_mux = xSemaphoreCreateRecursiveMutex();
tt_assert(lvgl_mux);
tt::Thread* thread = tt::thread_alloc_ex("display_task", 8192, &display_task, nullptr);
tt::thread_set_priority(thread, tt::ThreadPriorityHigh); // TODO: try out THREAD_PRIORITY_RENDER
tt::thread_start(thread);
esp_lcd_panel_handle_t panel_handle = NULL;
esp_lcd_rgb_panel_config_t panel_config = {
.clk_src = LCD_CLK_SRC_DEFAULT,
.timings = {
.pclk_hz = WAVESHARE_LCD_PIXEL_CLOCK_HZ,
.h_res = WAVESHARE_LCD_HOR_RES,
.v_res = WAVESHARE_LCD_VER_RES,
.hsync_pulse_width = 10,
// The following parameters should refer to LCD spec
.hsync_back_porch = 10,
.hsync_front_porch = 20,
.vsync_pulse_width = 10,
.vsync_back_porch = 10,
.vsync_front_porch = 10,
},
.data_width = 16, // RGB565 in parallel mode, thus 16bit in width
.bits_per_pixel = 16,
.num_fbs = WAVESHARE_LCD_NUM_FB,
.bounce_buffer_size_px = 0,
.sram_trans_align = 0,
.psram_trans_align = 64,
.hsync_gpio_num = WAVESHARE_LCD_PIN_NUM_HSYNC,
.vsync_gpio_num = WAVESHARE_LCD_PIN_NUM_VSYNC,
.de_gpio_num = WAVESHARE_LCD_PIN_NUM_DE,
.pclk_gpio_num = WAVESHARE_LCD_PIN_NUM_PCLK,
.disp_gpio_num = WAVESHARE_LCD_PIN_NUM_DISP_EN,
.data_gpio_nums = {WAVESHARE_LCD_PIN_NUM_DATA0, WAVESHARE_LCD_PIN_NUM_DATA1, WAVESHARE_LCD_PIN_NUM_DATA2, WAVESHARE_LCD_PIN_NUM_DATA3, WAVESHARE_LCD_PIN_NUM_DATA4, WAVESHARE_LCD_PIN_NUM_DATA5, WAVESHARE_LCD_PIN_NUM_DATA6, WAVESHARE_LCD_PIN_NUM_DATA7, WAVESHARE_LCD_PIN_NUM_DATA8, WAVESHARE_LCD_PIN_NUM_DATA9, WAVESHARE_LCD_PIN_NUM_DATA10, WAVESHARE_LCD_PIN_NUM_DATA11, WAVESHARE_LCD_PIN_NUM_DATA12, WAVESHARE_LCD_PIN_NUM_DATA13, WAVESHARE_LCD_PIN_NUM_DATA14, WAVESHARE_LCD_PIN_NUM_DATA15},
.flags = {.disp_active_low = false, .refresh_on_demand = false, .fb_in_psram = true, .double_fb = WAVESHARE_LCD_USE_DOUBLE_FB, .no_fb = false, .bb_invalidate_cache = false}
};
if (esp_lcd_new_rgb_panel(&panel_config, &panel_handle) != ESP_OK) {
TT_LOG_E(TAG, "Failed to create RGB panel");
return nullptr;
}
esp_lcd_rgb_panel_event_callbacks_t cbs = {
.on_vsync = on_vsync_event,
.on_bounce_empty = nullptr,
.on_bounce_frame_finish = nullptr
};
if (esp_lcd_rgb_panel_register_event_callbacks(panel_handle, &cbs, nullptr) != ESP_OK) {
TT_LOG_E(TAG, "Failed to register callbacks");
return nullptr;
}
if (esp_lcd_panel_reset(panel_handle) != ESP_OK) {
TT_LOG_E(TAG, "Failed to reset panel");
return nullptr;
}
if (esp_lcd_panel_init(panel_handle) != ESP_OK) {
TT_LOG_E(TAG, "Failed to init panel");
return nullptr;
}
lv_init();
#if WAVESHARE_LCD_USE_DOUBLE_FB
// initialize LVGL draw buffers
lv_draw_buf_t* buffer1 = lv_draw_buf_create(WAVESHARE_LCD_HOR_RES, WAVESHARE_LCD_BUFFER_HEIGHT, LV_COLOR_FORMAT_RGB565, 0);
lv_draw_buf_t* buffer2 = lv_draw_buf_create(WAVESHARE_LCD_HOR_RES, WAVESHARE_LCD_BUFFER_HEIGHT, LV_COLOR_FORMAT_RGB565, 0);
tt_assert(buffer1);
tt_assert(buffer2);
#else
lv_draw_buf_t* buffer1 = lv_draw_buf_create(WAVESHARE_LCD_HOR_RES, WAVESHARE_LCD_VER_RES, LV_COLOR_FORMAT_RGB565, 0);
lv_draw_buf_t* buffer2 = NULL;
tt_assert(buffer1);
#endif // WAVESHARE_USE_DOUBLE_FB
lv_display_t* display = lv_display_create(WAVESHARE_LCD_HOR_RES, WAVESHARE_LCD_VER_RES);
lv_display_set_draw_buffers(display, buffer1, buffer2);
lv_display_set_flush_cb(display, &display_flush_callback);
lv_display_set_user_data(display, panel_handle);
lv_display_set_antialiasing(display, false);
lv_display_set_render_mode(display, LV_DISPLAY_RENDER_MODE_PARTIAL);
const esp_timer_create_args_t lvgl_tick_timer_args = {
.callback = &lvgl_tick_task,
.name = "lvgl_tick"
};
esp_timer_handle_t lvgl_tick_timer = nullptr;
ESP_ERROR_CHECK(esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer));
ESP_ERROR_CHECK(esp_timer_start_periodic(lvgl_tick_timer, WAVESHARE_LVGL_TICK_PERIOD_MS * 1000));
return display;
}
void ws3t_display_destroy() {
// TODO: de-init display, its buffer and touch, stop display tasks, stop timer
// TODO: see esp_lvlg_port.c for more info
if (lvgl_mux) {
vSemaphoreDelete(lvgl_mux);
lvgl_mux = nullptr;
}
#if LV_ENABLE_GC || !LV_MEM_CUSTOM
lv_deinit();
#endif
}
+10
View File
@@ -0,0 +1,10 @@
#pragma once
#include "lvgl.h"
#include <cstdint>
bool ws3t_display_lock(uint32_t timeout_ms);
void ws3t_display_unlock(void);
lv_display_t* ws3t_display_create();
void ws3t_display_destroy();
+18
View File
@@ -0,0 +1,18 @@
#include "lvgl_i.h"
#include "display_i.h"
#include "touch_i.h"
#include "Ui/LvglSync.h"
bool ws3t_init_lvgl() {
tt::lvgl::sync_set(&ws3t_display_lock, &ws3t_display_unlock);
lv_display_t* display = ws3t_display_create();
if (display == nullptr) {
return false;
}
ws3t_touch_init(display);
return true;
}
+3
View File
@@ -0,0 +1,3 @@
#pragma once
bool ws3t_init_lvgl();
+72
View File
@@ -0,0 +1,72 @@
#include "config.h"
#include "driver/i2c.h"
#include "esp_err.h"
#include "esp_lcd_touch_gt911.h"
#include "esp_log.h"
#include "lvgl.h"
#define TAG "waveshare_s3_touch_i2c"
static esp_lcd_touch_handle_t touch_init_internal() {
static esp_lcd_panel_io_handle_t tp_io_handle = nullptr;
static esp_lcd_panel_io_i2c_config_t tp_io_config = ESP_LCD_TOUCH_IO_I2C_GT911_CONFIG();
ESP_LOGI(TAG, "Initialize touch IO");
// TODO: Revert on new ESP-IDF version
static_assert(ESP_IDF_VERSION == ESP_IDF_VERSION_VAL(5, 3, 1));
// ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t)WAVESHARE_TOUCH_I2C_PORT, &tp_io_config, &tp_io_handle));
esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t)WAVESHARE_TOUCH_I2C_PORT, &tp_io_config, &tp_io_handle);
esp_lcd_touch_config_t tp_cfg = {
.x_max = WAVESHARE_LCD_VER_RES,
.y_max = WAVESHARE_LCD_HOR_RES,
.rst_gpio_num = GPIO_NUM_NC,
.int_gpio_num = GPIO_NUM_NC,
.flags = {
.swap_xy = 0,
.mirror_x = 0,
.mirror_y = 0,
},
};
/* Initialize touch */
ESP_LOGI(TAG, "Initialize touch controller GT911");
esp_lcd_touch_handle_t tp = nullptr;
ESP_ERROR_CHECK(esp_lcd_touch_new_i2c_gt911(tp_io_handle, &tp_cfg, &tp));
return tp;
}
static void touch_callback(lv_indev_t* indev, lv_indev_data_t* data) {
uint16_t touchpad_x[1] = {0};
uint16_t touchpad_y[1] = {0};
uint8_t touchpad_cnt = 0;
/* Read touch controller data */
auto touch_handle = static_cast<esp_lcd_touch_handle_t>(lv_indev_get_user_data(indev));
esp_lcd_touch_read_data(touch_handle);
/* Get coordinates */
bool touchpad_pressed = esp_lcd_touch_get_coordinates(touch_handle, touchpad_x, touchpad_y, nullptr, &touchpad_cnt, 1);
if (touchpad_pressed && touchpad_cnt > 0) {
data->point.x = touchpad_x[0];
data->point.y = touchpad_y[0];
data->state = LV_INDEV_STATE_PR;
} else {
data->state = LV_INDEV_STATE_REL;
}
}
void ws3t_touch_init(lv_display_t* display) {
esp_lcd_touch_handle_t touch_handle = touch_init_internal();
ESP_LOGI(TAG, "Register display indev to LVGL");
static lv_indev_t* device = nullptr;
device = lv_indev_create();
lv_indev_set_type(device, LV_INDEV_TYPE_POINTER);
lv_indev_set_read_cb(device, &touch_callback);
lv_indev_set_display(device, display);
lv_indev_set_user_data(device, touch_handle);
}
+5
View File
@@ -0,0 +1,5 @@
#pragma once
#include "lvgl.h"
void ws3t_touch_init(lv_display_t* display);
@@ -0,0 +1,15 @@
#include "waveshare_s3_touch.h"
#include "lvgl_i.h"
bool ws3t_bootstrap();
extern const tt::hal::Configuration waveshare_s3_touch = {
.bootstrap = &ws3t_bootstrap,
.init_graphics = &ws3t_init_lvgl,
.display = {
.set_backlight_duty = nullptr // TODO: This requires implementing the CH422G IO expander
},
.sdcard = nullptr,
.power = nullptr
};
@@ -0,0 +1,6 @@
#pragma once
#include "Hal/Configuration.h"
// Waveshare S3 Touch LCD 4.3
extern const tt::hal::Configuration waveshare_s3_touch;