一、背景
链路层(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_GEN_DISC_SCAN, DEFAULT_SCAN_DURATION);
// 连接间隔
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]
网友评论