[BLE]低功耗蓝牙之GAP、GATT

2023-05-16

一、开篇

    本篇主要介绍一下关于BLE开发过程中必须了解的两个协议:GAP(通用访问协议)、GATT(通用属性协议)。两个协议都隶属于Host层,直接关系到应用层开发,与BLE开发人员的关系比较密切,其分别负责连接前数据广播和连接后的数据传输。


三、试验平台

Software Version:BLE_STACK_CC26XX_2.1.0

Hardware Version:CC2640/CC2650

IDE:IAR 7.40

四、GAP

    1、蓝牙低能耗技术“完成”一次连接(即扫描其它设备、建立链路、发送数据、认证和适当地结束)只需3ms。而标准蓝牙技术完成相同的连接周期需要数百毫秒。

    GAP层有4种不同类型的广播:通用的、定向的、不可连接的以及可发现的。

    设备每次广播时,会在3个广播信道上发送相同的报文。这些报文被称为一个广播事件。除了定向报文以外,其他广播事件均可以选择20ms - 10.28s不等的间隔。通常,一个广播中的设备会每一秒广播一次。广播事件之间的时间称为广播间隔。主机可以控制该间隔。但是,设备周期性的发送广播会有一个问题:由于设备间的时钟会不同程度的漂移,两个设备可能在很长一段时间同时广播而造成千扰。为防止选一情况的发生,在上一次广播事件发生后加入随机延时。它们发送下一个广播事件时也很可能不再冲突。

    通用广播:通用广播是用途最广的广播方式。进行通用广播的设备能够被扫描设备扫描到,或者在接收到连接请求时作为从设备进入一个连接。通用广播可以在没有连接的情况下发出,换句话说,没有主从设备之分。

    定向广播:有时候,设备间需要快速建立连接。如果从设备想这么做,就需要进行广播。定向广播事件就是为了尽可能快的建立连接。这种报文包含两个地址:广播者的地址和发起者的地址。发起设备收到发绐自己的定向广播报文后,可以立即发送连接请求作为回应。

    不可连接广播:不想被连接的设备使用不可连接广播事件。这种广播的典型应用包括设备只想广播数据,而不想被扫描或者连接。速也是唯一可用于只有发射机而没有接收机设备的广播类型。不可连接广播设备不会进入连接态,因此,它只能根据主机的要求在广播态和就绪态之间切换。

    可发现广播:最后一种广播事件是可发现广播。这种广播不能用于发起连接,但允许其他设备扫描该广播设备。这意味着该设备可以被发现,既可以广播数据,又可以响应扫描,但不能建立连接。这是一种适用于广播数据的广播形式,动态数据可以包含于广播数据之中,而静态数据可以包含于扫描响应数据之中。可发现广播不会进入连接态,而只能在停止后回到就绪态。

    如上面所述,BLE设备可以进行广播。但是,一个广播设备必须在广播中包含一些有用的数据。这意味着可以通过4种广播事件中的3种进行广播:通用广播、不可连接广播以及可发现广播。进行广播时,需要在广播报文中给数据打上标签。之所以要这么做,是因为并非所有设备都能理解所有可能的广播数据。因此,需要给广播数据打上标签并指出其长度。每个数据片段均起始于一个长度域,用以指示后面的类型及数据域的长度;接下来是类型域,接收机可根据其内容判断自己是否能够理解后面的数据。事例代码:

// GAP - Advertisement data (max size = 31 bytes, though this is
// best kept short to conserve power while advertisting)
static uint8_t advertData[] =
{
  // Flags; this sets the device to use limited discoverable
  // mode (advertises for 30 seconds at a time) instead of general
  // discoverable mode (advertises indefinitely)
  0x02,   // length of this data
  GAP_ADTYPE_FLAGS,
  DEFAULT_DISCOVERABLE_MODE | GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED,

  // service UUID, to notify central devices what services are included
  // in this peripheral
  0x03,   // length of this data
  GAP_ADTYPE_16BIT_MORE,      // some of the UUID's, but not all
#ifdef FEATURE_OAD
  LO_UINT16(OAD_SERVICE_UUID),
  HI_UINT16(OAD_SERVICE_UUID)
#else
  LO_UINT16(SIMPLEPROFILE_SERV_UUID),
  HI_UINT16(SIMPLEPROFILE_SERV_UUID)
#endif //!FEATURE_OAD
};


