Просмотр исходного кода

feat: 代码整理, 蓝牙整理

kindring 1 день назад
Родитель
Сommit
b577cdceb3
10 измененных файлов с 739 добавлено и 403 удалено
  1. 235 1
      main/app_ble.c
  2. 35 0
      main/app_ble.h
  3. 5 3
      main/app_io.c
  4. 1 1
      main/app_io.h
  5. 47 1
      main/app_manager.c
  6. 5 2
      main/app_manager.h
  7. 331 140
      main/ble_nvs.c
  8. 73 0
      main/ble_nvs.h
  9. 2 2
      main/bt_app_av.c
  10. 5 253
      main/main.c

+ 235 - 1
main/app_ble.c

@@ -2,4 +2,238 @@
 // Created by kindring on 2025/12/26.
 //
 
-#include "app_ble.h"
+
+#include "app_ble.h"
+
+#include "bt_app_av.h"
+#include "bt_app_core.h"
+#include "esp_bt.h"
+#include "esp_bt_device.h"
+#include "esp_bt_main.h"
+#include "esp_err.h"
+#include "esp_gap_bt_api.h"
+#include "esp_log.h"
+
+#define TAG "app_ble"
+
+/* event for stack up */
+enum {
+    BT_APP_EVT_STACK_UP = 0,
+};
+
+char *m_ble_name = "YunTune";
+
+/********************************
+ * STATIC FUNCTION DECLARATIONS
+ *******************************/
+
+/* Device callback function */
+static void bt_app_dev_cb(esp_bt_dev_cb_event_t event, esp_bt_dev_cb_param_t *param);
+/* GAP callback function */
+static void bt_app_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param);
+/* handler for bluetooth stack enabled events */
+static void bt_av_hdl_stack_evt(uint16_t event, void *p_param);
+
+
+
+static void bt_app_dev_cb(esp_bt_dev_cb_event_t event, esp_bt_dev_cb_param_t *param)
+{
+    switch (event) {
+    case ESP_BT_DEV_NAME_RES_EVT: {
+        if (param->name_res.status == ESP_BT_STATUS_SUCCESS) {
+            ESP_LOGI(BT_AV_TAG, "Get local device name success: %s", param->name_res.name);
+        } else {
+            ESP_LOGE(BT_AV_TAG, "Get local device name failed, status: %d", param->name_res.status);
+        }
+        break;
+    }
+    default: {
+        ESP_LOGI(BT_AV_TAG, "event: %d", event);
+        break;
+    }
+    }
+}
+
+static void bt_app_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param)
+{
+    uint8_t *bda = NULL;
+
+    switch (event) {
+    /* when authentication completed, this event comes */
+    case ESP_BT_GAP_AUTH_CMPL_EVT: {
+        if (param->auth_cmpl.stat == ESP_BT_STATUS_SUCCESS) {
+            ESP_LOGI(BT_AV_TAG, "authentication success: %s", param->auth_cmpl.device_name);
+            esp_log_buffer_hex(BT_AV_TAG, param->auth_cmpl.bda, ESP_BD_ADDR_LEN);
+        } else {
+            ESP_LOGE(BT_AV_TAG, "authentication failed, status: %d", param->auth_cmpl.stat);
+        }
+        ESP_LOGI(BT_AV_TAG, "link key type of current link is: %d", param->auth_cmpl.lk_type);
+        break;
+    }
+    case ESP_BT_GAP_ENC_CHG_EVT: {
+        char *str_enc[3] = {"OFF", "E0", "AES"};
+        bda = (uint8_t *)param->enc_chg.bda;
+        ESP_LOGI(BT_AV_TAG, "Encryption mode to [%02x:%02x:%02x:%02x:%02x:%02x] changed to %s",
+                 bda[0], bda[1], bda[2], bda[3], bda[4], bda[5], str_enc[param->enc_chg.enc_mode]);
+        break;
+    }
+
+#if (CONFIG_EXAMPLE_A2DP_SINK_SSP_ENABLED == true)
+    /* when Security Simple Pairing user confirmation requested, this event comes */
+    case ESP_BT_GAP_CFM_REQ_EVT:
+        ESP_LOGI(BT_AV_TAG, "ESP_BT_GAP_CFM_REQ_EVT Please compare the numeric value: %"PRIu32, param->cfm_req.num_val);
+        esp_bt_gap_ssp_confirm_reply(param->cfm_req.bda, true);
+        break;
+    /* when Security Simple Pairing passkey notified, this event comes */
+    case ESP_BT_GAP_KEY_NOTIF_EVT:
+        ESP_LOGI(BT_AV_TAG, "ESP_BT_GAP_KEY_NOTIF_EVT passkey: %"PRIu32, param->key_notif.passkey);
+        break;
+    /* when Security Simple Pairing passkey requested, this event comes */
+    case ESP_BT_GAP_KEY_REQ_EVT:
+        ESP_LOGI(BT_AV_TAG, "ESP_BT_GAP_KEY_REQ_EVT Please enter passkey!");
+        break;
+#endif
+
+    /* when GAP mode changed, this event comes */
+    case ESP_BT_GAP_MODE_CHG_EVT:
+        ESP_LOGI(BT_AV_TAG, "ESP_BT_GAP_MODE_CHG_EVT mode: %d", param->mode_chg.mode);
+        break;
+    /* when ACL connection completed, this event comes */
+    case ESP_BT_GAP_ACL_CONN_CMPL_STAT_EVT:
+        bda = (uint8_t *)param->acl_conn_cmpl_stat.bda;
+        ESP_LOGI(BT_AV_TAG, "ESP_BT_GAP_ACL_CONN_CMPL_STAT_EVT Connected to [%02x:%02x:%02x:%02x:%02x:%02x], status: 0x%x",
+                 bda[0], bda[1], bda[2], bda[3], bda[4], bda[5], param->acl_conn_cmpl_stat.stat);
+        break;
+    /* when ACL disconnection completed, this event comes */
+    case ESP_BT_GAP_ACL_DISCONN_CMPL_STAT_EVT:
+        bda = (uint8_t *)param->acl_disconn_cmpl_stat.bda;
+        ESP_LOGI(BT_AV_TAG, "ESP_BT_GAP_ACL_DISC_CMPL_STAT_EVT Disconnected from [%02x:%02x:%02x:%02x:%02x:%02x], reason: 0x%x",
+                 bda[0], bda[1], bda[2], bda[3], bda[4], bda[5], param->acl_disconn_cmpl_stat.reason);
+        break;
+    /* others */
+    default: {
+        ESP_LOGI(BT_AV_TAG, "event: %d", event);
+        break;
+    }
+    }
+}
+
+
+/*******************************
+ * STATIC FUNCTION DEFINITIONS
+ ******************************/
+static char *bda2str(uint8_t * bda, char *str, size_t size)
+{
+    if (bda == NULL || str == NULL || size < 18) {
+        return NULL;
+    }
+
+    uint8_t *p = bda;
+    sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x",
+            p[0], p[1], p[2], p[3], p[4], p[5]);
+    return str;
+}
+
+
+static void bt_av_hdl_stack_evt(uint16_t event, void *p_param)
+{
+    ESP_LOGD(BT_AV_TAG, "%s event: %d", __func__, event);
+
+    switch (event) {
+        /* when do the stack up, this event comes */
+        case BT_APP_EVT_STACK_UP: {
+            esp_bt_gap_set_device_name(m_ble_name);
+            esp_bt_dev_register_callback(bt_app_dev_cb);
+            esp_bt_gap_register_callback(bt_app_gap_cb);
+
+            assert(esp_avrc_ct_init() == ESP_OK);
+            esp_avrc_ct_register_callback(bt_app_rc_ct_cb);
+            assert(esp_avrc_tg_init() == ESP_OK);
+            esp_avrc_tg_register_callback(bt_app_rc_tg_cb);
+
+            esp_avrc_rn_evt_cap_mask_t evt_set = {0};
+            esp_avrc_rn_evt_bit_mask_operation(ESP_AVRC_BIT_MASK_OP_SET, &evt_set, ESP_AVRC_RN_VOLUME_CHANGE);
+            assert(esp_avrc_tg_set_rn_evt_cap(&evt_set) == ESP_OK);
+
+            assert(esp_a2d_sink_init() == ESP_OK);
+            esp_a2d_register_callback(&bt_app_a2d_cb);
+            esp_a2d_sink_register_data_callback(bt_app_a2d_data_cb);
+
+            /* Get the default value of the delay value */
+            esp_a2d_sink_get_delay_value();
+            /* Get local device name */
+            esp_bt_gap_get_device_name();
+
+            /* set discoverable and connectable mode, wait to be connected */
+            esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
+            break;
+        }
+            /* others */
+        default:
+            ESP_LOGE(BT_AV_TAG, "%s unhandled event: %d", __func__, event);
+            break;
+    }
+}
+
+// 初始化蓝牙 模块
+esp_err_t init_ble(char *name) {
+    char bda_str[18] = {0};
+    esp_err_t  err = ESP_OK;
+
+
+    m_ble_name = name;
+
+    ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_BLE));
+
+    esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
+    err = esp_bt_controller_init(&bt_cfg);
+    if (err != ESP_OK) {
+        ESP_LOGE(TAG, "%s initialize controller failed: %s", __func__, esp_err_to_name(err));
+        return err;
+    }
+    err = esp_bt_controller_enable(ESP_BT_MODE_CLASSIC_BT);
+    if (err != ESP_OK) {
+        ESP_LOGE(TAG, "%s enable controller failed: %s", __func__, esp_err_to_name(err));
+        return err;
+    }
+
+    esp_bluedroid_config_t bluedroid_cfg = BT_BLUEDROID_INIT_CONFIG_DEFAULT();
+
+#if (CONFIG_EXAMPLE_A2DP_SINK_SSP_ENABLED == false)
+    bluedroid_cfg.ssp_en = false;
+#endif
+
+    if ((err = esp_bluedroid_init_with_cfg(&bluedroid_cfg)) != ESP_OK) {
+        ESP_LOGE(TAG, "%s initialize bluedroid failed: %s", __func__, esp_err_to_name(err));
+        return err;
+    }
+
+    if ((err = esp_bluedroid_enable()) != ESP_OK) {
+        ESP_LOGE(TAG, "%s enable bluedroid failed: %s", __func__, esp_err_to_name(err));
+        return err;
+    }
+
+#if (CONFIG_EXAMPLE_A2DP_SINK_SSP_ENABLED == true)
+    /* set default parameters for Secure Simple Pairing */
+    esp_bt_sp_param_t param_type = ESP_BT_SP_IOCAP_MODE;
+    esp_bt_io_cap_t iocap = ESP_BT_IO_CAP_IO;
+    esp_bt_gap_set_security_param(param_type, &iocap, sizeof(uint8_t));
+#endif
+
+    /* set default parameters for Legacy Pairing (use fixed pin code 1234) */
+    esp_bt_pin_type_t pin_type = ESP_BT_PIN_TYPE_FIXED;
+    esp_bt_pin_code_t pin_code;
+    pin_code[0] = '1';
+    pin_code[1] = '2';
+    pin_code[2] = '3';
+    pin_code[3] = '4';
+    esp_bt_gap_set_pin(pin_type, 4, pin_code);
+    ESP_LOGI(TAG, "Own address:[%s]", bda2str((uint8_t *)esp_bt_dev_get_address(), bda_str, sizeof(bda_str)));
+    bt_app_task_start_up();
+
+    /* bluetooth device name, connection mode and profile set up */
+    bt_app_work_dispatch(bt_av_hdl_stack_evt, BT_APP_EVT_STACK_UP, NULL, 0, NULL);
+
+    return err;
+}
+

