初始版本

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

View File

@@ -0,0 +1,838 @@
/**
* 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_advdata.h"
#include "ble_gap.h"
#include "ble_srv_common.h"
#include "sdk_common.h"
// NOTE: For now, Security Manager Out of Band Flags (OOB) are omitted from the advertising data.
// Types of LE Bluetooth Device Address AD type
#define AD_TYPE_BLE_DEVICE_ADDR_TYPE_PUBLIC 0UL
#define AD_TYPE_BLE_DEVICE_ADDR_TYPE_RANDOM 1UL
#define UUID16_SIZE 2 /**< Size of 16 bit UUID. */
#define UUID32_SIZE 4 /**< Size of 32 bit UUID. */
#define UUID128_SIZE 16 /**< Size of 128 bit UUID. */
#define N_AD_TYPES 2 /**< The number of Advertising data types to search for at a time. */
static ret_code_t ble_device_addr_encode(uint8_t * p_encoded_data,
uint16_t * p_offset,
uint16_t max_size)
{
ret_code_t err_code;
ble_gap_addr_t device_addr;
// Check for buffer overflow.
if (((*p_offset) + AD_TYPE_BLE_DEVICE_ADDR_SIZE) > max_size)
{
return NRF_ERROR_DATA_SIZE;
}
// Get BLE address.
err_code = sd_ble_gap_addr_get(&device_addr);
VERIFY_SUCCESS(err_code);
// Encode LE Bluetooth Device Address.
p_encoded_data[*p_offset] = (uint8_t)(AD_TYPE_FIELD_SIZE +
AD_TYPE_BLE_DEVICE_ADDR_DATA_SIZE);
*p_offset += AD_LENGTH_FIELD_SIZE;
p_encoded_data[*p_offset] = BLE_GAP_AD_TYPE_LE_BLUETOOTH_DEVICE_ADDRESS;
*p_offset += AD_TYPE_FIELD_SIZE;
memcpy(&p_encoded_data[*p_offset], &device_addr.addr[0], BLE_GAP_ADDR_LEN);
*p_offset += BLE_GAP_ADDR_LEN;
if (BLE_GAP_ADDR_TYPE_PUBLIC == device_addr.addr_type)
{
p_encoded_data[*p_offset] = AD_TYPE_BLE_DEVICE_ADDR_TYPE_PUBLIC;
}
else
{
p_encoded_data[*p_offset] = AD_TYPE_BLE_DEVICE_ADDR_TYPE_RANDOM;
}
*p_offset += AD_TYPE_BLE_DEVICE_ADDR_TYPE_SIZE;
return NRF_SUCCESS;
}
static ret_code_t name_encode(const ble_advdata_t * p_advdata,
uint8_t * p_encoded_data,
uint16_t * p_offset,
uint16_t max_size)
{
ret_code_t err_code;
uint16_t rem_adv_data_len;
uint16_t actual_length;
uint8_t adv_data_format;
// Validate parameters
if ((BLE_ADVDATA_SHORT_NAME == p_advdata->name_type) && (0 == p_advdata->short_name_len))
{
return NRF_ERROR_INVALID_PARAM;
}
// Check for buffer overflow.
if ( (((*p_offset) + AD_DATA_OFFSET) > max_size) ||
( (BLE_ADVDATA_SHORT_NAME == p_advdata->name_type) &&
(((*p_offset) + AD_DATA_OFFSET + p_advdata->short_name_len) > max_size)))
{
return NRF_ERROR_DATA_SIZE;
}
rem_adv_data_len = max_size - (*p_offset) - AD_DATA_OFFSET;
actual_length = rem_adv_data_len;
// Get GAP device name and length
err_code = sd_ble_gap_device_name_get(&p_encoded_data[(*p_offset) + AD_DATA_OFFSET],
&actual_length);
VERIFY_SUCCESS(err_code);
// Check if device intend to use short name and it can fit available data size.
// If the name is shorter than the preferred short name length then it is no longer
// a short name and is in fact the complete name of the device.
if (((p_advdata->name_type == BLE_ADVDATA_FULL_NAME) ||
(actual_length <= p_advdata->short_name_len)) &&
(actual_length <= rem_adv_data_len))
{
// Complete device name can fit, setting Complete Name in Adv Data.
adv_data_format = BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME;
}
else
{
// Else short name needs to be used. Or application has requested use of short name.
adv_data_format = BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME;
// If application has set a preference on the short name size, it needs to be considered,
// else fit what can be fit.
if ((BLE_ADVDATA_SHORT_NAME == p_advdata->name_type) &&
(p_advdata->short_name_len <= rem_adv_data_len))
{
// Short name fits available size.
actual_length = p_advdata->short_name_len;
}
// Else whatever can fit the data buffer will be packed.
else
{
actual_length = rem_adv_data_len;
}
}
// There is only 1 byte intended to encode length which is (actual_length + AD_TYPE_FIELD_SIZE)
if (actual_length > (0x00FF - AD_TYPE_FIELD_SIZE))
{
return NRF_ERROR_DATA_SIZE;
}
// Complete name field in encoded data.
p_encoded_data[*p_offset] = (uint8_t)(AD_TYPE_FIELD_SIZE + actual_length);
*p_offset += AD_LENGTH_FIELD_SIZE;
p_encoded_data[*p_offset] = adv_data_format;
*p_offset += AD_TYPE_FIELD_SIZE;
*p_offset += actual_length;
return NRF_SUCCESS;
}
static ret_code_t appearance_encode(uint8_t * p_encoded_data,
uint16_t * p_offset,
uint16_t max_size)
{
ret_code_t err_code;
uint16_t appearance;
// Check for buffer overflow.
if (((*p_offset) + AD_TYPE_APPEARANCE_SIZE) > max_size)
{
return NRF_ERROR_DATA_SIZE;
}
// Get GAP appearance field.
err_code = sd_ble_gap_appearance_get(&appearance);
VERIFY_SUCCESS(err_code);
// Encode Length, AD Type and Appearance.
p_encoded_data[*p_offset] = (uint8_t)(AD_TYPE_FIELD_SIZE + AD_TYPE_APPEARANCE_DATA_SIZE);
*p_offset += AD_LENGTH_FIELD_SIZE;
p_encoded_data[*p_offset] = BLE_GAP_AD_TYPE_APPEARANCE;
*p_offset += AD_TYPE_FIELD_SIZE;
*p_offset += uint16_encode(appearance, &p_encoded_data[*p_offset]);
return NRF_SUCCESS;
}
static ret_code_t flags_encode(int8_t flags,
uint8_t * p_encoded_data,
uint16_t * p_offset,
uint16_t max_size)
{
// Check for buffer overflow.
if (((*p_offset) + AD_TYPE_FLAGS_SIZE) > max_size)
{
return NRF_ERROR_DATA_SIZE;
}
// Encode flags.
p_encoded_data[*p_offset] = (uint8_t)(AD_TYPE_FIELD_SIZE + AD_TYPE_FLAGS_DATA_SIZE);
*p_offset += AD_LENGTH_FIELD_SIZE;
p_encoded_data[*p_offset] = BLE_GAP_AD_TYPE_FLAGS;
*p_offset += AD_TYPE_FIELD_SIZE;
p_encoded_data[*p_offset] = flags;
*p_offset += AD_TYPE_FLAGS_DATA_SIZE;
return NRF_SUCCESS;
}
static ret_code_t tx_power_level_encode(int8_t tx_power_level,
uint8_t * p_encoded_data,
uint16_t * p_offset,
uint16_t max_size)
{
// Check for buffer overflow.
if (((*p_offset) + AD_TYPE_TX_POWER_LEVEL_SIZE) > max_size)
{
return NRF_ERROR_DATA_SIZE;
}
// Encode TX Power Level.
p_encoded_data[*p_offset] = (uint8_t)(AD_TYPE_FIELD_SIZE +
AD_TYPE_TX_POWER_LEVEL_DATA_SIZE);
*p_offset += AD_LENGTH_FIELD_SIZE;
p_encoded_data[*p_offset] = BLE_GAP_AD_TYPE_TX_POWER_LEVEL;
*p_offset += AD_TYPE_FIELD_SIZE;
p_encoded_data[*p_offset] = tx_power_level;
*p_offset += AD_TYPE_TX_POWER_LEVEL_DATA_SIZE;
return NRF_SUCCESS;
}
static ret_code_t uuid_list_sized_encode(const ble_advdata_uuid_list_t * p_uuid_list,
uint8_t adv_type,
uint8_t uuid_size,
uint8_t * p_encoded_data,
uint16_t * p_offset,
uint16_t max_size)
{
int i;
bool is_heading_written = false;
uint16_t start_pos = *p_offset;
uint16_t length;
for (i = 0; i < p_uuid_list->uuid_cnt; i++)
{
ret_code_t err_code;
uint8_t encoded_size;
ble_uuid_t uuid = p_uuid_list->p_uuids[i];
// Find encoded uuid size.
err_code = sd_ble_uuid_encode(&uuid, &encoded_size, NULL);
VERIFY_SUCCESS(err_code);
// Check size.
if (encoded_size == uuid_size)
{
uint8_t heading_bytes = (is_heading_written) ? 0 : AD_DATA_OFFSET;
// Check for buffer overflow
if (((*p_offset) + encoded_size + heading_bytes) > max_size)
{
return NRF_ERROR_DATA_SIZE;
}
if (!is_heading_written)
{
// Write AD structure heading.
*p_offset += AD_LENGTH_FIELD_SIZE;
p_encoded_data[*p_offset] = adv_type;
*p_offset += AD_TYPE_FIELD_SIZE;
is_heading_written = true;
}
// Write UUID.
err_code = sd_ble_uuid_encode(&uuid, &encoded_size, &p_encoded_data[*p_offset]);
VERIFY_SUCCESS(err_code);
*p_offset += encoded_size;
}
}
if (is_heading_written)
{
// Write length.
length = (*p_offset) - (start_pos + AD_LENGTH_FIELD_SIZE);
// There is only 1 byte intended to encode length
if (length > 0x00FF)
{
return NRF_ERROR_DATA_SIZE;
}
p_encoded_data[start_pos] = (uint8_t)length;
}
return NRF_SUCCESS;
}
static ret_code_t uuid_list_encode(const ble_advdata_uuid_list_t * p_uuid_list,
uint8_t adv_type_16,
uint8_t adv_type_128,
uint8_t * p_encoded_data,
uint16_t * p_offset,
uint16_t max_size)
{
ret_code_t err_code;
// Encode 16 bit UUIDs.
err_code = uuid_list_sized_encode(p_uuid_list,
adv_type_16,
sizeof(uint16_le_t),
p_encoded_data,
p_offset,
max_size);
VERIFY_SUCCESS(err_code);
// Encode 128 bit UUIDs.
err_code = uuid_list_sized_encode(p_uuid_list,
adv_type_128,
sizeof(ble_uuid128_t),
p_encoded_data,
p_offset,
max_size);
VERIFY_SUCCESS(err_code);
return NRF_SUCCESS;
}
static ret_code_t conn_int_check(const ble_advdata_conn_int_t *p_conn_int)
{
// Check Minimum Connection Interval.
if ((p_conn_int->min_conn_interval < 0x0006) ||
(
(p_conn_int->min_conn_interval > 0x0c80) &&
(p_conn_int->min_conn_interval != 0xffff)
)
)
{
return NRF_ERROR_INVALID_PARAM;
}
// Check Maximum Connection Interval.
if ((p_conn_int->max_conn_interval < 0x0006) ||
(
(p_conn_int->max_conn_interval > 0x0c80) &&
(p_conn_int->max_conn_interval != 0xffff)
)
)
{
return NRF_ERROR_INVALID_PARAM;
}
// Make sure Minimum Connection Interval is not bigger than Maximum Connection Interval.
if ((p_conn_int->min_conn_interval != 0xffff) &&
(p_conn_int->max_conn_interval != 0xffff) &&
(p_conn_int->min_conn_interval > p_conn_int->max_conn_interval)
)
{
return NRF_ERROR_INVALID_PARAM;
}
return NRF_SUCCESS;
}
static ret_code_t conn_int_encode(const ble_advdata_conn_int_t * p_conn_int,
uint8_t * p_encoded_data,
uint16_t * p_offset,
uint16_t max_size)
{
ret_code_t err_code;
// Check for buffer overflow.
if (((*p_offset) + AD_TYPE_CONN_INT_SIZE) > max_size)
{
return NRF_ERROR_DATA_SIZE;
}
// Check parameters.
err_code = conn_int_check(p_conn_int);
VERIFY_SUCCESS(err_code);
// Encode Length and AD Type.
p_encoded_data[*p_offset] = (uint8_t)(AD_TYPE_FIELD_SIZE + AD_TYPE_CONN_INT_DATA_SIZE);
*p_offset += AD_LENGTH_FIELD_SIZE;
p_encoded_data[*p_offset] = BLE_GAP_AD_TYPE_SLAVE_CONNECTION_INTERVAL_RANGE;
*p_offset += AD_TYPE_FIELD_SIZE;
// Encode Minimum and Maximum Connection Intervals.
*p_offset += uint16_encode(p_conn_int->min_conn_interval, &p_encoded_data[*p_offset]);
*p_offset += uint16_encode(p_conn_int->max_conn_interval, &p_encoded_data[*p_offset]);
return NRF_SUCCESS;
}
static ret_code_t manuf_specific_data_encode(const ble_advdata_manuf_data_t * p_manuf_sp_data,
uint8_t * p_encoded_data,
uint16_t * p_offset,
uint16_t max_size)
{
uint32_t data_size = AD_TYPE_MANUF_SPEC_DATA_ID_SIZE + p_manuf_sp_data->data.size;
// Check for buffer overflow.
if (((*p_offset) + AD_DATA_OFFSET + data_size) > max_size)
{
return NRF_ERROR_DATA_SIZE;
}
// There is only 1 byte intended to encode length which is (data_size + AD_TYPE_FIELD_SIZE)
if (data_size > (0x00FF - AD_TYPE_FIELD_SIZE))
{
return NRF_ERROR_DATA_SIZE;
}
// Encode Length and AD Type.
p_encoded_data[*p_offset] = (uint8_t)(AD_TYPE_FIELD_SIZE + data_size);
*p_offset += AD_LENGTH_FIELD_SIZE;
p_encoded_data[*p_offset] = BLE_GAP_AD_TYPE_MANUFACTURER_SPECIFIC_DATA;
*p_offset += AD_TYPE_FIELD_SIZE;
// Encode Company Identifier.
*p_offset += uint16_encode(p_manuf_sp_data->company_identifier, &p_encoded_data[*p_offset]);
// Encode additional manufacturer specific data.
if (p_manuf_sp_data->data.size > 0)
{
if (p_manuf_sp_data->data.p_data == NULL)
{
return NRF_ERROR_INVALID_PARAM;
}
memcpy(&p_encoded_data[*p_offset], p_manuf_sp_data->data.p_data, p_manuf_sp_data->data.size);
*p_offset += p_manuf_sp_data->data.size;
}
return NRF_SUCCESS;
}
// Implemented only for 16-bit UUIDs
static ret_code_t service_data_encode(const ble_advdata_t * p_advdata,
uint8_t * p_encoded_data,
uint16_t * p_offset,
uint16_t max_size)
{
uint8_t i;
// Check parameter consistency.
if (p_advdata->p_service_data_array == NULL)
{
return NRF_ERROR_INVALID_PARAM;
}
for (i = 0; i < p_advdata->service_data_count; i++)
{
ble_advdata_service_data_t * p_service_data;
uint32_t data_size;
p_service_data = &p_advdata->p_service_data_array[i];
// For now implemented only for 16-bit UUIDs
data_size = AD_TYPE_SERV_DATA_16BIT_UUID_SIZE + p_service_data->data.size;
// There is only 1 byte intended to encode length which is (data_size + AD_TYPE_FIELD_SIZE)
if (data_size > (0x00FF - AD_TYPE_FIELD_SIZE))
{
return NRF_ERROR_DATA_SIZE;
}
// Encode Length and AD Type.
p_encoded_data[*p_offset] = (uint8_t)(AD_TYPE_FIELD_SIZE + data_size);
*p_offset += AD_LENGTH_FIELD_SIZE;
p_encoded_data[*p_offset] = BLE_GAP_AD_TYPE_SERVICE_DATA;
*p_offset += AD_TYPE_FIELD_SIZE;
// Encode service 16-bit UUID.
*p_offset += uint16_encode(p_service_data->service_uuid, &p_encoded_data[*p_offset]);
// Encode additional service data.
if (p_service_data->data.size > 0)
{
if (p_service_data->data.p_data == NULL)
{
return NRF_ERROR_INVALID_PARAM;
}
memcpy(&p_encoded_data[*p_offset], p_service_data->data.p_data, p_service_data->data.size);
*p_offset += p_service_data->data.size;
}
}
return NRF_SUCCESS;
}
ret_code_t ble_advdata_encode(ble_advdata_t const * const p_advdata,
uint8_t * const p_encoded_data,
uint16_t * const p_len)
{
ret_code_t err_code = NRF_SUCCESS;
uint16_t max_size = *p_len;
*p_len = 0;
// Encode LE Bluetooth Device Address
if (p_advdata->include_ble_device_addr)
{
err_code = ble_device_addr_encode(p_encoded_data, p_len, max_size);
VERIFY_SUCCESS(err_code);
}
// Encode appearance.
if (p_advdata->include_appearance)
{
err_code = appearance_encode(p_encoded_data, p_len, max_size);
VERIFY_SUCCESS(err_code);
}
//Encode Flags
if (p_advdata->flags != 0 )
{
err_code = flags_encode(p_advdata->flags, p_encoded_data, p_len, max_size);
VERIFY_SUCCESS(err_code);
}
// Encode TX power level.
if (p_advdata->p_tx_power_level != NULL)
{
err_code = tx_power_level_encode(*p_advdata->p_tx_power_level,
p_encoded_data,
p_len,
max_size);
VERIFY_SUCCESS(err_code);
}
// Encode 'more available' uuid list.
if (p_advdata->uuids_more_available.uuid_cnt > 0)
{
err_code = uuid_list_encode(&p_advdata->uuids_more_available,
BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_MORE_AVAILABLE,
BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_MORE_AVAILABLE,
p_encoded_data,
p_len,
max_size);
VERIFY_SUCCESS(err_code);
}
// Encode 'complete' uuid list.
if (p_advdata->uuids_complete.uuid_cnt > 0)
{
err_code = uuid_list_encode(&p_advdata->uuids_complete,
BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_COMPLETE,
BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_COMPLETE,
p_encoded_data,
p_len,
max_size);
VERIFY_SUCCESS(err_code);
}
// Encode 'solicited service' uuid list.
if (p_advdata->uuids_solicited.uuid_cnt > 0)
{
err_code = uuid_list_encode(&p_advdata->uuids_solicited,
BLE_GAP_AD_TYPE_SOLICITED_SERVICE_UUIDS_16BIT,
BLE_GAP_AD_TYPE_SOLICITED_SERVICE_UUIDS_128BIT,
p_encoded_data,
p_len,
max_size);
VERIFY_SUCCESS(err_code);
}
// Encode Slave Connection Interval Range.
if (p_advdata->p_slave_conn_int != NULL)
{
err_code = conn_int_encode(p_advdata->p_slave_conn_int, p_encoded_data, p_len, max_size);
VERIFY_SUCCESS(err_code);
}
// Encode Manufacturer Specific Data.
if (p_advdata->p_manuf_specific_data != NULL)
{
err_code = manuf_specific_data_encode(p_advdata->p_manuf_specific_data,
p_encoded_data,
p_len,
max_size);
VERIFY_SUCCESS(err_code);
}
// Encode Service Data.
if (p_advdata->service_data_count > 0)
{
err_code = service_data_encode(p_advdata, p_encoded_data, p_len, max_size);
VERIFY_SUCCESS(err_code);
}
// Encode name. WARNING: it is encoded last on purpose since too long device name is truncated.
if (p_advdata->name_type != BLE_ADVDATA_NO_NAME)
{
err_code = name_encode(p_advdata, p_encoded_data, p_len, max_size);
VERIFY_SUCCESS(err_code);
}
return err_code;
}
uint16_t ble_advdata_search(uint8_t const * p_encoded_data,
uint16_t data_len,
uint16_t * p_offset,
uint8_t ad_type)
{
if ((p_encoded_data == NULL) || (p_offset == NULL))
{
return 0;
}
uint16_t i = 0;
while ((i + 1 < data_len) && ((i < *p_offset) || (p_encoded_data[i + 1] != ad_type)))
{
// Jump to next data.
i += (p_encoded_data[i] + 1);
}
if (i >= data_len)
{
return 0;
}
else
{
uint16_t offset = i + 2;
uint16_t len = p_encoded_data[i] ? (p_encoded_data[i] - 1) : 0;
if (!len || ((offset + len) > data_len))
{
// Malformed. Zero length or extends beyond provided data.
return 0;
}
*p_offset = offset;
return len;
}
}
uint8_t * ble_advdata_parse(uint8_t * p_encoded_data,
uint16_t data_len,
uint8_t ad_type)
{
uint16_t offset = 0;
uint16_t len = ble_advdata_search(p_encoded_data, data_len, &offset, ad_type);
if (len == 0)
{
return NULL;
}
else
{
return &p_encoded_data[offset];
}
}
bool ble_advdata_name_find(uint8_t const * p_encoded_data,
uint16_t data_len,
char const * p_target_name)
{
uint16_t parsed_name_len;
uint8_t const * p_parsed_name;
uint16_t data_offset = 0;
if (p_target_name == NULL)
{
return false;
}
parsed_name_len = ble_advdata_search(p_encoded_data,
data_len,
&data_offset,
BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME);
p_parsed_name = &p_encoded_data[data_offset];
if ( (data_offset != 0)
&& (parsed_name_len != 0)
&& (strlen(p_target_name) == parsed_name_len)
&& (memcmp(p_target_name, p_parsed_name, parsed_name_len) == 0))
{
return true;
}
return false;
}
bool ble_advdata_short_name_find(uint8_t const * p_encoded_data,
uint16_t data_len,
char const * p_target_name,
uint8_t const short_name_min_len)
{
uint16_t parsed_name_len;
uint8_t const * p_parsed_name;
uint16_t data_offset = 0;
if (p_target_name == NULL)
{
return false;
}
parsed_name_len = ble_advdata_search(p_encoded_data,
data_len,
&data_offset,
BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME);
p_parsed_name = &p_encoded_data[data_offset];
if ( (data_offset != 0)
&& (parsed_name_len != 0)
&& (parsed_name_len >= short_name_min_len)
&& (parsed_name_len < strlen(p_target_name))
&& (memcmp(p_target_name, p_parsed_name, parsed_name_len) == 0))
{
return true;
}
return false;
}
bool ble_advdata_uuid_find(uint8_t const * p_encoded_data,
uint16_t data_len,
ble_uuid_t const * p_target_uuid)
{
ret_code_t err_code;
uint16_t data_offset = 0;
uint8_t raw_uuid_len = UUID128_SIZE;
uint8_t const * p_parsed_uuid;
uint16_t parsed_uuid_len = data_len;
uint8_t raw_uuid[UUID128_SIZE];
uint8_t ad_types[N_AD_TYPES];
err_code = sd_ble_uuid_encode(p_target_uuid, &raw_uuid_len, raw_uuid);
if ((p_encoded_data == NULL) || (err_code != NRF_SUCCESS))
{
// Invalid p_encoded_data or p_target_uuid.
return false;
}
switch (raw_uuid_len)
{
case UUID16_SIZE:
ad_types[0] = BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_COMPLETE;
ad_types[1] = BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_MORE_AVAILABLE;
break;
case UUID32_SIZE:
// Not currently supported by sd_ble_uuid_encode().
ad_types[0] = BLE_GAP_AD_TYPE_32BIT_SERVICE_UUID_COMPLETE;
ad_types[1] = BLE_GAP_AD_TYPE_32BIT_SERVICE_UUID_MORE_AVAILABLE;
break;
case UUID128_SIZE:
ad_types[0] = BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_COMPLETE;
ad_types[1] = BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_MORE_AVAILABLE;
break;
default:
return false;
}
for (uint8_t i = 0; (i < N_AD_TYPES) && (data_offset == 0); i++)
{
parsed_uuid_len = ble_advdata_search(p_encoded_data, data_len, &data_offset, ad_types[i]);
}
if (data_offset == 0)
{
// Could not find any relevant UUIDs in the encoded data.
return false;
}
p_parsed_uuid = &p_encoded_data[data_offset];
// Verify if any UUID matches the given UUID.
for (uint16_t list_offset = 0; list_offset < parsed_uuid_len; list_offset += raw_uuid_len)
{
if (memcmp(&p_parsed_uuid[list_offset], raw_uuid, raw_uuid_len) == 0)
{
return true;
}
}
// Could not find the UUID among the encoded data.
return false;
}
bool ble_advdata_appearance_find(uint8_t const * p_encoded_data,
uint16_t data_len,
uint16_t const * p_target_appearance)
{
uint16_t data_offset = 0;
uint8_t appearance_len;
uint16_t decoded_appearance;
appearance_len = ble_advdata_search(p_encoded_data, data_len, &data_offset, BLE_GAP_AD_TYPE_APPEARANCE);
if ( (data_offset == 0)
|| (p_target_appearance == NULL)
|| (appearance_len == 0))
{
// Could not find any Appearance in the encoded data, or invalid p_target_appearance.
return false;
}
decoded_appearance = uint16_decode(&p_encoded_data[data_offset]);
if (decoded_appearance == *p_target_appearance)
{
return true;
}
// Could not find the appearance among the encoded data.
return false;
}