五、GATT

    通用属性配置文件(GATT)在属性协议(ATT)的基础上构建,为属性协议传输和存储数据建立了一些通用操作和框架。

1)GATT定义了两个角色:服务器和客户端

    GATT的角色并不一定与特定的GAP角色有关联,但可能由更高层级的配置文件指定。GATT和ATT不是传输专用,也可以用于BR/EDR和低耗能。但是,由于GATT和ATT用作发现服务,故必须在低耗能技术中实施。GATT服务器存储通过属性协议传输的数据,并接受GATT客户端发出的属性协议请求、指令及确认。GATT服务器发送请求回复,而如果在配置时GATT服务器发生特定事件,则会向GATT客户端异步发送指示和通知。GATT还指定GATT服务器中所载的数据格式。

    属性在当经由属性协议传输时,会被格式化为相关的服务和特性。服务可能包括许多特征。特征包括单一值和许多描述特征值的描述符。

凭借经定义的服务、特征和特征描述符架构,并非配置文件特定的GATT客户端仍然可以遍历GATT服务器,并向用户显示特征值。特征描述符可用于显示特征值的描述符,从而可让用户了解该值。

2)GATT配置文件层级

    GATT配置文件规格规定了交换配置文件数据的架构。此架构定义了配置文件所用的基本元素,例如服务和特征。

该层级的最高层是配置文件(profile)。配置文件由实现用例所需的一个或多个服务组成。服务由特征或有关其它服务的引用组成。每一个特征包括一个值,还可能包括有关该值的可选信息。服务、特征以及特征的组件(即特征值和特征描述符)构成了配置文件数据,并全部存储在服务器的属性中。

    英文原版(摘自Core_V4.1 vol 1:6.5,p226):The top level of the hierarchy is a profile. A profile is composed of oneor more services necessary to fulfill a use case. A service is composed of characteristicsor references to other services. Each characteristic contains a value and maycontain optional information about the value. Theservice and characteristic and the components of the characteristic (i.e.,value and descriptors) contain the profile data and are all stored in Attributes on theserver.

3)服务

    服务是数据和完成设备或设备的某些部分的特定功能或特征的相关行为的集合。服务可能涉及其它主要或次要服务和/或构成该服务的特征集合。

服务分为两种类型:主要服务和次要服务。主要服务提供设备的主要功能。次要服务提供设备的辅助功能,引用自该设备至少一项主要服务。

为了令早前的客户端保持向后兼容性,服务定义的其后修订仅可增加新引用的服务或可选特征。服务定义的其后修订也不得改变该服务定义先前修订的特征。

服务可能用于一个或多个配置文件,以实现特定用例。

4)特征

    特征,连同属性和有关如何访问该值的配置信息以及有关如何显示或表述该值的信息,是用于服务的值。特征定义包含特征声明、特征属性和值。它还可能包含描述该值或允许服务器配置有关特征值的描述符。

协议栈代码实现如下:

/*********************************************************************
 * Profile Attributes - variables
 */
// Simple Profile Service attribute
static CONST gattAttrType_t simpleProfileService = { ATT_BT_UUID_SIZE, simpleProfileServUUID };
// Simple Profile Characteristic 1 Properties
static uint8 simpleProfileChar1Props = GATT_PROP_READ | GATT_PROP_WRITE;
// Characteristic 1 Value
static uint8 simpleProfileChar1 = 0;
// Simple Profile Characteristic 1 User Description
static uint8 simpleProfileChar1UserDesp[17] = "Characteristic 1";


/*********************************************************************
 * Profile Attributes - Table
 */
