I don't know why this is happening.

Fork of BLE_API by Bluetooth Low Energy

Committer:
rgrover1
Date:
Thu Jul 02 09:06:11 2015 +0100
Revision:
715:6d415ac147aa
Parent:
714:a6130aaa0fd9
Synchronized with git rev 69726547
Author: Rohit Grover
Release 0.3.9
=============

A minor patch to fix a build error introduced by the previous
release. This has to do with certain declarations being made members
of class UUID.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
rgrover1 714:a6130aaa0fd9 1 /* mbed Microcontroller Library
rgrover1 714:a6130aaa0fd9 2 * Copyright (c) 2006-2013 ARM Limited
rgrover1 714:a6130aaa0fd9 3 *
rgrover1 714:a6130aaa0fd9 4 * Licensed under the Apache License, Version 2.0 (the "License");
rgrover1 714:a6130aaa0fd9 5 * you may not use this file except in compliance with the License.
rgrover1 714:a6130aaa0fd9 6 * You may obtain a copy of the License at
rgrover1 714:a6130aaa0fd9 7 *
rgrover1 714:a6130aaa0fd9 8 * http://www.apache.org/licenses/LICENSE-2.0
rgrover1 714:a6130aaa0fd9 9 *
rgrover1 714:a6130aaa0fd9 10 * Unless required by applicable law or agreed to in writing, software
rgrover1 714:a6130aaa0fd9 11 * distributed under the License is distributed on an "AS IS" BASIS,
rgrover1 714:a6130aaa0fd9 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
rgrover1 714:a6130aaa0fd9 13 * See the License for the specific language governing permissions and
rgrover1 714:a6130aaa0fd9 14 * limitations under the License.
rgrover1 714:a6130aaa0fd9 15 */
rgrover1 714:a6130aaa0fd9 16
rgrover1 714:a6130aaa0fd9 17 #ifndef SERVICES_URIBEACONCONFIGSERVICE_H_
rgrover1 714:a6130aaa0fd9 18 #define SERVICES_URIBEACONCONFIGSERVICE_H_
rgrover1 714:a6130aaa0fd9 19
rgrover1 714:a6130aaa0fd9 20 #include "BLEDevice.h"
rgrover1 714:a6130aaa0fd9 21 #include "mbed.h"
rgrover1 714:a6130aaa0fd9 22
rgrover1 715:6d415ac147aa 23 extern const uint8_t UUID_URI_BEACON_SERVICE[UUID::LENGTH_OF_LONG_UUID];
rgrover1 715:6d415ac147aa 24 extern const uint8_t UUID_LOCK_STATE_CHAR[UUID::LENGTH_OF_LONG_UUID];
rgrover1 715:6d415ac147aa 25 extern const uint8_t UUID_LOCK_CHAR[UUID::LENGTH_OF_LONG_UUID];
rgrover1 715:6d415ac147aa 26 extern const uint8_t UUID_UNLOCK_CHAR[UUID::LENGTH_OF_LONG_UUID];
rgrover1 715:6d415ac147aa 27 extern const uint8_t UUID_URI_DATA_CHAR[UUID::LENGTH_OF_LONG_UUID];
rgrover1 715:6d415ac147aa 28 extern const uint8_t UUID_FLAGS_CHAR[UUID::LENGTH_OF_LONG_UUID];
rgrover1 715:6d415ac147aa 29 extern const uint8_t UUID_ADV_POWER_LEVELS_CHAR[UUID::LENGTH_OF_LONG_UUID];
rgrover1 715:6d415ac147aa 30 extern const uint8_t UUID_TX_POWER_MODE_CHAR[UUID::LENGTH_OF_LONG_UUID];
rgrover1 715:6d415ac147aa 31 extern const uint8_t UUID_BEACON_PERIOD_CHAR[UUID::LENGTH_OF_LONG_UUID];
rgrover1 715:6d415ac147aa 32 extern const uint8_t UUID_RESET_CHAR[UUID::LENGTH_OF_LONG_UUID];
rgrover1 714:a6130aaa0fd9 33
rgrover1 715:6d415ac147aa 34 extern const uint8_t BEACON_UUID[sizeof(UUID::ShortUUIDBytes_t)];
rgrover1 714:a6130aaa0fd9 35
rgrover1 714:a6130aaa0fd9 36 /**
rgrover1 714:a6130aaa0fd9 37 * @class URIBeaconConfigService
rgrover1 714:a6130aaa0fd9 38 * @brief UriBeacon Configuration Service. Can be used to set URL, adjust power levels, and set flags.
rgrover1 714:a6130aaa0fd9 39 * See http://uribeacon.org
rgrover1 714:a6130aaa0fd9 40 *
rgrover1 714:a6130aaa0fd9 41 */
rgrover1 714:a6130aaa0fd9 42 class URIBeaconConfigService {
rgrover1 714:a6130aaa0fd9 43 public:
rgrover1 714:a6130aaa0fd9 44 /**
rgrover1 714:a6130aaa0fd9 45 * @brief Transmission Power Modes for UriBeacon
rgrover1 714:a6130aaa0fd9 46 */
rgrover1 714:a6130aaa0fd9 47 static const uint8_t TX_POWER_MODE_LOWEST = 0; /*!< Lowest TX power mode */
rgrover1 714:a6130aaa0fd9 48 static const uint8_t TX_POWER_MODE_LOW = 1; /*!< Low TX power mode */
rgrover1 714:a6130aaa0fd9 49 static const uint8_t TX_POWER_MODE_MEDIUM = 2; /*!< Medium TX power mode */
rgrover1 714:a6130aaa0fd9 50 static const uint8_t TX_POWER_MODE_HIGH = 3; /*!< High TX power mode */
rgrover1 714:a6130aaa0fd9 51 static const unsigned NUM_POWER_MODES = 4; /*!< Number of Power Modes defined */
rgrover1 714:a6130aaa0fd9 52
rgrover1 714:a6130aaa0fd9 53 static const int ADVERTISING_INTERVAL_MSEC = 1000; // Advertising interval for config service.
rgrover1 714:a6130aaa0fd9 54 static const int SERVICE_DATA_MAX = 31; // Maximum size of service data in ADV packets
rgrover1 714:a6130aaa0fd9 55
rgrover1 714:a6130aaa0fd9 56 typedef uint8_t Lock_t[16]; /* 128 bits */
rgrover1 714:a6130aaa0fd9 57 typedef int8_t PowerLevels_t[NUM_POWER_MODES];
rgrover1 714:a6130aaa0fd9 58
rgrover1 714:a6130aaa0fd9 59 static const int URI_DATA_MAX = 18;
rgrover1 714:a6130aaa0fd9 60 typedef uint8_t UriData_t[URI_DATA_MAX];
rgrover1 714:a6130aaa0fd9 61
rgrover1 714:a6130aaa0fd9 62 struct Params_t {
rgrover1 714:a6130aaa0fd9 63 Lock_t lock;
rgrover1 714:a6130aaa0fd9 64 uint8_t uriDataLength;
rgrover1 714:a6130aaa0fd9 65 UriData_t uriData;
rgrover1 714:a6130aaa0fd9 66 uint8_t flags;
rgrover1 714:a6130aaa0fd9 67 PowerLevels_t advPowerLevels; // Current value of AdvertisedPowerLevels
rgrover1 714:a6130aaa0fd9 68 uint8_t txPowerMode; // Firmware power levels used with setTxPower()
rgrover1 714:a6130aaa0fd9 69 uint16_t beaconPeriod;
rgrover1 714:a6130aaa0fd9 70 };
rgrover1 714:a6130aaa0fd9 71
rgrover1 714:a6130aaa0fd9 72 /**
rgrover1 714:a6130aaa0fd9 73 * @param[ref] ble
rgrover1 714:a6130aaa0fd9 74 * BLEDevice object for the underlying controller.
rgrover1 714:a6130aaa0fd9 75 * @param[in/out] paramsIn
rgrover1 714:a6130aaa0fd9 76 * Reference to application-visible beacon state, loaded
rgrover1 714:a6130aaa0fd9 77 * from persistent storage at startup.
rgrover1 714:a6130aaa0fd9 78 * @paramsP[in] resetToDefaultsFlag
rgrover1 714:a6130aaa0fd9 79 * Applies to the state of the 'paramsIn' parameter.
rgrover1 714:a6130aaa0fd9 80 * If true, it indicates that paramsIn is potentially
rgrover1 714:a6130aaa0fd9 81 * un-initialized, and default values should be used
rgrover1 714:a6130aaa0fd9 82 * instead. Otherwise, paramsIn overrides the defaults.
rgrover1 714:a6130aaa0fd9 83 * @param[in] defaultUriDataIn
rgrover1 714:a6130aaa0fd9 84 * Default un-encoded URI; applies only if the resetToDefaultsFlag is true.
rgrover1 714:a6130aaa0fd9 85 * @param[in] defaultAdvPowerLevelsIn
rgrover1 714:a6130aaa0fd9 86 * Default power-levels array; applies only if the resetToDefaultsFlag is true.
rgrover1 714:a6130aaa0fd9 87 */
rgrover1 714:a6130aaa0fd9 88 URIBeaconConfigService(BLEDevice &bleIn,
rgrover1 714:a6130aaa0fd9 89 Params_t &paramsIn,
rgrover1 714:a6130aaa0fd9 90 bool resetToDefaultsFlag,
rgrover1 714:a6130aaa0fd9 91 const char *defaultURIDataIn,
rgrover1 714:a6130aaa0fd9 92 PowerLevels_t &defaultAdvPowerLevelsIn) :
rgrover1 714:a6130aaa0fd9 93 ble(bleIn),
rgrover1 714:a6130aaa0fd9 94 params(paramsIn),
rgrover1 714:a6130aaa0fd9 95 defaultUriDataLength(),
rgrover1 714:a6130aaa0fd9 96 defaultUriData(),
rgrover1 714:a6130aaa0fd9 97 defaultAdvPowerLevels(defaultAdvPowerLevelsIn),
rgrover1 714:a6130aaa0fd9 98 initSucceeded(false),
rgrover1 714:a6130aaa0fd9 99 resetFlag(),
rgrover1 714:a6130aaa0fd9 100 lockedStateChar(UUID_LOCK_STATE_CHAR, &lockedState),
rgrover1 714:a6130aaa0fd9 101 lockChar(UUID_LOCK_CHAR, &params.lock),
rgrover1 714:a6130aaa0fd9 102 uriDataChar(UUID_URI_DATA_CHAR, params.uriData, 0, URI_DATA_MAX,
rgrover1 714:a6130aaa0fd9 103 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE),
rgrover1 714:a6130aaa0fd9 104 unlockChar(UUID_UNLOCK_CHAR, &params.lock),
rgrover1 714:a6130aaa0fd9 105 flagsChar(UUID_FLAGS_CHAR, &params.flags),
rgrover1 714:a6130aaa0fd9 106 advPowerLevelsChar(UUID_ADV_POWER_LEVELS_CHAR, &params.advPowerLevels),
rgrover1 714:a6130aaa0fd9 107 txPowerModeChar(UUID_TX_POWER_MODE_CHAR, &params.txPowerMode),
rgrover1 714:a6130aaa0fd9 108 beaconPeriodChar(UUID_BEACON_PERIOD_CHAR, &params.beaconPeriod),
rgrover1 714:a6130aaa0fd9 109 resetChar(UUID_RESET_CHAR, &resetFlag) {
rgrover1 714:a6130aaa0fd9 110
rgrover1 714:a6130aaa0fd9 111 encodeURI(defaultURIDataIn, defaultUriData, defaultUriDataLength);
rgrover1 714:a6130aaa0fd9 112 if (defaultUriDataLength > URI_DATA_MAX) {
rgrover1 714:a6130aaa0fd9 113 return;
rgrover1 714:a6130aaa0fd9 114 }
rgrover1 714:a6130aaa0fd9 115
rgrover1 714:a6130aaa0fd9 116 if (!resetToDefaultsFlag && (params.uriDataLength > URI_DATA_MAX)) {
rgrover1 714:a6130aaa0fd9 117 resetToDefaultsFlag = true;
rgrover1 714:a6130aaa0fd9 118 }
rgrover1 714:a6130aaa0fd9 119 if (resetToDefaultsFlag) {
rgrover1 714:a6130aaa0fd9 120 resetToDefaults();
rgrover1 714:a6130aaa0fd9 121 } else {
rgrover1 714:a6130aaa0fd9 122 updateCharacteristicValues();
rgrover1 714:a6130aaa0fd9 123 }
rgrover1 714:a6130aaa0fd9 124
rgrover1 714:a6130aaa0fd9 125 lockedState = isLocked();
rgrover1 714:a6130aaa0fd9 126
rgrover1 714:a6130aaa0fd9 127 lockChar.setWriteAuthorizationCallback(this, &URIBeaconConfigService::lockAuthorizationCallback);
rgrover1 714:a6130aaa0fd9 128 unlockChar.setWriteAuthorizationCallback(this, &URIBeaconConfigService::unlockAuthorizationCallback);
rgrover1 714:a6130aaa0fd9 129 uriDataChar.setWriteAuthorizationCallback(this, &URIBeaconConfigService::uriDataWriteAuthorizationCallback);
rgrover1 714:a6130aaa0fd9 130 flagsChar.setWriteAuthorizationCallback(this, &URIBeaconConfigService::basicAuthorizationCallback<uint8_t>);
rgrover1 714:a6130aaa0fd9 131 advPowerLevelsChar.setWriteAuthorizationCallback(this, &URIBeaconConfigService::basicAuthorizationCallback<PowerLevels_t>);
rgrover1 714:a6130aaa0fd9 132 txPowerModeChar.setWriteAuthorizationCallback(this, &URIBeaconConfigService::powerModeAuthorizationCallback);
rgrover1 714:a6130aaa0fd9 133 beaconPeriodChar.setWriteAuthorizationCallback(this, &URIBeaconConfigService::basicAuthorizationCallback<uint16_t>);
rgrover1 714:a6130aaa0fd9 134 resetChar.setWriteAuthorizationCallback(this, &URIBeaconConfigService::basicAuthorizationCallback<uint8_t>);
rgrover1 714:a6130aaa0fd9 135
rgrover1 714:a6130aaa0fd9 136 static GattCharacteristic *charTable[] = {
rgrover1 714:a6130aaa0fd9 137 &lockedStateChar, &lockChar, &unlockChar, &uriDataChar,
rgrover1 714:a6130aaa0fd9 138 &flagsChar, &advPowerLevelsChar, &txPowerModeChar, &beaconPeriodChar, &resetChar
rgrover1 714:a6130aaa0fd9 139 };
rgrover1 714:a6130aaa0fd9 140
rgrover1 714:a6130aaa0fd9 141 GattService configService(UUID_URI_BEACON_SERVICE, charTable, sizeof(charTable) / sizeof(GattCharacteristic *));
rgrover1 714:a6130aaa0fd9 142
rgrover1 714:a6130aaa0fd9 143 ble.addService(configService);
rgrover1 714:a6130aaa0fd9 144 ble.onDataWritten(this, &URIBeaconConfigService::onDataWrittenCallback);
rgrover1 714:a6130aaa0fd9 145
rgrover1 714:a6130aaa0fd9 146 setupURIBeaconConfigAdvertisements(); /* Setup advertising for the configService. */
rgrover1 714:a6130aaa0fd9 147
rgrover1 714:a6130aaa0fd9 148 initSucceeded = true;
rgrover1 714:a6130aaa0fd9 149 }
rgrover1 714:a6130aaa0fd9 150
rgrover1 714:a6130aaa0fd9 151 bool configuredSuccessfully(void) const {
rgrover1 714:a6130aaa0fd9 152 return initSucceeded;
rgrover1 714:a6130aaa0fd9 153 }
rgrover1 714:a6130aaa0fd9 154
rgrover1 714:a6130aaa0fd9 155 /* Start out by advertising the configService for a limited time after
rgrover1 714:a6130aaa0fd9 156 * startup; and switch to the normal non-connectible beacon functionality
rgrover1 714:a6130aaa0fd9 157 * afterwards. */
rgrover1 714:a6130aaa0fd9 158 void setupURIBeaconConfigAdvertisements()
rgrover1 714:a6130aaa0fd9 159 {
rgrover1 714:a6130aaa0fd9 160 const char DEVICE_NAME[] = "mUriBeacon Config";
rgrover1 714:a6130aaa0fd9 161
rgrover1 714:a6130aaa0fd9 162 ble.clearAdvertisingPayload();
rgrover1 714:a6130aaa0fd9 163
rgrover1 714:a6130aaa0fd9 164 ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
rgrover1 714:a6130aaa0fd9 165
rgrover1 714:a6130aaa0fd9 166 // UUID is in different order in the ADV frame (!)
rgrover1 714:a6130aaa0fd9 167 uint8_t reversedServiceUUID[sizeof(UUID_URI_BEACON_SERVICE)];
rgrover1 714:a6130aaa0fd9 168 for (unsigned int i = 0; i < sizeof(UUID_URI_BEACON_SERVICE); i++) {
rgrover1 714:a6130aaa0fd9 169 reversedServiceUUID[i] = UUID_URI_BEACON_SERVICE[sizeof(UUID_URI_BEACON_SERVICE) - i - 1];
rgrover1 714:a6130aaa0fd9 170 }
rgrover1 714:a6130aaa0fd9 171 ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS, reversedServiceUUID, sizeof(reversedServiceUUID));
rgrover1 714:a6130aaa0fd9 172 ble.accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_TAG);
rgrover1 714:a6130aaa0fd9 173 ble.accumulateScanResponse(GapAdvertisingData::COMPLETE_LOCAL_NAME, reinterpret_cast<const uint8_t *>(&DEVICE_NAME), sizeof(DEVICE_NAME));
rgrover1 714:a6130aaa0fd9 174 ble.accumulateScanResponse(GapAdvertisingData::TX_POWER_LEVEL,
rgrover1 714:a6130aaa0fd9 175 reinterpret_cast<uint8_t *>(&defaultAdvPowerLevels[URIBeaconConfigService::TX_POWER_MODE_LOW]),
rgrover1 714:a6130aaa0fd9 176 sizeof(uint8_t));
rgrover1 714:a6130aaa0fd9 177
rgrover1 714:a6130aaa0fd9 178 ble.setTxPower(params.advPowerLevels[params.txPowerMode]);
rgrover1 714:a6130aaa0fd9 179 ble.setDeviceName(reinterpret_cast<const uint8_t *>(&DEVICE_NAME));
rgrover1 714:a6130aaa0fd9 180 ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
rgrover1 714:a6130aaa0fd9 181 ble.setAdvertisingInterval(Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(ADVERTISING_INTERVAL_MSEC));
rgrover1 714:a6130aaa0fd9 182 }
rgrover1 714:a6130aaa0fd9 183
rgrover1 714:a6130aaa0fd9 184 /* Helper function to switch to the non-connectible normal mode for URIBeacon. This gets called after a timeout. */
rgrover1 714:a6130aaa0fd9 185 void setupURIBeaconAdvertisements()
rgrover1 714:a6130aaa0fd9 186 {
rgrover1 714:a6130aaa0fd9 187 uint8_t serviceData[SERVICE_DATA_MAX];
rgrover1 714:a6130aaa0fd9 188 unsigned serviceDataLen = 0;
rgrover1 714:a6130aaa0fd9 189
rgrover1 714:a6130aaa0fd9 190 /* Reinitialize the BLE stack. This will clear away the existing services and advertising state. */
rgrover1 714:a6130aaa0fd9 191 ble.shutdown();
rgrover1 714:a6130aaa0fd9 192 ble.init();
rgrover1 714:a6130aaa0fd9 193
rgrover1 714:a6130aaa0fd9 194 // Fields from the Service
rgrover1 714:a6130aaa0fd9 195 unsigned beaconPeriod = params.beaconPeriod;
rgrover1 714:a6130aaa0fd9 196 unsigned txPowerMode = params.txPowerMode;
rgrover1 714:a6130aaa0fd9 197 unsigned uriDataLength = params.uriDataLength;
rgrover1 714:a6130aaa0fd9 198 URIBeaconConfigService::UriData_t &uriData = params.uriData;
rgrover1 714:a6130aaa0fd9 199 URIBeaconConfigService::PowerLevels_t &advPowerLevels = params.advPowerLevels;
rgrover1 714:a6130aaa0fd9 200 uint8_t flags = params.flags;
rgrover1 714:a6130aaa0fd9 201
rgrover1 714:a6130aaa0fd9 202 extern void saveURIBeaconConfigParams(const Params_t *paramsP); /* forward declaration; necessary to avoid a circular dependency. */
rgrover1 714:a6130aaa0fd9 203 saveURIBeaconConfigParams(&params);
rgrover1 714:a6130aaa0fd9 204
rgrover1 714:a6130aaa0fd9 205 ble.clearAdvertisingPayload();
rgrover1 714:a6130aaa0fd9 206 ble.setTxPower(params.advPowerLevels[params.txPowerMode]);
rgrover1 714:a6130aaa0fd9 207 ble.setAdvertisingType(GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED);
rgrover1 714:a6130aaa0fd9 208 ble.setAdvertisingInterval(beaconPeriod);
rgrover1 714:a6130aaa0fd9 209 ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
rgrover1 714:a6130aaa0fd9 210 ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, BEACON_UUID, sizeof(BEACON_UUID));
rgrover1 714:a6130aaa0fd9 211
rgrover1 714:a6130aaa0fd9 212 serviceData[serviceDataLen++] = BEACON_UUID[0];
rgrover1 714:a6130aaa0fd9 213 serviceData[serviceDataLen++] = BEACON_UUID[1];
rgrover1 714:a6130aaa0fd9 214 serviceData[serviceDataLen++] = flags;
rgrover1 714:a6130aaa0fd9 215 serviceData[serviceDataLen++] = advPowerLevels[txPowerMode];
rgrover1 714:a6130aaa0fd9 216 for (unsigned j = 0; j < uriDataLength; j++) {
rgrover1 714:a6130aaa0fd9 217 serviceData[serviceDataLen++] = uriData[j];
rgrover1 714:a6130aaa0fd9 218 }
rgrover1 714:a6130aaa0fd9 219 ble.accumulateAdvertisingPayload(GapAdvertisingData::SERVICE_DATA, serviceData, serviceDataLen);
rgrover1 714:a6130aaa0fd9 220 }
rgrover1 714:a6130aaa0fd9 221
rgrover1 714:a6130aaa0fd9 222 private:
rgrover1 714:a6130aaa0fd9 223 // True if the lock bits are non-zero
rgrover1 714:a6130aaa0fd9 224 bool isLocked() {
rgrover1 714:a6130aaa0fd9 225 Lock_t testLock;
rgrover1 714:a6130aaa0fd9 226 memset(testLock, 0, sizeof(Lock_t));
rgrover1 714:a6130aaa0fd9 227 return memcmp(params.lock, testLock, sizeof(Lock_t));
rgrover1 714:a6130aaa0fd9 228 }
rgrover1 714:a6130aaa0fd9 229
rgrover1 714:a6130aaa0fd9 230 /*
rgrover1 714:a6130aaa0fd9 231 * This callback is invoked when a GATT client attempts to modify any of the
rgrover1 714:a6130aaa0fd9 232 * characteristics of this service. Attempts to do so are also applied to
rgrover1 714:a6130aaa0fd9 233 * the internal state of this service object.
rgrover1 714:a6130aaa0fd9 234 */
rgrover1 714:a6130aaa0fd9 235 void onDataWrittenCallback(const GattCharacteristicWriteCBParams *writeParams) {
rgrover1 714:a6130aaa0fd9 236 uint16_t handle = writeParams->charHandle;
rgrover1 714:a6130aaa0fd9 237
rgrover1 714:a6130aaa0fd9 238 if (handle == lockChar.getValueHandle()) {
rgrover1 714:a6130aaa0fd9 239 // Validated earlier
rgrover1 714:a6130aaa0fd9 240 memcpy(params.lock, writeParams->data, sizeof(Lock_t));
rgrover1 714:a6130aaa0fd9 241 // use isLocked() in case bits are being set to all 0's
rgrover1 714:a6130aaa0fd9 242 lockedState = isLocked();
rgrover1 714:a6130aaa0fd9 243 } else if (handle == unlockChar.getValueHandle()) {
rgrover1 714:a6130aaa0fd9 244 // Validated earlier
rgrover1 714:a6130aaa0fd9 245 memset(params.lock, 0, sizeof(Lock_t));
rgrover1 714:a6130aaa0fd9 246 lockedState = false;
rgrover1 714:a6130aaa0fd9 247 } else if (handle == uriDataChar.getValueHandle()) {
rgrover1 714:a6130aaa0fd9 248 params.uriDataLength = writeParams->len;
rgrover1 714:a6130aaa0fd9 249 memcpy(params.uriData, writeParams->data, params.uriDataLength);
rgrover1 714:a6130aaa0fd9 250 } else if (handle == flagsChar.getValueHandle()) {
rgrover1 714:a6130aaa0fd9 251 params.flags = *(writeParams->data);
rgrover1 714:a6130aaa0fd9 252 } else if (handle == advPowerLevelsChar.getValueHandle()) {
rgrover1 714:a6130aaa0fd9 253 memcpy(params.advPowerLevels, writeParams->data, sizeof(PowerLevels_t));
rgrover1 714:a6130aaa0fd9 254 } else if (handle == txPowerModeChar.getValueHandle()) {
rgrover1 714:a6130aaa0fd9 255 params.txPowerMode = *(writeParams->data);
rgrover1 714:a6130aaa0fd9 256 } else if (handle == beaconPeriodChar.getValueHandle()) {
rgrover1 714:a6130aaa0fd9 257 params.beaconPeriod = *((uint16_t *)(writeParams->data));
rgrover1 714:a6130aaa0fd9 258
rgrover1 714:a6130aaa0fd9 259 /* Re-map beaconPeriod to within permissible bounds if necessary. */
rgrover1 714:a6130aaa0fd9 260 if (params.beaconPeriod != 0) {
rgrover1 714:a6130aaa0fd9 261 bool paramsUpdated = false;
rgrover1 714:a6130aaa0fd9 262 if (params.beaconPeriod < ble.getMinAdvertisingInterval()) {
rgrover1 714:a6130aaa0fd9 263 params.beaconPeriod = ble.getMinAdvertisingInterval();
rgrover1 714:a6130aaa0fd9 264 paramsUpdated = true;
rgrover1 714:a6130aaa0fd9 265 } else if (params.beaconPeriod > ble.getMaxAdvertisingInterval()) {
rgrover1 714:a6130aaa0fd9 266 params.beaconPeriod = ble.getMaxAdvertisingInterval();
rgrover1 714:a6130aaa0fd9 267 paramsUpdated = true;
rgrover1 714:a6130aaa0fd9 268 }
rgrover1 714:a6130aaa0fd9 269 if (paramsUpdated) {
rgrover1 714:a6130aaa0fd9 270 ble.updateCharacteristicValue(beaconPeriodChar.getValueHandle(), reinterpret_cast<uint8_t *>(&params.beaconPeriod), sizeof(uint16_t));
rgrover1 714:a6130aaa0fd9 271 }
rgrover1 714:a6130aaa0fd9 272 }
rgrover1 714:a6130aaa0fd9 273 } else if (handle == resetChar.getValueHandle()) {
rgrover1 714:a6130aaa0fd9 274 resetToDefaults();
rgrover1 714:a6130aaa0fd9 275 }
rgrover1 714:a6130aaa0fd9 276 }
rgrover1 714:a6130aaa0fd9 277
rgrover1 714:a6130aaa0fd9 278 /*
rgrover1 714:a6130aaa0fd9 279 * Reset the default values.
rgrover1 714:a6130aaa0fd9 280 */
rgrover1 714:a6130aaa0fd9 281 void resetToDefaults(void) {
rgrover1 714:a6130aaa0fd9 282 lockedState = false;
rgrover1 714:a6130aaa0fd9 283 memset(params.lock, 0, sizeof(Lock_t));
rgrover1 714:a6130aaa0fd9 284 memcpy(params.uriData, defaultUriData, URI_DATA_MAX);
rgrover1 714:a6130aaa0fd9 285 params.uriDataLength = defaultUriDataLength;
rgrover1 714:a6130aaa0fd9 286 params.flags = 0;
rgrover1 714:a6130aaa0fd9 287 memcpy(params.advPowerLevels, defaultAdvPowerLevels, sizeof(PowerLevels_t));
rgrover1 714:a6130aaa0fd9 288 params.txPowerMode = TX_POWER_MODE_LOW;
rgrover1 714:a6130aaa0fd9 289 params.beaconPeriod = 1000;
rgrover1 714:a6130aaa0fd9 290 updateCharacteristicValues();
rgrover1 714:a6130aaa0fd9 291 }
rgrover1 714:a6130aaa0fd9 292
rgrover1 714:a6130aaa0fd9 293 /*
rgrover1 714:a6130aaa0fd9 294 * Internal helper function used to update the GATT database following any
rgrover1 714:a6130aaa0fd9 295 * change to the internal state of the service object.
rgrover1 714:a6130aaa0fd9 296 */
rgrover1 714:a6130aaa0fd9 297 void updateCharacteristicValues(void) {
rgrover1 714:a6130aaa0fd9 298 ble.updateCharacteristicValue(lockedStateChar.getValueHandle(), &lockedState, 1);
rgrover1 714:a6130aaa0fd9 299 ble.updateCharacteristicValue(uriDataChar.getValueHandle(), params.uriData, params.uriDataLength);
rgrover1 714:a6130aaa0fd9 300 ble.updateCharacteristicValue(flagsChar.getValueHandle(), &params.flags, 1);
rgrover1 714:a6130aaa0fd9 301 ble.updateCharacteristicValue(beaconPeriodChar.getValueHandle(),
rgrover1 714:a6130aaa0fd9 302 reinterpret_cast<uint8_t *>(&params.beaconPeriod), sizeof(uint16_t));
rgrover1 714:a6130aaa0fd9 303 ble.updateCharacteristicValue(txPowerModeChar.getValueHandle(), &params.txPowerMode, 1);
rgrover1 714:a6130aaa0fd9 304 ble.updateCharacteristicValue(advPowerLevelsChar.getValueHandle(),
rgrover1 714:a6130aaa0fd9 305 reinterpret_cast<uint8_t *>(params.advPowerLevels), sizeof(PowerLevels_t));
rgrover1 714:a6130aaa0fd9 306 }
rgrover1 714:a6130aaa0fd9 307
rgrover1 714:a6130aaa0fd9 308 private:
rgrover1 714:a6130aaa0fd9 309 void lockAuthorizationCallback(GattCharacteristicWriteAuthCBParams *authParams) {
rgrover1 714:a6130aaa0fd9 310 if (lockedState) {
rgrover1 714:a6130aaa0fd9 311 authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INSUF_AUTHORIZATION;
rgrover1 714:a6130aaa0fd9 312 } else if (authParams->len != sizeof(Lock_t)) {
rgrover1 714:a6130aaa0fd9 313 authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_ATT_VAL_LENGTH;
rgrover1 714:a6130aaa0fd9 314 } else if (authParams->offset != 0) {
rgrover1 714:a6130aaa0fd9 315 authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_OFFSET;
rgrover1 714:a6130aaa0fd9 316 } else {
rgrover1 714:a6130aaa0fd9 317 authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
rgrover1 714:a6130aaa0fd9 318 }
rgrover1 714:a6130aaa0fd9 319 }
rgrover1 714:a6130aaa0fd9 320
rgrover1 714:a6130aaa0fd9 321
rgrover1 714:a6130aaa0fd9 322 void unlockAuthorizationCallback(GattCharacteristicWriteAuthCBParams *authParams) {
rgrover1 714:a6130aaa0fd9 323 if (!lockedState) {
rgrover1 714:a6130aaa0fd9 324 authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
rgrover1 714:a6130aaa0fd9 325 } else if (authParams->len != sizeof(Lock_t)) {
rgrover1 714:a6130aaa0fd9 326 authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_ATT_VAL_LENGTH;
rgrover1 714:a6130aaa0fd9 327 } else if (authParams->offset != 0) {
rgrover1 714:a6130aaa0fd9 328 authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_OFFSET;
rgrover1 714:a6130aaa0fd9 329 } else if (memcmp(authParams->data, params.lock, sizeof(Lock_t)) != 0) {
rgrover1 714:a6130aaa0fd9 330 authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INSUF_AUTHORIZATION;
rgrover1 714:a6130aaa0fd9 331 } else {
rgrover1 714:a6130aaa0fd9 332 authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
rgrover1 714:a6130aaa0fd9 333 }
rgrover1 714:a6130aaa0fd9 334 }
rgrover1 714:a6130aaa0fd9 335
rgrover1 714:a6130aaa0fd9 336 void uriDataWriteAuthorizationCallback(GattCharacteristicWriteAuthCBParams *authParams) {
rgrover1 714:a6130aaa0fd9 337 if (lockedState) {
rgrover1 714:a6130aaa0fd9 338 authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INSUF_AUTHORIZATION;
rgrover1 714:a6130aaa0fd9 339 } else if (authParams->offset != 0) {
rgrover1 714:a6130aaa0fd9 340 authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_OFFSET;
rgrover1 714:a6130aaa0fd9 341 } else {
rgrover1 714:a6130aaa0fd9 342 authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
rgrover1 714:a6130aaa0fd9 343 }
rgrover1 714:a6130aaa0fd9 344 }
rgrover1 714:a6130aaa0fd9 345
rgrover1 714:a6130aaa0fd9 346 void powerModeAuthorizationCallback(GattCharacteristicWriteAuthCBParams *authParams) {
rgrover1 714:a6130aaa0fd9 347 if (lockedState) {
rgrover1 714:a6130aaa0fd9 348 authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INSUF_AUTHORIZATION;
rgrover1 714:a6130aaa0fd9 349 } else if (authParams->len != sizeof(uint8_t)) {
rgrover1 714:a6130aaa0fd9 350 authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_ATT_VAL_LENGTH;
rgrover1 714:a6130aaa0fd9 351 } else if (authParams->offset != 0) {
rgrover1 714:a6130aaa0fd9 352 authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_OFFSET;
rgrover1 714:a6130aaa0fd9 353 } else if (*((uint8_t *)authParams->data) >= NUM_POWER_MODES) {
rgrover1 714:a6130aaa0fd9 354 authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_WRITE_NOT_PERMITTED;
rgrover1 714:a6130aaa0fd9 355 } else {
rgrover1 714:a6130aaa0fd9 356 authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
rgrover1 714:a6130aaa0fd9 357 }
rgrover1 714:a6130aaa0fd9 358 }
rgrover1 714:a6130aaa0fd9 359
rgrover1 714:a6130aaa0fd9 360 template <typename T>
rgrover1 714:a6130aaa0fd9 361 void basicAuthorizationCallback(GattCharacteristicWriteAuthCBParams *authParams) {
rgrover1 714:a6130aaa0fd9 362 if (lockedState) {
rgrover1 714:a6130aaa0fd9 363 authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INSUF_AUTHORIZATION;
rgrover1 714:a6130aaa0fd9 364 } else if (authParams->len != sizeof(T)) {
rgrover1 714:a6130aaa0fd9 365 authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_ATT_VAL_LENGTH;
rgrover1 714:a6130aaa0fd9 366 } else if (authParams->offset != 0) {
rgrover1 714:a6130aaa0fd9 367 authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_OFFSET;
rgrover1 714:a6130aaa0fd9 368 } else {
rgrover1 714:a6130aaa0fd9 369 authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
rgrover1 714:a6130aaa0fd9 370 }
rgrover1 714:a6130aaa0fd9 371 }
rgrover1 714:a6130aaa0fd9 372
rgrover1 714:a6130aaa0fd9 373 BLEDevice &ble;
rgrover1 714:a6130aaa0fd9 374 Params_t &params;
rgrover1 714:a6130aaa0fd9 375
rgrover1 714:a6130aaa0fd9 376 size_t defaultUriDataLength; // Default value that is restored on reset
rgrover1 714:a6130aaa0fd9 377 UriData_t defaultUriData; // Default value that is restored on reset
rgrover1 714:a6130aaa0fd9 378 PowerLevels_t &defaultAdvPowerLevels; // Default value that is restored on reset
rgrover1 714:a6130aaa0fd9 379
rgrover1 714:a6130aaa0fd9 380 uint8_t lockedState;
rgrover1 714:a6130aaa0fd9 381 bool initSucceeded;
rgrover1 714:a6130aaa0fd9 382 uint8_t resetFlag;
rgrover1 714:a6130aaa0fd9 383
rgrover1 714:a6130aaa0fd9 384 ReadOnlyGattCharacteristic<uint8_t> lockedStateChar;
rgrover1 714:a6130aaa0fd9 385 WriteOnlyGattCharacteristic<Lock_t> lockChar;
rgrover1 714:a6130aaa0fd9 386 GattCharacteristic uriDataChar;
rgrover1 714:a6130aaa0fd9 387 WriteOnlyGattCharacteristic<Lock_t> unlockChar;
rgrover1 714:a6130aaa0fd9 388 ReadWriteGattCharacteristic<uint8_t> flagsChar;
rgrover1 714:a6130aaa0fd9 389 ReadWriteGattCharacteristic<PowerLevels_t> advPowerLevelsChar;
rgrover1 714:a6130aaa0fd9 390 ReadWriteGattCharacteristic<uint8_t> txPowerModeChar;
rgrover1 714:a6130aaa0fd9 391 ReadWriteGattCharacteristic<uint16_t> beaconPeriodChar;
rgrover1 714:a6130aaa0fd9 392 WriteOnlyGattCharacteristic<uint8_t> resetChar;
rgrover1 714:a6130aaa0fd9 393
rgrover1 714:a6130aaa0fd9 394 public:
rgrover1 714:a6130aaa0fd9 395 /*
rgrover1 714:a6130aaa0fd9 396 * Encode a human-readable URI into the binary format defined by URIBeacon spec (https://github.com/google/uribeacon/tree/master/specification).
rgrover1 714:a6130aaa0fd9 397 */
rgrover1 714:a6130aaa0fd9 398 static void encodeURI(const char *uriDataIn, UriData_t uriDataOut, size_t &sizeofURIDataOut) {
rgrover1 714:a6130aaa0fd9 399 const char *prefixes[] = {
rgrover1 714:a6130aaa0fd9 400 "http://www.",
rgrover1 714:a6130aaa0fd9 401 "https://www.",
rgrover1 714:a6130aaa0fd9 402 "http://",
rgrover1 714:a6130aaa0fd9 403 "https://",
rgrover1 714:a6130aaa0fd9 404 "urn:uuid:"
rgrover1 714:a6130aaa0fd9 405 };
rgrover1 714:a6130aaa0fd9 406 const size_t NUM_PREFIXES = sizeof(prefixes) / sizeof(char *);
rgrover1 714:a6130aaa0fd9 407 const char *suffixes[] = {
rgrover1 714:a6130aaa0fd9 408 ".com/",
rgrover1 714:a6130aaa0fd9 409 ".org/",
rgrover1 714:a6130aaa0fd9 410 ".edu/",
rgrover1 714:a6130aaa0fd9 411 ".net/",
rgrover1 714:a6130aaa0fd9 412 ".info/",
rgrover1 714:a6130aaa0fd9 413 ".biz/",
rgrover1 714:a6130aaa0fd9 414 ".gov/",
rgrover1 714:a6130aaa0fd9 415 ".com",
rgrover1 714:a6130aaa0fd9 416 ".org",
rgrover1 714:a6130aaa0fd9 417 ".edu",
rgrover1 714:a6130aaa0fd9 418 ".net",
rgrover1 714:a6130aaa0fd9 419 ".info",
rgrover1 714:a6130aaa0fd9 420 ".biz",
rgrover1 714:a6130aaa0fd9 421 ".gov"
rgrover1 714:a6130aaa0fd9 422 };
rgrover1 714:a6130aaa0fd9 423 const size_t NUM_SUFFIXES = sizeof(suffixes) / sizeof(char *);
rgrover1 714:a6130aaa0fd9 424
rgrover1 714:a6130aaa0fd9 425 sizeofURIDataOut = 0;
rgrover1 714:a6130aaa0fd9 426 memset(uriDataOut, 0, sizeof(UriData_t));
rgrover1 714:a6130aaa0fd9 427
rgrover1 714:a6130aaa0fd9 428 if ((uriDataIn == NULL) || (strlen(uriDataIn) == 0)) {
rgrover1 714:a6130aaa0fd9 429 return;
rgrover1 714:a6130aaa0fd9 430 }
rgrover1 714:a6130aaa0fd9 431
rgrover1 714:a6130aaa0fd9 432 /*
rgrover1 714:a6130aaa0fd9 433 * handle prefix
rgrover1 714:a6130aaa0fd9 434 */
rgrover1 714:a6130aaa0fd9 435 for (unsigned i = 0; i < NUM_PREFIXES; i++) {
rgrover1 714:a6130aaa0fd9 436 size_t prefixLen = strlen(prefixes[i]);
rgrover1 714:a6130aaa0fd9 437 if (strncmp(uriDataIn, prefixes[i], prefixLen) == 0) {
rgrover1 714:a6130aaa0fd9 438 uriDataOut[sizeofURIDataOut++] = i;
rgrover1 714:a6130aaa0fd9 439 uriDataIn += prefixLen;
rgrover1 714:a6130aaa0fd9 440 break;
rgrover1 714:a6130aaa0fd9 441 }
rgrover1 714:a6130aaa0fd9 442 }
rgrover1 714:a6130aaa0fd9 443
rgrover1 714:a6130aaa0fd9 444 /*
rgrover1 714:a6130aaa0fd9 445 * handle suffixes
rgrover1 714:a6130aaa0fd9 446 */
rgrover1 714:a6130aaa0fd9 447 while (*uriDataIn && (sizeofURIDataOut < URI_DATA_MAX)) {
rgrover1 714:a6130aaa0fd9 448 /* check for suffix match */
rgrover1 714:a6130aaa0fd9 449 unsigned i;
rgrover1 714:a6130aaa0fd9 450 for (i = 0; i < NUM_SUFFIXES; i++) {
rgrover1 714:a6130aaa0fd9 451 size_t suffixLen = strlen(suffixes[i]);
rgrover1 714:a6130aaa0fd9 452 if (strncmp(uriDataIn, suffixes[i], suffixLen) == 0) {
rgrover1 714:a6130aaa0fd9 453 uriDataOut[sizeofURIDataOut++] = i;
rgrover1 714:a6130aaa0fd9 454 uriDataIn += suffixLen;
rgrover1 714:a6130aaa0fd9 455 break; /* from the for loop for checking against suffixes */
rgrover1 714:a6130aaa0fd9 456 }
rgrover1 714:a6130aaa0fd9 457 }
rgrover1 714:a6130aaa0fd9 458 /* This is the default case where we've got an ordinary character which doesn't match a suffix. */
rgrover1 714:a6130aaa0fd9 459 if (i == NUM_SUFFIXES) {
rgrover1 714:a6130aaa0fd9 460 uriDataOut[sizeofURIDataOut++] = *uriDataIn;
rgrover1 714:a6130aaa0fd9 461 ++uriDataIn;
rgrover1 714:a6130aaa0fd9 462 }
rgrover1 714:a6130aaa0fd9 463 }
rgrover1 714:a6130aaa0fd9 464 }
rgrover1 714:a6130aaa0fd9 465 };
rgrover1 714:a6130aaa0fd9 466
rgrover1 714:a6130aaa0fd9 467 #endif // SERVICES_URIBEACONCONFIGSERVICE_H_