微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

ESP32 - 从广告中提取制造商特定数据

如何解决ESP32 - 从广告中提取制造商特定数据

TL;DR: 一个 ESP32 通过 BLE 广播(已经工作),另一个 ESP32 监听。我无法正确解析收到的广告,即无法提取制造商特定数据!


目标:一个 ESP32(调用 A)广播包含制造商特定数据 (MSD) 的广告,该广告被另一个 ESP32(调用 B)接收,并将该数据打印到控制台。

我使用的是新的基于 RISC-V 的 ESP32C3,它支持蓝牙 5.0,但我所做的一切都是基于蓝牙 4.2。

我在哪里:

  1. A 可以广播有效的广告(通过 Ubertooth/Wireshark 进行检查)
  2. B 从 A 接收某些东西,尽管该数据包仅与 Ubertooth 接收到的(正确)数据包非常松散地对应。

代码

用于设置 A 的结构:

// Struct defining advertising parameters
static esp_ble_adv_params_t ble_adv_params = {
    .adv_int_min        = 0x0800,.adv_int_max        = 0x0900,.adv_type           = ADV_TYPE_NONCONN_IND,.own_addr_type      = BLE_ADDR_TYPE_PUBLIC,.channel_map        = ADV_CHNL_ALL,.adv_filter_policy  = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,// NO IDEA ABOUT THAT ONE,ESPECIALLY GIVEN THAT WE SEND NONCONNECTABLE AND NONSCANNABLE ADVERTISEMENTS!
};

用于定义广告负载的结构:

    esp_ble_adv_data_t ble_adv_data =
    {
            .set_scan_rsp           = false,.include_name           = true,// "Name" refers to the name passed as an argument within "esp_ble_gap_set_device_name()"
            .include_txpower        = false,.min_interval           = 0xffff,// Not sure what those are for,as the chosen advertisement packets are non-connectable...
            .max_interval           = 0xFFFF,.appearance             = 64,// 64 is appearance ID of phone. Only to maybe be able to find it on my galaxy phone
            .manufacturer_len       = ble_adv_payload_len,.p_manufacturer_data    = (uint8_t *) ble_adv_payload,// Currently just some human-readable string used for debugging
            .service_data_len       = 0,.p_service_data         = NULL,.service_uuid_len       = 0,.p_service_uuid         = NULL,.flag = 0
    };

由于Ubertooth 接收到A 发送的正确数据包,我认为A 设置正确。

用于定义 B 的扫描行为的结构:

// Struct defining scanning parameters
static esp_ble_scan_params_t ble_scan_params = {
    .scan_type              = BLE_SCAN_TYPE_PASSIVE,// Don't send scan requests upon receiving an advertisement
    .own_addr_type          = BLE_ADDR_TYPE_PUBLIC,// Use (static) public address,makes debugging easier
    .scan_filter_policy     = BLE_SCAN_FILTER_ALLOW_ONLY_WLST,// Consider all advertisements
    .scan_interval          = 0x50,// Time between each scan window begin
    .scan_window            = 0x30,// Length of scan window
    .scan_duplicate         = BLE_SCAN_DUPLICATE_disABLE        // Filters out duplicate advertisements,e.g. if an advertisement received k times,it is only reported once
};

剩下的大部分代码只是样板,唯一真正相关的部分是 B 的回调函数,每当发生 GAP-Event 时都会调用它(GAP-Events 可以在 esp_gap_ble_api.h 中找到,从第 138 行开始) ).

B 的回调函数

