本系列文章由江山(csdn名:补不补布)(github:jianggogogo)自己写成,当中用到引用时都已经标记出来,如果出现版权问题,请直接联系我修改。当然,技术在于分享,欢迎大家转载,不过请注明出处。最后,如果出现有错误的地方欢迎大家指正。
基于谷雨cc2640教程
对蓝牙有基础的朋友可能知道蓝牙的一些概念,这就是一个典型蓝牙协议栈。那么对于蓝牙新手来说,我们就可以降蓝牙协议栈看作是一个飞机,我们只需要学习如何开飞机就行,至于飞机怎么做,那不是我们现阶段需要考虑的事情。
有效连接间隔等于两个连接事件之间的时间跨度。当没有数据从从机发送到主机时,从机每500ms 一个 连接事件 交互一次 。
为了有时间能够扫描新设备,可以使用的最小连接间隔为12.5+5*n。n为当前连接的数量。
外设可以发送连接参数更新请求来请求主机更改连接设置。
-该请求包含四个参数:最小连接间隔,最大连接间隔,从延迟和
监管 超时。这些值表外围设备对连接所需的参数(连接间隔作为范围给出)。当 主机 设备接收到该请求时,它可以接受或拒绝新的参数。
主机和从机可以由于任何原因终止连接,一方终止,另一方必须在两台设备退出连接状态之前进行相应。
应用层可以直接调用GAP APi来执行BLE相关功能,大多数GAP由GAProle task处理。
GAP层功能主要在库代码中定义,这些功能大多由GAPRole调用,不需要应用直接调用。
操作流程:
1、 初始化GAPRole参数:
2、初始化GAPROle任务,并且将应用程序回调函数传回GAPRole。
4、GAPRole任务处理了绝大多数GAP事件,将一些事件转发到应用程序。
1、初始化参数:
2、启动任务:
3、从应用程序中发送数据之后,会通过central函数到达stack。
4、GAPRole任务也处理了一部分事件,然后将一部分事件转发到应用程序。
GATT主要用于两个连接设备之间的数据通信。数据以特征值的形式传输和存储。从GATT的角度来看,:
1、gatt服务
2、通用属性服务:GATT服务器的信息。
3、设备信息服务:
4、simple_gatt_profile 这个是用于测试的profile文件。
以下是简单Profile 文件属性表的逐行描述,由以下句柄引用。
0x001F是 simple_gatt_profile 服务声明 。该声明的 UUID 为 0x2800 (蓝牙定义的
GATT_PRIMARY_SERVICE_UUID )。该声明的值是 simple_gatt_profile (自定义)的 UUID 。
0x0020是 SimpleProfileChar1 的特征声明 。该声明可以被认为是指向
SimpleProfileChar1 值的指针。该声明的 UUID 为 0x2803 (蓝牙定义的
GATT_CHARACTER_UUID )。 5 字节 的特征值如下 (从 MSB 到 LSB
字节0 :蓝牙规范中定义的 SimpleProfileChar1 的属性(以下是一些相关属性。)
0x02:允许读取特征值
0x04:允许写入特征值(无响应
0x08:允许写入特征值(带响应
0x10:允许通知特征值(无确认
0x20:允许通知特征值(带确认 0x0A 的值表示特性可读( 0x02 )和可写 0x08 )。
字节1 2 SimpleProfileChar1 值的字节反转句柄(句柄 0x0021
字节3 4 SimpleProfileChar1 值的 UUID (自定义 0xFFF1
0x0021是 SimpleProfileChar1 值 。该值的 UUID 为 0xFFF1 (自定义)。该值是特征的实际有效载荷数据。如其特征声明(句柄 0x0020 )所示,该值是可读写的。
0x0022是 SimpleProfileChar1 用户描述 。该描述的 UUID 为 0x2901 (蓝牙定义)。该
描述的值是描述特征的可读字符串。
0x00230x002F 是剩下的四个特征描述的 simpleProfileChar1 相同结构的属性。 唯一
不同的 属性,处理 0x002B ,描述如下。
0x002B是 SimpleProfileChar4 客户端特征配置 。此配置的 UUID 为 0x2902 (蓝牙定
义)。通过写入此属性, GATT 服务器可以将 SimpleProfileChar4 配置为通知。
GGS是实主机或者外围设备的低功耗多必须的。当然,使用低功耗的设备也必然包含GGS。GGS的目的实在设备发现和连接启动的过程中进行辅助。
$install/src/inc #include "gapgattserver.h"
// GAP GATT Attributes
static uint8_t attDeviceName[GAP_DEVICE_NAME_LEN] = "Simple BLE Peripheral"; GGS_SetParameter(GGS_DEVICE_NAME_ATT, GAP_DEVICE_NAME_LEN, attDeviceName);
3、使用GGS初始化应用程序回调。
4、将GGS添加到GATT服务器。
该服务提供注册GATT服务的相关信息。
这一部分要求用户必须使能GATT可变服务属性,当使用ble的时候。
GATT客户端没有属性表或者profile文件。因为他是收集方。
同样的,GATT的服务也在库中实现:
VOID GATT_InitClient();
GATT_RegisterForInd(selfEntity);
5、GATT客户端可以从GATT服务器接受指示或者数据。
GATT得大部分配置在:GattServApp
GATTServApp存储和管理应用程序范围的属性表。各种 Profile 文件使用此模块将其特性添加到属性表 中 。低功耗蓝牙 协议栈 使用此模块来响应 GATT 客户端的请求。例如, GATT客户端可以发送“发现所有主要特征”消息。 GATT 服务器上的 低功耗蓝牙协议栈 收到此消息,并使用 GATTServApp 查找并发送存储在属性表中的所有主要特性。从 Profile 文件访的GATTServApp 功能在 gattservapp_util.c 中定义。
1、创建属性表:
// 初始化GATT属性
GGS_AddService(GATT_ALL_SERVICES); //添加服务
GATTServApp_AddService(GATT_ALL_SERVICES); //添加属性服务
DevInfo_AddService(); // 加入设备信息服务
#ifndef FEATURE_OAD_ONCHIP
SimpleProfile_AddService(GATT_ALL_SERVICES); // Simple GATT Profile #endif //!FEATURE_OAD_ONCHIP
我们可以查到profile的翻译有:轮廓;简介;形象;外形。但是你在蓝牙协议中这个词语究竟是代表什么。其实不是很好定义,不妨我们直接就简单的把这个profile看成字母A,然后我们自己来定义这个定义:
每个GATT属性的服务,都需要一个属性表:
表的定义:
static gattAttribute_t simpleProfileAttrTbl[SERVAPP_NUM_ATTR_SUPPORTED]
typedef struct attAttribute_t { gattAttrType_t type; //!< Attribute type (2 or 16 octet UUIDs)
uint8 permissions; //!< Attribute permissions
uint16 handle; //!< Attribute handle - assigned internally by attribute server
uint8* const pValue; //!< Attribute value - encoding of the octet array is defined in //!< the applicable profile. The maximum length of an attribute //!< value shall be 512 octets. } gattAttribute_t;
权限配置:
应用程序启动的时候,需要添加所支持的GATT服务:
1、为客户端特征配置CCC数组分配空间:
2、初始化CCC数组,
GATTServApp_InitCharCfg(INVALID_CONHANDLE, simpleProfileChar4Config );
3、使用GATTServApp注册配置文件:
1、客户端读取请求:
当给定属性收到GATT客户端的读取请求的时候,调用回调文件。
2、客户端的写请求:
GATT_PARAM_NUM_PREPARE_WRITES
GATT_RegisterForMsgs
可以接收到更多的GATT事件:
主要有以下三类:
1、GATT服务器无法发送ATT相应,尝试在下一个连接间隔发送。
2、ATT流量控制违规,通知应用程序接入的设备违反ATT流量规则。
3、更新ATT MTU大小。
在客户端通过认证配对方法之前,无法访问需要身份验证的特性。
应用程序需要定义自己的授权请求,所以协议栈将这些特性的读写请求转发到应用程序层。
1、 注册授权回调:
CONST gattServiceCBs_t simpleProfileCBs = {
simpleProfile_ReadAttrCB, // Read callback function pointer
simpleProfile_WriteAttrCB, // Write callback function pointer
simpleProfile_authorizationCB // Authorization callback function pointer };
2、调用回调函数:
不要再这里执行复杂的功能
static bStatus_t simpleProfile_authorizationCB( uint16 connHandle,gattAttribute_t *pAttr,uint8 opcode ) {
//This is just an example implementation, normal use cases would require //more complex logic to determine that the device is authorized
if(clientIsAuthorized)
return SUCCESS;
else return ATT_ERR_INSUFFICIENT_AUTHOR; }