uint8_t glpc_unpack_meas_value(uint8_t *packed_meas, struct glp_meas* meas_val, uint16_t *seq_num) { uint8_t cursor = 0; // Flags meas_val->flags = packed_meas[cursor]; cursor += 1; // Sequence Number *seq_num = co_read16p(packed_meas + cursor); cursor += 2; // Base Time cursor += prf_unpack_date_time(packed_meas + cursor, &(meas_val->base_time)); //Time Offset if((meas_val->flags & GLP_MEAS_TIME_OFF_PRES) != 0) { meas_val->time_offset = co_read16p(packed_meas + cursor); cursor += 2; } // Glucose Concentration, type and location if((meas_val->flags & GLP_MEAS_GL_CTR_TYPE_AND_SPL_LOC_PRES) != 0) { meas_val->concentration = co_read16p(packed_meas + cursor); cursor += 2; /* type and location are 2 nibble values */ meas_val->type = packed_meas[cursor] >> 4; meas_val->location = packed_meas[cursor] & 0xF; cursor += 1; }
void prf_unpack_char_pres_fmt(const uint8_t *packed_val, struct prf_char_pres_fmt* char_pres_fmt) { char_pres_fmt->format = *packed_val; char_pres_fmt->exponent = *(packed_val + 1); char_pres_fmt->unit = co_read16p(packed_val + 2); char_pres_fmt->name_space = *(packed_val + 4); char_pres_fmt->description = co_read16p(packed_val + 5); }
void blpc_unpack_meas_value(struct bps_bp_meas* pmeas_val, uint8_t* packed_bp) { uint8_t cursor; // blood pressure measurement flags pmeas_val->flags = packed_bp[0]; // Blood Pressure Measurement Compound Value - Systolic pmeas_val->systolic = co_read16p(&(packed_bp[1])); // Blood Pressure Measurement Compound Value - Diastolic (mmHg) pmeas_val->diastolic = co_read16p(&(packed_bp[3])); // Blood Pressure Measurement Compound Value - Mean Arterial Pressure (mmHg) pmeas_val->mean_arterial_pressure = co_read16p(&(packed_bp[5])); cursor = 7; // time flag set if ((pmeas_val->flags & BPS_FLAG_TIME_STAMP_PRESENT) == BPS_FLAG_TIME_STAMP_PRESENT) { cursor += prf_unpack_date_time(packed_bp + cursor, &(pmeas_val->time_stamp)); } // pulse rate flag set if ((pmeas_val->flags & BPS_FLAG_PULSE_RATE_PRESENT) == BPS_FLAG_PULSE_RATE_PRESENT) { pmeas_val->pulse_rate = co_read16p(&(packed_bp[cursor + 0])); cursor += 2; } // User ID flag set if ((pmeas_val->flags & BPS_FLAG_USER_ID_PRESENT) == BPS_FLAG_USER_ID_PRESENT) { pmeas_val->user_id = packed_bp[cursor + 0]; cursor += 1; } // measurement status flag set if ((pmeas_val->flags & BPS_FLAG_MEAS_STATUS_PRESENT) == BPS_FLAG_MEAS_STATUS_PRESENT) { pmeas_val->meas_status = co_read16p(&(packed_bp[cursor + 0])); cursor += 2; } }
/** **************************************************************************************** * @brief Handles reception of the @ref GATT_WRITE_CMD_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 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 char_code = ADC_NOTIFY_ERR_CHAR; uint8_t status = PRF_APP_ERROR; if (KE_IDX_GET(src_id) == adc_notify_env.con_info.conidx) { if (param->handle == adc_notify_env.adc_notify_shdl + ADC_NOTIFY_IDX_CFG) { char_code = ADC_NOTIFY_CFG; } if (char_code == ADC_NOTIFY_CFG) { // Written value uint16_t ntf_cfg; // Extract value before check ntf_cfg = co_read16p(¶m->value[0]); // Only update configuration if value for stop or notification enable if ((ntf_cfg == PRF_CLI_STOP_NTFIND) || (ntf_cfg == PRF_CLI_START_NTF)) { //Save value in DB attmdb_att_set_value(param->handle, sizeof(uint16_t), (uint8_t *)¶m->value[0]); // Conserve information in environment if (ntf_cfg == PRF_CLI_START_NTF) { // Ntf cfg bit set to 1 adc_notify_env.feature |= PRF_CLI_START_NTF; } else { // Ntf cfg bit set to 0 adc_notify_env.feature &= ~PRF_CLI_START_NTF; } adc_notify_send_cfg(ntf_cfg); status = PRF_ERR_OK; } } } // Send Write Response atts_write_rsp_send(adc_notify_env.con_info.conidx, param->handle, status); return (KE_MSG_CONSUMED); }
uint8_t prf_unpack_date_time(uint8_t *packed_date, struct prf_date_time* date_time) { date_time->year = co_read16p(&(packed_date[0])); date_time->month = packed_date[2]; date_time->day = packed_date[3]; date_time->hour = packed_date[4]; date_time->min = packed_date[5]; date_time->sec = packed_date[6]; return 7; }
/** **************************************************************************************** * @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); }
/** **************************************************************************************** * @brief Handles reception of the @ref GATT_WRITE_CMD_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 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 char_code = SAMPLE128_ERR_CHAR; uint8_t status = PRF_APP_ERROR; if (KE_IDX_GET(src_id) == sample128_env.con_info.conidx) { if (param->handle == sample128_env.sample128_shdl + SAMPLE128_1_IDX_VAL) { char_code = SAMPLE128_1_CHAR; } if (param->handle == sample128_env.sample128_shdl + SAMPLE128_2_IDX_CFG) { char_code = SAMPLE128_2_CFG; } if (char_code == SAMPLE128_1_CHAR) { //Save value in DB attmdb_att_set_value(param->handle, sizeof(uint8_t), (uint8_t *)¶m->value[0]); if(param->last) { sample128_send_val(param->value[0]); leds_state.flag = param->value[0]; //app_sample128_start_leds(); } status = PRF_ERR_OK; } else if (char_code == SAMPLE128_2_CFG) { // Written value uint16_t ntf_cfg; // Extract value before check ntf_cfg = co_read16p(¶m->value[0]); // Only update configuration if value for stop or notification enable if ((ntf_cfg == PRF_CLI_STOP_NTFIND) || (ntf_cfg == PRF_CLI_START_NTF)) { //Save value in DB attmdb_att_set_value(param->handle, sizeof(uint16_t), (uint8_t *)¶m->value[0]); // Conserve information in environment if (ntf_cfg == PRF_CLI_START_NTF) { // Ntf cfg bit set to 1 sample128_env.feature |= PRF_CLI_START_NTF; } else { // Ntf cfg bit set to 0 sample128_env.feature &= ~PRF_CLI_START_NTF; } status = PRF_ERR_OK; } } } // Send Write Response atts_write_rsp_send(sample128_env.con_info.conidx, param->handle, 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 GATTC_WRITE_CMD_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 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) { // Get the conidx uint8_t conidx = KE_IDX_GET(src_id); // Get the address of the environment struct pasps_idx_env_tag *pasps_idx_env = PRF_CLIENT_GET_ENV(KE_BUILD_ID(dest_id, conidx), pasps_idx); // Check if the connection exists if (pasps_idx_env != NULL) { /* * --------------------------------------------------------------------------------------------- * Alert Status Client Characteristic Configuration Descriptor Value - Write * --------------------------------------------------------------------------------------------- */ /* * --------------------------------------------------------------------------------------------- * Ringer Setting Client Characteristic Configuration Descriptor Value - Write * --------------------------------------------------------------------------------------------- */ if ((param->handle == (pasps_env.pass_shdl + PASS_IDX_ALERT_STATUS_CFG)) || (param->handle == (pasps_env.pass_shdl + PASS_IDX_RINGER_SETTING_CFG))) { // Status uint8_t status = PRF_ERR_OK; // Received configuration value uint16_t ntf_cfg = co_read16p(¶m->value[0]); if ((ntf_cfg == PRF_CLI_STOP_NTFIND) || (ntf_cfg == PRF_CLI_START_NTF)) { // Set the value of the Alert Status Client Characteristic Configuration Descriptor attmdb_att_set_value(param->handle, sizeof(uint16_t), (uint8_t *)&ntf_cfg); struct pasps_written_char_val_ind *ind = KE_MSG_ALLOC(PASPS_WRITTEN_CHAR_VAL_IND, pasps_idx_env->con_info.appid, dest_id, pasps_written_char_val_ind); ind->conhdl = gapc_get_conhdl(pasps_idx_env->con_info.conidx); if (param->handle == pasps_env.pass_shdl + PASS_IDX_ALERT_STATUS_CFG) { ind->value.alert_status_ntf_cfg = ntf_cfg; ind->att_code = PASPS_ALERT_STATUS_NTF_CFG; if (ntf_cfg == PRF_CLI_STOP_NTFIND) { PASPS_DISABLE_NTF(pasps_idx_env, PASPS_FLAG_ALERT_STATUS_CFG); } else { PASPS_ENABLE_NTF(pasps_idx_env, PASPS_FLAG_ALERT_STATUS_CFG); } } else { ind->value.ringer_setting_ntf_cfg = ntf_cfg; ind->att_code = PASPS_RINGER_SETTING_NTF_CFG; if (ntf_cfg == PRF_CLI_STOP_NTFIND) { PASPS_DISABLE_NTF(pasps_idx_env, PASPS_FLAG_RINGER_SETTING_CFG); } else { PASPS_ENABLE_NTF(pasps_idx_env, PASPS_FLAG_RINGER_SETTING_CFG); } } ke_msg_send(ind); } else { status = PRF_APP_ERROR; } // Send write response atts_write_rsp_send(pasps_idx_env->con_info.conidx, param->handle, status); } /* * --------------------------------------------------------------------------------------------- * Ringer Control Point Characteristic Value - Write Without Response * --------------------------------------------------------------------------------------------- */ else if (param->handle == (pasps_env.pass_shdl + PASS_IDX_RINGER_CTNL_PT_VAL)) { // Inform the HL ? bool inform_hl = false; // Check the received value switch (param->value[0]) { case (PASP_SILENT_MODE): { // Ignore if ringer is already silent if (pasps_env.ringer_state == PASP_RINGER_NORMAL) { inform_hl = true; } } break; case (PASP_CANCEL_SILENT_MODE): { // Ignore if ringer is not silent if (pasps_env.ringer_state == PASP_RINGER_SILENT) { inform_hl = true; } } break; case (PASP_MUTE_ONCE): { inform_hl = true; } break; // No need to respond with an error (Write Without Response) default: break; } if (inform_hl) { struct pasps_written_char_val_ind *ind = KE_MSG_ALLOC(PASPS_WRITTEN_CHAR_VAL_IND, pasps_idx_env->con_info.appid, TASK_PASPS, pasps_written_char_val_ind); ind->conhdl = gapc_get_conhdl(pasps_idx_env->con_info.conidx);; ind->att_code = PASPS_RINGER_CTNL_PT_CHAR_VAL; ind->value.ringer_ctnl_pt = param->value[0]; ke_msg_send(ind); } } else { ASSERT_ERR(0); } } // else ignore the message 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); }
/** **************************************************************************************** * @brief Handles reception of the @ref GL2C_CODE_ATT_WR_CMD_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 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) { // Counter uint8_t i; // Status uint8_t status = PRF_APP_ERROR; // Written value uint16_t ntf_cfg; // Look for the BAS instance for (i = 0; ((i < bass_env.bas_nb) && (status == PRF_APP_ERROR)); i++) { if (param->handle == bass_env.shdl[i] + BAS_IDX_BATT_LVL_NTF_CFG) { // Go out of the loop status = PRF_ERR_OK; } } //Revert Last incrementation i--; // If the attribute has been found, status is PRF_ERR_OK if (status == PRF_ERR_OK) { // Extract value before check ntf_cfg = co_read16p(¶m->value[0]); // Only update configuration if value for stop or notification enable if ((ntf_cfg == PRF_CLI_STOP_NTFIND) || (ntf_cfg == PRF_CLI_START_NTF)) { // Set NTF Cfg value in the DB attmdb_att_set_value(bass_env.shdl[i] + BAS_IDX_BATT_LVL_NTF_CFG, sizeof(uint16_t), (uint8_t *)&ntf_cfg); // Conserve information in environment if (ntf_cfg == PRF_CLI_START_NTF) { // Ntf cfg bit set to 1 bass_env.features[i] |= BASS_FLAG_NTF_CFG_BIT; } else { // Ntf cfg bit set to 0 bass_env.features[i] &= ~BASS_FLAG_NTF_CFG_BIT; } if(param->last) { // Inform APP of configuration change struct bass_batt_level_ntf_cfg_ind * ind = KE_MSG_ALLOC(BASS_BATT_LEVEL_NTF_CFG_IND, bass_env.con_info.appid, TASK_BASS, bass_batt_level_ntf_cfg_ind); ind->conhdl = gapc_get_conhdl(bass_env.con_info.conidx); co_write16p(&ind->ntf_cfg, ntf_cfg); ind->bas_instance = i; ke_msg_send(ind); } } else { status = PRF_APP_ERROR; } // Send write response atts_write_rsp_send(bass_env.con_info.conidx, param->handle, status); } 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) { // Status uint8_t error_status = param->status; // Get the address of the environment struct basc_env_tag *basc_env = PRF_CLIENT_GET_ENV(dest_id, basc); if (error_status == PRF_ERR_OK) { // Battery Level Value if (basc_env->last_char_code == BASC_RD_BAS_BATT_LEVEL) { struct basc_batt_level_ind *ind = KE_MSG_ALLOC(BASC_BATT_LEVEL_IND, basc_env->con_info.appid, dest_id, basc_batt_level_ind); ind->conhdl = basc_env->con_info.conhdl; ind->ind_type = BASC_BATT_LEVEL_RD_RSP; ind->batt_level = param->data.data[0]; ind->bas_nb = basc_env->last_svc_inst_req; ke_msg_send(ind); } // Battery Level Client Characteristic Configuration Descriptor value else if (basc_env->last_char_code == BASC_RD_BAS_BATT_LEVEL_CLI_CFG) { struct basc_batt_level_ntf_cfg_rd_rsp *rsp = KE_MSG_ALLOC(BASC_BATT_LEVEL_NTF_CFG_RD_RSP, basc_env->con_info.appid, dest_id, basc_batt_level_ntf_cfg_rd_rsp); rsp->conhdl = basc_env->con_info.conhdl; rsp->bas_nb = basc_env->last_svc_inst_req; rsp->ntf_cfg = co_read16p(¶m->data.data[0]); ke_msg_send(rsp); } // Battery Level Client Presentation Format Descriptor value else if (basc_env->last_char_code == BASC_RD_BAS_BATT_LEVEL_PRES_FORMAT) { struct basc_batt_level_pres_format_rd_rsp *rsp = KE_MSG_ALLOC(BASC_BATT_LEVEL_PRES_FORMAT_RD_RSP, basc_env->con_info.appid, dest_id, basc_batt_level_pres_format_rd_rsp); rsp->conhdl = basc_env->con_info.conhdl; rsp->bas_nb = basc_env->last_svc_inst_req; prf_unpack_char_pres_fmt(¶m->data.data[0], &rsp->char_pres_format); ke_msg_send(rsp); } //Unsupported Characteristic else { error_status = PRF_ERR_INEXISTENT_HDL; } } // Send Error indication to APP if needed if (error_status != PRF_ERR_OK) { basc_error_ind_send(basc_env, error_status); } return (KE_MSG_CONSUMED); }
/** **************************************************************************************** * @brief Handles reception of the @ref GATTC_WRITE_CMD_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 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 conidx = KE_IDX_GET(src_id); // Get the address of the environment struct anps_idx_env_tag *anps_idx_env = PRF_CLIENT_GET_ENV(KE_BUILD_ID(dest_id, conidx), anps_idx); // Check if the connection exists if (anps_idx_env != NULL) { // Status uint8_t status = PRF_ERR_OK; /* * --------------------------------------------------------------------------------------------- * New Alert Client Characteristic Configuration Descriptor Value - Write * --------------------------------------------------------------------------------------------- */ /* * --------------------------------------------------------------------------------------------- * Unread Status Alert Client Characteristic Configuration Descriptor Value - Write * --------------------------------------------------------------------------------------------- */ if ((param->handle == (anps_env.ans_shdl + ANS_IDX_NEW_ALERT_CFG)) || (param->handle == (anps_env.ans_shdl + ANS_IDX_UNREAD_ALERT_STATUS_CFG))) { // Received configuration value uint16_t ntf_cfg = co_read16p(¶m->value[0]); if (ntf_cfg <= PRF_CLI_START_NTF) { // Alert type uint8_t alert_type = (param->handle == (anps_env.ans_shdl + ANS_IDX_NEW_ALERT_CFG)) ? ANP_NEW_ALERT : ANP_UNREAD_ALERT; // Set the value of the Alert Status Client Characteristic Configuration Descriptor (Readable) attmdb_att_set_value(param->handle, sizeof(uint16_t), (uint8_t *)&ntf_cfg); // Update the status in the environment if (ntf_cfg == PRF_CLI_START_NTF) { ANPS_ENABLE_ALERT(anps_idx_env, alert_type); } else { ANPS_DISABLE_ALERT(anps_idx_env, alert_type); } // Inform the HL that the notification configuration status has been written anps_send_ntf_status_update_ind(anps_idx_env, alert_type); } else { status = PRF_APP_ERROR; } } /* * --------------------------------------------------------------------------------------------- * Alert Notification Control Point Characteristic Value - Write * --------------------------------------------------------------------------------------------- */ else if (param->handle == (anps_env.ans_shdl + ANS_IDX_ALERT_NTF_CTNL_PT_VAL)) { do { // Check the command ID value if (param->value[0] >= CMD_ID_NB) { status = ANP_CMD_NOT_SUPPORTED; break; } // Check the category ID value if ((param->value[1] >= CAT_ID_NB) && (param->value[1] != CAT_ID_ALL_SUPPORTED_CAT)) { status = ANP_CAT_NOT_SUPPORTED; break; } if (param->value[1] < CAT_ID_NB) { // New Alert if ((param->value[0] % 2) == 0) { // Check if the category is supported if (!ANPS_IS_NEW_ALERT_CATEGORY_SUPPORTED(param->value[1])) { status = ANP_CAT_NOT_SUPPORTED; break; } } // Unread Alert Status else { // Check if the category is supported if (!ANPS_IS_UNREAD_ALERT_CATEGORY_SUPPORTED(param->value[1])) { status = ANP_CAT_NOT_SUPPORTED; break; } } } // React according to the received command id value switch (param->value[0]) { // Enable New Alert Notification case (CMD_ID_EN_NEW_IN_ALERT_NTF): { if (param->value[1] != CAT_ID_ALL_SUPPORTED_CAT) { // Enable sending of new alert notification for the specified category ANPS_ENABLE_NEW_ALERT_CATEGORY(param->value[1], anps_idx_env); } else { // Enable sending of new alert notification for all supported category anps_idx_env->ntf_new_alert_cfg |= anps_env.supp_new_alert_cat; } anps_send_ntf_status_update_ind(anps_idx_env, ANP_NEW_ALERT); } break; // Enable Unread Alert Status Notification case (CMD_ID_EN_UNREAD_CAT_STATUS_NTF): { if (param->value[1] != CAT_ID_ALL_SUPPORTED_CAT) { // Enable sending of unread alert notification for the specified category ANPS_ENABLE_UNREAD_ALERT_CATEGORY(param->value[1], anps_idx_env); } else { // Enable sending of unread alert notification for all supported category anps_idx_env->ntf_unread_alert_cfg |= anps_env.supp_unread_alert_cat; } anps_send_ntf_status_update_ind(anps_idx_env, ANP_UNREAD_ALERT); } break; // Disable New Alert Notification case (CMD_ID_DIS_NEW_IN_ALERT_NTF): { if (param->value[1] != CAT_ID_ALL_SUPPORTED_CAT) { // Disable sending of new alert notification for the specified category ANPS_DISABLE_NEW_ALERT_CATEGORY(param->value[1], anps_idx_env); } else { // Disable sending of new alert notification for all supported category anps_idx_env->ntf_new_alert_cfg &= ~anps_env.supp_new_alert_cat; } anps_send_ntf_status_update_ind(anps_idx_env, ANP_NEW_ALERT); } break; // Disable Unread Alert Status Notification case (CMD_ID_DIS_UNREAD_CAT_STATUS_NTF): { if (param->value[1] != CAT_ID_ALL_SUPPORTED_CAT) { // Disable sending of unread alert notification for the specified category ANPS_DISABLE_UNREAD_ALERT_CATEGORY(param->value[1], anps_idx_env); } else { // Enable sending of unread alert notification for all supported category anps_idx_env->ntf_unread_alert_cfg &= ~anps_env.supp_unread_alert_cat; } anps_send_ntf_status_update_ind(anps_idx_env, ANP_UNREAD_ALERT); } break; // Notify New Alert immediately case (CMD_ID_NTF_NEW_IN_ALERT_IMM): { // Check if sending of notification is enabled if (ANPS_IS_ALERT_ENABLED(anps_idx_env, ANP_NEW_ALERT)) { if (param->value[1] == CAT_ID_ALL_SUPPORTED_CAT) { // Check if at least one category can be notified if (anps_idx_env->ntf_new_alert_cfg != 0) { anps_send_ntf_immediate_req_ind(anps_idx_env, ANP_NEW_ALERT, CAT_ID_ALL_SUPPORTED_CAT); } } else { // Check if sending of notifications has been enabled for the specified category. if (ANPS_IS_NEW_ALERT_CATEGORY_ENABLED(param->value[1], anps_idx_env)) { anps_send_ntf_immediate_req_ind(anps_idx_env, ANP_NEW_ALERT, param->value[1]); } } } } break; // Notify Unread Alert Status immediately case (CMD_ID_NTF_UNREAD_CAT_STATUS_IMM): { if (ANPS_IS_ALERT_ENABLED(anps_idx_env, ANP_UNREAD_ALERT)) { // Check if sending of notification is enabled if (ANPS_IS_ALERT_ENABLED(anps_idx_env, ANP_UNREAD_ALERT)) { if (param->value[1] == CAT_ID_ALL_SUPPORTED_CAT) { // Check if at least one category can be notified if (anps_idx_env->ntf_unread_alert_cfg != 0) { anps_send_ntf_immediate_req_ind(anps_idx_env, ANP_UNREAD_ALERT, CAT_ID_ALL_SUPPORTED_CAT); } } else { // Check if sending of notifications has been enabled for the specified category. if (ANPS_IS_UNREAD_ALERT_CATEGORY_ENABLED(param->value[1], anps_idx_env)) { anps_send_ntf_immediate_req_ind(anps_idx_env, ANP_UNREAD_ALERT, param->value[1]); } } } } } break; default: { ASSERT_ERR(0); } break; } } while (0); } else { ASSERT_ERR(0); } // Send write response atts_write_rsp_send(anps_idx_env->con_info.conidx, param->handle, status); } // else ignore the message return (KE_MSG_CONSUMED); }