Changed to work with St Board
Dependencies: BLE_API X_NUCLEO_IDB0XA1 mbed
Fork of BLE_URIBeacon by
Diff: main.cpp
- Revision:
- 16:1daa78939a3b
- Parent:
- 14:868a1207022d
- Child:
- 17:e2c0a1696e39
--- a/main.cpp Fri Mar 06 09:23:50 2015 +0000 +++ b/main.cpp Mon Mar 09 16:35:03 2015 +0000 @@ -14,244 +14,49 @@ * limitations under the License. */ -#include <stdint.h> -#include <stddef.h> -#include <nrf_error.h> #include "mbed.h" #include "BLEDevice.h" #include "URIBeaconConfigService.h" #include "DFUService.h" -#include "pstorage.h" #include "DeviceInformationService.h" - -// Struct to hold persistent data across power cycles -struct PersistentData_t { - uint32_t magic; - URIBeaconConfigService::Params_t params; - uint8_t pad[4]; -} __attribute__ ((aligned (4))); - -static const int PERSISTENT_DATA_ALIGNED_SIZE = sizeof(PersistentData_t); -// Seconds after power-on that config service is available. -static const int ADVERTISING_TIMEOUT_SECONDS = 60; -// Advertising interval for config service. -static const int ADVERTISING_INTERVAL_MSEC = 1000; -// Maximum size of service data in ADV packets -static const int SERVICE_DATA_MAX = 31; -// Magic that identifies persistent storage -static const uint32_t MAGIC = 0x1BEAC000; -// Values for ADV packets related to firmware levels -static URIBeaconConfigService::PowerLevels_t defaultAdvPowerLevels = {-20, -4, 0, 10}; -// Values for setTxPower() indexed by power mode. -static const int8_t firmwarePowerLevels[] = {-20, -4, 0, 10}; +#include "ConfigParamsPersistence.h" BLEDevice ble; URIBeaconConfigService *uriBeaconConfig; -pstorage_handle_t pstorageHandle; -PersistentData_t persistentData; -/* LEDs for indication */ -DigitalOut connectionStateLed(LED1); -DigitalOut advertisingStateLed(LED2); - -/* Dummy callback handler needed by Nordic's pstorage module. */ -void pstorageNotificationCallback(pstorage_handle_t *p_handle, - uint8_t op_code, - uint32_t result, - uint8_t * p_data, - uint32_t data_len) { - /* APP_ERROR_CHECK(result); */ -} - -void pstorageLoad() { - pstorage_init(); - pstorage_module_param_t pstorageParams = { - .cb = pstorageNotificationCallback, - .block_size = PERSISTENT_DATA_ALIGNED_SIZE, - .block_count = 1 - }; - pstorage_register(&pstorageParams, &pstorageHandle); - if (pstorage_load(reinterpret_cast<uint8_t *>(&persistentData), - &pstorageHandle, PERSISTENT_DATA_ALIGNED_SIZE, 0) != NRF_SUCCESS) { - // On failure zero out and let the service reset to defaults - memset(&persistentData, 0, sizeof(PersistentData_t)); - } -} - - -void pstorageSave() { - if (persistentData.magic != MAGIC) { - persistentData.magic = MAGIC; - pstorage_store(&pstorageHandle, - reinterpret_cast<uint8_t *>(&persistentData), - sizeof(PersistentData_t), - 0 /* offset */); - } else { - pstorage_update(&pstorageHandle, - reinterpret_cast<uint8_t *>(&persistentData), - sizeof(PersistentData_t), - 0 /* offset */); - } -} - -void startAdvertisingUriBeaconConfig() { - char DEVICE_NAME[] = "mUriBeacon Config"; - - ble.clearAdvertisingPayload(); - - // Stops advertising the UriBeacon Config Service after a delay - ble.setAdvertisingTimeout(ADVERTISING_TIMEOUT_SECONDS); - - ble.accumulateAdvertisingPayload( - GapAdvertisingData::BREDR_NOT_SUPPORTED | - GapAdvertisingData::LE_GENERAL_DISCOVERABLE); - - // UUID is in different order in the ADV frame (!) - uint8_t reversedServiceUUID[sizeof(UUID_URI_BEACON_SERVICE)]; - for (unsigned int i = 0; i < sizeof(UUID_URI_BEACON_SERVICE); i++) { - reversedServiceUUID[i] = - UUID_URI_BEACON_SERVICE[sizeof(UUID_URI_BEACON_SERVICE) - i - 1]; - } - ble.accumulateAdvertisingPayload( - GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS, - reversedServiceUUID, - sizeof(reversedServiceUUID)); - - ble.accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_TAG); - ble.accumulateScanResponse( - GapAdvertisingData::COMPLETE_LOCAL_NAME, - reinterpret_cast<uint8_t *>(&DEVICE_NAME), - sizeof(DEVICE_NAME)); - ble.accumulateScanResponse( - GapAdvertisingData::TX_POWER_LEVEL, - reinterpret_cast<uint8_t *>( - &defaultAdvPowerLevels[URIBeaconConfigService::TX_POWER_MODE_LOW]), - sizeof(uint8_t)); - - ble.setTxPower( - firmwarePowerLevels[URIBeaconConfigService::TX_POWER_MODE_LOW]); - - ble.setDeviceName(reinterpret_cast<uint8_t *>(&DEVICE_NAME)); - ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); - ble.setAdvertisingInterval( - Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(ADVERTISING_INTERVAL_MSEC)); +void disconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason) +{ ble.startAdvertising(); } -void startAdvertisingUriBeacon() { - uint8_t serviceData[SERVICE_DATA_MAX]; - int serviceDataLen = 0; - - advertisingStateLed = 1; - connectionStateLed = 1; - - ble.shutdown(); - ble.init(); - - // Fields from the Service - int beaconPeriod = persistentData.params.beaconPeriod; - int txPowerMode = persistentData.params.txPowerMode; - int uriDataLength = persistentData.params.uriDataLength; - URIBeaconConfigService::UriData_t &uriData = persistentData.params.uriData; - URIBeaconConfigService::PowerLevels_t &advPowerLevels = persistentData.params.advPowerLevels; - uint8_t flags = persistentData.params.flags; - - pstorageSave(); - - delete uriBeaconConfig; - uriBeaconConfig = NULL; - - ble.clearAdvertisingPayload(); - ble.setTxPower(firmwarePowerLevels[txPowerMode]); - - ble.setAdvertisingType( - GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED); - - ble.setAdvertisingInterval( - Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(beaconPeriod)); - - ble.accumulateAdvertisingPayload( - GapAdvertisingData::BREDR_NOT_SUPPORTED | - GapAdvertisingData::LE_GENERAL_DISCOVERABLE); - - ble.accumulateAdvertisingPayload( - GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, BEACON_UUID, - sizeof(BEACON_UUID)); - - serviceData[serviceDataLen++] = BEACON_UUID[0]; - serviceData[serviceDataLen++] = BEACON_UUID[1]; - serviceData[serviceDataLen++] = flags; - serviceData[serviceDataLen++] = advPowerLevels[txPowerMode]; - for (int j=0; j < uriDataLength; j++) { - serviceData[serviceDataLen++] = uriData[j]; - } - - ble.accumulateAdvertisingPayload( - GapAdvertisingData::SERVICE_DATA, - serviceData, serviceDataLen); - - ble.startAdvertising(); -} - -// After advertising timeout, stop config and switch to UriBeacon -void timeout(void) { - Gap::GapState_t state; - state = ble.getGapState(); - if (!state.connected) { - startAdvertisingUriBeacon(); - } -} - -// When connected to config service, change the LEDs -void connectionCallback(Gap::Handle_t handle, - Gap::addr_type_t peerAddrType, - const Gap::address_t peerAddr, - const Gap::ConnectionParams_t *params) { - advertisingStateLed = 1; - connectionStateLed = 0; -} - -// When disconnected from config service, start advertising UriBeacon -void disconnectionCallback(Gap::Handle_t handle, - Gap::DisconnectionReason_t reason) { - advertisingStateLed = 0; // on - connectionStateLed = 1; // off - startAdvertisingUriBeacon(); -} - int main(void) { - advertisingStateLed = 0; // on - connectionStateLed = 1; // off - ble.init(); ble.onDisconnection(disconnectionCallback); - ble.onConnection(connectionCallback); - // Advertising timeout - ble.onTimeout(timeout); - - pstorageLoad(); - bool resetToDefaults = persistentData.magic != MAGIC; - URIBeaconConfigService::UriData_t defaultUriData; - size_t defaultUriDataLength; - URIBeaconConfigService::encodeURI("http://uribeacon.org", defaultUriData, defaultUriDataLength); + /* + * Load parameters from (platform specific) persistent storage. Parameters + * can be set to non-default values while the URIBeacon is in configuration + * mode (within the first 60 seconds of power-up). Thereafter, parameters + * get copied out to persistent storage before switching to normal URIBeacon + * operation. + */ + URIBeaconConfigService::Params_t params; + loadURIBeaconConfigParams(¶ms); - uriBeaconConfig = new URIBeaconConfigService(ble, persistentData.params, resetToDefaults, - defaultUriData, defaultUriDataLength, defaultAdvPowerLevels); + /* Initialize a URIBeaconConfig service providing config params, default URI, and power levels. */ + static URIBeaconConfigService::PowerLevels_t defaultAdvPowerLevels = {-20, -4, 0, 10}; // Values for ADV packets related to firmware levels + uriBeaconConfig = new URIBeaconConfigService(ble, params, "http://uribeacon.org", defaultAdvPowerLevels); if (!uriBeaconConfig->configuredSuccessfully()) { error("failed to accommodate URI"); } // Setup auxiliary services to allow over-the-air firmware updates, etc DFUService dfu(ble); - DeviceInformationService deviceInfo( - ble, "ARM", "UriBeacon", "SN1", "hw-rev1", "fw-rev1", "soft-rev1"); + DeviceInformationService deviceInfo(ble, "ARM", "UriBeacon", "SN1", "hw-rev1", "fw-rev1", "soft-rev1"); - /* Start out by advertising the configService for a limited time after - * startup; and switch to the normal non-connectible beacon functionality - * afterwards. */ - startAdvertisingUriBeaconConfig(); + ble.startAdvertising(); /* Set the whole thing in motion. After this call a GAP central can scan the URIBeaconConfig + * service, which then automatically switches to the URIBeacon after a timeout. */ while (true) { ble.waitForEvent();