View File

@@ -0,0 +1,326 @@
/**
* 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_lib_advdata Advertising and Scan Response Data Encoder
* @{
* @ingroup ble_sdk_lib
* @brief Functions for encoding data in the Advertising and Scan Response Data format,
* and for passing the data to the stack.
*/
#ifndef BLE_ADVDATA_H__
#define BLE_ADVDATA_H__
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "ble.h"
#include "sdk_common.h"
#ifdef __cplusplus
extern "C" {
#endif
#define AD_LENGTH_FIELD_SIZE 1UL /**< Advertising Data and Scan Response format contains 1 octet for the length. */
#define AD_TYPE_FIELD_SIZE 1UL /**< Advertising Data and Scan Response format contains 1 octet for the AD type. */
#define AD_DATA_OFFSET (AD_LENGTH_FIELD_SIZE + AD_TYPE_FIELD_SIZE) /**< Offset for the AD data field of the Advertising Data and Scan Response format. */
#define AD_TYPE_BLE_DEVICE_ADDR_TYPE_SIZE 1UL /**< Data size (in octets) of the Address type of the LE Bluetooth Device Address AD type. */
#define AD_TYPE_BLE_DEVICE_ADDR_DATA_SIZE (BLE_GAP_ADDR_LEN + \
AD_TYPE_BLE_DEVICE_ADDR_TYPE_SIZE) /**< Data size (in octets) of the LE Bluetooth Device Address AD type. */
#define AD_TYPE_BLE_DEVICE_ADDR_SIZE (AD_DATA_OFFSET + \
AD_TYPE_BLE_DEVICE_ADDR_DATA_SIZE) /**< Size (in octets) of the LE Bluetooth Device Address AD type. */
#define AD_TYPE_APPEARANCE_DATA_SIZE 2UL /**< Data size (in octets) of the Appearance AD type. */
#define AD_TYPE_APPEARANCE_SIZE (AD_DATA_OFFSET + \
AD_TYPE_APPEARANCE_DATA_SIZE) /**< Size (in octets) of the Appearance AD type. */
#define AD_TYPE_FLAGS_DATA_SIZE 1UL /**< Data size (in octets) of the Flags AD type. */
#define AD_TYPE_FLAGS_SIZE (AD_DATA_OFFSET + \
AD_TYPE_FLAGS_DATA_SIZE) /**< Size (in octets) of the Flags AD type. */
#define AD_TYPE_TX_POWER_LEVEL_DATA_SIZE 1UL /**< Data size (in octets) of the TX Power Level AD type. */
#define AD_TYPE_TX_POWER_LEVEL_SIZE (AD_DATA_OFFSET + \
AD_TYPE_TX_POWER_LEVEL_DATA_SIZE) /**< Size (in octets) of the TX Power Level AD type. */
#define AD_TYPE_CONN_INT_DATA_SIZE 4UL /**< Data size (in octets) of the Slave Connection Interval Range AD type. */
#define AD_TYPE_CONN_INT_SIZE (AD_DATA_OFFSET + \
AD_TYPE_CONN_INT_DATA_SIZE) /**< Data size (in octets) of the Slave Connection Interval Range AD type. */
#define AD_TYPE_MANUF_SPEC_DATA_ID_SIZE 2UL /**< Size (in octets) of the Company Identifier Code, which is a part of the Manufacturer Specific Data AD type. */
#define AD_TYPE_SERV_DATA_16BIT_UUID_SIZE 2UL /**< Size (in octets) of the 16-bit UUID, which is a part of the Service Data AD type. */
#define BLE_ADV_DATA_MATCH_FULL_NAME 0xff
/**@brief Security Manager TK value. */
typedef struct
{
uint8_t tk[BLE_GAP_SEC_KEY_LEN]; /**< Array containing TK value in little-endian format. */
} ble_advdata_tk_value_t;
/**@brief Advertising data LE Role types. This enumeration contains the options available for the LE role inside
* the advertising data. */
typedef enum
{
BLE_ADVDATA_ROLE_NOT_PRESENT = 0, /**< LE Role AD structure not present. */
BLE_ADVDATA_ROLE_ONLY_PERIPH, /**< Only Peripheral Role supported. */
BLE_ADVDATA_ROLE_ONLY_CENTRAL, /**< Only Central Role supported. */
BLE_ADVDATA_ROLE_BOTH_PERIPH_PREFERRED, /**< Peripheral and Central Role supported. Peripheral Role preferred for connection establishment. */
BLE_ADVDATA_ROLE_BOTH_CENTRAL_PREFERRED /**< Peripheral and Central Role supported. Central Role preferred for connection establishment */
} ble_advdata_le_role_t;
/**@brief Advertising data name type. This enumeration contains the options available for the device name inside
* the advertising data. */
typedef enum
{
BLE_ADVDATA_NO_NAME, /**< Include no device name in advertising data. */
BLE_ADVDATA_SHORT_NAME, /**< Include short device name in advertising data. */
BLE_ADVDATA_FULL_NAME /**< Include full device name in advertising data. */
} ble_advdata_name_type_t;
/**@brief UUID list type. */
typedef struct
{
uint16_t uuid_cnt; /**< Number of UUID entries. */
ble_uuid_t * p_uuids; /**< Pointer to UUID array entries. */
} ble_advdata_uuid_list_t;
/**@brief Connection interval range structure. */
typedef struct
{
uint16_t min_conn_interval; /**< Minimum connection interval, in units of 1.25 ms, range 6 to 3200 (7.5 ms to 4 s). */
uint16_t max_conn_interval; /**< Maximum connection interval, in units of 1.25 ms, range 6 to 3200 (7.5 ms to 4 s). The value 0xFFFF indicates no specific maximum. */
} ble_advdata_conn_int_t;
/**@brief Manufacturer specific data structure. */
typedef struct
{
uint16_t company_identifier; /**< Company identifier code. */
uint8_array_t data; /**< Additional manufacturer specific data. */
} ble_advdata_manuf_data_t;
/**@brief Service data structure. */
typedef struct
{
uint16_t service_uuid; /**< Service UUID. */
uint8_array_t data; /**< Additional service data. */
} ble_advdata_service_data_t;
/**@brief Advertising data structure. This structure contains all options and data needed for encoding and
* setting the advertising data. */
typedef struct
{
ble_advdata_name_type_t name_type; /**< Type of device name. */
uint8_t short_name_len; /**< Length of short device name (if short type is specified). */
bool include_appearance; /**< Determines if Appearance shall be included. */
uint8_t flags; /**< Advertising data Flags field. */
int8_t * p_tx_power_level; /**< TX Power Level field. */
ble_advdata_uuid_list_t uuids_more_available; /**< List of UUIDs in the 'More Available' list. */
ble_advdata_uuid_list_t uuids_complete; /**< List of UUIDs in the 'Complete' list. */
ble_advdata_uuid_list_t uuids_solicited; /**< List of solicited UUIDs. */
ble_advdata_conn_int_t * p_slave_conn_int; /**< Slave Connection Interval Range. */
ble_advdata_manuf_data_t * p_manuf_specific_data; /**< Manufacturer specific data. */
ble_advdata_service_data_t * p_service_data_array; /**< Array of Service data structures. */
uint8_t service_data_count; /**< Number of Service data structures. */
bool include_ble_device_addr; /**< Determines if LE Bluetooth Device Address shall be included. */
ble_advdata_le_role_t le_role; /**< LE Role field. Included when different from @ref BLE_ADVDATA_ROLE_NOT_PRESENT. @warning This field can be used only for NFC. For BLE advertising, set it to NULL. */
ble_advdata_tk_value_t * p_tk_value; /**< Security Manager TK value field. Included when different from NULL. @warning This field can be used only for NFC. For BLE advertising, set it to NULL.*/
uint8_t * p_sec_mgr_oob_flags; /**< Security Manager Out Of Band Flags field. Included when different from NULL. @warning This field can be used only for NFC. For BLE advertising, set it to NULL.*/
ble_gap_lesc_oob_data_t * p_lesc_data; /**< LE Secure Connections OOB data. Included when different from NULL. @warning This field can be used only for NFC. For BLE advertising, set it to NULL.*/
} ble_advdata_t;
/**@brief Function for encoding data in the Advertising and Scan Response data format (AD structures).
*
* @details This function encodes data into the Advertising and Scan Response data format
* (AD structures) based on the fields in the supplied structures. This function can be
* used to create a payload of Advertising packet or Scan Response packet, or a payload of
* NFC message intended for initiating the Out-of-Band pairing.
*
* @param[in] p_advdata Pointer to the structure for specifying the content of encoded data.
* @param[out] p_encoded_data Pointer to the buffer where encoded data will be returned.
* @param[in,out] p_len \c in: Size of \p p_encoded_data buffer.
* \c out: Length of encoded data.
*
* @retval NRF_SUCCESS If the operation was successful.
* @retval NRF_ERROR_INVALID_PARAM If the operation failed because a wrong parameter was provided in
* \p p_advdata.
* @retval NRF_ERROR_DATA_SIZE If the operation failed because not all the requested data could
* fit into the provided buffer or some encoded AD structure is too
* long and its length cannot be encoded with one octet.
*
* @warning This API may override the application's request to use the long name and use a short name
* instead. This truncation will occur in case the long name does not fit the provided buffer size.
* The application can specify a preferred short name length if truncation is required.
* For example, if the complete device name is ABCD_HRMonitor, the application can specify the short name
* length to be 8, so that the short device name appears as ABCD_HRM instead of ABCD_HRMo or ABCD_HRMoni
* if the available size for the short name is 9 or 12 respectively, to have a more appropriate short name.
* However, it should be noted that this is just a preference that the application can specify, and
* if the preference is too large to fit in the provided buffer, the name can be truncated further.
*/
ret_code_t ble_advdata_encode(ble_advdata_t const * const p_advdata,
uint8_t * const p_encoded_data,
uint16_t * const p_len);
/**@brief Function for searching encoded Advertising or Scan Response data for specific data types.
*
* @details This function searches through encoded data e.g. the data produced by
* @ref ble_advdata_encode, or the data found in Advertising reports
* (@ref BLE_GAP_EVT_ADV_REPORT), and gives the offset of the data within the data buffer.
* The data with type \p ad_type can be found at p_encoded_data[*p_offset] after calling
* the function. This function can iterate through multiple instances of data of one
* type by calling it again with the offset provided by the previous call.
*
* Example code for finding multiple instances of one type of data:
* offset = 0;
* ble_advdata_search(&data, len, &offset, AD_TYPE);
* first_instance_of_data = data[offset];
* ble_advdata_search(&data, len, &offset, AD_TYPE);
* second_instance_of_data = data[offset];
*
* @param[in] p_encoded_data The data buffer containing the encoded Advertising data.
* @param[in] data_len The length of the data buffer \p p_encoded_data.
* @param[inout] p_offset \c in: The offset to start searching from.
* \c out: The offset the data type can be found at.
* This value is not changed if the call returns 0.
* @param[in] ad_type The type of data to search for.
*
* @return The length of the found data, or 0 if no data was found with the the type \p ad_type,
* or if \p p_encoded_data or \p p_offset were NULL.
*/
uint16_t ble_advdata_search(uint8_t const * p_encoded_data,
uint16_t data_len,
uint16_t * p_offset,
uint8_t ad_type);
/**@brief Function for getting specific data from encoded Advertising or Scan Response data.
*
* @details This function searches through encoded data e.g. the data produced by
* @ref ble_advdata_encode, or the data found in Advertising reports
* (@ref BLE_GAP_EVT_ADV_REPORT), and returns a pointer directly to the data within the
* data buffer.
*
* Example code:
* ad_type_data = ble_advdata_parse(&data, len, AD_TYPE);
*
* @param[in] p_encoded_data Data buffer containing the encoded Advertising data.
* @param[in] data_len Length of the data buffer \p p_encoded_data.
* @param[in] ad_type Type of data to search for.
*
* @return Pointer to the found data, or NULL if no data was found with the type \p ad_type,
* or if \p p_encoded_data or \p p_data_len were NULL.
*/
uint8_t * ble_advdata_parse(uint8_t * p_encoded_data,
uint16_t data_len,
uint8_t ad_type);
/**@brief Function for searching through encoded Advertising data for a complete local name.
*
* @param[in] p_encoded_data Data buffer containing the encoded Advertising data.
* @param[in] data_len Length of the data buffer \p p_encoded_data.
* @param[in] p_target_name Name to search for.
*
* @retval true If \p p_target_name was found among \p p_encoded_data, as a complete local name.
* @retval false If \p p_target_name was not found among \p p_encoded_data, or if \p p_encoded_data
* or \p p_target_name was NULL.
*/
bool ble_advdata_name_find(uint8_t const * p_encoded_data,
uint16_t data_len,
char const * p_target_name);
/**@brief Function for searching through encoded Advertising data for a device shortened name.
*
* @param[in] p_encoded_data Data buffer containing the encoded Advertising data.
* @param[in] data_len Length of the data buffer \p p_encoded_data.
* @param[in] p_target_name Name to search for.
* @param[in] short_name_min_len Minimum length of the shortened name.
* For example, if the advertising data has a shortened name 'No' and this parameter is
* set to 4 with a target_name set to Nordic_XXX it will return false, but if
* the shortened name in the advertising data is 'Nord', it will return true.
* @note: If the shortened name in the Advertising data has the same length as the target name,
* this function will return false, since this means that the complete name is actually
* longer, thus different than the target name.
*
* @retval true If \p p_target_name was found among \p p_encoded_data, as short local name.
* @retval false If \p p_target_name was not found among \p p_encoded_data, or if \p p_encoded_data
* or \p p_target_name was NULL.
*/
bool ble_advdata_short_name_find(uint8_t const * p_encoded_data,
uint16_t data_len,
char const * p_target_name,
uint8_t const short_name_min_len);
/**@brief Function for searching through encoded Advertising data for a UUID (16-bit or 128-bit).
*
* @param[in] p_encoded_data Data buffer containing the encoded Advertising data.
* @param[in] data_len Length of the data buffer \p p_encoded_data.
* @param[in] p_target_uuid UUID to search for.
*
* @retval true If \p p_target_uuid was found among \p p_encoded_data.
* @retval false If \p p_target_uuid was not found among \p p_encoded_data, or if \p p_encoded_data
* or \p p_target_uuid was NULL.
*/
bool ble_advdata_uuid_find(uint8_t const * p_encoded_data,
uint16_t data_len,
ble_uuid_t const * p_target_uuid);
/**@brief Function for searching through encoded Advertising data for an appearance.
*
* @param[in] p_encoded_data Data buffer containing the encoded Advertising data.
* @param[in] data_len Length of the data buffer \p p_encoded_data.
* @param[in] p_target_appearance Appearance to search for.
*
* @retval true If \p p_target_appearance was found among \p p_encoded_data.
* @retval false If \p p_target_appearance was not found among \p p_encoded_data, or if \p p_encoded_data
* or \p p_target_appearance was NULL.
*/
bool ble_advdata_appearance_find(uint8_t const * p_encoded_data,
uint16_t data_len,
uint16_t const * p_target_appearance);
#ifdef __cplusplus
}
#endif
#endif // BLE_ADVDATA_H__
/** @} */

