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:
Tue Jul 26 14:40:25 2016 +0100
Revision:
0:4c8f8bf32a99
Child:
1:9db4d46bb63f
Update example at tag mbed-os-5.0.1-rc1

Who changed what in which revision?

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