一. 声明

本专栏文章我们会以连载的方式持续更新,本专栏计划更新内容如下:

第一篇:蓝牙综合介绍 ,主要介绍蓝牙的一些概念,产生背景,发展轨迹,市面蓝牙介绍,以及蓝牙开发板介绍。

第二篇:Transport层介绍,主要介绍蓝牙协议栈跟蓝牙芯片之前的硬件传输协议,比如基于UART的H4,H5,BCSP,基于USB的H2等

第三篇:传统蓝牙controller介绍,主要介绍传统蓝牙芯片的介绍,包括射频层(RF),基带层(baseband),链路管理层(LMP)等

第四篇:传统蓝牙host介绍,主要介绍传统蓝牙的协议栈,比如HCI,L2CAP,SDP,RFCOMM,HFP,SPP,HID,AVDTP,AVCTP,A2DP,AVRCP,OBEX,PBAP,MAP等等一系列的协议吧。

第五篇:低功耗蓝牙controller介绍,主要介绍低功耗蓝牙芯片,包括物理层(PHY),链路层(LL)

第六篇:低功耗蓝牙host介绍,低功耗蓝牙协议栈的介绍,包括HCI,L2CAP,ATT,GATT,SM等

第七篇:蓝牙芯片介绍,主要介绍一些蓝牙芯片的初始化流程,基于HCI vendor command的扩展

第八篇:附录,主要介绍以上常用名词的介绍以及一些特殊流程的介绍等。

另外,开发板如下所示,对于想学习蓝牙协议栈的最好人手一套。以便更好的学习蓝牙协议栈,相信我,学完这一套视频你将拥有修改任何协议栈的能力(比如Linux下的bluez,Android下的bluedroid)。

------------------------------------------------------------------------------------------------------------------------------------------

CSDN学院链接(进入选择你想要学习的课程):https://edu.csdn.net/lecturer/5352?spm=1002.2001.3001.4144

蓝牙交流扣扣群:970324688

Github代码:https://github.com/sj15712795029/bluetooth_stack

入手开发板:https://item.taobao.com/item.htm?spm=a1z10.1-c-s.w4004-22329603896.18.5aeb41f973iStr&id=622836061708

------------------------------------------------------------------------------------------------------------------------------------------

二.搜索command以及产生的event

蓝牙搜索没什么好说的吧,就是搜索周边设备,也叫inquiry,搜索command以及产生的event如下:

整个流程如下:

1)首先协议栈给蓝牙芯片发送搜索command

2)芯片收到搜索命令上报协议栈一个command status的event

3)然后芯片上报协议栈搜索结果

4)最终芯片上报协议栈搜索完成

我们就以上4个步骤来一一分析下每个封包,既巩固我们前面所说的封包格式,又学到协议栈跟芯片的交互流程。

首先我们来说下搜索command,命令格式如下:

参数:

LAP:

其中LAP的有效值在:https://www.bluetooth.com/specifications/assigned-numbers/baseband/

Inquiry_Length:搜索时间

Num_Responses:最多返回的设备个数

注意此部分如果Inquiry_Length跟Num_Responses有一方满足,那么就停止搜索。

搜索命令具体封包如下:

搜索代码实现如下:

err_t hci_inquiry(uint32_t lap, uint8_t inq_len, uint8_t num_resp,err_t (*inq_result)(struct hci_pcb_t *pcb,struct hci_inq_res_t *inqres),err_t (* inq_complete)(struct hci_pcb_t *pcb,uint16_t result))
{struct bt_pbuf_t *p;struct hci_inq_res_t *tmpres;/* Free any previous inquiry result list */while(pcb->ires != NULL){tmpres = pcb->ires;pcb->ires = pcb->ires->next;bt_memp_free(MEMP_HCI_INQ, tmpres);}pcb->inq_complete = inq_complete;pcb->inq_result = inq_result;if((p = bt_pbuf_alloc(BT_TRANSPORT_TYPE, HCI_INQUIRY_PLEN, BT_PBUF_RAM)) == NULL){BT_HCI_TRACE_ERROR("ERROR:file[%s],function[%s],line[%d] bt_pbuf_alloc fail\n",__FILE__,__FUNCTION__,__LINE__);return BT_ERR_MEM; /* Could not allocate memory for bt_pbuf_t */}/* Assembling command packet */p = hci_cmd_ass(p, HCI_INQUIRY, HCI_LINK_CONTROL, HCI_INQUIRY_PLEN);/* Assembling cmd prameters */bt_le_store_24((uint8_t *)p->payload,3,lap);((uint8_t *)p->payload)[6] = inq_len;((uint8_t *)p->payload)[7] = num_resp;phybusif_output(p, p->tot_len,PHYBUSIF_PACKET_TYPE_CMD);bt_pbuf_free(p);return BT_ERR_OK;
}