View File

@@ -0,0 +1,572 @@
/**
* 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(NRF_BLE_CONN_PARAMS)
#include <stdlib.h>
#include "nrf.h"
#include "sdk_errors.h"
#include "ble_hci.h"
#include "ble_err.h"
#include "ble_conn_params.h"
#include "ble_srv_common.h"
#include "ble_conn_state.h"
#include "nrf_sdh_ble.h"
#include "app_timer.h"
#include "app_util.h"
#define NRF_BLE_CONN_PARAMS_INSTANCE_COUNT NRF_SDH_BLE_PERIPHERAL_LINK_COUNT //!< The number of @ref ble_conn_params_instance_t instances kept by the conn_params module.
#if (NRF_BLE_CONN_PARAMS_INSTANCE_COUNT < 1)
#error Invalid NRF_SDH_BLE_PERIPHERAL_LINK_COUNT value. Set it in SDK config (nrf_sdh_ble).
#endif
/** @brief Each peripheral link has such an instance associated with it.
*/
typedef struct
{
uint16_t conn_handle; //!< The connection handle of this link. If this is @ref BLE_CONN_HANDLE_INVALID, the instance is free.
app_timer_id_t timer_id; //!< The ID of the timer associated with this link.
uint8_t update_count; //!< The number of times the connection parameters have been attempted negotiated on this link.
uint8_t params_ok; //!< Whether the current connection parameters on this link are acceptable according to the @p preferred_conn_params, and configured maximum deviations.
ble_gap_conn_params_t preferred_conn_params; //!< The desired connection parameters for this link.
} ble_conn_params_instance_t;
static app_timer_t m_timer_data[NRF_BLE_CONN_PARAMS_INSTANCE_COUNT] = {{{0}}}; //!< Data needed for timers.
static ble_conn_params_instance_t m_conn_params_instances[NRF_BLE_CONN_PARAMS_INSTANCE_COUNT] = {{0}}; //!< Configuration data for each connection.
static ble_conn_params_init_t m_conn_params_config; //!< Configuration as provided by the application during intialization.
static ble_gap_conn_params_t m_preferred_conn_params; //!< The preferred connection parameters as specified during initialization.
//lint -esym(551, m_preferred_conn_params) "Not accessed"
/**@brief Function for retrieving the conn_params instance belonging to a conn_handle
*
* @params[in] conn_handle The connection handle to retrieve the instance of.
*
* @return A pointer to the instance, or NULL if no instance was found with that conn_handle.
*/
static ble_conn_params_instance_t * instance_get(uint16_t conn_handle)
{
//lint -save -e681 "Loop not entered" when NRF_BLE_CONN_PARAMS_INSTANCE_COUNT is 0
for (uint32_t i = 0; i < NRF_BLE_CONN_PARAMS_INSTANCE_COUNT; i++)
{
if (m_conn_params_instances[i].conn_handle == conn_handle)
{
return &m_conn_params_instances[i];
}
}
//lint -restore
return NULL;
}
/**@brief Function for initializing an instance, and associating it with a conn_handle.
*
* @params[in] p_instance The instance to initialize and associate.
* @params[in] conn_handle The connection handle to associate with.
*/
static __INLINE void instance_claim(ble_conn_params_instance_t * p_instance, uint16_t conn_handle)
{
p_instance->conn_handle = conn_handle;
p_instance->update_count = 0;
p_instance->preferred_conn_params = m_preferred_conn_params;
}
/**@brief Function for freeing an instance.
*
* @params[in] p_instance The instance to free.
*/
static __INLINE void instance_free(ble_conn_params_instance_t * p_instance)
{
p_instance->conn_handle = BLE_CONN_HANDLE_INVALID;
}
/**@brief Function for validating a set of connection parameters against the preferred parameters.
*
* @param[in] p_preferred_conn_params The desired parameters.
* @param[in] p_actual_conn_params The parameters to validate.
* @param[in] max_slave_latency_err The amount of discrepancy in slave latency, in number of
* connection intervals, that will be accepted.
* @param[in] max_sup_timeout_err The amount of discrepancy in supervision timeout, in tens of
* milliseconds, that will be accepted.
*
* @return Whether the params in @p p_actual_conn_params are acceptable given the other parameters.
*/
static bool is_conn_params_ok(ble_gap_conn_params_t const * p_preferred_conn_params,
ble_gap_conn_params_t const * p_actual_conn_params,
uint16_t max_slave_latency_err,
uint16_t max_sup_timeout_err)
{
uint32_t max_allowed_sl = p_preferred_conn_params->slave_latency + max_slave_latency_err;
uint32_t min_allowed_sl = p_preferred_conn_params->slave_latency
- MIN(max_slave_latency_err, p_preferred_conn_params->slave_latency);
uint32_t max_allowed_to = p_preferred_conn_params->conn_sup_timeout + max_sup_timeout_err;
uint32_t min_allowed_to = p_preferred_conn_params->conn_sup_timeout
- MIN(max_sup_timeout_err, p_preferred_conn_params->conn_sup_timeout);
// Check if interval is within the acceptable range.
// NOTE: Using max_conn_interval in the received event data because this contains
// the client's connection interval.
if ((p_actual_conn_params->max_conn_interval < p_preferred_conn_params->min_conn_interval)
|| (p_actual_conn_params->max_conn_interval > p_preferred_conn_params->max_conn_interval))
{
return false;
}
// Check if slave latency is within the acceptable deviation.
if ((p_actual_conn_params->slave_latency < min_allowed_sl)
|| (p_actual_conn_params->slave_latency > max_allowed_sl))
{
return false;
}
// Check if supervision timeout is within the acceptable deviation.
if ((p_actual_conn_params->conn_sup_timeout < min_allowed_to)
|| (p_actual_conn_params->conn_sup_timeout > max_allowed_to))
{
return false;
}
return true;
}
static void send_error_evt(ret_code_t err_code)
{
if (m_conn_params_config.error_handler != NULL)
{
m_conn_params_config.error_handler(err_code);
}
}
/**@brief Function for sending a conn_param_update request on-air, and handling errors.
*
* @param[in] conn_handle Connection to send request on.
* @param[in] p_new_conn_params Connection parameters to request.
*
* @return Whether the request was successfully sent.
*/
static bool send_update_request(uint16_t conn_handle, ble_gap_conn_params_t * p_new_conn_params)
{
ret_code_t err_code;
err_code = sd_ble_gap_conn_param_update(conn_handle, p_new_conn_params);
if ((err_code != NRF_SUCCESS) && (err_code != NRF_ERROR_BUSY)) // NRF_ERROR_BUSY means another conn_param_update request is pending.
{
send_error_evt(err_code);
}
return (err_code == NRF_SUCCESS);
}
/**@brief Function called after conn_params_update_delay has happened. This is triggered by app_timer.
*
* @param[in] p_context Context identifying which connection this is for.
*/
static void update_timeout_handler(void * p_context)
{
uint32_t conn_handle = (uint32_t)p_context;
ble_conn_params_instance_t * p_instance = instance_get(conn_handle);
if (p_instance != NULL)
{
// Check if we have reached the maximum number of attempts
if (p_instance->update_count < m_conn_params_config.max_conn_params_update_count)
{
bool update_sent = send_update_request(conn_handle, &p_instance->preferred_conn_params);
if (update_sent)
{
p_instance->update_count++;
}
}
else
{
p_instance->update_count = 0;
// Negotiation failed, disconnect automatically if this has been configured
if (m_conn_params_config.disconnect_on_fail)
{
ret_code_t err_code;
err_code = sd_ble_gap_disconnect(conn_handle, BLE_HCI_CONN_INTERVAL_UNACCEPTABLE);
if ((err_code != NRF_SUCCESS) && (err_code != NRF_ERROR_INVALID_STATE)) // NRF_ERROR_INVALID_STATE means disconnect is already in progress.
{
send_error_evt(err_code);
}
}
// Notify the application that the procedure has failed
if (m_conn_params_config.evt_handler != NULL)
{
ble_conn_params_evt_t evt;
evt.evt_type = BLE_CONN_PARAMS_EVT_FAILED;
evt.conn_handle = conn_handle;
m_conn_params_config.evt_handler(&evt);
}
}
}
}
ret_code_t ble_conn_params_init(const ble_conn_params_init_t * p_init)
{
ret_code_t err_code;
VERIFY_PARAM_NOT_NULL(p_init);
m_conn_params_config = *p_init;
m_conn_params_config.p_conn_params = &m_preferred_conn_params;
if (p_init->p_conn_params != NULL)
{
// Set the connection params in stack.
err_code = sd_ble_gap_ppcp_set(p_init->p_conn_params);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
m_preferred_conn_params = *p_init->p_conn_params;
}
else
{
// Get the (default) connection params from stack.
err_code = sd_ble_gap_ppcp_get(&m_preferred_conn_params);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
}
//lint -save -e681 "Loop not entered" when NRF_BLE_CONN_PARAMS_INSTANCE_COUNT is 0
for (uint32_t i = 0; i < NRF_BLE_CONN_PARAMS_INSTANCE_COUNT; i++)
{
ble_conn_params_instance_t * p_instance = &m_conn_params_instances[i];
instance_free(p_instance);
p_instance->timer_id = &m_timer_data[i];
err_code = app_timer_create(&p_instance->timer_id,
APP_TIMER_MODE_SINGLE_SHOT,
update_timeout_handler);
if (err_code != NRF_SUCCESS)
{
return NRF_ERROR_INTERNAL;
}
}
//lint -restore
return NRF_SUCCESS;
}
ret_code_t ble_conn_params_stop(void)
{
ret_code_t err_code;
//lint -save -e681 "Loop not entered" when NRF_BLE_CONN_PARAMS_INSTANCE_COUNT is 0
for (uint32_t i = 0; i < NRF_BLE_CONN_PARAMS_INSTANCE_COUNT; i++)
{
err_code = app_timer_stop(m_conn_params_instances[i].timer_id);
switch (err_code)
{
case NRF_SUCCESS:
/* do nothing */
break;
case NRF_ERROR_INVALID_STATE:
/* do nothing */
break;
case NRF_ERROR_NO_MEM:
return NRF_ERROR_BUSY;
case NRF_ERROR_INVALID_PARAM:
/* fallthrough */
default:
return NRF_ERROR_INTERNAL;
}
}
//lint -restore
return NRF_SUCCESS;
}
/**@brief Function for taking appropriate action based on the current state of connection parameters.
*
* @param[in] conn_handle Connection to handle.
* @param[in] p_instance Configuration for the connection.
*/
static void conn_params_negotiation(uint16_t conn_handle, ble_conn_params_instance_t * p_instance)
{
// Start negotiation if the received connection parameters are not acceptable
if (!p_instance->params_ok)
{
ret_code_t err_code;
uint32_t timeout_ticks;
if (p_instance->update_count == 0)
{
// First connection parameter update
timeout_ticks = m_conn_params_config.first_conn_params_update_delay;
}
else
{
timeout_ticks = m_conn_params_config.next_conn_params_update_delay;
}
err_code = app_timer_start(p_instance->timer_id, timeout_ticks, (void *)(uint32_t)conn_handle);
if (err_code != NRF_SUCCESS)
{
send_error_evt(err_code);
}
}
else
{
p_instance->update_count = 0;
// Notify the application that the procedure has succeeded
if (m_conn_params_config.evt_handler != NULL)
{
ble_conn_params_evt_t evt;
evt.evt_type = BLE_CONN_PARAMS_EVT_SUCCEEDED;
evt.conn_handle = conn_handle;
m_conn_params_config.evt_handler(&evt);
}
}
}
/**@brief Function for handling a connection event from the SoftDevice.
*
* @param[in] p_ble_evt Event from the SoftDevice.
*/
static void on_connect(ble_evt_t const * p_ble_evt)
{
uint8_t role = p_ble_evt->evt.gap_evt.params.connected.role;
uint16_t conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
if (role != BLE_GAP_ROLE_PERIPH)
{
return;
}
ble_conn_params_instance_t * p_instance = instance_get(BLE_CONN_HANDLE_INVALID);
if (p_instance == NULL)
{
send_error_evt(NRF_ERROR_NO_MEM);
return;
}
instance_claim(p_instance, conn_handle);
p_instance->params_ok = is_conn_params_ok(&p_instance->preferred_conn_params,
&p_ble_evt->evt.gap_evt.params.connected.conn_params,
NRF_BLE_CONN_PARAMS_MAX_SLAVE_LATENCY_DEVIATION,
NRF_BLE_CONN_PARAMS_MAX_SUPERVISION_TIMEOUT_DEVIATION);
// Check if we shall handle negotiation on connect
if (m_conn_params_config.start_on_notify_cccd_handle == BLE_GATT_HANDLE_INVALID)
{
conn_params_negotiation(conn_handle, p_instance);
}
}
/**@brief Function for handling a disconnection event from the SoftDevice.
*
* @param[in] p_ble_evt Event from the SoftDevice.
*/
static void on_disconnect(ble_evt_t const * p_ble_evt)
{
ret_code_t err_code;
uint16_t conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
ble_conn_params_instance_t * p_instance = instance_get(conn_handle);
if (p_instance != NULL)
{
// Stop timer if running
err_code = app_timer_stop(p_instance->timer_id);
if (err_code != NRF_SUCCESS)
{
send_error_evt(err_code);
}
instance_free(p_instance);
}
}
/**@brief Function for handling a GATT write event from the SoftDevice.
*
* @details To provide the start_on_notify_cccd_handle functionality.
*
* @param[in] p_ble_evt Event from the SoftDevice.
*/
static void on_write(ble_evt_t const * p_ble_evt)
{
ble_gatts_evt_write_t const * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
// Check if this is the correct CCCD
if (
(p_evt_write->handle == m_conn_params_config.start_on_notify_cccd_handle)
&&
(p_evt_write->len == 2)
)
{
uint16_t conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
ble_conn_params_instance_t * p_instance = instance_get(conn_handle);
if (p_instance != NULL)
{
// Check if this is a 'start notification'
if (ble_srv_is_notification_enabled(p_evt_write->data))
{
// Do connection parameter negotiation if necessary
conn_params_negotiation(conn_handle, p_instance);
}
else
{
ret_code_t err_code;
// Stop timer if running
err_code = app_timer_stop(p_instance->timer_id);
if (err_code != NRF_SUCCESS)
{
send_error_evt(err_code);
}
}
}
}
}
/**@brief Function for handling a connection parameter update event from the SoftDevice.
*
* @details This event means the peer central has changed the connection parameters or declined our
* request.
*
* @param[in] p_ble_evt Event from the SoftDevice.
*/
static void on_conn_params_update(ble_evt_t const * p_ble_evt)
{
uint16_t conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
ble_conn_params_instance_t * p_instance = instance_get(conn_handle);
if (p_instance != NULL)
{
p_instance->params_ok = is_conn_params_ok(
&p_instance->preferred_conn_params,
&p_ble_evt->evt.gap_evt.params.conn_param_update.conn_params,
NRF_BLE_CONN_PARAMS_MAX_SLAVE_LATENCY_DEVIATION,
NRF_BLE_CONN_PARAMS_MAX_SUPERVISION_TIMEOUT_DEVIATION);
conn_params_negotiation(conn_handle, p_instance);
}
}
/**
* @brief Function for handling BLE events.
*
* @param[in] p_ble_evt Event received from the BLE stack.
* @param[in] p_context Context.
*/
static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
{
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_WRITE:
on_write(p_ble_evt);
break;
case BLE_GAP_EVT_CONN_PARAM_UPDATE:
on_conn_params_update(p_ble_evt);
break;
default:
// No implementation needed.
break;
}
}
ret_code_t ble_conn_params_change_conn_params(uint16_t conn_handle,
ble_gap_conn_params_t * p_new_params)
{
ret_code_t err_code = BLE_ERROR_INVALID_CONN_HANDLE;
ble_conn_params_instance_t * p_instance = instance_get(conn_handle);
if (p_new_params == NULL)
{
p_new_params = &m_preferred_conn_params;
}
if (p_instance != NULL)
{
// Send request to central.
err_code = sd_ble_gap_conn_param_update(conn_handle, p_new_params);
if (err_code == NRF_SUCCESS)
{
p_instance->params_ok = false;
p_instance->update_count = 1;
p_instance->preferred_conn_params = *p_new_params;
}
}
return err_code;
}
NRF_SDH_BLE_OBSERVER(m_ble_observer, BLE_CONN_PARAMS_BLE_OBSERVER_PRIO, ble_evt_handler, NULL);
#endif //ENABLED

