/** **************************************************************************************** * @brief Handles @ref GATTC_CMP_EVT for GATTC_NOTIFY and GATT_INDICATE message meaning * that Measurement notification/indication has been correctly sent to peer device * * * @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 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) { switch(param->req_type) { case GATTC_NOTIFY: { /* send message indication if an error occurs, * or if all notification complete event has been received */ if((param->status != PRF_ERR_OK) || (!(GLPS_IS(MEAS_CTX_SENT))) || (GLPS_IS(MEAS_CTX_SENT) && (GLPS_IS(MEAS_SENT)))) { GLPS_CLEAR(SENDING_MEAS); // send completed information to APP task 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 = gapc_get_conhdl(glps_env.con_info.conidx); cmp_evt->request = GLPS_SEND_MEAS_REQ_NTF_CMP; cmp_evt->status = param->status; ke_msg_send(cmp_evt); } else { // Measurement value notification sent GLPS_SET(MEAS_SENT); } } break; case GATTC_INDICATE: { // verify if indication should be conveyed to application task if(glps_env.racp_ind_src == glps_env.con_info.appid) { // send completed information to APP task 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 = gapc_get_conhdl(glps_env.con_info.conidx); cmp_evt->request = GLPS_SEND_RACP_RSP_IND_CMP; cmp_evt->status = param->status; ke_msg_send(cmp_evt); } } break; default: break; } return (KE_MSG_CONSUMED); }
/** **************************************************************************************** * @brief Handles reception of the @ref GLPS_CREATE_DB_REQ message. * The handler adds GLS into the database using the database * configuration value given in 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 glps_create_db_req_handler(ke_msg_id_t const msgid, struct glps_create_db_req const *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { //Service Configuration Flag uint16_t cfg_flag = GLPS_MANDATORY_MASK; //Database Creation Status uint8_t status; //Save Profile ID glps_env.con_info.prf_id = TASK_GLPS; //Save Database Configuration if(param->meas_ctx_supported) { GLPS_SET(MEAS_CTX_SUPPORTED); } // set start handle or automatically set it when creating database (start_hdl = 0) glps_env.shdl=param->start_hdl; /*---------------------------------------------------* * Glucose Service Creation *---------------------------------------------------*/ //Set Configuration Flag Value if (GLPS_IS(MEAS_CTX_SUPPORTED)) { cfg_flag |= GLPS_MEAS_CTX_PRES_MASK; } //Add Service Into Database status = atts_svc_create_db(&glps_env.shdl, (uint8_t *)&cfg_flag, GLS_IDX_NB, NULL, dest_id, &glps_att_db[0]); //Disable GLS attsdb_svc_set_permission(glps_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_GLPS, GLPS_IDLE); } //Send response to application struct glps_create_db_cfm * cfm = KE_MSG_ALLOC(GLPS_CREATE_DB_CFM, src_id, TASK_GLPS, glps_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 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); }