用户工具

站点工具


侧边栏

CC2640R2&BLE5.0开发

关于我们

入门开始

视频教程

外设驱动

开发BLE应用

工具集

其他

cc2640r2f:gatt

这是本文档旧的修订版!


通用属性配置文件(GATT)

正如GAP层负责连接相关的功能,GATT主要是负责在两个已经连接的设备交互数据,GAP层把BLE设备区分为主机Master(Central)和从机Slave(Perpherial),在GATT层则区分为Server和Client。客户端读取和写入存储在服务端的特征值(Characteristics )。

Server
该设备包含由GATT客户端读取或写入的characteristic。

Client
从GATT服务器读取或写入数据的蓝牙设备。

注意:对于GATT分层的Server/Client角色和GAP分层的Master(Central)/Slave(Perpherial)并没有直接关系。如上图,手机作为Central/Client,CC2640R2开发板作为 Peripheral/Server。

GATT的Profile、Service、Characteristics、Attributes

对于GATT层的Profile、Service、Characteristics、Attributes概念,我们一定要深入理解,因为一旦建立连接后,不管是嵌入式端还是应用端进行数据交互的都是这些概念。为了帮助理解,我们抽象以下包含关系:

一个或者多个Characteristic组成一个Service,一个多个Service组成Profile,Characteristic又由多个Attributes组成,每个Attribute由包含 Handle、Type、Permissions三个属性。
以下我们着重理解Characteristic,也是我们数据交互的最终实体,每个特征包含以下4个Attributes。

  • Characteristic Value(特征值)
    用于characteristic的值

  • Characteristic Declaration(特征声明)
    存储特征值的属性,位置和类型的描述符

  • Client Characteristic Configuration(客户端特征配置)
    允许GATT服务器配置要通知的特性(异步发送消息)或指示的配置(与确认异步发送消息)

  • Characteristic User Description(特征用户描述)
    描述特征的ASCII字符串
    这些属性存储在属性表中的GATT服务器中。除了该值之外,以下属性与每个属性相关联。

以上的每个Attributes 又由以下元素组成。

  • Handle(句柄)
    表中属性的索引(每个属性都有一个唯一的句柄)

  • Type(类型)
    指示属性数据表示什么(称为UUID [通用唯一标识符],其中一些是蓝牙SIG定义的,一些是自定义的)

  • Permissions(权限)
    强制GATT客户端设备如何以及如何访问属性的值

GATT客户端抽象层

下图所示,在GATT客户端应用程序大部分是直接使用GATT的API(少部分直接使用ATT层API),没有profile文件,因为GATT客户是得到数据,不需要建立属性表和配置文件。

GATT服务端抽象层

如图所示,在GATT服务端,GATT层的大部分功能由独立的profiles处理,然后可以看见perfiles又使用GAttservApp模块(一个可配置的模块,用于储存和管理属性表,详见BLE Stack API Reference)处理。

所以在建立GATT服务端的时候首先需要配置profiles文件,profiles文件调用GattServAppApp模块并使用其API与GATT层接口。在这种情况下应用程序不需要直接调用GATT层API,应用程序和Profiles文件接口。

GATT Services 和 Profile

在概述部分讲过,GATT service是characteristic的集合,多个service可以组合在一起形成一个profile,许多profile仅实现一个service,所以profile和service可以互换。

在simple_peripheral示例应用程序项目中定义了四个GATT服务。

  • GAP GATT服务(GGS)
    此服务包含设备和访问信息,例如设备名称,供应商标识和产品标识。
    为此服务定义了以下特征:

    设备名称
    表现(Appearance)
    外围首选连接参数

  • 通用属性服务
    该服务包含有关GATT服务器的信息,是蓝牙低功耗协议栈的一部分,每个GATT服务器设备都需要根据蓝牙5.0版本核心规范。

  • 设备信息服务
    此服务公开了有关设备的信息,如硬件,软件版本,固件版本,规范信息,合规性信息和制造商名称。设备信息服务是蓝牙低功耗协议栈的一部分,由应用程序配置。

  • simple_gatt_profile服务
    此服务是用于测试和演示的示例配置文件。完整的源代码在simple_gatt_profile.c和simple_gatt_profile.h文件中提供。
      // Initialize GATT attributes
      GGS_AddService(GATT_ALL_SERVICES);           // GAP GATT Service
      GATTServApp_AddService(GATT_ALL_SERVICES);   // GATT Service
      DevInfo_AddService();                        // Device Information Service
      SimpleProfile_AddService(GATT_ALL_SERVICES); // Simple GATT Profile

    下图显示了simple_peripheral项目中的属性表,这些属性的设置都是通过上面4个服务函数。可以逐一打开查看修改。