View File

@@ -0,0 +1,156 @@
/**
* 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_conn_params Connection Parameters Negotiation
* @{
* @ingroup ble_sdk_lib
* @brief Module for initiating and executing a connection parameters negotiation procedure.
*/
#ifndef BLE_CONN_PARAMS_H__
#define BLE_CONN_PARAMS_H__
#include <stdint.h>
#include "ble.h"
#include "ble_srv_common.h"
#include "sdk_errors.h"
#ifdef __cplusplus
extern "C" {
#endif
/**@brief Connection Parameters Module event type. */
typedef enum
{
BLE_CONN_PARAMS_EVT_FAILED, //!< Negotiation procedure failed.
BLE_CONN_PARAMS_EVT_SUCCEEDED //!< Negotiation procedure succeeded.
} ble_conn_params_evt_type_t;
/**@brief Connection Parameters Module event. */
typedef struct
{
ble_conn_params_evt_type_t evt_type; //!< Type of event.
uint16_t conn_handle; //!< Connection the event refers to.
} ble_conn_params_evt_t;
/**@brief Connection Parameters Module event handler type. */
typedef void (*ble_conn_params_evt_handler_t) (ble_conn_params_evt_t * p_evt);
/**@brief Connection Parameters Module init structure. This contains all options and data needed for
* initialization of the connection parameters negotiation module. */
typedef struct
{
ble_gap_conn_params_t * p_conn_params; //!< Pointer to the connection parameters desired by the application. When calling ble_conn_params_init, if this parameter is set to NULL, the connection parameters will be fetched from host.
uint32_t first_conn_params_update_delay; //!< Time from initiating event (connect or start of notification) to first time sd_ble_gap_conn_param_update is called (in number of timer ticks).
uint32_t next_conn_params_update_delay; //!< Time between each call to sd_ble_gap_conn_param_update after the first (in number of timer ticks). Recommended value 30 seconds as per BLUETOOTH SPECIFICATION Version 4.0.
uint8_t max_conn_params_update_count; //!< Number of attempts before giving up the negotiation.
uint16_t start_on_notify_cccd_handle; //!< If procedure is to be started when notification is started, set this to the handle of the corresponding CCCD. Set to BLE_GATT_HANDLE_INVALID if procedure is to be started on connect event.
bool disconnect_on_fail; //!< Set to TRUE if a failed connection parameters update shall cause an automatic disconnection, set to FALSE otherwise.
ble_conn_params_evt_handler_t evt_handler; //!< Event handler to be called for handling events in the Connection Parameters.
ble_srv_error_handler_t error_handler; //!< Function to be called in case of an error.
} ble_conn_params_init_t;
/**@brief Function for initializing the Connection Parameters module.
*
* @note If the negotiation procedure should be triggered when notification/indication of
* any characteristic is enabled by the peer, then this function must be called after
* having initialized the services.
*
* @param[in] p_init This contains information needed to initialize this module.
*
* @retval NRF_SUCCESS Successful initialization.
* @retval NRF_ERROR_INVALID_ADDR The provided Connection Parameters pointer is invalid.
* @retval NRF_ERROR_INVALID_PARAM The provided Connection Parameters are not valid.
* @retval NRF_ERROR_NULL @p p_init was NULL.
* @retval NRF_ERROR_INTERNAL An unexpected error occurred.
*/
ret_code_t ble_conn_params_init(const ble_conn_params_init_t * p_init);
/**@brief Function for stopping the Connection Parameters module.
*
* @details This function is intended to be used by the application to clean up the connection
* parameters update module. This will stop the connection parameters update timer if
* running, thereby preventing any impending connection parameters update procedure. This
* function must be called by the application when it needs to clean itself up (for
* example, before disabling the bluetooth SoftDevice) so that an unwanted timer expiry
* event can be avoided.
*
* @retval NRF_SUCCESS Successfully stopped module.
* @retval NRF_ERROR_BUSY Could not complete operation at this time. Try again later.
Note that some timers may have been disabled.
* @retval NRF_ERROR_INTERNAL An unexpected error occurred.
*/
ret_code_t ble_conn_params_stop(void);
/**@brief Function for changing the current connection parameters to a new set.
*
* @details Use this function to change the connection parameters to a new set of parameter
* (ie different from the ones given at init of the module).
* This function is useful for scenario where most of the time the application
* needs a relatively big connection interval, and just sometimes, for a temporary
* period requires shorter connection interval, for example to transfer a higher
* amount of data.
* If the given parameters does not match the current connection's parameters
* this function initiates a new negotiation.
*
* @param[in] conn_handle The connection to change connection parameters on.
* @param[in] p_new_params This contains the new connections parameters to setup.
*
* @retval NRF_SUCCESS Successfully started Connection Parameter update procedure.
* @retval NRF_ERROR_INVALID_ADDR The provided Connection Parameters pointer is invalid.
* @retval NRF_ERROR_INVALID_PARAM The provided Connection Parameters are not valid.
* @retval BLE_ERROR_INVALID_CONN_HANDLE The provided connection handle is invalid.
* @retval NRF_ERROR_INVALID_STATE The connection is not in a state where this operation can
* performed.
* @retval NRF_ERROR_BUSY Could not start operation at this time. Try again later.
* @retval NRF_ERROR_NO_MEM The SoftDevice lacks the memory to perform the action.
*/
ret_code_t ble_conn_params_change_conn_params(uint16_t conn_handle,
ble_gap_conn_params_t * p_new_params);
#ifdef __cplusplus
}
#endif
#endif // BLE_CONN_PARAMS_H__
/** @} */

View File

