void bass_disable(void) { // Counter uint8_t i; // Information get in the DB atts_size_t att_length; uint8_t *att_value; // Send current configuration to the application struct bass_disable_ind *ind = KE_MSG_ALLOC(BASS_DISABLE_IND, bass_env.con_info.appid, TASK_BASS, bass_disable_ind); ind->conhdl = bass_env.con_info.conhdl; for (i = 0; i < bass_env.bas_nb; i++) { if((bass_env.features[i] & BASS_FLAG_NTF_CFG_BIT) == BASS_FLAG_NTF_CFG_BIT) { ind->batt_level_ntf_cfg[i] = PRF_CLI_START_NTF; // Reset ntf cfg bit in features bass_env.features[i] &= ~BASS_FLAG_NTF_CFG_BIT; } else { ind->batt_level_ntf_cfg[i] = PRF_CLI_STOP_NTFIND; } // Get Battery Level value attsdb_att_get_value(bass_env.shdl[i] + BAS_IDX_BATT_LVL_VAL, &att_length, &att_value); ind->batt_lvl[i] = *att_value; } ke_msg_send(ind); // Go to idle state ke_state_set(TASK_BASS, BASS_IDLE); }
/** **************************************************************************************** * @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 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 = PRF_ERR_OK; if (param->conhdl == qpps_env.conhdl) { // Client Char. Configuration uint8_t char_index = param->handle - (qpps_env.shdl + QPPS_IDX_VAL_NTF_CFG); if ((param->handle > (qpps_env.shdl + QPPS_IDX_VAL_CHAR)) && ((char_index % 3) == 0)) { uint16_t value = 0x0000; //Extract value before check memcpy(&value, &(param->value), sizeof(uint16_t)); if ((value == PRF_CLI_STOP_NTFIND) || (value == PRF_CLI_START_NTF)) { if (value == PRF_CLI_STOP_NTFIND) { qpps_env.features &= ~(QPPS_VALUE_NTF_CFG << (char_index / 3)); } else //PRF_CLI_START_NTF { qpps_env.features |= QPPS_VALUE_NTF_CFG << (char_index / 3); } } else { status = PRF_APP_ERROR; } if (status == PRF_ERR_OK) { uint8_t *old_value; atts_size_t length; attsdb_att_get_value(param->handle, &length, &old_value); if (value != co_read16p(old_value)) { //Update the attribute value attsdb_att_set_value(param->handle, sizeof(uint16_t), (uint8_t *)&value); if(param->last) { //Inform APP of configuration change struct qpps_cfg_indntf_ind * ind = KE_MSG_ALLOC(QPPS_CFG_INDNTF_IND, qpps_env.appid, TASK_QPPS, qpps_cfg_indntf_ind); ind->char_index = (char_index / 3); memcpy(&ind->cfg_val, &value, sizeof(uint16_t)); ke_msg_send(ind); } } } } else if (param->handle == (qpps_env.shdl + QPPS_IDX_RX_DATA_VAL)) { if (param->length <= QPP_DATA_MAX_LEN) { //inform APP of configuration change struct qpps_data_val_ind * ind = KE_MSG_ALLOC_DYN(QPPS_DAVA_VAL_IND, qpps_env.appid, TASK_QPPS, qpps_data_val_ind, param->length); memcpy(&ind->conhdl, &(qpps_env.conhdl), sizeof(uint16_t)); //Send received data to app value ind->length = param->length; memcpy(ind->data, param->value, param->length); ke_msg_send(ind); } else { status = QPPS_ERR_RX_DATA_EXCEED_MAX_LENGTH; } } else { status = QPPS_ERR_INVALID_PARAM; } } if (param->response) { //Send write response atts_write_rsp_send(qpps_env.conhdl, param->handle, status); } return (KE_MSG_CONSUMED); }