+ 35 - 0
main/app_ble.h

@@ -4,5 +4,40 @@
 
 #ifndef YUNTUNE_APP_BLE_H
 #define YUNTUNE_APP_BLE_H
+#include "esp_err.h"
+
+/**
+ * @brief 设置蓝牙设备名称
+ * @param name 新的蓝牙设备名称
+ * @return 成功返回ESP_OK,失败返回错误代码
+ */
+esp_err_t set_ble_name(const char *name);
+
+/**
+ * @brief 获取当前蓝牙设备名称
+ * @return 当前蓝牙设备名称
+ */
+const char* get_ble_name(void);
+
+/**
+ * @brief 关闭蓝牙
+ * @return 成功返回ESP_OK,失败返回错误代码
+ */
+esp_err_t deinit_ble(void);
+
+/**
+ * @brief 设置蓝牙为可发现模式
+ * @return 成功返回ESP_OK,失败返回错误代码
+ */
+esp_err_t set_ble_discoverable(void);
+
+/**
+ * @brief 设置蓝牙为不可发现模式
+ * @return 成功返回ESP_OK,失败返回错误代码
+ */
+esp_err_t set_ble_non_discoverable(void);
+
+
+esp_err_t init_ble(char *name);
 
 #endif //YUNTUNE_APP_BLE_H

+ 5 - 3
main/app_io.c

