cc2640学习笔记

文件目录结构

cc2650iot
1.x        基本入门例程
2.x        外设教程
3.x        RTOS系统例程
4.x        协处理器例程
5.x        高级例程
common        通用文件
target        不同的芯片封装和不同开发板之间存在差异的文件
说明:RGZ表示7*7封装;RSM表示4*4封装
    后缀为RGZ或RSM的文件夹        里面包含了板级差异文件,代表一种板子,开发中需为自己的板子添加改文件夹
        board.h        文件中定义了工程中会用到的IO等资源信息以及外设操作接口函数等
        xxx_cc26xx_RGZ.h        上面的board.h文件会包含该头文件,该文件是更加底层的板级和芯片级的资源的声明和定义。
        xxx_cc26xx_RGZ.c        各种外设资源的结构体定义
    board.c        根据宏定义进行不同封装和开发板的头文件的包含,用于决定使用该目录下的哪个板级方案。


1.1_simple_peripheral
iar
    app        包含app工程相关的文件
        FlashROM
            Exe        包含hex文件等
            List        map文件
            Obj            .o等文件
    config
    settings
    stack        包含stack工程相关的文件
        FlashROM        各种编译链接后得到的文件
            Exe        包含hex文件等
            List        map文件
            Obj            .o等文件
        settings
    xxx.eww        IAR IDE Workspace
source
    app
        main.c
        simple_peripheral.c
        simple_peripheral.h
    driver
    profile
        simple_gatt_profile.c
        simple_gatt_profile.h
    stack
        osal_icall_ble.c

通用属性配置文件(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)并没有直接关系。

