app_manager.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. //
  2. // Created by kindring on 2025/12/26.
  3. //
  4. #include "esp_log.h"
  5. #include "app_io.h"
  6. #include "app_manager.h"
  7. #include <string.h>
  8. #include "app_ble.h"
  9. #include "ble_nvs.h"
  10. #include "esp_timer.h"
  11. #include "portmacro.h"
  12. #include "freertos/task.h"
  13. #include "esp_bt_defs.h"
  14. #include "esp_bt_device.h"
  15. #include "esp_gap_bt_api.h"
  16. #define TAG "app_manager"
  17. audio_mode_t m_current_audio_mode = AUDIO_MODE_AUX;
  18. static bool is_reconnecting = false;
  19. static int current_reconnect_attempt = 0;
  20. static uint64_t last_reconnect_time = 0;
  21. const char* mode_names[] = {
  22. "NORMAL",
  23. "BASS_BOOST",
  24. };
  25. yun_config_t g_device_config = {
  26. .device_name = "YunTune",
  27. .auto_reconnect = true,
  28. .audio_mode = AUDIO_MODE_AUX,
  29. .wifi_mode = WIFI_MODE_AP,
  30. .reconnect_wait_time = 2,
  31. .reconnect_max_attempts = 10,
  32. .wifi_ssid = '\0',
  33. .wifi_password = '\0',
  34. .ap_ssid = "YunTune",
  35. .ap_password = "YunTune",
  36. };
  37. static void start_reconnection_process(bt_device_list_t *device_list);
  38. // 切换为下一个播放模式
  39. audio_mode_t next_audio_mode()
  40. {
  41. const audio_mode_t next_audio_mode = (m_current_audio_mode + 1) % AUDIO_MODE_MAX;
  42. ESP_LOGI(TAG, "Audio mode switched to: %s", mode_names[next_audio_mode]);
  43. update_output_mode(next_audio_mode);
  44. return next_audio_mode;
  45. }
  46. // 保存连接的蓝牙信息
  47. esp_err_t save_bt_info(uint8_t *bda, char *device_name)
  48. {
  49. if (!bda || !device_name) {
  50. ESP_LOGE(TAG, "Invalid input parameters");
  51. return ESP_ERR_INVALID_ARG;
  52. }
  53. // 创建蓝牙设备信息结构体
  54. bt_device_info_t bt_info = {0};
  55. // 复制蓝牙设备地址
  56. memcpy(bt_info.bda, bda, 6);
  57. // 复制设备名称
  58. strncpy(bt_info.device_name, device_name, sizeof(bt_info.device_name) - 1);
  59. bt_info.device_name[sizeof(bt_info.device_name) - 1] = '\0';
  60. // 设置其他属性
  61. bt_info.is_paired = true;
  62. bt_info.connect_count++;
  63. bt_info.last_connect_time = esp_timer_get_time(); // 获取当前时间戳
  64. bt_info.is_valid = true;
  65. // 使用公共函数保存蓝牙设备信息
  66. esp_err_t err = bt_device_add_or_update(&bt_info);
  67. if (err != ESP_OK) {
  68. ESP_LOGE(TAG, "Failed to save bluetooth device info: %s", esp_err_to_name(err));
  69. return err;
  70. }
  71. ESP_LOGI(TAG, "Bluetooth device info saved successfully: %s", device_name);
  72. return ESP_OK;
  73. }
  74. esp_err_t reconnect_ble()
  75. {
  76. // 获取最新的蓝牙设备信息
  77. // 尝试连接蓝牙
  78. if (!g_device_config.auto_reconnect) {
  79. ESP_LOGI(TAG, "Auto-reconnect is disabled, skipping reconnection");
  80. return ESP_OK;
  81. }
  82. if (is_reconnecting) {
  83. ESP_LOGI(TAG, "Already in reconnection process");
  84. return ESP_OK;
  85. }
  86. is_reconnecting = true;
  87. current_reconnect_attempt = 0;
  88. // 获取保存的蓝牙设备列表
  89. bt_device_list_t device_list;
  90. esp_err_t err = bt_device_get_list(&device_list);
  91. if (err != ESP_OK) {
  92. ESP_LOGE(TAG, "Failed to get bluetooth device list: %s", esp_err_to_name(err));
  93. is_reconnecting = false;
  94. return err;
  95. }
  96. // 按最后连接时间排序,优先尝试最近连接过的设备
  97. bt_device_info_t *most_recent_device = NULL;
  98. uint64_t latest_time = 0;
  99. for (int i = 0; i < MAX_BT_DEVICES; i++) {
  100. if (device_list.devices[i].is_valid &&
  101. device_list.devices[i].last_connect_time > latest_time) {
  102. latest_time = device_list.devices[i].last_connect_time;
  103. most_recent_device = &device_list.devices[i];
  104. }
  105. }
  106. if (most_recent_device != NULL) {
  107. ESP_LOGI(TAG, "Attempting to reconnect to: %s", most_recent_device->device_name);
  108. // 调用蓝牙连接函数
  109. err = connect_to_bt_device(most_recent_device->bda, most_recent_device->device_name);
  110. if (err != ESP_OK) {
  111. ESP_LOGW(TAG, "Initial reconnection attempt failed: %s", esp_err_to_name(err));
  112. // 如果初始连接失败,启动重试机制
  113. start_reconnection_process(&device_list);
  114. }
  115. } else {
  116. ESP_LOGI(TAG, "No saved bluetooth devices to reconnect");
  117. is_reconnecting = false;
  118. }
  119. return ESP_OK;
  120. }
  121. // 查找下一个候选连接设备
  122. static bt_device_info_t* find_next_candidate_device(bt_device_list_t *device_list, int attempt_order)
  123. {
  124. // 创建一个临时数组来存储有效的设备信息
  125. bt_device_info_t valid_devices[MAX_BT_DEVICES];
  126. int valid_count = 0;
  127. // 收集所有有效设备
  128. for (int i = 0; i < MAX_BT_DEVICES; i++) {
  129. if (device_list->devices[i].is_valid) {
  130. memcpy(&valid_devices[valid_count], &device_list->devices[i], sizeof(bt_device_info_t));
  131. valid_count++;
  132. }
  133. }
  134. if (valid_count == 0) {
  135. return NULL;
  136. }
  137. // 简单的排序:根据连接次数和最后连接时间
  138. // 这里使用简单的冒泡排序,实际应用中可能需要更高效的算法
  139. for (int i = 0; i < valid_count - 1; i++) {
  140. for (int j = 0; j < valid_count - i - 1; j++) {
  141. // 按照连接次数降序排列,然后按最后连接时间降序排列
  142. if ((valid_devices[j].connect_count < valid_devices[j+1].connect_count) ||
  143. (valid_devices[j].connect_count == valid_devices[j+1].connect_count &&
  144. valid_devices[j].last_connect_time < valid_devices[j+1].last_connect_time)) {
  145. bt_device_info_t temp = valid_devices[j];
  146. valid_devices[j] = valid_devices[j+1];
  147. valid_devices[j+1] = temp;
  148. }
  149. }
  150. }
  151. // 返回指定顺序的设备
  152. if (attempt_order < valid_count) {
  153. // 找到原始设备列表中的索引并返回指针
  154. for (int i = 0; i < MAX_BT_DEVICES; i++) {
  155. if (device_list->devices[i].is_valid &&
  156. memcmp(&device_list->devices[i], &valid_devices[attempt_order], sizeof(bt_device_info_t)) == 0) {
  157. return &device_list->devices[i];
  158. }
  159. }
  160. }
  161. return NULL;
  162. }
  163. // 启动重连过程
  164. static void start_reconnection_process(bt_device_list_t *device_list)
  165. {
  166. // 按连接次数和最后连接时间排序,尝试其他设备
  167. for (int attempt = 0; attempt < g_device_config.reconnect_max_attempts; attempt++) {
  168. bt_device_info_t *candidate_device = find_next_candidate_device(device_list, attempt);
  169. if (candidate_device != NULL) {
  170. ESP_LOGI(TAG, "Attempting reconnection to candidate device: %s (attempt %d/%d)",
  171. candidate_device->device_name, attempt + 1, g_device_config.reconnect_max_attempts);
  172. esp_err_t err = connect_to_bt_device(candidate_device->bda, candidate_device->device_name);
  173. if (err == ESP_OK) {
  174. ESP_LOGI(TAG, "Successfully connected to %s", candidate_device->device_name);
  175. is_reconnecting = false;
  176. return;
  177. }
  178. // 等待一段时间再尝试下一个设备
  179. vTaskDelay(g_device_config.reconnect_wait_time * 1000 / portTICK_PERIOD_MS);
  180. }
  181. }
  182. ESP_LOGW(TAG, "All reconnection attempts failed");
  183. is_reconnecting = false;
  184. }
  185. // 当蓝牙连接成功时调用此函数更新设备信息
  186. void on_bt_connection_success(uint8_t *bda, char *device_name)
  187. {
  188. if (bda && device_name) {
  189. // 更新设备连接计数和时间
  190. bt_device_info_t bt_info = {0};
  191. memcpy(bt_info.bda, bda, 6);
  192. strncpy(bt_info.device_name, device_name, sizeof(bt_info.device_name) - 1);
  193. bt_info.device_name[sizeof(bt_info.device_name) - 1] = '\0';
  194. bt_info.is_paired = true;
  195. bt_info.connect_count++; // 增加连接计数
  196. bt_info.last_connect_time = esp_timer_get_time();
  197. bt_info.is_valid = true;
  198. // 保存更新后的设备信息
  199. esp_err_t err = bt_device_add_or_update(&bt_info);
  200. if (err != ESP_OK) {
  201. ESP_LOGE(TAG, "Failed to update bluetooth device info after connection: %s", esp_err_to_name(err));
  202. } else {
  203. ESP_LOGI(TAG, "Bluetooth device info updated after successful connection: %s", device_name);
  204. }
  205. }
  206. // 重置重连状态
  207. is_reconnecting = false;
  208. current_reconnect_attempt = 0;
  209. }
  210. // 当蓝牙断开连接时调用此函数,如果启用自动重连则开始重连
  211. void on_bt_disconnection()
  212. {
  213. ESP_LOGI(TAG, "Bluetooth disconnected, checking for auto-reconnect");
  214. if (g_device_config.auto_reconnect && !is_reconnecting) {
  215. ESP_LOGI(TAG, "Starting auto-reconnect process...");
  216. // 延迟一点时间再开始重连,避免立即重连导致的问题
  217. vTaskDelay(g_device_config.reconnect_wait_time * 1000 / portTICK_PERIOD_MS);
  218. reconnect_ble();
  219. }
  220. }
  221. esp_err_t init_app()
  222. {
  223. esp_err_t err = ESP_OK;
  224. err = ble_nvs_init(&g_device_config);
  225. if (err != ESP_OK) {
  226. ESP_LOGE(TAG, "Failed to initialize NVS");
  227. return err;
  228. }
  229. init_io(g_device_config.audio_mode);
  230. // 初始化蓝牙
  231. init_ble(g_device_config.device_name);
  232. // 根据逻辑调整蓝牙的运行模式
  233. if (g_device_config.audio_mode == AUDIO_MODE_BLE)
  234. {
  235. // todo 重连 蓝牙设备
  236. reconnect_ble();
  237. }
  238. return ESP_OK;
  239. }