static gattAttribute_t simpleProfileAttrTbl[SERVAPP_NUM_ATTR_SUPPORTED] = 
{
  // Simple Profile Service
  { 
    { ATT_BT_UUID_SIZE, primaryServiceUUID }, /* type */
    GATT_PERMIT_READ,                         /* permissions */
    0,                                        /* handle */
    (uint8 *)&simpleProfileService            /* pValue */
  },
    // Characteristic 1 Declaration
    { 
      { ATT_BT_UUID_SIZE, characterUUID },
      GATT_PERMIT_READ, 
      0,
      &simpleProfileChar1Props 
    },
      // Characteristic Value 1
      { 
        { ATT_BT_UUID_SIZE, simpleProfilechar1UUID },
        GATT_PERMIT_READ | GATT_PERMIT_WRITE, 
        0, 
        &simpleProfileChar1 
      },
      // Characteristic 1 User Description
      { 
        { ATT_BT_UUID_SIZE, charUserDescUUID },
        GATT_PERMIT_READ, 
        0, 
        simpleProfileChar1UserDesp 
      },      

5)关于句柄handle 和UUID

    Handle即是地址(记住它,类比于C语言的指针操作)

    属性句柄:一台设备可以有许多的属性,例如温度传感器可能包含温度属性、设备名称属性和电池电量属性。表面看来,通过属性类型似乎足以判别某种属性。比如使用温度属性来获取温度,通过设备名称属性来获取设备名等。但是,如果设备包含了两种温度属性,比如一个室内温度传感器加上室外温度传感器,情况会变得怎样。这时你便无法直接读取温度传感器,而必须读取第一个或第二个温度属性。考虑到可能有任意多个温度传感器,问题将变得更加复杂。为了解决这个同题,我们使用了一个16位的地址,也就是属性句柄。有效的句柄范围从0x0001--xFFFF。0x0000为无效句柄,不能用于寻址属性。可以根据在软硬件或嵌入式方面的背景,把句柄(Handle)相应地想象为内存地址、端口号、属性值对应的硬件寄存器地址

    属性类型:可以被公开的数据有许许多多的类型:温度、压强、体积、距离、功率、时间、充电状态、开关状态、状态机的状态等。所公开的数据的种类称作属性类型。为了区分如此多的数据类型,一串128位的数字被用来标识属性的类型。这个唯一标识码就叫做通用唯一识别码(UUID),128位的UUID相当长,设备间为了识别数据的类型需要发送长达16个字节的数据。为了提高传输效率,蓝牙技术联盟( SIG)定义了一种称为“蓝牙UUID基数”的128位通用唯一识别码,结合一个较短的16位数使用。二者仍然遵循通用唯一识别码的分配规则,只不过在设备间传输常用的UUID时,只发送较短的16位版本,接收方收到后补上蓝牙的UUID基数即可。

蓝牙UUID基数如下:

000000000000—1000—8000—00805F9B34FB

例如要发送的16位识别码位0X2A01,完整的128位UUID便是:

00002A010000—1000—8000—00805F9B34FB

    由上所述,所以在协议栈代码中经常见到的都是16位的UUID而不常见128位的UUID的原因所在,下面是官方demo的UUID,供参考。

// Simple Profile Service UUID
#define SIMPLEPROFILE_SERV_UUID               0xFFF0
    
// Key Pressed UUID
#define SIMPLEPROFILE_CHAR1_UUID            0xFFF1
#define SIMPLEPROFILE_CHAR2_UUID            0xFFF2
#define SIMPLEPROFILE_CHAR3_UUID            0xFFF3
#define SIMPLEPROFILE_CHAR4_UUID            0xFFF4
#define SIMPLEPROFILE_CHAR5_UUID            0xFFF5