GATT服务{Profile{Service{Characteristic{Attributes

以下我们着重理解Characteristic,也是我们数据交互的最终实体,每个特征包含以下4个Attributes
    1.Characteristic Value(特征值)
        特征的数据值
    2.Characteristic Declaration(特征声明)
        存储特征值的属性,位置和类型的描述符
    3.Client Characteristic Configuration(客户端特征配置)
        GATT服务器特征是notify属性还是indicate属性。
    4.Characteristic User Description(特征用户描述)
        描述特征的ASCII字符串
        
这些属性存储在属性表中的GATT服务器中。除了该值之外,以下特性与每个属性相关联        
以上的每个Attributes又由以下元素组成
    1.Handle(句柄)
        表中属性的索引(每个属性都有一个唯一的句柄)
    2.Type(类型)
        指示属性数据表示什么(称为 UUID,有些是蓝牙组织规定的,有些则是自定义)
    3.Permissions(权限)
        强制GATT客户端设备如何访问属性的值


像GAP层一样,GATT层也是抽象的,这种抽象取决于设备是作为GATT客户端还是GATT服务器。根据蓝牙规范的定义,GATT层是ATT层的抽象GATT客户端没有属性表或Profile文件,因为它们是收集方,而不是提供方。GATT层的功能在库中实现,但头文件功能可在gatt.h文件中找到。

GATT客户端抽象层
1.在GATT客户端应用程序大部分是直接使用GATT的API(少部分直接使用ATT层API),没有profile文件,因为GATT客户是得到数据,不需要建立属性表和配置文件。
            Application->GATT->ATT
                    |-----------^
2.在应用程序中直接使用GATT层
    1.初始化GATT客户端
        VOID GATT_InitClient();
    2.注册接收传入的ATT指示和通知
        GATT_RegisterForInd(selfEntity);
    3.执行GATT客户端过程
        1.应用程序调用GATT功能函数。
            status = GATT_WriteCharValue(connHandle, &req, selfEntity);
        2.GATT功能函数调用ATT功能函数并且发送到协议栈任务。
        3.BLE Stack接收ICall命令,通过无线方式发送到服务器,后将状态返回给应用程序。(此部分在库中实现)
    4.接收并处理应用程序中GATT客户端过程的响应
        1.BLE Stack通过无线方式接收GATT服务器的写响应,并向应用程序任务发送GATT消息。(此部分在库中实现)
        2.应用程序任务接收来自BLE Stack的GATT消息
            if (ICall_fetchServiceMsg(&src, &dest,(void **)&pMsg) == ICALL_ERRNO_SUCCESS)
             {
                if ((src == ICALL_SERVICE_CLASS_BLE) && (dest == selfEntity))
                {
                  // Process inter-task message
                  SimpleBLECentral_processStackMsg((ICall_Hdr *)pMsg);
                }

                if (pMsg)
                {
                  ICall_freeMsg(pMsg);
                }
             }
        3.应用程序处理堆栈消息以处理写响应
    5.GATT客户端也可以直接从GATT服务器接收异步指示或通知数据。要接收GATT服务端的通知或指示,如步骤2.这些通知和指示也将作为ATT事件在GATT消息中发送给应用程序。
    


GATT服务端抽象层
1.在GATT服务端,GATT层的大部分功能由独立的profiles处理,这些profiles又使用GattservApp模块。
            Application->Profiles->GattServApp->GATT->ATT
                |            |--------------------^     ^
                |---------------------------------^       |
                |--------------------------------------|
2.在建立GATT服务端的时候首先需要创建profiles文件,配置GATTServApp模块。profiles文件调用GattServApp模块并使用其API与GATT层交互。在这种情况下应用程序不需要直接调用GATT层API,应用程序直接和Profiles文件通信。
3.GattServApp模块
    1.GattServApp存储和管理应用程序范围的属性表。各种Profile文件使用此模块将其特性添加到属性表中。低功耗蓝牙协议栈使用此模块来响应GATT客户端的请求。例如GATT客户端可以发送“发现所有主要特征”消息。GATT服务器上的低功耗蓝牙协议栈收到此消息,并使用GATTServApp查找并发送存储在属性表中的所有主要特性。从Profile文件访问的GATTServApp功能在gattservapp_util.c中定义。
    2.创建属性表
        1.应用程序使用GattServApp来创建GATT表来添加服务。每个服务都包含具有UUID,值、权限以及读取和写入回调的属性列表。
        2.属性表初始化必须在应用程序初始化函数中调用,也就是simple_peripheral_init()。
            // Initialize GATT attributes
            GGS_AddService(GATT_ALL_SERVICES); // GAP
            GATTServApp_AddService(GATT_ALL_SERVICES); // GATT attributes
            DevInfo_AddService(); // Device Information Service
            #ifndef FEATURE_OAD_ONCHIP
            SimpleProfile_AddService(GATT_ALL_SERVICES); // Simple GATT Profile
            #endif //!FEATURE_OAD_ONCHIP
    3.Profile架构


在simple_peripheral示例应用程序项目中定义了四个GATT服务
1.GAP GATT服务(GGS)
    此服务包含设备和访问信息,例如设备名称,供应商标识和产品标识。该服务是实现主机和从机所必需的,它的目的是在设备发现和连接启动过程中进行辅助。
    为此服务定义了以下特征:
        设备名称
        表现
        外围首选连接参数
    使用GGS
        GGS以lib库的形式在协议栈中提供。
        API接口可以在gapgattserver.h中查看。
        初始化GGS参数
            // 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);
        使用GGS初始化应用程序回调(可选)。当GGS中任何特征发生变化时,都会通知应用程序。
            GGS_RegisterAppCBs (&appGGSCBs);
        将GGS添加到GATT服务器
            GGS_AddService(GATT_ALL_SERVICES);           // GAP
2.通用属性服务
    GATTServApp_AddService(GATT_ALL_SERVICES);   // GATT attributes
    该服务包含有关GATT服务器的信息,是蓝牙低功耗协议栈的一部分,每个GATT服务器设备都需要根据蓝牙版本核心规范。
3.设备信息服务
    DevInfo_AddService();                        // Device Information Service
    此服务公开了有关设备的信息,入硬件,软件版本,固件版本,规范信息,合规性信息和制造商名称。设备信息服务是蓝牙低功耗协议栈的一部分,由应用程序配置。
4.simple_gatt_profile服务
    SimpleProfile_AddService(GATT_ALL_SERVICES); // Simple GATT Profile
    此服务是用于测试和演示的实例配置文件,完整的源代码在simple_gatt_profile.c和simple_gatt_profile.h文件中提供。
    默认的simple_gatt_profile包含以下特性:
        SIMPLEPROFILE_CHAR1:可以从GATT客户端设备读取或写入的1字节值。
        SIMPLEPROFILE_CHAR2:可以从GATT客户端设备读取但不能写入的1字节值。
        SIMPLEPROFILE_CHAR3:可以从GATT客户端设备写入但不能读取的1字节值。
        SIMPLEPROFILE_CHAR4:不能从GATT客户端设备直接读取或写入的1字节值(该值是通知属性,该值是必须的)。
        SIMPLEPROFILE_CHAR5:可从GATT客户端设备读取(但不写入)的5字节值。
        
        


属性表可以看成一列火车,里面有17个属性可以看成17个车厢,每个车厢中都有一个属性权限,将这个属性权限看做一把钥匙,这个钥匙的权限值代表这个车厢可以打开任何一个车厢(即该属性具有属性表中所有属性的读/写权限)。而属性表文件上部的simpleProfileChar1Props只代表这把钥匙对于char1的操作权限。作用对象不同。


GATT安全
    GATT服务器可以针对每个特征独立地定义权限。服务器可能允许任何客户端访问某些特性,同时将访问其他特性仅限于认证或授权的客户端。这些权限通常被定义为更高级别的配置文件规范的一部分。对于自定义配置文件,用户可以选择他们认为合适的权限。
    1.认证
        在客户端通过认证配对方法之前,无法访问需要身份验证的特性。此验证在协议栈内执行,无需应用程序处理。唯一的要求是使GATT服务器正确注册该特性。例如,simple_gatt_profile的特征5允许经过认证的读取。当未经身份验证的客户端尝试读取此值时,GATT 服务器使用ERROR_INSUFFICIENT_AUTHEN(0x41)自动拒绝其请求,而不会调用simpleProfile_ReadAttrCB()。客户端成功认证后,读/写请求将转发到配置文件读/写回调。
    2.授权
        授权是BLE已经实现的一个安全层。由于应用程序需要定义自己的授权要求,所以协议栈将这些特性的读/写请求转发到配置文件的应用程序层。要从配置文件注册GATT服务器的授权信息,它必须使用协议栈定义一个授权回调。simple_gatt_profile默认情况下不执行此操作,但下面是如何修改此操作的示例。
            1.注册授权回调
                在simpleProfileCBs中加入回调函数名simpleProfile_authorizationCB
            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;
                }
                授权回调在协议栈上下文中执行;因此,不应在此功能中执行复杂的处理。具体实施由开发人员决定;上述回调应该被视为一个shell。如果客户端被授权访问该特性,返回值应为“SUCCESS”,否则返回值应为“ATT_ERR_INSUFFICIENT_AUTHOR”,如果尚未获得正确的授权。授权要求事先通过连接进行身份验证,否则将作为错误响应发送ATT_ERR_INSUFFICIENT_AUTHEN。

SDK结构

simple_central.c
    SimpleBLECentral_startGapDiscovery    开始发现设备
    SimpleBLECentral_createTask    简单BLE外围设备的任务创建函数
    SimpleBLECentral_init    初始化函数为简单的BLE*应用任务
    SimpleBLECentral_taskFxn    简单的BLE Central的应用程序任务入口点
    SimpleBLECentral_processStackMsg    处理协议栈消息
    SimpleBLECentral_processAppMsg    处理APP消息
    SimpleBLECentral_processRoleEvent    主机角色事件处理函数
    SimpleBLECentral_handleKeys    处理此设备的所有按键事件
    SimpleBLECentral_processGATTMsg    处理GATT消息和事件
    SimpleBLECentral_processCmdCompleteEvt    处理一个传入的OSAL HCI命令完成事件
    SimpleBLECentral_startDiscovery    开始服务发现
    SimpleBLECentral_findSvcUuid    在广告客户的服务UUID列表中查找给定的UUID
    SimpleBLECentral_addDeviceInfo    将设备添加到设备发现结果列表中
调用关系
    SimpleBLECentral_taskFxn
        SimpleBLECentral_init
        SimpleBLECentral_processStackMsg
            GAP_MSG_EVENT:SimpleBLECentral_processRoleEvent
                GAP_DEVICE_INIT_DONE_EVENT:初始化时可以用于打印以及扫描(如果对应的宏定义满足)
                GAP_DEVICE_INFO_EVENT:    SimpleBLECentral_findSvcUuid
                                        SimpleBLECentral_addDeviceInfo
                GAP_DEVICE_DISCOVERY_EVENT:设备发现过程完成时可用于选择设备并建立连接
                GAP_LINK_ESTABLISHED_EVENT:建立链接请求完成时可用于打印
                GAP_LINK_TERMINATED_EVENT:连接终止时可用于打印
                GAP_LINK_PARAM_UPDATE_EVENT:接收到更新参数事件时可用于打印
            GATT_MSG_EVENT:SimpleBLECentral_processGATTMsg
            HCI_GAP_EVENT_EVENT:SimpleBLECentral_processCmdCompleteEvt
        SimpleBLECentral_processAppMsg    //此处主要处理消息队列中的消息
            可以根据不同的事件进行不同的处理例如,案件触发扫描,收发数据等
        SimpleBLECentral_startDiscovery

simple_peripheral.c
    SimpleBLEPeripheral_createTask    简单BLE外围设备的任务创建函数
    SimpleBLEPeripheral_init
    SimpleBLEPeripheral_taskFxn    简单BLE外围设备的应用程序任务入口点
    SimpleBLEPeripheral_processStackMsg    处理协议栈消息
    SimpleBLEPeripheral_processGATTMsg    处理GATT消息和事件
    SimpleBLEPeripheral_sendAttRsp    发送等待的ATT响应消息
    SimpleBLEPeripheral_freeAttRsp    *ATT响应消息
    SimpleBLEPeripheral_processAppMsg    处理APP消息
    SimpleBLEPeripheral_stateChangeCB
    SimpleBLEPeripheral_processStateChangeEvt    蓝牙状态回调函数
    SimpleBLEPeripheral_charValueChangeCB    特征值改变回调函数
    SimpleBLEPeripheral_processCharValueChangeEvt    处理挂起的特征值改变事件
    SimpleBLEPeripheral_performPeriodicTask 处理自定义的定时EVENT事件
    SimpleBLEPeripheral_processOadWriteCB    处理对OAD配置文件的写请求
    SimpleBLEPeripheral_clockHandler    时钟超时的处理函数
    SimpleBLEPeripheral_enqueueMsg    创建一条消息并将该消息放入RTOS队列中
调用关系
    SimpleBLEPeripheral_taskFxn
        SimpleBLEPeripheral_init
        SimpleBLEPeripheral_sendAttRsp
        SimpleBLEPeripheral_processStackMsg
            GATT_MSG_EVENT:SimpleBLEPeripheral_processGATTMsg
        SimpleBLEPeripheral_processAppMsg
            SBP_STATE_CHANGE_EVT:SimpleBLEPeripheral_processStateChangeEvt
            SBP_CHAR_CHANGE_EVT:SimpleBLEPeripheral_processCharValueChangeEvt//接收并处理对应通道的消息
            SBC_KEY_CHANGE_EVT:SimpleBLEPeripheral_handleKeys
        SimpleBLEPeripheral_performPeriodicTask


发送接收数据
主机发送:
    GATT_WriteCharValue
主机接收:
    1.第一步,注册接收notify消息GATT_RegisterForInd(selfEntity);
    第二部,在GATT_MSG_EVENT消息处理函数SimpleBLECentral_processGATTMsg增加ATT_HANDLE_VALUE_NOTI 处理代码:
        else if (pMsg->method == ATT_HANDLE_VALUE_NOTI)
        {
        //数据内容为:pMsg->msg.handleValueNoti.pValue
        //数据长度为:pMsg->msg.handleValueNoti.len
        UartWrite(pMsg->msg.handleValueNoti.pValue,
        pMsg->msg.handleValueNoti.len);
        }
    2.从机还可以使用函数SimpleProfile_SetParameter()修改特征值的值,然后主机中调用GATT_ReadCharValue()函数来读取该特征值

从机发送:
    1.GATT_Notification不需要主机回应
    2.GATT_Indication需要主机回应
从机接收:
    第一步:注册Profile回调函数,用来接收特征值事件。SimpleProfile_RegisterAppCBs(&SimpleBLEPeripheral_simpleProfileCBs);
    第二部:在回调函数SimpleBLEPeripheral_processCharValueChangeEvt中调用SimpleProfile_GetParameter读取数据


蓝牙profile
    蓝牙profile可以理解为主从双方通信过程中的格式化数据,并存储在蓝牙从机中,作为服务端,而主机作为客户端,客户端可以获取服务端的数据或属性,这个数据就称之为特征值。
    
GATT(Generic Attribute profile)                    
    GATT服务是profile的一种集合,负责两个设备之间的数据通信,数据以特征值的形式传输和存储。从GATT的角度看,主机和从机两个设备连接后,分别变成了两种角色:GATT客户端和GATT服务器。

GAP(Generic Access Profile)通用访问配置文件
    BLE协议栈的GAP层负责连接功能。该层处理设备的接入模式和过程,包括设备发现,链路建立,链路终止,安全特性的启动和设备配置。
    

ICall是一种软件模块,可为应用程序与协议栈提供通信服务,app中调用的协议栈API函数,大多来自ICall模块,另外ICall还提供RTOS的一些线程同步、动态内存等服务。ICall使得app和stack在统一的RTOS环境中高效运行,共享资源。使用ICall之前必须:1、ICall_init();2、ICall_createRemoteTasks();3、ICall_registerApp(&selfEntity, &sem);

广播的相关参数

Advertising_Type  (广播类型)
广播的类型一般分为4种,分别是:
    1.可连接的非定向广播。
        这是一种用途最广的广播类型,包括广播数据和扫描响应数据,它表示当前设备可以接受其他任何设备的连接请求。
    2.可连接的定向广播。
        定向广播类型是为了尽可能快的建立连接。这种报文包含两个地址:广播者的地址和发起者的地址。发起者收到发给自己的定向广播报文之后,可以立即发送连接请求作为回应。
        定向广播类型有特殊的时序要求。完整的广播事件必须每3.75ms重复一次。这一要求使得扫描设备只需扫描3.75ms便可以收到定向广播设备的消息。当然,如此快的发送会让报文充斥着广播信道,进而导致该区域内的其他设备无法进行广播。因此,定向广播不可以持续1.28s以上的时间。如果主机没有主动要求停止,或者连接没有建立,控制器都会自动停止广播。一旦到了1.28s,主机便只能使用间隔长得多的可连接非定向广播让其他设备来连接。
        当使用定向广播时,设备不能被主动扫描。此外,定向广播报文的净荷中也不能带有其他附加数据。该净荷只能包含两个必须的地址。
    3.不可连接的非定向广播。
        仅仅发送广播数据。
    4.可扫描的非定向广播。
        这种广播不能用于发起连接,但允许其他设备扫描该广播设备。这意味着设备可以被发现,既可以发送广播数据,也可以响应扫描发送扫描回应数据,但不能建立连接。这是一种适用于广播数据的广播形式,动态数据可以包含于广播数据之中,而静态数据可以包含于扫描相应数据之中。
    注意:所谓的定向和非定向针对的是广播的对象,如果是针对特定的对象进行广播(在广播包PDU中会包含目标对象的MAC)就是定向广播,反之就是非定向。可连接和不可连接是指是否接受连接请求,如果是不可连接的广播类型,它将不回应连接请求。可扫描广播类型是指回应扫描请求。
设置广播类型的方法
    cc2640默认应该是可连接非定向类型
    修改方法:GAPRole_SetParameter(GAPROLE_ADV_EVENT_TYPE, sizeof( uint8 ), &advType );


Advertising interval  (广播间隔)
设备每次广播时,会在3个广播信道上发送相同的报文。这些报文被称为一个广播事件。除了定向报文以外,其他广播事件均可以选择“20ms~10.28s”不等的间隔。通常,一个广播中的设备会每一秒广播一次。两个相邻广播事件之间的事件称为广播间隔。

    但是,设备周期性的发送广播会有一个问题:由于设备间的时钟会不同程度的漂移,两个设备可能在很长一段时间同时广播而造成干扰。为防止这一情况的发生,除定向广播之外的其他广播类型,发送时间均会被扰动。实现该扰动的方式为,在上一次广播事件后加入“0 ~ 10ms”的随机延时。这意味着,即使两个设备广播间隔相同,并在相同信道及时间点上发送造成了冲突,但它们发送下一个广播事件时也会有很大可能不再冲突。所以,两个相邻的广播事件的之间的时间间隔(T_advEvent)为:T_AdvEvent = advInterval + advDelay。
    其中,advInterval必须是“0.625ms”的整数倍,范围是“20ms~10.24s”之间。其中,advInterval必须是“0.625ms”的整数倍,范围是“20ms ~ 10.24s”之间。
    当然,实际设置过程中没有广播间隔参数,而是设置Advertising_Interval_Min(最小广播间隔)和Advertising_Interval_Max(最大广播间隔)这两个参数来调整广播间隔,它们都是以“0.625ms”为单位,如果要固定广播间隔为某一个值,只需要将这两个参数设置为同一个有效数值即可。
设置广播间隔的方法
    //普通可发现模式(在未连接情况下一直广播下去)下修改广播间隔的方法
    GAP_SetParamValue(TGAP_GEN_DISC_ADV_INT_MIN, advInt );//单位是0.625ms
    GAP_SetParamValue(TGAP_GEN_DISC_ADV_INT_MAX, advInt );//单位是0.625ms
    //有限可发现模式(广播一定时间后停止广播)下修改广播间隔的方法
    GAP_SetParamValue( TGAP_LIM_DISC_ADV_INT_MIN, advInt );//单位是0.625ms
    GAP_SetParamValue( TGAP_LIM_DISC_ADV_INT_MAX, advInt );//单位是0.625ms


Own_Address_Type  (自身地址类型)
Direct_Address_Type  (定向地址类型)
Direct_Address  (定向地址)
Advertising_Channel_Map  (广播信道)
Advertising_Filter_Policy  (广播过滤策略)
Advertising And ScanReponse Data  (广播和扫描回应数据)

过程跟踪

无配对绑定过程
从机
1.BLE Peripheral
        SimpleBLEPeripheral_init
2.0xCC78AB7A7290 Initialized
    SimpleBLEPeripheral_processAppMsg
        case SBP_STATE_CHANGE_EVT:SimpleBLEPeripheral_processStateChangeEvt
            case GAPROLE_STARTED
3.Advertising
    SimpleBLEPeripheral_processAppMsg
        case SBP_STATE_CHANGE_EVT:SimpleBLEPeripheral_processStateChangeEvt
            case GAPROLE_ADVERTISING
4.Num Conns: 1
4.connected 0xCC78AB7A72FE
    SimpleBLEPeripheral_processAppMsg
        case SBP_STATE_CHANGE_EVT:SimpleBLEPeripheral_processStateChangeEvt
            case GAPROLE_CONNECTED


主机
1.BLE Central
    SimpleBLECentral_init
2.0xCC78AB7A72FE Initialized
    SimpleBLECentral_processStackMsg
        case GAP_MSG_EVENT:SimpleBLECentral_processRoleEvent
            case GAP_DEVICE_INIT_DONE_EVENT
3.Connected: 0xCC78AB7A7290
    SimpleBLECentral_processStackMsg
        case GAP_MSG_EVENT:SimpleBLECentral_processRoleEvent
            case GAP_LINK_ESTABLISHED_EVENT
4.MTU Size: 23
5.Simple Svc Found, charHdl: 46
    SimpleBLECentral_processStackMsg
        case GATT_MSG_EVENT:SimpleBLECentral_processGATTMsg
            BLE_DISC_STATE_IDLE:SimpleBLECentral_processGATTDiscEvent
                BLE_DISC_STATE_CHAR:SimpleBLECentral_processGATTDiscEvent
Param Update: 0
    SimpleBLECentral_processStackMsg
        case GAP_MSG_EVENT:SimpleBLECentral_processRoleEvent
            case GAP_LINK_PARAM_UPDATE_EVENT

配对绑定

GAP Bond Manager(GAP绑定管理器)

GAPBondMgr使用的一般过程如下
1.配对过程,即交换秘钥
2.使用步骤1的秘钥加密连接
3.绑定过程将秘钥存储在安全闪存(SNV)中
4.重新连接时,使用存储在SNV中的秘钥来加密连接

使用GAPBondMgr
GAPRole处理一些GAPBondMgr功能。GAPBondMgr在gapbondmgr.c和gapbondmgr.h中定义。
1.配置协议栈以支持GAPBondMgr功能,以及是否需要安全连接。在stack项目中的build_config.opt中定义以下内容:    
    DGAP_BOND_MGR
    DBLE_V42_FEATURES=SECURE_CONNS_CFG
2.协议栈还必须配置为使用1或2个SNV页面,通过在stack项目中将OSAL_SNV=1或OSAL_SNV = 2。
3.如果使用安全连接,PDU大小必须>=69.这可以通过在应用程序项目中定义以下预处理器符号来设置:MAX_PDU_SIZE = 69。此外,可用于安全连接的最小堆空间大小为 3690。
4.通过根据需要初始化其参数来配置GAPBondMgr。
5.使用GAPBondMgr注册应用程序回调,以便应用程序可以与GAPBondMgr通信并通知事件。
    GAPBondMgr_Register(&security_examples_central_bondCB);
6.一旦GAPBondMgr被配置,它主要从应用程序的角度自主运行。当建立连接时,根据初始化期间设置的配置参数启动配对和绑定,并根据需要通过定义的回调与应用程序进行通信。

配对模式
Pairing Disabled禁用配对
    配对设置为FALSE时,BLE协议栈会自动拒绝任何配对尝试。如下设置GAPBondMgr以禁用配对:
        uint8 pairMode = GAPBOND_PAIRING_MODE_NO_PAIRING;
        GAPBondMgr_SetParameter(GAPBOND_PAIRING_MODE, sizeof(uint8_t),&pairMode);
Just Works Pairing 只配对
    Just Works 配对允许加密而不需要MITM(人在中间保护,就是指在配对过程中,有些认为的在中间的操作来进行保护)身份验证,容易受到MITM攻击。Just Works配对可以是LE Legacy或Secure Connections配对。GAPBondMgr不需要任何额外的输入。配置GAPBondMgr为Just Works配对如下。
        uint8_t pairMode = GAPBOND_PAIRING_MODE_INITIATE;
        uint8_t mitm = FALSE;
        GAPBondMgr_SetParameter( GAPBOND_PAIRING_MODE, sizeof (uint8_t),&pairMode);
        GAPBondMgr_SetParameter( GAPBOND_MITM_PROTECTION, sizeof (uint8_t),&mitm);
一旦发送配对请求,应用程序将收到一个GAPBOND_PAIRING_STATE_STARTED事件,一旦配对过程完成,就会发生 GAPBOND_PAIRING_STATE_COMPLETE 事件。此时,链接被加密。

Passcode Entry密码输入
密码输入是一种可以防止MITM攻击的身份验证配对。它可以是LE Legacy配对或安全连接配对。在这种配对方法中,一个设备显示6位密码,另一个设备输入密码。GAPBondMgr在启动时注册的密码回调用于输入或显示密码。以下是启动Passcode Entry配对的示例,其中显示密码。
    1.定义密码回调
    2.配置GAPBondMgr
    3.处理密码回调并向协议栈发送响应
        根据从GAPBondMgr返回uiInputs和uiOutputs内容,必须显示或输入密码。然后使用GAPBondMgr_PasscodeRsp()将密码发送到GAPBondMgr,以便配对可以继续。密码很可能是随机生成的,设备必须为用户提供输入密码的方式,然后使用GAPBondMgr_PasscodeRsp()发送给GAPBondMgr。


Numeric Comparison数字比较
    数组比较是一种经过身份验证的配对,可以防止MITM攻击。只能作为安全连接配对,两个设备都显示6位数的代码。每个设备必须通过按钮或其他一些输入来指示代码是否匹配。GAPBondMgr在启动时注册的密码回调用于显示 6 位数代码。以下是启动数字比较配对的示例。
    1.定义密码回调来显示代码
    2.配置GAPBondMgr
    3.处理密码回调和显示代码
    4.接受用户输入 YES-No,并发送回应 GAPBondMgr
        GAPBondMgr_PasscodeRsp(connHandle, SUCCESS, TRUE);


GAPBondMgr与应用程序之间的完全交互图如下:(此处只显示应用层,详情请参考cc2640低功耗蓝牙入门教程)
>第一次连接
1.Pairing State Callback        GATBOND_PAIRING_STATE_STARTED
2.Passcode Callback
    显示密码
    发送回应
3.Pairing State Callback        GAPBOND_PAIRING_STATE_COMPLETE
>后续连接
从SNV中取出秘钥
4.Pairing State Callback        GAPBOND_PAIRING_STATE_BONDED

启用绑定后,GAPBondMgr将配对过程中传输的长期密钥存储到SNV。完成后,通过GAPBOND_PAIRING_STATE_COMPLETE事件通知应用程序。仅在初始连接时,配对和绑定传递给应用程序GAPBOND_PAIRING_STATE_COMPLETE回调。为了将来连接到绑定设备,安全密钥从闪存加载,从而跳过配对过程。在这种情况下,只有PAIRING_STATE_BONDED被传递给应用程序对状态回调。

GAPBondMgr各参数解析
1.passkey
    在xxx_init函数中该值表示默认密码,当后续没有重新修改密码时该值就是最终密码。
    在一些情况下我们会在密码回调中重新设置该值,此时密码就不是之前的默认密码了
2.pairMode
该值有3个选项
GAPBOND_PAIRING_MODE_NO_PAIRING
    如果主从机中有一方配置为该模式则当双发在连接后只要另一发发起配对则连接就会断开
GAPBOND_PAIRING_MODE_WAIT_FOR_REQ
    该模式是一种被动的模式,一般长用于主机上。若另一发不发起配对则直接连接成功,另一*发起连接则本设备进行相应配合。
GAPBOND_PAIRING_MODE_INITIATE
    如果要使能配对,主从机中至少要有一个配置为该模式。
    一般情况下我们倾向于将从机配置为该模式,因为一般主机都是发起连接的一方需要考虑连接不同设备时的通用性,故将配对绑定等安全事务留给设备来决定是否需要做,如果不需要则直接连接完成,如果需要则主机只需要进行相应的配合即可。并且一般从机都是一些io很少的设备不一定支持密码的比较。
3.mitm
人在中间保护。
当该值被配置为FALSE时,说明不需要人在中间参与,后面的ioCap设置就会被忽略。
4.ioCap
该值表示本机是否具有显示或者输入的功能,比如GAPBOND_IO_CAP_DISPLAY_ONLY,表示可以将密码显示在屏幕上给操作人看,如果有I/O接口可以输入密码,也可以选择GAPBOND_IO_CAP_KEYBOARD_ONLY。
5.bonding
该值的取值为TRUE或FALSE。表示是否需要绑定过程,需要注意只有使能配对之后才可能有绑定,故若首次与别的设备连接没有配对过程则,该值就算为TRUE也不会执行绑定。

上一篇:Android蓝牙低功耗(BLE)API尚未准备就绪


下一篇:本机Android BLE实现本质上是同步的吗?