Lightly modified version of the BLE stack, that doesn't bring up a DFUService by default... as we have our own.
Fork of BLE_API by
Diff: services/URIBeaconConfigService.h
- Revision:
- 309:bc91f7ba346d
- Parent:
- 300:d9a39f759a6a
- Child:
- 310:0b79de98eceb
--- a/services/URIBeaconConfigService.h Mon Mar 09 16:23:54 2015 +0000 +++ b/services/URIBeaconConfigService.h Mon Mar 09 16:23:55 2015 +0000 @@ -51,6 +51,9 @@ static const uint8_t TX_POWER_MODE_HIGH = 3; /*!< High TX power mode */ static const unsigned int NUM_POWER_MODES = 4; /*!< Number of Power Modes defined */ + static const int ADVERTISING_TIMEOUT_SECONDS = 60; // Seconds after power-on that config service is available. + static const int ADVERTISING_INTERVAL_MSEC = 1000; // Advertising interval for config service. + static const int SERVICE_DATA_MAX = 31; // Maximum size of service data in ADV packets typedef uint8_t Lock_t[16]; /* 128 bits */ typedef int8_t PowerLevels_t[NUM_POWER_MODES]; @@ -80,24 +83,23 @@ * @param[in] resetToDefaultsFlag * reset params state to the defaults. * @param[in] defaultUriDataIn - * Default encoded URIData; applies only if the resetToDefaultsFlag is true. - * @param[in] defaultUriDataLengthIn - * Length of the default encoded URIData (from above); applies only if the resetToDefaultsFlag is true. + * Default un-encoded URI; applies only if the resetToDefaultsFlag is true. * @param[in] defaultAdvPowerLevelsIn * Default power-levels array; applies only if the resetToDefaultsFlag is true. */ URIBeaconConfigService(BLEDevice &bleIn, Params_t ¶msIn, bool resetToDefaultsFlag, - UriData_t &defaultUriDataIn, - int defaultUriDataLengthIn, + const char *defaultURIDataIn, PowerLevels_t &defaultAdvPowerLevelsIn) : ble(bleIn), params(paramsIn), - defaultUriDataLength(defaultUriDataLengthIn), - defaultUriData(defaultUriDataIn), + defaultUriDataLength(), + defaultUriData(), defaultAdvPowerLevels(defaultAdvPowerLevelsIn), initSucceeded(false), + resetFlag(), + configAdvertisementTimeoutTicker(), lockedStateChar(UUID_LOCK_STATE_CHAR, &lockedState), lockChar(UUID_LOCK_CHAR, ¶ms.lock), uriDataChar(UUID_URI_DATA_CHAR, params.uriData, 0, URI_DATA_MAX, @@ -108,7 +110,9 @@ txPowerModeChar(UUID_TX_POWER_MODE_CHAR, ¶ms.txPowerMode), beaconPeriodChar(UUID_BEACON_PERIOD_CHAR, ¶ms.beaconPeriod), resetChar(UUID_RESET_CHAR, &resetFlag) { - if (defaultUriDataLengthIn > URI_DATA_MAX) { + + encodeURI(defaultURIDataIn, defaultUriData, defaultUriDataLength); + if (defaultUriDataLength > URI_DATA_MAX) { return; } @@ -143,6 +147,11 @@ ble.addService(configService); ble.onDataWritten(this, &URIBeaconConfigService::onDataWrittenCallback); + /* Start out by advertising the configService for a limited time after + * startup; and switch to the normal non-connectible beacon functionality + * afterwards. */ + setupUriBeaconConfigAdvertisements(); + initSucceeded = true; } @@ -150,6 +159,108 @@ return initSucceeded; } + /* Start out by advertising the configService for a limited time after + * startup; and switch to the normal non-connectible beacon functionality + * afterwards. */ + void setupUriBeaconConfigAdvertisements() + { + char DEVICE_NAME[] = "mUriBeacon Config"; + + ble.clearAdvertisingPayload(); + + // Stops advertising the UriBeacon Config Service after a delay + configAdvertisementTimeoutTicker.attach(this, &URIBeaconConfigService::timeout, 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)); + + /////// TODO + // 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 setupUriBeaconAdvertisements() + { + // 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) { + setupUriBeaconAdvertisements(); + configAdvertisementTimeoutTicker.detach(); + } + } private: // True if the lock bits are non-zero @@ -257,13 +368,14 @@ BLEDevice &ble; Params_t ¶ms; // Default value that is restored on reset - uint16_t defaultUriDataLength; - UriData_t &defaultUriData; + size_t defaultUriDataLength; + UriData_t defaultUriData; // Default value that is restored on reset PowerLevels_t &defaultAdvPowerLevels; uint8_t lockedState; bool initSucceeded; uint8_t resetFlag; + Ticker configAdvertisementTimeoutTicker; ReadOnlyGattCharacteristic<uint8_t> lockedStateChar; WriteOnlyGattCharacteristic<Lock_t> lockChar;