初始版本

This commit is contained in:
xiaozhengsheng
2025-08-19 09:49:41 +08:00
parent 10f1ddf1c1
commit 6df0f7d96e
2974 changed files with 1712873 additions and 54 deletions

View File

@@ -0,0 +1,476 @@
/**
* Copyright (c) 2017 - 2020, 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 "sdk_common.h"
#if NRF_MODULE_ENABLED(BLE_OTS_C)
#include <stdlib.h>
#include "nrf_ble_ots_c.h"
#include "nrf_ble_ots_c_oacp.h"
#include "nrf_ble_ots_c_l2cap.h"
#include "ble.h"
#define NRF_LOG_MODULE_NAME ble_ots_c
#include "nrf_log.h"
NRF_LOG_MODULE_REGISTER();
#include "sdk_common.h"
#define BLE_OTS_OACP_SUPPORT_FEATURE_CREATE_bp 0
#define BLE_OTS_OACP_SUPPORT_FEATURE_DELETE_bp 1
#define BLE_OTS_OACP_SUPPORT_FEATURE_CALC_CHECKSUM_bp 2
#define BLE_OTS_OACP_SUPPORT_FEATURE_EXECUTE_bp 3
#define BLE_OTS_OACP_SUPPORT_FEATURE_READ_bp 4
#define BLE_OTS_OACP_SUPPORT_FEATURE_WRITE_bp 5
#define BLE_OTS_OACP_SUPPORT_FEATURE_APPEND_bp 6
#define BLE_OTS_OACP_SUPPORT_FEATURE_TRUNCATE_bp 7
#define BLE_OTS_OACP_SUPPORT_FEATURE_PATCH_bp 8
#define BLE_OTS_OACP_SUPPORT_FEATURE_ABORT_bp 9
#define BLE_OTS_OLCP_SUPPORT_FEATURE_GOTO_bp 0
#define BLE_OTS_OLCP_SUPPORT_FEATURE_ORDER_bp 1
#define BLE_OTS_OLCP_SUPPORT_FEATURE_REQ_NUM_OBJECTS_bp 2
#define BLE_OTS_OLCP_SUPPORT_FEATURE_CLEAR_MARKING_bp 3
#define MODULE_INITIALIZED (p_ots_c->initialized) /**< Macro designating whether the module was initialized properly. */
static const ble_uuid_t m_ots_uuid = {BLE_UUID_OTS_SERVICE, BLE_UUID_TYPE_BLE}; /**< Object Transfer Service UUID. */
/**@brief Function for intercepting the errors of GATTC and the BLE GATT Queue.
*
* @param[in] nrf_error Error code.
* @param[in] p_ctx Parameter from the event handler.
* @param[in] conn_handle Connection handle.
*/
static void gatt_error_handler(uint32_t nrf_error,
void * p_ctx,
uint16_t conn_handle)
{
nrf_ble_ots_c_t * p_ots_c = (nrf_ble_ots_c_t *)p_ctx;
NRF_LOG_DEBUG("A GATT Client error has occurred on conn_handle: 0X%X", conn_handle);
if (p_ots_c->err_handler != NULL)
{
p_ots_c->err_handler(nrf_error);
}
}
ret_code_t nrf_ble_ots_c_init(nrf_ble_ots_c_t * p_ots_c,
nrf_ble_ots_c_init_t * p_ots_c_init)
{
ret_code_t err_code = NRF_SUCCESS;
VERIFY_PARAM_NOT_NULL(p_ots_c);
VERIFY_PARAM_NOT_NULL(p_ots_c_init);
VERIFY_PARAM_NOT_NULL(p_ots_c_init->evt_handler);
VERIFY_PARAM_NOT_NULL(p_ots_c_init->p_gatt_queue);
memset (p_ots_c, 0, sizeof(nrf_ble_ots_c_t));
p_ots_c->conn_handle = BLE_CONN_HANDLE_INVALID;
p_ots_c->evt_handler = p_ots_c_init->evt_handler;
p_ots_c->err_handler = p_ots_c_init->err_handler;
p_ots_c->p_gatt_queue = p_ots_c_init->p_gatt_queue;
p_ots_c->gatt_err_handler = gatt_error_handler;
err_code = ble_db_discovery_evt_register(&m_ots_uuid);
VERIFY_SUCCESS(err_code);
p_ots_c->initialized = true;
return err_code;
}
/**@brief Function for checking whether the peer's Object Transfer Service instance has been discovered.
@param[in] p_ots_c Pointer to the GATT Service client structure instance.
@return True, if the Object Transfer service handles are valid.
@return False, if the Object Transfer service handles are invalid.
*/
static bool ots_gatt_handles_are_valid(const nrf_ble_ots_c_t * const p_ots_c)
{
return (p_ots_c->service.object_prop_char.handle_value != BLE_GATT_HANDLE_INVALID
&& p_ots_c->service.object_size_char.handle_value != BLE_GATT_HANDLE_INVALID
&& p_ots_c->service.object_type_char.handle_value != BLE_GATT_HANDLE_INVALID
&& p_ots_c->service.ots_feature_char.handle_value != BLE_GATT_HANDLE_INVALID);
}
ret_code_t nrf_ble_ots_c_feature_read(nrf_ble_ots_c_t * const p_ots_c)
{
VERIFY_MODULE_INITIALIZED();
nrf_ble_gq_req_t read_req;
memset(&read_req, 0, sizeof(nrf_ble_gq_req_t));
read_req.type = NRF_BLE_GQ_REQ_GATTC_READ;
read_req.error_handler.cb = p_ots_c->gatt_err_handler;
read_req.error_handler.p_ctx = (nrf_ble_ots_c_t *)p_ots_c;
read_req.params.gattc_read.handle = p_ots_c->service.ots_feature_char.handle_value;
read_req.params.gattc_read.offset = 0;
return nrf_ble_gq_item_add(p_ots_c->p_gatt_queue, &read_req, p_ots_c->conn_handle);
}
ret_code_t nrf_ble_ots_c_obj_size_read(nrf_ble_ots_c_t * const p_ots_c)
{
VERIFY_MODULE_INITIALIZED();
if( p_ots_c->service.object_size_char.handle_value == BLE_GATT_HANDLE_INVALID)
{
return NRF_ERROR_INVALID_STATE;
}
nrf_ble_gq_req_t read_req;
memset(&read_req, 0, sizeof(nrf_ble_gq_req_t));
read_req.type = NRF_BLE_GQ_REQ_GATTC_READ;
read_req.error_handler.cb = p_ots_c->gatt_err_handler;
read_req.error_handler.p_ctx = (nrf_ble_ots_c_t *)p_ots_c;
read_req.params.gattc_read.handle = p_ots_c->service.object_size_char.handle_value;
read_req.params.gattc_read.offset = 0;
return nrf_ble_gq_item_add(p_ots_c->p_gatt_queue, &read_req, p_ots_c->conn_handle);
}
ret_code_t nrf_ble_ots_c_obj_properties_read(nrf_ble_ots_c_t * const p_ots_c)
{
VERIFY_MODULE_INITIALIZED();
if( p_ots_c->service.object_prop_char.handle_value == BLE_GATT_HANDLE_INVALID)
{
return NRF_ERROR_INVALID_STATE;
}
nrf_ble_gq_req_t read_req;
memset(&read_req, 0, sizeof(nrf_ble_gq_req_t));
read_req.type = NRF_BLE_GQ_REQ_GATTC_READ;
read_req.error_handler.cb = p_ots_c->gatt_err_handler;
read_req.error_handler.p_ctx = (nrf_ble_ots_c_t *)p_ots_c;
read_req.params.gattc_read.handle = p_ots_c->service.object_prop_char.handle_value;
read_req.params.gattc_read.offset = 0;
return nrf_ble_gq_item_add(p_ots_c->p_gatt_queue, &read_req, p_ots_c->conn_handle);
}
static void prop_read_rsp_decode(nrf_ble_ots_c_t * p_ots_c, const ble_evt_t * p_ble_evt)
{
const ble_gattc_evt_read_rsp_t * p_response;
p_response = &p_ble_evt->evt.gattc_evt.params.read_rsp;
uint32_t properties;
properties = uint32_decode(&p_response->data[0]);
nrf_ble_ots_c_evt_t evt;
evt.conn_handle = p_ble_evt->evt.gattc_evt.conn_handle;
evt.params.prop.raw = properties;
evt.evt_type = NRF_BLE_OTS_C_EVT_PROP_READ_RESP;
p_ots_c->evt_handler(&evt);
}
/**@brief Function for handling read response events.
*
* @details This function will validate the read response and raise the appropriate
* event to the application.
*
* @param[in] p_ots_c Pointer to the Object Transfer instance.
* @param[in] p_ble_evt Pointer to the SoftDevice event.
*/
static void on_read_rsp(nrf_ble_ots_c_t * p_ots_c, const ble_evt_t * p_ble_evt)
{
const ble_gattc_evt_read_rsp_t * p_response;
// Check if the event is on the link for this instance
if (p_ots_c->conn_handle != p_ble_evt->evt.gattc_evt.conn_handle)
{
return;
}
p_response = &p_ble_evt->evt.gattc_evt.params.read_rsp;
if (p_response->handle == p_ots_c->service.ots_feature_char.handle_value)
{
nrf_ble_ots_c_evt_t evt;
evt.conn_handle = p_ble_evt->evt.gattc_evt.conn_handle;
evt.evt_type = NRF_BLE_OTS_C_EVT_FEATURE_READ_RESP;
uint32_t oacp_features;
oacp_features = uint32_decode(&p_response->data[0]);
evt.params.feature.oacp_create = oacp_features >> BLE_OTS_OACP_SUPPORT_FEATURE_CREATE_bp;
evt.params.feature.oacp_delete = oacp_features >> BLE_OTS_OACP_SUPPORT_FEATURE_DELETE_bp;
evt.params.feature.oacp_crc = oacp_features >> BLE_OTS_OACP_SUPPORT_FEATURE_CALC_CHECKSUM_bp;
evt.params.feature.oacp_execute = oacp_features >> BLE_OTS_OACP_SUPPORT_FEATURE_EXECUTE_bp;
evt.params.feature.oacp_read = oacp_features >> BLE_OTS_OACP_SUPPORT_FEATURE_READ_bp;
evt.params.feature.oacp_write = oacp_features >> BLE_OTS_OACP_SUPPORT_FEATURE_WRITE_bp;
evt.params.feature.oacp_append = oacp_features >> BLE_OTS_OACP_SUPPORT_FEATURE_APPEND_bp;
evt.params.feature.oacp_truncate = oacp_features >> BLE_OTS_OACP_SUPPORT_FEATURE_TRUNCATE_bp;
evt.params.feature.oacp_patch = oacp_features >> BLE_OTS_OACP_SUPPORT_FEATURE_PATCH_bp;
evt.params.feature.oacp_abort = oacp_features >> BLE_OTS_OACP_SUPPORT_FEATURE_ABORT_bp;
uint32_t olcp_features;
/*lint --e{415} --e{416} -save suppress Warning 415: Likely access of out-of-bounds pointer */
olcp_features = uint32_decode(&p_response->data[sizeof(uint32_t)]);
/*lint -restore*/
evt.params.feature.olcp_goto = olcp_features >> BLE_OTS_OLCP_SUPPORT_FEATURE_GOTO_bp;
evt.params.feature.olcp_order = olcp_features >> BLE_OTS_OLCP_SUPPORT_FEATURE_ORDER_bp;
evt.params.feature.olcp_req_num = olcp_features >> BLE_OTS_OLCP_SUPPORT_FEATURE_REQ_NUM_OBJECTS_bp;
evt.params.feature.olcp_clear = olcp_features >> BLE_OTS_OLCP_SUPPORT_FEATURE_CLEAR_MARKING_bp;
p_ots_c->evt_handler(&evt);
}
if (p_response->handle == p_ots_c->service.object_size_char.handle_value)
{
nrf_ble_ots_c_evt_t evt;
evt.conn_handle = p_ble_evt->evt.gattc_evt.conn_handle;
evt.evt_type = NRF_BLE_OTS_C_EVT_SIZE_READ_RESP;
uint8_t len = 0;
evt.params.size.current_size = uint32_decode(&p_response->data[len]);
len += sizeof(uint32_t);
/*lint --e{415} --e{416} -save suppress Warning 415: Likely access of out-of-bounds pointer */
evt.params.size.allocated_size = uint32_decode(&p_response->data[len]);
/*lint -restore*/
/*lint --e{438} -save */
len += sizeof(uint32_t);
/*lint -restore*/
p_ots_c->evt_handler(&evt);
}
if (p_response->handle == p_ots_c->service.object_prop_char.handle_value)
{
prop_read_rsp_decode(p_ots_c, p_ble_evt);
}
}
void nrf_ble_ots_c_on_db_disc_evt(nrf_ble_ots_c_t const * const p_ots_c,
ble_db_discovery_evt_t * const p_evt)
{
VERIFY_MODULE_INITIALIZED_VOID();
nrf_ble_ots_c_evt_t evt;
ble_gatt_db_char_t* p_chars;
p_chars = p_evt->params.discovered_db.charateristics;
evt.evt_type = NRF_BLE_OTS_C_EVT_DISCOVERY_FAILED;
if ((p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE) &&
(p_evt->params.discovered_db.srv_uuid.uuid == BLE_UUID_OTS_SERVICE) &&
(p_evt->params.discovered_db.srv_uuid.type == BLE_UUID_TYPE_BLE))
{
// Find the handles of the OTS characteristics.
for (uint32_t i = 0; i < p_evt->params.discovered_db.char_count; i++)
{
switch (p_chars[i].characteristic.uuid.uuid)
{
case BLE_UUID_OTS_FEATURES:
NRF_LOG_DEBUG("OTS Feature Characteristic found.\r\n");
memcpy(&evt.params.handles.ots_feature_char,
&p_chars[i].characteristic,
sizeof(ble_gattc_char_t));
break;
case BLE_UUID_OTS_OBJECT_NAME:
NRF_LOG_DEBUG("Object Name Characteristic found.\r\n");
memcpy(&evt.params.handles.object_name_char,
&p_chars[i].characteristic,
sizeof(ble_gattc_char_t));
break;
case BLE_UUID_OTS_OBJECT_TYPE:
NRF_LOG_DEBUG("Object Type Characteristic found.\r\n");
memcpy(&evt.params.handles.object_type_char,
&p_chars[i].characteristic,
sizeof(ble_gattc_char_t));
break;
case BLE_UUID_OTS_OBJECT_SIZE:
NRF_LOG_DEBUG("Object Size Characteristic found.\r\n");
memcpy(&evt.params.handles.object_size_char,
&p_chars[i].characteristic,
sizeof(ble_gattc_char_t));
break;
case BLE_UUID_OTS_OBJECT_PROPERTIES:
NRF_LOG_DEBUG("Object Properties Characteristic found.\r\n");
memcpy(&evt.params.handles.object_prop_char,
&p_chars[i].characteristic,
sizeof(ble_gattc_char_t));
break;
case BLE_UUID_OTS_OACP:
NRF_LOG_DEBUG("Object Action Control Point found. CCCD Handle %x\r\n", p_chars[i].cccd_handle);
memcpy(&evt.params.handles.object_action_cp_char,
&p_chars[i].characteristic,
sizeof(ble_gattc_char_t));
evt.params.handles.object_action_cp_cccd.handle = p_chars[i].cccd_handle;
break;
default:
break;
}
}
evt.evt_type = NRF_BLE_OTS_C_EVT_DISCOVERY_COMPLETE;
evt.conn_handle = p_evt->conn_handle;
}
else if ((p_evt->evt_type == BLE_DB_DISCOVERY_SRV_NOT_FOUND) ||
(p_evt->evt_type == BLE_DB_DISCOVERY_ERROR))
{
evt.evt_type = NRF_BLE_OTS_C_EVT_DISCOVERY_FAILED;
}
else
{
return;
}
p_ots_c->evt_handler(&evt);
}
/**@brief Function for handling the Disconnect event.
@param[in] p_cts Pointer to the GATT Service client structure instance.
@param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_disconnect(nrf_ble_ots_c_t * const p_ots_c, ble_evt_t const * const p_ble_evt)
{
if (p_ots_c->conn_handle == p_ble_evt->evt.gap_evt.conn_handle)
{
p_ots_c->conn_handle = BLE_CONN_HANDLE_INVALID;
if (ots_gatt_handles_are_valid(p_ots_c))
{
// There was a valid instance of ots on the peer. Send an event to the
// application, so that it can do any clean up related to this module.
nrf_ble_ots_c_evt_t evt;
evt.evt_type = NRF_BLE_OTS_C_EVT_DISCONN_COMPLETE;
p_ots_c->evt_handler(&evt);
memset(&p_ots_c->service, 0, sizeof(nrf_ble_ots_c_service_t));
}
}
}
void nrf_ble_ots_c_on_ble_evt(ble_evt_t const * const p_ble_evt,
void * p_context)
{
nrf_ble_ots_c_t * p_ots_c;
p_ots_c = (nrf_ble_ots_c_t*) p_context;
VERIFY_MODULE_INITIALIZED_VOID();
VERIFY_PARAM_NOT_NULL_VOID(p_ots_c);
VERIFY_PARAM_NOT_NULL_VOID(p_ble_evt);
switch (p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_DISCONNECTED:
on_disconnect(p_ots_c, p_ble_evt);
break;
case BLE_GATTC_EVT_READ_RSP:
on_read_rsp(p_ots_c, p_ble_evt);
break;
case BLE_GATTC_EVT_WRITE_RSP:
if ((p_ble_evt->evt.gattc_evt.error_handle != BLE_GATT_HANDLE_INVALID)
&& (p_ble_evt->evt.gattc_evt.error_handle ==
p_ots_c->service.object_action_cp_char.handle_value))
{
if (p_ble_evt->evt.gattc_evt.gatt_status == BLE_GATT_STATUS_ATTERR_CPS_CCCD_CONFIG_ERROR)
{
NRF_LOG_INFO("write to OACP failed, CCCD improperly configured, enable indications on OACP and try again");
}
else
{
NRF_LOG_INFO("BLE_GATTC_EVT_WRITE_RSP error handle: %x error response %x\r\n",
p_ble_evt->evt.gattc_evt.error_handle,
p_ble_evt->evt.gattc_evt.gatt_status);
}
}
break;
default:
break;
}
ots_c_l2cap_on_ble_evt(p_ots_c, p_ble_evt);
ots_c_oacp_on_ble_evt(p_ots_c, p_ble_evt);
}
ret_code_t nrf_ble_ots_c_handles_assign(nrf_ble_ots_c_t * const p_ots_c,
uint16_t const conn_handle,
nrf_ble_ots_c_service_t const * const p_peer_handles)
{
VERIFY_MODULE_INITIALIZED();
VERIFY_PARAM_NOT_NULL(p_ots_c);
p_ots_c->conn_handle = conn_handle;
if (p_peer_handles != NULL)
{
p_ots_c->service.ots_feature_char.handle_value = p_peer_handles->ots_feature_char.handle_value;
p_ots_c->service.object_type_char.handle_value = p_peer_handles->object_type_char.handle_value;
p_ots_c->service.object_size_char.handle_value = p_peer_handles->object_size_char.handle_value;
p_ots_c->service.object_prop_char.handle_value = p_peer_handles->object_prop_char.handle_value;
p_ots_c->service.object_action_cp_char.handle_value = p_peer_handles->object_action_cp_char.handle_value;
p_ots_c->service.object_action_cp_cccd.handle = p_peer_handles->object_action_cp_cccd.handle;
}
return nrf_ble_gq_conn_handle_register(p_ots_c->p_gatt_queue, conn_handle);
}
#endif // NRF_MODULE_ENABLED(BLE_OTS_C)

View File

@@ -0,0 +1,351 @@
/**
* Copyright (c) 2017 - 2020, 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 nrf_ble_ots_c Object Transfer Service Client
* @{
* @ingroup ble_sdk_srv
* @brief Object Transfer Service Client module
*
* @details This is the main module of the Object Transfer Service (OTS) Client.
*/
#ifndef NRF_BLE_OTS_C_H__
#define NRF_BLE_OTS_C_H__
#include <stdint.h>
#include "ble_gattc.h"
#include "ble.h"
#include "nrf_error.h"
#include "ble_srv_common.h"
#include "ble_db_discovery.h"
#include "sdk_errors.h"
#ifdef __cplusplus
extern "C" {
#endif
/**@brief Macro for defining a ble_ots instance.
*
* @param _name Name of the instance.
* @hideinitializer
*/
#define NRF_BLE_OTS_C_DEF(_name) \
static nrf_ble_ots_c_t _name; \
NRF_SDH_BLE_OBSERVER(_name ## _ble_obs, \
BLE_OTS_C_BLE_OBSERVER_PRIO, \
nrf_ble_ots_c_on_ble_evt, &_name) \
/** @brief Macro for defining multiple ble_ots instances.
*
* @param _name Name of the array of instances.
* @param _cnt Number of instances to define.
* @hideinitializer
*/
#define NRF_BLE_OTS_C_ARRAY_DEF(_name, _cnt) \
static nrf_ble_ots_c_t _name[_cnt]; \
NRF_SDH_BLE_OBSERVERS(_name ## _ble_obs, \
BLE_OTS_C_BLE_OBSERVER_PRIO, \
nrf_ble_ots_c_on_ble_evt, &_name, _cnt)
/** @brief Types of Object Action Control Point Procedures. */
typedef enum
{
NRF_BLE_OTS_C_OACP_PROC_CREATE = 0x01, //!< Create object.
NRF_BLE_OTS_C_OACP_PROC_DELETE = 0x02, //!< Delete object.
NRF_BLE_OTS_C_OACP_PROC_CALC_CHKSUM = 0x03, //!< Calculate checksum.
NRF_BLE_OTS_C_OACP_PROC_EXECUTE = 0x04, //!< Execute object.
NRF_BLE_OTS_C_OACP_PROC_READ = 0x05, //!< Read object.
NRF_BLE_OTS_C_OACP_PROC_WRITE = 0x06, //!< Write object.
NRF_BLE_OTS_C_OACP_PROC_ABORT = 0x07, //!< Abort object.
NRF_BLE_OTS_C_OACP_PROC_RESP = 0x60 //!< Procedure response.
} ble_ots_c_oacp_proc_type_t;
/** @brief Object Action Control Point return codes. */
typedef enum
{
NRF_BLE_OTS_C_OACP_RES_SUCCESS = 0x01, //!< Success.
NRF_BLE_OTS_C_OACP_RES_OPCODE_NOT_SUP = 0x02, //!< Not supported.
NRF_BLE_OTS_C_OACP_RES_INV_PARAM = 0x03, //!< Invalid parameter.
NRF_BLE_OTS_C_OACP_RES_INSUFF_RES = 0x04, //!< Insufficient resources.
NRF_BLE_OTS_C_OACP_RES_INV_OBJ = 0x05, //!< Invalid object.
NRF_BLE_OTS_C_OACP_RES_CHAN_UNAVAIL = 0x06, //!< Channel unavailable.
NRF_BLE_OTS_C_OACP_RES_UNSUP_TYPE = 0x07, //!< Unsupported procedure.
NRF_BLE_OTS_C_OACP_RES_NOT_PERMITTED = 0x08, //!< Procedure not permitted.
NRF_BLE_OTS_C_OACP_RES_OBJ_LOCKED = 0x09, //!< Object locked.
NRF_BLE_OTS_C_OACP_RES_OPER_FAILED = 0x0A //!< Operation failed.
} ble_ots_c_oacp_res_code_t;
/**@brief Type of the Object Transfer Service Client event. */
typedef enum
{
NRF_BLE_OTS_C_EVT_DISCOVERY_FAILED, //!< Event indicating that the Object Transfer Service has not been found on the peer.
NRF_BLE_OTS_C_EVT_DISCOVERY_COMPLETE, //!< Event indicating that the Object Transfer Service is present on the peer device.
NRF_BLE_OTS_C_EVT_DISCONN_COMPLETE, //!< Event indicating that the Object Transfer Service Client module finished processing the BLE_GAP_EVT_DISCONNECTED event. The application can use this event to do a cleanup related to the Object Transfer Service Client.
NRF_BLE_OTS_C_EVT_FEATURE_READ_RESP, //!< Event indicating that the feature characteristic was read. The available features of the peer will be provided in the event.
NRF_BLE_OTS_C_EVT_OACP_RESP, //!< Event indicating that a response was received (result of a write to the OACP).
NRF_BLE_OTS_C_EVT_OBJ_READ, //!< Event indicating that the Object Transfer Service Client finished reading object from the peer.
NRF_BLE_OTS_C_EVT_OBJ_WRITE, //!< Event indicating that the Object Transfer Service Client finished writing an object to the peer.
NRF_BLE_OTS_C_EVT_CHANNEL_RELEASED, //!< Event indicating that the L2CAP Connection Oriented Channel was disconnected.
NRF_BLE_OTS_C_EVT_SIZE_READ_RESP, //!< Event indicating that the object size characteristic was read.
NRF_BLE_OTS_C_EVT_PROP_READ_RESP //!< Event indicating that the object properties characteristic was read.
} nrf_ble_ots_c_evt_type_t;
/** @brief Structure to hold the features of a server. */
typedef struct
{
uint8_t oacp_create : 1;
uint8_t oacp_delete : 1;
uint8_t oacp_crc : 1;
uint8_t oacp_execute : 1;
uint8_t oacp_read : 1;
uint8_t oacp_write : 1;
uint8_t oacp_append : 1;
uint8_t oacp_truncate : 1;
uint8_t oacp_patch : 1;
uint8_t oacp_abort : 1;
uint8_t olcp_goto : 1;
uint8_t olcp_order : 1;
uint8_t olcp_req_num : 1;
uint8_t olcp_clear : 1;
} nrf_ble_ots_c_feature_t;
/**@brief Properties of an Object Transfer Service object. */
typedef union
{
struct
{
bool is_delete_permitted :1; /**< Object can be deleted. */
bool is_execute_permitted :1; /**< Object can be executed. */
bool is_read_permitted :1; /**< Object can be read. */
bool is_write_permitted :1; /**< Object can be written. */
bool is_append_permitted :1; /**< Object can be appended. */
bool is_truncate_permitted :1; /**< When writing using truncate mode, and the written length is shorter than the object, the object size is decreased. */
bool is_patch_permitted :1; /**< When patching, a part of the object is replaced. */
bool is_marked :1; /**< Boolean to keep track whether the object is marked or not. */
} decoded;
uint32_t raw;
} nrf_ble_ots_c_obj_properties_t;
/**@brief Structure for holding the Object Transfer Service found during the
discovery process.
*/
typedef struct
{
ble_gattc_service_t service; //!< The Object Transfer Service holding the discovered Object Transfer Service (0x1825).
ble_gattc_char_t ots_feature_char; //!< OTS Feature (0x2ABD).
ble_gattc_char_t object_name_char; //!< Object name (0x2ABE).
ble_gattc_char_t object_type_char; //!< Object type (0x2ABF).
ble_gattc_char_t object_size_char; //!< Object size (0x2AC0).
ble_gattc_char_t object_prop_char; //!< Object properties (0x2AC4).
ble_gattc_char_t object_action_cp_char; //!< Object action control point (0x2AC5).
ble_gattc_desc_t object_action_cp_cccd; //!< Object action control point descriptor. Enables or disables Object Transfer notifications.
} nrf_ble_ots_c_service_t;
/** @brief Structure to hold responses received when writing to the Object Action Control Point on the server. */
typedef struct
{
ble_ots_c_oacp_proc_type_t request_op_code;
ble_ots_c_oacp_res_code_t result_code;
} nrf_ble_ots_c_oacp_response_t;
/** @brief Structure to hold the size of the object on the server when read from the Object Size characteristic on the server. */
typedef struct
{
uint32_t current_size;
uint32_t allocated_size;
} nrf_ble_ots_c_obj_size;
/**@brief Structure containing the event from the Object Transfer client module to the application.
*/
typedef struct
{
nrf_ble_ots_c_evt_type_t evt_type; /**< Type of event. See @ref nrf_ble_ots_c_evt_type_t. */
uint16_t conn_handle; /**< Handle of the connection for which this event has occurred. */
union
{
nrf_ble_ots_c_feature_t feature; /**< Will be provided if the event type is @ref NRF_BLE_OTS_C_EVT_FEATURE_READ_RESP.*/
nrf_ble_ots_c_service_t handles; /**< Handles that the Object Transfer service occupies in the peer device. Will be filled if the event type is @ref NRF_BLE_OTS_C_EVT_DISCOVERY_COMPLETE.*/
nrf_ble_ots_c_oacp_response_t response; /**< Will be provided if the event type is @ref NRF_BLE_OTS_C_EVT_OACP_RESP. */
ble_data_t object; /**< Will be provided if the event type is @ref NRF_BLE_OTS_C_EVT_OBJ_READ. */
nrf_ble_ots_c_obj_size size; /**< Will be provided if the event type is @ref NRF_BLE_OTS_C_EVT_SIZE_READ_RESP. */
nrf_ble_ots_c_obj_properties_t prop; /**< Will be provided if the eevnt type is @ref NRF_BLE_OTS_C_EVT_PROP_READ_RESP. */
} params;
} nrf_ble_ots_c_evt_t;
/**@brief Object Transfer handler type. */
typedef void (* nrf_ble_ots_c_evt_handler_t)(nrf_ble_ots_c_evt_t * p_evt);
/**@brief Structure for holding the information related to the Object Transfer Service.
@warning This structure must be zero-initialized.
*/
typedef struct
{
bool initialized; /**< Boolean telling whether the context was initialized or not. */
uint16_t conn_handle; /**< Active connection handle. */
nrf_ble_ots_c_service_t service; /**< Structure to store the different handles and UUIDs related to the service. */
nrf_ble_ots_c_evt_handler_t evt_handler; /**< Pointer to event handler function. */
ble_srv_error_handler_t err_handler; /**< Pointer to error handler function. */
nrf_ble_gq_req_error_cb_t gatt_err_handler; /**< Error handler to be called in case of an error from the SoftDevice. */
uint16_t local_cid; /**< Connection ID of the current connection. */
ble_l2cap_evt_ch_setup_t ch_setup; /**< Parameters of the L2CAP Channel Setup Completed event. */
uint32_t transmitted_bytes; /**< Variable used when transferring an object to the peer. */
uint32_t received_bytes; /**< Variable used when transferring an object from the peer. */
ble_data_t * current_obj; /**< Pointer to the current object to be transferred. */
nrf_ble_gq_t * p_gatt_queue; /**< Pointer to the BLE GATT Queue instance. */
} nrf_ble_ots_c_t;
/**@brief Initialization parameters. These must be supplied when calling @ref nrf_ble_ots_c_init. */
typedef struct
{
nrf_ble_ots_c_evt_handler_t evt_handler; /**< The event handler that is called by the Object Transfer client module when any related event occurs. */
ble_srv_error_handler_t err_handler; /**< The error handler that is called by the Object Transfer client module if any error occurs. */
nrf_ble_gq_t * p_gatt_queue; /**< Pointer to the BLE GATT Queue instance. */
} nrf_ble_ots_c_init_t;
/**@brief Function for initializing the Object Transfer client module.
@param[in,out] p_ots_c Pointer to the Object Transfer Service client structure instance.
@param[in] p_ots_c_init Init parameters that contain the event handler that is called
by the Object Transfer client module when any related event occurs.
@retval NRF_SUCCESS If the service was initialized successfully.
@retval NRF_ERROR_NULL If any of the input parameters are NULL.
@retval err_code If functions from other modules return errors to this function,
the @ref nrf_error are propagated.
*/
ret_code_t nrf_ble_ots_c_init(nrf_ble_ots_c_t * p_ots_c,
nrf_ble_ots_c_init_t * p_ots_c_init);
/**@brief Function for handling events from the Database Discovery module.
@details This function handles an event from the Database Discovery module, and determines
whether it relates to the discovery of Object Transfer Service at the peer. If it does,
the function calls the application's event handler to indicate that Object Transfer Service
has been discovered at the peer.
@param[in,out] p_ots_c Pointer to the Object Transfer Service client structure instance.
@param[in] p_evt Pointer to the event received from the Database Discovery module.
*/
void nrf_ble_ots_c_on_db_disc_evt(nrf_ble_ots_c_t const * const p_ots_c,
ble_db_discovery_evt_t * const p_evt);
/**@brief Function for reading the features characteristic (@ref BLE_UUID_OTS_FEATURES) on the server.
@param[in,out] p_ots_c Pointer to Object Transfer Client structure.
@retval NRF_SUCCESS Operation success.
@retval err_code Otherwise, this API propagates the error code returned by function @ref nrf_ble_gq_item_add.
*/
ret_code_t nrf_ble_ots_c_feature_read(nrf_ble_ots_c_t * const p_ots_c);
/**@brief Function for reading the Object Size characteristic (@ref BLE_UUID_OTS_FEATURES) on the server.
@param[in,out] p_ots_c Pointer to Object Transfer Client structure.
@retval NRF_SUCCESS Operation success.
@retval NRF_ERROR_INVALID_STATE If the Object Size characteristic has not been discovered.
@retval err_code Otherwise, this API propagates the error code returned by function @ref nrf_ble_gq_item_add.
*/
ret_code_t nrf_ble_ots_c_obj_size_read(nrf_ble_ots_c_t * const p_ots_c);
/**@brief Function for reading the Object properties (@ref BLE_UUID_OTS_OBJECT_PROPERTIES) on the server.
@param[in,out] p_ots_c Pointer to Object Transfer Client structure.
@retval NRF_SUCCESS Operation success.
@retval NRF_ERROR_INVALID_STATE If the Object Properties characteristic has not been discovered.
@retval err_code Otherwise, this API propagates the error code returned by function @ref nrf_ble_gq_item_add.
*/
ret_code_t nrf_ble_ots_c_obj_properties_read(nrf_ble_ots_c_t * const p_ots_c);
/**@brief Function for handling the Application's BLE Stack events.
@param[in] p_ble_evt Pointer to the BLE event received.
@param[in,out] p_context Pointer to the Object Transfer Service client structure instance.
*/
void nrf_ble_ots_c_on_ble_evt(const ble_evt_t * const p_ble_evt, void * p_context);
ret_code_t nrf_ble_ots_c_obj_name_read(nrf_ble_ots_c_t * const p_ots_c, ble_data_t * p_obj);
ret_code_t nrf_ble_ots_c_obj_name_write(nrf_ble_ots_c_t * const p_ots_c, ble_data_t * p_obj);
ret_code_t nrf_ble_ots_c_obj_type_read(nrf_ble_ots_c_t * const p_ots_c);
/**@brief Function for assigning handles to an Object Transfer Service Client instance.
@details Call this function when a link has been established with a peer to
associate the link to an instance of the module. This makes it
possible to handle several links and associate each link to a particular
instance of the Object Transfer Service Client module. The connection handle and
attribute handles are provided from the discovery event
@ref NRF_BLE_OTS_C_EVT_DISCOVERY_COMPLETE.
@param[in,out] p_ots_c Pointer to the Object Transfer Service Client structure instance for associating the link.
@param[in] conn_handle Connection handle to be associated with the given Object Transfer Service Client
instance.
@param[in] p_peer_handles Attribute handles on the Object Transfer Service server that you want this
Object Transfer Service client to interact with.
@retval NRF_SUCCESS If the connection handle was successfully stored in the Object Transfer Service instance.
@retval NRF_ERROR_NULL If any of the input parameters are NULL.
@retval err_code Otherwise, this API propagates the error code returned by function
@ref nrf_ble_gq_conn_handle_register.
*/
ret_code_t nrf_ble_ots_c_handles_assign(nrf_ble_ots_c_t * const p_ots_c,
uint16_t const conn_handle,
nrf_ble_ots_c_service_t const * const p_peer_handles);
#endif // NRF_BLE_OTS_C_H__
/** @} */

View File

@@ -0,0 +1,302 @@
/**
* Copyright (c) 2017 - 2020, 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 "sdk_common.h"
#if NRF_MODULE_ENABLED(BLE_OTS_C_L2CAP)
#include <stdlib.h>
#include "nrf_ble_ots_c.h"
#include "nrf_ble_ots_c_oacp.h"
#include "nrf_ble_ots_c_l2cap.h"
#include "ble.h"
#define NRF_LOG_MODULE_NAME ble_ots_c_l2cap
#include "nrf_log.h"
NRF_LOG_MODULE_REGISTER();
#include "sdk_common.h"
#define MODULE_INITIALIZED (p_ots_c->initialized) /**< Macro designating whether the module has been initialized properly. */
/**@brief Function for handling the BLE_L2CAP_EVT_CH_SETUP event.
*
* @param[in] p_ots_c Object Transfer Service Instance.
* @param[in] p_ble_evt Pointer to the event received from BLE stack.
*/
static void on_l2cap_ch_setup_complete(nrf_ble_ots_c_t * const p_ots_c,
ble_evt_t const * const p_ble_evt)
{
p_ots_c->local_cid = p_ble_evt->evt.l2cap_evt.local_cid;
p_ots_c->ch_setup.tx_params.peer_mps = p_ble_evt->evt.l2cap_evt.params.ch_setup.tx_params.peer_mps;
p_ots_c->ch_setup.tx_params.tx_mtu = p_ble_evt->evt.l2cap_evt.params.ch_setup.tx_params.tx_mtu;
p_ots_c->ch_setup.tx_params.credits = p_ble_evt->evt.l2cap_evt.params.ch_setup.tx_params.credits;
}
/**@brief This function sends the next MTU of the object.
*
* @param[in] p_ots_c Object Transfer Service Instance.
*/
static void send_resume(nrf_ble_ots_c_t * const p_ots_c)
{
ret_code_t err_code;
uint16_t tx_size;
tx_size = MIN((p_ots_c->current_obj->len - p_ots_c->transmitted_bytes),
p_ots_c->ch_setup.tx_params.tx_mtu);
ble_data_t obj;
obj.len = tx_size;
obj.p_data = &p_ots_c->current_obj->p_data[p_ots_c->transmitted_bytes];
err_code = sd_ble_l2cap_ch_tx(p_ots_c->conn_handle, p_ots_c->local_cid, &obj);
if (err_code == NRF_ERROR_RESOURCES)
{
return; // Too many SDUs queued for transmission, the transmission will be tried again on the next BLE_L2CAP_EVT_CH_TX event.
}
if(err_code != NRF_SUCCESS && p_ots_c->err_handler != NULL)
{
p_ots_c->err_handler(err_code);
}
}
/**@brief This function receives the next of the object.
*
* @param[in] p_ots_c Object Transfer Service Instance.
*/
static void receive_resume(nrf_ble_ots_c_t * const p_ots_c)
{
ret_code_t err_code;
ble_data_t sdu_buf;
sdu_buf.p_data = &p_ots_c->current_obj->p_data[p_ots_c->received_bytes];
sdu_buf.len = p_ots_c->current_obj->len - p_ots_c->received_bytes;
err_code = sd_ble_l2cap_ch_rx(p_ots_c->conn_handle,
p_ots_c->local_cid,
&sdu_buf);
if (err_code == NRF_ERROR_RESOURCES)
{
return; // Too many SDUs queued for transmission, the transmission will be tried again on the next BLE_L2CAP_EVT_CH_RX event.
}
if(err_code != NRF_SUCCESS && p_ots_c->err_handler != NULL)
{
p_ots_c->err_handler(err_code);
}
}
/**@brief Function for handling the BLE_L2CAP_EVT_CH_TX event.
*
* @param[in] p_ots_c Object Transfer Service Instance.
* @param[in] p_ble_evt Pointer to the event received from BLE stack.
*/
static void on_l2cap_ch_tx(nrf_ble_ots_c_t * const p_ots_c, ble_evt_t const * const p_ble_evt)
{
if(p_ots_c->local_cid != p_ble_evt->evt.l2cap_evt.local_cid)
{
return;
}
NRF_LOG_DEBUG("Bytes sent in the previous PDU: %i",
p_ble_evt->evt.l2cap_evt.params.tx.sdu_buf.len);
NRF_LOG_HEXDUMP_DEBUG(p_ble_evt->evt.l2cap_evt.params.tx.sdu_buf.p_data,
p_ble_evt->evt.l2cap_evt.params.tx.sdu_buf.len);
p_ots_c->transmitted_bytes += p_ble_evt->evt.l2cap_evt.params.tx.sdu_buf.len;
uint16_t remaining_tx_bytes = p_ots_c->current_obj->len - p_ots_c->transmitted_bytes;
NRF_LOG_DEBUG("Total bytes transmitted: %i ",
(p_ots_c->transmitted_bytes));
NRF_LOG_DEBUG("Total bytes remaining: %i",
(remaining_tx_bytes));
if (remaining_tx_bytes == 0)
{
nrf_ble_ots_c_evt_t evt;
evt.evt_type = NRF_BLE_OTS_C_EVT_OBJ_WRITE;
evt.params.object.len = p_ots_c->current_obj->len;
evt.params.object.p_data = p_ots_c->current_obj->p_data;
p_ots_c->evt_handler(&evt);
}
else
{
send_resume(p_ots_c);
}
}
/**@brief Function for handling the BLE_L2CAP_EVT_CH_TR event.
*
* @param[in] p_ots_c Object Transfer Service Instance.
* @param[in] p_ble_evt Pointer to the event received from BLE stack.
*/
static void on_l2cap_ch_rx(nrf_ble_ots_c_t * const p_ots_c,
ble_evt_t const * const p_ble_evt)
{
if(p_ots_c->local_cid != p_ble_evt->evt.l2cap_evt.local_cid)
{
return;
}
NRF_LOG_DEBUG("Bytes received: %i", p_ble_evt->evt.l2cap_evt.params.rx.sdu_len);
NRF_LOG_HEXDUMP_DEBUG(p_ble_evt->evt.l2cap_evt.params.rx.sdu_buf.p_data,
p_ble_evt->evt.l2cap_evt.params.rx.sdu_len);
memcpy(&p_ots_c->current_obj->p_data[p_ots_c->received_bytes], //Not needed`? buffer provied
p_ble_evt->evt.l2cap_evt.params.rx.sdu_buf.p_data,
p_ble_evt->evt.l2cap_evt.params.rx.sdu_len);
p_ots_c->received_bytes += p_ble_evt->evt.l2cap_evt.params.rx.sdu_len;
uint16_t remaining_bytes = (p_ots_c->current_obj->len - p_ots_c->received_bytes);
if(remaining_bytes == 0)
{
nrf_ble_ots_c_evt_t evt;
evt.evt_type = NRF_BLE_OTS_C_EVT_OBJ_READ;
evt.params.object.len = p_ots_c->current_obj->len;
evt.params.object.p_data = p_ots_c->current_obj->p_data;
p_ots_c->evt_handler(&evt);
}
else
{
receive_resume(p_ots_c);
}
}
/**@brief Function for handling the BLE_L2CAP_EVT_CH_RELEASED event.
*
* @param[in] p_ots_c Object Transfer Service Instance.
* @param[in] p_ble_evt Pointer to the event received from BLE stack.
*/
static void on_l2cap_ch_released(nrf_ble_ots_c_t * const p_ots_c,
ble_evt_t const * const p_ble_evt)
{
nrf_ble_ots_c_evt_t evt;
evt.evt_type = NRF_BLE_OTS_C_EVT_CHANNEL_RELEASED;
p_ots_c->evt_handler(&evt);
}
ret_code_t nrf_ble_ots_c_l2cap_obj_send(nrf_ble_ots_c_t * const p_ots_c, ble_data_t * p_obj)
{
VERIFY_MODULE_INITIALIZED();
VERIFY_PARAM_NOT_NULL(p_ots_c);
VERIFY_PARAM_NOT_NULL(p_obj);
ret_code_t err_code;
uint16_t tx_size;
p_ots_c->transmitted_bytes = 0;
tx_size = MIN(p_obj->len, p_ots_c->ch_setup.tx_params.tx_mtu);
p_ots_c->current_obj = p_obj;
ble_data_t obj;
obj.len = tx_size;
obj.p_data = p_obj->p_data;
err_code = sd_ble_l2cap_ch_tx(p_ots_c->conn_handle, p_ots_c->local_cid, &obj);
return err_code;
}
ret_code_t nrf_ble_ots_c_l2cap_obj_receive(nrf_ble_ots_c_t * const p_ots_c, ble_data_t * p_obj)
{
uint32_t err_code;
p_ots_c->received_bytes = 0;
p_ots_c->current_obj = p_obj;
err_code = sd_ble_l2cap_ch_rx(p_ots_c->conn_handle,
p_ots_c->local_cid,
p_ots_c->current_obj);
return err_code;
}
void ots_c_l2cap_on_ble_evt(nrf_ble_ots_c_t * const p_ots_c,
ble_evt_t const * const p_ble_evt)
{
VERIFY_MODULE_INITIALIZED_VOID();
VERIFY_PARAM_NOT_NULL_VOID(p_ots_c);
VERIFY_PARAM_NOT_NULL_VOID(p_ble_evt);
if (p_ble_evt->evt.l2cap_evt.local_cid != p_ots_c->local_cid)
{
return;
}
switch (p_ble_evt->header.evt_id)
{
case BLE_L2CAP_EVT_CH_SETUP:
NRF_LOG_DEBUG("BLE_L2CAP_EVT_CH_SETUP");
on_l2cap_ch_setup_complete(p_ots_c, p_ble_evt);
break;
case BLE_L2CAP_EVT_CH_TX:
NRF_LOG_DEBUG("BLE_L2CAP_EVT_CH_TX");
on_l2cap_ch_tx(p_ots_c, p_ble_evt);
break;
case BLE_L2CAP_EVT_CH_RX:
NRF_LOG_DEBUG("BLE_L2CAP_EVT_CH_RX");
on_l2cap_ch_rx(p_ots_c, p_ble_evt);
break;
case BLE_L2CAP_EVT_CH_CREDIT:
NRF_LOG_DEBUG("BLE_L2CAP_EVT_CH_CREDIT");
break;
case BLE_L2CAP_EVT_CH_RELEASED:
NRF_LOG_DEBUG("BLE_L2CAP_EVT_CH_RELEASED");
on_l2cap_ch_released(p_ots_c, p_ble_evt);
break;
default:
break;
}
}
#endif // NRF_MODULE_ENABLED(BLE_OTS_C_L2CAP)

View File

@@ -0,0 +1,104 @@
/**
* Copyright (c) 2017 - 2020, 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 nrf_ble_ots_c_l2cap Object Transfer Service Client
* @{
* @ingroup nrf_ble_ots_c
* @brief Object Transfer Service client module
*
* @details This is the main module of the Object Transfer Service (OTS) client.
*/
#ifndef NRF_BLE_OTS_C_L2CAP_H__
#define NRF_BLE_OTS_C_L2CAP_H__
#include <stdint.h>
#include "ble_gattc.h"
#include "ble.h"
#include "nrf_error.h"
#include "ble_srv_common.h"
#include "ble_db_discovery.h"
#include "sdk_errors.h"
#include "nrf_ble_ots_c.h"
#ifdef __cplusplus
extern "C" {
#endif
/**@brief Function for handling the Application's BLE Stack events.
@param[in,out] p_ots_c Pointer to Object Transfer client structure.
@param[in] p_ble_evt Pointer to the BLE event received.
*/
void ots_c_l2cap_on_ble_evt(nrf_ble_ots_c_t * const p_ots_c,
ble_evt_t const * const p_ble_evt);
/**@brief Function sending an object.
@details This Function will only succeed in sending an object if the peer is in a state to
receive it. call @ref nrf_ble_ots_c_oacp_write_object before this function.
@param[in,out] p_ots_c Pointer to Object Transfer client structure.
@param[in,out] p_obj Pointer to object that will be sent to the peer.
@retval NRF_ERROR_INVALID_STATE if the Object Transfer module is not initialized.
@retval NRF_ERROR_NULL if any of the input parameters are NULL.
*/
ret_code_t nrf_ble_ots_c_l2cap_obj_send(nrf_ble_ots_c_t * const p_ots_c, ble_data_t * p_obj);
/**@brief Function for receiving an object.
@details This Function will only succeed in receiving an object if the peer is in a state to
send it. call @ref nrf_ble_ots_c_oacp_read_object before this function.
@param[in,out] p_ots_c Pointer to Object Transfer client structure.
@param[in,out] p_obj Pointer to buffer where the received data will be stored.
*/
ret_code_t nrf_ble_ots_c_l2cap_obj_receive(nrf_ble_ots_c_t * const p_ots_c, ble_data_t * p_obj);
#endif // NRF_BLE_OTS_C_L2CAP_H__
/** @} */

View File

@@ -0,0 +1,264 @@
/**
* Copyright (c) 2017 - 2020, 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 "sdk_common.h"
#if NRF_MODULE_ENABLED(BLE_OTS_C_OACP)
#include <stdlib.h>
#include "nrf_ble_ots_c_oacp.h"
#include "ble.h"
#define NRF_LOG_MODULE_NAME ble_ots_c_oacp
#include "nrf_log.h"
NRF_LOG_MODULE_REGISTER();
#include "sdk_common.h"
#define BLE_OTS_OACP_WRITE_OP_SIZE 10
#define BLE_OTS_OACP_READ_OP_SIZE 9
#define MODULE_INITIALIZED (p_ots_c->initialized)
static void oacp_response(nrf_ble_ots_c_t const * const p_ots_c,
ble_gattc_evt_t const * const p_ble_gattc_evt)
{
nrf_ble_ots_c_evt_t evt;
nrf_ble_ots_c_evt_handler_t evt_handler = p_ots_c->evt_handler;
/*lint --e{415} --e{416} -save suppress Warning 415: Likely access of out-of-bounds pointer */
evt.params.response.request_op_code = (ble_ots_c_oacp_proc_type_t) p_ble_gattc_evt->params.hvx.data[sizeof(uint8_t)];
evt.params.response.result_code = (ble_ots_c_oacp_res_code_t) p_ble_gattc_evt->params.hvx.data[2*sizeof(uint8_t)];
/*lint -restore*/
evt.evt_type = NRF_BLE_OTS_C_EVT_OACP_RESP;
evt.conn_handle = p_ble_gattc_evt->conn_handle;
evt_handler(&evt);
}
/**@brief Function for handling the indication and notifications from the GATT Service Server.
@param[in] p_ots_c Pointer to Object Transfer client structure.
@param[in] p_ble_gattc_evt Pointer to a GATTC event.
*/
static void on_hvx(nrf_ble_ots_c_t const * const p_ots_c,
ble_gattc_evt_t const * const p_ble_gattc_evt)
{
uint16_t oacp_handle = p_ots_c->service.object_action_cp_char.handle_value;
if ((p_ble_gattc_evt->params.hvx.handle == oacp_handle)
&& (p_ots_c->evt_handler != NULL))
{
ret_code_t err_code = sd_ble_gattc_hv_confirm(p_ble_gattc_evt->conn_handle,
oacp_handle);
if ((err_code != NRF_SUCCESS) && (p_ots_c->err_handler != NULL))
{
p_ots_c->err_handler(err_code);
}
uint8_t op_code = p_ble_gattc_evt->params.hvx.data[0];
if(op_code == NRF_BLE_OTS_C_OACP_PROC_RESP)
{
oacp_response(p_ots_c, p_ble_gattc_evt);
}
}
}
/**@brief Function for checking whether the peer's Object Transfer Service instance has been discovered.
@param[in] p_ots_c Pointer to the GATT Service Client structure instance.
@return True if the Object Transfer Service handles are valid.
@return False if the Object Transfer Service handles are invalid.
*/
static bool ots_gatt_handles_are_valid(const nrf_ble_ots_c_t * const p_ots_c)
{
return (p_ots_c->service.object_prop_char.handle_value != BLE_GATT_HANDLE_INVALID
&& p_ots_c->service.object_size_char.handle_value != BLE_GATT_HANDLE_INVALID
&& p_ots_c->service.object_type_char.handle_value != BLE_GATT_HANDLE_INVALID
&& p_ots_c->service.ots_feature_char.handle_value != BLE_GATT_HANDLE_INVALID);
}
ret_code_t nrf_ble_ots_c_indication_enable(nrf_ble_ots_c_t * const p_ots_c,
bool const indication_enable)
{
VERIFY_MODULE_INITIALIZED();
VERIFY_TRUE(ots_gatt_handles_are_valid(p_ots_c), NRF_ERROR_INVALID_STATE);
if (p_ots_c->conn_handle == BLE_CONN_HANDLE_INVALID)
{
return NRF_ERROR_INVALID_STATE;
}
uint8_t cccd[BLE_CCCD_VALUE_LEN];
nrf_ble_gq_req_t cccd_req;
uint16_t cccd_val = (indication_enable) ? BLE_GATT_HVX_INDICATION : 0;
cccd[0] = LSB_16(cccd_val);
cccd[1] = MSB_16(cccd_val);
memset(&cccd_req, 0, sizeof(nrf_ble_gq_req_t));
cccd_req.type = NRF_BLE_GQ_REQ_GATTC_WRITE;
cccd_req.error_handler.cb = p_ots_c->gatt_err_handler;
cccd_req.error_handler.p_ctx = (nrf_ble_ots_c_t *)p_ots_c;
cccd_req.params.gattc_write.handle = p_ots_c->service.object_action_cp_cccd.handle;
cccd_req.params.gattc_write.len = BLE_CCCD_VALUE_LEN;
cccd_req.params.gattc_write.offset = 0;
cccd_req.params.gattc_write.p_value = cccd;
cccd_req.params.gattc_write.write_op = BLE_GATT_OP_WRITE_REQ;
return nrf_ble_gq_item_add(p_ots_c->p_gatt_queue, &cccd_req, p_ots_c->conn_handle);
}
ret_code_t nrf_ble_ots_c_oacp_write_object(nrf_ble_ots_c_t * const p_ots_c, uint32_t offset, uint32_t len, bool truncate)
{
VERIFY_MODULE_INITIALIZED();
VERIFY_TRUE(ots_gatt_handles_are_valid(p_ots_c), NRF_ERROR_INVALID_STATE);
if (p_ots_c->conn_handle == BLE_CONN_HANDLE_INVALID)
{
return NRF_ERROR_INVALID_STATE;
}
ret_code_t err_code = NRF_SUCCESS;
uint8_t val[BLE_OTS_OACP_WRITE_OP_SIZE];
memset(val, 0, sizeof(val));
uint32_t i = 0;
// OP Code
val[i++] = NRF_BLE_OTS_C_OACP_PROC_WRITE;
//Offset
i += uint32_encode(offset, &val[i]);
//Len
i += uint32_encode(len, &val[i]);
val[i] |= (truncate << 0);
nrf_ble_gq_req_t write_req;
memset(&write_req, 0, sizeof(nrf_ble_gq_req_t));
write_req.type = NRF_BLE_GQ_REQ_GATTC_WRITE;
write_req.error_handler.cb = p_ots_c->gatt_err_handler;
write_req.error_handler.p_ctx = (nrf_ble_ots_c_t *)p_ots_c;
write_req.params.gattc_write.handle = p_ots_c->service.object_action_cp_char.handle_value;
write_req.params.gattc_write.len = i;
write_req.params.gattc_write.offset = 0;
write_req.params.gattc_write.p_value = val;
write_req.params.gattc_write.write_op = BLE_GATT_OP_WRITE_REQ;
err_code = nrf_ble_gq_item_add(p_ots_c->p_gatt_queue, &write_req, p_ots_c->conn_handle);
if(err_code != NRF_SUCCESS)
{
p_ots_c->err_handler(err_code);
}
return err_code;
}
ret_code_t nrf_ble_ots_c_oacp_read_object(nrf_ble_ots_c_t * const p_ots_c, uint32_t offset, uint32_t len)
{
VERIFY_MODULE_INITIALIZED();
VERIFY_TRUE(ots_gatt_handles_are_valid(p_ots_c), NRF_ERROR_INVALID_STATE);
if (p_ots_c->conn_handle == BLE_CONN_HANDLE_INVALID)
{
return NRF_ERROR_INVALID_STATE;
}
uint8_t val[BLE_OTS_OACP_READ_OP_SIZE];
memset(val, 0, sizeof(val));
uint32_t i = 0;
// OP Code
val[i++] = NRF_BLE_OTS_C_OACP_PROC_READ;
//Offset
i += uint32_encode(offset, &val[i]);
//Len
i += uint32_encode(len, &val[i]);
nrf_ble_gq_req_t write_req;
memset(&write_req, 0, sizeof(nrf_ble_gq_req_t));
write_req.type = NRF_BLE_GQ_REQ_GATTC_WRITE;
write_req.error_handler.cb = p_ots_c->gatt_err_handler;
write_req.error_handler.p_ctx = (nrf_ble_ots_c_t *)p_ots_c;
write_req.params.gattc_write.handle = p_ots_c->service.object_action_cp_char.handle_value;
write_req.params.gattc_write.len = sizeof(val);
write_req.params.gattc_write.offset = 0;
write_req.params.gattc_write.p_value = val;
write_req.params.gattc_write.write_op = BLE_GATT_OP_WRITE_REQ;
return nrf_ble_gq_item_add(p_ots_c->p_gatt_queue, &write_req, p_ots_c->conn_handle);
}
void ots_c_oacp_on_ble_evt(nrf_ble_ots_c_t * const p_ots_c,
ble_evt_t const * const p_ble_evt)
{
VERIFY_MODULE_INITIALIZED_VOID();
VERIFY_PARAM_NOT_NULL_VOID(p_ots_c);
VERIFY_PARAM_NOT_NULL_VOID(p_ble_evt);
switch (p_ble_evt->header.evt_id)
{
case BLE_GATTC_EVT_HVX:
on_hvx(p_ots_c, &(p_ble_evt->evt.gattc_evt));
break;
default:
break;
}
}
#endif // NRF_MODULE_ENABLED(BLE_OTS_C)

View File

@@ -0,0 +1,124 @@
/**
* Copyright (c) 2016 - 2020, 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 nrf_ble_ots_c_oacp Object Transfer Service Client Object Action Control Point
* @{
* @ingroup nrf_ble_ots_c
* @brief Object Action Control Point module
*
* @details This is the Object Action Control Point module of the Object Transfer Service (OTS) Client.
*/
#ifndef NRF_BLE_OTS_C_OACP_H__
#define NRF_BLE_OTS_C_OACP_H__
#include <stdint.h>
#include "ble_gattc.h"
#include "ble.h"
#include "nrf_error.h"
#include "ble_srv_common.h"
#include "ble_db_discovery.h"
#include "sdk_errors.h"
#include "nrf_ble_ots_c.h"
#ifdef __cplusplus
extern "C" {
#endif
/**@brief Function for enabling remote indication.
@param[in,out] p_ots_c Pointer to Object Transfer Client structure.
@param[in] enable True to enable Object Action Control Point (OACP) indication; false to disable.
@retval NRF_SUCCESS Operation success.
@retval err_code If functions from other modules return errors to this function,
the @ref nrf_error are propagated.
*/
ret_code_t nrf_ble_ots_c_indication_enable(nrf_ble_ots_c_t * const p_ots_c,
bool const enable);
/**@brief Function for requesting a write of an object.
@details This function informs the peer about the length of the object to write.
(The object itself is not written by this function.)
The peer indicates a response on the Object Action Control Point.
If the write is accepted (the event NRF_BLE_OTS_C_OACP_RES_SUCCESS ), an object can be
transfered with @ref nrf_ble_ots_c_l2cap_obj_send.
@param[in,out] p_ots_c Pointer to Object Transfer Client structure.
@param[in] offset Offset of the write.
@param[in] len Length of the object to write.
@param[in] truncate True to let the write truncate on the object.
@retval NRF_SUCCESS Operation success.
@retval NRF_ERROR_INVALID_STATE Module is not initialized, or the handles of the peer OACP
are invalid.
@retval err_code Otherwise, this API propagates the error code returned by functions: @ref nrf_ble_gq_item_add.
*/
ret_code_t nrf_ble_ots_c_oacp_write_object(nrf_ble_ots_c_t * const p_ots_c, uint32_t offset, uint32_t len, bool truncate);
/**@brief Function for requesting a read of an object.
@param[in,out] p_ots_c Pointer to Object Transfer Client structure.
@param[in] offset Offset of the read.
@param[in] len Length of the read.
@retval NRF_SUCCESS Operation success.
@return Otherwise this API propagates the error code returned by functions: @ref nrf_ble_gq_item_add.
*/
ret_code_t nrf_ble_ots_c_oacp_read_object(nrf_ble_ots_c_t * const p_ots_c, uint32_t offset, uint32_t len);
/**@brief Function for handling the Application's BLE Stack events.
@param[in,out] p_ots_c Pointer to Object Transfer client structure.
@param[in] p_ble_evt Pointer to the BLE event received.
*/
void ots_c_oacp_on_ble_evt(nrf_ble_ots_c_t * const p_ots_c,
ble_evt_t const * const p_ble_evt);
#endif // NRF_BLE_OTS_C_OACP_H__
/** @} */