# ESP32 BLE广播包中自定义厂商数据的动态更新与抓包验证实战 ## 一、原理:广播数据与厂商字段 BLE广播包(Advertising Packet)由多个AD Structure组成,每个结构包含长度、类型和数据。其中,类型`0xFF`表示厂商自定义数据(Manufacturer Specific Data),格式为: - 2字节公司ID(Company ID,如0x004C为Apple,0x0059为Nordic) - 自定义数据(长度可变) ESP32的BLE协议栈通过`esp_ble_adv_data_t`结构体配置广播数据,其中`manufacturer_len`和`manufacturer_data`字段用于设置厂商数据。动态更新即指在广播过程中,通过`esp_ble_gap_config_adv_data()`函数重新配置广播数据,使设备状态变化实时反映在广播包中。 ## 二、硬件与软件准备 - 硬件:ESP32开发板(如ESP32-DevKitC) - 软件:ESP-IDF v4.4+(或Arduino-ESP32,但本文以ESP-IDF为例) - 抓包工具:手机nRF Connect App,或PC端Wireshark + BLE dongle(如nRF52840) ## 三、配置步骤 ### 1. 初始化BLE并设置广播参数 ```c #include #include "esp_bt.h" #include "esp_bt_main.h" #include "esp_gap_ble_api.h" // 厂商数据缓冲区(假设公司ID为0xFFFF,自定义数据为4字节状态) static uint8_t manufacturer_data[6] = {0xFF, 0xFF, 0x01, 0x02, 0x03, 0x04}; // 广播数据配置结构体 static esp_ble_adv_data_t adv_data = { .set_scan_rsp = false, .include_name = true, .include_txpower = true, .min_interval = 0x20, .max_interval = 0x40, .appearance = 0x00, .manufacturer_len = sizeof(manufacturer_data), .manufacturer_data = manufacturer_data, }; void ble_init() { ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT)); esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); esp_bt_controller_init(&bt_cfg); esp_bt_controller_enable(ESP_BT_MODE_BTDM); esp_bluedroid_init(); esp_bluedroid_enable(); // 注册GAP回调 esp_ble_gap_register_callback(gap_event_handler); // 设置广播参数 esp_ble_adv_params_t adv_params = { .adv_int_min = 0x20, .adv_int_max = 0x40, .adv_type = ADV_TYPE_IND, .own_addr_type = BLE_ADDR_TYPE_PUBLIC, .channel_map = ADV_CHNL_ALL, .adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY, }; esp_ble_gap_config_adv_data(&adv_data); // 初始配置 esp_ble_gap_start_advertising(&adv_params); } ``` ### 2. 动态更新厂商数据 在需要更新状态时(如传感器读数变化),修改`manufacturer_data`数组,并重新调用`esp_ble_gap_config_adv_data()`。注意:必须先停止广播或直接重新配置,ESP-IDF允许在广播中更新,但需确保数据长度一致。 ```c void update_manufacturer_data(uint8_t *new_data, uint8_t len) { if (len > 4) return; // 假设最大4字节自定义数据 memcpy(&manufacturer_data[2], new_data, len); // 跳过公司ID adv_data.manufacturer_len = len + 2; adv_data.manufacturer_data = manufacturer_data; esp_ble_gap_config_adv_data(&adv_data); } ``` ### 3. GAP事件处理 在`gap_event_handler`中处理`ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT`,确认配置完成,然后重新启动广播(如果之前停止了)。 ```c static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) { switch (event) { case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT: // 配置完成,确保广播在运行 esp_ble_gap_start_advertising(&adv_params); break; case ESP_GAP_BLE_ADV_START_COMPLETE_EVT: if (param->adv_start_cmpl.status != ESP_BT_STATUS_SUCCESS) { printf("广告启动失败\n"); } break; default: break; } } ``` ## 四、完整代码示例 以下是一个可运行的示例,每5秒更新一次状态值(递增): ```c #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_bt.h" #include "esp_bt_main.h" #include "esp_gap_ble_api.h" static uint8_t manufacturer_data[6] = {0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}; static esp_ble_adv_data_t adv_data; static esp_ble_adv_params_t adv_params; void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) { if (event == ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT) { esp_ble_gap_start_advertising(&adv_params); } } void update_task(void *arg) { uint8_t counter = 0; while (1) { vTaskDelay(pdMS_TO_TICKS(5000)); counter++; manufacturer_data[2] = counter; // 更新第3字节 adv_data.manufacturer_len = sizeof(manufacturer_data); adv_data.manufacturer_data = manufacturer_data; esp_ble_gap_config_adv_data(&adv_data); printf("更新广播数据: counter=%d\n", counter); } } void app_main() { // 初始化BLE...(同前) // 配置adv_data和adv_params... // 启动初始广播... xTaskCreate(update_task, "update", 2048, NULL, 5, NULL); } ``` ## 五、抓包验证技巧 ### 1. 使用nRF Connect(手机) - 打开App,扫描设备,找到你的ESP32设备名。 - 点击设备,查看“ADVERTISING DATA”中的“Manufacturer Specific Data”。 - 观察数据变化:每5秒应看到第3字节递增。 ### 2. 使用Wireshark + BLE dongle - 将nRF52840 dongle插入PC,使用Wireshark捕获BLE流量。 - 过滤`btle.advertising_data.manufacturer_specific_data.company_id == 0xffff`。 - 展开数据包,查看“Manufacturer Specific Data”字段,确认动态更新。 ### 3. 常见问题排查 - **数据不更新**:检查是否在`ADV_DATA_SET_COMPLETE_EVT`后重新启动广播?如果广播未停止,某些版本可能不生效。建议先`esp_ble_gap_stop_advertising()`,再配置,再启动。 - **数据长度变化**:如果长度变化,需确保`adv_data.manufacturer_len`正确,且广播数据总长度不超过31字节(含其他AD结构)。 - **抓包看不到**:确认广播类型为`ADV_TYPE_IND`(可扫描),且手机或dongle支持厂商数据解析。 ## 六、注意事项 - **广播间隔**:动态更新频率不宜过高,否则会增加功耗和无线拥塞。建议至少100ms以上。 - **数据一致性**:更新过程中,广播包可能被截获为旧数据,这是正常的,因为广播是异步的。 - **内存管理**:`manufacturer_data`必须保持有效,直到配置完成事件触发。 - **兼容性**:不同ESP-IDF版本API略有差异,请参考对应文档。 ## 七、总结 通过本文,你学会了在ESP32上动态更新BLE广播包中的厂商自定义数据,并掌握了抓包验证的方法。这一技巧在智能家居、信标、传感器网络等场景中非常实用。记住,动态更新广播数据是BLE开发中的高级技巧,合理运用能大幅提升设备交互体验。