mirror of
https://github.com/78/xiaozhi-esp32.git
synced 2026-07-02 01:54:47 +08:00
Compare commits
8 Commits
copilot/fi
...
copilot/fi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
10bd3df13b | ||
|
|
89af80b605 | ||
|
|
7c95b6ce8f | ||
|
|
a21d600e82 | ||
|
|
564e929aea | ||
|
|
bbd5f70c3c | ||
|
|
d35f03134f | ||
|
|
d71841d248 |
@@ -255,13 +255,13 @@ elseif(CONFIG_BOARD_TYPE_ESP_HI)
|
||||
set(BOARD_TYPE "esp-hi")
|
||||
# Set ESP_HI emoji directory for DEFAULT_ASSETS_EXTRA_FILES
|
||||
set(DEFAULT_ASSETS_EXTRA_FILES "${CMAKE_BINARY_DIR}/emoji")
|
||||
elseif(CONFIG_BOARD_TYPE_ECHOEAR)
|
||||
set(BOARD_TYPE "echoear")
|
||||
elseif(CONFIG_BOARD_TYPE_ESP_VOCAT)
|
||||
set(BOARD_TYPE "esp-vocat")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_20_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_20_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
set(EMOTE_RESOLUTION "360_360")
|
||||
# set(EMOTE_EXTERNAL_PATH "${CMAKE_CURRENT_SOURCE_DIR}/boards/echoear/assets")
|
||||
# set(EMOTE_EXTERNAL_PATH "${CMAKE_CURRENT_SOURCE_DIR}/boards/esp-vocat/assets")
|
||||
elseif(CONFIG_BOARD_TYPE_ESP_SENSAIRSHUTTLE)
|
||||
set(BOARD_TYPE "esp-sensairshuttle")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_16_4)
|
||||
@@ -371,6 +371,11 @@ elseif(CONFIG_BOARD_TYPE_WAVESHARE_ESP32_S3_ePaper_1_54_v2)
|
||||
set(BOARD_TYPE "esp32-s3-epaper-1.54")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_20_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_20_4)
|
||||
elseif(CONFIG_BOARD_TYPE_WAVESHARE_ESP32_S3_ePaper_3_97)
|
||||
set(MANUFACTURER "waveshare")
|
||||
set(BOARD_TYPE "esp32-s3-epaper-3.97")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_30_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_30_4)
|
||||
elseif(CONFIG_BOARD_TYPE_WAVESHARE_ESP32_S3_RLCD_4_2)
|
||||
set(MANUFACTURER "waveshare")
|
||||
set(BOARD_TYPE "esp32-s3-rlcd-4.2")
|
||||
|
||||
@@ -185,8 +185,8 @@ choice BOARD_TYPE
|
||||
config BOARD_TYPE_ESP_P4_FUNCTION_EV_BOARD
|
||||
bool "Espressif ESP-P4-Function-EV-Board"
|
||||
depends on IDF_TARGET_ESP32P4
|
||||
config BOARD_TYPE_ECHOEAR
|
||||
bool "EchoEar"
|
||||
config BOARD_TYPE_ESP_VOCAT
|
||||
bool "Espressif ESP-VoCat"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_KEVIN_BOX_2
|
||||
bool "Kevin Box 2"
|
||||
@@ -335,6 +335,9 @@ choice BOARD_TYPE
|
||||
config BOARD_TYPE_WAVESHARE_ESP32_S3_ePaper_1_54_v2
|
||||
bool "Waveshare ESP32-S3-ePaper-1.54_v2"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_WAVESHARE_ESP32_S3_ePaper_3_97
|
||||
bool "Waveshare ESP32-S3-ePaper-3.97"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_WAVESHARE_ESP32_S3_RLCD_4_2
|
||||
bool "Waveshare ESP32-S3-RLCD-4.2"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
@@ -653,7 +656,7 @@ choice DISPLAY_STYLE
|
||||
config USE_EMOTE_MESSAGE_STYLE
|
||||
bool "Emote animation style"
|
||||
depends on BOARD_TYPE_ESP_BOX || BOARD_TYPE_ESP_BOX_3 \
|
||||
|| BOARD_TYPE_ECHOEAR || BOARD_TYPE_LICHUANG_DEV_S3 \
|
||||
|| BOARD_TYPE_ESP_VOCAT || BOARD_TYPE_LICHUANG_DEV_S3 \
|
||||
|| BOARD_TYPE_ESP_SENSAIRSHUTTLE
|
||||
endchoice
|
||||
|
||||
@@ -754,7 +757,7 @@ config USE_DEVICE_AEC
|
||||
|| BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_AMOLED_2_06 || BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_LCD_4B || BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_4B || BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_7B \
|
||||
|| BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_3_4C || BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_4C || BOARD_TYPE_ESP_S3_LCD_EV_Board_2 || BOARD_TYPE_YUNLIAO_S3 \
|
||||
|| BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_7 || BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_8 || BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_10_1 \
|
||||
|| BOARD_TYPE_ECHOEAR || BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_LCD_3_49 || BOARD_TYPE_WAVESHARE_ESP32_S3_RLCD_4_2 || BOARD_TYPE_ZHENGCHEN_CAM || BOARD_TYPE_ZHENGCHEN_CAM_ML307 \
|
||||
|| BOARD_TYPE_ESP_VOCAT || BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_LCD_3_49 || BOARD_TYPE_WAVESHARE_ESP32_S3_RLCD_4_2 || BOARD_TYPE_ZHENGCHEN_CAM || BOARD_TYPE_ZHENGCHEN_CAM_ML307 \
|
||||
|| BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_LCD_4_3C)
|
||||
help
|
||||
To work properly, device-side AEC requires a clean output reference path from the speaker signal and physical acoustic isolation between the microphone and speaker.
|
||||
|
||||
@@ -11,6 +11,10 @@ private:
|
||||
|
||||
public:
|
||||
LampController(gpio_num_t gpio_num) : gpio_num_(gpio_num) {
|
||||
if (gpio_num_ == GPIO_NUM_NC) {
|
||||
return;
|
||||
}
|
||||
|
||||
gpio_config_t config = {
|
||||
.pin_bit_mask = (1ULL << gpio_num_),
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# EchoEar 喵伴
|
||||
# ESP-VoCat 喵伴
|
||||
|
||||
## 简介
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<a href="https://oshwhub.com/esp-college/echoear"><b> 立创开源平台 </b></a>
|
||||
</div>
|
||||
|
||||
EchoEar 喵伴是一款智能 AI 开发套件,搭载 ESP32-S3-WROOM-1 模组,1.85 寸 QSPI 圆形触摸屏,双麦阵列,支持离线语音唤醒与声源定位算法。硬件详情等可查看[立创开源项目](https://oshwhub.com/esp-college/echoear)。
|
||||
ESP-VoCat 喵伴是一款智能 AI 开发套件,搭载 ESP32-S3-WROOM-1 模组,1.85 寸 QSPI 圆形触摸屏,双麦阵列,支持离线语音唤醒与声源定位算法。硬件详情等可查看[立创开源项目](https://oshwhub.com/esp-college/echoear)。
|
||||
|
||||
## 配置、编译命令
|
||||
|
||||
@@ -25,11 +25,11 @@ idf.py menuconfig
|
||||
分别配置如下选项:
|
||||
|
||||
### 基本配置
|
||||
- `Xiaozhi Assistant` → `Board Type` → 选择 `EchoEar`
|
||||
- `Xiaozhi Assistant` → `Board Type` → 选择 `Espressif ESP-VoCat`
|
||||
|
||||
### UI风格选择
|
||||
|
||||
EchoEar 支持多种不同的 UI 显示风格,通过 menuconfig 配置选择:
|
||||
ESP-VoCat 支持多种不同的 UI 显示风格,通过 menuconfig 配置选择:
|
||||
|
||||
- `Xiaozhi Assistant` → `Select display style` → 选择显示风格
|
||||
|
||||
@@ -63,7 +63,7 @@ EchoEar 支持多种不同的 UI 显示风格,通过 menuconfig 配置选择
|
||||
- **适用**: 喜欢微信风格的用户
|
||||
- **类**: `SpiLcdDisplay`
|
||||
|
||||
> **说明**: EchoEar 使用16MB Flash,需要使用专门的分区表配置来合理分配存储空间给应用程序、OTA更新、资源文件等。
|
||||
> **说明**: ESP-VoCat 喵伴使用16MB Flash,需要使用专门的分区表配置来合理分配存储空间给应用程序、OTA更新、资源文件等。
|
||||
|
||||
按 `S` 保存,按 `Q` 退出。
|
||||
|
||||
@@ -75,7 +75,7 @@ idf.py build
|
||||
|
||||
**烧录**
|
||||
|
||||
将 EchoEar 连接至电脑,**注意打开电源**,并运行:
|
||||
将 ESP-VoCat 喵伴连接至电脑,**注意打开电源**,并运行:
|
||||
|
||||
```bash
|
||||
idf.py flash
|
||||
@@ -2,7 +2,7 @@
|
||||
"target": "esp32s3",
|
||||
"builds": [
|
||||
{
|
||||
"name": "echoear",
|
||||
"name": "esp-vocat",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_USE_EMOTE_MESSAGE_STYLE=y",
|
||||
"CONFIG_MMAP_FILE_NAME_LENGTH=32",
|
||||
@@ -24,7 +24,7 @@
|
||||
#include <freertos/semphr.h>
|
||||
#include <freertos/task.h>
|
||||
|
||||
#define TAG "EchoEar"
|
||||
#define TAG "ESP-VoCat"
|
||||
|
||||
|
||||
temperature_sensor_handle_t temp_sensor = NULL;
|
||||
@@ -282,7 +282,7 @@ public:
|
||||
// Create touch interrupt semaphore
|
||||
touch_isr_mux_ = xSemaphoreCreateBinary();
|
||||
if (touch_isr_mux_ == NULL) {
|
||||
ESP_LOGE("EchoEar", "Failed to create touch semaphore");
|
||||
ESP_LOGE(TAG, "Failed to create touch semaphore");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -319,15 +319,15 @@ public:
|
||||
// Press event (transition from not touched to touched)
|
||||
press_count_++;
|
||||
event = TOUCH_PRESS;
|
||||
ESP_LOGI("EchoEar", "TOUCH PRESS - count: %d, x: %d, y: %d", press_count_, tp_.x, tp_.y);
|
||||
ESP_LOGI(TAG, "TOUCH PRESS - count: %d, x: %d, y: %d", press_count_, tp_.x, tp_.y);
|
||||
} else if (!is_touched && was_touched_) {
|
||||
// Release event (transition from touched to not touched)
|
||||
event = TOUCH_RELEASE;
|
||||
ESP_LOGI("EchoEar", "TOUCH RELEASE - total presses: %d", press_count_);
|
||||
ESP_LOGI(TAG, "TOUCH RELEASE - total presses: %d", press_count_);
|
||||
} else if (is_touched && was_touched_) {
|
||||
// Continuous touch (hold)
|
||||
event = TOUCH_HOLD;
|
||||
ESP_LOGD("EchoEar", "TOUCH HOLD - x: %d, y: %d", tp_.x, tp_.y);
|
||||
ESP_LOGD(TAG, "TOUCH HOLD - x: %d, y: %d", tp_.x, tp_.y);
|
||||
}
|
||||
|
||||
// Update previous state
|
||||
@@ -380,7 +380,7 @@ private:
|
||||
SemaphoreHandle_t touch_isr_mux_;
|
||||
};
|
||||
|
||||
class EchoEar : public WifiBoard {
|
||||
class EspVocat : public WifiBoard {
|
||||
private:
|
||||
i2c_master_bus_handle_t i2c_bus_;
|
||||
Cst816s* cst816s_;
|
||||
@@ -471,7 +471,7 @@ private:
|
||||
while (true) {
|
||||
if (touchpad->WaitForTouchEvent()) {
|
||||
auto &app = Application::GetInstance();
|
||||
auto &board = (EchoEar &)Board::GetInstance();
|
||||
auto &board = (EspVocat &)Board::GetInstance();
|
||||
|
||||
ESP_LOGD(TAG, "Touch event, TP_PIN_NUM_INT: %d", gpio_get_level(TP_PIN_NUM_INT));
|
||||
touchpad->UpdateTouchPoint();
|
||||
@@ -509,7 +509,7 @@ private:
|
||||
gpio_config(&int_gpio_config);
|
||||
gpio_install_isr_service(0);
|
||||
gpio_intr_enable(TP_PIN_NUM_INT);
|
||||
gpio_isr_handler_add(TP_PIN_NUM_INT, EchoEar::touch_isr_callback, cst816s_);
|
||||
gpio_isr_handler_add(TP_PIN_NUM_INT, EspVocat::touch_isr_callback, cst816s_);
|
||||
}
|
||||
|
||||
void InitializeSpi()
|
||||
@@ -612,7 +612,7 @@ private:
|
||||
#endif // CONFIG_ESP_VIDEO_ENABLE_USB_UVC_VIDEO_DEVICE
|
||||
|
||||
public:
|
||||
~EchoEar() {
|
||||
~EspVocat() {
|
||||
// Stop tasks
|
||||
if (charge_task_handle_ != nullptr) {
|
||||
vTaskDelete(charge_task_handle_);
|
||||
@@ -627,7 +627,7 @@ public:
|
||||
delete display_;
|
||||
// Note: backlight_ (PwmBacklight) and camera_ (EspVideo) are not deleted here
|
||||
// because their base classes (Backlight, Camera) don't have virtual destructors.
|
||||
// Since EchoEar is a singleton that lives for the device lifetime, this is acceptable.
|
||||
// Since EspVocat is a singleton that lives for the device lifetime, this is acceptable.
|
||||
|
||||
// Remove GPIO ISR handler
|
||||
gpio_isr_handler_remove(TP_PIN_NUM_INT);
|
||||
@@ -640,7 +640,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
EchoEar() : boot_button_(BOOT_BUTTON_GPIO)
|
||||
EspVocat() : boot_button_(BOOT_BUTTON_GPIO)
|
||||
{
|
||||
InitializeI2c();
|
||||
uint8_t pcb_version = DetectPcbVersion();
|
||||
@@ -693,4 +693,4 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
DECLARE_BOARD(EchoEar);
|
||||
DECLARE_BOARD(EspVocat);
|
||||
48
main/boards/waveshare/esp32-s3-epaper-3.97/README.md
Normal file
48
main/boards/waveshare/esp32-s3-epaper-3.97/README.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# 产品链接
|
||||
|
||||
[微雪电子 ESP32-S3-ePaper-3.97](https://www.waveshare.net/shop/ESP32-S3-ePaper-3.97.htm)
|
||||
|
||||
# 编译配置命令
|
||||
|
||||
**克隆工程**
|
||||
|
||||
```bash
|
||||
git clone https://github.com/78/xiaozhi-esp32.git
|
||||
```
|
||||
|
||||
**进入工程**
|
||||
|
||||
```bash
|
||||
cd xiaozhi-esp32
|
||||
```
|
||||
|
||||
**配置编译目标为 ESP32S3**
|
||||
|
||||
```bash
|
||||
idf.py set-target esp32s3
|
||||
```
|
||||
|
||||
**打开 menuconfig**
|
||||
|
||||
```bash
|
||||
idf.py menuconfig
|
||||
```
|
||||
|
||||
**选择板子**
|
||||
|
||||
```bash
|
||||
Xiaozhi Assistant -> Board Type -> Waveshare ESP32-S3-ePaper-3.97
|
||||
```
|
||||
|
||||
**编译**
|
||||
|
||||
```ba
|
||||
idf.py build
|
||||
```
|
||||
|
||||
**下载并打开串口终端**
|
||||
|
||||
```bash
|
||||
idf.py build flash monitor
|
||||
```
|
||||
|
||||
44
main/boards/waveshare/esp32-s3-epaper-3.97/config.h
Normal file
44
main/boards/waveshare/esp32-s3-epaper-3.97/config.h
Normal file
@@ -0,0 +1,44 @@
|
||||
#ifndef _BOARD_CONFIG_H_
|
||||
#define _BOARD_CONFIG_H_
|
||||
|
||||
#include <driver/gpio.h>
|
||||
|
||||
#define AUDIO_INPUT_SAMPLE_RATE 24000
|
||||
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
|
||||
|
||||
#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_13
|
||||
#define AUDIO_I2S_GPIO_WS GPIO_NUM_47
|
||||
#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_14
|
||||
#define AUDIO_I2S_GPIO_DIN GPIO_NUM_21
|
||||
#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_48
|
||||
|
||||
#define AUDIO_CODEC_PA_PIN GPIO_NUM_39
|
||||
#define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_41
|
||||
#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_42
|
||||
#define AUDIO_CODEC_ES8311_ADDR ES8311_CODEC_DEFAULT_ADDR
|
||||
|
||||
#define BOOT_BUTTON_GPIO GPIO_NUM_0
|
||||
#define VBAT_PWR_GPIO GPIO_NUM_1
|
||||
|
||||
#define EPD_SPI_NUM SPI3_HOST
|
||||
|
||||
#define EPD_DC_PIN GPIO_NUM_9
|
||||
#define EPD_CS_PIN GPIO_NUM_10
|
||||
#define EPD_SCK_PIN GPIO_NUM_11
|
||||
#define EPD_MOSI_PIN GPIO_NUM_12
|
||||
#define EPD_RST_PIN GPIO_NUM_46
|
||||
#define EPD_BUSY_PIN GPIO_NUM_3
|
||||
|
||||
#define EXAMPLE_LCD_WIDTH 800
|
||||
#define EXAMPLE_LCD_HEIGHT 480
|
||||
|
||||
#define DISPLAY_MIRROR_X false
|
||||
#define DISPLAY_MIRROR_Y false
|
||||
#define DISPLAY_SWAP_XY false
|
||||
|
||||
#define DISPLAY_OFFSET_X 0
|
||||
#define DISPLAY_OFFSET_Y 0
|
||||
|
||||
|
||||
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
12
main/boards/waveshare/esp32-s3-epaper-3.97/config.json
Normal file
12
main/boards/waveshare/esp32-s3-epaper-3.97/config.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"manufacturer": "waveshare",
|
||||
"target": "esp32s3",
|
||||
"builds": [
|
||||
{
|
||||
"name": "esp32-s3-epaper-3.97",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_USE_WECHAT_MESSAGE_STYLE=n"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
393
main/boards/waveshare/esp32-s3-epaper-3.97/custom_lcd_display.cc
Normal file
393
main/boards/waveshare/esp32-s3-epaper-3.97/custom_lcd_display.cc
Normal file
@@ -0,0 +1,393 @@
|
||||
#include "custom_lcd_display.h"
|
||||
#include <esp_lcd_panel_io.h>
|
||||
#include <esp_log.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <stdio.h>
|
||||
#include <vector>
|
||||
#include "board.h"
|
||||
#include "config.h"
|
||||
#include "esp_lvgl_port.h"
|
||||
#include "settings.h"
|
||||
|
||||
#define TAG "CustomEpdDisplay"
|
||||
|
||||
#define BYTES_PER_PIXEL (LV_COLOR_FORMAT_GET_SIZE(LV_COLOR_FORMAT_RGB565))
|
||||
#define BUFF_SIZE (EXAMPLE_LCD_WIDTH * EXAMPLE_LCD_HEIGHT * BYTES_PER_PIXEL)
|
||||
|
||||
void CustomEpdDisplay::lvgl_flush_cb(lv_display_t* disp, const lv_area_t* area, uint8_t* color_p) {
|
||||
assert(disp != NULL);
|
||||
CustomEpdDisplay* driver = (CustomEpdDisplay*)lv_display_get_user_data(disp);
|
||||
uint16_t* buffer = (uint16_t*)color_p;
|
||||
driver->EPD_Clear();
|
||||
for (int y = area->y1; y <= area->y2; y++) {
|
||||
for (int x = area->x1; x <= area->x2; x++) {
|
||||
uint8_t color = (*buffer < 0x7fff) ? DRIVER_COLOR_BLACK : DRIVER_COLOR_WHITE;
|
||||
driver->EPD_DrawColorPixel(x, y, color);
|
||||
buffer++;
|
||||
}
|
||||
}
|
||||
driver->EPD_DisplayPart();
|
||||
lv_disp_flush_ready(disp);
|
||||
}
|
||||
|
||||
CustomEpdDisplay::CustomEpdDisplay(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_handle_t panel,
|
||||
int width, int height, int offset_x, int offset_y, bool mirror_x,
|
||||
bool mirror_y, bool swap_xy, custom_epd_spi_t _epd_spi_data)
|
||||
: LcdDisplay(panel_io, panel, width, height),
|
||||
epd_spi_data(_epd_spi_data),
|
||||
Width(width),
|
||||
Height(height) {
|
||||
ESP_LOGI(TAG, "Initialize SPI");
|
||||
spi_port_init();
|
||||
spi_gpio_init();
|
||||
|
||||
ESP_LOGI(TAG, "Initialize LVGL library");
|
||||
lv_init();
|
||||
|
||||
lvgl_port_cfg_t port_cfg = ESP_LVGL_PORT_INIT_CONFIG();
|
||||
port_cfg.task_priority = 2;
|
||||
port_cfg.timer_period_ms = 50;
|
||||
lvgl_port_init(&port_cfg);
|
||||
lvgl_port_lock(0);
|
||||
|
||||
buffer = (uint8_t*)heap_caps_malloc(epd_spi_data.buffer_len, MALLOC_CAP_SPIRAM);
|
||||
assert(buffer);
|
||||
display_ = lv_display_create(width, height); /* 以水平和垂直分辨率(像素)进行基本初始化 */
|
||||
lv_display_set_flush_cb(display_, lvgl_flush_cb);
|
||||
lv_display_set_user_data(display_, this);
|
||||
|
||||
uint8_t* buffer_1 = NULL;
|
||||
buffer_1 = (uint8_t*)heap_caps_malloc(BUFF_SIZE, MALLOC_CAP_SPIRAM);
|
||||
assert(buffer_1);
|
||||
lv_display_set_buffers(display_, buffer_1, NULL, BUFF_SIZE, LV_DISPLAY_RENDER_MODE_FULL);
|
||||
|
||||
ESP_LOGI(TAG, "EPD init");
|
||||
EPD_Init();
|
||||
ESP_LOGI(TAG, "EPD Clear");
|
||||
EPD_Clear();
|
||||
EPD_Display();
|
||||
|
||||
lvgl_port_unlock();
|
||||
if (display_ == nullptr) {
|
||||
ESP_LOGE(TAG, "Failed to add display");
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "ui start");
|
||||
|
||||
SetupUI();
|
||||
}
|
||||
|
||||
CustomEpdDisplay::~CustomEpdDisplay() {}
|
||||
|
||||
void CustomEpdDisplay::spi_gpio_init() {
|
||||
int rst = epd_spi_data.rst;
|
||||
int cs = epd_spi_data.cs;
|
||||
int dc = epd_spi_data.dc;
|
||||
int busy = epd_spi_data.busy;
|
||||
|
||||
gpio_config_t gpio_conf = {};
|
||||
gpio_conf.intr_type = GPIO_INTR_DISABLE;
|
||||
gpio_conf.mode = GPIO_MODE_OUTPUT;
|
||||
gpio_conf.pin_bit_mask = (0x1ULL << rst) | (0x1ULL << dc) | (0x1ULL << cs);
|
||||
gpio_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
gpio_conf.pull_up_en = GPIO_PULLUP_ENABLE;
|
||||
ESP_ERROR_CHECK_WITHOUT_ABORT(gpio_config(&gpio_conf));
|
||||
|
||||
gpio_conf.mode = GPIO_MODE_INPUT;
|
||||
gpio_conf.pin_bit_mask = (0x1ULL << busy);
|
||||
ESP_ERROR_CHECK_WITHOUT_ABORT(gpio_config(&gpio_conf));
|
||||
|
||||
set_rst_1();
|
||||
}
|
||||
|
||||
void CustomEpdDisplay::spi_port_init() {
|
||||
int mosi = epd_spi_data.mosi;
|
||||
int scl = epd_spi_data.scl;
|
||||
int spi_host = epd_spi_data.spi_host;
|
||||
esp_err_t ret;
|
||||
spi_bus_config_t buscfg = {};
|
||||
buscfg.miso_io_num = -1;
|
||||
buscfg.mosi_io_num = mosi;
|
||||
buscfg.sclk_io_num = scl;
|
||||
buscfg.quadwp_io_num = -1;
|
||||
buscfg.quadhd_io_num = -1;
|
||||
buscfg.max_transfer_sz = 4096;
|
||||
|
||||
spi_device_interface_config_t devcfg = {};
|
||||
devcfg.spics_io_num = -1;
|
||||
devcfg.clock_speed_hz = 20 * 1000 * 1000; // Clock out at 10 MHz
|
||||
devcfg.mode = 0; // SPI mode 0
|
||||
devcfg.queue_size = 7; // We want to be able to queue 7 transactions at a time
|
||||
|
||||
ret = spi_bus_initialize((spi_host_device_t)spi_host, &buscfg, SPI_DMA_CH_AUTO);
|
||||
ESP_ERROR_CHECK(ret);
|
||||
ret = spi_bus_add_device((spi_host_device_t)spi_host, &devcfg, &spi);
|
||||
ESP_ERROR_CHECK(ret);
|
||||
}
|
||||
|
||||
void CustomEpdDisplay::read_busy() {
|
||||
int busy = epd_spi_data.busy;
|
||||
while (gpio_get_level((gpio_num_t)busy) == 1) {
|
||||
vTaskDelay(pdMS_TO_TICKS(5)); // LOW: idle, HIGH: busy
|
||||
}
|
||||
}
|
||||
|
||||
void CustomEpdDisplay::SPI_SendByte(uint8_t data) {
|
||||
esp_err_t ret;
|
||||
spi_transaction_t t;
|
||||
memset(&t, 0, sizeof(t));
|
||||
t.length = 8;
|
||||
t.tx_buffer = &data;
|
||||
ret = spi_device_polling_transmit(spi, &t); // Transmit!
|
||||
assert(ret == ESP_OK); // Should have had no issues.
|
||||
}
|
||||
|
||||
void CustomEpdDisplay::EPD_SendData(uint8_t data) {
|
||||
set_dc_1();
|
||||
set_cs_0();
|
||||
SPI_SendByte(data);
|
||||
set_cs_1();
|
||||
}
|
||||
|
||||
void CustomEpdDisplay::EPD_SendCommand(uint8_t command) {
|
||||
set_dc_0();
|
||||
set_cs_0();
|
||||
SPI_SendByte(command);
|
||||
set_cs_1();
|
||||
}
|
||||
|
||||
void CustomEpdDisplay::writeBytes(uint8_t* buffer, int len) {
|
||||
set_dc_1();
|
||||
set_cs_0();
|
||||
|
||||
const int MAX_SPI_TRANSFER = 4096;
|
||||
|
||||
int remaining = len;
|
||||
int offset = 0;
|
||||
|
||||
while (remaining > 0) {
|
||||
int chunk_size = (remaining > MAX_SPI_TRANSFER) ? MAX_SPI_TRANSFER : remaining;
|
||||
|
||||
esp_err_t ret;
|
||||
spi_transaction_t t;
|
||||
memset(&t, 0, sizeof(t));
|
||||
t.length = 8 * chunk_size;
|
||||
t.tx_buffer = buffer + offset;
|
||||
ret = spi_device_polling_transmit(spi, &t); // Transmit!
|
||||
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "SPI transmit failed at offset %d, chunk %d: %s", offset, chunk_size,
|
||||
esp_err_to_name(ret));
|
||||
break;
|
||||
}
|
||||
|
||||
remaining -= chunk_size;
|
||||
offset += chunk_size;
|
||||
}
|
||||
|
||||
set_cs_1();
|
||||
}
|
||||
|
||||
void CustomEpdDisplay::writeBytes(const uint8_t* buffer, int len) {
|
||||
set_dc_1();
|
||||
set_cs_0();
|
||||
|
||||
const int MAX_SPI_TRANSFER = 4096;
|
||||
|
||||
int remaining = len;
|
||||
int offset = 0;
|
||||
|
||||
while (remaining > 0) {
|
||||
int chunk_size = (remaining > MAX_SPI_TRANSFER) ? MAX_SPI_TRANSFER : remaining;
|
||||
|
||||
esp_err_t ret;
|
||||
spi_transaction_t t;
|
||||
memset(&t, 0, sizeof(t));
|
||||
t.length = 8 * chunk_size;
|
||||
t.tx_buffer = buffer + offset;
|
||||
ret = spi_device_polling_transmit(spi, &t); // Transmit!
|
||||
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "SPI transmit failed at offset %d, chunk %d: %s", offset, chunk_size,
|
||||
esp_err_to_name(ret));
|
||||
break;
|
||||
}
|
||||
|
||||
remaining -= chunk_size;
|
||||
offset += chunk_size;
|
||||
}
|
||||
|
||||
set_cs_1();
|
||||
}
|
||||
|
||||
void CustomEpdDisplay::EPD_SetWindows(uint16_t Xstart, uint16_t Ystart, uint16_t Xend,
|
||||
uint16_t Yend) {
|
||||
EPD_SendCommand(0x44); // SET_RAM_X_ADDRESS_START_END_POSITION
|
||||
EPD_SendData((Xstart * 8) & 0xFF);
|
||||
EPD_SendData(((Xstart * 8) >> 8) & 0xFF);
|
||||
EPD_SendData((Xend * 8) & 0xFF);
|
||||
EPD_SendData(((Xend * 8) >> 8) & 0xFF);
|
||||
|
||||
EPD_SendCommand(0x45); // SET_RAM_Y_ADDRESS_START_END_POSITION
|
||||
EPD_SendData(Yend & 0xFF);
|
||||
EPD_SendData((Yend >> 8) & 0xFF);
|
||||
EPD_SendData(Ystart & 0xFF);
|
||||
EPD_SendData((Ystart >> 8) & 0xFF);
|
||||
}
|
||||
|
||||
void CustomEpdDisplay::EPD_SetCursor(uint16_t Xstart, uint16_t Ystart) {
|
||||
EPD_SendCommand(0x4E);
|
||||
EPD_SendData((Xstart * 8) & 0xFF);
|
||||
EPD_SendData(((Xstart * 8) >> 8) & 0xFF);
|
||||
|
||||
EPD_SendCommand(0x4F);
|
||||
EPD_SendData(Ystart & 0xFF);
|
||||
EPD_SendData((Ystart >> 8) & 0xFF);
|
||||
}
|
||||
|
||||
void CustomEpdDisplay::EPD_TurnOnDisplay() {
|
||||
EPD_SendCommand(0x22);
|
||||
EPD_SendData(0xF7);
|
||||
EPD_SendCommand(0x20);
|
||||
read_busy();
|
||||
}
|
||||
|
||||
void CustomEpdDisplay::EPD_TurnOnDisplayPart() {
|
||||
EPD_SendCommand(0x22);
|
||||
EPD_SendData(0xFF);
|
||||
EPD_SendCommand(0x20);
|
||||
read_busy();
|
||||
}
|
||||
|
||||
void CustomEpdDisplay::EPD_Init() {
|
||||
set_rst_1();
|
||||
vTaskDelay(pdMS_TO_TICKS(50));
|
||||
set_rst_0();
|
||||
vTaskDelay(pdMS_TO_TICKS(2));
|
||||
set_rst_1();
|
||||
vTaskDelay(pdMS_TO_TICKS(50));
|
||||
|
||||
read_busy();
|
||||
EPD_SendCommand(0x12); // SWRESET
|
||||
read_busy();
|
||||
|
||||
EPD_SendCommand(0x18);
|
||||
EPD_SendData(0x80);
|
||||
|
||||
EPD_SendCommand(0x0C); // Driver output control
|
||||
EPD_SendData(0xAE);
|
||||
EPD_SendData(0xC7);
|
||||
EPD_SendData(0xC3);
|
||||
EPD_SendData(0xC0);
|
||||
EPD_SendData(0x80);
|
||||
|
||||
EPD_SendCommand(0x01); // Driver output control
|
||||
EPD_SendData((Height - 1) % 256);
|
||||
EPD_SendData((Height - 1) / 256);
|
||||
EPD_SendData(0x02);
|
||||
|
||||
EPD_SendCommand(0x3C); // BorderWavefrom
|
||||
EPD_SendData(0x01);
|
||||
|
||||
EPD_SendCommand(0x11); // data entry mode
|
||||
EPD_SendData(0x01);
|
||||
|
||||
EPD_SendCommand(0x44); // set Ram-X address start/end position
|
||||
EPD_SendData(0x00);
|
||||
EPD_SendData(0x00);
|
||||
EPD_SendData((Width - 1) % 256);
|
||||
EPD_SendData((Width - 1) / 256);
|
||||
|
||||
EPD_SendCommand(0x45); // set Ram-Y address start/end position
|
||||
EPD_SendData((Height - 1) % 256);
|
||||
EPD_SendData((Height - 1) / 256);
|
||||
EPD_SendData(0x00);
|
||||
EPD_SendData(0x00);
|
||||
|
||||
EPD_SendCommand(0x4E); // set RAM x address count to 0;
|
||||
EPD_SendData(0x00);
|
||||
EPD_SendData(0x00);
|
||||
EPD_SendCommand(0x4F); // set RAM y address count to 0X199;
|
||||
EPD_SendData(0x00);
|
||||
EPD_SendData(0x00);
|
||||
|
||||
read_busy();
|
||||
}
|
||||
|
||||
void CustomEpdDisplay::EPD_Clear() {
|
||||
int buffer_len = epd_spi_data.buffer_len;
|
||||
memset(buffer, 0xff, buffer_len);
|
||||
}
|
||||
|
||||
void CustomEpdDisplay::EPD_Display() {
|
||||
int buffer_len = epd_spi_data.buffer_len;
|
||||
EPD_SendCommand(0x24);
|
||||
assert(buffer);
|
||||
writeBytes(buffer, buffer_len);
|
||||
EPD_TurnOnDisplay();
|
||||
}
|
||||
|
||||
void CustomEpdDisplay::EPD_DisplayPartBaseImage() {
|
||||
int buffer_len = epd_spi_data.buffer_len;
|
||||
EPD_SendCommand(0x24);
|
||||
assert(buffer);
|
||||
writeBytes(buffer, buffer_len);
|
||||
EPD_SendCommand(0x26);
|
||||
writeBytes(buffer, buffer_len);
|
||||
EPD_TurnOnDisplay();
|
||||
}
|
||||
|
||||
void CustomEpdDisplay::EPD_Init_Partial() {
|
||||
set_rst_1();
|
||||
vTaskDelay(pdMS_TO_TICKS(50));
|
||||
set_rst_0();
|
||||
vTaskDelay(pdMS_TO_TICKS(2));
|
||||
set_rst_1();
|
||||
vTaskDelay(pdMS_TO_TICKS(50));
|
||||
|
||||
read_busy();
|
||||
|
||||
EPD_SendCommand(0x18);
|
||||
EPD_SendData(0x80);
|
||||
|
||||
EPD_SendCommand(0x3C);
|
||||
EPD_SendData(0x80);
|
||||
|
||||
EPD_SetWindows(0, Width - 1, Height - 1, 0);
|
||||
|
||||
EPD_SetCursor(0, Height - 1);
|
||||
|
||||
read_busy();
|
||||
}
|
||||
|
||||
void CustomEpdDisplay::EPD_DisplayPart() {
|
||||
EPD_SendCommand(0x24);
|
||||
assert(buffer);
|
||||
writeBytes(buffer, 48000);
|
||||
EPD_TurnOnDisplayPart();
|
||||
}
|
||||
|
||||
void CustomEpdDisplay::EPD_Sleep() {
|
||||
EPD_SendCommand(0x10); // enter deep sleep
|
||||
EPD_SendData(0x01);
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
set_rst_0();
|
||||
set_cs_0();
|
||||
set_dc_0();
|
||||
}
|
||||
|
||||
void CustomEpdDisplay::EPD_DrawColorPixel(uint16_t x, uint16_t y, uint8_t color) {
|
||||
if (x >= Width || y >= Height) {
|
||||
ESP_LOGE("EPD", "Out of bounds pixel: (%d,%d)", x, y);
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t index = y * Width / 8 + (x >> 3);
|
||||
uint8_t bit = 7 - (x & 0x07);
|
||||
if (color == DRIVER_COLOR_WHITE) {
|
||||
buffer[index] |= (0x01 << bit);
|
||||
} else {
|
||||
buffer[index] &= ~(0x01 << bit);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
#ifndef __CUSTOM_LCD_DISPLAY_H__
|
||||
#define __CUSTOM_LCD_DISPLAY_H__
|
||||
|
||||
#include <driver/gpio.h>
|
||||
#include "lcd_display.h"
|
||||
|
||||
/* Display color */
|
||||
typedef enum {
|
||||
DRIVER_COLOR_WHITE = 0xff,
|
||||
DRIVER_COLOR_BLACK = 0x00,
|
||||
FONT_BACKGROUND = DRIVER_COLOR_WHITE,
|
||||
} COLOR_IMAGE;
|
||||
|
||||
typedef struct {
|
||||
uint8_t cs;
|
||||
uint8_t dc;
|
||||
uint8_t rst;
|
||||
uint8_t busy;
|
||||
uint8_t mosi;
|
||||
uint8_t scl;
|
||||
int spi_host;
|
||||
int buffer_len;
|
||||
} custom_epd_spi_t;
|
||||
|
||||
class CustomEpdDisplay : public LcdDisplay {
|
||||
public:
|
||||
CustomEpdDisplay(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_handle_t panel, int width,
|
||||
int height, int offset_x, int offset_y, bool mirror_x, bool mirror_y,
|
||||
bool swap_xy, custom_epd_spi_t _epd_spi_data);
|
||||
~CustomEpdDisplay();
|
||||
|
||||
void EPD_Init(); /* 墨水屏初始化 */
|
||||
void EPD_Clear(); /* 清空屏幕 */
|
||||
void EPD_Display(); /* 刷buffer到墨水屏 */
|
||||
void EPD_Sleep();
|
||||
|
||||
/*快速刷新*/
|
||||
void EPD_DisplayPartBaseImage();
|
||||
void EPD_Init_Partial();
|
||||
void EPD_DisplayPart();
|
||||
void EPD_DrawColorPixel(uint16_t x, uint16_t y, uint8_t color);
|
||||
|
||||
private:
|
||||
const custom_epd_spi_t epd_spi_data;
|
||||
const int Width;
|
||||
const int Height;
|
||||
spi_device_handle_t spi;
|
||||
uint8_t* buffer = NULL;
|
||||
|
||||
static void lvgl_flush_cb(lv_display_t* disp, const lv_area_t* area, uint8_t* color_p);
|
||||
|
||||
void spi_gpio_init();
|
||||
void spi_port_init();
|
||||
void read_busy();
|
||||
|
||||
void set_cs_1() { gpio_set_level((gpio_num_t)epd_spi_data.cs, 1); }
|
||||
void set_cs_0() { gpio_set_level((gpio_num_t)epd_spi_data.cs, 0); }
|
||||
void set_dc_1() { gpio_set_level((gpio_num_t)epd_spi_data.dc, 1); }
|
||||
void set_dc_0() { gpio_set_level((gpio_num_t)epd_spi_data.dc, 0); }
|
||||
void set_rst_1() { gpio_set_level((gpio_num_t)epd_spi_data.rst, 1); }
|
||||
void set_rst_0() { gpio_set_level((gpio_num_t)epd_spi_data.rst, 0); }
|
||||
|
||||
void SPI_SendByte(uint8_t data);
|
||||
void EPD_SendData(uint8_t data);
|
||||
void EPD_SendCommand(uint8_t command);
|
||||
void writeBytes(uint8_t* buffer, int len);
|
||||
void writeBytes(const uint8_t* buffer, int len);
|
||||
void EPD_SetWindows(uint16_t Xstart, uint16_t Ystart, uint16_t Xend, uint16_t Yend);
|
||||
void EPD_SetCursor(uint16_t Xstart, uint16_t Ystart);
|
||||
void EPD_TurnOnDisplay();
|
||||
void EPD_TurnOnDisplayPart();
|
||||
};
|
||||
|
||||
#endif // __CUSTOM_LCD_DISPLAY_H__
|
||||
@@ -0,0 +1,178 @@
|
||||
#include <driver/i2c_master.h>
|
||||
#include <driver/spi_common.h>
|
||||
#include <esp_lcd_panel_vendor.h>
|
||||
#include <esp_log.h>
|
||||
#include <stdio.h>
|
||||
#include "application.h"
|
||||
#include "button.h"
|
||||
#include "codecs/es8311_audio_codec.h"
|
||||
#include "config.h"
|
||||
#include "custom_lcd_display.h"
|
||||
#include "lvgl.h"
|
||||
#include "mcp_server.h"
|
||||
#include "wifi_board.h"
|
||||
|
||||
#include "axp2101.h"
|
||||
#include "codecs/box_audio_codec.h"
|
||||
#include "i2c_device.h"
|
||||
#include "power_save_timer.h"
|
||||
|
||||
#define TAG "waveshare_epaper_3_97"
|
||||
|
||||
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);
|
||||
// Set ALDO2 to 3.3V
|
||||
WriteReg(0x93, (3300 - 500) / 100);
|
||||
// Set ALDO3 to 3.3V
|
||||
WriteReg(0x94, (3300 - 500) / 100);
|
||||
|
||||
// Enable ALDO1、ALDO2、ALDO2
|
||||
WriteReg(0x90, 0x07);
|
||||
|
||||
WriteReg(0x64, 0x03); // CV charger voltage setting to 4.2V
|
||||
|
||||
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
|
||||
}
|
||||
};
|
||||
|
||||
class WaveshareEsp32s3ePaper3inch97 : public WifiBoard {
|
||||
private:
|
||||
i2c_master_bus_handle_t i2c_bus_;
|
||||
Pmic* pmic_ = nullptr;
|
||||
Button boot_button_;
|
||||
Button pwr_button_;
|
||||
CustomEpdDisplay* display_;
|
||||
PowerSaveTimer* power_save_timer_;
|
||||
|
||||
void InitializePowerSaveTimer() {
|
||||
power_save_timer_ = new PowerSaveTimer(-1, 100, 300);
|
||||
power_save_timer_->OnShutdownRequest([this]() {
|
||||
GetDisplay()->SetChatMessage("system", "OFF");
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
pmic_->PowerOff();
|
||||
});
|
||||
power_save_timer_->SetEnabled(true);
|
||||
}
|
||||
|
||||
void InitializeI2c() {
|
||||
i2c_master_bus_config_t i2c_bus_cfg = {};
|
||||
i2c_bus_cfg.i2c_port = (i2c_port_t)0;
|
||||
i2c_bus_cfg.sda_io_num = AUDIO_CODEC_I2C_SDA_PIN;
|
||||
i2c_bus_cfg.scl_io_num = AUDIO_CODEC_I2C_SCL_PIN;
|
||||
i2c_bus_cfg.clk_source = I2C_CLK_SRC_DEFAULT;
|
||||
i2c_bus_cfg.glitch_ignore_cnt = 7;
|
||||
i2c_bus_cfg.intr_priority = 0;
|
||||
i2c_bus_cfg.trans_queue_depth = 0;
|
||||
i2c_bus_cfg.flags.enable_internal_pullup = 1;
|
||||
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &i2c_bus_));
|
||||
}
|
||||
|
||||
void InitializeButtons() {
|
||||
boot_button_.OnClick([this]() {
|
||||
auto& app = Application::GetInstance();
|
||||
// During startup (before connected), pressing BOOT button enters Wi-Fi config mode
|
||||
// without reboot
|
||||
if (app.GetDeviceState() == kDeviceStateStarting) {
|
||||
EnterWifiConfigMode();
|
||||
return;
|
||||
}
|
||||
app.ToggleChatState();
|
||||
});
|
||||
|
||||
pwr_button_.OnClick([this]() {
|
||||
GetDisplay()->SetChatMessage("system", "OFF");
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
pmic_->PowerOff();
|
||||
});
|
||||
}
|
||||
|
||||
void InitializeAxp2101() {
|
||||
ESP_LOGI(TAG, "Init AXP2101");
|
||||
pmic_ = new Pmic(i2c_bus_, 0x34);
|
||||
}
|
||||
|
||||
void InitializeTools() {
|
||||
auto& mcp_server = McpServer::GetInstance();
|
||||
mcp_server.AddTool("self.disp.network", "重新配网", PropertyList(),
|
||||
[this](const PropertyList&) -> ReturnValue {
|
||||
EnterWifiConfigMode();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void InitializeEpdDisplay() {
|
||||
custom_epd_spi_t epd_spi_data = {};
|
||||
epd_spi_data.cs = EPD_CS_PIN;
|
||||
epd_spi_data.dc = EPD_DC_PIN;
|
||||
epd_spi_data.rst = EPD_RST_PIN;
|
||||
epd_spi_data.busy = EPD_BUSY_PIN;
|
||||
epd_spi_data.mosi = EPD_MOSI_PIN;
|
||||
epd_spi_data.scl = EPD_SCK_PIN;
|
||||
epd_spi_data.spi_host = EPD_SPI_NUM;
|
||||
epd_spi_data.buffer_len = 48000;
|
||||
display_ = new CustomEpdDisplay(NULL, NULL, EXAMPLE_LCD_WIDTH, EXAMPLE_LCD_HEIGHT,
|
||||
DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X,
|
||||
DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY, epd_spi_data);
|
||||
}
|
||||
|
||||
public:
|
||||
WaveshareEsp32s3ePaper3inch97()
|
||||
: boot_button_(BOOT_BUTTON_GPIO), pwr_button_(VBAT_PWR_GPIO, 1) {
|
||||
InitializePowerSaveTimer();
|
||||
InitializeI2c();
|
||||
InitializeAxp2101();
|
||||
InitializeButtons();
|
||||
InitializeTools();
|
||||
InitializeEpdDisplay();
|
||||
}
|
||||
|
||||
virtual AudioCodec* GetAudioCodec() override {
|
||||
static Es8311AudioCodec audio_codec(
|
||||
i2c_bus_, I2C_NUM_0, 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);
|
||||
return &audio_codec;
|
||||
}
|
||||
|
||||
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 Display* GetDisplay() override { return display_; }
|
||||
|
||||
virtual void SetPowerSaveLevel(PowerSaveLevel level) override {
|
||||
if (level != PowerSaveLevel::LOW_POWER) {
|
||||
power_save_timer_->WakeUp();
|
||||
}
|
||||
WifiBoard::SetPowerSaveLevel(level);
|
||||
}
|
||||
};
|
||||
|
||||
DECLARE_BOARD(WaveshareEsp32s3ePaper3inch97);
|
||||
@@ -1079,6 +1079,11 @@ void LcdDisplay::SetEmotion(const char* emotion) {
|
||||
if (gif_controller_) {
|
||||
DisplayLockGuard lock(this);
|
||||
gif_controller_->Stop();
|
||||
// Hide image before destroying GIF controller to prevent LVGL from
|
||||
// accessing freed image data during rendering between lock scopes
|
||||
if (emoji_image_) {
|
||||
lv_obj_add_flag(emoji_image_, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
gif_controller_.reset();
|
||||
}
|
||||
|
||||
|
||||
@@ -12,8 +12,10 @@
|
||||
|
||||
|
||||
SingleLed::SingleLed(gpio_num_t gpio) {
|
||||
// If the gpio is not connected, you should use NoLed class
|
||||
assert(gpio != GPIO_NUM_NC);
|
||||
if (gpio == GPIO_NUM_NC) {
|
||||
ESP_LOGW(TAG, "SingleLed initialized with GPIO_NUM_NC, LED will not function");
|
||||
return;
|
||||
}
|
||||
|
||||
led_strip_config_t strip_config = {};
|
||||
strip_config.strip_gpio_num = gpio;
|
||||
@@ -41,7 +43,9 @@ SingleLed::SingleLed(gpio_num_t gpio) {
|
||||
}
|
||||
|
||||
SingleLed::~SingleLed() {
|
||||
esp_timer_stop(blink_timer_);
|
||||
if (blink_timer_ != nullptr) {
|
||||
esp_timer_stop(blink_timer_);
|
||||
}
|
||||
if (led_strip_ != nullptr) {
|
||||
led_strip_del(led_strip_);
|
||||
}
|
||||
|
||||
@@ -424,7 +424,7 @@ def pack_assets_simple(target_path, include_path, out_file, assets_path, max_nam
|
||||
current_year = datetime.now().year
|
||||
asset_name = os.path.basename(assets_path)
|
||||
header_file_path = os.path.join(include_path, f'mmap_generate_{asset_name}.h')
|
||||
with open(header_file_path, 'w') as output_header:
|
||||
with open(header_file_path, 'w', encoding='utf-8') as output_header:
|
||||
output_header.write('/*\n')
|
||||
output_header.write(' * SPDX-FileCopyrightText: 2022-{} Espressif Systems (Shanghai) CO LTD\n'.format(current_year))
|
||||
output_header.write(' *\n')
|
||||
@@ -463,7 +463,7 @@ def read_wakenet_from_sdkconfig(sdkconfig_path):
|
||||
return []
|
||||
|
||||
models = []
|
||||
with io.open(sdkconfig_path, "r") as f:
|
||||
with io.open(sdkconfig_path, "r", encoding="utf-8") as f:
|
||||
for label in f:
|
||||
label = label.strip("\n")
|
||||
if 'CONFIG_SR_WN' in label and '#' not in label[0]:
|
||||
@@ -488,7 +488,7 @@ def read_multinet_from_sdkconfig(sdkconfig_path):
|
||||
print(f"Warning: sdkconfig file not found: {sdkconfig_path}")
|
||||
return []
|
||||
|
||||
with io.open(sdkconfig_path, "r") as f:
|
||||
with io.open(sdkconfig_path, "r", encoding="utf-8") as f:
|
||||
models_string = ''
|
||||
for label in f:
|
||||
label = label.strip("\n")
|
||||
@@ -549,7 +549,7 @@ def read_wake_word_type_from_sdkconfig(sdkconfig_path):
|
||||
'wake_word_disabled': False
|
||||
}
|
||||
|
||||
with io.open(sdkconfig_path, "r") as f:
|
||||
with io.open(sdkconfig_path, "r", encoding="utf-8") as f:
|
||||
for line in f:
|
||||
line = line.strip("\n")
|
||||
if line.startswith('#'):
|
||||
@@ -578,7 +578,7 @@ def read_custom_wake_word_from_sdkconfig(sdkconfig_path):
|
||||
return None
|
||||
|
||||
config_values = {}
|
||||
with io.open(sdkconfig_path, "r") as f:
|
||||
with io.open(sdkconfig_path, "r", encoding="utf-8") as f:
|
||||
for line in f:
|
||||
line = line.strip("\n")
|
||||
if line.startswith('#') or '=' not in line:
|
||||
@@ -777,7 +777,7 @@ def build_assets_integrated(wakenet_model_paths, multinet_model_paths, text_font
|
||||
config_path = generate_config_json(temp_build_dir, assets_dir)
|
||||
|
||||
# Load config and pack assets
|
||||
with open(config_path, 'r') as f:
|
||||
with open(config_path, 'r', encoding='utf-8') as f:
|
||||
config_data = json.load(f)
|
||||
|
||||
# Use simplified packing function
|
||||
|
||||
@@ -18,7 +18,7 @@ def get_board_type_from_compile_commands() -> Optional[str]:
|
||||
compile_file = Path("build/compile_commands.json")
|
||||
if not compile_file.exists():
|
||||
return None
|
||||
with compile_file.open() as f:
|
||||
with compile_file.open(encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
for item in data:
|
||||
if not item["file"].endswith("main.cc"):
|
||||
@@ -31,7 +31,7 @@ def get_board_type_from_compile_commands() -> Optional[str]:
|
||||
|
||||
def get_project_version() -> Optional[str]:
|
||||
"""Read set(PROJECT_VER "x.y.z") from root CMakeLists.txt"""
|
||||
with Path("CMakeLists.txt").open() as f:
|
||||
with Path("CMakeLists.txt").open(encoding='utf-8') as f:
|
||||
for line in f:
|
||||
if line.startswith("set(PROJECT_VER"):
|
||||
return line.split("\"")[1]
|
||||
@@ -87,7 +87,7 @@ def _collect_variants(config_filename: str = "config.json") -> list[dict[str, st
|
||||
board = board_dir.relative_to(_BOARDS_DIR).as_posix()
|
||||
|
||||
try:
|
||||
with cfg_path.open() as f:
|
||||
with cfg_path.open(encoding='utf-8') as f:
|
||||
cfg = json.load(f)
|
||||
|
||||
manufacturer = _get_manufacturer(cfg)
|
||||
@@ -232,7 +232,7 @@ def release(board_type: str, config_filename: str = "config.json", *, filter_nam
|
||||
project_version = get_project_version()
|
||||
print(f"Project Version: {project_version} ({cfg_path})")
|
||||
|
||||
with cfg_path.open() as f:
|
||||
with cfg_path.open(encoding='utf-8') as f:
|
||||
cfg = json.load(f)
|
||||
target = cfg["target"]
|
||||
manufacturer = _get_manufacturer(cfg)
|
||||
@@ -279,7 +279,7 @@ def release(board_type: str, config_filename: str = "config.json", *, filter_nam
|
||||
sys.exit(1)
|
||||
|
||||
# Append sdkconfig
|
||||
with Path("sdkconfig").open("a") as f:
|
||||
with Path("sdkconfig").open("a", encoding='utf-8') as f:
|
||||
f.write("\n")
|
||||
f.write("# Append by release.py\n")
|
||||
for append in sdkconfig_append:
|
||||
|
||||
@@ -236,11 +236,11 @@ def main():
|
||||
target_dir = os.path.join("firmwares", tag)
|
||||
info["tag"] = tag
|
||||
info["url"] = os.path.join(os.environ['OSS_BUCKET_URL'], target_dir, "xiaozhi.bin")
|
||||
open(info_path, "w").write(json.dumps(info, indent=4))
|
||||
open(info_path, "w", encoding="utf-8").write(json.dumps(info, indent=4))
|
||||
# upload all file to oss
|
||||
upload_dir_to_oss(folder, target_dir)
|
||||
# read info.json
|
||||
info = json.load(open(info_path))
|
||||
info = json.load(open(info_path, encoding="utf-8"))
|
||||
# post info.json to server
|
||||
post_info_to_server(info)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user