just a fork

Fork of BLE_API by Bluetooth Low Energy

Committer:
rgrover1
Date:
Wed Dec 02 10:29:44 2015 +0000
Revision:
993:4d62b7967c11
Parent:
992:ca834f7ae8ed
Child:
1042:21a86ac7f5b1
Synchronized with git rev 12e27cd4
Author: Rohit Grover
Release 2.1.3
=============

* Improvements to CallChainOfFunctionPointerswithContext:
- add a `detach` function to be able to remove callbacks.
- detach function now return true if a function has been detached and
false otherwise.
- add a function call operator.
- use safe-bool idiom. see : http://www.artima.com/cppsource/safebool.html

* Add SafeBool class which allow to easily declare a safe bool operator in
c++03.

* Improvements to FunctionPointerWithContext:
- fix call propagation
- use safe bool idiom

* Add config file for generating Doxygen.

* Setup for onRadioNotification callback does not call initRadioNotification
anymore.

* GapAdvertisementData now handles replacement and appending of data fields
based on type. Some fields can be replaced with new values, and others
require the payload to be appended.

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__