Lightly modified version of the BLE stack, that doesn't bring up a DFUService by default... as we have our own.

Fork of BLE_API by Bluetooth Low Energy

Committer:
rgrover1
Date:
Mon Dec 01 14:31:20 2014 +0000
Revision:
225:f6cbfd817d16
Parent:
224:c55213f24647
Child:
226:ec436a9ceb31
Synchronized with git rev 88d278cc
Author: Rohit Grover
make UUID consts static so that the header file can be included from multiple compilation units.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
rgrover1 171:6092e61690dc 1 /* mbed Microcontroller Library
rgrover1 171:6092e61690dc 2 * Copyright (c) 2006-2013 ARM Limited
rgrover1 171:6092e61690dc 3 *
rgrover1 171:6092e61690dc 4 * Licensed under the Apache License, Version 2.0 (the "License");
rgrover1 171:6092e61690dc 5 * you may not use this file except in compliance with the License.
rgrover1 171:6092e61690dc 6 * You may obtain a copy of the License at
rgrover1 171:6092e61690dc 7 *
rgrover1 171:6092e61690dc 8 * http://www.apache.org/licenses/LICENSE-2.0
rgrover1 171:6092e61690dc 9 *
rgrover1 171:6092e61690dc 10 * Unless required by applicable law or agreed to in writing, software
rgrover1 171:6092e61690dc 11 * distributed under the License is distributed on an "AS IS" BASIS,
rgrover1 171:6092e61690dc 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
rgrover1 171:6092e61690dc 13 * See the License for the specific language governing permissions and
rgrover1 171:6092e61690dc 14 * limitations under the License.
rgrover1 171:6092e61690dc 15 */
rgrover1 171:6092e61690dc 16
rgrover1 207:e88130dc254c 17 #ifndef __BLE_URI_BEACON_CONFIG_SERVICE_H__
rgrover1 207:e88130dc254c 18 #define __BLE_URI_BEACON_CONFIG_SERVICE_H__
rgrover1 171:6092e61690dc 19
rgrover1 171:6092e61690dc 20 #include "BLEDevice.h"
rgrover1 171:6092e61690dc 21
rgrover1 225:f6cbfd817d16 22 #define URI_BEACON_CONFIG_UUID_INITIALIZER_LIST(FIRST, SECOND) { \
rgrover1 225:f6cbfd817d16 23 0xee, 0x0c, FIRST, SECOND, 0x87, 0x86, 0x40, 0xba, \
rgrover1 225:f6cbfd817d16 24 0xab, 0x96, 0x99, 0xb9, 0x1a, 0xc9, 0x81, 0xd8, \
rgrover1 171:6092e61690dc 25 }
rgrover1 225:f6cbfd817d16 26 static const uint8_t URIBeacon2ControlServiceUUID[] = URI_BEACON_CONFIG_UUID_INITIALIZER_LIST(0x20, 0x80);
rgrover1 225:f6cbfd817d16 27 static const uint8_t lockedStateCharUUID[] = URI_BEACON_CONFIG_UUID_INITIALIZER_LIST(0x20, 0x81);
rgrover1 225:f6cbfd817d16 28 static const uint8_t uriDataCharUUID[] = URI_BEACON_CONFIG_UUID_INITIALIZER_LIST(0x20, 0x84);
rgrover1 225:f6cbfd817d16 29 static const uint8_t flagsCharUUID[] = URI_BEACON_CONFIG_UUID_INITIALIZER_LIST(0x20, 0x85);
rgrover1 225:f6cbfd817d16 30 static const uint8_t txPowerLevelsCharUUID[] = URI_BEACON_CONFIG_UUID_INITIALIZER_LIST(0x20, 0x86);
rgrover1 225:f6cbfd817d16 31 static const uint8_t txPowerModeCharUUID[] = URI_BEACON_CONFIG_UUID_INITIALIZER_LIST(0x20, 0x87);
rgrover1 225:f6cbfd817d16 32 static const uint8_t beaconPeriodCharUUID[] = URI_BEACON_CONFIG_UUID_INITIALIZER_LIST(0x20, 0x88);
rgrover1 225:f6cbfd817d16 33 static const uint8_t resetCharUUID[] = URI_BEACON_CONFIG_UUID_INITIALIZER_LIST(0x20, 0x89);
rgrover1 171:6092e61690dc 34
rgrover1 207:e88130dc254c 35 class URIBeaconConfigService {
rgrover1 180:afcd2f9c2ada 36 public:
rgrover1 175:4e85f7225f8f 37 enum TXPowerModes_t {
rgrover1 175:4e85f7225f8f 38 TX_POWER_MODE_LOWEST = 0,
rgrover1 175:4e85f7225f8f 39 TX_POWER_MODE_LOW = 1,
rgrover1 175:4e85f7225f8f 40 TX_POWER_MODE_MEDIUM = 2,
rgrover1 175:4e85f7225f8f 41 TX_POWER_MODE_HIGH = 3,
rgrover1 177:17f4b5924fe9 42 NUM_POWER_MODES
rgrover1 175:4e85f7225f8f 43 };
rgrover1 175:4e85f7225f8f 44
rgrover1 181:bbb6ce1082c3 45 /**
rgrover1 181:bbb6ce1082c3 46 * @param[ref] ble
rgrover1 181:bbb6ce1082c3 47 * BLEDevice object for the underlying controller.
rgrover1 208:88a3a58769bf 48 * @param[in] uridata
rgrover1 181:bbb6ce1082c3 49 * URI as a null-terminated string.
rgrover1 181:bbb6ce1082c3 50 * @param[in] flagsIn
rgrover1 181:bbb6ce1082c3 51 * UriBeacon Flags.
rgrover1 218:8ae02569fab9 52 * @param[in] powerLevels[]
rgrover1 218:8ae02569fab9 53 * Table of UriBeacon Tx Power Levels in dBm.
rgrover1 218:8ae02569fab9 54 * @param[in] powerMode
rgrover1 218:8ae02569fab9 55 * Currently effective power mode.
rgrover1 181:bbb6ce1082c3 56 * @param[in] beaconPeriodIn
rgrover1 181:bbb6ce1082c3 57 * The period in milliseconds that a UriBeacon packet is
rgrover1 181:bbb6ce1082c3 58 * transmitted. A value of zero disables UriBeacon
rgrover1 181:bbb6ce1082c3 59 * transmissions.
rgrover1 181:bbb6ce1082c3 60 */
rgrover1 218:8ae02569fab9 61 URIBeaconConfigService(BLEDevice &bleIn,
rgrover1 218:8ae02569fab9 62 const char *uriDataIn,
rgrover1 222:33b04c693e83 63 uint8_t flagsIn = 0,
rgrover1 218:8ae02569fab9 64 const int8_t powerLevelsIn[NUM_POWER_MODES] = NULL,
rgrover1 222:33b04c693e83 65 TXPowerModes_t powerModeIn = TX_POWER_MODE_LOW,
rgrover1 222:33b04c693e83 66 uint16_t beaconPeriodIn = 1000) :
rgrover1 192:3fd3dcf49005 67 ble(bleIn),
rgrover1 192:3fd3dcf49005 68 payloadIndex(0),
rgrover1 192:3fd3dcf49005 69 serviceDataPayload(),
rgrover1 192:3fd3dcf49005 70 initSucceeded(false),
rgrover1 192:3fd3dcf49005 71 lockedState(false),
rgrover1 192:3fd3dcf49005 72 uriDataLength(0),
rgrover1 192:3fd3dcf49005 73 uriData(),
rgrover1 192:3fd3dcf49005 74 flags(flagsIn),
rgrover1 192:3fd3dcf49005 75 powerLevels(),
rgrover1 201:9bb7b3f45c20 76 beaconPeriod(beaconPeriodIn),
rgrover1 192:3fd3dcf49005 77 lockedStateChar(lockedStateCharUUID, reinterpret_cast<uint8_t *>(&lockedState), 1, 1, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ),
rgrover1 215:f9d0169b9c28 78 uriDataChar(uriDataCharUUID, uriData, MAX_SIZE_URI_DATA_CHAR_VALUE, MAX_SIZE_URI_DATA_CHAR_VALUE,
rgrover1 225:f6cbfd817d16 79 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE),
rgrover1 192:3fd3dcf49005 80 flagsChar(flagsCharUUID, &flags, 1, 1, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE),
rgrover1 224:c55213f24647 81 txPowerLevelsChar(txPowerLevelsCharUUID, reinterpret_cast<uint8_t *>(powerLevels), sizeof(powerLevels), sizeof(powerLevels),
rgrover1 192:3fd3dcf49005 82 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE),
rgrover1 218:8ae02569fab9 83 txPowerModeChar(txPowerModeCharUUID, reinterpret_cast<uint8_t *>(&txPowerMode), sizeof(uint8_t), sizeof(uint8_t),
rgrover1 218:8ae02569fab9 84 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE),
rgrover1 192:3fd3dcf49005 85 beaconPeriodChar(beaconPeriodCharUUID, reinterpret_cast<uint8_t *>(&beaconPeriod), 2, 2,
rgrover1 192:3fd3dcf49005 86 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE),
rgrover1 215:f9d0169b9c28 87 resetChar(resetCharUUID, reinterpret_cast<uint8_t *>(&resetFlag), 1, 1, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE)
rgrover1 192:3fd3dcf49005 88 {
rgrover1 194:669eced4cd5e 89 if ((uriDataIn == NULL) || ((uriDataLength = strlen(uriDataIn)) == 0) || (uriDataLength > MAX_SIZE_URI_DATA_CHAR_VALUE)) {
rgrover1 192:3fd3dcf49005 90 return;
rgrover1 192:3fd3dcf49005 91 }
rgrover1 194:669eced4cd5e 92 strcpy(reinterpret_cast<char *>(uriData), uriDataIn);
rgrover1 192:3fd3dcf49005 93
rgrover1 218:8ae02569fab9 94 if (powerModeIn != NULL) {
rgrover1 218:8ae02569fab9 95 memcpy(powerLevels, powerLevelsIn, sizeof(powerLevels));
rgrover1 218:8ae02569fab9 96 updateTxPowerLevelsCharacteristic();
rgrover1 218:8ae02569fab9 97 }
rgrover1 218:8ae02569fab9 98
rgrover1 210:0c14030d1bd0 99 configureGAP();
rgrover1 171:6092e61690dc 100
rgrover1 192:3fd3dcf49005 101 GattCharacteristic *charTable[] = {&lockedStateChar, &uriDataChar, &flagsChar, &txPowerLevelsChar, &beaconPeriodChar, &resetChar};
rgrover1 192:3fd3dcf49005 102 GattService beaconControlService(URIBeacon2ControlServiceUUID, charTable, sizeof(charTable) / sizeof(GattCharacteristic *));
rgrover1 182:d16f8c11816b 103
rgrover1 192:3fd3dcf49005 104 ble.addService(beaconControlService);
rgrover1 207:e88130dc254c 105 ble.onDataWritten(this, &URIBeaconConfigService::onDataWritten);
rgrover1 192:3fd3dcf49005 106 }
rgrover1 192:3fd3dcf49005 107
rgrover1 193:ac2feceb7e87 108 bool configuredSuccessfully(void) const {
rgrover1 192:3fd3dcf49005 109 return initSucceeded;
rgrover1 171:6092e61690dc 110 }
rgrover1 171:6092e61690dc 111
rgrover1 173:05c4b1cea65f 112 /**
rgrover1 196:febbd68b1095 113 * Please note that the following public APIs are offered to allow modifying
rgrover1 196:febbd68b1095 114 * the service programmatically. It is also possible to do so over BLE GATT
rgrover1 196:febbd68b1095 115 * transactions.
rgrover1 196:febbd68b1095 116 */
rgrover1 196:febbd68b1095 117 public:
rgrover1 196:febbd68b1095 118 /**
rgrover1 173:05c4b1cea65f 119 * Update flags of the URIBeacon dynamically.
rgrover1 173:05c4b1cea65f 120 *
rgrover1 173:05c4b1cea65f 121 * @param[in] flagsIn
rgrover1 173:05c4b1cea65f 122 *
rgrover1 173:05c4b1cea65f 123 * ### UriBeacon Flags
rgrover1 173:05c4b1cea65f 124 * Bit | Description
rgrover1 173:05c4b1cea65f 125 * :---- | :----------
rgrover1 173:05c4b1cea65f 126 * 0 | Invisible Hint
rgrover1 173:05c4b1cea65f 127 * 1..7 | Reserved for future use. Must be zero.
rgrover1 173:05c4b1cea65f 128 *
rgrover1 173:05c4b1cea65f 129 * The `Invisible Hint` flag is a command for the user-agent that tells
rgrover1 173:05c4b1cea65f 130 * it not to access or display the UriBeacon. This is a guideline only,
rgrover1 173:05c4b1cea65f 131 * and is not a blocking method. User agents may, with user approval,
rgrover1 173:05c4b1cea65f 132 * display invisible beacons.
rgrover1 173:05c4b1cea65f 133 */
rgrover1 171:6092e61690dc 134 void setFlags(uint8_t flagsIn) {
rgrover1 171:6092e61690dc 135 flags = flagsIn;
rgrover1 210:0c14030d1bd0 136 configureGAP();
rgrover1 211:f181effe5de3 137 updateFlagsCharacteristic();
rgrover1 171:6092e61690dc 138 }
rgrover1 171:6092e61690dc 139
rgrover1 177:17f4b5924fe9 140 /**
rgrover1 219:5603d539120c 141 * Update the txPowerLevels table.
rgrover1 177:17f4b5924fe9 142 */
rgrover1 219:5603d539120c 143 void setTxPowerLevels(const int8_t powerLevelsIn[NUM_POWER_MODES]) {
rgrover1 219:5603d539120c 144 memcpy(powerLevels, powerLevelsIn, sizeof(powerLevels));
rgrover1 223:01a71f5e0ce4 145 configureGAP();
rgrover1 219:5603d539120c 146 updateTxPowerLevelsCharacteristic();
rgrover1 177:17f4b5924fe9 147 }
rgrover1 177:17f4b5924fe9 148
rgrover1 177:17f4b5924fe9 149 /**
rgrover1 177:17f4b5924fe9 150 * Set the effective power mode from one of the values in the powerLevels tables.
rgrover1 177:17f4b5924fe9 151 */
rgrover1 219:5603d539120c 152 void setTxPowerMode(TXPowerModes_t mode) {
rgrover1 218:8ae02569fab9 153 txPowerMode = mode;
rgrover1 210:0c14030d1bd0 154 configureGAP();
rgrover1 218:8ae02569fab9 155 updateTxPowerModeCharacteristic();
rgrover1 171:6092e61690dc 156 }
rgrover1 171:6092e61690dc 157
rgrover1 183:41d6ffadba96 158 /**
rgrover1 183:41d6ffadba96 159 * The period in milliseconds that a UriBeacon packet is transmitted.
rgrover1 183:41d6ffadba96 160 *
rgrover1 183:41d6ffadba96 161 * @Note: A value of zero disables UriBeacon transmissions.
rgrover1 183:41d6ffadba96 162 */
rgrover1 171:6092e61690dc 163 void setBeaconPeriod(uint16_t beaconPeriodIn) {
rgrover1 171:6092e61690dc 164 beaconPeriod = beaconPeriodIn;
rgrover1 210:0c14030d1bd0 165 configureGAP();
rgrover1 211:f181effe5de3 166 updateBeaconPeriodCharacteristic();
rgrover1 171:6092e61690dc 167 }
rgrover1 171:6092e61690dc 168
rgrover1 196:febbd68b1095 169 private:
rgrover1 186:ce34008cea95 170 /**
rgrover1 186:ce34008cea95 171 * Setup the advertisement payload and GAP settings.
rgrover1 186:ce34008cea95 172 */
rgrover1 210:0c14030d1bd0 173 void configureGAP(void) {
rgrover1 171:6092e61690dc 174 const uint8_t BEACON_UUID[] = {0xD8, 0xFE};
rgrover1 171:6092e61690dc 175
rgrover1 206:49646c933822 176 payloadIndex = 0;
rgrover1 171:6092e61690dc 177 serviceDataPayload[payloadIndex++] = BEACON_UUID[0];
rgrover1 171:6092e61690dc 178 serviceDataPayload[payloadIndex++] = BEACON_UUID[1];
rgrover1 171:6092e61690dc 179 serviceDataPayload[payloadIndex++] = flags;
rgrover1 218:8ae02569fab9 180 serviceDataPayload[payloadIndex++] = powerLevels[txPowerMode];
rgrover1 171:6092e61690dc 181
rgrover1 206:49646c933822 182 const char *urlData = reinterpret_cast<char *>(uriData);
rgrover1 206:49646c933822 183 size_t sizeofURLData = uriDataLength;
rgrover1 206:49646c933822 184 size_t encodedBytes = encodeURISchemePrefix(urlData, sizeofURLData) + encodeURI(urlData, sizeofURLData);
rgrover1 171:6092e61690dc 185
rgrover1 171:6092e61690dc 186 ble.clearAdvertisingPayload();
rgrover1 171:6092e61690dc 187 ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, BEACON_UUID, sizeof(BEACON_UUID));
rgrover1 171:6092e61690dc 188 ble.accumulateAdvertisingPayload(GapAdvertisingData::SERVICE_DATA, serviceDataPayload, encodedBytes + 4);
rgrover1 171:6092e61690dc 189
rgrover1 201:9bb7b3f45c20 190 ble.setAdvertisingInterval(Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(beaconPeriod));
rgrover1 218:8ae02569fab9 191 ble.setTxPower(powerLevels[txPowerMode]);
rgrover1 171:6092e61690dc 192 }
rgrover1 171:6092e61690dc 193
rgrover1 171:6092e61690dc 194 size_t encodeURISchemePrefix(const char *&urldata, size_t &sizeofURLData) {
rgrover1 213:ac3b745af1d0 195 if (!sizeofURLData) {
rgrover1 213:ac3b745af1d0 196 return 0;
rgrover1 213:ac3b745af1d0 197 }
rgrover1 213:ac3b745af1d0 198
rgrover1 171:6092e61690dc 199 const char *prefixes[] = {
rgrover1 171:6092e61690dc 200 "http://www.",
rgrover1 171:6092e61690dc 201 "https://www.",
rgrover1 171:6092e61690dc 202 "http://",
rgrover1 171:6092e61690dc 203 "https://",
rgrover1 171:6092e61690dc 204 "urn:uuid:"
rgrover1 171:6092e61690dc 205 };
rgrover1 171:6092e61690dc 206
rgrover1 206:49646c933822 207 size_t encodedBytes = 0;
rgrover1 171:6092e61690dc 208 const size_t NUM_PREFIXES = sizeof(prefixes) / sizeof(char *);
rgrover1 171:6092e61690dc 209 for (unsigned i = 0; i < NUM_PREFIXES; i++) {
rgrover1 171:6092e61690dc 210 size_t prefixLen = strlen(prefixes[i]);
rgrover1 171:6092e61690dc 211 if (strncmp(urldata, prefixes[i], prefixLen) == 0) {
rgrover1 171:6092e61690dc 212 serviceDataPayload[payloadIndex++] = i;
rgrover1 206:49646c933822 213 encodedBytes = 1;
rgrover1 171:6092e61690dc 214
rgrover1 206:49646c933822 215 urldata += prefixLen;
rgrover1 171:6092e61690dc 216 sizeofURLData -= prefixLen;
rgrover1 171:6092e61690dc 217 break;
rgrover1 171:6092e61690dc 218 }
rgrover1 171:6092e61690dc 219 }
rgrover1 171:6092e61690dc 220
rgrover1 171:6092e61690dc 221 return encodedBytes;
rgrover1 171:6092e61690dc 222 }
rgrover1 171:6092e61690dc 223
rgrover1 171:6092e61690dc 224 size_t encodeURI(const char *urldata, size_t sizeofURLData) {
rgrover1 171:6092e61690dc 225 const char *suffixes[] = {
rgrover1 171:6092e61690dc 226 ".com/",
rgrover1 171:6092e61690dc 227 ".org/",
rgrover1 171:6092e61690dc 228 ".edu/",
rgrover1 171:6092e61690dc 229 ".net/",
rgrover1 171:6092e61690dc 230 ".info/",
rgrover1 171:6092e61690dc 231 ".biz/",
rgrover1 171:6092e61690dc 232 ".gov/",
rgrover1 171:6092e61690dc 233 ".com",
rgrover1 171:6092e61690dc 234 ".org",
rgrover1 171:6092e61690dc 235 ".edu",
rgrover1 171:6092e61690dc 236 ".net",
rgrover1 171:6092e61690dc 237 ".info",
rgrover1 171:6092e61690dc 238 ".biz",
rgrover1 171:6092e61690dc 239 ".gov"
rgrover1 171:6092e61690dc 240 };
rgrover1 171:6092e61690dc 241 const size_t NUM_SUFFIXES = sizeof(suffixes) / sizeof(char *);
rgrover1 171:6092e61690dc 242
rgrover1 171:6092e61690dc 243 size_t encodedBytes = 0;
rgrover1 171:6092e61690dc 244 while (sizeofURLData && (payloadIndex < MAX_SIZEOF_SERVICE_DATA_PAYLOAD)) {
rgrover1 171:6092e61690dc 245 /* check for suffix match */
rgrover1 171:6092e61690dc 246 unsigned i;
rgrover1 171:6092e61690dc 247 for (i = 0; i < NUM_SUFFIXES; i++) {
rgrover1 171:6092e61690dc 248 size_t suffixLen = strlen(suffixes[i]);
rgrover1 171:6092e61690dc 249 if ((suffixLen == 0) || (sizeofURLData < suffixLen)) {
rgrover1 171:6092e61690dc 250 continue;
rgrover1 171:6092e61690dc 251 }
rgrover1 171:6092e61690dc 252
rgrover1 171:6092e61690dc 253 if (strncmp(urldata, suffixes[i], suffixLen) == 0) {
rgrover1 171:6092e61690dc 254 serviceDataPayload[payloadIndex++] = i;
rgrover1 171:6092e61690dc 255 ++encodedBytes;
rgrover1 171:6092e61690dc 256 urldata += suffixLen;
rgrover1 171:6092e61690dc 257 sizeofURLData -= suffixLen;
rgrover1 171:6092e61690dc 258 break; /* from the for loop for checking against suffixes */
rgrover1 171:6092e61690dc 259 }
rgrover1 171:6092e61690dc 260 }
rgrover1 171:6092e61690dc 261 /* This is the default case where we've got an ordinary character which doesn't match a suffix. */
rgrover1 171:6092e61690dc 262 if (i == NUM_SUFFIXES) {
rgrover1 171:6092e61690dc 263 serviceDataPayload[payloadIndex++] = *urldata;
rgrover1 171:6092e61690dc 264 ++encodedBytes;
rgrover1 171:6092e61690dc 265 ++urldata;
rgrover1 171:6092e61690dc 266 --sizeofURLData;
rgrover1 171:6092e61690dc 267 }
rgrover1 171:6092e61690dc 268 }
rgrover1 192:3fd3dcf49005 269 if (sizeofURLData == 0) {
rgrover1 192:3fd3dcf49005 270 initSucceeded = true;
rgrover1 182:d16f8c11816b 271 }
rgrover1 171:6092e61690dc 272
rgrover1 171:6092e61690dc 273 return encodedBytes;
rgrover1 171:6092e61690dc 274 }
rgrover1 171:6092e61690dc 275
rgrover1 203:7b5178d2fa03 276 void onDataWritten(const GattCharacteristicWriteCBParams *params) {
rgrover1 185:7cd70497aec8 277 if (params->charHandle == uriDataChar.getValueAttribute().getHandle()) {
rgrover1 185:7cd70497aec8 278 if (lockedState) { /* When locked, the device isn't allowed to update the uriData characteristic. */
rgrover1 185:7cd70497aec8 279 /* Restore GATT database with previous value. */
rgrover1 211:f181effe5de3 280 updateURIDataCharacteristic();
rgrover1 185:7cd70497aec8 281 return;
rgrover1 185:7cd70497aec8 282 }
rgrover1 185:7cd70497aec8 283
rgrover1 185:7cd70497aec8 284 /* We don't handle very large writes at the moment. */
rgrover1 185:7cd70497aec8 285 if ((params->offset != 0) || (params->len > MAX_SIZE_URI_DATA_CHAR_VALUE)) {
rgrover1 185:7cd70497aec8 286 return;
rgrover1 185:7cd70497aec8 287 }
rgrover1 185:7cd70497aec8 288
rgrover1 185:7cd70497aec8 289 uriDataLength = params->len;
rgrover1 187:057c547facd2 290 memcpy(uriData, params->data, uriDataLength);
rgrover1 185:7cd70497aec8 291 } else if (params->charHandle == flagsChar.getValueAttribute().getHandle()) {
rgrover1 185:7cd70497aec8 292 if (lockedState) { /* When locked, the device isn't allowed to update the characteristic. */
rgrover1 185:7cd70497aec8 293 /* Restore GATT database with previous value. */
rgrover1 211:f181effe5de3 294 updateFlagsCharacteristic();
rgrover1 185:7cd70497aec8 295 return;
rgrover1 185:7cd70497aec8 296 } else {
rgrover1 185:7cd70497aec8 297 flags = *(params->data);
rgrover1 185:7cd70497aec8 298 }
rgrover1 185:7cd70497aec8 299 } else if (params->charHandle == txPowerLevelsChar.getValueAttribute().getHandle()) {
rgrover1 185:7cd70497aec8 300 if (lockedState) { /* When locked, the device isn't allowed to update the characteristic. */
rgrover1 185:7cd70497aec8 301 /* Restore GATT database with previous value. */
rgrover1 221:f813cddc145b 302 updateTxPowerLevelsCharacteristic();
rgrover1 185:7cd70497aec8 303 return;
rgrover1 185:7cd70497aec8 304 } else {
rgrover1 185:7cd70497aec8 305 memcpy(powerLevels, params->data, NUM_POWER_MODES * sizeof(int8_t));
rgrover1 185:7cd70497aec8 306 }
rgrover1 221:f813cddc145b 307 } else if (params->charHandle == txPowerModeChar.getValueAttribute().getHandle()) {
rgrover1 221:f813cddc145b 308 if (lockedState) { /* When locked, the device isn't allowed to update the characteristic. */
rgrover1 221:f813cddc145b 309 /* Restore GATT database with previous value. */
rgrover1 221:f813cddc145b 310 updateTxPowerModeCharacteristic();
rgrover1 221:f813cddc145b 311 return;
rgrover1 221:f813cddc145b 312 } else {
rgrover1 221:f813cddc145b 313 txPowerMode = *reinterpret_cast<const TXPowerModes_t *>(params->data);
rgrover1 221:f813cddc145b 314 }
rgrover1 185:7cd70497aec8 315 } else if (params->charHandle == beaconPeriodChar.getValueAttribute().getHandle()) {
rgrover1 185:7cd70497aec8 316 if (lockedState) { /* When locked, the device isn't allowed to update the characteristic. */
rgrover1 185:7cd70497aec8 317 /* Restore GATT database with previous value. */
rgrover1 211:f181effe5de3 318 updateBeaconPeriodCharacteristic();
rgrover1 185:7cd70497aec8 319 return;
rgrover1 185:7cd70497aec8 320 } else {
rgrover1 185:7cd70497aec8 321 beaconPeriod = *((uint16_t *)(params->data));
rgrover1 185:7cd70497aec8 322 }
rgrover1 189:a23091b54ab5 323 } else if (params->charHandle == resetChar.getValueAttribute().getHandle()) {
rgrover1 200:80dd3e50705c 324 resetDefaults();
rgrover1 185:7cd70497aec8 325 }
rgrover1 210:0c14030d1bd0 326 configureGAP();
rgrover1 185:7cd70497aec8 327 ble.setAdvertisingPayload();
rgrover1 185:7cd70497aec8 328 }
rgrover1 185:7cd70497aec8 329
rgrover1 200:80dd3e50705c 330 void resetDefaults(void) {
rgrover1 216:3f5e47361919 331 lockedState = false;
rgrover1 212:852d45a52016 332 uriDataLength = 0;
rgrover1 216:3f5e47361919 333 memset(uriData, 0, MAX_SIZE_URI_DATA_CHAR_VALUE);
rgrover1 212:852d45a52016 334 flags = 0;
rgrover1 216:3f5e47361919 335 memset(powerLevels, 0, sizeof(powerLevels));
rgrover1 218:8ae02569fab9 336 txPowerMode = TX_POWER_MODE_LOW;
rgrover1 212:852d45a52016 337 beaconPeriod = 0;
rgrover1 189:a23091b54ab5 338
rgrover1 211:f181effe5de3 339 updateGATT();
rgrover1 211:f181effe5de3 340 }
rgrover1 211:f181effe5de3 341
rgrover1 211:f181effe5de3 342 void updateGATT(void) {
rgrover1 214:7d79fa197212 343 updateLockedStateCharacteristic();
rgrover1 211:f181effe5de3 344 updateURIDataCharacteristic();
rgrover1 211:f181effe5de3 345 updateFlagsCharacteristic();
rgrover1 211:f181effe5de3 346 updateBeaconPeriodCharacteristic();
rgrover1 220:e75e8ba1ff80 347 updateTxPowerLevelsCharacteristic();
rgrover1 220:e75e8ba1ff80 348 updateTxPowerModeCharacteristic();
rgrover1 211:f181effe5de3 349 }
rgrover1 211:f181effe5de3 350
rgrover1 214:7d79fa197212 351 void updateLockedStateCharacteristic(void) {
rgrover1 214:7d79fa197212 352 ble.updateCharacteristicValue(lockedStateChar.getValueAttribute().getHandle(), reinterpret_cast<uint8_t *>(&lockedState), sizeof(lockedState));
rgrover1 214:7d79fa197212 353 }
rgrover1 214:7d79fa197212 354
rgrover1 211:f181effe5de3 355 void updateURIDataCharacteristic(void) {
rgrover1 189:a23091b54ab5 356 ble.updateCharacteristicValue(uriDataChar.getValueAttribute().getHandle(), uriData, uriDataLength);
rgrover1 211:f181effe5de3 357 }
rgrover1 211:f181effe5de3 358
rgrover1 211:f181effe5de3 359 void updateFlagsCharacteristic(void) {
rgrover1 189:a23091b54ab5 360 ble.updateCharacteristicValue(flagsChar.getValueAttribute().getHandle(), &flags, 1 /* size */);
rgrover1 211:f181effe5de3 361 }
rgrover1 211:f181effe5de3 362
rgrover1 211:f181effe5de3 363 void updateBeaconPeriodCharacteristic(void) {
rgrover1 189:a23091b54ab5 364 ble.updateCharacteristicValue(beaconPeriodChar.getValueAttribute().getHandle(), reinterpret_cast<uint8_t *>(&beaconPeriod), sizeof(uint16_t));
rgrover1 189:a23091b54ab5 365 }
rgrover1 189:a23091b54ab5 366
rgrover1 218:8ae02569fab9 367 void updateTxPowerModeCharacteristic(void) {
rgrover1 220:e75e8ba1ff80 368 ble.updateCharacteristicValue(txPowerModeChar.getValueAttribute().getHandle(), reinterpret_cast<uint8_t *>(&txPowerMode), sizeof(uint8_t));
rgrover1 218:8ae02569fab9 369 }
rgrover1 218:8ae02569fab9 370
rgrover1 218:8ae02569fab9 371 void updateTxPowerLevelsCharacteristic(void) {
rgrover1 218:8ae02569fab9 372 ble.updateCharacteristicValue(txPowerLevelsChar.getValueAttribute().getHandle(), reinterpret_cast<uint8_t *>(powerLevels), NUM_POWER_MODES * sizeof(int8_t));
rgrover1 218:8ae02569fab9 373 }
rgrover1 218:8ae02569fab9 374
rgrover1 185:7cd70497aec8 375 private:
rgrover1 185:7cd70497aec8 376 /**
rgrover1 185:7cd70497aec8 377 * For debugging only.
rgrover1 185:7cd70497aec8 378 */
rgrover1 185:7cd70497aec8 379 void dumpEncodedSeviceData() const {
rgrover1 185:7cd70497aec8 380 printf("encoded: '");
rgrover1 185:7cd70497aec8 381 for (unsigned i = 0; i < payloadIndex; i++) {
rgrover1 185:7cd70497aec8 382 printf(" %02x", serviceDataPayload[i]);
rgrover1 185:7cd70497aec8 383 }
rgrover1 185:7cd70497aec8 384 printf("'\r\n");
rgrover1 185:7cd70497aec8 385 }
rgrover1 185:7cd70497aec8 386
rgrover1 171:6092e61690dc 387 private:
rgrover1 199:6b57874115f6 388 static const size_t MAX_SIZEOF_SERVICE_DATA_PAYLOAD = 18; /* Uri Data must be between 0 and 18 bytes in length. */
rgrover1 204:479f81fd5d3b 389 static const size_t MAX_SIZE_URI_DATA_CHAR_VALUE = 48; /* This is chosen arbitrarily. It should be large enough
rgrover1 204:479f81fd5d3b 390 * to hold any reasonable uncompressed URI. */
rgrover1 171:6092e61690dc 391
rgrover1 171:6092e61690dc 392 private:
rgrover1 206:49646c933822 393 BLEDevice &ble;
rgrover1 171:6092e61690dc 394
rgrover1 206:49646c933822 395 size_t payloadIndex;
rgrover1 206:49646c933822 396 uint8_t serviceDataPayload[MAX_SIZEOF_SERVICE_DATA_PAYLOAD];
rgrover1 206:49646c933822 397 bool initSucceeded;
rgrover1 182:d16f8c11816b 398
rgrover1 206:49646c933822 399 bool lockedState;
rgrover1 206:49646c933822 400 uint16_t uriDataLength;
rgrover1 206:49646c933822 401 uint8_t uriData[MAX_SIZE_URI_DATA_CHAR_VALUE];
rgrover1 206:49646c933822 402 uint8_t flags;
rgrover1 206:49646c933822 403 int8_t powerLevels[NUM_POWER_MODES];
rgrover1 218:8ae02569fab9 404 TXPowerModes_t txPowerMode;
rgrover1 206:49646c933822 405 uint16_t beaconPeriod;
rgrover1 206:49646c933822 406 bool resetFlag;
rgrover1 171:6092e61690dc 407
rgrover1 206:49646c933822 408 GattCharacteristic lockedStateChar;
rgrover1 206:49646c933822 409 GattCharacteristic uriDataChar;
rgrover1 206:49646c933822 410 GattCharacteristic flagsChar;
rgrover1 206:49646c933822 411 GattCharacteristic txPowerLevelsChar;
rgrover1 218:8ae02569fab9 412 GattCharacteristic txPowerModeChar;
rgrover1 206:49646c933822 413 GattCharacteristic beaconPeriodChar;
rgrover1 206:49646c933822 414 GattCharacteristic resetChar;
rgrover1 171:6092e61690dc 415 };
rgrover1 171:6092e61690dc 416
rgrover1 207:e88130dc254c 417 #endif /* #ifndef __BLE_URI_BEACON_CONFIG_SERVICE_H__*/