Diff: features/FEATURE_BLE/ble/GapAdvertisingData.h
- Revision:
- 0:0e018d759a2a
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/features/FEATURE_BLE/ble/GapAdvertisingData.h Tue Nov 08 18:27:11 2016 +0000
@@ -0,0 +1,567 @@
+/* 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 __GAP_ADVERTISING_DATA_H__
+#define __GAP_ADVERTISING_DATA_H__
+
+#include <stdint.h>
+#include <string.h>
+
+#include "blecommon.h"
+
+#define GAP_ADVERTISING_DATA_MAX_PAYLOAD (31)
+
+/**
+ * @brief This class provides several helper functions to generate properly
+ * formatted GAP Advertising and Scan Response data payloads.
+ *
+ * @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 defined
+ * by the Bluetooth SIG:
+ * https://www.bluetooth.org/en-us/specification/assigned-numbers/generic-access-profile.
+ *
+ * @par
+ * For convenience, all appropriate AD types are encapsulated
+ * in GapAdvertisingData::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 like adding an exclusive AD field twice in the Advertising
+ * or Scan Response payload.
+ *
+ * @par EXAMPLE
+ *
+ * @code
+ *
+ * // ToDo
+ *
+ * @endcode
+ */
+class GapAdvertisingData
+{
+public:
+ /*!
+ * @brief A list of Advertising Data types commonly used by peripherals.
+ * 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 = 0x01, /**< Flags, refer to GapAdvertisingData::Flags_t. */
+ INCOMPLETE_LIST_16BIT_SERVICE_IDS = 0x02, /**< Incomplete list of 16-bit Service IDs. */
+ COMPLETE_LIST_16BIT_SERVICE_IDS = 0x03, /**< Complete list of 16-bit Service IDs. */
+ INCOMPLETE_LIST_32BIT_SERVICE_IDS = 0x04, /**< Incomplete list of 32-bit Service IDs (not relevant for Bluetooth 4.0). */
+ COMPLETE_LIST_32BIT_SERVICE_IDS = 0x05, /**< Complete list of 32-bit Service IDs (not relevant for Bluetooth 4.0). */
+ INCOMPLETE_LIST_128BIT_SERVICE_IDS = 0x06, /**< Incomplete list of 128-bit Service IDs. */
+ COMPLETE_LIST_128BIT_SERVICE_IDS = 0x07, /**< Complete list of 128-bit Service IDs. */
+ SHORTENED_LOCAL_NAME = 0x08, /**< Shortened Local Name. */
+ COMPLETE_LOCAL_NAME = 0x09, /**< Complete Local Name. */
+ TX_POWER_LEVEL = 0x0A, /**< TX Power Level (in dBm). */
+ DEVICE_ID = 0x10, /**< Device ID. */
+ SLAVE_CONNECTION_INTERVAL_RANGE = 0x12, /**< Slave Connection Interval Range. */
+ LIST_128BIT_SOLICITATION_IDS = 0x15, /**< List of 128 bit service UUIDs the device is looking for. */
+ SERVICE_DATA = 0x16, /**< Service Data. */
+ APPEARANCE = 0x19, /**< Appearance, refer to GapAdvertisingData::Appearance_t. */
+ ADVERTISING_INTERVAL = 0x1A, /**< Advertising Interval. */
+ MANUFACTURER_SPECIFIC_DATA = 0xFF /**< Manufacturer Specific Data. */
+ };
+ /**
+ * Type alias for GapAdvertisingData::DataType_t.
+ *
+ * @deprecated This type alias will be dropped in future releases.
+ */
+ typedef enum DataType_t DataType;
+
+ /**
+ * @brief A list of values for the FLAGS AD Type.
+ *
+ * @note You can use more than one value in the FLAGS AD Type (ex.
+ * LE_GENERAL_DISCOVERABLE and BREDR_NOT_SUPPORTED).
+ *
+ * @par Source
+ *
+ * @li @c Bluetooth Core Specification 4.0 (Vol. 3), Part C, Section 18.1.
+ */
+ enum Flags_t {
+ LE_LIMITED_DISCOVERABLE = 0x01, /**< Peripheral device is discoverable for a limited period of time. */
+ LE_GENERAL_DISCOVERABLE = 0x02, /**< Peripheral device is discoverable at any moment. */
+ BREDR_NOT_SUPPORTED = 0x04, /**< Peripheral device is LE only. */
+ SIMULTANEOUS_LE_BREDR_C = 0x08, /**< Not relevant - central mode only. */
+ SIMULTANEOUS_LE_BREDR_H = 0x10 /**< Not relevant - central mode only. */
+ };
+ /**
+ * Type alias for GapAdvertisingData::Flags_t.
+ *
+ * @deprecated This type alias will be dropped in future releases.
+ */
+ typedef enum Flags_t Flags;
+
+ /**
+ * @brief
+ * A list of values for the APPEARANCE AD Type, which describes 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 = 0, /**< Unknown or unspecified appearance type. */
+ GENERIC_PHONE = 64, /**< Generic Phone. */
+ GENERIC_COMPUTER = 128, /**< Generic Computer. */
+ GENERIC_WATCH = 192, /**< Generic Watch. */
+ WATCH_SPORTS_WATCH = 193, /**< Sports Watch. */
+ GENERIC_CLOCK = 256, /**< Generic Clock. */
+ GENERIC_DISPLAY = 320, /**< Generic Display. */
+ GENERIC_REMOTE_CONTROL = 384, /**< Generic Remote Control. */
+ GENERIC_EYE_GLASSES = 448, /**< Generic Eye Glasses. */
+ GENERIC_TAG = 512, /**< Generic Tag. */
+ GENERIC_KEYRING = 576, /**< Generic Keyring. */
+ GENERIC_MEDIA_PLAYER = 640, /**< Generic Media Player. */
+ GENERIC_BARCODE_SCANNER = 704, /**< Generic Barcode Scanner. */
+ GENERIC_THERMOMETER = 768, /**< Generic Thermometer. */
+ THERMOMETER_EAR = 769, /**< Ear Thermometer. */
+ GENERIC_HEART_RATE_SENSOR = 832, /**< Generic Heart Rate Sensor. */
+ HEART_RATE_SENSOR_HEART_RATE_BELT = 833, /**< Belt Heart Rate Sensor. */
+ GENERIC_BLOOD_PRESSURE = 896, /**< Generic Blood Pressure. */
+ BLOOD_PRESSURE_ARM = 897, /**< Arm Blood Pressure. */
+ BLOOD_PRESSURE_WRIST = 898, /**< Wrist Blood Pressure. */
+ HUMAN_INTERFACE_DEVICE_HID = 960, /**< Human Interface Device (HID). */
+ KEYBOARD = 961, /**< Keyboard. */
+ MOUSE = 962, /**< Mouse. */
+ JOYSTICK = 963, /**< Joystick. */
+ GAMEPAD = 964, /**< Gamepad. */
+ DIGITIZER_TABLET = 965, /**< Digitizer Tablet. */
+ CARD_READER = 966, /**< Card Reader. */
+ DIGITAL_PEN = 967, /**< Digital Pen. */
+ BARCODE_SCANNER = 968, /**< Barcode Scanner. */
+ GENERIC_GLUCOSE_METER = 1024, /**< Generic Glucose Meter. */
+ GENERIC_RUNNING_WALKING_SENSOR = 1088, /**< Generic Running/Walking Sensor. */
+ RUNNING_WALKING_SENSOR_IN_SHOE = 1089, /**< In Shoe Running/Walking Sensor. */
+ RUNNING_WALKING_SENSOR_ON_SHOE = 1090, /**< On Shoe Running/Walking Sensor. */
+ RUNNING_WALKING_SENSOR_ON_HIP = 1091, /**< On Hip Running/Walking Sensor. */
+ GENERIC_CYCLING = 1152, /**< Generic Cycling. */
+ CYCLING_CYCLING_COMPUTER = 1153, /**< Cycling Computer. */
+ CYCLING_SPEED_SENSOR = 1154, /**< Cycling Speed Sensor. */
+ CYCLING_CADENCE_SENSOR = 1155, /**< Cycling Cadence Sensor. */
+ CYCLING_POWER_SENSOR = 1156, /**< Cycling Power Sensor. */
+ CYCLING_SPEED_AND_CADENCE_SENSOR = 1157, /**< Cycling Speed and Cadence Sensor. */
+ PULSE_OXIMETER_GENERIC = 3136, /**< Generic Pulse Oximeter. */
+ PULSE_OXIMETER_FINGERTIP = 3137, /**< Fingertip Pulse Oximeter. */
+ PULSE_OXIMETER_WRIST_WORN = 3138, /**< Wrist Worn Pulse Oximeter. */
+ GENERIC_WEIGHT_SCALE = 3200, /**< Generic Weight Scale. */
+ OUTDOOR_GENERIC = 5184, /**< Generic Outdoor. */
+ OUTDOOR_LOCATION_DISPLAY_DEVICE = 5185, /**< Outdoor Location Display Device. */
+ OUTDOOR_LOCATION_AND_NAVIGATION_DISPLAY_DEVICE = 5186, /**< Outdoor Location and Navigation Display Device. */
+ OUTDOOR_LOCATION_POD = 5187, /**< Outdoor Location Pod. */
+ OUTDOOR_LOCATION_AND_NAVIGATION_POD = 5188 /**< Outdoor Location and Navigation Pod. */
+ };
+ /**
+ * Type alias for GapAdvertisingData::Appearance_t.
+ *
+ * @deprecated This type alias will be dropped in future releases.
+ */
+ typedef enum Appearance_t Appearance;
+
+ /**
+ * Empty constructor.
+ */
+ GapAdvertisingData(void) : _payload(), _payloadLen(0), _appearance(GENERIC_TAG) {
+ /* empty */
+ }
+
+ /**
+ * Adds advertising data based on the specified AD type (see GapAdvertisingData::DataType_t).
+ * If the supplied AD type is already present in the advertising
+ * payload, then the value is updated.
+ *
+ * @param[in] advDataType The Advertising 'DataType' to add.
+ * @param[in] payload Pointer to the payload contents.
+ * @param[in] len Size of the payload in bytes.
+ *
+ * @return BLE_ERROR_BUFFER_OVERFLOW if the new value causes the
+ * advertising buffer to overflow. BLE_ERROR_NONE is returned
+ * on success.
+ *
+ * @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.
+ */
+ 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 exist, either add to field or replace */
+ return addField(advDataType, payload, len, field);
+ } else {
+ /* Field doesn't exists, insert new */
+ return appendField(advDataType, payload, len);
+ }
+ }
+
+ /**
+ * Update a particular ADV field in the advertising payload (based on
+ * matching type).
+ *
+ * @param[in] advDataType The Advertising 'DataType' to add.
+ * @param[in] payload Pointer to the payload contents.
+ * @param[in] len Size of the payload in bytes.
+ *
+ * @return BLE_ERROR_UNSPECIFIED if the specified field is not found,
+ * BLE_ERROR_BUFFER_OVERFLOW if the new value causes the
+ * advertising buffer to overflow. BLE_ERROR_NONE is returned
+ * on success.
+ */
+ 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 exist, replace field contents */
+ return updateField(advDataType, payload, len, field);
+ } else {
+ /* field doesn't exists, return an error */
+ return BLE_ERROR_UNSPECIFIED;
+ }
+ }
+
+ /**
+ * Helper function to add APPEARANCE data to the advertising payload.
+ *
+ * @param appearance
+ * The APPEARANCE value to add.
+ *
+ * @return BLE_ERROR_BUFFER_OVERFLOW if the specified data would cause the
+ * advertising buffer to overflow, else BLE_ERROR_NONE.
+ */
+ ble_error_t addAppearance(Appearance appearance = GENERIC_TAG) {
+ _appearance = appearance;
+ return addData(GapAdvertisingData::APPEARANCE, (uint8_t *)&appearance, 2);
+ }
+
+ /**
+ * Helper function to add FLAGS data to the advertising payload.
+ *
+ * @param[in] flags
+ * LE_LIMITED_DISCOVERABLE
+ * The peripheral is discoverable for a limited period of time.
+ * LE_GENERAL_DISCOVERABLE
+ * The peripheral is permanently discoverable.
+ * BREDR_NOT_SUPPORTED
+ * This peripheral is a Bluetooth Low Energy only device (no EDR support).
+ *
+ * @return BLE_ERROR_BUFFER_OVERFLOW if the specified data would cause the
+ * advertising buffer to overflow, else BLE_ERROR_NONE.
+ */
+ ble_error_t addFlags(uint8_t flags = LE_GENERAL_DISCOVERABLE) {
+ return addData(GapAdvertisingData::FLAGS, &flags, 1);
+ }
+
+ /**
+ * Helper function to add TX_POWER_LEVEL data to the advertising payload.
+ *
+ * @return BLE_ERROR_BUFFER_OVERFLOW if the specified data would cause the
+ * advertising buffer to overflow, else BLE_ERROR_NONE.
+ */
+ ble_error_t addTxPower(int8_t txPower) {
+ /* To Do: Basic error checking to make sure txPower is in range. */
+ return addData(GapAdvertisingData::TX_POWER_LEVEL, (uint8_t *)&txPower, 1);
+ }
+
+ /**
+ * Clears the payload and resets the payload length counter.
+ */
+ void clear(void) {
+ memset(&_payload, 0, GAP_ADVERTISING_DATA_MAX_PAYLOAD);
+ _payloadLen = 0;
+ }
+
+ /**
+ * Access the current payload.
+ *
+ * @return A pointer to the current payload.
+ */
+ const uint8_t *getPayload(void) const {
+ return _payload;
+ }
+
+ /**
+ * Get the current payload length.
+ *
+ * @return The current payload length (0..31 bytes).
+ */
+ uint8_t getPayloadLen(void) const {
+ return _payloadLen;
+ }
+
+ /**
+ * Get the current appearance value.
+ *
+ * @return The 16-bit appearance value for this device.
+ */
+ uint16_t getAppearance(void) const {
+ return (uint16_t)_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, NULL otherwise.
+ * Where the first element is the length of the field.
+ */
+ const uint8_t* findField(DataType_t type) const {
+ return findField(type);
+ }
+
+private:
+ /**
+ * Append advertising data based on the specified AD type (see
+ * GapAdvertisingData::DataType_t).
+ *
+ * @param[in] advDataType
+ * The type of the new data.
+ * @param[in] payload
+ * A pointer to the data to be appended to the advertising
+ * payload.
+ * @param[in] len
+ * The length of th data pointed to by @p payload.
+ *
+ * @return BLE_ERROR_BUFFER_OVERFLOW if the specified data would cause the
+ * advertising buffer to overflow, else BLE_ERROR_NONE.
+ */
+ 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(&_payload[_payloadLen], len + 1, 1);
+ _payloadLen++;
+
+ /* Field ID. */
+ memset(&_payload[_payloadLen], (uint8_t)advDataType, 1);
+ _payloadLen++;
+
+ /* Payload. */
+ memcpy(&_payload[_payloadLen], payload, len);
+ _payloadLen += len;
+
+ return BLE_ERROR_NONE;
+ }
+
+ /**
+ * Search advertisement data for field.
+ *
+ * @param[in] type
+ * The type of the data to find.
+ *
+ * @return A pointer to the first element in the field if found, NULL
+ * otherwise. Where the first element is the length of the field.
+ */
+ uint8_t* findField(DataType_t type) {
+ /* Scan through advertisement data */
+ for (uint8_t idx = 0; idx < _payloadLen; ) {
+ uint8_t fieldType = _payload[idx + 1];
+
+ if (fieldType == type) {
+ return &_payload[idx];
+ }
+
+ /* Advance to next field */
+ idx += _payload[idx] + 1;
+ }
+
+ /* Field not found */
+ return NULL;
+ }
+
+ /**
+ * Given the a pointer to a field in the advertising payload it replaces
+ * the existing data in the field with the supplied data.
+ *
+ * @param[in] advDataType
+ * The type of the new data.
+ * @param[in] payload
+ * A pointer to the data to be added to the advertising
+ * payload.
+ * @param[in] len
+ * The length of th data pointed to by @p payload.
+ * @param[in] field
+ * A pointer to the field of type @p advDataType in the
+ * advertising buffer.
+ *
+ * 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 will 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) <= GAP_ADVERTISING_DATA_MAX_PAYLOAD) {
+ /*
+ * Make room for new field by moving the remainder of the
+ * advertisement payload "to the right" starting after the
+ * TYPE field.
+ */
+ uint8_t* end = &_payload[_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 will be overwritten with the new value */
+ default: {
+ result = updateField(advDataType, payload, len, field);
+
+ break;
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Given the a pointer to a field in the advertising payload it replaces
+ * the existing data in the field with the supplied data.
+ *
+ * @param[in] advDataType
+ * The type of the data to be updated.
+ * @param[in] payload
+ * A pointer to the data to be updated to the advertising
+ * payload.
+ * @param[in] len
+ * The length of th data pointed to by @p payload.
+ * @param[in] field
+ * A 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) < &_payload[_payloadLen]) {
+ *field = field[dataLength + 2];
+ field++;
+ }
+
+ /* Reduce length */
+ _payloadLen -= dataLength + 2;
+
+ /* Add new field */
+ result = appendField(advDataType, payload, len);
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * The advertising data buffer
+ */
+ uint8_t _payload[GAP_ADVERTISING_DATA_MAX_PAYLOAD];
+ /**
+ * The length of the data added to the advertising buffer.
+ */
+ uint8_t _payloadLen;
+ /**
+ * Appearance value.
+ */
+ uint16_t _appearance;
+};
+
+#endif /* ifndef __GAP_ADVERTISING_DATA_H__ */