@@ -0,0 +1,497 @@
/**
* 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 "ble_conn_state.h"
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "ble.h"
#include "nrf_atflags.h"
#include "app_error.h"
#include "nrf_sdh_ble.h"
#include "app_util_platform.h"
#define DEFAULT_FLAG_COLLECTION_COUNT 6 /**< The number of flags kept for each connection, excluding user flags. */
#define TOTAL_FLAG_COLLECTION_COUNT (DEFAULT_FLAG_COLLECTION_COUNT \
+ BLE_CONN_STATE_USER_FLAG_COUNT) /**< The number of flags kept for each connection, including user flags. */
/**@brief Structure containing all the flag collections maintained by the Connection State module.
*/
typedef struct
{
nrf_atflags_t valid_flags; /**< Flags indicating which connection handles are valid. */
nrf_atflags_t connected_flags; /**< Flags indicating which connections are connected, since disconnected connection handles will not immediately be invalidated. */
nrf_atflags_t central_flags; /**< Flags indicating in which connections the local device is the central. */
nrf_atflags_t encrypted_flags; /**< Flags indicating which connections are encrypted. */
nrf_atflags_t mitm_protected_flags; /**< Flags indicating which connections have encryption with protection from man-in-the-middle attacks. */
nrf_atflags_t lesc_flags; /**< Flags indicating which connections have bonded using LE Secure Connections (LESC). */
nrf_atflags_t user_flags[BLE_CONN_STATE_USER_FLAG_COUNT]; /**< Flags that can be reserved by the user. The flags will be cleared when a connection is invalidated, otherwise, the user is wholly responsible for the flag states. */
} ble_conn_state_flag_collections_t;
ANON_UNIONS_ENABLE;
/**@brief Structure containing the internal state of the Connection State module.
*/
typedef struct
{
nrf_atflags_t acquired_flags; /**< Bitmap for keeping track of which user flags have been acquired. */
union
{
ble_conn_state_flag_collections_t flags; /**< Flag collections kept by the Connection State module. */
nrf_atflags_t flag_array[TOTAL_FLAG_COLLECTION_COUNT]; /**< Flag collections as array to allow iterating over all flag collections. */
};
} ble_conn_state_t;
ANON_UNIONS_DISABLE;
static ble_conn_state_t m_bcs = {0}; /**< Instantiation of the internal state. */
/**@brief Function for resetting all internal memory to the values it had at initialization.
*/
void bcs_internal_state_reset(void)
{
memset( &m_bcs, 0, sizeof(ble_conn_state_t) );
}
ble_conn_state_conn_handle_list_t conn_handle_list_get(nrf_atflags_t flags)
{
ble_conn_state_conn_handle_list_t conn_handle_list;
conn_handle_list.len = 0;
if (flags != 0)
{
for (uint32_t i = 0; i < BLE_CONN_STATE_MAX_CONNECTIONS; i++)
{
if (nrf_atflags_get(&flags, i))
{
conn_handle_list.conn_handles[conn_handle_list.len++] = i;
}
}
}
return conn_handle_list;
}
uint32_t active_flag_count(nrf_atflags_t flags)
{
uint32_t set_flag_count = 0;
for (uint32_t i = 0; i < BLE_CONN_STATE_MAX_CONNECTIONS; i++)
{
if (nrf_atflags_get(&flags, i))
{
set_flag_count += 1;
}
}
return set_flag_count;
}
/**@brief Function for activating a connection record.
*
* @param p_record The record to activate.
* @param conn_handle The connection handle to copy into the record.
* @param role The role of the connection.
*
* @return whether the record was activated successfully.
*/
static bool record_activate(uint16_t conn_handle)
{
if (conn_handle >= BLE_CONN_STATE_MAX_CONNECTIONS)
{
return false;
}
nrf_atflags_set(&m_bcs.flags.connected_flags, conn_handle);
nrf_atflags_set(&m_bcs.flags.valid_flags, conn_handle);
return true;
}
/**@brief Function for marking a connection record as invalid and resetting the values.
*
* @param p_record The record to invalidate.
*/
static void record_invalidate(uint16_t conn_handle)
{
for (uint32_t i = 0; i < TOTAL_FLAG_COLLECTION_COUNT; i++)
{
nrf_atflags_clear(&m_bcs.flag_array[i], conn_handle);
}
}
/**@brief Function for marking a connection as disconnected. See @ref BLE_CONN_STATUS_DISCONNECTED.
*
* @param p_record The record of the connection to set as disconnected.
*/
static void record_set_disconnected(uint16_t conn_handle)
{
nrf_atflags_clear(&m_bcs.flags.connected_flags, conn_handle);
}
/**@brief Function for invalidating records with a @ref BLE_CONN_STATUS_DISCONNECTED
* connection status
*/
static void record_purge_disconnected()
{
nrf_atflags_t disconnected_flags = ~m_bcs.flags.connected_flags;
ble_conn_state_conn_handle_list_t disconnected_list;
UNUSED_RETURN_VALUE(nrf_atomic_u32_and(&disconnected_flags, m_bcs.flags.valid_flags));
disconnected_list = conn_handle_list_get(disconnected_flags);
for (uint32_t i = 0; i < disconnected_list.len; i++)
{
record_invalidate(disconnected_list.conn_handles[i]);
}
}
/**@brief Function for checking if a user flag has been acquired.
*
* @param[in] flag_id Which flag to check.
*
* @return Whether the flag has been acquired.
*/
static bool user_flag_is_acquired(ble_conn_state_user_flag_id_t flag_id)
{
return nrf_atflags_get(&m_bcs.acquired_flags, flag_id);
}
void ble_conn_state_init(void)
{
bcs_internal_state_reset();
}
static void flag_toggle(nrf_atflags_t * p_flags, uint16_t conn_handle, bool value)
{
if (value)
{
nrf_atflags_set(p_flags, conn_handle);
}
else
{
nrf_atflags_clear(p_flags, conn_handle);
}
}
/**
* @brief Function for handling BLE events.
*
* @param[in] p_ble_evt Event received from the BLE stack.
* @param[in] p_context Context.
*/
static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
{
uint16_t conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
switch (p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_CONNECTED:
record_purge_disconnected();
if ( !record_activate(conn_handle) )
{
// No more records available. Should not happen.
APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
}
#ifdef BLE_GAP_ROLE_CENTRAL
else if ((p_ble_evt->evt.gap_evt.params.connected.role == BLE_GAP_ROLE_CENTRAL))
{
// Central
nrf_atflags_set(&m_bcs.flags.central_flags, conn_handle);
}
#endif // BLE_GAP_ROLE_CENTRAL
else
{
// No implementation required.
}
break;
case BLE_GAP_EVT_DISCONNECTED:
record_set_disconnected(conn_handle);
break;
case BLE_GAP_EVT_CONN_SEC_UPDATE:
{
uint8_t sec_lv = p_ble_evt->evt.gap_evt.params.conn_sec_update.conn_sec.sec_mode.lv;
// Set/unset flags based on security level.
flag_toggle(&m_bcs.flags.lesc_flags, conn_handle, sec_lv >= 4);
flag_toggle(&m_bcs.flags.mitm_protected_flags, conn_handle, sec_lv >= 3);
flag_toggle(&m_bcs.flags.encrypted_flags, conn_handle, sec_lv >= 2);
break;
}
case BLE_GAP_EVT_AUTH_STATUS:
if (p_ble_evt->evt.gap_evt.params.auth_status.auth_status == BLE_GAP_SEC_STATUS_SUCCESS)
{
bool lesc = p_ble_evt->evt.gap_evt.params.auth_status.lesc;
flag_toggle(&m_bcs.flags.lesc_flags, conn_handle, lesc);
}
break;
}
}
NRF_SDH_BLE_OBSERVER(m_ble_evt_observer, BLE_CONN_STATE_BLE_OBSERVER_PRIO, ble_evt_handler, NULL);
bool ble_conn_state_valid(uint16_t conn_handle)
{
if (conn_handle >= BLE_CONN_STATE_MAX_CONNECTIONS)
{
return false;
}
return nrf_atflags_get(&m_bcs.flags.valid_flags, conn_handle);
}
uint8_t ble_conn_state_role(uint16_t conn_handle)
{
uint8_t role = BLE_GAP_ROLE_INVALID;
if (ble_conn_state_valid(conn_handle))
{
#if defined (BLE_GAP_ROLE_PERIPH) && defined (BLE_GAP_ROLE_CENTRAL)
bool central = nrf_atflags_get(&m_bcs.flags.central_flags, conn_handle);
role = central ? BLE_GAP_ROLE_CENTRAL : BLE_GAP_ROLE_PERIPH;
#elif defined (BLE_GAP_ROLE_CENTRAL)
role = BLE_GAP_ROLE_CENTRAL;
#else
role = BLE_GAP_ROLE_PERIPH;
#endif // defined (BLE_GAP_ROLE_PERIPH) && defined (BLE_GAP_ROLE_CENTRAL)
}
return role;
}
ble_conn_state_status_t ble_conn_state_status(uint16_t conn_handle)
{
ble_conn_state_status_t conn_status = BLE_CONN_STATUS_INVALID;
if (ble_conn_state_valid(conn_handle))
{
bool connected = nrf_atflags_get(&m_bcs.flags.connected_flags, conn_handle);
conn_status = connected ? BLE_CONN_STATUS_CONNECTED : BLE_CONN_STATUS_DISCONNECTED;
}
return conn_status;
}
bool ble_conn_state_encrypted(uint16_t conn_handle)
{
if (ble_conn_state_valid(conn_handle))
{
return nrf_atflags_get(&m_bcs.flags.encrypted_flags, conn_handle);
}
return false;
}
bool ble_conn_state_mitm_protected(uint16_t conn_handle)
{
if (ble_conn_state_valid(conn_handle))
{
return nrf_atflags_get(&m_bcs.flags.mitm_protected_flags, conn_handle);
}
return false;
}
bool ble_conn_state_lesc(uint16_t conn_handle)
{
if (ble_conn_state_valid(conn_handle))
{
return nrf_atflags_get(&m_bcs.flags.lesc_flags, conn_handle);
}
return false;
}
uint32_t ble_conn_state_conn_count(void)
{
return active_flag_count(m_bcs.flags.connected_flags);
}
uint32_t ble_conn_state_central_conn_count(void)
{
nrf_atflags_t central_conn_flags = m_bcs.flags.central_flags;
UNUSED_RETURN_VALUE(nrf_atomic_u32_and(&central_conn_flags, m_bcs.flags.connected_flags));
return active_flag_count(central_conn_flags);
}
uint32_t ble_conn_state_peripheral_conn_count(void)
{
nrf_atflags_t peripheral_conn_flags = ~m_bcs.flags.central_flags;
UNUSED_RETURN_VALUE(nrf_atomic_u32_and(&peripheral_conn_flags, m_bcs.flags.connected_flags));
return active_flag_count(peripheral_conn_flags);
}
ble_conn_state_conn_handle_list_t ble_conn_state_conn_handles(void)
{
return conn_handle_list_get(m_bcs.flags.valid_flags);
}
ble_conn_state_conn_handle_list_t ble_conn_state_central_handles(void)
{
nrf_atflags_t central_conn_flags = m_bcs.flags.central_flags;
UNUSED_RETURN_VALUE(nrf_atomic_u32_and(&central_conn_flags, m_bcs.flags.connected_flags));
return conn_handle_list_get(central_conn_flags);
}
ble_conn_state_conn_handle_list_t ble_conn_state_periph_handles(void)
{
nrf_atflags_t peripheral_conn_flags = ~m_bcs.flags.central_flags;
UNUSED_RETURN_VALUE(nrf_atomic_u32_and(&peripheral_conn_flags, m_bcs.flags.connected_flags));
return conn_handle_list_get(peripheral_conn_flags);
}
uint16_t ble_conn_state_conn_idx(uint16_t conn_handle)
{
if (ble_conn_state_valid(conn_handle))
{
return conn_handle;
}
else
{
return BLE_CONN_STATE_MAX_CONNECTIONS;
}
}
ble_conn_state_user_flag_id_t ble_conn_state_user_flag_acquire(void)
{
uint32_t acquired_flag = nrf_atflags_find_and_set_flag(&m_bcs.acquired_flags,
BLE_CONN_STATE_USER_FLAG_COUNT);
if (acquired_flag == BLE_CONN_STATE_USER_FLAG_COUNT)
{
return BLE_CONN_STATE_USER_FLAG_INVALID;
}
return (ble_conn_state_user_flag_id_t)acquired_flag;
}
bool ble_conn_state_user_flag_get(uint16_t conn_handle, ble_conn_state_user_flag_id_t flag_id)
{
if (user_flag_is_acquired(flag_id) && ble_conn_state_valid(conn_handle))
{
return nrf_atflags_get(&m_bcs.flags.user_flags[flag_id], conn_handle);
}
else
{
return false;
}
}
void ble_conn_state_user_flag_set(uint16_t conn_handle,
ble_conn_state_user_flag_id_t flag_id,
bool value)
{
if (user_flag_is_acquired(flag_id) && ble_conn_state_valid(conn_handle))
{
flag_toggle(&m_bcs.flags.user_flags[flag_id], conn_handle, value);
}
}
static uint32_t for_each_set_flag(nrf_atflags_t flags,
ble_conn_state_user_function_t user_function,
void * p_context)
{
if (user_function == NULL)
{
return 0;
}
uint32_t call_count = 0;
if (flags != 0)
{
for (uint32_t i = 0; i < BLE_CONN_STATE_MAX_CONNECTIONS; i++)
{
if (nrf_atflags_get(&flags, i))
{
user_function(i, p_context);
call_count += 1;
}
}
}
return call_count;
}
uint32_t ble_conn_state_for_each_connected(ble_conn_state_user_function_t user_function,
void * p_context)
{
return for_each_set_flag(m_bcs.flags.connected_flags, user_function, p_context);
}
uint32_t ble_conn_state_for_each_set_user_flag(ble_conn_state_user_flag_id_t flag_id,
ble_conn_state_user_function_t user_function,
void * p_context)
{
if (!user_flag_is_acquired(flag_id))
{
return 0;
}
return for_each_set_flag(m_bcs.flags.user_flags[flag_id], user_function, p_context);
}

View File

