Android 蓝牙BLE连接、广播、数据传输流程分析

如今的社会已经从IT时代过渡到了DT时代,数据的重要性不言而喻。将数据安全快速的传输给对方是一件非常重要的事情,如今诞生了很多不同的传输技术,每一种传输技术都是为了和对方进行数据交互。BLE技术也是这样,它的最终目的就是为了在两个设备间进行数据交互。我们从BLE的本质出发,搞清楚它是如何实现数据交互的,也就真正搞清楚了BLE的工作原理。

下面从3个方面,逐步讲解BLE的数据收发过程。

本文结合nordic的代码和蓝牙核心规范5.2来进行介绍。本文认为你对BLE协议栈的各个层已经有了一个大概认识,对BLE协议栈还不太熟悉的朋友可以参看拙作:蓝牙低功耗(BLE)协议栈

一 广播
1.1 从设备

从设备想要别人能够发现自己就需要不停的进行广播。

Host层通过HCI层定义的接口来设置广播数据。

HCI层的命令格式如下图:

设置广播数据的命令格式如下图:

 OpCode,0x0008,两个字节
parameter Total Length,一个字节,也就是Advertising_Data_Length,根据Advertising_Data计算得来
Advertising_Data, 由HCI 以上层传下来
事实上只有Advertising_Data会通过空中发送。Advertising_Data的格式如下:

详细介绍参看:蓝牙核心卷 5.2 , Vol 3, Part C, 11

可以看到广播数据可能有多个元素:AD Structure 1,AD Structure 2 … AD Structure N,每一个AD Structure的格式为,1个字节长度,一个字节AD Type,n个字节的AD Data。广播数据包也遵循一定的格式,广播包的数据格式参看:AD Type和Core Specification Supplement

LL层定义的广播报文的格式如下图:

1.用户设置广播参数和广播内容
ble_gap.h
        //设置广播参数,以及广播类容
        uint32_t sd_ble_gap_adv_set_configure(uint8_t *p_adv_handle, ble_gap_adv_data_t const         *p_adv_data, ble_gap_adv_params_t const *p_adv_params)
设置广播参数,ocf=0x006,ogf=0x08
命令格式:

 gap协议层会根据HCI层提供的接口来设置广播参数

 设置广播数据,ocf=0x0008,ogf=0x08
gap协议层会根据HCI层提供的接口来设置广播数据

2. 开启广播
命令格式:

 gap层提供的函数接口:uint32_t sd_ble_gap_adv_start(uint8_t adv_handle, uint8_t conn_cfg_tag)
HCI层提供的接口,ocf=0x00a,ogf=0x08

 3、广播的具体数据
通过抓包工具得到的广播包的数据:
在这里插入图片描述
在这里插入图片描述

aa, 前导码

d6 be 89 8e,接入地址:0x8e89bed6。(蓝牙传输均使用小端模式)

40 19,报头

        0000b,PDU Type,ADV_IND,普通广播. 详见:Vol 6, Part B, 2.3, Table 2.3
        0b, RFU,未使用
        0b, ChSel, 通道选择,未使用
        1b,TxAdd,广播者的mac地址类型,1表示随机地址
        0b,RxAdd, 扫描者mac地址类型,未知
        19,数据长度,指的是Payload的长度
8b 89 e6 26 c9 4c: 0x4cc926e6898b mac地址, Payload的一部分

02 01 1a , AD Structure 1,广播报文的第一个元素

        02,长度
        01,类型,«Flags»
        1a,数据

02 0a 0c

  • 02, 长度
  • 0a,类型,«Tx Power Level»
  • 0x,数据

 从设备设置的广播数据流向:用户调用GAP提供的接口,GAP调用HCI层接口,HCI层再传给LL层。
在这里插入图片描述

1.2 主设备

  • 设置扫描参数
  • 开启扫描
