You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何正确使用HCITool及代码实现Set Extended Advertising Data Command

问题描述
  • 目标:重实现HCITool功能,通过cmd命令设置携带厂商数据的蓝牙LE扩展广播数据
  • 执行以下两种hcitool命令均返回错误码1,提示命令不存在:
    hcitool -i hci0 cmd 0x08 0x0037 01 03 01 0C FFFF 12 34
    
    hcitool -i hci0 cmd 0x08 0x0037 01 03 01 0C FF FF 12 34
    
  • 基于HCITool源码修改的自定义代码运行后,用btmon未检测到扩展广播数据已正确设置,怀疑参数传递或命令构造逻辑有误
一、HCI命令格式错误分析

你调用的是LE Set Extended Advertising Data命令(OGF=0x08,OCF=0x0037),该命令对参数格式有严格要求,你的命令存在两个核心问题:

  1. 数据长度不匹配:参数中0x0C代表后续数据长度为12字节,但实际仅提供了FFFF 12 34共4字节,长度不匹配导致控制器拒绝执行
  2. AD结构缺失:厂商数据需要遵循蓝牙AD(Advertising Data)结构,必须包含AD Type(0xFF)字段,你的命令直接写入厂商ID,缺少该标识

正确命令示例

hcitool -i hci0 cmd 0x08 0x0037 00 00 00 05 FF FF FF 12 34

参数解释:

  • 00:Advertising Handle(默认广播句柄)
  • 00:Operation(0x00=覆盖设置广播数据)
  • 00:Fragment Preference(0x00=允许数据分片)
  • 05:后续AD数据总长度(0xFF(AD Type) + FF FF(厂商ID) + 12 34(自定义数据)共5字节)
  • FF:AD Type标识(厂商特定数据)
  • FF FF:厂商ID(示例值0xFFFF)
  • 12 34:自定义厂商数据
二、自定义代码问题排查

你的代码存在三处关键错误:

  1. 参数数组不完整:仅定义了厂商ID和自定义数据,缺少命令必需的前4个固定参数(Advertising Handle、Operation、Fragment Preference、Data Length)
  2. 循环逻辑越界:for (i = 2, len = 0; i < 12 && len < (int) sizeof(buf); i++, len++)中,arr数组仅3个元素,i从2开始后会越界读取垃圾数据,导致参数长度错误
  3. 命令结构错误:未按照HCI规范构造完整的命令参数,控制器无法识别错误格式的命令,因此btmon看不到有效设置请求
三、解决思路

1. 遵循HCI规范构造命令参数

LE Set Extended Advertising Data命令的参数结构必须严格符合蓝牙核心规范:

偏移字段长度说明
0Advertising Handle1广播句柄,默认用0x00
1Operation10x00=设置数据,0x01=添加数据,0x02=删除
2Fragment Preference10x00=允许分片,0x01=禁止分片
3Data Length1后续AD数据的总长度
4~nAdvertising DataNAD结构数据,厂商数据格式为0xFF + 厂商ID(2字节) + 自定义数据

2. 修正代码实现

以下是调整后的完整代码:

static void cmd_manufacturer(int dev_id)
{
    unsigned char buf[HCI_MAX_EVENT_SIZE], *ptr = buf;
    struct hci_filter flt;
    hci_event_hdr *hdr;
    int len, dd;
    uint16_t ocf;
    uint8_t ogf;

    if (dev_id < 0)
        dev_id = hci_get_route(NULL);

    ogf = 0x08; // LE Controller命令组
    ocf = 0x0037; // LE Set Extended Advertising Data命令

    // 构造完整命令参数
    *ptr++ = 0x00; // Advertising Handle
    *ptr++ = 0x00; // Operation: 覆盖设置广播数据
    *ptr++ = 0x00; // Fragment Preference: 允许分片
    *ptr++ = 0x05; // Data Length: 后续AD数据总长度(1+2+2=5)
    *ptr++ = 0xFF; // AD Type: 厂商特定数据标识
    *ptr++ = 0xFF; // 厂商ID低字节(0xFFFF)
    *ptr++ = 0xFF; // 厂商ID高字节
    *ptr++ = 0x12; // 自定义厂商数据1
    *ptr++ = 0x34; // 自定义厂商数据2
    len = ptr - buf; // 计算参数总长度

    dd = hci_open_dev(dev_id);
    if (dd < 0) {
        perror("Device open failed");
        exit(EXIT_FAILURE);
    }

    // 设置HCI事件过滤器
    hci_filter_clear(&flt);
    hci_filter_set_ptype(HCI_EVENT_PKT, &flt);
    hci_filter_all_events(&flt);
    if (setsockopt(dd, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) {
        perror("HCI filter setup failed");
        exit(EXIT_FAILURE);
    }

    printf("< HCI Command: ogf 0x%02x, ocf 0x%04x, plen %d\n", ogf, ocf, len);

    if (hci_send_cmd(dd, ogf, ocf, len, buf) < 0) {
        perror("Send failed");
        exit(EXIT_FAILURE);
    }

    // 读取命令响应
    len = read(dd, buf, sizeof(buf));
    if (len < 0) {
        perror("Read failed");
        exit(EXIT_FAILURE);
    }

    hdr = (void *)(buf + 1);
    ptr = buf + (1 + HCI_EVENT_HDR_SIZE);
    len -= (1 + HCI_EVENT_HDR_SIZE);

    printf("> HCI Event: 0x%02x plen %d\n", hdr->evt, hdr->plen);

    // 检查命令执行状态
    if (hdr->evt == EVT_CMD_COMPLETE) {
        uint8_t status = ptr[3]; // 命令完成事件中的状态字段
        if (status != 0x00) {
            fprintf(stderr, "Command failed with status 0x%02x\n", status);
        } else {
            printf("Extended advertising data set successfully\n");
        }
    }

    hci_close_dev(dd);
}

3. 验证步骤

  1. 确保蓝牙控制器处于LE广播模式:
    hciconfig hci0 down && hciconfig hci0 up && hciconfig hci0 leadv
    
  2. 运行修改后的程序执行广播数据设置
  3. 用btmon捕获HCI数据包,确认LE Set Extended Advertising Data命令存在且响应状态为0x00(执行成功)
  4. 用bluetoothctl scan on扫描蓝牙设备,查看目标广播包中是否包含指定的厂商数据

内容的提问来源于stack exchange,提问作者ascode

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 16:55:25