Bill Schilit / Mbed 2 deprecated BLE_UriBeacon

Dependencies:   BLE_API mbed nRF51822

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

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 }