diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 489a0a35f2..82c49b56a4 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -499,6 +499,8 @@ elseif(CONFIG_BOARD_TYPE_YUNLIAO_S3) set(BUILTIN_TEXT_FONT font_puhui_basic_20_4) set(BUILTIN_ICON_FONT font_awesome_20_4) set(DEFAULT_EMOJI_COLLECTION twemoji_64) +elseif(CONFIG_BOARD_TYPE_PDI_CHATBOX_V1) + set(BOARD_TYPE "pdi-chatbox-v1") endif() file(GLOB BOARD_SOURCES diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild index 02de0938d3..6f429644c4 100644 --- a/main/Kconfig.projbuild +++ b/main/Kconfig.projbuild @@ -378,6 +378,9 @@ choice BOARD_TYPE config BOARD_TYPE_YUNLIAO_S3 bool "小智云聊-S3" depends on IDF_TARGET_ESP32S3 + config BOARD_TYPE_PDI_CHATBOX_V1 + bool "Dandefly.AIoT" + depends on IDF_TARGET_ESP32S3 endchoice choice ESP_S3_LCD_EV_Board_Version_TYPE diff --git a/main/boards/pdi-chatbox-v1/config.h b/main/boards/pdi-chatbox-v1/config.h new file mode 100644 index 0000000000..4b978e5807 --- /dev/null +++ b/main/boards/pdi-chatbox-v1/config.h @@ -0,0 +1,34 @@ +#ifndef _BOARD_CONFIG_H_ +#define _BOARD_CONFIG_H_ + +#include + +#define POWER_OFF_TIMER 60 + +#define AUDIO_INPUT_SAMPLE_RATE 24000 +#define AUDIO_OUTPUT_SAMPLE_RATE 24000 + +#define AUDIO_INPUT_REFERENCE true + +#define AUDIO_PA_CTRL GPIO_NUM_8 + +#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_38 +#define AUDIO_I2S_GPIO_WS GPIO_NUM_13 +#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_14 +#define AUDIO_I2S_GPIO_DIN GPIO_NUM_12 +#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_45 + +#define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_1 +#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_2 +#define AUDIO_CODEC_ES8311_ADDR ES8311_CODEC_DEFAULT_ADDR +#define AUDIO_CODEC_ES7210_ADDR 0x82 + +#define KEY_HOLD_GPIO GPIO_NUM_5 + +#define BAT_ADC_GPIO GPIO_NUM_9 + +#define BUILTIN_LED_GPIO GPIO_NUM_48 + +#define BOOT_BUTTON_GPIO GPIO_NUM_4 + +#endif // _BOARD_CONFIG_H_ diff --git a/main/boards/pdi-chatbox-v1/config.json b/main/boards/pdi-chatbox-v1/config.json new file mode 100644 index 0000000000..c019313161 --- /dev/null +++ b/main/boards/pdi-chatbox-v1/config.json @@ -0,0 +1,11 @@ +{ + "target": "esp32s3", + "builds": [ + { + "name": "pdi-chatbox-v1", + "sdkconfig_append": [ + "CONFIG_USE_DEVICE_AEC=y" + ] + } + ] +} diff --git a/main/boards/pdi-chatbox-v1/led_eye.cc b/main/boards/pdi-chatbox-v1/led_eye.cc new file mode 100644 index 0000000000..f5f41d65b0 --- /dev/null +++ b/main/boards/pdi-chatbox-v1/led_eye.cc @@ -0,0 +1,181 @@ +#include "Led_Eye.h" +#include "application.h" +#include + +#define TAG "LEDEYE" + +#define DEFAULT_BRIGHTNESS 32 +#define HIGH_BRIGHTNESS 64 +#define LOW_BRIGHTNESS 18 + +#define BLINK_INFINITE -1 + + +LedEye::LedEye(gpio_num_t gpio) { + assert(gpio != GPIO_NUM_NC); + led_strip_config_t strip_config = {}; + strip_config.strip_gpio_num = gpio; + strip_config.max_leds = LED_MAX_NUM; + strip_config.color_component_format = LED_STRIP_COLOR_COMPONENT_FMT_GRB; + strip_config.led_model = LED_MODEL_WS2812; + led_strip_rmt_config_t rmt_config = {}; + rmt_config.resolution_hz = 10 * 1000 * 1000; // 10MHz + + ESP_ERROR_CHECK(led_strip_new_rmt_device(&strip_config, &rmt_config, &led_strip_)); + led_strip_clear(led_strip_); + + esp_timer_create_args_t blink_timer_args = { + .callback = [](void *arg) { + auto led = static_cast(arg); + led->OnBlinkTimer(); + }, + .arg = this, + .dispatch_method = ESP_TIMER_TASK, + .name = "blink_timer", + .skip_unhandled_events = false, + }; + ESP_ERROR_CHECK(esp_timer_create(&blink_timer_args, &blink_timer_)); +} + +LedEye::~LedEye() { + esp_timer_stop(blink_timer_); + if (led_strip_ != nullptr) { + led_strip_del(led_strip_); + } +} + +void LedEye::SetSingleColor(uint8_t index,uint8_t red,uint8_t green,uint8_t blue) { + cyc_blink_flag=0; + colors[index].red=red; + colors[index].green=green; + colors[index].blue=blue; +} + +void LedEye::SetAllColor(uint8_t red,uint8_t green,uint8_t blue) { + cyc_blink_flag=0; + for(uint8_t i=0;i lock(mutex_); + esp_timer_stop(blink_timer_); + for(uint8_t i=0;i lock(mutex_); + esp_timer_stop(blink_timer_); + led_strip_clear(led_strip_); + cyc_blink_flag=0; +} + +void LedEye::BlinkOnce() { + Blink(1, 100); +} + +void LedEye::Blink(int times, int interval_ms) { + StartBlinkTask(times, interval_ms); +} + +void LedEye::StartContinuousBlink(int interval_ms) { + StartBlinkTask(BLINK_INFINITE, interval_ms); +} + +void LedEye::StartBlink(int interval_ms) { + cyc_blink_flag=1; + StartBlinkTask(BLINK_INFINITE, interval_ms); +} + +void LedEye::StartBlinkTask(int times, int interval_ms) { + if (led_strip_ == nullptr) { + return; + } + + std::lock_guard lock(mutex_); + esp_timer_stop(blink_timer_); + + blink_counter_ = times * 2; + blink_interval_ms_ = interval_ms; + esp_timer_start_periodic(blink_timer_, interval_ms * 1000); +} + +void LedEye::OnBlinkTimer() { + std::lock_guard lock(mutex_); + blink_counter_--; + if (blink_counter_ & 1) { + for(uint8_t i=0;i +#include +#include +#include +#include + +#define LED_MAX_NUM 2 + +struct Color { + uint8_t red = 0, green = 0, blue = 0; +}; + +class LedEye : public Led { +public: + LedEye(gpio_num_t gpio); + virtual ~LedEye(); + void OnStateChanged() override; + +private: + std::mutex mutex_; + TaskHandle_t blink_task_ = nullptr; + led_strip_handle_t led_strip_ = nullptr; + struct Color colors[LED_MAX_NUM]; + uint8_t cyc_blink_flag; + int blink_counter_ = 0; + int blink_interval_ms_ = 0; + esp_timer_handle_t blink_timer_ = nullptr; + + void StartBlinkTask(int times, int interval_ms); + void OnBlinkTimer(); + + void BlinkOnce(); + void Blink(int times, int interval_ms); + void StartContinuousBlink(int interval_ms); + void StartBlink(int interval_ms); + void TurnOn(); + void TurnOff(); + void SetSingleColor(uint8_t index,uint8_t red,uint8_t green,uint8_t blue); + void SetAllColor(uint8_t red,uint8_t green,uint8_t blue); +}; + +#endif // _LedEye_LED_H_ diff --git a/main/boards/pdi-chatbox-v1/pdi_chatbox_v1.cc b/main/boards/pdi-chatbox-v1/pdi_chatbox_v1.cc new file mode 100644 index 0000000000..06712df617 --- /dev/null +++ b/main/boards/pdi-chatbox-v1/pdi_chatbox_v1.cc @@ -0,0 +1,163 @@ +#include "wifi_board.h" +#include "codecs/box_audio_codec.h" +#include "application.h" +#include "button.h" +#include "config.h" +#include "i2c_device.h" +#include + +#include +#include +#include "system_info.h" +#include +#include "esp_system.h" + +#include "board.h" +#include "system_info.h" +#include "settings.h" +#include "assets/lang_config.h" +#include "mcp_server.h" +#include +#include +#include +#include +#include "esp_wifi.h" +#include "esp_event.h" +#include "application.h" +#include "driver/rtc_io.h" +#include "led_eye.h" +#include "wifi_station.h" + +#define TAG "pdi_chatbox_v1" + + +class ES7210_ES8311_AudioCodec : public BoxAudioCodec { +public: + ES7210_ES8311_AudioCodec(i2c_master_bus_handle_t i2c_bus) + : BoxAudioCodec(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_PA_CTRL, + AUDIO_CODEC_ES8311_ADDR, + AUDIO_CODEC_ES7210_ADDR, + AUDIO_INPUT_REFERENCE) { + } +}; + +class pdi_chatbox_v1 : public WifiBoard { +private: + i2c_master_bus_handle_t i2c_bus_; + Button boot_button_; + uint32_t idleCount; + esp_timer_handle_t clock_timer_handle_ = nullptr; + + static void TimerShutDown(void* arg){ + static uint32_t count; + auto &app=Application::GetInstance(); + pdi_chatbox_v1* instance = static_cast(arg); + if(app.GetDeviceState() == kDeviceStateIdle){ + count+=1; + }else{ + count=0; + } + if(count >= POWER_OFF_TIMER){ + instance->ShutDown(); + } + } + void ShutDown(){ + esp_wifi_stop(); + esp_wifi_deinit(); + auto& app = Application::GetInstance(); + app.PlaySound(Lang::Sounds::OGG_LOW_BATTERY); + vTaskDelay(pdMS_TO_TICKS(500)); + gpio_set_level(KEY_HOLD_GPIO, 0); + } + void InitShowDownTimer() { + esp_timer_create_args_t timer_args = { + .callback = &pdi_chatbox_v1::TimerShutDown, // 静态函数 + .arg = this, + .dispatch_method = ESP_TIMER_TASK, + .name = "TimerShutDown", + .skip_unhandled_events = true + }; + esp_timer_create(&timer_args, &clock_timer_handle_); + esp_timer_start_periodic(clock_timer_handle_, 1000000); // 1秒 + } + + void InitializeI2c() { + // Initialize I2C peripheral + i2c_master_bus_config_t i2c_bus_cfg = { + .i2c_port = (i2c_port_t)1, + .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, + .intr_priority = 0, + .trans_queue_depth = 0, + .flags = { + .enable_internal_pullup = 1, + }, + }; + ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &i2c_bus_)); + } + + void InitPowerGpio(){ + // 配置 GPIO + gpio_config_t io_conf; + io_conf.intr_type = GPIO_INTR_DISABLE; // 禁用中断 + io_conf.mode = GPIO_MODE_OUTPUT; // 设置为输出模式 + io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; // 禁用下拉 + io_conf.pull_up_en = GPIO_PULLUP_ENABLE; // 使能上拉 + io_conf.pin_bit_mask = (1ULL << KEY_HOLD_GPIO); // 设置输出引脚 + gpio_config(&io_conf); // 应用配置 + gpio_set_level(KEY_HOLD_GPIO, 1); //打开电源 + } + + void InitializeButtons() { + boot_button_.OnClick([this]() { + static uint8_t wifi_button_times=0; + auto& app = Application::GetInstance(); + if (app.GetDeviceState() == kDeviceStateStarting && !WifiStation::GetInstance().IsConnected()) { + wifi_button_times++; + } + if(wifi_button_times>2){ + ResetWifiConfiguration(); + } + else{ + app.ToggleChatState(); + } + }); + boot_button_.OnLongPress([this]() { + ShutDown(); + }); + } + + void InitializeTools() { + + } + +public: + pdi_chatbox_v1() : boot_button_(BOOT_BUTTON_GPIO,false,5000,50) { + InitPowerGpio(); + InitializeI2c(); + InitializeButtons(); + InitializeTools(); + InitShowDownTimer(); + } + + virtual AudioCodec* GetAudioCodec() override { + static ES7210_ES8311_AudioCodec audio_codec(i2c_bus_); + return &audio_codec; + } + + virtual Led* GetLed() override { + static LedEye led(BUILTIN_LED_GPIO); + return &led; + } +}; +DECLARE_BOARD(pdi_chatbox_v1);