diff options
author | Trygve Laugstøl <trygvis@inamo.no> | 2018-08-23 17:08:59 +0200 |
---|---|---|
committer | Trygve Laugstøl <trygvis@inamo.no> | 2018-08-23 17:12:21 +0200 |
commit | 3061ecca3d0fdfb87dabbf5f63c9e06c2a30f53a (patch) | |
tree | ab49cc16ed0b853452c5c2ed2d3042416d628986 /thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns | |
download | iot-sensors-3061ecca3d0fdfb87dabbf5f63c9e06c2a30f53a.tar.gz iot-sensors-3061ecca3d0fdfb87dabbf5f63c9e06c2a30f53a.tar.bz2 iot-sensors-3061ecca3d0fdfb87dabbf5f63c9e06c2a30f53a.tar.xz iot-sensors-3061ecca3d0fdfb87dabbf5f63c9e06c2a30f53a.zip |
Diffstat (limited to 'thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns')
7 files changed, 2838 insertions, 0 deletions
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_ln_common.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_ln_common.h new file mode 100644 index 0000000..54cb080 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_ln_common.h @@ -0,0 +1,94 @@ +/** + * Copyright (c) 2015 - 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_ln_common Location and Navigation common defines + * @{ + * @ingroup ble_sdk_srv + * @brief Location and Navigation common defines + * + * @details This module contains define values common to LNS and LNCP + */ + +#ifndef BLE_LNS_COMMON_H__ +#define BLE_LNS_COMMON_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#define BLE_LNS_INVALID_ROUTE 0xFFFF +#define BLE_LNS_NO_FIX 0xFF + +#define BLE_LNS_MAX_NUM_ROUTES 10 /**< The maximum number of routes. This affects memory usage only. */ +#define BLE_LNS_MAX_ROUTE_NAME_LEN BLE_GATT_ATT_MTU_DEFAULT - 5 /**< The maximum length of length of a route name. */ +#define MAX_CTRL_POINT_RESP_PARAM_LEN BLE_LNS_MAX_ROUTE_NAME_LEN + 3 /**< Maximum length of a control point response. */ + +// Location and Navigation Service feature bits +#define BLE_LNS_FEATURE_INSTANT_SPEED_SUPPORTED (0x01 << 0) /**< Instaneous Speed Supported bit. */ +#define BLE_LNS_FEATURE_TOTAL_DISTANCE_SUPPORTED (0x01 << 1) /**< Total Distance Supported bit. */ +#define BLE_LNS_FEATURE_LOCATION_SUPPORTED (0x01 << 2) /**< Location Supported bit. */ +#define BLE_LNS_FEATURE_ELEVATION_SUPPORTED (0x01 << 3) /**< Elevation Supported bit. */ +#define BLE_LNS_FEATURE_HEADING_SUPPORTED (0x01 << 4) /**< Heading Supported bit. */ +#define BLE_LNS_FEATURE_ROLLING_TIME_SUPPORTED (0x01 << 5) /**< Rolling Time Supported bit. */ +#define BLE_LNS_FEATURE_UTC_TIME_SUPPORTED (0x01 << 6) /**< UTC Time Supported bit. */ +#define BLE_LNS_FEATURE_REMAINING_DISTANCE_SUPPORTED (0x01 << 7) /**< Remaining Distance Supported bit. */ +#define BLE_LNS_FEATURE_REMAINING_VERT_DISTANCE_SUPPORTED (0x01 << 8) /**< Remaining Vertical Distance Supported bit. */ +#define BLE_LNS_FEATURE_EST_TIME_OF_ARRIVAL_SUPPORTED (0x01 << 9) /**< Estimated Time of Arrival Supported bit. */ +#define BLE_LNS_FEATURE_NUM_SATS_IN_SOLUTION_SUPPORTED (0x01 << 10) /**< Number of Satellites in Solution Supported bit. */ +#define BLE_LNS_FEATURE_NUM_SATS_IN_VIEW_SUPPORTED (0x01 << 11) /**< Number of Satellites in View Supported bit. */ +#define BLE_LNS_FEATURE_TIME_TO_FIRST_FIX_SUPPORTED (0x01 << 12) /**< Time to First Fix Supported bit. */ +#define BLE_LNS_FEATURE_EST_HORZ_POS_ERROR_SUPPORTED (0x01 << 13) /**< Estimated Horizontal Position Error Supported bit. */ +#define BLE_LNS_FEATURE_EST_VERT_POS_ERROR_SUPPORTED (0x01 << 14) /**< Estimated Vertical Position Error Supported bit. */ +#define BLE_LNS_FEATURE_HORZ_DILUTION_OF_PRECISION_SUPPORTED (0x01 << 15) /**< Horizontal Dilution of Precision Supported bit. */ +#define BLE_LNS_FEATURE_VERT_DILUTION_OF_PRECISION_SUPPORTED (0x01 << 16) /**< Vertical Dilution of Precision Supported bit. */ +#define BLE_LNS_FEATURE_LOC_AND_SPEED_CONTENT_MASKING_SUPPORTED (0x01 << 17) /**< Location and Speed Characteristic Content Masking Supported bit. */ +#define BLE_LNS_FEATURE_FIX_RATE_SETTING_SUPPORTED (0x01 << 18) /**< Fix Rate Setting Supported bit. */ +#define BLE_LNS_FEATURE_ELEVATION_SETTING_SUPPORTED (0x01 << 19) /**< Elevation Setting Supported bit. */ +#define BLE_LNS_FEATURE_POSITION_STATUS_SUPPORTED (0x01 << 20) /**< Position Status Supported bit. */ + + +#ifdef __cplusplus +} +#endif + +#endif /* BLE_LNS_COMMON_H__ */ + +/** @} */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_ln_cp.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_ln_cp.c new file mode 100644 index 0000000..97eb3d9 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_ln_cp.c @@ -0,0 +1,821 @@ +/** + * Copyright (c) 2015 - 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_ln_cp.h" +#include "ble_ln_db.h" +#include "ble_ln_common.h" +#include "sdk_common.h" + +#define NRF_LOG_MODULE_NAME ble_ln_cp +#include "nrf_log.h" +NRF_LOG_MODULE_REGISTER(); + +// Feature Mask bits +#define FEATURE_MASK_INSTANTANEOUS_SPEED (0x01 << 0) /**< Instantaneous Speed mask bit. */ +#define FEATURE_MASK_TOTAL_DISTANCE (0x01 << 1) /**< Total Distance mask bit. */ +#define FEATURE_MASK_LOCATION (0x01 << 2) /**< Location mask bit. */ +#define FEATURE_MASK_ELEVATION (0x01 << 3) /**< Elevation mask bit. */ +#define FEATURE_MASK_HEADING (0x01 << 4) /**< Heading mask bit. */ +#define FEATURE_MASK_ROLLING_TIME (0x01 << 5) /**< Rolling Time mask bit. */ +#define FEATURE_MASK_UTC_TIME (0x01 << 6) /**< UTC Time mask bit. */ + +// Data Control point parameter type lengths. +#define INT8_LEN 1 +#define INT16_LEN 2 +#define INT24_LEN 3 +#define INT32_LEN 4 + +#define OPCODE_LENGTH 1 /**< Length of opcode inside Location and Navigation Measurement packet. */ +#define HANDLE_LENGTH 2 /**< Length of handle inside Location and Navigation Measurement packet. */ + +static ble_lncp_rsp_code_t notify_app(ble_lncp_t const * p_lncp, ble_lncp_evt_t const * p_evt) +{ + ble_lncp_rsp_code_t rsp = LNCP_RSP_SUCCESS; + + if (p_lncp->evt_handler != NULL) + { + rsp = p_lncp->evt_handler(p_lncp, p_evt); + } + + return rsp; +} + + +static void resp_send(ble_lncp_t * p_lncp) +{ + // Send indication + uint16_t hvx_len; + uint8_t hvx_data[MAX_CTRL_POINT_RESP_PARAM_LEN]; + ble_gatts_hvx_params_t hvx_params; + uint32_t err_code; + + memset(&hvx_params, 0, sizeof(hvx_params)); + + hvx_len = 3 + p_lncp->pending_rsp.rsp_param_len; + hvx_data[0] = LNCP_OP_RESPONSE_CODE; + hvx_data[1] = p_lncp->pending_rsp.op_code; + hvx_data[2] = p_lncp->pending_rsp.rsp_code; + + memcpy(&hvx_data[3], &p_lncp->pending_rsp.rsp_param[0], p_lncp->pending_rsp.rsp_param_len); + + hvx_params.handle = p_lncp->ctrlpt_handles.value_handle; + hvx_params.type = BLE_GATT_HVX_INDICATION; + hvx_params.offset = 0; + hvx_params.p_len = &hvx_len; + hvx_params.p_data = hvx_data; + + err_code = sd_ble_gatts_hvx(p_lncp->conn_handle, &hvx_params); + + // Error handling + if ((err_code == NRF_SUCCESS) && (hvx_len != p_lncp->pending_rsp.rsp_param_len + 3)) + { + err_code = NRF_ERROR_DATA_SIZE; + } + + switch (err_code) + { + case NRF_SUCCESS: + p_lncp->procedure_status = LNCP_STATE_CONFIRMATION_PENDING; + // Wait for HVC event + break; + + case NRF_ERROR_RESOURCES: + // Wait for TX_COMPLETE event to retry transmission + p_lncp->procedure_status = LNCP_STATE_INDICATION_PENDING; + break; + + default: + p_lncp->procedure_status = LNCP_STATE_INDICATION_PENDING; + // error + if (p_lncp->error_handler != NULL) + { + p_lncp->error_handler(err_code); + } + break; + } +} + + +static void on_connect(ble_lncp_t * p_lncp, ble_evt_t const * p_ble_evt) +{ + memset(&p_lncp->mask, 0, sizeof(ble_lncp_mask_t)); + p_lncp->conn_handle = p_ble_evt->evt.gap_evt.conn_handle; + p_lncp->procedure_status = LNCP_STATE_NO_PROC_IN_PROGRESS; +} + + +static void on_disconnect(ble_lncp_t * p_lncp, ble_evt_t const * p_ble_evt) +{ + UNUSED_PARAMETER(p_ble_evt); + p_lncp->conn_handle = BLE_CONN_HANDLE_INVALID; + p_lncp->procedure_status = LNCP_STATE_NO_PROC_IN_PROGRESS; +} + + +static void on_hvc_confirm(ble_lncp_t * p_lncp, ble_evt_t const * p_ble_evt) +{ + if (p_ble_evt->evt.gatts_evt.params.hvc.handle == p_lncp->ctrlpt_handles.value_handle) + { + if (p_lncp->procedure_status == LNCP_STATE_CONFIRMATION_PENDING) + { + p_lncp->procedure_status = LNCP_STATE_NO_PROC_IN_PROGRESS; + } + else + { + if (p_lncp->error_handler != NULL) + { + p_lncp->error_handler(NRF_ERROR_INVALID_STATE); + } + } + } +} + + +static void on_tx_complete(ble_lncp_t * p_lncp) +{ + if (p_lncp->procedure_status == LNCP_STATE_INDICATION_PENDING) + { + resp_send(p_lncp); + } +} + + +/**@brief Handle write events to the control point cccd. + * + * @param[in] p_lncp Location and Navigation Service structure. + * @param[in] p_evt_write Write event received from the BLE stack. + */ +static void on_lncp_cccd_write(ble_lncp_t * p_lncp, ble_gatts_evt_write_t const * p_evt_write) +{ + if (p_evt_write->len == BLE_CCCD_VALUE_LEN) + { + // CCCD written, update indications state + p_lncp->is_ctrlpt_indication_enabled = ble_srv_is_indication_enabled(p_evt_write->data); + } +} + + +/**@brief Handle write events to the navigation cccd. + * + * @param[in] p_lncp Location and Navigation Service structure. + * @param[in] p_evt_write Write event received from the BLE stack. + */ +static void on_nav_cccd_write(ble_lncp_t * p_lncp, ble_gatts_evt_write_t const * p_evt_write) +{ + if (p_evt_write->len == BLE_CCCD_VALUE_LEN) + { + // CCCD written, update notification state + p_lncp->is_nav_notification_enabled = ble_srv_is_notification_enabled(p_evt_write->data); + } +} + + +/**@brief Event handler for control point write. + * + * @param[in] p_lncp Location and Navigation Service structure. + * @param[in] p_ble_evt Event received from the BLE stack. + */ +static void on_set_cumulative_value(ble_lncp_t * p_lncp, ble_gatts_evt_write_t const * p_evt_write) +{ + if ( !(p_lncp->available_features & BLE_LNS_FEATURE_TOTAL_DISTANCE_SUPPORTED) ) + { + p_lncp->pending_rsp.rsp_code = LNCP_RSP_OP_CODE_NOT_SUPPORTED; + return; + } + + if (p_evt_write->len != OPCODE_LENGTH + INT24_LEN) + { + p_lncp->pending_rsp.rsp_code = LNCP_RSP_INVALID_PARAMETER; + return; + } + + const uint32_t total_distance = uint24_decode(&p_evt_write->data[1]); + + const ble_lncp_evt_t evt = { + .evt_type = LNCP_EVT_TOTAL_DISTANCE_SET, + .params.total_distance = total_distance + }; + p_lncp->pending_rsp.rsp_code = notify_app(p_lncp, &evt); + + if (p_lncp->pending_rsp.rsp_code == LNCP_RSP_SUCCESS) + { + p_lncp->total_distance = total_distance; + } + +} + + +/**@brief Event handler for control point write. + * + * @param[in] p_lncp Location and Navigation Service structure. + * @param[in] p_ble_evt Event received from the BLE stack. + */ +static void on_mask_loc_speed_content(ble_lncp_t * p_lncp, ble_gatts_evt_write_t const * p_evt_write) +{ + if ( !(p_lncp->available_features & BLE_LNS_FEATURE_LOC_AND_SPEED_CONTENT_MASKING_SUPPORTED) ) + { + p_lncp->pending_rsp.rsp_code = LNCP_RSP_OP_CODE_NOT_SUPPORTED; + return; + } + + if (p_evt_write->len != OPCODE_LENGTH + INT16_LEN) + { + p_lncp->pending_rsp.rsp_code = LNCP_RSP_INVALID_PARAMETER; + return; + } + + uint16_t rcvd_mask = uint16_decode(&p_evt_write->data[1]); + + if (rcvd_mask > 0x7F) + { + p_lncp->pending_rsp.rsp_code = LNCP_RSP_INVALID_PARAMETER; + return; + } + + const ble_lncp_evt_t evt = { + .evt_type = LNCP_EVT_MASK_SET, + .params.mask.flags = rcvd_mask + }; + p_lncp->pending_rsp.rsp_code = notify_app(p_lncp, &evt); + + if (p_lncp->pending_rsp.rsp_code == LNCP_RSP_SUCCESS) + { + p_lncp->mask.flags = rcvd_mask; + } +} + + +/**@brief Event handler for control point write. + * + * @param[in] p_lncp Location and Navigation Service structure. + * @param[in] p_ble_evt Event received from the BLE stack. + */ +static void on_nav_control(ble_lncp_t * p_lncp, ble_gatts_evt_write_t const * p_evt_write) +{ + if ( !(p_lncp->is_navigation_present) ) + { + p_lncp->pending_rsp.rsp_code = LNCP_RSP_OP_CODE_NOT_SUPPORTED; + return; + } + + if (p_evt_write->len != LNCP_NAV_CMD_LEN) + { + p_lncp->pending_rsp.rsp_code = LNCP_RSP_INVALID_PARAMETER; + return; + } + + /*lint --e{415} --e{416} -save suppress Warning 415: possible access out of bond */ + const uint8_t data_buf = p_evt_write->data[1]; + /*lint -restore*/ + + if (data_buf > LNCP_NAV_CMD_MAX) + { + p_lncp->pending_rsp.rsp_code = LNCP_RSP_INVALID_PARAMETER; + return; + } + + const ble_lncp_nav_cmd_t cmd = (ble_lncp_nav_cmd_t) data_buf; + + if (cmd == LNCP_CMD_NAV_START || cmd == LNCP_CMD_NAV_CONTINUE || cmd == LNCP_CMD_NAV_NEAREST) + { + p_lncp->is_navigation_running = true; + } + else if (cmd == LNCP_CMD_NAV_STOP || cmd == LNCP_CMD_NAV_PAUSE) + { + p_lncp->is_navigation_running = false; + } + + const ble_lncp_evt_t evt = { + .evt_type = LNCP_EVT_NAV_COMMAND, + .params.nav_cmd = cmd + }; + p_lncp->pending_rsp.rsp_code = notify_app(p_lncp, &evt); +} + + +/**@brief Event handler for control point write. + * + * @param[in] p_lncp Location and Navigation Service structure. + * @param[in] p_ble_evt Event received from the BLE stack. + */ +static void on_req_num_routes(ble_lncp_t * p_lncp, ble_gatts_evt_write_t const * p_evt_write) +{ + p_lncp->pending_rsp.rsp_code = LNCP_RSP_SUCCESS; + + if ( !(p_lncp->is_navigation_present) ) + { + p_lncp->pending_rsp.rsp_code = LNCP_RSP_OP_CODE_NOT_SUPPORTED; + return; + } + + if (p_evt_write->len != OPCODE_LENGTH) + { + p_lncp->pending_rsp.rsp_code = LNCP_RSP_INVALID_PARAMETER; + return; + } + + const uint8_t num_records = ble_ln_db_num_records_get(); + p_lncp->pending_rsp.rsp_param_len = uint16_encode(num_records, &p_lncp->pending_rsp.rsp_param[0]); +} + + +/**@brief Event handler for control point write. + * + * @param[in] p_lncp Location and Navigation Service structure. + * @param[in] p_ble_evt Event received from the BLE stack. + */ +static void on_req_name_of_route(ble_lncp_t * p_lncp, ble_gatts_evt_write_t const * p_evt_write) +{ + uint8_t * p_name; + uint32_t err_code; + + p_lncp->pending_rsp.rsp_code = LNCP_RSP_SUCCESS; + + if ( !(p_lncp->is_navigation_present) ) + { + p_lncp->pending_rsp.rsp_code = LNCP_RSP_OP_CODE_NOT_SUPPORTED; + return; + } + + if (p_evt_write->len != OPCODE_LENGTH + INT16_LEN) + { + p_lncp->pending_rsp.rsp_code = LNCP_RSP_INVALID_PARAMETER; + return; + } + + /*lint --e{415} --e{416} -save suppress Warning 415: possible access out of bond */ + const uint16_t route_num = uint16_decode(&p_evt_write->data[1]); + /*lint -restore*/ + + err_code = ble_ln_db_record_name_get(route_num, &p_name); + if (err_code != NRF_SUCCESS) + { + p_lncp->pending_rsp.rsp_code = LNCP_RSP_OPERATION_FAILED; + return; + } + memcpy(&p_lncp->pending_rsp.rsp_param[0], p_name, BLE_LNS_MAX_ROUTE_NAME_LEN); + + p_lncp->pending_rsp.rsp_param_len = BLE_LNS_MAX_ROUTE_NAME_LEN; +} + + +/**@brief Event handler for control point write. + * + * @param[in] p_lncp Location and Navigation Service structure. + * @param[in] p_ble_evt Event received from the BLE stack. + */ +static void on_select_route(ble_lncp_t * p_lncp, ble_gatts_evt_write_t const * p_evt_write) +{ + if ( !(p_lncp->is_navigation_present)) + { + p_lncp->pending_rsp.rsp_code = LNCP_RSP_OP_CODE_NOT_SUPPORTED; + return; + } + + if (p_evt_write->len != OPCODE_LENGTH + INT16_LEN) + { + p_lncp->pending_rsp.rsp_code = LNCP_RSP_INVALID_PARAMETER; + return; + } + + const uint16_t route_num = uint16_decode(&p_evt_write->data[1]); + const uint16_t stored_num = ble_ln_db_num_records_get(); + + if (route_num >= stored_num) + { + p_lncp->pending_rsp.rsp_code = LNCP_RSP_INVALID_PARAMETER; + return; + } + + const ble_lncp_evt_t evt = { + .evt_type = LNCP_EVT_ROUTE_SELECTED, + .params.selected_route = route_num + }; + p_lncp->pending_rsp.rsp_code = notify_app(p_lncp, &evt); + + if (p_lncp->pending_rsp.rsp_code == LNCP_RSP_SUCCESS) + { + p_lncp->selected_route = route_num; + } +} + + +/**@brief Event handler for control point write. + * + * @param[in] p_lncp Location and Navigation Service structure. + * @param[in] p_ble_evt Event received from the BLE stack. + */ +static void on_set_fix_rate(ble_lncp_t * p_lncp, ble_gatts_evt_write_t const * p_evt_write) +{ + p_lncp->pending_rsp.rsp_code = LNCP_RSP_SUCCESS; + + if ( !(p_lncp->available_features & BLE_LNS_FEATURE_FIX_RATE_SETTING_SUPPORTED) ) + { + p_lncp->pending_rsp.rsp_code = LNCP_RSP_OP_CODE_NOT_SUPPORTED; + return; + } + + if (p_evt_write->len != OPCODE_LENGTH + INT8_LEN) + { + p_lncp->pending_rsp.rsp_code = LNCP_RSP_INVALID_PARAMETER; + return; + } + + /*lint --e{415} --e{416} -save suppress Warning 415: possible access out of bond */ + const uint8_t fix_rate = p_evt_write->data[1]; + /*lint -restore*/ + + const ble_lncp_evt_t evt = { + .evt_type = LNCP_EVT_FIX_RATE_SET, + .params.fix_rate = fix_rate + }; + p_lncp->pending_rsp.rsp_code = notify_app(p_lncp, &evt); + + if (p_lncp->pending_rsp.rsp_code == LNCP_RSP_SUCCESS) + { + p_lncp->fix_rate = fix_rate; + } +} + + +/**@brief Event handler for control point write. + * + * @param[in] p_lncp Location and Navigation Service structure. + * @param[in] p_ble_evt Event received from the BLE stack. + */ +static void on_set_elevation(ble_lncp_t * p_lncp, ble_gatts_evt_write_t const * p_evt_write) +{ + p_lncp->pending_rsp.rsp_code = LNCP_RSP_SUCCESS; + + if ( !(p_lncp->available_features & BLE_LNS_FEATURE_ELEVATION_SETTING_SUPPORTED) ) + { + p_lncp->pending_rsp.rsp_code = LNCP_RSP_OP_CODE_NOT_SUPPORTED; + return; + } + + if (p_evt_write->len != OPCODE_LENGTH + INT24_LEN) + { + p_lncp->pending_rsp.rsp_code = LNCP_RSP_INVALID_PARAMETER; + return; + } + + const uint32_t elevation = uint24_decode(&p_evt_write->data[1]); + ble_lncp_evt_t evt = { + .evt_type = LNCP_EVT_ELEVATION_SET, + .params.elevation = elevation + }; + p_lncp->pending_rsp.rsp_code = notify_app(p_lncp, &evt); + + if (p_lncp->pending_rsp.rsp_code == LNCP_RSP_SUCCESS) + { + p_lncp->elevation = elevation; + } +} + + +/**@brief Handle write events to the Location and Navigation Service Control Point characteristic. + * + * @param[in] p_lncp Location and Navigation Service structure. + * @param[in] p_evt_write Write event received from the BLE stack. + */ +static void on_ctrlpt_write(ble_lncp_t * p_lncp, ble_gatts_evt_write_t const * p_evt_write) +{ + uint32_t err_code; + + p_lncp->pending_rsp.rsp_param_len = 0; + + ble_gatts_rw_authorize_reply_params_t write_authorize_reply; + memset(&write_authorize_reply, 0, sizeof(write_authorize_reply)); + + write_authorize_reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE; + + if (p_lncp->is_ctrlpt_indication_enabled) + { + if (p_lncp->procedure_status == LNCP_STATE_NO_PROC_IN_PROGRESS) + { + write_authorize_reply.params.write.update = 1; + write_authorize_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS; + + // if the op code is navigation control, its cccd must be checked + if (p_evt_write->len > 0 && p_lncp->is_navigation_present) + { + if ( p_evt_write->data[0] == LNCP_OP_NAV_CONTROL + || p_evt_write->data[0] == LNCP_OP_REQ_NAME_OF_ROUTE + || p_evt_write->data[0] == LNCP_OP_REQ_NUM_ROUTES) + { + if (!p_lncp->is_nav_notification_enabled) + { + write_authorize_reply.params.write.gatt_status = LNCP_RSP_CCCD_CONFIG_IMPROPER; + } + } + } + } + else + { + write_authorize_reply.params.write.gatt_status = LNCP_RSP_PROC_ALR_IN_PROG; + } + } + else + { + write_authorize_reply.params.write.gatt_status = LNCP_RSP_CCCD_CONFIG_IMPROPER; + } + + // reply to the write authorization + do { + err_code = sd_ble_gatts_rw_authorize_reply(p_lncp->conn_handle, &write_authorize_reply); + if (err_code != NRF_SUCCESS && err_code != NRF_ERROR_BUSY) + { + if (p_lncp->error_handler != NULL) + { + p_lncp->error_handler(err_code); + } + } + } while (err_code == NRF_ERROR_BUSY); + + + if (write_authorize_reply.params.write.gatt_status != BLE_GATT_STATUS_SUCCESS) + { + return; + } + + // Start executing the control point write action + p_lncp->procedure_status = LNCP_STATE_INDICATION_PENDING; + if (p_evt_write->len > 0) + { + p_lncp->pending_rsp.op_code = (ble_lncp_op_code_t) p_evt_write->data[0]; + switch (p_lncp->pending_rsp.op_code) + { + case LNCP_OP_SET_CUMULATIVE_VALUE: + on_set_cumulative_value(p_lncp, p_evt_write); + break; + + case LNCP_OP_MASK_LOC_SPEED_CONTENT: + on_mask_loc_speed_content(p_lncp, p_evt_write); + break; + + case LNCP_OP_NAV_CONTROL: + on_nav_control(p_lncp, p_evt_write); + break; + + case LNCP_OP_REQ_NUM_ROUTES: + on_req_num_routes(p_lncp, p_evt_write); + break; + + case LNCP_OP_REQ_NAME_OF_ROUTE: + on_req_name_of_route(p_lncp, p_evt_write); + break; + + case LNCP_OP_SELECT_ROUTE: + on_select_route(p_lncp, p_evt_write); + break; + + case LNCP_OP_SET_FIX_RATE: + on_set_fix_rate(p_lncp, p_evt_write); + break; + + case LNCP_OP_SET_ELEVATION: + on_set_elevation(p_lncp, p_evt_write); + break; + + // Unrecognized Op Code + default: + p_lncp->pending_rsp.rsp_code = LNCP_RSP_OP_CODE_NOT_SUPPORTED; + break; + } + + resp_send(p_lncp); + } + else + { + p_lncp->procedure_status = LNCP_STATE_NO_PROC_IN_PROGRESS; + } +} + + +/**@brief Write authorization request event handler. + * + * @details The write authorization request event handler is only called when writing to the control point. + * + * @param[in] p_lncp Location and Navigation Service structure. + * @param[in] p_ble_evt Event received from the BLE stack. + */ +static void on_rw_authorize_req(ble_lncp_t * p_lncp, ble_evt_t const * p_ble_evt) +{ + const ble_gatts_evt_rw_authorize_request_t * p_auth_req = + &p_ble_evt->evt.gatts_evt.params.authorize_request; + + if ( + (p_auth_req->type == BLE_GATTS_AUTHORIZE_TYPE_WRITE) + && + (p_auth_req->request.write.handle == p_lncp->ctrlpt_handles.value_handle) + && + (p_auth_req->request.write.op != BLE_GATTS_OP_PREP_WRITE_REQ) + && + (p_auth_req->request.write.op != BLE_GATTS_OP_EXEC_WRITE_REQ_NOW) + && + (p_auth_req->request.write.op != BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL) + ) + { + on_ctrlpt_write(p_lncp, &p_auth_req->request.write); + } + +} + + +/**@brief Write event handler. + * + * @param[in] p_lncp Location and Navigation Service structure. + * @param[in] p_ble_evt Event received from the BLE stack. + */ +static void on_write(ble_lncp_t * p_lncp, ble_evt_t const * p_ble_evt) +{ + const ble_gatts_evt_write_t * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write; + + if (p_evt_write->handle == p_lncp->ctrlpt_handles.cccd_handle) + { + on_lncp_cccd_write(p_lncp, p_evt_write); + } + else if (p_evt_write->handle == p_lncp->navigation_handles.cccd_handle) + { + on_nav_cccd_write(p_lncp, p_evt_write); + } +} + + +void ble_lncp_on_ble_evt(ble_lncp_t * p_lncp, ble_evt_t const * p_ble_evt) +{ + VERIFY_PARAM_NOT_NULL_VOID(p_lncp); + VERIFY_PARAM_NOT_NULL_VOID(p_ble_evt); + + switch (p_ble_evt->header.evt_id) + { + case BLE_GAP_EVT_CONNECTED: + on_connect(p_lncp, p_ble_evt); + break; + + case BLE_GAP_EVT_DISCONNECTED: + if (p_ble_evt->evt.gap_evt.conn_handle == p_lncp->conn_handle) + { + on_disconnect(p_lncp, p_ble_evt); + } + break; + + case BLE_GATTS_EVT_WRITE: + if (p_ble_evt->evt.gatts_evt.conn_handle == p_lncp->conn_handle) + { + on_write(p_lncp, p_ble_evt); + } + break; + + case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST: + if (p_ble_evt->evt.gatts_evt.conn_handle == p_lncp->conn_handle) + { + on_rw_authorize_req(p_lncp, p_ble_evt); + } + break; + + case BLE_GATTS_EVT_HVC: + if (p_ble_evt->evt.gatts_evt.conn_handle == p_lncp->conn_handle) + { + on_hvc_confirm(p_lncp, p_ble_evt); + } + break; + + case BLE_GATTS_EVT_HVN_TX_COMPLETE: + on_tx_complete(p_lncp); + break; + + default: + // no implementation + break; + } +} + + +uint32_t ble_lncp_total_distance_get(ble_lncp_t const * p_lncp) +{ + if (p_lncp == NULL) + { + return 0; + } + + return p_lncp->total_distance; +} + + +uint32_t ble_lncp_elevation_get(ble_lncp_t const * p_lncp) +{ + if (p_lncp == NULL) + { + return 0; + } + + return p_lncp->elevation; +} + + +ble_lncp_mask_t ble_lncp_mask_get(ble_lncp_t const * p_lncp) +{ + if (p_lncp == NULL) + { + const ble_lncp_mask_t empty_mask = {0}; + return empty_mask; + } + + return p_lncp->mask; +} + + +bool ble_lncp_is_navigation_running(ble_lncp_t const * p_lncp) +{ + if (p_lncp == NULL) + { + return false; + } + + return p_lncp->is_navigation_running; +} + + +ret_code_t ble_lncp_init(ble_lncp_t * p_lncp, ble_lncp_init_t const * p_lncp_init) +{ + VERIFY_PARAM_NOT_NULL(p_lncp); + VERIFY_PARAM_NOT_NULL(p_lncp_init); + + ble_add_char_params_t add_char_params; + + memset(&add_char_params, 0, sizeof(add_char_params)); + + p_lncp->service_handle = p_lncp_init->service_handle; + p_lncp->evt_handler = p_lncp_init->evt_handler; + p_lncp->error_handler = p_lncp_init->error_handler; + p_lncp->available_features = p_lncp_init->available_features; + p_lncp->is_position_quality_present = p_lncp_init->is_position_quality_present; + p_lncp->is_navigation_present = p_lncp_init->is_navigation_present; + p_lncp->total_distance = p_lncp_init->total_distance; + p_lncp->elevation = p_lncp_init->elevation; + p_lncp->navigation_handles = p_lncp_init->navigation_handles; + + p_lncp->fix_rate = BLE_LNS_NO_FIX; + p_lncp->selected_route = BLE_LNS_INVALID_ROUTE; + + p_lncp->procedure_status = LNCP_STATE_NO_PROC_IN_PROGRESS; + p_lncp->conn_handle = BLE_CONN_HANDLE_INVALID; + p_lncp->is_navigation_running = false; + p_lncp->is_nav_notification_enabled = false; + p_lncp->is_ctrlpt_indication_enabled = false; + + memset(&p_lncp->mask, 0, sizeof(ble_lncp_mask_t)); + + add_char_params.uuid = BLE_UUID_LN_CONTROL_POINT_CHAR; + add_char_params.max_len = 0; + add_char_params.char_props.indicate = true; + add_char_params.char_props.write = true; + add_char_params.is_defered_write = true; + add_char_params.is_var_len = true; + add_char_params.max_len = BLE_GATT_ATT_MTU_DEFAULT; + add_char_params.write_access = p_lncp_init->write_perm; + add_char_params.cccd_write_access = p_lncp_init->cccd_write_perm; + + NRF_LOG_DEBUG("Initialized"); + + return characteristic_add(p_lncp->service_handle, + &add_char_params, + &p_lncp->ctrlpt_handles); +} diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_ln_cp.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_ln_cp.h new file mode 100644 index 0000000..768ba23 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_ln_cp.h @@ -0,0 +1,255 @@ +/** + * Copyright (c) 2015 - 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_lncp Location and Navigation Service Control Point + * @{ + * @ingroup ble_sdk_srv + * @brief Location and Navigation Service Control Point module + * + * @details This module implements the Location and Navigation Service Control Point behavior. + */ + +#ifndef BLE_LN_CTRLPT_H__ +#define BLE_LN_CTRLPT_H__ + +#include "ble_srv_common.h" +#include "sdk_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define BLE_LNS_MAX_ROUTE_NAME_LEN BLE_GATT_ATT_MTU_DEFAULT - 5 /**< The maximum length of length of a route name. */ +#define MAX_CTRL_POINT_RESP_PARAM_LEN BLE_LNS_MAX_ROUTE_NAME_LEN + 3 /**< Maximum length of a control point response. */ + +typedef struct ble_lncp_s ble_lncp_t; + +/** @brief Location and Navigation event type. This list defines the possible events types from the Location and Navigation Service. */ +typedef enum +{ + LNCP_EVT_ELEVATION_SET, /**< Location and Navigation elevation was set. */ + LNCP_EVT_FIX_RATE_SET, /**< Fix rate was set. */ + LNCP_EVT_ROUTE_SELECTED, /**< A route was selected. */ + LNCP_EVT_NAV_COMMAND, /**< A navigation command was issued. */ + LNCP_EVT_MASK_SET, /**< Location and Speed feature mask was set. */ + LNCP_EVT_TOTAL_DISTANCE_SET /**< Location and Navigation total distance was set. */ +} ble_lncp_evt_type_t; + + +/** @brief Navigation commands. These commands can be sent to the control point and returned by an event callback. */ +typedef enum +{ + LNCP_CMD_NAV_STOP = 0x00, /**< When received, is_navigation_running in @ref ble_lns_s will be set to false. */ + LNCP_CMD_NAV_START = 0x01, /**< When received, is_navigation_running in @ref ble_lns_s will be set to true. */ + LNCP_CMD_NAV_PAUSE = 0x02, /**< When received, is_navigation_running in @ref ble_lns_s will be set to false. */ + LNCP_CMD_NAV_CONTINUE = 0x03, /**< When received, is_navigation_running in @ref ble_lns_s will be set to true. */ + LNCP_CMD_NAV_SKIP_WAYPOINT = 0x04, /**< When received, is_navigation_running in @ref ble_lns_s will not be affected. */ + LNCP_CMD_NAV_NEAREST = 0x05, /**< When received, is_navigation_running in @ref ble_lns_s will be set to true. */ +} ble_lncp_nav_cmd_t; +#define LNCP_NAV_CMD_MAX 0x05 +#define LNCP_NAV_CMD_LEN (OPCODE_LENGTH + 1) + + +#if defined(__CC_ARM) + #pragma push + #pragma anon_unions +#elif defined(__ICCARM__) + #pragma language=extended +#elif defined(__GNUC__) + /* anonymous unions are enabled by default */ +#endif + +/** @brief A mask can be used to temporarily enable and disable features of the Location and Speed characteristic.*/ +typedef union +{ + uint8_t flags; + struct + { + uint8_t instantaneous_speed :1; + uint8_t total_distance :1; + uint8_t location :1; + uint8_t elevation :1; + uint8_t heading :1; + uint8_t rolling_time :1; + uint8_t utc_time :1; + }; +} ble_lncp_mask_t; + +#if defined(__CC_ARM) + #pragma pop +#elif defined(__ICCARM__) + /* leave anonymous unions enabled */ +#elif defined(__GNUC__) + /* anonymous unions are enabled by default */ +#endif + +typedef struct +{ + ble_lncp_evt_type_t evt_type; + union + { + ble_lncp_mask_t mask; + ble_lncp_nav_cmd_t nav_cmd; + uint32_t total_distance; + uint8_t fix_rate; + uint16_t selected_route; + uint32_t elevation; + } params; +} ble_lncp_evt_t; + + +// Location and Navigation Control Point response values +typedef enum +{ + LNCP_RSP_RESERVED = 0x00, /**< Reserved for future use. */ + LNCP_RSP_SUCCESS = 0x01, /**< Success. */ + LNCP_RSP_OP_CODE_NOT_SUPPORTED = 0x02, /**< Op Code not supported. */ + LNCP_RSP_INVALID_PARAMETER = 0x03, /**< Invalid Parameter. */ + LNCP_RSP_OPERATION_FAILED = 0x04, /**< Operation Failed. */ + LNCP_RSP_PROC_ALR_IN_PROG = BLE_GATT_STATUS_ATTERR_CPS_PROC_ALR_IN_PROG, /**< Control point procedure is already in progress. */ + LNCP_RSP_CCCD_CONFIG_IMPROPER = BLE_GATT_STATUS_ATTERR_CPS_CCCD_CONFIG_ERROR /**< CCCD is improperly configured. */ +} ble_lncp_rsp_code_t; + + +typedef ble_lncp_rsp_code_t (*ble_lncp_evt_handler_t) (ble_lncp_t const * p_lncp, ble_lncp_evt_t const * p_evt); + +// Location and Navigation Control Point Op Code values +typedef enum +{ + LNCP_OP_RESERVED = 0x00, /**< Reserved for future use. */ + LNCP_OP_SET_CUMULATIVE_VALUE = 0x01, /**< Set Cumulative Value. */ + LNCP_OP_MASK_LOC_SPEED_CONTENT = 0x02, /**< Mask Location and Speed Characteristic Content. */ + LNCP_OP_NAV_CONTROL = 0x03, /**< Navigation Control. */ + LNCP_OP_REQ_NUM_ROUTES = 0x04, /**< Request Number of Routes. */ + LNCP_OP_REQ_NAME_OF_ROUTE = 0x05, /**< Request Name of Route. */ + LNCP_OP_SELECT_ROUTE = 0x06, /**< Select Route. */ + LNCP_OP_SET_FIX_RATE = 0x07, /**< Set Fix Rate. */ + LNCP_OP_SET_ELEVATION = 0x08, /**< Set Elevation. */ + LNCP_OP_RESPONSE_CODE = 0x20 /**< Response code. */ +} ble_lncp_op_code_t; + + +/** @brief Location and Navigation Control Point procedure status */ +typedef enum +{ + LNCP_STATE_NO_PROC_IN_PROGRESS, /**< No procedure in progress. */ + LNCP_STATE_INDICATION_PENDING, /**< Control Point indication is pending. */ + LNCP_STATE_CONFIRMATION_PENDING, /**< Waiting for the indication confirmation. */ +} ble_lncp_procedure_status_t; + + +/** @brief Information included in a control point write response indication. */ +typedef struct +{ + ble_lncp_op_code_t op_code; /**< Opcode of the control point write action. */ + ble_lncp_rsp_code_t rsp_code; /**< Response code of the control point write action. */ + uint8_t rsp_param_len; + uint8_t rsp_param[MAX_CTRL_POINT_RESP_PARAM_LEN]; +} ble_lncp_rsp_t; + + +typedef struct +{ + uint16_t service_handle; + ble_lncp_evt_handler_t evt_handler; + ble_srv_error_handler_t error_handler; + + uint32_t available_features; /**< Value of the LN feature. */ + bool is_position_quality_present; /**< If set to true, the position quality characteristic will be added. Else not. */ + bool is_control_point_present; /**< If set to true, the control point characteristic will be added. Else not. */ + bool is_navigation_present; /**< If set to true, the navigation characteristic will be added. Else not. */ + ble_gatts_char_handles_t navigation_handles; + + uint32_t total_distance; + uint32_t elevation; + + security_req_t write_perm; + security_req_t cccd_write_perm; +} ble_lncp_init_t; + + +struct ble_lncp_s +{ + uint16_t conn_handle; + uint16_t service_handle; + ble_gatts_char_handles_t ctrlpt_handles; + ble_gatts_char_handles_t navigation_handles; + ble_lncp_evt_handler_t evt_handler; + ble_srv_error_handler_t error_handler; + ble_lncp_procedure_status_t procedure_status; + ble_lncp_rsp_t pending_rsp; + + ble_lncp_mask_t mask; + uint32_t total_distance; + uint32_t elevation; + uint8_t fix_rate; + uint16_t selected_route; + uint32_t available_features; /**< Value of the LN feature. */ + bool is_position_quality_present; /**< If set to true, the position quality characteristic will be added. Else not. */ + bool is_control_point_present; /**< If set to true, the control point characteristic will be added. Else not. */ + bool is_navigation_present; /**< If set to true, the navigation characteristic will be added. Else not. */ + bool is_navigation_running; /**< This variable can be set using the control point. Must be true to be able to send navigation updates. */ + + bool is_ctrlpt_indication_enabled; /**< True if indication is enabled on the Control Point characteristic. */ + bool is_nav_notification_enabled; /**< True if notification is enabled on the Navigation characteristic. */ +}; + + +void ble_lncp_on_ble_evt(ble_lncp_t * p_lncp, ble_evt_t const * p_ble_evt); + +uint32_t ble_lncp_total_distance_get(ble_lncp_t const * p_lncp); + +uint32_t ble_lncp_elevation_get(ble_lncp_t const * p_lncp); + +ble_lncp_mask_t ble_lncp_mask_get(ble_lncp_t const * p_lncp); + +bool ble_lncp_is_navigation_running(ble_lncp_t const * p_lncp); + +ret_code_t ble_lncp_init(ble_lncp_t * p_lncp, ble_lncp_init_t const * p_lncp_init); + + +#ifdef __cplusplus +} +#endif + +#endif //BLE_LN_CTRLPT_H__ + +/** @} */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_ln_db.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_ln_db.c new file mode 100644 index 0000000..d1ef5f6 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_ln_db.c @@ -0,0 +1,151 @@ +/** + * Copyright (c) 2015 - 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_ln_db.h" +#include "ble_ln_common.h" + +typedef struct +{ + bool in_use_flag; + ble_lns_route_t record; +} database_entry_t; + +static database_entry_t m_database[BLE_LNS_MAX_NUM_ROUTES]; +static uint8_t m_database_crossref[BLE_LNS_MAX_NUM_ROUTES]; +static uint16_t m_num_records; + +void ble_ln_db_init(void) +{ + int i; + + for (i = 0; i < BLE_LNS_MAX_NUM_ROUTES; i++) + { + m_database[i].in_use_flag = false; + m_database_crossref[i] = 0xFF; + } + + m_num_records = 0; +} + + +uint16_t ble_ln_db_num_records_get(void) +{ + return m_num_records; +} + + +ret_code_t ble_ln_db_record_get(uint8_t rec_ndx, ble_lns_route_t * p_rec) +{ + if (rec_ndx >= m_num_records) + { + return NRF_ERROR_INVALID_PARAM; + } + + // copy record to the specified memory + *p_rec = m_database[m_database_crossref[rec_ndx]].record; + + return NRF_SUCCESS; +} + + +ret_code_t ble_ln_db_record_name_get(uint8_t rec_ndx, uint8_t ** p_buf) +{ + if (rec_ndx >= m_num_records) + { + return NRF_ERROR_INVALID_PARAM; + } + + // copy record to the specified memory + *p_buf = m_database[m_database_crossref[rec_ndx]].record.route_name; + + return NRF_SUCCESS; +} + + +ret_code_t ble_ln_db_record_add(ble_lns_route_t * p_rec) +{ + int i; + + if (m_num_records == BLE_LNS_MAX_NUM_ROUTES) + { + return NRF_ERROR_NO_MEM; + } + + // find next available database entry + for (i = 0; i < BLE_LNS_MAX_NUM_ROUTES; i++) + { + if (!m_database[i].in_use_flag) + { + m_database[i].in_use_flag = true; + m_database[i].record = *p_rec; + m_database[i].record.route_id = i; + m_database_crossref[m_num_records] = i; + p_rec->route_id = i; + m_num_records++; + return NRF_SUCCESS; + } + } + + return NRF_ERROR_NO_MEM; +} + + +ret_code_t ble_ln_db_record_delete(uint8_t rec_ndx) +{ + int i; + + if (rec_ndx >= m_num_records) + { + return NRF_ERROR_NOT_FOUND; + } + + // free entry + m_database[m_database_crossref[rec_ndx]].in_use_flag = false; + + // decrease number of records + m_num_records--; + + // remove cross reference index + for (i = rec_ndx; 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_ble_lns/ble_ln_db.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_ln_db.h new file mode 100644 index 0000000..649c19f --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_ln_db.h @@ -0,0 +1,122 @@ +/** + * Copyright (c) 2015 - 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_ln_db Location and Navigation database + * @{ + * @ingroup ble_sdk_srv + * @brief Location and Navigation route database + */ + +#ifndef BLE_LN_DB__ +#define BLE_LN_DB__ + +#include "ble_lns.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/**@brief Function for initializing the route database. + * + * @details This call initializes the database holding route records. + * + * @return NRF_SUCCESS on success. + */ +void ble_ln_db_init(void); + +/**@brief Function for getting the number of records in the database. + * + * @details This call returns the number of records in the database. + * + * @return Number of records in the database. + */ +uint16_t ble_ln_db_num_records_get(void); + +/**@brief Function for getting a record from the database. + * + * @details This call returns a specified record from the database. + * + * @param[in] record_num Index of the record to retrieve. + * @param[out] p_rec Pointer to record structure where retrieved record is copied to. + * + * @return NRF_SUCCESS on success. + */ +ret_code_t ble_ln_db_record_get(uint8_t record_num, ble_lns_route_t * p_rec); + +/**@brief Function for getting a record name from the database. + * + * @details This call returns a specified record name from the database. + * + * @param[in] rec_ndx Index of the record to retrieve. + * @param[out] p_buf Pointer to array where retrieved record name is copied to. + * + * @return NRF_SUCCESS on success. + */ +ret_code_t ble_ln_db_record_name_get(uint8_t rec_ndx, uint8_t ** p_buf); + +/**@brief Function for adding a record at the end of the database. + * + * @details This call adds a record as the last record in the database. + * + * @param[in] p_rec Pointer to record to add to database. + * + * @return NRF_SUCCESS on success. + */ +ret_code_t ble_ln_db_record_add(ble_lns_route_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 record to delete. + * + * @return NRF_SUCCESS on success. + */ +ret_code_t ble_ln_db_record_delete(uint8_t record_num); + + +#ifdef __cplusplus +} +#endif + +#endif // BLE_LN_DB_H__ + +/** @} */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_lns.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_lns.c new file mode 100644 index 0000000..4129d1d --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_lns.c @@ -0,0 +1,1014 @@ +/** + * Copyright (c) 2015 - 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_lns.h" +#include "ble_ln_db.h" +#include "ble_ln_common.h" +#include "sdk_common.h" + +#define NRF_LOG_MODULE_NAME ble_lns +#include "nrf_log.h" +NRF_LOG_MODULE_REGISTER(); + +// Location and Speed flag bits +#define LOC_SPEED_FLAG_INSTANT_SPEED_PRESENT (0x01 << 0) /**< Instantaneous Speed Present bit. */ +#define LOC_SPEED_FLAG_TOTAL_DISTANCE_PRESENT (0x01 << 1) /**< Total Distance Present bit. */ +#define LOC_SPEED_FLAG_LOCATION_PRESENT (0x01 << 2) /**< Location Present bit. */ +#define LOC_SPEED_FLAG_ELEVATION_PRESENT (0x01 << 3) /**< Elevation Present bit. */ +#define LOC_SPEED_FLAG_HEADING_PRESENT (0x01 << 4) /**< Heading Present bit. */ +#define LOC_SPEED_FLAG_ROLLING_TIME_PRESENT (0x01 << 5) /**< Rolling Time Present bit. */ +#define LOC_SPEED_FLAG_UTC_TIME_PRESENT (0x01 << 6) /**< UTC Time Present bit. */ +#define LOC_SPEED_FLAG_POSITION_STATUS (0x03 << 7) /**< Position Status bits(2). */ +#define LOC_SPEED_FLAG_SPEED_AND_DIST_FORMAT (0x01 << 9) /**< Speed and Distance Format. */ +#define LOC_SPEED_FLAG_ELEVATION_SOURCE (0x03 << 10) /**< Elevation Source bits(2). */ +#define LOC_SPEED_FLAG_HEADING_SOURCE (0x01 << 12) /**< Heading Source. */ + +// Position Quality flag bits +#define POS_QUAL_FLAG_NUM_SATS_IN_SOLUTION_PRESENT (0x01 << 0) /**< Number of Satellites in Solution Present bit. */ +#define POS_QUAL_FLAG_NUM_SATS_IN_VIEW_PRESENT (0x01 << 1) /**< Number of Satellites in View Present bit. */ +#define POS_QUAL_FLAG_TIME_TO_FIRST_FIX_PRESESNT (0x01 << 2) /**< Time to First Fix Present bit. */ +#define POS_QUAL_FLAG_EHPE_PRESENT (0x01 << 3) /**< EHPE Present bit. */ +#define POS_QUAL_FLAG_EVPE_PRESENT (0x01 << 4) /**< EVPE Present bit. */ +#define POS_QUAL_FLAG_HDOP_PRESENT (0x01 << 5) /**< HDOP Present bit. */ +#define POS_QUAL_FLAG_VDOP_PRESENT (0x01 << 6) /**< VDOP Present bit. */ +#define POS_QUAL_FLAG_POSITION_STATUS (0x03 << 7) /**< Position Status bits(2). */ + +// Navigation flag bits +#define NAV_FLAG_REMAINING_DIST_PRESENT (0x01 << 0) /**< Remaining Distance Present bit. */ +#define NAV_FLAG_REAMINGING_VERT_DIST_PRESESNT (0x01 << 1) /**< Remaining Vertical Distance Present bit . */ +#define NAV_FLAG_ETA_PRESENT (0x01 << 2) /**< Estimated Time of Arrival Present bit. */ +#define NAV_FLAG_POSITION_STATUS (0x03 << 3) /**< Position Status bits(2). */ +#define NAV_FLAG_HEADING_SOURCE (0x01 << 5) /**< Heading Source bit. */ +#define NAV_FLAG_NAVIGATION_INDICATOR_TYPE (0x01 << 6) /**< Navigation Indicator Type bit. */ +#define NAV_FLAG_WAYPOINT_REACHED (0x01 << 7) /**< Waypoint Reached bit. */ +#define NAV_FLAG_DESTINATION_REACHED (0x01 << 8) /**< Destination Reached bit. */ + +#define BLE_LNS_NAV_MAX_LEN 19 /**< The length of a navigation notification when all features are enabled. See @ref ble_lns_navigation_t to see what this represents, or check https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.navigation.xml. */ + + +static void notification_buffer_process(ble_lns_t * p_lns) +{ + notification_t * p_notification; + + // See if a notification is pending + if (p_lns->pending_loc_speed_notifications[0].is_pending == true) + { + p_notification = &p_lns->pending_loc_speed_notifications[0]; + } + else if (p_lns->pending_loc_speed_notifications[1].is_pending == true) + { + p_notification = &p_lns->pending_loc_speed_notifications[1]; + } + else if (p_lns->pending_navigation_notification.is_pending == true) + { + p_notification = &p_lns->pending_navigation_notification; + } + else + { + p_notification = NULL; + } + + // send the notification if necessary + if (p_notification != NULL) + { + uint32_t err_code; + ble_gatts_hvx_params_t hvx_params; + + memset(&hvx_params, 0, sizeof(hvx_params)); + + uint16_t hvx_len = p_notification->len; + + hvx_params.handle = p_notification->handle; + hvx_params.type = BLE_GATT_HVX_NOTIFICATION; + hvx_params.offset = 0; + hvx_params.p_len = &hvx_len; + hvx_params.p_data = &p_notification->data[0]; + + err_code = sd_ble_gatts_hvx(p_lns->conn_handle, &hvx_params); + + if ((err_code == NRF_SUCCESS) && (hvx_len == p_notification->len)) + { + p_notification->is_pending = false; + } + } +} + + +/**@brief Connect event handler. + * + * @param[in] p_lns Location and Navigation Service structure. + * @param[in] p_ble_evt Event received from the BLE stack. + */ +static void on_connect(ble_lns_t * p_lns, ble_evt_t const * p_ble_evt) +{ + p_lns->conn_handle = p_ble_evt->evt.gap_evt.conn_handle; + + // clear pending notifications + p_lns->pending_loc_speed_notifications[0].is_pending = false; + p_lns->pending_loc_speed_notifications[1].is_pending = false; + p_lns->pending_navigation_notification.is_pending = false; +} + + +/**@brief Disconnect event handler. + * + * @param[in] p_lns Location and Navigation Service structure. + * @param[in] p_ble_evt Event received from the BLE stack. + */ +static void on_disconnect(ble_lns_t * p_lns, ble_evt_t const * p_ble_evt) +{ + if (p_lns->conn_handle != p_ble_evt->evt.gatts_evt.conn_handle) + { + return; + } + + p_lns->conn_handle = BLE_CONN_HANDLE_INVALID; +} + + +/**@brief Handle write events to the control point cccd. + * + * @param[in] p_lncp Location and Navigation Service structure. + * @param[in] p_evt_write Write event received from the BLE stack. + */ +static void on_ctrl_pt_cccd_write(ble_lns_t * p_lns, ble_gatts_evt_write_t const * p_evt_write) +{ + if (p_evt_write->len == BLE_CCCD_VALUE_LEN) + { + if (p_lns->evt_handler != NULL) + { + ble_lns_evt_t evt; + + if (ble_srv_is_indication_enabled(p_evt_write->data)) + { + evt.evt_type = BLE_LNS_CTRLPT_EVT_INDICATION_ENABLED; + } + else + { + evt.evt_type = BLE_LNS_CTRLPT_EVT_INDICATION_DISABLED; + } + + p_lns->evt_handler(p_lns, &evt); + } + } +} + + +/**@brief Handle write events to the Location and Speed cccd. + * + * @param[in] p_lns Location and Navigation Service structure. + * @param[in] p_evt_write Write event received from the BLE stack. + */ +static void on_loc_speed_cccd_write(ble_lns_t * p_lns, + ble_gatts_evt_write_t const * p_evt_write) +{ + if (p_evt_write->len == BLE_CCCD_VALUE_LEN) + { + // CCCD written, update notification state + p_lns->is_loc_speed_notification_enabled = ble_srv_is_notification_enabled(p_evt_write->data); + if (p_lns->evt_handler != NULL) + { + ble_lns_evt_t evt; + + if (p_lns->is_loc_speed_notification_enabled) + { + evt.evt_type = BLE_LNS_LOC_SPEED_EVT_NOTIFICATION_ENABLED; + } + else + { + evt.evt_type = BLE_LNS_LOC_SPEED_EVT_NOTIFICATION_DISABLED; + } + + p_lns->evt_handler(p_lns, &evt); + } + } +} + + +/**@brief Handle write events to the navigation cccd. + * + * @param[in] p_lns Location and Navigation Service structure. + * @param[in] p_evt_write Write event received from the BLE stack. + */ +static void on_nav_cccd_write(ble_lns_t * p_lns, + ble_gatts_evt_write_t const * p_evt_write) +{ + if (p_evt_write->len == BLE_CCCD_VALUE_LEN) + { + p_lns->is_nav_notification_enabled = ble_srv_is_notification_enabled(p_evt_write->data); + if (p_lns->evt_handler != NULL) + { + ble_lns_evt_t evt; + + if (p_lns->is_nav_notification_enabled) + { + evt.evt_type = BLE_LNS_NAVIGATION_EVT_NOTIFICATION_ENABLED; + } + else + { + evt.evt_type = BLE_LNS_NAVIGATION_EVT_NOTIFICATION_DISABLED; + } + + p_lns->evt_handler(p_lns, &evt); + } + } +} + + +/**@brief Write event handler. + * + * @param[in] p_lns Location and Navigation Service structure. + * @param[in] p_ble_evt Event received from the BLE stack. + */ +static void on_write(ble_lns_t * p_lns, ble_evt_t const * p_ble_evt) +{ + if (p_lns->conn_handle != p_ble_evt->evt.gatts_evt.conn_handle) + { + return; + } + + ble_gatts_evt_write_t const * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write; + + if (p_evt_write->handle == p_lns->ctrlpt_handles.cccd_handle) + { + on_ctrl_pt_cccd_write(p_lns, p_evt_write); + } + else if (p_evt_write->handle == p_lns->loc_speed_handles.cccd_handle) + { + on_loc_speed_cccd_write(p_lns, p_evt_write); + } + else if (p_evt_write->handle == p_lns->navigation_handles.cccd_handle) + { + on_nav_cccd_write(p_lns, p_evt_write); + } +} + + +/**@brief Tx Complete event handler. This is used to retry sending a packet. + * + * @details Tx Complete event handler. + * Handles WRITE events from the BLE stack and if an indication was pending try sending it + * again. + * + * @param[in] p_lns Location navigation structure. + */ +static void on_tx_complete(ble_lns_t * p_lns) +{ + notification_buffer_process(p_lns); +} + + +/**@brief Encode position quality. + * + * @param[in] p_lns Location and Navigation Service structure. + * @param[in] p_pos_qual Position quality data to be encoded. + * @param[out] p_encoded_buffer Buffer where the encoded data will be written. + * + * @return Size of encoded data. + */ +static uint8_t pos_qual_encode(ble_lns_t const * p_lns, + ble_lns_pos_quality_t const * p_pos_qual, + uint8_t * p_encoded_buffer) +{ + uint16_t flags = 0; + uint8_t len = 2; // flags are added at last + + flags |= ((uint16_t)p_pos_qual->position_status << 7) & POS_QUAL_FLAG_POSITION_STATUS; + + if (p_pos_qual->number_of_satellites_in_solution_present) + { + flags |= POS_QUAL_FLAG_NUM_SATS_IN_SOLUTION_PRESENT; + p_encoded_buffer[len++] = p_pos_qual->number_of_satellites_in_solution; + } + + if (p_pos_qual->number_of_satellites_in_view_present) + { + flags |= POS_QUAL_FLAG_NUM_SATS_IN_VIEW_PRESENT; + p_encoded_buffer[len++] = p_pos_qual->number_of_satellites_in_view; + } + + if (p_pos_qual->time_to_first_fix_present) + { + flags |= POS_QUAL_FLAG_TIME_TO_FIRST_FIX_PRESESNT; + len += uint16_encode(p_pos_qual->time_to_first_fix, &p_encoded_buffer[len]); + } + + if (p_pos_qual->ehpe_present) + { + flags |= POS_QUAL_FLAG_EHPE_PRESENT; + len += uint32_encode(p_pos_qual->ehpe, &p_encoded_buffer[len]); + } + + if (p_pos_qual->evpe_present) + { + flags |= POS_QUAL_FLAG_EVPE_PRESENT; + len += uint32_encode(p_pos_qual->evpe, &p_encoded_buffer[len]); + } + + if (p_pos_qual->hdop_present) + { + flags |= POS_QUAL_FLAG_HDOP_PRESENT; + p_encoded_buffer[len++] = p_pos_qual->hdop; + } + + if (p_pos_qual->vdop_present) + { + flags |= POS_QUAL_FLAG_VDOP_PRESENT; + p_encoded_buffer[len++] = p_pos_qual->vdop; + } + + // Flags field + uint16_encode(flags, &p_encoded_buffer[0]); //lint !e534 "Ignoring return value of function" + + return len; +} + + +/**@brief Encode Location and Speed data packet 1 + * + * @param[in] p_lns Location and Navigation Service structure. + * @param[in] p_loc_speed Location and Speed data to be encoded. + * @param[out] p_encoded_buffer Pointer to buffer buffer where encoded data will be written. + * + * @return Size of encoded data. + * + */ +static uint8_t loc_speed_encode_packet1(ble_lns_t const * p_lns, + ble_lns_loc_speed_t const * p_loc_speed, + uint8_t * p_encoded_buffer) +{ + uint16_t flags = 0; + uint8_t len = 2; + + ble_lncp_mask_t const mask = ble_lncp_mask_get(&p_lns->ctrl_pt); + + // Instantaneous Speed + if (p_lns->available_features & BLE_LNS_FEATURE_INSTANT_SPEED_SUPPORTED) + { + if (p_loc_speed->instant_speed_present && !mask.instantaneous_speed) + { + flags |= LOC_SPEED_FLAG_INSTANT_SPEED_PRESENT; + flags |= ((uint16_t)p_loc_speed->data_format<<9) & LOC_SPEED_FLAG_SPEED_AND_DIST_FORMAT; + len += uint16_encode(p_loc_speed->instant_speed, &p_encoded_buffer[len]); + } + } + + // Total Distance + if (p_lns->available_features & BLE_LNS_FEATURE_TOTAL_DISTANCE_SUPPORTED) + { + if (p_loc_speed->total_distance_present && !mask.total_distance) + { + uint32_t const total_distance = ble_lncp_total_distance_get(&p_lns->ctrl_pt); + flags |= LOC_SPEED_FLAG_TOTAL_DISTANCE_PRESENT; + len += uint24_encode(total_distance, &p_encoded_buffer[len]); + } + } + + // Location + if (p_lns->available_features & BLE_LNS_FEATURE_LOCATION_SUPPORTED) + { + if (p_loc_speed->location_present && !mask.location) + { + flags |= LOC_SPEED_FLAG_LOCATION_PRESENT; + flags |= ((uint16_t)p_loc_speed->position_status <<7) & LOC_SPEED_FLAG_POSITION_STATUS; + len += uint32_encode(p_loc_speed->latitude, &p_encoded_buffer[len]); + len += uint32_encode(p_loc_speed->longitude, &p_encoded_buffer[len]); + } + } + + // Flags field + uint16_encode(flags, &p_encoded_buffer[0]); //lint !e534 "Ignoring return value of function" + + return len; +} + + +/**@brief Encode Location and Speed data packet 2 + * + * @param[in] p_lns Location and Navigation Service structure. + * @param[in] p_loc_speed Location and Speed data to be encoded. + * @param[out] p_encoded_buffer Pointer to buffer buffer where encoded data will be written. + * + * @return Size of encoded data. + * + */ +static uint8_t loc_speed_encode_packet2(ble_lns_t const * p_lns, + ble_lns_loc_speed_t const * p_loc_speed, + uint8_t * p_encoded_buffer) +{ + uint16_t flags = 0; + uint8_t len = 2; + + ble_lncp_mask_t const mask = ble_lncp_mask_get(&p_lns->ctrl_pt); + + // Elevation + if (p_lns->available_features & BLE_LNS_FEATURE_ELEVATION_SUPPORTED) + { + if (p_loc_speed->elevation_present && !mask.elevation) + { + uint32_t const elevation = ble_lncp_elevation_get(&p_lns->ctrl_pt); + + flags |= LOC_SPEED_FLAG_ELEVATION_PRESENT; + flags |= ((uint16_t) p_loc_speed->elevation_source << 10) & LOC_SPEED_FLAG_ELEVATION_SOURCE; + len += uint24_encode(elevation, &p_encoded_buffer[len]); + } + } + + // Heading + if (p_lns->available_features & BLE_LNS_FEATURE_HEADING_SUPPORTED) + { + if (p_loc_speed->heading_present && !mask.heading) + { + flags |= LOC_SPEED_FLAG_HEADING_PRESENT; + flags |= ((uint16_t) p_loc_speed->heading_source << 12) & LOC_SPEED_FLAG_HEADING_SOURCE; + len += uint16_encode(p_loc_speed->heading, &p_encoded_buffer[len]); + } + } + + // Rolling Time + if (p_lns->available_features & BLE_LNS_FEATURE_ROLLING_TIME_SUPPORTED) + { + if ((p_loc_speed->rolling_time_present && !mask.rolling_time)) + { + flags |= LOC_SPEED_FLAG_ROLLING_TIME_PRESENT; + p_encoded_buffer[len++] = p_loc_speed->rolling_time; + } + } + + // UTC Time + if (p_lns->available_features & BLE_LNS_FEATURE_UTC_TIME_SUPPORTED) + { + if ((p_loc_speed->utc_time_time_present && !mask.utc_time)) + { + flags |= LOC_SPEED_FLAG_UTC_TIME_PRESENT; + len += ble_date_time_encode(&p_loc_speed->utc_time, &p_encoded_buffer[len]); + } + } + // Flags field + uint16_encode(flags, &p_encoded_buffer[0]); //lint !e534 "Ignoring return value of function" + + return len; +} + + +/**@brief Encode Navigation data. + * + * @param[in] p_lns Location and Navigation Service structure. + * @param[in] p_navigation Navigation data to be encoded. + * @param[out] p_encoded_buffer Buffer where the encoded data will be written. + * + * @return Size of encoded data. + */ +static uint8_t navigation_encode(ble_lns_t const * p_lns, + ble_lns_navigation_t const * p_navigation, + uint8_t * p_encoded_buffer) +{ + uint16_t flags = 0; + uint8_t len = 2; + + // Bearing + len += uint16_encode(p_navigation->bearing, &p_encoded_buffer[len]); + + // Heading + len += uint16_encode(p_navigation->heading, &p_encoded_buffer[len]); + + // Remaining Distance + if (p_lns->available_features & BLE_LNS_FEATURE_REMAINING_DISTANCE_SUPPORTED) + { + if (p_navigation->remaining_dist_present) + { + flags |= NAV_FLAG_REMAINING_DIST_PRESENT; + p_encoded_buffer[len++] = ((p_navigation->remaining_distance >> 0) & 0xFF); + p_encoded_buffer[len++] = ((p_navigation->remaining_distance >> 8) & 0xFF); + p_encoded_buffer[len++] = ((p_navigation->remaining_distance >> 16) & 0xFF); + } + } + + // Remaining Vertical Distance + if (p_lns->available_features & BLE_LNS_FEATURE_REMAINING_VERT_DISTANCE_SUPPORTED) + { + if (p_navigation->remaining_vert_dist_present) + { + flags |= NAV_FLAG_REAMINGING_VERT_DIST_PRESESNT; + p_encoded_buffer[len++] = ((p_navigation->remaining_vert_distance >> 0) & 0xFF); + p_encoded_buffer[len++] = ((p_navigation->remaining_vert_distance >> 8) & 0xFF); + p_encoded_buffer[len++] = ((p_navigation->remaining_vert_distance >> 16) & 0xFF); + } + } + + // Estimated Time of Arrival + if (p_lns->available_features & BLE_LNS_FEATURE_EST_TIME_OF_ARRIVAL_SUPPORTED) + { + if (p_navigation->eta_present) + { + flags |= NAV_FLAG_ETA_PRESENT; + len += ble_date_time_encode(&p_navigation->eta, &p_encoded_buffer[len]); + } + } + + flags |= ((uint16_t)p_navigation->position_status <<3) & NAV_FLAG_POSITION_STATUS; + flags |= ((uint16_t)p_navigation->heading_source <<5) & NAV_FLAG_HEADING_SOURCE; + flags |= ((uint16_t)p_navigation->navigation_indicator_type<<6)& NAV_FLAG_NAVIGATION_INDICATOR_TYPE; + flags |= ((uint16_t)p_navigation->waypoint_reached <<7)& NAV_FLAG_WAYPOINT_REACHED; + flags |= ((uint16_t)p_navigation->destination_reached <<8)& NAV_FLAG_DESTINATION_REACHED; + + // Flags field + uint16_encode(flags, &p_encoded_buffer[0]); //lint !e534 "Ignoring return value of function" + + return len; +} + + +/**@brief Add Location and Navigation Feature characteristic. + * + * @param[in] p_lns Location and Navigation Service structure. + * @param[in] p_lns_init Information needed to initialize the service. + * + * @return NRF_SUCCESS on success, otherwise an error code. + */ +static ret_code_t loc_and_nav_feature_char_add(ble_lns_t * p_lns, ble_lns_init_t const * p_lns_init) +{ + uint8_t init_value_encoded[sizeof(uint32_t)]; + uint8_t len; + ble_add_char_params_t add_char_params; + + len = uint32_encode(p_lns_init->available_features, init_value_encoded); + + memset(&add_char_params, 0, sizeof(add_char_params)); + + add_char_params.uuid = BLE_UUID_LN_FEATURE_CHAR; + add_char_params.max_len = len; + add_char_params.init_len = len; + add_char_params.p_init_value = &init_value_encoded[0]; + add_char_params.char_props.read = true; + add_char_params.read_access = p_lns_init->loc_nav_feature_security_req_read_perm; + + return characteristic_add(p_lns->service_handle, + &add_char_params, + &p_lns->feature_handles); +} + + +/**@brief Add Location and Speed characteristic. + * + * @param[in] p_lns Location and Navigation Service structure. + * @param[in] p_lns_init Information needed to initialize the service. + * + * @return NRF_SUCCESS on success, otherwise an error code. + */ +static ret_code_t loc_speed_char_add(ble_lns_t * p_lns, ble_lns_init_t const * p_lns_init) +{ + uint8_t encoded_initial_loc_speed1[BLE_GATT_ATT_MTU_DEFAULT]; + uint8_t len; + ble_add_char_params_t add_char_params; + + len = loc_speed_encode_packet1(p_lns, p_lns_init->p_location_speed, &encoded_initial_loc_speed1[0]); + + memset(&add_char_params, 0, sizeof(add_char_params)); + + add_char_params.uuid = BLE_UUID_LN_LOCATION_AND_SPEED_CHAR; + add_char_params.max_len = BLE_GATT_ATT_MTU_DEFAULT ; + add_char_params.init_len = len; + add_char_params.p_init_value = &encoded_initial_loc_speed1[0]; + add_char_params.is_var_len = true; + add_char_params.char_props.notify = true; + add_char_params.cccd_write_access = p_lns_init->loc_speed_security_req_cccd_write_perm; + + return characteristic_add(p_lns->service_handle, + &add_char_params, + &p_lns->loc_speed_handles); +} + + +/**@brief Add Location and Navigation position quality characteristic. + * + * @param[in] p_lns Location and Navigation Service structure. + * @param[in] p_lns_init Information needed to initialize the service. + * + * @return NRF_SUCCESS on success, otherwise an error code. + */ +static ret_code_t pos_quality_char_add(ble_lns_t * p_lns, ble_lns_init_t const * p_lns_init) +{ + uint8_t len; + uint8_t init_value_encoded[BLE_GATT_ATT_MTU_DEFAULT]; + ble_add_char_params_t add_char_params; + + len = pos_qual_encode(p_lns, p_lns_init->p_position_quality, init_value_encoded); + + memset(&add_char_params, 0, sizeof(add_char_params)); + + add_char_params.uuid = BLE_UUID_LN_POSITION_QUALITY_CHAR; + add_char_params.max_len = BLE_GATT_ATT_MTU_DEFAULT ; + add_char_params.init_len = len; + add_char_params.p_init_value = init_value_encoded; + add_char_params.char_props.read = true; + add_char_params.read_access = p_lns_init->position_quality_security_req_read_perm; + + return characteristic_add(p_lns->service_handle, + &add_char_params, + &p_lns->pos_qual_handles); +} + + +/**@brief Add Navigation characteristic. + * + * @param[in] p_lns Location and Navigation Service structure. + * @param[in] p_lns_init Information needed to initialize the service. + * + * @return NRF_SUCCESS on success, otherwise an error code. + */ +static ret_code_t navigation_char_add(ble_lns_t * p_lns, ble_lns_init_t const * p_lns_init) +{ + ble_add_char_params_t add_char_params; + + memset(&add_char_params, 0, sizeof(add_char_params)); + + add_char_params.uuid = BLE_UUID_LN_NAVIGATION_CHAR; + add_char_params.max_len = BLE_LNS_NAV_MAX_LEN; + add_char_params.init_len = 0; + add_char_params.p_init_value = NULL; + add_char_params.char_props.notify = true; + add_char_params.cccd_write_access = p_lns_init->navigation_security_req_cccd_write_perm; + + return characteristic_add(p_lns->service_handle, + &add_char_params, + &p_lns->navigation_handles); +} + + +/** @brief Check if there is a mismatch in initialization parameters. + * + * @details It is possible to give an input which has an internal mismatch. Such a mismatch can arise in two different ways. + * One possibility is a mismatch between the characteristic present indicators and the available features specified. + * The other mismatch arises when no pointer to the characteristic data structure is specified. + * + * @param[in] p_lns_init The init structure which will be checked + * + * @return false if there is no mismatch. true if there is a mismatch + */ +static bool init_param_mismatch_present(ble_lns_init_t const * p_lns_init) +{ + if (p_lns_init->is_position_quality_present == false) + { + if (p_lns_init->available_features & + (BLE_LNS_FEATURE_NUM_SATS_IN_SOLUTION_SUPPORTED | + BLE_LNS_FEATURE_NUM_SATS_IN_VIEW_SUPPORTED | + BLE_LNS_FEATURE_TIME_TO_FIRST_FIX_SUPPORTED | + BLE_LNS_FEATURE_EST_HORZ_POS_ERROR_SUPPORTED | + BLE_LNS_FEATURE_EST_VERT_POS_ERROR_SUPPORTED | + BLE_LNS_FEATURE_HORZ_DILUTION_OF_PRECISION_SUPPORTED | + BLE_LNS_FEATURE_VERT_DILUTION_OF_PRECISION_SUPPORTED) + ) + { + return true; + } + if (p_lns_init->p_position_quality != NULL) + { + return true; + } + } + else if (p_lns_init->is_position_quality_present == true) + { + if (p_lns_init->p_position_quality == NULL) + { + return true; + } + } + + if (p_lns_init->is_control_point_present == false) + { + if (p_lns_init->available_features & + (BLE_LNS_FEATURE_LOC_AND_SPEED_CONTENT_MASKING_SUPPORTED | + BLE_LNS_FEATURE_FIX_RATE_SETTING_SUPPORTED | + BLE_LNS_FEATURE_ELEVATION_SETTING_SUPPORTED) + ) + { + return true; + } + } + + if (p_lns_init->is_navigation_present == false) + { + if (p_lns_init->available_features & + (BLE_LNS_FEATURE_REMAINING_DISTANCE_SUPPORTED | + BLE_LNS_FEATURE_REMAINING_VERT_DISTANCE_SUPPORTED | + BLE_LNS_FEATURE_EST_TIME_OF_ARRIVAL_SUPPORTED) + ) + { + return true; + } + if (p_lns_init->p_navigation != NULL) + { + return true; + } + } + else if (p_lns_init->is_navigation_present == true) + { + if (p_lns_init->p_navigation == NULL) + { + return true; + } + } + + // location and speed must always be specified + if (p_lns_init->p_location_speed == NULL) + { + return true; + } + + return false; +} + + +void ble_lns_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context) +{ + VERIFY_PARAM_NOT_NULL_VOID(p_context); + VERIFY_PARAM_NOT_NULL_VOID(p_ble_evt); + + ble_lns_t * p_lns = (ble_lns_t *)p_context; + ble_lncp_on_ble_evt(&p_lns->ctrl_pt, p_ble_evt); + + switch (p_ble_evt->header.evt_id) + { + case BLE_GAP_EVT_CONNECTED: + on_connect(p_lns, p_ble_evt); + break; + + case BLE_GAP_EVT_DISCONNECTED: + on_disconnect(p_lns, p_ble_evt); + break; + + case BLE_GATTS_EVT_WRITE: + on_write(p_lns, p_ble_evt); + break; + + case BLE_GATTS_EVT_HVN_TX_COMPLETE: + on_tx_complete(p_lns); + break; + + default: + // no implementation + break; + } +} + + +ret_code_t ble_lns_init(ble_lns_t * p_lns, ble_lns_init_t const * p_lns_init) +{ + VERIFY_PARAM_NOT_NULL(p_lns); + VERIFY_PARAM_NOT_NULL(p_lns_init); + + if (init_param_mismatch_present(p_lns_init) == true) + { + return NRF_ERROR_INVALID_PARAM; + } + + uint32_t err_code; + ble_uuid_t service_uuid; + ble_lncp_init_t lncp_init; + + // Initialize service structure + p_lns->evt_handler = p_lns_init->evt_handler; + p_lns->error_handler = p_lns_init->error_handler; + p_lns->conn_handle = BLE_CONN_HANDLE_INVALID; + p_lns->available_features = p_lns_init->available_features; + p_lns->is_navigation_present = p_lns_init->is_navigation_present; + + // clear pending notifications + p_lns->pending_loc_speed_notifications[0].is_pending = false; + p_lns->pending_loc_speed_notifications[1].is_pending = false; + p_lns->pending_navigation_notification.is_pending = false; + + p_lns->p_location_speed = p_lns_init->p_location_speed; + p_lns->p_position_quality = p_lns_init->p_position_quality; + p_lns->p_navigation = p_lns_init->p_navigation; + + p_lns->is_loc_speed_notification_enabled = false; + p_lns->is_nav_notification_enabled = false; + + ble_ln_db_init(); + + // Add service + BLE_UUID_BLE_ASSIGN(service_uuid, BLE_UUID_LOCATION_AND_NAVIGATION_SERVICE); + + err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &service_uuid, &p_lns->service_handle); + VERIFY_SUCCESS(err_code); + + // Add location and navigation feature characteristic + err_code = loc_and_nav_feature_char_add(p_lns, p_lns_init); + VERIFY_SUCCESS(err_code); + + // Add location and speed characteristic + err_code = loc_speed_char_add(p_lns, p_lns_init); + VERIFY_SUCCESS(err_code); + + if (p_lns_init->is_position_quality_present) + { + // Add Position quality characteristic + err_code = pos_quality_char_add(p_lns, p_lns_init); + VERIFY_SUCCESS(err_code); + } + else + { + p_lns->pos_qual_handles.cccd_handle = BLE_GATT_HANDLE_INVALID; + p_lns->pos_qual_handles.sccd_handle = BLE_GATT_HANDLE_INVALID; + p_lns->pos_qual_handles.user_desc_handle = BLE_GATT_HANDLE_INVALID; + p_lns->pos_qual_handles.value_handle = BLE_GATT_HANDLE_INVALID; + } + + if (p_lns_init->is_navigation_present) + { + // Add navigation characteristic + err_code = navigation_char_add(p_lns, p_lns_init); + VERIFY_SUCCESS(err_code); + } + else + { + p_lns->navigation_handles.cccd_handle = BLE_GATT_HANDLE_INVALID; + p_lns->navigation_handles.sccd_handle = BLE_GATT_HANDLE_INVALID; + p_lns->navigation_handles.user_desc_handle = BLE_GATT_HANDLE_INVALID; + p_lns->navigation_handles.value_handle = BLE_GATT_HANDLE_INVALID; + } + + if (p_lns_init->is_control_point_present) + { + lncp_init.error_handler = p_lns_init->error_handler; + lncp_init.evt_handler = p_lns_init->lncp_evt_handler; + lncp_init.write_perm = p_lns_init->ctrl_point_security_req_write_perm; + lncp_init.cccd_write_perm = p_lns_init->ctrl_point_security_req_cccd_write_perm; + lncp_init.available_features = p_lns_init->available_features; + lncp_init.is_position_quality_present = p_lns_init->is_position_quality_present; + lncp_init.is_navigation_present = p_lns_init->is_navigation_present; + + lncp_init.total_distance = p_lns_init->p_location_speed->total_distance; + lncp_init.elevation = p_lns_init->p_location_speed->elevation; + + lncp_init.service_handle = p_lns->service_handle; + lncp_init.navigation_handles = p_lns->navigation_handles; + + // Add control pointer characteristic + err_code = ble_lncp_init(&p_lns->ctrl_pt, &lncp_init); + VERIFY_SUCCESS(err_code); + + memcpy(&p_lns->ctrlpt_handles, &p_lns->ctrl_pt.ctrlpt_handles, sizeof(ble_gatts_char_handles_t)); + } + + NRF_LOG_DEBUG("Initialized"); + + return NRF_SUCCESS; +} + + +ret_code_t ble_lns_loc_speed_send(ble_lns_t * p_lns) +{ + VERIFY_PARAM_NOT_NULL(p_lns); + + if (p_lns->conn_handle == BLE_CONN_HANDLE_INVALID) + { + return NRF_ERROR_INVALID_STATE; + } + + if (!p_lns->is_loc_speed_notification_enabled) + { + return NRF_ERROR_INVALID_STATE; + } + + notification_t * notif1 = &p_lns->pending_loc_speed_notifications[0]; + notification_t * notif2 = &p_lns->pending_loc_speed_notifications[1]; + + // clear previous unsent data. Previous data is invalid. + notif1->is_pending = false; + notif2->is_pending = false; + + // check if it is necessary to send packet 1 + if (p_lns->available_features & (BLE_LNS_FEATURE_INSTANT_SPEED_SUPPORTED + | BLE_LNS_FEATURE_TOTAL_DISTANCE_SUPPORTED + | BLE_LNS_FEATURE_LOCATION_SUPPORTED)) + { + // encode + notif1->len = loc_speed_encode_packet1(p_lns, p_lns->p_location_speed, ¬if1->data[0]); + notif1->handle = p_lns->loc_speed_handles.value_handle; + notif1->is_pending = true; + + // send + notification_buffer_process(p_lns); + } + + // check if it is necessary to send packet 2 + if (p_lns->available_features & (BLE_LNS_FEATURE_ELEVATION_SUPPORTED + | BLE_LNS_FEATURE_HEADING_SUPPORTED + | BLE_LNS_FEATURE_ROLLING_TIME_SUPPORTED + | BLE_LNS_FEATURE_UTC_TIME_SUPPORTED)) + { + notif2->len = loc_speed_encode_packet2(p_lns, p_lns->p_location_speed, ¬if2->data[0]); + notif2->handle = p_lns->loc_speed_handles.value_handle; + notif2->is_pending = true; + + // send + notification_buffer_process(p_lns); + } + + return NRF_SUCCESS; +} + + +ret_code_t ble_lns_navigation_send(ble_lns_t * p_lns) +{ + VERIFY_PARAM_NOT_NULL(p_lns); + + if (p_lns->conn_handle == BLE_CONN_HANDLE_INVALID) + { + return NRF_ERROR_INVALID_STATE; + } + + notification_t * notif = &p_lns->pending_navigation_notification; + + // clear previous unsent data. Previous data is invalid. + notif->is_pending = false; + + if (!p_lns->is_navigation_present) + { + return NRF_ERROR_NOT_SUPPORTED; + } + + if (!p_lns->is_nav_notification_enabled) + { + return NRF_ERROR_INVALID_STATE; + } + + if (!ble_lncp_is_navigation_running(&p_lns->ctrl_pt)) + { + return NRF_ERROR_INVALID_STATE; + } + + notif->len = navigation_encode(p_lns, p_lns->p_navigation, ¬if->data[0]); + notif->handle = p_lns->navigation_handles.value_handle; + notif->is_pending = true; + + notification_buffer_process(p_lns); + + return NRF_SUCCESS; +} + + +ret_code_t ble_lns_add_route(ble_lns_t * p_lns, ble_lns_route_t * p_route) +{ + VERIFY_PARAM_NOT_NULL(p_lns); + VERIFY_PARAM_NOT_NULL(p_route); + + if (p_lns->is_navigation_present == false) + { + return NRF_ERROR_NOT_SUPPORTED; + } + + return ble_ln_db_record_add(p_route); +} + + +ret_code_t ble_lns_remove_route(ble_lns_t * p_lns, uint16_t route_id) +{ + VERIFY_PARAM_NOT_NULL(p_lns); + + if (p_lns->is_navigation_present == false) + { + return NRF_ERROR_NOT_SUPPORTED; + } + + return ble_ln_db_record_delete(route_id); +} diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_lns.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_lns.h new file mode 100644 index 0000000..28a9223 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_lns.h @@ -0,0 +1,381 @@ +/** + * Copyright (c) 2015 - 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_lns Location and Navigation Service + * @{ + * @ingroup ble_sdk_srv + * @brief Location and Navigation Service module. + * + * @details This module implements the Location and Navigation Service with the Location and Speed, Position + * Quality, Feature, Control Point, and Navigation characteristics. + * + * If an event handler is supplied by the application, the Location and Navigation Service will + * generate Location and Navigation Service events to the application. + * + * @note The application must register this module as BLE event observer using the + * NRF_SDH_BLE_OBSERVER macro. Example: + * @code + * ble_lns_t instance; + * NRF_SDH_BLE_OBSERVER(anything, BLE_LNS_BLE_OBSERVER_PRIO, + * ble_lns_on_ble_evt, &instance); + * @endcode + */ + +#ifndef BLE_LNS_H__ +#define BLE_LNS_H__ + +#include "ble_srv_common.h" +#include "ble_date_time.h" +#include "ble_ln_common.h" +#include "ble_ln_cp.h" +#include "sdk_common.h" +#include "nrf_sdh_ble.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/**@ Macro for defining a ble_lns instance. + * + * @param _name Name of the instance. + * @hideinitializer + */ +#define BLE_LNS_DEF(_name) \ +static ble_lns_t _name; \ +NRF_SDH_BLE_OBSERVER(_name ## _obs, \ + BLE_LNS_BLE_OBSERVER_PRIO, \ + ble_lns_on_ble_evt, &_name) + + +/**@brief Location and Navigation event type. This list defines the possible events types from the Location and Navigation Service. */ +typedef enum +{ + BLE_LNS_CTRLPT_EVT_INDICATION_ENABLED, /**< Control Point value indication was enabled. */ + BLE_LNS_CTRLPT_EVT_INDICATION_DISABLED, /**< Control Point value indication was disabled. */ + BLE_LNS_LOC_SPEED_EVT_NOTIFICATION_ENABLED, /**< Location and Speed value notification was enabled. */ + BLE_LNS_LOC_SPEED_EVT_NOTIFICATION_DISABLED, /**< Location and Speed value notification was disabled. */ + BLE_LNS_NAVIGATION_EVT_NOTIFICATION_ENABLED, /**< Navigation value notification was enabled. */ + BLE_LNS_NAVIGATION_EVT_NOTIFICATION_DISABLED, /**< Navigation value notification was disabled. */ +} ble_lns_evt_type_t; + +/**@brief Location and Navigation event structure. When an event occurs, the data structures of the module are automatically updated. */ +typedef struct +{ + ble_lns_evt_type_t evt_type; +} ble_lns_evt_t; + +// Forward declarations of the ble_lns types. +typedef struct ble_lns_init_s ble_lns_init_t; +typedef struct ble_lns_s ble_lns_t; +typedef struct ble_lns_loc_speed_s ble_lns_loc_speed_t; +typedef struct ble_lns_pos_quality_s ble_lns_pos_quality_t; +typedef struct ble_lns_navigation_s ble_lns_navigation_t; + + +typedef struct +{ + bool is_pending; + uint16_t handle; + uint16_t len; + uint8_t data[BLE_GATT_ATT_MTU_DEFAULT]; +} notification_t; + + +/**@brief Location and Navigation Service event handler type. */ +typedef void (*ble_lns_evt_handler_t) (ble_lns_t const * p_lns, ble_lns_evt_t const * p_evt); + + +/**@brief Location and Navigation Service init structure. This structure contains all options + * and data needed to initialize the service. + */ +struct ble_lns_init_s +{ + ble_lns_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Location and Navigation Service. */ + ble_lncp_evt_handler_t lncp_evt_handler; + ble_srv_error_handler_t error_handler; /**< Errors will be sent back to this function. */ + + bool is_position_quality_present; /**< If set to true, the position quality characteristic will be added. Else not. */ + bool is_control_point_present; /**< If set to true, the control point characteristic will be added. Else not. */ + bool is_navigation_present; /**< If set to true, the navigation characteristic will be added. Else not. */ + + security_req_t loc_nav_feature_security_req_read_perm; /**< Read security level of the LN Feature characteristic. */ + security_req_t loc_speed_security_req_cccd_write_perm; /**< CCCD write security level of the Write Location and Speed characteristic. */ + security_req_t position_quality_security_req_read_perm; /**< Read security level of the Position Quality characteristic. */ + security_req_t navigation_security_req_cccd_write_perm; /**< CCCD write security level of the Navigation characteristic. */ + security_req_t ctrl_point_security_req_write_perm; /**< Read security level of the LN Control Point characteristic. */ + security_req_t ctrl_point_security_req_cccd_write_perm; /**< CCCD write security level of the LN Control Point characteristic. */ + + uint32_t available_features; /**< Value of the LN feature. */ + ble_lns_loc_speed_t * p_location_speed; /**< Initial Location and Speed. */ + ble_lns_pos_quality_t * p_position_quality; /**< Initial Position Quality. */ + ble_lns_navigation_t * p_navigation; /**< Initial Navigation data structure. */ +}; + +/**@brief Definition of a navigation route.*/ +typedef struct +{ + uint16_t route_id; + uint8_t route_name[BLE_LNS_MAX_ROUTE_NAME_LEN]; +} ble_lns_route_t; + +/**@brief Location and Navigation Service structure. This structure contains various status information for the service. */ +struct ble_lns_s +{ + ble_lns_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Location and Navigation Service. */ + ble_srv_error_handler_t error_handler; /**< Error handler. */ + + bool is_navigation_present; /**< If set to true, the navigation characteristic is present. Else not. */ + + uint16_t conn_handle; /**< Handle of the current connection (as provided by the BLE stack; BLE_CONN_HANDLE_INVALID if not in a connection). */ + uint16_t service_handle; /**< Handle of Location and Navigation Service (as provided by the BLE stack). */ + ble_gatts_char_handles_t loc_speed_handles; /**< Handles related to the Location and Speed characteristic. */ + ble_gatts_char_handles_t feature_handles; /**< Handles related to the Location and Navigation Feature characteristic. */ + ble_gatts_char_handles_t navigation_handles; /**< Handles related to the Navigation characteristic. */ + ble_gatts_char_handles_t pos_qual_handles; /**< Handles related to the Position Quality characteristic. */ + ble_gatts_char_handles_t ctrlpt_handles; + uint32_t available_features; /**< Value of Location and Navigation feature. */ + + bool is_loc_speed_notification_enabled; /**< True if notification is enabled on the Location and Speed characteristic. */ + bool is_nav_notification_enabled; /**< True if notification is enabled on the Navigation characteristic. */ + + notification_t pending_loc_speed_notifications[2]; /**< This buffer holds location and speed notifications. */ + notification_t pending_navigation_notification; /**< This buffer holds navigation notifications. */ + ble_lns_loc_speed_t * p_location_speed; /**< Location and Speed. */ + ble_lns_pos_quality_t * p_position_quality; /**< Position measurement quality. */ + ble_lns_navigation_t * p_navigation; /**< Navigation data structure. */ + ble_lncp_t ctrl_pt; +}; + +/**@brief Position status. This enumeration defines how to interpret the position data. */ +typedef enum +{ + BLE_LNS_NO_POSITION = 0, + BLE_LNS_POSITION_OK = 1, + BLE_LNS_ESTIMATED = 2, + BLE_LNS_LAST_KNOWN_POSITION = 3 +} ble_lns_pos_status_type_t; + +/**@brief The format of the position and speed measurements. */ +typedef enum +{ + BLE_LNS_SPEED_DISTANCE_FORMAT_2D = 0, + BLE_LNS_SPEED_DISTANCE_FORMAT_3D = 1 +} ble_lns_speed_distance_format_t; + +/**@brief Elevation source. */ +typedef enum +{ + BLE_LNS_ELEV_SOURCE_POSITIONING_SYSTEM = 0, + BLE_LNS_ELEV_SOURCE_BAROMETRIC = 1, + BLE_LNS_ELEV_SOURCE_DATABASE_SERVICE = 2, + BLE_LNS_ELEV_SOURCE_OTHER = 3 +} ble_lns_elevation_source_t; + +/**@brief Heading source. */ +typedef enum +{ + BLE_LNS_HEADING_SOURCE_MOVEMENT = 0, + BLE_LNS_HEADING_SOURCE_COMPASS = 1 +} ble_lns_heading_source_t; + +/**@brief Location and Speed data structure. */ +struct ble_lns_loc_speed_s +{ + bool instant_speed_present; /**< Instantaneous Speed present (0=not present, 1=present). */ + bool total_distance_present; /**< Total Distance present (0=not present, 1=present). */ + bool location_present; /**< Location present (0=not present, 1=present). */ + bool elevation_present; /**< Elevation present (0=not present, 1=present). */ + bool heading_present; /**< Heading present (0=not present, 1=present). */ + bool rolling_time_present; /**< Rolling Time present (0=not present, 1=present). */ + bool utc_time_time_present; /**< UTC Time present (0=not present, 1=present). */ + ble_lns_pos_status_type_t position_status; /**< Status of current position */ + ble_lns_speed_distance_format_t data_format; /**< Format of data (either 2D or 3D). */ + ble_lns_elevation_source_t elevation_source; /**< Source of the elevation measurement. */ + ble_lns_heading_source_t heading_source; /**< Source of the heading measurement. */ + uint16_t instant_speed; /**< Instantaneous Speed (1/10 meter per sec). */ + uint32_t total_distance; /**< Total Distance (meters), size=24 bits. */ + int32_t latitude; /**< Latitude (10e-7 degrees). */ + int32_t longitude; /**< Longitude (10e-7 degrees). */ + int32_t elevation; /**< Elevation (1/100 meters), size=24 bits. */ + uint16_t heading; /**< Heading (1/100 degrees). */ + uint8_t rolling_time; /**< Rolling Time (seconds). */ + ble_date_time_t utc_time; /**< UTC Time. */ +}; + +/**@brief Position quality structure. */ +struct ble_lns_pos_quality_s +{ + bool number_of_satellites_in_solution_present; /**< The number of satellites present in solution (0=not present, 1=present). */ + bool number_of_satellites_in_view_present; /**< The number of satellites present in solution (0=not present, 1=present). */ + bool time_to_first_fix_present; /**< Time to the first position fix present (0=not present, 1=present). */ + bool ehpe_present; /**< Error in horizontal position estimate present (0=not present, 1=present). */ + bool evpe_present; /**< Error in vertical position estimate present (0=not present, 1=present). */ + bool hdop_present; /**< Horizontal dilution of precision present (0=not present, 1=present). */ + bool vdop_present; /**< Vertical dilution of precision present (0=not present, 1=present). */ + ble_lns_pos_status_type_t position_status; /**< Status of last measured position. */ + uint8_t number_of_satellites_in_solution; /**< The number of satellites in solution (unitless, with a resolution of 1). */ + uint8_t number_of_satellites_in_view; /**< The number of satellites in view (unitless, with a resolution of 1). */ + uint16_t time_to_first_fix; /**< Time to the first position fix (seconds, with a resolution of 1/10). */ + uint32_t ehpe; /**< Error in horizontal position estimate (meters, with a resolution of 1/100). */ + uint32_t evpe; /**< Error in vertical position estimate (meters, with a resolution of 1/100). */ + uint8_t hdop; /**< Horizontal dilution of precision (unitless, with a resolution of 2/10). */ + uint8_t vdop; /**< Vertical dilution of precision (unitless, with a resolution of 2/10). */ +}; + +/**@brief Navigation indicator type. */ +typedef enum +{ + BLE_LNS_NAV_TO_WAYPOINT = 0, + BLE_LNS_NAV_TO_DESTINATION = 1 +} ble_lns_nav_indicator_type_t; + +/**@brief Navigation data structure. */ +struct ble_lns_navigation_s +{ + bool remaining_dist_present; /**< Remaining Distance present (0=not present, 1=present). */ + bool remaining_vert_dist_present; /**< Remaining Vertical Distance present (0=not present, 1=present). */ + bool eta_present; /**< Estimated Time of Arrival present (0=not present, 1=present). */ + ble_lns_pos_status_type_t position_status; /**< Status of last measured position. */ + ble_lns_heading_source_t heading_source; /**< Source of the heading measurement. */ + ble_lns_nav_indicator_type_t navigation_indicator_type; /**< Navigation indicator type. */ + bool waypoint_reached; /**< Waypoint Reached (0=not reached, 1=reached). */ + bool destination_reached; /**< Destination Reached (0=not reached, 1=reached). */ + uint16_t bearing; /**< Bearing (1/100 degrees).*/ + uint16_t heading; /**< Heading (1/100 degrees), size=24 bit. */ + uint32_t remaining_distance; /**< Remaining Distance (1/10 meters), size=24 bit. */ + int32_t remaining_vert_distance; /**< Remaining Vertical Distance (1/100 meters), size=24 bit. */ + ble_date_time_t eta; /**< Estimated Time of Arrival. */ +}; + + +/**@brief Function for initializing the Location and Navigation Service. + * + * @param[out] p_lns Location and Navigation 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_lns_init Information needed to initialize the service. + * + * @retval NRF_SUCCESS If the service was initialized successfully. + * @retval NRF_ERROR_NULL If a NULL parameter was provided. + * @retval NRF_INVALID_PARAMS If there is an inconsistency in the initialization structure. + * @return Otherwise, an error code from either sd_ble_gatts_service_add() or sd_ble_gatts_characteristic_add() is returned. + */ +ret_code_t ble_lns_init(ble_lns_t * p_lns, ble_lns_init_t const * p_lns_init); + + +/**@brief Function for handling Location and Navigation Service BLE stack events. + * + * @details This function handles all events from the BLE stack that are of interest to the + * Location and Navigation Service. + * + * @note The function returns when a NULL parameter is provided. + * + * @param[in] p_ble_evt Event received from the BLE stack. + * @param[in] p_context Location and Navigation Service structure. + */ +void ble_lns_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context); + + +/**@brief Function for sending location and speed data if notification has been enabled. + * + * @details The application calls this function after having performed a location and speed determination. + * If notification has been enabled, the location and speed data is encoded and sent to + * the client. + * + * @param[in] p_lns Location and Navigation Service structure holding the location and speed data. + * + * @retval NRF_SUCCESS If the data was sent successfully. + * @retval NRF_ERROR_NULL If a NULL parameter was provided. + * @retval NRF_ERROR_INVALID_STATE If notification is disabled. + */ +ret_code_t ble_lns_loc_speed_send(ble_lns_t * p_lns); + + +/**@brief Function for sending navigation data if notification has been enabled. + * + * @details The application calls this function after having performed a navigation determination. + * If notification has been enabled, the navigation data is encoded and sent to + * the client. + * + * @param[in] p_lns Location and Navigation Service structure holding the navigation data. + * + * @retval NRF_SUCCESS If the data was sent successfully. + * @retval NRF_ERROR_NULL If a NULL parameter was provided. + * @retval NRF_ERROR_NOT_SUPPORTED If the navigation characteristic is absent. + * @retval NRF_ERROR_INVALID_STATE If navigation is not running or notification is disabled. + */ +ret_code_t ble_lns_navigation_send(ble_lns_t * p_lns); + + +/**@brief Function for adding a route to the Location and Navigation Service. + * + * @param[in] p_lns Location and Navigation Service structure. + * @param[in,out] p_route The new route to be added. The route ID is updated. + * + * @retval NRF_SUCCESS If the route was added successfully. + * @retval NRF_ERROR_NULL If a NULL parameter was provided. + * @retval NRF_ERROR_NOT_SUPPORTED If the navigation characteristic is absent. + * @retval NRF_ERROR_NO_MEM If there is no memory left. + * @retval NRF_ERROR_INTERNAL If there is an inconsistency in the routes table. + */ +ret_code_t ble_lns_add_route(ble_lns_t * p_lns, ble_lns_route_t * p_route); + + +/**@brief Function for removing a route from the Location and Navigation Service. + * + * @param[in] p_lns Location and Navigation Service structure. + * @param[in] route_id The ID of the route to be removed. + * + * @retval NRF_SUCCESS If the route was removed successfully. + * @retval NRF_ERROR_NULL If a NULL parameter was provided. + * @retval NRF_ERROR_NOT_SUPPORTED If the navigation characteristic is absent. + * @retval NRF_INVALID_PARAM If the route ID does not exist. + */ +ret_code_t ble_lns_remove_route(ble_lns_t * p_lns, uint16_t route_id); + + +#ifdef __cplusplus +} +#endif + +#endif // BLE_LNS_H__ + +/** @} */ |