有关连接参数概念和作用在 Generic Access Profile (GAP) 一章已详细讲解,这一章演示如何通过修改 simple_peripheral 例程实现连接参数更新,并分析程序流程。
连接参数更新过程中都是主机发起的,从机只能被动接收主机设置的参数。
这个过程发生在连接的时候,当连接之后如果主机设置的参数不利于从机,从机可以发送请求,请求中包含需要的连接参数。
从机请求主机重新更新连接参数,主机可以拒绝。如果主机同意修改连接参数,并且参数合理,则主机发起连接参数更新。如果参数不合理(例如主机不支持过大或者过小的连接间隔),则主机会对参数进行协商,选择最合理的参数进行设置。
从机发起连接参数更新请求的过程包含了主机发起连接参数更新的过程。本文以 simple_peripheral 工程为例,演示由从机发起连接参数更新请求的过程。
使用 USB 连接 CC2640R2F Evaluation Board ,确保跳线帽正确连接,如下图所示:
协议栈和 IAR 安装以及工程编译参考 CC2640R2 BLE 开发环境搭建 编译参考 编译第一个工程(simple_peripheral),有关 BTool 使用请参考 BTool 。 有关 Packet Sniffer 使用请参考 Packet Sniffer 。所有工具可以在 CC2640R2开发工具集介绍 里获得。
在 peripheral.c 文件中,定义了 startUpdateClock
的结构体变量,startUpdateClock
作为连接参数更新的定时器事件句柄。
在 gapRole_init() 中,可以找到其初始化过程: Util_constructClock (& startUpdateClock, gapRole_clockHandler,0, 0, false, START_CONN_UPDATE_EVT );
这里创建了一个周期为 0 ,并且只执行一次的定时器,其中回调处理函数的参数是 START_CONN_UPDATE_EVT 事件。
gapRole_processGAPMsg
中,GAP_LINK_ESTABLISHED_EVENT
事件的处理过程可以看到://source\ti\ble5stack\profiles\roles\cc26xx\peripheral.c GAP_LINK_ESTABLISHED_EVENT Line 1195
uint16_t timeout = GAP_GetParamValue(TGAP_CONN_PAUSE_PERIPHERAL);
Util_restartClock(&startUpdateClock, timeout*1000);
一旦连接建立,就启动该定时器。timeout
通过 GAP_GetParamValue
得到。在 SimpleBLEPeripheral_init
函数中,下面代码段已经设置了DEFAULT_CONN_PAUSE_PERIPHERAL 值。
//examples\rtos\CC2640R2_LAUNCHXL\ble5stack\simple_peripheral\src\app\simple_peripheral.c DEFAULT_CONN_PAUSE_PERIPHERAL Line 144
// Connection Pause Peripheral time value (in seconds)
#define DEFAULT_CONN_PAUSE_PERIPHERAL 6
GAP_SetParamValue(TGAP_CONN_PAUSE_PERIPHERAL, DEFAULT_CONN_PAUSE_PERIPHERAL);
当定时器时间到达后,调用下面的回调函数,并传入初始化中设置的 START_CONN_UPDATE_EVT
参数,可以看出该回调函数仅发送了一个事件。
//source\ti\ble5stack\profiles\roles\cc26xx\peripheral.c gapRole_clockHandler Line 1626
void gapRole_clockHandler(UArg a0)
{
gapRole_setEvent(a0);
}
然后在 gapRole_taskFxn
函数中进行相应事件处理,调用 gapRole_startConnUpdate
函数进行连接参数更新。
//source\ti\ble5stack\profiles\roles\cc26xx\peripheral.c gapRole_taskFxn Line 895
if (events & START_CONN_UPDATE_EVT)
{
// Start connection update procedure
gapRole_startConnUpdate(GAPROLE_NO_ACTION, &gapRole_updateConnParams);
}
最后在 simple_peripheral.c 中使用以下函数端对连接参数变量进行赋值。特别注意 DEFAULT_ENABLE_UPDATE_REQUEST
,需要在其定义处修改为 GAPROLE_LINK_PARAM_UPDATE_INITIATE_BOTH_PARAMS
,这样双方都可以启动连接参数更新过程。
//examples\rtos\CC2640R2_LAUNCHXL\ble5stack\simple_peripheral\src\app\simple_peripheral.c enableUpdateRequest line 510
uint8_t enableUpdateRequest = DEFAULT_ENABLE_UPDATE_REQUEST;
uint16_t desiredMinInterval = DEFAULT_DESIRED_MIN_CONN_INTERVAL;
uint16_t desiredMaxInterval = DEFAULT_DESIRED_MAX_CONN_INTERVAL;
uint16_t desiredSlaveLatency = DEFAULT_DESIRED_SLAVE_LATENCY;
uint16_t desiredConnTimeout = DEFAULT_DESIRED_CONN_TIMEOUT;
peripheral.c
文件中直接修改连接参数,在更新的时候使用自己设置的连接参数。//examples\rtos\CC2640R2_LAUNCHXL\ble5stack\simple_peripheral\src\app\simple_peripheral.c DEFAULT_DESIRED_MAX_CONN_INTERVAL line 118
#define DEFAULT_DESIRED_MAX_CONN_INTERVAL 500
#define DEFAULT_DESIRED_CONN_TIMEOUT 2500
#define DEFAULT_DESIRED_SLAVE_LATENCY 1
下图是使用 BTool 建立连接之后等待 6 秒收到的数据。可以看出,在连接的时候使用的是主机端设置的连接参数。ConnInterval = 80 ,ConnLatency = 0 ,ConnTimout = 2000 。建立连接 6 秒之后,启动连接参数更新,并且更新为设置的 ConnInterval = 500 ,ConnLatency = 1 ,ConnTimout = 2500 。
使用 Packet Sniffer 抓包分析一下流程:
如图所示,首先,定时器时间到达之后,由从机向主机(S->M)发送连接参数更新请求命令,并携带更新参数值。主机接收到之后有权利拒绝本次更新,如果主机返回 0X0000(M->S),表示同意本次连接参数更新。
然后,主机端会根据从机的参数进行一次协商,如果从机设置的参数不满足主机端设置的最大值或最小值,则主机会设置当前支持的最大值。举个例子,如果把 DEFAULT_DESIRED_CONN_TIMEOUT
改成一个比较小的数值,主机端可能就不会使用我们设定的值,而使用主机端所能支持的最小值。
最后,主机发送协商之后最终使用的连接参数(M->S),从机接收并更新后返回应答响应。
//source\ti\ble5stack\inc\l2cap.h L2CAP_CONN_PARAMS_ACCEPTED line 210
#define L2CAP_CONN_PARAMS_ACCEPTED 0x0000 //!< Connection Parameters accepted
#define L2CAP_CONN_PARAMS_REJECTED 0x0001 //!< Connection Parameters rejected
下面是连接过程中,由主机直接发起的连接参数更新请求,可以看出如果是主机直接修改连接参数,只需要发送连接参数更新请求。从机返回响应之后即完成了连接参数更新。
文章所有代码、工具、文档开源。加入我们QQ群 591679055获取更多支持,共同研究CC2640R2F&BLE5.0。