|
@@ -8,20 +8,30 @@
|
|
|
#include "app_io.h"
|
|
#include "app_io.h"
|
|
|
#include "app_manager.h"
|
|
#include "app_manager.h"
|
|
|
|
|
|
|
|
|
|
+#include <string.h>
|
|
|
|
|
+
|
|
|
#include "app_ble.h"
|
|
#include "app_ble.h"
|
|
|
#include "ble_nvs.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"
|
|
#define TAG "app_manager"
|
|
|
|
|
|
|
|
audio_mode_t m_current_audio_mode = AUDIO_MODE_AUX;
|
|
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[] = {
|
|
const char* mode_names[] = {
|
|
|
"NORMAL",
|
|
"NORMAL",
|
|
|
"BASS_BOOST",
|
|
"BASS_BOOST",
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
-device_config_t g_device_config = {
|
|
|
|
|
|
|
+yun_config_t g_device_config = {
|
|
|
.device_name = "YunTune",
|
|
.device_name = "YunTune",
|
|
|
.auto_reconnect = true,
|
|
.auto_reconnect = true,
|
|
|
.audio_mode = AUDIO_MODE_AUX,
|
|
.audio_mode = AUDIO_MODE_AUX,
|
|
@@ -34,6 +44,8 @@ device_config_t g_device_config = {
|
|
|
.ap_password = "YunTune",
|
|
.ap_password = "YunTune",
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
+static void start_reconnection_process(bt_device_list_t *device_list);
|
|
|
|
|
+
|
|
|
// 切换为下一个播放模式
|
|
// 切换为下一个播放模式
|
|
|
audio_mode_t next_audio_mode()
|
|
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)
|
|
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()
|
|
esp_err_t init_app()
|
|
|
{
|
|
{
|
|
@@ -69,7 +275,7 @@ esp_err_t init_app()
|
|
|
if (g_device_config.audio_mode == AUDIO_MODE_BLE)
|
|
if (g_device_config.audio_mode == AUDIO_MODE_BLE)
|
|
|
{
|
|
{
|
|
|
// todo 重连 蓝牙设备
|
|
// todo 重连 蓝牙设备
|
|
|
-
|
|
|
|
|
|
|
+ reconnect_ble();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
return ESP_OK;
|
|
return ESP_OK;
|