其次,我们来看下command status的event,封包格式如下

参数:

Status:在9.6小节我们以及介绍errcode的值分别代表什么意思

Num_HCI_Command_Packets:

Command_Opcode:用于标示command status是返回哪个cmmand的,此部分应该跟我们HCI command的opcode一样,此部分也就是inquiry command.

Command status封包格式如下:

代码中没有针对此部分做特别处理,基本上算是打印:

case HCI_COMMAND_STATUS:switch(((uint8_t *)p->payload)[0]){case HCI_SUCCESS:BT_HCI_TRACE_DEBUG("hci_event_input: Command Status\n");break;default:BT_HCI_TRACE_DEBUG("hci_event_input: Command failed, %s\n", hci_get_error_code(((uint8_t *)p->payload)[0]));bt_pbuf_header(p, -2); /* Adjust payload pointer not to coverNum_HCI_Command_Packets and status parameter */ocf = *((uint16_t *)p->payload) & 0x03FF;ogf = *((uint16_t *)p->payload) >> 10;bt_pbuf_header(p, -2); /* Adjust payload pointer not to cover Command_Opcodeparameter */HCI_EVENT_CMD_COMPLETE(pcb,ogf,ocf,((uint8_t *)p->payload)[0],ret);bt_pbuf_header(p, 4);break;}BT_HCI_TRACE_DEBUG("Num_HCI_Command_Packets: 0x%x\n", ((uint8_t *)p->payload)[1]);pcb->numcmd += ((uint8_t *)p->payload)[1]; /* Add number of completed command packets to thenumber of command packets that the BT modulecan buffer */BT_HCI_TRACE_DEBUG("Command_Opcode: 0x%x 0x%x\n", ((uint8_t *)p->payload)[2], ((uint8_t *)p->payload)[3]);break;

然后,我们来看下搜索结果的event,封包格式如下

参数:

Num_Responses:搜索到设备的个数,一般芯片会每次上来一个,然后以多个搜索结果event上来,但是也不排除有一次上来多个搜索结果的event.

BD_ADDR:搜索到的蓝牙地址.

Page_Scan_Repetition_Mode

Reserved:保留参数

Class_Of_Device:设备类型,具体参照:https://www.bluetooth.com/specifications/assigned-numbers/baseband/

Clock_Offset:时钟偏移

注意此部分普通的搜索不会上来remote bluetooth name,需要额外去调用Remote Name Request command去请求,当然EIR除外,后续我们会说明EIR。

普通搜索的结果封包格式如下:

代码处理如下:

case HCI_INQUIRY_RESULT:for(i=0; i<((uint8_t *)p->payload)[0]; i++){resp_offset = i*14;BT_HCI_TRACE_DEBUG("hci_event_input: Inquiry result %d\nBD_ADDR: 0x",i);for(i = 0; i < BD_ADDR_LEN; i++){BT_HCI_TRACE_DEBUG("%x",((uint8_t *)p->payload)[1+resp_offset+i]);}BT_HCI_TRACE_DEBUG("\n");BT_HCI_TRACE_DEBUG("Page_Scan_Rep_Mode: 0x%x\n",((uint8_t *)p->payload)[7+resp_offset]);BT_HCI_TRACE_DEBUG("Class_of_Dev: 0x%x 0x%x 0x%x\n",((uint8_t *)p->payload)[10+resp_offset],((uint8_t *)p->payload)[11+resp_offset], ((uint8_t *)p->payload)[12+resp_offset]);BT_HCI_TRACE_DEBUG("Clock_Offset: 0x%x%x\n",((uint8_t *)p->payload)[13+resp_offset],((uint8_t *)p->payload)[14+resp_offset]);bdaddr = (void *)(((uint8_t *)p->payload)+(1+resp_offset));if((inqres = bt_memp_malloc(MEMP_HCI_INQ)) != NULL){bd_addr_set(&(inqres->bdaddr), bdaddr);inqres->psrm = ((uint8_t *)p->payload)[7+resp_offset];inqres->psm = ((uint8_t *)p->payload)[9+resp_offset];memcpy(inqres->cod, ((uint8_t *)p->payload)+10+resp_offset, 3);inqres->co = *((uint16_t *)(((uint8_t *)p->payload)+13+resp_offset));HCI_REG(&(pcb->ires), inqres);HCI_EVENT_INQ_RESULT(pcb,inqres,ret); /*---通过这个函数回调到APP应用层 */}else{BT_HCI_TRACE_ERROR("ERROR:file[%s],function[%s],line[%d] bt_memp_malloc fail\n",__FILE__,__FUNCTION__,__LINE__);}}break;

