Updated

Fork of BLE_API by Bluetooth Low Energy

Committer:
vbahl2
Date:
Tue May 09 03:03:23 2017 +0000
Revision:
1210:1f56dc951637
Parent:
993:4d62b7967c11
Child:
1042:21a86ac7f5b1
j

Who changed what in which revision?

UserRevisionLine numberNew contents of line
rgrover1 710:b2e1a2660ec2 1 /* mbed Microcontroller Library
rgrover1 710:b2e1a2660ec2 2 * Copyright (c) 2006-2013 ARM Limited
rgrover1 710:b2e1a2660ec2 3 *
rgrover1 710:b2e1a2660ec2 4 * Licensed under the Apache License, Version 2.0 (the "License");
rgrover1 710:b2e1a2660ec2 5 * you may not use this file except in compliance with the License.
rgrover1 710:b2e1a2660ec2 6 * You may obtain a copy of the License at
rgrover1 710:b2e1a2660ec2 7 *
rgrover1 710:b2e1a2660ec2 8 * http://www.apache.org/licenses/LICENSE-2.0
rgrover1 710:b2e1a2660ec2 9 *
rgrover1 710:b2e1a2660ec2 10 * Unless required by applicable law or agreed to in writing, software
rgrover1 710:b2e1a2660ec2 11 * distributed under the License is distributed on an "AS IS" BASIS,
rgrover1 710:b2e1a2660ec2 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
rgrover1 710:b2e1a2660ec2 13 * See the License for the specific language governing permissions and
rgrover1 710:b2e1a2660ec2 14 * limitations under the License.
rgrover1 710:b2e1a2660ec2 15 */
rgrover1 710:b2e1a2660ec2 16
rgrover1 710:b2e1a2660ec2 17 #ifndef __GAP_ADVERTISING_DATA_H__
rgrover1 710:b2e1a2660ec2 18 #define __GAP_ADVERTISING_DATA_H__
rgrover1 710:b2e1a2660ec2 19
rgrover1 710:b2e1a2660ec2 20 #include <stdint.h>
rgrover1 710:b2e1a2660ec2 21 #include <string.h>
rgrover1 710:b2e1a2660ec2 22
rgrover1 710:b2e1a2660ec2 23 #include "blecommon.h"
rgrover1 710:b2e1a2660ec2 24
rgrover1 710:b2e1a2660ec2 25 #define GAP_ADVERTISING_DATA_MAX_PAYLOAD (31)
rgrover1 710:b2e1a2660ec2 26
rgrover1 710:b2e1a2660ec2 27 /**************************************************************************/
rgrover1 710:b2e1a2660ec2 28 /*!
rgrover1 710:b2e1a2660ec2 29 \brief
rgrover1 710:b2e1a2660ec2 30 This class provides several helper functions to generate properly
rgrover1 993:4d62b7967c11 31 formatted GAP Advertising and Scan Response data payloads.
rgrover1 710:b2e1a2660ec2 32
rgrover1 710:b2e1a2660ec2 33 \note
rgrover1 993:4d62b7967c11 34 See Bluetooth Specification 4.0 (Vol. 3), Part C, Sections 11 and 18
rgrover1 710:b2e1a2660ec2 35 for further information on Advertising and Scan Response data.
rgrover1 710:b2e1a2660ec2 36
rgrover1 710:b2e1a2660ec2 37 \par Advertising and Scan Response Payloads
rgrover1 710:b2e1a2660ec2 38 Advertising data and Scan Response data are organized around a set of
rgrover1 710:b2e1a2660ec2 39 data types called 'AD types' in Bluetooth 4.0 (see the Bluetooth Core
rgrover1 710:b2e1a2660ec2 40 Specification v4.0, Vol. 3, Part C, Sections 11 and 18).
rgrover1 710:b2e1a2660ec2 41
rgrover1 710:b2e1a2660ec2 42 \par
rgrover1 993:4d62b7967c11 43 Each AD type has its own standardized assigned number, as defined
rgrover1 710:b2e1a2660ec2 44 by the Bluetooth SIG:
rgrover1 710:b2e1a2660ec2 45 https://www.bluetooth.org/en-us/specification/assigned-numbers/generic-access-profile
rgrover1 710:b2e1a2660ec2 46
rgrover1 710:b2e1a2660ec2 47 \par
rgrover1 993:4d62b7967c11 48 For convenience, all appropriate AD types are encapsulated
rgrover1 993:4d62b7967c11 49 in GapAdvertisingData::DataType.
rgrover1 710:b2e1a2660ec2 50
rgrover1 710:b2e1a2660ec2 51 \par
rgrover1 710:b2e1a2660ec2 52 Before the AD Types and their payload (if any) can be inserted into
rgrover1 710:b2e1a2660ec2 53 the Advertising or Scan Response frames, they need to be formatted as
rgrover1 710:b2e1a2660ec2 54 follows:
rgrover1 710:b2e1a2660ec2 55
rgrover1 993:4d62b7967c11 56 \li \c Record length (1 byte).
rgrover1 993:4d62b7967c11 57 \li \c AD Type (1 byte).
rgrover1 993:4d62b7967c11 58 \li \c AD payload (optional; only present if record length > 1).
rgrover1 710:b2e1a2660ec2 59
rgrover1 710:b2e1a2660ec2 60 \par
rgrover1 710:b2e1a2660ec2 61 This class takes care of properly formatting the payload, performs
rgrover1 710:b2e1a2660ec2 62 some basic checks on the payload length, and tries to avoid common
rgrover1 710:b2e1a2660ec2 63 errors like adding an exclusive AD field twice in the Advertising
rgrover1 710:b2e1a2660ec2 64 or Scan Response payload.
rgrover1 710:b2e1a2660ec2 65
rgrover1 710:b2e1a2660ec2 66 \par EXAMPLE
rgrover1 710:b2e1a2660ec2 67
rgrover1 710:b2e1a2660ec2 68 \code
rgrover1 710:b2e1a2660ec2 69
rgrover1 710:b2e1a2660ec2 70 // ToDo
rgrover1 710:b2e1a2660ec2 71
rgrover1 710:b2e1a2660ec2 72 \endcode
rgrover1 710:b2e1a2660ec2 73 */
rgrover1 710:b2e1a2660ec2 74 /**************************************************************************/
rgrover1 710:b2e1a2660ec2 75 class GapAdvertisingData
rgrover1 710:b2e1a2660ec2 76 {
rgrover1 710:b2e1a2660ec2 77 public:
rgrover1 710:b2e1a2660ec2 78 /**********************************************************************/
rgrover1 710:b2e1a2660ec2 79 /*!
rgrover1 710:b2e1a2660ec2 80 \brief
rgrover1 710:b2e1a2660ec2 81 A list of Advertising Data types commonly used by peripherals.
rgrover1 710:b2e1a2660ec2 82 These AD types are used to describe the capabilities of the
rgrover1 993:4d62b7967c11 83 peripheral, and are inserted inside the advertising or scan
rgrover1 710:b2e1a2660ec2 84 response payloads.
rgrover1 710:b2e1a2660ec2 85
rgrover1 710:b2e1a2660ec2 86 \par Source
rgrover1 710:b2e1a2660ec2 87 \li \c Bluetooth Core Specification 4.0 (Vol. 3), Part C, Section 11, 18
rgrover1 710:b2e1a2660ec2 88 \li \c https://www.bluetooth.org/en-us/specification/assigned-numbers/generic-access-profile
rgrover1 710:b2e1a2660ec2 89 */
rgrover1 710:b2e1a2660ec2 90 /**********************************************************************/
rgrover1 756:503c4bd89a3d 91 enum DataType_t {
rgrover1 970:b3e45745026d 92 FLAGS = 0x01, /**< \ref *Flags */
rgrover1 970:b3e45745026d 93 INCOMPLETE_LIST_16BIT_SERVICE_IDS = 0x02, /**< Incomplete list of 16-bit Service IDs */
rgrover1 970:b3e45745026d 94 COMPLETE_LIST_16BIT_SERVICE_IDS = 0x03, /**< Complete list of 16-bit Service IDs */
rgrover1 970:b3e45745026d 95 INCOMPLETE_LIST_32BIT_SERVICE_IDS = 0x04, /**< Incomplete list of 32-bit Service IDs (not relevant for Bluetooth 4.0) */
rgrover1 970:b3e45745026d 96 COMPLETE_LIST_32BIT_SERVICE_IDS = 0x05, /**< Complete list of 32-bit Service IDs (not relevant for Bluetooth 4.0) */
rgrover1 970:b3e45745026d 97 INCOMPLETE_LIST_128BIT_SERVICE_IDS = 0x06, /**< Incomplete list of 128-bit Service IDs */
rgrover1 970:b3e45745026d 98 COMPLETE_LIST_128BIT_SERVICE_IDS = 0x07, /**< Complete list of 128-bit Service IDs */
rgrover1 970:b3e45745026d 99 SHORTENED_LOCAL_NAME = 0x08, /**< Shortened Local Name */
rgrover1 970:b3e45745026d 100 COMPLETE_LOCAL_NAME = 0x09, /**< Complete Local Name */
rgrover1 970:b3e45745026d 101 TX_POWER_LEVEL = 0x0A, /**< TX Power Level (in dBm) */
rgrover1 970:b3e45745026d 102 DEVICE_ID = 0x10, /**< Device ID */
rgrover1 970:b3e45745026d 103 SLAVE_CONNECTION_INTERVAL_RANGE = 0x12, /**< Slave Connection Interval Range */
rgrover1 993:4d62b7967c11 104 LIST_128BIT_SOLICITATION_IDS = 0x15, /**< List of 128 bit service UUIDs the device is looking for */
rgrover1 970:b3e45745026d 105 SERVICE_DATA = 0x16, /**< Service Data */
rgrover1 970:b3e45745026d 106 APPEARANCE = 0x19, /**< \ref Appearance */
rgrover1 970:b3e45745026d 107 ADVERTISING_INTERVAL = 0x1A, /**< Advertising Interval */
rgrover1 970:b3e45745026d 108 MANUFACTURER_SPECIFIC_DATA = 0xFF /**< Manufacturer Specific Data */
rgrover1 710:b2e1a2660ec2 109 };
rgrover1 756:503c4bd89a3d 110 typedef enum DataType_t DataType; /* Deprecated type alias. This may be dropped in a future release. */
rgrover1 710:b2e1a2660ec2 111
rgrover1 710:b2e1a2660ec2 112 /**********************************************************************/
rgrover1 710:b2e1a2660ec2 113 /*!
rgrover1 710:b2e1a2660ec2 114 \brief
rgrover1 993:4d62b7967c11 115 A list of values for the FLAGS AD Type.
rgrover1 710:b2e1a2660ec2 116
rgrover1 710:b2e1a2660ec2 117 \note
rgrover1 710:b2e1a2660ec2 118 You can use more than one value in the FLAGS AD Type (ex.
rgrover1 710:b2e1a2660ec2 119 LE_GENERAL_DISCOVERABLE and BREDR_NOT_SUPPORTED).
rgrover1 710:b2e1a2660ec2 120
rgrover1 710:b2e1a2660ec2 121 \par Source
rgrover1 710:b2e1a2660ec2 122 \li \c Bluetooth Core Specification 4.0 (Vol. 3), Part C, Section 18.1
rgrover1 710:b2e1a2660ec2 123 */
rgrover1 710:b2e1a2660ec2 124 /**********************************************************************/
rgrover1 756:503c4bd89a3d 125 enum Flags_t {
rgrover1 993:4d62b7967c11 126 LE_LIMITED_DISCOVERABLE = 0x01, /**< *Peripheral device is discoverable for a limited period of time. */
rgrover1 993:4d62b7967c11 127 LE_GENERAL_DISCOVERABLE = 0x02, /**< Peripheral device is discoverable at any moment. */
rgrover1 993:4d62b7967c11 128 BREDR_NOT_SUPPORTED = 0x04, /**< Peripheral device is LE only. */
rgrover1 993:4d62b7967c11 129 SIMULTANEOUS_LE_BREDR_C = 0x08, /**< Not relevant - central mode only. */
rgrover1 993:4d62b7967c11 130 SIMULTANEOUS_LE_BREDR_H = 0x10 /**< Not relevant - central mode only. */
rgrover1 710:b2e1a2660ec2 131 };
rgrover1 756:503c4bd89a3d 132 typedef enum Flags_t Flags; /* Deprecated type alias. This may be dropped in a future release. */
rgrover1 710:b2e1a2660ec2 133
rgrover1 710:b2e1a2660ec2 134 /**********************************************************************/
rgrover1 710:b2e1a2660ec2 135 /*!
rgrover1 710:b2e1a2660ec2 136 \brief
rgrover1 710:b2e1a2660ec2 137 A list of values for the APPEARANCE AD Type, which describes the
rgrover1 993:4d62b7967c11 138 physical shape or appearance of the device.
rgrover1 710:b2e1a2660ec2 139
rgrover1 710:b2e1a2660ec2 140 \par Source
rgrover1 710:b2e1a2660ec2 141 \li \c Bluetooth Core Specification Supplement, Part A, Section 1.12
rgrover1 710:b2e1a2660ec2 142 \li \c Bluetooth Core Specification 4.0 (Vol. 3), Part C, Section 12.2
rgrover1 710:b2e1a2660ec2 143 \li \c https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.gap.appearance.xml
rgrover1 710:b2e1a2660ec2 144 */
rgrover1 710:b2e1a2660ec2 145 /**********************************************************************/
rgrover1 756:503c4bd89a3d 146 enum Appearance_t {
rgrover1 993:4d62b7967c11 147 UNKNOWN = 0, /**< Unknown or unspecified appearance type. */
rgrover1 993:4d62b7967c11 148 GENERIC_PHONE = 64, /**< Generic Phone. */
rgrover1 993:4d62b7967c11 149 GENERIC_COMPUTER = 128, /**< Generic Computer. */
rgrover1 993:4d62b7967c11 150 GENERIC_WATCH = 192, /**< Generic Watch. */
rgrover1 993:4d62b7967c11 151 WATCH_SPORTS_WATCH = 193, /**< Sports Watch. */
rgrover1 993:4d62b7967c11 152 GENERIC_CLOCK = 256, /**< Generic Clock. */
rgrover1 993:4d62b7967c11 153 GENERIC_DISPLAY = 320, /**< Generic Display. */
rgrover1 993:4d62b7967c11 154 GENERIC_REMOTE_CONTROL = 384, /**< Generic Remote Control. */
rgrover1 993:4d62b7967c11 155 GENERIC_EYE_GLASSES = 448, /**< Generic Eye Glasses. */
rgrover1 993:4d62b7967c11 156 GENERIC_TAG = 512, /**< Generic Tag. */
rgrover1 993:4d62b7967c11 157 GENERIC_KEYRING = 576, /**< Generic Keyring. */
rgrover1 993:4d62b7967c11 158 GENERIC_MEDIA_PLAYER = 640, /**< Generic Media Player. */
rgrover1 993:4d62b7967c11 159 GENERIC_BARCODE_SCANNER = 704, /**< Generic Barcode Scanner. */
rgrover1 993:4d62b7967c11 160 GENERIC_THERMOMETER = 768, /**< Generic Thermometer. */
rgrover1 993:4d62b7967c11 161 THERMOMETER_EAR = 769, /**< Ear Thermometer. */
rgrover1 993:4d62b7967c11 162 GENERIC_HEART_RATE_SENSOR = 832, /**< Generic Heart Rate Sensor. */
rgrover1 993:4d62b7967c11 163 HEART_RATE_SENSOR_HEART_RATE_BELT = 833, /**< Belt Heart Rate Sensor. */
rgrover1 993:4d62b7967c11 164 GENERIC_BLOOD_PRESSURE = 896, /**< Generic Blood Pressure. */
rgrover1 993:4d62b7967c11 165 BLOOD_PRESSURE_ARM = 897, /**< Arm Blood Pressure. */
rgrover1 993:4d62b7967c11 166 BLOOD_PRESSURE_WRIST = 898, /**< Wrist Blood Pressure. */
rgrover1 993:4d62b7967c11 167 HUMAN_INTERFACE_DEVICE_HID = 960, /**< Human Interface Device (HID). */
rgrover1 993:4d62b7967c11 168 KEYBOARD = 961, /**< Keyboard. */
rgrover1 993:4d62b7967c11 169 MOUSE = 962, /**< Mouse. */
rgrover1 993:4d62b7967c11 170 JOYSTICK = 963, /**< Joystick. */
rgrover1 993:4d62b7967c11 171 GAMEPAD = 964, /**< Gamepad. */
rgrover1 993:4d62b7967c11 172 DIGITIZER_TABLET = 965, /**< Digitizer Tablet. */
rgrover1 993:4d62b7967c11 173 CARD_READER = 966, /**< Card Reader. */
rgrover1 993:4d62b7967c11 174 DIGITAL_PEN = 967, /**< Digital Pen. */
rgrover1 993:4d62b7967c11 175 BARCODE_SCANNER = 968, /**< Barcode Scanner. */
rgrover1 993:4d62b7967c11 176 GENERIC_GLUCOSE_METER = 1024, /**< Generic Glucose Meter. */
rgrover1 993:4d62b7967c11 177 GENERIC_RUNNING_WALKING_SENSOR = 1088, /**< Generic Running/Walking Sensor. */
rgrover1 993:4d62b7967c11 178 RUNNING_WALKING_SENSOR_IN_SHOE = 1089, /**< In Shoe Running/Walking Sensor. */
rgrover1 993:4d62b7967c11 179 RUNNING_WALKING_SENSOR_ON_SHOE = 1090, /**< On Shoe Running/Walking Sensor. */
rgrover1 993:4d62b7967c11 180 RUNNING_WALKING_SENSOR_ON_HIP = 1091, /**< On Hip Running/Walking Sensor. */
rgrover1 993:4d62b7967c11 181 GENERIC_CYCLING = 1152, /**< Generic Cycling. */
rgrover1 993:4d62b7967c11 182 CYCLING_CYCLING_COMPUTER = 1153, /**< Cycling Computer. */
rgrover1 993:4d62b7967c11 183 CYCLING_SPEED_SENSOR = 1154, /**< Cycling Speed Sensor. */
rgrover1 993:4d62b7967c11 184 CYCLING_CADENCE_SENSOR = 1155, /**< Cycling Cadence Sensor. */
rgrover1 993:4d62b7967c11 185 CYCLING_POWER_SENSOR = 1156, /**< Cycling Power Sensor. */
rgrover1 993:4d62b7967c11 186 CYCLING_SPEED_AND_CADENCE_SENSOR = 1157, /**< Cycling Speed and Cadence Sensor. */
rgrover1 993:4d62b7967c11 187 PULSE_OXIMETER_GENERIC = 3136, /**< Generic Pulse Oximeter. */
rgrover1 993:4d62b7967c11 188 PULSE_OXIMETER_FINGERTIP = 3137, /**< Fingertip Pulse Oximeter. */
rgrover1 993:4d62b7967c11 189 PULSE_OXIMETER_WRIST_WORN = 3138, /**< Wrist Worn Pulse Oximeter. */
rgrover1 993:4d62b7967c11 190 OUTDOOR_GENERIC = 5184, /**< Generic Outdoor. */
rgrover1 993:4d62b7967c11 191 OUTDOOR_LOCATION_DISPLAY_DEVICE = 5185, /**< Outdoor Location Display Device. */
rgrover1 993:4d62b7967c11 192 OUTDOOR_LOCATION_AND_NAVIGATION_DISPLAY_DEVICE = 5186, /**< Outdoor Location and Navigation Display Device. */
rgrover1 993:4d62b7967c11 193 OUTDOOR_LOCATION_POD = 5187, /**< Outdoor Location Pod. */
rgrover1 993:4d62b7967c11 194 OUTDOOR_LOCATION_AND_NAVIGATION_POD = 5188 /**< Outdoor Location and Navigation Pod. */
rgrover1 710:b2e1a2660ec2 195 };
rgrover1 756:503c4bd89a3d 196 typedef enum Appearance_t Appearance; /* Deprecated type alias. This may be dropped in a future release. */
rgrover1 710:b2e1a2660ec2 197
rgrover1 710:b2e1a2660ec2 198 GapAdvertisingData(void) : _payload(), _payloadLen(0), _appearance(GENERIC_TAG) {
rgrover1 710:b2e1a2660ec2 199 /* empty */
rgrover1 710:b2e1a2660ec2 200 }
rgrover1 710:b2e1a2660ec2 201
rgrover1 710:b2e1a2660ec2 202 /**
rgrover1 993:4d62b7967c11 203 * Adds advertising data based on the specified AD type (see DataType).
rgrover1 710:b2e1a2660ec2 204 *
rgrover1 993:4d62b7967c11 205 * @param advDataType The Advertising 'DataType' to add.
rgrover1 993:4d62b7967c11 206 * @param payload Pointer to the payload contents.
rgrover1 993:4d62b7967c11 207 * @param len Size of the payload in bytes.
rgrover1 710:b2e1a2660ec2 208 *
rgrover1 710:b2e1a2660ec2 209 * @return BLE_ERROR_BUFFER_OVERFLOW if the specified data would cause the
rgrover1 710:b2e1a2660ec2 210 * advertising buffer to overflow, else BLE_ERROR_NONE.
rgrover1 710:b2e1a2660ec2 211 */
rgrover1 710:b2e1a2660ec2 212 ble_error_t addData(DataType advDataType, const uint8_t *payload, uint8_t len)
rgrover1 765:4cd91998cd48 213 {
rgrover1 993:4d62b7967c11 214 ble_error_t result = BLE_ERROR_BUFFER_OVERFLOW;
rgrover1 993:4d62b7967c11 215
rgrover1 993:4d62b7967c11 216 // find field
rgrover1 993:4d62b7967c11 217 uint8_t* field = findField(advDataType);
rgrover1 993:4d62b7967c11 218
rgrover1 993:4d62b7967c11 219 // Field type already exist, either add to field or replace
rgrover1 993:4d62b7967c11 220 if (field) {
rgrover1 993:4d62b7967c11 221 switch(advDataType) {
rgrover1 993:4d62b7967c11 222 // These fields will be overwritten with the new value
rgrover1 993:4d62b7967c11 223 case FLAGS:
rgrover1 993:4d62b7967c11 224 case SHORTENED_LOCAL_NAME:
rgrover1 993:4d62b7967c11 225 case COMPLETE_LOCAL_NAME:
rgrover1 993:4d62b7967c11 226 case TX_POWER_LEVEL:
rgrover1 993:4d62b7967c11 227 case DEVICE_ID:
rgrover1 993:4d62b7967c11 228 case SLAVE_CONNECTION_INTERVAL_RANGE:
rgrover1 993:4d62b7967c11 229 case SERVICE_DATA:
rgrover1 993:4d62b7967c11 230 case APPEARANCE:
rgrover1 993:4d62b7967c11 231 case ADVERTISING_INTERVAL:
rgrover1 993:4d62b7967c11 232 case MANUFACTURER_SPECIFIC_DATA: {
rgrover1 993:4d62b7967c11 233 // current field length, with the type subtracted
rgrover1 993:4d62b7967c11 234 uint8_t dataLength = field[0] - 1;
rgrover1 993:4d62b7967c11 235
rgrover1 993:4d62b7967c11 236 // new data has same length, do in-order replacement
rgrover1 993:4d62b7967c11 237 if (len == dataLength) {
rgrover1 993:4d62b7967c11 238 for (uint8_t idx = 0; idx < dataLength; idx++) {
rgrover1 993:4d62b7967c11 239 field[2 + idx] = payload[idx];
rgrover1 993:4d62b7967c11 240 }
rgrover1 993:4d62b7967c11 241 } else {
rgrover1 993:4d62b7967c11 242 // check if data fits
rgrover1 993:4d62b7967c11 243 if ((_payloadLen - dataLength + len) <= GAP_ADVERTISING_DATA_MAX_PAYLOAD) {
rgrover1 993:4d62b7967c11 244
rgrover1 993:4d62b7967c11 245 // remove old field
rgrover1 993:4d62b7967c11 246 while ((field + dataLength + 2) < &_payload[_payloadLen]) {
rgrover1 993:4d62b7967c11 247 *field = field[dataLength + 2];
rgrover1 993:4d62b7967c11 248 field++;
rgrover1 993:4d62b7967c11 249 }
rgrover1 993:4d62b7967c11 250
rgrover1 993:4d62b7967c11 251 // reduce length
rgrover1 993:4d62b7967c11 252 _payloadLen -= dataLength + 2;
rgrover1 993:4d62b7967c11 253
rgrover1 993:4d62b7967c11 254 // add new field
rgrover1 993:4d62b7967c11 255 result = appendField(advDataType, payload, len);
rgrover1 993:4d62b7967c11 256 }
rgrover1 993:4d62b7967c11 257 }
rgrover1 710:b2e1a2660ec2 258
rgrover1 993:4d62b7967c11 259 break;
rgrover1 993:4d62b7967c11 260 }
rgrover1 993:4d62b7967c11 261 // These fields will have the new data appended if there is sufficient space
rgrover1 993:4d62b7967c11 262 case INCOMPLETE_LIST_16BIT_SERVICE_IDS:
rgrover1 993:4d62b7967c11 263 case COMPLETE_LIST_16BIT_SERVICE_IDS:
rgrover1 993:4d62b7967c11 264 case INCOMPLETE_LIST_32BIT_SERVICE_IDS:
rgrover1 993:4d62b7967c11 265 case COMPLETE_LIST_32BIT_SERVICE_IDS:
rgrover1 993:4d62b7967c11 266 case INCOMPLETE_LIST_128BIT_SERVICE_IDS:
rgrover1 993:4d62b7967c11 267 case COMPLETE_LIST_128BIT_SERVICE_IDS:
rgrover1 993:4d62b7967c11 268 case LIST_128BIT_SOLICITATION_IDS: {
rgrover1 993:4d62b7967c11 269 // check if data fits
rgrover1 993:4d62b7967c11 270 if ((_payloadLen + len) <= GAP_ADVERTISING_DATA_MAX_PAYLOAD) {
rgrover1 993:4d62b7967c11 271 // make room for new field by moving the remainder of the
rgrover1 993:4d62b7967c11 272 // advertisement payload "to the right" starting after the
rgrover1 993:4d62b7967c11 273 // TYPE field.
rgrover1 993:4d62b7967c11 274 uint8_t* end = &_payload[_payloadLen];
rgrover1 993:4d62b7967c11 275
rgrover1 993:4d62b7967c11 276 while (&field[1] < end) {
rgrover1 993:4d62b7967c11 277 end[len] = *end;
rgrover1 993:4d62b7967c11 278 end--;
rgrover1 993:4d62b7967c11 279 }
rgrover1 993:4d62b7967c11 280
rgrover1 993:4d62b7967c11 281 // insert new data
rgrover1 993:4d62b7967c11 282 for (uint8_t idx = 0; idx < len; idx++) {
rgrover1 993:4d62b7967c11 283 field[2 + idx] = payload[idx];
rgrover1 993:4d62b7967c11 284 }
rgrover1 993:4d62b7967c11 285
rgrover1 993:4d62b7967c11 286 // increment lengths
rgrover1 993:4d62b7967c11 287 field[0] += len;
rgrover1 993:4d62b7967c11 288 _payloadLen += len;
rgrover1 993:4d62b7967c11 289
rgrover1 993:4d62b7967c11 290 result = BLE_ERROR_NONE;
rgrover1 993:4d62b7967c11 291 }
rgrover1 993:4d62b7967c11 292
rgrover1 993:4d62b7967c11 293 break;
rgrover1 993:4d62b7967c11 294 }
rgrover1 993:4d62b7967c11 295 // Field exists but updating it is not supported. Abort operation.
rgrover1 993:4d62b7967c11 296 default:
rgrover1 993:4d62b7967c11 297 result = BLE_ERROR_NOT_IMPLEMENTED;
rgrover1 993:4d62b7967c11 298 break;
rgrover1 993:4d62b7967c11 299 }
rgrover1 993:4d62b7967c11 300 } else {
rgrover1 993:4d62b7967c11 301 // field doesn't exists, insert new
rgrover1 993:4d62b7967c11 302 result = appendField(advDataType, payload, len);
rgrover1 710:b2e1a2660ec2 303 }
rgrover1 710:b2e1a2660ec2 304
rgrover1 993:4d62b7967c11 305 return result;
rgrover1 710:b2e1a2660ec2 306 }
rgrover1 710:b2e1a2660ec2 307
rgrover1 710:b2e1a2660ec2 308 /**
rgrover1 765:4cd91998cd48 309 * Update a particular ADV field in the advertising payload (based on
rgrover1 765:4cd91998cd48 310 * matching type and length). Note: the length of the new data must be the
rgrover1 765:4cd91998cd48 311 * same as the old one.
rgrover1 763:36c3e2b1f1ae 312 *
rgrover1 765:4cd91998cd48 313 * @param[in] advDataType The Advertising 'DataType' to add.
rgrover1 765:4cd91998cd48 314 * @param[in] payload Pointer to the payload contents.
rgrover1 765:4cd91998cd48 315 * @param[in] len Size of the payload in bytes.
rgrover1 763:36c3e2b1f1ae 316 *
rgrover1 763:36c3e2b1f1ae 317 * @return BLE_ERROR_UNSPECIFIED if the specified field is not found, else
rgrover1 763:36c3e2b1f1ae 318 * BLE_ERROR_NONE.
rgrover1 763:36c3e2b1f1ae 319 */
rgrover1 765:4cd91998cd48 320 ble_error_t updateData(DataType_t advDataType, const uint8_t *payload, uint8_t len)
rgrover1 765:4cd91998cd48 321 {
rgrover1 765:4cd91998cd48 322 if ((payload == NULL) || (len == 0)) {
rgrover1 765:4cd91998cd48 323 return BLE_ERROR_INVALID_PARAM;
rgrover1 765:4cd91998cd48 324 }
rgrover1 765:4cd91998cd48 325
rgrover1 765:4cd91998cd48 326 /* A local struct to describe an ADV field. This definition comes from the Bluetooth Core Spec. (v4.2) Part C, Section 11. */
rgrover1 765:4cd91998cd48 327 struct ADVField_t {
rgrover1 993:4d62b7967c11 328 uint8_t len; /* Describes the length (in bytes) of the following type and bytes. */
rgrover1 765:4cd91998cd48 329 uint8_t type; /* Should have the same representation of DataType_t (above). */
rgrover1 765:4cd91998cd48 330 uint8_t bytes[0]; /* A placeholder for variable length data. */
rgrover1 765:4cd91998cd48 331 };
rgrover1 765:4cd91998cd48 332
rgrover1 765:4cd91998cd48 333 /* Iterate over the adv fields looking for the first match. */
rgrover1 763:36c3e2b1f1ae 334 uint8_t byteIndex = 0;
rgrover1 763:36c3e2b1f1ae 335 while (byteIndex < _payloadLen) {
rgrover1 765:4cd91998cd48 336 ADVField_t *currentADV = (ADVField_t *)&_payload[byteIndex];
rgrover1 993:4d62b7967c11 337 if ((currentADV->len == (len + 1)) && /* Incoming len only describes the payload, whereas ADV->len describes [type + payload]. */
rgrover1 765:4cd91998cd48 338 (currentADV->type == advDataType)) {
rgrover1 765:4cd91998cd48 339 memcpy(currentADV->bytes, payload, len);
rgrover1 763:36c3e2b1f1ae 340 return BLE_ERROR_NONE;
rgrover1 763:36c3e2b1f1ae 341 }
rgrover1 765:4cd91998cd48 342
rgrover1 993:4d62b7967c11 343 byteIndex += (currentADV->len + 1); /* Advance by len+1; '+1' is needed to span the len field itself. */
rgrover1 763:36c3e2b1f1ae 344 }
rgrover1 763:36c3e2b1f1ae 345
rgrover1 763:36c3e2b1f1ae 346 return BLE_ERROR_UNSPECIFIED;
rgrover1 763:36c3e2b1f1ae 347 }
rgrover1 763:36c3e2b1f1ae 348
rgrover1 763:36c3e2b1f1ae 349 /**
rgrover1 993:4d62b7967c11 350 * Helper function to add APPEARANCE data to the advertising payload.
rgrover1 710:b2e1a2660ec2 351 *
rgrover1 710:b2e1a2660ec2 352 * @param appearance
rgrover1 993:4d62b7967c11 353 * The APPEARANCE value to add.
rgrover1 710:b2e1a2660ec2 354 *
rgrover1 710:b2e1a2660ec2 355 * @return BLE_ERROR_BUFFER_OVERFLOW if the specified data would cause the
rgrover1 710:b2e1a2660ec2 356 * advertising buffer to overflow, else BLE_ERROR_NONE.
rgrover1 710:b2e1a2660ec2 357 */
rgrover1 710:b2e1a2660ec2 358 ble_error_t addAppearance(Appearance appearance = GENERIC_TAG) {
rgrover1 710:b2e1a2660ec2 359 _appearance = appearance;
rgrover1 710:b2e1a2660ec2 360 return addData(GapAdvertisingData::APPEARANCE, (uint8_t *)&appearance, 2);
rgrover1 710:b2e1a2660ec2 361 }
rgrover1 710:b2e1a2660ec2 362
rgrover1 710:b2e1a2660ec2 363 /**
rgrover1 710:b2e1a2660ec2 364 * Helper function to add FLAGS data to the advertising payload.
rgrover1 710:b2e1a2660ec2 365 * @param flags
rgrover1 710:b2e1a2660ec2 366 * LE_LIMITED_DISCOVERABLE
rgrover1 710:b2e1a2660ec2 367 * The peripheral is discoverable for a limited period of time.
rgrover1 710:b2e1a2660ec2 368 * LE_GENERAL_DISCOVERABLE
rgrover1 710:b2e1a2660ec2 369 * The peripheral is permanently discoverable.
rgrover1 710:b2e1a2660ec2 370 * BREDR_NOT_SUPPORTED
rgrover1 710:b2e1a2660ec2 371 * This peripheral is a Bluetooth Low Energy only device (no EDR support).
rgrover1 710:b2e1a2660ec2 372 *
rgrover1 710:b2e1a2660ec2 373 * @return BLE_ERROR_BUFFER_OVERFLOW if the specified data would cause the
rgrover1 710:b2e1a2660ec2 374 * advertising buffer to overflow, else BLE_ERROR_NONE.
rgrover1 710:b2e1a2660ec2 375 */
rgrover1 710:b2e1a2660ec2 376 ble_error_t addFlags(uint8_t flags = LE_GENERAL_DISCOVERABLE) {
rgrover1 710:b2e1a2660ec2 377 return addData(GapAdvertisingData::FLAGS, &flags, 1);
rgrover1 710:b2e1a2660ec2 378 }
rgrover1 710:b2e1a2660ec2 379
rgrover1 710:b2e1a2660ec2 380 /**
rgrover1 993:4d62b7967c11 381 * Helper function to add TX_POWER_LEVEL data to the advertising payload.
rgrover1 710:b2e1a2660ec2 382 *
rgrover1 710:b2e1a2660ec2 383 * @return BLE_ERROR_BUFFER_OVERFLOW if the specified data would cause the
rgrover1 710:b2e1a2660ec2 384 * advertising buffer to overflow, else BLE_ERROR_NONE.
rgrover1 710:b2e1a2660ec2 385 */
rgrover1 710:b2e1a2660ec2 386 ble_error_t addTxPower(int8_t txPower) {
rgrover1 993:4d62b7967c11 387 /* To Do: Basic error checking to make sure txPower is in range. */
rgrover1 710:b2e1a2660ec2 388 return addData(GapAdvertisingData::TX_POWER_LEVEL, (uint8_t *)&txPower, 1);
rgrover1 710:b2e1a2660ec2 389 }
rgrover1 710:b2e1a2660ec2 390
rgrover1 710:b2e1a2660ec2 391 /**
rgrover1 993:4d62b7967c11 392 * Clears the payload and resets the payload length counter.
rgrover1 710:b2e1a2660ec2 393 */
rgrover1 710:b2e1a2660ec2 394 void clear(void) {
rgrover1 710:b2e1a2660ec2 395 memset(&_payload, 0, GAP_ADVERTISING_DATA_MAX_PAYLOAD);
rgrover1 710:b2e1a2660ec2 396 _payloadLen = 0;
rgrover1 710:b2e1a2660ec2 397 }
rgrover1 710:b2e1a2660ec2 398
rgrover1 710:b2e1a2660ec2 399 /**
rgrover1 993:4d62b7967c11 400 * Returns a pointer to the current payload.
rgrover1 710:b2e1a2660ec2 401 */
rgrover1 710:b2e1a2660ec2 402 const uint8_t *getPayload(void) const {
rgrover1 769:2d236d9afa9e 403 return _payload;
rgrover1 710:b2e1a2660ec2 404 }
rgrover1 710:b2e1a2660ec2 405
rgrover1 710:b2e1a2660ec2 406 /**
rgrover1 993:4d62b7967c11 407 * Returns the current payload length (0..31 bytes).
rgrover1 710:b2e1a2660ec2 408 */
rgrover1 710:b2e1a2660ec2 409 uint8_t getPayloadLen(void) const {
rgrover1 710:b2e1a2660ec2 410 return _payloadLen;
rgrover1 710:b2e1a2660ec2 411 }
rgrover1 710:b2e1a2660ec2 412
rgrover1 710:b2e1a2660ec2 413 /**
rgrover1 993:4d62b7967c11 414 * Returns the 16-bit appearance value for this device.
rgrover1 710:b2e1a2660ec2 415 */
rgrover1 710:b2e1a2660ec2 416 uint16_t getAppearance(void) const {
rgrover1 710:b2e1a2660ec2 417 return (uint16_t)_appearance;
rgrover1 710:b2e1a2660ec2 418 }
rgrover1 710:b2e1a2660ec2 419
rgrover1 993:4d62b7967c11 420 /**
rgrover1 993:4d62b7967c11 421 * Search advertisement data for field.
rgrover1 993:4d62b7967c11 422 * Returns pointer to the first element in the field if found, NULL otherwise.
rgrover1 993:4d62b7967c11 423 * Where the first element is the length of the field.
rgrover1 993:4d62b7967c11 424 */
rgrover1 993:4d62b7967c11 425 const uint8_t* findField(DataType_t type) const {
rgrover1 993:4d62b7967c11 426 return findField(type);
rgrover1 993:4d62b7967c11 427 }
rgrover1 993:4d62b7967c11 428
rgrover1 710:b2e1a2660ec2 429 private:
rgrover1 993:4d62b7967c11 430 /**
rgrover1 993:4d62b7967c11 431 * Append advertising data based on the specified AD type (see DataType)
rgrover1 993:4d62b7967c11 432 */
rgrover1 993:4d62b7967c11 433 ble_error_t appendField(DataType advDataType, const uint8_t *payload, uint8_t len)
rgrover1 993:4d62b7967c11 434 {
rgrover1 993:4d62b7967c11 435 /* Make sure we don't exceed the 31 byte payload limit */
rgrover1 993:4d62b7967c11 436 if (_payloadLen + len + 2 > GAP_ADVERTISING_DATA_MAX_PAYLOAD) {
rgrover1 993:4d62b7967c11 437 return BLE_ERROR_BUFFER_OVERFLOW;
rgrover1 993:4d62b7967c11 438 }
rgrover1 993:4d62b7967c11 439
rgrover1 993:4d62b7967c11 440 /* Field length. */
rgrover1 993:4d62b7967c11 441 memset(&_payload[_payloadLen], len + 1, 1);
rgrover1 993:4d62b7967c11 442 _payloadLen++;
rgrover1 993:4d62b7967c11 443
rgrover1 993:4d62b7967c11 444 /* Field ID. */
rgrover1 993:4d62b7967c11 445 memset(&_payload[_payloadLen], (uint8_t)advDataType, 1);
rgrover1 993:4d62b7967c11 446 _payloadLen++;
rgrover1 993:4d62b7967c11 447
rgrover1 993:4d62b7967c11 448 /* Payload. */
rgrover1 993:4d62b7967c11 449 memcpy(&_payload[_payloadLen], payload, len);
rgrover1 993:4d62b7967c11 450 _payloadLen += len;
rgrover1 993:4d62b7967c11 451
rgrover1 993:4d62b7967c11 452 return BLE_ERROR_NONE;
rgrover1 993:4d62b7967c11 453 }
rgrover1 993:4d62b7967c11 454
rgrover1 993:4d62b7967c11 455 /**
rgrover1 993:4d62b7967c11 456 * Search advertisement data for field.
rgrover1 993:4d62b7967c11 457 * Returns pointer to the first element in the field if found, NULL otherwise.
rgrover1 993:4d62b7967c11 458 * Where the first element is the length of the field.
rgrover1 993:4d62b7967c11 459 */
rgrover1 993:4d62b7967c11 460 uint8_t* findField(DataType_t type) {
rgrover1 993:4d62b7967c11 461 // scan through advertisement data
rgrover1 993:4d62b7967c11 462 for (uint8_t idx = 0; idx < _payloadLen; ) {
rgrover1 993:4d62b7967c11 463 uint8_t fieldType = _payload[idx + 1];
rgrover1 993:4d62b7967c11 464
rgrover1 993:4d62b7967c11 465 if (fieldType == type) {
rgrover1 993:4d62b7967c11 466 return &_payload[idx];
rgrover1 993:4d62b7967c11 467 }
rgrover1 993:4d62b7967c11 468
rgrover1 993:4d62b7967c11 469 // advance to next field
rgrover1 993:4d62b7967c11 470 idx += _payload[idx] + 1;
rgrover1 993:4d62b7967c11 471 }
rgrover1 993:4d62b7967c11 472
rgrover1 993:4d62b7967c11 473 // field not found
rgrover1 993:4d62b7967c11 474 return NULL;
rgrover1 993:4d62b7967c11 475 }
rgrover1 993:4d62b7967c11 476
rgrover1 710:b2e1a2660ec2 477 uint8_t _payload[GAP_ADVERTISING_DATA_MAX_PAYLOAD];
rgrover1 710:b2e1a2660ec2 478 uint8_t _payloadLen;
rgrover1 710:b2e1a2660ec2 479 uint16_t _appearance;
rgrover1 710:b2e1a2660ec2 480 };
rgrover1 710:b2e1a2660ec2 481
rgrover1 710:b2e1a2660ec2 482 #endif // ifndef __GAP_ADVERTISING_DATA_H__