mirror of https://github.com/ARMmbed/mbed-os.git
1129 lines
31 KiB
C++
1129 lines
31 KiB
C++
/* mbed Microcontroller Library
|
|
* Copyright (c) 2006-2013 ARM Limited
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#ifndef MBED_GAP_ADVERTISING_DATA_H__
|
|
#define MBED_GAP_ADVERTISING_DATA_H__
|
|
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "platform/Span.h"
|
|
#include "platform/NonCopyable.h"
|
|
|
|
#include "ble/blecommon.h"
|
|
#include "ble/SafeEnum.h"
|
|
#include "UUID.h"
|
|
|
|
/**
|
|
* @addtogroup ble
|
|
* @{
|
|
* @addtogroup gap
|
|
* @{
|
|
*/
|
|
|
|
namespace ble {
|
|
|
|
/*!
|
|
* List of standard Advertising Data types.
|
|
*
|
|
* These AD types are used to describe the capabilities of the peripheral
|
|
* and are inserted inside the advertising or scan response payloads.
|
|
*
|
|
* @par Source
|
|
*
|
|
* @li @c Bluetooth Core Specification 4.0 (Vol. 3), Part C, Section 11, 18.
|
|
* @li @c https://www.bluetooth.org/en-us/specification/assigned-numbers/generic-access-profile.
|
|
*/
|
|
struct adv_data_type_t : SafeEnum<adv_data_type_t, uint8_t> {
|
|
/** struct scoped enum wrapped by the class */
|
|
enum type {
|
|
/**
|
|
* Flags, refer to AdvertisingData::Flags_t.
|
|
*/
|
|
FLAGS = 0x01,
|
|
|
|
/**
|
|
* Incomplete list of 16-bit Service IDs.
|
|
*/
|
|
INCOMPLETE_LIST_16BIT_SERVICE_IDS = 0x02,
|
|
|
|
/**
|
|
* Complete list of 16-bit Service IDs.
|
|
*/
|
|
COMPLETE_LIST_16BIT_SERVICE_IDS = 0x03,
|
|
|
|
/**
|
|
* Incomplete list of 32-bit Service IDs (not relevant for Bluetooth 4.0).
|
|
*/
|
|
INCOMPLETE_LIST_32BIT_SERVICE_IDS = 0x04,
|
|
|
|
/**
|
|
* Complete list of 32-bit Service IDs (not relevant for Bluetooth 4.0).
|
|
*/
|
|
COMPLETE_LIST_32BIT_SERVICE_IDS = 0x05,
|
|
|
|
/**
|
|
* Incomplete list of 128-bit Service IDs.
|
|
*/
|
|
INCOMPLETE_LIST_128BIT_SERVICE_IDS = 0x06,
|
|
|
|
/**
|
|
* Complete list of 128-bit Service IDs.
|
|
*/
|
|
COMPLETE_LIST_128BIT_SERVICE_IDS = 0x07,
|
|
|
|
/**
|
|
* Shortened Local Name.
|
|
*/
|
|
SHORTENED_LOCAL_NAME = 0x08,
|
|
|
|
/**
|
|
* Complete Local Name.
|
|
*/
|
|
COMPLETE_LOCAL_NAME = 0x09,
|
|
|
|
/**
|
|
* TX Power Level (in dBm).
|
|
*/
|
|
TX_POWER_LEVEL = 0x0A,
|
|
|
|
/**
|
|
* Device ID.
|
|
*/
|
|
DEVICE_ID = 0x10,
|
|
|
|
/**
|
|
* Slave Connection Interval Range.
|
|
*/
|
|
SLAVE_CONNECTION_INTERVAL_RANGE = 0x12,
|
|
|
|
/**
|
|
* List of 128-bit service UUIDs the device is looking for.
|
|
*/
|
|
LIST_128BIT_SOLICITATION_IDS = 0x15,
|
|
|
|
/**
|
|
* Service Data.
|
|
*/
|
|
SERVICE_DATA = 0x16,
|
|
|
|
/**
|
|
* Appearance, refer to AdvertisingData::Appearance_t.
|
|
*/
|
|
APPEARANCE = 0x19,
|
|
|
|
/**
|
|
* Advertising Interval.
|
|
*/
|
|
ADVERTISING_INTERVAL = 0x1A,
|
|
|
|
/**
|
|
* Manufacturer Specific Data.
|
|
*/
|
|
MANUFACTURER_SPECIFIC_DATA = 0xFF
|
|
};
|
|
|
|
/**
|
|
* Construct a new instance of adv_data_type_t.
|
|
*/
|
|
adv_data_type_t(type value) :
|
|
SafeEnum<adv_data_type_t, uint8_t>(value) { }
|
|
};
|
|
|
|
|
|
/**
|
|
* Set of advertising flags.
|
|
*
|
|
* @note LE_LIMITED_DISCOVERABLE and LE_GENERAL_DISCOVERABLE are mutually
|
|
* exclusive
|
|
*
|
|
* @li @c Bluetooth Core Specification 4.0 (Vol. 3), Part C, Section 18.1.
|
|
*/
|
|
struct adv_data_flags_t {
|
|
enum {
|
|
LE_LIMITED_DISCOVERABLE = 0x01, /**< Discoverable for a limited period of time.*/
|
|
LE_GENERAL_DISCOVERABLE = 0x02, /**< Discoverable at any moment. */
|
|
BREDR_NOT_SUPPORTED = 0x04, /**< LE only and does not support Bluetooth Enhanced DataRate. */
|
|
SIMULTANEOUS_LE_BREDR_C = 0x08, /**< Not relevant - dual mode only. */
|
|
SIMULTANEOUS_LE_BREDR_H = 0x10 /**< Not relevant - dual mode only. */
|
|
};
|
|
|
|
static const uint8_t default_flags = BREDR_NOT_SUPPORTED | LE_GENERAL_DISCOVERABLE;
|
|
|
|
/** Create from raw value */
|
|
adv_data_flags_t(uint8_t value = 0) : _value(value) {};
|
|
|
|
adv_data_flags_t& setGeneralDiscoverable(bool enable = true) {
|
|
_value &= ~0x03;
|
|
if (enable) {
|
|
_value |= LE_GENERAL_DISCOVERABLE;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
adv_data_flags_t& setLimitedDiscoverable(bool enable = true) {
|
|
_value &= ~0x03;
|
|
if (enable) {
|
|
_value |= LE_LIMITED_DISCOVERABLE;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
adv_data_flags_t& setBredrNotSupported(bool enable = true) {
|
|
_value &= ~BREDR_NOT_SUPPORTED;
|
|
if (enable) {
|
|
_value |= BREDR_NOT_SUPPORTED;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
adv_data_flags_t& setSimultaneousLeBredrC(bool enable = true) {
|
|
_value &= ~SIMULTANEOUS_LE_BREDR_C;
|
|
if (enable) {
|
|
_value |= SIMULTANEOUS_LE_BREDR_C;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
adv_data_flags_t& setSimultaneousLeBredrH(bool enable = true) {
|
|
_value &= ~SIMULTANEOUS_LE_BREDR_H;
|
|
if (enable) {
|
|
_value |= SIMULTANEOUS_LE_BREDR_H;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
bool getGeneralDiscoverable() {
|
|
return _value& LE_GENERAL_DISCOVERABLE;
|
|
}
|
|
|
|
bool getlimitedDiscoverable() {
|
|
return _value& LE_LIMITED_DISCOVERABLE;
|
|
}
|
|
|
|
bool getBrEdrNotSupported() {
|
|
return _value& BREDR_NOT_SUPPORTED;
|
|
}
|
|
|
|
bool getSimultaneousLeBredrC() {
|
|
return _value& SIMULTANEOUS_LE_BREDR_C;
|
|
}
|
|
|
|
bool getSimultaneousLeBredrH() {
|
|
return _value& SIMULTANEOUS_LE_BREDR_H;
|
|
}
|
|
|
|
void clear() {
|
|
_value = 0;
|
|
}
|
|
|
|
uint8_t value() {
|
|
return _value;
|
|
}
|
|
|
|
private:
|
|
uint8_t _value;
|
|
};
|
|
|
|
|
|
/**
|
|
* Enumeration of values for the adv_data_type_t::APPEARANCE.
|
|
*
|
|
* These values describe the physical shape or appearance of the device.
|
|
*
|
|
* @par Source
|
|
*
|
|
* @li @c Bluetooth Core Specification Supplement, Part A, Section 1.12.
|
|
* @li @c Bluetooth Core Specification 4.0 (Vol. 3), Part C, Section 12.2.
|
|
* @li @c https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.gap.appearance.xml.
|
|
*/
|
|
struct adv_data_appearance_t : SafeEnum<adv_data_appearance_t, uint16_t> {
|
|
/** struct scoped enum wrapped by the class */
|
|
enum type {
|
|
/**
|
|
* Unknown or unspecified appearance type.
|
|
*/
|
|
UNKNOWN = 0,
|
|
|
|
/**
|
|
* Generic Phone.
|
|
*/
|
|
GENERIC_PHONE = 64,
|
|
|
|
/**
|
|
* Generic Computer.
|
|
*/
|
|
GENERIC_COMPUTER = 128,
|
|
|
|
/**
|
|
* Generic Watch.
|
|
*/
|
|
GENERIC_WATCH = 192,
|
|
|
|
/**
|
|
* Sports Watch.
|
|
*/
|
|
WATCH_SPORTS_WATCH = 193,
|
|
|
|
/**
|
|
* Generic Clock.
|
|
*/
|
|
GENERIC_CLOCK = 256,
|
|
|
|
/**
|
|
* Generic Display.
|
|
*/
|
|
GENERIC_DISPLAY = 320,
|
|
|
|
/**
|
|
* Generic Remote Control.
|
|
*/
|
|
GENERIC_REMOTE_CONTROL = 384,
|
|
|
|
/**
|
|
* Generic Eye Glasses.
|
|
*/
|
|
GENERIC_EYE_GLASSES = 448,
|
|
|
|
/**
|
|
* Generic Tag.
|
|
*/
|
|
GENERIC_TAG = 512,
|
|
|
|
/**
|
|
* Generic Keyring.
|
|
*/
|
|
GENERIC_KEYRING = 576,
|
|
|
|
/**
|
|
* Generic Media Player.
|
|
*/
|
|
GENERIC_MEDIA_PLAYER = 640,
|
|
|
|
/**
|
|
* Generic Bar Code Scanner.
|
|
*/
|
|
GENERIC_BARCODE_SCANNER = 704,
|
|
|
|
/**
|
|
* Generic Thermometer.
|
|
*/
|
|
GENERIC_THERMOMETER = 768,
|
|
|
|
/**
|
|
* Ear Thermometer.
|
|
*/
|
|
THERMOMETER_EAR = 769,
|
|
|
|
/**
|
|
* Generic Heart Rate Sensor.
|
|
*/
|
|
GENERIC_HEART_RATE_SENSOR = 832,
|
|
|
|
/**
|
|
* Belt Heart Rate Sensor.
|
|
*/
|
|
HEART_RATE_SENSOR_HEART_RATE_BELT = 833,
|
|
|
|
/**
|
|
* Generic Blood Pressure.
|
|
*/
|
|
GENERIC_BLOOD_PRESSURE = 896,
|
|
|
|
/**
|
|
* Arm Blood Pressure.
|
|
*/
|
|
BLOOD_PRESSURE_ARM = 897,
|
|
|
|
/**
|
|
* Wrist Blood Pressure.
|
|
*/
|
|
BLOOD_PRESSURE_WRIST = 898,
|
|
|
|
/**
|
|
* Human Interface Device (HID).
|
|
*/
|
|
HUMAN_INTERFACE_DEVICE_HID = 960,
|
|
|
|
/**
|
|
* Keyboard.
|
|
*/
|
|
KEYBOARD = 961,
|
|
|
|
/**
|
|
* Mouse.
|
|
*/
|
|
MOUSE = 962,
|
|
|
|
/**
|
|
* Joystick.
|
|
*/
|
|
JOYSTICK = 963,
|
|
|
|
/**
|
|
* Gamepad.
|
|
*/
|
|
GAMEPAD = 964,
|
|
|
|
/**
|
|
* Digitizer Tablet.
|
|
*/
|
|
DIGITIZER_TABLET = 965,
|
|
|
|
/**
|
|
* Card Reader.
|
|
*/
|
|
CARD_READER = 966,
|
|
|
|
/**
|
|
* Digital Pen.
|
|
*/
|
|
DIGITAL_PEN = 967,
|
|
|
|
/**
|
|
* Bar Code Scanner.
|
|
*/
|
|
BARCODE_SCANNER = 968,
|
|
|
|
/**
|
|
* Generic Glucose Meter.
|
|
*/
|
|
GENERIC_GLUCOSE_METER = 1024,
|
|
|
|
/**
|
|
* Generic Running/Walking Sensor.
|
|
*/
|
|
GENERIC_RUNNING_WALKING_SENSOR = 1088,
|
|
|
|
/**
|
|
* In Shoe Running/Walking Sensor.
|
|
*/
|
|
RUNNING_WALKING_SENSOR_IN_SHOE = 1089,
|
|
|
|
/**
|
|
* On Shoe Running/Walking Sensor.
|
|
*/
|
|
RUNNING_WALKING_SENSOR_ON_SHOE = 1090,
|
|
|
|
/**
|
|
* On Hip Running/Walking Sensor.
|
|
*/
|
|
RUNNING_WALKING_SENSOR_ON_HIP = 1091,
|
|
|
|
/**
|
|
* Generic Cycling.
|
|
*/
|
|
GENERIC_CYCLING = 1152,
|
|
|
|
/**
|
|
* Cycling Computer.
|
|
*/
|
|
CYCLING_CYCLING_COMPUTER = 1153,
|
|
|
|
/**
|
|
* Cycling Speed Sensor.
|
|
*/
|
|
CYCLING_SPEED_SENSOR = 1154,
|
|
|
|
/**
|
|
* Cycling Cadence Sensor.
|
|
*/
|
|
CYCLING_CADENCE_SENSOR = 1155,
|
|
|
|
/**
|
|
* Cycling Power Sensor.
|
|
*/
|
|
CYCLING_POWER_SENSOR = 1156,
|
|
|
|
/**
|
|
* Cycling Speed and Cadence Sensor.
|
|
*/
|
|
CYCLING_SPEED_AND_CADENCE_SENSOR = 1157,
|
|
|
|
/**
|
|
* Generic Pulse Oximeter.
|
|
*/
|
|
PULSE_OXIMETER_GENERIC = 3136,
|
|
|
|
/**
|
|
* Fingertip Pulse Oximeter.
|
|
*/
|
|
PULSE_OXIMETER_FINGERTIP = 3137,
|
|
|
|
/**
|
|
* Wrist Worn Pulse Oximeter.
|
|
*/
|
|
PULSE_OXIMETER_WRIST_WORN = 3138,
|
|
|
|
/**
|
|
* Generic Weight Scale.
|
|
*/
|
|
GENERIC_WEIGHT_SCALE = 3200,
|
|
|
|
/**
|
|
* Generic Outdoor.
|
|
*/
|
|
OUTDOOR_GENERIC = 5184,
|
|
|
|
/**
|
|
* Outdoor Location Display Device.
|
|
*/
|
|
OUTDOOR_LOCATION_DISPLAY_DEVICE = 5185,
|
|
|
|
/**
|
|
* Outdoor Location and Navigation Display Device.
|
|
*/
|
|
OUTDOOR_LOCATION_AND_NAVIGATION_DISPLAY_DEVICE = 5186,
|
|
|
|
/**
|
|
* Outdoor Location Pod.
|
|
*/
|
|
OUTDOOR_LOCATION_POD = 5187,
|
|
|
|
/**
|
|
* Outdoor Location and Navigation Pod.
|
|
*/
|
|
OUTDOOR_LOCATION_AND_NAVIGATION_POD = 5188
|
|
};
|
|
|
|
/**
|
|
* Construct a new instance of adv_data_appearance_t.
|
|
*/
|
|
adv_data_appearance_t(type value) :
|
|
SafeEnum<adv_data_appearance_t, uint16_t>(value) { }
|
|
};
|
|
|
|
|
|
class AdvertisingDataBuilder
|
|
{
|
|
public:
|
|
/** Advertising data needs a user provided buffer to store the data.
|
|
*
|
|
* @param buffer Buffer used to store the data.
|
|
* @note Use Gap::getMaxAdvertisingDataLength() to find out how much can be accepted.
|
|
*/
|
|
AdvertisingDataBuilder(mbed::Span<uint8_t> buffer) :
|
|
_buffer(buffer),
|
|
_payload_length(0) {
|
|
}
|
|
|
|
/** Advertising data needs a user provided buffer to store the data.
|
|
*
|
|
* @param buffer Pointer to buffer to be used for storing advertising data.
|
|
* @param buffer_size Size of the buffer.
|
|
* @note Use Gap::getMaxAdvertisingDataLength() to find out how much can be accepted.
|
|
*/
|
|
AdvertisingDataBuilder(uint8_t* buffer, size_t buffer_size) :
|
|
_buffer(buffer, buffer_size),
|
|
_payload_length(0) {
|
|
}
|
|
|
|
/**
|
|
* Get the subspan of the buffer containing valid data.
|
|
*
|
|
* @return A Span containing the payload.
|
|
*/
|
|
mbed::Span<uint8_t> getAdvertisingData() const {
|
|
return _buffer.first(_payload_length);
|
|
}
|
|
|
|
/**
|
|
* Add a new field into the payload. Will return an error if type is already present.
|
|
*
|
|
* @param[in] advDataType The type of the field to add.
|
|
* @param[in] fieldData Span of data to add.
|
|
*
|
|
* @retval BLE_ERROR_NONE on success.
|
|
* @retval BLE_ERROR_BUFFER_OVERFLOW if buffer is too small to contain the new data.
|
|
* @retval BLE_ERROR_OPERATION_NOT_PERMITTED if data type already present.
|
|
*/
|
|
ble_error_t addData(
|
|
adv_data_type_t advDataType,
|
|
mbed::Span<const uint8_t> fieldData
|
|
) {
|
|
if (findField(advDataType)) {
|
|
return BLE_ERROR_OPERATION_NOT_PERMITTED;
|
|
} else {
|
|
return addField(advDataType, fieldData);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Replace a new field into the payload. Will fail if type is not already present.
|
|
*
|
|
* @param[in] advDataType The type of the field to add.
|
|
* @param[in] fieldData Span of data to add.
|
|
*
|
|
* @retval BLE_ERROR_NONE on success.
|
|
* @retval BLE_ERROR_BUFFER_OVERFLOW if buffer is too small to contain the new data.
|
|
* @retval BLE_ERROR_NOT_FOUND if data type not present.
|
|
*/
|
|
ble_error_t replaceData(
|
|
adv_data_type_t advDataType,
|
|
mbed::Span<const uint8_t> fieldData
|
|
) {
|
|
uint8_t* field = findField(advDataType);
|
|
|
|
if (field) {
|
|
return replaceField(advDataType, fieldData, field);
|
|
} else {
|
|
return BLE_ERROR_NOT_FOUND;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Append data to an existing field in the payload. Will fail if type is not already
|
|
* present.
|
|
*
|
|
* @param[in] advDataType The type of the field to add.
|
|
* @param[in] fieldData Span of data to add.
|
|
*
|
|
* @retval BLE_ERROR_NONE on success.
|
|
* @retval BLE_ERROR_BUFFER_OVERFLOW if buffer is too small to contain the new data.
|
|
* @retval BLE_ERROR_NOT_FOUND if data type not present.
|
|
*/
|
|
ble_error_t appendData(
|
|
adv_data_type_t advDataType,
|
|
mbed::Span<const uint8_t> fieldData
|
|
) {
|
|
uint8_t* field = findField(advDataType);
|
|
|
|
if (field) {
|
|
return appendToField(fieldData, field);
|
|
} else {
|
|
return BLE_ERROR_NOT_FOUND;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Remove existing date of given type. Will return an error if type is not present.
|
|
*
|
|
* @param[in] advDataType The type of the field to remove.
|
|
*
|
|
* @return BLE_ERROR_NONE returned on success, BLE_ERROR_INVALID_PARAM if field doesn't exist
|
|
*/
|
|
ble_error_t removeData(
|
|
adv_data_type_t advDataType
|
|
) {
|
|
uint8_t* field = findField(advDataType);
|
|
|
|
if (field) {
|
|
return removeField(field);
|
|
} else {
|
|
return BLE_ERROR_NOT_FOUND;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Adds a new field into the payload. If the supplied advertising data type is
|
|
* already present in the advertising payload, then the value is replaced.
|
|
*
|
|
* @param[in] advDataType The type of the field to add.
|
|
* @param[in] fieldData Span of data to add.
|
|
*
|
|
* @retval BLE_ERROR_NONE on success.
|
|
* @retval BLE_ERROR_BUFFER_OVERFLOW if buffer is too small to contain the new data.
|
|
*/
|
|
ble_error_t addOrReplaceData(
|
|
adv_data_type_t advDataType,
|
|
mbed::Span<const uint8_t> fieldData
|
|
) {
|
|
uint8_t* field = findField(advDataType);
|
|
|
|
if (field) {
|
|
return replaceField(advDataType, fieldData, field);
|
|
} else {
|
|
return addField(advDataType, fieldData);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Adds a new field into the payload. If the supplied advertising data type is
|
|
* already present in the advertising payload, then the value is replaced.
|
|
*
|
|
* @param[in] advDataType The type of the field to add.
|
|
* @param[in] fieldData Span of data to add.
|
|
*
|
|
* @retval BLE_ERROR_NONE on success.
|
|
* @retval BLE_ERROR_BUFFER_OVERFLOW if buffer is too small to contain the new data.
|
|
*/
|
|
ble_error_t addOrAppendData(
|
|
adv_data_type_t advDataType,
|
|
mbed::Span<const uint8_t> fieldData
|
|
) {
|
|
uint8_t* field = findField(advDataType);
|
|
|
|
if (field) {
|
|
return appendToField(fieldData, field);
|
|
} else {
|
|
return addField(advDataType, fieldData);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Clears the advertising data payload.
|
|
*
|
|
* @post getPayloadLen() returns 0.
|
|
*/
|
|
void clear() {
|
|
memset(_buffer.data(), 0, _buffer.size());
|
|
_payload_length = 0;
|
|
}
|
|
|
|
/**
|
|
* Add device appearance in the advertising payload.
|
|
*
|
|
* @param[in] appearance The appearance to advertise.
|
|
*
|
|
* @retval BLE_ERROR_NONE on success.
|
|
* @retval BLE_ERROR_BUFFER_OVERFLOW if buffer is too small to contain the new data.
|
|
*
|
|
* @note This call is equivalent to calling addOrReplaceData() with
|
|
* adv_data_type_t::APPEARANCE as the field type.
|
|
*/
|
|
ble_error_t setAppearance(
|
|
adv_data_appearance_t appearance
|
|
) {
|
|
uint8_t appearence_byte = appearance.value();
|
|
mbed::Span<const uint8_t> appearance_span((const uint8_t*) &appearence_byte, 2);
|
|
return addOrReplaceData(adv_data_type_t::APPEARANCE, appearance_span);
|
|
}
|
|
|
|
/**
|
|
* Add BLE flags in the advertising payload.
|
|
*
|
|
* @param[in] flags Bitfield describing the capability of the device. See
|
|
* allowed flags in Flags_t.
|
|
*
|
|
* @retval BLE_ERROR_NONE on success.
|
|
* @retval BLE_ERROR_BUFFER_OVERFLOW if buffer is too small to contain the new data.
|
|
*
|
|
* @note This call is equivalent to calling addOrReplaceData() with
|
|
* adv_data_type_t::FLAGS as the field type.
|
|
*/
|
|
ble_error_t setFlags(
|
|
adv_data_flags_t flags = adv_data_flags_t::default_flags
|
|
) {
|
|
uint8_t flags_byte = flags.value();
|
|
mbed::Span<const uint8_t> flags_span((const uint8_t*) &flags_byte, 1);
|
|
return addOrReplaceData(adv_data_type_t::FLAGS, flags_span);
|
|
}
|
|
|
|
/**
|
|
* Add the advertising TX in the advertising payload.
|
|
*
|
|
* @param[in] txPower Transmission power level in dB.
|
|
*
|
|
* @retval BLE_ERROR_NONE on success.
|
|
* @retval BLE_ERROR_BUFFER_OVERFLOW if buffer is too small to contain the new data.
|
|
*
|
|
* @note This call is equivalent to calling addOrReplaceData() with
|
|
* adv_data_type_t::TX_POWER_LEVEL as the field type.
|
|
*/
|
|
ble_error_t setTxPowerAdvertised(
|
|
advertising_power_t txPower
|
|
) {
|
|
mbed::Span<const uint8_t> power_span((const uint8_t*) &txPower, 1);
|
|
return addOrReplaceData(adv_data_type_t::TX_POWER_LEVEL, power_span);
|
|
}
|
|
|
|
/**
|
|
* Add device name to the advertising payload.
|
|
*
|
|
* @param[in] name Null terminated string containing the name.
|
|
* @param[in] complete Complete local name if true, otherwise
|
|
*
|
|
* @retval BLE_ERROR_NONE on success.
|
|
* @retval BLE_ERROR_BUFFER_OVERFLOW if buffer is too small to contain the new data.
|
|
*/
|
|
ble_error_t setName(
|
|
const char* name,
|
|
bool complete = true
|
|
) {
|
|
mbed::Span<const uint8_t> power_span((const uint8_t*)name, strlen(name));
|
|
|
|
if (complete) {
|
|
return addOrReplaceData(adv_data_type_t::COMPLETE_LOCAL_NAME, power_span);
|
|
} else {
|
|
return addOrReplaceData(adv_data_type_t::SHORTENED_LOCAL_NAME, power_span);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Add manufacturer specific data to the advertising payload.
|
|
*
|
|
* @param[in] data New data to be added.
|
|
*
|
|
* @retval BLE_ERROR_NONE on success.
|
|
* @retval BLE_ERROR_BUFFER_OVERFLOW if buffer is too small to contain the new data.
|
|
*/
|
|
ble_error_t setManufacturerSpecificData(
|
|
mbed::Span<const uint8_t> data
|
|
) {
|
|
return addOrReplaceData(adv_data_type_t::MANUFACTURER_SPECIFIC_DATA, data);
|
|
}
|
|
|
|
|
|
ble_error_t setAdvertisingInterval(adv_interval_t interval) {
|
|
return addOrReplaceData(
|
|
adv_data_type_t::ADVERTISING_INTERVAL,
|
|
mbed::make_Span((const uint8_t*)interval.storage(), 2)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Add service data data to the advertising payload.
|
|
*
|
|
* @param[in] service UUID of the service.
|
|
* @param[in] data New data to be added.
|
|
* @param[in] complete True if this is a complete list.
|
|
*
|
|
* @retval BLE_ERROR_NONE on success.
|
|
* @retval BLE_ERROR_BUFFER_OVERFLOW if buffer is too small to contain the new data.
|
|
*/
|
|
ble_error_t setServiceData(
|
|
UUID service,
|
|
mbed::Span<const uint8_t> data
|
|
) {
|
|
size_t total_size = data.size() + service.getLen() + 2;
|
|
size_t old_size = getFieldSize(adv_data_type_t::SERVICE_DATA);
|
|
|
|
/* if we can't fit the new data do not proceed */
|
|
if (total_size > data.size() - (_payload_length - old_size)) {
|
|
return BLE_ERROR_BUFFER_OVERFLOW;
|
|
}
|
|
|
|
if (old_size) {
|
|
removeData(adv_data_type_t::SERVICE_DATA);
|
|
}
|
|
|
|
ble_error_t status1 = addData(
|
|
adv_data_type_t::SERVICE_DATA,
|
|
mbed::make_Span(service.getBaseUUID(), service.getLen())
|
|
);
|
|
|
|
ble_error_t status2 = appendData(adv_data_type_t::SERVICE_DATA, data);
|
|
|
|
if (status1 != BLE_ERROR_NONE || status2 != BLE_ERROR_NONE) {
|
|
return BLE_ERROR_INTERNAL_STACK_FAILURE;
|
|
}
|
|
|
|
return BLE_ERROR_NONE;
|
|
}
|
|
|
|
/**
|
|
* Add local service IDs to the advertising payload. If they data can't fit
|
|
* no modification will take place.
|
|
*
|
|
* @param[in] data New data to be added.
|
|
* @param[in] complete True if this is a complete list.
|
|
*
|
|
* @retval BLE_ERROR_NONE on success.
|
|
* @retval BLE_ERROR_BUFFER_OVERFLOW if buffer is too small to contain the new data.
|
|
*/
|
|
ble_error_t setLocalServiceList(
|
|
mbed::Span<const UUID> data,
|
|
bool complete = true
|
|
) {
|
|
ble_error_t status = BLE_ERROR_NONE;
|
|
|
|
/* first count all the bytes we need to store all the UUIDs */
|
|
size_t size_long = 0;
|
|
size_t size_short = 0;
|
|
for (size_t i = 0; i < data.size(); ++i) {
|
|
if (data[i].shortOrLong() == UUID::UUID_TYPE_SHORT) {
|
|
size_short++;
|
|
} else {
|
|
size_long++;
|
|
}
|
|
}
|
|
|
|
/* calculate total size including headers for types */
|
|
size_t total_size = size_long + (!!size_long) * 2 +
|
|
size_short + (!!size_short) * 2;
|
|
|
|
/* count all the bytes of existing data */
|
|
size_t old_size = getFieldSize(adv_data_type_t::INCOMPLETE_LIST_16BIT_SERVICE_IDS) +
|
|
getFieldSize(adv_data_type_t::COMPLETE_LIST_16BIT_SERVICE_IDS) +
|
|
getFieldSize(adv_data_type_t::INCOMPLETE_LIST_128BIT_SERVICE_IDS) +
|
|
getFieldSize(adv_data_type_t::COMPLETE_LIST_128BIT_SERVICE_IDS);
|
|
|
|
/* if we can't fit the new data do not proceed */
|
|
if (total_size > data.size() - (_payload_length - old_size)) {
|
|
return BLE_ERROR_BUFFER_OVERFLOW;
|
|
}
|
|
|
|
/* otherwise wipe old data */
|
|
removeData(adv_data_type_t::INCOMPLETE_LIST_16BIT_SERVICE_IDS);
|
|
removeData(adv_data_type_t::COMPLETE_LIST_16BIT_SERVICE_IDS);
|
|
removeData(adv_data_type_t::INCOMPLETE_LIST_128BIT_SERVICE_IDS);
|
|
removeData(adv_data_type_t::COMPLETE_LIST_128BIT_SERVICE_IDS);
|
|
|
|
const adv_data_type_t short_type = complete ?
|
|
adv_data_type_t::COMPLETE_LIST_16BIT_SERVICE_IDS :
|
|
adv_data_type_t::INCOMPLETE_LIST_16BIT_SERVICE_IDS;
|
|
|
|
const adv_data_type_t long_type = complete ?
|
|
adv_data_type_t::COMPLETE_LIST_128BIT_SERVICE_IDS :
|
|
adv_data_type_t::INCOMPLETE_LIST_128BIT_SERVICE_IDS;
|
|
|
|
/* and insert individual UUIDs into appropriate fields */
|
|
for (size_t i = 0; i < data.size(); ++i) {
|
|
adv_data_type_t field_type(adv_data_type_t::FLAGS);
|
|
if (data[i].shortOrLong() == UUID::UUID_TYPE_SHORT) {
|
|
field_type = short_type;
|
|
} else {
|
|
field_type = long_type;
|
|
}
|
|
|
|
mbed::Span<const uint8_t> span(data[i].getBaseUUID(), data[i].getLen());
|
|
|
|
uint8_t *field = findField(field_type);
|
|
|
|
if (field) {
|
|
status = appendToField(span, field);
|
|
if (status != BLE_ERROR_NONE) {
|
|
/* we already checked for size so this must not happen */
|
|
return BLE_ERROR_INTERNAL_STACK_FAILURE;
|
|
}
|
|
} else {
|
|
status = addField(field_type, span);
|
|
if (status != BLE_ERROR_NONE) {
|
|
/* we already checked for size so this must not happen */
|
|
return BLE_ERROR_INTERNAL_STACK_FAILURE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
/**
|
|
* Return a span of data containing the the type of data requested.
|
|
*
|
|
* @param[out] data Span used to return the requested data.
|
|
* @param[in] advDataType Data type to return.
|
|
*
|
|
* @return BLE_ERROR_NONE if data was found and BLE_ERROR_NOT_FOUND if not.
|
|
*/
|
|
ble_error_t getData(
|
|
mbed::Span<const uint8_t> &data,
|
|
adv_data_type_t advDataType
|
|
) {
|
|
uint8_t *field = findField(advDataType);
|
|
if (field) {
|
|
uint8_t data_length = field[0] - 1 /* skip type */;
|
|
data = mbed::make_Span((const uint8_t*)(field + 2 /* skip type and length */), data_length);
|
|
return BLE_ERROR_NONE;
|
|
} else {
|
|
return BLE_ERROR_NOT_FOUND;
|
|
}
|
|
}
|
|
|
|
private:
|
|
/**
|
|
* Search advertisement data for a specific field.
|
|
*
|
|
* @param[in] type The type of the field to find.
|
|
*
|
|
* @return A pointer to the first element in the field if found. The first
|
|
* element being the length of the field followed by the value of the field.
|
|
* NULL if the field is not present in the payload.
|
|
*/
|
|
uint8_t* findField(adv_data_type_t type)
|
|
{
|
|
/* Scan through advertisement data */
|
|
for (uint8_t idx = 0; idx < _payload_length; ) {
|
|
uint8_t fieldType = _buffer[idx + 1];
|
|
|
|
if (fieldType == type) {
|
|
return _buffer.data() + idx;
|
|
}
|
|
|
|
/* Advance to next field */
|
|
idx += _buffer[idx] + 1;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
size_t getFieldSize(adv_data_type_t type) {
|
|
uint8_t *field = findField(type);
|
|
if (field) {
|
|
return field[0] + 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Append advertising data based on the specified type.
|
|
*
|
|
* @param[in] advDataType Type of the new data.
|
|
* @param[in] fieldData Span of data to add.
|
|
*
|
|
* @retval BLE_ERROR_NONE on success.
|
|
* @retval BLE_ERROR_BUFFER_OVERFLOW if buffer is too small to contain the new data.
|
|
*/
|
|
ble_error_t addField(
|
|
adv_data_type_t advDataType,
|
|
mbed::Span<const uint8_t> fieldData
|
|
) {
|
|
|
|
/* Make sure we don't exceed the buffer size */
|
|
if (_payload_length + fieldData.size() + 2 > _buffer.size()) {
|
|
return BLE_ERROR_BUFFER_OVERFLOW;
|
|
}
|
|
|
|
/* Field length. */
|
|
_buffer[_payload_length] = fieldData.size() + 1;
|
|
++_payload_length;
|
|
|
|
/* Field ID. */
|
|
_buffer[_payload_length] = advDataType.value();
|
|
++_payload_length;
|
|
|
|
/* Payload. */
|
|
memcpy(&_buffer[_payload_length], fieldData.data(), fieldData.size());
|
|
_payload_length += fieldData.size();
|
|
|
|
return BLE_ERROR_NONE;
|
|
}
|
|
|
|
/**
|
|
* Append data to a field in the advertising payload.
|
|
*
|
|
* @param[in] fieldData Span of data to add.
|
|
* @param[in] field Pointer to the field in the advertising buffer.
|
|
*
|
|
* @return BLE_ERROR_NONE on success.
|
|
*/
|
|
ble_error_t appendToField(
|
|
mbed::Span<const uint8_t> fieldData,
|
|
uint8_t* field
|
|
) {
|
|
/* Check if data fits */
|
|
if ((_payload_length + fieldData.size()) <= _buffer.size()) {
|
|
/*
|
|
* Make room for new field by moving the remainder of the
|
|
* advertisement payload "to the right" starting after the
|
|
* TYPE field.
|
|
*/
|
|
uint8_t* end = _buffer.data() + _payload_length;
|
|
|
|
while (&field[1] < end) {
|
|
end[fieldData.size()] = *end;
|
|
end--;
|
|
}
|
|
|
|
/* Insert new data */
|
|
for (uint8_t idx = 0; idx < fieldData.size(); idx++) {
|
|
field[2 + idx] = fieldData[idx];
|
|
}
|
|
|
|
/* Increment lengths */
|
|
field[0] += fieldData.size();
|
|
_payload_length += fieldData.size();
|
|
|
|
return BLE_ERROR_NONE;
|
|
} else {
|
|
return BLE_ERROR_BUFFER_OVERFLOW;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Update in place the value of a field in the advertising payload.
|
|
*
|
|
* @param[in] advDataType Type of the new data.
|
|
* @param[in] fieldData Span of data to add.
|
|
* @param[in] field Pointer to the field of type @p advDataType in the
|
|
* advertising buffer.
|
|
*
|
|
* @retval BLE_ERROR_NONE on success.
|
|
* @retval BLE_ERROR_BUFFER_OVERFLOW if buffer is too small to contain the new data.
|
|
*/
|
|
ble_error_t replaceField(
|
|
adv_data_type_t advDataType,
|
|
mbed::Span<const uint8_t> fieldData,
|
|
uint8_t* field
|
|
) {
|
|
ble_error_t result = BLE_ERROR_BUFFER_OVERFLOW;
|
|
uint8_t old_data_length = field[0] - 1;
|
|
|
|
/* New data has same length, do in-order replacement */
|
|
if (fieldData.size() == old_data_length) {
|
|
for (uint8_t idx = 0; idx < old_data_length; idx++) {
|
|
field[2 + idx] = fieldData[idx];
|
|
}
|
|
|
|
result = BLE_ERROR_NONE;
|
|
} else {
|
|
/* Check if data fits */
|
|
if ((_payload_length - old_data_length + fieldData.size()) <= _buffer.size()) {
|
|
removeField(field);
|
|
|
|
/* Add new field */
|
|
result = addField(advDataType, fieldData);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Remove the field.
|
|
*
|
|
* @param[in] field Pointer to the field in the advertising buffer.
|
|
*
|
|
* @return BLE_ERROR_NONE on success.
|
|
*/
|
|
ble_error_t removeField(
|
|
uint8_t* field
|
|
) {
|
|
uint8_t old_data_length = field[0] - 1;
|
|
|
|
/* Remove old field */
|
|
while ((field + old_data_length + 2) < _buffer.data() + _payload_length) {
|
|
*field = field[old_data_length + 2];
|
|
field++;
|
|
}
|
|
|
|
/* Reduce length */
|
|
_payload_length -= old_data_length + 2;
|
|
|
|
return BLE_ERROR_NONE;
|
|
}
|
|
|
|
protected:
|
|
/** The memory backing the the data provided by the user. */
|
|
mbed::Span<uint8_t> _buffer;
|
|
|
|
/** Length of the data added to the advertising buffer. */
|
|
uint8_t _payload_length;
|
|
};
|
|
|
|
} // namespace ble
|
|
|
|
/**
|
|
* @}
|
|
* @}
|
|
*/
|
|
|
|
|
|
#endif /* ifndef MBED_GAP_ADVERTISING_DATA_H__ */
|