/** **************************************************************************************** * @brief Handles reception of the @ref GATT_READ_CHAR_RESP message. * Generic event received after every simple read command sent to peer server. * @param[in] msgid Id of the message received (probably unused). * @param[in] param Pointer to the parameters of the message. * @param[in] dest_id ID of the receiving task instance (probably unused). * @param[in] src_id ID of the sending task instance. * @return If the message was consumed or not. **************************************************************************************** */ static int gatt_rd_char_rsp_handler(ke_msg_id_t const msgid, struct gatt_read_char_resp const *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { // Get the address of the environment struct qppc_env_tag *qppc_env = PRF_CLIENT_GET_ENV(dest_id, qppc); struct qppc_rd_char_rsp * rsp = KE_MSG_ALLOC_DYN(QPPC_RD_CHAR_RSP, qppc_env->con_info.appid, dest_id, qppc_rd_char_rsp, param->data.len); rsp->conhdl = qppc_env->con_info.conhdl; rsp->status = param->status; rsp->char_code = qppc_env->last_char_code; rsp->data.len = param->data.len; rsp->data.each_len = param->data.each_len; memcpy(&rsp->data.data[0], ¶m->data.data[0], param->data.len); ke_msg_send(rsp); return (KE_MSG_CONSUMED); }
void rscps_send_cmp_evt(uint8_t src_id, uint8_t dest_id, uint16_t conhdl, uint8_t operation, uint8_t status) { // Go back to the Connected state if the state is busy if (ke_state_get(src_id) == RSCPS_BUSY) { ke_state_set(src_id, RSCPS_CONNECTED); } // Set the operation code rscps_env.operation = RSCPS_RESERVED_OP_CODE; // Send the message struct rscps_cmp_evt *evt = KE_MSG_ALLOC(RSCPS_CMP_EVT, dest_id, src_id, rscps_cmp_evt); evt->conhdl = conhdl; evt->operation = operation; evt->status = status; ke_msg_send(evt); }
/** **************************************************************************************** * @brief Handles reception of the @ref GATTC_READ_IND message. * Generic event received after every simple read command sent to peer server. * @param[in] msgid Id of the message received (probably unused). * @param[in] param Pointer to the parameters of the message. * @param[in] dest_id ID of the receiving task instance (probably unused). * @param[in] src_id ID of the sending task instance. * @return If the message was consumed or not. **************************************************************************************** */ static int gattc_read_ind_handler(ke_msg_id_t const msgid, struct gattc_read_ind const *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { // Get the address of the environment struct glpc_env_tag *glpc_env = PRF_CLIENT_GET_ENV(dest_id, glpc); struct glpc_read_features_rsp * rsp = KE_MSG_ALLOC(GLPC_READ_FEATURES_RSP, glpc_env->con_info.appid, dest_id, glpc_read_features_rsp); // set connection handle rsp->conhdl = gapc_get_conhdl(glpc_env->con_info.conidx); // set error status rsp->status = ATT_ERR_NO_ERROR; // unpack feature information rsp->features = co_read16p(param->value); ke_msg_send(rsp); return (KE_MSG_CONSUMED); }
void prf_disc_svc_send(struct prf_con_info* con_info, uint16_t uuid) { //send GATT discover primary services by UUID request: find by type request struct gattc_disc_cmd * svc_req = KE_MSG_ALLOC_DYN(GATTC_DISC_CMD, KE_BUILD_ID(TASK_GATTC, con_info->conidx), con_info->prf_id, gattc_disc_cmd, ATT_UUID_16_LEN); //gatt request type: by UUID svc_req->req_type = GATTC_DISC_BY_UUID_SVC; //start handle; svc_req->start_hdl = ATT_1ST_REQ_START_HDL; //end handle svc_req->end_hdl = ATT_1ST_REQ_END_HDL; // UUID search svc_req->uuid_len = ATT_UUID_16_LEN; //set the first two bytes to the value array, LSB to MSB:Health Thermometer Service UUID first co_write16p(&(svc_req->uuid[0]), uuid); //send the message to GATT, which will send back the response when it gets it ke_msg_send(svc_req); }
/** **************************************************************************************** * @brief Handles ready indication from the GAP. - Reset the stack * * @param[in] msgid Id of the message received. * @param[in] param Pointer to the parameters of the message. * @param[in] dest_id ID of the receiving task instance (TASK_GAP). * @param[in] src_id ID of the sending task instance. * * @return If the message was consumed or not. **************************************************************************************** */ int gapm_device_ready_ind_handler(ke_msg_id_t const msgid, void const *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { if (ke_state_get(dest_id) == APP_DISABLED) { // reset the lower layers. struct gapm_reset_cmd* cmd = KE_MSG_ALLOC(GAPM_RESET_CMD, TASK_GAPM, TASK_APP, gapm_reset_cmd); cmd->operation = GAPM_RESET; ke_msg_send(cmd); } else { // APP_DISABLED state is used to wait the GAP_READY_EVT message ASSERT_ERR(0); } return (KE_MSG_CONSUMED); }
/** **************************************************************************************** * @brief Handles reception of encrypt request command * * @param[in] msgid Id of the message received. * @param[in] param Pointer to the parameters of the message. * @param[in] dest_id ID of the receiving task instance (TASK_GAP). * @param[in] src_id ID of the sending task instance. * * @return If the message was consumed or not. **************************************************************************************** */ int gapc_encrypt_req_ind_handler(ke_msg_id_t const msgid, struct gapc_encrypt_req_ind *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { struct gapc_encrypt_cfm* cfm = KE_MSG_ALLOC(GAPC_ENCRYPT_CFM, src_id, dest_id, gapc_encrypt_cfm); if (!app_validate_encrypt_req_func(param)) { cfm->found = false; } else { if(((app_sec_env.auth & GAP_AUTH_BOND) != 0) && (memcmp(&(app_sec_env.rand_nb), &(param->rand_nb), RAND_NB_LEN) == 0) && (app_sec_env.ediv == param->ediv)) { cfm->found = true; cfm->key_size = app_sec_env.key_size; memcpy(&(cfm->ltk), &(app_sec_env.ltk), KEY_LEN); // update connection auth app_connect_confirm(app_sec_env.auth); app_sec_encrypt_complete_func(); } else { cfm->found = false; } } ke_msg_send(cfm); if (cfm->found == false) app_disconnect(); return (KE_MSG_CONSUMED); }
/** **************************************************************************************** * @brief Handles read command characteristic event indication from device_config profile * * @param[in] msgid Id of the message received. * @param[in] param Pointer to the parameters of the message. * @param[in] dest_id ID of the receiving task instance (TASK_GAP). * @param[in] src_id ID of the sending task instance. * * @return If the message was consumed or not. **************************************************************************************** */ int app_device_read_request_ind_handler(ke_msg_id_t const msgid, struct device_config_read_request_ind const *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { uint8_t status = 0; // Allocate message struct device_config_read_response_cmd *cmd = KE_MSG_ALLOC(DEVICE_READ_RESPONSE_CMD, TASK_DEVICE_CONFIG, TASK_APP, device_config_read_response_cmd); if (param->param_id >= app_device_config_env.params_num) { status = 1; } if (!status) { cmd->size = app_device_config_env.params[param->param_id].size; memcpy(cmd->val, app_device_config_env.params[param->param_id].p_data, cmd->size ); } else { cmd->size = 0; } cmd->param_id = param->param_id; cmd->conhdl = app_env.conhdl; cmd->status = status; ke_msg_send(cmd); return (KE_MSG_CONSUMED); }
/** **************************************************************************************** * @brief Handles reception of the @ref GL2C_CODE_ATT_WR_CMD_IND message. * The message is redirected from TASK_SVC because at profile enable, the ATT handle is * register for TASK_FINDT. In the handler, an ATT Write Response/Error Response should * be sent for ATT protocol, but Alert Level Characteristic only supports WNR so no * response PDU is needed. * @param[in] msgid Id of the message received (probably unused). * @param[in] param Pointer to the parameters of the message. * @param[in] dest_id ID of the receiving task instance (probably unused). * @param[in] src_id ID of the sending task instance. * @return If the message was consumed or not. **************************************************************************************** */ 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) { uint8_t alert_lvl = 0x0000; if (KE_IDX_GET(src_id) == findt_env.con_info.conidx) { if(param->handle == findt_env.shdl + FINDT_IAS_IDX_ALERT_LVL_VAL) { alert_lvl = param->value[0]; //Check if Alert Level is valid if ((param->value[0] <= FINDT_ALERT_HIGH)) { //Update the attribute value attmdb_att_set_value(param->handle, sizeof(uint8_t), (uint8_t *)&alert_lvl); if(param->last) { // Allocate the alert value change indication struct findt_alert_ind *ind = KE_MSG_ALLOC(FINDT_ALERT_IND, findt_env.con_info.appid, TASK_FINDT, findt_alert_ind); // Fill in the parameter structure ind->conhdl = gapc_get_conhdl(findt_env.con_info.conidx); ind->alert_lvl = alert_lvl; // Send the message ke_msg_send(ind); } // It was a Write Without Response so no RSP needed. } } } return (KE_MSG_CONSUMED); }
/** **************************************************************************************** * @brief Handles start indication from the Proximity Reporter profile. * * @param[in] msgid Id of the message received. * @param[in] param Pointer to the parameters of the message. * @param[in] dest_id ID of the receiving task instance (TASK_GAP). * @param[in] src_id ID of the sending task instance. * * @return If the message was consumed or not. **************************************************************************************** */ int accel_create_db_cfm_handler(ke_msg_id_t const msgid, struct accel_create_db_cfm const *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { // If state is not idle, ignore the message if (ke_state_get(dest_id) == APP_DB_INIT) { app_accel_init(); // Inform the Application Manager struct app_module_init_cmp_evt *cfm = KE_MSG_ALLOC(APP_MODULE_INIT_CMP_EVT, TASK_APP, TASK_APP, app_module_init_cmp_evt); cfm->status = CO_ERROR_NO_ERROR; //param->status; ke_msg_send(cfm); } return (KE_MSG_CONSUMED); }
void app_custom_connection(struct gapc_connection_req_ind const *param) { #if BLE_ACCEL int temp=4; uint8_t *temp_v; app_accel_adv_stopped(); if (!param->con_latency) { // Not completely verified, but this improves the stability of the connection. struct gapc_param_update_req_ind * req = KE_MSG_ALLOC(GAPC_PARAM_UPDATE_REQ_IND, TASK_GAPC, TASK_APP, gapc_param_update_req_ind); // Fill in the parameter structure //req->conhdl = param->conn_info.conhdl; //GZ req->conn_par.intv_min = param->conn_info.con_interval; //GZ req->conn_par.intv_max = param->conn_info.con_interval; attmdb_att_get_value(ACCEL_HANDLE(ACCEL_IDX_ACCEL_X_EN), &(temp), &(temp_v)); if(temp_v[1] > 1) accel_con_interval = temp_v[1]; req->params.intv_min = (accel_con_interval-1)*10/1.25; req->params.intv_max = (accel_con_interval)*10/1.25; req->params.latency = param->con_latency; if(param->sup_to * 8 / 1.25 <= 3200) req->params.time_out = param->sup_to * 8 / 1.25; else req->params.time_out = 3200/1.25; #if BLE_HID_DEVICE puts("Send GAP_PARAM_UPDATE_REQ"); #endif ke_msg_send(req); } #endif }
/** **************************************************************************************** * @brief Handles reception of the @ref HPSS_CREATE_DB_REQ message. * The handler adds HPS into the database. * @param[in] msgid Id of the message received (probably unused). * @param[in] param Pointer to the parameters of the message. * @param[in] dest_id ID of the receiving task instance (probably unused). * @param[in] src_id ID of the sending task instance. * @return If the message was consumed or not. **************************************************************************************** */ static int hpss_create_db_req_handler(ke_msg_id_t const msgid, struct hpss_create_db_req const *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { //Database Creation Status uint8_t status; //Save Profile ID hpss_env.con_info.prf_id = TASK_HPSS; /*---------------------------------------------------* * HTTP Proxy Service Creation *---------------------------------------------------*/ //Add Service Into Database status = attm_svc_create_db(&hpss_env.hps_shdl, NULL, HPS_IDX_NB, NULL, dest_id, &hpss_att_db[0]); //Disable HPS attmdb_svc_set_permission(hpss_env.hps_shdl, PERM(SVC, DISABLE)); //Go to Idle State if (status == ATT_ERR_NO_ERROR) { //If we are here, database has been fulfilled with success, go to idle state ke_state_set(TASK_HPSS, HPSS_IDLE); } //Send CFM to application struct hpss_create_db_cfm * cfm = KE_MSG_ALLOC(HPSS_CREATE_DB_CFM, src_id, TASK_HPSS, hpss_create_db_cfm); cfm->status = status; ke_msg_send(cfm); return (KE_MSG_CONSUMED); }
void app_hrps_enable(void) { // Allocate the message struct hrps_enable_req * req = KE_MSG_ALLOC(HRPS_ENABLE_REQ, TASK_HRPS, TASK_APP, hrps_enable_req); //结构体填充部分需要后续改善 // Fill in the parameter structure ///Connection handle req->conhdl = app_env.conhdl; /// security level: b0= nothing, b1=unauthenticated, b2=authenticated, b3=authorized; /// b1 or b2 and b3 can go together req->sec_lvl = PERM(SVC, ENABLE); ///Type of connection - will someday depend on button press length; can be CFG or DISCOVERY req->con_type = PRF_CON_NORMAL;// PRF_CON_DISCOVERY; /// Heart Rate Notification configuration req->hr_meas_ntf_en = 1;//PRF_CLI_START_NTF;//PRF_CLI_STOP_NTFIND ///Body Sensor Location req->body_sensor_loc = 1; // Send the message ke_msg_send(req); }
void disc_enable_cfm_send(struct disc_env_tag *disc_env, struct prf_con_info *con_info, uint8_t status) { // Send APP the details of the discovered attributes on DISS struct disc_enable_cfm * rsp = KE_MSG_ALLOC(DISC_ENABLE_CFM, con_info->appid, con_info->prf_id, disc_enable_cfm); rsp->conhdl = gapc_get_conhdl(con_info->conidx); rsp->status = status; if (status == PRF_ERR_OK) { rsp->dis = disc_env->dis; // Go to connected state ke_state_set(con_info->prf_id, DISC_CONNECTED); } else { PRF_CLIENT_ENABLE_ERROR(disc_envs, con_info->prf_id, DISC); } ke_msg_send(rsp); }
/* **************************************************************************************** * @brief Gatt Read Characteristic request. *//** * * @param[in] req_type GATT request type: * - GATT_READ_CHAR * - GATT_READ_BY_UUID_CHAR * - GATT_READ_LONG_CHAR * - GATT_READ_MULT_LONG_CHAR * - GATT_READ_DESC * - GATT_READ_LONG_DESC * @param[in] conhdl Connection handle. * @param[in] valhdl Value handle. * @response GATT_READ_CHAR_RESP or GATT_READ_CHAR_MULTI_RESP * @description * * This API is used by the application to send a GATT_READ_CHAR_REQ mssage. * Upon reception of this message, GATT will checks whether the parameters are correct, * if not correct then the GATT_CMP_EVT message with error code GATT_INVALID_PARAM_ERR * will be generically built and sent to Application directly. If parameter is correct, * the GATT_READ_CHAR_RESP message will be received. * **************************************************************************************** */ void app_gatt_read_char_req(uint8_t req_type, uint16_t conhdl, uint16_t valhdl) { struct gatt_read_char_req *msg = KE_MSG_ALLOC(GATT_READ_CHAR_REQ, TASK_GATT, TASK_APP, gatt_read_char_req); //Connection handle msg->conhdl = conhdl; //GATT request type msg->req_type = req_type; //Read offset msg->offset = 0; //Start handle range msg->start_hdl = 0x0001; //End handle range msg->end_hdl = GATT_MAX_ATTR_HDL; //Number of UUID msg->nb_uuid = 0x01; //Handle of char value msg->uuid[0].expect_resp_size = ATT_UUID_16_LEN; msg->uuid[0].value_size = ATT_UUID_16_LEN; co_write16p(&msg->uuid[0].value[0], valhdl); ke_msg_send(msg); }
static int diss_create_db_req_handler(ke_msg_id_t const msgid, struct diss_create_db_req const *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { //Service content flag uint32_t cfg_flag; //DB Creation Statis uint8_t status = ATT_ERR_NO_ERROR; //Save profile id diss_env.con_info.prf_id = TASK_DISS; //Compute Attribute Table and save it in environment cfg_flag = diss_compute_cfg_flag(param->features); status = attm_svc_create_db(&diss_env.shdl, (uint8_t *)&cfg_flag, DIS_IDX_NB, &diss_env.att_tbl[0], dest_id, &diss_att_db[0]); if (status == ATT_ERR_NO_ERROR) { //Disable service status = attmdb_svc_set_permission(diss_env.shdl, PERM(SVC, DISABLE)); //If we are here, database has been fulfilled with success, go to idle test ke_state_set(TASK_DISS, DISS_IDLE); } //Send response to application struct diss_create_db_cfm * cfm = KE_MSG_ALLOC(DISS_CREATE_DB_CFM, src_id, TASK_DISS, diss_create_db_cfm); cfm->status = status; ke_msg_send(cfm); return (KE_MSG_CONSUMED); }
/** **************************************************************************************** * @brief Handles reception of the @ref GATTC_CMP_EVT message. * This generic event is received for different requests, so need to keep track. * @param[in] msgid Id of the message received (probably unused). * @param[in] param Pointer to the parameters of the message. * @param[in] dest_id ID of the receiving task instance (probably unused). * @param[in] src_id ID of the sending task instance. * @return If the message was consumed or not. **************************************************************************************** */ static int gattc_cmp_evt_handler(ke_msg_id_t const msgid, struct gattc_cmp_evt const *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { uint8_t state = ke_state_get(dest_id); // Get the address of the environment struct scppc_env_tag *scppc_env = PRF_CLIENT_GET_ENV(dest_id, scppc); uint8_t status = PRF_ERR_OK; if(state == SCPPC_DISCOVERING) { if ((param->status == ATT_ERR_ATTRIBUTE_NOT_FOUND) || (param->status == ATT_ERR_NO_ERROR)) { // Service start/end handles has been received if(scppc_env->last_uuid_req == ATT_SVC_SCAN_PARAMETERS) { // check if service handles are not ok if(scppc_env->scps.svc.shdl== ATT_INVALID_HANDLE) { // stop discovery procedure. scppc_enable_cfm_send(scppc_env, &scppc_env->con_info, PRF_ERR_STOP_DISC_CHAR_MISSING); } // Too many services found only one such service should exist else if(scppc_env->nb_svc > 1) { scppc_enable_cfm_send(scppc_env, &scppc_env->con_info, PRF_ERR_MULTIPLE_SVC); } else { // Discover all SCPS characteristics prf_disc_char_all_send(&(scppc_env->con_info), &(scppc_env->scps.svc)); scppc_env->last_uuid_req = ATT_DECL_CHARACTERISTIC; } } else if(scppc_env->last_uuid_req == ATT_DECL_CHARACTERISTIC) { status = prf_check_svc_char_validity(SCPPC_CHAR_MAX, scppc_env->scps.chars, scppc_scps_char); if(status == PRF_ERR_OK) { //If Scan Refresh Char. is present, discover its descriptor if (scppc_env->scps.chars[SCPPC_CHAR_SCAN_REFRESH].char_hdl != ATT_INVALID_HANDLE) { scppc_env->last_uuid_req = ATT_INVALID_HANDLE; scppc_env->last_char_code = scppc_scps_char_desc[SCPPC_DESC_SCAN_REFRESH_CFG].char_code; // Discover Scan Refresh Char. Descriptor - Mandatory prf_disc_char_desc_send(&(scppc_env->con_info), &(scppc_env->scps.chars[scppc_env->last_char_code])); } else { scppc_enable_cfm_send(scppc_env, &scppc_env->con_info, status); } } else { // Stop discovery procedure. scppc_enable_cfm_send(scppc_env, &scppc_env->con_info, status); } } else { status = prf_check_svc_char_desc_validity(SCPPC_DESC_MAX, scppc_env->scps.descs, scppc_scps_char_desc, scppc_env->scps.chars); scppc_enable_cfm_send(scppc_env, &scppc_env->con_info, status); } if (status == PRF_ERR_OK) { // Write Scan Interval Windows value struct scppc_scan_intv_wd_wr_req * req = KE_MSG_ALLOC(SCPPC_SCAN_INTV_WD_WR_REQ, dest_id, dest_id, scppc_scan_intv_wd_wr_req); req->conhdl = gapc_get_conhdl(scppc_env->con_info.conidx); co_write16p(&req->scan_intv_wd.le_scan_intv, scppc_env->scan_intv_wd.le_scan_intv); co_write16p(&req->scan_intv_wd.le_scan_window, scppc_env->scan_intv_wd.le_scan_window); ke_msg_send(req); } } } else if (state == SCPPC_CONNECTED) { switch(param->req_type) { case GATTC_WRITE: { struct scppc_wr_char_rsp *wr_cfm = KE_MSG_ALLOC(SCPPC_WR_CHAR_RSP, scppc_env->con_info.appid, dest_id, scppc_wr_char_rsp); wr_cfm->conhdl = gapc_get_conhdl(scppc_env->con_info.conidx); //it will be a GATT status code wr_cfm->status = param->status; // send the message ke_msg_send(wr_cfm); } break; case GATTC_READ: { if(param->status != GATT_ERR_NO_ERROR) { // an error occurs while reading peer device attribute scppc_error_ind_send(scppc_env, param->status); } } break; default: break; } } return (KE_MSG_CONSUMED); }
/** **************************************************************************************** * @brief Handles reception of the @ref SCPPC_ENABLE_REQ message. * The handler enables the Scan Parameters Profile Client Role. * @param[in] msgid Id of the message received (probably unused). * @param[in] param Pointer to the parameters of the message. * @param[in] dest_id ID of the receiving task instance (probably unused). * @param[in] src_id ID of the sending task instance. * @return If the message was consumed or not. **************************************************************************************** */ static int scppc_enable_req_handler(ke_msg_id_t const msgid, struct scppc_enable_req const *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { // Status uint8_t status; // Scan Parameters Profile Client Role Task Environment struct scppc_env_tag *scppc_env; // Connection Information struct prf_con_info con_info; // Fill the Connection Information structure con_info.conidx = gapc_get_conidx(param->conhdl); con_info.prf_id = dest_id; con_info.appid = src_id; // Add an environment for the provided device status = PRF_CLIENT_ENABLE(con_info, param, scppc); if (status == PRF_ERR_FEATURE_NOT_SUPPORTED) { // The message has been forwarded to another task id. return (KE_MSG_NO_FREE); } else if (status == PRF_ERR_OK) { scppc_env = PRF_CLIENT_GET_ENV(dest_id, scppc); // Save Scan Interval Window value memcpy(&scppc_env->scan_intv_wd, ¶m->scan_intv_wd, sizeof(struct scan_intv_wd)); // Config connection, start discovering if(param->con_type == PRF_CON_DISCOVERY) { //start discovering SCPS on peer prf_disc_svc_send(&(scppc_env->con_info), ATT_SVC_SCAN_PARAMETERS); scppc_env->last_uuid_req = ATT_SVC_SCAN_PARAMETERS; // Go to DISCOVERING state ke_state_set(dest_id, SCPPC_DISCOVERING); } // Normal connection, get saved att details else { scppc_env->scps = param->scps; if (scppc_env->scps.chars[SCPPC_CHAR_SCAN_REFRESH].char_hdl != ATT_INVALID_HANDLE) { /* If connected to a bonded Scan Server, the Scan Client shall enable notifications of the * Scan Refresh characteristic using the Client Characteristic Configuration descriptor. */ struct scppc_scan_refresh_ntf_cfg_req *req = KE_MSG_ALLOC(SCPPC_SCAN_REFRESH_NTF_CFG_REQ, dest_id, dest_id, scppc_scan_refresh_ntf_cfg_req); req->conhdl = gapc_get_conhdl(scppc_env->con_info.conidx); req->ntf_cfg = PRF_CLI_START_NTF; // send the message ke_msg_send(req); } else { // Write Scan Interval Windows value struct scppc_scan_intv_wd_wr_req * req = KE_MSG_ALLOC(SCPPC_SCAN_INTV_WD_WR_REQ, dest_id, dest_id, scppc_scan_intv_wd_wr_req); req->conhdl = gapc_get_conhdl(scppc_env->con_info.conidx); co_write16p(&req->scan_intv_wd.le_scan_intv, scppc_env->scan_intv_wd.le_scan_intv); co_write16p(&req->scan_intv_wd.le_scan_window, scppc_env->scan_intv_wd.le_scan_window); ke_msg_send(req); } scppc_enable_cfm_send(scppc_env, &con_info, PRF_ERR_OK); } } else { // An error has been raised during the process, scps is NULL and won't be handled scppc_enable_cfm_send(NULL, &con_info, status); } return (KE_MSG_CONSUMED); }
/** **************************************************************************************** * @brief Handles GAP manager command complete events. * * @param[in] msgid Id of the message received. * @param[in] param Pointer to the parameters of the message. * @param[in] dest_id ID of the receiving task instance (TASK_GAP). * @param[in] src_id ID of the sending task instance. * * @return If the message was consumed or not. **************************************************************************************** */ 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) { // reset completed case GAPM_RESET: { if(param->status != GAP_ERR_NO_ERROR) { ASSERT_ERR(0); // unexpected error } else { // set device configuration struct gapm_set_dev_config_cmd* cmd = KE_MSG_ALLOC(GAPM_SET_DEV_CONFIG_CMD, TASK_GAPM, TASK_APP, gapm_set_dev_config_cmd); app_configuration_func(dest_id, cmd); ke_msg_send(cmd); } } break; // device configuration updated case GAPM_SET_DEV_CONFIG: { if(param->status != GAP_ERR_NO_ERROR) { ASSERT_ERR(0); // unexpected error } else { app_set_dev_config_complete_func(); } } break; // Advertising finished case GAPM_ADV_UNDIRECT: { app_adv_undirect_complete(param->status); } break; // Directed advertising finished case GAPM_ADV_DIRECT: { app_adv_direct_complete(param->status); } break; case GAPM_SCAN_PASSIVE: case GAPM_SCAN_ACTIVE: { if (param->status == GAP_ERR_CANCELED) { app_connect(); } else { app_scanning(); } } break; /* end */ case GAPM_CANCEL: { if(param->status != GAP_ERR_NO_ERROR) { ASSERT_ERR(0); // unexpected error } } case GAPM_CONNECTION_DIRECT: if (param->status == GAP_ERR_CANCELED) { app_connect_failed_func(); } break; default: { ASSERT_ERR(0); // unexpected error } break; } return (KE_MSG_CONSUMED); }
/** **************************************************************************************** * @brief Handles reception of the @ref GATT_READ_CHAR_RESP message. * Generic event received after every simple read command sent to peer server. * @param[in] msgid Id of the message received (probably unused). * @param[in] param Pointer to the parameters of the message. * @param[in] dest_id ID of the receiving task instance (probably unused). * @param[in] src_id ID of the sending task instance. * @return If the message was consumed or not. **************************************************************************************** */ static int gatt_rd_char_rsp_handler(ke_msg_id_t const msgid, struct gatt_read_char_resp const *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { uint8_t error_status = param->status; // Get the address of the environment struct hogpbh_env_tag *hogpbh_env = PRF_CLIENT_GET_ENV(dest_id, hogpbh); if (error_status == PRF_ERR_OK) { switch (hogpbh_env->last_char_code) { // Boot Keyboard Input Report Read Response case (HOGPBH_CHAR_BOOT_KB_IN_REPORT): // Boot Mouse Input Report Read Response case (HOGPBH_CHAR_BOOT_MOUSE_IN_REPORT): // Boot Mouse Input Report Read Response case (HOGPBH_CHAR_BOOT_KB_OUT_REPORT): { // Check report length if (param->data.len <= HOGPBH_BOOT_REPORT_MAX_LEN) { struct hogpbh_boot_report_ind *ind = KE_MSG_ALLOC_DYN(HOGPBH_BOOT_REPORT_IND, hogpbh_env->con_info.appid, dest_id, hogpbh_boot_report_ind, param->data.len); ind->conhdl = hogpbh_env->con_info.conhdl; ind->ind_type = HOGPBH_IND_RD_RSP; ind->hids_nb = hogpbh_env->last_svc_inst_req; ind->char_code = hogpbh_env->last_char_code; ind->report_length = param->data.len; memcpy(&ind->report[0], ¶m->data.data[0], param->data.len); ke_msg_send(ind); } else { error_status = PRF_ERR_UNEXPECTED_LEN; } break; } //Protocol Mode Read Response case (HOGPBH_CHAR_PROTO_MODE): { struct hogpbh_proto_mode_rd_rsp *rsp = KE_MSG_ALLOC(HOGPBH_PROTO_MODE_RD_RSP, hogpbh_env->con_info.appid, dest_id, hogpbh_proto_mode_rd_rsp); rsp->conhdl = hogpbh_env->con_info.conhdl; rsp->hids_nb = hogpbh_env->last_svc_inst_req; memcpy(&rsp->proto_mode, ¶m->data.data[0], sizeof(uint8_t)); ke_msg_send(rsp); break; } //Client Characteristic Configuration case (HOGPBH_RD_WR_HIDS_BOOT_KB_IN_REPORT_CFG): case (HOGPBH_RD_WR_HIDS_BOOT_MOUSE_IN_REPORT_CFG): { struct hogpbh_cfg_ntf_rd_rsp *rsp = KE_MSG_ALLOC(HOGPBH_CFG_NTF_RD_RSP, hogpbh_env->con_info.appid, dest_id, hogpbh_cfg_ntf_rd_rsp); rsp->conhdl = hogpbh_env->con_info.conhdl; rsp->desc_code = hogpbh_env->last_char_code; rsp->hids_nb = hogpbh_env->last_svc_inst_req; memcpy(&rsp->cfg_val, ¶m->data.data[0], sizeof(uint16_t)); ke_msg_send(rsp); break; } default: break; } } if (error_status != PRF_ERR_OK) { hogpbh_char_req_rsp_send(hogpbh_env, HOGPBH_RD_CHAR_ERR_RSP, error_status); } return (KE_MSG_CONSUMED); }
/** **************************************************************************************** * @brief Handles reception of the @ref GATT_HANDLE_VALUE_NTF message. * @param[in] msgid Id of the message received (probably unused). * @param[in] param Pointer to the parameters of the message. * @param[in] dest_id ID of the receiving task instance (probably unused). * @param[in] src_id ID of the sending task instance. * @return If the message was consumed or not. **************************************************************************************** */ static int gatt_handle_value_ntf_handler(ke_msg_id_t const msgid, struct gatt_handle_value_notif const *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { // Get the address of the environment struct cscpc_env_tag *cscpc_env = PRF_CLIENT_GET_ENV(dest_id, cscpc); if (cscpc_env != NULL) { // Offset uint8_t offset = CSCP_CSC_MEAS_MIN_LEN; // CSC Measurement value has been received struct cscpc_value_ind *ind = KE_MSG_ALLOC(CSCPC_VALUE_IND, cscpc_env->con_info.appid, cscpc_env->con_info.prf_id, cscpc_value_ind); // Connection Handle ind->conhdl = param->conhdl; // Attribute code ind->att_code = CSCPC_NTF_CSC_MEAS; /*---------------------------------------------------- * Unpack Measurement -------------------------------- *----------------------------------------------------*/ // Flags ind->value.csc_meas.flags = param->value[0]; // Cumulative Wheel Revolutions // Last Wheel Event Time if ((param->value[0] & CSCP_MEAS_WHEEL_REV_DATA_PRESENT) == CSCP_MEAS_WHEEL_REV_DATA_PRESENT) { // Cumulative Wheel Revolutions ind->value.csc_meas.cumul_wheel_rev = co_read32p(¶m->value[offset]); offset += 4; // Last Wheel Event Time ind->value.csc_meas.last_wheel_evt_time = co_read16p(¶m->value[offset]); offset += 2; } // Cumulative Crank Revolutions // Last Crank Event Time if ((param->value[0] & CSCP_MEAS_CRANK_REV_DATA_PRESENT) == CSCP_MEAS_CRANK_REV_DATA_PRESENT) { // Cumulative Crank Revolutions ind->value.csc_meas.cumul_crank_rev = co_read16p(¶m->value[offset]); offset += 2; // Last Crank Event Time ind->value.csc_meas.last_crank_evt_time = co_read16p(¶m->value[offset]); } ke_msg_send(ind); } // else ignore the message return (KE_MSG_CONSUMED); }
/** **************************************************************************************** * @brief Handles reception of the @ref GATT_READ_CHAR_RESP message. * @param[in] msgid Id of the message received. * @param[in] param Pointer to the parameters of the message. * @param[in] dest_id ID of the receiving task instance. * @param[in] src_id ID of the sending task instance. * @return If the message was consumed or not. **************************************************************************************** */ static int gatt_rd_char_rsp_handler(ke_msg_id_t const msgid, struct gatt_read_char_resp const *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { // Get the address of the environment struct cscpc_env_tag *cscpc_env = PRF_CLIENT_GET_ENV(dest_id, cscpc); if (cscpc_env != NULL) { ASSERT_ERR(cscpc_env->operation != NULL); ASSERT_ERR(((struct cscpc_cmd *)cscpc_env->operation)->operation == CSCPC_READ_OP_CODE); if (param->status == GATT_NO_ERROR) { // Send the read value to the HL struct cscpc_value_ind *ind = KE_MSG_ALLOC(CSCPC_VALUE_IND, cscpc_env->con_info.appid, cscpc_env->con_info.prf_id, cscpc_value_ind); ind->conhdl = cscpc_env->con_info.conhdl; switch (((struct cscpc_read_cmd *)cscpc_env->operation)->read_code) { // Read CSC Feature Characteristic value case (CSCPC_RD_CSC_FEAT): { co_write16p(&ind->value.sensor_feat, param->data.data[0]); // Mask the reserved bits ind->value.sensor_feat &= CSCP_FEAT_ALL_SUPP; } break; // Read Sensor Location Characteristic value case (CSCPC_RD_SENSOR_LOC): { ind->value.sensor_loc = (param->data.data[0] < CSCP_LOC_MAX) ? param->data.data[0] : CSCP_LOC_OTHER; } break; // Read Client Characteristic Configuration Descriptor value case (CSCPC_RD_WR_CSC_MEAS_CFG): case (CSCPC_RD_WR_SC_CTNL_PT_CFG): { co_write16p(&ind->value.ntf_cfg, param->data.data[0]); } break; default: { ASSERT_ERR(0); } break; } ind->att_code = ((struct cscpc_read_cmd *)cscpc_env->operation)->read_code; // Send the message to the application ke_msg_send(ind); } // Send a complete event status to the application cscpc_send_cmp_evt(cscpc_env, CSCPC_READ_OP_CODE, param->status); } // else drop the message return (KE_MSG_CONSUMED); }
/** **************************************************************************************** * @brief Handles reception of the @ref GLPS_ENABLE_REQ message. * The handler enables the Glucose Sensor Profile and initialize readable values. * @param[in] msgid Id of the message received (probably unused).off * @param[in] param Pointer to the parameters of the message. * @param[in] dest_id ID of the receiving task instance (probably unused). * @param[in] src_id ID of the sending task instance. * @return If the message was consumed or not. **************************************************************************************** */ static int glps_enable_req_handler(ke_msg_id_t const msgid, struct glps_enable_req const *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { uint8_t status = PRF_ERR_REQ_DISALLOWED; if(!GLPS_IS(ENABLE)) { // Check if the provided connection exist if (gap_get_rec_idx(param->conhdl) != GAP_INVALID_CONIDX) { status = PRF_ERR_OK; GLPS_SET(ENABLE); //Value used to initialize all readable value in DB uint16_t indntf_cfg = PRF_CLI_STOP_NTFIND; // Save the application task id glps_env.con_info.appid = src_id; // Save the connection handle associated to the profile glps_env.con_info.conhdl = param->conhdl; // No RACP at service start. GLPS_CLEAR(RACP_ON_GOING); GLPS_CLEAR(SENDING_MEAS); // Configure Glucose Measuremment IND Cfg in DB if(param->con_type == PRF_CON_NORMAL) { glps_env.evt_cfg = param->evt_cfg; } else { glps_env.evt_cfg = 0; } if((glps_env.evt_cfg & GLPS_MEAS_NTF_CFG) != 0) { indntf_cfg = PRF_CLI_START_NTF; } //Set Glucose measurement notification configuration attsdb_att_set_value(GLPS_HANDLE(GLS_IDX_MEAS_NTF_CFG), sizeof(uint16_t), (uint8_t *)&indntf_cfg); // Configure Intermediate Cuff Pressure NTF Cfg in DB //Configure Glucose measurement context notification if (GLPS_IS(MEAS_CTX_SUPPORTED)) { indntf_cfg = PRF_CLI_STOP_NTFIND; if((glps_env.evt_cfg & GLPS_MEAS_CTX_NTF_CFG) != 0) { indntf_cfg = PRF_CLI_START_NTF; } //Set Glucose measurement context notification configuration attsdb_att_set_value(GLPS_HANDLE(GLS_IDX_MEAS_CTX_NTF_CFG), sizeof(uint16_t), (uint8_t *)&indntf_cfg); } indntf_cfg = PRF_CLI_STOP_NTFIND; if((glps_env.evt_cfg & GLPS_RACP_IND_CFG) != 0) { indntf_cfg = PRF_CLI_START_IND; } //Set record access control point indication configuration attsdb_att_set_value(GLPS_HANDLE(GLS_IDX_REC_ACCESS_CTRL_IND_CFG), sizeof(uint16_t), (uint8_t *)&indntf_cfg); //Set Glucose sensor features attsdb_att_set_value(GLPS_HANDLE(GLS_IDX_FEATURE_VAL), sizeof(uint16_t), (uint8_t *)¶m->features); // Enable Service + Set Security Level attsdb_svc_set_permission(glps_env.shdl, param->sec_lvl); // Go to connected state ke_state_set(TASK_GLPS, GLPS_CONNECTED); } } // send completed information to APP task that contains error status struct glps_enable_cfm * cmp_evt = KE_MSG_ALLOC(GLPS_ENABLE_CFM, src_id, TASK_GLPS, glps_enable_cfm); cmp_evt->conhdl = param->conhdl; cmp_evt->status = status; ke_msg_send(cmp_evt); return (KE_MSG_CONSUMED); }
/** **************************************************************************************** * @brief Handles reception of the @ref SAMPLE128_CREATE_DB_REQ message. * @param[in] msgid Id of the message received (probably unused). * @param[in] param Pointer to the parameters of the message. * @param[in] dest_id ID of the receiving task instance (probably unused). * @param[in] src_id ID of the sending task instance. * @return If the message was consumed or not. **************************************************************************************** */ static int sample128_create_db_req_handler(ke_msg_id_t const msgid, struct sample128_create_db_req const *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { //Database Creation Status uint8_t status; uint8_t nb_att_16; uint8_t nb_att_128; uint8_t nb_att_32; uint16_t att_decl_svc = ATT_DECL_PRIMARY_SERVICE; uint16_t att_decl_char = ATT_DECL_CHARACTERISTIC; uint16_t att_decl_cfg = ATT_DESC_CLIENT_CHAR_CFG; uint16_t val_hdl; uint16_t char_hdl; //Save Profile ID sample128_env.con_info.prf_id = TASK_SAMPLE128; /*---------------------------------------------------* * Link Loss Service Creation *---------------------------------------------------*/ //Add Service Into Database nb_att_16 = 4; // 2 UUID16 atts nb_att_32 = 0;// No UUID32 att nb_att_128 = 2; //1 UUID128 att status = attmdb_add_service(&(sample128_env.sample128_shdl), TASK_SAMPLE128, nb_att_16, nb_att_32, nb_att_128, 58); //total attributte size = 36, 16 (svc) + 19 (desc_char) + 1 (att) if (status == ATT_ERR_NO_ERROR) { //add svc attribute status = attmdb_add_attribute(sample128_env.sample128_shdl, ATT_UUID_128_LEN, //Data size = 16 (ATT_UUID_128_LEN) ATT_UUID_16_LEN, (uint8_t*)&att_decl_svc, PERM(RD, ENABLE), &(sample128_env.sample128_shdl)); status = attmdb_att_set_value(sample128_env.sample128_shdl, ATT_UUID_128_LEN, (uint8_t *)sample128_svc.uuid); //char 1 //add char attribute status = attmdb_add_attribute(sample128_env.sample128_shdl, ATT_UUID_128_LEN + 3, //Data size = 19 (ATT_UUID_128_LEN + 3) ATT_UUID_16_LEN, (uint8_t*) &att_decl_char, PERM(RD, ENABLE), &(char_hdl)); //add val attribute status = attmdb_add_attribute(sample128_env.sample128_shdl, sizeof(uint8_t), //Data size = 1 ATT_UUID_128_LEN, (uint8_t*)&sample128_1_val.uuid, PERM(RD, ENABLE) | PERM(WR, ENABLE), &(val_hdl)); memcpy(sample128_1_char.attr_hdl, &val_hdl, sizeof(uint16_t)); status = attmdb_att_set_value(char_hdl, sizeof(sample128_1_char), (uint8_t *)&sample128_1_char); //////char 2 //add char attribute status = attmdb_add_attribute(sample128_env.sample128_shdl, ATT_UUID_128_LEN + 3, //Data size = 19 (ATT_UUID_128_LEN + 3) ATT_UUID_16_LEN, (uint8_t*) &att_decl_char, PERM(RD, ENABLE), &(char_hdl)); //add val attribute status = attmdb_add_attribute(sample128_env.sample128_shdl, sizeof(uint8_t), //Data size = 1 ATT_UUID_128_LEN, (uint8_t*)&sample128_2_val.uuid, PERM(RD, ENABLE) | PERM(NTF, ENABLE), &(val_hdl)); memcpy(sample128_2_char.attr_hdl, &val_hdl, sizeof(uint16_t)); status = attmdb_att_set_value(char_hdl, sizeof(sample128_2_char), (uint8_t *)&sample128_2_char); //add cfg attribute status = attmdb_add_attribute(sample128_env.sample128_shdl, sizeof(uint16_t), ATT_UUID_16_LEN, (uint8_t*) &att_decl_cfg, PERM(RD, ENABLE) | PERM(WR, ENABLE), &(val_hdl)); //Disable sample128 service attmdb_svc_set_permission(sample128_env.sample128_shdl, PERM(SVC, DISABLE)); //Go to Idle State //If we are here, database has been fulfilled with success, go to idle state ke_state_set(TASK_SAMPLE128, SAMPLE128_IDLE); } //Send CFM to application struct sample128_create_db_cfm * cfm = KE_MSG_ALLOC(SAMPLE128_CREATE_DB_CFM, src_id, TASK_SAMPLE128, sample128_create_db_cfm); cfm->status = status; ke_msg_send(cfm); return (KE_MSG_CONSUMED); }
/** **************************************************************************************** * @brief Handles reception of the @ref GATT_WRITE_CMD_IND message. * The handler compares the new values with current ones and notifies them if they changed. * @param[in] msgid Id of the message received (probably unused). * @param[in] param Pointer to the parameters of the message. * @param[in] dest_id ID of the receiving task instance (probably unused). * @param[in] src_id ID of the sending task instance. * @return If the message was consumed or not. **************************************************************************************** */ static int gatt_write_cmd_ind_handler(ke_msg_id_t const msgid, struct gatt_write_cmd_ind const *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { uint8_t status = ATT_ERR_INSUFF_AUTHOR; // check connection if (param->conhdl == glps_env.con_info.conhdl) { uint8_t att_idx = GLPS_IDX(param->handle); status = PRF_ERR_OK; // check if it's a client configuration char if(glps_att_db[att_idx].uuid == ATT_DESC_CLIENT_CHAR_CFG) { uint16_t cli_cfg; uint8_t evt_mask = GLPS_IND_NTF_EVT(att_idx); // get client configuration cli_cfg = co_read16(&(param->value)); // stop indication/notification if(cli_cfg == PRF_CLI_STOP_NTFIND) { glps_env.evt_cfg &= ~evt_mask; } // start indication/notification (check that char value accept it) else if((((glps_att_db[att_idx-1].perm & PERM(IND, ENABLE)) != 0) && cli_cfg == PRF_CLI_START_IND) ||(((glps_att_db[att_idx-1].perm & PERM(NTF, ENABLE)) != 0) && cli_cfg == PRF_CLI_START_NTF)) { glps_env.evt_cfg |= evt_mask; } // improper value else { status = GLP_ERR_IMPROPER_CLI_CHAR_CFG; } if (status == PRF_ERR_OK) { //Inform APP of configuration change struct glps_cfg_indntf_ind * ind = KE_MSG_ALLOC(GLPS_CFG_INDNTF_IND, glps_env.con_info.appid, TASK_GLPS, glps_cfg_indntf_ind); //Update the attribute value attsdb_att_set_value(param->handle, sizeof(uint16_t), (uint8_t *)&cli_cfg); ind->conhdl = glps_env.con_info.conhdl; ind->evt_cfg = glps_env.evt_cfg; ke_msg_send(ind); } } else if (glps_att_db[att_idx].uuid == ATT_CHAR_REC_ACCESS_CTRL_PT) { uint8_t* value; uint16_t length; struct glp_racp_req racp_req; // If a request is on going if(GLPS_IS(RACP_ON_GOING)) { // if it's an abort command, execute it. if((param->offset == 0) && (param->value[0] == GLP_REQ_ABORT_OP)) { //forward abort operation to application struct glps_racp_req_ind * req = KE_MSG_ALLOC(GLPS_RACP_REQ_IND, glps_env.con_info.appid, TASK_GLPS, glps_racp_req_ind); req->conhdl = glps_env.con_info.conhdl; req->racp_req.op_code = GLP_REQ_ABORT_OP; req->racp_req.filter.operator = 0; ke_msg_send(req); } else { // do nothing since a procedure already in progress status = GLP_ERR_PROC_ALREADY_IN_PROGRESS; } } else { // Update the attribute value (note several write could be required since // attribute length > (ATT_MTU-3) attsdb_att_update_value(param->handle, param->length, param->offset, (uint8_t*)&(param->value[0])); // retrieve full data. attsdb_att_get_value(param->handle, &length, &value); // unpack record access control point value status = glps_unpack_racp_req(value, length, &racp_req); // check unpacked status switch(status) { case PRF_APP_ERROR: { /* Do nothing, ignore request since it's not complete and maybe * requires several peer write to be performed. */ } break; case PRF_ERR_OK: { // check wich request shall be send to api task switch(racp_req.op_code) { case GLP_REQ_REP_STRD_RECS: case GLP_REQ_DEL_STRD_RECS: case GLP_REQ_REP_NUM_OF_STRD_RECS: { if((glps_env.evt_cfg & GLPS_RACP_IND_CFG) != 0) { //forward request operation to application struct glps_racp_req_ind * req = KE_MSG_ALLOC(GLPS_RACP_REQ_IND, glps_env.con_info.appid, TASK_GLPS, glps_racp_req_ind); // RACP on going. GLPS_SET(RACP_ON_GOING); req->conhdl = glps_env.con_info.conhdl; req->racp_req = racp_req; ke_msg_send(req); } else { status = PRF_CCCD_IMPR_CONFIGURED; } } break; case GLP_REQ_ABORT_OP: { // nothing to abort, send an error message. struct glp_racp_rsp racp_rsp; racp_rsp.op_code = GLP_REQ_RSP_CODE; racp_rsp.operand.rsp.op_code_req = racp_req.op_code; racp_rsp.operand.rsp.status = GLP_RSP_ABORT_UNSUCCESSFUL; // send record access control response indication glps_send_racp_rsp(&(racp_rsp), TASK_GLPS); } break; default: { // nothing to do since it's handled during unpack } break; } } break; default: { /* There is an error in record access control request, inform peer * device that request is incorrect. */ struct glp_racp_rsp racp_rsp; racp_rsp.op_code = GLP_REQ_RSP_CODE; racp_rsp.operand.rsp.op_code_req = racp_req.op_code; racp_rsp.operand.rsp.status = status; // send record access control response indication glps_send_racp_rsp(&(racp_rsp), TASK_GLPS); } break; } } } // not expected request else { status = ATT_ERR_WRITE_NOT_PERMITTED; } } if(param->response) { //Send write response atts_write_rsp_send(param->conhdl, param->handle, status); } return (KE_MSG_CONSUMED); }
/** **************************************************************************************** * @brief Handles reception of the @ref GLPS_MEAS_SEND_REQ message. * @param[in] msgid Id of the message received (probably unused). * @param[in] param Pointer to the parameters of the message. * @param[in] dest_id ID of the receiving task instance (probably unused). * @param[in] src_id ID of the sending task instance. * @return If the message was consumed or not. **************************************************************************************** */ static int glps_meas_send_req_handler(ke_msg_id_t const msgid, struct glps_send_meas_with_ctx_req const *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { uint8_t status = PRF_ERR_OK; if(param->conhdl == glps_env.con_info.conhdl) { // device already sending a measurement if(GLPS_IS(SENDING_MEAS)) { //Cannot send another measurement in parallel status = (PRF_ERR_REQ_DISALLOWED); } else { // inform that device is sending a measurement GLPS_SET(SENDING_MEAS); // check if context is supported if((msgid == GLPS_SEND_MEAS_WITH_CTX_REQ) && !(GLPS_IS(MEAS_CTX_SUPPORTED))) { // Context not supported status = (PRF_ERR_FEATURE_NOT_SUPPORTED); } // check if notifications enabled else if(((glps_env.evt_cfg & GLPS_MEAS_NTF_CFG) == 0) || (((glps_env.evt_cfg & GLPS_MEAS_CTX_NTF_CFG) == 0) && (msgid == GLPS_SEND_MEAS_WITH_CTX_REQ))) { // Not allowed to send measurement if Notifications not enabled. status = (PRF_ERR_NTF_DISABLED); } else { struct atts_elmt * att_elmt; struct gatt_notify_req * ntf = KE_MSG_ALLOC(GATT_NOTIFY_REQ, TASK_GATT, TASK_GLPS, gatt_notify_req); // retrieve value pointer in database att_elmt = attsdb_get_attribute(GLPS_HANDLE(GLS_IDX_MEAS_VAL)); // pack measured value in database att_elmt->length = glps_pack_meas_value(att_elmt->value, &(param->meas), param->seq_num); //Send notification through GATT ntf->conhdl = glps_env.con_info.conhdl; ntf->charhdl = GLPS_HANDLE(GLS_IDX_MEAS_VAL); ke_msg_send(ntf); if(msgid == GLPS_SEND_MEAS_WITH_CTX_REQ) { // 2 notification complete messages expected GLPS_SET(MEAS_CTX_SENT); // retrieve value pointer in database att_elmt = attsdb_get_attribute(GLPS_HANDLE(GLS_IDX_MEAS_CTX_VAL)); // pack measured value in database att_elmt->length = glps_pack_meas_ctx_value(att_elmt->value, &(param->ctx), param->seq_num); ntf = KE_MSG_ALLOC(GATT_NOTIFY_REQ, TASK_GATT, TASK_GLPS, gatt_notify_req); //Send notification through GATT ntf->conhdl = glps_env.con_info.conhdl; ntf->charhdl = GLPS_HANDLE(GLS_IDX_MEAS_CTX_VAL); ke_msg_send(ntf); } else { // 1 notification complete messages expected GLPS_CLEAR(MEAS_CTX_SENT); } } } } else { //Wrong Connection Handle status = (PRF_ERR_INVALID_PARAM); } // send command complete if an error occurs if(status != PRF_ERR_OK) { // allow to send other measurements GLPS_CLEAR(SENDING_MEAS); // send completed information to APP task that contains error status struct glps_req_cmp_evt * cmp_evt = KE_MSG_ALLOC(GLPS_REQ_CMP_EVT, glps_env.con_info.appid, TASK_GLPS, glps_req_cmp_evt); cmp_evt->conhdl = param->conhdl; cmp_evt->request = GLPS_SEND_MEAS_REQ_NTF_CMP; cmp_evt->status = status; ke_msg_send(cmp_evt); } return (KE_MSG_CONSUMED); }
/** **************************************************************************************** * @brief Handles reception of the @ref GATTC_CMP_EVT message. * This generic event is received for different requests, so need to keep track. * @param[in] msgid Id of the message received (probably unused). * @param[in] param Pointer to the parameters of the message. * @param[in] dest_id ID of the receiving task instance (probably unused). * @param[in] src_id ID of the sending task instance. * @return If the message was consumed or not. **************************************************************************************** */ static int gattc_cmp_evt_handler(ke_msg_id_t const msgid, struct gattc_cmp_evt const *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { uint8_t state = ke_state_get(dest_id); uint8_t status; // Get the address of the environment struct tipc_env_tag *tipc_env = PRF_CLIENT_GET_ENV(dest_id, tipc); if(state == TIPC_DISCOVERING) { if ((param->status == ATT_ERR_ATTRIBUTE_NOT_FOUND)|| (param->status == ATT_ERR_NO_ERROR)) { // Currently Discovering Current Time service characteristics. if(tipc_env->last_svc_req == ATT_SVC_CURRENT_TIME) { // service start/end handles has been received if(tipc_env->last_uuid_req == ATT_SVC_CURRENT_TIME) { // check if service handles are not ok if (tipc_env->cts.svc.shdl == ATT_INVALID_HANDLE) { // stop discovery procedure. tipc_enable_cfm_send(tipc_env, &tipc_env->con_info, PRF_ERR_STOP_DISC_CHAR_MISSING); } //too many services found only one such service should exist else if(tipc_env->nb_svc != 1) { // stop discovery procedure. tipc_enable_cfm_send(tipc_env, &tipc_env->con_info, PRF_ERR_MULTIPLE_SVC); } // check if service handles are ok else { //discover all CTS characteristics prf_disc_char_all_send(&(tipc_env->con_info), &(tipc_env->cts.svc)); tipc_env->last_uuid_req = ATT_DECL_CHARACTERISTIC; } } else if(tipc_env->last_uuid_req == ATT_DECL_CHARACTERISTIC) { status = prf_check_svc_char_validity(TIPC_CHAR_CTS_MAX, tipc_env->cts.chars, tipc_cts_char); // check for characteristic properties. if(status == PRF_ERR_OK) { tipc_env->last_uuid_req = ATT_INVALID_HANDLE; tipc_env->last_char_code = TIPC_CHAR_CTS_CURR_TIME; //request all service characteristic description for CTS prf_disc_char_desc_send(&(tipc_env->con_info), &(tipc_env->cts.chars[TIPC_CHAR_CTS_CURR_TIME])); } else { // stop discovery procedure. tipc_enable_cfm_send(tipc_env, &tipc_env->con_info, status); } } else { status = prf_check_svc_char_desc_validity(TIPC_DESC_CTS_MAX, tipc_env->cts.descs, tipc_cts_char_desc, tipc_env->cts.chars); if(status == PRF_ERR_OK) { // reset number of services tipc_env->nb_svc = 0; //start discovering NDCS on peer prf_disc_svc_send(&(tipc_env->con_info), ATT_SVC_NEXT_DST_CHANGE); tipc_env->last_uuid_req = ATT_SVC_NEXT_DST_CHANGE; tipc_env->last_svc_req = ATT_SVC_NEXT_DST_CHANGE; } else { // stop discovery procedure. tipc_enable_cfm_send(tipc_env, &tipc_env->con_info, status); } } } // Currently Next DST Change service characteristics. else if(tipc_env->last_svc_req == ATT_SVC_NEXT_DST_CHANGE) { // service start/end handles has been received if(tipc_env->last_uuid_req == ATT_SVC_NEXT_DST_CHANGE) { if (tipc_env->ndcs.svc.shdl == ATT_INVALID_HANDLE) { // reset number of services tipc_env->nb_svc = 0; //start discovering RTUS on peer prf_disc_svc_send(&(tipc_env->con_info), ATT_SVC_REF_TIME_UPDATE); tipc_env->last_uuid_req = ATT_SVC_REF_TIME_UPDATE; tipc_env->last_svc_req = ATT_SVC_REF_TIME_UPDATE; } //too many services found only one such service should exist else if(tipc_env->nb_svc != 1) { // stop discovery procedure. tipc_enable_cfm_send(tipc_env, &tipc_env->con_info, PRF_ERR_MULTIPLE_SVC); } // check if service handles are ok else { //discover all NDCS characteristics prf_disc_char_all_send(&(tipc_env->con_info), &(tipc_env->ndcs.svc)); tipc_env->last_uuid_req = ATT_DECL_CHARACTERISTIC; } } else if(tipc_env->last_uuid_req == ATT_DECL_CHARACTERISTIC) { status = prf_check_svc_char_validity(TIPC_CHAR_NDCS_MAX, tipc_env->ndcs.chars, tipc_ndcs_char); // check for characteristic properties. if(status == PRF_ERR_OK) { // reset number of services tipc_env->nb_svc = 0; //start discovering RTUS on peer prf_disc_svc_send(&(tipc_env->con_info), ATT_SVC_REF_TIME_UPDATE); tipc_env->last_uuid_req = ATT_SVC_REF_TIME_UPDATE; tipc_env->last_svc_req = ATT_SVC_REF_TIME_UPDATE; } else { // stop discovery procedure. tipc_enable_cfm_send(tipc_env, &tipc_env->con_info, status); } } } // Currently Reference Time Update service characteristics. else if(tipc_env->last_svc_req == ATT_SVC_REF_TIME_UPDATE) { // service start/end handles has been received if(tipc_env->last_uuid_req == ATT_SVC_REF_TIME_UPDATE) { if (tipc_env->rtus.svc.shdl == ATT_INVALID_HANDLE) { // send app the details about the discovered TIPS DB to save tipc_enable_cfm_send(tipc_env, &tipc_env->con_info, PRF_ERR_OK); } //too many services found only one such service should exist else if(tipc_env->nb_svc != 1) { // stop discovery procedure. tipc_enable_cfm_send(tipc_env, &tipc_env->con_info, PRF_ERR_MULTIPLE_SVC); } // check if service handles are ok else { //discover all RTUS characteristics prf_disc_char_all_send(&(tipc_env->con_info), &(tipc_env->rtus.svc)); tipc_env->last_uuid_req = ATT_DECL_CHARACTERISTIC; } } else if(tipc_env->last_uuid_req == ATT_DECL_CHARACTERISTIC) { status = prf_check_svc_char_validity(TIPC_CHAR_RTUS_MAX, tipc_env->rtus.chars, tipc_rtus_char); // check for characteristic properties. if(status == PRF_ERR_OK) { // send app the details about the discovered TIPS DB to save tipc_enable_cfm_send(tipc_env, &tipc_env->con_info, PRF_ERR_OK); } else { // stop discovery procedure. tipc_enable_cfm_send(tipc_env, &tipc_env->con_info, status); } } } } } else if(state == TIPC_CONNECTED) { switch(param->req_type) { case GATTC_WRITE: case GATTC_WRITE_NO_RESPONSE: { struct tipc_wr_char_rsp *wr_cfm = KE_MSG_ALLOC(TIPC_WR_CHAR_RSP, tipc_env->con_info.appid, dest_id, tipc_wr_char_rsp); wr_cfm->conhdl = gapc_get_conhdl(tipc_env->con_info.conidx); //it will be a GATT status code wr_cfm->status = param->status; // send the message ke_msg_send(wr_cfm); } break; case GATTC_READ: { // an error occurs while reading peer attribute, inform app if(param->status != GATT_ERR_NO_ERROR) { tipc_error_ind_send(tipc_env, param->status); } } break; default: break; } } return (KE_MSG_CONSUMED); }
/** **************************************************************************************** * @brief Handles reception of the @ref BEACON_CREATE_DB_REQ message. * The handler adds BAS into the database using value of the features param. * @param[in] msgid Id of the message received (probably unused). * @param[in] param Pointer to the parameters of the message. * @param[in] dest_id ID of the receiving task instance (probably unused). * @param[in] src_id ID of the sending task instance. * @return If the message was consumed or not. **************************************************************************************** */ static int beacon_create_db_req_handler(ke_msg_id_t const msgid, struct beacon_create_db_req const *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { // Service content flag uint8_t cfg_flag = BEACON_CFG_FLAG_MANDATORY_MASK; // Status uint8_t status = PRF_ERR_OK; // // Counter // uint8_t i; // // Battery Level characteristic value permissions // uint16_t perm; // // Battery Level characteristic value properties // uint8_t prop; // Save profile id beacon_env.con_info.prf_id = TASK_BEACON; //beacon_env.features = param->features; status = atts_svc_create_db(&beacon_env.shdl, (uint8_t *)&cfg_flag, BEACON_IDX_NB, NULL,dest_id, &beacon_att_db[0]); //Disable service status = attsdb_svc_set_permission(beacon_env.shdl, PERM(SVC, DISABLE)); //Go to Idle State if (status == ATT_ERR_NO_ERROR) { //If we are here, database has been fulfilled with success, go to idle test ke_state_set(TASK_BEACON, BEACON_IDLE); } //Send response to application struct beacon_create_db_cfm * cfm = KE_MSG_ALLOC(BEACON_CREATE_DB_CFM, beacon_env.con_info.appid, TASK_BEACON, beacon_create_db_cfm); cfm->status = status; ke_msg_send(cfm); // // Check number of BAS instances // if (param->bas_nb <= BASS_NB_BAS_INSTANCES_MAX) // { // // Save number of BAS // bass_env.bas_nb = param->bas_nb; // for (i = 0; ((i < param->bas_nb) && (status == PRF_ERR_OK)); i++) // { // // Save database configuration // bass_env.features[i] = param->features[i]; // // Check if notifications are supported // if (bass_env.features[i] == BAS_BATT_LVL_NTF_SUP) // { // cfg_flag |= BAS_CFG_FLAG_NTF_SUP_MASK; // } // // Check if multiple instances // if (bass_env.bas_nb > 1) // { // cfg_flag |= BAS_CFG_FLAG_MTP_BAS_MASK; // } // //Create BAS in the DB // status = atts_svc_create_db(&bass_env.shdl[i], (uint8_t *)&cfg_flag, BAS_IDX_NB, NULL, // dest_id, &bas_att_db[0]); // //Disable the service and set optional features // if (status == PRF_ERR_OK) // { // //Disable service // status = attsdb_svc_set_permission(bass_env.shdl[i], PERM(SVC, DISABLE)); // //Set optional properties and permissions // if (bass_env.features[i] == BAS_BATT_LVL_NTF_SUP) // { // prop = ATT_CHAR_PROP_RD | ATT_CHAR_PROP_NTF; // perm = PERM(RD, ENABLE) | PERM(NTF, ENABLE); // attsdb_att_partial_value_update(bass_env.shdl[i] + BAS_IDX_BATT_LVL_CHAR, 0, 1, &prop); // attsdb_att_set_permission(bass_env.shdl[i] + BAS_IDX_BATT_LVL_VAL, perm); // } // } // // Reset configuration flag // cfg_flag = BAS_CFG_FLAG_MANDATORY_MASK; // } // if (status == PRF_ERR_OK) // { // //If we are here, database has been fulfilled with success, go to idle state // ke_state_set(TASK_BASS, BASS_IDLE); // } // } // else // { // status = PRF_ERR_INVALID_PARAM; // } // // Send confirmation to application // struct bass_create_db_cfm * cfm = KE_MSG_ALLOC(BASS_CREATE_DB_CFM, src_id, TASK_BASS, // bass_create_db_cfm); // cfm->status = status; // ke_msg_send(cfm); return (KE_MSG_CONSUMED); }
/** **************************************************************************************** * @brief Handles reception of the @ref GATT_HANDLE_VALUE_IND message. * @param[in] msgid Id of the message received (probably unused). * @param[in] param Pointer to the parameters of the message. * @param[in] dest_id ID of the receiving task instance (probably unused). * @param[in] src_id ID of the sending task instance. * @return If the message was consumed or not. **************************************************************************************** */ static int gatt_handle_value_ind_handler(ke_msg_id_t const msgid, struct gatt_handle_value_ind const *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { // Get the address of the environment struct cscpc_env_tag *cscpc_env = PRF_CLIENT_GET_ENV(dest_id, cscpc); if (cscpc_env != NULL) { // Check if we were waiting for the indication if (cscpc_env->operation != NULL) { if (((struct cscpc_cmd *)cscpc_env->operation)->operation == CSCPC_CTNL_PT_CFG_IND_OP_CODE) { // Stop the procedure timeout timer ke_timer_clear(CSCPC_TIMEOUT_TIMER_IND, dest_id); // CSC Measurement value has been received struct cscpc_value_ind *ind = KE_MSG_ALLOC(CSCPC_VALUE_IND, cscpc_env->con_info.appid, cscpc_env->con_info.prf_id, cscpc_value_ind); // Connection Handle ind->conhdl = param->conhdl; // Attribute code ind->att_code = CSCPC_IND_SC_CTNL_PT; // Requested operation code ind->value.ctnl_pt_rsp.req_op_code = param->value[1]; // Response value ind->value.ctnl_pt_rsp.resp_value = param->value[2]; // Get the list of supported sensor locations if needed if ((ind->value.ctnl_pt_rsp.req_op_code == CSCP_CTNL_PT_OP_REQ_SUPP_LOC) && (ind->value.ctnl_pt_rsp.resp_value == CSCP_CTNL_PT_RESP_SUCCESS) && (param->size > 3)) { // Get the number of supported locations that have been received uint8_t nb_supp_loc = (param->size - 3); // Counter uint8_t counter; // Location uint8_t loc; for (counter = 0; counter < nb_supp_loc; counter++) { loc = param->value[counter + 3]; // Check if valid if (loc < CSCP_LOC_MAX) { ind->value.ctnl_pt_rsp.supp_loc |= (1 << loc); } } } // Send the message ke_msg_send(ind); // Send the complete event message cscpc_send_cmp_evt(cscpc_env, CSCPC_CTNL_PT_CFG_WR_OP_CODE, PRF_ERR_OK); } // else drop the message } // else drop the message } // else ignore the message return (KE_MSG_CONSUMED); }
/** **************************************************************************************** * @brief Handles reception of the @ref GATTC_READ_IND message. * Generic event received after every simple read command sent to peer server. * @param[in] msgid Id of the message received (probably unused). * @param[in] param Pointer to the parameters of the message. * @param[in] dest_id ID of the receiving task instance (probably unused). * @param[in] src_id ID of the sending task instance. * @return If the message was consumed or not. **************************************************************************************** */ static int gattc_read_ind_handler(ke_msg_id_t const msgid, struct gattc_read_ind const *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { // Get the address of the environment struct tipc_env_tag *tipc_env = PRF_CLIENT_GET_ENV(dest_id, tipc); //Current Time Characteristic if (tipc_env->last_char_code == TIPC_RD_CTS_CURR_TIME) { //Build a TIPC_CT_IND message struct tipc_ct_ind * ind = KE_MSG_ALLOC(TIPC_CT_IND, tipc_env->con_info.appid, dest_id, tipc_ct_ind); // retrieve connection handle ind->conhdl = gapc_get_conhdl(tipc_env->con_info.conidx); // Unpack Current Time Value. tipc_unpack_curr_time_value(&(ind->ct_val), (uint8_t*) &(param->value[0])); //Indication Type ind->ind_type = TIP_RD_RSP, ke_msg_send(ind); } //Local Time Information Characteristic else if (tipc_env->last_char_code == TIPC_RD_CTS_LOCAL_TIME_INFO) { //Build a TIPC_LTI_RD_RSP message struct tipc_lti_rd_rsp * rsp = KE_MSG_ALLOC(TIPC_LTI_RD_RSP, tipc_env->con_info.appid, dest_id, tipc_lti_rd_rsp); // Retrieve Connection handle rsp->conhdl = gapc_get_conhdl(tipc_env->con_info.conidx); // Local Time Information Value rsp->lti_val.time_zone = param->value[0]; rsp->lti_val.dst_offset = param->value[1]; ke_msg_send(rsp); } //Reference Time Information Characteristic else if (tipc_env->last_char_code == TIPC_RD_CTS_REF_TIME_INFO) { //Build a TIPC_RTI_RD_RSP message struct tipc_rti_rd_rsp * rsp = KE_MSG_ALLOC(TIPC_RTI_RD_RSP, tipc_env->con_info.appid, dest_id, tipc_rti_rd_rsp); // Retrieve Connection handle rsp->conhdl = gapc_get_conhdl(tipc_env->con_info.conidx); // Reference Time Information Value rsp->rti_val.time_source = param->value[0]; rsp->rti_val.time_accuracy = param->value[1]; rsp->rti_val.days_update = param->value[2]; rsp->rti_val.hours_update = param->value[3]; ke_msg_send(rsp); } //Time with DST Characteristic else if (tipc_env->last_char_code == TIPC_RD_NDCS_TIME_WITH_DST) { //Build a TIPC_TDST_RD_RSP message struct tipc_tdst_rd_rsp * rsp = KE_MSG_ALLOC(TIPC_TDST_RD_RSP, tipc_env->con_info.appid, dest_id, tipc_tdst_rd_rsp); // Retrieve Connection handle rsp->conhdl = gapc_get_conhdl(tipc_env->con_info.conidx); // Time with DST Value prf_unpack_date_time((uint8_t*) &(param->value[0]), &(rsp->tdst_val.date_time)); rsp->tdst_val.dst_offset = param->value[7]; ke_msg_send(rsp); } //Time Update State Characteristic else if (tipc_env->last_char_code == TIPC_RD_RTUS_TIME_UPD_STATE) { //Build a TIPC_TUS_RD_RSP message struct tipc_tus_rd_rsp * rsp = KE_MSG_ALLOC(TIPC_TUS_RD_RSP, tipc_env->con_info.appid, dest_id, tipc_tus_rd_rsp); // Retrieve Connection handle rsp->conhdl = gapc_get_conhdl(tipc_env->con_info.conidx); // Reference Time Information Value rsp->tus_val.current_state = param->value[0]; rsp->tus_val.result = param->value[1]; ke_msg_send(rsp); } //Current Time Characteristic - Client Characteristic Configuration Descriptor else if (tipc_env->last_char_code == TIPC_RD_CTS_CURR_TIME_CLI_CFG) { //Build a TIPC_CT_NTF_CFG_RD_RSP message struct tipc_ct_ntf_cfg_rd_rsp * rsp = KE_MSG_ALLOC(TIPC_CT_NTF_CFG_RD_RSP, tipc_env->con_info.appid, dest_id, tipc_ct_ntf_cfg_rd_rsp); // Retrieve Connection handle rsp->conhdl = gapc_get_conhdl(tipc_env->con_info.conidx); // Notification Configuration memcpy(&rsp->ntf_cfg, ¶m->value[0], sizeof(rsp->ntf_cfg)); ke_msg_send(rsp); } return (KE_MSG_CONSUMED); }
/** **************************************************************************************** * @brief Handles reception of the @ref GATT_CMP_EVT message. * @param[in] msgid Id of the message received. * @param[in] param Pointer to the parameters of the message. * @param[in] dest_id ID of the receiving task instance. * @param[in] src_id ID of the sending task instance. * @return If the message was consumed or not. **************************************************************************************** */ static int gatt_cmp_evt_handler(ke_msg_id_t const msgid, struct gatt_cmp_evt const *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { // Get the address of the environment struct cscpc_env_tag *cscpc_env = PRF_CLIENT_GET_ENV(dest_id, cscpc); if (cscpc_env != NULL) { // Status uint8_t status = PRF_ERR_STOP_DISC_CHAR_MISSING; ASSERT_ERR(cscpc_env->operation != NULL); ASSERT_ERR(((struct cscpc_cmd *)cscpc_env->operation)->operation == CSCPC_ENABLE_OP_CODE); if ((param->status == ATT_ERR_ATTRIBUTE_NOT_FOUND) || (param->status == ATT_ERR_NO_ERROR)) { /* ------------------------------------------------- * SERVICE DISCOVERY ------------------------------- * ------------------------------------------------- */ if (cscpc_env->last_req == ATT_SVC_CYCLING_SPEED_CADENCE) { if (cscpc_env->nb_svc > 0) { // Check if service handles are OK if ((cscpc_env->cscs.svc.shdl != ATT_INVALID_HANDLE) && (cscpc_env->cscs.svc.ehdl != ATT_INVALID_HANDLE) && (cscpc_env->cscs.svc.shdl < cscpc_env->cscs.svc.ehdl)) { // Status is OK status = PRF_ERR_OK; // Discover all CSCS characteristics cscpc_env->last_req = ATT_DECL_CHARACTERISTIC; prf_disc_char_all_send(&(cscpc_env->con_info), &(cscpc_env->cscs.svc)); } // Handles are not corrects, the Cycling Speed and Cadence Service has not been found, stop } // The Cycling Speed and Cadence Service has not been found, stop discovery } /* ------------------------------------------------- * CHARACTERISTICS DISCOVERY ----------------------- * ------------------------------------------------- */ else if (cscpc_env->last_req == ATT_DECL_CHARACTERISTIC) { // Check if mandatory properties have been found and if properties are correct status = prf_check_svc_char_validity(CSCP_CSCS_CHAR_MAX, cscpc_env->cscs.chars, cscpc_cscs_char); // Check for characteristic properties. if (status == PRF_ERR_OK) { cscpc_env->last_req = CSCP_CSCS_CSC_MEAS_CHAR; // Find the Client Characteristic Configuration Descriptor for the CSC Measurement characteristic prf_disc_char_desc_send(&(cscpc_env->con_info), &(cscpc_env->cscs.chars[CSCP_CSCS_CSC_MEAS_CHAR])); } } /* ------------------------------------------------- * DESCRIPTORS DISCOVERY --------------------------- * ------------------------------------------------- */ else { // Discovery over ? bool disc_over = true; if (cscpc_env->last_req == CSCP_CSCS_CSC_MEAS_CHAR) { // Check if the SC Control Point Characteristic has been found if (cscpc_env->cscs.chars[CSCP_CSCS_SC_CTNL_PT_CHAR].char_hdl != ATT_INVALID_SEARCH_HANDLE) { // Status is OK status = PRF_ERR_OK; // Find the Client Characteristic Configuration Descriptor for the SC Control Point characteristic cscpc_env->last_req = CSCP_CSCS_SC_CTNL_PT_CHAR; prf_disc_char_desc_send(&(cscpc_env->con_info), &(cscpc_env->cscs.chars[CSCP_CSCS_SC_CTNL_PT_CHAR])); // Discovery continues disc_over = false; } } else { // Discovery is over ASSERT_ERR(cscpc_env->last_req == CSCP_CSCS_SC_CTNL_PT_CHAR); } if (disc_over) { status = prf_check_svc_char_desc_validity(CSCPC_DESC_MAX, cscpc_env->cscs.descs, cscpc_cscs_char_desc, cscpc_env->cscs.chars); if (status == PRF_ERR_OK) { // Reset number of services cscpc_env->nb_svc = 0; // Register in GATT for notifications/indications prf_register_atthdl2gatt(&cscpc_env->con_info, &cscpc_env->cscs.svc); // Send the content of the service to the HL struct cscpc_cscs_content_ind *ind = KE_MSG_ALLOC(CSCPC_CSCS_CONTENT_IND, cscpc_env->con_info.appid, cscpc_env->con_info.prf_id, cscpc_cscs_content_ind); ind->conhdl = cscpc_env->con_info.conhdl; memcpy(&ind->cscs, &cscpc_env->cscs, sizeof(struct cscpc_cscs_content)); // Send the message ke_msg_send(ind); // Stop discovery procedure. cscpc_send_cmp_evt(cscpc_env, CSCPC_ENABLE_OP_CODE, status); } } } } else { status = param->status; } if (status != PRF_ERR_OK) { // Stop discovery procedure. cscpc_send_cmp_evt(cscpc_env, CSCPC_ENABLE_OP_CODE, status); } } // else ignore the message return (KE_MSG_CONSUMED); }