/** **************************************************************************************** * @brief Handles reception of the @ref GATT_WRITE_CMD_IND message. * The handler checks if the stream needs to be turned on. * @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) { // Update the attribute value attmdb_att_update_value(param->handle, param->length, param->offset, (uint8_t*)&(param->value[0])); switch (STREAMDATAD_IDX(param->handle)) { case STREAMDATAD_IDX_ENABLE_VAL: streamdatad_streamonoff(); atts_write_rsp_send(streamdatad_env.conhdl, param->handle, PRF_ERR_OK); break; case STREAMDATAD_IDX_STREAMDATAD_D0_EN: case STREAMDATAD_IDX_STREAMDATAD_D1_EN: case STREAMDATAD_IDX_STREAMDATAD_D2_EN: case STREAMDATAD_IDX_STREAMDATAD_D3_EN: case STREAMDATAD_IDX_STREAMDATAD_D4_EN: case STREAMDATAD_IDX_STREAMDATAD_D5_EN: case STREAMDATAD_IDX_STREAMDATAD_D6_EN: case STREAMDATAD_IDX_STREAMDATAD_D7_EN: case STREAMDATAD_IDX_STREAMDATAD_D8_EN: case STREAMDATAD_IDX_STREAMDATAD_D9_EN: atts_write_rsp_send(streamdatad_env.conhdl, param->handle, PRF_ERR_OK); break; case STREAMDATAD_IDX_STREAMDATAD_D0_VAL: case STREAMDATAD_IDX_STREAMDATAD_D1_VAL: case STREAMDATAD_IDX_STREAMDATAD_D2_VAL: case STREAMDATAD_IDX_STREAMDATAD_D3_VAL: case STREAMDATAD_IDX_STREAMDATAD_D4_VAL: case STREAMDATAD_IDX_STREAMDATAD_D5_VAL: case STREAMDATAD_IDX_STREAMDATAD_D6_VAL: case STREAMDATAD_IDX_STREAMDATAD_D7_VAL: case STREAMDATAD_IDX_STREAMDATAD_D8_VAL: case STREAMDATAD_IDX_STREAMDATAD_D9_VAL: { struct streamdatad_rcv_data_packet_ind * ind = KE_MSG_ALLOC(STREAMDATAD_RCV_DATA_PACKET_IND, streamdatad_env.con_info.appid, dest_id, streamdatad_rcv_data_packet_ind); ind->conhdl = gapc_get_conhdl(streamdatad_env.con_info.conidx); ind->handle = param->handle; ind->seq = param->value[0]; // is already incrementing (with the dummy data of the test) ind->size = param->length; memcpy(&(ind->value[0]), &(param->value[0]), param->length); // Forward Received packet data to APP with the sequence number to indicate lost packets ke_msg_send(ind); } break; } return (KE_MSG_CONSUMED); }
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 char_code = PROXR_ERR_CHAR; uint8_t status = PRF_APP_ERROR; if (param->conhdl == beacon_env.con_info.conhdl) { if (param->handle == beacon_env.shdl + BEACON_IDX_LVL_VAL) { //Save value in DB attsdb_att_set_value(param->handle, sizeof(uint8_t), (uint8_t *)¶m->value[0]); #if QN_NVDS_WRITE if (NVDS_OK == nvds_put(NVDS_TAG_MEASURED_POWER, sizeof(param->value[0]), (uint8_t *)¶m->value[0])) { status = PRF_ERR_OK; } #else status = PRF_ERR_OK; #endif //Response atts_write_rsp_send(beacon_env.con_info.conhdl, param->handle, status); } } 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 = 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); }
/** **************************************************************************************** * @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_1_shdl + SAMPLE128_1_IDX_VAL) { char_code = SAMPLE128_1_CHAR; } if (char_code != SAMPLE128_ERR_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]); } 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_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 GL2C_CODE_ATT_WR_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 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 *meas_intv_range; uint16_t meas_intv_rge[2]; uint16_t value = 0x0000; uint8_t status = PRF_ERR_OK; uint8_t char_code = 0; if (KE_IDX_GET(src_id) == htpt_env.con_info.conidx) { //Extract value before check memcpy(&value, &(param->value), sizeof(uint16_t)); //Measurement Interval Char. - Value if (param->handle == (htpt_env.shdl + htpt_env.att_tbl[HTPT_MEAS_INTV_CHAR] + 1)) { /* * Get Measurement Interval range in database * Valid Range descriptor exists because measurement interval is writable */ attmdb_att_get_value(param->handle + htpt_get_valid_rge_offset(), &meas_intv_rge[0], &meas_intv_range); memcpy(&meas_intv_rge[0], meas_intv_range, sizeof(uint16_t)); memcpy(&meas_intv_rge[1], meas_intv_range + 2, sizeof(uint16_t)); //Check if value to write is in allowed range if (((value >= meas_intv_rge[0]) && (value <= meas_intv_rge[1])) || (value == 0)) { //Send APP the indication with the new value struct htpt_meas_intv_chg_ind * ind = KE_MSG_ALLOC(HTPT_MEAS_INTV_CHG_IND, htpt_env.con_info.appid, TASK_HTPT, htpt_meas_intv_chg_ind); memcpy(&ind->intv, &value, sizeof(uint16_t)); ke_msg_send(ind); } else { status = HTPT_OUT_OF_RANGE_ERR_CODE; } } else { //Temperature Measurement Char. - Client Char. Configuration if (param->handle == (htpt_env.shdl + HTS_IDX_TEMP_MEAS_IND_CFG)) { char_code = HTPT_TEMP_MEAS_CHAR; if (value == PRF_CLI_STOP_NTFIND) { htpt_env.features &= ~HTPT_MASK_TEMP_MEAS_CFG; } else if (value == PRF_CLI_START_IND) { htpt_env.features |= HTPT_MASK_TEMP_MEAS_CFG; } else { //Invalid value status = HTPT_OUT_OF_RANGE_ERR_CODE; } } //Measurement Interval Char. - Client Char. Configuration else if (param->handle == (htpt_env.shdl + htpt_env.att_tbl[HTPT_MEAS_INTV_CHAR] + 2)) { char_code = HTPT_MEAS_INTV_CHAR; if (value == PRF_CLI_STOP_NTFIND) { htpt_env.features &= ~HTPT_MASK_MEAS_INTV_CFG; } else if (value == PRF_CLI_START_IND) { htpt_env.features |= HTPT_MASK_MEAS_INTV_CFG; } else { //Invalid value status = HTPT_OUT_OF_RANGE_ERR_CODE; } } //Intermediate Measurement Char. - Client Char. Configuration else if (param->handle == (htpt_env.shdl + htpt_env.att_tbl[HTPT_INTERM_TEMP_CHAR] + 2)) { char_code = HTPT_INTERM_TEMP_CHAR; if (value == PRF_CLI_STOP_NTFIND) { htpt_env.features &= ~HTPT_MASK_INTM_MEAS_CFG; } else if (value == PRF_CLI_START_NTF) { htpt_env.features |= HTPT_MASK_INTM_MEAS_CFG; } else { //Invalid value status = HTPT_OUT_OF_RANGE_ERR_CODE; } } if (status == PRF_ERR_OK) { if(param->last) { //Inform APP of configuration change struct htpt_cfg_indntf_ind * ind = KE_MSG_ALLOC(HTPT_CFG_INDNTF_IND, htpt_env.con_info.appid, TASK_HTPT, htpt_cfg_indntf_ind); ind->conhdl = gapc_get_conhdl(htpt_env.con_info.conidx); ind->char_code = char_code; memcpy(&ind->cfg_val, &value, sizeof(uint16_t)); ke_msg_send(ind); } } } if (status == PRF_ERR_OK) { //Update the attribute value attmdb_att_set_value(param->handle, sizeof(uint16_t), (uint8_t *)&value); } //Send write response atts_write_rsp_send(htpt_env.con_info.conidx, param->handle, 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) { // 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 GL2C_CODE_ATT_WR_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 gattc_write_cmd_ind_handler(ke_msg_id_t const msgid, struct gattc_write_cmd_ind const *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { uint16_t cfg_value = 0x0000; uint8_t time_upd_ctnl_pt = 0x00; uint8_t status = CO_ERROR_NO_ERROR; // Get the address of the environment struct tips_idx_env_tag *tips_idx_env = PRF_CLIENT_GET_ENV(dest_id, tips_idx); //CTS : Current Time Char. - Notification Configuration if (param->handle == tips_env.cts_shdl + CTS_IDX_CURRENT_TIME_CFG) { //Extract value before check memcpy(&cfg_value, ¶m->value[0], sizeof(uint16_t)); //only update configuration if value for stop or notification enable if ((cfg_value == PRF_CLI_STOP_NTFIND) || (cfg_value == PRF_CLI_START_NTF)) { //Update value in DB attmdb_att_set_value(param->handle, sizeof(uint16_t), (uint8_t *)&cfg_value); if (cfg_value == PRF_CLI_STOP_NTFIND) { tips_idx_env->ntf_state &= ~TIPS_CTS_CURRENT_TIME_CFG; } else //PRF_CLI_START_NTF { tips_idx_env->ntf_state |= TIPS_CTS_CURRENT_TIME_CFG; } if (param->last) { //Inform APP of configuration change struct tips_current_time_ccc_ind * msg = KE_MSG_ALLOC(TIPS_CURRENT_TIME_CCC_IND, tips_idx_env->con_info.appid, dest_id, tips_current_time_ccc_ind); msg->conhdl = gapc_get_conhdl(tips_idx_env->con_info.conidx); msg->cfg_val = cfg_value; ke_msg_send(msg); } } else { //Invalid value => send Error Response with Error Code set to App Error status = PRF_APP_ERROR; } } //RTUS : Time Update Control Point Char. - Val else if (param->handle == tips_env.rtus_shdl + RTUS_IDX_TIME_UPD_CTNL_PT_VAL) { time_upd_ctnl_pt = param->value[0]; //Check if value to write is in allowed range if ((time_upd_ctnl_pt == TIPS_TIME_UPD_CTNL_PT_GET) || (time_upd_ctnl_pt == TIPS_TIME_UPD_CTNL_PT_CANCEL)) { //Update value in DB attmdb_att_set_value(param->handle, sizeof(uint8_t), (uint8_t *)&time_upd_ctnl_pt); if(param->last) { //Send APP the indication with the new value struct tips_time_upd_ctnl_pt_ind * msg = KE_MSG_ALLOC(TIPS_TIME_UPD_CTNL_PT_IND, tips_idx_env->con_info.appid, dest_id, tips_time_upd_ctnl_pt_ind); msg->conhdl = gapc_get_conhdl(tips_idx_env->con_info.conidx); /* * Time Update Control Point Characteristic Value * 0x01 - Get Reference Update * 0x02 - Cancel Reference Update */ msg->value = time_upd_ctnl_pt; ke_msg_send(msg); } } } //Send Write Response if (param->response == 0x01) { atts_write_rsp_send(tips_idx_env->con_info.conidx, param->handle, status); } return (KE_MSG_CONSUMED); }
/** **************************************************************************************** * @brief Handles reception of the @ref GL2C_CODE_ATT_WR_CMD_IND message. * The handler will analyse what has been set and decide alert level * @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 = UDSS_ERR_CHAR; uint8_t status = PRF_APP_ERROR; if (KE_IDX_GET(src_id) == udss_env.con_info.conidx) { // uint8_t att_idx = GLPS_IDX(param->handle); status = PRF_ERR_OK; if (param->handle == udss_env.shdl + UDS_IDX_USER_HEIGHT_VAL) { char_code = UDSS_USER_HEIGHT_CHAR; //Set User Height to specified value attmdb_att_set_value(udss_env.shdl + UDS_IDX_USER_HEIGHT_VAL, sizeof(uint8_t), (uint8_t *)¶m->value[0]); } else if (param->handle == udss_env.shdl + UDS_IDX_USER_AGE_VAL) { char_code = UDSS_USER_AGE_CHAR; //Set User Age to specified value attmdb_att_set_value(udss_env.shdl + UDS_IDX_USER_AGE_VAL, sizeof(uint8_t), (uint8_t *)¶m->value[0]); } else if (param->handle == udss_env.shdl + UDS_IDX_USER_DATE_OF_BIRTH_VAL) { char_code = UDSS_USER_DATE_OF_BIRTH_CHAR; //Set User Date of Birth to specified value attmdb_att_set_value(udss_env.shdl + UDS_IDX_USER_DATE_OF_BIRTH_VAL, sizeof(struct date), (uint8_t *)¶m->value[0]); } else if (param->handle == udss_env.shdl + UDS_IDX_USER_DB_CHANGE_INCR_VAL) { char_code = UDSS_USER_DB_CHANGE_INCR_CHAR; //Set User DB Change Increment to specified value attmdb_att_set_value(udss_env.shdl + UDS_IDX_USER_DB_CHANGE_INCR_VAL, sizeof(uint8_t), (uint8_t *)¶m->value[0]); } else if (param->handle == udss_env.shdl + UDS_IDX_USER_CTRL_POINT_VAL) { uint8_t reqstatus; uint8_t* value; uint16_t length; struct uds_ucp_req ucp_req; // Update the attribute value (note several write could be required since // attribute length > (ATT_MTU-3) attmdb_att_update_value(param->handle, param->length, param->offset, (uint8_t*)&(param->value[0])); // retrieve full data. attmdb_att_get_value(param->handle, &length, &value); // unpack user control point value reqstatus = udss_unpack_ucp_req(value, length, &ucp_req); // check unpacked status switch(reqstatus) { 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(ucp_req.op_code) { case UDS_REQ_REG_NEW_USER: case UDS_REQ_CONSENT: case UDS_REQ_DEL_USER_DATA: { //forward request operation to application struct udss_ucp_req_ind * req = KE_MSG_ALLOC(UDSS_UCP_REQ_IND, udss_env.con_info.appid, TASK_UDSS, udss_ucp_req_ind); // UCP on going. // UDSS_SET(UCP_ON_GOING); req->conhdl = gapc_get_conhdl(udss_env.con_info.conidx); req->ucp_req = ucp_req; ke_msg_send(req); } break; // case UDS_REQ_ABORT_OP: // { // // nothing to abort, send an error message. // struct uds_ucp_rsp ucp_rsp; // ucp_rsp.op_code = UDS_REQ_RSP_CODE; // ucp_rsp.operand.rsp.op_code_req = // ucp_req.op_code; // ucp_rsp.operand.rsp.status = UDS_RSP_ABORT_UNSUCCESSFUL; // // send user control response indication // udss_send_ucp_rsp(&(ucp_rsp), // TASK_UDSS); // } // break; default: { // nothing to do since it's handled during unpack } break; } } break; default: { /* There is an error in user control request, inform peer * device that request is incorrect. */ struct uds_ucp_rsp ucp_rsp; ucp_rsp.op_code = UDS_REQ_RSP_CODE; ucp_rsp.req_op_code = ucp_req.op_code; ucp_rsp.rsp_val = reqstatus; // send user control response indication udss_send_ucp_rsp(&(ucp_rsp), TASK_UDSS); } break; } } // not expected request else { status = ATT_ERR_WRITE_NOT_PERMITTED; } } if(param->response) { // Send Write Response atts_write_rsp_send(udss_env.con_info.conidx, param->handle, status); } return (KE_MSG_CONSUMED); }
/** **************************************************************************************** * @brief Handles reception of the @ref GL2C_CODE_ATT_WR_CMD_IND message. * The handler will * @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) { uint16_t value = 0x0000; uint8_t char_code = HPS_ERR_CHAR; uint8_t status = PRF_APP_ERROR; if (KE_IDX_GET(src_id) == hpss_env.con_info.conidx) { if (param->handle == hpss_env.hps_shdl + HPS_IDX_URI_VAL) { char_code = HPS_URI_CHAR; } else if (param->handle == hpss_env.hps_shdl + HPS_IDX_HEADER_VAL) { char_code = HPS_HEADER_CHAR; } else if (param->handle == hpss_env.hps_shdl + HPS_IDX_BODY_VAL) { char_code = HPS_BODY_CHAR; } else if (param->handle == hpss_env.hps_shdl + HPS_IDX_CNTL_PT_VAL) { char_code = HPS_CNTL_PT_CHAR; } //this case is processed seperately else if (param->handle == hpss_env.hps_shdl + HPS_IDX_STATUS_CODE_CFG) { //Extract value before check memcpy(&value, &(param->value), sizeof(uint16_t)); if ((value == PRF_CLI_STOP_NTFIND) || (value == PRF_CLI_START_NTF)) { status = PRF_ERR_OK; if (value == PRF_CLI_STOP_NTFIND) { hpss_env.features &= ~HPSS_STATUS_CODE_NTF_CFG; } else //PRF_CLI_START_NTF { hpss_env.features |= HPSS_STATUS_CODE_NTF_CFG; } } else { status = PRF_APP_ERROR; } if (status == PRF_ERR_OK) { //Update the attribute value attmdb_att_set_value(param->handle, sizeof(uint16_t), (uint8_t *)&value); if(param->last) { //Inform APP of configuration change struct hpss_cfg_indntf_ind * ind = KE_MSG_ALLOC(HPSS_CFG_INDNTF_IND, hpss_env.con_info.appid, TASK_HPSS, hpss_cfg_indntf_ind); ind->conhdl = gapc_get_conhdl(hpss_env.con_info.conidx); memcpy(&ind->cfg_val, &value, sizeof(uint16_t)); ke_msg_send(ind); } } //If HPS, send write response if (param->response != 0x00) { // Send Write Response atts_write_rsp_send(hpss_env.con_info.conidx, param->handle, status); } return (KE_MSG_CONSUMED); } if (char_code != HPS_ERR_CHAR) { //Save value in DB attmdb_att_set_value(param->handle, sizeof(uint8_t), (uint8_t *)¶m->value[0]); status = PRF_ERR_OK; switch(char_code) { case HPS_URI_CHAR: if ((param->length + param->offset) <= HPS_URI_MAX_LEN) { // First part of the uri value if (param->offset == 0) { // Set value in the database attmdb_att_set_value(param->handle, param->length, (uint8_t *)¶m->value[0]); } else { // Complete the value stored in the database attmdb_att_update_value(param->handle, param->length, param->offset, (uint8_t *)¶m->value[0]); } if(param->last) { uint16_t len = 0; uint8_t *data = NULL; // Get complete uri value and length attmdb_att_get_value(param->handle, &len, &data); // Inform APP. Allocate the URI value change indication struct hpss_uri_ind *ind = KE_MSG_ALLOC(HPSS_URI_IND, hpss_env.con_info.appid, TASK_HPSS, hpss_uri_ind); // Fill in the parameter structure ind->conhdl = gapc_get_conhdl(hpss_env.con_info.conidx); ind->char_code = HPS_URI_CHAR; ind->len = len; memcpy(&ind->uri, data, len); ke_msg_send(ind); } } break; case HPS_HEADER_CHAR: if ((param->length + param->offset) <= HPS_HEADER_MAX_LEN) { // First part of the uri value if (param->offset == 0) { // Set value in the database attmdb_att_set_value(param->handle, param->length, (uint8_t *)¶m->value[0]); } else { // Complete the value stored in the database attmdb_att_update_value(param->handle, param->length, param->offset, (uint8_t *)¶m->value[0]); } if(param->last) { uint16_t len = 0; uint8_t *data = NULL; // Get complete uri value and length attmdb_att_get_value(param->handle, &len, &data); // Inform APP. Allocate the URI value change indication struct hpss_header_ind *ind = KE_MSG_ALLOC(HPSS_HEADER_IND, hpss_env.con_info.appid, TASK_HPSS, hpss_header_ind); // Fill in the parameter structure ind->conhdl = gapc_get_conhdl(hpss_env.con_info.conidx); ind->char_code = HPS_HEADER_CHAR; ind->len = len; memcpy(&ind->header, data, len); ke_msg_send(ind); } } break; case HPS_BODY_CHAR: if ((param->length + param->offset) <= HPS_BODY_MAX_LEN) { // First part of the uri value if (param->offset == 0) { // Set value in the database attmdb_att_set_value(param->handle, param->length, (uint8_t *)¶m->value[0]); } else { // Complete the value stored in the database attmdb_att_update_value(param->handle, param->length, param->offset, (uint8_t *)¶m->value[0]); } if(param->last) { uint16_t len = 0; uint8_t *data = NULL; // Get complete uri value and length attmdb_att_get_value(param->handle, &len, &data); // Inform APP. Allocate the URI value change indication struct hpss_body_ind *ind = KE_MSG_ALLOC(HPSS_BODY_IND, hpss_env.con_info.appid, TASK_HPSS, hpss_body_ind); // Fill in the parameter structure ind->conhdl = gapc_get_conhdl(hpss_env.con_info.conidx); ind->char_code = HPS_BODY_CHAR; ind->len = len; memcpy(&ind->body, data, len); ke_msg_send(ind); } } break; case HPS_CNTL_PT_CHAR: if ((param->length + param->offset) <= HPS_CNTL_PT_MAX_LEN) { // First part of the uri value if (param->offset == 0) { // Set value in the database attmdb_att_set_value(param->handle, param->length, (uint8_t *)¶m->value[0]); } else { // Complete the value stored in the database attmdb_att_update_value(param->handle, param->length, param->offset, (uint8_t *)¶m->value[0]); } if(param->last) { uint16_t len = 0; uint8_t *data = NULL; // Get complete uri value and length attmdb_att_get_value(param->handle, &len, &data); // Inform APP. Allocate the URI value change indication struct hpss_cntl_pt_ind *ind = KE_MSG_ALLOC(HPSS_CNTL_PT_IND, hpss_env.con_info.appid, TASK_HPSS, hpss_cntl_pt_ind); // Fill in the parameter structure ind->conhdl = gapc_get_conhdl(hpss_env.con_info.conidx); ind->char_code = HPS_CNTL_PT_CHAR; ind->len = len; memcpy(&ind->cntl_pt, data, len); ke_msg_send(ind); } } break; default: break; } //If HPS, send write response if (param->response != 0x00) { // Send Write Response atts_write_rsp_send(hpss_env.con_info.conidx, param->handle, status); } } } return (KE_MSG_CONSUMED); }
/** **************************************************************************************** * @brief Handles reception of the @ref GL2C_CODE_ATT_WR_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 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) { // Update the attribute value attmdb_att_update_value(param->handle, param->length, param->offset, (uint8_t*)&(param->value[0])); switch (ACCEL_IDX(param->handle)) { case ACCEL_IDX_ENABLE_VAL: { uint16_t len; uint8_t* accel_en; uint8_t* axis_en; uint8_t* range; if(*(uint8_t*)&(param->value[0]) > 1) accel_threshold = *(uint8_t*)&(param->value[0]) - 2; // set_accel_thr(); attmdb_att_get_value(ACCEL_HANDLE(ACCEL_IDX_ENABLE_VAL), &(len), &(accel_en)); // Indicate to the application the state of the profile if (accel_en) { // Allocate the start indication message struct accel_start_ind *ind = KE_MSG_ALLOC(ACCEL_START_IND, accel_env.con_info.appid, dest_id, accel_start_ind); // Fill in the parameter structure for (int i = 0; i < ACCEL_MAX; i++) { attmdb_att_get_value(ACCEL_DIR_VAL_HANDLE(i), &(len), &(axis_en)); ind->accel_en[i] = *axis_en; } attmdb_att_get_value(ACCEL_HANDLE(ACCEL_IDX_RANGE_VAL), &(len), &(range)); ind->range = *range; // Send the message ke_msg_send(ind); } else { // Send the stop indication ke_msg_send_basic(ACCEL_STOP_IND, accel_env.con_info.appid, TASK_ACCEL); } } break; case ACCEL_IDX_ACCEL_DISPLAY1_VAL: case ACCEL_IDX_ACCEL_DISPLAY2_VAL: if(*(uint8_t*)&(param->value[0]) == 0xFF) { if(param->length > 1 && *(uint8_t*)&(param->value[1]) > 1) accel_con_interval = *(uint8_t*)&(param->value[1]); if(param->length > 2 && *(uint8_t*)&(param->value[2]) > 1) accel_mode = *(uint8_t*)&(param->value[2])-2; if(param->length > 3 && *(uint8_t*)&(param->value[3]) > 1) accel_latency = *(uint8_t*)&(param->value[3])-2; if(param->length > 4 && *(uint8_t*)&(param->value[4]) > 1) accel_window = *(uint8_t*)&(param->value[4]); } { uint8_t line; uint16_t len; uint8_t* display; struct accel_write_line_ind *ind = KE_MSG_ALLOC(ACCEL_WRITE_LINE_IND, accel_env.con_info.appid, TASK_ACCEL, accel_write_line_ind); line = (param->handle == ACCEL_HANDLE(ACCEL_IDX_ACCEL_DISPLAY1_VAL))?0:1; attmdb_att_get_value(param->handle, &(len), &(display)); // Fill in the parameter structure memcpy(ind->text, display, len); ind->line = line; // Send the message ke_msg_send(ind); } atts_write_rsp_send(accel_env.con_info.conidx, param->handle, PRF_ERR_OK); break; case ACCEL_IDX_ACCEL_X_VAL: case ACCEL_IDX_ACCEL_X_EN: if(*(uint8_t*)&(param->value[0]) > 1) accel_adv_interval1 = *(uint8_t*)&(param->value[0]); atts_write_rsp_send(accel_env.con_info.conidx, param->handle, PRF_ERR_OK); break; case ACCEL_IDX_ACCEL_Y_VAL: case ACCEL_IDX_ACCEL_Y_EN: if(*(uint8_t*)&(param->value[0]) > 1) accel_adv_interval2 = *(uint8_t*)&(param->value[0]); if(*(uint8_t*)&(param->value[0]) == 255) accel_adv_interval2 = 0; atts_write_rsp_send(accel_env.con_info.conidx, param->handle, PRF_ERR_OK); break; case ACCEL_IDX_ACCEL_Z_VAL: case ACCEL_IDX_ACCEL_Z_EN: if(*(uint8_t*)&(param->value[0]) > 1) accel_adv_interval3 = *(uint8_t*)&(param->value[0]); if(*(uint8_t*)&(param->value[0]) == 255) accel_adv_interval3 = 0; atts_write_rsp_send(accel_env.con_info.conidx, param->handle, PRF_ERR_OK); break; default: atts_write_rsp_send(accel_env.con_info.conidx, param->handle, PRF_ERR_OK); break; } return (KE_MSG_CONSUMED); }
/** **************************************************************************************** * @brief Handles reception of the @ref GL2C_CODE_ATT_WR_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 gattc_write_cmd_ind_handler(ke_msg_id_t const msgid, struct gattc_write_cmd_ind const *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { uint16_t value = 0x0000; uint8_t status = PRF_ERR_OK; if (KE_IDX_GET(src_id) == hrps_env.con_info.conidx) { //BP Measurement Char. - Client Char. Configuration if (param->handle == (hrps_env.shdl + HRS_IDX_HR_MEAS_NTF_CFG)) { //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) { hrps_env.features &= ~HRPS_HR_MEAS_NTF_CFG; } else //PRF_CLI_START_NTF { hrps_env.features |= HRPS_HR_MEAS_NTF_CFG; } } else { status = PRF_APP_ERROR; } if (status == PRF_ERR_OK) { //Update the attribute value attmdb_att_set_value(param->handle, sizeof(uint16_t), (uint8_t *)&value); if(param->last) { //Inform APP of configuration change struct hrps_cfg_indntf_ind * ind = KE_MSG_ALLOC(HRPS_CFG_INDNTF_IND, hrps_env.con_info.appid, TASK_HRPS, hrps_cfg_indntf_ind); ind->conhdl = gapc_get_conhdl(hrps_env.con_info.conidx); memcpy(&ind->cfg_val, &value, sizeof(uint16_t)); ke_msg_send(ind); } } } //HR Control Point Char. Value else { if (HRPS_IS_SUPPORTED(HRPS_ENGY_EXP_FEAT_SUP)) { //Extract value memcpy(&value, &(param->value), sizeof(uint8_t)); if (value == 0x1) { //inform APP of configuration change struct hrps_energy_exp_reset_ind * ind = KE_MSG_ALLOC(HRPS_ENERGY_EXP_RESET_IND, hrps_env.con_info.appid, TASK_HRPS, hrps_energy_exp_reset_ind); ind->conhdl = gapc_get_conhdl(hrps_env.con_info.conidx); ke_msg_send(ind); } else { status = HRS_ERR_HR_CNTL_POINT_NOT_SUPPORTED; } } else { //Allowed to send Application Error if value inconvenient status = HRS_ERR_HR_CNTL_POINT_NOT_SUPPORTED; } } } //Send write response atts_write_rsp_send(hrps_env.con_info.conidx, 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) { uint16_t value = 0x0000; uint8_t status = PRF_ERR_OK; uint8_t char_code = 0; if (param->conhdl == blps_env.con_info.conhdl) { //Extract value before check memcpy(&value, &(param->value), sizeof(uint16_t)); //BP Measurement Char. - Client Char. Configuration if (param->handle == (blps_env.shdl + BPS_IDX_BP_MEAS_IND_CFG)) { if ((value == PRF_CLI_STOP_NTFIND) || (value == PRF_CLI_START_IND)) { char_code = BPS_BP_MEAS_CODE; if (value == PRF_CLI_STOP_NTFIND) { blps_env.evt_cfg &= ~BLPS_BP_MEAS_IND_CFG; } else //PRF_CLI_START_IND { blps_env.evt_cfg |= BLPS_BP_MEAS_IND_CFG; } } else { status = PRF_APP_ERROR; } } else if (param->handle == (blps_env.shdl + BPS_IDX_INTM_CUFF_PRESS_NTF_CFG)) { if ((value == PRF_CLI_STOP_NTFIND) || (value == PRF_CLI_START_NTF)) { char_code = BPS_INTERM_CP_CODE; if (value == PRF_CLI_STOP_NTFIND) { blps_env.evt_cfg &= ~BLPS_INTM_CUFF_PRESS_NTF_CFG; } else //PRF_CLI_START_NTF { blps_env.evt_cfg |= BLPS_INTM_CUFF_PRESS_NTF_CFG; } } else { status = PRF_APP_ERROR; } } if (status == PRF_ERR_OK) { //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 blps_cfg_indntf_ind * ind = KE_MSG_ALLOC(BLPS_CFG_INDNTF_IND, blps_env.con_info.appid, TASK_BLPS, blps_cfg_indntf_ind); memcpy(&ind->conhdl, &blps_env.con_info.conhdl, sizeof(uint16_t)); ind->char_code = char_code; memcpy(&ind->cfg_val, &value, sizeof(uint16_t)); ke_msg_send(ind); } } } //Send write response atts_write_rsp_send(blps_env.con_info.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_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); }
/** **************************************************************************************** * @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); }