Bladeren bron

add adc and sc7a20.h

haitaowang1001 1 dag geleden
bovenliggende
commit
7a4bb634e3

+ 7 - 3
main/application.cc

@@ -511,7 +511,7 @@ void Application::Start() {
     // Enter the main event loop
     MainEventLoop();
 }
-
+int fist=1;
 void Application::OnClockTimer() {
     clock_ticks_++;
 
@@ -523,9 +523,13 @@ void Application::OnClockTimer() {
         // SystemInfo::PrintTaskCpuUsage(pdMS_TO_TICKS(1000));
         // SystemInfo::PrintTaskList();
         SystemInfo::PrintHeapStats();
-        if (Board::GetInstance().internetConnet==1 && clock_ticks_%50==0)
+        if (Board::GetInstance().internetConnet==1)
         {
-            Board::GetInstance().postAlive();
+            if (clock_ticks_%50==0 || fist==1)
+            {
+                fist=0;
+                Board::GetInstance().postAlive();
+            }
         }
     }
 }

BIN
main/assets/zh-CN/0.p3


BIN
main/assets/zh-CN/1.p3


+ 11 - 0
main/audio/processors/afe_audio_processor.cc

@@ -170,6 +170,11 @@ void AfeAudioProcessor::AudioProcessorTask() {
 
 void AfeAudioProcessor::EnableDeviceAec(bool enable) {
     if (enable) {
+        if (afe_data_==NULL)
+        {
+           ESP_LOGI(TAG, "afe_data_ is NULL");
+           return;
+        }
 #if CONFIG_USE_DEVICE_AEC
         afe_iface_->disable_vad(afe_data_);
         afe_iface_->enable_aec(afe_data_);
@@ -177,6 +182,12 @@ void AfeAudioProcessor::EnableDeviceAec(bool enable) {
         ESP_LOGE(TAG, "Device AEC is not supported");
 #endif
     } else {
+        if (afe_data_==NULL)
+        {
+           ESP_LOGI(TAG, "afe_data_ is NULL");
+           return;
+        }
+        
         afe_iface_->disable_aec(afe_data_);
         afe_iface_->enable_vad(afe_data_);
     }

+ 2 - 2
main/boards/atk-dnesp32s3-box0/power_manager.h

@@ -82,12 +82,12 @@ private:
             uint16_t adc;
             uint8_t level;
         } levels[] = {
-            {2835, 0}, 
+            {2080, 0}, 
             {2953, 20},
             {3033, 40},
             {3112, 60},
             {3228, 80},
-            {3306, 100}
+            {2310, 100}
         };
 
         // 低于最低值时

+ 24 - 2
main/boards/common/blufi.c

@@ -61,7 +61,7 @@
 
 static void example_event_callback(esp_blufi_cb_event_t event, esp_blufi_cb_param_t *param);
 
-#define WIFI_LIST_NUM   10
+#define WIFI_LIST_NUM   2
 
 #define NVS_STA_SSID_KEY "sta_ssid"
 #define NVS_STA_PASS_KEY "sta_pass"
@@ -176,7 +176,9 @@ static void ip_event_handler(void* arg, esp_event_base_t event_base,
  
             // 添加延迟确保数据写入完成 
             vTaskDelay(pdMS_TO_TICKS(100));
-            blufi_security_deinit();
+            esp_blufi_host_deinit();
+            esp_blufi_controller_deinit();
+//            blufi_entry_func_deinit();
             // 重启设备
             esp_restart();           
         } else {
@@ -542,3 +544,23 @@ void blufi_entry_func(void)
 }
 
 
+void blufi_entry_func_deinit(void)
+{
+    esp_err_t ret;
+
+    BLUFI_INFO("BLUFI deinit start");
+
+    ret = esp_blufi_host_deinit();
+    if (ret) {
+        BLUFI_ERROR( "%s deinit host failed: %s\n", __func__, esp_err_to_name(ret));
+    }
+#if CONFIG_BT_CONTROLLER_ENABLED || !CONFIG_BT_NIMBLE_ENABLED
+    ret = esp_blufi_controller_deinit();
+    if (ret) {
+        BLUFI_ERROR( "%s deinit controller failed: %s\n", __func__, esp_err_to_name(ret));
+    }
+#endif
+    BLUFI_INFO("BLUFI deinit finished");
+
+}
+

+ 1 - 0
main/boards/common/blufi.h

@@ -44,6 +44,7 @@ esp_err_t esp_blufi_controller_deinit(void);
  
 // 主测试函数
 void blufi_entry_func(void);
+void blufi_entry_func_deinit(void);
 
 #ifdef __cplusplus 
 }

+ 24 - 6
main/boards/common/board.cc

@@ -162,7 +162,6 @@ std::string Board::GetJson() {
 }
 
 void Board::postAlive() {
-    
     // 创建HTTP客户端
     auto network = Board::GetInstance().GetNetwork();
     if (!network) {
@@ -177,20 +176,39 @@ void Board::postAlive() {
         return;
     }
 
+    // 获取电池状态
+    int level;
+    bool charging, discharging;
+    GetBatteryLevel(level, charging, discharging);
+    
+    // 根据充电状态设置esoc值
+    std::string esoc_value;
+    if (charging) {
+        esoc_value = "-1";
+    } else {
+        esoc_value = std::to_string(level);
+    }
+    // 打印esoc值
+    ESP_LOGI(TAG, "ESOC value: %s", esoc_value.c_str());
     std::string json = "{}"; 
     // 获取MAC地址并构建JSON
     std::string mac = SystemInfo::GetMacAddress();
     ESP_LOGI(TAG, "Device MAC: %s", mac.c_str());
-    http->SetHeader("macAddress", SystemInfo::GetMacAddress().c_str());
+    
+    // 设置HTTP头
+    http->SetHeader("macAddress", mac.c_str());
     http->SetHeader("Content-Type", "application/json");
+    http->SetHeader("esoc", esoc_value.c_str()); // 添加esoc头
+    
     http->SetContent(std::move(json));
-    std::string url ="http://36.134.23.41:8004/xiaozhi-app/app/device/getDeviceEnable";
+    std::string url = "http://36.134.23.41:8004/xiaozhi-app/app/device/getDeviceEnable";
     
     // 发送POST请求
-    if (!http->Open("POST",url.c_str())) {
+    if (!http->Open("POST", url.c_str())) {
         ESP_LOGE(TAG, "HTTP POST failed to open connection");
         return;
     }
+    
     // 获取响应状态码
     int status = http->GetStatusCode();
     ESP_LOGI(TAG, "HTTP response status: %d", status);
@@ -200,7 +218,7 @@ void Board::postAlive() {
     } else {
         ESP_LOGW(TAG, "POST received non-200 status: %d", status);
     }
+    
     http->Close();
     ESP_LOGD(TAG, "postAlive completed");
-}
-
+}

+ 2 - 4
main/boards/common/wifi_board.cc

@@ -37,8 +37,9 @@ void WifiBoard::EnterWifiConfigMode() {
 
     auto& application = Application::GetInstance();
     application.SetDeviceState(kDeviceStateWifiConfiguring);
+#if 1
     blufi_entry_func();
-#if 0
+#else 
     auto& wifi_ap = WifiConfigurationAp::GetInstance();
     wifi_ap.SetLanguage(Lang::CODE);
     wifi_ap.SetSsidPrefix("Xiaozhi");
@@ -65,7 +66,6 @@ void WifiBoard::EnterWifiConfigMode() {
         vTaskDelay(pdMS_TO_TICKS(10000));
     }
 }
-
 void WifiBoard::StartNetwork() {
     // User can press BOOT button while starting to enter WiFi configuration mode
     if (wifi_config_mode_) {
@@ -130,8 +130,6 @@ ssid_manager_destroy(ssid_manager);
         return;
     }
     Board::GetInstance().internetConnet=1;
-
-
 }
 
 NetworkInterface* WifiBoard::GetNetwork() {

+ 3 - 3
main/boards/cx-mxb-wifi/config.h

@@ -16,8 +16,8 @@
 #define AUDIO_I2S_GPIO_DOUT GPIO_NUM_40
 
 #define AUDIO_CODEC_PA_PIN       GPIO_NUM_46
-#define AUDIO_CODEC_I2C_SDA_PIN  GPIO_NUM_15
-#define AUDIO_CODEC_I2C_SCL_PIN  GPIO_NUM_16
+#define AUDIO_CODEC_I2C_SDA_PIN  GPIO_NUM_4
+#define AUDIO_CODEC_I2C_SCL_PIN  GPIO_NUM_5
 #define AUDIO_CODEC_ES8311_ADDR  ES8311_CODEC_DEFAULT_ADDR
 #define AUDIO_CODEC_ES7210_ADDR  ES7210_CODEC_DEFAULT_ADDR
 
@@ -31,7 +31,7 @@
 #define DISPLAY_SCL GPIO_NUM_21
 #define DISPLAY_DC GPIO_NUM_7
 #define DISPLAY_CS GPIO_NUM_8
-#define DISPLAY_RES GPIO_NUM_46
+#define DISPLAY_RES GPIO_NUM_17
 #define DISPLAY_WIDTH   240
 #define DISPLAY_HEIGHT  240
 #define DISPLAY_SWAP_XY  false

+ 103 - 10
main/boards/cx-mxb-wifi/cx-mxb-wifi.cc

@@ -8,20 +8,22 @@
 #include "config.h"
 #include "power_manager.h"
 #include "power_save_timer.h"
+#include "assets/lang_config.h"
+
 
 #include <esp_log.h>
 #include <esp_lcd_panel_vendor.h>
 #include <driver/i2c_master.h>
 #include <driver/spi_common.h>
 #include <wifi_station.h>
+#include "sc7a20h.h"
+#include <esp_sleep.h>
 
-#define TAG "EspBoxBoard"
+#define TAG "CX_MXB_WIFI"
 
 LV_FONT_DECLARE(font_puhui_20_4);
 LV_FONT_DECLARE(font_awesome_20_4);
 
-
-
 class CX_MXB_WIFI : public WifiBoard {
 private:
     i2c_master_bus_handle_t i2c_bus_;
@@ -31,9 +33,18 @@ private:
     esp_lcd_panel_handle_t panel_ = nullptr;
     PowerSaveTimer* power_save_timer_;
     PowerManager* power_manager_;
+    SC7660Driver* sc7660_driver;
+    TaskHandle_t aec_switch_task_handle_;
+    QueueHandle_t aec_switch_queue_;
+    bool aec_switch_requested_;
+
+    void InitializeSC7660() {
+        sc7660_driver = new SC7660Driver(i2c_bus_);
+        sc7660_driver->init();
+    }
 
     void InitializePowerManager() {
-        power_manager_ = new PowerManager(GPIO_NUM_1);
+        power_manager_ = new PowerManager(GPIO_NUM_17);
         power_manager_->OnChargingStatusChanged([this](bool is_charging) {
             if (is_charging) {
                 power_save_timer_->SetEnabled(false);
@@ -44,9 +55,19 @@ private:
     }
 
     void InitializePowerSaveTimer() {
-
         power_save_timer_ = new PowerSaveTimer(-1, 60, 300);
+        power_save_timer_->OnEnterSleepMode([this]() {
+            ESP_LOGI(TAG, "Enabling sleep mode");
+        });
+        power_save_timer_->OnExitSleepMode([this]() {
+           ESP_LOGI(TAG, "exit sleep mode");
+        });
         power_save_timer_->OnShutdownRequest([this]() {
+            // 配置 GPIO9 为高电平唤醒源
+            esp_sleep_enable_ext0_wakeup(GPIO_NUM_9,GPIO_INTR_POSEDGE);
+
+            // 进入睡眠模式
+            esp_deep_sleep_start();
         });
         power_save_timer_->SetEnabled(true);
     }
@@ -67,7 +88,16 @@ private:
         };
         ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &i2c_bus_));
     }
-
+    void InitializeSpi() {
+        spi_bus_config_t buscfg = {};
+        buscfg.mosi_io_num = DISPLAY_SDA;
+        buscfg.miso_io_num = GPIO_NUM_NC;
+        buscfg.sclk_io_num = DISPLAY_SCL;
+        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]() {
             auto& app = Application::GetInstance();
@@ -79,19 +109,79 @@ private:
 
 #if CONFIG_USE_DEVICE_AEC
         boot_button_.OnDoubleClick([this]() {
+
             auto& app = Application::GetInstance();
-            if (app.GetDeviceState() == kDeviceStateIdle) {
-                app.SetAecMode(app.GetAecMode() == kAecOff ? kAecOnDeviceSide : kAecOff);
+            // 排除其他状态
+            if (app.GetDeviceState() == kDeviceStateSpeaking || 
+                app.GetDeviceState() == kDeviceStateListening ||
+                app.GetDeviceState() == kDeviceStateIdle) {
+            // 如果当前处于对话状态,先终止对话
+            if (app.GetDeviceState() == kDeviceStateSpeaking || 
+                app.GetDeviceState() == kDeviceStateListening) {
+                app.ToggleChatState(); // 终止当前对话
+            }
+            
+            // 切换AEC模式
+            AecMode new_mode = app.GetAecMode() == kAecOff ? kAecOnDeviceSide : kAecOff;
+            app.SetAecMode(new_mode);
+            
+            ESP_LOGI(TAG, "AEC mode switched to: %d", new_mode);
+            
+            // 添加语音提醒 - 使用正确的Alert方法签名
+            if (new_mode == kAecOnDeviceSide) {
+                app.Alert(Lang::Strings::ACCESS_VIA_BROWSER, "", "happy", Lang::Sounds::P3_0);
+            } else {
+                app.Alert(Lang::Strings::ACCESS_VIA_BROWSER, "", "happy", Lang::Sounds::P3_1);
             }
+        }
         });
 #endif
     }
+    void InitializeSt7789Display() {
+        ESP_LOGD(TAG, "Install panel IO");
+        esp_lcd_panel_io_spi_config_t io_config = {};
+        io_config.cs_gpio_num = DISPLAY_CS;
+        io_config.dc_gpio_num = DISPLAY_DC;
+        io_config.spi_mode = 3;
+        io_config.pclk_hz = 80 * 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");
+        esp_lcd_panel_dev_config_t panel_config = {};
+        panel_config.reset_gpio_num = DISPLAY_RES;
+        panel_config.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB;
+        panel_config.bits_per_pixel = 16;
+        ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(panel_io_, &panel_config, &panel_));
+        ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_));
+        ESP_ERROR_CHECK(esp_lcd_panel_init(panel_));
+        ESP_ERROR_CHECK(esp_lcd_panel_swap_xy(panel_, DISPLAY_SWAP_XY));
+        ESP_ERROR_CHECK(esp_lcd_panel_mirror(panel_, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y));
+        ESP_ERROR_CHECK(esp_lcd_panel_invert_color(panel_, true));
+
+        display_ = new SpiLcdDisplay(panel_io_, panel_, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, 
+            DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY, 
+        {
+            .text_font = &font_puhui_20_4,
+            .icon_font = &font_awesome_20_4,
+#if CONFIG_USE_WECHAT_MESSAGE_STYLE
+            .emoji_font = font_emoji_32_init(),
+#else
+            .emoji_font = font_emoji_64_init(),
+#endif
+        });
+    }
 public:
     CX_MXB_WIFI() : boot_button_(BOOT_BUTTON_GPIO) {
         InitializePowerManager();
         InitializePowerSaveTimer();
         InitializeI2c();
+        InitializeSpi();
         InitializeButtons();
+        InitializeSC7660();
+        InitializeSt7789Display();
     }
 
     virtual AudioCodec* GetAudioCodec() override {
@@ -110,6 +200,7 @@ public:
             AUDIO_INPUT_REFERENCE);
         return &audio_codec;
     }
