TYBLE16 on os5 sample programs

Dependencies:   BME280 TextLCD nRF51_Vdd

Fork of TYBLE16_mbedlized_os5_BASE by Kenji Arai

Please refer following notebook.
/users/kenjiArai/notebook/tyble16-module-as-mbed-os-5-board-mbedlization/

Committer:
kenjiArai
Date:
Sat Apr 14 04:56:34 2018 +0000
Revision:
1:9011c83e4178
added samples

Who changed what in which revision?

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