void esp_ble_callback_fun(esp_gap_ble_cb_event_t event,esp_ble_gap_cb_param_t *param)
{
    // Do a case split on the different events. For Now,only "ESP_GAP_BLE_SCAN_RESULT_EVT" is of interest
    switch (event) { 
    case ESP_GAP_BLE_SCAN_RESULT_EVT:
        if ((param->scan_rst).search_evt != ESP_GAP_SEARCH_INQ_RES_EVT) {
            printf(
                    "B: Callback function received a non-\"ESP_GAP_SEARCH_INQ_RES_EVT\" event!\n");
            return;
        }

        // copy the parameter UNION
        esp_ble_gap_cb_param_t scan_result = *param;


        // Create a POINTER to the "bda" entry,which is accessed by interpreting the scan_result UNION as a scan_rst STRUCT
        // Note that "esp_bd_addr_t" is a typedef for a uint8_t array!
        esp_bd_addr_t *ble_adv_addr = &scan_result.scan_rst.bda;

        printf("\n-------------------------\nMessage: \n");
        uint8_t adv_data_len  = scan_result.scan_rst.adv_data_len;
        uint8_t *adv_data     = scan_result.scan_rst.ble_adv;

        printf("Message length: %i\n",adv_data_len);
        printf("Message body:\n");                  // NOT SO SURE ABOUT THIS!

        for(int i = 0; i < adv_data_len; ++i)
        {
            printf("%X",adv_data[i]);
        }
        printf("\n-------------------------\n");

        break; // @suppress("No break at end of case")
    default:
        // NOT SUPPORTED! JUST IGnorE THEM!
        break;
    }
}

示例输出

B 串行输出

Message: 
Message length: 22
Message body:
31940069414C4943454FF486579512FFFFFFFF

Wireshark 中收到的数据包:

Frame 78135: 61 bytes on wire (488 bits),61 bytes captured (488 bits) on interface /tmp/pipe,id 0
PPI version 0,24 bytes
    Version: 0
    Flags: 0x00
        .... ...0 = Alignment: Not aligned
        0000 000. = Reserved: 0x00
    Header length: 24
    DLT: 251
    Reserved: 36750c0000620900e05b56b811051000
Bluetooth
Bluetooth Low Energy Link Layer
    Access Address: 0x8e89bed6
    Packet Header: 0x1c22 (PDU Type: ADV_NONCONN_IND,ChSel: #2,TxAdd: Public)
        .... 0010 = PDU Type: ADV_NONCONN_IND (0x2)
        ...0 .... = RFU: 0
        ..1. .... = Channel Selection Algorithm: #2
        .0.. .... = Tx Address: Public
        0... .... = Reserved: False
        Length: 28
    Advertising Address: Espressi_43:3e:d6 (7c:df:a1:43:3e:d6)
    Advertising Data
        Appearance: Generic Phone
        Device Name: ALICE
        Manufacturer Specific
        Slave Connection Interval Range: 81918.8 - 81918.8 msec
        Connection Interval Min: 65535 (81918.8 msec)
        Connection Interval Max: 65535 (81918.8 msec)
    CRC: 0x905934

0000   00 00 18 00 fb 00 00 00 36 75 0c 00 00 62 09 00   ........6u...b..
0010   e0 5b 56 b8 11 05 10 00 d6 be 89 8e 22 1c d6 3e   .[V........."..>
0020   43 a1 df 7c 03 19 40 00 06 09 41 4c 49 43 45 04   C..|..@...ALICE.
0030   ff 48 65 79 05 12 ff ff ff ff 09 9a 2c            .hey........,

对于没有 MSD 的数据包,我计算了 B 收到的数据包的二进制表示(即 adv_data内容)和 Ubertooth 收到的数据包之间的最长公共子序列。他们只有 46 位共同点,这肯定是一个奇怪的数字!

我的问题:

  1. 我是否正确假设 adv_data,即 scan_result.scan_rst.ble_adv 保存原始 BLE 数据包? ble_adv(esp_gap_ble_api.h,第 936 行)的定义令人难以置信让 IMO 感到困惑,因为它被称为“收到的 EIR”,尽管 EIR 仅在蓝牙 5.0 中引入...
  2. 如何从收到的 BLE 广告中提取 MSD?

解决方法

EIR 很久以前就被引入了,并且出现在蓝牙 4.0 中。

您应该在打印十六进制字符串时使用 %02X,因为它会包含前导零。

ble_adv 只包含 EIR 内容,而不是整个数据包。

EIR 使用长度、类型、值编码。您的制造数据编码如下:

4(长度) 0xff(制造商数据) 嘿(内容)

注意制造商数据内容的两个字节应该是Bluetooth SIG注册的公司ID。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。