经典蓝牙广播数据问题

mryboy
Posts: 6
Joined: Thu May 21, 2020 9:56 am

经典蓝牙广播数据问题

Postby mryboy » Thu Jun 24, 2021 2:36 am

模块:ESP32-WROVER-B
IDF:release/v4.3
协议:经典蓝牙,GAP+SPP
需求:蓝牙广播的时候传递信息
问题描述:没有找到这种需求的例程,发现GAP的API中esp_bt_gap_config_eir_data可以配置数据,广播时能收到。一开始include_uuid设置为false,发现电脑上接收到一个manufacturer数据包,数据比manufacturer_len配置的大小少2个字节,而且配置的长度大于50个字节后就无效了;include_uuid设置为true能收到两个manufacturer数据包,一个是26字节,一个是20字节,第一个的数据是缓冲区配置的,第二个的数据不知道哪里来的。完全不懂这个函数和这个结构体的使用,在例程和IDF的文档上也没有相关资料,请求帮助,或者有什么其它在广播时设备给电脑传递信息的方法也行。

Code: Select all

#define ESP_BT_EIR_MAX_LEN                  240
/// EIR data content, according to "Supplement to the Bluetooth Core Specification"
typedef struct {
    bool                    fec_required;           /*!< FEC is required or not, true by default */
    bool                    include_txpower;        /*!< EIR data include TX power, false by default */
    bool                    include_uuid;           /*!< EIR data include UUID, false by default */
    uint8_t                 flag;                   /*!< EIR flags, see ESP_BT_EIR_FLAG for details, EIR will not include flag if it is 0, 0 by default */
    uint16_t                manufacturer_len;       /*!< Manufacturer data length, 0 by default */
    uint8_t                 *p_manufacturer_data;   /*!< Manufacturer data point */
    uint16_t                url_len;                /*!< URL length, 0 by default */
    uint8_t                 *p_url;                 /*!< URL point */
} esp_bt_eir_data_t;

/**
 * @brief           This function is called to config EIR data.
 *
 *                  esp_bt_gap_cb_t will be called with ESP_BT_GAP_CONFIG_EIR_DATA_EVT after config EIR ends.
 *
 * @param[in]       eir_data - pointer of EIR data content
 * @return
 *                  - ESP_OK : Succeed
 *                  - ESP_ERR_INVALID_STATE: if bluetooth stack is not yet enabled
 *                  - ESP_ERR_INVALID_ARG: if param is invalid
 *                  - ESP_FAIL: others
 */
esp_err_t esp_bt_gap_config_eir_data(esp_bt_eir_data_t *eir_data);

ESP_Boblane
Posts: 5
Joined: Fri Jun 25, 2021 1:43 am

Re: 经典蓝牙广播数据问题

Postby ESP_Boblane » Fri Jun 25, 2021 4:01 am

mryboy 你好,

根据蓝牙核心协议 Core_spec_v4.2 [Vol3, Part C] 第八章的介绍,EIR data 部分总长 240 字节,按照 length-type-value 的格式排列。如下图所示:
eir_data_format.png

目前 ESP32 上支持的 EIR type 有:
  1. /// Extended Inquiry Response data type
  2. #define ESP_BT_EIR_TYPE_FLAGS                   0x01      /*!< Flag with information such as BR/EDR and LE support */
  3. #define ESP_BT_EIR_TYPE_INCMPL_16BITS_UUID      0x02      /*!< Incomplete list of 16-bit service UUIDs */
  4. #define ESP_BT_EIR_TYPE_CMPL_16BITS_UUID        0x03      /*!< Complete list of 16-bit service UUIDs */
  5. #define ESP_BT_EIR_TYPE_INCMPL_32BITS_UUID      0x04      /*!< Incomplete list of 32-bit service UUIDs */
  6. #define ESP_BT_EIR_TYPE_CMPL_32BITS_UUID        0x05      /*!< Complete list of 32-bit service UUIDs */
  7. #define ESP_BT_EIR_TYPE_INCMPL_128BITS_UUID     0x06      /*!< Incomplete list of 128-bit service UUIDs */
  8. #define ESP_BT_EIR_TYPE_CMPL_128BITS_UUID       0x07      /*!< Complete list of 128-bit service UUIDs */
  9. #define ESP_BT_EIR_TYPE_SHORT_LOCAL_NAME        0x08      /*!< Shortened Local Name */
  10. #define ESP_BT_EIR_TYPE_CMPL_LOCAL_NAME         0x09      /*!< Complete Local Name */
  11. #define ESP_BT_EIR_TYPE_TX_POWER_LEVEL          0x0a      /*!< Tx power level, value is 1 octet ranging from  -127 to 127, unit is dBm*/
  12. #define ESP_BT_EIR_TYPE_URL                     0x24      /*!< Uniform resource identifier */
  13. #define ESP_BT_EIR_TYPE_MANU_SPECIFIC           0xff      /*!< Manufacturer specific data */
  14. #define  ESP_BT_EIR_TYPE_MAX_NUM                12        /*!< MAX number of EIR type */