@@ -0,0 +1,361 @@
/**
* 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_conn_state Connection state
* @ingroup ble_sdk_lib
* @{
* @brief Module for storing data on BLE connections.
*
* @details This module stores certain states for each connection, which can be queried by
* connection handle. The module uses BLE events to keep the states updated.
*
* In addition to the preprogrammed states, this module can also keep track of a number of
* binary user states, or <i>user flags</i>. These are reset to 0 for new connections, but
* otherwise not touched by this module.
*
* This module uses the @ref nrf_atomic module to make the flag operations thread-safe.
*
* @note A connection handle is not immediately invalidated when it is disconnected. Certain states,
* such as the role, can still be queried until the next time a new connection is established
* to any device.
*
*/
#ifndef BLE_CONN_STATE_H__
#define BLE_CONN_STATE_H__
#include <stdbool.h>
#include <stdint.h>
#include "ble.h"
#include "ble_gap.h"
#include "nrf_atomic.h"
#ifdef __cplusplus
extern "C" {
#endif
/**@brief Connection handle statuses.
*/
typedef enum
{
BLE_CONN_STATUS_INVALID, /**< The connection handle is invalid. */
BLE_CONN_STATUS_DISCONNECTED, /**< The connection handle refers to a connection that has been disconnected, but not yet invalidated. */
BLE_CONN_STATUS_CONNECTED, /**< The connection handle refers to an active connection. */
} ble_conn_state_status_t;
#define BLE_CONN_STATE_MAX_CONNECTIONS BLE_GAP_ROLE_COUNT_COMBINED_MAX /**< The maximum number of connections supported. */
#define BLE_CONN_STATE_USER_FLAG_COUNT 24 /**< The number of available user flags. */
/**@brief Type used to present a list of conn_handles.
*/
typedef struct
{
uint32_t len; /**< The length of the list. */
uint16_t conn_handles[BLE_CONN_STATE_MAX_CONNECTIONS]; /**< The list of handles. */
} ble_conn_state_conn_handle_list_t;
/**@brief One ID for each user flag collection.
*
* @details These IDs are used to identify user flag collections in the API calls.
*/
typedef enum
{
BLE_CONN_STATE_USER_FLAG0 = 0,
BLE_CONN_STATE_USER_FLAG1,
BLE_CONN_STATE_USER_FLAG2,
BLE_CONN_STATE_USER_FLAG3,
BLE_CONN_STATE_USER_FLAG4,
BLE_CONN_STATE_USER_FLAG5,
BLE_CONN_STATE_USER_FLAG6,
BLE_CONN_STATE_USER_FLAG7,
BLE_CONN_STATE_USER_FLAG8,
BLE_CONN_STATE_USER_FLAG9,
BLE_CONN_STATE_USER_FLAG10,
BLE_CONN_STATE_USER_FLAG11,
BLE_CONN_STATE_USER_FLAG12,
BLE_CONN_STATE_USER_FLAG13,
BLE_CONN_STATE_USER_FLAG14,
BLE_CONN_STATE_USER_FLAG15,
BLE_CONN_STATE_USER_FLAG16,
BLE_CONN_STATE_USER_FLAG17,
BLE_CONN_STATE_USER_FLAG18,
BLE_CONN_STATE_USER_FLAG19,
BLE_CONN_STATE_USER_FLAG20,
BLE_CONN_STATE_USER_FLAG21,
BLE_CONN_STATE_USER_FLAG22,
BLE_CONN_STATE_USER_FLAG23,
BLE_CONN_STATE_USER_FLAG_INVALID,
} ble_conn_state_user_flag_id_t;
/**@brief Function to be called when a flag ID is set. See @ref ble_conn_state_for_each_set_user_flag.
*
* @param[in] conn_handle The connection the flag is set for.
* @param[in] p_context Arbitrary pointer provided by the caller of
* @ref ble_conn_state_for_each_set_user_flag.
*/
typedef void (*ble_conn_state_user_function_t)(uint16_t conn_handle, void * p_context);
/**
* @defgroup ble_conn_state_functions BLE connection state functions
* @{
*/
/**@brief Function for initializing or resetting the module.
*
* @details This function sets all states to their default, removing all records of connection handles.
*/
void ble_conn_state_init(void);
/**@brief Function for querying whether a connection handle represents a valid connection.
*
* @details A connection might be valid and have a BLE_CONN_STATUS_DISCONNECTED status.
* Those connections are invalidated after a new connection occurs.
*
* @param[in] conn_handle Handle of the connection.
*
* @retval true If conn_handle represents a valid connection, thus a connection for which
we have a record.
* @retval false If conn_handle is @ref BLE_GAP_ROLE_INVALID, or if it has never been recorded.
*/
bool ble_conn_state_valid(uint16_t conn_handle);
/**@brief Function for querying the role of the local device in a connection.
*
* @param[in] conn_handle Handle of the connection to get the role for.
*
* @return The role of the local device in the connection (see @ref BLE_GAP_ROLES).
* If conn_handle is not valid, the function returns BLE_GAP_ROLE_INVALID.
*/
uint8_t ble_conn_state_role(uint16_t conn_handle);
/**@brief Function for querying the status of a connection.
*
* @param[in] conn_handle Handle of the connection.
*
* @return The status of the connection.
* If conn_handle is not valid, the function returns BLE_CONN_STATE_INVALID.
*/
ble_conn_state_status_t ble_conn_state_status(uint16_t conn_handle);
/**@brief Function for querying whether a connection is encrypted.
*
* @param[in] conn_handle Handle of connection to get the encryption state for.
*
* @retval true If the connection is encrypted.
* @retval false If the connection is not encrypted or conn_handle is invalid.
*/
bool ble_conn_state_encrypted(uint16_t conn_handle);
/**@brief Function for querying whether a connection encryption is protected from Man in the Middle
* attacks.
*
* @param[in] conn_handle Handle of connection to get the MITM state for.
*
* @retval true If the connection is encrypted with MITM protection.
* @retval false If the connection is not encrypted, or encryption is not MITM protected, or
* conn_handle is invalid.
*/
bool ble_conn_state_mitm_protected(uint16_t conn_handle);
/**@brief Function for querying whether a connection was bonded using LE Secure Connections (LESC).
*
* The connection must currently be encrypted.
*
* @note This function will report false if bonded, and the LESC bonding was unauthenticated
* ("Just Works") and happened in a previous connection. To detect such cases as well, check
* the stored bonding key, e.g. in Peer Manager, which has a LESC flag associated with it.
*
* @param[in] conn_handle Handle of connection to get the LESC state for.
*
* @retval true If the connection was bonded using LESC.
* @retval false If the connection has not been bonded using LESC, or conn_handle is invalid.
*/
bool ble_conn_state_lesc(uint16_t conn_handle);
/**@brief Function for querying the total number of connections.
*
* @return The total number of valid connections for which the module has a record.
*/
uint32_t ble_conn_state_conn_count(void);
/**@brief Function for querying the total number of connections in which the role of the local
* device is @ref BLE_GAP_ROLE_CENTRAL.
*
* @return The number of connections in which the role of the local device is
* @ref BLE_GAP_ROLE_CENTRAL.
*/
uint32_t ble_conn_state_central_conn_count(void);
/**@brief Function for querying the total number of connections in which the role of the local
* device is @ref BLE_GAP_ROLE_PERIPH.
*
* @return The number of connections in which the role of the local device is
* @ref BLE_GAP_ROLE_PERIPH.
*/
uint32_t ble_conn_state_peripheral_conn_count(void);
/**@brief Function for obtaining a list of all connection handles for which the module has a record.
*
* @details This function takes into account connections whose state is BLE_CONN_STATUS_DISCONNECTED.
*
* @return A list of all valid connection handles for which the module has a record.
*/
ble_conn_state_conn_handle_list_t ble_conn_state_conn_handles(void);
/**@brief Function for obtaining a list of connection handles in which the role of the local
* device is @ref BLE_GAP_ROLE_CENTRAL.
*
* @details This function takes into account connections whose state is BLE_CONN_STATUS_DISCONNECTED.
*
* @return A list of all valid connection handles for which the module has a record and in which
* the role of local device is @ref BLE_GAP_ROLE_CENTRAL.
*/
ble_conn_state_conn_handle_list_t ble_conn_state_central_handles(void);
/**@brief Function for obtaining the handle for the connection in which the role of the local device
* is @ref BLE_GAP_ROLE_PERIPH.
*
* @details This function takes into account connections whose state is BLE_CONN_STATUS_DISCONNECTED.
*
* @return A list of all valid connection handles for which the module has a record and in which
* the role of local device is @ref BLE_GAP_ROLE_PERIPH.
*/
ble_conn_state_conn_handle_list_t ble_conn_state_periph_handles(void);
/**@brief Function for translating a connection handle to a value that can be used as an array index.
*
* @details Function for mapping connection handles onto the range <0 - MAX_CONNECTIONS>.
*
* @note The index will be the same as long as a connection is invalid. A subsequent connection with
* the same connection handle might have a different index.
*
* @param[in] conn_handle The connection for which to retrieve an index.
*
* @return An index unique to this connection. Or @ref BLE_CONN_STATE_MAX_CONNECTIONS if
* @p conn_handle refers to an invalid connection.
*/
uint16_t ble_conn_state_conn_idx(uint16_t conn_handle);
/**@brief Function for obtaining exclusive access to one of the user flag collections.
*
* @details The acquired collection contains one flag for each connection. These flags can be set
* and read individually for each connection.
*
* The state of user flags will not be modified by the connection state module, except to
* set it to 0 for a connection when that connection is invalidated.
*
* @return The ID of the acquired flag, or BLE_CONN_STATE_USER_FLAG_INVALID if none are available.
*/
ble_conn_state_user_flag_id_t ble_conn_state_user_flag_acquire(void);
/**@brief Function for reading the value of a user flag.
*
* @param[in] conn_handle Handle of connection to get the flag state for.
* @param[in] flag_id Which flag to get the state for.
*
* @return The state of the flag. If conn_handle is invalid, the function returns false.
*/
bool ble_conn_state_user_flag_get(uint16_t conn_handle, ble_conn_state_user_flag_id_t flag_id);
/**@brief Function for setting the value of a user flag.
*
* @param[in] conn_handle Handle of connection to set the flag state for.
* @param[in] flag_id Which flag to set the state for.
* @param[in] value Value to set the flag state to.
*/
void ble_conn_state_user_flag_set(uint16_t conn_handle,
ble_conn_state_user_flag_id_t flag_id,
bool value);
/**@brief Function for running a function for each active connection.
*
* @param[in] user_function The function to run for each connection.
* @param[in] p_context Arbitrary context to be passed to \p user_function.
*
* @return The number of times \p user_function was run.
*/
uint32_t ble_conn_state_for_each_connected(ble_conn_state_user_function_t user_function,
void * p_context);
/**@brief Function for running a function for each flag that is set in a user flag collection.
*
* @param[in] flag_id Which flags to check.
* @param[in] user_function The function to run when a flag is set.
* @param[in] p_context Arbitrary context to be passed to \p user_function.
*
* @return The number of times \p user_function was run.
*/
uint32_t ble_conn_state_for_each_set_user_flag(ble_conn_state_user_flag_id_t flag_id,
ble_conn_state_user_function_t user_function,
void * p_context);
/** @} */
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* BLE_CONN_STATE_H__ */

View File

@@ -0,0 +1,113 @@
/**
* Copyright (c) 2011 - 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 ASAs Bluetooth profile
* qualification listings, this section of source code must not be modified.
*/
/** @file
* @brief Contains definition of ble_date_time structure.
*/
/** @file
*
* @defgroup ble_sdk_srv_date_time BLE Date Time characteristic type
* @{
* @ingroup ble_sdk_lib
* @brief Definition of ble_date_time_t type.
*/
#ifndef BLE_DATE_TIME_H__
#define BLE_DATE_TIME_H__
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/**@brief Date and Time structure. */
typedef struct
{
uint16_t year;
uint8_t month;
uint8_t day;
uint8_t hours;
uint8_t minutes;
uint8_t seconds;
} ble_date_time_t;
static __INLINE uint8_t ble_date_time_encode(const ble_date_time_t * p_date_time,
uint8_t * p_encoded_data)
{
uint8_t len = uint16_encode(p_date_time->year, p_encoded_data);
p_encoded_data[len++] = p_date_time->month;
p_encoded_data[len++] = p_date_time->day;
p_encoded_data[len++] = p_date_time->hours;
p_encoded_data[len++] = p_date_time->minutes;
p_encoded_data[len++] = p_date_time->seconds;
return len;
}
static __INLINE uint8_t ble_date_time_decode(ble_date_time_t * p_date_time,
const uint8_t * p_encoded_data)
{
uint8_t len = sizeof(uint16_t);
p_date_time->year = uint16_decode(p_encoded_data);
p_date_time->month = p_encoded_data[len++];
p_date_time->day = p_encoded_data[len++];
p_date_time->hours = p_encoded_data[len++];
p_date_time->minutes = p_encoded_data[len++];
p_date_time->seconds = p_encoded_data[len++];
return len;
}
#ifdef __cplusplus
}
#endif
#endif // BLE_DATE_TIME_H__
/** @} */

View File

@@ -0,0 +1,92 @@
/**
* 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_sdk_lib_gatt_db GATT Database Service Structure
* @{
* @ingroup ble_sdk_lib
*/
#ifndef BLE_GATT_DB_H__
#define BLE_GATT_DB_H__
#include <stdint.h>
#include "ble.h"
#include "ble_gattc.h"
#include "sdk_config.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifndef BLE_GATT_DB_MAX_CHARS
#define BLE_GATT_DB_MAX_CHARS 6 /**< The maximum number of characteristics present in a service record. */
#endif // BLE_GATT_DB_MAX_CHARS
/**@brief Structure for holding the characteristic and the handle of its CCCD present on a server.
*/
typedef struct
{
ble_gattc_char_t characteristic; /**< Structure containing information about the characteristic. */
uint16_t cccd_handle; /**< CCCD Handle value for this characteristic. This will be set to BLE_GATT_HANDLE_INVALID if a CCCD is not present at the server. */
uint16_t ext_prop_handle; /**< Extended Properties Handle value for this characteristic. This will be set to BLE_GATT_HANDLE_INVALID if an Extended Properties descriptor is not present at the server. */
uint16_t user_desc_handle; /**< User Description Handle value for this characteristic. This will be set to BLE_GATT_HANDLE_INVALID if a User Description descriptor is not present at the server. */
uint16_t report_ref_handle; /**< Report Reference Handle value for this characteristic. This will be set to BLE_GATT_HANDLE_INVALID if a Report Reference descriptor is not present at the server. */
} ble_gatt_db_char_t;
/**@brief Structure for holding information about the service and the characteristics present on a
* server.
*/
typedef struct
{
ble_uuid_t srv_uuid; /**< UUID of the service. */
uint8_t char_count; /**< Number of characteristics present in the service. */
ble_gattc_handle_range_t handle_range; /**< Service Handle Range. */
ble_gatt_db_char_t charateristics[BLE_GATT_DB_MAX_CHARS]; /**< Array of information related to the characteristics present in the service. This list can extend further than one. */
} ble_gatt_db_srv_t;
#ifdef __cplusplus
}
#endif
#endif /* BLE_GATT_DB_H__ */
/** @} */

View File

@@ -0,0 +1,76 @@
/**
* 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 ASAs Bluetooth profile
* qualification listings, this section of source code must not be modified.
*/
#ifndef BLE_SENSOR_LOCATION_H__
#define BLE_SENSOR_LOCATION_H__
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
BLE_SENSOR_LOCATION_OTHER = 0 , /**<-- Other */
BLE_SENSOR_LOCATION_TOP_OF_SHOE = 1 , /**<-- Top of shoe */
BLE_SENSOR_LOCATION_IN_SHOE = 2 , /**<-- In shoe */
BLE_SENSOR_LOCATION_HIP = 3 , /**<-- Hip */
BLE_SENSOR_LOCATION_FRONT_WHEEL = 4 , /**<-- Front Wheel */
BLE_SENSOR_LOCATION_LEFT_CRANK = 5 , /**<-- Left Crank */
BLE_SENSOR_LOCATION_RIGHT_CRANK = 6 , /**<-- Right Crank */
BLE_SENSOR_LOCATION_LEFT_PEDAL = 7 , /**<-- Left Pedal */
BLE_SENSOR_LOCATION_RIGHT_PEDAL = 8 , /**<-- Right Pedal */
BLE_SENSOR_LOCATION_FRONT_HUB = 9 , /**<-- Front Hub */
BLE_SENSOR_LOCATION_REAR_DROPOUT = 10, /**<-- Rear Dropout */
BLE_SENSOR_LOCATION_CHAINSTAY = 11, /**<-- Chainstay */
BLE_SENSOR_LOCATION_REAR_WHEEL = 12, /**<-- Rear Wheel */
BLE_SENSOR_LOCATION_REAR_HUB = 13, /**<-- Rear Hub */
}ble_sensor_location_t;
#define BLE_NB_MAX_SENSOR_LOCATIONS 14
#ifdef __cplusplus
}
#endif
#endif // BLE_SENSOR_LOCATION_H__

