主要介绍下蓝牙协议栈(bluetooth stack)低功耗蓝牙广播的流程以及协议栈的实现流程,BLE Advertising flow
btsnoop以及流程在资料中的......\STM32_UBUNTU_BLUETOOTH\2-蓝牙资料\蓝牙协议分析\BLE广播.log
本专栏文章我们会以连载的方式持续更新,本专栏计划更新内容如下:
第一篇:蓝牙综合介绍 ,主要介绍蓝牙的一些概念,产生背景,发展轨迹,市面蓝牙介绍,以及蓝牙开发板介绍。
第二篇: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学院链接(进入选择你想要学习的课程):
蓝牙交流扣扣群:970324688
Github代码:
入手开发板:
蓝牙学习目录:
--------------------------------------------------------------------------------------------------------------------------
整个流程如下(注意在初始化的时候有省略的步骤,只列出初始化的关键步骤)
我们再来看下ellisys的流程(跟Wireshark显示基本一样,主要是ellisys在流程中会自带解析,所以我顺便也贴下)
注意我们在截图初始化的时候只是截取了两个command以及event,一个是跟传统蓝牙有差别的set event mask,一个是write le host supported,其他可以参照传统蓝牙的初始化,步骤整理如下:
步骤1)发送设置事件掩码的command(set event mask)以及收到commnd complete event
步骤2)发送设置支持BLE的command(write le host support)收到command complete event
步骤3)发送BLE 设置广播参数的command(LE Set Advertising Parameters)
步骤4)发送BLE设置广播数据的command(LE Set Advertising Data)
步骤5)发送BLE开启广播的command(LE Set Advertising Enable)
步骤6)收到步骤4)5)6)的command complete
步骤7)发送BLE关闭广播的command(LE Set Advertising Enable)以及收到commnd complete event
下面我们就详细说下每个步骤
此部分在上一个小节搜索广播的时候介绍过,不再重复
此部分在上一个小节搜索广播的时候介绍过,不再重复
我们来看下这个command的格式:
我们直接来看下btsnoop
对应的代码如下:
err_t hci_le_set_adv_param(uint16_t adv_int_min, uint16_t adv_int_max, uint8_t adv_type,
uint8_t own_address_typ, uint8_t peer_address_type,struct bd_addr_t *peer_address, uint8_t channel_map, uint8_t filter_policy)
{
struct bt_pbuf_t *p;
uint8_t offset = 0;
if((p = bt_pbuf_alloc(BT_TRANSPORT_TYPE, HCI_SET_LE_ADV_PARAM_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;
}
/* Assembling command packet */
p = hci_cmd_ass(p, HCI_LE_SET_ADV_PARAM, HCI_LE, HCI_SET_LE_ADV_PARAM_PLEN);
offset = 3;
bt_le_store_16((uint8_t *)p->payload,offset,adv_int_min);
offset = 2;
bt_le_store_16((uint8_t *)p->payload,offset,adv_int_max);
offset = 2;
((uint8_t *)p->payload)[offset] = adv_type;
offset = 1;
((uint8_t *)p->payload)[offset] = own_address_typ;
offset = 1;
((uint8_t *)p->payload)[offset] = peer_address_type;
offset = 1;
memcpy(((uint8_t *)p->payload) offset, peer_address->addr, BD_ADDR_LEN);
offset = BD_ADDR_LEN;
((uint8_t *)p->payload)[offset] = channel_map;
offset = 1;
((uint8_t *)p->payload)[offset] = filter_policy;
phybusif_output(p, p->tot_len,PHYBUSIF_PACKET_TYPE_CMD);
bt_pbuf_free(p);
return BT_ERR_OK;
}
我们来看下HCI command格式:
此命令是设置广播数据的,广播数据的格式在上个小节,搜索广播的时候已经说到,我们就不再重复了,我们直接来看下我们设置的代码以及btsnoop
为了测试简单,我自己也就广播了一个蓝牙名称,广播数据如下:
广播调用如下:
实现如下:
err_t hci_le_set_adv_data(uint8_t adv_len,uint8_t *adv_data)
{
struct bt_pbuf_t *p;
uint8_t offset = 0;
if((p = bt_pbuf_alloc(BT_TRANSPORT_TYPE, HCI_SET_LE_ADV_DATA_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;
}
/* Assembling command packet */
p = hci_cmd_ass(p, HCI_LE_SET_ADV_DATA, HCI_LE, HCI_SET_LE_ADV_DATA_PLEN);
offset = 3;
((uint8_t *)p->payload)[offset] = adv_len;
offset = 1;
memset(((uint8_t *)p->payload) offset,0,HCI_SET_LE_ADV_DATA_PLEN-offset);
memcpy(((uint8_t *)p->payload) offset, adv_data, adv_len);
phybusif_output(p, p->tot_len,PHYBUSIF_PACKET_TYPE_CMD);
bt_pbuf_free(p);
return BT_ERR_OK;
}
此部分要注意的是不管你的广播数据是什么,都要填满31Byte,第一个参数广播数据是你真是的广播长度
最后来看下btsnoop:
我们来看下command格式:
参数很简单,就是简单的开启跟关闭
我们来看下代码实现:
err_t hci_le_set_adv_enable(uint8_t enable)
{
struct bt_pbuf_t *p;
uint8_t offset = 0;
if((p = bt_pbuf_alloc(BT_TRANSPORT_TYPE, HCI_SET_LE_ADV_ENABLE_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;
}
/* Assembling command packet */
p = hci_cmd_ass(p, HCI_LE_SET_ADV_ENABLE, HCI_LE, HCI_SET_LE_ADV_ENABLE_PLEN);
offset = 3;
((uint8_t *)p->payload)[offset] = enable;
phybusif_output(p, p->tot_len,PHYBUSIF_PACKET_TYPE_CMD);
bt_pbuf_free(p);
return BT_ERR_OK;
}
最后我们来看下btsnoop:
这个command我们已经在传统蓝牙HCI介绍了,我直接贴下这3个command complete的event
这个在步骤5)已经介绍,我们直接来截图btsnoop