发帖
3 0 0

AI-WB2配网【下】

WildboarG
论坛元老

23

主题

159

回帖

3650

积分

论坛元老

积分
3650
Ai-WB2系列 55 3 3 天前

AI-WB2蓝牙配网


Static Badge Static Badge Static Badge

蓝牙配网


原理:手机 App → 通过蓝牙 → 发送 Wi-Fi SSID & 密码 → Wi-Fi 设备接收 & 连接网络

1️⃣ 设备进入蓝牙配网模式

  • 设备(如 AI-WB2、ESP32 等)启用 BLE 并作为 ****蓝牙从设备(Peripheral)
  • 设备会广播 BLE 服务 UUID,等待手机或 PC 连接

2️⃣ 手机 App 连接蓝牙

  • 手机打开蓝牙,扫描附近的 BLE 设备(可以筛选特定 UUID)
  • 连接到目标设备后,发现自定义 BLE 服务 & 特征(Characteristic)

3️⃣ 手机发送 Wi-Fi 信息

  • 通过 BLE 特征(Characteristic) 向设备写入:
    • SSID(Wi-Fi 名称)
    • 密码
    • 加密方式(可选)
  • 设备解析收到的数据,并存储到 Flash 或 RAM 中。

4️⃣ 设备尝试连接 Wi-Fi

  • 设备断开蓝牙连接,尝试用接收到的 SSID & 密码连接 Wi-Fi。
  • 连接成功后,可以返回成功状态给手机。

图片.png

代码示例


