[BLE]低功耗蓝牙之GAP、GATT_ble gap gatt-程序员宅基地

技术标签: BLE  开发人员  框架  

一、开篇

    本篇主要介绍一下关于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.

0

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






版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_21842557/article/details/50771077

智能推荐

Lua保留规定小数位数_lua保留小数点后两位-程序员宅基地

文章浏览阅读4.2k次。使用string格式化方式 如果需要的结果是字符串,则可以使用string.format()函数 保留2位小数:string.format(“%.2f”, x)使用数字计算方式 使用%运算符,得到的结果是数字 x%1 表示x的小数部分,x-x%1 表示x的整数部分。 类似的,x-x%0.01 将x精确到小数点后2位。----------------..._lua保留小数点后两位

Bellman-Ford算法和队列优化(SPFA)——求单源最短路径_bellman-ford算法 c语言 找出最短路径-程序员宅基地

文章浏览阅读749次。来源自我的博客 http://www.yingzinanfei.com/2017/04/07/bellman-fordsuanfaheduilieyouhuaspfaqiudanyuanzuiduanlujing/#include #include int main(){ int n, m; scanf("%d%d", &n, &m);_bellman-ford算法 c语言 找出最短路径

vue中多行文本标签_css实现单行、多行文本超出显示省略号-程序员宅基地

文章浏览阅读1k次。前言:项目中我们经常遇到这种需求,需要对单行、多行文本超出显示为省略号。这篇文章主要总结了小编解决此问题的方法,有不足之处欢迎大家指正。单行文本省略.ellipsis-line {border: 1px solid #f70505;padding: 8px;width: 400px;overflow: hidden;text-overflow: ellipsis; //文本溢出显示省略号white..._vue css 单行显示

python基础 - pip 安装与升级_pip-23.2.1-py3-none-any.whl-程序员宅基地

文章浏览阅读5.7k次,点赞2次,收藏9次。pip 是 Python 包管理工具,该工具提供了对Python 包的查找、下载、安装、卸载的功能。Python 2.7.9 + 或 Python 3.4+ 以上版本都自带 pip 工具。pip 官网:https://pypi.org/project/pip/通过以下命令来判断是否已安装:C:\Users\Rnanprince>pip -Vpip 19.1.1 from D:\Program Files\Anaconda3\lib\site-packages\pip (python 3_pip-23.2.1-py3-none-any.whl

SSM整合web项目访问同时html和jsp页面_jsp和ssm冲突吗-程序员宅基地

文章浏览阅读2.3k次。ssm 配置请看:https://blog.csdn.net/qq_19688207/article/details/114578526?spm=1001.2014.3001.5501更改其中SpringMVC-servlet.xml和web.xml一、SpringMVC-servlet.xml配置:新增: <!-- 载入静态资源文件 --> <mvc:resources location="/resources/" mapping="/resources..._jsp和ssm冲突吗

谷歌浏览器安装json格式化插件_chrom92 json-程序员宅基地

文章浏览阅读268次。实际开发工作中经常用到json数据,那么就会有这样一个需求:在谷歌浏览器中访问URL地址返回的json数据能否按照json格式展现出来。比如,在谷歌浏览器中访问:http://jsonview.com/example.json展现效果如下:那么安装了JsonView扩展程序后的展现效果如下:很明显,后者的效果更好。实现步骤如下:1、下载JsonView扩展程序压缩包下载地址:https://github.com/gildas-lormeau/JSONView-for-Chro_chrom92 json

随便推点

pip install uwsgi安装uwsgi出错_pip安装uwsgi python.h no such-程序员宅基地

文章浏览阅读1.6w次,点赞3次,收藏10次。使用python3.6安装uwsgi 老出错找不到 Python.hplugins/python/uwsgi_python.h:2:20: fatal error: Python.h: No such file or directory compilation terminated.网上搜了很多方法都没解决。仔细研究一番之后发现Python版本造成的,首先找到pip安装目录,$ pip inst..._pip安装uwsgi python.h no such

【STM32H7】第3章 ThreadX FileX移植SDIO接口SD的基础知识_stm32h7 sdmmc filex-程序员宅基地

文章浏览阅读1k次,点赞2次,收藏6次。论坛原始地址(持续更新):http://www.armbbs.cn/forum.php?mod=viewthread&tid=100749第3章 ThreadX FileX移植SDIO接口SD的基础知识本章节为大家讲解SDMMC(Secure digital input/output MultiMediaCard interface)总线的基础知识和对应的HAL库API。为下个章节SD卡的移植做准备。目录第3章 ThreadX FileX移植SDIO接口SD的基础知识3...._stm32h7 sdmmc filex

css伪类之input输入框鼠标点击边框变色效果_css 伪类选择器 鼠标键入input框-程序员宅基地

文章浏览阅读5w次,点赞13次,收藏37次。css相关,鼠标点击输入域后出现有颜色的边框.problem input:focus{ border-style:solid; border-color: #03a9f4; box-shadow: 0 0 15px #03a9f4;}css相关,鼠标点击输入域后出现有颜色的边框效果如下:进行更多交流微信扫描_css 伪类选择器 鼠标键入input框

支付宝H5支付调不起来,提示ERR_UNKNOWN_URL_SCHEME_h5 app 支付宝页面无法打开 net::err_unknoen_url_scheme-程序员宅基地

文章浏览阅读4.2k次。在WebView中如果使用到支付宝,需要添加以下代码,否则操作系统会将支付宝的URL拦截,导致你打不开支付宝页面。mWebView.setWebViewClient(new WebViewClient(){ @Override public boolean shouldOverrideUrlLoading(WebView view, _h5 app 支付宝页面无法打开 net::err_unknoen_url_scheme

长春高中计算机考试时间安排,2019年长春中考考试时间安排,长春中考考试科目时间安排表...-程序员宅基地

文章浏览阅读304次。2019年长春中考考试时间安排,长春中考考试科目时间安排表每年的长春中考时间每年大约在6月中下旬及7月上旬,具体详细时间要等每年教育局具体出通知。本文小编整理了关于2019年长春中考考试时间及考试科目安排的相关资讯,再次提醒具体准确时间和科目请参考长春教育局官方发布的通知公告。一、长春中考考试时间安排及科目6月27日上午8:30—10:30,语文6月27日下午14:00—15:40,物理和化学(合..._长春美术自动化考试

SPI协议讲解与总结_spimode-程序员宅基地

文章浏览阅读5.3k次,点赞9次,收藏25次。SPI的通信原理很简单,它以主从方式工作,这种模式通常有一个主设备和一个或多个从设备,需要至少4根线,事实上3根也可以(单向传输时)。它们分别是MISO(主设备数据输入)、MOSI(主设备数据输出)、SCLK(时钟)、CS(片选)。_spimode

推荐文章

热门文章

相关标签