From 3a52761d30b078b8192d7f5034b089f644f12c59 Mon Sep 17 00:00:00 2001 From: Wang is proud <63460444+KingingWang@users.noreply.github.com> Date: Sat, 24 Jan 2026 21:55:24 +0800 Subject: [PATCH] Fixed compilation errors that occurred after enabling blufi (#1677) --- docs/blufi.md | 6 +- main/CMakeLists.txt | 1 + main/boards/common/blufi.cpp | 209 ++++++++++++++++++++++++------- main/boards/common/blufi.h | 52 +++++--- main/boards/common/wifi_board.cc | 3 +- 5 files changed, 207 insertions(+), 64 deletions(-) diff --git a/docs/blufi.md b/docs/blufi.md index 292b0d75..e1b32d5d 100644 --- a/docs/blufi.md +++ b/docs/blufi.md @@ -8,13 +8,13 @@ BluFi - 需要支持 BLE 的芯片与固件配置。 - 在 `idf.py menuconfig` 中启用 `WiFi Configuration Method -> Esp Blufi`(`CONFIG_USE_ESP_BLUFI_WIFI_PROVISIONING=y` - )。如果只想用 BluFi,可关闭同一菜单下的 Hotspot/Acoustic 选项。 + )。如果想使用 BluFi,必须关闭同一菜单下的 Hotspot 选项,否则默认使用 Hotspot 配网模式。 - 保持默认的 NVS 与事件循环初始化(项目的 `app_main` 已处理)。 - CONFIG_BT_BLUEDROID_ENABLED、CONFIG_BT_NIMBLE_ENABLED这两个宏应二选一,不能同时启用。 ## 工作流程 -1) 手机端通过 BluFi(如官方 EspBlufi App 或自研客户端)连接设备,发送 Wi‑Fi SSID/密码。 +1) 手机端通过 BluFi(如官方 EspBlufi App 或自研客户端)连接设备,发送 Wi‑Fi SSID/密码,手机端可以通过blufi协议获取设备端扫描到的WiFi列表。 2) 设备侧在 `ESP_BLUFI_EVENT_REQ_CONNECT_TO_AP` 中将凭据写入 `SsidManager`(存储到 NVS,属于 `esp-wifi-connect` 组件)。 3) 随后启动 `WifiStation` 扫描并连接;状态通过 BluFi 返回。 4) 配网成功后设备会自动连接新 Wi‑Fi;失败则返回失败状态。 @@ -30,7 +30,7 @@ BluFi ## 注意事项 -- BluFi 与 Hotspot/声波配网可以同时编译,但会同时启动,增加内存占用。建议在 menuconfig 中只保留一种方式。 +- BluFi 配网不支持与热点配网同时开启。如果热点配网已经启动,则默认使用热点配网。请在 menuconfig 中只保留一种配网方式。 - 若多次测试,建议清除或覆盖存储的 SSID(`wifi` 命名空间),避免旧配置干扰。 - 如果使用自定义 BluFi 客户端,需遵循官方协议帧格式,参考上文官方文档链接。 - 官方文档中已提供EspBlufi APP下载地址 diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 14d6b30b..10c4f5ae 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -789,6 +789,7 @@ idf_component_register(SRCS ${SOURCES} spi_flash console efuse + bt ) # Use target_compile_definitions to define BOARD_TYPE, BOARD_NAME diff --git a/main/boards/common/blufi.cpp b/main/boards/common/blufi.cpp index ccfce118..e15dc168 100644 --- a/main/boards/common/blufi.cpp +++ b/main/boards/common/blufi.cpp @@ -3,25 +3,21 @@ #include #include #include - -#include "application.h" +#include #include "esp_bt.h" +#include "esp_event.h" #include "esp_log.h" -#include "esp_mac.h" -#include "esp_system.h" +#include "esp_timer.h" #include "esp_wifi.h" -#include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "wifi_manager.h" -// Bluedroid specific #ifdef CONFIG_BT_BLUEDROID_ENABLED #include "esp_bt_device.h" #include "esp_bt_main.h" #include "esp_gap_ble_api.h" #endif -// NimBLE specific #ifdef CONFIG_BT_NIMBLE_ENABLED #include "console/console.h" #include "host/ble_hs.h" @@ -36,22 +32,18 @@ extern void esp_blufi_btc_deinit(void); #endif extern "C" { -// Blufi Advertising & Connection void esp_blufi_adv_start(void); void esp_blufi_adv_stop(void); void esp_blufi_disconnect(void); -// Internal BTC layer functions needed for error reporting void btc_blufi_report_error(esp_blufi_error_state_t state); -// Bluedroid specific GAP event handler #ifdef CONFIG_BT_BLUEDROID_ENABLED void esp_blufi_gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param); #endif -// NimBLE specific internal functions #ifdef CONFIG_BT_NIMBLE_ENABLED void esp_blufi_gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg); int esp_blufi_gatt_svr_init(void); @@ -61,14 +53,12 @@ void esp_blufi_btc_deinit(void); #endif } -// mbedTLS for security #include #include "esp_crc.h" #include "esp_random.h" #include "mbedtls/md5.h" #include "ssid_manager.h" -// Logging Tag static const char *BLUFI_TAG = "BLUFI_CLASS"; static wifi_mode_t GetWifiModeWithFallback(const WifiManager &wifi) { @@ -98,9 +88,7 @@ Blufi::Blufi() m_deinited(false), m_sta_ssid_len(0), m_sta_is_connecting(false) { - // Initialize member variables memset(&m_sta_config, 0, sizeof(m_sta_config)); - memset(&m_ap_config, 0, sizeof(m_ap_config)); memset(m_sta_bssid, 0, sizeof(m_sta_bssid)); memset(m_sta_ssid, 0, sizeof(m_sta_ssid)); memset(&m_sta_conn_info, 0, sizeof(m_sta_conn_info)); @@ -113,11 +101,23 @@ Blufi::~Blufi() { } esp_err_t Blufi::init() { - esp_err_t ret; + esp_err_t ret = ESP_FAIL; inited_ = true; m_provisioned = false; m_deinited = false; + // Start WiFi scan early to have results ready when user connects + auto &wifi_manager = WifiManager::GetInstance(); + if (!wifi_manager.IsInitialized() || !wifi_manager.IsConfigMode()) { + // start scan immediately + start_wifi_scan(); + } else { + ESP_LOGE(BLUFI_TAG, + "Blufi and WiFi hotspot network configuration cannot " + "be used simultaneously."); + return ret; + } + #if CONFIG_BT_CONTROLLER_ENABLED || !CONFIG_BT_NIMBLE_ENABLED ret = _controller_init(); if (ret) { @@ -236,26 +236,20 @@ void Blufi::_nimble_on_reset(int reason) { ESP_LOGE(BLUFI_TAG, "NimBLE Resetting state; reason=%d", reason); } -void Blufi::_nimble_on_sync() { - // This is called when the host and controller are synced. - // It's a good place to initialize the Blufi profile. - esp_blufi_profile_init(); -} +void Blufi::_nimble_on_sync() { esp_blufi_profile_init(); } void Blufi::_nimble_host_task(void *param) { ESP_LOGI(BLUFI_TAG, "BLE Host Task Started"); - nimble_port_run(); // This function will return only when nimble_port_stop() is executed + nimble_port_run(); nimble_port_freertos_deinit(); } esp_err_t Blufi::_host_init() { - // esp_nimble_init() is called by controller_init for NimBLE ble_hs_cfg.reset_cb = _nimble_on_reset; ble_hs_cfg.sync_cb = _nimble_on_sync; ble_hs_cfg.gatts_register_cb = esp_blufi_gatt_svr_register_cb; - // Security Manager settings (can be customized) - ble_hs_cfg.sm_io_cap = 4; // IO capability: No Input, No Output + ble_hs_cfg.sm_io_cap = 4; #ifdef CONFIG_EXAMPLE_BONDING ble_hs_cfg.sm_bonding = 1; #endif @@ -263,7 +257,7 @@ esp_err_t Blufi::_host_init() { int rc = esp_blufi_gatt_svr_init(); assert(rc == 0); - ble_store_config_init(); // Configure the BLE storage + ble_store_config_init(); esp_blufi_btc_init(); esp_err_t err = esp_nimble_enable(_nimble_host_task); @@ -285,9 +279,7 @@ esp_err_t Blufi::_host_deinit(void) { return ret; } -esp_err_t Blufi::_gap_register_callback(void) { - return ESP_OK; // For NimBLE, GAP callbacks are handled differently -} +esp_err_t Blufi::_gap_register_callback(void) { return ESP_OK; } esp_err_t Blufi::_host_and_cb_init() { static esp_blufi_callbacks_t blufi_callbacks = { @@ -329,7 +321,6 @@ esp_err_t Blufi::_controller_init() { } #ifdef CONFIG_BT_NIMBLE_ENABLED - // For NimBLE, host init needs to be done after controller init ret = esp_nimble_init(); if (ret) { ESP_LOGE(BLUFI_TAG, "esp_nimble_init() failed: %s", esp_err_to_name(ret)); @@ -350,7 +341,7 @@ esp_err_t Blufi::_controller_deinit() { } return ret; } -#endif // Generic controller init +#endif static int myrand(void *rng_state, unsigned char *output, size_t len) { esp_fill_random(output, len); @@ -404,7 +395,7 @@ void Blufi::_dh_negotiate_data_handler(uint8_t *data, int len, uint8_t **output_ uint8_t type = data[0]; switch (type) { - case 0x00: /* DH_PARAM_LEN */ + case 0x00: if (len < 3) { ESP_LOGE(BLUFI_TAG, "DH_PARAM_LEN packet too short"); btc_blufi_report_error(ESP_BLUFI_DATA_FORMAT_ERROR); @@ -422,7 +413,7 @@ void Blufi::_dh_negotiate_data_handler(uint8_t *data, int len, uint8_t **output_ btc_blufi_report_error(ESP_BLUFI_DH_MALLOC_ERROR); } break; - case 0x01: /* DH_PARAM_DATA */ { + case 0x01: { if (m_sec->dh_param == nullptr) { ESP_LOGE(BLUFI_TAG, "DH param not allocated"); btc_blufi_report_error(ESP_BLUFI_DH_PARAM_ERROR); @@ -540,6 +531,119 @@ int Blufi::_get_softap_conn_num() { return 0; } +void Blufi::start_wifi_scan() { + ESP_LOGI(BLUFI_TAG, "Starting dedicated WiFi scan"); + + // Check if a scan is already in progress + if (m_scan_in_progress) { + ESP_LOGW(BLUFI_TAG, "Scan already in progress, skipping"); + return; + } + + m_scan_in_progress = true; + + // Get current WiFi mode + wifi_mode_t current_mode; + esp_err_t err = esp_wifi_get_mode(¤t_mode); + + if (current_mode == WIFI_MODE_AP) { + // If in AP mode, temporarily switch to APSTA to allow scanning + ESP_LOGI(BLUFI_TAG, "WiFi in AP mode"); + err = esp_wifi_set_mode(WIFI_MODE_STA); + if (err != ESP_OK) { + ESP_LOGE(BLUFI_TAG, "Failed to set WiFi mode to STA: %s", esp_err_to_name(err)); + m_scan_in_progress = false; + return; + } + // Need to restart WiFi for mode change to take effect + err = esp_wifi_start(); + if (err != ESP_OK) { + ESP_LOGE(BLUFI_TAG, "Failed to start WiFi after mode switch: %s", esp_err_to_name(err)); + m_scan_in_progress = false; + return; + } + // Register scan event handler + esp_event_handler_instance_t scan_event_instance; + esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, + &Blufi::_wifi_scan_event_handler, this, + &scan_event_instance); + + // Start scan + err = esp_wifi_scan_start(NULL, false); + if (err != ESP_OK) { + ESP_LOGE(BLUFI_TAG, "Failed to start WiFi scan: %s", esp_err_to_name(err)); + m_scan_in_progress = false; + return; + } + } else if (current_mode == WIFI_MODE_STA) { + // Start scan + err = esp_wifi_scan_start(NULL, false); + if (err != ESP_OK) { + ESP_LOGE(BLUFI_TAG, "Failed to start WiFi scan: %s", esp_err_to_name(err)); + m_scan_in_progress = false; + return; + } + } else { + ESP_LOGE(BLUFI_TAG, "Unexpected WiFi mode: %d", current_mode); + m_scan_in_progress = false; + return; + } + + ESP_LOGI(BLUFI_TAG, "WiFi scan started"); +} + +void Blufi::_send_wifi_list() { + if (m_ap_records.empty()) { + ESP_LOGW(BLUFI_TAG, "No AP records available to send"); + return; + } + + ESP_LOGI(BLUFI_TAG, "Sending WiFi list with %d APs", m_ap_records.size()); + + std::vector blufi_ap_list; + for (const auto &ap : m_ap_records) { + esp_blufi_ap_record_t blufi_ap; + memset(&blufi_ap, 0, sizeof(blufi_ap)); + memcpy(blufi_ap.ssid, ap.ssid, std::min((size_t)32, sizeof(ap.ssid))); + blufi_ap.rssi = ap.rssi; + blufi_ap_list.push_back(blufi_ap); + } + + esp_blufi_send_wifi_list(blufi_ap_list.size(), blufi_ap_list.data()); + + m_ap_records.clear(); + start_wifi_scan(); +} + +void Blufi::_wifi_scan_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, + void *event_data) { + Blufi *self = static_cast(arg); + + if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_SCAN_DONE) { + ESP_LOGI(BLUFI_TAG, "WiFi scan done"); + + uint16_t ap_num = 0; + esp_wifi_scan_get_ap_num(&ap_num); + + if (ap_num == 0) { + ESP_LOGW(BLUFI_TAG, "No APs found"); + self->m_ap_records.clear(); + } else { + if (static_cast(arg)->m_scan_should_save_ssid == true) { + self->m_ap_records.resize(ap_num); + esp_wifi_scan_get_ap_records(&ap_num, self->m_ap_records.data()); + + ESP_LOGI(BLUFI_TAG, "Found %d APs", ap_num); + for (const auto &ap : self->m_ap_records) { + ESP_LOGI(BLUFI_TAG, " SSID: %s, RSSI: %d, Authmode: %d", (char *)ap.ssid, + ap.rssi, ap.authmode); + } + } + } + self->m_scan_in_progress = false; + } +} + void Blufi::_handle_event(esp_blufi_cb_event_t event, esp_blufi_cb_param_t *param) { switch (event) { case ESP_BLUFI_EVENT_INIT_FINISH: @@ -564,7 +668,6 @@ void Blufi::_handle_event(esp_blufi_cb_event_t event, esp_blufi_cb_param_t *para } else { esp_blufi_adv_stop(); if (!m_deinited) { - // Deinit BLE stack after provisioning completes to free resources. xTaskCreate( [](void *ctx) { static_cast(ctx)->deinit(); @@ -604,33 +707,42 @@ void Blufi::_handle_event(esp_blufi_cb_event_t event, esp_blufi_cb_param_t *para std::string ssid(reinterpret_cast(m_sta_config.sta.ssid)); std::string password(reinterpret_cast(m_sta_config.sta.password)); - // Save credentials through SsidManager SsidManager::GetInstance().AddSsid(ssid, password); - auto &wifi_manager = WifiManager::GetInstance(); - if (!wifi_manager.IsInitialized() && !wifi_manager.Initialize()) { - ESP_LOGE(BLUFI_TAG, "Failed to initialize WifiManager"); - break; - } + m_scan_should_save_ssid = false; - // Track SSID for BLUFI status reporting. m_sta_ssid_len = static_cast(std::min(ssid.size(), sizeof(m_sta_ssid))); memcpy(m_sta_ssid, ssid.c_str(), m_sta_ssid_len); memset(m_sta_bssid, 0, sizeof(m_sta_bssid)); m_sta_connected = false; m_sta_got_ip = false; m_sta_is_connecting = true; - m_sta_conn_info = {}; // Reset connection info + m_sta_conn_info = {}; m_sta_conn_info.sta_ssid = m_sta_ssid; m_sta_conn_info.sta_ssid_len = m_sta_ssid_len; + auto &wifi_manager = WifiManager::GetInstance(); + + if (wifi_manager.IsInitialized()) { + if (wifi_manager.IsConfigMode()) { + wifi_manager.StopConfigAp(); + } + wifi_manager.StopStation(); + } + + if (!wifi_manager.IsInitialized() && !wifi_manager.Initialize()) { + ESP_LOGE(BLUFI_TAG, "Failed to initialize WifiManager"); + break; + } + + vTaskDelay(pdMS_TO_TICKS(500)); + wifi_manager.StartStation(); - // Wait for connection in a separate task to avoid blocking the BLUFI handler. xTaskCreate( [](void *ctx) { auto *self = static_cast(ctx); auto &wifi = WifiManager::GetInstance(); - constexpr int kConnectTimeoutMs = 10000; // 10s + constexpr int kConnectTimeoutMs = 10000; constexpr TickType_t kDelayTick = pdMS_TO_TICKS(200); int waited_ms = 0; @@ -669,7 +781,6 @@ void Blufi::_handle_event(esp_blufi_cb_event_t event, esp_blufi_cb_param_t *para softap_conn_num, &info); ESP_LOGI(BLUFI_TAG, "connected to WiFi"); - // Close BluFi session after successful provisioning to free resources. if (self->m_ble_is_connected) { esp_blufi_disconnect(); } @@ -749,6 +860,14 @@ void Blufi::_handle_event(esp_blufi_cb_event_t event, esp_blufi_cb_param_t *para m_sta_config.sta.password[param->sta_passwd.passwd_len] = '\0'; ESP_LOGI(BLUFI_TAG, "Recv STA PASSWORD : %s", m_sta_config.sta.password); break; + case ESP_BLUFI_EVENT_GET_WIFI_LIST: { + ESP_LOGI(BLUFI_TAG, "BLUFI get wifi list"); + while (m_scan_in_progress) { + vTaskDelay(pdMS_TO_TICKS(500)); + } + _send_wifi_list(); + break; + } default: ESP_LOGW(BLUFI_TAG, "Unhandled event: %d", event); break; diff --git a/main/boards/common/blufi.h b/main/boards/common/blufi.h index 39b84116..2e02f7eb 100644 --- a/main/boards/common/blufi.h +++ b/main/boards/common/blufi.h @@ -1,12 +1,17 @@ #pragma once #include -#include "mbedtls/dhm.h" -#include "mbedtls/aes.h" -#include "esp_err.h" +#include +#include +#include #include "esp_blufi_api.h" -#include "esp_wifi_types.h" - +#include "esp_err.h" +#include "esp_timer.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "mbedtls/aes.h" +#include "mbedtls/dhm.h" +#include "wifi_manager.h" class Blufi { public: @@ -15,6 +20,14 @@ public: */ static Blufi &GetInstance(); + /** + * @brief Start WiFi scan for Blufi provisioning + * This method intelligently handles WiFi scanning based on current WiFi state: + * - If WiFi config mode is active, it uses the existing scan results from WifiConfigurationAp + * - Otherwise, it performs a dedicated scan without interfering with normal WiFi operations + */ + void start_wifi_scan(); + /** * @brief Initializes the Bluetooth controller, host, and Blufi profile. * This is the main entry point to start the Blufi process. @@ -40,7 +53,6 @@ private: ~Blufi(); - // Initialization logic static esp_err_t _controller_init(); @@ -58,7 +70,8 @@ private: void _security_deinit(); - void _dh_negotiate_data_handler(uint8_t *data, int len, uint8_t **output_data, int *output_len, bool *need_free); + void _dh_negotiate_data_handler(uint8_t *data, int len, uint8_t **output_data, int *output_len, + bool *need_free); int _aes_encrypt(uint8_t iv8, uint8_t *crypt_data, int crypt_len); @@ -70,12 +83,19 @@ private: static int _get_softap_conn_num(); - // These C-style functions are registered with ESP-IDF and call the corresponding instance methods. + // WiFi scan methods + void _send_wifi_list(); + void _start_dedicated_wifi_scan(); + static void _wifi_scan_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, + void *event_data); + + // These C-style functions are registered with ESP-IDF and call the corresponding instance + // methods. static void _event_callback_trampoline(esp_blufi_cb_event_t event, esp_blufi_cb_param_t *param); - static void _negotiate_data_handler_trampoline(uint8_t *data, int len, uint8_t **output_data, int *output_len, - bool *need_free); + static void _negotiate_data_handler_trampoline(uint8_t *data, int len, uint8_t **output_data, + int *output_len, bool *need_free); static int _encrypt_func_trampoline(uint8_t iv8, uint8_t *crypt_data, int crypt_len); @@ -91,12 +111,12 @@ private: // Security context, formerly blufi_sec struct struct BlufiSecurity { -#define DH_SELF_PUB_KEY_LEN 128 +#define DH_SELF_PUB_KEY_LEN 128 uint8_t self_public_key[DH_SELF_PUB_KEY_LEN]; -#define SHARE_KEY_LEN 128 +#define SHARE_KEY_LEN 128 uint8_t share_key[SHARE_KEY_LEN]; size_t share_len; -#define PSK_LEN 16 +#define PSK_LEN 16 uint8_t psk[PSK_LEN]; uint8_t *dh_param; int dh_param_len; @@ -109,7 +129,6 @@ private: // State variables wifi_config_t m_sta_config{}; - wifi_config_t m_ap_config{}; bool m_ble_is_connected; bool m_sta_connected; bool m_sta_got_ip; @@ -120,4 +139,9 @@ private: int m_sta_ssid_len; bool m_sta_is_connecting; esp_blufi_extra_info_t m_sta_conn_info{}; + + // WiFi scan related + std::vector m_ap_records; + bool m_scan_in_progress = false; + bool m_scan_should_save_ssid = true; }; diff --git a/main/boards/common/wifi_board.cc b/main/boards/common/wifi_board.cc index 77aff4fc..c24ed315 100644 --- a/main/boards/common/wifi_board.cc +++ b/main/boards/common/wifi_board.cc @@ -175,8 +175,7 @@ void WifiBoard::StartWifiConfigMode() { Application::GetInstance().Alert(Lang::Strings::WIFI_CONFIG_MODE, hint.c_str(), "gear", Lang::Sounds::OGG_WIFICONFIG); }); -#endif -#if CONFIG_USE_ESP_BLUFI_WIFI_PROVISIONING +#elif CONFIG_USE_ESP_BLUFI_WIFI_PROVISIONING auto &blufi = Blufi::GetInstance(); // initialize esp-blufi protocol blufi.init();