Run on TY51822r3 board with ACC sensor (LIS3DH or BMC050)

Dependencies:   BLE_API LIS3DH mbed nRF51822 BMC050 nRF51_LowPwr nRF51_Vdd

Fork of BLE_EddystoneBeacon_Service by Bluetooth Low Energy

Committer:
kenjiArai
Date:
Sat Jun 11 01:51:59 2016 +0000
Revision:
37:ea459e6c6a35
Parent:
34:f6d4a699a1ea
Added low power mode (use nRF51_LowPwr library) for reduce Idle Current

Who changed what in which revision?

UserRevisionLine numberNew contents of line
andresag 34:f6d4a699a1ea 1 /* mbed Microcontroller Library
andresag 34:f6d4a699a1ea 2 * Copyright (c) 2006-2015 ARM Limited
andresag 34:f6d4a699a1ea 3 *
andresag 34:f6d4a699a1ea 4 * Licensed under the Apache License, Version 2.0 (the "License");
andresag 34:f6d4a699a1ea 5 * you may not use this file except in compliance with the License.
andresag 34:f6d4a699a1ea 6 * You may obtain a copy of the License at
andresag 34:f6d4a699a1ea 7 *
andresag 34:f6d4a699a1ea 8 * http://www.apache.org/licenses/LICENSE-2.0
andresag 34:f6d4a699a1ea 9 *
andresag 34:f6d4a699a1ea 10 * Unless required by applicable law or agreed to in writing, software
andresag 34:f6d4a699a1ea 11 * distributed under the License is distributed on an "AS IS" BASIS,
andresag 34:f6d4a699a1ea 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
andresag 34:f6d4a699a1ea 13 * See the License for the specific language governing permissions and
andresag 34:f6d4a699a1ea 14 * limitations under the License.
andresag 34:f6d4a699a1ea 15 */
andresag 34:f6d4a699a1ea 16
andresag 34:f6d4a699a1ea 17 #include "EddystoneService.h"
andresag 34:f6d4a699a1ea 18
andresag 34:f6d4a699a1ea 19 /* Initialise the EddystoneService using parameters from persistent storage */
andresag 34:f6d4a699a1ea 20 EddystoneService::EddystoneService(BLE &bleIn,
andresag 34:f6d4a699a1ea 21 EddystoneParams_t &paramsIn,
andresag 34:f6d4a699a1ea 22 const PowerLevels_t &advPowerLevelsIn,
andresag 34:f6d4a699a1ea 23 const PowerLevels_t &radioPowerLevelsIn,
andresag 34:f6d4a699a1ea 24 uint32_t advConfigIntervalIn) :
andresag 34:f6d4a699a1ea 25 ble(bleIn),
andresag 34:f6d4a699a1ea 26 operationMode(EDDYSTONE_MODE_NONE),
andresag 34:f6d4a699a1ea 27 urlFrame(paramsIn.urlData, paramsIn.urlDataLength),
andresag 34:f6d4a699a1ea 28 uidFrame(paramsIn.uidNamespaceID, paramsIn.uidInstanceID),
andresag 34:f6d4a699a1ea 29 tlmFrame(paramsIn.tlmVersion),
andresag 34:f6d4a699a1ea 30 resetFlag(false),
andresag 34:f6d4a699a1ea 31 tlmBatteryVoltageCallback(NULL),
andresag 34:f6d4a699a1ea 32 tlmBeaconTemperatureCallback(NULL)
andresag 34:f6d4a699a1ea 33 {
andresag 34:f6d4a699a1ea 34 lockState = paramsIn.lockState;
andresag 34:f6d4a699a1ea 35 flags = paramsIn.flags;
andresag 34:f6d4a699a1ea 36 txPowerMode = paramsIn.txPowerMode;
andresag 34:f6d4a699a1ea 37 beaconPeriod = correctAdvertisementPeriod(paramsIn.beaconPeriod);
andresag 34:f6d4a699a1ea 38
andresag 34:f6d4a699a1ea 39 memcpy(lock, paramsIn.lock, sizeof(Lock_t));
andresag 34:f6d4a699a1ea 40 memcpy(unlock, paramsIn.unlock, sizeof(Lock_t));
andresag 34:f6d4a699a1ea 41
andresag 34:f6d4a699a1ea 42 eddystoneConstructorHelper(advPowerLevelsIn, radioPowerLevelsIn, advConfigIntervalIn);
andresag 34:f6d4a699a1ea 43 }
andresag 34:f6d4a699a1ea 44
andresag 34:f6d4a699a1ea 45 /* When using this constructor we need to call setURLData,
andresag 34:f6d4a699a1ea 46 * setTMLData and setUIDData to initialise values manually
andresag 34:f6d4a699a1ea 47 */
andresag 34:f6d4a699a1ea 48 EddystoneService::EddystoneService(BLE &bleIn,
andresag 34:f6d4a699a1ea 49 const PowerLevels_t &advPowerLevelsIn,
andresag 34:f6d4a699a1ea 50 const PowerLevels_t &radioPowerLevelsIn,
andresag 34:f6d4a699a1ea 51 uint32_t advConfigIntervalIn) :
andresag 34:f6d4a699a1ea 52 ble(bleIn),
andresag 34:f6d4a699a1ea 53 operationMode(EDDYSTONE_MODE_NONE),
andresag 34:f6d4a699a1ea 54 urlFrame(),
andresag 34:f6d4a699a1ea 55 uidFrame(),
andresag 34:f6d4a699a1ea 56 tlmFrame(),
andresag 34:f6d4a699a1ea 57 lockState(false),
andresag 34:f6d4a699a1ea 58 resetFlag(false),
andresag 34:f6d4a699a1ea 59 lock(),
andresag 34:f6d4a699a1ea 60 unlock(),
andresag 34:f6d4a699a1ea 61 flags(0),
andresag 34:f6d4a699a1ea 62 txPowerMode(0),
andresag 34:f6d4a699a1ea 63 beaconPeriod(DEFAULT_BEACON_PERIOD_MSEC),
andresag 34:f6d4a699a1ea 64 tlmBatteryVoltageCallback(NULL),
andresag 34:f6d4a699a1ea 65 tlmBeaconTemperatureCallback(NULL)
andresag 34:f6d4a699a1ea 66 {
andresag 34:f6d4a699a1ea 67 eddystoneConstructorHelper(advPowerLevelsIn, radioPowerLevelsIn, advConfigIntervalIn);
andresag 34:f6d4a699a1ea 68 }
andresag 34:f6d4a699a1ea 69
andresag 34:f6d4a699a1ea 70 /* Setup callback to update BatteryVoltage in TLM frame */
andresag 34:f6d4a699a1ea 71 void EddystoneService::onTLMBatteryVoltageUpdate(TlmUpdateCallback_t tlmBatteryVoltageCallbackIn)
andresag 34:f6d4a699a1ea 72 {
andresag 34:f6d4a699a1ea 73 tlmBatteryVoltageCallback = tlmBatteryVoltageCallbackIn;
andresag 34:f6d4a699a1ea 74 }
andresag 34:f6d4a699a1ea 75
andresag 34:f6d4a699a1ea 76 /* Setup callback to update BeaconTemperature in TLM frame */
andresag 34:f6d4a699a1ea 77 void EddystoneService::onTLMBeaconTemperatureUpdate(TlmUpdateCallback_t tlmBeaconTemperatureCallbackIn)
andresag 34:f6d4a699a1ea 78 {
andresag 34:f6d4a699a1ea 79 tlmBeaconTemperatureCallback = tlmBeaconTemperatureCallbackIn;
andresag 34:f6d4a699a1ea 80 }
andresag 34:f6d4a699a1ea 81
andresag 34:f6d4a699a1ea 82 void EddystoneService::setTLMData(uint8_t tlmVersionIn)
andresag 34:f6d4a699a1ea 83 {
andresag 34:f6d4a699a1ea 84 tlmFrame.setTLMData(tlmVersionIn);
andresag 34:f6d4a699a1ea 85 }
andresag 34:f6d4a699a1ea 86
andresag 34:f6d4a699a1ea 87 void EddystoneService::setURLData(const char *urlDataIn)
andresag 34:f6d4a699a1ea 88 {
andresag 34:f6d4a699a1ea 89 urlFrame.setURLData(urlDataIn);
andresag 34:f6d4a699a1ea 90 }
andresag 34:f6d4a699a1ea 91
andresag 34:f6d4a699a1ea 92 void EddystoneService::setUIDData(const UIDNamespaceID_t *uidNamespaceIDIn, const UIDInstanceID_t *uidInstanceIDIn)
andresag 34:f6d4a699a1ea 93 {
andresag 34:f6d4a699a1ea 94 uidFrame.setUIDData(uidNamespaceIDIn, uidInstanceIDIn);
andresag 34:f6d4a699a1ea 95 }
andresag 34:f6d4a699a1ea 96
andresag 34:f6d4a699a1ea 97 EddystoneService::EddystoneError_t EddystoneService::startConfigService(void)
andresag 34:f6d4a699a1ea 98 {
andresag 34:f6d4a699a1ea 99 if (operationMode == EDDYSTONE_MODE_CONFIG) {
andresag 34:f6d4a699a1ea 100 /* Nothing to do, we are already in config mode */
andresag 34:f6d4a699a1ea 101 return EDDYSTONE_ERROR_NONE;
andresag 34:f6d4a699a1ea 102 } else if (advConfigInterval == 0) {
andresag 34:f6d4a699a1ea 103 /* Nothing to do, the advertisement interval is 0 */
andresag 34:f6d4a699a1ea 104 return EDDYSTONE_ERROR_INVALID_ADVERTISING_INTERVAL;
andresag 34:f6d4a699a1ea 105 }
andresag 34:f6d4a699a1ea 106
andresag 34:f6d4a699a1ea 107 if (operationMode == EDDYSTONE_MODE_BEACON) {
andresag 34:f6d4a699a1ea 108 ble.shutdown();
andresag 34:f6d4a699a1ea 109 /* Free unused memory */
andresag 34:f6d4a699a1ea 110 freeBeaconFrames();
andresag 34:f6d4a699a1ea 111 operationMode = EDDYSTONE_MODE_CONFIG;
andresag 34:f6d4a699a1ea 112 ble.init(this, &EddystoneService::bleInitComplete);
andresag 34:f6d4a699a1ea 113 return EDDYSTONE_ERROR_NONE;
andresag 34:f6d4a699a1ea 114 }
andresag 34:f6d4a699a1ea 115
andresag 34:f6d4a699a1ea 116 operationMode = EDDYSTONE_MODE_CONFIG;
andresag 34:f6d4a699a1ea 117 setupConfigService();
andresag 34:f6d4a699a1ea 118 return EDDYSTONE_ERROR_NONE;
andresag 34:f6d4a699a1ea 119 }
andresag 34:f6d4a699a1ea 120
andresag 34:f6d4a699a1ea 121 EddystoneService::EddystoneError_t EddystoneService::startBeaconService(uint16_t consecUrlFramesIn, uint16_t consecUidFramesIn, uint16_t consecTlmFramesIn)
andresag 34:f6d4a699a1ea 122 {
andresag 34:f6d4a699a1ea 123 if (operationMode == EDDYSTONE_MODE_BEACON) {
andresag 34:f6d4a699a1ea 124 /* Nothing to do, we are already in beacon mode */
andresag 34:f6d4a699a1ea 125 return EDDYSTONE_ERROR_NONE;
andresag 34:f6d4a699a1ea 126 } else if (!consecUrlFramesIn && !consecUidFramesIn && !consecTlmFramesIn) {
andresag 34:f6d4a699a1ea 127 /* Nothing to do, the user wants 0 consecutive frames of everything */
andresag 34:f6d4a699a1ea 128 return EDDYSTONE_ERROR_INVALID_CONSEC_FRAMES;
andresag 34:f6d4a699a1ea 129 } else if (!beaconPeriod) {
andresag 34:f6d4a699a1ea 130 /* Nothing to do, the period is 0 for all frames */
andresag 34:f6d4a699a1ea 131 return EDDYSTONE_ERROR_INVALID_BEACON_PERIOD;
andresag 34:f6d4a699a1ea 132 }
andresag 34:f6d4a699a1ea 133
andresag 34:f6d4a699a1ea 134 /* Setup tracking of the current advertised frame. Note that this will
andresag 34:f6d4a699a1ea 135 * cause URL or UID frames to be advertised first!
andresag 34:f6d4a699a1ea 136 */
andresag 34:f6d4a699a1ea 137 currentAdvertisedFrame = EDDYSTONE_FRAME_TLM;
andresag 34:f6d4a699a1ea 138 consecFrames[EDDYSTONE_FRAME_URL] = consecUrlFramesIn;
andresag 34:f6d4a699a1ea 139 consecFrames[EDDYSTONE_FRAME_UID] = consecUidFramesIn;
andresag 34:f6d4a699a1ea 140 consecFrames[EDDYSTONE_FRAME_TLM] = consecTlmFramesIn;
andresag 34:f6d4a699a1ea 141
andresag 34:f6d4a699a1ea 142 memset(currentConsecFrames, 0, sizeof(uint16_t) * NUM_EDDYSTONE_FRAMES);
andresag 34:f6d4a699a1ea 143
andresag 34:f6d4a699a1ea 144 if (operationMode == EDDYSTONE_MODE_CONFIG) {
andresag 34:f6d4a699a1ea 145 ble.shutdown();
andresag 34:f6d4a699a1ea 146 /* Free unused memory */
andresag 34:f6d4a699a1ea 147 freeConfigCharacteristics();
andresag 34:f6d4a699a1ea 148 operationMode = EDDYSTONE_MODE_BEACON;
andresag 34:f6d4a699a1ea 149 ble.init(this, &EddystoneService::bleInitComplete);
andresag 34:f6d4a699a1ea 150 return EDDYSTONE_ERROR_NONE;
andresag 34:f6d4a699a1ea 151 }
andresag 34:f6d4a699a1ea 152
andresag 34:f6d4a699a1ea 153 operationMode = EDDYSTONE_MODE_BEACON;
andresag 34:f6d4a699a1ea 154 setupBeaconService();
andresag 34:f6d4a699a1ea 155 return EDDYSTONE_ERROR_NONE;
andresag 34:f6d4a699a1ea 156 }
andresag 34:f6d4a699a1ea 157
andresag 34:f6d4a699a1ea 158 /* It is not the responsibility of the Eddystone implementation to store
andresag 34:f6d4a699a1ea 159 * the configured parameters in persistent storage since this is
andresag 34:f6d4a699a1ea 160 * platform-specific. So we provide this function that returns the
andresag 34:f6d4a699a1ea 161 * configured values that need to be stored and the main application
andresag 34:f6d4a699a1ea 162 * takes care of storing them.
andresag 34:f6d4a699a1ea 163 */
andresag 34:f6d4a699a1ea 164 void EddystoneService::getEddystoneParams(EddystoneParams_t *params)
andresag 34:f6d4a699a1ea 165 {
andresag 34:f6d4a699a1ea 166 params->lockState = lockState;
andresag 34:f6d4a699a1ea 167 params->flags = flags;
andresag 34:f6d4a699a1ea 168 params->txPowerMode = txPowerMode;
andresag 34:f6d4a699a1ea 169 params->beaconPeriod = beaconPeriod;
andresag 34:f6d4a699a1ea 170 params->tlmVersion = tlmFrame.getTLMVersion();
andresag 34:f6d4a699a1ea 171 params->urlDataLength = urlFrame.getEncodedURLDataLength();
andresag 34:f6d4a699a1ea 172
andresag 34:f6d4a699a1ea 173 memcpy(params->advPowerLevels, advPowerLevels, sizeof(PowerLevels_t));
andresag 34:f6d4a699a1ea 174 memcpy(params->lock, lock, sizeof(Lock_t));
andresag 34:f6d4a699a1ea 175 memcpy(params->unlock, unlock, sizeof(Lock_t));
andresag 34:f6d4a699a1ea 176 memcpy(params->urlData, urlFrame.getEncodedURLData(), urlFrame.getEncodedURLDataLength());
andresag 34:f6d4a699a1ea 177 memcpy(params->uidNamespaceID, uidFrame.getUIDNamespaceID(), sizeof(UIDNamespaceID_t));
andresag 34:f6d4a699a1ea 178 memcpy(params->uidInstanceID, uidFrame.getUIDInstanceID(), sizeof(UIDInstanceID_t));
andresag 34:f6d4a699a1ea 179 }
andresag 34:f6d4a699a1ea 180
andresag 34:f6d4a699a1ea 181 /* Helper function used only once during constructing the object to avoid
andresag 34:f6d4a699a1ea 182 * duplicated code.
andresag 34:f6d4a699a1ea 183 */
andresag 34:f6d4a699a1ea 184 void EddystoneService::eddystoneConstructorHelper(const PowerLevels_t &advPowerLevelsIn,
andresag 34:f6d4a699a1ea 185 const PowerLevels_t &radioPowerLevelsIn,
andresag 34:f6d4a699a1ea 186 uint32_t advConfigIntervalIn)
andresag 34:f6d4a699a1ea 187 {
andresag 34:f6d4a699a1ea 188 advConfigInterval = (advConfigIntervalIn > 0) ? correctAdvertisementPeriod(advConfigIntervalIn) : 0;
andresag 34:f6d4a699a1ea 189
andresag 34:f6d4a699a1ea 190 memcpy(radioPowerLevels, radioPowerLevelsIn, sizeof(PowerLevels_t));
andresag 34:f6d4a699a1ea 191 memcpy(advPowerLevels, advPowerLevelsIn, sizeof(PowerLevels_t));
andresag 34:f6d4a699a1ea 192
andresag 34:f6d4a699a1ea 193 /* TODO: Note that this timer is started from the time EddystoneService
andresag 34:f6d4a699a1ea 194 * is initialised and NOT from when the device is booted. So app needs
andresag 34:f6d4a699a1ea 195 * to take care that EddystoneService is one of the first things to be
andresag 34:f6d4a699a1ea 196 * started!
andresag 34:f6d4a699a1ea 197 */
andresag 34:f6d4a699a1ea 198 timeSinceBootTimer.start();
andresag 34:f6d4a699a1ea 199 }
andresag 34:f6d4a699a1ea 200
andresag 34:f6d4a699a1ea 201 /* When changing modes, we shutdown and init the BLE instance, so
andresag 34:f6d4a699a1ea 202 * this is needed to complete the initialisation task.
andresag 34:f6d4a699a1ea 203 */
andresag 34:f6d4a699a1ea 204 void EddystoneService::bleInitComplete(BLE::InitializationCompleteCallbackContext* initContext)
andresag 34:f6d4a699a1ea 205 {
andresag 34:f6d4a699a1ea 206 if (initContext->error != BLE_ERROR_NONE) {
andresag 34:f6d4a699a1ea 207 /* Initialisation failed */
andresag 34:f6d4a699a1ea 208 return;
andresag 34:f6d4a699a1ea 209 }
andresag 34:f6d4a699a1ea 210
andresag 34:f6d4a699a1ea 211 switch (operationMode) {
andresag 34:f6d4a699a1ea 212 case EDDYSTONE_MODE_CONFIG:
andresag 34:f6d4a699a1ea 213 setupConfigService();
andresag 34:f6d4a699a1ea 214 break;
andresag 34:f6d4a699a1ea 215 case EDDYSTONE_MODE_BEACON:
andresag 34:f6d4a699a1ea 216 setupBeaconService();
andresag 34:f6d4a699a1ea 217 break;
andresag 34:f6d4a699a1ea 218 default:
andresag 34:f6d4a699a1ea 219 /* Some error occurred */
andresag 34:f6d4a699a1ea 220 break;
andresag 34:f6d4a699a1ea 221 }
andresag 34:f6d4a699a1ea 222 }
andresag 34:f6d4a699a1ea 223
andresag 34:f6d4a699a1ea 224 void EddystoneService::swapAdvertisedFrame(void)
andresag 34:f6d4a699a1ea 225 {
andresag 34:f6d4a699a1ea 226 /* This essentially works out which is the next frame to be swapped in
andresag 34:f6d4a699a1ea 227 * and updated the advertised packets. It will eventually terminate
andresag 34:f6d4a699a1ea 228 * and in the worst case the frame swapped in is the current advertised
andresag 34:f6d4a699a1ea 229 * frame.
andresag 34:f6d4a699a1ea 230 */
andresag 34:f6d4a699a1ea 231 while (true) {
andresag 34:f6d4a699a1ea 232 currentAdvertisedFrame = (currentAdvertisedFrame + 1) % NUM_EDDYSTONE_FRAMES;
andresag 34:f6d4a699a1ea 233
andresag 34:f6d4a699a1ea 234 if (currentAdvertisedFrame == EDDYSTONE_FRAME_URL && consecFrames[EDDYSTONE_FRAME_URL] > 0) {
andresag 34:f6d4a699a1ea 235 updateAdvertisementPacket(rawUrlFrame, urlFrame.getRawFrameSize());
andresag 34:f6d4a699a1ea 236 return;
andresag 34:f6d4a699a1ea 237 } else if (currentAdvertisedFrame == EDDYSTONE_FRAME_UID && consecFrames[EDDYSTONE_FRAME_UID] > 0) {
andresag 34:f6d4a699a1ea 238 updateAdvertisementPacket(rawUidFrame, uidFrame.getRawFrameSize());
andresag 34:f6d4a699a1ea 239 return;
andresag 34:f6d4a699a1ea 240 } else if (currentAdvertisedFrame == EDDYSTONE_FRAME_TLM && consecFrames[EDDYSTONE_FRAME_UID] > 0) {
andresag 34:f6d4a699a1ea 241 updateRawTLMFrame();
andresag 34:f6d4a699a1ea 242 updateAdvertisementPacket(rawTlmFrame, tlmFrame.getRawFrameSize());
andresag 34:f6d4a699a1ea 243 return;
andresag 34:f6d4a699a1ea 244 }
andresag 34:f6d4a699a1ea 245 }
andresag 34:f6d4a699a1ea 246 }
andresag 34:f6d4a699a1ea 247
andresag 34:f6d4a699a1ea 248 /* Helper function that calls user-defined functions to update Battery Voltage and Temperature (if available),
andresag 34:f6d4a699a1ea 249 * then updates the raw frame data and finally updates the actual advertised packet. This operation must be
andresag 34:f6d4a699a1ea 250 * done fairly often because the TLM frame TimeSinceBoot must have a 0.1 secs resolution according to the
andresag 34:f6d4a699a1ea 251 * Eddystone specification.
andresag 34:f6d4a699a1ea 252 */
andresag 34:f6d4a699a1ea 253 void EddystoneService::updateRawTLMFrame(void)
andresag 34:f6d4a699a1ea 254 {
andresag 34:f6d4a699a1ea 255 if (tlmBeaconTemperatureCallback != NULL) {
andresag 34:f6d4a699a1ea 256 tlmFrame.updateBeaconTemperature((*tlmBeaconTemperatureCallback)(tlmFrame.getBeaconTemperature()));
andresag 34:f6d4a699a1ea 257 }
andresag 34:f6d4a699a1ea 258 if (tlmBatteryVoltageCallback != NULL) {
andresag 34:f6d4a699a1ea 259 tlmFrame.updateBatteryVoltage((*tlmBatteryVoltageCallback)(tlmFrame.getBatteryVoltage()));
andresag 34:f6d4a699a1ea 260 }
andresag 34:f6d4a699a1ea 261 tlmFrame.updateTimeSinceBoot(timeSinceBootTimer.read_ms());
andresag 34:f6d4a699a1ea 262 tlmFrame.constructTLMFrame(rawTlmFrame);
andresag 34:f6d4a699a1ea 263 }
andresag 34:f6d4a699a1ea 264
andresag 34:f6d4a699a1ea 265 void EddystoneService::updateAdvertisementPacket(const uint8_t* rawFrame, size_t rawFrameLength)
andresag 34:f6d4a699a1ea 266 {
andresag 34:f6d4a699a1ea 267 ble.gap().clearAdvertisingPayload();
andresag 34:f6d4a699a1ea 268 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
andresag 34:f6d4a699a1ea 269 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, EDDYSTONE_UUID, sizeof(EDDYSTONE_UUID));
andresag 34:f6d4a699a1ea 270 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::SERVICE_DATA, rawFrame, rawFrameLength);
andresag 34:f6d4a699a1ea 271 }
andresag 34:f6d4a699a1ea 272
andresag 34:f6d4a699a1ea 273 void EddystoneService::setupBeaconService(void)
andresag 34:f6d4a699a1ea 274 {
andresag 34:f6d4a699a1ea 275 /* Initialise arrays to hold constructed raw frames */
andresag 34:f6d4a699a1ea 276 if (consecFrames[EDDYSTONE_FRAME_URL] > 0) {
andresag 34:f6d4a699a1ea 277 rawUrlFrame = new uint8_t[urlFrame.getRawFrameSize()];
andresag 34:f6d4a699a1ea 278 urlFrame.constructURLFrame(rawUrlFrame, advPowerLevels[txPowerMode]);
andresag 34:f6d4a699a1ea 279 }
andresag 34:f6d4a699a1ea 280
andresag 34:f6d4a699a1ea 281 if (consecFrames[EDDYSTONE_FRAME_UID] > 0) {
andresag 34:f6d4a699a1ea 282 rawUidFrame = new uint8_t[uidFrame.getRawFrameSize()];
andresag 34:f6d4a699a1ea 283 uidFrame.constructUIDFrame(rawUidFrame, advPowerLevels[txPowerMode]);
andresag 34:f6d4a699a1ea 284 }
andresag 34:f6d4a699a1ea 285
andresag 34:f6d4a699a1ea 286 if (consecFrames[EDDYSTONE_FRAME_TLM] > 0) {
andresag 34:f6d4a699a1ea 287 rawTlmFrame = new uint8_t[tlmFrame.getRawFrameSize()];
andresag 34:f6d4a699a1ea 288 /* Do not initialise because we have to reconstruct every 0.1 secs */
andresag 34:f6d4a699a1ea 289 }
andresag 34:f6d4a699a1ea 290
andresag 34:f6d4a699a1ea 291 /* Configure advertisements */
andresag 34:f6d4a699a1ea 292 ble.gap().setTxPower(radioPowerLevels[txPowerMode]);
andresag 34:f6d4a699a1ea 293 ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED);
andresag 34:f6d4a699a1ea 294 ble.gap().setAdvertisingInterval(beaconPeriod);
andresag 34:f6d4a699a1ea 295 ble.gap().onRadioNotification(this, &EddystoneService::radioNotificationCallback);
andresag 34:f6d4a699a1ea 296 ble.gap().initRadioNotification();
andresag 34:f6d4a699a1ea 297
andresag 34:f6d4a699a1ea 298 /* Set advertisement packet payload */
andresag 34:f6d4a699a1ea 299 swapAdvertisedFrame();
andresag 34:f6d4a699a1ea 300
andresag 34:f6d4a699a1ea 301 /* Start advertising */
andresag 34:f6d4a699a1ea 302 ble.gap().startAdvertising();
andresag 34:f6d4a699a1ea 303 }
andresag 34:f6d4a699a1ea 304
andresag 34:f6d4a699a1ea 305 void EddystoneService::setupConfigService(void)
andresag 34:f6d4a699a1ea 306 {
andresag 34:f6d4a699a1ea 307 lockStateChar = new ReadOnlyGattCharacteristic<bool>(UUID_LOCK_STATE_CHAR, &lockState);
andresag 34:f6d4a699a1ea 308 lockChar = new WriteOnlyArrayGattCharacteristic<uint8_t, sizeof(Lock_t)>(UUID_LOCK_CHAR, lock);
andresag 34:f6d4a699a1ea 309 unlockChar = new WriteOnlyArrayGattCharacteristic<uint8_t, sizeof(Lock_t)>(UUID_UNLOCK_CHAR, unlock);
andresag 34:f6d4a699a1ea 310 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);
andresag 34:f6d4a699a1ea 311 flagsChar = new ReadWriteGattCharacteristic<uint8_t>(UUID_FLAGS_CHAR, &flags);
andresag 34:f6d4a699a1ea 312 advPowerLevelsChar = new ReadWriteArrayGattCharacteristic<int8_t, sizeof(PowerLevels_t)>(UUID_ADV_POWER_LEVELS_CHAR, advPowerLevels);
andresag 34:f6d4a699a1ea 313 txPowerModeChar = new ReadWriteGattCharacteristic<uint8_t>(UUID_TX_POWER_MODE_CHAR, &txPowerMode);
andresag 34:f6d4a699a1ea 314 beaconPeriodChar = new ReadWriteGattCharacteristic<uint16_t>(UUID_BEACON_PERIOD_CHAR, &beaconPeriod);
andresag 34:f6d4a699a1ea 315 resetChar = new WriteOnlyGattCharacteristic<bool>(UUID_RESET_CHAR, &resetFlag);
andresag 34:f6d4a699a1ea 316
andresag 34:f6d4a699a1ea 317 lockChar->setWriteAuthorizationCallback(this, &EddystoneService::lockAuthorizationCallback);
andresag 34:f6d4a699a1ea 318 unlockChar->setWriteAuthorizationCallback(this, &EddystoneService::unlockAuthorizationCallback);
andresag 34:f6d4a699a1ea 319 urlDataChar->setWriteAuthorizationCallback(this, &EddystoneService::urlDataWriteAuthorizationCallback);
andresag 34:f6d4a699a1ea 320 flagsChar->setWriteAuthorizationCallback(this, &EddystoneService::basicAuthorizationCallback<uint8_t>);
andresag 34:f6d4a699a1ea 321 advPowerLevelsChar->setWriteAuthorizationCallback(this, &EddystoneService::basicAuthorizationCallback<PowerLevels_t>);
andresag 34:f6d4a699a1ea 322 txPowerModeChar->setWriteAuthorizationCallback(this, &EddystoneService::powerModeAuthorizationCallback);
andresag 34:f6d4a699a1ea 323 beaconPeriodChar->setWriteAuthorizationCallback(this, &EddystoneService::basicAuthorizationCallback<uint16_t>);
andresag 34:f6d4a699a1ea 324 resetChar->setWriteAuthorizationCallback(this, &EddystoneService::basicAuthorizationCallback<bool>);
andresag 34:f6d4a699a1ea 325
andresag 34:f6d4a699a1ea 326 charTable[0] = lockStateChar;
andresag 34:f6d4a699a1ea 327 charTable[1] = lockChar;
andresag 34:f6d4a699a1ea 328 charTable[2] = unlockChar;
andresag 34:f6d4a699a1ea 329 charTable[3] = urlDataChar;
andresag 34:f6d4a699a1ea 330 charTable[4] = flagsChar;
andresag 34:f6d4a699a1ea 331 charTable[5] = advPowerLevelsChar;
andresag 34:f6d4a699a1ea 332 charTable[6] = txPowerModeChar;
andresag 34:f6d4a699a1ea 333 charTable[7] = beaconPeriodChar;
andresag 34:f6d4a699a1ea 334 charTable[8] = resetChar;
andresag 34:f6d4a699a1ea 335
andresag 34:f6d4a699a1ea 336 GattService configService(UUID_URL_BEACON_SERVICE, charTable, sizeof(charTable) / sizeof(GattCharacteristic *));
andresag 34:f6d4a699a1ea 337
andresag 34:f6d4a699a1ea 338 ble.gattServer().addService(configService);
andresag 34:f6d4a699a1ea 339 ble.gattServer().onDataWritten(this, &EddystoneService::onDataWrittenCallback);
andresag 34:f6d4a699a1ea 340 updateCharacteristicValues();
andresag 34:f6d4a699a1ea 341 setupEddystoneConfigAdvertisements();
andresag 34:f6d4a699a1ea 342 }
andresag 34:f6d4a699a1ea 343
andresag 34:f6d4a699a1ea 344 void EddystoneService::freeConfigCharacteristics(void)
andresag 34:f6d4a699a1ea 345 {
andresag 34:f6d4a699a1ea 346 delete lockStateChar;
andresag 34:f6d4a699a1ea 347 delete lockChar;
andresag 34:f6d4a699a1ea 348 delete unlockChar;
andresag 34:f6d4a699a1ea 349 delete urlDataChar;
andresag 34:f6d4a699a1ea 350 delete flagsChar;
andresag 34:f6d4a699a1ea 351 delete advPowerLevelsChar;
andresag 34:f6d4a699a1ea 352 delete txPowerModeChar;
andresag 34:f6d4a699a1ea 353 delete beaconPeriodChar;
andresag 34:f6d4a699a1ea 354 delete resetChar;
andresag 34:f6d4a699a1ea 355 }
andresag 34:f6d4a699a1ea 356
andresag 34:f6d4a699a1ea 357 void EddystoneService::freeBeaconFrames(void)
andresag 34:f6d4a699a1ea 358 {
andresag 34:f6d4a699a1ea 359 delete[] rawUrlFrame;
andresag 34:f6d4a699a1ea 360 delete[] rawUidFrame;
andresag 34:f6d4a699a1ea 361 delete[] rawTlmFrame;
andresag 34:f6d4a699a1ea 362 }
andresag 34:f6d4a699a1ea 363
andresag 34:f6d4a699a1ea 364 void EddystoneService::radioNotificationCallback(bool radioActive)
andresag 34:f6d4a699a1ea 365 {
andresag 34:f6d4a699a1ea 366 if (radioActive) {
andresag 34:f6d4a699a1ea 367 /* Do nothing */
andresag 34:f6d4a699a1ea 368 return;
andresag 34:f6d4a699a1ea 369 }
andresag 34:f6d4a699a1ea 370
andresag 34:f6d4a699a1ea 371 tlmFrame.updatePduCount();
andresag 34:f6d4a699a1ea 372 currentConsecFrames[currentAdvertisedFrame]++;
andresag 34:f6d4a699a1ea 373
andresag 34:f6d4a699a1ea 374 if (consecFrames[currentAdvertisedFrame] > currentConsecFrames[currentAdvertisedFrame]) {
andresag 34:f6d4a699a1ea 375 if (currentAdvertisedFrame == EDDYSTONE_FRAME_TLM) {
andresag 34:f6d4a699a1ea 376 /* Update the TLM frame otherwise we will not meet the 0.1 secs resolution of
andresag 34:f6d4a699a1ea 377 * the Eddystone specification.
andresag 34:f6d4a699a1ea 378 */
andresag 34:f6d4a699a1ea 379 updateRawTLMFrame();
andresag 34:f6d4a699a1ea 380 updateAdvertisementPacket(rawTlmFrame, tlmFrame.getRawFrameSize());
andresag 34:f6d4a699a1ea 381 }
andresag 34:f6d4a699a1ea 382 /* Keep advertising the same frame */
andresag 34:f6d4a699a1ea 383 return;
andresag 34:f6d4a699a1ea 384 }
andresag 34:f6d4a699a1ea 385
andresag 34:f6d4a699a1ea 386 currentConsecFrames[currentAdvertisedFrame] = 0;
andresag 34:f6d4a699a1ea 387
andresag 34:f6d4a699a1ea 388 #ifdef YOTTA_CFG_MBED_OS
andresag 34:f6d4a699a1ea 389 minar::Scheduler::postCallback(this, &EddystoneService::swapAdvertisedFrame);
andresag 34:f6d4a699a1ea 390 #else
andresag 34:f6d4a699a1ea 391 swapAdvertisedFrameTimeout.attach_us(this, &EddystoneService::swapAdvertisedFrame, 1);
andresag 34:f6d4a699a1ea 392 #endif
andresag 34:f6d4a699a1ea 393 }
andresag 34:f6d4a699a1ea 394
andresag 34:f6d4a699a1ea 395 /*
andresag 34:f6d4a699a1ea 396 * Internal helper function used to update the GATT database following any
andresag 34:f6d4a699a1ea 397 * change to the internal state of the service object.
andresag 34:f6d4a699a1ea 398 */
andresag 34:f6d4a699a1ea 399 void EddystoneService::updateCharacteristicValues(void)
andresag 34:f6d4a699a1ea 400 {
andresag 34:f6d4a699a1ea 401 ble.gattServer().write(lockStateChar->getValueHandle(), reinterpret_cast<uint8_t *>(&lockState), sizeof(bool));
andresag 34:f6d4a699a1ea 402 ble.gattServer().write(urlDataChar->getValueHandle(), urlFrame.getEncodedURLData(), urlFrame.getEncodedURLDataLength());
andresag 34:f6d4a699a1ea 403 ble.gattServer().write(flagsChar->getValueHandle(), &flags, sizeof(uint8_t));
andresag 34:f6d4a699a1ea 404 ble.gattServer().write(beaconPeriodChar->getValueHandle(), reinterpret_cast<uint8_t *>(&beaconPeriod), sizeof(uint16_t));
andresag 34:f6d4a699a1ea 405 ble.gattServer().write(txPowerModeChar->getValueHandle(), &txPowerMode, sizeof(uint8_t));
andresag 34:f6d4a699a1ea 406 ble.gattServer().write(advPowerLevelsChar->getValueHandle(), reinterpret_cast<uint8_t *>(advPowerLevels), sizeof(PowerLevels_t));
andresag 34:f6d4a699a1ea 407 ble.gattServer().write(lockChar->getValueHandle(), lock, sizeof(PowerLevels_t));
andresag 34:f6d4a699a1ea 408 ble.gattServer().write(unlockChar->getValueHandle(), unlock, sizeof(PowerLevels_t));
andresag 34:f6d4a699a1ea 409 }
andresag 34:f6d4a699a1ea 410
andresag 34:f6d4a699a1ea 411 void EddystoneService::setupEddystoneConfigAdvertisements(void)
andresag 34:f6d4a699a1ea 412 {
andresag 34:f6d4a699a1ea 413 ble.gap().clearAdvertisingPayload();
andresag 34:f6d4a699a1ea 414 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
andresag 34:f6d4a699a1ea 415
andresag 34:f6d4a699a1ea 416 /* UUID is in different order in the ADV frame (!) */
andresag 34:f6d4a699a1ea 417 uint8_t reversedServiceUUID[sizeof(UUID_URL_BEACON_SERVICE)];
andresag 34:f6d4a699a1ea 418 for (size_t i = 0; i < sizeof(UUID_URL_BEACON_SERVICE); i++) {
andresag 34:f6d4a699a1ea 419 reversedServiceUUID[i] = UUID_URL_BEACON_SERVICE[sizeof(UUID_URL_BEACON_SERVICE) - i - 1];
andresag 34:f6d4a699a1ea 420 }
andresag 34:f6d4a699a1ea 421 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS, reversedServiceUUID, sizeof(reversedServiceUUID));
andresag 34:f6d4a699a1ea 422 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_TAG);
andresag 34:f6d4a699a1ea 423 ble.gap().accumulateScanResponse(GapAdvertisingData::COMPLETE_LOCAL_NAME, reinterpret_cast<const uint8_t *>(&DEVICE_NAME), sizeof(DEVICE_NAME));
andresag 34:f6d4a699a1ea 424 ble.gap().accumulateScanResponse(
andresag 34:f6d4a699a1ea 425 GapAdvertisingData::TX_POWER_LEVEL,
andresag 34:f6d4a699a1ea 426 reinterpret_cast<uint8_t *>(&advPowerLevels[TX_POWER_MODE_LOW]),
andresag 34:f6d4a699a1ea 427 sizeof(uint8_t));
andresag 34:f6d4a699a1ea 428
andresag 34:f6d4a699a1ea 429 ble.gap().setTxPower(radioPowerLevels[txPowerMode]);
andresag 34:f6d4a699a1ea 430 ble.gap().setDeviceName(reinterpret_cast<const uint8_t *>(&DEVICE_NAME));
andresag 34:f6d4a699a1ea 431 ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
andresag 34:f6d4a699a1ea 432 ble.gap().setAdvertisingInterval(advConfigInterval);
andresag 34:f6d4a699a1ea 433 ble.gap().startAdvertising();
andresag 34:f6d4a699a1ea 434 }
andresag 34:f6d4a699a1ea 435
andresag 34:f6d4a699a1ea 436 void EddystoneService::lockAuthorizationCallback(GattWriteAuthCallbackParams *authParams)
andresag 34:f6d4a699a1ea 437 {
andresag 34:f6d4a699a1ea 438 if (lockState) {
andresag 34:f6d4a699a1ea 439 authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INSUF_AUTHORIZATION;
andresag 34:f6d4a699a1ea 440 } else if (authParams->len != sizeof(Lock_t)) {
andresag 34:f6d4a699a1ea 441 authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_ATT_VAL_LENGTH;
andresag 34:f6d4a699a1ea 442 } else if (authParams->offset != 0) {
andresag 34:f6d4a699a1ea 443 authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_OFFSET;
andresag 34:f6d4a699a1ea 444 } else {
andresag 34:f6d4a699a1ea 445 authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
andresag 34:f6d4a699a1ea 446 }
andresag 34:f6d4a699a1ea 447 }
andresag 34:f6d4a699a1ea 448
andresag 34:f6d4a699a1ea 449 void EddystoneService::unlockAuthorizationCallback(GattWriteAuthCallbackParams *authParams)
andresag 34:f6d4a699a1ea 450 {
andresag 34:f6d4a699a1ea 451 if (!lockState && (authParams->len == sizeof(Lock_t))) {
andresag 34:f6d4a699a1ea 452 authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
andresag 34:f6d4a699a1ea 453 } else if (authParams->len != sizeof(Lock_t)) {
andresag 34:f6d4a699a1ea 454 authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_ATT_VAL_LENGTH;
andresag 34:f6d4a699a1ea 455 } else if (authParams->offset != 0) {
andresag 34:f6d4a699a1ea 456 authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_OFFSET;
andresag 34:f6d4a699a1ea 457 } else if (memcmp(authParams->data, lock, sizeof(Lock_t)) != 0) {
andresag 34:f6d4a699a1ea 458 authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INSUF_AUTHORIZATION;
andresag 34:f6d4a699a1ea 459 } else {
andresag 34:f6d4a699a1ea 460 authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
andresag 34:f6d4a699a1ea 461 }
andresag 34:f6d4a699a1ea 462 }
andresag 34:f6d4a699a1ea 463
andresag 34:f6d4a699a1ea 464 void EddystoneService::urlDataWriteAuthorizationCallback(GattWriteAuthCallbackParams *authParams)
andresag 34:f6d4a699a1ea 465 {
andresag 34:f6d4a699a1ea 466 if (lockState) {
andresag 34:f6d4a699a1ea 467 authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INSUF_AUTHORIZATION;
andresag 34:f6d4a699a1ea 468 } else if (authParams->offset != 0) {
andresag 34:f6d4a699a1ea 469 authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_OFFSET;
andresag 34:f6d4a699a1ea 470 } else {
andresag 34:f6d4a699a1ea 471 authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
andresag 34:f6d4a699a1ea 472 }
andresag 34:f6d4a699a1ea 473 }
andresag 34:f6d4a699a1ea 474
andresag 34:f6d4a699a1ea 475 void EddystoneService::powerModeAuthorizationCallback(GattWriteAuthCallbackParams *authParams)
andresag 34:f6d4a699a1ea 476 {
andresag 34:f6d4a699a1ea 477 if (lockState) {
andresag 34:f6d4a699a1ea 478 authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INSUF_AUTHORIZATION;
andresag 34:f6d4a699a1ea 479 } else if (authParams->len != sizeof(uint8_t)) {
andresag 34:f6d4a699a1ea 480 authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_ATT_VAL_LENGTH;
andresag 34:f6d4a699a1ea 481 } else if (authParams->offset != 0) {
andresag 34:f6d4a699a1ea 482 authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_OFFSET;
andresag 34:f6d4a699a1ea 483 } else if (*((uint8_t *)authParams->data) >= NUM_POWER_MODES) {
andresag 34:f6d4a699a1ea 484 authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_WRITE_NOT_PERMITTED;
andresag 34:f6d4a699a1ea 485 } else {
andresag 34:f6d4a699a1ea 486 authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
andresag 34:f6d4a699a1ea 487 }
andresag 34:f6d4a699a1ea 488 }
andresag 34:f6d4a699a1ea 489
andresag 34:f6d4a699a1ea 490 template <typename T>
andresag 34:f6d4a699a1ea 491 void EddystoneService::basicAuthorizationCallback(GattWriteAuthCallbackParams *authParams)
andresag 34:f6d4a699a1ea 492 {
andresag 34:f6d4a699a1ea 493 if (lockState) {
andresag 34:f6d4a699a1ea 494 authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INSUF_AUTHORIZATION;
andresag 34:f6d4a699a1ea 495 } else if (authParams->len != sizeof(T)) {
andresag 34:f6d4a699a1ea 496 authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_ATT_VAL_LENGTH;
andresag 34:f6d4a699a1ea 497 } else if (authParams->offset != 0) {
andresag 34:f6d4a699a1ea 498 authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_OFFSET;
andresag 34:f6d4a699a1ea 499 } else {
andresag 34:f6d4a699a1ea 500 authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
andresag 34:f6d4a699a1ea 501 }
andresag 34:f6d4a699a1ea 502 }
andresag 34:f6d4a699a1ea 503
andresag 34:f6d4a699a1ea 504 /*
andresag 34:f6d4a699a1ea 505 * This callback is invoked when a GATT client attempts to modify any of the
andresag 34:f6d4a699a1ea 506 * characteristics of this service. Attempts to do so are also applied to
andresag 34:f6d4a699a1ea 507 * the internal state of this service object.
andresag 34:f6d4a699a1ea 508 */
andresag 34:f6d4a699a1ea 509 void EddystoneService::onDataWrittenCallback(const GattWriteCallbackParams *writeParams)
andresag 34:f6d4a699a1ea 510 {
andresag 34:f6d4a699a1ea 511 uint16_t handle = writeParams->handle;
andresag 34:f6d4a699a1ea 512
andresag 34:f6d4a699a1ea 513 if (handle == lockChar->getValueHandle()) {
andresag 34:f6d4a699a1ea 514 memcpy(lock, writeParams->data, sizeof(Lock_t));
andresag 34:f6d4a699a1ea 515 /* Set the state to be locked by the lock code (note: zeros are a valid lock) */
andresag 34:f6d4a699a1ea 516 lockState = true;
andresag 34:f6d4a699a1ea 517 ble.gattServer().write(lockChar->getValueHandle(), lock, sizeof(PowerLevels_t));
andresag 34:f6d4a699a1ea 518 ble.gattServer().write(lockStateChar->getValueHandle(), reinterpret_cast<uint8_t *>(&lockState), sizeof(bool));
andresag 34:f6d4a699a1ea 519 } else if (handle == unlockChar->getValueHandle()) {
andresag 34:f6d4a699a1ea 520 /* Validated earlier */
andresag 34:f6d4a699a1ea 521 lockState = false;
andresag 34:f6d4a699a1ea 522 ble.gattServer().write(unlockChar->getValueHandle(), unlock, sizeof(PowerLevels_t));
andresag 34:f6d4a699a1ea 523 ble.gattServer().write(lockStateChar->getValueHandle(), reinterpret_cast<uint8_t *>(&lockState), sizeof(bool));
andresag 34:f6d4a699a1ea 524 } else if (handle == urlDataChar->getValueHandle()) {
andresag 34:f6d4a699a1ea 525 urlFrame.setEncodedURLData(writeParams->data, writeParams->len);
andresag 34:f6d4a699a1ea 526 ble.gattServer().write(urlDataChar->getValueHandle(), urlFrame.getEncodedURLData(), urlFrame.getEncodedURLDataLength());
andresag 34:f6d4a699a1ea 527 } else if (handle == flagsChar->getValueHandle()) {
andresag 34:f6d4a699a1ea 528 flags = *(writeParams->data);
andresag 34:f6d4a699a1ea 529 ble.gattServer().write(flagsChar->getValueHandle(), &flags, sizeof(uint8_t));
andresag 34:f6d4a699a1ea 530 } else if (handle == advPowerLevelsChar->getValueHandle()) {
andresag 34:f6d4a699a1ea 531 memcpy(advPowerLevels, writeParams->data, sizeof(PowerLevels_t));
andresag 34:f6d4a699a1ea 532 ble.gattServer().write(advPowerLevelsChar->getValueHandle(), reinterpret_cast<uint8_t *>(advPowerLevels), sizeof(PowerLevels_t));
andresag 34:f6d4a699a1ea 533 } else if (handle == txPowerModeChar->getValueHandle()) {
andresag 34:f6d4a699a1ea 534 txPowerMode = *(writeParams->data);
andresag 34:f6d4a699a1ea 535 ble.gattServer().write(txPowerModeChar->getValueHandle(), &txPowerMode, sizeof(uint8_t));
andresag 34:f6d4a699a1ea 536 } else if (handle == beaconPeriodChar->getValueHandle()) {
andresag 34:f6d4a699a1ea 537 uint16_t tmpBeaconPeriod = correctAdvertisementPeriod(*((uint16_t *)(writeParams->data)));
andresag 34:f6d4a699a1ea 538 if (tmpBeaconPeriod != beaconPeriod) {
andresag 34:f6d4a699a1ea 539 beaconPeriod = tmpBeaconPeriod;
andresag 34:f6d4a699a1ea 540 ble.gattServer().write(beaconPeriodChar->getValueHandle(), reinterpret_cast<uint8_t *>(&beaconPeriod), sizeof(uint16_t));
andresag 34:f6d4a699a1ea 541 }
andresag 34:f6d4a699a1ea 542 } else if (handle == resetChar->getValueHandle() && (*((uint8_t *)writeParams->data) != 0)) {
andresag 34:f6d4a699a1ea 543 /* Reset characteristics to default values */
andresag 34:f6d4a699a1ea 544 flags = 0;
andresag 34:f6d4a699a1ea 545 txPowerMode = TX_POWER_MODE_LOW;
andresag 34:f6d4a699a1ea 546 beaconPeriod = DEFAULT_BEACON_PERIOD_MSEC;
andresag 34:f6d4a699a1ea 547
andresag 34:f6d4a699a1ea 548 urlFrame.setURLData(DEFAULT_URL);
andresag 34:f6d4a699a1ea 549 memset(lock, 0, sizeof(Lock_t));
andresag 34:f6d4a699a1ea 550
andresag 34:f6d4a699a1ea 551 ble.gattServer().write(urlDataChar->getValueHandle(), urlFrame.getEncodedURLData(), urlFrame.getEncodedURLDataLength());
andresag 34:f6d4a699a1ea 552 ble.gattServer().write(flagsChar->getValueHandle(), &flags, sizeof(uint8_t));
andresag 34:f6d4a699a1ea 553 ble.gattServer().write(txPowerModeChar->getValueHandle(), &txPowerMode, sizeof(uint8_t));
andresag 34:f6d4a699a1ea 554 ble.gattServer().write(beaconPeriodChar->getValueHandle(), reinterpret_cast<uint8_t *>(&beaconPeriod), sizeof(uint16_t));
andresag 34:f6d4a699a1ea 555 ble.gattServer().write(lockChar->getValueHandle(), lock, sizeof(PowerLevels_t));
andresag 34:f6d4a699a1ea 556 }
andresag 34:f6d4a699a1ea 557 }
andresag 34:f6d4a699a1ea 558
andresag 34:f6d4a699a1ea 559 uint16_t EddystoneService::correctAdvertisementPeriod(uint16_t beaconPeriodIn) const
andresag 34:f6d4a699a1ea 560 {
andresag 34:f6d4a699a1ea 561 /* Re-map beaconPeriod to within permissible bounds if necessary. */
andresag 34:f6d4a699a1ea 562 if (beaconPeriodIn != 0) {
andresag 34:f6d4a699a1ea 563 if (beaconPeriodIn < ble.gap().getMinAdvertisingInterval()) {
andresag 34:f6d4a699a1ea 564 return ble.gap().getMinAdvertisingInterval();
andresag 34:f6d4a699a1ea 565 } else if (beaconPeriodIn > ble.gap().getMaxAdvertisingInterval()) {
andresag 34:f6d4a699a1ea 566 return ble.gap().getMaxAdvertisingInterval();
andresag 34:f6d4a699a1ea 567 }
andresag 34:f6d4a699a1ea 568 }
andresag 34:f6d4a699a1ea 569 return beaconPeriodIn;
andresag 34:f6d4a699a1ea 570 }