**@brief GAP scanning parameters. */
typedef struct
{
  uint8_t               extended               : 1; /**< If 1, the scanner will accept extended advertising packets.
                                                         If set to 0, the scanner will not receive advertising packets
                                                         on secondary advertising channels, and will not be able
                                                         to receive long advertising PDUs.
                                                         @note Extended scanning is only supported as an experimental feature in this
                                                               SoftDevice. */
  uint8_t               report_incomplete_evts : 1; /**< If 1, events of type @ref ble_gap_evt_adv_report_t may have
                                                         @ref ble_gap_adv_report_type_t::status set to
                                                         @ref BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA.
                                                         This parameter is ignored when used with @ref sd_ble_gap_connect
                                                         @note This may be used to abort receiving more packets from an extended
                                                               advertising event, and is only available for extended
                                                               scanning, see @ref sd_ble_gap_scan_start.
                                                         @note This feature is not supported by this SoftDevice. */
  uint8_t               active                 : 1; /**< If 1, perform active scanning by sending scan requests.
                                                         This parameter is ignored when used with @ref sd_ble_gap_connect. */
  uint8_t               filter_policy          : 2; /**< Scanning filter policy. @sa BLE_GAP_SCAN_FILTER_POLICIES.
                                                         @note Only @ref BLE_GAP_SCAN_FP_ACCEPT_ALL and
                                                               @ref BLE_GAP_SCAN_FP_WHITELIST are valid when used with
                                                               @ref sd_ble_gap_connect */
  uint8_t               scan_phys;                  /**< Bitfield of PHYs to scan on. If set to @ref BLE_GAP_PHY_AUTO,
                                                         scan_phys will default to @ref BLE_GAP_PHY_1MBPS.
                                                         - If @ref ble_gap_scan_params_t::extended is set to 0, the only
                                                           supported PHY is @ref BLE_GAP_PHY_1MBPS.
                                                         - When used with @ref sd_ble_gap_scan_start,
                                                           the bitfield indicates the PHYs the scanner will use for scanning
                                                           on primary advertising channels. The scanner will accept
                                                           @ref BLE_GAP_PHYS_SUPPORTED as secondary advertising channel PHYs.
                                                         - When used with @ref sd_ble_gap_connect, the
                                                           bitfield indicates the PHYs on where a connection may be initiated.
                                                           If scan_phys contains @ref BLE_GAP_PHY_1MBPS and/or @ref BLE_GAP_PHY_2MBPS,
                                                           the primary scan PHY is @ref BLE_GAP_PHY_1MBPS.
                                                           If scan_phys also contains @ref BLE_GAP_PHY_CODED, the primary scan
                                                           PHY will also contain @ref BLE_GAP_PHY_CODED. If the only scan PHY is
                                                           @ref BLE_GAP_PHY_CODED, the primary scan PHY is
                                                           @ref BLE_GAP_PHY_CODED only. */
  uint16_t              interval;                   /**< Scan interval in 625 us units. @sa BLE_GAP_SCAN_INTERVALS. */
  uint16_t              window;                     /**< Scan window in 625 us units. @sa BLE_GAP_SCAN_WINDOW. */
  uint16_t              timeout;                    /**< Scan timeout in 10 ms units. @sa BLE_GAP_SCAN_TIMEOUT. */
  ble_gap_ch_mask_t     channel_mask;               /**< Channel mask for primary and secondary advertising channels.
                                                         At least one of the primary channels, that is channel index 37-39, must be
                                                         set to 0.
                                                         Masking away secondary channels is not supported. */
} ble_gap_scan_params_t;
/**@brief Data structure. */
typedef struct
{
  uint8_t     *p_data;  /**< Pointer to the data buffer provided to/from the application. */
  uint16_t     len;     /**< Length of the data buffer, in bytes. */
} ble_data_t;

//用户调用该函数,进行设置扫描参数,同时开始扫描
uint32_t sd_ble_gap_scan_start(ble_gap_scan_params_t const *p_scan_params, ble_data_t const * p_adv_report_buffer);

HCI层提供的接口:

  • 设置扫描参数
    设置扫描参数的指令格式:

  • HCI层提供的接口:ogf=0x08,ocf=0x00b
    在这里插入图片描述
  • 开启扫描
    在这里插入图片描述
    HCI层提供的接口:ogf=0x08,ocf=0x00c
    在这里插入图片描述

二 连接

