mbed-os-examples / Mbed OS mbed-os-example-ble-EddystoneService
Committer:
mbed_official
Date:
Thu Jul 28 23:14:36 2016 +0100
Revision:
1:9db4d46bb63f
Parent:
0:4c8f8bf32a99
Child:
2:9ee673e0b86a
Merge branch 'master' of https://github.com/ARMmbed/mbed-os-example-ble


Commit copied from ./src/github.com/ARMmbed/mbed-os-example-ble

Who changed what in which revision?

UserRevisionLine numberNew contents of line
mbed_official 1:9db4d46bb63f 1 /* mbed Microcontroller Library
mbed_official 1:9db4d46bb63f 2 * Copyright (c) 2006-2015 ARM Limited
mbed_official 1:9db4d46bb63f 3 *
mbed_official 1:9db4d46bb63f 4 * Licensed under the Apache License, Version 2.0 (the "License");
mbed_official 1:9db4d46bb63f 5 * you may not use this file except in compliance with the License.
mbed_official 1:9db4d46bb63f 6 * You may obtain a copy of the License at
mbed_official 1:9db4d46bb63f 7 *
mbed_official 1:9db4d46bb63f 8 * http://www.apache.org/licenses/LICENSE-2.0
mbed_official 1:9db4d46bb63f 9 *
mbed_official 1:9db4d46bb63f 10 * Unless required by applicable law or agreed to in writing, software
mbed_official 1:9db4d46bb63f 11 * distributed under the License is distributed on an "AS IS" BASIS,
mbed_official 1:9db4d46bb63f 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
mbed_official 1:9db4d46bb63f 13 * See the License for the specific language governing permissions and
mbed_official 1:9db4d46bb63f 14 * limitations under the License.
mbed_official 1:9db4d46bb63f 15 */
mbed_official 1:9db4d46bb63f 16
mbed_official 1:9db4d46bb63f 17 #include "EddystoneService.h"
mbed_official 1:9db4d46bb63f 18
mbed_official 1:9db4d46bb63f 19 /* Initialise the EddystoneService using parameters from persistent storage */
mbed_official 1:9db4d46bb63f 20 EddystoneService::EddystoneService(BLE &bleIn,
mbed_official 1:9db4d46bb63f 21 EddystoneParams_t &paramsIn,
mbed_official 1:9db4d46bb63f 22 const PowerLevels_t &radioPowerLevelsIn,
mbed_official 1:9db4d46bb63f 23 EventQueue &evQ,
mbed_official 1:9db4d46bb63f 24 uint32_t advConfigIntervalIn) :
mbed_official 1:9db4d46bb63f 25 ble(bleIn),
mbed_official 1:9db4d46bb63f 26 operationMode(EDDYSTONE_MODE_NONE),
mbed_official 1:9db4d46bb63f 27 urlFrame(paramsIn.urlData, paramsIn.urlDataLength),
mbed_official 1:9db4d46bb63f 28 uidFrame(paramsIn.uidNamespaceID, paramsIn.uidInstanceID),
mbed_official 1:9db4d46bb63f 29 tlmFrame(paramsIn.tlmVersion),
mbed_official 1:9db4d46bb63f 30 resetFlag(false),
mbed_official 1:9db4d46bb63f 31 rawUrlFrame(NULL),
mbed_official 1:9db4d46bb63f 32 rawUidFrame(NULL),
mbed_official 1:9db4d46bb63f 33 rawTlmFrame(NULL),
mbed_official 1:9db4d46bb63f 34 tlmBatteryVoltageCallback(NULL),
mbed_official 1:9db4d46bb63f 35 tlmBeaconTemperatureCallback(NULL),
mbed_official 1:9db4d46bb63f 36 uidFrameCallbackHandle(),
mbed_official 1:9db4d46bb63f 37 urlFrameCallbackHandle(),
mbed_official 1:9db4d46bb63f 38 tlmFrameCallbackHandle(),
mbed_official 1:9db4d46bb63f 39 radioManagerCallbackHandle(),
mbed_official 1:9db4d46bb63f 40 deviceName(DEFAULT_DEVICE_NAME),
mbed_official 1:9db4d46bb63f 41 eventQueue(evQ)
mbed_official 1:9db4d46bb63f 42 {
mbed_official 1:9db4d46bb63f 43 lockState = paramsIn.lockState;
mbed_official 1:9db4d46bb63f 44 flags = paramsIn.flags;
mbed_official 1:9db4d46bb63f 45 txPowerMode = paramsIn.txPowerMode;
mbed_official 1:9db4d46bb63f 46 urlFramePeriod = correctAdvertisementPeriod(paramsIn.urlFramePeriod);
mbed_official 1:9db4d46bb63f 47 uidFramePeriod = correctAdvertisementPeriod(paramsIn.uidFramePeriod);
mbed_official 1:9db4d46bb63f 48 tlmFramePeriod = correctAdvertisementPeriod(paramsIn.tlmFramePeriod);
mbed_official 1:9db4d46bb63f 49
mbed_official 1:9db4d46bb63f 50 memcpy(lock, paramsIn.lock, sizeof(Lock_t));
mbed_official 1:9db4d46bb63f 51 memcpy(unlock, paramsIn.unlock, sizeof(Lock_t));
mbed_official 1:9db4d46bb63f 52
mbed_official 1:9db4d46bb63f 53 eddystoneConstructorHelper(paramsIn.advPowerLevels, radioPowerLevelsIn, advConfigIntervalIn);
mbed_official 1:9db4d46bb63f 54 }
mbed_official 1:9db4d46bb63f 55
mbed_official 1:9db4d46bb63f 56 /* When using this constructor we need to call setURLData,
mbed_official 1:9db4d46bb63f 57 * setTMLData and setUIDData to initialise values manually
mbed_official 1:9db4d46bb63f 58 */
mbed_official 1:9db4d46bb63f 59 EddystoneService::EddystoneService(BLE &bleIn,
mbed_official 1:9db4d46bb63f 60 const PowerLevels_t &advPowerLevelsIn,
mbed_official 1:9db4d46bb63f 61 const PowerLevels_t &radioPowerLevelsIn,
mbed_official 1:9db4d46bb63f 62 EventQueue &evQ,
mbed_official 1:9db4d46bb63f 63 uint32_t advConfigIntervalIn) :
mbed_official 1:9db4d46bb63f 64 ble(bleIn),
mbed_official 1:9db4d46bb63f 65 operationMode(EDDYSTONE_MODE_NONE),
mbed_official 1:9db4d46bb63f 66 urlFrame(),
mbed_official 1:9db4d46bb63f 67 uidFrame(),
mbed_official 1:9db4d46bb63f 68 tlmFrame(),
mbed_official 1:9db4d46bb63f 69 lockState(false),
mbed_official 1:9db4d46bb63f 70 resetFlag(false),
mbed_official 1:9db4d46bb63f 71 lock(),
mbed_official 1:9db4d46bb63f 72 unlock(),
mbed_official 1:9db4d46bb63f 73 flags(0),
mbed_official 1:9db4d46bb63f 74 txPowerMode(0),
mbed_official 1:9db4d46bb63f 75 urlFramePeriod(DEFAULT_URL_FRAME_PERIOD_MSEC),
mbed_official 1:9db4d46bb63f 76 uidFramePeriod(DEFAULT_UID_FRAME_PERIOD_MSEC),
mbed_official 1:9db4d46bb63f 77 tlmFramePeriod(DEFAULT_TLM_FRAME_PERIOD_MSEC),
mbed_official 1:9db4d46bb63f 78 rawUrlFrame(NULL),
mbed_official 1:9db4d46bb63f 79 rawUidFrame(NULL),
mbed_official 1:9db4d46bb63f 80 rawTlmFrame(NULL),
mbed_official 1:9db4d46bb63f 81 tlmBatteryVoltageCallback(NULL),
mbed_official 1:9db4d46bb63f 82 tlmBeaconTemperatureCallback(NULL),
mbed_official 1:9db4d46bb63f 83 uidFrameCallbackHandle(),
mbed_official 1:9db4d46bb63f 84 urlFrameCallbackHandle(),
mbed_official 1:9db4d46bb63f 85 tlmFrameCallbackHandle(),
mbed_official 1:9db4d46bb63f 86 radioManagerCallbackHandle(),
mbed_official 1:9db4d46bb63f 87 deviceName(DEFAULT_DEVICE_NAME),
mbed_official 1:9db4d46bb63f 88 eventQueue(evQ)
mbed_official 1:9db4d46bb63f 89 {
mbed_official 1:9db4d46bb63f 90 eddystoneConstructorHelper(advPowerLevelsIn, radioPowerLevelsIn, advConfigIntervalIn);
mbed_official 1:9db4d46bb63f 91 }
mbed_official 1:9db4d46bb63f 92
mbed_official 1:9db4d46bb63f 93 /* Setup callback to update BatteryVoltage in TLM frame */
mbed_official 1:9db4d46bb63f 94 void EddystoneService::onTLMBatteryVoltageUpdate(TlmUpdateCallback_t tlmBatteryVoltageCallbackIn)
mbed_official 1:9db4d46bb63f 95 {
mbed_official 1:9db4d46bb63f 96 tlmBatteryVoltageCallback = tlmBatteryVoltageCallbackIn;
mbed_official 1:9db4d46bb63f 97 }
mbed_official 1:9db4d46bb63f 98
mbed_official 1:9db4d46bb63f 99 /* Setup callback to update BeaconTemperature in TLM frame */
mbed_official 1:9db4d46bb63f 100 void EddystoneService::onTLMBeaconTemperatureUpdate(TlmUpdateCallback_t tlmBeaconTemperatureCallbackIn)
mbed_official 1:9db4d46bb63f 101 {
mbed_official 1:9db4d46bb63f 102 tlmBeaconTemperatureCallback = tlmBeaconTemperatureCallbackIn;
mbed_official 1:9db4d46bb63f 103 }
mbed_official 1:9db4d46bb63f 104
mbed_official 1:9db4d46bb63f 105 void EddystoneService::setTLMData(uint8_t tlmVersionIn)
mbed_official 1:9db4d46bb63f 106 {
mbed_official 1:9db4d46bb63f 107 tlmFrame.setTLMData(tlmVersionIn);
mbed_official 1:9db4d46bb63f 108 }
mbed_official 1:9db4d46bb63f 109
mbed_official 1:9db4d46bb63f 110 void EddystoneService::setURLData(const char *urlDataIn)
mbed_official 1:9db4d46bb63f 111 {
mbed_official 1:9db4d46bb63f 112 urlFrame.setURLData(urlDataIn);
mbed_official 1:9db4d46bb63f 113 }
mbed_official 1:9db4d46bb63f 114
mbed_official 1:9db4d46bb63f 115 void EddystoneService::setUIDData(const UIDNamespaceID_t &uidNamespaceIDIn, const UIDInstanceID_t &uidInstanceIDIn)
mbed_official 1:9db4d46bb63f 116 {
mbed_official 1:9db4d46bb63f 117 uidFrame.setUIDData(uidNamespaceIDIn, uidInstanceIDIn);
mbed_official 1:9db4d46bb63f 118 }
mbed_official 1:9db4d46bb63f 119
mbed_official 1:9db4d46bb63f 120 EddystoneService::EddystoneError_t EddystoneService::startConfigService(void)
mbed_official 1:9db4d46bb63f 121 {
mbed_official 1:9db4d46bb63f 122 if (operationMode == EDDYSTONE_MODE_CONFIG) {
mbed_official 1:9db4d46bb63f 123 /* Nothing to do, we are already in config mode */
mbed_official 1:9db4d46bb63f 124 return EDDYSTONE_ERROR_NONE;
mbed_official 1:9db4d46bb63f 125 } else if (advConfigInterval == 0) {
mbed_official 1:9db4d46bb63f 126 /* Nothing to do, the advertisement interval is 0 */
mbed_official 1:9db4d46bb63f 127 return EDDYSTONE_ERROR_INVALID_ADVERTISING_INTERVAL;
mbed_official 1:9db4d46bb63f 128 }
mbed_official 1:9db4d46bb63f 129
mbed_official 1:9db4d46bb63f 130 if (operationMode == EDDYSTONE_MODE_BEACON) {
mbed_official 1:9db4d46bb63f 131 ble.shutdown();
mbed_official 1:9db4d46bb63f 132 stopBeaconService();
mbed_official 1:9db4d46bb63f 133 }
mbed_official 1:9db4d46bb63f 134
mbed_official 1:9db4d46bb63f 135 if (!ble.hasInitialized()) {
mbed_official 1:9db4d46bb63f 136 operationMode = EDDYSTONE_MODE_CONFIG;
mbed_official 1:9db4d46bb63f 137 ble.init(this, &EddystoneService::bleInitComplete);
mbed_official 1:9db4d46bb63f 138 /* Set the device name once more */
mbed_official 1:9db4d46bb63f 139 ble.gap().setDeviceName(reinterpret_cast<const uint8_t *>(deviceName));
mbed_official 1:9db4d46bb63f 140 return EDDYSTONE_ERROR_NONE;
mbed_official 1:9db4d46bb63f 141 }
mbed_official 1:9db4d46bb63f 142
mbed_official 1:9db4d46bb63f 143 operationMode = EDDYSTONE_MODE_CONFIG;
mbed_official 1:9db4d46bb63f 144 setupConfigService();
mbed_official 1:9db4d46bb63f 145 return EDDYSTONE_ERROR_NONE;
mbed_official 1:9db4d46bb63f 146 }
mbed_official 1:9db4d46bb63f 147
mbed_official 1:9db4d46bb63f 148 EddystoneService::EddystoneError_t EddystoneService::startBeaconService(void)
mbed_official 1:9db4d46bb63f 149 {
mbed_official 1:9db4d46bb63f 150 if (operationMode == EDDYSTONE_MODE_BEACON) {
mbed_official 1:9db4d46bb63f 151 /* Nothing to do, we are already in beacon mode */
mbed_official 1:9db4d46bb63f 152 return EDDYSTONE_ERROR_NONE;
mbed_official 1:9db4d46bb63f 153 } else if (!urlFramePeriod && !uidFramePeriod && !tlmFramePeriod) {
mbed_official 1:9db4d46bb63f 154 /* Nothing to do, the period is 0 for all frames */
mbed_official 1:9db4d46bb63f 155 return EDDYSTONE_ERROR_INVALID_ADVERTISING_INTERVAL;
mbed_official 1:9db4d46bb63f 156 }
mbed_official 1:9db4d46bb63f 157
mbed_official 1:9db4d46bb63f 158 if (operationMode == EDDYSTONE_MODE_CONFIG) {
mbed_official 1:9db4d46bb63f 159 ble.shutdown();
mbed_official 1:9db4d46bb63f 160 /* Free unused memory */
mbed_official 1:9db4d46bb63f 161 freeConfigCharacteristics();
mbed_official 1:9db4d46bb63f 162 }
mbed_official 1:9db4d46bb63f 163
mbed_official 1:9db4d46bb63f 164 if (!ble.hasInitialized()) {
mbed_official 1:9db4d46bb63f 165 operationMode = EDDYSTONE_MODE_BEACON;
mbed_official 1:9db4d46bb63f 166 ble.init(this, &EddystoneService::bleInitComplete);
mbed_official 1:9db4d46bb63f 167 /* Set the device name once more */
mbed_official 1:9db4d46bb63f 168 ble.gap().setDeviceName(reinterpret_cast<const uint8_t *>(deviceName));
mbed_official 1:9db4d46bb63f 169 return EDDYSTONE_ERROR_NONE;
mbed_official 1:9db4d46bb63f 170 }
mbed_official 1:9db4d46bb63f 171
mbed_official 1:9db4d46bb63f 172 operationMode = EDDYSTONE_MODE_BEACON;
mbed_official 1:9db4d46bb63f 173 setupBeaconService();
mbed_official 1:9db4d46bb63f 174
mbed_official 1:9db4d46bb63f 175 return EDDYSTONE_ERROR_NONE;
mbed_official 1:9db4d46bb63f 176 }
mbed_official 1:9db4d46bb63f 177
mbed_official 1:9db4d46bb63f 178 EddystoneService::EddystoneError_t EddystoneService::stopCurrentService(void)
mbed_official 1:9db4d46bb63f 179 {
mbed_official 1:9db4d46bb63f 180 switch (operationMode) {
mbed_official 1:9db4d46bb63f 181 case EDDYSTONE_MODE_NONE:
mbed_official 1:9db4d46bb63f 182 return EDDYSTONE_ERROR_INVALID_STATE;
mbed_official 1:9db4d46bb63f 183 case EDDYSTONE_MODE_BEACON:
mbed_official 1:9db4d46bb63f 184 ble.shutdown();
mbed_official 1:9db4d46bb63f 185 stopBeaconService();
mbed_official 1:9db4d46bb63f 186 break;
mbed_official 1:9db4d46bb63f 187 case EDDYSTONE_MODE_CONFIG:
mbed_official 1:9db4d46bb63f 188 ble.shutdown();
mbed_official 1:9db4d46bb63f 189 freeConfigCharacteristics();
mbed_official 1:9db4d46bb63f 190 break;
mbed_official 1:9db4d46bb63f 191 default:
mbed_official 1:9db4d46bb63f 192 /* Some error occurred */
mbed_official 1:9db4d46bb63f 193 error("Invalid EddystonService mode");
mbed_official 1:9db4d46bb63f 194 break;
mbed_official 1:9db4d46bb63f 195 }
mbed_official 1:9db4d46bb63f 196 operationMode = EDDYSTONE_MODE_NONE;
mbed_official 1:9db4d46bb63f 197 /* Currently on some platforms, the BLE stack handles power management,
mbed_official 1:9db4d46bb63f 198 * so we should bring it up again, but not configure it.
mbed_official 1:9db4d46bb63f 199 * Once the system sleep without BLE initialised is fixed, remove this
mbed_official 1:9db4d46bb63f 200 */
mbed_official 1:9db4d46bb63f 201 ble.init(this, &EddystoneService::bleInitComplete);
mbed_official 1:9db4d46bb63f 202
mbed_official 1:9db4d46bb63f 203 return EDDYSTONE_ERROR_NONE;
mbed_official 1:9db4d46bb63f 204 }
mbed_official 1:9db4d46bb63f 205
mbed_official 1:9db4d46bb63f 206 ble_error_t EddystoneService::setCompleteDeviceName(const char *deviceNameIn)
mbed_official 1:9db4d46bb63f 207 {
mbed_official 1:9db4d46bb63f 208 /* Make sure the device name is safe */
mbed_official 1:9db4d46bb63f 209 ble_error_t error = ble.gap().setDeviceName(reinterpret_cast<const uint8_t *>(deviceNameIn));
mbed_official 1:9db4d46bb63f 210 if (error == BLE_ERROR_NONE) {
mbed_official 1:9db4d46bb63f 211 deviceName = deviceNameIn;
mbed_official 1:9db4d46bb63f 212 if (operationMode == EDDYSTONE_MODE_CONFIG) {
mbed_official 1:9db4d46bb63f 213 /* Need to update the advertising packets to the new name */
mbed_official 1:9db4d46bb63f 214 setupEddystoneConfigScanResponse();
mbed_official 1:9db4d46bb63f 215 }
mbed_official 1:9db4d46bb63f 216 }
mbed_official 1:9db4d46bb63f 217
mbed_official 1:9db4d46bb63f 218 return error;
mbed_official 1:9db4d46bb63f 219 }
mbed_official 1:9db4d46bb63f 220
mbed_official 1:9db4d46bb63f 221 /* It is not the responsibility of the Eddystone implementation to store
mbed_official 1:9db4d46bb63f 222 * the configured parameters in persistent storage since this is
mbed_official 1:9db4d46bb63f 223 * platform-specific. So we provide this function that returns the
mbed_official 1:9db4d46bb63f 224 * configured values that need to be stored and the main application
mbed_official 1:9db4d46bb63f 225 * takes care of storing them.
mbed_official 1:9db4d46bb63f 226 */
mbed_official 1:9db4d46bb63f 227 void EddystoneService::getEddystoneParams(EddystoneParams_t &params)
mbed_official 1:9db4d46bb63f 228 {
mbed_official 1:9db4d46bb63f 229 params.lockState = lockState;
mbed_official 1:9db4d46bb63f 230 params.flags = flags;
mbed_official 1:9db4d46bb63f 231 params.txPowerMode = txPowerMode;
mbed_official 1:9db4d46bb63f 232 params.urlFramePeriod = urlFramePeriod;
mbed_official 1:9db4d46bb63f 233 params.tlmFramePeriod = tlmFramePeriod;
mbed_official 1:9db4d46bb63f 234 params.uidFramePeriod = uidFramePeriod;
mbed_official 1:9db4d46bb63f 235 params.tlmVersion = tlmFrame.getTLMVersion();
mbed_official 1:9db4d46bb63f 236 params.urlDataLength = urlFrame.getEncodedURLDataLength();
mbed_official 1:9db4d46bb63f 237
mbed_official 1:9db4d46bb63f 238 memcpy(params.advPowerLevels, advPowerLevels, sizeof(PowerLevels_t));
mbed_official 1:9db4d46bb63f 239 memcpy(params.lock, lock, sizeof(Lock_t));
mbed_official 1:9db4d46bb63f 240 memcpy(params.unlock, unlock, sizeof(Lock_t));
mbed_official 1:9db4d46bb63f 241 memcpy(params.urlData, urlFrame.getEncodedURLData(), urlFrame.getEncodedURLDataLength());
mbed_official 1:9db4d46bb63f 242 memcpy(params.uidNamespaceID, uidFrame.getUIDNamespaceID(), sizeof(UIDNamespaceID_t));
mbed_official 1:9db4d46bb63f 243 memcpy(params.uidInstanceID, uidFrame.getUIDInstanceID(), sizeof(UIDInstanceID_t));
mbed_official 1:9db4d46bb63f 244 }
mbed_official 1:9db4d46bb63f 245
mbed_official 1:9db4d46bb63f 246 /* Helper function used only once during constructing the object to avoid
mbed_official 1:9db4d46bb63f 247 * duplicated code.
mbed_official 1:9db4d46bb63f 248 */
mbed_official 1:9db4d46bb63f 249 void EddystoneService::eddystoneConstructorHelper(const PowerLevels_t &advPowerLevelsIn,
mbed_official 1:9db4d46bb63f 250 const PowerLevels_t &radioPowerLevelsIn,
mbed_official 1:9db4d46bb63f 251 uint32_t advConfigIntervalIn)
mbed_official 1:9db4d46bb63f 252 {
mbed_official 1:9db4d46bb63f 253 /* We cannot use correctAdvertisementPeriod() for this check because the function
mbed_official 1:9db4d46bb63f 254 * call to get the minimum advertising interval in the BLE API is different for
mbed_official 1:9db4d46bb63f 255 * connectable and non-connectable advertising.
mbed_official 1:9db4d46bb63f 256 */
mbed_official 1:9db4d46bb63f 257 if (advConfigIntervalIn != 0) {
mbed_official 1:9db4d46bb63f 258 if (advConfigIntervalIn < ble.gap().getMinAdvertisingInterval()) {
mbed_official 1:9db4d46bb63f 259 advConfigInterval = ble.gap().getMinAdvertisingInterval();
mbed_official 1:9db4d46bb63f 260 } else if (advConfigIntervalIn > ble.gap().getMaxAdvertisingInterval()) {
mbed_official 1:9db4d46bb63f 261 advConfigInterval = ble.gap().getMaxAdvertisingInterval();
mbed_official 1:9db4d46bb63f 262 } else {
mbed_official 1:9db4d46bb63f 263 advConfigInterval = advConfigIntervalIn;
mbed_official 1:9db4d46bb63f 264 }
mbed_official 1:9db4d46bb63f 265 }
mbed_official 1:9db4d46bb63f 266
mbed_official 1:9db4d46bb63f 267 memcpy(radioPowerLevels, radioPowerLevelsIn, sizeof(PowerLevels_t));
mbed_official 1:9db4d46bb63f 268 memcpy(advPowerLevels, advPowerLevelsIn, sizeof(PowerLevels_t));
mbed_official 1:9db4d46bb63f 269
mbed_official 1:9db4d46bb63f 270 /* TODO: Note that this timer is started from the time EddystoneService
mbed_official 1:9db4d46bb63f 271 * is initialised and NOT from when the device is booted. So app needs
mbed_official 1:9db4d46bb63f 272 * to take care that EddystoneService is one of the first things to be
mbed_official 1:9db4d46bb63f 273 * started!
mbed_official 1:9db4d46bb63f 274 */
mbed_official 1:9db4d46bb63f 275 timeSinceBootTimer.start();
mbed_official 1:9db4d46bb63f 276
mbed_official 1:9db4d46bb63f 277 /* Set the device name at startup */
mbed_official 1:9db4d46bb63f 278 ble.gap().setDeviceName(reinterpret_cast<const uint8_t *>(deviceName));
mbed_official 1:9db4d46bb63f 279 }
mbed_official 1:9db4d46bb63f 280
mbed_official 1:9db4d46bb63f 281 /* When changing modes, we shutdown and init the BLE instance, so
mbed_official 1:9db4d46bb63f 282 * this is needed to complete the initialisation task.
mbed_official 1:9db4d46bb63f 283 */
mbed_official 1:9db4d46bb63f 284 void EddystoneService::bleInitComplete(BLE::InitializationCompleteCallbackContext* initContext)
mbed_official 1:9db4d46bb63f 285 {
mbed_official 1:9db4d46bb63f 286 if (initContext->error != BLE_ERROR_NONE) {
mbed_official 1:9db4d46bb63f 287 /* Initialisation failed */
mbed_official 1:9db4d46bb63f 288 return;
mbed_official 1:9db4d46bb63f 289 }
mbed_official 1:9db4d46bb63f 290
mbed_official 1:9db4d46bb63f 291 switch (operationMode) {
mbed_official 1:9db4d46bb63f 292 case EDDYSTONE_MODE_CONFIG:
mbed_official 1:9db4d46bb63f 293 setupConfigService();
mbed_official 1:9db4d46bb63f 294 break;
mbed_official 1:9db4d46bb63f 295 case EDDYSTONE_MODE_BEACON:
mbed_official 1:9db4d46bb63f 296 setupBeaconService();
mbed_official 1:9db4d46bb63f 297 break;
mbed_official 1:9db4d46bb63f 298 case EDDYSTONE_MODE_NONE:
mbed_official 1:9db4d46bb63f 299 /* We don't need to do anything here, but it isn't an error */
mbed_official 1:9db4d46bb63f 300 break;
mbed_official 1:9db4d46bb63f 301 default:
mbed_official 1:9db4d46bb63f 302 /* Some error occurred */
mbed_official 1:9db4d46bb63f 303 error("Invalid EddystonService mode");
mbed_official 1:9db4d46bb63f 304 break;
mbed_official 1:9db4d46bb63f 305 }
mbed_official 1:9db4d46bb63f 306 }
mbed_official 1:9db4d46bb63f 307
mbed_official 1:9db4d46bb63f 308 void EddystoneService::swapAdvertisedFrame(FrameType frameType)
mbed_official 1:9db4d46bb63f 309 {
mbed_official 1:9db4d46bb63f 310 switch(frameType) {
mbed_official 1:9db4d46bb63f 311 case EDDYSTONE_FRAME_URL:
mbed_official 1:9db4d46bb63f 312 updateAdvertisementPacket(rawUrlFrame, urlFrame.getRawFrameSize());
mbed_official 1:9db4d46bb63f 313 break;
mbed_official 1:9db4d46bb63f 314 case EDDYSTONE_FRAME_UID:
mbed_official 1:9db4d46bb63f 315 updateAdvertisementPacket(rawUidFrame, uidFrame.getRawFrameSize());
mbed_official 1:9db4d46bb63f 316 break;
mbed_official 1:9db4d46bb63f 317 case EDDYSTONE_FRAME_TLM:
mbed_official 1:9db4d46bb63f 318 updateRawTLMFrame();
mbed_official 1:9db4d46bb63f 319 updateAdvertisementPacket(rawTlmFrame, tlmFrame.getRawFrameSize());
mbed_official 1:9db4d46bb63f 320 break;
mbed_official 1:9db4d46bb63f 321 default:
mbed_official 1:9db4d46bb63f 322 /* Some error occurred */
mbed_official 1:9db4d46bb63f 323 error("Frame to swap in does not specify a valid type");
mbed_official 1:9db4d46bb63f 324 break;
mbed_official 1:9db4d46bb63f 325 }
mbed_official 1:9db4d46bb63f 326 }
mbed_official 1:9db4d46bb63f 327
mbed_official 1:9db4d46bb63f 328 /* Helper function that calls user-defined functions to update Battery Voltage and Temperature (if available),
mbed_official 1:9db4d46bb63f 329 * then updates the raw frame data and finally updates the actual advertised packet. This operation must be
mbed_official 1:9db4d46bb63f 330 * done fairly often because the TLM frame TimeSinceBoot must have a 0.1 secs resolution according to the
mbed_official 1:9db4d46bb63f 331 * Eddystone specification.
mbed_official 1:9db4d46bb63f 332 */
mbed_official 1:9db4d46bb63f 333 void EddystoneService::updateRawTLMFrame(void)
mbed_official 1:9db4d46bb63f 334 {
mbed_official 1:9db4d46bb63f 335 if (tlmBeaconTemperatureCallback != NULL) {
mbed_official 1:9db4d46bb63f 336 tlmFrame.updateBeaconTemperature((*tlmBeaconTemperatureCallback)(tlmFrame.getBeaconTemperature()));
mbed_official 1:9db4d46bb63f 337 }
mbed_official 1:9db4d46bb63f 338 if (tlmBatteryVoltageCallback != NULL) {
mbed_official 1:9db4d46bb63f 339 tlmFrame.updateBatteryVoltage((*tlmBatteryVoltageCallback)(tlmFrame.getBatteryVoltage()));
mbed_official 1:9db4d46bb63f 340 }
mbed_official 1:9db4d46bb63f 341 tlmFrame.updateTimeSinceBoot(timeSinceBootTimer.read_ms());
mbed_official 1:9db4d46bb63f 342 tlmFrame.constructTLMFrame(rawTlmFrame);
mbed_official 1:9db4d46bb63f 343 }
mbed_official 1:9db4d46bb63f 344
mbed_official 1:9db4d46bb63f 345 void EddystoneService::updateAdvertisementPacket(const uint8_t* rawFrame, size_t rawFrameLength)
mbed_official 1:9db4d46bb63f 346 {
mbed_official 1:9db4d46bb63f 347 ble.gap().clearAdvertisingPayload();
mbed_official 1:9db4d46bb63f 348 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
mbed_official 1:9db4d46bb63f 349 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, EDDYSTONE_UUID, sizeof(EDDYSTONE_UUID));
mbed_official 1:9db4d46bb63f 350 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::SERVICE_DATA, rawFrame, rawFrameLength);
mbed_official 1:9db4d46bb63f 351 }
mbed_official 1:9db4d46bb63f 352
mbed_official 1:9db4d46bb63f 353 void EddystoneService::setupBeaconService(void)
mbed_official 1:9db4d46bb63f 354 {
mbed_official 1:9db4d46bb63f 355 /* Initialise arrays to hold constructed raw frames */
mbed_official 1:9db4d46bb63f 356 if (urlFramePeriod) {
mbed_official 1:9db4d46bb63f 357 rawUrlFrame = new uint8_t[urlFrame.getRawFrameSize()];
mbed_official 1:9db4d46bb63f 358 urlFrame.constructURLFrame(rawUrlFrame, advPowerLevels[txPowerMode]);
mbed_official 1:9db4d46bb63f 359 }
mbed_official 1:9db4d46bb63f 360
mbed_official 1:9db4d46bb63f 361 if (uidFramePeriod) {
mbed_official 1:9db4d46bb63f 362 rawUidFrame = new uint8_t[uidFrame.getRawFrameSize()];
mbed_official 1:9db4d46bb63f 363 uidFrame.constructUIDFrame(rawUidFrame, advPowerLevels[txPowerMode]);
mbed_official 1:9db4d46bb63f 364 }
mbed_official 1:9db4d46bb63f 365
mbed_official 1:9db4d46bb63f 366 if (tlmFramePeriod) {
mbed_official 1:9db4d46bb63f 367 rawTlmFrame = new uint8_t[tlmFrame.getRawFrameSize()];
mbed_official 1:9db4d46bb63f 368 /* Do not initialise because we have to reconstruct every 0.1 secs */
mbed_official 1:9db4d46bb63f 369 }
mbed_official 1:9db4d46bb63f 370
mbed_official 1:9db4d46bb63f 371 /* Configure advertisements */
mbed_official 1:9db4d46bb63f 372 ble.gap().setTxPower(radioPowerLevels[txPowerMode]);
mbed_official 1:9db4d46bb63f 373 ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED);
mbed_official 1:9db4d46bb63f 374 ble.gap().setAdvertisingInterval(ble.gap().getMaxAdvertisingInterval());
mbed_official 1:9db4d46bb63f 375
mbed_official 1:9db4d46bb63f 376 /* Make sure the queue is currently empty */
mbed_official 1:9db4d46bb63f 377 advFrameQueue.reset();
mbed_official 1:9db4d46bb63f 378 /* Setup callbacks to periodically add frames to be advertised to the queue and
mbed_official 1:9db4d46bb63f 379 * add initial frame so that we have something to advertise on startup */
mbed_official 1:9db4d46bb63f 380 if (uidFramePeriod) {
mbed_official 1:9db4d46bb63f 381 advFrameQueue.push(EDDYSTONE_FRAME_UID);
mbed_official 1:9db4d46bb63f 382 uidFrameCallbackHandle = eventQueue.post_every(
mbed_official 1:9db4d46bb63f 383 uidFramePeriod,
mbed_official 1:9db4d46bb63f 384 Callback<void(FrameType)>(this, &EddystoneService::enqueueFrame),
mbed_official 1:9db4d46bb63f 385 EDDYSTONE_FRAME_UID
mbed_official 1:9db4d46bb63f 386 );
mbed_official 1:9db4d46bb63f 387 }
mbed_official 1:9db4d46bb63f 388 if (tlmFramePeriod) {
mbed_official 1:9db4d46bb63f 389 advFrameQueue.push(EDDYSTONE_FRAME_TLM);
mbed_official 1:9db4d46bb63f 390 tlmFrameCallbackHandle = eventQueue.post_every(
mbed_official 1:9db4d46bb63f 391 tlmFramePeriod,
mbed_official 1:9db4d46bb63f 392 Callback<void(FrameType)>(this, &EddystoneService::enqueueFrame),
mbed_official 1:9db4d46bb63f 393 EDDYSTONE_FRAME_TLM
mbed_official 1:9db4d46bb63f 394 );
mbed_official 1:9db4d46bb63f 395 }
mbed_official 1:9db4d46bb63f 396 if (urlFramePeriod) {
mbed_official 1:9db4d46bb63f 397 advFrameQueue.push(EDDYSTONE_FRAME_URL);
mbed_official 1:9db4d46bb63f 398 tlmFrameCallbackHandle = eventQueue.post_every(
mbed_official 1:9db4d46bb63f 399 urlFramePeriod,
mbed_official 1:9db4d46bb63f 400 Callback<void(FrameType)>(this, &EddystoneService::enqueueFrame),
mbed_official 1:9db4d46bb63f 401 EDDYSTONE_FRAME_URL
mbed_official 1:9db4d46bb63f 402 );
mbed_official 1:9db4d46bb63f 403 }
mbed_official 1:9db4d46bb63f 404
mbed_official 1:9db4d46bb63f 405 /* Start advertising */
mbed_official 1:9db4d46bb63f 406 manageRadio();
mbed_official 1:9db4d46bb63f 407 }
mbed_official 1:9db4d46bb63f 408
mbed_official 1:9db4d46bb63f 409 void EddystoneService::enqueueFrame(FrameType frameType)
mbed_official 1:9db4d46bb63f 410 {
mbed_official 1:9db4d46bb63f 411 advFrameQueue.push(frameType);
mbed_official 1:9db4d46bb63f 412 if (!radioManagerCallbackHandle) {
mbed_official 1:9db4d46bb63f 413 /* Advertising stopped and there is not callback posted in the scheduler. Just
mbed_official 1:9db4d46bb63f 414 * execute the manager to resume advertising */
mbed_official 1:9db4d46bb63f 415 manageRadio();
mbed_official 1:9db4d46bb63f 416 }
mbed_official 1:9db4d46bb63f 417 }
mbed_official 1:9db4d46bb63f 418
mbed_official 1:9db4d46bb63f 419 void EddystoneService::manageRadio(void)
mbed_official 1:9db4d46bb63f 420 {
mbed_official 1:9db4d46bb63f 421 FrameType frameType;
mbed_official 1:9db4d46bb63f 422 uint32_t startTimeManageRadio = timeSinceBootTimer.read_ms();
mbed_official 1:9db4d46bb63f 423
mbed_official 1:9db4d46bb63f 424 /* Signal that there is currently no callback posted */
mbed_official 1:9db4d46bb63f 425 radioManagerCallbackHandle = 0;
mbed_official 1:9db4d46bb63f 426
mbed_official 1:9db4d46bb63f 427 if (advFrameQueue.pop(frameType)) {
mbed_official 1:9db4d46bb63f 428 /* We have something to advertise */
mbed_official 1:9db4d46bb63f 429 if (ble.gap().getState().advertising) {
mbed_official 1:9db4d46bb63f 430 ble.gap().stopAdvertising();
mbed_official 1:9db4d46bb63f 431 }
mbed_official 1:9db4d46bb63f 432 swapAdvertisedFrame(frameType);
mbed_official 1:9db4d46bb63f 433 ble.gap().startAdvertising();
mbed_official 1:9db4d46bb63f 434
mbed_official 1:9db4d46bb63f 435 /* Increase the advertised packet count in TLM frame */
mbed_official 1:9db4d46bb63f 436 tlmFrame.updatePduCount();
mbed_official 1:9db4d46bb63f 437
mbed_official 1:9db4d46bb63f 438 /* Post a callback to itself to stop the advertisement or pop the next
mbed_official 1:9db4d46bb63f 439 * frame from the queue. However, take into account the time taken to
mbed_official 1:9db4d46bb63f 440 * swap in this frame. */
mbed_official 1:9db4d46bb63f 441 radioManagerCallbackHandle = eventQueue.post_in(
mbed_official 1:9db4d46bb63f 442 ble.gap().getMinNonConnectableAdvertisingInterval() - (timeSinceBootTimer.read_ms() - startTimeManageRadio),
mbed_official 1:9db4d46bb63f 443 Callback<void()>(this, &EddystoneService::manageRadio)
mbed_official 1:9db4d46bb63f 444 );
mbed_official 1:9db4d46bb63f 445 } else if (ble.gap().getState().advertising) {
mbed_official 1:9db4d46bb63f 446 /* Nothing else to advertise, stop advertising and do not schedule any callbacks */
mbed_official 1:9db4d46bb63f 447 ble.gap().stopAdvertising();
mbed_official 1:9db4d46bb63f 448 }
mbed_official 1:9db4d46bb63f 449 }
mbed_official 1:9db4d46bb63f 450
mbed_official 1:9db4d46bb63f 451 void EddystoneService::setupConfigService(void)
mbed_official 1:9db4d46bb63f 452 {
mbed_official 1:9db4d46bb63f 453 lockStateChar = new ReadOnlyGattCharacteristic<bool>(UUID_LOCK_STATE_CHAR, &lockState);
mbed_official 1:9db4d46bb63f 454 lockChar = new WriteOnlyArrayGattCharacteristic<uint8_t, sizeof(Lock_t)>(UUID_LOCK_CHAR, lock);
mbed_official 1:9db4d46bb63f 455 unlockChar = new WriteOnlyArrayGattCharacteristic<uint8_t, sizeof(Lock_t)>(UUID_UNLOCK_CHAR, unlock);
mbed_official 1:9db4d46bb63f 456 urlDataChar = new GattCharacteristic(UUID_URL_DATA_CHAR, urlFrame.getEncodedURLData(), 0, URL_DATA_MAX, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE);
mbed_official 1:9db4d46bb63f 457 flagsChar = new ReadWriteGattCharacteristic<uint8_t>(UUID_FLAGS_CHAR, &flags);
mbed_official 1:9db4d46bb63f 458 advPowerLevelsChar = new ReadWriteArrayGattCharacteristic<int8_t, sizeof(PowerLevels_t)>(UUID_ADV_POWER_LEVELS_CHAR, advPowerLevels);
mbed_official 1:9db4d46bb63f 459 txPowerModeChar = new ReadWriteGattCharacteristic<uint8_t>(UUID_TX_POWER_MODE_CHAR, &txPowerMode);
mbed_official 1:9db4d46bb63f 460 beaconPeriodChar = new ReadWriteGattCharacteristic<uint16_t>(UUID_BEACON_PERIOD_CHAR, &urlFramePeriod);
mbed_official 1:9db4d46bb63f 461 resetChar = new WriteOnlyGattCharacteristic<bool>(UUID_RESET_CHAR, &resetFlag);
mbed_official 1:9db4d46bb63f 462
mbed_official 1:9db4d46bb63f 463 lockChar->setWriteAuthorizationCallback(this, &EddystoneService::lockAuthorizationCallback);
mbed_official 1:9db4d46bb63f 464 unlockChar->setWriteAuthorizationCallback(this, &EddystoneService::unlockAuthorizationCallback);
mbed_official 1:9db4d46bb63f 465 urlDataChar->setWriteAuthorizationCallback(this, &EddystoneService::urlDataWriteAuthorizationCallback);
mbed_official 1:9db4d46bb63f 466 flagsChar->setWriteAuthorizationCallback(this, &EddystoneService::basicAuthorizationCallback<uint8_t>);
mbed_official 1:9db4d46bb63f 467 advPowerLevelsChar->setWriteAuthorizationCallback(this, &EddystoneService::basicAuthorizationCallback<PowerLevels_t>);
mbed_official 1:9db4d46bb63f 468 txPowerModeChar->setWriteAuthorizationCallback(this, &EddystoneService::powerModeAuthorizationCallback);
mbed_official 1:9db4d46bb63f 469 beaconPeriodChar->setWriteAuthorizationCallback(this, &EddystoneService::basicAuthorizationCallback<uint16_t>);
mbed_official 1:9db4d46bb63f 470 resetChar->setWriteAuthorizationCallback(this, &EddystoneService::basicAuthorizationCallback<bool>);
mbed_official 1:9db4d46bb63f 471
mbed_official 1:9db4d46bb63f 472 charTable[0] = lockStateChar;
mbed_official 1:9db4d46bb63f 473 charTable[1] = lockChar;
mbed_official 1:9db4d46bb63f 474 charTable[2] = unlockChar;
mbed_official 1:9db4d46bb63f 475 charTable[3] = urlDataChar;
mbed_official 1:9db4d46bb63f 476 charTable[4] = flagsChar;
mbed_official 1:9db4d46bb63f 477 charTable[5] = advPowerLevelsChar;
mbed_official 1:9db4d46bb63f 478 charTable[6] = txPowerModeChar;
mbed_official 1:9db4d46bb63f 479 charTable[7] = beaconPeriodChar;
mbed_official 1:9db4d46bb63f 480 charTable[8] = resetChar;
mbed_official 1:9db4d46bb63f 481
mbed_official 1:9db4d46bb63f 482 GattService configService(UUID_URL_BEACON_SERVICE, charTable, sizeof(charTable) / sizeof(GattCharacteristic *));
mbed_official 1:9db4d46bb63f 483
mbed_official 1:9db4d46bb63f 484 ble.gattServer().addService(configService);
mbed_official 1:9db4d46bb63f 485 ble.gattServer().onDataWritten(this, &EddystoneService::onDataWrittenCallback);
mbed_official 1:9db4d46bb63f 486 updateCharacteristicValues();
mbed_official 1:9db4d46bb63f 487 setupEddystoneConfigAdvertisements();
mbed_official 1:9db4d46bb63f 488 }
mbed_official 1:9db4d46bb63f 489
mbed_official 1:9db4d46bb63f 490 void EddystoneService::freeConfigCharacteristics(void)
mbed_official 1:9db4d46bb63f 491 {
mbed_official 1:9db4d46bb63f 492 delete lockStateChar;
mbed_official 1:9db4d46bb63f 493 delete lockChar;
mbed_official 1:9db4d46bb63f 494 delete unlockChar;
mbed_official 1:9db4d46bb63f 495 delete urlDataChar;
mbed_official 1:9db4d46bb63f 496 delete flagsChar;
mbed_official 1:9db4d46bb63f 497 delete advPowerLevelsChar;
mbed_official 1:9db4d46bb63f 498 delete txPowerModeChar;
mbed_official 1:9db4d46bb63f 499 delete beaconPeriodChar;
mbed_official 1:9db4d46bb63f 500 delete resetChar;
mbed_official 1:9db4d46bb63f 501 }
mbed_official 1:9db4d46bb63f 502
mbed_official 1:9db4d46bb63f 503 void EddystoneService::stopBeaconService(void)
mbed_official 1:9db4d46bb63f 504 {
mbed_official 1:9db4d46bb63f 505 /* Free unused memory */
mbed_official 1:9db4d46bb63f 506 if (rawUrlFrame) {
mbed_official 1:9db4d46bb63f 507 delete[] rawUrlFrame;
mbed_official 1:9db4d46bb63f 508 rawUrlFrame = NULL;
mbed_official 1:9db4d46bb63f 509 }
mbed_official 1:9db4d46bb63f 510 if (rawUidFrame) {
mbed_official 1:9db4d46bb63f 511 delete[] rawUidFrame;
mbed_official 1:9db4d46bb63f 512 rawUidFrame = NULL;
mbed_official 1:9db4d46bb63f 513 }
mbed_official 1:9db4d46bb63f 514 if (rawTlmFrame) {
mbed_official 1:9db4d46bb63f 515 delete[] rawTlmFrame;
mbed_official 1:9db4d46bb63f 516 rawTlmFrame = NULL;
mbed_official 1:9db4d46bb63f 517 }
mbed_official 1:9db4d46bb63f 518
mbed_official 1:9db4d46bb63f 519 /* Unschedule callbacks */
mbed_official 1:9db4d46bb63f 520 if (urlFrameCallbackHandle) {
mbed_official 1:9db4d46bb63f 521 eventQueue.cancel(urlFrameCallbackHandle);
mbed_official 1:9db4d46bb63f 522 urlFrameCallbackHandle = 0;
mbed_official 1:9db4d46bb63f 523 }
mbed_official 1:9db4d46bb63f 524 if (uidFrameCallbackHandle) {
mbed_official 1:9db4d46bb63f 525 eventQueue.cancel(uidFrameCallbackHandle);
mbed_official 1:9db4d46bb63f 526 uidFrameCallbackHandle = 0;
mbed_official 1:9db4d46bb63f 527 }
mbed_official 1:9db4d46bb63f 528 if (tlmFrameCallbackHandle) {
mbed_official 1:9db4d46bb63f 529 eventQueue.cancel(tlmFrameCallbackHandle);
mbed_official 1:9db4d46bb63f 530 tlmFrameCallbackHandle = 0;
mbed_official 1:9db4d46bb63f 531 }
mbed_official 1:9db4d46bb63f 532 if (radioManagerCallbackHandle) {
mbed_official 1:9db4d46bb63f 533 eventQueue.cancel(radioManagerCallbackHandle);
mbed_official 1:9db4d46bb63f 534 radioManagerCallbackHandle = 0;
mbed_official 1:9db4d46bb63f 535 }
mbed_official 1:9db4d46bb63f 536 }
mbed_official 1:9db4d46bb63f 537
mbed_official 1:9db4d46bb63f 538 /*
mbed_official 1:9db4d46bb63f 539 * Internal helper function used to update the GATT database following any
mbed_official 1:9db4d46bb63f 540 * change to the internal state of the service object.
mbed_official 1:9db4d46bb63f 541 */
mbed_official 1:9db4d46bb63f 542 void EddystoneService::updateCharacteristicValues(void)
mbed_official 1:9db4d46bb63f 543 {
mbed_official 1:9db4d46bb63f 544 ble.gattServer().write(lockStateChar->getValueHandle(), reinterpret_cast<uint8_t *>(&lockState), sizeof(bool));
mbed_official 1:9db4d46bb63f 545 ble.gattServer().write(urlDataChar->getValueHandle(), urlFrame.getEncodedURLData(), urlFrame.getEncodedURLDataLength());
mbed_official 1:9db4d46bb63f 546 ble.gattServer().write(flagsChar->getValueHandle(), &flags, sizeof(uint8_t));
mbed_official 1:9db4d46bb63f 547 ble.gattServer().write(beaconPeriodChar->getValueHandle(), reinterpret_cast<uint8_t *>(&urlFramePeriod), sizeof(uint16_t));
mbed_official 1:9db4d46bb63f 548 ble.gattServer().write(txPowerModeChar->getValueHandle(), &txPowerMode, sizeof(uint8_t));
mbed_official 1:9db4d46bb63f 549 ble.gattServer().write(advPowerLevelsChar->getValueHandle(), reinterpret_cast<uint8_t *>(advPowerLevels), sizeof(PowerLevels_t));
mbed_official 1:9db4d46bb63f 550 ble.gattServer().write(lockChar->getValueHandle(), lock, sizeof(PowerLevels_t));
mbed_official 1:9db4d46bb63f 551 ble.gattServer().write(unlockChar->getValueHandle(), unlock, sizeof(PowerLevels_t));
mbed_official 1:9db4d46bb63f 552 }
mbed_official 1:9db4d46bb63f 553
mbed_official 1:9db4d46bb63f 554 void EddystoneService::setupEddystoneConfigAdvertisements(void)
mbed_official 1:9db4d46bb63f 555 {
mbed_official 1:9db4d46bb63f 556 ble.gap().clearAdvertisingPayload();
mbed_official 1:9db4d46bb63f 557
mbed_official 1:9db4d46bb63f 558 /* Accumulate the new payload */
mbed_official 1:9db4d46bb63f 559 ble.gap().accumulateAdvertisingPayload(
mbed_official 1:9db4d46bb63f 560 GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE
mbed_official 1:9db4d46bb63f 561 );
mbed_official 1:9db4d46bb63f 562 /* UUID is in different order in the ADV frame (!) */
mbed_official 1:9db4d46bb63f 563 uint8_t reversedServiceUUID[sizeof(UUID_URL_BEACON_SERVICE)];
mbed_official 1:9db4d46bb63f 564 for (size_t i = 0; i < sizeof(UUID_URL_BEACON_SERVICE); i++) {
mbed_official 1:9db4d46bb63f 565 reversedServiceUUID[i] = UUID_URL_BEACON_SERVICE[sizeof(UUID_URL_BEACON_SERVICE) - i - 1];
mbed_official 1:9db4d46bb63f 566 }
mbed_official 1:9db4d46bb63f 567 ble.gap().accumulateAdvertisingPayload(
mbed_official 1:9db4d46bb63f 568 GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS,
mbed_official 1:9db4d46bb63f 569 reversedServiceUUID,
mbed_official 1:9db4d46bb63f 570 sizeof(reversedServiceUUID)
mbed_official 1:9db4d46bb63f 571 );
mbed_official 1:9db4d46bb63f 572 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_TAG);
mbed_official 1:9db4d46bb63f 573 setupEddystoneConfigScanResponse();
mbed_official 1:9db4d46bb63f 574
mbed_official 1:9db4d46bb63f 575 ble.gap().setTxPower(radioPowerLevels[txPowerMode]);
mbed_official 1:9db4d46bb63f 576 ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
mbed_official 1:9db4d46bb63f 577 ble.gap().setAdvertisingInterval(advConfigInterval);
mbed_official 1:9db4d46bb63f 578 ble.gap().startAdvertising();
mbed_official 1:9db4d46bb63f 579 }
mbed_official 1:9db4d46bb63f 580
mbed_official 1:9db4d46bb63f 581 void EddystoneService::setupEddystoneConfigScanResponse(void)
mbed_official 1:9db4d46bb63f 582 {
mbed_official 1:9db4d46bb63f 583 ble.gap().clearScanResponse();
mbed_official 1:9db4d46bb63f 584 ble.gap().accumulateScanResponse(
mbed_official 1:9db4d46bb63f 585 GapAdvertisingData::COMPLETE_LOCAL_NAME,
mbed_official 1:9db4d46bb63f 586 reinterpret_cast<const uint8_t *>(deviceName),
mbed_official 1:9db4d46bb63f 587 strlen(deviceName)
mbed_official 1:9db4d46bb63f 588 );
mbed_official 1:9db4d46bb63f 589 ble.gap().accumulateScanResponse(
mbed_official 1:9db4d46bb63f 590 GapAdvertisingData::TX_POWER_LEVEL,
mbed_official 1:9db4d46bb63f 591 reinterpret_cast<uint8_t *>(&advPowerLevels[TX_POWER_MODE_LOW]),
mbed_official 1:9db4d46bb63f 592 sizeof(uint8_t)
mbed_official 1:9db4d46bb63f 593 );
mbed_official 1:9db4d46bb63f 594 }
mbed_official 1:9db4d46bb63f 595
mbed_official 1:9db4d46bb63f 596 void EddystoneService::lockAuthorizationCallback(GattWriteAuthCallbackParams *authParams)
mbed_official 1:9db4d46bb63f 597 {
mbed_official 1:9db4d46bb63f 598 if (lockState) {
mbed_official 1:9db4d46bb63f 599 authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INSUF_AUTHORIZATION;
mbed_official 1:9db4d46bb63f 600 } else if (authParams->len != sizeof(Lock_t)) {
mbed_official 1:9db4d46bb63f 601 authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_ATT_VAL_LENGTH;
mbed_official 1:9db4d46bb63f 602 } else if (authParams->offset != 0) {
mbed_official 1:9db4d46bb63f 603 authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_OFFSET;
mbed_official 1:9db4d46bb63f 604 } else {
mbed_official 1:9db4d46bb63f 605 authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
mbed_official 1:9db4d46bb63f 606 }
mbed_official 1:9db4d46bb63f 607 }
mbed_official 1:9db4d46bb63f 608
mbed_official 1:9db4d46bb63f 609 void EddystoneService::unlockAuthorizationCallback(GattWriteAuthCallbackParams *authParams)
mbed_official 1:9db4d46bb63f 610 {
mbed_official 1:9db4d46bb63f 611 if (!lockState && (authParams->len == sizeof(Lock_t))) {
mbed_official 1:9db4d46bb63f 612 authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
mbed_official 1:9db4d46bb63f 613 } else if (authParams->len != sizeof(Lock_t)) {
mbed_official 1:9db4d46bb63f 614 authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_ATT_VAL_LENGTH;
mbed_official 1:9db4d46bb63f 615 } else if (authParams->offset != 0) {
mbed_official 1:9db4d46bb63f 616 authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_OFFSET;
mbed_official 1:9db4d46bb63f 617 } else if (memcmp(authParams->data, lock, sizeof(Lock_t)) != 0) {
mbed_official 1:9db4d46bb63f 618 authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INSUF_AUTHORIZATION;
mbed_official 1:9db4d46bb63f 619 } else {
mbed_official 1:9db4d46bb63f 620 authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
mbed_official 1:9db4d46bb63f 621 }
mbed_official 1:9db4d46bb63f 622 }
mbed_official 1:9db4d46bb63f 623
mbed_official 1:9db4d46bb63f 624 void EddystoneService::urlDataWriteAuthorizationCallback(GattWriteAuthCallbackParams *authParams)
mbed_official 1:9db4d46bb63f 625 {
mbed_official 1:9db4d46bb63f 626 if (lockState) {
mbed_official 1:9db4d46bb63f 627 authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INSUF_AUTHORIZATION;
mbed_official 1:9db4d46bb63f 628 } else if (authParams->offset != 0) {
mbed_official 1:9db4d46bb63f 629 authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_OFFSET;
mbed_official 1:9db4d46bb63f 630 } else {
mbed_official 1:9db4d46bb63f 631 authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
mbed_official 1:9db4d46bb63f 632 }
mbed_official 1:9db4d46bb63f 633 }
mbed_official 1:9db4d46bb63f 634
mbed_official 1:9db4d46bb63f 635 void EddystoneService::powerModeAuthorizationCallback(GattWriteAuthCallbackParams *authParams)
mbed_official 1:9db4d46bb63f 636 {
mbed_official 1:9db4d46bb63f 637 if (lockState) {
mbed_official 1:9db4d46bb63f 638 authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INSUF_AUTHORIZATION;
mbed_official 1:9db4d46bb63f 639 } else if (authParams->len != sizeof(uint8_t)) {
mbed_official 1:9db4d46bb63f 640 authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_ATT_VAL_LENGTH;
mbed_official 1:9db4d46bb63f 641 } else if (authParams->offset != 0) {
mbed_official 1:9db4d46bb63f 642 authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_OFFSET;
mbed_official 1:9db4d46bb63f 643 } else if (*((uint8_t *)authParams->data) >= NUM_POWER_MODES) {
mbed_official 1:9db4d46bb63f 644 authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_WRITE_NOT_PERMITTED;
mbed_official 1:9db4d46bb63f 645 } else {
mbed_official 1:9db4d46bb63f 646 authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
mbed_official 1:9db4d46bb63f 647 }
mbed_official 1:9db4d46bb63f 648 }
mbed_official 1:9db4d46bb63f 649
mbed_official 1:9db4d46bb63f 650 template <typename T>
mbed_official 1:9db4d46bb63f 651 void EddystoneService::basicAuthorizationCallback(GattWriteAuthCallbackParams *authParams)
mbed_official 1:9db4d46bb63f 652 {
mbed_official 1:9db4d46bb63f 653 if (lockState) {
mbed_official 1:9db4d46bb63f 654 authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INSUF_AUTHORIZATION;
mbed_official 1:9db4d46bb63f 655 } else if (authParams->len != sizeof(T)) {
mbed_official 1:9db4d46bb63f 656 authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_ATT_VAL_LENGTH;
mbed_official 1:9db4d46bb63f 657 } else if (authParams->offset != 0) {
mbed_official 1:9db4d46bb63f 658 authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_OFFSET;
mbed_official 1:9db4d46bb63f 659 } else {
mbed_official 1:9db4d46bb63f 660 authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
mbed_official 1:9db4d46bb63f 661 }
mbed_official 1:9db4d46bb63f 662 }
mbed_official 1:9db4d46bb63f 663
mbed_official 1:9db4d46bb63f 664 /*
mbed_official 1:9db4d46bb63f 665 * This callback is invoked when a GATT client attempts to modify any of the
mbed_official 1:9db4d46bb63f 666 * characteristics of this service. Attempts to do so are also applied to
mbed_official 1:9db4d46bb63f 667 * the internal state of this service object.
mbed_official 1:9db4d46bb63f 668 */
mbed_official 1:9db4d46bb63f 669 void EddystoneService::onDataWrittenCallback(const GattWriteCallbackParams *writeParams)
mbed_official 1:9db4d46bb63f 670 {
mbed_official 1:9db4d46bb63f 671 uint16_t handle = writeParams->handle;
mbed_official 1:9db4d46bb63f 672
mbed_official 1:9db4d46bb63f 673 if (handle == lockChar->getValueHandle()) {
mbed_official 1:9db4d46bb63f 674 memcpy(lock, writeParams->data, sizeof(Lock_t));
mbed_official 1:9db4d46bb63f 675 /* Set the state to be locked by the lock code (note: zeros are a valid lock) */
mbed_official 1:9db4d46bb63f 676 lockState = true;
mbed_official 1:9db4d46bb63f 677 ble.gattServer().write(lockChar->getValueHandle(), lock, sizeof(PowerLevels_t));
mbed_official 1:9db4d46bb63f 678 ble.gattServer().write(lockStateChar->getValueHandle(), reinterpret_cast<uint8_t *>(&lockState), sizeof(bool));
mbed_official 1:9db4d46bb63f 679 } else if (handle == unlockChar->getValueHandle()) {
mbed_official 1:9db4d46bb63f 680 /* Validated earlier */
mbed_official 1:9db4d46bb63f 681 lockState = false;
mbed_official 1:9db4d46bb63f 682 ble.gattServer().write(unlockChar->getValueHandle(), unlock, sizeof(PowerLevels_t));
mbed_official 1:9db4d46bb63f 683 ble.gattServer().write(lockStateChar->getValueHandle(), reinterpret_cast<uint8_t *>(&lockState), sizeof(bool));
mbed_official 1:9db4d46bb63f 684 } else if (handle == urlDataChar->getValueHandle()) {
mbed_official 1:9db4d46bb63f 685 urlFrame.setEncodedURLData(writeParams->data, writeParams->len);
mbed_official 1:9db4d46bb63f 686 ble.gattServer().write(urlDataChar->getValueHandle(), urlFrame.getEncodedURLData(), urlFrame.getEncodedURLDataLength());
mbed_official 1:9db4d46bb63f 687 } else if (handle == flagsChar->getValueHandle()) {
mbed_official 1:9db4d46bb63f 688 flags = *(writeParams->data);
mbed_official 1:9db4d46bb63f 689 ble.gattServer().write(flagsChar->getValueHandle(), &flags, sizeof(uint8_t));
mbed_official 1:9db4d46bb63f 690 } else if (handle == advPowerLevelsChar->getValueHandle()) {
mbed_official 1:9db4d46bb63f 691 memcpy(advPowerLevels, writeParams->data, sizeof(PowerLevels_t));
mbed_official 1:9db4d46bb63f 692 ble.gattServer().write(advPowerLevelsChar->getValueHandle(), reinterpret_cast<uint8_t *>(advPowerLevels), sizeof(PowerLevels_t));
mbed_official 1:9db4d46bb63f 693 } else if (handle == txPowerModeChar->getValueHandle()) {
mbed_official 1:9db4d46bb63f 694 txPowerMode = *(writeParams->data);
mbed_official 1:9db4d46bb63f 695 ble.gattServer().write(txPowerModeChar->getValueHandle(), &txPowerMode, sizeof(uint8_t));
mbed_official 1:9db4d46bb63f 696 } else if (handle == beaconPeriodChar->getValueHandle()) {
mbed_official 1:9db4d46bb63f 697 uint16_t tmpBeaconPeriod = correctAdvertisementPeriod(*((uint16_t *)(writeParams->data)));
mbed_official 1:9db4d46bb63f 698 if (tmpBeaconPeriod != urlFramePeriod) {
mbed_official 1:9db4d46bb63f 699 urlFramePeriod = tmpBeaconPeriod;
mbed_official 1:9db4d46bb63f 700 ble.gattServer().write(beaconPeriodChar->getValueHandle(), reinterpret_cast<uint8_t *>(&urlFramePeriod), sizeof(uint16_t));
mbed_official 1:9db4d46bb63f 701 }
mbed_official 1:9db4d46bb63f 702 } else if (handle == resetChar->getValueHandle() && (*((uint8_t *)writeParams->data) != 0)) {
mbed_official 1:9db4d46bb63f 703 /* Reset characteristics to default values */
mbed_official 1:9db4d46bb63f 704 flags = 0;
mbed_official 1:9db4d46bb63f 705 txPowerMode = TX_POWER_MODE_LOW;
mbed_official 1:9db4d46bb63f 706 urlFramePeriod = DEFAULT_URL_FRAME_PERIOD_MSEC;
mbed_official 1:9db4d46bb63f 707
mbed_official 1:9db4d46bb63f 708 urlFrame.setURLData(DEFAULT_URL);
mbed_official 1:9db4d46bb63f 709 memset(lock, 0, sizeof(Lock_t));
mbed_official 1:9db4d46bb63f 710
mbed_official 1:9db4d46bb63f 711 ble.gattServer().write(urlDataChar->getValueHandle(), urlFrame.getEncodedURLData(), urlFrame.getEncodedURLDataLength());
mbed_official 1:9db4d46bb63f 712 ble.gattServer().write(flagsChar->getValueHandle(), &flags, sizeof(uint8_t));
mbed_official 1:9db4d46bb63f 713 ble.gattServer().write(txPowerModeChar->getValueHandle(), &txPowerMode, sizeof(uint8_t));
mbed_official 1:9db4d46bb63f 714 ble.gattServer().write(beaconPeriodChar->getValueHandle(), reinterpret_cast<uint8_t *>(&urlFramePeriod), sizeof(uint16_t));
mbed_official 1:9db4d46bb63f 715 ble.gattServer().write(lockChar->getValueHandle(), lock, sizeof(PowerLevels_t));
mbed_official 1:9db4d46bb63f 716 }
mbed_official 1:9db4d46bb63f 717 }
mbed_official 1:9db4d46bb63f 718
mbed_official 1:9db4d46bb63f 719 uint16_t EddystoneService::correctAdvertisementPeriod(uint16_t beaconPeriodIn) const
mbed_official 1:9db4d46bb63f 720 {
mbed_official 1:9db4d46bb63f 721 /* Re-map beaconPeriod to within permissible bounds if necessary. */
mbed_official 1:9db4d46bb63f 722 if (beaconPeriodIn != 0) {
mbed_official 1:9db4d46bb63f 723 if (beaconPeriodIn < ble.gap().getMinNonConnectableAdvertisingInterval()) {
mbed_official 1:9db4d46bb63f 724 return ble.gap().getMinNonConnectableAdvertisingInterval();
mbed_official 1:9db4d46bb63f 725 } else if (beaconPeriodIn > ble.gap().getMaxAdvertisingInterval()) {
mbed_official 1:9db4d46bb63f 726 return ble.gap().getMaxAdvertisingInterval();
mbed_official 1:9db4d46bb63f 727 }
mbed_official 1:9db4d46bb63f 728 }
mbed_official 1:9db4d46bb63f 729 return beaconPeriodIn;
mbed_official 1:9db4d46bb63f 730 }
mbed_official 1:9db4d46bb63f 731
mbed_official 1:9db4d46bb63f 732 void EddystoneService::setURLFrameAdvertisingInterval(uint16_t urlFrameIntervalIn)
mbed_official 1:9db4d46bb63f 733 {
mbed_official 1:9db4d46bb63f 734 if (urlFrameIntervalIn == urlFramePeriod) {
mbed_official 1:9db4d46bb63f 735 /* Do nothing */
mbed_official 1:9db4d46bb63f 736 return;
mbed_official 1:9db4d46bb63f 737 }
mbed_official 1:9db4d46bb63f 738
mbed_official 1:9db4d46bb63f 739 /* Make sure the input period is within bounds */
mbed_official 1:9db4d46bb63f 740 urlFramePeriod = correctAdvertisementPeriod(urlFrameIntervalIn);
mbed_official 1:9db4d46bb63f 741
mbed_official 1:9db4d46bb63f 742 if (operationMode == EDDYSTONE_MODE_BEACON) {
mbed_official 1:9db4d46bb63f 743 if (urlFrameCallbackHandle) {
mbed_official 1:9db4d46bb63f 744 eventQueue.cancel(urlFrameCallbackHandle);
mbed_official 1:9db4d46bb63f 745 } else {
mbed_official 1:9db4d46bb63f 746 /* This frame was just enabled */
mbed_official 1:9db4d46bb63f 747 if (!rawUidFrame && urlFramePeriod) {
mbed_official 1:9db4d46bb63f 748 /* Allocate memory for this frame and construct it */
mbed_official 1:9db4d46bb63f 749 rawUrlFrame = new uint8_t[urlFrame.getRawFrameSize()];
mbed_official 1:9db4d46bb63f 750 urlFrame.constructURLFrame(rawUrlFrame, advPowerLevels[txPowerMode]);
mbed_official 1:9db4d46bb63f 751 }
mbed_official 1:9db4d46bb63f 752 }
mbed_official 1:9db4d46bb63f 753
mbed_official 1:9db4d46bb63f 754 if (urlFramePeriod) {
mbed_official 1:9db4d46bb63f 755 /* Currently the only way to change the period of a callback
mbed_official 1:9db4d46bb63f 756 * is to cancel it and reschedule
mbed_official 1:9db4d46bb63f 757 */
mbed_official 1:9db4d46bb63f 758 urlFrameCallbackHandle = eventQueue.post_every(
mbed_official 1:9db4d46bb63f 759 urlFramePeriod,
mbed_official 1:9db4d46bb63f 760 Callback<void(FrameType)>(this, &EddystoneService::enqueueFrame),
mbed_official 1:9db4d46bb63f 761 EDDYSTONE_FRAME_URL
mbed_official 1:9db4d46bb63f 762 );
mbed_official 1:9db4d46bb63f 763 } else {
mbed_official 1:9db4d46bb63f 764 urlFrameCallbackHandle = 0;
mbed_official 1:9db4d46bb63f 765 }
mbed_official 1:9db4d46bb63f 766 } else if (operationMode == EDDYSTONE_MODE_CONFIG) {
mbed_official 1:9db4d46bb63f 767 ble.gattServer().write(beaconPeriodChar->getValueHandle(), reinterpret_cast<uint8_t *>(&urlFramePeriod), sizeof(uint16_t));
mbed_official 1:9db4d46bb63f 768 }
mbed_official 1:9db4d46bb63f 769 }
mbed_official 1:9db4d46bb63f 770
mbed_official 1:9db4d46bb63f 771 void EddystoneService::setUIDFrameAdvertisingInterval(uint16_t uidFrameIntervalIn)
mbed_official 1:9db4d46bb63f 772 {
mbed_official 1:9db4d46bb63f 773 if (uidFrameIntervalIn == uidFramePeriod) {
mbed_official 1:9db4d46bb63f 774 /* Do nothing */
mbed_official 1:9db4d46bb63f 775 return;
mbed_official 1:9db4d46bb63f 776 }
mbed_official 1:9db4d46bb63f 777
mbed_official 1:9db4d46bb63f 778 /* Make sure the input period is within bounds */
mbed_official 1:9db4d46bb63f 779 uidFramePeriod = correctAdvertisementPeriod(uidFrameIntervalIn);
mbed_official 1:9db4d46bb63f 780
mbed_official 1:9db4d46bb63f 781 if (operationMode == EDDYSTONE_MODE_BEACON) {
mbed_official 1:9db4d46bb63f 782 if (uidFrameCallbackHandle) {
mbed_official 1:9db4d46bb63f 783 /* The advertisement interval changes, update the periodic callback */
mbed_official 1:9db4d46bb63f 784 eventQueue.cancel(uidFrameCallbackHandle);
mbed_official 1:9db4d46bb63f 785 } else {
mbed_official 1:9db4d46bb63f 786 /* This frame was just enabled */
mbed_official 1:9db4d46bb63f 787 if (!rawUidFrame && uidFramePeriod) {
mbed_official 1:9db4d46bb63f 788 /* Allocate memory for this frame and construct it */
mbed_official 1:9db4d46bb63f 789 rawUidFrame = new uint8_t[uidFrame.getRawFrameSize()];
mbed_official 1:9db4d46bb63f 790 uidFrame.constructUIDFrame(rawUidFrame, advPowerLevels[txPowerMode]);
mbed_official 1:9db4d46bb63f 791 }
mbed_official 1:9db4d46bb63f 792 }
mbed_official 1:9db4d46bb63f 793
mbed_official 1:9db4d46bb63f 794 if (uidFramePeriod) {
mbed_official 1:9db4d46bb63f 795 /* Currently the only way to change the period of a callback
mbed_official 1:9db4d46bb63f 796 * is to cancel it and reschedule
mbed_official 1:9db4d46bb63f 797 */
mbed_official 1:9db4d46bb63f 798 uidFrameCallbackHandle = eventQueue.post_every(
mbed_official 1:9db4d46bb63f 799 uidFramePeriod,
mbed_official 1:9db4d46bb63f 800 Callback<void(FrameType)>(this, &EddystoneService::enqueueFrame),
mbed_official 1:9db4d46bb63f 801 EDDYSTONE_FRAME_UID
mbed_official 1:9db4d46bb63f 802 );
mbed_official 1:9db4d46bb63f 803 } else {
mbed_official 1:9db4d46bb63f 804 uidFrameCallbackHandle = 0;
mbed_official 1:9db4d46bb63f 805 }
mbed_official 1:9db4d46bb63f 806 }
mbed_official 1:9db4d46bb63f 807 }
mbed_official 1:9db4d46bb63f 808
mbed_official 1:9db4d46bb63f 809 void EddystoneService::setTLMFrameAdvertisingInterval(uint16_t tlmFrameIntervalIn)
mbed_official 1:9db4d46bb63f 810 {
mbed_official 1:9db4d46bb63f 811 if (tlmFrameIntervalIn == tlmFramePeriod) {
mbed_official 1:9db4d46bb63f 812 /* Do nothing */
mbed_official 1:9db4d46bb63f 813 return;
mbed_official 1:9db4d46bb63f 814 }
mbed_official 1:9db4d46bb63f 815
mbed_official 1:9db4d46bb63f 816 /* Make sure the input period is within bounds */
mbed_official 1:9db4d46bb63f 817 tlmFramePeriod = correctAdvertisementPeriod(tlmFrameIntervalIn);
mbed_official 1:9db4d46bb63f 818
mbed_official 1:9db4d46bb63f 819 if (operationMode == EDDYSTONE_MODE_BEACON) {
mbed_official 1:9db4d46bb63f 820 if (tlmFrameCallbackHandle) {
mbed_official 1:9db4d46bb63f 821 /* The advertisement interval changes, update periodic callback */
mbed_official 1:9db4d46bb63f 822 eventQueue.cancel(tlmFrameCallbackHandle);
mbed_official 1:9db4d46bb63f 823 } else {
mbed_official 1:9db4d46bb63f 824 /* This frame was just enabled */
mbed_official 1:9db4d46bb63f 825 if (!rawTlmFrame && tlmFramePeriod) {
mbed_official 1:9db4d46bb63f 826 /* Allocate memory for this frame and construct it */
mbed_official 1:9db4d46bb63f 827 rawTlmFrame = new uint8_t[tlmFrame.getRawFrameSize()];
mbed_official 1:9db4d46bb63f 828 /* Do not construct the TLM frame because this changes every 0.1 seconds */
mbed_official 1:9db4d46bb63f 829 }
mbed_official 1:9db4d46bb63f 830 }
mbed_official 1:9db4d46bb63f 831
mbed_official 1:9db4d46bb63f 832 if (tlmFramePeriod) {
mbed_official 1:9db4d46bb63f 833 /* Currently the only way to change the period of a callback
mbed_official 1:9db4d46bb63f 834 * is to cancel it and reschedule
mbed_official 1:9db4d46bb63f 835 */
mbed_official 1:9db4d46bb63f 836 tlmFrameCallbackHandle = eventQueue.post_every(
mbed_official 1:9db4d46bb63f 837 tlmFramePeriod,
mbed_official 1:9db4d46bb63f 838 Callback<void(FrameType)>(this, &EddystoneService::enqueueFrame),
mbed_official 1:9db4d46bb63f 839 EDDYSTONE_FRAME_TLM
mbed_official 1:9db4d46bb63f 840 );
mbed_official 1:9db4d46bb63f 841 } else {
mbed_official 1:9db4d46bb63f 842 tlmFrameCallbackHandle = 0;
mbed_official 1:9db4d46bb63f 843 }
mbed_official 1:9db4d46bb63f 844 }
mbed_official 1:9db4d46bb63f 845 }