#include <FreeRTOS.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <task.h>
#include <timers.h>
​
#include <lwip/tcpip.h>
​
#include <bl602_glb.h>
​
#include <bl_sys.h>
#include <bl_uart.h>
#include <cli.h>
​
//////////////////////////////////
#include "axk_blufi.h"
#include "ble_interface.h"
#include "blufi.h"
#include "blufi_api.h"
#include "blufi_hal.h"
#include "blufi_init.h"
#include "blufi_security.h"
#include "wifi_interface.h"
#include <../wifi_mgmr.h>
//////////////////////////////////
​
static int scan_counter;
static bool ble_is_connected = false;
static bool gl_sta_connected = false;
blufi_config_t g_blufi_config = {0};
​
static void blufi_wifi_event(int event, void *param) { //wifi事件回调
  switch (event) {
​
  case BLUFI_STATION_CONNECTED: 
    gl_sta_connected = true;
    break;
  case BLUFI_STATION_DISCONNECTED:
    gl_sta_connected = false;
    break;
  case BLUFI_STATION_GOT_IP: {
    axk_blufi_extra_info_t info;
    memset(&info, 0, sizeof(axk_blufi_extra_info_t));
    wifi_conn_ap_info_get(&g_blufi_config.wifi.sta);
    memcpy(info.sta_bssid, g_blufi_config.wifi.sta.cwjap_param.bssid, 6);
    info.sta_bssid_set = true;
    info.sta_ssid = (uint8_t *)g_blufi_config.wifi.sta.cwjap_param.ssid;
    info.sta_ssid_len = strlen(g_blufi_config.wifi.sta.cwjap_param.ssid);
​
    if (ble_is_connected == true) {
      axk_blufi_send_wifi_conn_report(g_blufi_config.wifi.cwmode,
                                      _BLUFI_STA_CONN_SUCCESS, 0, &info);
    } else {
      printf("BLUFI BLE is not connected yet\r\n");
    }
​
    printf("BLUFI save ssid&&pwd \r\n");
    printf("START YOUR FOUTION:\r\n");  //一般联网成功这里开始写用户自定义任务
    g_blufi_config.wifi.cwmode = WIFIMODE_STA;
  } break;
  default:
    break;
  }
}
​
static void example_event_callback(_blufi_cb_event_t event,
                                   _blufi_cb_param_t *param) { //蓝牙事件回调
  switch (event) {
  case AXK_BLUFI_EVENT_INIT_FINISH://BLUFI初始化完成开启蓝牙广播
    printf("BLUFI init finish\n");
    axk_blufi_adv_start();
    break;
  case AXK_BLUFI_EVENT_DEINIT_FINISH://反初始化
    printf("BLUFI deinit finish\n");
    break;
  case AXK_BLUFI_EVENT_BLE_CONNECT: //蓝牙已连接
    printf("BLUFI ble connect\n");
    ble_is_connected = true;
    axk_blufi_adv_stop();
    blufi_security_init();         
    break;
  case AXK_BLUFI_EVENT_BLE_DISCONNECT: //蓝牙断开连接
    printf("BLUFI ble disconnect\n");
    ble_is_connected = false;
    blufi_security_deinit();
    axk_blufi_adv_start();
    break;
  case AXK_BLUFI_EVENT_SET_WIFI_OPMODE: //设置WIFI工作模式,一般都是配网,也就是用wb2连接别人,那就是STA
    printf("BLUFI Set WIFI opmode %d\n", param->wifi_mode.op_mode);
    g_blufi_config.wifi.cwmode = WIFIMODE_STA;
    break;
  case AXK_BLUFI_EVENT_REQ_CONNECT_TO_AP: { //蓝牙端获取WIFI信息并请求连接ap
    cwjap_param_t cwjap_param = {0};
    printf("BLUFI requset wifi connect to AP\n");
    cwjap_param = g_blufi_config.wifi.sta.cwjap_param;
    if (axk_hal_conn_ap_info_set(&cwjap_param) != BLUFI_ERR_SUCCESS) {
      printf("BLUFI axk_hal_conn_ap_info_set fail\r\n");
      break;
    }
    g_blufi_config.wifi.sta.state = BLUFI_WIFI_STATE_CONNECTING;
  }
​
  break;
  case AXK_BLUFI_EVENT_REQ_DISCONNECT_FROM_AP://请求设备断开 Wi-Fi
    printf("BLUFI requset wifi disconnect from AP\n");
    axk_hal_disconn_ap();
    break;
  case AXK_BLUFI_EVENT_REPORT_ERROR: //Wi-Fi 连接或 BLUFI 发生错误
    printf("BLUFI report error, error code %d\n", param->report_error.state);
    axk_blufi_send_error_info(param->report_error.state);
    break;
  case AXK_BLUFI_EVENT_GET_WIFI_STATUS: { //查询 Wi-Fi 连接状态
    wifi_mode_t mode;
    mode = g_blufi_config.wifi.cwmode;
​
    if (gl_sta_connected) {
      axk_blufi_extra_info_t info;
      memset(&info, 0, sizeof(axk_blufi_extra_info_t));
      wifi_conn_ap_info_get(&g_blufi_config.wifi.sta);
      memcpy(info.sta_bssid, g_blufi_config.wifi.sta.cwjap_param.bssid, 6);
      info.sta_bssid_set = true;
      info.sta_ssid = (uint8_t *)g_blufi_config.wifi.sta.cwjap_param.ssid;
      info.sta_ssid_len = strlen(g_blufi_config.wifi.sta.cwjap_param.ssid);
      axk_blufi_send_wifi_conn_report(mode, _BLUFI_STA_CONN_SUCCESS, 0, &info);
    } else {
      axk_blufi_send_wifi_conn_report(mode, _BLUFI_STA_CONN_FAIL, 0, NULL);
    }
    printf("BLUFI get wifi status from AP\n");
​
    break;
  }
  case AXK_BLUFI_EVENT_RECV_SLAVE_DISCONNECT_BLE: //设备主动断开 BLE 连接
    printf("blufi close a gatt connection\r\n");
    axk_blufi_disconnect();
    break;
  case AXK_BLUFI_EVENT_RECV_STA_BSSID: // 接收 Wi-Fi 路由器的 BSSID
    memset(g_blufi_config.wifi.sta.cwjap_param.bssid, 0, 6);
    memcpy(g_blufi_config.wifi.sta.cwjap_param.bssid, param->sta_bssid.bssid,
           6);
    // sta_config.sta.bssid_set = 1;
    // esp_wifi_set_config(WIFI_IF_STA, &sta_config);
    printf("Recv STA BSSID %s\r\n", param->sta_bssid.bssid);
    break;
  case AXK_BLUFI_EVENT_RECV_STA_SSID: //接收 Wi-Fi SSID
    memset(g_blufi_config.wifi.sta.cwjap_param.ssid, 0, 33);
    strncpy(g_blufi_config.wifi.sta.cwjap_param.ssid,
            (char *)param->sta_ssid.ssid, param->sta_ssid.ssid_len);
​
    printf("Recv STA SSID %s\r\n",
           (char *)g_blufi_config.wifi.sta.cwjap_param.ssid);
    break;
  case AXK_BLUFI_EVENT_RECV_STA_PASSWD: //接收 Wi-Fi 密码
        // 先清空 Wi-Fi 密码存储区域,避免旧数据干扰
    memset(g_blufi_config.wifi.sta.cwjap_param.pwd, 0, 64);
​
    // 这里 `param->sta_ssid.ssid` 实际上是 Wi-Fi 密码,虽然名字容易误导
    // 由于结构体内存复用,所以它存的是密码,而非 SSID
    strncpy(g_blufi_config.wifi.sta.cwjap_param.pwd,
            (char *)param->sta_ssid.ssid, param->sta_ssid.ssid_len);
​
    // 打印收到的 Wi-Fi 密码,确保传输正确
    printf("Recv STA PASSWORD %s\r\n",
           (char *)g_blufi_config.wifi.sta.cwjap_param.pwd);
​
    break;
  default:
    break;
  }
}
​
static _blufi_callbacks_t example_callbacks = {
    .event_cb = example_event_callback,
    .negotiate_data_handler = blufi_dh_negotiate_data_handler,
    .encrypt_func = blufi_aes_encrypt,
    .decrypt_func = blufi_aes_decrypt,
    .checksum_func = blufi_crc_checksum,
};
​
int at_blufi_start(void) {
  int ret = -1;
  axk_hal_blufi_init();
​
  ret = _blufi_host_and_cb_init(&example_callbacks);
  if (ret) {
    printf("%s initialise failed: %d\n", __func__, ret);
  }
  return ret;
}
​
static void proc_main_entry(void *pvParameters) {
  wifi_interface_init(blufi_wifi_event);
  at_blufi_start();
  vTaskDelete(NULL);
}
​
void main() {
  static TaskHandle_t proc_main_task;
  bl_sys_init();
  xTaskCreate(proc_main_entry, (char *)"main_entry", 1024, NULL, 15,
              &proc_main_task);
  tcpip_init(NULL, NULL);
  printf("blufi demo test\r\n");
}
​

