From 6a55d65660118360de10df1b1ba421c65ddefb6a Mon Sep 17 00:00:00 2001 From: Vincent Coubard Date: Fri, 9 Nov 2018 22:38:22 +0000 Subject: [PATCH] BLE: Create advertising payload builder. This change set use a data buffer to set data and scan responses. --- features/FEATURE_BLE/ble/Gap.h | 18 +- .../FEATURE_BLE/ble/gap/AdvertisingData.h | 967 ------------------ .../ble/gap/AdvertisingDataBuilder.h | 552 ++++++++++ features/FEATURE_BLE/ble/generic/GenericGap.h | 29 +- .../FEATURE_BLE/source/generic/GenericGap.cpp | 42 +- 5 files changed, 619 insertions(+), 989 deletions(-) delete mode 100644 features/FEATURE_BLE/ble/gap/AdvertisingData.h create mode 100644 features/FEATURE_BLE/ble/gap/AdvertisingDataBuilder.h diff --git a/features/FEATURE_BLE/ble/Gap.h b/features/FEATURE_BLE/ble/Gap.h index 87392d6f1a..2b4d4e7db7 100644 --- a/features/FEATURE_BLE/ble/Gap.h +++ b/features/FEATURE_BLE/ble/Gap.h @@ -20,7 +20,7 @@ #include "BLETypes.h" #include "BLEProtocol.h" #include "GapAdvertisingData.h" -#include "ble/gap/AdvertisingData.h" +#include "ble/gap/AdvertisingDataBuilder.h" #include "GapAdvertisingParams.h" #include "GapScanningParams.h" #include "GapEvents.h" @@ -1705,17 +1705,27 @@ public: return BLE_ERROR_NOT_IMPLEMENTED; } - virtual ble_error_t setAdvertisingPayload(AdvHandle_t handle, const AdvertisingData& payload, - bool minimiseFragmentation = false) { + virtual ble_error_t setAdvertisingPayload( + AdvHandle_t handle, + mbed::Span payload, + bool minimiseFragmentation = false + ) + { (void) handle; (void) payload; /* Requesting action from porter(s): override this API if this capability is supported. */ return BLE_ERROR_NOT_IMPLEMENTED; } - virtual ble_error_t setAdvertisingScanResponse(AdvHandle_t handle, const AdvertisingData& response) { + virtual ble_error_t setAdvertisingScanResponse( + AdvHandle_t handle, + mbed::Span response, + bool minimiseFragmentation + ) + { (void) handle; (void) response; + (void) minimiseFragmentation; /* Requesting action from porter(s): override this API if this capability is supported. */ return BLE_ERROR_NOT_IMPLEMENTED; } diff --git a/features/FEATURE_BLE/ble/gap/AdvertisingData.h b/features/FEATURE_BLE/ble/gap/AdvertisingData.h deleted file mode 100644 index c669cb6cc6..0000000000 --- a/features/FEATURE_BLE/ble/gap/AdvertisingData.h +++ /dev/null @@ -1,967 +0,0 @@ -/* 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 -#include -#include - -#include "blecommon.h" -#include "platform/Span.h" -#include "NonCopyable.h" - -/** - * @addtogroup ble - * @{ - * @addtogroup gap - * @{ - */ - -#define GAP_ADVERTISING_DATA_MAX_PAYLOAD (31) - -/** - * GAP advertising data builder. - * - * Advertising data are used by broadcaster or peripheral to advertise state - * about the device. This class offers the function to add and update states present - * in an advertisement payload. - * - * After construction, the advertising payload contained in the instance of - * AdvertisingData is empty. Adding new states and named fields can be - * achieved by invoking the function addData(), and updating existing state - * involves calling the function updateData(). - * - * Fields present in the payload can be retrieved by a call to the function - * findField. - * - * This class includes shorthand for the most common fields: - * - FLAGS: addFlags(). - * - APPEARANCE: addAppearance(). - * - TX_POWER_LEVEL: addTxPower(). - * - * @code - * - * Gap ⪆ - * - * static const uint8_t device_name[] = "HRM"; - * - * // construct an empty advertising payload - * AdvertisingData advertising_data; - * - * // set the flags of the advertising device - * advertising_data.addFlags( - * AdvertisingData::LE_GENERAL_DISCOVERABLE | - * AdvertisingData::BREDR_NOT_SUPPORTED - * ); - * - * // set the advertised name of the device - * advertising_data.addData( - * AdvertisingData::COMPLETE_LOCAL_NAME, - * device_name, - * sizeof(device_name) - * ); - * - * // update the advertising data of the gap payload - * gap.setAdvertisingPayload(advertising_data); - * - * @endcode - * - * @note See Bluetooth Specification 4.0 (Vol. 3), Part C, Sections 11 and 18 - * for further information on advertising and scan response data. - * - * @par Advertising and Scan Response Payloads - * Advertising data and scan response data are organized around a set of - * data types called 'AD types' in Bluetooth 4.0 (see the Bluetooth Core - * Specification v4.0, Vol. 3, Part C, Sections 11 and 18). - * - * @par - * Each AD type has its own standardized assigned number, as - * the Bluetooth SIG defines: - * https://www.bluetooth.org/en-us/specification/assigned-numbers/generic-access-profile. - * - * @par - * For convenience, all appropriate AD types are encapsulated in - * AdvertisingData::DataType. - * - * @par - * Before the AD Types and their payload (if any) can be inserted into - * the advertising or scan response frames, they need to be formatted as - * follows: - * - * @li @c Record length (1 byte). - * @li @c AD Type (1 byte). - * @li @c AD payload (optional; only present if record length > 1). - * - * @par - * This class takes care of properly formatting the payload, performs - * some basic checks on the payload length and tries to avoid common - * errors such as adding an exclusive AD field twice in the advertising - * or scan response payload. - */ -class AdvertisingData -{ -public: - /*! - * 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. - */ - enum DataType_t { - /** - * 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 - - }; - - /** - * Alias for AdvertisingData::DataType_t. - * - * @deprecated Future releases will drop this type alias. - */ - typedef enum DataType_t DataType; - - /** - * Enumeration of allowed flags for DataType_t::FLAGS. - * - * @note DataType_t::FLAGS may contain several flags that the bitwise - * and operator (ex.LE_GENERAL_DISCOVERABLE & BREDR_NOT_SUPPORTED) assembled. - * - * @par Source - * - * @li @c Bluetooth Core Specification 4.0 (Vol. 3), Part C, Section 18.1. - */ - enum Flags_t { - /** - * Peripheral device is discoverable for a limited period of time. - */ - LE_LIMITED_DISCOVERABLE = 0x01, - - /** - * Peripheral device is discoverable at any moment. - */ - LE_GENERAL_DISCOVERABLE = 0x02, - - /** - * Peripheral device is LE only and does not support Bluetooth Enhanced - * DataRate. - */ - BREDR_NOT_SUPPORTED = 0x04, - - /** - * Not relevant - dual mode only. - */ - SIMULTANEOUS_LE_BREDR_C = 0x08, - - /** - * Not relevant - dual mode only. - */ - SIMULTANEOUS_LE_BREDR_H = 0x10 - - }; - - /** - * Alias for AdvertisingData::Flags_t. - * - * @deprecated Future releases will drop this type alias. - */ - typedef enum Flags_t Flags; - - /** - * Enumeration of values for the DataType_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. - */ - enum Appearance_t { - /** - * 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 - - }; - - /** - * Alias for AdvertisingData::Appearance_t. - * - * @deprecated Future releases will drop this type alias. - */ - typedef enum Appearance_t Appearance; - - /** 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. - */ - AdvertisingData(mbed::Span buffer) : - _buffer(buffer), - _payloadLen(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. - */ - AdvertisingData(uint8_t* buffer, size_t buffer_size) : - _buffer(buffer, buffer_size), - _payloadLen(0) { - } - - /** Return maximum size of the data that can be stored. - * - * @return Size of the buffer used to store the data. - */ - size_t getBufferSize() const { - return _buffer.size(); - } - - /** - * Get the subspan of the buffer containing valid data. - * - * @return A Span containing the payload. - */ - void getData(mbed::Span &data) { - data = mbed::make_Span(_buffer.data(), _payloadLen); - } - - /** - * Get the pointer to the advertising payload bytes. - * - * @return A pointer to the payload. - */ - const uint8_t *getPayload() const - { - return _buffer.data(); - } - - /** - * Get the pointer to the advertising payload bytes. - * - * @return A pointer to the payload. - */ - uint8_t *getPayload() { - return _buffer.data(); - } - - /** - * Get the payload length. - * - * @return The payload length in bytes. - */ - uint8_t getPayloadLen(void) const - { - return _payloadLen; - } - - /** - * Adds a new field into the payload. - * - * If the supplied advertising data type is already present in the - * advertising payload, then the value is updated. - * - * @param[in] advDataType The type of the field to add. - * @param[in] payload Pointer to the value of the field to add. - * @param[in] len Size in bytes of the value to add. - * - * @return BLE_ERROR_NONE on success. - * @return BLE_ERROR_BUFFER_OVERFLOW if the new value causes the advertising - * buffer to overflow. - * - * @note When the specified data type is INCOMPLETE_LIST_16BIT_SERVICE_IDS, - * COMPLETE_LIST_16BIT_SERVICE_IDS, INCOMPLETE_LIST_32BIT_SERVICE_IDS, - * COMPLETE_LIST_32BIT_SERVICE_IDS, INCOMPLETE_LIST_128BIT_SERVICE_IDS, - * COMPLETE_LIST_128BIT_SERVICE_IDS or LIST_128BIT_SOLICITATION_IDS, the - * supplied value is appended to the values present in the payload. - */ - ble_error_t addData(DataType_t advDataType, const uint8_t *payload, uint8_t len) - { - /* Find field */ - uint8_t* field = findField(advDataType); - - if (field) { - /* Field type already exists, either add to field or replace */ - return addField(advDataType, payload, len, field); - } else { - /* Field doesn't exist, insert new */ - return appendField(advDataType, payload, len); - } - } - - /** - * Update a specific field in the advertising payload. - * - * @param[in] advDataType The type of the field to update. - * @param[in] payload Pointer to the updated value of the field. - * @param[in] len Size of the new value in bytes. - * - * @return BLE_ERROR_NONE returned on success. - * @return BLE_ERROR_UNSPECIFIED if the specified field is not found, - * @return BLE_ERROR_BUFFER_OVERFLOW if the new value causes the - * advertising buffer to overflow. - */ - ble_error_t updateData(DataType_t advDataType, const uint8_t *payload, uint8_t len) - { - /* Find field */ - uint8_t* field = findField(advDataType); - - if (field) { - /* Field type already exists, replace field contents */ - return updateField(advDataType, payload, len, field); - } else { - /* field doesn't exist, return an error */ - return BLE_ERROR_UNSPECIFIED; - } - } - - /** - * Add device appearance in the advertising payload. - * - * @param[in] appearance The appearance to advertise. - * - * @return BLE_ERROR_NONE on success. - * @return BLE_ERROR_BUFFER_OVERFLOW if the specified data would cause the - * advertising buffer to overflow. - * - * @note This call is equivalent to calling addData() with - * AdvertisingData::APPEARANCE as the field type. - */ - ble_error_t addAppearance(Appearance appearance = GENERIC_TAG) - { - return addData(AdvertisingData::APPEARANCE, (uint8_t *)&appearance, 2); - } - - /** - * Add BLE flags in the advertising payload. - * - * @param[in] flags Bitfield describing the capability of the device. See - * allowed flags in Flags_t. - * - * @return BLE_ERROR_NONE on success. - * @return BLE_ERROR_BUFFER_OVERFLOW if the specified data would cause the - * advertising buffer to overflow. - * - * @note This call is equivalent to calling addData() with - * AdvertisingData::FLAGS as the field type. - */ - ble_error_t addFlags(uint8_t flags = LE_GENERAL_DISCOVERABLE) - { - return addData(AdvertisingData::FLAGS, &flags, 1); - } - - /** - * Add the advertising TX in the advertising payload. - * - * @param[in] txPower Transmission power level in dB. - * - * @return BLE_ERROR_NONE on success. - * @return BLE_ERROR_BUFFER_OVERFLOW if the specified data would cause the - * advertising buffer to overflow. - * - * @note This call is equivalent to calling addData() with - * AdvertisingData::TX_POWER_LEVEL as the field type. - */ - ble_error_t addTxPower(int8_t txPower) - { - /* To Do: Basic error checking to make sure txPower is in range. */ - return addData(AdvertisingData::TX_POWER_LEVEL, (uint8_t *)&txPower, 1); - } - - /** - * Clears the advertising data payload. - * - * @post getPayloadLen() returns 0. - */ - void clear(void) - { - memset(_buffer.data(), 0, GAP_ADVERTISING_DATA_MAX_PAYLOAD); - _payloadLen = 0; - } - - /** - * Get the appearance set. - * - * If no value has been set, this function returns GENERIC_TAG. - * - * @return The appearance value set for this device. - */ - uint16_t getAppearance(void) const - { - uint16_t appearance = GENERIC_TAG; - const uint8_t *field = findField(AdvertisingData::APPEARANCE); - if (field) { - memcpy((uint8_t*)&appearance, field, 2); - } - return appearance; - } - - /** - * 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. - * @return NULL if the field is not present in the payload. - */ - const uint8_t* findField(DataType_t type) const - { - /* Scan through advertisement data */ - for (uint8_t idx = 0; idx < _payloadLen; ) { - uint8_t fieldType = _buffer[idx + 1]; - - if (fieldType == type) { - return (_buffer.data() + idx); - } - - /* Advance to next field */ - idx += _buffer[idx] + 1; - } - - /* Field not found */ - return NULL; - } - -private: - /** - * Append advertising data based on the specified type. - * - * @param[in] advDataType Type of the new data. - * @param[in] payload Pointer to the data to be appended to the advertising - * payload. - * @param[in] len Length of the data pointed to by @p payload. - * - * @return BLE_ERROR_NONE on success. - * @return BLE_ERROR_BUFFER_OVERFLOW if the specified data would cause the - * advertising buffer to overflow. - */ - ble_error_t appendField(DataType advDataType, const uint8_t *payload, uint8_t len) - { - /* Make sure we don't exceed the 31-byte payload limit */ - if (_payloadLen + len + 2 > GAP_ADVERTISING_DATA_MAX_PAYLOAD) { - return BLE_ERROR_BUFFER_OVERFLOW; - } - - /* Field length. */ - memset(_buffer.data() + _payloadLen, len + 1, 1); - _payloadLen++; - - /* Field ID. */ - memset(_buffer.data() + _payloadLen, (uint8_t)advDataType, 1); - _payloadLen++; - - /* Payload. */ - memcpy(_buffer.data() + _payloadLen, payload, len); - _payloadLen += len; - - return BLE_ERROR_NONE; - } - - /** - * 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. - * @return NULL if the field is not present in the payload. - */ - uint8_t* findField(DataType_t type) - { - return const_cast( - static_cast(this)->findField(type) - ); - } - - /** - * Update in place the value of a field in the advertising payload. - * - * @param[in] advDataType Type of the new data. - * @param[in] payload Pointer to the data to be added to the advertising - * payload. - * @param[in] len Length of the data pointed to by @p payload. - * @param[in] field Pointer to the field of type @p advDataType in the - * advertising buffer. - * - * @note When the specified AD type is INCOMPLETE_LIST_16BIT_SERVICE_IDS, - * COMPLETE_LIST_16BIT_SERVICE_IDS, INCOMPLETE_LIST_32BIT_SERVICE_IDS, - * COMPLETE_LIST_32BIT_SERVICE_IDS, INCOMPLETE_LIST_128BIT_SERVICE_IDS, - * COMPLETE_LIST_128BIT_SERVICE_IDS or LIST_128BIT_SOLICITATION_IDS, the - * supplied value is appended to the values previously added to the - * payload. - * - * @return BLE_ERROR_NONE on success. - */ - ble_error_t addField( - DataType_t advDataType, - const uint8_t *payload, - uint8_t len, - uint8_t* field - ) { - ble_error_t result = BLE_ERROR_BUFFER_OVERFLOW; - - switch(advDataType) { - /* These fields have the new data appended if there is sufficient space. */ - case INCOMPLETE_LIST_16BIT_SERVICE_IDS: - case COMPLETE_LIST_16BIT_SERVICE_IDS: - case INCOMPLETE_LIST_32BIT_SERVICE_IDS: - case COMPLETE_LIST_32BIT_SERVICE_IDS: - case INCOMPLETE_LIST_128BIT_SERVICE_IDS: - case COMPLETE_LIST_128BIT_SERVICE_IDS: - case LIST_128BIT_SOLICITATION_IDS: { - /* Check if data fits */ - if ((_payloadLen + len) <= _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() +_payloadLen; - - while (&field[1] < end) { - end[len] = *end; - end--; - } - - /* Insert new data */ - for (uint8_t idx = 0; idx < len; idx++) { - field[2 + idx] = payload[idx]; - } - - /* Increment lengths */ - field[0] += len; - _payloadLen += len; - - result = BLE_ERROR_NONE; - } - - break; - } - /* These fields are overwritten with the new value */ - default: { - result = updateField(advDataType, payload, len, field); - - break; - } - } - - return result; - } - - /** - * Update in place the value of a field in the advertising payload. - * - * @param[in] advDataType Type of the new data. - * @param[in] payload Pointer to the data to be added to the advertising - * payload. - * @param[in] len Length of the data pointed to by @p payload. - * @param[in] field Pointer to the field of type @p advDataType in the - * advertising buffer. - * - * @return BLE_ERROR_NONE on success. - */ - ble_error_t updateField( - DataType_t advDataType, - const uint8_t *payload, - uint8_t len, - uint8_t* field - ) { - ble_error_t result = BLE_ERROR_BUFFER_OVERFLOW; - uint8_t dataLength = field[0] - 1; - - /* New data has same length, do in-order replacement */ - if (len == dataLength) { - for (uint8_t idx = 0; idx < dataLength; idx++) { - field[2 + idx] = payload[idx]; - } - - result = BLE_ERROR_NONE; - } else { - /* Check if data fits */ - if ((_payloadLen - dataLength + len) <= GAP_ADVERTISING_DATA_MAX_PAYLOAD) { - - /* Remove old field */ - while ((field + dataLength + 2) < _buffer.data() + _payloadLen) { - *field = field[dataLength + 2]; - field++; - } - - /* Reduce length */ - _payloadLen -= dataLength + 2; - - /* Add new field */ - result = appendField(advDataType, payload, len); - } - } - - return result; - } - -protected: - AdvertisingData(const AdvertisingData& other) : - _buffer(other._buffer), - _payloadLen(other._payloadLen) { - } - -protected: - /** The memory backing the the data provided by the user. */ - mbed::Span _buffer; - - /** Length of the data added to the advertising buffer. */ - uint8_t _payloadLen; -}; - -/** - * @} - * @} - */ - - -#endif /* ifndef MBED_GAP_ADVERTISING_DATA_H__ */ diff --git a/features/FEATURE_BLE/ble/gap/AdvertisingDataBuilder.h b/features/FEATURE_BLE/ble/gap/AdvertisingDataBuilder.h new file mode 100644 index 0000000000..8272145faa --- /dev/null +++ b/features/FEATURE_BLE/ble/gap/AdvertisingDataBuilder.h @@ -0,0 +1,552 @@ +/* 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 +#include +#include + +#include "blecommon.h" +#include "platform/Span.h" +#include "NonCopyable.h" + +/** + * @addtogroup ble + * @{ + * @addtogroup gap + * @{ + */ + +struct GapAdvertisingConstant { + /*! + * 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. + */ + enum DataType { + /** + * 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 + }; + + /** + * Enumeration of allowed flags for DataType_t::FLAGS. + * + * @note DataType_t::FLAGS may contain several flags that the bitwise + * and operator (ex.LE_GENERAL_DISCOVERABLE & BREDR_NOT_SUPPORTED) assembled. + * + * @par Source + * + * @li @c Bluetooth Core Specification 4.0 (Vol. 3), Part C, Section 18.1. + */ + enum Flags { + /** + * Peripheral device is discoverable for a limited period of time. + */ + LE_LIMITED_DISCOVERABLE = 0x01, + + /** + * Peripheral device is discoverable at any moment. + */ + LE_GENERAL_DISCOVERABLE = 0x02, + + /** + * Peripheral device is LE only and does not support Bluetooth Enhanced + * DataRate. + */ + BREDR_NOT_SUPPORTED = 0x04, + + /** + * Not relevant - dual mode only. + */ + SIMULTANEOUS_LE_BREDR_C = 0x08, + + /** + * Not relevant - dual mode only. + */ + SIMULTANEOUS_LE_BREDR_H = 0x10 + + }; + + /** + * Enumeration of values for the DataType_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. + */ + enum Appearance { + /** + * 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 + + }; +}; + + +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 buffer) : + _buffer(buffer), + _payloadLen(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), + _payloadLen(0) { + } + + /** + * Get the subspan of the buffer containing valid data. + * + * @return A Span containing the payload. + */ + mbed::Span getAdvertisingData() const { + return _buffer.first(_payloadLen); + } + + /** + * Adds a new field into the payload. + * + * If the supplied advertising data type is already present in the + * advertising payload, then the value is updated. + * + * @param[in] advDataType The type of the field to add. + * @param[in] payload Pointer to the value of the field to add. + * @param[in] len Size in bytes of the value to add. + * + * @return BLE_ERROR_NONE on success. + * @return BLE_ERROR_BUFFER_OVERFLOW if the new value causes the advertising + * buffer to overflow. + * + * @note When the specified data type is INCOMPLETE_LIST_16BIT_SERVICE_IDS, + * COMPLETE_LIST_16BIT_SERVICE_IDS, INCOMPLETE_LIST_32BIT_SERVICE_IDS, + * COMPLETE_LIST_32BIT_SERVICE_IDS, INCOMPLETE_LIST_128BIT_SERVICE_IDS, + * COMPLETE_LIST_128BIT_SERVICE_IDS or LIST_128BIT_SOLICITATION_IDS, the + * supplied value is appended to the values present in the payload. + */ + ble_error_t addData(GapAdvertisingConstant::DataType advDataType, const uint8_t *payload, uint8_t len) + { + return appendField(advDataType, payload, len); + } + + /** + * Clears the advertising data payload. + * + * @post getPayloadLen() returns 0. + */ + void clear(void) + { + memset(_buffer.data(), 0, _buffer.size()); + _payloadLen = 0; + } + +private: + /** + * Append advertising data based on the specified type. + * + * @param[in] advDataType Type of the new data. + * @param[in] payload Pointer to the data to be appended to the advertising + * payload. + * @param[in] len Length of the data pointed to by @p payload. + * + * @return BLE_ERROR_NONE on success. + * @return BLE_ERROR_BUFFER_OVERFLOW if the specified data would cause the + * advertising buffer to overflow. + */ + ble_error_t appendField(GapAdvertisingConstant::DataType advDataType, const uint8_t *payload, uint8_t len) + { + /* Make sure we don't exceed the buffer size */ + if (_payloadLen + len + 2 > _buffer.size()) { + return BLE_ERROR_BUFFER_OVERFLOW; + } + + /* Field length. */ + memset(_buffer.data() + _payloadLen, len + 1, 1); + _payloadLen++; + + /* Field ID. */ + memset(_buffer.data() + _payloadLen, (uint8_t)advDataType, 1); + _payloadLen++; + + /* Payload. */ + memcpy(_buffer.data() + _payloadLen, payload, len); + _payloadLen += len; + + return BLE_ERROR_NONE; + } + +protected: + /** The memory backing the the data provided by the user. */ + mbed::Span _buffer; + + /** Length of the data added to the advertising buffer. */ + uint8_t _payloadLen; +}; + +/** + * @} + * @} + */ + + +#endif /* ifndef MBED_GAP_ADVERTISING_DATA_H__ */ diff --git a/features/FEATURE_BLE/ble/generic/GenericGap.h b/features/FEATURE_BLE/ble/generic/GenericGap.h index f8345ffef2..0bb8c3da2a 100644 --- a/features/FEATURE_BLE/ble/generic/GenericGap.h +++ b/features/FEATURE_BLE/ble/generic/GenericGap.h @@ -89,11 +89,23 @@ public: const GapAdvertisingParameters ¶ms ); - ble_error_t setAdvertisingPayload(AdvHandle_t handle, const AdvertisingData& payload, bool minimiseFragmentation = false); + ble_error_t setAdvertisingPayload( + AdvHandle_t handle, + mbed::Span payload, + bool minimiseFragmentation + ); - ble_error_t setAdvertisingScanResponse(AdvHandle_t handle, const AdvertisingData& response, bool minimiseFragmentation = false); + ble_error_t setAdvertisingScanResponse( + AdvHandle_t handle, + mbed::Span response, + bool minimiseFragmentation + ); - ble_error_t startAdvertising(AdvHandle_t handle, uint8_t maxEvents = 0, uint32_t maxDuration = 0); + ble_error_t startAdvertising( + AdvHandle_t handle, + uint8_t maxEvents = 0, + uint32_t maxDuration = 0 + ); ble_error_t stopAdvertising(AdvHandle_t handle); @@ -383,7 +395,12 @@ public: ); private: - ble_error_t setAdvertisingData(AdvHandle_t handle, const AdvertisingData& payload, bool minimiseFragmentation, bool scan_reponse); + ble_error_t setAdvertisingData( + AdvHandle_t handle, + mbed::Span payload, + bool minimiseFragmentation, + bool scan_response + ); /** @note Implements ConnectionEventMonitor. * @copydoc ConnectionEventMonitor::set_connection_event_handler @@ -528,13 +545,13 @@ private: pal::scanning_filter_policy_t _scanning_filter_policy; pal::advertising_filter_policy_t _advertising_filter_policy; mutable Whitelist_t _whitelist; - + bool _privacy_enabled; PeripheralPrivacyConfiguration_t _peripheral_privacy_configuration; CentralPrivacyConfiguration_t _central_privacy_configuration; ble::address_t _random_static_identity_address; bool _random_address_rotating; - + mbed::Timeout _advertising_timeout; mbed::Timeout _scan_timeout; mbed::Ticker _address_rotation_ticker; diff --git a/features/FEATURE_BLE/source/generic/GenericGap.cpp b/features/FEATURE_BLE/source/generic/GenericGap.cpp index 93fd4c789e..3477702da0 100644 --- a/features/FEATURE_BLE/source/generic/GenericGap.cpp +++ b/features/FEATURE_BLE/source/generic/GenericGap.cpp @@ -1670,39 +1670,57 @@ ble_error_t GenericGap::setAdvertisingParams( ); } -ble_error_t GenericGap::setAdvertisingPayload(AdvHandle_t handle, const AdvertisingData& payload, bool minimiseFragmentation) { +ble_error_t GenericGap::setAdvertisingPayload( + AdvHandle_t handle, + mbed::Span payload, + bool minimiseFragmentation +) { return setAdvertisingData(handle, payload, minimiseFragmentation, false); } -ble_error_t GenericGap::setAdvertisingScanResponse(AdvHandle_t handle, const AdvertisingData& response, bool minimiseFragmentation) { +ble_error_t GenericGap::setAdvertisingScanResponse( + AdvHandle_t handle, + mbed::Span response, + bool minimiseFragmentation +) { return setAdvertisingData(handle, response, minimiseFragmentation, true); } -ble_error_t GenericGap::setAdvertisingData(AdvHandle_t handle, const AdvertisingData& payload, bool minimiseFragmentation, bool scan_reponse) { +ble_error_t GenericGap::setAdvertisingData( + AdvHandle_t handle, + mbed::Span payload, + bool minimiseFragmentation, + bool scan_response +) { if (!get_adv_set_bit(_existing_sets, handle)) { return BLE_ERROR_INVALID_PARAM; } if (!is_extended_advertising_enabled()) { if (handle == Gap::LEGACY_ADVERTISING_HANDLE) { - if (scan_reponse) { + if (payload.size() < GAP_ADVERTISING_DATA_MAX_PAYLOAD) { + return BLE_ERROR_INVALID_PARAM; + } + if (scan_response) { return _pal_gap.set_advertising_data( - payload.getPayloadLen(), - pal::advertising_data_t(payload.getPayload(), payload.getPayloadLen()) + payload.size(), + pal::advertising_data_t(payload.data(), payload.size()) ); } else { return _pal_gap.set_scan_response_data( - payload.getPayloadLen(), - pal::advertising_data_t(payload.getPayload(), payload.getPayloadLen()) + payload.size(), + pal::advertising_data_t(payload.data(), payload.size()) ); } + } else { + return BLE_ERROR_INVALID_PARAM; } return BLE_ERROR_NOT_IMPLEMENTED; } ble_error_t status = BLE_ERROR_NONE; uint16_t index = 0; - const uint16_t& length = payload.getPayloadLen(); + const uint16_t& length = payload.size(); uint16_t packet_data_length = length; typedef pal::advertising_fragment_description_t op_t; @@ -1716,13 +1734,13 @@ ble_error_t GenericGap::setAdvertisingData(AdvHandle_t handle, const Advertising operation = op_t::LAST_FRAGMENT; } - if (scan_reponse) { + if (scan_response) { status = _pal_gap.set_extended_scan_response_data( handle, operation, minimiseFragmentation, packet_data_length, - payload.getPayload() + index + &payload[index] ); } else { status = _pal_gap.set_extended_advertising_data( @@ -1730,7 +1748,7 @@ ble_error_t GenericGap::setAdvertisingData(AdvHandle_t handle, const Advertising operation, minimiseFragmentation, packet_data_length, - payload.getPayload() + index + &payload[index] ); }