+    
     virtual bool GetBatteryLevel(int& level, bool& charging, bool& discharging) override {
         static bool last_discharging = false;
         charging = power_manager_->IsCharging();
@@ -128,7 +219,9 @@ public:
         }
         WifiBoard::SetPowerSaveMode(enabled);
     }
-
+    virtual Display* GetDisplay() override {
+        return display_;
+    }
 };
 
-DECLARE_BOARD(CX_MXB_WIFI);
+DECLARE_BOARD(CX_MXB_WIFI);

+ 7 - 7
main/boards/cx-mxb-wifi/power_manager.h

@@ -27,7 +27,7 @@ private:
 
     void CheckBatteryStatus() {
         // Get charging status
-        bool new_charging_status = gpio_get_level(charging_pin_) == 1;
+        bool new_charging_status = gpio_get_level(charging_pin_) ==1;
         if (new_charging_status != is_charging_) {
             is_charging_ = new_charging_status;
             if (on_charging_status_changed_) {
@@ -69,12 +69,12 @@ private:
             uint16_t adc;
             uint8_t level;
         } levels[] = {
-            {2047, 0},
-            {2106, 20},
-            {2164, 40},
-            {2223, 60},
-            {2281, 80},
-            {2310, 100}
+            {2000, 0},
+            {2060, 20},
+            {2120, 40},
+            {2180, 60},
+            {2240, 80},
+            {2340, 100}
         };
 
         // 低于最低值时

+ 175 - 0
main/boards/cx-mxb-wifi/sc7a20h.h

@@ -0,0 +1,175 @@
+#pragma once
+#include "driver/gpio.h"
+#include "driver/i2c_master.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/queue.h"
+#include "esp_log.h"
+
+#define TAG1 "SC7660"
+
+// SC7660寄存器地址
+#define SC7660_ADDR 0x19 // 假设I2C地址为0x19,请根据实际硬件确认
+
+#define SC7660_CTRL_REG0 0x1F
+
+#define SC7660_CTRL_REG1 0x20
+#define SC7660_CTRL_REG2 0x21
+#define SC7660_CTRL_REG3 0x22
+#define SC7660_CTRL_REG4 0x23
+#define SC7660_CTRL_REG5 0x24
+#define SC7660_CTRL_REG6 0x25
+
+#define SC7660_CLICK_CFG 0x38
+#define SC7660_CLICK_SRC 0x39
+#define SC7660_CLICK_THS 0x3A
+#define SC7660_TIME_LIMIT 0x3B
+#define SC7660_TIME_LATENCY 0x3C
+#define SC7660_TIME_WINDOW 0x3D
+
+#define SC7660_INT1_CFG 0x30
+#define SC7660_INT1_THS 0x32
+#define SC7660_INT1_DURATION 0x33
+
+#define SC7660_STATUS_REG 0x27
+#define SC7660_OUT_X_L 0x28
+#define SC7660_OUT_X_H 0x29
+#define SC7660_OUT_Y_L 0x2A
+#define SC7660_OUT_Y_H 0x2B
+#define SC7660_OUT_Z_L 0x2C
+#define SC7660_OUT_Z_H 0x2D
+
+#define SC7660_CTRL_REG58 58
+
+// 中断引脚配置
+#define SC7660_INT1_GPIO GPIO_NUM_9
+
+class SC7660Driver {
+private:
+    i2c_master_dev_handle_t dev_handle;
+//    QueueHandle_t interrupt_queue;
+    
+    esp_err_t write_register(uint8_t reg, uint8_t value) {
+        uint8_t write_buf[2] = {reg, value};
+        return i2c_master_transmit(dev_handle, write_buf, sizeof(write_buf), -1);
+    }
+    
+    esp_err_t read_register(uint8_t reg, uint8_t *value) {
+        esp_err_t ret = i2c_master_transmit(dev_handle, &reg, 1, -1);
+        if (ret != ESP_OK) return ret;
+        return i2c_master_receive(dev_handle, value, 1, -1);
+    }
+    
+    esp_err_t read_registers(uint8_t reg, uint8_t *data, size_t len) {
+        esp_err_t ret = i2c_master_transmit(dev_handle, &reg, 1, -1);
+        if (ret != ESP_OK) return ret;
+        return i2c_master_receive(dev_handle, data, len, -1);
+    }
+
+public:
+    SC7660Driver(i2c_master_bus_handle_t bus_handle) {
+        i2c_device_config_t dev_cfg = {
+            .dev_addr_length = I2C_ADDR_BIT_LEN_7,
+            .device_address = SC7660_ADDR,
+            .scl_speed_hz = 400000, // 400kHz
+        };
+        
+        ESP_ERROR_CHECK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &dev_handle));
+        
+        // 创建中断队列
+       // interrupt_queue = xQueueCreate(10, sizeof(uint32_t));
+    }
+    
+    ~SC7660Driver() {
+        i2c_master_bus_rm_device(dev_handle);
+        //vQueueDelete(interrupt_queue);
+    }
+    
+    esp_err_t init() {
+        ESP_LOGI(TAG1, "Initializing SC7660...");
+        
+        ESP_ERROR_CHECK(write_register(SC7660_CTRL_REG0, 0x08));
+        
+        // 1. 进入掉电模式进行配置
+        ESP_ERROR_CHECK(write_register(SC7660_CTRL_REG1, 0x47));
+        
+        // 2. 配置双击检测参数(基于文档7.5节示例)
+        // 设置ODR为25Hz,使能XYZ轴
+        ESP_ERROR_CHECK(write_register(SC7660_CTRL_REG4, 0x88));
+        
+        // 配置高通滤波器(作用于CLICK功能)
+        ESP_ERROR_CHECK(write_register(SC7660_CTRL_REG2, 0x31));
+        
+        // 设置量程为±2G,BDU=1
+        ESP_ERROR_CHECK(write_register(SC7660_CTRL_REG3, 0x40));
+        
+        // 使能X和Y轴的双击检测
+        ESP_ERROR_CHECK(write_register(SC7660_CTRL_REG6, 0x00));
+        
+        // 设置点击阈值
+        ESP_ERROR_CHECK(write_register(SC7660_CTRL_REG5, 0x00));
+        
+        // 设置时间限制窗口
+        ESP_ERROR_CHECK(write_register(SC7660_INT1_CFG, 0x2A));
+        
+        // 设置中断持续时间
+        ESP_ERROR_CHECK(write_register(SC7660_INT1_THS, 0x03));
+        
+        // 设置双击时间窗口
+        ESP_ERROR_CHECK(write_register(SC7660_INT1_DURATION, 0x50));
+        
+        // 3. 配置中断
+        // 将双击中断映射到INT1引脚
+        ESP_ERROR_CHECK(write_register(SC7660_CTRL_REG58, 0x02)); 
+ 
+        
+        ESP_LOGI(TAG1, "SC7660 initialization complete");
+        return ESP_OK;
+    }
+    
+    // esp_err_t setup_interrupt() {
+    //     // 配置GPIO9为输入,用于接收INT1中断
+    //     gpio_config_t io_conf = {
+    //         .pin_bit_mask = (1ULL << SC7660_INT1_GPIO),
+    //         .mode = GPIO_MODE_INPUT,
+    //         .pull_up_en = GPIO_PULLUP_DISABLE,
+    //         .pull_down_en = GPIO_PULLDOWN_DISABLE,
+    //         .intr_type = GPIO_INTR_POSEDGE, // 上升沿触发
+    //     };
+    //     ESP_ERROR_CHECK(gpio_config(&io_conf));
+        
+    //     // 安装GPIO ISR服务
+    //     ESP_ERROR_CHECK(gpio_install_isr_service(0));
+        
+    //     // 添加ISR处理程序
+    //     ESP_ERROR_CHECK(gpio_isr_handler_add(SC7660_INT1_GPIO, interrupt_handler, this));
+        
+    //     return ESP_OK;
+    // }
+    
+    // static void IRAM_ATTR interrupt_handler(void* arg) {
+    //     SC7660Driver* driver = (SC7660Driver*)arg;
+    //     uint32_t gpio_num = SC7660_INT1_GPIO;
+    //     xQueueSendFromISR(driver->interrupt_queue, &gpio_num, NULL);
+    // }
+    
+    // void handle_interrupts() {
+    //     uint32_t io_num;
+    //     while (xQueueReceive(interrupt_queue, &io_num, portMAX_DELAY)) {
+    //         if (io_num == SC7660_INT1_GPIO) {
+    //             // 唤醒设备
+    //           ESP_LOGI(TAG1, "weak up.");  
+    //         }
+    //     }
+    // }
+    
+    // // 任务函数
+    // static void interrupt_task(void* arg) {
+    //     SC7660Driver* driver = (SC7660Driver*)arg;
+    //     driver->handle_interrupts();
+    // }
+    
+    // esp_err_t start_interrupt_handler() {
+    //     return xTaskCreate(interrupt_task, "sc7660_int", 2048, this, 5, NULL) == pdPASS ? ESP_OK : ESP_FAIL;
+    // }
+};