流程分析


结合日志来分析连接的流程;

  1. 我先烧录好程序,打开串口检测日志
  2. 手机微信小程序安心可IoT的配网里有个BLUFI配网就是蓝牙配网,记得打开蓝牙,并给小程序使用蓝牙的权限。
  3. 扫描设备

图片.png

  1. 名字是 AXK_BLUFI,点击连接

图片.png

  1. 保证手机连接的2.4G的WIFI,输入密码,然后点配置WIFI

图片.png

  1. 然后看,我们串口输出的日志

图片.png

注意【blufi】这几行的输出,这几行是从小程序连接到蓝牙后一直到配网成功过程

消息中有两个函数:

btc_transfer_context:用于跨线程传输 BLE 任务,确保数据安全传输。

btc_thread_handler :在 BTC 线程中执行 BLE 事件(如 Wi-Fi 连接)

一个是蓝牙端发出的事件标志。一个是执行对应事件的任务。总之就是要执行一个任务.

例如:第三行 BLUFI ble connect根据蓝牙事件回调函数可知,这是已经完成连接蓝牙。那么推测前两行传递的任务就是执行连接蓝牙,也就是我在小程序扫描后点击AXK_BLUFI后,通过手机端发起的任务。

[blufi]btc_transfer_context msg 1 3 0x42023634
[blufi] btc_thread_handler msg 1 3 0x4201bad0

//act=3 <====> AXK_BLUFI_EVENT_BLE_CONNECT

BLUFI ble connect

[BLE] connected
[BLE] conn param updated: int 0x0006 lat 0 to 500
[BLE] conn param updated: int 0x0027 lat 0 to 500
[BLE] mtu updated:247

[BLUFI] ccc change 1 客户端已启用通知(用于接收 Wi-Fi 连接状态)

[BLE] conn param updated: int 0x0020 lat 0 to 400
[blufi]btc_transfer_context msg 1 10 0x42023584
[blufi] btc_thread_handler msg 1 10 0x4201bad0

//act=10 <====>AXK_BLUFI_EVENT_RECV_STA_SSID

Recv STA SSID CU_5ZPu

[blufi]btc_transfer_context msg 1 11 0x42023584
[blufi] btc_thread_handler msg 1 11 0x4201bad0

//act=11<====>AXK_BLUFI_EVENT_RECV_STA_PASSWD

Recv STA PASSWORD HYGS3305

[blufi]btc_transfer_context msg 1 5 0x00000000
[blufi] btc_thread_handler msg 1 5 0x00000000

//act=5
<====>AXK_BLUFI_EVENT_REQ_CONNECT_TO_AP

BLUFI requset wifi connect to AP

// 往下隔了wifi连接的日志还有几行

...

[blufi]btc_transfer_context msg 0 2 0x4201989c
[blufi] btc_thread_handler msg 0 2 0x4201b780

//act=2 <====> AXK_BLUFI_EVENT_REQ_CONNECT_TO_AP

BLUFI save ssid&&pwd
START YOUR FOUTION // 这里就表示已经连接好了wifi,后面写自己的逻辑代码

验证推测就从代码里找日志从那里输出的。

全局搜索这个函数 btc_transfer_context 位于ble_btc.c

里边发现了

printf("[blufi]%s msg %u %u %p\n", __func__, msg->sig, msg->act, arg);
​

是不是刚好与第一行对应上了

[blufi]函数名 msg msg->sig msg->act ,arg

sig:消息类型。 以第一行举例,sig=1,也就是协议栈向应用层响应。

typedef enum {
    BTC_SIG_API_CALL = 0,   // APP TO STACK
    BTC_SIG_API_CB,         // STACK TO APP
    BTC_SIG_NUM,
} btc_sig_t; //btc message type

act:具体的应答事件号。这里还以第一行举例,事件号是3 刚好对应AXK_BLUFI_EVENT_BLE_CONNECT 就是蓝牙连接的事件,猜测得到验证

图片.png

  1. 连接成功

图片.png

图片.png

后面就可以写自己任务函数了。

──── 0人觉得很赞 ────

使用道具 举报

厉害厉害~
赞~
学习了
您需要登录后才可以回帖 立即登录
高级模式
返回
统计信息
  • 会员数: 28203 个
  • 话题数: 40108 篇