diff options
Diffstat (limited to 'thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms')
12 files changed, 3422 insertions, 0 deletions
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_db.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_db.c new file mode 100644 index 0000000..e5f6240 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_db.c @@ -0,0 +1,143 @@ +/** + * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include <stdbool.h> +#include <stdint.h> +#include "cgms_db.h" + +typedef struct +{ + bool in_use_flag; + ble_cgms_rec_t record; +} database_entry_t; + +static database_entry_t m_database[CGMS_DB_MAX_RECORDS]; +static uint8_t m_database_crossref[CGMS_DB_MAX_RECORDS]; +static uint16_t m_num_records; + + +ret_code_t cgms_db_init(void) +{ + int i; + + for (i = 0; i < CGMS_DB_MAX_RECORDS; i++) + { + m_database[i].in_use_flag = false; + m_database_crossref[i] = 0xFF; + } + + m_num_records = 0; + + return NRF_SUCCESS; +} + + +uint16_t cgms_db_num_records_get(void) +{ + return m_num_records; +} + + +ret_code_t cgms_db_record_get(uint8_t record_num, ble_cgms_rec_t * p_rec) +{ + if ((record_num >= m_num_records) || (m_num_records == 0)) + { + return NRF_ERROR_NOT_FOUND; + } + // copy record to the specified memory + *p_rec = m_database[m_database_crossref[record_num]].record; + + return NRF_SUCCESS; +} + + +ret_code_t cgms_db_record_add(ble_cgms_rec_t * p_rec) +{ + int i; + + if (m_num_records == CGMS_DB_MAX_RECORDS) + { + return NRF_ERROR_NO_MEM; + } + + // find next available database entry + for (i = 0; i < CGMS_DB_MAX_RECORDS; i++) + { + if (!m_database[i].in_use_flag) + { + m_database[i].in_use_flag = true; + m_database[i].record = *p_rec; + + m_database_crossref[m_num_records] = i; + m_num_records++; + + return NRF_SUCCESS; + } + } + + return NRF_ERROR_NO_MEM; +} + + +ret_code_t cgms_db_record_delete(uint8_t record_num) +{ + int i; + + if (record_num >= m_num_records) + { + // Deleting a non-existent record is not an error + return NRF_SUCCESS; + } + + // free entry + m_database[m_database_crossref[record_num]].in_use_flag = false; + + // decrease number of records + m_num_records--; + + // remove cross reference index + for (i = record_num; i < m_num_records; i++) + { + m_database_crossref[i] = m_database_crossref[i + 1]; + } + + return NRF_SUCCESS; +} + + diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_db.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_db.h new file mode 100644 index 0000000..6928057 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_db.h @@ -0,0 +1,118 @@ +/** + * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +/** @file + * + * @defgroup ble_sdk_srv_cgms_db Continuous Glucose Monitoring Service database + * @{ + * @ingroup ble_cgms + * + * @brief Continuous Glucose Monitoring Service database module. + * + * @details This module implements a database of stored glucose measurement values. + * This database is meant as an example of a database that the @ref ble_cgms can use. + * Replace this module if this implementation does not suit + * your application. Any replacement implementation should follow the API below to ensure + * that the qualification of the @ref ble_cgms is not compromised. + */ + +#ifndef BLE_CGMS_DB_H__ +#define BLE_CGMS_DB_H__ + +#include "sdk_errors.h" +#include "nrf_ble_cgms.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define CGMS_DB_MAX_RECORDS 100 // !< Number of records that can be stored in the database. + + +/**@brief Function for initializing the glucose record database. + * + * @retval NRF_SUCCESS If the database was successfully initialized. + */ +ret_code_t cgms_db_init(void); + + +/**@brief Function for getting the number of records in the database. + * + * @return The number of records in the database. + */ +uint16_t cgms_db_num_records_get(void); + + +/**@brief Function for getting a specific record from the database. + * + * @param[in] record_num Index of the record to retrieve. + * @param[out] p_rec Pointer to the record structure to which the retrieved record is copied. + * + * @retval NRF_SUCCESS If the record was successfully retrieved. + */ +ret_code_t cgms_db_record_get(uint8_t record_num, ble_cgms_rec_t * p_rec); + + +/**@brief Function for adding a record at the end of the database. + * + * @param[in] p_rec Pointer to the record to add to the database. + * + * @retval NRF_SUCCESS If the record was successfully added to the database. + */ +ret_code_t cgms_db_record_add(ble_cgms_rec_t * p_rec); + + +/**@brief Function for deleting a database entry. + * + * @details This call deletes an record from the database. + * + * @param[in] record_num Index of the record to delete. + * + * @retval NRF_SUCCESS If the record was successfully deleted from the database. + */ +ret_code_t cgms_db_record_delete(uint8_t record_num); + + +#ifdef __cplusplus +} +#endif + +#endif // BLE_CGMS_DB_H__ + +/** @} */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_meas.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_meas.c new file mode 100644 index 0000000..50d6416 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_meas.c @@ -0,0 +1,248 @@ +/** + * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include <stdint.h> +#include <string.h> +#include "ble.h" +#include "sdk_macros.h" +#include "ble_srv_common.h" +#include "nrf_ble_cgms.h" +#include "cgms_meas.h" +#include "cgms_db.h" + +/**@brief Function for encoding a Glucose measurement. + * + * @param[in] p_meas Measurement to be encoded. + * @param[out] p_encoded_buffer Pointer to buffer where the encoded measurement is to be stored. + * + * @return Size of encoded measurement. + */ +static uint8_t cgms_meas_encode(nrf_ble_cgms_t * p_cgms, + const nrf_ble_cgms_meas_t * p_meas, + uint8_t * p_encoded_buffer) +{ + uint8_t len = 2; + + uint8_t flags = p_meas->flags; + + len += uint16_encode(p_meas->glucose_concentration, + &p_encoded_buffer[len]); + len += uint16_encode(p_meas->time_offset, + &p_encoded_buffer[len]); + + if (p_meas->sensor_status_annunciation.warning != 0) + { + p_encoded_buffer[len++] = p_meas->sensor_status_annunciation.warning; + flags |= NRF_BLE_CGMS_STATUS_FLAGS_WARNING_OCT_PRESENT; + } + + if (p_meas->sensor_status_annunciation.calib_temp != 0) + { + p_encoded_buffer[len++] = p_meas->sensor_status_annunciation.calib_temp; + flags |= NRF_BLE_CGMS_STATUS_FLAGS_CALTEMP_OCT_PRESENT; + } + + if (p_meas->sensor_status_annunciation.status != 0) + { + p_encoded_buffer[len++] = p_meas->sensor_status_annunciation.status; + flags |= NRF_BLE_CGMS_STATUS_FLAGS_STATUS_OCT_PRESENT; + } + + // Trend field + if (p_cgms->feature.feature & NRF_BLE_CGMS_FEAT_CGM_TREND_INFORMATION_SUPPORTED) + { + if (flags & NRF_BLE_CGMS_FLAG_TREND_INFO_PRESENT) + { + len += uint16_encode(p_meas->trend, &p_encoded_buffer[len]); + } + } + + // Quality field + if (p_cgms->feature.feature & NRF_BLE_CGMS_FEAT_CGM_QUALITY_SUPPORTED) + { + if (flags & NRF_BLE_CGMS_FLAGS_QUALITY_PRESENT) + { + len += uint16_encode(p_meas->quality, &p_encoded_buffer[len]); + } + } + + p_encoded_buffer[1] = flags; + p_encoded_buffer[0] = len; + return len; +} + + +/**@brief Function for adding a characteristic for the Continuous Glucose Meter Measurement. + * + * @param[in] p_cgms Service instance. + * + * @return NRF_SUCCESS if characteristic was successfully added, otherwise an error code. + */ +ret_code_t cgms_meas_char_add(nrf_ble_cgms_t * p_cgms) +{ + uint8_t num_recs; + uint8_t encoded_cgms_meas[NRF_BLE_CGMS_MEAS_LEN_MAX]; + ble_add_char_params_t add_char_params; + ble_cgms_rec_t initial_cgms_rec_value; + + memset(&add_char_params, 0, sizeof(add_char_params)); + memset(&initial_cgms_rec_value, 0, sizeof(ble_cgms_rec_t)); + + num_recs = cgms_db_num_records_get(); + if (num_recs > 0) + { + uint32_t err_code = cgms_db_record_get(num_recs - 1, &initial_cgms_rec_value); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + } + + add_char_params.uuid = BLE_UUID_CGM_MEASUREMENT; + add_char_params.max_len = NRF_BLE_CGMS_MEAS_LEN_MAX; + add_char_params.init_len = cgms_meas_encode(p_cgms, + &initial_cgms_rec_value.meas, + encoded_cgms_meas); + add_char_params.p_init_value = encoded_cgms_meas; + add_char_params.is_var_len = true; + add_char_params.char_props.notify = true; + add_char_params.cccd_write_access = SEC_JUST_WORKS; + + + return characteristic_add(p_cgms->service_handle, + &add_char_params, + &p_cgms->char_handles.measurment); +} + + +ret_code_t cgms_meas_send(nrf_ble_cgms_t * p_cgms, ble_cgms_rec_t * p_rec, uint8_t * p_count) +{ + + uint32_t err_code; + uint8_t encoded_meas[NRF_BLE_CGMS_MEAS_LEN_MAX + NRF_BLE_CGMS_MEAS_REC_LEN_MAX]; + uint16_t len = 0; + uint16_t hvx_len = NRF_BLE_CGMS_MEAS_LEN_MAX; + int i; + ble_gatts_hvx_params_t hvx_params; + + for (i = 0; i < *p_count; i++) + { + uint8_t meas_len = cgms_meas_encode(p_cgms, &(p_rec[i].meas), (encoded_meas + len)); + if (len + meas_len >= NRF_BLE_CGMS_MEAS_LEN_MAX) + { + break; + } + len += meas_len; + } + *p_count = i; + hvx_len = len; + + memset(&hvx_params, 0, sizeof(hvx_params)); + + hvx_params.handle = p_cgms->char_handles.measurment.value_handle; + hvx_params.type = BLE_GATT_HVX_NOTIFICATION; + hvx_params.offset = 0; + hvx_params.p_len = &hvx_len; + hvx_params.p_data = encoded_meas; + + err_code = sd_ble_gatts_hvx(p_cgms->conn_handle, &hvx_params); + if (err_code == NRF_SUCCESS) + { + if (hvx_len != len) + { + err_code = NRF_ERROR_DATA_SIZE; + } + else + { + // Measurement successfully sent + p_cgms->racp_data.racp_proc_records_reported += *p_count; + p_cgms->racp_data.racp_proc_records_reported_since_txcomplete++; + } + } + + return err_code; +} + + +/**@brief Function for handling the Glucose measurement CCCD write event. + * + * @param[in] p_cgms Service instance. + * @param[in] p_evt_write WRITE event to be handled. + */ +static void on_meas_cccd_write(nrf_ble_cgms_t * p_cgms, ble_gatts_evt_write_t const * p_evt_write) +{ + if (p_evt_write->len == 2) + { + // CCCD written, update notification state + if (p_cgms->evt_handler != NULL) + { + nrf_ble_cgms_evt_t evt; + + if (ble_srv_is_notification_enabled(p_evt_write->data)) + { + evt.evt_type = NRF_BLE_CGMS_EVT_NOTIFICATION_ENABLED; + } + else + { + evt.evt_type = NRF_BLE_CGMS_EVT_NOTIFICATION_DISABLED; + } + + p_cgms->evt_handler(p_cgms, &evt); + } + } +} + + +/**@brief Function for handling the WRITE event. + * + * @details Handles WRITE events from the BLE stack. + * + * @param[in] p_cgms Glucose Service structure. + * @param[in] p_ble_evt Event received from the BLE stack. + */ +void cgms_meas_on_write(nrf_ble_cgms_t * p_cgms, ble_gatts_evt_write_t const * p_evt_write) +{ + + if (p_evt_write->handle == p_cgms->char_handles.measurment.cccd_handle) + { + on_meas_cccd_write(p_cgms, p_evt_write); + } +} + + diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_meas.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_meas.h new file mode 100644 index 0000000..d56c704 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_meas.h @@ -0,0 +1,103 @@ +/** + * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +/** @file + * + * @defgroup ble_sdk_srv_cgms_meas Continuous Glucose Monitoring Service Measurement + * @{ + * @ingroup ble_cgms + * @brief Continuous Glucose Monitoring Service Measurement module. + * + * @details This module implements parts of the Continuous Glucose Monitoring that relate to the + * Measurement characteristic. Events are propagated to this module from @ref ble_cgms + * using @ref cgms_meas_on_write. + * + */ + + +#ifndef NRF_BLE_CGMS_MEAS_H__ +#define NRF_BLE_CGMS_MEAS_H__ + +#include "ble.h" +#include "ble_srv_common.h" +#include "sdk_errors.h" +#include "nrf_ble_cgms.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/**@brief Function for adding a characteristic for the Continuous Glucose Monitoring Measurement. + * + * @param[in] p_cgms Instance of the CGM Service. + * + * @retval NRF_SUCCESS If the characteristic was successfully added. + * @return If functions from other modules return errors to this function, + * the @ref nrf_error are propagated. + */ +ret_code_t cgms_meas_char_add(nrf_ble_cgms_t * p_cgms); + +/**@brief Function for sending a CGM Measurement. + * + * @param[in] p_cgms Instance of the CGM Service. + * @param[in] p_rec Measurement to be sent. + * @param[in] count Number of measurements to encode. + * + * @retval NRF_SUCCESS If the measurement was successfully sent. + * @return If functions from other modules return errors to this function, + * the @ref nrf_error are propagated. + */ +ret_code_t cgms_meas_send(nrf_ble_cgms_t * p_cgms, ble_cgms_rec_t * p_rec, uint8_t * count); + + +/**@brief Function for handling the @ref BLE_GATTS_EVT_WRITE event from the BLE stack. + * + * @param[in] p_cgms Instance of the CGM Service. + * @param[in] p_evt_write Event received from the BLE stack. + */ +void cgms_meas_on_write(nrf_ble_cgms_t * p_cgms, ble_gatts_evt_write_t const * p_evt_write); + +#ifdef __cplusplus +} +#endif + +#endif // NRF_BLE_CGMS_MEAS_H__ + +/** @} */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_racp.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_racp.c new file mode 100644 index 0000000..0327383 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_racp.c @@ -0,0 +1,866 @@ +/** + * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include <stdint.h> +#include <string.h> +#include "ble.h" +#include "ble_srv_common.h" +#include "cgms_racp.h" +#include "cgms_db.h" +#include "cgms_meas.h" + +#define OPERAND_LESS_GREATER_FILTER_TYPE_SIZE 1 // !< 1 byte. +#define OPERAND_LESS_GREATER_FILTER_PARAM_SIZE 2 // !< 2 bytes. +#define OPERAND_LESS_GREATER_SIZE OPERAND_LESS_GREATER_FILTER_TYPE_SIZE \ + + OPERAND_LESS_GREATER_FILTER_PARAM_SIZE // !< Total size of the operand. + +/**@brief Function for adding a characteristic for the Record Access Control Point. + * + * @param[in] p_cgms Service instance. + * + * @return NRF_SUCCESS if characteristic was successfully added, otherwise an error code. + */ +ret_code_t cgms_racp_char_add(nrf_ble_cgms_t * p_cgms) +{ + ble_add_char_params_t add_char_params; + + memset(&add_char_params, 0, sizeof(add_char_params)); + + add_char_params.uuid = BLE_UUID_RECORD_ACCESS_CONTROL_POINT_CHAR; + add_char_params.max_len = BLE_GATT_ATT_MTU_DEFAULT; + add_char_params.init_len = 0; + add_char_params.p_init_value = 0; + add_char_params.is_var_len = true; + add_char_params.write_access = SEC_JUST_WORKS; + add_char_params.char_props.write = true; + add_char_params.char_props.indicate = true; + add_char_params.cccd_write_access = SEC_JUST_WORKS; + add_char_params.is_defered_write = 1; + + return characteristic_add(p_cgms->service_handle, + &add_char_params, + &p_cgms->char_handles.racp); +} + + +/**@brief Function for sending response from Specific Operation Control Point. + * + * @param[in] p_cgms Service instance. + * @param[in] p_racp_val RACP value to be sent. + */ +static void racp_send(nrf_ble_cgms_t * p_cgms, ble_racp_value_t * p_racp_val) +{ + uint32_t err_code; + uint8_t encoded_resp[25]; + uint8_t len; + uint16_t hvx_len; + ble_gatts_hvx_params_t hvx_params; + + if ( + (p_cgms->cgms_com_state != STATE_RACP_RESPONSE_PENDING) + && + (p_cgms->racp_data.racp_proc_records_reported_since_txcomplete > 0) + ) + { + p_cgms->cgms_com_state = STATE_RACP_RESPONSE_PENDING; + return; + } + + // Send indication + len = ble_racp_encode(p_racp_val, encoded_resp); + hvx_len = len; + + memset(&hvx_params, 0, sizeof(hvx_params)); + + hvx_params.handle = p_cgms->char_handles.racp.value_handle; + hvx_params.type = BLE_GATT_HVX_INDICATION; + hvx_params.offset = 0; + hvx_params.p_len = &hvx_len; + hvx_params.p_data = encoded_resp; + + err_code = sd_ble_gatts_hvx(p_cgms->conn_handle, &hvx_params); + + // Error handling + if ((err_code == NRF_SUCCESS) && (hvx_len != len)) + { + err_code = NRF_ERROR_DATA_SIZE; + } + + switch (err_code) + { + case NRF_SUCCESS: + // Wait for HVC event. + p_cgms->cgms_com_state = STATE_RACP_RESPONSE_IND_VERIF; + break; + + case NRF_ERROR_RESOURCES: + // Wait for TX_COMPLETE event to retry transmission. + p_cgms->cgms_com_state = STATE_RACP_RESPONSE_PENDING; + break; + + case NRF_ERROR_INVALID_STATE: + // Make sure state machine returns to the default state. + p_cgms->cgms_com_state = STATE_NO_COMM; + break; + + default: + // Report error to application. + if (p_cgms->error_handler != NULL) + { + p_cgms->error_handler(err_code); + } + + // Make sure state machine returns to the default state. + p_cgms->cgms_com_state = STATE_NO_COMM; + break; + } +} + + +/**@brief Function for sending a RACP response containing a Response Code Op Code and Response Code Value. + * + * @param[in] p_cgms Service instance. + * @param[in] opcode RACP Op Code. + * @param[in] value RACP Response Code Value. + */ +static void racp_response_code_send(nrf_ble_cgms_t * p_cgms, uint8_t opcode, uint8_t value) +{ + p_cgms->racp_data.pending_racp_response.opcode = RACP_OPCODE_RESPONSE_CODE; + p_cgms->racp_data.pending_racp_response.operator = RACP_OPERATOR_NULL; + p_cgms->racp_data.pending_racp_response.operand_len = 2; + p_cgms->racp_data.pending_racp_response.p_operand = + p_cgms->racp_data.pending_racp_response_operand; + + p_cgms->racp_data.pending_racp_response_operand[0] = opcode; + p_cgms->racp_data.pending_racp_response_operand[1] = value; + + racp_send(p_cgms, &p_cgms->racp_data.pending_racp_response); +} + + +/**@brief Function for responding to the ALL operation. + * + * @param[in] p_cgms Service instance. + * + * @return NRF_SUCCESS on success, otherwise an error code. + */ +static uint32_t racp_report_records_all(nrf_ble_cgms_t * p_cgms) +{ + uint16_t total_records = cgms_db_num_records_get(); + uint16_t cur_nb_rec; + uint8_t i; + uint8_t nb_rec_to_send; + + if (p_cgms->racp_data.racp_proc_record_ndx >= total_records) + { + p_cgms->cgms_com_state = STATE_NO_COMM; + } + else + { + uint32_t err_code; + ble_cgms_rec_t rec[NRF_BLE_CGMS_MEAS_REC_PER_NOTIF_MAX]; + + cur_nb_rec = total_records - p_cgms->racp_data.racp_proc_record_ndx; + if (cur_nb_rec > NRF_BLE_CGMS_MEAS_REC_PER_NOTIF_MAX) + { + cur_nb_rec = NRF_BLE_CGMS_MEAS_REC_PER_NOTIF_MAX; + } + nb_rec_to_send = (uint8_t)cur_nb_rec; + + for (i = 0; i < cur_nb_rec; i++) + { + err_code = cgms_db_record_get(p_cgms->racp_data.racp_proc_record_ndx + i, &(rec[i])); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + } + err_code = cgms_meas_send(p_cgms, rec, &nb_rec_to_send); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + p_cgms->racp_data.racp_proc_record_ndx += nb_rec_to_send; + } + + return NRF_SUCCESS; +} + + +/**@brief Function for responding to the FIRST or the LAST operation. + * + * @param[in] p_cgms Service instance. + * + * @return NRF_SUCCESS on success, otherwise an error code. + */ +static uint32_t racp_report_records_first_last(nrf_ble_cgms_t * p_cgms) +{ + uint32_t err_code; + ble_cgms_rec_t rec; + uint16_t total_records; + uint8_t nb_rec_to_send = 1; + + total_records = cgms_db_num_records_get(); + + if ((p_cgms->racp_data.racp_proc_records_reported != 0) || (total_records == 0)) + { + p_cgms->cgms_com_state = STATE_NO_COMM; + } + else + { + if (p_cgms->racp_data.racp_proc_operator == RACP_OPERATOR_FIRST) + { + err_code = cgms_db_record_get(0, &rec); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + } + else if (p_cgms->racp_data.racp_proc_operator == RACP_OPERATOR_LAST) + { + err_code = cgms_db_record_get(total_records - 1, &rec); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + } + + err_code = cgms_meas_send(p_cgms, &rec, &nb_rec_to_send); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + p_cgms->racp_data.racp_proc_record_ndx++; + } + + return NRF_SUCCESS; +} + + +/**@brief Function for responding to the LESS OR EQUAL operation. + * + * @param[in] p_cgms Service instance. + * + * @return NRF_SUCCESS on success, otherwise an error code. + */ +static ret_code_t racp_report_records_less_equal(nrf_ble_cgms_t * p_cgms) +{ + uint16_t total_rec_nb_to_send; + uint16_t rec_nb_left_to_send; + uint8_t nb_rec_to_send; + uint16_t i; + + total_rec_nb_to_send = p_cgms->racp_data.racp_proc_records_ndx_last_to_send +1; + + if (p_cgms->racp_data.racp_proc_record_ndx >= total_rec_nb_to_send) + { + p_cgms->cgms_com_state = STATE_NO_COMM; + } + else + { + ret_code_t err_code; + ble_cgms_rec_t rec[NRF_BLE_CGMS_MEAS_REC_PER_NOTIF_MAX]; + + rec_nb_left_to_send = total_rec_nb_to_send - p_cgms->racp_data.racp_proc_records_reported; + + if (rec_nb_left_to_send > NRF_BLE_CGMS_MEAS_REC_PER_NOTIF_MAX) + { + nb_rec_to_send = NRF_BLE_CGMS_MEAS_REC_PER_NOTIF_MAX; + } + else + { + nb_rec_to_send = (uint8_t)rec_nb_left_to_send; + } + + for (i = 0; i < nb_rec_to_send; i++) + { + err_code = cgms_db_record_get(p_cgms->racp_data.racp_proc_record_ndx + i, &(rec[i])); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + } + err_code = cgms_meas_send(p_cgms, rec, &nb_rec_to_send); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + p_cgms->racp_data.racp_proc_record_ndx += nb_rec_to_send; + } + + return NRF_SUCCESS; +} + + +/**@brief Function for responding to the GREATER OR EQUAL operation. + * + * @param[in] p_cgms Service instance. + * + * @return NRF_SUCCESS on success, otherwise an error code. + */ +static ret_code_t racp_report_records_greater_equal(nrf_ble_cgms_t * p_cgms) +{ + ret_code_t err_code; + uint16_t total_rec_nb = cgms_db_num_records_get(); + uint16_t rec_nb_left_to_send; + uint8_t nb_rec_to_send; + uint16_t i; + + + total_rec_nb = cgms_db_num_records_get(); + if (p_cgms->racp_data.racp_proc_record_ndx >= total_rec_nb) + { + p_cgms->cgms_com_state = STATE_NO_COMM; + return NRF_SUCCESS; + } + + ble_cgms_rec_t rec[NRF_BLE_CGMS_MEAS_REC_PER_NOTIF_MAX]; + + rec_nb_left_to_send = total_rec_nb - p_cgms->racp_data.racp_proc_record_ndx; + if (rec_nb_left_to_send > NRF_BLE_CGMS_MEAS_REC_PER_NOTIF_MAX) + { + nb_rec_to_send = NRF_BLE_CGMS_MEAS_REC_PER_NOTIF_MAX; + } + else + { + nb_rec_to_send = (uint8_t)rec_nb_left_to_send; + } + + for (i = 0; i < nb_rec_to_send; i++) + { + err_code = cgms_db_record_get(p_cgms->racp_data.racp_proc_record_ndx + i, &(rec[i])); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + } + err_code = cgms_meas_send(p_cgms, rec, &nb_rec_to_send); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + p_cgms->racp_data.racp_proc_record_ndx += nb_rec_to_send; + + return NRF_SUCCESS; +} + + +/**@brief Function for informing that the REPORT RECORDS procedure is completed. + * + * @param[in] p_cgms Service instance. + */ +static void racp_report_records_completed(nrf_ble_cgms_t * p_cgms) +{ + uint8_t resp_code_value; + + if (p_cgms->racp_data.racp_proc_records_reported > 0) + { + resp_code_value = RACP_RESPONSE_SUCCESS; + } + else + { + resp_code_value = RACP_RESPONSE_NO_RECORDS_FOUND; + } + + racp_response_code_send(p_cgms, RACP_OPCODE_REPORT_RECS, resp_code_value); +} + + +/**@brief Function for the RACP report records procedure. + * + * @param[in] p_cgms Service instance. + */ +static void racp_report_records_procedure(nrf_ble_cgms_t * p_cgms) +{ + ret_code_t err_code = NRF_SUCCESS; + + while (p_cgms->cgms_com_state == STATE_RACP_PROC_ACTIVE) + { + // Execute requested procedure + switch (p_cgms->racp_data.racp_proc_operator) + { + case RACP_OPERATOR_ALL: + err_code = racp_report_records_all(p_cgms); + break; + + case RACP_OPERATOR_FIRST: + // Fall through. + case RACP_OPERATOR_LAST: + err_code = racp_report_records_first_last(p_cgms); + break; + case RACP_OPERATOR_GREATER_OR_EQUAL: + err_code = racp_report_records_greater_equal(p_cgms); + break; + case RACP_OPERATOR_LESS_OR_EQUAL: + err_code = racp_report_records_less_equal(p_cgms); + break; + default: + // Report error to application + if (p_cgms->error_handler != NULL) + { + p_cgms->error_handler(NRF_ERROR_INTERNAL); + } + + // Make sure state machine returns to the default state + // state_set(STATE_NO_COMM); + p_cgms->cgms_com_state = STATE_NO_COMM; + return; + } + + // Error handling + switch (err_code) + { + case NRF_SUCCESS: + if (p_cgms->cgms_com_state != STATE_RACP_PROC_ACTIVE) + { + racp_report_records_completed(p_cgms); + } + break; + + case NRF_ERROR_RESOURCES: + // Wait for TX_COMPLETE event to resume transmission. + return; + + case NRF_ERROR_INVALID_STATE: + // Notification is probably not enabled. Ignore request. + p_cgms->cgms_com_state = STATE_NO_COMM; + return; + + default: + // Report error to application. + if (p_cgms->error_handler != NULL) + { + p_cgms->error_handler(err_code); + } + + // Make sure state machine returns to the default state. + p_cgms->cgms_com_state = STATE_NO_COMM; + return; + } + } +} + + +/**@brief Function for testing if the received request is to be executed. + * + * @param[in] p_racp_request Request to be checked. + * @param[out] p_response_code Response code to be sent in case the request is rejected. + * RACP_RESPONSE_RESERVED is returned if the received message is + * to be rejected without sending a respone. + * + * @return TRUE if the request is to be executed, FALSE if it is to be rejected. + * If it is to be rejected, p_response_code will contain the response code to be + * returned to the central. + */ +static bool is_request_to_be_executed(nrf_ble_cgms_t * p_cgms, + const ble_racp_value_t * p_racp_request, + uint8_t * p_response_code) +{ + *p_response_code = RACP_RESPONSE_RESERVED; + + if (p_racp_request->opcode == RACP_OPCODE_ABORT_OPERATION) + { + if (p_cgms->cgms_com_state == STATE_RACP_PROC_ACTIVE) + { + if (p_racp_request->operator != RACP_OPERATOR_NULL) + { + *p_response_code = RACP_RESPONSE_INVALID_OPERATOR; + } + else if (p_racp_request->operand_len != 0) + { + *p_response_code = RACP_RESPONSE_INVALID_OPERAND; + } + else + { + *p_response_code = RACP_RESPONSE_SUCCESS; + } + } + else + { + *p_response_code = RACP_RESPONSE_ABORT_FAILED; + } + } + else if (p_cgms->cgms_com_state != STATE_NO_COMM) + { + return false; + } + // Supported opcodes + else if ((p_racp_request->opcode == RACP_OPCODE_REPORT_RECS) || + (p_racp_request->opcode == RACP_OPCODE_REPORT_NUM_RECS)) + { + switch (p_racp_request->operator) + { + // Operators without a filter. + case RACP_OPERATOR_ALL: + // Fall through. + case RACP_OPERATOR_FIRST: + // Fall through. + case RACP_OPERATOR_LAST: + if (p_racp_request->operand_len != 0) + { + *p_response_code = RACP_RESPONSE_INVALID_OPERAND; + } + break; + + // Operators with a filter as part of the operand. + case RACP_OPERATOR_LESS_OR_EQUAL: + // Fall Through. + case RACP_OPERATOR_GREATER_OR_EQUAL: + if (*(p_racp_request->p_operand) == RACP_OPERAND_FILTER_TYPE_FACING_TIME) + { + *p_response_code = RACP_RESPONSE_PROCEDURE_NOT_DONE; + } + if (p_racp_request->operand_len != OPERAND_LESS_GREATER_SIZE) + { + *p_response_code = RACP_RESPONSE_INVALID_OPERAND; + } + break; + + case RACP_OPERATOR_RANGE: + *p_response_code = RACP_RESPONSE_OPERATOR_UNSUPPORTED; + break; + + // Invalid operators. + case RACP_OPERATOR_NULL: + // Fall through. + default: + *p_response_code = RACP_RESPONSE_INVALID_OPERATOR; + break; + } + } + // Unsupported opcodes. + else if (p_racp_request->opcode == RACP_OPCODE_DELETE_RECS) + { + *p_response_code = RACP_RESPONSE_OPCODE_UNSUPPORTED; + } + // Unknown opcodes. + else + { + *p_response_code = RACP_RESPONSE_OPCODE_UNSUPPORTED; + } + + return (*p_response_code == RACP_RESPONSE_RESERVED); +} + + + + +/**@brief Function for getting a record with time offset less or equal to the input param. + * + * @param[in] offset The record that this function returns must have an time offset less or greater to this. + * @param[out] record_num Pointer to the record index of the record that has the desired time offset. + * + * @retval NRF_SUCCESS If the record was successfully retrieved. + * @retval NRF_ERROR_NOT_FOUND A record with the desired offset does not exist in the database. + * @return If functions from other modules return errors to this function, + * the @ref nrf_error are propagated. + */ +static ret_code_t record_index_offset_less_or_equal_get(uint16_t offset, uint16_t * record_num) +{ + ret_code_t err_code; + ble_cgms_rec_t rec; + uint16_t upper_bound = cgms_db_num_records_get(); + + for((*record_num) = upper_bound; (*record_num)-- >0;) + { + err_code = cgms_db_record_get(*record_num, &rec); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + if (rec.meas.time_offset <= offset) + { + return NRF_SUCCESS; + } + } + return NRF_ERROR_NOT_FOUND; +} + + + +/**@brief Function for getting a record with time offset greater or equal to the input param. + * + * @param[in] offset The record that this function returns must have an time offset equal or + * greater to this. + * @param[out] record_num Pointer to the record index of the record that has the desired time offset. + * + * @retval NRF_SUCCESS If the record was successfully retrieved. + * @retval NRF_ERROR_NOT_FOUND A record with the desired offset does not exist in the database. + * @return If functions from other modules return errors to this function, + * the @ref nrf_error are propagated. + */ +static ret_code_t record_index_offset_greater_or_equal_get(uint16_t offset, uint16_t * record_num) +{ + ret_code_t err_code; + ble_cgms_rec_t rec; + uint16_t upper_bound = cgms_db_num_records_get(); + + for(*record_num = 0; *record_num < upper_bound; (*record_num)++) + { + err_code = cgms_db_record_get(*record_num, &rec); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + if (rec.meas.time_offset >= offset) + { + return NRF_SUCCESS; + } + } + return NRF_ERROR_NOT_FOUND; +} + + +/**@brief Function for processing a REPORT RECORDS request. + * + * @details Set initial values before entering the state machine of racp_report_records_procedure(). + * + * @param[in] p_cgms Service instance. + * @param[in] p_racp_request Request to be executed. + */ +static void report_records_request_execute(nrf_ble_cgms_t * p_cgms, + ble_racp_value_t * p_racp_request) +{ + p_cgms->cgms_com_state = STATE_RACP_PROC_ACTIVE; + + p_cgms->racp_data.racp_proc_record_ndx = 0; + p_cgms->racp_data.racp_proc_operator = p_racp_request->operator; + p_cgms->racp_data.racp_proc_records_reported = 0; + p_cgms->racp_data.racp_proc_records_ndx_last_to_send = 0; + + if (p_cgms->racp_data.racp_proc_operator == RACP_OPERATOR_GREATER_OR_EQUAL) + { + uint16_t offset_requested = uint16_decode(&p_cgms->racp_data.racp_request.p_operand[OPERAND_LESS_GREATER_FILTER_TYPE_SIZE]); + ret_code_t err_code = record_index_offset_greater_or_equal_get(offset_requested, &p_cgms->racp_data.racp_proc_record_ndx); + if (err_code != NRF_SUCCESS) + { + racp_report_records_completed(p_cgms); + } + + } + if (p_cgms->racp_data.racp_proc_operator == RACP_OPERATOR_LESS_OR_EQUAL) + { + uint16_t offset_requested = uint16_decode(&p_cgms->racp_data.racp_request.p_operand[OPERAND_LESS_GREATER_FILTER_TYPE_SIZE]); + ret_code_t err_code = record_index_offset_less_or_equal_get(offset_requested, + &p_cgms->racp_data.racp_proc_records_ndx_last_to_send); + if (err_code != NRF_SUCCESS) + { + racp_report_records_completed(p_cgms); + } + } + racp_report_records_procedure(p_cgms); +} + + +/**@brief Function for processing a REPORT NUM RECORDS request. + * + * @param[in] p_cgms Service instance. + * @param[in] p_racp_request Request to be executed. + */ +static void report_num_records_request_execute(nrf_ble_cgms_t * p_cgms, + ble_racp_value_t * p_racp_request) +{ + uint16_t total_records; + uint16_t num_records; + + total_records = cgms_db_num_records_get(); + num_records = 0; + + if (p_racp_request->operator == RACP_OPERATOR_ALL) + { + num_records = total_records; + } + else if ((p_racp_request->operator == RACP_OPERATOR_FIRST) || + (p_racp_request->operator == RACP_OPERATOR_LAST)) + { + if (total_records > 0) + { + num_records = 1; + } + } + else if (p_racp_request->operator == RACP_OPERATOR_GREATER_OR_EQUAL) + { + uint16_t index_of_offset; + uint16_t offset_requested = uint16_decode(&p_cgms->racp_data.racp_request.p_operand[OPERAND_LESS_GREATER_FILTER_TYPE_SIZE]); + ret_code_t err_code = record_index_offset_greater_or_equal_get(offset_requested, &index_of_offset); + + if (err_code != NRF_SUCCESS) + { + num_records = 0; + } + else + { + num_records = total_records - index_of_offset; + } + } + + p_cgms->racp_data.pending_racp_response.opcode = RACP_OPCODE_NUM_RECS_RESPONSE; + p_cgms->racp_data.pending_racp_response.operator = RACP_OPERATOR_NULL; + p_cgms->racp_data.pending_racp_response.operand_len = sizeof(uint16_t); + p_cgms->racp_data.pending_racp_response.p_operand = + p_cgms->racp_data.pending_racp_response_operand; + + p_cgms->racp_data.pending_racp_response_operand[0] = num_records & 0xFF; + p_cgms->racp_data.pending_racp_response_operand[1] = num_records >> 8; + + racp_send(p_cgms, &p_cgms->racp_data.pending_racp_response); +} + + +/**@brief Function for handling a write event to the Record Access Control Point. + * + * @param[in] p_cgms Service instance. + * @param[in] p_evt_write WRITE event to be handled. + */ +static void on_racp_value_write(nrf_ble_cgms_t * p_cgms, ble_gatts_evt_write_t const * p_evt_write) +{ + uint8_t response_code; + + // set up reply to authorized write. + ble_gatts_rw_authorize_reply_params_t auth_reply; + uint32_t err_code; + + 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; + + // Decode request. + ble_racp_decode(p_evt_write->len, p_evt_write->data, &p_cgms->racp_data.racp_request); + + // Check if request is to be executed + if (is_request_to_be_executed(p_cgms, &p_cgms->racp_data.racp_request, &response_code)) + { + auth_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS; + auth_reply.params.write.update = 1; + + err_code = sd_ble_gatts_rw_authorize_reply(p_cgms->conn_handle, + &auth_reply); + if (err_code != NRF_SUCCESS) + { + if (p_cgms->error_handler != NULL) + { + p_cgms->error_handler(err_code); + } + return; + } + + // Execute request + if (p_cgms->racp_data.racp_request.opcode == RACP_OPCODE_REPORT_RECS) + { + report_records_request_execute(p_cgms, &p_cgms->racp_data.racp_request); + } + else if (p_cgms->racp_data.racp_request.opcode == RACP_OPCODE_REPORT_NUM_RECS) + { + report_num_records_request_execute(p_cgms, &p_cgms->racp_data.racp_request); + } + } + else if (response_code != RACP_RESPONSE_RESERVED) + { + auth_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS; + auth_reply.params.write.update = 1; + err_code = sd_ble_gatts_rw_authorize_reply(p_cgms->conn_handle, + &auth_reply); + + if (err_code != NRF_SUCCESS) + { + if (p_cgms->error_handler != NULL) + { + p_cgms->error_handler(err_code); + } + return; + } + // Abort any running procedure + p_cgms->cgms_com_state = STATE_NO_COMM; + + // Respond with error code + racp_response_code_send(p_cgms, p_cgms->racp_data.racp_request.opcode, response_code); + } + else + { + // ignore request + auth_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS; + auth_reply.params.write.update = 1; + err_code = sd_ble_gatts_rw_authorize_reply(p_cgms->conn_handle, + &auth_reply); + + if (err_code != NRF_SUCCESS) + { + if (p_cgms->error_handler != NULL) + { + p_cgms->error_handler(err_code); + } + return; + } + } +} + + +void cgms_racp_on_rw_auth_req(nrf_ble_cgms_t * p_cgms, + ble_gatts_evt_rw_authorize_request_t const * p_auth_req) +{ + if (p_auth_req->type == BLE_GATTS_AUTHORIZE_TYPE_WRITE) + { + if (p_auth_req->request.write.handle == p_cgms->char_handles.racp.value_handle) + { + on_racp_value_write(p_cgms, &p_auth_req->request.write); + } + } +} + + +/**@brief Function for handling BLE_GATTS_EVT_HVN_TX_COMPLETE events. + * + * @param[in] p_cgms Glucose Service structure. + */ +void cgms_racp_on_tx_complete(nrf_ble_cgms_t * p_cgms) +{ + p_cgms->racp_data.racp_proc_records_reported_since_txcomplete = 0; + + if (p_cgms->cgms_com_state == STATE_RACP_RESPONSE_PENDING) + { + racp_send(p_cgms, &p_cgms->racp_data.pending_racp_response); + } + else if (p_cgms->cgms_com_state == STATE_RACP_PROC_ACTIVE) + { + racp_report_records_procedure(p_cgms); + } +} + + diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_racp.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_racp.h new file mode 100644 index 0000000..e1d92af --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_racp.h @@ -0,0 +1,99 @@ +/** + * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +/** @file + * + * @defgroup ble_sdk_srv_cgms_racp Record Access Control Point + * @{ + * @ingroup ble_cgms + * @brief Continuous Glucose Monitoring Service RACP module. + * + * @details This module implements parts of the Continuous Glucose Monitoring that relate to the + * Record Access Control Point. Events are propagated to this module from @ref ble_cgms + * using @ref cgms_racp_on_rw_auth_req and @ref cgms_racp_on_tx_complete. + * + */ + +#ifndef NRF_BLE_CGMS_RACP_H__ +#define NRF_BLE_CGMS_RACP_H__ + +#include "ble.h" +#include "ble_srv_common.h" +#include "sdk_errors.h" +#include "nrf_ble_cgms.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/**@brief Function for adding a characteristic for the Record Access Control Point. + * + * @param[in] p_cgms Instance of the CGM Service. + * + * @retval NRF_SUCCESS If the characteristic was successfully added. + * @retval NRF_ERROR_NULL If any of the input parameters are NULL. + * @return If functions from other modules return errors to this function, + * the @ref nrf_error are propagated. + */ +ret_code_t cgms_racp_char_add(nrf_ble_cgms_t * p_cgms); + + +/**@brief Function for handling @ref BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST events. + * + * @param[in] p_cgms Instance of the CGM Service. + * @param[in] p_auth_req Authorize request event to be handled. + */ +void cgms_racp_on_rw_auth_req(nrf_ble_cgms_t * p_cgms, + ble_gatts_evt_rw_authorize_request_t const * p_auth_req); + + +/**@brief Function for handling @ref BLE_GATTS_EVT_HVN_TX_COMPLETE events. + * + * @param[in] p_cgms Instance of the CGM Service. + */ +void cgms_racp_on_tx_complete(nrf_ble_cgms_t * p_cgms); + +#ifdef __cplusplus +} +#endif + +#endif // NRF_BLE_CGMS_RACP_H__ + +/** @} */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_socp.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_socp.c new file mode 100644 index 0000000..2ade378 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_socp.c @@ -0,0 +1,431 @@ +/** + * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include <stdint.h> +#include <string.h> +#include "ble.h" +#include "ble_srv_common.h" +#include "cgms_sst.h" +#include "cgms_socp.h" + + +#define NRF_BLE_CGMS_PLUS_INFINTE 0x07FE +#define NRF_BLE_CGMS_MINUS_INFINTE 0x0802 + +/**@brief Specific Operation Control Point opcodes. */ +#define SOCP_OPCODE_RESERVED 0x00 /**< Specific Operation Control Point opcode - Reserved for future use. */ +#define SOCP_WRITE_CGM_COMMUNICATION_INTERVAL 0x01 +#define SOCP_READ_CGM_COMMUNICATION_INTERVAL 0x02 +#define SOCP_READ_CGM_COMMUNICATION_INTERVAL_RESPONSE 0x03 +#define SOCP_WRITE_GLUCOSE_CALIBRATION_VALUE 0x04 +#define SOCP_READ_GLUCOSE_CALIBRATION_VALUE 0x05 +#define SOCP_READ_GLUCOSE_CALIBRATION_VALUE_RESPONSE 0x06 +#define SOCP_WRITE_PATIENT_HIGH_ALERT_LEVEL 0x07 +#define SOCP_READ_PATIENT_HIGH_ALERT_LEVEL 0x08 +#define SOCP_READ_PATIENT_HIGH_ALERT_LEVEL_RESPONSE 0x09 +#define SOCP_WRITE_PATIENT_LOW_ALERT_LEVEL 0x0A +#define SOCP_READ_PATIENT_LOW_ALERT_LEVEL 0x0B +#define SOCP_READ_PATIENT_LOW_ALERT_LEVEL_RESPONSE 0x0C +#define SOCP_SET_HYPO_ALERT_LEVEL 0x0D /**Set Hypo Alert Level Hypo Alert Level value in mg/dL The response to this control point is Response Code. */ +#define SOCP_GET_HYPO_ALERT_LEVEL 0x0E /**Get Hypo Alert Level N/A The normal response to this control point is Op Code 0x0F. For error conditions, the response is Response Code */ +#define SOCP_HYPO_ALERT_LEVEL_RESPONSE 0x0F /**Hypo Alert Level Response Hypo Alert Level value in mg/dL This is the normal response to Op Code 0x0E */ +#define SOCP_SET_HYPER_ALERT_LEVEL 0x10 /**Set Hyper Alert Level Hyper Alert Level value in mg/dL The response to this control point is Response Code. */ +#define SOCP_GET_HYPER_ALERT_LEVEL 0x11 /**Get Hyper Alert Level N/A The normal response to this control point is Op Code 0x12. For error conditions, the response is Response Code */ +#define SOCP_HYPER_ALERT_LEVEL_RESPONSE 0x12 /**Hyper Alert Level Response Hyper Alert Level value in mg/dL This is the normal response to Op Code 0x11 */ +#define SOCP_SET_RATE_OF_DECREASE_ALERT_LEVEL 0x13 /**Set Rate of Decrease Alert Level Rate of Decrease Alert Level value in mg/dL/min The response to this control point is Response Code. */ +#define SOCP_GET_RATE_OF_DECREASE_ALERT_LEVEL 0x14 /**Get Rate of Decrease Alert Level N/A The normal response to this control point is Op Code 0x15. For error conditions, the response is Response Code */ +#define SOCP_RATE_OF_DECREASE_ALERT_LEVEL_RESPONSE 0x15 /**Rate of Decrease Alert Level Response Rate of Decrease Alert Level value in mg/dL/min This is the normal response to Op Code 0x14 */ +#define SOCP_SET_RATE_OF_INCREASE_ALERT_LEVEL 0x16 /**Set Rate of Increase Alert Level Rate of Increase Alert Level value in mg/dL/min The response to this control point is Response Code. */ +#define SOCP_GET_RATE_OF_INCREASE_ALERT_LEVEL 0x17 /**Get Rate of Increase Alert Level N/A The normal response to this control point is Op Code 0x18. For error conditions, the response is Response Code */ +#define SOCP_RATE_OF_INCREASE_ALERT_LEVEL_RESPONSE 0x18 /**Rate of Increase Alert Level Response Rate of Increase Alert Level value in mg/dL/min This is the normal response to Op Code 0x17 */ +#define SOCP_RESET_DEVICE_SPECIFIC_ALERT 0x19 /**Reset Device Specific Alert N/A The response to this control point is Response Code. */ + +#define SOCP_START_THE_SESSION 0x1A +#define SOCP_STOP_THE_SESSION 0x1B +#define SOCP_RESPONSE_CODE 0x1C + +#define SOCP_RSP_RESERVED_FOR_FUTURE_USE 0x00 +#define SOCP_RSP_SUCCESS 0x01 +#define SOCP_RSP_OP_CODE_NOT_SUPPORTED 0x02 +#define SOCP_RSP_INVALID_OPERAND 0x03 +#define SOCP_RSP_PROCEDURE_NOT_COMPLETED 0x04 +#define SOCP_RSP_OUT_OF_RANGE 0x05 + +static void ble_socp_decode(uint8_t data_len, uint8_t const * p_data, ble_cgms_socp_value_t * p_socp_val) +{ + p_socp_val->opcode = 0xFF; + p_socp_val->operand_len = 0; + p_socp_val->p_operand = NULL; + + if (data_len > 0) + { + p_socp_val->opcode = p_data[0]; + } + if (data_len > 1) + { + p_socp_val->operand_len = data_len - 1; + p_socp_val->p_operand = (uint8_t*)&p_data[1]; // lint !e416 + } +} + + +uint8_t ble_socp_encode(const ble_socp_rsp_t * p_socp_rsp, uint8_t * p_data) +{ + uint8_t len = 0; + int i; + + + if (p_data != NULL) + { + p_data[len++] = p_socp_rsp->opcode; + + if ( + (p_socp_rsp->opcode != SOCP_READ_CGM_COMMUNICATION_INTERVAL_RESPONSE) + && (p_socp_rsp->opcode != SOCP_READ_PATIENT_HIGH_ALERT_LEVEL_RESPONSE) + && (p_socp_rsp->opcode != SOCP_READ_PATIENT_LOW_ALERT_LEVEL_RESPONSE) + && (p_socp_rsp->opcode != SOCP_HYPO_ALERT_LEVEL_RESPONSE) + && (p_socp_rsp->opcode != SOCP_HYPER_ALERT_LEVEL_RESPONSE) + && (p_socp_rsp->opcode != SOCP_RATE_OF_DECREASE_ALERT_LEVEL_RESPONSE) + && (p_socp_rsp->opcode != SOCP_RATE_OF_INCREASE_ALERT_LEVEL_RESPONSE) + && (p_socp_rsp->opcode != SOCP_READ_GLUCOSE_CALIBRATION_VALUE_RESPONSE) + ) + { + p_data[len++] = p_socp_rsp->req_opcode; + p_data[len++] = p_socp_rsp->rsp_code; + } + + for (i = 0; i < p_socp_rsp->size_val; i++) + { + p_data[len++] = p_socp_rsp->resp_val[i]; + } + } + + return len; +} + + +/**@brief Function for adding a characteristic for the Specific Operations Control Point. + * + * @param[in] p_cgms Service instance. + * + * @return NRF_SUCCESS if characteristic was successfully added, otherwise an error code. + */ +ret_code_t cgms_socp_char_add(nrf_ble_cgms_t * p_cgms) +{ + ble_add_char_params_t add_char_params; + + memset(&add_char_params, 0, sizeof(add_char_params)); + + add_char_params.uuid = BLE_UUID_CGM_SPECIFIC_OPS_CTRLPT; + add_char_params.max_len = BLE_GATT_ATT_MTU_DEFAULT; + add_char_params.init_len = 0; + add_char_params.p_init_value = 0; + add_char_params.is_var_len = true; + add_char_params.char_props.indicate = true; + add_char_params.char_props.write = true; + add_char_params.write_access = SEC_JUST_WORKS; + add_char_params.cccd_write_access = SEC_JUST_WORKS; + add_char_params.is_defered_write = 1; + + return characteristic_add(p_cgms->service_handle, + &add_char_params, + &p_cgms->char_handles.socp); +} + + +/**@brief Function for sending a response from the Specific Operation Control Point. + * + * @param[in] p_cgms Service instance. + */ +static void socp_send(nrf_ble_cgms_t * p_cgms) +{ + uint32_t err_code; + uint8_t encoded_resp[25]; + uint8_t len; + uint16_t hvx_len; + ble_gatts_hvx_params_t hvx_params; + + // Send indication + len = ble_socp_encode(&(p_cgms->socp_response), encoded_resp); + hvx_len = len; + + memset(&hvx_params, 0, sizeof(hvx_params)); + + hvx_params.handle = p_cgms->char_handles.socp.value_handle; + hvx_params.type = BLE_GATT_HVX_INDICATION; + hvx_params.offset = 0; + hvx_params.p_len = &hvx_len; + hvx_params.p_data = encoded_resp; + + err_code = sd_ble_gatts_hvx(p_cgms->conn_handle, &hvx_params); + + // Error handling + if ((err_code == NRF_SUCCESS) && (hvx_len != len)) + { + err_code = NRF_ERROR_DATA_SIZE; + } + + switch (err_code) + { + case NRF_SUCCESS: + // Wait for HVC event. + p_cgms->cgms_com_state = STATE_SOCP_RESPONSE_IND_VERIF; + break; + + case NRF_ERROR_RESOURCES: + // Wait for TX_COMPLETE event to retry transmission. + p_cgms->cgms_com_state = STATE_SOCP_RESPONSE_PENDING; + break; + + case NRF_ERROR_INVALID_STATE: + // Make sure state machine returns to the default state. + p_cgms->cgms_com_state = STATE_NO_COMM; + break; + + default: + // Report error to application. + if (p_cgms->error_handler != NULL) + { + p_cgms->error_handler(err_code); + } + + // Make sure state machine returns to the default state. + p_cgms->cgms_com_state = STATE_NO_COMM; + break; + } +} + + +void encode_get_response(uint8_t rsp_code, ble_socp_rsp_t * p_rsp, uint16_t in_val) +{ + p_rsp->opcode = rsp_code; + p_rsp->rsp_code = SOCP_RSP_SUCCESS; + p_rsp->size_val += uint16_encode(in_val, &(p_rsp->resp_val[p_rsp->size_val])); +} + + +void decode_set_opcode(nrf_ble_cgms_t * p_cgms, + ble_cgms_socp_value_t * rcv_val, + uint16_t min, + uint16_t max, + uint16_t * p_val) +{ + uint16_t rcvd_val = uint16_decode(rcv_val->p_operand); + + if ((rcvd_val == NRF_BLE_CGMS_PLUS_INFINTE) + || (rcvd_val == NRF_BLE_CGMS_MINUS_INFINTE) + || (rcvd_val > max) + || (rcvd_val < min)) + { + p_cgms->socp_response.rsp_code = SOCP_RSP_OUT_OF_RANGE; + } + else + { + p_cgms->socp_response.rsp_code = SOCP_RSP_SUCCESS; + *p_val = rcvd_val; + } +} + + +static bool is_feature_present(nrf_ble_cgms_t * p_cgms, uint32_t feature) +{ + return (p_cgms->feature.feature & feature); +} + + +/**@brief Function for handling a write event to the Specific Operation Control Point. + * + * @param[in] p_cgms Service instance. + * @param[in] p_evt_write WRITE event to be handled. + */ +static void on_socp_value_write(nrf_ble_cgms_t * p_cgms, ble_gatts_evt_write_t const * p_evt_write) +{ + ble_cgms_socp_value_t socp_request; + nrf_ble_cgms_evt_t evt; + ble_gatts_rw_authorize_reply_params_t auth_reply; + uint32_t err_code; + + memset(&auth_reply, 0, sizeof(auth_reply)); + + auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE; + + auth_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS; + auth_reply.params.write.update = 1; + + err_code = sd_ble_gatts_rw_authorize_reply(p_cgms->conn_handle, &auth_reply); + if (err_code != NRF_SUCCESS) + { + if (p_cgms->error_handler != NULL) + { + p_cgms->error_handler(err_code); + } + return; + } + + // Decode request + ble_socp_decode(p_evt_write->len, p_evt_write->data, &socp_request); + + p_cgms->socp_response.opcode = SOCP_RESPONSE_CODE; + p_cgms->socp_response.req_opcode = socp_request.opcode; + p_cgms->socp_response.rsp_code = SOCP_RSP_OP_CODE_NOT_SUPPORTED; + p_cgms->socp_response.size_val = 0; + + + switch (socp_request.opcode) + { + case SOCP_WRITE_CGM_COMMUNICATION_INTERVAL: + p_cgms->socp_response.rsp_code = SOCP_RSP_SUCCESS; + p_cgms->comm_interval = socp_request.p_operand[0]; + evt.evt_type = NRF_BLE_CGMS_EVT_WRITE_COMM_INTERVAL; + p_cgms->evt_handler(p_cgms, &evt); + break; + + case SOCP_READ_CGM_COMMUNICATION_INTERVAL: + p_cgms->socp_response.opcode = SOCP_READ_CGM_COMMUNICATION_INTERVAL_RESPONSE; + p_cgms->socp_response.resp_val[0] = p_cgms->comm_interval; + p_cgms->socp_response.size_val++; + break; + + case SOCP_START_THE_SESSION: + if (p_cgms->is_session_started) + { + p_cgms->socp_response.rsp_code = SOCP_RSP_PROCEDURE_NOT_COMPLETED; + } + else if ((p_cgms->nb_run_session != 0) && + !(is_feature_present(p_cgms, NRF_BLE_CGMS_FEAT_MULTIPLE_SESSIONS_SUPPORTED))) + { + p_cgms->socp_response.rsp_code = SOCP_RSP_PROCEDURE_NOT_COMPLETED; + } + else + { + p_cgms->socp_response.rsp_code = SOCP_RSP_SUCCESS; + p_cgms->is_session_started = true; + p_cgms->nb_run_session++; + + if (p_cgms->evt_handler != NULL) + { + evt.evt_type = NRF_BLE_CGMS_EVT_START_SESSION; + p_cgms->evt_handler(p_cgms, &evt); + } + + ble_cgms_sst_t sst; + memset(&sst, 0, sizeof(ble_cgms_sst_t)); + + err_code = cgms_sst_set(p_cgms, &sst); + if (err_code != NRF_SUCCESS) + { + if (p_cgms->error_handler != NULL) + { + p_cgms->error_handler(err_code); + } + } + p_cgms->sensor_status.time_offset = 0; + p_cgms->sensor_status.status.status &= (~NRF_BLE_CGMS_STATUS_SESSION_STOPPED); + + err_code = nrf_ble_cgms_update_status(p_cgms, &p_cgms->sensor_status); + if (err_code != NRF_SUCCESS) + { + if (p_cgms->error_handler != NULL) + { + p_cgms->error_handler(err_code); + } + } + } + break; + + case SOCP_STOP_THE_SESSION: + { + nrf_ble_cgm_status_t status; + memset(&status, 0, sizeof(nrf_ble_cgm_status_t)); + + p_cgms->evt_handler(p_cgms, &evt); + p_cgms->socp_response.rsp_code = SOCP_RSP_SUCCESS; + p_cgms->is_session_started = false; + + status.time_offset = p_cgms->sensor_status.time_offset; + status.status.status = p_cgms->sensor_status.status.status | + NRF_BLE_CGMS_STATUS_SESSION_STOPPED; + + if (p_cgms->evt_handler != NULL) + { + evt.evt_type = NRF_BLE_CGMS_EVT_STOP_SESSION; + p_cgms->evt_handler(p_cgms, &evt); + } + err_code = nrf_ble_cgms_update_status(p_cgms, &status); + if (err_code != NRF_SUCCESS) + { + if (p_cgms->error_handler != NULL) + { + p_cgms->error_handler(err_code); + } + } + break; + } + + default: + p_cgms->socp_response.rsp_code = SOCP_RSP_OP_CODE_NOT_SUPPORTED; + break; + } + + socp_send(p_cgms); +} + + +void cgms_socp_on_rw_auth_req(nrf_ble_cgms_t * p_cgms, + ble_gatts_evt_rw_authorize_request_t const * p_auth_req) +{ + if (p_auth_req->type == BLE_GATTS_AUTHORIZE_TYPE_WRITE) + { + if (p_auth_req->request.write.handle == p_cgms->char_handles.socp.value_handle) + { + on_socp_value_write(p_cgms, &p_auth_req->request.write); + } + } +} + + +void cgms_socp_on_tx_complete(nrf_ble_cgms_t * p_cgms) +{ + if (p_cgms->cgms_com_state == STATE_SOCP_RESPONSE_PENDING) + { + socp_send(p_cgms); + } +} + + diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_socp.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_socp.h new file mode 100644 index 0000000..80cb35b --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_socp.h @@ -0,0 +1,107 @@ +/** + * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +/** @file + * + * @defgroup ble_sdk_srv_cgms_socp Specific Operations Control Point + * @{ + * @ingroup ble_cgms + * @brief Continuous Glucose Monitoring Service SOCP module. + * + * @details This module implements parts of the Continuous Glucose Monitoring that relate to the + * Specific Operations Control Point. Events are propagated to this module from @ref ble_cgms + * using @ref cgms_socp_on_rw_auth_req and @ref cgms_socp_on_tx_complete. + * + */ + +#ifndef NRF_BLE_CGMS_SOCP_H__ +#define NRF_BLE_CGMS_SOCP_H__ + +#include "ble.h" +#include "ble_srv_common.h" +#include "sdk_errors.h" +#include "nrf_ble_cgms.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/**@brief Specific Operation Control Point value. */ +typedef struct +{ + uint8_t opcode; /**< Opcode. */ + uint8_t operand_len; /**< Length of the operand. */ + uint8_t * p_operand; /**< Pointer to the operand. */ +} ble_cgms_socp_value_t; + + +/**@brief Function for adding a characteristic for the Specific Operations Control Point. + * + * @param[in] p_cgms Instance of the CGM Service. + * + * @retval NRF_SUCCESS If the characteristic was successfully added. + * @return If functions from other modules return errors to this function, + * the @ref nrf_error are propagated. + */ +ret_code_t cgms_socp_char_add(nrf_ble_cgms_t * p_cgms); + + +/**@brief Function for handling @ref BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST events. + * + * @param[in] p_cgms Instance of the CGM Service. + * @param[in] p_auth_req Authorize request event to be handled. + */ +void cgms_socp_on_rw_auth_req(nrf_ble_cgms_t * p_cgms, + ble_gatts_evt_rw_authorize_request_t const * p_auth_req); + + +/**@brief Function for handling @ref BLE_GATTS_EVT_HVN_TX_COMPLETE events. + * + * @param[in] p_cgms Instance of the CGM Service. + */ +void cgms_socp_on_tx_complete(nrf_ble_cgms_t * p_cgms); + +#ifdef __cplusplus +} +#endif + +#endif // NRF_BLE_CGMS_SOCP_H__ + +/** @} */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_sst.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_sst.c new file mode 100644 index 0000000..b6b2fcd --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_sst.c @@ -0,0 +1,235 @@ +/** + * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include <stdint.h> +#include <string.h> +#include <time.h> +#include "ble.h" +#include "ble_srv_common.h" +#include "nrf_ble_cgms.h" +#include "cgms_sst.h" + + +void sst_decode(ble_cgms_sst_t * p_sst, const uint8_t * p_data, const uint16_t len) +{ + uint32_t index; + + if (len != NRF_BLE_CGMS_SST_LEN) + { + return; + } + + index = ble_date_time_decode(&p_sst->date_time, p_data); + + p_sst->time_zone = p_data[index++]; + p_sst->dst = p_data[index++]; +} + + +void convert_ble_time_c_time(ble_cgms_sst_t * p_sst, struct tm * p_c_time_date) +{ + p_c_time_date->tm_sec = p_sst->date_time.seconds; + p_c_time_date->tm_min = p_sst->date_time.minutes; + p_c_time_date->tm_hour = p_sst->date_time.hours; + p_c_time_date->tm_mday = p_sst->date_time.day; + p_c_time_date->tm_mon = p_sst->date_time.month; + p_c_time_date->tm_year = p_sst->date_time.year - 1900; + + // Ignore daylight saving for this conversion. + p_c_time_date->tm_isdst = 0; +} + + +void calc_sst(uint16_t offset, struct tm * p_c_time_date) +{ + time_t c_time_in_sec; + + c_time_in_sec = mktime(p_c_time_date); + c_time_in_sec = c_time_in_sec - (offset * 60); + *p_c_time_date = *(localtime(&c_time_in_sec)); + + if (p_c_time_date->tm_isdst == 1) + { + // Daylight saving time is not used and must be removed. + p_c_time_date->tm_hour = p_c_time_date->tm_hour - 1; + p_c_time_date->tm_isdst = 0; + } +} + + +static void convert_c_time_ble_time(ble_cgms_sst_t * p_sst, struct tm * p_c_time_date) +{ + p_sst->date_time.seconds = p_c_time_date->tm_sec; + p_sst->date_time.minutes = p_c_time_date->tm_min; + p_sst->date_time.hours = p_c_time_date->tm_hour; + p_sst->date_time.day = p_c_time_date->tm_mday; + p_sst->date_time.month = p_c_time_date->tm_mon; + p_sst->date_time.year = p_c_time_date->tm_year + 1900; +} + + +static uint8_t sst_encode(ble_cgms_sst_t * p_sst, uint8_t * p_encoded_sst) +{ + uint8_t len; + + len = ble_date_time_encode(&p_sst->date_time, p_encoded_sst); + + p_encoded_sst[len++] = p_sst->time_zone; + p_encoded_sst[len++] = p_sst->dst; + + return len; +} + + +static ret_code_t cgm_update_sst(nrf_ble_cgms_t * p_cgms, ble_gatts_evt_write_t const * p_evt_write) +{ + ble_cgms_sst_t sst; + struct tm c_time_and_date; + + memset(&sst, 0, sizeof(ble_cgms_sst_t)); + + sst_decode(&sst, p_evt_write->data, p_evt_write->len); + convert_ble_time_c_time(&sst, &c_time_and_date); + calc_sst(p_cgms->sensor_status.time_offset, &c_time_and_date); + convert_c_time_ble_time(&sst, &c_time_and_date); + + return cgms_sst_set(p_cgms, &sst); +} + + +/**@brief Function for handling the Glucose session start time write event. + * + * @param[in] p_cgms Service instance. + * @param[in] p_evt_write WRITE event to be handled. + */ +static void on_sst_value_write(nrf_ble_cgms_t * p_cgms, ble_gatts_evt_write_t const * p_evt_write) +{ + ble_gatts_rw_authorize_reply_params_t auth_reply; + uint32_t err_code; + + memset(&auth_reply, 0, sizeof(auth_reply)); + + auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE; + auth_reply.params.write.update = 1; + auth_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS; + + err_code = sd_ble_gatts_rw_authorize_reply(p_cgms->conn_handle, &auth_reply); + if (err_code != NRF_SUCCESS) + { + if (p_cgms->error_handler != NULL) + { + p_cgms->error_handler(err_code); + } + } + + err_code = cgm_update_sst(p_cgms, p_evt_write); + if (err_code != NRF_SUCCESS) + { + if (p_cgms->error_handler != NULL) + { + p_cgms->error_handler(err_code); + } + } +} + + +/**@brief Function for adding a characteristic for the Session Start Time. + * + * @param[in] p_cgms Service instance. + * + * @return NRF_SUCCESS if characteristic was successfully added, otherwise an error code. + */ +ret_code_t cgms_sst_char_add(nrf_ble_cgms_t * p_cgms) +{ + ble_add_char_params_t add_char_params; + uint8_t init_value[NRF_BLE_CGMS_SST_LEN] = {0}; + + memset(&add_char_params, 0, sizeof(add_char_params)); + + add_char_params.uuid = BLE_UUID_CGM_SESSION_START_TIME; + add_char_params.max_len = NRF_BLE_CGMS_SST_LEN; + + add_char_params.init_len = NRF_BLE_CGMS_SST_LEN; + add_char_params.p_init_value = init_value; + + add_char_params.read_access = SEC_JUST_WORKS; + add_char_params.write_access = SEC_JUST_WORKS; + add_char_params.is_defered_write = 1; + add_char_params.char_props.write = true; + add_char_params.char_props.read = true; + + return characteristic_add(p_cgms->service_handle, + &add_char_params, + &p_cgms->char_handles.sst); +} + + +ret_code_t cgms_sst_set(nrf_ble_cgms_t * p_cgms, ble_cgms_sst_t * p_sst) +{ + uint16_t conn_handle; + uint16_t value_handle; + ble_gatts_value_t sst_val; + uint8_t encoded_start_session_time[NRF_BLE_CGMS_SST_LEN]; + uint8_t gatts_value_set_len = 0; + + gatts_value_set_len = sst_encode(p_sst, encoded_start_session_time); + conn_handle = p_cgms->conn_handle; + value_handle = p_cgms->char_handles.sst.value_handle; + memset(&sst_val, 0, sizeof(ble_gatts_value_t)); + sst_val.len = gatts_value_set_len; + sst_val.p_value = encoded_start_session_time; + sst_val.offset = 0; + + return (sd_ble_gatts_value_set(conn_handle, value_handle, &sst_val)); +} + + +void cgms_sst_on_rw_auth_req(nrf_ble_cgms_t * p_cgms, + ble_gatts_evt_rw_authorize_request_t const * p_auth_req) +{ + if (p_auth_req->type == BLE_GATTS_AUTHORIZE_TYPE_WRITE) + { + if (p_auth_req->request.write.handle == p_cgms->char_handles.sst.value_handle) + { + on_sst_value_write(p_cgms, &p_auth_req->request.write); + } + } +} + + diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_sst.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_sst.h new file mode 100644 index 0000000..800c81c --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_sst.h @@ -0,0 +1,115 @@ +/** + * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +/** @file + * + * @defgroup ble_sdk_srv_cgms_sst Session Start Time + * @{ + * @ingroup ble_cgms + * + * @brief Continuous Glucose Monitoring Service SST module. + * + * @details This module implements parts of the Continuous Glucose Monitoring that relate to the + * Session Start Time characteristic. Events are propagated to this module from @ref ble_cgms + * using @ref cgms_sst_on_rw_auth_req. + * + */ + +#ifndef NRF_BLE_CGMS_SST_H__ +#define NRF_BLE_CGMS_SST_H__ + + +#include "ble.h" +#include "ble_srv_common.h" +#include "ble_date_time.h" +#include "sdk_errors.h" +#include "nrf_ble_cgms.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +/**@brief Required data for setting the SST characteristic value. */ +typedef struct +{ + ble_date_time_t date_time; /**< Date and time. */ + uint8_t time_zone; /**< Time zone. */ + uint8_t dst; /**< Daylight saving time. */ +}ble_cgms_sst_t; + +/**@brief Function for adding a characteristic for the Session Start Time. + * + * @param[in] p_cgms Instance of the CGM Service. + * + * @retval NRF_SUCCESS If the characteristic was successfully added. + * @return If functions from other modules return errors to this function, + * the @ref nrf_error are propagated. + */ +ret_code_t cgms_sst_char_add(nrf_ble_cgms_t * p_cgms); + + +/**@brief Function for setting the Session Run Time attribute. + * + * @param[in] p_cgms Instance of the CGM Service. + * @param[in] p_sst Time and date that will be displayed in the session start time attribute. + * + * @retval NRF_SUCCESS If the Session Run Time Attribute was successfully set. + * @return If functions from other modules return errors to this function, + * the @ref nrf_error are propagated. + */ +ret_code_t cgms_sst_set(nrf_ble_cgms_t * p_cgms, ble_cgms_sst_t * p_sst); + + +/**@brief Function for handling @ref BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST events. + * + * @param[in] p_cgms Instance of the CGM Service. + * @param[in] p_auth_req Authorize request event to be handled. + */ +void cgms_sst_on_rw_auth_req(nrf_ble_cgms_t * p_cgms, + ble_gatts_evt_rw_authorize_request_t const * p_auth_req); + +#ifdef __cplusplus +} +#endif + +#endif // NRF_BLE_CGMS_SST_H__ + +/** @} */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/nrf_ble_cgms.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/nrf_ble_cgms.c new file mode 100644 index 0000000..f895edb --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/nrf_ble_cgms.c @@ -0,0 +1,504 @@ +/** + * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include "ble_racp.h" +#include "ble_srv_common.h" + +#include "ble_date_time.h" +#include "sdk_common.h" + +#include "nrf_ble_cgms.h" +#include "cgms_db.h" +#include "cgms_meas.h" +#include "cgms_racp.h" +#include "cgms_socp.h" +#include "cgms_sst.h" + +#define OPERAND_FILTER_TYPE_RESV 0x00 /**< Filter type value reserved for future use. */ +#define OPERAND_FILTER_TYPE_SEQ_NUM 0x01 /**< Filter data using Sequence Number criteria. */ +#define OPERAND_FILTER_TYPE_FACING_TIME 0x02 /**< Filter data using User Facing Time criteria. */ + + +/**@brief Function for setting next sequence number by reading the last record in the data base. + * + * @return NRF_SUCCESS on successful initialization of service, otherwise an error code. + */ +static uint32_t next_sequence_number_set(void) +{ + uint16_t num_records; + ble_cgms_rec_t rec; + + num_records = cgms_db_num_records_get(); + if (num_records > 0) + { + // Get last record + uint32_t err_code = cgms_db_record_get(num_records - 1, &rec); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + } + + return NRF_SUCCESS; +} + + +uint8_t encode_feature_location_type(uint8_t * p_out_buffer, nrf_ble_cgms_feature_t * p_in_feature) +{ + uint8_t len = 0; + + len += uint24_encode(p_in_feature->feature, &p_out_buffer[len]); + p_out_buffer[len++] = (p_in_feature->sample_location << 4) | (p_in_feature->type & 0x0F); + len += uint16_encode(0xFFFF, &p_out_buffer[len]); + + return len; +} + + +/**@brief Function for adding a characteristic for the glucose feature. + * + * @param[in] p_cgms Service instance. + * + * @return NRF_SUCCESS if characteristic was successfully added, otherwise an error code. + */ +static uint32_t glucose_feature_char_add(nrf_ble_cgms_t * p_cgms) +{ + uint8_t init_value_len; + uint8_t encoded_initial_feature[NRF_BLE_CGMS_FEATURE_LEN]; + ble_add_char_params_t add_char_params; + + memset(&add_char_params, 0, sizeof(add_char_params)); + + init_value_len = encode_feature_location_type(encoded_initial_feature, &(p_cgms->feature)); + + add_char_params.uuid = BLE_UUID_CGM_FEATURE; + add_char_params.max_len = init_value_len; + add_char_params.init_len = init_value_len; + add_char_params.p_init_value = encoded_initial_feature; + add_char_params.read_access = SEC_JUST_WORKS; + add_char_params.write_access = SEC_NO_ACCESS; + + + return characteristic_add(p_cgms->service_handle, + &add_char_params, + &p_cgms->char_handles.feature); +} + + +uint8_t encode_status(uint8_t * p_out_buffer, nrf_ble_cgms_t * p_cgms) +{ + uint8_t len = 0; + + len += uint16_encode(p_cgms->sensor_status.time_offset, &p_out_buffer[len]); + + p_out_buffer[len++] = p_cgms->sensor_status.status.status; + p_out_buffer[len++] = p_cgms->sensor_status.status.calib_temp; + p_out_buffer[len++] = p_cgms->sensor_status.status.warning; + + return len; +} + + +/**@brief Function for adding a status characteristic for the CGMS. + * + * @param[in] p_cgms Service instance. + * + * @return NRF_SUCCESS if characteristic was successfully added, otherwise an error code. + */ +static uint32_t status_char_add(nrf_ble_cgms_t * p_cgms) +{ + uint8_t init_value_len; + uint8_t encoded_initial_status[NRF_BLE_CGMS_STATUS_LEN]; + ble_add_char_params_t add_char_params; + + memset(&add_char_params, 0, sizeof(add_char_params)); + + init_value_len = encode_status(encoded_initial_status, p_cgms); + + add_char_params.uuid = BLE_UUID_CGM_STATUS; + add_char_params.max_len = init_value_len; + add_char_params.init_len = init_value_len; + add_char_params.p_init_value = encoded_initial_status; + add_char_params.read_access = SEC_JUST_WORKS; + add_char_params.write_access = SEC_NO_ACCESS; + + return characteristic_add(p_cgms->service_handle, + &add_char_params, + &p_cgms->char_handles.status); +} + + +/**@brief Function for adding a characteristic for the Session Run Time. + * + * @param[in] p_cgms Service instance. + * + * @return NRF_SUCCESS if characteristic was successfully added, otherwise an error code. + */ +static uint32_t srt_char_add(nrf_ble_cgms_t * p_cgms) +{ + uint8_t len = 0; + uint8_t encoded_initial_srt[NRF_BLE_CGMS_SRT_LEN]; + ble_add_char_params_t add_char_params; + + memset(&add_char_params, 0, sizeof(add_char_params)); + + + len += uint16_encode(p_cgms->session_run_time, &(encoded_initial_srt[len])); + + add_char_params.uuid = BLE_UUID_CGM_SESSION_RUN_TIME; + add_char_params.max_len = NRF_BLE_CGMS_SRT_LEN; + add_char_params.init_len = len; + add_char_params.p_init_value = encoded_initial_srt; + add_char_params.read_access = SEC_JUST_WORKS; + add_char_params.write_access = SEC_NO_ACCESS; + add_char_params.char_props.read = true; + + return characteristic_add(p_cgms->service_handle, + &add_char_params, + &p_cgms->char_handles.srt); +} + + +uint8_t init_calib_val[] = { + 0x3E, + 0x00, + 0x07, + 0x00, + 0x06, + 0x07, + 0x00, + 0x00, + 0x00, + 0x00, +}; +ret_code_t nrf_ble_cgms_init(nrf_ble_cgms_t * p_cgms, const nrf_ble_cgms_init_t * p_cgms_init) +{ + VERIFY_PARAM_NOT_NULL(p_cgms); + VERIFY_PARAM_NOT_NULL(p_cgms_init); + VERIFY_PARAM_NOT_NULL(p_cgms_init->evt_handler); + + uint32_t err_code; + ble_uuid_t ble_uuid; + + // Initialize data base + err_code = cgms_db_init(); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + + err_code = next_sequence_number_set(); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + + // Initialize service structure + p_cgms->evt_handler = p_cgms_init->evt_handler; + p_cgms->error_handler = p_cgms_init->error_handler; + p_cgms->feature = p_cgms_init->feature; + p_cgms->sensor_status = p_cgms_init->initial_sensor_status; + p_cgms->session_run_time = p_cgms_init->initial_run_time; + p_cgms->is_session_started = false; + p_cgms->nb_run_session = 0; + p_cgms->conn_handle = BLE_CONN_HANDLE_INVALID; + + p_cgms->feature.feature = 0; + p_cgms->feature.feature |= NRF_BLE_CGMS_FEAT_MULTIPLE_BOND_SUPPORTED; + p_cgms->feature.feature |= NRF_BLE_CGMS_FEAT_MULTIPLE_SESSIONS_SUPPORTED; + p_cgms->feature.type = NRF_BLE_CGMS_MEAS_TYPE_VEN_BLOOD; + p_cgms->feature.sample_location = NRF_BLE_CGMS_MEAS_LOC_AST; + p_cgms->feature.feature |= NRF_BLE_CGMS_FEAT_MULTIPLE_BOND_SUPPORTED; + + memcpy(p_cgms->calibration_val[0].value, init_calib_val, NRF_BLE_CGMS_MAX_CALIB_LEN); + + // Initialize global variables + p_cgms->cgms_com_state = STATE_NO_COMM; + p_cgms->racp_data.racp_proc_records_reported_since_txcomplete = 0; + + // Add service + BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_CGM_SERVICE); + + err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, + &ble_uuid, + &p_cgms->service_handle); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + + // Add glucose measurement characteristic + err_code = cgms_meas_char_add(p_cgms); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + + // Add glucose measurement feature characteristic + err_code = glucose_feature_char_add(p_cgms); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + + // Add glucose measurement status characteristic + err_code = status_char_add(p_cgms); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + + // Add record control access point characteristic + err_code = cgms_racp_char_add(p_cgms); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + + // Add Start Session Time characteristic + err_code = cgms_sst_char_add(p_cgms); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + + // Add Session Run Time characteristic + err_code = srt_char_add(p_cgms); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + + // Add Specific Operations Control Point characteristic + err_code = cgms_socp_char_add(p_cgms); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + + return NRF_SUCCESS; +} + + +/**@brief Function for handling the WRITE event. + * + * @details Handles WRITE events from the BLE stack. + * + * @param[in] p_cgms Glucose Service structure. + * @param[in] p_ble_evt Event received from the BLE stack. + */ +static void on_write(nrf_ble_cgms_t * p_cgms, ble_evt_t const * p_ble_evt) +{ + ble_gatts_evt_write_t const * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write; + + cgms_meas_on_write(p_cgms, p_evt_write); +} + + +/**@brief Function for handling the TX_COMPLETE event. + * + * @details Handles TX_COMPLETE events from the BLE stack. + * + * @param[in] p_cgms Glucose Service structure. + * @param[in] p_ble_evt Event received from the BLE stack. + */ +static void on_tx_complete(nrf_ble_cgms_t * p_cgms, ble_evt_t const * p_ble_evt) +{ + p_cgms->racp_data.racp_proc_records_reported_since_txcomplete = 0; + + cgms_racp_on_tx_complete(p_cgms); + cgms_socp_on_tx_complete(p_cgms); +} + + +/**@brief Function for handling the HVC event. + * + * @details Handles HVC events from the BLE stack. + * + * @param[in] p_cgms Glucose Service structure. + * @param[in] p_ble_evt Event received from the BLE stack. + */ +static void on_hvc(nrf_ble_cgms_t * p_cgms, ble_evt_t const * p_ble_evt) +{ + ble_gatts_evt_hvc_t const * p_hvc = &p_ble_evt->evt.gatts_evt.params.hvc; + + if (p_hvc->handle == p_cgms->char_handles.racp.value_handle) + { + if (p_cgms->cgms_com_state == STATE_RACP_RESPONSE_IND_VERIF) + { + // Indication has been acknowledged. Return to default state. + p_cgms->cgms_com_state = STATE_NO_COMM; + } + else + { + // We did not expect this event in this state. Report error to application. + if (p_cgms->error_handler != NULL) + { + p_cgms->error_handler(NRF_ERROR_INVALID_STATE); + } + } + } + if (p_hvc->handle == p_cgms->char_handles.socp.value_handle) + { + if (p_cgms->cgms_com_state == STATE_SOCP_RESPONSE_IND_VERIF) + { + // Indication has been acknowledged. Return to default state. + p_cgms->cgms_com_state = STATE_NO_COMM; + } + else + { + // We did not expect this event in this state. Report error to application. + if (p_cgms->error_handler != NULL) + { + p_cgms->error_handler(NRF_ERROR_INVALID_STATE); + } + } + } +} + + +static void on_rw_authorize_request(nrf_ble_cgms_t * p_cgms, ble_gatts_evt_t const * p_gatts_evt) +{ + ble_gatts_evt_rw_authorize_request_t const * p_auth_req = + &p_gatts_evt->params.authorize_request; + + cgms_racp_on_rw_auth_req(p_cgms, p_auth_req); + cgms_socp_on_rw_auth_req(p_cgms, p_auth_req); + cgms_sst_on_rw_auth_req(p_cgms, p_auth_req); +} + + +void nrf_ble_cgms_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context) +{ + nrf_ble_cgms_t * p_cgms = (nrf_ble_cgms_t *)p_context; + + switch (p_ble_evt->header.evt_id) + { + case BLE_GAP_EVT_CONNECTED: + p_cgms->conn_handle = p_ble_evt->evt.gap_evt.conn_handle; + p_cgms->cgms_com_state = STATE_NO_COMM; + break; + + case BLE_GAP_EVT_DISCONNECTED: + p_cgms->conn_handle = BLE_CONN_HANDLE_INVALID; + break; + + case BLE_GATTS_EVT_WRITE: + on_write(p_cgms, p_ble_evt); + break; + + case BLE_GATTS_EVT_HVN_TX_COMPLETE: + on_tx_complete(p_cgms, p_ble_evt); + break; + + case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST: + on_rw_authorize_request(p_cgms, &p_ble_evt->evt.gatts_evt); + break; + + case BLE_GATTS_EVT_HVC: + on_hvc(p_cgms, p_ble_evt); + break; + + default: + // No implementation needed. + break; + } +} + + +ret_code_t nrf_ble_cgms_meas_create(nrf_ble_cgms_t * p_cgms, ble_cgms_rec_t * p_rec) +{ + uint32_t err_code = NRF_SUCCESS; + uint8_t nb_rec_to_send = 1; + + err_code = cgms_db_record_add(p_rec); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + if ((p_cgms->conn_handle != BLE_CONN_HANDLE_INVALID) && (p_cgms->comm_interval != 0)) + { + err_code = cgms_meas_send(p_cgms, p_rec, &nb_rec_to_send); + } + return err_code; +} + + +ret_code_t nrf_ble_cgms_update_status(nrf_ble_cgms_t * p_cgms, nrf_ble_cgm_status_t * p_status) +{ + uint8_t encoded_status[NRF_BLE_CGMS_STATUS_LEN]; + ble_gatts_value_t status_val; + + memset(&status_val, 0, sizeof(status_val)); + p_cgms->sensor_status = *p_status; + status_val.len = encode_status(encoded_status, p_cgms); + status_val.p_value = encoded_status; + status_val.offset = 0; + + return (sd_ble_gatts_value_set(p_cgms->conn_handle, p_cgms->char_handles.status.value_handle, + &status_val)); +} + + +ret_code_t nrf_ble_cgms_conn_handle_assign(nrf_ble_cgms_t * p_cgms, uint16_t conn_handle) +{ + VERIFY_PARAM_NOT_NULL(p_cgms); + p_cgms->conn_handle = conn_handle; + return NRF_SUCCESS; +} + + +ret_code_t nrf_ble_cgms_srt_set(nrf_ble_cgms_t * p_cgms, uint16_t run_time) +{ + ble_gatts_value_t srt_val; + uint8_t encoded_session_run_time[NRF_BLE_CGMS_SRT_LEN]; + uint8_t gatts_value_set_len = 0; + + gatts_value_set_len = uint16_encode(run_time, encoded_session_run_time); // (p_sst, encoded_start_session_time); + + memset(&srt_val, 0, sizeof(ble_gatts_value_t)); + srt_val.len = gatts_value_set_len; + srt_val.p_value = encoded_session_run_time; + srt_val.offset = 0; + + return (sd_ble_gatts_value_set(p_cgms->conn_handle, p_cgms->char_handles.srt.value_handle, + &srt_val)); +} + + diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/nrf_ble_cgms.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/nrf_ble_cgms.h new file mode 100644 index 0000000..dbac766 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/nrf_ble_cgms.h @@ -0,0 +1,453 @@ +/** + * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +/** @file + * + * @defgroup ble_cgms Continuous Glucose Monitoring Service + * @{ + * @ingroup ble_sdk_srv + * @brief Continuous Glucose Monitoring Service (CGMS) module. + * + * @details This module implements a sensor for the Continuous Glucose Monitoring Service. + * The sensor is a GATT Server that sends CGM measurements to a connected CGMS + * Collector. The CGMS Sensor stores records that can be accessed with the + * Record Access Control Point (RACP). The collector can access the features and status + * of the sensor. Session Run Time and Session Start Time can be used to convey timing + * information between the sensor and the collector. The Specific Operations Control Point + * is used to stop and start monitoring sessions, among other things. + * + * @note The application must register this module as BLE event observer using the + * NRF_SDH_BLE_OBSERVER macro. Example: + * @code + * nrf_ble_cgms_t instance; + * NRF_SDH_BLE_OBSERVER(anything, NRF_BLE_CGMS_BLE_OBSERVER_PRIO, + * nrf_ble_cgms_on_ble_evt, &instance); + * @endcode + */ + +#ifndef NRF_BLE_CGMS_H__ +#define NRF_BLE_CGMS_H__ + +#include "ble_srv_common.h" +#include "sdk_errors.h" +#include "ble_racp.h" +#include "nrf_sdh_ble.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/**@brief Macro for defining a nrf_ble_cgms instance. + * + * @param _name Name of the instance. + * @hideinitializer + */ +#define NRF_BLE_CGMS_DEF(_name) \ +static nrf_ble_cgms_t _name; \ +NRF_SDH_BLE_OBSERVER(_name ## _obs, \ + NRF_BLE_CGMS_BLE_OBSERVER_PRIO, \ + nrf_ble_cgms_on_ble_evt, &_name) + +/**@name CGM Feature characteristic defines + * @{ */ +#define NRF_BLE_CGMS_FEAT_CALIBRATION_SUPPORTED (0x01 << 0) //!< Calibration supported. +#define NRF_BLE_CGMS_FEAT_PATIENT_HIGH_LOW_ALERTS_SUPPORTED (0x01 << 1) //!< Patient High/Low Alerts supported. +#define NRF_BLE_CGMS_FEAT_HYPO_ALERTS_SUPPORTED (0x01 << 2) //!< Hypo Alerts supported. +#define NRF_BLE_CGMS_FEAT_HYPER_ALERTS_SUPPORTED (0x01 << 3) //!< Hyper Alerts supported. +#define NRF_BLE_CGMS_FEAT_RATE_OF_INCREASE_DECREASE_ALERTS_SUPPORTED (0x01 << 4) //!< Rate of Increase/Decrease Alerts supported. +#define NRF_BLE_CGMS_FEAT_DEVICE_SPECIFIC_ALERT_SUPPORTED (0x01 << 5) //!< Device Specific Alert supported. +#define NRF_BLE_CGMS_FEAT_SENSOR_MALFUNCTION_DETECTION_SUPPORTED (0x01 << 6) //!< Sensor Malfunction Detection supported. +#define NRF_BLE_CGMS_FEAT_SENSOR_TEMPERATURE_HIGH_LOW_DETECTION_SUPPORTED (0x01 << 7) //!< Sensor Temperature High-Low Detection supported. +#define NRF_BLE_CGMS_FEAT_SENSOR_RESULT_HIGH_LOW_DETECTION_SUPPORTED (0x01 << 8) //!< Sensor Result High-Low Detection supported. +#define NRF_BLE_CGMS_FEAT_LOW_BATTERY_DETECTION_SUPPORTED (0x01 << 9) //!< Low Battery Detection supported. +#define NRF_BLE_CGMS_FEAT_SENSOR_TYPE_ERROR_DETECTION_SUPPORTED (0x01 << 10) //!< Sensor Type Error Detection supported. +#define NRF_BLE_CGMS_FEAT_GENERAL_DEVICE_FAULT_SUPPORTED (0x01 << 11) //!< General Device Fault supported. +#define NRF_BLE_CGMS_FEAT_E2E_CRC_SUPPORTED (0x01 << 12) //!< E2E-CRC supported. +#define NRF_BLE_CGMS_FEAT_MULTIPLE_BOND_SUPPORTED (0x01 << 13) //!< Multiple Bond supported. +#define NRF_BLE_CGMS_FEAT_MULTIPLE_SESSIONS_SUPPORTED (0x01 << 14) //!< Multiple Sessions supported. +#define NRF_BLE_CGMS_FEAT_CGM_TREND_INFORMATION_SUPPORTED (0x01 << 15) //!< CGM Trend Information supported. +#define NRF_BLE_CGMS_FEAT_CGM_QUALITY_SUPPORTED (0x01 << 16) //!< CGM Quality supported. +/** @} */ + +/**@name Continuous Glucose Monitoring type + * @{ */ +#define NRF_BLE_CGMS_MEAS_TYPE_CAP_BLOOD 0x01 //!< Capillary Whole blood. +#define NRF_BLE_CGMS_MEAS_TYPE_CAP_PLASMA 0x02 //!< Capillary Plasma. +#define NRF_BLE_CGMS_MEAS_TYPE_VEN_BLOOD 0x03 //!< Venous Whole blood. +#define NRF_BLE_CGMS_MEAS_TYPE_VEN_PLASMA 0x04 //!< Venous Plasma. +#define NRF_BLE_CGMS_MEAS_TYPE_ART_BLOOD 0x05 //!< Arterial Whole blood. +#define NRF_BLE_CGMS_MEAS_TYPE_ART_PLASMA 0x06 //!< Arterial Plasma. +#define NRF_BLE_CGMS_MEAS_TYPE_UNDET_BLOOD 0x07 //!< Undetermined Whole blood. +#define NRF_BLE_CGMS_MEAS_TYPE_UNDET_PLASMA 0x08 //!< Undetermined Plasma. +#define NRF_BLE_CGMS_MEAS_TYPE_FLUID 0x09 //!< Interstitial Fluid (ISF). +#define NRF_BLE_CGMS_MEAS_TYPE_CONTROL 0x0A //!< Control Solution. +/** @} */ + +/**@name CGM sample location + * @{ */ +#define NRF_BLE_CGMS_MEAS_LOC_FINGER 0x01 //!< Finger. +#define NRF_BLE_CGMS_MEAS_LOC_AST 0x02 //!< Alternate Site Test (AST). +#define NRF_BLE_CGMS_MEAS_LOC_EAR 0x03 //!< Earlobe. +#define NRF_BLE_CGMS_MEAS_LOC_CONTROL 0x04 //!< Control solution. +#define NRF_BLE_CGMS_MEAS_LOC_SUB_TISSUE 0x05 //!< Subcutaneous tissue. +#define NRF_BLE_CGMS_MEAS_LOC_NOT_AVAIL 0x0F //!< Sample Location value not available. +/** @} */ + +/**@name CGM Measurement Sensor Status Annunciation + * @{ */ +#define NRF_BLE_CGMS_STATUS_SESSION_STOPPED (0x01 << 0) //!< Status: Session Stopped. +#define NRF_BLE_CGMS_STATUS_DEVICE_BATTERY_LOW (0x01 << 1) //!< Status: Device Battery Low. +#define NRF_BLE_CGMS_STATUS_SENSOR_TYPE_INCORRECT_FOR_DEVICE (0x01 << 2) //!< Status: Sensor type incorrect for device. +#define NRF_BLE_CGMS_STATUS_SENSOR_MALFUNCTION (0x01 << 3) //!< Status: Sensor malfunction. +#define NRF_BLE_CGMS_STATUS_DEVICE_SPECIFIC_ALERT (0x01 << 4) //!< Status: Device Specific Alert. +#define NRF_BLE_CGMS_STATUS_GENERAL_DEVICE_FAULT (0x01 << 5) //!< Status: General device fault has occurred in the sensor. +/** @} */ + +/**@name CGM Measurement flags + * @{ */ +#define NRF_BLE_CGMS_FLAG_TREND_INFO_PRESENT 0x01 //!< CGM Trend Information Present. +#define NRF_BLE_CGMS_FLAGS_QUALITY_PRESENT 0x02 //!< CGM Quality Present. +#define NRF_BLE_CGMS_STATUS_FLAGS_WARNING_OCT_PRESENT 0x20 //!< Sensor Status Annunciation Field, Warning-Octet present. +#define NRF_BLE_CGMS_STATUS_FLAGS_CALTEMP_OCT_PRESENT 0x40 //!< Sensor Status Annunciation Field, Cal/Temp-Octet present. +#define NRF_BLE_CGMS_STATUS_FLAGS_STATUS_OCT_PRESENT 0x80 //!< Sensor Status Annunciation Field, Status-Octet present. +/** @} */ + +/**@name Byte length of various commands (used for validating, encoding, and decoding data). + * @{ */ +#define NRF_BLE_CGMS_MEAS_OP_LEN 1 //!< Length of the opcode inside the Glucose Measurement packet. +#define NRF_BLE_CGMS_MEAS_HANDLE_LEN 2 //!< Length of the handle inside the Glucose Measurement packet. +#define NRF_BLE_CGMS_MEAS_LEN_MAX (BLE_GATT_ATT_MTU_DEFAULT - \ + NRF_BLE_CGMS_MEAS_OP_LEN - \ + NRF_BLE_CGMS_MEAS_HANDLE_LEN) //!< Maximum size of a transmitted Glucose Measurement. + +#define NRF_BLE_CGMS_MEAS_REC_LEN_MAX 15 //!< Maximum length of one measurement record. Size 1 byte, flags 1 byte, glucose concentration 2 bytes, offset 2 bytes, status 3 bytes, trend 2 bytes, quality 2 bytes, CRC 2 bytes. +#define NRF_BLE_CGMS_MEAS_REC_LEN_MIN 6 //!< Minimum length of one measurement record. Size 1 byte, flags 1 byte, glucose concentration 2 bytes, offset 2 bytes. +#define NRF_BLE_CGMS_MEAS_REC_PER_NOTIF_MAX (NRF_BLE_CGMS_MEAS_LEN_MAX / \ + NRF_BLE_CGMS_MEAS_REC_LEN_MIN) //!< Maximum number of records per notification. We can send more than one measurement record per notification, but we do not want a a single record split over two notifications. + +#define NRF_BLE_CGMS_SOCP_RESP_CODE_LEN 2 //!< Length of a response. Response code 1 byte, response value 1 byte. +#define NRF_BLE_CGMS_FEATURE_LEN 6 //!< Length of a feature. Feature 3 bytes, type 4 bits, sample location 4 bits, CRC 2 bytes. +#define NRF_BLE_CGMS_STATUS_LEN 7 //!< Length of a status. Offset 2 bytes, status 3 bytes, CRC 2 bytes. +#define NRF_BLE_CGMS_MAX_CALIB_LEN 10 //!< Length of a calibration record. Concentration 2 bytes, time 2 bytes, calibration 4 bits, calibration sample location 4 bits, next calibration time 2 bytes, record number 2 bytes, calibration status 1 byte. +#define NRF_BLE_CGMS_CALIBS_NB_MAX 5 //!< Maximum number of calibration values that can be stored. +#define NRF_BLE_CGMS_SST_LEN 9 //!< Length of the start time. Date time 7 bytes, time zone 1 byte, DST 1 byte. +#define NRF_BLE_CGMS_CRC_LEN 2 //!< Length of the CRC bytes (if used). +#define NRF_BLE_CGMS_SRT_LEN 2 //!< Length of the Session Run Time attribute. + +#define NRF_BLE_CGMS_SOCP_RESP_LEN (NRF_BLE_CGMS_MEAS_LEN_MAX - \ + NRF_BLE_CGMS_SOCP_RESP_CODE_LEN) //!< Max lenth of a SOCP response. + +#define NRF_BLE_CGMS_RACP_PENDING_OPERANDS_MAX 2 // !< Maximum number of pending Record Access Control Point operations. +/** @} */ + +/** + * @defgroup nrf_ble_cgms_enums Enumerations + * @{ + */ + +/**@brief CGM Service events. */ +typedef enum +{ + NRF_BLE_CGMS_EVT_NOTIFICATION_ENABLED, /**< Glucose value notification enabled. */ + NRF_BLE_CGMS_EVT_NOTIFICATION_DISABLED, /**< Glucose value notification disabled. */ + NRF_BLE_CGMS_EVT_START_SESSION, /**< Glucose value notification start session. */ + NRF_BLE_CGMS_EVT_STOP_SESSION, /**< Glucose value notification stop session. */ + NRF_BLE_CGMS_EVT_WRITE_COMM_INTERVAL, /**< Glucose value write communication interval. */ +} nrf_ble_cgms_evt_type_t; + + +/**@brief CGM Service communication states. */ +typedef enum +{ + STATE_NO_COMM, /**< The service is not in a communicating state. */ + STATE_RACP_PROC_ACTIVE, /**< Processing requested data. */ + STATE_RACP_RESPONSE_PENDING, /**< There is an RACP indication waiting to be sent. */ + STATE_RACP_RESPONSE_IND_VERIF, /**< Waiting for a verification of an RACP indication. */ + STATE_SOCP_RESPONSE_PENDING, /**< There is an SOCP indication waiting to be sent. */ + STATE_SOCP_RESPONSE_IND_VERIF /**< Waiting for a verification of an SOCP indication. */ +} nrf_ble_cgms_com_state_t; + +/** @} */ // End tag for Enumeration group. + +/** + * @defgroup nrf_ble_cgms_structs Structures + * @{ + */ + +/**@brief CGM Service event. */ +typedef struct +{ + nrf_ble_cgms_evt_type_t evt_type; /**< Type of event. */ +} nrf_ble_cgms_evt_t; + +/** @} */ // End tag for Structure group. + +/** + * @defgroup nrf_ble_cgms_types Types + * @{ + */ + +/**@brief Forward declaration of the nrf_ble_cgms_t type. */ +typedef struct ble_cgms_s nrf_ble_cgms_t; + + +/**@brief CGM Service event handler type. */ +typedef void (* ble_cgms_evt_handler_t) (nrf_ble_cgms_t * p_cgms, nrf_ble_cgms_evt_t * p_evt); + +/** @} */ // End tag for Types group. + +/** + * @addtogroup nrf_ble_cgms_structs + * @{ + */ + +/**@brief CGM Measurement Sensor Status Annunciation. */ +typedef struct +{ + uint8_t warning; /**< Warning annunciation. */ + uint8_t calib_temp; /**< Calibration and Temperature annunciation. */ + uint8_t status; /**< Status annunciation. */ +} nrf_ble_cgms_sensor_annunc_t; + + +/**@brief CGM measurement. */ +typedef struct +{ + uint8_t flags; /**< Indicates the presence of optional fields and the Sensor Status Annunciation field. */ + uint16_t glucose_concentration; /**< Glucose concentration. 16-bit word comprising 4-bit exponent and signed 12-bit mantissa. */ + uint16_t time_offset; /**< Time offset. Represents the time difference between measurements. */ + nrf_ble_cgms_sensor_annunc_t sensor_status_annunciation; /**< Sensor Status Annunciation. Variable length, can include Status, Cal/Temp, and Warning. */ + uint16_t trend; /**< Optional field that can include Trend Information. */ + uint16_t quality; /**< Optional field that includes the Quality of the measurement. */ +} nrf_ble_cgms_meas_t; + + +/**@brief CGM Measurement record. */ +typedef struct +{ + nrf_ble_cgms_meas_t meas; /**< CGM measurement. */ +} ble_cgms_rec_t; + + +/**@brief Features supported by the CGM Service. */ +typedef struct +{ + uint32_t feature; /**< Information on supported features in the CGM Service. */ + uint8_t type; /**< Type. */ + uint8_t sample_location; /**< Sample location. */ +}nrf_ble_cgms_feature_t; + + +/**@brief Status of the CGM measurement. */ +typedef struct +{ + uint16_t time_offset; /**< Time offset. */ + nrf_ble_cgms_sensor_annunc_t status; /**< Status. */ +} nrf_ble_cgm_status_t; + + +/**@brief CGM Service initialization structure that contains all options and data needed for + * initializing the service. */ +typedef struct +{ + ble_cgms_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the CGM Service. */ + ble_srv_error_handler_t error_handler; /**< Function to be called when an error occurs. */ + nrf_ble_cgms_feature_t feature; /**< Features supported by the service. */ + nrf_ble_cgm_status_t initial_sensor_status; /**< Sensor status. */ + uint16_t initial_run_time; /**< Run time. */ +} nrf_ble_cgms_init_t; + + +/**@brief Specific Operation Control Point response structure. */ +typedef struct +{ + uint8_t opcode; /**< Opcode describing the response. */ + uint8_t req_opcode; /**< The original opcode for the request to which this response belongs. */ + uint8_t rsp_code; /**< Response code. */ + uint8_t resp_val[NRF_BLE_CGMS_SOCP_RESP_LEN]; /**< Array containing the response value. */ + uint8_t size_val; /**< Length of the response value. */ +} ble_socp_rsp_t; + + +/**@brief Calibration value. */ +typedef struct +{ + uint8_t value[NRF_BLE_CGMS_MAX_CALIB_LEN]; /**< Array containing the calibration value. */ +} nrf_ble_cgms_calib_t; + + +/**@brief Record Access Control Point transaction data. */ +typedef struct +{ + uint8_t racp_proc_operator; /**< Operator of the current request. */ + uint16_t racp_proc_record_ndx; /**< Current record index. */ + uint16_t racp_proc_records_ndx_last_to_send; /**< The last record to send, can be used together with racp_proc_record_ndx to determine a range of records to send. (used by greater/less filters). */ + uint16_t racp_proc_records_reported; /**< Number of reported records. */ + uint16_t racp_proc_records_reported_since_txcomplete; /**< Number of reported records since the last TX_COMPLETE event. */ + ble_racp_value_t racp_request; /**< RACP procedure that has been requested from the peer. */ + ble_racp_value_t pending_racp_response; /**< RACP response to be sent. */ + uint8_t pending_racp_response_operand[NRF_BLE_CGMS_RACP_PENDING_OPERANDS_MAX]; /**< Operand of the RACP response to be sent. */ +} nrf_ble_cgms_racp_t; + + +/** @brief Handles related to CGM characteristics. */ +typedef struct +{ + ble_gatts_char_handles_t measurment; /**< Handles related to the CGM Measurement characteristic. */ + ble_gatts_char_handles_t feature; /**< Handles related to the CGM Feature characteristic. */ + ble_gatts_char_handles_t sst; /**< Handles related to the CGM Session Start Time characteristic. */ + ble_gatts_char_handles_t racp; /**< Handles related to the CGM Record Access Control Point characteristic. */ + ble_gatts_char_handles_t srt; /**< Handles related to the CGM Session Run Time characteristic. */ + ble_gatts_char_handles_t socp; /**< Handles related to the CGM Specific Operations Control Point characteristic. */ + ble_gatts_char_handles_t status; /**< Handles related to the CGM Status characteristic. */ +} nrf_ble_cgms_char_handler_t; + + +/**@brief Status information for the CGM Service. */ +struct ble_cgms_s +{ + ble_cgms_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the CGM Service. */ + ble_srv_error_handler_t error_handler; /**< Function to be called if an error occurs. */ + uint16_t service_handle; /**< Handle of the CGM Service (as provided by the BLE stack). */ + nrf_ble_cgms_char_handler_t char_handles; /**< GATTS characteristic handles for the different characteristics in the service. */ + uint16_t conn_handle; /**< Handle of the current connection (as provided by the BLE stack; @ref BLE_CONN_HANDLE_INVALID if not in a connection). */ + nrf_ble_cgms_feature_t feature; /**< Structure to store the value of the feature characteristic. */ + uint8_t comm_interval; /**< Variable to keep track of the communication interval. */ + ble_socp_rsp_t socp_response; /**< Structure containing reponse data to be indicated to the peer device. */ + nrf_ble_cgms_calib_t calibration_val[NRF_BLE_CGMS_CALIBS_NB_MAX]; /**< Calibration value. Can be read from and written to SOCP. */ + bool is_session_started; /**< Indicator if we are currently in a session. */ + uint8_t nb_run_session; /**< Variable to keep track of the number of sessions that were run. */ + uint16_t session_run_time; /**< Variable to store the expected run time of a session. */ + nrf_ble_cgm_status_t sensor_status; /**< Structure to keep track of the sensor status. */ + nrf_ble_cgms_com_state_t cgms_com_state; /**< Current communication state. */ + nrf_ble_cgms_racp_t racp_data; /**< Structure to manage Record Access requests. */ +}; + +/** @} */ + + +/** + * @defgroup nrf_ble_cgms_functions Functions + * @{ + */ + +/**@brief Function for updating the status. + * + * @param[in] p_cgms Instance of the CGM Service. + * @param[in] p_status New status. + * + * @retval NRF_SUCCESS If the status was updated successfully. + * @return If functions from other modules return errors to this function, + * the @ref nrf_error are propagated. + */ +ret_code_t nrf_ble_cgms_update_status(nrf_ble_cgms_t * p_cgms, nrf_ble_cgm_status_t * p_status); + + +/**@brief Function for initializing the CGM Service. + * + * @param[out] p_cgms CGM Service structure. This structure must be supplied by + * the application. It is initialized by this function and will later + * be used to identify this particular service instance. + * @param[in] p_cgms_init Information needed to initialize the service. + * + * @retval NRF_SUCCESS If the service was initialized successfully. + * @retval NRF_ERROR_NULL If any of the input parameters are NULL. + * @return If functions from other modules return errors to this function, + * the @ref nrf_error are propagated. + */ +ret_code_t nrf_ble_cgms_init(nrf_ble_cgms_t * p_cgms, const nrf_ble_cgms_init_t * p_cgms_init); + + +/**@brief Function for handling the application's BLE stack events. + * + * @details Handles all events from the BLE stack that are of interest to the CGM Service. + * + * @param[in] p_ble_evt Event received from the BLE stack. + * @param[in] p_context Instance of the CGM Service. + */ +void nrf_ble_cgms_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context); + + +/**@brief Function for reporting a new glucose measurement to the CGM Service module. + * + * @details The application calls this function after having performed a new glucose measurement. + * The new measurement is recorded in the RACP database. + * + * @param[in] p_cgms Instance of the CGM Service. + * @param[in] p_rec Pointer to the glucose record (measurement plus context). + * + * @retval NRF_SUCCESS If a measurement was successfully created. + * @return If functions from other modules return errors to this function, + * the @ref nrf_error are propagated. + */ +ret_code_t nrf_ble_cgms_meas_create(nrf_ble_cgms_t * p_cgms, ble_cgms_rec_t * p_rec); + + +/**@brief Function for assigning a connection handle to a CGM Service instance. + * + * @param[in] p_cgms Instance of the CGM Service. + * @param[in] conn_handle Connection Handle to use for this instance of the CGM Service. + * + * @retval NRF_SUCCESS If the connection handle was successfully stored in the CGM Service instance. + * @retval NRF_ERROR_NULL If any of the input parameters are NULL. + */ +ret_code_t nrf_ble_cgms_conn_handle_assign(nrf_ble_cgms_t * p_cgms, uint16_t conn_handle); + + +/**@brief Function for setting the Session Run Time attribute value. + * + * @param[in] p_cgms Instance of the CGM Service. + * @param[in] run_time Run Time that will be displayed in the Session Run Time + * attribute value. + * + * @retval NRF_SUCCESS If the Session Run Time attribute value was set successfully. + * @return If functions from other modules return errors to this function, + * the @ref nrf_error are propagated. + */ +ret_code_t nrf_ble_cgms_srt_set(nrf_ble_cgms_t * p_cgms, uint16_t run_time); + +/** @} */ // End tag for Function group. + +#ifdef __cplusplus +} +#endif + +#endif // NRF_BLE_CGMS_H__ + +/** @} */ |