谈到16位的UUID,通常不直接使用数值,而是冠以一个名称并加上书名号(这些UUID可以在gatt_profile_uuid.h中查看到

0x1800 - 0x26FF用作服务类通用唯一识别码

0x2700 - 0x27FF用于标识计量单位

0x2800 - 0x28FF用于区分属性类型

0x2900 - 0x29FF用作特性描述

0x2A00- 0x7FFF用于区分特性类型

UUID,就是用来唯一识别一个特征值的ID。

handle,就是对应的attribute的一个句柄。

具体细节详见:Generic Attribute Profile (GATT)

摘抄一部分源码供参考:

/**
 * GATT Service UUIDs
 */
#define IMMEDIATE_ALERT_SERV_UUID       0x1802  // Immediate Alert
#define LINK_LOSS_SERV_UUID             0x1803  // Link Loss
#define TX_PWR_LEVEL_SERV_UUID          0x1804  // Tx Power
#define CURRENT_TIME_SERV_UUID          0x1805  // Current Time Service
#define REF_TIME_UPDATE_SERV_UUID       0x1806  // Reference Time Update Service

/**
 * GATT Characteristic UUIDs
 */
#define ALERT_LEVEL_UUID                0x2A06  // Alert Level
#define TX_PWR_LEVEL_UUID               0x2A07  // Tx Power Level
#define DATE_TIME_UUID                  0x2A08  // Date Time
#define DAY_OF_WEEK_UUID                0x2A09  // Day of Week
#define DAY_DATE_TIME_UUID              0x2A0A  // Day Date Time
#define EXACT_TIME_256_UUID             0x2A0C  // Exact Time 256

/**
 * GATT Unit UUIDs
 */
#define GATT_UNITLESS_UUID                    0x2700  // <Symbol>, <Expressed in terms of SI base units>
#define GATT_UNIT_LENGTH_METER_UUID           0x2701  // m, m
#define GATT_UNIT_MASS_KGRAM_UUID             0x2702  // kg, kg

    所有对特征值的操作,都是通过对UUID 的搜索得到对应的handle之后,通过handle来操作特征值的。对于蓝牙通信来说,其都是通过一个个不同的UUID来标识区分不同的服务,区分不同的特性,甚至服务和特性之间的类别。



六、总结

    不知道写什么了,就这样吧,后续想到了写吧,学习BLE也不久,路还很长。路漫漫其修远兮,吾将上下而求索~~~

    PS:该死的房价。。。。啊啊啊啊啊啊。。。。

    参考:1)蓝牙技术联盟官方网站

               2)Bluetooth开发者门户

               3)Bluetooth Spec Core_V4.1






本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

