uint32_t ble_sc_ctrlpt_rsp_send(ble_sc_ctrlpt_t * p_sc_ctrlpt, ble_scpt_response_t response_status) { uint32_t err_code = NRF_SUCCESS; ble_sc_ctrlpt_rsp_t rsp; uint8_t encoded_ctrl_rsp[BLE_SC_CTRLPT_MAX_LEN]; uint16_t hvx_len; ble_gatts_hvx_params_t hvx_params; if (p_sc_ctrlpt->procedure_status != BLE_SCPT_AUTOMATIC_CALIB_IN_PROGRESS) { return NRF_ERROR_INVALID_STATE; } rsp.status = response_status; rsp.opcode = BLE_SCPT_START_AUTOMATIC_CALIBRATION; hvx_len = ctrlpt_rsp_encode(p_sc_ctrlpt, &rsp, encoded_ctrl_rsp); // Send indication memset(&hvx_params, 0, sizeof(hvx_params)); hvx_params.handle = p_sc_ctrlpt->sc_ctrlpt_handles.value_handle; hvx_params.type = BLE_GATT_HVX_INDICATION; hvx_params.offset = 0; hvx_params.p_len = &hvx_len; hvx_params.p_data = encoded_ctrl_rsp; err_code = sd_ble_gatts_hvx(p_sc_ctrlpt->conn_handle, &hvx_params); if (err_code == NRF_SUCCESS) { p_sc_ctrlpt->procedure_status = BLE_SCPT_NO_PROC_IN_PROGRESS; } return err_code; }
/**@brief Handle a write event to the Speed and Cadence Control Point. * * @param[in] p_sc_ctrlpt SC Ctrlpt structure. * @param[in] p_evt_write WRITE event to be handled. */ static void on_ctrlpt_write(ble_sc_ctrlpt_t * p_sc_ctrlpt, ble_gatts_evt_write_t const * p_evt_write) { ble_sc_ctrlpt_val_t rcvd_ctrlpt = { BLE_SCPT_RESPONSE_CODE , 0, BLE_SENSOR_LOCATION_OTHER }; ble_sc_ctrlpt_rsp_t rsp; uint32_t err_code; ble_gatts_rw_authorize_reply_params_t auth_reply; ble_sc_ctrlpt_evt_t evt; auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE; auth_reply.params.write.offset = 0; auth_reply.params.write.len = 0; auth_reply.params.write.p_data = NULL; auth_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS; auth_reply.params.write.update = 1; if (is_cccd_configured(p_sc_ctrlpt)) { if (p_sc_ctrlpt->procedure_status == BLE_SCPT_NO_PROC_IN_PROGRESS) { auth_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS; } else { auth_reply.params.write.gatt_status = SC_CTRLPT_NACK_PROC_ALREADY_IN_PROGRESS; } } else { auth_reply.params.write.gatt_status = SC_CTRLPT_NACK_CCCD_IMPROPERLY_CONFIGURED; } err_code = sd_ble_gatts_rw_authorize_reply(p_sc_ctrlpt->conn_handle, &auth_reply); if (err_code != NRF_SUCCESS) { // Report error to application. if (p_sc_ctrlpt->error_handler != NULL) { p_sc_ctrlpt->error_handler(err_code); } } if (auth_reply.params.write.gatt_status != BLE_GATT_STATUS_SUCCESS) { return; } p_sc_ctrlpt->procedure_status = BLE_SCPT_INDICATION_PENDING; rsp.status = BLE_SCPT_OP_CODE_NOT_SUPPORTED; err_code = sc_ctrlpt_decode(p_evt_write->data, p_evt_write->len, &rcvd_ctrlpt); if (err_code != NRF_SUCCESS) { rsp.opcode = rcvd_ctrlpt.opcode; rsp.status = BLE_SCPT_OP_CODE_NOT_SUPPORTED; } else { rsp.opcode = rcvd_ctrlpt.opcode; switch (rcvd_ctrlpt.opcode) { case BLE_SCPT_REQUEST_SUPPORTED_SENSOR_LOCATIONS: if ((p_sc_ctrlpt->supported_functions & BLE_SRV_SC_CTRLPT_SENSOR_LOCATIONS_OP_SUPPORTED) == BLE_SRV_SC_CTRLPT_SENSOR_LOCATIONS_OP_SUPPORTED) { rsp.status = BLE_SCPT_SUCCESS; } else { rsp.status = BLE_SCPT_OP_CODE_NOT_SUPPORTED; } break; case BLE_SCPT_UPDATE_SENSOR_LOCATION: if ((p_sc_ctrlpt->supported_functions & BLE_SRV_SC_CTRLPT_SENSOR_LOCATIONS_OP_SUPPORTED) == BLE_SRV_SC_CTRLPT_SENSOR_LOCATIONS_OP_SUPPORTED) { if (is_location_supported(p_sc_ctrlpt, rcvd_ctrlpt.location)) { ble_gatts_value_t gatts_value; uint8_t rcvd_location = (uint8_t)rcvd_ctrlpt.location; rsp.status = BLE_SCPT_SUCCESS; // Initialize value struct. memset(&gatts_value, 0, sizeof(gatts_value)); gatts_value.len = sizeof(uint8_t); gatts_value.offset = 0; gatts_value.p_value = &rcvd_location; evt.evt_type = BLE_SC_CTRLPT_EVT_UPDATE_LOCATION; evt.params.update_location = rcvd_ctrlpt.location; if (p_sc_ctrlpt->evt_handler != NULL) { rsp.status = p_sc_ctrlpt->evt_handler(p_sc_ctrlpt, &evt); } if (rsp.status == BLE_SCPT_SUCCESS) { err_code = sd_ble_gatts_value_set(p_sc_ctrlpt->conn_handle, p_sc_ctrlpt->sensor_location_handle, &gatts_value); if (err_code != NRF_SUCCESS) { // Report error to application if (p_sc_ctrlpt->error_handler != NULL) { p_sc_ctrlpt->error_handler(err_code); } rsp.status = BLE_SCPT_OPERATION_FAILED; } } } else { rsp.status = BLE_SCPT_INVALID_PARAMETER; } } else { rsp.status = BLE_SCPT_OP_CODE_NOT_SUPPORTED; } break; case BLE_SCPT_SET_CUMULATIVE_VALUE: if ((p_sc_ctrlpt->supported_functions & BLE_SRV_SC_CTRLPT_CUM_VAL_OP_SUPPORTED) == BLE_SRV_SC_CTRLPT_CUM_VAL_OP_SUPPORTED) { rsp.status = BLE_SCPT_SUCCESS; evt.evt_type = BLE_SC_CTRLPT_EVT_SET_CUMUL_VALUE; evt.params.cumulative_value = rcvd_ctrlpt.cumulative_value; if (p_sc_ctrlpt->evt_handler != NULL) { rsp.status = p_sc_ctrlpt->evt_handler(p_sc_ctrlpt, &evt); } } else { rsp.status = BLE_SCPT_OP_CODE_NOT_SUPPORTED; } break; case BLE_SCPT_START_AUTOMATIC_CALIBRATION: if ((p_sc_ctrlpt->supported_functions & BLE_SRV_SC_CTRLPT_START_CALIB_OP_SUPPORTED) == BLE_SRV_SC_CTRLPT_START_CALIB_OP_SUPPORTED) { p_sc_ctrlpt->procedure_status = BLE_SCPT_AUTOMATIC_CALIB_IN_PROGRESS; evt.evt_type = BLE_SC_CTRLPT_EVT_START_CALIBRATION; if (p_sc_ctrlpt->evt_handler != NULL) { rsp.status = p_sc_ctrlpt->evt_handler(p_sc_ctrlpt, &evt); if (rsp.status != BLE_SCPT_SUCCESS) { // If the application returns an error, the response is to be sent // right away and the calibration is considered as not started. p_sc_ctrlpt->procedure_status = BLE_SCPT_INDICATION_PENDING; } } } else { rsp.status = BLE_SCPT_OP_CODE_NOT_SUPPORTED; } break; default: rsp.status = BLE_SCPT_OP_CODE_NOT_SUPPORTED; break; } } p_sc_ctrlpt->response.len = ctrlpt_rsp_encode(p_sc_ctrlpt, &rsp, p_sc_ctrlpt->response.encoded_ctrl_rsp); if (p_sc_ctrlpt->procedure_status == BLE_SCPT_INDICATION_PENDING) { sc_ctrlpt_resp_send(p_sc_ctrlpt); } }