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.
source/EddystoneService.cpp@0:4c8f8bf32a99, 2016-07-26 (annotated)
- 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?
User | Revision | Line number | New 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 ¶msIn, |
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 ¶ms) |
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 | } |