Fixed compilation errors that occurred after enabling blufi (#1677)

This commit is contained in:
Wang is proud
2026-01-24 21:55:24 +08:00
committed by GitHub
parent 6b3659c2f5
commit 3a52761d30
5 changed files with 207 additions and 64 deletions

View File

@@ -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 或自研客户端)连接设备,发送 WiFi SSID/密码。
1) 手机端通过 BluFi如官方 EspBlufi App 或自研客户端)连接设备,发送 WiFi SSID/密码手机端可以通过blufi协议获取设备端扫描到的WiFi列表
2) 设备侧在 `ESP_BLUFI_EVENT_REQ_CONNECT_TO_AP` 中将凭据写入 `SsidManager`(存储到 NVS属于 `esp-wifi-connect` 组件)。
3) 随后启动 `WifiStation` 扫描并连接;状态通过 BluFi 返回。
4) 配网成功后设备会自动连接新 WiFi失败则返回失败状态。
@@ -30,7 +30,7 @@ BluFi
## 注意事项
- BluFi 与 Hotspot/声波配网可以同时编译,但会同时启动,增加内存占用。建议在 menuconfig 中只保留一种方式。
- BluFi 配网不支持与热点配网同时开启。如果热点配网已经启动,则默认使用热点配网。请在 menuconfig 中只保留一种配网方式。
- 若多次测试,建议清除或覆盖存储的 SSID`wifi` 命名空间),避免旧配置干扰。
- 如果使用自定义 BluFi 客户端,需遵循官方协议帧格式,参考上文官方文档链接。
- 官方文档中已提供EspBlufi APP下载地址

View File

@@ -789,6 +789,7 @@ idf_component_register(SRCS ${SOURCES}
spi_flash
console
efuse
bt
)
# Use target_compile_definitions to define BOARD_TYPE, BOARD_NAME

View File

@@ -3,25 +3,21 @@
#include <cassert>
#include <cstring>
#include <string>
#include "application.h"
#include <vector>
#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 <wifi_station.h>
#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(&current_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<esp_blufi_ap_record_t> 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<Blufi *>(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<Blufi *>(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<Blufi *>(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<const char *>(m_sta_config.sta.ssid));
std::string password(reinterpret_cast<const char *>(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<int>(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<Blufi *>(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;

View File

@@ -1,12 +1,17 @@
#pragma once
#include <aes/esp_aes.h>
#include "mbedtls/dhm.h"
#include "mbedtls/aes.h"
#include "esp_err.h"
#include <cassert>
#include <cstring>
#include <vector>
#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<wifi_ap_record_t> m_ap_records;
bool m_scan_in_progress = false;
bool m_scan_should_save_ssid = true;
};

View File

@@ -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();