@@ -105,10 +105,10 @@ esp_err_t update_output_mode(const audio_mode_t mode)
     esp_err_t err = ESP_OK;
     // 根据音频模式设置GPIO19输出状态
     switch(mode) {
-        case AUDIO_MODE_NORMAL:
+        case AUDIO_MODE_AUX:
             err = gpio_set_level(IO_OUTPUT_SW, 0); // 低电平
             break;
-        case AUDIO_MODE_BASS_BOOST:
+        case AUDIO_MODE_BLE:
             err = gpio_set_level(IO_OUTPUT_SW, 1); // 高电平
             break;
         default:
@@ -171,7 +171,7 @@ esp_err_t init_amp_io() {
 
 
 // 初始化io引脚配置
-int init_io() {
+int init_io(audio_mode_t audio_mode) {
     // 安装GPIO ISR服务
     esp_err_t err = gpio_install_isr_service(0);
     g_io_evt_queue = xQueueCreate(10, sizeof(uint32_t));
@@ -182,5 +182,7 @@ int init_io() {
     init_led_io();
     init_btn_io();
 
+    update_output_mode(audio_mode);
+
     return 0;
 }

+ 1 - 1
main/app_io.h

@@ -20,6 +20,6 @@
 esp_err_t set_led_io(const bool on);
 esp_err_t enable_amp(const bool on);
 esp_err_t update_output_mode(audio_mode_t  mode);
-int init_io();
+int init_io(audio_mode_t mode);
 
 #endif //YUNTUNE_APP_IO_H

+ 47 - 1
main/app_manager.c

@@ -8,16 +8,32 @@
 #include "app_io.h"
 #include "app_manager.h"
 
+#include "app_ble.h"
+#include "ble_nvs.h"
+
 
 #define TAG "app_manager"
 
-audio_mode_t m_current_audio_mode = AUDIO_MODE_NORMAL;
+audio_mode_t m_current_audio_mode = AUDIO_MODE_AUX;
 
 const char* mode_names[] = {
     "NORMAL",
     "BASS_BOOST",
 };
 
+device_config_t  g_device_config = {
+    .device_name = "YunTune",
+    .auto_reconnect = true,
+    .audio_mode =  AUDIO_MODE_AUX,
+    .wifi_mode = WIFI_MODE_AP,
+    .reconnect_wait_time = 2,
+    .reconnect_max_attempts = 10,
+    .wifi_ssid = '\0',
+    .wifi_password = '\0',
+    .ap_ssid = "YunTune",
+    .ap_password = "YunTune",
+};
+
 // 切换为下一个播放模式
 audio_mode_t next_audio_mode()
 {
@@ -29,4 +45,34 @@ audio_mode_t next_audio_mode()
     return next_audio_mode;
 }
 
+// 保存连接的蓝牙信息
+esp_err_t  save_bt_info(uint8_t *bda,  char *device_name)
+{
+
+}
+
+
+esp_err_t init_app()
+{
+    esp_err_t  err = ESP_OK;
+    err = ble_nvs_init(&g_device_config);
+    if  (err != ESP_OK) {
+        ESP_LOGE(TAG, "Failed to initialize NVS");
+        return err;
+    }
+    init_io(g_device_config.audio_mode);
+
+    // 初始化蓝牙
+    init_ble(g_device_config.device_name);
+
+    // 根据逻辑调整蓝牙的运行模式
+    if (g_device_config.audio_mode ==  AUDIO_MODE_BLE)
+    {
+        // todo 重连 蓝牙设备
+
+    }
+
+    return ESP_OK;
+}
+
 

+ 5 - 2
main/app_manager.h

@@ -9,13 +9,16 @@
  * 功放工作模式, 切换aux与蓝牙模式
  */
 typedef enum {
-    AUDIO_MODE_NORMAL = 0,
-    AUDIO_MODE_BASS_BOOST,
+    AUDIO_MODE_AUX = 0,
+    AUDIO_MODE_BLE,
     AUDIO_MODE_MAX
 } audio_mode_t;
 
+
+
 audio_mode_t next_audio_mode();
 
+esp_err_t init_app();
 
 
 #endif //YUNTUNE_APP_MANAGER_H

+ 331 - 140
main/ble_nvs.c

@@ -4,216 +4,407 @@
 
 #include "ble_nvs.h"
 
+#include <string.h>
+
 #include "esp_err.h"
 #include "esp_log.h"
 #include "nvs_flash.h"
 
 static const char *TAG = "BLE_NVS";
 
-#define NVS_STORAGE_NAMESPACE "bt_device"
-#define NVS_KEY_BT_ADDR "last_addr"
-#define NVS_KEY_BT_NAME "last_name"
-#define NVS_KEY_IS_PAIRED "is_paired"
-#define NVS_KEY_CONNECT_COUNT "connect_count"
-#define NVS_KEY_LAST_CONNECT_TIME "last_connect_time"
-#define NVS_KEY_AUTO_RECONNECT "auto_reconnect"
 
-static bool s_auto_reconnect = true;
-static bool s_reconnect_active = false;
 
-esp_err_t ble_nvs_init()
+esp_err_t bt_device_load_config(device_config_t *device_config)
 {
-    esp_err_t ret = nvs_flash_init();
+    if (device_config == NULL) {
+        ESP_LOGE(TAG, "device_config is NULL");
+        return ESP_ERR_INVALID_ARG;
+    }
+    nvs_handle_t nvs_handle;
+    esp_err_t err = nvs_open(NVS_NAMESPACE, NVS_READONLY, &nvs_handle);
+    if (err != ESP_OK) {
+        ESP_LOGE(TAG, "Error opening NVS handle: %s", esp_err_to_name(err));
+        return err;
+    }
+    size_t len = sizeof(device_config->device_name);
+    err = nvs_get_str(nvs_handle, DEVICE_NAME_KEY, device_config->device_name, &len);
+    if (err != ESP_OK) {
+        ESP_LOGW(TAG, "Failed to read device name, using default: %s", esp_err_to_name(err));
+        strncpy(device_config->device_name, DEFAULT_DEVICE_NAME, sizeof(device_config->device_name) - 1);
+        device_config->device_name[sizeof(device_config->device_name) - 1] = '\0';
+    }
+    // 读取自动重连设置
+    int8_t auto_reconnect;
+    err = nvs_get_i8(nvs_handle, AUTO_RECONNECT_KEY, &auto_reconnect);
+    if (err == ESP_OK) {
+        device_config->auto_reconnect = (bool)auto_reconnect;
+    } else {
+        ESP_LOGW(TAG, "Failed to read auto_reconnect, using default: %s", esp_err_to_name(err));
+        device_config->auto_reconnect = true; // 默认开启自动重连
+    }
+    // 读取音频模式
+    int8_t audio_mode;
+    err = nvs_get_i8(nvs_handle, AUDIO_MODE_KEY, &audio_mode);
+    if (err == ESP_OK && audio_mode >= 0 && audio_mode < AUDIO_MODE_MAX) {
+        device_config->audio_mode = (audio_mode_t)audio_mode;
+    } else {
+        ESP_LOGW(TAG, "Failed to read audio_mode, using default: %s", esp_err_to_name(err));
+        device_config->audio_mode = AUDIO_MODE_AUX; // 默认为aux模式
+    }
 
-    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
-        ESP_LOGW(TAG, "NVS partition needs to be erased");
-        ESP_ERROR_CHECK(nvs_flash_erase());
-        ret = nvs_flash_init();
+
+    // 读取WiFi模式
+    int8_t wifi_mode;
+    err = nvs_get_i8(nvs_handle, WIFI_MODE_KEY, &wifi_mode);
+    if (err == ESP_OK && wifi_mode >= 0 && wifi_mode < WIFI_MODE_MAX) {
+        device_config->wifi_mode = (wifi_mode_t)wifi_mode;
+    } else {
+        ESP_LOGW(TAG, "Failed to read wifi_mode, using default: %s", esp_err_to_name(err));
+        device_config->wifi_mode = WIFI_MODE_STA; // 默认为STA模式
+    }
+    // 读取WiFi SSID
+    len = sizeof(device_config->wifi_ssid);
+    err = nvs_get_str(nvs_handle, WIFI_SSID_KEY, device_config->wifi_ssid, &len);
+    if (err != ESP_OK) {
+        ESP_LOGW(TAG, "Failed to read wifi_ssid, using default: %s", esp_err_to_name(err));
+        device_config->wifi_ssid[0] = '\0';
+    }
+    // 读取WiFi密码
+    len = sizeof(device_config->wifi_password);
+    err = nvs_get_str(nvs_handle, WIFI_PASSWORD_KEY, device_config->wifi_password, &len);
+    if (err != ESP_OK) {
+        ESP_LOGW(TAG, "Failed to read wifi_password, using default: %s", esp_err_to_name(err));
+        device_config->wifi_password[0] = '\0';
+    }
+    // 读取AP SSID
+    len = sizeof(device_config->ap_ssid);
+    err = nvs_get_str(nvs_handle, AP_SSID_KEY, device_config->ap_ssid, &len);
+    if (err != ESP_OK) {
+        ESP_LOGW(TAG, "Failed to read ap_ssid, using default: %s", esp_err_to_name(err));
+        strncpy(device_config->ap_ssid, DEFAULT_DEVICE_NAME, sizeof(device_config->ap_ssid) - 1);
+        device_config->ap_ssid[sizeof(device_config->ap_ssid) - 1] = '\0';
     }
 
-    if (ret != ESP_OK) {
-        ESP_LOGE(TAG, "Failed to initialize NVS: %s", esp_err_to_name(ret));
-        return ret;
+    // 读取AP密码
+    len = sizeof(device_config->ap_password);
+    err = nvs_get_str(nvs_handle, AP_PASSWORD_KEY, device_config->ap_password, &len);
+    if (err != ESP_OK) {
+        ESP_LOGW(TAG, "Failed to read ap_password, using default: %s", esp_err_to_name(err));
+        device_config->ap_password[0] = '\0';
     }
 
-    ESP_LOGI(TAG, "Bluetooth Device Manager initialized");
+    nvs_close(nvs_handle);
+    ESP_LOGI(TAG, "Device configuration loaded successfully");
     return ESP_OK;
 }
 
-esp_err_t bt_device_save_info(const bt_device_info_t *device_info)
+esp_err_t bt_device_save_config(const device_config_t *device_config)
 {
-    if (!device_info) {
+    if (device_config == NULL) {
+        ESP_LOGE(TAG, "device_config is NULL");
         return ESP_ERR_INVALID_ARG;
     }
 
-    nvs_handle_t handle;
-    esp_err_t ret;
+    nvs_handle_t nvs_handle;
+    esp_err_t err = nvs_open(NVS_NAMESPACE, NVS_READWRITE, &nvs_handle);
+    if (err != ESP_OK) {
+        ESP_LOGE(TAG, "Error opening NVS handle: %s", esp_err_to_name(err));
+        return err;
+    }
 
-    ret = nvs_open(NVS_STORAGE_NAMESPACE, NVS_READWRITE, &handle);
-    if (ret != ESP_OK) {
-        ESP_LOGE(TAG, "Error opening NVS handle: %s", esp_err_to_name(ret));
-        return ret;
+    // 保存设备名称
+    err = nvs_set_str(nvs_handle, DEVICE_NAME_KEY, device_config->device_name);
+    if (err != ESP_OK) {
+        ESP_LOGE(TAG, "Failed to save device name: %s", esp_err_to_name(err));
+        goto cleanup;
     }
 
-    // 保存蓝牙设备地址
-    ret = nvs_set_blob(handle, NVS_KEY_BT_ADDR, device_info->bda, 6);
-    if (ret != ESP_OK)
-    {
-        ESP_LOGE(TAG, "Failed to save Bluetooth address: %s", esp_err_to_name(ret));
-        nvs_close(handle);
-        return ret;
+    // 保存自动重连设置
+    int8_t auto_reconnect = (int8_t)device_config->auto_reconnect;
+    err = nvs_set_i8(nvs_handle, AUTO_RECONNECT_KEY, auto_reconnect);
+    if (err != ESP_OK) {
+        ESP_LOGE(TAG, "Failed to save auto_reconnect: %s", esp_err_to_name(err));
+        goto cleanup;
     }
 
-    // 保存设备名称
-    ret = nvs_set_str(handle, NVS_KEY_BT_NAME, device_info->device_name);
-    if (ret != ESP_OK) {
-        ESP_LOGE(TAG, "Failed to save device name: %s", esp_err_to_name(ret));
-        nvs_close(handle);
-        return ret;
+    // 保存音频模式模式
+    int8_t audio_mode = (int8_t)device_config->audio_mode;
+    err = nvs_set_i8(nvs_handle, AUDIO_MODE_KEY, audio_mode);
+    if (err != ESP_OK) {
+        ESP_LOGE(TAG, "Failed to save audio_mode: %s", esp_err_to_name(err));
+        goto cleanup;
     }
 
-    // 保存配对状态
-    ret = nvs_set_u8(handle, NVS_KEY_IS_PAIRED, device_info->is_paired ? 1 : 0);
-    if (ret != ESP_OK) {
-        ESP_LOGE(TAG, "Failed to save pairing status: %s", esp_err_to_name(ret));
-        nvs_close(handle);
-        return ret;
+    // 保存WiFi模式
+    int8_t wifi_mode = (int8_t)device_config->wifi_mode;
+    err = nvs_set_i8(nvs_handle, WIFI_MODE_KEY, wifi_mode);
+    if (err != ESP_OK) {
+        ESP_LOGE(TAG, "Failed to save wifi_mode: %s", esp_err_to_name(err));
+        goto cleanup;
     }
 
-    // 保存连接次数
-    ret = nvs_set_u32(handle, NVS_KEY_CONNECT_COUNT, device_info->connect_count);
-    if (ret != ESP_OK) {
-        ESP_LOGE(TAG, "Failed to save connect count: %s", esp_err_to_name(ret));
-        nvs_close(handle);
-        return ret;
+    // 保存WiFi SSID
+    err = nvs_set_str(nvs_handle, WIFI_SSID_KEY, device_config->wifi_ssid);
+    if (err != ESP_OK) {
+        ESP_LOGE(TAG, "Failed to save wifi_ssid: %s", esp_err_to_name(err));
+        goto cleanup;
     }
 
-    // 保存最后连接时间
-    ret = nvs_set_u64(handle, NVS_KEY_LAST_CONNECT_TIME, device_info->last_connect_time);
-    if (ret != ESP_OK) {
-        ESP_LOGE(TAG, "Failed to save last connect time: %s", esp_err_to_name(ret));
-        nvs_close(handle);
-        return ret;
+    // 保存WiFi密码
+    err = nvs_set_str(nvs_handle, WIFI_PASSWORD_KEY, device_config->wifi_password);
+    if (err != ESP_OK) {
+        ESP_LOGE(TAG, "Failed to save wifi_password: %s", esp_err_to_name(err));
+        goto cleanup;
     }
 
-    // 提交更改
-    ret = nvs_commit(handle);
-    if (ret != ESP_OK) {
-        ESP_LOGE(TAG, "Failed to commit NVS changes: %s", esp_err_to_name(ret));
+    // 保存AP SSID
+    err = nvs_set_str(nvs_handle, AP_SSID_KEY, device_config->ap_ssid);
+    if (err != ESP_OK) {
+        ESP_LOGE(TAG, "Failed to save ap_ssid: %s", esp_err_to_name(err));
+        goto cleanup;
     }
 
-    nvs_close(handle);
+    // 保存AP密码
+    err = nvs_set_str(nvs_handle, AP_PASSWORD_KEY, device_config->ap_password);
+    if (err != ESP_OK) {
+        ESP_LOGE(TAG, "Failed to save ap_password: %s", esp_err_to_name(err));
+        goto cleanup;
+    }
+
+    err = nvs_commit(nvs_handle);
+    if (err != ESP_OK) {
+        ESP_LOGE(TAG, "Failed to commit changes: %s", esp_err_to_name(err));
+    } else {
+        ESP_LOGI(TAG, "Device configuration saved successfully");
+    }
 
-    ESP_LOGI(TAG, "Bluetooth device info saved successfully");
-    return ret;
+cleanup:
+    nvs_close(nvs_handle);
+    return err;
 }
 
-esp_err_t bt_device_load_info(bt_device_info_t *device_info)
+esp_err_t bt_device_load_bt_info(bt_device_info_t *bt_info)
 {
-    if (!device_info) {
+    if (bt_info == NULL) {
+        ESP_LOGE(TAG, "bt_info is NULL");
         return ESP_ERR_INVALID_ARG;
     }
 
-    nvs_handle_t handle;
-    esp_err_t ret;
+    nvs_handle_t nvs_handle;
+    esp_err_t err = nvs_open(NVS_NAMESPACE, NVS_READONLY, &nvs_handle);
+    if (err != ESP_OK) {
+        ESP_LOGE(TAG, "Error opening NVS handle: %s", esp_err_to_name(err));
+        return err;
+    }
 
-    ret = nvs_open(NVS_STORAGE_NAMESPACE, NVS_READONLY, &handle);
-    if (ret != ESP_OK) {
-        ESP_LOGE(TAG, "Error opening NVS handle: %s", esp_err_to_name(ret));
-        return ret;
+    // 读取蓝牙设备列表
+    size_t required_size = 0;
+    err = nvs_get_blob(nvs_handle, BT_DEVICE_LIST_KEY, NULL, &required_size);
+    if (err == ESP_OK && required_size == sizeof(bt_device_list_t)) {
+        bt_device_list_t device_list;
+        err = nvs_get_blob(nvs_handle, BT_DEVICE_LIST_KEY, &device_list, &required_size);
+        if (err != ESP_OK) {
+            ESP_LOGE(TAG, "Failed to read bluetooth device list: %s", esp_err_to_name(err));
+        } else {
+            // 将第一个有效设备信息复制到输出参数
+            for (int i = 0; i < MAX_BT_DEVICES; i++) {
+                if (device_list.devices[i].is_valid) {
+                    memcpy(bt_info, &device_list.devices[i], sizeof(bt_device_info_t));
+                    ESP_LOGI(TAG, "Bluetooth device info loaded successfully");
+                    break;
+                }
+            }
+        }
+    } else if (err == ESP_ERR_NVS_NOT_FOUND) {
+        // 如果没有找到蓝牙设备信息,则初始化为默认值
+        memset(bt_info, 0, sizeof(bt_device_info_t));
+        strncpy(bt_info->device_name, DEFAULT_DEVICE_NAME, sizeof(bt_info->device_name) - 1);
+        bt_info->device_name[sizeof(bt_info->device_name) - 1] = '\0';
+        ESP_LOGI(TAG, "Bluetooth device info not found, using default values");
+        err = ESP_OK;
+    } else {
+        ESP_LOGE(TAG, "Error getting size for bluetooth device list: %s", esp_err_to_name(err));
     }
 
-    // 读取蓝牙设备地址
-    size_t addr_len = 6;
-    ret = nvs_get_blob(handle, NVS_KEY_BT_ADDR, device_info->bda, &addr_len);
-    if (ret != ESP_OK) {
-        ESP_LOGE(TAG, "Failed to load Bluetooth address: %s", esp_err_to_name(ret));
-        nvs_close(handle);
-        return ret;
+    nvs_close(nvs_handle);
+    return err;
+}
+
+esp_err_t bt_device_get_list(bt_device_list_t *device_list)
+{
+    if (device_list == NULL) {
+        ESP_LOGE(TAG, "device_list is NULL");
+        return ESP_ERR_INVALID_ARG;
     }
 
-    // 读取设备名称
-    size_t name_len = sizeof(device_info->device_name);
-    ret = nvs_get_str(handle, NVS_KEY_BT_NAME, device_info->device_name, &name_len);
-    if (ret != ESP_OK) {
-        ESP_LOGE(TAG, "Failed to load device name: %s", esp_err_to_name(ret));
-        nvs_close(handle);
-        return ret;
+    nvs_handle_t nvs_handle;
+    esp_err_t err = nvs_open(NVS_NAMESPACE, NVS_READONLY, &nvs_handle);
+    if (err != ESP_OK) {
+        ESP_LOGE(TAG, "Error opening NVS handle: %s", esp_err_to_name(err));
+        return err;
     }
 
-    // 读取配对状态
-    uint8_t is_paired;
-    ret = nvs_get_u8(handle, NVS_KEY_IS_PAIRED, &is_paired);
-    if (ret == ESP_OK) {
-        device_info->is_paired = (is_paired != 0);
+    // 读取蓝牙设备列表
+    size_t required_size = 0;
+    err = nvs_get_blob(nvs_handle, BT_DEVICE_LIST_KEY, NULL, &required_size);
+    if (err == ESP_OK && required_size == sizeof(bt_device_list_t)) {
+        err = nvs_get_blob(nvs_handle, BT_DEVICE_LIST_KEY, device_list, &required_size);
+        if (err != ESP_OK) {
+            ESP_LOGE(TAG, "Failed to read bluetooth device list: %s", esp_err_to_name(err));
+        } else {
+            ESP_LOGI(TAG, "Bluetooth device list loaded successfully");
+        }
+    } else if (err == ESP_ERR_NVS_NOT_FOUND) {
+        // 如果没有找到蓝牙设备列表,则初始化为默认值
+        memset(device_list, 0, sizeof(bt_device_list_t));
+        ESP_LOGI(TAG, "Bluetooth device list not found, using default values");
+        err = ESP_OK;
     } else {
-        device_info->is_paired = false;
+        ESP_LOGE(TAG, "Error getting size for bluetooth device list: %s", esp_err_to_name(err));
     }
 
-    // 读取连接次数
-    ret = nvs_get_u32(handle, NVS_KEY_CONNECT_COUNT, &device_info->connect_count);
-    if (ret != ESP_OK) {
-        device_info->connect_count = 0;
+    nvs_close(nvs_handle);
+    return err;
+}
+
+esp_err_t bt_device_add_or_update(const bt_device_info_t *bt_info)
+{
+    if (bt_info == NULL) {
+        ESP_LOGE(TAG, "[bt_info] is NULL");
+        return ESP_ERR_INVALID_ARG;
     }
 
-    // 读取最后连接时间
-    ret = nvs_get_u64(handle, NVS_KEY_LAST_CONNECT_TIME, &device_info->last_connect_time);
-    if (ret != ESP_OK) {
-        device_info->last_connect_time = 0;
+    nvs_handle_t nvs_handle;
+    esp_err_t err = nvs_open(NVS_NAMESPACE, NVS_READWRITE, &nvs_handle);
+    if (err != ESP_OK) {
+        ESP_LOGE(TAG, "Error opening NVS handle: %s", esp_err_to_name(err));
+        return err;
     }
 
-    nvs_close(handle);
+    // 读取现有蓝牙设备列表
+    bt_device_list_t device_list;
+    size_t required_size = 0;
+    err = nvs_get_blob(nvs_handle, BT_DEVICE_LIST_KEY, NULL, &required_size);
+    if (err == ESP_OK && required_size == sizeof(bt_device_list_t)) {
+        err = nvs_get_blob(nvs_handle, BT_DEVICE_LIST_KEY, &device_list, &required_size);
+        if (err != ESP_OK) {
+            ESP_LOGE(TAG, "Failed to read existing bluetooth device list: %s", esp_err_to_name(err));
+            // 初始化为空列表
+            memset(&device_list, 0, sizeof(bt_device_list_t));
+        }
+    } else if (err == ESP_ERR_NVS_NOT_FOUND) {
+        // 如果没有找到现有列表,初始化为空列表
+        memset(&device_list, 0, sizeof(bt_device_list_t));
+    } else {
+        ESP_LOGE(TAG, "Error getting size for bluetooth device list: %s", esp_err_to_name(err));
+        nvs_close(nvs_handle);
+        return err;
+    }
 
-    ESP_LOGI(TAG, "Bluetooth device info loaded successfully");
-    return ESP_OK;
-}
+    // 检查是否已存在相同BDA的设备
+    bool found_existing = false;
+    for (int i = 0; i < MAX_BT_DEVICES; i++) {
+        if (device_list.devices[i].is_valid &&
+            memcmp(device_list.devices[i].bda, bt_info->bda, 6) == 0) {
+            // 更新现有设备信息
+            memcpy(&device_list.devices[i], bt_info, sizeof(bt_device_info_t));
+            device_list.devices[i].is_valid = true;
+            found_existing = true;
+            ESP_LOGI(TAG, "Updated existing bluetooth device with BDA");
+            break;
+        }
+    }
 
-esp_err_t bt_device_clear_info(void)
-{
-    nvs_handle_t handle;
-    esp_err_t ret;
+    if (!found_existing) {
+        // 寻找空闲位置
+        int empty_slot = -1;
+        for (int i = 0; i < MAX_BT_DEVICES; i++) {
+            if (!device_list.devices[i].is_valid) {
+                empty_slot = i;
+                break;
+            }
+        }
 
-    ret = nvs_open(NVS_STORAGE_NAMESPACE, NVS_READWRITE, &handle);
-    if (ret != ESP_OK) {
-        ESP_LOGE(TAG, "Error opening NVS handle: %s", esp_err_to_name(ret));
-        return ret;
+        if (empty_slot != -1) {
+            // 在空闲位置添加新设备
+            memcpy(&device_list.devices[empty_slot], bt_info, sizeof(bt_device_info_t));
+            device_list.devices[empty_slot].is_valid = true;
+            ESP_LOGI(TAG, "Added new bluetooth device at slot %d", empty_slot);
+        } else {
+            // 超过最大设备数,需要覆盖最久未连接的设备
+            int oldest_idx = -1;
+            uint64_t oldest_time = UINT64_MAX;
+
+            for (int i = 0; i < MAX_BT_DEVICES; i++) {
+                if (device_list.devices[i].last_connect_time < oldest_time) {
+                    oldest_time = device_list.devices[i].last_connect_time;
+                    oldest_idx = i;
+                }
+            }
+
+            if (oldest_idx != -1) {
+                memcpy(&device_list.devices[oldest_idx], bt_info, sizeof(bt_device_info_t));
+                device_list.devices[oldest_idx].is_valid = true;
+                ESP_LOGI(TAG, "Replaced oldest bluetooth device at slot %d", oldest_idx);
+            }
+        }
     }
 
-    // 清除所有键值
-    nvs_erase_all(handle);
-    ret = nvs_commit(handle);
-    nvs_close(handle);
+    // 保存更新后的设备列表
+    err = nvs_set_blob(nvs_handle, BT_DEVICE_LIST_KEY, &device_list, sizeof(bt_device_list_t));
+    if (err != ESP_OK) {
+        ESP_LOGE(TAG, "Failed to save bluetooth device list: %s", esp_err_to_name(err));
+        nvs_close(nvs_handle);
+        return err;
+    }
 
-    ESP_LOGI(TAG, "Bluetooth device info cleared");
-    return ret;
+    err = nvs_commit(nvs_handle);
+    if (err != ESP_OK) {
+        ESP_LOGE(TAG, "Failed to commit bluetooth device list: %s", esp_err_to_name(err));
+    } else {
+        ESP_LOGI(TAG, "Bluetooth device list saved successfully");
+    }
+
+    nvs_close(nvs_handle);
+    return err;
 }
 
-void bt_device_set_auto_reconnect(bool enable)
+esp_err_t bt_device_reset_config(void)
 {
-    s_auto_reconnect = enable;
+    nvs_handle_t nvs_handle;
+    esp_err_t err = nvs_open(NVS_NAMESPACE, NVS_READWRITE, &nvs_handle);
+    if (err != ESP_OK) {
+        ESP_LOGE(TAG, "Error opening NVS handle: %s", esp_err_to_name(err));
+        return err;
+    }
 
-    nvs_handle_t handle;
-    if (nvs_open(NVS_STORAGE_NAMESPACE, NVS_READWRITE, &handle) == ESP_OK) {
-        nvs_set_u8(handle, NVS_KEY_AUTO_RECONNECT, enable ? 1 : 0);
-        nvs_commit(handle);
-        nvs_close(handle);
+    err = nvs_erase_all(nvs_handle);
+    if (err != ESP_OK) {
+        ESP_LOGE(TAG, "Failed to erase all config: %s", esp_err_to_name(err));
+    } else {
+        ESP_LOGI(TAG, "All configuration erased successfully");
     }
+
+    nvs_close(nvs_handle);
+    return err;
 }
 
-bool bt_device_get_auto_reconnect(void)
-{
-    uint8_t auto_reconnect;
-    nvs_handle_t handle;
-    esp_err_t ret;
-
-    ret = nvs_open(NVS_STORAGE_NAMESPACE, NVS_READONLY, &handle);
-    if (ret == ESP_OK) {
-        ret = nvs_get_u8(handle, NVS_KEY_AUTO_RECONNECT, &auto_reconnect);
-        nvs_close(handle);
-        if (ret == ESP_OK) {
-            s_auto_reconnect = (auto_reconnect != 0);
+// 初始化nv参数
+esp_err_t ble_nvs_init(device_config_t *device_config) {
+    esp_err_t err = nvs_flash_init();
+    if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
+        ESP_ERROR_CHECK(nvs_flash_erase());
+        err = nvs_flash_init();
+    }
+    ESP_ERROR_CHECK(err);
+    // 如果传入了device_config,加载配置
+    if (device_config != NULL) {
+        err = bt_device_load_config(device_config);
+        if (err != ESP_OK) {
+            ESP_LOGE(TAG, "Failed to load device config: %s", esp_err_to_name(err));
+            // 即使加载失败,也返回ESP_OK,因为NVS已初始化
         }
     }
-
-    return s_auto_reconnect;
+    ESP_LOGI(TAG, "BLE NVS initialized successfully");
+    return ESP_OK;
 }

+ 73 - 0
main/ble_nvs.h

@@ -5,8 +5,47 @@
 #ifndef YUNTUNE_BLE_NVS_H
 #define YUNTUNE_BLE_NVS_H
 
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "esp_err.h"
+
+#include "app_manager.h"
+
+
 #define BT_DEVICE_NAME_MAX_LEN 64
 #define MAX_RECONNECT_ATTEMPTS 3
+#define MAX_BT_DEVICES 3  // 最多保存3个蓝牙设备信息
+
+#define NVS_NAMESPACE "ble_config"
+#define DEFAULT_DEVICE_NAME "YunTune"
+
+#define DEVICE_NAME_KEY "dev_name"
+#define AUTO_RECONNECT_KEY "auto_reconn"
+#define AUDIO_MODE_KEY "audio_mode"
+#define WIFI_MODE_KEY "wifi_mode"
+#define WIFI_SSID_KEY "wifi_ssid"
+#define WIFI_PASSWORD_KEY "wifi_pass"
+#define AP_SSID_KEY "ap_ssid"
+#define AP_PASSWORD_KEY "ap_pass"
+
+// 蓝牙设备信息键名定义
+#define BT_DEVICE_LIST_KEY "bt_list"
+
+
+/**
+ * wifi 工作模式
+ */
+typedef enum  {
+    // wifi 热点模式
+    WIFI_MODE_AP = 0,
+    // wifi 客户端模式
+    WIFI_MODE_STA,
+    // 自动模式, 连接sta失败时自动切换为AP模式
+    WIFI_MODE_AUTO,
+    WIFI_MODE_MAX
+} wifi_mode_t;
+
 // 蓝牙设备信息结构
 typedef struct {
     uint8_t bda[6];                           // 蓝牙设备地址
@@ -14,8 +53,42 @@ typedef struct {
     bool is_paired;                           // 是否已配对
     uint32_t connect_count;                   // 连接次数
     uint64_t last_connect_time;               // 最后连接时间戳
+    bool is_valid;                            // 记录是否有效
 } bt_device_info_t;
 
+// 蓝牙设备信息数组
+typedef struct {
+    bt_device_info_t devices[MAX_BT_DEVICES];
+} bt_device_list_t;
+
+// 设备基础信息配置
+typedef struct {
+    // 蓝牙设备显示的名称, 默认为"YunTune"不允许更改
+    char device_name[BT_DEVICE_NAME_MAX_LEN];
+    // 是否允许自动重连
+    bool auto_reconnect;
+    audio_mode_t audio_mode;
+    wifi_mode_t wifi_mode;
+    // 重连等待 时间, 每次重连等待 n 秒, 失败后切换下一个连接,
+    int reconnect_wait_time;
+    int reconnect_max_attempts;
+    // Wi-Fi ssid 依赖 auto_connect_wifi
+    char wifi_ssid[32];
+    // Wi-Fi password 依赖 auto_connect_wifi
+    char wifi_password[64];
+    // AP模式下配置的ssid和密码 默认为"YunTune"
+    char ap_ssid[32];
+    char ap_password[64];
+} device_config_t;
+
 
+esp_err_t ble_nvs_init(device_config_t *device_config);
+esp_err_t bt_device_load_config(device_config_t *device_config);
+esp_err_t bt_device_save_config(const device_config_t *device_config);
+esp_err_t bt_device_load_bt_info(bt_device_info_t *bt_info);
+esp_err_t bt_device_save_bt_info(const bt_device_info_t *bt_info);
+esp_err_t bt_device_add_or_update(const bt_device_info_t *bt_info);
+esp_err_t bt_device_get_list(bt_device_list_t *device_list);
+esp_err_t bt_device_reset_config(void);
 
 #endif //YUNTUNE_BLE_NVS_H

+ 2 - 2
main/bt_app_av.c

@@ -30,7 +30,6 @@
 #include "sys/lock.h"
 
 #include "audio.h"
-#include "ble_device_manager.h"
 
 /* AVRCP used transaction labels */
 #define APP_RC_CT_TL_GET_CAPS            (0)
@@ -287,7 +286,6 @@ static void bt_av_hdl_a2d_evt(uint16_t event, void *p_param)
             bt_i2s_task_start_up();
             // 保存连接的设备信息到NVS
             // todo 获取设备名称
-            bt_device_update_stats(bda, "Unknown_Device"); // 实际应用中应该获取设备名称
 
         } else if (a2d->conn_stat.state == ESP_A2D_CONNECTION_STATE_CONNECTING) {
             bt_i2s_driver_install();
@@ -521,6 +519,7 @@ static void bt_av_hdl_avrc_tg_evt(uint16_t event, void *p_param)
     }
 }
 
+
 /********************************
  * EXTERNAL FUNCTION DEFINITIONS
  *******************************/
@@ -529,6 +528,7 @@ void bt_app_a2d_cb(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param)
 {
     switch (event) {
     case ESP_A2D_CONNECTION_STATE_EVT:
+
     case ESP_A2D_AUDIO_STATE_EVT:
     case ESP_A2D_AUDIO_CFG_EVT:
     case ESP_A2D_PROF_STATE_EVT:

+ 5 - 253
main/main.c

@@ -20,263 +20,15 @@
 #include "esp_log.h"
 
 #include "esp_bt.h"
-#include "bt_app_core.h"
-#include "bt_app_av.h"
-#include "esp_bt_main.h"
-#include "esp_bt_device.h"
-#include "esp_gap_bt_api.h"
-#include "esp_a2dp_api.h"
-#include "esp_avrc_api.h"
-#include "driver/gpio.h"
+#include "app_manager.h"
 
-
-/* device name */
-#define LOCAL_DEVICE_NAME    "ESP_SPEAKER"
-
-/* event for stack up */
-enum {
-    BT_APP_EVT_STACK_UP = 0,
-};
-
-/* GPIO definitions */
-#define GPIO_BTN        GPIO_NUM_2   // 按钮引脚
-#define GPIO_OUTPUT     GPIO_NUM_19  // 输出控制引脚
-
-
-/* Audio mode states */
-typedef enum {
-    AUDIO_MODE_NORMAL = 0,
-    AUDIO_MODE_BASS_BOOST,
-    AUDIO_MODE_MAX
-} audio_mode_t;
-
-static audio_mode_t current_audio_mode = AUDIO_MODE_NORMAL;
-
-
-/********************************
- * STATIC FUNCTION DECLARATIONS
- *******************************/
-
-/* Device callback function */
-static void bt_app_dev_cb(esp_bt_dev_cb_event_t event, esp_bt_dev_cb_param_t *param);
-/* GAP callback function */
-static void bt_app_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param);
-/* handler for bluetooth stack enabled events */
-static void bt_av_hdl_stack_evt(uint16_t event, void *p_param);
-
-
-/* GPIO interrupt handler */
-static void IRAM_ATTR gpio_isr_handler(void* arg);
-
-/* Switch audio mode */
-static void switch_audio_mode(void);
-/* Update GPIO output based on audio mode */
-static void update_gpio_output(void);
-
-/*******************************
- * STATIC FUNCTION DEFINITIONS
- ******************************/
-static char *bda2str(uint8_t * bda, char *str, size_t size)
-{
-    if (bda == NULL || str == NULL || size < 18) {
-        return NULL;
-    }
-
-    uint8_t *p = bda;
-    sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x",
-            p[0], p[1], p[2], p[3], p[4], p[5]);
-    return str;
-}
-
-static void bt_app_dev_cb(esp_bt_dev_cb_event_t event, esp_bt_dev_cb_param_t *param)
-{
-    switch (event) {
-    case ESP_BT_DEV_NAME_RES_EVT: {
-        if (param->name_res.status == ESP_BT_STATUS_SUCCESS) {
-            ESP_LOGI(BT_AV_TAG, "Get local device name success: %s", param->name_res.name);
-        } else {
-            ESP_LOGE(BT_AV_TAG, "Get local device name failed, status: %d", param->name_res.status);
-        }
-        break;
-    }
-    default: {
-        ESP_LOGI(BT_AV_TAG, "event: %d", event);
-        break;
-    }
-    }
-}
-
-static void bt_app_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param)
-{
-    uint8_t *bda = NULL;
-
-    switch (event) {
-    /* when authentication completed, this event comes */
-    case ESP_BT_GAP_AUTH_CMPL_EVT: {
-        if (param->auth_cmpl.stat == ESP_BT_STATUS_SUCCESS) {
-            ESP_LOGI(BT_AV_TAG, "authentication success: %s", param->auth_cmpl.device_name);
-            esp_log_buffer_hex(BT_AV_TAG, param->auth_cmpl.bda, ESP_BD_ADDR_LEN);
-        } else {
-            ESP_LOGE(BT_AV_TAG, "authentication failed, status: %d", param->auth_cmpl.stat);
-        }
-        ESP_LOGI(BT_AV_TAG, "link key type of current link is: %d", param->auth_cmpl.lk_type);
-        break;
-    }
-    case ESP_BT_GAP_ENC_CHG_EVT: {
-        char *str_enc[3] = {"OFF", "E0", "AES"};
-        bda = (uint8_t *)param->enc_chg.bda;
-        ESP_LOGI(BT_AV_TAG, "Encryption mode to [%02x:%02x:%02x:%02x:%02x:%02x] changed to %s",
-                 bda[0], bda[1], bda[2], bda[3], bda[4], bda[5], str_enc[param->enc_chg.enc_mode]);
-        break;
-    }
-
-#if (CONFIG_EXAMPLE_A2DP_SINK_SSP_ENABLED == true)
-    /* when Security Simple Pairing user confirmation requested, this event comes */
-    case ESP_BT_GAP_CFM_REQ_EVT:
-        ESP_LOGI(BT_AV_TAG, "ESP_BT_GAP_CFM_REQ_EVT Please compare the numeric value: %"PRIu32, param->cfm_req.num_val);
-        esp_bt_gap_ssp_confirm_reply(param->cfm_req.bda, true);
-        break;
-    /* when Security Simple Pairing passkey notified, this event comes */
-    case ESP_BT_GAP_KEY_NOTIF_EVT:
-        ESP_LOGI(BT_AV_TAG, "ESP_BT_GAP_KEY_NOTIF_EVT passkey: %"PRIu32, param->key_notif.passkey);
-        break;
-    /* when Security Simple Pairing passkey requested, this event comes */
-    case ESP_BT_GAP_KEY_REQ_EVT:
-        ESP_LOGI(BT_AV_TAG, "ESP_BT_GAP_KEY_REQ_EVT Please enter passkey!");
-        break;
-#endif
-
-    /* when GAP mode changed, this event comes */
-    case ESP_BT_GAP_MODE_CHG_EVT:
-        ESP_LOGI(BT_AV_TAG, "ESP_BT_GAP_MODE_CHG_EVT mode: %d", param->mode_chg.mode);
-        break;
-    /* when ACL connection completed, this event comes */
-    case ESP_BT_GAP_ACL_CONN_CMPL_STAT_EVT:
-        bda = (uint8_t *)param->acl_conn_cmpl_stat.bda;
-        ESP_LOGI(BT_AV_TAG, "ESP_BT_GAP_ACL_CONN_CMPL_STAT_EVT Connected to [%02x:%02x:%02x:%02x:%02x:%02x], status: 0x%x",
-                 bda[0], bda[1], bda[2], bda[3], bda[4], bda[5], param->acl_conn_cmpl_stat.stat);
-        break;
-    /* when ACL disconnection completed, this event comes */
-    case ESP_BT_GAP_ACL_DISCONN_CMPL_STAT_EVT:
-        bda = (uint8_t *)param->acl_disconn_cmpl_stat.bda;
-        ESP_LOGI(BT_AV_TAG, "ESP_BT_GAP_ACL_DISC_CMPL_STAT_EVT Disconnected from [%02x:%02x:%02x:%02x:%02x:%02x], reason: 0x%x",
-                 bda[0], bda[1], bda[2], bda[3], bda[4], bda[5], param->acl_disconn_cmpl_stat.reason);
-        break;
-    /* others */
-    default: {
-        ESP_LOGI(BT_AV_TAG, "event: %d", event);
-        break;
-    }
-    }
-}
-
-static void bt_av_hdl_stack_evt(uint16_t event, void *p_param)
-{
-    ESP_LOGD(BT_AV_TAG, "%s event: %d", __func__, event);
-
-    switch (event) {
-    /* when do the stack up, this event comes */
-    case BT_APP_EVT_STACK_UP: {
-        esp_bt_gap_set_device_name(LOCAL_DEVICE_NAME);
-        esp_bt_dev_register_callback(bt_app_dev_cb);
-        esp_bt_gap_register_callback(bt_app_gap_cb);
-
-        assert(esp_avrc_ct_init() == ESP_OK);
-        esp_avrc_ct_register_callback(bt_app_rc_ct_cb);
-        assert(esp_avrc_tg_init() == ESP_OK);
-        esp_avrc_tg_register_callback(bt_app_rc_tg_cb);
-
-        esp_avrc_rn_evt_cap_mask_t evt_set = {0};
-        esp_avrc_rn_evt_bit_mask_operation(ESP_AVRC_BIT_MASK_OP_SET, &evt_set, ESP_AVRC_RN_VOLUME_CHANGE);
-        assert(esp_avrc_tg_set_rn_evt_cap(&evt_set) == ESP_OK);
-
-        assert(esp_a2d_sink_init() == ESP_OK);
-        esp_a2d_register_callback(&bt_app_a2d_cb);
-        esp_a2d_sink_register_data_callback(bt_app_a2d_data_cb);
-
-        /* Get the default value of the delay value */
-        esp_a2d_sink_get_delay_value();
-        /* Get local device name */
-        esp_bt_gap_get_device_name();
-
-        /* set discoverable and connectable mode, wait to be connected */
-        esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
-        break;
-    }
-    /* others */
-    default:
-        ESP_LOGE(BT_AV_TAG, "%s unhandled event: %d", __func__, event);
-        break;
-    }
-}
-
-
-
-/*******************************
- * MAIN ENTRY POINT
- ******************************/
+#define TAG "YUNTUNE"
+#define VERSION "v1.0.0"
 
 void app_main(void)
 {
-    char bda_str[18] = {0};
-    /* initialize NVS — it is used to store PHY calibration data */
-    esp_err_t err = nvs_flash_init();
-    if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
-        ESP_ERROR_CHECK(nvs_flash_erase());
-        err = nvs_flash_init();
-    }
+    ESP_LOGI(TAG, "app version: %s", VERSION);
+    esp_err_t err = init_app();
     ESP_ERROR_CHECK(err);
-    ESP_LOGI(BT_AV_TAG, "Initializing hw gpio ...");
-    init_io();
-    ESP_LOGI(BT_AV_TAG, "Initializing bluetooth ...");
-
-    /*
-     * This example only uses the functions of Classical Bluetooth.
-     * So release the controller memory for Bluetooth Low Energy.
-     */
-    ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_BLE));
-
-    esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
-    if ((err = esp_bt_controller_init(&bt_cfg)) != ESP_OK) {
-        ESP_LOGE(BT_AV_TAG, "%s initialize controller failed: %s", __func__, esp_err_to_name(err));
-        return;
-    }
-    if ((err = esp_bt_controller_enable(ESP_BT_MODE_CLASSIC_BT)) != ESP_OK) {
-        ESP_LOGE(BT_AV_TAG, "%s enable controller failed: %s", __func__, esp_err_to_name(err));
-        return;
-    }
-
-    esp_bluedroid_config_t bluedroid_cfg = BT_BLUEDROID_INIT_CONFIG_DEFAULT();
-#if (CONFIG_EXAMPLE_A2DP_SINK_SSP_ENABLED == false)
-    bluedroid_cfg.ssp_en = false;
-#endif
-    if ((err = esp_bluedroid_init_with_cfg(&bluedroid_cfg)) != ESP_OK) {
-        ESP_LOGE(BT_AV_TAG, "%s initialize bluedroid failed: %s", __func__, esp_err_to_name(err));
-        return;
-    }
-
-    if ((err = esp_bluedroid_enable()) != ESP_OK) {
-        ESP_LOGE(BT_AV_TAG, "%s enable bluedroid failed: %s", __func__, esp_err_to_name(err));
-        return;
-    }
-
-#if (CONFIG_EXAMPLE_A2DP_SINK_SSP_ENABLED == true)
-    /* set default parameters for Secure Simple Pairing */
-    esp_bt_sp_param_t param_type = ESP_BT_SP_IOCAP_MODE;
-    esp_bt_io_cap_t iocap = ESP_BT_IO_CAP_IO;
-    esp_bt_gap_set_security_param(param_type, &iocap, sizeof(uint8_t));
-#endif
 
-    /* set default parameters for Legacy Pairing (use fixed pin code 1234) */
-    esp_bt_pin_type_t pin_type = ESP_BT_PIN_TYPE_FIXED;
-    esp_bt_pin_code_t pin_code;
-    pin_code[0] = '1';
-    pin_code[1] = '2';
-    pin_code[2] = '3';
-    pin_code[3] = '4';
-    esp_bt_gap_set_pin(pin_type, 4, pin_code);
-    ESP_LOGI(BT_AV_TAG, "Own address:[%s]", bda2str((uint8_t *)esp_bt_dev_get_address(), bda_str, sizeof(bda_str)));
-    bt_app_task_start_up();
-    /* bluetooth device name, connection mode and profile set up */
-    bt_app_work_dispatch(bt_av_hdl_stack_evt, BT_APP_EVT_STACK_UP, NULL, 0, NULL);
 }