蓝牙 ble连接流程及ellisys空包分析

随着ble设备的普及,众多品牌的手机和车载连接着各式各样的ble外设,接触多的有手环、手表、双模耳机、遥控器、鼠标、键盘或者智能家居设备等等

连接类问题一直是蓝牙开发的重要一环,不懂的人可能只会一个劲的问为什么,开发时遇到实际问题时可能也会苦于日志不全,无法确认问题原因,看完这一篇希望对你们有所帮助

基于android平台讲一下

一、ble的开启

蓝牙service中在开启蓝牙时会读取(android 12之前在package/app/bluetooth/res/value/config.xml,13在package/modules下)中的协议配置文件,去开启对应的协议service,ble对应gatt,强制启用,源码流程中配置关闭gatt蓝牙启动不了,开启蓝牙仍然是btsnoop中下发一个hci_reset

二、ble扫描

发起扫描的接口有两个,一个是系统设置中调用的startdiscovery,传统蓝牙和ble一起扫描,协议栈system/bt/stack/btm/btm_inq.cc可以改掉只扫描传统蓝牙,扫描结果都是从action_found广播发出,另一个就是各种ble应用调用的gatt startscan,只用来发现外围的ble设备广播,通过onscanResultble回调扫描结果,扫描指令下发前会通过Command: HCI_LE_Set_Scan_Parameters设置窗口、间隔、过滤policy等,这块实际应用遇到问题例如:外围设备广播以20ms间隔广播一次,中心设备设置扫描间隔100ms,扫描窗口为10ms,可能出现扫描设备要很久,或者某一次扫描无法扫到该设备,扫描的窗口碰不上对方设备广播的频率。扫描开启指令则通过Command: HCI_LE_Set_Scan_Enable下发,另外ble也支持extends类型广播,相比传统ble广播,支持的数据大小和参数都有变化

三、ble广播类型

ble设备广播地址类型主要就是public address和random private address,由ble是否支持私有模式决定。ble广播通过event: HCI_LE_Advertising_Report上报到host,Event_Type标注了广播类型,协议栈也有对应的解析,应用层也可以取到该类型

system\bt\stack\btm\btm_ble_gap.cc

if (legacy_evt_type == 0x00) {  // ADV_IND;

      event_type = 0x0013;

    } else if (legacy_evt_type == 0x01) {  // ADV_DIRECT_IND;

      event_type = 0x0015;

    } else if (legacy_evt_type == 0x02) {  // ADV_SCAN_IND;

      event_type = 0x0012;

    } else if (legacy_evt_type == 0x03) {  // ADV_NONCONN_IND;

      event_type = 0x0010;

    } else if (legacy_evt_type == 0x04) {  // SCAN_RSP;

      // We can't distinguish between "SCAN_RSP to an ADV_IND", and "SCAN_RSP to

      // an ADV_SCAN_IND", so always return "SCAN_RSP to an ADV_IND"

      event_type = 0x001B;

ADV_IND:可连接广播

ADV_DIRECT_IND :定向广播,直连广播

ADV_SCAN_IND:扫描请求广播,获取对方更多数据,对应scn rsp

ADV_NONCONN_IND:不可连接广播,只用来广播一些特定数据

SCAN_RSP:回应scan req

四、ble连接参数和流程

选择扫描到的可连接广播,创建连接,蓝牙协议5.4

连接完成事件会在触发创建连接后扫描到对方可连接广播并下发connect_ind,触发双方连接状态

完整连接流程图

五、结合协议具体看一下空包

对方设备发送可连接广播

整个连接包的交互主要为下图:在广播channel上收到可连接广播包,接收到后需在T_IFS(150us)内发出connect_ind连接包,然后在时间transmitWindowDelay+transmitWindowOffset到ransmitWindowDelay+transmitWindowOffset+transmitWindowSize时间内接着发出第一包数据(一般是empty package),对方在T_IFS时间内回复成功,链路连接正式建立完成,并且以第一包为锚点,之后在Connection Interval内进行数据交互。后续进行version、feature exchange,还有加密等不再细讲

发送connect_ind包后,紧接着发送empty package

empty package交互完成,连接建立ok

下图为第一包交互对方不响应会继续发送empty等待对方响应

遇到ble连接问题可以抓空包分析下连接流程是否正常,经常出现第一包empty package不回包,建立失败,一部分是环境干扰,直接丢包,还有可能对方设备处理异常了,具体问题具体分析。

  • 15
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的CC2642 BLE蓝牙连接流程的代码示例,供您参考: ```c #include "simple_ble.h" #include "ti_drivers_config.h" // 定义服务和特征UUID static simple_ble_service_t my_service = {{ .uuid128 = {0x00, 0x00, 0x00, 0x00, 0xAB, 0xCD, 0xEF, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x00} }}; static simple_ble_char_t my_char = { .uuid16 = 0x1234, .properties = PROP_RW, .value_length = 4 }; static uint8_t my_value[4] = {0x00, 0x01, 0x02, 0x03}; // 初始化BLE void ble_init(void) { // 初始化simple BLE库 simple_ble_init(&ti_drivers_ble_config); // 注册服务和特征 simple_ble_add_service(&my_service); simple_ble_add_characteristic(1, 1, 0, 0, // Service index, characteristic index sizeof(my_value), (uint8_t*)my_value, &my_service.uuid128, &my_char.uuid16, &my_char); // 开始广播 simple_ble_adv_only_name(); } // 处理BLE事件 void ble_evt_handler(ble_evt_t const* p_ble_evt) { switch (p_ble_evt->header.evt_id) { case BLE_GAP_EVT_CONNECTED: // 连接建立后,可以在此处启动数据传输等操作 break; case BLE_GAP_EVT_DISCONNECTED: // 连接断开后,可以在此处停止数据传输等操作 break; default: // 其他事件处理 break; } } int main(void) { // 初始化BLE ble_init(); while (1) { // 处理BLE事件 simple_ble_app_event_loop(); // 主程序其他逻辑 // ... } } ``` 在上面的示例中,我们使用了Simple BLE库来简化BLE开发。首先在`ble_init()`函数中初始化Simple BLE库,注册服务和特征,并开始广播。在`ble_evt_handler()`函数中处理BLE事件,包括连接建立连接断开。在主程序循环中,通过`simple_ble_app_event_loop()`函数来处理BLE事件。 需要注意的是,此示例仅演示了最基本的BLE连接流程,实际应用中需要根据具体需求进行修改和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值