View 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.
*
*/
/* Attention!
* To maintain compliance with Nordic Semiconductor ASA's Bluetooth profile
* qualification listings, this section of source code must not be modified.
*/
#include "ble_srv_common.h"
#include <string.h>
#include "nordic_common.h"
#include "app_error.h"
#include "ble.h"
bool ble_srv_is_notification_enabled(uint8_t const * p_encoded_data)
{
uint16_t cccd_value = uint16_decode(p_encoded_data);
return ((cccd_value & BLE_GATT_HVX_NOTIFICATION) != 0);
}
bool ble_srv_is_indication_enabled(uint8_t const * p_encoded_data)
{
uint16_t cccd_value = uint16_decode(p_encoded_data);
return ((cccd_value & BLE_GATT_HVX_INDICATION) != 0);
}
uint8_t ble_srv_report_ref_encode(uint8_t * p_encoded_buffer,
const ble_srv_report_ref_t * p_report_ref)
{
uint8_t len = 0;
p_encoded_buffer[len++] = p_report_ref->report_id;
p_encoded_buffer[len++] = p_report_ref->report_type;
APP_ERROR_CHECK_BOOL(len == BLE_SRV_ENCODED_REPORT_REF_LEN);
return len;
}
void ble_srv_ascii_to_utf8(ble_srv_utf8_str_t * p_utf8, char * p_ascii)
{
p_utf8->length = (uint16_t)strlen(p_ascii);
p_utf8->p_str = (uint8_t *)p_ascii;
}
/**@brief Function for setting security requirements of a characteristic.
*
* @param[in] level required security level.
* @param[out] p_perm Characteristic security requirements.
*
* @return encoded security level and security mode.
*/
static inline void set_security_req(security_req_t level, ble_gap_conn_sec_mode_t * p_perm)
{
BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(p_perm);
switch (level)
{
case SEC_NO_ACCESS:
BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(p_perm);
break;
case SEC_OPEN:
BLE_GAP_CONN_SEC_MODE_SET_OPEN(p_perm);
break;
case SEC_JUST_WORKS:
BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(p_perm);
break;
case SEC_MITM:
BLE_GAP_CONN_SEC_MODE_SET_ENC_WITH_MITM(p_perm);
break;
case SEC_SIGNED:
BLE_GAP_CONN_SEC_MODE_SET_SIGNED_NO_MITM(p_perm);
break;
case SEC_SIGNED_MITM:
BLE_GAP_CONN_SEC_MODE_SET_SIGNED_WITH_MITM(p_perm);
break;
}
return;
}
uint32_t characteristic_add(uint16_t service_handle,
ble_add_char_params_t * p_char_props,
ble_gatts_char_handles_t * p_char_handle)
{
ble_gatts_char_md_t char_md;
ble_gatts_attr_t attr_char_value;
ble_uuid_t char_uuid;
ble_gatts_attr_md_t attr_md;
ble_gatts_attr_md_t user_descr_attr_md;
ble_gatts_attr_md_t cccd_md;
if (p_char_props->uuid_type == 0)
{
char_uuid.type = BLE_UUID_TYPE_BLE;
}
else
{
char_uuid.type = p_char_props->uuid_type;
}
char_uuid.uuid = p_char_props->uuid;
memset(&attr_md, 0, sizeof(ble_gatts_attr_md_t));
set_security_req(p_char_props->read_access, &attr_md.read_perm);
set_security_req(p_char_props->write_access, & attr_md.write_perm);
attr_md.rd_auth = (p_char_props->is_defered_read ? 1 : 0);
attr_md.wr_auth = (p_char_props->is_defered_write ? 1 : 0);
attr_md.vlen = (p_char_props->is_var_len ? 1 : 0);
attr_md.vloc = (p_char_props->is_value_user ? BLE_GATTS_VLOC_USER : BLE_GATTS_VLOC_STACK);
memset(&char_md, 0, sizeof(ble_gatts_char_md_t));
if ((p_char_props->char_props.notify == 1)||(p_char_props->char_props.indicate == 1))
{
memset(&cccd_md, 0, sizeof(cccd_md));
set_security_req(p_char_props->cccd_write_access, &cccd_md.write_perm);
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
cccd_md.vloc = BLE_GATTS_VLOC_STACK;
char_md.p_cccd_md = &cccd_md;
}
char_md.char_props = p_char_props->char_props;
char_md.char_ext_props = p_char_props->char_ext_props;
memset(&attr_char_value, 0, sizeof(ble_gatts_attr_t));
attr_char_value.p_uuid = &char_uuid;
attr_char_value.p_attr_md = &attr_md;
attr_char_value.max_len = p_char_props->max_len;
if (p_char_props->p_init_value != NULL)
{
attr_char_value.init_len = p_char_props->init_len;
attr_char_value.p_value = p_char_props->p_init_value;
}
if (p_char_props->p_user_descr != NULL)
{
memset(&user_descr_attr_md, 0, sizeof(ble_gatts_attr_md_t));
char_md.char_user_desc_max_size = p_char_props->p_user_descr->max_size;
char_md.char_user_desc_size = p_char_props->p_user_descr->size;
char_md.p_char_user_desc = p_char_props->p_user_descr->p_char_user_desc;
char_md.p_user_desc_md = &user_descr_attr_md;
set_security_req(p_char_props->p_user_descr->read_access, &user_descr_attr_md.read_perm);
set_security_req(p_char_props->p_user_descr->write_access, &user_descr_attr_md.write_perm);
user_descr_attr_md.rd_auth = (p_char_props->p_user_descr->is_defered_read ? 1 : 0);
user_descr_attr_md.wr_auth = (p_char_props->p_user_descr->is_defered_write ? 1 : 0);
user_descr_attr_md.vlen = (p_char_props->p_user_descr->is_var_len ? 1 : 0);
user_descr_attr_md.vloc = (p_char_props->p_user_descr->is_value_user ? BLE_GATTS_VLOC_USER : BLE_GATTS_VLOC_STACK);
}
if (p_char_props->p_presentation_format != NULL)
{
char_md.p_char_pf = p_char_props->p_presentation_format;
}
return sd_ble_gatts_characteristic_add(service_handle,
&char_md,
&attr_char_value,
p_char_handle);
}
uint32_t descriptor_add(uint16_t char_handle,
ble_add_descr_params_t * p_descr_props,
uint16_t * p_descr_handle)
{
ble_gatts_attr_t descr_params;
ble_uuid_t desc_uuid;
ble_gatts_attr_md_t attr_md;
memset(&descr_params, 0, sizeof(descr_params));
if (p_descr_props->uuid_type == 0)
{
desc_uuid.type = BLE_UUID_TYPE_BLE;
}
else
{
desc_uuid.type = p_descr_props->uuid_type;
}
desc_uuid.uuid = p_descr_props->uuid;
descr_params.p_uuid = &desc_uuid;
set_security_req(p_descr_props->read_access, &attr_md.read_perm);
set_security_req(p_descr_props->write_access,&attr_md.write_perm);
attr_md.rd_auth = (p_descr_props->is_defered_read ? 1 : 0);
attr_md.wr_auth = (p_descr_props->is_defered_write ? 1 : 0);
attr_md.vlen = (p_descr_props->is_var_len ? 1 : 0);
attr_md.vloc = (p_descr_props->is_value_user ? BLE_GATTS_VLOC_USER : BLE_GATTS_VLOC_STACK);
descr_params.p_attr_md = &attr_md;
descr_params.init_len = p_descr_props->init_len;
descr_params.init_offs = p_descr_props->init_offs;
descr_params.max_len = p_descr_props->max_len;
descr_params.p_value = p_descr_props->p_value;
return sd_ble_gatts_descriptor_add(char_handle, &descr_params, p_descr_handle);
}

View File

