3 软件概述
使用BLE软件开发套件进行软件开发包括五个主要的阶段:OSAL,HAL,BLE协议栈,配置文件和应用.BLE协议栈是以编译后的接口提供的(看不到源码),然而OSAL和HAL代码是以源码提供的.除此之外,三个GAP profiles(外设,控制,外设结合管理)提供,还有许多GATT 配置和应用例程.
这个文档在BLE开发套件软件的默认安装目录中,路径是C:\Texas Instruments\BLE-CC254X-1.3.2\.
注意:在这一段中,SimpleBLEPeripheral工程会被作为一个参考;然而所有的BLE工程都是相识的结构.
3.1 操作系统抽象层(OSAL)
BLE协议栈,配置文件和所有应用建立在OSAL上.OSAL不是一个传统感觉的操作系统,相反地是一个循环控制,允许软件去建立事件执行.软件的各种层需要这种类型的控制,一个任务标识符必须被创建,任务初始化进程必须被定义并加入到OSAL初始化中,并且一个事件处理进程必须被定义.可选地,一个消息处理进程也应该被定义.BLE栈的许多层都是OSAL任务,比如LL层,因为它的优先级最高(因为它需要非常严格的时钟要求).
除任务管理之外,OSAL提供一些额外的服务,比如消息传递,内存管理和时钟.所有的OSAL代码都是以源码提供.
注意:OSAL提供的服务远远不止这里提到的,包括消息管理,计时器管理等等;然而许多应用对这些深层次的不需要.这个指导只是对OSAL架构做了一个基本的介绍.
3.1.1 任务初始化
为了使用OSAL,在main函数的结尾应该调用osal_start_system函数.这是开始运行系统的OSAL程序,且它会调用在应用中定义的isalInitTasts函数.在SimpleBLEPeripheral工程中,这个函数可以在OSAL_SimpleBLEPeripheral.c中发现.
使用OSAL的软件的每一层必须有一个初始化程序,它会被调用在osalInitTasks函数.在这个函数中,每一个层的初始化程序都会被调用.因为任务初始化程序被调用,一个8位的任务ID被指派到各个任务.注意当创建一个应用时,非常重要的一点是你要把它添加到任务列表的末端,这样它会有一个比较高的任务ID比其他任务.这是因为任务ID决定了任务的优先级,一个低的任务ID意味着高的优先级(任务ID是从0开始增加的,增加一个任务,ID++).协议栈的任务有一个高的优先级是非常重要的,这样才能恰当的完成任务.比如SimpleBLEPeripheral应用,它的初始化函数是SimpleBLEPeripheral_Init,且它有一个最高的任务ID,因此优先级也最低.
3.1.2 任务事件和事件处理
当完成里OSAL初始化后,它运行执行循环(死循环)去检测任务事件.这个循环在OSAL.c中的osal_start_system函数中能找到.任务时间是以一个16位变量实现的,每个任务有一个16位事件变量,事件变量的每一位是一个唯一的事件.定义和这些标志的使用完全在于应用程序.
比如,SimpleBLEPeripheral应用定义了一个标志在simpleBLEPeripheral.h中:SBP_START_DEVICE_EVT(0x0001),它代表初始化已经完成且应用程序已经开始.一个唯一的标志是保留的且不能被应用程序定义,它是0x8000,它对应的事件是SYS_EVENT_MSG(这个任务被用在任务间消息的通知,它会在3.1.3涉及到).
当OSAL检测到一个任务的事件后,它会调用这个任务的时间处理函数.每一层必须添加它的时间处理程序到表中,这个表是由叫tastsArr的函数指针数组构成的(tastsArr位于OSAL_SimpleBLEPeripheral.c中).你会注意到事件处理程序在tastsArr中的次序和任务ID在osalInitTasks函数中的次序是一致的.这样的要求是为了通过合适的软件层处理事件.
就SimpleBLEPeripheral应用而言,事件处理函数叫做SimpleBLEPerpheral_ProcessEvent.注意的是事件如果被处理后,但是没有从事件标志中移除,OSAL将继续调用任务的事件处理函数.正如SimpleBLEPeripheral应用中SimpleBLEPeripheral_ProcessEvent函数,在START_DEVICE_EVT事件发生后,它返回16位事件变量,用SBP_START_DEVICE_EVT标志清除.
对于软件中的其他层设置一个OSAL事件向其他层,或者是自己是可能的.最简单的设置OSAL事件是使用osal_set_event函数(原型在OSAL.h),它会立刻调度一个新的事件.在这个函数中,你指定任务ID(任务将要处理事件)和事件标志作为参数.
另一种设置OSAL事件向其他层的方法是使用osal_start_timerEx函数(原型在OSAL_Timers.h).这个函数操作类似于osal_set_event函数.你选择任务的ID(任务处理事件)和事件处理标志作为参数.然而osal_sart_timerEx中的第三个参数,你应该输入一个毫秒单位的超时值.OSAL将要设置一个定时器,指定的事件不会得到设置直到定时器超时.
3.1.3 堆管理
OSAL提供基本的内存管理函数.osal_mem_alloc函数提供一个基本的内存分配函数类似于标准C分配内存函数,需要一个参数决定分配内存的字节数,且返回一个无类型的指针.如果没有内存可以分配,一个空指针将返回.类似地,osal_mem_free函数工作类似于标准C free函数,释放先前由osal_mem_alloc分配的内存.
预处理定义INT_HEAP_LEN被使用来预留动态分配的内存.
为了指导你会使用多少内存,你可以设置预处理定义OSALMEM_METRICS=TRUE在工程选项中,然后在应用的压力测试下,你发送尽量多的消息,连接尽量多的客户机在最坏的情况下,如果应用是可应用地,记得使用结合和加密在测试期间,你会在OSAL_Memory.c中的memMax变量中看到在同一时间曾经分配的内存.这种方法可以可以做为一种降低INT_HEAP_LEN的一种指导,如果需要的话,但是测试是需要的,因为堆会被使用通过BLE栈.
3.1.4 OSAL消息
OSAL也提供了一种系统,不同的软件中的子系统相互之间交流通过发送和接受消息.消息包括任意的数据类型和任意的数据长度.为了发送OSAL消息,第一块内存必须分配通过调用osal_msg_allocate函数,传递一个消息的长度作为唯一的一个参数.一个指向分配空间的指针将返回(你不需要使用osal_msg_alloc当使用osal_msg_allocate).如果没有内存可使用,一个空的指针将返回.你然后就可以复制数据到缓冲区了.为了发送消息,osal_msg_send将要被调用,目地任务和消息缓冲区的指针作为参数.
OSAL将给接收任务发送一个信号,一个信息到达了,通过设置SYS_EVENT_MSG标志为目地任务.这样引起接受任务的事件处理函数被调用.接收任务然后取回数据通过osal_msg_receive,且处理数据依据接受到的数据.推荐每一个OSAL任务有一个局部消息处理函数(simpleBLEPeripheral应用的消息处理函数是simpleBLEPeripheral_ProcessOSALMsg),决定采取什么行动基于接收的消息类型.一旦接收任务完成处理消息,它必须解除分配内存通过osal_msg_deallocate(你不能使用osal_mem_free当使用osal_msg_deallocate).
3.2 硬件抽象层(HAL)
CC2540/41软件的硬件抽象层(HAL)提供了一个抽象接口在物理硬件和应用,协议栈之间.它允许一个新的硬件(PCB)移植而不需要修改协议栈和应用的源代码.HAL包括SPI,UART通信接口,ADC,keys和LED等.HAL驱动支持以下硬件平台:
SmartRF05EB+CC2540EM
SmartRF05EB+CC2541EM
CC2540 Keyfob
CC2541 Keyfob
CC2541 SensorTag
CC2540 USB Dongle
当开发一个不同的硬件平台,可能需要修改HAL源代码,从而保证兼容.
更多的信息关于HAL API在[2]可以找到.
3.3 BLE协议栈
BLE全部协议栈以一个库文件作为工程代码提供(德州仪器不提供协议栈的源代码因为政策问题).GAP和GATT层的功能应该这样理解,他们直接地相互作用和应用,配置文件.
3.3.1 通用访问配置文件(GAP)
BLE协议栈的GAP层负责支持设备访问模式和过程,包括设备发现,建立连接,中断连接,安全特性的开始,设备配置.
GAP层总是操作在四个角色中的一个角色:
l 广播 - 处于没有连接状态的登广告者
l 观察者 - 浏览广告,但是没有开始连接
l 外围设备 - 一个已经连接的登广告者,且是从模式进行操作在一个单一的链接层连接.
l 控制中心 - 浏览广告且开始连接;作为主模式操作在单一的或者多链接层连接.常见的,BLE控制栈支持3个以上同时连接.
BLE规格允许多个角色确定的合作.应用程序默认下只支持外围角色,虽然提供的源代码可以运行外围和广播角色的结合.
在典型的蓝牙低功耗系统中,外围设备用刊登一个特别的数据,让所有控制设备知道它是一个可连接的设备.这个广告包括设备地址,也包括许多额外的数据,比如设备名称.控制设备,一旦接收到广告,就会发送一个扫描请求给外围设备.外围设备回应一个扫描答复.这就是设备发现过程,在这个过程当中,控制设备察觉到外围设备,它可以建立一个连接和外围设备了.然后控制设备发送一个请求为了建立连接向外围设备.一个连接请求包含许多连接参数:
l 连接间隔 - 在BLE中,两个设备之间,一个跳变次数计划被使用,两个设备相互之间发送接收数据在一个具体的通道中,然后在一个新的通道(链接层操纵通道的转化)一个具体的时间之后相遇.两个设备发送和接收数据的相遇被认为是连接事件.甚至这里没有应用数据用于发送和接收,两个设备一直在进行链路层数据交换,来保持连接.连接间隔是两个连接事件之间的一段时间,是1.25ms的倍数.连接间隔在最小值6(1.25*6=7.5ms)和3200(1.25*3200=4s)之间.
不同的应用可能需要不同的连接间隔.拥有一个长的连接间 隔的优势是对节省电非常重要,因为设备在连接事件之间会睡 眠.不利的是如果设备有数据需要发送,它必须等待直到下一 个连接事件.
拥有一个短的连接间隔的优势是会有非常多的机会进行数据 的发送和接收,因为两个设备频繁的连接.不好的地方是会消 耗非常多的电量,因为设备频繁的唤醒在连接事件中.
l 从潜伏 - 这个参数是给从设备一个选项,可以跳过许多连接事件.这给了外围设备许多灵活性,如果没有数据发送,它会选择跳过连接事件继续睡觉,这样节省了许多电量.这个参数值适用于外围设备.
从潜伏值代表能跳过的最大的事件数.它从最小的0(没有连接事件跳过)到最大的499;然而最大的值不能使有效连接间隔大于16s(看下面公式)
l 监督超时 - 这是两个成功连接事件之间最大的时间.如果这个时间超时了没有成功连接,则设备被认为连接丢失,并且返回一个未连接的状态.这个参数的代表值是10ms的倍数.监督超时值从10(100ms)到3200(32.0s)之间.除此之外,超时值必须大于有效的连接间隔(在下面解释).
有效的连接间隔等于两个连接事件之间的时间,假设从机跳过最大的可能的时间如果从潜伏设置(有效的连接间隔等于实际的连接间隔如果从潜伏被设置为0).它可以使用以下的公式进行计算:
有效连接间隔 = (连接间隔)*(1 + (从潜伏))
举个例子如下:
连接间隔:80(100ms)
从潜伏:4
有效连接间隔:(100ms) * (1 + 4) = 500ms
这告诉我们,在没有数据从从机到主机这中情况下,从机只在500ms时发送数据.
在许多应用中,从机将跳过最大的连接间隔.因此当选择你的连接参数是考虑有效的连接间隔是有用的.选择正确的连接参数组合对你的BLE设备优化是至关重要的.下面列出一个通用的权衡的概述在连接参数设置中:
减少连接间隔会:
l 增加所有设备的电量消耗
l 增加所有直接连接的流量
l 减少发送数据到另一个设备的时间
增加连接间隔会:
l 减少所有连接设备的电量
l 减少所有连接设备的流量
l 增加发送数据到另一个设备的时间
减少从潜伏(或者设置为0)会:
l 增加外围设备的电量消耗
l 减少从主设备发送外围设备接收数据的时间
增加从潜伏会:
l 减少外围设备的电量消耗当外围设备没有数据给控制设备发送时
l 增加时间,控制设备发送数据从设备接收数据
在许多情况下,控制设备请求一个连接和外围设备,请求时包含一些参数,这个参数对外围设备是不利地.另一种情况下,外围设备有强烈的意愿要改变参数在连接当中,主要基于外围应用.外围设备会向控制设备发送申请通过”连接参数更新申请”,这个请求通过协议栈的L2CAP层控制.
这个请求包括四个参数:最小连接间隔,最大连接间隔,从潜伏和超时.这些参数是外围设备请求是给的(连接间隔是一个范围).当控制设备接收到这个请求,它会选择是接受还是拒绝这些新参数.
一个连接可以被主或者从设备的任何原因自动的终止.一边的设备发起了终止,另一边的设备必须在两个设备退出已连接状态前做出相应的回答.
在BLE连接期GAP也操控安全特性的发起.某个数据可能是可读的或者可写的只有在一个可授权的连接.一旦连接建立,两个设备会派对.当派对完成,当派对完成,加密和授权的密钥就会生成.一个典型的情况是外围设备需要主设备提供一个万能钥匙来完成派对过程.这个可以是一个固定的值,比如“000000”,或者随机生成一个值给使用者或者显示出来。然后主设备发送一个正确的万能钥匙,两个设备交换密钥来加密和授权连接。
在许多情况下,同样的主从设备将有规律的连接和断开。BLE有一套安全机制当派对时需要两个设备给对方一个长的安全密钥。这个机制叫做绑定,在再次连接时允许两个设备很快的再次建立解密和授权而不要进行完整的派对,因为他们已经相互保存了对方长的密钥信息。
在SimpelBLEPeripheral 应用中,GAP 角色的管理被GAP prifile操作,绑定信息的管理被GAP security profile操作。更多的CC2540/41 BLE 协议栈的GAP profiles会在3.4讲解。
3.3.2 Generic Attribute Profile(GATT)(通用属性框架)
BLE协议栈的GATT层是为了两个设备的应用进行数据通信设计的。从GATT观点看,两个连接的设备会是以下两种角色的一种:
GATT Client-这个设备从GATT Server读或者写数据。
GATT Server-这个设备提供可被GATT Client读和写的数据。
特别重要的提醒是,GATT的客户机和服务机是完全独立的,不同于BLE链接层的从和主或者GAP外围和控制角色。
一个GATT服务机包括一个或者多个GATT服务,这些服务收集数据来完成一个特殊的功能或者特性。
在SimpelBLEPeripheral应用例程中,这里有三种GATT服务:
受委托的GAP服务 - 这个服务包括设备和获取信息,比如设备名、供应商和产品ID,和BLE协议栈的一部分。在每个BLE版本中的BLE设备都需要它。这一部分的源代码没有提供,它被编译到协议栈库中。
受委托的GATT服务 - 这个服务包括GATT服务和一部分BLE协议栈的信息。每一个BLE版本的GATT服务设备需要它.源代码也没有提供,被编译进协议栈库中.
SimpleGATTProfile 服务 - 这个服务是一个示例框架,测试和示例会需要它.这个全部的源码simpleGATTProfile.c和simpleGATTProfile.h被提供.
特殊的数是一个值,服务,属性和配置信息需要使用它。GATT定义了一个子程序去发现,读取,写属性在BLE连接。
GATT服务的这个特殊的值以及他们的属性和他们的配置数据(公认为描述符)被存储在属性表中。属性表是一个简单的数据库,包括小的数据块(属性)。除了数据自身,每一个属性有以下特征连结它:
Handle - 这是属性在表中地址的根本。每一个属性有一个唯一的句柄。
Type - 这表明数据代表什么。它常常指向UUID(通用标识符),UUID通过Bluetooth SIG或者客户类型指定。
Permissions - 这强制执行是否还是怎样一个GATT客户设备获取属性值。
GATT定义了许多子程序为了GATT服务机和客户机的通信。
这里有许多子程序:
Read Charcteristic Value - 这个客户机请求读取字符值用一个特定的手柄,服务机给客户机应答一个值(假如属性有读权限)
Read Using Characteristic UUID - 客户机请求读取所有的某个类型的字符值,服务机用句柄和相应类型所有值应答(假如属性有读的权限)。客户机不需要知道这些字符的句柄。
Read Multiple Characteristic Value - 客户机请求读取许多句柄的字符值在一个请求中,服务机用这个值应答(假如这些属性有读权限).客户机必须知道怎样在这些不同的字符值中解析这个数据。
Discover Characteristic by UUID - 客户机请求发现某个特定值的句柄通过它的类型。服务机回应字符陈述,包括字符句柄和字符读取权限。
Write Characteristic Value - 客户机请求写字符值用特定的句柄,服务机回应客户机是否写字符成功与否。
Write Characteristic Descriptor - 客户机用特定的句柄写字符描述符,服务机回应是否写成功与否。
Characteristic Value Notification - 服务机通知客户机用字符值。客户机不需要提示服务机因为这些数据,也不要发送任何应答当通知收到,但是它必须第一时间配置字符来使能通知。一个框架定义什么时候服务机需要发送数据。
每个框架建立它相应的服务和内在地注册服务用GATT服务机在设备上。GATT服务机增加全部的服务给属性表,指定唯一的句柄给每个属性。
这里有许多特殊的属性类型在GATT属性表中,这些值是Bluetooth SIG定义的:
GATT_PRIMARY_SERVICE_UUID - 这个代表新的设备的开始和提供服务的类型.
GATT_CHARACTER_UUID - 这是大家认为的字符陈述,它表明它是一个GATT字符值.
GATT_CLIENT_UHAR_CFG_UUID - 这个属性代表在属性表中字符描述符在字符值前出现.它允许GATT客户机去使能字符值的通知.
GATT_CHAR_USER_DESC_UUID - 这个属性代表在属性表中字符描述符在字符值前出现.它包括一个ASICC字符串用相应字符来描述.
这些只是一部分包括在BLE规格中属性类型,更多其他属性类型,请看[4].
3.3.3 使用GAP和GATT栈的API
应用和框架直接调用GAP和GATT API函数去完成相关的BLE功能,比如广播,连接和读写字符.更多关于API细节的信息在BLE协议栈中不同层中,可以翻阅交互式的HTML指导.更多细节见[4].
关于使用GAP或者GATT API通用的步骤如下:
1.使用合适的参数调用API函数
2.协议栈执行特定的行为且返回
3.当行为完成或者协议栈有信息返回给调用任务,协议栈会发送一个OSAL信息给调用任务.
4.调用任务接收和处理依据返回的信息.
5.调用任务重新分派信息.
这个过程的示例会在GAP外围角色架构中发现(peripheral.c):
1.为了初始化设备,profile会调用API函数GAP_DeviceInit.
2.GAP完成初始化后,函数会返回SUCCESS(0x00).
3.在初始化完成后,BLE协议栈发送一个OSAL信息给外围设备profile用一个头事件值GAP_MSG_EVENT和一个操作码值GAP_DEVICE_INIT_DONE_EVENT.
4.Profile任务接收到一个SYS_EVENT_MSG事件,表明它有一个信息在等待.profile接收信息并查看头和操作码.根据这些,profile会相应的抛出信息数据给合适的类型(gapDeviceInitDoneEvent_t)和进程.在这种情况下,profile会把产生的密钥存储在NV存储空间且在本地保存设备地址.
5.Profile重新分派信息并且返回.
这里有许多情况会发生当一个GATT客户机设备想完成一个GATT读取请求向匹配的GATT服务机.
1.应用调用GATT子程序API函数.传递连接句柄,字符句柄(包括在数据类型中),和它自己的任务ID作为参数.
2.GATT处理请求,并且返回SUCCESS(0x00).
3.协议栈发送出读请求在下一个连接事件.当一个读应答被远程设备接收,协议栈会发送一个OSAL消息(在读应答中包括数据)给应用.消息包括一个GATT_MSG_EVENT头事件值和一个ATT_READ_RSP方法值.
4.应用任务接收到一个SYS_EVENT_MSG事件,表明它有消息在等待.profile接收到消息,然后查看头和方法值.根据这些,profile知道抛出信息数据给合适的类型(attReadRsp_t)且恢复从读应答中接收的数据.
5.Profile重新分派信息且返回.
3.3.4 GATT服务机应用API
GATT服务机应用提供API给更高的层GATT profile去完成两个主要的功能:
注册和注销服务属性且回调函数从GATT服务机
添加和删除GATT服务.这个API添加和删除GATT服务属性列表且回调从GATT服务机应用.
Profile支持一个或更多的服务.每个服务支持特性或者相关的其他服务.每个特性包括一个值且包括可选的描述.服务,特性,特性值和描述全部被作为属性保存在服务机中.
一个服务属性列表在GATT服务应用开始时注册,其他所有的服务属性跟在后面.每个服务是一个gattAttribute_t类型的数组,在gatt.h中定义.
3.3.5 库文件
尽管BLE应用使用协议栈需要一个库文件,但这里有两个库文件,一个是CC2540的,一个是CC2541的(详细的查看2.1关于栈和应用的配置).下面的表1作为在工程中使用那个库文件做一个参考:
3.4 profiles
BLE软件开发包包括三个GAP角色profile,一个GAP安全profile,一个许多例程GATT服务profiles.
3.4.1 GAP外围角色prifile
外围角色profile提供一个中间给keyfob去广播,连接控制设备(虽然连接的初始化必须来自控制设备)和请求一个特定集的连接参数从主设备.
关于外围角色profile的主要函数原型在peripheral.h中.API提供去得到和设置某个profile参数的功能:各自为GAPRole_GetParameter和GAPRole_SetParameter.这里有许多感兴趣的GAP角色参数:
GAPROLE_ADVERT_ENABLED - 这个参数使能和关闭广播,这个参数的默认值为TRUE.
GAPROLE_ADVERT_DATA - 这是一个字符串包括出现在广播包中的数据.通过设置这些值为{0x02,0x01,0x05},设备将使用限制的发现模式当广播的时候.更多关于广播的数据类型请参考[7].
GAPROLE_SCAN_RSP_DATA - 这是一个字符串包括设备名,设备名会出现在扫描应答数据中.如果一个观察者或者控制设备正在扫描且发送一个扫描请求给外围设备,这外围设备会应答给一个包括这个字符串的扫描应答.
GAPROLE_ADVERT_OFF_TIME - 当设备想设置为限制的发现模式,这个参数需要.它设置设备需要等待多长时间在再次变的可被发现在限制的发现期间的最后.通过设置这个值为0,设备不需要变得可发现再次直到GAPROLE_ADVERT_ENABLED被再次设置为TRUE.
GAPROLE_PARAM_UPDATE_ENABLE - 这个使能自动连接参数以更新请求.profile默认的值为FALSE.
GAPROLE_MIN_CONN_INTERVAL - 这个参数是最小要求的连接间隔值.默认值为80,对应的时间为100ms.
GAPROLE_MAX_CONN_INTERVAL - 这个参数是最大要求的连接间隔值.默认的值为3200,对应的时间为4.0s.
GAPPROLE_SLAVE_LATENCY - 这个参数是被要求的从潜伏值.默认的值为0.
GAPPROLE_TIMEOUT_MULTIPLIER - 这个参数设置为连接监督的超时时间,默认的值为1000,对应的时间为10.0s.
GAP外围角色使用回调函数去通知事件的应用.这些通过函数GAPRole_StartDevice去安排.这个函数初始化GAP外围角色仅且被调用一次.它唯一的参数就是一个指向gapRolesCBs_t类型的指针,gapRolesCBs_t是一个包括两个函数指针的结构体:
pfnStateChange - 这个函数在每一次GAP状态的改变会调用,GAP新的状态作为它的参数.
pfnRssiRead - 这个函数在每一次RSSI已经被读会调用,RSSI值作为它的参数.
它是由应用提供真实的回调函数.在应用例程中,状态改变的函数是peripheralStateNotificationCB,然而这个没有定义在RSSI读的时候(一个空的指针最为参数给pfnRssiRead).
外围profile也包括一个自动连接参数来更新特性,通过设置GAPROLE_PARAM_UPDATE_ENABLE参数为TRUE.如果特性被使能且外围设备进入连接在连接间隔,如果连接间隔超了预先设置的连接间隔或者是从潜伏时间或者超时(不是预先设定的值),外围profile将自动的发送一个连接参数去更新请求用预先设定的参数.一旦参数值在BLE规定中是合法的,控制设备将接受请求并且改变连接参数.在示例应用中,先前的连接参数被设置在SimpleBLEPeripheral_Init函数中,而且这些参数会被容易的改变为其他值.
其他详细的使用GAP Peripheral Role Profile见[4]
3.4.2 GAP Perpheral/Broadcaster Multi_Role Profile
外围/广播 多角色 profile几乎相等地操作外围角色profile;然而它提供额外的功能允许设备同时地操作外围和广播GAP角色.为了使用多角色功能,文件peripheral.c和peripheral.h不能被编译进来而且peripheralBroadcaster.c和peripheralBroadcaster.h被编译进来.另外预处理值PLUS_BROADCASTER应该被定义当使用外围/广播多角色profile.
外围/广播profile和外围profile的函数名字是一样的.这样允许开发者开发一个角色应用,如果增加多角色支持只需要对现有的代码进行很小的修改.
3.4.3 GAP Central Role Profile
控制角色profile提供一组方法,控制设备发现通知(登广告)设备,建立一个连接和外围设备,更新连接参数,和监视RSSI.
主要的控制角色profile的API函数原型在central.h.
API提供函数去得到和设置某个GAP profile参数:GAPCentralRole_GetParameter和GAPCentralRole_SetParameter.
GAP控制角色profiles使用回调函数去通知事件的应用.这些通过函数GAPCentralRole_StartDevice去设置.这个函数初始化GAP控制角色仅且调用一次.它唯一的参数是指向类型为gapCentralRolesCBs_t的指针,它是一个包含两个函数指针的结构体:
eventCB - GAP事件发生会调用这个函数,比如当设备在扫描是被发现或者连接被重新建立或者中断.
rssiCB - 当RSSI已经被读这个函数会被调用,RSSI值作为参数传入.
它是由应用去提供真正的回调函数.在SimpleBLECentral示例应用中,事件回调函数是simpleBLECentralEventCB,RSSI回调函数是simpleBLECentralRssiCB.
外围profile也包含一个自动连接参数去更新特性,通过设置GAPROLE_PARAM_UPDATE_ENABLE为TRUE去设置.如果特性被使能且外围设备进入连接在连接间隔,如果连接间隔超了预先设置的连接间隔或者是从潜伏时间或者超时(不是预先设定的值),外围profile将自动的发送一个连接参数去更新请求用预先设定的参数.一旦参数值在BLE规定中是合法的,控制设备将接受请求并且改变连接参数.在示例应用中,先前的连接参数被设置在SimpleBLEPeripheral_Init函数中,而且这些参数会被容易的改变为其他值.
另外详细的使用GAP控制角色profile见[4].
3.4.4 GAP Bond Manager
注意:GAP外围绑定管理从BLEv1.0软件版本被替换为BLEv1.1,它现在支持外围和控制角色配置.文件gapperiphbondmgr.c和gapperiphbondmgr.h还一直被包括进来以支持以前的应用;然而推荐以后的应用使用最新的绑定管理,因为它还有额外的特性
GAP绑定管理允许设备自动的开始和响应配对的请求从一个已连接的设备.配对后,如果安全密钥已经交换且绑定已经使能,绑定管理会保存安全密钥信息到非易失性的存储器中.
无论何时绑定管理器发起,它都会把以前存储的绑定信息加载到内存中.当设备进入一个新的连接,而且如果配对的设备地址和加载进来信息的地址相匹配的话,它会通过验证,其他需要的数据会传递到GAP层.通过这种方法,加密会很容易地(或者自动)重建.
绑定管理主要被GAP角色profile控制;然而应用可以通过GAPBONDMgr_SetParameter和GAPBondMgr_GetParameter函数获取绑定管理器的参数.应用在初始化时通过使用GAPBondMgr_SetParameter函数去建立绑定管理器.这里有许多有趣的绑定管理器参数:
GAPBOND_PAIRING_MODE - 这个参数告诉绑定管理器是否配对通过,不论它等待一个请求从控制设备或者是自己发起配对.默认的设置是等待一个请求从控制设备.
GAPBOND_MINTM_PROTECTION - 这个参数是设置中间人保护是否使能.如果使能了,配对请求将鉴定连接在从和主之间.profile默认的值为FALSE,即使应用设置它为TRUE在初始化的时候.
GAPBOND_IO_CAPABILITIES - 这个参数告诉绑定管理器设备的输入和输出的能力.为了判断设备是否有显示屏或者输入键盘这个参数是需要的.然而,默认的值为GAPBOND_IO_CAP_DISPLAY_ONLY,表明设备有一个显示屏但没有键盘.即使设备没有物理意义上的显示器,一个展示的钥匙(在用户指导中)被认为是一个显示器.默认的万能钥匙是一个六位数字字符串”000000”.
GAPBOND_BONDING_ENABLED - 这个参数使能绑定.profile默认的值为FALSE,即使SimpleBLEPeripheral应用设置它为TRUE在初始化时.
绑定管理器使用回调函数去通知事件的应用.这些通过函数GAPBondMgr_Register去设置.它的参数是一个指向gapBondCBs_t类型的指针,它是一个包括两个结构体的指针:
passcodeCB - 在配对过程中如果请求需要认证这个函数需要被调用.它允许应用产生一个六位数字密码.
pairStateCB - 当配对状态改变时,无论是配对开始,完成,或者两个设备已经绑定,它都会调用这个函数去通知应用.
它是由应用去提供一个真实的回调函数.在SimpleBLECentral应用中,密码回调函数是simpleBLECentralPasscodeCB,配对状态回调函数是simpleBLECentralPairStateCB.
另外详细地使用GAP绑定管理器请见[4].
3.4.5 Simple GATT Profile
GATT profiles用于储存和操作数据在设备的GATT服务中.简单的GATT profile提供一个简单GATT profile实现示例,目的为了演示.GATT profile源代码包含在simpleGATTProfile.c和simpleGATTProfile.h中.这个源代码在创建另外的profile或者客户定制或者基于蓝牙规格时作为参考.
简单的GATT profile包括以下API函数:
SimpleProfile_AddService - 初始化线程,在GATT服务机线程增加服务属性到属性表中且注册读和写回调函数在profile中.
SimpleProfile_SetParameter - 允许应用设置和改变参数在profile;这些参数和GATT特性值是一致的.如果通知被使能为了特性值,当这个函数被调用时通知会开始设置一个新的特性值.
SimpleProfile_GetParameter - 允许应用去读取参数值从这个profile中.
SimpleProfile_RegisterAppCBs - 允许应用注册一个回调函数在简单的GATT profile中,这个回调函数会在任何时候成功地调用GATT客户机服务去写一个新值对任何特性,但这个特性在服务机中需要写权限(SIMPLEPROFILE_CHAR1或者SIMPLEPROFILE_CHAR3).指向simpleProfileCB_t类型的回调函数指针需要被应用定义,并且需要传一个参数当调用注册函数时.
简单的GATT profile也包括以下局部函数:
simpleProfile_ReadAttrCB - 这个函数必须在增加线程中注册到GATT服务机中.每一次GATT客户机设备想从属性读取到profile中,这个函数都会被调用.如果profile不包括任何读权限的属性,这个函数不需要.
simpleProfile_WriteAtteCB - 这个函数必须在增加线程中注册到GATT服务机中.每一次GATT客户机设备想写一个属性到profile中,这个函数会被调用.在真实地写新数据到属性中,它会检查数据是否有效.当一个客户特性配置值被写到绑定的设备中,它也会通知绑定管理器去存储数据到非易失性存储器中.如果profile不包括任何写权限的属性,这个函数是不需要的.
simpleProfile_HandleConnStatusCB - 这个必须注册在链接数据库时为了在链接状态改变是接受一个回调.如果一个连接终止,它会自动地重置所有的特性配置值去关闭通知和指示.
许多其他的函数去处理客户机特性配置.使用这些函数去查找特性配置的操作,读,写,或者重置这些值或者处理一个特性值的通知.
简单的GATT profile包括五个特性,这些特性值可以被应用设置和读取分别通过使用SimpleProfile_SetParameter和SimpleProfile_GetParameter函数.下面是参数:
SIMPLEPROFILE_CHAR1 - 这是GATT profile第一个特性的参数.它是一个字节类型的值,可以从GATT客户机设备中读和写.
SIMPLEPROFILE_CHAR2 - 这是GATT profile第二个特性的参数.它是一个字节类型的值,可以从GATT客户机设备中读,但是不能写.
SIMPLEPROFILE_CHAR3 - 这是GATT profile第三个特性的参数.它是一个字节类型的值,可以从GATT客户机设备中写,但是不能读.
SIMPLEPROFILE_CHAR4 - 这是GATT profile第四个特性的参数.它是一个字节类型的值,不可以从GATT客户机设备中读和写.然而它的值可以作为一个通知给GATT客户机设备.
SIMPLEPROFILE_CHAR5 - 这是GATT profile第五个特性的参数.它是五个字节类型的值,可以读,但是不能写从GATT客户机设备仅且连接已经加密(配对).
为了设置为通知,GATT客户机必须开启通知通过写0x0001(GATT_CLIENT_CFG_NOTIFY)对特性配置属性.一旦通知被使能,每一次应用使用SimpleProfile_SetParameter设置一个新值则来自特性的数据将被发送到GATT客户机.