diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 7fbebf69..3d8f10f1 100755 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -6,6 +6,7 @@ set(SOURCES "audio_codecs/audio_codec.cc" "display/display.cc" "display/no_display.cc" "display/st7789_display.cc" + "display/ili9341_display.cc" "display/ssd1306_display.cc" "protocols/protocol.cc" "protocols/mqtt_protocol.cc" diff --git a/main/boards/esp-box-3/config.h b/main/boards/esp-box-3/config.h index a1255732..14bddbd3 100644 --- a/main/boards/esp-box-3/config.h +++ b/main/boards/esp-box-3/config.h @@ -26,12 +26,17 @@ #define VOLUME_UP_BUTTON_GPIO GPIO_NUM_NC #define VOLUME_DOWN_BUTTON_GPIO GPIO_NUM_NC -#define DISPLAY_SDA_PIN GPIO_NUM_NC -#define DISPLAY_SCL_PIN GPIO_NUM_NC -#define DISPLAY_WIDTH 128 -#define DISPLAY_HEIGHT 64 +#define DISPLAY_WIDTH 320 +#define DISPLAY_HEIGHT 240 #define DISPLAY_MIRROR_X true #define DISPLAY_MIRROR_Y true +#define DISPLAY_SWAP_XY false + +#define DISPLAY_OFFSET_X 0 +#define DISPLAY_OFFSET_Y 0 + +#define DISPLAY_BACKLIGHT_PIN GPIO_NUM_47 +#define DISPLAY_BACKLIGHT_OUTPUT_INVERT false #endif // _BOARD_CONFIG_H_ diff --git a/main/boards/esp-box-3/esp_box3_board.cc b/main/boards/esp-box-3/esp_box3_board.cc index c74106f0..dcd80c10 100644 --- a/main/boards/esp-box-3/esp_box3_board.cc +++ b/main/boards/esp-box-3/esp_box3_board.cc @@ -1,6 +1,6 @@ #include "wifi_board.h" #include "audio_codecs/box_audio_codec.h" -#include "display/no_display.h" +#include "display/ili9341_display.h" #include "application.h" #include "button.h" #include "led.h" @@ -8,14 +8,37 @@ #include "iot/thing_manager.h" #include +#include #include +#include #define TAG "EspBox3Board" +static const ili9341_lcd_init_cmd_t vendor_specific_init[] = { + {0xC8, (uint8_t []){0xFF, 0x93, 0x42}, 3, 0}, + {0xC0, (uint8_t []){0x0E, 0x0E}, 2, 0}, + {0xC5, (uint8_t []){0xD0}, 1, 0}, + {0xC1, (uint8_t []){0x02}, 1, 0}, + {0xB4, (uint8_t []){0x02}, 1, 0}, + {0xE0, (uint8_t []){0x00, 0x03, 0x08, 0x06, 0x13, 0x09, 0x39, 0x39, 0x48, 0x02, 0x0a, 0x08, 0x17, 0x17, 0x0F}, 15, 0}, + {0xE1, (uint8_t []){0x00, 0x28, 0x29, 0x01, 0x0d, 0x03, 0x3f, 0x33, 0x52, 0x04, 0x0f, 0x0e, 0x37, 0x38, 0x0F}, 15, 0}, + + {0xB1, (uint8_t []){00, 0x1B}, 2, 0}, + {0x36, (uint8_t []){0x08}, 1, 0}, + {0x3A, (uint8_t []){0x55}, 1, 0}, + {0xB7, (uint8_t []){0x06}, 1, 0}, + + {0x11, (uint8_t []){0}, 0x80, 0}, + {0x29, (uint8_t []){0}, 0x80, 0}, + + {0, (uint8_t []){0}, 0xff, 0}, +}; + class EspBox3Board : public WifiBoard { private: i2c_master_bus_handle_t i2c_bus_; Button boot_button_; + Ili9341Display* display_; void InitializeI2c() { // Initialize I2C peripheral @@ -34,12 +57,64 @@ private: ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &i2c_bus_)); } + void InitializeSpi() { + spi_bus_config_t buscfg = {}; + buscfg.mosi_io_num = GPIO_NUM_6; + buscfg.miso_io_num = GPIO_NUM_NC; + buscfg.sclk_io_num = GPIO_NUM_7; + buscfg.quadwp_io_num = GPIO_NUM_NC; + buscfg.quadhd_io_num = GPIO_NUM_NC; + buscfg.max_transfer_sz = DISPLAY_WIDTH * DISPLAY_HEIGHT * sizeof(uint16_t); + ESP_ERROR_CHECK(spi_bus_initialize(SPI3_HOST, &buscfg, SPI_DMA_CH_AUTO)); + } + void InitializeButtons() { boot_button_.OnClick([this]() { Application::GetInstance().ToggleChatState(); }); } + void InitializeIli9341Display() { + esp_lcd_panel_io_handle_t panel_io = nullptr; + esp_lcd_panel_handle_t panel = nullptr; + + // 液晶屏控制IO初始化 + ESP_LOGD(TAG, "Install panel IO"); + esp_lcd_panel_io_spi_config_t io_config = {}; + io_config.cs_gpio_num = GPIO_NUM_5; + io_config.dc_gpio_num = GPIO_NUM_4; + io_config.spi_mode = 0; + io_config.pclk_hz = 40 * 1000 * 1000; + io_config.trans_queue_depth = 10; + io_config.lcd_cmd_bits = 8; + io_config.lcd_param_bits = 8; + ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(SPI3_HOST, &io_config, &panel_io)); + + // 初始化液晶屏驱动芯片 + ESP_LOGD(TAG, "Install LCD driver"); + const ili9341_vendor_config_t vendor_config = { + .init_cmds = &vendor_specific_init[0], + .init_cmds_size = sizeof(vendor_specific_init) / sizeof(ili9341_lcd_init_cmd_t), + }; + + esp_lcd_panel_dev_config_t panel_config = {}; + panel_config.reset_gpio_num = GPIO_NUM_48; + panel_config.flags.reset_active_high = 1, + panel_config.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB; + panel_config.bits_per_pixel = 16; + panel_config.vendor_config = (void *)&vendor_config; + ESP_ERROR_CHECK(esp_lcd_new_panel_ili9341(panel_io, &panel_config, &panel)); + + esp_lcd_panel_reset(panel); + esp_lcd_panel_init(panel); + esp_lcd_panel_invert_color(panel, true); + esp_lcd_panel_swap_xy(panel, DISPLAY_SWAP_XY); + esp_lcd_panel_mirror(panel, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y); + esp_lcd_panel_disp_on_off(panel, true); + display_ = new Ili9341Display(panel_io, panel, DISPLAY_BACKLIGHT_PIN, DISPLAY_BACKLIGHT_OUTPUT_INVERT, + DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY); + } + // 物联网初始化,添加对 AI 可见设备 void InitializeIot() { auto& thing_manager = iot::ThingManager::GetInstance(); @@ -49,6 +124,8 @@ private: public: EspBox3Board() : boot_button_(BOOT_BUTTON_GPIO) { InitializeI2c(); + InitializeSpi(); + InitializeIli9341Display(); InitializeButtons(); InitializeIot(); } @@ -70,8 +147,7 @@ public: } virtual Display* GetDisplay() override { - static NoDisplay display; - return &display; + return display_; } }; diff --git a/main/display/ili9341_display.cc b/main/display/ili9341_display.cc new file mode 100644 index 00000000..9daa2355 --- /dev/null +++ b/main/display/ili9341_display.cc @@ -0,0 +1,374 @@ +#include "ili9341_display.h" +#include "font_awesome_symbols.h" + +#include +#include +#include +#include + +#define TAG "Ili9341Display" +#define LCD_LEDC_CH LEDC_CHANNEL_0 + +#define ILI9341_LVGL_TICK_PERIOD_MS 2 +#define ILI9341_LVGL_TASK_MAX_DELAY_MS 20 +#define ILI9341_LVGL_TASK_MIN_DELAY_MS 1 +#define ILI9341_LVGL_TASK_STACK_SIZE (4 * 1024) +#define ILI9341_LVGL_TASK_PRIORITY 10 + +LV_FONT_DECLARE(font_puhui_14_1); +LV_FONT_DECLARE(font_awesome_30_1); +LV_FONT_DECLARE(font_awesome_14_1); + +static lv_disp_drv_t disp_drv; + +static void ili9341_lvgl_flush_cb(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map) +{ + esp_lcd_panel_handle_t panel_handle = (esp_lcd_panel_handle_t)drv->user_data; + int offsetx1 = area->x1; + int offsetx2 = area->x2; + int offsety1 = area->y1; + int offsety2 = area->y2; + // copy a buffer's content to a specific area of the display + esp_lcd_panel_draw_bitmap(panel_handle, offsetx1, offsety1, offsetx2 + 1, offsety2 + 1, color_map); + lv_disp_flush_ready(&disp_drv); +} + +/* Rotate display and touch, when rotated screen in LVGL. Called when driver parameters are updated. */ +static void ili9341_lvgl_port_update_callback(lv_disp_drv_t *drv) +{ + esp_lcd_panel_handle_t panel_handle = (esp_lcd_panel_handle_t)drv->user_data; + + switch (drv->rotated) + { + case LV_DISP_ROT_NONE: + // Rotate LCD display + esp_lcd_panel_swap_xy(panel_handle, false); + esp_lcd_panel_mirror(panel_handle, true, false); +#if CONFIG_ILI9341_LCD_TOUCH_ENABLED + // Rotate LCD touch + esp_lcd_touch_set_mirror_y(tp, false); + esp_lcd_touch_set_mirror_x(tp, false); +#endif + break; + case LV_DISP_ROT_90: + // Rotate LCD display + esp_lcd_panel_swap_xy(panel_handle, true); + esp_lcd_panel_mirror(panel_handle, true, true); +#if CONFIG_ILI9341_LCD_TOUCH_ENABLED + // Rotate LCD touch + esp_lcd_touch_set_mirror_y(tp, false); + esp_lcd_touch_set_mirror_x(tp, false); +#endif + break; + case LV_DISP_ROT_180: + // Rotate LCD display + esp_lcd_panel_swap_xy(panel_handle, false); + esp_lcd_panel_mirror(panel_handle, false, true); +#if CONFIG_ILI9341_LCD_TOUCH_ENABLED + // Rotate LCD touch + esp_lcd_touch_set_mirror_y(tp, false); + esp_lcd_touch_set_mirror_x(tp, false); +#endif + break; + case LV_DISP_ROT_270: + // Rotate LCD display + esp_lcd_panel_swap_xy(panel_handle, true); + esp_lcd_panel_mirror(panel_handle, false, false); +#if CONFIG_ILI9341_LCD_TOUCH_ENABLED + // Rotate LCD touch + esp_lcd_touch_set_mirror_y(tp, false); + esp_lcd_touch_set_mirror_x(tp, false); +#endif + break; + } +} + +void Ili9341Display::LvglTask() { + ESP_LOGI(TAG, "Starting LVGL task"); + uint32_t task_delay_ms = ILI9341_LVGL_TASK_MAX_DELAY_MS; + while (1) + { + // Lock the mutex due to the LVGL APIs are not thread-safe + if (Lock()) + { + task_delay_ms = lv_timer_handler(); + Unlock(); + } + if (task_delay_ms > ILI9341_LVGL_TASK_MAX_DELAY_MS) + { + task_delay_ms = ILI9341_LVGL_TASK_MAX_DELAY_MS; + } + else if (task_delay_ms < ILI9341_LVGL_TASK_MIN_DELAY_MS) + { + task_delay_ms = ILI9341_LVGL_TASK_MIN_DELAY_MS; + } + vTaskDelay(pdMS_TO_TICKS(task_delay_ms)); + } +} + +Ili9341Display::Ili9341Display(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_handle_t panel, + gpio_num_t backlight_pin, bool backlight_output_invert, + int width, int height, int offset_x, int offset_y, bool mirror_x, bool mirror_y, bool swap_xy) + : panel_io_(panel_io), panel_(panel), backlight_pin_(backlight_pin), backlight_output_invert_(backlight_output_invert), + mirror_x_(mirror_x), mirror_y_(mirror_y), swap_xy_(swap_xy){ + width_ = width; + height_ = height; + offset_x_ = offset_x; + offset_y_ = offset_y; + + + InitializeBacklight(backlight_pin); + + // draw white + std::vector buffer(width_, 0xFFFF); + for (int y = 0; y < height_; y++) { + esp_lcd_panel_draw_bitmap(panel_, 0, y, width_, y + 1, buffer.data()); + } + + // Set the display to on + ESP_LOGI(TAG, "Turning display on"); + ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_, true)); + + ESP_LOGI(TAG, "Initialize LVGL library"); + lv_init(); + // alloc draw buffers used by LVGL + static lv_disp_draw_buf_t disp_buf; // contains internal graphic buffer(s) called draw buffer(s) + // it's recommended to choose the size of the draw buffer(s) to be at least 1/10 screen sized + lv_color_t *buf1 = (lv_color_t *)heap_caps_malloc(width_ * 10 * sizeof(lv_color_t), MALLOC_CAP_DMA); + assert(buf1); + lv_color_t *buf2 = (lv_color_t *)heap_caps_malloc(width_ * 10 * sizeof(lv_color_t), MALLOC_CAP_DMA); + assert(buf2); + // initialize LVGL draw buffers + lv_disp_draw_buf_init(&disp_buf, buf1, buf2, width_ * 10); + + ESP_LOGI(TAG, "Register display driver to LVGL"); + lv_disp_drv_init(&disp_drv); + disp_drv.hor_res = width_; + disp_drv.ver_res = height_; + disp_drv.offset_x = offset_x_; + disp_drv.offset_y = offset_y_; + disp_drv.flush_cb = ili9341_lvgl_flush_cb; + disp_drv.drv_update_cb = ili9341_lvgl_port_update_callback; + disp_drv.draw_buf = &disp_buf; + disp_drv.user_data = panel_; + + lv_disp_drv_register(&disp_drv); + + ESP_LOGI(TAG, "Install LVGL tick timer"); + // Tick interface for LVGL (using esp_timer to generate 2ms periodic event) + const esp_timer_create_args_t lvgl_tick_timer_args = { + .callback = [](void* arg) { + lv_tick_inc(ILI9341_LVGL_TICK_PERIOD_MS); + }, + .arg = NULL, + .dispatch_method = ESP_TIMER_TASK, + .name = "LVGL Tick Timer", + .skip_unhandled_events = false + }; + ESP_ERROR_CHECK(esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer_)); + ESP_ERROR_CHECK(esp_timer_start_periodic(lvgl_tick_timer_, ILI9341_LVGL_TICK_PERIOD_MS * 1000)); + + lvgl_mutex_ = xSemaphoreCreateRecursiveMutex(); + assert(lvgl_mutex_ != nullptr); + ESP_LOGI(TAG, "Create LVGL task"); + xTaskCreate([](void *arg) { + static_cast(arg)->LvglTask(); + vTaskDelete(NULL); + }, "LVGL", ILI9341_LVGL_TASK_STACK_SIZE, this, ILI9341_LVGL_TASK_PRIORITY, NULL); + + SetBacklight(100); + + SetupUI(); +} + +Ili9341Display::~Ili9341Display() { + ESP_ERROR_CHECK(esp_timer_stop(lvgl_tick_timer_)); + ESP_ERROR_CHECK(esp_timer_delete(lvgl_tick_timer_)); + + if (network_label_ != nullptr) { + lv_obj_del(ai_messge_label_); + lv_obj_del(user_messge_label_); + } + + if (content_ != nullptr) { + lv_obj_del(content_); + } + if (status_bar_ != nullptr) { + lv_obj_del(status_bar_); + } + if (side_bar_ != nullptr) { + lv_obj_del(side_bar_); + } + if (container_ != nullptr) { + lv_obj_del(container_); + } + + if (panel_ != nullptr) { + esp_lcd_panel_del(panel_); + } + if (panel_io_ != nullptr) { + esp_lcd_panel_io_del(panel_io_); + } + vSemaphoreDelete(lvgl_mutex_); +} + +void Ili9341Display::InitializeBacklight(gpio_num_t backlight_pin) { + if (backlight_pin == GPIO_NUM_NC) { + return; + } + + // Setup LEDC peripheral for PWM backlight control + const ledc_channel_config_t backlight_channel = { + .gpio_num = backlight_pin, + .speed_mode = LEDC_LOW_SPEED_MODE, + .channel = LCD_LEDC_CH, + .intr_type = LEDC_INTR_DISABLE, + .timer_sel = LEDC_TIMER_0, + .duty = 0, + .hpoint = 0, + .flags = { + .output_invert = backlight_output_invert_, + } + }; + const ledc_timer_config_t backlight_timer = { + .speed_mode = LEDC_LOW_SPEED_MODE, + .duty_resolution = LEDC_TIMER_10_BIT, + .timer_num = LEDC_TIMER_0, + .freq_hz = 5000, + .clk_cfg = LEDC_AUTO_CLK, + .deconfigure = false + }; + + ESP_ERROR_CHECK(ledc_timer_config(&backlight_timer)); + ESP_ERROR_CHECK(ledc_channel_config(&backlight_channel)); +} + +void Ili9341Display::SetBacklight(uint8_t brightness) { + if (backlight_pin_ == GPIO_NUM_NC) { + return; + } + + if (brightness > 100) { + brightness = 100; + } + + ESP_LOGI(TAG, "Setting LCD backlight: %d%%", brightness); + // LEDC resolution set to 10bits, thus: 100% = 1023 + uint32_t duty_cycle = (1023 * brightness) / 100; + ESP_ERROR_CHECK(ledc_set_duty(LEDC_LOW_SPEED_MODE, LCD_LEDC_CH, duty_cycle)); + ESP_ERROR_CHECK(ledc_update_duty(LEDC_LOW_SPEED_MODE, LCD_LEDC_CH)); +} + +bool Ili9341Display::Lock(int timeout_ms) { + // Convert timeout in milliseconds to FreeRTOS ticks + // If `timeout_ms` is set to 0, the program will block until the condition is met + const TickType_t timeout_ticks = (timeout_ms == 0) ? portMAX_DELAY : pdMS_TO_TICKS(timeout_ms); + return xSemaphoreTakeRecursive(lvgl_mutex_, timeout_ticks) == pdTRUE; +} + +void Ili9341Display::Unlock() { + xSemaphoreGiveRecursive(lvgl_mutex_); +} + +void Ili9341Display::SetChatMessage(const std::string &role, const std::string &content) { + if (ai_messge_label_== nullptr || user_messge_label_== nullptr) { + return; + } + DisplayLockGuard lock(this); + ESP_LOGI(TAG,"role:%s",role.c_str()); + if(role=="assistant") + { + std::string new_content = "AI:" + content; + lv_label_set_text(ai_messge_label_, new_content.c_str()); + } + else if(role=="user") + { + std::string new_content = "User:" + content; + lv_label_set_text(user_messge_label_, new_content.c_str()); + } + else{ + std::string new_content = "AI:"; + lv_label_set_text(ai_messge_label_, new_content.c_str()); + new_content="User:"; + lv_label_set_text(user_messge_label_, new_content.c_str()); + } +} + +void Ili9341Display::SetupUI() { + DisplayLockGuard lock(this); + + auto screen = lv_disp_get_scr_act(lv_disp_get_default()); + lv_obj_set_style_text_font(screen, &font_puhui_14_1, 0); + lv_obj_set_style_text_color(screen, lv_color_black(), 0); + + /* Container */ + container_ = lv_obj_create(screen); + lv_obj_set_size(container_, LV_HOR_RES, LV_VER_RES); + lv_obj_set_flex_flow(container_, LV_FLEX_FLOW_COLUMN); + lv_obj_set_style_pad_all(container_, 0, 0); + lv_obj_set_style_border_width(container_, 0, 0); + lv_obj_set_style_pad_row(container_, 0, 0); + + /* Status bar */ + status_bar_ = lv_obj_create(container_); + lv_obj_set_size(status_bar_, LV_HOR_RES, 18); + lv_obj_set_style_radius(status_bar_, 0, 0); + + /* Content */ + content_ = lv_obj_create(container_); + lv_obj_set_scrollbar_mode(content_, LV_SCROLLBAR_MODE_OFF); + lv_obj_set_style_radius(content_, 0, 0); + lv_obj_set_width(content_, LV_HOR_RES); + lv_obj_set_flex_grow(content_, 1); + + emotion_label_ = lv_label_create(content_); + lv_obj_set_style_text_font(emotion_label_, &font_awesome_30_1, 0); + lv_label_set_text(emotion_label_, FONT_AWESOME_AI_CHIP); + //lv_obj_center(emotion_label_); + lv_obj_align(emotion_label_,LV_ALIGN_TOP_MID, 0, -10); // 左侧居中,向右偏移10个单位 + + static lv_style_t style_msg; + lv_style_init(&style_msg); + lv_style_set_width(&style_msg, LV_HOR_RES-25); + + user_messge_label_ = lv_label_create(content_); + lv_obj_set_style_text_font(user_messge_label_, &font_puhui_14_1, 0); + lv_label_set_text(user_messge_label_, "User:"); + lv_obj_add_style(user_messge_label_, &style_msg, 0); + lv_obj_align(user_messge_label_,LV_ALIGN_TOP_LEFT, 2, 25); + + ai_messge_label_ = lv_label_create(content_); + lv_obj_set_style_text_font(ai_messge_label_, &font_puhui_14_1, 0); + lv_label_set_text(ai_messge_label_, "AI:"); + lv_obj_add_style(ai_messge_label_, &style_msg, 0); + lv_obj_align(ai_messge_label_,LV_ALIGN_TOP_LEFT, 2, 77); + + /* Status bar */ + lv_obj_set_flex_flow(status_bar_, LV_FLEX_FLOW_ROW); + lv_obj_set_style_pad_all(status_bar_, 0, 0); + lv_obj_set_style_border_width(status_bar_, 0, 0); + lv_obj_set_style_pad_column(status_bar_, 0, 0); + + network_label_ = lv_label_create(status_bar_); + lv_label_set_text(network_label_, ""); + lv_obj_set_style_text_font(network_label_, &font_awesome_14_1, 0); + + notification_label_ = lv_label_create(status_bar_); + lv_obj_set_flex_grow(notification_label_, 1); + lv_obj_set_style_text_align(notification_label_, LV_TEXT_ALIGN_CENTER, 0); + lv_label_set_text(notification_label_, "通知"); + lv_obj_add_flag(notification_label_, LV_OBJ_FLAG_HIDDEN); + + status_label_ = lv_label_create(status_bar_); + lv_obj_set_flex_grow(status_label_, 1); + lv_label_set_text(status_label_, "正在初始化"); + lv_obj_set_style_text_align(status_label_, LV_TEXT_ALIGN_CENTER, 0); + + mute_label_ = lv_label_create(status_bar_); + lv_label_set_text(mute_label_, ""); + lv_obj_set_style_text_font(mute_label_, &font_awesome_14_1, 0); + + battery_label_ = lv_label_create(status_bar_); + lv_label_set_text(battery_label_, ""); + lv_obj_set_style_text_font(battery_label_, &font_awesome_14_1, 0); +} \ No newline at end of file diff --git a/main/display/ili9341_display.h b/main/display/ili9341_display.h new file mode 100644 index 00000000..9beb08b8 --- /dev/null +++ b/main/display/ili9341_display.h @@ -0,0 +1,51 @@ +#ifndef ILI9341_DISPLAY_H +#define ILI9341_DISPLAY_H + +#include "display.h" +#include "esp_lcd_ili9341.h" +#include +#include +#include +#include +#include +#include + +class Ili9341Display : public Display { +private: + esp_lcd_panel_io_handle_t panel_io_ = nullptr; + esp_lcd_panel_handle_t panel_ = nullptr; + gpio_num_t backlight_pin_ = GPIO_NUM_NC; + bool backlight_output_invert_ = false; + bool mirror_x_ = false; + bool mirror_y_ = false; + bool swap_xy_ = false; + int offset_x_ = 0; + int offset_y_ = 0; + SemaphoreHandle_t lvgl_mutex_ = nullptr; + esp_timer_handle_t lvgl_tick_timer_ = nullptr; + + lv_obj_t* status_bar_ = nullptr; + lv_obj_t* content_ = nullptr; + lv_obj_t* container_ = nullptr; + lv_obj_t* side_bar_ = nullptr; + + lv_obj_t *user_messge_label_ = nullptr; + lv_obj_t *ai_messge_label_ = nullptr; + + void InitializeBacklight(gpio_num_t backlight_pin); + void SetBacklight(uint8_t brightness); + void SetupUI(); + void LvglTask(); + + virtual bool Lock(int timeout_ms = 0) override; + virtual void Unlock() override; + virtual void SetChatMessage(const std::string &role, const std::string &content) override; + +public: + Ili9341Display(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_handle_t panel, + gpio_num_t backlight_pin, bool backlight_output_invert, + int width, int height, int offset_x, int offset_y, bool mirror_x, bool mirror_y, bool swap_xy); + ~Ili9341Display(); +}; + +#endif // Ili9341_DISPLAY_H diff --git a/main/idf_component.yml b/main/idf_component.yml index 6cbd79a0..45049fdd 100644 --- a/main/idf_component.yml +++ b/main/idf_component.yml @@ -1,6 +1,6 @@ ## IDF Component Manager Manifest File dependencies: - espressif/esp_lcd_ili9341: "==1.0.0" + espressif/esp_lcd_ili9341: "==1.2.0" 78/esp-wifi-connect: "~1.4.1" 78/esp-opus-encoder: "~2.0.0" 78/esp-ml307: "~1.7.0"