CC2640R2F学习笔记(10)——GAP主机端连接

一、背景

链路层(LL)控制设备的射频状态,有五个设备状态:待机、广播、扫描、初始化和连接。

广播 为广播数据包,而 扫描 则是监听广播。

GAP通信中角色,中心设备(Central - 主机)用来扫描和连接 外围设备(Peripheral - 从机)。

二、配置连接参数

2.1 连接参数相关宏

#define DEFAULT_CONN_INT                      200
#define DEFAULT_CONN_TIMEOUT                  1000
#define DEFAULT_CONN_LATENCY                  0

// 连接时是否启动高速扫描,避免从机广播间隔长,导致主机连接很慢
#define DEFAULT_LINK_HIGH_DUTY_CYCLE          FALSE

2.2 配置GAP参数值

以SDK2.4 multi_role工程为例,在 multi_role_init() 初始化多角色应用程序函数中,

/*===================================== 主机 =====================================*/
/*------------------- 连接参数 -------------------*/
// 连接间隔
GAP_SetParamValue(TGAP_CONN_EST_INT_MIN, DEFAULT_CONN_INT);
GAP_SetParamValue(TGAP_CONN_EST_INT_MAX, DEFAULT_CONN_INT);
GAP_SetParamValue(TGAP_CONN_EST_SUPERV_TIMEOUT, DEFAULT_CONN_TIMEOUT);
GAP_SetParamValue(TGAP_CONN_EST_LATENCY, DEFAULT_CONN_LATENCY);

2.3 配置GAP角色规范(Role Profile)

以SDK2.4 multi_role工程为例,在 multi_role_init() 初始化多角色应用程序函数中,

 /*===================================== 主机 =====================================*/
/*------------------- 连接参数 -------------------*/
// 设置可连接设备数
VOID GAPRole_StartDevice(&multi_role_gapRoleCBs, &maxNumBleConns);

// 为连接句柄表分配内存
if(connHandleMap = ICall_malloc(sizeof(connHandleMapEntry_t) *maxNumBleConns))
{
    // 初始化连接句柄表的索引
    for(uint8_t i = 0; i < maxNumBleConns; i++)             
    {
        connHandleMap[i].connHandle = INVALID_CONNHANDLE;
    }
}

// 为特征句柄表分配内存
if(discInfo = ICall_malloc(sizeof(discInfo_t) *maxNumBleConns))
{
    // 初始化特征句柄表的索引
    for(uint8_t i = 0; i < maxNumBleConns; i++)                      
    {
        discInfo[i].charHdl = 0;
        discInfo[i].discState = BLE_DISC_STATE_IDLE;
        discInfo[i].svcEndHdl = 0;
        discInfo[i].svcStartHdl = 0;
    }
}

三、连接相关函数

3.1 正在连接标志

以SDK2.4 multi_role工程为例,multi_role.c中局部变量

static uint8_t connecting = FALSE;

3.2 执行连接函数

/**
 @brief 执行连接函数
 @param index 索引
 @return TRUE - 成功;FALSE - 失败
*/
bool mr_doConnect(uint8_t index)
{
    if(connecting == TRUE)                                              // 如果正在连接,则取消
    {
        GAPRole_TerminateConnection(GAP_CONNHANDLE_INIT);               // 终止连接

        connecting = FALSE;                                             // 清除连接标志
        return FALSE;
    }
    else                                                                // 尝试连接
    {
        GAPRole_EstablishLink(DEFAULT_LINK_HIGH_DUTY_CYCLE,             // 连接当前设备
                              DEFAULT_LINK_WHITE_LIST,
                              devList[index].addrType,
                              devList[index].addr);

        connecting = TRUE;                                              // 连接标志置一
        return TRUE;
    }
}

3.3 执行断连函数

/**
 @brief 执行断开连接函数
 @param index 索引
 @return TRUE - 成功;FALSE - 失败
*/
bool mr_doDisconnect(uint8_t index)
{
    GAPRole_TerminateConnection(connHandleMap[index].connHandle);       // 与当前设备终止连接

    return TRUE;
}

四、连接相关事件

在执行完连接函数或者断连函数后,会产生相应的事件。

以SDK2.4 multi_role工程为例,在 multi_role_processRoleEvent() 处理多角色事件函数中,

4.1 建立连接完成事件

switch(pEvent->gap.opcode)
{
    /*===================================== 建立链接事件 =====================================*/
    case GAP_LINK_ESTABLISHED_EVENT:
    {

        if(pEvent->gap.hdr.status == SUCCESS)                           // 如果建立链接成功
        {
            connecting = FALSE;                                         // 清除正在连接标志

            // Add index-to-connHandle mapping entry and update menus
            uint8_t index = multi_role_addMappingEntry(pEvent->linkCmpl.connectionHandle,
                                                       pEvent->linkCmpl.devAddr);

            if(linkDB_NumActive() >= maxNumBleConns)                    // 如果没有活跃链接,则关闭广播
            {
                uint8_t advertEnabled = FALSE;
                GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t),
                                     &advertEnabled, NULL);
            }

            // 开始发现服务
            multi_role_startDiscovery(pEvent->linkCmpl.connectionHandle);

            // Start periodic clock if this is the first connection
            if(linkDB_NumActive() == 1)
            {
                Util_startClock(&periodicClock);
            }
        }
        else                                                            // 如果建立链接失败
        {
            /* Display_print0(dispHandle, MR_ROW_STATUS1, 0, "Connect Failed"); */
            /* Display_print1(dispHandle, MR_ROW_STATUS2, 0, "Reason: %d", pEvent->gap.hdr.status); */
        }
    }
    break;
}

4.2 终止连接事件

switch(pEvent->gap.opcode)
{
 /*===================================== 中断链接事件 =====================================*/
    case GAP_LINK_TERMINATED_EVENT:
    {

        // 获取当前活跃连接设备数
        uint8_t currentNumActive = linkDB_NumActive();

        // 从连接句柄表中查找索引
        connIndex = multi_role_mapConnHandleToIndex(pEvent->linkTerminate.connectionHandle);

        // Check to prevent buffer overrun
        if(connIndex < maxNumBleConns)
        {
            // 重置连接设备信息
            connHandleMap[connIndex].connHandle = INVALID_CONNHANDLE;

            discInfo[connIndex].discState = BLE_DISC_STATE_IDLE;
            discInfo[connIndex].charHdl = 0;

            // If there aren't any active connections
            if(currentNumActive == 0)
            {
                // 停止周期定时器
                Util_stopClock(&periodicClock);
            }

            // If it is possible to advertise again
            /*
            if(currentNumActive == (maxNumBleConns-1))
            {
                Display_print0(dispHandle, MR_ROW_ADV, 0, "Ready to Advertise");
                Display_print0(dispHandle, MR_ROW_STATUS2, 0, "Ready to Scan");
            }
            */
        }
    }
    break;
}

• 由 Leung 写于 2019 年 3 月 27 日

• 参考:simplelink_cc2640r2_sdk_2_40_00_32 [提取码:3pg6]

你可能感兴趣的:(CC2640R2F)