diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 73f07b37..5fdd5726 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -134,6 +134,8 @@ elseif(CONFIG_BOARD_TYPE_XINGZHI_Cube_1_54TFT_ML307) set(BOARD_TYPE "xingzhi-cube-1.54tft-ml307") elseif(CONFIG_BOARD_TYPE_SENSECAP_WATCHER) set(BOARD_TYPE "sensecap-watcher") +elseif(CONFIG_BOARD_TYPE_DOIT_S3_AIBOX) + set(BOARD_TYPE "doit-s3-aibox") elseif(CONFIG_BOARD_TYPE_ESP32_CGC) set(BOARD_TYPE "esp32-cgc") endif() diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild index b0213a42..5fe196b3 100644 --- a/main/Kconfig.projbuild +++ b/main/Kconfig.projbuild @@ -158,6 +158,8 @@ choice BOARD_TYPE bool "无名科技星智1.54(ML307)" config BOARD_TYPE_SENSECAP_WATCHER bool "SenseCAP Watcher" + config BOARD_TYPE_DOIT_S3_AIBOX + bool "四博智联AI陪伴盒子" endchoice choice DISPLAY_OLED_TYPE diff --git a/main/boards/doit-s3-aibox/README.md b/main/boards/doit-s3-aibox/README.md new file mode 100644 index 00000000..006b9e76 --- /dev/null +++ b/main/boards/doit-s3-aibox/README.md @@ -0,0 +1,42 @@ +# 四博智联AI陪伴盒子 + +# 特性 +* 使用PDM麦克风 +* 使用共阳极LED + +## 按键配置 +* BUTTON3:短按-打断/唤醒 +* BUTTON1:音量+ +* BUTTON2:音量- + +## 编译配置命令 + +**配置编译目标为 ESP32S3:** + +```bash +idf.py set-target esp32s3 +``` + +**打开 menuconfig:** + +```bash +idf.py menuconfig +``` + +**选择板子:** + +``` +Xiaozhi Assistant -> Board Type -> 四博智联AI陪伴盒子 +``` + +**修改 psram 配置:** + +``` +Component config -> ESP PSRAM -> SPI RAM config -> Mode (QUAD/OCT) -> Octal Mode PSRAM +``` + +**编译:** + +```bash +idf.py build +``` \ No newline at end of file diff --git a/main/boards/doit-s3-aibox/config.h b/main/boards/doit-s3-aibox/config.h new file mode 100644 index 00000000..9c44200d --- /dev/null +++ b/main/boards/doit-s3-aibox/config.h @@ -0,0 +1,29 @@ +#ifndef _BOARD_CONFIG_H_ +#define _BOARD_CONFIG_H_ + +#include + +#define AUDIO_INPUT_SAMPLE_RATE 16000 +#define AUDIO_OUTPUT_SAMPLE_RATE 24000 + +#define AUDIO_I2S_MIC_GPIO_WS GPIO_NUM_41 +#define AUDIO_I2S_MIC_GPIO_SCK GPIO_NUM_40 +#define AUDIO_I2S_MIC_GPIO_DIN GPIO_NUM_42 +#define AUDIO_I2S_SPK_GPIO_DOUT GPIO_NUM_18 +#define AUDIO_I2S_SPK_GPIO_BCLK GPIO_NUM_17 +#define AUDIO_I2S_SPK_GPIO_LRCK GPIO_NUM_16 + +/* +IO9: BUTTON2 +IO10: BUTTON3 引出:KEY3 +IO15: BUTTON1 +*/ +#define BUILTIN_LED_GPIO GPIO_NUM_45 +#define BOOT_BUTTON_GPIO GPIO_NUM_10 +#define TOUCH_BUTTON_GPIO GPIO_NUM_NC +#define VOLUME_UP_BUTTON_GPIO GPIO_NUM_15 +#define VOLUME_DOWN_BUTTON_GPIO GPIO_NUM_9 +#define RESET_NVS_BUTTON_GPIO GPIO_NUM_10 +#define RESET_FACTORY_BUTTON_GPIO GPIO_NUM_NC + +#endif // _BOARD_CONFIG_H_ diff --git a/main/boards/doit-s3-aibox/config.json b/main/boards/doit-s3-aibox/config.json new file mode 100644 index 00000000..a9de834a --- /dev/null +++ b/main/boards/doit-s3-aibox/config.json @@ -0,0 +1,10 @@ +{ + "target": "esp32s3", + "builds": [ + { + "name": "doit-s3-aibox", + "sdkconfig_append": [ + ] + } + ] +} \ No newline at end of file diff --git a/main/boards/doit-s3-aibox/doit_s3_aibox.cc b/main/boards/doit-s3-aibox/doit_s3_aibox.cc new file mode 100644 index 00000000..1a75785e --- /dev/null +++ b/main/boards/doit-s3-aibox/doit_s3_aibox.cc @@ -0,0 +1,146 @@ +#include "wifi_board.h" +#include "audio_codecs/no_audio_codec.h" +#include "system_reset.h" +#include "application.h" +#include "button.h" +#include "config.h" +#include "iot/thing_manager.h" +#include "led/gpio_led.h" +#include +#include +#include +#include + +#define TAG "DoitS3AiBox" + +class DoitS3AiBox : public WifiBoard { +private: + Button boot_button_; + Button touch_button_; + Button volume_up_button_; + Button volume_down_button_; + uint8_t click_times; + uint32_t check_time; + + void InitializeButtons() { + click_times = 0; + check_time = 0; + boot_button_.OnClick([this]() { + if(click_times==0) { + check_time = esp_timer_get_time()/1000; + } + if(esp_timer_get_time()/1000-check_time<1000) { + click_times++; + check_time = esp_timer_get_time()/1000; + } else { + click_times = 0; + check_time = 0; + } + auto& app = Application::GetInstance(); + if (app.GetDeviceState() == kDeviceStateStarting && !WifiStation::GetInstance().IsConnected()) { + ResetWifiConfiguration(); + } + app.ToggleChatState(); + }); + boot_button_.OnDoubleClick([this]() { + click_times++; + ESP_LOGI(TAG, "DoubleClick times %d", click_times); + if(click_times==3) { + click_times = 0; + ResetWifiConfiguration(); + } + }); + + boot_button_.OnLongPress([this]() { + if(click_times>=3) { + ResetWifiConfiguration(); + } else { + click_times = 0; + check_time = 0; + } + }); + + touch_button_.OnPressDown([this]() { + click_times = 0; + Application::GetInstance().StartListening(); + }); + touch_button_.OnPressUp([this]() { + click_times = 0; + Application::GetInstance().StopListening(); + }); + + volume_up_button_.OnClick([this]() { + click_times = 0; + auto codec = GetAudioCodec(); + auto volume = codec->output_volume() + 10; + if (volume > 100) { + volume = 100; + } + codec->SetOutputVolume(volume); + }); + + volume_up_button_.OnLongPress([this]() { + click_times = 0; + GetAudioCodec()->SetOutputVolume(100); + }); + + volume_down_button_.OnClick([this]() { + click_times = 0; + auto codec = GetAudioCodec(); + auto volume = codec->output_volume() - 10; + if (volume < 0) { + volume = 0; + } + codec->SetOutputVolume(volume); + }); + + volume_down_button_.OnLongPress([this]() { + click_times = 0; + GetAudioCodec()->SetOutputVolume(0); + }); + } + + // 物联网初始化,添加对 AI 可见设备 + void InitializeIot() { + auto& thing_manager = iot::ThingManager::GetInstance(); + thing_manager.AddThing(iot::CreateThing("Speaker")); + } + + + void InitializeGpio(gpio_num_t gpio_num_) { + gpio_config_t config = { + .pin_bit_mask = (1ULL << gpio_num_), + .mode = GPIO_MODE_OUTPUT, + .pull_up_en = GPIO_PULLUP_ENABLE, + .pull_down_en = GPIO_PULLDOWN_DISABLE, + .intr_type = GPIO_INTR_DISABLE, + }; + ESP_ERROR_CHECK(gpio_config(&config)); + gpio_set_level(gpio_num_, 1); + } + +public: + DoitS3AiBox() : + boot_button_(BOOT_BUTTON_GPIO), + touch_button_(TOUCH_BUTTON_GPIO), + volume_up_button_(VOLUME_UP_BUTTON_GPIO), + volume_down_button_(VOLUME_DOWN_BUTTON_GPIO){ + // 上拉io48 置高电平 + InitializeGpio(GPIO_NUM_48); + InitializeButtons(); + InitializeIot(); + } + + virtual Led* GetLed() override { + static GpioLed led(BUILTIN_LED_GPIO, 1); + return &led; + } + + virtual AudioCodec* GetAudioCodec() override { + static NoAudioCodecSimplexPdm audio_codec(AUDIO_INPUT_SAMPLE_RATE, AUDIO_OUTPUT_SAMPLE_RATE, + AUDIO_I2S_SPK_GPIO_BCLK, AUDIO_I2S_SPK_GPIO_LRCK, AUDIO_I2S_SPK_GPIO_DOUT, AUDIO_I2S_MIC_GPIO_WS, AUDIO_I2S_MIC_GPIO_DIN); + return &audio_codec; + } +}; + +DECLARE_BOARD(DoitS3AiBox);