可以看到其中的一些类型,与 esp_bt_eir_data_t 能对应的上,目前,没有接口去直接设置 UUID 的值。

我在 demo esp_spp_acceptor/example_spp_acceptor_demo.c 中添加了如下代码:
  1. static uint8_t manufacturer_data[60] = {
  2.     0x00, 0x02, 0x00, 0x04, 0x00, 0x06, 0x00, 0x08, 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x0e, 0x00,
  3.     0x10, 0x00, 0x12, 0x00, 0x14, 0x00, 0x16, 0x00, 0x18, 0x00, 0x1a, 0x00, 0x1c, 0x00, 0x1e,
  4.     0x00, 0x20, 0x00, 0x22, 0x00, 0x24, 0x00, 0x26, 0x00, 0x28, 0x00, 0x2a, 0x00, 0x2c, 0x00,
  5.     0x2e, 0x00, 0x30, 0x00, 0x32, 0x00, 0x34, 0x00, 0x36, 0x00, 0x38, 0x00, 0x3a, 0x00, 0x3c,
  6. };
  7. static esp_bt_eir_data_t eir_data;
  8.  
  9. void app_main(void)
  10. {
  11. ...
  12.     if ((ret = esp_bt_gap_register_callback(esp_bt_gap_cb)) != ESP_OK) {
  13.         ESP_LOGE(SPP_TAG, "%s gap register failed: %s\n", __func__, esp_err_to_name(ret));
  14.         return;
  15.     }
  16.  
  17.     eir_data.fec_required = true;
  18.     eir_data.include_uuid = true;
  19.     eir_data.flag = ESP_BT_EIR_FLAG_GEN_DISC | ESP_BT_EIR_FLAG_DMT_CONTROLLER_SPT | ESP_BT_EIR_FLAG_DMT_HOST_SPT;
  20.     eir_data.manufacturer_len = 60;
  21.     eir_data.p_manufacturer_data = manufacturer_data;
  22.     if ((ret = esp_bt_gap_config_eir_data(&eir_data)) != ESP_OK) {
  23.         ESP_LOGE(SPP_TAG, "%s gap config eir data failed: %s\n", __func__, esp_err_to_name(ret));
  24.         return;
  25.     }
  26.  
  27.     if ((ret = esp_spp_register_callback(esp_spp_cb)) != ESP_OK) {
  28.         ESP_LOGE(SPP_TAG, "%s spp register failed: %s\n", __func__, esp_err_to_name(ret));
  29.         return;
  30.     }
  31. ...
  32. }
