diff options
Diffstat (limited to 'thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_ln_cp.c')
-rw-r--r-- | thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_ln_cp.c | 821 |
1 files changed, 821 insertions, 0 deletions
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); +} |