最后我们来看下搜索完成的event,封包格式如下:

参数:

Status:搜索完成状态

Wireshark封包格式如下:

代码处理如下:

case HCI_INQUIRY_COMPLETE:BT_HCI_TRACE_DEBUG("DEBUG:hci_event_input: Inquiry complete, 0x%x %s\n",((uint8_t *)p->payload)[0], hci_get_error_code(((uint8_t *)p->payload)[0]));HCI_EVENT_INQ_COMPLETE(pcb,((uint8_t *)p->payload)[0],ret);/* 通过这个函数回调到APP应用层 */break;

三.取消搜索command以及产生的event

正常取消搜索流程如下:

这里要重点提一下,个人觉得不合理的地方,我觉得取消搜索,也应该来搜索完成的event,这样设计才合理,我手里的芯片是CSR8811,没有上报协议栈搜索完成的消息,我们暂时先以这个流程说明,后续有了其他芯片重点验证下这个case

回到主题,流程如下:

1)发送取消搜索的命令

2)收到command complete with inquiry cancel opcode

我们来整个分析下这两个步骤

步骤1:发送取消搜索命令,取消搜索的命令格式如下,很简单的一个命令,甚至连参数都没有

Wireshark封包格式如下:

代码如下:


err_t hci_cancel_inquiry(void)
{struct bt_pbuf_t *p;struct hci_inq_res_t *tmpres;/* Free any previous inquiry result list */while(pcb->ires != NULL){tmpres = pcb->ires;pcb->ires = pcb->ires->next;bt_memp_free(MEMP_HCI_INQ, tmpres);}if((p = bt_pbuf_alloc(BT_TRANSPORT_TYPE, HCI_CANCEL_INQUIRY_PLEN, BT_PBUF_RAM)) == NULL){BT_HCI_TRACE_ERROR("ERROR:file[%s],function[%s],line[%d] bt_pbuf_alloc fail\n",__FILE__,__FUNCTION__,__LINE__);return BT_ERR_MEM; /* Could not allocate memory for bt_pbuf_t */}/* Assembling command packet */p = hci_cmd_ass(p, HCI_INQUIRY_CANCEL, HCI_LINK_CONTROL, HCI_CANCEL_INQUIRY_PLEN);phybusif_output(p, p->tot_len,PHYBUSIF_PACKET_TYPE_CMD);bt_pbuf_free(p);return BT_ERR_OK;
}

步骤2:收到command complete with inquiry cancel opcode,command complete的封包格式如下:

参数:

Num_HCI_Command_Packets:

Command_Opcode:这个opcode就不用介绍了吧,很熟悉啊·

Return_Parameter(s):返回的参数,要看具体的命令返回什么参数,我们在取消搜索的时候看到返回status的参数,所以此部分应该是status。

直接上Wireshark喽

在代码中我们在event input中监测command complete处理如下

另外,我送个彩蛋,就是我比较好奇他说如果BE/EDR处于搜索状态,那么就取消搜索,但是如果此时我们不在搜索中我们下取消搜索会怎么样呢,以下是我试的结果,贴上来下:

我们会同样受到command complete,但是status结果是command disallowed.

