主机扫描到广播事件,回调user_on_adv_report_ind( )函数。该函数里先使用memcmp()函数对收到的广播数据和本地预存的数据进行对比,这里是对比服务的128bit UUID。 在主机的user_config.h文件下,预定义了USER_ADVERTISE_DATA:
#define USER_ADVERTISE_DATA "\x11\x07\xb7\x5c\x49\xd2\x04\xa3\x40\x71\xa0\xb5\x35\x85\x3e\xb0\x83\x07"
把这个128bit数据和从广播收到的数据比对,如果匹配则说明找到了需要连接的从机。
void user_on_adv_report_ind(struct gapm_adv_report_ind const * param)
{
if(!memcmp(¶m->report.data[3], USER_ADVERTISE_DATA, USER_ADVERTISE_DATA_LEN))
{
arch_printf("Connect with %02x %02x %02x %02x %02x %02x",
param->report.adv_addr.addr[5],
param->report.adv_addr.addr[4],
param->report.adv_addr.addr[3],
param->report.adv_addr.addr[2],
param->report.adv_addr.addr[1],
param->report.adv_addr.addr[0]);
app_easy_gap_start_connection_to_set(param->report.adv_addr_type, (uint8_t *)¶m->report.adv_addr.addr, MS_TO_DOUBLESLOTS(USER_CON_INTV));
user_gapm_cancel();
}
}
我们看一下server端定义的service,SPS_SERVICE_UUID是128bit的,{0xb7, 0x5c, 0x49, 0xd2, 0x04, 0xa3, 0x40, 0x71, 0xa0, 0xb5, 0x35, 0x85, 0x3e, 0xb0, 0x83, 0x07}
#define SPS_SERVICE_UUID {0xb7, 0x5c, 0x49, 0xd2, 0x04, 0xa3, 0x40, 0x71, 0xa0, 0xb5, 0x35, 0x85, 0x3e, 0xb0, 0x83, 0x07}
#define SPS_SERVER_TX_UUID {0xb8, 0x5c, 0x49, 0xd2, 0x04, 0xa3, 0x40, 0x71, 0xa0, 0xb5, 0x35, 0x85, 0x3e, 0xb0, 0x83, 0x07}
#define SPS_SERVER_RX_UUID {0xba, 0x5c, 0x49, 0xd2, 0x04, 0xa3, 0x40, 0x71, 0xa0, 0xb5, 0x35, 0x85, 0x3e, 0xb0, 0x83, 0x07}
#define SPS_FLOW_CTRL_UUID {0xb9, 0x5c, 0x49, 0xd2, 0x04, 0xa3, 0x40, 0x71, 0xa0, 0xb5, 0x35, 0x85, 0x3e, 0xb0, 0x83, 0x07}
#define SPS_SERVER_TX_CHAR_LEN 160
#define SPS_SERVER_RX_CHAR_LEN 160
#define SPS_FLOW_CTRL_CHAR_LEN 1
上面在回调函数user_on_adv_report_ind()的末尾调用了 user_gapm_cancel(),取消当前GAP任务,也就是正进行的扫描任务。该函数是向ke内核发送一个取消的消息。
static void user_gapm_cancel(void)
{
struct gapm_cancel_cmd *cmd = app_gapm_cancel_msg_create();
app_gapm_cancel_msg_send(cmd);
}
内核收到该消息后,rwip_schedule()会发出GAPM_CMP_EVT事件,该事件触发回调函数gapm_cmp_evt_handler( )。 程序进一步进入gapm_cmp_evt_handler( )函数下的 case GAPM_SCAN_ACTIVE:或 case GAPM_SCAN_PASSIVE:语句,执行 EXECUTE_CALLBACK_PARAM(app_on_scanning_completed, param->status);
int gapm_cmp_evt_handler(ke_msg_id_t const msgid,
struct gapm_cmp_evt const *param,
ke_task_id_t const dest_id,
ke_task_id_t const src_id)
{
switch(param->operation)
{
case GAPM_RESET:
{
if(param->status != GAP_ERR_NO_ERROR)
{
ASSERT_ERR(0);
}
else
{
app_easy_gap_dev_configure ();
}
}
break;
case GAPM_SET_DEV_CONFIG:
{
if(param->status != GAP_ERR_NO_ERROR)
{
ASSERT_ERR(0);
}
else
{
EXECUTE_CALLBACK_VOID(app_on_set_dev_config_complete);
}
}
break;
case GAPM_ADV_UNDIRECT:
{
EXECUTE_CALLBACK_PARAM(app_on_adv_undirect_complete, param->status);
}
break;
case GAPM_ADV_DIRECT:
{
EXECUTE_CALLBACK_PARAM(app_on_adv_direct_complete, param->status);
}
break;
case GAPM_SCAN_ACTIVE:
case GAPM_SCAN_PASSIVE:
{
EXECUTE_CALLBACK_PARAM(app_on_scanning_completed, param->status);
}
break;
case GAPM_CONNECTION_DIRECT:
if (param->status == GAP_ERR_CANCELED)
{
EXECUTE_CALLBACK_VOID(app_on_connect_failed);
}
break;
case GAPM_CANCEL:
{
if(param->status != GAP_ERR_NO_ERROR)
{
ASSERT_ERR(0);
}
if (app_process_catch_rest_cb!=NULL)
{
app_process_catch_rest_cb(msgid,param,dest_id,src_id);
}
}
break;
default:
if (app_process_catch_rest_cb!=NULL)
{
app_process_catch_rest_cb(msgid,param,dest_id,src_id);
}
break;
}
return (KE_MSG_CONSUMED);
}
其中app_on_scanning_completed定义等于user_on_scanning_completed( )。也就是说,会回调user_on_scanning_completed( )函数处理。
该函先判断GAP的任务状态是否是GAP_ERR_CANCELED,如果是则说明找到一个符合条件的广播者,并且GAP已经取消了扫描任务,此时需要设置连接参数并发出连接消息 ,然后设置连接超时计时器。如果状态不是GAP_ERR_CANCELED,说明未有找到广播者,重新启动新的扫描。
#define USER_CON_TIMEOUT 700
void user_on_scanning_completed (uint8_t status)
{
if(status == GAP_ERR_CANCELED)
{
app_easy_gap_start_connection_to();
connection_timer = app_easy_timer(USER_CON_TIMEOUT, user_gapm_cancel);
}
else
{
user_scan_start();
}
return;
}
连接消息发出后,会有两种结果,一是收到来自 GAPC 的连接请求 (GAPC_CONNECTION_REQ_IND) 指示事件,二是定时器超时,取消连接任务。
当收到连接请求指示事件(GAPC_CONNECTION_REQ_IND) 的时候,会触发gapc_connection_req_ind_handler( )函数。该函数会读取当前TASK_APP任务状态,并把状态从APP_CONNECTABLE设置为APP_CONNECTED。 该函数最后通过EXECUTE_CALLBACK_PARAM1_PARAM2(app_on_connection, connection_idx, param),调用了user_on_connection()函数。
int gapc_connection_req_ind_handler(ke_msg_id_t const msgid,
struct gapc_connection_req_ind const *param,
ke_task_id_t const dest_id,
ke_task_id_t const src_id)
{
if (ke_state_get(dest_id) == APP_CONNECTABLE)
{
uint8_t connection_idx=KE_IDX_GET(src_id);
ASSERT_WARNING(connection_idx<APP_EASY_MAX_ACTIVE_CONNECTION);
app_env[connection_idx].conidx = connection_idx;
if (connection_idx != GAP_INVALID_CONIDX)
{
app_env[connection_idx].connection_active=true;
ke_state_set(TASK_APP, APP_CONNECTED);
app_env[connection_idx].conhdl = param->conhdl;
app_env[connection_idx].peer_addr_type = param->peer_addr_type;
memcpy(app_env[connection_idx].peer_addr.addr, param->peer_addr.addr, BD_ADDR_LEN);
#if (BLE_APP_SEC)
app_easy_gap_confirm(connection_idx, (enum gap_auth) app_sec_env[connection_idx].auth, GAP_AUTHZ_NOT_SET);
#else
app_easy_gap_confirm(connection_idx, GAP_AUTH_REQ_NO_MITM_NO_BOND, GAP_AUTHZ_NOT_SET);
#endif
}
EXECUTE_CALLBACK_PARAM1_PARAM2(app_on_connection, connection_idx, param);
}
else
{
ASSERT_ERR(0);
}
return (KE_MSG_CONSUMED);
}
在user_on_connection( )函数里,主机(client)调用app_easy_timer_cancel( )取消连接超时计时器,调用app_prf_enable( )启用配置文件和服务并初始化, 调用user_gattc_exc_mtu_cmd( ) 函数发出交换MTU。
void user_on_connection(uint8_t connection_idx, struct gapc_connection_req_ind const *param)
{
if (app_env[connection_idx].conidx != GAP_INVALID_CONIDX)
{
app_easy_timer_cancel(connection_timer);
app_prf_enable (param->conhdl);
user_gattc_exc_mtu_cmd(connection_idx);
if ((user_default_hnd_conf.security_request_scenario==DEF_SEC_REQ_ON_CONNECT) && (BLE_APP_SEC))
{
app_easy_security_request(connection_idx);
}
arch_printf("Device connected\r\n");
}
else
{
user_scan_start();
}
}
以上分析了主机从扫描到广播者发出的广播数据开始到建立连接的全过程:扫描到广播数据---->通过匹配服务的UUID找到连接对象---->发出建立连接请求(向从机发出)---->收到连接请求消息指示(从机同意了)---->把状态从可连接切换为已连接,启用配置文件和服务并初始化、交换MTU,---->连接建立成功。 至此,设备建立连接完毕,主机(client)可以修改从机(server)的服务特征值(可写的情况下),从机也可以发出NOTIFY或INDICATION来和主机交互数据。
|