使用BTool获取的简单GATT配置文件特性表。红色表示Profile声明,黄色表示字符声明,White表示与特定声明相关的属性。

simple_gatt_profile包含以下特性:

  • SIMPLEPROFILE_CHAR1
    可以从GATT客户端设备读取或写入的1字节值
  • SIMPLEPROFILE_CHAR2
    可以从GATT客户端设备读取但不能写入的1字节值
  • SIMPLEPROFILE_CHAR3
    可以从GATT客户端设备写入但不能读取的1字节值
  • SIMPLEPROFILE_CHAR4
    不能从GATT客户端设备直接读取或写入的1字节值(该值是通知属性)
  • SIMPLEPROFILE_CHAR5
    可从GATT客户端设备读取(但不写入)的5字节值

0x001C是simple_gatt_profile服务声明。
此声明的UUID为0x2800(蓝牙定义 GATT_PRIMARY_SERVICE_UUID)。该声明的值是simple_gatt_profile(自定义)的UUID。

0x001D是SimpleProfileChar1特征声明。
该声明可以被认为是指向SimpleProfileChar1值的指针。该声明的UUID为0x2803(蓝牙定义GATT_CHARACTER_UUID)。下面解释characteristic声明值的含义(MSB到LSB):

  • 字节0是蓝牙核心规范版本5.0中定义的SimpleProfileChar1的属性 (以下是某些相关属性)。
    0x02:允许读取特征值
    0x04:允许写入特征值(无响应)
    0x08:允许写入特征值(带响应)
    0x10:允许通知特征值(无确认)
    0x20:允许通知特征值(带确认)
    characteristic1 0x0A的意义是该特性可读可写(0x02|0x08)
  • 字节1-2:SimpleProfileChar1的值的句柄(句柄0x001E)
  • 字节3-4:SimpleProfileChar1值的UUID(自定义0xFFF1)

  • 0x001E是SimpleProfileChar1特征值
    该值的UUID为0xFFF1(自定义)。该值是characteristic的实际有效载荷数据。如其SimpleProfileChar1声明(句柄0x01D)所示,该值是可读写的。

  • 0x001F是SimpleProfileChar1特征用户描述
    该描述的UUID为0x2901(蓝牙定义)。该描述的值是描述特征的用户可读字符串。

  • 0x0020 - 0x002C
    剩下的四个特征描述具有和simpleProfileChar1相同结构的属性。唯一不同的属性是处理0x0028时,描述如下。

    0x0028是SimpleProfileChar4客户端特征配置。此配置的UUID为0x2902(蓝牙定义)。通过写入此属性,GATT服务器可以将SimpleProfileChar4配置为通知(写入0x0001)或指示(写入0x0002)。将0x0000写入此属性将禁用通知和指示。

GATT安全

如GATT 服务端抽象所述,GATT服务器可以为每个特性独立定义权限。服务器可能允许任何客户端访问某些characteristic,同时将访问其他characteristic仅限于认证或授权的客户端。这些权限通常被定义为更高级别的配置文件规范的一部分。对于自定义配置文件,用户可以选择他们认为合适的权限。有关GATT安全性的更多信息,请参阅蓝牙核心规范版本5.0的安全注意事项部分([第3卷,第G部分,第8部分])。

认证(Authentication)

在客户端通过认证配对方法之前,无法访问需要身份验证的特性。此验证在堆栈内执行,无需应用程序处理。唯一的要求是使GATT服务端正确注册该特性。
例如,simple_gatt_profile的characteristic5设置需要认证的读取。

//characteristic 5 
{ 
   {  ATT_BT_UUID_SIZE , simpleProfilechar5UUID  },
   GATT_PERMIT_AUTHEN_READ ,
   0 ,
   simpleProfileChar5 
},

当未经身份验证的客户端尝试读取此值时,GATT服务器将自动拒绝它,而不调用simpleProfile_ReadAttrCB()。只有当认证成功之后,读写的请求才会转发到profiles的读写回调,请参阅一下代码,该代码在simple_gatt_profile.c中simpleProfile_ReadAttrCB()函数里面。

  case SIMPLEPROFILE_CHAR1_UUID:
  case SIMPLEPROFILE_CHAR2_UUID:
  case SIMPLEPROFILE_CHAR4_UUID:
    *pLen = 1;
    pValue[0] = *pAttr->pValue;
    break;

  case SIMPLEPROFILE_CHAR5_UUID:
    *pLen = SIMPLEPROFILE_CHAR5_LEN;
    VOID memcpy( pValue, pAttr->pValue, SIMPLEPROFILE_CHAR5_LEN );
    break;

  default:
    // Should never get here! (characteristics 3 和 4没有读权限)
    *pLen = 0;
    status = ATT_ERR_ATTR_NOT_FOUND;
    break;