在 demo esp_spp_initiator/main/example_spp_initiator_demo.c 中添加了如下代码:
  1. static void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param)
  2. {
  3.     switch(event){
  4.     case ESP_BT_GAP_DISC_RES_EVT:
  5.         ESP_LOGI(SPP_TAG, "ESP_BT_GAP_DISC_RES_EVT");
  6.         esp_log_buffer_hex(SPP_TAG, param->disc_res.bda, ESP_BD_ADDR_LEN);
  7.         for (int i = 0; i < param->disc_res.num_prop; i++){
  8.             if (param->disc_res.prop[i].type == ESP_BT_GAP_DEV_PROP_EIR
  9.                 && get_name_from_eir(param->disc_res.prop[i].val, peer_bdname, &peer_bdname_len)){
  10.                 esp_log_buffer_char(SPP_TAG, peer_bdname, peer_bdname_len);
  11.                 if (strlen(remote_device_name) == peer_bdname_len &&
  12.                     strncmp(peer_bdname, remote_device_name, peer_bdname_len) == 0) {
  13.                     uint8_t *eir_val = NULL;
  14.                     uint8_t eir_len = 0;
  15.                     for (int type = 0; type <= ESP_BT_EIR_TYPE_MANU_SPECIFIC; type++) {
  16.                         switch (type) {
  17.                         case ESP_BT_EIR_TYPE_FLAGS:
  18.                         case ESP_BT_EIR_TYPE_INCMPL_16BITS_UUID:
  19.                         case ESP_BT_EIR_TYPE_CMPL_16BITS_UUID:
  20.                         case ESP_BT_EIR_TYPE_INCMPL_32BITS_UUID:
  21.                         case ESP_BT_EIR_TYPE_CMPL_32BITS_UUID:
  22.                         case ESP_BT_EIR_TYPE_INCMPL_128BITS_UUID:
  23.                         case ESP_BT_EIR_TYPE_CMPL_128BITS_UUID:
  24.                         case ESP_BT_EIR_TYPE_TX_POWER_LEVEL:
  25.                         case ESP_BT_EIR_TYPE_URL:
  26.                         case ESP_BT_EIR_TYPE_MANU_SPECIFIC:
  27.                             eir_val = esp_bt_gap_resolve_eir_data(param->disc_res.prop[i].val, type, &eir_len);
  28.                             break;
  29.                         default:
  30.                             break;
  31.                         }
  32.  
  33.                         if (eir_val) {
  34.                             switch (type) {
  35.                             case ESP_BT_EIR_TYPE_FLAGS:
  36.                                 printf("--FLAGS len:%d\n", eir_len);
  37.                                 esp_log_buffer_hex("  FLAGS", eir_val, eir_len);
  38.                                 break;
  39.                             case ESP_BT_EIR_TYPE_INCMPL_16BITS_UUID:
  40.                                 printf("--INCMPL_16BITS_UUID len:%d\n", eir_len);
  41.                                 esp_log_buffer_hex("  INCMPL_16BITS_UUID", eir_val, eir_len);
  42.                                 break;
  43.                             case ESP_BT_EIR_TYPE_CMPL_16BITS_UUID:
  44.                                 printf("--CMPL_16BITS_UUID len:%d\n", eir_len);
  45.                                 esp_log_buffer_hex("  CMPL_16BITS_UUID", eir_val, eir_len);
  46.                                 break;
  47.                             case ESP_BT_EIR_TYPE_INCMPL_32BITS_UUID:
  48.                                 printf("--INCMPL_32BITS_UUID len:%d\n", eir_len);
  49.                                 esp_log_buffer_hex("  INCMPL_32BITS_UUID", eir_val, eir_len);
  50.                                 break;
  51.                             case ESP_BT_EIR_TYPE_CMPL_32BITS_UUID:
  52.                                 printf("--CMPL_32BITS_UUID len:%d\n", eir_len);
  53.                                 esp_log_buffer_hex("  CMPL_32BITS_UUID", eir_val, eir_len);
  54.                                 break;
  55.                             case ESP_BT_EIR_TYPE_INCMPL_128BITS_UUID:
  56.                                 printf("--INCMPL_128BITS_UUID len:%d\n", eir_len);
  57.                                 esp_log_buffer_hex("  INCMPL_128BITS_UUID", eir_val, eir_len);
  58.                                 break;
  59.                             case ESP_BT_EIR_TYPE_CMPL_128BITS_UUID:
  60.                                 printf("--CMPL_128BITS_UUID len:%d\n", eir_len);
  61.                                 esp_log_buffer_hex("  CMPL_128BITS_UUID", eir_val, eir_len);
  62.                                 break;
  63.                             case ESP_BT_EIR_TYPE_TX_POWER_LEVEL:
  64.                                 printf("--TX_POWER_LEVEL len:%d\n", eir_len);
  65.                                 esp_log_buffer_hex("  TX_POWER_LEVEL", eir_val, eir_len);
  66.                                 break;
  67.                             case ESP_BT_EIR_TYPE_URL:
  68.                                 printf("--URL len:%d\n", eir_len);
  69.                                 esp_log_buffer_hex("  URL", eir_val, eir_len);
  70.                                 break;
  71.                             case ESP_BT_EIR_TYPE_MANU_SPECIFIC:
  72.                                 printf("--MANU_SPECIFIC len:%d\n", eir_len);
  73.                                 esp_log_buffer_hex("  MANU_SPECIFIC", eir_val, eir_len);
  74.                                 break;
  75.                             default:
  76.                                 break;
  77.                             }
  78.                         }
  79.                     }
  80.                     memcpy(peer_bd_addr, param->disc_res.bda, ESP_BD_ADDR_LEN);
  81.                     esp_spp_start_discovery(peer_bd_addr);
  82.                     esp_bt_gap_cancel_discovery();
  83.                 }
  84.             }
  85.         }
  86.         break;
  87.     case ESP_BT_GAP_DISC_STATE_CHANGED_EVT:
  88.         ESP_LOGI(SPP_TAG, "ESP_BT_GAP_DISC_STATE_CHANGED_EVT");
  89.         break;
  90. ...
  91. }
GAP discovery 的结果如 discovery_res.png 所示,同时电脑上用 wireshark 对 dongle 抓包的结果如 cap.png 所示。两边均接收到 60 字节的 manufacturer_data 数据。
Attachments
cap.png
cap.png (395.51 KiB) Viewed 3001 times
discovery_res.png
discovery_res.png (66.03 KiB) Viewed 3001 times
eir_data_format.png
eir_data_format.png (113.69 KiB) Viewed 3001 times

Who is online

Users browsing this forum: No registered users and 51 guests