typedef struct
{
  uint8_t addr_id_peer : 1;       /**< Only valid for peer addresses.
                                       Reference to peer in device identities list (as set with @ref sd_ble_gap_device_identities_set) when peer is using privacy. */
  uint8_t addr_type    : 7;       /**< See @ref BLE_GAP_ADDR_TYPES. */
  uint8_t addr[BLE_GAP_ADDR_LEN]; /**< 48-bit address, LSB format. */
} ble_gap_addr_t;

typedef struct
{
  uint16_t min_conn_interval;         /**< Minimum Connection Interval in 1.25 ms units, see @ref BLE_GAP_CP_LIMITS.*/
  uint16_t max_conn_interval;         /**< Maximum Connection Interval in 1.25 ms units, see @ref BLE_GAP_CP_LIMITS.*/
  uint16_t slave_latency;             /**< Slave Latency in number of connection events, see @ref BLE_GAP_CP_LIMITS.*/
  uint16_t conn_sup_timeout;          /**< Connection Supervision Timeout in 10 ms units, see @ref BLE_GAP_CP_LIMITS.*/
} ble_gap_conn_params_t;
/*
p_peer_addr: 对端设备地址
p_scan_params:扫描参数
p_conn_params:连接参数
conn_cfg_tag:连接配置标识
*/
uint32_t sd_ble_gap_connect(ble_gap_addr_t const *p_peer_addr, ble_gap_scan_params_t const *p_scan_params, ble_gap_conn_params_t const *p_conn_params, uint8_t conn_cfg_tag)

HCI层连接命令的格式:

LL层连接请求格式:


HCI层接口:

 

连接请求

在空中传播的数据:

aa d6 be 89 8e c5 22 81 1b f2 8e 55 68 d0 a3 1a d7 7b d0 cf c5 ca 6a e6 c7 ee 02 16 00 28 00 00 00 f4 01 ff ff ff ff 1f 26 2a de cc


aa,前导码
d6 be 89 8e,0x8e89bed6接入地址
LL 报头 C5(1100 0101) 22
        0101b, 数据类型, CONNECT_IND,连接请求
        0b, RFU,未使用
        0b, ChSel, 通道选择,未使用
        1b,TxAdd,发起者的mac地址类型,1表示随机地址
        1b,RxAdd, 接收者的mac地址类型,1表示随机地址
        22, 0x22 Payload长度
Payload
        81 1b f2 8e 55 68, 发起者的Mac地址0x68558ef21b81
        d0 a3 1a d7 7b d0,接受者的mac地址0xd07bd71aa3d0
        cf c5 ca 6a,用于连接的计入地址0x6acac5cf
        e6 c7 ee,CRC初始值0xeec7e6
        02,传输窗口大小,单位1.25ms
        16 00,传输窗口偏移,单位1.25ms
        28 00, 连接间隔,0x0028,单位1.25ms
        00 00, 从设备延时,0x0000
        f4 01, 超时时间,0x01f4,单位10ms
        ff ff ff ff 1f, 通道图,表示哪些信道是好的 0x1f ff ff ff ff,最高的3位保留,其余位表示通信的信道,1表示可用,0表示不可用。
        26(001 00110), SCA & Hope
                001b, 高三位SCA,主设备时钟精度

00110b,低5位,hope值,6
2a de cc,CRC校验,0xccde2a


HCI层会根据GAP传下来的参数,组合成LL层需要的数据格式,也就是黄色部分的数据。实际上GAP会按照HCI提供的接口所要求的参数格式传参。这里重点是突出空中传播的数据部分,因此统一使用LL层的格式。 

三 发现服务
3.1 发现分组服务
发现主服务的过程


用户调用sd_ble_gattc_primary_services_discover:

uint32_t sd_ble_gattc_primary_services_discover(uint16_t conn_handle, uint16_t start_handle, ble_uuid_t const *p_srvc_uuid)

协议栈的调用:
在这里插入图片描述

发送的数据aa cc c5 ca 6a 0e 0b 07 00 04 00 10 01 00 ff ff 00 28 cf 2d 83


aa: 前导码
cc c5 ca 6a: 接入地址,0x6acac5cc
0e 0b,LL层报头
        10b,LLID,表示开始报文
        1b,NESE(预期序列号)
        1b,序列号(SN)
        0b,MD(更多数据)
        0b,CP(是否包含CTEinfo)
        最高两位,RFU保留
        0b,Payload长度
