/** **************************************************************************************** * @brief Handles reception of the @ref QPPC_RD_CHAR_REQ message. * Check if the handle exists in profile(already discovered) and send request, otherwise * error to APP. * @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 qppc_rd_char_req_handler(ke_msg_id_t const msgid, struct qppc_rd_char_req const *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { uint16_t search_hdl = ATT_INVALID_SEARCH_HANDLE; // Get the address of the environment struct qppc_env_tag *qppc_env = PRF_CLIENT_GET_ENV(dest_id, qppc); if (param->conhdl == qppc_env->con_info.conhdl && param->char_code < qppc_env->nb_char) { qppc_env->last_char_code = param->char_code; search_hdl = qppc_env->qpps.descs[param->char_code].desc_hdl; //check if handle is variable if (search_hdl != ATT_INVALID_SEARCH_HANDLE) { prf_read_char_send(&(qppc_env->con_info), qppc_env->qpps.svc.shdl, qppc_env->qpps.svc.ehdl, search_hdl); } else { qppc_error_ind_send(qppc_env, PRF_ERR_INEXISTENT_HDL); } } else { qppc_error_ind_send(qppc_env, PRF_ERR_INVALID_PARAM); } return (KE_MSG_CONSUMED); }
/** **************************************************************************************** * @brief Handles reception of the @ref PROXM_RD_ALERT_LVL_REQ message. * Request to read the LLS 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 proxm_rd_alert_lvl_req_handler(ke_msg_id_t const msgid, struct proxm_rd_alert_lvl_req const *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { // Get the address of the environment struct proxm_env_tag *proxm_env = PRF_CLIENT_GET_ENV(dest_id, proxm); // Save the read characteristic code proxm_env->last_char_code = PROXM_RD_LL_ALERT_LVL; if(param->conhdl == gapc_get_conhdl(proxm_env->con_info.conidx)) { if(proxm_env->lls.charact.val_hdl != ATT_INVALID_HANDLE) { // Send Read Char. request prf_read_char_send(&proxm_env->con_info, proxm_env->lls.svc.shdl, proxm_env->lls.svc.ehdl, proxm_env->lls.charact.val_hdl); } else { prf_client_att_info_rsp((prf_env_struct*) proxm_env, PROXM_RD_CHAR_RSP, PRF_ERR_INEXISTENT_HDL, NULL); } } else { // Wrong connection handle prf_client_att_info_rsp((prf_env_struct*) proxm_env, PROXM_RD_CHAR_RSP, PRF_ERR_INVALID_PARAM, NULL); } return (KE_MSG_CONSUMED); }
/** **************************************************************************************** * @brief Handles reception of the @ref GLPC_READ_FEATURES_REQ message. * Send by application task, it's used to retrieve Glucose Sensor features. * * @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 glpc_read_features_req_handler(ke_msg_id_t const msgid, struct glpc_read_features_req 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); uint8_t status = glpc_validate_request(glpc_env, param->conhdl, GLPC_CHAR_FEATURE); // request can be performed if(status == PRF_ERR_OK) { // read glucose sensor feature prf_read_char_send(&(glpc_env->con_info), glpc_env->gls.svc.shdl, glpc_env->gls.svc.ehdl, glpc_env->gls.chars[GLPC_CHAR_FEATURE].val_hdl); } // send command response with error code else { 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 error status rsp->conhdl = param->conhdl; rsp->status = status; ke_msg_send(rsp); } return (KE_MSG_CONSUMED); }
/** **************************************************************************************** * @brief Handles reception of the @ref HOGPBH_RD_CHAR_REQ message. * @param[in] msgid Id of the message received (probably unused). * @param[in] param Pointer to the parameters of the message. * @param[in] dest_id ID of the receiving task instance (probably unused). * @param[in] src_id ID of the sending task instance. * @return If the message was consumed or not. **************************************************************************************** */ static int hogpbh_rd_char_req_handler(ke_msg_id_t const msgid, struct hogpbh_rd_char_req const *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { // Status uint8_t status = PRF_ERR_OK; // Attribute handle uint16_t search_hdl = ATT_INVALID_SEARCH_HANDLE; // Get the address of the environment struct hogpbh_env_tag *hogpbh_env = PRF_CLIENT_GET_ENV(dest_id, hogpbh); // Save the attribute read code hogpbh_env->last_char_code = param->char_code; if((param->conhdl == hogpbh_env->con_info.conhdl) && (param->hids_nb < HOGPBH_NB_HIDS_INST_MAX)) { // Descriptor if(((param->char_code & HOGPBH_DESC_MASK) == HOGPBH_DESC_MASK) && ((param->char_code & ~HOGPBH_DESC_MASK) < HOGPBH_DESC_MASK)) { search_hdl = hogpbh_env->hids[param->hids_nb].descs[param->char_code & ~HOGPBH_DESC_MASK].desc_hdl; } // Characteristic else if (param->char_code < HOGPBH_CHAR_MAX) { search_hdl = hogpbh_env->hids[param->hids_nb].chars[param->char_code].val_hdl; } // Check if handle is viable if (search_hdl != ATT_INVALID_SEARCH_HANDLE) { prf_read_char_send(&(hogpbh_env->con_info), hogpbh_env->hids[param->hids_nb].svc.shdl, hogpbh_env->hids[param->hids_nb].svc.ehdl, search_hdl); // Save the service instance number hogpbh_env->last_svc_inst_req = param->hids_nb; } else { status = PRF_ERR_INEXISTENT_HDL; } } else { status = PRF_ERR_INVALID_PARAM; } if (status != PRF_ERR_OK) { hogpbh_char_req_rsp_send(hogpbh_env, HOGPBH_RD_CHAR_ERR_RSP, status); } return (KE_MSG_CONSUMED); }
/** **************************************************************************************** * @brief Handles reception of the @ref STREAMDATAH_STREAMON_REQ message. * Turns on the stream by writing a nonzero value to the STREAMDATAD_ENABLE attribute. * @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 streamdatah_rd_streamon_enable_req_handler(ke_msg_id_t const msgid, struct streamdatah_rd_streamon_enable_req const *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { // Get the address of the environment struct streamdatah_env_tag *streamdatah_env = PRF_CLIENT_GET_ENV(dest_id, streamdatah); prf_read_char_send(&streamdatah_env->con_info, streamdatah_env->streamdatad.svc.shdl, streamdatah_env->streamdatad.svc.ehdl, streamdatah_env->streamdatad.chars[STREAMDATAD_ENABLE_CHAR].val_hdl); return (KE_MSG_CONSUMED); }
/** **************************************************************************************** * @brief Handles reception of the @ref HTPC_RD_DATETIME_REQ message. * Check if the handle exists in profile(already discovered) and send request, otherwise * error to APP. * @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 htpc_rd_char_req_handler(ke_msg_id_t const msgid, struct htpc_rd_char_req const *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { // Attribute handle uint16_t search_hdl = ATT_INVALID_SEARCH_HANDLE; // Get the address of the environment struct htpc_env_tag *htpc_env = PRF_CLIENT_GET_ENV(dest_id, htpc); if(param->conhdl == gapc_get_conhdl(htpc_env->con_info.conidx)) { // Descriptors if(((param->char_code & HTPC_DESC_HTS_MASK) == HTPC_DESC_HTS_MASK) && ((param->char_code & ~HTPC_DESC_HTS_MASK) < HTPC_DESC_HTS_MAX)) { search_hdl = htpc_env->hts.descs[param->char_code & ~HTPC_DESC_HTS_MASK].desc_hdl; } // Characteristic else if (param->char_code < HTPC_CHAR_HTS_MAX) { search_hdl = htpc_env->hts.chars[param->char_code].val_hdl; } // Check if handle is viable if (search_hdl != ATT_INVALID_SEARCH_HANDLE) { htpc_env->last_char_code = param->char_code; prf_read_char_send(&(htpc_env->con_info), htpc_env->hts.svc.shdl, htpc_env->hts.svc.ehdl, search_hdl); } else { prf_client_att_info_rsp((prf_env_struct*) htpc_env, HTPC_RD_CHAR_RSP, PRF_ERR_INEXISTENT_HDL, NULL); } } else { prf_client_att_info_rsp((prf_env_struct*) htpc_env, HTPC_RD_CHAR_RSP, PRF_ERR_INVALID_PARAM, NULL); } return (KE_MSG_CONSUMED); }
/** **************************************************************************************** * @brief Handles reception of the @ref BASC_CHAR_RD_REQ message. * @param[in] msgid Id of the message received (probably unused). * @param[in] param Pointer to the parameters of the message. * @param[in] dest_id ID of the receiving task instance (probably unused). * @param[in] src_id ID of the sending task instance. * @return If the message was consumed or not. **************************************************************************************** */ static int basc_char_rd_req_handler(ke_msg_id_t const msgid, struct basc_char_rd_req const *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { uint16_t search_hdl = ATT_INVALID_SEARCH_HANDLE; // Get the address of the environment struct basc_env_tag *basc_env = PRF_CLIENT_GET_ENV(dest_id, basc); // Check Connection Handle, BAS Instance if((param->conhdl == basc_env->con_info.conhdl) && (param->bas_nb < BASC_NB_BAS_INSTANCES_MAX)) { //Battery Level Service Descriptor if(((param->char_code & BAS_DESC_MASK) == BAS_DESC_MASK) && ((param->char_code & ~BAS_DESC_MASK) < BAS_DESC_MASK)) { search_hdl = basc_env->bas[param->bas_nb].descs[param->char_code & ~BAS_DESC_MASK].desc_hdl; } //Battery Service Characteristic else if (param->char_code < BAS_CHAR_MAX) { search_hdl = basc_env->bas[param->bas_nb].chars[param->char_code].val_hdl; } // Check if handle is viable if (search_hdl != ATT_INVALID_SEARCH_HANDLE) { prf_read_char_send(&(basc_env->con_info), basc_env->bas[param->bas_nb].svc.shdl, basc_env->bas[param->bas_nb].svc.ehdl, search_hdl); // Save the service instance number basc_env->last_svc_inst_req = param->bas_nb; // Save the attribute read code basc_env->last_char_code = param->char_code; } else { basc_error_ind_send(basc_env, PRF_ERR_INEXISTENT_HDL); } } else { basc_error_ind_send(basc_env, PRF_ERR_INVALID_PARAM); } return (KE_MSG_CONSUMED); }
/** **************************************************************************************** * @brief Handles reception of the @ref BLPC_RD_DATETIME_REQ message. * Check if the handle exists in profile(already discovered) and send request, otherwise * error to APP. * @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 blpc_rd_char_req_handler(ke_msg_id_t const msgid, struct blpc_rd_char_req const *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { uint16_t search_hdl = 0x0000; uint16_t shdl = 0x0000; uint16_t ehdl = 0x0000; // Get the address of the environment struct blpc_env_tag *blpc_env = PRF_CLIENT_GET_ENV(dest_id, blpc); if(param->conhdl == gapc_get_conhdl(blpc_env->con_info.conidx)) { if((param->char_code & BLPC_DESC_MASK) == BLPC_DESC_MASK) { search_hdl = blpc_env->bps.descs[param->char_code & ~BLPC_DESC_MASK].desc_hdl; shdl = blpc_env->bps.svc.shdl; ehdl = blpc_env->bps.svc.ehdl; } else { search_hdl = blpc_env->bps.chars[param->char_code].val_hdl; shdl = blpc_env->bps.svc.shdl; ehdl = blpc_env->bps.svc.ehdl; } //check if handle is viable if (search_hdl != ATT_INVALID_SEARCH_HANDLE) { prf_read_char_send(&(blpc_env->con_info), shdl, ehdl, search_hdl); } else { prf_client_att_info_rsp((prf_env_struct*) blpc_env, BLPC_RD_CHAR_RSP, PRF_ERR_INEXISTENT_HDL, NULL); } } else { prf_client_att_info_rsp((prf_env_struct*) blpc_env, BLPC_RD_CHAR_RSP, PRF_ERR_INVALID_PARAM, NULL); } return (KE_MSG_CONSUMED); }
/** **************************************************************************************** * @brief Handles reception of the @ref HRPC_RD_DATETIME_REQ message. * Check if the handle exists in profile(already discovered) and send request, otherwise * error to APP. * @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 hrpc_rd_char_req_handler(ke_msg_id_t const msgid, struct hrpc_rd_char_req const *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { uint16_t search_hdl = ATT_INVALID_SEARCH_HANDLE; // Get the address of the environment struct hrpc_env_tag *hrpc_env = PRF_CLIENT_GET_ENV(dest_id, hrpc); if(param->conhdl == hrpc_env->con_info.conhdl) { if(((param->char_code & HRPC_DESC_MASK) == HRPC_DESC_MASK) && ((param->char_code & ~HRPC_DESC_MASK) < HRPC_DESC_MAX)) { search_hdl = hrpc_env->hrs.descs[param->char_code & ~HRPC_DESC_MASK].desc_hdl; } else if (param->char_code < HRPC_CHAR_MAX) { search_hdl = hrpc_env->hrs.chars[param->char_code].val_hdl; } //check if handle is viable if (search_hdl != ATT_INVALID_SEARCH_HANDLE) { hrpc_env->last_char_code = param->char_code; prf_read_char_send(&(hrpc_env->con_info), hrpc_env->hrs.svc.shdl, hrpc_env->hrs.svc.ehdl, search_hdl); } else { hrpc_error_ind_send(hrpc_env, PRF_ERR_INEXISTENT_HDL); } } else { hrpc_error_ind_send(hrpc_env, PRF_ERR_INVALID_PARAM); } return (KE_MSG_CONSUMED); }
/** **************************************************************************************** * @brief Handles reception of the @ref SCPPC_SCAN_REFRESH_NTF_CFG_RD_REQ message. * @param[in] msgid Id of the message received (probably unused). * @param[in] param Pointer to the parameters of the message. * @param[in] dest_id ID of the receiving task instance (probably unused). * @param[in] src_id ID of the sending task instance. * @return If the message was consumed or not. **************************************************************************************** */ static int scppc_scan_refresh_ntf_cfg_rd_req_handler(ke_msg_id_t const msgid, struct scppc_scan_refresh_ntf_cfg_rd_req const *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { // Get the address of the environment struct scppc_env_tag *scppc_env = PRF_CLIENT_GET_ENV(dest_id, scppc); if (param->conhdl == gapc_get_conhdl(scppc_env->con_info.conidx)) { scppc_env->last_char_code = SCPPC_DESC_SCAN_REFRESH_CFG; prf_read_char_send(&(scppc_env->con_info), scppc_env->scps.svc.shdl, scppc_env->scps.svc.ehdl, scppc_env->scps.descs[SCPPC_DESC_SCAN_REFRESH_CFG].desc_hdl); } else { scppc_error_ind_send(scppc_env, PRF_ERR_INVALID_PARAM); } return (KE_MSG_CONSUMED); }
/** **************************************************************************************** * @brief Handles reception of the @ref TIPC_RD_CHAR_REQ message. * Check if the handle exists in profile(already discovered) and send request, otherwise * error to APP. * @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 tipc_rd_char_req_handler(ke_msg_id_t const msgid, struct tipc_rd_char_req const *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { // Attribute Handle uint16_t search_hdl = ATT_INVALID_SEARCH_HANDLE; // Service struct prf_svc *svc; // Get the address of the environment struct tipc_env_tag *tipc_env = PRF_CLIENT_GET_ENV(dest_id, tipc); if(param->conhdl == gapc_get_conhdl(tipc_env->con_info.conidx)) { //Next DST Change Service Characteristic if (((param->char_code & TIPC_CHAR_NDCS_MASK) == TIPC_CHAR_NDCS_MASK) && ((param->char_code & ~TIPC_CHAR_NDCS_MASK) < TIPC_CHAR_NDCS_MAX)) { svc = &tipc_env->ndcs.svc; search_hdl = tipc_env->ndcs.chars[param->char_code & ~TIPC_CHAR_NDCS_MASK].val_hdl; } //Reference Time Update Service Characteristic else if (((param->char_code & TIPC_CHAR_RTUS_MASK) == TIPC_CHAR_RTUS_MASK) && ((param->char_code & ~TIPC_CHAR_RTUS_MASK) < TIPC_CHAR_RTUS_MAX)) { svc = &tipc_env->rtus.svc; search_hdl = tipc_env->rtus.chars[param->char_code & ~TIPC_CHAR_RTUS_MASK].val_hdl; } else { svc = &tipc_env->cts.svc; //Current Time Characteristic Descriptor if (((param->char_code & TIPC_DESC_CTS_MASK) == TIPC_DESC_CTS_MASK) && ((param->char_code & ~TIPC_DESC_CTS_MASK) < TIPC_DESC_CTS_MAX)) { search_hdl = tipc_env->cts.descs[param->char_code & ~TIPC_DESC_CTS_MASK].desc_hdl; } //Current Time Service Characteristic else if (param->char_code < TIPC_CHAR_CTS_MAX) { search_hdl = tipc_env->cts.chars[param->char_code].val_hdl; } } // Check if handle is viable if (search_hdl != ATT_INVALID_SEARCH_HANDLE) { tipc_env->last_char_code = param->char_code; prf_read_char_send(&(tipc_env->con_info), svc->shdl, svc->ehdl, search_hdl); } else { tipc_error_ind_send(tipc_env, PRF_ERR_INEXISTENT_HDL); } } else { tipc_error_ind_send(tipc_env, PRF_ERR_INVALID_PARAM); } return (KE_MSG_CONSUMED); }
/** **************************************************************************************** * @brief Handles reception of the @ref CSCPC_READ_CMD message. * @param[in] msgid Id of the message received. * @param[in] param Pointer to the parameters of the message. * @param[in] dest_id ID of the receiving task instance. * @param[in] src_id ID of the sending task instance. * @return If the message was consumed or not. **************************************************************************************** */ static int cscpc_read_cmd_handler(ke_msg_id_t const msgid, struct cscpc_read_cmd *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { // Message status uint8_t msg_status = KE_MSG_CONSUMED; // Get the address of the environment struct cscpc_env_tag *cscpc_env = PRF_CLIENT_GET_ENV(dest_id, cscpc); if (cscpc_env != NULL) { // Attribute Handle uint16_t handle = ATT_INVALID_SEARCH_HANDLE; // Status uint8_t status = PRF_ERR_OK; ASSERT_ERR(ke_state_get(dest_id) != CSCPC_IDLE); // Check the provided connection handle if (param->conhdl == cscpc_env->con_info.conhdl) { // Check the current state if (ke_state_get(dest_id) == CSCPC_BUSY) { // Keep the request for later msg_status = KE_MSG_SAVED; } else // State is CSCPC_CONNECTED { ASSERT_ERR(cscpc_env->operation == NULL); switch (param->read_code) { // Read CSC Feature case (CSCPC_RD_CSC_FEAT): { handle = cscpc_env->cscs.chars[CSCP_CSCS_CSC_FEAT_CHAR].val_hdl; } break; // Read Sensor Location case (CSCPC_RD_SENSOR_LOC): { handle = cscpc_env->cscs.chars[CSCP_CSCS_SENSOR_LOC_CHAR].val_hdl; } break; // Read CSC Measurement Characteristic Client Char. Cfg. Descriptor Value case (CSCPC_RD_WR_CSC_MEAS_CFG): { handle = cscpc_env->cscs.descs[CSCPC_DESC_CSC_MEAS_CL_CFG].desc_hdl; } break; // Read Unread Alert Characteristic Client Char. Cfg. Descriptor Value case (CSCPC_RD_WR_SC_CTNL_PT_CFG): { handle = cscpc_env->cscs.descs[CSCPC_DESC_SC_CTNL_PT_CL_CFG].desc_hdl; } break; default: { status = PRF_ERR_INVALID_PARAM; } break; } // Check if handle is viable if (handle != ATT_INVALID_SEARCH_HANDLE) { // Force the operation value param->operation = CSCPC_READ_OP_CODE; // Store the command structure cscpc_env->operation = param; msg_status = KE_MSG_NO_FREE; // Send the read request prf_read_char_send(&(cscpc_env->con_info), cscpc_env->cscs.svc.shdl, cscpc_env->cscs.svc.ehdl, handle); // Go to the Busy state ke_state_set(dest_id, CSCPC_BUSY); } else { status = PRF_ERR_INEXISTENT_HDL; } } } else { status = PRF_ERR_INVALID_PARAM; } if (status != PRF_ERR_OK) { // Send the complete event message to the task id stored in the environment cscpc_send_cmp_evt(cscpc_env, CSCPC_READ_OP_CODE, status); } } else { // No connection exists, send the status to the requester cscpc_send_no_conn_cmp_evt(dest_id, src_id, param->conhdl, CSCPC_READ_OP_CODE); } return (int)msg_status; }
/** **************************************************************************************** * @brief Handles reception of the @ref ANPC_ENABLE_CMD message. * @param[in] msgid Id of the message received. * @param[in] param Pointer to the parameters of the message. * @param[in] dest_id ID of the receiving task instance. * @param[in] src_id ID of the sending task instance. * @return If the message was consumed or not. **************************************************************************************** */ static int anpc_enable_cmd_handler(ke_msg_id_t const msgid, struct anpc_enable_cmd *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { // Status uint8_t status = PRF_ERR_OK; // Message status uint8_t msg_status = KE_MSG_CONSUMED; // Alert Notification Profile Client Role Task Environment struct anpc_env_tag *anpc_env; // Connection Information struct prf_con_info con_info; // Check if the provided connection handle is valid if (gapc_get_conidx(param->conhdl) != GAP_INVALID_CONIDX) { // Fill the Connection Information structure con_info.conidx = gapc_get_conidx(param->conhdl); con_info.prf_id = dest_id; con_info.appid = src_id; // Add an environment for the provided connection status = PRF_CLIENT_ENABLE(con_info, param, anpc); } else { status = PRF_ERR_REQ_DISALLOWED; } if (status == PRF_ERR_OK) { // Get the newly created environment anpc_env = PRF_CLIENT_GET_ENV(dest_id, anpc); // Keep the connection info memcpy(&anpc_env->con_info, &con_info, sizeof(struct prf_con_info)); // Start discovering if (param->con_type == PRF_CON_DISCOVERY) { // Configure the environment for a discovery procedure anpc_env->last_req = ATT_SVC_ALERT_NTF; // Force the operation value param->operation = ANPC_ENABLE_OP_CODE; prf_disc_svc_send(&(anpc_env->con_info), ATT_SVC_ALERT_NTF); } // Bond information are provided else { // Keep the provided database content memcpy(&anpc_env->ans, ¶m->ans, sizeof(struct anpc_ans_content)); // Register in GATT for notifications/indications prf_register_atthdl2gatt(&anpc_env->con_info, &anpc_env->ans.svc); // Force the operation value param->operation = ANPC_ENABLE_RD_NEW_ALERT_OP_CODE; // Check Supported New Alert Category prf_read_char_send(&(anpc_env->con_info), anpc_env->ans.svc.shdl, anpc_env->ans.svc.ehdl, anpc_env->ans.chars[ANPC_CHAR_SUP_NEW_ALERT_CAT].val_hdl); } // Keep the operation anpc_env->operation = (void *)param; // Do not free the message msg_status = KE_MSG_NO_FREE; // Go to BUSY state ke_state_set(dest_id, ANPC_BUSY); } else if (status == PRF_ERR_FEATURE_NOT_SUPPORTED) { // The message will be forwarded towards the good task instance msg_status = KE_MSG_NO_FREE; } else { // The request is disallowed (profile already enabled for this connection, or not enough memory, ...) anpc_send_no_conn_cmp_evt(dest_id, src_id, param->conhdl, ANPC_ENABLE_OP_CODE); } return (int)msg_status; }
/** **************************************************************************************** * @brief Handles reception of the @ref GATTC_CMP_EVT message. * @param[in] msgid Id of the message received. * @param[in] param Pointer to the parameters of the message. * @param[in] dest_id ID of the receiving task instance. * @param[in] src_id ID of the sending task instance. * @return If the message was consumed or not. **************************************************************************************** */ static int gattc_cmp_evt_handler(ke_msg_id_t const msgid, struct gattc_cmp_evt const *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { // Get the address of the environment struct anpc_env_tag *anpc_env = PRF_CLIENT_GET_ENV(dest_id, anpc); if (anpc_env != NULL) { switch (param->req_type) { case (GATTC_DISC_BY_UUID_SVC): case (GATTC_DISC_ALL_CHAR): case (GATTC_DISC_DESC_CHAR): { // Status uint8_t status = PRF_ERR_STOP_DISC_CHAR_MISSING; if ((param->status == ATT_ERR_ATTRIBUTE_NOT_FOUND) || (param->status == ATT_ERR_NO_ERROR)) { ASSERT_ERR(((struct anpc_cmd *)anpc_env->operation)->operation == ANPC_ENABLE_OP_CODE); /* ------------------------------------------------- * SERVICE DISCOVERY ------------------------------- * ------------------------------------------------- */ if (anpc_env->last_req == ATT_SVC_ALERT_NTF) { if (anpc_env->nb_svc > 0) { // Check if service handles are OK if ((anpc_env->ans.svc.shdl != ATT_INVALID_HANDLE) && (anpc_env->ans.svc.ehdl != ATT_INVALID_HANDLE) && (anpc_env->ans.svc.shdl < anpc_env->ans.svc.ehdl)) { // Status is OK status = PRF_ERR_OK; // Discover all ANS characteristics prf_disc_char_all_send(&(anpc_env->con_info), &(anpc_env->ans.svc)); anpc_env->last_req = ATT_DECL_CHARACTERISTIC; } // Handles are not corrects, the Phone Alert Status Service has not been found, stop } // The Phone Alert Status Service has not been found, stop discovery } /* ------------------------------------------------- * CHARACTERISTICS DISCOVERY ----------------------- * ------------------------------------------------- */ else if (anpc_env->last_req == ATT_DECL_CHARACTERISTIC) { // Check if mandatory properties have been found and if properties are correct status = prf_check_svc_char_validity(ANPC_CHAR_MAX, anpc_env->ans.chars, anpc_ans_char); // Check for characteristic properties. if (status == PRF_ERR_OK) { anpc_env->last_req = ANPC_CHAR_NEW_ALERT; // Find the Client Characteristic Configuration Descriptor for the New Alert characteristic prf_disc_char_desc_send(&(anpc_env->con_info), &(anpc_env->ans.chars[ANPC_CHAR_NEW_ALERT])); } } /* ------------------------------------------------- * DESCRIPTORS DISCOVERY --------------------------- * ------------------------------------------------- */ else { if (anpc_env->last_req == ANPC_CHAR_NEW_ALERT) { status = PRF_ERR_OK; anpc_env->last_req = ANPC_CHAR_UNREAD_ALERT_STATUS; // Find the Client Characteristic Configuration Descriptor for the Unread Alert Status characteristic prf_disc_char_desc_send(&(anpc_env->con_info), &(anpc_env->ans.chars[ANPC_CHAR_UNREAD_ALERT_STATUS])); } else if (anpc_env->last_req == ANPC_CHAR_UNREAD_ALERT_STATUS) { status = prf_check_svc_char_desc_validity(ANPC_DESC_MAX, anpc_env->ans.descs, anpc_ans_char_desc, anpc_env->ans.chars); if (status == PRF_ERR_OK) { // Reset number of services anpc_env->nb_svc = 0; // Register in GATT for notifications/indications prf_register_atthdl2gatt(&anpc_env->con_info, &anpc_env->ans.svc); // Send the content of the service to the HL struct anpc_ans_content_ind *ind = KE_MSG_ALLOC(ANPC_ANS_CONTENT_IND, anpc_env->con_info.appid, anpc_env->con_info.prf_id, anpc_ans_content_ind); ind->conhdl = gapc_get_conhdl(anpc_env->con_info.conidx); memcpy(&ind->ans, &anpc_env->ans, sizeof(struct anpc_ans_content)); // Send the message ke_msg_send(ind); // Force the operation value ((struct anpc_enable_cmd *)anpc_env->operation)->operation = ANPC_ENABLE_RD_NEW_ALERT_OP_CODE; // Check Supported New Alert Categories prf_read_char_send(&(anpc_env->con_info), anpc_env->ans.svc.shdl, anpc_env->ans.svc.ehdl, anpc_env->ans.chars[ANPC_CHAR_SUP_NEW_ALERT_CAT].val_hdl); } } else { ASSERT_ERR(0); } } } else { status = param->status; } if (status != PRF_ERR_OK) { // Stop discovery procedure. anpc_send_cmp_evt(anpc_env, ANPC_ENABLE_OP_CODE, status); } } break; case (GATTC_WRITE): { // Retrieve the operation currently performed uint8_t operation = ((struct anpc_cmd *)anpc_env->operation)->operation; switch (operation) { case (ANPC_WRITE_OP_CODE): { uint8_t wr_code = ((struct anpc_write_cmd *)anpc_env->operation)->write_code; if ((wr_code == ANPC_RD_WR_NEW_ALERT_CFG) || (wr_code == ANPC_RD_WR_UNREAD_ALERT_STATUS_CFG) || (wr_code == ANPC_WR_ALERT_NTF_CTNL_PT)) { anpc_send_cmp_evt(anpc_env, ANPC_WRITE_OP_CODE, param->status); } else { ASSERT_ERR(0); } } break; case (ANPC_ENABLE_WR_NEW_ALERT_OP_CODE): { // Look for the next category to enable if (anpc_found_next_alert_cat(anpc_env, ((struct anpc_enable_cmd *)anpc_env->operation)->new_alert_enable)) { // Enable sending of notifications for the found category ID anpc_write_alert_ntf_ctnl_pt(anpc_env, CMD_ID_EN_NEW_IN_ALERT_NTF, anpc_env->last_req - 1); } else { // Force the operation value ((struct anpc_cmd *)anpc_env->operation)->operation = ANPC_ENABLE_WR_NTF_NEW_ALERT_OP_CODE; // Send a "Notify New Alert Immediately" command with the Category ID field set to 0xFF anpc_write_alert_ntf_ctnl_pt(anpc_env, CMD_ID_NTF_NEW_IN_ALERT_IMM, CAT_ID_ALL_SUPPORTED_CAT); } } break; case (ANPC_ENABLE_WR_NTF_NEW_ALERT_OP_CODE): { // Reset the environment anpc_env->last_req = CAT_ID_SPL_ALERT; if (anpc_found_next_alert_cat(anpc_env, ((struct anpc_enable_cmd *)anpc_env->operation)->unread_alert_enable)) { // Force the operation value ((struct anpc_cmd *)anpc_env->operation)->operation = ANPC_ENABLE_WR_UNREAD_ALERT_OP_CODE; // Enable sending of notifications for the found category ID anpc_write_alert_ntf_ctnl_pt(anpc_env, CMD_ID_EN_UNREAD_CAT_STATUS_NTF, anpc_env->last_req - 1); } else { anpc_send_cmp_evt(anpc_env, ANPC_ENABLE_OP_CODE, PRF_ERR_OK); } } break; case (ANPC_ENABLE_WR_UNREAD_ALERT_OP_CODE): { // Look for the next category to enable if (anpc_found_next_alert_cat(anpc_env, ((struct anpc_enable_cmd *)anpc_env->operation)->unread_alert_enable)) { // Enable sending of notifications for the found category ID anpc_write_alert_ntf_ctnl_pt(anpc_env, CMD_ID_EN_UNREAD_CAT_STATUS_NTF, anpc_env->last_req - 1); } else { // Force the operation value ((struct anpc_cmd *)anpc_env->operation)->operation = ANPC_ENABLE_WR_NTF_UNREAD_ALERT_OP_CODE; // Send a "Notify New Alert Immediately" command with the Category ID field set to 0xFF anpc_write_alert_ntf_ctnl_pt(anpc_env, CMD_ID_NTF_UNREAD_CAT_STATUS_IMM, CAT_ID_ALL_SUPPORTED_CAT); } } break; case (ANPC_ENABLE_WR_NTF_UNREAD_ALERT_OP_CODE): { // The discovery procedure is over anpc_send_cmp_evt(anpc_env, ANPC_ENABLE_OP_CODE, param->status); } break; default: { ASSERT_ERR(0); } break; } } break; case (GATTC_READ): { switch (((struct anpc_cmd *)anpc_env->operation)->operation) { // Read Supported New Alert Category Characteristic value case (ANPC_ENABLE_RD_NEW_ALERT_OP_CODE): { if (param->status == GATT_ERR_NO_ERROR) { // Force the operation value ((struct anpc_cmd *)anpc_env->operation)->operation = ANPC_ENABLE_RD_UNREAD_ALERT_OP_CODE; // Check Supported Unread Alert Category prf_read_char_send(&(anpc_env->con_info), anpc_env->ans.svc.shdl, anpc_env->ans.svc.ehdl, anpc_env->ans.chars[ANPC_CHAR_SUP_UNREAD_ALERT_CAT].val_hdl); } else { anpc_send_cmp_evt(anpc_env, ANPC_ENABLE_OP_CODE, param->status); } } break; case (ANPC_ENABLE_RD_UNREAD_ALERT_OP_CODE): { if (param->status == GATT_ERR_NO_ERROR) { // If peer device was unknown, stop the procedure if (((struct anpc_enable_cmd *)anpc_env->operation)->con_type == PRF_CON_DISCOVERY) { anpc_send_cmp_evt(anpc_env, ANPC_ENABLE_OP_CODE, PRF_ERR_OK); } // If peer device was already known (bonded), start Recovery from Connection Loss procedure else { // Reset the environment anpc_env->last_req = CAT_ID_SPL_ALERT; if (anpc_found_next_alert_cat(anpc_env, ((struct anpc_enable_cmd *)anpc_env->operation)->new_alert_enable)) { // Force the operation value ((struct anpc_cmd *)anpc_env->operation)->operation = ANPC_ENABLE_WR_NEW_ALERT_OP_CODE; // Enable sending of notifications for the found category ID anpc_write_alert_ntf_ctnl_pt(anpc_env, CMD_ID_EN_NEW_IN_ALERT_NTF, anpc_env->last_req - 1); } else { // Reset the environment anpc_env->last_req = CAT_ID_SPL_ALERT; if (anpc_found_next_alert_cat(anpc_env, ((struct anpc_enable_cmd *)anpc_env->operation)->unread_alert_enable)) { // Force the operation value ((struct anpc_cmd *)anpc_env->operation)->operation = ANPC_ENABLE_WR_UNREAD_ALERT_OP_CODE; // Enable sending of notifications for the found category ID anpc_write_alert_ntf_ctnl_pt(anpc_env, CMD_ID_EN_UNREAD_CAT_STATUS_NTF, anpc_env->last_req - 1); } else { anpc_send_cmp_evt(anpc_env, ANPC_ENABLE_OP_CODE, PRF_ERR_OK); } } } } else { anpc_send_cmp_evt(anpc_env, ANPC_ENABLE_OP_CODE, param->status); } } break; case (ANPC_READ_OP_CODE): { // Inform the requester that the read procedure is over anpc_send_cmp_evt(anpc_env, ANPC_READ_OP_CODE, param->status); } break; default: { ASSERT_ERR(0); } } } break; case (GATTC_REGISTER): case (GATTC_UNREGISTER): { // Do nothing } break; default: { ASSERT_ERR(0); } break; } } // else ignore the message return (KE_MSG_CONSUMED); }
/** **************************************************************************************** * @brief Handles reception of the @ref ANPC_READ_CMD message. * @param[in] msgid Id of the message received. * @param[in] param Pointer to the parameters of the message. * @param[in] dest_id ID of the receiving task instance. * @param[in] src_id ID of the sending task instance. * @return If the message was consumed or not. **************************************************************************************** */ static int anpc_read_cmd_handler(ke_msg_id_t const msgid, struct anpc_read_cmd *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { // Message status uint8_t msg_status = KE_MSG_CONSUMED; // Get the address of the environment struct anpc_env_tag *anpc_env = PRF_CLIENT_GET_ENV(dest_id, anpc); if (anpc_env != NULL) { // Attribute Handle uint16_t handle = ATT_INVALID_SEARCH_HANDLE; // Status uint8_t status = PRF_ERR_OK; // State is Connected or Busy ASSERT_ERR(ke_state_get(dest_id) != ANPC_IDLE); // Check the provided connection handle if (gapc_get_conidx(param->conhdl) == anpc_env->con_info.conidx) { // Check the current state if (ke_state_get(dest_id) == ANPC_BUSY) { // Keep the request for later, status is PRF_ERR_OK msg_status = KE_MSG_SAVED; } else // State is ANPC_CONNECTED { ASSERT_ERR(anpc_env->operation == NULL); switch (param->read_code) { // Read New Alert Characteristic Client Char. Cfg. Descriptor Value case (ANPC_RD_WR_NEW_ALERT_CFG): { handle = anpc_env->ans.descs[ANPC_DESC_NEW_ALERT_CL_CFG].desc_hdl; } break; // Read Unread Alert Characteristic Client Char. Cfg. Descriptor Value case (ANPC_RD_WR_UNREAD_ALERT_STATUS_CFG): { handle = anpc_env->ans.descs[ANPC_DESC_UNREAD_ALERT_STATUS_CL_CFG].desc_hdl; } break; default: { status = PRF_ERR_INVALID_PARAM; } break; } // Check if handle is viable if ((handle != ATT_INVALID_SEARCH_HANDLE) && (status == PRF_ERR_OK)) { // Force the operation value param->operation = ANPC_READ_OP_CODE; // Store the command structure anpc_env->operation = param; msg_status = KE_MSG_NO_FREE; // Send the read request prf_read_char_send(&(anpc_env->con_info), anpc_env->ans.svc.shdl, anpc_env->ans.svc.ehdl, handle); // Go to the Busy state ke_state_set(dest_id, ANPC_BUSY); } else { status = PRF_ERR_INEXISTENT_HDL; } } } else { status = PRF_ERR_INVALID_PARAM; } if (status != PRF_ERR_OK) { anpc_send_cmp_evt(anpc_env, ANPC_READ_OP_CODE, status); } } else { // No connection exists anpc_send_no_conn_cmp_evt(dest_id, src_id, param->conhdl, ANPC_READ_OP_CODE); } return (int)msg_status; }