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