传统蓝牙HCI搜索流程介绍(bluetooth inquiry)相关推荐

  1. 一篇文章足够你学习蓝牙技术,提供史上最全的蓝牙技术(传统蓝牙/低功耗蓝牙)文章总结,文档下载总结(2020/12/11更新)

    本文章目的: 1)给广大蓝牙爱好者提供蓝牙资料下载渠道 2)给广大蓝牙爱好者增加一个蓝牙学习文章导读 我们的蓝牙书以及CSDN蓝牙系列的书籍以及视频有以下计划,大家可以根据兴趣爱好或者工作需要挑选特定 ...

  2. 低功耗蓝牙搜索广播的实现流流程介绍 /BLE scan flow ----- 蓝牙低功耗协议栈

    零. 概述 主要介绍下蓝牙协议栈(bluetooth stack)低功耗蓝牙搜索广播的流程以及协议栈的实现流程,BLE scan flow btsnoop以及流程在资料中的......\STM32_U ...

  3. BLE广播流程介绍 蓝牙广播 低功耗蓝牙广播的实现流流程介绍 /BLE Advertising flow ----- 蓝牙低功耗协议栈

    零. 概述 主要介绍下蓝牙协议栈(bluetooth stack)低功耗蓝牙广播的流程以及协议栈的实现流程,BLE  Advertising flow btsnoop以及流程在资料中的......\S ...

  4. Android O HIDL的使用例子 -- 蓝牙HCI 服务进程

    1.1.Treble 计划概览 Android O 引入" Treble" 计划,目标是通过重构 Android OS 的 framework,使 Android 设备制造商能更快 ...

  5. 传统蓝牙RFCOMM协议(Bluetooth rfcomm)流程介绍

    零. 概述 本文章主要讲下蓝牙协议栈RFCOMM协议部分流控介绍 一. 声明 本专栏文章我们会以连载的方式持续更新,本专栏计划更新内容如下: 第一篇:蓝牙综合介绍 ,主要介绍蓝牙的一些概念,产生背景, ...

  6. ESP32 VHCI架构传统蓝牙设置scan mode,让设备能被搜索到

    零. 声明 本专栏文章我们会以连载的方式持续更新,本专栏计划更新内容如下: 第一篇:ESP-IDF基本介绍,主要会涉及模组,芯片,开发板的介绍,环境搭建,程序编译下载,启动流程等一些基本的操作,让你对 ...

  7. 蓝牙协议栈模组在linux ubuntu 跑蓝牙协议栈 --传统蓝牙搜索演示以及实现原理

    零. 概述 主要介绍下用Linux ubuntu虚拟机外接我们的蓝牙扩展版跑蓝牙协议栈的初始化以及搜索演示 一. 声明 本专栏文章我们会以连载的方式持续更新,本专栏计划更新内容如下: 第一篇:蓝牙综合 ...

  8. 蓝牙协议栈开发板 STM32F1 跑蓝牙协议栈 --传统蓝牙搜索演示以及实现原理

    零. 概述 主要介绍下蓝牙协议栈开发板跑传统蓝牙搜索AT指令以及上位机操作步骤,以及原理 一. 声明 本专栏文章我们会以连载的方式持续更新,本专栏计划更新内容如下: 第一篇:蓝牙综合介绍 ,主要介绍蓝 ...

  9. 蓝牙HCI command/event/acl/sco格式介绍

    一. 声明 本专栏文章我们会以连载的方式持续更新,本专栏计划更新内容如下: 第一篇:蓝牙综合介绍 ,主要介绍蓝牙的一些概念,产生背景,发展轨迹,市面蓝牙介绍,以及蓝牙开发板介绍. 第二篇:Transp ...

  10. android 传统蓝牙Bluetooth联通性

    Android平台包含了对蓝牙网络协议栈的支持,它允许一个蓝牙设备跟其他的蓝牙设备进行无线的数据交换.应用程序通过Android蓝牙API提供访问蓝牙的功能.这些API会把应用程序无线连接到其他的蓝牙 ...

最新文章

  1. Java设计模式圣经连载(05)-代理模式
  2. python怎么读是啥意思-请问在python中**是啥什么意思?
  3. JavaScript实现完整的ComplexNumber复数类(附完整源码)
  4. CMOS图像传感器——高动态范围
  5. SQL Server 数据库部分常用语句小结
  6. Spring的核心模块解析
  7. [渝粤教育] 广东-国家-开放大学 21秋期末考试服务标准化10011k1
  8. windows搭建SFTP服务器
  9. RTTI、dynamic_cast、typeid、虚函数表
  10. Java数据结构(1)---顺序表
  11. yum使用总结(转)
  12. QT运行时加载UI文件
  13. 解决Ubuntu显卡驱动的问题
  14. Unity2020打包ARCore项目apk
  15. 黑龙江大学自考,助学专业软件工程(本科)招生简章
  16. wps怎么自动生成目录?2分钟完成
  17. 利用QQ游戏破解QQ密码
  18. PHP中smart原则,目标smart原则 “smart原则”什么意思?
  19. 撩妹奇招——修改Excel单元格默认格式
  20. java 年轻代算法_java内存模型 年轻代/年老代 持久区,jvm中的年轻代 老年代 持久代 gc...

热门文章

  1. 科幻作文关于计算机,智能科幻作文范文
  2. 【成功解决】运行qt生成的.exe文件报“无法找到入口”的问题
  3. 126邮箱stmp服务器,网易邮箱设置海外服务器 打造海外邮件快车道
  4. 踩坑指南!pytorch1.2.0安装!又是猛男落泪的一天!
  5. 数据分类算法-朴素贝叶斯
  6. [转]C#中的global关键字(global::)
  7. 2021年广东省安全员C证(专职安全生产管理人员)找解析及广东省安全员C证(专职安全生产管理人员)模拟考试题
  8. 标准盒模型和IE盒模型
  9. 计算机英语的四种变量,计算机英语:BASIC语言变量
  10. JAVA解析IP地址