授权(Authorization)

授权是发生在认证之后对一些文档的访问权限更改删除,需要授权。授权是BLE已经实现的一个安全层。由于应用程序需要定义自己的授权要求,所以协议栈将这些特性的读/写请求转发到配置文件的应用程序层。

要从profile文件注册GATT服务器的授权信息,它必须使用堆栈定义一个授权回调。如下面伪代码(例程中没有使用授权)。

  1. 注册授权回调
    CONST  gattServiceCBs_t  simpleProfileCBs  = { 
       simpleProfile_ReadAttrCB ,      //读回调函数指针
       simpleProfile_WriteAttrCB ,     //写回调函数指针
       simpleProfile_authorizationCB   //授权回调函数指针
    };
  2. 实现授权回调代码

    static  bStatus_t  simpleProfile_authorizationCB ( uint16  connHandle , gattAttribute_t  * pAttr , uint8  opcode  )
    { 
       //这只是一个示例实现,正常的用例将需要
       更复杂的逻辑来确定设备是否被授权
    
       if (clientIsAuthorized )
          return SUCCESS ; 
       else
          return ATT_ERR_INSUFFICIENT_AUTHOR ; 
    }

    授权回调在协议栈上下文中执行,因此在这个函数中不应该执行太复杂的处理。具体实现由开发人员决定;上述回调应该被视为一个shell。如果客户端有权访问该特征返回SUCCESS,如果没有返回ATT_ERR_INSUFFICIENT_AUTHOR,授权需要事先通过连接进行身份验证,否则ATT_ERR_INSUFFICIENT_AUTHEN将作为错误响应发送。

如果需要授权的特性并注册了授权回调,但没有定义应用级授权回调,那么协议栈将返回ATT_ERR_UNLIKELY。因为这个错误并不明确,所以TI建议使用授权回调。

直接使用GATT层

上面客户端抽象说过,应用程序也可以直接使用GATT层API,本节就介绍如何在应用程序中使用GATT层,GATT层的功能在库中实现,但头文件功能可在gatt.h中找到。BLE Stack API Reference中有完整的API参考。作为GATT客户端(在simple_central项目中)使用GATT层的一般过程如下:

图中可以看出,GATT客户端发送命令之后,通过ICALL给协议栈发送ATT命令,然后协议栈处理之后返回响应,再由ICALL以ATT事件通知应用程序,应用程序得到ATT事件之后异步处理。注意:除了收到对自己的命令的响应外,GATT客户端还可以从GATT服务器接收异步数据作为指示或通知。使用GATT_RegisterForInd(selfEntity)注册接收这些ATT通知和指示。这些通知和指示也作为ATT事件(ATT_HANDLE_VALUE_NOTI& ATT_HANDLE_VALUE_INDG)发送到应用程序。这些事件必须按照GATT Services和Profile中的说明进行处理。

GAP GATT 服务(GGS)

在前面GATT服务和简介中说过,GGS服务包含设备和访问信息,例如设备名称,Appearance,外围首选连接参数。GGS的目的是在设备发现和连接启动过程中进行辅助。有关GGS的更多信息,请参阅蓝牙核心规范版本5.0的“GAT service”和“Characteristics for GATT Server”部分([Vol 3],C部分,第12节)。

  1. 包含标题
    #include  “gapgattserver.h”
  2. 初始化GGS参数
    // GAP GATT Attributes 
    static  uint8_t  attDeviceName [ GAP_DEVICE_NAME_LEN ]  =  “This is a text” ;   
    GGS_SetParameter (GGS_DEVICE_NAME_ATT , GAP_DEVICE_NAME_LEN , attDeviceName );
  3. 使用GGS初始化应用程序回调(可选)。当GGS中的任何特征发生变化时,都会通知应用程序。
    GGS_RegisterAppCB (&appGGSCBs );
  4. 将GGS添加到GATT服务器。
    bStatus_t  GGS_AddService (GATT_ALL_SERVICES );

    经过上面4个步骤的配置,就成功设置了GGS的参数,在central设备连接外围设备的时候就能获取这些参数,使用我们公司提供的XXX.apk可以在手机界面直接查看我们设置的参数值。

加入我们

文章所有代码、工具、文档开源。加入我们QQ群 591679055获取更多支持,共同研究CC2640R2F&BLE5.0。

CC2640R2F&BLE5.0-乐控畅联 © Copyright 2017, 成都乐控畅联科技有限公司.

cc2640r2f/gatt.1504168239.txt.gz · 最后更改: 2021/06/22 23:14 (外部编辑)