![](/media/cache/img/default_profile.jpg.50x50_q85.jpg)
Changed to work with St Board
Dependencies: BLE_API X_NUCLEO_IDB0XA1 mbed
Fork of BLE_URIBeacon by
main.cpp@13:b82d8db73633, 2015-02-13 (annotated)
- Committer:
- rgrover1
- Date:
- Fri Feb 13 13:05:49 2015 +0000
- Revision:
- 13:b82d8db73633
- Parent:
- 11:c77cc2b74101
- Child:
- 14:868a1207022d
Updating to Bill's version of the URIBeacon app
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
rgrover1 | 13:b82d8db73633 | 1 | /* |
rgrover1 | 13:b82d8db73633 | 2 | * Copyright 2014-2015 Google Inc. All rights reserved. |
rgrover1 | 0:790a27ffc99b | 3 | * |
rgrover1 | 0:790a27ffc99b | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
rgrover1 | 0:790a27ffc99b | 5 | * you may not use this file except in compliance with the License. |
rgrover1 | 0:790a27ffc99b | 6 | * You may obtain a copy of the License at |
rgrover1 | 0:790a27ffc99b | 7 | * |
rgrover1 | 13:b82d8db73633 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
rgrover1 | 0:790a27ffc99b | 9 | * |
rgrover1 | 0:790a27ffc99b | 10 | * Unless required by applicable law or agreed to in writing, software |
rgrover1 | 0:790a27ffc99b | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
rgrover1 | 0:790a27ffc99b | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
rgrover1 | 0:790a27ffc99b | 13 | * See the License for the specific language governing permissions and |
rgrover1 | 0:790a27ffc99b | 14 | * limitations under the License. |
rgrover1 | 0:790a27ffc99b | 15 | */ |
rgrover1 | 0:790a27ffc99b | 16 | |
rgrover1 | 13:b82d8db73633 | 17 | #include <stdint.h> |
rgrover1 | 13:b82d8db73633 | 18 | #include <stddef.h> |
rgrover1 | 13:b82d8db73633 | 19 | #include <nrf_error.h> |
rgrover1 | 0:790a27ffc99b | 20 | #include "mbed.h" |
rgrover1 | 0:790a27ffc99b | 21 | #include "BLEDevice.h" |
rgrover1 | 13:b82d8db73633 | 22 | #include "URIBeaconConfigService.h" |
rgrover1 | 11:c77cc2b74101 | 23 | #include "DFUService.h" |
rgrover1 | 13:b82d8db73633 | 24 | #include "pstorage.h" |
rgrover1 | 11:c77cc2b74101 | 25 | #include "DeviceInformationService.h" |
rgrover1 | 0:790a27ffc99b | 26 | |
rgrover1 | 13:b82d8db73633 | 27 | // Struct to hold persistent data across power cycles |
rgrover1 | 13:b82d8db73633 | 28 | struct PersistentData_t { |
rgrover1 | 13:b82d8db73633 | 29 | uint32_t magic; |
rgrover1 | 13:b82d8db73633 | 30 | URIBeaconConfigService::Params_t params; |
rgrover1 | 13:b82d8db73633 | 31 | uint8_t pad[4]; |
rgrover1 | 13:b82d8db73633 | 32 | } __attribute__ ((aligned (4))); |
rgrover1 | 13:b82d8db73633 | 33 | |
rgrover1 | 13:b82d8db73633 | 34 | static const int PERSISTENT_DATA_ALIGNED_SIZE = sizeof(PersistentData_t); |
rgrover1 | 13:b82d8db73633 | 35 | // Seconds after power-on that config service is available. |
rgrover1 | 13:b82d8db73633 | 36 | static const int ADVERTISING_TIMEOUT_SECONDS = 60; |
rgrover1 | 13:b82d8db73633 | 37 | // Advertising interval for config service. |
rgrover1 | 13:b82d8db73633 | 38 | static const int ADVERTISING_INTERVAL_MSEC = 1000; |
rgrover1 | 13:b82d8db73633 | 39 | // Maximum size of service data in ADV packets |
rgrover1 | 13:b82d8db73633 | 40 | static const int SERVICE_DATA_MAX = 31; |
rgrover1 | 13:b82d8db73633 | 41 | // Magic that identifies persistent storage |
rgrover1 | 13:b82d8db73633 | 42 | static const uint32_t MAGIC = 0x1BEAC000; |
rgrover1 | 13:b82d8db73633 | 43 | // Values for ADV packets related to firmware levels |
rgrover1 | 13:b82d8db73633 | 44 | static URIBeaconConfigService::PowerLevels_t defaultAdvPowerLevels = {-20, -4, 0, 10}; |
rgrover1 | 13:b82d8db73633 | 45 | // Values for setTxPower() indexed by power mode. |
rgrover1 | 13:b82d8db73633 | 46 | static const int8_t firmwarePowerLevels[] = {-20, -4, 0, 10}; |
rgrover1 | 13:b82d8db73633 | 47 | |
rgrover1 | 0:790a27ffc99b | 48 | BLEDevice ble; |
rgrover1 | 13:b82d8db73633 | 49 | URIBeaconConfigService *uriBeaconConfig; |
rgrover1 | 13:b82d8db73633 | 50 | pstorage_handle_t pstorageHandle; |
rgrover1 | 13:b82d8db73633 | 51 | PersistentData_t persistentData; |
rgrover1 | 13:b82d8db73633 | 52 | |
rgrover1 | 13:b82d8db73633 | 53 | /* LEDs for indication */ |
rgrover1 | 13:b82d8db73633 | 54 | DigitalOut connectionStateLed(LED1); |
rgrover1 | 13:b82d8db73633 | 55 | DigitalOut advertisingStateLed(LED2); |
rgrover1 | 13:b82d8db73633 | 56 | |
rgrover1 | 13:b82d8db73633 | 57 | /* Dummy callback handler needed by Nordic's pstorage module. */ |
rgrover1 | 13:b82d8db73633 | 58 | void pstorageNotificationCallback(pstorage_handle_t *p_handle, |
rgrover1 | 13:b82d8db73633 | 59 | uint8_t op_code, |
rgrover1 | 13:b82d8db73633 | 60 | uint32_t result, |
rgrover1 | 13:b82d8db73633 | 61 | uint8_t * p_data, |
rgrover1 | 13:b82d8db73633 | 62 | uint32_t data_len) { |
rgrover1 | 13:b82d8db73633 | 63 | /* APP_ERROR_CHECK(result); */ |
rgrover1 | 13:b82d8db73633 | 64 | } |
rgrover1 | 13:b82d8db73633 | 65 | |
rgrover1 | 13:b82d8db73633 | 66 | void pstorageLoad() { |
rgrover1 | 13:b82d8db73633 | 67 | pstorage_init(); |
rgrover1 | 13:b82d8db73633 | 68 | pstorage_module_param_t pstorageParams = { |
rgrover1 | 13:b82d8db73633 | 69 | .cb = pstorageNotificationCallback, |
rgrover1 | 13:b82d8db73633 | 70 | .block_size = PERSISTENT_DATA_ALIGNED_SIZE, |
rgrover1 | 13:b82d8db73633 | 71 | .block_count = 1 |
rgrover1 | 13:b82d8db73633 | 72 | }; |
rgrover1 | 13:b82d8db73633 | 73 | pstorage_register(&pstorageParams, &pstorageHandle); |
rgrover1 | 13:b82d8db73633 | 74 | if (pstorage_load(reinterpret_cast<uint8_t *>(&persistentData), |
rgrover1 | 13:b82d8db73633 | 75 | &pstorageHandle, PERSISTENT_DATA_ALIGNED_SIZE, 0) != NRF_SUCCESS) { |
rgrover1 | 13:b82d8db73633 | 76 | // On failure zero out and let the service reset to defaults |
rgrover1 | 13:b82d8db73633 | 77 | memset(&persistentData, 0, sizeof(PersistentData_t)); |
rgrover1 | 13:b82d8db73633 | 78 | } |
rgrover1 | 13:b82d8db73633 | 79 | } |
rgrover1 | 13:b82d8db73633 | 80 | |
rgrover1 | 13:b82d8db73633 | 81 | |
rgrover1 | 13:b82d8db73633 | 82 | void pstorageSave() { |
rgrover1 | 13:b82d8db73633 | 83 | if (persistentData.magic != MAGIC) { |
rgrover1 | 13:b82d8db73633 | 84 | persistentData.magic = MAGIC; |
rgrover1 | 13:b82d8db73633 | 85 | pstorage_store(&pstorageHandle, |
rgrover1 | 13:b82d8db73633 | 86 | reinterpret_cast<uint8_t *>(&persistentData), |
rgrover1 | 13:b82d8db73633 | 87 | sizeof(PersistentData_t), |
rgrover1 | 13:b82d8db73633 | 88 | 0 /* offset */); |
rgrover1 | 13:b82d8db73633 | 89 | } else { |
rgrover1 | 13:b82d8db73633 | 90 | pstorage_update(&pstorageHandle, |
rgrover1 | 13:b82d8db73633 | 91 | reinterpret_cast<uint8_t *>(&persistentData), |
rgrover1 | 13:b82d8db73633 | 92 | sizeof(PersistentData_t), |
rgrover1 | 13:b82d8db73633 | 93 | 0 /* offset */); |
rgrover1 | 13:b82d8db73633 | 94 | } |
rgrover1 | 13:b82d8db73633 | 95 | } |
rgrover1 | 13:b82d8db73633 | 96 | |
rgrover1 | 13:b82d8db73633 | 97 | void startAdvertisingUriBeaconConfig() { |
rgrover1 | 13:b82d8db73633 | 98 | char DEVICE_NAME[] = "mUriBeacon Config"; |
rgrover1 | 13:b82d8db73633 | 99 | |
rgrover1 | 13:b82d8db73633 | 100 | ble.clearAdvertisingPayload(); |
rgrover1 | 13:b82d8db73633 | 101 | |
rgrover1 | 13:b82d8db73633 | 102 | // Stops advertising the UriBeacon Config Service after a delay |
rgrover1 | 13:b82d8db73633 | 103 | ble.setAdvertisingTimeout(ADVERTISING_TIMEOUT_SECONDS); |
rgrover1 | 13:b82d8db73633 | 104 | |
rgrover1 | 13:b82d8db73633 | 105 | ble.accumulateAdvertisingPayload( |
rgrover1 | 13:b82d8db73633 | 106 | GapAdvertisingData::BREDR_NOT_SUPPORTED | |
rgrover1 | 13:b82d8db73633 | 107 | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); |
rgrover1 | 13:b82d8db73633 | 108 | |
rgrover1 | 13:b82d8db73633 | 109 | // UUID is in different order in the ADV frame (!) |
rgrover1 | 13:b82d8db73633 | 110 | uint8_t reversedServiceUUID[sizeof(UUID_URI_BEACON_SERVICE)]; |
rgrover1 | 13:b82d8db73633 | 111 | for (unsigned int i = 0; i < sizeof(UUID_URI_BEACON_SERVICE); i++) { |
rgrover1 | 13:b82d8db73633 | 112 | reversedServiceUUID[i] = |
rgrover1 | 13:b82d8db73633 | 113 | UUID_URI_BEACON_SERVICE[sizeof(UUID_URI_BEACON_SERVICE) - i - 1]; |
rgrover1 | 13:b82d8db73633 | 114 | } |
rgrover1 | 13:b82d8db73633 | 115 | ble.accumulateAdvertisingPayload( |
rgrover1 | 13:b82d8db73633 | 116 | GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS, |
rgrover1 | 13:b82d8db73633 | 117 | reversedServiceUUID, |
rgrover1 | 13:b82d8db73633 | 118 | sizeof(reversedServiceUUID)); |
rgrover1 | 0:790a27ffc99b | 119 | |
rgrover1 | 13:b82d8db73633 | 120 | ble.accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_TAG); |
rgrover1 | 13:b82d8db73633 | 121 | ble.accumulateScanResponse( |
rgrover1 | 13:b82d8db73633 | 122 | GapAdvertisingData::COMPLETE_LOCAL_NAME, |
rgrover1 | 13:b82d8db73633 | 123 | reinterpret_cast<uint8_t *>(&DEVICE_NAME), |
rgrover1 | 13:b82d8db73633 | 124 | sizeof(DEVICE_NAME)); |
rgrover1 | 13:b82d8db73633 | 125 | ble.accumulateScanResponse( |
rgrover1 | 13:b82d8db73633 | 126 | GapAdvertisingData::TX_POWER_LEVEL, |
rgrover1 | 13:b82d8db73633 | 127 | reinterpret_cast<uint8_t *>( |
rgrover1 | 13:b82d8db73633 | 128 | &defaultAdvPowerLevels[URIBeaconConfigService::TX_POWER_MODE_LOW]), |
rgrover1 | 13:b82d8db73633 | 129 | sizeof(uint8_t)); |
rgrover1 | 13:b82d8db73633 | 130 | |
rgrover1 | 13:b82d8db73633 | 131 | ble.setTxPower( |
rgrover1 | 13:b82d8db73633 | 132 | firmwarePowerLevels[URIBeaconConfigService::TX_POWER_MODE_LOW]); |
rgrover1 | 13:b82d8db73633 | 133 | |
rgrover1 | 13:b82d8db73633 | 134 | ble.setDeviceName(reinterpret_cast<uint8_t *>(&DEVICE_NAME)); |
rgrover1 | 13:b82d8db73633 | 135 | ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); |
rgrover1 | 13:b82d8db73633 | 136 | ble.setAdvertisingInterval( |
rgrover1 | 13:b82d8db73633 | 137 | Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(ADVERTISING_INTERVAL_MSEC)); |
rgrover1 | 6:31b65d4ea67d | 138 | ble.startAdvertising(); |
rgrover1 | 6:31b65d4ea67d | 139 | } |
rgrover1 | 0:790a27ffc99b | 140 | |
rgrover1 | 13:b82d8db73633 | 141 | void startAdvertisingUriBeacon() { |
rgrover1 | 13:b82d8db73633 | 142 | uint8_t serviceData[SERVICE_DATA_MAX]; |
rgrover1 | 13:b82d8db73633 | 143 | int serviceDataLen = 0; |
rgrover1 | 13:b82d8db73633 | 144 | |
rgrover1 | 13:b82d8db73633 | 145 | advertisingStateLed = 1; |
rgrover1 | 13:b82d8db73633 | 146 | connectionStateLed = 1; |
rgrover1 | 13:b82d8db73633 | 147 | |
rgrover1 | 13:b82d8db73633 | 148 | ble.shutdown(); |
rgrover1 | 13:b82d8db73633 | 149 | ble.init(); |
rgrover1 | 13:b82d8db73633 | 150 | |
rgrover1 | 13:b82d8db73633 | 151 | // Fields from the Service |
rgrover1 | 13:b82d8db73633 | 152 | int beaconPeriod = persistentData.params.beaconPeriod; |
rgrover1 | 13:b82d8db73633 | 153 | int txPowerMode = persistentData.params.txPowerMode; |
rgrover1 | 13:b82d8db73633 | 154 | int uriDataLength = persistentData.params.uriDataLength; |
rgrover1 | 13:b82d8db73633 | 155 | URIBeaconConfigService::UriData_t &uriData = persistentData.params.uriData; |
rgrover1 | 13:b82d8db73633 | 156 | URIBeaconConfigService::PowerLevels_t &advPowerLevels = persistentData.params.advPowerLevels; |
rgrover1 | 13:b82d8db73633 | 157 | uint8_t flags = persistentData.params.flags; |
rgrover1 | 13:b82d8db73633 | 158 | |
rgrover1 | 13:b82d8db73633 | 159 | pstorageSave(); |
rgrover1 | 13:b82d8db73633 | 160 | |
rgrover1 | 13:b82d8db73633 | 161 | delete uriBeaconConfig; |
rgrover1 | 13:b82d8db73633 | 162 | uriBeaconConfig = NULL; |
rgrover1 | 13:b82d8db73633 | 163 | |
rgrover1 | 13:b82d8db73633 | 164 | ble.clearAdvertisingPayload(); |
rgrover1 | 13:b82d8db73633 | 165 | ble.setTxPower(firmwarePowerLevels[txPowerMode]); |
rgrover1 | 13:b82d8db73633 | 166 | |
rgrover1 | 13:b82d8db73633 | 167 | ble.setAdvertisingType( |
rgrover1 | 13:b82d8db73633 | 168 | GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED); |
rgrover1 | 13:b82d8db73633 | 169 | |
rgrover1 | 13:b82d8db73633 | 170 | ble.setAdvertisingInterval( |
rgrover1 | 13:b82d8db73633 | 171 | Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(beaconPeriod)); |
rgrover1 | 13:b82d8db73633 | 172 | |
rgrover1 | 13:b82d8db73633 | 173 | ble.accumulateAdvertisingPayload( |
rgrover1 | 13:b82d8db73633 | 174 | GapAdvertisingData::BREDR_NOT_SUPPORTED | |
rgrover1 | 13:b82d8db73633 | 175 | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); |
rgrover1 | 13:b82d8db73633 | 176 | |
rgrover1 | 13:b82d8db73633 | 177 | ble.accumulateAdvertisingPayload( |
rgrover1 | 13:b82d8db73633 | 178 | GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, BEACON_UUID, |
rgrover1 | 13:b82d8db73633 | 179 | sizeof(BEACON_UUID)); |
rgrover1 | 13:b82d8db73633 | 180 | |
rgrover1 | 13:b82d8db73633 | 181 | serviceData[serviceDataLen++] = BEACON_UUID[0]; |
rgrover1 | 13:b82d8db73633 | 182 | serviceData[serviceDataLen++] = BEACON_UUID[1]; |
rgrover1 | 13:b82d8db73633 | 183 | serviceData[serviceDataLen++] = flags; |
rgrover1 | 13:b82d8db73633 | 184 | serviceData[serviceDataLen++] = advPowerLevels[txPowerMode]; |
rgrover1 | 13:b82d8db73633 | 185 | for (int j=0; j < uriDataLength; j++) { |
rgrover1 | 13:b82d8db73633 | 186 | serviceData[serviceDataLen++] = uriData[j]; |
rgrover1 | 13:b82d8db73633 | 187 | } |
rgrover1 | 13:b82d8db73633 | 188 | |
rgrover1 | 13:b82d8db73633 | 189 | ble.accumulateAdvertisingPayload( |
rgrover1 | 13:b82d8db73633 | 190 | GapAdvertisingData::SERVICE_DATA, |
rgrover1 | 13:b82d8db73633 | 191 | serviceData, serviceDataLen); |
rgrover1 | 13:b82d8db73633 | 192 | |
rgrover1 | 13:b82d8db73633 | 193 | ble.startAdvertising(); |
rgrover1 | 13:b82d8db73633 | 194 | } |
rgrover1 | 13:b82d8db73633 | 195 | |
rgrover1 | 13:b82d8db73633 | 196 | // After advertising timeout, stop config and switch to UriBeacon |
rgrover1 | 13:b82d8db73633 | 197 | void timeout(void) { |
rgrover1 | 13:b82d8db73633 | 198 | Gap::GapState_t state; |
rgrover1 | 13:b82d8db73633 | 199 | state = ble.getGapState(); |
rgrover1 | 13:b82d8db73633 | 200 | if (!state.connected) { |
rgrover1 | 13:b82d8db73633 | 201 | startAdvertisingUriBeacon(); |
rgrover1 | 13:b82d8db73633 | 202 | } |
rgrover1 | 13:b82d8db73633 | 203 | } |
rgrover1 | 13:b82d8db73633 | 204 | |
rgrover1 | 13:b82d8db73633 | 205 | // When connected to config service, change the LEDs |
rgrover1 | 13:b82d8db73633 | 206 | void connectionCallback(Gap::Handle_t handle, |
rgrover1 | 13:b82d8db73633 | 207 | Gap::addr_type_t peerAddrType, |
rgrover1 | 13:b82d8db73633 | 208 | const Gap::address_t peerAddr, |
rgrover1 | 13:b82d8db73633 | 209 | const Gap::ConnectionParams_t *params) { |
rgrover1 | 13:b82d8db73633 | 210 | advertisingStateLed = 1; |
rgrover1 | 13:b82d8db73633 | 211 | connectionStateLed = 0; |
rgrover1 | 13:b82d8db73633 | 212 | } |
rgrover1 | 13:b82d8db73633 | 213 | |
rgrover1 | 13:b82d8db73633 | 214 | // When disconnected from config service, start advertising UriBeacon |
rgrover1 | 13:b82d8db73633 | 215 | void disconnectionCallback(Gap::Handle_t handle, |
rgrover1 | 13:b82d8db73633 | 216 | Gap::DisconnectionReason_t reason) { |
rgrover1 | 13:b82d8db73633 | 217 | advertisingStateLed = 0; // on |
rgrover1 | 13:b82d8db73633 | 218 | connectionStateLed = 1; // off |
rgrover1 | 13:b82d8db73633 | 219 | startAdvertisingUriBeacon(); |
rgrover1 | 13:b82d8db73633 | 220 | } |
rgrover1 | 13:b82d8db73633 | 221 | |
rgrover1 | 0:790a27ffc99b | 222 | int main(void) |
rgrover1 | 0:790a27ffc99b | 223 | { |
rgrover1 | 13:b82d8db73633 | 224 | advertisingStateLed = 0; // on |
rgrover1 | 13:b82d8db73633 | 225 | connectionStateLed = 1; // off |
rgrover1 | 13:b82d8db73633 | 226 | |
rgrover1 | 0:790a27ffc99b | 227 | ble.init(); |
rgrover1 | 6:31b65d4ea67d | 228 | ble.onDisconnection(disconnectionCallback); |
rgrover1 | 13:b82d8db73633 | 229 | ble.onConnection(connectionCallback); |
rgrover1 | 13:b82d8db73633 | 230 | // Advertising timeout |
rgrover1 | 13:b82d8db73633 | 231 | ble.onTimeout(timeout); |
rgrover1 | 0:790a27ffc99b | 232 | |
rgrover1 | 13:b82d8db73633 | 233 | pstorageLoad(); |
rgrover1 | 13:b82d8db73633 | 234 | bool resetToDefaults = persistentData.magic != MAGIC; |
rgrover1 | 13:b82d8db73633 | 235 | |
rgrover1 | 13:b82d8db73633 | 236 | URIBeaconConfigService::UriData_t defaultUriData; |
rgrover1 | 13:b82d8db73633 | 237 | size_t defaultUriDataLength; |
rgrover1 | 13:b82d8db73633 | 238 | URIBeaconConfigService::encodeURI("http://uribeacon.org", defaultUriData, defaultUriDataLength); |
rgrover1 | 13:b82d8db73633 | 239 | |
rgrover1 | 13:b82d8db73633 | 240 | uriBeaconConfig = new URIBeaconConfigService(ble, persistentData.params, resetToDefaults, |
rgrover1 | 13:b82d8db73633 | 241 | defaultUriData, defaultUriDataLength, defaultAdvPowerLevels); |
rgrover1 | 13:b82d8db73633 | 242 | if (!uriBeaconConfig->configuredSuccessfully()) { |
rgrover1 | 6:31b65d4ea67d | 243 | error("failed to accommodate URI"); |
rgrover1 | 6:31b65d4ea67d | 244 | } |
rgrover1 | 0:790a27ffc99b | 245 | |
rgrover1 | 13:b82d8db73633 | 246 | // Setup auxiliary services to allow over-the-air firmware updates, etc |
rgrover1 | 13:b82d8db73633 | 247 | DFUService dfu(ble); |
rgrover1 | 13:b82d8db73633 | 248 | DeviceInformationService deviceInfo( |
rgrover1 | 13:b82d8db73633 | 249 | ble, "ARM", "UriBeacon", "SN1", "hw-rev1", "fw-rev1", "soft-rev1"); |
rgrover1 | 11:c77cc2b74101 | 250 | |
rgrover1 | 13:b82d8db73633 | 251 | /* Start out by advertising the configService for a limited time after |
rgrover1 | 13:b82d8db73633 | 252 | * startup; and switch to the normal non-connectible beacon functionality |
rgrover1 | 13:b82d8db73633 | 253 | * afterwards. */ |
rgrover1 | 13:b82d8db73633 | 254 | startAdvertisingUriBeaconConfig(); |
rgrover1 | 0:790a27ffc99b | 255 | |
rgrover1 | 0:790a27ffc99b | 256 | while (true) { |
rgrover1 | 0:790a27ffc99b | 257 | ble.waitForEvent(); |
rgrover1 | 0:790a27ffc99b | 258 | } |
rgrover1 | 0:790a27ffc99b | 259 | } |