Jelajahi Sumber

docs: 基本代码整理

kindring 1 bulan lalu
induk
melakukan
88ebbfaa20
7 mengubah file dengan 234 tambahan dan 11 penghapusan
  1. 2 0
      .gitignore
  2. 1 1
      main/CMakeLists.txt
  3. 209 3
      main/app_manager.c
  4. 14 0
      main/app_manager.h
  5. 3 3
      main/ble_nvs.c
  6. 4 4
      main/ble_nvs.h
  7. 1 0
      main/bt_app_av.c

+ 2 - 0
.gitignore

@@ -0,0 +1,2 @@
+/cmake-build-debug/
+/cmake-build-debug-esp_idf/

+ 1 - 1
main/CMakeLists.txt

@@ -1,5 +1,5 @@
 idf_component_register(SRCS "main.c"  "bt_app_av.c"
-                            "bt_app_core.c"
+                            "bt_app_core.c" "app_manager.c" "ble_nvs.c" "app_io.c"
                            
                     PRIV_REQUIRES esp_driver_i2s bt nvs_flash esp_ringbuf esp_driver_dac
                     REQUIRES driver

+ 209 - 3
main/app_manager.c

@@ -8,20 +8,30 @@
 #include "app_io.h"
 #include "app_manager.h"
 
+#include <string.h>
+
 #include "app_ble.h"
 #include "ble_nvs.h"
-
+#include "esp_timer.h"
+#include "portmacro.h"
+#include "freertos/task.h"
+#include "esp_bt_defs.h"
+#include "esp_bt_device.h"
+#include "esp_gap_bt_api.h"
 
 #define TAG "app_manager"
 
 audio_mode_t m_current_audio_mode = AUDIO_MODE_AUX;
+static bool is_reconnecting = false;
+static int current_reconnect_attempt = 0;
+static uint64_t last_reconnect_time = 0;
 
 const char* mode_names[] = {
     "NORMAL",
     "BASS_BOOST",
 };
 
-device_config_t  g_device_config = {
+yun_config_t  g_device_config = {
     .device_name = "YunTune",
     .auto_reconnect = true,
     .audio_mode =  AUDIO_MODE_AUX,
@@ -34,6 +44,8 @@ device_config_t  g_device_config = {
     .ap_password = "YunTune",
 };
 
+static void start_reconnection_process(bt_device_list_t *device_list);
+
 // 切换为下一个播放模式
 audio_mode_t next_audio_mode()
 {
@@ -48,9 +60,203 @@ audio_mode_t next_audio_mode()
 // 保存连接的蓝牙信息
 esp_err_t  save_bt_info(uint8_t *bda,  char *device_name)
 {
+    if (!bda || !device_name) {
+        ESP_LOGE(TAG, "Invalid input parameters");
+        return ESP_ERR_INVALID_ARG;
+    }
+    // 创建蓝牙设备信息结构体
+    bt_device_info_t bt_info = {0};
+
+    // 复制蓝牙设备地址
+    memcpy(bt_info.bda, bda, 6);
+
+    // 复制设备名称
+    strncpy(bt_info.device_name, device_name, sizeof(bt_info.device_name) - 1);
+    bt_info.device_name[sizeof(bt_info.device_name) - 1] = '\0';
+
+    // 设置其他属性
+    bt_info.is_paired = true;
+    bt_info.connect_count++;
+    bt_info.last_connect_time = esp_timer_get_time(); // 获取当前时间戳
+    bt_info.is_valid = true;
+
+    // 使用公共函数保存蓝牙设备信息
+    esp_err_t err = bt_device_add_or_update(&bt_info);
+    if (err != ESP_OK) {
+        ESP_LOGE(TAG, "Failed to save bluetooth device info: %s", esp_err_to_name(err));
+        return err;
+    }
+
+    ESP_LOGI(TAG, "Bluetooth device info saved successfully: %s", device_name);
+    return ESP_OK;
+
+}
+
+esp_err_t reconnect_ble()
+{
+    // 获取最新的蓝牙设备信息
+    // 尝试连接蓝牙
+    if (!g_device_config.auto_reconnect) {
+        ESP_LOGI(TAG, "Auto-reconnect is disabled, skipping reconnection");
+        return ESP_OK;
+    }
+
+    if (is_reconnecting) {
+        ESP_LOGI(TAG, "Already in reconnection process");
+        return ESP_OK;
+    }
+    is_reconnecting = true;
+    current_reconnect_attempt = 0;
+    // 获取保存的蓝牙设备列表
+    bt_device_list_t device_list;
+    esp_err_t err = bt_device_get_list(&device_list);
+    if (err != ESP_OK) {
+        ESP_LOGE(TAG, "Failed to get bluetooth device list: %s", esp_err_to_name(err));
+        is_reconnecting = false;
+        return err;
+    }
+    // 按最后连接时间排序,优先尝试最近连接过的设备
+    bt_device_info_t *most_recent_device = NULL;
+    uint64_t latest_time = 0;
 
+    for (int i = 0; i < MAX_BT_DEVICES; i++) {
+        if (device_list.devices[i].is_valid &&
+            device_list.devices[i].last_connect_time > latest_time) {
+            latest_time = device_list.devices[i].last_connect_time;
+            most_recent_device = &device_list.devices[i];
+            }
+    }
+
+    if (most_recent_device != NULL) {
+        ESP_LOGI(TAG, "Attempting to reconnect to: %s", most_recent_device->device_name);
+        // 调用蓝牙连接函数
+        err = connect_to_bt_device(most_recent_device->bda, most_recent_device->device_name);
+        if (err != ESP_OK) {
+            ESP_LOGW(TAG, "Initial reconnection attempt failed: %s", esp_err_to_name(err));
+            // 如果初始连接失败,启动重试机制
+            start_reconnection_process(&device_list);
+        }
+    } else {
+        ESP_LOGI(TAG, "No saved bluetooth devices to reconnect");
+        is_reconnecting = false;
+    }
+
+    return ESP_OK;
 }
 
+// 查找下一个候选连接设备
+static bt_device_info_t* find_next_candidate_device(bt_device_list_t *device_list, int attempt_order)
+{
+    // 创建一个临时数组来存储有效的设备信息
+    bt_device_info_t valid_devices[MAX_BT_DEVICES];
+    int valid_count = 0;
+
+    // 收集所有有效设备
+    for (int i = 0; i < MAX_BT_DEVICES; i++) {
+        if (device_list->devices[i].is_valid) {
+            memcpy(&valid_devices[valid_count], &device_list->devices[i], sizeof(bt_device_info_t));
+            valid_count++;
+        }
+    }
+
+    if (valid_count == 0) {
+        return NULL;
+    }
+
+    // 简单的排序:根据连接次数和最后连接时间
+    // 这里使用简单的冒泡排序,实际应用中可能需要更高效的算法
+    for (int i = 0; i < valid_count - 1; i++) {
+        for (int j = 0; j < valid_count - i - 1; j++) {
+            // 按照连接次数降序排列,然后按最后连接时间降序排列
+            if ((valid_devices[j].connect_count < valid_devices[j+1].connect_count) ||
+                (valid_devices[j].connect_count == valid_devices[j+1].connect_count &&
+                 valid_devices[j].last_connect_time < valid_devices[j+1].last_connect_time)) {
+                bt_device_info_t temp = valid_devices[j];
+                valid_devices[j] = valid_devices[j+1];
+                valid_devices[j+1] = temp;
+                 }
+        }
+    }
+
+    // 返回指定顺序的设备
+    if (attempt_order < valid_count) {
+        // 找到原始设备列表中的索引并返回指针
+        for (int i = 0; i < MAX_BT_DEVICES; i++) {
+            if (device_list->devices[i].is_valid &&
+                memcmp(&device_list->devices[i], &valid_devices[attempt_order], sizeof(bt_device_info_t)) == 0) {
+                return &device_list->devices[i];
+                }
+        }
+    }
+
+    return NULL;
+}
+// 启动重连过程
+static void start_reconnection_process(bt_device_list_t *device_list)
+{
+    // 按连接次数和最后连接时间排序,尝试其他设备
+    for (int attempt = 0; attempt < g_device_config.reconnect_max_attempts; attempt++) {
+        bt_device_info_t *candidate_device = find_next_candidate_device(device_list, attempt);
+        if (candidate_device != NULL) {
+            ESP_LOGI(TAG, "Attempting reconnection to candidate device: %s (attempt %d/%d)",
+                     candidate_device->device_name, attempt + 1, g_device_config.reconnect_max_attempts);
+
+            esp_err_t err = connect_to_bt_device(candidate_device->bda, candidate_device->device_name);
+            if (err == ESP_OK) {
+                ESP_LOGI(TAG, "Successfully connected to %s", candidate_device->device_name);
+                is_reconnecting = false;
+                return;
+            }
+
+            // 等待一段时间再尝试下一个设备
+            vTaskDelay(g_device_config.reconnect_wait_time * 1000 / portTICK_PERIOD_MS);
+        }
+    }
+
+    ESP_LOGW(TAG, "All reconnection attempts failed");
+    is_reconnecting = false;
+}
+
+// 当蓝牙连接成功时调用此函数更新设备信息
+void on_bt_connection_success(uint8_t *bda, char *device_name)
+{
+    if (bda && device_name) {
+        // 更新设备连接计数和时间
+        bt_device_info_t bt_info = {0};
+        memcpy(bt_info.bda, bda, 6);
+        strncpy(bt_info.device_name, device_name, sizeof(bt_info.device_name) - 1);
+        bt_info.device_name[sizeof(bt_info.device_name) - 1] = '\0';
+        bt_info.is_paired = true;
+        bt_info.connect_count++; // 增加连接计数
+        bt_info.last_connect_time = esp_timer_get_time();
+        bt_info.is_valid = true;
+
+        // 保存更新后的设备信息
+        esp_err_t err = bt_device_add_or_update(&bt_info);
+        if (err != ESP_OK) {
+            ESP_LOGE(TAG, "Failed to update bluetooth device info after connection: %s", esp_err_to_name(err));
+        } else {
+            ESP_LOGI(TAG, "Bluetooth device info updated after successful connection: %s", device_name);
+        }
+    }
+
+    // 重置重连状态
+    is_reconnecting = false;
+    current_reconnect_attempt = 0;
+}
+
+// 当蓝牙断开连接时调用此函数,如果启用自动重连则开始重连
+void on_bt_disconnection()
+{
+    ESP_LOGI(TAG, "Bluetooth disconnected, checking for auto-reconnect");
+
+    if (g_device_config.auto_reconnect && !is_reconnecting) {
+        ESP_LOGI(TAG, "Starting auto-reconnect process...");
+        // 延迟一点时间再开始重连,避免立即重连导致的问题
+        vTaskDelay(g_device_config.reconnect_wait_time * 1000 / portTICK_PERIOD_MS);
+        reconnect_ble();
+    }
+}
 
 esp_err_t init_app()
 {
@@ -69,7 +275,7 @@ esp_err_t init_app()
     if (g_device_config.audio_mode ==  AUDIO_MODE_BLE)
     {
         // todo 重连 蓝牙设备
-
+        reconnect_ble();
     }
 
     return ESP_OK;

+ 14 - 0
main/app_manager.h

@@ -5,6 +5,8 @@
 #ifndef YUNTUNE_APP_MANAGER_H
 #define YUNTUNE_APP_MANAGER_H
 
+#include "esp_err.h"
+
 /**
  * 功放工作模式, 切换aux与蓝牙模式
  */
@@ -14,6 +16,18 @@ typedef enum {
     AUDIO_MODE_MAX
 } audio_mode_t;
 
+// 运行上下文
+typedef struct {
+    audio_mode_t audio_mode;
+    char *device_name;
+    bool auto_reconnect;
+    int reconnect_wait_time;
+    int reconnect_max_attempts;
+    char *wifi_ssid;
+    char *wifi_password;
+    char *ap_ssid;
+    char *ap_password;
+} device_config_t;
 
 
 audio_mode_t next_audio_mode();

+ 3 - 3
main/ble_nvs.c

@@ -14,7 +14,7 @@ static const char *TAG = "BLE_NVS";
 
 
 
-esp_err_t bt_device_load_config(device_config_t *device_config)
+esp_err_t bt_device_load_config(yun_config_t *device_config)
 {
     if (device_config == NULL) {
         ESP_LOGE(TAG, "device_config is NULL");
@@ -98,7 +98,7 @@ esp_err_t bt_device_load_config(device_config_t *device_config)
     return ESP_OK;
 }
 
-esp_err_t bt_device_save_config(const device_config_t *device_config)
+esp_err_t bt_device_save_config(const yun_config_t *device_config)
 {
     if (device_config == NULL) {
         ESP_LOGE(TAG, "device_config is NULL");
@@ -390,7 +390,7 @@ esp_err_t bt_device_reset_config(void)
 }
 
 // 初始化nv参数
-esp_err_t ble_nvs_init(device_config_t *device_config) {
+esp_err_t ble_nvs_init(yun_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());

+ 4 - 4
main/ble_nvs.h

@@ -79,12 +79,12 @@ typedef struct {
     // AP模式下配置的ssid和密码 默认为"YunTune"
     char ap_ssid[32];
     char ap_password[64];
-} device_config_t;
+} yun_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 ble_nvs_init(yun_config_t *device_config);
+esp_err_t bt_device_load_config(yun_config_t *device_config);
+esp_err_t bt_device_save_config(const yun_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);

+ 1 - 0
main/bt_app_av.c

@@ -287,6 +287,7 @@ static void bt_av_hdl_a2d_evt(uint16_t event, void *p_param)
             // 保存连接的设备信息到NVS
             // todo 获取设备名称
 
+
         } else if (a2d->conn_stat.state == ESP_A2D_CONNECTION_STATE_CONNECTING) {
             bt_i2s_driver_install();
         }