Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: BLE_API mbed nRF51822
main.cpp
00001 /* 00002 * Copyright 2014-2015 Google Inc. All rights reserved. 00003 * 00004 * Licensed under the Apache License, Version 2.0 (the "License"); 00005 * you may not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an "AS IS" BASIS, 00012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 00017 #include <stdint.h> 00018 #include <stddef.h> 00019 #include <nrf_error.h> 00020 #include "mbed.h" 00021 #include "BLEDevice.h" 00022 #include "URIBeaconConfigService.h" 00023 #include "DFUService.h" 00024 #include "pstorage.h" 00025 #include "DeviceInformationService.h" 00026 00027 // Struct to hold persistent data across power cycles 00028 struct PersistentData_t { 00029 uint32_t magic; 00030 URIBeaconConfigService::Params_t params; 00031 uint8_t pad[4]; 00032 } __attribute__ ((aligned (4))); 00033 00034 static const int PERSISTENT_DATA_ALIGNED_SIZE = sizeof(PersistentData_t); 00035 // Seconds after power-on that config service is available. 00036 static const int ADVERTISING_TIMEOUT_SECONDS = 60; 00037 // Advertising interval for config service. 00038 static const int ADVERTISING_INTERVAL_MSEC = 1000; 00039 // Maximum size of service data in ADV packets 00040 static const int SERVICE_DATA_MAX = 31; 00041 // Magic that identifies persistent storage 00042 static const uint32_t MAGIC = 0x1BEAC000; 00043 // Values for ADV packets related to firmware levels 00044 static URIBeaconConfigService::PowerLevels_t defaultAdvPowerLevels = {-20, -4, 0, 10}; 00045 // Values for setTxPower() indexed by power mode. 00046 static const int8_t firmwarePowerLevels[] = {-20, -4, 0, 10}; 00047 00048 BLEDevice ble; 00049 URIBeaconConfigService *uriBeaconConfig; 00050 pstorage_handle_t pstorageHandle; 00051 PersistentData_t persistentData; 00052 00053 /* LEDs for indication */ 00054 DigitalOut connectionStateLed(LED1); 00055 DigitalOut advertisingStateLed(LED2); 00056 00057 void blink(int count) { 00058 for (int i = 0; i <= count; i++) { 00059 advertisingStateLed = !advertisingStateLed; 00060 wait(0.2); 00061 advertisingStateLed = !advertisingStateLed; 00062 wait(0.2); 00063 } 00064 } 00065 00066 /* Dummy callback handler needed by Nordic's pstorage module. */ 00067 void pstorageNotificationCallback(pstorage_handle_t *p_handle, 00068 uint8_t op_code, 00069 uint32_t result, 00070 uint8_t * p_data, 00071 uint32_t data_len) { 00072 /* APP_ERROR_CHECK(result); */ 00073 } 00074 00075 void pstorageLoad() { 00076 pstorage_init(); 00077 pstorage_module_param_t pstorageParams = { 00078 .cb = pstorageNotificationCallback, 00079 .block_size = PERSISTENT_DATA_ALIGNED_SIZE, 00080 .block_count = 1 00081 }; 00082 pstorage_register(&pstorageParams, &pstorageHandle); 00083 if (pstorage_load(reinterpret_cast<uint8_t *>(&persistentData), 00084 &pstorageHandle, PERSISTENT_DATA_ALIGNED_SIZE, 0) != NRF_SUCCESS) { 00085 // On failure zero out and let the service reset to defaults 00086 memset(&persistentData, 0, sizeof(PersistentData_t)); 00087 } 00088 } 00089 00090 00091 void pstorageSave() { 00092 if (persistentData.magic != MAGIC) { 00093 persistentData.magic = MAGIC; 00094 pstorage_store(&pstorageHandle, 00095 reinterpret_cast<uint8_t *>(&persistentData), 00096 sizeof(PersistentData_t), 00097 0 /* offset */); 00098 } else { 00099 pstorage_update(&pstorageHandle, 00100 reinterpret_cast<uint8_t *>(&persistentData), 00101 sizeof(PersistentData_t), 00102 0 /* offset */); 00103 } 00104 } 00105 00106 void startAdvertisingUriBeaconConfig() { 00107 char DEVICE_NAME[] = "mUriBeacon Config"; 00108 00109 ble.clearAdvertisingPayload(); 00110 00111 // Stops advertising the UriBeacon Config Service after a delay 00112 ble.setAdvertisingTimeout(ADVERTISING_TIMEOUT_SECONDS); 00113 00114 ble.accumulateAdvertisingPayload( 00115 GapAdvertisingData::BREDR_NOT_SUPPORTED | 00116 GapAdvertisingData::LE_GENERAL_DISCOVERABLE); 00117 00118 // UUID is in different order in the ADV frame (!) 00119 uint8_t reversedServiceUUID[sizeof(UUID_URI_BEACON_SERVICE)]; 00120 for (unsigned int i = 0; i < sizeof(UUID_URI_BEACON_SERVICE); i++) { 00121 reversedServiceUUID[i] = 00122 UUID_URI_BEACON_SERVICE[sizeof(UUID_URI_BEACON_SERVICE) - i - 1]; 00123 } 00124 ble.accumulateAdvertisingPayload( 00125 GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS, 00126 reversedServiceUUID, 00127 sizeof(reversedServiceUUID)); 00128 00129 ble.accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_TAG); 00130 ble.accumulateScanResponse( 00131 GapAdvertisingData::COMPLETE_LOCAL_NAME, 00132 reinterpret_cast<uint8_t *>(&DEVICE_NAME), 00133 sizeof(DEVICE_NAME)); 00134 ble.accumulateScanResponse( 00135 GapAdvertisingData::TX_POWER_LEVEL, 00136 reinterpret_cast<uint8_t *>( 00137 &defaultAdvPowerLevels[URIBeaconConfigService::TX_POWER_MODE_LOW]), 00138 sizeof(uint8_t)); 00139 00140 ble.setTxPower( 00141 firmwarePowerLevels[URIBeaconConfigService::TX_POWER_MODE_LOW]); 00142 00143 ble.setDeviceName(reinterpret_cast<uint8_t *>(&DEVICE_NAME)); 00144 ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); 00145 ble.setAdvertisingInterval( 00146 Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(ADVERTISING_INTERVAL_MSEC)); 00147 ble.startAdvertising(); 00148 } 00149 00150 00151 void startAdvertisingUriBeacon() { 00152 uint8_t serviceData[SERVICE_DATA_MAX]; 00153 int serviceDataLen = 0; 00154 00155 advertisingStateLed = 1; 00156 connectionStateLed = 1; 00157 00158 ble.shutdown(); 00159 ble.init(); 00160 00161 // Fields from the Service 00162 int beaconPeriod = persistentData.params.beaconPeriod; 00163 int txPowerMode = persistentData.params.txPowerMode; 00164 int uriDataLength = persistentData.params.uriDataLength; 00165 URIBeaconConfigService::UriData_t &uriData = persistentData.params.uriData; 00166 URIBeaconConfigService::PowerLevels_t &advPowerLevels = 00167 persistentData.params.advPowerLevels; 00168 uint8_t flags = persistentData.params.flags; 00169 00170 pstorageSave(); 00171 00172 delete uriBeaconConfig; 00173 uriBeaconConfig = NULL; 00174 00175 ble.clearAdvertisingPayload(); 00176 ble.setTxPower(firmwarePowerLevels[txPowerMode]); 00177 00178 ble.setAdvertisingType( 00179 GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED); 00180 00181 ble.setAdvertisingInterval( 00182 Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(beaconPeriod)); 00183 00184 ble.accumulateAdvertisingPayload( 00185 GapAdvertisingData::BREDR_NOT_SUPPORTED | 00186 GapAdvertisingData::LE_GENERAL_DISCOVERABLE); 00187 00188 ble.accumulateAdvertisingPayload( 00189 GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, BEACON_UUID, 00190 sizeof(BEACON_UUID)); 00191 00192 serviceData[serviceDataLen++] = BEACON_UUID[0]; 00193 serviceData[serviceDataLen++] = BEACON_UUID[1]; 00194 serviceData[serviceDataLen++] = flags; 00195 serviceData[serviceDataLen++] = advPowerLevels[txPowerMode]; 00196 for (int j=0; j < uriDataLength; j++) { 00197 serviceData[serviceDataLen++] = uriData[j]; 00198 } 00199 00200 ble.accumulateAdvertisingPayload( 00201 GapAdvertisingData::SERVICE_DATA, 00202 serviceData, serviceDataLen); 00203 00204 ble.startAdvertising(); 00205 } 00206 00207 // After advertising timeout, stop config and switch to UriBeacon 00208 void timeout(void) { 00209 Gap::GapState_t state; 00210 state = ble.getGapState(); 00211 if (!state.connected) { 00212 startAdvertisingUriBeacon(); 00213 } 00214 } 00215 00216 // When connected to config service, change the LEDs 00217 void connectionCallback(Gap::Handle_t handle, 00218 Gap::addr_type_t peerAddrType, 00219 const Gap::address_t peerAddr, 00220 const Gap::ConnectionParams_t *params) { 00221 advertisingStateLed = 1; 00222 connectionStateLed = 0; 00223 } 00224 00225 // When disconnected from config service, start advertising UriBeacon 00226 void disconnectionCallback(Gap::Handle_t handle, 00227 Gap::DisconnectionReason_t reason) { 00228 advertisingStateLed = 0; // on 00229 connectionStateLed = 1; // off 00230 startAdvertisingUriBeacon(); 00231 } 00232 00233 int main(void) { 00234 URIBeaconConfigService::UriData_t uriData = { 00235 // http://uribeacon.org 00236 0x02, 'u', 'r', 'i', 'b', 'e', 'a', 'c', 'o', 'n', 0x08 00237 }; 00238 int uriDataLength = 11; 00239 00240 advertisingStateLed = 0; // on 00241 connectionStateLed = 1; // off 00242 00243 ble.init(); 00244 ble.onDisconnection(disconnectionCallback); 00245 ble.onConnection(connectionCallback); 00246 // Advertising timeout 00247 ble.onTimeout(timeout); 00248 00249 pstorageLoad(); 00250 bool resetToDefaults = persistentData.magic != MAGIC; 00251 uriBeaconConfig = new URIBeaconConfigService( 00252 ble, persistentData.params, resetToDefaults, 00253 uriData, uriDataLength, defaultAdvPowerLevels); 00254 if (!uriBeaconConfig->configuredSuccessfully()) { 00255 error("failed to accommodate URI"); 00256 } 00257 00258 // Setup auxiliary services to allow over-the-air firmware updates, etc 00259 DFUService dfu(ble); 00260 DeviceInformationService deviceInfo( 00261 ble, "ARM", "UriBeacon", "SN1", "hw-rev1", "fw-rev1", "soft-rev1"); 00262 00263 00264 startAdvertisingUriBeaconConfig(); 00265 00266 while (true) { 00267 ble.waitForEvent(); 00268 } 00269 }
Generated on Sat Jul 16 2022 23:23:58 by
1.7.2