当BLE设备收到配对设备发来的更新特征值请求时会产生一个GATTC_WRITE_CMD_IND消息,这是GATT Task messages里的一种。
enum gattc_msg_id
{
GATTC_CMP_EVT = KE_FIRST_MSG(TASK_GATTC),
GATTC_EXC_MTU_CMD,
GATTC_DISC_CMD,
GATTC_DISC_SVC_IND,
GATTC_DISC_SVC_INCL_IND,
GATTC_DISC_CHAR_IND,
GATTC_DISC_CHAR_DESC_IND,
GATTC_READ_CMD,
GATTC_READ_IND,
GATTC_WRITE_CMD,
GATTC_EXECUTE_WRITE_CMD,
GATTC_EVENT_IND,
GATTC_REG_TO_PEER_EVT_CMD,
GATTC_SEND_EVT_CMD,
GATTC_WRITE_CMD_IND,
GATTC_SEND_SVC_CHANGED_CMD,
GATTC_SVC_CHANGED_CFG_IND,
GATTC_WRITE_CMD_CFM,
GATTC_READ_CMD_IND,
};
GATTC_WRITE_CMD_IND消息会触发回调函数gattc_write_cmd_ind_handler()。该函数位于custs1_task.c文件。
const struct ke_msg_handler custs1_connected[] =
{
{GATTC_WRITE_CMD_IND, (ke_msg_func_t)gattc_write_cmd_ind_handler},
{GATTC_CMP_EVT, (ke_msg_func_t)gattc_cmp_evt_handler},
{CUSTS1_VAL_NTF_REQ, (ke_msg_func_t)custs1_val_ntf_req_handler},
{CUSTS1_VAL_SET_REQ, (ke_msg_func_t)custs1_val_set_req_handler},
{CUSTS1_VAL_IND_REQ, (ke_msg_func_t)custs1_val_ind_req_handler},
};
gattc_write_cmd_ind_handler()把消息从GAP层传递给app_entry_point_handler()APP接入点函数,该函数负责把消息再次传递给用户APP应用函数。
static int gattc_write_cmd_ind_handler(ke_msg_id_t const msgid,
struct gattc_write_cmd_ind const *param,
ke_task_id_t const dest_id,
ke_task_id_t const src_id)
{
uint16_t att_idx, value_hdl;
uint8_t status = PRF_ERR_OK;
uint8_t uuid[GATT_UUID_128_LEN];
uint8_t uuid_len;
att_size_t len;
uint8_t *value;
uint16_t perm;
if (KE_IDX_GET(src_id) == custs1_env.con_info.conidx)
{
att_idx = param->handle - custs1_env.shdl;
if( att_idx < custs1_env.max_nb_att )
{
attmdb_att_get_uuid(param->handle, &uuid_len, &(uuid[0]));
if ((uint16_t)*(uint16_t *)&uuid[0] == ATT_DESC_CLIENT_CHAR_CFG)
{
value_hdl = get_value_handle( param->handle );
if ( !value_hdl ) ASSERT_ERR(0);
attmdb_att_get_permission(value_hdl, &perm);
status = check_client_char_cfg(PERM_IS_SET(perm, NTF, ENABLE), param);
if (status == PRF_ERR_OK)
{
status = attmdb_att_set_value(param->handle, param->length, (uint8_t*)&(param->value[0]));
}
}
else
{
uint8_t i = 0;
status = PRF_ERR_OK;
while( cust_prf_funcs[i].task_id != TASK_NONE )
{
if( cust_prf_funcs[i].task_id == dest_id)
{
if ( cust_prf_funcs[i].value_wr_validation_func != NULL)
{
status = cust_prf_funcs[i].value_wr_validation_func(att_idx, param->last, param->offset, param->length, (uint8_t *)¶m->value[0]);
break;
} else i++;
} else i++;
}
if (status == PRF_ERR_OK)
{
if (param->offset == 0)
{
status = attmdb_att_set_value(param->handle, param->length, (uint8_t *)¶m->value[0]);
}
else
{
status = attmdb_att_update_value(param->handle, param->length, param->offset,
(uint8_t *)¶m->value[0]);
}
}
}
if( (param->last) && (status == PRF_ERR_OK) )
{
if( attmdb_att_get_value(param->handle, &len, &value) != ATT_ERR_NO_ERROR )
{
ASSERT_ERR(0);
}
struct custs1_val_write_ind *req_id = KE_MSG_ALLOC_DYN(CUSTS1_VAL_WRITE_IND,
custs1_env.con_info.appid, custs1_env.con_info.prf_id,
custs1_val_write_ind,
len);
memcpy(req_id->value, (uint8_t*)&value[0], len);
req_id->conhdl = gapc_get_conhdl(custs1_env.con_info.conidx);
req_id->handle = att_idx;
req_id->length = len;
ke_msg_send(req_id);
}
}
else
{
status = PRF_ERR_INEXISTENT_HDL;
}
if (param->response == 1)
{
atts_write_rsp_send(custs1_env.con_info.conidx, param->handle, status);
}
}
return (KE_MSG_CONSUMED);
}
函数通过 if( (param->last) && (status == PRF_ERR_OK) )判断数据全部接收完后,调用attmdb_att_get_value(param->handle, &len, &value)获取数据和数据长度。
然后新建一个CUSTS1_VAL_WRITE_IND 消息的结构体,并填充刚才接收的数据,最后通过调用ke_msg_send()函数把这个消息发给用户应用APP处理,该消息内含数据长度和全部数据。这里 Inform APP,很重要,把消息从GAP层发给了用户应用APP处理。
收到并处理该消息的是app_entry_point_handler()函数,该函数在sdk_app_api目录下的app_entry_point.c文件里。sdk_app_api目录的文件是负责连接底层SDK和用户APP的接口。
app_entry_point_handler()是用户应用程序入口点处理函数。
int app_entry_point_handler(ke_msg_id_t const msgid,
void const *param,
ke_task_id_t const dest_id,
ke_task_id_t const src_id)
{
int i = 0;
enum ke_msg_status_tag process_msg_handling_result;
while (i < (sizeof(app_process_handlers) / sizeof(process_event_func_t)))
{
ASSERT_ERR(app_process_handlers[i]);
if (app_process_handlers[i](msgid, param, dest_id, src_id, &process_msg_handling_result) == PR_EVENT_HANDLED)
{
return (process_msg_handling_result);
}
i++;
}
if (app_process_catch_rest_cb != NULL)
{
app_process_catch_rest_cb(msgid,param, dest_id, src_id);
}
return (KE_MSG_CONSUMED);
};
app_entry_point_handler()函数里判断消息是否已经处理,如果处理了则退出终止消息传递流程。如果没有处理,则调用app_process_catch_rest_cb()回调函数进行处理。处理完毕后,return (KE_MSG_CONSUMED),告知该消息已经处理完毕。
文件user_callback_config.h里定义了回调函数app_process_catch_rest_cb = user_catch_rest_hndl();
static const catch_rest_event_func_t app_process_catch_rest_cb = (catch_rest_event_func_t)user_catch_rest_hndl;
也就是说GAP层发来的消息通过app_entry_point_handler()接入点处理函数后调用了用户定义的回调函数user_catch_rest_hndl来处理。该函数简介里说明,是处理未被SDK内部机制处理的消息。下面看一下user_catch_rest_hndl这个回调函数都做了啥:
void user_catch_rest_hndl(ke_msg_id_t const msgid,
void const *param,
ke_task_id_t const dest_id,
ke_task_id_t const src_id)
{
switch(msgid)
{
case CUSTS1_VAL_WRITE_IND:
{
struct custs1_val_write_ind const *msg_param = (struct custs1_val_write_ind const *)(param);
switch (msg_param->handle)
{
case CUST1_IDX_CONTROL_POINT_VAL:
user_custs1_ctrl_wr_ind_handler(msgid, msg_param, dest_id, src_id);
break;
case CUST1_IDX_LED_STATE_VAL:
user_custs1_led_wr_ind_handler(msgid, msg_param, dest_id, src_id);
break;
case CUST1_IDX_ADC_VAL_1_NTF_CFG:
user_custs1_adc_val_1_cfg_ind_handler(msgid, msg_param, dest_id, src_id);
break;
case CUST1_IDX_BUTTON_STATE_NTF_CFG:
user_custs1_button_cfg_ind_handler(msgid, msg_param, dest_id, src_id);
break;
case CUST1_IDX_INDICATEABLE_IND_CFG:
user_custs1_long_val_cfg_ind_handler(msgid, msg_param, dest_id, src_id);
break;
case CUST1_IDX_LONG_VALUE_NTF_CFG:
user_custs1_long_val_cfg_ind_handler(msgid, msg_param, dest_id, src_id);
break;
case CUST1_IDX_LONG_VALUE_VAL:
user_custs1_long_val_wr_ind_handler(msgid, msg_param, dest_id, src_id);
break;
default:
break;
}
} break;
case CUSTS1_VAL_NTF_CFM:
{
struct custs1_val_ntf_cfm const *msg_param = (struct custs1_val_ntf_cfm const *)(param);
switch (msg_param->handle)
{
case CUST1_IDX_ADC_VAL_1_VAL:
break;
case CUST1_IDX_BUTTON_STATE_VAL:
break;
case CUST1_IDX_LONG_VALUE_VAL:
break;
default:
break;
}
} break;
case CUSTS1_VAL_IND_CFM:
{
struct custs1_val_ind_cfm const *msg_param = (struct custs1_val_ind_cfm const *)(param);
switch (msg_param->handle)
{
case CUST1_IDX_INDICATEABLE_VAL:
break;
default:
break;
}
} break;
case GAPC_PARAM_UPDATED_IND:
{
struct gapc_param_updated_ind const *msg_param = (struct gapc_param_updated_ind const *)(param);
if ((msg_param->con_interval >= user_connection_param_conf.intv_min) &&
(msg_param->con_interval <= user_connection_param_conf.intv_max) &&
(msg_param->con_latency == user_connection_param_conf.latency) &&
(msg_param->sup_to == user_connection_param_conf.time_out))
{
}
} break;
default:
break;
}
}
根据msgid,选择对应分支进行处理。现在是一个特征值改变的指示消息CUSTS1_VAL_WRITE_IND (Indicate that the characteristic value has been written)。 进入CUSTS1_VAL_WRITE_IND分支后,根据消息具体内容的handle选择对应的服务回调函数来处理。这里是user_custs1_led_wr_ind_handler()函数。 下面看一下这个回调函数user_custs1_led_wr_ind_handler()。
void user_custs1_led_wr_ind_handler(ke_msg_id_t const msgid,
struct custs1_val_write_ind const *param,
ke_task_id_t const dest_id,
ke_task_id_t const src_id)
{
uint8_t val = 0;
memcpy(&val, ¶m->value[0], param->length);
if (val == CUSTS1_LED_ON)
GPIO_SetActive(GPIO_LED_PORT, GPIO_LED_PIN);
else if (val == CUSTS1_LED_OFF)
GPIO_SetInactive(GPIO_LED_PORT, GPIO_LED_PIN);
}
struct custs1_val_write_ind
{
uint16_t conhdl;
uint16_t handle;
uint16_t length;
uint8_t value[__ARRAY_EMPTY];
};
把传递来的消息具体数据内容*param结构体里的元素uint8_t value[__ARRAY_EMPTY]复制到val变量里。当然这里应该是param->length = 1,也就是数组只有一个元素。 复制完毕后,根据这个值来决定GPIO口输出状态。这里是点亮或熄灭LED灯,当然也可以是去做其他事情。
以上是整个BLE设备收到其它配对设备比如手机等发来的消息后的处理流程。
|