07 00 04 00,L2CAP层报头
        07 00,Length,Information Payload长度,0x0007
        04 00,通道号,0x0004
10 01 00 ff ff 00 28,ATT层数据
        10,请求类型,ATT_READ_BY_GROUP_TYPE_REQ
        01 00,开始Handle,0x0001
        ff ff,结束Handle,0xffff
        00 28,UUID类型,0x2800,表示主要服务
cf 2d 83,CRC校验,0x832dcf

 

 

3.2 发现分组服务响应

响应命令的数据格式:
在这里插入图片描述
在这里插入图片描述

空中传播的数据

aa cc c5 ca 6a 06 12 0e 00 04 00 11 06 01 00 09 00 00 18 0a 00 0a 00 01 18 a8 64 7c
  • 1

在这里插入图片描述

 

四 数据交互

4.1 主设备写命令

ATT层数据格式:
在这里插入图片描述

typedef struct
{
  uint8_t        write_op;             /**< Write Operation to be performed, see @ref BLE_GATT_WRITE_OPS. */
  uint8_t        flags;                /**< Flags, see @ref BLE_GATT_EXEC_WRITE_FLAGS. */
  uint16_t       handle;               /**< Handle to the attribute to be written. */
  uint16_t       offset;               /**< Offset in bytes. @note For WRITE_CMD and WRITE_REQ, offset must be 0. */
  uint16_t       len;                  /**< Length of data in bytes. */
  uint8_t const *p_value;              /**< Pointer to the value data. */
} ble_gattc_write_params_t;
uint32_t sd_ble_gattc_write(uint16_t conn_handle, ble_gattc_write_params_t const *p_write_params)

协议栈处理流程:

  • 用户层设置连接句柄,以及需要发送的数据信息
    在这里插入图片描述

 ATT层获得L2CAP层的buffer指针,并填充发送消息类型,需要写的属性句柄,以及真实的数据。消息类型和句柄必须要占用3个字节的空间,因此有效数据长度不能大于MTU_SIZE - 3。调用L2CAP层的装载函数,并指明数据长度和通道ID
在这里插入图片描述

 L2CAP层获取HCI层的数据buffer指针之后首先构建一个HCI的头,并把有效数据装载到buffer中
在这里插入图片描述

 

 

4.2 从设备发出通知

在这里插入图片描述
在这里插入图片描述

  • 1
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在 Android 设备上发送蓝牙低功耗(BLE广播,你需要执行以下步骤: 1. 获取 BluetoothAdapter 对象并检查是否支持 BLE。可以使用以下代码获取 BluetoothAdapter 对象: ``` BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter(); ``` 2. 创建一个 AdvertiseSettings 对象,用于配置广播的参数。你可以使用以下代码创建 AdvertiseSettings 对象: ``` AdvertiseSettings settings = new AdvertiseSettings.Builder() .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_BALANCED) .setConnectable(false) .setTimeout(0) .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM) .build(); ``` 在这个示例中,我们将广播模式设置为平衡模式,使广播更加稳定。我们还将广播设置为不可连接,并将超时设置为 0。 3. 创建一个 AdvertiseData 对象,用于在广播中包含数据。你可以使用以下代码创建 AdvertiseData 对象: ``` AdvertiseData data = new AdvertiseData.Builder() .setIncludeDeviceName(true) .setIncludeTxPowerLevel(false) .addManufacturerData(0x1234, new byte[] { 0x01, 0x02, 0x03 }) .build(); ``` 在这个示例中,我们将设备名称包含在广播中,并添加了一个制造商数据字段。 4. 开始广播。你可以使用以下代码开始广播: ``` bluetoothAdapter.getBluetoothLeAdvertiser().startAdvertising(settings, data, advertisingCallback); ``` 在这个示例中,我们将 AdvertiseSettings 和 AdvertiseData 对象传递给 startAdvertising() 方法,并提供了一个广告回调函数 advertisingCallback。 这些步骤将使你的 Android 设备开始发送 BLE 广播
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值