附图9 BLE库文件
由于GAP和GATT与用户程序直接交互,因此下文对库文件中GAP和GATT一一讲解。
2、GAP秘书处
2.1角色(即服务,功能)
GAP运行在如下四种角色的一种:
· Broadcaster 广播员—我在,但只可远观,不可连接。
· Observer 观察员—看看谁在,但我只远观,不连接。
· Peripheral 外设(从机)—我在,谁要我就跟谁走,协议栈单层连接。
· Central 核心(主机)—看看谁在,并且愿意跟我走我就带她/他走,协议栈单层或多层连接,目前最多支持3个同时连接。
虽然指标显示BLE可以同时扮演多个角色,但是在TI提供的BLE实例应用中缺省只支持外设角色。每一种角色都由一个剧本(roleprofile)来定义。
2.2连接
主从机连接过程
一个典型的低功耗蓝牙系统同时包含外设和核心(主机),两者的连接过程如下:
外设角色向外发送自己的信息(设备地址、名字等),主机收到外设广播信息后,发送扫描请求(scanrequest)给外设,外设响应主机的请求,连接建立完成。
连接参数
主要有通信间隙(connectioninterval)、外设鄙视(slavelatency)、最大耐心等待时间(supervisiontimeout)等,下面简单说明。
· 通信间隙—蓝牙通信是间断的、跳频的,每次连接都可能选择不同的子频带。跳频的好处是避免频道拥塞,间断连接的好处是节省功耗,通信间隙就是指两次连接之间的时间间隔。这个间隔以1.25ms为基本单位,最小6单位最大3200单位,间隙越小通信越及时,间隙越大功耗越低。
· 外设鄙视—外设与主机建立连接以后,没事的时候主机总会定期发送问候信息到外设,外设懒得搭理,这些主机发送的信息就浮云般飘过。可以忽略的连接事件个数从0到499个,最多不超过32秒。有效连接间隙= 连接间隙x (1+ 外设鄙视).
· 最大耐心等待时间—指的是为了创建一个连接,主机允许的最大等候时间,在这个时间内,不停的尝试连接。范围是10个~3200个通信间隙基本单位(1.25ms)。
以上三参数大小设置优劣是显而易见的,在此也飘过。连接参数的设置请参看后文“5.1GAP外设剧本”小节。
连接异常处理
举例说明连接异常,如主机采用从机并不舒坦的参数来请求连接,有如主从机已经连接了,但从机有想法了,要改参数条约。通过“连接参数更新请求(ConnectionParameter Update Request)”来解决问题,交由L2CAP“收发室物流处”处理。连接参数上文已经说了,不再叙述。
加密处理
利用配对实现,利用密匙来加密授权连接。典型的过程是:外设向主机请求口令一个(passkey)以便进行配对,待主机发送了正确的口令之后,连接通信通过主从机互换密码来校验。由于蓝牙通信是间断通信,如果一个应用需要经常通信,而每次通信都要重新申请连接,那将是劳神费力的,为此GAP安全卫士(SM,security profile)提供了一种长期签证(long-termset of keys),叫做绑定(bonding),这样每次建立连接通关流程就简便快捷了。
3、出纳GATT
GATT负责两个设备间通信的数据交互。共有两种角色:出纳员(GATTClient)和银行(GATTServer),银行提供资金,出纳从银行存取款。银行可以同时面对多个出纳员。这两种角色和主从机等角色是无关的。
GATT把工作拆分成几部分来实现:读关键词(CharacteristicValue)和描述符(CharacteristicDescriptor),用来去库房查找提取数据。写读关键词和描述符。
GATT银行(GATTServer)的业务部门(API)主要提供两个主要的功能:一是服务功能,注册或销毁服务(serviceattribute),并作为回调函数(callbackfunction);二是管理功能,添加或删除GATT银行业务。
一个角色定义的剧本可以同时定义多个角色,每个角色的服务、关键词、关键值、描述符(service,characteristic, characteristic value and descriptors)都以句柄(attributes)形式保存在角色提供的服务上。所有的服务都是一个gattAttribute_t类型的array,在文件gatt.h.中定义。
4、调用GAP和GATT的一般过程
· API调用
· 协议栈响应并返回
· 协议栈发送一个OSAL消息(数据)去调用相应任务事件
· 调用任务去接收和处理消息
· 消息清除
以设备初始化为GAP外设角色来举例说明,外设角色由其剧本(GAPperipheral role profile)来决定,实例程序在文件peripheral.c内。
· 调用API函数GAP_DeviceInit。
· GAP检查了一下说,好,可以初始化,返回值为SUCCESS (0x00),并通知BLE干活。
· BLE协议栈发送OSAL消息给外设角色剧本(peripheral roleprofile),消息内容包括要干什么(eventvalue)GAP_MSG_EVENT和指标是什么(opcodevalue,参数)。
· 角色剧本的服务任务就收到了事件请求SYS_EVENT_MSG,表示有消息来了。
· 角色剧本接收消息,并拆看到底是什么事,接着把消息数据转换(cast)成具体要干事情,并完成相应的工作(这里为gapDeviceInitDoneEvent_t)。
· 角色剧本清除消息并返回。
再举一个例子:GATT客户端设备想从GATT服务器端读取数据,即GATT出纳想从GATT银行那边取点钱出来
· 应用程序调用GATT子进程API函数GATT_ReadCharValue,传递的参数为连接句柄、关键词句柄和自身任务的ID。
· GATT答应了这个请求,返回值为SUCCESS (0x00),向下告知BLE有活干了。
· BLE协议栈在下次建立蓝牙连接时,发送取钱的指令给银行,当银行说好,我们正好有柜员没事在干剪指甲,于是把钱取出来交给了BLE。
· BLE接着就把取到的钱包成消息(OSAL message),通过出纳GATT返回给了应用程序。消息内包含GATT_MSG_EVENT和修改了的ATT_READ_RSP。
· 应用程序接收到了从OSAL来的SYS_EVENT_MSG事件,表示钱可能到了
· 应用程序接收消息,拆包检查,并把需要的钱拿走。
· 最后,应用程序把包装袋销毁,没事了,返回。
5、GAP角色剧本profiles
在TI的BLE实例应用中提供了3中GAP角色剧本,保卫处角色,和几种GATT出纳/库管示例程序服务角色。
5.1 GAP外设剧本
其API函数在peripheral.h中定义,包括:
· GAPROLE_ADVERT_ENABLED—广播使能。
· GAPROLE_ADVERT_DATA—包含在广播里的信息。
· GAPROLE_SCAN_RSP_DATA—外设用于回复主机扫描请求的信息。
· GAPROLE_ADVERT_OFF_TIME—表示外设关闭广播持续时间,该值为零表示无限期关闭广播直到下一次广播使能信号到来。
· GAPROLE_PARAM_UPDATE_ENABLE—使能自动更新连接参数,可以让外设连接失败时自动调整连接参数以便重新连接。
· GAPROLE_MIN_CONN_INTERVAL—设置最小连接间隙,缺省值为80个单位(每单位1.25ms)。
· GAPROLE_MIN_CONN_INTERVAL—设置最大连接间隙,缺省值为3200个单位。
· GAPROLE_SLAVE_LATENCY—外设鄙视参数,缺省为零。
· GAPROLE_TIMEOUT_MULTIPLIER--最大耐心等待时间,缺省为1000个单位。
GAPRole_StartDevice函数用来初始化GAP外设角色,其唯一的参数是gapRolesCBs_t,这个参数是一个包含两个函数指针的结构体,这两函数是pfnStateChange和pfnRssiRead,前者标示状态,后者标示RSSI已经被读走了。
5.2 多角色同时扮演
前文5.1中设备配置为外设,这里以设备同时为外设和广播员两种角色。方法为:去除前文外设的定义剧本peripheral.c和peripheral.h,添加新的剧本peripheralBroadcaster.c和peripheralBroadcaster.h;定义处理器值(preprocessorvalue)PLUS_BROADCASTER。
5.3 GAP主机剧本
与外设剧本相似,主机剧本的API函数在central.h中定义,包括GAPCentralRole_GetParameter和GAPCentralRole_SetParameter以及其他。如GAPROLE_PARAM_UPDATE_ENABLE连接参数自动更新使能的功能,跟外设角色的一样。
GAPCentralRole_StartDevice函数用来初始化GAP主机角色,其唯一的参数是gapCentralRolesCBs_t,,这个参数是一个包含两个函数指针的结构体,这两函数是eventCB和rssiCB,每次GAP时间发生,前者都会被调用,后者标示RSSI已经被读走。
5.4 GAP绑定管理器剧本
用于保持长期的连接。同时支持外设配置和主机配置。当建立了配对连接后,如果绑定使能,绑定管理器就维护这个连接。主要参数有:GAPBOND_PAIRING_MODE,GAPBOND_MITM_PROTECTION,GAPBOND_IO_CAPABILITIES,GAPBOND_IO_CAP_DISPLAY_ONLY,GAPBOND_BONDING_ENABLED
GAPBondMgr_Register函数用来初始化GAP主机角色,其唯一的参数是gapBondCBs_t,,这个参数是一个包含两个函数指针的结构体,这两函数是pairStateCB和passcodeCB,前者返回状态,后者用于配对时产生6为数字口令(passcode)。
5.5怎样编写一个剧本来创建(定义)新的角色(功能、服务)
以SimpleGATT Profile为剧本名称,包含两个文件simpleGATTProfile.c和simpleGATTProfile.h。包含如下主要API函数:
· SimpleProfile_AddService—用于初始化的进程,作用是添加服务句柄(serviceattributes)到句柄组(attributetable)内,寄存器读取和回写。
· SimpleProfile_SetParameter—设置剧本(profile)关键词(characteristics)
· SimpleProfile_GetParameter—获取获取设置剧本关键词
·
SimpleProfile_RegisterApPCBs· simpleProfile_ReadAttrCB
· simpleProfile_WriteAttrCB
· simpleProfile_HandleConnStatusCB
这个实例剧本共有5个关键词:
· SIMPLEPROFILE_CHAR1
· …
· SIMPLEPROFILE_CHAR5