[BLE]低功耗蓝牙之GAP、GATT 的相关文章

  • [BLE]CC2640之定时器(Clock)事件

    一 定时器 xff08 Clock xff09 所谓定时器本质上递减计数器 xff0c 当计数器减到零时可以触发某种动作的执行 这种动作可以通过回调函数来实现 xff0c 当定时器计时完成后 xff0c 自定义的回调函数会立即被调用 回调函
  • BLE Mesh(六)配网流程

    配网流程 概述配网协议配网承载层 Provisioning Bearer 配网协议 Provisioning Protocol 流程详解发送Beacon信号邀请交换公共密钥认证输出带外 xff08 Output OOB xff09 输入带外
  • HLK-B36 WIFI/BLE 二合一透传沙雕按键说明

    模块如下 沙雕说明如下 实际操作如下 恢复出厂设置 xff1a 插usb上电 xff0c 长按ES0 6秒以上 xff0c WIFI灯和STA灯同时灭掉然后亮起 xff0c STA开始闪烁 进入AT模式方式1 xff1a 插上USB xff
  • 蓝牙5.1的ble那些事儿

    到这里 对于非连接状态应该有一些新的认识了 接下来 顺其自然当然就是连接了 你谈对象 忙活半天 当然是想干点什么事情了 当然也有老司机翻车 连接上后 一端要主动向另一端发起问候 否则长时间不联系 那么就断开好了 主动问候的一端我们称之为ma
  • 蓝牙:GATT,属性,特性,服务

    接着上一篇 通用属性配置文件 xff08 Generic Attribute Profile xff09 1 GATT简介 通用属性配置文件Generic Attribute Profile简称GATT GATT定义了属性类型并规定了如何使
  • 理解innodb的锁(record,gap,Next-Key lock)

    Record lock 单条索引记录上加锁 record lock锁住的永远是索引 而非记录本身 即使该表上没有任何索引 那么innodb会在后台创建一个隐藏的聚集主键索引 那么锁住的就是这个隐藏的聚集主键索引 所以说当一条sql没有走任何
  • BLE连接建立过程详解

    同一款手机 为什么跟某些设备可以连接成功 而跟另外一些设备又连接不成功 同一个设备 为什么跟某些手机可以建立连接 而跟另外一些手机又无法建立连接 同一个手机 同一个设备 为什么他们两者有时候连起来很快 有时候连起来又很慢 Master是什么
  • BLE低功耗蓝牙协议栈

    目录 一 BLE低功耗蓝牙协议栈 1 蓝牙核心协议 Bluetooth Core 2 蓝牙应用层协议 Bluetooth Application 3 BLE低功耗蓝牙核心协议层详解 Bluetooth Core 物理层 PHY 链路层 LL
  • BLE MESH组网(一)简介和基本概念

    BLE MESH组网 一 BLE MESH简介 BLE MESH来源 BLE MESH用处 BLE MESH的通讯方式 管理洪水 市场内蓝牙设备支持 安全性 BLE MESH协议栈模型 BLE MESH基本概念 节点 元素 模型和状态 地址
  • Android(Java)开发之获取BLE广播包(扫描后获取:广播数据+扫描应答数据+RSSI)

    一 安卓BLE的广播包数据从哪获取 通常 安卓APP读写BLE设备的数据都是建立连接后通过GATT获取或修改 但是 BLE设备向外广播时本身会携带一部分有用信息 如将传感数据存放到广播包的自定义数据段 最近接触的一个iBeacon Eddy
  • Dialog DA14585+Sensirion SHT3X+SGP30环境温湿度检测设计

    好记性不如烂笔头 既然不够聪明 就乖乖的做笔记 温故而知新 Phosphor IOT Module是以DA14585作为主控的用于环境监测的评估板 DA14585是符合Bluetooth 5 0标准 16M 32位ARM Cortex M0
  • CC2642 数据长度扩展(LE Data Length Extension)

    概要 数据长度扩展 LE Data Length Extension 功能允许LE控制器在连接状态下发送具有高达251字节的PDU 在连接期间的任何时刻 主从设备可以协商该PDU大小 这个和MTU不同 MTU是应用层的数据传输长度 这个是链
  • 蓝牙PHY6222添加OTA升级功能

    主要步骤 1 代码添加 ota app service 2 keil软件添加ota app代码 3 烧录软件添加ota设置 4 手机ota app升级 准备 奉加微电子官网下载6222的代码SDK V3 0以上 下载官网的PhyPlusKi
  • 解密蓝牙mesh系列

    转载自 蓝牙技术联盟 蓝牙mesh网络 低功耗 低功耗蓝牙 低功耗蓝牙 Bluetooth Low Energy 是一项相当成功的无线技术 如今已经很难找到不支持低功耗蓝牙的智能手机或平板电脑了 可以说它是可穿戴技术兴起的关键因素 在医疗设
  • BLE蓝牙笔记----数据包解析

    本文是参考一些博文和书籍做的笔记 如有不适联系删除 参考 https www cnblogs com iini p 8977806 html BLE4 0 低功耗蓝牙 协议 总结 目录 1 广播包 1 1 PDU Type 1 2 MAC地
  • 蓝牙 BLE 协议学习: 有关概念介绍

    背景 在学校内就用过蓝牙技术参加过比赛 并拿了奖 而蓝牙作为物联网中比较常见的协议 有必要进行深入的学习 此后的文章会以 ble v4 0 进行学习 介绍 蓝牙技术最初由电信巨头爱立信公司于 1994 年创制 当时是作为 RS232 数据线
  • nRF52832 — 串口BLE例程逐行解析【转载】

    原文链接 http blog csdn net u011034150 article details 50617686 转载文章 若有不妥 通知后我会立即删除 本讲逐行代码解析官方串口BLE例程demo 主要分一下几个部分 1 Main函数
  • Android BLE API:未收到 GATT 通知

    用于测试的设备 Nexus 4 Android 4 3 连接工作正常 但onCharacteristicChanged我的回调方法从未被调用 但是我正在使用注册通知setCharacteristicNotification char tru
  • Android Ble GATT_ERROR 133 经常使用三星设备

    我正在研究 BLE 应用程序 我已经使用 Nexus Moto Samsung LG 等不同设备进行了测试 我仅在三星设备中收到 GATT 错误 133 三星 A5 2016 尝试连接 10 次 但只连接了 2 或 3 次 请帮助我 Non
  • Android 中的 BLE Gatt onConnectionStateChanged 失败,状态为 257

    我正在开发一个同时连接到多个BLE设备的Android应用程序 之后我从这些设备永久读取特征 但过了一会儿 我在onConnectionStateChanged 函数中得到状态257 android文档没有解释错误的原因是什么 或者如何修复

随机推荐