From a8687f37369d4b992bc9ea2e329ad3a65be48a31 Mon Sep 17 00:00:00 2001 From: Y1hsiaochunnn <66012385+Y1hsiaochunnn@users.noreply.github.com> Date: Fri, 19 Sep 2025 22:42:30 +0800 Subject: [PATCH] New Waveshare ESP32-S3-Touch-LCD-4B third party board, 86 box form. (#1199) Co-authored-by: Xiaoxia --- main/CMakeLists.txt | 5 + main/Kconfig.projbuild | 4 +- .../waveshare-s3-touch-lcd-4b/README.md | 12 + .../boards/waveshare-s3-touch-lcd-4b/config.h | 65 +++ .../waveshare-s3-touch-lcd-4b/config.json | 12 + .../esp32-s3-touch-lcd-4b.cc | 432 ++++++++++++++++++ main/idf_component.yml | 1 + 7 files changed, 530 insertions(+), 1 deletion(-) create mode 100644 main/boards/waveshare-s3-touch-lcd-4b/README.md create mode 100644 main/boards/waveshare-s3-touch-lcd-4b/config.h create mode 100644 main/boards/waveshare-s3-touch-lcd-4b/config.json create mode 100644 main/boards/waveshare-s3-touch-lcd-4b/esp32-s3-touch-lcd-4b.cc diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index f9867e18..d9751fc5 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -229,6 +229,11 @@ elseif(CONFIG_BOARD_TYPE_ESP32S3_Touch_AMOLED_2_06) set(BUILTIN_TEXT_FONT font_puhui_basic_30_4) set(BUILTIN_ICON_FONT font_awesome_30_4) set(DEFAULT_EMOJI_COLLECTION twemoji_64) +elseif(CONFIG_BOARD_TYPE_ESP32S3_Touch_LCD_4B) + set(BOARD_TYPE "waveshare-s3-touch-lcd-4b") + set(BUILTIN_TEXT_FONT font_puhui_basic_30_4) + set(BUILTIN_ICON_FONT font_awesome_30_4) + set(DEFAULT_EMOJI_COLLECTION twemoji_64) elseif(CONFIG_BOARD_TYPE_ESP32S3_Touch_AMOLED_1_75) set(BOARD_TYPE "waveshare-s3-touch-amoled-1.75") set(BUILTIN_TEXT_FONT font_puhui_basic_30_4) diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild index 2e1875ae..68753e16 100644 --- a/main/Kconfig.projbuild +++ b/main/Kconfig.projbuild @@ -215,6 +215,8 @@ choice BOARD_TYPE bool "Waveshare ESP32-S3-Touch-AMOLED-2.06" config BOARD_TYPE_ESP32S3_Touch_AMOLED_1_75 bool "Waveshare ESP32-S3-Touch-AMOLED-1.75" + config BOARD_TYPE_ESP32S3_Touch_LCD_4B + bool "Waveshare ESP32-S3-Touch-LCD-4B" depends on IDF_TARGET_ESP32S3 config BOARD_TYPE_ESP32S3_Touch_LCD_1_85C bool "Waveshare ESP32-S3-Touch-LCD-1.85C" @@ -545,7 +547,7 @@ config USE_DEVICE_AEC default n depends on USE_AUDIO_PROCESSOR && (BOARD_TYPE_ESP_BOX_3 || BOARD_TYPE_ESP_BOX || BOARD_TYPE_ESP_BOX_LITE \ || BOARD_TYPE_LICHUANG_DEV || BOARD_TYPE_ESP32S3_KORVO2_V3 || BOARD_TYPE_ESP32S3_Touch_AMOLED_1_75 \ - || BOARD_TYPE_ESP32S3_Touch_AMOLED_2_06 || BOARD_TYPE_ESP32P4_WIFI6_Touch_LCD_4B \ + || BOARD_TYPE_ESP32S3_Touch_AMOLED_2_06 || BOARD_TYPE_ESP32S3_Touch_LCD_4B || BOARD_TYPE_ESP32P4_WIFI6_Touch_LCD_4B \ || BOARD_TYPE_ESP32P4_WIFI6_Touch_LCD_XC || BOARD_TYPE_ESP_S3_LCD_EV_Board_2 || BOARD_TYPE_YUNLIAO_S3 \ || BOARD_TYPE_ECHOEAR) help diff --git a/main/boards/waveshare-s3-touch-lcd-4b/README.md b/main/boards/waveshare-s3-touch-lcd-4b/README.md new file mode 100644 index 00000000..81dc4505 --- /dev/null +++ b/main/boards/waveshare-s3-touch-lcd-4b/README.md @@ -0,0 +1,12 @@ +# Waveshare ESP32-S3-Touch-LCD-4B + + +[ESP32-S3-Touch-LCD-4B](https://www.waveshare.com/esp32-s3-touch-lcd-4b.htm) is waveshare electronics designed an intelligent 86 box based on ESP32-S3 module equipped with a 480*480 IPS capacitive touch screen + + +## Configuration + +Configuration in `menuconfig`. + +Selection Board Type `Xiaozhi Assistant --> Board Type` +- Waveshare ESP32-S3-Touch-LCD-4B \ No newline at end of file diff --git a/main/boards/waveshare-s3-touch-lcd-4b/config.h b/main/boards/waveshare-s3-touch-lcd-4b/config.h new file mode 100644 index 00000000..aba2eac6 --- /dev/null +++ b/main/boards/waveshare-s3-touch-lcd-4b/config.h @@ -0,0 +1,65 @@ +#ifndef _BOARD_CONFIG_H_ +#define _BOARD_CONFIG_H_ + +#include + +#define AUDIO_INPUT_SAMPLE_RATE 24000 +#define AUDIO_OUTPUT_SAMPLE_RATE 24000 + +#define AUDIO_INPUT_REFERENCE true + +#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_5 +#define AUDIO_I2S_GPIO_WS GPIO_NUM_7 +#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_16 +#define AUDIO_I2S_GPIO_DIN GPIO_NUM_15 +#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_6 + +#define AUDIO_CODEC_PA_PIN GPIO_NUM_NC +#define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_47 +#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_48 +#define AUDIO_CODEC_ES8311_ADDR ES8311_CODEC_DEFAULT_ADDR +#define AUDIO_CODEC_ES7210_ADDR ES7210_CODEC_DEFAULT_ADDR + +#define I2C_ADDRESS ESP_IO_EXPANDER_I2C_TCA9554_ADDRESS_000 +#define BOOT_BUTTON_GPIO GPIO_NUM_0 + +#define BSP_LCD_VSYNC (GPIO_NUM_3) +#define BSP_LCD_HSYNC (GPIO_NUM_46) +#define BSP_LCD_DE (GPIO_NUM_17) +#define BSP_LCD_PCLK (GPIO_NUM_9) +#define BSP_LCD_DISP (GPIO_NUM_NC) +#define BSP_LCD_DATA0 (GPIO_NUM_40) +#define BSP_LCD_DATA1 (GPIO_NUM_41) +#define BSP_LCD_DATA2 (GPIO_NUM_42) +#define BSP_LCD_DATA3 (GPIO_NUM_2) +#define BSP_LCD_DATA4 (GPIO_NUM_1) +#define BSP_LCD_DATA5 (GPIO_NUM_21) +#define BSP_LCD_DATA6 (GPIO_NUM_8) +#define BSP_LCD_DATA7 (GPIO_NUM_18) +#define BSP_LCD_DATA8 (GPIO_NUM_45) +#define BSP_LCD_DATA9 (GPIO_NUM_38) +#define BSP_LCD_DATA10 (GPIO_NUM_39) +#define BSP_LCD_DATA11 (GPIO_NUM_10) +#define BSP_LCD_DATA12 (GPIO_NUM_11) +#define BSP_LCD_DATA13 (GPIO_NUM_12) +#define BSP_LCD_DATA14 (GPIO_NUM_13) +#define BSP_LCD_DATA15 (GPIO_NUM_14) + +#define BSP_LCD_IO_SPI_CS (IO_EXPANDER_PIN_NUM_0) +#define BSP_LCD_IO_SPI_SCL (IO_EXPANDER_PIN_NUM_2) +#define BSP_LCD_IO_SPI_SDA (IO_EXPANDER_PIN_NUM_1) + +#define DISPLAY_WIDTH 480 +#define DISPLAY_HEIGHT 480 + +#define DISPLAY_SWAP_XY false +#define DISPLAY_MIRROR_X false +#define DISPLAY_MIRROR_Y false + +#define DISPLAY_OFFSET_X 0 +#define DISPLAY_OFFSET_Y 0 + +#define DISPLAY_BACKLIGHT_PIN GPIO_NUM_4 +#define DISPLAY_BACKLIGHT_OUTPUT_INVERT true + +#endif // _BOARD_CONFIG_H_ diff --git a/main/boards/waveshare-s3-touch-lcd-4b/config.json b/main/boards/waveshare-s3-touch-lcd-4b/config.json new file mode 100644 index 00000000..f703cc0d --- /dev/null +++ b/main/boards/waveshare-s3-touch-lcd-4b/config.json @@ -0,0 +1,12 @@ +{ + "target": "esp32s3", + "builds": [ + { + "name": "waveshare-s3-touch-lcd-4b", + "sdkconfig_append": [ + "CONFIG_USE_WECHAT_MESSAGE_STYLE=n", + "CONFIG_USE_DEVICE_AEC=y" + ] + } + ] +} \ No newline at end of file diff --git a/main/boards/waveshare-s3-touch-lcd-4b/esp32-s3-touch-lcd-4b.cc b/main/boards/waveshare-s3-touch-lcd-4b/esp32-s3-touch-lcd-4b.cc new file mode 100644 index 00000000..bef2b55b --- /dev/null +++ b/main/boards/waveshare-s3-touch-lcd-4b/esp32-s3-touch-lcd-4b.cc @@ -0,0 +1,432 @@ +#include "wifi_board.h" +#include "display/lcd_display.h" +#include "esp_lcd_st7701.h" + +#include "codecs/box_audio_codec.h" +#include "application.h" +#include "button.h" +#include "led/single_led.h" +#include "mcp_server.h" +#include "config.h" +#include "power_save_timer.h" +#include "axp2101.h" +#include "i2c_device.h" +#include + +#include +#include +#include +#include +#include "esp_io_expander_tca9554.h" +#include "settings.h" + +#include +#include +#include + +#include +#include +#include +#include + +#define TAG "WaveshareEsp32s3TouchLCD4b" + +class Pmic : public Axp2101 { +public: + Pmic(i2c_master_bus_handle_t i2c_bus, uint8_t addr) : Axp2101(i2c_bus, addr) { + WriteReg(0x22, 0b110); // PWRON > OFFLEVEL as POWEROFF Source enable + WriteReg(0x27, 0x10); // hold 4s to power off + + // Disable All DCs but DC1 + WriteReg(0x80, 0x01); + // Disable All LDOs + WriteReg(0x90, 0x00); + WriteReg(0x91, 0x00); + + // Set DC1 to 3.3V + WriteReg(0x82, (3300 - 1500) / 100); + + // Set ALDO1 to 3.3V + WriteReg(0x92, (3300 - 500) / 100); + + // Enable ALDO1(MIC) + WriteReg(0x90, 0x01); + + WriteReg(0x64, 0x02); // CV charger voltage setting to 4.1V + + WriteReg(0x61, 0x02); // set Main battery precharge current to 50mA + WriteReg(0x62, 0x08); // set Main battery charger current to 400mA ( 0x08-200mA, 0x09-300mA, 0x0A-400mA ) + WriteReg(0x63, 0x01); // set Main battery term charge current to 25mA + } +}; + +#define LCD_OPCODE_WRITE_CMD (0x02ULL) +#define LCD_OPCODE_READ_CMD (0x03ULL) +#define LCD_OPCODE_WRITE_COLOR (0x32ULL) + +static const st7701_lcd_init_cmd_t lcd_init_cmds[] = { +// {cmd, { data }, data_size, delay_ms} + {0x11, (uint8_t[]){0x00}, 0, 120}, + {0xFF, (uint8_t[]){0x77, 0x01, 0x00, 0x00, 0x10}, 5, 0}, + {0xC0, (uint8_t[]){0x3B, 0x00}, 2, 0}, + {0xC1, (uint8_t[]){0x0D, 0x02}, 2, 0}, + {0xC2, (uint8_t[]){0x21, 0x08}, 2, 0}, + {0xCD, (uint8_t[]){0x08}, 1, 0}, + {0xB0, (uint8_t[]){0x00, 0x11, 0x18, 0x0E, 0x11, 0x06, 0x07, 0x08, 0x07, 0x22, 0x04, 0x12, 0x0F, 0xAA, 0x31, 0x18}, 16, 0}, + {0xB1, (uint8_t[]){0x00, 0x11, 0x19, 0x0E, 0x12, 0x07, 0x08, 0x08, 0x08, 0x22, 0x04, 0x11, 0x11, 0xA9, 0x32, 0x18}, 16, 0}, + {0xFF, (uint8_t[]){0x77, 0x01, 0x00, 0x00, 0x11}, 5, 0}, + {0xB0, (uint8_t[]){0x60}, 1, 0}, + {0xB1, (uint8_t[]){0x30}, 1, 0}, + {0xB2, (uint8_t[]){0x87}, 1, 0}, + {0xB3, (uint8_t[]){0x80}, 1, 0}, + {0xB5, (uint8_t[]){0x49}, 1, 0}, + {0xB7, (uint8_t[]){0x85}, 1, 0}, + {0xB8, (uint8_t[]){0x21}, 1, 0}, + {0xC1, (uint8_t[]){0x78}, 1, 0}, + {0xC2, (uint8_t[]){0x78}, 1, 20}, + {0xE0, (uint8_t[]){0x00, 0x1B, 0x02}, 3, 0}, + {0xE1, (uint8_t[]){0x08, 0xA0, 0x00, 0x00, 0x07, 0xA0, 0x00, 0x00, 0x00, 0x44, 0x44}, 11, 0}, + {0xE2, (uint8_t[]){0x11, 0x11, 0x44, 0x44, 0xED, 0xA0, 0x00, 0x00, 0xEC, 0xA0, 0x00, 0x00}, 12, 0}, + {0xE3, (uint8_t[]){0x00, 0x00, 0x11, 0x11}, 4, 0}, + {0xE4, (uint8_t[]){0x44, 0x44}, 2, 0}, + {0xE5, (uint8_t[]){0x0A, 0xE9, 0xD8, 0xA0, 0x0C, 0xEB, 0xD8, 0xA0, 0x0E, 0xED, 0xD8, 0xA0, 0x10, 0xEF, 0xD8, 0xA0}, 16, 0}, + {0xE6, (uint8_t[]){0x00, 0x00, 0x11, 0x11}, 4, 0}, + {0xE7, (uint8_t[]){0x44, 0x44}, 2, 0}, + {0xE8, (uint8_t[]){0x09, 0xE8, 0xD8, 0xA0, 0x0B, 0xEA, 0xD8, 0xA0, 0x0D, 0xEC, 0xD8, 0xA0, 0x0F, 0xEE, 0xD8, 0xA0}, 16, 0}, + {0xEB, (uint8_t[]){0x02, 0x00, 0xE4, 0xE4, 0x88, 0x00, 0x40}, 7, 0}, + {0xEC, (uint8_t[]){0x3C, 0x00}, 2, 0}, + {0xED, (uint8_t[]){0xAB, 0x89, 0x76, 0x54, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x20, 0x45, 0x67, 0x98, 0xBA}, 16, 0}, + {0xFF, (uint8_t[]){0x77, 0x01, 0x00, 0x00, 0x00}, 5, 0}, + {0x36, (uint8_t[]){0x00}, 1, 0}, + {0x3A, (uint8_t[]){0x66}, 1, 0}, + {0x21, (uint8_t[]){0x00}, 0, 120}, + {0x29, (uint8_t[]){0x00}, 0, 0}, +}; + +class WaveshareEsp32s3TouchLCD4b : public WifiBoard { +private: + i2c_master_bus_handle_t i2c_bus_; + Pmic* pmic_ = nullptr; + Button boot_button_; + LcdDisplay* display_; + esp_io_expander_handle_t io_expander = NULL; + PowerSaveTimer* power_save_timer_; + + uint32_t key_press_start; + bool key_pressed; + bool key_handled; + + void InitializePowerSaveTimer() { + power_save_timer_ = new PowerSaveTimer(-1, 60, 300); + power_save_timer_->OnEnterSleepMode([this]() { + GetDisplay()->SetPowerSaveMode(true); + GetBacklight()->SetBrightness(70); }); + power_save_timer_->OnExitSleepMode([this]() { + GetDisplay()->SetPowerSaveMode(false); + GetBacklight()->RestoreBrightness(); }); + power_save_timer_->OnShutdownRequest([this](){ + pmic_->PowerOff(); }); + power_save_timer_->SetEnabled(true); + } + + void InitializeCodecI2c() { + // Initialize I2C peripheral + i2c_master_bus_config_t i2c_bus_cfg = { + .i2c_port = I2C_NUM_0, + .sda_io_num = AUDIO_CODEC_I2C_SDA_PIN, + .scl_io_num = AUDIO_CODEC_I2C_SCL_PIN, + .clk_source = I2C_CLK_SRC_DEFAULT, + .glitch_ignore_cnt = 7, + .trans_queue_depth = 0, + .flags = { + .enable_internal_pullup = 1, + }, + }; + ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &i2c_bus_)); + } + + void InitializeTca9554(void) { + esp_io_expander_new_i2c_tca9554(i2c_bus_, I2C_ADDRESS, &io_expander); + esp_io_expander_set_dir(io_expander, IO_EXPANDER_PIN_NUM_3|IO_EXPANDER_PIN_NUM_5 | IO_EXPANDER_PIN_NUM_6 , IO_EXPANDER_OUTPUT); + esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_3, 1); + esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_6, 0); + vTaskDelay(pdMS_TO_TICKS(200)); + esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_5, 0); + vTaskDelay(pdMS_TO_TICKS(200)); + esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_5, 1); + vTaskDelay(pdMS_TO_TICKS(200)); + esp_io_expander_set_dir(io_expander, IO_EXPANDER_PIN_NUM_4|IO_EXPANDER_PIN_NUM_6, IO_EXPANDER_INPUT); + } + void InitializeAxp2101() { + ESP_LOGI(TAG, "Init AXP2101"); + pmic_ = new Pmic(i2c_bus_, 0x34); + } + + void InitializeRGB() { + esp_lcd_panel_io_handle_t panel_io = nullptr; + + spi_line_config_t line_config = { + .cs_io_type = IO_TYPE_EXPANDER, + .cs_expander_pin = BSP_LCD_IO_SPI_CS, + .scl_io_type = IO_TYPE_EXPANDER, + .scl_expander_pin = BSP_LCD_IO_SPI_SCL, + .sda_io_type = IO_TYPE_EXPANDER, + .sda_expander_pin = BSP_LCD_IO_SPI_SDA, + .io_expander = io_expander, + }; + esp_lcd_panel_io_3wire_spi_config_t io_config = ST7701_PANEL_IO_3WIRE_SPI_CONFIG(line_config, 0); + ESP_ERROR_CHECK(esp_lcd_new_panel_io_3wire_spi(&io_config, &panel_io)); + esp_lcd_panel_handle_t panel_handle = NULL; + esp_lcd_rgb_panel_config_t rgb_config = { + .clk_src = LCD_CLK_SRC_DEFAULT, + .timings = { + .pclk_hz = 16 * 1000 * 1000, + .h_res = DISPLAY_WIDTH, + .v_res = DISPLAY_HEIGHT, + .hsync_pulse_width = 10, + .hsync_back_porch = 10, + .hsync_front_porch = 20, + .vsync_pulse_width = 10, + .vsync_back_porch = 10, + .vsync_front_porch = 10, + .flags = { + .pclk_active_neg = false + } + }, + .data_width = 16, + .bits_per_pixel = 16, + .num_fbs = 2, + .bounce_buffer_size_px = 480 * 20, + .psram_trans_align = 64, + .hsync_gpio_num = BSP_LCD_HSYNC, + .vsync_gpio_num = BSP_LCD_VSYNC, + .de_gpio_num = BSP_LCD_DE, + .pclk_gpio_num = BSP_LCD_PCLK, + .disp_gpio_num = BSP_LCD_DISP, + .data_gpio_nums = { + BSP_LCD_DATA0, BSP_LCD_DATA1, BSP_LCD_DATA2, BSP_LCD_DATA3, + BSP_LCD_DATA4, BSP_LCD_DATA5, BSP_LCD_DATA6, BSP_LCD_DATA7, + BSP_LCD_DATA8, BSP_LCD_DATA9, BSP_LCD_DATA10, BSP_LCD_DATA11, + BSP_LCD_DATA12, BSP_LCD_DATA13, BSP_LCD_DATA14, BSP_LCD_DATA15 + }, + .flags = { + .fb_in_psram = 1, + }, + }; + + rgb_config.timings.h_res = DISPLAY_WIDTH; + rgb_config.timings.v_res = DISPLAY_HEIGHT; + st7701_vendor_config_t vendor_config = { + .init_cmds = lcd_init_cmds, + .init_cmds_size = sizeof(lcd_init_cmds) / sizeof(lcd_init_cmds[0]), + .rgb_config = &rgb_config, + .flags = { + .mirror_by_cmd = 0, + .auto_del_panel_io = 1, + } + }; + const esp_lcd_panel_dev_config_t panel_config = { + .reset_gpio_num = GPIO_NUM_NC, + .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB, + .bits_per_pixel = 18, + .vendor_config = &vendor_config, + }; + ESP_ERROR_CHECK(esp_lcd_new_panel_st7701(panel_io, &panel_config, &panel_handle)); + esp_lcd_panel_init(panel_handle); + + display_ = new RgbLcdDisplay(panel_io, panel_handle, + DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, + DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY); + } + + void InitializeButtons() { + boot_button_.OnClick([this]() { + auto& app = Application::GetInstance(); + if (app.GetDeviceState() == kDeviceStateStarting && !WifiStation::GetInstance().IsConnected()) { + ResetWifiConfiguration(); + } + app.ToggleChatState(); + }); + +#if CONFIG_USE_DEVICE_AEC + boot_button_.OnDoubleClick([this]() { + auto& app = Application::GetInstance(); + if (app.GetDeviceState() == kDeviceStateIdle) { + app.SetAecMode(app.GetAecMode() == kAecOff ? kAecOnDeviceSide : kAecOff); + } + }); +#endif + } + + void InitializeTouch() { + esp_lcd_touch_handle_t tp; + esp_lcd_touch_config_t tp_cfg = { + .x_max = DISPLAY_WIDTH - 1, + .y_max = DISPLAY_HEIGHT - 1, + .rst_gpio_num = GPIO_NUM_NC, + .int_gpio_num = GPIO_NUM_NC, + .levels = { + .reset = 0, + .interrupt = 0, + }, + .flags = { + .swap_xy = 0, + .mirror_x = 0, + .mirror_y = 0, + }, + }; + esp_lcd_panel_io_handle_t tp_io_handle = NULL; + esp_lcd_panel_io_i2c_config_t tp_io_config = ESP_LCD_TOUCH_IO_I2C_GT911_CONFIG(); + tp_io_config.scl_speed_hz = 400* 1000; + ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c(i2c_bus_, &tp_io_config, &tp_io_handle)); + ESP_LOGI(TAG, "Initialize touch controller"); + ESP_ERROR_CHECK(esp_lcd_touch_new_i2c_gt911(tp_io_handle, &tp_cfg, &tp)); + const lvgl_port_touch_cfg_t touch_cfg = { + .disp = lv_display_get_default(), + .handle = tp, + }; + lvgl_port_add_touch(&touch_cfg); + ESP_LOGI(TAG, "Touch panel initialized successfully"); + } + + void InitializeTools() { + auto &mcp_server = McpServer::GetInstance(); + mcp_server.AddTool("self.system.reconfigure_wifi", + "Reboot the device and enter WiFi configuration mode.\n" + "**CAUTION** You must ask the user to confirm this action.", + PropertyList(), [this](const PropertyList& properties) { + ResetWifiConfiguration(); + return true; + }); + } + void CheckKeyState() { + if (!io_expander) return; + + uint32_t current_level; + esp_err_t ret = esp_io_expander_get_level(io_expander, IO_EXPANDER_PIN_NUM_4, ¤t_level); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to read IO_EXPANDER_PIN_NUM_4 level"); + return; + } + + static uint32_t last_level = 0; + static uint64_t press_start_time_ms = 0; + + if (current_level != last_level) { + last_level = current_level; + + if (current_level > 0) { + press_start_time_ms = esp_timer_get_time() / 1000; + ESP_LOGD(TAG, "Button pressed, start time recorded"); + } else { + uint64_t press_duration = (esp_timer_get_time() / 1000) - press_start_time_ms; + ESP_LOGI(TAG, "Button released after %llums", press_duration); + + if (press_duration < 1000) { + ESP_LOGI(TAG, "Short press detected, switching to factory partition"); + + const esp_partition_t* factory_partition = esp_partition_find_first( + ESP_PARTITION_TYPE_APP, + ESP_PARTITION_SUBTYPE_APP_FACTORY, + nullptr + ); + if (factory_partition) { + ESP_LOGI(TAG, "Found factory partition: %s", factory_partition->label); + ESP_ERROR_CHECK(esp_ota_set_boot_partition(factory_partition)); + esp_restart(); + } else { + ESP_LOGE(TAG, "Factory partition not found"); + } + } else { + ESP_LOGI(TAG, "Long press detected (>1000ms), no action"); + } + } + } + } + + void InitializeKeyMonitor() { + key_press_start = 0; + key_pressed = false; + key_handled = false; + + xTaskCreatePinnedToCore( + [](void* arg) { + auto* board = static_cast(arg); + while (true) { + board->CheckKeyState(); + vTaskDelay(pdMS_TO_TICKS(20)); + } + }, + "key_monitor_task", + 4096, + this, + 5, + nullptr, + 0 + ); + } + +public: + WaveshareEsp32s3TouchLCD4b() : boot_button_(BOOT_BUTTON_GPIO) { + InitializePowerSaveTimer(); + InitializeCodecI2c(); + InitializeTca9554(); + InitializeAxp2101(); + InitializeRGB(); + InitializeTouch(); + InitializeButtons(); + InitializeTools(); + InitializeKeyMonitor(); // 启动按键监听 + GetBacklight()->SetBrightness(100); + } + + virtual AudioCodec* GetAudioCodec() override { + static BoxAudioCodec audio_codec( + i2c_bus_, + AUDIO_INPUT_SAMPLE_RATE, + AUDIO_OUTPUT_SAMPLE_RATE, + AUDIO_I2S_GPIO_MCLK, + AUDIO_I2S_GPIO_BCLK, + AUDIO_I2S_GPIO_WS, + AUDIO_I2S_GPIO_DOUT, + AUDIO_I2S_GPIO_DIN, + AUDIO_CODEC_PA_PIN, + AUDIO_CODEC_ES8311_ADDR, + AUDIO_CODEC_ES7210_ADDR, + AUDIO_INPUT_REFERENCE); + return &audio_codec; + } + + virtual Display* GetDisplay() override { + return display_; + } + + virtual Backlight* GetBacklight() override { + static PwmBacklight backlight(DISPLAY_BACKLIGHT_PIN, DISPLAY_BACKLIGHT_OUTPUT_INVERT); + return &backlight; + } + + virtual bool GetBatteryLevel(int &level, bool &charging, bool &discharging) override { + static bool last_discharging = false; + charging = pmic_->IsCharging(); + discharging = pmic_->IsDischarging(); + if (discharging != last_discharging) + { + power_save_timer_->SetEnabled(discharging); + last_discharging = discharging; + } + + level = pmic_->GetBatteryLevel(); + return true; + } + + virtual void SetPowerSaveMode(bool enabled) override { + if (!enabled) + { + power_save_timer_->WakeUp(); + } + WifiBoard::SetPowerSaveMode(enabled); + } +}; + +DECLARE_BOARD(WaveshareEsp32s3TouchLCD4b); diff --git a/main/idf_component.yml b/main/idf_component.yml index 2de024f1..9d7d762f 100644 --- a/main/idf_component.yml +++ b/main/idf_component.yml @@ -4,6 +4,7 @@ dependencies: espressif/esp_lcd_ili9341: ==1.2.0 espressif/esp_lcd_gc9a01: ==2.0.1 espressif/esp_lcd_st77916: ^1.0.1 + espressif/esp_lcd_st7701: "^1.1.*" espressif/esp_lcd_axs15231b: ^1.0.0 espressif/esp_lcd_st7796: version: 1.3.4