初始版本
This commit is contained in:
813
components/ble/ble_advertising/ble_advertising.c
Normal file
813
components/ble/ble_advertising/ble_advertising.c
Normal file
@@ -0,0 +1,813 @@
|
||||
/**
|
||||
* Copyright (c) 2015 - 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_ADVERTISING)
|
||||
#include "ble_advdata.h"
|
||||
#include "ble_advertising.h"
|
||||
#include "nrf_soc.h"
|
||||
#include "nrf_log.h"
|
||||
#include "sdk_errors.h"
|
||||
#include "nrf_sdh_ble.h"
|
||||
|
||||
#define BLE_ADV_MODES (5) /**< Total number of possible advertising modes. */
|
||||
|
||||
|
||||
/**@brief Function for checking if the whitelist is in use.
|
||||
*
|
||||
* @param[in] p_advertising Advertising module instance.
|
||||
*/
|
||||
static bool whitelist_has_entries(ble_advertising_t * const p_advertising)
|
||||
{
|
||||
return p_advertising->whitelist_in_use;
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for checking if an address is valid.
|
||||
*
|
||||
* @param[in] p_addr Pointer to a bluetooth address.
|
||||
*/
|
||||
static bool addr_is_valid(uint8_t const * const p_addr)
|
||||
{
|
||||
for (uint32_t i = 0; i < BLE_GAP_ADDR_LEN; i++)
|
||||
{
|
||||
if (p_addr[i] != 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for checking the next advertising mode.
|
||||
*
|
||||
* @param[in] adv_mode Current advertising mode.
|
||||
*/
|
||||
static ble_adv_mode_t adv_mode_next_get(ble_adv_mode_t adv_mode)
|
||||
{
|
||||
return (ble_adv_mode_t)((adv_mode + 1) % BLE_ADV_MODES);
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling the Connected event.
|
||||
*
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
*/
|
||||
static void on_connected(ble_advertising_t * const p_advertising, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
if (p_ble_evt->evt.gap_evt.params.connected.role == BLE_GAP_ROLE_PERIPH)
|
||||
{
|
||||
p_advertising->current_slave_link_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling the Disconnected event.
|
||||
*
|
||||
* @param[in] p_advertising Advertising module instance.
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
*/
|
||||
static void on_disconnected(ble_advertising_t * const p_advertising, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
p_advertising->whitelist_temporarily_disabled = false;
|
||||
|
||||
if (p_ble_evt->evt.gap_evt.conn_handle == p_advertising->current_slave_link_conn_handle &&
|
||||
p_advertising->adv_modes_config.ble_adv_on_disconnect_disabled == false)
|
||||
{
|
||||
ret = ble_advertising_start(p_advertising, BLE_ADV_MODE_DIRECTED_HIGH_DUTY);
|
||||
if ((ret != NRF_SUCCESS) && (p_advertising->error_handler != NULL))
|
||||
{
|
||||
p_advertising->error_handler(ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling the Timeout event.
|
||||
*
|
||||
* @param[in] p_advertising Advertising module instance.
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
*/
|
||||
static void on_terminated(ble_advertising_t * const p_advertising, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
ret_code_t ret;
|
||||
|
||||
if (p_ble_evt->header.evt_id != BLE_GAP_EVT_ADV_SET_TERMINATED)
|
||||
{
|
||||
// Nothing to do.
|
||||
return;
|
||||
}
|
||||
|
||||
if ( p_ble_evt->evt.gap_evt.params.adv_set_terminated.reason == BLE_GAP_EVT_ADV_SET_TERMINATED_REASON_TIMEOUT
|
||||
||p_ble_evt->evt.gap_evt.params.adv_set_terminated.reason == BLE_GAP_EVT_ADV_SET_TERMINATED_REASON_LIMIT_REACHED)
|
||||
{
|
||||
// Start advertising in the next mode.
|
||||
ret = ble_advertising_start(p_advertising, adv_mode_next_get(p_advertising->adv_mode_current));
|
||||
|
||||
if ((ret != NRF_SUCCESS) && (p_advertising->error_handler != NULL))
|
||||
{
|
||||
p_advertising->error_handler(ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Get the next available advertising mode.
|
||||
*
|
||||
* @param[in] p_advertising Advertising module instance.
|
||||
* @param[in] adv_mode Requested advertising mode.
|
||||
*
|
||||
* @returns adv_mode if possible, or the best available mode if not.
|
||||
*/
|
||||
static ble_adv_mode_t adv_mode_next_avail_get(ble_advertising_t * const p_advertising,
|
||||
ble_adv_mode_t adv_mode)
|
||||
{
|
||||
bool peer_addr_is_valid = addr_is_valid(p_advertising->peer_address.addr);
|
||||
|
||||
// If a mode is disabled, continue to the next mode.
|
||||
|
||||
switch (adv_mode)
|
||||
{
|
||||
case BLE_ADV_MODE_DIRECTED_HIGH_DUTY:
|
||||
if ( (p_advertising->adv_modes_config.ble_adv_directed_high_duty_enabled)
|
||||
&& (!p_advertising->adv_modes_config.ble_adv_extended_enabled)
|
||||
&& (peer_addr_is_valid))
|
||||
{
|
||||
return BLE_ADV_MODE_DIRECTED_HIGH_DUTY;
|
||||
}
|
||||
// Fallthrough.
|
||||
|
||||
case BLE_ADV_MODE_DIRECTED:
|
||||
if ((p_advertising->adv_modes_config.ble_adv_directed_enabled) && peer_addr_is_valid)
|
||||
{
|
||||
return BLE_ADV_MODE_DIRECTED;
|
||||
}
|
||||
// Fallthrough.
|
||||
|
||||
case BLE_ADV_MODE_FAST:
|
||||
if (p_advertising->adv_modes_config.ble_adv_fast_enabled)
|
||||
{
|
||||
return BLE_ADV_MODE_FAST;
|
||||
}
|
||||
// Fallthrough.
|
||||
|
||||
case BLE_ADV_MODE_SLOW:
|
||||
if (p_advertising->adv_modes_config.ble_adv_slow_enabled)
|
||||
{
|
||||
return BLE_ADV_MODE_SLOW;
|
||||
}
|
||||
// Fallthrough.
|
||||
|
||||
default:
|
||||
return BLE_ADV_MODE_IDLE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for starting high duty directed advertising.
|
||||
*
|
||||
* @param[in] p_advertising Advertising instance.
|
||||
* @param[out] p_adv_params Advertising parameters.
|
||||
*
|
||||
* @return NRF_SUCCESS
|
||||
*/
|
||||
static ret_code_t set_adv_mode_directed_high_duty(ble_advertising_t * const p_advertising,
|
||||
ble_gap_adv_params_t * p_adv_params)
|
||||
{
|
||||
p_advertising->adv_evt = BLE_ADV_EVT_DIRECTED_HIGH_DUTY;
|
||||
p_advertising->p_adv_data = NULL;
|
||||
|
||||
p_adv_params->p_peer_addr = &(p_advertising->peer_address);
|
||||
p_adv_params->interval = 0;
|
||||
p_adv_params->properties.type = BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED_HIGH_DUTY_CYCLE;
|
||||
p_adv_params->duration = BLE_GAP_ADV_TIMEOUT_HIGH_DUTY_MAX;
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for starting directed slow advertising.
|
||||
*
|
||||
* @param[in] p_advertising Advertising module instance.
|
||||
* @param[out] p_adv_params Advertising parameters.
|
||||
*
|
||||
* @return NRF_SUCCESS
|
||||
*/
|
||||
static ret_code_t set_adv_mode_directed(ble_advertising_t * const p_advertising,
|
||||
ble_gap_adv_params_t * p_adv_params)
|
||||
{
|
||||
p_advertising->adv_evt = BLE_ADV_EVT_DIRECTED;
|
||||
#if !defined (S112) && !defined(S312) && !defined(S113)
|
||||
if (p_advertising->adv_modes_config.ble_adv_extended_enabled)
|
||||
{
|
||||
p_adv_params->properties.type = BLE_GAP_ADV_TYPE_EXTENDED_CONNECTABLE_NONSCANNABLE_DIRECTED;
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif // !defined (S112) && !defined(S312)
|
||||
p_adv_params->properties.type = BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED;
|
||||
#if !defined (S112) && !defined(S312) && !defined(S113)
|
||||
}
|
||||
#endif // !defined (S112) && !defined(S312) && !defined(S113)
|
||||
p_adv_params->duration = p_advertising->adv_modes_config.ble_adv_directed_timeout;
|
||||
|
||||
p_advertising->p_adv_data = NULL;
|
||||
|
||||
p_adv_params->p_peer_addr = &p_advertising->peer_address;
|
||||
p_adv_params->interval = p_advertising->adv_modes_config.ble_adv_directed_interval;
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for indicating whether to use whitelist for advertising.
|
||||
*
|
||||
* @param[in] p_advertising Advertising module instance.
|
||||
*
|
||||
* @return Whether to use whitelist.
|
||||
*/
|
||||
static bool use_whitelist(ble_advertising_t * const p_advertising)
|
||||
{
|
||||
return((p_advertising->adv_modes_config.ble_adv_whitelist_enabled) &&
|
||||
(!p_advertising->whitelist_temporarily_disabled) &&
|
||||
(whitelist_has_entries(p_advertising)));
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for setting new advertising flags in the advertising parameters.
|
||||
*
|
||||
* @param[in] p_advertising Advertising module instance.
|
||||
* @param[in] flags New flags.
|
||||
*
|
||||
* @return Any error from @ref sd_ble_gap_adv_set_configure.
|
||||
*/
|
||||
static ret_code_t flags_set(ble_advertising_t * const p_advertising, uint8_t flags)
|
||||
{
|
||||
uint8_t * p_flags = ble_advdata_parse(p_advertising->adv_data.adv_data.p_data,
|
||||
p_advertising->adv_data.adv_data.len,
|
||||
BLE_GAP_AD_TYPE_FLAGS);
|
||||
|
||||
if (p_flags != NULL)
|
||||
{
|
||||
*p_flags = flags;
|
||||
}
|
||||
|
||||
return sd_ble_gap_adv_set_configure(&p_advertising->adv_handle, &p_advertising->adv_data, &p_advertising->adv_params);
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for starting fast advertising.
|
||||
*
|
||||
* @param[in] p_advertising Advertising module instance.
|
||||
* @param[out] p_adv_params Advertising parameters.
|
||||
*
|
||||
* @return NRF_SUCCESS or an error from @ref flags_set().
|
||||
*/
|
||||
static ret_code_t set_adv_mode_fast(ble_advertising_t * const p_advertising,
|
||||
ble_gap_adv_params_t * p_adv_params)
|
||||
{
|
||||
ret_code_t ret;
|
||||
|
||||
p_adv_params->interval = p_advertising->adv_modes_config.ble_adv_fast_interval;
|
||||
p_adv_params->duration = p_advertising->adv_modes_config.ble_adv_fast_timeout;
|
||||
|
||||
#if !defined (S112) && !defined(S312) && !defined(S113)
|
||||
if (p_advertising->adv_modes_config.ble_adv_extended_enabled)
|
||||
{
|
||||
p_advertising->adv_params.properties.type = BLE_GAP_ADV_TYPE_EXTENDED_CONNECTABLE_NONSCANNABLE_UNDIRECTED;
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif // !defined (S112) && !defined(S312) && !defined(S113)
|
||||
p_advertising->adv_params.properties.type = BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED;
|
||||
#if !defined (S112) && !defined(S312) && !defined(S113)
|
||||
}
|
||||
#endif // !defined (S112) && !defined(S312) && !defined(S113)
|
||||
|
||||
if (use_whitelist(p_advertising))
|
||||
{
|
||||
p_adv_params->filter_policy = BLE_GAP_ADV_FP_FILTER_CONNREQ;
|
||||
|
||||
// Set correct flags.
|
||||
ret = flags_set(p_advertising, BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED);
|
||||
VERIFY_SUCCESS(ret);
|
||||
|
||||
p_advertising->adv_evt = BLE_ADV_EVT_FAST_WHITELIST;
|
||||
}
|
||||
else
|
||||
{
|
||||
p_advertising->adv_evt = BLE_ADV_EVT_FAST;
|
||||
}
|
||||
p_advertising->p_adv_data = &(p_advertising->adv_data);
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for starting slow advertising.
|
||||
*
|
||||
* @param[in] p_advertising Advertising module instance.
|
||||
* @param[out] p_adv_params Advertising parameters.
|
||||
*
|
||||
* @return NRF_SUCCESS or an error from @ref flags_set().
|
||||
*/
|
||||
static ret_code_t set_adv_mode_slow(ble_advertising_t * const p_advertising,
|
||||
ble_gap_adv_params_t * p_adv_params)
|
||||
{
|
||||
ret_code_t ret;
|
||||
|
||||
p_adv_params->interval = p_advertising->adv_modes_config.ble_adv_slow_interval;
|
||||
p_adv_params->duration = p_advertising->adv_modes_config.ble_adv_slow_timeout;
|
||||
|
||||
#if !defined (S112) && !defined(S312) && !defined(S113)
|
||||
if (p_advertising->adv_modes_config.ble_adv_extended_enabled)
|
||||
{
|
||||
p_advertising->adv_params.properties.type = BLE_GAP_ADV_TYPE_EXTENDED_CONNECTABLE_NONSCANNABLE_UNDIRECTED;
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif // !defined (S112) && !defined(S312) && !defined(S113)
|
||||
p_advertising->adv_params.properties.type = BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED;
|
||||
#if !defined (S112) && !defined(S312) && !defined(S113)
|
||||
}
|
||||
#endif // !defined (S112) && !defined(S312) && !defined(S113)
|
||||
|
||||
if (use_whitelist(p_advertising))
|
||||
{
|
||||
p_adv_params->filter_policy = BLE_GAP_ADV_FP_FILTER_CONNREQ;
|
||||
|
||||
// Set correct flags.
|
||||
ret = flags_set(p_advertising, BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED);
|
||||
VERIFY_SUCCESS(ret);
|
||||
|
||||
p_advertising->adv_evt = BLE_ADV_EVT_SLOW_WHITELIST;
|
||||
}
|
||||
else
|
||||
{
|
||||
p_advertising->adv_evt = BLE_ADV_EVT_SLOW;
|
||||
}
|
||||
p_advertising->p_adv_data = &(p_advertising->adv_data);
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for checking if an advertising module configuration is legal.
|
||||
*
|
||||
* @details Advertising module can not be initialized if high duty directed advertising is used
|
||||
* together with extended advertising.
|
||||
*
|
||||
* @param[in] p_config Pointer to the configuration.
|
||||
*
|
||||
* @return True If the configuration is valid.
|
||||
* @return False If the configuration is invalid.
|
||||
*/
|
||||
static bool config_is_valid(ble_adv_modes_config_t const * const p_config)
|
||||
{
|
||||
if ((p_config->ble_adv_directed_high_duty_enabled == true) &&
|
||||
(p_config->ble_adv_extended_enabled == true))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#if !defined (S140)
|
||||
else if ( p_config->ble_adv_primary_phy == BLE_GAP_PHY_CODED ||
|
||||
p_config->ble_adv_secondary_phy == BLE_GAP_PHY_CODED)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif // !defined (S140)
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for getting the maximum size of the advertising data buffer.
|
||||
*
|
||||
* @param[in] p_advertising Advertising module instance.
|
||||
*
|
||||
* @returns The maximum size of the advertising data buffer.
|
||||
*/
|
||||
static uint16_t adv_set_data_size_max_get(ble_advertising_t const * const p_advertising)
|
||||
{
|
||||
uint16_t adv_set_data_size_max;
|
||||
|
||||
if (p_advertising->adv_modes_config.ble_adv_extended_enabled == true)
|
||||
{
|
||||
#ifdef BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_CONNECTABLE_MAX_SUPPORTED
|
||||
adv_set_data_size_max = BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_CONNECTABLE_MAX_SUPPORTED;
|
||||
#else
|
||||
adv_set_data_size_max = BLE_GAP_ADV_SET_DATA_SIZE_MAX;
|
||||
#endif // BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_CONNECTABLE_MAX_SUPPORTED
|
||||
}
|
||||
else
|
||||
{
|
||||
adv_set_data_size_max = BLE_GAP_ADV_SET_DATA_SIZE_MAX;
|
||||
}
|
||||
|
||||
return adv_set_data_size_max;
|
||||
}
|
||||
|
||||
|
||||
void ble_advertising_conn_cfg_tag_set(ble_advertising_t * const p_advertising,
|
||||
uint8_t ble_cfg_tag)
|
||||
{
|
||||
p_advertising->conn_cfg_tag = ble_cfg_tag;
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_advertising_init(ble_advertising_t * const p_advertising,
|
||||
ble_advertising_init_t const * const p_init)
|
||||
{
|
||||
uint32_t ret;
|
||||
if ((p_init == NULL) || (p_advertising == NULL))
|
||||
{
|
||||
return NRF_ERROR_NULL;
|
||||
}
|
||||
if (!config_is_valid(&p_init->config))
|
||||
{
|
||||
return NRF_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
p_advertising->adv_mode_current = BLE_ADV_MODE_IDLE;
|
||||
p_advertising->adv_modes_config = p_init->config;
|
||||
p_advertising->conn_cfg_tag = BLE_CONN_CFG_TAG_DEFAULT;
|
||||
p_advertising->evt_handler = p_init->evt_handler;
|
||||
p_advertising->error_handler = p_init->error_handler;
|
||||
p_advertising->current_slave_link_conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
p_advertising->p_adv_data = &p_advertising->adv_data;
|
||||
|
||||
memset(&p_advertising->peer_address, 0, sizeof(p_advertising->peer_address));
|
||||
|
||||
// Copy advertising data.
|
||||
if (!p_advertising->initialized)
|
||||
{
|
||||
p_advertising->adv_handle = BLE_GAP_ADV_SET_HANDLE_NOT_SET;
|
||||
}
|
||||
p_advertising->adv_data.adv_data.p_data = p_advertising->enc_advdata[0];
|
||||
p_advertising->adv_data.adv_data.len = adv_set_data_size_max_get(p_advertising);
|
||||
|
||||
ret = ble_advdata_encode(&p_init->advdata, p_advertising->enc_advdata[0], &p_advertising->adv_data.adv_data.len);
|
||||
VERIFY_SUCCESS(ret);
|
||||
|
||||
p_advertising->adv_data.scan_rsp_data.p_data = p_advertising->enc_scan_rsp_data[0];
|
||||
p_advertising->adv_data.scan_rsp_data.len = adv_set_data_size_max_get(p_advertising);
|
||||
|
||||
ret = ble_advdata_encode(&p_init->srdata,
|
||||
p_advertising->adv_data.scan_rsp_data.p_data,
|
||||
&p_advertising->adv_data.scan_rsp_data.len);
|
||||
VERIFY_SUCCESS(ret);
|
||||
|
||||
// Configure a initial advertising configuration. The advertising data and and advertising
|
||||
// parameters will be changed later when we call @ref ble_advertising_start, but must be set
|
||||
// to legal values here to define an advertising handle.
|
||||
p_advertising->adv_params.primary_phy = BLE_GAP_PHY_1MBPS;
|
||||
p_advertising->adv_params.duration = p_advertising->adv_modes_config.ble_adv_fast_timeout;
|
||||
p_advertising->adv_params.properties.type = BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED;
|
||||
p_advertising->adv_params.p_peer_addr = NULL;
|
||||
p_advertising->adv_params.filter_policy = BLE_GAP_ADV_FP_ANY;
|
||||
p_advertising->adv_params.interval = p_advertising->adv_modes_config.ble_adv_fast_interval;
|
||||
|
||||
ret = sd_ble_gap_adv_set_configure(&p_advertising->adv_handle, NULL, &p_advertising->adv_params);
|
||||
VERIFY_SUCCESS(ret);
|
||||
|
||||
p_advertising->initialized = true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for checking that a phy define value matches one of the valid phys from the SD.
|
||||
*
|
||||
* @param[in] PHY to be validated.
|
||||
*
|
||||
* @retval true If the PHY value is valid (1mbit, 2mbit, coded).
|
||||
* @retval false If the PHY value is invalid.
|
||||
*/
|
||||
static bool phy_is_valid(uint32_t const * const p_phy)
|
||||
{
|
||||
if ((*p_phy) == BLE_GAP_PHY_1MBPS ||
|
||||
(*p_phy) == BLE_GAP_PHY_2MBPS
|
||||
#if defined (S140)
|
||||
|| (*p_phy) == BLE_GAP_PHY_CODED
|
||||
#endif // !defined (S140)
|
||||
)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_advertising_start(ble_advertising_t * const p_advertising,
|
||||
ble_adv_mode_t advertising_mode)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
if (p_advertising->initialized == false)
|
||||
{
|
||||
return NRF_ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
p_advertising->adv_mode_current = advertising_mode;
|
||||
|
||||
memset(&p_advertising->peer_address, 0, sizeof(p_advertising->peer_address));
|
||||
|
||||
if ( ((p_advertising->adv_modes_config.ble_adv_directed_high_duty_enabled) && (p_advertising->adv_mode_current == BLE_ADV_MODE_DIRECTED_HIGH_DUTY))
|
||||
||((p_advertising->adv_modes_config.ble_adv_directed_enabled) && (p_advertising->adv_mode_current == BLE_ADV_MODE_DIRECTED_HIGH_DUTY))
|
||||
||((p_advertising->adv_modes_config.ble_adv_directed_enabled) && (p_advertising->adv_mode_current == BLE_ADV_MODE_DIRECTED))
|
||||
)
|
||||
{
|
||||
if (p_advertising->evt_handler != NULL)
|
||||
{
|
||||
p_advertising->peer_addr_reply_expected = true;
|
||||
p_advertising->evt_handler(BLE_ADV_EVT_PEER_ADDR_REQUEST);
|
||||
}
|
||||
else
|
||||
{
|
||||
p_advertising->peer_addr_reply_expected = false;
|
||||
}
|
||||
}
|
||||
|
||||
p_advertising->adv_mode_current = adv_mode_next_avail_get(p_advertising, advertising_mode);
|
||||
|
||||
// Fetch the whitelist.
|
||||
if ((p_advertising->evt_handler != NULL) &&
|
||||
(p_advertising->adv_mode_current == BLE_ADV_MODE_FAST || p_advertising->adv_mode_current == BLE_ADV_MODE_SLOW) &&
|
||||
(p_advertising->adv_modes_config.ble_adv_whitelist_enabled) &&
|
||||
(!p_advertising->whitelist_temporarily_disabled))
|
||||
{
|
||||
p_advertising->whitelist_in_use = false;
|
||||
p_advertising->whitelist_reply_expected = true;
|
||||
p_advertising->evt_handler(BLE_ADV_EVT_WHITELIST_REQUEST);
|
||||
}
|
||||
else
|
||||
{
|
||||
p_advertising->whitelist_reply_expected = false;
|
||||
}
|
||||
|
||||
// Initialize advertising parameters with default values.
|
||||
memset(&p_advertising->adv_params, 0, sizeof(p_advertising->adv_params));
|
||||
|
||||
p_advertising->adv_params.properties.type = BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED;
|
||||
|
||||
// Use 1MBIT as primary phy if no phy was selected.
|
||||
if (phy_is_valid(&p_advertising->adv_modes_config.ble_adv_primary_phy))
|
||||
{
|
||||
p_advertising->adv_params.primary_phy = p_advertising->adv_modes_config.ble_adv_primary_phy;
|
||||
}
|
||||
else
|
||||
{
|
||||
p_advertising->adv_params.primary_phy = BLE_GAP_PHY_1MBPS;
|
||||
}
|
||||
|
||||
if (p_advertising->adv_modes_config.ble_adv_extended_enabled)
|
||||
{
|
||||
// Use 1MBIT as secondary phy if no phy was selected.
|
||||
if (phy_is_valid(&p_advertising->adv_modes_config.ble_adv_secondary_phy))
|
||||
{
|
||||
p_advertising->adv_params.secondary_phy = p_advertising->adv_modes_config.ble_adv_secondary_phy;
|
||||
}
|
||||
else
|
||||
{
|
||||
p_advertising->adv_params.secondary_phy = BLE_GAP_PHY_1MBPS;
|
||||
}
|
||||
}
|
||||
p_advertising->adv_params.filter_policy = BLE_GAP_ADV_FP_ANY;
|
||||
|
||||
// Set advertising parameters and events according to selected advertising mode.
|
||||
switch (p_advertising->adv_mode_current)
|
||||
{
|
||||
case BLE_ADV_MODE_DIRECTED_HIGH_DUTY:
|
||||
ret = set_adv_mode_directed_high_duty(p_advertising, &p_advertising->adv_params);
|
||||
break;
|
||||
|
||||
case BLE_ADV_MODE_DIRECTED:
|
||||
ret = set_adv_mode_directed(p_advertising, &p_advertising->adv_params);
|
||||
break;
|
||||
|
||||
case BLE_ADV_MODE_FAST:
|
||||
ret = set_adv_mode_fast(p_advertising, &p_advertising->adv_params);
|
||||
break;
|
||||
|
||||
case BLE_ADV_MODE_SLOW:
|
||||
ret = set_adv_mode_slow(p_advertising, &p_advertising->adv_params);
|
||||
break;
|
||||
|
||||
case BLE_ADV_MODE_IDLE:
|
||||
p_advertising->adv_evt = BLE_ADV_EVT_IDLE;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (p_advertising->adv_mode_current != BLE_ADV_MODE_IDLE)
|
||||
{
|
||||
|
||||
ret = sd_ble_gap_adv_set_configure(&p_advertising->adv_handle, p_advertising->p_adv_data, &p_advertising->adv_params);
|
||||
if (ret != NRF_SUCCESS)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
ret = sd_ble_gap_adv_start(p_advertising->adv_handle, p_advertising->conn_cfg_tag);
|
||||
|
||||
if (ret != NRF_SUCCESS)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (p_advertising->evt_handler != NULL)
|
||||
{
|
||||
p_advertising->evt_handler(p_advertising->adv_evt);
|
||||
}
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
void ble_advertising_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
|
||||
{
|
||||
ble_advertising_t * p_advertising = (ble_advertising_t *)p_context;
|
||||
|
||||
switch (p_ble_evt->header.evt_id)
|
||||
{
|
||||
case BLE_GAP_EVT_CONNECTED:
|
||||
on_connected(p_advertising, p_ble_evt);
|
||||
break;
|
||||
|
||||
// Upon disconnection, whitelist will be activated and direct advertising is started.
|
||||
case BLE_GAP_EVT_DISCONNECTED:
|
||||
on_disconnected(p_advertising, p_ble_evt);
|
||||
break;
|
||||
|
||||
// Upon terminated advertising (time-out), the next advertising mode is started.
|
||||
case BLE_GAP_EVT_ADV_SET_TERMINATED:
|
||||
on_terminated(p_advertising, p_ble_evt);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_advertising_peer_addr_reply(ble_advertising_t * const p_advertising,
|
||||
ble_gap_addr_t * p_peer_address)
|
||||
{
|
||||
if (!p_advertising->peer_addr_reply_expected)
|
||||
{
|
||||
return NRF_ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
p_advertising->peer_addr_reply_expected = false;
|
||||
|
||||
memcpy(&p_advertising->peer_address, p_peer_address, sizeof(p_advertising->peer_address));
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_advertising_whitelist_reply(ble_advertising_t * const p_advertising,
|
||||
ble_gap_addr_t const * p_gap_addrs,
|
||||
uint32_t addr_cnt,
|
||||
ble_gap_irk_t const * p_gap_irks,
|
||||
uint32_t irk_cnt)
|
||||
{
|
||||
if (!p_advertising->whitelist_reply_expected)
|
||||
{
|
||||
return NRF_ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
p_advertising->whitelist_reply_expected = false;
|
||||
p_advertising->whitelist_in_use = ((addr_cnt > 0) || (irk_cnt > 0));
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_advertising_restart_without_whitelist(ble_advertising_t * const p_advertising)
|
||||
{
|
||||
ret_code_t ret;
|
||||
|
||||
(void) sd_ble_gap_adv_stop(p_advertising->adv_handle);
|
||||
|
||||
p_advertising->whitelist_temporarily_disabled = true;
|
||||
p_advertising->whitelist_in_use = false;
|
||||
p_advertising->adv_params.filter_policy = BLE_GAP_ADV_FP_ANY;
|
||||
// Set correct flags.
|
||||
ret = flags_set(p_advertising, BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
|
||||
VERIFY_SUCCESS(ret);
|
||||
|
||||
ret = ble_advertising_start(p_advertising, p_advertising->adv_mode_current);
|
||||
if ((ret != NRF_SUCCESS) && (p_advertising->error_handler != NULL))
|
||||
{
|
||||
p_advertising->error_handler(ret);
|
||||
}
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
void ble_advertising_modes_config_set(ble_advertising_t * const p_advertising,
|
||||
ble_adv_modes_config_t const * const p_adv_modes_config)
|
||||
{
|
||||
p_advertising->adv_modes_config = *p_adv_modes_config;
|
||||
}
|
||||
|
||||
|
||||
ret_code_t ble_advertising_advdata_update(ble_advertising_t * const p_advertising,
|
||||
ble_advdata_t const * const p_advdata,
|
||||
ble_advdata_t const * const p_srdata)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_advertising);
|
||||
if (p_advertising->initialized == false)
|
||||
{
|
||||
return NRF_ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if ((p_advdata == NULL) && (p_srdata == NULL))
|
||||
{
|
||||
return NRF_ERROR_NULL;
|
||||
}
|
||||
|
||||
ble_gap_adv_data_t new_adv_data;
|
||||
memset(&new_adv_data, 0, sizeof(new_adv_data));
|
||||
|
||||
if (p_advdata != NULL)
|
||||
{
|
||||
new_adv_data.adv_data.p_data =
|
||||
(p_advertising->p_adv_data->adv_data.p_data != p_advertising->enc_advdata[0]) ?
|
||||
p_advertising->enc_advdata[0] : p_advertising->enc_advdata[1];
|
||||
new_adv_data.adv_data.len = adv_set_data_size_max_get(p_advertising);
|
||||
|
||||
ret_code_t ret = ble_advdata_encode(p_advdata,
|
||||
new_adv_data.adv_data.p_data,
|
||||
&new_adv_data.adv_data.len);
|
||||
VERIFY_SUCCESS(ret);
|
||||
}
|
||||
|
||||
if (p_srdata != NULL)
|
||||
{
|
||||
new_adv_data.scan_rsp_data.p_data =
|
||||
(p_advertising->p_adv_data->scan_rsp_data.p_data != p_advertising->enc_scan_rsp_data[0]) ?
|
||||
p_advertising->enc_scan_rsp_data[0] : p_advertising->enc_scan_rsp_data[1];
|
||||
new_adv_data.scan_rsp_data.len = adv_set_data_size_max_get(p_advertising);
|
||||
|
||||
ret_code_t ret = ble_advdata_encode(p_srdata,
|
||||
new_adv_data.scan_rsp_data.p_data,
|
||||
&new_adv_data.scan_rsp_data.len);
|
||||
VERIFY_SUCCESS(ret);
|
||||
}
|
||||
|
||||
memcpy(&p_advertising->adv_data, &new_adv_data, sizeof(p_advertising->adv_data));
|
||||
p_advertising->p_adv_data = &p_advertising->adv_data;
|
||||
|
||||
return sd_ble_gap_adv_set_configure(&p_advertising->adv_handle,
|
||||
p_advertising->p_adv_data,
|
||||
NULL);
|
||||
}
|
||||
|
||||
|
||||
#endif // NRF_MODULE_ENABLED(BLE_ADVERTISING)
|
||||
355
components/ble/ble_advertising/ble_advertising.h
Normal file
355
components/ble/ble_advertising/ble_advertising.h
Normal file
@@ -0,0 +1,355 @@
|
||||
/**
|
||||
* Copyright (c) 2015 - 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 ble_advertising Advertising Module
|
||||
* @{
|
||||
* @ingroup ble_sdk_lib
|
||||
* @brief Module for handling connectable BLE advertising.
|
||||
*
|
||||
* @details The Advertising Module handles connectable advertising for your application. It can
|
||||
* be configured with advertising modes to suit most typical use cases.
|
||||
* Your main application can react to changes in advertising modes
|
||||
* if an event handler is provided.
|
||||
*
|
||||
* @note The Advertising Module supports only applications with a single peripheral link.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BLE_ADVERTISING_H__
|
||||
#define BLE_ADVERTISING_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include "nrf_error.h"
|
||||
#include "ble.h"
|
||||
#include "ble_gap.h"
|
||||
#include "ble_gattc.h"
|
||||
#include "ble_advdata.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**@brief Macro for defining a ble_advertising instance.
|
||||
*
|
||||
* @param _name Name of the instance.
|
||||
* @hideinitializer
|
||||
*/
|
||||
#define BLE_ADVERTISING_DEF(_name) \
|
||||
static ble_advertising_t _name; \
|
||||
NRF_SDH_BLE_OBSERVER(_name ## _ble_obs, \
|
||||
BLE_ADV_BLE_OBSERVER_PRIO, \
|
||||
ble_advertising_on_ble_evt, &_name)
|
||||
|
||||
|
||||
/**@brief Advertising modes. */
|
||||
typedef enum
|
||||
{
|
||||
BLE_ADV_MODE_IDLE, /**< Idle; no connectable advertising is ongoing. */
|
||||
BLE_ADV_MODE_DIRECTED_HIGH_DUTY, /**< Directed advertising (high duty cycle) attempts to connect to the most recently disconnected peer. */
|
||||
BLE_ADV_MODE_DIRECTED, /**< Directed advertising (low duty cycle) attempts to connect to the most recently disconnected peer. */
|
||||
BLE_ADV_MODE_FAST, /**< Fast advertising will connect to any peer device, or filter with a whitelist if one exists. */
|
||||
BLE_ADV_MODE_SLOW, /**< Slow advertising is similar to fast advertising. By default, it uses a longer advertising interval and time-out than fast advertising. However, these options are defined by the user. */
|
||||
} ble_adv_mode_t;
|
||||
|
||||
/**@brief Advertising events.
|
||||
*
|
||||
* @details These events are propagated to the main application if a handler was provided during
|
||||
* initialization of the Advertising Module. Events for modes that are not used can be
|
||||
* ignored. Similarly, BLE_ADV_EVT_WHITELIST_REQUEST and BLE_ADV_EVT_PEER_ADDR_REQUEST
|
||||
* can be ignored if whitelist and direct advertising is not used.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
BLE_ADV_EVT_IDLE, /**< Idle; no connectable advertising is ongoing.*/
|
||||
BLE_ADV_EVT_DIRECTED_HIGH_DUTY, /**< Direct advertising mode has started. */
|
||||
BLE_ADV_EVT_DIRECTED, /**< Directed advertising (low duty cycle) has started. */
|
||||
BLE_ADV_EVT_FAST, /**< Fast advertising mode has started. */
|
||||
BLE_ADV_EVT_SLOW, /**< Slow advertising mode has started. */
|
||||
BLE_ADV_EVT_FAST_WHITELIST, /**< Fast advertising mode using the whitelist has started. */
|
||||
BLE_ADV_EVT_SLOW_WHITELIST, /**< Slow advertising mode using the whitelist has started. */
|
||||
BLE_ADV_EVT_WHITELIST_REQUEST, /**< Request a whitelist from the main application. For whitelist advertising to work, the whitelist must be set when this event occurs. */
|
||||
BLE_ADV_EVT_PEER_ADDR_REQUEST /**< Request a peer address from the main application. For directed advertising to work, the peer address must be set when this event occurs. */
|
||||
} ble_adv_evt_t;
|
||||
|
||||
/**@brief Options for the different advertisement modes.
|
||||
*
|
||||
* @details This structure is used to enable or disable advertising modes and to configure time-out
|
||||
* periods and advertising intervals.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
bool ble_adv_on_disconnect_disabled; /**< Enable or disable automatic return to advertising upon disconnecting.*/
|
||||
bool ble_adv_whitelist_enabled; /**< Enable or disable use of the whitelist. */
|
||||
bool ble_adv_directed_high_duty_enabled; /**< Enable or disable high duty direct advertising mode. Can not be used together with extended advertising. */
|
||||
bool ble_adv_directed_enabled; /**< Enable or disable direct advertising mode. */
|
||||
bool ble_adv_fast_enabled; /**< Enable or disable fast advertising mode. */
|
||||
bool ble_adv_slow_enabled; /**< Enable or disable slow advertising mode. */
|
||||
uint32_t ble_adv_directed_interval; /**< Advertising interval for directed advertising. */
|
||||
uint32_t ble_adv_directed_timeout; /**< Time-out (number of tries) for direct advertising. */
|
||||
uint32_t ble_adv_fast_interval; /**< Advertising interval for fast advertising. */
|
||||
uint32_t ble_adv_fast_timeout; /**< Time-out (in units of 10ms) for fast advertising. */
|
||||
uint32_t ble_adv_slow_interval; /**< Advertising interval for slow advertising. */
|
||||
uint32_t ble_adv_slow_timeout; /**< Time-out (in units of 10ms) for slow advertising. */
|
||||
bool ble_adv_extended_enabled; /**< Enable or disable extended advertising. */
|
||||
uint32_t ble_adv_secondary_phy; /**< PHY for the secondary (extended) advertising @ref BLE_GAP_PHYS (BLE_GAP_PHY_1MBPS, BLE_GAP_PHY_2MBPS or BLE_GAP_PHY_CODED). */
|
||||
uint32_t ble_adv_primary_phy; /**< PHY for the primary advertising. @ref BLE_GAP_PHYS (BLE_GAP_PHY_1MBPS, BLE_GAP_PHY_2MBPS or BLE_GAP_PHY_CODED). */
|
||||
} ble_adv_modes_config_t;
|
||||
|
||||
/**@brief BLE advertising event handler type. */
|
||||
typedef void (*ble_adv_evt_handler_t) (ble_adv_evt_t const adv_evt);
|
||||
|
||||
/**@brief BLE advertising error handler type. */
|
||||
typedef void (*ble_adv_error_handler_t) (uint32_t nrf_error);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
bool initialized;
|
||||
bool advertising_start_pending; /**< Flag to keep track of ongoing operations in flash. */
|
||||
ble_adv_mode_t adv_mode_current; /**< Variable to keep track of the current advertising mode. */
|
||||
ble_adv_modes_config_t adv_modes_config; /**< Struct to keep track of disabled and enabled advertising modes, as well as time-outs and intervals.*/
|
||||
uint8_t conn_cfg_tag; /**< Variable to keep track of what connection settings will be used if the advertising results in a connection. */
|
||||
|
||||
ble_adv_evt_t adv_evt; /**< Advertising event propogated to the main application. The event is either a transaction to a new advertising mode, or a request for whitelist or peer address. */
|
||||
ble_adv_evt_handler_t evt_handler; /**< Handler for the advertising events. Can be initialized as NULL if no handling is implemented on in the main application. */
|
||||
ble_adv_error_handler_t error_handler; /**< Handler for the advertising error events. */
|
||||
|
||||
ble_gap_adv_params_t adv_params; /**< GAP advertising parameters. */
|
||||
uint8_t adv_handle; /**< Handle for the advertising set. */
|
||||
|
||||
#ifdef BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_CONNECTABLE_MAX_SUPPORTED
|
||||
uint8_t enc_advdata[2][BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_CONNECTABLE_MAX_SUPPORTED]; /**< Advertising data sets in encoded form. Current and swap buffer. */
|
||||
uint8_t enc_scan_rsp_data[2][BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_CONNECTABLE_MAX_SUPPORTED]; /**< Scan response data sets in encoded form. Current and swap buffer. */
|
||||
#else
|
||||
uint8_t enc_advdata[2][BLE_GAP_ADV_SET_DATA_SIZE_MAX]; /**< Current advertising data in encoded form. */
|
||||
uint8_t enc_scan_rsp_data[2][BLE_GAP_ADV_SET_DATA_SIZE_MAX]; /**< Current scan response data in encoded form. */
|
||||
#endif // BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_CONNECTABLE_MAX_SUPPORTED
|
||||
|
||||
ble_gap_adv_data_t adv_data; /**< Advertising data. */
|
||||
ble_gap_adv_data_t *p_adv_data; /**< Will be set to point to @ref ble_advertising_t::adv_data for undirected advertising, and will be set to NULL for directed advertising. */
|
||||
|
||||
uint16_t current_slave_link_conn_handle; /**< Connection handle for the active link. */
|
||||
ble_gap_addr_t peer_address; /**< Address of the most recently connected peer, used for direct advertising. */
|
||||
bool peer_addr_reply_expected; /**< Flag to verify that peer address is only set when requested. */
|
||||
bool whitelist_temporarily_disabled; /**< Flag to keep track of temporary disabling of the whitelist. */
|
||||
bool whitelist_reply_expected; /**< Flag to verify that the whitelist is only set when requested. */
|
||||
bool whitelist_in_use; /**< This module needs to be aware of whether or not a whitelist has been set (e.g. using the Peer Manager) in order to start advertising with the proper advertising params (filter policy). */
|
||||
} ble_advertising_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t interval;
|
||||
uint32_t timeout;
|
||||
bool enabled;
|
||||
} ble_adv_mode_config_t;
|
||||
|
||||
/**@brief Initialization parameters for the Advertising Module.
|
||||
* @details This structure is used to pass advertising options, advertising data,
|
||||
* and an event handler to the Advertising Module during initialization.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
ble_advdata_t advdata; /**< Advertising data: name, appearance, discovery flags, and more. */
|
||||
ble_advdata_t srdata; /**< Scan response data: Supplement to advertising data. */
|
||||
ble_adv_modes_config_t config; /**< Select which advertising modes and intervals will be utilized.*/
|
||||
ble_adv_evt_handler_t evt_handler; /**< Event handler that will be called upon advertising events. */
|
||||
ble_adv_error_handler_t error_handler; /**< Error handler that will propogate internal errors to the main applications. */
|
||||
} ble_advertising_init_t;
|
||||
|
||||
|
||||
/**@brief Function for handling BLE events.
|
||||
*
|
||||
* @details This function must be called from the BLE stack event dispatcher for
|
||||
* the module to handle BLE events that are relevant for the Advertising Module.
|
||||
*
|
||||
* @param[in] p_ble_evt BLE stack event.
|
||||
* @param[in] p_adv Advertising Module instance.
|
||||
*/
|
||||
void ble_advertising_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_adv);
|
||||
|
||||
|
||||
/**@brief Function for initializing the Advertising Module.
|
||||
*
|
||||
* @details Encodes the required advertising data and passes it to the stack.
|
||||
* Also builds a structure to be passed to the stack when starting advertising.
|
||||
* Most of the supplied data is copied into a local structure where it is manipulated
|
||||
* depending on what advertising modes are started in @ref ble_advertising_start.
|
||||
* The exception is advdata_t::uuids_more_available, advdata_t::uuids_complete, and
|
||||
* advdata_t::uuids_solicited which are stored as pointers. The main application must
|
||||
* store these UUIDs.
|
||||
*
|
||||
* @param[out] p_advertising Advertising Module instance. This structure must be supplied by
|
||||
* the application. It is initialized by this function and will later
|
||||
* be used to identify this particular module instance.
|
||||
* @param[in] p_init Information needed to initialize the module.
|
||||
*
|
||||
* @retval NRF_SUCCESS If initialization was successful.
|
||||
* @retval NRF_ERROR_INVALID_PARAM If the advertising configuration in \p p_init is invalid.
|
||||
* @return If functions from other modules return errors to this function, the @ref nrf_error are propagated.
|
||||
*/
|
||||
uint32_t ble_advertising_init(ble_advertising_t * const p_advertising,
|
||||
ble_advertising_init_t const * const p_init);
|
||||
|
||||
|
||||
/**@brief Function for changing the connection settings tag that will be used for upcoming connections.
|
||||
*
|
||||
* @details See @ref sd_ble_cfg_set for more details about changing connection settings. If this
|
||||
* function is never called, @ref BLE_CONN_CFG_TAG_DEFAULT will be used.
|
||||
*
|
||||
* @param[in] p_advertising Advertising Module instance.
|
||||
* @param[in] ble_cfg_tag Configuration for the connection settings (see @ref sd_ble_cfg_set).
|
||||
*/
|
||||
void ble_advertising_conn_cfg_tag_set(ble_advertising_t * const p_advertising, uint8_t ble_cfg_tag);
|
||||
|
||||
/**@brief Function for starting advertising.
|
||||
*
|
||||
* @details You can start advertising in any of the advertising modes that you enabled
|
||||
* during initialization.
|
||||
*
|
||||
* @param[in] p_advertising Advertising Module instance.
|
||||
* @param[in] advertising_mode Advertising mode.
|
||||
*
|
||||
* @retval @ref NRF_SUCCESS On success, else an error code indicating reason for failure.
|
||||
* @retval @ref NRF_ERROR_INVALID_STATE If the module is not initialized.
|
||||
*/
|
||||
uint32_t ble_advertising_start(ble_advertising_t * const p_advertising,
|
||||
ble_adv_mode_t advertising_mode);
|
||||
|
||||
|
||||
/**@brief Function for setting the peer address.
|
||||
*
|
||||
* @details The peer address must be set by the application upon receiving a
|
||||
* @ref BLE_ADV_EVT_PEER_ADDR_REQUEST event. Without the peer address, the directed
|
||||
* advertising mode will not be run.
|
||||
*
|
||||
* @param[in] p_advertising Advertising Module instance.
|
||||
* @param[in] p_peer_addr Pointer to a peer address.
|
||||
*
|
||||
* @retval @ref NRF_SUCCESS Successfully stored the peer address pointer in the Advertising Module.
|
||||
* @retval @ref NRF_ERROR_INVALID_STATE If a reply was not expected.
|
||||
*/
|
||||
uint32_t ble_advertising_peer_addr_reply(ble_advertising_t * const p_advertising,
|
||||
ble_gap_addr_t * p_peer_addr);
|
||||
|
||||
|
||||
/**@brief Function for setting a whitelist.
|
||||
*
|
||||
* @details The whitelist must be set by the application upon receiving a
|
||||
* @ref BLE_ADV_EVT_WHITELIST_REQUEST event. Without the whitelist, the whitelist
|
||||
* advertising for fast and slow modes will not be run.
|
||||
*
|
||||
* @param[in] p_advertising Advertising Module instance.
|
||||
* @param[in] p_gap_addrs The list of GAP addresses to whitelist.
|
||||
* @param[in] addr_cnt The number of GAP addresses to whitelist.
|
||||
* @param[in] p_gap_irks The list of peer IRK to whitelist.
|
||||
* @param[in] irk_cnt The number of peer IRK to whitelist.
|
||||
*
|
||||
* @retval @ref NRF_SUCCESS If the operation was successful.
|
||||
* @retval @ref NRF_ERROR_INVALID_STATE If a call to this function was made without a
|
||||
* BLE_ADV_EVT_WHITELIST_REQUEST event being received.
|
||||
*/
|
||||
uint32_t ble_advertising_whitelist_reply(ble_advertising_t * const p_advertising,
|
||||
ble_gap_addr_t const * p_gap_addrs,
|
||||
uint32_t addr_cnt,
|
||||
ble_gap_irk_t const * p_gap_irks,
|
||||
uint32_t irk_cnt);
|
||||
|
||||
|
||||
/**@brief Function for disabling whitelist advertising.
|
||||
*
|
||||
* @details This function temporarily disables whitelist advertising.
|
||||
* Calling this function resets the current time-out countdown.
|
||||
*
|
||||
* @param[in] p_advertising Advertising Module instance.
|
||||
*
|
||||
* @retval @ref NRF_SUCCESS On success, else an error message propogated from the Softdevice.
|
||||
*/
|
||||
uint32_t ble_advertising_restart_without_whitelist(ble_advertising_t * const p_advertising);
|
||||
|
||||
|
||||
/**@brief Function for changing advertising modes configuration.
|
||||
*
|
||||
* @details This function can be called if you wish to reconfigure the advertising modes that the
|
||||
* Advertising Module will cycle through. Enable or disable modes as listed in
|
||||
* @ref ble_adv_mode_t; or change the duration of the advertising and use of whitelist.
|
||||
*
|
||||
* Keep in mind that @ref ble_adv_modes_config_t is also supplied when calling
|
||||
* @ref ble_advertising_init. Calling @ref ble_advertising_modes_config_set
|
||||
* is only necessary if your application requires this behaviour to change.
|
||||
*
|
||||
* @param[in] p_advertising Advertising Module instance.
|
||||
* @param[in] p_adv_modes_config Struct to keep track of disabled and enabled advertising modes,
|
||||
* as well as time-outs and intervals.
|
||||
*/
|
||||
void ble_advertising_modes_config_set(ble_advertising_t * const p_advertising,
|
||||
ble_adv_modes_config_t const * const p_adv_modes_config);
|
||||
|
||||
|
||||
/**@brief Function for updating advertising data.
|
||||
*
|
||||
* @details This function can be called if you wish to reconfigure the advertising data The update
|
||||
* will be effective even if advertising has already been started.
|
||||
*
|
||||
* @param[in] p_advertising Advertising Module instance.
|
||||
* @param[in] p_advdata Pointer to the structure for specifying the content of advertising data.
|
||||
* Or null if there should be no advertising data.
|
||||
* @param[in] p_srdata Pointer to the structure for specifying the content of scan response data.
|
||||
* Or null if there should be no advertising data.
|
||||
*
|
||||
* @retval @ref NRF_ERROR_NULL If advertising instance was null.
|
||||
* If both \p p_advdata and \p p_srdata are null.
|
||||
* @retval @ref NRF_ERROR_INVALID_STATE If advertising instance was not initialized.
|
||||
* @retval @ref NRF_SUCCESS or any error from @ref ble_advdata_encode or
|
||||
* @ref sd_ble_gap_adv_set_configure().
|
||||
*/
|
||||
ret_code_t ble_advertising_advdata_update(ble_advertising_t * const p_advertising,
|
||||
ble_advdata_t const * const p_advdata,
|
||||
ble_advdata_t const * const p_srdata);
|
||||
|
||||
/** @} */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // BLE_ADVERTISING_H__
|
||||
|
||||
/** @} */
|
||||
1030
components/ble/ble_db_discovery/ble_db_discovery.c
Normal file
1030
components/ble/ble_db_discovery/ble_db_discovery.c
Normal file
File diff suppressed because it is too large
Load Diff
271
components/ble/ble_db_discovery/ble_db_discovery.h
Normal file
271
components/ble/ble_db_discovery/ble_db_discovery.h
Normal file
@@ -0,0 +1,271 @@
|
||||
/**
|
||||
* Copyright (c) 2013 - 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 ble_db_discovery Database Discovery
|
||||
* @{
|
||||
* @ingroup ble_sdk_lib
|
||||
*
|
||||
* @brief Database discovery module.
|
||||
*
|
||||
* @details This module contains the APIs and types exposed by the DB Discovery module. These APIs
|
||||
* and types can be used by the application to perform discovery of a service and its
|
||||
* characteristics at the peer server. This module can also be used to discover the
|
||||
* desired services in multiple remote devices.
|
||||
*
|
||||
* @warning The maximum number of characteristics per service that can be discovered by this module
|
||||
* is determined by the number of characteristics in the service structure defined in
|
||||
* db_disc_config.h. If the peer has more than the supported number of characteristics, then
|
||||
* the first found will be discovered and any further characteristics will be ignored. Only the
|
||||
* following descriptors will be searched for at the peer: Client Characteristic Configuration,
|
||||
* Characteristic Extended Properties, Characteristic User Description, and Report Reference.
|
||||
*
|
||||
* @note Presently only one instance of a Primary Service can be discovered by this module. If
|
||||
* there are multiple instances of the service at the peer, only the first instance
|
||||
* of it at the peer is fetched and returned to the application.
|
||||
*
|
||||
* @note The application must propagate BLE stack events to this module by calling
|
||||
* ble_db_discovery_on_ble_evt().
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BLE_DB_DISCOVERY_H__
|
||||
#define BLE_DB_DISCOVERY_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "nrf_error.h"
|
||||
#include "ble.h"
|
||||
#include "ble_gattc.h"
|
||||
#include "ble_gatt_db.h"
|
||||
#include "nrf_ble_gq.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if !(defined(__LINT__))
|
||||
/**@brief Macro for defining a ble_db_discovery instance.
|
||||
*
|
||||
* @param _name Name of the instance.
|
||||
* @hideinitializer
|
||||
*/
|
||||
#define BLE_DB_DISCOVERY_DEF(_name) \
|
||||
static ble_db_discovery_t _name = {.discovery_in_progress = 0, \
|
||||
.conn_handle = BLE_CONN_HANDLE_INVALID}; \
|
||||
NRF_SDH_BLE_OBSERVER(_name ## _obs, \
|
||||
BLE_DB_DISC_BLE_OBSERVER_PRIO, \
|
||||
ble_db_discovery_on_ble_evt, &_name)
|
||||
|
||||
|
||||
/** @brief Macro for defining multiple ble_db_discovery instances.
|
||||
*
|
||||
* @param _name Name of the array of instances.
|
||||
* @param _cnt Number of instances to define.
|
||||
*/
|
||||
#define BLE_DB_DISCOVERY_ARRAY_DEF(_name, _cnt) \
|
||||
static ble_db_discovery_t _name[_cnt] = {MACRO_REPEAT(_cnt, DB_INIT)}; \
|
||||
\
|
||||
NRF_SDH_BLE_OBSERVERS(_name ## _obs, \
|
||||
BLE_DB_DISC_BLE_OBSERVER_PRIO, \
|
||||
ble_db_discovery_on_ble_evt, &_name, _cnt)
|
||||
|
||||
#if !(defined(DOXYGEN))
|
||||
#define DB_INIT() \
|
||||
{ \
|
||||
.discovery_in_progress = 0, \
|
||||
.conn_handle = BLE_CONN_HANDLE_INVALID, \
|
||||
},
|
||||
#endif
|
||||
|
||||
#else // __LINT__
|
||||
/* Swallow semicolons */
|
||||
/*lint -save -esym(528, *) -esym(529, *) : Symbol not referenced. */
|
||||
#define BLE_DB_DISCOVERY_ARRAY_DEF(A, B) static ble_db_discovery_t A[B]
|
||||
#define BLE_DB_DISCOVERY_DEF(A) static ble_db_discovery_t A
|
||||
/*lint -restore */
|
||||
#endif //!(defined(__LINT__))
|
||||
|
||||
#define BLE_DB_DISCOVERY_MAX_SRV 6 /**< Maximum number of services supported by this module. This also indicates the maximum number of users allowed to be registered to this module (one user per service). */
|
||||
|
||||
|
||||
/**@brief DB Discovery event type. */
|
||||
typedef enum
|
||||
{
|
||||
BLE_DB_DISCOVERY_COMPLETE, /**< Event indicating that the discovery of one service is complete. */
|
||||
BLE_DB_DISCOVERY_ERROR, /**< Event indicating that an internal error has occurred in the DB Discovery module. This could typically be because of the SoftDevice API returning an error code during the DB discover.*/
|
||||
BLE_DB_DISCOVERY_SRV_NOT_FOUND, /**< Event indicating that the service was not found at the peer.*/
|
||||
BLE_DB_DISCOVERY_AVAILABLE /**< Event indicating that the DB discovery instance is available.*/
|
||||
} ble_db_discovery_evt_type_t;
|
||||
|
||||
/**@brief Structure containing the event from the DB discovery module to the application. */
|
||||
typedef struct
|
||||
{
|
||||
ble_db_discovery_evt_type_t evt_type; /**< Type of event. */
|
||||
uint16_t conn_handle; /**< Handle of the connection for which this event has occurred. */
|
||||
union
|
||||
{
|
||||
ble_gatt_db_srv_t discovered_db; /**< Structure containing the information about the GATT Database at the server. This will be filled when the event type is @ref BLE_DB_DISCOVERY_COMPLETE. The UUID field of this will be filled when the event type is @ref BLE_DB_DISCOVERY_SRV_NOT_FOUND. */
|
||||
void const * p_db_instance; /**< Pointer to DB discovery instance @ref ble_db_discovery_t, indicating availability to the new discovery process. This will be filled when the event type is @ref BLE_DB_DISCOVERY_AVAILABLE. */
|
||||
uint32_t err_code; /**< nRF Error code indicating the type of error which occurred in the DB Discovery module. This will be filled when the event type is @ref BLE_DB_DISCOVERY_ERROR. */
|
||||
} params;
|
||||
} ble_db_discovery_evt_t;
|
||||
|
||||
/**@brief DB Discovery event handler type. */
|
||||
typedef void (* ble_db_discovery_evt_handler_t)(ble_db_discovery_evt_t * p_evt);
|
||||
|
||||
/**@brief Structure containing the pending event. */
|
||||
typedef struct
|
||||
{
|
||||
ble_db_discovery_evt_t evt; /**< Pending event. */
|
||||
ble_db_discovery_evt_handler_t evt_handler; /**< Event handler which should be called to raise this event. */
|
||||
} ble_db_discovery_user_evt_t;
|
||||
|
||||
/**@brief Structure for holding the information related to the GATT database at the server.
|
||||
*
|
||||
* @details This module identifies a remote database. Use one instance of this structure per
|
||||
* connection.
|
||||
*
|
||||
* @warning This structure must be zero-initialized.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
ble_gatt_db_srv_t services[BLE_DB_DISCOVERY_MAX_SRV]; /**< Information related to the current service being discovered. This is intended for internal use during service discovery.*/
|
||||
uint8_t srv_count; /**< Number of services at the peer's GATT database.*/
|
||||
uint8_t curr_char_ind; /**< Index of the current characteristic being discovered. This is intended for internal use during service discovery.*/
|
||||
uint8_t curr_srv_ind; /**< Index of the current service being discovered. This is intended for internal use during service discovery.*/
|
||||
uint8_t discoveries_count; /**< Number of service discoveries made, both successful and unsuccessful. */
|
||||
bool discovery_in_progress; /**< Variable to indicate whether there is a service discovery in progress. */
|
||||
uint16_t conn_handle; /**< Connection handle on which the discovery is started. */
|
||||
uint32_t pending_usr_evt_index; /**< The index to the pending user event array, pointing to the last added pending user event. */
|
||||
ble_db_discovery_user_evt_t pending_usr_evts[BLE_DB_DISCOVERY_MAX_SRV]; /**< Whenever a discovery related event is to be raised to a user module, it is stored in this array first. When all expected services have been discovered, all pending events are sent to the corresponding user modules. */
|
||||
} ble_db_discovery_t;
|
||||
|
||||
/**@brief DB discovery module initialization struct. */
|
||||
typedef struct
|
||||
{
|
||||
ble_db_discovery_evt_handler_t evt_handler; /**< Event handler to be called by the DB Discovery module. */
|
||||
nrf_ble_gq_t * p_gatt_queue; /**< Pointer to BLE GATT Queue instance. */
|
||||
} ble_db_discovery_init_t;
|
||||
|
||||
|
||||
/**@brief Function for initializing the DB Discovery module.
|
||||
*
|
||||
* @param[in] p_db_init Pointer to DB discovery initialization structure.
|
||||
*
|
||||
* @retval NRF_SUCCESS On successful initialization.
|
||||
* @retval NRF_ERROR_NULL If the initialization structure was NULL or
|
||||
* the structure content is empty.
|
||||
*/
|
||||
uint32_t ble_db_discovery_init(ble_db_discovery_init_t * p_db_init);
|
||||
|
||||
|
||||
/**@brief Function for closing the DB Discovery module.
|
||||
*
|
||||
* @details This function will clear up any internal variables and states maintained by the
|
||||
* module. To re-use the module after calling this function, the function @ref
|
||||
* ble_db_discovery_init must be called again. When using more than one DB Discovery
|
||||
* instance, this function should be called for each instance.
|
||||
*
|
||||
* @param[out] p_db_discovery Pointer to the DB discovery structure.
|
||||
*
|
||||
* @retval NRF_SUCCESS Operation success.
|
||||
*/
|
||||
uint32_t ble_db_discovery_close(ble_db_discovery_t * const p_db_discovery);
|
||||
|
||||
|
||||
/**@brief Function for registering with the DB Discovery module.
|
||||
*
|
||||
* @details The application can use this function to inform which service it is interested in
|
||||
* discovering at the server.
|
||||
*
|
||||
* @param[in] p_uuid Pointer to the UUID of the service to be discovered at the server.
|
||||
*
|
||||
* @note The total number of services that can be discovered by this module is @ref
|
||||
* BLE_DB_DISCOVERY_MAX_SRV. This effectively means that the maximum number of
|
||||
* registrations possible is equal to the @ref BLE_DB_DISCOVERY_MAX_SRV.
|
||||
*
|
||||
* @retval NRF_SUCCESS Operation success.
|
||||
* @retval NRF_ERROR_NULL When a NULL pointer is passed as input.
|
||||
* @retval NRF_ERROR_INVALID_STATE If this function is called without calling the
|
||||
* @ref ble_db_discovery_init.
|
||||
* @retval NRF_ERROR_NO_MEM The maximum number of registrations allowed by this module
|
||||
* has been reached.
|
||||
*/
|
||||
uint32_t ble_db_discovery_evt_register(const ble_uuid_t * const p_uuid);
|
||||
|
||||
|
||||
/**@brief Function for starting the discovery of the GATT database at the server.
|
||||
*
|
||||
* @param[out] p_db_discovery Pointer to the DB Discovery structure.
|
||||
* @param[in] conn_handle The handle of the connection for which the discovery should be
|
||||
* started.
|
||||
*
|
||||
* @retval NRF_SUCCESS Operation success.
|
||||
* @retval NRF_ERROR_NULL When a NULL pointer is passed as input.
|
||||
* @retval NRF_ERROR_INVALID_STATE If this function is called without calling the
|
||||
* @ref ble_db_discovery_init, or without calling
|
||||
* @ref ble_db_discovery_evt_register.
|
||||
* @retval NRF_ERROR_BUSY If a discovery is already in progress using
|
||||
* @p p_db_discovery. Use a different @ref ble_db_discovery_t
|
||||
* structure, or wait for a DB Discovery event before retrying.
|
||||
* @return This API propagates the error code returned by functions:
|
||||
* @ref nrf_ble_gq_conn_handle_register and @ref nrf_ble_gq_item_add.
|
||||
*/
|
||||
uint32_t ble_db_discovery_start(ble_db_discovery_t * p_db_discovery,
|
||||
uint16_t conn_handle);
|
||||
|
||||
|
||||
/**@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 DB Discovery structure.
|
||||
*/
|
||||
void ble_db_discovery_on_ble_evt(ble_evt_t const * p_ble_evt,
|
||||
void * p_context);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // BLE_DB_DISCOVERY_H__
|
||||
|
||||
/** @} */
|
||||
1817
components/ble/ble_dtm/ble_dtm.c
Normal file
1817
components/ble/ble_dtm/ble_dtm.c
Normal file
File diff suppressed because it is too large
Load Diff
333
components/ble/ble_dtm/ble_dtm.h
Normal file
333
components/ble/ble_dtm/ble_dtm.h
Normal file
@@ -0,0 +1,333 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 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 ble_dtm DTM - Direct Test Mode
|
||||
* @{
|
||||
* @ingroup ble_sdk_lib
|
||||
* @brief Module for testing RF/PHY using DTM commands.
|
||||
*/
|
||||
|
||||
#ifndef BLE_DTM_H__
|
||||
#define BLE_DTM_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "nrf.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define DTM_MAX_ANTENNA_CNT 0x13 /**< Maximum supported antenna count. */
|
||||
|
||||
/**@brief Configuration parameters. */
|
||||
#define DTM_BITRATE UARTE_BAUDRATE_BAUDRATE_Baud19200 /**< Serial bitrate on the UART */
|
||||
#define DEFAULT_TX_POWER RADIO_TXPOWER_TXPOWER_0dBm /**< Default Transmission power using in the DTM module. */
|
||||
#define DEFAULT_TIMER NRF_TIMER0 /**< Default timer used for timing. */
|
||||
#define DEFAULT_TIMER_IRQn TIMER0_IRQn /**< IRQ used for timer. NOTE: MUST correspond to DEFAULT_TIMER. */
|
||||
|
||||
#define ANOMALY_172_TIMER NRF_TIMER1 /**< Timer used for the workaround for errata 172 on affected nRF5 devices. */
|
||||
#define ANOMALY_172_TIMER_IRQn TIMER1_IRQn /**< IRQ used for timer. NOTE: MUST correspond to ERRATA_172_TIMER. */
|
||||
#define ANOMALY_172_TIMER_IRQHandler TIMER1_IRQHandler /**< IRQHandler used for timer. NOTE: MUST correspond to ERRATA_172_TIMER. */
|
||||
|
||||
/**@brief BLE DTM command codes. */
|
||||
typedef uint32_t dtm_cmd_t; /**< DTM command type. */
|
||||
|
||||
#define LE_TEST_SETUP 0 /**< DTM command: Set PHY or modulation, configure upper two bits of length,
|
||||
request matrix of supported features or request max values of parameters. */
|
||||
#define LE_RECEIVER_TEST 1 /**< DTM command: Start receive test. */
|
||||
#define LE_TRANSMITTER_TEST 2 /**< DTM command: Start transmission test. */
|
||||
#define LE_TEST_END 3 /**< DTM command: End test and send packet report. */
|
||||
|
||||
#define LE_TEST_SETUP_RESET 0 /**< DTM command control: Stop TX/RX, reset the packet length upper bits and set the PHY to 1Mbit. */
|
||||
#define LE_TEST_SETUP_SET_UPPER 1 /**< DTM command control: Set the upper two bits of the length field. */
|
||||
#define LE_TEST_SETUP_SET_PHY 2 /**< DTM command control: Select the PHY to be used for packets. */
|
||||
#define LE_TEST_SETUP_SELECT_MODULATION 3 /**< DTM command control: Select standard or stable modulation index. Stable modulation index is not supported. */
|
||||
#define LE_TEST_SETUP_READ_SUPPORTED 4 /**< DTM command control: Read the supported test case features. */
|
||||
#define LE_TEST_SETUP_READ_MAX 5 /**< DTM command control: Read the max supported time and length for packets. */
|
||||
#define LE_TEST_SETUP_CONSTANT_TONE 6 /**< DTM command control: Constant Tone Extension info. */
|
||||
#define LE_TEST_SETUP_CONSTANT_TONE_SLOT 7 /**< DTM command control: Constant Tone Extension slot. */
|
||||
#define LE_TEST_SETUP_ANTENNA_ARRAY 8 /**< DTM command control: Antenna number and switch patern. */
|
||||
#define LE_TEST_SETUP_TRANSMIT_POWER 9 /**< DTM command control: Transmit power set. */
|
||||
|
||||
#define LE_RESET_MIN_RANGE 0x00 /**< DTM command parameter: Reset. Minimum parameter value. */
|
||||
#define LE_RESET_MAX_RANGE 0x03 /**< DTM command parameter: Reset. Maximum parameter value. */
|
||||
|
||||
#define LE_SET_UPER_BITS_MIN_RANGE 0x00 /**< DTM command parameter: Set upper bits. Minimum parameter value. */
|
||||
#define LE_SET_UPER_BITS_MAX_RANGE 0x0F /**< DTM command parameter: Set upper bits. Maximum parameter value. */
|
||||
|
||||
#define LE_PHY_1M_MIN_RANGE 0x04 /**< DTM command parameter: Set PHY for future packets to use 1MBit PHY. Minimum parameter value. */
|
||||
#define LE_PHY_1M_MAX_RANGE 0x07 /**< DTM command parameter: Set PHY for future packets to use 1MBit PHY. Maximum parameter value. */
|
||||
#define LE_PHY_2M_MIN_RANGE 0x08 /**< DTM command parameter: Set PHY for future packets to use 2MBit PHY. Minimum parameter value. */
|
||||
#define LE_PHY_2M_MAX_RANGE 0x0B /**< DTM command parameter: Set PHY for future packets to use 2MBit PHY. Maximum parameter value. */
|
||||
#define LE_PHY_LE_CODED_S8_MIN_RANGE 0x0C /**< DTM command parameter: Set PHY for future packets to use coded PHY with S=8. Minimum parameter value. */
|
||||
#define LE_PHY_LE_CODED_S8_MAX_RANGE 0x0F /**< DTM command parameter: Set PHY for future packets to use coded PHY with S=8. Maximum parameter value. */
|
||||
#define LE_PHY_LE_CODED_S2_MIN_RANGE 0x10 /**< DTM command parameter: Set PHY for future packets to use coded PHY with S=2. Minimum parameter value. */
|
||||
#define LE_PHY_LE_CODED_S2_MAX_RANGE 0x13 /**< DTM command parameter: Set PHY for future packets to use coded PHY with S=2. Maximum parameter value. */
|
||||
|
||||
#define LE_MODULATION_INDEX_STANDARD_MIN_RANGE 0x00 /**< DTM command parameter: Set Modulation index to stadard. Minimum parameter value. */
|
||||
#define LE_MODULATION_INDEX_STANDARD_MAX_RANGE 0x03 /**< DTM command parameter: Set Modulation index to stadard. Maximum parameter value. */
|
||||
#define LE_MODULATION_INDEX_STABLE_MIN_RANGE 0x04 /**< DTM command parameter: Set Modulation index to stable. Minimum parameter value. */
|
||||
#define LE_MODULATION_INDEX_STABLE_MAX_RANGE 0x07 /**< DTM command parameter: Set Modulation index to stable. Maximum parameter value. */
|
||||
|
||||
#define LE_TEST_FEATURE_READ_MIN_RANGE 0x00 /**< DTM command parameter: Read test case supported feature. Minimum parameter value. */
|
||||
#define LE_TEST_FEATURE_READ_MAX_RANGE 0x03 /**< DTM command parameter: Read test case supported feature. Maximum parameter value. */
|
||||
|
||||
#define LE_TEST_SUPPORTED_TX_OCTETS_MIN_RANGE 0x00 /**< DTM command parameter: Read maximum supported Tx Octets. Minimum parameter value. */
|
||||
#define LE_TEST_SUPPORTED_TX_OCTETS_MAX_RANGE 0x03 /**< DTM command parameter: Read maximum supported Tx Octets. Maximum parameter value. */
|
||||
#define LE_TEST_SUPPORTED_TX_TIME_MIN_RANGE 0x04 /**< DTM command parameter: Read maximum supported Tx Time. Minimum parameter value. */
|
||||
#define LE_TEST_SUPPORTED_TX_TIME_MAX_RANGE 0x07 /**< DTM command parameter: Read maximum supported Tx Time. Maximum parameter value. */
|
||||
#define LE_TEST_SUPPORTED_RX_OCTETS_MIN_RANGE 0x08 /**< DTM command parameter: Read maximum supported Rx Octets. Minimum parameter value. */
|
||||
#define LE_TEST_SUPPORTED_RX_OCTETS_MAX_RANGE 0x0B /**< DTM command parameter: Read maximum supported Rx Octets. Maximum parameter value. */
|
||||
#define LE_TEST_SUPPORTED_RX_TIME_MIN_RANGE 0x0C /**< DTM command parameter: Read maximum supported Rx Time. Minimum parameter value. */
|
||||
#define LE_TEST_SUPPORTED_RX_TIME_MAX_RANGE 0x0F /**< DTM command parameter: Read maximum supported Rx Time. Maximum parameter value. */
|
||||
#define LE_TEST_SUPPORTED_CTE_LENGTH 0x10 /**< DTM command parameter: Read maximum length of the Constant Tone Extension supported. */
|
||||
|
||||
#define LE_UPPER_BITS_MASK 0x0C /**< DTM command parameter: Upper bits mask. */
|
||||
#define LE_UPPER_BITS_POS 0x04 /**< DTM command parameter: Upper bits position. */
|
||||
|
||||
#define LE_TRANSMIT_POWER_LVL_MIN -127 /**< DTM command parameter: Minimum supported transmit power level. */
|
||||
#define LE_TRANSMIT_POWER_LVL_MAX 20 /**< DTM command parameter: Maximum supported transmit power level. */
|
||||
#define LE_TRANSMIT_POWER_LVL_SET_MIN 0x7E /**< DTM command parameter: Set minimum transmit power level. */
|
||||
#define LE_TRANSMIT_POWER_LVL_SET_MAX 0x7F /**< DTM command parameter: Set maximum taranmit poer level. */
|
||||
|
||||
#define LE_TRANSMIT_POWER_RESPONSE_LVL_POS (0x01) /** Position of power level in the DTM power level set response. */
|
||||
#define LE_TRANSMIT_POWER_RESPONSE_LVL_MASK (0x1FE) /** Mask of the power level in the DTM power level set respose. */
|
||||
#define LE_TRANSMIT_POWER_MAX_LVL_BIT (1 << 0x0A) /** Maximum power level bit in the power level set response. */
|
||||
#define LE_TRANSMIT_POWER_MIN_LVL_BIT (1 << 0x09) /** Minimum power level bit in the power level set response. */
|
||||
|
||||
#define LE_CTE_TYPE_MASK 0x03 /** Mask of the CTE type in the CTEInfo. */
|
||||
#define LE_CTE_TYPE_POS 0x06 /** Position of the CTE type in the CTEInfo. */
|
||||
#define LE_CTE_CTETIME_MASK 0x1F /** Mask of the CTE Time in the CTEInfo. */
|
||||
|
||||
#define LE_CTE_TYPE_AOA 0x00 /** CTE Type Angle of Arrival. */
|
||||
#define LE_CTE_TYPE_AOD_1US 0x01 /** CTE Type Angle of Departure with 1 us slot. */
|
||||
#define LE_CTE_TYPE_AOD_2US 0x02 /** CTE Type Angle of Departure with 2 us slot.*/
|
||||
|
||||
#define LE_CTE_LENGTH_MIN 0x02 /**< DTM command parameter: Minimum supported CTE length in 8 us units. */
|
||||
#define LE_CTE_LENGTH_MAX 0x14 /**< DTM command parameter: Maximum supported CTE length in 8 us units. */
|
||||
|
||||
#define LE_ANTENNA_NUMBER_MASK 0x3F /**< DTM command parameter: Mask of the Antenna Number. */
|
||||
#define LE_ANTENA_SWITCH_PATTERN_MASK 0x80 /**< DTM command parameter: Mask of the Antenna switch pattern. */
|
||||
|
||||
#define LE_TEST_ANTENNA_NUMBER_MIN 0x01 /**< Minimum antenna number. */
|
||||
#define LE_TEST_ANTENNA_NUMBER_MAX 0x4B /**< Maximum antenna number. */
|
||||
|
||||
|
||||
// Configuration options used as parameter 2
|
||||
// when cmd == LE_TRANSMITTER_TEST and payload == DTM_PKT_VENDORSPECIFIC
|
||||
// Configuration value, if any, is supplied in parameter 3
|
||||
|
||||
#define CARRIER_TEST 0 /**< Length=0 indicates a constant, unmodulated carrier until LE_TEST_END or LE_RESET */
|
||||
#define CARRIER_TEST_STUDIO 1 /**< nRFgo Studio uses value 1 in length field, to indicate a constant, unmodulated carrier until LE_TEST_END or LE_RESET */
|
||||
#define SET_TX_POWER 2 /**< Set transmission power, value -40..+4 dBm in steps of 4 */
|
||||
#define SELECT_TIMER 3 /**< Select on of the 16 MHz timers 0, 1 or 2 */
|
||||
#define SET_NRF21540_TX_POWER 4 /**< Set nRF21540 transmission power level. Choose between two predefinied option +20 dBm or +10 dBm. */
|
||||
|
||||
#define LE_PACKET_REPORTING_EVENT 0x8000 /**< DTM Packet reporting event, returned by the device to the tester. */
|
||||
#define LE_TEST_STATUS_EVENT_SUCCESS 0x0000 /**< DTM Status event, indicating success. */
|
||||
#define LE_TEST_STATUS_EVENT_ERROR 0x0001 /**< DTM Status event, indicating an error. */
|
||||
|
||||
#define DTM_PKT_PRBS9 0x00 /**< Bit pattern PRBS9. */
|
||||
#define DTM_PKT_0X0F 0x01 /**< Bit pattern 11110000 (LSB is the leftmost bit). */
|
||||
#define DTM_PKT_0X55 0x02 /**< Bit pattern 10101010 (LSB is the leftmost bit). */
|
||||
#define DTM_PKT_0XFF 0x03 /**< Bit pattern 11111111 (Used only for coded PHY). */
|
||||
#define DTM_PKT_VENDORSPECIFIC 0x03 /**< Vendor specific PKT field value. Nordic: Continuous carrier test, or configuration. */
|
||||
#define DTM_PKT_TYPE_VENDORSPECIFIC 0xFF /**< Vendor specific packet type for internal use. */
|
||||
|
||||
#define DTM_PKT_CP_BIT 0x20 /**< CTEInfo Preset bit. Indicates whether the CTEInfo field is present in the packet. */
|
||||
|
||||
// The pdu payload type for each bit pattern. Identical to the PKT value except pattern 0xFF which is 0x04.
|
||||
#define DTM_PDU_TYPE_PRBS9 0x00 /**< PDU payload type for bit pattern PRBS9. */
|
||||
#define DTM_PDU_TYPE_0X0F 0x01 /**< PDU payload type for bit pattern 11110000 (LSB is the leftmost bit). */
|
||||
#define DTM_PDU_TYPE_0X55 0x02 /**< PDU payload type for bit pattern 10101010 (LSB is the leftmost bit). */
|
||||
#define DTM_PDU_TYPE_0XFF 0x04 /**< PDU payload type for bit pattern 11111111 (Used only for coded PHY). */
|
||||
|
||||
/**@brief Return codes from dtm_cmd(). */
|
||||
#define DTM_SUCCESS 0x00 /**< Indicate that the DTM function completed with success. */
|
||||
#define DTM_ERROR_ILLEGAL_CHANNEL 0x01 /**< Physical channel number must be in the range 0..39. */
|
||||
#define DTM_ERROR_INVALID_STATE 0x02 /**< Sequencing error: Command is not valid now. */
|
||||
#define DTM_ERROR_ILLEGAL_LENGTH 0x03 /**< Payload size must be in the range 0..37. */
|
||||
#define DTM_ERROR_ILLEGAL_CONFIGURATION 0x04 /**< Parameter out of range (legal range is function dependent). */
|
||||
#define DTM_ERROR_UNINITIALIZED 0x05 /**< DTM module has not been initialized by the application. */
|
||||
|
||||
|
||||
#define DTM_LE_DATA_PACKET_LEN_EXTENSION 0x02 /**< DTM Status Response: LE Data Packet Length Extension feature supported. */
|
||||
#define DTM_LE_2M_PHY 0x04 /**< DTM Status Response: LE 2M PHY supported. */
|
||||
#define DTM_LE_STABLE_MODULATION_INDEX 0x08 /**< DTM Status Response: Transmitter has a Stable Modulation Index. */
|
||||
#define DTM_LE_CODED_PHY 0x10 /**< DTM Status Response: LE Coded PHY supported. */
|
||||
#define DTM_LE_CONSTANT_TONE_EXTENSION 0x20 /**< DTM Status Response: Constant Tone Extension Supported. */
|
||||
#define DTM_LE_ANTENNA_SWITCH 0x40 /**< DTM Status Response: Antenna switching supported. */
|
||||
#define DTM_LE_AOD_1US_TANSMISSION 0x80 /**< DTM Status Response: 1us switching supported for AoD tansmission. */
|
||||
#define DTM_LE_AOD_1US_RECEPTION 0x100 /**< DTM Status Response: 1us sampling supported for AoA reception. */
|
||||
#define DTM_LE_AOA_1US_RECEPTION 0x200 /**< DTM Status Response: 1us switching and sampling supported for AoA reception. */
|
||||
|
||||
/**@details The UART poll cycle in micro seconds.
|
||||
* A baud rate of e.g. 19200 bits / second, and 8 data bits, 1 start/stop bit, no flow control,
|
||||
* give the time to transmit a byte: 10 bits * 1/19200 = approx: 520 us.
|
||||
* To ensure no loss of bytes, the UART should be polled every 260 us.
|
||||
*/
|
||||
#if DTM_BITRATE == UARTE_BAUDRATE_BAUDRATE_Baud9600
|
||||
#define UART_POLL_CYCLE ((uint32_t)(10*1e6/9600/2))
|
||||
#elif DTM_BITRATE == UARTE_BAUDRATE_BAUDRATE_Baud14400
|
||||
#define UART_POLL_CYCLE ((uint32_t)(10*1e6/14400/2))
|
||||
#elif DTM_BITRATE == UARTE_BAUDRATE_BAUDRATE_Baud19200
|
||||
#define UART_POLL_CYCLE ((uint32_t)(10*1e6/19200/2))
|
||||
#elif DTM_BITRATE == UARTE_BAUDRATE_BAUDRATE_Baud28800
|
||||
#define UART_POLL_CYCLE ((uint32_t)(10*1e6/28800/2))
|
||||
#elif DTM_BITRATE == UARTE_BAUDRATE_BAUDRATE_Baud38400
|
||||
#define UART_POLL_CYCLE ((uint32_t)(10*1e6/38400/2))
|
||||
#elif DTM_BITRATE == UARTE_BAUDRATE_BAUDRATE_Baud57600
|
||||
#define UART_POLL_CYCLE ((uint32_t)(10*1e6/57600/2))
|
||||
#elif DTM_BITRATE == UARTE_BAUDRATE_BAUDRATE_Baud76800
|
||||
#define UART_POLL_CYCLE ((uint32_t)(10*1e6/768000/2))
|
||||
#elif DTM_BITRATE == UARTE_BAUDRATE_BAUDRATE_Baud115200
|
||||
#define UART_POLL_CYCLE ((uint32_t)(10*1e6/115200/2))
|
||||
#elif DTM_BITRATE == UARTE_BAUDRATE_BAUDRATE_Baud230400
|
||||
#define UART_POLL_CYCLE ((uint32_t)(10*1e6/230400/2))
|
||||
#elif DTM_BITRATE == UARTE_BAUDRATE_BAUDRATE_Baud250000
|
||||
#define UART_POLL_CYCLE ((uint32_t)(10*1e6/250000/2))
|
||||
#elif DTM_BITRATE == UARTE_BAUDRATE_BAUDRATE_Baud460800
|
||||
#define UART_POLL_CYCLE ((uint32_t)(10*1e6/460800/2))
|
||||
#elif DTM_BITRATE == UARTE_BAUDRATE_BAUDRATE_Baud921600
|
||||
#define UART_POLL_CYCLE ((uint32_t)(10*1e6/921600/2))
|
||||
#elif DTM_BITRATE == UARTE_BAUDRATE_BAUDRATE_Baud1M
|
||||
#define UART_POLL_CYCLE ((uint32_t)(10*1e6/1e6/2))
|
||||
#else
|
||||
// It is possible to find values that work for other baud rates, but the formula above is not
|
||||
// guaranteed to work for all values. Suitable values may have to be found by trial and error.
|
||||
#error "Unsupported baud rate set."
|
||||
#endif
|
||||
|
||||
// Note: DTM_PKT_VENDORSPECIFIC, is not a packet type
|
||||
#define PACKET_TYPE_MAX DTM_PKT_0XFF /**< Highest value allowed as DTM Packet type. */
|
||||
|
||||
/** @brief BLE DTM event type. */
|
||||
typedef uint32_t dtm_event_t; /**< Type for handling DTM event. */
|
||||
|
||||
/** @brief BLE DTM frequency type. */
|
||||
typedef uint32_t dtm_freq_t; /**< Physical channel, valid range: 0..39. */
|
||||
|
||||
/**@brief BLE DTM packet types. */
|
||||
typedef uint32_t dtm_pkt_type_t; /**< Type for holding the requested DTM payload type.*/
|
||||
|
||||
/**@brief BLE DTM nRF21540 power mode. */
|
||||
typedef enum
|
||||
{
|
||||
NRF21540_POWER_MODE_A = 0x01, /**< Set nRF21540 transmission power level to the A(20 dBm) predefinied value. */
|
||||
NRF21540_POWER_MODE_B = 0x02 /**< Set nRF21540 transmission power level to the B(10 dBm) predefinied value. */
|
||||
} dtm_nrf21540_power_mode_t;
|
||||
|
||||
|
||||
/**@brief Function for initializing or re-initializing DTM module
|
||||
*
|
||||
* @return DTM_SUCCESS on successful initialization of the DTM module.
|
||||
*/
|
||||
uint32_t dtm_init(void);
|
||||
|
||||
|
||||
/**@brief Function for giving control to dtmlib for handling timer and radio events.
|
||||
* Will return to caller at 625us intervals or whenever another event than radio occurs
|
||||
* (such as UART input). Function will put MCU to sleep between events.
|
||||
*
|
||||
* @return Time counter, incremented every 625 us.
|
||||
*/
|
||||
uint32_t dtm_wait(void);
|
||||
|
||||
|
||||
/**@brief Function for calling when a complete command has been prepared by the Tester.
|
||||
*
|
||||
* @param[in] cmd received 16-bit complete command from the Tester.
|
||||
*
|
||||
* @return DTM_SUCCESS or one of the DTM_ERROR_ values
|
||||
*/
|
||||
uint32_t dtm_cmd(uint16_t cmd);
|
||||
|
||||
|
||||
/**@brief Function for reading the result of a DTM command
|
||||
*
|
||||
* @param[out] p_dtm_event Pointer to buffer for 16 bit event code according to DTM standard.
|
||||
*
|
||||
* @return true: new event, false: no event since last call, this event has been read earlier
|
||||
*/
|
||||
bool dtm_event_get(dtm_event_t * p_dtm_event);
|
||||
|
||||
|
||||
/**@brief Function for configuring the timer to use.
|
||||
*
|
||||
* @note Must be called when no DTM test is running.
|
||||
*
|
||||
* @param[in] new_timer Index (0..2) of timer to be used by the DTM library
|
||||
*
|
||||
* @return true: success, new timer was selected, false: parameter error
|
||||
*/
|
||||
bool dtm_set_timer(uint32_t new_timer);
|
||||
|
||||
|
||||
/**@brief Function for configuring the transmit power.
|
||||
*
|
||||
* @note Must be called when no DTM test is running.
|
||||
*
|
||||
* @param[in] new_tx_power New output level, +4..-40, in steps of 4.
|
||||
*
|
||||
* @return true: tx power setting changed, false: parameter error
|
||||
*/
|
||||
bool dtm_set_txpower(uint32_t new_tx_power);
|
||||
|
||||
|
||||
/**@brief Function for choosing nRF21540 power level.
|
||||
*
|
||||
* @note Must be called when no DTM test is running and nRF21540 is used.
|
||||
*
|
||||
* @param[in] power_mode nRF21540 power mode.
|
||||
*
|
||||
* @return true: tx power mode setting changed, false: parameter error
|
||||
*/
|
||||
bool dtm_set_nrf21450_power_mode(dtm_nrf21540_power_mode_t power_mode);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // BLE_DTM_H__
|
||||
|
||||
/** @} */
|
||||
103
components/ble/ble_dtm/ble_dtm_hw.h
Normal file
103
components/ble/ble_dtm/ble_dtm_hw.h
Normal file
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* 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 ble_dtm_hw Direct Test Mode HW
|
||||
* @{
|
||||
* @ingroup ble_sdk_lib
|
||||
* @brief Module contains hardware related function for testing RF/PHY using DTM commands.
|
||||
*/
|
||||
|
||||
#ifndef BLE_DTM_HW_H__
|
||||
#define BLE_DTM_HW_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "nrf.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/**@brief Function for selecting a timer resource.
|
||||
* This function may be called directly, or through dtm_cmd() specifying
|
||||
* DTM_PKT_VENDORSPECIFIC as payload, SELECT_TIMER as length, and the timer as freq
|
||||
*
|
||||
* @param[out] mp_timer Pointer to timer instance used in dtm source file.
|
||||
* @param[out] m_timer_irq Pointer to timer interrupt related to mp_timer.
|
||||
* @param[in] new_timer Timer id for the timer to use.
|
||||
*
|
||||
* @retval true if the timer was successfully changed.
|
||||
* @retval false if the error occurs.
|
||||
*/
|
||||
|
||||
bool dtm_hw_set_timer(NRF_TIMER_Type ** mp_timer, IRQn_Type * m_timer_irq, uint32_t new_timer);
|
||||
|
||||
|
||||
/**@brief Function for turning off radio test.
|
||||
* This function is platform depending. For now only nRF51 requieres this special function.
|
||||
*/
|
||||
void dtm_turn_off_test(void);
|
||||
|
||||
|
||||
/**@brief Function for setting constant carrier in radio settings.
|
||||
* This function is used to handle vendor specific command testing continous carrier without
|
||||
* a modulated signal.
|
||||
*/
|
||||
void dtm_constant_carrier(void);
|
||||
|
||||
|
||||
/**@brief Function for validating tx power and radio move settings.
|
||||
* @param[in] m_tx_power TX power for transmission test.
|
||||
* @param[in] m_radio_mode Radio mode value.
|
||||
*
|
||||
* @retval DTM_SUCCESS if input parameters values are correct.
|
||||
* @retval DTM_ERROR_ILLEGAL_CONFIGURATION if input parameters values are not correct.
|
||||
*/
|
||||
uint32_t dtm_radio_validate(uint32_t m_tx_power, uint8_t m_radio_mode);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // BLE_DTM_HW_H__
|
||||
|
||||
/** @} */
|
||||
120
components/ble/ble_dtm/ble_dtm_hw_nrf51.c
Normal file
120
components/ble/ble_dtm/ble_dtm_hw_nrf51.c
Normal file
@@ -0,0 +1,120 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#include "ble_dtm_hw.h"
|
||||
#include "ble_dtm.h"
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include "nrf.h"
|
||||
|
||||
|
||||
void dtm_turn_off_test()
|
||||
{
|
||||
NRF_RADIO->TEST = 0;
|
||||
}
|
||||
|
||||
|
||||
void dtm_constant_carrier()
|
||||
{
|
||||
NRF_RADIO->TEST = (RADIO_TEST_PLL_LOCK_Enabled << RADIO_TEST_PLL_LOCK_Pos) |
|
||||
(RADIO_TEST_CONST_CARRIER_Enabled << RADIO_TEST_CONST_CARRIER_Pos);
|
||||
}
|
||||
|
||||
|
||||
uint32_t dtm_radio_validate(int32_t m_tx_power, uint8_t m_radio_mode)
|
||||
{
|
||||
// Handle BLE Radio tuning parameters from production for DTM if required.
|
||||
// Only needed for DTM without SoftDevice, as the SoftDevice normally handles this.
|
||||
// PCN-083.
|
||||
if ( ((NRF_FICR->OVERRIDEEN) & FICR_OVERRIDEEN_BLE_1MBIT_Msk) == FICR_OVERRIDEEN_BLE_1MBIT_Override)
|
||||
{
|
||||
NRF_RADIO->OVERRIDE0 = NRF_FICR->BLE_1MBIT[0];
|
||||
NRF_RADIO->OVERRIDE1 = NRF_FICR->BLE_1MBIT[1];
|
||||
NRF_RADIO->OVERRIDE2 = NRF_FICR->BLE_1MBIT[2];
|
||||
NRF_RADIO->OVERRIDE3 = NRF_FICR->BLE_1MBIT[3];
|
||||
NRF_RADIO->OVERRIDE4 = NRF_FICR->BLE_1MBIT[4];
|
||||
}
|
||||
|
||||
// Initializing code below is quite generic - for BLE, the values are fixed, and expressions
|
||||
// are constant. Non-constant values are essentially set in radio_prepare().
|
||||
if (!(m_tx_power == RADIO_TXPOWER_TXPOWER_0dBm ||
|
||||
m_tx_power == RADIO_TXPOWER_TXPOWER_Pos4dBm ||
|
||||
m_tx_power == RADIO_TXPOWER_TXPOWER_Neg30dBm ||
|
||||
m_tx_power == RADIO_TXPOWER_TXPOWER_Neg20dBm ||
|
||||
m_tx_power == RADIO_TXPOWER_TXPOWER_Neg16dBm ||
|
||||
m_tx_power == RADIO_TXPOWER_TXPOWER_Neg12dBm ||
|
||||
m_tx_power == RADIO_TXPOWER_TXPOWER_Neg8dBm ||
|
||||
m_tx_power == RADIO_TXPOWER_TXPOWER_Neg4dBm
|
||||
) ||
|
||||
(m_radio_mode > RADIO_MODE_MODE_Ble_1Mbit) // Values 0 - 2: Proprietary mode, 3 (last valid): BLE
|
||||
)
|
||||
{
|
||||
return DTM_ERROR_ILLEGAL_CONFIGURATION;
|
||||
}
|
||||
|
||||
return DTM_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
bool dtm_hw_set_timer(NRF_TIMER_Type ** mp_timer, IRQn_Type * m_timer_irq, uint32_t new_timer)
|
||||
{
|
||||
if (new_timer == 0)
|
||||
{
|
||||
*mp_timer = NRF_TIMER0;
|
||||
*m_timer_irq = TIMER0_IRQn;
|
||||
}
|
||||
else if (new_timer == 1)
|
||||
{
|
||||
*mp_timer = NRF_TIMER1;
|
||||
*m_timer_irq = TIMER1_IRQn;
|
||||
}
|
||||
else if (new_timer == 2)
|
||||
{
|
||||
*mp_timer = NRF_TIMER2;
|
||||
*m_timer_irq = TIMER2_IRQn;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Parameter error: Only TIMER 0, 1, 2 provided by nRF51
|
||||
return false;
|
||||
}
|
||||
// New timer has been selected:
|
||||
return true;
|
||||
}
|
||||
|
||||
140
components/ble/ble_dtm/ble_dtm_hw_nrf52.c
Normal file
140
components/ble/ble_dtm/ble_dtm_hw_nrf52.c
Normal file
@@ -0,0 +1,140 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#include "ble_dtm_hw.h"
|
||||
#include "ble_dtm.h"
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include "nrf.h"
|
||||
|
||||
|
||||
void dtm_turn_off_test()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void dtm_constant_carrier()
|
||||
{
|
||||
NRF_RADIO->MODECNF0 = (RADIO_MODECNF0_RU_Default << RADIO_MODECNF0_RU_Pos) |
|
||||
(RADIO_MODECNF0_DTX_Center << RADIO_MODECNF0_DTX_Pos);
|
||||
}
|
||||
|
||||
|
||||
uint32_t dtm_radio_validate(uint32_t m_tx_power, uint8_t m_radio_mode)
|
||||
{
|
||||
// Initializing code below is quite generic - for BLE, the values are fixed, and expressions
|
||||
// are constant. Non-constant values are essentially set in radio_prepare().
|
||||
if (!(
|
||||
#if defined(NRF52840_XXAA) || defined(NRF52833_XXAA) || defined(NRF52820_XXAA)
|
||||
m_tx_power == RADIO_TXPOWER_TXPOWER_Pos8dBm ||
|
||||
m_tx_power == RADIO_TXPOWER_TXPOWER_Pos7dBm ||
|
||||
m_tx_power == RADIO_TXPOWER_TXPOWER_Pos6dBm ||
|
||||
m_tx_power == RADIO_TXPOWER_TXPOWER_Pos5dBm ||
|
||||
#endif //defined(NRF52840_XXAA) || defined(NRF52833_XXAA) || defined(NRF52820_XXAA)
|
||||
m_tx_power == RADIO_TXPOWER_TXPOWER_Pos4dBm ||
|
||||
m_tx_power == RADIO_TXPOWER_TXPOWER_Pos3dBm ||
|
||||
#if defined(NRF52840_XXAA) || defined(NRF52833_XXAA) || defined(NRF52820_XXAA)
|
||||
m_tx_power == RADIO_TXPOWER_TXPOWER_Pos2dBm ||
|
||||
#endif //defined(NRF52840_XXAA) || defined(NRF52833_XXAA)A || defined(NRF52820_XXAA)
|
||||
m_tx_power == RADIO_TXPOWER_TXPOWER_0dBm ||
|
||||
m_tx_power == RADIO_TXPOWER_TXPOWER_Neg4dBm ||
|
||||
m_tx_power == RADIO_TXPOWER_TXPOWER_Neg8dBm ||
|
||||
m_tx_power == RADIO_TXPOWER_TXPOWER_Neg12dBm ||
|
||||
m_tx_power == RADIO_TXPOWER_TXPOWER_Neg16dBm ||
|
||||
m_tx_power == RADIO_TXPOWER_TXPOWER_Neg20dBm ||
|
||||
m_tx_power == RADIO_TXPOWER_TXPOWER_Neg30dBm ||
|
||||
m_tx_power == RADIO_TXPOWER_TXPOWER_Neg40dBm
|
||||
) ||
|
||||
|
||||
!(
|
||||
#if defined(NRF52840_XXAA) || defined(NRF52811_XXAA) || defined(NRF52833_XXAA) || defined(NRF52820_XXAA)
|
||||
m_radio_mode == RADIO_MODE_MODE_Ble_LR125Kbit ||
|
||||
m_radio_mode == RADIO_MODE_MODE_Ble_LR500Kbit ||
|
||||
#endif //defined(NRF52840_XXAA) || defined(NRF52811_XXAA) || defined(NRF52833_XXAA) || defined(NRF52820_XXAA)
|
||||
m_radio_mode == RADIO_MODE_MODE_Ble_1Mbit ||
|
||||
m_radio_mode == RADIO_MODE_MODE_Ble_2Mbit
|
||||
)
|
||||
)
|
||||
{
|
||||
return DTM_ERROR_ILLEGAL_CONFIGURATION;
|
||||
}
|
||||
|
||||
return DTM_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
bool dtm_hw_set_timer(NRF_TIMER_Type ** mp_timer, IRQn_Type * m_timer_irq, uint32_t new_timer)
|
||||
{
|
||||
if (new_timer == 0)
|
||||
{
|
||||
*mp_timer = NRF_TIMER0;
|
||||
*m_timer_irq = TIMER0_IRQn;
|
||||
}
|
||||
else if (new_timer == 1)
|
||||
{
|
||||
*mp_timer = NRF_TIMER1;
|
||||
*m_timer_irq = TIMER1_IRQn;
|
||||
}
|
||||
else if (new_timer == 2)
|
||||
{
|
||||
*mp_timer = NRF_TIMER2;
|
||||
*m_timer_irq = TIMER2_IRQn;
|
||||
}
|
||||
#if !defined(NRF52810_XXAA) && !defined(NRF52811_XXAA)
|
||||
else if (new_timer == 3)
|
||||
{
|
||||
*mp_timer = NRF_TIMER3;
|
||||
*m_timer_irq = TIMER3_IRQn;
|
||||
}
|
||||
#if !defined(NRF52820_XXAA)
|
||||
else if (new_timer == 4)
|
||||
{
|
||||
*mp_timer = NRF_TIMER4;
|
||||
*m_timer_irq = TIMER4_IRQn;
|
||||
}
|
||||
#endif //!defined(NRF52820_XXAA)
|
||||
#endif //!defined(NRF52810_XXAA) && !defined(NRF52811_XXAA)
|
||||
else
|
||||
{
|
||||
// Parameter error: Only TIMER 0, 1, 2, 3 and 4 provided by nRF52
|
||||
return false;
|
||||
}
|
||||
// New timer has been selected:
|
||||
return true;
|
||||
}
|
||||
79
components/ble/ble_link_ctx_manager/ble_link_ctx_manager.c
Normal file
79
components/ble/ble_link_ctx_manager/ble_link_ctx_manager.c
Normal file
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* 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 "ble_link_ctx_manager.h"
|
||||
#include "sdk_common.h"
|
||||
|
||||
|
||||
ret_code_t blcm_link_ctx_get(blcm_link_ctx_storage_t const * const p_link_ctx_storage,
|
||||
uint16_t const conn_handle,
|
||||
void ** const pp_ctx_data)
|
||||
{
|
||||
uint8_t conn_id;
|
||||
|
||||
if (pp_ctx_data == NULL)
|
||||
{
|
||||
return NRF_ERROR_NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
*pp_ctx_data = NULL;
|
||||
}
|
||||
|
||||
VERIFY_PARAM_NOT_NULL(p_link_ctx_storage);
|
||||
VERIFY_PARAM_NOT_NULL(p_link_ctx_storage->p_ctx_data_pool);
|
||||
VERIFY_TRUE((p_link_ctx_storage->link_ctx_size % BYTES_PER_WORD) == 0, NRF_ERROR_INVALID_PARAM);
|
||||
|
||||
conn_id = ble_conn_state_conn_idx(conn_handle);
|
||||
|
||||
if (conn_id == BLE_CONN_STATE_MAX_CONNECTIONS)
|
||||
{
|
||||
return NRF_ERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (conn_id >= p_link_ctx_storage->max_links_cnt)
|
||||
{
|
||||
return NRF_ERROR_NO_MEM;
|
||||
}
|
||||
|
||||
*pp_ctx_data = (void *) ((uint8_t *) p_link_ctx_storage->p_ctx_data_pool +
|
||||
conn_id * p_link_ctx_storage->link_ctx_size);
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
127
components/ble/ble_link_ctx_manager/ble_link_ctx_manager.h
Normal file
127
components/ble/ble_link_ctx_manager/ble_link_ctx_manager.h
Normal file
@@ -0,0 +1,127 @@
|
||||
/**
|
||||
* 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 ble_link_ctx_manager BLE Link Context Manager
|
||||
* @{
|
||||
* @ingroup ble_sdk_lib
|
||||
* @brief Storage for link-related data.
|
||||
*
|
||||
* @details BLE Link Context Manager can be used as a simple storage for link-related data.
|
||||
* Each link context data is uniquely identified within the storage by its connection
|
||||
* handle and can be retrieved from it by using this handle.
|
||||
*
|
||||
*/
|
||||
#ifndef BLE_LINK_CTX_MANAGER_H__
|
||||
#define BLE_LINK_CTX_MANAGER_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include "ble_conn_state.h"
|
||||
#include "sdk_errors.h"
|
||||
|
||||
|
||||
/**@brief Macro for defining a blcm_link_ctx_storage instance.
|
||||
*
|
||||
* @param[in] _name Name of the instance.
|
||||
* @param[in] _max_clients Maximum number of clients connected at a time.
|
||||
* @param[in] _link_ctx_size Context size in bytes for a single link.
|
||||
*/
|
||||
#define BLE_LINK_CTX_MANAGER_DEF(_name, _max_clients, _link_ctx_size) \
|
||||
STATIC_ASSERT((_max_clients) <= BLE_CONN_STATE_MAX_CONNECTIONS); \
|
||||
static uint32_t CONCAT_2(_name, _ctx_data_pool)[(_max_clients)*BYTES_TO_WORDS(_link_ctx_size)]; \
|
||||
static blcm_link_ctx_storage_t _name = \
|
||||
{ \
|
||||
.p_ctx_data_pool = CONCAT_2(_name, _ctx_data_pool), \
|
||||
.max_links_cnt = (_max_clients), \
|
||||
.link_ctx_size = sizeof(CONCAT_2(_name, _ctx_data_pool))/(_max_clients) \
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Type of description that is used for registry of all current connections.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
void * const p_ctx_data_pool; /**< Pointer to links context memory pool. */
|
||||
uint8_t const max_links_cnt; /**< Maximum number of concurrent links. */
|
||||
uint16_t const link_ctx_size; /**< Context size in bytes for a single link (word-aligned). */
|
||||
} blcm_link_ctx_storage_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Function for getting the link context from the link registry.
|
||||
*
|
||||
* This function finds the link context in the registry. The link to find is identified by the
|
||||
* connection handle within the registry.
|
||||
*
|
||||
* The context is preserved for the lifetime of the connection. When a new connection occurs, the
|
||||
* value of its context is undefined, and should be initialized.
|
||||
*
|
||||
* @param[in] p_link_ctx_storage Pointer to the link storage descriptor.
|
||||
* @param[in] conn_handle Connection whose context to find.
|
||||
* @param[out] pp_ctx_data Pointer to data with context for the connection.
|
||||
*
|
||||
* @retval NRF_ERROR_NULL If \p p_link_ctx_storage is NULL or contains a NULL pointer, or if
|
||||
* \p pp_ctx_data is NULL.
|
||||
* @retval NRF_ERROR_INVALID_PARAM If \p p_link_ctx_storage::link_ctx_size is not multiple of word
|
||||
* size.
|
||||
* @retval NRF_ERROR_NOT_FOUND If \p conn_handle does not refer to an active or recently
|
||||
* disconnected link.
|
||||
* @retval NRF_ERROR_NO_MEM If there is not enough memory to store context for the given
|
||||
* connection handle. This can happen if the number of links is
|
||||
* greater than \p p_link_ctx_storage::max_links_cnt.
|
||||
* @retval NRF_SUCCESS If the operation was successful.
|
||||
*/
|
||||
ret_code_t blcm_link_ctx_get(blcm_link_ctx_storage_t const * const p_link_ctx_storage,
|
||||
uint16_t const conn_handle,
|
||||
void ** const pp_ctx_data);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // BLE_LINK_CTX_MANAGER_H__
|
||||
|
||||
/** @} */
|
||||
87
components/ble/ble_racp/ble_racp.c
Normal file
87
components/ble/ble_racp/ble_racp.c
Normal file
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 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_RACP)
|
||||
#include "ble_racp.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
void ble_racp_decode(uint8_t data_len, uint8_t const * p_data, ble_racp_value_t * p_racp_val)
|
||||
{
|
||||
p_racp_val->opcode = 0xFF;
|
||||
p_racp_val->operator = 0xFF;
|
||||
p_racp_val->operand_len = 0;
|
||||
p_racp_val->p_operand = NULL;
|
||||
|
||||
if (data_len > 0)
|
||||
{
|
||||
p_racp_val->opcode = p_data[0];
|
||||
}
|
||||
if (data_len > 1)
|
||||
{
|
||||
p_racp_val->operator = p_data[1]; //lint !e415
|
||||
}
|
||||
if (data_len > 2)
|
||||
{
|
||||
p_racp_val->operand_len = data_len - 2;
|
||||
p_racp_val->p_operand = (uint8_t*)&p_data[2]; //lint !e416
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint8_t ble_racp_encode(const ble_racp_value_t * p_racp_val, uint8_t * p_data)
|
||||
{
|
||||
uint8_t len = 0;
|
||||
int i;
|
||||
|
||||
if (p_data != NULL)
|
||||
{
|
||||
p_data[len++] = p_racp_val->opcode;
|
||||
p_data[len++] = p_racp_val->operator;
|
||||
|
||||
for (i = 0; i < p_racp_val->operand_len; i++)
|
||||
{
|
||||
p_data[len++] = p_racp_val->p_operand[i];
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
#endif // NRF_MODULE_ENABLED(BLE_RACP)
|
||||
136
components/ble/ble_racp/ble_racp.h
Normal file
136
components/ble/ble_racp/ble_racp.h
Normal file
@@ -0,0 +1,136 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 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 ble_racp Record Access Control Point
|
||||
* @{
|
||||
* @ingroup ble_sdk_lib
|
||||
* @brief Record Access Control Point library.
|
||||
*/
|
||||
|
||||
#ifndef BLE_RACP_H__
|
||||
#define BLE_RACP_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "ble.h"
|
||||
#include "ble_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**@brief Record Access Control Point opcodes. */
|
||||
#define RACP_OPCODE_RESERVED 0 /**< Record Access Control Point opcode - Reserved for future use. */
|
||||
#define RACP_OPCODE_REPORT_RECS 1 /**< Record Access Control Point opcode - Report stored records. */
|
||||
#define RACP_OPCODE_DELETE_RECS 2 /**< Record Access Control Point opcode - Delete stored records. */
|
||||
#define RACP_OPCODE_ABORT_OPERATION 3 /**< Record Access Control Point opcode - Abort operation. */
|
||||
#define RACP_OPCODE_REPORT_NUM_RECS 4 /**< Record Access Control Point opcode - Report number of stored records. */
|
||||
#define RACP_OPCODE_NUM_RECS_RESPONSE 5 /**< Record Access Control Point opcode - Number of stored records response. */
|
||||
#define RACP_OPCODE_RESPONSE_CODE 6 /**< Record Access Control Point opcode - Response code. */
|
||||
|
||||
/**@brief Record Access Control Point operators. */
|
||||
#define RACP_OPERATOR_NULL 0 /**< Record Access Control Point operator - Null. */
|
||||
#define RACP_OPERATOR_ALL 1 /**< Record Access Control Point operator - All records. */
|
||||
#define RACP_OPERATOR_LESS_OR_EQUAL 2 /**< Record Access Control Point operator - Less than or equal to. */
|
||||
#define RACP_OPERATOR_GREATER_OR_EQUAL 3 /**< Record Access Control Point operator - Greater than or equal to. */
|
||||
#define RACP_OPERATOR_RANGE 4 /**< Record Access Control Point operator - Within range of (inclusive). */
|
||||
#define RACP_OPERATOR_FIRST 5 /**< Record Access Control Point operator - First record (i.e. oldest record). */
|
||||
#define RACP_OPERATOR_LAST 6 /**< Record Access Control Point operator - Last record (i.e. most recent record). */
|
||||
#define RACP_OPERATOR_RFU_START 7 /**< Record Access Control Point operator - Start of Reserved for Future Use area. */
|
||||
|
||||
/**@brief Record Access Control Point Operand Filter Type Value. */
|
||||
#define RACP_OPERAND_FILTER_TYPE_TIME_OFFSET 1 /**< Record Access Control Point Operand Filter Type Value - Time Offset. */
|
||||
#define RACP_OPERAND_FILTER_TYPE_FACING_TIME 2 /**< Record Access Control Point Operand Filter Type Value - User Facing Time. */
|
||||
|
||||
/**@brief Record Access Control Point response codes. */
|
||||
#define RACP_RESPONSE_RESERVED 0 /**< Record Access Control Point response code - Reserved for future use. */
|
||||
#define RACP_RESPONSE_SUCCESS 1 /**< Record Access Control Point response code - Successful operation. */
|
||||
#define RACP_RESPONSE_OPCODE_UNSUPPORTED 2 /**< Record Access Control Point response code - Unsupported op code received. */
|
||||
#define RACP_RESPONSE_INVALID_OPERATOR 3 /**< Record Access Control Point response code - Operator not valid for service. */
|
||||
#define RACP_RESPONSE_OPERATOR_UNSUPPORTED 4 /**< Record Access Control Point response code - Unsupported operator. */
|
||||
#define RACP_RESPONSE_INVALID_OPERAND 5 /**< Record Access Control Point response code - Operand not valid for service. */
|
||||
#define RACP_RESPONSE_NO_RECORDS_FOUND 6 /**< Record Access Control Point response code - No matching records found. */
|
||||
#define RACP_RESPONSE_ABORT_FAILED 7 /**< Record Access Control Point response code - Abort could not be completed. */
|
||||
#define RACP_RESPONSE_PROCEDURE_NOT_DONE 8 /**< Record Access Control Point response code - Procedure could not be completed. */
|
||||
#define RACP_RESPONSE_OPERAND_UNSUPPORTED 9 /**< Record Access Control Point response code - Unsupported operand. */
|
||||
|
||||
/**@brief Record Access Control Point value structure. */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t opcode; /**< Op Code. */
|
||||
uint8_t operator; /**< Operator. */
|
||||
uint8_t operand_len; /**< Length of the operand. */
|
||||
uint8_t * p_operand; /**< Pointer to the operand. */
|
||||
} ble_racp_value_t;
|
||||
|
||||
/**@brief Function for decoding a Record Access Control Point write.
|
||||
*
|
||||
* @details This call decodes a write to the Record Access Control Point.
|
||||
*
|
||||
* @param[in] data_len Length of data in received write.
|
||||
* @param[in] p_data Pointer to received data.
|
||||
* @param[out] p_racp_val Pointer to decoded Record Access Control Point write.
|
||||
* @note This does not do a data copy. It assumes the data pointed to by
|
||||
* p_data is persistant until no longer needed.
|
||||
*/
|
||||
void ble_racp_decode(uint8_t data_len, uint8_t const * p_data, ble_racp_value_t * p_racp_val);
|
||||
|
||||
/**@brief Function for encoding a Record Access Control Point response.
|
||||
*
|
||||
* @details This call encodes a response from the Record Access Control Point response.
|
||||
*
|
||||
* @param[in] p_racp_val Pointer to Record Access Control Point to encode.
|
||||
* @param[out] p_data Pointer to where encoded data is written.
|
||||
* NOTE! It is calling routines respsonsibility to make sure.
|
||||
*
|
||||
* @return Length of encoded data.
|
||||
*/
|
||||
uint8_t ble_racp_encode(const ble_racp_value_t * p_racp_val, uint8_t * p_data);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // BLE_RACP_H__
|
||||
|
||||
/** @} */
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 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 "ble_radio_notification.h"
|
||||
#include "nrf_nvic.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
static bool m_radio_active = false; /**< Current radio state. */
|
||||
static ble_radio_notification_evt_handler_t m_evt_handler = NULL; /**< Application event handler for handling Radio Notification events. */
|
||||
|
||||
|
||||
void SWI1_IRQHandler(void)
|
||||
{
|
||||
m_radio_active = !m_radio_active;
|
||||
if (m_evt_handler != NULL)
|
||||
{
|
||||
m_evt_handler(m_radio_active);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_radio_notification_init(uint32_t irq_priority,
|
||||
uint8_t distance,
|
||||
ble_radio_notification_evt_handler_t evt_handler)
|
||||
{
|
||||
uint32_t err_code;
|
||||
|
||||
m_evt_handler = evt_handler;
|
||||
|
||||
// Initialize Radio Notification software interrupt
|
||||
err_code = sd_nvic_ClearPendingIRQ(SWI1_IRQn);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
|
||||
err_code = sd_nvic_SetPriority(SWI1_IRQn, irq_priority);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
|
||||
err_code = sd_nvic_EnableIRQ(SWI1_IRQn);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
|
||||
// Configure the event
|
||||
return sd_radio_notification_cfg_set(NRF_RADIO_NOTIFICATION_TYPE_INT_ON_BOTH, distance);
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 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 ble_radio_notification Radio Notification Event Handler
|
||||
* @{
|
||||
* @ingroup ble_sdk_lib
|
||||
* @brief Module for propagating Radio Notification events to the application.
|
||||
*/
|
||||
|
||||
#ifndef BLE_RADIO_NOTIFICATION_H__
|
||||
#define BLE_RADIO_NOTIFICATION_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "nrf_soc.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**@brief Application radio notification event handler type. */
|
||||
typedef void (*ble_radio_notification_evt_handler_t) (bool radio_active);
|
||||
|
||||
/**@brief Function for initializing the Radio Notification module.
|
||||
*
|
||||
* @param[in] irq_priority Interrupt priority for the Radio Notification interrupt handler.
|
||||
* @param[in] distance The time from an Active event until the radio is activated.
|
||||
* @param[in] evt_handler Handler to be executed when a radio notification event has been
|
||||
* received.
|
||||
*
|
||||
* @return NRF_SUCCESS on successful initialization, otherwise an error code.
|
||||
*/
|
||||
uint32_t ble_radio_notification_init(uint32_t irq_priority,
|
||||
uint8_t distance,
|
||||
ble_radio_notification_evt_handler_t evt_handler);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // BLE_RADIO_NOTIFICATION_H__
|
||||
|
||||
/** @} */
|
||||
390
components/ble/ble_services/ble_ancs_c/ancs_app_attr_get.c
Normal file
390
components/ble/ble_services/ble_ancs_c/ancs_app_attr_get.c
Normal file
@@ -0,0 +1,390 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
/* Disclaimer: This client implementation of the Apple Notification Center Service can and will be changed at any time by Nordic Semiconductor ASA.
|
||||
* Server implementations such as the ones found in iOS can be changed at any time by Apple and may cause this client implementation to stop working.
|
||||
*/
|
||||
|
||||
#include "ancs_app_attr_get.h"
|
||||
#include "nrf_ble_ancs_c.h"
|
||||
#include "sdk_macros.h"
|
||||
#include "nrf_log.h"
|
||||
#include "string.h"
|
||||
|
||||
#define GATTC_OPCODE_SIZE 1 /**< Size of the GATTC OPCODE. */
|
||||
#define GATTC_ATTR_HANDLE_SIZE 4 /**< Size of the attribute handle. */
|
||||
|
||||
|
||||
#define ANCS_GATTC_WRITE_PAYLOAD_LEN_MAX (BLE_GATT_ATT_MTU_DEFAULT - GATTC_OPCODE_SIZE - GATTC_ATTR_HANDLE_SIZE) /**< Maximum length of the data that can be sent in one write. */
|
||||
|
||||
|
||||
/**@brief Enumeration for keeping track of the state-based encoding while requesting app attributes. */
|
||||
typedef enum
|
||||
{
|
||||
APP_ATTR_COMMAND_ID, /**< Currently encoding the command ID. */
|
||||
APP_ATTR_APP_ID, /**< Currently encoding the app ID. */
|
||||
APP_ATTR_ATTR_ID, /**< Currently encoding the attribute ID. */
|
||||
APP_ATTR_DONE /**< Encoding done. */
|
||||
}encode_app_attr_t;
|
||||
|
||||
|
||||
/**@brief Function for determining whether an attribute is requested.
|
||||
*
|
||||
* @param[in] p_ancs iOS notification structure. This structure must be supplied by
|
||||
* the application. It identifies the particular client instance to use.
|
||||
*
|
||||
* @return True If it is requested
|
||||
* @return False If it is not requested.
|
||||
*/
|
||||
static bool app_attr_is_requested(ble_ancs_c_t * p_ancs, uint32_t attr_id)
|
||||
{
|
||||
if (p_ancs->ancs_app_attr_list[attr_id].get == true)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**@brief Function for counting the number of attributes that will be requested upon a "get app attributes" command.
|
||||
*
|
||||
* @param[in] p_ancs iOS notification structure. This structure must be supplied by
|
||||
* the application. It identifies the particular client instance to use.
|
||||
*
|
||||
* @return Number of attributes that will be requested upon a "get app attributes" command.
|
||||
*/
|
||||
static uint32_t app_attr_nb_to_get(ble_ancs_c_t * p_ancs)
|
||||
{
|
||||
uint32_t attr_nb_to_get = 0;
|
||||
for (uint32_t i = 0; i < (sizeof(p_ancs->ancs_app_attr_list)/sizeof(ble_ancs_c_attr_list_t)); i++)
|
||||
{
|
||||
if (app_attr_is_requested(p_ancs,i))
|
||||
{
|
||||
attr_nb_to_get++;
|
||||
}
|
||||
}
|
||||
return attr_nb_to_get;
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for encoding the command ID as part of assembling a "get app attributes" command.
|
||||
*
|
||||
* @param[in] p_ancs iOS notification structure. This structure must be supplied by
|
||||
* the application. It identifies the particular client instance to use.
|
||||
* @param[in] handle_value The handle that receives the execute command.
|
||||
* @param[in] p_offset Pointer to the offset for the write.
|
||||
* @param[in] p_index Pointer to the length encoded so far for the current write.
|
||||
* @param[in,out] p_gq_req Pointer to the BLE GATT request structure.
|
||||
*/
|
||||
static ret_code_t queued_write_tx_message(ble_ancs_c_t * p_ancs,
|
||||
uint16_t handle_value,
|
||||
uint16_t * p_offset,
|
||||
uint32_t * p_index,
|
||||
nrf_ble_gq_req_t * p_gq_req)
|
||||
{
|
||||
NRF_LOG_DEBUG("Starting new tx message.");
|
||||
|
||||
p_gq_req->type = NRF_BLE_GQ_REQ_GATTC_WRITE;
|
||||
p_gq_req->error_handler.cb = p_ancs->gatt_err_handler;
|
||||
p_gq_req->error_handler.p_ctx = p_ancs;
|
||||
p_gq_req->params.gattc_write.len = *p_index;
|
||||
p_gq_req->params.gattc_write.offset = *p_offset;
|
||||
p_gq_req->params.gattc_write.write_op = BLE_GATT_OP_PREP_WRITE_REQ;
|
||||
p_gq_req->params.gattc_write.handle = handle_value;
|
||||
|
||||
return nrf_ble_gq_item_add(p_ancs->p_gatt_queue, p_gq_req, p_ancs->conn_handle);
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for encoding the command ID as part of assembling a "get app attributes" command.
|
||||
*
|
||||
* @param[in] p_index Pointer to the length encoded so far for the current write.
|
||||
* @param[in,out] p_gq_req Pointer to the BLE GATT request structure.
|
||||
*/
|
||||
static encode_app_attr_t app_attr_encode_cmd_id(uint32_t * index,
|
||||
nrf_ble_gq_req_t * p_gq_req)
|
||||
{
|
||||
uint8_t * p_value = (uint8_t *)p_gq_req->params.gattc_write.p_value;
|
||||
NRF_LOG_DEBUG("Encoding command ID.");
|
||||
|
||||
// Encode Command ID.
|
||||
p_value[(*index)++] = BLE_ANCS_COMMAND_ID_GET_APP_ATTRIBUTES;
|
||||
return APP_ATTR_APP_ID;
|
||||
}
|
||||
|
||||
/**@brief Function for encoding the app ID as part of assembling a "get app attributes" command.
|
||||
*
|
||||
* @param[in] p_ancs iOS notification structure. This structure must be supplied by
|
||||
* the application. It identifies the particular client instance to use.
|
||||
* @param[in] p_app_id The app ID of the app for which to request app attributes.
|
||||
* @param[in] app_id_len Length of the app ID.
|
||||
* @param[in] p_index Pointer to the length encoded so far for the current write.
|
||||
* @param[in] p_offset Pointer to the accumulated offset for the next write.
|
||||
* @param[in] p_gq_req Pointer to the BLE GATT request structure.
|
||||
* @param[in] p_app_id_bytes_encoded_count Variable to keep count of the encoded app ID bytes.
|
||||
* As long as it is lower than the length of the app ID,
|
||||
* parsing continues.
|
||||
*/
|
||||
static encode_app_attr_t app_attr_encode_app_id(ble_ancs_c_t * p_ancs,
|
||||
uint32_t * p_index,
|
||||
uint16_t * p_offset,
|
||||
nrf_ble_gq_req_t * p_gq_req,
|
||||
const uint8_t * p_app_id,
|
||||
const uint32_t app_id_len,
|
||||
uint32_t * p_app_id_bytes_encoded_count)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
uint8_t * p_value = (uint8_t *)p_gq_req->params.gattc_write.p_value;
|
||||
|
||||
NRF_LOG_DEBUG("Encoding app ID.");
|
||||
if (*p_index >= ANCS_GATTC_WRITE_PAYLOAD_LEN_MAX)
|
||||
{
|
||||
err_code = queued_write_tx_message(p_ancs,
|
||||
p_ancs->service.control_point_char.handle_value,
|
||||
p_offset,
|
||||
p_index,
|
||||
p_gq_req);
|
||||
|
||||
if ((err_code != NRF_SUCCESS) && (p_ancs->error_handler != NULL))
|
||||
{
|
||||
p_ancs->error_handler(err_code);
|
||||
}
|
||||
|
||||
*(p_offset) += *p_index;
|
||||
*p_index = 0;
|
||||
}
|
||||
|
||||
//Encode app identifier.
|
||||
if (*p_app_id_bytes_encoded_count == app_id_len)
|
||||
{
|
||||
p_value[(*p_index)++] = '\0';
|
||||
(*p_app_id_bytes_encoded_count)++;
|
||||
}
|
||||
NRF_LOG_DEBUG("%c", p_app_id[(*p_app_id_bytes_encoded_count)]);
|
||||
if (*p_app_id_bytes_encoded_count < app_id_len)
|
||||
{
|
||||
p_value[(*p_index)++] = p_app_id[(*p_app_id_bytes_encoded_count)++];
|
||||
}
|
||||
if (*p_app_id_bytes_encoded_count > app_id_len)
|
||||
{
|
||||
return APP_ATTR_ATTR_ID;
|
||||
}
|
||||
return APP_ATTR_APP_ID;
|
||||
}
|
||||
|
||||
/**@brief Function for encoding the attribute ID as part of assembling a "get app attributes" command.
|
||||
*
|
||||
* @param[in] p_ancs iOS notification structure. This structure must be supplied by
|
||||
* the application. It identifies the particular client instance to use.
|
||||
* @param[in] p_index Pointer to the length encoded so far for the current write.
|
||||
* @param[in] p_offset Pointer to the accumulated offset for the next write.
|
||||
* @param[in,out] p_gq_req Pointer to the BLE GATT request structure.
|
||||
* @param[in] p_attr_count Pointer to a variable that iterates the possible app attributes.
|
||||
*/
|
||||
static encode_app_attr_t app_attr_encode_attr_id(ble_ancs_c_t * p_ancs,
|
||||
uint32_t * p_index,
|
||||
uint16_t * p_offset,
|
||||
nrf_ble_gq_req_t * p_gq_req,
|
||||
uint32_t * p_attr_count,
|
||||
uint32_t * attr_get_total_nb)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
uint8_t * p_value = (uint8_t *)p_gq_req->params.gattc_write.p_value;
|
||||
|
||||
NRF_LOG_DEBUG("Encoding attribute ID.");
|
||||
if ((*p_index) >= ANCS_GATTC_WRITE_PAYLOAD_LEN_MAX)
|
||||
{
|
||||
err_code = queued_write_tx_message(p_ancs,
|
||||
p_ancs->service.control_point_char.handle_value,
|
||||
p_offset,
|
||||
p_index,
|
||||
p_gq_req);
|
||||
|
||||
if ((err_code != NRF_SUCCESS) && (p_ancs->error_handler != NULL))
|
||||
{
|
||||
p_ancs->error_handler(err_code);
|
||||
}
|
||||
*(p_offset) += *p_index;
|
||||
*p_index = 0;
|
||||
}
|
||||
//Encode Attribute ID.
|
||||
if (*p_attr_count < BLE_ANCS_NB_OF_APP_ATTR)
|
||||
{
|
||||
if (app_attr_is_requested(p_ancs, *p_attr_count))
|
||||
{
|
||||
p_value[(*p_index)] = *p_attr_count;
|
||||
p_ancs->number_of_requested_attr++;
|
||||
(*p_index)++;
|
||||
NRF_LOG_DEBUG("offset %i", *p_offset);
|
||||
}
|
||||
(*p_attr_count)++;
|
||||
}
|
||||
if (*p_attr_count == BLE_ANCS_NB_OF_APP_ATTR)
|
||||
{
|
||||
return APP_ATTR_DONE;
|
||||
}
|
||||
return APP_ATTR_APP_ID;
|
||||
}
|
||||
|
||||
/**@brief Function for writing the "execute write" command to a handle for a given connection.
|
||||
*
|
||||
* @param[in] p_ancs iOS notification structure. This structure must be supplied by
|
||||
* the application. It identifies the particular client instance to use.
|
||||
* @param[in] handle_value Handle that receives the "execute write" command.
|
||||
* @param[in] p_gq_req Pointer to the BLE GATT request structure.
|
||||
*/
|
||||
static ret_code_t app_attr_execute_write(ble_ancs_c_t * p_ancs,
|
||||
uint16_t handle_value,
|
||||
nrf_ble_gq_req_t * p_gq_req)
|
||||
{
|
||||
NRF_LOG_DEBUG("Sending Execute Write command.");
|
||||
memset(p_gq_req, 0, sizeof(nrf_ble_gq_req_t));
|
||||
|
||||
p_gq_req->type = NRF_BLE_GQ_REQ_GATTC_WRITE;
|
||||
p_gq_req->error_handler.cb = p_ancs->gatt_err_handler;
|
||||
p_gq_req->error_handler.p_ctx = p_ancs;
|
||||
p_gq_req->params.gattc_write.handle = handle_value;
|
||||
p_gq_req->params.gattc_write.offset = 0;
|
||||
p_gq_req->params.gattc_write.write_op = BLE_GATT_OP_EXEC_WRITE_REQ;
|
||||
p_gq_req->params.gattc_write.flags = BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE;
|
||||
p_gq_req->params.gattc_write.len = 0;
|
||||
|
||||
return nrf_ble_gq_item_add(p_ancs->p_gatt_queue, p_gq_req, p_ancs->conn_handle);
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for sending a "get app attributes" request.
|
||||
*
|
||||
* @details Since the app ID may not fit in a single write, long write
|
||||
* with a state machine is used to encode the "get app attributes" request.
|
||||
*
|
||||
* @param[in] p_ancs iOS notification structure. This structure must be supplied by
|
||||
* the application. It identifies the particular client instance to use.
|
||||
* @param[in] p_app_id The app ID of the app for which to request app attributes.
|
||||
* @param[in] app_id_len Length of the app ID.
|
||||
*
|
||||
*/
|
||||
static uint32_t app_attr_get(ble_ancs_c_t * p_ancs,
|
||||
const uint8_t * p_app_id,
|
||||
uint32_t app_id_len)
|
||||
{
|
||||
uint32_t index = 0;
|
||||
uint32_t attr_bytes_encoded_count = 0;
|
||||
uint16_t offset = 0;
|
||||
uint32_t app_id_bytes_encoded_count = 0;
|
||||
encode_app_attr_t state = APP_ATTR_COMMAND_ID;
|
||||
ret_code_t err_code;
|
||||
|
||||
p_ancs->number_of_requested_attr = 0;
|
||||
|
||||
uint32_t attr_get_total_nb = app_attr_nb_to_get(p_ancs);
|
||||
nrf_ble_gq_req_t ancs_req;
|
||||
uint8_t gatt_value[BLE_ANCS_WRITE_MAX_MSG_LENGTH];
|
||||
|
||||
memset(&ancs_req, 0, sizeof(nrf_ble_gq_req_t));
|
||||
|
||||
ancs_req.params.gattc_write.p_value = gatt_value;
|
||||
|
||||
while (state != APP_ATTR_DONE)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case APP_ATTR_COMMAND_ID:
|
||||
state = app_attr_encode_cmd_id(&index,
|
||||
&ancs_req);
|
||||
break;
|
||||
case APP_ATTR_APP_ID:
|
||||
state = app_attr_encode_app_id(p_ancs,
|
||||
&index,
|
||||
&offset,
|
||||
&ancs_req,
|
||||
p_app_id,
|
||||
app_id_len,
|
||||
&app_id_bytes_encoded_count);
|
||||
break;
|
||||
case APP_ATTR_ATTR_ID:
|
||||
state = app_attr_encode_attr_id(p_ancs,
|
||||
&index,
|
||||
&offset,
|
||||
&ancs_req,
|
||||
&attr_bytes_encoded_count,
|
||||
&attr_get_total_nb);
|
||||
break;
|
||||
case APP_ATTR_DONE:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
err_code = queued_write_tx_message(p_ancs,
|
||||
p_ancs->service.control_point_char.handle_value,
|
||||
&offset,
|
||||
&index,
|
||||
&ancs_req);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
err_code = app_attr_execute_write(p_ancs,
|
||||
p_ancs->service.control_point_char.handle_value,
|
||||
&ancs_req);
|
||||
|
||||
p_ancs->parse_info.expected_number_of_attrs = p_ancs->number_of_requested_attr;
|
||||
|
||||
return err_code;
|
||||
}
|
||||
|
||||
|
||||
uint32_t ancs_c_app_attr_request(ble_ancs_c_t * p_ancs,
|
||||
const uint8_t * p_app_id,
|
||||
uint32_t len)
|
||||
{
|
||||
uint32_t err_code;
|
||||
|
||||
if (len == 0)
|
||||
{
|
||||
return NRF_ERROR_DATA_SIZE;
|
||||
}
|
||||
if (p_app_id[len] != '\0') // App ID to be requested must be null-terminated.
|
||||
{
|
||||
return NRF_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
p_ancs->parse_info.parse_state = COMMAND_ID;
|
||||
err_code = app_attr_get(p_ancs, p_app_id, len);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
68
components/ble/ble_services/ble_ancs_c/ancs_app_attr_get.h
Normal file
68
components/ble/ble_services/ble_ancs_c/ancs_app_attr_get.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 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.
|
||||
*
|
||||
*/
|
||||
#ifndef ANCS_APP_ATTR_GET_H__
|
||||
#define ANCS_APP_ATTR_GET_H__
|
||||
|
||||
#include "nrf_ble_ancs_c.h"
|
||||
/** @file
|
||||
*
|
||||
* @addtogroup ble_ancs_c
|
||||
* @{
|
||||
*/
|
||||
|
||||
#define BLE_ANCS_WRITE_MAX_MSG_LENGTH 20 /**< Maximum GATTC write length. */
|
||||
|
||||
/**@brief Function for requesting attributes for an app.
|
||||
*
|
||||
* @param[in] p_ancs iOS notification structure. This structure must be supplied by
|
||||
* the application. It identifies the particular client instance to use.
|
||||
* @param[in] app_id App identifier of the app for which to request app attributes.
|
||||
* @param[in] len Length of the app identifier.
|
||||
*
|
||||
* @retval NRF_SUCCESS If all operations were successful. Otherwise, an error code is returned.
|
||||
*/
|
||||
uint32_t ancs_c_app_attr_request(ble_ancs_c_t * p_ancs,
|
||||
const uint8_t * app_id,
|
||||
uint32_t len);
|
||||
|
||||
/** @} */
|
||||
|
||||
#endif // ANCS_APP_ATTR_GET_H__
|
||||
|
||||
392
components/ble/ble_services/ble_ancs_c/ancs_attr_parser.c
Normal file
392
components/ble/ble_services/ble_ancs_c/ancs_attr_parser.c
Normal file
@@ -0,0 +1,392 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
/* Disclaimer: This client implementation of the Apple Notification Center Service can and will be changed at any time by Nordic Semiconductor ASA.
|
||||
* Server implementations such as the ones found in iOS can be changed at any time by Apple and may cause this client implementation to stop working.
|
||||
*/
|
||||
|
||||
#include "nrf_ble_ancs_c.h"
|
||||
#include "ancs_attr_parser.h"
|
||||
#include "nrf_log.h"
|
||||
|
||||
|
||||
static bool all_req_attrs_parsed(ble_ancs_c_t * p_ancs)
|
||||
{
|
||||
if (p_ancs->parse_info.expected_number_of_attrs == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool attr_is_requested(ble_ancs_c_t * p_ancs, ble_ancs_c_attr_t attr)
|
||||
{
|
||||
if (p_ancs->parse_info.p_attr_list[attr.attr_id].get == true)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for parsing command id and notification id.
|
||||
* Used in the @ref parse_get_notif_attrs_response state machine.
|
||||
*
|
||||
* @details UID and command ID will be received only once at the beginning of the first
|
||||
* GATTC notification of a new attribute request for a given iOS notification.
|
||||
*
|
||||
* @param[in] p_ancs Pointer to an ANCS instance to which the event belongs.
|
||||
* @param[in] p_data_src Pointer to data that was received from the Notification Provider.
|
||||
* @param[in] index Pointer to an index that helps us keep track of the current data to be parsed.
|
||||
*
|
||||
* @return The next parse state.
|
||||
*/
|
||||
static ble_ancs_c_parse_state_t command_id_parse(ble_ancs_c_t * p_ancs,
|
||||
const uint8_t * p_data_src,
|
||||
uint32_t * index)
|
||||
{
|
||||
ble_ancs_c_parse_state_t parse_state;
|
||||
|
||||
p_ancs->parse_info.command_id = (ble_ancs_c_cmd_id_val_t) p_data_src[(*index)++];
|
||||
|
||||
switch (p_ancs->parse_info.command_id)
|
||||
{
|
||||
case BLE_ANCS_COMMAND_ID_GET_NOTIF_ATTRIBUTES:
|
||||
p_ancs->evt.evt_type = BLE_ANCS_C_EVT_NOTIF_ATTRIBUTE;
|
||||
p_ancs->parse_info.p_attr_list = p_ancs->ancs_notif_attr_list;
|
||||
p_ancs->parse_info.nb_of_attr = BLE_ANCS_NB_OF_NOTIF_ATTR;
|
||||
parse_state = NOTIF_UID;
|
||||
break;
|
||||
|
||||
case BLE_ANCS_COMMAND_ID_GET_APP_ATTRIBUTES:
|
||||
p_ancs->evt.evt_type = BLE_ANCS_C_EVT_APP_ATTRIBUTE;
|
||||
p_ancs->parse_info.p_attr_list = p_ancs->ancs_app_attr_list;
|
||||
p_ancs->parse_info.nb_of_attr = BLE_ANCS_NB_OF_APP_ATTR;
|
||||
parse_state = APP_ID;
|
||||
break;
|
||||
|
||||
default:
|
||||
//no valid command_id, abort the rest of the parsing procedure.
|
||||
NRF_LOG_DEBUG("Invalid Command ID");
|
||||
parse_state = DONE;
|
||||
break;
|
||||
}
|
||||
return parse_state;
|
||||
}
|
||||
|
||||
|
||||
static ble_ancs_c_parse_state_t notif_uid_parse(ble_ancs_c_t * p_ancs,
|
||||
const uint8_t * p_data_src,
|
||||
uint32_t * index)
|
||||
{
|
||||
p_ancs->evt.notif_uid = uint32_decode(&p_data_src[*index]);
|
||||
*index += sizeof(uint32_t);
|
||||
return ATTR_ID;
|
||||
}
|
||||
|
||||
static ble_ancs_c_parse_state_t app_id_parse(ble_ancs_c_t * p_ancs,
|
||||
const uint8_t * p_data_src,
|
||||
uint32_t * index)
|
||||
{
|
||||
p_ancs->evt.app_id[p_ancs->parse_info.current_app_id_index] = p_data_src[(*index)++];
|
||||
|
||||
if (p_ancs->evt.app_id[p_ancs->parse_info.current_app_id_index] != '\0')
|
||||
{
|
||||
p_ancs->parse_info.current_app_id_index++;
|
||||
return APP_ID;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ATTR_ID;
|
||||
}
|
||||
}
|
||||
|
||||
/**@brief Function for parsing the id of an iOS attribute.
|
||||
* Used in the @ref parse_get_notif_attrs_response state machine.
|
||||
*
|
||||
* @details We only request attributes that are registered with @ref ble_ancs_c_attr_add
|
||||
* once they have been reveiced we stop parsing.
|
||||
*
|
||||
* @param[in] p_ancs Pointer to an ANCS instance to which the event belongs.
|
||||
* @param[in] p_data_src Pointer to data that was received from the Notification Provider.
|
||||
* @param[in] index Pointer to an index that helps us keep track of the current data to be parsed.
|
||||
*
|
||||
* @return The next parse state.
|
||||
*/
|
||||
static ble_ancs_c_parse_state_t attr_id_parse(ble_ancs_c_t * p_ancs,
|
||||
const uint8_t * p_data_src,
|
||||
uint32_t * index)
|
||||
{
|
||||
p_ancs->evt.attr.attr_id = p_data_src[(*index)++];
|
||||
|
||||
if (p_ancs->evt.attr.attr_id >= p_ancs->parse_info.nb_of_attr)
|
||||
{
|
||||
NRF_LOG_DEBUG("Attribute ID Invalid.");
|
||||
return DONE;
|
||||
}
|
||||
p_ancs->evt.attr.p_attr_data = p_ancs->parse_info.p_attr_list[p_ancs->evt.attr.attr_id].p_attr_data;
|
||||
|
||||
if (all_req_attrs_parsed(p_ancs))
|
||||
{
|
||||
NRF_LOG_DEBUG("All requested attributes received. ");
|
||||
return DONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (attr_is_requested(p_ancs, p_ancs->evt.attr))
|
||||
{
|
||||
p_ancs->parse_info.expected_number_of_attrs--;
|
||||
}
|
||||
NRF_LOG_DEBUG("Attribute ID %i ", p_ancs->evt.attr.attr_id);
|
||||
return ATTR_LEN1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for parsing the length of an iOS attribute.
|
||||
* Used in the @ref parse_get_notif_attrs_response state machine.
|
||||
*
|
||||
* @details The Length is 2 bytes. Since there is a chance we reveice the bytes in two different
|
||||
* GATTC notifications, we parse only the first byte here and then set the state machine
|
||||
* ready to parse the next byte.
|
||||
*
|
||||
* @param[in] p_ancs Pointer to an ANCS instance to which the event belongs.
|
||||
* @param[in] p_data_src Pointer to data that was received from the Notification Provider.
|
||||
* @param[in] index Pointer to an index that helps us keep track of the current data to be parsed.
|
||||
*
|
||||
* @return The next parse state.
|
||||
*/
|
||||
static ble_ancs_c_parse_state_t attr_len1_parse(ble_ancs_c_t * p_ancs, const uint8_t * p_data_src, uint32_t * index)
|
||||
{
|
||||
p_ancs->evt.attr.attr_len = p_data_src[(*index)++];
|
||||
return ATTR_LEN2;
|
||||
}
|
||||
|
||||
/**@brief Function for parsing the length of an iOS attribute.
|
||||
* Used in the @ref parse_get_notif_attrs_response state machine.
|
||||
*
|
||||
* @details Second byte of the length field. If the length is zero, it means that the attribute is not
|
||||
* present and the state machine is set to parse the next attribute.
|
||||
*
|
||||
* @param[in] p_ancs Pointer to an ANCS instance to which the event belongs.
|
||||
* @param[in] p_data_src Pointer to data that was received from the Notification Provider.
|
||||
* @param[in] index Pointer to an index that helps us keep track of the current data to be parsed.
|
||||
*
|
||||
* @return The next parse state.
|
||||
*/
|
||||
static ble_ancs_c_parse_state_t attr_len2_parse(ble_ancs_c_t * p_ancs, const uint8_t * p_data_src, uint32_t * index)
|
||||
{
|
||||
p_ancs->evt.attr.attr_len |= (p_data_src[(*index)++] << 8);
|
||||
p_ancs->parse_info.current_attr_index = 0;
|
||||
|
||||
if (p_ancs->evt.attr.attr_len != 0)
|
||||
{
|
||||
//If the attribute has a length but there is no allocated space for this attribute
|
||||
if ((p_ancs->parse_info.p_attr_list[p_ancs->evt.attr.attr_id].attr_len == 0) ||
|
||||
(p_ancs->parse_info.p_attr_list[p_ancs->evt.attr.attr_id].p_attr_data == NULL))
|
||||
{
|
||||
return ATTR_SKIP;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ATTR_DATA;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
NRF_LOG_DEBUG("Attribute LEN %i ", p_ancs->evt.attr.attr_len);
|
||||
if (attr_is_requested(p_ancs, p_ancs->evt.attr))
|
||||
{
|
||||
p_ancs->evt_handler(&p_ancs->evt);
|
||||
}
|
||||
if (all_req_attrs_parsed(p_ancs))
|
||||
{
|
||||
return DONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ATTR_ID;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for parsing the data of an iOS attribute.
|
||||
* Used in the @ref parse_get_notif_attrs_response state machine.
|
||||
*
|
||||
* @details Read the data of the attribute into our local buffer.
|
||||
*
|
||||
* @param[in] p_ancs Pointer to an ANCS instance to which the event belongs.
|
||||
* @param[in] p_data_src Pointer to data that was received from the Notification Provider.
|
||||
* @param[in] index Pointer to an index that helps us keep track of the current data to be parsed.
|
||||
*
|
||||
* @return The next parse state.
|
||||
*/
|
||||
static ble_ancs_c_parse_state_t attr_data_parse(ble_ancs_c_t * p_ancs,
|
||||
const uint8_t * p_data_src,
|
||||
uint32_t * index)
|
||||
{
|
||||
// We have not reached the end of the attribute, nor our max allocated internal size.
|
||||
// Proceed with copying data over to our buffer.
|
||||
if ( (p_ancs->parse_info.current_attr_index < p_ancs->parse_info.p_attr_list[p_ancs->evt.attr.attr_id].attr_len)
|
||||
&& (p_ancs->parse_info.current_attr_index < p_ancs->evt.attr.attr_len))
|
||||
{
|
||||
//NRF_LOG_DEBUG("Byte copied to buffer: %c", p_data_src[(*index)]); // Un-comment this line to see every byte of an attribute as it is parsed. Commented out by default since it can overflow the uart buffer.
|
||||
p_ancs->evt.attr.p_attr_data[p_ancs->parse_info.current_attr_index++] = p_data_src[(*index)++];
|
||||
}
|
||||
|
||||
// We have reached the end of the attribute, or our max allocated internal size.
|
||||
// Stop copying data over to our buffer. NUL-terminate at the current index.
|
||||
if ( (p_ancs->parse_info.current_attr_index == p_ancs->evt.attr.attr_len) ||
|
||||
(p_ancs->parse_info.current_attr_index == p_ancs->parse_info.p_attr_list[p_ancs->evt.attr.attr_id].attr_len - 1))
|
||||
{
|
||||
if (attr_is_requested(p_ancs, p_ancs->evt.attr))
|
||||
{
|
||||
p_ancs->evt.attr.p_attr_data[p_ancs->parse_info.current_attr_index] = '\0';
|
||||
}
|
||||
|
||||
// If our max buffer size is smaller than the remaining attribute data, we must
|
||||
// increase index to skip the data until the start of the next attribute.
|
||||
if (p_ancs->parse_info.current_attr_index < p_ancs->evt.attr.attr_len)
|
||||
{
|
||||
return ATTR_SKIP;
|
||||
}
|
||||
NRF_LOG_DEBUG("Attribute finished!");
|
||||
if (attr_is_requested(p_ancs, p_ancs->evt.attr))
|
||||
{
|
||||
p_ancs->evt_handler(&p_ancs->evt);
|
||||
}
|
||||
if (all_req_attrs_parsed(p_ancs))
|
||||
{
|
||||
return DONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ATTR_ID;
|
||||
}
|
||||
}
|
||||
return ATTR_DATA;
|
||||
}
|
||||
|
||||
|
||||
static ble_ancs_c_parse_state_t attr_skip(ble_ancs_c_t * p_ancs, const uint8_t * p_data_src, uint32_t * index)
|
||||
{
|
||||
// We have not reached the end of the attribute, nor our max allocated internal size.
|
||||
// Proceed with copying data over to our buffer.
|
||||
if (p_ancs->parse_info.current_attr_index < p_ancs->evt.attr.attr_len)
|
||||
{
|
||||
p_ancs->parse_info.current_attr_index++;
|
||||
(*index)++;
|
||||
}
|
||||
// At the end of the attribute, determine if it should be passed to event handler and
|
||||
// continue parsing the next attribute ID if we are not done with all the attributes.
|
||||
if (p_ancs->parse_info.current_attr_index == p_ancs->evt.attr.attr_len)
|
||||
{
|
||||
if (attr_is_requested(p_ancs, p_ancs->evt.attr))
|
||||
{
|
||||
p_ancs->evt_handler(&p_ancs->evt);
|
||||
}
|
||||
if (all_req_attrs_parsed(p_ancs))
|
||||
{
|
||||
return DONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ATTR_ID;
|
||||
}
|
||||
}
|
||||
return ATTR_SKIP;
|
||||
}
|
||||
|
||||
|
||||
void ancs_parse_get_attrs_response(ble_ancs_c_t * p_ancs,
|
||||
const uint8_t * p_data_src,
|
||||
const uint16_t hvx_data_len)
|
||||
{
|
||||
uint32_t index;
|
||||
|
||||
for (index = 0; index < hvx_data_len;)
|
||||
{
|
||||
switch (p_ancs->parse_info.parse_state)
|
||||
{
|
||||
case COMMAND_ID:
|
||||
p_ancs->parse_info.parse_state = command_id_parse(p_ancs, p_data_src, &index);
|
||||
break;
|
||||
|
||||
case NOTIF_UID:
|
||||
p_ancs->parse_info.parse_state = notif_uid_parse(p_ancs, p_data_src, &index);
|
||||
break;
|
||||
|
||||
case APP_ID:
|
||||
p_ancs->parse_info.parse_state = app_id_parse(p_ancs, p_data_src, &index);
|
||||
break;
|
||||
|
||||
case ATTR_ID:
|
||||
p_ancs->parse_info.parse_state = attr_id_parse(p_ancs, p_data_src, &index);
|
||||
break;
|
||||
|
||||
case ATTR_LEN1:
|
||||
p_ancs->parse_info.parse_state = attr_len1_parse(p_ancs, p_data_src, &index);
|
||||
break;
|
||||
|
||||
case ATTR_LEN2:
|
||||
p_ancs->parse_info.parse_state = attr_len2_parse(p_ancs, p_data_src, &index);
|
||||
break;
|
||||
|
||||
case ATTR_DATA:
|
||||
p_ancs->parse_info.parse_state = attr_data_parse(p_ancs, p_data_src, &index);
|
||||
break;
|
||||
|
||||
case ATTR_SKIP:
|
||||
p_ancs->parse_info.parse_state = attr_skip(p_ancs, p_data_src, &index);
|
||||
break;
|
||||
|
||||
case DONE:
|
||||
NRF_LOG_DEBUG("Parse state: Done ");
|
||||
index = hvx_data_len;
|
||||
break;
|
||||
|
||||
default:
|
||||
// Default case will never trigger intentionally. Go to the DONE state to minimize the consequences.
|
||||
p_ancs->parse_info.parse_state = DONE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
77
components/ble/ble_services/ble_ancs_c/ancs_attr_parser.h
Normal file
77
components/ble/ble_services/ble_ancs_c/ancs_attr_parser.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 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.
|
||||
*
|
||||
*/
|
||||
#ifndef BLE_ANCS_ATTR_PARSER_H__
|
||||
#define BLE_ANCS_ATTR_PARSER_H__
|
||||
|
||||
#include "nrf_ble_ancs_c.h"
|
||||
|
||||
/** @file
|
||||
*
|
||||
* @addtogroup ble_ancs_c
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**@brief Function for parsing notification or app attribute response data.
|
||||
*
|
||||
* @details The data that comes from the Notification Provider can be much longer than what
|
||||
* would fit in a single GATTC notification. Therefore, this function relies on a
|
||||
* state-oriented switch case.
|
||||
* UID and command ID will be received only once at the beginning of the first
|
||||
* GATTC notification of a new attribute request for a given iOS notification.
|
||||
* After this, we can loop several ATTR_ID > LENGTH > DATA > ATTR_ID > LENGTH > DATA until
|
||||
* we have received all attributes we wanted as a Notification Consumer.
|
||||
* The Notification Provider can also simply stop sending attributes.
|
||||
*
|
||||
* 1 byte | 4 bytes |1 byte |2 bytes |... X bytes ... |1 bytes| 2 bytes| ... X bytes ...
|
||||
* --------|-------------|-------|--------|----------------|-------|--------|----------------
|
||||
* CMD_ID | NOTIF_UID |ATTR_ID| LENGTH | DATA |ATTR_ID| LENGTH | DATA
|
||||
*
|
||||
* @param[in] p_ancs Pointer to an ANCS instance to which the event belongs.
|
||||
* @param[in] p_data_src Pointer to data that was received from the Notification Provider.
|
||||
* @param[in] hvx_data_len Length of the data that was received from the Notification Provider.
|
||||
*/
|
||||
void ancs_parse_get_attrs_response(ble_ancs_c_t * p_ancs,
|
||||
const uint8_t * p_data_src,
|
||||
const uint16_t hvx_data_len);
|
||||
|
||||
/** @} */
|
||||
|
||||
#endif // BLE_ANCS_ATTR_PARSER_H__
|
||||
|
||||
683
components/ble/ble_services/ble_ancs_c/nrf_ble_ancs_c.c
Normal file
683
components/ble/ble_services/ble_ancs_c/nrf_ble_ancs_c.c
Normal file
@@ -0,0 +1,683 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 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.
|
||||
*
|
||||
*/
|
||||
/* Disclaimer: This client implementation of the Apple Notification Center Service can and will be changed at any time by Nordic Semiconductor ASA.
|
||||
* Server implementations such as the ones found in iOS can be changed at any time by Apple and may cause this client implementation to stop working.
|
||||
*/
|
||||
#include "sdk_common.h"
|
||||
#if NRF_MODULE_ENABLED(BLE_ANCS_C)
|
||||
#include "nrf_ble_ancs_c.h"
|
||||
#include "ancs_attr_parser.h"
|
||||
#include "ancs_app_attr_get.h"
|
||||
#include "ble_err.h"
|
||||
#include "ble_srv_common.h"
|
||||
#include "ble_db_discovery.h"
|
||||
#include "app_error.h"
|
||||
#define NRF_LOG_MODULE_NAME ble_ancs_c
|
||||
#include "nrf_log.h"
|
||||
NRF_LOG_MODULE_REGISTER();
|
||||
|
||||
#define BLE_ANCS_NOTIF_EVT_ID_INDEX 0 /**< Index of the Event ID field when parsing notifications. */
|
||||
#define BLE_ANCS_NOTIF_FLAGS_INDEX 1 /**< Index of the Flags field when parsing notifications. */
|
||||
#define BLE_ANCS_NOTIF_CATEGORY_ID_INDEX 2 /**< Index of the Category ID field when parsing notifications. */
|
||||
#define BLE_ANCS_NOTIF_CATEGORY_CNT_INDEX 3 /**< Index of the Category Count field when parsing notifications. */
|
||||
#define BLE_ANCS_NOTIF_NOTIF_UID 4 /**< Index of the Notification UID field when parsing notifications. */
|
||||
|
||||
#define BLE_CCCD_NOTIFY_BIT_MASK 0x0001 /**< Enables notification bit. */
|
||||
|
||||
#define TIME_STRING_LEN 15 /**< Unicode Technical Standard (UTS) #35 date format pattern "yyyyMMdd'T'HHmmSS" + "'\0'". */
|
||||
|
||||
|
||||
/**@brief 128-bit service UUID for the Apple Notification Center Service. */
|
||||
ble_uuid128_t const ble_ancs_base_uuid128 =
|
||||
{
|
||||
{
|
||||
// 7905F431-B5CE-4E99-A40F-4B1E122D00D0
|
||||
0xd0, 0x00, 0x2d, 0x12, 0x1e, 0x4b, 0x0f, 0xa4,
|
||||
0x99, 0x4e, 0xce, 0xb5, 0x31, 0xf4, 0x05, 0x79
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**@brief 128-bit control point UUID. */
|
||||
ble_uuid128_t const ble_ancs_cp_base_uuid128 =
|
||||
{
|
||||
{
|
||||
// 69d1d8f3-45e1-49a8-9821-9BBDFDAAD9D9
|
||||
0xd9, 0xd9, 0xaa, 0xfd, 0xbd, 0x9b, 0x21, 0x98,
|
||||
0xa8, 0x49, 0xe1, 0x45, 0xf3, 0xd8, 0xd1, 0x69
|
||||
}
|
||||
};
|
||||
|
||||
/**@brief 128-bit notification source UUID. */
|
||||
ble_uuid128_t const ble_ancs_ns_base_uuid128 =
|
||||
{
|
||||
{
|
||||
// 9FBF120D-6301-42D9-8C58-25E699A21DBD
|
||||
0xbd, 0x1d, 0xa2, 0x99, 0xe6, 0x25, 0x58, 0x8c,
|
||||
0xd9, 0x42, 0x01, 0x63, 0x0d, 0x12, 0xbf, 0x9f
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
/**@brief 128-bit data source UUID. */
|
||||
ble_uuid128_t const ble_ancs_ds_base_uuid128 =
|
||||
{
|
||||
{
|
||||
// 22EAC6E9-24D6-4BB5-BE44-B36ACE7C7BFB
|
||||
0xfb, 0x7b, 0x7c, 0xce, 0x6a, 0xb3, 0x44, 0xbe,
|
||||
0xb5, 0x4b, 0xd6, 0x24, 0xe9, 0xc6, 0xea, 0x22
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**@brief Function for intercepting errors of GATTC and 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)
|
||||
{
|
||||
ble_ancs_c_t * p_ancs = (ble_ancs_c_t *)p_ctx;
|
||||
|
||||
NRF_LOG_DEBUG("A GATT Client error has occurred on conn_handle: 0x%x", conn_handle);
|
||||
|
||||
if (p_ancs->error_handler != NULL)
|
||||
{
|
||||
p_ancs->error_handler(nrf_error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling Disconnected event received from the SoftDevice.
|
||||
*
|
||||
* @details This function checks whether the disconnect event is happening on the link
|
||||
* associated with the current instance of the module. If the event is happening,
|
||||
* the function sets the conn_handle of the instance to invalid.
|
||||
*
|
||||
* @param[in] p_ancs Pointer to the ANCS client structure.
|
||||
* @param[in] p_ble_evt Pointer to the BLE event received.
|
||||
*/
|
||||
static void on_disconnected(ble_ancs_c_t * p_ancs, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
if (p_ancs->conn_handle == p_ble_evt->evt.gap_evt.conn_handle)
|
||||
{
|
||||
p_ancs->conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ble_ancs_c_on_db_disc_evt(ble_ancs_c_t * p_ancs, ble_db_discovery_evt_t * p_evt)
|
||||
{
|
||||
NRF_LOG_DEBUG("Database Discovery handler called with event 0x%x", p_evt->evt_type);
|
||||
|
||||
ble_ancs_c_evt_t evt;
|
||||
ble_gatt_db_char_t * p_chars;
|
||||
|
||||
p_chars = p_evt->params.discovered_db.charateristics;
|
||||
|
||||
// Check whether the ANCS Service was discovered.
|
||||
if ( (p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE)
|
||||
&& (p_evt->params.discovered_db.srv_uuid.uuid == ANCS_UUID_SERVICE)
|
||||
&& (p_evt->params.discovered_db.srv_uuid.type == p_ancs->service.service.uuid.type))
|
||||
{
|
||||
// Find the handles of the ANCS characteristic.
|
||||
for (uint32_t i = 0; i < p_evt->params.discovered_db.char_count; i++)
|
||||
{
|
||||
switch (p_chars[i].characteristic.uuid.uuid)
|
||||
{
|
||||
case ANCS_UUID_CHAR_CONTROL_POINT:
|
||||
NRF_LOG_INFO("Control Point characteristic found.");
|
||||
memcpy(&evt.service.control_point_char,
|
||||
&p_chars[i].characteristic,
|
||||
sizeof(ble_gattc_char_t));
|
||||
break;
|
||||
|
||||
case ANCS_UUID_CHAR_DATA_SOURCE:
|
||||
NRF_LOG_INFO("Data Source characteristic found.");
|
||||
memcpy(&evt.service.data_source_char,
|
||||
&p_chars[i].characteristic,
|
||||
sizeof(ble_gattc_char_t));
|
||||
evt.service.data_source_cccd.handle = p_chars[i].cccd_handle;
|
||||
break;
|
||||
|
||||
case ANCS_UUID_CHAR_NOTIFICATION_SOURCE:
|
||||
NRF_LOG_INFO("Notification Point characteristic found.");
|
||||
memcpy(&evt.service.notif_source_char,
|
||||
&p_chars[i].characteristic,
|
||||
sizeof(ble_gattc_char_t));
|
||||
evt.service.notif_source_cccd.handle = p_chars[i].cccd_handle;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
evt.evt_type = BLE_ANCS_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 = BLE_ANCS_C_EVT_DISCOVERY_FAILED;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
p_ancs->evt_handler(&evt);
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for checking whether the data in an iOS notification is out of bounds.
|
||||
*
|
||||
* @param[in] notif An iOS notification.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the notification is within bounds.
|
||||
* @retval NRF_ERROR_INVALID_PARAM If the notification is out of bounds.
|
||||
*/
|
||||
static uint32_t ble_ancs_verify_notification_format(ble_ancs_c_evt_notif_t const * notif)
|
||||
{
|
||||
if ( (notif->evt_id >= BLE_ANCS_NB_OF_EVT_ID)
|
||||
|| (notif->category_id >= BLE_ANCS_NB_OF_CATEGORY_ID))
|
||||
{
|
||||
return NRF_ERROR_INVALID_PARAM;
|
||||
}
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
/**@brief Function for receiving and validating notifications received from the Notification Provider.
|
||||
*
|
||||
* @param[in] p_ancs Pointer to an ANCS instance to which the event belongs.
|
||||
* @param[in] p_data_src Pointer to the data that was received from the Notification Provider.
|
||||
* @param[in] hvx_len Length of the data that was received from the Notification Provider.
|
||||
*/
|
||||
static void parse_notif(ble_ancs_c_t const * p_ancs,
|
||||
uint8_t const * p_data_src,
|
||||
uint16_t const hvx_data_len)
|
||||
{
|
||||
ble_ancs_c_evt_t ancs_evt;
|
||||
uint32_t err_code;
|
||||
if (hvx_data_len != BLE_ANCS_NOTIFICATION_DATA_LENGTH)
|
||||
{
|
||||
ancs_evt.evt_type = BLE_ANCS_C_EVT_INVALID_NOTIF;
|
||||
p_ancs->evt_handler(&ancs_evt);
|
||||
}
|
||||
|
||||
/*lint --e{415} --e{416} -save suppress Warning 415: possible access out of bound*/
|
||||
ancs_evt.notif.evt_id =
|
||||
(ble_ancs_c_evt_id_values_t) p_data_src[BLE_ANCS_NOTIF_EVT_ID_INDEX];
|
||||
|
||||
ancs_evt.notif.evt_flags.silent =
|
||||
(p_data_src[BLE_ANCS_NOTIF_FLAGS_INDEX] >> BLE_ANCS_EVENT_FLAG_SILENT) & 0x01;
|
||||
|
||||
ancs_evt.notif.evt_flags.important =
|
||||
(p_data_src[BLE_ANCS_NOTIF_FLAGS_INDEX] >> BLE_ANCS_EVENT_FLAG_IMPORTANT) & 0x01;
|
||||
|
||||
ancs_evt.notif.evt_flags.pre_existing =
|
||||
(p_data_src[BLE_ANCS_NOTIF_FLAGS_INDEX] >> BLE_ANCS_EVENT_FLAG_PREEXISTING) & 0x01;
|
||||
|
||||
ancs_evt.notif.evt_flags.positive_action =
|
||||
(p_data_src[BLE_ANCS_NOTIF_FLAGS_INDEX] >> BLE_ANCS_EVENT_FLAG_POSITIVE_ACTION) & 0x01;
|
||||
|
||||
ancs_evt.notif.evt_flags.negative_action =
|
||||
(p_data_src[BLE_ANCS_NOTIF_FLAGS_INDEX] >> BLE_ANCS_EVENT_FLAG_NEGATIVE_ACTION) & 0x01;
|
||||
|
||||
ancs_evt.notif.category_id =
|
||||
(ble_ancs_c_category_id_val_t) p_data_src[BLE_ANCS_NOTIF_CATEGORY_ID_INDEX];
|
||||
|
||||
ancs_evt.notif.category_count = p_data_src[BLE_ANCS_NOTIF_CATEGORY_CNT_INDEX];
|
||||
ancs_evt.notif.notif_uid = uint32_decode(&p_data_src[BLE_ANCS_NOTIF_NOTIF_UID]);
|
||||
/*lint -restore*/
|
||||
|
||||
err_code = ble_ancs_verify_notification_format(&ancs_evt.notif);
|
||||
if (err_code == NRF_SUCCESS)
|
||||
{
|
||||
ancs_evt.evt_type = BLE_ANCS_C_EVT_NOTIF;
|
||||
}
|
||||
else
|
||||
{
|
||||
ancs_evt.evt_type = BLE_ANCS_C_EVT_INVALID_NOTIF;
|
||||
}
|
||||
|
||||
p_ancs->evt_handler(&ancs_evt);
|
||||
}
|
||||
|
||||
|
||||
ret_code_t nrf_ble_ancs_c_app_attr_request(ble_ancs_c_t * p_ancs,
|
||||
uint8_t const * p_app_id,
|
||||
uint32_t len)
|
||||
{
|
||||
return ancs_c_app_attr_request(p_ancs, p_app_id, len);
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for receiving and validating notifications received from the Notification Provider.
|
||||
*
|
||||
* @param[in] p_ancs Pointer to an ANCS instance to which the event belongs.
|
||||
* @param[in] p_ble_evt Bluetooth stack event.
|
||||
*/
|
||||
static void on_evt_gattc_notif(ble_ancs_c_t * p_ancs, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
ble_gattc_evt_hvx_t const * p_notif = &p_ble_evt->evt.gattc_evt.params.hvx;
|
||||
|
||||
if (p_ble_evt->evt.gattc_evt.conn_handle != p_ancs->conn_handle)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (p_notif->handle == p_ancs->service.notif_source_char.handle_value)
|
||||
{
|
||||
parse_notif(p_ancs, p_notif->data, p_notif->len);
|
||||
}
|
||||
else if (p_notif->handle == p_ancs->service.data_source_char.handle_value)
|
||||
{
|
||||
ancs_parse_get_attrs_response(p_ancs, p_notif->data, p_notif->len);
|
||||
}
|
||||
else
|
||||
{
|
||||
// No applicable action.
|
||||
}
|
||||
}
|
||||
|
||||
/**@brief Function for handling error response events.
|
||||
*
|
||||
* @param[in] p_ancs Pointer to an ANCS instance to which the event belongs.
|
||||
* @param[in] p_ble_evt Pointer to the SoftDevice event.
|
||||
*/
|
||||
static void on_ctrlpt_error_rsp(ble_ancs_c_t * p_ancs, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
ble_ancs_c_evt_t ancs_evt;
|
||||
|
||||
ancs_evt.evt_type = BLE_ANCS_C_EVT_NP_ERROR;
|
||||
ancs_evt.err_code_np = p_ble_evt->evt.gattc_evt.gatt_status;
|
||||
|
||||
p_ancs->evt_handler(&ancs_evt);
|
||||
}
|
||||
|
||||
/**@brief Function for handling write response events.
|
||||
*
|
||||
* @param[in] p_ancs Pointer to an ANCS instance to which the event belongs.
|
||||
* @param[in] p_ble_evt Pointer to the SoftDevice event.
|
||||
*/
|
||||
static void on_write_rsp(ble_ancs_c_t * p_ancs, ble_evt_t const* p_ble_evt)
|
||||
{
|
||||
// Check if the event is on the link for this instance.
|
||||
if (p_ancs->conn_handle != p_ble_evt->evt.gattc_evt.conn_handle)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if ((p_ble_evt->evt.gattc_evt.error_handle != BLE_GATT_HANDLE_INVALID)
|
||||
&& (p_ble_evt->evt.gattc_evt.error_handle == p_ancs->service.control_point_char.handle_value))
|
||||
{
|
||||
on_ctrlpt_error_rsp(p_ancs,p_ble_evt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ble_ancs_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
|
||||
{
|
||||
ble_ancs_c_t * p_ancs = (ble_ancs_c_t *)p_context;
|
||||
uint16_t evt = p_ble_evt->header.evt_id;
|
||||
|
||||
switch (evt)
|
||||
{
|
||||
case BLE_GATTC_EVT_WRITE_RSP:
|
||||
on_write_rsp(p_ancs, p_ble_evt);
|
||||
break;
|
||||
|
||||
case BLE_GATTC_EVT_HVX:
|
||||
on_evt_gattc_notif(p_ancs, p_ble_evt);
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVT_DISCONNECTED:
|
||||
on_disconnected(p_ancs, p_ble_evt);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ret_code_t ble_ancs_c_init(ble_ancs_c_t * p_ancs, ble_ancs_c_init_t const * p_ancs_init)
|
||||
{
|
||||
uint32_t err_code;
|
||||
|
||||
// Verify that the parameters needed for initializing this instance of ANCS are not NULL.
|
||||
VERIFY_PARAM_NOT_NULL(p_ancs);
|
||||
VERIFY_PARAM_NOT_NULL(p_ancs_init);
|
||||
VERIFY_PARAM_NOT_NULL(p_ancs_init->evt_handler);
|
||||
|
||||
// Initialize state for the attribute-parsing state machine.
|
||||
p_ancs->parse_info.parse_state = COMMAND_ID;
|
||||
p_ancs->parse_info.p_data_dest = NULL;
|
||||
p_ancs->parse_info.current_attr_index = 0;
|
||||
p_ancs->parse_info.current_app_id_index = 0;
|
||||
|
||||
p_ancs->evt_handler = p_ancs_init->evt_handler;
|
||||
p_ancs->error_handler = p_ancs_init->error_handler;
|
||||
p_ancs->conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
p_ancs->p_gatt_queue = p_ancs_init->p_gatt_queue;
|
||||
p_ancs->gatt_err_handler = gatt_error_handler;
|
||||
|
||||
p_ancs->service.data_source_cccd.uuid.uuid = BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG;
|
||||
p_ancs->service.notif_source_cccd.uuid.uuid = BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG;
|
||||
|
||||
// Make sure that the instance of service is clear. GATT handles inside the service and characteristics are set to @ref BLE_GATT_HANDLE_INVALID.
|
||||
memset(&p_ancs->service, 0, sizeof(ble_ancs_c_service_t));
|
||||
|
||||
// Assign UUID types.
|
||||
err_code = sd_ble_uuid_vs_add(&ble_ancs_base_uuid128, &p_ancs->service.service.uuid.type);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
err_code = sd_ble_uuid_vs_add(&ble_ancs_cp_base_uuid128, &p_ancs->service.control_point_char.uuid.type);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
err_code = sd_ble_uuid_vs_add(&ble_ancs_ns_base_uuid128, &p_ancs->service.notif_source_char.uuid.type);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
err_code = sd_ble_uuid_vs_add(&ble_ancs_ds_base_uuid128, &p_ancs->service.data_source_char.uuid.type);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
// Assign UUID to the service.
|
||||
p_ancs->service.service.uuid.uuid = ANCS_UUID_SERVICE;
|
||||
p_ancs->service.service.uuid.type = p_ancs->service.service.uuid.type;
|
||||
|
||||
return ble_db_discovery_evt_register(&p_ancs->service.service.uuid);
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for creating a tx message for writing a CCCD.
|
||||
*
|
||||
* @param[in] p_ancs Pointer to the iOS notification structure. This structure must be supplied by
|
||||
* the application. It identifies the particular client instance to use.
|
||||
* @param[in] handle_cccd Handle of the CCCD.
|
||||
* @param[in] enable Enables or disables GATTC notifications.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the message is created successfully.
|
||||
* @retval NRF_ERROR_INVALID_PARAM If one of the input parameters is invalid.
|
||||
* @retval err_code Otherwise, this API propagates the error code returned by function
|
||||
* @ref nrf_ble_gq_item_add.
|
||||
*/
|
||||
static uint32_t cccd_configure(ble_ancs_c_t const * const p_ancs,
|
||||
uint16_t const handle_cccd,
|
||||
bool notification_enable)
|
||||
{
|
||||
nrf_ble_gq_req_t ancs_c_req;
|
||||
uint8_t cccd[BLE_CCCD_VALUE_LEN];
|
||||
uint16_t cccd_val = notification_enable ? BLE_GATT_HVX_NOTIFICATION : 0;
|
||||
|
||||
cccd[0] = LSB_16(cccd_val);
|
||||
cccd[1] = MSB_16(cccd_val);
|
||||
|
||||
memset(&ancs_c_req, 0, sizeof(nrf_ble_gq_req_t));
|
||||
|
||||
ancs_c_req.type = NRF_BLE_GQ_REQ_GATTC_WRITE;
|
||||
ancs_c_req.error_handler.cb = p_ancs->gatt_err_handler;
|
||||
ancs_c_req.error_handler.p_ctx = (ble_ancs_c_t *)p_ancs;
|
||||
ancs_c_req.params.gattc_write.handle = handle_cccd;
|
||||
ancs_c_req.params.gattc_write.len = BLE_CCCD_VALUE_LEN;
|
||||
ancs_c_req.params.gattc_write.offset = 0;
|
||||
ancs_c_req.params.gattc_write.write_op = BLE_GATT_OP_WRITE_REQ;
|
||||
ancs_c_req.params.gattc_write.p_value = cccd;
|
||||
|
||||
return nrf_ble_gq_item_add(p_ancs->p_gatt_queue, &ancs_c_req, p_ancs->conn_handle);
|
||||
}
|
||||
|
||||
|
||||
ret_code_t ble_ancs_c_notif_source_notif_enable(ble_ancs_c_t const * p_ancs)
|
||||
{
|
||||
NRF_LOG_INFO("Enable Notification Source. Writing to CCCD handle: %i. ",
|
||||
p_ancs->service.notif_source_cccd.handle);
|
||||
return cccd_configure(p_ancs, p_ancs->service.notif_source_cccd.handle, true);
|
||||
}
|
||||
|
||||
|
||||
ret_code_t ble_ancs_c_notif_source_notif_disable(ble_ancs_c_t const * p_ancs)
|
||||
{
|
||||
return cccd_configure(p_ancs, p_ancs->service.notif_source_cccd.handle, false);
|
||||
}
|
||||
|
||||
|
||||
ret_code_t ble_ancs_c_data_source_notif_enable(ble_ancs_c_t const * p_ancs)
|
||||
{
|
||||
NRF_LOG_INFO("Enable Notification Data Source. Writing to CCCD handle: %i. ",
|
||||
p_ancs->service.data_source_cccd.handle);
|
||||
return cccd_configure(p_ancs, p_ancs->service.data_source_cccd.handle, true);
|
||||
}
|
||||
|
||||
|
||||
ret_code_t ble_ancs_c_data_source_notif_disable(ble_ancs_c_t const * p_ancs)
|
||||
{
|
||||
return cccd_configure(p_ancs, p_ancs->service.data_source_cccd.handle, false);
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_ancs_get_notif_attrs(ble_ancs_c_t * p_ancs,
|
||||
uint32_t const p_uid)
|
||||
{
|
||||
nrf_ble_gq_req_t ancs_req;
|
||||
uint8_t gattc_value[BLE_ANCS_WRITE_MAX_MSG_LENGTH];
|
||||
|
||||
memset(&ancs_req, 0, sizeof(nrf_ble_gq_req_t));
|
||||
|
||||
uint32_t index = 0;
|
||||
p_ancs->number_of_requested_attr = 0;
|
||||
|
||||
ancs_req.type = NRF_BLE_GQ_REQ_GATTC_WRITE;
|
||||
ancs_req.error_handler.cb = p_ancs->gatt_err_handler;
|
||||
ancs_req.error_handler.p_ctx = p_ancs;
|
||||
ancs_req.params.gattc_write.handle = p_ancs->service.control_point_char.handle_value;
|
||||
ancs_req.params.gattc_write.offset = 0;
|
||||
ancs_req.params.gattc_write.write_op = BLE_GATT_OP_WRITE_REQ;
|
||||
ancs_req.params.gattc_write.p_value = gattc_value;
|
||||
|
||||
//Encode Command ID.
|
||||
gattc_value[index++] = BLE_ANCS_COMMAND_ID_GET_NOTIF_ATTRIBUTES;
|
||||
|
||||
//Encode Notification UID.
|
||||
index += uint32_encode(p_uid, &(gattc_value[index]));
|
||||
|
||||
//Encode Attribute ID.
|
||||
for (uint32_t attr = 0; attr < BLE_ANCS_NB_OF_NOTIF_ATTR; attr++)
|
||||
{
|
||||
if (p_ancs->ancs_notif_attr_list[attr].get == true)
|
||||
{
|
||||
gattc_value[index++] = (uint8_t)attr;
|
||||
|
||||
if ((attr == BLE_ANCS_NOTIF_ATTR_ID_TITLE) ||
|
||||
(attr == BLE_ANCS_NOTIF_ATTR_ID_SUBTITLE) ||
|
||||
(attr == BLE_ANCS_NOTIF_ATTR_ID_MESSAGE))
|
||||
{
|
||||
//Encode Length field. Only applicable for Title, Subtitle, and Message.
|
||||
index += uint16_encode(p_ancs->ancs_notif_attr_list[attr].attr_len,
|
||||
&(gattc_value[index]));
|
||||
}
|
||||
|
||||
p_ancs->number_of_requested_attr++;
|
||||
}
|
||||
}
|
||||
|
||||
ancs_req.params.gattc_write.len = index;
|
||||
p_ancs->parse_info.expected_number_of_attrs = p_ancs->number_of_requested_attr;
|
||||
|
||||
return nrf_ble_gq_item_add(p_ancs->p_gatt_queue, &ancs_req, p_ancs->conn_handle);
|
||||
}
|
||||
|
||||
|
||||
ret_code_t nrf_ble_ancs_c_attr_add(ble_ancs_c_t * p_ancs,
|
||||
ble_ancs_c_notif_attr_id_val_t const id,
|
||||
uint8_t * p_data,
|
||||
uint16_t const len)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_data);
|
||||
|
||||
if ((len == 0) || (len > BLE_ANCS_ATTR_DATA_MAX))
|
||||
{
|
||||
return NRF_ERROR_INVALID_LENGTH;
|
||||
}
|
||||
|
||||
p_ancs->ancs_notif_attr_list[id].get = true;
|
||||
p_ancs->ancs_notif_attr_list[id].attr_len = len;
|
||||
p_ancs->ancs_notif_attr_list[id].p_attr_data = p_data;
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
ret_code_t nrf_ble_ancs_c_app_attr_add(ble_ancs_c_t * p_ancs,
|
||||
ble_ancs_c_app_attr_id_val_t const id,
|
||||
uint8_t * p_data,
|
||||
uint16_t const len)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_ancs);
|
||||
VERIFY_PARAM_NOT_NULL(p_data);
|
||||
|
||||
if ((len == 0) || (len > BLE_ANCS_ATTR_DATA_MAX))
|
||||
{
|
||||
return NRF_ERROR_INVALID_LENGTH;
|
||||
}
|
||||
|
||||
p_ancs->ancs_app_attr_list[id].get = true;
|
||||
p_ancs->ancs_app_attr_list[id].attr_len = len;
|
||||
p_ancs->ancs_app_attr_list[id].p_attr_data = p_data;
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
ret_code_t ble_ancs_c_app_attr_remove(ble_ancs_c_t * p_ancs,
|
||||
ble_ancs_c_app_attr_id_val_t const id)
|
||||
{
|
||||
p_ancs->ancs_app_attr_list[id].get = false;
|
||||
p_ancs->ancs_app_attr_list[id].attr_len = 0;
|
||||
p_ancs->ancs_app_attr_list[id].p_attr_data = NULL;
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
ret_code_t ble_ancs_c_notif_attr_remove(ble_ancs_c_t * p_ancs,
|
||||
ble_ancs_c_notif_attr_id_val_t const id)
|
||||
{
|
||||
p_ancs->ancs_notif_attr_list[id].get = false;
|
||||
p_ancs->ancs_notif_attr_list[id].attr_len = 0;
|
||||
p_ancs->ancs_notif_attr_list[id].p_attr_data = NULL;
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
ret_code_t nrf_ble_ancs_c_attr_req_clear_all(ble_ancs_c_t * p_ancs)
|
||||
{
|
||||
memset(p_ancs->ancs_notif_attr_list, 0 , sizeof(p_ancs->ancs_notif_attr_list));
|
||||
memset(p_ancs->ancs_app_attr_list, 0 , sizeof(p_ancs->ancs_app_attr_list));
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
ret_code_t nrf_ble_ancs_c_request_attrs(ble_ancs_c_t * p_ancs,
|
||||
ble_ancs_c_evt_notif_t const * p_notif)
|
||||
{
|
||||
uint32_t err_code;
|
||||
err_code = ble_ancs_verify_notification_format(p_notif);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
err_code = ble_ancs_get_notif_attrs(p_ancs, p_notif->notif_uid);
|
||||
p_ancs->parse_info.parse_state = COMMAND_ID;
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
static uint16_t encode_notif_action(uint8_t * p_encoded_data, uint32_t uid, ble_ancs_c_action_id_values_t action_id)
|
||||
{
|
||||
uint8_t index = 0;
|
||||
|
||||
p_encoded_data[index++] = BLE_ANCS_COMMAND_ID_GET_PERFORM_NOTIF_ACTION;
|
||||
index += uint32_encode(uid, &p_encoded_data[index]);
|
||||
p_encoded_data[index++] = (uint8_t)action_id;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
ret_code_t nrf_ancs_perform_notif_action(ble_ancs_c_t * p_ancs, uint32_t uid, ble_ancs_c_action_id_values_t action_id)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_ancs);
|
||||
|
||||
nrf_ble_gq_req_t ancs_req;
|
||||
uint8_t gattc_value[BLE_ANCS_WRITE_MAX_MSG_LENGTH];
|
||||
|
||||
memset(&ancs_req, 0, sizeof(nrf_ble_gq_req_t));
|
||||
|
||||
uint16_t len = encode_notif_action(gattc_value, uid, action_id);
|
||||
|
||||
ancs_req.type = NRF_BLE_GQ_REQ_GATTC_WRITE;
|
||||
ancs_req.error_handler.cb = p_ancs->gatt_err_handler;
|
||||
ancs_req.error_handler.p_ctx = p_ancs;
|
||||
ancs_req.params.gattc_write.handle = p_ancs->service.control_point_char.handle_value;
|
||||
ancs_req.params.gattc_write.p_value = gattc_value;
|
||||
ancs_req.params.gattc_write.offset = 0;
|
||||
ancs_req.params.gattc_write.write_op = BLE_GATT_OP_WRITE_REQ;
|
||||
ancs_req.params.gattc_write.len = len;
|
||||
|
||||
return nrf_ble_gq_item_add(p_ancs->p_gatt_queue, &ancs_req, p_ancs->conn_handle);
|
||||
}
|
||||
|
||||
ret_code_t nrf_ble_ancs_c_handles_assign(ble_ancs_c_t * p_ancs,
|
||||
uint16_t const conn_handle,
|
||||
ble_ancs_c_service_t const * p_peer_handles)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_ancs);
|
||||
|
||||
p_ancs->conn_handle = conn_handle;
|
||||
|
||||
if (p_peer_handles != NULL)
|
||||
{
|
||||
p_ancs->service.control_point_char.handle_value = p_peer_handles->control_point_char.handle_value;
|
||||
p_ancs->service.data_source_cccd.handle = p_peer_handles->data_source_cccd.handle;
|
||||
p_ancs->service.data_source_char.handle_value = p_peer_handles->data_source_char.handle_value;
|
||||
p_ancs->service.notif_source_cccd.handle = p_peer_handles->notif_source_cccd.handle;
|
||||
p_ancs->service.notif_source_char.handle_value = p_peer_handles->notif_source_char.handle_value;
|
||||
}
|
||||
|
||||
return nrf_ble_gq_conn_handle_register(p_ancs->p_gatt_queue, conn_handle);
|
||||
}
|
||||
|
||||
#endif// NRF_MODULE_ENABLED(BLE_ANCS_C)
|
||||
620
components/ble/ble_services/ble_ancs_c/nrf_ble_ancs_c.h
Normal file
620
components/ble/ble_services/ble_ancs_c/nrf_ble_ancs_c.h
Normal file
@@ -0,0 +1,620 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 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 ble_ancs_c Apple Notification Service Client
|
||||
* @{
|
||||
* @ingroup ble_sdk_srv
|
||||
*
|
||||
* @brief Apple Notification Center Service Client module.
|
||||
*
|
||||
* @details Disclaimer: This client implementation of the Apple Notification Center Service can
|
||||
* be changed at any time by Nordic Semiconductor ASA. Server implementations such as the
|
||||
* ones found in iOS can be changed at any time by Apple and may cause this client
|
||||
* implementation to stop working.
|
||||
*
|
||||
* This module implements the Apple Notification Center Service (ANCS) client.
|
||||
* This client can be used as a Notification Consumer (NC) that receives data
|
||||
* notifications from a Notification Provider (NP). The NP is typically an iOS
|
||||
* device that is acting as a server. For terminology and up-to-date specs, see
|
||||
* http://developer.apple.com.
|
||||
*
|
||||
* The term "notification" is used in two different meanings:
|
||||
* - An <i>iOS notification</i> is the data received from the Notification Provider.
|
||||
* - A <i>GATTC notification</i> is a way to transfer data with <i>Bluetooth</i> Smart.
|
||||
* In this module, iOS notifications are received through the GATTC notifications.
|
||||
* The full term (iOS notification or GATTC notification) is used where required to avoid confusion.
|
||||
*
|
||||
* Upon initializing the module, you must add the different iOS notification attributes you
|
||||
* would like to receive for iOS notifications (see @ref nrf_ble_ancs_c_attr_add).
|
||||
*
|
||||
* Once a connection is established with a central device, the module does a service discovery to
|
||||
* discover the ANCS server handles. If this succeeds (@ref BLE_ANCS_C_EVT_DISCOVERY_COMPLETE),
|
||||
* the handles for the ANCS server are part of the @ref ble_ancs_c_evt_t structure and must be
|
||||
* assigned to an ANCS_C instance using the @ref nrf_ble_ancs_c_handles_assign function. For more
|
||||
* information about service discovery, see the @ref lib_ble_db_discovery documentation.
|
||||
*
|
||||
* The application can now subscribe to iOS notifications with
|
||||
* @ref ble_ancs_c_notif_source_notif_enable. The notifications arrive in the @ref BLE_ANCS_C_EVT_NOTIF event.
|
||||
* @ref nrf_ble_ancs_c_request_attrs can be used to request attributes for the notifications. The attributes
|
||||
* arrive in the @ref BLE_ANCS_C_EVT_NOTIF_ATTRIBUTE event.
|
||||
* Use @ref nrf_ble_ancs_c_app_attr_request to request attributes of the app that issued
|
||||
* the notifications. The app attributes arrive in the @ref BLE_ANCS_C_EVT_APP_ATTRIBUTE event.
|
||||
* Use @ref nrf_ancs_perform_notif_action to make the Notification Provider perform an
|
||||
* action based on the provided notification.
|
||||
*
|
||||
* @msc
|
||||
* hscale = "1.5";
|
||||
* Application, ANCS_C;
|
||||
* |||;
|
||||
* Application=>ANCS_C [label = "ble_ancs_c_attr_add(attribute)"];
|
||||
* Application=>ANCS_C [label = "ble_ancs_c_init(ancs_instance, event_handler)"];
|
||||
* ...;
|
||||
* Application<<=ANCS_C [label = "BLE_ANCS_C_EVT_DISCOVERY_COMPLETE"];
|
||||
* Application=>ANCS_C [label = "ble_ancs_c_handles_assign(ancs_instance, conn_handle, service_handles)"];
|
||||
* Application=>ANCS_C [label = "ble_ancs_c_notif_source_notif_enable(ancs_instance)"];
|
||||
* Application=>ANCS_C [label = "ble_ancs_c_data_source_notif_enable(ancs_instance)"];
|
||||
* |||;
|
||||
* ...;
|
||||
* |||;
|
||||
* Application<<=ANCS_C [label = "BLE_ANCS_C_EVT_NOTIF"];
|
||||
* |||;
|
||||
* ...;
|
||||
* |||;
|
||||
* Application=>ANCS_C [label = "ble_ancs_c_request_attrs(attr_id, buffer)"];
|
||||
* Application<<=ANCS_C [label = "BLE_ANCS_C_EVT_NOTIF_ATTRIBUTE"];
|
||||
* |||;
|
||||
* @endmsc
|
||||
*
|
||||
* @note The application must register this module as the BLE event observer by using the
|
||||
* NRF_SDH_BLE_OBSERVER macro. Example:
|
||||
* @code
|
||||
* ble_ancs_c_t instance;
|
||||
* NRF_SDH_BLE_OBSERVER(anything, BLE_ANCS_C_BLE_OBSERVER_PRIO,
|
||||
* ble_ancs_c_on_ble_evt, &instance);
|
||||
* @endcode
|
||||
*/
|
||||
#ifndef BLE_ANCS_C_H__
|
||||
#define BLE_ANCS_C_H__
|
||||
|
||||
#include "ble_types.h"
|
||||
#include "ble_srv_common.h"
|
||||
#include "sdk_errors.h"
|
||||
#include "ble_db_discovery.h"
|
||||
#include "nrf_sdh_ble.h"
|
||||
#include "nrf_ble_gq.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**@brief Macro for defining a ble_ancs_c instance.
|
||||
*
|
||||
* @param _name Name of the instance.
|
||||
* @hideinitializer
|
||||
*/
|
||||
#define BLE_ANCS_C_DEF(_name) \
|
||||
static ble_ancs_c_t _name; \
|
||||
NRF_SDH_BLE_OBSERVER(_name ## _obs, \
|
||||
BLE_ANCS_C_BLE_OBSERVER_PRIO, \
|
||||
ble_ancs_c_on_ble_evt, &_name)
|
||||
|
||||
/** @brief Macro for defining multiple ble_ancs_c instances.
|
||||
*
|
||||
* @param _name Name of the array of instances.
|
||||
* @param _cnt Number of instances to define.
|
||||
* @hideinitializer
|
||||
*/
|
||||
#define BLE_ANCS_C_ARRAY_DEF(_name, _cnt) \
|
||||
sstatic ble_ancs_c_t _name[_cnt]; \
|
||||
NRF_SDH_BLE_OBSERVERS(_name ## _obs, \
|
||||
BLE_ANCS_C_BLE_OBSERVER_PRIO, \
|
||||
ble_ancs_c_on_ble_evt, &_name, _cnt)
|
||||
|
||||
#define BLE_ANCS_ATTR_DATA_MAX 32 //!< Maximum data length of an iOS notification attribute.
|
||||
#define BLE_ANCS_NB_OF_CATEGORY_ID 12 //!< Number of iOS notification categories: Other, Incoming Call, Missed Call, Voice Mail, Social, Schedule, Email, News, Health and Fitness, Business and Finance, Location, Entertainment.
|
||||
#define BLE_ANCS_NB_OF_NOTIF_ATTR 8 //!< Number of iOS notification attributes: AppIdentifier, Title, Subtitle, Message, MessageSize, Date, PositiveActionLabel, NegativeActionLabel.
|
||||
#define BLE_ANCS_NB_OF_APP_ATTR 1 //!< Number of iOS application attributes: DisplayName.
|
||||
#define BLE_ANCS_NB_OF_EVT_ID 3 //!< Number of iOS notification events: Added, Modified, Removed.
|
||||
|
||||
/** @brief Length of the iOS notification data.
|
||||
*
|
||||
* @details 8 bytes:
|
||||
* Event ID |Event flags |Category ID |Category count|Notification UID
|
||||
* ---------|------------|------------|--------------|----------------
|
||||
* 1 byte | 1 byte | 1 byte | 1 byte | 4 bytes
|
||||
*/
|
||||
#define BLE_ANCS_NOTIFICATION_DATA_LENGTH 8
|
||||
|
||||
#define ANCS_UUID_SERVICE 0xF431 //!< 16-bit service UUID for the Apple Notification Center Service.
|
||||
#define ANCS_UUID_CHAR_CONTROL_POINT 0xD8F3 //!< 16-bit control point UUID.
|
||||
#define ANCS_UUID_CHAR_DATA_SOURCE 0xC6E9 //!< 16-bit data source UUID.
|
||||
#define ANCS_UUID_CHAR_NOTIFICATION_SOURCE 0x120D //!< 16-bit notification source UUID.
|
||||
|
||||
#define BLE_ANCS_EVENT_FLAG_SILENT 0 //!< 0b.......1 Silent: First (LSB) bit is set. All flags can be active at the same time.
|
||||
#define BLE_ANCS_EVENT_FLAG_IMPORTANT 1 //!< 0b......1. Important: Second (LSB) bit is set. All flags can be active at the same time.
|
||||
#define BLE_ANCS_EVENT_FLAG_PREEXISTING 2 //!< 0b.....1.. Pre-existing: Third (LSB) bit is set. All flags can be active at the same time.
|
||||
#define BLE_ANCS_EVENT_FLAG_POSITIVE_ACTION 3 //!< 0b....1... Positive action: Fourth (LSB) bit is set. All flags can be active at the same time.
|
||||
#define BLE_ANCS_EVENT_FLAG_NEGATIVE_ACTION 4 //!< 0b...1.... Negative action: Fifth (LSB) bit is set. All flags can be active at the same time.
|
||||
|
||||
/** @defgroup BLE_ANCS_NP_ERROR_CODES Notification Provider (iOS) Error Codes
|
||||
* @{ */
|
||||
#define BLE_ANCS_NP_UNKNOWN_COMMAND 0x01A0 //!< The command ID is unknown to the NP.
|
||||
#define BLE_ANCS_NP_INVALID_COMMAND 0x01A1 //!< The command format is invalid.
|
||||
#define BLE_ANCS_NP_INVALID_PARAMETER 0x01A2 //!< One or more parameters do not exist in the NP.
|
||||
#define BLE_ANCS_NP_ACTION_FAILED 0x01A3 //!< The action failed to be performed by the NP.
|
||||
/** @} */
|
||||
|
||||
|
||||
/**@brief Event types that are passed from client to application on an event. */
|
||||
typedef enum
|
||||
{
|
||||
BLE_ANCS_C_EVT_DISCOVERY_COMPLETE, /**< A successful connection has been established and the service was found on the connected peer. */
|
||||
BLE_ANCS_C_EVT_DISCOVERY_FAILED, /**< It was not possible to discover the service or characteristics of the connected peer. */
|
||||
BLE_ANCS_C_EVT_NOTIF, /**< An iOS notification was received on the notification source control point. */
|
||||
BLE_ANCS_C_EVT_INVALID_NOTIF, /**< An iOS notification was received on the notification source control point, but the format is invalid. */
|
||||
BLE_ANCS_C_EVT_NOTIF_ATTRIBUTE, /**< A received iOS notification attribute has been parsed. */
|
||||
BLE_ANCS_C_EVT_APP_ATTRIBUTE, /**< An iOS app attribute has been parsed. */
|
||||
BLE_ANCS_C_EVT_NP_ERROR, /**< An error has been sent on the ANCS Control Point from the iOS Notification Provider. */
|
||||
} ble_ancs_c_evt_type_t;
|
||||
|
||||
/**@brief Category IDs for iOS notifications. */
|
||||
typedef enum
|
||||
{
|
||||
BLE_ANCS_CATEGORY_ID_OTHER, /**< The iOS notification belongs to the "Other" category. */
|
||||
BLE_ANCS_CATEGORY_ID_INCOMING_CALL, /**< The iOS notification belongs to the "Incoming Call" category. */
|
||||
BLE_ANCS_CATEGORY_ID_MISSED_CALL, /**< The iOS notification belongs to the "Missed Call" category. */
|
||||
BLE_ANCS_CATEGORY_ID_VOICE_MAIL, /**< The iOS notification belongs to the "Voice Mail" category. */
|
||||
BLE_ANCS_CATEGORY_ID_SOCIAL, /**< The iOS notification belongs to the "Social" category. */
|
||||
BLE_ANCS_CATEGORY_ID_SCHEDULE, /**< The iOS notification belongs to the "Schedule" category. */
|
||||
BLE_ANCS_CATEGORY_ID_EMAIL, /**< The iOS notification belongs to the "Email" category. */
|
||||
BLE_ANCS_CATEGORY_ID_NEWS, /**< The iOS notification belongs to the "News" category. */
|
||||
BLE_ANCS_CATEGORY_ID_HEALTH_AND_FITNESS, /**< The iOS notification belongs to the "Health and Fitness" category. */
|
||||
BLE_ANCS_CATEGORY_ID_BUSINESS_AND_FINANCE, /**< The iOS notification belongs to the "Business and Finance" category. */
|
||||
BLE_ANCS_CATEGORY_ID_LOCATION, /**< The iOS notification belongs to the "Location" category. */
|
||||
BLE_ANCS_CATEGORY_ID_ENTERTAINMENT /**< The iOS notification belongs to the "Entertainment" category. */
|
||||
} ble_ancs_c_category_id_val_t;
|
||||
|
||||
/**@brief Event IDs for iOS notifications. */
|
||||
typedef enum
|
||||
{
|
||||
BLE_ANCS_EVENT_ID_NOTIFICATION_ADDED, /**< The iOS notification was added. */
|
||||
BLE_ANCS_EVENT_ID_NOTIFICATION_MODIFIED, /**< The iOS notification was modified. */
|
||||
BLE_ANCS_EVENT_ID_NOTIFICATION_REMOVED /**< The iOS notification was removed. */
|
||||
} ble_ancs_c_evt_id_values_t;
|
||||
|
||||
/**@brief Control point command IDs that the Notification Consumer can send to the Notification Provider. */
|
||||
typedef enum
|
||||
{
|
||||
BLE_ANCS_COMMAND_ID_GET_NOTIF_ATTRIBUTES, /**< Requests attributes to be sent from the NP to the NC for a given notification. */
|
||||
BLE_ANCS_COMMAND_ID_GET_APP_ATTRIBUTES, /**< Requests attributes to be sent from the NP to the NC for a given iOS app. */
|
||||
BLE_ANCS_COMMAND_ID_GET_PERFORM_NOTIF_ACTION, /**< Requests an action to be performed on a given notification. For example, dismiss an alarm. */
|
||||
} ble_ancs_c_cmd_id_val_t;
|
||||
|
||||
/**@brief IDs for actions that can be performed for iOS notifications. */
|
||||
typedef enum
|
||||
{
|
||||
ACTION_ID_POSITIVE = 0, /**< Positive action. */
|
||||
ACTION_ID_NEGATIVE /**< Negative action. */
|
||||
} ble_ancs_c_action_id_values_t;
|
||||
|
||||
/**@brief App attribute ID values.
|
||||
* @details Currently, only one value is defined. However, the number of app
|
||||
* attributes might increase. For this reason, they are stored in an enumeration.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
BLE_ANCS_APP_ATTR_ID_DISPLAY_NAME = 0 /**< Command used to get the display name for an app identifier. */
|
||||
} ble_ancs_c_app_attr_id_val_t;
|
||||
|
||||
/**@brief IDs for iOS notification attributes. */
|
||||
typedef enum
|
||||
{
|
||||
BLE_ANCS_NOTIF_ATTR_ID_APP_IDENTIFIER = 0, /**< Identifies that the attribute data is of an "App Identifier" type. */
|
||||
BLE_ANCS_NOTIF_ATTR_ID_TITLE, /**< Identifies that the attribute data is a "Title". */
|
||||
BLE_ANCS_NOTIF_ATTR_ID_SUBTITLE, /**< Identifies that the attribute data is a "Subtitle". */
|
||||
BLE_ANCS_NOTIF_ATTR_ID_MESSAGE, /**< Identifies that the attribute data is a "Message". */
|
||||
BLE_ANCS_NOTIF_ATTR_ID_MESSAGE_SIZE, /**< Identifies that the attribute data is a "Message Size". */
|
||||
BLE_ANCS_NOTIF_ATTR_ID_DATE, /**< Identifies that the attribute data is a "Date". */
|
||||
BLE_ANCS_NOTIF_ATTR_ID_POSITIVE_ACTION_LABEL, /**< The notification has a "Positive action" that can be executed associated with it. */
|
||||
BLE_ANCS_NOTIF_ATTR_ID_NEGATIVE_ACTION_LABEL, /**< The notification has a "Negative action" that can be executed associated with it. */
|
||||
} ble_ancs_c_notif_attr_id_val_t;
|
||||
|
||||
/**@brief Flags for iOS notifications. */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t silent : 1; //!< If this flag is set, the notification has a low priority.
|
||||
uint8_t important : 1; //!< If this flag is set, the notification has a high priority.
|
||||
uint8_t pre_existing : 1; //!< If this flag is set, the notification is pre-existing.
|
||||
uint8_t positive_action : 1; //!< If this flag is set, the notification has a positive action that can be taken.
|
||||
uint8_t negative_action : 1; //!< If this flag is set, the notification has a negative action that can be taken.
|
||||
} ble_ancs_c_notif_flags_t;
|
||||
|
||||
/**@brief Parsing states for received iOS notification and app attributes. */
|
||||
typedef enum
|
||||
{
|
||||
COMMAND_ID, /**< Parsing the command ID. */
|
||||
NOTIF_UID, /**< Parsing the notification UID. */
|
||||
APP_ID, /**< Parsing app ID. */
|
||||
ATTR_ID, /**< Parsing attribute ID. */
|
||||
ATTR_LEN1, /**< Parsing the LSB of the attribute length. */
|
||||
ATTR_LEN2, /**< Parsing the MSB of the attribute length. */
|
||||
ATTR_DATA, /**< Parsing the attribute data. */
|
||||
ATTR_SKIP, /**< Parsing is skipped for the rest of an attribute (or entire attribute). */
|
||||
DONE, /**< Parsing for one attribute is done. */
|
||||
} ble_ancs_c_parse_state_t;
|
||||
|
||||
/**@brief iOS notification structure. */
|
||||
typedef struct
|
||||
{
|
||||
uint32_t notif_uid; //!< Notification UID.
|
||||
ble_ancs_c_evt_id_values_t evt_id; //!< Whether the notification was added, removed, or modified.
|
||||
ble_ancs_c_notif_flags_t evt_flags; //!< Bitmask to signal whether a special condition applies to the notification. For example, "Silent" or "Important".
|
||||
ble_ancs_c_category_id_val_t category_id; //!< Classification of the notification type. For example, email or location.
|
||||
uint8_t category_count; //!< Current number of active notifications for this category ID.
|
||||
} ble_ancs_c_evt_notif_t;
|
||||
|
||||
/**@brief iOS attribute structure. This type is used for both notification attributes and app attributes. */
|
||||
typedef struct
|
||||
{
|
||||
uint16_t attr_len; //!< Length of the received attribute data.
|
||||
uint32_t attr_id; //!< Classification of the attribute type. For example, "Title" or "Date".
|
||||
uint8_t * p_attr_data; //!< Pointer to where the memory is allocated for storing incoming attributes.
|
||||
} ble_ancs_c_attr_t;
|
||||
|
||||
/**@brief iOS notification attribute structure for incoming attributes. */
|
||||
typedef struct
|
||||
{
|
||||
uint32_t notif_uid; //!< UID of the notification that the attribute belongs to.
|
||||
ble_ancs_c_attr_t attrs; //!< A received attribute.
|
||||
} ble_ancs_c_evt_attr_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t attr_len; //!< Length of the received attribute data.
|
||||
uint32_t attr_id; //!< Classification of the attribute type. For example, "Title" or "Date".
|
||||
uint8_t * p_attr_data; //!< Pointer to where the memory is allocated for storing incoming attributes.
|
||||
} ble_ancs_c_evt_app_attr_t;
|
||||
|
||||
/**@brief iOS notification attribute content requested by the application. */
|
||||
typedef struct
|
||||
{
|
||||
bool get; //!< Boolean to determine whether this attribute will be requested from the Notification Provider.
|
||||
uint32_t attr_id; //!< Attribute ID: AppIdentifier(0), Title(1), Subtitle(2), Message(3), MessageSize(4), Date(5), PositiveActionLabel(6), NegativeActionLabel(7).
|
||||
uint16_t attr_len; //!< Length of the attribute. If more data is received from the Notification Provider, all the data beyond this length is discarded.
|
||||
uint8_t * p_attr_data; //!< Pointer to where the memory is allocated for storing incoming attributes.
|
||||
} ble_ancs_c_attr_list_t;
|
||||
|
||||
/**@brief Structure used for holding the Apple Notification Center Service found during the
|
||||
discovery process.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
ble_gattc_service_t service; //!< The GATT Service holding the discovered Apple Notification Center Service. (0xF431).
|
||||
ble_gattc_char_t control_point_char; //!< ANCS Control Point Characteristic. Allows interaction with the peer (0xD8F3).
|
||||
ble_gattc_char_t notif_source_char; //!< ANCS Notification Source Characteristic. Keeps track of arrival, modification, and removal of notifications (0x120D).
|
||||
ble_gattc_desc_t notif_source_cccd; //!< ANCS Notification Source Characteristic Descriptor. Enables or disables GATT notifications.
|
||||
ble_gattc_char_t data_source_char; //!< ANCS Data Source Characteristic, where attribute data for the notifications is received from peer (0xC6E9).
|
||||
ble_gattc_desc_t data_source_cccd; //!< ANCS Data Source Characteristic Descriptor. Enables or disables GATT notifications.
|
||||
} ble_ancs_c_service_t;
|
||||
|
||||
/**@brief ANCS client module event structure.
|
||||
*
|
||||
* @details The structure contains the event that is to be handled by the main application.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
ble_ancs_c_evt_type_t evt_type; //!< Type of event.
|
||||
uint16_t conn_handle; //!< Connection handle on which the ANCS service was discovered on the peer device. This is filled if the @p evt_type is @ref BLE_ANCS_C_EVT_DISCOVERY_COMPLETE.
|
||||
ble_ancs_c_evt_notif_t notif; //!< iOS notification. This is filled if @p evt_type is @ref BLE_ANCS_C_EVT_NOTIF.
|
||||
uint16_t err_code_np; //!< An error coming from the Notification Provider. This is filled with @ref BLE_ANCS_NP_ERROR_CODES if @p evt_type is @ref BLE_ANCS_C_EVT_NP_ERROR.
|
||||
ble_ancs_c_attr_t attr; //!< iOS notification attribute or app attribute, depending on the event type.
|
||||
uint32_t notif_uid; //!< Notification UID.
|
||||
uint8_t app_id[BLE_ANCS_ATTR_DATA_MAX]; //!< App identifier.
|
||||
ble_ancs_c_service_t service; //!< Information on the discovered Alert Notification Service. This is filled if the @p evt_type is @ref BLE_ANCS_C_EVT_DISCOVERY_COMPLETE.
|
||||
} ble_ancs_c_evt_t;
|
||||
|
||||
/**@brief iOS notification event handler type. */
|
||||
typedef void (*ble_ancs_c_evt_handler_t) (ble_ancs_c_evt_t * p_evt);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ble_ancs_c_attr_list_t * p_attr_list; //!< The current list of attributes that are being parsed. This will point to either @ref ble_ancs_c_t::ancs_notif_attr_list or @ref ble_ancs_c_t::ancs_app_attr_list.
|
||||
uint32_t nb_of_attr; //!< Number of possible attributes. When parsing begins, it is set to either @ref BLE_ANCS_NB_OF_NOTIF_ATTR or @ref BLE_ANCS_NB_OF_APP_ATTR.
|
||||
uint32_t expected_number_of_attrs; //!< The number of attributes expected upon receiving attributes. Keeps track of when to stop reading incoming attributes.
|
||||
ble_ancs_c_parse_state_t parse_state; //!< ANCS notification attribute parsing state.
|
||||
ble_ancs_c_cmd_id_val_t command_id; //!< Variable to keep track of what command type is being parsed ( @ref BLE_ANCS_COMMAND_ID_GET_NOTIF_ATTRIBUTES or @ref BLE_ANCS_COMMAND_ID_GET_APP_ATTRIBUTES).
|
||||
uint8_t * p_data_dest; //!< Attribute that the parsed data is copied into.
|
||||
uint16_t current_attr_index; //!< Variable to keep track of the parsing progress, for the given attribute.
|
||||
uint32_t current_app_id_index; //!< Variable to keep track of the parsing progress, for the given app identifier.
|
||||
} ble_ancs_parse_sm_t;
|
||||
|
||||
/**@brief iOS notification structure, which contains various status information for the client. */
|
||||
typedef struct
|
||||
{
|
||||
ble_ancs_c_evt_handler_t evt_handler; //!< Event handler to be called for handling events in the Apple Notification client application.
|
||||
ble_srv_error_handler_t error_handler; //!< Function to be called in case of an error.
|
||||
nrf_ble_gq_req_error_cb_t gatt_err_handler; //!< Error handler to be called in case of an error from SoftDevice.
|
||||
uint16_t conn_handle; //!< Handle of the current connection. Set with @ref nrf_ble_ancs_c_handles_assign when connected.
|
||||
ble_ancs_c_service_t service; //!< Structure to store the different handles and UUIDs related to the service.
|
||||
ble_ancs_c_attr_list_t ancs_notif_attr_list[BLE_ANCS_NB_OF_NOTIF_ATTR]; //!< For all attributes: contains information about whether the attributes are to be requested upon attribute request, and the length and buffer of where to store attribute data.
|
||||
ble_ancs_c_attr_list_t ancs_app_attr_list[BLE_ANCS_NB_OF_APP_ATTR]; //!< For all app attributes: contains information about whether the attributes are to be requested upon attribute request, and the length and buffer of where to store attribute data.
|
||||
uint32_t number_of_requested_attr; //!< The number of attributes that are to be requested when an iOS notification attribute request is made.
|
||||
ble_ancs_parse_sm_t parse_info; //!< Structure containing different information used to parse incoming attributes correctly (from data_source characteristic).
|
||||
ble_ancs_c_evt_t evt; //!< Allocate memory for the event here. The event is filled with several iterations of the @ref ancs_parse_get_attrs_response function when requesting iOS notification attributes.
|
||||
nrf_ble_gq_t * p_gatt_queue; //!< Pointer to the BLE GATT Queue instance.
|
||||
|
||||
} ble_ancs_c_t;
|
||||
|
||||
/**@brief Apple Notification client init structure, which contains all options and data needed for
|
||||
* initialization of the client. */
|
||||
typedef struct
|
||||
{
|
||||
ble_ancs_c_evt_handler_t evt_handler; //!< Event handler to be called for handling events in the Battery Service.
|
||||
ble_srv_error_handler_t error_handler; //!< Function to be called in case of an error.
|
||||
nrf_ble_gq_t * p_gatt_queue; //!< Pointer to the BLE GATT Queue instance.
|
||||
} ble_ancs_c_init_t;
|
||||
|
||||
|
||||
/**@brief Apple Notification Center Service UUIDs. */
|
||||
extern const ble_uuid128_t ble_ancs_base_uuid128; //!< Service UUID.
|
||||
extern const ble_uuid128_t ble_ancs_cp_base_uuid128; //!< Control Point UUID.
|
||||
extern const ble_uuid128_t ble_ancs_ns_base_uuid128; //!< Notification Source UUID.
|
||||
extern const ble_uuid128_t ble_ancs_ds_base_uuid128; //!< Data Source UUID.
|
||||
|
||||
|
||||
/**@brief Function for handling BLE stack events of the application.
|
||||
*
|
||||
* @details Handles all events from the BLE stack that are of interest to the ANCS client.
|
||||
*
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
* @param[in] p_context ANCS client structure.
|
||||
*/
|
||||
void ble_ancs_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
|
||||
|
||||
|
||||
/**@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 ANCS at the peer. If it does, this function
|
||||
* calls the application's event handler to indicate that ANCS was
|
||||
* discovered at the peer. The function also populates the event with service-related
|
||||
* information before providing it to the application.
|
||||
*
|
||||
* @param[in] p_ancs Pointer to the ANCS client structure.
|
||||
* @param[in] p_evt Pointer to the event received from the Database Discovery module.
|
||||
*/
|
||||
void ble_ancs_c_on_db_disc_evt(ble_ancs_c_t * p_ancs, ble_db_discovery_evt_t * p_evt);
|
||||
|
||||
|
||||
/**@brief Function for initializing the ANCS client.
|
||||
*
|
||||
* @param[out] p_ancs ANCS client structure. This structure must be
|
||||
* supplied by the application. It is initialized by this function
|
||||
* and will later be used to identify this particular client instance.
|
||||
* @param[in] p_ancs_init Information needed to initialize the client.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the client was initialized successfully. Otherwise, an error code is returned.
|
||||
*/
|
||||
ret_code_t ble_ancs_c_init(ble_ancs_c_t * p_ancs, ble_ancs_c_init_t const * p_ancs_init);
|
||||
|
||||
|
||||
/**@brief Function for writing to the CCCD to enable notifications from the Apple Notification Service.
|
||||
*
|
||||
* @param[in] p_ancs iOS notification structure. This structure must be supplied by
|
||||
* the application. It identifies the particular client instance to use.
|
||||
*
|
||||
* @retval NRF_SUCCESS If writing to the CCCD was successful. Otherwise,
|
||||
* this API propagates the error code returned by function
|
||||
* @ref nrf_ble_gq_item_add.
|
||||
*/
|
||||
ret_code_t ble_ancs_c_notif_source_notif_enable(ble_ancs_c_t const * p_ancs);
|
||||
|
||||
|
||||
/**@brief Function for writing to the CCCD to enable data source notifications from the ANCS.
|
||||
*
|
||||
* @param[in] p_ancs iOS notification structure. This structure must be supplied by
|
||||
* the application. It identifies the particular client instance to use.
|
||||
*
|
||||
* @retval NRF_SUCCESS If writing to the CCCD was successful. Otherwise,
|
||||
* this API propagates the error code returned by function
|
||||
* @ref nrf_ble_gq_item_add.
|
||||
*/
|
||||
ret_code_t ble_ancs_c_data_source_notif_enable(ble_ancs_c_t const * p_ancs);
|
||||
|
||||
|
||||
/**@brief Function for writing to the CCCD to disable notifications from the ANCS.
|
||||
*
|
||||
* @param[in] p_ancs iOS notification structure. This structure must be supplied by
|
||||
* the application. It identifies the particular client instance to use.
|
||||
*
|
||||
* @retval NRF_SUCCESS If writing to the CCCD was successful. Otherwise
|
||||
* this API propagates the error code returned by function
|
||||
* @ref nrf_ble_gq_item_add.
|
||||
*/
|
||||
ret_code_t ble_ancs_c_notif_source_notif_disable(ble_ancs_c_t const * p_ancs);
|
||||
|
||||
|
||||
/**@brief Function for writing to the CCCD to disable data source notifications from the ANCS.
|
||||
*
|
||||
* @param[in] p_ancs iOS notification structure. This structure must be supplied by
|
||||
* the application. It identifies the particular client instance to use.
|
||||
*
|
||||
* @retval NRF_SUCCESS If writing to the CCCD was successful. Otherwise,
|
||||
* this API propagates the error code returned by function
|
||||
* @ref nrf_ble_gq_item_add.
|
||||
*/
|
||||
ret_code_t ble_ancs_c_data_source_notif_disable(ble_ancs_c_t const * p_ancs);
|
||||
|
||||
|
||||
/**@brief Function for registering attributes that will be requested when @ref nrf_ble_ancs_c_request_attrs
|
||||
* is called.
|
||||
*
|
||||
* @param[in] p_ancs ANCS client instance on which the attribute is registered.
|
||||
* @param[in] id ID of the attribute that is added.
|
||||
* @param[in] p_data Pointer to the buffer where the data of the attribute can be stored.
|
||||
* @param[in] len Length of the buffer where the data of the attribute can be stored.
|
||||
|
||||
* @retval NRF_SUCCESS If all operations are successful. Otherwise, an error code is returned.
|
||||
*/
|
||||
ret_code_t nrf_ble_ancs_c_attr_add(ble_ancs_c_t * p_ancs,
|
||||
ble_ancs_c_notif_attr_id_val_t const id,
|
||||
uint8_t * p_data,
|
||||
uint16_t const len);
|
||||
|
||||
|
||||
/**@brief Function for removing attributes, so that they are no longer requested when
|
||||
* @ref nrf_ble_ancs_c_request_attrs is called.
|
||||
*
|
||||
* @param[in] p_ancs ANCS client instance on which the attribute is removed.
|
||||
* @param[in] id ID of the attribute that is removed.
|
||||
*
|
||||
* @retval NRF_SUCCESS If all operations are successful. Otherwise, an error code is returned.
|
||||
*/
|
||||
ret_code_t nrf_ble_ancs_c_attr_remove(ble_ancs_c_t * p_ancs,
|
||||
ble_ancs_c_notif_attr_id_val_t const id);
|
||||
|
||||
/**@brief Function for removing attributes, so that they are no longer requested when
|
||||
* @ref nrf_ble_ancs_c_app_attr_request is called.
|
||||
*
|
||||
* @param[in] p_ancs ANCS client instance on which the attribute is removed.
|
||||
* @param[in] id ID of the attribute that is removed.
|
||||
*
|
||||
* @retval NRF_SUCCESS If all operations are successful. Otherwise, an error code is returned.
|
||||
*/
|
||||
ret_code_t nrf_ble_ancs_c_app_attr_remove(ble_ancs_c_t * p_ancs,
|
||||
ble_ancs_c_app_attr_id_val_t const id);
|
||||
|
||||
|
||||
/**@brief Function for registering attributes that will be requested when @ref nrf_ble_ancs_c_app_attr_request
|
||||
* is called.
|
||||
*
|
||||
* @param[in] p_ancs ANCS client instance on which the attribute is registered.
|
||||
* @param[in] id ID of the attribute that is added.
|
||||
* @param[in] p_data Pointer to the buffer where the data of the attribute can be stored.
|
||||
* @param[in] len Length of the buffer where the data of the attribute can be stored.
|
||||
*
|
||||
* @retval NRF_SUCCESS If all operations are successful. Otherwise, an error code is returned.
|
||||
*/
|
||||
ret_code_t nrf_ble_ancs_c_app_attr_add(ble_ancs_c_t * p_ancs,
|
||||
ble_ancs_c_app_attr_id_val_t const id,
|
||||
uint8_t * p_data,
|
||||
uint16_t const len);
|
||||
|
||||
/**@brief Function for clearing the list of notification attributes and app attributes that
|
||||
* would be requested from NP.
|
||||
*
|
||||
* @param[in] p_ancs iOS notification structure. This structure must be supplied by
|
||||
* the application. It identifies the particular client instance to use.
|
||||
**/
|
||||
ret_code_t nrf_ble_ancs_c_attr_req_clear_all(ble_ancs_c_t * p_ancs);
|
||||
|
||||
/**@brief Function for requesting attributes for a notification.
|
||||
*
|
||||
* @param[in] p_ancs iOS notification structure. This structure must be supplied by
|
||||
* the application. It identifies the particular client instance to use.
|
||||
* @param[in] p_notif Pointer to the notification whose attributes will be requested from
|
||||
* the Notification Provider.
|
||||
*
|
||||
* @retval NRF_SUCCESS If all operations are successful. Otherwise, an error code is returned.
|
||||
*/
|
||||
ret_code_t nrf_ble_ancs_c_request_attrs(ble_ancs_c_t * p_ancs,
|
||||
ble_ancs_c_evt_notif_t const * p_notif);
|
||||
|
||||
/**@brief Function for requesting attributes for a given app.
|
||||
*
|
||||
* @param[in] p_ancs iOS notification structure. This structure must be supplied by
|
||||
* the application. It identifies the particular client instance to use.
|
||||
* @param[in] p_app_id App identifier of the app for which the app attributes are requested.
|
||||
* @param[in] len Length of the app identifier.
|
||||
*
|
||||
* @retval NRF_SUCCESS If all operations are successful. Otherwise, an error code is returned.
|
||||
*/
|
||||
ret_code_t nrf_ble_ancs_c_app_attr_request(ble_ancs_c_t * p_ancs,
|
||||
uint8_t const * p_app_id,
|
||||
uint32_t len);
|
||||
|
||||
|
||||
/**@brief Function for performing a notification action.
|
||||
*
|
||||
* @param[in] p_ancs iOS notification structure. This structure must be supplied by
|
||||
* the application. It identifies the particular client instance to use.
|
||||
* @param[in] uuid The UUID of the notification for which to perform the action.
|
||||
* @param[in] action_id Perform a positive or negative action.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the operation is successful.
|
||||
* @retval NRF_ERROR_NULL If @p p_ancs is a NULL pointer.
|
||||
* @retval err_code Otherwise, this API propagates the error code returned by function
|
||||
* @ref nrf_ble_gq_item_add.
|
||||
*/
|
||||
ret_code_t nrf_ancs_perform_notif_action(ble_ancs_c_t * p_ancs,
|
||||
uint32_t uuid,
|
||||
ble_ancs_c_action_id_values_t action_id);
|
||||
|
||||
/**@brief Function for assigning a handle to this instance of ancs_c.
|
||||
*
|
||||
* @details Call this function when a link has been established with a peer to
|
||||
* associate the link to this instance of the module. This makes it
|
||||
* possible to handle several links and associate each link to a particular
|
||||
* instance of this module. The connection handle and attribute handles are
|
||||
* provided from the discovery event @ref BLE_ANCS_C_EVT_DISCOVERY_COMPLETE.
|
||||
*
|
||||
* @param[in] p_ancs Pointer to the ANCS client structure instance for associating the link.
|
||||
* @param[in] conn_handle Connection handle to associated with the given ANCS instance.
|
||||
* @param[in] p_service Attribute handles on the ANCS server that you want this ANCS client to
|
||||
* interact with.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the operation is successful.
|
||||
* @retval NRF_ERROR_NULL If @p p_ancs is a NULL pointer.
|
||||
* @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_ancs_c_handles_assign(ble_ancs_c_t * p_ancs,
|
||||
uint16_t const conn_handle,
|
||||
ble_ancs_c_service_t const * p_service);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // BLE_ANCS_C_H__
|
||||
|
||||
/** @} */
|
||||
|
||||
530
components/ble/ble_services/ble_ans_c/ble_ans_c.c
Normal file
530
components/ble/ble_services/ble_ans_c/ble_ans_c.c
Normal file
@@ -0,0 +1,530 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 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.
|
||||
*
|
||||
*/
|
||||
/* Attention!
|
||||
* To maintain compliance with Nordic Semiconductor ASA's Bluetooth profile
|
||||
* qualification listings, this section of source code must not be modified.
|
||||
*/
|
||||
#include "sdk_common.h"
|
||||
#if NRF_MODULE_ENABLED(BLE_ANS_C)
|
||||
#include "ble_ans_c.h"
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include "ble_err.h"
|
||||
#include "nrf_assert.h"
|
||||
#include "ble_db_discovery.h"
|
||||
#define NRF_LOG_MODULE_NAME ble_ans_c
|
||||
#include "nrf_log.h"
|
||||
NRF_LOG_MODULE_REGISTER();
|
||||
|
||||
#define NOTIFICATION_DATA_LENGTH 2 /**< The mandatory length of the notification data. After the mandatory data, the optional message is located. */
|
||||
#define READ_DATA_LENGTH_MIN 1 /**< Minimum data length in a valid Alert Notification Read Response message. */
|
||||
#define WRITE_MESSAGE_LENGTH 2 /**< Length of the write message for CCCD and control point. */
|
||||
|
||||
|
||||
/**@brief Function for intercepting GATTC and @ref nrf_ble_gq errors.
|
||||
*
|
||||
* @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)
|
||||
{
|
||||
ble_ans_c_t * p_ans = (ble_ans_c_t *)p_ctx;
|
||||
|
||||
NRF_LOG_DEBUG("A GATT Client error has occurred on conn_handle: 0X%X", conn_handle);
|
||||
|
||||
if (p_ans->error_handler != NULL)
|
||||
{
|
||||
p_ans->error_handler(nrf_error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** @brief Function for copying a characteristic.
|
||||
*/
|
||||
static void char_set(ble_gattc_char_t * p_dest_char, ble_gattc_char_t const * p_source_char)
|
||||
{
|
||||
memcpy(p_dest_char, p_source_char, sizeof(ble_gattc_char_t));
|
||||
}
|
||||
|
||||
static void char_cccd_set(ble_gattc_desc_t * p_cccd, uint16_t cccd_handle)
|
||||
{
|
||||
p_cccd->handle = cccd_handle;
|
||||
}
|
||||
|
||||
/** @brief Function for checking the presence of all the handles required by the client to use the server.
|
||||
*/
|
||||
static bool is_valid_ans_srv_discovered(ble_ans_c_service_t const * p_srv)
|
||||
{
|
||||
if ((p_srv->alert_notif_ctrl_point.handle_value == BLE_GATT_HANDLE_INVALID) ||
|
||||
(p_srv->suported_new_alert_cat.handle_value == BLE_GATT_HANDLE_INVALID) ||
|
||||
(p_srv->suported_unread_alert_cat.handle_value == BLE_GATT_HANDLE_INVALID) ||
|
||||
(p_srv->new_alert.handle_value == BLE_GATT_HANDLE_INVALID) ||
|
||||
(p_srv->unread_alert_status.handle_value == BLE_GATT_HANDLE_INVALID) ||
|
||||
(p_srv->new_alert_cccd.handle == BLE_GATT_HANDLE_INVALID) ||
|
||||
(p_srv->unread_alert_cccd.handle == BLE_GATT_HANDLE_INVALID)
|
||||
)
|
||||
{
|
||||
// At least one required characteristic is missing on the server side.
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void ble_ans_c_on_db_disc_evt(ble_ans_c_t * p_ans, ble_db_discovery_evt_t const * p_evt)
|
||||
{
|
||||
ble_ans_c_evt_t evt;
|
||||
|
||||
memset(&evt, 0, sizeof(ble_ans_c_evt_t));
|
||||
evt.conn_handle = p_evt->conn_handle;
|
||||
|
||||
// Check if the Alert Notification Service is discovered.
|
||||
if (p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE
|
||||
&&
|
||||
p_evt->params.discovered_db.srv_uuid.uuid == BLE_UUID_ALERT_NOTIFICATION_SERVICE
|
||||
&&
|
||||
p_evt->params.discovered_db.srv_uuid.type == BLE_UUID_TYPE_BLE)
|
||||
{
|
||||
// Find the characteristics inside the service.
|
||||
for (uint8_t i = 0; i < p_evt->params.discovered_db.char_count; i++)
|
||||
{
|
||||
ble_gatt_db_char_t const * p_char = &(p_evt->params.discovered_db.charateristics[i]);
|
||||
|
||||
switch (p_char->characteristic.uuid.uuid)
|
||||
{
|
||||
case BLE_UUID_ALERT_NOTIFICATION_CONTROL_POINT_CHAR:
|
||||
NRF_LOG_DEBUG("Found Ctrlpt \r\n\r");
|
||||
char_set(&evt.data.service.alert_notif_ctrl_point, &p_char->characteristic);
|
||||
break;
|
||||
|
||||
case BLE_UUID_UNREAD_ALERT_CHAR:
|
||||
NRF_LOG_DEBUG("Found Unread Alert \r\n\r");
|
||||
char_set(&evt.data.service.unread_alert_status, &p_char->characteristic);
|
||||
char_cccd_set(&evt.data.service.unread_alert_cccd,
|
||||
p_char->cccd_handle);
|
||||
break;
|
||||
|
||||
case BLE_UUID_NEW_ALERT_CHAR:
|
||||
NRF_LOG_DEBUG("Found New Alert \r\n\r");
|
||||
char_set(&evt.data.service.new_alert, &p_char->characteristic);
|
||||
char_cccd_set(&evt.data.service.new_alert_cccd,
|
||||
p_char->cccd_handle);
|
||||
break;
|
||||
|
||||
case BLE_UUID_SUPPORTED_UNREAD_ALERT_CATEGORY_CHAR:
|
||||
NRF_LOG_DEBUG("Found supported unread alert category \r\n\r");
|
||||
char_set(&evt.data.service.suported_unread_alert_cat, &p_char->characteristic);
|
||||
break;
|
||||
|
||||
case BLE_UUID_SUPPORTED_NEW_ALERT_CATEGORY_CHAR:
|
||||
NRF_LOG_DEBUG("Found supported new alert category \r\n\r");
|
||||
char_set(&evt.data.service.suported_new_alert_cat, &p_char->characteristic);
|
||||
break;
|
||||
|
||||
default:
|
||||
// No implementation needed.
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (is_valid_ans_srv_discovered(&evt.data.service))
|
||||
{
|
||||
evt.evt_type = BLE_ANS_C_EVT_DISCOVERY_COMPLETE;
|
||||
}
|
||||
}
|
||||
else if ((p_evt->evt_type == BLE_DB_DISCOVERY_SRV_NOT_FOUND) ||
|
||||
(p_evt->evt_type == BLE_DB_DISCOVERY_ERROR))
|
||||
{
|
||||
evt.evt_type = BLE_ANS_C_EVT_DISCOVERY_FAILED;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
p_ans->evt_handler(&evt);
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for receiving and validating notifications received from the central.
|
||||
*/
|
||||
static void event_notify(ble_ans_c_t * p_ans, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
uint32_t message_length;
|
||||
ble_ans_c_evt_t event;
|
||||
ble_ans_alert_notification_t * p_alert = &event.data.alert;
|
||||
ble_gattc_evt_hvx_t const * p_notification = &p_ble_evt->evt.gattc_evt.params.hvx;
|
||||
|
||||
// If the message is not valid, then ignore.
|
||||
event.evt_type = BLE_ANS_C_EVT_NOTIFICATION;
|
||||
if (p_notification->len < NOTIFICATION_DATA_LENGTH)
|
||||
{
|
||||
return;
|
||||
}
|
||||
message_length = p_notification->len - NOTIFICATION_DATA_LENGTH;
|
||||
|
||||
if (p_notification->handle == p_ans->service.new_alert.handle_value)
|
||||
{
|
||||
BLE_UUID_COPY_INST(event.uuid, p_ans->service.new_alert.uuid);
|
||||
}
|
||||
else if (p_notification->handle == p_ans->service.unread_alert_status.handle_value)
|
||||
{
|
||||
BLE_UUID_COPY_INST(event.uuid, p_ans->service.unread_alert_status.uuid);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Nothing to process.
|
||||
return;
|
||||
}
|
||||
|
||||
p_alert->alert_category = p_notification->data[0];
|
||||
p_alert->alert_category_count = p_notification->data[1]; //lint !e415
|
||||
p_alert->alert_msg_length = (message_length > p_ans->message_buffer_size)
|
||||
? p_ans->message_buffer_size
|
||||
: message_length;
|
||||
p_alert->p_alert_msg_buf = p_ans->p_message_buffer;
|
||||
|
||||
memcpy(p_alert->p_alert_msg_buf,
|
||||
&p_notification->data[NOTIFICATION_DATA_LENGTH],
|
||||
p_alert->alert_msg_length); //lint !e416
|
||||
|
||||
p_ans->evt_handler(&event);
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for validating and passing the response to the application,
|
||||
* when a read response is received.
|
||||
*/
|
||||
static void event_read_rsp(ble_ans_c_t * p_ans, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
ble_ans_c_evt_t event;
|
||||
ble_gattc_evt_read_rsp_t const * p_response;
|
||||
|
||||
p_response = &p_ble_evt->evt.gattc_evt.params.read_rsp;
|
||||
event.evt_type = BLE_ANS_C_EVT_READ_RESP;
|
||||
|
||||
if (p_response->len < READ_DATA_LENGTH_MIN)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (p_response->handle == p_ans->service.suported_new_alert_cat.handle_value)
|
||||
{
|
||||
BLE_UUID_COPY_INST(event.uuid, p_ans->service.suported_new_alert_cat.uuid);
|
||||
}
|
||||
else if (p_response->handle == p_ans->service.suported_unread_alert_cat.handle_value)
|
||||
{
|
||||
BLE_UUID_COPY_INST(event.uuid, p_ans->service.suported_unread_alert_cat.uuid);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the response is not valid, then ignore.
|
||||
return;
|
||||
}
|
||||
|
||||
event.data.settings = *(ble_ans_alert_settings_t *)(p_response->data);
|
||||
|
||||
if (p_response->len == READ_DATA_LENGTH_MIN)
|
||||
{
|
||||
// These variables must default to 0, if they are not returned by central.
|
||||
event.data.settings.ans_high_prioritized_alert_support = 0;
|
||||
event.data.settings.ans_instant_message_support = 0;
|
||||
}
|
||||
|
||||
p_ans->evt_handler(&event);
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for disconnecting and cleaning the current service.
|
||||
*/
|
||||
static void event_disconnect(ble_ans_c_t * p_ans, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
if (p_ans->conn_handle == p_ble_evt->evt.gap_evt.conn_handle)
|
||||
{
|
||||
p_ans->conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
|
||||
// Clearing all data for the service also sets all handle values to @ref BLE_GATT_HANDLE_INVALID
|
||||
memset(&p_ans->service, 0, sizeof(ble_ans_c_service_t));
|
||||
|
||||
// If there was a valid instance of IAS on the peer, send an event to the
|
||||
// application, so that it can do any cleanup related to this module.
|
||||
ble_ans_c_evt_t evt;
|
||||
|
||||
evt.evt_type = BLE_ANS_C_EVT_DISCONN_COMPLETE;
|
||||
p_ans->evt_handler(&evt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling of BLE stack events. */
|
||||
void ble_ans_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
|
||||
{
|
||||
ble_ans_c_t * p_ans = (ble_ans_c_t *)p_context;
|
||||
|
||||
switch (p_ble_evt->header.evt_id)
|
||||
{
|
||||
case BLE_GATTC_EVT_HVX:
|
||||
event_notify(p_ans, p_ble_evt);
|
||||
break;
|
||||
|
||||
case BLE_GATTC_EVT_READ_RSP:
|
||||
event_read_rsp(p_ans, p_ble_evt);
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVT_DISCONNECTED:
|
||||
event_disconnect(p_ans, p_ble_evt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_ans_c_init(ble_ans_c_t * p_ans, ble_ans_c_init_t const * p_ans_init)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_ans);
|
||||
VERIFY_PARAM_NOT_NULL(p_ans_init);
|
||||
VERIFY_PARAM_NOT_NULL(p_ans_init->evt_handler);
|
||||
VERIFY_PARAM_NOT_NULL(p_ans_init->p_gatt_queue);
|
||||
|
||||
// Clear all handles.
|
||||
memset(p_ans, 0, sizeof(ble_ans_c_t));
|
||||
p_ans->conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
|
||||
p_ans->evt_handler = p_ans_init->evt_handler;
|
||||
p_ans->error_handler = p_ans_init->error_handler;
|
||||
p_ans->message_buffer_size = p_ans_init->message_buffer_size;
|
||||
p_ans->p_message_buffer = p_ans_init->p_message_buffer;
|
||||
p_ans->p_gatt_queue = p_ans_init->p_gatt_queue;
|
||||
|
||||
BLE_UUID_BLE_ASSIGN(p_ans->service.service.uuid, BLE_UUID_ALERT_NOTIFICATION_SERVICE);
|
||||
BLE_UUID_BLE_ASSIGN(p_ans->service.new_alert.uuid, BLE_UUID_NEW_ALERT_CHAR);
|
||||
BLE_UUID_BLE_ASSIGN(p_ans->service.alert_notif_ctrl_point.uuid,
|
||||
BLE_UUID_ALERT_NOTIFICATION_CONTROL_POINT_CHAR);
|
||||
BLE_UUID_BLE_ASSIGN(p_ans->service.unread_alert_status.uuid, BLE_UUID_UNREAD_ALERT_CHAR);
|
||||
BLE_UUID_BLE_ASSIGN(p_ans->service.suported_new_alert_cat.uuid,
|
||||
BLE_UUID_SUPPORTED_NEW_ALERT_CATEGORY_CHAR);
|
||||
BLE_UUID_BLE_ASSIGN(p_ans->service.suported_unread_alert_cat.uuid,
|
||||
BLE_UUID_SUPPORTED_UNREAD_ALERT_CATEGORY_CHAR);
|
||||
|
||||
BLE_UUID_BLE_ASSIGN(p_ans->service.new_alert_cccd.uuid, BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG);
|
||||
BLE_UUID_BLE_ASSIGN(p_ans->service.unread_alert_cccd.uuid,
|
||||
BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG);
|
||||
|
||||
return ble_db_discovery_evt_register(&p_ans->service.service.uuid);
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for creating a tx message for writing a CCCD.
|
||||
*/
|
||||
static uint32_t cccd_configure(ble_ans_c_t const * const p_ans,
|
||||
uint16_t handle_cccd,
|
||||
bool notification_enable)
|
||||
{
|
||||
nrf_ble_gq_req_t cccd_req;
|
||||
uint16_t cccd_val = notification_enable ? BLE_GATT_HVX_NOTIFICATION : 0;
|
||||
uint8_t cccd[WRITE_MESSAGE_LENGTH];
|
||||
|
||||
memset(&cccd_req, 0, sizeof(nrf_ble_gq_req_t));
|
||||
|
||||
cccd[0] = LSB_16(cccd_val);
|
||||
cccd[1] = MSB_16(cccd_val);
|
||||
|
||||
cccd_req.type = NRF_BLE_GQ_REQ_GATTC_WRITE;
|
||||
cccd_req.error_handler.cb = gatt_error_handler;
|
||||
cccd_req.error_handler.p_ctx = (ble_ans_c_t *)p_ans;
|
||||
cccd_req.params.gattc_write.handle = handle_cccd;
|
||||
cccd_req.params.gattc_write.len = WRITE_MESSAGE_LENGTH;
|
||||
cccd_req.params.gattc_write.p_value = cccd;
|
||||
cccd_req.params.gattc_write.offset = 0;
|
||||
cccd_req.params.gattc_write.write_op = BLE_GATT_OP_WRITE_REQ;
|
||||
|
||||
return nrf_ble_gq_item_add(p_ans->p_gatt_queue, &cccd_req, p_ans->conn_handle);
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_ans_c_enable_notif_new_alert(ble_ans_c_t const * p_ans)
|
||||
{
|
||||
if (p_ans->conn_handle == BLE_CONN_HANDLE_INVALID)
|
||||
{
|
||||
return NRF_ERROR_INVALID_STATE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return cccd_configure(p_ans,
|
||||
p_ans->service.new_alert_cccd.handle,
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_ans_c_disable_notif_new_alert(ble_ans_c_t const * p_ans)
|
||||
{
|
||||
return cccd_configure(p_ans,
|
||||
p_ans->service.new_alert_cccd.handle,
|
||||
false);
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_ans_c_enable_notif_unread_alert(ble_ans_c_t const * p_ans)
|
||||
{
|
||||
if ( p_ans->conn_handle == BLE_CONN_HANDLE_INVALID)
|
||||
{
|
||||
return NRF_ERROR_INVALID_STATE;
|
||||
}
|
||||
return cccd_configure(p_ans,
|
||||
p_ans->service.unread_alert_cccd.handle,
|
||||
true);
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_ans_c_disable_notif_unread_alert(ble_ans_c_t const * p_ans)
|
||||
{
|
||||
return cccd_configure(p_ans,
|
||||
p_ans->service.unread_alert_cccd.handle,
|
||||
false);
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_ans_c_control_point_write(ble_ans_c_t const * p_ans,
|
||||
ble_ans_control_point_t const * p_control_point)
|
||||
{
|
||||
nrf_ble_gq_req_t gq_req;
|
||||
uint8_t write_data[WRITE_MESSAGE_LENGTH];
|
||||
|
||||
write_data[0] = p_control_point->command;
|
||||
write_data[1] = p_control_point->category;
|
||||
|
||||
memset(&gq_req, 0, sizeof(nrf_ble_gq_req_t));
|
||||
|
||||
gq_req.type = NRF_BLE_GQ_REQ_GATTC_WRITE;
|
||||
gq_req.error_handler.cb = gatt_error_handler;
|
||||
gq_req.error_handler.p_ctx = (ble_ans_c_t *)p_ans;
|
||||
gq_req.params.gattc_write.handle = p_ans->service.alert_notif_ctrl_point.handle_value;
|
||||
gq_req.params.gattc_write.len = WRITE_MESSAGE_LENGTH;
|
||||
gq_req.params.gattc_write.p_value = write_data;
|
||||
gq_req.params.gattc_write.offset = 0;
|
||||
gq_req.params.gattc_write.write_op = BLE_GATT_OP_WRITE_REQ;
|
||||
|
||||
return nrf_ble_gq_item_add(p_ans->p_gatt_queue, &gq_req, p_ans->conn_handle);
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_ans_c_new_alert_read(ble_ans_c_t const * p_ans)
|
||||
{
|
||||
nrf_ble_gq_req_t gq_req;
|
||||
|
||||
memset(&gq_req, 0, sizeof(nrf_ble_gq_req_t));
|
||||
|
||||
gq_req.type = NRF_BLE_GQ_REQ_GATTC_READ;
|
||||
gq_req.error_handler.cb = gatt_error_handler;
|
||||
gq_req.error_handler.p_ctx = (ble_ans_c_t *)p_ans;
|
||||
gq_req.params.gattc_read.handle = p_ans->service.suported_new_alert_cat.handle_value;
|
||||
gq_req.params.gattc_read.offset = 0;
|
||||
|
||||
return nrf_ble_gq_item_add(p_ans->p_gatt_queue, &gq_req, p_ans->conn_handle);
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_ans_c_unread_alert_read(ble_ans_c_t const * p_ans)
|
||||
{
|
||||
nrf_ble_gq_req_t gq_req;
|
||||
|
||||
memset(&gq_req, 0, sizeof(nrf_ble_gq_req_t));
|
||||
|
||||
gq_req.type = NRF_BLE_GQ_REQ_GATTC_READ;
|
||||
gq_req.error_handler.cb = gatt_error_handler;
|
||||
gq_req.error_handler.p_ctx = (ble_ans_c_t *)p_ans;
|
||||
gq_req.params.gattc_read.handle = p_ans->service.suported_unread_alert_cat.handle_value;
|
||||
gq_req.params.gattc_read.offset = 0;
|
||||
|
||||
return nrf_ble_gq_item_add(p_ans->p_gatt_queue, &gq_req, p_ans->conn_handle);
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_ans_c_new_alert_notify(ble_ans_c_t const * p_ans, ble_ans_category_id_t category_id)
|
||||
{
|
||||
ble_ans_control_point_t control_point;
|
||||
|
||||
control_point.command = ANS_NOTIFY_NEW_INCOMING_ALERT_IMMEDIATELY;
|
||||
control_point.category = category_id;
|
||||
|
||||
return ble_ans_c_control_point_write(p_ans, &control_point);
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_ans_c_unread_alert_notify(ble_ans_c_t const * p_ans, ble_ans_category_id_t category_id)
|
||||
{
|
||||
ble_ans_control_point_t control_point;
|
||||
|
||||
control_point.command = ANS_NOTIFY_UNREAD_CATEGORY_STATUS_IMMEDIATELY;
|
||||
control_point.category = category_id;
|
||||
|
||||
return ble_ans_c_control_point_write(p_ans, &control_point);
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_ans_c_handles_assign(ble_ans_c_t * p_ans,
|
||||
uint16_t conn_handle,
|
||||
ble_ans_c_service_t const * p_peer_handles)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_ans);
|
||||
|
||||
if (!is_valid_ans_srv_discovered(p_peer_handles))
|
||||
{
|
||||
return NRF_ERROR_INVALID_PARAM;
|
||||
}
|
||||
p_ans->conn_handle = conn_handle;
|
||||
|
||||
if (p_peer_handles != NULL)
|
||||
{
|
||||
// Copy the handles from the discovered characteristics to the provided client instance.
|
||||
char_set(&p_ans->service.alert_notif_ctrl_point, &p_peer_handles->alert_notif_ctrl_point);
|
||||
char_set(&p_ans->service.suported_new_alert_cat, &p_peer_handles->suported_new_alert_cat);
|
||||
char_set(&p_ans->service.suported_unread_alert_cat, &p_peer_handles->suported_unread_alert_cat);
|
||||
char_set(&p_ans->service.new_alert, &p_peer_handles->new_alert);
|
||||
char_cccd_set(&p_ans->service.new_alert_cccd, p_peer_handles->new_alert_cccd.handle);
|
||||
char_set(&p_ans->service.unread_alert_status, &p_peer_handles->unread_alert_status);
|
||||
char_cccd_set(&p_ans->service.unread_alert_cccd, p_peer_handles->unread_alert_cccd.handle);
|
||||
}
|
||||
|
||||
return nrf_ble_gq_conn_handle_register(p_ans->p_gatt_queue, conn_handle);
|
||||
}
|
||||
#endif // NRF_MODULE_ENABLED(BLE_ANS_C)
|
||||
418
components/ble/ble_services/ble_ans_c/ble_ans_c.h
Normal file
418
components/ble/ble_services/ble_ans_c/ble_ans_c.h
Normal file
@@ -0,0 +1,418 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 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 ble_ans_c Alert Notification Service Client
|
||||
* @{
|
||||
* @ingroup ble_sdk_srv
|
||||
* @brief Alert Notification module.
|
||||
*
|
||||
* @details This module implements the Alert Notification Client according to the
|
||||
* Alert Notification Profile.
|
||||
*
|
||||
* @note The application must register this module as the BLE event observer by using the
|
||||
* NRF_SDH_BLE_OBSERVER macro. Example:
|
||||
* @code
|
||||
* ble_ans_c_t instance;
|
||||
* NRF_SDH_BLE_OBSERVER(anything, BLE_ANS_C_BLE_OBSERVER_PRIO,
|
||||
* ble_ans_c_on_ble_evt, &instance);
|
||||
* @endcode
|
||||
*
|
||||
* @note Attention!
|
||||
* To maintain compliance with Nordic Semiconductor ASA Bluetooth profile
|
||||
* qualification listings, this section of source code must not be modified.
|
||||
*/
|
||||
#ifndef BLE_ANS_C_H__
|
||||
#define BLE_ANS_C_H__
|
||||
|
||||
#include "ble.h"
|
||||
#include "ble_gatts.h"
|
||||
#include "ble_types.h"
|
||||
#include "sdk_common.h"
|
||||
#include "ble_srv_common.h"
|
||||
#include "ble_db_discovery.h"
|
||||
#include "nrf_ble_gq.h"
|
||||
#include "nrf_sdh_ble.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**@brief Macro for defining a ble_ans_c instance.
|
||||
*
|
||||
* @param _name Name of the instance.
|
||||
* @hideinitializer
|
||||
*/
|
||||
#define BLE_ANS_C_DEF(_name) \
|
||||
static ble_ans_c_t _name; \
|
||||
NRF_SDH_BLE_OBSERVER(_name ## _obs, \
|
||||
BLE_ANS_C_BLE_OBSERVER_PRIO, \
|
||||
ble_ans_c_on_ble_evt, &_name)
|
||||
|
||||
/** @brief Macro for defining multiple ble_ans_c instances.
|
||||
*
|
||||
* @param _name Name of the array of instances.
|
||||
* @param _cnt Number of instances to define.
|
||||
* @hideinitializer
|
||||
*/
|
||||
#define BLE_ANS_C_ARRAY_DEF(_name, _cnt) \
|
||||
static ble_ans_c_t _name[_cnt]; \
|
||||
NRF_SDH_BLE_OBSERVERS(_name ## _obs, \
|
||||
BLE_ANS_C_BLE_OBSERVER_PRIO, \
|
||||
ble_ans_c_on_ble_evt, &_name, _cnt)
|
||||
|
||||
// Forward declaration of the ble_ans_c_t type.
|
||||
typedef struct ble_ans_c_s ble_ans_c_t;
|
||||
|
||||
/** Alert types, as defined in the alert category ID. UUID: 0x2A43. */
|
||||
typedef enum
|
||||
{
|
||||
ANS_TYPE_SIMPLE_ALERT = 0, /**< General text alert or non-text alert.*/
|
||||
ANS_TYPE_EMAIL = 1, /**< Email message arrives.*/
|
||||
ANS_TYPE_NEWS = 2, /**< News feeds such as RSS, Atom.*/
|
||||
ANS_TYPE_NOTIFICATION_CALL = 3, /**< Incoming call.*/
|
||||
ANS_TYPE_MISSED_CALL = 4, /**< Missed call.*/
|
||||
ANS_TYPE_SMS_MMS = 5, /**< SMS or MMS message arrives.*/
|
||||
ANS_TYPE_VOICE_MAIL = 6, /**< Voice mail.*/
|
||||
ANS_TYPE_SCHEDULE = 7, /**< Alert that occurs on calendar, planner.*/
|
||||
ANS_TYPE_HIGH_PRIORITIZED_ALERT = 8, /**< Alert to be handled as high priority.*/
|
||||
ANS_TYPE_INSTANT_MESSAGE = 9, /**< Alert for incoming instant messages.*/
|
||||
ANS_TYPE_ALL_ALERTS = 0xFF /**< Identifies all alerts. */
|
||||
} ble_ans_category_id_t;
|
||||
|
||||
/** Alert notification control point commands, as defined in the Alert Notification Specification.
|
||||
* UUID: 0x2A44.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
ANS_ENABLE_NEW_INCOMING_ALERT_NOTIFICATION = 0, /**< Enable New Incoming Alert Notification.*/
|
||||
ANS_ENABLE_UNREAD_CATEGORY_STATUS_NOTIFICATION = 1, /**< Enable Unread Category Status Notification.*/
|
||||
ANS_DISABLE_NEW_INCOMING_ALERT_NOTIFICATION = 2, /**< Disable New Incoming Alert Notification.*/
|
||||
ANS_DISABLE_UNREAD_CATEGORY_STATUS_NOTIFICATION = 3, /**< Disable Unread Category Status Notification.*/
|
||||
ANS_NOTIFY_NEW_INCOMING_ALERT_IMMEDIATELY = 4, /**< Notify New Incoming Alert immediately.*/
|
||||
ANS_NOTIFY_UNREAD_CATEGORY_STATUS_IMMEDIATELY = 5, /**< Notify Unread Category Status immediately.*/
|
||||
} ble_ans_command_id_t;
|
||||
|
||||
/**@brief Alert Notification Event types that are passed from client to the application on an event. */
|
||||
typedef enum
|
||||
{
|
||||
BLE_ANS_C_EVT_DISCOVERY_COMPLETE, /**< A successful connection is established and the characteristics of the server were fetched. */
|
||||
BLE_ANS_C_EVT_DISCOVERY_FAILED, /**< It was not possible to discover service or characteristics of the connected peer. */
|
||||
BLE_ANS_C_EVT_DISCONN_COMPLETE, /**< The connection is taken down. */
|
||||
BLE_ANS_C_EVT_NOTIFICATION, /**< A valid notification was received from the server.*/
|
||||
BLE_ANS_C_EVT_READ_RESP, /**< A read response was received from the server.*/
|
||||
BLE_ANS_C_EVT_WRITE_RESP /**< A write response was received from the server.*/
|
||||
} ble_ans_c_evt_type_t;
|
||||
|
||||
/**@brief Alert Notification Control Point structure. */
|
||||
typedef struct
|
||||
{
|
||||
ble_ans_command_id_t command; /**< The command to be written to the control point. See @ref ble_ans_command_id_t. */
|
||||
ble_ans_category_id_t category; /**< The category for the control point for which the command applies. See @ref ble_ans_category_id_t. */
|
||||
} ble_ans_control_point_t;
|
||||
|
||||
/**@brief Alert Notification Setting structure containing the supported alerts in the service.
|
||||
*
|
||||
*@details
|
||||
* The structure contains bit fields that describe which alerts are supported:
|
||||
* - 0 = Unsupported
|
||||
* - 1 = Supported
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint8_t ans_simple_alert_support : 1; /**< Support for general text alert or non-text alert.*/
|
||||
uint8_t ans_email_support : 1; /**< Support for alert when an email message arrives.*/
|
||||
uint8_t ans_news_support : 1; /**< Support for news feeds such as RSS, Atom.*/
|
||||
uint8_t ans_notification_call_support : 1; /**< Support for incoming call.*/
|
||||
uint8_t ans_missed_call_support : 1; /**< Support for missed call.*/
|
||||
uint8_t ans_sms_mms_support : 1; /**< Support for SMS or MMS message arrival.*/
|
||||
uint8_t ans_voice_mail_support : 1; /**< Support for voice mail.*/
|
||||
uint8_t ans_schedule_support : 1; /**< Support for alert that occurs on calendar or planner.*/
|
||||
uint8_t ans_high_prioritized_alert_support : 1; /**< Support for alert that should be handled as high priority.*/
|
||||
uint8_t ans_instant_message_support : 1; /**< Support for alert for incoming instant messages.*/
|
||||
uint8_t reserved : 6; /**< Reserved for future use. */
|
||||
} ble_ans_alert_settings_t;
|
||||
|
||||
/**@brief Alert Notification structure
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint8_t alert_category; /**< Alert category to which this alert belongs.*/
|
||||
uint8_t alert_category_count; /**< Number of alerts in the category. */
|
||||
uint32_t alert_msg_length; /**< Length of the optional text message sent by the server. */
|
||||
uint8_t * p_alert_msg_buf; /**< Pointer to the buffer that contains the optional text message. */
|
||||
} ble_ans_alert_notification_t;
|
||||
|
||||
/**@brief Structure for holding information on the Alert Notification Service, if found on the server. */
|
||||
typedef struct
|
||||
{
|
||||
ble_gattc_service_t service; /**< The GATT service that holds the discovered Alert Notification Service. */
|
||||
ble_gattc_char_t alert_notif_ctrl_point; /**< Characteristic for the Alert Notification Control Point. See @ref BLE_UUID_ALERT_NOTIFICATION_CONTROL_POINT_CHAR. */
|
||||
ble_gattc_char_t suported_new_alert_cat; /**< Characteristic for the Supported New Alert category. See @ref BLE_UUID_SUPPORTED_NEW_ALERT_CATEGORY_CHAR. */
|
||||
ble_gattc_char_t suported_unread_alert_cat; /**< Characteristic for the Unread Alert category. See @ref BLE_UUID_SUPPORTED_UNREAD_ALERT_CATEGORY_CHAR. */
|
||||
ble_gattc_char_t new_alert; /**< Characteristic for the New Alert Notification. See @ref BLE_UUID_NEW_ALERT_CHAR. */
|
||||
ble_gattc_desc_t new_alert_cccd; /**< Characteristic Descriptor for the New Alert category. Enables or disables GATT notifications. */
|
||||
ble_gattc_char_t unread_alert_status; /**< Characteristic for the Unread Alert Notification. See @ref BLE_UUID_UNREAD_ALERT_CHAR. */
|
||||
ble_gattc_desc_t unread_alert_cccd; /**< Characteristic Descriptor for the Unread Alert category. Enables or disables GATT notifications */
|
||||
} ble_ans_c_service_t;
|
||||
|
||||
/**@brief Alert Notification Event structure
|
||||
*
|
||||
* @details Structure for holding information about the event that should be handled, as well as
|
||||
* additional information.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
ble_ans_c_evt_type_t evt_type; /**< Type of event. */
|
||||
uint16_t conn_handle; /**< Connection handle on which the ANS service was discovered on the peer device. This is filled if the evt_type is @ref BLE_ANS_C_EVT_DISCOVERY_COMPLETE.*/
|
||||
ble_uuid_t uuid; /**< UUID of the event in case of an alert or notification. */
|
||||
union
|
||||
{
|
||||
ble_ans_alert_settings_t settings; /**< Setting returned from server on read request. */
|
||||
ble_ans_alert_notification_t alert; /**< Alert Notification data sent by the server. */
|
||||
uint32_t error_code; /**< Additional status or error code, if the event is caused by a stack error or GATT status, for example during service discovery. */
|
||||
ble_ans_c_service_t service; /**< Information on the discovered Alert Notification Service. This is filled if the evt_type is @ref BLE_ANS_C_EVT_DISCOVERY_COMPLETE.*/
|
||||
} data;
|
||||
} ble_ans_c_evt_t;
|
||||
|
||||
/**@brief Alert Notification event handler type. */
|
||||
typedef void (*ble_ans_c_evt_handler_t) (ble_ans_c_evt_t * p_evt);
|
||||
|
||||
/**@brief Alert Notification structure. Contains various status information for the client. */
|
||||
struct ble_ans_c_s
|
||||
{
|
||||
ble_ans_c_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Alert Notification Client Application. */
|
||||
ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
|
||||
uint16_t conn_handle; /**< Handle of the current connection (as provided by the BLE stack; if not in a connection, the handle is BLE_CONN_HANDLE_INVALID). */
|
||||
uint8_t central_handle; /**< Handle for the currently connected central, if peer is bonded. */
|
||||
uint8_t service_handle; /**< Handle for the service in the database to be used for this instance. */
|
||||
uint32_t message_buffer_size; /**< Size of the message buffer to hold the additional text messages received on notifications. */
|
||||
uint8_t * p_message_buffer; /**< Pointer to the buffer to be used for additional text message handling. */
|
||||
ble_ans_c_service_t service; /**< Struct to store different handles and UUIDs related to the service. */
|
||||
nrf_ble_gq_t * p_gatt_queue; /**< Pointer to the BLE GATT Queue instance. */
|
||||
};
|
||||
|
||||
/**@brief Alert Notification init structure. Contains all options and data needed for
|
||||
* the initialization of the client.*/
|
||||
typedef struct
|
||||
{
|
||||
ble_ans_c_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Battery Service. */
|
||||
ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
|
||||
uint32_t message_buffer_size; /**< Size of the buffer to handle messages. */
|
||||
uint8_t * p_message_buffer; /**< Pointer to the buffer for passing messages. */
|
||||
nrf_ble_gq_t * p_gatt_queue; /**< Pointer to the BLE GATT Queue instance. */
|
||||
} ble_ans_c_init_t;
|
||||
|
||||
|
||||
/**@brief Function for handling events from the Database Discovery module.
|
||||
*
|
||||
* @details Call this function when you get a callback event from the Database Discovery module.
|
||||
* This function handles an event from the Database Discovery module and determines
|
||||
* whether it relates to the discovery of Heart Rate Service at the peer. If it does, this function
|
||||
* calls the application's event handler to indicate that the Heart Rate Service was
|
||||
* discovered at the peer. The function also populates the event with service-related
|
||||
* information before providing it to the application.
|
||||
*
|
||||
* @param[in] p_ans Pointer to the Alert Notification client structure instance that will handle
|
||||
* the discovery.
|
||||
* @param[in] p_evt Pointer to the event received from the Database Discovery module.
|
||||
*/
|
||||
void ble_ans_c_on_db_disc_evt(ble_ans_c_t * p_ans, ble_db_discovery_evt_t const * p_evt);
|
||||
|
||||
|
||||
/**@brief Function for handling the application's BLE stack events.
|
||||
*
|
||||
* @details Handles all events from the BLE stack of interest to the Alert Notification Client.
|
||||
*
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
* @param[in] p_context Alert Notification Client structure.
|
||||
*/
|
||||
void ble_ans_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
|
||||
|
||||
|
||||
/**@brief Function for initializing the Alert Notification Client.
|
||||
*
|
||||
* @param[out] p_ans Alert Notification Client structure. This structure must be
|
||||
* supplied by the application. It is initialized by this function,
|
||||
* and is later used to identify this particular client instance.
|
||||
* @param[in] p_ans_init Information needed to initialize the client.
|
||||
*
|
||||
* @return NRF_SUCCESS on successful initialization of client. Otherwise, it returns an error code.
|
||||
*/
|
||||
uint32_t ble_ans_c_init(ble_ans_c_t * p_ans, ble_ans_c_init_t const * p_ans_init);
|
||||
|
||||
|
||||
/**@brief Function for writing the to CCCD to enable new alert notifications from the Alert Notification Service.
|
||||
*
|
||||
* @param[in] p_ans Alert Notification structure. This structure must be supplied by
|
||||
* the application. It identifies the particular client instance to use.
|
||||
*
|
||||
* @return NRF_SUCCESS on successful writing of the CCCD. Otherwise, it returns an error code.
|
||||
*/
|
||||
uint32_t ble_ans_c_enable_notif_new_alert(ble_ans_c_t const * p_ans);
|
||||
|
||||
|
||||
/**@brief Function for writing to the CCCD to enable unread alert notifications from the Alert Notification Service.
|
||||
*
|
||||
* @param[in] p_ans Alert Notification structure. This structure must be supplied by
|
||||
* the application. It identifies the particular client instance to use.
|
||||
*
|
||||
* @return NRF_SUCCESS on successful writing of the CCCD. Otherwise, it returns an error code.
|
||||
*/
|
||||
uint32_t ble_ans_c_enable_notif_unread_alert(ble_ans_c_t const * p_ans);
|
||||
|
||||
|
||||
/**@brief Function for writing to the CCCD to disable new alert notifications from the Alert Notification Service.
|
||||
*
|
||||
* @param[in] p_ans Alert Notification structure. This structure must be supplied by
|
||||
* the application. It identifies the particular client instance to use.
|
||||
*
|
||||
* @return NRF_SUCCESS on successful writing of the CCCD. Otherwise, it returns an error code.
|
||||
*/
|
||||
uint32_t ble_ans_c_disable_notif_new_alert(ble_ans_c_t const * p_ans);
|
||||
|
||||
|
||||
/**@brief Function for writing to the CCCD to disable unread alert notifications from the Alert Notification Service.
|
||||
*
|
||||
* @param[in] p_ans Alert Notification structure. This structure must be supplied by
|
||||
* the application. It identifies the particular client instance to use.
|
||||
*
|
||||
* @return NRF_SUCCESS on successful writing of the CCCD, otherwise an error code.
|
||||
*/
|
||||
uint32_t ble_ans_c_disable_notif_unread_alert(ble_ans_c_t const * p_ans);
|
||||
|
||||
|
||||
/**@brief Function for writing to the Alert Notification Control Point to specify alert notification behavior in the
|
||||
* Alert Notification Service on the Central.
|
||||
*
|
||||
* @param[in] p_ans Alert Notification structure. This structure must be
|
||||
* supplied by the application. It identifies the particular client
|
||||
* instance to use.
|
||||
* @param[in] p_control_point Alert Notification Control Point structure. This structure
|
||||
* specifies the values to write to the Alert Notification Control
|
||||
* Point (UUID 0x2A44).
|
||||
*
|
||||
* @return NRF_SUCCESS on successful writing of the Control Point. Otherwise,
|
||||
* this API propagates the error code returned by function
|
||||
* @ref nrf_ble_gq_item_add.
|
||||
*/
|
||||
uint32_t ble_ans_c_control_point_write(ble_ans_c_t const * p_ans,
|
||||
ble_ans_control_point_t const * p_control_point);
|
||||
|
||||
|
||||
/**@brief Function for reading the Supported New Alert characteristic value of the service.
|
||||
* The value describes the alerts supported in the central.
|
||||
*
|
||||
* @param[in] p_ans Alert Notification structure. This structure must be supplied by
|
||||
* the application. It identifies the particular client instance to use.
|
||||
*
|
||||
* @return NRF_SUCCESS on successful transmission of the read request. Otherwise,
|
||||
* this API propagates the error code returned by function
|
||||
* @ref nrf_ble_gq_item_add.
|
||||
*/
|
||||
uint32_t ble_ans_c_new_alert_read(ble_ans_c_t const * p_ans);
|
||||
|
||||
|
||||
/**@brief Function for reading the Supported Unread Alert characteristic value of the service.
|
||||
* The value describes the alerts supported in the central.
|
||||
*
|
||||
* @param[in] p_ans Alert Notification structure. This structure must be supplied by
|
||||
* the application. It identifies the particular client instance to use.
|
||||
*
|
||||
* @return NRF_SUCCESS on successful transmission of the read request. Otherwise,
|
||||
* this API propagates the error code returned by function
|
||||
* @ref nrf_ble_gq_item_add.
|
||||
*/
|
||||
uint32_t ble_ans_c_unread_alert_read(ble_ans_c_t const * p_ans);
|
||||
|
||||
|
||||
/**@brief Function for requesting the peer to notify the New Alert characteristics immediately.
|
||||
*
|
||||
* @param[in] p_ans Alert Notification structure. This structure must be supplied by
|
||||
* the application. It identifies the particular client instance to use.
|
||||
* @param[in] category The category ID for which the peer should notify the client.
|
||||
*
|
||||
* @return NRF_SUCCESS on successful transmission of the read request. Otherwise, it returns an error code.
|
||||
*/
|
||||
uint32_t ble_ans_c_new_alert_notify(ble_ans_c_t const * p_ans, ble_ans_category_id_t category);
|
||||
|
||||
|
||||
/**@brief Function for requesting the peer to notify the Unread Alert characteristics immediately.
|
||||
*
|
||||
* @param[in] p_ans Alert Notification structure. This structure must be supplied by
|
||||
* the application. It identifies the particular client instance to use.
|
||||
* @param[in] category The category ID for which the peer should notify the client.
|
||||
*
|
||||
* @return NRF_SUCCESS on successful transmission of the read request. Otherwise, it returns an error code.
|
||||
*/
|
||||
uint32_t ble_ans_c_unread_alert_notify(ble_ans_c_t const * p_ans, ble_ans_category_id_t category);
|
||||
|
||||
|
||||
/**@brief Function for assigning handles to an instance of ans_c.
|
||||
*
|
||||
* @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 ans_c module. The connection handle and attribute handles
|
||||
* are provided from the discovery event @ref BLE_ANS_C_EVT_DISCOVERY_COMPLETE.
|
||||
*
|
||||
* @param[in] p_ans Pointer to the Alert Notification client structure instance to
|
||||
* associate with the handles.
|
||||
* @param[in] conn_handle Connection handle to associated with the given Alert Notification Client
|
||||
* Instance.
|
||||
* @param[in] p_peer_handles Attribute handles on the ANS server that you want this ANS client to
|
||||
* interact with.
|
||||
*
|
||||
*/
|
||||
uint32_t ble_ans_c_handles_assign(ble_ans_c_t * p_ans,
|
||||
uint16_t const conn_handle,
|
||||
ble_ans_c_service_t const * p_peer_handles);
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // BLE_ANS_C_H__
|
||||
|
||||
/** @} */
|
||||
|
||||
365
components/ble/ble_services/ble_bas/ble_bas.c
Normal file
365
components/ble/ble_services/ble_bas/ble_bas.c
Normal file
@@ -0,0 +1,365 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 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.
|
||||
*
|
||||
*/
|
||||
/* Attention!
|
||||
* To maintain compliance with Nordic Semiconductor ASA's Bluetooth profile
|
||||
* qualification listings, this section of source code must not be modified.
|
||||
*/
|
||||
#include "sdk_common.h"
|
||||
#if NRF_MODULE_ENABLED(BLE_BAS)
|
||||
#include "ble_bas.h"
|
||||
#include <string.h>
|
||||
#include "ble_srv_common.h"
|
||||
#include "ble_conn_state.h"
|
||||
|
||||
#define NRF_LOG_MODULE_NAME ble_bas
|
||||
#if BLE_BAS_CONFIG_LOG_ENABLED
|
||||
#define NRF_LOG_LEVEL BLE_BAS_CONFIG_LOG_LEVEL
|
||||
#define NRF_LOG_INFO_COLOR BLE_BAS_CONFIG_INFO_COLOR
|
||||
#define NRF_LOG_DEBUG_COLOR BLE_BAS_CONFIG_DEBUG_COLOR
|
||||
#else // BLE_BAS_CONFIG_LOG_ENABLED
|
||||
#define NRF_LOG_LEVEL 0
|
||||
#endif // BLE_BAS_CONFIG_LOG_ENABLED
|
||||
#include "nrf_log.h"
|
||||
NRF_LOG_MODULE_REGISTER();
|
||||
|
||||
|
||||
#define INVALID_BATTERY_LEVEL 255
|
||||
|
||||
|
||||
/**@brief Function for handling the Write event.
|
||||
*
|
||||
* @param[in] p_bas Battery Service structure.
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
*/
|
||||
static void on_write(ble_bas_t * p_bas, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
if (!p_bas->is_notification_supported)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ble_gatts_evt_write_t const * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
|
||||
|
||||
if ( (p_evt_write->handle == p_bas->battery_level_handles.cccd_handle)
|
||||
&& (p_evt_write->len == 2))
|
||||
{
|
||||
if (p_bas->evt_handler == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ble_bas_evt_t evt;
|
||||
|
||||
if (ble_srv_is_notification_enabled(p_evt_write->data))
|
||||
{
|
||||
evt.evt_type = BLE_BAS_EVT_NOTIFICATION_ENABLED;
|
||||
}
|
||||
else
|
||||
{
|
||||
evt.evt_type = BLE_BAS_EVT_NOTIFICATION_DISABLED;
|
||||
}
|
||||
evt.conn_handle = p_ble_evt->evt.gatts_evt.conn_handle;
|
||||
|
||||
// CCCD written, call application event handler.
|
||||
p_bas->evt_handler(p_bas, &evt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ble_bas_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
|
||||
{
|
||||
if ((p_context == NULL) || (p_ble_evt == NULL))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ble_bas_t * p_bas = (ble_bas_t *)p_context;
|
||||
|
||||
switch (p_ble_evt->header.evt_id)
|
||||
{
|
||||
case BLE_GATTS_EVT_WRITE:
|
||||
on_write(p_bas, p_ble_evt);
|
||||
break;
|
||||
|
||||
default:
|
||||
// No implementation needed.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for adding the Battery Level characteristic.
|
||||
*
|
||||
* @param[in] p_bas Battery Service structure.
|
||||
* @param[in] p_bas_init Information needed to initialize the service.
|
||||
*
|
||||
* @return NRF_SUCCESS on success, otherwise an error code.
|
||||
*/
|
||||
static ret_code_t battery_level_char_add(ble_bas_t * p_bas, const ble_bas_init_t * p_bas_init)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
ble_add_char_params_t add_char_params;
|
||||
ble_add_descr_params_t add_descr_params;
|
||||
uint8_t initial_battery_level;
|
||||
uint8_t init_len;
|
||||
uint8_t encoded_report_ref[BLE_SRV_ENCODED_REPORT_REF_LEN];
|
||||
|
||||
// Add battery level characteristic
|
||||
initial_battery_level = p_bas_init->initial_batt_level;
|
||||
|
||||
memset(&add_char_params, 0, sizeof(add_char_params));
|
||||
add_char_params.uuid = BLE_UUID_BATTERY_LEVEL_CHAR;
|
||||
add_char_params.max_len = sizeof(uint8_t);
|
||||
add_char_params.init_len = sizeof(uint8_t);
|
||||
add_char_params.p_init_value = &initial_battery_level;
|
||||
add_char_params.char_props.notify = p_bas->is_notification_supported;
|
||||
add_char_params.char_props.read = 1;
|
||||
add_char_params.cccd_write_access = p_bas_init->bl_cccd_wr_sec;
|
||||
add_char_params.read_access = p_bas_init->bl_rd_sec;
|
||||
|
||||
err_code = characteristic_add(p_bas->service_handle,
|
||||
&add_char_params,
|
||||
&(p_bas->battery_level_handles));
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
|
||||
if (p_bas_init->p_report_ref != NULL)
|
||||
{
|
||||
// Add Report Reference descriptor
|
||||
init_len = ble_srv_report_ref_encode(encoded_report_ref, p_bas_init->p_report_ref);
|
||||
|
||||
memset(&add_descr_params, 0, sizeof(add_descr_params));
|
||||
add_descr_params.uuid = BLE_UUID_REPORT_REF_DESCR;
|
||||
add_descr_params.read_access = p_bas_init->bl_report_rd_sec;
|
||||
add_descr_params.init_len = init_len;
|
||||
add_descr_params.max_len = add_descr_params.init_len;
|
||||
add_descr_params.p_value = encoded_report_ref;
|
||||
|
||||
err_code = descriptor_add(p_bas->battery_level_handles.value_handle,
|
||||
&add_descr_params,
|
||||
&p_bas->report_ref_handle);
|
||||
return err_code;
|
||||
}
|
||||
else
|
||||
{
|
||||
p_bas->report_ref_handle = BLE_GATT_HANDLE_INVALID;
|
||||
}
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
ret_code_t ble_bas_init(ble_bas_t * p_bas, const ble_bas_init_t * p_bas_init)
|
||||
{
|
||||
if (p_bas == NULL || p_bas_init == NULL)
|
||||
{
|
||||
return NRF_ERROR_NULL;
|
||||
}
|
||||
|
||||
ret_code_t err_code;
|
||||
ble_uuid_t ble_uuid;
|
||||
|
||||
// Initialize service structure
|
||||
p_bas->evt_handler = p_bas_init->evt_handler;
|
||||
p_bas->is_notification_supported = p_bas_init->support_notification;
|
||||
p_bas->battery_level_last = INVALID_BATTERY_LEVEL;
|
||||
|
||||
// Add service
|
||||
BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_BATTERY_SERVICE);
|
||||
|
||||
err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &ble_uuid, &p_bas->service_handle);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
// Add battery level characteristic
|
||||
err_code = battery_level_char_add(p_bas, p_bas_init);
|
||||
return err_code;
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for sending notifications with the Battery Level characteristic.
|
||||
*
|
||||
* @param[in] p_hvx_params Pointer to structure with notification data.
|
||||
* @param[in] conn_handle Connection handle.
|
||||
*
|
||||
* @return NRF_SUCCESS on success, otherwise an error code.
|
||||
*/
|
||||
static ret_code_t battery_notification_send(ble_gatts_hvx_params_t * const p_hvx_params,
|
||||
uint16_t conn_handle)
|
||||
{
|
||||
ret_code_t err_code = sd_ble_gatts_hvx(conn_handle, p_hvx_params);
|
||||
if (err_code == NRF_SUCCESS)
|
||||
{
|
||||
NRF_LOG_INFO("Battery notification has been sent using conn_handle: 0x%04X", conn_handle);
|
||||
}
|
||||
else
|
||||
{
|
||||
NRF_LOG_DEBUG("Error: 0x%08X while sending notification with conn_handle: 0x%04X",
|
||||
err_code,
|
||||
conn_handle);
|
||||
}
|
||||
return err_code;
|
||||
}
|
||||
|
||||
|
||||
ret_code_t ble_bas_battery_level_update(ble_bas_t * p_bas,
|
||||
uint8_t battery_level,
|
||||
uint16_t conn_handle)
|
||||
{
|
||||
if (p_bas == NULL)
|
||||
{
|
||||
return NRF_ERROR_NULL;
|
||||
}
|
||||
|
||||
ret_code_t err_code = NRF_SUCCESS;
|
||||
ble_gatts_value_t gatts_value;
|
||||
|
||||
if (battery_level != p_bas->battery_level_last)
|
||||
{
|
||||
// Initialize value struct.
|
||||
memset(&gatts_value, 0, sizeof(gatts_value));
|
||||
|
||||
gatts_value.len = sizeof(uint8_t);
|
||||
gatts_value.offset = 0;
|
||||
gatts_value.p_value = &battery_level;
|
||||
|
||||
// Update database.
|
||||
err_code = sd_ble_gatts_value_set(BLE_CONN_HANDLE_INVALID,
|
||||
p_bas->battery_level_handles.value_handle,
|
||||
&gatts_value);
|
||||
if (err_code == NRF_SUCCESS)
|
||||
{
|
||||
NRF_LOG_INFO("Battery level has been updated: %d%%", battery_level)
|
||||
|
||||
// Save new battery value.
|
||||
p_bas->battery_level_last = battery_level;
|
||||
}
|
||||
else
|
||||
{
|
||||
NRF_LOG_DEBUG("Error during battery level update: 0x%08X", err_code)
|
||||
|
||||
return err_code;
|
||||
}
|
||||
|
||||
// Send value if connected and notifying.
|
||||
if (p_bas->is_notification_supported)
|
||||
{
|
||||
ble_gatts_hvx_params_t hvx_params;
|
||||
|
||||
memset(&hvx_params, 0, sizeof(hvx_params));
|
||||
|
||||
hvx_params.handle = p_bas->battery_level_handles.value_handle;
|
||||
hvx_params.type = BLE_GATT_HVX_NOTIFICATION;
|
||||
hvx_params.offset = gatts_value.offset;
|
||||
hvx_params.p_len = &gatts_value.len;
|
||||
hvx_params.p_data = gatts_value.p_value;
|
||||
|
||||
if (conn_handle == BLE_CONN_HANDLE_ALL)
|
||||
{
|
||||
ble_conn_state_conn_handle_list_t conn_handles = ble_conn_state_conn_handles();
|
||||
|
||||
// Try sending notifications to all valid connection handles.
|
||||
for (uint32_t i = 0; i < conn_handles.len; i++)
|
||||
{
|
||||
if (ble_conn_state_status(conn_handles.conn_handles[i]) == BLE_CONN_STATUS_CONNECTED)
|
||||
{
|
||||
if (err_code == NRF_SUCCESS)
|
||||
{
|
||||
err_code = battery_notification_send(&hvx_params,
|
||||
conn_handles.conn_handles[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Preserve the first non-zero error code
|
||||
UNUSED_RETURN_VALUE(battery_notification_send(&hvx_params,
|
||||
conn_handles.conn_handles[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
err_code = battery_notification_send(&hvx_params, conn_handle);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
err_code = NRF_ERROR_INVALID_STATE;
|
||||
}
|
||||
}
|
||||
|
||||
return err_code;
|
||||
}
|
||||
|
||||
|
||||
ret_code_t ble_bas_battery_lvl_on_reconnection_update(ble_bas_t * p_bas,
|
||||
uint16_t conn_handle)
|
||||
{
|
||||
if (p_bas == NULL)
|
||||
{
|
||||
return NRF_ERROR_NULL;
|
||||
}
|
||||
|
||||
ret_code_t err_code;
|
||||
|
||||
if (p_bas->is_notification_supported)
|
||||
{
|
||||
ble_gatts_hvx_params_t hvx_params;
|
||||
uint16_t len = sizeof(uint8_t);
|
||||
|
||||
memset(&hvx_params, 0, sizeof(hvx_params));
|
||||
|
||||
hvx_params.handle = p_bas->battery_level_handles.value_handle;
|
||||
hvx_params.type = BLE_GATT_HVX_NOTIFICATION;
|
||||
hvx_params.offset = 0;
|
||||
hvx_params.p_len = &len;
|
||||
hvx_params.p_data = &p_bas->battery_level_last;
|
||||
|
||||
err_code = battery_notification_send(&hvx_params, conn_handle);
|
||||
|
||||
return err_code;
|
||||
}
|
||||
|
||||
return NRF_ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
|
||||
#endif // NRF_MODULE_ENABLED(BLE_BAS)
|
||||
212
components/ble/ble_services/ble_bas/ble_bas.h
Normal file
212
components/ble/ble_services/ble_bas/ble_bas.h
Normal file
@@ -0,0 +1,212 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 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 ble_bas Battery Service
|
||||
* @{
|
||||
* @ingroup ble_sdk_srv
|
||||
* @brief Battery Service module.
|
||||
*
|
||||
* @details This module implements the Battery Service with the Battery Level characteristic.
|
||||
* During initialization it adds the Battery Service and Battery Level characteristic
|
||||
* to the BLE stack database. Optionally it can also add a Report Reference descriptor
|
||||
* to the Battery Level characteristic (used when including the Battery Service in
|
||||
* the HID service).
|
||||
*
|
||||
* If specified, the module will support notification of the Battery Level characteristic
|
||||
* through the ble_bas_battery_level_update() function.
|
||||
* If an event handler is supplied by the application, the Battery Service will
|
||||
* generate Battery 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_bas_t instance;
|
||||
* NRF_SDH_BLE_OBSERVER(anything, BLE_BAS_BLE_OBSERVER_PRIO,
|
||||
* ble_bas_on_ble_evt, &instance);
|
||||
* @endcode
|
||||
*
|
||||
* @note Attention!
|
||||
* To maintain compliance with Nordic Semiconductor ASA Bluetooth profile
|
||||
* qualification listings, this section of source code must not be modified.
|
||||
*/
|
||||
#ifndef BLE_BAS_H__
|
||||
#define BLE_BAS_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "ble.h"
|
||||
#include "ble_srv_common.h"
|
||||
#include "nrf_sdh_ble.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**@brief Macro for defining a ble_bas instance.
|
||||
*
|
||||
* @param _name Name of the instance.
|
||||
* @hideinitializer
|
||||
*/
|
||||
#define BLE_BAS_DEF(_name) \
|
||||
static ble_bas_t _name; \
|
||||
NRF_SDH_BLE_OBSERVER(_name ## _obs, \
|
||||
BLE_BAS_BLE_OBSERVER_PRIO, \
|
||||
ble_bas_on_ble_evt, \
|
||||
&_name)
|
||||
|
||||
/**@brief Battery Service event type. */
|
||||
typedef enum
|
||||
{
|
||||
BLE_BAS_EVT_NOTIFICATION_ENABLED, /**< Battery value notification enabled event. */
|
||||
BLE_BAS_EVT_NOTIFICATION_DISABLED /**< Battery value notification disabled event. */
|
||||
} ble_bas_evt_type_t;
|
||||
|
||||
/**@brief Battery Service event. */
|
||||
typedef struct
|
||||
{
|
||||
ble_bas_evt_type_t evt_type; /**< Type of event. */
|
||||
uint16_t conn_handle; /**< Connection handle. */
|
||||
} ble_bas_evt_t;
|
||||
|
||||
// Forward declaration of the ble_bas_t type.
|
||||
typedef struct ble_bas_s ble_bas_t;
|
||||
|
||||
/**@brief Battery Service event handler type. */
|
||||
typedef void (* ble_bas_evt_handler_t) (ble_bas_t * p_bas, ble_bas_evt_t * p_evt);
|
||||
|
||||
/**@brief Battery Service init structure. This contains all options and data needed for
|
||||
* initialization of the service.*/
|
||||
typedef struct
|
||||
{
|
||||
ble_bas_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Battery Service. */
|
||||
bool support_notification; /**< TRUE if notification of Battery Level measurement is supported. */
|
||||
ble_srv_report_ref_t * p_report_ref; /**< If not NULL, a Report Reference descriptor with the specified value will be added to the Battery Level characteristic */
|
||||
uint8_t initial_batt_level; /**< Initial battery level */
|
||||
security_req_t bl_rd_sec; /**< Security requirement for reading the BL characteristic value. */
|
||||
security_req_t bl_cccd_wr_sec; /**< Security requirement for writing the BL characteristic CCCD. */
|
||||
security_req_t bl_report_rd_sec; /**< Security requirement for reading the BL characteristic descriptor. */
|
||||
} ble_bas_init_t;
|
||||
|
||||
/**@brief Battery Service structure. This contains various status information for the service. */
|
||||
struct ble_bas_s
|
||||
{
|
||||
ble_bas_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Battery Service. */
|
||||
uint16_t service_handle; /**< Handle of Battery Service (as provided by the BLE stack). */
|
||||
ble_gatts_char_handles_t battery_level_handles; /**< Handles related to the Battery Level characteristic. */
|
||||
uint16_t report_ref_handle; /**< Handle of the Report Reference descriptor. */
|
||||
uint8_t battery_level_last; /**< Last Battery Level measurement passed to the Battery Service. */
|
||||
bool is_notification_supported; /**< TRUE if notification of Battery Level is supported. */
|
||||
};
|
||||
|
||||
|
||||
/**@brief Function for initializing the Battery Service.
|
||||
*
|
||||
* @param[out] p_bas Battery Service structure. This structure will have to be supplied by
|
||||
* the application. It will be initialized by this function, and will later
|
||||
* be used to identify this particular service instance.
|
||||
* @param[in] p_bas_init Information needed to initialize the service.
|
||||
*
|
||||
* @return NRF_SUCCESS on successful initialization of service, otherwise an error code.
|
||||
*/
|
||||
ret_code_t ble_bas_init(ble_bas_t * p_bas, const ble_bas_init_t * p_bas_init);
|
||||
|
||||
|
||||
/**@brief Function for handling the Application's BLE Stack events.
|
||||
*
|
||||
* @details Handles all events from the BLE stack of interest to the Battery Service.
|
||||
*
|
||||
* @note For the requirements in the BAS specification to be fulfilled,
|
||||
* ble_bas_battery_level_update() must be called upon reconnection if the
|
||||
* battery level has changed while the service has been disconnected from a bonded
|
||||
* client.
|
||||
*
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
* @param[in] p_context Battery Service structure.
|
||||
*/
|
||||
void ble_bas_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
|
||||
|
||||
|
||||
/**@brief Function for updating the battery level.
|
||||
*
|
||||
* @details The application calls this function after having performed a battery measurement.
|
||||
* The battery level characteristic will only be sent to the clients which have
|
||||
* enabled notifications. \ref BLE_CONN_HANDLE_ALL can be used as a connection handle
|
||||
* to send notifications to all connected devices.
|
||||
*
|
||||
* @param[in] p_bas Battery Service structure.
|
||||
* @param[in] battery_level New battery measurement value (in percent of full capacity).
|
||||
* @param[in] conn_handle Connection handle.
|
||||
*
|
||||
* @return NRF_SUCCESS on success, otherwise an error code.
|
||||
*/
|
||||
ret_code_t ble_bas_battery_level_update(ble_bas_t * p_bas,
|
||||
uint8_t battery_level,
|
||||
uint16_t conn_handle);
|
||||
|
||||
|
||||
/**@brief Function for sending the last battery level when bonded client reconnects.
|
||||
*
|
||||
* @details The application calls this function, in the case of a reconnection of
|
||||
* a bonded client if the value of the battery has changed since
|
||||
* its disconnection.
|
||||
*
|
||||
* @note For the requirements in the BAS specification to be fulfilled,
|
||||
* this function must be called upon reconnection if the battery level has changed
|
||||
* while the service has been disconnected from a bonded client.
|
||||
*
|
||||
* @param[in] p_bas Battery Service structure.
|
||||
* @param[in] conn_handle Connection handle.
|
||||
*
|
||||
* @return NRF_SUCCESS on success,
|
||||
* NRF_ERROR_INVALID_STATE when notification is not supported,
|
||||
* otherwise an error code returned by @ref sd_ble_gatts_hvx.
|
||||
*/
|
||||
ret_code_t ble_bas_battery_lvl_on_reconnection_update(ble_bas_t * p_bas,
|
||||
uint16_t conn_handle);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // BLE_BAS_H__
|
||||
|
||||
/** @} */
|
||||
341
components/ble/ble_services/ble_bas_c/ble_bas_c.c
Normal file
341
components/ble/ble_services/ble_bas_c/ble_bas_c.c
Normal file
@@ -0,0 +1,341 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 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_BAS_C)
|
||||
#include "ble_bas_c.h"
|
||||
#include "ble_types.h"
|
||||
#include "ble_db_discovery.h"
|
||||
#include "ble_gattc.h"
|
||||
#define NRF_LOG_MODULE_NAME ble_bas_c
|
||||
#include "nrf_log.h"
|
||||
NRF_LOG_MODULE_REGISTER();
|
||||
|
||||
|
||||
/**@brief Function for intercepting errors of GATTC and 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)
|
||||
{
|
||||
ble_bas_c_t * p_bas_c = (ble_bas_c_t *)p_ctx;
|
||||
|
||||
NRF_LOG_DEBUG("A GATT Client error has occurred on conn_handle: 0X%X", conn_handle);
|
||||
|
||||
if (p_bas_c->error_handler != NULL)
|
||||
{
|
||||
p_bas_c->error_handler(nrf_error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling read response events.
|
||||
*
|
||||
* @details This function validates the read response and raises the appropriate
|
||||
* event to the application.
|
||||
*
|
||||
* @param[in] p_bas_c Pointer to the Battery Service Client Structure.
|
||||
* @param[in] p_ble_evt Pointer to the SoftDevice event.
|
||||
*/
|
||||
static void on_read_rsp(ble_bas_c_t * p_bas_c, ble_evt_t const * 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_bas_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_bas_c->peer_bas_db.bl_handle)
|
||||
{
|
||||
ble_bas_c_evt_t evt;
|
||||
|
||||
evt.conn_handle = p_ble_evt->evt.gattc_evt.conn_handle;
|
||||
evt.evt_type = BLE_BAS_C_EVT_BATT_READ_RESP;
|
||||
|
||||
evt.params.battery_level = p_response->data[0];
|
||||
|
||||
p_bas_c->evt_handler(p_bas_c, &evt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling Handle Value Notification received from the SoftDevice.
|
||||
*
|
||||
* @details This function handles the Handle Value Notification received from the SoftDevice
|
||||
* and checks whether it is a notification of the Battery Level measurement from the peer. If
|
||||
* it is, this function decodes the battery level measurement and sends it to the
|
||||
* application.
|
||||
*
|
||||
* @param[in] p_ble_bas_c Pointer to the Battery Service Client structure.
|
||||
* @param[in] p_ble_evt Pointer to the BLE event received.
|
||||
*/
|
||||
static void on_hvx(ble_bas_c_t * p_ble_bas_c, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
// Check if the event is on the link for this instance.
|
||||
if (p_ble_bas_c->conn_handle != p_ble_evt->evt.gattc_evt.conn_handle)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Check if this notification is a battery level notification.
|
||||
if (p_ble_evt->evt.gattc_evt.params.hvx.handle == p_ble_bas_c->peer_bas_db.bl_handle)
|
||||
{
|
||||
if (p_ble_evt->evt.gattc_evt.params.hvx.len == 1)
|
||||
{
|
||||
ble_bas_c_evt_t ble_bas_c_evt;
|
||||
ble_bas_c_evt.conn_handle = p_ble_evt->evt.gattc_evt.conn_handle;
|
||||
ble_bas_c_evt.evt_type = BLE_BAS_C_EVT_BATT_NOTIFICATION;
|
||||
|
||||
ble_bas_c_evt.params.battery_level = p_ble_evt->evt.gattc_evt.params.hvx.data[0];
|
||||
|
||||
p_ble_bas_c->evt_handler(p_ble_bas_c, &ble_bas_c_evt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ble_bas_on_db_disc_evt(ble_bas_c_t * p_ble_bas_c, const ble_db_discovery_evt_t * p_evt)
|
||||
{
|
||||
// Check if the Battery Service was discovered.
|
||||
if (p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE
|
||||
&&
|
||||
p_evt->params.discovered_db.srv_uuid.uuid == BLE_UUID_BATTERY_SERVICE
|
||||
&&
|
||||
p_evt->params.discovered_db.srv_uuid.type == BLE_UUID_TYPE_BLE)
|
||||
{
|
||||
// Find the CCCD Handle of the Battery Level characteristic.
|
||||
uint8_t i;
|
||||
|
||||
ble_bas_c_evt_t evt;
|
||||
evt.evt_type = BLE_BAS_C_EVT_DISCOVERY_COMPLETE;
|
||||
evt.conn_handle = p_evt->conn_handle;
|
||||
for (i = 0; i < p_evt->params.discovered_db.char_count; i++)
|
||||
{
|
||||
if (p_evt->params.discovered_db.charateristics[i].characteristic.uuid.uuid ==
|
||||
BLE_UUID_BATTERY_LEVEL_CHAR)
|
||||
{
|
||||
// Found Battery Level characteristic. Store CCCD handle and break.
|
||||
evt.params.bas_db.bl_cccd_handle =
|
||||
p_evt->params.discovered_db.charateristics[i].cccd_handle;
|
||||
evt.params.bas_db.bl_handle =
|
||||
p_evt->params.discovered_db.charateristics[i].characteristic.handle_value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
NRF_LOG_DEBUG("Battery Service discovered at peer.");
|
||||
|
||||
//If the instance has been assigned prior to db_discovery, assign the db_handles.
|
||||
if (p_ble_bas_c->conn_handle != BLE_CONN_HANDLE_INVALID)
|
||||
{
|
||||
if ((p_ble_bas_c->peer_bas_db.bl_cccd_handle == BLE_GATT_HANDLE_INVALID)&&
|
||||
(p_ble_bas_c->peer_bas_db.bl_handle == BLE_GATT_HANDLE_INVALID))
|
||||
{
|
||||
p_ble_bas_c->peer_bas_db = evt.params.bas_db;
|
||||
}
|
||||
}
|
||||
p_ble_bas_c->evt_handler(p_ble_bas_c, &evt);
|
||||
}
|
||||
else if ((p_evt->evt_type == BLE_DB_DISCOVERY_SRV_NOT_FOUND) ||
|
||||
(p_evt->evt_type == BLE_DB_DISCOVERY_ERROR))
|
||||
{
|
||||
NRF_LOG_DEBUG("Battery Service discovery failure at peer. ");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Do nothing.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for creating a message for writing to the CCCD.
|
||||
*/
|
||||
static uint32_t cccd_configure(ble_bas_c_t * p_ble_bas_c, bool notification_enable)
|
||||
{
|
||||
NRF_LOG_DEBUG("Configuring CCCD. CCCD Handle = %d, Connection Handle = %d",
|
||||
p_ble_bas_c->peer_bas_db.bl_cccd_handle,
|
||||
p_ble_bas_c->conn_handle);
|
||||
|
||||
nrf_ble_gq_req_t bas_c_req;
|
||||
uint8_t cccd[BLE_CCCD_VALUE_LEN];
|
||||
uint16_t cccd_val = notification_enable ? BLE_GATT_HVX_NOTIFICATION : 0;
|
||||
|
||||
cccd[0] = LSB_16(cccd_val);
|
||||
cccd[1] = MSB_16(cccd_val);
|
||||
|
||||
memset(&bas_c_req, 0, sizeof(bas_c_req));
|
||||
|
||||
bas_c_req.type = NRF_BLE_GQ_REQ_GATTC_WRITE;
|
||||
bas_c_req.error_handler.cb = gatt_error_handler;
|
||||
bas_c_req.error_handler.p_ctx = p_ble_bas_c;
|
||||
bas_c_req.params.gattc_write.handle = p_ble_bas_c->peer_bas_db.bl_cccd_handle;
|
||||
bas_c_req.params.gattc_write.len = BLE_CCCD_VALUE_LEN;
|
||||
bas_c_req.params.gattc_write.p_value = cccd;
|
||||
bas_c_req.params.gattc_write.offset = 0;
|
||||
bas_c_req.params.gattc_write.write_op = BLE_GATT_OP_WRITE_REQ;
|
||||
|
||||
return nrf_ble_gq_item_add(p_ble_bas_c->p_gatt_queue, &bas_c_req, p_ble_bas_c->conn_handle);
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_bas_c_init(ble_bas_c_t * p_ble_bas_c, ble_bas_c_init_t * p_ble_bas_c_init)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_ble_bas_c);
|
||||
VERIFY_PARAM_NOT_NULL(p_ble_bas_c_init);
|
||||
|
||||
ble_uuid_t bas_uuid;
|
||||
|
||||
bas_uuid.type = BLE_UUID_TYPE_BLE;
|
||||
bas_uuid.uuid = BLE_UUID_BATTERY_SERVICE;
|
||||
|
||||
p_ble_bas_c->conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
p_ble_bas_c->peer_bas_db.bl_cccd_handle = BLE_GATT_HANDLE_INVALID;
|
||||
p_ble_bas_c->peer_bas_db.bl_handle = BLE_GATT_HANDLE_INVALID;
|
||||
p_ble_bas_c->evt_handler = p_ble_bas_c_init->evt_handler;
|
||||
p_ble_bas_c->error_handler = p_ble_bas_c_init->error_handler;
|
||||
p_ble_bas_c->p_gatt_queue = p_ble_bas_c_init->p_gatt_queue;
|
||||
|
||||
return ble_db_discovery_evt_register(&bas_uuid);
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling the Disconnected event received from the SoftDevice.
|
||||
*
|
||||
* @details This function checks whether the disconnect event is happening on the link
|
||||
* associated with the current instance of the module. If the event is happening,
|
||||
* the function sets the instance's conn_handle to invalid.
|
||||
*
|
||||
* @param[in] p_ble_bas_c Pointer to the Battery Service Client structure.
|
||||
* @param[in] p_ble_evt Pointer to the BLE event received.
|
||||
*/
|
||||
static void on_disconnected(ble_bas_c_t * p_ble_bas_c, const ble_evt_t * p_ble_evt)
|
||||
{
|
||||
if (p_ble_bas_c->conn_handle == p_ble_evt->evt.gap_evt.conn_handle)
|
||||
{
|
||||
p_ble_bas_c->conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
p_ble_bas_c->peer_bas_db.bl_cccd_handle = BLE_GATT_HANDLE_INVALID;
|
||||
p_ble_bas_c->peer_bas_db.bl_handle = BLE_GATT_HANDLE_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ble_bas_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
|
||||
{
|
||||
if ((p_ble_evt == NULL) || (p_context == NULL))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ble_bas_c_t * p_ble_bas_c = (ble_bas_c_t *)p_context;
|
||||
|
||||
switch (p_ble_evt->header.evt_id)
|
||||
{
|
||||
case BLE_GATTC_EVT_HVX:
|
||||
on_hvx(p_ble_bas_c, p_ble_evt);
|
||||
break;
|
||||
|
||||
case BLE_GATTC_EVT_READ_RSP:
|
||||
on_read_rsp(p_ble_bas_c, p_ble_evt);
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVT_DISCONNECTED:
|
||||
on_disconnected(p_ble_bas_c, p_ble_evt);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_bas_c_bl_notif_enable(ble_bas_c_t * p_ble_bas_c)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_ble_bas_c);
|
||||
|
||||
if (p_ble_bas_c->conn_handle == BLE_CONN_HANDLE_INVALID)
|
||||
{
|
||||
return NRF_ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
return cccd_configure(p_ble_bas_c, true);
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_bas_c_bl_read(ble_bas_c_t * p_ble_bas_c)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_ble_bas_c);
|
||||
if (p_ble_bas_c->conn_handle == BLE_CONN_HANDLE_INVALID)
|
||||
{
|
||||
return NRF_ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
nrf_ble_gq_req_t bas_c_req;
|
||||
|
||||
memset(&bas_c_req, 0, sizeof(bas_c_req));
|
||||
bas_c_req.type = NRF_BLE_GQ_REQ_GATTC_READ;
|
||||
bas_c_req.error_handler.cb = gatt_error_handler;
|
||||
bas_c_req.error_handler.p_ctx = p_ble_bas_c;
|
||||
bas_c_req.params.gattc_read.handle = p_ble_bas_c->peer_bas_db.bl_handle;
|
||||
|
||||
return nrf_ble_gq_item_add(p_ble_bas_c->p_gatt_queue, &bas_c_req, p_ble_bas_c->conn_handle);
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_bas_c_handles_assign(ble_bas_c_t * p_ble_bas_c,
|
||||
uint16_t conn_handle,
|
||||
ble_bas_c_db_t * p_peer_handles)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_ble_bas_c);
|
||||
|
||||
p_ble_bas_c->conn_handle = conn_handle;
|
||||
if (p_peer_handles != NULL)
|
||||
{
|
||||
p_ble_bas_c->peer_bas_db = *p_peer_handles;
|
||||
}
|
||||
|
||||
return nrf_ble_gq_conn_handle_register(p_ble_bas_c->p_gatt_queue, conn_handle);
|
||||
}
|
||||
#endif // NRF_MODULE_ENABLED(BLE_BAS_C)
|
||||
280
components/ble/ble_services/ble_bas_c/ble_bas_c.h
Normal file
280
components/ble/ble_services/ble_bas_c/ble_bas_c.h
Normal file
@@ -0,0 +1,280 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 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 ble_bas_c Battery Service Client
|
||||
* @{
|
||||
* @ingroup ble_sdk_srv
|
||||
* @brief Battery Service Client module.
|
||||
*
|
||||
* @details This module contains APIs to read and interact with the Battery Service of a remote
|
||||
* device.
|
||||
*
|
||||
* @note The application must register this module as the BLE event observer by using the
|
||||
* NRF_SDH_BLE_OBSERVER macro. Example:
|
||||
* @code
|
||||
* ble_bas_c_t instance;
|
||||
* NRF_SDH_BLE_OBSERVER(anything, BLE_BAS_C_BLE_OBSERVER_PRIO,
|
||||
* ble_bas_c_on_ble_evt, &instance);
|
||||
* @endcode
|
||||
*/
|
||||
|
||||
#ifndef BLE_BAS_C_H__
|
||||
#define BLE_BAS_C_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include "ble.h"
|
||||
#include "ble_db_discovery.h"
|
||||
#include "ble_srv_common.h"
|
||||
#include "nrf_ble_gq.h"
|
||||
#include "nrf_sdh_ble.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**@brief Macro for defining a ble_bas_c instance.
|
||||
*
|
||||
* @param _name Name of the instance.
|
||||
* @hideinitializer
|
||||
*/
|
||||
#define BLE_BAS_C_DEF(_name) \
|
||||
static ble_bas_c_t _name; \
|
||||
NRF_SDH_BLE_OBSERVER(_name ## _obs, \
|
||||
BLE_BAS_C_BLE_OBSERVER_PRIO, \
|
||||
ble_bas_c_on_ble_evt, &_name)
|
||||
|
||||
/** @brief Macro for defining multiple ble_bas_c instances.
|
||||
*
|
||||
* @param _name Name of the array of instances.
|
||||
* @param _cnt Number of instances to define.
|
||||
* @hideinitializer
|
||||
*/
|
||||
#define BLE_BAS_C_ARRAY_DEF(_name, _cnt) \
|
||||
static ble_bas_c_t _name[_cnt]; \
|
||||
NRF_SDH_BLE_OBSERVERS(_name ## _obs, \
|
||||
BLE_BAS_C_BLE_OBSERVER_PRIO, \
|
||||
ble_bas_c_on_ble_evt, &_name, _cnt)
|
||||
|
||||
/**
|
||||
* @defgroup bas_c_enums Enumerations
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**@brief Battery Service Client event type. */
|
||||
typedef enum
|
||||
{
|
||||
BLE_BAS_C_EVT_DISCOVERY_COMPLETE, /**< Event indicating that the Battery Service was discovered at the peer. */
|
||||
BLE_BAS_C_EVT_BATT_NOTIFICATION, /**< Event indicating that a notification of the Battery Level characteristic was received from the peer. */
|
||||
BLE_BAS_C_EVT_BATT_READ_RESP /**< Event indicating that a read response on Battery Level characteristic was received from the peer. */
|
||||
} ble_bas_c_evt_type_t;
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @defgroup bas_c_structs Structures
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**@brief Structure containing the handles related to the Battery Service found on the peer. */
|
||||
typedef struct
|
||||
{
|
||||
uint16_t bl_cccd_handle; /**< Handle of the CCCD of the Battery Level characteristic. */
|
||||
uint16_t bl_handle; /**< Handle of the Battery Level characteristic, as provided by the SoftDevice. */
|
||||
} ble_bas_c_db_t;
|
||||
|
||||
/**@brief Battery Service Client Event structure. */
|
||||
typedef struct
|
||||
{
|
||||
ble_bas_c_evt_type_t evt_type; /**< Event Type. */
|
||||
uint16_t conn_handle; /**< Connection handle relevant to this event.*/
|
||||
union
|
||||
{
|
||||
ble_bas_c_db_t bas_db; /**< Handles related to the Battery Service, found on the peer device. This is filled if the evt_type is @ref BLE_BAS_C_EVT_DISCOVERY_COMPLETE.*/
|
||||
uint8_t battery_level; /**< Information about the battery level, received from peer. This field is used for the events @ref BLE_BAS_C_EVT_BATT_NOTIFICATION and @ref BLE_BAS_C_EVT_BATT_READ_RESP.*/
|
||||
} params;
|
||||
} ble_bas_c_evt_t;
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @defgroup bas_c_types Types
|
||||
* @{
|
||||
*/
|
||||
|
||||
// Forward declaration of the ble_bas_t type.
|
||||
typedef struct ble_bas_c_s ble_bas_c_t;
|
||||
|
||||
/**@brief Event handler type.
|
||||
*
|
||||
* @details This is the type of the event handler that is to be provided by the application
|
||||
* of the BAS module to receive events.
|
||||
*/
|
||||
typedef void (* ble_bas_c_evt_handler_t) (ble_bas_c_t * p_bas_bas_c, ble_bas_c_evt_t * p_evt);
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @addtogroup bas_c_structs
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**@brief Battery Service Client structure. */
|
||||
struct ble_bas_c_s
|
||||
{
|
||||
uint16_t conn_handle; /**< Connection handle, as provided by the SoftDevice. */
|
||||
ble_bas_c_db_t peer_bas_db; /**< Handles related to BAS on the peer.*/
|
||||
ble_bas_c_evt_handler_t evt_handler; /**< Application event handler to be called when there is an event related to the Battery Service. */
|
||||
ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
|
||||
nrf_ble_gq_t * p_gatt_queue; /**< Pointer to the BLE GATT Queue instance. */
|
||||
};
|
||||
|
||||
/**@brief Battery Service Client initialization structure. */
|
||||
typedef struct
|
||||
{
|
||||
ble_bas_c_evt_handler_t evt_handler; /**< Event handler to be called by the Battery Service Client module when there is an event related to the Battery Service. */
|
||||
ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
|
||||
nrf_ble_gq_t * p_gatt_queue; /**< Pointer to the BLE GATT Queue instance. */
|
||||
} ble_bas_c_init_t;
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @defgroup bas_c_functions Functions
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**@brief Function for initializing the Battery Service Client module.
|
||||
*
|
||||
* @details This function initializes the module and sets up database discovery to discover
|
||||
* the Battery Service. After calling this function, call @ref ble_db_discovery_start
|
||||
* to start discovery once a link with a peer has been established.
|
||||
*
|
||||
* @param[out] p_ble_bas_c Pointer to the Battery Service Client structure.
|
||||
* @param[in] p_ble_bas_c_init Pointer to the Battery Service initialization structure that contains
|
||||
* the initialization information.
|
||||
*
|
||||
* @retval NRF_SUCCESS Operation success.
|
||||
* @retval NRF_ERROR_NULL A parameter is NULL.
|
||||
* @retval err_code Otherwise, an error code returned by @ref ble_db_discovery_evt_register.
|
||||
*/
|
||||
uint32_t ble_bas_c_init(ble_bas_c_t * p_ble_bas_c, ble_bas_c_init_t * p_ble_bas_c_init);
|
||||
|
||||
|
||||
/**@brief Function for handling BLE events from the SoftDevice.
|
||||
*
|
||||
* @details This function handles the BLE events received from the SoftDevice. If a BLE
|
||||
* event is relevant to the Battery Service Client module, the function uses the event's data to update
|
||||
* interval variables and, if necessary, send events to the application.
|
||||
*
|
||||
* @note This function must be called by the application.
|
||||
*
|
||||
* @param[in] p_ble_evt Pointer to the BLE event.
|
||||
* @param[in] p_context Pointer to the Battery Service client structure.
|
||||
*/
|
||||
void ble_bas_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
|
||||
|
||||
|
||||
/**@brief Function for enabling notifications on the Battery Level characteristic.
|
||||
*
|
||||
* @details This function enables the notification of the Battery Level characteristic at the
|
||||
* peer by writing to the CCCD of the Battery Level Characteristic.
|
||||
*
|
||||
* @param p_ble_bas_c Pointer to the Battery Service client structure.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the SoftDevice has been requested to write to the CCCD of the peer.
|
||||
* @retval NRF_ERROR_NULL Parameter is NULL.
|
||||
* @retval err_code Otherwise, an error code returned by the SoftDevice API @ref
|
||||
* sd_ble_gattc_write.
|
||||
*/
|
||||
uint32_t ble_bas_c_bl_notif_enable(ble_bas_c_t * p_ble_bas_c);
|
||||
|
||||
|
||||
/**@brief Function for reading the Battery Level characteristic.
|
||||
*
|
||||
* @param p_ble_bas_c Pointer to the Battery Service client structure.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the read request was successfully queued to be sent to peer.
|
||||
*/
|
||||
uint32_t ble_bas_c_bl_read(ble_bas_c_t * p_ble_bas_c);
|
||||
|
||||
|
||||
/**@brief Function for handling events from the Database Discovery module.
|
||||
*
|
||||
* @details Call this function when you get a callback event from the Database Discovery module.
|
||||
* This function handles an event from the Database Discovery module, and determines
|
||||
* whether it relates to the discovery of Battery Service at the peer. If it does, this function
|
||||
* calls the application's event handler to indicate that the Battery Service was
|
||||
* discovered at the peer. The function also populates the event with service-related
|
||||
* information before providing it to the application.
|
||||
*
|
||||
* @param p_ble_bas_c Pointer to the Battery Service client structure.
|
||||
* @param[in] p_evt Pointer to the event received from the Database Discovery module.
|
||||
*
|
||||
*/
|
||||
void ble_bas_on_db_disc_evt(ble_bas_c_t * p_ble_bas_c, ble_db_discovery_evt_t const * p_evt);
|
||||
|
||||
|
||||
/**@brief Function for assigning handles to this instance of bas_c.
|
||||
*
|
||||
* @details Call this function when a link has been established with a peer to
|
||||
* associate the link to this instance of the module. This makes it
|
||||
* possible to handle several links and associate each link to a particular
|
||||
* instance of this module. The connection handle and attribute handles are
|
||||
* provided from the discovery event @ref BLE_BAS_C_EVT_DISCOVERY_COMPLETE.
|
||||
*
|
||||
* @param[in] p_ble_bas_c Pointer to the Battery client structure instance for associating the link.
|
||||
* @param[in] conn_handle Connection handle associated with the given Battery Client Instance.
|
||||
* @param[in] p_peer_handles Attribute handles on the BAS server you want this BAS client to
|
||||
* interact with.
|
||||
*/
|
||||
uint32_t ble_bas_c_handles_assign(ble_bas_c_t * p_ble_bas_c,
|
||||
uint16_t conn_handle,
|
||||
ble_bas_c_db_t * p_peer_handles);
|
||||
|
||||
/** @} */ // End tag for Function group.
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // BLE_BAS_C_H__
|
||||
|
||||
/** @} */ // End tag for the file.
|
||||
420
components/ble/ble_services/ble_bps/ble_bps.c
Normal file
420
components/ble/ble_services/ble_bps/ble_bps.c
Normal file
@@ -0,0 +1,420 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 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.
|
||||
*
|
||||
*/
|
||||
/* Attention!
|
||||
* To maintain compliance with Nordic Semiconductor ASA's Bluetooth profile
|
||||
* qualification listings, this section of source code must not be modified.
|
||||
*/
|
||||
#include "sdk_common.h"
|
||||
#if NRF_MODULE_ENABLED(BLE_BPS)
|
||||
#include "ble_bps.h"
|
||||
#include "ble_err.h"
|
||||
#include <string.h>
|
||||
#include "nordic_common.h"
|
||||
#include "ble_srv_common.h"
|
||||
|
||||
|
||||
#define OPCODE_LENGTH 1 /**< Length of opcode inside Blood Pressure Measurement packet. */
|
||||
#define HANDLE_LENGTH 2 /**< Length of handle inside Blood Pressure Measurement packet. */
|
||||
#define MAX_BPM_LEN (BLE_GATT_ATT_MTU_DEFAULT - OPCODE_LENGTH - HANDLE_LENGTH) /**< Maximum size of a transmitted Blood Pressure Measurement. */
|
||||
|
||||
// Blood Pressure Measurement Flags bits
|
||||
#define BPS_MEAS_BLOOD_PRESSURE_UNITS_FLAG_BIT (0x01 << 0) /**< Blood Pressure Units Flag bit. */
|
||||
#define BPS_MEAS_TIME_STAMP_FLAG_BIT (0x01 << 1) /**< Time Stamp Flag bit. */
|
||||
#define BPS_MEAS_PULSE_RATE_FLAG_BIT (0x01 << 2) /**< Pulse Rate Flag bit. */
|
||||
#define BPS_MEAS_USER_ID_FLAG_BIT (0x01 << 3) /**< User ID Flag bit. */
|
||||
#define BPS_MEAS_MEASUREMENT_STATUS_FLAG_BIT (0x01 << 4) /**< Measurement Status Flag bit. */
|
||||
|
||||
|
||||
/**@brief Function for interception of GATT errors and @ref nrf_ble_gq errors.
|
||||
*
|
||||
* @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)
|
||||
{
|
||||
ble_bps_t * p_bps = (ble_bps_t *)p_ctx;
|
||||
|
||||
if (p_bps->error_handler != NULL)
|
||||
{
|
||||
p_bps->error_handler(nrf_error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling the Connect event.
|
||||
*
|
||||
* @param[in] p_bps Blood Pressure Service structure.
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
*/
|
||||
static void on_connect(ble_bps_t * p_bps, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
|
||||
p_bps->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
|
||||
|
||||
err_code = nrf_ble_gq_conn_handle_register(p_bps->p_gatt_queue,
|
||||
p_ble_evt->evt.gap_evt.conn_handle);
|
||||
|
||||
if ((p_bps->error_handler != NULL) &&
|
||||
(err_code != NRF_SUCCESS))
|
||||
{
|
||||
p_bps->error_handler(err_code);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling the Disconnect event.
|
||||
*
|
||||
* @param[in] p_bps Blood Pressure Service structure.
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
*/
|
||||
static void on_disconnect(ble_bps_t * p_bps, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
UNUSED_PARAMETER(p_ble_evt);
|
||||
p_bps->conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling the write events to the Blood Pressure Measurement characteristic.
|
||||
*
|
||||
* @param[in] p_bps Blood Pressure Service structure.
|
||||
* @param[in] p_evt_write Write event received from the BLE stack.
|
||||
*/
|
||||
static void on_cccd_write(ble_bps_t * p_bps, ble_gatts_evt_write_t const * p_evt_write)
|
||||
{
|
||||
if (p_evt_write->len == 2)
|
||||
{
|
||||
// CCCD written, update indication state
|
||||
if (p_bps->evt_handler != NULL)
|
||||
{
|
||||
ble_bps_evt_t evt;
|
||||
|
||||
if (ble_srv_is_indication_enabled(p_evt_write->data))
|
||||
{
|
||||
evt.evt_type = BLE_BPS_EVT_INDICATION_ENABLED;
|
||||
}
|
||||
else
|
||||
{
|
||||
evt.evt_type = BLE_BPS_EVT_INDICATION_DISABLED;
|
||||
}
|
||||
|
||||
p_bps->evt_handler(p_bps, &evt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling the Write event.
|
||||
*
|
||||
* @param[in] p_bps Blood Pressure Service structure.
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
*/
|
||||
static void on_write(ble_bps_t * p_bps, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
ble_gatts_evt_write_t const * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
|
||||
|
||||
if (p_evt_write->handle == p_bps->meas_handles.cccd_handle)
|
||||
{
|
||||
on_cccd_write(p_bps, p_evt_write);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling the HVC event.
|
||||
*
|
||||
* @details Handles HVC events from the BLE stack.
|
||||
*
|
||||
* @param[in] p_bps Blood Pressure Service structure.
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
*/
|
||||
static void on_hvc(ble_bps_t * p_bps, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
ble_gatts_evt_hvc_t const * p_hvc = &p_ble_evt->evt.gatts_evt.params.hvc;
|
||||
|
||||
if (p_hvc->handle == p_bps->meas_handles.value_handle)
|
||||
{
|
||||
ble_bps_evt_t evt;
|
||||
|
||||
evt.evt_type = BLE_BPS_EVT_INDICATION_CONFIRMED;
|
||||
p_bps->evt_handler(p_bps, &evt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ble_bps_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
|
||||
{
|
||||
ble_bps_t * p_bps = (ble_bps_t *)p_context;
|
||||
|
||||
switch (p_ble_evt->header.evt_id)
|
||||
{
|
||||
case BLE_GAP_EVT_CONNECTED:
|
||||
on_connect(p_bps, p_ble_evt);
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVT_DISCONNECTED:
|
||||
on_disconnect(p_bps, p_ble_evt);
|
||||
break;
|
||||
|
||||
case BLE_GATTS_EVT_WRITE:
|
||||
on_write(p_bps, p_ble_evt);
|
||||
break;
|
||||
|
||||
case BLE_GATTS_EVT_HVC:
|
||||
on_hvc(p_bps, p_ble_evt);
|
||||
break;
|
||||
|
||||
default:
|
||||
// No implementation needed.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for encoding a Blood Pressure Measurement.
|
||||
*
|
||||
* @param[in] p_bps Blood Pressure Service structure.
|
||||
* @param[in] p_bps_meas Measurement to be encoded.
|
||||
* @param[out] p_encoded_buffer Buffer where the encoded data will be written.
|
||||
*
|
||||
* @return Size of encoded data.
|
||||
*/
|
||||
static uint8_t bps_measurement_encode(ble_bps_t * p_bps,
|
||||
ble_bps_meas_t * p_bps_meas,
|
||||
uint8_t * p_encoded_buffer)
|
||||
{
|
||||
uint8_t flags = 0;
|
||||
uint8_t len = 1;
|
||||
uint16_t encoded_sfloat;
|
||||
|
||||
// Set measurement units flag
|
||||
if (p_bps_meas->blood_pressure_units_in_kpa)
|
||||
{
|
||||
flags |= BPS_MEAS_BLOOD_PRESSURE_UNITS_FLAG_BIT;
|
||||
}
|
||||
|
||||
// Blood Pressure Measurement - Systolic
|
||||
encoded_sfloat = ((p_bps_meas->blood_pressure_systolic.exponent << 12) & 0xF000) |
|
||||
((p_bps_meas->blood_pressure_systolic.mantissa << 0) & 0x0FFF);
|
||||
len += uint16_encode(encoded_sfloat, &p_encoded_buffer[len]);
|
||||
|
||||
// Blood Pressure Measurement - Diastolic
|
||||
encoded_sfloat = ((p_bps_meas->blood_pressure_diastolic.exponent << 12) & 0xF000) |
|
||||
((p_bps_meas->blood_pressure_diastolic.mantissa << 0) & 0x0FFF);
|
||||
len += uint16_encode(encoded_sfloat, &p_encoded_buffer[len]);
|
||||
|
||||
// Blood Pressure Measurement - Mean Arterial Pressure
|
||||
encoded_sfloat = ((p_bps_meas->mean_arterial_pressure.exponent << 12) & 0xF000) |
|
||||
((p_bps_meas->mean_arterial_pressure.mantissa << 0) & 0x0FFF);
|
||||
len += uint16_encode(encoded_sfloat, &p_encoded_buffer[len]);
|
||||
|
||||
// Time Stamp field
|
||||
if (p_bps_meas->time_stamp_present)
|
||||
{
|
||||
flags |= BPS_MEAS_TIME_STAMP_FLAG_BIT;
|
||||
len += ble_date_time_encode(&p_bps_meas->time_stamp, &p_encoded_buffer[len]);
|
||||
}
|
||||
|
||||
// Pulse Rate
|
||||
if (p_bps_meas->pulse_rate_present)
|
||||
{
|
||||
flags |= BPS_MEAS_PULSE_RATE_FLAG_BIT;
|
||||
|
||||
encoded_sfloat = ((p_bps_meas->pulse_rate.exponent << 12) & 0xF000) |
|
||||
((p_bps_meas->pulse_rate.mantissa << 0) & 0x0FFF);
|
||||
len += uint16_encode(encoded_sfloat, &p_encoded_buffer[len]);
|
||||
}
|
||||
|
||||
// User ID
|
||||
if (p_bps_meas->user_id_present)
|
||||
{
|
||||
flags |= BPS_MEAS_USER_ID_FLAG_BIT;
|
||||
p_encoded_buffer[len++] = p_bps_meas->user_id;
|
||||
}
|
||||
|
||||
// Measurement Status
|
||||
if (p_bps_meas->measurement_status_present)
|
||||
{
|
||||
flags |= BPS_MEAS_MEASUREMENT_STATUS_FLAG_BIT;
|
||||
len += uint16_encode(p_bps_meas->measurement_status, &p_encoded_buffer[len]);
|
||||
}
|
||||
|
||||
// Flags field
|
||||
p_encoded_buffer[0] = flags;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_bps_init(ble_bps_t * p_bps, ble_bps_init_t const * p_bps_init)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_bps);
|
||||
VERIFY_PARAM_NOT_NULL(p_bps_init);
|
||||
VERIFY_PARAM_NOT_NULL(p_bps_init->p_gatt_queue);
|
||||
|
||||
uint32_t err_code;
|
||||
uint8_t init_value_encoded[MAX_BPM_LEN];
|
||||
uint8_t initial_feature_len;
|
||||
ble_bps_meas_t initial_bpm;
|
||||
ble_uuid_t ble_uuid;
|
||||
ble_add_char_params_t add_char_params;
|
||||
|
||||
// Initialize service structure
|
||||
p_bps->evt_handler = p_bps_init->evt_handler;
|
||||
p_bps->error_handler = p_bps_init->error_handler;
|
||||
p_bps->p_gatt_queue = p_bps_init->p_gatt_queue;
|
||||
p_bps->conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
p_bps->feature = p_bps_init->feature;
|
||||
|
||||
// Add service
|
||||
BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_BLOOD_PRESSURE_SERVICE);
|
||||
|
||||
err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &ble_uuid, &p_bps->service_handle);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
|
||||
// Add measurement characteristic
|
||||
memset(&initial_bpm, 0, sizeof(initial_bpm));
|
||||
memset(&add_char_params, 0, sizeof(add_char_params));
|
||||
|
||||
add_char_params.uuid = BLE_UUID_BLOOD_PRESSURE_MEASUREMENT_CHAR;
|
||||
add_char_params.max_len = MAX_BPM_LEN;
|
||||
add_char_params.is_var_len = true;
|
||||
add_char_params.init_len = bps_measurement_encode(p_bps, &initial_bpm, init_value_encoded);
|
||||
add_char_params.p_init_value = init_value_encoded;
|
||||
add_char_params.char_props.indicate = 1;
|
||||
add_char_params.cccd_write_access = p_bps_init->bp_cccd_wr_sec;
|
||||
|
||||
err_code = characteristic_add(p_bps->service_handle, &add_char_params, &p_bps->meas_handles);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
|
||||
// Add feature characteristic
|
||||
initial_feature_len = uint16_encode(p_bps_init->feature, init_value_encoded);
|
||||
|
||||
memset(&add_char_params, 0, sizeof(add_char_params));
|
||||
|
||||
add_char_params.uuid = BLE_UUID_BLOOD_PRESSURE_FEATURE_CHAR;
|
||||
add_char_params.max_len = initial_feature_len;
|
||||
add_char_params.init_len = initial_feature_len;
|
||||
add_char_params.p_init_value = init_value_encoded;
|
||||
add_char_params.char_props.read = 1;
|
||||
add_char_params.read_access = p_bps_init->bp_feature_rd_sec;
|
||||
|
||||
err_code = characteristic_add(p_bps->service_handle, &add_char_params, &p_bps->feature_handles);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_bps_measurement_send(ble_bps_t * p_bps, ble_bps_meas_t * p_bps_meas)
|
||||
{
|
||||
uint32_t err_code;
|
||||
|
||||
// Send value if connected
|
||||
if (p_bps->conn_handle != BLE_CONN_HANDLE_INVALID)
|
||||
{
|
||||
uint8_t encoded_bps_meas[MAX_BPM_LEN];
|
||||
uint16_t len;
|
||||
nrf_ble_gq_req_t bps_req;
|
||||
|
||||
len = bps_measurement_encode(p_bps, p_bps_meas, encoded_bps_meas);
|
||||
|
||||
memset(&bps_req, 0, sizeof(nrf_ble_gq_req_t));
|
||||
|
||||
bps_req.type = NRF_BLE_GQ_REQ_GATTS_HVX;
|
||||
bps_req.error_handler.cb = gatt_error_handler;
|
||||
bps_req.error_handler.p_ctx = p_bps;
|
||||
bps_req.params.gatts_hvx.handle = p_bps->meas_handles.value_handle;
|
||||
bps_req.params.gatts_hvx.offset = 0;
|
||||
bps_req.params.gatts_hvx.p_data = encoded_bps_meas;
|
||||
bps_req.params.gatts_hvx.p_len = &len;
|
||||
bps_req.params.gatts_hvx.type = BLE_GATT_HVX_INDICATION;
|
||||
|
||||
err_code = nrf_ble_gq_item_add(p_bps->p_gatt_queue, &bps_req, p_bps->conn_handle);
|
||||
}
|
||||
else
|
||||
{
|
||||
err_code = NRF_ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
return err_code;
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_bps_is_indication_enabled(ble_bps_t * p_bps, bool * p_indication_enabled)
|
||||
{
|
||||
uint32_t err_code;
|
||||
uint8_t cccd_value_buf[BLE_CCCD_VALUE_LEN];
|
||||
ble_gatts_value_t gatts_value;
|
||||
|
||||
// Initialize value struct.
|
||||
memset(&gatts_value, 0, sizeof(gatts_value));
|
||||
|
||||
gatts_value.len = BLE_CCCD_VALUE_LEN;
|
||||
gatts_value.offset = 0;
|
||||
gatts_value.p_value = cccd_value_buf;
|
||||
|
||||
err_code = sd_ble_gatts_value_get(p_bps->conn_handle,
|
||||
p_bps->meas_handles.cccd_handle,
|
||||
&gatts_value);
|
||||
|
||||
if (err_code == NRF_SUCCESS)
|
||||
{
|
||||
*p_indication_enabled = ble_srv_is_indication_enabled(cccd_value_buf);
|
||||
}
|
||||
if (err_code == BLE_ERROR_GATTS_SYS_ATTR_MISSING)
|
||||
{
|
||||
*p_indication_enabled = false;
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
return err_code;
|
||||
}
|
||||
#endif // NRF_MODULE_ENABLED(BLE_BPS)
|
||||
226
components/ble/ble_services/ble_bps/ble_bps.h
Normal file
226
components/ble/ble_services/ble_bps/ble_bps.h
Normal file
@@ -0,0 +1,226 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 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 ble_bps Blood Pressure Service
|
||||
* @{
|
||||
* @ingroup ble_sdk_srv
|
||||
* @brief Blood Pressure Service module.
|
||||
*
|
||||
* @details This module implements the Blood Pressure Service.
|
||||
*
|
||||
* If an event handler is supplied by the application, the Blood Pressure
|
||||
* Service will generate Blood Pressure 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_bps_t instance;
|
||||
* NRF_SDH_BLE_OBSERVER(anything, BLE_BPS_BLE_OBSERVER_PRIO,
|
||||
* ble_bps_on_ble_evt, &instance);
|
||||
* @endcode
|
||||
*
|
||||
* @note Attention!
|
||||
* To maintain compliance with Nordic Semiconductor ASA Bluetooth profile
|
||||
* qualification listings, this section of source code must not be modified.
|
||||
*/
|
||||
|
||||
#ifndef BLE_BPS_H__
|
||||
#define BLE_BPS_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "ble.h"
|
||||
#include "ble_srv_common.h"
|
||||
#include "ble_date_time.h"
|
||||
#include "nrf_sdh_ble.h"
|
||||
#include "nrf_ble_gq.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**@brief Macro for defining a ble_bps instance.
|
||||
*
|
||||
* @param _name Name of the instance.
|
||||
* @hideinitializer
|
||||
*/
|
||||
#define BLE_BPS_DEF(_name) \
|
||||
static ble_bps_t _name; \
|
||||
NRF_SDH_BLE_OBSERVER(_name ## _obs, \
|
||||
BLE_BPS_BLE_OBSERVER_PRIO, \
|
||||
ble_bps_on_ble_evt, &_name)
|
||||
|
||||
|
||||
// Blood Pressure Feature bits
|
||||
#define BLE_BPS_FEATURE_BODY_MOVEMENT_BIT (0x01 << 0) /**< Body Movement Detection Support bit. */
|
||||
#define BLE_BPS_FEATURE_CUFF_FIT_BIT (0x01 << 1) /**< Cuff Fit Detection Support bit. */
|
||||
#define BLE_BPS_FEATURE_IRREGULAR_PULSE_BIT (0x01 << 2) /**< Irregular Pulse Detection Support bit. */
|
||||
#define BLE_BPS_FEATURE_PULSE_RATE_RANGE_BIT (0x01 << 3) /**< Pulse Rate Range Detection Support bit. */
|
||||
#define BLE_BPS_FEATURE_MEASUREMENT_POSITION_BIT (0x01 << 4) /**< Measurement Position Detection Support bit. */
|
||||
#define BLE_BPS_FEATURE_MULTIPLE_BOND_BIT (0x01 << 5) /**< Multiple Bond Support bit. */
|
||||
|
||||
|
||||
/**@brief Blood Pressure Service event type. */
|
||||
typedef enum
|
||||
{
|
||||
BLE_BPS_EVT_INDICATION_ENABLED, /**< Blood Pressure value indication enabled event. */
|
||||
BLE_BPS_EVT_INDICATION_DISABLED, /**< Blood Pressure value indication disabled event. */
|
||||
BLE_BPS_EVT_INDICATION_CONFIRMED /**< Confirmation of a blood pressure measurement indication has been received. */
|
||||
} ble_bps_evt_type_t;
|
||||
|
||||
/**@brief Blood Pressure Service event. */
|
||||
typedef struct
|
||||
{
|
||||
ble_bps_evt_type_t evt_type; /**< Type of event. */
|
||||
} ble_bps_evt_t;
|
||||
|
||||
// Forward declaration of the ble_bps_t type.
|
||||
typedef struct ble_bps_s ble_bps_t;
|
||||
|
||||
/**@brief Blood Pressure Service event handler type. */
|
||||
typedef void (*ble_bps_evt_handler_t) (ble_bps_t * p_bps, ble_bps_evt_t * p_evt);
|
||||
|
||||
/**@brief SFLOAT format (IEEE-11073 16-bit FLOAT, defined as a 16-bit vlue with 12-bit mantissa and
|
||||
* 4-bit exponent. */
|
||||
typedef struct
|
||||
{
|
||||
int8_t exponent; /**< Base 10 exponent, only 4 bits */
|
||||
int16_t mantissa; /**< Mantissa, only 12 bits */
|
||||
} ieee_float16_t;
|
||||
|
||||
/**@brief Blood Pressure Service init structure. This contains all options and data
|
||||
* needed for initialization of the service. */
|
||||
typedef struct
|
||||
{
|
||||
ble_bps_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Blood Pressure Service. */
|
||||
ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
|
||||
security_req_t bp_cccd_wr_sec; /**< Security requirement for writing blood pressure measurement characteristic CCCD. */
|
||||
security_req_t bp_feature_rd_sec; /**< Security requirement for reading the blood pressure feature characteristic. */
|
||||
uint16_t feature; /**< Initial value for blood pressure feature */
|
||||
nrf_ble_gq_t * p_gatt_queue; /**< Pointer to BLE GATT Queue instance. */
|
||||
} ble_bps_init_t;
|
||||
|
||||
/**@brief Blood Pressure Service structure. This contains various status information for
|
||||
* the service. */
|
||||
struct ble_bps_s
|
||||
{
|
||||
ble_bps_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Blood Pressure Service. */
|
||||
ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
|
||||
uint16_t service_handle; /**< Handle of Blood Pressure Service (as provided by the BLE stack). */
|
||||
ble_gatts_char_handles_t meas_handles; /**< Handles related to the Blood Pressure Measurement characteristic. */
|
||||
ble_gatts_char_handles_t feature_handles; /**< Handles related to the Blood Pressure Feature characteristic. */
|
||||
uint16_t conn_handle; /**< Handle of the current connection (as provided by the BLE stack, is BLE_CONN_HANDLE_INVALID if not in a connection). */
|
||||
uint16_t feature; /**< Value of Blood Pressure feature. */
|
||||
nrf_ble_gq_t * p_gatt_queue; /**< Pointer to BLE GATT Queue instance. */
|
||||
};
|
||||
|
||||
/**@brief Blood Pressure Service measurement structure. This contains a Blood Pressure
|
||||
* measurement. */
|
||||
typedef struct ble_bps_meas_s
|
||||
{
|
||||
bool blood_pressure_units_in_kpa; /**< Blood Pressure Units Flag, 0=mmHg, 1=kPa */
|
||||
bool time_stamp_present; /**< Time Stamp Flag, 0=not present, 1=present. */
|
||||
bool pulse_rate_present; /**< Pulse Rate Flag, 0=not present, 1=present. */
|
||||
bool user_id_present; /**< User ID Flag, 0=not present, 1=present. */
|
||||
bool measurement_status_present; /**< Measurement Status Flag, 0=not present, 1=present. */
|
||||
ieee_float16_t blood_pressure_systolic; /**< Blood Pressure Measurement Compound Value - Systolic. */
|
||||
ieee_float16_t blood_pressure_diastolic; /**< Blood Pressure Measurement Compound Value - Diastolic . */
|
||||
ieee_float16_t mean_arterial_pressure; /**< Blood Pressure Measurement Compound Value - Mean Arterial Pressure. */
|
||||
ble_date_time_t time_stamp; /**< Time Stamp. */
|
||||
ieee_float16_t pulse_rate; /**< Pulse Rate. */
|
||||
uint8_t user_id; /**< User ID. */
|
||||
uint16_t measurement_status; /**< Measurement Status. */
|
||||
} ble_bps_meas_t;
|
||||
|
||||
|
||||
/**@brief Function for initializing the Blood Pressure Service.
|
||||
*
|
||||
* @param[out] p_bps Blood Pressure Service structure. This structure will have to
|
||||
* be supplied by the application. It will be initialized by this function,
|
||||
* and will later be used to identify this particular service instance.
|
||||
* @param[in] p_bps_init Information needed to initialize the service.
|
||||
*
|
||||
* @return NRF_SUCCESS on successful initialization of service, otherwise an error code.
|
||||
*/
|
||||
uint32_t ble_bps_init(ble_bps_t * p_bps, ble_bps_init_t const * p_bps_init);
|
||||
|
||||
|
||||
/**@brief Function for handling the Application's BLE Stack events.
|
||||
*
|
||||
* @details Handles all events from the BLE stack of interest to the Blood Pressure Service.
|
||||
*
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
* @param[in] p_context Blood Pressure Service structure.
|
||||
*/
|
||||
void ble_bps_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
|
||||
|
||||
|
||||
/**@brief Function for sending blood pressure measurement if indication has been enabled.
|
||||
*
|
||||
* @details The application calls this function after having performed a Blood Pressure
|
||||
* measurement. If indication has been enabled, the measurement data is encoded and
|
||||
* sent to the client.
|
||||
*
|
||||
* @param[in] p_bps Blood Pressure Service structure.
|
||||
* @param[in] p_bps_meas Pointer to new blood pressure measurement.
|
||||
*
|
||||
* @return NRF_SUCCESS on success, otherwise an error code.
|
||||
*/
|
||||
uint32_t ble_bps_measurement_send(ble_bps_t * p_bps, ble_bps_meas_t * p_bps_meas);
|
||||
|
||||
|
||||
/**@brief Function for checking if indication of Blood Pressure Measurement is currently enabled.
|
||||
*
|
||||
* @param[in] p_bps Blood Pressure Service structure.
|
||||
* @param[out] p_indication_enabled TRUE if indication is enabled, FALSE otherwise.
|
||||
*
|
||||
* @return NRF_SUCCESS on success, otherwise an error code.
|
||||
*/
|
||||
uint32_t ble_bps_is_indication_enabled(ble_bps_t * p_bps, bool * p_indication_enabled);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // BLE_BPS_H__
|
||||
|
||||
/** @} */
|
||||
344
components/ble/ble_services/ble_cscs/ble_cscs.c
Normal file
344
components/ble/ble_services/ble_cscs/ble_cscs.c
Normal file
@@ -0,0 +1,344 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 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.
|
||||
*
|
||||
*/
|
||||
/* Attention!
|
||||
* To maintain compliance with Nordic Semiconductor ASA's Bluetooth profile
|
||||
* qualification listings, this section of source code must not be modified.
|
||||
*/
|
||||
|
||||
#include "ble_cscs.h"
|
||||
#include <string.h>
|
||||
#include "nordic_common.h"
|
||||
#include "ble.h"
|
||||
#include "ble_err.h"
|
||||
#include "ble_srv_common.h"
|
||||
#include "app_util.h"
|
||||
|
||||
#define OPCODE_LENGTH 1 /**< Length of opcode inside Cycling Speed and Cadence Measurement packet. */
|
||||
#define HANDLE_LENGTH 2 /**< Length of handle inside Cycling Speed and Cadence Measurement packet. */
|
||||
#define MAX_CSCM_LEN (BLE_GATT_ATT_MTU_DEFAULT - OPCODE_LENGTH - HANDLE_LENGTH) /**< Maximum size of a transmitted Cycling Speed and Cadence Measurement. */
|
||||
|
||||
// Cycling Speed and Cadence Measurement flag bits
|
||||
#define CSC_MEAS_FLAG_MASK_WHEEL_REV_DATA_PRESENT (0x01 << 0) /**< Wheel revolution data present flag bit. */
|
||||
#define CSC_MEAS_FLAG_MASK_CRANK_REV_DATA_PRESENT (0x01 << 1) /**< Crank revolution data present flag bit. */
|
||||
|
||||
|
||||
/**@brief Function for handling the Connect event.
|
||||
*
|
||||
* @param[in] p_cscs Cycling Speed and Cadence Service structure.
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
*/
|
||||
static void on_connect(ble_cscs_t * p_cscs, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
p_cscs->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling the Disconnect event.
|
||||
*
|
||||
* @param[in] p_cscs Cycling Speed and Cadence Service structure.
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
*/
|
||||
static void on_disconnect(ble_cscs_t * p_cscs, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
UNUSED_PARAMETER(p_ble_evt);
|
||||
p_cscs->conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling write events to the CSCS Measurement characteristic.
|
||||
*
|
||||
* @param[in] p_cscs Cycling Speed and Cadence Service structure.
|
||||
* @param[in] p_evt_write Write event received from the BLE stack.
|
||||
*/
|
||||
static void on_meas_cccd_write(ble_cscs_t * p_cscs, ble_gatts_evt_write_t const * p_evt_write)
|
||||
{
|
||||
if (p_evt_write->len == 2)
|
||||
{
|
||||
// CCCD written, update notification state
|
||||
if (p_cscs->evt_handler != NULL)
|
||||
{
|
||||
ble_cscs_evt_t evt;
|
||||
|
||||
if (ble_srv_is_notification_enabled(p_evt_write->data))
|
||||
{
|
||||
evt.evt_type = BLE_CSCS_EVT_NOTIFICATION_ENABLED;
|
||||
}
|
||||
else
|
||||
{
|
||||
evt.evt_type = BLE_CSCS_EVT_NOTIFICATION_DISABLED;
|
||||
}
|
||||
|
||||
p_cscs->evt_handler(p_cscs, &evt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling the Write event.
|
||||
*
|
||||
* @param[in] p_cscs Cycling Speed and Cadence Service structure.
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
*/
|
||||
static void on_write(ble_cscs_t * p_cscs, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
ble_gatts_evt_write_t const * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
|
||||
|
||||
if (p_evt_write->handle == p_cscs->meas_handles.cccd_handle)
|
||||
{
|
||||
on_meas_cccd_write(p_cscs, p_evt_write);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ble_cscs_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
|
||||
{
|
||||
ble_cscs_t * p_cscs = (ble_cscs_t *)p_context;
|
||||
|
||||
if (p_cscs == NULL || p_ble_evt == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ble_sc_ctrlpt_on_ble_evt(&(p_cscs->ctrl_pt), p_ble_evt);
|
||||
|
||||
switch (p_ble_evt->header.evt_id)
|
||||
{
|
||||
case BLE_GAP_EVT_CONNECTED:
|
||||
on_connect(p_cscs, p_ble_evt);
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVT_DISCONNECTED:
|
||||
on_disconnect(p_cscs, p_ble_evt);
|
||||
break;
|
||||
|
||||
case BLE_GATTS_EVT_WRITE:
|
||||
on_write(p_cscs, p_ble_evt);
|
||||
break;
|
||||
|
||||
default:
|
||||
// No implementation needed.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for encoding a CSCS Measurement.
|
||||
*
|
||||
* @param[in] p_cscs Cycling Speed and Cadence Service structure.
|
||||
* @param[in] p_csc_measurement Measurement to be encoded.
|
||||
* @param[out] p_encoded_buffer Buffer where the encoded data will be written.
|
||||
*
|
||||
* @return Size of encoded data.
|
||||
*/
|
||||
static uint8_t csc_measurement_encode(ble_cscs_t * p_cscs,
|
||||
ble_cscs_meas_t * p_csc_measurement,
|
||||
uint8_t * p_encoded_buffer)
|
||||
{
|
||||
uint8_t flags = 0;
|
||||
uint8_t len = 1;
|
||||
|
||||
// Cumulative Wheel Revolutions and Last Wheel Event Time Fields
|
||||
if (p_cscs->feature & BLE_CSCS_FEATURE_WHEEL_REV_BIT)
|
||||
{
|
||||
if (p_csc_measurement->is_wheel_rev_data_present)
|
||||
{
|
||||
flags |= CSC_MEAS_FLAG_MASK_WHEEL_REV_DATA_PRESENT;
|
||||
len += uint32_encode(p_csc_measurement->cumulative_wheel_revs, &p_encoded_buffer[len]);
|
||||
len += uint16_encode(p_csc_measurement->last_wheel_event_time, &p_encoded_buffer[len]);
|
||||
}
|
||||
}
|
||||
|
||||
// Cumulative Crank Revolutions and Last Crank Event Time Fields
|
||||
if (p_cscs->feature & BLE_CSCS_FEATURE_CRANK_REV_BIT)
|
||||
{
|
||||
if (p_csc_measurement->is_crank_rev_data_present)
|
||||
{
|
||||
flags |= CSC_MEAS_FLAG_MASK_CRANK_REV_DATA_PRESENT;
|
||||
len += uint16_encode(p_csc_measurement->cumulative_crank_revs, &p_encoded_buffer[len]);
|
||||
len += uint16_encode(p_csc_measurement->last_crank_event_time, &p_encoded_buffer[len]);
|
||||
}
|
||||
}
|
||||
|
||||
// Flags Field
|
||||
p_encoded_buffer[0] = flags;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_cscs_init(ble_cscs_t * p_cscs, ble_cscs_init_t const * p_cscs_init)
|
||||
{
|
||||
if (p_cscs == NULL || p_cscs_init == NULL)
|
||||
{
|
||||
return NRF_ERROR_NULL;
|
||||
}
|
||||
|
||||
uint32_t err_code;
|
||||
uint8_t init_value_encoded[MAX_CSCM_LEN];
|
||||
ble_cscs_meas_t initial_scm = {0};
|
||||
ble_add_char_params_t add_char_params;
|
||||
ble_uuid_t ble_uuid;
|
||||
ble_cs_ctrlpt_init_t sc_ctrlpt_init;
|
||||
|
||||
// Initialize service structure
|
||||
p_cscs->evt_handler = p_cscs_init->evt_handler;
|
||||
p_cscs->conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
p_cscs->feature = p_cscs_init->feature;
|
||||
|
||||
// Add service
|
||||
BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_CYCLING_SPEED_AND_CADENCE);
|
||||
|
||||
err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
|
||||
&ble_uuid,
|
||||
&p_cscs->service_handle);
|
||||
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
|
||||
// Add cycling speed and cadence measurement characteristic
|
||||
memset(&add_char_params, 0, sizeof(add_char_params));
|
||||
add_char_params.uuid = BLE_UUID_CSC_MEASUREMENT_CHAR;
|
||||
add_char_params.max_len = MAX_CSCM_LEN;
|
||||
add_char_params.is_var_len = true;
|
||||
add_char_params.init_len = csc_measurement_encode(p_cscs, &initial_scm, init_value_encoded);
|
||||
add_char_params.p_init_value = init_value_encoded;
|
||||
add_char_params.char_props.notify = 1;
|
||||
add_char_params.cccd_write_access = p_cscs_init->csc_meas_cccd_wr_sec;
|
||||
|
||||
err_code = characteristic_add(p_cscs->service_handle, &add_char_params, &p_cscs->meas_handles);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
|
||||
// Add cycling speed and cadence feature characteristic
|
||||
memset(&add_char_params, 0, sizeof(add_char_params));
|
||||
add_char_params.uuid = BLE_UUID_CSC_FEATURE_CHAR;
|
||||
add_char_params.max_len = sizeof(uint16_t);
|
||||
add_char_params.init_len = uint16_encode(p_cscs_init->feature, &init_value_encoded[0]);
|
||||
add_char_params.p_init_value = init_value_encoded;
|
||||
add_char_params.char_props.read = 1;
|
||||
add_char_params.read_access = p_cscs_init->csc_feature_rd_sec;
|
||||
|
||||
err_code = characteristic_add(p_cscs->service_handle,
|
||||
&add_char_params,
|
||||
&p_cscs->feature_handles);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
|
||||
// Add Sensor Location characteristic (optional)
|
||||
if (p_cscs_init->sensor_location != NULL)
|
||||
{
|
||||
memset(&add_char_params, 0, sizeof(add_char_params));
|
||||
add_char_params.uuid = BLE_UUID_SENSOR_LOCATION_CHAR;
|
||||
add_char_params.max_len = sizeof(uint8_t);
|
||||
add_char_params.init_len = sizeof(uint8_t);
|
||||
add_char_params.p_init_value = (uint8_t *)p_cscs_init->sensor_location;
|
||||
add_char_params.char_props.read = 1;
|
||||
add_char_params.read_access = p_cscs_init->csc_location_rd_sec;
|
||||
|
||||
err_code = characteristic_add(p_cscs->service_handle, &add_char_params, &p_cscs->sensor_loc_handles);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
}
|
||||
|
||||
// Add speed and cadence control point characteristic
|
||||
sc_ctrlpt_init.error_handler = p_cscs_init->error_handler;
|
||||
sc_ctrlpt_init.size_list_supported_locations = p_cscs_init->size_list_supported_locations;
|
||||
sc_ctrlpt_init.supported_functions = p_cscs_init->ctrplt_supported_functions;
|
||||
sc_ctrlpt_init.evt_handler = p_cscs_init->ctrlpt_evt_handler;
|
||||
sc_ctrlpt_init.list_supported_locations = p_cscs_init->list_supported_locations;
|
||||
sc_ctrlpt_init.sc_ctrlpt_wr_sec = p_cscs_init->sc_ctrlpt_wr_sec;
|
||||
sc_ctrlpt_init.sc_ctrlpt_cccd_wr_sec = p_cscs_init->sc_ctrlpt_cccd_wr_sec;
|
||||
sc_ctrlpt_init.sensor_location_handle = p_cscs->sensor_loc_handles.value_handle;
|
||||
sc_ctrlpt_init.service_handle = p_cscs->service_handle;
|
||||
|
||||
return ble_sc_ctrlpt_init(&p_cscs->ctrl_pt, &sc_ctrlpt_init);
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_cscs_measurement_send(ble_cscs_t * p_cscs, ble_cscs_meas_t * p_measurement)
|
||||
{
|
||||
if (p_cscs == NULL || p_measurement == NULL)
|
||||
{
|
||||
return NRF_ERROR_NULL;
|
||||
}
|
||||
|
||||
uint32_t err_code;
|
||||
|
||||
// Send value if connected and notifying
|
||||
if (p_cscs->conn_handle != BLE_CONN_HANDLE_INVALID)
|
||||
{
|
||||
uint8_t encoded_csc_meas[MAX_CSCM_LEN];
|
||||
uint16_t len;
|
||||
uint16_t hvx_len;
|
||||
ble_gatts_hvx_params_t hvx_params;
|
||||
|
||||
len = csc_measurement_encode(p_cscs, p_measurement, encoded_csc_meas);
|
||||
hvx_len = len;
|
||||
|
||||
memset(&hvx_params, 0, sizeof(hvx_params));
|
||||
|
||||
hvx_params.handle = p_cscs->meas_handles.value_handle;
|
||||
hvx_params.type = BLE_GATT_HVX_NOTIFICATION;
|
||||
hvx_params.offset = 0;
|
||||
hvx_params.p_len = &hvx_len;
|
||||
hvx_params.p_data = encoded_csc_meas;
|
||||
|
||||
err_code = sd_ble_gatts_hvx(p_cscs->conn_handle, &hvx_params);
|
||||
if ((err_code == NRF_SUCCESS) && (hvx_len != len))
|
||||
{
|
||||
err_code = NRF_ERROR_DATA_SIZE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
err_code = NRF_ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
return err_code;
|
||||
}
|
||||
219
components/ble/ble_services/ble_cscs/ble_cscs.h
Normal file
219
components/ble/ble_services/ble_cscs/ble_cscs.h
Normal file
@@ -0,0 +1,219 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 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 ble_cscs Cycling Speed and Cadence Service
|
||||
* @{
|
||||
* @ingroup ble_sdk_srv
|
||||
* @brief Cycling Speed and Cadence Service module.
|
||||
*
|
||||
* @details This module implements the Cycling Speed and Cadence Service. If enabled, notification
|
||||
* of the Cycling Speead and Candence Measurement is performed when the application
|
||||
* calls ble_cscs_measurement_send().
|
||||
*
|
||||
* To use this service, you need to provide the the supported features (@ref BLE_CSCS_FEATURES).
|
||||
* If you choose to support Wheel revolution data (feature bit @ref BLE_CSCS_FEATURE_WHEEL_REV_BIT),
|
||||
* you then need to support the 'setting of cumulative value' operation by the supporting the
|
||||
* Speed and Cadence Control Point (@ref ble_sdk_srv_sc_ctrlpt) by setting the @ref BLE_SRV_SC_CTRLPT_CUM_VAL_OP_SUPPORTED
|
||||
* bit of the ctrplt_supported_functions in the @ref ble_cscs_init_t structure.
|
||||
* If you want to support the 'start autocalibration' control point feature, you need, after the @ref BLE_SC_CTRLPT_EVT_START_CALIBRATION
|
||||
* has been received and the auto calibration is finished, to call the @ref ble_sc_ctrlpt_rsp_send to indicate that the operation is finished
|
||||
* and thus be able to receive new control point operations.
|
||||
* If you want to support the 'sensor location' related operation, you need to provide a list of supported location in the
|
||||
* @ref ble_cscs_init_t structure.
|
||||
*
|
||||
*
|
||||
* @note The application must register this module as BLE event observer using the
|
||||
* NRF_SDH_BLE_OBSERVER macro. Example:
|
||||
* @code
|
||||
* ble_cscs_t instance;
|
||||
* NRF_SDH_BLE_OBSERVER(anything, BLE_CSCS_BLE_OBSERVER_PRIO,
|
||||
* ble_cscs_on_ble_evt, &instance);
|
||||
* @endcode
|
||||
*
|
||||
* @note Attention!
|
||||
* To maintain compliance with Nordic Semiconductor ASA Bluetooth profile
|
||||
* qualification listings, this section of source code must not be modified.
|
||||
*/
|
||||
|
||||
#ifndef BLE_CSCS_H__
|
||||
#define BLE_CSCS_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "ble.h"
|
||||
#include "ble_srv_common.h"
|
||||
#include "ble_sc_ctrlpt.h"
|
||||
#include "ble_sensor_location.h"
|
||||
#include "nrf_sdh_ble.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**@brief Macro for defining a ble_cscs instance.
|
||||
*
|
||||
* @param _name Name of the instance.
|
||||
* @hideinitializer
|
||||
*/
|
||||
#define BLE_CSCS_DEF(_name) \
|
||||
static ble_cscs_t _name; \
|
||||
NRF_SDH_BLE_OBSERVER(_name ## _obs, \
|
||||
BLE_CSCS_BLE_OBSERVER_PRIO, \
|
||||
ble_cscs_on_ble_evt, &_name)
|
||||
|
||||
|
||||
/** @defgroup BLE_CSCS_FEATURES Cycling Speed and Cadence Service feature bits
|
||||
* @{ */
|
||||
#define BLE_CSCS_FEATURE_WHEEL_REV_BIT (0x01 << 0) /**< Wheel Revolution Data Supported bit. */
|
||||
#define BLE_CSCS_FEATURE_CRANK_REV_BIT (0x01 << 1) /**< Crank Revolution Data Supported bit. */
|
||||
#define BLE_CSCS_FEATURE_MULTIPLE_SENSORS_BIT (0x01 << 2) /**< Multiple Sensor Locations Supported bit. */
|
||||
/** @} */
|
||||
|
||||
|
||||
/**@brief Cycling Speed and Cadence Service event type. */
|
||||
typedef enum
|
||||
{
|
||||
BLE_CSCS_EVT_NOTIFICATION_ENABLED, /**< Cycling Speed and Cadence value notification enabled event. */
|
||||
BLE_CSCS_EVT_NOTIFICATION_DISABLED /**< Cycling Speed and Cadence value notification disabled event. */
|
||||
} ble_cscs_evt_type_t;
|
||||
|
||||
/**@brief Cycling Speed and Cadence Service event. */
|
||||
typedef struct
|
||||
{
|
||||
ble_cscs_evt_type_t evt_type; /**< Type of event. */
|
||||
} ble_cscs_evt_t;
|
||||
|
||||
// Forward declaration of the ble_csc_t type.
|
||||
typedef struct ble_cscs_s ble_cscs_t;
|
||||
|
||||
/**@brief Cycling Speed and Cadence Service event handler type. */
|
||||
typedef void (*ble_cscs_evt_handler_t) (ble_cscs_t * p_cscs, ble_cscs_evt_t * p_evt);
|
||||
|
||||
/**@brief Cycling Speed and Cadence Service init structure. This contains all options and data
|
||||
* needed for initialization of the service. */
|
||||
typedef struct
|
||||
{
|
||||
ble_cscs_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Cycling Speed and Cadence Service. */
|
||||
security_req_t csc_meas_cccd_wr_sec; /**< Security requirement for writing cycling speed and cadence measurement characteristic CCCD. */
|
||||
security_req_t csc_feature_rd_sec; /**< Security requirement for reading cycling speed and cadence feature characteristic. */
|
||||
security_req_t csc_location_rd_sec; /**< Security requirement for reading cycling speed and cadence location characteristic. */
|
||||
security_req_t sc_ctrlpt_cccd_wr_sec; /**< Security requirement for writing speed and cadence control point characteristic CCCD. */
|
||||
security_req_t sc_ctrlpt_wr_sec; /**< Security requirement for writing speed and cadence control point characteristic. */
|
||||
uint16_t feature; /**< Initial value for features of sensor @ref BLE_CSCS_FEATURES. */
|
||||
uint8_t ctrplt_supported_functions; /**< Supported control point functionalities see @ref BLE_SRV_SC_CTRLPT_SUPP_FUNC. */
|
||||
ble_sc_ctrlpt_evt_handler_t ctrlpt_evt_handler; /**< Event handler */
|
||||
ble_sensor_location_t *list_supported_locations; /**< List of supported sensor locations.*/
|
||||
uint8_t size_list_supported_locations; /**< Number of supported sensor locations in the list.*/
|
||||
ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
|
||||
ble_sensor_location_t *sensor_location; /**< Initial Sensor Location, if NULL, sensor_location characteristic is not added*/
|
||||
} ble_cscs_init_t;
|
||||
|
||||
/**@brief Cycling Speed and Cadence Service structure. This contains various status information for
|
||||
* the service. */
|
||||
struct ble_cscs_s
|
||||
{
|
||||
ble_cscs_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Cycling Speed and Cadence Service. */
|
||||
uint16_t service_handle; /**< Handle of Cycling Speed and Cadence Service (as provided by the BLE stack). */
|
||||
ble_gatts_char_handles_t meas_handles; /**< Handles related to the Cycling Speed and Cadence Measurement characteristic. */
|
||||
ble_gatts_char_handles_t feature_handles; /**< Handles related to the Cycling Speed and Cadence feature characteristic. */
|
||||
ble_gatts_char_handles_t sensor_loc_handles; /**< Handles related to the Cycling Speed and Cadence Sensor Location characteristic. */
|
||||
uint16_t conn_handle; /**< Handle of the current connection (as provided by the BLE stack, is BLE_CONN_HANDLE_INVALID if not in a connection). */
|
||||
uint16_t feature; /**< Bit mask of features available on sensor. */
|
||||
ble_sc_ctrlpt_t ctrl_pt; /**< data for speed and cadence control point */
|
||||
};
|
||||
|
||||
/**@brief Cycling Speed and Cadence Service measurement structure. This contains a Cycling Speed and
|
||||
* Cadence Service measurement. */
|
||||
typedef struct ble_cscs_meas_s
|
||||
{
|
||||
bool is_wheel_rev_data_present; /**< True if Wheel Revolution Data is present in the measurement. */
|
||||
bool is_crank_rev_data_present; /**< True if Crank Revolution Data is present in the measurement. */
|
||||
uint32_t cumulative_wheel_revs; /**< Cumulative Wheel Revolutions. */
|
||||
uint16_t last_wheel_event_time; /**< Last Wheel Event Time. */
|
||||
uint16_t cumulative_crank_revs; /**< Cumulative Crank Revolutions. */
|
||||
uint16_t last_crank_event_time; /**< Last Crank Event Time. */
|
||||
} ble_cscs_meas_t;
|
||||
|
||||
|
||||
/**@brief Function for initializing the Cycling Speed and Cadence Service.
|
||||
*
|
||||
* @param[out] p_cscs Cycling Speed and Cadence Service structure. This structure will have to
|
||||
* be supplied by the application. It will be initialized by this function,
|
||||
* and will later be used to identify this particular service instance.
|
||||
* @param[in] p_cscs_init Information needed to initialize the service.
|
||||
*
|
||||
* @return NRF_SUCCESS on successful initialization of service, otherwise an error code.
|
||||
*/
|
||||
uint32_t ble_cscs_init(ble_cscs_t * p_cscs, ble_cscs_init_t const * p_cscs_init);
|
||||
|
||||
|
||||
/**@brief Function for handling the Application's BLE Stack events.
|
||||
*
|
||||
* @details Handles all events from the BLE stack of interest to the Cycling Speed and Cadence
|
||||
* Service.
|
||||
*
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
* @param[in] p_context Cycling Speed and Cadence Service structure.
|
||||
*/
|
||||
void ble_cscs_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
|
||||
|
||||
|
||||
/**@brief Function for sending cycling speed and cadence measurement if notification has been enabled.
|
||||
*
|
||||
* @details The application calls this function after having performed a Cycling Speed and Cadence
|
||||
* Service measurement. If notification has been enabled, the measurement data is encoded
|
||||
* and sent to the client.
|
||||
*
|
||||
* @param[in] p_cscs Cycling Speed and Cadence Service structure.
|
||||
* @param[in] p_measurement Pointer to new cycling speed and cadence measurement.
|
||||
*
|
||||
* @return NRF_SUCCESS on success, otherwise an error code.
|
||||
*/
|
||||
uint32_t ble_cscs_measurement_send(ble_cscs_t * p_cscs, ble_cscs_meas_t * p_measurement);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // BLE_CSCS_H__
|
||||
|
||||
/** @} */
|
||||
656
components/ble/ble_services/ble_cscs/ble_sc_ctrlpt.c
Normal file
656
components/ble/ble_services/ble_cscs/ble_sc_ctrlpt.c
Normal file
@@ -0,0 +1,656 @@
|
||||
/**
|
||||
* Copyright (c) 2013 - 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.
|
||||
*
|
||||
*/
|
||||
/* Attention!
|
||||
* To maintain compliance with Nordic Semiconductor ASA's Bluetooth profile
|
||||
* qualification listings, this section of source code must not be modified.
|
||||
*/
|
||||
|
||||
#include "ble_sc_ctrlpt.h"
|
||||
#include <string.h>
|
||||
#include "nordic_common.h"
|
||||
#include "ble.h"
|
||||
#include "ble_err.h"
|
||||
#include "ble_srv_common.h"
|
||||
#include "app_util.h"
|
||||
|
||||
#define SC_CTRLPT_NACK_PROC_ALREADY_IN_PROGRESS (BLE_GATT_STATUS_ATTERR_APP_BEGIN + 0)
|
||||
#define SC_CTRLPT_NACK_CCCD_IMPROPERLY_CONFIGURED (BLE_GATT_STATUS_ATTERR_APP_BEGIN + 1)
|
||||
|
||||
uint32_t ble_sc_ctrlpt_init(ble_sc_ctrlpt_t * p_sc_ctrlpt,
|
||||
const ble_cs_ctrlpt_init_t * p_sc_ctrlpt_init)
|
||||
{
|
||||
if (p_sc_ctrlpt == NULL || p_sc_ctrlpt_init == NULL)
|
||||
{
|
||||
return NRF_ERROR_NULL;
|
||||
}
|
||||
|
||||
ble_add_char_params_t add_char_params;
|
||||
|
||||
p_sc_ctrlpt->conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
p_sc_ctrlpt->procedure_status = BLE_SCPT_NO_PROC_IN_PROGRESS;
|
||||
|
||||
p_sc_ctrlpt->size_list_supported_locations = p_sc_ctrlpt_init->size_list_supported_locations;
|
||||
|
||||
if ((p_sc_ctrlpt_init->size_list_supported_locations != 0) &&
|
||||
(p_sc_ctrlpt_init->list_supported_locations != NULL))
|
||||
{
|
||||
memcpy(p_sc_ctrlpt->list_supported_locations,
|
||||
p_sc_ctrlpt_init->list_supported_locations,
|
||||
p_sc_ctrlpt->size_list_supported_locations * sizeof(ble_sensor_location_t));
|
||||
}
|
||||
|
||||
p_sc_ctrlpt->service_handle = p_sc_ctrlpt_init->service_handle;
|
||||
p_sc_ctrlpt->evt_handler = p_sc_ctrlpt_init->evt_handler;
|
||||
p_sc_ctrlpt->supported_functions = p_sc_ctrlpt_init->supported_functions;
|
||||
p_sc_ctrlpt->sensor_location_handle = p_sc_ctrlpt_init->sensor_location_handle;
|
||||
p_sc_ctrlpt->error_handler = p_sc_ctrlpt_init->error_handler;
|
||||
|
||||
// Add speed and cadence control point characteristic
|
||||
memset(&add_char_params, 0, sizeof(add_char_params));
|
||||
add_char_params.uuid = BLE_UUID_SC_CTRLPT_CHAR;
|
||||
add_char_params.max_len = BLE_SC_CTRLPT_MAX_LEN;
|
||||
add_char_params.is_var_len = true;
|
||||
add_char_params.char_props.indicate = 1;
|
||||
add_char_params.char_props.write = 1;
|
||||
add_char_params.cccd_write_access = p_sc_ctrlpt_init->sc_ctrlpt_cccd_wr_sec;
|
||||
add_char_params.write_access = p_sc_ctrlpt_init->sc_ctrlpt_wr_sec;
|
||||
add_char_params.is_defered_write = true;
|
||||
|
||||
return characteristic_add(p_sc_ctrlpt->service_handle,
|
||||
&add_char_params,
|
||||
&p_sc_ctrlpt->sc_ctrlpt_handles);
|
||||
}
|
||||
|
||||
|
||||
/**@brief Decode an incoming control point write.
|
||||
*
|
||||
* @param[in] rcvd_val received write value
|
||||
* @param[in] len value length
|
||||
* @param[out] decoded_ctrlpt decoded control point structure
|
||||
*/
|
||||
static uint32_t sc_ctrlpt_decode(uint8_t const * p_rcvd_val,
|
||||
uint8_t len,
|
||||
ble_sc_ctrlpt_val_t * p_write_val)
|
||||
{
|
||||
int pos = 0;
|
||||
|
||||
if (len < BLE_SC_CTRLPT_MIN_LEN)
|
||||
{
|
||||
return NRF_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
p_write_val->opcode = (ble_scpt_operator_t) p_rcvd_val[pos++];
|
||||
|
||||
switch (p_write_val->opcode)
|
||||
{
|
||||
case BLE_SCPT_REQUEST_SUPPORTED_SENSOR_LOCATIONS:
|
||||
break;
|
||||
|
||||
case BLE_SCPT_START_AUTOMATIC_CALIBRATION:
|
||||
break;
|
||||
|
||||
case BLE_SCPT_UPDATE_SENSOR_LOCATION:
|
||||
p_write_val->location = (ble_sensor_location_t)p_rcvd_val[pos];
|
||||
break;
|
||||
|
||||
case BLE_SCPT_SET_CUMULATIVE_VALUE:
|
||||
p_write_val->cumulative_value = uint32_decode(&(p_rcvd_val[pos]));
|
||||
break;
|
||||
|
||||
default:
|
||||
return NRF_ERROR_INVALID_PARAM;
|
||||
}
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**@brief encode a control point response indication.
|
||||
*
|
||||
* @param[in] p_sc_ctrlpt SC Ctrlpt structure.
|
||||
* @param[in] p_ctrlpt_rsp structure containing response data to be encoded
|
||||
* @param[out] p_data pointer where data needs to be written
|
||||
* @return size of encoded data
|
||||
*/
|
||||
static int ctrlpt_rsp_encode(ble_sc_ctrlpt_t * p_sc_ctrlpt,
|
||||
ble_sc_ctrlpt_rsp_t * p_ctrlpt_rsp,
|
||||
uint8_t * p_data)
|
||||
{
|
||||
int len = 0;
|
||||
|
||||
p_data[len++] = BLE_SCPT_RESPONSE_CODE;
|
||||
p_data[len++] = p_ctrlpt_rsp->opcode;
|
||||
p_data[len++] = p_ctrlpt_rsp->status;
|
||||
|
||||
if (p_ctrlpt_rsp->status == BLE_SCPT_SUCCESS)
|
||||
{
|
||||
switch (p_ctrlpt_rsp->opcode)
|
||||
{
|
||||
case BLE_SCPT_REQUEST_SUPPORTED_SENSOR_LOCATIONS:
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < p_sc_ctrlpt->size_list_supported_locations; i++)
|
||||
{
|
||||
p_data[len++] = p_sc_ctrlpt->list_supported_locations[i];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
// No implementation needed.
|
||||
break;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
/**@brief check if a given sensor location is supported or not.
|
||||
*
|
||||
* @param[in] p_sc_ctrlpt SC Ctrlpt structure.
|
||||
* @param[in] location sensor location to check.
|
||||
* @return true if the given location is found in the list of supported locations, false otherwise.
|
||||
*/
|
||||
static bool is_location_supported(ble_sc_ctrlpt_t * p_sc_ctrlpt, ble_sensor_location_t location)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < p_sc_ctrlpt->size_list_supported_locations; i++)
|
||||
{
|
||||
if (p_sc_ctrlpt->list_supported_locations[i] == location)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**@brief check if the cccd is configured
|
||||
*
|
||||
* @param[in] p_sc_ctrlpt SC Ctrlpt structure.
|
||||
* @return true if the sc_control point's cccd is correctly configured, false otherwise.
|
||||
*/
|
||||
static bool is_cccd_configured(ble_sc_ctrlpt_t * p_sc_ctrlpt)
|
||||
{
|
||||
uint32_t err_code;
|
||||
uint8_t cccd_value_buf[BLE_CCCD_VALUE_LEN];
|
||||
bool is_sccp_indic_enabled = false;
|
||||
ble_gatts_value_t gatts_value;
|
||||
|
||||
// Initialize value struct.
|
||||
memset(&gatts_value, 0, sizeof(gatts_value));
|
||||
|
||||
gatts_value.len = BLE_CCCD_VALUE_LEN;
|
||||
gatts_value.offset = 0;
|
||||
gatts_value.p_value = cccd_value_buf;
|
||||
|
||||
err_code = sd_ble_gatts_value_get(p_sc_ctrlpt->conn_handle,
|
||||
p_sc_ctrlpt->sc_ctrlpt_handles.cccd_handle,
|
||||
&gatts_value);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
// Report error to application
|
||||
if (p_sc_ctrlpt->error_handler != NULL)
|
||||
{
|
||||
p_sc_ctrlpt->error_handler(err_code);
|
||||
}
|
||||
}
|
||||
|
||||
is_sccp_indic_enabled = ble_srv_is_indication_enabled(cccd_value_buf);
|
||||
|
||||
return is_sccp_indic_enabled;
|
||||
}
|
||||
|
||||
|
||||
/**@brief sends a control point indication.
|
||||
*
|
||||
* @param[in] p_sc_ctrlpt SC Ctrlpt structure.
|
||||
*/
|
||||
static void sc_ctrlpt_resp_send(ble_sc_ctrlpt_t * p_sc_ctrlpt)
|
||||
{
|
||||
uint16_t hvx_len;
|
||||
ble_gatts_hvx_params_t hvx_params;
|
||||
uint32_t err_code;
|
||||
|
||||
if (p_sc_ctrlpt->procedure_status == BLE_SCPT_INDICATION_PENDING)
|
||||
{
|
||||
hvx_len = p_sc_ctrlpt->response.len;
|
||||
memset(&hvx_params, 0, sizeof(hvx_params));
|
||||
|
||||
hvx_params.handle = p_sc_ctrlpt->sc_ctrlpt_handles.value_handle;
|
||||
hvx_params.type = BLE_GATT_HVX_INDICATION;
|
||||
hvx_params.offset = 0;
|
||||
hvx_params.p_len = &hvx_len;
|
||||
hvx_params.p_data = p_sc_ctrlpt->response.encoded_ctrl_rsp;
|
||||
|
||||
err_code = sd_ble_gatts_hvx(p_sc_ctrlpt->conn_handle, &hvx_params);
|
||||
|
||||
// Error handling
|
||||
if ((err_code == NRF_SUCCESS) && (hvx_len != p_sc_ctrlpt->response.len))
|
||||
{
|
||||
err_code = NRF_ERROR_DATA_SIZE;
|
||||
}
|
||||
|
||||
switch (err_code)
|
||||
{
|
||||
case NRF_SUCCESS:
|
||||
p_sc_ctrlpt->procedure_status = BLE_SCPT_IND_CONFIRM_PENDING;
|
||||
// Wait for HVC event
|
||||
break;
|
||||
|
||||
case NRF_ERROR_RESOURCES:
|
||||
// Wait for TX_COMPLETE event to retry transmission.
|
||||
p_sc_ctrlpt->procedure_status = BLE_SCPT_INDICATION_PENDING;
|
||||
break;
|
||||
|
||||
default:
|
||||
// Report error to application.
|
||||
p_sc_ctrlpt->procedure_status = BLE_SCPT_NO_PROC_IN_PROGRESS;
|
||||
if (p_sc_ctrlpt->error_handler != NULL)
|
||||
{
|
||||
p_sc_ctrlpt->error_handler(err_code);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Handle a write event to the Speed and Cadence Control Point.
|
||||
*
|
||||
* @param[in] p_sc_ctrlpt SC Ctrlpt structure.
|
||||
* @param[in] p_evt_write WRITE event to be handled.
|
||||
*/
|
||||
static void on_ctrlpt_write(ble_sc_ctrlpt_t * p_sc_ctrlpt,
|
||||
ble_gatts_evt_write_t const * p_evt_write)
|
||||
{
|
||||
ble_sc_ctrlpt_val_t rcvd_ctrlpt =
|
||||
{ BLE_SCPT_RESPONSE_CODE , 0, BLE_SENSOR_LOCATION_OTHER };
|
||||
|
||||
ble_sc_ctrlpt_rsp_t rsp;
|
||||
uint32_t err_code;
|
||||
ble_gatts_rw_authorize_reply_params_t auth_reply;
|
||||
ble_sc_ctrlpt_evt_t evt;
|
||||
|
||||
auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE;
|
||||
auth_reply.params.write.offset = 0;
|
||||
auth_reply.params.write.len = 0;
|
||||
auth_reply.params.write.p_data = NULL;
|
||||
auth_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
|
||||
auth_reply.params.write.update = 1;
|
||||
|
||||
if (is_cccd_configured(p_sc_ctrlpt))
|
||||
{
|
||||
if (p_sc_ctrlpt->procedure_status == BLE_SCPT_NO_PROC_IN_PROGRESS)
|
||||
{
|
||||
auth_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
auth_reply.params.write.gatt_status = SC_CTRLPT_NACK_PROC_ALREADY_IN_PROGRESS;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auth_reply.params.write.gatt_status = SC_CTRLPT_NACK_CCCD_IMPROPERLY_CONFIGURED;
|
||||
}
|
||||
|
||||
err_code = sd_ble_gatts_rw_authorize_reply(p_sc_ctrlpt->conn_handle, &auth_reply);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
// Report error to application.
|
||||
if (p_sc_ctrlpt->error_handler != NULL)
|
||||
{
|
||||
p_sc_ctrlpt->error_handler(err_code);
|
||||
}
|
||||
}
|
||||
|
||||
if (auth_reply.params.write.gatt_status != BLE_GATT_STATUS_SUCCESS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
p_sc_ctrlpt->procedure_status = BLE_SCPT_INDICATION_PENDING;
|
||||
rsp.status = BLE_SCPT_OP_CODE_NOT_SUPPORTED;
|
||||
|
||||
err_code = sc_ctrlpt_decode(p_evt_write->data, p_evt_write->len, &rcvd_ctrlpt);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
rsp.opcode = rcvd_ctrlpt.opcode;
|
||||
rsp.status = BLE_SCPT_OP_CODE_NOT_SUPPORTED;
|
||||
}
|
||||
else
|
||||
{
|
||||
rsp.opcode = rcvd_ctrlpt.opcode;
|
||||
|
||||
switch (rcvd_ctrlpt.opcode)
|
||||
{
|
||||
case BLE_SCPT_REQUEST_SUPPORTED_SENSOR_LOCATIONS:
|
||||
if ((p_sc_ctrlpt->supported_functions &
|
||||
BLE_SRV_SC_CTRLPT_SENSOR_LOCATIONS_OP_SUPPORTED) ==
|
||||
BLE_SRV_SC_CTRLPT_SENSOR_LOCATIONS_OP_SUPPORTED)
|
||||
{
|
||||
rsp.status = BLE_SCPT_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
rsp.status = BLE_SCPT_OP_CODE_NOT_SUPPORTED;
|
||||
}
|
||||
break;
|
||||
|
||||
case BLE_SCPT_UPDATE_SENSOR_LOCATION:
|
||||
if ((p_sc_ctrlpt->supported_functions &
|
||||
BLE_SRV_SC_CTRLPT_SENSOR_LOCATIONS_OP_SUPPORTED) ==
|
||||
BLE_SRV_SC_CTRLPT_SENSOR_LOCATIONS_OP_SUPPORTED)
|
||||
{
|
||||
if (is_location_supported(p_sc_ctrlpt, rcvd_ctrlpt.location))
|
||||
{
|
||||
ble_gatts_value_t gatts_value;
|
||||
uint8_t rcvd_location = (uint8_t)rcvd_ctrlpt.location;
|
||||
rsp.status = BLE_SCPT_SUCCESS;
|
||||
|
||||
// Initialize value struct.
|
||||
memset(&gatts_value, 0, sizeof(gatts_value));
|
||||
|
||||
gatts_value.len = sizeof(uint8_t);
|
||||
gatts_value.offset = 0;
|
||||
gatts_value.p_value = &rcvd_location;
|
||||
|
||||
evt.evt_type = BLE_SC_CTRLPT_EVT_UPDATE_LOCATION;
|
||||
evt.params.update_location = rcvd_ctrlpt.location;
|
||||
if (p_sc_ctrlpt->evt_handler != NULL)
|
||||
{
|
||||
rsp.status = p_sc_ctrlpt->evt_handler(p_sc_ctrlpt, &evt);
|
||||
}
|
||||
if (rsp.status == BLE_SCPT_SUCCESS)
|
||||
{
|
||||
err_code = sd_ble_gatts_value_set(p_sc_ctrlpt->conn_handle,
|
||||
p_sc_ctrlpt->sensor_location_handle,
|
||||
&gatts_value);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
// Report error to application
|
||||
if (p_sc_ctrlpt->error_handler != NULL)
|
||||
{
|
||||
p_sc_ctrlpt->error_handler(err_code);
|
||||
}
|
||||
rsp.status = BLE_SCPT_OPERATION_FAILED;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rsp.status = BLE_SCPT_INVALID_PARAMETER;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rsp.status = BLE_SCPT_OP_CODE_NOT_SUPPORTED;
|
||||
}
|
||||
break;
|
||||
|
||||
case BLE_SCPT_SET_CUMULATIVE_VALUE:
|
||||
if ((p_sc_ctrlpt->supported_functions &
|
||||
BLE_SRV_SC_CTRLPT_CUM_VAL_OP_SUPPORTED) ==
|
||||
BLE_SRV_SC_CTRLPT_CUM_VAL_OP_SUPPORTED)
|
||||
{
|
||||
rsp.status = BLE_SCPT_SUCCESS;
|
||||
|
||||
evt.evt_type = BLE_SC_CTRLPT_EVT_SET_CUMUL_VALUE;
|
||||
evt.params.cumulative_value = rcvd_ctrlpt.cumulative_value;
|
||||
if (p_sc_ctrlpt->evt_handler != NULL)
|
||||
{
|
||||
rsp.status = p_sc_ctrlpt->evt_handler(p_sc_ctrlpt, &evt);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rsp.status = BLE_SCPT_OP_CODE_NOT_SUPPORTED;
|
||||
}
|
||||
break;
|
||||
|
||||
case BLE_SCPT_START_AUTOMATIC_CALIBRATION:
|
||||
if ((p_sc_ctrlpt->supported_functions &
|
||||
BLE_SRV_SC_CTRLPT_START_CALIB_OP_SUPPORTED) ==
|
||||
BLE_SRV_SC_CTRLPT_START_CALIB_OP_SUPPORTED)
|
||||
{
|
||||
p_sc_ctrlpt->procedure_status = BLE_SCPT_AUTOMATIC_CALIB_IN_PROGRESS;
|
||||
evt.evt_type = BLE_SC_CTRLPT_EVT_START_CALIBRATION;
|
||||
if (p_sc_ctrlpt->evt_handler != NULL)
|
||||
{
|
||||
rsp.status = p_sc_ctrlpt->evt_handler(p_sc_ctrlpt, &evt);
|
||||
if (rsp.status != BLE_SCPT_SUCCESS)
|
||||
{
|
||||
// If the application returns an error, the response is to be sent
|
||||
// right away and the calibration is considered as not started.
|
||||
p_sc_ctrlpt->procedure_status = BLE_SCPT_INDICATION_PENDING;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rsp.status = BLE_SCPT_OP_CODE_NOT_SUPPORTED;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
rsp.status = BLE_SCPT_OP_CODE_NOT_SUPPORTED;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
p_sc_ctrlpt->response.len = ctrlpt_rsp_encode(p_sc_ctrlpt, &rsp,
|
||||
p_sc_ctrlpt->response.encoded_ctrl_rsp);
|
||||
|
||||
|
||||
if (p_sc_ctrlpt->procedure_status == BLE_SCPT_INDICATION_PENDING)
|
||||
{
|
||||
sc_ctrlpt_resp_send(p_sc_ctrlpt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Authorize WRITE request event handler.
|
||||
*
|
||||
* @details Handles WRITE events from the BLE stack.
|
||||
*
|
||||
* @param[in] p_sc_ctrlpt SC Ctrlpt structure.
|
||||
* @param[in] p_gatts_evt GATTS Event received from the BLE stack.
|
||||
*
|
||||
*/
|
||||
static void on_rw_authorize_request(ble_sc_ctrlpt_t * p_sc_ctrlpt,
|
||||
ble_gatts_evt_t const * p_gatts_evt)
|
||||
{
|
||||
ble_gatts_evt_rw_authorize_request_t const * p_auth_req =
|
||||
&p_gatts_evt->params.authorize_request;
|
||||
|
||||
if (p_auth_req->type == BLE_GATTS_AUTHORIZE_TYPE_WRITE)
|
||||
{
|
||||
if ( (p_gatts_evt->params.authorize_request.request.write.op
|
||||
!= BLE_GATTS_OP_PREP_WRITE_REQ)
|
||||
&& (p_gatts_evt->params.authorize_request.request.write.op
|
||||
!= BLE_GATTS_OP_EXEC_WRITE_REQ_NOW)
|
||||
&& (p_gatts_evt->params.authorize_request.request.write.op
|
||||
!= BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL)
|
||||
)
|
||||
{
|
||||
if (p_auth_req->request.write.handle == p_sc_ctrlpt->sc_ctrlpt_handles.value_handle)
|
||||
{
|
||||
on_ctrlpt_write(p_sc_ctrlpt, &p_auth_req->request.write);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Tx Complete event handler.
|
||||
*
|
||||
* @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_sc_ctrlpt SC Ctrlpt structure.
|
||||
*
|
||||
*/
|
||||
static void on_tx_complete(ble_sc_ctrlpt_t * p_sc_ctrlpt)
|
||||
{
|
||||
if (p_sc_ctrlpt->procedure_status == BLE_SCPT_INDICATION_PENDING)
|
||||
{
|
||||
sc_ctrlpt_resp_send(p_sc_ctrlpt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling the Connect event.
|
||||
*
|
||||
* @param[in] p_sc_ctrlpt SC Ctrlpt structure.
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
*/
|
||||
static void on_connect(ble_sc_ctrlpt_t * p_sc_ctrlpt, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
p_sc_ctrlpt->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
|
||||
p_sc_ctrlpt->procedure_status = BLE_SCPT_NO_PROC_IN_PROGRESS;
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling the Disconnect event.
|
||||
*
|
||||
* @param[in] p_sc_ctrlpt SC Ctrlpt structure.
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
*/
|
||||
static void on_disconnect(ble_sc_ctrlpt_t * p_sc_ctrlpt, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
UNUSED_PARAMETER(p_ble_evt);
|
||||
p_sc_ctrlpt->conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
p_sc_ctrlpt->procedure_status = BLE_SCPT_NO_PROC_IN_PROGRESS;
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling the BLE_GATTS_EVT_HVC event.
|
||||
*
|
||||
* @param[in] p_sc_ctrlpt SC Ctrlpt structure.
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
*/
|
||||
static void on_sc_hvc_confirm(ble_sc_ctrlpt_t * p_sc_ctrlpt, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
if (p_ble_evt->evt.gatts_evt.params.hvc.handle == p_sc_ctrlpt->sc_ctrlpt_handles.value_handle)
|
||||
{
|
||||
if (p_sc_ctrlpt->procedure_status == BLE_SCPT_IND_CONFIRM_PENDING)
|
||||
{
|
||||
p_sc_ctrlpt->procedure_status = BLE_SCPT_NO_PROC_IN_PROGRESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ble_sc_ctrlpt_on_ble_evt(ble_sc_ctrlpt_t * p_sc_ctrlpt, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
if (p_sc_ctrlpt == NULL || p_ble_evt == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch (p_ble_evt->header.evt_id)
|
||||
{
|
||||
case BLE_GAP_EVT_CONNECTED:
|
||||
on_connect(p_sc_ctrlpt, p_ble_evt);
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVT_DISCONNECTED:
|
||||
on_disconnect(p_sc_ctrlpt, p_ble_evt);
|
||||
break;
|
||||
|
||||
case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST:
|
||||
on_rw_authorize_request(p_sc_ctrlpt, &p_ble_evt->evt.gatts_evt);
|
||||
break;
|
||||
|
||||
case BLE_GATTS_EVT_HVC:
|
||||
on_sc_hvc_confirm(p_sc_ctrlpt, p_ble_evt);
|
||||
break;
|
||||
|
||||
case BLE_GATTS_EVT_HVN_TX_COMPLETE:
|
||||
on_tx_complete(p_sc_ctrlpt);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_sc_ctrlpt_rsp_send(ble_sc_ctrlpt_t * p_sc_ctrlpt, ble_scpt_response_t response_status)
|
||||
{
|
||||
if (p_sc_ctrlpt == NULL)
|
||||
{
|
||||
return NRF_ERROR_NULL;
|
||||
}
|
||||
|
||||
uint32_t err_code = NRF_SUCCESS;
|
||||
ble_sc_ctrlpt_rsp_t rsp;
|
||||
uint8_t encoded_ctrl_rsp[BLE_SC_CTRLPT_MAX_LEN];
|
||||
uint16_t hvx_len;
|
||||
ble_gatts_hvx_params_t hvx_params;
|
||||
|
||||
if (p_sc_ctrlpt->procedure_status != BLE_SCPT_AUTOMATIC_CALIB_IN_PROGRESS)
|
||||
{
|
||||
return NRF_ERROR_INVALID_STATE;
|
||||
}
|
||||
rsp.status = response_status;
|
||||
rsp.opcode = BLE_SCPT_START_AUTOMATIC_CALIBRATION;
|
||||
hvx_len = ctrlpt_rsp_encode(p_sc_ctrlpt, &rsp, encoded_ctrl_rsp);
|
||||
|
||||
// Send indication
|
||||
memset(&hvx_params, 0, sizeof(hvx_params));
|
||||
|
||||
hvx_params.handle = p_sc_ctrlpt->sc_ctrlpt_handles.value_handle;
|
||||
hvx_params.type = BLE_GATT_HVX_INDICATION;
|
||||
hvx_params.offset = 0;
|
||||
hvx_params.p_len = &hvx_len;
|
||||
hvx_params.p_data = encoded_ctrl_rsp;
|
||||
|
||||
err_code = sd_ble_gatts_hvx(p_sc_ctrlpt->conn_handle, &hvx_params);
|
||||
|
||||
if (err_code == NRF_SUCCESS)
|
||||
{
|
||||
p_sc_ctrlpt->procedure_status = BLE_SCPT_NO_PROC_IN_PROGRESS;
|
||||
}
|
||||
return err_code;
|
||||
}
|
||||
248
components/ble/ble_services/ble_cscs/ble_sc_ctrlpt.h
Normal file
248
components/ble/ble_services/ble_cscs/ble_sc_ctrlpt.h
Normal file
@@ -0,0 +1,248 @@
|
||||
/**
|
||||
* Copyright (c) 2013 - 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 ble_sdk_srv_sc_ctrlpt Speed and Cadence Control Point
|
||||
* @{
|
||||
* @ingroup ble_sdk_srv
|
||||
* @brief Speed and Cadence Control Point module.
|
||||
*
|
||||
* @details This module implements the Speed and Cadence control point behavior. It is used
|
||||
* by the @ref ble_cscs module and the ble_sdk_srv_rsc module for control point
|
||||
* mechanisms like setting a cumulative value, Start an automatic calibration,
|
||||
* Update the sensor location or request the supported locations.
|
||||
*
|
||||
* @note Attention!
|
||||
* To maintain compliance with Nordic Semiconductor ASA Bluetooth profile
|
||||
* qualification listings, this section of source code must not be modified.
|
||||
*/
|
||||
|
||||
#ifndef BLE_SC_CTRLPT_H__
|
||||
#define BLE_SC_CTRLPT_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "ble.h"
|
||||
#include "ble_srv_common.h"
|
||||
#include "ble_sensor_location.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define BLE_SC_CTRLPT_MAX_LEN 19 /**< maximum lenght for Speed and cadence control point characteristic value. */
|
||||
#define BLE_SC_CTRLPT_MIN_LEN 1 /**< minimum length for Speed and cadence control point characteristic value. */
|
||||
|
||||
// Forward declaration of the ble_sc_ctrlpt_t type.
|
||||
typedef struct ble_sc_ctrlpt_s ble_sc_ctrlpt_t;
|
||||
|
||||
|
||||
/**@brief Speed and Cadence Control Point event type. */
|
||||
typedef enum
|
||||
{
|
||||
BLE_SC_CTRLPT_EVT_UPDATE_LOCATION, /**< rcvd update location opcode (the control point handles the change of location automatically, the event just informs the application in case it needs to adjust its algorithm). */
|
||||
BLE_SC_CTRLPT_EVT_SET_CUMUL_VALUE, /**< rcvd set cumulative value opcode, it is then up to the application to use the new cumulative value. */
|
||||
BLE_SC_CTRLPT_EVT_START_CALIBRATION, /**< rcvd start calibration opcode, the application needs, at the end ot the calibration to call ble_sc_ctrlpt_send_rsp. */
|
||||
} ble_sc_ctrlpt_evt_type_t;
|
||||
|
||||
|
||||
/**@brief Speed and Cadence Control point event. */
|
||||
typedef struct
|
||||
{
|
||||
ble_sc_ctrlpt_evt_type_t evt_type; /**< Type of event. */
|
||||
union
|
||||
{
|
||||
ble_sensor_location_t update_location;
|
||||
uint32_t cumulative_value;
|
||||
}params;
|
||||
} ble_sc_ctrlpt_evt_t;
|
||||
|
||||
|
||||
/** Speed and Cadence Control Point operator code (see RSC service specification)*/
|
||||
typedef enum {
|
||||
BLE_SCPT_SET_CUMULATIVE_VALUE = 0x01, /**< Operator to set a given cumulative value. */
|
||||
BLE_SCPT_START_AUTOMATIC_CALIBRATION = 0x02, /**< Operator to start automatic calibration. */
|
||||
BLE_SCPT_UPDATE_SENSOR_LOCATION = 0x03, /**< Operator to update the sensor location. */
|
||||
BLE_SCPT_REQUEST_SUPPORTED_SENSOR_LOCATIONS = 0x04, /**< Operator to request the supported sensor locations. */
|
||||
BLE_SCPT_RESPONSE_CODE = 0x10, /**< Response Code. */
|
||||
} ble_scpt_operator_t;
|
||||
|
||||
|
||||
/** Speed and Cadence Control Point response parameter (see RSC service specification)*/
|
||||
typedef enum {
|
||||
BLE_SCPT_SUCCESS = 0x01, /**< Sucess Response. */
|
||||
BLE_SCPT_OP_CODE_NOT_SUPPORTED = 0x02, /**< Error Response received opcode not supported. */
|
||||
BLE_SCPT_INVALID_PARAMETER = 0x03, /**< Error Response received parameter invalid. */
|
||||
BLE_SCPT_OPERATION_FAILED = 0x04, /**< Error Response operation failed. */
|
||||
} ble_scpt_response_t;
|
||||
|
||||
|
||||
/** Speed and Cadence Control Point procedure status (indicates is a procedure is in progress or not and which procedure is in progress*/
|
||||
typedef enum {
|
||||
BLE_SCPT_NO_PROC_IN_PROGRESS = 0x00, /**< No procedure in progress. */
|
||||
BLE_SCPT_AUTOMATIC_CALIB_IN_PROGRESS = 0x01, /**< Automatic Calibration is in progress. */
|
||||
BLE_SCPT_INDICATION_PENDING = 0x02, /**< Control Point Indication is pending. */
|
||||
BLE_SCPT_IND_CONFIRM_PENDING = 0x03, /**< Waiting for the indication confirmation. */
|
||||
}ble_scpt_procedure_status_t;
|
||||
|
||||
/**@brief Speed and Cadence Control point event handler type. */
|
||||
typedef ble_scpt_response_t (*ble_sc_ctrlpt_evt_handler_t) (ble_sc_ctrlpt_t * p_sc_ctrlpt,
|
||||
ble_sc_ctrlpt_evt_t * p_evt);
|
||||
|
||||
|
||||
typedef struct{
|
||||
ble_scpt_operator_t opcode;
|
||||
uint32_t cumulative_value;
|
||||
ble_sensor_location_t location;
|
||||
}ble_sc_ctrlpt_val_t;
|
||||
|
||||
|
||||
typedef struct{
|
||||
ble_scpt_operator_t opcode;
|
||||
ble_scpt_response_t status;
|
||||
ble_sensor_location_t location_list[BLE_NB_MAX_SENSOR_LOCATIONS];
|
||||
}ble_sc_ctrlpt_rsp_t;
|
||||
|
||||
|
||||
/**
|
||||
* \defgroup BLE_SRV_SC_CTRLPT_SUPP_FUNC Control point functionalities.
|
||||
*@{
|
||||
*/
|
||||
#define BLE_SRV_SC_CTRLPT_SENSOR_LOCATIONS_OP_SUPPORTED 0x01 /**< Support for sensor location related operations */
|
||||
#define BLE_SRV_SC_CTRLPT_CUM_VAL_OP_SUPPORTED 0x02 /**< Support for setting cumulative value related operations */
|
||||
#define BLE_SRV_SC_CTRLPT_START_CALIB_OP_SUPPORTED 0x04 /**< Support for starting calibration related operations */
|
||||
/**
|
||||
*@}
|
||||
*/
|
||||
|
||||
/**@brief Speed and Cadence Control Point init structure. This contains all options and data
|
||||
* needed for initialization of the Speed and Cadence Control Point module. */
|
||||
typedef struct
|
||||
{
|
||||
security_req_t sc_ctrlpt_cccd_wr_sec; /**< Security requirement for writing speed and cadence control point characteristic CCCD. */
|
||||
security_req_t sc_ctrlpt_wr_sec; /**< Security requirement for writing speed and cadence control point characteristic. */
|
||||
uint8_t supported_functions; /**< supported control point functionalities see @ref BLE_SRV_SC_CTRLPT_SUPP_FUNC. */
|
||||
uint16_t service_handle; /**< Handle of the parent service (as provided by the BLE stack). */
|
||||
ble_sc_ctrlpt_evt_handler_t evt_handler; /**< event handler */
|
||||
ble_sensor_location_t *list_supported_locations; /**< list of supported sensor locations.*/
|
||||
uint8_t size_list_supported_locations; /**< number of supported sensor locations in the list.*/
|
||||
uint16_t sensor_location_handle; /**< handle for the sensor location characteristic (if sensor_location related operation are supported).*/
|
||||
ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
|
||||
} ble_cs_ctrlpt_init_t;
|
||||
|
||||
|
||||
/**@brief Speed and Cadence Control Point response indication structure. */
|
||||
typedef struct
|
||||
{
|
||||
ble_scpt_response_t status; /**< control point response status .*/
|
||||
uint8_t len; /**< control point response length .*/
|
||||
uint8_t encoded_ctrl_rsp[BLE_SC_CTRLPT_MAX_LEN]; /**< control point encoded response.*/
|
||||
}ble_sc_ctrlpt_resp_t;
|
||||
|
||||
|
||||
/**@brief Speed and Cadence Control Point structure. This contains various status information for
|
||||
* the Speed and Cadence Control Point behavior. */
|
||||
struct ble_sc_ctrlpt_s
|
||||
{
|
||||
uint8_t supported_functions; /**< supported control point functionalities see @ref BLE_SRV_SC_CTRLPT_SUPP_FUNC. */
|
||||
uint16_t service_handle; /**< Handle of the parent service (as provided by the BLE stack). */
|
||||
ble_gatts_char_handles_t sc_ctrlpt_handles; /**< Handles related to the Speed and Cadence Control Point characteristic. */
|
||||
uint16_t conn_handle; /**< Handle of the current connection (as provided by the BLE stack, is BLE_CONN_HANDLE_INVALID if not in a connection). */
|
||||
ble_sensor_location_t list_supported_locations[BLE_NB_MAX_SENSOR_LOCATIONS]; /**< list of supported sensor locations.*/
|
||||
uint8_t size_list_supported_locations; /**< number of supported sensor locations in the list.*/
|
||||
ble_sc_ctrlpt_evt_handler_t evt_handler; /**< Handle of the parent service (as provided by the BLE stack). */
|
||||
uint16_t sensor_location_handle; /**< handle for the sensor location characteristic (if sensor_location related operation are supported).*/
|
||||
ble_scpt_procedure_status_t procedure_status; /**< status of possible procedure*/
|
||||
ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
|
||||
ble_sc_ctrlpt_resp_t response; /**< pending response data.*/
|
||||
};
|
||||
|
||||
#define SCPT_OPCODE_POS 0 /**< Request opcode position. */
|
||||
#define SCPT_PARAMETER_POS 1 /**< Request parameter position. */
|
||||
|
||||
#define SCPT_RESPONSE_REQUEST_OPCODE_POS 1 /**< Response position of requested opcode. */
|
||||
#define SCPT_RESPONSE_CODE_POS 2 /**< Response position of response code. */
|
||||
#define SCPT_RESPONSE_PARAMETER 3 /**< Response position of response parameter. */
|
||||
|
||||
#define SCPT_MIN_RESPONSE_SIZE 3 /**< Minimum size for control point response. */
|
||||
#define SCPT_MAX_RESPONSE_SIZE (SCPT_MIN_RESPONSE_SIZE + NB_MAX_SENSOR_LOCATIONS) /**< Maximum size for control point response. */
|
||||
|
||||
|
||||
/**@brief Function for Initializing the Speed and Cadence Control Point.
|
||||
*
|
||||
* @details Function for Initializing the Speed and Cadence Control Point.
|
||||
* @param[in] p_sc_ctrlpt Speed and Cadence Control Point structure.
|
||||
* @param[in] p_sc_ctrlpt_init Information needed to initialize the control point behavior.
|
||||
*
|
||||
* @return NRF_SUCCESS on successful initialization of service, otherwise an error code.
|
||||
*/
|
||||
uint32_t ble_sc_ctrlpt_init(ble_sc_ctrlpt_t * p_sc_ctrlpt,
|
||||
ble_cs_ctrlpt_init_t const * p_sc_ctrlpt_init);
|
||||
|
||||
|
||||
/**@brief Function for sending a control point response.
|
||||
*
|
||||
* @details Function for sending a control point response when the control point received was
|
||||
* BLE_SCPT_START_AUTOMATIC_CALIBRATION. To be called after the calibration procedure is finished.
|
||||
*
|
||||
* @param[in] p_sc_ctrlpt Speed and Cadence Control Point structure.
|
||||
* @param[in] response_status status to include in the control point response.
|
||||
*/
|
||||
uint32_t ble_sc_ctrlpt_rsp_send(ble_sc_ctrlpt_t * p_sc_ctrlpt, ble_scpt_response_t response_status);
|
||||
|
||||
|
||||
/**@brief Speed and Cadence Control Point BLE stack event handler.
|
||||
*
|
||||
* @details Handles all events from the BLE stack of interest to the Speed and Cadence Control Point.
|
||||
*
|
||||
* @param[in] p_sc_ctrlpt Speed and Cadence Control Point structure.
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
*/
|
||||
void ble_sc_ctrlpt_on_ble_evt(ble_sc_ctrlpt_t * p_sc_ctrlpt, ble_evt_t const * p_ble_evt);
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // BLE_SC_CTRLPT_H__
|
||||
|
||||
/** @} */
|
||||
399
components/ble/ble_services/ble_cts_c/ble_cts_c.c
Normal file
399
components/ble/ble_services/ble_cts_c/ble_cts_c.c
Normal file
@@ -0,0 +1,399 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 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_CTS_C)
|
||||
#include <string.h>
|
||||
#include "ble.h"
|
||||
#include "ble_srv_common.h"
|
||||
#include "ble_gattc.h"
|
||||
#include "ble_cts_c.h"
|
||||
#include "ble_date_time.h"
|
||||
#include "ble_db_discovery.h"
|
||||
#define NRF_LOG_MODULE_NAME ble_cts_c
|
||||
#include "nrf_log.h"
|
||||
NRF_LOG_MODULE_REGISTER();
|
||||
|
||||
#define CTS_YEAR_MIN 1582 /**< The lowest valid Current Time year is the year when the Western calendar was introduced. */
|
||||
#define CTS_YEAR_MAX 9999 /**< The highest possible Current Time year. */
|
||||
|
||||
#define CTS_C_CURRENT_TIME_EXPECTED_LENGTH 10 /**< | Year |Month |Day |Hours |Minutes |Seconds |Weekday |Fraction|Reason |
|
||||
| 2 bytes |1 byte |1 byte |1 byte |1 byte |1 byte |1 byte |1 byte |1 byte | = 10 bytes. */
|
||||
|
||||
|
||||
/**@brief Function for intercepting 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)
|
||||
{
|
||||
ble_cts_c_t * p_cts = (ble_cts_c_t *)p_ctx;
|
||||
|
||||
NRF_LOG_DEBUG("A GATT Client error has occurred on conn_handle: 0X%X", conn_handle);
|
||||
|
||||
if (p_cts->error_handler != NULL)
|
||||
{
|
||||
p_cts->error_handler(nrf_error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@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 Current Time Service at the peer. If it does, this function
|
||||
* calls the application's event handler to indicate that the Current Time Service was
|
||||
* discovered at the peer. The function also populates the event with service-related
|
||||
* information before providing it to the application.
|
||||
*
|
||||
* @param[in] p_evt Pointer to the event received from the Database Discovery module.
|
||||
*
|
||||
*/
|
||||
void ble_cts_c_on_db_disc_evt(ble_cts_c_t * p_cts, ble_db_discovery_evt_t * p_evt)
|
||||
{
|
||||
NRF_LOG_DEBUG("Database Discovery handler called with event 0x%x", p_evt->evt_type);
|
||||
|
||||
ble_cts_c_evt_t evt;
|
||||
const ble_gatt_db_char_t * p_chars = p_evt->params.discovered_db.charateristics;
|
||||
|
||||
evt.conn_handle = p_evt->conn_handle;
|
||||
|
||||
// Check if the Current Time Service was discovered.
|
||||
if ( (p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE)
|
||||
&& (p_evt->params.discovered_db.srv_uuid.uuid == BLE_UUID_CURRENT_TIME_SERVICE)
|
||||
&& (p_evt->params.discovered_db.srv_uuid.type == BLE_UUID_TYPE_BLE))
|
||||
{
|
||||
// Find the handles of the Current Time characteristic.
|
||||
for (uint32_t i = 0; i < p_evt->params.discovered_db.char_count; i++)
|
||||
{
|
||||
if (p_evt->params.discovered_db.charateristics[i].characteristic.uuid.uuid ==
|
||||
BLE_UUID_CURRENT_TIME_CHAR)
|
||||
{
|
||||
// Found Current Time characteristic. Store CCCD and value handle and break.
|
||||
evt.params.char_handles.cts_handle = p_chars->characteristic.handle_value;
|
||||
evt.params.char_handles.cts_cccd_handle = p_chars->cccd_handle;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
NRF_LOG_INFO("Current Time Service discovered at peer.");
|
||||
|
||||
evt.evt_type = BLE_CTS_C_EVT_DISCOVERY_COMPLETE;
|
||||
}
|
||||
else if ((p_evt->evt_type == BLE_DB_DISCOVERY_SRV_NOT_FOUND) ||
|
||||
(p_evt->evt_type == BLE_DB_DISCOVERY_ERROR))
|
||||
{
|
||||
evt.evt_type = BLE_CTS_C_EVT_DISCOVERY_FAILED;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
p_cts->evt_handler(p_cts, &evt);
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_cts_c_init(ble_cts_c_t * p_cts, ble_cts_c_init_t const * p_cts_init)
|
||||
{
|
||||
// Verify that the parameters needed to initialize this instance of CTS are not NULL.
|
||||
VERIFY_PARAM_NOT_NULL(p_cts);
|
||||
VERIFY_PARAM_NOT_NULL(p_cts_init);
|
||||
VERIFY_PARAM_NOT_NULL(p_cts_init->error_handler);
|
||||
VERIFY_PARAM_NOT_NULL(p_cts_init->evt_handler);
|
||||
VERIFY_PARAM_NOT_NULL(p_cts_init->p_gatt_queue);
|
||||
|
||||
static ble_uuid_t cts_uuid;
|
||||
|
||||
BLE_UUID_BLE_ASSIGN(cts_uuid, BLE_UUID_CURRENT_TIME_SERVICE);
|
||||
|
||||
p_cts->evt_handler = p_cts_init->evt_handler;
|
||||
p_cts->error_handler = p_cts_init->error_handler;
|
||||
p_cts->conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
p_cts->char_handles.cts_handle = BLE_GATT_HANDLE_INVALID;
|
||||
p_cts->char_handles.cts_cccd_handle = BLE_GATT_HANDLE_INVALID;
|
||||
p_cts->p_gatt_queue = p_cts_init->p_gatt_queue;
|
||||
|
||||
return ble_db_discovery_evt_register(&cts_uuid);
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for decoding a read from the Current Time characteristic.
|
||||
*
|
||||
* @param[in] p_time Current Time structure.
|
||||
* @param[in] p_data Pointer to the buffer containing the Current Time.
|
||||
* @param[in] length Length of the buffer containing the Current Time.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the time struct is valid.
|
||||
* @retval NRF_ERROR_DATA_SIZE If the length does not match the expected size of the data.
|
||||
*/
|
||||
static uint32_t current_time_decode(current_time_char_t * p_time,
|
||||
uint8_t const * p_data,
|
||||
uint32_t const length)
|
||||
{
|
||||
//lint -save -e415 -e416 "Access of out of bounds pointer" "Creation of out of bounds pointer"
|
||||
|
||||
if (length != CTS_C_CURRENT_TIME_EXPECTED_LENGTH)
|
||||
{
|
||||
// Return to prevent accessing the out-of-bounds data.
|
||||
return NRF_ERROR_DATA_SIZE;
|
||||
}
|
||||
|
||||
NRF_LOG_DEBUG("Current Time read response data:");
|
||||
NRF_LOG_HEXDUMP_DEBUG(p_data, 10);
|
||||
|
||||
uint32_t index = 0;
|
||||
|
||||
// Date.
|
||||
index += ble_date_time_decode(&p_time->exact_time_256.day_date_time.date_time, p_data);
|
||||
|
||||
// Day of week.
|
||||
p_time->exact_time_256.day_date_time.day_of_week = p_data[index++];
|
||||
|
||||
// Fractions of a second.
|
||||
p_time->exact_time_256.fractions256 = p_data[index++];
|
||||
|
||||
// Reason for updating the time.
|
||||
p_time->adjust_reason.manual_time_update = (p_data[index] >> 0) & 0x01;
|
||||
p_time->adjust_reason.external_reference_time_update = (p_data[index] >> 1) & 0x01;
|
||||
p_time->adjust_reason.change_of_time_zone = (p_data[index] >> 2) & 0x01;
|
||||
p_time->adjust_reason.change_of_daylight_savings_time = (p_data[index] >> 3) & 0x01;
|
||||
|
||||
//lint -restore
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for decoding a read from the Current Time characteristic.
|
||||
*
|
||||
* @param[in] p_time Current Time struct.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the time struct is valid.
|
||||
* @retval NRF_ERROR_INVALID_DATA If the time is out of bounds.
|
||||
*/
|
||||
static uint32_t current_time_validate(current_time_char_t * p_time)
|
||||
{
|
||||
// Year.
|
||||
if ( (p_time->exact_time_256.day_date_time.date_time.year > CTS_YEAR_MAX)
|
||||
|| ((p_time->exact_time_256.day_date_time.date_time.year < CTS_YEAR_MIN)
|
||||
&& (p_time->exact_time_256.day_date_time.date_time.year != 0)))
|
||||
{
|
||||
return NRF_ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
// Month.
|
||||
if (p_time->exact_time_256.day_date_time.date_time.month > 12)
|
||||
{
|
||||
return NRF_ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
// Day.
|
||||
if (p_time->exact_time_256.day_date_time.date_time.day > 31)
|
||||
{
|
||||
return NRF_ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
// Hours.
|
||||
if (p_time->exact_time_256.day_date_time.date_time.hours > 23)
|
||||
{
|
||||
return NRF_ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
// Minutes.
|
||||
if (p_time->exact_time_256.day_date_time.date_time.minutes > 59)
|
||||
{
|
||||
return NRF_ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
// Seconds.
|
||||
if (p_time->exact_time_256.day_date_time.date_time.seconds > 59)
|
||||
{
|
||||
return NRF_ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
// Day of week.
|
||||
if (p_time->exact_time_256.day_date_time.day_of_week > 7)
|
||||
{
|
||||
return NRF_ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for reading the Current Time. The time is decoded, and then validated.
|
||||
* Depending on the outcome, the CTS event handler will be called with
|
||||
* the Current Time event or an invalid time event.
|
||||
*
|
||||
* @param[in] p_cts Current Time Service client structure.
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
*/
|
||||
static void current_time_read(ble_cts_c_t * p_cts, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
ble_cts_c_evt_t evt;
|
||||
uint32_t err_code = NRF_SUCCESS;
|
||||
|
||||
// Check whether the event is on the same connection as this CTS instance
|
||||
if (p_cts->conn_handle != p_ble_evt->evt.gattc_evt.conn_handle)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (p_ble_evt->evt.gattc_evt.gatt_status == BLE_GATT_STATUS_SUCCESS)
|
||||
{
|
||||
err_code = current_time_decode(&evt.params.current_time,
|
||||
p_ble_evt->evt.gattc_evt.params.read_rsp.data,
|
||||
p_ble_evt->evt.gattc_evt.params.read_rsp.len);
|
||||
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
// The data length was invalid. Decoding was not completed.
|
||||
evt.evt_type = BLE_CTS_C_EVT_INVALID_TIME;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Verify that the time is valid.
|
||||
err_code = current_time_validate(&evt.params.current_time);
|
||||
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
// Invalid time received.
|
||||
evt.evt_type = BLE_CTS_C_EVT_INVALID_TIME;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Valid time reveiced.
|
||||
evt.evt_type = BLE_CTS_C_EVT_CURRENT_TIME;
|
||||
}
|
||||
}
|
||||
p_cts->evt_handler(p_cts, &evt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling the Disconnect event.
|
||||
*
|
||||
* @param[in] p_cts Current Time Service client structure.
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
*/
|
||||
static void on_disconnect(ble_cts_c_t * p_cts, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
if (p_cts->conn_handle == p_ble_evt->evt.gap_evt.conn_handle)
|
||||
{
|
||||
p_cts->conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
}
|
||||
|
||||
if (ble_cts_c_is_cts_discovered(p_cts))
|
||||
{
|
||||
// There was a valid instance of CTS on the peer. Send an event to the
|
||||
// application, so that it can do any clean up related to this module.
|
||||
ble_cts_c_evt_t evt;
|
||||
|
||||
evt.evt_type = BLE_CTS_C_EVT_DISCONN_COMPLETE;
|
||||
|
||||
p_cts->evt_handler(p_cts, &evt);
|
||||
p_cts->char_handles.cts_handle = BLE_GATT_HANDLE_INVALID;
|
||||
p_cts->char_handles.cts_cccd_handle = BLE_GATT_HANDLE_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ble_cts_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
|
||||
{
|
||||
ble_cts_c_t * p_cts = (ble_cts_c_t *)p_context;
|
||||
NRF_LOG_DEBUG("BLE event handler called with event 0x%x", p_ble_evt->header.evt_id);
|
||||
|
||||
switch (p_ble_evt->header.evt_id)
|
||||
{
|
||||
case BLE_GATTC_EVT_READ_RSP:
|
||||
current_time_read(p_cts, p_ble_evt);
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVT_DISCONNECTED:
|
||||
on_disconnect(p_cts, p_ble_evt);
|
||||
break;
|
||||
|
||||
default:
|
||||
// No implementation needed.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_cts_c_current_time_read(ble_cts_c_t const * p_cts)
|
||||
{
|
||||
if (!ble_cts_c_is_cts_discovered(p_cts))
|
||||
{
|
||||
return NRF_ERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
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 = gatt_error_handler;
|
||||
read_req.error_handler.p_ctx = (ble_cts_c_t *)p_cts;
|
||||
read_req.params.gattc_read.handle = p_cts->char_handles.cts_handle;
|
||||
read_req.params.gattc_read.offset = 0;
|
||||
|
||||
return nrf_ble_gq_item_add(p_cts->p_gatt_queue, &read_req, p_cts->conn_handle);
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_cts_c_handles_assign(ble_cts_c_t * p_cts,
|
||||
const uint16_t conn_handle,
|
||||
const ble_cts_c_handles_t * p_peer_handles)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_cts);
|
||||
|
||||
p_cts->conn_handle = conn_handle;
|
||||
if (p_peer_handles != NULL)
|
||||
{
|
||||
p_cts->char_handles.cts_cccd_handle = p_peer_handles->cts_cccd_handle;
|
||||
p_cts->char_handles.cts_handle = p_peer_handles->cts_handle;
|
||||
}
|
||||
|
||||
return nrf_ble_gq_conn_handle_register(p_cts->p_gatt_queue, conn_handle);
|
||||
}
|
||||
#endif // NRF_MODULE_ENABLED(BLE_CTS_C)
|
||||
291
components/ble/ble_services/ble_cts_c/ble_cts_c.h
Normal file
291
components/ble/ble_services/ble_cts_c/ble_cts_c.h
Normal file
@@ -0,0 +1,291 @@
|
||||
/**
|
||||
* Copyright (c) 2014 - 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 ble_cts_c Current Time Service Client
|
||||
* @{
|
||||
* @ingroup ble_sdk_srv
|
||||
* @brief Current Time Service Client module.
|
||||
*
|
||||
* @details This module implements the Current Time Service (CTS) client-peripheral role of
|
||||
* the Time Profile. After security is established, the module tries to discover the
|
||||
* Current Time Service and its characteristic on the central side. If this succeeds,
|
||||
* the application can trigger a read of the current time from the connected server.
|
||||
*
|
||||
* The module informs the application about the successful discovery with the
|
||||
* @ref BLE_CTS_C_EVT_DISCOVERY_COMPLETE event. The handles for the CTS server are now
|
||||
* available in the @ref ble_cts_c_evt_t structure. These handles must be assigned to an
|
||||
* instance of CTS_C with @ref ble_cts_c_handles_assign. For more information about the
|
||||
* service discovery, see the ble_discovery module documentation: @ref lib_ble_db_discovery.
|
||||
*
|
||||
* After assigning the handles to an instance of CTS_C, the application can use the function
|
||||
* @ref ble_cts_c_current_time_read to read the current time. If the read succeeds, it triggers either
|
||||
* a @ref BLE_CTS_C_EVT_CURRENT_TIME event or a @ref BLE_CTS_C_EVT_INVALID_TIME event
|
||||
* (depending whether the data that was read was actually a valid time). Then the read result is sent
|
||||
* to the application. The current time is then available in the params field of the
|
||||
* passed @ref ble_cts_c_evt_t structure.
|
||||
*
|
||||
* @note The application must register this module as the BLE event observer by using the
|
||||
* NRF_SDH_BLE_OBSERVER macro. Example:
|
||||
* @code
|
||||
* ble_cts_c_t instance;
|
||||
* NRF_SDH_BLE_OBSERVER(anything, BLE_CTS_C_BLE_OBSERVER_PRIO,
|
||||
* ble_cts_c_on_ble_evt, &instance);
|
||||
* @endcode
|
||||
*/
|
||||
|
||||
#ifndef BLE_CTS_C_H__
|
||||
#define BLE_CTS_C_H__
|
||||
|
||||
#include "ble_srv_common.h"
|
||||
#include "ble_gattc.h"
|
||||
#include "ble.h"
|
||||
#include "ble_date_time.h"
|
||||
#include "ble_db_discovery.h"
|
||||
#include "nrf_ble_gq.h"
|
||||
#include "nrf_sdh_ble.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**@brief Macro for defining a ble_bps instance.
|
||||
*
|
||||
* @param _name Name of the instance.
|
||||
* @hideinitializer
|
||||
*/
|
||||
#define BLE_CTS_C_DEF(_name) \
|
||||
static ble_cts_c_t _name; \
|
||||
NRF_SDH_BLE_OBSERVER(_name ## _obs, \
|
||||
BLE_CTS_C_BLE_OBSERVER_PRIO, \
|
||||
ble_cts_c_on_ble_evt, &_name)
|
||||
|
||||
/** @brief Macro for defining multiple ble_cts_c instances.
|
||||
*
|
||||
* @param _name Name of the array of instances.
|
||||
* @param _cnt Number of instances to define.
|
||||
* @hideinitializer
|
||||
*/
|
||||
#define BLE_CTS_C_ARRAY_DEF(_name, _cnt) \
|
||||
static ble_cts_c_t _name[_cnt]; \
|
||||
NRF_SDH_BLE_OBSERVERS(_name ## _obs, \
|
||||
BLE_CTS_C_BLE_OBSERVER_PRIO, \
|
||||
ble_cts_c_on_ble_evt, &_name, _cnt)
|
||||
|
||||
|
||||
/**@brief "Day Date Time" field of the "Exact Time 256" field of the Current Time characteristic. */
|
||||
typedef struct
|
||||
{
|
||||
ble_date_time_t date_time;
|
||||
uint8_t day_of_week;
|
||||
} day_date_time_t;
|
||||
|
||||
/**@brief "Exact Time 256" field of the Current Time characteristic. */
|
||||
typedef struct
|
||||
{
|
||||
day_date_time_t day_date_time;
|
||||
uint8_t fractions256;
|
||||
} exact_time_256_t;
|
||||
|
||||
/**@brief "Adjust Reason" field of the Current Time characteristic. */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t manual_time_update : 1;
|
||||
uint8_t external_reference_time_update : 1;
|
||||
uint8_t change_of_time_zone : 1;
|
||||
uint8_t change_of_daylight_savings_time : 1;
|
||||
} adjust_reason_t;
|
||||
|
||||
/**@brief Data structure for the Current Time characteristic. */
|
||||
typedef struct
|
||||
{
|
||||
exact_time_256_t exact_time_256;
|
||||
adjust_reason_t adjust_reason;
|
||||
} current_time_char_t;
|
||||
|
||||
// Forward declaration of the ble_cts_c_t type.
|
||||
typedef struct ble_cts_c_s ble_cts_c_t;
|
||||
|
||||
/**@brief Current Time Service client event type. */
|
||||
typedef enum
|
||||
{
|
||||
BLE_CTS_C_EVT_DISCOVERY_COMPLETE, /**< The Current Time Service was found at the peer. */
|
||||
BLE_CTS_C_EVT_DISCOVERY_FAILED, /**< The Current Time Service was not found at the peer. */
|
||||
BLE_CTS_C_EVT_DISCONN_COMPLETE, /**< Event indicating that the Current Time Service Client module finished processing the BLE_GAP_EVT_DISCONNECTED event. This event is triggered only if a valid instance of the Current Time Service was found at the server. The application can use this event to do a cleanup related to the Current Time Service client.*/
|
||||
BLE_CTS_C_EVT_CURRENT_TIME, /**< A new Current Time reading has been received. */
|
||||
BLE_CTS_C_EVT_INVALID_TIME /**< The Current Time value received from the peer is invalid.*/
|
||||
} ble_cts_c_evt_type_t;
|
||||
|
||||
/**@brief Structure containing the handles related to the Heart Rate Service found on the peer. */
|
||||
typedef struct
|
||||
{
|
||||
uint16_t cts_handle; /**< Handle of the Current Time characteristic, as provided by the SoftDevice. */
|
||||
uint16_t cts_cccd_handle; /**< Handle of the CCCD of the Current Time characteristic. */
|
||||
} ble_cts_c_handles_t;
|
||||
|
||||
/**@brief Current Time Service client event. */
|
||||
typedef struct
|
||||
{
|
||||
ble_cts_c_evt_type_t evt_type; /**< Type of event. */
|
||||
uint16_t conn_handle; /**< Connection handle on which the CTS service was discovered on the peer device. This is filled if the evt_type is @ref BLE_CTS_C_EVT_DISCOVERY_COMPLETE.*/
|
||||
union
|
||||
{
|
||||
current_time_char_t current_time; /**< Current Time characteristic data. This is filled when the evt_type is @ref BLE_CTS_C_EVT_CURRENT_TIME. */
|
||||
ble_cts_c_handles_t char_handles; /**< Handles related to Current Time, found on the peer device. This is filled when the evt_type is @ref BLE_HRS_C_EVT_DISCOVERY_COMPLETE.*/
|
||||
} params;
|
||||
} ble_cts_c_evt_t;
|
||||
|
||||
/**@brief Current Time Service client event handler type. */
|
||||
typedef void (* ble_cts_c_evt_handler_t) (ble_cts_c_t * p_cts, ble_cts_c_evt_t * p_evt);
|
||||
|
||||
|
||||
/**@brief Current Time Service client structure. This structure contains status information for the client. */
|
||||
struct ble_cts_c_s
|
||||
{
|
||||
ble_cts_c_evt_handler_t evt_handler; /**< Event handler to be called for handling events from the Current Time Service client. */
|
||||
ble_srv_error_handler_t error_handler; /**< Function to be called if an error occurs. */
|
||||
ble_cts_c_handles_t char_handles; /**< Handles of Current Time characteristic at the peer. (Handles are provided by the BLE stack through the Database Discovery module.) */
|
||||
uint16_t conn_handle; /**< Handle of the current connection. BLE_CONN_HANDLE_INVALID if not in a connection. */
|
||||
nrf_ble_gq_t * p_gatt_queue; /**< Pointer to the BLE GATT Queue instance. */
|
||||
};
|
||||
|
||||
/**@brief Current Time Service client init structure. This structure contains all options and data needed for the initialization of the client.*/
|
||||
typedef struct
|
||||
{
|
||||
ble_cts_c_evt_handler_t evt_handler; /**< Event handler to be called for handling events from the Current Time Service client. */
|
||||
ble_srv_error_handler_t error_handler; /**< Function to be called if an error occurs. */
|
||||
nrf_ble_gq_t * p_gatt_queue; /**< Pointer to the BLE GATT Queue instance. */
|
||||
} ble_cts_c_init_t;
|
||||
|
||||
|
||||
/**@brief Function for initializing the Current Time Service client.
|
||||
*
|
||||
* @details This function must be used by the application to initialize the Current Time Service client.
|
||||
*
|
||||
* @param[out] p_cts Current Time Service client structure. This structure must
|
||||
* be supplied by the application. It is initialized by this
|
||||
* function and can later be used to identify this particular client
|
||||
* instance.
|
||||
* @param[in] p_cts_init Information needed to initialize the Current Time Service client.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the service was initialized successfully.
|
||||
*/
|
||||
uint32_t ble_cts_c_init(ble_cts_c_t * p_cts, const ble_cts_c_init_t * p_cts_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 CTS at the peer. If it does, the function
|
||||
* calls the application's event handler to indicate that CTS was
|
||||
* discovered. The function also populates the event with service-related
|
||||
* information before providing it to the application.
|
||||
*
|
||||
* @param[in] p_cts Pointer to the CTS client structure.
|
||||
* @param[in] p_evt Pointer to the event received from the Database Discovery module.
|
||||
*/
|
||||
void ble_cts_c_on_db_disc_evt(ble_cts_c_t * p_cts, ble_db_discovery_evt_t * p_evt);
|
||||
|
||||
|
||||
/**@brief Function for handling the application's BLE stack events.
|
||||
*
|
||||
* @details This function handles all events from the BLE stack that are of interest to the
|
||||
* Current Time Service client. This is a callback function that must be dispatched
|
||||
* from the main application context.
|
||||
*
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
* @param[in] p_context Current Time Service client structure.
|
||||
*/
|
||||
void ble_cts_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
|
||||
|
||||
|
||||
/**@brief Function for checking whether the peer's Current Time Service instance and the Current Time
|
||||
* Characteristic have been discovered.
|
||||
*
|
||||
* @param[in] p_cts Current Time Service client structure.
|
||||
*/
|
||||
static __INLINE bool ble_cts_c_is_cts_discovered(const ble_cts_c_t * p_cts)
|
||||
{
|
||||
return (p_cts->char_handles.cts_handle != BLE_GATT_HANDLE_INVALID);
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for reading the peer's Current Time Service Current Time characteristic.
|
||||
*
|
||||
* @param[in] p_cts Current Time Service client structure.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the operation is successful.
|
||||
* @retval err_code Otherwise, this API propagates the error code returned by function
|
||||
* @ref nrf_ble_gq_item_add.
|
||||
*/
|
||||
uint32_t ble_cts_c_current_time_read(ble_cts_c_t const * p_cts);
|
||||
|
||||
|
||||
/**@brief Function for assigning handles to this instance of cts_c.
|
||||
*
|
||||
* @details Call this function when a link has been established with a peer to
|
||||
* associate the link to this instance of the module. This association makes it
|
||||
* possible to handle several links and associate each link to a particular
|
||||
* instance of this module. The connection handle and attribute handles are
|
||||
* provided from the discovery event @ref BLE_CTS_C_EVT_DISCOVERY_COMPLETE.
|
||||
*
|
||||
* @param[in] p_cts Pointer to the CTS client structure instance for associating the link.
|
||||
* @param[in] conn_handle Connection handle to associate with the given CTS instance.
|
||||
* @param[in] p_peer_handles Attribute handles for the CTS server you want this CTS client to
|
||||
* interact with.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the operation was successful.
|
||||
* @retval NRF_ERROR_NULL If a p_cts was a NULL pointer.
|
||||
* @retval err_code Otherwise, this API propagates the error code returned by function
|
||||
* @ref nrf_ble_gq_conn_handle_register.
|
||||
*/
|
||||
uint32_t ble_cts_c_handles_assign(ble_cts_c_t * p_cts,
|
||||
const uint16_t conn_handle,
|
||||
const ble_cts_c_handles_t * p_peer_handles);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // BLE_CTS_C_H__
|
||||
|
||||
/** @} */
|
||||
323
components/ble/ble_services/ble_dfu/ble_dfu.c
Normal file
323
components/ble/ble_services/ble_dfu/ble_dfu.c
Normal file
@@ -0,0 +1,323 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
/* Attention!
|
||||
* To maintain compliance with Nordic Semiconductor ASA's Bluetooth profile
|
||||
* qualification listings, this section of source code must not be modified.
|
||||
*/
|
||||
|
||||
#include "ble_dfu.h"
|
||||
#include <string.h>
|
||||
#include "ble_hci.h"
|
||||
#include "sdk_macros.h"
|
||||
#include "ble_srv_common.h"
|
||||
#include "nrf_nvic.h"
|
||||
#include "nrf_sdm.h"
|
||||
#include "nrf_soc.h"
|
||||
#include "nrf_log.h"
|
||||
#include "nrf_dfu_ble_svci_bond_sharing.h"
|
||||
#include "nrf_bootloader_info.h"
|
||||
#include "nrf_svci_async_function.h"
|
||||
#include "nrf_pwr_mgmt.h"
|
||||
#include "peer_manager.h"
|
||||
#include "gatts_cache_manager.h"
|
||||
#include "peer_id.h"
|
||||
|
||||
#define MAX_CTRL_POINT_RESP_PARAM_LEN 3 /**< Max length of the responses. */
|
||||
|
||||
#define BLE_DFU_SERVICE_UUID 0xFE59 /**< The 16-bit UUID of the Secure DFU Service. */
|
||||
|
||||
static ble_dfu_buttonless_t m_dfu; /**< Structure holding information about the Buttonless Secure DFU Service. */
|
||||
|
||||
NRF_SDH_BLE_OBSERVER(m_dfus_obs, BLE_DFU_BLE_OBSERVER_PRIO, ble_dfu_buttonless_on_ble_evt, &m_dfu);
|
||||
|
||||
|
||||
/**@brief Function that is called if no event handler is provided.
|
||||
*/
|
||||
static void dummy_evt_handler(ble_dfu_buttonless_evt_type_t evt)
|
||||
{
|
||||
NRF_LOG_DEBUG("Dummy event handler received event 0x%x", evt);
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling write events to the Buttonless Secure DFU Service Service Control Point characteristic.
|
||||
*
|
||||
* @param[in] p_evt_write Write event received from the BLE stack.
|
||||
*/
|
||||
static void on_ctrlpt_write(ble_gatts_evt_write_t const * p_evt_write)
|
||||
{
|
||||
uint32_t err_code;
|
||||
|
||||
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;
|
||||
|
||||
uint8_t cccd_val[2];
|
||||
ble_gatts_value_t value = {.p_value = cccd_val, .len = 2, .offset = 0};
|
||||
err_code = sd_ble_gatts_value_get(m_dfu.conn_handle, m_dfu.control_point_char.cccd_handle, &value);
|
||||
if (err_code == NRF_SUCCESS && ble_srv_is_indication_enabled(cccd_val))
|
||||
{
|
||||
write_authorize_reply.params.write.update = 1;
|
||||
write_authorize_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
write_authorize_reply.params.write.gatt_status = BLE_GATT_STATUS_ATTERR_CPS_CCCD_CONFIG_ERROR;
|
||||
}
|
||||
|
||||
// Authorize the write request
|
||||
do {
|
||||
err_code = sd_ble_gatts_rw_authorize_reply(m_dfu.conn_handle, &write_authorize_reply);
|
||||
} while (err_code == NRF_ERROR_BUSY);
|
||||
|
||||
|
||||
if (write_authorize_reply.params.write.gatt_status != BLE_GATT_STATUS_SUCCESS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Forward the write event to the Buttonless DFU module.
|
||||
ble_dfu_buttonless_on_ctrl_pt_write(p_evt_write);
|
||||
}
|
||||
|
||||
|
||||
/**@brief Write authorization request event handler.
|
||||
*
|
||||
* @details The write authorization request event handler is called when writing to the control point.
|
||||
*
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
*/
|
||||
static void on_rw_authorize_req(ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
if (p_ble_evt->evt.gatts_evt.conn_handle != m_dfu.conn_handle)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
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 == m_dfu.control_point_char.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_auth_req->request.write);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Connect event handler.
|
||||
*
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
*/
|
||||
static void on_connect(ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
m_dfu.conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
|
||||
}
|
||||
|
||||
|
||||
/**@brief Disconnect event handler.
|
||||
*
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
*/
|
||||
static void on_disconnect(ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
if (m_dfu.conn_handle != p_ble_evt->evt.gap_evt.conn_handle)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_dfu.conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling the HVC events.
|
||||
*
|
||||
* @details Handles HVC events from the BLE stack.
|
||||
*
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
*/
|
||||
static void on_hvc(ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
uint32_t err_code;
|
||||
ble_gatts_evt_hvc_t const * p_hvc = &p_ble_evt->evt.gatts_evt.params.hvc;
|
||||
|
||||
if (p_hvc->handle == m_dfu.control_point_char.value_handle)
|
||||
{
|
||||
// Enter bootloader if we were waiting for reset after hvc indication confimation.
|
||||
if (m_dfu.is_waiting_for_reset)
|
||||
{
|
||||
err_code = ble_dfu_buttonless_bootloader_start_prepare();
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
m_dfu.evt_handler(BLE_DFU_EVT_BOOTLOADER_ENTER_FAILED);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ble_dfu_buttonless_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL_VOID(p_ble_evt);
|
||||
|
||||
switch (p_ble_evt->header.evt_id)
|
||||
{
|
||||
case BLE_GAP_EVT_CONNECTED:
|
||||
on_connect(p_ble_evt);
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVT_DISCONNECTED:
|
||||
on_disconnect(p_ble_evt);
|
||||
break;
|
||||
|
||||
case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST:
|
||||
on_rw_authorize_req(p_ble_evt);
|
||||
break;
|
||||
|
||||
case BLE_GATTS_EVT_HVC:
|
||||
on_hvc(p_ble_evt);
|
||||
break;
|
||||
|
||||
default:
|
||||
// no implementation
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_dfu_buttonless_resp_send(ble_dfu_buttonless_op_code_t op_code, ble_dfu_buttonless_rsp_code_t rsp_code)
|
||||
{
|
||||
// Send indication
|
||||
uint32_t err_code;
|
||||
const uint16_t len = MAX_CTRL_POINT_RESP_PARAM_LEN;
|
||||
uint16_t hvx_len;
|
||||
uint8_t hvx_data[MAX_CTRL_POINT_RESP_PARAM_LEN];
|
||||
ble_gatts_hvx_params_t hvx_params;
|
||||
|
||||
memset(&hvx_params, 0, sizeof(hvx_params));
|
||||
|
||||
hvx_len = len;
|
||||
hvx_data[0] = DFU_OP_RESPONSE_CODE;
|
||||
hvx_data[1] = (uint8_t)op_code;
|
||||
hvx_data[2] = (uint8_t)rsp_code;
|
||||
|
||||
hvx_params.handle = m_dfu.control_point_char.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(m_dfu.conn_handle, &hvx_params);
|
||||
if ((err_code == NRF_SUCCESS) && (hvx_len != len))
|
||||
{
|
||||
err_code = NRF_ERROR_DATA_SIZE;
|
||||
}
|
||||
|
||||
return err_code;
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_dfu_buttonless_bootloader_start_finalize(void)
|
||||
{
|
||||
uint32_t err_code;
|
||||
|
||||
NRF_LOG_DEBUG("In ble_dfu_buttonless_bootloader_start_finalize\r\n");
|
||||
|
||||
err_code = sd_power_gpregret_clr(0, 0xffffffff);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
err_code = sd_power_gpregret_set(0, BOOTLOADER_DFU_START);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
// Indicate that the Secure DFU bootloader will be entered
|
||||
m_dfu.evt_handler(BLE_DFU_EVT_BOOTLOADER_ENTER);
|
||||
|
||||
// Signal that DFU mode is to be enter to the power management module
|
||||
nrf_pwr_mgmt_shutdown(NRF_PWR_MGMT_SHUTDOWN_GOTO_DFU);
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_dfu_buttonless_init(const ble_dfu_buttonless_init_t * p_dfu_init)
|
||||
{
|
||||
uint32_t err_code;
|
||||
ble_uuid_t service_uuid;
|
||||
ble_uuid128_t nordic_base_uuid = BLE_NORDIC_VENDOR_BASE_UUID;
|
||||
|
||||
VERIFY_PARAM_NOT_NULL(p_dfu_init);
|
||||
|
||||
// Initialize the service structure.
|
||||
m_dfu.conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
m_dfu.evt_handler = p_dfu_init->evt_handler;
|
||||
m_dfu.is_waiting_for_reset = false;
|
||||
|
||||
if (m_dfu.evt_handler == NULL)
|
||||
{
|
||||
m_dfu.evt_handler = dummy_evt_handler;
|
||||
}
|
||||
|
||||
err_code = ble_dfu_buttonless_backend_init(&m_dfu);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
BLE_UUID_BLE_ASSIGN(service_uuid, BLE_DFU_SERVICE_UUID);
|
||||
|
||||
// Add the DFU service declaration.
|
||||
err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
|
||||
&service_uuid,
|
||||
&(m_dfu.service_handle));
|
||||
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
// Add vendor specific base UUID to use with the Buttonless DFU characteristic.
|
||||
err_code = sd_ble_uuid_vs_add(&nordic_base_uuid, &m_dfu.uuid_type);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
// Add the Buttonless DFU Characteristic (with bonds/without bonds).
|
||||
err_code = ble_dfu_buttonless_char_add(&m_dfu);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
249
components/ble/ble_services/ble_dfu/ble_dfu.h
Normal file
249
components/ble/ble_services/ble_dfu/ble_dfu.h
Normal file
@@ -0,0 +1,249 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 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 ble_dfu Buttonless DFU Service
|
||||
* @{
|
||||
* @ingroup ble_sdk_srv
|
||||
* @brief Buttonless DFU Service module.
|
||||
*
|
||||
* @details This module implements a proprietary Buttonless Secure DFU Service. The service can
|
||||
* be configured to support bonds or not. The bond support configuration must correspond to the
|
||||
* requirement of Secure DFU bootloader.
|
||||
*
|
||||
* @note Attention!
|
||||
* To maintain compliance with Nordic Semiconductor ASA Bluetooth profile
|
||||
* qualification listings, this section of source code must not be modified.
|
||||
*/
|
||||
|
||||
#ifndef BLE_DFU_H__
|
||||
#define BLE_DFU_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include "ble_srv_common.h"
|
||||
#include "nrf_sdh_ble.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/**@brief SoC observer priority.
|
||||
* @details Priority of this module's SoC event handler.
|
||||
*/
|
||||
#define BLE_DFU_SOC_OBSERVER_PRIO 1
|
||||
|
||||
#define BLE_DFU_BUTTONLESS_CHAR_UUID (0x0003) /**< Value combined with vendor-specific base to create Unbonded Buttonless characteristic UUID. */
|
||||
#define BLE_DFU_BUTTONLESS_BONDED_CHAR_UUID (0x0004) /**< Value combined with vendor-specific base to create Bonded Buttonless characteristic UUID. */
|
||||
|
||||
|
||||
/**@brief Nordic vendor-specific base UUID.
|
||||
*/
|
||||
#define BLE_NORDIC_VENDOR_BASE_UUID \
|
||||
{{ \
|
||||
0x50, 0xEA, 0xDA, 0x30, 0x88, 0x83, 0xB8, 0x9F, \
|
||||
0x60, 0x4F, 0x15, 0xF3, 0x00, 0x00, 0xC9, 0x8E \
|
||||
}}
|
||||
|
||||
|
||||
/**@brief Nordic Buttonless DFU Service event type .
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
BLE_DFU_EVT_BOOTLOADER_ENTER_PREPARE, /**< Event indicating that the device is preparing to enter bootloader.*/
|
||||
BLE_DFU_EVT_BOOTLOADER_ENTER, /**< Event indicating that the bootloader will be entered after return of this event.*/
|
||||
BLE_DFU_EVT_BOOTLOADER_ENTER_FAILED, /**< Failure to enter bootloader mode.*/
|
||||
BLE_DFU_EVT_RESPONSE_SEND_ERROR, /**< Failure to send response.*/
|
||||
} ble_dfu_buttonless_evt_type_t;
|
||||
|
||||
|
||||
/**@brief Nordic Buttonless DFU Service event handler type.
|
||||
*/
|
||||
typedef void (*ble_dfu_buttonless_evt_handler_t) (ble_dfu_buttonless_evt_type_t p_evt);
|
||||
/**@brief Enumeration of Bootloader DFU response codes.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
DFU_RSP_INVALID = 0x00, /**< Invalid op code. */
|
||||
DFU_RSP_SUCCESS = 0x01, /**< Success. */
|
||||
DFU_RSP_OP_CODE_NOT_SUPPORTED = 0x02, /**< Op code not supported. */
|
||||
DFU_RSP_OPERATION_FAILED = 0x04, /**< Operation failed. */
|
||||
DFU_RSP_ADV_NAME_INVALID = 0x05, /**< Requested advertisement name is too short or too long. */
|
||||
DFU_RSP_BUSY = 0x06, /**< Ongoing async operation. */
|
||||
DFU_RSP_NOT_BONDED = 0x07, /**< Buttonless unavailable due to device not bonded. */
|
||||
} ble_dfu_buttonless_rsp_code_t;
|
||||
|
||||
|
||||
/**@brief Enumeration of Bootloader DFU Operation codes.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
DFU_OP_RESERVED = 0x00, /**< Reserved for future use. */
|
||||
DFU_OP_ENTER_BOOTLOADER = 0x01, /**< Enter bootloader. */
|
||||
DFU_OP_SET_ADV_NAME = 0x02, /**< Set advertisement name to use in DFU mode. */
|
||||
DFU_OP_RESPONSE_CODE = 0x20 /**< Response code. */
|
||||
} ble_dfu_buttonless_op_code_t;
|
||||
|
||||
|
||||
/**@brief Type holding memory used by Secure DFU Buttonless Service.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint8_t uuid_type; /**< UUID type for DFU UUID. */
|
||||
uint16_t service_handle; /**< Service Handle of DFU (as provided by the SoftDevice). */
|
||||
uint16_t conn_handle; /**< Connection handle for the current peer. */
|
||||
ble_gatts_char_handles_t control_point_char; /**< Handles related to the DFU Control Point characteristic. */
|
||||
uint32_t peers_count; /**< Counter to see how many persistently stored peers must be updated for Service Changed indication. This value will be counted down when comparing write requests. */
|
||||
ble_dfu_buttonless_evt_handler_t evt_handler; /**< Event handler that is called upon Buttonless DFU events. See @ref ble_dfu_buttonless_evt_type_t. */
|
||||
bool is_waiting_for_reset; /**< Flag indicating that the device will enter bootloader. */
|
||||
bool is_waiting_for_svci; /**< Flag indicating that the device is waiting for async SVCI operation */
|
||||
} ble_dfu_buttonless_t;
|
||||
|
||||
|
||||
/**@brief Type used to initialize the Secure DFU Buttonless Service.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
ble_dfu_buttonless_evt_handler_t evt_handler; /**< Bootloader event handler. */
|
||||
} ble_dfu_buttonless_init_t;
|
||||
|
||||
|
||||
/**@brief Function for initializing the Device Firmware Update module.
|
||||
*
|
||||
* @param[in] p_dfu_init Structure containing the values of characteristics needed by the
|
||||
* service.
|
||||
* @retval NRF_SUCCESS on successful initialization of the service.
|
||||
*/
|
||||
uint32_t ble_dfu_buttonless_init(const ble_dfu_buttonless_init_t * p_dfu_init);
|
||||
|
||||
|
||||
/**@brief Function for initializing the async SVCI interface.
|
||||
*
|
||||
* @warning Ensure that no interrupts are triggered when calling this functions as
|
||||
* interrupts and exceptions are forwarded to the bootloader for the period
|
||||
* of the call and may be lost.
|
||||
*
|
||||
* @details This configures the async interface for calling to the
|
||||
* bootloader through SVCI interface.
|
||||
*
|
||||
* @retval NRF_SUCCESS on success, otherwise an error code.
|
||||
*/
|
||||
uint32_t ble_dfu_buttonless_async_svci_init(void);
|
||||
|
||||
|
||||
/**@brief Function to initialize the backend Secure DFU Buttonless service which is either
|
||||
* supports bonds or not.
|
||||
*
|
||||
* @note Do not call this function directly. It is called internally by @ref ble_dfu_buttonless_init.
|
||||
*
|
||||
* @param[in] p_dfu Nordic DFU Service structure.
|
||||
*
|
||||
* @return NRF_SUCCESS On sucessfully initializing, otherwise an error code.
|
||||
*/
|
||||
uint32_t ble_dfu_buttonless_backend_init(ble_dfu_buttonless_t * p_dfu);
|
||||
|
||||
|
||||
|
||||
/**@brief Function for adding the buttonless characteristic.
|
||||
*
|
||||
* @note This will be implemented differently on bonded/unbonded Buttonless DFU service.
|
||||
*
|
||||
* @param[in] p_dfu Nordic DFU Service structure.
|
||||
*
|
||||
* @return NRF_SUCCESS on success, otherwise an error code.
|
||||
*/
|
||||
uint32_t ble_dfu_buttonless_char_add(ble_dfu_buttonless_t * p_dfu);
|
||||
|
||||
|
||||
/**@brief Function for sending a response back to the client.
|
||||
*
|
||||
* @param[in] op_code Operation code to send the response for.
|
||||
* @param[in] rsp_code Response code for the operation.
|
||||
*
|
||||
* @retval NRF_SUCCESS on success, otherwise an error code.
|
||||
*/
|
||||
uint32_t ble_dfu_buttonless_resp_send(ble_dfu_buttonless_op_code_t op_code, ble_dfu_buttonless_rsp_code_t rsp_code);
|
||||
|
||||
|
||||
/**@brief Function for handling the application's BLE stack events.
|
||||
*
|
||||
* @details Handles all events from the BLE stack of interest to the DFU buttonless service.
|
||||
*
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
* @param[in] p_context BLE context structure.
|
||||
*/
|
||||
void ble_dfu_buttonless_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
|
||||
|
||||
|
||||
/**@brief Function for handling control point write requests.
|
||||
*
|
||||
* @details Handles write requests to the control point in
|
||||
* DFU with bonds or without bonds.
|
||||
*
|
||||
* @param[in] p_evt_write GATTS write event.
|
||||
*/
|
||||
void ble_dfu_buttonless_on_ctrl_pt_write(ble_gatts_evt_write_t const * p_evt_write);
|
||||
|
||||
|
||||
/**@brief Function for preparing to enter the bootloader.
|
||||
*
|
||||
* @warning This function is called directly. (It is called internally).
|
||||
*
|
||||
* @retval Any error code from calling @ref sd_ble_gap_disconnect.
|
||||
*/
|
||||
uint32_t ble_dfu_buttonless_bootloader_start_prepare(void);
|
||||
|
||||
|
||||
/**@brief Function for finalizing entering the bootloader.
|
||||
*
|
||||
* @warning This function is not to be called. (It is called internally).
|
||||
*
|
||||
* @retval NRF_SUCCESS Finalize was started correctly.
|
||||
*/
|
||||
uint32_t ble_dfu_buttonless_bootloader_start_finalize(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // BLE_DIS_H__
|
||||
|
||||
/** @} */
|
||||
367
components/ble/ble_services/ble_dfu/ble_dfu_bonded.c
Normal file
367
components/ble/ble_services/ble_dfu/ble_dfu_bonded.c
Normal file
@@ -0,0 +1,367 @@
|
||||
/**
|
||||
* 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 <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include "nrf_dfu_ble_svci_bond_sharing.h"
|
||||
#include "nordic_common.h"
|
||||
#include "nrf_error.h"
|
||||
#include "ble_dfu.h"
|
||||
#include "nrf_log.h"
|
||||
#include "peer_manager.h"
|
||||
#include "gatts_cache_manager.h"
|
||||
#include "peer_id.h"
|
||||
#include "nrf_sdh_soc.h"
|
||||
#include "nrf_strerror.h"
|
||||
|
||||
#if (NRF_DFU_BLE_BUTTONLESS_SUPPORTS_BONDS)
|
||||
|
||||
|
||||
void ble_dfu_buttonless_on_sys_evt(uint32_t, void * );
|
||||
uint32_t nrf_dfu_svci_vector_table_set(void);
|
||||
uint32_t nrf_dfu_svci_vector_table_unset(void);
|
||||
|
||||
/**@brief Define function for async interface to set peer data. */
|
||||
NRF_SVCI_ASYNC_FUNC_DEFINE(NRF_DFU_SVCI_SET_PEER_DATA, nrf_dfu_set_peer_data, nrf_dfu_peer_data_t);
|
||||
|
||||
// Register SoC observer for the Buttonless Secure DFU service
|
||||
NRF_SDH_SOC_OBSERVER(m_dfu_buttonless_soc_obs, BLE_DFU_SOC_OBSERVER_PRIO, ble_dfu_buttonless_on_sys_evt, NULL);
|
||||
|
||||
ble_dfu_buttonless_t * mp_dfu;
|
||||
static nrf_dfu_peer_data_t m_peer_data;
|
||||
|
||||
|
||||
/**@brief Function for handling Peer Manager events.
|
||||
*
|
||||
* @param[in] p_evt Peer Manager event.
|
||||
*/
|
||||
static void pm_evt_handler(pm_evt_t const * p_evt)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
if (mp_dfu == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Only handle this when we are waiting to reset into DFU mode
|
||||
if (!mp_dfu->is_waiting_for_reset)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch(p_evt->evt_id)
|
||||
{
|
||||
case PM_EVT_PEER_DATA_UPDATE_SUCCEEDED:
|
||||
if (p_evt->params.peer_data_update_succeeded.data_id == PM_PEER_DATA_ID_SERVICE_CHANGED_PENDING)
|
||||
{
|
||||
mp_dfu->peers_count--;
|
||||
NRF_LOG_DEBUG("Updating Service Changed indication for peers, %d left", mp_dfu->peers_count);
|
||||
if (mp_dfu->peers_count == 0)
|
||||
{
|
||||
NRF_LOG_DEBUG("Finished updating Service Changed indication for peers");
|
||||
// We have updated Service Changed Indication for all devices.
|
||||
ret = ble_dfu_buttonless_bootloader_start_finalize();
|
||||
if (ret != NRF_SUCCESS)
|
||||
{
|
||||
mp_dfu->evt_handler(BLE_DFU_EVT_BOOTLOADER_ENTER_FAILED);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PM_EVT_PEER_DATA_UPDATE_FAILED:
|
||||
// Failure to update data. Service Changed cannot be sent but DFU mode is still possible
|
||||
ret = ble_dfu_buttonless_bootloader_start_finalize();
|
||||
if (ret != NRF_SUCCESS)
|
||||
{
|
||||
mp_dfu->evt_handler(BLE_DFU_EVT_BOOTLOADER_ENTER_FAILED);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static uint32_t retrieve_peer_data(void)
|
||||
{
|
||||
ret_code_t ret;
|
||||
pm_peer_data_bonding_t bonding_data = {0};
|
||||
pm_peer_id_t peer_id;
|
||||
|
||||
ret = pm_peer_id_get(mp_dfu->conn_handle, &peer_id);
|
||||
VERIFY_SUCCESS(ret);
|
||||
|
||||
if (peer_id == PM_PEER_ID_INVALID)
|
||||
{
|
||||
return NRF_ERROR_FORBIDDEN;
|
||||
}
|
||||
|
||||
ret = pm_peer_data_bonding_load(peer_id, &bonding_data);
|
||||
VERIFY_SUCCESS(ret);
|
||||
|
||||
memcpy(&m_peer_data.ble_id, &bonding_data.peer_ble_id, sizeof(ble_gap_id_key_t));
|
||||
memcpy(&m_peer_data.enc_key, &bonding_data.own_ltk, sizeof(ble_gap_enc_key_t));
|
||||
|
||||
uint16_t len = SYSTEM_SERVICE_ATT_SIZE;
|
||||
ret = sd_ble_gatts_sys_attr_get(mp_dfu->conn_handle,
|
||||
m_peer_data.sys_serv_attr,
|
||||
&len,
|
||||
BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS);
|
||||
|
||||
NRF_LOG_DEBUG("system attribute table len: %d", len);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for entering the bootloader.
|
||||
*
|
||||
* @details This starts forwarding peer data to the Secure DFU bootloader.
|
||||
*/
|
||||
static uint32_t enter_bootloader(void)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
NRF_LOG_INFO("Writing peer data to the bootloader...");
|
||||
|
||||
if (mp_dfu->is_waiting_for_svci)
|
||||
{
|
||||
return ble_dfu_buttonless_resp_send(DFU_OP_ENTER_BOOTLOADER, DFU_RSP_BUSY);
|
||||
}
|
||||
|
||||
// If retrieve_peer_data returns NRF_ERROR_FORBIDDEN, then the device was not bonded.
|
||||
ret = retrieve_peer_data();
|
||||
VERIFY_SUCCESS(ret);
|
||||
|
||||
ret = nrf_dfu_set_peer_data(&m_peer_data);
|
||||
if (ret == NRF_SUCCESS)
|
||||
{
|
||||
// The request was accepted. Waiting for sys events to progress.
|
||||
mp_dfu->is_waiting_for_svci = true;
|
||||
}
|
||||
else if (ret == NRF_ERROR_FORBIDDEN)
|
||||
{
|
||||
NRF_LOG_ERROR("The bootloader has write protected its settings page. This prohibits setting the peer data. "\
|
||||
"The bootloader must be compiled with NRF_BL_SETTINGS_PAGE_PROTECT=0 to allow setting the peer data.");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_dfu_buttonless_backend_init(ble_dfu_buttonless_t * p_dfu)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_dfu);
|
||||
|
||||
// Set the memory used by the backend.
|
||||
mp_dfu = p_dfu;
|
||||
|
||||
// Initialize the Peer manager handler.
|
||||
return pm_register(pm_evt_handler);
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_dfu_buttonless_async_svci_init(void)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
// Set the vector table base address to the bootloader.
|
||||
ret = nrf_dfu_svci_vector_table_set();
|
||||
NRF_LOG_DEBUG("nrf_dfu_svci_vector_table_set() -> %s",
|
||||
(ret == NRF_SUCCESS) ? "success" : nrf_strerror_get(ret));
|
||||
VERIFY_SUCCESS(ret);
|
||||
|
||||
// Initialize the asynchronous SuperVisor interface to set peer data in Secure DFU bootloader.
|
||||
ret = nrf_dfu_set_peer_data_init();
|
||||
NRF_LOG_DEBUG("nrf_dfu_set_peer_data_init() -> %s",
|
||||
(ret == NRF_SUCCESS) ? "success" : nrf_strerror_get(ret));
|
||||
VERIFY_SUCCESS(ret);
|
||||
|
||||
// Set the vector table base address back to main application.
|
||||
ret = nrf_dfu_svci_vector_table_unset();
|
||||
NRF_LOG_DEBUG("nrf_dfu_svci_vector_table_unset() -> %s",
|
||||
(ret == NRF_SUCCESS) ? "success" : nrf_strerror_get(ret));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void ble_dfu_buttonless_on_sys_evt(uint32_t sys_evt, void * p_context)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
if (!nrf_dfu_set_peer_data_is_initialized())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ret = nrf_dfu_set_peer_data_on_sys_evt(sys_evt);
|
||||
if (ret == NRF_ERROR_INVALID_STATE)
|
||||
{
|
||||
// The system event is not from an operation started by buttonless DFU.
|
||||
// No action is taken, and nothing is reported.
|
||||
}
|
||||
else if (ret == NRF_SUCCESS)
|
||||
{
|
||||
// Peer data was successfully forwarded to the Secure DFU bootloader.
|
||||
// Set the flag indicating that we are waiting for indication response
|
||||
// to activate the reset.
|
||||
mp_dfu->is_waiting_for_reset = true;
|
||||
mp_dfu->is_waiting_for_svci = false;
|
||||
|
||||
// Report back the positive response
|
||||
ret = ble_dfu_buttonless_resp_send(DFU_OP_ENTER_BOOTLOADER, DFU_RSP_SUCCESS);
|
||||
if (ret != NRF_SUCCESS)
|
||||
{
|
||||
mp_dfu->evt_handler(BLE_DFU_EVT_RESPONSE_SEND_ERROR);
|
||||
mp_dfu->is_waiting_for_reset = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Failed to set peer data. Report this.
|
||||
mp_dfu->is_waiting_for_reset = false;
|
||||
mp_dfu->is_waiting_for_svci = false;
|
||||
ret = ble_dfu_buttonless_resp_send(DFU_OP_ENTER_BOOTLOADER, DFU_RSP_BUSY);
|
||||
|
||||
// Report the failure to send the response to the client
|
||||
if (ret != NRF_SUCCESS)
|
||||
{
|
||||
mp_dfu->evt_handler(BLE_DFU_EVT_RESPONSE_SEND_ERROR);
|
||||
}
|
||||
|
||||
// Report the failure to enter DFU mode
|
||||
mp_dfu->evt_handler(BLE_DFU_EVT_BOOTLOADER_ENTER_FAILED);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_dfu_buttonless_char_add(ble_dfu_buttonless_t * p_dfu)
|
||||
{
|
||||
ble_add_char_params_t add_char_params;
|
||||
|
||||
memset(&add_char_params, 0, sizeof(add_char_params));
|
||||
add_char_params.uuid = BLE_DFU_BUTTONLESS_BONDED_CHAR_UUID;
|
||||
add_char_params.uuid_type = p_dfu->uuid_type;
|
||||
add_char_params.char_props.indicate = 1;
|
||||
add_char_params.char_props.write = 1;
|
||||
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.cccd_write_access = SEC_JUST_WORKS;
|
||||
add_char_params.write_access = SEC_JUST_WORKS;
|
||||
add_char_params.read_access = SEC_OPEN;
|
||||
|
||||
return characteristic_add(p_dfu->service_handle, &add_char_params, &p_dfu->control_point_char);
|
||||
}
|
||||
|
||||
|
||||
void ble_dfu_buttonless_on_ctrl_pt_write(ble_gatts_evt_write_t const * p_evt_write)
|
||||
{
|
||||
uint32_t ret;
|
||||
ble_dfu_buttonless_rsp_code_t rsp_code = DFU_RSP_OPERATION_FAILED;
|
||||
|
||||
// Start executing the control point write action
|
||||
switch (p_evt_write->data[0])
|
||||
{
|
||||
case DFU_OP_ENTER_BOOTLOADER:
|
||||
ret = enter_bootloader();
|
||||
if (ret == NRF_SUCCESS)
|
||||
{
|
||||
rsp_code = DFU_RSP_SUCCESS;
|
||||
}
|
||||
else if (ret == NRF_ERROR_BUSY)
|
||||
{
|
||||
rsp_code = DFU_RSP_BUSY;
|
||||
}
|
||||
else if (ret == NRF_ERROR_FORBIDDEN)
|
||||
{
|
||||
rsp_code = DFU_RSP_NOT_BONDED;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
rsp_code = DFU_RSP_OP_CODE_NOT_SUPPORTED;
|
||||
break;
|
||||
}
|
||||
|
||||
// Report back in case of error
|
||||
if (rsp_code != DFU_RSP_SUCCESS)
|
||||
{
|
||||
ret = ble_dfu_buttonless_resp_send((ble_dfu_buttonless_op_code_t)p_evt_write->data[0],
|
||||
rsp_code);
|
||||
|
||||
if (ret != NRF_SUCCESS)
|
||||
{
|
||||
mp_dfu->evt_handler(BLE_DFU_EVT_RESPONSE_SEND_ERROR);
|
||||
}
|
||||
|
||||
// Report the error to the main application
|
||||
mp_dfu->evt_handler(BLE_DFU_EVT_BOOTLOADER_ENTER_FAILED);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_dfu_buttonless_bootloader_start_prepare(void)
|
||||
{
|
||||
NRF_LOG_DEBUG("In ble_dfu_buttonless_bootloader_start_prepare");
|
||||
|
||||
// Indicate to main app that DFU mode is starting.
|
||||
// This event can be used to let the device take down any connection to
|
||||
// bonded devices.
|
||||
mp_dfu->evt_handler(BLE_DFU_EVT_BOOTLOADER_ENTER_PREPARE);
|
||||
|
||||
// Store the number of peers for which Peer Manager is expected to successfully write events.
|
||||
mp_dfu->peers_count = peer_id_n_ids();
|
||||
|
||||
// Set local database changed to get Service Changed indication for all bonded peers
|
||||
// on next bootup (either because of a successful or aborted DFU).
|
||||
gscm_local_database_has_changed();
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
#endif // NRF_DFU_BLE_BUTTONLESS_SUPPORTS_BONDS
|
||||
|
||||
299
components/ble/ble_services/ble_dfu/ble_dfu_unbonded.c
Normal file
299
components/ble/ble_services/ble_dfu/ble_dfu_unbonded.c
Normal file
@@ -0,0 +1,299 @@
|
||||
/**
|
||||
* 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 <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include "nrf_dfu_ble_svci_bond_sharing.h"
|
||||
#include "nordic_common.h"
|
||||
#include "nrf_error.h"
|
||||
#include "ble_dfu.h"
|
||||
#include "nrf_log.h"
|
||||
#include "nrf_sdh_soc.h"
|
||||
|
||||
#if (!NRF_DFU_BLE_BUTTONLESS_SUPPORTS_BONDS)
|
||||
|
||||
#define NRF_DFU_ADV_NAME_MAX_LENGTH (20)
|
||||
|
||||
|
||||
void ble_dfu_buttonless_on_sys_evt(uint32_t, void * );
|
||||
uint32_t nrf_dfu_svci_vector_table_set(void);
|
||||
uint32_t nrf_dfu_svci_vector_table_unset(void);
|
||||
|
||||
/**@brief Define functions for async interface to set new advertisement name for DFU mode. */
|
||||
NRF_SVCI_ASYNC_FUNC_DEFINE(NRF_DFU_SVCI_SET_ADV_NAME, nrf_dfu_set_adv_name, nrf_dfu_adv_name_t);
|
||||
|
||||
// Register SoC observer for the Buttonless Secure DFU service
|
||||
NRF_SDH_SOC_OBSERVER(m_dfu_buttonless_soc_obs, BLE_DFU_SOC_OBSERVER_PRIO, ble_dfu_buttonless_on_sys_evt, NULL);
|
||||
|
||||
ble_dfu_buttonless_t * mp_dfu = NULL;
|
||||
static nrf_dfu_adv_name_t m_adv_name;
|
||||
|
||||
|
||||
/**@brief Function for setting an advertisement name.
|
||||
*
|
||||
* @param[in] adv_name The new advertisement name.
|
||||
*
|
||||
* @retval NRF_SUCCESS Advertisement name was successfully set.
|
||||
* @retval DFU_RSP_BUSY Advertisement name was not set because of an ongoing operation.
|
||||
* @retval Any other errors from the SVCI interface call.
|
||||
*/
|
||||
static uint32_t set_adv_name(nrf_dfu_adv_name_t * p_adv_name)
|
||||
{
|
||||
uint32_t err_code;
|
||||
|
||||
if (mp_dfu->is_waiting_for_svci)
|
||||
{
|
||||
return DFU_RSP_BUSY;
|
||||
}
|
||||
|
||||
err_code = nrf_dfu_set_adv_name(p_adv_name);
|
||||
if (err_code == NRF_SUCCESS)
|
||||
{
|
||||
// The request was accepted.
|
||||
mp_dfu->is_waiting_for_svci = true;
|
||||
}
|
||||
else if (err_code == NRF_ERROR_FORBIDDEN)
|
||||
{
|
||||
NRF_LOG_ERROR("The bootloader has write protected its settings page. This prohibits setting the advertising name. "\
|
||||
"The bootloader must be compiled with NRF_BL_SETTINGS_PAGE_PROTECT=0 to allow setting the advertising name.");
|
||||
}
|
||||
|
||||
return err_code;
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for entering the bootloader.
|
||||
*/
|
||||
static uint32_t enter_bootloader()
|
||||
{
|
||||
uint32_t err_code;
|
||||
|
||||
if (mp_dfu->is_waiting_for_svci)
|
||||
{
|
||||
// We have an ongoing async operation. Entering bootloader mode is not possible at this time.
|
||||
err_code = ble_dfu_buttonless_resp_send(DFU_OP_ENTER_BOOTLOADER, DFU_RSP_BUSY);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
mp_dfu->evt_handler(BLE_DFU_EVT_RESPONSE_SEND_ERROR);
|
||||
}
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
// Set the flag indicating that we expect DFU mode.
|
||||
// This will be handled on acknowledgement of the characteristic indication.
|
||||
mp_dfu->is_waiting_for_reset = true;
|
||||
|
||||
err_code = ble_dfu_buttonless_resp_send(DFU_OP_ENTER_BOOTLOADER, DFU_RSP_SUCCESS);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
mp_dfu->is_waiting_for_reset = false;
|
||||
}
|
||||
|
||||
return err_code;
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_dfu_buttonless_backend_init(ble_dfu_buttonless_t * p_dfu)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_dfu);
|
||||
|
||||
mp_dfu = p_dfu;
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_dfu_buttonless_async_svci_init(void)
|
||||
{
|
||||
uint32_t ret_val;
|
||||
|
||||
ret_val = nrf_dfu_svci_vector_table_set();
|
||||
VERIFY_SUCCESS(ret_val);
|
||||
|
||||
ret_val = nrf_dfu_set_adv_name_init();
|
||||
VERIFY_SUCCESS(ret_val);
|
||||
|
||||
ret_val = nrf_dfu_svci_vector_table_unset();
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
|
||||
void ble_dfu_buttonless_on_sys_evt(uint32_t sys_evt, void * p_context)
|
||||
{
|
||||
uint32_t err_code;
|
||||
|
||||
if (!nrf_dfu_set_adv_name_is_initialized())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
err_code = nrf_dfu_set_adv_name_on_sys_evt(sys_evt);
|
||||
if (err_code == NRF_ERROR_INVALID_STATE)
|
||||
{
|
||||
// The system event is not from an operation started by buttonless DFU.
|
||||
// No action is taken, and nothing is reported.
|
||||
}
|
||||
else if (err_code == NRF_SUCCESS)
|
||||
{
|
||||
// The async operation is finished.
|
||||
// Set the flag indicating that we are waiting for indication response
|
||||
// to activate the reset.
|
||||
mp_dfu->is_waiting_for_svci = false;
|
||||
|
||||
// Report back the positive response
|
||||
err_code = ble_dfu_buttonless_resp_send(DFU_OP_SET_ADV_NAME, DFU_RSP_SUCCESS);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
mp_dfu->evt_handler(BLE_DFU_EVT_RESPONSE_SEND_ERROR);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Invalid error code reported back.
|
||||
mp_dfu->is_waiting_for_svci = false;
|
||||
|
||||
err_code = ble_dfu_buttonless_resp_send(DFU_OP_SET_ADV_NAME, DFU_RSP_BUSY);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
mp_dfu->evt_handler(BLE_DFU_EVT_RESPONSE_SEND_ERROR);
|
||||
}
|
||||
|
||||
// Report the failure to enter DFU mode
|
||||
mp_dfu->evt_handler(BLE_DFU_EVT_BOOTLOADER_ENTER_FAILED);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_dfu_buttonless_char_add(ble_dfu_buttonless_t * p_dfu)
|
||||
{
|
||||
ble_add_char_params_t add_char_params;
|
||||
|
||||
memset(&add_char_params, 0, sizeof(add_char_params));
|
||||
add_char_params.uuid = BLE_DFU_BUTTONLESS_CHAR_UUID;
|
||||
add_char_params.uuid_type = p_dfu->uuid_type;
|
||||
add_char_params.char_props.indicate = 1;
|
||||
add_char_params.char_props.write = 1;
|
||||
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.cccd_write_access = SEC_OPEN;
|
||||
add_char_params.write_access = SEC_OPEN;
|
||||
add_char_params.read_access = SEC_OPEN;
|
||||
|
||||
return characteristic_add(p_dfu->service_handle, &add_char_params, &p_dfu->control_point_char);
|
||||
}
|
||||
|
||||
|
||||
void ble_dfu_buttonless_on_ctrl_pt_write(ble_gatts_evt_write_t const * p_evt_write)
|
||||
{
|
||||
uint32_t err_code;
|
||||
ble_dfu_buttonless_rsp_code_t rsp_code = DFU_RSP_OPERATION_FAILED;
|
||||
|
||||
// Start executing the control point write operation
|
||||
/*lint -e415 -e416 -save "Out of bounds access"*/
|
||||
switch (p_evt_write->data[0])
|
||||
{
|
||||
case DFU_OP_ENTER_BOOTLOADER:
|
||||
err_code = enter_bootloader();
|
||||
if (err_code == NRF_SUCCESS)
|
||||
{
|
||||
rsp_code = DFU_RSP_SUCCESS;
|
||||
}
|
||||
else if (err_code == NRF_ERROR_BUSY)
|
||||
{
|
||||
rsp_code = DFU_RSP_BUSY;
|
||||
}
|
||||
break;
|
||||
|
||||
case DFU_OP_SET_ADV_NAME:
|
||||
if( (p_evt_write->data[1] > NRF_DFU_ADV_NAME_MAX_LENGTH)
|
||||
|| (p_evt_write->data[1] == 0))
|
||||
{
|
||||
// New advertisement name too short or too long.
|
||||
rsp_code = DFU_RSP_ADV_NAME_INVALID;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(m_adv_name.name, &p_evt_write->data[2], p_evt_write->data[1]);
|
||||
m_adv_name.len = p_evt_write->data[1];
|
||||
err_code = set_adv_name(&m_adv_name);
|
||||
if (err_code == NRF_SUCCESS)
|
||||
{
|
||||
rsp_code = DFU_RSP_SUCCESS;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
rsp_code = DFU_RSP_OP_CODE_NOT_SUPPORTED;
|
||||
break;
|
||||
}
|
||||
/*lint -restore*/
|
||||
|
||||
|
||||
// Report back in case of error
|
||||
if (rsp_code != DFU_RSP_SUCCESS)
|
||||
{
|
||||
err_code = ble_dfu_buttonless_resp_send((ble_dfu_buttonless_op_code_t)p_evt_write->data[0], rsp_code);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
mp_dfu->evt_handler(BLE_DFU_EVT_RESPONSE_SEND_ERROR);
|
||||
|
||||
}
|
||||
// Report the error to the main application
|
||||
mp_dfu->evt_handler(BLE_DFU_EVT_BOOTLOADER_ENTER_FAILED);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t ble_dfu_buttonless_bootloader_start_prepare(void)
|
||||
{
|
||||
uint32_t err_code;
|
||||
|
||||
// Indicate to main app that DFU mode is starting.
|
||||
mp_dfu->evt_handler(BLE_DFU_EVT_BOOTLOADER_ENTER_PREPARE);
|
||||
|
||||
err_code = ble_dfu_buttonless_bootloader_start_finalize();
|
||||
return err_code;
|
||||
}
|
||||
|
||||
#endif // NRF_DFU_BOTTONLESS_SUPPORT_BOND
|
||||
280
components/ble/ble_services/ble_dis/ble_dis.c
Normal file
280
components/ble/ble_services/ble_dis/ble_dis.c
Normal file
@@ -0,0 +1,280 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 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.
|
||||
*
|
||||
*/
|
||||
/* Attention!
|
||||
* To maintain compliance with Nordic Semiconductor ASA's Bluetooth profile
|
||||
* qualification listings, this section of source code must not be modified.
|
||||
*/
|
||||
#include "sdk_common.h"
|
||||
#if NRF_MODULE_ENABLED(BLE_DIS)
|
||||
#include "ble_dis.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "app_error.h"
|
||||
#include "ble_gatts.h"
|
||||
#include "ble_srv_common.h"
|
||||
|
||||
|
||||
#define BLE_DIS_SYS_ID_LEN 8 /**< Length of System ID Characteristic Value. */
|
||||
#define BLE_DIS_PNP_ID_LEN 7 /**< Length of Pnp ID Characteristic Value. */
|
||||
|
||||
static uint16_t service_handle;
|
||||
static ble_gatts_char_handles_t manufact_name_handles;
|
||||
static ble_gatts_char_handles_t model_num_handles;
|
||||
static ble_gatts_char_handles_t serial_num_handles;
|
||||
static ble_gatts_char_handles_t hw_rev_handles;
|
||||
static ble_gatts_char_handles_t fw_rev_handles;
|
||||
static ble_gatts_char_handles_t sw_rev_handles;
|
||||
static ble_gatts_char_handles_t sys_id_handles;
|
||||
static ble_gatts_char_handles_t reg_cert_data_list_handles;
|
||||
static ble_gatts_char_handles_t pnp_id_handles;
|
||||
|
||||
|
||||
/**@brief Function for encoding a System ID.
|
||||
*
|
||||
* @param[out] p_encoded_buffer Buffer where the encoded data will be written.
|
||||
* @param[in] p_sys_id System ID to be encoded.
|
||||
*/
|
||||
static void sys_id_encode(uint8_t * p_encoded_buffer, ble_dis_sys_id_t const * p_sys_id)
|
||||
{
|
||||
APP_ERROR_CHECK_BOOL(p_sys_id != NULL);
|
||||
APP_ERROR_CHECK_BOOL(p_encoded_buffer != NULL);
|
||||
|
||||
p_encoded_buffer[0] = (p_sys_id->manufacturer_id & 0x00000000FF);
|
||||
p_encoded_buffer[1] = (p_sys_id->manufacturer_id & 0x000000FF00) >> 8;
|
||||
p_encoded_buffer[2] = (p_sys_id->manufacturer_id & 0x0000FF0000) >> 16;
|
||||
p_encoded_buffer[3] = (p_sys_id->manufacturer_id & 0x00FF000000) >> 24;
|
||||
p_encoded_buffer[4] = (p_sys_id->manufacturer_id & 0xFF00000000) >> 32;
|
||||
|
||||
p_encoded_buffer[5] = (p_sys_id->organizationally_unique_id & 0x0000FF);
|
||||
p_encoded_buffer[6] = (p_sys_id->organizationally_unique_id & 0x00FF00) >> 8;
|
||||
p_encoded_buffer[7] = (p_sys_id->organizationally_unique_id & 0xFF0000) >> 16;
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for encoding a PnP ID.
|
||||
*
|
||||
* @param[out] p_encoded_buffer Buffer where the encoded data will be written.
|
||||
* @param[in] p_pnp_id PnP ID to be encoded.
|
||||
*/
|
||||
static void pnp_id_encode(uint8_t * p_encoded_buffer, ble_dis_pnp_id_t const * p_pnp_id)
|
||||
{
|
||||
uint8_t len = 0;
|
||||
|
||||
APP_ERROR_CHECK_BOOL(p_pnp_id != NULL);
|
||||
APP_ERROR_CHECK_BOOL(p_encoded_buffer != NULL);
|
||||
|
||||
p_encoded_buffer[len++] = p_pnp_id->vendor_id_source;
|
||||
|
||||
len += uint16_encode(p_pnp_id->vendor_id, &p_encoded_buffer[len]);
|
||||
len += uint16_encode(p_pnp_id->product_id, &p_encoded_buffer[len]);
|
||||
len += uint16_encode(p_pnp_id->product_version, &p_encoded_buffer[len]);
|
||||
|
||||
APP_ERROR_CHECK_BOOL(len == BLE_DIS_PNP_ID_LEN);
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for adding the Characteristic.
|
||||
*
|
||||
* @param[in] uuid UUID of characteristic to be added.
|
||||
* @param[in] p_char_value Initial value of characteristic to be added.
|
||||
* @param[in] char_len Length of initial value. This will also be the maximum value.
|
||||
* @param[in] rd_sec Security requirement for reading characteristic value.
|
||||
* @param[out] p_handles Handles of new characteristic.
|
||||
*
|
||||
* @return NRF_SUCCESS on success, otherwise an error code.
|
||||
*/
|
||||
static uint32_t char_add(uint16_t uuid,
|
||||
uint8_t * p_char_value,
|
||||
uint16_t char_len,
|
||||
security_req_t const rd_sec,
|
||||
ble_gatts_char_handles_t * p_handles)
|
||||
{
|
||||
ble_add_char_params_t add_char_params;
|
||||
|
||||
APP_ERROR_CHECK_BOOL(p_char_value != NULL);
|
||||
APP_ERROR_CHECK_BOOL(char_len > 0);
|
||||
|
||||
memset(&add_char_params, 0, sizeof(add_char_params));
|
||||
|
||||
add_char_params.uuid = uuid;
|
||||
add_char_params.max_len = char_len;
|
||||
add_char_params.init_len = char_len;
|
||||
add_char_params.p_init_value = p_char_value;
|
||||
add_char_params.char_props.read = 1;
|
||||
add_char_params.read_access = rd_sec;
|
||||
|
||||
return characteristic_add(service_handle, &add_char_params, p_handles);
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_dis_init(ble_dis_init_t const * p_dis_init)
|
||||
{
|
||||
uint32_t err_code;
|
||||
ble_uuid_t ble_uuid;
|
||||
|
||||
// Add service
|
||||
BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_DEVICE_INFORMATION_SERVICE);
|
||||
|
||||
err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &ble_uuid, &service_handle);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
|
||||
// Add characteristics
|
||||
if (p_dis_init->manufact_name_str.length > 0)
|
||||
{
|
||||
err_code = char_add(BLE_UUID_MANUFACTURER_NAME_STRING_CHAR,
|
||||
p_dis_init->manufact_name_str.p_str,
|
||||
p_dis_init->manufact_name_str.length,
|
||||
p_dis_init->dis_char_rd_sec,
|
||||
&manufact_name_handles);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
}
|
||||
if (p_dis_init->model_num_str.length > 0)
|
||||
{
|
||||
err_code = char_add(BLE_UUID_MODEL_NUMBER_STRING_CHAR,
|
||||
p_dis_init->model_num_str.p_str,
|
||||
p_dis_init->model_num_str.length,
|
||||
p_dis_init->dis_char_rd_sec,
|
||||
&model_num_handles);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
}
|
||||
if (p_dis_init->serial_num_str.length > 0)
|
||||
{
|
||||
err_code = char_add(BLE_UUID_SERIAL_NUMBER_STRING_CHAR,
|
||||
p_dis_init->serial_num_str.p_str,
|
||||
p_dis_init->serial_num_str.length,
|
||||
p_dis_init->dis_char_rd_sec,
|
||||
&serial_num_handles);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
}
|
||||
if (p_dis_init->hw_rev_str.length > 0)
|
||||
{
|
||||
err_code = char_add(BLE_UUID_HARDWARE_REVISION_STRING_CHAR,
|
||||
p_dis_init->hw_rev_str.p_str,
|
||||
p_dis_init->hw_rev_str.length,
|
||||
p_dis_init->dis_char_rd_sec,
|
||||
&hw_rev_handles);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
}
|
||||
if (p_dis_init->fw_rev_str.length > 0)
|
||||
{
|
||||
err_code = char_add(BLE_UUID_FIRMWARE_REVISION_STRING_CHAR,
|
||||
p_dis_init->fw_rev_str.p_str,
|
||||
p_dis_init->fw_rev_str.length,
|
||||
p_dis_init->dis_char_rd_sec,
|
||||
&fw_rev_handles);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
}
|
||||
if (p_dis_init->sw_rev_str.length > 0)
|
||||
{
|
||||
err_code = char_add(BLE_UUID_SOFTWARE_REVISION_STRING_CHAR,
|
||||
p_dis_init->sw_rev_str.p_str,
|
||||
p_dis_init->sw_rev_str.length,
|
||||
p_dis_init->dis_char_rd_sec,
|
||||
&sw_rev_handles);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
}
|
||||
if (p_dis_init->p_sys_id != NULL)
|
||||
{
|
||||
uint8_t encoded_sys_id[BLE_DIS_SYS_ID_LEN];
|
||||
|
||||
sys_id_encode(encoded_sys_id, p_dis_init->p_sys_id);
|
||||
err_code = char_add(BLE_UUID_SYSTEM_ID_CHAR,
|
||||
encoded_sys_id,
|
||||
BLE_DIS_SYS_ID_LEN,
|
||||
p_dis_init->dis_char_rd_sec,
|
||||
&sys_id_handles);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
}
|
||||
if (p_dis_init->p_reg_cert_data_list != NULL)
|
||||
{
|
||||
err_code = char_add(BLE_UUID_IEEE_REGULATORY_CERTIFICATION_DATA_LIST_CHAR,
|
||||
p_dis_init->p_reg_cert_data_list->p_list,
|
||||
p_dis_init->p_reg_cert_data_list->list_len,
|
||||
p_dis_init->dis_char_rd_sec,
|
||||
®_cert_data_list_handles);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
}
|
||||
if (p_dis_init->p_pnp_id != NULL)
|
||||
{
|
||||
uint8_t encoded_pnp_id[BLE_DIS_PNP_ID_LEN];
|
||||
|
||||
pnp_id_encode(encoded_pnp_id, p_dis_init->p_pnp_id);
|
||||
err_code = char_add(BLE_UUID_PNP_ID_CHAR,
|
||||
encoded_pnp_id,
|
||||
BLE_DIS_PNP_ID_LEN,
|
||||
p_dis_init->dis_char_rd_sec,
|
||||
&pnp_id_handles);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
}
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
#endif // NRF_MODULE_ENABLED(BLE_DIS)
|
||||
134
components/ble/ble_services/ble_dis/ble_dis.h
Normal file
134
components/ble/ble_services/ble_dis/ble_dis.h
Normal file
@@ -0,0 +1,134 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 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 ble_dis Device Information Service
|
||||
* @{
|
||||
* @ingroup ble_sdk_srv
|
||||
* @brief Device Information Service module.
|
||||
*
|
||||
* @details This module implements the Device Information Service.
|
||||
* During initialization it adds the Device Information Service to the BLE stack database.
|
||||
* It then encodes the supplied information, and adds the corresponding characteristics.
|
||||
*
|
||||
* @note Attention!
|
||||
* To maintain compliance with Nordic Semiconductor ASA Bluetooth profile
|
||||
* qualification listings, this section of source code must not be modified.
|
||||
*/
|
||||
|
||||
#ifndef BLE_DIS_H__
|
||||
#define BLE_DIS_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include "ble_srv_common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @defgroup DIS_VENDOR_ID_SRC_VALUES Vendor ID Source values
|
||||
* @{
|
||||
*/
|
||||
#define BLE_DIS_VENDOR_ID_SRC_BLUETOOTH_SIG 1 /**< Vendor ID assigned by Bluetooth SIG. */
|
||||
#define BLE_DIS_VENDOR_ID_SRC_USB_IMPL_FORUM 2 /**< Vendor ID assigned by USB Implementer's Forum. */
|
||||
/** @} */
|
||||
|
||||
/**@brief System ID parameters */
|
||||
typedef struct
|
||||
{
|
||||
uint64_t manufacturer_id; /**< Manufacturer ID. Only 5 LSOs shall be used. */
|
||||
uint32_t organizationally_unique_id; /**< Organizationally unique ID. Only 3 LSOs shall be used. */
|
||||
} ble_dis_sys_id_t;
|
||||
|
||||
/**@brief IEEE 11073-20601 Regulatory Certification Data List Structure */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t * p_list; /**< Pointer the byte array containing the encoded opaque structure based on IEEE 11073-20601 specification. */
|
||||
uint8_t list_len; /**< Length of the byte array. */
|
||||
} ble_dis_reg_cert_data_list_t;
|
||||
|
||||
/**@brief PnP ID parameters */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t vendor_id_source; /**< Vendor ID Source. see @ref DIS_VENDOR_ID_SRC_VALUES. */
|
||||
uint16_t vendor_id; /**< Vendor ID. */
|
||||
uint16_t product_id; /**< Product ID. */
|
||||
uint16_t product_version; /**< Product Version. */
|
||||
} ble_dis_pnp_id_t;
|
||||
|
||||
/**@brief Device Information Service init structure. This contains all possible characteristics
|
||||
* needed for initialization of the service.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
ble_srv_utf8_str_t manufact_name_str; /**< Manufacturer Name String. */
|
||||
ble_srv_utf8_str_t model_num_str; /**< Model Number String. */
|
||||
ble_srv_utf8_str_t serial_num_str; /**< Serial Number String. */
|
||||
ble_srv_utf8_str_t hw_rev_str; /**< Hardware Revision String. */
|
||||
ble_srv_utf8_str_t fw_rev_str; /**< Firmware Revision String. */
|
||||
ble_srv_utf8_str_t sw_rev_str; /**< Software Revision String. */
|
||||
ble_dis_sys_id_t * p_sys_id; /**< System ID. */
|
||||
ble_dis_reg_cert_data_list_t * p_reg_cert_data_list; /**< IEEE 11073-20601 Regulatory Certification Data List. */
|
||||
ble_dis_pnp_id_t * p_pnp_id; /**< PnP ID. */
|
||||
security_req_t dis_char_rd_sec; /**< Security requirement for reading any DIS characteristic value. */
|
||||
} ble_dis_init_t;
|
||||
|
||||
/**@brief Function for initializing the Device Information Service.
|
||||
*
|
||||
* @details This call allows the application to initialize the device information service.
|
||||
* It adds the DIS service and DIS characteristics to the database, using the initial
|
||||
* values supplied through the p_dis_init parameter. Characteristics which are not to be
|
||||
* added, shall be set to NULL in p_dis_init.
|
||||
*
|
||||
* @param[in] p_dis_init The structure containing the values of characteristics needed by the
|
||||
* service.
|
||||
*
|
||||
* @return NRF_SUCCESS on successful initialization of service.
|
||||
*/
|
||||
uint32_t ble_dis_init(ble_dis_init_t const * p_dis_init);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // BLE_DIS_H__
|
||||
|
||||
/** @} */
|
||||
516
components/ble/ble_services/ble_dis_c/ble_dis_c.c
Normal file
516
components/ble/ble_services/ble_dis_c/ble_dis_c.c
Normal file
@@ -0,0 +1,516 @@
|
||||
/**
|
||||
* 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_DIS_C)
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "ble.h"
|
||||
#include "ble_dis_c.h"
|
||||
#include "ble_gattc.h"
|
||||
#include "nrf_bitmask.h"
|
||||
#include "app_error.h"
|
||||
|
||||
#define NRF_LOG_MODULE_NAME ble_dis
|
||||
#include "nrf_log.h"
|
||||
NRF_LOG_MODULE_REGISTER();
|
||||
|
||||
|
||||
// Value Field lengths for System ID characteristic.
|
||||
#define BLE_DIS_C_MANUF_ID_LEN 5 /**< Length of Manufacturer ID field inside System ID characteristic. */
|
||||
#define BLE_DIS_C_OU_ID_LEN 3 /**< Length of Organizationally Unique ID field inside System ID characteristic. */
|
||||
|
||||
// Value Field lengths for PnP ID characteristic.
|
||||
#define BLE_DIS_C_VENDOR_ID_SRC_LEN 1 /**< Length of Vendor ID Source field inside PnP ID characteristic. */
|
||||
#define BLE_DIS_C_VENDOR_ID_LEN 2 /**< Length of Vendor ID field inside PnP ID characteristic. */
|
||||
#define BLE_DIS_C_PRODUCT_ID_LEN 2 /**< Length of Product ID field inside PnP ID characteristic. */
|
||||
#define BLE_DIS_C_PRODUCT_VER_LEN 2 /**< Length of Product Version field inside PnP ID characteristic. */
|
||||
|
||||
#define BLE_DIS_C_ALL_CHARS_DISABLED_MASK 0x0000 /**< All DIS characteristics should be disabled. */
|
||||
#define BLE_DIS_C_ALL_CHARS_ENABLED_MASK 0xFFFF /**< All DIS characteristics should be enabled. */
|
||||
|
||||
|
||||
/**@brief Function for interception of gattc errors.
|
||||
*
|
||||
* @param[in] nrf_error Error code returned by SoftDevice.
|
||||
* @param[in] p_contex Parameter from the event handler.
|
||||
* @param[in] conn_handle Connection handle.
|
||||
*/
|
||||
static void gatt_error_handler(uint32_t nrf_error, void * p_contex, uint16_t conn_handle)
|
||||
{
|
||||
UNUSED_PARAMETER(conn_handle);
|
||||
|
||||
ble_dis_c_t const * const p_ble_disc_c = (ble_dis_c_t *)p_contex;
|
||||
|
||||
if (p_ble_disc_c != NULL)
|
||||
{
|
||||
p_ble_disc_c->error_handler(nrf_error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for decoding System ID characteristic value.
|
||||
*
|
||||
* @param[in] p_data Pointer to System ID characteristic data.
|
||||
* @param[in] len Length of the System ID characteristic data.
|
||||
* @param[out] p_sys_id Decoded System ID characteristic.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the characteristic was initialized successfully.
|
||||
* @retval NRF_ERROR_INVALID_LENGTH Any parameter is NULL.
|
||||
*/
|
||||
static ret_code_t system_id_decode(uint8_t const * p_data,
|
||||
uint16_t len,
|
||||
ble_dis_sys_id_t * const p_sys_id)
|
||||
{
|
||||
uint16_t const expected_len = (BLE_DIS_C_MANUF_ID_LEN + BLE_DIS_C_OU_ID_LEN);
|
||||
|
||||
// Validate response length.
|
||||
if (expected_len != len)
|
||||
{
|
||||
NRF_LOG_ERROR("System ID characteristic data cannot be decoded.");
|
||||
NRF_LOG_ERROR("Expected data length != Received data length: %d != %d", expected_len, len);
|
||||
return NRF_ERROR_INVALID_LENGTH;
|
||||
}
|
||||
|
||||
// Decode Manufacturer ID.
|
||||
p_sys_id->manufacturer_id = uint40_decode(p_data);
|
||||
p_data += BLE_DIS_C_MANUF_ID_LEN;
|
||||
|
||||
// Decode Organizationally unique ID.
|
||||
p_sys_id->organizationally_unique_id = uint24_decode(p_data);
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for decoding PnP ID characteristic value.
|
||||
*
|
||||
* @param[in] p_data Pointer to PnP ID characteristic data.
|
||||
* @param[in] len Length of the PnP ID characteristic data.
|
||||
* @param[out] p_pnp_id Decoded PnP ID characteristic.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the characteristic was initialized successfully.
|
||||
* @retval NRF_ERROR_INVALID_LENGTH Any parameter is NULL.
|
||||
*/
|
||||
static ret_code_t pnp_id_decode(uint8_t const * p_data,
|
||||
uint16_t len,
|
||||
ble_dis_pnp_id_t * const p_pnp_id)
|
||||
{
|
||||
uint16_t const expected_len = (BLE_DIS_C_VENDOR_ID_SRC_LEN + BLE_DIS_C_VENDOR_ID_LEN +
|
||||
BLE_DIS_C_PRODUCT_ID_LEN + BLE_DIS_C_PRODUCT_VER_LEN);
|
||||
|
||||
// Validate response length.
|
||||
if (expected_len != len)
|
||||
{
|
||||
NRF_LOG_ERROR("PnP ID characteristic data cannot be decoded.");
|
||||
NRF_LOG_ERROR("Expected data length != Received data length: %d != %d", expected_len, len);
|
||||
return NRF_ERROR_INVALID_LENGTH;
|
||||
}
|
||||
|
||||
// Decode Vendor ID Source.
|
||||
p_pnp_id->vendor_id_source = p_data[0];
|
||||
p_data += BLE_DIS_C_VENDOR_ID_SRC_LEN;
|
||||
|
||||
// Decode Vendor ID.
|
||||
p_pnp_id->vendor_id = uint16_decode(p_data);
|
||||
p_data += BLE_DIS_C_VENDOR_ID_LEN;
|
||||
|
||||
// Decode Product ID.
|
||||
p_pnp_id->product_id = uint16_decode(p_data);
|
||||
p_data += BLE_DIS_C_PRODUCT_ID_LEN;
|
||||
|
||||
// Decode Product Version.
|
||||
p_pnp_id->product_version = uint16_decode(p_data);
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for matching DIS Client characteristic type with the provided response handle.
|
||||
*
|
||||
* @param[in] p_ble_dis_c Pointer to the Device Information Client Structure.
|
||||
* @param[in] response_handle Attribute handle from the response event.
|
||||
*/
|
||||
static ble_dis_c_char_type_t char_type_get(ble_dis_c_t * p_ble_dis_c, uint16_t response_handle)
|
||||
{
|
||||
for (ble_dis_c_char_type_t char_type = (ble_dis_c_char_type_t) 0;
|
||||
char_type < BLE_DIS_C_CHAR_TYPES_NUM;
|
||||
char_type++)
|
||||
{
|
||||
if (response_handle == p_ble_dis_c->handles[char_type])
|
||||
{
|
||||
return char_type;
|
||||
}
|
||||
}
|
||||
return BLE_DIS_C_CHAR_TYPES_NUM;
|
||||
}
|
||||
|
||||
|
||||
/**@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_ble_dis_c Pointer to the Device Information Client Structure.
|
||||
* @param[in] p_ble_evt Pointer to the SoftDevice event.
|
||||
*/
|
||||
static void on_read_rsp(ble_dis_c_t * p_ble_dis_c, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
ble_gattc_evt_read_rsp_t const * p_response = &p_ble_evt->evt.gattc_evt.params.read_rsp;
|
||||
ble_dis_c_evt_t ble_dis_c_evt;
|
||||
ble_dis_c_char_type_t char_type;
|
||||
|
||||
// Check if the event is on the link for this instance and the event handler is present.
|
||||
if ((p_ble_dis_c->evt_handler == NULL) ||
|
||||
(p_ble_dis_c->conn_handle != p_ble_evt->evt.gattc_evt.conn_handle))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
char_type = char_type_get(p_ble_dis_c, p_response->handle);
|
||||
if (char_type < BLE_DIS_C_CHAR_TYPES_NUM) // Characteristic type is valid.
|
||||
{
|
||||
memset(&ble_dis_c_evt, 0, sizeof(ble_dis_c_evt_t));
|
||||
|
||||
ble_dis_c_evt.conn_handle = p_ble_evt->evt.gattc_evt.conn_handle;
|
||||
|
||||
if (p_ble_evt->evt.gattc_evt.gatt_status == BLE_GATT_STATUS_SUCCESS)
|
||||
{
|
||||
ble_dis_c_evt_read_rsp_t * const p_dis_rsp = &ble_dis_c_evt.params.read_rsp;
|
||||
|
||||
ble_dis_c_evt.evt_type = BLE_DIS_C_EVT_DIS_C_READ_RSP;
|
||||
|
||||
p_dis_rsp->char_type = char_type;
|
||||
p_dis_rsp->handle = p_response->handle;
|
||||
|
||||
// Decode characteristic value.
|
||||
switch (char_type)
|
||||
{
|
||||
case BLE_DIS_C_MANUF_NAME:
|
||||
case BLE_DIS_C_MODEL_NUM:
|
||||
case BLE_DIS_C_SERIAL_NUM:
|
||||
case BLE_DIS_C_HW_REV:
|
||||
case BLE_DIS_C_FW_REV:
|
||||
case BLE_DIS_C_SW_REV:
|
||||
p_dis_rsp->content.string.p_data = (uint8_t *) p_response->data;
|
||||
p_dis_rsp->content.string.len = p_response->len;
|
||||
break;
|
||||
|
||||
case BLE_DIS_C_SYS_ID:
|
||||
err_code = system_id_decode(p_response->data,
|
||||
p_response->len,
|
||||
&p_dis_rsp->content.sys_id);
|
||||
if ((p_ble_dis_c->error_handler != NULL) && (err_code != NRF_SUCCESS))
|
||||
{
|
||||
p_ble_dis_c->error_handler(err_code);
|
||||
}
|
||||
break;
|
||||
|
||||
case BLE_DIS_C_CERT_LIST:
|
||||
p_dis_rsp->content.cert_list.p_list = (uint8_t *) p_response->data;
|
||||
p_dis_rsp->content.cert_list.list_len = p_response->len;
|
||||
break;
|
||||
|
||||
case BLE_DIS_C_PNP_ID:
|
||||
err_code = pnp_id_decode(p_response->data,
|
||||
p_response->len,
|
||||
&p_dis_rsp->content.pnp_id);
|
||||
if ((p_ble_dis_c->error_handler != NULL) && (err_code != NRF_SUCCESS))
|
||||
{
|
||||
p_ble_dis_c->error_handler(err_code);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
p_ble_dis_c->evt_handler(p_ble_dis_c, &ble_dis_c_evt);
|
||||
NRF_LOG_DEBUG("Received correct read response.");
|
||||
}
|
||||
else // Generate error event.
|
||||
{
|
||||
ble_dis_c_evt.evt_type = BLE_DIS_C_EVT_DIS_C_READ_RSP_ERROR;
|
||||
|
||||
ble_dis_c_evt.params.read_rsp_err.char_type = char_type;
|
||||
ble_dis_c_evt.params.read_rsp_err.err_handle = p_ble_evt->evt.gattc_evt.error_handle;
|
||||
ble_dis_c_evt.params.read_rsp_err.gatt_status = p_ble_evt->evt.gattc_evt.gatt_status;
|
||||
|
||||
p_ble_dis_c->evt_handler(p_ble_dis_c, &ble_dis_c_evt);
|
||||
NRF_LOG_ERROR("Read request failed: 0x%04X.", p_ble_evt->evt.gattc_evt.gatt_status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling Disconnected event received from the SoftDevice.
|
||||
*
|
||||
* @details This function checks if the disconnect event is happening on the link
|
||||
* associated with the current instance of the module. If so, it will set its
|
||||
* conn_handle to invalid.
|
||||
*
|
||||
* @param[in] p_ble_dis_c Pointer to the Device Information Client Structure.
|
||||
* @param[in] p_ble_evt Pointer to the BLE event received.
|
||||
*/
|
||||
static void on_disconnected(ble_dis_c_t * p_ble_dis_c, const ble_evt_t * p_ble_evt)
|
||||
{
|
||||
if (p_ble_dis_c->conn_handle == p_ble_evt->evt.gap_evt.conn_handle)
|
||||
{
|
||||
p_ble_dis_c->conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
|
||||
if (p_ble_dis_c->evt_handler != NULL)
|
||||
{
|
||||
ble_dis_c_evt_t dis_c_evt =
|
||||
{
|
||||
.evt_type = BLE_DIS_C_EVT_DISCONNECTED,
|
||||
.conn_handle = p_ble_evt->evt.gap_evt.conn_handle
|
||||
};
|
||||
|
||||
p_ble_dis_c->evt_handler(p_ble_dis_c, &dis_c_evt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ret_code_t ble_dis_c_init(ble_dis_c_t * p_ble_dis_c, ble_dis_c_init_t * p_ble_dis_c_init)
|
||||
{
|
||||
ble_uuid_t dis_uuid;
|
||||
|
||||
VERIFY_PARAM_NOT_NULL(p_ble_dis_c);
|
||||
VERIFY_PARAM_NOT_NULL(p_ble_dis_c_init);
|
||||
|
||||
dis_uuid.type = BLE_UUID_TYPE_BLE;
|
||||
dis_uuid.uuid = BLE_UUID_DEVICE_INFORMATION_SERVICE;
|
||||
|
||||
p_ble_dis_c->conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
p_ble_dis_c->p_gatt_queue = p_ble_dis_c_init->p_gatt_queue;
|
||||
p_ble_dis_c->evt_handler = p_ble_dis_c_init->evt_handler;
|
||||
p_ble_dis_c->error_handler = p_ble_dis_c_init->error_handler;
|
||||
memset(p_ble_dis_c->handles, BLE_GATT_HANDLE_INVALID, sizeof(p_ble_dis_c->handles));
|
||||
|
||||
// Enable only selected characteristics if characteristic group is defined.
|
||||
if (p_ble_dis_c_init->char_group.p_char_type != NULL)
|
||||
{
|
||||
p_ble_dis_c->char_mask = BLE_DIS_C_ALL_CHARS_DISABLED_MASK;
|
||||
|
||||
for (uint8_t i = 0; i < p_ble_dis_c_init->char_group.size; i++)
|
||||
{
|
||||
nrf_bitmask_bit_set(p_ble_dis_c_init->char_group.p_char_type[i],
|
||||
&p_ble_dis_c->char_mask);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
p_ble_dis_c->char_mask = BLE_DIS_C_ALL_CHARS_ENABLED_MASK;
|
||||
}
|
||||
|
||||
return ble_db_discovery_evt_register(&dis_uuid);
|
||||
}
|
||||
|
||||
|
||||
void ble_dis_c_on_db_disc_evt(ble_dis_c_t * p_ble_dis_c, ble_db_discovery_evt_t * p_evt)
|
||||
{
|
||||
ble_gatt_db_char_t * p_chars = p_evt->params.discovered_db.charateristics;
|
||||
ble_dis_c_evt_t ble_dis_c_evt;
|
||||
|
||||
// Check if the service discovery is necessary for the link and if the event handler is present.
|
||||
if ((p_ble_dis_c->evt_handler == NULL) ||
|
||||
(p_ble_dis_c->conn_handle == p_evt->conn_handle))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the DIS was discovered.
|
||||
if ((p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE) &&
|
||||
(p_evt->params.discovered_db.srv_uuid.uuid == BLE_UUID_DEVICE_INFORMATION_SERVICE) &&
|
||||
(p_evt->params.discovered_db.srv_uuid.type == BLE_UUID_TYPE_BLE))
|
||||
{
|
||||
memset(&ble_dis_c_evt, 0, sizeof(ble_dis_c_evt_t));
|
||||
ble_dis_c_evt.evt_type = BLE_DIS_C_EVT_DISCOVERY_COMPLETE;
|
||||
ble_dis_c_evt.conn_handle = p_evt->conn_handle;
|
||||
|
||||
for (uint32_t i = 0; i < p_evt->params.discovered_db.char_count; i++)
|
||||
{
|
||||
switch (p_chars[i].characteristic.uuid.uuid)
|
||||
{
|
||||
case BLE_UUID_MANUFACTURER_NAME_STRING_CHAR:
|
||||
ble_dis_c_evt.params.disc_complete.handles[BLE_DIS_C_MANUF_NAME] =
|
||||
p_chars[i].characteristic.handle_value;
|
||||
break;
|
||||
|
||||
case BLE_UUID_MODEL_NUMBER_STRING_CHAR:
|
||||
ble_dis_c_evt.params.disc_complete.handles[BLE_DIS_C_MODEL_NUM] =
|
||||
p_chars[i].characteristic.handle_value;
|
||||
break;
|
||||
|
||||
case BLE_UUID_SERIAL_NUMBER_STRING_CHAR:
|
||||
ble_dis_c_evt.params.disc_complete.handles[BLE_DIS_C_SERIAL_NUM] =
|
||||
p_chars[i].characteristic.handle_value;
|
||||
break;
|
||||
|
||||
case BLE_UUID_HARDWARE_REVISION_STRING_CHAR:
|
||||
ble_dis_c_evt.params.disc_complete.handles[BLE_DIS_C_HW_REV] =
|
||||
p_chars[i].characteristic.handle_value;
|
||||
break;
|
||||
|
||||
case BLE_UUID_FIRMWARE_REVISION_STRING_CHAR:
|
||||
ble_dis_c_evt.params.disc_complete.handles[BLE_DIS_C_FW_REV] =
|
||||
p_chars[i].characteristic.handle_value;
|
||||
break;
|
||||
|
||||
case BLE_UUID_SOFTWARE_REVISION_STRING_CHAR:
|
||||
ble_dis_c_evt.params.disc_complete.handles[BLE_DIS_C_SW_REV] =
|
||||
p_chars[i].characteristic.handle_value;
|
||||
break;
|
||||
|
||||
case BLE_UUID_SYSTEM_ID_CHAR:
|
||||
ble_dis_c_evt.params.disc_complete.handles[BLE_DIS_C_SYS_ID] =
|
||||
p_chars[i].characteristic.handle_value;
|
||||
break;
|
||||
|
||||
case BLE_UUID_IEEE_REGULATORY_CERTIFICATION_DATA_LIST_CHAR:
|
||||
ble_dis_c_evt.params.disc_complete.handles[BLE_DIS_C_CERT_LIST] =
|
||||
p_chars[i].characteristic.handle_value;
|
||||
break;
|
||||
|
||||
case BLE_UUID_PNP_ID_CHAR:
|
||||
ble_dis_c_evt.params.disc_complete.handles[BLE_DIS_C_PNP_ID] =
|
||||
p_chars[i].characteristic.handle_value;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Forget handle values for disabled characteristics
|
||||
for (ble_dis_c_char_type_t char_type = (ble_dis_c_char_type_t) 0;
|
||||
char_type < BLE_DIS_C_CHAR_TYPES_NUM;
|
||||
char_type++)
|
||||
{
|
||||
if (!nrf_bitmask_bit_is_set(char_type, &p_ble_dis_c->char_mask))
|
||||
{
|
||||
ble_dis_c_evt.params.disc_complete.handles[char_type] = BLE_GATT_HANDLE_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
p_ble_dis_c->evt_handler(p_ble_dis_c, &ble_dis_c_evt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ble_dis_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
|
||||
{
|
||||
ble_dis_c_t * p_ble_dis_c = (ble_dis_c_t *) p_context;
|
||||
|
||||
if ((p_ble_dis_c == NULL) || (p_ble_evt == NULL))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (p_ble_dis_c->conn_handle == BLE_CONN_HANDLE_INVALID)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch (p_ble_evt->header.evt_id)
|
||||
{
|
||||
case BLE_GATTC_EVT_READ_RSP:
|
||||
on_read_rsp(p_ble_dis_c, p_ble_evt);
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVT_DISCONNECTED:
|
||||
on_disconnected(p_ble_dis_c, p_ble_evt);
|
||||
break;
|
||||
|
||||
default:
|
||||
// No implementation needed.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ret_code_t ble_dis_c_read(ble_dis_c_t * p_ble_dis_c, ble_dis_c_char_type_t char_type)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
nrf_ble_gq_req_t dis_c_req;
|
||||
|
||||
VERIFY_PARAM_NOT_NULL(p_ble_dis_c);
|
||||
VERIFY_TRUE(char_type < BLE_DIS_C_CHAR_TYPES_NUM, NRF_ERROR_INVALID_PARAM);
|
||||
|
||||
if ((p_ble_dis_c->conn_handle == BLE_CONN_HANDLE_INVALID) ||
|
||||
(p_ble_dis_c->handles[char_type] == BLE_GATT_HANDLE_INVALID))
|
||||
{
|
||||
return NRF_ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
memset(&dis_c_req, 0, sizeof(dis_c_req));
|
||||
dis_c_req.type = NRF_BLE_GQ_REQ_GATTC_READ;
|
||||
dis_c_req.error_handler.cb = gatt_error_handler;
|
||||
dis_c_req.error_handler.p_ctx = p_ble_dis_c;
|
||||
dis_c_req.params.gattc_read.handle = p_ble_dis_c->handles[char_type];
|
||||
|
||||
err_code = nrf_ble_gq_item_add(p_ble_dis_c->p_gatt_queue, &dis_c_req, p_ble_dis_c->conn_handle);
|
||||
return err_code;
|
||||
}
|
||||
|
||||
|
||||
ret_code_t ble_dis_c_handles_assign(ble_dis_c_t * p_ble_dis_c,
|
||||
uint16_t conn_handle,
|
||||
ble_dis_c_handle_t const * p_peer_handles)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_ble_dis_c);
|
||||
|
||||
p_ble_dis_c->conn_handle = conn_handle;
|
||||
if (p_peer_handles != NULL)
|
||||
{
|
||||
memcpy(p_ble_dis_c->handles, p_peer_handles, sizeof(p_ble_dis_c->handles));
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(p_ble_dis_c->handles, BLE_GATT_HANDLE_INVALID, sizeof(p_ble_dis_c->handles));
|
||||
}
|
||||
return nrf_ble_gq_conn_handle_register(p_ble_dis_c->p_gatt_queue, conn_handle);
|
||||
}
|
||||
|
||||
|
||||
#endif // NRF_MODULE_ENABLED(BLE_DIS_C)
|
||||
|
||||
311
components/ble/ble_services/ble_dis_c/ble_dis_c.h
Normal file
311
components/ble/ble_services/ble_dis_c/ble_dis_c.h
Normal file
@@ -0,0 +1,311 @@
|
||||
/**
|
||||
* 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 ble_dis_c Device Information Service Client
|
||||
* @{
|
||||
* @ingroup ble_sdk_srv
|
||||
* @brief Device information Service Client module.
|
||||
*
|
||||
* @details This module contains the APIs and types exposed by the Device information Service Client
|
||||
* module. These APIs and types can be used by the application to perform discovery of
|
||||
* the Device information Service at the peer and interact with it.
|
||||
*
|
||||
* @note The application must register this module as BLE event observer using the
|
||||
* NRF_SDH_BLE_OBSERVER macro. Example:
|
||||
* @code
|
||||
* ble_dis_c_t instance;
|
||||
* NRF_SDH_BLE_OBSERVER(anything, BLE_DIS_C_BLE_OBSERVER_PRIO,
|
||||
* ble_dis_c_on_ble_evt, &instance);
|
||||
* @endcode
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BLE_DIS_C_H__
|
||||
#define BLE_DIS_C_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "ble.h"
|
||||
#include "ble_gatt.h"
|
||||
#include "ble_db_discovery.h"
|
||||
#include "ble_srv_common.h"
|
||||
#include "ble_dis.h"
|
||||
#include "nrf_ble_gq.h"
|
||||
#include "nrf_sdh_ble.h"
|
||||
|
||||
#include "sdk_config.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**@brief Macro for defining a ble_dis_c instance.
|
||||
*
|
||||
* @param _name Name of the instance.
|
||||
* @hideinitializer
|
||||
*/
|
||||
#define BLE_DIS_C_DEF(_name) \
|
||||
static ble_dis_c_t _name; \
|
||||
NRF_SDH_BLE_OBSERVER(_name ## _obs, \
|
||||
BLE_DIS_C_BLE_OBSERVER_PRIO, \
|
||||
ble_dis_c_on_ble_evt, &_name)
|
||||
|
||||
/** @brief Macro for defining multiple ble_dis_c instances.
|
||||
*
|
||||
* @param _name Name of the array of instances.
|
||||
* @param _cnt Number of instances to define.
|
||||
* @hideinitializer
|
||||
*/
|
||||
#define BLE_DIS_C_ARRAY_DEF(_name, _cnt) \
|
||||
static ble_dis_c_t _name[_cnt]; \
|
||||
NRF_SDH_BLE_OBSERVERS(_name ## _obs, \
|
||||
BLE_DIS_C_BLE_OBSERVER_PRIO, \
|
||||
ble_dis_c_on_ble_evt, &_name, _cnt)
|
||||
|
||||
|
||||
/**@brief DIS Client event type. */
|
||||
typedef enum
|
||||
{
|
||||
BLE_DIS_C_EVT_DISCOVERY_COMPLETE, /**< Event indicating that the DIS and its characteristics were discovered. See @ref ble_dis_c_evt_disc_complete_t. */
|
||||
BLE_DIS_C_EVT_DIS_C_READ_RSP, /**< Event indicating that the client has received a read response from a peer. See @ref ble_dis_c_evt_read_rsp_t. */
|
||||
BLE_DIS_C_EVT_DIS_C_READ_RSP_ERROR, /**< Event indicating that the client's read request has failed. See @ref ble_dis_c_evt_read_rsp_err_t. */
|
||||
BLE_DIS_C_EVT_DISCONNECTED /**< Event indicating that the DIS server has disconnected. */
|
||||
} ble_dis_c_evt_type_t;
|
||||
|
||||
/**@brief DIS Client characteristic type. */
|
||||
typedef enum
|
||||
{
|
||||
BLE_DIS_C_MANUF_NAME, /**< Manufacturer Name String characteristic. */
|
||||
BLE_DIS_C_MODEL_NUM, /**< Model Number String characteristic. */
|
||||
BLE_DIS_C_SERIAL_NUM, /**< Serial Number String characteristic. */
|
||||
BLE_DIS_C_HW_REV, /**< Hardware Revision String characteristic. */
|
||||
BLE_DIS_C_FW_REV, /**< Firmware Revision String characteristic. */
|
||||
BLE_DIS_C_SW_REV, /**< Software Revision String characteristic. */
|
||||
BLE_DIS_C_SYS_ID, /**< System ID characteristic. */
|
||||
BLE_DIS_C_CERT_LIST, /**< IEEE 11073-20601 Regulatory Certification Data List characteristic. */
|
||||
BLE_DIS_C_PNP_ID, /**< PnP ID characteristic. */
|
||||
BLE_DIS_C_CHAR_TYPES_NUM /**< Number of all possible characteristic types. */
|
||||
} ble_dis_c_char_type_t;
|
||||
|
||||
/**@brief Attribute handle pointing to DIS characteristics on the connected peer device. */
|
||||
typedef uint16_t ble_dis_c_handle_t;
|
||||
|
||||
/**@brief Event structure for @ref BLE_DIS_C_EVT_DISCOVERY_COMPLETE. */
|
||||
typedef struct
|
||||
{
|
||||
ble_dis_c_handle_t handles[BLE_DIS_C_CHAR_TYPES_NUM]; /**< Handles on the connected peer device needed to interact with it. */
|
||||
} ble_dis_c_evt_disc_complete_t;
|
||||
|
||||
/**@brief Response data for string-based DIS characteristics. */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t * p_data; /**< Pointer to response data. */
|
||||
uint8_t len; /**< Response data length. */
|
||||
} ble_dis_c_string_t;
|
||||
|
||||
/**@brief Event structure for @ref BLE_DIS_C_EVT_DIS_C_READ_RSP. */
|
||||
typedef struct
|
||||
{
|
||||
ble_dis_c_char_type_t char_type; /**< Characteristic type. */
|
||||
ble_dis_c_handle_t handle; /**< Attribute handle from the response event. */
|
||||
union
|
||||
{
|
||||
ble_dis_c_string_t string; /**< String-based characteristics response data. Filled when char_type is in the following range: @ref BLE_DIS_C_MANUF_NAME - @ref BLE_DIS_C_SW_REV (inclusive). */
|
||||
ble_dis_sys_id_t sys_id; /**< System ID characteristic response data. Filled when char_type is @ref BLE_DIS_C_SYS_ID. */
|
||||
ble_dis_reg_cert_data_list_t cert_list; /**< IEEE 11073-20601 Regulatory Certification Data List characteristic response data. Filled when char_type is @ref BLE_DIS_C_CERT_LIST. */
|
||||
ble_dis_pnp_id_t pnp_id; /**< PnP ID characteristic response data. Filled when char_type is @ref BLE_DIS_C_PNP_ID. */
|
||||
} content;
|
||||
} ble_dis_c_evt_read_rsp_t;
|
||||
|
||||
/**@brief Event structure for @ref BLE_DIS_C_EVT_DIS_C_READ_RSP_ERROR. */
|
||||
typedef struct
|
||||
{
|
||||
ble_dis_c_char_type_t char_type; /**< Characteristic type. */
|
||||
ble_dis_c_handle_t err_handle; /**< Attribute handle from the response event. */
|
||||
uint16_t gatt_status; /**< GATT status code for the read operation, see @ref BLE_GATT_STATUS_CODES. */
|
||||
} ble_dis_c_evt_read_rsp_err_t;
|
||||
|
||||
/**@brief Structure containing the DIS event data received from the peer. */
|
||||
typedef struct
|
||||
{
|
||||
ble_dis_c_evt_type_t evt_type; /**< Type of the event. */
|
||||
uint16_t conn_handle; /**< Connection handle on which the @ref ble_dis_c_evt_t event occurred.*/
|
||||
union
|
||||
{
|
||||
ble_dis_c_evt_disc_complete_t disc_complete; /**< Discovery Complete Event Parameters. Filled when evt_type is @ref BLE_DIS_C_EVT_DISCOVERY_COMPLETE. */
|
||||
ble_dis_c_evt_read_rsp_t read_rsp; /**< Read Response Event Parameters. Filled when evt_type is @ref BLE_DIS_C_EVT_DIS_C_READ_RSP. */
|
||||
ble_dis_c_evt_read_rsp_err_t read_rsp_err; /**< Read Response Error Event Parameters. Filled when evt_type is @ref BLE_DIS_C_EVT_DIS_C_READ_RSP_ERROR. */
|
||||
} params;
|
||||
} ble_dis_c_evt_t;
|
||||
|
||||
// Forward declaration of the ble_dis_t type.
|
||||
typedef struct ble_dis_c_s ble_dis_c_t;
|
||||
|
||||
/**@brief Event handler type.
|
||||
*
|
||||
* @details This is the type of the event handler that should be provided by the application
|
||||
* of this module to receive events.
|
||||
*/
|
||||
typedef void (* ble_dis_c_evt_handler_t)(ble_dis_c_t * p_ble_dis_c, ble_dis_c_evt_t const * p_evt);
|
||||
|
||||
/**@brief DIS Client structure. */
|
||||
struct ble_dis_c_s
|
||||
{
|
||||
uint16_t conn_handle; /**< Handle of the current connection. Set with @ref ble_dis_c_handles_assign when connected. */
|
||||
uint16_t char_mask; /**< Mask with enabled DIS characteristics.*/
|
||||
ble_dis_c_handle_t handles[BLE_DIS_C_CHAR_TYPES_NUM]; /**< Handles on the connected peer device needed to interact with it. */
|
||||
ble_srv_error_handler_t error_handler; /**< Application error handler to be called in case of an error. */
|
||||
ble_dis_c_evt_handler_t evt_handler; /**< Application event handler to be called when there is an event related to the DIS. */
|
||||
nrf_ble_gq_t * p_gatt_queue; /**< Pointer to BLE GATT Queue instance. */
|
||||
};
|
||||
|
||||
/**@brief Structure describing the group of DIS characteristics with which this module can interact. */
|
||||
typedef struct
|
||||
{
|
||||
ble_dis_c_char_type_t * p_char_type; /**< Pointer to array with selected characteristics. */
|
||||
uint8_t size; /**< Group size. */
|
||||
} ble_dis_c_char_group_t;
|
||||
|
||||
/**@brief DIS Client initialization structure. */
|
||||
typedef struct
|
||||
{
|
||||
ble_dis_c_char_group_t char_group; /**< Group of DIS characteristics that should be enabled for this module instance. */
|
||||
ble_srv_error_handler_t error_handler; /**< Application error handler to be called in case of an error. */
|
||||
ble_dis_c_evt_handler_t evt_handler; /**< Application event handler to be called when there is an event related to the Device Information service. */
|
||||
nrf_ble_gq_t * p_gatt_queue; /**< Pointer to BLE GATT Queue instance. */
|
||||
} ble_dis_c_init_t;
|
||||
|
||||
|
||||
/**@brief Function for initializing the Device Information service client module.
|
||||
*
|
||||
* @details This function registers with the Database Discovery module
|
||||
* for the DIS. Doing so will make the Database Discovery
|
||||
* module look for the presence of a DIS instance at the peer when a
|
||||
* discovery is started.
|
||||
*
|
||||
* @param[in] p_ble_dis_c Pointer to the DIS client structure.
|
||||
* @param[in] p_ble_dis_c_init Pointer to the DIS initialization structure containing the
|
||||
* initialization information.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the module was initialized successfully.
|
||||
* @retval NRF_ERROR_NULL Any parameter is NULL.
|
||||
* @return If functions from other modules return errors to this function
|
||||
* (@ref ble_db_discovery_evt_register), the @ref nrf_error are propagated.
|
||||
*/
|
||||
ret_code_t ble_dis_c_init(ble_dis_c_t * p_ble_dis_c, ble_dis_c_init_t * p_ble_dis_c_init);
|
||||
|
||||
|
||||
/**@brief Function for handling events from the database discovery module.
|
||||
*
|
||||
* @details This function will handle an event from the database discovery module, and determine
|
||||
* if it relates to the discovery of DIS at the peer. If so, it will
|
||||
* call the application's event handler indicating that DIS has been
|
||||
* discovered at the peer. It also populates the event with the service related
|
||||
* information before providing it to the application.
|
||||
*
|
||||
* @param[in] p_ble_dis_c Pointer to the DIS client structure.
|
||||
* @param[in] p_evt Pointer to the event received from the database discovery module.
|
||||
*/
|
||||
void ble_dis_c_on_db_disc_evt(ble_dis_c_t * p_ble_dis_c, ble_db_discovery_evt_t * p_evt);
|
||||
|
||||
|
||||
/**@brief Function for handling BLE events from the SoftDevice.
|
||||
*
|
||||
* @details This function handles the BLE events received from the SoftDevice. If a BLE
|
||||
* event is relevant to the DIS module, it is used to update internal variables
|
||||
* and, if necessary, send events to the application.
|
||||
*
|
||||
* @param[in] p_ble_evt Pointer to the BLE event.
|
||||
* @param[in] p_context Pointer to the DIS client structure.
|
||||
*/
|
||||
void ble_dis_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
|
||||
|
||||
|
||||
/**@brief Function for reading different characteristics from DIS.
|
||||
*
|
||||
* @details This function can be used to read different characteristics that are available
|
||||
* inside DIS. The response data will be provided from the response event
|
||||
* @ref BLE_DIS_C_EVT_DIS_C_READ_RSP. The @ref BLE_DIS_C_EVT_DIS_C_READ_RSP_ERROR
|
||||
* event can be generated if the read operation is unsuccessful.
|
||||
*
|
||||
* @param[in] p_ble_dis_c Pointer to the DIS client structure.
|
||||
* @param[in] char_type Type of characteristic to read.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the operation was successful.
|
||||
* @retval NRF_ERROR_NULL If a \p p_ble_dis_c was a NULL pointer.
|
||||
* @retval NRF_ERROR_INVALID_PARAM If a \p char_type is not valid.
|
||||
* @retval NRF_ERROR_INVALID_STATE If connection handle or attribute handle is invalid.
|
||||
* @retval NRF_ERROR_NO_MEM If the client request queue is full.
|
||||
*/
|
||||
ret_code_t ble_dis_c_read(ble_dis_c_t * p_ble_dis_c, ble_dis_c_char_type_t char_type);
|
||||
|
||||
|
||||
/**@brief Function for assigning handles to this instance of dis_c.
|
||||
*
|
||||
* @details Call this function when a link has been established with a peer to
|
||||
* associate this link to this instance of the module. This makes it
|
||||
* possible to handle several links and associate each link to a particular
|
||||
* instance of this module. The connection handle and attribute handles will be
|
||||
* provided from the discovery event @ref BLE_DIS_C_EVT_DISCOVERY_COMPLETE.
|
||||
*
|
||||
* @param[in] p_ble_dis_c Pointer to the DIS client structure instance to associate with these
|
||||
* handles.
|
||||
* @param[in] conn_handle Connection handle associated with the given DIS Instance.
|
||||
* @param[in] p_peer_handles Attribute handles on the DIS server that you want this DIS client to
|
||||
* interact with.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the operation was successful.
|
||||
* @retval NRF_ERROR_NULL If a \p p_ble_dis_c was a NULL pointer.
|
||||
*/
|
||||
ret_code_t ble_dis_c_handles_assign(ble_dis_c_t * p_ble_dis_c,
|
||||
uint16_t conn_handle,
|
||||
ble_dis_c_handle_t const * p_peer_handles);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // BLE_DIS_C_H__
|
||||
|
||||
/** @} */
|
||||
135
components/ble/ble_services/ble_escs/escs_defs.h
Normal file
135
components/ble/ble_services/ble_escs/escs_defs.h
Normal file
@@ -0,0 +1,135 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#ifndef ESCS_DEFS_H__
|
||||
#define ESCS_DEFS_H__
|
||||
|
||||
#include "es.h"
|
||||
|
||||
/*@file Contains definitions specific to the Eddystone Configuration Service */
|
||||
|
||||
#define ESCS_LOCK_STATE_NEW_LOCK_CODE_WRITE_LENGTH 17
|
||||
|
||||
#define ESCS_UID_READ_LENGTH (ES_UID_LENGTH)
|
||||
#define ESCS_UID_WRITE_LENGTH (ES_UID_NAMESPACE_LENGTH + \
|
||||
ES_UID_INSTANCE_LENGTH + ES_FRAME_TYPE_LENGTH)
|
||||
|
||||
#define ESCS_TLM_READ_LENGTH (ESCS_TLM_READ_LENGTH)
|
||||
#define ESCS_TLM_WRITE_LENGTH (ES_FRAME_TYPE_LENGTH)
|
||||
|
||||
#define ESCS_EID_READ_LENGTH (14)
|
||||
#define ESCS_EID_WRITE_ECDH_LENGTH (34)
|
||||
#define ESCS_EID_WRITE_PUB_KEY_INDEX (1)
|
||||
#define ESCS_EID_WRITE_ENC_ID_KEY_INDEX (1)
|
||||
#define ESCS_EID_WRITE_IDK_LENGTH (18)
|
||||
|
||||
#define ESCS_LOCK_STATE_READ_LENGTH (1)
|
||||
|
||||
#define ESCS_URL_MIN_WRITE_LENGTH (4)
|
||||
#define ESCS_URL_WRITE_LENGTH (19)
|
||||
|
||||
#ifdef NRF52_SERIES
|
||||
#define ESCS_NUM_OF_SUPPORTED_TX_POWER (9)
|
||||
/**@brief TX power levels, based on nRF52 specifications. */
|
||||
#define ESCS_SUPPORTED_TX_POWER {-40, -20, -16, -12, -8, -4, 0, 3, 4}
|
||||
#elif NRF51
|
||||
/**@brief TX power levels, based on nRF51 specifications. */
|
||||
#define ESCS_NUM_OF_SUPPORTED_TX_POWER (8)
|
||||
#define ESCS_SUPPORTED_TX_POWER {-30, -20, -16, -12, -8, -4, 0, 4}
|
||||
#else
|
||||
#error MISSING TX POWER
|
||||
#endif
|
||||
|
||||
// Defined in Eddystone Specifications
|
||||
#define ESCS_AES_KEY_SIZE (16)
|
||||
#define ESCS_ECDH_KEY_SIZE (32)
|
||||
|
||||
#define ESCS_ADV_SLOT_CHAR_LENGTH_MAX (34) // Corresponds to when the slots is configured as an EID slot
|
||||
|
||||
// Characteristic: Broadcast Capabilities
|
||||
|
||||
// Field: nrf_ble_escs_init_params_t.broadcast_cap.cap_bitfield
|
||||
#define ESCS_BROADCAST_VAR_ADV_SUPPORTED_Yes (1) // Set if the beacon supports individual per-slot adv intervals
|
||||
#define ESCS_BROADCAST_VAR_ADV_SUPPORTED_No (0)
|
||||
#define ESCS_BROADCAST_VAR_ADV_SUPPORTED_Pos (0)
|
||||
#define ESCS_BROADCAST_VAR_ADV_SUPPORTED_Msk (1 << ESCS_BROADCAST_VAR_ADV_SUPPORTED_Pos)
|
||||
#define ESCS_BROADCAST_VAR_TX_POWER_SUPPORTED_Yes (1) // Set if the beacon supports individual per-slot TX intervals
|
||||
#define ESCS_BROADCAST_VAR_TX_POWER_SUPPORTED_No (0)
|
||||
#define ESCS_BROADCAST_VAR_TX_POWER_SUPPORTED_Pos (1)
|
||||
#define ESCS_BROADCAST_VAR_TX_POWER_SUPPORTED_Msk (1 << ESCS_BROADCAST_VAR_TX_POWER_SUPPORTED_Pos)
|
||||
#define ESCS_BROADCAST_VAR_RFU_MASK (0x03) // AND Mask to guarantee that bits 0x04 to 0x80 (RFU) are cleared
|
||||
|
||||
// Field: nrf_ble_escs_init_params_t.broadcast_cap.supp_frame_types
|
||||
#define ESCS_FRAME_TYPE_UID_SUPPORTED_Yes (1)
|
||||
#define ESCS_FRAME_TYPE_UID_SUPPORTED_No (0)
|
||||
#define ESCS_FRAME_TYPE_UID_SUPPORTED_Pos (0)
|
||||
#define ESCS_FRAME_TYPE_UID_SUPPORTED_Msk (1 << ESCS_FRAME_TYPE_UID_SUPPORTED_Pos)
|
||||
|
||||
#define ESCS_FRAME_TYPE_URL_SUPPORTED_Yes (1)
|
||||
#define ESCS_FRAME_TYPE_URL_SUPPORTED_No (0)
|
||||
#define ESCS_FRAME_TYPE_URL_SUPPORTED_Pos (1)
|
||||
#define ESCS_FRAME_TYPE_URL_SUPPORTED_Msk (1 << ESCS_FRAME_TYPE_URL_SUPPORTED_Pos)
|
||||
|
||||
#define ESCS_FRAME_TYPE_TLM_SUPPORTED_Yes (1)
|
||||
#define ESCS_FRAME_TYPE_TLM_SUPPORTED_No (0)
|
||||
#define ESCS_FRAME_TYPE_TLM_SUPPORTED_Pos (2)
|
||||
#define ESCS_FRAME_TYPE_TLM_SUPPORTED_Msk (1 << ESCS_FRAME_TYPE_TLM_SUPPORTED_Pos)
|
||||
|
||||
#define ESCS_FRAME_TYPE_EID_SUPPORTED_Yes (1)
|
||||
#define ESCS_FRAME_TYPE_EID_SUPPORTED_No (0)
|
||||
#define ESCS_FRAME_TYPE_EID_SUPPORTED_Pos (3)
|
||||
#define ESCS_FRAME_TYPE_EID_SUPPORTED_Msk (1 << ESCS_FRAME_TYPE_EID_SUPPORTED_Pos)
|
||||
|
||||
#define ESCS_FRAME_TYPE_RFU_MASK (0x000F) // AND Mask to guarantee that bits 0x0010 to 0x8000 (RFU) are cleared
|
||||
|
||||
// Characteristic: Lock State: Lock State (READ)
|
||||
#define ESCS_LOCK_STATE_LOCKED (0x00)
|
||||
#define ESCS_LOCK_STATE_UNLOCKED (0x01)
|
||||
#define ESCS_LOCK_STATE_UNLOCKED_AUTO_RELOCK_DISABLED (0x02)
|
||||
|
||||
// Characteristic: Lock State: Lock Byte (WRITE)
|
||||
#define ESCS_LOCK_BYTE_LOCK (0x00)
|
||||
#define ESCS_LOCK_BYTE_DISABLE_AUTO_RELOCK (0x02)
|
||||
|
||||
|
||||
// Charcteristic: Remain Connectable
|
||||
#define ESCS_FUNCT_REMAIN_CONNECTABLE_SUPPORTED_Yes (0x01)
|
||||
#define ESCS_FUNCT_REMAIN_CONNECTABLE_SUPPORTED_No (0x00)
|
||||
|
||||
#endif // ESCS_DEFS_H__
|
||||
649
components/ble/ble_services/ble_escs/nrf_ble_escs.c
Normal file
649
components/ble/ble_services/ble_escs/nrf_ble_escs.c
Normal file
@@ -0,0 +1,649 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#include "nrf_ble_escs.h"
|
||||
#include <string.h>
|
||||
#include "es_app_config.h"
|
||||
|
||||
#ifdef BLE_HANDLER_DEBUG
|
||||
#include "SEGGER_RTT.h"
|
||||
#define DEBUG_PRINTF SEGGER_RTT_printf
|
||||
#else
|
||||
#define DEBUG_PRINTF(...)
|
||||
#endif
|
||||
|
||||
#define EID_BUFF_SIZE 64
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t val_handle;
|
||||
uint16_t uuid;
|
||||
} val_handle_to_uuid_t;
|
||||
|
||||
static ble_add_char_params_t BROADCAST_CAP_CHAR_INIT =
|
||||
{
|
||||
.uuid = BLE_UUID_ESCS_BROADCAST_CAP_CHAR,
|
||||
.read_access = SEC_OPEN,
|
||||
.char_props =
|
||||
{
|
||||
.read = 1,
|
||||
},
|
||||
.is_defered_read = true,
|
||||
.is_var_len = true,
|
||||
.init_len = NRF_BLE_ESCS_BROADCAST_CAP_LEN,
|
||||
.max_len = NRF_BLE_ESCS_BROADCAST_CAP_LEN,
|
||||
};
|
||||
|
||||
static ble_add_char_params_t ACTIVE_SLOT_CHAR_INIT =
|
||||
{
|
||||
.uuid = BLE_UUID_ESCS_ACTIVE_SLOT_CHAR,
|
||||
.read_access = SEC_OPEN,
|
||||
.write_access = SEC_OPEN,
|
||||
.char_props =
|
||||
{
|
||||
.read = 1,
|
||||
.write = 1,
|
||||
},
|
||||
.is_defered_read = true,
|
||||
.is_defered_write = true,
|
||||
.is_value_user = true,
|
||||
.init_len = sizeof(nrf_ble_escs_active_slot_t),
|
||||
.max_len = sizeof(nrf_ble_escs_active_slot_t),
|
||||
};
|
||||
|
||||
static ble_add_char_params_t ADV_INTERVAL_CHAR_INIT =
|
||||
{
|
||||
.uuid = BLE_UUID_ESCS_ADV_INTERVAL_CHAR,
|
||||
.read_access = SEC_OPEN,
|
||||
.write_access = SEC_OPEN,
|
||||
.char_props =
|
||||
{
|
||||
.read = 1,
|
||||
.write = 1,
|
||||
},
|
||||
.is_defered_read = true,
|
||||
.is_defered_write = true,
|
||||
.init_len = sizeof(nrf_ble_escs_adv_interval_t),
|
||||
.max_len = sizeof(nrf_ble_escs_adv_interval_t),
|
||||
};
|
||||
|
||||
static ble_add_char_params_t RADIO_TX_PWR_CHAR_INIT =
|
||||
{
|
||||
.uuid = BLE_UUID_ESCS_RADIO_TX_PWR_CHAR,
|
||||
.read_access = SEC_OPEN,
|
||||
.write_access = SEC_OPEN,
|
||||
.char_props =
|
||||
{
|
||||
.read = 1,
|
||||
.write = 1,
|
||||
},
|
||||
.is_defered_read = true,
|
||||
.is_defered_write = true,
|
||||
.init_len = sizeof(nrf_ble_escs_radio_tx_pwr_t),
|
||||
.max_len = sizeof(nrf_ble_escs_radio_tx_pwr_t),
|
||||
};
|
||||
|
||||
static ble_add_char_params_t ADV_TX_PWR_CHAR_INIT =
|
||||
{
|
||||
.uuid = BLE_UUID_ESCS_ADV_TX_PWR_CHAR,
|
||||
.read_access = SEC_OPEN,
|
||||
.write_access = SEC_OPEN,
|
||||
.char_props =
|
||||
{
|
||||
.read = 1,
|
||||
.write = 1,
|
||||
},
|
||||
.is_defered_read = true,
|
||||
.is_defered_write = true,
|
||||
.init_len = sizeof(nrf_ble_escs_adv_tx_pwr_t),
|
||||
.max_len = sizeof(nrf_ble_escs_adv_tx_pwr_t),
|
||||
};
|
||||
|
||||
static ble_add_char_params_t LOCK_STATE_CHAR_INIT =
|
||||
{
|
||||
.uuid = BLE_UUID_ESCS_LOCK_STATE_CHAR,
|
||||
.read_access = SEC_OPEN,
|
||||
.write_access = SEC_OPEN,
|
||||
.char_props =
|
||||
{
|
||||
.read = 1,
|
||||
.write = 1,
|
||||
},
|
||||
.is_defered_read = true,
|
||||
.is_defered_write = true,
|
||||
.is_var_len = true,
|
||||
.is_value_user = true,
|
||||
.init_len = 1,
|
||||
.max_len = 17,
|
||||
};
|
||||
|
||||
static ble_add_char_params_t UNLOCK_CHAR_INIT =
|
||||
{
|
||||
.uuid = BLE_UUID_ESCS_UNLOCK_CHAR,
|
||||
.read_access = SEC_OPEN,
|
||||
.write_access = SEC_OPEN,
|
||||
.char_props =
|
||||
{
|
||||
.read = 1,
|
||||
.write = 1,
|
||||
},
|
||||
.is_defered_read = true,
|
||||
.is_defered_write = true,
|
||||
.init_len = 1,
|
||||
.max_len = ESCS_AES_KEY_SIZE,
|
||||
};
|
||||
|
||||
static ble_add_char_params_t PUBLIC_ECDH_KEY_CHAR_INIT =
|
||||
{
|
||||
.uuid = BLE_UUID_ESCS_PUBLIC_ECDH_KEY_CHAR,
|
||||
.read_access = SEC_OPEN,
|
||||
.char_props =
|
||||
{
|
||||
.read = 1,
|
||||
},
|
||||
.is_defered_read = true,
|
||||
.is_var_len = true,
|
||||
.init_len = 1,
|
||||
.max_len = ESCS_ECDH_KEY_SIZE,
|
||||
};
|
||||
|
||||
static ble_add_char_params_t EID_ID_KEY_CHAR_INIT =
|
||||
{
|
||||
.uuid = BLE_UUID_ESCS_EID_ID_KEY_CHAR,
|
||||
.read_access = SEC_OPEN,
|
||||
.char_props =
|
||||
{
|
||||
.read = 1,
|
||||
},
|
||||
.is_defered_read = true,
|
||||
.is_var_len = true,
|
||||
.init_len = 1,
|
||||
.max_len = ESCS_AES_KEY_SIZE,
|
||||
};
|
||||
|
||||
static ble_add_char_params_t RW_ADV_SLOT_CHAR_INIT =
|
||||
{
|
||||
.uuid = BLE_UUID_ESCS_RW_ADV_SLOT_CHAR,
|
||||
.read_access = SEC_OPEN,
|
||||
.write_access = SEC_OPEN,
|
||||
.char_props =
|
||||
{
|
||||
.read = 1,
|
||||
.write = 1,
|
||||
},
|
||||
.is_defered_read = true,
|
||||
.is_defered_write = true,
|
||||
.is_var_len = true,
|
||||
.max_len = ESCS_ADV_SLOT_CHAR_LENGTH_MAX,
|
||||
};
|
||||
|
||||
static ble_add_char_params_t FACTORY_RESET_CHAR_INIT =
|
||||
{
|
||||
.uuid = BLE_UUID_ESCS_FACTORY_RESET_CHAR,
|
||||
.write_access = SEC_OPEN,
|
||||
.char_props =
|
||||
{
|
||||
.write = 1,
|
||||
},
|
||||
.is_defered_write = true,
|
||||
.init_len = sizeof(nrf_ble_escs_factory_reset_t),
|
||||
.max_len = sizeof(nrf_ble_escs_factory_reset_t),
|
||||
};
|
||||
|
||||
static ble_add_char_params_t REMAIN_CONNECTABLE_CHAR_INIT =
|
||||
{
|
||||
.uuid = BLE_UUID_ESCS_REMAIN_CONNECTABLE_CHAR,
|
||||
.read_access = SEC_OPEN,
|
||||
.write_access = SEC_OPEN,
|
||||
.char_props =
|
||||
{
|
||||
.read = 1,
|
||||
.write = 1,
|
||||
},
|
||||
.is_defered_read = true,
|
||||
.is_defered_write = true,
|
||||
.init_len = 1,
|
||||
.max_len = 1,
|
||||
};
|
||||
|
||||
static val_handle_to_uuid_t m_handle_to_uuid_map[BLE_ESCS_NUMBER_OF_CHARACTERISTICS]; //!< Map from handle to UUID.
|
||||
static uint8_t m_handle_to_uuid_map_idx = 0; //!< Index of map from handle to UUID.
|
||||
static uint8_t m_eid_mem[EID_BUFF_SIZE] = {0}; //!< Memory buffer used for EID writes.
|
||||
static ble_user_mem_block_t m_eid_mem_block =
|
||||
{
|
||||
.p_mem = m_eid_mem,
|
||||
.len = EID_BUFF_SIZE
|
||||
}; //!< Memory block used for EID writes.
|
||||
|
||||
|
||||
|
||||
/**@brief Function for adding characteristic to Eddystone service.
|
||||
*
|
||||
* @param[in] p_escs Eddystone Configuration Service structure.
|
||||
* @param[in] p_escs_init Information needed to initialize the service.
|
||||
* @param[in] p_char_init Information needed to initialize the characteristic.
|
||||
*
|
||||
* @return NRF_SUCCESS on success, otherwise an error code.
|
||||
*/
|
||||
static uint32_t char_add(ble_add_char_params_t * p_char_init,
|
||||
nrf_ble_escs_t * p_escs,
|
||||
void * p_value,
|
||||
ble_gatts_char_handles_t * p_handles)
|
||||
{
|
||||
uint32_t err_code;
|
||||
|
||||
VERIFY_PARAM_NOT_NULL(p_char_init);
|
||||
VERIFY_PARAM_NOT_NULL(p_escs);
|
||||
VERIFY_PARAM_NOT_NULL(p_value);
|
||||
VERIFY_PARAM_NOT_NULL(p_handles);
|
||||
|
||||
p_char_init->uuid_type = p_escs->uuid_type;
|
||||
p_char_init->p_init_value = p_value;
|
||||
|
||||
err_code = characteristic_add(p_escs->service_handle,
|
||||
p_char_init,
|
||||
p_handles);
|
||||
|
||||
if (err_code == NRF_SUCCESS)
|
||||
{
|
||||
ASSERT(m_handle_to_uuid_map_idx < BLE_ESCS_NUMBER_OF_CHARACTERISTICS);
|
||||
m_handle_to_uuid_map[m_handle_to_uuid_map_idx].val_handle = p_handles->value_handle;
|
||||
m_handle_to_uuid_map[m_handle_to_uuid_map_idx].uuid = p_char_init->uuid;
|
||||
m_handle_to_uuid_map_idx++;
|
||||
}
|
||||
|
||||
return err_code;
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling the @ref BLE_GAP_EVT_CONNECTED event from the SoftDevice.
|
||||
*
|
||||
* @param[in] p_escs Eddystone Configuration Service structure.
|
||||
* @param[in] p_ble_evt Pointer to the event received from BLE stack.
|
||||
*/
|
||||
static void on_connect(nrf_ble_escs_t * p_escs, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL_VOID(p_escs);
|
||||
p_escs->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling the @ref BLE_GAP_EVT_DISCONNECTED event from the SoftDevice.
|
||||
*
|
||||
* @param[in] p_escs Eddystone Configuration Service structure.
|
||||
* @param[in] p_ble_evt Pointer to the event received from BLE stack.
|
||||
*/
|
||||
static void on_disconnect(nrf_ble_escs_t * p_escs, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL_VOID(p_escs);
|
||||
UNUSED_PARAMETER(p_ble_evt);
|
||||
p_escs->conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
}
|
||||
|
||||
|
||||
static uint32_t get_evt_type_for_handle(uint16_t handle, uint16_t * p_uuid)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_uuid);
|
||||
|
||||
for (uint8_t i = 0; i < BLE_ESCS_NUMBER_OF_CHARACTERISTICS; ++i)
|
||||
{
|
||||
if (m_handle_to_uuid_map[i].val_handle == handle)
|
||||
{
|
||||
*p_uuid = m_handle_to_uuid_map[i].uuid;
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return NRF_ERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
/**@brief Function for handling the @ref BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST: BLE_GATTS_AUTHORIZE_TYPE_WRITE event from the SoftDevice.
|
||||
*
|
||||
* @param[in] p_escs Eddystone Configuration Service structure.
|
||||
* @param[in] p_ble_evt Pointer to the event received from BLE stack.
|
||||
*/
|
||||
static ret_code_t on_write(nrf_ble_escs_t * p_escs, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
uint32_t err_code;
|
||||
uint16_t write_evt_uuid = 0;
|
||||
|
||||
VERIFY_PARAM_NOT_NULL(p_escs);
|
||||
VERIFY_PARAM_NOT_NULL(p_ble_evt);
|
||||
|
||||
ble_gatts_evt_write_t const * p_evt_write =
|
||||
&p_ble_evt->evt.gatts_evt.params.authorize_request.request.write;
|
||||
|
||||
err_code = get_evt_type_for_handle(p_evt_write->handle, &write_evt_uuid);
|
||||
RETURN_IF_ERROR(err_code);
|
||||
|
||||
p_escs->write_evt_handler(p_escs,
|
||||
write_evt_uuid,
|
||||
p_evt_write->handle,
|
||||
p_evt_write->data,
|
||||
p_evt_write->len);
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling the @ref BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST: BLE_GATTS_AUTHORIZE_TYPE_WRITE: event from the SoftDevice.
|
||||
*
|
||||
* @param[in] p_escs Eddystone Configuration Service structure.
|
||||
* @param[in] p_ble_evt Pointer to the event received from BLE stack.
|
||||
*/
|
||||
static void on_long_write(nrf_ble_escs_t * p_escs, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
static uint16_t write_evt_uuid;
|
||||
static bool write_evt_uuid_set = false;
|
||||
uint32_t err_code;
|
||||
|
||||
VERIFY_PARAM_NOT_NULL_VOID(p_escs);
|
||||
VERIFY_PARAM_NOT_NULL_VOID(p_ble_evt);
|
||||
|
||||
ble_gatts_evt_write_t const * p_evt_write =
|
||||
&p_ble_evt->evt.gatts_evt.params.authorize_request.request.write;
|
||||
|
||||
ble_gatts_rw_authorize_reply_params_t reply = {0};
|
||||
|
||||
if (p_evt_write->op == BLE_GATTS_OP_PREP_WRITE_REQ)
|
||||
{
|
||||
err_code = get_evt_type_for_handle(p_evt_write->handle, &write_evt_uuid);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
write_evt_uuid_set = true;
|
||||
|
||||
reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE;
|
||||
reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
|
||||
reply.params.write.update = 0;
|
||||
reply.params.write.offset = 0;
|
||||
reply.params.write.len = p_evt_write->len;
|
||||
reply.params.write.p_data = NULL;
|
||||
|
||||
err_code = sd_ble_gatts_rw_authorize_reply(p_escs->conn_handle, &reply);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
|
||||
else if (p_evt_write->op == BLE_GATTS_OP_EXEC_WRITE_REQ_NOW)
|
||||
{
|
||||
uint8_t value_buffer[ESCS_ADV_SLOT_CHAR_LENGTH_MAX] = {0};
|
||||
ble_gatts_value_t value =
|
||||
{
|
||||
.len = sizeof(value_buffer),
|
||||
.offset = 0,
|
||||
.p_value = &(value_buffer[0])
|
||||
};
|
||||
|
||||
ASSERT(write_evt_uuid_set);
|
||||
write_evt_uuid_set = false;
|
||||
|
||||
reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE;
|
||||
reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
|
||||
reply.params.write.update = 0;
|
||||
reply.params.write.offset = 0;
|
||||
reply.params.write.len = p_evt_write->len;
|
||||
reply.params.write.p_data = NULL;
|
||||
|
||||
err_code = sd_ble_gatts_rw_authorize_reply(p_escs->conn_handle, &reply);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
// Now that the value has been accepted using 'sd_ble_gatts_rw_authorize_reply', it can be found in the database.
|
||||
err_code = sd_ble_gatts_value_get( p_escs->conn_handle,
|
||||
p_escs->rw_adv_slot_handles.value_handle,
|
||||
&value);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
p_escs->write_evt_handler(p_escs,
|
||||
write_evt_uuid,
|
||||
p_evt_write->handle,
|
||||
value.p_value,
|
||||
value.len);
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling events from the SoftDevice related to long writes.
|
||||
*
|
||||
* @param[in] p_escs Eddystone Configuration Service structure.
|
||||
* @param[in] p_ble_evt Pointer to the event received from BLE stack.
|
||||
*/
|
||||
static ret_code_t on_read(nrf_ble_escs_t * p_escs, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_escs);
|
||||
VERIFY_PARAM_NOT_NULL(p_ble_evt);
|
||||
ret_code_t err_code;
|
||||
uint16_t read_evt_uuid = 0;
|
||||
uint16_t val_handle = p_ble_evt->evt.gatts_evt.params.authorize_request.request.read.handle;
|
||||
err_code = get_evt_type_for_handle(val_handle, &read_evt_uuid);
|
||||
RETURN_IF_ERROR(err_code);
|
||||
|
||||
p_escs->read_evt_handler(p_escs, read_evt_uuid, val_handle);
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static ret_code_t on_rw_authorize_req(nrf_ble_escs_t * p_escs, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
VERIFY_PARAM_NOT_NULL(p_escs);
|
||||
VERIFY_PARAM_NOT_NULL(p_ble_evt);
|
||||
|
||||
ble_gatts_evt_rw_authorize_request_t const * ar =
|
||||
&p_ble_evt->evt.gatts_evt.params.authorize_request;
|
||||
|
||||
if (ar->type == BLE_GATTS_AUTHORIZE_TYPE_READ)
|
||||
{
|
||||
err_code = on_read(p_escs, p_ble_evt);
|
||||
RETURN_IF_ERROR(err_code);
|
||||
}
|
||||
else if (ar->type == BLE_GATTS_AUTHORIZE_TYPE_WRITE)
|
||||
{
|
||||
if (ar->request.write.op == BLE_GATTS_OP_WRITE_REQ
|
||||
|| ar->request.write.op == BLE_GATTS_OP_WRITE_CMD)
|
||||
{
|
||||
err_code = on_write(p_escs, p_ble_evt);
|
||||
RETURN_IF_ERROR(err_code);
|
||||
}
|
||||
|
||||
else if (ar->request.write.op == BLE_GATTS_OP_PREP_WRITE_REQ
|
||||
|| ar->request.write.op == BLE_GATTS_OP_EXEC_WRITE_REQ_NOW)
|
||||
{
|
||||
on_long_write(p_escs, p_ble_evt);
|
||||
}
|
||||
else if (ar->request.write.op == BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL)
|
||||
{
|
||||
ble_gatts_rw_authorize_reply_params_t auth_reply;
|
||||
memset(&auth_reply, 0, sizeof(auth_reply));
|
||||
|
||||
auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE;
|
||||
auth_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
|
||||
|
||||
err_code = sd_ble_gatts_rw_authorize_reply(p_ble_evt->evt.gatts_evt.conn_handle, &auth_reply);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return NRF_ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
ret_code_t nrf_ble_escs_on_ble_evt(nrf_ble_escs_t * p_escs, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
|
||||
VERIFY_PARAM_NOT_NULL(p_escs);
|
||||
VERIFY_PARAM_NOT_NULL(p_ble_evt);
|
||||
|
||||
switch (p_ble_evt->header.evt_id)
|
||||
{
|
||||
case BLE_GAP_EVT_CONNECTED:
|
||||
on_connect(p_escs, p_ble_evt);
|
||||
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVT_DISCONNECTED:
|
||||
on_disconnect(p_escs, p_ble_evt);
|
||||
break;
|
||||
|
||||
case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST:
|
||||
err_code = on_rw_authorize_req(p_escs, p_ble_evt);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
break;
|
||||
|
||||
// BLE_EVT_USER_MEM_REQUEST & BLE_EVT_USER_MEM_RELEASE are for long writes to the RW ADV slot characteristic
|
||||
case BLE_EVT_USER_MEM_REQUEST:
|
||||
err_code = sd_ble_user_mem_reply(p_escs->conn_handle, &m_eid_mem_block);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
break;
|
||||
|
||||
case BLE_EVT_USER_MEM_RELEASE:
|
||||
break;
|
||||
|
||||
default:
|
||||
// No implementation needed.
|
||||
break;
|
||||
}
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
ret_code_t nrf_ble_escs_init(nrf_ble_escs_t * p_escs, const nrf_ble_escs_init_t * p_escs_init)
|
||||
{
|
||||
uint32_t err_code;
|
||||
ble_uuid_t ble_uuid;
|
||||
ble_uuid128_t ecs_base_uuid = ESCS_BASE_UUID;
|
||||
uint8_t zero_val = 0;
|
||||
|
||||
VERIFY_PARAM_NOT_NULL(p_escs);
|
||||
VERIFY_PARAM_NOT_NULL(p_escs_init);
|
||||
|
||||
// Initialize the service structure.
|
||||
p_escs->conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
p_escs->write_evt_handler = p_escs_init->write_evt_handler;
|
||||
p_escs->read_evt_handler = p_escs_init->read_evt_handler;
|
||||
|
||||
// Add a custom base UUID.
|
||||
err_code = sd_ble_uuid_vs_add(&ecs_base_uuid, &p_escs->uuid_type);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
ble_uuid.type = p_escs->uuid_type;
|
||||
ble_uuid.uuid = BLE_UUID_ESCS_SERVICE;
|
||||
|
||||
// Add the service.
|
||||
err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
|
||||
&ble_uuid,
|
||||
&p_escs->service_handle);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
m_handle_to_uuid_map_idx = 0;
|
||||
|
||||
// Set up initial values for characteristics
|
||||
|
||||
// Eddystone spec requires big endian
|
||||
nrf_ble_escs_broadcast_cap_t temp = p_escs_init->p_init_vals->broadcast_cap;
|
||||
temp.supp_frame_types = BYTES_SWAP_16BIT(temp.supp_frame_types);
|
||||
|
||||
nrf_ble_escs_adv_interval_t temp_interval = p_escs_init->p_init_vals->adv_interval;
|
||||
temp_interval = BYTES_SWAP_16BIT(temp_interval);
|
||||
|
||||
// Adding chracteristics
|
||||
|
||||
err_code = char_add(&BROADCAST_CAP_CHAR_INIT, p_escs,
|
||||
&temp, &p_escs->broadcast_cap_handles);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
err_code = char_add(&ACTIVE_SLOT_CHAR_INIT, p_escs,
|
||||
p_escs->p_active_slot, &p_escs->active_slot_handles);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
err_code = char_add(&ADV_INTERVAL_CHAR_INIT, p_escs,
|
||||
&temp_interval, &p_escs->adv_interval_handles);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
err_code = char_add(&RADIO_TX_PWR_CHAR_INIT, p_escs,
|
||||
&(p_escs_init->p_init_vals->radio_tx_pwr), &p_escs->radio_tx_pwr_handles);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
err_code = char_add(&ADV_TX_PWR_CHAR_INIT, p_escs,
|
||||
&(p_escs_init->p_init_vals->adv_tx_pwr), &p_escs->adv_tx_pwr_handles);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
err_code = char_add(&LOCK_STATE_CHAR_INIT, p_escs,
|
||||
&p_escs->lock_state, &p_escs->lock_state_handles);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
err_code = char_add(&UNLOCK_CHAR_INIT, p_escs,
|
||||
&zero_val, &p_escs->unlock_handles);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
err_code = char_add(&PUBLIC_ECDH_KEY_CHAR_INIT, p_escs,
|
||||
&zero_val, &p_escs->pub_ecdh_key_handles);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
err_code = char_add(&EID_ID_KEY_CHAR_INIT, p_escs,
|
||||
&zero_val, &p_escs->eid_id_key_handles);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
err_code = char_add(&RW_ADV_SLOT_CHAR_INIT, p_escs,
|
||||
&zero_val, &p_escs->rw_adv_slot_handles);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
err_code = char_add(&FACTORY_RESET_CHAR_INIT, p_escs,
|
||||
&(p_escs_init->p_init_vals->factory_reset), &p_escs->factory_reset_handles);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
err_code = char_add(&REMAIN_CONNECTABLE_CHAR_INIT, p_escs,
|
||||
&(p_escs_init->p_init_vals->remain_connectable.r_is_non_connectable_supported),
|
||||
&p_escs->remain_connectable_handles);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
259
components/ble/ble_services/ble_escs/nrf_ble_escs.h
Normal file
259
components/ble/ble_services/ble_escs/nrf_ble_escs.h
Normal file
@@ -0,0 +1,259 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#ifndef NRF_BLE_ESCS_H__
|
||||
#define NRF_BLE_ESCS_H__
|
||||
|
||||
#include "ble.h"
|
||||
#include "ble_srv_common.h"
|
||||
#include "app_util_platform.h"
|
||||
#include "sdk_common.h"
|
||||
#include "escs_defs.h"
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @defgroup nrf_ble_escs Eddystone Configuration Service
|
||||
* @brief Eddystone Configuration Service module.
|
||||
* @ingroup ble_sdk_srv
|
||||
* @{
|
||||
*/
|
||||
|
||||
#define BLE_ESCS_NUMBER_OF_CHARACTERISTICS 13 //!< Number of characteristics contained in the Eddystone Configuration Service.
|
||||
|
||||
#define BLE_UUID_ESCS_SERVICE 0x7500 //!< UUID of the Eddystone Configuration Service.
|
||||
|
||||
// ECS UUIDs
|
||||
#define BLE_UUID_ESCS_BROADCAST_CAP_CHAR 0x7501
|
||||
#define BLE_UUID_ESCS_ACTIVE_SLOT_CHAR 0x7502
|
||||
#define BLE_UUID_ESCS_ADV_INTERVAL_CHAR 0x7503
|
||||
#define BLE_UUID_ESCS_RADIO_TX_PWR_CHAR 0x7504
|
||||
#define BLE_UUID_ESCS_ADV_TX_PWR_CHAR 0x7505
|
||||
#define BLE_UUID_ESCS_LOCK_STATE_CHAR 0x7506
|
||||
#define BLE_UUID_ESCS_UNLOCK_CHAR 0x7507
|
||||
#define BLE_UUID_ESCS_PUBLIC_ECDH_KEY_CHAR 0x7508
|
||||
#define BLE_UUID_ESCS_EID_ID_KEY_CHAR 0x7509
|
||||
#define BLE_UUID_ESCS_RW_ADV_SLOT_CHAR 0x750A
|
||||
#define BLE_UUID_ESCS_FACTORY_RESET_CHAR 0x750B
|
||||
#define BLE_UUID_ESCS_REMAIN_CONNECTABLE_CHAR 0x750C
|
||||
|
||||
#define ESCS_BASE_UUID \
|
||||
{{0x95, 0xE2, 0xED, 0xEB, 0x1B, 0xA0, 0x39, 0x8A, 0xDF, 0x4B, 0xD3, 0x8E, 0x00, 0x00, 0xC8, \
|
||||
0xA3}}
|
||||
// A3C8XXXX-8ED3-4BDF-8A39-A01BEBEDE295
|
||||
|
||||
#define NRF_BLE_ESCS_BROADCAST_CAP_LEN (ESCS_NUM_OF_SUPPORTED_TX_POWER + 6) // According to the eddystone spec, there are 6 bytes of data in addition to the supported_radio_tx_power array
|
||||
|
||||
|
||||
/**@brief Data fields in the Broadcast Capabilities characteristic.
|
||||
* @note This is a packed structure. Therefore, you should not change it.
|
||||
*/
|
||||
typedef PACKED_STRUCT
|
||||
{
|
||||
int8_t vers_byte;
|
||||
int8_t max_supp_total_slots;
|
||||
int8_t max_supp_eid_slots;
|
||||
int8_t cap_bitfield;
|
||||
int16_t supp_frame_types;
|
||||
int8_t supp_radio_tx_power[ESCS_NUM_OF_SUPPORTED_TX_POWER];
|
||||
} nrf_ble_escs_broadcast_cap_t;
|
||||
|
||||
typedef uint8_t nrf_ble_escs_active_slot_t;
|
||||
typedef uint16_t nrf_ble_escs_adv_interval_t;
|
||||
typedef int8_t nrf_ble_escs_radio_tx_pwr_t;
|
||||
typedef int8_t nrf_ble_escs_adv_tx_pwr_t;
|
||||
|
||||
/**@brief Read states of the Lock State characteristic. */
|
||||
typedef enum
|
||||
{
|
||||
NRF_BLE_ESCS_LOCK_STATE_LOCKED = ESCS_LOCK_STATE_LOCKED,
|
||||
NRF_BLE_ESCS_LOCK_STATE_UNLOCKED = ESCS_LOCK_STATE_UNLOCKED,
|
||||
NRF_BLE_ESCS_LOCK_STATE_UNLOCKED_AUTO_RELOCK_DISABLED =
|
||||
ESCS_LOCK_STATE_UNLOCKED_AUTO_RELOCK_DISABLED
|
||||
} nrf_ble_escs_lock_state_read_t;
|
||||
|
||||
/**@brief Write bytes of the Lock State characteristic. */
|
||||
typedef enum
|
||||
{
|
||||
NRF_BLE_ESCS_LOCK_BYTE_LOCK = ESCS_LOCK_BYTE_LOCK,
|
||||
NRF_BLE_ESCS_LOCK_BYTE_DISABLE_AUTO_RELOCK = ESCS_LOCK_BYTE_DISABLE_AUTO_RELOCK
|
||||
} nrf_ble_escs_lock_byte_t;
|
||||
|
||||
/**@brief Write data fields of the Lock State characteristic.
|
||||
* @note This is a packed structure. Therefore, you should not change it.
|
||||
*/
|
||||
typedef PACKED_STRUCT
|
||||
{
|
||||
nrf_ble_escs_lock_byte_t lock_byte;
|
||||
int8_t encrypted_key[ESCS_AES_KEY_SIZE];
|
||||
} nrf_ble_escs_lock_state_write_t;
|
||||
|
||||
/**@brief Lock State characteristic. */
|
||||
typedef union
|
||||
{
|
||||
nrf_ble_escs_lock_state_read_t read;
|
||||
nrf_ble_escs_lock_state_write_t write;
|
||||
} nrf_ble_escs_lock_state_t;
|
||||
|
||||
/**@brief Unlock characteristic (read/write). */
|
||||
typedef union
|
||||
{
|
||||
int8_t r_challenge[ESCS_AES_KEY_SIZE];
|
||||
int8_t w_unlock_token[ESCS_AES_KEY_SIZE];
|
||||
} nrf_ble_escs_unlock_t;
|
||||
|
||||
/**@brief Public ECDH Key characteristic.
|
||||
* @note This is a packed structure. Therefore, you should not change it.
|
||||
*/
|
||||
typedef PACKED_STRUCT
|
||||
{
|
||||
int8_t key[ESCS_ECDH_KEY_SIZE];
|
||||
} nrf_ble_escs_public_ecdh_key_t;
|
||||
|
||||
/**@brief EID Identity Key characteristic.
|
||||
* @note This is a packed structure. Therefore, you should not change it.
|
||||
*/
|
||||
typedef PACKED_STRUCT
|
||||
{
|
||||
int8_t key[ESCS_AES_KEY_SIZE];
|
||||
} nrf_ble_escs_eid_id_key_t;
|
||||
|
||||
|
||||
typedef uint8_t nrf_ble_escs_factory_reset_t;
|
||||
|
||||
/**@brief Unlock characteristic (read/write). */
|
||||
typedef union
|
||||
{
|
||||
uint8_t r_is_non_connectable_supported;
|
||||
uint8_t w_remain_connectable_boolean;
|
||||
} nrf_ble_escs_remain_conntbl_t;
|
||||
|
||||
/**@brief Eddystone Configuration Service initialization parameters (corresponding to required characteristics). */
|
||||
typedef struct
|
||||
{
|
||||
nrf_ble_escs_broadcast_cap_t broadcast_cap;
|
||||
nrf_ble_escs_adv_interval_t adv_interval;
|
||||
nrf_ble_escs_radio_tx_pwr_t radio_tx_pwr;
|
||||
nrf_ble_escs_adv_tx_pwr_t adv_tx_pwr;
|
||||
nrf_ble_escs_factory_reset_t factory_reset;
|
||||
nrf_ble_escs_remain_conntbl_t remain_connectable;
|
||||
} nrf_ble_escs_init_params_t;
|
||||
|
||||
// Forward Declaration of nrf_ble_escs_t type.
|
||||
typedef struct nrf_ble_escs_s nrf_ble_escs_t;
|
||||
|
||||
typedef void (*nrf_ble_escs_write_evt_handler_t)(nrf_ble_escs_t * p_escs,
|
||||
uint16_t uuid,
|
||||
uint16_t value_handle,
|
||||
uint8_t const * p_data,
|
||||
uint16_t length);
|
||||
|
||||
typedef void (*nrf_ble_escs_read_evt_handler_t)(nrf_ble_escs_t * p_escs,
|
||||
uint16_t uuid,
|
||||
uint16_t value_handle);
|
||||
|
||||
/**@brief Eddystone Configuration Service initialization structure.
|
||||
*
|
||||
* @details This structure contains the initialization information for the service. The application
|
||||
* must fill this structure and pass it to the service using the @ref nrf_ble_escs_init
|
||||
* function.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
nrf_ble_escs_init_params_t * p_init_vals; //!< Initialization parameters for the service.
|
||||
nrf_ble_escs_write_evt_handler_t write_evt_handler; //!< Event handler to be called for authorizing write requests.
|
||||
nrf_ble_escs_read_evt_handler_t read_evt_handler; //!< Event handler to be called for authorizing read requests.
|
||||
} nrf_ble_escs_init_t;
|
||||
|
||||
struct nrf_ble_escs_s
|
||||
{
|
||||
uint8_t uuid_type; //!< UUID type for the Eddystone Configuration Service Base UUID.
|
||||
uint16_t service_handle; //!< Handle of the Eddystone Configuration Service (as provided by the SoftDevice).
|
||||
ble_gatts_char_handles_t broadcast_cap_handles; //!< Handles related to the Capabilities characteristic (as provided by the SoftDevice).
|
||||
ble_gatts_char_handles_t active_slot_handles; //!< Handles related to the Active Slot characteristic (as provided by the SoftDevice).
|
||||
ble_gatts_char_handles_t adv_interval_handles; //!< Handles related to the Advertising Interval characteristic (as provided by the SoftDevice).
|
||||
ble_gatts_char_handles_t radio_tx_pwr_handles; //!< Handles related to the Radio Tx Power characteristic (as provided by the SoftDevice).
|
||||
ble_gatts_char_handles_t adv_tx_pwr_handles; //!< Handles related to the (Advanced) Advertised Tx Power characteristic (as provided by the SoftDevice).
|
||||
ble_gatts_char_handles_t lock_state_handles; //!< Handles related to the Lock State characteristic (as provided by the SoftDevice).
|
||||
ble_gatts_char_handles_t unlock_handles; //!< Handles related to the Unlock characteristic (as provided by the SoftDevice).
|
||||
ble_gatts_char_handles_t pub_ecdh_key_handles; //!< Handles related to the Public ECDH Key characteristic (as provided by the SoftDevice).
|
||||
ble_gatts_char_handles_t eid_id_key_handles; //!< Handles related to the EID Identity Key characteristic (as provided by the SoftDevice).
|
||||
ble_gatts_char_handles_t rw_adv_slot_handles; //!< Handles related to the ADV Slot Data characteristic (as provided by the SoftDevice).
|
||||
ble_gatts_char_handles_t factory_reset_handles; //!< Handles related to the (Advanced) Factory reset characteristic (as provided by the SoftDevice).
|
||||
ble_gatts_char_handles_t remain_connectable_handles; //!< Handles related to the (Advanced) Remain Connectable characteristic (as provided by the SoftDevice).
|
||||
uint16_t conn_handle; //!< Handle of the current connection (as provided by the SoftDevice). @ref BLE_CONN_HANDLE_INVALID if not in a connection.
|
||||
nrf_ble_escs_write_evt_handler_t write_evt_handler; //!< Event handler to be called for handling write attempts.
|
||||
nrf_ble_escs_read_evt_handler_t read_evt_handler; //!< Event handler to be called for handling read attempts.
|
||||
uint8_t * p_active_slot;
|
||||
uint8_t lock_state;
|
||||
};
|
||||
|
||||
|
||||
/**@brief Function for initializing the Eddystone Configuration Service.
|
||||
*
|
||||
* @param[out] p_escs Eddystone Configuration 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_ecs_init Information needed to initialize the service.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the service was successfully initialized. Otherwise, an error code is returned.
|
||||
* @retval NRF_ERROR_NULL If either of the pointers @p p_escs or @p p_ecs_init is NULL.
|
||||
*/
|
||||
ret_code_t nrf_ble_escs_init(nrf_ble_escs_t * p_escs, const nrf_ble_escs_init_t * p_ecs_init);
|
||||
|
||||
/**@brief Function for handling the Eddystone Configuration Service's BLE events.
|
||||
*
|
||||
* @details The Eddystone Configuration Service expects the application to call this function each time an
|
||||
* event is received from the SoftDevice. This function processes the event if it
|
||||
* is relevant and calls the Eddystone Configuration Service event handler of the
|
||||
* application if necessary.
|
||||
*
|
||||
* @param[in] p_escs Eddystone Configuration Service structure.
|
||||
* @param[in] p_ble_evt Event received from the SoftDevice.
|
||||
*
|
||||
* @retval NRF_ERROR_NULL If any of the arguments given are NULL.
|
||||
* @retval NRF_SUCCESS otherwise.
|
||||
*/
|
||||
ret_code_t nrf_ble_escs_on_ble_evt(nrf_ble_escs_t * p_escs, ble_evt_t const * p_ble_evt);
|
||||
|
||||
/** @} */
|
||||
|
||||
#endif // NRF_BLE_ESCS_H__
|
||||
1121
components/ble/ble_services/ble_gls/ble_gls.c
Normal file
1121
components/ble/ble_services/ble_gls/ble_gls.c
Normal file
File diff suppressed because it is too large
Load Diff
330
components/ble/ble_services/ble_gls/ble_gls.h
Normal file
330
components/ble/ble_services/ble_gls/ble_gls.h
Normal file
@@ -0,0 +1,330 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 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 ble_gls Glucose Service
|
||||
* @{
|
||||
* @ingroup ble_sdk_srv
|
||||
* @brief Glucose Service module.
|
||||
*
|
||||
* @details This module implements the Glucose Service.
|
||||
*
|
||||
* @note The application must register this module as BLE event observer using the
|
||||
* NRF_SDH_BLE_OBSERVER macro. Example:
|
||||
* @code
|
||||
* ble_gls_t instance;
|
||||
* NRF_SDH_BLE_OBSERVER(anything, BLE_GLS_BLE_OBSERVER_PRIO,
|
||||
* ble_gls_on_ble_evt, &instance);
|
||||
* @endcode
|
||||
*
|
||||
* @note Attention!
|
||||
* To maintain compliance with Nordic Semiconductor ASA Bluetooth profile
|
||||
* qualification listings, this section of source code must not be modified.
|
||||
*/
|
||||
|
||||
#ifndef BLE_GLS_H__
|
||||
#define BLE_GLS_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "ble.h"
|
||||
#include "ble_srv_common.h"
|
||||
#include "ble_date_time.h"
|
||||
#include "nrf_ble_gq.h"
|
||||
#include "nrf_sdh_ble.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**@brief Macro for defining a ble_gls instance.
|
||||
*
|
||||
* @param _name Name of the instance.
|
||||
* @hideinitializer
|
||||
*/
|
||||
#define BLE_GLS_DEF(_name) \
|
||||
static ble_gls_t _name; \
|
||||
NRF_SDH_BLE_OBSERVER(_name ## _obs, \
|
||||
BLE_GLS_BLE_OBSERVER_PRIO, \
|
||||
ble_gls_on_ble_evt, &_name)
|
||||
|
||||
|
||||
/**@brief Glucose feature */
|
||||
#define BLE_GLS_FEATURE_LOW_BATT 0x0001 /**< Low Battery Detection During Measurement Supported */
|
||||
#define BLE_GLS_FEATURE_MALFUNC 0x0002 /**< Sensor Malfunction Detection Supported */
|
||||
#define BLE_GLS_FEATURE_SAMPLE_SIZE 0x0004 /**< Sensor Sample Size Supported */
|
||||
#define BLE_GLS_FEATURE_INSERT_ERR 0x0008 /**< Sensor Strip Insertion Error Detection Supported */
|
||||
#define BLE_GLS_FEATURE_TYPE_ERR 0x0010 /**< Sensor Strip Type Error Detection Supported */
|
||||
#define BLE_GLS_FEATURE_RES_HIGH_LOW 0x0020 /**< Sensor Result High-Low Detection Supported */
|
||||
#define BLE_GLS_FEATURE_TEMP_HIGH_LOW 0x0040 /**< Sensor Temperature High-Low Detection Supported */
|
||||
#define BLE_GLS_FEATURE_READ_INT 0x0080 /**< Sensor Read Interrupt Detection Supported */
|
||||
#define BLE_GLS_FEATURE_GENERAL_FAULT 0x0100 /**< General Device Fault Supported */
|
||||
#define BLE_GLS_FEATURE_TIME_FAULT 0x0200 /**< Time Fault Supported */
|
||||
#define BLE_GLS_FEATURE_MULTI_BOND 0x0400 /**< Multiple Bond Supported */
|
||||
|
||||
/**@brief Glucose measurement flags */
|
||||
#define BLE_GLS_MEAS_FLAG_TIME_OFFSET 0x01 /**< Time Offset Present */
|
||||
#define BLE_GLS_MEAS_FLAG_CONC_TYPE_LOC 0x02 /**< Glucose Concentration, Type, and Sample Location Present */
|
||||
#define BLE_GLS_MEAS_FLAG_UNITS_KG_L 0x00 /**< Glucose Concentration Units kg/L */
|
||||
#define BLE_GLS_MEAS_FLAG_UNITS_MOL_L 0x04 /**< Glucose Concentration Units mol/L */
|
||||
#define BLE_GLS_MEAS_FLAG_SENSOR_STATUS 0x08 /**< Sensor Status Annunciation Present */
|
||||
#define BLE_GLS_MEAS_FLAG_CONTEXT_INFO 0x10 /**< Context Information Follows */
|
||||
|
||||
/**@brief Glucose measurement type */
|
||||
#define BLE_GLS_MEAS_TYPE_CAP_BLOOD 1 /**< Capillary whole blood */
|
||||
#define BLE_GLS_MEAS_TYPE_CAP_PLASMA 2 /**< Capillary plasma */
|
||||
#define BLE_GLS_MEAS_TYPE_VEN_BLOOD 3 /**< Venous whole blood */
|
||||
#define BLE_GLS_MEAS_TYPE_VEN_PLASMA 4 /**< Venous plasma */
|
||||
#define BLE_GLS_MEAS_TYPE_ART_BLOOD 5 /**< Arterial whole blood */
|
||||
#define BLE_GLS_MEAS_TYPE_ART_PLASMA 6 /**< Arterial plasma */
|
||||
#define BLE_GLS_MEAS_TYPE_UNDET_BLOOD 7 /**< Undetermined whole blood */
|
||||
#define BLE_GLS_MEAS_TYPE_UNDET_PLASMA 8 /**< Undetermined plasma */
|
||||
#define BLE_GLS_MEAS_TYPE_FLUID 9 /**< Interstitial fluid (ISF) */
|
||||
#define BLE_GLS_MEAS_TYPE_CONTROL 10 /**< Control solution */
|
||||
|
||||
/**@brief Glucose measurement location */
|
||||
#define BLE_GLS_MEAS_LOC_FINGER 1 /**< Finger */
|
||||
#define BLE_GLS_MEAS_LOC_AST 2 /**< Alternate Site Test (AST) */
|
||||
#define BLE_GLS_MEAS_LOC_EAR 3 /**< Earlobe */
|
||||
#define BLE_GLS_MEAS_LOC_CONTROL 4 /**< Control solution */
|
||||
#define BLE_GLS_MEAS_LOC_NOT_AVAIL 15 /**< Sample Location value not available */
|
||||
|
||||
/**@brief Glucose sensor status annunciation */
|
||||
#define BLE_GLS_MEAS_STATUS_BATT_LOW 0x0001 /**< Device battery low at time of measurement */
|
||||
#define BLE_GLS_MEAS_STATUS_SENSOR_FAULT 0x0002 /**< Sensor malfunction or faulting at time of measurement */
|
||||
#define BLE_GLS_MEAS_STATUS_SAMPLE_SIZE 0x0004 /**< Sample size for blood or control solution insufficient at time of measurement */
|
||||
#define BLE_GLS_MEAS_STATUS_STRIP_INSERT 0x0008 /**< Strip insertion error */
|
||||
#define BLE_GLS_MEAS_STATUS_STRIP_TYPE 0x0010 /**< Strip type incorrect for device */
|
||||
#define BLE_GLS_MEAS_STATUS_RESULT_HIGH 0x0020 /**< Sensor result higher than the device can process */
|
||||
#define BLE_GLS_MEAS_STATUS_RESULT_LOW 0x0040 /**< Sensor result lower than the device can process */
|
||||
#define BLE_GLS_MEAS_STATUS_TEMP_HIGH 0x0080 /**< Sensor temperature too high for valid test/result at time of measurement */
|
||||
#define BLE_GLS_MEAS_STATUS_TEMP_LOW 0x0100 /**< Sensor temperature too low for valid test/result at time of measurement */
|
||||
#define BLE_GLS_MEAS_STATUS_STRIP_PULL 0x0200 /**< Sensor read interrupted because strip was pulled too soon at time of measurement */
|
||||
#define BLE_GLS_MEAS_STATUS_GENERAL_FAULT 0x0400 /**< General device fault has occurred in the sensor */
|
||||
#define BLE_GLS_MEAS_STATUS_TIME_FAULT 0x0800 /**< Time fault has occurred in the sensor and time may be inaccurate */
|
||||
|
||||
/**@brief Glucose measurement context flags */
|
||||
#define BLE_GLS_CONTEXT_FLAG_CARB 0x01 /**< Carbohydrate id and carbohydrate present */
|
||||
#define BLE_GLS_CONTEXT_FLAG_MEAL 0x02 /**< Meal present */
|
||||
#define BLE_GLS_CONTEXT_FLAG_TESTER 0x04 /**< Tester-health present */
|
||||
#define BLE_GLS_CONTEXT_FLAG_EXERCISE 0x08 /**< Exercise duration and exercise intensity present */
|
||||
#define BLE_GLS_CONTEXT_FLAG_MED 0x10 /**< Medication ID and medication present */
|
||||
#define BLE_GLS_CONTEXT_FLAG_MED_KG 0x00 /**< Medication value units, kilograms */
|
||||
#define BLE_GLS_CONTEXT_FLAG_MED_L 0x20 /**< Medication value units, liters */
|
||||
#define BLE_GLS_CONTEXT_FLAG_HBA1C 0x40 /**< Hba1c present */
|
||||
#define BLE_GLS_CONTEXT_FLAG_EXT 0x80 /**< Extended flags present */
|
||||
|
||||
/**@brief Glucose measurement context carbohydrate ID */
|
||||
#define BLE_GLS_CONTEXT_CARB_BREAKFAST 1 /**< Breakfast */
|
||||
#define BLE_GLS_CONTEXT_CARB_LUNCH 2 /**< Lunch */
|
||||
#define BLE_GLS_CONTEXT_CARB_DINNER 3 /**< Dinner */
|
||||
#define BLE_GLS_CONTEXT_CARB_SNACK 4 /**< Snack */
|
||||
#define BLE_GLS_CONTEXT_CARB_DRINK 5 /**< Drink */
|
||||
#define BLE_GLS_CONTEXT_CARB_SUPPER 6 /**< Supper */
|
||||
#define BLE_GLS_CONTEXT_CARB_BRUNCH 7 /**< Brunch */
|
||||
|
||||
/**@brief Glucose measurement context meal */
|
||||
#define BLE_GLS_CONTEXT_MEAL_PREPRANDIAL 1 /**< Preprandial (before meal) */
|
||||
#define BLE_GLS_CONTEXT_MEAL_POSTPRANDIAL 2 /**< Postprandial (after meal) */
|
||||
#define BLE_GLS_CONTEXT_MEAL_FASTING 3 /**< Fasting */
|
||||
#define BLE_GLS_CONTEXT_MEAL_CASUAL 4 /**< Casual (snacks, drinks, etc.) */
|
||||
#define BLE_GLS_CONTEXT_MEAL_BEDTIME 5 /**< Bedtime */
|
||||
|
||||
/**@brief Glucose measurement context tester */
|
||||
#define BLE_GLS_CONTEXT_TESTER_SELF 1 /**< Self */
|
||||
#define BLE_GLS_CONTEXT_TESTER_PRO 2 /**< Health care professional */
|
||||
#define BLE_GLS_CONTEXT_TESTER_LAB 3 /**< Lab test */
|
||||
#define BLE_GLS_CONTEXT_TESTER_NOT_AVAIL 15 /**< Tester value not available */
|
||||
|
||||
/**@brief Glucose measurement context health */
|
||||
#define BLE_GLS_CONTEXT_HEALTH_MINOR 1 /**< Minor health issues */
|
||||
#define BLE_GLS_CONTEXT_HEALTH_MAJOR 2 /**< Major health issues */
|
||||
#define BLE_GLS_CONTEXT_HEALTH_MENSES 3 /**< During menses */
|
||||
#define BLE_GLS_CONTEXT_HEALTH_STRESS 4 /**< Under stress */
|
||||
#define BLE_GLS_CONTEXT_HEALTH_NONE 5 /**< No health issues */
|
||||
#define BLE_GLS_CONTEXT_HEALTH_NOT_AVAIL 15 /**< Health value not available */
|
||||
|
||||
/**@brief Glucose measurement context medication ID */
|
||||
#define BLE_GLS_CONTEXT_MED_RAPID 1 /**< Rapid acting insulin */
|
||||
#define BLE_GLS_CONTEXT_MED_SHORT 2 /**< Short acting insulin */
|
||||
#define BLE_GLS_CONTEXT_MED_INTERMED 3 /**< Intermediate acting insulin */
|
||||
#define BLE_GLS_CONTEXT_MED_LONG 4 /**< Long acting insulin */
|
||||
#define BLE_GLS_CONTEXT_MED_PREMIX 5 /**< Pre-mixed insulin */
|
||||
|
||||
|
||||
/**@brief SFLOAT format (IEEE-11073 16-bit FLOAT, meaning 4 bits for exponent (base 10) and 12 bits mantissa) */
|
||||
typedef struct
|
||||
{
|
||||
int8_t exponent; /**< Base 10 exponent, should be using only 4 bits */
|
||||
int16_t mantissa; /**< Mantissa, should be using only 12 bits */
|
||||
} sfloat_t;
|
||||
|
||||
/**@brief Glucose Service event type. */
|
||||
typedef enum
|
||||
{
|
||||
BLE_GLS_EVT_NOTIFICATION_ENABLED, /**< Glucose value notification enabled event. */
|
||||
BLE_GLS_EVT_NOTIFICATION_DISABLED /**< Glucose value notification disabled event. */
|
||||
} ble_gls_evt_type_t;
|
||||
|
||||
/**@brief Glucose Service event. */
|
||||
typedef struct
|
||||
{
|
||||
ble_gls_evt_type_t evt_type; /**< Type of event. */
|
||||
} ble_gls_evt_t;
|
||||
|
||||
// Forward declaration of the ble_gls_t type.
|
||||
typedef struct ble_gls_s ble_gls_t;
|
||||
|
||||
/**@brief Glucose Service event handler type. */
|
||||
typedef void (*ble_gls_evt_handler_t)(ble_gls_t * p_gls, ble_gls_evt_t * p_evt);
|
||||
|
||||
/**@brief Glucose Measurement structure. This contains glucose measurement value. */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t flags; /**< Flags */
|
||||
uint16_t sequence_number; /**< Sequence number */
|
||||
ble_date_time_t base_time; /**< Time stamp */
|
||||
int16_t time_offset; /**< Time offset */
|
||||
sfloat_t glucose_concentration; /**< Glucose concentration */
|
||||
uint8_t type; /**< Type */
|
||||
uint8_t sample_location; /**< Sample location */
|
||||
uint16_t sensor_status_annunciation; /**< Sensor status annunciation */
|
||||
} ble_gls_meas_t;
|
||||
|
||||
/**@brief Glucose measurement context structure */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t flags; /**< Flags */
|
||||
uint8_t extended_flags; /**< Extended Flags */
|
||||
uint8_t carbohydrate_id; /**< Carbohydrate ID */
|
||||
sfloat_t carbohydrate; /**< Carbohydrate */
|
||||
uint8_t meal; /**< Meal */
|
||||
uint8_t tester_and_health; /**< Tester and health */
|
||||
uint16_t exercise_duration; /**< Exercise Duration */
|
||||
uint8_t exercise_intensity; /**< Exercise Intensity */
|
||||
uint8_t medication_id; /**< Medication ID */
|
||||
sfloat_t medication; /**< Medication */
|
||||
uint16_t hba1c; /**< HbA1c */
|
||||
} ble_gls_meas_context_t;
|
||||
|
||||
/**@brief Glucose measurement record */
|
||||
typedef struct
|
||||
{
|
||||
ble_gls_meas_t meas; /**< Glucose measurement */
|
||||
ble_gls_meas_context_t context; /**< Glucose measurement context */
|
||||
} ble_gls_rec_t;
|
||||
|
||||
/**@brief Glucose Service init structure. This contains all options and data needed for
|
||||
* initialization of the service. */
|
||||
typedef struct
|
||||
{
|
||||
ble_gls_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Glucose Service. */
|
||||
ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
|
||||
uint16_t feature; /**< Glucose Feature value indicating supported features. */
|
||||
bool is_context_supported; /**< Determines if optional Glucose Measurement Context is to be supported. */
|
||||
security_req_t gl_meas_cccd_wr_sec; /**< Security requirement for writing glucose measurement characteristic CCCD. */
|
||||
security_req_t gl_feature_rd_sec; /**< Security requirement for reading glucose feature characteristic. */
|
||||
security_req_t racp_cccd_wr_sec; /**< Security requirement for writing RACP Characteristic CCCD. */
|
||||
security_req_t racp_wr_sec; /**< Security requirement for writing RACP Characteristic. (Service specification mandates authentication) */
|
||||
nrf_ble_gq_t * p_gatt_queue; /**< Pointer to BLE GATT Queue instance. */
|
||||
} ble_gls_init_t;
|
||||
|
||||
/**@brief Glucose Service structure. This contains various status information for the service. */
|
||||
struct ble_gls_s
|
||||
{
|
||||
ble_gls_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Glucose Service. */
|
||||
ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
|
||||
uint16_t service_handle; /**< Handle of Glucose Service (as provided by the BLE stack). */
|
||||
ble_gatts_char_handles_t glm_handles; /**< Handles related to the Glucose Measurement characteristic. */
|
||||
ble_gatts_char_handles_t glm_context_handles; /**< Handles related to the Glucose Measurement Context characteristic. */
|
||||
ble_gatts_char_handles_t glf_handles; /**< Handles related to the Glucose Feature characteristic. */
|
||||
ble_gatts_char_handles_t racp_handles; /**< Handles related to the Record Access Control Point characteristic. */
|
||||
uint16_t conn_handle; /**< Handle of the current connection (as provided by the BLE stack, is BLE_CONN_HANDLE_INVALID if not in a connection). */
|
||||
nrf_ble_gq_t * p_gatt_queue; /**< Pointer to BLE GATT Queue instance. */
|
||||
uint16_t feature;
|
||||
bool is_context_supported;
|
||||
};
|
||||
|
||||
|
||||
/**@brief Function for initializing the Glucose Service.
|
||||
*
|
||||
* @details This call allows the application to initialize the Glucose Service.
|
||||
*
|
||||
* @param[out] p_gls Glucose Service structure. This structure will have to be supplied by
|
||||
* the application. It will be initialized by this function, and will later
|
||||
* be used to identify this particular service instance.
|
||||
* @param[in] p_gls_init Information needed to initialize the service.
|
||||
*
|
||||
* @return NRF_SUCCESS on successful initialization of service, otherwise an error code.
|
||||
*/
|
||||
uint32_t ble_gls_init(ble_gls_t * p_gls, ble_gls_init_t const * p_gls_init);
|
||||
|
||||
|
||||
/**@brief Function for handling the Application's BLE Stack events.
|
||||
*
|
||||
* @details Handles all events from the BLE stack of interest to the Glucose Service.
|
||||
*
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
* @param[in] p_context Glucose Service structure.
|
||||
*/
|
||||
void ble_gls_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
|
||||
|
||||
|
||||
/**@brief Function for reporting a new glucose measurement to the glucose service module.
|
||||
*
|
||||
* @details The application calls this function after having performed a new glucose measurement.
|
||||
* The new measurement is recorded in the RACP database.
|
||||
*
|
||||
* @param[in] p_gls Glucose Service structure.
|
||||
* @param[in] p_rec Pointer to glucose record (measurement plus context).
|
||||
*
|
||||
* @return NRF_SUCCESS on success, otherwise an error code.
|
||||
*/
|
||||
uint32_t ble_gls_glucose_new_meas(ble_gls_t * p_gls, ble_gls_rec_t * p_rec);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // BLE_GLS_H__
|
||||
|
||||
/** @} */
|
||||
|
||||
143
components/ble/ble_services/ble_gls/ble_gls_db.c
Normal file
143
components/ble/ble_services/ble_gls/ble_gls_db.c
Normal file
@@ -0,0 +1,143 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 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_GLS)
|
||||
#include "ble_gls_db.h"
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
bool in_use_flag;
|
||||
ble_gls_rec_t record;
|
||||
} database_entry_t;
|
||||
|
||||
static database_entry_t m_database[BLE_GLS_DB_MAX_RECORDS];
|
||||
static uint8_t m_database_crossref[BLE_GLS_DB_MAX_RECORDS];
|
||||
static uint16_t m_num_records;
|
||||
|
||||
|
||||
uint32_t ble_gls_db_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < BLE_GLS_DB_MAX_RECORDS; i++)
|
||||
{
|
||||
m_database[i].in_use_flag = false;
|
||||
m_database_crossref[i] = 0xFF;
|
||||
}
|
||||
|
||||
m_num_records = 0;
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
uint16_t ble_gls_db_num_records_get(void)
|
||||
{
|
||||
return m_num_records;
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_gls_db_record_get(uint8_t rec_ndx, ble_gls_rec_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;
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_gls_db_record_add(ble_gls_rec_t * p_rec)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (m_num_records == BLE_GLS_DB_MAX_RECORDS)
|
||||
{
|
||||
return NRF_ERROR_NO_MEM;
|
||||
}
|
||||
|
||||
// find next available database entry
|
||||
for (i = 0; i < BLE_GLS_DB_MAX_RECORDS; i++)
|
||||
{
|
||||
if (!m_database[i].in_use_flag)
|
||||
{
|
||||
m_database[i].in_use_flag = true;
|
||||
m_database[i].record = *p_rec;
|
||||
|
||||
m_database_crossref[m_num_records] = i;
|
||||
m_num_records++;
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return NRF_ERROR_NO_MEM;
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_gls_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;
|
||||
}
|
||||
#endif // NRF_MODULE_ENABLED(BLE_GLS)
|
||||
121
components/ble/ble_services/ble_gls/ble_gls_db.h
Normal file
121
components/ble/ble_services/ble_gls/ble_gls_db.h
Normal file
@@ -0,0 +1,121 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 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 ble_sdk_srv_gls_db Glucose Database Service
|
||||
* @{
|
||||
* @ingroup ble_sdk_srv
|
||||
* @brief Glucose Service module.
|
||||
*
|
||||
* @details This module implements at database of stored glucose measurement values.
|
||||
*
|
||||
* @note Attention!
|
||||
* To maintain compliance with Nordic Semiconductor ASA Bluetooth profile
|
||||
* qualification listings, These APIs must not be modified. However, the corresponding
|
||||
* functions' implementations can be modified.
|
||||
*/
|
||||
|
||||
#ifndef BLE_GLS_DB_H__
|
||||
#define BLE_GLS_DB_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include "ble_gls.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define BLE_GLS_DB_MAX_RECORDS 20
|
||||
|
||||
/**@brief Function for initializing the glucose record database.
|
||||
*
|
||||
* @details This call initializes the database holding glucose records.
|
||||
*
|
||||
* @return NRF_SUCCESS on success.
|
||||
*/
|
||||
uint32_t ble_gls_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_gls_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.
|
||||
*/
|
||||
uint32_t ble_gls_db_record_get(uint8_t record_num, ble_gls_rec_t * p_rec);
|
||||
|
||||
/**@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.
|
||||
*/
|
||||
uint32_t ble_gls_db_record_add(ble_gls_rec_t * p_rec);
|
||||
|
||||
/**@brief Function for deleting a database entry.
|
||||
*
|
||||
* @details This call deletes an record from the database.
|
||||
*
|
||||
* @param[in] record_num Index of record to delete.
|
||||
*
|
||||
* @return NRF_SUCCESS on success.
|
||||
*/
|
||||
uint32_t ble_gls_db_record_delete(uint8_t record_num);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // BLE_GLS_DB_H__
|
||||
|
||||
/** @} */
|
||||
1576
components/ble/ble_services/ble_hids/ble_hids.c
Normal file
1576
components/ble/ble_services/ble_hids/ble_hids.c
Normal file
File diff suppressed because it is too large
Load Diff
439
components/ble/ble_services/ble_hids/ble_hids.h
Normal file
439
components/ble/ble_services/ble_hids/ble_hids.h
Normal file
@@ -0,0 +1,439 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 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 ble_hids Human Interface Device Service
|
||||
* @{
|
||||
* @ingroup ble_sdk_srv
|
||||
* @brief Human Interface Device Service module.
|
||||
*
|
||||
* @details This module implements the Human Interface Device Service with the corresponding set of
|
||||
* characteristics. During initialization it adds the Human Interface Device Service and
|
||||
* a set of characteristics as per the Human Interface Device Service specification and
|
||||
* the user requirements to the BLE stack database.
|
||||
*
|
||||
* If enabled, notification of Input Report characteristics is performed when the
|
||||
* application calls the corresponding ble_hids_xx_input_report_send() function.
|
||||
*
|
||||
* If an event handler is supplied by the application, the Human Interface Device Service
|
||||
* will generate Human Interface Device 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_hids_t instance;
|
||||
* NRF_SDH_BLE_OBSERVER(anything, BLE_HIDS_BLE_OBSERVER_PRIO,
|
||||
* ble_hids_on_ble_evt, &instance);
|
||||
* @endcode
|
||||
*
|
||||
* @note Attention!
|
||||
* To maintain compliance with Nordic Semiconductor ASA Bluetooth profile
|
||||
* qualification listings, this section of source code must not be modified.
|
||||
*/
|
||||
|
||||
#ifndef BLE_HIDS_H__
|
||||
#define BLE_HIDS_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "ble.h"
|
||||
#include "ble_srv_common.h"
|
||||
#include "ble_link_ctx_manager.h"
|
||||
#include "nrf_sdh_ble.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**@brief Allocate static data for keeping host connection contexts.
|
||||
*
|
||||
* @param _name Name of BLE HIDS instance.
|
||||
* @param[in] _hids_max_clients Maximum number of HIDS clients connected at a time.
|
||||
* @param[in] ... Lengths of HIDS reports.
|
||||
*
|
||||
* @details
|
||||
* Mapping of HIDS reports in the HIDS report context:
|
||||
* - Structure of type @ref ble_hids_client_context_t
|
||||
* - Boot keyboard input report
|
||||
* - Boot keyboard output report
|
||||
* - Boot mouse input report
|
||||
* - Input reports
|
||||
* - Output reports
|
||||
* - Feature reports
|
||||
* @hideinitializer
|
||||
*/
|
||||
#define BLE_HIDS_DEF(_name, \
|
||||
_hids_max_clients, \
|
||||
...) \
|
||||
BLE_LINK_CTX_MANAGER_DEF(CONCAT_2(_name, _link_ctx_storage), \
|
||||
(_hids_max_clients), \
|
||||
BLE_HIDS_LINK_CTX_SIZE_CALC(__VA_ARGS__)); \
|
||||
static ble_hids_t _name = \
|
||||
{ \
|
||||
.p_link_ctx_storage = &CONCAT_2(_name, _link_ctx_storage) \
|
||||
}; \
|
||||
NRF_SDH_BLE_OBSERVER(_name ## _obs, \
|
||||
BLE_HIDS_BLE_OBSERVER_PRIO, \
|
||||
ble_hids_on_ble_evt, \
|
||||
&_name)
|
||||
|
||||
/**@brief Helping macro for @ref BLE_HIDS_DEF, that calculates the link context size for BLE HIDS
|
||||
* instance.
|
||||
*
|
||||
* @param[in] ... Lengths of HIDS reports
|
||||
* @hideinitializer
|
||||
*/
|
||||
#define BLE_HIDS_LINK_CTX_SIZE_CALC(...) \
|
||||
(sizeof(ble_hids_client_context_t) + \
|
||||
MACRO_MAP_REC(BLE_HIDS_REPORT_ADD, __VA_ARGS__) \
|
||||
(BOOT_KB_INPUT_REPORT_MAX_SIZE) + \
|
||||
(BOOT_KB_OUTPUT_REPORT_MAX_SIZE) + \
|
||||
(BOOT_MOUSE_INPUT_REPORT_MAX_SIZE)) \
|
||||
|
||||
/**@brief Helping macro for @ref BLE_HIDS_LINK_CTX_SIZE_CALC, that adds Input/Output/Feature report
|
||||
* lengths.
|
||||
*
|
||||
* @param[in] _report_size Length of the specific report.
|
||||
* @hideinitializer
|
||||
*/
|
||||
#define BLE_HIDS_REPORT_ADD(_report_size) (_report_size) +
|
||||
|
||||
/** @name Report Type values
|
||||
* @anchor BLE_HIDS_REPORT_TYPE @{
|
||||
*/
|
||||
// Report Type values
|
||||
#define BLE_HIDS_REP_TYPE_INPUT 1
|
||||
#define BLE_HIDS_REP_TYPE_OUTPUT 2
|
||||
#define BLE_HIDS_REP_TYPE_FEATURE 3
|
||||
/** @} */
|
||||
|
||||
// Maximum number of the various Report Types
|
||||
#define BLE_HIDS_MAX_INPUT_REP 10
|
||||
#define BLE_HIDS_MAX_OUTPUT_REP 10
|
||||
#define BLE_HIDS_MAX_FEATURE_REP 10
|
||||
|
||||
// Information Flags
|
||||
#define HID_INFO_FLAG_REMOTE_WAKE_MSK 0x01
|
||||
#define HID_INFO_FLAG_NORMALLY_CONNECTABLE_MSK 0x02
|
||||
|
||||
#define BOOT_KB_INPUT_REPORT_MAX_SIZE 8 /**< Maximum size of a Boot Keyboard Input Report (as per Appendix B in Device Class Definition for Human Interface Devices (HID), Version 1.11). */
|
||||
#define BOOT_KB_OUTPUT_REPORT_MAX_SIZE 1 /**< Maximum size of a Boot Keyboard Output Report (as per Appendix B in Device Class Definition for Human Interface Devices (HID), Version 1.11). */
|
||||
#define BOOT_MOUSE_INPUT_REPORT_MIN_SIZE 3 /**< Minimum size of a Boot Mouse Input Report (as per Appendix B in Device Class Definition for Human Interface Devices (HID), Version 1.11). */
|
||||
#define BOOT_MOUSE_INPUT_REPORT_MAX_SIZE 8 /**< Maximum size of a Boot Mouse Input Report (as per Appendix B in Device Class Definition for Human Interface Devices (HID), Version 1.11). */
|
||||
|
||||
/**@brief HID Service characteristic id. */
|
||||
typedef struct
|
||||
{
|
||||
uint16_t uuid; /**< UUID of characteristic. */
|
||||
uint8_t rep_type; /**< Type of report (only used for BLE_UUID_REPORT_CHAR, see @ref BLE_HIDS_REPORT_TYPE). */
|
||||
uint8_t rep_index; /**< Index of the characteristic (only used for BLE_UUID_REPORT_CHAR). */
|
||||
} ble_hids_char_id_t;
|
||||
|
||||
/**@brief HID Service event type. */
|
||||
typedef enum
|
||||
{
|
||||
BLE_HIDS_EVT_HOST_SUSP, /**< Suspend command received. */
|
||||
BLE_HIDS_EVT_HOST_EXIT_SUSP, /**< Exit suspend command received. */
|
||||
BLE_HIDS_EVT_NOTIF_ENABLED, /**< Notification enabled event. */
|
||||
BLE_HIDS_EVT_NOTIF_DISABLED, /**< Notification disabled event. */
|
||||
BLE_HIDS_EVT_REP_CHAR_WRITE, /**< A new value has been written to an Report characteristic. */
|
||||
BLE_HIDS_EVT_BOOT_MODE_ENTERED, /**< Boot mode entered. */
|
||||
BLE_HIDS_EVT_REPORT_MODE_ENTERED, /**< Report mode entered. */
|
||||
BLE_HIDS_EVT_REPORT_READ /**< Read with response */
|
||||
} ble_hids_evt_type_t;
|
||||
|
||||
/**@brief HID Service event. */
|
||||
typedef struct
|
||||
{
|
||||
ble_hids_evt_type_t evt_type; /**< Type of event. */
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
ble_hids_char_id_t char_id; /**< Id of characteristic for which notification has been started. */
|
||||
} notification;
|
||||
struct
|
||||
{
|
||||
ble_hids_char_id_t char_id; /**< Id of characteristic having been written. */
|
||||
uint16_t offset; /**< Offset for the write operation. */
|
||||
uint16_t len; /**< Length of the incoming data. */
|
||||
uint8_t const * data; /**< Incoming data, variable length */
|
||||
} char_write;
|
||||
struct
|
||||
{
|
||||
ble_hids_char_id_t char_id; /**< Id of characteristic being read. */
|
||||
} char_auth_read;
|
||||
} params;
|
||||
ble_evt_t const * p_ble_evt; /**< corresponding received ble event, NULL if not relevant */
|
||||
} ble_hids_evt_t;
|
||||
|
||||
// Forward declaration of the ble_hids_t type.
|
||||
typedef struct ble_hids_s ble_hids_t;
|
||||
|
||||
/**@brief HID Service event handler type. */
|
||||
typedef void (*ble_hids_evt_handler_t) (ble_hids_t * p_hids, ble_hids_evt_t * p_evt);
|
||||
|
||||
/**@brief Security requirements for HID Service characteristic. */
|
||||
typedef struct
|
||||
{
|
||||
security_req_t rd; /**< Security requirement for reading HID Service characteristic value. */
|
||||
security_req_t wr; /**< Security requirement for writing HID Service characteristic value. */
|
||||
security_req_t cccd_wr; /**< Security requirement for writing HID Service characteristic CCCD. */
|
||||
} ble_hids_char_sec_t;
|
||||
|
||||
/**@brief HID Information characteristic value. */
|
||||
typedef struct
|
||||
{
|
||||
uint16_t bcd_hid; /**< 16-bit unsigned integer representing version number of base USB HID Specification implemented by HID Device */
|
||||
uint8_t b_country_code; /**< Identifies which country the hardware is localized for. Most hardware is not localized and thus this value would be zero (0). */
|
||||
uint8_t flags; /**< See http://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.hid_information.xml */
|
||||
security_req_t rd_sec; /**< Security requirement for reading HID Information characteristic value. */
|
||||
} ble_hids_hid_information_t;
|
||||
|
||||
/**@brief HID Service Input Report characteristic init structure. This contains all options and
|
||||
* data needed for initialization of one Input Report characteristic. */
|
||||
typedef struct
|
||||
{
|
||||
uint16_t max_len; /**< Maximum length of characteristic value. */
|
||||
ble_srv_report_ref_t rep_ref; /**< Value of the Report Reference descriptor. */
|
||||
ble_hids_char_sec_t sec; /**< Security requirements for HID Service Input Report characteristic. */
|
||||
} ble_hids_inp_rep_init_t;
|
||||
|
||||
/**@brief HID Service Output Report characteristic init structure. This contains all options and
|
||||
* data needed for initialization of one Output Report characteristic. */
|
||||
typedef struct
|
||||
{
|
||||
uint16_t max_len; /**< Maximum length of characteristic value. */
|
||||
ble_srv_report_ref_t rep_ref; /**< Value of the Report Reference descriptor. */
|
||||
ble_hids_char_sec_t sec; /**< Security requirements for HID Service Output Report characteristic. */
|
||||
} ble_hids_outp_rep_init_t;
|
||||
|
||||
/**@brief HID Service Feature Report characteristic init structure. This contains all options and
|
||||
* data needed for initialization of one Feature Report characteristic. */
|
||||
typedef struct
|
||||
{
|
||||
uint16_t max_len; /**< Maximum length of characteristic value. */
|
||||
ble_srv_report_ref_t rep_ref; /**< Value of the Report Reference descriptor. */
|
||||
ble_hids_char_sec_t sec; /**< Security requirements for HID Service Feature Report characteristic. */
|
||||
} ble_hids_feature_rep_init_t;
|
||||
|
||||
/**@brief HID Service Report Map characteristic init structure. This contains all options and data
|
||||
* needed for initialization of the Report Map characteristic. */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t * p_data; /**< Report map data. */
|
||||
uint16_t data_len; /**< Length of report map data. */
|
||||
uint8_t ext_rep_ref_num; /**< Number of Optional External Report Reference descriptors. */
|
||||
ble_uuid_t const * p_ext_rep_ref; /**< Optional External Report Reference descriptor (will be added if != NULL). */
|
||||
security_req_t rd_sec; /**< Security requirement for HID Service Report Map characteristic. */
|
||||
} ble_hids_rep_map_init_t;
|
||||
|
||||
/**@brief HID Report characteristic structure. */
|
||||
typedef struct
|
||||
{
|
||||
ble_gatts_char_handles_t char_handles; /**< Handles related to the Report characteristic. */
|
||||
uint16_t ref_handle; /**< Handle of the Report Reference descriptor. */
|
||||
} ble_hids_rep_char_t;
|
||||
|
||||
/**@brief HID Host context structure. It keeps information relevant to a single host. */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t protocol_mode; /**< Protocol mode. */
|
||||
uint8_t ctrl_pt; /**< HID Control Point. */
|
||||
} ble_hids_client_context_t;
|
||||
|
||||
/**@brief HID Service init structure. This contains all options and data needed for initialization
|
||||
* of the service. */
|
||||
typedef struct
|
||||
{
|
||||
ble_hids_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the HID Service. */
|
||||
ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
|
||||
bool is_kb; /**< TRUE if device is operating as a keyboard, FALSE if it is not. */
|
||||
bool is_mouse; /**< TRUE if device is operating as a mouse, FALSE if it is not. */
|
||||
uint8_t inp_rep_count; /**< Number of Input Report characteristics. */
|
||||
ble_hids_inp_rep_init_t const * p_inp_rep_array; /**< Information about the Input Report characteristics. */
|
||||
uint8_t outp_rep_count; /**< Number of Output Report characteristics. */
|
||||
ble_hids_outp_rep_init_t const * p_outp_rep_array; /**< Information about the Output Report characteristics. */
|
||||
uint8_t feature_rep_count; /**< Number of Feature Report characteristics. */
|
||||
ble_hids_feature_rep_init_t const * p_feature_rep_array; /**< Information about the Feature Report characteristics. */
|
||||
ble_hids_rep_map_init_t rep_map; /**< Information nedeed for initialization of the Report Map characteristic. */
|
||||
ble_hids_hid_information_t hid_information; /**< Value of the HID Information characteristic. */
|
||||
uint8_t included_services_count; /**< Number of services to include in HID service. */
|
||||
uint16_t * p_included_services_array; /**< Array of services to include in HID service. */
|
||||
security_req_t protocol_mode_rd_sec; /**< Security requirement for reading HID service Protocol Mode characteristic. */
|
||||
security_req_t protocol_mode_wr_sec; /**< Security requirement for writing HID service Protocol Mode characteristic. */
|
||||
security_req_t ctrl_point_wr_sec; /**< Security requirement for writing HID service Control Point characteristic. */
|
||||
ble_hids_char_sec_t boot_mouse_inp_rep_sec; /**< Security requirements for HID Boot Keyboard Input Report characteristic. */
|
||||
ble_hids_char_sec_t boot_kb_inp_rep_sec; /**< Security requirements for HID Boot Keyboard Input Report characteristic. */
|
||||
ble_hids_char_sec_t boot_kb_outp_rep_sec; /**< Security requirements for HID Boot Keyboard Output Report characteristic. */
|
||||
} ble_hids_init_t;
|
||||
|
||||
/**@brief HID Service structure. This contains various status information for the service. */
|
||||
struct ble_hids_s
|
||||
{
|
||||
ble_hids_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the HID Service. */
|
||||
ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
|
||||
uint16_t service_handle; /**< Handle of HID Service (as provided by the BLE stack). */
|
||||
ble_gatts_char_handles_t protocol_mode_handles; /**< Handles related to the Protocol Mode characteristic (will only be created if ble_hids_init_t.is_kb or ble_hids_init_t.is_mouse is set). */
|
||||
uint8_t inp_rep_count; /**< Number of Input Report characteristics. */
|
||||
ble_hids_rep_char_t inp_rep_array[BLE_HIDS_MAX_INPUT_REP]; /**< Information about the Input Report characteristics. */
|
||||
uint8_t outp_rep_count; /**< Number of Output Report characteristics. */
|
||||
ble_hids_rep_char_t outp_rep_array[BLE_HIDS_MAX_OUTPUT_REP]; /**< Information about the Output Report characteristics. */
|
||||
uint8_t feature_rep_count; /**< Number of Feature Report characteristics. */
|
||||
ble_hids_rep_char_t feature_rep_array[BLE_HIDS_MAX_FEATURE_REP]; /**< Information about the Feature Report characteristics. */
|
||||
ble_gatts_char_handles_t rep_map_handles; /**< Handles related to the Report Map characteristic. */
|
||||
uint16_t rep_map_ext_rep_ref_handle; /**< Handle of the Report Map External Report Reference descriptor. */
|
||||
ble_gatts_char_handles_t boot_kb_inp_rep_handles; /**< Handles related to the Boot Keyboard Input Report characteristic (will only be created if ble_hids_init_t.is_kb is set). */
|
||||
ble_gatts_char_handles_t boot_kb_outp_rep_handles; /**< Handles related to the Boot Keyboard Output Report characteristic (will only be created if ble_hids_init_t.is_kb is set). */
|
||||
ble_gatts_char_handles_t boot_mouse_inp_rep_handles; /**< Handles related to the Boot Mouse Input Report characteristic (will only be created if ble_hids_init_t.is_mouse is set). */
|
||||
ble_gatts_char_handles_t hid_information_handles; /**< Handles related to the Report Map characteristic. */
|
||||
ble_gatts_char_handles_t hid_control_point_handles; /**< Handles related to the Report Map characteristic. */
|
||||
blcm_link_ctx_storage_t * const p_link_ctx_storage; /**< Link context storage with handles of all current connections and its data context. */
|
||||
ble_hids_inp_rep_init_t const * p_inp_rep_init_array; /**< Pointer to information about the Input Report characteristics. */
|
||||
ble_hids_outp_rep_init_t const * p_outp_rep_init_array; /**< Pointer to information about the Output Report characteristics. */
|
||||
ble_hids_feature_rep_init_t const * p_feature_rep_init_array; /**< Pointer to information about the Feature Report characteristics. */
|
||||
};
|
||||
|
||||
/**@brief Function for initializing the HID Service.
|
||||
*
|
||||
* @param[out] p_hids HID Service structure. This structure will have to be supplied by the
|
||||
* application. It will be initialized by this function, and will later be
|
||||
* used to identify this particular service instance.
|
||||
* @param[in] p_hids_init Information needed to initialize the service.
|
||||
*
|
||||
* @return NRF_SUCCESS on successful initialization of service, otherwise an error code.
|
||||
*/
|
||||
uint32_t ble_hids_init(ble_hids_t * p_hids, const ble_hids_init_t * p_hids_init);
|
||||
|
||||
/**@brief Function for handling the Application's BLE Stack events.
|
||||
*
|
||||
* @details Handles all events from the BLE stack of interest to the HID Service.
|
||||
*
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
* @param[in] p_context HID Service structure.
|
||||
*/
|
||||
void ble_hids_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
|
||||
|
||||
/**@brief Function for sending Input Report.
|
||||
*
|
||||
* @details Sends data on an Input Report characteristic.
|
||||
*
|
||||
* @param[in] p_hids HID Service structure.
|
||||
* @param[in] rep_index Index of the characteristic (corresponding to the index in
|
||||
* ble_hids_t.inp_rep_array as passed to ble_hids_init()).
|
||||
* @param[in] len Length of data to be sent.
|
||||
* @param[in] p_data Pointer to data to be sent.
|
||||
* @param[in] conn_handle Connection handle, where the notification will be sent.
|
||||
*
|
||||
* @return NRF_SUCCESS on successful sending of input report, otherwise an error code.
|
||||
*/
|
||||
uint32_t ble_hids_inp_rep_send(ble_hids_t * p_hids,
|
||||
uint8_t rep_index,
|
||||
uint16_t len,
|
||||
uint8_t * p_data,
|
||||
uint16_t conn_handle);
|
||||
|
||||
/**@brief Function for sending Boot Keyboard Input Report.
|
||||
*
|
||||
* @details Sends data on an Boot Keyboard Input Report characteristic.
|
||||
*
|
||||
* @param[in] p_hids HID Service structure.
|
||||
* @param[in] len Length of data to be sent.
|
||||
* @param[in] p_data Pointer to data to be sent.
|
||||
* @param[in] conn_handle Connection handle, where the notification will be sent.
|
||||
*
|
||||
* @return NRF_SUCCESS on successful sending of the report, otherwise an error code.
|
||||
*/
|
||||
uint32_t ble_hids_boot_kb_inp_rep_send(ble_hids_t * p_hids,
|
||||
uint16_t len,
|
||||
uint8_t * p_data,
|
||||
uint16_t conn_handle);
|
||||
|
||||
/**@brief Function for sending Boot Mouse Input Report.
|
||||
*
|
||||
* @details Sends data on an Boot Mouse Input Report characteristic.
|
||||
*
|
||||
* @param[in] p_hids HID Service structure.
|
||||
* @param[in] buttons State of mouse buttons.
|
||||
* @param[in] x_delta Horizontal movement.
|
||||
* @param[in] y_delta Vertical movement.
|
||||
* @param[in] optional_data_len Length of optional part of Boot Mouse Input Report.
|
||||
* @param[in] p_optional_data Optional part of Boot Mouse Input Report.
|
||||
* @param[in] conn_handle Connection handle.
|
||||
*
|
||||
* @return NRF_SUCCESS on successful sending of the report, otherwise an error code.
|
||||
*/
|
||||
uint32_t ble_hids_boot_mouse_inp_rep_send(ble_hids_t * p_hids,
|
||||
uint8_t buttons,
|
||||
int8_t x_delta,
|
||||
int8_t y_delta,
|
||||
uint16_t optional_data_len,
|
||||
uint8_t * p_optional_data,
|
||||
uint16_t conn_handle);
|
||||
|
||||
/**@brief Function for getting the current value of Output Report from the stack.
|
||||
*
|
||||
* @details Fetches the current value of the output report characteristic from the stack.
|
||||
*
|
||||
* @param[in] p_hids HID Service structure.
|
||||
* @param[in] rep_index Index of the characteristic (corresponding to the index in
|
||||
* ble_hids_t.outp_rep_array as passed to ble_hids_init()).
|
||||
* @param[in] len Length of output report needed.
|
||||
* @param[in] offset Offset in bytes to read from.
|
||||
* @param[in] conn_handle Connection handle.
|
||||
* @param[out] p_outp_rep Pointer to the output report.
|
||||
*
|
||||
* @return NRF_SUCCESS on successful read of the report, otherwise an error code.
|
||||
*/
|
||||
uint32_t ble_hids_outp_rep_get(ble_hids_t * p_hids,
|
||||
uint8_t rep_index,
|
||||
uint16_t len,
|
||||
uint8_t offset,
|
||||
uint16_t conn_handle,
|
||||
uint8_t * p_outp_rep);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // BLE_HIDS_H__
|
||||
|
||||
/** @} */
|
||||
391
components/ble/ble_services/ble_hrs/ble_hrs.c
Normal file
391
components/ble/ble_services/ble_hrs/ble_hrs.c
Normal file
@@ -0,0 +1,391 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 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.
|
||||
*
|
||||
*/
|
||||
/* Attention!
|
||||
* To maintain compliance with Nordic Semiconductor ASA's Bluetooth profile
|
||||
* qualification listings, this section of source code must not be modified.
|
||||
*/
|
||||
#include "sdk_common.h"
|
||||
#if NRF_MODULE_ENABLED(BLE_HRS)
|
||||
#include "ble_hrs.h"
|
||||
#include <string.h>
|
||||
#include "ble_srv_common.h"
|
||||
|
||||
|
||||
#define OPCODE_LENGTH 1 /**< Length of opcode inside Heart Rate Measurement packet. */
|
||||
#define HANDLE_LENGTH 2 /**< Length of handle inside Heart Rate Measurement packet. */
|
||||
#define MAX_HRM_LEN (NRF_SDH_BLE_GATT_MAX_MTU_SIZE - OPCODE_LENGTH - HANDLE_LENGTH) /**< Maximum size of a transmitted Heart Rate Measurement. */
|
||||
|
||||
#define INITIAL_VALUE_HRM 0 /**< Initial Heart Rate Measurement value. */
|
||||
|
||||
// Heart Rate Measurement flag bits
|
||||
#define HRM_FLAG_MASK_HR_VALUE_16BIT (0x01 << 0) /**< Heart Rate Value Format bit. */
|
||||
#define HRM_FLAG_MASK_SENSOR_CONTACT_DETECTED (0x01 << 1) /**< Sensor Contact Detected bit. */
|
||||
#define HRM_FLAG_MASK_SENSOR_CONTACT_SUPPORTED (0x01 << 2) /**< Sensor Contact Supported bit. */
|
||||
#define HRM_FLAG_MASK_EXPENDED_ENERGY_INCLUDED (0x01 << 3) /**< Energy Expended Status bit. Feature Not Supported */
|
||||
#define HRM_FLAG_MASK_RR_INTERVAL_INCLUDED (0x01 << 4) /**< RR-Interval bit. */
|
||||
|
||||
|
||||
/**@brief Function for handling the Connect event.
|
||||
*
|
||||
* @param[in] p_hrs Heart Rate Service structure.
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
*/
|
||||
static void on_connect(ble_hrs_t * p_hrs, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
p_hrs->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling the Disconnect event.
|
||||
*
|
||||
* @param[in] p_hrs Heart Rate Service structure.
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
*/
|
||||
static void on_disconnect(ble_hrs_t * p_hrs, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
UNUSED_PARAMETER(p_ble_evt);
|
||||
p_hrs->conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling write events to the Heart Rate Measurement characteristic.
|
||||
*
|
||||
* @param[in] p_hrs Heart Rate Service structure.
|
||||
* @param[in] p_evt_write Write event received from the BLE stack.
|
||||
*/
|
||||
static void on_hrm_cccd_write(ble_hrs_t * p_hrs, ble_gatts_evt_write_t const * p_evt_write)
|
||||
{
|
||||
if (p_evt_write->len == 2)
|
||||
{
|
||||
// CCCD written, update notification state
|
||||
if (p_hrs->evt_handler != NULL)
|
||||
{
|
||||
ble_hrs_evt_t evt;
|
||||
|
||||
if (ble_srv_is_notification_enabled(p_evt_write->data))
|
||||
{
|
||||
evt.evt_type = BLE_HRS_EVT_NOTIFICATION_ENABLED;
|
||||
}
|
||||
else
|
||||
{
|
||||
evt.evt_type = BLE_HRS_EVT_NOTIFICATION_DISABLED;
|
||||
}
|
||||
|
||||
p_hrs->evt_handler(p_hrs, &evt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling the Write event.
|
||||
*
|
||||
* @param[in] p_hrs Heart Rate Service structure.
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
*/
|
||||
static void on_write(ble_hrs_t * p_hrs, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
ble_gatts_evt_write_t const * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
|
||||
|
||||
if (p_evt_write->handle == p_hrs->hrm_handles.cccd_handle)
|
||||
{
|
||||
on_hrm_cccd_write(p_hrs, p_evt_write);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ble_hrs_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
|
||||
{
|
||||
ble_hrs_t * p_hrs = (ble_hrs_t *) p_context;
|
||||
|
||||
switch (p_ble_evt->header.evt_id)
|
||||
{
|
||||
case BLE_GAP_EVT_CONNECTED:
|
||||
on_connect(p_hrs, p_ble_evt);
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVT_DISCONNECTED:
|
||||
on_disconnect(p_hrs, p_ble_evt);
|
||||
break;
|
||||
|
||||
case BLE_GATTS_EVT_WRITE:
|
||||
on_write(p_hrs, p_ble_evt);
|
||||
break;
|
||||
|
||||
default:
|
||||
// No implementation needed.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for encoding a Heart Rate Measurement.
|
||||
*
|
||||
* @param[in] p_hrs Heart Rate Service structure.
|
||||
* @param[in] heart_rate Measurement to be encoded.
|
||||
* @param[out] p_encoded_buffer Buffer where the encoded data will be written.
|
||||
*
|
||||
* @return Size of encoded data.
|
||||
*/
|
||||
static uint8_t hrm_encode(ble_hrs_t * p_hrs, uint16_t heart_rate, uint8_t * p_encoded_buffer)
|
||||
{
|
||||
uint8_t flags = 0;
|
||||
uint8_t len = 1;
|
||||
int i;
|
||||
|
||||
// Set sensor contact related flags
|
||||
if (p_hrs->is_sensor_contact_supported)
|
||||
{
|
||||
flags |= HRM_FLAG_MASK_SENSOR_CONTACT_SUPPORTED;
|
||||
}
|
||||
if (p_hrs->is_sensor_contact_detected)
|
||||
{
|
||||
flags |= HRM_FLAG_MASK_SENSOR_CONTACT_DETECTED;
|
||||
}
|
||||
|
||||
// Encode heart rate measurement
|
||||
if (heart_rate > 0xff)
|
||||
{
|
||||
flags |= HRM_FLAG_MASK_HR_VALUE_16BIT;
|
||||
len += uint16_encode(heart_rate, &p_encoded_buffer[len]);
|
||||
}
|
||||
else
|
||||
{
|
||||
p_encoded_buffer[len++] = (uint8_t)heart_rate;
|
||||
}
|
||||
|
||||
// Encode rr_interval values
|
||||
if (p_hrs->rr_interval_count > 0)
|
||||
{
|
||||
flags |= HRM_FLAG_MASK_RR_INTERVAL_INCLUDED;
|
||||
}
|
||||
for (i = 0; i < p_hrs->rr_interval_count; i++)
|
||||
{
|
||||
if (len + sizeof(uint16_t) > p_hrs->max_hrm_len)
|
||||
{
|
||||
// Not all stored rr_interval values can fit into the encoded hrm,
|
||||
// move the remaining values to the start of the buffer.
|
||||
memmove(&p_hrs->rr_interval[0],
|
||||
&p_hrs->rr_interval[i],
|
||||
(p_hrs->rr_interval_count - i) * sizeof(uint16_t));
|
||||
break;
|
||||
}
|
||||
len += uint16_encode(p_hrs->rr_interval[i], &p_encoded_buffer[len]);
|
||||
}
|
||||
p_hrs->rr_interval_count -= i;
|
||||
|
||||
// Add flags
|
||||
p_encoded_buffer[0] = flags;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_hrs_init(ble_hrs_t * p_hrs, const ble_hrs_init_t * p_hrs_init)
|
||||
{
|
||||
uint32_t err_code;
|
||||
ble_uuid_t ble_uuid;
|
||||
ble_add_char_params_t add_char_params;
|
||||
uint8_t encoded_initial_hrm[MAX_HRM_LEN];
|
||||
|
||||
// Initialize service structure
|
||||
p_hrs->evt_handler = p_hrs_init->evt_handler;
|
||||
p_hrs->is_sensor_contact_supported = p_hrs_init->is_sensor_contact_supported;
|
||||
p_hrs->conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
p_hrs->is_sensor_contact_detected = false;
|
||||
p_hrs->rr_interval_count = 0;
|
||||
p_hrs->max_hrm_len = MAX_HRM_LEN;
|
||||
|
||||
// Add service
|
||||
BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_HEART_RATE_SERVICE);
|
||||
|
||||
err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
|
||||
&ble_uuid,
|
||||
&p_hrs->service_handle);
|
||||
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
|
||||
// Add heart rate measurement characteristic
|
||||
memset(&add_char_params, 0, sizeof(add_char_params));
|
||||
|
||||
add_char_params.uuid = BLE_UUID_HEART_RATE_MEASUREMENT_CHAR;
|
||||
add_char_params.max_len = MAX_HRM_LEN;
|
||||
add_char_params.init_len = hrm_encode(p_hrs, INITIAL_VALUE_HRM, encoded_initial_hrm);
|
||||
add_char_params.p_init_value = encoded_initial_hrm;
|
||||
add_char_params.is_var_len = true;
|
||||
add_char_params.char_props.notify = 1;
|
||||
add_char_params.cccd_write_access = p_hrs_init->hrm_cccd_wr_sec;
|
||||
|
||||
err_code = characteristic_add(p_hrs->service_handle, &add_char_params, &(p_hrs->hrm_handles));
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
|
||||
if (p_hrs_init->p_body_sensor_location != NULL)
|
||||
{
|
||||
// Add body sensor location characteristic
|
||||
memset(&add_char_params, 0, sizeof(add_char_params));
|
||||
|
||||
add_char_params.uuid = BLE_UUID_BODY_SENSOR_LOCATION_CHAR;
|
||||
add_char_params.max_len = sizeof(uint8_t);
|
||||
add_char_params.init_len = sizeof(uint8_t);
|
||||
add_char_params.p_init_value = p_hrs_init->p_body_sensor_location;
|
||||
add_char_params.char_props.read = 1;
|
||||
add_char_params.read_access = p_hrs_init->bsl_rd_sec;
|
||||
|
||||
err_code = characteristic_add(p_hrs->service_handle, &add_char_params, &(p_hrs->bsl_handles));
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
}
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_hrs_heart_rate_measurement_send(ble_hrs_t * p_hrs, uint16_t heart_rate)
|
||||
{
|
||||
uint32_t err_code;
|
||||
|
||||
// Send value if connected and notifying
|
||||
if (p_hrs->conn_handle != BLE_CONN_HANDLE_INVALID)
|
||||
{
|
||||
uint8_t encoded_hrm[MAX_HRM_LEN];
|
||||
uint16_t len;
|
||||
uint16_t hvx_len;
|
||||
ble_gatts_hvx_params_t hvx_params;
|
||||
|
||||
len = hrm_encode(p_hrs, heart_rate, encoded_hrm);
|
||||
hvx_len = len;
|
||||
|
||||
memset(&hvx_params, 0, sizeof(hvx_params));
|
||||
|
||||
hvx_params.handle = p_hrs->hrm_handles.value_handle;
|
||||
hvx_params.type = BLE_GATT_HVX_NOTIFICATION;
|
||||
hvx_params.offset = 0;
|
||||
hvx_params.p_len = &hvx_len;
|
||||
hvx_params.p_data = encoded_hrm;
|
||||
|
||||
err_code = sd_ble_gatts_hvx(p_hrs->conn_handle, &hvx_params);
|
||||
if ((err_code == NRF_SUCCESS) && (hvx_len != len))
|
||||
{
|
||||
err_code = NRF_ERROR_DATA_SIZE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
err_code = NRF_ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
return err_code;
|
||||
}
|
||||
|
||||
|
||||
void ble_hrs_rr_interval_add(ble_hrs_t * p_hrs, uint16_t rr_interval)
|
||||
{
|
||||
if (p_hrs->rr_interval_count == BLE_HRS_MAX_BUFFERED_RR_INTERVALS)
|
||||
{
|
||||
// The rr_interval buffer is full, delete the oldest value
|
||||
memmove(&p_hrs->rr_interval[0],
|
||||
&p_hrs->rr_interval[1],
|
||||
(BLE_HRS_MAX_BUFFERED_RR_INTERVALS - 1) * sizeof(uint16_t));
|
||||
p_hrs->rr_interval_count--;
|
||||
}
|
||||
|
||||
// Add new value
|
||||
p_hrs->rr_interval[p_hrs->rr_interval_count++] = rr_interval;
|
||||
}
|
||||
|
||||
|
||||
bool ble_hrs_rr_interval_buffer_is_full(ble_hrs_t * p_hrs)
|
||||
{
|
||||
return (p_hrs->rr_interval_count == BLE_HRS_MAX_BUFFERED_RR_INTERVALS);
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_hrs_sensor_contact_supported_set(ble_hrs_t * p_hrs, bool is_sensor_contact_supported)
|
||||
{
|
||||
// Check if we are connected to peer
|
||||
if (p_hrs->conn_handle == BLE_CONN_HANDLE_INVALID)
|
||||
{
|
||||
p_hrs->is_sensor_contact_supported = is_sensor_contact_supported;
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NRF_ERROR_INVALID_STATE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ble_hrs_sensor_contact_detected_update(ble_hrs_t * p_hrs, bool is_sensor_contact_detected)
|
||||
{
|
||||
p_hrs->is_sensor_contact_detected = is_sensor_contact_detected;
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_hrs_body_sensor_location_set(ble_hrs_t * p_hrs, uint8_t body_sensor_location)
|
||||
{
|
||||
ble_gatts_value_t gatts_value;
|
||||
|
||||
// Initialize value struct.
|
||||
memset(&gatts_value, 0, sizeof(gatts_value));
|
||||
|
||||
gatts_value.len = sizeof(uint8_t);
|
||||
gatts_value.offset = 0;
|
||||
gatts_value.p_value = &body_sensor_location;
|
||||
|
||||
return sd_ble_gatts_value_set(p_hrs->conn_handle, p_hrs->bsl_handles.value_handle, &gatts_value);
|
||||
}
|
||||
|
||||
|
||||
void ble_hrs_on_gatt_evt(ble_hrs_t * p_hrs, nrf_ble_gatt_evt_t const * p_gatt_evt)
|
||||
{
|
||||
if ( (p_hrs->conn_handle == p_gatt_evt->conn_handle)
|
||||
&& (p_gatt_evt->evt_id == NRF_BLE_GATT_EVT_ATT_MTU_UPDATED))
|
||||
{
|
||||
p_hrs->max_hrm_len = p_gatt_evt->params.att_mtu_effective - OPCODE_LENGTH - HANDLE_LENGTH;
|
||||
}
|
||||
}
|
||||
#endif // NRF_MODULE_ENABLED(BLE_HRS)
|
||||
266
components/ble/ble_services/ble_hrs/ble_hrs.h
Normal file
266
components/ble/ble_services/ble_hrs/ble_hrs.h
Normal file
@@ -0,0 +1,266 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 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 ble_hrs Heart Rate Service
|
||||
* @{
|
||||
* @ingroup ble_sdk_srv
|
||||
* @brief Heart Rate Service module.
|
||||
*
|
||||
* @details This module implements the Heart Rate Service with the Heart Rate Measurement,
|
||||
* Body Sensor Location and Heart Rate Control Point characteristics.
|
||||
* During initialization it adds the Heart Rate Service and Heart Rate Measurement
|
||||
* characteristic to the BLE stack database. Optionally it also adds the
|
||||
* Body Sensor Location and Heart Rate Control Point characteristics.
|
||||
*
|
||||
* If enabled, notification of the Heart Rate Measurement characteristic is performed
|
||||
* when the application calls ble_hrs_heart_rate_measurement_send().
|
||||
*
|
||||
* The Heart Rate Service also provides a set of functions for manipulating the
|
||||
* various fields in the Heart Rate Measurement characteristic, as well as setting
|
||||
* the Body Sensor Location characteristic value.
|
||||
*
|
||||
* If an event handler is supplied by the application, the Heart Rate Service will
|
||||
* generate Heart Rate 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_hrs_t instance;
|
||||
* NRF_SDH_BLE_OBSERVER(anything, BLE_HRS_BLE_OBSERVER_PRIO,
|
||||
* ble_hrs_on_ble_evt, &instance);
|
||||
* @endcode
|
||||
*
|
||||
* @note Attention!
|
||||
* To maintain compliance with Nordic Semiconductor ASA Bluetooth profile
|
||||
* qualification listings, this section of source code must not be modified.
|
||||
*/
|
||||
|
||||
#ifndef BLE_HRS_H__
|
||||
#define BLE_HRS_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "ble.h"
|
||||
#include "ble_srv_common.h"
|
||||
#include "nrf_sdh_ble.h"
|
||||
#include "nrf_ble_gatt.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**@brief Macro for defining a ble_hrs instance.
|
||||
*
|
||||
* @param _name Name of the instance.
|
||||
* @hideinitializer
|
||||
*/
|
||||
#define BLE_HRS_DEF(_name) \
|
||||
static ble_hrs_t _name; \
|
||||
NRF_SDH_BLE_OBSERVER(_name ## _obs, \
|
||||
BLE_HRS_BLE_OBSERVER_PRIO, \
|
||||
ble_hrs_on_ble_evt, &_name)
|
||||
|
||||
// Body Sensor Location values
|
||||
#define BLE_HRS_BODY_SENSOR_LOCATION_OTHER 0
|
||||
#define BLE_HRS_BODY_SENSOR_LOCATION_CHEST 1
|
||||
#define BLE_HRS_BODY_SENSOR_LOCATION_WRIST 2
|
||||
#define BLE_HRS_BODY_SENSOR_LOCATION_FINGER 3
|
||||
#define BLE_HRS_BODY_SENSOR_LOCATION_HAND 4
|
||||
#define BLE_HRS_BODY_SENSOR_LOCATION_EAR_LOBE 5
|
||||
#define BLE_HRS_BODY_SENSOR_LOCATION_FOOT 6
|
||||
|
||||
#define BLE_HRS_MAX_BUFFERED_RR_INTERVALS 20 /**< Size of RR Interval buffer inside service. */
|
||||
|
||||
|
||||
/**@brief Heart Rate Service event type. */
|
||||
typedef enum
|
||||
{
|
||||
BLE_HRS_EVT_NOTIFICATION_ENABLED, /**< Heart Rate value notification enabled event. */
|
||||
BLE_HRS_EVT_NOTIFICATION_DISABLED /**< Heart Rate value notification disabled event. */
|
||||
} ble_hrs_evt_type_t;
|
||||
|
||||
/**@brief Heart Rate Service event. */
|
||||
typedef struct
|
||||
{
|
||||
ble_hrs_evt_type_t evt_type; /**< Type of event. */
|
||||
} ble_hrs_evt_t;
|
||||
|
||||
// Forward declaration of the ble_hrs_t type.
|
||||
typedef struct ble_hrs_s ble_hrs_t;
|
||||
|
||||
/**@brief Heart Rate Service event handler type. */
|
||||
typedef void (*ble_hrs_evt_handler_t) (ble_hrs_t * p_hrs, ble_hrs_evt_t * p_evt);
|
||||
|
||||
/**@brief Heart Rate Service init structure. This contains all options and data needed for
|
||||
* initialization of the service. */
|
||||
typedef struct
|
||||
{
|
||||
ble_hrs_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Heart Rate Service. */
|
||||
bool is_sensor_contact_supported; /**< Determines if sensor contact detection is to be supported. */
|
||||
uint8_t * p_body_sensor_location; /**< If not NULL, initial value of the Body Sensor Location characteristic. */
|
||||
security_req_t hrm_cccd_wr_sec; /**< Security requirement for writing the HRM characteristic CCCD. */
|
||||
security_req_t bsl_rd_sec; /**< Security requirement for reading the BSL characteristic value. */
|
||||
} ble_hrs_init_t;
|
||||
|
||||
/**@brief Heart Rate Service structure. This contains various status information for the service. */
|
||||
struct ble_hrs_s
|
||||
{
|
||||
ble_hrs_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Heart Rate Service. */
|
||||
bool is_expended_energy_supported; /**< TRUE if Expended Energy measurement is supported. */
|
||||
bool is_sensor_contact_supported; /**< TRUE if sensor contact detection is supported. */
|
||||
uint16_t service_handle; /**< Handle of Heart Rate Service (as provided by the BLE stack). */
|
||||
ble_gatts_char_handles_t hrm_handles; /**< Handles related to the Heart Rate Measurement characteristic. */
|
||||
ble_gatts_char_handles_t bsl_handles; /**< Handles related to the Body Sensor Location characteristic. */
|
||||
ble_gatts_char_handles_t hrcp_handles; /**< Handles related to the Heart Rate Control Point characteristic. */
|
||||
uint16_t conn_handle; /**< Handle of the current connection (as provided by the BLE stack, is BLE_CONN_HANDLE_INVALID if not in a connection). */
|
||||
bool is_sensor_contact_detected; /**< TRUE if sensor contact has been detected. */
|
||||
uint16_t rr_interval[BLE_HRS_MAX_BUFFERED_RR_INTERVALS]; /**< Set of RR Interval measurements since the last Heart Rate Measurement transmission. */
|
||||
uint16_t rr_interval_count; /**< Number of RR Interval measurements since the last Heart Rate Measurement transmission. */
|
||||
uint8_t max_hrm_len; /**< Current maximum HR measurement length, adjusted according to the current ATT MTU. */
|
||||
};
|
||||
|
||||
|
||||
/**@brief Function for initializing the Heart Rate Service.
|
||||
*
|
||||
* @param[out] p_hrs Heart Rate Service structure. This structure will have to be supplied by
|
||||
* the application. It will be initialized by this function, and will later
|
||||
* be used to identify this particular service instance.
|
||||
* @param[in] p_hrs_init Information needed to initialize the service.
|
||||
*
|
||||
* @return NRF_SUCCESS on successful initialization of service, otherwise an error code.
|
||||
*/
|
||||
uint32_t ble_hrs_init(ble_hrs_t * p_hrs, ble_hrs_init_t const * p_hrs_init);
|
||||
|
||||
|
||||
/**@brief Function for handling the GATT module's events.
|
||||
*
|
||||
* @details Handles all events from the GATT module of interest to the Heart Rate Service.
|
||||
*
|
||||
* @param[in] p_hrs Heart Rate Service structure.
|
||||
* @param[in] p_gatt_evt Event received from the GATT module.
|
||||
*/
|
||||
void ble_hrs_on_gatt_evt(ble_hrs_t * p_hrs, nrf_ble_gatt_evt_t const * p_gatt_evt);
|
||||
|
||||
|
||||
/**@brief Function for handling the Application's BLE Stack events.
|
||||
*
|
||||
* @details Handles all events from the BLE stack of interest to the Heart Rate Service.
|
||||
*
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
* @param[in] p_context Heart Rate Service structure.
|
||||
*/
|
||||
void ble_hrs_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
|
||||
|
||||
|
||||
/**@brief Function for sending heart rate measurement if notification has been enabled.
|
||||
*
|
||||
* @details The application calls this function after having performed a heart rate measurement.
|
||||
* If notification has been enabled, the heart rate measurement data is encoded and sent to
|
||||
* the client.
|
||||
*
|
||||
* @param[in] p_hrs Heart Rate Service structure.
|
||||
* @param[in] heart_rate New heart rate measurement.
|
||||
*
|
||||
* @return NRF_SUCCESS on success, otherwise an error code.
|
||||
*/
|
||||
uint32_t ble_hrs_heart_rate_measurement_send(ble_hrs_t * p_hrs, uint16_t heart_rate);
|
||||
|
||||
|
||||
/**@brief Function for adding a RR Interval measurement to the RR Interval buffer.
|
||||
*
|
||||
* @details All buffered RR Interval measurements will be included in the next heart rate
|
||||
* measurement message, up to the maximum number of measurements that will fit into the
|
||||
* message. If the buffer is full, the oldest measurement in the buffer will be deleted.
|
||||
*
|
||||
* @param[in] p_hrs Heart Rate Service structure.
|
||||
* @param[in] rr_interval New RR Interval measurement (will be buffered until the next
|
||||
* transmission of Heart Rate Measurement).
|
||||
*/
|
||||
void ble_hrs_rr_interval_add(ble_hrs_t * p_hrs, uint16_t rr_interval);
|
||||
|
||||
|
||||
/**@brief Function for checking if RR Interval buffer is full.
|
||||
*
|
||||
* @param[in] p_hrs Heart Rate Service structure.
|
||||
*
|
||||
* @return true if RR Interval buffer is full, false otherwise.
|
||||
*/
|
||||
bool ble_hrs_rr_interval_buffer_is_full(ble_hrs_t * p_hrs);
|
||||
|
||||
|
||||
/**@brief Function for setting the state of the Sensor Contact Supported bit.
|
||||
*
|
||||
* @param[in] p_hrs Heart Rate Service structure.
|
||||
* @param[in] is_sensor_contact_supported New state of the Sensor Contact Supported bit.
|
||||
*
|
||||
* @return NRF_SUCCESS on success, otherwise an error code.
|
||||
*/
|
||||
uint32_t ble_hrs_sensor_contact_supported_set(ble_hrs_t * p_hrs, bool is_sensor_contact_supported);
|
||||
|
||||
|
||||
/**@brief Function for setting the state of the Sensor Contact Detected bit.
|
||||
*
|
||||
* @param[in] p_hrs Heart Rate Service structure.
|
||||
* @param[in] is_sensor_contact_detected TRUE if sensor contact is detected, FALSE otherwise.
|
||||
*/
|
||||
void ble_hrs_sensor_contact_detected_update(ble_hrs_t * p_hrs, bool is_sensor_contact_detected);
|
||||
|
||||
|
||||
/**@brief Function for setting the Body Sensor Location.
|
||||
*
|
||||
* @details Sets a new value of the Body Sensor Location characteristic. The new value will be sent
|
||||
* to the client the next time the client reads the Body Sensor Location characteristic.
|
||||
*
|
||||
* @param[in] p_hrs Heart Rate Service structure.
|
||||
* @param[in] body_sensor_location New Body Sensor Location.
|
||||
*
|
||||
* @return NRF_SUCCESS on success, otherwise an error code.
|
||||
*/
|
||||
uint32_t ble_hrs_body_sensor_location_set(ble_hrs_t * p_hrs, uint8_t body_sensor_location);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // BLE_HRS_H__
|
||||
|
||||
/** @} */
|
||||
313
components/ble/ble_services/ble_hrs_c/ble_hrs_c.c
Normal file
313
components/ble/ble_services/ble_hrs_c/ble_hrs_c.c
Normal file
@@ -0,0 +1,313 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 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.
|
||||
*
|
||||
*/
|
||||
/**@cond To Make Doxygen skip documentation generation for this file.
|
||||
* @{
|
||||
*/
|
||||
#include "sdk_common.h"
|
||||
#if NRF_MODULE_ENABLED(BLE_HRS_C)
|
||||
#include "ble_hrs_c.h"
|
||||
#include "ble_db_discovery.h"
|
||||
#include "ble_types.h"
|
||||
#include "ble_gattc.h"
|
||||
|
||||
#define NRF_LOG_MODULE_NAME ble_hrs_c
|
||||
#include "nrf_log.h"
|
||||
NRF_LOG_MODULE_REGISTER();
|
||||
|
||||
#define HRM_FLAG_MASK_HR_16BIT (0x01 << 0) /**< Bit mask used to extract the type of heart rate value. This is used to find if the received heart rate is a 16 bit value or an 8 bit value. */
|
||||
#define HRM_FLAG_MASK_HR_RR_INT (0x01 << 4) /**< Bit mask used to extract the presence of RR_INTERVALS. This is used to find if the received measurement includes RR_INTERVALS. */
|
||||
|
||||
|
||||
/**@brief Function for interception of 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)
|
||||
{
|
||||
ble_hrs_c_t * p_ble_hrs_c = (ble_hrs_c_t *)p_ctx;
|
||||
|
||||
NRF_LOG_DEBUG("A GATT Client error has occurred on conn_handle: 0X%X", conn_handle);
|
||||
|
||||
if (p_ble_hrs_c->error_handler != NULL)
|
||||
{
|
||||
p_ble_hrs_c->error_handler(nrf_error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling Handle Value Notification received from the SoftDevice.
|
||||
*
|
||||
* @details This function uses the Handle Value Notification received from the SoftDevice
|
||||
* and checks whether it is a notification of the heart rate measurement from the peer. If
|
||||
* it is, this function decodes the heart rate measurement and sends it to the
|
||||
* application.
|
||||
*
|
||||
* @param[in] p_ble_hrs_c Pointer to the Heart Rate Client structure.
|
||||
* @param[in] p_ble_evt Pointer to the BLE event received.
|
||||
*/
|
||||
static void on_hvx(ble_hrs_c_t * p_ble_hrs_c, const ble_evt_t * p_ble_evt)
|
||||
{
|
||||
// Check if the event is on the link for this instance.
|
||||
if (p_ble_hrs_c->conn_handle != p_ble_evt->evt.gattc_evt.conn_handle)
|
||||
{
|
||||
NRF_LOG_DEBUG("Received HVX on link 0x%x, not associated to this instance. Ignore.",
|
||||
p_ble_evt->evt.gattc_evt.conn_handle);
|
||||
return;
|
||||
}
|
||||
|
||||
NRF_LOG_DEBUG("Received HVX on link 0x%x, hrm_handle 0x%x",
|
||||
p_ble_evt->evt.gattc_evt.params.hvx.handle,
|
||||
p_ble_hrs_c->peer_hrs_db.hrm_handle);
|
||||
|
||||
// Check if this is a heart rate notification.
|
||||
if (p_ble_evt->evt.gattc_evt.params.hvx.handle == p_ble_hrs_c->peer_hrs_db.hrm_handle)
|
||||
{
|
||||
ble_hrs_c_evt_t ble_hrs_c_evt;
|
||||
uint32_t index = 0;
|
||||
|
||||
ble_hrs_c_evt.evt_type = BLE_HRS_C_EVT_HRM_NOTIFICATION;
|
||||
ble_hrs_c_evt.conn_handle = p_ble_hrs_c->conn_handle;
|
||||
ble_hrs_c_evt.params.hrm.rr_intervals_cnt = 0;
|
||||
|
||||
if (!(p_ble_evt->evt.gattc_evt.params.hvx.data[index++] & HRM_FLAG_MASK_HR_16BIT))
|
||||
{
|
||||
// 8-bit heart rate value received.
|
||||
ble_hrs_c_evt.params.hrm.hr_value = p_ble_evt->evt.gattc_evt.params.hvx.data[index++]; //lint !e415 suppress Lint Warning 415: Likely access out of bond
|
||||
}
|
||||
else
|
||||
{
|
||||
// 16-bit heart rate value received.
|
||||
ble_hrs_c_evt.params.hrm.hr_value =
|
||||
uint16_decode(&(p_ble_evt->evt.gattc_evt.params.hvx.data[index]));
|
||||
index += sizeof(uint16_t);
|
||||
}
|
||||
|
||||
if ((p_ble_evt->evt.gattc_evt.params.hvx.data[0] & HRM_FLAG_MASK_HR_RR_INT))
|
||||
{
|
||||
uint32_t i;
|
||||
/*lint --e{415} --e{416} --e{662} --e{661} -save suppress Warning 415: possible access out of bond */
|
||||
for (i = 0; i < BLE_HRS_C_RR_INTERVALS_MAX_CNT; i ++)
|
||||
{
|
||||
if (index >= p_ble_evt->evt.gattc_evt.params.hvx.len)
|
||||
{
|
||||
break;
|
||||
}
|
||||
ble_hrs_c_evt.params.hrm.rr_intervals[i] =
|
||||
uint16_decode(&(p_ble_evt->evt.gattc_evt.params.hvx.data[index]));
|
||||
index += sizeof(uint16_t);
|
||||
}
|
||||
/*lint -restore*/
|
||||
ble_hrs_c_evt.params.hrm.rr_intervals_cnt = (uint8_t)i;
|
||||
}
|
||||
p_ble_hrs_c->evt_handler(p_ble_hrs_c, &ble_hrs_c_evt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling Disconnected event received from the SoftDevice.
|
||||
*
|
||||
* @details This function checks whether the disconnect event is happening on the link
|
||||
* associated with the current instance of the module. If the event is happening, the function sets the instance's
|
||||
* conn_handle to invalid.
|
||||
*
|
||||
* @param[in] p_ble_hrs_c Pointer to the Heart Rate Client structure.
|
||||
* @param[in] p_ble_evt Pointer to the BLE event received.
|
||||
*/
|
||||
static void on_disconnected(ble_hrs_c_t * p_ble_hrs_c, const ble_evt_t * p_ble_evt)
|
||||
{
|
||||
if (p_ble_hrs_c->conn_handle == p_ble_evt->evt.gap_evt.conn_handle)
|
||||
{
|
||||
p_ble_hrs_c->conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
p_ble_hrs_c->peer_hrs_db.hrm_cccd_handle = BLE_GATT_HANDLE_INVALID;
|
||||
p_ble_hrs_c->peer_hrs_db.hrm_handle = BLE_GATT_HANDLE_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ble_hrs_on_db_disc_evt(ble_hrs_c_t * p_ble_hrs_c, const ble_db_discovery_evt_t * p_evt)
|
||||
{
|
||||
// Check if the Heart Rate Service was discovered.
|
||||
if (p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE &&
|
||||
p_evt->params.discovered_db.srv_uuid.uuid == BLE_UUID_HEART_RATE_SERVICE &&
|
||||
p_evt->params.discovered_db.srv_uuid.type == BLE_UUID_TYPE_BLE)
|
||||
{
|
||||
// Find the CCCD Handle of the Heart Rate Measurement characteristic.
|
||||
uint32_t i;
|
||||
|
||||
ble_hrs_c_evt_t evt;
|
||||
|
||||
evt.evt_type = BLE_HRS_C_EVT_DISCOVERY_COMPLETE;
|
||||
evt.conn_handle = p_evt->conn_handle;
|
||||
|
||||
for (i = 0; i < p_evt->params.discovered_db.char_count; i++)
|
||||
{
|
||||
if (p_evt->params.discovered_db.charateristics[i].characteristic.uuid.uuid ==
|
||||
BLE_UUID_HEART_RATE_MEASUREMENT_CHAR)
|
||||
{
|
||||
// Found Heart Rate characteristic. Store CCCD handle and break.
|
||||
evt.params.peer_db.hrm_cccd_handle =
|
||||
p_evt->params.discovered_db.charateristics[i].cccd_handle;
|
||||
evt.params.peer_db.hrm_handle =
|
||||
p_evt->params.discovered_db.charateristics[i].characteristic.handle_value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
NRF_LOG_DEBUG("Heart Rate Service discovered at peer.");
|
||||
//If the instance has been assigned prior to db_discovery, assign the db_handles.
|
||||
if (p_ble_hrs_c->conn_handle != BLE_CONN_HANDLE_INVALID)
|
||||
{
|
||||
if ((p_ble_hrs_c->peer_hrs_db.hrm_cccd_handle == BLE_GATT_HANDLE_INVALID)&&
|
||||
(p_ble_hrs_c->peer_hrs_db.hrm_handle == BLE_GATT_HANDLE_INVALID))
|
||||
{
|
||||
p_ble_hrs_c->peer_hrs_db = evt.params.peer_db;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
p_ble_hrs_c->evt_handler(p_ble_hrs_c, &evt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_hrs_c_init(ble_hrs_c_t * p_ble_hrs_c, ble_hrs_c_init_t * p_ble_hrs_c_init)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_ble_hrs_c);
|
||||
VERIFY_PARAM_NOT_NULL(p_ble_hrs_c_init);
|
||||
|
||||
ble_uuid_t hrs_uuid;
|
||||
|
||||
hrs_uuid.type = BLE_UUID_TYPE_BLE;
|
||||
hrs_uuid.uuid = BLE_UUID_HEART_RATE_SERVICE;
|
||||
|
||||
p_ble_hrs_c->evt_handler = p_ble_hrs_c_init->evt_handler;
|
||||
p_ble_hrs_c->error_handler = p_ble_hrs_c_init->error_handler;
|
||||
p_ble_hrs_c->p_gatt_queue = p_ble_hrs_c_init->p_gatt_queue;
|
||||
p_ble_hrs_c->conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
p_ble_hrs_c->peer_hrs_db.hrm_cccd_handle = BLE_GATT_HANDLE_INVALID;
|
||||
p_ble_hrs_c->peer_hrs_db.hrm_handle = BLE_GATT_HANDLE_INVALID;
|
||||
|
||||
return ble_db_discovery_evt_register(&hrs_uuid);
|
||||
}
|
||||
|
||||
void ble_hrs_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
|
||||
{
|
||||
ble_hrs_c_t * p_ble_hrs_c = (ble_hrs_c_t *)p_context;
|
||||
|
||||
if ((p_ble_hrs_c == NULL) || (p_ble_evt == NULL))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch (p_ble_evt->header.evt_id)
|
||||
{
|
||||
case BLE_GATTC_EVT_HVX:
|
||||
on_hvx(p_ble_hrs_c, p_ble_evt);
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVT_DISCONNECTED:
|
||||
on_disconnected(p_ble_hrs_c, p_ble_evt);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for creating a message for writing to the CCCD.
|
||||
*/
|
||||
static uint32_t cccd_configure(ble_hrs_c_t * p_ble_hrs_c, bool enable)
|
||||
{
|
||||
NRF_LOG_DEBUG("Configuring CCCD. CCCD Handle = %d, Connection Handle = %d",
|
||||
p_ble_hrs_c->peer_hrs_db.hrm_cccd_handle,
|
||||
p_ble_hrs_c->conn_handle);
|
||||
|
||||
nrf_ble_gq_req_t hrs_c_req;
|
||||
uint8_t cccd[BLE_CCCD_VALUE_LEN];
|
||||
uint16_t cccd_val = enable ? BLE_GATT_HVX_NOTIFICATION : 0;
|
||||
|
||||
cccd[0] = LSB_16(cccd_val);
|
||||
cccd[1] = MSB_16(cccd_val);
|
||||
|
||||
memset(&hrs_c_req, 0, sizeof(hrs_c_req));
|
||||
|
||||
hrs_c_req.type = NRF_BLE_GQ_REQ_GATTC_WRITE;
|
||||
hrs_c_req.error_handler.cb = gatt_error_handler;
|
||||
hrs_c_req.error_handler.p_ctx = p_ble_hrs_c;
|
||||
hrs_c_req.params.gattc_write.handle = p_ble_hrs_c->peer_hrs_db.hrm_cccd_handle;
|
||||
hrs_c_req.params.gattc_write.len = BLE_CCCD_VALUE_LEN;
|
||||
hrs_c_req.params.gattc_write.p_value = cccd;
|
||||
hrs_c_req.params.gattc_write.write_op = BLE_GATT_OP_WRITE_REQ;
|
||||
|
||||
return nrf_ble_gq_item_add(p_ble_hrs_c->p_gatt_queue, &hrs_c_req, p_ble_hrs_c->conn_handle);
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_hrs_c_hrm_notif_enable(ble_hrs_c_t * p_ble_hrs_c)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_ble_hrs_c);
|
||||
|
||||
return cccd_configure(p_ble_hrs_c, true);
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_hrs_c_handles_assign(ble_hrs_c_t * p_ble_hrs_c,
|
||||
uint16_t conn_handle,
|
||||
const hrs_db_t * p_peer_hrs_handles)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_ble_hrs_c);
|
||||
|
||||
p_ble_hrs_c->conn_handle = conn_handle;
|
||||
if (p_peer_hrs_handles != NULL)
|
||||
{
|
||||
p_ble_hrs_c->peer_hrs_db = *p_peer_hrs_handles;
|
||||
}
|
||||
|
||||
return nrf_ble_gq_conn_handle_register(p_ble_hrs_c->p_gatt_queue, conn_handle);
|
||||
}
|
||||
/** @}
|
||||
* @endcond
|
||||
*/
|
||||
#endif // NRF_MODULE_ENABLED(BLE_HRS_C)
|
||||
300
components/ble/ble_services/ble_hrs_c/ble_hrs_c.h
Normal file
300
components/ble/ble_services/ble_hrs_c/ble_hrs_c.h
Normal file
@@ -0,0 +1,300 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 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 ble_hrs_c Heart Rate Service Client
|
||||
* @{
|
||||
* @ingroup ble_sdk_srv
|
||||
* @brief Heart Rate Service Client module.
|
||||
*
|
||||
* @details This module contains the APIs and types exposed by the Heart Rate Service Client
|
||||
* module. The application can use these APIs and types to perform the discovery of
|
||||
* Heart Rate Service at the peer and to interact with it.
|
||||
*
|
||||
* @warning Currently, this module only supports the Heart Rate Measurement characteristic. This
|
||||
* means that it is able to enable notification of the characteristic at the peer and
|
||||
* is able to receive Heart Rate Measurement notifications from the peer. It does not
|
||||
* support the Body Sensor Location and the Heart Rate Control Point characteristics.
|
||||
* When a Heart Rate Measurement is received, this module decodes only the
|
||||
* Heart Rate Measurement value field (both 8-bit and 16-bit) and provides it to
|
||||
* the application.
|
||||
*
|
||||
* @note The application must register this module as the BLE event observer by using the
|
||||
* NRF_SDH_BLE_OBSERVER macro. Example:
|
||||
* @code
|
||||
* ble_hrs_c_t instance;
|
||||
* NRF_SDH_BLE_OBSERVER(anything, BLE_HRS_C_BLE_OBSERVER_PRIO,
|
||||
* ble_hrs_c_on_ble_evt, &instance);
|
||||
* @endcode
|
||||
*/
|
||||
|
||||
#ifndef BLE_HRS_C_H__
|
||||
#define BLE_HRS_C_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include "ble.h"
|
||||
#include "ble_db_discovery.h"
|
||||
#include "ble_srv_common.h"
|
||||
#include "sdk_config.h"
|
||||
#include "nrf_ble_gq.h"
|
||||
#include "nrf_sdh_ble.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**@brief Macro for defining a ble_hrs_c instance.
|
||||
*
|
||||
* @param _name Name of the instance.
|
||||
* @hideinitializer
|
||||
*/
|
||||
#define BLE_HRS_C_DEF(_name) \
|
||||
static ble_hrs_c_t _name; \
|
||||
NRF_SDH_BLE_OBSERVER(_name ## _obs, \
|
||||
BLE_HRS_C_BLE_OBSERVER_PRIO, \
|
||||
ble_hrs_c_on_ble_evt, &_name)
|
||||
|
||||
/** @brief Macro for defining multiple ble_hrs_c instances.
|
||||
*
|
||||
* @param _name Name of the array of instances.
|
||||
* @param _cnt Number of instances to define.
|
||||
* @hideinitializer
|
||||
*/
|
||||
#define BLE_HRS_C_ARRAY_DEF(_name, _cnt) \
|
||||
static ble_hrs_c_t _name[_cnt]; \
|
||||
NRF_SDH_BLE_OBSERVERS(_name ## _obs, \
|
||||
BLE_HRS_C_BLE_OBSERVER_PRIO, \
|
||||
ble_hrs_c_on_ble_evt, &_name, _cnt)
|
||||
|
||||
|
||||
/** @brief Maximum number of RR intervals to be decoded for each HRM notifications (any extra RR intervals are ignored).
|
||||
*
|
||||
* This define should be defined in the sdk_config.h file to override the default.
|
||||
*/
|
||||
#ifndef BLE_HRS_C_RR_INTERVALS_MAX_CNT
|
||||
#define BLE_HRS_C_RR_INTERVALS_MAX_CNT 20
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* @defgroup hrs_c_enums Enumerations
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**@brief HRS Client event type. */
|
||||
typedef enum
|
||||
{
|
||||
BLE_HRS_C_EVT_DISCOVERY_COMPLETE = 1, /**< Event indicating that the Heart Rate Service was discovered at the peer. */
|
||||
BLE_HRS_C_EVT_HRM_NOTIFICATION /**< Event indicating that a notification of the Heart Rate Measurement characteristic was received from the peer. */
|
||||
} ble_hrs_c_evt_type_t;
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @defgroup hrs_c_structs Structures
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**@brief Structure containing the Heart Rate Measurement received from the peer. */
|
||||
typedef struct
|
||||
{
|
||||
uint16_t hr_value; /**< Heart Rate Value. */
|
||||
uint8_t rr_intervals_cnt; /**< Number of RR intervals. */
|
||||
uint16_t rr_intervals[BLE_HRS_C_RR_INTERVALS_MAX_CNT]; /**< RR intervals. */
|
||||
} ble_hrm_t;
|
||||
|
||||
/**@brief Structure containing the handles related to the Heart Rate Service found on the peer. */
|
||||
typedef struct
|
||||
{
|
||||
uint16_t hrm_cccd_handle; /**< Handle of the CCCD of the Heart Rate Measurement characteristic. */
|
||||
uint16_t hrm_handle; /**< Handle of the Heart Rate Measurement characteristic, as provided by the SoftDevice. */
|
||||
} hrs_db_t;
|
||||
|
||||
/**@brief Heart Rate Event structure. */
|
||||
typedef struct
|
||||
{
|
||||
ble_hrs_c_evt_type_t evt_type; /**< Type of the event. */
|
||||
uint16_t conn_handle; /**< Connection handle on which the Heart Rate service was discovered on the peer device..*/
|
||||
union
|
||||
{
|
||||
hrs_db_t peer_db; /**< Handles related to the Heart Rate, found on the peer device. This is filled if the evt_type is @ref BLE_HRS_C_EVT_DISCOVERY_COMPLETE.*/
|
||||
ble_hrm_t hrm; /**< Heart Rate Measurement received. This is filled if the evt_type is @ref BLE_HRS_C_EVT_HRM_NOTIFICATION. */
|
||||
} params;
|
||||
} ble_hrs_c_evt_t;
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @defgroup hrs_c_types Types
|
||||
* @{
|
||||
*/
|
||||
|
||||
// Forward declaration of the ble_bas_t type.
|
||||
typedef struct ble_hrs_c_s ble_hrs_c_t;
|
||||
|
||||
/**@brief Event handler type.
|
||||
*
|
||||
* @details This is the type of the event handler that is to be provided by the application
|
||||
* of this module to receive events.
|
||||
*/
|
||||
typedef void (* ble_hrs_c_evt_handler_t) (ble_hrs_c_t * p_ble_hrs_c, ble_hrs_c_evt_t * p_evt);
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @addtogroup hrs_c_structs
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**@brief Heart Rate Client structure.
|
||||
*/
|
||||
struct ble_hrs_c_s
|
||||
{
|
||||
uint16_t conn_handle; /**< Connection handle, as provided by the SoftDevice. */
|
||||
hrs_db_t peer_hrs_db; /**< Handles related to HRS on the peer. */
|
||||
ble_hrs_c_evt_handler_t evt_handler; /**< Application event handler to be called when there is an event related to the Heart Rate Service. */
|
||||
ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
|
||||
nrf_ble_gq_t * p_gatt_queue; /**< Pointer to the BLE GATT Queue instance. */
|
||||
};
|
||||
|
||||
/**@brief Heart Rate Client initialization structure.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
ble_hrs_c_evt_handler_t evt_handler; /**< Event handler to be called by the Heart Rate Client module when there is an event related to the Heart Rate Service. */
|
||||
ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
|
||||
nrf_ble_gq_t * p_gatt_queue; /**< Pointer to the BLE GATT Queue instance. */
|
||||
} ble_hrs_c_init_t;
|
||||
|
||||
/** @} */
|
||||
|
||||
|
||||
/**
|
||||
* @defgroup hrs_c_functions Functions
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**@brief Function for initializing the Heart Rate Client module.
|
||||
*
|
||||
* @details This function registers with the Database Discovery module for the Heart Rate Service.
|
||||
* The module looks for the presence of a Heart Rate Service instance at the peer
|
||||
* when a discovery is started.
|
||||
*
|
||||
* @param[in] p_ble_hrs_c Pointer to the Heart Rate Client structure.
|
||||
* @param[in] p_ble_hrs_c_init Pointer to the Heart Rate initialization structure that contains
|
||||
* the initialization information.
|
||||
*
|
||||
* @retval NRF_SUCCESS On successful initialization.
|
||||
* @retval err_code Otherwise, this function propagates the error code returned by the Database Discovery module API
|
||||
* @ref ble_db_discovery_evt_register.
|
||||
*/
|
||||
uint32_t ble_hrs_c_init(ble_hrs_c_t * p_ble_hrs_c, ble_hrs_c_init_t * p_ble_hrs_c_init);
|
||||
|
||||
|
||||
/**@brief Function for handling BLE events from the SoftDevice.
|
||||
*
|
||||
* @details This function handles the BLE events received from the SoftDevice. If a BLE
|
||||
* event is relevant to the Heart Rate Client module, the function uses the event's data to update
|
||||
* interval variables and, if necessary, send events to the application.
|
||||
*
|
||||
* @param[in] p_ble_evt Pointer to the BLE event.
|
||||
* @param[in] p_context Pointer to the Heart Rate Client structure.
|
||||
*/
|
||||
void ble_hrs_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
|
||||
|
||||
|
||||
/**@brief Function for requesting the peer to start sending notification of Heart Rate
|
||||
* Measurement.
|
||||
*
|
||||
* @details This function enables notification of the Heart Rate Measurement at the peer
|
||||
* by writing to the CCCD of the Heart Rate Measurement characteristic.
|
||||
*
|
||||
* @param p_ble_hrs_c Pointer to the Heart Rate Client structure.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the SoftDevice is requested to write to the CCCD of the peer.
|
||||
* @retval err_code Otherwise, this function propagates the error code returned
|
||||
* by the SoftDevice API @ref sd_ble_gattc_write.
|
||||
*/
|
||||
uint32_t ble_hrs_c_hrm_notif_enable(ble_hrs_c_t * p_ble_hrs_c);
|
||||
|
||||
|
||||
/**@brief Function for handling events from the Database Discovery module.
|
||||
*
|
||||
* @details Call this function when you get a callback event from the Database Discovery module.
|
||||
* This function handles an event from the Database Discovery module and determines
|
||||
* whether it relates to the discovery of Heart Rate Service at the peer. If it does, the function
|
||||
* calls the application's event handler to indicate that the Heart Rate Service was
|
||||
* discovered at the peer. The function also populates the event with service-related
|
||||
* information before providing it to the application.
|
||||
*
|
||||
* @param[in] p_ble_hrs_c Pointer to the Heart Rate Client structure instance for associating the link.
|
||||
* @param[in] p_evt Pointer to the event received from the Database Discovery module.
|
||||
*
|
||||
*/
|
||||
void ble_hrs_on_db_disc_evt(ble_hrs_c_t * p_ble_hrs_c, const ble_db_discovery_evt_t * p_evt);
|
||||
|
||||
|
||||
/**@brief Function for assigning handles to an instance of hrs_c.
|
||||
*
|
||||
* @details Call this function when a link has been established with a peer to
|
||||
* associate the link to this instance of the module. This association makes it
|
||||
* possible to handle several links and associate each link to a particular
|
||||
* instance of this module. The connection handle and attribute handles are
|
||||
* provided from the discovery event @ref BLE_HRS_C_EVT_DISCOVERY_COMPLETE.
|
||||
*
|
||||
* @param[in] p_ble_hrs_c Pointer to the Heart Rate Client structure instance for associating the link.
|
||||
* @param[in] conn_handle Connection handle to associate with the given Heart Rate Client Instance.
|
||||
* @param[in] p_peer_hrs_handles Attribute handles for the HRS server you want this HRS_C client to
|
||||
* interact with.
|
||||
*/
|
||||
uint32_t ble_hrs_c_handles_assign(ble_hrs_c_t * p_ble_hrs_c,
|
||||
uint16_t conn_handle,
|
||||
const hrs_db_t * p_peer_hrs_handles);
|
||||
|
||||
/** @} */ // End tag for Function group.
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // BLE_HRS_C_H__
|
||||
|
||||
/** @} */ // End tag for the file.
|
||||
404
components/ble/ble_services/ble_hts/ble_hts.c
Normal file
404
components/ble/ble_services/ble_hts/ble_hts.c
Normal file
@@ -0,0 +1,404 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 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.
|
||||
*
|
||||
*/
|
||||
/* Attention!
|
||||
* To maintain compliance with Nordic Semiconductor ASA's Bluetooth profile
|
||||
* qualification listings, this section of source code must not be modified.
|
||||
*/
|
||||
#include "sdk_common.h"
|
||||
#if NRF_MODULE_ENABLED(BLE_HTS)
|
||||
#include "ble_err.h"
|
||||
#include "ble_hts.h"
|
||||
#include <string.h>
|
||||
#include "ble_srv_common.h"
|
||||
|
||||
|
||||
#define OPCODE_LENGTH 1 /**< Length of opcode inside Health Thermometer Measurement packet. */
|
||||
#define HANDLE_LENGTH 2 /**< Length of handle inside Health Thermometer Measurement packet. */
|
||||
#define MAX_HTM_LEN (BLE_GATT_ATT_MTU_DEFAULT - OPCODE_LENGTH - HANDLE_LENGTH) /**< Maximum size of a transmitted Health Thermometer Measurement. */
|
||||
|
||||
// Health Thermometer Measurement flag bits
|
||||
#define HTS_MEAS_FLAG_TEMP_UNITS_BIT (0x01 << 0) /**< Temperature Units flag. */
|
||||
#define HTS_MEAS_FLAG_TIME_STAMP_BIT (0x01 << 1) /**< Time Stamp flag. */
|
||||
#define HTS_MEAS_FLAG_TEMP_TYPE_BIT (0x01 << 2) /**< Temperature Type flag. */
|
||||
|
||||
|
||||
/**@brief Function for interception of GATT errors and @ref nrf_ble_gq errors.
|
||||
*
|
||||
* @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)
|
||||
{
|
||||
ble_hts_t * p_hts = (ble_hts_t *)p_ctx;
|
||||
|
||||
if (p_hts->error_handler != NULL)
|
||||
{
|
||||
p_hts->error_handler(nrf_error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling the Connect event.
|
||||
*
|
||||
* @param[in] p_hts Health Thermometer Service structure.
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
*/
|
||||
static void on_connect(ble_hts_t * p_hts, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
|
||||
p_hts->conn_handle = p_ble_evt->evt.gatts_evt.conn_handle;
|
||||
|
||||
err_code = nrf_ble_gq_conn_handle_register(p_hts->p_gatt_queue, p_hts->conn_handle);
|
||||
|
||||
if ((p_hts->error_handler != NULL) &&
|
||||
(err_code != NRF_SUCCESS))
|
||||
{
|
||||
p_hts->error_handler(err_code);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling the Disconnect event.
|
||||
*
|
||||
* @param[in] p_hts Health Thermometer Service structure.
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
*/
|
||||
static void on_disconnect(ble_hts_t * p_hts, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
UNUSED_PARAMETER(p_ble_evt);
|
||||
p_hts->conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling write events to the Blood Pressure Measurement characteristic.
|
||||
*
|
||||
* @param[in] p_hts Health Thermometer Service structure.
|
||||
* @param[in] p_evt_write Write event received from the BLE stack.
|
||||
*/
|
||||
static void on_cccd_write(ble_hts_t * p_hts, ble_gatts_evt_write_t const * p_evt_write)
|
||||
{
|
||||
if (p_evt_write->len == 2)
|
||||
{
|
||||
// CCCD written, update indication state
|
||||
if (p_hts->evt_handler != NULL)
|
||||
{
|
||||
ble_hts_evt_t evt;
|
||||
|
||||
if (ble_srv_is_indication_enabled(p_evt_write->data))
|
||||
{
|
||||
evt.evt_type = BLE_HTS_EVT_INDICATION_ENABLED;
|
||||
}
|
||||
else
|
||||
{
|
||||
evt.evt_type = BLE_HTS_EVT_INDICATION_DISABLED;
|
||||
}
|
||||
|
||||
p_hts->evt_handler(p_hts, &evt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling the Write event.
|
||||
*
|
||||
* @param[in] p_hts Health Thermometer Service structure.
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
*/
|
||||
static void on_write(ble_hts_t * p_hts, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
ble_gatts_evt_write_t const * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
|
||||
|
||||
if (p_evt_write->handle == p_hts->meas_handles.cccd_handle)
|
||||
{
|
||||
on_cccd_write(p_hts, p_evt_write);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling the HVC event.
|
||||
*
|
||||
* @details Handles HVC events from the BLE stack.
|
||||
*
|
||||
* @param[in] p_hts Health Thermometer Service structure.
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
*/
|
||||
static void on_hvc(ble_hts_t * p_hts, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
ble_gatts_evt_hvc_t const * p_hvc = &p_ble_evt->evt.gatts_evt.params.hvc;
|
||||
|
||||
if (p_hvc->handle == p_hts->meas_handles.value_handle)
|
||||
{
|
||||
ble_hts_evt_t evt;
|
||||
|
||||
evt.evt_type = BLE_HTS_EVT_INDICATION_CONFIRMED;
|
||||
p_hts->evt_handler(p_hts, &evt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ble_hts_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
|
||||
{
|
||||
ble_hts_t * p_hts = (ble_hts_t *)p_context;
|
||||
|
||||
switch (p_ble_evt->header.evt_id)
|
||||
{
|
||||
case BLE_GAP_EVT_CONNECTED:
|
||||
on_connect(p_hts, p_ble_evt);
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVT_DISCONNECTED:
|
||||
on_disconnect(p_hts, p_ble_evt);
|
||||
break;
|
||||
|
||||
case BLE_GATTS_EVT_WRITE:
|
||||
on_write(p_hts, p_ble_evt);
|
||||
break;
|
||||
|
||||
case BLE_GATTS_EVT_HVC:
|
||||
on_hvc(p_hts, p_ble_evt);
|
||||
break;
|
||||
|
||||
default:
|
||||
// No implementation needed.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for encoding a Health Thermometer Measurement.
|
||||
*
|
||||
* @param[in] p_hts Health Thermometer Service structure.
|
||||
* @param[in] p_hts_meas Measurement to be encoded.
|
||||
* @param[out] p_encoded_buffer Buffer where the encoded data will be written.
|
||||
*
|
||||
* @return Size of encoded data.
|
||||
*/
|
||||
static uint8_t hts_measurement_encode(ble_hts_t * p_hts,
|
||||
ble_hts_meas_t * p_hts_meas,
|
||||
uint8_t * p_encoded_buffer)
|
||||
{
|
||||
uint8_t flags = 0;
|
||||
uint8_t len = 1;
|
||||
uint32_t encoded_temp;
|
||||
|
||||
// Flags field
|
||||
if (p_hts_meas->temp_in_fahr_units)
|
||||
{
|
||||
flags |= HTS_MEAS_FLAG_TEMP_UNITS_BIT;
|
||||
}
|
||||
if (p_hts_meas->time_stamp_present)
|
||||
{
|
||||
flags |= HTS_MEAS_FLAG_TIME_STAMP_BIT;
|
||||
}
|
||||
|
||||
// Temperature Measurement Value field
|
||||
if (p_hts_meas->temp_in_fahr_units)
|
||||
{
|
||||
flags |= HTS_MEAS_FLAG_TEMP_UNITS_BIT;
|
||||
|
||||
encoded_temp = ((p_hts_meas->temp_in_fahr.exponent << 24) & 0xFF000000) |
|
||||
((p_hts_meas->temp_in_fahr.mantissa << 0) & 0x00FFFFFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
encoded_temp = ((p_hts_meas->temp_in_celcius.exponent << 24) & 0xFF000000) |
|
||||
((p_hts_meas->temp_in_celcius.mantissa << 0) & 0x00FFFFFF);
|
||||
}
|
||||
len += uint32_encode(encoded_temp, &p_encoded_buffer[len]);
|
||||
|
||||
// Time Stamp field
|
||||
if (p_hts_meas->time_stamp_present)
|
||||
{
|
||||
flags |= HTS_MEAS_FLAG_TIME_STAMP_BIT;
|
||||
len += ble_date_time_encode(&p_hts_meas->time_stamp, &p_encoded_buffer[len]);
|
||||
}
|
||||
|
||||
// Temperature Type field
|
||||
if (p_hts_meas->temp_type_present)
|
||||
{
|
||||
flags |= HTS_MEAS_FLAG_TEMP_TYPE_BIT;
|
||||
p_encoded_buffer[len++] = p_hts_meas->temp_type;
|
||||
}
|
||||
|
||||
// Flags field
|
||||
p_encoded_buffer[0] = flags;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_hts_init(ble_hts_t * p_hts, ble_hts_init_t const * p_hts_init)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_hts);
|
||||
VERIFY_PARAM_NOT_NULL(p_hts_init);
|
||||
VERIFY_PARAM_NOT_NULL(p_hts_init->p_gatt_queue);
|
||||
|
||||
uint32_t err_code;
|
||||
uint8_t init_value[MAX_HTM_LEN];
|
||||
ble_hts_meas_t initial_htm;
|
||||
ble_uuid_t ble_uuid;
|
||||
ble_add_char_params_t add_char_params;
|
||||
|
||||
// Initialize service structure
|
||||
p_hts->evt_handler = p_hts_init->evt_handler;
|
||||
p_hts->p_gatt_queue = p_hts_init->p_gatt_queue;
|
||||
p_hts->error_handler = p_hts_init->error_handler;
|
||||
p_hts->conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
p_hts->temp_type = p_hts_init->temp_type;
|
||||
|
||||
// Add service
|
||||
BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_HEALTH_THERMOMETER_SERVICE);
|
||||
|
||||
err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &ble_uuid, &p_hts->service_handle);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
|
||||
// Add measurement characteristic
|
||||
memset(&add_char_params, 0, sizeof(add_char_params));
|
||||
memset(&initial_htm, 0, sizeof(initial_htm));
|
||||
|
||||
add_char_params.uuid = BLE_UUID_TEMPERATURE_MEASUREMENT_CHAR;
|
||||
add_char_params.init_len = hts_measurement_encode(p_hts, &initial_htm, init_value);
|
||||
add_char_params.max_len = MAX_HTM_LEN;
|
||||
add_char_params.p_init_value = init_value;
|
||||
add_char_params.is_var_len = true;
|
||||
add_char_params.char_props.indicate = 1;
|
||||
add_char_params.cccd_write_access = p_hts_init->ht_meas_cccd_wr_sec;
|
||||
|
||||
err_code = characteristic_add(p_hts->service_handle, &add_char_params, &p_hts->meas_handles);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
|
||||
// Add temperature type characteristic
|
||||
if (p_hts_init->temp_type_as_characteristic)
|
||||
{
|
||||
memset(&add_char_params, 0, sizeof(add_char_params));
|
||||
|
||||
add_char_params.uuid = BLE_UUID_TEMPERATURE_TYPE_CHAR;
|
||||
add_char_params.max_len = sizeof(uint8_t);
|
||||
add_char_params.char_props.read = 1;
|
||||
add_char_params.read_access = p_hts_init->ht_type_rd_sec;
|
||||
add_char_params.init_len = sizeof(uint8_t);
|
||||
add_char_params.p_init_value = (uint8_t *) &(p_hts_init->temp_type);
|
||||
|
||||
err_code = characteristic_add(p_hts->service_handle,
|
||||
&add_char_params,
|
||||
&p_hts->temp_type_handles);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
}
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_hts_measurement_send(ble_hts_t * p_hts, ble_hts_meas_t * p_hts_meas)
|
||||
{
|
||||
uint32_t err_code;
|
||||
|
||||
// Send value if connected
|
||||
if (p_hts->conn_handle != BLE_CONN_HANDLE_INVALID)
|
||||
{
|
||||
uint8_t encoded_hts_meas[MAX_HTM_LEN];
|
||||
uint16_t len;
|
||||
nrf_ble_gq_req_t hts_req;
|
||||
|
||||
len = hts_measurement_encode(p_hts, p_hts_meas, encoded_hts_meas);
|
||||
|
||||
memset(&hts_req, 0, sizeof(nrf_ble_gq_req_t));
|
||||
|
||||
hts_req.type = NRF_BLE_GQ_REQ_GATTS_HVX;
|
||||
hts_req.error_handler.cb = gatt_error_handler;
|
||||
hts_req.error_handler.p_ctx = p_hts;
|
||||
hts_req.params.gatts_hvx.handle = p_hts->meas_handles.value_handle;
|
||||
hts_req.params.gatts_hvx.offset = 0;
|
||||
hts_req.params.gatts_hvx.p_data = encoded_hts_meas;
|
||||
hts_req.params.gatts_hvx.p_len = &len;
|
||||
hts_req.params.gatts_hvx.type = BLE_GATT_HVX_INDICATION;
|
||||
|
||||
err_code = nrf_ble_gq_item_add(p_hts->p_gatt_queue, &hts_req, p_hts->conn_handle);
|
||||
}
|
||||
else
|
||||
{
|
||||
err_code = NRF_ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
return err_code;
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_hts_is_indication_enabled(ble_hts_t * p_hts, bool * p_indication_enabled)
|
||||
{
|
||||
uint32_t err_code;
|
||||
uint8_t cccd_value_buf[BLE_CCCD_VALUE_LEN];
|
||||
ble_gatts_value_t gatts_value;
|
||||
|
||||
// Initialize value struct.
|
||||
memset(&gatts_value, 0, sizeof(gatts_value));
|
||||
|
||||
gatts_value.len = BLE_CCCD_VALUE_LEN;
|
||||
gatts_value.offset = 0;
|
||||
gatts_value.p_value = cccd_value_buf;
|
||||
|
||||
err_code = sd_ble_gatts_value_get(p_hts->conn_handle,
|
||||
p_hts->meas_handles.cccd_handle,
|
||||
&gatts_value);
|
||||
if (err_code == NRF_SUCCESS)
|
||||
{
|
||||
*p_indication_enabled = ble_srv_is_indication_enabled(cccd_value_buf);
|
||||
}
|
||||
if (err_code == BLE_ERROR_GATTS_SYS_ATTR_MISSING)
|
||||
{
|
||||
*p_indication_enabled = false;
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
return err_code;
|
||||
}
|
||||
#endif // NRF_MODULE_ENABLED(BLE_HTS)
|
||||
224
components/ble/ble_services/ble_hts/ble_hts.h
Normal file
224
components/ble/ble_services/ble_hts/ble_hts.h
Normal file
@@ -0,0 +1,224 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 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 ble_hts Health Thermometer Service
|
||||
* @{
|
||||
* @ingroup ble_sdk_srv
|
||||
* @brief Health Thermometer Service module.
|
||||
*
|
||||
* @details This module implements the Health Thermometer Service.
|
||||
*
|
||||
* If an event handler is supplied by the application, the Health Thermometer
|
||||
* Service will generate Health Thermometer 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_hts_t instance;
|
||||
* NRF_SDH_BLE_OBSERVER(anything, BLE_HTS_BLE_OBSERVER_PRIO,
|
||||
* ble_hts_on_ble_evt, &instance);
|
||||
* @endcode
|
||||
*
|
||||
* @note Attention!
|
||||
* To maintain compliance with Nordic Semiconductor ASA Bluetooth profile
|
||||
* qualification listings, this section of source code must not be modified.
|
||||
*/
|
||||
|
||||
#ifndef BLE_HTS_H__
|
||||
#define BLE_HTS_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "ble.h"
|
||||
#include "ble_srv_common.h"
|
||||
#include "ble_date_time.h"
|
||||
#include "nrf_sdh_ble.h"
|
||||
#include "nrf_ble_gq.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**@brief Macro for defining a ble_hts instance.
|
||||
*
|
||||
* @param _name Name of the instance.
|
||||
* @hideinitializer
|
||||
*/
|
||||
#define BLE_HTS_DEF(_name) \
|
||||
static ble_hts_t _name; \
|
||||
NRF_SDH_BLE_OBSERVER(_name ## _obs, \
|
||||
BLE_HTS_BLE_OBSERVER_PRIO, \
|
||||
ble_hts_on_ble_evt, &_name)
|
||||
|
||||
// Temperature Type measurement locations
|
||||
#define BLE_HTS_TEMP_TYPE_ARMPIT 1
|
||||
#define BLE_HTS_TEMP_TYPE_BODY 2
|
||||
#define BLE_HTS_TEMP_TYPE_EAR 3
|
||||
#define BLE_HTS_TEMP_TYPE_FINGER 4
|
||||
#define BLE_HTS_TEMP_TYPE_GI_TRACT 5
|
||||
#define BLE_HTS_TEMP_TYPE_MOUTH 6
|
||||
#define BLE_HTS_TEMP_TYPE_RECTUM 7
|
||||
#define BLE_HTS_TEMP_TYPE_TOE 8
|
||||
#define BLE_HTS_TEMP_TYPE_EAR_DRUM 9
|
||||
|
||||
|
||||
/**@brief Health Thermometer Service event type. */
|
||||
typedef enum
|
||||
{
|
||||
BLE_HTS_EVT_INDICATION_ENABLED, /**< Health Thermometer value indication enabled event. */
|
||||
BLE_HTS_EVT_INDICATION_DISABLED, /**< Health Thermometer value indication disabled event. */
|
||||
BLE_HTS_EVT_INDICATION_CONFIRMED /**< Confirmation of a temperature measurement indication has been received. */
|
||||
} ble_hts_evt_type_t;
|
||||
|
||||
/**@brief Health Thermometer Service event. */
|
||||
typedef struct
|
||||
{
|
||||
ble_hts_evt_type_t evt_type; /**< Type of event. */
|
||||
} ble_hts_evt_t;
|
||||
|
||||
// Forward declaration of the ble_hts_t type.
|
||||
typedef struct ble_hts_s ble_hts_t;
|
||||
|
||||
/**@brief Health Thermometer Service event handler type. */
|
||||
typedef void (*ble_hts_evt_handler_t) (ble_hts_t * p_hts, ble_hts_evt_t * p_evt);
|
||||
|
||||
/**@brief FLOAT format (IEEE-11073 32-bit FLOAT, defined as a 32-bit value with a 24-bit mantissa
|
||||
* and an 8-bit exponent. */
|
||||
typedef struct
|
||||
{
|
||||
int8_t exponent; /**< Base 10 exponent */
|
||||
int32_t mantissa; /**< Mantissa, should be using only 24 bits */
|
||||
} ieee_float32_t;
|
||||
|
||||
/**@brief Health Thermometer Service init structure. This contains all options and data
|
||||
* needed for initialization of the service. */
|
||||
typedef struct
|
||||
{
|
||||
ble_hts_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Health Thermometer Service. */
|
||||
ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
|
||||
security_req_t ht_meas_cccd_wr_sec; /**< Security requirement for writing health thermometer measurement characteristic CCCD. */
|
||||
security_req_t ht_type_rd_sec; /**< Security requirement for reading health thermometer type characteristic. */
|
||||
uint8_t temp_type_as_characteristic; /**< Set non-zero if temp type given as characteristic */
|
||||
uint8_t temp_type; /**< Temperature type if temperature characteristic is used */
|
||||
nrf_ble_gq_t * p_gatt_queue; /**< Pointer to BLE GATT Queue instance. */
|
||||
} ble_hts_init_t;
|
||||
|
||||
/**@brief Health Thermometer Service structure. This contains various status information for
|
||||
* the service. */
|
||||
struct ble_hts_s
|
||||
{
|
||||
ble_hts_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Health Thermometer Service. */
|
||||
ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
|
||||
uint16_t service_handle; /**< Handle of Health Thermometer Service (as provided by the BLE stack). */
|
||||
ble_gatts_char_handles_t meas_handles; /**< Handles related to the Health Thermometer Measurement characteristic. */
|
||||
ble_gatts_char_handles_t temp_type_handles; /**< Handles related to the Health Thermometer Temperature Type characteristic. */
|
||||
uint16_t conn_handle; /**< Handle of the current connection (as provided by the BLE stack, is BLE_CONN_HANDLE_INVALID if not in a connection). */
|
||||
uint8_t temp_type; /**< Temperature type indicates where the measurement was taken. */
|
||||
nrf_ble_gq_t * p_gatt_queue; /**< Pointer to BLE GATT Queue instance. */
|
||||
};
|
||||
|
||||
/**@brief Health Thermometer Service measurement structure. This contains a Health Thermometer
|
||||
* measurement. */
|
||||
typedef struct ble_hts_meas_s
|
||||
{
|
||||
bool temp_in_fahr_units; /**< True if Temperature is in Fahrenheit units, Celcius otherwise. */
|
||||
bool time_stamp_present; /**< True if Time Stamp is present. */
|
||||
bool temp_type_present; /**< True if Temperature Type is present. */
|
||||
ieee_float32_t temp_in_celcius; /**< Temperature Measurement Value (Celcius). */
|
||||
ieee_float32_t temp_in_fahr; /**< Temperature Measurement Value (Fahrenheit). */
|
||||
ble_date_time_t time_stamp; /**< Time Stamp. */
|
||||
uint8_t temp_type; /**< Temperature Type. */
|
||||
} ble_hts_meas_t;
|
||||
|
||||
|
||||
/**@brief Function for initializing the Health Thermometer Service.
|
||||
*
|
||||
* @param[out] p_hts Health Thermometer Service structure. This structure will have to
|
||||
* be supplied by the application. It will be initialized by this function,
|
||||
* and will later be used to identify this particular service instance.
|
||||
* @param[in] p_hts_init Information needed to initialize the service.
|
||||
*
|
||||
* @return NRF_SUCCESS on successful initialization of service, otherwise an error code.
|
||||
*/
|
||||
uint32_t ble_hts_init(ble_hts_t * p_hts, const ble_hts_init_t * p_hts_init);
|
||||
|
||||
|
||||
/**@brief Function for handling the Application's BLE Stack events.
|
||||
*
|
||||
* @details Handles all events from the BLE stack of interest to the Health Thermometer Service.
|
||||
*
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
* @param[in] p_context Health Thermometer Service structure.
|
||||
*/
|
||||
void ble_hts_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
|
||||
|
||||
|
||||
/**@brief Function for sending health thermometer measurement if indication has been enabled.
|
||||
*
|
||||
* @details The application calls this function after having performed a Health Thermometer
|
||||
* measurement. If indication has been enabled, the measurement data is encoded and
|
||||
* sent to the client.
|
||||
*
|
||||
* @param[in] p_hts Health Thermometer Service structure.
|
||||
* @param[in] p_hts_meas Pointer to new health thermometer measurement.
|
||||
*
|
||||
* @return NRF_SUCCESS on success, otherwise an error code.
|
||||
*/
|
||||
uint32_t ble_hts_measurement_send(ble_hts_t * p_hts, ble_hts_meas_t * p_hts_meas);
|
||||
|
||||
|
||||
/**@brief Function for checking if indication of Temperature Measurement is currently enabled.
|
||||
*
|
||||
* @param[in] p_hts Health Thermometer Service structure.
|
||||
* @param[out] p_indication_enabled TRUE if indication is enabled, FALSE otherwise.
|
||||
*
|
||||
* @return NRF_SUCCESS on success, otherwise an error code.
|
||||
*/
|
||||
uint32_t ble_hts_is_indication_enabled(ble_hts_t * p_hts, bool * p_indication_enabled);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // BLE_HTS_H__
|
||||
|
||||
/** @} */
|
||||
200
components/ble/ble_services/ble_ias/ble_ias.c
Normal file
200
components/ble/ble_services/ble_ias/ble_ias.c
Normal file
@@ -0,0 +1,200 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 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.
|
||||
*
|
||||
*/
|
||||
/* Attention!
|
||||
* To maintain compliance with Nordic Semiconductor ASA's Bluetooth profile
|
||||
* qualification listings, this section of source code must not be modified.
|
||||
*/
|
||||
#include "sdk_common.h"
|
||||
#if NRF_MODULE_ENABLED(BLE_IAS)
|
||||
#include "ble_ias.h"
|
||||
#include <string.h>
|
||||
#include "ble_srv_common.h"
|
||||
|
||||
#define NRF_LOG_MODULE_NAME ble_ias
|
||||
#if BLE_IAS_CONFIG_LOG_ENABLED
|
||||
#define NRF_LOG_LEVEL BLE_IAS_CONFIG_LOG_LEVEL
|
||||
#define NRF_LOG_INFO_COLOR BLE_IAS_CONFIG_INFO_COLOR
|
||||
#define NRF_LOG_DEBUG_COLOR BLE_IAS_CONFIG_DEBUG_COLOR
|
||||
#else // BLE_IAS_CONFIG_LOG_ENABLED
|
||||
#define NRF_LOG_LEVEL 0
|
||||
#endif // BLE_IAS_CONFIG_LOG_ENABLED
|
||||
#include "nrf_log.h"
|
||||
NRF_LOG_MODULE_REGISTER();
|
||||
|
||||
|
||||
#define INITIAL_ALERT_LEVEL BLE_CHAR_ALERT_LEVEL_NO_ALERT
|
||||
|
||||
|
||||
/**@brief Function for handling the Connect event.
|
||||
*
|
||||
* @param[in] p_ias Immediate Alert Service structure.
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
*/
|
||||
static void on_connect(ble_ias_t * p_ias, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
ble_ias_client_context_t * p_client = NULL;
|
||||
|
||||
err_code = blcm_link_ctx_get(p_ias->p_link_ctx_storage,
|
||||
p_ble_evt->evt.gap_evt.conn_handle,
|
||||
(void *) &p_client);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
NRF_LOG_ERROR("Link context for 0x%02X connection handle could not be fetched.",
|
||||
p_ble_evt->evt.gap_evt.conn_handle);
|
||||
}
|
||||
else
|
||||
{
|
||||
p_client->alert_level = INITIAL_ALERT_LEVEL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling the Write event.
|
||||
*
|
||||
* @param[in] p_ias Immediate Alert Service structure.
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
*/
|
||||
static void on_write(ble_ias_t * p_ias, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
ble_gatts_evt_write_t const * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
|
||||
|
||||
if ((p_evt_write->handle == p_ias->alert_level_handles.value_handle) && (p_evt_write->len == 1))
|
||||
{
|
||||
// Alert level written, call application event handler
|
||||
ret_code_t err_code;
|
||||
ble_ias_evt_t evt;
|
||||
ble_ias_client_context_t * p_client;
|
||||
|
||||
err_code = blcm_link_ctx_get(p_ias->p_link_ctx_storage,
|
||||
p_ble_evt->evt.gatts_evt.conn_handle,
|
||||
(void *) &p_client);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
NRF_LOG_ERROR("Link context for 0x%02X connection handle could not be fetched.",
|
||||
p_ble_evt->evt.gatts_evt.conn_handle);
|
||||
}
|
||||
else
|
||||
{
|
||||
p_client->alert_level = p_evt_write->data[0];
|
||||
}
|
||||
|
||||
evt.evt_type = BLE_IAS_EVT_ALERT_LEVEL_UPDATED;
|
||||
evt.conn_handle = p_ble_evt->evt.gatts_evt.conn_handle;
|
||||
evt.p_link_ctx = p_client;
|
||||
|
||||
p_ias->evt_handler(p_ias, &evt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ble_ias_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
|
||||
{
|
||||
ble_ias_t * p_ias = (ble_ias_t *)p_context;
|
||||
|
||||
switch (p_ble_evt->header.evt_id)
|
||||
{
|
||||
case BLE_GAP_EVT_CONNECTED:
|
||||
on_connect(p_ias, p_ble_evt);
|
||||
break;
|
||||
|
||||
case BLE_GATTS_EVT_WRITE:
|
||||
on_write(p_ias, p_ble_evt);
|
||||
break;
|
||||
|
||||
default:
|
||||
// No implementation needed.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_ias_init(ble_ias_t * p_ias, const ble_ias_init_t * p_ias_init)
|
||||
{
|
||||
uint32_t err_code;
|
||||
uint8_t initial_alert_level;
|
||||
ble_uuid_t ble_uuid;
|
||||
ble_add_char_params_t add_char_params;
|
||||
|
||||
// Initialize service structure
|
||||
if (p_ias_init->evt_handler == NULL)
|
||||
{
|
||||
return NRF_ERROR_INVALID_PARAM;
|
||||
}
|
||||
p_ias->evt_handler = p_ias_init->evt_handler;
|
||||
|
||||
// Add service
|
||||
BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_IMMEDIATE_ALERT_SERVICE);
|
||||
|
||||
err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
|
||||
&ble_uuid,
|
||||
&p_ias->service_handle);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
// Add alert level characteristic
|
||||
initial_alert_level = INITIAL_ALERT_LEVEL;
|
||||
|
||||
memset(&add_char_params, 0, sizeof(add_char_params));
|
||||
add_char_params.uuid = BLE_UUID_ALERT_LEVEL_CHAR;
|
||||
add_char_params.max_len = sizeof (uint8_t);
|
||||
add_char_params.init_len = sizeof (uint8_t);
|
||||
add_char_params.p_init_value = &initial_alert_level;
|
||||
add_char_params.char_props.write_wo_resp = 1;
|
||||
add_char_params.write_access = p_ias_init->alert_wr_sec;
|
||||
|
||||
return characteristic_add(p_ias->service_handle,
|
||||
&add_char_params,
|
||||
&p_ias->alert_level_handles);
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_ias_alert_level_get(ble_ias_t * p_ias, uint16_t conn_handle, uint8_t * p_alert_level)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
ble_ias_client_context_t * p_client;
|
||||
|
||||
err_code = blcm_link_ctx_get(p_ias->p_link_ctx_storage, conn_handle, (void *) &p_client);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
*p_alert_level = p_client->alert_level;
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
#endif // NRF_MODULE_ENABLED(BLE_IAS)
|
||||
196
components/ble/ble_services/ble_ias/ble_ias.h
Normal file
196
components/ble/ble_services/ble_ias/ble_ias.h
Normal file
@@ -0,0 +1,196 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 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 ble_ias Immediate Alert Service
|
||||
* @{
|
||||
* @ingroup ble_sdk_srv
|
||||
* @brief Immediate Alert Service module.
|
||||
*
|
||||
* @details This module implements the Immediate Alert Service with the Alert Level characteristic.
|
||||
* During initialization it adds the Immediate Alert Service and Alert Level characteristic
|
||||
* to the BLE stack database.
|
||||
*
|
||||
* The application must supply an event handler for receiving Immediate Alert Service
|
||||
* events. Using this handler, the service will notify the application when the
|
||||
* Alert Level characteristic value changes.
|
||||
*
|
||||
* The service also provides a function for letting the application poll the current
|
||||
* value of the Alert Level characteristic.
|
||||
*
|
||||
* @note The application must register this module as BLE event observer using the
|
||||
* NRF_SDH_BLE_OBSERVER macro. Example:
|
||||
* @code
|
||||
* ble_ias_t instance;
|
||||
* NRF_SDH_BLE_OBSERVER(anything, BLE_IAS_BLE_OBSERVER_PRIO,
|
||||
* ble_ias_on_ble_evt, &instance);
|
||||
* @endcode
|
||||
*
|
||||
* @note Attention!
|
||||
* To maintain compliance with Nordic Semiconductor ASA Bluetooth profile
|
||||
* qualification listings, this section of source code must not be modified.
|
||||
*/
|
||||
|
||||
#ifndef BLE_IAS_H__
|
||||
#define BLE_IAS_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include "ble.h"
|
||||
#include "nrf_sdh_ble.h"
|
||||
#include "ble_link_ctx_manager.h"
|
||||
#include "ble_srv_common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/**@brief Macro for defining a ble_ias instance.
|
||||
*
|
||||
* @param _name Name of the instance.
|
||||
* @param[in] _ias_max_clients Maximum number of IAS clients connected at a time.
|
||||
* @hideinitializer
|
||||
*/
|
||||
#define BLE_IAS_DEF(_name, _ias_max_clients) \
|
||||
BLE_LINK_CTX_MANAGER_DEF(CONCAT_2(_name, _link_ctx_storage), \
|
||||
(_ias_max_clients), \
|
||||
sizeof(ble_ias_client_context_t)); \
|
||||
static ble_ias_t _name = \
|
||||
{ \
|
||||
.p_link_ctx_storage = &CONCAT_2(_name, _link_ctx_storage) \
|
||||
}; \
|
||||
NRF_SDH_BLE_OBSERVER(_name ## _obs, \
|
||||
BLE_IAS_BLE_OBSERVER_PRIO, \
|
||||
ble_ias_on_ble_evt, \
|
||||
&_name)
|
||||
|
||||
|
||||
/**@brief Immediate Alert Service event type. */
|
||||
typedef enum
|
||||
{
|
||||
BLE_IAS_EVT_ALERT_LEVEL_UPDATED /**< Alert Level Updated event. */
|
||||
} ble_ias_evt_type_t;
|
||||
|
||||
|
||||
/**@brief Immediate Alert Service client context structure.
|
||||
*
|
||||
* @details This structure contains state context related to hosts.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint8_t alert_level; /**< New Alert Level value. */
|
||||
} ble_ias_client_context_t;
|
||||
|
||||
|
||||
/**@brief Immediate Alert Service event. */
|
||||
typedef struct
|
||||
{
|
||||
ble_ias_evt_type_t evt_type; /**< Type of event. */
|
||||
uint16_t conn_handle; /**< Connection handle. */
|
||||
ble_ias_client_context_t * p_link_ctx; /**< A pointer to the link context. */
|
||||
} ble_ias_evt_t;
|
||||
|
||||
|
||||
// Forward declaration of the ble_ias_t type.
|
||||
typedef struct ble_ias_s ble_ias_t;
|
||||
|
||||
|
||||
/**@brief Immediate Alert Service event handler type. */
|
||||
typedef void (*ble_ias_evt_handler_t) (ble_ias_t * p_ias, ble_ias_evt_t * p_evt);
|
||||
|
||||
|
||||
/**@brief Immediate Alert Service init structure. This contains all options and data needed for
|
||||
* initialization of the service. */
|
||||
typedef struct
|
||||
{
|
||||
ble_ias_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Immediate Alert Service. */
|
||||
security_req_t alert_wr_sec; /**< Security requirement for writing Alert Level characteristic. */
|
||||
} ble_ias_init_t;
|
||||
|
||||
|
||||
/**@brief Immediate Alert Service structure. This contains various status information for the
|
||||
* service. */
|
||||
struct ble_ias_s
|
||||
{
|
||||
ble_ias_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Immediate Alert Service. */
|
||||
uint16_t service_handle; /**< Handle of Immediate Alert Service (as provided by the BLE stack). */
|
||||
ble_gatts_char_handles_t alert_level_handles; /**< Handles related to the Alert Level characteristic. */
|
||||
blcm_link_ctx_storage_t * const p_link_ctx_storage; /**< Pointer to link context storage with handles of all current connections and its context. */
|
||||
};
|
||||
|
||||
|
||||
/**@brief Function for initializing the Immediate Alert Service.
|
||||
*
|
||||
* @param[out] p_ias Immediate Alert Service structure. This structure will have to be
|
||||
* supplied by the application. It will be initialized by this function,
|
||||
* and will later be used to identify this particular service instance.
|
||||
* @param[in] p_ias_init Information needed to initialize the service.
|
||||
*
|
||||
* @return NRF_SUCCESS on successful initialization of service, otherwise an error code.
|
||||
*/
|
||||
uint32_t ble_ias_init(ble_ias_t * p_ias, const ble_ias_init_t * p_ias_init);
|
||||
|
||||
|
||||
/**@brief Function for handling the Application's BLE Stack events.
|
||||
*
|
||||
* @details Handles all events from the BLE stack of interest to the Immediate Alert Service.
|
||||
*
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
* @param[in] p_context Immediate Alert Service structure.
|
||||
*/
|
||||
void ble_ias_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
|
||||
|
||||
|
||||
/**@brief Function for getting value of the Alert Level characteristic.
|
||||
*
|
||||
* @param[in] p_ias Immediate Alert Service structure.
|
||||
* @param[in] conn_handle Connection handle of the destination client.
|
||||
* @param[out] p_alert_level Alert Level value which has been set by the specific client.
|
||||
*/
|
||||
uint32_t ble_ias_alert_level_get(ble_ias_t * p_ias, uint16_t conn_handle, uint8_t * p_alert_level);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // BLE_IAS_H__
|
||||
|
||||
/** @} */
|
||||
247
components/ble/ble_services/ble_ias_c/ble_ias_c.c
Normal file
247
components/ble/ble_services/ble_ias_c/ble_ias_c.c
Normal file
@@ -0,0 +1,247 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 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_IAS_C)
|
||||
#include "ble_ias_c.h"
|
||||
|
||||
#include <string.h>
|
||||
#include "ble.h"
|
||||
#include "ble_srv_common.h"
|
||||
#include "ble_gattc.h"
|
||||
#include "ble_db_discovery.h"
|
||||
|
||||
|
||||
/**@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)
|
||||
{
|
||||
UNUSED_PARAMETER(conn_handle);
|
||||
|
||||
ble_ias_c_t * p_ias_c = (ble_ias_c_t *)p_ctx;
|
||||
|
||||
if (p_ias_c->error_handler != NULL)
|
||||
{
|
||||
p_ias_c->error_handler(nrf_error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ble_ias_c_on_db_disc_evt(ble_ias_c_t * p_ias_c, ble_db_discovery_evt_t const * p_evt)
|
||||
{
|
||||
ble_ias_c_evt_t evt;
|
||||
|
||||
memset(&evt, 0, sizeof(ble_ias_c_evt_t));
|
||||
evt.conn_handle = p_evt->conn_handle;
|
||||
|
||||
ble_gatt_db_char_t const * p_chars = p_evt->params.discovered_db.charateristics;
|
||||
|
||||
// Check if the Immediate Alert Service was discovered.
|
||||
if ( (p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE)
|
||||
&& (p_evt->params.discovered_db.srv_uuid.uuid == BLE_UUID_IMMEDIATE_ALERT_SERVICE)
|
||||
&& (p_evt->params.discovered_db.srv_uuid.type == BLE_UUID_TYPE_BLE))
|
||||
{
|
||||
for (uint32_t i = 0; i < p_evt->params.discovered_db.char_count; i++)
|
||||
{
|
||||
// The Alert Level characteristic in the Immediate Alert Service instance is found
|
||||
// on peer. Check if it has the correct property 'Write without response'.
|
||||
switch (p_chars[i].characteristic.uuid.uuid)
|
||||
{
|
||||
case BLE_UUID_ALERT_LEVEL_CHAR:
|
||||
if (p_chars[i].characteristic.char_props.write_wo_resp)
|
||||
{
|
||||
// Found Alert Level characteristic inside the Immediate Alert Service.
|
||||
memcpy(&evt.alert_level,
|
||||
&p_chars[i].characteristic,
|
||||
sizeof(ble_gattc_char_t));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((p_evt->evt_type == BLE_DB_DISCOVERY_SRV_NOT_FOUND) ||
|
||||
(p_evt->evt_type == BLE_DB_DISCOVERY_ERROR))
|
||||
{
|
||||
evt.evt_type = BLE_IAS_C_EVT_DISCOVERY_FAILED;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (evt.alert_level.handle_value != BLE_GATT_HANDLE_INVALID)
|
||||
{
|
||||
evt.evt_type = BLE_IAS_C_EVT_DISCOVERY_COMPLETE;
|
||||
}
|
||||
|
||||
p_ias_c->evt_handler(p_ias_c, &evt);
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_ias_c_init(ble_ias_c_t * p_ias_c, ble_ias_c_init_t const * p_ias_c_init)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_ias_c);
|
||||
VERIFY_PARAM_NOT_NULL(p_ias_c_init);
|
||||
VERIFY_PARAM_NOT_NULL(p_ias_c_init->evt_handler);
|
||||
VERIFY_PARAM_NOT_NULL(p_ias_c_init->p_gatt_queue);
|
||||
|
||||
p_ias_c->evt_handler = p_ias_c_init->evt_handler;
|
||||
p_ias_c->error_handler = p_ias_c_init->error_handler;
|
||||
p_ias_c->p_gatt_queue = p_ias_c_init->p_gatt_queue;
|
||||
p_ias_c->conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
p_ias_c->alert_level_char.handle_value = BLE_GATT_HANDLE_INVALID;
|
||||
|
||||
BLE_UUID_BLE_ASSIGN(p_ias_c->alert_level_char.uuid, BLE_UUID_ALERT_LEVEL_CHAR);
|
||||
BLE_UUID_BLE_ASSIGN(p_ias_c->service_uuid, BLE_UUID_IMMEDIATE_ALERT_SERVICE);
|
||||
|
||||
return ble_db_discovery_evt_register(&p_ias_c->service_uuid);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**@brief Function for handling the Disconnect event.
|
||||
*
|
||||
* @param[in] p_ias_c Immediate Alert Service client structure.
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
*/
|
||||
static void on_disconnect(ble_ias_c_t * p_ias_c, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
// The following values will be re-initialized when a new connection is made.
|
||||
p_ias_c->conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
|
||||
if (ble_ias_c_is_discovered(p_ias_c))
|
||||
{
|
||||
// There was a valid instance of IAS on the peer. Send an event to the
|
||||
// application, so that it can do a cleanup related to this module.
|
||||
ble_ias_c_evt_t evt;
|
||||
|
||||
evt.evt_type = BLE_IAS_C_EVT_DISCONN_COMPLETE;
|
||||
|
||||
p_ias_c->evt_handler(p_ias_c, &evt);
|
||||
p_ias_c->alert_level_char.handle_value = BLE_GATT_HANDLE_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ble_ias_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
|
||||
{
|
||||
uint32_t err_code = NRF_SUCCESS;
|
||||
ble_ias_c_t * p_ias_c = (ble_ias_c_t *)p_context;
|
||||
|
||||
switch (p_ble_evt->header.evt_id)
|
||||
{
|
||||
case BLE_GAP_EVT_DISCONNECTED:
|
||||
on_disconnect(p_ias_c, p_ble_evt);
|
||||
break;
|
||||
|
||||
default:
|
||||
// No implementation needed.
|
||||
break;
|
||||
}
|
||||
|
||||
if ((err_code != NRF_SUCCESS) && (p_ias_c->error_handler != NULL))
|
||||
{
|
||||
p_ias_c->error_handler(err_code);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for performing a Write procedure.
|
||||
*
|
||||
* @param[in] p_ias_c Pointer to Immediate Alert Service client structure.
|
||||
* @param[in] length Length of data to be written.
|
||||
* @param[in] p_value Data to be written.
|
||||
*
|
||||
* @return NRF_SUCCESS on success, otherwise an error code.
|
||||
*/
|
||||
static uint32_t write_characteristic_value(ble_ias_c_t const * const p_ias_c,
|
||||
uint16_t length,
|
||||
uint8_t * p_value)
|
||||
{
|
||||
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 = gatt_error_handler;
|
||||
write_req.error_handler.p_ctx = (ble_ias_c_t *)p_ias_c;
|
||||
write_req.params.gattc_write.handle = p_ias_c->alert_level_char.handle_value;
|
||||
write_req.params.gattc_write.write_op = BLE_GATT_OP_WRITE_CMD;
|
||||
write_req.params.gattc_write.offset = 0;
|
||||
write_req.params.gattc_write.len = length;
|
||||
write_req.params.gattc_write.p_value = p_value;
|
||||
|
||||
return nrf_ble_gq_item_add(p_ias_c->p_gatt_queue, &write_req, p_ias_c->conn_handle);
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_ias_c_send_alert_level(ble_ias_c_t const * p_ias_c, uint8_t alert_level)
|
||||
{
|
||||
if (!ble_ias_c_is_discovered(p_ias_c))
|
||||
{
|
||||
return NRF_ERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
return write_characteristic_value(p_ias_c,
|
||||
sizeof(uint8_t),
|
||||
&alert_level);
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_ias_c_handles_assign(ble_ias_c_t * p_ias_c,
|
||||
const uint16_t conn_handle,
|
||||
const uint16_t alert_level_handle)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_ias_c);
|
||||
|
||||
p_ias_c->conn_handle = conn_handle;
|
||||
p_ias_c->alert_level_char.handle_value = alert_level_handle;
|
||||
|
||||
return nrf_ble_gq_conn_handle_register(p_ias_c->p_gatt_queue, conn_handle);
|
||||
}
|
||||
#endif //NRF_MODULE_ENABLED(BLE_IAS_C)
|
||||
244
components/ble/ble_services/ble_ias_c/ble_ias_c.h
Normal file
244
components/ble/ble_services/ble_ias_c/ble_ias_c.h
Normal file
@@ -0,0 +1,244 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 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 ble_ias_c Immediate Alert Service Client
|
||||
* @{
|
||||
* @ingroup ble_sdk_srv
|
||||
* @brief Immediate Alert Service Client module
|
||||
*
|
||||
* @details This module implements the Immediate Alert Service client - the locator role of the Find Me
|
||||
* profile. On @ref BLE_GAP_EVT_CONNECTED event, this module starts discovery of the
|
||||
* Immediate Alert Service with Alert Level characteristic at the peer. This module will
|
||||
* inform the application about the successful service and characteristic discovery with
|
||||
* the @ref BLE_IAS_C_EVT_DISCOVERY_COMPLETE event. The application can use @ref
|
||||
* ble_ias_c_send_alert_level function to signal alerts to the peer.
|
||||
*
|
||||
* @note The application must register this module as the BLE event observer by using the
|
||||
* NRF_SDH_BLE_OBSERVER macro. Example:
|
||||
* @code
|
||||
* ble_ias_c_t instance;
|
||||
* NRF_SDH_BLE_OBSERVER(anything, BLE_IAS_C_BLE_OBSERVER_PRIO,
|
||||
* ble_ias_c_on_ble_evt, &instance);
|
||||
* @endcode
|
||||
*/
|
||||
|
||||
#ifndef BLE_IAS_C_H__
|
||||
#define BLE_IAS_C_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include "ble_srv_common.h"
|
||||
#include "ble_gattc.h"
|
||||
#include "ble.h"
|
||||
#include "ble_db_discovery.h"
|
||||
#include "nrf_ble_gq.h"
|
||||
#include "nrf_sdh_ble.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**@brief Macro for defining a ble_ias_c instance.
|
||||
*
|
||||
* @param _name Name of the instance.
|
||||
* @hideinitializer
|
||||
*/
|
||||
#define BLE_IAS_C_DEF(_name) \
|
||||
static ble_ias_c_t _name; \
|
||||
NRF_SDH_BLE_OBSERVER(_name ## _obs, \
|
||||
BLE_IAS_C_BLE_OBSERVER_PRIO, \
|
||||
ble_ias_c_on_ble_evt, &_name)
|
||||
|
||||
/** @brief Macro for defining multiple ble_ias_c instances.
|
||||
*
|
||||
* @param _name Name of the array of instances.
|
||||
* @param _cnt Number of instances to define.
|
||||
* @hideinitializer
|
||||
*/
|
||||
#define BLE_IAS_C_ARRAY_DEF(_name, _cnt) \
|
||||
static ble_ias_c_t _name[_cnt]; \
|
||||
NRF_SDH_BLE_OBSERVERS(_name ## _obs, \
|
||||
BLE_IAS_C_BLE_OBSERVER_PRIO, \
|
||||
ble_ias_c_on_ble_evt, &_name, _cnt)
|
||||
|
||||
|
||||
// Forward declaration of the ble_ias_c_t type.
|
||||
typedef struct ble_ias_c_s ble_ias_c_t;
|
||||
|
||||
/**@brief Immediate Alert Service client event type. */
|
||||
typedef enum
|
||||
{
|
||||
BLE_IAS_C_EVT_DISCOVERY_COMPLETE, /**< Event indicating that the Immediate Alert Service is found at the peer. */
|
||||
BLE_IAS_C_EVT_DISCOVERY_FAILED, /**< Event indicating that the Immediate Alert Service is not found at the peer. */
|
||||
BLE_IAS_C_EVT_DISCONN_COMPLETE /**< Event indicating that the Immediate Alert Service Client module completed the processing of BLE_GAP_EVT_DISCONNECTED event. This event is triggered only if a valid instance of IAS was found at the peer during the discovery phase. The application can use this event to do a cleanup related to the IAS Client.*/
|
||||
} ble_ias_c_evt_type_t;
|
||||
|
||||
/**@brief Immediate Alert Service client event. */
|
||||
typedef struct
|
||||
{
|
||||
ble_ias_c_evt_type_t evt_type; /**< Type of event. */
|
||||
uint16_t conn_handle; /**< Connection handle on which the IAS service was discovered on the peer device. This is filled if the evt_type is @ref BLE_IAS_C_EVT_DISCOVERY_COMPLETE.*/
|
||||
ble_gattc_char_t alert_level; /**< Information on the discovered Alert Level characteristic discovered. This is filled if the evt_type is @ref BLE_IAS_C_EVT_DISCOVERY_COMPLETE.*/
|
||||
} ble_ias_c_evt_t;
|
||||
|
||||
/**@brief Immediate Alert Service client event handler type. */
|
||||
typedef void (*ble_ias_c_evt_handler_t) (ble_ias_c_t * p_ias_c, ble_ias_c_evt_t * p_evt);
|
||||
|
||||
/**@brief IAS Client structure. Contains various status information for the client. */
|
||||
struct ble_ias_c_s
|
||||
{
|
||||
ble_ias_c_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Immediate Alert Service client. */
|
||||
ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
|
||||
uint16_t conn_handle; /**< Handle of the current connection. Set with @ref ble_ias_c_handles_assign when connected. */
|
||||
ble_uuid_t service_uuid; /**< The GATT Service holding the discovered Immediate Service. */
|
||||
ble_gattc_char_t alert_level_char; /**< IAS Alert Level Characteristic. Stores data about the alert characteristic found on the peer. */
|
||||
nrf_ble_gq_t * p_gatt_queue; /**< Pointer to the BLE GATT Queue instance. */
|
||||
};
|
||||
|
||||
/**@brief IAS Client init structure. Contains all options and data needed for the initialization of
|
||||
* the client.*/
|
||||
typedef struct
|
||||
{
|
||||
ble_ias_c_evt_handler_t evt_handler; /**< Event handler to be called for handling events from the Immediate Alert Service client. */
|
||||
ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
|
||||
nrf_ble_gq_t * p_gatt_queue; /**< Pointer to the BLE GATT Queue instance. */
|
||||
} ble_ias_c_init_t;
|
||||
|
||||
|
||||
/**@brief Function for initializing the Immediate Alert Service client.
|
||||
*
|
||||
* @details This call allows the application to initialize the Immediate Alert Service client.
|
||||
*
|
||||
* @param[out] p_ias_c Immediate Alert Service client structure. This structure must
|
||||
* be supplied by the application. It is initialized by this
|
||||
* function, and is later used to identify this particular client
|
||||
* instance.
|
||||
* @param[in] p_ias_c_init Information needed to initialize the Immediate Alert Service client.
|
||||
*
|
||||
* @return NRF_SUCCESS on successful initialization of service.
|
||||
*/
|
||||
uint32_t ble_ias_c_init(ble_ias_c_t * p_ias_c, ble_ias_c_init_t const * p_ias_c_init);
|
||||
|
||||
|
||||
/**@brief Function for sending alert level to the peer.
|
||||
*
|
||||
* @details This function allows the application to send an alert to the peer.
|
||||
*
|
||||
* @param[in] p_ias_c Immediate Alert Service client structure.
|
||||
* @param[in] alert_level Required alert level to be sent to the peer.
|
||||
*
|
||||
* @retval NRF_SUCCESS On success.
|
||||
* @retval err_code Otherwise, this API propagates the error code returned by function
|
||||
* @ref nrf_ble_gq_item_add.
|
||||
*/
|
||||
uint32_t ble_ias_c_send_alert_level(ble_ias_c_t const * p_ias_c, uint8_t alert_level);
|
||||
|
||||
|
||||
/**@brief Function for handling the Application's BLE Stack events for Immediate Alert Service client.
|
||||
*
|
||||
* @details Handles all events from the BLE stack of interest to the Immediate Alert Service client.
|
||||
*
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
* @param[in] p_context Immediate Alert Service client structure.
|
||||
*/
|
||||
void ble_ias_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
|
||||
|
||||
|
||||
/**@brief Function for checking whether the peer's Immediate Alert Service instance and the Alert Level
|
||||
* characteristic have been discovered.
|
||||
*
|
||||
* @param[in] p_ias_c Immediate Alert Service client structure.
|
||||
*
|
||||
* @return True, if a handle is assigned to alert_level_handle, meaning it must have been discovered.
|
||||
* @return False, if the handle is invalid.
|
||||
*/
|
||||
static __INLINE bool ble_ias_c_is_discovered(ble_ias_c_t const * p_ias_c)
|
||||
{
|
||||
return (p_ias_c->alert_level_char.handle_value != BLE_GATT_HANDLE_INVALID);
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling events from the Database Discovery module.
|
||||
*
|
||||
* @details Call this function when you get a callback event from the Database Discovery module.
|
||||
* This function handles an event from the Database Discovery module, and determines
|
||||
* whether it relates to the discovery of Immediate Alert Service at the peer. If it does, the function
|
||||
* calls the application's event handler to indicate that the Immediate Alert Service was
|
||||
* discovered at the peer. The function also populates the event with service-related
|
||||
* information before providing it to the application.
|
||||
*
|
||||
* @param[in] p_ias_c Pointer to the Immediate Alert client structure instance that will handle
|
||||
* the discovery.
|
||||
* @param[in] p_evt Pointer to the event received from the Database Discovery module.
|
||||
*
|
||||
*/
|
||||
void ble_ias_c_on_db_disc_evt(ble_ias_c_t * p_ias_c, ble_db_discovery_evt_t const * p_evt);
|
||||
|
||||
|
||||
/**@brief Function for assigning handles to an instance of ias_c.
|
||||
*
|
||||
* @details Call this function when a link has been established with a peer to
|
||||
* associate the link to this instance of the module. This makes it
|
||||
* possible to handle several links and associate each link to a particular
|
||||
* instance of this module. The connection handle and attribute handles are
|
||||
* provided from the discovery event @ref BLE_IAS_C_EVT_DISCOVERY_COMPLETE.
|
||||
*
|
||||
* @param[in] p_ias_c Pointer to the IAS client structure instance for associating the link.
|
||||
* @param[in] conn_handle Connection handle to associated with the given IAS instance.
|
||||
* @param[in] alert_level_handle Attribute handle on the IAS server that you want this IAS_C client to
|
||||
* interact with.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the operation was successful.
|
||||
* @retval NRF_ERROR_NULL If a p_ias_c was a NULL pointer.
|
||||
* @retval err_code Otherwise, this API propagates the error code returned by function
|
||||
* @ref nrf_ble_gq_conn_handle_register.
|
||||
*/
|
||||
uint32_t ble_ias_c_handles_assign(ble_ias_c_t * p_ias_c,
|
||||
uint16_t conn_handle,
|
||||
uint16_t alert_level_handle);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // BLE_IAS_C_H__
|
||||
|
||||
/** @} */
|
||||
981
components/ble/ble_services/ble_ipsp/ble_ipsp.c
Normal file
981
components/ble/ble_services/ble_ipsp/ble_ipsp.c
Normal file
@@ -0,0 +1,981 @@
|
||||
/**
|
||||
* Copyright (c) 2014 - 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.
|
||||
*
|
||||
*/
|
||||
/* Attention!
|
||||
* To maintain compliance with Nordic Semiconductor ASA's Bluetooth profile
|
||||
* qualification listings, this section of source code must not be modified.
|
||||
*/
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include "nordic_common.h"
|
||||
#include "sdk_errors.h"
|
||||
#include "nrf.h"
|
||||
#include "sdk_config.h"
|
||||
#include "ble_ipsp.h"
|
||||
#include "ble_srv_common.h"
|
||||
#include "sdk_os.h"
|
||||
|
||||
|
||||
/**
|
||||
* @defgroup ble_ipsp_log Module's Log Macros
|
||||
* @details Macros used for creating module logs which can be useful in understanding handling
|
||||
* of events or actions on API requests. These are intended for debugging purposes and
|
||||
* can be enabled by defining the IOT_BLE_IPSP_CONFIG_LOG_ENABLED to 1.
|
||||
* @note If NRF_LOG_ENABLED is disabled, having IOT_BLE_IPSP_CONFIG_LOG_ENABLED
|
||||
* has no effect.
|
||||
* @{
|
||||
*/
|
||||
|
||||
#if IOT_BLE_IPSP_CONFIG_LOG_ENABLED
|
||||
|
||||
#define NRF_LOG_MODULE_NAME ipsp
|
||||
|
||||
#define NRF_LOG_LEVEL IOT_BLE_IPSP_CONFIG_LOG_LEVEL
|
||||
#define NRF_LOG_INFO_COLOR IOT_BLE_IPSP_CONFIG_INFO_COLOR
|
||||
#define NRF_LOG_DEBUG_COLOR IOT_BLE_IPSP_CONFIG_DEBUG_COLOR
|
||||
|
||||
#include "nrf_log.h"
|
||||
NRF_LOG_MODULE_REGISTER();
|
||||
|
||||
#define BLE_IPSP_TRC NRF_LOG_DEBUG /**< Used for getting trace of execution in the module. */
|
||||
#define BLE_IPSP_ERR NRF_LOG_ERROR /**< Used for logging errors in the module. */
|
||||
#define BLE_IPSP_DUMP NRF_LOG_HEXDUMP_DEBUG /**< Used for dumping octet information to get details of bond information etc. */
|
||||
|
||||
#define BLE_IPSP_ENTRY() BLE_IPSP_TRC(">> %s", __func__)
|
||||
#define BLE_IPSP_EXIT() BLE_IPSP_TRC("<< %s", __func__)
|
||||
#define BLE_IPSP_EXIT_WITH_RESULT(result) BLE_IPSP_TRC("<< %s, result 0x%08lX", __func__, result)
|
||||
|
||||
#else // IOT_BLE_IPSP_CONFIG_LOG_ENABLED
|
||||
|
||||
#define BLE_IPSP_TRC(...) /**< Disables traces. */
|
||||
#define BLE_IPSP_DUMP(...) /**< Disables dumping of octet streams. */
|
||||
#define BLE_IPSP_ERR(...) /**< Disables error logs. */
|
||||
|
||||
#define BLE_IPSP_ENTRY(...)
|
||||
#define BLE_IPSP_EXIT(...)
|
||||
#define BLE_IPSP_EXIT_WITH_RESULT(...)
|
||||
|
||||
#endif // IOT_BLE_IPSP_CONFIG_LOG_ENABLED
|
||||
|
||||
#define IPSP_ANY_CID 0xFFFE /**< Identifier for any channel. Usage: Search for existing channel on a connection handle. */
|
||||
|
||||
/**
|
||||
* @defgroup api_param_check API Parameters check macros.
|
||||
*
|
||||
* @details Macros that verify parameters passed to the module in the APIs. These macros
|
||||
* could be mapped to nothing in final versions of code to save execution and size.
|
||||
* BLE_HPS_DISABLE_API_PARAM_CHECK should be defined to disable these checks.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
#if (BLE_IPSP_DISABLE_API_PARAM_CHECK == 0)
|
||||
|
||||
/**@brief Macro to check is module is initialized before requesting one of the module procedures. */
|
||||
#define VERIFY_MODULE_IS_INITIALIZED() \
|
||||
if (m_evt_handler == NULL) \
|
||||
{ \
|
||||
return (NRF_ERROR_MODULE_NOT_INITIALIZED + NRF_ERROR_BLE_IPSP_ERR_BASE); \
|
||||
}
|
||||
|
||||
/**@brief Macro to check is module is initialized before requesting one of the module
|
||||
procedures but does not use any return code. */
|
||||
#define VERIFY_MODULE_IS_INITIALIZED_VOID() \
|
||||
if (m_evt_handler == NULL) \
|
||||
{ \
|
||||
return; \
|
||||
}
|
||||
|
||||
/**@brief Verify NULL parameters are not passed to API by application. */
|
||||
#define NULL_PARAM_CHECK(PARAM) \
|
||||
if ((PARAM) == NULL) \
|
||||
{ \
|
||||
return (NRF_ERROR_NULL + NRF_ERROR_BLE_IPSP_ERR_BASE); \
|
||||
}
|
||||
|
||||
/**@brief Verify the connection handle passed to the API. */
|
||||
#define VERIFY_CON_HANDLE(CON_HANDLE) \
|
||||
if ((CON_HANDLE) == BLE_CONN_HANDLE_INVALID) \
|
||||
{ \
|
||||
return (NRF_ERROR_INVALID_PARAM + NRF_ERROR_BLE_IPSP_ERR_BASE); \
|
||||
}
|
||||
|
||||
#else // BLE_IPSP_DISABLE_API_PARAM_CHECK
|
||||
|
||||
#define VERIFY_MODULE_IS_INITIALIZED()
|
||||
#define VERIFY_MODULE_IS_INITIALIZED_VOID()
|
||||
#define NULL_PARAM_CHECK(PARAM)
|
||||
#define VERIFY_CON_HANDLE(CON_HANDLE)
|
||||
|
||||
#endif //BLE_IPSP_DISABLE_API_PARAM_CHECK
|
||||
|
||||
/**
|
||||
* @defgroup ble_ipsp_mutex_lock_unlock Module's Mutex Lock/Unlock Macros.
|
||||
*
|
||||
* @details Macros used to lock and unlock modules. Currently, SDK does not use mutexes but
|
||||
* framework is provided in case the need to use an alternative architecture arises.
|
||||
* @{
|
||||
*/
|
||||
#define BLE_IPSP_MUTEX_LOCK() SDK_MUTEX_LOCK(m_ipsp_mutex) /**< Lock module using mutex */
|
||||
#define BLE_IPSP_MUTEX_UNLOCK() SDK_MUTEX_UNLOCK(m_ipsp_mutex) /**< Unlock module using mutex */
|
||||
/** @} */
|
||||
|
||||
#define IPSP_MAX_CONNECTED_DEVICES BLE_IPSP_MAX_CHANNELS /**< Table for maximum number of connected devices the module will keep track of. */
|
||||
#define RX_BUFFER_TOTAL_SIZE (BLE_IPSP_RX_BUFFER_SIZE * BLE_IPSP_RX_BUFFER_COUNT) /**< Total receive buffer size reserved for each IPSP channel. */
|
||||
#define MAX_L2CAP_RX_BUFFER (RX_BUFFER_TOTAL_SIZE * BLE_IPSP_MAX_CHANNELS) /**< Total receive buffer received for all channels. */
|
||||
#define INVALID_CHANNEL_INSTANCE 0xFF /**< Indicates channel instance is invalid. */
|
||||
|
||||
|
||||
/**@brief IPSP Channel States. */
|
||||
typedef enum
|
||||
{
|
||||
CHANNEL_IDLE, /**< Indicates the channel is free and not in use. */
|
||||
CHANNEL_CONNECTING, /**< Indicates the channel creation is requested and is awaiting a response. */
|
||||
CHANNEL_CONNECTED, /**< Indicates the channel is connected and ready for data exchange. */
|
||||
CHANNEL_DISCONNECTING /**< Indicates the channel is in the process of being disconnected. */
|
||||
} channel_state_t;
|
||||
|
||||
|
||||
/**@brief Possible response actions for an incoming channel. Default is to accept. */
|
||||
typedef enum
|
||||
{
|
||||
INCOMING_CHANNEL_ACCEPT, /**< Indicates that the incoming channel should be accepted if all other criteria are met. */
|
||||
INCOMING_CHANNEL_REJECT /**< Indicates that the incoming channel for IPSP PSM should be rejected regardless of the other criteria. */
|
||||
} incoming_channel_action_t;
|
||||
|
||||
/**@brief Data type for book keeping connected devices.
|
||||
*
|
||||
* @note Not all connected devices establish an L2CAP connection.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
volatile incoming_channel_action_t response; /**< Indicator if the incoming channel should be accepted or rejected. */
|
||||
ble_gap_addr_t ble_addr; /**< Bluetooth device address of the peer. */
|
||||
uint16_t conn_handle; /**< Connection handle identifying the link with the peer. */
|
||||
} peer_connection_t;
|
||||
|
||||
|
||||
/**@brief IPSP Channel Information. */
|
||||
typedef struct
|
||||
{
|
||||
uint16_t conn_handle; /**< Identifies the BLE link on which channel is established. BLE_CONN_HANDLE_INVALID if channel is unassigned. */
|
||||
uint16_t cid; /**< L2CAP channel identifier needed to manage the channel once established. BLE_L2CAP_CID_INVALID if channel is unassigned. */
|
||||
uint16_t rx_buffer_status; /**< Usage status of RX buffers. */
|
||||
uint8_t state; /**< State information for the channel. See @ref channel_state_t for details. */
|
||||
uint8_t * p_rx_buffer; /**< Receive buffer for the channel. */
|
||||
} channel_t;
|
||||
|
||||
|
||||
static ble_ipsp_evt_handler_t m_evt_handler = NULL; /**< Asynchronous event notification callback registered with the module. */
|
||||
static channel_t m_channel[BLE_IPSP_MAX_CHANNELS]; /**< Table of channels managed by the module. */
|
||||
static uint8_t m_rx_buffer[MAX_L2CAP_RX_BUFFER]; /**< Receive buffer reserved for all channels to receive data on the L2CAP IPSP channel. */
|
||||
static peer_connection_t m_connected_device[IPSP_MAX_CONNECTED_DEVICES]; /**< Table maintaining list of peer devices and the connection handle.
|
||||
\n This information is needed for the 6lowpan compression and decompression.
|
||||
\n And no interface exists to query the softdevice. */
|
||||
SDK_MUTEX_DEFINE(m_ipsp_mutex) /**< Mutex variable. Currently unused, this declaration does not occupy any space in RAM. */
|
||||
|
||||
|
||||
/**@brief Initialize the peer connected device in the list.
|
||||
*
|
||||
* @param[in] index Identifies the list element to be initialized.
|
||||
*/
|
||||
static __INLINE void connected_device_init(uint32_t index)
|
||||
{
|
||||
memset (&m_connected_device[index].ble_addr, 0, sizeof(ble_gap_addr_t));
|
||||
m_connected_device[index].conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
m_connected_device[index].response = INCOMING_CHANNEL_ACCEPT;
|
||||
}
|
||||
|
||||
|
||||
/**@brief Allocate an entry for the peer connected device in the list.
|
||||
*
|
||||
* @param[in] p_peer_addr Pointer to peer's device address.
|
||||
* @param[in] conn_handle Connection handle identifying the link with the peer.
|
||||
*/
|
||||
static __INLINE void connected_device_allocate(ble_gap_addr_t const * p_peer_addr,
|
||||
uint16_t conn_handle)
|
||||
{
|
||||
for (uint32_t index = 0; index < IPSP_MAX_CONNECTED_DEVICES; index++)
|
||||
{
|
||||
if (m_connected_device[index].conn_handle == BLE_CONN_HANDLE_INVALID)
|
||||
{
|
||||
m_connected_device[index].conn_handle = conn_handle;
|
||||
memcpy(m_connected_device[index].ble_addr.addr, p_peer_addr->addr, BLE_GAP_ADDR_LEN);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Search for an entry for the peer connected device in the list.
|
||||
*
|
||||
* @param[in] conn_handle Connection handle identifying the link with the peer.
|
||||
*
|
||||
* @retval A valid device index in the list if found, else,
|
||||
* IPSP_MAX_CONNECTED_DEVICES indicating the search failed.
|
||||
*/
|
||||
static __INLINE uint32_t connected_device_search(uint16_t conn_handle)
|
||||
{
|
||||
for (uint32_t index = 0; index < IPSP_MAX_CONNECTED_DEVICES; index++)
|
||||
{
|
||||
if (m_connected_device[index].conn_handle == conn_handle)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
}
|
||||
return IPSP_MAX_CONNECTED_DEVICES;
|
||||
}
|
||||
|
||||
|
||||
/**@brief Initialize channel.
|
||||
*
|
||||
* @param[in] ch_id Identifies the IPSP channel on which the procedure is requested.
|
||||
*/
|
||||
static __INLINE void channel_init(uint8_t ch_id)
|
||||
{
|
||||
m_channel[ch_id].conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
m_channel[ch_id].cid = BLE_L2CAP_CID_INVALID;
|
||||
m_channel[ch_id].rx_buffer_status = 0;
|
||||
m_channel[ch_id].state = CHANNEL_IDLE;
|
||||
m_channel[ch_id].p_rx_buffer = &m_rx_buffer[ch_id*RX_BUFFER_TOTAL_SIZE];
|
||||
}
|
||||
|
||||
|
||||
/**@brief Free channel.
|
||||
*
|
||||
* @param[in] ch_id Identifies the IPSP channel on which the procedure is requested.
|
||||
*/
|
||||
static __INLINE void channel_free(uint8_t ch_id)
|
||||
{
|
||||
BLE_IPSP_TRC("[Index 0x%02X]:[Conn Handle 0x%04X]:[CID 0x%04X]: Freeing channel",
|
||||
ch_id, m_channel[ch_id].conn_handle, m_channel[ch_id].cid);
|
||||
|
||||
channel_init(ch_id);
|
||||
}
|
||||
|
||||
|
||||
/**@brief Searches the IPSP channel based on connection handle and local L2CAP channel identifier.
|
||||
*
|
||||
* @param[in] conn_handle The connection handle, identifying the peer device.
|
||||
* @param[in] l2cap_cid The local L2CAP channel identifier, identifying the L2CAP channel.
|
||||
* @param[out] p_ch_id The IPSP channel identifier, if the search succeeded, else,
|
||||
* BLE_IPSP_MAX_CHANNELS indicating no IPSP channel was found.
|
||||
*/
|
||||
static __INLINE uint32_t channel_search(uint16_t conn_handle, uint16_t l2cap_cid, uint8_t * p_ch_id)
|
||||
{
|
||||
BLE_IPSP_TRC("[Conn Handle 0x%04X]:[CID 0x%04X]: channel_search",
|
||||
conn_handle, l2cap_cid);
|
||||
|
||||
for (int i = 0; i < BLE_IPSP_MAX_CHANNELS; i++)
|
||||
{
|
||||
BLE_IPSP_TRC("[@ Index 0x%02X] ==> Conn Handle: 0x%04X"
|
||||
" CID : 0x%04X",
|
||||
i, m_channel[i].conn_handle, m_channel[i].cid);
|
||||
|
||||
if (m_channel[i].conn_handle == conn_handle)
|
||||
{
|
||||
if ((l2cap_cid == IPSP_ANY_CID) || (m_channel[i].cid == l2cap_cid))
|
||||
{
|
||||
BLE_IPSP_TRC("channel_search succeeded, index 0x%04X", i);
|
||||
|
||||
*p_ch_id = (uint8_t)i;
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BLE_IPSP_TRC("No matching channel found!");
|
||||
return (NRF_ERROR_BLE_IPSP_ERR_BASE + NRF_ERROR_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
||||
/**@brief Notify application of an event.
|
||||
*
|
||||
* @param[in] Identifies the IPSP instance for which the event is notified.
|
||||
* @param[in] Describes the notified event and its parameters, if any.
|
||||
*/
|
||||
static __INLINE void app_notify(ble_ipsp_handle_t * p_handle, ble_ipsp_evt_t * p_event)
|
||||
{
|
||||
BLE_IPSP_MUTEX_UNLOCK();
|
||||
|
||||
BLE_IPSP_TRC("[Conn Handle 0x%04X]:[CID 0x%04X]: Notifying application of event 0x%04X",
|
||||
p_handle->conn_handle, p_handle->cid, p_event->evt_id);
|
||||
|
||||
UNUSED_VARIABLE(m_evt_handler(p_handle, p_event));
|
||||
|
||||
BLE_IPSP_MUTEX_LOCK();
|
||||
}
|
||||
|
||||
|
||||
/**@brief Verifies if the buffer is TX buffer on the channel or not.
|
||||
*
|
||||
* @param[in] ch_id Identifies the IPSP channel for which the procedure is requested.
|
||||
* @param[in] p_buffer Address of the buffer being verified to be TX or not.
|
||||
*/
|
||||
static __INLINE bool is_tx_buffer(uint32_t ch_id, const uint8_t * p_buffer)
|
||||
{
|
||||
// If the buffer is in the RX buffer list, then it is not TX!
|
||||
if ((p_buffer >= (uint8_t *)&m_channel[ch_id].p_rx_buffer) &&
|
||||
(p_buffer < (uint8_t *)&m_channel[ch_id].p_rx_buffer[RX_BUFFER_TOTAL_SIZE]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**@brief Submit receive buffers to the softdevice for a channel.
|
||||
*
|
||||
* @param[in] ch_id Identifies the IPSP channel for which the procedure is requested.
|
||||
*/
|
||||
static __INLINE void rx_buffers_submit(uint32_t ch_id)
|
||||
{
|
||||
uint32_t retval;
|
||||
|
||||
for (uint32_t buffer_index = 0; buffer_index < BLE_IPSP_RX_BUFFER_COUNT; buffer_index++)
|
||||
{
|
||||
const ble_data_t sdu_buf =
|
||||
{
|
||||
.p_data = (uint8_t *)&m_channel[ch_id].p_rx_buffer[buffer_index * BLE_IPSP_MTU],
|
||||
.len = BLE_IPSP_MTU
|
||||
};
|
||||
|
||||
if (IS_SET(m_channel[ch_id].rx_buffer_status, buffer_index) == 0)
|
||||
{
|
||||
retval = sd_ble_l2cap_ch_rx(m_channel[ch_id].conn_handle,
|
||||
m_channel[ch_id].cid,
|
||||
&sdu_buf);
|
||||
if (retval == NRF_SUCCESS)
|
||||
{
|
||||
SET_BIT(m_channel[ch_id].rx_buffer_status, buffer_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Mark a receive buffer as not in use for a particular channel.
|
||||
*
|
||||
* @param[in] ch_id Identifies the IPSP channel for which the procedure is requested.
|
||||
* @param[in] p_buffer The buffer to be marked as unused.
|
||||
*
|
||||
* @note This is a temporary state for the receive buffer before it is resubmitted to the SoftDevice.
|
||||
*/
|
||||
static __INLINE void rx_buffer_mark_unused(uint32_t ch_id, uint8_t * p_buffer)
|
||||
{
|
||||
for (uint32_t buffer_index = 0; buffer_index < BLE_IPSP_RX_BUFFER_COUNT; buffer_index++)
|
||||
{
|
||||
if (&m_channel[ch_id].p_rx_buffer[buffer_index * BLE_IPSP_MTU] == p_buffer)
|
||||
{
|
||||
CLR_BIT(m_channel[ch_id].rx_buffer_status, buffer_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ble_ipsp_evt_handler(ble_evt_t const * p_evt)
|
||||
{
|
||||
VERIFY_MODULE_IS_INITIALIZED_VOID();
|
||||
|
||||
ble_ipsp_handle_t handle;
|
||||
ble_ipsp_evt_t ipsp_event;
|
||||
uint32_t retval;
|
||||
uint8_t ch_id;
|
||||
bool notify_event;
|
||||
bool submit_rx_buffer;
|
||||
|
||||
ch_id = INVALID_CHANNEL_INSTANCE;
|
||||
notify_event = false;
|
||||
submit_rx_buffer = false;
|
||||
retval = NRF_SUCCESS;
|
||||
ipsp_event.evt_result = NRF_SUCCESS;
|
||||
handle.conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
handle.cid = BLE_L2CAP_CID_INVALID;
|
||||
|
||||
BLE_IPSP_TRC("Received BLE Event 0x%04X",p_evt->header.evt_id);
|
||||
|
||||
BLE_IPSP_MUTEX_LOCK();
|
||||
|
||||
switch (p_evt->header.evt_id)
|
||||
{
|
||||
case BLE_GAP_EVT_CONNECTED:
|
||||
{
|
||||
// Create an entry in the connected devices table.
|
||||
// This is needed to be able to fetch the peer address on IPSP channel establishment.
|
||||
connected_device_allocate(&p_evt->evt.gap_evt.params.connected.peer_addr,
|
||||
p_evt->evt.gap_evt.conn_handle);
|
||||
break;
|
||||
}
|
||||
case BLE_L2CAP_EVT_CH_SETUP_REQUEST:
|
||||
{
|
||||
// This event is generated for the acceptor role and indicates an channel establishment
|
||||
// request from the peer.
|
||||
ble_l2cap_ch_setup_params_t reply_param;
|
||||
uint16_t local_cid;
|
||||
|
||||
memset(&reply_param, 0, sizeof(ble_l2cap_ch_setup_params_t));
|
||||
|
||||
reply_param.le_psm = p_evt->evt.l2cap_evt.params.ch_setup_request.le_psm;
|
||||
reply_param.rx_params.rx_mtu = BLE_IPSP_MTU;
|
||||
reply_param.rx_params.rx_mps = BLE_IPSP_RX_MPS;
|
||||
|
||||
// Check if a channel already exists with the peer.
|
||||
retval = channel_search(p_evt->evt.l2cap_evt.conn_handle,
|
||||
IPSP_ANY_CID,
|
||||
&ch_id);
|
||||
|
||||
BLE_IPSP_TRC("Exiting channel_search result 0x%08X", ch_id);
|
||||
|
||||
if (retval == NRF_SUCCESS)
|
||||
{
|
||||
BLE_IPSP_TRC("Rejecting channel, as IPSP channel already exists "
|
||||
"0x%08X in state 0x%08X", ch_id, m_channel[ch_id].state);
|
||||
|
||||
reply_param.status = BLE_L2CAP_CH_STATUS_CODE_NO_RESOURCES;
|
||||
|
||||
// Reinitialize ch_id to invalid so that existing channel is not impacted.
|
||||
ch_id = INVALID_CHANNEL_INSTANCE;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t peer_device_index = connected_device_search(p_evt->evt.l2cap_evt.conn_handle);
|
||||
local_cid = p_evt->evt.l2cap_evt.local_cid;
|
||||
|
||||
if (p_evt->evt.l2cap_evt.params.ch_setup_request.le_psm != BLE_IPSP_PSM)
|
||||
{
|
||||
reply_param.status = BLE_L2CAP_CH_STATUS_CODE_LE_PSM_NOT_SUPPORTED;
|
||||
BLE_IPSP_TRC("Rejecting L2CAP Channel, unknown PSM %04X!",
|
||||
p_evt->evt.l2cap_evt.params.ch_setup_request.le_psm);
|
||||
}
|
||||
else if ((peer_device_index != IPSP_MAX_CONNECTED_DEVICES) &&
|
||||
(m_connected_device[peer_device_index].response == INCOMING_CHANNEL_REJECT))
|
||||
{
|
||||
reply_param.status = BLE_L2CAP_CH_STATUS_CODE_NO_RESOURCES;
|
||||
BLE_IPSP_ERR("Barred incoming requests by the application. "
|
||||
"Rejecting L2CAP Channel %04X!",
|
||||
p_evt->evt.l2cap_evt.params.ch_setup_request.le_psm);
|
||||
}
|
||||
else if (p_evt->evt.l2cap_evt.params.ch_setup_request.tx_params.tx_mtu < BLE_IPSP_MTU)
|
||||
{
|
||||
reply_param.status = BLE_L2CAP_CH_STATUS_CODE_UNACCEPTABLE_PARAMS;
|
||||
BLE_IPSP_TRC("Rejecting L2CAP Channel, unacceptable TX parameters!");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Peer request acceptable, look for a free channel.
|
||||
retval = channel_search(BLE_CONN_HANDLE_INVALID, BLE_L2CAP_CID_INVALID, &ch_id);
|
||||
BLE_IPSP_TRC("Free channel search result 0x%08X", ch_id);
|
||||
|
||||
if (retval != NRF_SUCCESS)
|
||||
{
|
||||
BLE_IPSP_TRC("Rejecting L2CAP Channel, no resources!");
|
||||
reply_param.status = BLE_L2CAP_CH_STATUS_CODE_NO_RESOURCES;
|
||||
}
|
||||
else
|
||||
{
|
||||
BLE_IPSP_TRC("Accepting L2CAP Channel");
|
||||
reply_param.rx_params.sdu_buf.p_data = NULL;
|
||||
reply_param.rx_params.sdu_buf.len = 0;
|
||||
reply_param.status = BLE_L2CAP_CH_STATUS_CODE_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
retval = sd_ble_l2cap_ch_setup(p_evt->evt.l2cap_evt.conn_handle,
|
||||
&local_cid,
|
||||
&reply_param);
|
||||
|
||||
BLE_IPSP_TRC("sd_ble_l2cap_ch_setup result = 0x%08lX", retval);
|
||||
|
||||
if ((retval == NRF_SUCCESS) &&
|
||||
(reply_param.status == BLE_L2CAP_CH_STATUS_CODE_SUCCESS) &&
|
||||
(ch_id != INVALID_CHANNEL_INSTANCE))
|
||||
{
|
||||
BLE_IPSP_TRC("[0x%04X][0x%04X]: Channel Connected. Rx MPS = 0x%04X",
|
||||
p_evt->evt.l2cap_evt.conn_handle,
|
||||
p_evt->evt.l2cap_evt.local_cid,
|
||||
reply_param.rx_params.rx_mps);
|
||||
|
||||
ipsp_event.evt_id = BLE_IPSP_EVT_CHANNEL_CONNECTED;
|
||||
ipsp_event.evt_result = NRF_SUCCESS;
|
||||
|
||||
// Channel is assigned to this link.
|
||||
m_channel[ch_id].state = CHANNEL_CONNECTING;
|
||||
m_channel[ch_id].conn_handle = p_evt->evt.l2cap_evt.conn_handle;
|
||||
m_channel[ch_id].cid = local_cid;
|
||||
}
|
||||
else if (ch_id != INVALID_CHANNEL_INSTANCE)
|
||||
{
|
||||
// Free the allocated channel.
|
||||
channel_init(ch_id);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BLE_L2CAP_EVT_CH_SETUP:
|
||||
{
|
||||
// This event is generated for both initiator and acceptor roles.
|
||||
// This event indicates that the IPSP channel is successfully established.
|
||||
retval = channel_search(p_evt->evt.l2cap_evt.conn_handle,
|
||||
p_evt->evt.l2cap_evt.local_cid,
|
||||
&ch_id);
|
||||
|
||||
if (retval != NRF_SUCCESS)
|
||||
{
|
||||
BLE_IPSP_TRC("Reply on unknown channel, dropping the event.");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_channel[ch_id].state == CHANNEL_CONNECTING)
|
||||
{
|
||||
// Channel created successfully.
|
||||
|
||||
// Initialize IPSP handle.
|
||||
handle.conn_handle = p_evt->evt.l2cap_evt.conn_handle;
|
||||
handle.cid = p_evt->evt.l2cap_evt.local_cid;
|
||||
|
||||
// Initialize the event.
|
||||
ipsp_event.evt_id = BLE_IPSP_EVT_CHANNEL_CONNECTED;
|
||||
ipsp_event.evt_result = NRF_SUCCESS;
|
||||
|
||||
// Set the channel state appropriately.
|
||||
m_channel[ch_id].state = CHANNEL_CONNECTED;
|
||||
|
||||
// Set the flag to trigger submission of the receive buffers to the softdevice.
|
||||
submit_rx_buffer = true;
|
||||
|
||||
// Notify the event to the application.
|
||||
notify_event = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BLE_L2CAP_EVT_CH_SETUP_REFUSED:
|
||||
{
|
||||
// This event is generated for both initiator and acceptor roles.
|
||||
// This event indicates that the IPSP channel establishment failed.
|
||||
retval = channel_search(p_evt->evt.l2cap_evt.conn_handle,
|
||||
p_evt->evt.l2cap_evt.local_cid,
|
||||
&ch_id);
|
||||
|
||||
if (retval != NRF_SUCCESS)
|
||||
{
|
||||
BLE_IPSP_TRC("Reply on unknown channel, dropping the event.");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_channel[ch_id].state == CHANNEL_CONNECTING)
|
||||
{
|
||||
// Channel creation failed as peer rejected the connection.
|
||||
|
||||
// Initialize the event.
|
||||
ipsp_event.evt_id = BLE_IPSP_EVT_CHANNEL_CONNECTED;
|
||||
ipsp_event.evt_result = NRF_ERROR_BLE_IPSP_PEER_REJECTED;
|
||||
|
||||
BLE_IPSP_ERR("Peer rejected channel creation request, reason %d",
|
||||
p_evt->evt.l2cap_evt.params.ch_setup_refused.status);
|
||||
|
||||
// Free the channel.
|
||||
channel_free(ch_id);
|
||||
|
||||
// Notify the event to the application.
|
||||
notify_event = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BLE_L2CAP_EVT_CH_RELEASED:
|
||||
{
|
||||
BLE_IPSP_TRC("L2CAP Channel disconnected.");
|
||||
|
||||
ipsp_event.evt_id = BLE_IPSP_EVT_CHANNEL_DISCONNECTED;
|
||||
|
||||
retval = channel_search(p_evt->evt.l2cap_evt.conn_handle,
|
||||
p_evt->evt.l2cap_evt.local_cid,
|
||||
&ch_id);
|
||||
|
||||
// Notify application of disconnection.
|
||||
if (retval == NRF_SUCCESS)
|
||||
{
|
||||
handle.conn_handle = p_evt->evt.l2cap_evt.conn_handle;
|
||||
handle.cid = p_evt->evt.l2cap_evt.local_cid;
|
||||
|
||||
channel_free(ch_id);
|
||||
|
||||
// Notify the event to the application.
|
||||
notify_event = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BLE_L2CAP_EVT_CH_RX:
|
||||
{
|
||||
ipsp_event.evt_id = BLE_IPSP_EVT_CHANNEL_DATA_RX;
|
||||
|
||||
retval = channel_search(p_evt->evt.l2cap_evt.conn_handle,
|
||||
p_evt->evt.l2cap_evt.local_cid,
|
||||
&ch_id);
|
||||
|
||||
if (retval == NRF_SUCCESS)
|
||||
{
|
||||
handle.conn_handle = p_evt->evt.l2cap_evt.conn_handle;
|
||||
handle.cid = p_evt->evt.l2cap_evt.local_cid;
|
||||
|
||||
rx_buffer_mark_unused(ch_id, p_evt->evt.l2cap_evt.params.rx.sdu_buf.p_data);
|
||||
|
||||
// Set the flag to trigger submission of the receive buffers to the softdevice.
|
||||
submit_rx_buffer = true;
|
||||
|
||||
// Notify the event to the application.
|
||||
notify_event = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BLE_L2CAP_EVT_CH_TX:
|
||||
{
|
||||
BLE_IPSP_TRC("BLE_L2CAP_EVT_CH_TX --> p_sdu_buf = %p, p_sdu_buf.p_data = %p",
|
||||
&p_evt->evt.l2cap_evt.params.tx.sdu_buf, p_evt->evt.l2cap_evt.params.tx.sdu_buf.p_data);
|
||||
|
||||
retval = channel_search(p_evt->evt.l2cap_evt.conn_handle,
|
||||
p_evt->evt.l2cap_evt.local_cid,
|
||||
&ch_id);
|
||||
|
||||
if ((ch_id != INVALID_CHANNEL_INSTANCE) &&
|
||||
p_evt->evt.l2cap_evt.local_cid == m_channel[ch_id].cid)
|
||||
{
|
||||
// Initialize the event.
|
||||
ipsp_event.evt_id = BLE_IPSP_EVT_CHANNEL_DATA_TX_COMPLETE;
|
||||
|
||||
// Initialize the handle.
|
||||
handle.conn_handle = m_channel[ch_id].conn_handle;
|
||||
handle.cid = m_channel[ch_id].cid;
|
||||
|
||||
// Notify the event to the application.
|
||||
notify_event = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BLE_L2CAP_EVT_CH_SDU_BUF_RELEASED:
|
||||
{
|
||||
BLE_IPSP_TRC("BLE_L2CAP_EVT_CH_SDU_BUF_RELEASED --> p_sdu_buf = %p, p_sdu_buf.p_data = %p",
|
||||
&p_evt->evt.l2cap_evt.params.ch_sdu_buf_released.sdu_buf,
|
||||
p_evt->evt.l2cap_evt.params.ch_sdu_buf_released.sdu_buf.p_data);
|
||||
|
||||
retval = channel_search(p_evt->evt.l2cap_evt.conn_handle,
|
||||
p_evt->evt.l2cap_evt.local_cid,
|
||||
&ch_id);
|
||||
|
||||
if ((ch_id != INVALID_CHANNEL_INSTANCE) &&
|
||||
(p_evt->evt.l2cap_evt.local_cid == m_channel[ch_id].cid) &&
|
||||
(is_tx_buffer(ch_id, p_evt->evt.l2cap_evt.params.ch_sdu_buf_released.sdu_buf.p_data)))
|
||||
{
|
||||
// Initialize the event.
|
||||
ipsp_event.evt_id = BLE_IPSP_EVT_CHANNEL_DATA_TX_COMPLETE;
|
||||
ipsp_event.evt_result = NRF_ERROR_BLE_IPSP_LINK_DISCONNECTED;
|
||||
|
||||
// Initialize the handle.
|
||||
handle.conn_handle = m_channel[ch_id].conn_handle;
|
||||
handle.cid = m_channel[ch_id].cid;
|
||||
|
||||
// Notify the event to the application.
|
||||
notify_event = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BLE_GAP_EVT_DISCONNECTED:
|
||||
{
|
||||
uint32_t peer_device_index = connected_device_search(handle.conn_handle);
|
||||
if (peer_device_index < IPSP_MAX_CONNECTED_DEVICES)
|
||||
{
|
||||
connected_device_init(peer_device_index);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (notify_event)
|
||||
{
|
||||
ble_ipsp_event_param_t event_param;
|
||||
uint32_t peer_device_index;
|
||||
|
||||
peer_device_index = connected_device_search(handle.conn_handle);
|
||||
|
||||
if (peer_device_index < IPSP_MAX_CONNECTED_DEVICES)
|
||||
{
|
||||
event_param.p_peer = &m_connected_device[peer_device_index].ble_addr;
|
||||
BLE_IPSP_TRC("Found peer device. Address type = 0x%02x",
|
||||
event_param.p_peer->addr_type);
|
||||
BLE_IPSP_DUMP((uint8_t *)event_param.p_peer->addr, 6);
|
||||
}
|
||||
else
|
||||
{
|
||||
event_param.p_peer = NULL;
|
||||
}
|
||||
|
||||
event_param.p_l2cap_evt = &p_evt->evt.l2cap_evt;
|
||||
ipsp_event.p_evt_param = &event_param;
|
||||
|
||||
app_notify(&handle, &ipsp_event);
|
||||
}
|
||||
|
||||
// Trigger submission of the receive buffers to the softdevice.
|
||||
if (submit_rx_buffer)
|
||||
{
|
||||
rx_buffers_submit(ch_id);
|
||||
}
|
||||
|
||||
BLE_IPSP_MUTEX_UNLOCK();
|
||||
UNUSED_VARIABLE(retval);
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_ipsp_init(const ble_ipsp_init_t * p_init)
|
||||
{
|
||||
BLE_IPSP_ENTRY();
|
||||
|
||||
ble_uuid_t ble_uuid;
|
||||
uint32_t err_code;
|
||||
uint16_t handle;
|
||||
|
||||
NULL_PARAM_CHECK(p_init);
|
||||
NULL_PARAM_CHECK(p_init->evt_handler);
|
||||
|
||||
SDK_MUTEX_INIT(m_ipsp_mutex);
|
||||
|
||||
BLE_IPSP_MUTEX_LOCK();
|
||||
|
||||
// Add service to indicate IPSP support.
|
||||
BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_IPSP_SERVICE);
|
||||
|
||||
err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &ble_uuid, &handle);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
|
||||
m_evt_handler = p_init->evt_handler;
|
||||
|
||||
// Initialize the channel.
|
||||
for (int i = 0; i < BLE_IPSP_MAX_CHANNELS; i++)
|
||||
{
|
||||
channel_init(i);
|
||||
}
|
||||
|
||||
// Initialize the connected peer device table.
|
||||
for (int i = 0; i < IPSP_MAX_CONNECTED_DEVICES; i++)
|
||||
{
|
||||
connected_device_init(i);
|
||||
}
|
||||
BLE_IPSP_MUTEX_UNLOCK();
|
||||
|
||||
BLE_IPSP_EXIT();
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_ipsp_connect(const ble_ipsp_handle_t * p_handle)
|
||||
{
|
||||
VERIFY_MODULE_IS_INITIALIZED();
|
||||
NULL_PARAM_CHECK(p_handle);
|
||||
VERIFY_CON_HANDLE(p_handle->conn_handle);
|
||||
|
||||
uint32_t err_code;
|
||||
uint8_t ch_id = INVALID_CHANNEL_INSTANCE;
|
||||
|
||||
BLE_IPSP_TRC("[Conn Handle 0x%04X]: >> ble_ipsp_connect",
|
||||
p_handle->conn_handle);
|
||||
|
||||
BLE_IPSP_MUTEX_LOCK();
|
||||
|
||||
// Check if channel already exists with the peer.
|
||||
err_code = channel_search(p_handle->conn_handle, IPSP_ANY_CID, &ch_id);
|
||||
|
||||
if (err_code == NRF_SUCCESS)
|
||||
{
|
||||
// IPSP channel already exists.
|
||||
err_code = NRF_ERROR_BLE_IPSP_CHANNEL_ALREADY_EXISTS;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Search for a free channel.
|
||||
err_code = channel_search(BLE_CONN_HANDLE_INVALID, BLE_L2CAP_CID_INVALID, &ch_id);
|
||||
BLE_IPSP_TRC("2 channel_search result %08X", err_code);
|
||||
|
||||
if (err_code == NRF_SUCCESS)
|
||||
{
|
||||
m_channel[ch_id].state = CHANNEL_CONNECTING;
|
||||
|
||||
ble_l2cap_ch_setup_params_t param =
|
||||
{
|
||||
.le_psm = BLE_IPSP_PSM,
|
||||
.rx_params = {
|
||||
.rx_mtu = BLE_IPSP_MTU,
|
||||
.rx_mps = BLE_IPSP_RX_MPS,
|
||||
.sdu_buf =
|
||||
{
|
||||
.p_data = NULL,
|
||||
.len = 0
|
||||
}
|
||||
}
|
||||
};
|
||||
BLE_IPSP_TRC("Requesting sd_ble_l2cap_ch_setup");
|
||||
|
||||
err_code = sd_ble_l2cap_ch_setup(p_handle->conn_handle,
|
||||
&m_channel[ch_id].cid,
|
||||
¶m);
|
||||
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
BLE_IPSP_ERR("sd_ble_l2cap_ch_conn_request failed, reason %08lX", err_code);
|
||||
channel_free(ch_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
BLE_IPSP_TRC("Local channel id from SD %04X.", m_channel[ch_id].cid);
|
||||
m_channel[ch_id].conn_handle = p_handle->conn_handle;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
err_code = (NRF_ERROR_BLE_IPSP_ERR_BASE + NRF_ERROR_NO_MEM);
|
||||
}
|
||||
}
|
||||
|
||||
BLE_IPSP_MUTEX_UNLOCK();
|
||||
|
||||
BLE_IPSP_EXIT_WITH_RESULT(err_code);
|
||||
|
||||
return err_code;
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_ipsp_send(ble_ipsp_handle_t const * p_handle,
|
||||
uint8_t const * p_data,
|
||||
uint16_t data_len)
|
||||
{
|
||||
BLE_IPSP_ENTRY();
|
||||
|
||||
VERIFY_MODULE_IS_INITIALIZED();
|
||||
NULL_PARAM_CHECK(p_handle);
|
||||
NULL_PARAM_CHECK(p_data);
|
||||
VERIFY_CON_HANDLE(p_handle->conn_handle);
|
||||
|
||||
uint32_t err_code;
|
||||
uint8_t ch_id;
|
||||
|
||||
BLE_IPSP_MUTEX_LOCK();
|
||||
|
||||
err_code = channel_search(p_handle->conn_handle, p_handle->cid, &ch_id);
|
||||
|
||||
if (err_code == NRF_SUCCESS)
|
||||
{
|
||||
const ble_data_t p_sdu_buf =
|
||||
{
|
||||
.p_data = (uint8_t *)p_data,
|
||||
.len = data_len
|
||||
};
|
||||
|
||||
BLE_IPSP_TRC("p_sdu_buf = %p, p_sdu_buf.p_data = %p",
|
||||
&p_sdu_buf, p_data);
|
||||
|
||||
err_code = sd_ble_l2cap_ch_tx(p_handle->conn_handle,
|
||||
p_handle->cid,
|
||||
&p_sdu_buf);
|
||||
}
|
||||
|
||||
BLE_IPSP_MUTEX_UNLOCK();
|
||||
|
||||
BLE_IPSP_EXIT_WITH_RESULT(err_code);
|
||||
|
||||
return err_code;
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_ipsp_disconnect(ble_ipsp_handle_t const * p_handle)
|
||||
{
|
||||
BLE_IPSP_ENTRY();
|
||||
|
||||
VERIFY_MODULE_IS_INITIALIZED();
|
||||
NULL_PARAM_CHECK(p_handle);
|
||||
VERIFY_CON_HANDLE(p_handle->conn_handle);
|
||||
|
||||
uint32_t err_code;
|
||||
uint8_t ch_id;
|
||||
|
||||
BLE_IPSP_MUTEX_LOCK();
|
||||
|
||||
err_code = channel_search(p_handle->conn_handle, p_handle->cid, &ch_id);
|
||||
|
||||
if (err_code == NRF_SUCCESS)
|
||||
{
|
||||
m_channel[ch_id].state = CHANNEL_DISCONNECTING;
|
||||
|
||||
err_code = sd_ble_l2cap_ch_release(p_handle->conn_handle,
|
||||
p_handle->cid);
|
||||
}
|
||||
|
||||
BLE_IPSP_MUTEX_UNLOCK();
|
||||
|
||||
BLE_IPSP_EXIT_WITH_RESULT(err_code);
|
||||
|
||||
return err_code;
|
||||
}
|
||||
|
||||
|
||||
void ble_ipsp_incoming_channel_reject(uint16_t conn_handle)
|
||||
{
|
||||
uint32_t peer_device_index = connected_device_search(conn_handle);
|
||||
|
||||
if (peer_device_index != IPSP_MAX_CONNECTED_DEVICES)
|
||||
{
|
||||
m_connected_device[peer_device_index].response = INCOMING_CHANNEL_REJECT;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ble_ipsp_incoming_channel_accept(uint16_t conn_handle)
|
||||
{
|
||||
uint32_t peer_device_index = connected_device_search(conn_handle);
|
||||
|
||||
if (peer_device_index != IPSP_MAX_CONNECTED_DEVICES)
|
||||
{
|
||||
m_connected_device[peer_device_index].response = INCOMING_CHANNEL_ACCEPT;
|
||||
}
|
||||
}
|
||||
253
components/ble/ble_services/ble_ipsp/ble_ipsp.h
Normal file
253
components/ble/ble_services/ble_ipsp/ble_ipsp.h
Normal file
@@ -0,0 +1,253 @@
|
||||
/**
|
||||
* Copyright (c) 2014 - 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 ble_ipsp Internet Protocol Support Profile
|
||||
* @{
|
||||
* @ingroup ble_sdk_srv
|
||||
* @brief Internet Protocol Support Profile.
|
||||
*
|
||||
* @details This module implements the Internet Protocol Support Profile creating and managing
|
||||
* transport for 6lowpan.
|
||||
* GATT is used to discover if IPSP is supported or not, but no IP data is exchanged
|
||||
* over GATT. To exchange data, LE L2CAP Credit Mode is used. The PSM used for the channel
|
||||
* is BLE_IPSP_PSM and is defined by the specification. The MTU mandated by the
|
||||
* specification is 1280 bytes.
|
||||
*
|
||||
* @note Attention!
|
||||
* To maintain compliance with Nordic Semiconductor ASA's Bluetooth profile
|
||||
* qualification listings, this section of source code must not be modified.
|
||||
*/
|
||||
|
||||
#ifndef BLE_IPSP_H__
|
||||
#define BLE_IPSP_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include "ble.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**@brief Maximum IPSP channels required to be supported. */
|
||||
#define BLE_IPSP_MAX_CHANNELS 1
|
||||
|
||||
/**@brief Maximum Transmit Unit on IPSP channel. */
|
||||
#define BLE_IPSP_MTU 1280
|
||||
|
||||
/**@brief Receive MPS used by IPSP. */
|
||||
#define BLE_IPSP_RX_MPS 50
|
||||
|
||||
/**@brief Transmission MPS used by IPSP.
|
||||
*
|
||||
* @note The actual MPS used is minimum of this value and the one requested by
|
||||
* the peer during the channel setup. Here, the value used is
|
||||
* (23 + 27 * 7).
|
||||
*/
|
||||
#define BLE_IPSP_TX_MPS 212
|
||||
|
||||
/**@brief Maximum data size that can be received.
|
||||
*
|
||||
* @details Maximum data size that can be received on the IPSP channel.
|
||||
* Modify this values to intentionally set a receive size less
|
||||
* than the MTU set on the channel.
|
||||
*/
|
||||
#define BLE_IPSP_RX_BUFFER_SIZE 1280
|
||||
|
||||
/**@brief Maximum number of receive buffers.
|
||||
*
|
||||
* @details Maximum number of receive buffers to be used per IPSP channel.
|
||||
* Each receive buffer is of size @ref BLE_IPSP_RX_BUFFER_SIZE.
|
||||
* This configuration has implications on the number of SDUs that can
|
||||
* be received while an SDU is being consumed by the application
|
||||
* (6LoWPAN/IP Stack).
|
||||
*/
|
||||
#define BLE_IPSP_RX_BUFFER_COUNT 4
|
||||
|
||||
/**@brief L2CAP Protocol Service Multiplexers number. */
|
||||
#define BLE_IPSP_PSM 0x0023
|
||||
|
||||
|
||||
/**@brief IPSP event identifier type. */
|
||||
typedef enum
|
||||
{
|
||||
BLE_IPSP_EVT_CHANNEL_CONNECTED, /**< Channel connection event. */
|
||||
BLE_IPSP_EVT_CHANNEL_DISCONNECTED, /**< Channel disconnection event. */
|
||||
BLE_IPSP_EVT_CHANNEL_DATA_RX, /**< Data received on channel event. */
|
||||
BLE_IPSP_EVT_CHANNEL_DATA_TX_COMPLETE /**< Requested data transmission complete on channel event. */
|
||||
} ble_ipsp_evt_type_t;
|
||||
|
||||
|
||||
/**@brief IPSP event parameter. */
|
||||
typedef struct
|
||||
{
|
||||
ble_l2cap_evt_t const * p_l2cap_evt; /**< L2CAP event parameters. */
|
||||
ble_gap_addr_t const * p_peer; /**< Peer device address. */
|
||||
} ble_ipsp_event_param_t;
|
||||
|
||||
|
||||
/**@brief IPSP event and associated parameter type. */
|
||||
typedef struct
|
||||
{
|
||||
ble_ipsp_evt_type_t evt_id; /**< Identifier event type. */
|
||||
ble_ipsp_event_param_t * p_evt_param; /**< Parameters associated with the event. */
|
||||
uint32_t evt_result; /**< Result of the event.
|
||||
\n The event result is SDK_ERR_RX_PKT_TRUNCATED for @ref BLE_IPSP_EVT_CHANNEL_DATA_RX,
|
||||
\n implies that an incomplete SDU was received due to insufficient RX buffer size.
|
||||
\n The size determined by @ref BLE_IPSP_RX_BUFFER_SIZE. */
|
||||
} ble_ipsp_evt_t;
|
||||
|
||||
|
||||
/**@brief IPSP handle. */
|
||||
typedef struct
|
||||
{
|
||||
uint16_t conn_handle; /**< Identifies the link on which the IPSP channel is established. */
|
||||
uint16_t cid; /**< Identifies the IPSP logical channel. */
|
||||
} ble_ipsp_handle_t;
|
||||
|
||||
|
||||
/**@brief Profile event handler type.
|
||||
*
|
||||
* @param[in] p_handle Identifies the connection and channel on which the event occurred.
|
||||
* @param[in] p_evt Event and related parameters (if any).
|
||||
*
|
||||
* @returns Provision for the application to indicate if the event was successfully processed or
|
||||
* not. Currently not used.
|
||||
*/
|
||||
typedef uint32_t (*ble_ipsp_evt_handler_t) (ble_ipsp_handle_t const * p_handle,
|
||||
ble_ipsp_evt_t const * p_evt);
|
||||
|
||||
|
||||
/**@brief IPSP initialization structure.
|
||||
*
|
||||
* @details IPSP initialization structure containing all options and data needed to
|
||||
* initialize the profile.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
ble_ipsp_evt_handler_t evt_handler; /**< Event notification callback registered with the module to receive asynchronous events. */
|
||||
} ble_ipsp_init_t;
|
||||
|
||||
|
||||
/**@brief Function for initializing the Internet Protocol Support Profile.
|
||||
*
|
||||
* @param[in] p_init Information needed to initialize the service.
|
||||
*
|
||||
* @retval NRF_SUCCESS If initialization of the service was successful, else,
|
||||
* an error code indicating reason for failure.
|
||||
*/
|
||||
uint32_t ble_ipsp_init(ble_ipsp_init_t const * p_init);
|
||||
|
||||
|
||||
/**@brief Function for requesting a channel creation for the Internet Protocol Support Profile.
|
||||
*
|
||||
* @details Channel creation for Internet Protocol Support Profile (IPSP) is requested using this
|
||||
* API. Connection handle provided in p_handle parameter identifies the peer with which
|
||||
* the IPSP channel is being requested.
|
||||
* NRF_SUCCESS return value by the API is only indicative of request procedure having
|
||||
* succeeded. Result of channel establishment is known when the
|
||||
* @ref BLE_IPSP_EVT_CHANNEL_CONNECTED event is notified.
|
||||
* Therefore, the application must wait for @ref BLE_IPSP_EVT_CHANNEL_CONNECTED event on
|
||||
* successful return of this API.
|
||||
*
|
||||
* @param[in] p_handle Indicates the connection handle on which IPSP channel is to be created.
|
||||
*
|
||||
* @retval NRF_SUCCESS If initialization of the service was successful, else,
|
||||
* an error code indicating reason for failure.
|
||||
*/
|
||||
uint32_t ble_ipsp_connect(ble_ipsp_handle_t const * p_handle);
|
||||
|
||||
|
||||
/**@brief Function for sending IP data to peer.
|
||||
*
|
||||
* @param[in] p_handle Instance of the logical channel and peer for which the data is intended.
|
||||
* @param[in] p_data Pointer to memory containing the data to be transmitted.
|
||||
* @note This memory must be resident and should not be freed unless
|
||||
* @ref BLE_IPSP_EVT_CHANNEL_DATA_TX_COMPLETE event is notified.
|
||||
* @param[in] data_len Length/size of data to be transferred.
|
||||
*
|
||||
* @retval NRF_SUCCESS If initialization of the service was successful, else,
|
||||
* an error code indicating reason for failure.
|
||||
*/
|
||||
uint32_t ble_ipsp_send(ble_ipsp_handle_t const * p_handle,
|
||||
uint8_t const * p_data,
|
||||
uint16_t data_len);
|
||||
|
||||
|
||||
/**@brief Function for disconnecting IP transport.
|
||||
*
|
||||
* @param[in] p_handle Identifies IPSP transport.
|
||||
*
|
||||
* @retval NRF_SUCCESS If initialization of the service was successful, else,
|
||||
* an error code indicating reason for failure.
|
||||
*/
|
||||
uint32_t ble_ipsp_disconnect(ble_ipsp_handle_t const * p_handle);
|
||||
|
||||
|
||||
/**@brief Function to accept incoming connections from a peer.
|
||||
*
|
||||
* @param[in] conn_handle Identifies the link with the peer.
|
||||
*/
|
||||
void ble_ipsp_incoming_channel_accept(uint16_t conn_handle);
|
||||
|
||||
|
||||
/**@brief Function to reject incoming connections from a peer.
|
||||
*
|
||||
* @param[in] conn_handle Identifies the link with the peer.
|
||||
*/
|
||||
void ble_ipsp_incoming_channel_reject(uint16_t conn_handle);
|
||||
|
||||
|
||||
/**@brief BLE event handler of the module.
|
||||
*
|
||||
* @param[in] p_evt BLE event to be handled.
|
||||
*
|
||||
* @retval NRF_SUCCESS If initialization of the service was successful, else,
|
||||
* an error code indicating reason for failure.
|
||||
*/
|
||||
void ble_ipsp_evt_handler(ble_evt_t const * p_evt);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // BLE_IPSP_H__
|
||||
|
||||
/** @} */
|
||||
150
components/ble/ble_services/ble_lbs/ble_lbs.c
Normal file
150
components/ble/ble_services/ble_lbs/ble_lbs.c
Normal file
@@ -0,0 +1,150 @@
|
||||
/**
|
||||
* Copyright (c) 2013 - 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_LBS)
|
||||
#include "ble_lbs.h"
|
||||
#include "ble_srv_common.h"
|
||||
|
||||
|
||||
/**@brief Function for handling the Write event.
|
||||
*
|
||||
* @param[in] p_lbs LED Button Service structure.
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
*/
|
||||
static void on_write(ble_lbs_t * p_lbs, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
ble_gatts_evt_write_t const * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
|
||||
|
||||
if ( (p_evt_write->handle == p_lbs->led_char_handles.value_handle)
|
||||
&& (p_evt_write->len == 1)
|
||||
&& (p_lbs->led_write_handler != NULL))
|
||||
{
|
||||
p_lbs->led_write_handler(p_ble_evt->evt.gap_evt.conn_handle, p_lbs, p_evt_write->data[0]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ble_lbs_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
|
||||
{
|
||||
ble_lbs_t * p_lbs = (ble_lbs_t *)p_context;
|
||||
|
||||
switch (p_ble_evt->header.evt_id)
|
||||
{
|
||||
case BLE_GATTS_EVT_WRITE:
|
||||
on_write(p_lbs, p_ble_evt);
|
||||
break;
|
||||
|
||||
default:
|
||||
// No implementation needed.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_lbs_init(ble_lbs_t * p_lbs, const ble_lbs_init_t * p_lbs_init)
|
||||
{
|
||||
uint32_t err_code;
|
||||
ble_uuid_t ble_uuid;
|
||||
ble_add_char_params_t add_char_params;
|
||||
|
||||
// Initialize service structure.
|
||||
p_lbs->led_write_handler = p_lbs_init->led_write_handler;
|
||||
|
||||
// Add service.
|
||||
ble_uuid128_t base_uuid = {LBS_UUID_BASE};
|
||||
err_code = sd_ble_uuid_vs_add(&base_uuid, &p_lbs->uuid_type);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
ble_uuid.type = p_lbs->uuid_type;
|
||||
ble_uuid.uuid = LBS_UUID_SERVICE;
|
||||
|
||||
err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &ble_uuid, &p_lbs->service_handle);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
// Add Button characteristic.
|
||||
memset(&add_char_params, 0, sizeof(add_char_params));
|
||||
add_char_params.uuid = LBS_UUID_BUTTON_CHAR;
|
||||
add_char_params.uuid_type = p_lbs->uuid_type;
|
||||
add_char_params.init_len = sizeof(uint8_t);
|
||||
add_char_params.max_len = sizeof(uint8_t);
|
||||
add_char_params.char_props.read = 1;
|
||||
add_char_params.char_props.notify = 1;
|
||||
|
||||
add_char_params.read_access = SEC_OPEN;
|
||||
add_char_params.cccd_write_access = SEC_OPEN;
|
||||
|
||||
err_code = characteristic_add(p_lbs->service_handle,
|
||||
&add_char_params,
|
||||
&p_lbs->button_char_handles);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
|
||||
// Add LED characteristic.
|
||||
memset(&add_char_params, 0, sizeof(add_char_params));
|
||||
add_char_params.uuid = LBS_UUID_LED_CHAR;
|
||||
add_char_params.uuid_type = p_lbs->uuid_type;
|
||||
add_char_params.init_len = sizeof(uint8_t);
|
||||
add_char_params.max_len = sizeof(uint8_t);
|
||||
add_char_params.char_props.read = 1;
|
||||
add_char_params.char_props.write = 1;
|
||||
|
||||
add_char_params.read_access = SEC_OPEN;
|
||||
add_char_params.write_access = SEC_OPEN;
|
||||
|
||||
return characteristic_add(p_lbs->service_handle, &add_char_params, &p_lbs->led_char_handles);
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_lbs_on_button_change(uint16_t conn_handle, ble_lbs_t * p_lbs, uint8_t button_state)
|
||||
{
|
||||
ble_gatts_hvx_params_t params;
|
||||
uint16_t len = sizeof(button_state);
|
||||
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
params.type = BLE_GATT_HVX_NOTIFICATION;
|
||||
params.handle = p_lbs->button_char_handles.value_handle;
|
||||
params.p_data = &button_state;
|
||||
params.p_len = &len;
|
||||
|
||||
return sd_ble_gatts_hvx(conn_handle, ¶ms);
|
||||
}
|
||||
#endif // NRF_MODULE_ENABLED(BLE_LBS)
|
||||
161
components/ble/ble_services/ble_lbs/ble_lbs.h
Normal file
161
components/ble/ble_services/ble_lbs/ble_lbs.h
Normal file
@@ -0,0 +1,161 @@
|
||||
/**
|
||||
* Copyright (c) 2015 - 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 ble_lbs LED Button Service Server
|
||||
* @{
|
||||
* @ingroup ble_sdk_srv
|
||||
*
|
||||
* @brief LED Button Service Server module.
|
||||
*
|
||||
* @details This module implements a custom LED Button Service with an LED and Button Characteristics.
|
||||
* During initialization, the module adds the LED Button Service and Characteristics
|
||||
* to the BLE stack database.
|
||||
*
|
||||
* The application must supply an event handler for receiving LED Button Service
|
||||
* events. Using this handler, the service notifies the application when the
|
||||
* LED value changes.
|
||||
*
|
||||
* The service also provides a function for letting the application notify
|
||||
* the state of the Button Characteristic to connected peers.
|
||||
*
|
||||
* @note The application must register this module as BLE event observer using the
|
||||
* NRF_SDH_BLE_OBSERVER macro. Example:
|
||||
* @code
|
||||
* ble_hids_t instance;
|
||||
* NRF_SDH_BLE_OBSERVER(anything, BLE_HIDS_BLE_OBSERVER_PRIO,
|
||||
* ble_hids_on_ble_evt, &instance);
|
||||
* @endcode
|
||||
*/
|
||||
|
||||
#ifndef BLE_LBS_H__
|
||||
#define BLE_LBS_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "ble.h"
|
||||
#include "ble_srv_common.h"
|
||||
#include "nrf_sdh_ble.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**@brief Macro for defining a ble_lbs instance.
|
||||
*
|
||||
* @param _name Name of the instance.
|
||||
* @hideinitializer
|
||||
*/
|
||||
#define BLE_LBS_DEF(_name) \
|
||||
static ble_lbs_t _name; \
|
||||
NRF_SDH_BLE_OBSERVER(_name ## _obs, \
|
||||
BLE_LBS_BLE_OBSERVER_PRIO, \
|
||||
ble_lbs_on_ble_evt, &_name)
|
||||
|
||||
#define LBS_UUID_BASE {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15, \
|
||||
0xDE, 0xEF, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00}
|
||||
#define LBS_UUID_SERVICE 0x1523
|
||||
#define LBS_UUID_BUTTON_CHAR 0x1524
|
||||
#define LBS_UUID_LED_CHAR 0x1525
|
||||
|
||||
|
||||
// Forward declaration of the ble_lbs_t type.
|
||||
typedef struct ble_lbs_s ble_lbs_t;
|
||||
|
||||
typedef void (*ble_lbs_led_write_handler_t) (uint16_t conn_handle, ble_lbs_t * p_lbs, uint8_t new_state);
|
||||
|
||||
/** @brief LED Button Service init structure. This structure contains all options and data needed for
|
||||
* initialization of the service.*/
|
||||
typedef struct
|
||||
{
|
||||
ble_lbs_led_write_handler_t led_write_handler; /**< Event handler to be called when the LED Characteristic is written. */
|
||||
} ble_lbs_init_t;
|
||||
|
||||
/**@brief LED Button Service structure. This structure contains various status information for the service. */
|
||||
struct ble_lbs_s
|
||||
{
|
||||
uint16_t service_handle; /**< Handle of LED Button Service (as provided by the BLE stack). */
|
||||
ble_gatts_char_handles_t led_char_handles; /**< Handles related to the LED Characteristic. */
|
||||
ble_gatts_char_handles_t button_char_handles; /**< Handles related to the Button Characteristic. */
|
||||
uint8_t uuid_type; /**< UUID type for the LED Button Service. */
|
||||
ble_lbs_led_write_handler_t led_write_handler; /**< Event handler to be called when the LED Characteristic is written. */
|
||||
};
|
||||
|
||||
|
||||
/**@brief Function for initializing the LED Button Service.
|
||||
*
|
||||
* @param[out] p_lbs LED Button 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_lbs_init Information needed to initialize the service.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the service was initialized successfully. Otherwise, an error code is returned.
|
||||
*/
|
||||
uint32_t ble_lbs_init(ble_lbs_t * p_lbs, const ble_lbs_init_t * p_lbs_init);
|
||||
|
||||
|
||||
/**@brief Function for handling the application's BLE stack events.
|
||||
*
|
||||
* @details This function handles all events from the BLE stack that are of interest to the LED Button Service.
|
||||
*
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
* @param[in] p_context LED Button Service structure.
|
||||
*/
|
||||
void ble_lbs_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
|
||||
|
||||
|
||||
/**@brief Function for sending a button state notification.
|
||||
*
|
||||
' @param[in] conn_handle Handle of the peripheral connection to which the button state notification will be sent.
|
||||
* @param[in] p_lbs LED Button Service structure.
|
||||
* @param[in] button_state New button state.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the notification was sent successfully. Otherwise, an error code is returned.
|
||||
*/
|
||||
uint32_t ble_lbs_on_button_change(uint16_t conn_handle, ble_lbs_t * p_lbs, uint8_t button_state);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // BLE_LBS_H__
|
||||
|
||||
/** @} */
|
||||
322
components/ble/ble_services/ble_lbs_c/ble_lbs_c.c
Normal file
322
components/ble/ble_services/ble_lbs_c/ble_lbs_c.c
Normal file
@@ -0,0 +1,322 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 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_LBS_C)
|
||||
|
||||
#include "ble_lbs_c.h"
|
||||
#include "ble_db_discovery.h"
|
||||
#include "ble_types.h"
|
||||
#include "ble_gattc.h"
|
||||
#define NRF_LOG_MODULE_NAME ble_lbs_c
|
||||
#include "nrf_log.h"
|
||||
NRF_LOG_MODULE_REGISTER();
|
||||
|
||||
#define WRITE_MESSAGE_LENGTH BLE_CCCD_VALUE_LEN /**< Length of the write message for CCCD. */
|
||||
|
||||
|
||||
/**@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)
|
||||
{
|
||||
ble_lbs_c_t * p_ble_lbs_c = (ble_lbs_c_t *)p_ctx;
|
||||
|
||||
NRF_LOG_DEBUG("A GATT Client error has occurred on conn_handle: 0X%X", conn_handle);
|
||||
|
||||
if (p_ble_lbs_c->error_handler != NULL)
|
||||
{
|
||||
p_ble_lbs_c->error_handler(nrf_error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling Handle Value Notification received from the SoftDevice.
|
||||
*
|
||||
* @details This function uses the Handle Value Notification received from the SoftDevice
|
||||
* and checks whether it is a notification of Button state from the peer. If
|
||||
* it is, this function decodes the state of the button and sends it to the
|
||||
* application.
|
||||
*
|
||||
* @param[in] p_ble_lbs_c Pointer to the Led Button Client structure.
|
||||
* @param[in] p_ble_evt Pointer to the BLE event received.
|
||||
*/
|
||||
static void on_hvx(ble_lbs_c_t * p_ble_lbs_c, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
// Check if the event is on the link for this instance.
|
||||
if (p_ble_lbs_c->conn_handle != p_ble_evt->evt.gattc_evt.conn_handle)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Check if this is a Button notification.
|
||||
if (p_ble_evt->evt.gattc_evt.params.hvx.handle == p_ble_lbs_c->peer_lbs_db.button_handle)
|
||||
{
|
||||
if (p_ble_evt->evt.gattc_evt.params.hvx.len == 1)
|
||||
{
|
||||
ble_lbs_c_evt_t ble_lbs_c_evt;
|
||||
|
||||
ble_lbs_c_evt.evt_type = BLE_LBS_C_EVT_BUTTON_NOTIFICATION;
|
||||
ble_lbs_c_evt.conn_handle = p_ble_lbs_c->conn_handle;
|
||||
ble_lbs_c_evt.params.button.button_state = p_ble_evt->evt.gattc_evt.params.hvx.data[0];
|
||||
p_ble_lbs_c->evt_handler(p_ble_lbs_c, &ble_lbs_c_evt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling the Disconnected event received from the SoftDevice.
|
||||
*
|
||||
* @details This function checks whether the disconnect event is happening on the link
|
||||
* associated with the current instance of the module. If the event is happening, the function sets the instance's
|
||||
* conn_handle to invalid.
|
||||
*
|
||||
* @param[in] p_ble_lbs_c Pointer to the Led Button Client structure.
|
||||
* @param[in] p_ble_evt Pointer to the BLE event received.
|
||||
*/
|
||||
static void on_disconnected(ble_lbs_c_t * p_ble_lbs_c, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
if (p_ble_lbs_c->conn_handle == p_ble_evt->evt.gap_evt.conn_handle)
|
||||
{
|
||||
p_ble_lbs_c->conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
p_ble_lbs_c->peer_lbs_db.button_cccd_handle = BLE_GATT_HANDLE_INVALID;
|
||||
p_ble_lbs_c->peer_lbs_db.button_handle = BLE_GATT_HANDLE_INVALID;
|
||||
p_ble_lbs_c->peer_lbs_db.led_handle = BLE_GATT_HANDLE_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ble_lbs_on_db_disc_evt(ble_lbs_c_t * p_ble_lbs_c, ble_db_discovery_evt_t const * p_evt)
|
||||
{
|
||||
// Check if the LED Button Service was discovered.
|
||||
if (p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE &&
|
||||
p_evt->params.discovered_db.srv_uuid.uuid == LBS_UUID_SERVICE &&
|
||||
p_evt->params.discovered_db.srv_uuid.type == p_ble_lbs_c->uuid_type)
|
||||
{
|
||||
ble_lbs_c_evt_t evt;
|
||||
|
||||
evt.evt_type = BLE_LBS_C_EVT_DISCOVERY_COMPLETE;
|
||||
evt.conn_handle = p_evt->conn_handle;
|
||||
|
||||
for (uint32_t i = 0; i < p_evt->params.discovered_db.char_count; i++)
|
||||
{
|
||||
const ble_gatt_db_char_t * p_char = &(p_evt->params.discovered_db.charateristics[i]);
|
||||
switch (p_char->characteristic.uuid.uuid)
|
||||
{
|
||||
case LBS_UUID_LED_CHAR:
|
||||
evt.params.peer_db.led_handle = p_char->characteristic.handle_value;
|
||||
break;
|
||||
case LBS_UUID_BUTTON_CHAR:
|
||||
evt.params.peer_db.button_handle = p_char->characteristic.handle_value;
|
||||
evt.params.peer_db.button_cccd_handle = p_char->cccd_handle;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
NRF_LOG_DEBUG("LED Button Service discovered at peer.");
|
||||
//If the instance was assigned prior to db_discovery, assign the db_handles
|
||||
if (p_ble_lbs_c->conn_handle != BLE_CONN_HANDLE_INVALID)
|
||||
{
|
||||
if ((p_ble_lbs_c->peer_lbs_db.led_handle == BLE_GATT_HANDLE_INVALID)&&
|
||||
(p_ble_lbs_c->peer_lbs_db.button_handle == BLE_GATT_HANDLE_INVALID)&&
|
||||
(p_ble_lbs_c->peer_lbs_db.button_cccd_handle == BLE_GATT_HANDLE_INVALID))
|
||||
{
|
||||
p_ble_lbs_c->peer_lbs_db = evt.params.peer_db;
|
||||
}
|
||||
}
|
||||
|
||||
p_ble_lbs_c->evt_handler(p_ble_lbs_c, &evt);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_lbs_c_init(ble_lbs_c_t * p_ble_lbs_c, ble_lbs_c_init_t * p_ble_lbs_c_init)
|
||||
{
|
||||
uint32_t err_code;
|
||||
ble_uuid_t lbs_uuid;
|
||||
ble_uuid128_t lbs_base_uuid = {LBS_UUID_BASE};
|
||||
|
||||
VERIFY_PARAM_NOT_NULL(p_ble_lbs_c);
|
||||
VERIFY_PARAM_NOT_NULL(p_ble_lbs_c_init);
|
||||
VERIFY_PARAM_NOT_NULL(p_ble_lbs_c_init->evt_handler);
|
||||
VERIFY_PARAM_NOT_NULL(p_ble_lbs_c_init->p_gatt_queue);
|
||||
|
||||
p_ble_lbs_c->peer_lbs_db.button_cccd_handle = BLE_GATT_HANDLE_INVALID;
|
||||
p_ble_lbs_c->peer_lbs_db.button_handle = BLE_GATT_HANDLE_INVALID;
|
||||
p_ble_lbs_c->peer_lbs_db.led_handle = BLE_GATT_HANDLE_INVALID;
|
||||
p_ble_lbs_c->conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
p_ble_lbs_c->evt_handler = p_ble_lbs_c_init->evt_handler;
|
||||
p_ble_lbs_c->p_gatt_queue = p_ble_lbs_c_init->p_gatt_queue;
|
||||
p_ble_lbs_c->error_handler = p_ble_lbs_c_init->error_handler;
|
||||
|
||||
err_code = sd_ble_uuid_vs_add(&lbs_base_uuid, &p_ble_lbs_c->uuid_type);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
lbs_uuid.type = p_ble_lbs_c->uuid_type;
|
||||
lbs_uuid.uuid = LBS_UUID_SERVICE;
|
||||
|
||||
return ble_db_discovery_evt_register(&lbs_uuid);
|
||||
}
|
||||
|
||||
void ble_lbs_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
|
||||
{
|
||||
if ((p_context == NULL) || (p_ble_evt == NULL))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ble_lbs_c_t * p_ble_lbs_c = (ble_lbs_c_t *)p_context;
|
||||
|
||||
switch (p_ble_evt->header.evt_id)
|
||||
{
|
||||
case BLE_GATTC_EVT_HVX:
|
||||
on_hvx(p_ble_lbs_c, p_ble_evt);
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVT_DISCONNECTED:
|
||||
on_disconnected(p_ble_lbs_c, p_ble_evt);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for configuring the CCCD.
|
||||
*
|
||||
* @param[in] p_ble_lbs_c Pointer to the LED Button Client structure.
|
||||
* @param[in] enable Whether to enable or disable the CCCD.
|
||||
*
|
||||
* @return NRF_SUCCESS if the CCCD configure was successfully sent to the peer.
|
||||
*/
|
||||
static uint32_t cccd_configure(ble_lbs_c_t * p_ble_lbs_c, bool enable)
|
||||
{
|
||||
NRF_LOG_DEBUG("Configuring CCCD. CCCD Handle = %d, Connection Handle = %d",
|
||||
p_ble_lbs_c->peer_lbs_db.button_cccd_handle,
|
||||
p_ble_lbs_c->conn_handle);
|
||||
|
||||
nrf_ble_gq_req_t cccd_req;
|
||||
uint16_t cccd_val = enable ? BLE_GATT_HVX_NOTIFICATION : 0;
|
||||
uint8_t cccd[WRITE_MESSAGE_LENGTH];
|
||||
|
||||
cccd[0] = LSB_16(cccd_val);
|
||||
cccd[1] = MSB_16(cccd_val);
|
||||
|
||||
cccd_req.type = NRF_BLE_GQ_REQ_GATTC_WRITE;
|
||||
cccd_req.error_handler.cb = gatt_error_handler;
|
||||
cccd_req.error_handler.p_ctx = p_ble_lbs_c;
|
||||
cccd_req.params.gattc_write.handle = p_ble_lbs_c->peer_lbs_db.button_cccd_handle;
|
||||
cccd_req.params.gattc_write.len = WRITE_MESSAGE_LENGTH;
|
||||
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_ble_lbs_c->p_gatt_queue, &cccd_req, p_ble_lbs_c->conn_handle);
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_lbs_c_button_notif_enable(ble_lbs_c_t * p_ble_lbs_c)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_ble_lbs_c);
|
||||
|
||||
if (p_ble_lbs_c->conn_handle == BLE_CONN_HANDLE_INVALID)
|
||||
{
|
||||
return NRF_ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
return cccd_configure(p_ble_lbs_c,
|
||||
true);
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_lbs_led_status_send(ble_lbs_c_t * p_ble_lbs_c, uint8_t status)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_ble_lbs_c);
|
||||
|
||||
if (p_ble_lbs_c->conn_handle == BLE_CONN_HANDLE_INVALID)
|
||||
{
|
||||
return NRF_ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
NRF_LOG_DEBUG("Writing LED status 0x%x", status);
|
||||
|
||||
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 = gatt_error_handler;
|
||||
write_req.error_handler.p_ctx = p_ble_lbs_c;
|
||||
write_req.params.gattc_write.handle = p_ble_lbs_c->peer_lbs_db.led_handle;
|
||||
write_req.params.gattc_write.len = sizeof(status);
|
||||
write_req.params.gattc_write.p_value = &status;
|
||||
write_req.params.gattc_write.offset = 0;
|
||||
write_req.params.gattc_write.write_op = BLE_GATT_OP_WRITE_CMD;
|
||||
|
||||
return nrf_ble_gq_item_add(p_ble_lbs_c->p_gatt_queue, &write_req, p_ble_lbs_c->conn_handle);
|
||||
}
|
||||
|
||||
uint32_t ble_lbs_c_handles_assign(ble_lbs_c_t * p_ble_lbs_c,
|
||||
uint16_t conn_handle,
|
||||
const lbs_db_t * p_peer_handles)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_ble_lbs_c);
|
||||
|
||||
p_ble_lbs_c->conn_handle = conn_handle;
|
||||
if (p_peer_handles != NULL)
|
||||
{
|
||||
p_ble_lbs_c->peer_lbs_db = *p_peer_handles;
|
||||
}
|
||||
return nrf_ble_gq_conn_handle_register(p_ble_lbs_c->p_gatt_queue, conn_handle);
|
||||
}
|
||||
|
||||
#endif // NRF_MODULE_ENABLED(BLE_LBS_C)
|
||||
266
components/ble/ble_services/ble_lbs_c/ble_lbs_c.h
Normal file
266
components/ble/ble_services/ble_lbs_c/ble_lbs_c.h
Normal file
@@ -0,0 +1,266 @@
|
||||
/**
|
||||
* 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 ble_lbs_c LED Button Service Client
|
||||
* @{
|
||||
* @ingroup ble_sdk_srv
|
||||
* @brief The LED Button Service client can be used to set up a LED and read a button state on a
|
||||
* LED button service server.
|
||||
*
|
||||
* @details This module contains the APIs and types exposed by the LED Button Service Client
|
||||
* module. The application can use these APIs and types to perform the discovery of
|
||||
* LED Button Service at the peer and to interact with it.
|
||||
*
|
||||
* @note The application must register this module as the BLE event observer by using the
|
||||
* NRF_SDH_BLE_OBSERVER macro. Example:
|
||||
* @code
|
||||
* ble_lbs_c_t instance;
|
||||
* NRF_SDH_BLE_OBSERVER(anything, BLE_LBS_C_BLE_OBSERVER_PRIO,
|
||||
* ble_lbs_c_on_ble_evt, &instance);
|
||||
* @endcode
|
||||
*/
|
||||
|
||||
#ifndef BLE_LBS_C_H__
|
||||
#define BLE_LBS_C_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include "ble.h"
|
||||
#include "ble_db_discovery.h"
|
||||
#include "ble_srv_common.h"
|
||||
#include "nrf_ble_gq.h"
|
||||
#include "nrf_sdh_ble.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**@brief Macro for defining a ble_lbs_c instance.
|
||||
*
|
||||
* @param _name Name of the instance.
|
||||
* @hideinitializer
|
||||
*/
|
||||
#define BLE_LBS_C_DEF(_name) \
|
||||
static ble_lbs_c_t _name; \
|
||||
NRF_SDH_BLE_OBSERVER(_name ## _obs, \
|
||||
BLE_LBS_C_BLE_OBSERVER_PRIO, \
|
||||
ble_lbs_c_on_ble_evt, &_name)
|
||||
|
||||
/**@brief Macro for defining multiple ble_lbs_c instances.
|
||||
*
|
||||
* @param _name Name of the array of instances.
|
||||
* @param _cnt Number of instances to define.
|
||||
*/
|
||||
#define BLE_LBS_C_ARRAY_DEF(_name, _cnt) \
|
||||
static ble_lbs_c_t _name[_cnt]; \
|
||||
NRF_SDH_BLE_OBSERVERS(_name ## _obs, \
|
||||
BLE_LBS_C_BLE_OBSERVER_PRIO, \
|
||||
ble_lbs_c_on_ble_evt, &_name, _cnt)
|
||||
|
||||
|
||||
#define LBS_UUID_BASE {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15, \
|
||||
0xDE, 0xEF, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00}
|
||||
#define LBS_UUID_SERVICE 0x1523
|
||||
#define LBS_UUID_BUTTON_CHAR 0x1524
|
||||
#define LBS_UUID_LED_CHAR 0x1525
|
||||
|
||||
/**@brief LBS Client event type. */
|
||||
typedef enum
|
||||
{
|
||||
BLE_LBS_C_EVT_DISCOVERY_COMPLETE = 1, /**< Event indicating that the LED Button Service was discovered at the peer. */
|
||||
BLE_LBS_C_EVT_BUTTON_NOTIFICATION /**< Event indicating that a notification of the LED Button Button characteristic was received from the peer. */
|
||||
} ble_lbs_c_evt_type_t;
|
||||
|
||||
/**@brief Structure containing the Button value received from the peer. */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t button_state; /**< Button Value. */
|
||||
} ble_button_t;
|
||||
|
||||
/**@brief Structure containing the handles related to the LED Button Service found on the peer. */
|
||||
typedef struct
|
||||
{
|
||||
uint16_t button_cccd_handle; /**< Handle of the CCCD of the Button characteristic. */
|
||||
uint16_t button_handle; /**< Handle of the Button characteristic as provided by the SoftDevice. */
|
||||
uint16_t led_handle; /**< Handle of the LED characteristic as provided by the SoftDevice. */
|
||||
} lbs_db_t;
|
||||
|
||||
/**@brief LED Button Event structure. */
|
||||
typedef struct
|
||||
{
|
||||
ble_lbs_c_evt_type_t evt_type; /**< Type of the event. */
|
||||
uint16_t conn_handle; /**< Connection handle on which the event occured.*/
|
||||
union
|
||||
{
|
||||
ble_button_t button; /**< Button value received. This is filled if the evt_type is @ref BLE_LBS_C_EVT_BUTTON_NOTIFICATION. */
|
||||
lbs_db_t peer_db; /**< Handles related to the LED Button Service found on the peer device. This is filled if the evt_type is @ref BLE_LBS_C_EVT_DISCOVERY_COMPLETE.*/
|
||||
} params;
|
||||
} ble_lbs_c_evt_t;
|
||||
|
||||
// Forward declaration of the ble_lbs_c_t type.
|
||||
typedef struct ble_lbs_c_s ble_lbs_c_t;
|
||||
|
||||
/**@brief Event handler type.
|
||||
*
|
||||
* @details This is the type of the event handler that is to be provided by the application
|
||||
* of this module in order to receive events.
|
||||
*/
|
||||
typedef void (* ble_lbs_c_evt_handler_t) (ble_lbs_c_t * p_ble_lbs_c, ble_lbs_c_evt_t * p_evt);
|
||||
|
||||
/**@brief LED Button Client structure. */
|
||||
struct ble_lbs_c_s
|
||||
{
|
||||
uint16_t conn_handle; /**< Connection handle as provided by the SoftDevice. */
|
||||
lbs_db_t peer_lbs_db; /**< Handles related to LBS on the peer. */
|
||||
ble_lbs_c_evt_handler_t evt_handler; /**< Application event handler to be called when there is an event related to the LED Button service. */
|
||||
ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
|
||||
uint8_t uuid_type; /**< UUID type. */
|
||||
nrf_ble_gq_t * p_gatt_queue; /**< Pointer to the BLE GATT Queue instance. */
|
||||
};
|
||||
|
||||
/**@brief LED Button Client initialization structure. */
|
||||
typedef struct
|
||||
{
|
||||
ble_lbs_c_evt_handler_t evt_handler; /**< Event handler to be called by the LED Button Client module when there is an event related to the LED Button Service. */
|
||||
nrf_ble_gq_t * p_gatt_queue; /**< Pointer to the BLE GATT Queue instance. */
|
||||
ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
|
||||
} ble_lbs_c_init_t;
|
||||
|
||||
|
||||
/**@brief Function for initializing the LED Button client module.
|
||||
*
|
||||
* @details This function registers with the Database Discovery module for the
|
||||
* LED Button Service. The module looks for the presence of a LED Button Service instance
|
||||
* at the peer when a discovery is started.
|
||||
*
|
||||
* @param[in] p_ble_lbs_c Pointer to the LED Button client structure.
|
||||
* @param[in] p_ble_lbs_c_init Pointer to the LED Button initialization structure that contains the
|
||||
* initialization information.
|
||||
*
|
||||
* @retval NRF_SUCCESS On successful initialization.
|
||||
* @retval err_code Otherwise, this function propagates the error code returned by the Database Discovery module API
|
||||
* @ref ble_db_discovery_evt_register.
|
||||
*/
|
||||
uint32_t ble_lbs_c_init(ble_lbs_c_t * p_ble_lbs_c, ble_lbs_c_init_t * p_ble_lbs_c_init);
|
||||
|
||||
|
||||
/**@brief Function for handling BLE events from the SoftDevice.
|
||||
*
|
||||
* @details This function handles the BLE events received from the SoftDevice. If a BLE event
|
||||
* is relevant to the LED Button Client module, the function uses the event's data to update interval
|
||||
* variables and, if necessary, send events to the application.
|
||||
*
|
||||
* @param[in] p_ble_evt Pointer to the BLE event.
|
||||
* @param[in] p_context Pointer to the LED button client structure.
|
||||
*/
|
||||
void ble_lbs_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
|
||||
|
||||
|
||||
/**@brief Function for requesting the peer to start sending notification of the Button
|
||||
* Characteristic.
|
||||
*
|
||||
* @details This function enables to notification of the Button at the peer
|
||||
* by writing to the CCCD of the Button characteristic.
|
||||
*
|
||||
* @param[in] p_ble_lbs_c Pointer to the LED Button Client structure.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the SoftDevice has been requested to write to the CCCD of the peer.
|
||||
* @retval NRF_ERROR_INVALID_STATE If no connection handle has been assigned (@ref ble_lbs_c_handles_assign).
|
||||
* @retval NRF_ERROR_NULL If the given parameter is NULL.
|
||||
* @retval err_code Otherwise, this API propagates the error code returned by function
|
||||
* @ref nrf_ble_gq_item_add.
|
||||
*/
|
||||
uint32_t ble_lbs_c_button_notif_enable(ble_lbs_c_t * p_ble_lbs_c);
|
||||
|
||||
|
||||
/**@brief Function for handling events from the Database Discovery module.
|
||||
*
|
||||
* @details Call this function when you get a callback event from the Database Discovery module. This
|
||||
* function handles an event from the Database Discovery module, and determines whether it
|
||||
* relates to the discovery of LED Button service at the peer. If it does, this function calls the
|
||||
* application's event handler to indicate that the LED Button service was discovered
|
||||
* at the peer. The function also populates the event with service-related information before
|
||||
* providing it to the application.
|
||||
*
|
||||
* @param[in] p_ble_lbs_c Pointer to the LED Button client structure.
|
||||
* @param[in] p_evt Pointer to the event received from the Database Discovery module.
|
||||
*/
|
||||
void ble_lbs_on_db_disc_evt(ble_lbs_c_t * p_ble_lbs_c, const ble_db_discovery_evt_t * p_evt);
|
||||
|
||||
|
||||
/**@brief Function for assigning handles to this instance of lbs_c.
|
||||
*
|
||||
* @details Call this function when a link has been established with a peer to associate the link
|
||||
* to this instance of the module. This makes it possible to handle several links and
|
||||
* associate each link to a particular instance of this module.
|
||||
*
|
||||
* @param[in] p_ble_lbs_c Pointer to the LED Button client structure instance for associating the link.
|
||||
* @param[in] conn_handle Connection handle to associate with the given LED Button Client Instance.
|
||||
* @param[in] p_peer_handles LED Button Service handles found on the peer (from @ref BLE_LBS_C_EVT_DISCOVERY_COMPLETE event).
|
||||
*
|
||||
* @retval NRF_SUCCESS If the status was sent successfully.
|
||||
* @retval err_code Otherwise, this API propagates the error code returned by function
|
||||
* @ref nrf_ble_gq_item_add.
|
||||
*
|
||||
*/
|
||||
uint32_t ble_lbs_c_handles_assign(ble_lbs_c_t * p_ble_lbs_c,
|
||||
uint16_t conn_handle,
|
||||
const lbs_db_t * p_peer_handles);
|
||||
|
||||
|
||||
/**@brief Function for writing the LED status to the connected server.
|
||||
*
|
||||
* @param[in] p_ble_lbs_c Pointer to the LED Button client structure.
|
||||
* @param[in] status LED status to send.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the status was sent successfully.
|
||||
* @retval err_code Otherwise, this API propagates the error code returned by function
|
||||
* @ref nrf_ble_gq_conn_handle_register.
|
||||
*/
|
||||
uint32_t ble_lbs_led_status_send(ble_lbs_c_t * p_ble_lbs_c, uint8_t status);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // BLE_LBS_C_H__
|
||||
|
||||
/** @} */
|
||||
221
components/ble/ble_services/ble_lls/ble_lls.c
Normal file
221
components/ble/ble_services/ble_lls/ble_lls.c
Normal file
@@ -0,0 +1,221 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 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.
|
||||
*
|
||||
*/
|
||||
/* Attention!
|
||||
* To maintain compliance with Nordic Semiconductor ASA's Bluetooth profile
|
||||
* qualification listings, this section of source code must not be modified.
|
||||
*/
|
||||
#include "sdk_common.h"
|
||||
#if NRF_MODULE_ENABLED(BLE_LLS)
|
||||
#include "ble_lls.h"
|
||||
#include <string.h>
|
||||
#include "ble_hci.h"
|
||||
#include "ble_srv_common.h"
|
||||
|
||||
|
||||
/**@brief Function for handling the Connect event.
|
||||
*
|
||||
* @param[in] p_lls Link Loss Service structure.
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
*/
|
||||
static void on_connect(ble_lls_t * p_lls, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
// Link reconnected, notify application with a no_alert event
|
||||
ble_lls_evt_t evt;
|
||||
|
||||
p_lls->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
|
||||
|
||||
evt.evt_type = BLE_LLS_EVT_LINK_LOSS_ALERT;
|
||||
evt.params.alert_level = BLE_CHAR_ALERT_LEVEL_NO_ALERT;
|
||||
p_lls->evt_handler(p_lls, &evt);
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling the Disconnect event.
|
||||
*
|
||||
* @param[in] p_lls Link Loss Service structure.
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
*/
|
||||
static void on_disconnect(ble_lls_t * p_lls, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
uint8_t reason = p_ble_evt->evt.gap_evt.params.disconnected.reason;
|
||||
|
||||
if (reason == BLE_HCI_CONNECTION_TIMEOUT)
|
||||
{
|
||||
// Link loss detected, notify application
|
||||
uint32_t err_code;
|
||||
ble_lls_evt_t evt;
|
||||
|
||||
evt.evt_type = BLE_LLS_EVT_LINK_LOSS_ALERT;
|
||||
|
||||
err_code = ble_lls_alert_level_get(p_lls, &evt.params.alert_level);
|
||||
if (err_code == NRF_SUCCESS)
|
||||
{
|
||||
p_lls->evt_handler(p_lls, &evt);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (p_lls->error_handler != NULL)
|
||||
{
|
||||
p_lls->error_handler(err_code);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling the Authentication Status event.
|
||||
*
|
||||
* @param[in] p_lls Link Loss Service structure.
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
*/
|
||||
static void on_auth_status(ble_lls_t * p_lls, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
if (p_ble_evt->evt.gap_evt.params.auth_status.auth_status == BLE_GAP_SEC_STATUS_SUCCESS)
|
||||
{
|
||||
ble_lls_evt_t evt;
|
||||
|
||||
evt.evt_type = BLE_LLS_EVT_LINK_LOSS_ALERT;
|
||||
evt.params.alert_level = BLE_CHAR_ALERT_LEVEL_NO_ALERT;
|
||||
|
||||
p_lls->evt_handler(p_lls, &evt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ble_lls_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
|
||||
{
|
||||
ble_lls_t * p_lls = (ble_lls_t *)p_context;
|
||||
|
||||
if (p_lls == NULL || p_ble_evt == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch (p_ble_evt->header.evt_id)
|
||||
{
|
||||
case BLE_GAP_EVT_CONNECTED:
|
||||
on_connect(p_lls, p_ble_evt);
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVT_DISCONNECTED:
|
||||
on_disconnect(p_lls, p_ble_evt);
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVT_AUTH_STATUS:
|
||||
on_auth_status(p_lls, p_ble_evt);
|
||||
break;
|
||||
|
||||
default:
|
||||
// No implementation needed.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_lls_init(ble_lls_t * p_lls, const ble_lls_init_t * p_lls_init)
|
||||
{
|
||||
uint32_t err_code;
|
||||
ble_uuid_t ble_uuid;
|
||||
ble_add_char_params_t add_char_params;
|
||||
|
||||
if (p_lls == NULL || p_lls_init == NULL)
|
||||
{
|
||||
return NRF_ERROR_NULL;
|
||||
}
|
||||
|
||||
if (p_lls_init->evt_handler == NULL)
|
||||
{
|
||||
return NRF_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
// Initialize service structure
|
||||
p_lls->evt_handler = p_lls_init->evt_handler;
|
||||
p_lls->error_handler = p_lls_init->error_handler;
|
||||
|
||||
// Add service
|
||||
BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_LINK_LOSS_SERVICE);
|
||||
|
||||
err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
|
||||
&ble_uuid,
|
||||
&p_lls->service_handle);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
|
||||
// Add alert level characteristic
|
||||
memset(&add_char_params, 0, sizeof(add_char_params));
|
||||
|
||||
add_char_params.uuid = BLE_UUID_ALERT_LEVEL_CHAR;
|
||||
add_char_params.max_len = sizeof(uint8_t);
|
||||
add_char_params.char_props.read = 1;
|
||||
add_char_params.char_props.write = 1;
|
||||
add_char_params.write_access = p_lls_init->alert_level_wr_sec;
|
||||
add_char_params.read_access = p_lls_init->alert_level_rd_sec;
|
||||
add_char_params.init_len = sizeof(uint8_t);
|
||||
add_char_params.p_init_value = (uint8_t *) &(p_lls_init->initial_alert_level);
|
||||
|
||||
return characteristic_add(p_lls->service_handle,
|
||||
&add_char_params,
|
||||
&p_lls->alert_level_handles);
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_lls_alert_level_get(ble_lls_t * p_lls, uint8_t * p_alert_level)
|
||||
{
|
||||
ble_gatts_value_t gatts_value;
|
||||
|
||||
if (p_lls == NULL || p_alert_level == NULL)
|
||||
{
|
||||
return NRF_ERROR_NULL;
|
||||
}
|
||||
|
||||
// Initialize value struct.
|
||||
memset(&gatts_value, 0, sizeof(gatts_value));
|
||||
|
||||
gatts_value.len = sizeof(uint8_t);
|
||||
gatts_value.offset = 0;
|
||||
gatts_value.p_value = p_alert_level;
|
||||
|
||||
return sd_ble_gatts_value_get(p_lls->conn_handle,
|
||||
p_lls->alert_level_handles.value_handle,
|
||||
&gatts_value);
|
||||
}
|
||||
#endif // NRF_MODULE_ENABLED(BLE_LLS)
|
||||
176
components/ble/ble_services/ble_lls/ble_lls.h
Normal file
176
components/ble/ble_services/ble_lls/ble_lls.h
Normal file
@@ -0,0 +1,176 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 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 ble_lls Link Loss Service
|
||||
* @{
|
||||
* @ingroup ble_sdk_srv
|
||||
* @brief Link Loss Service module.
|
||||
*
|
||||
* @details This module implements the Link Loss Service with the Alert Level characteristic.
|
||||
* During initialization it adds the Link Loss Service and Alert Level characteristic
|
||||
* to the BLE stack database.
|
||||
*
|
||||
* The application must supply an event handler for receiving Link Loss Service
|
||||
* events. Using this handler, the service will notify the application when the
|
||||
* link has been lost, and which Alert Level has been set.
|
||||
*
|
||||
* The service also provides a function for letting the application poll the current
|
||||
* value of the Alert Level characteristic.
|
||||
*
|
||||
* @note The application must register this module as BLE event observer using the
|
||||
* NRF_SDH_BLE_OBSERVER macro. Example:
|
||||
* @code
|
||||
* ble_lls_t instance;
|
||||
* NRF_SDH_BLE_OBSERVER(anything, BLE_LLS_BLE_OBSERVER_PRIO,
|
||||
* ble_lls_on_ble_evt, &instance);
|
||||
* @endcode
|
||||
*
|
||||
* @note Attention!
|
||||
* To maintain compliance with Nordic Semiconductor ASA Bluetooth profile
|
||||
* qualification listings, this section of source code must not be modified.
|
||||
*/
|
||||
|
||||
#ifndef BLE_LLS_H__
|
||||
#define BLE_LLS_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include "ble.h"
|
||||
#include "ble_srv_common.h"
|
||||
#include "nrf_sdh_ble.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**@brief Macro for defining a ble_lls instance.
|
||||
*
|
||||
* @param _name Name of the instance.
|
||||
* @hideinitializer
|
||||
*/
|
||||
#define BLE_LLS_DEF(_name) \
|
||||
static ble_lls_t _name; \
|
||||
NRF_SDH_BLE_OBSERVER(_name ## _obs, \
|
||||
BLE_LLS_BLE_OBSERVER_PRIO, \
|
||||
ble_lls_on_ble_evt, &_name)
|
||||
|
||||
|
||||
/**@brief Link Loss Service event type. */
|
||||
typedef enum
|
||||
{
|
||||
BLE_LLS_EVT_LINK_LOSS_ALERT /**< Alert Level Updated event. */
|
||||
} ble_lls_evt_type_t;
|
||||
|
||||
/**@brief Link Loss Service event. */
|
||||
typedef struct
|
||||
{
|
||||
ble_lls_evt_type_t evt_type; /**< Type of event. */
|
||||
union
|
||||
{
|
||||
uint8_t alert_level; /**< New Alert Level value. */
|
||||
} params;
|
||||
} ble_lls_evt_t;
|
||||
|
||||
// Forward declaration of the ble_lls_t type.
|
||||
typedef struct ble_lls_s ble_lls_t;
|
||||
|
||||
/**@brief Link Loss Service event handler type. */
|
||||
typedef void (*ble_lls_evt_handler_t) (ble_lls_t * p_lls, ble_lls_evt_t * p_evt);
|
||||
|
||||
/**@brief Link Loss Service init structure. This contains all options and data needed for initialization of the service. */
|
||||
typedef struct
|
||||
{
|
||||
ble_lls_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Link Loss Service. */
|
||||
ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
|
||||
uint8_t initial_alert_level; /**< Initial value of the Alert Level characteristic. */
|
||||
security_req_t alert_level_rd_sec; /**< Security requirement for reading Alert Level characteristic. */
|
||||
security_req_t alert_level_wr_sec; /**< Security requirement for writing Alert Level characteristic. */
|
||||
} ble_lls_init_t;
|
||||
|
||||
/**@brief Link Loss Service structure. This contains various status information for the service. */
|
||||
struct ble_lls_s
|
||||
{
|
||||
ble_lls_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Link Loss Service. */
|
||||
ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
|
||||
uint16_t service_handle; /**< Handle of Link Loss Service (as provided by the BLE stack). */
|
||||
ble_gatts_char_handles_t alert_level_handles; /**< Handles related to the Alert Level characteristic. */
|
||||
uint16_t conn_handle; /**< Handle of the current connection (as provided by the BLE stack, is BLE_CONN_HANDLE_INVALID if not in a connection). */
|
||||
};
|
||||
|
||||
|
||||
/**@brief Function for initializing the Link Loss Service.
|
||||
*
|
||||
* @param[out] p_lls Link Loss Service structure. This structure will have to be supplied by
|
||||
* the application. It will be initialized by this function, and will later
|
||||
* be used to identify this particular service instance.
|
||||
* @param[in] p_lls_init Information needed to initialize the service.
|
||||
*
|
||||
* @return NRF_SUCCESS on successful initialization of service, otherwise an error code.
|
||||
*/
|
||||
uint32_t ble_lls_init(ble_lls_t * p_lls, const ble_lls_init_t * p_lls_init);
|
||||
|
||||
|
||||
/**@brief Function for handling the Application's BLE Stack events.
|
||||
*
|
||||
* @details Handles all events from the BLE stack of interest to the Link Loss Service.
|
||||
*
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
* @param[in] p_context Link Loss Service structure.
|
||||
*/
|
||||
void ble_lls_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
|
||||
|
||||
|
||||
/**@brief Function for getting current value of the Alert Level characteristic.
|
||||
*
|
||||
* @param[in] p_lls Link Loss Service structure.
|
||||
* @param[out] p_alert_level Current Alert Level value.
|
||||
*
|
||||
* @return NRF_SUCCESS on success, otherwise an error code.
|
||||
*/
|
||||
uint32_t ble_lls_alert_level_get(ble_lls_t * p_lls, uint8_t * p_alert_level);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // BLE_LLS_H__
|
||||
|
||||
/** @} */
|
||||
235
components/ble/ble_services/ble_nus/ble_nus.c
Normal file
235
components/ble/ble_services/ble_nus/ble_nus.c
Normal file
@@ -0,0 +1,235 @@
|
||||
/****************************************Copyright (c)************************************************
|
||||
**
|
||||
**--------------File Info-----------------------------------------------------------------------------
|
||||
** File name:ble_nus.c
|
||||
** Last modified Date:
|
||||
** Last Version:
|
||||
** Descriptions :串口透传服务文件
|
||||
**---------------------------------------------------------------------------------------------------*/
|
||||
#include "sdk_common.h"
|
||||
//这里设置了串口透传服务程序模块的“编译开关”,所以要在sdk_config.h中启用BLE_NUS
|
||||
#if NRF_MODULE_ENABLED(BLE_NUS)
|
||||
#include "ble.h"
|
||||
#include "ble_nus.h"
|
||||
#include "ble_srv_common.h"
|
||||
#include "nrf_log.h"
|
||||
|
||||
#if 0
|
||||
#define NRF_LOG_MODULE_NAME ble_nus
|
||||
#if BLE_NUS_CONFIG_LOG_ENABLED
|
||||
#define NRF_LOG_LEVEL BLE_NUS_CONFIG_LOG_LEVEL
|
||||
#define NRF_LOG_INFO_COLOR BLE_NUS_CONFIG_INFO_COLOR
|
||||
#define NRF_LOG_DEBUG_COLOR BLE_NUS_CONFIG_DEBUG_COLOR
|
||||
#else // BLE_NUS_CONFIG_LOG_ENABLED
|
||||
#define NRF_LOG_LEVEL 0
|
||||
#endif // BLE_NUS_CONFIG_LOG_ENABLED
|
||||
|
||||
NRF_LOG_MODULE_REGISTER();
|
||||
#endif
|
||||
|
||||
#define BLE_NUS_MAX_RX_CHAR_LEN BLE_NUS_MAX_DATA_LEN //RX特征最大长度(字节数)
|
||||
#define BLE_NUS_MAX_TX_CHAR_LEN BLE_NUS_MAX_DATA_LEN //TX特征最大长度(字节数)
|
||||
|
||||
//SoftDevice提交的“Write”事件处理函数
|
||||
static void on_write(ble_nus_t * p_nus, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
//定义一个串口透传事件结构体变量,用于执行回调时传递参数
|
||||
ble_nus_evt_t evt;
|
||||
//定义write事件结构体指针并指向GATT事件的write
|
||||
ble_gatts_evt_write_t const * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
|
||||
|
||||
//清空evt结构体
|
||||
memset(&evt, 0, sizeof(ble_nus_evt_t));
|
||||
//指向串口透传实例
|
||||
evt.p_nus = p_nus;
|
||||
//设置连接句柄
|
||||
evt.conn_handle = p_ble_evt->evt.gatts_evt.conn_handle;
|
||||
//写RX特征值
|
||||
if ((p_evt_write->handle == p_nus->rx_handles.value_handle) &&
|
||||
(p_nus->data_handler != NULL))
|
||||
{
|
||||
//设置事件类型
|
||||
evt.type = BLE_NUS_EVT_RX_DATA;
|
||||
//设置数据
|
||||
evt.params.rx_data.p_data = p_evt_write->data;
|
||||
//设置数据长度
|
||||
evt.params.rx_data.length = p_evt_write->len;
|
||||
//执行回调
|
||||
p_nus->data_handler(&evt);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Do Nothing. This event is not relevant for this service.
|
||||
}
|
||||
}
|
||||
|
||||
//SoftDevice提交的“BLE_GATTS_EVT_HVN_TX_COMPLETE”事件处理函数
|
||||
static void on_hvx_tx_complete(ble_nus_t * p_nus, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
//定义一个串口透传事件结构体变量evt,用于执行回调时传递参数
|
||||
ble_nus_evt_t evt;
|
||||
//清零evt
|
||||
memset(&evt, 0, sizeof(ble_nus_evt_t));
|
||||
//设置事件类型
|
||||
evt.type = BLE_NUS_EVT_TX_RDY;
|
||||
//指向串口透传服务实例
|
||||
evt.p_nus = p_nus;
|
||||
//设置连接句柄
|
||||
evt.conn_handle = p_ble_evt->evt.gatts_evt.conn_handle;
|
||||
//执行回调
|
||||
p_nus->data_handler(&evt);
|
||||
}
|
||||
|
||||
|
||||
//串口透传服务BLE事件监视者的事件回调函数
|
||||
void ble_nus_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
|
||||
{
|
||||
//检查参数是否有效
|
||||
if ((p_context == NULL) || (p_ble_evt == NULL))
|
||||
{
|
||||
return;
|
||||
}
|
||||
//定义一个串口透传结构体指针并指向串口透传结构体
|
||||
ble_nus_t * p_nus = (ble_nus_t *)p_context;
|
||||
//判断事件类型
|
||||
switch (p_ble_evt->header.evt_id)
|
||||
{
|
||||
//写事件
|
||||
case BLE_GATTS_EVT_WRITE:
|
||||
on_write(p_nus, p_ble_evt);
|
||||
break;
|
||||
//TX就绪事件
|
||||
case BLE_GATTS_EVT_HVN_TX_COMPLETE:
|
||||
on_hvx_tx_complete(p_nus, p_ble_evt);
|
||||
break;
|
||||
|
||||
default:
|
||||
// No implementation needed.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//初始化串口透传服务
|
||||
uint32_t ble_nus_init(ble_nus_t * p_nus, ble_nus_init_t const * p_nus_init)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
//定义16位UUID结构体变量
|
||||
ble_uuid_t ble_uuid;
|
||||
//定义128位UUID结构体变量,并初始化为串口透传服务UUID基数
|
||||
ble_uuid128_t nus_base_uuid = NUS_BASE_UUID;
|
||||
//定义特征参数结构体变量
|
||||
ble_add_char_params_t add_char_params;
|
||||
//检查指针是否为NULL
|
||||
VERIFY_PARAM_NOT_NULL(p_nus);
|
||||
VERIFY_PARAM_NOT_NULL(p_nus_init);
|
||||
|
||||
//拷贝串口透传服务初始化结构体中的事件句柄
|
||||
p_nus->data_handler = p_nus_init->data_handler;
|
||||
|
||||
//将自定义UUID基数添加到SoftDevice
|
||||
err_code = sd_ble_uuid_vs_add(&nus_base_uuid, &p_nus->uuid_type);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
//UUID类型和数值赋值给ble_uuid变量
|
||||
ble_uuid.type = BLE_UUID_TYPE_BLE;
|
||||
ble_uuid.uuid = BLE_UUID_NUS_SERVICE;
|
||||
|
||||
//添加串口透传服务
|
||||
err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
|
||||
&ble_uuid,
|
||||
&p_nus->service_handle);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
/*---------------------以下代码添加RX特征--------------------*/
|
||||
//添加RX特征
|
||||
//配置参数之前先清零add_char_params
|
||||
memset(&add_char_params, 0, sizeof(add_char_params));
|
||||
//RX特征的UUID
|
||||
add_char_params.uuid = BLE_UUID_NUS_RX_CHARACTERISTIC;
|
||||
//RX特征的UUID类型
|
||||
add_char_params.uuid_type = p_nus->uuid_type;
|
||||
//设置RX特征值的最大长度
|
||||
add_char_params.max_len = BLE_NUS_MAX_RX_CHAR_LEN;
|
||||
//设置RX特征值的初始长度
|
||||
add_char_params.init_len = sizeof(uint8_t);
|
||||
//设置RX的特征值长度为可变长度
|
||||
add_char_params.is_var_len = true;
|
||||
//设置RX特征的性质支持写
|
||||
add_char_params.char_props.write = 1;
|
||||
//设置RX特性的性质支持读
|
||||
add_char_params.char_props.read = 1;
|
||||
//设置RX特征的性质支持无响应写
|
||||
add_char_params.char_props.write_wo_resp = 1;
|
||||
//设置读/写RX特征值的安全需求:无安全性
|
||||
add_char_params.read_access = SEC_OPEN;
|
||||
add_char_params.write_access = SEC_OPEN;
|
||||
//为串口透传服务添加RX特征
|
||||
err_code = characteristic_add(p_nus->service_handle, &add_char_params, &p_nus->rx_handles);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
/*---------------------添加RX特征-END------------------------*/
|
||||
|
||||
/*---------------------以下代码添加TX特征--------------------*/
|
||||
//添加TX特征
|
||||
//配置参数之前先清零add_char_params
|
||||
memset(&add_char_params, 0, sizeof(add_char_params));
|
||||
//TX特征的UUID
|
||||
add_char_params.uuid = BLE_UUID_NUS_TX_CHARACTERISTIC;
|
||||
//TX特征的UUID类型
|
||||
add_char_params.uuid_type = p_nus->uuid_type;
|
||||
//设置TX特征值的最大长度
|
||||
add_char_params.max_len = BLE_NUS_MAX_TX_CHAR_LEN;
|
||||
//设置TX特征值的初始长度
|
||||
add_char_params.init_len = sizeof(uint8_t);
|
||||
//设置TX的特征值长度为可变长度
|
||||
add_char_params.is_var_len = true;
|
||||
//设置TX特征的性质:支持通知
|
||||
add_char_params.char_props.notify = 1;
|
||||
//设置TX特性的性质:支持读
|
||||
add_char_params.char_props.read = 1;
|
||||
//设置读/写RX特征值的安全需求:无安全性
|
||||
add_char_params.read_access = SEC_OPEN;
|
||||
add_char_params.write_access = SEC_OPEN;
|
||||
add_char_params.cccd_write_access = SEC_OPEN;
|
||||
//为串口透传服务添加TX特征
|
||||
return characteristic_add(p_nus->service_handle, &add_char_params, &p_nus->tx_handles);
|
||||
/*---------------------添加TX特征-END------------------------*/
|
||||
}
|
||||
|
||||
//蓝牙数据上传发送,并进行反馈
|
||||
uint32_t ble_nus_data_send(ble_nus_t * p_nus,
|
||||
uint8_t * p_data,
|
||||
uint16_t * p_length,
|
||||
uint16_t conn_handle)
|
||||
{
|
||||
ble_gatts_hvx_params_t hvx_params;
|
||||
//验证p_uarts没有指向NULL
|
||||
VERIFY_PARAM_NOT_NULL(p_nus);
|
||||
|
||||
//如果连接句柄无效,表示没有和主机建立连接,返回NRF_ERROR_NOT_FOUND
|
||||
if (conn_handle == BLE_CONN_HANDLE_INVALID)
|
||||
{
|
||||
return NRF_ERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (*p_length > BLE_NUS_MAX_DATA_LEN)
|
||||
{
|
||||
return NRF_ERROR_INVALID_PARAM;
|
||||
}
|
||||
//设置之前先清零hvx_params
|
||||
memset(&hvx_params, 0, sizeof(hvx_params));
|
||||
//TX特征值句柄
|
||||
hvx_params.handle = p_nus->tx_handles.value_handle;
|
||||
//发送的数据
|
||||
hvx_params.p_data = p_data;
|
||||
//发送的数据长度
|
||||
hvx_params.p_len = p_length;
|
||||
//类型为通知
|
||||
hvx_params.type = BLE_GATT_HVX_NOTIFICATION;
|
||||
//发送TX特征值通知
|
||||
return sd_ble_gatts_hvx(conn_handle, &hvx_params);
|
||||
}
|
||||
|
||||
|
||||
#endif // NRF_MODULE_ENABLED(BLE_NUS)
|
||||
165
components/ble/ble_services/ble_nus/ble_nus.h
Normal file
165
components/ble/ble_services/ble_nus/ble_nus.h
Normal file
@@ -0,0 +1,165 @@
|
||||
#ifndef BLE_NUS_H__
|
||||
#define BLE_NUS_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "sdk_config.h"
|
||||
#include "ble.h"
|
||||
#include "ble_srv_common.h"
|
||||
#include "nrf_sdh_ble.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//定义串口透传服务实例,该实例完成2件事情
|
||||
//1:定义了static类型串口透传服务结构体变量,为串口透传服务结构体分配了内存
|
||||
//2:注册了BLE事件监视者,这使得串口透传程序模块可以接收BLE协议栈的事件,从而可以在ble_uarts_on_ble_evt()事件回调函数中处理自己感兴趣的事件
|
||||
#define BLE_NUS_DEF(_name) \
|
||||
static ble_nus_t _name; \
|
||||
NRF_SDH_BLE_OBSERVER(_name ## _obs, \
|
||||
BLE_NUS_BLE_OBSERVER_PRIO, \
|
||||
ble_nus_on_ble_evt, \
|
||||
&_name)
|
||||
|
||||
//定义串口透传服务128位UUID基数
|
||||
#define NUS_BASE_UUID {{0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}
|
||||
//定义串口透传服务16位UUID
|
||||
#define BLE_UUID_NUS_SERVICE 0x1000 //串口透传服务16位UUID
|
||||
#define BLE_UUID_NUS_TX_CHARACTERISTIC 0x1002 //TX特征16位UUID
|
||||
#define BLE_UUID_NUS_RX_CHARACTERISTIC 0x1001 //RX特征16位UUID
|
||||
|
||||
//定义操作码长度
|
||||
#define OPCODE_LENGTH 1
|
||||
//定义句柄长度
|
||||
#define HANDLE_LENGTH 2
|
||||
|
||||
//定义最大传输数据长度(字节数)
|
||||
#if defined(NRF_SDH_BLE_GATT_MAX_MTU_SIZE) && (NRF_SDH_BLE_GATT_MAX_MTU_SIZE != 0)
|
||||
#define BLE_NUS_MAX_DATA_LEN (NRF_SDH_BLE_GATT_MAX_MTU_SIZE - OPCODE_LENGTH - HANDLE_LENGTH)
|
||||
#else
|
||||
#define BLE_NUS_MAX_DATA_LEN (BLE_GATT_MTU_SIZE_DEFAULT - OPCODE_LENGTH - HANDLE_LENGTH)
|
||||
#warning NRF_SDH_BLE_GATT_MAX_MTU_SIZE is not defined.
|
||||
#endif
|
||||
|
||||
|
||||
//定义串口透传事件类型,这是用户自己定义的,供应用程序使用
|
||||
typedef enum
|
||||
{
|
||||
BLE_NUS_EVT_RX_DATA, //接收到新的数据
|
||||
BLE_NUS_EVT_TX_RDY, //准备就绪,可以发送新数据
|
||||
BLE_NUS_EVT_COMM_STARTED, /**< Notification has been enabled. */
|
||||
BLE_NUS_EVT_COMM_STOPPED, /**< Notification has been disabled. */
|
||||
} ble_nus_evt_type_t;
|
||||
|
||||
|
||||
/* Forward declaration of the ble_nus_t type. */
|
||||
typedef struct ble_nus_s ble_nus_t;
|
||||
|
||||
|
||||
//串口透传服务BLE_NUS_EVT_RX_DATA事件数据结构体,该结构体用于当BLE_NUS_EVT_RX_DATA产生时将接收的数据信息传递给处理函数
|
||||
typedef struct
|
||||
{
|
||||
uint8_t const * p_data; //指向存放接收数据的缓存
|
||||
uint16_t length; //接收的数据长度
|
||||
} ble_nus_evt_rx_data_t;
|
||||
|
||||
|
||||
/**@brief Nordic UART Service client context structure.
|
||||
*
|
||||
* @details This structure contains state context related to hosts.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
bool is_notification_enabled; /**< Variable to indicate if the peer has enabled notification of the RX characteristic.*/
|
||||
} ble_nus_client_context_t;
|
||||
|
||||
|
||||
//串口透传服务事件结构体
|
||||
typedef struct
|
||||
{
|
||||
ble_nus_evt_type_t type; //事件类型
|
||||
ble_nus_t * p_nus; //指向串口透传实例的指针
|
||||
uint16_t conn_handle; //连接句柄
|
||||
// ble_nus_client_context_t * p_link_ctx; /**< A pointer to the link context. */
|
||||
union
|
||||
{
|
||||
ble_nus_evt_rx_data_t rx_data; //BLE_NUS_EVT_RX_DATA事件数据
|
||||
} params;
|
||||
} ble_nus_evt_t;
|
||||
|
||||
|
||||
//定义函数指针类型ble_uarts_data_handler_t
|
||||
typedef void (* ble_nus_data_handler_t) (ble_nus_evt_t * p_evt);
|
||||
|
||||
|
||||
//串口服务初始化结构体
|
||||
typedef struct
|
||||
{
|
||||
ble_nus_data_handler_t data_handler; //处理接收数据的事件句柄
|
||||
} ble_nus_init_t;
|
||||
|
||||
|
||||
//串口透传服务结构体,包含所需要的信息
|
||||
struct ble_nus_s
|
||||
{
|
||||
uint8_t uuid_type; //UUID类型
|
||||
uint16_t service_handle; //串口透传服务句柄(由协议栈提供)
|
||||
ble_gatts_char_handles_t tx_handles; //TX特征句柄
|
||||
ble_gatts_char_handles_t rx_handles; //RX特征句柄
|
||||
// blcm_link_ctx_storage_t * const p_link_ctx_storage; /**< Pointer to link context storage with handles of all current connections and its context. */
|
||||
ble_nus_data_handler_t data_handler; //处理接收数据的事件句柄
|
||||
};
|
||||
|
||||
|
||||
/**@brief Function for initializing the Nordic UART Service.
|
||||
*
|
||||
* @param[out] p_nus Nordic UART 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_nus_init Information needed to initialize the service.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the service was successfully initialized. Otherwise, an error code is returned.
|
||||
* @retval NRF_ERROR_NULL If either of the pointers p_nus or p_nus_init is NULL.
|
||||
*/
|
||||
uint32_t ble_nus_init(ble_nus_t * p_nus, ble_nus_init_t const * p_nus_init);
|
||||
|
||||
|
||||
/**@brief Function for handling the Nordic UART Service's BLE events.
|
||||
*
|
||||
* @details The Nordic UART Service expects the application to call this function each time an
|
||||
* event is received from the SoftDevice. This function processes the event if it
|
||||
* is relevant and calls the Nordic UART Service event handler of the
|
||||
* application if necessary.
|
||||
*
|
||||
* @param[in] p_ble_evt Event received from the SoftDevice.
|
||||
* @param[in] p_context Nordic UART Service structure.
|
||||
*/
|
||||
void ble_nus_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
|
||||
|
||||
|
||||
/**@brief Function for sending a data to the peer.
|
||||
*
|
||||
* @details This function sends the input string as an RX characteristic notification to the
|
||||
* peer.
|
||||
*
|
||||
* @param[in] p_nus Pointer to the Nordic UART Service structure.
|
||||
* @param[in] p_data String to be sent.
|
||||
* @param[in,out] p_length Pointer Length of the string. Amount of sent bytes.
|
||||
* @param[in] conn_handle Connection Handle of the destination client.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the string was sent successfully. Otherwise, an error code is returned.
|
||||
*/
|
||||
uint32_t ble_nus_data_send(ble_nus_t * p_nus,
|
||||
uint8_t * p_data,
|
||||
uint16_t * p_length,
|
||||
uint16_t conn_handle);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // BLE_NUS_H__
|
||||
|
||||
/** @} */
|
||||
297
components/ble/ble_services/ble_nus_c/ble_nus_c.c
Normal file
297
components/ble/ble_services/ble_nus_c/ble_nus_c.c
Normal file
@@ -0,0 +1,297 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 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_NUS_C)
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "ble.h"
|
||||
#include "ble_nus_c.h"
|
||||
#include "ble_gattc.h"
|
||||
#include "ble_srv_common.h"
|
||||
#include "app_error.h"
|
||||
|
||||
#define NRF_LOG_MODULE_NAME ble_nus_c
|
||||
#include "nrf_log.h"
|
||||
NRF_LOG_MODULE_REGISTER();
|
||||
|
||||
|
||||
/**@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)
|
||||
{
|
||||
ble_nus_c_t * p_ble_nus_c = (ble_nus_c_t *)p_ctx;
|
||||
|
||||
NRF_LOG_DEBUG("A GATT Client error has occurred on conn_handle: 0X%X", conn_handle);
|
||||
|
||||
if (p_ble_nus_c->error_handler != NULL)
|
||||
{
|
||||
p_ble_nus_c->error_handler(nrf_error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ble_nus_c_on_db_disc_evt(ble_nus_c_t * p_ble_nus_c, ble_db_discovery_evt_t * p_evt)
|
||||
{
|
||||
ble_nus_c_evt_t nus_c_evt;
|
||||
memset(&nus_c_evt,0,sizeof(ble_nus_c_evt_t));
|
||||
|
||||
ble_gatt_db_char_t * p_chars = p_evt->params.discovered_db.charateristics;
|
||||
|
||||
// Check if the NUS was discovered.
|
||||
if ( (p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE)
|
||||
&& (p_evt->params.discovered_db.srv_uuid.uuid == BLE_UUID_NUS_SERVICE)
|
||||
&& (p_evt->params.discovered_db.srv_uuid.type == p_ble_nus_c->uuid_type))
|
||||
{
|
||||
for (uint32_t i = 0; i < p_evt->params.discovered_db.char_count; i++)
|
||||
{
|
||||
switch (p_chars[i].characteristic.uuid.uuid)
|
||||
{
|
||||
case BLE_UUID_NUS_RX_CHARACTERISTIC:
|
||||
nus_c_evt.handles.nus_rx_handle = p_chars[i].characteristic.handle_value;
|
||||
break;
|
||||
|
||||
case BLE_UUID_NUS_TX_CHARACTERISTIC:
|
||||
nus_c_evt.handles.nus_tx_handle = p_chars[i].characteristic.handle_value;
|
||||
nus_c_evt.handles.nus_tx_cccd_handle = p_chars[i].cccd_handle;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (p_ble_nus_c->evt_handler != NULL)
|
||||
{
|
||||
nus_c_evt.conn_handle = p_evt->conn_handle;
|
||||
nus_c_evt.evt_type = BLE_NUS_C_EVT_DISCOVERY_COMPLETE;
|
||||
p_ble_nus_c->evt_handler(p_ble_nus_c, &nus_c_evt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**@brief Function for handling Handle Value Notification received from the SoftDevice.
|
||||
*
|
||||
* @details This function uses the Handle Value Notification received from the SoftDevice
|
||||
* and checks if it is a notification of the NUS TX characteristic from the peer.
|
||||
* If it is, this function decodes the data and sends it to the application.
|
||||
*
|
||||
* @param[in] p_ble_nus_c Pointer to the NUS Client structure.
|
||||
* @param[in] p_ble_evt Pointer to the BLE event received.
|
||||
*/
|
||||
static void on_hvx(ble_nus_c_t * p_ble_nus_c, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
// HVX can only occur from client sending.
|
||||
if ( (p_ble_nus_c->handles.nus_tx_handle != BLE_GATT_HANDLE_INVALID)
|
||||
&& (p_ble_evt->evt.gattc_evt.params.hvx.handle == p_ble_nus_c->handles.nus_tx_handle)
|
||||
&& (p_ble_nus_c->evt_handler != NULL))
|
||||
{
|
||||
ble_nus_c_evt_t ble_nus_c_evt;
|
||||
|
||||
ble_nus_c_evt.evt_type = BLE_NUS_C_EVT_NUS_TX_EVT;
|
||||
ble_nus_c_evt.p_data = (uint8_t *)p_ble_evt->evt.gattc_evt.params.hvx.data;
|
||||
ble_nus_c_evt.data_len = p_ble_evt->evt.gattc_evt.params.hvx.len;
|
||||
|
||||
p_ble_nus_c->evt_handler(p_ble_nus_c, &ble_nus_c_evt);
|
||||
NRF_LOG_DEBUG("Client sending data.");
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t ble_nus_c_init(ble_nus_c_t * p_ble_nus_c, ble_nus_c_init_t * p_ble_nus_c_init)
|
||||
{
|
||||
uint32_t err_code;
|
||||
ble_uuid_t uart_uuid;
|
||||
ble_uuid128_t nus_base_uuid = NUS_BASE_UUID;
|
||||
|
||||
VERIFY_PARAM_NOT_NULL(p_ble_nus_c);
|
||||
VERIFY_PARAM_NOT_NULL(p_ble_nus_c_init);
|
||||
VERIFY_PARAM_NOT_NULL(p_ble_nus_c_init->p_gatt_queue);
|
||||
|
||||
err_code = sd_ble_uuid_vs_add(&nus_base_uuid, &p_ble_nus_c->uuid_type);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
uart_uuid.type = p_ble_nus_c->uuid_type;
|
||||
uart_uuid.uuid = BLE_UUID_NUS_SERVICE;
|
||||
|
||||
p_ble_nus_c->conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
p_ble_nus_c->evt_handler = p_ble_nus_c_init->evt_handler;
|
||||
p_ble_nus_c->error_handler = p_ble_nus_c_init->error_handler;
|
||||
p_ble_nus_c->handles.nus_tx_handle = BLE_GATT_HANDLE_INVALID;
|
||||
p_ble_nus_c->handles.nus_rx_handle = BLE_GATT_HANDLE_INVALID;
|
||||
p_ble_nus_c->p_gatt_queue = p_ble_nus_c_init->p_gatt_queue;
|
||||
|
||||
return ble_db_discovery_evt_register(&uart_uuid);
|
||||
}
|
||||
|
||||
void ble_nus_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
|
||||
{
|
||||
ble_nus_c_t * p_ble_nus_c = (ble_nus_c_t *)p_context;
|
||||
|
||||
if ((p_ble_nus_c == NULL) || (p_ble_evt == NULL))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( (p_ble_nus_c->conn_handle == BLE_CONN_HANDLE_INVALID)
|
||||
||(p_ble_nus_c->conn_handle != p_ble_evt->evt.gap_evt.conn_handle)
|
||||
)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch (p_ble_evt->header.evt_id)
|
||||
{
|
||||
case BLE_GATTC_EVT_HVX:
|
||||
on_hvx(p_ble_nus_c, p_ble_evt);
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVT_DISCONNECTED:
|
||||
if (p_ble_evt->evt.gap_evt.conn_handle == p_ble_nus_c->conn_handle
|
||||
&& p_ble_nus_c->evt_handler != NULL)
|
||||
{
|
||||
ble_nus_c_evt_t nus_c_evt;
|
||||
|
||||
nus_c_evt.evt_type = BLE_NUS_C_EVT_DISCONNECTED;
|
||||
|
||||
p_ble_nus_c->conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
p_ble_nus_c->evt_handler(p_ble_nus_c, &nus_c_evt);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// No implementation needed.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**@brief Function for creating a message for writing to the CCCD. */
|
||||
static uint32_t cccd_configure(ble_nus_c_t * p_ble_nus_c, bool notification_enable)
|
||||
{
|
||||
nrf_ble_gq_req_t cccd_req;
|
||||
uint8_t cccd[BLE_CCCD_VALUE_LEN];
|
||||
uint16_t cccd_val = notification_enable ? BLE_GATT_HVX_NOTIFICATION : 0;
|
||||
|
||||
memset(&cccd_req, 0, sizeof(nrf_ble_gq_req_t));
|
||||
|
||||
cccd[0] = LSB_16(cccd_val);
|
||||
cccd[1] = MSB_16(cccd_val);
|
||||
|
||||
cccd_req.type = NRF_BLE_GQ_REQ_GATTC_WRITE;
|
||||
cccd_req.error_handler.cb = gatt_error_handler;
|
||||
cccd_req.error_handler.p_ctx = p_ble_nus_c;
|
||||
cccd_req.params.gattc_write.handle = p_ble_nus_c->handles.nus_tx_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;
|
||||
cccd_req.params.gattc_write.flags = BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE;
|
||||
|
||||
return nrf_ble_gq_item_add(p_ble_nus_c->p_gatt_queue, &cccd_req, p_ble_nus_c->conn_handle);
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_nus_c_tx_notif_enable(ble_nus_c_t * p_ble_nus_c)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_ble_nus_c);
|
||||
|
||||
if ( (p_ble_nus_c->conn_handle == BLE_CONN_HANDLE_INVALID)
|
||||
||(p_ble_nus_c->handles.nus_tx_cccd_handle == BLE_GATT_HANDLE_INVALID)
|
||||
)
|
||||
{
|
||||
return NRF_ERROR_INVALID_STATE;
|
||||
}
|
||||
return cccd_configure(p_ble_nus_c, true);
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_nus_c_string_send(ble_nus_c_t * p_ble_nus_c, uint8_t * p_string, uint16_t length)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_ble_nus_c);
|
||||
|
||||
nrf_ble_gq_req_t write_req;
|
||||
|
||||
memset(&write_req, 0, sizeof(nrf_ble_gq_req_t));
|
||||
|
||||
if (length > BLE_NUS_MAX_DATA_LEN)
|
||||
{
|
||||
NRF_LOG_WARNING("Content too long.");
|
||||
return NRF_ERROR_INVALID_PARAM;
|
||||
}
|
||||
if (p_ble_nus_c->conn_handle == BLE_CONN_HANDLE_INVALID)
|
||||
{
|
||||
NRF_LOG_WARNING("Connection handle invalid.");
|
||||
return NRF_ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
write_req.type = NRF_BLE_GQ_REQ_GATTC_WRITE;
|
||||
write_req.error_handler.cb = gatt_error_handler;
|
||||
write_req.error_handler.p_ctx = p_ble_nus_c;
|
||||
write_req.params.gattc_write.handle = p_ble_nus_c->handles.nus_rx_handle;
|
||||
write_req.params.gattc_write.len = length;
|
||||
write_req.params.gattc_write.offset = 0;
|
||||
write_req.params.gattc_write.p_value = p_string;
|
||||
write_req.params.gattc_write.write_op = BLE_GATT_OP_WRITE_CMD;
|
||||
write_req.params.gattc_write.flags = BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE;
|
||||
|
||||
return nrf_ble_gq_item_add(p_ble_nus_c->p_gatt_queue, &write_req, p_ble_nus_c->conn_handle);
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_nus_c_handles_assign(ble_nus_c_t * p_ble_nus,
|
||||
uint16_t conn_handle,
|
||||
ble_nus_c_handles_t const * p_peer_handles)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_ble_nus);
|
||||
|
||||
p_ble_nus->conn_handle = conn_handle;
|
||||
if (p_peer_handles != NULL)
|
||||
{
|
||||
p_ble_nus->handles.nus_tx_cccd_handle = p_peer_handles->nus_tx_cccd_handle;
|
||||
p_ble_nus->handles.nus_tx_handle = p_peer_handles->nus_tx_handle;
|
||||
p_ble_nus->handles.nus_rx_handle = p_peer_handles->nus_rx_handle;
|
||||
}
|
||||
return nrf_ble_gq_conn_handle_register(p_ble_nus->p_gatt_queue, conn_handle);
|
||||
}
|
||||
#endif // NRF_MODULE_ENABLED(BLE_NUS_C)
|
||||
279
components/ble/ble_services/ble_nus_c/ble_nus_c.h
Normal file
279
components/ble/ble_services/ble_nus_c/ble_nus_c.h
Normal file
@@ -0,0 +1,279 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 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 ble_nus_c Nordic UART Service Client
|
||||
* @{
|
||||
* @ingroup ble_sdk_srv
|
||||
* @brief Nordic UART Service Client module.
|
||||
*
|
||||
* @details This module contains the APIs and types exposed by the Nordic UART Service Client
|
||||
* module. The application can use these APIs and types to perform the discovery of
|
||||
* the Nordic UART Service at the peer and to interact with it.
|
||||
*
|
||||
* @note The application must register this module as the BLE event observer by using the
|
||||
* NRF_SDH_BLE_OBSERVER macro. Example:
|
||||
* @code
|
||||
* ble_nus_c_t instance;
|
||||
* NRF_SDH_BLE_OBSERVER(anything, BLE_NUS_C_BLE_OBSERVER_PRIO,
|
||||
* ble_nus_c_on_ble_evt, &instance);
|
||||
* @endcode
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BLE_NUS_C_H__
|
||||
#define BLE_NUS_C_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "ble.h"
|
||||
#include "ble_gatt.h"
|
||||
#include "ble_db_discovery.h"
|
||||
#include "ble_srv_common.h"
|
||||
#include "nrf_ble_gq.h"
|
||||
#include "nrf_sdh_ble.h"
|
||||
|
||||
#include "sdk_config.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**@brief Macro for defining a ble_nus_c instance.
|
||||
*
|
||||
* @param _name Name of the instance.
|
||||
* @hideinitializer
|
||||
*/
|
||||
#define BLE_NUS_C_DEF(_name) \
|
||||
static ble_nus_c_t _name; \
|
||||
NRF_SDH_BLE_OBSERVER(_name ## _obs, \
|
||||
BLE_NUS_C_BLE_OBSERVER_PRIO, \
|
||||
ble_nus_c_on_ble_evt, &_name)
|
||||
|
||||
/** @brief Macro for defining multiple ble_nus_c instances.
|
||||
*
|
||||
* @param _name Name of the array of instances.
|
||||
* @param _cnt Number of instances to define.
|
||||
* @hideinitializer
|
||||
*/
|
||||
#define BLE_NUS_C_ARRAY_DEF(_name, _cnt) \
|
||||
static ble_nus_c_t _name[_cnt]; \
|
||||
NRF_SDH_BLE_OBSERVERS(_name ## _obs, \
|
||||
BLE_NUS_C_BLE_OBSERVER_PRIO, \
|
||||
ble_nus_c_on_ble_evt, &_name, _cnt)
|
||||
|
||||
#define NUS_BASE_UUID {{0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x00, 0x00, 0x40, 0x6E}} /**< Used vendor-specific UUID. */
|
||||
|
||||
#define BLE_UUID_NUS_SERVICE 0x0001 /**< The UUID of the Nordic UART Service. */
|
||||
#define BLE_UUID_NUS_RX_CHARACTERISTIC 0x0002 /**< The UUID of the RX Characteristic. */
|
||||
#define BLE_UUID_NUS_TX_CHARACTERISTIC 0x0003 /**< The UUID of the TX Characteristic. */
|
||||
|
||||
#define OPCODE_LENGTH 1
|
||||
#define HANDLE_LENGTH 2
|
||||
|
||||
/**@brief Maximum length of data (in bytes) that can be transmitted to the peer by the Nordic UART service module. */
|
||||
#if defined(NRF_SDH_BLE_GATT_MAX_MTU_SIZE) && (NRF_SDH_BLE_GATT_MAX_MTU_SIZE != 0)
|
||||
#define BLE_NUS_MAX_DATA_LEN (NRF_SDH_BLE_GATT_MAX_MTU_SIZE - OPCODE_LENGTH - HANDLE_LENGTH)
|
||||
#else
|
||||
#define BLE_NUS_MAX_DATA_LEN (BLE_GATT_MTU_SIZE_DEFAULT - OPCODE_LENGTH - HANDLE_LENGTH)
|
||||
#warning NRF_SDH_BLE_GATT_MAX_MTU_SIZE is not defined.
|
||||
#endif
|
||||
|
||||
|
||||
/**@brief NUS Client event type. */
|
||||
typedef enum
|
||||
{
|
||||
BLE_NUS_C_EVT_DISCOVERY_COMPLETE, /**< Event indicating that the NUS service and its characteristics were found. */
|
||||
BLE_NUS_C_EVT_NUS_TX_EVT, /**< Event indicating that the central received something from a peer. */
|
||||
BLE_NUS_C_EVT_DISCONNECTED /**< Event indicating that the NUS server disconnected. */
|
||||
} ble_nus_c_evt_type_t;
|
||||
|
||||
/**@brief Handles on the connected peer device needed to interact with it. */
|
||||
typedef struct
|
||||
{
|
||||
uint16_t nus_tx_handle; /**< Handle of the NUS TX characteristic, as provided by a discovery. */
|
||||
uint16_t nus_tx_cccd_handle; /**< Handle of the CCCD of the NUS TX characteristic, as provided by a discovery. */
|
||||
uint16_t nus_rx_handle; /**< Handle of the NUS RX characteristic, as provided by a discovery. */
|
||||
} ble_nus_c_handles_t;
|
||||
|
||||
/**@brief Structure containing the NUS event data received from the peer. */
|
||||
typedef struct
|
||||
{
|
||||
ble_nus_c_evt_type_t evt_type;
|
||||
uint16_t conn_handle;
|
||||
uint16_t max_data_len;
|
||||
uint8_t * p_data;
|
||||
uint16_t data_len;
|
||||
ble_nus_c_handles_t handles; /**< Handles on which the Nordic UART service characteristics were discovered on the peer device. This is filled if the evt_type is @ref BLE_NUS_C_EVT_DISCOVERY_COMPLETE.*/
|
||||
} ble_nus_c_evt_t;
|
||||
|
||||
// Forward declaration of the ble_nus_t type.
|
||||
typedef struct ble_nus_c_s ble_nus_c_t;
|
||||
|
||||
/**@brief Event handler type.
|
||||
*
|
||||
* @details This is the type of the event handler that is to be provided by the application
|
||||
* of this module to receive events.
|
||||
*/
|
||||
typedef void (* ble_nus_c_evt_handler_t)(ble_nus_c_t * p_ble_nus_c, ble_nus_c_evt_t const * p_evt);
|
||||
|
||||
/**@brief NUS Client structure. */
|
||||
struct ble_nus_c_s
|
||||
{
|
||||
uint8_t uuid_type; /**< UUID type. */
|
||||
uint16_t conn_handle; /**< Handle of the current connection. Set with @ref ble_nus_c_handles_assign when connected. */
|
||||
ble_nus_c_handles_t handles; /**< Handles on the connected peer device needed to interact with it. */
|
||||
ble_nus_c_evt_handler_t evt_handler; /**< Application event handler to be called when there is an event related to the NUS. */
|
||||
ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
|
||||
nrf_ble_gq_t * p_gatt_queue; /**< Pointer to BLE GATT Queue instance. */
|
||||
};
|
||||
|
||||
/**@brief NUS Client initialization structure. */
|
||||
typedef struct
|
||||
{
|
||||
ble_nus_c_evt_handler_t evt_handler; /**< Application event handler to be called when there is an event related to the NUS. */
|
||||
ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
|
||||
nrf_ble_gq_t * p_gatt_queue; /**< Pointer to BLE GATT Queue instance. */
|
||||
} ble_nus_c_init_t;
|
||||
|
||||
|
||||
/**@brief Function for initializing the Nordic UART client module.
|
||||
*
|
||||
* @details This function registers with the Database Discovery module
|
||||
* for the NUS. The Database Discovery module looks for the presence
|
||||
* of a NUS instance at the peer when a discovery is started.
|
||||
*
|
||||
* @param[in] p_ble_nus_c Pointer to the NUS client structure.
|
||||
* @param[in] p_ble_nus_c_init Pointer to the NUS initialization structure that contains the
|
||||
* initialization information.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the module was initialized successfully.
|
||||
* @retval err_code Otherwise, this function propagates the error code
|
||||
* returned by the Database Discovery module API
|
||||
* @ref ble_db_discovery_evt_register.
|
||||
*/
|
||||
uint32_t ble_nus_c_init(ble_nus_c_t * p_ble_nus_c, ble_nus_c_init_t * p_ble_nus_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 NUS at the peer. If it does, the function
|
||||
* calls the application's event handler to indicate that NUS was
|
||||
* discovered at the peer. The function also populates the event with service-related
|
||||
* information before providing it to the application.
|
||||
*
|
||||
* @param[in] p_ble_nus_c Pointer to the NUS client structure.
|
||||
* @param[in] p_evt Pointer to the event received from the Database Discovery module.
|
||||
*/
|
||||
void ble_nus_c_on_db_disc_evt(ble_nus_c_t * p_ble_nus_c, ble_db_discovery_evt_t * p_evt);
|
||||
|
||||
|
||||
/**@brief Function for handling BLE events from the SoftDevice.
|
||||
*
|
||||
* @details This function handles the BLE events received from the SoftDevice. If a BLE
|
||||
* event is relevant to the NUS module, the function uses the event's data to update
|
||||
* internal variables and, if necessary, send events to the application.
|
||||
*
|
||||
* @param[in] p_ble_evt Pointer to the BLE event.
|
||||
* @param[in] p_context Pointer to the NUS client structure.
|
||||
*/
|
||||
void ble_nus_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
|
||||
|
||||
|
||||
/**@brief Function for requesting the peer to start sending notification of TX characteristic.
|
||||
*
|
||||
* @details This function enables notifications of the NUS TX characteristic at the peer
|
||||
* by writing to the CCCD of the NUS TX characteristic.
|
||||
*
|
||||
* @param p_ble_nus_c Pointer to the NUS client structure.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the operation was successful.
|
||||
* @retval err_code Otherwise, this API propagates the error code returned by function @ref nrf_ble_gq_item_add.
|
||||
*/
|
||||
uint32_t ble_nus_c_tx_notif_enable(ble_nus_c_t * p_ble_nus_c);
|
||||
|
||||
|
||||
/**@brief Function for sending a string to the server.
|
||||
*
|
||||
* @details This function writes the RX characteristic of the server.
|
||||
*
|
||||
* @param[in] p_ble_nus_c Pointer to the NUS client structure.
|
||||
* @param[in] p_string String to be sent.
|
||||
* @param[in] length Length of the string.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the string was sent successfully.
|
||||
* @retval err_code Otherwise, this API propagates the error code returned by function @ref nrf_ble_gq_item_add.
|
||||
*/
|
||||
uint32_t ble_nus_c_string_send(ble_nus_c_t * p_ble_nus_c, uint8_t * p_string, uint16_t length);
|
||||
|
||||
|
||||
/**@brief Function for assigning handles to this instance of nus_c.
|
||||
*
|
||||
* @details Call this function when a link has been established with a peer to
|
||||
* associate the link to this instance of the module. This makes it
|
||||
* possible to handle several links and associate each link to a particular
|
||||
* instance of this module. The connection handle and attribute handles are
|
||||
* provided from the discovery event @ref BLE_NUS_C_EVT_DISCOVERY_COMPLETE.
|
||||
*
|
||||
* @param[in] p_ble_nus_c Pointer to the NUS client structure instance to associate with these
|
||||
* handles.
|
||||
* @param[in] conn_handle Connection handle to associated with the given NUS Instance.
|
||||
* @param[in] p_peer_handles Attribute handles on the NUS server that you want this NUS client to
|
||||
* interact with.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the operation was successful.
|
||||
* @retval NRF_ERROR_NULL If a p_nus was a NULL pointer.
|
||||
* @retval err_code Otherwise, this API propagates the error code returned
|
||||
* by function @ref nrf_ble_gq_item_add.
|
||||
*/
|
||||
uint32_t ble_nus_c_handles_assign(ble_nus_c_t * p_ble_nus_c,
|
||||
uint16_t conn_handle,
|
||||
ble_nus_c_handles_t const * p_peer_handles);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // BLE_NUS_C_H__
|
||||
|
||||
/** @} */
|
||||
327
components/ble/ble_services/ble_rscs/ble_rscs.c
Normal file
327
components/ble/ble_services/ble_rscs/ble_rscs.c
Normal file
@@ -0,0 +1,327 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 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.
|
||||
*
|
||||
*/
|
||||
/* Attention!
|
||||
* To maintain compliance with Nordic Semiconductor ASA's Bluetooth profile
|
||||
* qualification listings, this section of source code must not be modified.
|
||||
*/
|
||||
|
||||
#include "sdk_common.h"
|
||||
|
||||
#if NRF_MODULE_ENABLED(BLE_RSCS)
|
||||
|
||||
#include "ble_rscs.h"
|
||||
#include <string.h>
|
||||
#include "ble.h"
|
||||
#include "ble_srv_common.h"
|
||||
|
||||
#define OPCODE_LENGTH 1 /**< Length of opcode inside Running Speed and Cadence Measurement packet. */
|
||||
#define HANDLE_LENGTH 2 /**< Length of handle inside Running Speed and Cadence Measurement packet. */
|
||||
#define MAX_RSCM_LEN (BLE_GATT_ATT_MTU_DEFAULT - OPCODE_LENGTH - HANDLE_LENGTH) /**< Maximum size of a transmitted Running Speed and Cadence Measurement. */
|
||||
|
||||
// Running Speed and Cadence Measurement flag bits
|
||||
#define RSC_MEAS_FLAG_INSTANT_STRIDE_LEN_PRESENT (0x01 << 0) /**< Instantaneous Stride Length Present flag bit. */
|
||||
#define RSC_MEAS_FLAG_TOTAL_DISTANCE_PRESENT (0x01 << 1) /**< Total Distance Present flag bit. */
|
||||
#define RSC_MEAS_FLAG_WALKING_OR_RUNNING_BIT (0x01 << 2) /**< Walking or Running Status flag bit. */
|
||||
|
||||
|
||||
/**@brief Function for handling the Connect event.
|
||||
*
|
||||
* @param[in] p_rscs Running Speed and Cadence Service structure.
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
*/
|
||||
static void on_connect(ble_rscs_t * p_rscs, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
p_rscs->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling the Disconnect event.
|
||||
*
|
||||
* @param[in] p_rscs Running Speed and Cadence Service structure.
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
*/
|
||||
static void on_disconnect(ble_rscs_t * p_rscs, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
UNUSED_PARAMETER(p_ble_evt);
|
||||
p_rscs->conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling the write events to the RSCS Measurement characteristic.
|
||||
*
|
||||
* @param[in] p_rscs Running Speed and Cadence Service structure.
|
||||
* @param[in] p_evt_write Write event received from the BLE stack.
|
||||
*/
|
||||
static void on_meas_cccd_write(ble_rscs_t * p_rscs, ble_gatts_evt_write_t const * p_evt_write)
|
||||
{
|
||||
if (p_evt_write->len == 2)
|
||||
{
|
||||
// CCCD written, update notification state
|
||||
if (p_rscs->evt_handler != NULL)
|
||||
{
|
||||
ble_rscs_evt_t evt;
|
||||
|
||||
if (ble_srv_is_notification_enabled(p_evt_write->data))
|
||||
{
|
||||
evt.evt_type = BLE_RSCS_EVT_NOTIFICATION_ENABLED;
|
||||
}
|
||||
else
|
||||
{
|
||||
evt.evt_type = BLE_RSCS_EVT_NOTIFICATION_DISABLED;
|
||||
}
|
||||
|
||||
p_rscs->evt_handler(p_rscs, &evt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling the Write event.
|
||||
*
|
||||
* @param[in] p_rscs Running Speed and Cadence Service structure.
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
*/
|
||||
static void on_write(ble_rscs_t * p_rscs, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
ble_gatts_evt_write_t const * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
|
||||
|
||||
if (p_evt_write->handle == p_rscs->meas_handles.cccd_handle)
|
||||
{
|
||||
on_meas_cccd_write(p_rscs, p_evt_write);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ble_rscs_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
|
||||
{
|
||||
if ((p_context == NULL) || (p_ble_evt == NULL))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ble_rscs_t * p_rscs = (ble_rscs_t *)p_context;
|
||||
|
||||
switch (p_ble_evt->header.evt_id)
|
||||
{
|
||||
case BLE_GAP_EVT_CONNECTED:
|
||||
on_connect(p_rscs, p_ble_evt);
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVT_DISCONNECTED:
|
||||
on_disconnect(p_rscs, p_ble_evt);
|
||||
break;
|
||||
|
||||
case BLE_GATTS_EVT_WRITE:
|
||||
on_write(p_rscs, p_ble_evt);
|
||||
break;
|
||||
|
||||
default:
|
||||
// No implementation needed.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for encoding a RSCS Measurement.
|
||||
*
|
||||
* @param[in] p_rscs Running Speed and Cadence Service structure.
|
||||
* @param[in] p_rsc_measurement Measurement to be encoded.
|
||||
* @param[out] p_encoded_buffer Buffer where the encoded data will be written.
|
||||
*
|
||||
* @return Size of encoded data.
|
||||
*/
|
||||
static uint8_t rsc_measurement_encode(const ble_rscs_t * p_rscs,
|
||||
const ble_rscs_meas_t * p_rsc_measurement,
|
||||
uint8_t * p_encoded_buffer)
|
||||
{
|
||||
uint8_t flags = 0;
|
||||
uint8_t len = 1;
|
||||
|
||||
// Instantaneous speed field
|
||||
len += uint16_encode(p_rsc_measurement->inst_speed, &p_encoded_buffer[len]);
|
||||
|
||||
// Instantaneous cadence field
|
||||
p_encoded_buffer[len++] = p_rsc_measurement->inst_cadence;
|
||||
|
||||
// Instantaneous stride length field
|
||||
if (p_rscs->feature & BLE_RSCS_FEATURE_INSTANT_STRIDE_LEN_BIT)
|
||||
{
|
||||
if (p_rsc_measurement->is_inst_stride_len_present)
|
||||
{
|
||||
flags |= RSC_MEAS_FLAG_INSTANT_STRIDE_LEN_PRESENT;
|
||||
len += uint16_encode(p_rsc_measurement->inst_stride_length,
|
||||
&p_encoded_buffer[len]);
|
||||
}
|
||||
}
|
||||
|
||||
// Total distance field
|
||||
if (p_rscs->feature & BLE_RSCS_FEATURE_TOTAL_DISTANCE_BIT)
|
||||
{
|
||||
if (p_rsc_measurement->is_total_distance_present)
|
||||
{
|
||||
flags |= RSC_MEAS_FLAG_TOTAL_DISTANCE_PRESENT;
|
||||
len += uint32_encode(p_rsc_measurement->total_distance, &p_encoded_buffer[len]);
|
||||
}
|
||||
}
|
||||
|
||||
// Flags field
|
||||
if (p_rscs->feature & BLE_RSCS_FEATURE_WALKING_OR_RUNNING_STATUS_BIT)
|
||||
{
|
||||
if (p_rsc_measurement->is_running)
|
||||
{
|
||||
flags |= RSC_MEAS_FLAG_WALKING_OR_RUNNING_BIT;
|
||||
}
|
||||
}
|
||||
p_encoded_buffer[0] = flags;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_rscs_init(ble_rscs_t * p_rscs, const ble_rscs_init_t * p_rscs_init)
|
||||
{
|
||||
if (p_rscs == NULL || p_rscs_init == NULL)
|
||||
{
|
||||
return NRF_ERROR_NULL;
|
||||
}
|
||||
|
||||
uint32_t err_code;
|
||||
uint8_t init_value_encoded[MAX(MAX_RSCM_LEN, sizeof(uint16_t))];
|
||||
ble_uuid_t ble_uuid;
|
||||
ble_add_char_params_t add_char_params;
|
||||
|
||||
// Initialize service structure
|
||||
p_rscs->evt_handler = p_rscs_init->evt_handler;
|
||||
p_rscs->conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
p_rscs->feature = p_rscs_init->feature;
|
||||
|
||||
// Add service
|
||||
BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_RUNNING_SPEED_AND_CADENCE);
|
||||
|
||||
err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
|
||||
&ble_uuid,
|
||||
&p_rscs->service_handle);
|
||||
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
|
||||
// Add measurement characteristic
|
||||
memset(&add_char_params, 0, sizeof(add_char_params));
|
||||
add_char_params.uuid = BLE_UUID_RSC_MEASUREMENT_CHAR;
|
||||
add_char_params.max_len = MAX_RSCM_LEN;
|
||||
add_char_params.is_var_len = true;
|
||||
add_char_params.char_props.notify = 1;
|
||||
add_char_params.cccd_write_access = p_rscs_init->rsc_meas_cccd_wr_sec;
|
||||
add_char_params.p_init_value = init_value_encoded;
|
||||
add_char_params.init_len = rsc_measurement_encode(p_rscs,
|
||||
&p_rscs_init->initial_rcm,
|
||||
init_value_encoded);
|
||||
|
||||
err_code = characteristic_add(p_rscs->service_handle, &add_char_params, &p_rscs->meas_handles);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
|
||||
// Add feature characteristic
|
||||
memset(&add_char_params, 0, sizeof(add_char_params));
|
||||
add_char_params.uuid = BLE_UUID_RSC_FEATURE_CHAR;
|
||||
add_char_params.max_len = sizeof(uint16_t);
|
||||
add_char_params.init_len = uint16_encode(p_rscs_init->feature, init_value_encoded);
|
||||
add_char_params.p_init_value = init_value_encoded;
|
||||
add_char_params.char_props.read = 1;
|
||||
add_char_params.read_access = p_rscs_init->rsc_feature_rd_sec;
|
||||
|
||||
err_code = characteristic_add(p_rscs->service_handle,
|
||||
&add_char_params,
|
||||
&p_rscs->feature_handles);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_rscs_measurement_send(ble_rscs_t * p_rscs, ble_rscs_meas_t * p_measurement)
|
||||
{
|
||||
if (p_rscs == NULL || p_measurement == NULL)
|
||||
{
|
||||
return NRF_ERROR_NULL;
|
||||
}
|
||||
|
||||
uint32_t err_code;
|
||||
|
||||
// Send value if connected and notifying
|
||||
if (p_rscs->conn_handle != BLE_CONN_HANDLE_INVALID)
|
||||
{
|
||||
uint8_t encoded_rsc_meas[MAX_RSCM_LEN];
|
||||
uint16_t len;
|
||||
uint16_t hvx_len;
|
||||
ble_gatts_hvx_params_t hvx_params;
|
||||
|
||||
len = rsc_measurement_encode(p_rscs, p_measurement, encoded_rsc_meas);
|
||||
hvx_len = len;
|
||||
|
||||
memset(&hvx_params, 0, sizeof(hvx_params));
|
||||
|
||||
hvx_params.handle = p_rscs->meas_handles.value_handle;
|
||||
hvx_params.type = BLE_GATT_HVX_NOTIFICATION;
|
||||
hvx_params.offset = 0;
|
||||
hvx_params.p_len = &hvx_len;
|
||||
hvx_params.p_data = encoded_rsc_meas;
|
||||
|
||||
err_code = sd_ble_gatts_hvx(p_rscs->conn_handle, &hvx_params);
|
||||
if ((err_code == NRF_SUCCESS) && (hvx_len != len))
|
||||
{
|
||||
err_code = NRF_ERROR_DATA_SIZE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
err_code = NRF_ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
return err_code;
|
||||
}
|
||||
#endif // NRF_MODULE_ENABLED(BLE_RSCS)
|
||||
201
components/ble/ble_services/ble_rscs/ble_rscs.h
Normal file
201
components/ble/ble_services/ble_rscs/ble_rscs.h
Normal file
@@ -0,0 +1,201 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 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 ble_rscs Running Speed and Cadence Service
|
||||
* @{
|
||||
* @ingroup ble_sdk_srv
|
||||
* @brief Running Speed and Cadence Service module.
|
||||
*
|
||||
* @details This module implements the Running Speed and Cadence Service. If enabled, notification
|
||||
* of the Running Speead and Candence Measurement is performed when the application
|
||||
* calls ble_rscs_measurement_send().
|
||||
*
|
||||
* If an event handler is supplied by the application, the Running Speed and Cadence
|
||||
* Service will generate Running Speed and Cadence 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_rscs_t instance;
|
||||
* NRF_SDH_BLE_OBSERVER(anything, BLE_RSCS_BLE_OBSERVER_PRIO,
|
||||
* ble_rscs_on_ble_evt, &instance);
|
||||
* @endcode
|
||||
*
|
||||
* @note Attention!
|
||||
* To maintain compliance with Nordic Semiconductor ASA Bluetooth profile
|
||||
* qualification listings, this section of source code must not be modified.
|
||||
*/
|
||||
|
||||
#ifndef BLE_RSCS_H__
|
||||
#define BLE_RSCS_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "ble_srv_common.h"
|
||||
#include "nrf_sdh_ble.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**@brief Macro for defining a ble_rscs instance.
|
||||
*
|
||||
* @param _name Name of the instance.
|
||||
* @hideinitializer
|
||||
*/
|
||||
#define BLE_RSCS_DEF(_name) \
|
||||
static ble_rscs_t _name; \
|
||||
NRF_SDH_BLE_OBSERVER(_name ## _obs, \
|
||||
BLE_RSCS_BLE_OBSERVER_PRIO, \
|
||||
ble_rscs_on_ble_evt, &_name)
|
||||
|
||||
/**@brief Running Speed and Cadence Service feature bits. */
|
||||
#define BLE_RSCS_FEATURE_INSTANT_STRIDE_LEN_BIT (0x01 << 0) /**< Instantaneous Stride Length Measurement Supported bit. */
|
||||
#define BLE_RSCS_FEATURE_TOTAL_DISTANCE_BIT (0x01 << 1) /**< Total Distance Measurement Supported bit. */
|
||||
#define BLE_RSCS_FEATURE_WALKING_OR_RUNNING_STATUS_BIT (0x01 << 2) /**< Walking or Running Status Supported bit. */
|
||||
#define BLE_RSCS_FEATURE_CALIBRATION_PROCEDURE_BIT (0x01 << 3) /**< Calibration Procedure Supported bit. */
|
||||
#define BLE_RSCS_FEATURE_MULTIPLE_SENSORS_BIT (0x01 << 4) /**< Multiple Sensor Locations Supported bit. */
|
||||
|
||||
|
||||
/**@brief Running Speed and Cadence Service event type. */
|
||||
typedef enum
|
||||
{
|
||||
BLE_RSCS_EVT_NOTIFICATION_ENABLED, /**< Running Speed and Cadence value notification enabled event. */
|
||||
BLE_RSCS_EVT_NOTIFICATION_DISABLED /**< Running Speed and Cadence value notification disabled event. */
|
||||
} ble_rscs_evt_type_t;
|
||||
|
||||
/**@brief Running Speed and Cadence Service event. */
|
||||
typedef struct
|
||||
{
|
||||
ble_rscs_evt_type_t evt_type; /**< Type of event. */
|
||||
} ble_rscs_evt_t;
|
||||
|
||||
// Forward declaration of the ble_rsc types.
|
||||
typedef struct ble_rscs_s ble_rscs_t;
|
||||
typedef struct ble_rscs_meas_s ble_rscs_meas_t;
|
||||
|
||||
/**@brief Running Speed and Cadence Service event handler type. */
|
||||
typedef void (*ble_rscs_evt_handler_t) (ble_rscs_t * p_rscs, ble_rscs_evt_t * p_evt);
|
||||
|
||||
/**@brief Running Speed and Cadence Service measurement structure. This contains a Running Speed and
|
||||
* Cadence measurement.
|
||||
*/
|
||||
struct ble_rscs_meas_s
|
||||
{
|
||||
bool is_inst_stride_len_present; /**< True if Instantaneous Stride Length is present in the measurement. */
|
||||
bool is_total_distance_present; /**< True if Total Distance is present in the measurement. */
|
||||
bool is_running; /**< True if running, False if walking. */
|
||||
uint16_t inst_speed; /**< Instantaneous Speed. */
|
||||
uint8_t inst_cadence; /**< Instantaneous Cadence. */
|
||||
uint16_t inst_stride_length; /**< Instantaneous Stride Length. */
|
||||
uint32_t total_distance; /**< Total Distance. */
|
||||
};
|
||||
|
||||
/**@brief Running Speed and Cadence Service init structure. This contains all options and data
|
||||
* needed for initialization of the service.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
ble_rscs_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Running Speed and Cadence Service. */
|
||||
security_req_t rsc_meas_cccd_wr_sec; /**< Security requirement for writing running speed and cadence measurement characteristic CCCD. */
|
||||
security_req_t rsc_feature_rd_sec; /**< Security requirement for reading running speed and cadence feature characteristic. */
|
||||
uint16_t feature; /**< Initial value for features of sensor. */
|
||||
ble_rscs_meas_t initial_rcm; /**< Initial Running Speed Cadence Measurement.*/
|
||||
} ble_rscs_init_t;
|
||||
|
||||
/**@brief Running Speed and Cadence Service structure. This contains various status information for
|
||||
* the service.
|
||||
*/
|
||||
struct ble_rscs_s
|
||||
{
|
||||
ble_rscs_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Running Speed and Cadence Service. */
|
||||
uint16_t service_handle; /**< Handle of Running Speed and Cadence Service (as provided by the BLE stack). */
|
||||
ble_gatts_char_handles_t meas_handles; /**< Handles related to the Running Speed and Cadence Measurement characteristic. */
|
||||
ble_gatts_char_handles_t feature_handles; /**< Handles related to the Running Speed and Cadence feature characteristic. */
|
||||
uint16_t conn_handle; /**< Handle of the current connection (as provided by the BLE stack, is BLE_CONN_HANDLE_INVALID if not in a connection). */
|
||||
uint16_t feature; /**< Bit mask of features available on sensor. */
|
||||
};
|
||||
|
||||
|
||||
/**@brief Function for initializing the Running Speed and Cadence Service.
|
||||
*
|
||||
* @param[out] p_rscs Running Speed and Cadence Service structure. This structure will have to
|
||||
* be supplied by the application. It will be initialized by this function,
|
||||
* and will later be used to identify this particular service instance.
|
||||
* @param[in] p_rscs_init Information needed to initialize the service.
|
||||
*
|
||||
* @return NRF_SUCCESS on successful initialization of service, otherwise an error code.
|
||||
*/
|
||||
uint32_t ble_rscs_init(ble_rscs_t * p_rscs, const ble_rscs_init_t * p_rscs_init);
|
||||
|
||||
|
||||
/**@brief Function for handling the Application's BLE Stack events.
|
||||
*
|
||||
* @details Handles all events from the BLE stack of interest to the Running Speed and Cadence
|
||||
* Service.
|
||||
*
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
* @param[in] p_context Running Speed and Cadence Service structure.
|
||||
*/
|
||||
void ble_rscs_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
|
||||
|
||||
|
||||
/**@brief Function for sending running speed and cadence measurement if notification has been enabled.
|
||||
*
|
||||
* @details The application calls this function after having performed a Running Speed and Cadence
|
||||
* measurement. If notification has been enabled, the measurement data is encoded and sent
|
||||
* to the client.
|
||||
*
|
||||
* @param[in] p_rscs Running Speed and Cadence Service structure.
|
||||
* @param[in] p_measurement Pointer to new running speed and cadence measurement.
|
||||
*
|
||||
* @return NRF_SUCCESS on success, otherwise an error code.
|
||||
*/
|
||||
uint32_t ble_rscs_measurement_send(ble_rscs_t * p_rscs, ble_rscs_meas_t * p_measurement);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // BLE_RSCS_H__
|
||||
|
||||
/** @} */
|
||||
323
components/ble/ble_services/ble_rscs_c/ble_rscs_c.c
Normal file
323
components/ble/ble_services/ble_rscs_c/ble_rscs_c.c
Normal file
@@ -0,0 +1,323 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 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.
|
||||
*
|
||||
*/
|
||||
/**@cond To Make Doxygen skip documentation generation for this file.
|
||||
* @{
|
||||
*/
|
||||
#include "sdk_common.h"
|
||||
#if NRF_MODULE_ENABLED(BLE_RSCS_C)
|
||||
#include "ble_rscs_c.h"
|
||||
#include "ble_db_discovery.h"
|
||||
#include "ble_types.h"
|
||||
#include "ble_gattc.h"
|
||||
|
||||
#define NRF_LOG_MODULE_NAME ble_rscs_c
|
||||
#include "nrf_log.h"
|
||||
NRF_LOG_MODULE_REGISTER();
|
||||
|
||||
#define WRITE_MESSAGE_LENGTH BLE_CCCD_VALUE_LEN /**< Length of the write message for CCCD. */
|
||||
|
||||
|
||||
/**@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)
|
||||
{
|
||||
ble_rscs_c_t * p_ble_rscs_c = (ble_rscs_c_t *)p_ctx;
|
||||
|
||||
NRF_LOG_DEBUG("A GATT Client error has occurred on conn_handle: 0X%X", conn_handle);
|
||||
|
||||
if (p_ble_rscs_c->error_handler != NULL)
|
||||
{
|
||||
p_ble_rscs_c->error_handler(nrf_error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling Handle Value Notification received from the SoftDevice.
|
||||
*
|
||||
* @details This function uses the Handle Value Notification received from the SoftDevice
|
||||
* and checks whether it is a notification of the Running Speed and Cadence measurement from
|
||||
* the peer. If it is, this function decodes the Running Speed measurement and sends it
|
||||
* to the application.
|
||||
*
|
||||
* @param[in] p_ble_rscs_c Pointer to the Running Speed and Cadence Client structure.
|
||||
* @param[in] p_ble_evt Pointer to the BLE event received.
|
||||
*/
|
||||
static void on_hvx(ble_rscs_c_t * p_ble_rscs_c, const ble_evt_t * p_ble_evt)
|
||||
{
|
||||
const ble_gattc_evt_hvx_t * p_notif = &p_ble_evt->evt.gattc_evt.params.hvx;
|
||||
|
||||
// Check if the event is on the link for this instance
|
||||
if (p_ble_rscs_c->conn_handle != p_ble_evt->evt.gattc_evt.conn_handle)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if this is a Running Speed and Cadence notification.
|
||||
if (p_ble_evt->evt.gattc_evt.params.hvx.handle == p_ble_rscs_c->peer_db.rsc_handle)
|
||||
{
|
||||
uint32_t index = 0;
|
||||
ble_rscs_c_evt_t ble_rscs_c_evt;
|
||||
ble_rscs_c_evt.evt_type = BLE_RSCS_C_EVT_RSC_NOTIFICATION;
|
||||
ble_rscs_c_evt.conn_handle = p_ble_evt->evt.gattc_evt.conn_handle;
|
||||
|
||||
//lint -save -e415 -e416 -e662 "Access of out of bounds pointer" "Creation of out of bounds pointer"
|
||||
|
||||
// Flags field
|
||||
ble_rscs_c_evt.params.rsc.is_inst_stride_len_present = p_notif->data[index] >> BLE_RSCS_INSTANT_STRIDE_LEN_PRESENT & 0x01;
|
||||
ble_rscs_c_evt.params.rsc.is_total_distance_present = p_notif->data[index] >> BLE_RSCS_TOTAL_DISTANCE_PRESENT & 0x01;
|
||||
ble_rscs_c_evt.params.rsc.is_running = p_notif->data[index] >> BLE_RSCS_WALKING_OR_RUNNING_STATUS_BIT & 0x01;
|
||||
index++;
|
||||
|
||||
// Instantaneous speed
|
||||
ble_rscs_c_evt.params.rsc.inst_speed = uint16_decode(&p_notif->data[index]);
|
||||
index += sizeof(uint16_t);
|
||||
|
||||
// Instantaneous cadence
|
||||
ble_rscs_c_evt.params.rsc.inst_cadence = p_notif->data[index];
|
||||
index++;
|
||||
|
||||
// Instantaneous stride length
|
||||
if (ble_rscs_c_evt.params.rsc.is_inst_stride_len_present == true)
|
||||
{
|
||||
ble_rscs_c_evt.params.rsc.inst_stride_length = uint16_decode(&p_notif->data[index]);
|
||||
index += sizeof(uint16_t);
|
||||
}
|
||||
|
||||
// Total distance field
|
||||
if (ble_rscs_c_evt.params.rsc.is_total_distance_present == true)
|
||||
{
|
||||
ble_rscs_c_evt.params.rsc.total_distance = uint32_decode(&p_notif->data[index]);
|
||||
//index += sizeof(uint32_t);
|
||||
}
|
||||
|
||||
p_ble_rscs_c->evt_handler(p_ble_rscs_c, &ble_rscs_c_evt);
|
||||
|
||||
//lint -restore
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@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 Running Speed and Cadence service at the peer. If it does, the function
|
||||
* calls the application's event handler to indicate that the Running Speed and Cadence
|
||||
* service was discovered at the peer. The function also populates the event with service-related
|
||||
* information before providing it to the application.
|
||||
*
|
||||
* @param[in] p_evt Pointer to the event received from the Database Discovery module.
|
||||
*
|
||||
*/
|
||||
void ble_rscs_on_db_disc_evt(ble_rscs_c_t * p_ble_rscs_c, const ble_db_discovery_evt_t * p_evt)
|
||||
{
|
||||
// Check if the Heart Rate Service was discovered.
|
||||
if (p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE &&
|
||||
p_evt->params.discovered_db.srv_uuid.uuid == BLE_UUID_RUNNING_SPEED_AND_CADENCE &&
|
||||
p_evt->params.discovered_db.srv_uuid.type == BLE_UUID_TYPE_BLE)
|
||||
{
|
||||
ble_rscs_c_evt_t evt;
|
||||
evt.conn_handle = p_evt->conn_handle;
|
||||
|
||||
// Find the CCCD Handle of the Running Speed and Cadence characteristic.
|
||||
for (uint32_t i = 0; i < p_evt->params.discovered_db.char_count; i++)
|
||||
{
|
||||
if (p_evt->params.discovered_db.charateristics[i].characteristic.uuid.uuid ==
|
||||
BLE_UUID_RSC_MEASUREMENT_CHAR)
|
||||
{
|
||||
// Found Running Speed and Cadence characteristic. Store CCCD handle and break.
|
||||
evt.params.rscs_db.rsc_cccd_handle =
|
||||
p_evt->params.discovered_db.charateristics[i].cccd_handle;
|
||||
evt.params.rscs_db.rsc_handle =
|
||||
p_evt->params.discovered_db.charateristics[i].characteristic.handle_value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
NRF_LOG_DEBUG("Running Speed and Cadence Service discovered at peer.");
|
||||
|
||||
// If the instance has been assigned prior to db_discovery, assign the db_handles.
|
||||
if (p_ble_rscs_c->conn_handle != BLE_CONN_HANDLE_INVALID)
|
||||
{
|
||||
if ((p_ble_rscs_c->peer_db.rsc_cccd_handle == BLE_GATT_HANDLE_INVALID)&&
|
||||
(p_ble_rscs_c->peer_db.rsc_handle == BLE_GATT_HANDLE_INVALID))
|
||||
{
|
||||
p_ble_rscs_c->peer_db = evt.params.rscs_db;
|
||||
}
|
||||
}
|
||||
|
||||
evt.evt_type = BLE_RSCS_C_EVT_DISCOVERY_COMPLETE;
|
||||
|
||||
p_ble_rscs_c->evt_handler(p_ble_rscs_c, &evt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_rscs_c_init(ble_rscs_c_t * p_ble_rscs_c, ble_rscs_c_init_t * p_ble_rscs_c_init)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_ble_rscs_c);
|
||||
VERIFY_PARAM_NOT_NULL(p_ble_rscs_c_init);
|
||||
|
||||
ble_uuid_t rscs_uuid;
|
||||
|
||||
rscs_uuid.type = BLE_UUID_TYPE_BLE;
|
||||
rscs_uuid.uuid = BLE_UUID_RUNNING_SPEED_AND_CADENCE;
|
||||
|
||||
p_ble_rscs_c->evt_handler = p_ble_rscs_c_init->evt_handler;
|
||||
p_ble_rscs_c->error_handler = p_ble_rscs_c_init->error_handler;
|
||||
p_ble_rscs_c->conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
p_ble_rscs_c->peer_db.rsc_cccd_handle = BLE_GATT_HANDLE_INVALID;
|
||||
p_ble_rscs_c->peer_db.rsc_handle = BLE_GATT_HANDLE_INVALID;
|
||||
p_ble_rscs_c->p_gatt_queue = p_ble_rscs_c_init->p_gatt_queue;
|
||||
|
||||
return ble_db_discovery_evt_register(&rscs_uuid);
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_rscs_c_handles_assign(ble_rscs_c_t * p_ble_rscs_c,
|
||||
uint16_t conn_handle,
|
||||
ble_rscs_c_db_t * p_peer_handles)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_ble_rscs_c);
|
||||
p_ble_rscs_c->conn_handle = conn_handle;
|
||||
if (p_peer_handles != NULL)
|
||||
{
|
||||
p_ble_rscs_c->peer_db = *p_peer_handles;
|
||||
}
|
||||
|
||||
return nrf_ble_gq_conn_handle_register(p_ble_rscs_c->p_gatt_queue, conn_handle);
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling Disconnected event received from the SoftDevice.
|
||||
*
|
||||
* @details This function check whether the disconnect event is happening on the link
|
||||
* associated with the current instance of the module. If the event is happening, the function sets the instance's
|
||||
* conn_handle to invalid.
|
||||
*
|
||||
* @param[in] p_ble_rscs_c Pointer to the RSC Client structure.
|
||||
* @param[in] p_ble_evt Pointer to the BLE event received.
|
||||
*/
|
||||
static void on_disconnected(ble_rscs_c_t * p_ble_rscs_c, const ble_evt_t * p_ble_evt)
|
||||
{
|
||||
if (p_ble_rscs_c->conn_handle == p_ble_evt->evt.gap_evt.conn_handle)
|
||||
{
|
||||
p_ble_rscs_c->conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
p_ble_rscs_c->peer_db.rsc_cccd_handle = BLE_GATT_HANDLE_INVALID;
|
||||
p_ble_rscs_c->peer_db.rsc_handle = BLE_GATT_HANDLE_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ble_rscs_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
|
||||
{
|
||||
if ((p_context == NULL) || (p_ble_evt == NULL))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ble_rscs_c_t * p_ble_rscs_c = (ble_rscs_c_t *)p_context;
|
||||
|
||||
switch (p_ble_evt->header.evt_id)
|
||||
{
|
||||
case BLE_GATTC_EVT_HVX:
|
||||
on_hvx(p_ble_rscs_c, p_ble_evt);
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVT_DISCONNECTED:
|
||||
on_disconnected(p_ble_rscs_c, p_ble_evt);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for creating a message for writing to the CCCD.
|
||||
*/
|
||||
static uint32_t cccd_configure(ble_rscs_c_t * p_ble_rscs_c, bool enable)
|
||||
{
|
||||
NRF_LOG_DEBUG("Configuring CCCD. CCCD Handle = %d, Connection Handle = %d",
|
||||
p_ble_rscs_c->peer_db.rsc_cccd_handle,
|
||||
p_ble_rscs_c->conn_handle);
|
||||
|
||||
uint8_t cccd[WRITE_MESSAGE_LENGTH];
|
||||
uint16_t cccd_val = enable ? BLE_GATT_HVX_NOTIFICATION : 0;
|
||||
nrf_ble_gq_req_t rscs_c_req;
|
||||
|
||||
cccd[0] = LSB_16(cccd_val);
|
||||
cccd[1] = MSB_16(cccd_val);
|
||||
|
||||
memset(&rscs_c_req, 0, sizeof(rscs_c_req));
|
||||
rscs_c_req.type = NRF_BLE_GQ_REQ_GATTC_WRITE;
|
||||
rscs_c_req.error_handler.cb = gatt_error_handler;
|
||||
rscs_c_req.error_handler.p_ctx = p_ble_rscs_c;
|
||||
rscs_c_req.params.gattc_write.handle = p_ble_rscs_c->peer_db.rsc_cccd_handle;
|
||||
rscs_c_req.params.gattc_write.len = WRITE_MESSAGE_LENGTH;
|
||||
rscs_c_req.params.gattc_write.p_value = cccd;
|
||||
rscs_c_req.params.gattc_write.offset = 0;
|
||||
rscs_c_req.params.gattc_write.write_op = BLE_GATT_OP_WRITE_REQ;
|
||||
|
||||
return nrf_ble_gq_item_add(p_ble_rscs_c->p_gatt_queue, &rscs_c_req, p_ble_rscs_c->conn_handle);
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_rscs_c_rsc_notif_enable(ble_rscs_c_t * p_ble_rscs_c)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_ble_rscs_c);
|
||||
|
||||
if (p_ble_rscs_c->conn_handle == BLE_CONN_HANDLE_INVALID)
|
||||
{
|
||||
return NRF_ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
return cccd_configure(p_ble_rscs_c, true);
|
||||
}
|
||||
|
||||
/** @}
|
||||
* @endcond
|
||||
*/
|
||||
#endif // NRF_MODULE_ENABLED(BLE_RSCS_C)
|
||||
237
components/ble/ble_services/ble_rscs_c/ble_rscs_c.h
Normal file
237
components/ble/ble_services/ble_rscs_c/ble_rscs_c.h
Normal file
@@ -0,0 +1,237 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 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.
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* @defgroup ble_rscs_c Running Speed and Cadence Service Client
|
||||
* @{
|
||||
* @ingroup ble_sdk_srv
|
||||
*
|
||||
* @details This module contains the APIs and types exposed by the Running Speed and Cadence
|
||||
* Service Client module. The application can use these APIs and types to perform
|
||||
* discovery of Running Speed and Cadence Service at the peer and interact with it.
|
||||
*
|
||||
* @note The application must register this module as BLE event observer by using the
|
||||
* NRF_SDH_BLE_OBSERVER macro. Example:
|
||||
* @code
|
||||
* ble_rscs_c_t instance;
|
||||
* NRF_SDH_BLE_OBSERVER(anything, BLE_RSCS_C_BLE_OBSERVER_PRIO,
|
||||
* ble_rscs_c_on_ble_evt, &instance);
|
||||
* @endcode
|
||||
*/
|
||||
#ifndef BLE_RSCS_C_H__
|
||||
#define BLE_RSCS_C_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "ble.h"
|
||||
#include "ble_db_discovery.h"
|
||||
#include "ble_srv_common.h"
|
||||
#include "nrf_ble_gq.h"
|
||||
#include "nrf_sdh_ble.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**@brief Macro for defining a ble_rscs_c instance.
|
||||
*
|
||||
* @param _name Name of the instance.
|
||||
* @hideinitializer
|
||||
*/
|
||||
#define BLE_RSCS_C_DEF(_name) \
|
||||
static ble_rscs_c_t _name; \
|
||||
NRF_SDH_BLE_OBSERVER(_name ## _obs, \
|
||||
BLE_RSCS_C_BLE_OBSERVER_PRIO, \
|
||||
ble_rscs_c_on_ble_evt, &_name)
|
||||
|
||||
/** @brief Macro for defining multiple ble_rscs_c instances.
|
||||
*
|
||||
* @param _name Name of the array of instances.
|
||||
* @param _cnt Number of instances to define.
|
||||
* @hideinitializer
|
||||
*/
|
||||
#define BLE_RSCS_C_ARRAY_DEF(_name, _cnt) \
|
||||
static ble_rscs_c_t _name[_cnt]; \
|
||||
NRF_SDH_BLE_OBSERVERS(_name ## _obs, \
|
||||
BLE_RSCS_C_BLE_OBSERVER_PRIO, \
|
||||
ble_rscs_c_on_ble_evt, &_name, _cnt)
|
||||
|
||||
#define BLE_RSCS_INSTANT_STRIDE_LEN_PRESENT 0x00 /**< Instantaneous Stride Length Measurement Supported bit. */
|
||||
#define BLE_RSCS_TOTAL_DISTANCE_PRESENT 0x01 /**< Total Distance Measurement Supported bit. */
|
||||
#define BLE_RSCS_WALKING_OR_RUNNING_STATUS_BIT 0x02 /**< Walking or Running Status Supported bit. */
|
||||
|
||||
|
||||
/**@brief Structure containing the handles related to the Running Speed and Cadence Service found on the peer. */
|
||||
typedef struct
|
||||
{
|
||||
uint16_t rsc_cccd_handle; /**< Handle of the CCCD of the Running Speed and Cadence characteristic. */
|
||||
uint16_t rsc_handle; /**< Handle of the Running Speed and Cadence characteristic as provided by the SoftDevice. */
|
||||
} ble_rscs_c_db_t;
|
||||
|
||||
/**@brief RSCS Client event type. */
|
||||
typedef enum
|
||||
{
|
||||
BLE_RSCS_C_EVT_DISCOVERY_COMPLETE = 1, /**< Event indicating that the Running Speed and Cadence Service has been discovered at the peer. */
|
||||
BLE_RSCS_C_EVT_RSC_NOTIFICATION /**< Event indicating that a notification of the Running Speed and Cadence measurement characteristic has been received from the peer. */
|
||||
} ble_rscs_c_evt_type_t;
|
||||
|
||||
/**@brief Structure containing the Running Speed and Cadence measurement received from the peer. */
|
||||
typedef struct
|
||||
{
|
||||
bool is_inst_stride_len_present; /**< True if Instantaneous Stride Length is present in the measurement. */
|
||||
bool is_total_distance_present; /**< True if Total Distance is present in the measurement. */
|
||||
bool is_running; /**< True if running, False if walking. */
|
||||
uint16_t inst_speed; /**< Instantaneous Speed. */
|
||||
uint8_t inst_cadence; /**< Instantaneous Cadence. */
|
||||
uint16_t inst_stride_length; /**< Instantaneous Stride Length. */
|
||||
uint32_t total_distance; /**< Total Distance. */
|
||||
} ble_rsc_t;
|
||||
|
||||
/**@brief Running Speed and Cadence Event structure. */
|
||||
typedef struct
|
||||
{
|
||||
ble_rscs_c_evt_type_t evt_type; /**< Type of the event. */
|
||||
uint16_t conn_handle; /**< Connection handle on which the rscs_c event occured.*/
|
||||
union
|
||||
{
|
||||
ble_rscs_c_db_t rscs_db; /**< Running Speed and Cadence Service related handles found on the peer device. This is filled if the evt_type is @ref BLE_RSCS_C_EVT_DISCOVERY_COMPLETE.*/
|
||||
ble_rsc_t rsc; /**< Running Speed and Cadence measurement received. This is filled if the evt_type is @ref BLE_RSCS_C_EVT_RSC_NOTIFICATION. */
|
||||
} params;
|
||||
} ble_rscs_c_evt_t;
|
||||
|
||||
// Forward declaration of the ble_rscs_c_t type.
|
||||
typedef struct ble_rscs_c_s ble_rscs_c_t;
|
||||
|
||||
/**@brief Event handler type.
|
||||
*
|
||||
* @details This is the type of the event handler that is to be provided by the application
|
||||
* of this module in order to receive events.
|
||||
*/
|
||||
typedef void (* ble_rscs_c_evt_handler_t) (ble_rscs_c_t * p_ble_rscs_c, ble_rscs_c_evt_t * p_evt);
|
||||
|
||||
/**@brief Running Speed and Cadence client structure. */
|
||||
struct ble_rscs_c_s
|
||||
{
|
||||
uint16_t conn_handle; /**< Connection handle as provided by the SoftDevice. */
|
||||
ble_rscs_c_db_t peer_db; /**< Handles related to RSCS on the peer*/
|
||||
ble_rscs_c_evt_handler_t evt_handler; /**< Application event handler to be called when there is an event related to the Running Speed and Cadence service. */
|
||||
ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
|
||||
nrf_ble_gq_t * p_gatt_queue; /**< Pointer to BLE GATT Queue instance. */
|
||||
};
|
||||
|
||||
/**@brief Running Speed and Cadence client initialization structure. */
|
||||
typedef struct
|
||||
{
|
||||
ble_rscs_c_evt_handler_t evt_handler; /**< Event handler to be called by the Running Speed and Cadence Client module whenever there is an event related to the Running Speed and Cadence Service. */
|
||||
ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
|
||||
nrf_ble_gq_t * p_gatt_queue; /**< Pointer to BLE GATT Queue instance. */
|
||||
} ble_rscs_c_init_t;
|
||||
|
||||
|
||||
/**@brief Function for initializing the Running Speed and Cadence Service Client module.
|
||||
*
|
||||
* @details This function will initialize the module and set up Database Discovery to discover
|
||||
* the Running Speed and Cadence Service. After calling this function, call @ref ble_db_discovery_start
|
||||
* to start discovery once a link with a peer has been established.
|
||||
*
|
||||
* @param[out] p_ble_rscs_c Pointer to the RSC Service Client structure.
|
||||
* @param[in] p_ble_rscs_c_init Pointer to the RSC Service initialization structure containing
|
||||
* the initialization information.
|
||||
*
|
||||
* @retval NRF_SUCCESS Operation success.
|
||||
* @retval NRF_ERROR_NULL A parameter is NULL.
|
||||
* @retval err_code Otherwise, this function propagates the error code returned by @ref ble_db_discovery_evt_register.
|
||||
*/
|
||||
uint32_t ble_rscs_c_init(ble_rscs_c_t * p_ble_rscs_c, ble_rscs_c_init_t * p_ble_rscs_c_init);
|
||||
|
||||
|
||||
/**@brief Function for handling the Application's BLE Stack events.
|
||||
*
|
||||
* @details Handles all events from the BLE stack that are of interest to the Running Speed and Cadence
|
||||
* Service Client.
|
||||
*
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
* @param[in] p_context Running Speed and Cadence Service Client structure.
|
||||
*/
|
||||
void ble_rscs_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
|
||||
|
||||
|
||||
uint32_t ble_rscs_c_rsc_notif_enable(ble_rscs_c_t * p_ble_rscs_c);
|
||||
|
||||
|
||||
/**@brief Function for handling events from the Database Discovery module.
|
||||
*
|
||||
* @details Call this function when you get a callback event from the Database Discovery module.
|
||||
* This function handles an event from the Database Discovery module, and determines
|
||||
* whether it relates to the discovery of Running Speed and Cadence Service at the peer.
|
||||
* If it does, the function calls the application's event handler to indicate that the RSC Service was
|
||||
* discovered at the peer. The function also populates the event with service-related
|
||||
* information before providing it to the application.
|
||||
*
|
||||
* @param p_ble_rscs_c Pointer to the Runnind Speed and Cadence Service Client structure.
|
||||
* @param[in] p_evt Pointer to the event received from the Database Discovery module.
|
||||
*/
|
||||
void ble_rscs_on_db_disc_evt(ble_rscs_c_t * p_ble_rscs_c, ble_db_discovery_evt_t const * p_evt);
|
||||
|
||||
|
||||
/**@brief Function for assigning handles to this instance of rscs_c.
|
||||
*
|
||||
* @details Call this function when a link has been established with a peer to
|
||||
* associate the link to this instance of the module. This makes it
|
||||
* possible to handle several links and associate each link to a particular
|
||||
* instance of this module. The connection handle and attribute handles are
|
||||
* provided from the discovery event @ref BLE_RSCS_C_EVT_DISCOVERY_COMPLETE.
|
||||
*
|
||||
* @param[in] p_ble_rscs_c Pointer to the RSC client structure instance for associating the link.
|
||||
* @param[in] conn_handle Connection handle to associated with the given RSCS Client Instance.
|
||||
* @param[in] p_peer_handles Attribute handles on the RSCS server that you want this RSCS client
|
||||
* to interact with.
|
||||
*/
|
||||
uint32_t ble_rscs_c_handles_assign(ble_rscs_c_t * p_ble_rscs_c,
|
||||
uint16_t conn_handle,
|
||||
ble_rscs_c_db_t * p_peer_handles);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // BLE_RSCS_C_H__
|
||||
|
||||
/** @} */ // End tag for the file.
|
||||
128
components/ble/ble_services/ble_tps/ble_tps.c
Normal file
128
components/ble/ble_services/ble_tps/ble_tps.c
Normal file
@@ -0,0 +1,128 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 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.
|
||||
*
|
||||
*/
|
||||
/* Attention!
|
||||
* To maintain compliance with Nordic Semiconductor ASA's Bluetooth profile
|
||||
* qualification listings, this section of source code must not be modified.
|
||||
*/
|
||||
#include "sdk_common.h"
|
||||
#if NRF_MODULE_ENABLED(BLE_TPS)
|
||||
#include "ble_tps.h"
|
||||
#include <string.h>
|
||||
#include "ble_srv_common.h"
|
||||
|
||||
|
||||
/**@brief Function for handling the Connect event.
|
||||
*
|
||||
* @param[in] p_tps TX Power Service structure.
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
*/
|
||||
static void on_connect(ble_tps_t * p_tps, ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
p_tps->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
|
||||
}
|
||||
|
||||
|
||||
void ble_tps_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
|
||||
{
|
||||
ble_tps_t * p_tps = (ble_tps_t *)p_context;
|
||||
|
||||
switch (p_ble_evt->header.evt_id)
|
||||
{
|
||||
case BLE_GAP_EVT_CONNECTED:
|
||||
on_connect(p_tps, p_ble_evt);
|
||||
break;
|
||||
|
||||
default:
|
||||
// No implementation needed.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_tps_init(ble_tps_t * p_tps, const ble_tps_init_t * p_tps_init)
|
||||
{
|
||||
uint32_t err_code;
|
||||
ble_uuid_t ble_uuid;
|
||||
ble_add_char_params_t add_char_params;
|
||||
|
||||
// Add service
|
||||
BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_TX_POWER_SERVICE);
|
||||
|
||||
err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
|
||||
&ble_uuid,
|
||||
&p_tps->service_handle);
|
||||
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
|
||||
// Add TX Power Level characteristic
|
||||
memset(&add_char_params, 0, sizeof(add_char_params));
|
||||
add_char_params.uuid = BLE_UUID_TX_POWER_LEVEL_CHAR;
|
||||
add_char_params.max_len = sizeof(uint8_t);
|
||||
add_char_params.init_len = sizeof(uint8_t);
|
||||
add_char_params.p_init_value = (uint8_t *) &p_tps_init->initial_tx_power_level;
|
||||
add_char_params.char_props.read = 1;
|
||||
add_char_params.read_access = p_tps_init->tpl_rd_sec;
|
||||
|
||||
return characteristic_add(p_tps->service_handle,
|
||||
&add_char_params,
|
||||
&p_tps->tx_power_level_handles);
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_tps_tx_power_level_set(ble_tps_t * p_tps, int8_t tx_power_level)
|
||||
{
|
||||
ble_gatts_value_t gatts_value;
|
||||
|
||||
// Initialize value struct.
|
||||
memset(&gatts_value, 0, sizeof(gatts_value));
|
||||
|
||||
gatts_value.len = sizeof(uint8_t);
|
||||
gatts_value.offset = 0;
|
||||
gatts_value.p_value = (uint8_t*)&tx_power_level;
|
||||
|
||||
// Update database
|
||||
return sd_ble_gatts_value_set(p_tps->conn_handle,
|
||||
p_tps->tx_power_level_handles.value_handle,
|
||||
&gatts_value);
|
||||
}
|
||||
#endif // NRF_MODULE_ENABLED(BLE_TPS)
|
||||
138
components/ble/ble_services/ble_tps/ble_tps.h
Normal file
138
components/ble/ble_services/ble_tps/ble_tps.h
Normal file
@@ -0,0 +1,138 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 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 ble_tps TX Power Service
|
||||
* @{
|
||||
* @ingroup ble_sdk_srv
|
||||
* @brief TX Power Service module.
|
||||
*
|
||||
* @details This module implements the TX Power Service with the TX Power Level characteristic.
|
||||
* During initialization it adds the TX Power Service and TX Power Level characteristic
|
||||
* with the specified initial value to the BLE stack database.
|
||||
*
|
||||
* It provides a function for letting the application update the TX Power Level
|
||||
* characteristic.
|
||||
*
|
||||
* @note Attention!
|
||||
* To maintain compliance with Nordic Semiconductor ASA Bluetooth profile
|
||||
* qualification listings, this section of source code must not be modified.
|
||||
*/
|
||||
|
||||
#ifndef BLE_TPS_H__
|
||||
#define BLE_TPS_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include "ble.h"
|
||||
#include "ble_srv_common.h"
|
||||
#include "nrf_sdh_ble.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**@brief Macro for defining a ble_tps instance.
|
||||
*
|
||||
* @param _name Name of the instance.
|
||||
* @hideinitializer
|
||||
*/
|
||||
#define BLE_TPS_DEF(_name) \
|
||||
static ble_tps_t _name; \
|
||||
NRF_SDH_BLE_OBSERVER(_name ## _obs, \
|
||||
BLE_TPS_BLE_OBSERVER_PRIO, \
|
||||
ble_tps_on_ble_evt, &_name)
|
||||
|
||||
|
||||
/**@brief TX Power Service init structure. This contains all options and data needed for
|
||||
* initialization of the service. */
|
||||
typedef struct
|
||||
{
|
||||
int8_t initial_tx_power_level; /**< Initial value of the TX Power Level characteristic (in dBm). */
|
||||
security_req_t tpl_rd_sec; /**< Security requirement for reading TX Power Level characteristic. */
|
||||
} ble_tps_init_t;
|
||||
|
||||
/**@brief TX Power Service structure. This contains various status information for the service. */
|
||||
typedef struct
|
||||
{
|
||||
uint16_t service_handle; /**< Handle of TX Power Service (as provided by the BLE stack). */
|
||||
ble_gatts_char_handles_t tx_power_level_handles; /**< Handles related to the TX Power Level characteristic. */
|
||||
uint16_t conn_handle; /**< Handle of the current connection (as provided by the BLE stack, is BLE_CONN_HANDLE_INVALID if not in a connection). */
|
||||
} ble_tps_t;
|
||||
|
||||
|
||||
/**@brief Function for initializing the TX Power Service.
|
||||
*
|
||||
* @param[out] p_hrs TX Power Service structure. This structure will have to be supplied by
|
||||
* the application. It will be initialized by this function, and will later
|
||||
* be used to identify this particular service instance.
|
||||
* @param[in] p_tps_init Information needed to initialize the service.
|
||||
*
|
||||
* @return NRF_SUCCESS on successful initialization of service, otherwise an error code.
|
||||
*/
|
||||
uint32_t ble_tps_init(ble_tps_t * p_hrs, const ble_tps_init_t * p_tps_init);
|
||||
|
||||
|
||||
/**@brief Function for handling the Application's BLE Stack events.
|
||||
*
|
||||
* @details Handles all events from the BLE stack of interest to the TX Power Service.
|
||||
*
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
* @param[in] p_context TX Power Service structure.
|
||||
*/
|
||||
void ble_tps_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
|
||||
|
||||
|
||||
/**@brief Function for setting the value of the TX Power Level characteristic.
|
||||
*
|
||||
* @param[in] p_tps TX Power Service structure.
|
||||
* @param[in] tx_power_level New TX Power Level (unit dBm, range -100 to 20).
|
||||
*
|
||||
* @return NRF_SUCCESS on success, otherwise an error code.
|
||||
*/
|
||||
uint32_t ble_tps_tx_power_level_set(ble_tps_t * p_tps, int8_t tx_power_level);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // BLE_TPS_H__
|
||||
|
||||
/** @} */
|
||||
198
components/ble/ble_services/eddystone/es.h
Normal file
198
components/ble/ble_services/eddystone/es.h
Normal file
@@ -0,0 +1,198 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#ifndef ES_H__
|
||||
#define ES_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include "app_util_platform.h"
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @defgroup eddystone_types Frame types and data formats
|
||||
* @brief Definitions specific to Eddystone frame types and data formats.
|
||||
* @ingroup eddystone
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @brief Swap 2 bytes.
|
||||
*/
|
||||
#define BYTES_SWAP_16BIT(x) (x << 8 | x >> 8)
|
||||
|
||||
/** @brief Reverse 4 bytes.
|
||||
*/
|
||||
#define BYTES_REVERSE_32BIT(x) \
|
||||
((x << 24 | ((x << 8) & 0x00FF0000)) | (((x >> 8) & 0x0000FF00) | x >> 24))
|
||||
|
||||
/** @brief Check if the error code is equal to NRF_SUCCESS. If it is not, return the error code.
|
||||
*/
|
||||
#define RETURN_IF_ERROR(PARAM) \
|
||||
if ((PARAM) != NRF_SUCCESS) \
|
||||
{ \
|
||||
return (PARAM); \
|
||||
}
|
||||
|
||||
#define ES_UUID 0xFEAA //!< UUID for Eddystone beacons according to specification.
|
||||
|
||||
#define ES_UID_FRAME_TYPE 0x00 //!< UID frame type (fixed at 0x00).
|
||||
#define ES_UID_RFU 0x00, 0x00 //!< Reserved for future use according to specification.
|
||||
|
||||
#define ES_URL_FRAME_TYPE 0x10 //!< URL frame type (fixed at 0x10).
|
||||
#define ES_URL_SCHEME 0x00 //!< URL prefix scheme according to specification (0x00 = "http://www").
|
||||
|
||||
#define ES_TLM_FRAME_TYPE 0x20 //!< TLM frame type (fixed at 0x20).
|
||||
#define ES_EID_FRAME_TYPE 0x30 //!< EID frame type (fixed at 0x30).
|
||||
|
||||
#define ES_FRAME_TYPE_LENGTH (1) //!< Length of a frame type field.
|
||||
|
||||
#define ES_UID_LENGTH (20) //!< Length of a UID frame.
|
||||
#define ES_UID_NAMESPACE_LENGTH (10) //!< Length of a UID frame namespace field.
|
||||
#define ES_UID_INSTANCE_LENGTH (6) //!< Length of a UID frame instance field.
|
||||
#define ES_UID_RFU_LENGTH (2) //!< Length of a UID frame RFU field.
|
||||
|
||||
#define ES_URL_LENGTH (20) //!< Length of a URL frame.
|
||||
#define ES_URL_URL_SCHEME_LENGTH (1) //!< Length of a URL frame URL scheme field.
|
||||
#define ES_URL_ENCODED_URL_LENGTH (17) //!< Maximum length of a URL frame encoded URL field.
|
||||
|
||||
#define ES_TLM_LENGTH (14) //!< Length of a TLM frame.
|
||||
#define ES_TLM_VBATT_LENGTH (2) //!< Length of a TLM frame VBATT field.
|
||||
#define ES_TLM_TEMP_LENGTH (2) //!< Length of a TLM frame TEMP field.
|
||||
#define ES_TLM_ADV_CNT_LENGTH (4) //!< Length of a TLM frame ADV count field.
|
||||
#define ES_TLM_SEC_CNT_LENGTH (4) //!< Length of a TLM frame seconds field.
|
||||
|
||||
#define ES_EID_LENGTH (10) //!< Length of an EID frame.
|
||||
#define ES_EID_ID_LENGTH (8) //!< Length of an EID frame ephemeral ID field.
|
||||
#define ES_EID_GATTS_READ_LENGTH (14)
|
||||
#define ES_EID_GATTS_READ_FRAME_TYPE_IDX (0)
|
||||
#define ES_EID_GATTS_READ_EXPONENT_IDX (1)
|
||||
#define ES_EID_GATTS_READ_CLCK_VALUE_IDX (2)
|
||||
#define ES_EID_GATTS_READ_EID_IDX (6)
|
||||
|
||||
#define ES_ETLM_LENGTH (18) //!< Length of an eTLM frame.
|
||||
#define ES_ETLM_ECRYPTED_LENGTH (ES_TLM_VBATT_LENGTH + \
|
||||
ES_TLM_TEMP_LENGTH + \
|
||||
ES_TLM_ADV_CNT_LENGTH + \
|
||||
ES_TLM_SEC_CNT_LENGTH) //!< Length of an eTLM frame encrypted TLM field.
|
||||
|
||||
#define ES_ETLM_RFU (0x00) //!< eTLM frame RFU field value.
|
||||
#define ES_SPEC_VERSION_BYTE (0x00) //!< eTLM frame specification version field value.
|
||||
|
||||
/** @brief Eddystone frame type values. These values are advertised as frame types. */
|
||||
typedef enum
|
||||
{
|
||||
ES_FRAME_TYPE_UID = ES_UID_FRAME_TYPE, /**< UID frame type. */
|
||||
ES_FRAME_TYPE_URL = ES_URL_FRAME_TYPE, /**< URL frame type. */
|
||||
ES_FRAME_TYPE_TLM = ES_TLM_FRAME_TYPE, /**< TLM frame type. */
|
||||
ES_FRAME_TYPE_EID = ES_EID_FRAME_TYPE /**< EID frame type. */
|
||||
} es_frame_type_t;
|
||||
|
||||
/** @brief TLM version values. */
|
||||
typedef enum
|
||||
{
|
||||
ES_TLM_VERSION_TLM = 0x00, /**< TLM. */
|
||||
ES_TLM_VERSION_ETLM = 0x01 /**< Encrypted TLM (eTLM). */
|
||||
} es_tlm_version_t;
|
||||
|
||||
/** @brief UID frame data representation.
|
||||
* @note This is a packed structure. Therefore, you should not change it.
|
||||
*/
|
||||
typedef PACKED_STRUCT
|
||||
{
|
||||
es_frame_type_t frame_type; //!< Frame type (see @ref es_frame_type_t).
|
||||
int8_t ranging_data; //!< Calibrated TX power at 0 m.
|
||||
int8_t namespace[ES_UID_NAMESPACE_LENGTH]; //!< UID namespace.
|
||||
int8_t instance[ES_UID_INSTANCE_LENGTH]; //!< UID instance.
|
||||
int8_t rfu[ES_UID_RFU_LENGTH]; //!< RFU.
|
||||
} es_uid_frame_t;
|
||||
|
||||
|
||||
/** @brief URL frame data representation.
|
||||
* @note This is a packed structure. Therefore, you should not change it.
|
||||
*/
|
||||
typedef PACKED_STRUCT
|
||||
{
|
||||
es_frame_type_t frame_type; //!< Frame type (see @ref es_frame_type_t).
|
||||
int8_t ranging_data; //!< Calibrated TX power at 0 m.
|
||||
uint8_t url_scheme; //!< URL scheme.
|
||||
uint8_t encoded_url[ES_URL_ENCODED_URL_LENGTH]; //!< Encoded URL (variable length).
|
||||
} es_url_frame_t;
|
||||
|
||||
|
||||
/** @brief TLM frame data representation.
|
||||
* @note This is a packed structure. Therefore, you should not change it.
|
||||
*/
|
||||
typedef PACKED_STRUCT
|
||||
{
|
||||
es_frame_type_t frame_type; //!< Frame type (see @ref es_frame_type_t).
|
||||
es_tlm_version_t version; //!< TLM version (see @ref es_tlm_version_t).
|
||||
int8_t vbatt[ES_TLM_VBATT_LENGTH]; //!< Battery voltage (in 1 mV units).
|
||||
int8_t temp[ES_TLM_TEMP_LENGTH]; //!< Beacon temperature.
|
||||
int8_t adv_cnt[ES_TLM_ADV_CNT_LENGTH]; //!< Advertising PDU count.
|
||||
int8_t sec_cnt[ES_TLM_SEC_CNT_LENGTH]; //!< Time since power-on or reboot.
|
||||
} es_tlm_frame_t;
|
||||
|
||||
/** @brief EID frame data representation.
|
||||
* @note This is a packed structure. Therefore, you should not change it.
|
||||
*/
|
||||
typedef PACKED_STRUCT
|
||||
{
|
||||
es_frame_type_t frame_type; //!< Frame type (see @ref es_frame_type_t).
|
||||
int8_t ranging_data; //!< Calibrated TX power at 0 m.
|
||||
int8_t eid[ES_EID_ID_LENGTH]; //!< 8-byte ephemeral identifier.
|
||||
} es_eid_frame_t;
|
||||
|
||||
|
||||
/** @brief eTLM frame data representation.
|
||||
* @note This is a packed structure. Therefore, you should not change it.
|
||||
*/
|
||||
typedef PACKED_STRUCT
|
||||
{
|
||||
es_frame_type_t frame_type; //!< Frame type (see @ref es_frame_type_t).
|
||||
es_tlm_version_t version; //!< TLM version (see @ref es_tlm_version_t).
|
||||
int8_t encrypted_tlm[ES_ETLM_ECRYPTED_LENGTH]; //!< Encrypted TLM data.
|
||||
int16_t random_salt; //!< Salt
|
||||
int16_t msg_integrity_check; //!< Message integrity check.
|
||||
} es_etlm_frame_t;
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif // ES_H__
|
||||
359
components/ble/ble_services/eddystone/es_adv.c
Normal file
359
components/ble/ble_services/eddystone/es_adv.c
Normal file
@@ -0,0 +1,359 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#include "es_adv.h"
|
||||
#include "app_error.h"
|
||||
#include "es_adv_frame.h"
|
||||
#include "es_adv_timing.h"
|
||||
#include "es_tlm.h"
|
||||
#include "es_slot.h"
|
||||
|
||||
#define MULTIPROT_BEACON_DELAY_MS 75 //!< Maximum delay of the beacon send by multiprotocol example.
|
||||
|
||||
static es_adv_evt_handler_t m_adv_evt_handler; //!< Eddystone advertisement event handler.
|
||||
static bool m_is_connected = false; //!< Is the Eddystone beacon in a connected state.
|
||||
static bool m_remain_connectable = false; //!< Should the Eddystone beacon remain connectable.
|
||||
static uint8_t m_ecs_uuid_type = 0; //!< UUID type of the Eddystone Configuration Service.
|
||||
static uint16_t m_adv_interval = APP_CFG_NON_CONN_ADV_INTERVAL_MS; //!< Current advertisement interval.
|
||||
|
||||
static uint8_t m_enc_advdata[BLE_GAP_ADV_SET_DATA_SIZE_MAX]; //!< Buffer for storing an encoded advertising set.
|
||||
static uint8_t m_enc_scan_response_data[BLE_GAP_ADV_SET_DATA_SIZE_MAX]; //!< Buffer for storing an encoded scan data.
|
||||
static uint8_t *mp_adv_handle; //!< Pointer to the advertising handle.
|
||||
|
||||
/**@brief Struct that contains pointers to the encoded advertising data. */
|
||||
static ble_gap_adv_data_t m_adv_data =
|
||||
{
|
||||
.adv_data =
|
||||
{
|
||||
.p_data = m_enc_advdata,
|
||||
.len = BLE_GAP_ADV_SET_DATA_SIZE_MAX
|
||||
},
|
||||
.scan_rsp_data =
|
||||
{
|
||||
.p_data = m_enc_scan_response_data,
|
||||
.len = BLE_GAP_ADV_SET_DATA_SIZE_MAX
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
/**@brief Function for invoking registered callback.
|
||||
*
|
||||
* @param[in] evt Event to issue to callback.
|
||||
*/
|
||||
static void invoke_callback(es_adv_evt_t evt)
|
||||
{
|
||||
if (m_adv_evt_handler != NULL)
|
||||
{
|
||||
m_adv_evt_handler(evt);
|
||||
}
|
||||
}
|
||||
|
||||
/**@brief Starting advertising.
|
||||
* @param[in] p_adv_params Advertisement parameters to use.
|
||||
*/
|
||||
static void adv_start(ble_gap_adv_params_t * p_adv_params)
|
||||
{
|
||||
ret_code_t err_code = NRF_SUCCESS;
|
||||
|
||||
es_tlm_adv_cnt_inc();
|
||||
|
||||
err_code = sd_ble_gap_adv_set_configure(mp_adv_handle, &m_adv_data, p_adv_params);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
err_code = sd_ble_gap_adv_start(*mp_adv_handle, BLE_CONN_CFG_TAG_DEFAULT);
|
||||
|
||||
if (err_code != NRF_ERROR_BUSY && err_code != NRF_SUCCESS)
|
||||
{
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Given state of Eddystone beacon, get advertisement parameters. */
|
||||
static void get_adv_params(ble_gap_adv_params_t * p_adv_params,
|
||||
bool non_connectable,
|
||||
bool remain_connectable)
|
||||
{
|
||||
// Initialize advertising parameters (used when starting advertising).
|
||||
memset(p_adv_params, 0, sizeof(ble_gap_adv_params_t));
|
||||
|
||||
// Non-connectable
|
||||
p_adv_params->properties.type = non_connectable
|
||||
? BLE_GAP_ADV_TYPE_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED
|
||||
: BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED;
|
||||
p_adv_params->p_peer_addr = NULL; // Undirected advertisement.
|
||||
p_adv_params->filter_policy = BLE_GAP_ADV_FP_ANY;
|
||||
p_adv_params->primary_phy = BLE_GAP_PHY_1MBPS;
|
||||
|
||||
if (non_connectable)
|
||||
{
|
||||
#ifdef MULTIPROTOCOL_802154_MODE
|
||||
/* In case the Eddystone component is used by multiprotocol example,
|
||||
calculate the interval taking into account that beacon may be sent with a delay.
|
||||
MULTIPROTOCOL_802154_MODE is defined for multiprotocol examples only.
|
||||
*/
|
||||
p_adv_params->interval = MSEC_TO_UNITS(((m_adv_interval - MULTIPROT_BEACON_DELAY_MS) > 0 ? (m_adv_interval - MULTIPROT_BEACON_DELAY_MS) : m_adv_interval), UNIT_0_625_MS);
|
||||
#else
|
||||
p_adv_params->interval = MSEC_TO_UNITS(m_adv_interval, UNIT_0_625_MS);
|
||||
#endif // MULTIPROTOCOL_802154_MODE
|
||||
p_adv_params->duration = BLE_GAP_ADV_TIMEOUT_GENERAL_UNLIMITED;
|
||||
}
|
||||
else
|
||||
{
|
||||
p_adv_params->interval = MSEC_TO_UNITS(APP_CFG_CONNECTABLE_ADV_INTERVAL_MS, UNIT_0_625_MS);
|
||||
p_adv_params->duration = APP_CFG_CONNECTABLE_ADV_TIMEOUT;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Update advertisement data and start connectable advertisements. */
|
||||
static void connectable_adv_start(void)
|
||||
{
|
||||
ble_gap_adv_params_t connectable_adv_params;
|
||||
ble_advdata_t scrsp_data;
|
||||
ble_uuid_t scrp_uuids[] = {{BLE_UUID_ESCS_SERVICE, m_ecs_uuid_type}};
|
||||
|
||||
memset(&scrsp_data, 0, sizeof(scrsp_data));
|
||||
scrsp_data.name_type = BLE_ADVDATA_FULL_NAME;
|
||||
scrsp_data.include_appearance = false;
|
||||
scrsp_data.uuids_complete.uuid_cnt = sizeof(scrp_uuids) / sizeof(scrp_uuids[0]);
|
||||
scrsp_data.uuids_complete.p_uuids = scrp_uuids;
|
||||
|
||||
m_adv_data.scan_rsp_data.p_data = m_enc_scan_response_data;
|
||||
m_adv_data.scan_rsp_data.len = BLE_GAP_ADV_SET_DATA_SIZE_MAX;
|
||||
|
||||
// As the data to be written does not depend on the slot_no, we can safely send
|
||||
es_adv_frame_fill_connectable_adv_data(&scrsp_data, &m_adv_data);
|
||||
|
||||
get_adv_params(&connectable_adv_params, false, m_remain_connectable);
|
||||
adv_start(&connectable_adv_params);
|
||||
|
||||
invoke_callback(ES_ADV_EVT_CONNECTABLE_ADV_STARTED);
|
||||
}
|
||||
|
||||
|
||||
static void adv_stop(void)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
|
||||
err_code = sd_ble_gap_adv_stop(*mp_adv_handle);
|
||||
if (err_code != NRF_ERROR_INVALID_STATE)
|
||||
{
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
|
||||
es_adv_timing_stop();
|
||||
}
|
||||
|
||||
|
||||
static void adv_restart(void)
|
||||
{
|
||||
if (!m_remain_connectable)
|
||||
{
|
||||
es_adv_start_non_connctable_adv();
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
connectable_adv_start();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function handling events from @ref es_adv_timing.c.
|
||||
*
|
||||
* @param[in] p_evt Advertisement timing event.
|
||||
*/
|
||||
static void adv_timing_callback(const es_adv_timing_evt_t * p_evt)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
ble_gap_adv_params_t non_connectable_adv_params;
|
||||
const es_slot_reg_t * p_reg = es_slot_get_registry();
|
||||
|
||||
// As new advertisement data will be loaded, stop advertising.
|
||||
err_code = sd_ble_gap_adv_stop(*mp_adv_handle);
|
||||
if (err_code != NRF_ERROR_INVALID_STATE && err_code != BLE_ERROR_INVALID_ADV_HANDLE)
|
||||
{
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
|
||||
// If a non-eTLM frame is to be advertised.
|
||||
if (p_evt->evt_id == ES_ADV_TIMING_EVT_ADV_SLOT)
|
||||
{
|
||||
err_code = sd_ble_gap_tx_power_set(BLE_GAP_TX_POWER_ROLE_ADV, 0, p_reg->slots[p_evt->slot_no].radio_tx_pwr);
|
||||
if (err_code != BLE_ERROR_INVALID_ADV_HANDLE)
|
||||
{
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
es_adv_frame_fill_non_connectable_adv_data(p_evt->slot_no, false, &m_adv_data);
|
||||
}
|
||||
|
||||
// If an eTLM frame is to be advertised
|
||||
else if (p_evt->evt_id == ES_ADV_TIMING_EVT_ADV_ETLM)
|
||||
{
|
||||
err_code = sd_ble_gap_tx_power_set(BLE_GAP_TX_POWER_ROLE_ADV, 0, p_reg->slots[p_reg->tlm_slot].radio_tx_pwr);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
es_adv_frame_fill_non_connectable_adv_data(p_evt->slot_no, true, &m_adv_data);
|
||||
}
|
||||
|
||||
invoke_callback(ES_ADV_EVT_NON_CONN_ADV);
|
||||
|
||||
get_adv_params(&non_connectable_adv_params, true, m_remain_connectable);
|
||||
adv_start(&non_connectable_adv_params);
|
||||
}
|
||||
|
||||
|
||||
void es_adv_start_connectable_adv(void)
|
||||
{
|
||||
if (!m_is_connected)
|
||||
{
|
||||
adv_stop();
|
||||
|
||||
connectable_adv_start();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void es_adv_start_non_connctable_adv(void)
|
||||
{
|
||||
es_adv_timing_start(m_adv_interval);
|
||||
}
|
||||
|
||||
|
||||
void es_adv_remain_connectable_set(bool remain_connectable)
|
||||
{
|
||||
m_remain_connectable = remain_connectable;
|
||||
}
|
||||
|
||||
|
||||
bool es_adv_remain_connectable_get(void)
|
||||
{
|
||||
return m_remain_connectable;
|
||||
}
|
||||
|
||||
|
||||
void es_adv_on_ble_evt(ble_evt_t const * p_ble_evt)
|
||||
{
|
||||
switch (p_ble_evt->header.evt_id)
|
||||
{
|
||||
case BLE_GAP_EVT_CONNECTED:
|
||||
m_is_connected = true;
|
||||
|
||||
// The beacon must provide these advertisements for the client to see updated values
|
||||
// during the connection.
|
||||
es_adv_start_non_connctable_adv();
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVT_DISCONNECTED:
|
||||
m_is_connected = false;
|
||||
|
||||
// Stop all advertising to give some time for writing to flash.
|
||||
adv_stop();
|
||||
adv_restart();
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVT_ADV_SET_TERMINATED:
|
||||
if (p_ble_evt->evt.gap_evt.params.adv_set_terminated.reason == BLE_GAP_EVT_ADV_SET_TERMINATED_REASON_TIMEOUT &&
|
||||
!m_is_connected)
|
||||
{
|
||||
invoke_callback(ES_ADV_EVT_CONNECTABLE_ADV_STOPPED);
|
||||
|
||||
adv_restart();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void es_adv_interval_set(nrf_ble_escs_adv_interval_t interval)
|
||||
{
|
||||
const es_slot_reg_t * p_reg = es_slot_get_registry();
|
||||
uint16_t min_valid_adv_interval;
|
||||
|
||||
bool eTLM_required = (p_reg->num_configured_eid_slots > 0) && (p_reg->tlm_configured);
|
||||
|
||||
min_valid_adv_interval = eTLM_required ? \
|
||||
p_reg->num_configured_slots * (APP_CONFIG_ADV_FRAME_SPACING_MS_MIN + \
|
||||
APP_CONFIG_ADV_FRAME_ETLM_SPACING_MS) \
|
||||
: \
|
||||
p_reg->num_configured_slots * APP_CONFIG_ADV_FRAME_SPACING_MS_MIN;
|
||||
|
||||
m_adv_interval = (interval > min_valid_adv_interval) ? interval : min_valid_adv_interval;
|
||||
|
||||
#ifdef APP_CONFIG_ADV_INTERVAL_MS_MAX
|
||||
if (m_adv_interval > APP_CONFIG_ADV_INTERVAL_MS_MAX)
|
||||
{
|
||||
m_adv_interval = APP_CONFIG_ADV_INTERVAL_MS_MAX;
|
||||
}
|
||||
#endif // APP_CONFIG_ADV_INTERVAL_MS_MAX
|
||||
}
|
||||
|
||||
|
||||
nrf_ble_escs_adv_interval_t es_adv_interval_get(void)
|
||||
{
|
||||
return m_adv_interval;
|
||||
}
|
||||
|
||||
|
||||
void es_adv_init(uint8_t ecs_uuid_type,
|
||||
es_adv_evt_handler_t adv_event_handler,
|
||||
nrf_ble_escs_adv_interval_t adv_interval,
|
||||
bool remain_connectable,
|
||||
uint8_t * const p_adv_handle)
|
||||
{
|
||||
m_ecs_uuid_type = ecs_uuid_type;
|
||||
m_adv_evt_handler = adv_event_handler;
|
||||
m_is_connected = false;
|
||||
m_remain_connectable = remain_connectable;
|
||||
m_adv_interval = adv_interval;
|
||||
mp_adv_handle = p_adv_handle;
|
||||
|
||||
es_tlm_init();
|
||||
|
||||
es_adv_timing_init(adv_timing_callback);
|
||||
}
|
||||
|
||||
void es_adv_timers_init(void)
|
||||
{
|
||||
es_adv_timing_timers_init();
|
||||
}
|
||||
129
components/ble/ble_services/eddystone/es_adv.h
Normal file
129
components/ble/ble_services/eddystone/es_adv.h
Normal file
@@ -0,0 +1,129 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#ifndef ES_ADV_H__
|
||||
#define ES_ADV_H__
|
||||
|
||||
#include "nrf_ble_escs.h"
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @defgroup eddystone_adv Eddystone advertising module
|
||||
* @brief Types and functions for handling advertising in Eddystone beacons.
|
||||
* @ingroup eddystone
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @brief Eddystone Advertiser events. */
|
||||
typedef enum
|
||||
{
|
||||
ES_ADV_EVT_NON_CONN_ADV,
|
||||
ES_ADV_EVT_CONNECTABLE_ADV_STARTED,
|
||||
ES_ADV_EVT_CONNECTABLE_ADV_STOPPED,
|
||||
} es_adv_evt_t;
|
||||
|
||||
/** @brief Eddystone Advertiser event handler. */
|
||||
typedef void (*es_adv_evt_handler_t)(es_adv_evt_t evt);
|
||||
|
||||
/** @brief Function for initializing the module.
|
||||
*
|
||||
* @param[in] ecs_uuid_type ECS UUID type used for advertising the Eddystone Configuration Service UUID.
|
||||
* @param[in] adv_event_handler Eddystone advertiser event handler.
|
||||
* @param[in] adv_interval Advertisement interval to use.
|
||||
* @param[in] remain_connectable Flag that specifies if advertisements should remain connectable.
|
||||
* @param[in] p_adv_handle Pointer to the advertising handle used to start and stop advertising.
|
||||
*/
|
||||
void es_adv_init(uint8_t ecs_uuid_type,
|
||||
es_adv_evt_handler_t adv_event_handler,
|
||||
nrf_ble_escs_adv_interval_t adv_interval,
|
||||
bool remain_connectable,
|
||||
uint8_t * const p_adv_handle);
|
||||
|
||||
/** @brief Function for passing BLE events to this module.
|
||||
*
|
||||
* @param[in] p_ble_evt Pointer to the BLE evt.
|
||||
*/
|
||||
void es_adv_on_ble_evt(ble_evt_t const * p_ble_evt);
|
||||
|
||||
/** @brief Function for starting the advertisements.
|
||||
*/
|
||||
void es_adv_start_non_connctable_adv(void);
|
||||
|
||||
/** @brief Function for specifying if the beacon should remain connectable.
|
||||
*
|
||||
* @param[in] remain_connectable Value to be set.
|
||||
*/
|
||||
void es_adv_remain_connectable_set(bool remain_connectable);
|
||||
|
||||
/** @brief Function for starting connectable advertisements.
|
||||
*/
|
||||
void es_adv_start_connectable_adv(void);
|
||||
|
||||
/** @brief Function for setting the base advertisement interval for non-connectable advertisements.
|
||||
*
|
||||
* The minimum allowed advertisement interval is calculated based on the configured minimum advertisement
|
||||
* frame spacings and the number of configured slots. If eTLM slots are configured a separate minimum
|
||||
* advertisement frame spacing is used for those. If @p interval is outside of range, the closest valid value
|
||||
* is set.
|
||||
*
|
||||
* @param interval The new advertisement interval.
|
||||
*/
|
||||
void es_adv_interval_set(nrf_ble_escs_adv_interval_t interval);
|
||||
|
||||
/** @brief Function for getting a pointer to the current advertisement interval.
|
||||
*
|
||||
* @retval Pointer to the current advertisement interval.
|
||||
*/
|
||||
nrf_ble_escs_adv_interval_t es_adv_interval_get(void);
|
||||
|
||||
/** @brief Function for getting the value of the 'remain_connectable' field.
|
||||
*
|
||||
* @retval Value of 'remain_connectable'.
|
||||
*/
|
||||
bool es_adv_remain_connectable_get(void);
|
||||
|
||||
/** @brief Function for initializing the Eddystone advertisement timers.
|
||||
*/
|
||||
void es_adv_timers_init(void);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif // ES_ADV_H__
|
||||
120
components/ble/ble_services/eddystone/es_adv_frame.c
Normal file
120
components/ble/ble_services/eddystone/es_adv_frame.c
Normal file
@@ -0,0 +1,120 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#include "es_adv_frame.h"
|
||||
#include "es_slot.h"
|
||||
|
||||
|
||||
/**@brief Function for setting advertisement data, using 'ble_advdata_encode'.
|
||||
*
|
||||
* @param[in] p_scrsp_data Scan response data.
|
||||
* @param[in] p_es_data_array Eddystone service data array.
|
||||
*/
|
||||
static void fill_adv_data(ble_advdata_t * p_scrsp_data, uint8_array_t * p_es_data_array, ble_gap_adv_data_t * const p_adv_data)
|
||||
{
|
||||
ble_advdata_t adv_data;
|
||||
ret_code_t err_code;
|
||||
ble_uuid_t adv_uuids[] = {{ES_UUID, BLE_UUID_TYPE_BLE}};
|
||||
uint8_array_t es_data_array = {0};
|
||||
|
||||
ble_advdata_service_data_t service_data; // Structure to hold Service Data.
|
||||
|
||||
service_data.service_uuid = APP_ES_UUID; // Eddystone UUID to allow discoverability on iOS devices.
|
||||
|
||||
service_data.data = (p_es_data_array != NULL) ? *p_es_data_array : es_data_array;
|
||||
|
||||
// Build and set advertising data.
|
||||
memset(&adv_data, 0, sizeof(ble_advdata_t));
|
||||
|
||||
adv_data.name_type = BLE_ADVDATA_NO_NAME;
|
||||
adv_data.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;
|
||||
adv_data.uuids_complete.uuid_cnt = sizeof(adv_uuids) / sizeof(adv_uuids[0]);
|
||||
adv_data.uuids_complete.p_uuids = adv_uuids;
|
||||
adv_data.p_service_data_array = &service_data;
|
||||
adv_data.service_data_count = (p_es_data_array != NULL) ? 1 : 0;
|
||||
|
||||
err_code = ble_advdata_encode(&adv_data,
|
||||
p_adv_data->adv_data.p_data,
|
||||
&p_adv_data->adv_data.len);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
if (p_scrsp_data != NULL)
|
||||
{
|
||||
err_code = ble_advdata_encode(p_scrsp_data,
|
||||
p_adv_data->scan_rsp_data.p_data,
|
||||
&p_adv_data->scan_rsp_data.len);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
else
|
||||
{
|
||||
p_adv_data->scan_rsp_data.p_data = NULL;
|
||||
p_adv_data->scan_rsp_data.len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void es_adv_frame_fill_connectable_adv_data(ble_advdata_t * p_scrsp_data, ble_gap_adv_data_t * const p_adv_data)
|
||||
{
|
||||
fill_adv_data(p_scrsp_data, NULL, p_adv_data);
|
||||
}
|
||||
|
||||
|
||||
void es_adv_frame_fill_non_connectable_adv_data(uint8_t slot_no, bool etlm, ble_gap_adv_data_t * const p_adv_data)
|
||||
{
|
||||
uint8_array_t es_data_array = {0};
|
||||
const es_slot_reg_t * p_reg = es_slot_get_registry();
|
||||
|
||||
if (etlm)
|
||||
{
|
||||
es_slot_etlm_update(slot_no);
|
||||
|
||||
// If eTLM, the incoming slot_no points to the corresponding EID slot, update to point to TLM slot.
|
||||
slot_no = p_reg->tlm_slot;
|
||||
}
|
||||
|
||||
// If TLM, update the TLM data.
|
||||
else if (p_reg->slots[slot_no].adv_frame.type == ES_FRAME_TYPE_TLM)
|
||||
{
|
||||
es_slot_tlm_update();
|
||||
}
|
||||
|
||||
es_data_array.p_data = (uint8_t *)&p_reg->slots[slot_no].adv_frame.frame;
|
||||
es_data_array.size = p_reg->slots[slot_no].adv_frame.length;
|
||||
|
||||
fill_adv_data(NULL, &es_data_array, p_adv_data);
|
||||
}
|
||||
73
components/ble/ble_services/eddystone/es_adv_frame.h
Normal file
73
components/ble/ble_services/eddystone/es_adv_frame.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#ifndef ES_ADV_FRAME_H__
|
||||
#define ES_ADV_FRAME_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include "ble_advdata.h"
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @addtogroup eddystone_adv
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**@brief Function for setting up connectable advertisement data using @ref
|
||||
* ble_advdata_encode.
|
||||
*
|
||||
* @param[in] p_scrsp_data Pointer to the scan response data that will be encoded.
|
||||
* @param[in,out] p_adv_data Pointer to the encoded advertising data (including scan response).
|
||||
*/
|
||||
void es_adv_frame_fill_connectable_adv_data(ble_advdata_t * p_scrsp_data, ble_gap_adv_data_t * const p_adv_data);
|
||||
|
||||
/**@brief Function for setting up non-connectable advertisement data using @ref
|
||||
* ble_advdata_encode.
|
||||
*
|
||||
* @param[in] slot_no Slot to fill in data for.
|
||||
* @param[in] etlm Flag that specifies if Eddystone-TLM is required.
|
||||
* @param[in,out] p_adv_data Pointer to the encoded advertising data (including scan response).
|
||||
*/
|
||||
void es_adv_frame_fill_non_connectable_adv_data(uint8_t slot_no, bool etlm, ble_gap_adv_data_t * const p_adv_data);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif // ES_ADV_FRAME_H__
|
||||
220
components/ble/ble_services/eddystone/es_adv_timing.c
Normal file
220
components/ble/ble_services/eddystone/es_adv_timing.c
Normal file
@@ -0,0 +1,220 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#include "app_timer.h"
|
||||
#include "es_adv_timing.h"
|
||||
#include "es_adv_timing_resolver.h"
|
||||
#include "es_slot.h"
|
||||
|
||||
|
||||
APP_TIMER_DEF(m_es_adv_interval_timer); //!< Timer for advertising the set of slots.
|
||||
APP_TIMER_DEF(m_es_slot_timer); //!< Timer for advertising individual slots.
|
||||
|
||||
static nrf_ble_escs_adv_interval_t m_current_adv_interval; //!< Current advertisement interval.
|
||||
static es_adv_timing_callback_t m_timing_mgr_callback; //!< Registered callback.
|
||||
static es_adv_timing_resolver_result_t m_adv_timing_result; //!< Current advertising timing result.
|
||||
static bool m_non_conn_adv_active; //!< Is the beacon advertising non-conn advertisements?
|
||||
|
||||
/**@brief Function for invoking registered callback.
|
||||
*
|
||||
* @param[in] p_evt Event to issue to callback.
|
||||
*/
|
||||
static void invoke_callback(const es_adv_timing_evt_t * p_evt)
|
||||
{
|
||||
if (m_timing_mgr_callback != NULL && m_non_conn_adv_active)
|
||||
{
|
||||
m_timing_mgr_callback(p_evt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if APP_CONFIG_TLM_ADV_INTERLEAVE_RATIO > 1
|
||||
static bool frame_to_adv_is_tlm(const es_adv_timing_evt_t * p_evt)
|
||||
{
|
||||
const es_slot_reg_t * p_reg = es_slot_get_registry();
|
||||
|
||||
return (p_reg->tlm_configured &&
|
||||
(p_evt->slot_no == p_reg->tlm_slot || p_evt->evt_id == ES_ADV_TIMING_EVT_ADV_ETLM));
|
||||
}
|
||||
|
||||
|
||||
static bool tlm_should_be_advertised(uint32_t adv_event_cnt)
|
||||
{
|
||||
return (adv_event_cnt % APP_CONFIG_TLM_ADV_INTERLEAVE_RATIO) == 0;
|
||||
}
|
||||
#endif // APP_CONFIG_TLM_ADV_INTERLEAVE_RATIO > 1
|
||||
|
||||
|
||||
/**@brief Timeout handler for the advertisement slot timer. */
|
||||
static void adv_slot_timeout(void * p_context)
|
||||
{
|
||||
|
||||
ret_code_t err_code;
|
||||
uint32_t active_slot_index = (uint32_t)p_context;
|
||||
|
||||
es_adv_timing_evt_t evt;
|
||||
|
||||
evt.slot_no = m_adv_timing_result.timing_results[active_slot_index].slot_no;
|
||||
|
||||
evt.evt_id = m_adv_timing_result.timing_results[active_slot_index].is_etlm
|
||||
? ES_ADV_TIMING_EVT_ADV_ETLM
|
||||
: ES_ADV_TIMING_EVT_ADV_SLOT;
|
||||
|
||||
// Trigger an event for the next slot if this slot is not the last to be advertised in this event.
|
||||
// Note: since we check 'm_adv_timing_result.len_timing_results > 1' we can safely cast the result of
|
||||
// the subtraction to a uint32.
|
||||
if (m_non_conn_adv_active && \
|
||||
m_adv_timing_result.len_timing_results > 1 && \
|
||||
active_slot_index < (uint32_t)(m_adv_timing_result.len_timing_results - 1))
|
||||
{
|
||||
err_code = app_timer_start( m_es_slot_timer,
|
||||
APP_TIMER_TICKS(m_adv_timing_result.timing_results[active_slot_index].delay_ms),
|
||||
(void*)(active_slot_index + 1));
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
|
||||
#if APP_CONFIG_TLM_ADV_INTERLEAVE_RATIO > 1
|
||||
static uint32_t adv_event_cnt = 0;
|
||||
|
||||
if (active_slot_index == 0)
|
||||
{
|
||||
adv_event_cnt++;
|
||||
}
|
||||
|
||||
if (frame_to_adv_is_tlm(&evt) && !tlm_should_be_advertised(adv_event_cnt))
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif // APP_CONFIG_TLM_ADV_INTERLEAVE_RATIO > 1
|
||||
|
||||
invoke_callback(&evt);
|
||||
}
|
||||
|
||||
|
||||
/**@brief Timeout handler for the advertisement interval timer. */
|
||||
static void adv_interval_timeout(void * p_context)
|
||||
{
|
||||
if (es_slot_get_registry()->num_configured_slots > 0)
|
||||
{
|
||||
// Trigger slot timeout for advertising the first slot.
|
||||
// Note: The slot number is not the index in the slot registry, it is the index of the active slots.
|
||||
adv_slot_timeout(NULL);
|
||||
}
|
||||
|
||||
if (m_non_conn_adv_active)
|
||||
{
|
||||
uint32_t err_code = app_timer_start(m_es_adv_interval_timer,
|
||||
APP_TIMER_TICKS(m_current_adv_interval),
|
||||
NULL);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void es_adv_timing_timers_init(void)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
|
||||
err_code = app_timer_create(&m_es_adv_interval_timer,
|
||||
APP_TIMER_MODE_SINGLE_SHOT,
|
||||
adv_interval_timeout);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
err_code = app_timer_create(&m_es_slot_timer,
|
||||
APP_TIMER_MODE_SINGLE_SHOT,
|
||||
adv_slot_timeout);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for finding and setting advertisement timing configuration. */
|
||||
static void adv_timing_set(void)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
const es_slot_reg_t * p_reg = es_slot_get_registry();
|
||||
|
||||
es_adv_timing_resolver_input_t resolver_input = {
|
||||
.adv_interval = m_current_adv_interval,
|
||||
.p_result = &m_adv_timing_result,
|
||||
.num_slots_configured = p_reg->num_configured_slots,
|
||||
.p_slots_configured = p_reg->slots_configured,
|
||||
.num_eid_slots_configured = p_reg->num_configured_eid_slots,
|
||||
.p_eid_slots_configured = p_reg->eid_slots_configured,
|
||||
.tlm_configured = p_reg->tlm_configured,
|
||||
.tlm_slot = p_reg->tlm_slot};
|
||||
|
||||
err_code = es_adv_timing_resolve(&resolver_input);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
|
||||
|
||||
void es_adv_timing_start(uint16_t adv_interval)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
|
||||
const es_slot_reg_t * p_reg = es_slot_get_registry();
|
||||
|
||||
m_non_conn_adv_active = true;
|
||||
|
||||
if (p_reg->num_configured_slots > 0)
|
||||
{
|
||||
m_current_adv_interval = adv_interval;
|
||||
|
||||
err_code = app_timer_start(m_es_adv_interval_timer,
|
||||
APP_TIMER_TICKS(m_current_adv_interval),
|
||||
NULL);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
adv_timing_set();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void es_adv_timing_stop(void)
|
||||
{
|
||||
m_non_conn_adv_active = false; // Stops timers from being re-fired.
|
||||
}
|
||||
|
||||
|
||||
void es_adv_timing_init(es_adv_timing_callback_t p_handler)
|
||||
{
|
||||
m_non_conn_adv_active = false;
|
||||
m_timing_mgr_callback = p_handler;
|
||||
memset(&m_adv_timing_result, 0, sizeof(m_adv_timing_result));
|
||||
}
|
||||
97
components/ble/ble_services/eddystone/es_adv_timing.h
Normal file
97
components/ble/ble_services/eddystone/es_adv_timing.h
Normal file
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#ifndef ES_ADV_TIMING_H__
|
||||
#define ES_ADV_TIMING_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @defgroup eddystone_adv_timing Timing
|
||||
* @brief Events and functions for advertisement timing.
|
||||
* @ingroup eddystone_adv
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**@brief Eddystone advertisement timing event types. */
|
||||
typedef enum
|
||||
{
|
||||
ES_ADV_TIMING_EVT_ADV_SLOT, //!< Advertising non-eTLM slot.
|
||||
ES_ADV_TIMING_EVT_ADV_ETLM //!< Advertising eTLM slot.
|
||||
} es_adv_timing_evt_id_t;
|
||||
|
||||
/**@brief Eddystone advertisement timing event. */
|
||||
typedef struct
|
||||
{
|
||||
es_adv_timing_evt_id_t evt_id; //!< Event type ID.
|
||||
uint8_t slot_no; /**< @brief Slot number.
|
||||
* @details For non-eTLM events: The slot number to advertise.
|
||||
*
|
||||
* For eTLM events: The slot number of the corresponding EID slot. */
|
||||
} es_adv_timing_evt_t;
|
||||
|
||||
/**@brief Eddystone advertisement timing event callback.
|
||||
*
|
||||
* @param[in] p_evt Pointer to the Eddystone advertisement timing event.
|
||||
*/
|
||||
typedef void (*es_adv_timing_callback_t)(const es_adv_timing_evt_t * p_evt);
|
||||
|
||||
/**@brief Function for starting Eddystone advertisement timing event generation. */
|
||||
void es_adv_timing_start(uint16_t adv_interval);
|
||||
|
||||
|
||||
/**@brief Function for stopping Eddystone advertisement timing event generation. */
|
||||
void es_adv_timing_stop(void);
|
||||
|
||||
/**@brief Function for initializing the Eddystone advertisement timers.
|
||||
*/
|
||||
void es_adv_timing_timers_init(void);
|
||||
|
||||
/**@brief Function for initializing the Eddystone advertisement timing module.
|
||||
*
|
||||
* @param[in] handler Eddystone advertisement timing event handler to register.
|
||||
*/
|
||||
void es_adv_timing_init(es_adv_timing_callback_t handler);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif // ES_ADV_TIMING_H__
|
||||
145
components/ble/ble_services/eddystone/es_adv_timing_resolver.c
Normal file
145
components/ble/ble_services/eddystone/es_adv_timing_resolver.c
Normal file
@@ -0,0 +1,145 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "es_adv_timing_resolver.h"
|
||||
#include "sdk_macros.h"
|
||||
|
||||
/**@brief Function for finding delay to use after each non-eTLM advertisement.
|
||||
*
|
||||
* @param[in] adv_interval Configured advertisement interval.
|
||||
* @param[in] num_slots_configured Number of configured slots.
|
||||
* @param[in] eTLM_required Is there an eTLM slot.
|
||||
*/
|
||||
static uint16_t get_adv_delay(uint16_t adv_interval,
|
||||
uint8_t num_slots_configured,
|
||||
bool eTLM_required)
|
||||
{
|
||||
// If eTLM is required, don't count this when calculating delay.
|
||||
return adv_interval / (num_slots_configured - (eTLM_required ? 1 : 0));
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for checking if given slot_no is an EID slot.
|
||||
*
|
||||
* @param[in] slot_no Slot number to check.
|
||||
* @param[in] p_eid_slots_configured Pointer to list of configured EID slots.
|
||||
* @param[in] num_eid_slots_configured Number of EID slots configured.
|
||||
*/
|
||||
static bool is_eid(uint8_t slot_no, const uint8_t * p_eid_slots_configured, uint8_t num_eid_slots_configured)
|
||||
{
|
||||
for (uint32_t i = 0; i < num_eid_slots_configured; ++i)
|
||||
{
|
||||
if (slot_no == p_eid_slots_configured[i])
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ret_code_t es_adv_timing_resolve(es_adv_timing_resolver_input_t * p_input)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_input);
|
||||
|
||||
uint8_t result_index = 0;
|
||||
bool eTLM_required = p_input->tlm_configured && p_input->num_eid_slots_configured > 0;
|
||||
uint16_t base_delay;
|
||||
|
||||
if (p_input->num_slots_configured == 0)
|
||||
{
|
||||
return NRF_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
base_delay = get_adv_delay(p_input->adv_interval, p_input->num_slots_configured, eTLM_required);
|
||||
|
||||
for (uint32_t i = 0; i < p_input->num_slots_configured; ++i)
|
||||
{
|
||||
uint8_t slot_no = p_input->p_slots_configured[i];
|
||||
|
||||
if (!(eTLM_required && slot_no == p_input->tlm_slot))
|
||||
{
|
||||
es_adv_timing_resolver_adv_timing_t * p_current_result = &p_input->p_result->timing_results[result_index];
|
||||
p_current_result->slot_no = slot_no;
|
||||
p_current_result->is_etlm = false;
|
||||
|
||||
// If an eTLM is to be advertised for this frame, this value will be changed.
|
||||
p_current_result->delay_ms = base_delay;
|
||||
|
||||
result_index++;
|
||||
|
||||
if (eTLM_required &&
|
||||
is_eid(slot_no, p_input->p_eid_slots_configured, p_input->num_eid_slots_configured))
|
||||
{
|
||||
es_adv_timing_resolver_adv_timing_t * p_eTLM_timing_result =
|
||||
&p_input->p_result->timing_results[result_index];
|
||||
|
||||
p_current_result->delay_ms = APP_CONFIG_ADV_FRAME_ETLM_SPACING_MS; // Update delay from EID to eTLM frame.
|
||||
|
||||
p_eTLM_timing_result->slot_no = slot_no; // Point to EID slot-no, as this will be
|
||||
// used for finding the correct EIK.
|
||||
p_eTLM_timing_result->is_etlm = true; // Configure as eTLM frame.
|
||||
|
||||
if (base_delay > APP_CONFIG_ADV_FRAME_ETLM_SPACING_MS)
|
||||
{
|
||||
p_eTLM_timing_result->delay_ms =
|
||||
base_delay -
|
||||
APP_CONFIG_ADV_FRAME_ETLM_SPACING_MS; // Set delay of eTLM frame.
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
p_eTLM_timing_result->delay_ms = APP_CONFIG_ADV_FRAME_SPACING_MS_MIN;
|
||||
}
|
||||
|
||||
result_index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
p_input->p_result->len_timing_results = result_index; // Note: index has been increased to equal length of result.
|
||||
|
||||
if (p_input->p_result->len_timing_results > 0)
|
||||
{
|
||||
p_input->p_result->timing_results[p_input->p_result->len_timing_results - 1].delay_ms = 0; // Last Slot does not need delay.
|
||||
}
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#ifndef ES_ADV_TIMING_RESOLVER_H__
|
||||
#define ES_ADV_TIMING_RESOLVER_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "es_app_config.h"
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @addtogroup eddystone_adv_timing
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @brief Timing parameters for a single slot. */
|
||||
typedef struct
|
||||
{
|
||||
bool is_etlm; //!< Flag that specifies if the slot is an eTLM.
|
||||
uint8_t slot_no; /**< @brief Slot number. @details
|
||||
* For non-eTLM slots: The slot number of the given frame.
|
||||
*
|
||||
* For eTLM slots: The slot number of the corresponding EID frame. */
|
||||
uint16_t delay_ms; //!< Delay from this frame to the next.
|
||||
} es_adv_timing_resolver_adv_timing_t;
|
||||
|
||||
/**@brief Results of calculating advertisement delays. */
|
||||
typedef struct
|
||||
{
|
||||
es_adv_timing_resolver_adv_timing_t timing_results[APP_MAX_ADV_SLOTS - APP_MAX_EID_SLOTS +
|
||||
(APP_MAX_EID_SLOTS * 2)]; //!< List of timing results.
|
||||
uint8_t len_timing_results; //!< Length of results.
|
||||
} es_adv_timing_resolver_result_t;
|
||||
|
||||
/**@brief Input to the timing resolver. */
|
||||
typedef struct
|
||||
{
|
||||
uint16_t adv_interval; //!< Global advertisement interval.
|
||||
uint8_t num_slots_configured; //!< Number of configured slots.
|
||||
const uint8_t * p_slots_configured; //!< Pointer to the list of configured slots.
|
||||
uint8_t num_eid_slots_configured; //!< Number of configured EID slots.
|
||||
const uint8_t * p_eid_slots_configured; //!< Pointer to the list of configured EID slots.
|
||||
bool tlm_configured; //!< Flag that specifies if TLM slot is configured.
|
||||
uint8_t tlm_slot; //!< Slot number of the TLM slot (if @p tlm_configured is true).
|
||||
es_adv_timing_resolver_result_t * p_result; //!< Output result.
|
||||
} es_adv_timing_resolver_input_t;
|
||||
|
||||
/**@brief Function for getting the input for advertisement interval calculation.
|
||||
*
|
||||
* @param[in,out] p_input Input to advertisement interval calculation (see @ref es_adv_timing_resolver_input_t).
|
||||
* @retval NRF_SUCCESS If the operation was successful. Otherwise, an error code is returned.
|
||||
*/
|
||||
ret_code_t es_adv_timing_resolve(es_adv_timing_resolver_input_t * p_input);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif // ES_ADV_TIMING_RESOLVER_H__
|
||||
66
components/ble/ble_services/eddystone/es_battery_voltage.h
Normal file
66
components/ble/ble_services/eddystone/es_battery_voltage.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#ifndef ES_BATTERY_VOLTAGE_H__
|
||||
#define ES_BATTERY_VOLTAGE_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @addtogroup eddystone_tlm
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**@brief Function for initializing the battery voltage module.
|
||||
*/
|
||||
void es_battery_voltage_init(void);
|
||||
|
||||
/**@brief Function for reading the battery voltage.
|
||||
*
|
||||
* @param[out] p_vbatt Pointer to the battery voltage value.
|
||||
*/
|
||||
void es_battery_voltage_get(uint16_t * p_vbatt);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif // ES_BATTERY_VOLTAGE_H__
|
||||
104
components/ble/ble_services/eddystone/es_battery_voltage_saadc.c
Normal file
104
components/ble/ble_services/eddystone/es_battery_voltage_saadc.c
Normal file
@@ -0,0 +1,104 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#include "es_battery_voltage.h"
|
||||
#include "nrf_drv_saadc.h"
|
||||
#include "sdk_macros.h"
|
||||
|
||||
#define ADC_REF_VOLTAGE_IN_MILLIVOLTS 600 //!< Reference voltage (in milli volts) used by ADC while doing conversion.
|
||||
#define DIODE_FWD_VOLT_DROP_MILLIVOLTS 270 //!< Typical forward voltage drop of the diode (Part no: SD103ATW-7-F) that is connected in series with the voltage supply. This is the voltage drop when the forward current is 1mA. Source: Data sheet of 'SURFACE MOUNT SCHOTTKY BARRIER DIODE ARRAY' available at www.diodes.com.
|
||||
#define ADC_RES_10BIT 1024 //!< Maximum digital value for 10-bit ADC conversion.
|
||||
#define ADC_PRE_SCALING_COMPENSATION 6 //!< The ADC is configured to use VDD with 1/3 prescaling as input. And hence the result of conversion is to be multiplied by 3 to get the actual value of the battery voltage.
|
||||
#define ADC_RESULT_IN_MILLI_VOLTS(ADC_VALUE) \
|
||||
((((ADC_VALUE) *ADC_REF_VOLTAGE_IN_MILLIVOLTS) / ADC_RES_10BIT) * ADC_PRE_SCALING_COMPENSATION)
|
||||
|
||||
static nrf_saadc_value_t adc_buf; //!< Buffer used for storing ADC value.
|
||||
static uint16_t m_batt_lvl_in_milli_volts; //!< Current battery level.
|
||||
|
||||
/**@brief Function handling events from 'nrf_drv_saadc.c'.
|
||||
*
|
||||
* @param[in] p_evt SAADC event.
|
||||
*/
|
||||
static void saadc_event_handler(nrf_drv_saadc_evt_t const * p_evt)
|
||||
{
|
||||
if (p_evt->type == NRF_DRV_SAADC_EVT_DONE)
|
||||
{
|
||||
nrf_saadc_value_t adc_result;
|
||||
|
||||
adc_result = p_evt->data.done.p_buffer[0];
|
||||
|
||||
m_batt_lvl_in_milli_volts =
|
||||
ADC_RESULT_IN_MILLI_VOLTS(adc_result) + DIODE_FWD_VOLT_DROP_MILLIVOLTS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void es_battery_voltage_init(void)
|
||||
{
|
||||
ret_code_t err_code = nrf_drv_saadc_init(NULL, saadc_event_handler);
|
||||
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
nrf_saadc_channel_config_t config =
|
||||
NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_VDD);
|
||||
err_code = nrf_drv_saadc_channel_init(0, &config);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
err_code = nrf_drv_saadc_buffer_convert(&adc_buf, 1);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
err_code = nrf_drv_saadc_sample();
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
|
||||
|
||||
void es_battery_voltage_get(uint16_t * p_vbatt)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL_VOID(p_vbatt);
|
||||
|
||||
*p_vbatt = m_batt_lvl_in_milli_volts;
|
||||
if (!nrf_drv_saadc_is_busy())
|
||||
{
|
||||
ret_code_t err_code = nrf_drv_saadc_buffer_convert(&adc_buf, 1);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
err_code = nrf_drv_saadc_sample();
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
}
|
||||
355
components/ble/ble_services/eddystone/es_flash.c
Normal file
355
components/ble/ble_services/eddystone/es_flash.c
Normal file
@@ -0,0 +1,355 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#include <string.h>
|
||||
#include "es_flash.h"
|
||||
#include "es_util.h"
|
||||
#include "app_scheduler.h"
|
||||
#include "ble_hci.h"
|
||||
#include "fds.h"
|
||||
#include "nrf_nvic.h"
|
||||
|
||||
#define SIZE_OF_PRIV_KEY ESCS_ECDH_KEY_SIZE //!< Size of ECDH private key.
|
||||
#define SIZE_OF_PUB_KEY ESCS_ECDH_KEY_SIZE //!< Size of ECDH public key.
|
||||
#define SIZE_OF_LOCK_KEY ESCS_AES_KEY_SIZE //!< Size of lock key.
|
||||
#define FILE_ID_ES_FLASH 0x1337 //!< File ID used for all flash access EXCEPT lock code.
|
||||
#define FILE_ID_ES_FLASH_LOCK_KEY 0x1338 //!< File ID used for lock code flash access.
|
||||
#define RECORD_KEY_FLAGS 0x1 //!< File record for flash flags.
|
||||
#define RECORD_KEY_PRIV_KEY 0x2 //!< File record for private key.
|
||||
#define RECORD_KEY_PUB_KEY 0x3 //!< File record for public key.
|
||||
#define RECORD_KEY_LOCK_KEY 0x4 //!< File record for lock key.
|
||||
#define RECORD_KEY_BEACON_CONFIG 0x5 //!< File record for lock key.
|
||||
|
||||
static uint16_t RECORD_KEY_SLOTS[5] = {0x6, 0x7, 0x8, 0x9, 0xa}; //!< File record for slots.
|
||||
|
||||
/**@brief Structure used for invoking flash access function. */
|
||||
typedef struct
|
||||
{
|
||||
uint16_t record_key;
|
||||
uint16_t file_id;
|
||||
uint8_t * p_data_buf;
|
||||
uint8_t * p_data;
|
||||
uint16_t size_bytes;
|
||||
es_flash_access_t access_type;
|
||||
} flash_access_params_t;
|
||||
|
||||
static volatile uint32_t m_num_pending_ops; //!< Current number of outstanding FDS operations.
|
||||
static volatile bool m_factory_reset_done; //!< Has a factory reset operation been completed.
|
||||
static uint16_t m_conn_handle = BLE_CONN_HANDLE_INVALID; //!< Current connection handle.
|
||||
|
||||
|
||||
#if APP_MAX_ADV_SLOTS > 32
|
||||
#error "APP_MAX_ADV_SLOTS must be <= 32"
|
||||
#endif
|
||||
|
||||
#define SLOT_DECL(i, _) __ALIGN(4) static uint8_t slot## i ##_buf[sizeof(es_slot_t)];
|
||||
EVAL(REPEAT(APP_MAX_ADV_SLOTS, SLOT_DECL, ~))
|
||||
|
||||
__ALIGN(4) static uint8_t lock_key_buf[SIZE_OF_LOCK_KEY]; //!< Buffer for lock key flash access.
|
||||
|
||||
#define SLOT(i, _) slot## i ##_buf,
|
||||
static uint8_t * slots_buf_p[APP_MAX_ADV_SLOTS] = {
|
||||
EVAL(REPEAT(APP_MAX_ADV_SLOTS, SLOT, ~))
|
||||
};
|
||||
|
||||
__ALIGN(4) static uint8_t flash_flags_buf[sizeof(es_flash_flags_t)]; //!< Buffer for flash flags flash access.
|
||||
__ALIGN(4) static uint8_t beacon_config_buf[sizeof(es_flash_beacon_config_t)]; //!< Buffer for beacon config flash access.
|
||||
|
||||
/**@brief Function handling scheduled FDS garbage collection. */
|
||||
static void fds_gc_event(void * p_event_data, uint16_t event_size)
|
||||
{
|
||||
ret_code_t fds_err_code;
|
||||
|
||||
fds_err_code = fds_gc();
|
||||
if (fds_err_code != NRF_SUCCESS)
|
||||
APP_ERROR_CHECK_BOOL(NRF_ERROR_INTERNAL);
|
||||
m_num_pending_ops++;
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function handling FDS events.
|
||||
*
|
||||
* @param[in] p_evt FDS event.
|
||||
*/
|
||||
static void fds_cb(fds_evt_t const * const p_evt)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
|
||||
switch (p_evt->id)
|
||||
{
|
||||
case FDS_EVT_INIT:
|
||||
m_num_pending_ops = 0;
|
||||
break;
|
||||
case FDS_EVT_DEL_FILE:
|
||||
if (p_evt->del.file_id == FILE_ID_ES_FLASH)
|
||||
{
|
||||
m_factory_reset_done = true;
|
||||
}
|
||||
// Fall through
|
||||
case FDS_EVT_DEL_RECORD:
|
||||
// Schedule garbage collection
|
||||
err_code = app_sched_event_put(NULL, 0, fds_gc_event);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
break;
|
||||
|
||||
case FDS_EVT_GC:
|
||||
// During factory reset, a file is deleted, and garbage collection is scheduled
|
||||
// when the callback for that deletion is invoked.
|
||||
// So here we know that the factory reset is completed.
|
||||
if (m_factory_reset_done)
|
||||
{
|
||||
if (m_conn_handle != BLE_CONN_HANDLE_INVALID)
|
||||
{
|
||||
err_code =
|
||||
sd_ble_gap_disconnect(m_conn_handle,
|
||||
BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_factory_reset_done = false;
|
||||
(void)sd_nvic_SystemReset();
|
||||
}
|
||||
}
|
||||
// Fall through:
|
||||
case FDS_EVT_UPDATE:
|
||||
// Fall through:
|
||||
case FDS_EVT_WRITE:
|
||||
if (m_num_pending_ops > 0)
|
||||
{
|
||||
m_num_pending_ops--;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function performing flash access (read/write/clear).
|
||||
*
|
||||
* @param[in] p_params Flash access parameters.
|
||||
*/
|
||||
static ret_code_t access_flash_data(const flash_access_params_t * p_params)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
fds_flash_record_t record = {0};
|
||||
fds_record_desc_t desc = {0};
|
||||
fds_find_token_t ft = {0};
|
||||
fds_record_t record_to_write =
|
||||
{
|
||||
.data.p_data = p_params->p_data_buf,
|
||||
.file_id = p_params->file_id
|
||||
};
|
||||
|
||||
err_code = fds_record_find_by_key(p_params->record_key, &desc, &ft);
|
||||
|
||||
// If its a read or clear, we can not accept errors on lookup
|
||||
if (p_params->access_type == ES_FLASH_ACCESS_READ)
|
||||
{
|
||||
RETURN_IF_ERROR(err_code);
|
||||
}
|
||||
|
||||
if (p_params->access_type == ES_FLASH_ACCESS_CLEAR && err_code == FDS_ERR_NOT_FOUND)
|
||||
{
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
switch (p_params->access_type)
|
||||
{
|
||||
case ES_FLASH_ACCESS_READ:
|
||||
err_code = fds_record_open(&desc, &record);
|
||||
RETURN_IF_ERROR(err_code);
|
||||
|
||||
memcpy(p_params->p_data, record.p_data, p_params->size_bytes);
|
||||
|
||||
err_code = fds_record_close(&desc);
|
||||
RETURN_IF_ERROR(err_code);
|
||||
|
||||
break;
|
||||
|
||||
case ES_FLASH_ACCESS_WRITE:
|
||||
memcpy(p_params->p_data_buf, p_params->p_data, p_params->size_bytes);
|
||||
|
||||
record_to_write.data.length_words = (p_params->size_bytes +3) / 4;
|
||||
record_to_write.key = p_params->record_key;
|
||||
|
||||
if (err_code == FDS_ERR_NOT_FOUND)
|
||||
{
|
||||
err_code = fds_record_write(&desc, &record_to_write);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
err_code = fds_record_update(&desc, &record_to_write);
|
||||
}
|
||||
|
||||
RETURN_IF_ERROR(err_code);
|
||||
m_num_pending_ops++;
|
||||
break;
|
||||
|
||||
case ES_FLASH_ACCESS_CLEAR:
|
||||
err_code = fds_record_delete(&desc);
|
||||
RETURN_IF_ERROR(err_code);
|
||||
m_num_pending_ops++;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
ret_code_t es_flash_access_lock_key(uint8_t * p_lock_key, es_flash_access_t access_type)
|
||||
{
|
||||
flash_access_params_t params = {.record_key = RECORD_KEY_LOCK_KEY,
|
||||
.file_id = FILE_ID_ES_FLASH_LOCK_KEY,
|
||||
.p_data_buf = lock_key_buf,
|
||||
.p_data = (uint8_t *)p_lock_key,
|
||||
.size_bytes = SIZE_OF_LOCK_KEY,
|
||||
.access_type = access_type};
|
||||
|
||||
return access_flash_data(¶ms);
|
||||
}
|
||||
|
||||
|
||||
ret_code_t es_flash_access_beacon_config(es_flash_beacon_config_t * p_config,
|
||||
es_flash_access_t access_type)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
|
||||
flash_access_params_t params = {.record_key = RECORD_KEY_BEACON_CONFIG,
|
||||
.file_id = FILE_ID_ES_FLASH,
|
||||
.p_data_buf = beacon_config_buf,
|
||||
.p_data = (uint8_t *)p_config,
|
||||
.size_bytes = sizeof(es_flash_beacon_config_t),
|
||||
.access_type = access_type};
|
||||
|
||||
err_code = access_flash_data(¶ms);
|
||||
|
||||
return err_code;
|
||||
}
|
||||
|
||||
|
||||
ret_code_t es_flash_access_slot_configs(uint8_t slot_no,
|
||||
es_slot_t * p_slot,
|
||||
es_flash_access_t access_type)
|
||||
{
|
||||
if (slot_no >= APP_MAX_ADV_SLOTS)
|
||||
{
|
||||
return NRF_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
flash_access_params_t params = {.record_key = RECORD_KEY_SLOTS[slot_no],
|
||||
.file_id = FILE_ID_ES_FLASH,
|
||||
.p_data_buf = slots_buf_p[slot_no],
|
||||
.p_data = (uint8_t *)p_slot,
|
||||
.size_bytes = sizeof(es_slot_t),
|
||||
.access_type = access_type};
|
||||
|
||||
return access_flash_data(¶ms);
|
||||
}
|
||||
|
||||
|
||||
ret_code_t es_flash_access_flags(es_flash_flags_t * p_flags, es_flash_access_t access_type)
|
||||
{
|
||||
flash_access_params_t params = {.record_key = RECORD_KEY_FLAGS,
|
||||
.file_id = FILE_ID_ES_FLASH,
|
||||
.p_data_buf = flash_flags_buf,
|
||||
.p_data = (uint8_t *)p_flags,
|
||||
.size_bytes = sizeof(es_flash_flags_t),
|
||||
.access_type = access_type};
|
||||
|
||||
return access_flash_data(¶ms);
|
||||
}
|
||||
|
||||
|
||||
ret_code_t es_flash_factory_reset(void)
|
||||
{
|
||||
// Delete everything except the lock key:
|
||||
ret_code_t ret_code = fds_file_delete(FILE_ID_ES_FLASH);
|
||||
|
||||
return ret_code;
|
||||
}
|
||||
|
||||
|
||||
uint32_t es_flash_num_pending_ops(void)
|
||||
{
|
||||
return m_num_pending_ops;
|
||||
}
|
||||
|
||||
|
||||
void es_flash_on_ble_evt(ble_evt_t const * p_evt)
|
||||
{
|
||||
switch (p_evt->header.evt_id)
|
||||
{
|
||||
case BLE_GAP_EVT_CONNECTED:
|
||||
m_conn_handle = p_evt->evt.common_evt.conn_handle;
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVT_DISCONNECTED:
|
||||
m_conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
if (m_factory_reset_done)
|
||||
{
|
||||
m_factory_reset_done = false;
|
||||
(void)sd_nvic_SystemReset();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ret_code_t es_flash_init(void)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
|
||||
m_num_pending_ops = 1; // Will be set to 0 when getting FDS_EVT_INIT event
|
||||
|
||||
m_conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
|
||||
m_factory_reset_done = false;
|
||||
|
||||
err_code = fds_register(fds_cb);
|
||||
RETURN_IF_ERROR(err_code);
|
||||
|
||||
err_code = fds_init();
|
||||
RETURN_IF_ERROR(err_code);
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
177
components/ble/ble_services/eddystone/es_flash.h
Normal file
177
components/ble/ble_services/eddystone/es_flash.h
Normal file
@@ -0,0 +1,177 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#ifndef ES_FLASH_H__
|
||||
#define ES_FLASH_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "es_slot.h"
|
||||
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @defgroup eddystone_flash Flash access
|
||||
* @brief Types and functions to access the flash of the Eddystone beacon.
|
||||
* @ingroup eddystone
|
||||
* @{
|
||||
*/
|
||||
|
||||
#define WORD_SIZE 4
|
||||
|
||||
#define FLASH_ACCES_ERROR_CHECK_ALLOW_NOT_FOUND(err_code) \
|
||||
if (err_code != (FDS_ERR_NOT_FOUND)) \
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
#define FLASH_OP_WAIT() \
|
||||
uint32_t pending_ops = es_flash_num_pending_ops(); \
|
||||
while (pending_ops != 0) \
|
||||
{ \
|
||||
pending_ops = es_flash_num_pending_ops(); \
|
||||
}
|
||||
|
||||
/**@brief Beacon configuration. */
|
||||
typedef struct
|
||||
{
|
||||
nrf_ble_escs_adv_interval_t adv_interval; //!< Advertising interval.
|
||||
bool remain_connectable; //!< Flag that specifies if the beacon should remain connectable.
|
||||
} es_flash_beacon_config_t;
|
||||
|
||||
/**@brief Structure for keeping track of which slot has a configuration that must be restored upon reboot.
|
||||
* @details The size of this structure must be word aligned and match the flash block size of 32 bytes.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
bool slot_is_empty[APP_MAX_ADV_SLOTS]; //!< Flag that indicates whether the slot is empty.
|
||||
uint8_t padding[WORD_SIZE - ((APP_MAX_ADV_SLOTS + 1) % WORD_SIZE)]; //!< Padding used to ensure word alignment.
|
||||
} es_flash_flags_t;
|
||||
|
||||
/**@brief Flash access types.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
ES_FLASH_ACCESS_READ, //!< Read data.
|
||||
ES_FLASH_ACCESS_WRITE, //!< Write data.
|
||||
ES_FLASH_ACCESS_CLEAR //!< Clear data.
|
||||
} es_flash_access_t;
|
||||
|
||||
/**@brief Function for accessing beacon configurations.
|
||||
*
|
||||
* @param[out,in] p_config Pointer to the beacon configuration buffer.
|
||||
* @param[in] access_type Access type (see @ref es_flash_access_t).
|
||||
* @return For possible return values, see:
|
||||
* - @ref fds_record_find_by_key
|
||||
* - @ref fds_record_open
|
||||
* - @ref fds_record_close
|
||||
* - @ref fds_record_write
|
||||
* - @ref fds_record_update
|
||||
* - @ref fds_record_delete
|
||||
*/
|
||||
ret_code_t es_flash_access_beacon_config(es_flash_beacon_config_t * p_config,
|
||||
es_flash_access_t access_type);
|
||||
|
||||
/**@brief Function for accessing slot configuration from flash.
|
||||
*
|
||||
* @param[in] slot_no Slot index.
|
||||
* @param[out,in] p_slot Pointer to the slot configuration buffer.
|
||||
* @param[in] access_type Access type (see @ref es_flash_access_t).
|
||||
* @return For possible return values, see:
|
||||
* - @ref fds_record_find_by_key
|
||||
* - @ref fds_record_open
|
||||
* - @ref fds_record_close
|
||||
* - @ref fds_record_write
|
||||
* - @ref fds_record_update
|
||||
* - @ref fds_record_delete
|
||||
*/
|
||||
ret_code_t es_flash_access_slot_configs(uint8_t slot_no,
|
||||
es_slot_t * p_slot,
|
||||
es_flash_access_t access_type);
|
||||
|
||||
|
||||
/**@brief Function for accessing the beacon lock key from flash.
|
||||
*
|
||||
* @param[out,in] p_lock_key Pointer to the lock key buffer.
|
||||
* @param[in] access_type Access type (see @ref es_flash_access_t).
|
||||
* @return For possible return values, see:
|
||||
* - @ref fds_record_find_by_key
|
||||
* - @ref fds_record_open
|
||||
* - @ref fds_record_close
|
||||
* - @ref fds_record_write
|
||||
* - @ref fds_record_update
|
||||
* - @ref fds_record_delete
|
||||
*/
|
||||
ret_code_t es_flash_access_lock_key(uint8_t * p_lock_key, es_flash_access_t access_type);
|
||||
|
||||
/**@brief Function for accessing the flash configuration flag from flash.
|
||||
*
|
||||
* @param[out,in] p_flags Pointer to the flag buffer.
|
||||
* @param[in] access_type Access type (see @ref es_flash_access_t).
|
||||
* @return For possible return values, see:
|
||||
* - @ref fds_record_find_by_key
|
||||
* - @ref fds_record_open
|
||||
* - @ref fds_record_close
|
||||
* - @ref fds_record_write
|
||||
* - @ref fds_record_update
|
||||
* - @ref fds_record_delete
|
||||
*/
|
||||
ret_code_t es_flash_access_flags(es_flash_flags_t * p_flags, es_flash_access_t access_type);
|
||||
|
||||
/**@brief Function for retrieving the number of queued operations.
|
||||
* @return The number of operations that are queued.
|
||||
*/
|
||||
uint32_t es_flash_num_pending_ops(void);
|
||||
|
||||
/**@brief Function for performing a factory reset.
|
||||
* @return FDS return code.
|
||||
*/
|
||||
ret_code_t es_flash_factory_reset(void);
|
||||
|
||||
void es_flash_on_ble_evt(ble_evt_t const * p_evt);
|
||||
|
||||
/**@brief Function for initializing the flash module.
|
||||
*
|
||||
* @return See @ref fds_init for possible return values.
|
||||
*/
|
||||
ret_code_t es_flash_init(void);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif // ES_FLASH_H__
|
||||
186
components/ble/ble_services/eddystone/es_gatts.c
Normal file
186
components/ble/ble_services/eddystone/es_gatts.c
Normal file
@@ -0,0 +1,186 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "es_gatts.h"
|
||||
#include "es_gatts_read.h"
|
||||
#include "es_gatts_write.h"
|
||||
#include "es_slot.h"
|
||||
|
||||
static uint8_t m_active_slot;
|
||||
|
||||
/**@brief Function checking if beacon is unlocked.
|
||||
*
|
||||
* @param[in] p_escs Pointer to Eddystone Configuration Service.
|
||||
*
|
||||
* @retval true If beacon is unlocked.
|
||||
* @retval false If beacon is locked.
|
||||
*/
|
||||
static bool is_beacon_unlocked(const nrf_ble_escs_t * p_escs)
|
||||
{
|
||||
return p_escs->lock_state != NRF_BLE_ESCS_LOCK_STATE_LOCKED;
|
||||
}
|
||||
|
||||
|
||||
ret_code_t es_gatts_send_reply(nrf_ble_escs_t * p_escs,
|
||||
ble_gatts_rw_authorize_reply_params_t * p_reply)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_escs);
|
||||
VERIFY_PARAM_NOT_NULL(p_reply);
|
||||
|
||||
if (p_escs->conn_handle != BLE_CONN_HANDLE_INVALID)
|
||||
{
|
||||
return sd_ble_gatts_rw_authorize_reply(p_escs->conn_handle, p_reply);
|
||||
}
|
||||
|
||||
return NRF_ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
|
||||
ret_code_t es_gatts_send_op_not_permitted(nrf_ble_escs_t * p_escs, bool read)
|
||||
{
|
||||
ble_gatts_rw_authorize_reply_params_t reply = {0};
|
||||
|
||||
VERIFY_PARAM_NOT_NULL(p_escs);
|
||||
|
||||
if (read)
|
||||
{
|
||||
reply.type = BLE_GATTS_AUTHORIZE_TYPE_READ;
|
||||
reply.params.read.gatt_status = BLE_GATT_STATUS_ATTERR_READ_NOT_PERMITTED;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE;
|
||||
reply.params.write.gatt_status = BLE_GATT_STATUS_ATTERR_WRITE_NOT_PERMITTED;
|
||||
}
|
||||
|
||||
return es_gatts_send_reply(p_escs, &reply);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void es_gatts_handle_write(nrf_ble_escs_t * p_escs,
|
||||
uint16_t uuid,
|
||||
uint16_t val_handle,
|
||||
uint8_t const * p_data,
|
||||
uint16_t length)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
|
||||
if (is_beacon_unlocked(p_escs))
|
||||
{
|
||||
if (uuid == BLE_UUID_ESCS_UNLOCK_CHAR)
|
||||
{
|
||||
err_code = es_gatts_send_op_not_permitted(p_escs, false);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
err_code = es_gatts_write_handle_unlocked_write(
|
||||
p_escs, uuid, val_handle, p_data, length, m_active_slot);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if (uuid == BLE_UUID_ESCS_UNLOCK_CHAR)
|
||||
{
|
||||
err_code = es_gatts_write_handle_unlock(p_escs, p_data, length, val_handle);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
err_code = es_gatts_send_op_not_permitted(p_escs, false);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void es_gatts_handle_read(nrf_ble_escs_t * p_escs, uint16_t uuid, uint16_t val_handle)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
|
||||
if (is_beacon_unlocked(p_escs))
|
||||
{
|
||||
if (uuid == BLE_UUID_ESCS_UNLOCK_CHAR)
|
||||
{
|
||||
err_code = es_gatts_send_op_not_permitted(p_escs, true);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
err_code = es_gatts_read_handle_unlocked_read(p_escs, uuid, val_handle, m_active_slot);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
}
|
||||
|
||||
else // Beacon is locked.
|
||||
{
|
||||
if (uuid == BLE_UUID_ESCS_UNLOCK_CHAR)
|
||||
{
|
||||
err_code = es_gatts_read_handle_unlock(p_escs);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
err_code = es_gatts_read_handle_locked_read(p_escs, uuid);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ret_code_t es_gatts_init(nrf_ble_escs_t * p_ble_escs)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_ble_escs);
|
||||
|
||||
m_active_slot = 0;
|
||||
|
||||
p_ble_escs->p_active_slot = &m_active_slot;
|
||||
p_ble_escs->lock_state = NRF_BLE_ESCS_LOCK_STATE_LOCKED;
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
109
components/ble/ble_services/eddystone/es_gatts.h
Normal file
109
components/ble/ble_services/eddystone/es_gatts.h
Normal file
@@ -0,0 +1,109 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ES_GATTS_H__
|
||||
#define ES_GATTS_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include "nrf_ble_escs.h"
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @defgroup eddystone_gatts GATTS
|
||||
* @brief Functions for handling GATTS write and read requests.
|
||||
* @ingroup eddystone
|
||||
* @{
|
||||
*/
|
||||
|
||||
ret_code_t es_gatts_init(nrf_ble_escs_t * p_ble_escs);
|
||||
|
||||
/**@brief Function for handling all write requests from the Central.
|
||||
*
|
||||
* @param[in] p_escs Pointer to the Eddystone Configuration Service.
|
||||
* @param[in] uuid The UUID of the characteristic that is being written to.
|
||||
* @param[in] val_handle Value handle field of the characteristic handle of the characteristic that is being written to.
|
||||
* @param[in] p_data Pointer to the data to be written.
|
||||
* @param[in] length Length of the data to be written.
|
||||
*
|
||||
*/
|
||||
void es_gatts_handle_write(nrf_ble_escs_t * p_escs,
|
||||
uint16_t uuid,
|
||||
uint16_t val_handle,
|
||||
uint8_t const * p_data,
|
||||
uint16_t length);
|
||||
|
||||
|
||||
/**@brief Function for handling all read requests from the Central.
|
||||
*
|
||||
* @param[in] p_escs Pointer to the Eddystone Configuration Service.
|
||||
* @param[in] uuid The UUID of the characteristic that is being read from.
|
||||
* @param[in] val_handle Value handle field of the characteristic handle of the characteristic that is being read from.
|
||||
*
|
||||
*/
|
||||
void es_gatts_handle_read(nrf_ble_escs_t * p_escs, uint16_t uuid, uint16_t val_handle);
|
||||
|
||||
/**@brief Function for sending an RW-authorization reply.
|
||||
*
|
||||
* @param[in] p_escs Pointer to the Eddystone Configuration Service.
|
||||
* @param[in] p_reply Pointer to the reply to send.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the reply was successfully issued to the SoftDevice.
|
||||
* @retval NRF_ERROR_NULL If either of the pointers @p p_escs or @p p_reply is NULL.
|
||||
* @retval NRF_ERROR_INVALID_STATE If the connection handle of @p p_escs is invalid.
|
||||
* @return Otherwise, an error code from sd_ble_gatts_rw_authorize_reply() is returned.
|
||||
*/
|
||||
ret_code_t es_gatts_send_reply(nrf_ble_escs_t * p_escs, ble_gatts_rw_authorize_reply_params_t * p_reply);
|
||||
|
||||
/**@brief Function for sending an RW-authorization reply with status 'Operation not permitted'.
|
||||
*
|
||||
* @param[in] p_escs Pointer to the Eddystone Configuration Service.
|
||||
* @param[in] op_is_read Flag that specifies if the operation being responded to is a 'read' operation.
|
||||
If false, a 'write' operation is assumed.
|
||||
*
|
||||
* @retval NRF_ERROR_NULL If @p p_escs is NULL.
|
||||
* @return Otherwise, the error code from es_gatts_send_reply() is returned.
|
||||
*/
|
||||
ret_code_t es_gatts_send_op_not_permitted(nrf_ble_escs_t * p_escs, bool op_is_read);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif // ES_GATTS_H__
|
||||
245
components/ble/ble_services/eddystone/es_gatts_read.c
Normal file
245
components/ble/ble_services/eddystone/es_gatts_read.c
Normal file
@@ -0,0 +1,245 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "es_gatts_read.h"
|
||||
#include "es_adv.h"
|
||||
#include "es_gatts.h"
|
||||
#include "es_security.h"
|
||||
#include "es_slot.h"
|
||||
|
||||
static ret_code_t send_read_reply(nrf_ble_escs_t * p_escs, ble_gatts_rw_authorize_reply_params_t * p_reply)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_escs);
|
||||
VERIFY_PARAM_NOT_NULL(p_reply);
|
||||
|
||||
p_reply->type = BLE_GATTS_AUTHORIZE_TYPE_READ;
|
||||
p_reply->params.read.update = 1;
|
||||
p_reply->params.read.offset = 0;
|
||||
|
||||
return es_gatts_send_reply(p_escs, p_reply);
|
||||
}
|
||||
|
||||
|
||||
static ret_code_t read_value(nrf_ble_escs_t * p_escs, uint8_t length, const void * p_value)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_escs);
|
||||
VERIFY_PARAM_NOT_NULL(p_value);
|
||||
|
||||
ble_gatts_rw_authorize_reply_params_t reply = {0};
|
||||
reply.params.read.len = length;
|
||||
reply.params.read.p_data = p_value;
|
||||
reply.params.read.gatt_status = BLE_GATT_STATUS_SUCCESS;
|
||||
|
||||
return send_read_reply(p_escs, &reply);
|
||||
}
|
||||
|
||||
|
||||
static ret_code_t read_from_gattdb(nrf_ble_escs_t * p_escs, uint16_t val_handle)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_escs);
|
||||
|
||||
ret_code_t err_code;
|
||||
|
||||
// Go straight to the characteristic
|
||||
uint8_t value_buffer[ESCS_ADV_SLOT_CHAR_LENGTH_MAX] = {0};
|
||||
ble_gatts_value_t value = {.len = sizeof(value_buffer),
|
||||
.offset = 0,
|
||||
.p_value = &(value_buffer[0])};
|
||||
|
||||
err_code = sd_ble_gatts_value_get(p_escs->conn_handle, val_handle, &value);
|
||||
RETURN_IF_ERROR(err_code);
|
||||
|
||||
return read_value(p_escs, value.len, value.p_value);
|
||||
}
|
||||
|
||||
|
||||
static ret_code_t read_adv_slot(nrf_ble_escs_t * p_escs, uint8_t active_slot, const es_slot_reg_t * p_reg)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_escs);
|
||||
|
||||
ble_gatts_rw_authorize_reply_params_t reply = {0};
|
||||
uint8_t eid_buf[14];
|
||||
|
||||
// If an EID slot is read, load scaler, clock value and ephemeral ID.
|
||||
if (p_reg->slots[active_slot].adv_frame.type == ES_FRAME_TYPE_EID)
|
||||
{
|
||||
/*lint -save -e666 */
|
||||
uint32_t clock_value = es_security_clock_get(active_slot);
|
||||
clock_value = BYTES_REVERSE_32BIT(clock_value);
|
||||
/*lint -restore */
|
||||
|
||||
reply.params.read.len = ES_EID_GATTS_READ_LENGTH;
|
||||
|
||||
// Fill EID buffer with data
|
||||
eid_buf[ES_EID_GATTS_READ_FRAME_TYPE_IDX] = ES_FRAME_TYPE_EID;
|
||||
eid_buf[ES_EID_GATTS_READ_EXPONENT_IDX] = es_security_scaler_get(active_slot);
|
||||
|
||||
memcpy(&eid_buf[ES_EID_GATTS_READ_CLCK_VALUE_IDX], &clock_value, sizeof(clock_value));
|
||||
/*lint -save -e545 */
|
||||
memcpy(&eid_buf[ES_EID_GATTS_READ_EID_IDX],
|
||||
&p_reg->slots[active_slot].adv_frame.frame.eid.eid,
|
||||
ES_EID_ID_LENGTH);
|
||||
/*lint -restore */
|
||||
reply.params.read.p_data = eid_buf;
|
||||
}
|
||||
|
||||
// Otherwise, simply load the contents of the frame.
|
||||
else
|
||||
{
|
||||
// Check if slot being read is an eTLM slot.
|
||||
if ((p_reg->num_configured_eid_slots > 0) && p_reg->tlm_configured && (p_reg->tlm_slot == active_slot))
|
||||
{
|
||||
// Fill eTLM slot using EID key from first EID slot.
|
||||
es_slot_etlm_update(p_reg->eid_slots_configured[0]);
|
||||
}
|
||||
reply.params.read.len = p_reg->slots[active_slot].adv_frame.length;
|
||||
reply.params.read.p_data = (uint8_t *)&p_reg->slots[active_slot].adv_frame.frame;
|
||||
}
|
||||
|
||||
reply.params.read.gatt_status = BLE_GATT_STATUS_SUCCESS;
|
||||
|
||||
return send_read_reply(p_escs, &reply);
|
||||
}
|
||||
|
||||
|
||||
ret_code_t es_gatts_read_handle_locked_read(nrf_ble_escs_t * p_escs, uint16_t uuid)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_escs);
|
||||
|
||||
if (uuid == BLE_UUID_ESCS_REMAIN_CONNECTABLE_CHAR)
|
||||
{
|
||||
uint8_t retval = APP_IS_REMAIN_CONNECTABLE_SUPPORTED;
|
||||
return read_value(p_escs, sizeof(retval), &retval);
|
||||
}
|
||||
|
||||
else if (uuid == BLE_UUID_ESCS_LOCK_STATE_CHAR)
|
||||
{
|
||||
return read_value(p_escs, ESCS_LOCK_STATE_READ_LENGTH, &p_escs->lock_state);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
return es_gatts_send_op_not_permitted(p_escs, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ret_code_t es_gatts_read_handle_unlock(nrf_ble_escs_t * p_escs)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_escs);
|
||||
|
||||
ret_code_t err_code;
|
||||
uint8_t key_buff[ESCS_AES_KEY_SIZE];
|
||||
|
||||
err_code = es_security_random_challenge_generate(key_buff);
|
||||
RETURN_IF_ERROR(err_code);
|
||||
|
||||
es_security_unlock_prepare(key_buff);
|
||||
|
||||
return read_value(p_escs, ESCS_AES_KEY_SIZE, key_buff);
|
||||
}
|
||||
|
||||
|
||||
ret_code_t es_gatts_read_handle_unlocked_read(nrf_ble_escs_t * p_escs,
|
||||
uint16_t uuid,
|
||||
uint16_t val_handle,
|
||||
uint8_t active_slot)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_escs);
|
||||
|
||||
const es_slot_reg_t * p_reg = es_slot_get_registry();
|
||||
|
||||
switch (uuid)
|
||||
{
|
||||
case BLE_UUID_ESCS_BROADCAST_CAP_CHAR:
|
||||
case BLE_UUID_ESCS_UNLOCK_CHAR:
|
||||
case BLE_UUID_ESCS_PUBLIC_ECDH_KEY_CHAR:
|
||||
case BLE_UUID_ESCS_ACTIVE_SLOT_CHAR:
|
||||
return read_from_gattdb(p_escs, val_handle);
|
||||
|
||||
case BLE_UUID_ESCS_LOCK_STATE_CHAR:
|
||||
return read_value(p_escs, ESCS_LOCK_STATE_READ_LENGTH, &p_escs->lock_state);
|
||||
|
||||
case BLE_UUID_ESCS_ADV_INTERVAL_CHAR:
|
||||
{
|
||||
nrf_ble_escs_adv_interval_t adv_interval = es_adv_interval_get();
|
||||
adv_interval = BYTES_SWAP_16BIT(adv_interval);
|
||||
return read_value(p_escs, sizeof(adv_interval), &adv_interval);
|
||||
}
|
||||
|
||||
case BLE_UUID_ESCS_RADIO_TX_PWR_CHAR:
|
||||
return read_value(p_escs,
|
||||
sizeof(nrf_ble_escs_radio_tx_pwr_t),
|
||||
&p_reg->slots[active_slot].radio_tx_pwr);
|
||||
|
||||
case BLE_UUID_ESCS_ADV_TX_PWR_CHAR:
|
||||
return read_value(p_escs,
|
||||
sizeof(nrf_ble_escs_radio_tx_pwr_t),
|
||||
p_reg->slots[active_slot].adv_custom_tx_power
|
||||
? (uint8_t *)(&p_reg->slots[active_slot].custom_tx_power)
|
||||
: (uint8_t *)(&p_reg->slots[active_slot].radio_tx_pwr));
|
||||
|
||||
case BLE_UUID_ESCS_REMAIN_CONNECTABLE_CHAR:
|
||||
{
|
||||
uint8_t retval = APP_IS_REMAIN_CONNECTABLE_SUPPORTED;
|
||||
return read_value(p_escs, sizeof(retval), &retval);
|
||||
}
|
||||
|
||||
case BLE_UUID_ESCS_EID_ID_KEY_CHAR:
|
||||
if (p_reg->slots[active_slot].configured &&
|
||||
(p_reg->slots[active_slot].adv_frame.type == ES_FRAME_TYPE_EID))
|
||||
{
|
||||
return read_value(p_escs,
|
||||
sizeof(nrf_ble_escs_eid_id_key_t),
|
||||
&p_reg->slots[active_slot].encrypted_eid_id_key);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
return es_gatts_send_op_not_permitted(p_escs, true);
|
||||
}
|
||||
|
||||
case BLE_UUID_ESCS_RW_ADV_SLOT_CHAR:
|
||||
return read_adv_slot(p_escs, active_slot, p_reg);
|
||||
|
||||
default:
|
||||
return NRF_ERROR_INVALID_PARAM;
|
||||
}
|
||||
}
|
||||
71
components/ble/ble_services/eddystone/es_gatts_read.h
Normal file
71
components/ble/ble_services/eddystone/es_gatts_read.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ES_GATTS_READ_H__
|
||||
#define ES_GATTS_READ_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include "nrf_ble_escs.h"
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @defgroup eddystone_gatts_read GATTS read
|
||||
* @brief Functions for handling GATTS read requests.
|
||||
* @ingroup eddystone_gatts
|
||||
* @{
|
||||
*/
|
||||
|
||||
ret_code_t es_gatts_read_send_not_permitted(nrf_ble_escs_t * p_escs);
|
||||
|
||||
ret_code_t es_gatts_read_handle_unlocked_read(nrf_ble_escs_t * p_escs,
|
||||
uint16_t uuid,
|
||||
uint16_t val_handle,
|
||||
uint8_t active_slot);
|
||||
|
||||
ret_code_t es_gatts_read_handle_unlock(nrf_ble_escs_t * p_escs);
|
||||
|
||||
ret_code_t es_gatts_read_handle_locked_read(nrf_ble_escs_t * p_escs,
|
||||
uint16_t uuid);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif // ES_GATTS_READ_H__
|
||||
254
components/ble/ble_services/eddystone/es_gatts_write.c
Normal file
254
components/ble/ble_services/eddystone/es_gatts_write.c
Normal file
@@ -0,0 +1,254 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "es_gatts_write.h"
|
||||
#include "es_adv.h"
|
||||
#include "es_flash.h"
|
||||
#include "es_gatts.h"
|
||||
#include "es_security.h"
|
||||
|
||||
|
||||
static ret_code_t send_write_reply(nrf_ble_escs_t * p_escs, ble_gatts_rw_authorize_reply_params_t * p_reply)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_escs);
|
||||
VERIFY_PARAM_NOT_NULL(p_reply);
|
||||
|
||||
p_reply->type = BLE_GATTS_AUTHORIZE_TYPE_WRITE;
|
||||
p_reply->params.write.update = 1;
|
||||
p_reply->params.write.offset = 0;
|
||||
|
||||
return es_gatts_send_reply(p_escs, p_reply);
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function checking if length of event is correct, given the frame data.
|
||||
*
|
||||
* @param[in] p_data Written ADV Slot data.
|
||||
* @param[in] length Written length.
|
||||
*
|
||||
* @retval true If length is valid.
|
||||
* @retval false If length is not valid.
|
||||
*/
|
||||
static bool length_is_valid(uint8_t const * p_data, uint8_t length)
|
||||
{
|
||||
if (length == 0 || (length == 1 && p_data[0] == 0))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
switch ((es_frame_type_t)p_data[0])
|
||||
{
|
||||
case ES_FRAME_TYPE_UID:
|
||||
return length == ESCS_UID_WRITE_LENGTH;
|
||||
|
||||
case ES_FRAME_TYPE_URL:
|
||||
return ((length >= ESCS_URL_MIN_WRITE_LENGTH) && (length <= ESCS_URL_WRITE_LENGTH));
|
||||
|
||||
case ES_FRAME_TYPE_TLM:
|
||||
return (length == ESCS_TLM_WRITE_LENGTH);
|
||||
|
||||
case ES_FRAME_TYPE_EID:
|
||||
return ((length == ESCS_EID_WRITE_ECDH_LENGTH) ||
|
||||
(length == ESCS_EID_WRITE_IDK_LENGTH));
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ret_code_t es_gatts_write_handle_unlocked_write(nrf_ble_escs_t * p_escs,
|
||||
uint16_t uuid,
|
||||
uint16_t val_handle,
|
||||
uint8_t const * p_data,
|
||||
uint16_t length,
|
||||
uint8_t active_slot)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_escs);
|
||||
VERIFY_PARAM_NOT_NULL(p_data);
|
||||
|
||||
ret_code_t err_code;
|
||||
ble_gatts_rw_authorize_reply_params_t reply = {0};
|
||||
bool long_write = false;
|
||||
|
||||
reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
|
||||
|
||||
switch (uuid)
|
||||
{
|
||||
case BLE_UUID_ESCS_ACTIVE_SLOT_CHAR:
|
||||
if (*p_data > APP_MAX_ADV_SLOTS - 1)
|
||||
{
|
||||
// Invalid Attribute Length: for an attempt to write illegal values.
|
||||
// The beacon will list the total number of available slots in the
|
||||
// max_supported_total_slots field in the Capabilities characteristic.
|
||||
reply.params.write.gatt_status = BLE_GATT_STATUS_ATTERR_INVALID_ATT_VAL_LENGTH;
|
||||
length = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case BLE_UUID_ESCS_ADV_INTERVAL_CHAR:
|
||||
es_adv_interval_set(BYTES_SWAP_16BIT(*(nrf_ble_escs_adv_interval_t *)p_data));
|
||||
break;
|
||||
|
||||
case BLE_UUID_ESCS_RADIO_TX_PWR_CHAR:
|
||||
es_slot_radio_tx_pwr_set(active_slot, *(nrf_ble_escs_radio_tx_pwr_t *)(p_data));
|
||||
break;
|
||||
|
||||
case BLE_UUID_ESCS_ADV_TX_PWR_CHAR:
|
||||
// Update slot info so that ADV data will only be read from what is written by client.
|
||||
es_slot_set_adv_custom_tx_power(active_slot, *(nrf_ble_escs_radio_tx_pwr_t *)(p_data));
|
||||
break;
|
||||
|
||||
case BLE_UUID_ESCS_LOCK_STATE_CHAR:
|
||||
if (length == 1 && (*p_data == NRF_BLE_ESCS_LOCK_BYTE_LOCK ||
|
||||
*p_data == NRF_BLE_ESCS_LOCK_BYTE_DISABLE_AUTO_RELOCK))
|
||||
{
|
||||
// Do nothing special, allow the write.
|
||||
}
|
||||
else if (length == ESCS_LOCK_STATE_NEW_LOCK_CODE_WRITE_LENGTH &&
|
||||
*p_data == NRF_BLE_ESCS_LOCK_BYTE_LOCK)
|
||||
{
|
||||
// 0x00 + key[16] : transition to lock state and update the lock code.
|
||||
err_code = es_security_lock_code_update((uint8_t*)(p_data) + 1);
|
||||
RETURN_IF_ERROR(err_code);
|
||||
|
||||
// Only write the lock byte (0x00) to the characteristic, so set length to 1.
|
||||
length = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Any invalid values locks the characteristic by default.
|
||||
(*(uint8_t*)p_data) = NRF_BLE_ESCS_LOCK_BYTE_LOCK;
|
||||
length = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case BLE_UUID_ESCS_RW_ADV_SLOT_CHAR:
|
||||
if (length > 20)
|
||||
{
|
||||
long_write = true;
|
||||
}
|
||||
reply.params.write.gatt_status = length_is_valid(p_data, length)
|
||||
? BLE_GATT_STATUS_SUCCESS
|
||||
: BLE_GATT_STATUS_ATTERR_INVALID_ATT_VAL_LENGTH;
|
||||
|
||||
if (reply.params.write.gatt_status == BLE_GATT_STATUS_SUCCESS)
|
||||
{
|
||||
es_slot_on_write(active_slot, length, p_data);
|
||||
es_adv_interval_set(es_adv_interval_get()); // Ensure that valid advertisement interval is used.
|
||||
}
|
||||
break;
|
||||
|
||||
case BLE_UUID_ESCS_FACTORY_RESET_CHAR:
|
||||
if (*p_data == 0x0B)
|
||||
{
|
||||
err_code = es_flash_factory_reset();
|
||||
RETURN_IF_ERROR(err_code);
|
||||
}
|
||||
break;
|
||||
|
||||
case BLE_UUID_ESCS_REMAIN_CONNECTABLE_CHAR:
|
||||
#if APP_IS_REMAIN_CONNECTABLE_SUPPORTED == ESCS_FUNCT_REMAIN_CONNECTABLE_SUPPORTED_Yes
|
||||
if (*p_data != 0)
|
||||
{
|
||||
es_adv_remain_connectable_set(true);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
es_adv_remain_connectable_set(false);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
reply.params.write.len = length;
|
||||
reply.params.write.p_data = p_data;
|
||||
|
||||
if (!long_write)
|
||||
{
|
||||
return send_write_reply(p_escs, &reply);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ret_code_t es_gatts_write_handle_unlock(nrf_ble_escs_t * p_escs,
|
||||
uint8_t const * p_data,
|
||||
uint16_t length,
|
||||
uint16_t val_handle)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_escs);
|
||||
VERIFY_PARAM_NOT_NULL(p_data);
|
||||
|
||||
ret_code_t err_code;
|
||||
ble_gatts_rw_authorize_reply_params_t reply = {0};
|
||||
ble_gatts_value_t value = {.len = length, .offset = 0, .p_value = (uint8_t*)p_data};
|
||||
|
||||
if (length == ESCS_AES_KEY_SIZE)
|
||||
{
|
||||
err_code = sd_ble_gatts_value_set(p_escs->conn_handle, val_handle, &value);
|
||||
|
||||
if (err_code == NRF_SUCCESS)
|
||||
{
|
||||
reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
|
||||
es_security_unlock_verify((value.p_value));
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
reply.params.write.gatt_status = BLE_GATT_STATUS_ATTERR_WRITE_NOT_PERMITTED;
|
||||
}
|
||||
}
|
||||
|
||||
reply.params.write.len = length;
|
||||
reply.params.write.p_data = (const uint8_t *)value.p_value;
|
||||
|
||||
return send_write_reply(p_escs, &reply);
|
||||
}
|
||||
71
components/ble/ble_services/eddystone/es_gatts_write.h
Normal file
71
components/ble/ble_services/eddystone/es_gatts_write.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ES_GATTS_WRITE_H__
|
||||
#define ES_GATTS_WRITE_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include "nrf_ble_escs.h"
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @defgroup eddystone_gatts_write GATTS write
|
||||
* @brief Functions for handling GATTS write requests.
|
||||
* @ingroup eddystone_gatts
|
||||
* @{
|
||||
*/
|
||||
|
||||
ret_code_t es_gatts_write_handle_unlocked_write(nrf_ble_escs_t * p_escs,
|
||||
uint16_t uuid,
|
||||
uint16_t val_handle,
|
||||
uint8_t const * p_data,
|
||||
uint16_t length,
|
||||
uint8_t active_slot);
|
||||
|
||||
ret_code_t es_gatts_write_handle_unlock(nrf_ble_escs_t * p_escs,
|
||||
uint8_t const * p_data,
|
||||
uint16_t length,
|
||||
uint16_t val_handle);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif // ES_GATTS_WRITE_H__
|
||||
606
components/ble/ble_services/eddystone/es_security.c
Normal file
606
components/ble/ble_services/eddystone/es_security.c
Normal file
@@ -0,0 +1,606 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "es_security.h"
|
||||
#include "app_timer.h"
|
||||
#include "es_flash.h"
|
||||
#include "es_stopwatch.h"
|
||||
#include "fds.h"
|
||||
#include "modes.h"
|
||||
#include "nrf_crypto.h"
|
||||
#include "nrf_soc.h"
|
||||
|
||||
#define NONCE_SIZE (6)
|
||||
#define TAG_SIZE (2)
|
||||
#define SALT_SIZE (2)
|
||||
#define TLM_DATA_SIZE (ES_TLM_LENGTH - 2)
|
||||
#define EIK_SIZE (ESCS_AES_KEY_SIZE)
|
||||
#define AES_ECB_CIPHERTEXT_LENGTH (16)
|
||||
#define AES_ECB_CLEARTEXT_LENGTH (16)
|
||||
|
||||
/**@brief Timing structure. */
|
||||
typedef struct
|
||||
{
|
||||
uint32_t time_counter;
|
||||
uint8_t k_scaler;
|
||||
} es_security_timing_t;
|
||||
|
||||
/**@brief Security slot structure. */
|
||||
typedef struct
|
||||
{
|
||||
nrf_ecb_hal_data_t aes_ecb_ik;
|
||||
nrf_ecb_hal_data_t aes_ecb_tk;
|
||||
uint8_t eid[ES_EID_ID_LENGTH];
|
||||
es_security_timing_t timing;
|
||||
bool is_occupied;
|
||||
} es_security_slot_t;
|
||||
|
||||
/**@brief Key pair structure. */
|
||||
typedef struct
|
||||
{
|
||||
nrf_crypto_ecc_private_key_t private;
|
||||
nrf_crypto_ecc_public_key_t public;
|
||||
} ecdh_key_pair_t;
|
||||
|
||||
/**@brief ECDH structure. */
|
||||
typedef struct
|
||||
{
|
||||
ecdh_key_pair_t ecdh_key_pair;
|
||||
} es_security_ecdh_t;
|
||||
|
||||
static nrf_ecb_hal_data_t m_aes_ecb_lk;
|
||||
static es_security_slot_t m_security_slot[APP_MAX_EID_SLOTS];
|
||||
static es_security_ecdh_t m_ecdh;
|
||||
static es_security_msg_cb_t m_security_callback;
|
||||
static es_stopwatch_id_t m_seconds_passed_sw_id;
|
||||
|
||||
// Use static context variables to avoid stack allocation.
|
||||
static nrf_crypto_aes_context_t m_aes_context;
|
||||
static nrf_crypto_hmac_context_t m_hmac_context;
|
||||
static nrf_crypto_aead_context_t m_aead_context;
|
||||
static nrf_crypto_ecc_key_pair_generate_context_t ecc_key_pair_generate_context;
|
||||
static nrf_crypto_ecdh_context_t ecdh_context;
|
||||
|
||||
/**@brief Generates a temporary key with the Identity key. */
|
||||
static void temp_key_generate(uint8_t slot_no);
|
||||
|
||||
/**@brief Generates a EID with the Temporary Key*/
|
||||
static void eid_generate(uint8_t slot_no)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
size_t ciphertext_size = AES_ECB_CIPHERTEXT_LENGTH;
|
||||
|
||||
temp_key_generate(slot_no);
|
||||
|
||||
memset(m_security_slot[slot_no].aes_ecb_tk.cleartext, 0, ESCS_AES_KEY_SIZE);
|
||||
m_security_slot[slot_no].aes_ecb_tk.cleartext[11] = m_security_slot[slot_no].timing.k_scaler;
|
||||
|
||||
uint32_t k_bits_cleared_time =
|
||||
(m_security_slot[slot_no].timing.time_counter >> m_security_slot[slot_no].timing.k_scaler)
|
||||
<< m_security_slot[slot_no].timing.k_scaler;
|
||||
|
||||
m_security_slot[slot_no].aes_ecb_tk.cleartext[12] =
|
||||
(uint8_t)((k_bits_cleared_time >> 24) & 0xff);
|
||||
m_security_slot[slot_no].aes_ecb_tk.cleartext[13] =
|
||||
(uint8_t)((k_bits_cleared_time >> 16) & 0xff);
|
||||
m_security_slot[slot_no].aes_ecb_tk.cleartext[14] = (uint8_t)((k_bits_cleared_time >> 8) & 0xff);
|
||||
m_security_slot[slot_no].aes_ecb_tk.cleartext[15] = (uint8_t)((k_bits_cleared_time) & 0xff);
|
||||
|
||||
err_code = nrf_crypto_aes_crypt(&m_aes_context,
|
||||
&g_nrf_crypto_aes_ecb_128_info,
|
||||
NRF_CRYPTO_ENCRYPT, // Operation
|
||||
m_security_slot[slot_no].aes_ecb_tk.key, // Key
|
||||
NULL, // IV
|
||||
m_security_slot[slot_no].aes_ecb_tk.cleartext, // Data in
|
||||
AES_ECB_CLEARTEXT_LENGTH, // Data in size
|
||||
m_security_slot[slot_no].aes_ecb_tk.ciphertext, // Data out
|
||||
&ciphertext_size); // Data out size
|
||||
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
memcpy(m_security_slot[slot_no].eid,
|
||||
m_security_slot[slot_no].aes_ecb_tk.ciphertext,
|
||||
ES_EID_ID_LENGTH);
|
||||
|
||||
m_security_callback(slot_no, ES_SECURITY_MSG_EID);
|
||||
}
|
||||
|
||||
|
||||
/**@brief Generates a temporary key with the Identity key. */
|
||||
static void temp_key_generate(uint8_t slot_no)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
size_t ciphertext_size = AES_ECB_CIPHERTEXT_LENGTH;
|
||||
|
||||
memset(m_security_slot[slot_no].aes_ecb_ik.cleartext, 0, ESCS_AES_KEY_SIZE);
|
||||
m_security_slot[slot_no].aes_ecb_ik.cleartext[11] = 0xFF;
|
||||
m_security_slot[slot_no].aes_ecb_ik.cleartext[14] =
|
||||
(uint8_t)((m_security_slot[slot_no].timing.time_counter >> 24) & 0xff);
|
||||
m_security_slot[slot_no].aes_ecb_ik.cleartext[15] =
|
||||
(uint8_t)((m_security_slot[slot_no].timing.time_counter >> 16) & 0xff);
|
||||
|
||||
err_code = nrf_crypto_aes_crypt(&m_aes_context,
|
||||
&g_nrf_crypto_aes_ecb_128_info,
|
||||
NRF_CRYPTO_ENCRYPT, // Operation
|
||||
m_security_slot[slot_no].aes_ecb_ik.key, // Key
|
||||
NULL, // IV
|
||||
m_security_slot[slot_no].aes_ecb_ik.cleartext, // Data in
|
||||
AES_ECB_CLEARTEXT_LENGTH, // Data in size
|
||||
m_security_slot[slot_no].aes_ecb_ik.ciphertext, // Data out
|
||||
&ciphertext_size); // Data out size
|
||||
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
memcpy(m_security_slot[slot_no].aes_ecb_tk.key,
|
||||
m_security_slot[slot_no].aes_ecb_ik.ciphertext,
|
||||
ESCS_AES_KEY_SIZE);
|
||||
}
|
||||
|
||||
|
||||
/**@brief See if EID should be re-calculated.
|
||||
*/
|
||||
static void check_rollovers_and_update_eid(uint8_t slot_no)
|
||||
{
|
||||
static uint32_t last_invocation_time_counter = 0;
|
||||
uint32_t scaler = 2 << (m_security_slot[slot_no].timing.k_scaler - 1);
|
||||
uint32_t diff;
|
||||
|
||||
if (last_invocation_time_counter == 0)
|
||||
{
|
||||
last_invocation_time_counter = m_security_slot[slot_no].timing.time_counter;
|
||||
}
|
||||
|
||||
diff = m_security_slot[slot_no].timing.time_counter - last_invocation_time_counter;
|
||||
|
||||
if (diff >= scaler)
|
||||
{
|
||||
// Store to last scaler-aligned time.
|
||||
last_invocation_time_counter = (m_security_slot[slot_no].timing.time_counter / scaler) * scaler;
|
||||
|
||||
eid_generate(slot_no);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Initialize lock code from flash. If it does not exist, copy from APP_CONFIG_LOCK_CODE.
|
||||
*/
|
||||
static void lock_code_init(uint8_t * p_lock_buff)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
|
||||
err_code = es_flash_access_lock_key(p_lock_buff, ES_FLASH_ACCESS_READ);
|
||||
FLASH_ACCES_ERROR_CHECK_ALLOW_NOT_FOUND(err_code);
|
||||
|
||||
// If no lock keys exist, then generate one and copy it to buffer.
|
||||
if (err_code == FDS_ERR_NOT_FOUND)
|
||||
{
|
||||
uint8_t lock_code[16] = APP_CONFIG_LOCK_CODE;
|
||||
|
||||
memcpy(p_lock_buff, lock_code, sizeof(lock_code));
|
||||
|
||||
err_code = es_flash_access_lock_key(p_lock_buff, ES_FLASH_ACCESS_WRITE);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void es_security_update_time(void)
|
||||
{
|
||||
static uint32_t timer_persist;
|
||||
uint32_t second_since_last_invocation = es_stopwatch_check(m_seconds_passed_sw_id);
|
||||
|
||||
if (second_since_last_invocation > 0)
|
||||
{
|
||||
for (uint32_t i = 0; i < APP_MAX_EID_SLOTS; ++i)
|
||||
{
|
||||
if (m_security_slot[i].is_occupied)
|
||||
{
|
||||
m_security_slot[i].timing.time_counter += second_since_last_invocation;
|
||||
check_rollovers_and_update_eid(i);
|
||||
}
|
||||
}
|
||||
|
||||
// Every 24 hr, write the new EID timer to flash.
|
||||
timer_persist += second_since_last_invocation;
|
||||
const uint32_t TWENTY_FOUR_HOURS = 60 * 60 * 24;
|
||||
if (timer_persist >= TWENTY_FOUR_HOURS)
|
||||
{
|
||||
for (uint32_t i = 0; i < APP_MAX_EID_SLOTS; ++i)
|
||||
{
|
||||
if (m_security_slot[i].is_occupied)
|
||||
{
|
||||
m_security_callback(i, ES_SECURITY_MSG_STORE_TIME);
|
||||
}
|
||||
}
|
||||
timer_persist = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void es_security_eid_slots_restore(uint8_t slot_no,
|
||||
uint8_t k_scaler,
|
||||
uint32_t time_counter,
|
||||
const uint8_t * p_ik)
|
||||
{
|
||||
m_security_slot[slot_no].timing.k_scaler = k_scaler;
|
||||
m_security_slot[slot_no].timing.time_counter = time_counter;
|
||||
memcpy(m_security_slot[slot_no].aes_ecb_ik.key, p_ik, ESCS_AES_KEY_SIZE);
|
||||
m_security_slot[slot_no].is_occupied = true;
|
||||
m_security_callback(slot_no, ES_SECURITY_MSG_IK);
|
||||
eid_generate(slot_no);
|
||||
}
|
||||
|
||||
|
||||
ret_code_t es_security_lock_code_update(uint8_t * p_ecrypted_key)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
uint8_t temp_buff[ESCS_AES_KEY_SIZE] = {0};
|
||||
size_t temp_buff_size = sizeof(temp_buff);
|
||||
|
||||
err_code = nrf_crypto_aes_crypt(&m_aes_context,
|
||||
&g_nrf_crypto_aes_ecb_128_info,
|
||||
NRF_CRYPTO_DECRYPT, // Operation
|
||||
m_aes_ecb_lk.key, // Key
|
||||
NULL, // IV
|
||||
p_ecrypted_key, // Data in
|
||||
16, // Data in size
|
||||
temp_buff, // Data out
|
||||
&temp_buff_size); // Data out size
|
||||
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
memcpy(m_aes_ecb_lk.key, temp_buff, ESCS_AES_KEY_SIZE);
|
||||
return es_flash_access_lock_key(m_aes_ecb_lk.key, ES_FLASH_ACCESS_WRITE);
|
||||
}
|
||||
|
||||
|
||||
void es_security_unlock_prepare(uint8_t * p_challenge)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
size_t ciphertext_size = AES_ECB_CIPHERTEXT_LENGTH;
|
||||
|
||||
memcpy(m_aes_ecb_lk.cleartext, p_challenge, ESCS_AES_KEY_SIZE);
|
||||
|
||||
err_code = nrf_crypto_aes_crypt(&m_aes_context,
|
||||
&g_nrf_crypto_aes_ecb_128_info,
|
||||
NRF_CRYPTO_ENCRYPT, // Operation
|
||||
m_aes_ecb_lk.key, // Key
|
||||
NULL, // IV
|
||||
m_aes_ecb_lk.cleartext, // Data in
|
||||
AES_ECB_CLEARTEXT_LENGTH, // Data in size
|
||||
m_aes_ecb_lk.ciphertext, // Data out
|
||||
&ciphertext_size); // Data out size
|
||||
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
|
||||
|
||||
void es_security_unlock_verify(uint8_t * p_unlock_token)
|
||||
{
|
||||
if (memcmp(p_unlock_token, m_aes_ecb_lk.ciphertext, ESCS_AES_KEY_SIZE) == 0)
|
||||
{
|
||||
m_security_callback(0, ES_SECURITY_MSG_UNLOCKED);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ret_code_t es_security_random_challenge_generate(uint8_t * p_rand_chlg_buff)
|
||||
{
|
||||
return nrf_crypto_rng_vector_generate(p_rand_chlg_buff, ESCS_AES_KEY_SIZE);
|
||||
}
|
||||
|
||||
|
||||
void es_security_shared_ik_receive(uint8_t slot_no, uint8_t * p_encrypted_ik, uint8_t scaler_k)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
size_t cleartext_size = AES_ECB_CLEARTEXT_LENGTH;
|
||||
|
||||
m_security_slot[slot_no].is_occupied = true;
|
||||
m_security_slot[slot_no].timing.k_scaler = scaler_k;
|
||||
m_security_slot[slot_no].timing.time_counter = APP_CONFIG_TIMING_INIT_VALUE;
|
||||
|
||||
err_code = nrf_crypto_aes_crypt(&m_aes_context,
|
||||
&g_nrf_crypto_aes_ecb_128_info,
|
||||
NRF_CRYPTO_DECRYPT, // Operation
|
||||
m_aes_ecb_lk.key, // Key
|
||||
NULL, // IV
|
||||
p_encrypted_ik, // Data in
|
||||
16, // Data in size
|
||||
m_security_slot[slot_no].aes_ecb_ik.key, // Data out
|
||||
&cleartext_size); // Data out size
|
||||
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
eid_generate(slot_no);
|
||||
|
||||
m_security_callback(slot_no, ES_SECURITY_MSG_IK);
|
||||
}
|
||||
|
||||
|
||||
void es_security_client_pub_ecdh_receive(uint8_t slot_no, uint8_t * p_pub_ecdh, uint8_t scaler_k)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
nrf_crypto_ecc_public_key_t phone_public; // Phone public ECDH key
|
||||
uint8_t beacon_public[ESCS_ECDH_KEY_SIZE]; // Beacon public ECDH key
|
||||
uint8_t shared[ESCS_ECDH_KEY_SIZE]; // Shared secret ECDH key
|
||||
uint8_t public_keys[64]; // Buffer for concatenated public keys
|
||||
uint8_t key_material[64]; // Buffer for holding key material
|
||||
uint8_t empty_check[ESCS_ECDH_KEY_SIZE] = {0};
|
||||
size_t beacon_public_size = sizeof(beacon_public);
|
||||
size_t shared_size = sizeof(shared);
|
||||
size_t key_material_size = sizeof(key_material);
|
||||
|
||||
m_security_slot[slot_no].is_occupied = true;
|
||||
m_security_slot[slot_no].timing.k_scaler = scaler_k;
|
||||
m_security_slot[slot_no].timing.time_counter = APP_CONFIG_TIMING_INIT_VALUE;
|
||||
|
||||
// Get public 32-byte service ECDH key from phone.
|
||||
err_code = nrf_crypto_ecc_public_key_from_raw(&g_nrf_crypto_ecc_curve25519_curve_info,
|
||||
&phone_public,
|
||||
p_pub_ecdh,
|
||||
ESCS_ECDH_KEY_SIZE);
|
||||
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
// Generate key pair.
|
||||
err_code = nrf_crypto_ecc_key_pair_generate(&ecc_key_pair_generate_context,
|
||||
&g_nrf_crypto_ecc_curve25519_curve_info,
|
||||
&m_ecdh.ecdh_key_pair.private,
|
||||
&m_ecdh.ecdh_key_pair.public);
|
||||
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
// Generate shared 32-byte ECDH secret from beacon private service ECDH key and phone public ECDH key.
|
||||
err_code = nrf_crypto_ecdh_compute(&ecdh_context,
|
||||
&m_ecdh.ecdh_key_pair.private,
|
||||
&phone_public,
|
||||
shared,
|
||||
&shared_size);
|
||||
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
// Verify that the shared secret is not zero at this point, and report an error/reset if it is.
|
||||
if (memcmp(empty_check, shared, ESCS_ECDH_KEY_SIZE) == 0)
|
||||
{
|
||||
APP_ERROR_CHECK(NRF_ERROR_INTERNAL);
|
||||
}
|
||||
|
||||
// Concatenate the resolver's public key and beacon's public key
|
||||
err_code = nrf_crypto_ecc_public_key_to_raw(&m_ecdh.ecdh_key_pair.public,
|
||||
beacon_public,
|
||||
&beacon_public_size);
|
||||
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
memcpy(public_keys, p_pub_ecdh, 32);
|
||||
memcpy(public_keys + 32, beacon_public, 32);
|
||||
|
||||
// Convert the shared secret to key material using HKDF-SHA256. HKDF is used with the salt set
|
||||
// to a concatenation of the resolver's public key and beacon's public key
|
||||
err_code = nrf_crypto_hkdf_calculate(&m_hmac_context,
|
||||
&g_nrf_crypto_hmac_sha256_info,
|
||||
key_material, // Output key
|
||||
&key_material_size, // Output key size
|
||||
shared, // Input key
|
||||
sizeof(shared), // Input key size
|
||||
public_keys, // Salt
|
||||
sizeof(public_keys), // Salt size
|
||||
NULL, // Additional info
|
||||
0, // Additional info size
|
||||
NRF_CRYPTO_HKDF_EXTRACT_AND_EXPAND); // Mode
|
||||
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
// Truncate the key material to 128 bits to convert it to an AES-128 secret key (Identity key).
|
||||
memcpy(m_security_slot[slot_no].aes_ecb_ik.key, key_material, ESCS_AES_KEY_SIZE);
|
||||
|
||||
eid_generate(slot_no);
|
||||
|
||||
m_security_callback(slot_no, ES_SECURITY_MSG_ECDH);
|
||||
m_security_callback(slot_no, ES_SECURITY_MSG_IK);
|
||||
}
|
||||
|
||||
|
||||
void es_security_pub_ecdh_get(uint8_t slot_no, uint8_t * p_edch_buffer)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
size_t buffer_size = ESCS_ECDH_KEY_SIZE;
|
||||
|
||||
err_code = nrf_crypto_ecc_public_key_to_raw(&m_ecdh.ecdh_key_pair.public,
|
||||
p_edch_buffer,
|
||||
&buffer_size);
|
||||
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
|
||||
|
||||
uint32_t es_security_clock_get(uint8_t slot_no)
|
||||
{
|
||||
return m_security_slot[slot_no].timing.time_counter;
|
||||
}
|
||||
|
||||
|
||||
void es_security_eid_slot_destroy(uint8_t slot_no)
|
||||
{
|
||||
memset(&m_security_slot[slot_no], 0, sizeof(es_security_slot_t));
|
||||
}
|
||||
|
||||
|
||||
uint8_t es_security_scaler_get(uint8_t slot_no)
|
||||
{
|
||||
return m_security_slot[slot_no].timing.k_scaler;
|
||||
}
|
||||
|
||||
|
||||
void es_security_eid_get(uint8_t slot_no, uint8_t * p_eid_buffer)
|
||||
{
|
||||
memcpy(p_eid_buffer, m_security_slot[slot_no].eid, ES_EID_ID_LENGTH);
|
||||
}
|
||||
|
||||
|
||||
void es_security_encrypted_eid_id_key_get(uint8_t slot_no, uint8_t * p_key_buffer)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
size_t ciphertext_size = AES_ECB_CIPHERTEXT_LENGTH;
|
||||
|
||||
memcpy(m_aes_ecb_lk.cleartext, m_security_slot[slot_no].aes_ecb_ik.key, ESCS_AES_KEY_SIZE);
|
||||
|
||||
err_code = nrf_crypto_aes_crypt(&m_aes_context,
|
||||
&g_nrf_crypto_aes_ecb_128_info,
|
||||
NRF_CRYPTO_ENCRYPT, // Operation
|
||||
m_aes_ecb_lk.key, // Key
|
||||
NULL, // IV
|
||||
m_aes_ecb_lk.cleartext, // Data in
|
||||
AES_ECB_CLEARTEXT_LENGTH, // Data in size
|
||||
m_aes_ecb_lk.ciphertext, // Data out
|
||||
&ciphertext_size); // Data out size
|
||||
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
memcpy(p_key_buffer, m_aes_ecb_lk.ciphertext, ESCS_AES_KEY_SIZE);
|
||||
}
|
||||
|
||||
|
||||
void es_security_plain_eid_id_key_get(uint8_t slot_no, uint8_t * p_key_buffer)
|
||||
{
|
||||
memcpy(p_key_buffer, m_security_slot[slot_no].aes_ecb_ik.key, ESCS_AES_KEY_SIZE);
|
||||
}
|
||||
|
||||
|
||||
void es_security_tlm_to_etlm(uint8_t ik_slot_no, es_tlm_frame_t * p_tlm, es_etlm_frame_t * p_etlm)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
uint8_t plain[TLM_DATA_SIZE] = {0}; // Plaintext tlm, without the frame byte and version.
|
||||
size_t nplain = TLM_DATA_SIZE; // Length of message plaintext.
|
||||
|
||||
/*lint -save -e420 */
|
||||
memcpy(plain, &p_tlm->vbatt[0], sizeof(plain));
|
||||
|
||||
uint8_t key[EIK_SIZE] = {0}; // Encryption/decryption key: EIK.
|
||||
|
||||
memcpy(key, &m_security_slot[ik_slot_no].aes_ecb_ik.key[0], EIK_SIZE);
|
||||
/*lint -restore */
|
||||
|
||||
uint8_t nonce[NONCE_SIZE] = {0}; // Nonce. This must not repeat for a given key.
|
||||
size_t nnonce = NONCE_SIZE; // Length of nonce.First 4 bytes are beacon time base with k-bits cleared.
|
||||
// Last two bits are randomly generated
|
||||
|
||||
// Take the current timestamp and clear the lowest K bits, use it as nonce.
|
||||
uint32_t k_bits_cleared_time = (m_security_slot[ik_slot_no].timing.time_counter
|
||||
>> m_security_slot[ik_slot_no].timing.k_scaler)
|
||||
<< m_security_slot[ik_slot_no].timing.k_scaler;
|
||||
|
||||
nonce[0] = (uint8_t)((k_bits_cleared_time >> 24) & 0xff);
|
||||
nonce[1] = (uint8_t)((k_bits_cleared_time >> 16) & 0xff);
|
||||
nonce[2] = (uint8_t)((k_bits_cleared_time >> 8) & 0xff);
|
||||
nonce[3] = (uint8_t)((k_bits_cleared_time) & 0xff);
|
||||
|
||||
// Generate random salt.
|
||||
uint8_t salt[SALT_SIZE] = {0};
|
||||
err_code = nrf_crypto_rng_vector_generate(salt, SALT_SIZE);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
memcpy(&nonce[4], salt, SALT_SIZE);
|
||||
|
||||
uint8_t cipher[ES_ETLM_ECRYPTED_LENGTH]; // Ciphertext output. nplain bytes are written.
|
||||
uint8_t tag[TAG_SIZE] = {0}; // Authentication tag. ntag bytes are written.
|
||||
size_t ntag = TAG_SIZE; // Length of authentication tag.
|
||||
|
||||
// Encryption
|
||||
// --------------------------------------------------------------------------
|
||||
err_code = nrf_crypto_aead_init(&m_aead_context, &g_nrf_crypto_aes_eax_128_info, key);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
err_code = nrf_crypto_aead_crypt(&m_aead_context,
|
||||
NRF_CRYPTO_ENCRYPT, // Operation
|
||||
nonce, // Nonce
|
||||
nnonce, // Nonce size
|
||||
NULL, // Additional authenticated data (adata)
|
||||
0, // Additional authenticated data size
|
||||
plain, // Input data
|
||||
nplain, // Input data size
|
||||
cipher, // Output data
|
||||
tag, // MAC result output
|
||||
ntag); // MAC size
|
||||
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
err_code = nrf_crypto_aead_uninit(&m_aead_context);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
// Construct the eTLM.
|
||||
// --------------------------------------------------------------------------
|
||||
p_etlm->frame_type = p_tlm->frame_type;
|
||||
p_etlm->version = ES_TLM_VERSION_ETLM;
|
||||
memcpy(p_etlm->encrypted_tlm, cipher, ES_ETLM_ECRYPTED_LENGTH);
|
||||
memcpy((uint8_t *)&p_etlm->random_salt, salt, SALT_SIZE);
|
||||
memcpy((uint8_t *)&p_etlm->msg_integrity_check, tag, TAG_SIZE);
|
||||
}
|
||||
|
||||
|
||||
ret_code_t es_security_init(es_security_msg_cb_t security_callback)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
|
||||
if (security_callback == NULL)
|
||||
{
|
||||
return NRF_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
// Get lock code from 'es_app_config.h', or fetch it from flash if exists.
|
||||
lock_code_init(m_aes_ecb_lk.key);
|
||||
|
||||
m_security_callback = security_callback;
|
||||
|
||||
memset(&m_ecdh, 0, sizeof(es_security_ecdh_t));
|
||||
|
||||
for (uint32_t i = 0; i < APP_MAX_EID_SLOTS; ++i)
|
||||
{
|
||||
m_security_slot[i].timing.time_counter = APP_CONFIG_TIMING_INIT_VALUE;
|
||||
}
|
||||
err_code = es_stopwatch_create(&m_seconds_passed_sw_id, APP_TIMER_TICKS(1000));
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
err_code = nrf_crypto_init();
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user