Eddystone beacons broadcast a small amount of information, like URLs, to nearby BLE devices. The canonical source for this example lives at https://github.com/ARMmbed/mbed-os-example-ble/tree/master/BLE_EddystoneService

Eddystone beacons broadcast a small amount of information, like URLs, to nearby BLE devices.

The Eddystone Beacon sample application runs in two stages:

  • On startup, the Configuration Service (which allows modification of the beacon runs for a user-defined period (default - 30 seconds).
  • When the Configuration Service period ends, the Eddystone Service broadcasts advertisement packets.

Running the application

Requirements

You should install the *Physical Web* application on your phone:

- Android version

- iOS version

Note: It is also possible to use a regular scanner to interract with your Eddystone beacon but it requires knowledge about BLE and Eddystone beacon specification out of the scope of this document.

Hardware requirements are in the main readme.

Building instructions

Building with mbed CLI

If you'd like to use mbed CLI to build this, then you should refer to the main readme. The instructions here relate to using the developer.mbed.org Online Compiler

In order to build this example in the mbed Online Compiler, first import the example using the ‘Import’ button on the right hand side.

Next, select a platform to build for. This must either be a platform that supports BLE, for example the NRF51-DK, or one of the following:

List of platforms supporting Bluetooth Low Energy

Or you must also add a piece of hardware and the supporting library that includes a Bluetooth Low Energy driver for that hardware, for example the K64F or NUCLEO_F401RE with the X-NUCLEO-IDB05A1

List of components supporting Bluetooth Low Energy.

Once you have selected your platform, compile the example and drag and drop the resulting binary onto your board.

For general instructions on using the mbed Online Compiler, please see the mbed Handbook

Working with nRF51-based 16K targets

Because of memory constraints, you can't use the SoftDevice 130 (S130) to build for nRF51-based 16K targets. If you are using these targets, then before building:

  1. Open the ``config.json`` file in this sample.
  2. Change ``soft device`` to ``S110``.
  3. Save.

You can now build for nRF51-based 16K targets.

Setting up the beacon

By default, the beacon directs to the url ``http://mbed.org``. You can change this to your own URL in two ways:

  • Manually edit the code in ``main.cpp`` in your copy of the sample.
  • Build and run the application's default code as explained in the building instructions. When the beacon starts up, the Configuration Service runs for 30 seconds (this is the default value; you can change it in ``main.cpp``). While the Configuration Service runs, you can use a BLE scanner on your phone to edit the values the service presents.

Checking for success

  • Build the application and install it on your board as explained in the building instructions.
  • Open the *Physical Web* application on your phone. It will start to search for nearby beacons.

https://developer.mbed.org/teams/mbed-os-examples/code/mbed-os-example-ble-EddystoneService/raw-file/4c8f8bf32a99/img/app_start.png

figure 1 Start of the *Physical Web* application version 0.1.856 on Android

  • When the beacon starts up, the Configuration Service runs for 30 seconds. During this time it is possible to change the URL advertised by the beacon. It is also important to note that during these 30 seconds, your device will not advertise any URL.

https://developer.mbed.org/teams/mbed-os-examples/code/mbed-os-example-ble-EddystoneService/raw-file/4c8f8bf32a99/img/open_configuration.png

figure 2 How to open the beacon configuration view using the *Physical Web* application version 0.1.856 on Android

  • Edit the URL advertised by your beacon.

https://developer.mbed.org/teams/mbed-os-examples/code/mbed-os-example-ble-EddystoneService/raw-file/4c8f8bf32a99/img/edit_url.png

figure 3 How to edit the URL advertised by your beacon using the *Physical Web* application version 0.1.856 on Android

  • Save the URL which will be advertised by your beacon.

https://developer.mbed.org/teams/mbed-os-examples/code/mbed-os-example-ble-EddystoneService/raw-file/4c8f8bf32a99/img/save_url.png

figure 4 How to save your beacon configuration and start advertising URL using the *Physical Web* application version 0.1.856 on Android.

  • Find your device; it should advertise the URL you have set.

https://developer.mbed.org/teams/mbed-os-examples/code/mbed-os-example-ble-EddystoneService/raw-file/4c8f8bf32a99/img/result.png

figure 5 Display of URL advertised by your beacon using the *Physical Web* application version 0.1.856 on Android.

Note: You can use the Eddystone Observer sample instead of a phone application.

Committer:
mbed_official
Date:
Fri Sep 08 14:45:32 2017 +0100
Revision:
43:00b5f99e0a15
Parent:
12:b31d7c0f906c
Merge pull request #102 from adbridge/master

Updating mbed-os to mbed-os-5.5.6
.
Commit copied from https://github.com/ARMmbed/mbed-os-example-ble

Who changed what in which revision?

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