BLE EddystoneService example

This example is a fork of the following mbed-os example:

https://developer.mbed.org/teams/mbed-os-examples/code/mbed-os-example-ble-EddystoneService/

Please read the documentation in this page.

Committer:
Vincent Coubard
Date:
Thu Jul 28 23:27:37 2016 +0100
Revision:
2:9ee673e0b86a
Parent:
1:9db4d46bb63f
Child:
3:5120491ba317
Sync with mbed-os-5.1.0-rc3

Who changed what in which revision?

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