Updated

Fork of BLE_API by Bluetooth Low Energy

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers GapAdvertisingData.h Source File

GapAdvertisingData.h

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2006-2013 ARM Limited
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 #ifndef __GAP_ADVERTISING_DATA_H__
00018 #define __GAP_ADVERTISING_DATA_H__
00019 
00020 #include <stdint.h>
00021 #include <string.h>
00022 
00023 #include "blecommon.h"
00024 
00025 #define GAP_ADVERTISING_DATA_MAX_PAYLOAD        (31)
00026 
00027 /**************************************************************************/
00028 /*!
00029     \brief
00030     This class provides several helper functions to generate properly
00031     formatted GAP Advertising and Scan Response data payloads.
00032 
00033     \note
00034     See Bluetooth Specification 4.0 (Vol. 3), Part C, Sections 11 and 18
00035     for further information on Advertising and Scan Response data.
00036 
00037     \par Advertising and Scan Response Payloads
00038     Advertising data and Scan Response data are organized around a set of
00039     data types called 'AD types' in Bluetooth 4.0 (see the Bluetooth Core
00040     Specification v4.0, Vol. 3, Part C, Sections 11 and 18).
00041 
00042     \par
00043     Each AD type has its own standardized assigned number, as defined
00044     by the Bluetooth SIG:
00045     https://www.bluetooth.org/en-us/specification/assigned-numbers/generic-access-profile
00046 
00047     \par
00048     For convenience, all appropriate AD types are encapsulated
00049     in GapAdvertisingData::DataType.
00050 
00051     \par
00052     Before the AD Types and their payload (if any) can be inserted into
00053     the Advertising or Scan Response frames, they need to be formatted as
00054     follows:
00055 
00056     \li \c Record length (1 byte).
00057     \li \c AD Type (1 byte).
00058     \li \c AD payload (optional; only present if record length > 1).
00059 
00060     \par
00061     This class takes care of properly formatting the payload, performs
00062     some basic checks on the payload length, and tries to avoid common
00063     errors like adding an exclusive AD field twice in the Advertising
00064     or Scan Response payload.
00065 
00066     \par EXAMPLE
00067 
00068     \code
00069 
00070     // ToDo
00071 
00072     \endcode
00073 */
00074 /**************************************************************************/
00075 class GapAdvertisingData
00076 {
00077 public:
00078     /**********************************************************************/
00079     /*!
00080         \brief
00081         A list of Advertising Data types commonly used by peripherals.
00082         These AD types are used to describe the capabilities of the
00083         peripheral, and are inserted inside the advertising or scan
00084         response payloads.
00085 
00086         \par Source
00087         \li \c Bluetooth Core Specification 4.0 (Vol. 3), Part C, Section 11, 18
00088         \li \c https://www.bluetooth.org/en-us/specification/assigned-numbers/generic-access-profile
00089     */
00090     /**********************************************************************/
00091     enum DataType_t {
00092         FLAGS                              = 0x01, /**< \ref *Flags */
00093         INCOMPLETE_LIST_16BIT_SERVICE_IDS  = 0x02, /**< Incomplete list of 16-bit Service IDs */
00094         COMPLETE_LIST_16BIT_SERVICE_IDS    = 0x03, /**< Complete list of 16-bit Service IDs */
00095         INCOMPLETE_LIST_32BIT_SERVICE_IDS  = 0x04, /**< Incomplete list of 32-bit Service IDs (not relevant for Bluetooth 4.0) */
00096         COMPLETE_LIST_32BIT_SERVICE_IDS    = 0x05, /**< Complete list of 32-bit Service IDs (not relevant for Bluetooth 4.0) */
00097         INCOMPLETE_LIST_128BIT_SERVICE_IDS = 0x06, /**< Incomplete list of 128-bit Service IDs */
00098         COMPLETE_LIST_128BIT_SERVICE_IDS   = 0x07, /**< Complete list of 128-bit Service IDs */
00099         SHORTENED_LOCAL_NAME               = 0x08, /**< Shortened Local Name */
00100         COMPLETE_LOCAL_NAME                = 0x09, /**< Complete Local Name */
00101         TX_POWER_LEVEL                     = 0x0A, /**< TX Power Level (in dBm) */
00102         DEVICE_ID                          = 0x10, /**< Device ID */
00103         SLAVE_CONNECTION_INTERVAL_RANGE    = 0x12, /**< Slave Connection Interval Range */
00104         LIST_128BIT_SOLICITATION_IDS       = 0x15, /**< List of 128 bit service UUIDs the device is looking for */
00105         SERVICE_DATA                       = 0x16, /**< Service Data */
00106         APPEARANCE                         = 0x19, /**< \ref Appearance */
00107         ADVERTISING_INTERVAL               = 0x1A, /**< Advertising Interval */
00108         MANUFACTURER_SPECIFIC_DATA         = 0xFF  /**< Manufacturer Specific Data */
00109     };
00110     typedef enum DataType_t DataType; /* Deprecated type alias. This may be dropped in a future release. */
00111 
00112     /**********************************************************************/
00113     /*!
00114         \brief
00115         A list of values for the FLAGS AD Type.
00116 
00117         \note
00118         You can use more than one value in the FLAGS AD Type (ex.
00119         LE_GENERAL_DISCOVERABLE and BREDR_NOT_SUPPORTED).
00120 
00121         \par Source
00122         \li \c Bluetooth Core Specification 4.0 (Vol. 3), Part C, Section 18.1
00123     */
00124     /**********************************************************************/
00125     enum Flags_t {
00126         LE_LIMITED_DISCOVERABLE = 0x01, /**< *Peripheral device is discoverable for a limited period of time. */
00127         LE_GENERAL_DISCOVERABLE = 0x02, /**< Peripheral device is discoverable at any moment. */
00128         BREDR_NOT_SUPPORTED     = 0x04, /**< Peripheral device is LE only. */
00129         SIMULTANEOUS_LE_BREDR_C = 0x08, /**< Not relevant - central mode only. */
00130         SIMULTANEOUS_LE_BREDR_H = 0x10  /**< Not relevant - central mode only. */
00131     };
00132     typedef enum Flags_t Flags; /* Deprecated type alias. This may be dropped in a future release. */
00133 
00134     /**********************************************************************/
00135     /*!
00136         \brief
00137         A list of values for the APPEARANCE AD Type, which describes the
00138         physical shape or appearance of the device.
00139 
00140         \par Source
00141         \li \c Bluetooth Core Specification Supplement, Part A, Section 1.12
00142         \li \c Bluetooth Core Specification 4.0 (Vol. 3), Part C, Section 12.2
00143         \li \c https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.gap.appearance.xml
00144     */
00145     /**********************************************************************/
00146     enum Appearance_t {
00147         UNKNOWN                                        = 0,     /**< Unknown or unspecified appearance type. */
00148         GENERIC_PHONE                                  = 64,    /**< Generic Phone. */
00149         GENERIC_COMPUTER                               = 128,   /**< Generic Computer. */
00150         GENERIC_WATCH                                  = 192,   /**< Generic Watch. */
00151         WATCH_SPORTS_WATCH                             = 193,   /**< Sports Watch. */
00152         GENERIC_CLOCK                                  = 256,   /**< Generic Clock. */
00153         GENERIC_DISPLAY                                = 320,   /**< Generic Display. */
00154         GENERIC_REMOTE_CONTROL                         = 384,   /**< Generic Remote Control. */
00155         GENERIC_EYE_GLASSES                            = 448,   /**< Generic Eye Glasses. */
00156         GENERIC_TAG                                    = 512,   /**< Generic Tag. */
00157         GENERIC_KEYRING                                = 576,   /**< Generic Keyring. */
00158         GENERIC_MEDIA_PLAYER                           = 640,   /**< Generic Media Player. */
00159         GENERIC_BARCODE_SCANNER                        = 704,   /**< Generic Barcode Scanner. */
00160         GENERIC_THERMOMETER                            = 768,   /**< Generic Thermometer. */
00161         THERMOMETER_EAR                                = 769,   /**< Ear Thermometer. */
00162         GENERIC_HEART_RATE_SENSOR                      = 832,   /**< Generic Heart Rate Sensor. */
00163         HEART_RATE_SENSOR_HEART_RATE_BELT              = 833,   /**< Belt Heart Rate Sensor. */
00164         GENERIC_BLOOD_PRESSURE                         = 896,   /**< Generic Blood Pressure. */
00165         BLOOD_PRESSURE_ARM                             = 897,   /**< Arm Blood Pressure. */
00166         BLOOD_PRESSURE_WRIST                           = 898,   /**< Wrist Blood Pressure. */
00167         HUMAN_INTERFACE_DEVICE_HID                     = 960,   /**< Human Interface Device (HID). */
00168         KEYBOARD                                       = 961,   /**< Keyboard. */
00169         MOUSE                                          = 962,   /**< Mouse. */
00170         JOYSTICK                                       = 963,   /**< Joystick. */
00171         GAMEPAD                                        = 964,   /**< Gamepad. */
00172         DIGITIZER_TABLET                               = 965,   /**< Digitizer Tablet. */
00173         CARD_READER                                    = 966,   /**< Card Reader. */
00174         DIGITAL_PEN                                    = 967,   /**< Digital Pen. */
00175         BARCODE_SCANNER                                = 968,   /**< Barcode Scanner. */
00176         GENERIC_GLUCOSE_METER                          = 1024,  /**< Generic Glucose Meter. */
00177         GENERIC_RUNNING_WALKING_SENSOR                 = 1088,  /**< Generic Running/Walking Sensor. */
00178         RUNNING_WALKING_SENSOR_IN_SHOE                 = 1089,  /**< In Shoe Running/Walking Sensor. */
00179         RUNNING_WALKING_SENSOR_ON_SHOE                 = 1090,  /**< On Shoe Running/Walking Sensor. */
00180         RUNNING_WALKING_SENSOR_ON_HIP                  = 1091,  /**< On Hip Running/Walking Sensor. */
00181         GENERIC_CYCLING                                = 1152,  /**< Generic Cycling. */
00182         CYCLING_CYCLING_COMPUTER                       = 1153,  /**< Cycling Computer. */
00183         CYCLING_SPEED_SENSOR                           = 1154,  /**< Cycling Speed Sensor. */
00184         CYCLING_CADENCE_SENSOR                         = 1155,  /**< Cycling Cadence Sensor. */
00185         CYCLING_POWER_SENSOR                           = 1156,  /**< Cycling Power Sensor. */
00186         CYCLING_SPEED_AND_CADENCE_SENSOR               = 1157,  /**< Cycling Speed and Cadence Sensor. */
00187         PULSE_OXIMETER_GENERIC                         = 3136,  /**< Generic Pulse Oximeter. */
00188         PULSE_OXIMETER_FINGERTIP                       = 3137,  /**< Fingertip Pulse Oximeter. */
00189         PULSE_OXIMETER_WRIST_WORN                      = 3138,  /**< Wrist Worn Pulse Oximeter. */
00190         OUTDOOR_GENERIC                                = 5184,  /**< Generic Outdoor. */
00191         OUTDOOR_LOCATION_DISPLAY_DEVICE                = 5185,  /**< Outdoor Location Display Device. */
00192         OUTDOOR_LOCATION_AND_NAVIGATION_DISPLAY_DEVICE = 5186,  /**< Outdoor Location and Navigation Display Device. */
00193         OUTDOOR_LOCATION_POD                           = 5187,  /**< Outdoor Location Pod. */
00194         OUTDOOR_LOCATION_AND_NAVIGATION_POD            = 5188   /**< Outdoor Location and Navigation Pod. */
00195     };
00196     typedef enum Appearance_t Appearance; /* Deprecated type alias. This may be dropped in a future release. */
00197 
00198     GapAdvertisingData(void) : _payload(), _payloadLen(0), _appearance(GENERIC_TAG) {
00199         /* empty */
00200     }
00201 
00202     /**
00203      * Adds advertising data based on the specified AD type (see DataType).
00204      *
00205      * @param  advDataType The Advertising 'DataType' to add.
00206      * @param  payload     Pointer to the payload contents.
00207      * @param  len         Size of the payload in bytes.
00208      *
00209      * @return BLE_ERROR_BUFFER_OVERFLOW if the specified data would cause the
00210      * advertising buffer to overflow, else BLE_ERROR_NONE.
00211      */
00212     ble_error_t addData(DataType advDataType, const uint8_t *payload, uint8_t len)
00213     {
00214         ble_error_t result = BLE_ERROR_BUFFER_OVERFLOW;
00215 
00216         // find field
00217         uint8_t* field = findField(advDataType);
00218 
00219         // Field type already exist, either add to field or replace
00220         if (field) {
00221             switch(advDataType) {
00222                 //  These fields will be overwritten with the new value
00223                 case FLAGS:
00224                 case SHORTENED_LOCAL_NAME:
00225                 case COMPLETE_LOCAL_NAME:
00226                 case TX_POWER_LEVEL:
00227                 case DEVICE_ID:
00228                 case SLAVE_CONNECTION_INTERVAL_RANGE:
00229                 case SERVICE_DATA:
00230                 case APPEARANCE:
00231                 case ADVERTISING_INTERVAL:
00232                 case MANUFACTURER_SPECIFIC_DATA: {
00233                     // current field length, with the type subtracted
00234                     uint8_t dataLength = field[0] - 1;
00235 
00236                     // new data has same length, do in-order replacement
00237                     if (len == dataLength) {
00238                         for (uint8_t idx = 0; idx < dataLength; idx++) {
00239                             field[2 + idx] = payload[idx];
00240                         }
00241                     } else {
00242                         // check if data fits
00243                         if ((_payloadLen - dataLength + len) <= GAP_ADVERTISING_DATA_MAX_PAYLOAD) {
00244 
00245                             // remove old field
00246                             while ((field + dataLength + 2) < &_payload[_payloadLen]) {
00247                                 *field = field[dataLength + 2];
00248                                 field++;
00249                             }
00250 
00251                             // reduce length
00252                             _payloadLen -= dataLength + 2;
00253 
00254                             // add new field
00255                             result = appendField(advDataType, payload, len);
00256                         }
00257                     }
00258 
00259                     break;
00260                 }
00261                 // These fields will have the new data appended if there is sufficient space
00262                 case INCOMPLETE_LIST_16BIT_SERVICE_IDS:
00263                 case COMPLETE_LIST_16BIT_SERVICE_IDS:
00264                 case INCOMPLETE_LIST_32BIT_SERVICE_IDS:
00265                 case COMPLETE_LIST_32BIT_SERVICE_IDS:
00266                 case INCOMPLETE_LIST_128BIT_SERVICE_IDS:
00267                 case COMPLETE_LIST_128BIT_SERVICE_IDS:
00268                 case LIST_128BIT_SOLICITATION_IDS: {
00269                     // check if data fits
00270                     if ((_payloadLen + len) <= GAP_ADVERTISING_DATA_MAX_PAYLOAD) {
00271                         // make room for new field by moving the remainder of the
00272                         // advertisement payload "to the right" starting after the
00273                         // TYPE field.
00274                         uint8_t* end = &_payload[_payloadLen];
00275 
00276                         while (&field[1] < end) {
00277                             end[len] = *end;
00278                             end--;
00279                         }
00280 
00281                         // insert new data
00282                         for (uint8_t idx = 0; idx < len; idx++) {
00283                             field[2 + idx] = payload[idx];
00284                         }
00285 
00286                         // increment lengths
00287                         field[0] += len;
00288                         _payloadLen += len;
00289 
00290                         result = BLE_ERROR_NONE;
00291                     }
00292 
00293                     break;
00294                 }
00295                 // Field exists but updating it is not supported. Abort operation.
00296                 default:
00297                     result = BLE_ERROR_NOT_IMPLEMENTED;
00298                     break;
00299             }
00300         } else {
00301             // field doesn't exists, insert new
00302             result = appendField(advDataType, payload, len);
00303         }
00304 
00305         return result;
00306     }
00307 
00308     /**
00309      * Update a particular ADV field in the advertising payload (based on
00310      * matching type and length). Note: the length of the new data must be the
00311      * same as the old one.
00312      *
00313      * @param[in] advDataType  The Advertising 'DataType' to add.
00314      * @param[in] payload      Pointer to the payload contents.
00315      * @param[in] len          Size of the payload in bytes.
00316      *
00317      * @return BLE_ERROR_UNSPECIFIED if the specified field is not found, else
00318      * BLE_ERROR_NONE.
00319      */
00320     ble_error_t updateData(DataType_t advDataType, const uint8_t *payload, uint8_t len)
00321     {
00322         if ((payload == NULL) || (len == 0)) {
00323             return BLE_ERROR_INVALID_PARAM;
00324         }
00325 
00326         /* A local struct to describe an ADV field. This definition comes from the Bluetooth Core Spec. (v4.2) Part C, Section 11. */
00327         struct ADVField_t {
00328             uint8_t  len;      /* Describes the length (in bytes) of the following type and bytes. */
00329             uint8_t  type;     /* Should have the same representation of DataType_t (above). */
00330             uint8_t  bytes[0]; /* A placeholder for variable length data. */
00331         };
00332 
00333         /* Iterate over the adv fields looking for the first match. */
00334         uint8_t byteIndex = 0;
00335         while (byteIndex < _payloadLen) {
00336             ADVField_t *currentADV = (ADVField_t *)&_payload[byteIndex];
00337             if ((currentADV->len  == (len + 1)) && /* Incoming len only describes the payload, whereas ADV->len describes [type + payload]. */
00338                 (currentADV->type == advDataType)) {
00339                 memcpy(currentADV->bytes, payload, len);
00340                 return BLE_ERROR_NONE;
00341             }
00342 
00343             byteIndex += (currentADV->len + 1); /* Advance by len+1; '+1' is needed to span the len field itself. */
00344         }
00345 
00346         return BLE_ERROR_UNSPECIFIED;
00347     }
00348 
00349     /**
00350      * Helper function to add APPEARANCE data to the advertising payload.
00351      *
00352      * @param  appearance
00353      *           The APPEARANCE value to add.
00354      *
00355      * @return BLE_ERROR_BUFFER_OVERFLOW if the specified data would cause the
00356      * advertising buffer to overflow, else BLE_ERROR_NONE.
00357      */
00358     ble_error_t addAppearance(Appearance appearance = GENERIC_TAG) {
00359         _appearance = appearance;
00360         return addData(GapAdvertisingData::APPEARANCE, (uint8_t *)&appearance, 2);
00361     }
00362 
00363     /**
00364      * Helper function to add FLAGS data to the advertising payload.
00365      * @param  flags
00366      *           LE_LIMITED_DISCOVERABLE
00367      *             The peripheral is discoverable for a limited period of time.
00368      *           LE_GENERAL_DISCOVERABLE
00369      *             The peripheral is permanently discoverable.
00370      *           BREDR_NOT_SUPPORTED
00371      *             This peripheral is a Bluetooth Low Energy only device (no EDR support).
00372      *
00373      * @return BLE_ERROR_BUFFER_OVERFLOW if the specified data would cause the
00374      * advertising buffer to overflow, else BLE_ERROR_NONE.
00375      */
00376     ble_error_t addFlags(uint8_t flags = LE_GENERAL_DISCOVERABLE) {
00377         return addData(GapAdvertisingData::FLAGS, &flags, 1);
00378     }
00379 
00380     /**
00381      * Helper function to add TX_POWER_LEVEL data to the advertising payload.
00382      *
00383      * @return BLE_ERROR_BUFFER_OVERFLOW if the specified data would cause the
00384      * advertising buffer to overflow, else BLE_ERROR_NONE.
00385      */
00386     ble_error_t addTxPower(int8_t txPower) {
00387         /* To Do: Basic error checking to make sure txPower is in range. */
00388         return addData(GapAdvertisingData::TX_POWER_LEVEL, (uint8_t *)&txPower, 1);
00389     }
00390 
00391     /**
00392      * Clears the payload and resets the payload length counter.
00393      */
00394     void        clear(void) {
00395         memset(&_payload, 0, GAP_ADVERTISING_DATA_MAX_PAYLOAD);
00396         _payloadLen = 0;
00397     }
00398 
00399     /**
00400      * Returns a pointer to the current payload.
00401      */
00402     const uint8_t *getPayload(void) const {
00403         return _payload;
00404     }
00405 
00406     /**
00407      * Returns the current payload length (0..31 bytes).
00408      */
00409     uint8_t     getPayloadLen(void) const {
00410         return _payloadLen;
00411     }
00412 
00413     /**
00414      * Returns the 16-bit appearance value for this device.
00415      */
00416     uint16_t    getAppearance(void) const {
00417         return (uint16_t)_appearance;
00418     }
00419 
00420     /**
00421      * Search advertisement data for field.
00422      * Returns pointer to the first element in the field if found, NULL otherwise.
00423      * Where the first element is the length of the field.
00424      */
00425     const uint8_t* findField(DataType_t type) const {
00426         return findField(type);
00427     }
00428 
00429 private:
00430     /**
00431      * Append advertising data based on the specified AD type (see DataType)
00432      */
00433     ble_error_t appendField(DataType advDataType, const uint8_t *payload, uint8_t len)
00434     {
00435         /* Make sure we don't exceed the 31 byte payload limit */
00436         if (_payloadLen + len + 2 > GAP_ADVERTISING_DATA_MAX_PAYLOAD) {
00437             return BLE_ERROR_BUFFER_OVERFLOW;
00438         }
00439 
00440         /* Field length. */
00441         memset(&_payload[_payloadLen], len + 1, 1);
00442         _payloadLen++;
00443 
00444         /* Field ID. */
00445         memset(&_payload[_payloadLen], (uint8_t)advDataType, 1);
00446         _payloadLen++;
00447 
00448         /* Payload. */
00449         memcpy(&_payload[_payloadLen], payload, len);
00450         _payloadLen += len;
00451 
00452         return BLE_ERROR_NONE;
00453     }
00454 
00455     /**
00456      * Search advertisement data for field.
00457      * Returns pointer to the first element in the field if found, NULL otherwise.
00458      * Where the first element is the length of the field.
00459      */
00460     uint8_t* findField(DataType_t type) {
00461         // scan through advertisement data
00462         for (uint8_t idx = 0; idx < _payloadLen; ) {
00463             uint8_t fieldType = _payload[idx + 1];
00464 
00465             if (fieldType == type) {
00466                 return &_payload[idx];
00467             }
00468 
00469             // advance to next field
00470             idx += _payload[idx] + 1;
00471         }
00472 
00473         // field not found
00474         return NULL;
00475     }
00476 
00477     uint8_t  _payload[GAP_ADVERTISING_DATA_MAX_PAYLOAD];
00478     uint8_t  _payloadLen;
00479     uint16_t _appearance;
00480 };
00481 
00482 #endif // ifndef __GAP_ADVERTISING_DATA_H__