#include "blufi.h" #include #include #include #include #include #include "esp_bt.h" #include "esp_event.h" #include "esp_log.h" #include "esp_timer.h" #include "esp_wifi.h" #include "freertos/task.h" #include "wifi_manager.h" #define BLUFI_DEVICE_NAME "Xiaozhi-Blufi" #ifdef CONFIG_BT_BLUEDROID_ENABLED #include "esp_bt_device.h" #include "esp_bt_main.h" #include "esp_gap_ble_api.h" #endif #ifdef CONFIG_BT_NIMBLE_ENABLED #include "console/console.h" #include "host/ble_hs.h" #include "nimble/nimble_port.h" #include "nimble/nimble_port_freertos.h" #include "services/gap/ble_svc_gap.h" extern void esp_blufi_gatt_svr_register_cb(struct ble_gatt_register_ctxt* ctxt, void* arg); extern int esp_blufi_gatt_svr_init(void); extern void esp_blufi_gatt_svr_deinit(void); extern void esp_blufi_btc_init(void); extern void esp_blufi_btc_deinit(void); #endif extern "C" { void esp_blufi_adv_start(void); void esp_blufi_adv_stop(void); void esp_blufi_disconnect(void); void btc_blufi_report_error(esp_blufi_error_state_t state); #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 #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); void esp_blufi_gatt_svr_deinit(void); void esp_blufi_btc_init(void); void esp_blufi_btc_deinit(void); #endif } #include #include "esp_crc.h" #include "esp_random.h" #include "mbedtls/md5.h" #include "ssid_manager.h" static const char* BLUFI_TAG = "BLUFI_CLASS"; static wifi_mode_t GetWifiModeWithFallback(const WifiManager& wifi) { if (wifi.IsConfigMode()) { return WIFI_MODE_AP; } if (wifi.IsInitialized() && wifi.IsConnected()) { return WIFI_MODE_STA; } wifi_mode_t mode = WIFI_MODE_STA; esp_wifi_get_mode(&mode); return mode; } Blufi& Blufi::GetInstance() { static Blufi instance; return instance; } Blufi::Blufi() : m_sec(nullptr), m_ble_is_connected(false), m_sta_connected(false), m_sta_got_ip(false), m_provisioned(false), m_deinited(false), m_sta_ssid_len(0), m_sta_is_connecting(false) { memset(&m_sta_config, 0, sizeof(m_sta_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)); } Blufi::~Blufi() { if (m_sec) { _security_deinit(); } } esp_err_t Blufi::init() { 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) { ESP_LOGE(BLUFI_TAG, "BLUFI controller init failed: %s", esp_err_to_name(ret)); return ret; } #endif ret = _host_and_cb_init(); if (ret) { ESP_LOGE(BLUFI_TAG, "BLUFI host and cb init failed: %s", esp_err_to_name(ret)); return ret; } ESP_LOGI(BLUFI_TAG, "BLUFI VERSION %04x", esp_blufi_get_version()); return ESP_OK; } esp_err_t Blufi::deinit() { esp_err_t ret = ESP_OK; if (inited_) { if (m_deinited) { return ESP_OK; } m_deinited = true; ret = _host_deinit(); if (ret) { ESP_LOGE(BLUFI_TAG, "Host deinit failed: %s", esp_err_to_name(ret)); } #if CONFIG_BT_CONTROLLER_ENABLED || !CONFIG_BT_NIMBLE_ENABLED ret = _controller_deinit(); if (ret) { ESP_LOGE(BLUFI_TAG, "Controller deinit failed: %s", esp_err_to_name(ret)); } #endif } return ret; } #ifdef CONFIG_BT_BLUEDROID_ENABLED esp_err_t Blufi::_host_init() { esp_err_t ret = esp_bluedroid_init(); if (ret) { ESP_LOGE(BLUFI_TAG, "%s init bluedroid failed: %s", __func__, esp_err_to_name(ret)); return ESP_FAIL; } ret = esp_bluedroid_enable(); if (ret) { ESP_LOGE(BLUFI_TAG, "%s enable bluedroid failed: %s", __func__, esp_err_to_name(ret)); return ESP_FAIL; } ESP_LOGI(BLUFI_TAG, "BD ADDR: " ESP_BD_ADDR_STR, ESP_BD_ADDR_HEX(esp_bt_dev_get_address())); return ESP_OK; } esp_err_t Blufi::_host_deinit() { esp_err_t ret = esp_blufi_profile_deinit(); if (ret != ESP_OK) return ret; ret = esp_bluedroid_disable(); if (ret) { ESP_LOGE(BLUFI_TAG, "%s disable bluedroid failed: %s", __func__, esp_err_to_name(ret)); return ESP_FAIL; } ret = esp_bluedroid_deinit(); if (ret) { ESP_LOGE(BLUFI_TAG, "%s deinit bluedroid failed: %s", __func__, esp_err_to_name(ret)); return ESP_FAIL; } return ESP_OK; } esp_err_t Blufi::_gap_register_callback() { esp_err_t rc = esp_ble_gap_register_callback(esp_blufi_gap_event_handler); if (rc) { return rc; } return esp_blufi_profile_init(); } esp_err_t Blufi::_host_and_cb_init() { static esp_blufi_callbacks_t blufi_callbacks = { .event_cb = &_event_callback_trampoline, .negotiate_data_handler = &_negotiate_data_handler_trampoline, .encrypt_func = &_encrypt_func_trampoline, .decrypt_func = &_decrypt_func_trampoline, .checksum_func = &_checksum_func_trampoline, }; esp_err_t ret = _host_init(); if (ret) { ESP_LOGE(BLUFI_TAG, "%s initialise host failed: %s", __func__, esp_err_to_name(ret)); return ret; } ret = esp_blufi_register_callbacks(&blufi_callbacks); if (ret) { ESP_LOGE(BLUFI_TAG, "%s blufi register failed, error code = %x", __func__, ret); return ret; } ret = _gap_register_callback(); if (ret) { ESP_LOGE(BLUFI_TAG, "%s gap register failed, error code = %x", __func__, ret); return ret; } return ESP_OK; } #endif /* CONFIG_BT_BLUEDROID_ENABLED */ #ifdef CONFIG_BT_NIMBLE_ENABLED // Stubs for NimBLE specific store functionality void ble_store_config_init(); void Blufi::_nimble_on_reset(int reason) { ESP_LOGE(BLUFI_TAG, "NimBLE Resetting state; reason=%d", reason); } 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(); nimble_port_freertos_deinit(); } esp_err_t Blufi::_host_init() { 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; ble_hs_cfg.sm_io_cap = 4; #ifdef CONFIG_EXAMPLE_BONDING ble_hs_cfg.sm_bonding = 1; #endif int rc = esp_blufi_gatt_svr_init(); assert(rc == 0); ble_store_config_init(); esp_blufi_btc_init(); esp_err_t err = esp_nimble_enable(_nimble_host_task); if (err) { ESP_LOGE(BLUFI_TAG, "%s failed: %s", __func__, esp_err_to_name(err)); return ESP_FAIL; } return ESP_OK; } esp_err_t Blufi::_host_deinit(void) { esp_err_t ret = nimble_port_stop(); if (ret == ESP_OK) { esp_nimble_deinit(); } esp_blufi_gatt_svr_deinit(); ret = esp_blufi_profile_deinit(); esp_blufi_btc_deinit(); return ret; } 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 = { .event_cb = &_event_callback_trampoline, .negotiate_data_handler = &_negotiate_data_handler_trampoline, .encrypt_func = &_encrypt_func_trampoline, .decrypt_func = &_decrypt_func_trampoline, .checksum_func = &_checksum_func_trampoline, }; esp_err_t ret = esp_blufi_register_callbacks(&blufi_callbacks); if (ret) { ESP_LOGE(BLUFI_TAG, "%s blufi register failed, error code = %x", __func__, ret); return ret; } // Host init must be called after registering callbacks for NimBLE ret = _host_init(); if (ret) { ESP_LOGE(BLUFI_TAG, "%s initialise host failed: %s", __func__, esp_err_to_name(ret)); return ret; } return ESP_OK; } #endif /* CONFIG_BT_NIMBLE_ENABLED */ #if CONFIG_BT_CONTROLLER_ENABLED || !CONFIG_BT_NIMBLE_ENABLED esp_err_t Blufi::_controller_init() { esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); esp_err_t ret = esp_bt_controller_init(&bt_cfg); if (ret) { ESP_LOGE(BLUFI_TAG, "%s initialize controller failed: %s", __func__, esp_err_to_name(ret)); return ret; } ret = esp_bt_controller_enable(ESP_BT_MODE_BLE); if (ret) { ESP_LOGE(BLUFI_TAG, "%s enable controller failed: %s", __func__, esp_err_to_name(ret)); return ret; } #ifdef CONFIG_BT_NIMBLE_ENABLED ret = esp_nimble_init(); if (ret) { ESP_LOGE(BLUFI_TAG, "esp_nimble_init() failed: %s", esp_err_to_name(ret)); return ret; } #endif return ESP_OK; } esp_err_t Blufi::_controller_deinit() { esp_err_t ret = esp_bt_controller_disable(); if (ret) { ESP_LOGE(BLUFI_TAG, "%s disable controller failed: %s", __func__, esp_err_to_name(ret)); } ret = esp_bt_controller_deinit(); if (ret) { ESP_LOGE(BLUFI_TAG, "%s deinit controller failed: %s", __func__, esp_err_to_name(ret)); } return ret; } #endif static int myrand(void* rng_state, unsigned char* output, size_t len) { esp_fill_random(output, len); return 0; } void Blufi::_security_init() { m_sec = new BlufiSecurity(); if (m_sec == nullptr) { ESP_LOGE(BLUFI_TAG, "Failed to allocate security context"); return; } memset(m_sec, 0, sizeof(BlufiSecurity)); m_sec->dhm = new mbedtls_dhm_context(); m_sec->aes = new mbedtls_aes_context(); mbedtls_dhm_init(m_sec->dhm); mbedtls_aes_init(m_sec->aes); memset(m_sec->iv, 0x0, sizeof(m_sec->iv)); } void Blufi::_security_deinit() { if (m_sec == nullptr) return; if (m_sec->dh_param) { free(m_sec->dh_param); } mbedtls_dhm_free(m_sec->dhm); mbedtls_aes_free(m_sec->aes); delete m_sec->dhm; delete m_sec->aes; delete m_sec; m_sec = nullptr; } void Blufi::_dh_negotiate_data_handler(uint8_t* data, int len, uint8_t** output_data, int* output_len, bool* need_free) { if (m_sec == nullptr) { ESP_LOGE(BLUFI_TAG, "Security not initialized in DH handler"); btc_blufi_report_error(ESP_BLUFI_INIT_SECURITY_ERROR); return; } if (len < 1) { ESP_LOGE(BLUFI_TAG, "DH handler: data too short"); btc_blufi_report_error(ESP_BLUFI_DATA_FORMAT_ERROR); return; } uint8_t type = data[0]; switch (type) { case 0x00: if (len < 3) { ESP_LOGE(BLUFI_TAG, "DH_PARAM_LEN packet too short"); btc_blufi_report_error(ESP_BLUFI_DATA_FORMAT_ERROR); return; } m_sec->dh_param_len = (data[1] << 8) | data[2]; if (m_sec->dh_param) { free(m_sec->dh_param); m_sec->dh_param = nullptr; } m_sec->dh_param = (uint8_t*)malloc(m_sec->dh_param_len); if (m_sec->dh_param == nullptr) { ESP_LOGE(BLUFI_TAG, "DH malloc failed"); btc_blufi_report_error(ESP_BLUFI_DH_MALLOC_ERROR); } break; 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); return; } uint8_t* param = m_sec->dh_param; memcpy(m_sec->dh_param, &data[1], m_sec->dh_param_len); int ret = mbedtls_dhm_read_params(m_sec->dhm, ¶m, ¶m[m_sec->dh_param_len]); if (ret) { ESP_LOGE(BLUFI_TAG, "mbedtls_dhm_read_params failed %d", ret); btc_blufi_report_error(ESP_BLUFI_READ_PARAM_ERROR); return; } const int dhm_len = mbedtls_dhm_get_len(m_sec->dhm); ret = mbedtls_dhm_make_public(m_sec->dhm, dhm_len, m_sec->self_public_key, dhm_len, myrand, NULL); if (ret != 0) { ESP_LOGE(BLUFI_TAG, "mbedtls_dhm_make_public failed: %d", ret); btc_blufi_report_error(ESP_BLUFI_MAKE_PUBLIC_ERROR); return; } ret = mbedtls_dhm_calc_secret(m_sec->dhm, m_sec->share_key, SHARE_KEY_LEN, &m_sec->share_len, myrand, NULL); if (ret != 0) { ESP_LOGE(BLUFI_TAG, "mbedtls_dhm_calc_secret failed: %d", ret); btc_blufi_report_error(ESP_BLUFI_ENCRYPT_ERROR); return; } ret = mbedtls_md5(m_sec->share_key, m_sec->share_len, m_sec->psk); if (ret != 0) { ESP_LOGE(BLUFI_TAG, "mbedtls_md5 failed: %d", ret); btc_blufi_report_error(ESP_BLUFI_CALC_MD5_ERROR); return; } ret = mbedtls_aes_setkey_enc(m_sec->aes, m_sec->psk, PSK_LEN * 8); if (ret != 0) { ESP_LOGE(BLUFI_TAG, "mbedtls_aes_setkey_enc failed: -0x%04X", -ret); btc_blufi_report_error(ESP_BLUFI_ENCRYPT_ERROR); return; } *output_data = m_sec->self_public_key; *output_len = dhm_len; *need_free = false; ESP_LOGI(BLUFI_TAG, "DH negotiation completed successfully"); free(m_sec->dh_param); m_sec->dh_param = nullptr; m_sec->dh_param_len = 0; break; } default: ESP_LOGE(BLUFI_TAG, "DH handler unknown type: %d", type); } } int Blufi::_aes_encrypt(uint8_t iv8, uint8_t* crypt_data, int crypt_len) { if (!m_sec || !m_sec->aes || !crypt_data || crypt_len <= 0) { ESP_LOGE(BLUFI_TAG, "Invalid parameters for AES encryption"); return -ESP_ERR_INVALID_ARG; } size_t iv_offset = 0; uint8_t iv0[16]; memcpy(iv0, m_sec->iv, 16); iv0[0] = iv8; int ret = mbedtls_aes_crypt_cfb128(m_sec->aes, MBEDTLS_AES_ENCRYPT, crypt_len, &iv_offset, iv0, crypt_data, crypt_data); if (ret == 0) { return crypt_len; } else { ESP_LOGE(BLUFI_TAG, "AES encrypt failed: %d", ret); return ret; } } int Blufi::_aes_decrypt(uint8_t iv8, uint8_t* crypt_data, int crypt_len) { if (!m_sec || !m_sec->aes || !crypt_data || crypt_len < 0) { ESP_LOGE(BLUFI_TAG, "Invalid parameters for AES decryption %p %p %d", m_sec->aes, crypt_data, crypt_len); return -ESP_ERR_INVALID_ARG; } size_t iv_offset = 0; uint8_t iv0[16]; memcpy(iv0, m_sec->iv, 16); iv0[0] = iv8; int ret = mbedtls_aes_crypt_cfb128(m_sec->aes, MBEDTLS_AES_DECRYPT, crypt_len, &iv_offset, iv0, crypt_data, crypt_data); if (ret != 0) { ESP_LOGE(BLUFI_TAG, "AES decrypt failed: %d", ret); return ret; } else { return crypt_len; } } uint16_t Blufi::_crc_checksum(uint8_t iv8, uint8_t* data, int len) { return esp_crc16_be(0, data, len); } int Blufi::_get_softap_conn_num() { auto& wifi = WifiManager::GetInstance(); if (!wifi.IsInitialized() || !wifi.IsConfigMode()) { return 0; } wifi_sta_list_t sta_list{}; if (esp_wifi_ap_get_sta_list(&sta_list) == ESP_OK) { return sta_list.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: ESP_LOGI(BLUFI_TAG, "BLUFI init finish"); esp_ble_gap_set_device_name(BLUFI_DEVICE_NAME); esp_blufi_adv_start(); break; case ESP_BLUFI_EVENT_DEINIT_FINISH: ESP_LOGI(BLUFI_TAG, "BLUFI deinit finish"); break; case ESP_BLUFI_EVENT_BLE_CONNECT: ESP_LOGI(BLUFI_TAG, "BLUFI ble connect"); m_ble_is_connected = true; esp_blufi_adv_stop(); _security_init(); break; case ESP_BLUFI_EVENT_BLE_DISCONNECT: ESP_LOGI(BLUFI_TAG, "BLUFI ble disconnect"); m_ble_is_connected = false; _security_deinit(); if (!m_provisioned) { esp_blufi_adv_start(); } else { esp_blufi_adv_stop(); if (!m_deinited) { xTaskCreate( [](void* ctx) { static_cast(ctx)->deinit(); vTaskDelete(nullptr); }, "blufi_deinit", 4096, this, 5, nullptr); } } break; case ESP_BLUFI_EVENT_SET_WIFI_OPMODE: { ESP_LOGI(BLUFI_TAG, "BLUFI Set WIFI opmode %d", param->wifi_mode.op_mode); auto& wifi_manager = WifiManager::GetInstance(); if (!wifi_manager.IsInitialized() && !wifi_manager.Initialize()) { ESP_LOGE(BLUFI_TAG, "Failed to initialize WifiManager for opmode change"); break; } switch (param->wifi_mode.op_mode) { case WIFI_MODE_STA: wifi_manager.StartStation(); break; case WIFI_MODE_AP: wifi_manager.StartConfigAp(); break; case WIFI_MODE_APSTA: ESP_LOGW(BLUFI_TAG, "APSTA mode not supported, starting station only"); wifi_manager.StartStation(); break; default: wifi_manager.StopStation(); wifi_manager.StopConfigAp(); break; } break; } case ESP_BLUFI_EVENT_REQ_CONNECT_TO_AP: { ESP_LOGI(BLUFI_TAG, "BLUFI request wifi connect to AP via esp-wifi-connect"); std::string ssid(reinterpret_cast(m_sta_config.sta.ssid)); std::string password(reinterpret_cast(m_sta_config.sta.password)); SsidManager::GetInstance().AddSsid(ssid, password); m_scan_should_save_ssid = false; 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 = {}; 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(); xTaskCreate( [](void* ctx) { auto* self = static_cast(ctx); auto& wifi = WifiManager::GetInstance(); constexpr int kConnectTimeoutMs = 10000; constexpr TickType_t kDelayTick = pdMS_TO_TICKS(200); int waited_ms = 0; while (waited_ms < kConnectTimeoutMs && !wifi.IsConnected()) { vTaskDelay(kDelayTick); waited_ms += 200; } wifi_mode_t mode = GetWifiModeWithFallback(wifi); const int softap_conn_num = _get_softap_conn_num(); if (wifi.IsConnected()) { self->m_sta_is_connecting = false; self->m_sta_connected = true; self->m_sta_got_ip = true; self->m_provisioned = true; auto current_ssid = wifi.GetSsid(); if (!current_ssid.empty()) { self->m_sta_ssid_len = static_cast( std::min(current_ssid.size(), sizeof(self->m_sta_ssid))); memcpy(self->m_sta_ssid, current_ssid.c_str(), self->m_sta_ssid_len); } wifi_ap_record_t ap_info{}; if (esp_wifi_sta_get_ap_info(&ap_info) == ESP_OK) { memcpy(self->m_sta_bssid, ap_info.bssid, sizeof(self->m_sta_bssid)); } esp_blufi_extra_info_t info = {}; memcpy(info.sta_bssid, self->m_sta_bssid, sizeof(self->m_sta_bssid)); info.sta_bssid_set = true; info.sta_ssid = self->m_sta_ssid; info.sta_ssid_len = self->m_sta_ssid_len; esp_blufi_send_wifi_conn_report(mode, ESP_BLUFI_STA_CONN_SUCCESS, softap_conn_num, &info); ESP_LOGI(BLUFI_TAG, "connected to WiFi"); if (self->m_ble_is_connected) { esp_blufi_disconnect(); } } else { self->m_sta_is_connecting = false; self->m_sta_connected = false; self->m_sta_got_ip = false; esp_blufi_extra_info_t info = {}; info.sta_ssid = self->m_sta_ssid; info.sta_ssid_len = self->m_sta_ssid_len; esp_blufi_send_wifi_conn_report(mode, ESP_BLUFI_STA_CONN_FAIL, softap_conn_num, &info); ESP_LOGE(BLUFI_TAG, "Failed to connect to WiFi via esp-wifi-connect"); } vTaskDelete(nullptr); }, "blufi_wifi_conn", 4096, this, 5, nullptr); break; } case ESP_BLUFI_EVENT_REQ_DISCONNECT_FROM_AP: ESP_LOGI(BLUFI_TAG, "BLUFI request wifi disconnect from AP"); if (WifiManager::GetInstance().IsInitialized()) { WifiManager::GetInstance().StopStation(); } m_sta_is_connecting = false; m_sta_connected = false; m_sta_got_ip = false; break; case ESP_BLUFI_EVENT_GET_WIFI_STATUS: { auto& wifi = WifiManager::GetInstance(); wifi_mode_t mode = GetWifiModeWithFallback(wifi); const int softap_conn_num = _get_softap_conn_num(); if (wifi.IsInitialized() && wifi.IsConnected()) { m_sta_connected = true; m_sta_got_ip = true; auto current_ssid = wifi.GetSsid(); if (!current_ssid.empty()) { m_sta_ssid_len = static_cast(std::min(current_ssid.size(), sizeof(m_sta_ssid))); memcpy(m_sta_ssid, current_ssid.c_str(), m_sta_ssid_len); } esp_blufi_extra_info_t info; memset(&info, 0, sizeof(esp_blufi_extra_info_t)); memcpy(info.sta_bssid, m_sta_bssid, 6); info.sta_ssid = m_sta_ssid; info.sta_ssid_len = m_sta_ssid_len; esp_blufi_send_wifi_conn_report(mode, ESP_BLUFI_STA_CONN_SUCCESS, softap_conn_num, &info); } else if (m_sta_is_connecting) { esp_blufi_send_wifi_conn_report(mode, ESP_BLUFI_STA_CONNECTING, softap_conn_num, &m_sta_conn_info); } else { esp_blufi_send_wifi_conn_report(mode, ESP_BLUFI_STA_CONN_FAIL, softap_conn_num, &m_sta_conn_info); } ESP_LOGI(BLUFI_TAG, "BLUFI get wifi status"); break; } case ESP_BLUFI_EVENT_RECV_STA_BSSID: memcpy(m_sta_config.sta.bssid, param->sta_bssid.bssid, 6); m_sta_config.sta.bssid_set = true; ESP_LOGI(BLUFI_TAG, "Recv STA BSSID"); break; case ESP_BLUFI_EVENT_RECV_STA_SSID: strncpy((char*)m_sta_config.sta.ssid, (char*)param->sta_ssid.ssid, param->sta_ssid.ssid_len); m_sta_config.sta.ssid[param->sta_ssid.ssid_len] = '\0'; ESP_LOGI(BLUFI_TAG, "Recv STA SSID: %s", m_sta_config.sta.ssid); break; case ESP_BLUFI_EVENT_RECV_STA_PASSWD: strncpy((char*)m_sta_config.sta.password, (char*)param->sta_passwd.passwd, param->sta_passwd.passwd_len); 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; } } void Blufi::_event_callback_trampoline(esp_blufi_cb_event_t event, esp_blufi_cb_param_t* param) { GetInstance()._handle_event(event, param); } void Blufi::_negotiate_data_handler_trampoline(uint8_t* data, int len, uint8_t** output_data, int* output_len, bool* need_free) { GetInstance()._dh_negotiate_data_handler(data, len, output_data, output_len, need_free); } int Blufi::_encrypt_func_trampoline(uint8_t iv8, uint8_t* crypt_data, int crypt_len) { return GetInstance()._aes_encrypt(iv8, crypt_data, crypt_len); } int Blufi::_decrypt_func_trampoline(uint8_t iv8, uint8_t* crypt_data, int crypt_len) { return GetInstance()._aes_decrypt(iv8, crypt_data, crypt_len); } uint16_t Blufi::_checksum_func_trampoline(uint8_t iv8, uint8_t* data, int len) { return _crc_checksum(iv8, data, len); }