@@ -0,0 +1,409 @@
/**
* 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_common Common service definitions
* @{
* @ingroup ble_sdk_srv
* @brief Constants, type definitions, and functions that are common to all services.
*/
#ifndef BLE_SRV_COMMON_H__
#define BLE_SRV_COMMON_H__
#include <stdint.h>
#include <stdbool.h>
#include "ble_types.h"
#include "app_util.h"
#include "ble.h"
#include "ble_gap.h"
#include "ble_gatt.h"
#ifdef __cplusplus
extern "C" {
#endif
/** @defgroup UUID_SERVICES Service UUID definitions
* @{ */
#define BLE_UUID_ALERT_NOTIFICATION_SERVICE 0x1811 /**< Alert Notification service UUID. */
#define BLE_UUID_BATTERY_SERVICE 0x180F /**< Battery service UUID. */
#define BLE_UUID_BLOOD_PRESSURE_SERVICE 0x1810 /**< Blood Pressure service UUID. */
#define BLE_UUID_CURRENT_TIME_SERVICE 0x1805 /**< Current Time service UUID. */
#define BLE_UUID_CYCLING_SPEED_AND_CADENCE 0x1816 /**< Cycling Speed and Cadence service UUID. */
#define BLE_UUID_LOCATION_AND_NAVIGATION_SERVICE 0x1819 /**< Location and Navigation service UUID. */
#define BLE_UUID_DEVICE_INFORMATION_SERVICE 0x180A /**< Device Information service UUID. */
#define BLE_UUID_GLUCOSE_SERVICE 0x1808 /**< Glucose service UUID. */
#define BLE_UUID_HEALTH_THERMOMETER_SERVICE 0x1809 /**< Health Thermometer service UUID. */
#define BLE_UUID_HEART_RATE_SERVICE 0x180D /**< Heart Rate service UUID. */
#define BLE_UUID_HUMAN_INTERFACE_DEVICE_SERVICE 0x1812 /**< Human Interface Device service UUID. */
#define BLE_UUID_IMMEDIATE_ALERT_SERVICE 0x1802 /**< Immediate Alert service UUID. */
#define BLE_UUID_LINK_LOSS_SERVICE 0x1803 /**< Link Loss service UUID. */
#define BLE_UUID_NEXT_DST_CHANGE_SERVICE 0x1807 /**< Next Dst Change service UUID. */
#define BLE_UUID_PHONE_ALERT_STATUS_SERVICE 0x180E /**< Phone Alert Status service UUID. */
#define BLE_UUID_REFERENCE_TIME_UPDATE_SERVICE 0x1806 /**< Reference Time Update service UUID. */
#define BLE_UUID_RUNNING_SPEED_AND_CADENCE 0x1814 /**< Running Speed and Cadence service UUID. */
#define BLE_UUID_SCAN_PARAMETERS_SERVICE 0x1813 /**< Scan Parameters service UUID. */
#define BLE_UUID_TX_POWER_SERVICE 0x1804 /**< TX Power service UUID. */
#define BLE_UUID_IPSP_SERVICE 0x1820 /**< Internet Protocol Support service UUID. */
#define BLE_UUID_BMS_SERVICE 0x181E /**< BOND MANAGEMENT service UUID*/
#define BLE_UUID_CGM_SERVICE 0x181F /**< Continuous Glucose Monitoring service UUID*/
#define BLE_UUID_PLX_SERVICE 0x1822 /**< Pulse Oximeter Service UUID*/
#define BLE_UUID_OTS_SERVICE 0x1825 /**< Object Transfer Service UUID*/
/** @} */
/** @defgroup UUID_CHARACTERISTICS Characteristic UUID definitions
* @{ */
#define BLE_UUID_REMOVABLE_CHAR 0x2A3A /**< Removable characteristic UUID. */
#define BLE_UUID_SERVICE_REQUIRED_CHAR 0x2A3B /**< Service Required characteristic UUID. */
#define BLE_UUID_ALERT_CATEGORY_ID_CHAR 0x2A43 /**< Alert Category Id characteristic UUID. */
#define BLE_UUID_ALERT_CATEGORY_ID_BIT_MASK_CHAR 0x2A42 /**< Alert Category Id Bit Mask characteristic UUID. */
#define BLE_UUID_ALERT_LEVEL_CHAR 0x2A06 /**< Alert Level characteristic UUID. */
#define BLE_UUID_ALERT_NOTIFICATION_CONTROL_POINT_CHAR 0x2A44 /**< Alert Notification Control Point characteristic UUID. */
#define BLE_UUID_ALERT_STATUS_CHAR 0x2A3F /**< Alert Status characteristic UUID. */
#define BLE_UUID_BATTERY_LEVEL_CHAR 0x2A19 /**< Battery Level characteristic UUID. */
#define BLE_UUID_BLOOD_PRESSURE_FEATURE_CHAR 0x2A49 /**< Blood Pressure Feature characteristic UUID. */
#define BLE_UUID_BLOOD_PRESSURE_MEASUREMENT_CHAR 0x2A35 /**< Blood Pressure Measurement characteristic UUID. */
#define BLE_UUID_BODY_SENSOR_LOCATION_CHAR 0x2A38 /**< Body Sensor Location characteristic UUID. */
#define BLE_UUID_BOOT_KEYBOARD_INPUT_REPORT_CHAR 0x2A22 /**< Boot Keyboard Input Report characteristic UUID. */
#define BLE_UUID_BOOT_KEYBOARD_OUTPUT_REPORT_CHAR 0x2A32 /**< Boot Keyboard Output Report characteristic UUID. */
#define BLE_UUID_BOOT_MOUSE_INPUT_REPORT_CHAR 0x2A33 /**< Boot Mouse Input Report characteristic UUID. */
#define BLE_UUID_CURRENT_TIME_CHAR 0x2A2B /**< Current Time characteristic UUID. */
#define BLE_UUID_DATE_TIME_CHAR 0x2A08 /**< Date Time characteristic UUID. */
#define BLE_UUID_DAY_DATE_TIME_CHAR 0x2A0A /**< Day Date Time characteristic UUID. */
#define BLE_UUID_DAY_OF_WEEK_CHAR 0x2A09 /**< Day Of Week characteristic UUID. */
#define BLE_UUID_DST_OFFSET_CHAR 0x2A0D /**< Dst Offset characteristic UUID. */
#define BLE_UUID_EXACT_TIME_256_CHAR 0x2A0C /**< Exact Time 256 characteristic UUID. */
#define BLE_UUID_FIRMWARE_REVISION_STRING_CHAR 0x2A26 /**< Firmware Revision String characteristic UUID. */
#define BLE_UUID_GLUCOSE_FEATURE_CHAR 0x2A51 /**< Glucose Feature characteristic UUID. */
#define BLE_UUID_GLUCOSE_MEASUREMENT_CHAR 0x2A18 /**< Glucose Measurement characteristic UUID. */
#define BLE_UUID_GLUCOSE_MEASUREMENT_CONTEXT_CHAR 0x2A34 /**< Glucose Measurement Context characteristic UUID. */
#define BLE_UUID_HARDWARE_REVISION_STRING_CHAR 0x2A27 /**< Hardware Revision String characteristic UUID. */
#define BLE_UUID_HEART_RATE_CONTROL_POINT_CHAR 0x2A39 /**< Heart Rate Control Point characteristic UUID. */
#define BLE_UUID_HEART_RATE_MEASUREMENT_CHAR 0x2A37 /**< Heart Rate Measurement characteristic UUID. */
#define BLE_UUID_HID_CONTROL_POINT_CHAR 0x2A4C /**< Hid Control Point characteristic UUID. */
#define BLE_UUID_HID_INFORMATION_CHAR 0x2A4A /**< Hid Information characteristic UUID. */
#define BLE_UUID_IEEE_REGULATORY_CERTIFICATION_DATA_LIST_CHAR 0x2A2A /**< IEEE Regulatory Certification Data List characteristic UUID. */
#define BLE_UUID_INTERMEDIATE_CUFF_PRESSURE_CHAR 0x2A36 /**< Intermediate Cuff Pressure characteristic UUID. */
#define BLE_UUID_INTERMEDIATE_TEMPERATURE_CHAR 0x2A1E /**< Intermediate Temperature characteristic UUID. */
#define BLE_UUID_LOCAL_TIME_INFORMATION_CHAR 0x2A0F /**< Local Time Information characteristic UUID. */
#define BLE_UUID_MANUFACTURER_NAME_STRING_CHAR 0x2A29 /**< Manufacturer Name String characteristic UUID. */
#define BLE_UUID_MEASUREMENT_INTERVAL_CHAR 0x2A21 /**< Measurement Interval characteristic UUID. */
#define BLE_UUID_MODEL_NUMBER_STRING_CHAR 0x2A24 /**< Model Number String characteristic UUID. */
#define BLE_UUID_UNREAD_ALERT_CHAR 0x2A45 /**< Unread Alert characteristic UUID. */
#define BLE_UUID_NEW_ALERT_CHAR 0x2A46 /**< New Alert characteristic UUID. */
#define BLE_UUID_PNP_ID_CHAR 0x2A50 /**< PNP Id characteristic UUID. */
#define BLE_UUID_PROTOCOL_MODE_CHAR 0x2A4E /**< Protocol Mode characteristic UUID. */
#define BLE_UUID_RECORD_ACCESS_CONTROL_POINT_CHAR 0x2A52 /**< Record Access Control Point characteristic UUID. */
#define BLE_UUID_REFERENCE_TIME_INFORMATION_CHAR 0x2A14 /**< Reference Time Information characteristic UUID. */
#define BLE_UUID_REPORT_CHAR 0x2A4D /**< Report characteristic UUID. */
#define BLE_UUID_REPORT_MAP_CHAR 0x2A4B /**< Report Map characteristic UUID. */
#define BLE_UUID_RINGER_CONTROL_POINT_CHAR 0x2A40 /**< Ringer Control Point characteristic UUID. */
#define BLE_UUID_RINGER_SETTING_CHAR 0x2A41 /**< Ringer Setting characteristic UUID. */
#define BLE_UUID_SCAN_INTERVAL_WINDOW_CHAR 0x2A4F /**< Scan Interval Window characteristic UUID. */
#define BLE_UUID_SCAN_REFRESH_CHAR 0x2A31 /**< Scan Refresh characteristic UUID. */
#define BLE_UUID_SERIAL_NUMBER_STRING_CHAR 0x2A25 /**< Serial Number String characteristic UUID. */
#define BLE_UUID_SOFTWARE_REVISION_STRING_CHAR 0x2A28 /**< Software Revision String characteristic UUID. */
#define BLE_UUID_SUPPORTED_NEW_ALERT_CATEGORY_CHAR 0x2A47 /**< Supported New Alert Category characteristic UUID. */
#define BLE_UUID_SUPPORTED_UNREAD_ALERT_CATEGORY_CHAR 0x2A48 /**< Supported Unread Alert Category characteristic UUID. */
#define BLE_UUID_SYSTEM_ID_CHAR 0x2A23 /**< System Id characteristic UUID. */
#define BLE_UUID_TEMPERATURE_MEASUREMENT_CHAR 0x2A1C /**< Temperature Measurement characteristic UUID. */
#define BLE_UUID_TEMPERATURE_TYPE_CHAR 0x2A1D /**< Temperature Type characteristic UUID. */
#define BLE_UUID_TIME_ACCURACY_CHAR 0x2A12 /**< Time Accuracy characteristic UUID. */
#define BLE_UUID_TIME_SOURCE_CHAR 0x2A13 /**< Time Source characteristic UUID. */
#define BLE_UUID_TIME_UPDATE_CONTROL_POINT_CHAR 0x2A16 /**< Time Update Control Point characteristic UUID. */
#define BLE_UUID_TIME_UPDATE_STATE_CHAR 0x2A17 /**< Time Update State characteristic UUID. */
#define BLE_UUID_TIME_WITH_DST_CHAR 0x2A11 /**< Time With Dst characteristic UUID. */
#define BLE_UUID_TIME_ZONE_CHAR 0x2A0E /**< Time Zone characteristic UUID. */
#define BLE_UUID_TX_POWER_LEVEL_CHAR 0x2A07 /**< TX Power Level characteristic UUID. */
#define BLE_UUID_CSC_FEATURE_CHAR 0x2A5C /**< Cycling Speed and Cadence Feature characteristic UUID. */
#define BLE_UUID_CSC_MEASUREMENT_CHAR 0x2A5B /**< Cycling Speed and Cadence Measurement characteristic UUID. */
#define BLE_UUID_RSC_FEATURE_CHAR 0x2A54 /**< Running Speed and Cadence Feature characteristic UUID. */
#define BLE_UUID_SC_CTRLPT_CHAR 0x2A55 /**< Speed and Cadence Control Point UUID. */
#define BLE_UUID_RSC_MEASUREMENT_CHAR 0x2A53 /**< Running Speed and Cadence Measurement characteristic UUID. */
#define BLE_UUID_SENSOR_LOCATION_CHAR 0x2A5D /**< Sensor Location characteristic UUID. */
#define BLE_UUID_EXTERNAL_REPORT_REF_DESCR 0x2907 /**< External Report Reference descriptor UUID. */
#define BLE_UUID_REPORT_REF_DESCR 0x2908 /**< Report Reference descriptor UUID. */
#define BLE_UUID_LN_FEATURE_CHAR 0x2A6A /**< Location Navigation Service, Feature characteristic UUID. */
#define BLE_UUID_LN_POSITION_QUALITY_CHAR 0x2A69 /**< Location Navigation Service, Position quality UUID. */
#define BLE_UUID_LN_LOCATION_AND_SPEED_CHAR 0x2A67 /**< Location Navigation Service, Location and Speed characteristic UUID. */
#define BLE_UUID_LN_NAVIGATION_CHAR 0x2A68 /**< Location Navigation Service, Navigation characteristic UUID. */
#define BLE_UUID_LN_CONTROL_POINT_CHAR 0x2A6B /**< Location Navigation Service, Control point characteristic UUID. */
#define BLE_UUID_BMS_CTRLPT 0x2AA4 /**< BMS Control Point characteristic UUID. */
#define BLE_UUID_BMS_FEATURE 0x2AA5 /**< BMS Feature characteristic UUID. */
#define BLE_UUID_CGM_MEASUREMENT 0x2AA7 /**< CGM Service, Measurement characteristic UUID*/
#define BLE_UUID_CGM_FEATURE 0x2AA8 /**< CGM Service, Feature characteristic UUID*/
#define BLE_UUID_CGM_STATUS 0x2AA9 /**< CGM Service, Status characteristic UUID*/
#define BLE_UUID_CGM_SESSION_START_TIME 0x2AAA /**< CGM Service, session start time characteristic UUID*/
#define BLE_UUID_CGM_SESSION_RUN_TIME 0x2AAB /**< CGM Service, session run time characteristic UUID*/
#define BLE_UUID_CGM_SPECIFIC_OPS_CTRLPT 0x2AAC /**< CGM Service, specific ops ctrlpt characteristic UUID*/
#define BLE_UUID_PLX_SPOT_CHECK_MEAS 0x2A5E /**< PLX Service, spot check measurement characteristic UUID*/
#define BLE_UUID_PLX_CONTINUOUS_MEAS 0x2A5F /**< PLX Service, continuous measurement characteristic UUID*/
#define BLE_UUID_PLX_FEATURES 0x2A60 /**< PLX Service, feature characteristic UUID*/
#define BLE_UUID_OTS_FEATURES 0x2ABD /**< OTS Service, feature characteristic UUID*/
#define BLE_UUID_OTS_OBJECT_NAME 0x2ABE /**< OTS Service, Object Name characteristic UUID*/
#define BLE_UUID_OTS_OBJECT_TYPE 0x2ABF /**< OTS Service, Object Type characteristic UUID*/
#define BLE_UUID_OTS_OBJECT_SIZE 0x2AC0 /**< OTS Service, Object Size characteristic UUID*/
#define BLE_UUID_OTS_OBJECT_FIRST_CREATED 0x2AC1 /**< OTS Service, Object First Created characteristic UUID*/
#define BLE_UUID_OTS_OBJECT_LAST_MODIFIED 0x2AC2 /**< OTS Service, Object Last Modified characteristic UUID*/
#define BLE_UUID_OTS_OBJECT_ID 0x2AC3 /**< OTS Service, Object ID characteristic UUID*/
#define BLE_UUID_OTS_OBJECT_PROPERTIES 0x2AC4 /**< OTS Service, Object Properties characteristic UUID*/
#define BLE_UUID_OTS_OACP 0x2AC5 /**< OTS Service, Object Action Control Point characteristic UUID*/
#define BLE_UUID_OTS_OLCP 0x2AC6 /**< OTS Service, Object List Control Point characteristic UUID*/
#define BLE_UUID_OTS_LF 0x2AC7 /**< OTS Service, Object List Filter characteristic UUID*/
#define BLE_UUID_OTS_OBJECT_CHANGED 0x2AC8 /**< OTS Service, Object Changed characteristic UUID*/
/** @} */
/** @defgroup ALERT_LEVEL_VALUES Definitions for the Alert Level characteristic values
* @{ */
#define BLE_CHAR_ALERT_LEVEL_NO_ALERT 0x00 /**< No Alert. */
#define BLE_CHAR_ALERT_LEVEL_MILD_ALERT 0x01 /**< Mild Alert. */
#define BLE_CHAR_ALERT_LEVEL_HIGH_ALERT 0x02 /**< High Alert. */
/** @} */
#define BLE_SRV_ENCODED_REPORT_REF_LEN 2 /**< The length of an encoded Report Reference Descriptor. */
#define BLE_CCCD_VALUE_LEN 2 /**< The length of a CCCD value. */
/**@brief Type definition for error handler function that will be called in case of an error in
* a service or a service library module. */
typedef void (*ble_srv_error_handler_t) (uint32_t nrf_error);
/**@brief Value of a Report Reference descriptor.
*
* @details This is mapping information that maps the parent characteristic to the Report ID(s) and
* Report Type(s) defined within a Report Map characteristic.
*/
typedef struct
{
uint8_t report_id; /**< Non-zero value if there is more than one instance of the same Report Type */
uint8_t report_type; /**< Type of Report characteristic (see @ref BLE_HIDS_REPORT_TYPE) */
} ble_srv_report_ref_t;
/**@brief UTF-8 string data type.
*
* @note The type can only hold a pointer to the string data (i.e. not the actual data).
*/
typedef struct
{
uint16_t length; /**< String length. */
uint8_t * p_str; /**< String data. */
} ble_srv_utf8_str_t;
/**@brief Security settings structure.
* @details This structure contains the security options needed during initialization of the
* service.
*/
typedef struct
{
ble_gap_conn_sec_mode_t read_perm; /**< Read permissions. */
ble_gap_conn_sec_mode_t write_perm; /**< Write permissions. */
} ble_srv_security_mode_t;
/**@brief Security settings structure.
* @details This structure contains the security options needed during initialization of the
* service. It can be used when the characteristics contains a CCCD.
*/
typedef struct
{
ble_gap_conn_sec_mode_t cccd_write_perm; /**< Write permissions for Client Characteristic Configuration Descriptor. */
ble_gap_conn_sec_mode_t read_perm; /**< Read permissions. */
ble_gap_conn_sec_mode_t write_perm; /**< Write permissions. */
} ble_srv_cccd_security_mode_t;
/**@brief Function for decoding a CCCD value, and then testing if notification is
* enabled.
*
* @param[in] p_encoded_data Buffer where the encoded CCCD is stored.
*
* @retval TRUE If notification is enabled.
* @retval FALSE Otherwise.
*/
bool ble_srv_is_notification_enabled(uint8_t const * p_encoded_data);
/**@brief Function for decoding a CCCD value, and then testing if indication is
* enabled.
*
* @param[in] p_encoded_data Buffer where the encoded CCCD is stored.
*
* @retval TRUE If indication is enabled.
* @retval FALSE Otherwise.
*/
bool ble_srv_is_indication_enabled(uint8_t const * p_encoded_data);
/**@brief Function for encoding a Report Reference Descriptor.
*
* @param[in] p_encoded_buffer The buffer of the encoded data.
* @param[in] p_report_ref Report Reference value to be encoded.
*
* @return Length of the encoded data.
*/
uint8_t ble_srv_report_ref_encode(uint8_t * p_encoded_buffer,
const ble_srv_report_ref_t * p_report_ref);
/**@brief Function for making a UTF-8 structure refer to an ASCII string.
*
* @param[out] p_utf8 UTF-8 structure to be set.
* @param[in] p_ascii ASCII string to be referred to.
*/
void ble_srv_ascii_to_utf8(ble_srv_utf8_str_t * p_utf8, char * p_ascii);
/**@brief Security Access enumeration.
* @details This enumeration gives the possible requirements for accessing a characteristic value.
*/
typedef enum
{
SEC_NO_ACCESS = 0, /**< Not possible to access. */
SEC_OPEN = 1, /**< Access open. */
SEC_JUST_WORKS = 2, /**< Access possible with 'Just Works' security at least. */
SEC_MITM = 3, /**< Access possible with 'MITM' security at least. */
SEC_SIGNED = 4, /**< Access possible with 'signed' security at least. */
SEC_SIGNED_MITM = 5 /**< Access possible with 'signed and MITM' security at least. */
}security_req_t;
/**@brief Characteristic User Descriptor parameters.
* @details This structure contains the parameters for User Descriptor.
*/
typedef struct
{
uint16_t max_size; /**< Maximum size of the user descriptor*/
uint16_t size; /**< Size of the user descriptor*/
uint8_t *p_char_user_desc; /**< User descriptor content, pointer to a UTF-8 encoded string (non-NULL terminated)*/
bool is_var_len; /**< Indicates if the user descriptor has variable length.*/
ble_gatt_char_props_t char_props; /**< user descriptor properties.*/
bool is_defered_read; /**< Indicate if deferred read operations are supported.*/
bool is_defered_write; /**< Indicate if deferred write operations are supported.*/
security_req_t read_access; /**< Security requirement for reading the user descriptor.*/
security_req_t write_access; /**< Security requirement for writing the user descriptor.*/
bool is_value_user; /**< Indicate if the content of the characteristic is to be stored in the application (user) or in the stack.*/
}ble_add_char_user_desc_t;
/**@brief Add characteristic parameters structure.
* @details This structure contains the parameters needed to use the @ref characteristic_add function.
*/
typedef struct
{
uint16_t uuid; /**< Characteristic UUID (16 bits UUIDs).*/
uint8_t uuid_type; /**< Base UUID. If 0, the Bluetooth SIG UUID will be used. Otherwise, this should be a value returned by @ref sd_ble_uuid_vs_add when adding the base UUID.*/
uint16_t max_len; /**< Maximum length of the characteristic value.*/
uint16_t init_len; /**< Initial length of the characteristic value.*/
uint8_t * p_init_value; /**< Initial encoded value of the characteristic.*/
bool is_var_len; /**< Indicates if the characteristic value has variable length.*/
ble_gatt_char_props_t char_props; /**< Characteristic properties.*/
ble_gatt_char_ext_props_t char_ext_props; /**< Characteristic extended properties.*/
bool is_defered_read; /**< Indicate if deferred read operations are supported.*/
bool is_defered_write; /**< Indicate if deferred write operations are supported.*/
security_req_t read_access; /**< Security requirement for reading the characteristic value.*/
security_req_t write_access; /**< Security requirement for writing the characteristic value.*/
security_req_t cccd_write_access; /**< Security requirement for writing the characteristic's CCCD.*/
bool is_value_user; /**< Indicate if the content of the characteristic is to be stored in the application (user) or in the stack.*/
ble_add_char_user_desc_t *p_user_descr; /**< Pointer to user descriptor if needed*/
ble_gatts_char_pf_t *p_presentation_format; /**< Pointer to characteristic format if needed*/
} ble_add_char_params_t;
/**@brief Add descriptor parameters structure.
* @details This structure contains the parameters needed to use the @ref descriptor_add function.
*/
typedef struct
{
uint16_t uuid; /**< descriptor UUID (16 bits UUIDs).*/
uint8_t uuid_type; /**< Base UUID. If 0, the Bluetooth SIG UUID will be used. Otherwise, this should be a value returned by @ref sd_ble_uuid_vs_add when adding the base UUID.*/
bool is_defered_read; /**< Indicate if deferred read operations are supported.*/
bool is_defered_write; /**< Indicate if deferred write operations are supported.*/
bool is_var_len; /**< Indicates if the descriptor value has variable length.*/
security_req_t read_access; /**< Security requirement for reading the descriptor value.*/
security_req_t write_access; /**< Security requirement for writing the descriptor value.*/
bool is_value_user; /**< Indicate if the content of the characteristic is to be stored in the application (user) or in the stack.*/
uint16_t init_len; /**< Initial descriptor value length in bytes. */
uint16_t init_offs; /**< Initial descriptor value offset in bytes. If different from zero, the first init_offs bytes of the attribute value will be left uninitialized. */
uint16_t max_len; /**< Maximum descriptor value length in bytes, see @ref BLE_GATTS_ATTR_LENS_MAX for maximum values. */
uint8_t* p_value; /**< Pointer to the value of the descriptor*/
} ble_add_descr_params_t;
/**@brief Function for adding a characteristic to a given service.
*
* If no pointer is given for the initial value,
* the initial length parameter will be ignored and the initial length will be 0.
*
* @param[in] service_handle Handle of the service to which the characteristic is to be added.
* @param[in] p_char_props Information needed to add the characteristic.
* @param[out] p_char_handle Handle of the added characteristic.
*
* @retval NRF_SUCCESS If the characteristic was added successfully. Otherwise, an error code is returned.
*/
uint32_t characteristic_add(uint16_t service_handle,
ble_add_char_params_t * p_char_props,
ble_gatts_char_handles_t * p_char_handle);
/**@brief Function for adding a characteristic's descriptor to a given characteristic.
*
* @param[in] char_handle Handle of the characteristic to which the descriptor is to be added, if @ref BLE_GATT_HANDLE_INVALID is used, it will be placed sequentially.
* @param[in] p_descr_props Information needed to add the descriptor.
* @param[out] p_descr_handle Handle of the added descriptor.
*
* @retval NRF_SUCCESS If the characteristic was added successfully. Otherwise, an error code is returned.
*/
uint32_t descriptor_add(uint16_t char_handle,
ble_add_descr_params_t * p_descr_props,
uint16_t * p_descr_handle);
#ifdef __cplusplus
}
#endif
#endif // BLE_SRV_COMMON_H__
/** @} */