+ 1 - 1
main/boards/waveshare-p4-wifi6-touch-lcd-xc/config.h

@@ -38,7 +38,7 @@
 #define DISPLAY_OFFSET_X  0
 #define DISPLAY_OFFSET_Y  0
 
-#define DISPLAY_BACKLIGHT_PIN GPIO_NUM_26
+#define DISPLAY_BACKLIGHT_PIN 
 #define DISPLAY_BACKLIGHT_OUTPUT_INVERT true
 
 #if CONFIG_LCD_TYPE_800_800_3_4_INCH

+ 211 - 211
main/display/display.cc

@@ -15,62 +15,62 @@
 #define TAG "Display"
 
 Display::Display() {
-    // // Notification timer
-    // esp_timer_create_args_t notification_timer_args = {
-    //     .callback = [](void *arg) {
-    //         Display *display = static_cast<Display*>(arg);
-    //         DisplayLockGuard lock(display);
-    //         lv_obj_add_flag(display->notification_label_, LV_OBJ_FLAG_HIDDEN);
-    //         lv_obj_clear_flag(display->status_label_, LV_OBJ_FLAG_HIDDEN);
-    //     },
-    //     .arg = this,
-    //     .dispatch_method = ESP_TIMER_TASK,
-    //     .name = "notification_timer",
-    //     .skip_unhandled_events = false,
-    // };
-    // ESP_ERROR_CHECK(esp_timer_create(&notification_timer_args, &notification_timer_));
+    // Notification timer
+    esp_timer_create_args_t notification_timer_args = {
+        .callback = [](void *arg) {
+            Display *display = static_cast<Display*>(arg);
+            DisplayLockGuard lock(display);
+            lv_obj_add_flag(display->notification_label_, LV_OBJ_FLAG_HIDDEN);
+            lv_obj_clear_flag(display->status_label_, LV_OBJ_FLAG_HIDDEN);
+        },
+        .arg = this,
+        .dispatch_method = ESP_TIMER_TASK,
+        .name = "notification_timer",
+        .skip_unhandled_events = false,
+    };
+    ESP_ERROR_CHECK(esp_timer_create(&notification_timer_args, &notification_timer_));
 
-    // // Create a power management lock
-    // auto ret = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "display_update", &pm_lock_);
-    // if (ret == ESP_ERR_NOT_SUPPORTED) {
-    //     ESP_LOGI(TAG, "Power management not supported");
-    // } else {
-    //     ESP_ERROR_CHECK(ret);
-    // }
+    // Create a power management lock
+    auto ret = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "display_update", &pm_lock_);
+    if (ret == ESP_ERR_NOT_SUPPORTED) {
+        ESP_LOGI(TAG, "Power management not supported");
+    } else {
+        ESP_ERROR_CHECK(ret);
+    }
 }
 
 Display::~Display() {
-    // if (notification_timer_ != nullptr) {
-    //     esp_timer_stop(notification_timer_);
-    //     esp_timer_delete(notification_timer_);
-    // }
+    if (notification_timer_ != nullptr) {
+        esp_timer_stop(notification_timer_);
+        esp_timer_delete(notification_timer_);
+    }
 
-    // if (network_label_ != nullptr) {
-    //     lv_obj_del(network_label_);
-    //     lv_obj_del(notification_label_);
-    //     lv_obj_del(status_label_);
-    //     lv_obj_del(mute_label_);
-    //     lv_obj_del(battery_label_);
-    //     lv_obj_del(emotion_label_);
-    // }
-    // if( low_battery_popup_ != nullptr ) {
-    //     lv_obj_del(low_battery_popup_);
-    // }
-    // if (pm_lock_ != nullptr) {
-    //     esp_pm_lock_delete(pm_lock_);
-    // }
+    if (network_label_ != nullptr) {
+        lv_obj_del(network_label_);
+        lv_obj_del(notification_label_);
+        lv_obj_del(status_label_);
+        lv_obj_del(mute_label_);
+        lv_obj_del(battery_label_);
+        lv_obj_del(emotion_label_);
+    }
+    if( low_battery_popup_ != nullptr ) {
+        lv_obj_del(low_battery_popup_);
+    }
+    if (pm_lock_ != nullptr) {
+        esp_pm_lock_delete(pm_lock_);
+    }
 }
 
 void Display::SetStatus(const char* status) {
-    // DisplayLockGuard lock(this);
-    // if (status_label_ == nullptr) {
-    //     return;
-    // }
-    // lv_label_set_text(status_label_, status);
-    // lv_obj_clear_flag(status_label_, LV_OBJ_FLAG_HIDDEN);
-    // lv_obj_add_flag(notification_label_, LV_OBJ_FLAG_HIDDEN);
+    DisplayLockGuard lock(this);
+    if (status_label_ == nullptr) {
+        return;
+    }
+    lv_label_set_text(status_label_, status);
+    lv_obj_clear_flag(status_label_, LV_OBJ_FLAG_HIDDEN);
+    lv_obj_add_flag(notification_label_, LV_OBJ_FLAG_HIDDEN);
 
-    // last_status_update_time_ = std::chrono::system_clock::now();
+    last_status_update_time_ = std::chrono::system_clock::now();
 }
 
 void Display::ShowNotification(const std::string &notification, int duration_ms) {
@@ -78,177 +78,177 @@ void Display::ShowNotification(const std::string &notification, int duration_ms)
 }
 
 void Display::ShowNotification(const char* notification, int duration_ms) {
-    // DisplayLockGuard lock(this);
-    // if (notification_label_ == nullptr) {
-    //     return;
-    // }
-    // lv_label_set_text(notification_label_, notification);
-    // lv_obj_clear_flag(notification_label_, LV_OBJ_FLAG_HIDDEN);
-    // lv_obj_add_flag(status_label_, LV_OBJ_FLAG_HIDDEN);
+    DisplayLockGuard lock(this);
+    if (notification_label_ == nullptr) {
+        return;
+    }
+    lv_label_set_text(notification_label_, notification);
+    lv_obj_clear_flag(notification_label_, LV_OBJ_FLAG_HIDDEN);
+    lv_obj_add_flag(status_label_, LV_OBJ_FLAG_HIDDEN);
 
-    // esp_timer_stop(notification_timer_);
-    // ESP_ERROR_CHECK(esp_timer_start_once(notification_timer_, duration_ms * 1000));
+    esp_timer_stop(notification_timer_);
+    ESP_ERROR_CHECK(esp_timer_start_once(notification_timer_, duration_ms * 1000));
 }
 
 void Display::UpdateStatusBar(bool update_all) {
-    // auto& app = Application::GetInstance();
-    // auto& board = Board::GetInstance();
-    // auto codec = board.GetAudioCodec();
+    auto& app = Application::GetInstance();
+    auto& board = Board::GetInstance();
+    auto codec = board.GetAudioCodec();
 
-    // // Update mute icon
-    // {
-    //     DisplayLockGuard lock(this);
-    //     if (mute_label_ == nullptr) {
-    //         return;
-    //     }
+    // Update mute icon
+    {
+        DisplayLockGuard lock(this);
+        if (mute_label_ == nullptr) {
+            return;
+        }
 
-    //     // 如果静音状态改变,则更新图标
-    //     if (codec->output_volume() == 0 && !muted_) {
-    //         muted_ = true;
-    //         lv_label_set_text(mute_label_, FONT_AWESOME_VOLUME_MUTE);
-    //     } else if (codec->output_volume() > 0 && muted_) {
-    //         muted_ = false;
-    //         lv_label_set_text(mute_label_, "");
-    //     }
-    // }
+        // 如果静音状态改变,则更新图标
+        if (codec->output_volume() == 0 && !muted_) {
+            muted_ = true;
+            lv_label_set_text(mute_label_, FONT_AWESOME_VOLUME_MUTE);
+        } else if (codec->output_volume() > 0 && muted_) {
+            muted_ = false;
+            lv_label_set_text(mute_label_, "");
+        }
+    }
 
-    // // Update time
-    // if (app.GetDeviceState() == kDeviceStateIdle) {
-    //     if (last_status_update_time_ + std::chrono::seconds(10) < std::chrono::system_clock::now()) {
-    //         // Set status to clock "HH:MM"
-    //         time_t now = time(NULL);
-    //         struct tm* tm = localtime(&now);
-    //         // Check if the we have already set the time
-    //         if (tm->tm_year >= 2025 - 1900) {
-    //             char time_str[16];
-    //             strftime(time_str, sizeof(time_str), "%H:%M  ", tm);
-    //             SetStatus(time_str);
-    //         } else {
-    //             ESP_LOGW(TAG, "System time is not set, tm_year: %d", tm->tm_year);
-    //         }
-    //     }
-    // }
+    // Update time
+    if (app.GetDeviceState() == kDeviceStateIdle) {
+        if (last_status_update_time_ + std::chrono::seconds(10) < std::chrono::system_clock::now()) {
+            // Set status to clock "HH:MM"
+            time_t now = time(NULL);
+            struct tm* tm = localtime(&now);
+            // Check if the we have already set the time
+            if (tm->tm_year >= 2025 - 1900) {
+                char time_str[16];
+                strftime(time_str, sizeof(time_str), "%H:%M  ", tm);
+                SetStatus(time_str);
+            } else {
+                ESP_LOGW(TAG, "System time is not set, tm_year: %d", tm->tm_year);
+            }
+        }
+    }
 
-    // esp_pm_lock_acquire(pm_lock_);
-    // // 更新电池图标
-    // int battery_level;
-    // bool charging, discharging;
-    // const char* icon = nullptr;
-    // if (board.GetBatteryLevel(battery_level, charging, discharging)) {
-    //     if (charging) {
-    //         icon = FONT_AWESOME_BATTERY_CHARGING;
-    //     } else {
-    //         const char* levels[] = {
-    //             FONT_AWESOME_BATTERY_EMPTY, // 0-19%
-    //             FONT_AWESOME_BATTERY_1,    // 20-39%
-    //             FONT_AWESOME_BATTERY_2,    // 40-59%
-    //             FONT_AWESOME_BATTERY_3,    // 60-79%
-    //             FONT_AWESOME_BATTERY_FULL, // 80-99%
-    //             FONT_AWESOME_BATTERY_FULL, // 100%
-    //         };
-    //         icon = levels[battery_level / 20];
-    //     }
-    //     DisplayLockGuard lock(this);
-    //     if (battery_label_ != nullptr && battery_icon_ != icon) {
-    //         battery_icon_ = icon;
-    //         lv_label_set_text(battery_label_, battery_icon_);
-    //     }
+    esp_pm_lock_acquire(pm_lock_);
+    // 更新电池图标
+    int battery_level;
+    bool charging, discharging;
+    const char* icon = nullptr;
+    if (board.GetBatteryLevel(battery_level, charging, discharging)) {
+        if (charging) {
+            icon = FONT_AWESOME_BATTERY_CHARGING;
+        } else {
+            const char* levels[] = {
+                FONT_AWESOME_BATTERY_EMPTY, // 0-19%
+                FONT_AWESOME_BATTERY_1,    // 20-39%
+                FONT_AWESOME_BATTERY_2,    // 40-59%
+                FONT_AWESOME_BATTERY_3,    // 60-79%
+                FONT_AWESOME_BATTERY_FULL, // 80-99%
+                FONT_AWESOME_BATTERY_FULL, // 100%
+            };
+            icon = levels[battery_level / 20];
+        }
+        DisplayLockGuard lock(this);
+        if (battery_label_ != nullptr && battery_icon_ != icon) {
+            battery_icon_ = icon;
+            lv_label_set_text(battery_label_, battery_icon_);
+        }
 
-    //     if (low_battery_popup_ != nullptr) {
-    //         if (strcmp(icon, FONT_AWESOME_BATTERY_EMPTY) == 0 && discharging) {
-    //             if (lv_obj_has_flag(low_battery_popup_, LV_OBJ_FLAG_HIDDEN)) { // 如果低电量提示框隐藏,则显示
-    //                 lv_obj_clear_flag(low_battery_popup_, LV_OBJ_FLAG_HIDDEN);
-    //                 app.PlaySound(Lang::Sounds::P3_LOW_BATTERY);
-    //             }
-    //         } else {
-    //             // Hide the low battery popup when the battery is not empty
-    //             if (!lv_obj_has_flag(low_battery_popup_, LV_OBJ_FLAG_HIDDEN)) { // 如果低电量提示框显示,则隐藏
-    //                 lv_obj_add_flag(low_battery_popup_, LV_OBJ_FLAG_HIDDEN);
-    //             }
-    //         }
-    //     }
-    // }
+        if (low_battery_popup_ != nullptr) {
+            if (strcmp(icon, FONT_AWESOME_BATTERY_EMPTY) == 0 && discharging) {
+                if (lv_obj_has_flag(low_battery_popup_, LV_OBJ_FLAG_HIDDEN)) { // 如果低电量提示框隐藏,则显示
+                    lv_obj_clear_flag(low_battery_popup_, LV_OBJ_FLAG_HIDDEN);
+                    app.PlaySound(Lang::Sounds::P3_LOW_BATTERY);
+                }
+            } else {
+                // Hide the low battery popup when the battery is not empty
+                if (!lv_obj_has_flag(low_battery_popup_, LV_OBJ_FLAG_HIDDEN)) { // 如果低电量提示框显示,则隐藏
+                    lv_obj_add_flag(low_battery_popup_, LV_OBJ_FLAG_HIDDEN);
+                }
+            }
+        }
+    }
 
-    // // 每 10 秒更新一次网络图标
-    // static int seconds_counter = 0;
-    // if (update_all || seconds_counter++ % 10 == 0) {
-    //     // 升级固件时,不读取 4G 网络状态,避免占用 UART 资源
-    //     auto device_state = Application::GetInstance().GetDeviceState();
-    //     static const std::vector<DeviceState> allowed_states = {
-    //         kDeviceStateIdle,
-    //         kDeviceStateStarting,
-    //         kDeviceStateWifiConfiguring,
-    //         kDeviceStateListening,
-    //         kDeviceStateActivating,
-    //     };
-    //     if (std::find(allowed_states.begin(), allowed_states.end(), device_state) != allowed_states.end()) {
-    //         icon = board.GetNetworkStateIcon();
-    //         if (network_label_ != nullptr && icon != nullptr && network_icon_ != icon) {
-    //             DisplayLockGuard lock(this);
-    //             network_icon_ = icon;
-    //             lv_label_set_text(network_label_, network_icon_);
-    //         }
-    //     }
-    // }
+    // 每 10 秒更新一次网络图标
+    static int seconds_counter = 0;
+    if (update_all || seconds_counter++ % 10 == 0) {
+        // 升级固件时,不读取 4G 网络状态,避免占用 UART 资源
+        auto device_state = Application::GetInstance().GetDeviceState();
+        static const std::vector<DeviceState> allowed_states = {
+            kDeviceStateIdle,
+            kDeviceStateStarting,
+            kDeviceStateWifiConfiguring,
+            kDeviceStateListening,
+            kDeviceStateActivating,
+        };
+        if (std::find(allowed_states.begin(), allowed_states.end(), device_state) != allowed_states.end()) {
+            icon = board.GetNetworkStateIcon();
+            if (network_label_ != nullptr && icon != nullptr && network_icon_ != icon) {
+                DisplayLockGuard lock(this);
+                network_icon_ = icon;
+                lv_label_set_text(network_label_, network_icon_);
+            }
+        }
+    }
 
-    // esp_pm_lock_release(pm_lock_);
+    esp_pm_lock_release(pm_lock_);
 }
 
 
 void Display::SetEmotion(const char* emotion) {
-    // struct Emotion {
-    //     const char* icon;
-    //     const char* text;
-    // };
+    struct Emotion {
+        const char* icon;
+        const char* text;
+    };
 
-    // static const std::vector<Emotion> emotions = {
-    //     {FONT_AWESOME_EMOJI_NEUTRAL, "neutral"},
-    //     {FONT_AWESOME_EMOJI_HAPPY, "happy"},
-    //     {FONT_AWESOME_EMOJI_LAUGHING, "laughing"},
-    //     {FONT_AWESOME_EMOJI_FUNNY, "funny"},
-    //     {FONT_AWESOME_EMOJI_SAD, "sad"},
-    //     {FONT_AWESOME_EMOJI_ANGRY, "angry"},
-    //     {FONT_AWESOME_EMOJI_CRYING, "crying"},
-    //     {FONT_AWESOME_EMOJI_LOVING, "loving"},
-    //     {FONT_AWESOME_EMOJI_EMBARRASSED, "embarrassed"},
-    //     {FONT_AWESOME_EMOJI_SURPRISED, "surprised"},
-    //     {FONT_AWESOME_EMOJI_SHOCKED, "shocked"},
-    //     {FONT_AWESOME_EMOJI_THINKING, "thinking"},
-    //     {FONT_AWESOME_EMOJI_WINKING, "winking"},
-    //     {FONT_AWESOME_EMOJI_COOL, "cool"},
-    //     {FONT_AWESOME_EMOJI_RELAXED, "relaxed"},
-    //     {FONT_AWESOME_EMOJI_DELICIOUS, "delicious"},
-    //     {FONT_AWESOME_EMOJI_KISSY, "kissy"},
-    //     {FONT_AWESOME_EMOJI_CONFIDENT, "confident"},
-    //     {FONT_AWESOME_EMOJI_SLEEPY, "sleepy"},
-    //     {FONT_AWESOME_EMOJI_SILLY, "silly"},
-    //     {FONT_AWESOME_EMOJI_CONFUSED, "confused"}
-    // };
+    static const std::vector<Emotion> emotions = {
+        {FONT_AWESOME_EMOJI_NEUTRAL, "neutral"},
+        {FONT_AWESOME_EMOJI_HAPPY, "happy"},
+        {FONT_AWESOME_EMOJI_LAUGHING, "laughing"},
+        {FONT_AWESOME_EMOJI_FUNNY, "funny"},
+        {FONT_AWESOME_EMOJI_SAD, "sad"},
+        {FONT_AWESOME_EMOJI_ANGRY, "angry"},
+        {FONT_AWESOME_EMOJI_CRYING, "crying"},
+        {FONT_AWESOME_EMOJI_LOVING, "loving"},
+        {FONT_AWESOME_EMOJI_EMBARRASSED, "embarrassed"},
+        {FONT_AWESOME_EMOJI_SURPRISED, "surprised"},
+        {FONT_AWESOME_EMOJI_SHOCKED, "shocked"},
+        {FONT_AWESOME_EMOJI_THINKING, "thinking"},
+        {FONT_AWESOME_EMOJI_WINKING, "winking"},
+        {FONT_AWESOME_EMOJI_COOL, "cool"},
+        {FONT_AWESOME_EMOJI_RELAXED, "relaxed"},
+        {FONT_AWESOME_EMOJI_DELICIOUS, "delicious"},
+        {FONT_AWESOME_EMOJI_KISSY, "kissy"},
+        {FONT_AWESOME_EMOJI_CONFIDENT, "confident"},
+        {FONT_AWESOME_EMOJI_SLEEPY, "sleepy"},
+        {FONT_AWESOME_EMOJI_SILLY, "silly"},
+        {FONT_AWESOME_EMOJI_CONFUSED, "confused"}
+    };
     
-    // // 查找匹配的表情
-    // std::string_view emotion_view(emotion);
-    // auto it = std::find_if(emotions.begin(), emotions.end(),
-    //     [&emotion_view](const Emotion& e) { return e.text == emotion_view; });
+    // 查找匹配的表情
+    std::string_view emotion_view(emotion);
+    auto it = std::find_if(emotions.begin(), emotions.end(),
+        [&emotion_view](const Emotion& e) { return e.text == emotion_view; });
     
-    // DisplayLockGuard lock(this);
-    // if (emotion_label_ == nullptr) {
-    //     return;
-    // }
+    DisplayLockGuard lock(this);
+    if (emotion_label_ == nullptr) {
+        return;
+    }
 
-    // // 如果找到匹配的表情就显示对应图标,否则显示默认的neutral表情
-    // if (it != emotions.end()) {
-    //     lv_label_set_text(emotion_label_, it->icon);
-    // } else {
-    //     lv_label_set_text(emotion_label_, FONT_AWESOME_EMOJI_NEUTRAL);
-    // }
+    // 如果找到匹配的表情就显示对应图标,否则显示默认的neutral表情
+    if (it != emotions.end()) {
+        lv_label_set_text(emotion_label_, it->icon);
+    } else {
+        lv_label_set_text(emotion_label_, FONT_AWESOME_EMOJI_NEUTRAL);
+    }
 }
 
 void Display::SetIcon(const char* icon) {
-    // DisplayLockGuard lock(this);
-    // if (emotion_label_ == nullptr) {
-    //     return;
-    // }
-    // lv_label_set_text(emotion_label_, icon);
+    DisplayLockGuard lock(this);
+    if (emotion_label_ == nullptr) {
+        return;
+    }
+    lv_label_set_text(emotion_label_, icon);
 }
 
 void Display::SetPreviewImage(const lv_img_dsc_t* image) {
@@ -256,25 +256,25 @@ void Display::SetPreviewImage(const lv_img_dsc_t* image) {
 }
 
 void Display::SetChatMessage(const char* role, const char* content) {
-    // DisplayLockGuard lock(this);
-    // if (chat_message_label_ == nullptr) {
-    //     return;
-    // }
-    // lv_label_set_text(chat_message_label_, content);
+    DisplayLockGuard lock(this);
+    if (chat_message_label_ == nullptr) {
+        return;
+    }
+    lv_label_set_text(chat_message_label_, content);
 }
 
 void Display::SetTheme(const std::string& theme_name) {
-//     current_theme_name_ = theme_name;
-//     Settings settings("display", true);
-//     settings.SetString("theme", theme_name);
+    current_theme_name_ = theme_name;
+    Settings settings("display", true);
+    settings.SetString("theme", theme_name);
 }
 
 void Display::ShowStandbyScreen(bool show) {
-//     if (show) {
-//         SetChatMessage("system", "");
-//         SetEmotion("sleepy");
-//     } else {
-//         SetChatMessage("system", "");
-//         SetEmotion("neutral");
-//     }
+    if (show) {
+        SetChatMessage("system", "");
+        SetEmotion("sleepy");
+    } else {
+        SetChatMessage("system", "");
+        SetEmotion("neutral");
+    }
 }